Python深度学习入门 - - Transformers网络学习笔记

news2024/12/29 10:48:41

前言


一、Transformers架构原理

Transformer 架构与传统循环神经网络RNN、LSTM相比具有并行计算、自注意力机制、位置编码和多头注意力等方面的差异。这些差异使得 Transformer 在处理长序列、建模上下文关系和并行计算方面表现出更强的能力,成为自然语言处理和其他序列任务中的重要架构。

在这里插入图片描述
编码器由 6 个相同的层堆叠组成。每一层都有两个子层。第一个是多头自注意机制,第二个是简单的位置全连接前馈网络。我们在两个子层的每个周围都采用了残差连接,然后进行层归一化。

解码器也由6 个相同的层堆叠组成。除了每个编码器层中的两个子层外,解码器还插入了第三个子层,对编码器堆栈的输出执行多头关注。与编码器类似,我们在每个子层周围采用残差连接,然后进行层归一化。

1、自注意力层(Self-Attention)

Transformers架构中加入了自注意力层,自注意力层相比之前GRU(门控循环单元),能并行地关注更多序列信息,这使得Transformers网络不再简单地依据前后依赖关系来建模序列信息的相关性,Transformers网络能关注更远的序列信息,从而捕获建模更长的时序关系。
在这里插入图片描述

假设输入序列为 X ∈ R L × d model X \in \mathbb{R}^{L \times d_{\text{model}}} XRL×dmodel,其中 L L L 表示序列长度, d model d_{\text{model}} dmodel 表示隐藏层的维度。多头注意力机制将输入序列分别映射为 h h h 个不同的查询(Query)、键(Key)和值(Value)序列,用于计算注意力分数。 S e l f − A t t e n t i o n Self-Attention SelfAttention 层的输入用矩阵 X i X_{i} Xi 进行表示,一般为词向量,则可以使用线性变换矩阵 W Q W^Q WQ W K W^K WK W V W^V WV用矩阵运算得到 Q i Q_i Qi K i K_i Ki V i V_i Vi

a i = W x i a_i = Wx_i ai=Wxi
Q i = W Q i a i Q_i = W_{Q_i}a_i Qi=WQiai

K i = W K i a i K_i = W_{K_i}a_i Ki=WKiai

V i = W V i a i V_i = W_{V_i}a_i Vi=WViai

每个注意力头都有自己的权重矩阵 W Q ∈ R d model × d k W_Q \in \mathbb{R}^{d_{\text{model}} \times d_k} WQRdmodel×dk W K ∈ R d model × d k W_K \in \mathbb{R}^{d_{\text{model}} \times d_k} WKRdmodel×dk W V ∈ R d model × d v W_V \in \mathbb{R}^{d_{\text{model}} \times d_v} WVRdmodel×dv,其中 d k d_k dk 表示查询和键的维度, d v d_v dv 表示值的维度。
在这里插入图片描述

然后,针对每个注意力头,通过计算查询 Q i Q_i Qi、键 K i K_i Ki 和值 V i V_i Vi 的点积注意力得到注意力分数 A t t e n t i o n i Attention_i Attentioni,其中 d k \sqrt{d_k} dk 是为了缩放注意力分数:

A t t e n t i o n i = softmax ( Q i K i ⊤ d k ) ⋅ V i Attention_i = \text{softmax}\left(\frac{{Q_iK_i^\top}}{\sqrt{d_k}}\right) \cdot V_i Attentioni=softmax(dk QiKi)Vi

论文作者解释了自注意力机制的几个优势,一个是能减少计算的复杂度,并行计算序列输入会使模型训练更加高效,相比CNN和RNN这种串行计算效率更高。第二是能更加有效地建模长时序信息依赖关系,同时减少前向传播和反向传播在网络中的传播路径,提高网络参数的更新速率

2、多头注意力机制(Multi-Head Attention)

多头注意力机制允许模型同时关注输入序列中不同位置的信息,通过不同的权重矩阵学习不同的注意力表示。这有助于模型更好地捕捉序列中的关系和重要性,并提升模型的表示能力。将所有注意力头的输出拼接并经过线性变换,得到最终的多头注意力输出:

MultiHead ( X ) = Concat ( A 1 , A 2 , … , A h ) W O \text{MultiHead}(X) = \text{Concat}(A_1, A_2, \ldots, A_h)W_O MultiHead(X)=Concat(A1,A2,,Ah)WO

其中 Concat \text{Concat} Concat 表示将所有注意力头的输出进行拼接, W O ∈ R h d v × d model W_O \in \mathbb{R}^{hd_v \times d_{\text{model}}} WORhdv×dmodel 是最终输出的线性变换权重矩阵。

在这里插入图片描述

多头注意力机制跟人的注意力机制很像,比如我们在读一段很长的话时,我们有不同的注意力窗口,但其中有些则是更为重要的信息特征,多头注意力能让更多重要的信息特征关联起来,进行全局的信息补充和理解

3、位置编码(Positional Encoding)

在RNN(LSTM,GRU)中,时间步长的概念按顺序编码,因为输入/输出流一次一个。 对于Transformer,序列输入的时候是并行的,所以不能很好的衡量序列片段间的位置相关性,作者将时间编码为正弦波,作为附加的额外输入。 这样的信号被添加到输入和输出以表示时间的流逝。

PE ( p o s , 2 i ) = sin ⁡ ( p o s 1000 0 2 i / d model ) \text{{PE}}(pos, 2i) = \sin\left(\frac{{pos}}{{10000^{2i/d_{\text{{model}}}}}}\right) PE(pos,2i)=sin(100002i/dmodelpos)

PE ( p o s , 2 i + 1 ) = cos ⁡ ( p o s 1000 0 2 i / d model ) \text{{PE}}(pos, 2i+1) = \cos\left(\frac{{pos}}{{10000^{2i/d_{\text{{model}}}}}}\right) PE(pos,2i+1)=cos(100002i/dmodelpos)

p o s pos pos 是单词的位置, d model d_{\text{{model}}} dmodel是这个向量的维数。也就是说,PE的每一个维度对应一个正弦曲线。对于偶数(2i)我们使用正弦,对于奇数(2i + 1)我们使用余弦。通过这种方式,我们能够为输入序列的每个标记提供不同的编码,因此现在可以并行地传递输入。为什么用三角函数,为什么偶数维(2i)用sin,奇数维(2i+1)用cos?

由三角函数性质公式:
s i n ( α + β ) = s i n α c o s β + c o s α s i n β sin(α + β) = sin α cosβ + cos α sin β sin(α+β)=sinαcosβ+cosαsinβ
c o s ( α + β ) = c o s α c o s β − s i n α s i n β cos(α + β) = cos α cosβ - sin α sin β cos(α+β)=cosαcosβsinαsinβ

代入上述公式有:
P E ( M + N , 2 i ) = P E ( M , 2 i ) × P E ( N , 2 i + 1 ) + P E ( M , 2 i + 1 ) × P E ( N , 2 i ) PE_{(M+N,2i)} = PE_{(M,2i)} × PE_{(N,2i+1)} + PE_{(M,2i+1) × PE(N,2i)} PE(M+N2i)=PE(M2i)×PE(N2i+1)+PE(M2i+1)×PE(N2i)
P E ( M + N , 2 i + 1 ) = P E ( M , 2 i + 1 ) × P E ( N , 2 i + 1 ) − P E ( M , 2 i ) × P E ( N , 2 i ) PE_{(M+N,2i+1)} = PE_{(M,2i+1)} × PE_{(N,2i+1)} - PE_{(M,2i) × PE(N,2i)} PE(M+N2i+1)=PE(M2i+1)×PE(N2i+1)PE(M2i)×PE(N2i)

也就是说, P E ( M + N ) PE_{(M+N)} PE(M+N) 可由 P E ( M ) PE_{(M)} PE(M) P E ( N ) PE_{(N)} PE(N) 相互计算得到,即各个位置间可以相互计算得到,绝对位置编码中包含了相对位置的信息

二、Pytorch源码浅析

1. Attention

