NLP学习笔记(六) Transformer简明介绍

news2024/9/20 22:44:30

大家好,我是半虹,这篇文章来讲 Transformer \text{Transformer} Transformer,想要获取更多相关文章,欢迎关注 自然语言处理 专栏


在之前的两篇文章中,我们介绍过序列到序列模型以及注意力机制在序列到序列模型中的应用

所谓序列到序列模型,就是那些输入是序列、输出也是序列的模型,这是从输入输出的角度来定义的

这些模型通常会使用编码器到解码器的架构,编码器用于处理输入序列,解码器用于生成输出序列

由于循环神经网络在处理序列数据时的优势,很多模型都会选择循环神经网络作为编码器和解码器


循环神经网络会逐步遍历序列,并通过隐状态的传递保存序列的历史信息,从而达到理解序列数据的目的

这是循环神经网络能够处理序列数据的关键,同时也是循环神经网络的局限所在

循环神经网络处理序列数据时需要逐步遍历,这是顺序性的,这个过程难以并行

此外,隐状态在长序列间进行传递容易丢失信息,使网络难以对长序列进行建模


另一方面,研究人员发现,注意力机制在序列到序列模型中的应用对性能的提升有很大帮助

后来就有人提出一个开创性的想法,能不能整个序列到序列模型就用注意力机制,不再基于循环神经网络

当然,我们知道这个尝试是成功了,这就是大名鼎鼎的 Transformer \text{Transformer} Transformer Attention Is All You Need \text{Attention Is All You Need} Attention Is All You Need

Transformer \text{Transformer} Transformer 不仅使训练过程可以并行,而且还能对长序列进行建模!


Transformer \text{Transformer} Transformer 虽然最初是在 NLP \text{NLP} NLP 领域中提出的,但其后来应用到 CV \text{CV} CV 领域也有亮眼的表现

可以说 Transformer \text{Transformer} Transformer 中的注意力机制开创了 RNN \text{RNN} RNN CNN \text{CNN} CNN 之外的一种全新范式

下面将会从总体到细节逐步剖析 Transformer \text{Transformer} Transformer 作为序列到序列模型时的运作方式


从本质上来说, Transformer \text{Transformer} Transformer 是一个编码器到解码器架构,下图是编码器到解码器架构的示意图

编码器到解码器

图片左半部分是编码器,处理输入序列得到编码信息,右半部分是解码器,根据编码信息生成输出序列

这里需要特别注意的是,解码器一般都是自回归生成,这意味着解码器会将上一步输出作为下一步输入

所以在这里我们能看到,解码器会将偏移一步之后的输出序列作为其输入 ( Teacher Forcing \text{Teacher Forcing} Teacher Forcing )


另外,编码器是由若干个编码层组成的,解码器是由若干个解码层组成的

Transformer \text{Transformer} Transformer  出现之前,编码层和解码层大多都是基于循环神经网络进行设计

Transformer \text{Transformer} Transformer  另辟蹊径,选择完全基于注意力机制进行设计,下图是其编码层和解码层的实现细节

编码层到解码层

如图所示,左半部分展示的是编码层的细节,右半部分展示的解码层的细节,二者皆有若干层堆叠

图中相同背景色的矩形框表示相同的子模块,大致上可以分为三种:

黄色背景的是多头注意力机制,绿色背景的是前馈神经网络,蓝色背景的是残差连接以及层正则化


运作步骤如下:

  1. 编码阶段
    1. 获取原始输入序列向量表示,将其作为编码层的输入
    2. 编码层操作大致上分为两步:
      1. 首先经过多头注意力机制,之后接残差连接和层正则化
      2. 然后经过前馈神经网络 ,之后接残差连接和层正则化
    3. 编码层有若干个,重复上述操作若干次
      这里要注意的是,上一个编码层的输出会用于下一个编码层的输入
      只有第一个编码层才以原始输入序列作为输入
  2. 解码阶段
    1. 获取偏移输出序列向量表示,将其作为解码层的输入
    2. 解码层操作大致上分为三步:
      1. 首先经过多头注意力机制,之后接残差连接和层正则化
      2. 然后经过多头注意力机制,之后接残差连接和层正则化
      3. 最后经过前馈神经网络 ,之后接残差连接和层正则化
    3. 解码层有若干个,重复上述操作若干次
      这里要注意的是,上一个解码层的输出会用于下一个解码层的输入
      只有第一个解码层才以偏移输出序列作为输入

