【论文+代码】1706.Transformer简易学习笔记

news2024/11/24 15:56:25

Transformer 论文: 1706.attention is all you need!
唐宇迪解读transformer:transformer2021年前,从NLP活到CV的过程
综述:2110.Transformers in Vision: A Survey
代码讲解1: Transformer 模型详解及代码实现 - 进击的程序猿 - 知乎
代码讲解2:: Transformer代码解读(Pytorch) - 神洛的文章 - 知乎
在这里插入图片描述在这里插入图片描述

一、 结构概述

图1 原论文总框图

输入:词向量(embedding)
位置编码模块:给输入的词的在全局的位置信息
多头注意力层:它是有多个单层注意力层构成
正则化层:
masked-head attention
在这里插入图片描述

图2 attention的计算方式(向量表示方法)

在这里插入图片描述
在这里插入图片描述

其他论文对其结构解读

2110.Transformers in Vision: A Survey

图2 自注意层如何使用在图像特征提取中

在这里插入图片描述

图3:Transformer模型的架构概述

在这里插入图片描述
该模型最初是为语言翻译任务开发的,其中一种语言的输入序列需要转换成另一种语言的输出序列。
Transformer编码器(中间行)对输入语言序列进行操作,并在将其传递给编码器块之前将其转换为嵌入。Transformer解码器(下一行)操作先前用翻译语言生成的输出和中间分支的编码输入序列,以输出输出序列中的下一个单词。先前的输出序列(用作解码器的输入)是通过将输出语句向右移动一个位置并在开始时附加句子开始标记来获得的。这种移位避免了模型学习简单地将解码器输入复制到输出。训练模型的基本事实是输出语言序列(没有任何右移)附加一个句子结束标记。由多头注意(顶行)和前馈层组成的块在编码器和解码器中重复N次。

图6 视觉transformer的架构

在这里插入图片描述

self-attention 代码实现

from: Transformer 模型详解及代码实现 - 进击的程序猿 - 知乎

单层attention的实现

输入序列单词的 Embedding Vector 经过线性变换(Linear 层)得到 Q、K、V 三个向量,并将它们作为 Self-Attention 层的输入。假设输入序列的长度为 seq_len,则 Q、K 和 V 的形状为(seq_len,d_k),其中,dk 表示每个词或向量的维度,也是 矩阵的列数。在论文中,输入给 Self-Attention 层的 Q、K、V 的向量维度是 64,
Embedding Vector 和 Encoder-Decoder 模块输入输出的维度都是 512。
在这里插入图片描述

class ScaleDotProductAttention(nn.Module):
    def __init__(self, ):
        super(ScaleDotProductAttention, self).__init__()
        self.softmax = nn.Softmax(dim = -1)

    def forward(self, Q, K, V, mask=None):
        K_T = K.transpose(-1, -2) # 计算矩阵 K 的转置  
        d_k = Q.size(-1)
        # 1, 计算 Q, K^T 矩阵的点积,再除以 sqrt(d_k) 得到注意力分数矩阵
        scores = torch.matmul(Q, K_T) / math.sqrt(d_k)
        # 2, 如果有掩码,则将注意力分数矩阵中对应掩码位置的值设为负无穷大
        if mask is not None:
            scores = scores.masked_fill(mask == 0, -1e9)
        # 3, 对注意力分数矩阵按照最后一个维度进行 softmax 操作,得到注意力权重矩阵,值范围为 [0, 1]
        attn_weights = self.softmax(scores)
        # 4, 将注意力权重矩阵乘以 V,得到最终的输出矩阵
        output = torch.matmul(attn_weights, V)

        return output, attn_weights

# 创建 Q、K、V 三个张量
Q = torch.randn(5, 10, 64)  # (batch_size, sequence_length, d_k)
K = torch.randn(5, 10, 64)  # (batch_size, sequence_length, d_k)
V = torch.randn(5, 10, 64)  # (batch_size, sequence_length, d_k)

# 创建 ScaleDotProductAttention 层
attention = ScaleDotProductAttention()

# 将 Q、K、V 三个张量传递给 ScaleDotProductAttention 层进行计算
output, attn_weights = attention(Q, K, V)

