【深度学习】位置编码

一、引言

Self-Attention并行的计算方式未考虑输入特征间的位置关系,这对NLP来说是不可接受的,毕竟一个句子中每个单词都有着明显的顺序关系。Transformer没有RNN、LSTM那样的顺序结构,所以Transformer在提出Self-Attention的同时提出了Positional Encoding。

如图所示,Transformer在Attention模块之前将位置编码加进了待输入特征中。

二、位置编码

首先需要明确NLP中数据的形式,一个批次包含多个句子,每个句子包含多个单词,每个单词被转为长度相同的token向量。由于每个句子中包含的单词数不同,所以会通过padding统一同一批次的embedding。假设一个批次padding后的embedding维度为 [ b a t c h _ s i z e , n u m _ t o k e n , d i m _ t o k e n ] [batch\_size,num\_token,dim\_token] [batch_size,num_token,dim_token]

1. 直观的位置编码

1.1 索引型

将token的索引作为位置编码,第一个token编码为0,第二个token编码为1,以此类推。

其主要问题在于位置编码的值无界

1.2 [0,1]型

为保证值有界,可限制位置编码范围为 [ 0 , 1 ] [0,1] [0,1],第一个token编码为0,最后一个token编码为1,其余token等间隔取值。例如共3个token时,位置编码为 [ 0 , 0.5 , 1 ] [0,0.5,1] [0,0.5,1],共4个token时,位置编码为 [ 0 , 0.33 , 0.66 , 1 ] [0,0.33,0.66,1] [0,0.33,0.66,1]

其主要问题在于两个句子的token个数不同时,两个相同位置间的相对距离不同。共3个token时,第三个与第一个token间距为1,但共4个token时,第三个与第一个token间距为0.66。

1.3 二进制型

为保证值有界句子长度不同时相对距离相同,可通过索引的二进制编码作为位置编码。下图为一个包含8个token,token向量长度为3的句子的位置编码。

如图,因为位置编码与embedding需要相加,所以通常位置编码的维度与embedding的维度相同。直白地说,有几个token就有几个位置编码,token向量的维度是多少位置编码向量的维度就是多少。

其主要问题在于二进制编码的位置向量处于离散空间,与输入相加后进入浮点世界,造成了空间上的浪费

不过,我们可以观察该类型位置编码的规律。纵向来看,每个维度的编码值变化频率不同蓝色变化周期为4,绿色变化周期为2,红色变化周期为1。

1.4 周期型

为保证值有界句子长度不同时相对距离相同节约空间,周期型位置编码包含了类似二进制型位置编码的变化规律,并将离散的二进制转为连续的 sin ⁡ \sin sin cos ⁡ \cos cos

sin ⁡ \sin sin为例,我们用 p o s pos pos表示embedding中token的索引,用 i i i表示token上元素的索引。于是第 p o s pos pos个token的位置编码可以表示如下:
P E ( p o s ) = [ sin ⁡ ( p o s 2 0 ) , sin ⁡ ( p o s 2 1 ) , ⋯ , sin ⁡ ( p o s 2 i ) , ⋯ , sin ⁡ ( p o s 2 d i m _ t o k e n − 1 ) ] PE_{(pos)}=[\sin(\frac{pos}{2^0}),\sin(\frac{pos}{2^1}),\cdots,\sin(\frac{pos}{2^i}),\cdots,\sin(\frac{pos}{2^{dim\_token-1}})] PE(pos)=[sin(20pos),sin(21pos),,sin(2ipos),,sin(2dim_token1pos)]

其中, p o s = 0 , 1 , ⋯ , n u m _ t o k e n − 1 pos=0,1,\cdots,num\_token-1 pos=0,1,,num_token1 i = 0 , 1 , ⋯ , d i m _ t o k e n − 1 i=0,1,\cdots,dim\_token-1 i=0,1,,dim_token1

可见,每个维度上 1 2 i \frac{1}{2^i} 2i1被用来控制变化规律,详情如下图。

但是,使用 1 2 i \frac{1}{2^i} 2i1来控制变化规律会使 P E ( p o s ) PE_{(pos)} PE(pos)很快形成一个闭环。

