36k字从Attention讲解Transformer及其在Vision中的应用(pytorch版)

文章目录

  • 0.卷积操作
  • 1.注意力
    • 1.1 注意力概述(Attention)
      • 1.1.1 Encoder-Decoder
      • 1.1.2 查询、键和值
      • 1.1.3 注意力汇聚: Nadaraya-Watson 核回归
    • 1.2 注意力评分函数
      • 1.2.1 加性注意力
      • 1.2.2 缩放点积注意力
    • 1.3 自注意力(Self-Attention)
      • 1.3.1 自注意力的定义和计算
      • 1.3.2 自注意力的应用
      • 1.3.3 Self-Attention 与 CNN 与 RNN
    • 1.4 多头自注意力 (Multihead Attention)
  • 2. Transformer
    • 2.1 Transformer的整体结构
    • 2.2 Transformer的输入
      • 2.2.1 单词Embedding
      • 2.2.2 位置Encoding
    • 2.3 Transformer的Encoder-Decoder
      • 2.3.1 Encoder block
      • 2.3.2 Decoder block
    • 2.4 Transformer的输出
    • 2.5 Transformer的训练过程和损失函数
      • 2.5.1 训练过程
      • 2.5.2 损失函数
    • 2.6 Transformer的代码实现
      • 2.6.1 基于位置的前馈神经网络
      • 2.6.2 残差连接和层规范化
      • 2.6.3 编码器
      • 2.6.4 解码器
      • 2.6.5 训练
  • 3. pytorch中的注意力机制类
    • 3.1 torch.nn.MultiheadAttention
  • 4. Transformer 在计算机视觉领域的应用
    • 4.1 Vision Transformer
      • 4.1.1 ViT的总体结构
      • 4.1.2 Embedding层结构详解
      • 4.1.3 Transformer Encoder详解
      • 4.1.4 MLP Head详解
    • 4.2 Swin Transformer
      • 4.2.1 网络的整体框架
      • 4.2.2 Patch Mering
      • 4.2.3 W-MSA
      • 4.2.4 SW-MSA
  • 参考文献

0.卷积操作

深度学习中的卷积操作:https://blog.csdn.net/zyw2002/article/details/128306697

1.注意力

1.1 注意力概述(Attention)

1.1.1 Encoder-Decoder

Encoder-Decoder框架顾名思义也就是编码-解码框架,在NLP中Encoder-Decoder框架主要被用来处理序列-序列问题。也就是输入一个序列,生成一个序列的问题。这两个序列可以分别是任意长度。

具体到NLP中的任务比如:

  • 文本摘要,输入一篇文章(序列数据),生成文章的摘要(序列数据)
  • 文本翻译,输入一句或一篇英文(序列数据),生成翻译后的中文(序列数据)
  • 问答系统,输入一个question(序列数据),生成一个answer(序列数据)

基于Encoder-Decoder框架具体使用什么模型实现,用的较多的应该就是seq2seq模型和Transformer了。

Encoder-Decoder中的输入和输出

输入
1)输入是一个向量
2)输入是一组向量

输出
1)每一个向量对应一个输出
2)整个序列只输出一个标签
在这里插入图片描述
3)模型自己决定输出序列的长度

Encoder-Decoder中的结构原理

在这里插入图片描述

Encoder:编码器,对于输入的序列<x1,x2,x3…xn>进行编码,使其转化为一个语义编码C,这个C中就储存了序列<x1,x2,x3…xn>的信息。

Encoder 是怎么编码的呢?

编码方式有很多种,在文本处理领域主要有RNN/LSTM/GRU/BiRNN/BiLSTM/BiGRU,可以依照自己的喜好来选择编码方式

以RNN为例来具体说明一下:
以上图为例,输入<x1,x2,x3,x4>,通过RNN生成隐藏层的状态值<h1,h2,h3,h4>,如何确定语义编码C呢?最简单的办法直接用最后时刻输出的ht作为C的状态值,这里也就是可以用h4直接作为语义编码C的值,也可以将所有时刻的隐藏层的值进行汇总,然后生成语义编码C的值,这里就是C=q(h1,h2,h3,h4),q是非线性激活函数。

得到了语义编码C之后,接下来就是要在Decoder中对语义编码C进行解码了。

Decoder:解码器,根据输入的语义编码C,然后将其解码成序列数据,解码方式也可以采用RNN/LSTM/GRU/BiRNN/BiLSTM/BiGRU

Decoder和Encoder的编码解码方式可以任意组合。

Decoder 是怎么解码的呢?

基于seq2seq模型有两种解码方式:

解码方法1:《Learning Phrase Representations using RNN Encoder–Decoder for Statistical Machine Translation》

在这里插入图片描述
该方法指出,因为语义编码C包含了整个输入序列的信息,所以在解码的每一步都引入C。文中Ecoder-Decoder均是使用RNN,在计算每一时刻的输出yt时,都应该输入语义编码C,即
在这里插入图片描述
类似的,下一个符号的条件分布是:

在这里插入图片描述
其中 h t h_t ht为当前t时刻的隐藏层的值, y t − 1 y_{t-1} yt1为上一时刻的预测输出,作为t时刻的输入,每一时刻的语义编码C是相同地。

解码方法2:《Sequence to Sequence Learning with Neural Networks》
在这里插入图片描述
这个编码方式相对简单,只在Decoder的初始输入引入语义编码C,将语义编码C作为隐藏层状态值 h 0 h_0 h0的初始值,
在这里插入图片描述
如上图,该模型读取一个输入句子“ABC”,并产生“WXYZ”作为输出句子。模型在输出句尾标记后停止进行预测。注意,LSTM读取反向输入句子,因为这样做会在数据中引入许多短期依赖关系

基于seq2seq模型有两种解码方式都不太好(两种解码方式都只采用了一个语义编码C),而基于attention模型的编码方式中采用了多个C

在这里插入图片描述
上图就是引入了Attention 机制的Encoder-Decoder框架。咱们一眼就能看出上图不再只有一个单一的语义编码C,而是有多个C1,C2,C3这样的编码。当我们在预测Y1时,可能Y1的注意力是放在C1上,那咱们就用C1作为语义编码,当预测Y2时,Y2的注意力集中在C2上,那咱们就用C2作为语义编码,以此类推,就模拟了人类的注意力机制。

以机器翻译例子"Tom chase Jerry" - "汤姆追逐杰瑞"来说明注意力机制:

当我们在翻译"杰瑞"的时候,为了体现出输入序列中英文单词对于翻译当前中文单词不同的影响程度,比如给出类似下面一个概率分布值:
(Tom,0.3)(Chase,0.2)(Jerry,0.5)

每个英文单词的概率代表了翻译当前单词“杰瑞”时,注意力分配模型分配给不同英文单词的注意力大小。这对于正确翻译目标语单词肯定是有帮助的,因为引入了新的信息。同理,目标句子中的每个单词都应该学会其对应的源语句子中单词的注意力分配概率信息。这意味着在生成每个单词Yi的时候,原先都是相同的中间语义表示C会替换成根据当前生成单词而不断变化的Ci。理解AM模型的关键就是这里,即由固定的中间语义表示C换成了根据当前输出单词来调整成加入注意力模型的变化的Ci。

每个Ci 对应这不同源语句子单词的注意力分配概率,比如对于上面的英汉翻译来说,对应的信息可能如下:
在这里插入图片描述
f2(“Tom”),f2(“Chase”),f2(“Jerry”)就是对应的隐藏层的值h(“Tom”),h(“Chase”),h(“Jerry”)。g函数就是加权求和。αi表示权值分布。因此Ci的公式就可以写成:
在这里插入图片描述

怎么知道attention模型所需要的输入句子单词注意力分配概率分布值 a i j a_{ij} aij呢? 我们可以通过下文介绍的注意力评分函数求得

1.1.2 查询、键和值

下面来看看如何通过自主性的与非自主性的注意力提示, 用神经网络来设计注意力机制的框架。

首先,考虑一个相对简单的状况, 即只使用非自主性提示。 要想将选择偏向于感官输入, 则可以简单地使用参数化的全连接层, 甚至是非参数化的最大汇聚层或平均汇聚层

在注意力机制的背景下,自主性提示被称为查询(query)。 给定任何查询,注意力机制通过注意力汇聚(attention pooling)将选择引导至感官输入(sensory inputs,例如中间特征表示)。在注意力机制中,这些感官输入被称为值(value)。 更通俗的解释,每个值都与一个键(key)配对, 这可以想象为感官输入的非自主提示。
在这里插入图片描述
如上图: 注意力机制通过注意力汇聚(注意力的分配方法)将查询(自主性提示)和键(非自主性提示)结合在一起,实现对值(感官输入)的选择倾向。

1.1.3 注意力汇聚: Nadaraya-Watson 核回归

上图中的注意力汇聚是怎么实现的呢?
可通过Nadaraya-Watson核回归模型来了解常见的注意力汇聚模型平均汇聚非参数注意力汇聚带参数注意力汇聚)。


