我很难理解 Transformer 架构中的位置明智前馈神经网络。
让我们以机器翻译任务为例,其中输入是句子。从图中我了解到,对于每个单词,不同的前馈神经网络用于自注意力子层的输出。前馈层应用类似的线性变换,但每个变换的实际权重和偏差不同,因为它们是两个不同的前馈神经网络。
参考Link,这是
PositionWiseFeedForward
神经网络的类
class PositionwiseFeedForward(nn.Module):
"Implements FFN equation."
def __init__(self, d_model, d_ff, dropout=0.1):
super(PositionwiseFeedForward, self).__init__()
self.w_1 = nn.Linear(d_model, d_ff)
self.w_2 = nn.Linear(d_ff, d_model)
self.dropout = nn.Dropout(dropout)
def forward(self, x):
return self.w_2(self.dropout(F.relu(self.w_1(x))))
我的问题是:
我没有看到任何关于此的立场。这是一个简单的两层全连接神经网络。假设
x
是句子中每个单词的嵌入列表,句子中的每个单词都由上层使用相同的权重和偏差集进行转换。(如果我错了,请纠正我)
我期待找到类似将每个单词嵌入传递到单独的
Linear
层的东西,该层将具有不同的权重和偏差,以实现与图片中所示类似的效果。
我也有同样的疑问,但我确实同意@Rabin Adhikari 的回答。
在提供的实现中,传递给
x
方法的 forward
是形状为 (batch_size, sequence_length, embedding_dimension)
的张量,而不是其扁平版本(形状为 (batch_size, sequence_length * embedding_dimension)
)。 (相同的)前馈层仅适用于每个批次和序列中每个位置的最后一个维度(嵌入维度),因此position-wise。
这解释了论文中的引用,该引用也在下面的答案和您的问题中
虽然不同位置的线性变换是相同的,但它们从(编码器)层到(编码器)层使用不同的参数。
很容易看出,向位置前馈层提供由重复相同标记组成的序列(此处由通过
torch.ones()
获得的简单嵌入表示),您会为每个标记获得相同的输出嵌入。
feed_forward = PositionwiseFeedForward(d_model=5, d_ff=3, dropout=0)
input_embeddings = torch.ones(1, 10, 5)
ff_outputs = feed_forward(input_embeddings)
ff_outputs, ff_outputs.shape
# --> (tensor([[[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252],
[-0.5512, -0.3976, 0.4570, 0.5153, 0.4252]]],
grad_fn=<ViewBackward0>), torch.Size([1, 10, 5]))
我还想引用《使用 Transformers 进行自然语言处理》一书的引用
请注意,诸如nn.Linear
之类的前馈层通常应用于形状为
的张量,它独立地作用于批次的每个元素(batch_size, input_dim)
。这实际上对于除最后一个维度之外的任何维度都是正确的,因此,当我们传递形状为(batch_size, seq_len, hidden_dim)
的张量时,该层将独立地应用于批次和序列的所有标记嵌入。 最终,重要的是要观察到,通过这种方式您可以获得批次中每个令牌的隐藏状态,这使得架构非常灵活。
它确实只是一个单一的前馈网络,而不是每个位置都有一个单独的前馈网络。我不知道为什么论文说“位置明智”。正如你所说,这里没有什么真正的位置明智的东西。
引用您提供的链接,
虽然不同位置的线性变换是相同的,但它们在层与层之间使用不同的参数。
传入
是单个词向量x
函数的
forward
z_i
,而不是列表。
我会直观地回答为什么它是位置明智的。 根据问题中的代码定义是否批量输入维度(批次、序列长度、d_model) 请注意,FF 层的输入维度是 d_model,这意味着相同的网络同时应用于特征维度(d_model)上的每个标记。 上面 @amiola 的答案中的例子用数字解释了这个概念。