如图,当 d i m _ t o k e n = 3 dim\_token=3 dim_token=3时,以 0.1 0.1 0.1的间隔在 [ 0 , 20 ] [0,20] [0,20] p o s pos pos,得到200个 P E ( p o s ) PE_{(pos)} PE(pos),前100个点为蓝色,后100个点为橙色,可以清晰看到它们的重叠部分。这表明即便 p o s pos pos不同, P E ( p o s ) PE_{(pos)} PE(pos)也有很多点的值是相同的,但我们希望位置编码像地址一样是独一无二的,所以我们使用 1 1000 0 i / d i m _ t o k e n \frac{1}{10000^{i/dim\_token}} 10000i/dim_token1替换 1 2 i \frac{1}{2^i} 2i1来控制变化规律。此时, P E ( p o s ) PE_{(pos)} PE(pos)如下图,不再有重叠。

于是有:
P E ( p o s ) = [ sin ⁡ ( w 0 p o s ) , sin ⁡ ( w 1 p o s ) , ⋯ , sin ⁡ ( w i p o s ) , ⋯ , sin ⁡ ( w d i m _ t o k e n − 1 p o s ) ] PE_{(pos)}=[\sin(w_0pos),\sin(w_1pos),\cdots,\sin(w_ipos),\cdots,\sin(w_{dim\_token-1}pos)] PE(pos)=[sin(w0pos),sin(w1pos),,sin(wipos),,sin(wdim_token1pos)]

其中, w i = 1 1000 0 i / d i m _ t o k e n w_i=\frac{1}{10000^{i/dim\_token}} wi=10000i/dim_token1

但它仍有一个问题,不同位置编码无法相互线性转换

2. Sinusoidal位置编码

为保证值有界句子长度不同时相对距离相同节约空间不同位置编码可相互线性转换,Sinusoidal型位置编码交替使用 sin ⁡ \sin sin cos ⁡ \cos cos,于是第 p o s pos pos个token的位置编码可表示如下:
P E ( p o s ) = [ sin ⁡ ( w 0 p o s ) , cos ⁡ ( w 0 p o s ) , ⋯ , sin ⁡ ( w i p o s ) , cos ⁡ ( w i p o s ) , ⋯ , sin ⁡ ( w d i m _ t o k e n 2 − 1 p o s ) , cos ⁡ ( w d i m _ t o k e n 2 − 1 p o s ) ] PE_{(pos)}=[\sin(w_0pos),\cos(w_0pos),\cdots,\sin(w_ipos),\cos(w_ipos),\cdots,\sin(w_{\frac{dim\_token}{2}-1}pos),\cos(w_{\frac{dim\_token}{2}-1}pos)] PE(pos)=[sin(w0pos),cos(w0pos),,sin(wipos),cos(wipos),,sin(w2dim_token1pos),cos(w2dim_token1pos)]

其中, p o s = 0 , 1 , ⋯ , n u m _ t o k e n − 1 pos=0,1,\cdots,num\_token-1 pos=0,1,,num_token1 i = 0 , 1 , ⋯ , d i m _ t o k e n 2 − 1 i=0,1,\cdots,\frac{dim\_token}{2}-1 i=0,1,,2dim_token1 w i = 1 1000 0 i / d i m _ t o k e n w_i=\frac{1}{10000^{i/dim\_token}} wi=10000i/dim_token1