为什么要在机器学习中引入注意力机制呢?

在全连接层,FC只能考虑相邻的几个数据,但是无法考虑到整个序列。
在这里插入图片描述
注意力机制(self-attention)可以考虑到整个序列的信息。因此,输出的向量带有全局的上下文信息。
在这里插入图片描述

1.2 注意力评分函数

接下来,我们讲解如何通过注意力评分函数来分配注意力。

我们使用高斯核来对查询(query)和键(key)之间的关系建模。 我们可以将高斯核指数部分视为注意力评分函数(attention scoring function), 简称评分函数(scoring function),然后把这个函数的输出结果输入到softmax函数中进行运算。 通过上述步骤,我们将得到与键对应的值的概率分布(即注意力权重)。最后,注意力汇聚的输出就是基于这些注意力权重的值的加权和

下图说明了如何将注意力汇聚的输出计算成为值的加权和, 其中a表示注意力评分函数。 由于注意力权重是概率分布, 因此加权和其本质上是加权平均值。
在这里插入图片描述
在这里插入图片描述
正如我们所看到的,选择不同的注意力评分函数a会导致不同的注意力汇聚操作。 在本节中,我们将介绍两个流行的评分函数(加性注意力、缩放点积注意力),稍后将用他们来实现更复杂的注意力机制


掩蔽softmax操作

掩蔽softmax操作, 是为实现下文的评分函数做铺垫。

正如上面提到的,softmax操作用于输出一个概率分布作为注意力权重。 在某些情况下,并非所有的值都应该被纳入到注意力汇聚中。 例如,为了高效处理小批量数据集, 某些文本序列被填充了没有意义的特殊词元。 为了仅将有意义的词元作为值来获取注意力汇聚, 我们可以指定一个有效序列长度(即词元的个数), 以便在计算softmax时过滤掉超出指定范围的位置。 通过这种方式,我们可以在下面的masked_softmax函数中 实现这样的掩蔽softmax操作(masked softmax operation), 其中任何超出有效长度的位置都被掩蔽并置为0。

#@save
def masked_softmax(X, valid_lens):
    """通过在最后一个轴上掩蔽元素来执行softmax操作"""
    # X:3D张量,valid_lens:1D或2D张量
    if valid_lens is None:
        return nn.functional.softmax(X, dim=-1)
    else:
        shape = X.shape
        if valid_lens.dim() == 1:
            valid_lens = torch.repeat_interleave(valid_lens, shape[1])
        else:
            valid_lens = valid_lens.reshape(-1)
        # 最后一轴上被掩蔽的元素使用一个非常大的负值替换,从而其softmax输出为0
        X = d2l.sequence_mask(X.reshape(-1, shape[-1]), valid_lens,
                              value=-1e6)
        return nn.functional.softmax(X.reshape(shape), dim=-1)

为了演示此函数是如何工作的, 考虑由两个2×4矩阵表示的样本, 这两个样本的有效长度分别为2和3。 经过掩蔽softmax操作,超出有效长度的值都被掩蔽为0。

masked_softmax(torch.rand(2, 2, 4), torch.tensor([2, 3]))
tensor([[[0.5423, 0.4577, 0.0000, 0.0000],
         [0.6133, 0.3867, 0.0000, 0.0000]],

        [[0.3324, 0.2348, 0.4329, 0.0000],
         [0.2444, 0.3943, 0.3613, 0.0000]]])

同样,我们也可以使用二维张量,为矩阵样本中的每一行指定有效长度。

masked_softmax(torch.rand(2, 2, 4), torch.tensor([[1, 3], [2, 4]]))
tensor([[[1.0000, 0.0000, 0.0000, 0.0000],
         [0.4142, 0.3582, 0.2275, 0.0000]],

        [[0.5565, 0.4435, 0.0000, 0.0000],
         [0.3305, 0.2070, 0.2827, 0.1798]]])

1.2.1 加性注意力

