Transformer为什么要有pos embedding

前几天面试面试官问了我一个问题,Transformer的编码部分用的是attention,那么它会不会在编码后几个单词的时候丢失掉前面的信息?Transformer为什么要有位置信息?想summary一下,小白一枚。

首先,个人感觉LSTM有点像串行结构,其最明显的特点是按单词顺序一个一个进行编码的,比如我在人民广场吃炸鸡:
input:[w1,w2,w3,w4,w5…w9]
但是在进行编码的时候隐状态h(t)的计算必须等到前t-1个隐变量计算完毕后才会开始计算,所以有点像串行结构。那么为什么LSTM模型后面词编码的时候会带有前面的信息呢?这是因为在计算h(t)时,是由w(t)、C(t-1)共同决定的,C(t-1)携带了前面单词的信息。

反过来看attention,attention并不像LSTM那样有时序概念,所以在用attention的时候得有pos embedding, 而lstm并不需要。还是刚刚那个我在人民广场吃炸鸡例子:
input:[w1,w2,w3,w4,w5…w9] word+pos-embedding
然后计算得出key,query,value; key和query做点积,做softmax运算计算出相似度,相似度乘以value为最终结果。用pos-embedding的原因是attention是为了来理解语言的顺序。

特别重要的一点:Transformer 与LSTM的一个明显区别:lstm作为rnn模型是迭代进行的,有语言顺序的,而Transformer是并行的,它没有时序关系。

在Vision Transformer中,1D位置嵌入和2D位置编码是通过在输入的图像或序列中添额外的位置信息来实现的。下面是实现1D位置嵌入和2D位置编码的代码示例: 1. 1D位置嵌入 ```python import torch import torch.nn as nn class ViT(nn.Module): def __init__(self, img_size=224, patch_size=16, num_classes=1000, dim=768, depth=12, heads=12, mlp_dim=3072, dropout=0.1): super().__init__() self.num_patches = (img_size // patch_size) ** 2 self.patch_size = patch_size self.pos_embedding = nn.Parameter(torch.randn(1, self.num_patches + 1, dim)) self.patch_embed = nn.Conv2d(3, dim, kernel_size=patch_size, stride=patch_size, bias=False) self.cls_token = nn.Parameter(torch.randn(1, 1, dim)) self.dropout = nn.Dropout(dropout) self.transformer = nn.ModuleList([ nn.TransformerEncoderLayer(d_model=dim, nhead=heads, dim_feedforward=mlp_dim, dropout=dropout) for _ in range(depth) ]) self.fc = nn.Linear(dim, num_classes) def forward(self, x): b, c, h, w = x.shape x = self.patch_embed(x).flatten(2).transpose(1, 2) x = torch.cat([self.cls_token.repeat(b, 1, 1), x], dim=1) x = x + self.pos_embedding[:, :(self.num_patches + 1)] x = self.dropout(x) for transformer_layer in self.transformer: x = transformer_layer(x) x = x.mean(dim=1) x = self.fc(x) return x ``` 在这个代码中,`self.pos_embedding` 是一个可学习的参数,其 shape 为 `(1, num_patches + 1, dim)`,其中 `num_patches` 是输入图像被分成的 patch 的数量,`dim` 是 Transformer 的隐藏维度。`self.cls_token` 是一个用于表示整个序列或图像的特殊 token,它也是一个可学习的参数,其 shape 为 `(1, 1, dim)`。在 forward 函数中,我们首先对输入图像进行 patch embedding,然后将 cls token 和位置嵌入到 patch embedding 的结果中。最后,我们将得到的序列输入到 Transformer 中。 2. 2D位置编码 ```python import torch import torch.nn as nn class ViT(nn.Module): def __init__(self, img_size=224, patch_size=16, num_classes=1000, dim=768, depth=12, heads=12, mlp_dim=3072, dropout=0.1): super().__init__() self.num_patches = (img_size // patch_size) ** 2 self.patch_size = patch_size self.pos_embedding = nn.Parameter(torch.randn(1, dim, img_size // patch_size, img_size // patch_size)) self.patch_embed = nn.Conv2d(3, dim, kernel_size=patch_size, stride=patch_size, bias=False) self.cls_token = nn.Parameter(torch.randn(1, 1, dim)) self.dropout = nn.Dropout(dropout) self.transformer = nn.ModuleList([ nn.TransformerEncoderLayer(d_model=dim, nhead=heads, dim_feedforward=mlp_dim, dropout=dropout) for _ in range(depth) ]) self.fc = nn.Linear(dim, num_classes) def forward(self, x): b, c, h, w = x.shape x = self.patch_embed(x).flatten(2).transpose(1, 2) x = torch.cat([self.cls_token.repeat(b, 1, 1), x], dim=1) x = x + self.pos_embedding x = self.dropout(x) for transformer_layer in self.transformer: x = transformer_layer(x) x = x.mean(dim=1) x = self.fc(x) return x ``` 在这个代码中,`self.pos_embedding` 是一个可学习的参数,其 shape 为 `(1, dim, img_size // patch_size, img_size // patch_size)`,其中 `img_size // patch_size` 是输入图像被分成的 patch 的数量。在 forward 函数中,我们首先对输入图像进行 patch embedding,然后将 cls token 和位置编码到 patch embedding 的结果中。最后,我们将得到的序列输入到 Transformer 中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值