该形式下 P E ( p o s ) PE_{(pos)} PE(pos)可以线性变换,可由下式证明:
P E ( p o s + Δ p o s ) = ( sin ⁡ ( w 0 ( p o s + Δ p o s ) ) cos ⁡ ( w 0 ( p o s + Δ p o s ) ) ⋯ sin ⁡ ( w d i m _ t o k e n 2 − 1 ( p o s + Δ p o s ) ) cos ⁡ ( w d i m _ t o k e n 2 − 1 ( p o s + Δ p o s ) ) ) = ( [ cos ⁡ ( w 0 Δ p o s ) sin ⁡ ( w 0 Δ p o s ) − sin ⁡ ( w 0 Δ p o s ) cos ⁡ ( w 0 Δ p o s ) ] ⋯ 0 ⋯ ⋯ ⋯ 0 ⋯ [ cos ⁡ ( w d i m _ t o k e n 2 − 1 Δ p o s ) sin ⁡ ( w d i m _ t o k e n 2 − 1 Δ p o s ) − sin ⁡ ( w d i m _ t o k e n 2 − 1 Δ p o s ) cos ⁡ ( w d i m _ t o k e n 2 − 1 Δ p o s ) ] ) ( sin ⁡ ( w 0 p o s ) cos ⁡ ( w 0 p o s ) ⋯ sin ⁡ ( w d i m _ t o k e n 2 − 1 p o s ) cos ⁡ ( w d i m _ t o k e n 2 − 1 p o s ) ) = T Δ p o s ∗ P E ( p o s ) \begin{split} PE_{(pos+\Delta pos)} &= \left(\begin{array}{c} \sin(w_0(pos+\Delta pos))\\ \cos(w_0(pos+\Delta pos))\\ \cdots\\ \sin(w_{\frac{dim\_token}{2}-1}(pos+\Delta pos))\\ \cos(w_{\frac{dim\_token}{2}-1}(pos+\Delta pos)) \end{array}\right)\\ &= \left(\begin{array}{c} \left[\begin{array}{c} \cos(w_0\Delta pos)&\sin(w_0\Delta pos)\\ -\sin(w_0\Delta pos)&\cos(w_0\Delta pos) \end{array}\right]&\cdots&0\\ \cdots&\cdots&\cdots\\ 0&\cdots&\left[\begin{array}{c} \cos(w_{\frac{dim\_token}{2}-1}\Delta pos)&\sin(w_{\frac{dim\_token}{2}-1}\Delta pos)\\ -\sin(w_{\frac{dim\_token}{2}-1}\Delta pos)&\cos(w_{\frac{dim\_token}{2}-1}\Delta pos) \end{array}\right]\\ \end{array}\right) \left(\begin{array}{c} \sin(w_0pos)\\ \cos(w_0pos)\\ \cdots\\ \sin(w_{\frac{dim\_token}{2}-1}pos)\\ \cos(w_{\frac{dim\_token}{2}-1}pos) \end{array}\right)\\ &= T_{\Delta pos}*PE_{(pos)} \end{split} PE(pos+Δpos)= sin(w0(pos+Δpos))cos(w0(pos+Δpos))sin(w2dim_token1(pos+Δpos))cos(w2dim_token1(pos+Δpos)) = [cos(w0Δpos)sin(w0Δpos)sin(w0Δpos)cos(w0Δpos)]00[cos(w2dim_token1Δpos)sin(w2dim_token1Δpos)sin(w2dim_token1Δpos)cos(w2dim_token1Δpos)] sin(w0pos)cos(w0pos)sin(w2dim_token1pos)cos(w2dim_token1pos) =TΔposPE(pos)

实际上,是用到如下和角公式中的第1项和第3项:

三、应用

1. Transformer中的位置编码

1.1 简介

上述Sinusoidal位置编码是在Transformer中针对NLP问题提出的。一个 n u m _ t o k e n = 50 , d i m _ t o k e n = 128 num\_token=50,dim\_token=128 num_token=50,dim_token=128的句子的位置编码如下图:

纵向来看,不同列的变化频率不同,从左到右频率依次下降。即使后58个维度无变化,为保证位置编码与embedding维度相同,仍然保留完整的128个维度。

位置编码在Transformer模型中的作用主要体现在以下几个方面:

(1) 捕捉词序信息:由于位置编码与词的位置相关,因此它们可以帮助模型理解输入序列中词的顺序。这对于依赖关系分析、句法分析等任务非常重要。
(2) 防止重复使用相同输入:由于位置编码是随机的,相同的输入序列会产生不同的位置编码。这有助于防止模型重复使用相同的输入来生成输出,从而提高模型的多样性和泛化能力。
(3) 增加模型的鲁棒性:位置编码的随机性可以帮助模型更好地处理噪声和异常值,从而提高其鲁棒性。

