def skip_gram(center, contexts_and_negatives, embed_v, embed_u):
v = embed_v(center)
u = embed_u(contexts_and_negatives)
pred = torch.bmm(v, u.permute(0, 2, 1))
return pred
net = nn.Sequential(nn.Embedding(num_embeddings=len(idx_to_token), embedding_dim=embed_size),
nn.Embedding(num_embeddings=len(idx_to_token), embedding_dim=embed_size))
pred = skip_gram(center, context_negative, net[0], net[1])
len(idx_to_token) = 512
embed_size = 100
那么v.shape = [512, 1, 100], u.shape = [512, 60, 100]
问题: 为啥skip_gram的前向传播直接是 vuT
为了便于说明,我们从v和u中直接拿一个"矩阵"来说明:
从v中拿一个batch, 假设为v1,且shape=[1, 100]; 从u中拿一个batch, 假设为u1,且shape=[60,100]; 为了方便举例,我们将两者的形状再次缩小,设v1.shape=[1, 3], u1.shape=[2, 3], 即设 v1=[0.5, 1,−0.1]u1=[0.1, 0.5, 0.2−0.5, 0.3, 0.8]
其中v1的一行代表一个中心词的向量;u1的每一行代表中心词上下文及噪声词的向量,所以v1u1T就表示中心词与每个上下文的词或噪声词的内积,假设u1的第一行是上下文词, 第二行是噪声词的向量,那么v1与u1第一行做内积结果应该趋向(上下文之间的词相似性更高), v1与u1第二行做内积结果应该趋向0(噪声词和中心词没啥关联),正好我们设置的label = [1, 0]这种格式, 通过交叉熵损失函数,迭代优化后会调整u1和v1的值(实际上是调整embed_v和embed_u),使得内积结果趋向label; 最终的词向量是embed_v,它每一行代表一个词的向量, 每个词的索引和行数对应
未完,待更新…
完整程序见:word2vec.py