下文会依次解析其中的核心操作,分别是:

序号操作出现步骤
1获取序列向量表示1.1    、2.1
2多头注意力机制1.2.12.2.12.2.2
3前馈神经网络1.2.22.2.3
4残差连接1.2.11.2.22.2.12.2.22.2.3
5层正则化1.2.11.2.22.2.12.2.22.2.3

1、获取序列向量表示

我们知道,自然语言是无法直接作为模型输入的,所以第一步首先要把自然语言转化成向量表示

一般来说,只需将序列经过嵌入层得到对应序列中每个词元的可学习向量即可,具体如下图所示:

词元表示

这样的做法在 RNN \text{RNN} RNN CNN \text{CNN} CNN 架构中没有问题,但 Transformer \text{Transformer} Transformer Attention \text{Attention} Attention 是无法建模位置信息的

为了弥补这个缺陷,在获取序列向量表示时需要额外加入位置信息

词元位置表示

如图所示,每个词元经过词元嵌入层得到语义表示,每个词元的位置经过位置嵌入层得到位置表示

然后对应的语义表示和位置表示通过相加的方式进行融合以得到最终表示: e i = t i + p i ,   i = 1 ,   2 ,   ⋯ e_{i} = t_{i} + p_{i},\ i = 1, \ 2,\ \cdots ei=ti+pi, i=1, 2, 


当然你也可以用拼接的方法对两个表示进行融合,相加只是论文中的设计

但是需要注意的是,如果用相加的方法进行融合,语义表示和位置表示的维度必须要是一样的

事实上,在论文中为了实现方便,同时也是为了进行残差连接

在编码层和解码层的每个子模块,其输入输出向量的特征维度都是一样的,具体来说特征维度 d = 512 d = 512 d=512


下面是本节的最后一个问题,如何获得位置表示?

最简单的方法就是像语义表示一样,经过嵌入层得到一个可学习的向量,然后通过数据来训练

但是,论文提出可以通过公式直接计算位置表示,具体的计算公式如下:
PE ( p , 2 i ) = sin ⁡ ( p   /   1000 0 2 i / d ) PE ( p , 2 i + 1 ) = cos ⁡ ( p   /   1000 0 2 i / d ) \begin{align} \text{PE}(p, 2i) &= \sin (p\ /\ 10000^{2i/d}) \\ \text{PE}(p, 2i + 1) &= \cos (p\ /\ 10000^{2i/d}) \end{align} PE(p,2i)PE(p,2i+1)=sin(p / 100002i/d)=cos(p / 100002i/d)
对于词元位置 p p p,位置向量的维度为 d d d,向量中的第 2 i 2i 2i 2 i + 1 2i+1 2i+1 维计算公式如上所示

一个例子如下:

词元位置编码

通过上述方式获得位置表示有以下优点

  • 可以直接计算得到,无需数据进行训练
  • 每个词元位置的向量表示都是唯一不变的
  • 使模型能够处理比训练集长的序列
  • 使模型易于学习到词元之间的相对关系,因为 PE ( p + k ) \text{PE}(p+k) PE(p+k) 可由 PE ( p ) \text{PE}(p) PE(p) 线性组合得到

2、多头注意力机制

多头注意力机制是整个模型的核心,且不说多头是什么操作,我们先来看注意力机制是啥

在上一篇文章中,我们讲过注意力机制在序列到序列模型中的应用,这里还是以翻译为例引入