在实际应用中,位置编码通常在自注意力机制之前添加到输入序列中。这样,自注意力机制可以同时考虑词的语义信息和位置信息,从而更好地捕捉输入序列中的依赖关系。

1.2 实现

import torch.nn as nn
import torchclass PositionalEncoding(nn.Module):def __init__(self, dim_token, max_num_token=5000):super(PositionalEncoding, self).__init__()self.encoding = torch.zeros(max_num_token, dim_token)pos = torch.arange(0, max_num_token).unsqueeze(dim=1)  # 不是每次实时计算,而是预估一个pos上限_2i = torch.arange(0, dim_token, step=2)  # 共计算dim_token/2-1次,每次计算两个值sin和cosself.encoding[:, 0::2] = torch.sin(pos / (10000 ** (_2i / dim_token)))self.encoding[:, 1::2] = torch.cos(pos / (10000 ** (_2i / dim_token)))def forward(self, x):batch_size, num_token, dim_token = x.size()return self.encoding[:num_token, :]  # num_token是padding前单词的数量if __name__ == '__main__':x = torch.randn((2, 3, 6))  # [batch_size,num_token,dim_token]pe = PositionalEncoding(6)  # dim_token必须是偶数y = pe(x)

2. DETR中的位置编码

2.1 简介

DETR将Transformer用在了CV的目标检测任务中,目标检测要求预测目标框,因此位置信息也很重要,所以也需要引入位置编码。DETR引入的位置编码也是Sinusoidal形式的。

不过,图像的维度与句子的维度不同。句子维度为 [ b a t c h _ s i z e , n u m _ t o k e n , d i m _ t o k e n ] [batch\_size,num\_token,dim\_token] [batch_size,num_token,dim_token],Transformer中位置编码与句子维度相同,一个位置编码向量表示一个句子(位置编码向量长度 = d i m _ t o k e n =dim\_token =dim_token)。图像维度为 [ b a t c h _ s i z e , n u m _ c h a n n e l , h e i g h t , w i d t h ] [batch\_size,num\_channel,height,width] [batch_size,num_channel,height,width],DETR中一个位置编码向量表示一个像素(位置编码向量长度 = n u m _ c h a n n e l =num\_channel =num_channel,一半的向量表示横坐标,另一半表示纵坐标)。此外,DETR还考虑了padding问题,仅针对非padding区域计算位置编码。

不仅如此,DETR中位置编码仅在Attention的 Q Q Q K K K中,而Transformer在 Q Q Q K K K V V V上都有。

2.2 实现

import torch.nn as nn
import torchclass PositionEmbeddingSine(nn.Module):def __init__(self, num_channel=64, temperature=10000):super().__init__()self.num_channel = num_channelself.temperature = temperaturedef forward(self, mask):assert mask is not Nonenot_mask = ~mask  # mask中True表示padding区域,False表示非padding区域pos_y = not_mask.cumsum(1)  # 如果是padding区域,pos不增加pos_x = not_mask.cumsum(2)  # 横、纵坐标均计算posi = torch.arange(self.num_channel)wi = self.temperature ** (2 * (i // 2) / self.num_channel)  # 2i = i // 2pos_x = pos_x[:, :, :, None] / wi  # 所有像素都有num_channel/2个横坐标pos_y = pos_y[:, :, :, None] / wi  # 所有像素都有num_channel/2个纵坐标pos_x = torch.stack((pos_x[:, :, :, 0::2].sin(), pos_x[:, :, :, 1::2].cos()), dim=4).flatten(3)  # 原本dim只到3,在第4个维度上stack然后flatten能使sin和cos交替出现pos_y = torch.stack((pos_y[:, :, :, 0::2].sin(), pos_y[:, :, :, 1::2].cos()), dim=4).flatten(3)pos = torch.cat((pos_y, pos_x), dim=3).permute(0, 3, 1, 2)  # 前半部分为纵坐标,后半部分为横坐标return posif __name__ == '__main__':x = torch.randn((8, 4, 5, 6))  # [batch_size,num_channel,height,width]mask = torch.zeros((8, 5, 6))  # 同一图像上mask在每个通道上都一样mask = mask.bool()  # 默认没有paddingpes = PositionEmbeddingSine(2)  # num_channel必须是偶数,这里输入的是num_channel/2,一半用于横坐标,另一半用于纵坐标y = pes(mask)