注意力层的思路就是,首先取Q矩阵最后一维的大小,将Q、K、V矩阵进行运算,除 d k \sqrt{d_k} dk 来缩放注意力分数,再用softmax归一化到[0, 1],下面代码还做了剪枝和masked判断,用来降低模型参数复杂度

def attention(query, key, value, mask=None, dropout=None):

    d_k = query.size(-1)
    scores = torch.matmul(query, key.transpose(-2, -1))/math.sqrt(d_k)
    if mask is not None:
        scores = scores.masked_fill(mask == 0, -1e9)
    p_attn = F.softmax(scores, dim = -1)
    if dropout is not None:
        p_attn = dropout(p_attn)
    return torch.matmul(p_attn, value), p_attn

2、MultiHeadedAttention

多头注意力集合多个Attention Layers,首先判断d-model%h是否有余数,如果有就报错,还有查看Q矩阵的第一维度size,决定后面attention映射计算和全连接层size。contiguous的作用是断掉拷贝之间的联系。forward函数最后又把矩阵转置回来,然后经过一层全连接最后返回出去。

class MultiHeadedAttention(nn.Module):
    def __init__(self, h, d_model, dropout=0.1):
        super(MultiHeadedAttention, self).__init__()
        assert d_model % h == 0                             
        self.d_k = d_model // h
        self.h = h
        self.linears = clones(nn.Linear(d_model, d_model), 4)
        self.attn = None
        self.dropout = nn.Dropout(p=dropout)

    def forward(self, query, key, value, mask=None):
        if mask is not None:
            # Same mask applied to all h heads.
            mask = mask.unsqueeze(1)
        nbatches = query.size(0)

        # 1) Do all the linear projections in batch from d_model => h x d_k
        query, key, value = [l(x).view(nbatches, -1, self.h, self.d_k).transpose(1, 2) for l, x in zip(self.linears, (query, key, value))]
        # 2) Apply attention on all the projected vectors in batch.
        x, self.attn = attention(query, key, value, mask=mask, dropout=self.dropout)

        # 3) "Concat" using a view and apply a final linear.
        x = x.transpose(1, 2).contiguous().view(nbatches, -1, self.h * self.d_k)
        return self.linears[-1](x)

3、PositionalEncoding

PositionalEncoding是编码器位置向量的编码,首先根据权重矩阵维度构造PE列表,构造e指数函数和正余弦函数,register-buffer的作用是在内存中定一个常量方便写入和读出,像位置编码向量这种常用的共享向量。forward函数实现的就是字符embedding与位置embedding的加和