假设现在我们要进行中译英任务,将 机器学习 翻译成 Machine Learning

当生成 Machine   时,模型其实应该将更多权重放在 机器 二字

当生成 Learning 时,模型其实应该将更多权重放在 学习 二字


注意力机制在本质上是根据当前查询以不同的权重抽取序列中的信息

序列中的每个元素会有一个键向量用于匹配,另有一个值向量表示其蕴含的信息

当给定查询向量时,会通过以下两个步骤得到最终要抽取的信息向量

首先,计算查询向量与每个键向量之间的匹配分数

然后,以匹配分数作为权重对所有值向量加权求和

注意力机制

其中最关键的部分就是打分函数的设计,简单来说就是如何衡量查询向量和键向量之间的匹配程度

Transformer \text{Transformer} Transformer 中所使用的打分函数是 scaled dot product \text{scaled dot product} scaled dot product,其计算公式如下: score ( Q , K ) = Q K T d k \text{score}(Q, K) = \frac{QK^T}{\sqrt{d_k}} score(Q,K)=dk QKT

其中, Q Q Q 为查询向量, K K K 为键向量, d k d_k dk 为键向量维度,以下是一些细节的解答

  • 为什么要做 scale \text{scale} scale

    假设 q q q k k k 都是均值为 0 0 0、方差为 1 1 1 的独立随机变量,那么二者点积 q ⋅ k q \cdot k qk 的均值为 0 0 0、而方差为 d k d_k dk

    如果 d k d_k dk 越大,那么点积方差越大,经过 softmax \text{softmax} softmax 之后,分布变得陡峭,梯度变小

  • 二是为什么设计 scale \text{scale} scale 的值是 1 d k \frac{1}{\sqrt{d_k}} dk 1

    假设 q q q k k k 都是均值为 0 0 0、方差为 1 1 1 的独立随机变量,那么二者点积 q ⋅ k q \cdot k qk 的均值为 0 0 0、而方差为 d k d_k dk

    如果将点积乘上缩放因子 1 d k \frac{1}{\sqrt{d_k}} dk 1,可以使得方差稳定在 1 1 1,这是因为 D ( q ⋅ k d k ) = d k ( d k ) 2 = 1 D(\frac{q \cdot k}{\sqrt{d_k}}) = \frac{d_k}{(\sqrt{d_k})^2} = 1 D(dk qk)=(dk )2dk=1


当查询向量来自序列本身时,此时的注意力机制被称为自注意力机制

序列中的每个元素对应三个向量,一是查询向量,二是键向量,三是值向量,那么如何得到这些向量呢

简单的话,可以直接将序列元素的向量表示同时作为上述向量,也可以将其经过不同的线性映射后得到

下面是自注意力机制的运作过程

Self Attention

在自注意力机制中,每个元素都会根据自身查询来获取序列的上下文信息,从而得到对应的向量表示

对比循环神经网络,二者都可用于编码序列,其不同之处在于自注意力机制能够并行地编码序列

这是因为序列中每个元素的注意力计算之间并没有依赖关系,因此可以通过矩阵运算来并行加速

反观循环神经网络则需要通过在序列中逐步传递隐状态来获取序列的上下文信息,这个过程不能并行


回到模型, Transformer \text{Transformer} Transformer 中共有三种注意力机制,对应到运行步骤分别是 1.2.12.2.12.2.2

1.2.1 是编码器自注意力机制,查询向量来自编码器,键向量、值向量也来自编码器

2.2.1 是解码器自注意力机制,查询向量来自解码器,键向量、值向量也来自解码器

2.2.2 是解码器外注意力机制,查询向量来自解码器,键向量、值向量则来自编码器


上述的三种注意力机制都会带有填充掩码 padding mask

这是由于神经网络在进行训练时,一般是以批量为单位的,但是同一批量里的序列通常长短不一

为了进行矩阵运算,需要用预先定义好的占位符,将同一批量里的序列填充到统一长度

