PyTorch中嵌入层后立即加上偏置和线性层有什么区别?

15

我正在阅读《使用fastai和PyTorch进行深度学习》一书,对于嵌入模块的作用仍然感到有些困惑。它似乎是一个简短且简单的网络,但我无法理解嵌入与没有偏置的线性函数之间的区别。我知道它执行了某种更快的计算版本的点积,其中一个矩阵是one-hot编码矩阵,另一个矩阵是嵌入矩阵。它这样做是为了选择数据的一部分?请指出我的错误所在。以下是书中展示的一个简单网络。

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)
2个回答

23

嵌入

[...] 嵌入和没有偏置的线性模型有何不同。

从本质上讲,一切都不同。 torch.nn.Embedding 是一个查找表;它与 torch.Tensor 相同,但具有一些变化(例如可能使用稀疏嵌入或在指定索引处使用默认值)。

例如:

import torch

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

print(embedding.weight)

print(embedding(torch.tensor([1])))

将输出:

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>)

因此,我们取了嵌入的第一行。它仅仅做了这个。

它在哪里被使用?

通常当我们想要为每一行编码一些意义(例如word2vec),并且可能对它们进行训练时。

线性

torch.nn.Linear(不带偏差)也是一个torch.Tensor(权重),但它对其(和输入)执行的操作本质上是:

output = input.matmul(weight.t())
每次调用该层(请参见源代码此层的功能定义)。
代码片段
您代码片段中的层执行以下操作:
- 在__init__中创建两个查找表 - 使用形状为(batch_size, 2)的输入调用该层: - 第一列包含用户嵌入的索引 - 第二列包含电影嵌入的索引 - 这些嵌入被乘以并相加,返回(batch_size,)(因此与nn.Linear不同,后者将返回(batch_size, out_features)并执行点积而不是像这里一样执行逐元素乘法和求和) 这可能是用于一些类似推荐系统的目的来训练用户和电影的表示方法。
其他事项
“我知道它做了某种更快的计算版本的点积,其中一个矩阵是独热编码矩阵,另一个是嵌入矩阵。”
不,它没有。 torch.nn.Embedding可以进行独热编码,也可能是稀疏的,但取决于算法(以及它们是否支持稀疏性),可能会有性能提升或不提升。

2

简介

  • nn.Embedding 用于分类输入。
  • nn.Linear 用于序数输入。

解释

当处理分类数据时,例如类标签(0、1、2、...),您使用 nn.Embedding。因为在查找表中,值与键不成比例。这种行为适用于分类数据,其值与语义无关。

另一方面,nn.Linear 是矩阵乘法,不提供上述行为。由于乘法的自然性质,输入和输出成比例。因此,您使用 nn.Linear 处理序数数据。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接