Transformer的前世今生 day08(Positional Encoding)

前情提要

  • Attention的优点:解决了长序列依赖问题,可以并行。Attention的缺点:开销变大了,而且不存在位置关系
  • 为了解决Attention中不存在位置关系的缺点,我们通过位置编码的形式加上位置关系

Positional Encoding(位置编码)

  • 通过在原输入词向量的基础上,给他加一个位置编码,组成新的输入词向量
    在这里插入图片描述
  • 位置编码的具体公式,如下:
    • 其中:pos指当前单词在句子中的位置,i指位置编码维度的第几维(通常来说词向量的维度为512,那么i就是0-511,表示第几维)
    • 所以,对于某个词的位置编码,偶数维度用了sin函数,奇数维度用了cos函数
      在这里插入图片描述
  • 得到位置编码后,与输入词向量X叠加后,得到新的输入词向量X’
    在这里插入图片描述
  • 由于sin和cos函数有以下公式,那么我们可以得到某一个位置的位置编码和其他两个位置的位置编码之间的关系,如下:
    在这里插入图片描述
  • 所以,当我们使用位置编码的这个函数时,对于pos+k位置的位置向量某一维2i或2i+1而言,可以表示为,pos位置与k位置的位置向量2i和2i+1的线性组合,而这个线性组合意味着pos+k的位置向量中蕴含了pos位置和k位置的位置信息
  • 而且这个位置编码的位置信息具有独特性,会随着我们输入句子的顺序改变而发生改变,比如“我爱你”中的你的位置编码,和“你爱我”中的你的位置编码所蕴含的位置信息就不同

参考文献

  1. 14 Positional Encoding (为什么 Self-Attention 需要位置编码)
  2. 1401 位置编码公式详细理解补充
  • 10
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Swin Transformer使用的是Learned Positional Encoding,如果要将其替换为Sinusoidal Positional Encoding,需要进行一些修改。 首先,可以定义一个Sinusoidal Positional Encoding的函数,如下所示: ```python import math import torch import torch.nn as nn class SinusoidalPositionalEmbedding(nn.Module): def __init__(self, d_model, max_len=512): super().__init__() self.d_model = d_model self.max_len = max_len pe = torch.zeros(max_len, d_model) position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1) div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model)) pe[:, 0::2] = torch.sin(position * div_term) pe[:, 1::2] = torch.cos(position * div_term) pe = pe.unsqueeze(0).transpose(0, 1) self.register_buffer('pe', pe) def forward(self, x): x = x * math.sqrt(self.d_model) seq_len = x.size(1) pe = self.pe[:seq_len, :] pe = pe.repeat(x.size(0), 1, 1) x = x + pe.to(x.device) return x ``` 然后,在Swin Transformer的构造函数中,将使用Learned Positional Encoding的部分替换为Sinusoidal Positional Encoding,如下所示: ```python import torch import torch.nn as nn from einops.layers.torch import Rearrange class SwinTransformer(nn.Module): def __init__(self, img_size=224, patch_size=4, in_chans=3, num_classes=1000, embed_dim=96, depths=[2, 2, 18, 2], num_heads=[3, 6, 12, 24], window_size=7, mlp_ratio=4., qkv_bias=True, qk_scale=None, drop_rate=0., attn_drop_rate=0., drop_path_rate=0.): super().__init__() norm_layer = nn.LayerNorm self.num_classes = num_classes self.num_features = self.embed_dim = embed_dim # stochastic depth decay rule dpr = [x.item() for x in torch.linspace(0, drop_path_rate, sum(depths))] # stochastic depth decay rule # patch embedding self.patch_embed = nn.Conv2d(in_chans, embed_dim, kernel_size=patch_size, stride=patch_size) self.norm1 = norm_layer(embed_dim) # pos embedding self.pos_embed = SinusoidalPositionalEmbedding(embed_dim, max_len=(img_size//patch_size)**2+1) # swin transformer blocks self.blocks = nn.ModuleList([ SwinTransformerBlock(dim=embed_dim, num_heads=num_heads[i], window_size=window_size, shift_size=window_size // 2 if i == 0 else 0, mlp_ratio=mlp_ratio, qkv_bias=qkv_bias, qk_scale=qk_scale, drop=drop_rate, attn_drop=attn_drop_rate, drop_path=dpr[sum(depths[:i]):sum(depths[:i+1])]) for i in range(len(depths))]) # norm before classifier self.norm2 = norm_layer(embed_dim) # classification head self.head = nn.Linear(embed_dim, num_classes) if num_classes > 0 else nn.Identity() def forward_features(self, x): x = self.patch_embed(x) x = self.norm1(x) x = x.flatten(2).transpose(1, 2) x = self.pos_embed(x) for i, blk in enumerate(self.blocks): x = blk(x) x = self.norm2(x) return x def forward(self, x): x = self.forward_features(x) x = x.mean(dim=1) # global average pooling x = self.head(x) return x ``` 这样,就完成了Swin Transformer模型中Positional Encoding形式的替换。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

丿罗小黑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值