Problème
Un modèle de langage ne doit pas regarder les mots futurs. L'attention causale masque le futur : la ligne de requête i ne peut s'intéresser qu'aux lignes de clé 0 à i.
Pour chaque ligne i (queries, keys et values ont toutes n lignes) :
- Notez chaque clé autorisée j ≤ i : score = (queries[i] · keys[j]) / √d, où d est le nombre de colonnes de keys.
- Appliquez softmax uniquement sur ces scores autorisés (soustrayez le plus grand avant de calculer e^x).
- Ligne de sortie i = Σ weight_j × values[j] pour j ≤ i.
Implémentez causal_attention(queries, keys, values).
Entrée
queries, keys : n lignes de d nombres.
values : n lignes de v nombres.
Sortie
Renvoyez la matrice de sortie n × v.
Contraintes
1 ≤ n ≤ 50, 1 ≤ d, v ≤ 32
-10 ≤ chaque valeur ≤ 10
Exemples
Entrée :
keys = [
[1.0],
[2.0],
[3.0]
]
values = [
[3.0],
[6.0],
[9.0]
]
queries = [
[0.0],
[0.0],
[0.0]
]
Sortie attendue :
expected = [
[3.0],
[4.5],
[6.0]
]
Entrée :
std::vector<std::vector<double>> keys = {
{1.0},
{2.0},
{3.0}
};
std::vector<std::vector<double>> values = {
{3.0},
{6.0},
{9.0}
};
std::vector<std::vector<double>> queries = {
{0.0},
{0.0},
{0.0}
};
Sortie attendue :
std::vector<std::vector<double>> expected = {
{3.0},
{4.5},
{6.0}
};
Entrée :
double[][] keys = new double[][] {
new double[] {1.0},
new double[] {2.0},
new double[] {3.0}
};
double[][] values = new double[][] {
new double[] {3.0},
new double[] {6.0},
new double[] {9.0}
};
double[][] queries = new double[][] {
new double[] {0.0},
new double[] {0.0},
new double[] {0.0}
};
Sortie attendue :
double[][] expected = new double[][] {
new double[] {3.0},
new double[] {4.5},
new double[] {6.0}
};
Explication
Tous les scores valent 0, donc chaque ligne fait la moyenne des valeurs qu'elle peut voir : la ligne 0 ne voit que 3, la ligne 1 fait la moyenne de 3 et 6 (4.5), la ligne 2 fait la moyenne des trois (6).
Entrée :
keys = [
[1.0, 0.0],
[1.0, 0.0]
]
values = [
[1.0, 2.0],
[3.0, 4.0]
]
queries = [
[1.0, 0.0],
[1.0, 0.0]
]
Sortie attendue :
expected = [
[1.0, 2.0],
[2.0, 3.0]
]
Entrée :
std::vector<std::vector<double>> keys = {
{1.0, 0.0},
{1.0, 0.0}
};
std::vector<std::vector<double>> values = {
{1.0, 2.0},
{3.0, 4.0}
};
std::vector<std::vector<double>> queries = {
{1.0, 0.0},
{1.0, 0.0}
};
Sortie attendue :
std::vector<std::vector<double>> expected = {
{1.0, 2.0},
{2.0, 3.0}
};
Entrée :
double[][] keys = new double[][] {
new double[] {1.0, 0.0},
new double[] {1.0, 0.0}
};
double[][] values = new double[][] {
new double[] {1.0, 2.0},
new double[] {3.0, 4.0}
};
double[][] queries = new double[][] {
new double[] {1.0, 0.0},
new double[] {1.0, 0.0}
};
Sortie attendue :
double[][] expected = new double[][] {
new double[] {1.0, 2.0},
new double[] {2.0, 3.0}
};
Explication
La ligne 0 ne voit qu'elle-même et copie values[0] = [1, 2]. La ligne 1 donne le même score aux deux clés et en fait la moyenne : [2, 3].
Références
Ce défi a été adapté pour CodeUtility. Suivez l'énoncé et les contraintes ci-dessus.