class PositionalEncoding(nn.Module):
    def __init__(self, d_model, dropout, max_len=5000):
        super(PositionalEncoding, self).__init__()
        self.dropout = nn.Dropout(p=dropout)
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len).unsqueeze(1)
        div_term = torch.exp(torch.arange(0, d_model, 2) *
                             -(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)
        self.register_buffer('pe', pe)

    def forward(self, x):
        x = x + Variable(self.pe[:, :x.size(1)], requires_grad=False)
        return self.dropout(x)

4、Embeddings

torch中的nn.embedding做了一下拓展,按照权重矩阵维度进行嵌入

class Embeddings(nn.Module):
    def __init__(self, d_model, vocab):
        super(Embeddings, self).__init__()
        self.lut = nn.Embedding(vocab, d_model)
        self.d_model = d_model

    def forward(self, x):
        return self.lut(x) * math.sqrt(self.d_model)

5、LayerNormalization

归一化层就是标准化的计算公式,计算均值和方差进行归一化

class LayerNorm(nn.Module):
    def __init__(self, features, eps=1e-6):
        super(LayerNorm, self).__init__()
        self.a_2 = nn.Parameter(torch.ones(features))
        self.b_2 = nn.Parameter(torch.zeros(features))
        self.eps = eps

    def forward(self, x):
        mean = x.mean(-1, keepdim=True)
        std = x.std(-1, keepdim=True)
        return self.a_2 * (x - mean) / (std + self.eps) + self.b_2


class SublayerConnection(nn.Module):

    def __init__(self, size, dropout):
        super(SublayerConnection, self).__init__()
        self.norm = LayerNorm(size)
        self.dropout = nn.Dropout(dropout)

    def forward(self, x, sublayer):
        return x + self.dropout(sublayer(self.norm(x)))

总结

以上就是Transformers网络学习笔记的全部内容,本文简单介绍了Transformers网络重要结构的数学原理以及简单分析一下Transformers的代码。Transformers 模型在自然语言处理(NLP)领域取得了巨大的成功,并在许多任务中取得了 state-of-the-art 的结果。后面研究人员也开始将其应用于计算机视觉(Computer Vision)领域,并取得了一些令人印象深刻的结果,像ViT(Vision Transformers)这种SOTA模型。

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

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

相关文章

Java代码审计17之fastjson反序列化漏洞(2)

文章目录 1、类加载与反射调用1.1、类加载1.2、测试代码1.3、通过类的加载和反射调用evil类 2、Fastjson TemplatesImpl链调试2.1、链路总览2.2、调试构造利用链 3、fastjson反序列化TemplatesImpl 利⽤3.1、开启 Feature.SupportNonPublicField 得作用3.2、构造利用payload3.3…

【kubernetes】使用virtual-kubelet扩展k8s

1 何为virtual-kubelet? kubelet是k8s的agent,负责监听Pod的调度情况,并运行Pod。而virtual-kubelet不是真实跑在宿主机上的,而是一个可以跑在任何地方的进程,该进程向k8s伪装成一个真实的Node,但是实际的…

关于DatagridviewComboBox控件的若干技术问题

一:DatagridviewComboBox 选定索引更改时更改 DatagridviewTextBox 文本内容 private void dataGridView1_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e){if (dataGridView1.CurrentCell.ColumnIndex 1 && e.Contr…

SpringSecurity - 认证与授权、自定义失败处理、跨域问题、认证成功/失败处理器

SpringSecurity 文章目录 SpringSecurity一、 简介二、快速入门2.1 maven坐标2.2 访问请求 三、认证与授权3.1 认证3.1.1 登录检验流程3.1.2 SpringSecurity 完整流程3.1.3 认证流程详解3.1.4 校验3.1.5 要解决的问题3.1.6 准备工作3.1.7 实现3.1.7.1 数据库校验用户3.1.7.1.1 …

在北京多有钱能称为富

背景 首先声明,此讨论仅限个人的观点,因为我本身不富嘛,所以想法应该非常局限。 举个栗子 富二代问我朋友,100~1000w之间,推荐一款车? 一开始听到这个问题的时候,有被唬住,觉得预…

Linux shell编程学习笔记2:我是谁 | who am i ?

一、前言 由于Linux系统的shell有许多种:sh、bash、cshell、tcsh、zsh……这些shell以sh为基础对象,在保持兼容性时又各有有创建,形成自己的功能特点,要想让我们编写的shell代码正确、可靠运行,我们首先应该了解我们的…

upload-labs文件上传1-5关

第一关 编写一句话木马1.php,编写完成后将后缀名修改为png 将1.png上传,上传时使用bp抓包 抓包后将后缀名修改为png 连接蚁剑 第二关 上传1.php,显示文件类型不正确 使用bp抓包发送重发器,修改文件后缀名后点击发送,…

【吴恩达老师《机器学习》】课后习题5之【偏差与方差】

在本练习中,您将实现正则化线性回归,并使用它来研究具有不同偏差-方差特性的模型。 在练习的前半部分,您将实现正则化线性回归,利用水库水位的变化来预测从大坝流出的水量。在后半部分中,您将对调试学习算法进行一些诊…

汽车电子——产品标准规范汇总和梳理(车载网络)

文章目录 前言 一、菊花链 二、K Line 三、L Line 四、RS485 五、LIN 六、CAN 七、FlexRay 八、MOST 九、Bluetooth 十、LAN 十一、移动网络 十二、实施和测试 总结 前言 见《汽车电子——产品标准规范汇总和梳理》 一、菊花链 暂无统一的正式标准。 菊花链通信&…

在Vue中通过ElementUI构建前端页面【登录,注册】,在IEDA构建后端实现前后端分离

一.ElementUI组件入门 1.对于ElementUI的理解 是一套基于 Vue.js 的开源UI组件库,提供了丰富的可复用组件,可以帮助开发者快速构建美观、易用的前端界面 2.Element UI 的特点和优势 多样化的组件:Element UI 提供了众多常用的基础组件&#…

信号量(信号量操作 基于信号量实现的生产者消费者模型)

本篇文章重点对信号量的概念,信号量的申请、初始化、释放、销毁等操作进行讲解。同时举例把信号量应用到生产者消费者模型来理解。希望本篇文章会对你有所帮助。 目录 一、信号量概念 1、1 什么是信号量 1、2 为什么要有信号量 1、3 信号量的PV操作 二、信号量的相关…

Element登录+注册

目录 一、ElementUI 1.1 定义 1.2 特点 1.3 完成用户注册登录界面搭建 1.3.1 创建一个Vue项目 1.3.2 在src目录下创建views目录 1.3.3 下载js依赖 ​编辑 1.3.4 创建用户登录注册组件 1.3.5 配置路由 1.3.6 修改项目端口并启动项目 二、数据交互 2.1 数据导入 2.2…

NLP BigModel

NLP 基础 建议看 [CS224N 2023]打基础 【NLP入门】1. n元语法模型 / 循环神经网络 【NLP入门】3. Word2Vec / GloVe Language Model:语言模型的马尔可夫假设(每个词出现的概率仅依赖前面出现的词),是一个自回归模型(…

sql注入(其他)

1.宽字节注入 组成汉字把转义的字符改为汉字 源代码 php 做转义 把语句改为gbk 2.http头部注入 3.补充

ElasticSearch - 索引库和文档相关命令操作

目录 一、ElasticSearch 索引库操作 1.1、mapping 属性 1.2、索引库相关操作 1.2.1、创建索引库 1.2.2、增加和删除索引库 1.2.3、修改索引库 1.3、文档操作 1.3.1、添加文档 1.3.2、文档的查询和删除 1.3.3、修改文档 1.全量修改:会先删除旧文档&#xf…

Windows 上下载并提取 Wikipedia

下载资源 很久以前看过了 Wikipedia 是支持 dump 的,不得不说真是造福人类的壮举。我其实也用不到这个,但是看见不少人是用来做 NLP 语料训练的。不过最近我也想尝试一些新的东西(我就是单纯想要这个文本数据),所以就…

C++ list容器的实现及讲解

所需要的基础知识 对C类的基本了解 默认构造函数 操作符重载 this指针 引用 模板等知识具有一定的了解&#xff0c;阅读该文章会很轻松。 链表节点 template<class T>struct list_node{T _data;list_node<T>* _next;list_node<T>* _prev;list_node(const T&…

Lyapunov optimization 李雅普诺夫优化

文章目录 正文引言Lyapunov drift for queueing networks 排队网络的Lyapunov漂移Quadratic Lyapunov functions 二次李雅普诺夫函数Bounding the Lyapunov drift 李亚普诺夫漂移的边界A basic Lyapunov drift theorem 一个基本的李雅普诺夫漂移定理 Lyapunov optimization for…

甲方测试如何做好外包项目的测试验收?

春节匆匆而过&#xff0c;打工人陆续回到了工作岗位又开始卷了起来。小酋也一样&#xff0c;已经返岗几天&#xff0c;今天趁着节后综合症消去大半又该聊点什么了。最近在做一个视频AI分析项目的测试验收&#xff0c;今天就围绕“如何做好外包项目的测试验收”为题&#xff0c;…

详细学习Mybatis(1)

详细学习Mybatis&#xff08;1&#xff09; 一、MyBatis概述1.1 框架1.2 三层框架1.3 了解Mybatis 二、Mybatis入门开发2.1 入门2.2、MyBatis入门程序的一些小细节2.3、MyBatis事务管理机制深度解析2.4、在开发中junit是如何使用的2.5、Mybatis集成日志框架logback 一、MyBatis…