# 打印输出矩阵和注意力权重矩阵的形状
print(f"ScaleDotProductAttention output shape: {output.shape}") # torch.Size([5, 10, 64])
print(f"attn_weights shape: {attn_weights.shape}") # torch.Size([5, 10, 10])

唐宇迪的self-attention的计算讲解

构建3个矩阵来查询,当前词和其他词的关系,特征向量表示
在这里插入图片描述

Q K V是由可训练的矩阵计算得到

在这里插入图片描述

向量对应位点乘

在这里插入图片描述

最终的输出结果 scale softmax

在这里插入图片描述

在这里插入图片描述

整体计算流程总结

即 K Q 计算是加权权重值
在这里插入图片描述

多头注意力

相当于卷积里的多层
在这里插入图片描述
多头表达多个特征
在这里插入图片描述
具体的计算
在这里插入图片描述

多头注意力代码

from: Transformer 模型详解及代码实现 - 进击的程序猿 - 知乎

class MultiHeadAttention(nn.Module):
    """Multi-Head Attention Layer
    Args:
        d_model: Dimensions of the input embedding vector, equal to input and output dimensions of each head
        n_head: number of heads, which is also the number of parallel attention layers
    """
    def __init__(self, d_model, n_head):
        super(MultiHeadAttention, self).__init__()
        self.n_head = n_head
        self.attention = ScaleDotProductAttention()
        self.w_q = nn.Linear(d_model, d_model)  # Q 线性变换层
        self.w_k = nn.Linear(d_model, d_model)  # K 线性变换层
        self.w_v = nn.Linear(d_model, d_model)  # V 线性变换层
        self.fc = nn.Linear(d_model, d_model)   # 输出线性变换层

    def forward(self, q, k, v, mask=None):
        # 1. dot product with weight matrices
        q, k, v = self.w_q(q), self.w_k(k), self.w_v(v) # size is [batch_size, seq_len, d_model]
        # 2, split by number of heads(n_head) # size is [batch_size, n_head, seq_len, d_model//n_head]
        q, k, v = self.split(q), self.split(k), self.split(v)
        # 3, compute attention
        sa_output, attn_weights = self.attention(q, k, v, mask)
        # 4, concat attention and linear transformation
        concat_tensor = self.concat(sa_output)
        mha_output = self.fc(concat_tensor)

        return mha_output

    def split(self, tensor):
        """
        split tensor by number of head(n_head)

        :param tensor: [batch_size, seq_len, d_model]
        :return: [batch_size, n_head, seq_len, d_model//n_head], 输出矩阵是四维的,第二个维度是 head 维度

        # 将 Q、K、V 通过 reshape 函数拆分为 n_head 个头
        batch_size, seq_len, _ = q.shape
        q = q.reshape(batch_size, seq_len, n_head, d_model // n_head)
        k = k.reshape(batch_size, seq_len, n_head, d_model // n_head)
        v = v.reshape(batch_size, seq_len, n_head, d_model // n_head)
        """

        batch_size, seq_len, d_model = tensor.size()
        d_tensor = d_model // self.n_head
        split_tensor = tensor.view(batch_size, seq_len, self.n_head, d_tensor).transpose(1, 2)
        # it is similar with group convolution (split by number of heads)

        return split_tensor

    def concat(self, sa_output):
        """ merge multiple heads back together

        Args:
            sa_output: [batch_size, n_head, seq_len, d_tensor]
            return: [batch_size, seq_len, d_model]
        """
        batch_size, n_head, seq_len, d_tensor = sa_output.size()
        d_model = n_head * d_tensor
        concat_tensor = sa_output.transpose(1, 2).contiguous().view(batch_size, seq_len, d_model)

        return concat_tensor

位置编码

实际的特征向量=token的词向量+位置编码
在这里插入图片描述

位置编码的代码

from : Transformer代码解读(Pytorch) - 神洛的文章 - 知乎

词嵌入之后紧接着就是位置编码,位置编码用以区分不同词以及同词不同特征之间的关系。代码中需要注意:X_只是初始化的矩阵,并不是输入进来的;完成位置编码之后会加一个dropout。另外,位置编码是最后加上去的,因此输入输出形状不变。

代码

