torch.nn.embedding函数的深入解析

  • 问题的开端
  • 过程解析
  • 总结
  • 其他


问题的开端

问题的起源从embedding开始,本人并不是以nlp为主,在看过一些论文和书籍后发现embedding有降维功能,但实际操作后,发现torch.nn.embedding这个函数将每一个元素都扩展成了embedding_dim的tensor,那么怎么达到降维的目的呢?根据在网上查到的博客,需要将元素的tensor加起来,才能降维。如果只理解到这里,问题已经解决,但是,该过程是怎么做的,我们不得而知。因此花了一些时间,阅读了torch.nn.embedding函数的源码,来和大家分享,节约下大家宝贵的科研时间。不一定全对,但是希望大家能提出错误并告诉我,我们一起学习。

过程解析

理论上,该过程主要由两条语句构成,分别是:

embedding = nn.Embedding()
out = embedding()

以上两个函数都省略了输入,作用分别对象的创建和调用forward函数,输入参数如下:

(self, num_embeddings, embedding_dim, padding_idx=None,
                 max_norm=None, norm_type=2., scale_grad_by_freq=False,
                 sparse=False, _weight=None)
(self, input)

可以看到,embedding对象的创建主要参数有两个,一个num_embeddings,一个是embedding_dim,分别代表嵌入字典的大小以及每个嵌入向量的大小。在源码中,这两个参数其实最重要的作用就是构建一个self.weight矩阵,该矩阵的行数就是num_embeddings,列数就是embedding_dim!由以下代码能看出:

self.weight = Parameter(torch.Tensor(num_embeddings, embedding_dim))
self.reset_parameters()

对于第二个函数,我们进入后,可以得到,他对weight进行了一个填充,约束是均值为0,标准差为1的正态分布,如下:

def normal_(tensor, mean=0., std=1.):

创建完对象后,其实结果的矩阵就已经定了,你得到了一个self.weight矩阵,该矩阵的大小为(num_embeddings,embedding_dim)。或者,你可以自定义self.weight,通过以下代码:

nn.Embedding.from_pretrained()

随后,通过

out = embedding(input)

它调用了forward方法,该方法调用了包下functional的embedding方法:

def forward(self, input):
    return F.embedding(
        input, self.weight, self.padding_idx, self.max_norm,
        self.norm_type, self.scale_grad_by_freq, self.sparse)

最终输入直接对应了获得的self.weight的行数,拿到结果tensor。

总结

该过程主要做了:
1.创建一个embedding对象,该对象中构建一个self.weight矩阵,矩阵的维度是(num_embeddings,embedding_dim),元素符合均值为0,标准差为1的正态分布
2.给出一个输入input,返回self.weight中input行的tensor

其他

本人阅读源码较少,可能有些错误,请大家指出并见谅,感谢各位大佬的阅读。