致谢:

本博客仅做记录使用,无任何商业用途,参考内容如下:
四种Position Embedding的原理与PyTorch手写逐行实现(Transformer/ViT/Swin-T/MAE)
【Transformer系列】深入浅出理解Positional Encoding位置编码
Transformer学习笔记一:Positional Encoding(位置编码)
DE⫶TR: End-to-End Object Detection with Transformers

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/6539.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

H.265 与 H.264 的主要区别

H.265 与 H.264 的主要区别 H.265 与 H.264 的主要区别各模块技术差异汇总宏块划分帧内预测模式帧间预测模式去块滤波ALF自适应环路滤波采样点自适应偏移(Sample Adaptive Offset)滤波并行化设计TileEntropy sliceDependent SliceWPP(Wavefro…

【C语言】命令行参数

执行程序时,可以从命令行传值给C程序。这些值被称为命令行参数。它们对程序很重要,特别是您想从外部控制程序,而不是在代码内对这些值进行硬编码时,就显得尤为重要了。 命令行参数是使用main()函数参数来处理的,其中&…

双fifo流水线操作——verilog练习与设计

文章目录 一、案例分析二、fifo_ctrl模块设计2.1 波形设计:2.2 代码实现2.2.1 fifo_ctrl2.2.2 顶层文件top_fifo_ctrl(rx和tx模块省略)2.2.3 仿真文件tb_fifo_ctrl 2.3波形仿真 一、案例分析 案例要求:写一个 fifo 控制器&#x…

SPARC VScode EIDE GDB 使用配置

前言 搞了多年的SPARC 最近接触了VSCODE插件感觉好用。想想看不是能方便调试和编译SPARC,决定使用开源的SPARC仿真环境和编译器来试试。感觉的却不错,借此献给使用SPARC的朋友们。安装 1.找微软官方的下载VSCODE. 2.电机左边的方块形状的图标&#xff0…

【强训笔记】day8

NO.3 思路&#xff1a;相乘除以最大公约数等于最小公倍数。最小公倍数等于gcd&#xff08;a&#xff0c;a%b&#xff09;递归直到b等于0。 代码实现&#xff1a; #include <iostream> using namespace std;int gcd(int a,int b) {if(b0) return a;return gcd(b,a%b); }…

【代码随想录】day48

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、198打家劫舍二、213打家劫舍II三、337打家劫舍III 一、198打家劫舍 class Solution { public:int rob(vector<int>& nums) {vector<int> dp(n…

二叉树的迭代遍历 | LeetCode 144. 二叉树的前序遍历、LeetCode 94. 二叉树的中序遍历、LeetCode 145. 二叉树的后序遍历

二叉树的前序遍历&#xff08;迭代法&#xff09; 1、题目 题目链接&#xff1a;144. 二叉树的前序遍历 给你二叉树的根节点 root &#xff0c;返回它节点值的 前序 遍历。 示例 1&#xff1a; 输入&#xff1a;root [1,null,2,3] 输出&#xff1a;[1,2,3]示例 2&#x…

JG/T 464-2014 集成材木门窗检测

集成材是指将木材的纤维方向基本平行的板材、小方材等在长度、宽度和厚度方向上集成胶合而成的材料&#xff0c;以集成材为主要受力构件制作的门窗&#xff0c;称为集成材木门窗。 JG/T 464-2014集成材木门窗检测项目 测试项目 测试标准 外观及表面质量 LY/T 1787 GB/T 928…

Android 安装过程三 MSG_ON_SESSION_SEALED、MSG_STREAM_VALIDATE_AND_COMMIT的处理

Android 安装过程一 界面跳转 知道&#xff0c;在InstallInstalling Activity中&#xff0c;PackageInstallerSession对象创建之后&#xff0c;接着会打开它&#xff0c;然后将安装文件进行拷贝&#xff0c;拷贝完成之后&#xff0c;会对Session对象确认。   从Session对象确…

MoE(Mixture of Experts,混合专家模型

MoE(Mixture of Experts,混合专家模型)是一种模型架构,它通过组合多个子模型(即“专家”)来提高模型的预测性能和效率。每个子模型专门处理输入空间的一个子集,而一个门控网络决定每个数据应该由哪个模型进行训练,以减少不同样本类型之间的干扰。这种架构能够在不损失性…

【北京仁爱堂】事出有因,原来是“肝”出现问题,才导致了痉挛性斜颈

痉挛性斜颈是肌张力障碍疾病中的一种&#xff0c;局限于颈部肌肉。由于颈部肌肉间断或持续的不自主的收缩&#xff0c;导致头颈部扭曲、歪斜、姿势异常。一般在30&#xff5e;40岁发病。由于痉挛性斜颈病因不明&#xff0c;西医方面药物及手术的临床疗效不甚理想&#xff0c;而…

初识Vue-组件通信(详解props和emit)

目录 一、组件通信介绍 1.概念 2.作用 3.特点 4.应用 二、组件通信语法 1.Props 1.1.在子组件中声明 props 1.2.在父组件中传递数据 2.Emit 2.1.在子组件中触发事件 2.2.在父组件中监听事件 三、应用实例 1. 购物车组件 2. 表单数据处理 四、总结 一、组件通信介…

std::sort并不支持所有的容器

std::sort并不支持所有的容器&#xff0c;无法对std::list使用std::sort()&#xff0c;但可以使用std::list的方法sort()。 #include <iostream> #include <string> #include <vector> #include <list> #include <algorithm> // std::sortin…

PHP 反序列化

一、PHP 序列化 1、对象的序列化 <?php class people{public $nameGaming;private $NationLiyue;protected $Birthday12/22;public function say(){echo "老板你好呀&#xff0c;我是和记厅的镖师&#xff0c;叫我嘉明就行&#xff0c;要运货吗你&#xff1f;"…

Linux查看某一个程序的安装路径

前提 这一方法的前提条件是&#xff1a;必须是运行着的程序。 方法 这里以查找运行的nginx的安装目录为例。 查看nginx运行进程&#xff0c;查看当前进程的PID&#xff0c;例子中的PID就是7992。 nginps -aux|grep nginx执行ls -l /proc/进程号/exe&#xff0c;然后会打印…

containerd的原理及应用详解(三)

本系列文章简介&#xff1a; 随着容器技术的迅猛发展&#xff0c;容器运行时成为了关注的焦点之一。而容器运行时的核心组件之一就是containerd。containerd是一个高度可扩展的容器运行时&#xff0c;它负责管理容器的生命周期、镜像管理以及资源隔离等核心功能。它是由Docker团…

android zygote进程启动流程

一&#xff0c;启动入口 app_main.cpp int main(int argc, char* const argv[]) {if (!LOG_NDEBUG) {String8 argv_String;for (int i 0; i < argc; i) {argv_String.append("\"");argv_String.append(argv[i]);argv_String.append("\" ")…

锂电池充放电方式曲线

作为一种“化学能-电能”相互转换的能量装置&#xff0c;锂电池在使用过程中必然会进行充电和放电&#xff0c;合理的充放电方式既能减轻锂电池的损伤程度&#xff0c;又能充分发挥锂电池的性能&#xff0c;具有重要的应用价值。 如《GB/T 31484-2015&#xff1a;电动汽车用动…

Server 2022 IIS10 PHP 7.2.33 升级至 PHP 8.3 (8.3.6)

下载最新版本 PHP 8.3 (8.3.6)&#xff0c;因为是 FastCGI 执行方式&#xff0c;选择 Non Thread Safe(非线程安全)。 若有以下提示&#xff1a; The mysqli extension is missing. Please check your PHP configuration. 或者 PHP Fatal error: Uncaught Error: Class &qu…

[C++基础学习-05]----C++函数详解

前言 在学习C的基础阶段&#xff0c;函数是一个非常重要的概念。函数是用来完成特定任务的一段代码&#xff0c;它可以被多次调用&#xff0c;并且可以接受参数和返回值。 正文 01-函数简介 函数的定义&#xff1a; 在C中&#xff0c;函数的定义通常包括函数的返回类…