Tensor = torch.Tensor
def positional_encoding(X, num_features, dropout_p=0.1, max_len=512) -> Tensor:
    r'''
        给输入加入位置编码
    参数:
        - num_features: 输入进来的维度
        - dropout_p: dropout的概率,当其为非零时执行dropout
        - max_len: 句子的最大长度,默认512
    
    形状:
        - 输入: [batch_size, seq_length, num_features]
        - 输出: [batch_size, seq_length, num_features]

    例子:
        >>> X = torch.randn((2,4,10))
        >>> X = positional_encoding(X, 10)
        >>> print(X.shape)
        >>> torch.Size([2, 4, 10])
    '''

    dropout = nn.Dropout(dropout_p)
    P = torch.zeros((1,max_len,num_features))
    X_ = torch.arange(max_len,dtype=torch.float32).reshape(-1,1) / torch.pow(
        10000,
        torch.arange(0,num_features,2,dtype=torch.float32) /num_features)
    P[:,:,0::2] = torch.sin(X_)
    P[:,:,1::2] = torch.cos(X_)
    X = X + P[:,:X.shape[1],:].to(X.device)
    return dropout(X)

# 位置编码例子
X = torch.randn((2,4,10))
X = positional_encoding(X, 10)
print(X.shape)

编码器其他细节

在这里插入图片描述

解码器

整体架构汇总
在这里插入图片描述

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

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

相关文章

从零开始探索C语言(六)----数组

文章目录 1. 数组初识1.1 数组声明1.2 数组初始化1.3 数组元素的访问1.4 获取数组长度1.5 数组名 2. 多维数组3. 形参数组4.函数返回数组5. 指向数组的指针6. 静态数组和动态数组6.2 静态数组6.2 动态数组 1. 数组初识 C 语言支持数组数据结构,它可以存储一个固定大…

【C++杂货铺】探索list的底层实现

