【Transformer系列】深入浅出理解Positional Encoding位置编码

news2024/11/28 9:43:14

一、参考资料

一文教你彻底理解Transformer中Positional Encoding
Transformer Architecture: The Positional Encoding
The Annotated Transformer
Master Positional Encoding: Part I
如何理解Transformer论文中的positional encoding,和三角函数有什么关系?
图解Transformer系列一:Positional Encoding(位置编码)
Transformer的位置编码详解

二、Positional Encoding

1. 引言

在任何一门语言中,词语的位置和顺序对句子意思表达都是至关重要的。传统RNN模型天然有序,在处理句子时,以序列的模式逐个处理句子中的词语,这使得词语的顺序信息在处理过程中被天然的保存下来,并不需要额外的处理。

由于Transformer模型没有RNN(循环神经网络)或CNN(卷积神经网络)结构,句子中的词语都是同时进入网络进行处理,所以没有明确的关于单词在源句子中位置的相对或绝对的信息。为了让模型理解序列中每个单词的位置(顺序),Transformer论文中提出了使用一种叫做Positional Encoding(位置编码)的技术。这种技术通过为每个单词添加一个额外的编码来表示它在序列中的位置,这样模型就能够理解单词在序列中的相对位置。

2. Positional Encoding的概念

在Transformer等模型中,输入序列通常是一系列嵌入向量(embedding vector),这些向量只包含单词或标记的语义信息,缺乏位置信息。为了解决这个问题,Positional Encoding将每个输入向量加上了一个表示其位置的向量,从而保留单词/标记的语义信息的同时,提供位置信息

一句话概括,Positional Encoding就是将位置信息添加(嵌入)到Embedding词向量中,让Transformer保留词向量的位置信息,可以提高模型对序列的理解能力。

3. 位置编码

以往我们根据单词之间的间隔比例算距离,如果设置整个句子长度为1,如:Attention is all you need ,其中is和you之间的距离为0.5。而 To follow along you will first need to install PyTorch 较长文本中子里的0.5距离则会隔很多单词,这显然不合适。

所以,总结一下理想的位置编码应该满足:

  1. 为每个字输出唯一的编码
  2. 不同长度的句子之间,任何两个字之间的差值应该保持一致;
  3. 编码值应该是有界的。

4. Positional Encoding的特性

  1. 每个位置有一个唯一的Positional Encoding;
  2. 两个位置之间的关系可以通过它们位置间的仿射变换来建模(获得);

5. Positional Encoding原理解析

常用的Positional Encoding方法有Sinusoidal Positional EncodingLearned Positional Encoding。其中,Sinusoidal Positional Encoding 是通过将正弦和余弦函数的不同频率应用于输入序列的位置来计算位置编码;Learned Positional Encoding 是通过学习一组可学习参数来计算位置编码。本节以 Sinusoidal Positional Encoding 为例,介绍 Positional Encoding的原理。

