详细介绍pytorch中的nn.Embedding()

  1. num_embeddings (python:int) – 词典的大小尺寸,比如总共出现5000个词,那就输入5000。此时index为(0-4999)
  2. embedding_dim (python:int) – 嵌入向量的维度,即用多少维来表示一个符号。
  3. padding_idx (python:int, optional) – 填充id,比如,输入长度为100,但是每次的句子长度并不一样,后面就需要用统一的数字填充,而这里就是指定这个数字,这样,网络在遇到填充id时,就不会计算其与其它符号的相关性。(初始化为0)
  4. max_norm (python:float, optional) – 最大范数,如果嵌入向量的范数超过了这个界限,就要进行再归一化。
  5. norm_type (python:float, optional) – 指定利用什么范数计算,并用于对比max_norm,默认为2范数。
  6. scale_grad_by_freq (boolean, optional) – 根据单词在mini-batch中出现的频率,对梯度进行放缩。默认为False.
  7. sparse (bool, optional) – 若为True,则与权重矩阵相关的梯度转变为稀疏张量。

后面的一堆东西,用过的都知道好像都没啥用是不是,那就别管它了。

其实一般就是前用两个参数
第2个参数 embedding_dim 就是嵌入向量的维度,即用embedding_dim值的维数来表示一个基本单位。
第1个参数 num_embeddings 就是生成num_embeddings个嵌入向量。
比如下面的代码,生成6个嵌入向量,每个嵌入向量的维度是2,
然后通过 .weight 看到生成的都是随机数:

embedding = nn.Embedding(6, 2)
print(embedding.weight)
Parameter containing:
tensor([[-0.7965, -0.2459],
        [ 1.1508, -0.7320],
        [ 0.0154, -0.2846],
        [ 0.2236, -0.0293],
        [ 0.5198, -1.1245],
        [ 0.7478,  0.3544]], requires_grad=True)

我们知道嵌入向量的每个值是随机数,那么这些随机数服从什么分布呢?

embedding = nn.Embedding(1, 3000)
m = embedding.weight[0]
print('均值:',torch.mean(m),'方差:',torch.var(m))
from scipy.stats import shapiro
print('结果:',shapiro(m.detach().numpy()))
均值: tensor(0.0049, grad_fn=<MeanBackward0>) 方差: tensor(0.9697, grad_fn=<VarBackward>)
结果: ShapiroResult(statistic=0.9994555711746216, pvalue=0.5714033246040344)

通过上面的代码我们可以看到数据的均值为0,方差为1。并且同时scipy.stats.shapiro可以检测数据是否符合正太分布,输出结果中第一个为统计量,统计量越接近1越代表数据和正态分布拟合的好,可以看到第一个值接近于1。所以我们可以知道:嵌入向量中的值是服从标准正态分布的。

那么我们是如何使用这些向量表示我们的词呢?
索引
看下面的代码:

embedding = nn.Embedding(6, 2)
x=torch.rand((3,2))*10
embedding(x)

这样的结果是报错,因为float不能作为索引:
要求输入必须是整数型

embedding = nn.Embedding(6, 2)
print('embedding.weight:',embedding.weight)
t = torch.ones((100,100)).to(int)
print('embedding(t):',embedding(t))
embedding.weight: Parameter containing:
tensor([[ 0.2666,  1.6938],
        [-0.2191,  0.2008],
        [ 0.0308,  0.3599],
        [ 0.6266, -1.1199],
        [ 2.0277, -0.3861],
        [-0.1880,  0.6900]], requires_grad=True)
embedding(t): tensor([[[-0.2191,  0.2008],
         [-0.2191,  0.2008],
         [-0.2191,  0.2008],
         ...,
         [-0.2191,  0.2008],
         [-0.2191,  0.2008],
         [-0.2191,  0.2008]],

        [[-0.2191,  0.2008],
         [-0.2191,  0.2008],
         [-0.2191,  0.2008],

输出结果很长,所以这里只展示一部分。我们先生成了一个 t , t 相当于我们的文本了,一共有100个句子,每个句子100个词。而我们对 t 的编码结果是每个词都是[-0.2191, 0.2008],我们发现这和embedding.weight[1]是一样的。因为Embedding就是根据索引值编码的。Embedding生成的每个嵌入向量都通过索引存储起来,以供后期编码使用。
又比如:

embedding = nn.Embedding(6, 2)
print('embedding.weight:',embedding.weight)
x=(torch.rand((3,2))*10).to(int)
print('x:',x)
print('embedding(x):',embedding(x))
embedding.weight: Parameter containing:
tensor([[-0.8326, -0.4983],
        [ 2.1820, -0.1443],
        [-0.4806, -0.1235],
        [ 0.3978, -0.2895],
        [ 1.2748, -1.1211],
        [-0.4095, -0.5246]], requires_grad=True)
x: tensor([[2, 6],
        [4, 5],
        [4, 7]])

以及报错:

我们可以看到报错信息索引超过了范围,因为Embedding的最大索引为5,而x中的6和7超过了这个值,所以就报错了。

并且nn.Embedding()是可以训练的,参考这个:
torch.nn.Embedding是否有梯度,是否会被训练

注:其实这个和nn.Parameter()的工作原理是一样的,都是先生成一些嵌入向量,然后调用它对自己的输入进行编码时,通过索引来取值编码。

来源:拒绝省略号

物联沃分享整理
物联沃-IOTWORD物联网 » 详细介绍pytorch中的nn.Embedding()

发表评论