文章目录 一、list的介绍及使用1.1 list的介绍1.2 list的使用1.2.1 list的构造1.2.2 list iterator的使用1.2.3 list capacity(容量相关)1.2.4 list element access(元素访问)1.2.5 list modifiers(链表修改&#xff0…

Redis7入门概述

✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Java从入门到精通 ✨特色专栏&#xf…

Docker的简介及安装

[shouce]http://shouce.jb51.net/docker_practice/栾一峰菜鸟教程参考文献 1 环境配置的难题 软件开发最大的麻烦事之一,就是环境配置。用户计算机的环境都不相同,你怎么知道自家的软件,能在那些机器跑起来? 用户必须保证两件事…

Ubuntu 22.04 桌面美化成Mac风格

安装插件 sudo apt install gnome-tweaks gnome-shell-extensions -y安装完成后在应用中可以搜索到一个名为(tweaks/优化)的应用。 下载安装主题、图标 主题 git clone https://github.com/vinceliuice/WhiteSur-gtk-theme.git cd WhiteSur-gtk-them…

智慧工厂能源管理系统

随着全球工业4.0浪潮的推进,制造业逐渐向智能化、绿色化方向发展。其中,智慧工厂能源管理系统作为绿色智能制造的重要组成部分,对于提高企业能源利用效率、降低生产成本具有重要意义。本文将从智慧工厂能源管理系统的背景、技术架构、功能及应…

Ceph一致性检查工具Scrub机制

本章介绍Ceph的一致性检查工具Scrub机制。首先介绍数据校验的基本知识,其次介绍Scrub的基本概念,然后介绍Scrub的调度机制,最后介绍Scrub具体实现的源代码分析。 1. 端到端的数据校验 在存储系统中可能会发生数据静默损坏(Silen…

【数据结构】堆的基础功能实现与PriorityQueue

文章目录 🍀堆的插入与删除🛫堆的插入🚩代码实现: 🛬堆的删除 🎋堆的常见习题🎈习题一🎈习题二🎈习题三 🎄PriorityQueue🐱‍👓Priori…

Metalenz和纵慧芯光联合推出新的结构光传感解决方案

- “Orion 18K”由Metalenz的超构表面光学元件和纵慧芯光(Vertilite)的伪随机垂直腔面发射激光器(VCSEL)组成。 - 面向智能手机的面部认证、无接触门禁控制、安防、手势识别、避障以及汽车车内监控等应用。 据麦姆斯咨询报道,领先的超构表面光学公司Metalenz和VCSEL供应商…

方案:TSINGSEE青犀视频AI智能算法平台电动车入梯检测解决方案

一、方案背景 随着大众的出行要求逐渐提升,交通拥堵现象也随处可见,电动车出行,就成了大家的首选。随着电动车数量的激增,众多用户为了个人方便,大多在室内停放或充电,有的甚至停放在走道、楼梯间等公共区…

MySQL 连接出现 Authentication plugin ‘caching_sha2_password‘ cannot be loaded

在使用Navicat Premium 12连接MySQL数据库时会出现Authentication plugin caching_sha2_password cannot be loaded 出错 出现这个原因是mysql8 之前的版本中加密规则是mysql_native_password,而在mysql8之后,加密规则是caching_sha2_password, 解决问题方法:把my…

记录了解php8-JIT

## 1.JIT编译原理1.1 JIT编译原理图 1.2 Zend Opcache作用 1.检查opcodes是否缓存2.zend compiler编译器进行编译生成opcodes3.optimizer优化器生成优化后的opcodes4.把优化后的opcodes放入opcodes cache缓存5.经过zend vm虚拟机生成opcodes handlers处理程序6.送入x86 cpu架…

记录使用layui弹窗实现签名、签字

一、前言 本来项目使用的是OCX方式做签字的,因为项目需要转到国产化,不在支持OCX方式,需要使用前端进行签字操作 注:有啥问题看看文档,或者换着思路来,本文仅供参考! 二、使用组件 获取jSign…

优雅的代码命名规范,代码如诗

优雅的代码命名规范 管理类命名传播类命名回调类命名监控类命名内存管理类命名过滤检测类命名结构类命名常见设计模式命名解析类命名网络类命名CRUD命名其他END 日常编码中,代码的命名是个大的学问。能快速的看懂开源软件的代码结构和意图,也是一项必备的…

【数据结构】二叉搜索树——二叉搜索树的概念和介绍、二叉搜索树的简单实现、二叉搜索树的增删查改

文章目录 二叉搜索树1. 二叉搜索树的概念和介绍2. 二叉搜索树的简单实现2.1二叉搜索树的插入2.2二叉搜索树的查找2.3二叉搜索树的遍历2.4二叉搜索树的删除2.5完整代码和测试 二叉搜索树 1. 二叉搜索树的概念和介绍 二叉搜索树又称二叉排序树,它或者是一棵空树&…

机器学习入门教学——可解释性

1、前言 近年来,机器学习模型被广泛地应用到现实生活中的一些重要领域,如面部识别、自动驾驶、语言处理和智慧医疗等。然而,机器学习模型就像一个黑盒子,给予一个输入,就能得到一个决策结果,但是我们并不知…

使用ECS和RDS部署WordPress,搭建个人博客并使用域名访问

目录 一、准备工作 1、准备ECS服务器 2、创建数据库账号和密码 二、部署环境 1、远程连接 2、安装Apache服务 3、部署WordPress 三、对博客的优化并使用域名访问 1、博客的设计优化 1.1 插件的使用 1.2 博客的设计介绍 2、使用域名访问 四、个人博客部署的心得 1…

glibc2.35-通过tls_dtor_list劫持exit执行流程

前言 glibc2.35删除了malloc_hook、free_hook以及realloc_hook,通过劫持这三个hook函数执行system已经不可行了。 传统堆漏洞利用是利用任意地址写改上上述几个hook从而执行system,在移除之后则需要找到同样只需要修改某个地址值并且能够造成程序流劫持…

OpenCV的绘图函数,实力绘画篮球场

关键函数:cv2.line(),cv2.circle(),cv2.rectangle(),cv2.ellipse(),cv2.putText() 等。 绘制几何形状 import cv2 as cv import numpy as npcv.rectangle(),cv.circle(),cv.line()&#xff0c…

安全远控如何设置?揭秘ToDesk、TeamViewer 、向日葵安全远程防御大招

写在前面一、远程控制:安全性不可忽略二、远控软件安全设置实测◉ ToDesk◉ TeamViewer◉ 向日葵 三、远控安全的亮点功能四、个人总结与建议 写在前面 说到远程办公,相信大家都不陌生。远程工作是员工在家中或者其他非办公场所上班的一种工作模式&…