然而,在计算注意力权重分布时,我们并不希望给这些占位符分配注意力权重

因此,在查询向量和键向量计算匹配分数后,将占位符的匹配分数设置为一个极小的值是合理的


解码器自注意力机制另有一个独特的掩码 decoder mask

这是因为解码过程是自回归的,就是在生成当前的词元时,只能看到之前的词元,不能看到之后的词元

如果直接使用注意力机制的话,那么在计算当前的词元时,会用自身查询与序列所有词元计算匹配分数

这样做显然是一个作弊的行为,使用什么方法可以避免呢

我们只需要将当前词元与之后词元的匹配分数设置为一个极小的值即可,如此就能保证训练和预测行为一致


至此终于把注意力机制介绍完了,最后再来看一下多头注意力机制是啥

上述介绍的注意力机制,序列中的每个元素都会对应一组查询、键、值向量,然后进行一次注意力计算

为了增强模型表达能力,序列中的每个元素可映射到多组查询、键、值向量,然后分别进行注意力计算

我们希望不同的映射能够在不同的特征空间学习到不同的信息,以此达到增强模型表达能力的目的

最后,多个特征空间中注意力计算的结果将会被拼接起来,然后经过一个线性映射得到最终的输出

多头注意力机制

3、前馈神经网络

前馈神经网络是为了增强模型的表达能力而设计的,将原有的向量表示映射到一个更好的特征空间

在本模型中,前馈神经网络由两个线性映射和一个激活函数组成,具体的公式表达如下:
FFN ( X ) = Linear 2 ( ReLU ( Linear 1 ( X ) ) ) = max ⁡ ( 0 ,   X W 1 + b 1 ) W 2 + b 2 \text{FFN}(X) = \text{Linear}2(\text{ReLU}(\text{Linear}1(X))) = \max(0,\ X W_1 + b_1) W_2 + b_2 FFN(X)=Linear2(ReLU(Linear1(X)))=max(0, XW1+b1)W2+b2
其中, Linear \text{Linear} Linear 是线性映射, ReLU \text{ReLU} ReLU 是激活函数, W 1 W_1 W1 b 1 b_1 b1 W 2 W_2 W2 b 2 b_2 b2 都是可学习的参数

输入的 X X X 特征维度是 512 512 512,经过第一个线性映射后变为 2048 2048 2048,经过第二个线性映射后变回 512 512 512


4、残差连接

残差连接有助于缓解深层网络在训练时出现的梯度问题,其核心思想非常简单,示意图如下所示:

残差连接

输入经过某个模块得到输出后,再将原始输入与模块输出相加才得到最终输出


5、层正则化

一般来说,正则化的作用是保证数据特征分布稳定,从而加速模型的收敛速度

常用的正则化方法包括以下两种:

  • BatchNorm:批正则化,对所有样本的每个特征做正则化,一般用于 CV   领域
  • LayerNorm:层正则化,对每个样本的所有特征做正则化,一般用于 NLP 领域

在本模型中使用的正则化方法是层正则化


上述的描述或许还是有些抽象,下面会用例子对比来讲两种正则化方法的异同

对于二维的情况,给定数据为:[B, F]

  • BatchNorm:正则化维度:[1, *],表示对每个 F 在所有 [B] 上做正则化
  • LayerNorm:正则化维度:[*, 1],表示对每个 B 在所有 [F] 上做正则化

对于三维的情况,给定数据为:[B, S, F]

  • BatchNorm:正则化维度:[1, 1, *],表示对每个 F 在所有 [B, S] 上做正则化
  • LayerNorm:正则化维度:[*, 1, 1],表示对每个 B 在所有 [S, F] 上做正则化

对于三维的情况,给定数据为:[B, H, W, C]

  • BatchNorm:正则化维度:[1, 1, 1, *],表示对每个 C 在所有 [B, H, W] 上做正则化
  • LayerNorm:正则化维度:[*, 1, 1, 1],表示对每个 B 在所有 [H, W, C] 上做正则化