#@save
class AdditiveAttention(nn.Module):
    """加性注意力"""
    def __init__(self, key_size, query_size, num_hiddens, dropout, **kwargs):
        super(AdditiveAttention, self).__init__(**kwargs)
        self.W_k = nn.Linear(key_size, num_hiddens, bias=False)
        self.W_q = nn.Linear(query_size, num_hiddens, bias=False)
        self.w_v = nn.Linear(num_hiddens, 1, bias=False)
        self.dropout = nn.Dropout(dropout)

    def forward(self, queries, keys, values, valid_lens):
        queries, keys = self.W_q(queries), self.W_k(keys)
        # 在维度扩展后,
        # queries的形状:(batch_size,查询的个数,1,num_hidden)
        # key的形状:(batch_size,1,“键-值”对的个数,num_hiddens)
        # 使用广播方式进行求和
        features = queries.unsqueeze(2) + keys.unsqueeze(1)
        features = torch.tanh(features)
        # self.w_v仅有一个输出,因此从形状中移除最后那个维度。
        # scores的形状:(batch_size,查询的个数,“键-值”对的个数)
        scores = self.w_v(features).squeeze(-1)
        self.attention_weights = masked_softmax(scores, valid_lens)
        # values的形状:(batch_size,“键-值”对的个数,值的维度)
        return torch.bmm(self.dropout(self.attention_weights), values)

我们用一个小例子来演示上面的AdditiveAttention类, 其中查询、键和值的形状为(批量大小,步数或词元序列长度,特征大小), 实际输出为(2,1,20)、(2,10,2)和(2,10,4)。 注意力汇聚输出的形状为(批量大小,查询的步数,值的维度)。

queries, keys = torch.normal(0, 1, (2, 1, 20)), torch.ones((2, 10, 2))
# values的小批量,两个值矩阵是相同的
values = torch.

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

python爬虫11:实战3

python爬虫11&#xff1a;实战3 前言 ​ python实现网络爬虫非常简单&#xff0c;只需要掌握一定的基础知识和一定的库使用技巧即可。本系列目标旨在梳理相关知识点&#xff0c;方便以后复习。 申明 ​ 本系列所涉及的代码仅用于个人研究与讨论&#xff0c;并不会对网站产生不好…

nonlocal关键字声明

nonlocal关键字声明 作用 使得内层函数可以使用/修改外层函数的变量 值得注意的是&#xff0c;在未使用nonlocal声明时 对于外层函数中的可变对象&#xff0c;内层函数即可访问&#xff0c;也可以修改 def outer():x, y [1], [2]def inner(z):x.append(1)print(x)print(z)r…

历史最佳二季度表现后,爱奇艺想为用户提供更多价值

以爱奇艺为首&#xff0c;随着长视频平台相继转变运营思路&#xff0c;走向盈利目标&#xff0c;最早完成蜕变的爱奇艺&#xff0c;已开始迈向下一阶段。 近日&#xff0c;爱奇艺发布了截至6月30日的2023年第二季度财报。除了依然亮眼的内容表现、业绩成果外&#xff0c;爱奇艺…

1.Flink源码编译

目录 1.环境版本 1.1 jdk 1.2.maven 1.3.node 1.4.scala 2.下载flink源码 3.编译源码 4.idea打开flink源码 5.运行wordcount 1.环境版本 软件地址 链接&#xff1a;https://pan.baidu.com/s/1ZxYydR8rBfpLCcIdaOzxVg 提取码&#xff1a;12xq 1.1 jdk 1.2 maven 1.…

Bean 作用域和生命周期

前言&#xff1a; &#x1f4d5;作者简介&#xff1a;热爱编程的小七&#xff0c;致力于C、Java、Python等多编程语言&#xff0c;热爱编程和长板的运动少年&#xff01; &#x1f4d8;相关专栏Java基础语法&#xff0c;JavaEE初阶&#xff0c;数据库&#xff0c;数据结构和算法…

GPT4模型架构的泄漏与分析

迄今为止&#xff0c;GPT4 模型是突破性的模型&#xff0c;可以免费或通过其商业门户&#xff08;供公开测试版使用&#xff09;向公众提供。它为许多企业家激发了新的项目想法和用例&#xff0c;但对参数数量和模型的保密却扼杀了所有押注于第一个 1 万亿参数模型到 100 万亿参…

【Mac】编译Spring 源码和Idea导入

今天我们开始Spring源码的阅读之旅。阅读Spring的源码的第一步当然是编译Spring源码。首先我们要去GitHub上将spring源码给clone下来。 笔者编译环境如下&#xff1a; Spring版本&#xff1a;5.28 https://github.com/spring-projects/spring-framework/tree/v5.2.8.RELEASE …

LoadRunner操作教程

日升时奋斗&#xff0c;日落时自省 目录 1、Virtual User Generator &#xff08;VUG&#xff09; 1.1、WebTours系统 1.1.1、WebTours启动 1.1.2、WebTours配置 1.2、脚本录制 1.3、编译 1.4、脚本运行 1.5、加强脚本 1.5.1、事务插入 1.5.2、插入集合点 1.5.3、参…

【C++ 学习 ⑰】- 继承(下)