Transformer论文中使用了三角函数来实现Positional Encoding,因为三角函数具有周期性,可以很好地表示序列中单词的相对位置。Transformer论文的作者使用了不同频率的正弦和余弦函数来作为位置编码:
{ P E ( p o s , 2 i ) = sin ⁡ ( p o s / 1000 0 2 i / d m o d e l ) P E ( pos , 2 i + 1 ) = cos ⁡ ( p o s / 1000 0 2 i / d m o d e l ) (1) \begin{equation} \begin{cases} PE(pos, 2i)=\sin \left(pos / 10000^{2 i / d_{model}}\right) \\ PE(\text {pos}, 2 i+1)=\cos \left(pos / 10000^{2 i / d_{model}}\right) \end{cases} \end{equation} \\ \tag{1} {PE(pos,2i)=sin(pos/100002i/dmodel)PE(pos,2i+1)=cos(pos/100002i/dmodel)(1)
其中,pos即 position,表示token在序列中的位置,设句子长度为 L,则 p o s = 0 , 1 , … , L − 1 pos=0,1,\ldots,L-1 pos=0,1,,L1 P E PE PE 是token的位置向量, P E ( p o s , 2 i ) PE(pos, 2i) PE(pos,2i) 表示这个位置向量里的第i个元素; d m o d e l d_{model} dmodel 表示token的维度(通常为512), i i i 代表奇数维度, 2 i 2i 2i 表示偶数维度。

从公式中可以看出,其实一个词语的位置编码是由不同频率的余弦函数组成的,从低位到高位,余弦函数对应的频率由1降低到 1 10000 \frac{1}{10000} 100001,波长从 2 π 2\pi 2π 增加到 10000 ⋅ 2 π 10000\cdot2\pi 100002π

例如,第一个token就是0。2i2i+1 表示Positional Encoding的维度,i的取值范围是: [ 0 , … , d m o d e l / 2 ) [0,\ldots,d_{model}/2) [0,,dmodel/2),其中 d m o d e l d_{model} dmodel 为512。所以,当pos为1时,对应的Positional Encoding可以写成:
P E ( 1 ) = [ sin ⁡ ( 1 / 1000 0 0 / 512 ) , cos ⁡ ( 1 / 1000 0 0 / 512 ) , sin ⁡ ( 1 / 1000 0 2 / 512 ) , cos ⁡ ( 1 / 1000 0 2 / 512 ) , … b m a t r i x \begin{aligned} &\left.PE\left(1\right)=\left[\sin\left(1/10000^{0/512}\right.\right),\cos\left(1/10000^{0/512}\right),\sin\left(1/10000^{2/512}\right.\right),\cos \\ &\begin{pmatrix}1/10000^{2/512}\end{pmatrix},\ldots {bmatrix} \end{aligned} PE(1)=[sin(1/100000/512),cos(1/100000/512),sin(1/100002/512),cos(1/100002/512),bmatrix
借助上述公式,我们可以得到一个特定位置的 d m o d e l d_{model} dmodel 维的位置向量,并且借助三角函数的性质:
{ s i n ⁡ ( α + β ) = s i n ⁡ α c o s ⁡ β + c o s ⁡ α s i n ⁡ β c o s ⁡ ( α + β ) = c o s ⁡ α c o s ⁡ β − s i n ⁡ α s i n ⁡ β (2) \begin{cases} sin⁡(α+β)=sin⁡αcos⁡β+cos⁡αsin⁡β \\ cos⁡(α+β)=cos⁡αcos⁡β−sin⁡αsin⁡β \\ \end{cases} \tag{2} {sin(α+β)=sinαcosβ+cosαsinβcos(α+β)=cosαcosβsinαsinβ(2)
可以得到:
{ P E ( p o s + k , 2 i ) = P E ( p o s , 2 i ) × P E ( k , 2 i + 1 ) + P E ( p o s , 2 i + 1 ) × P E ( k , 2 i ) P E ( p o s + k , 2 i + 1 ) = P E ( p o s , 2 i + 1 ) × P E ( k , 2 i + 1 ) − P E ( p o s , 2 i ) × P E ( k , 2 i ) (3) \begin{cases} PE(pos + k,2i) = PE(pos,2i) \times PE(k,2i+1) + PE(pos, 2i+1) \times PE(k,2i) \\ PE(pos + k,2i+1) = PE(pos,2i+1) \times PE(k,2i+1) - PE(pos, 2i) \times PE(k,2i) \end{cases} \tag{3} {PE(pos+k,2i)=PE(pos,2i)×PE(k,2i+1)+PE(pos,2i+1)×PE(k,2i)PE(pos+k,2i+1)=PE(pos,2i+1)×PE(k,2i+1)PE(pos,2i)×PE(k,2i)(3)
可以看出,对于 p o s + k pos+k pos+k 位置的位置向量某一维 2 i 2i 2i 2 i + 1 2i+1 2i+1 而言,可以表示为: p o s pos pos 位置与 k k k 位置的位置向量的 2 i 2i 2i 2 i + 1 2i+1 2i+1 维的线性组合,这样的线性组合意味着位置向量中蕴含了相对位置信息。

BERT用了Transformer,但位置信息是训练出来的,没有用正弦余弦;正弦余弦是考虑到语言的语义和相对位置有关而与绝对位置关系不大,一句话放在文首还是文中还是文末,排除特殊情况后语义应该是差不多的。所以只要合理设计,用其他周期函数也可以。

6. 通俗理解Positional Encoding

最简单直观的加入位置信息的方式就是使用1,2,3,4,…直接对句子进行位置编码(one-hot)。用二进制转化举个例子:
在这里插入图片描述

上表中维度0,维度1,维度2,维度3拼成的数字就是该位置对应的二进制表示。可以看到每个维度(每一列)其实都是有周期的,并且周期是不同的。具体来说,每个比特位的变化率都是不一样的,越低位的变化越快(越往右边走,变化频率越快),红色位置0和1每个数字会变化一次,而黄色位,每8个数字才会变化一次。这样就能够说明使用多个周期不同的周期函数组成的多维度编码和递增序列编码其实是可以等价的。这也回答了为什么周期函数能够引入位置信息。

同样的道理,不同频率的sin正弦函数和cos余弦函数组合,通过调整三角函数的频率,可以实现这种低位到高位的变化,这样就能把位置信息表示出来。128维位置编码2D示意图,如下图所示:
在这里插入图片描述

7. 位置向量与词向量

一般来说,可以使用向量拼接或者相加的方式,将位置向量和词向量相结合。

input = input_embedding + positional_encoding

这里,input_embedding是通过常规Embedding层,将每一个token的向量维度从vocab_size映射到d_model。由于是相加关系,则positional_encoding也是一个d_model维度的向量。(原论文中,d_model=512)
在这里插入图片描述

8. Positional Encoding的代码实现

参考OpenNMT中的代码实现:onmt/modules/embeddings.py

class PositionalEncoding(nn.Module):

    def __init__(self, d_model, max_len=5000):
        super(PositionalEncoding, self).__init__()       
        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)
        #pe.requires_grad = False
        self.register_buffer('pe', pe)

    def forward(self, x):
        return x + self.pe[:x.size(0), :]

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

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

相关文章

05ShardingSphere-JDBC水平分片

1、准备服务器 随着业务的扩大,订单表数据量不断增加,数据库面临存储压力,开始考虑对订单表进行水平分片。 将t_order表扩展为server-order0中的t_order0和t_order1、server-order1中的t_order0和t_order1 服务器规划:使用dock…

使用Python创建音乐播放器

1. 介绍 在本篇博客中,我们将介绍如何使用Python编程语言和wxPython模块创建一个简单的音乐播放器。我们将使用wxPython来构建用户界面,并借助pygame模块来实现音频播放的功能。 C:\pythoncode\new\quickplaywav.py 2. 使用方法 使用我们提供的源代码…

排查disabled问题之谷歌新版本特性

问题复现 最近我突然接手一个后台的bug,这个后台很久没有迭代更新了,我也不熟悉业务,所以只能看一下源码,问题很快就复现,测试的修复操作也很正确,就是因为渲染的input标签中存在disableddisabled’属性导…

2023 年您需要了解哪些类型的数据泄露?

到目前为止,所有公司都应该意识到网络安全威胁是任何企业面临的主要风险之一。其中,那些直接损害敏感数据的行为可能会造成特别严重的破坏。 目前,数据泄露的典型成本已接近 450 万美元(在过去三年中增加了 15%)&…

MySQL内外连接、索引特性

目录 内连接 外连接 索引特性 理解索引 删除索引 MySQL内外连接是一种用于联接两个或多个表的操作。内连接只返回满足连接条件的行,外连接返回满足条件和不满足条件的行。 内连接 SQL如下: SELECT ... FROM t1 INNER JOIN t2 ON 连接条件 [INNER …

使用香橙派 学习Linux的串口开发

串口的回顾 & 硬件接线 关于串口也是之前学习过很多次了,详见: 认识串口 和 蓝牙模块HC08_hc08蓝牙模块_mjmmm的博客-CSDN博客 串口的再认识-CSDN博客 香橙派提供了两路串口,第一路就是在刷机时串口连接的引脚(对应驱动ttyS0&…

input标签,新增那些属性

input标签作为页面与用户交互的重要入口&#xff0c;了解掌握input的属性&#xff0c;至为重要。 type属性 HTML5给input表现的type属性&#xff0c;添加了很多的属性值&#xff0c;用来丰富了文本框类型。比如&#xff1a; <body><input type"email" na…

前端--HTML

文章目录 HTML结构快速生成代码框架HTML常见标签 表格标签 编写简历信息 填写简历信息 Emmet 快捷键 HTML 特殊字符 一、HTML结构 1.认识HTML标签 HTML 代码是由 "标签" 构成的. 形如: <body>hello</body> 标签名 (body) 放到 < > 中 大部分标…

Spring框架中的@Conditional系列注解

目录 1 Contidional 介绍1.1 Condition 接口1.2 Spring Conditional注解实例1.3 Conditional 与Profile 的对比 2 Spring boot 扩展2.1 ConditionalOnClass和ConditionalOnMissingClass注解2.2 ConditionalOnBean 和ConditionalOnMissingBean注解2.3 ConditionalOnProperty注解…

(二十八)大数据实战——Flume数据采集之kafka数据生产与消费集成案例

前言 本节内容我们主要介绍一下flume数据采集和kafka消息中间键的整合。通过flume监听nc端口的数据&#xff0c;将数据发送到kafka消息的first主题中&#xff0c;然后在通过flume消费kafka中的主题消息&#xff0c;将消费到的消息打印到控制台上。集成使用flume作为kafka的生产…

18. 线性代数 - 线性变换

文章目录 线性空间线性变换线性变换的几何意义特征值与特征向量NumPy的矩阵操作Hi, 你好。我是茶桁。 经历了几节线性代数课程之后,终于咱们到了最后一节课了。本节课的内容说多不多,说少也不少。 我们先是要理解一下线性空间和线性变换,并且探讨一下线性变换的几何意义。…

Mapbox加载arcgis的底图

成果图 这种底图基本上都是按照raster来加载的&#xff0c;主要就是知道地址了&#xff0c;拼参数 具体参数请参考官网 https://developers.arcgis.com/rest/services-reference/enterprise/export-map.htm 源码 我的服务列表是这样的 http://XXXX:XXXX/arcgis/rest/services/…

Rsync远程同步inotify监控

Rsync 简介 rsync&#xff08;Remote Sync&#xff0c;远程同步&#xff09; 是一个开源的快速备份工具&#xff0c;可以在不同主机之间镜像同步整个目录树&#xff0c;支持增量备份&#xff0c;并保持链接和权限 在远程同步任务中&#xff0c;负责发起rsync同步操作的客户机…

【Docker】Docker简介

Docker简介 &#x1f4cb;导航 1. Docker简介1.1 什么是Docker&#xff1f;1.2 什么是容器&#xff1f;1.3 容器的优势&#xff1f;1.4 Docker的优势&#xff1f;1.5 虚拟技术与容器技术Docker的区别&#xff1f;1.6 为什么学习Docker? 2. 安装Docker3. Docker架构4. Docker命…

【算法训练-栈 一】【结构特性】有效的括号

废话不多说&#xff0c;喊一句号子鼓励自己&#xff1a;程序员永不失业&#xff0c;程序员走向架构&#xff01;本篇Blog的主题是【栈的使用】&#xff0c;使用【栈】这个基本的数据结构来实现&#xff0c;这个高频题的站点是&#xff1a;CodeTop&#xff0c;筛选条件为&#x…

影刀RPA解决WPS不存在的问题

问题阐述 明明电脑上已经安装了WPS&#xff0c;但影刀程序还是提示没有安装的问题 解决办法 1.打开WPS并关闭所有其他网页 2. 配置与修复 3.开始修复 出现这个框&#xff0c;就要关闭WPS&#xff0c;否则无法执行&#xff0c;关闭WPS不影响其修复 4.等待修复完成即可

《打造高可用PostgreSQL:策略与工具》

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f405;&#x1f43e;猫头虎建议程序员必备技术栈一览表&#x1f4d6;&#xff1a; &#x1f6e0;️ 全栈技术 Full Stack: &#x1f4da…

性能测试、负载测试、压力测试、稳定性测试简单区分

是一个总称&#xff0c;可细分为性能测试、负载测试、压力测试、稳定性测试。 性能测试 以系统设计初期规划的性能指标为预期目标&#xff0c;对系统不断施加压力&#xff0c;验证系统在资源可接受范围内&#xff0c;是否能达到性能瓶颈。 关键词提取理解 有性能指标&#…

【SpringMVC】JSON数据传输与异常处理的使用

文章目录 一、Jackson1.1 Jackson是什么1.2 常用注解1.3 实例1.3.1导入依赖1.3.2 配置spring-mvc.xml1.3.3 JsonController.java 二、Spring MVC异常处理机制2.1 使用原因2.2 SpringMVC异常处理2.2.1 异常处理机制流程图2.2.2 异常处理的三种方式 一、Jackson 1.1 Jackson是什…

Spring Boot配置文件(YAML Properties)总结

文章目录 配置文件的作用YAML配置文件Properties配置文件配置文件的加载顺序激活不同的配置文件配置文件的占位符自定义配置属性加密敏感信息配置文件的最佳实践结论 &#x1f389;欢迎来到架构设计专栏~Spring Boot配置文件&#xff08;YAML & Properties&#xff09;总结…