对于一个批量数据,输入序列的长度通常是不相等的

当序列长度变化较大时 ,使用 BatchNorm 训练得到的参数波动会很大

所以在处理序列数据时 ,选择 LayerNorm 是更合适的



好啦,本文到此结束,感谢阅读!

如果你觉得这篇文章还不错的话,欢迎点赞、收藏、关注,你的支持是对我最大的鼓励 (/ω\)

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

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

相关文章

Linux开启Docker远程访问并设置安全访问(证书密钥),附一份小白一键设置脚本哦!

前言 喜欢折腾慢慢看,不喜欢折腾直接跳到小简下文的一键脚本那里,两分钟搞好。 我的博客:https://blog.ideaopen.cn 我的公众号:小简聊开发 开启远程访问 编辑docker.service文件 vi /usr/lib/systemd/system/docker.service # …

Python FastAPI 框架 操作Mysql数据库 增删改查

2 比 1 更容易理解,可以先看2(单文件级别) 1、FastAPI 框架 操作Mysql数据库(项目多文件级别) FastAPI 可以使用任何您想要的关系型数据库。 在这里,让我们看一个使用着SQLAlchemy的示例。 您可以很容易地将SQLAlchemy支持任何…

每天进步一点点,今天来学结构体

什么是结构体? C 语言允许用户自己指定这样一种数据结构,它由不同类型的数据组合成一个整体,以便引用,这些组合在一个整体中的数据是互相联系的,这样的数据结构称为结构体,它相当于其它高级语言中记录。 …

01、数据结构——数组

一、数据结构与算法 数据结构是一门研究组织数据方式的学科,有了编程语言也就有了数据结构。学好数据结构可以编写出更加漂亮、更加有效率的代码。程序数据结构算法数据结构是算法的基础 二、稀疏数组: 1、基本介绍: 当一个数组中大部分元…

【Javascript】文本转语音SpeechSynthesisUtterance

SpeechSynthesisUtterance基本介绍 SpeechSynthesisUtterance是HTML5中新增的API,用于将指定文字合成为对应的语音.也包含一些配置项,指定如何去阅读(语言,音量,音调)等 SpeechSynthesisUtterance基本属性 SpeechSynthesisUtterance.lang 获取并设置话语的语言 SpeechSynthesis…

InfluxDB 笔记

概念 Measurement 类似于表名。 A measurement acts as a container for tags, fields, and timestamps. Tag 补充描述数据的信息,如示例中的location和scientist描述了该数据的采集地和采集人。这两个称为Tag Key,具体的值则称为Tag Value&#xff0c…

小程序基础篇-视图与逻辑

本次学习目标&#xff1a;实现页面间的导航跳转实现下拉刷新实现上拉加载更多知道小程序常用的生命周期函数1.页面导航页面导航指的是页面之前相互的跳转浏览器之间的页面导航有两种&#xff1a;<a>;location.href小程序之间的页面导航有两种&#xff1a;声明式导航&…

告警与恢复告警原理及实现

一、 背景自“双碳”政策提出以来&#xff0c;KaiwuDB 聚焦“数字能源”领域&#xff0c;为用户打造数字能源管理平台&#xff0c;旨在提升综合能源和碳资产管理能力。数字能源管理平台是以 KaiwuDB 为核心建设的云-边-端一体化数据服务平台&#xff0c;致力于为 IoT、工业互联…

前言技术--swagger

目录一、前后端分离的特点二、在没有swagger之前三、swagger的作用四、swagger的优点五、集成swagger5.1 新建springboot项目5.2 集成swagger5.3 开发一个controller用于测试5.4 启动服务&#xff0c;验证集成效果六、swagger常用注解七、swagger使用综合案例一、前后端分离的特…

Python的PyQt框架的使用-常用控件篇

