Problema
Um modelo de linguagem não pode olhar para palavras futuras. A atenção causal mascara o futuro: a linha de consulta i só pode atender às linhas de chave 0 a i.
Para cada linha i (queries, keys e values têm n linhas):
- Pontue cada chave permitida j ≤ i: score = (queries[i] · keys[j]) / √d, onde d é o número de colunas de keys.
- Aplique softmax apenas sobre essas pontuações permitidas (subtraia a maior antes de calcular e^x).
- Linha de saída i = Σ weight_j × values[j] para j ≤ i.
Implemente causal_attention(queries, keys, values).
Entrada
queries, keys: n linhas de d números.
values: n linhas de v números.
Saída
Retorne a matriz de saída n × v.
Restrições
1 ≤ n ≤ 50, 1 ≤ d, v ≤ 32
-10 ≤ cada valor ≤ 10
Exemplos
Entrada:
keys = [
[1.0],
[2.0],
[3.0]
]
values = [
[3.0],
[6.0],
[9.0]
]
queries = [
[0.0],
[0.0],
[0.0]
]
Saída esperada:
expected = [
[3.0],
[4.5],
[6.0]
]
Entrada:
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}
};
Saída esperada:
std::vector<std::vector<double>> expected = {
{3.0},
{4.5},
{6.0}
};
Entrada:
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}
};
Saída esperada:
double[][] expected = new double[][] {
new double[] {3.0},
new double[] {4.5},
new double[] {6.0}
};
Explicação
Todas as pontuações são 0, então cada linha faz a média dos valores que pode ver: a linha 0 vê só 3, a linha 1 faz a média de 3 e 6 (4.5), a linha 2 faz a média dos três (6).
Entrada:
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]
]
Saída esperada:
expected = [
[1.0, 2.0],
[2.0, 3.0]
]
Entrada:
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}
};
Saída esperada:
std::vector<std::vector<double>> expected = {
{1.0, 2.0},
{2.0, 3.0}
};
Entrada:
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}
};
Saída esperada:
double[][] expected = new double[][] {
new double[] {1.0, 2.0},
new double[] {2.0, 3.0}
};
Explicação
A linha 0 vê apenas a si mesma e copia values[0] = [1, 2]. A linha 1 dá a mesma pontuação às duas chaves e faz a média delas: [2, 3].
Referências
Este desafio foi adaptado para o CodeUtility. Siga o enunciado e as restrições acima.