目录 一、派生类的默认成员函数 二、继承与友元 三、继承与静态成员 四、复杂的菱形继承及菱形虚拟继承 五、继承和组合 一、派生类的默认成员函数 派生类的构造函数必须调用基类的构造函数初始化基类的那一部分成员。如果基类没有默认构造函数&#xff0c;那么必须在派生…

Python基础学习第一天:关于Python的简单介绍

前言 最近一批批大一新生都要开始踏入校园了&#xff0c;计算机专业 emmm…如果有需要学习python的&#xff0c;尤其是还没开学的&#xff0c;确实可以开始找找资料看看python了&#xff0c;如果是自己本来就对python感兴趣&#xff0c;更应该需要看看了&#xff0c;毕竟学校到…

阿里云 Serverless 应用引擎 2.0,正式公测!

阿里云 Serverless 应用引擎 SAE2.0 正式公测上线&#xff01;全面升级后的 SAE2.0 具备极简体验、标准开放、极致弹性三大优势&#xff0c;应用冷启动全面提效&#xff0c;秒级完成创建发布应用&#xff0c;应用成本下降 40% 以上。 此外&#xff0c;阿里云还带来容器服务 Se…

无涯教程-聚类算法 - Mean-Shift

如前所述&#xff0c;它是在无监督学习中使用的另一种强大的聚类算法&#xff0c;与K均值聚类不同&#xff0c;它不做任何假设&#xff0c;因此&#xff0c;它是一种非参数算法。 均值平移算法基本上是通过将数据点移向最高密度的数据点(即群集质心)来迭代地将数据点分配给群集…

【日常积累】Linux中vi/vim的使用

概述 vim是由vi发展演变过来的文本编辑器&#xff0c;因其具有语法高亮显示、多视窗编辑、代码折叠、支持插件等功能&#xff0c;由于其功能相比vi来说更加强大&#xff0c;所以在实际工作中的使用更加广泛。 vim工作模式 Vim具有多种工作模式&#xff0c;常用的工作模式有&…

去除wps段落柄,删除空白页

如图&#xff0c;有一个段落柄在左端&#xff0c;无法删除&#xff0c;只能编辑。 导致本来是8页内容&#xff0c;现在是9页&#xff0c;多了一空白页 后面新建一个空白页&#xff0c;发现默认会自带一个段落柄&#xff0c;所以有可能这个段落柄是不能消除的&#xff0c;那么如…

【LeetCode-面试经典150题-day15】

目录 104.二叉树的最大深度 100.相同的树 226.翻转二叉树 101.对称二叉树 105.从前序与中序遍历序列构造二叉树 106.从中序与后序遍历序列构造二叉树 117.填充每个节点的下一个右侧节点指针Ⅱ 104.二叉树的最大深度 题意&#xff1a; 给定一个二叉树 root &#xff0c;返回其…

智能井盖传感器,物联网智能井盖系统

随着城市人口的不断增加和城市化进程的不断推进&#xff0c;城市基础设施的安全和可靠性变得愈发重要&#xff0c;城市窨井盖作为城市基础设施重要组成部分之一&#xff0c;其安全性事关城市安全有序运行和居民生产生活安全保障。 近年来&#xff0c;各地都在加强城市窨井盖治理…

【C/C++】多态的概念 | 虚函数 | 虚函数指针

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

STM32 BOOT 启动配置 ISP升级 介绍

启动配置 在STM32F10xxx里&#xff0c;可以通过BOOT[1:0]引脚选择三种不同启动模式。 启动模式选择引脚启动模式说明BOOT1BOOT0X0主闪存存储器主闪存存储器被选为启动区域01系统存储器系统存储器被选为启动区域11内置SRAM内置SRAM被选为启动区域 在系统复位后&#xff0c; S…

Kafka核心原理第一弹——更新中

架构原理 一、高性能读写架构原理——顺序写零拷贝 首先了解两个专业术语&#xff0c;研究kafka这个东西&#xff0c;你必须得搞清楚这两个概念&#xff0c;吞吐量&#xff0c;延迟。 写数据请求发送给kafka一直到他处理成功&#xff0c;你认为写请求成功&#xff0c;假设是…

WOFOST模型与PCSE模型应用

目录 第一章 理论基础 农作物生长模型概述 第二章 数据准备 第三章 WOFOST模型基础 第四章 PythonCropSimulationEnvironment 第五章 案例拓展 更多应用 实现作物产量的准确估算对于农田生态系统响应全球变化、可持续发展、科学粮食政策制定、粮食安全维护都至关重要。传…
最新文章