Python的PyQt框架的使用-常用控件篇一、前言二 、QLineEdit 文本框三 、QPushButton按钮控件四、QRadioButton 单选按钮一、前言 个人主页: ζ小菜鸡大家好我是ζ小菜鸡&#xff0c;小伙伴们&#xff0c;让我们一起来学习Python的PyQt框架的常用控件。如果文章对你有帮助、欢迎…

第一个程序——构建一个ServerUI

简介 本次程序设计均使用python实现&#xff0c;使用sql server对聊天室用户的数据进行存储。通过python socket套接字编程&#xff0c;实现了在线聊天室的功能&#xff0c;并使用python tkinter进行UI界面的设计。 思路 由计算机网络的基础知识易知&#xff0c;两个主机之间…

基于LSTMGRU的微博突发事件分析与谣言检测(附完整的代码+报告)

问题描述及方法基础 本章主要对课题研究所涉及的机器学习、自然语言处理的原理和方法进行介绍,主要分为四部分,第一部分是将本课谣言检测任务的符号化描述;第二部分是微博数据的预处理,包括语言模型、文本分词等技术;第三部分与第四部分分别是本文搭建的微博谣言检测模型所…

py字符串的格式化笔记

print():和cjava差不多&#xff0c;只是逗号变了&#xff0c;其中 %s 就是模板中的占位符&#xff0c;表示这个位置先占着&#xff0c;待会儿要有数据填入到这里。然后再提供一个元组&#xff0c;里面依次存放需要填入到 %s 位置 的数据。这里是使用变量 (salary,tax,aftertax)…

CSS.前端基础.html

什么是 CSS? CSS 指层叠样式表 (Cascading Style Sheets)样式定义如何显示 HTML 元素样式通常存储在样式表中把样式添加到 HTML 4.0 中&#xff0c;是为了解决内容与表现分离的问题外部样式表可以极大提高工作效率外部样式表通常存储在 CSS 文件中多个样式定义可层叠为一个示…

丝绸之路也可以是科技传播之路

唐宋元海外贸易 618年-1368年 王孝通 生卒年代不详 孙思邈541年—682年 一行 公元683年-公元727年 李淳风 602年&#xff0d;670年 沈括 1031年&#xff0d;1095年 郭守敬 1231年&#xff0d;1316年 扎马鲁丁生卒年代不详 阿拉伯帝国 632年-1258年 阿尔花拉子模 780年&#xf…

【深度强化学习】【论文阅读】【双臂模仿】Deep Imitation Learning for BimanualRobotic Manipulation

title: Deep Imitation Learning for BimanualRobotic Manipulation date: 2023-01-15T20:54:56Z lastmod: 2023-01-19T18:31:57Z Deep Imitation Learning for BimanualRobotic Manipulation 1 Introduction 文中使用的模型是一个深度的、分层的、模块化的架构。与 baselin…

微服务负载均衡器Ribbon学习笔记

目录 1.什么是Ribbon 1.1 客户端的负载均衡 1.2 服务端的负载均衡 1.3 常见负载均衡算法 2. Nacos使用Ribbon 3. Ribbon负载均衡策略 4.修改默认负载均衡策略 方式1&#xff1a;通过自定义配置类来实现 方式2&#xff1a;通过修改配置文件实现&#xff08;推荐&#xf…

9、jQuery

jQuery库&#xff1a;里面存在大量的JavaScript函数 官网&#xff1a;https://jquery.com/ 9.1 获取jQuery jQuery引入 cdn 引入 <script src"https://cdn.bootcss.com/jquery/3.4.1/core.js"></script>本地引入 <script src"lib/jquery-3.6.3.…

C语言练习——3

C语言练习——3一、 操作符练习1.1交换两个变量&#xff08;不创建临时变量&#xff09;1.2 打印整数二进制的奇数位和偶数位1.3[二进制中1的个数](https://www.nowcoder.com/questionTerminal/8ee967e43c2c4ec193b040ea7fbb10b8)1.4[两个整数二进制位不同个数](https://www.no…

【 java 反射下篇】java反射机制不难吧?来看看这篇

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…