如何为 Transformer 实现位置明智的前馈神经网络?

问题描述 投票:0回答:4

我很难理解 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
层的东西,该层将具有不同的权重和偏差,以实现与图片中所示类似的效果。

machine-learning pytorch neural-network transformer-model
4个回答
5
投票

我也有同样的疑问,但我确实同意@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)的张量时,该层将独立地应用于批次和序列的所有标记嵌入

最终,重要的是要观察到,通过这种方式您可以获得批次中每个令牌的隐藏状态
,这使得架构非常灵活。

它确实只是一个单一的前馈网络,而不是每个位置都有一个单独的前馈网络。我不知道为什么论文说“位置明智”。正如你所说,这里没有什么真正的位置明智的东西。


1
投票
权重为一层共享。自注意力之后,假设所有变换后的向量位于同一向量空间中。因此,相同类型的变换可以应用于每个向量。这种直觉也用于其他一些任务,例如序列标记,其中每个标记共享相同的分类头。这减少了网络的参数并迫使自注意力来承担繁重的工作。

引用您提供的链接,

1
投票

虽然不同位置的线性变换是相同的,但它们在层与层之间使用不同的参数。

传入
x

函数的

forward
是单个词向量

z_i

,而不是列表。

我会直观地回答为什么它是位置明智的。
根据问题中的代码定义是否批量输入维度(批次、序列长度、d_model)
请注意,FF 层的输入维度是 d_model,这意味着相同的网络同时应用于特征维度(d_model)上的每个标记。
上面 @amiola 的答案中的例子用数字解释了这个概念。


0
投票
© www.soinside.com 2019 - 2024. All rights reserved.