PyTorch 中带有偏置的嵌入层和线性层之间有什么区别

Pet*_*man 3 python oop deep-learning pytorch fast-ai

我正在阅读“使用 fastai 和 PyTorch 为编码人员进行深度学习”一书。对于 Embedding 模块的作用,我仍然有些困惑。它似乎是一个简短而简单的网络,但我似乎无法理解 Embedding 与没有偏见的 Linear 的不同之处。我知道它做了一些更快的点积计算版本,其中一个矩阵是一个单热编码矩阵,另一个是嵌入矩阵。这样做实际上是为了选择一条数据?请指出我错在哪里。这是书中展示的简单网络之一。

class DotProduct(Module):
    def __init__(self, n_users, n_movies, n_factors):
        self.user_factors = Embedding(n_users, n_factors)
        self.movie_factors = Embedding(n_movies, n_factors)
        
    def forward(self, x):
        users = self.user_factors(x[:,0])
        movies = self.movie_factors(x[:,1])
        return (users * movies).sum(dim=1)
Run Code Online (Sandbox Code Playgroud)

Szy*_*zke 5

嵌入

[...] 嵌入与没有偏差的线性的不同之处。

基本上一切。torch.nn.Embedding是一个查找表;本质上与工作原理相同,torch.Tensor但有一些曲折(例如在指定索引处使用稀疏嵌入或默认值的可能性)。

例如:

import torch

embedding = torch.nn.Embedding(3, 4)

print(embedding.weight)

print(embedding(torch.tensor([1])))
Run Code Online (Sandbox Code Playgroud)

会输出:

Parameter containing:
tensor([[ 0.1420, -0.1886,  0.6524,  0.3079],
        [ 0.2620,  0.4661,  0.7936, -1.6946],
        [ 0.0931,  0.3512,  0.3210, -0.5828]], requires_grad=True)
tensor([[ 0.2620,  0.4661,  0.7936, -1.6946]], grad_fn=<EmbeddingBackward>)
Run Code Online (Sandbox Code Playgroud)

所以我们基本上采用了嵌入的第一行。它的作用不止于此。

它在哪里使用?

通常当我们想要为每一行编码一些含义(如 word2vec)时(例如,语义上接近的单词在欧几里得空间中接近)并可能训练它们

线性

torch.nn.Linear(没有偏差)也是一个torch.Tensor(权重),它对它(和输入)进行操作,本质上是:

output = input.matmul(weight.t())
Run Code Online (Sandbox Code Playgroud)

每次调用该层时(请参阅该层的源代码功能定义)。

代码片段

代码片段中的层基本上是这样的:

  • 在其中创建两个查找表 __init__
  • 该层使用形状输入调用(batch_size, 2)
    • 第一列包含用户嵌入的索引
    • 第二列包含电影嵌入的索引
  • 这些嵌入相乘并求和返回(batch_size,)(因此它与nn.Linear返回(batch_size, out_features)并执行点积而不是按元素乘法然后求和的方法不同,如下所示)

这可能用于训练一些类似推荐系统的表示(用户和电影)。

其他的东西

我知道它做了一些更快的点积计算版本,其中一个矩阵是一个单热编码矩阵,另一个是嵌入矩阵。

不,它没有。torch.nn.Embedding 可以是一种热编码,也可能是稀疏的,但取决于算法(以及那些是否支持稀疏性),会有加速或没有加速。