らんだむな記憶

blogというものを体験してみようか!的なー

埋め込み

import torch
import torch.nn as nn

vocab_size = 4
emb_dim = 3
embeddings = nn.Embedding(vocab_size, emb_dim)
print(embeddings.weight)

Parameter containing:
tensor([[ 0.2671, 1.1044, 0.4217],
[ 0.5168, 1.4011, 1.3565],
[ 2.3420, -1.9554, 0.0828],
[-1.6999, 0.3869, 1.1587]],, requires_grad=True)

x = torch.tensor([1])
score = embeddings(x)
print(score)

tensor(0.5168, 1.4011, 1.3565,
grad_fn=<EmbeddingBackward>)

y = torch.sum(score)
print(y)

tensor(3.2745, grad_fn=<SumBackward0>)

y.backward()
print(embeddings.weight.grad)

tensor([[0., 0., 0.],
[1., 1., 1.],
[0., 0., 0.],
[0., 0., 0.]])

順伝播の時には $1$ の one-hot 表現 $\begin{pmatrix}0 & 1 & 0 & 0\end{pmatrix}$ に対応して

\begin{align*}
\begin{pmatrix}0 & 1 & 0 & 0\end{pmatrix} \begin{pmatrix}
0.2671 & 1.1044 & 0.4217 \\
0.5168 & 1.4011 & 1.3565 \\
2.3420 & -1.9554 & 0.0828 \\
-1.6999 & 0.3869 & 1.1587
\end{pmatrix} =
\begin{pmatrix}0.5168 & 1.4011 & 1.3565\end{pmatrix}
\end{align*}

が得られ、逆伝播ではインデックス $1$ に対応するところに値が入ってきて

\begin{align*}
\begin{pmatrix}
0 & 0 & 0 \\
1 & 1 & 1 \\
0 & 0 & 0 \\
0 & 0 & 0
\end{pmatrix}
\end{align*}

が得られていることがわかる。何で逆伝播をこう計算するのが良いのかはよく分からないけど。ゼロつく 2 本の通りなんだと思うけど、まだまだシックリとはこない。

・・・って、あぁ、そうか。ここで $x = \begin{pmatrix}0 & 1 & 0 & 0\end{pmatrix}$ は定数であって、これについて偏微分をとるのではなく、重み行列 $W = (w_{ij})$ のほうか。$f(W) = x \cdot W$ なので $\frac{\del f}{\del w_{ij}}$ で生き残るのは $i=1$ の行の成分だけになると。「Back propagation in an embedding layer」という記事が参考になった。