介绍:
Embedding()
的作用不一定是针对单词嵌入,也可以应付推荐系统中用户和商品的嵌入。例子代码1
import torch
import torch.nn as nn
# 创建10个维度大小为3的嵌入向量
embedding=nn.Embedding(10,3)
input=torch.LongTensor([[1,2,4],[4,3,2]]) # 索引列表
print(embedding(input)) # 通过索引列表获取相应索引的嵌入向量
tensor([[[-0.5383, 0.0499, -0.7475],
[ 0.9555, 0.2302, -0.1948],
[-0.9377, -0.2700, 0.1331]],
[[-0.9377, -0.2700, 0.1331],
[ 0.3063, -0.8556, -0.1219],
[ 0.9555, 0.2302, -0.1948]]], grad_fn=<EmbeddingBackward>)
如果从词向量的角度来看可以有下面解释:
第一个参数是字的总数,第二个参数是字的向量表示的维度。
我们的输入input是两个句子,每个句子都是由四个字组成的,使用每个字的索引来表示,于是使用nn.Embedding对输入进行编码,每个字都会编码成长度为3的向量。
例子代码2
"""
padding_idx(int,可选):如果指定,则 `padding_idx` 处的条目对梯度没有贡献;
因此,在训练期间不会更新`padding_idx`索引的嵌入向量,即它仍然是一个固定的“pad”(填充)。
一般设置为0,因为这样就可以使索引从1开始计算了
"""
padding_idx = 0
embedding = nn.Embedding(10, 3, padding_idx=padding_idx) #
input = torch.LongTensor([0, 0, 1, 1, 2, 2, 5])
print(embedding(input))
tensor([[ 0.0000, 0.0000, 0.0000],
[ 0.0000, 0.0000, 0.0000],
[ 0.3913, 0.1981, -0.4038],
[ 0.3913, 0.1981, -0.4038],
[-1.0189, 0.3309, 0.2123],
[-1.0189, 0.3309, 0.2123],
[ 1.1989, -0.4495, -0.6550]], grad_fn=<EmbeddingBackward>)
# 索引0的向量全是0, 不参与训练
我是因为看了一下Transformer的代码才查询了这个API,下面是他的Embeddings
类
我是看到
Transformer
的词向量后面还要乘以math.sqrt(self.d_model)
感到很奇怪,所以查询了一下
class Embeddings(nn.Module):
def __init__(self,d_model,vocab):
#d_model=512 嵌入维度, vocab=当前语言的词表大小
super(Embeddings,self).__init__()
self.lut=nn.Embedding(vocab,d_model)
# one-hot转词嵌入,这里有一个待训练的矩阵E,大小是vocab*d_model
self.d_model=d_model # 512
def forward(self,x):
# x ~ (batch.size, sequence.length, one-hot),
#one-hot大小=vocab,当前语言的词表大小
return self.lut(x)*math.sqrt(self.d_model)
# 得到的10*512词嵌入矩阵,主动乘以sqrt(512)=22.6,
#这里我做了一些对比,感觉这个乘以sqrt(512)没啥用… 求反驳。
#这里的输出的tensor大小类似于(batch.size, sequence.length, 512)