【PyTorch][chapter 27][李宏毅深度学习][transformer-1]

news2024/11/15 11:11:54

前言:

           

            transformer 是深度学习四大基础架构之一,最早Google 发表在NIPS(NeurIPS 全称神经信息处理系统大会), 是一种seq2seq 的模型.采用的Encoder-Decoder 结构,应用比较广泛。

比如文本生成,语音转换,视频生成.

          相对RNN, LSTM ,transformer 可以并行计算,本篇重点介绍transformer 的Encoder 架构以及实现.

          深度学习四大基础架构

          MLP(BP), CNN, RNN, transformer


目录:

  1.     论文简介
  2.    Transorfomer 模型架构
  3.     Encoder 输入层
  4.     Transformer- Encoder  编码器
  5.     Multi-Head Attention  注意力机制
  6.     LayNorm
  7.    Transformer-Encoder PyTorch实现


一   论文简介  

     1  摘要     Abstract

      1.1   在主流的序列转录模型主要依赖循环,或者卷积神经网络,使用Encoder-Decoder 架构.

      1.2    这篇文章提出了一种新的简单的架构:transformer 核心是self-attention.

      1.3   通过机器翻译实验:  发现模型效果非常好.

   2    结论 Conclusion

    2.1:   这是一种序列转录模型. transformer主要应用了Mulite-Head Attention

    2.2:   实验效果: 在机器翻译效果比其它模型训练速度快,效果好

    2.3:预测该技术在其它领域的应用: 图片生成 ,语音生成 ,视频生成

    2.4:代码位置

3   导言  Introduction

         3.1: 现有技术:在seq2seq 里面常用的是 LSTM, RNN,GRU,CNN.

         3.2  RNN的缺陷:

                                   3.2.1  无法并行计算

                                   3.2.2  当序列特别长的时候,前面的信息会丢失。

                                   3.2.3  当序列特别长的时候,需要特别大的h 矩阵.内存开销大。

          3.3  现有技术 attention已经在编码器,解码器中应用.

          3.4 介绍 transformer 优势: 不再采用了Recurrent  架构,只使用attention 架构

                       3.4.1  可以并行计算,速度特别快

                       3.4.2  长序列,前面的信息不丢失

         

  4    相关工作 relate work

    4.1  现有技术

           4.1.1  cons2s ByteNet 利用卷积神经网络,但是难以处理长序列,优点是多输出通道

           4.1.2 self-attention: 在不同任务都表现不错

           4.1.3 End-to End 模型

   4.2 transformer:

        4.2.1   跟 RNN, Convolution 模型区别,第一个只依赖 self-attention来做

                   Encoder-Encoder的转录模型

        4.2.2 使用了mulite-head attention 

                 mulite-head 是使用cnn里面多输出通道原理


二   模型(model architecture)

                在序列转录模型里面现在较好的一个模型是Encoder-Decoder 架构,

transformer 采用的就是这种架构

               编码器

                           输入:    x_1,x_2,...x_n   

                           输出: z_1,z_2,..z_n

               解码器:  采用自回归模型

                               输入: z_1,z_2,..z_n     输出  y_1 。

                               根据y_1得到y_2

                               根据y_1,y_2得到 y_3

        

     


三  Encoder 输入层  

       

         输入的是一个句子:

         1   先提取词向量信息 X(Input Embedding)(batch_size,seq_length, input_size)

         2   再通过Positional Encoding 提取词向量的位置信息 PE(X)

         3   最后得到 含有位置信息的词向量 X=X+PE(X)

        


四   Transformer- Encoder  编码器

         Encoder 由 N=5 相同的layer 组成.

        每个layer  由2个sub-layer 组成

     4.1  第一个sublayer

     

   

          multi-Head attention->residual add->layerNorm

                          LayerNorm(x+sublayer(x))

4.2     第二个  sub-layer:

 position-wise Feed Forward->residual add->layerNorm

                        LayerNorm(x+sublayer(x))

       4.3    为什么叫simple,因为每个sub-layer 都是相同的

                   同时每个sub-layer 输出都是  d_{model}=512

       4.4  masked

                   这个在Decoder 时候用到

                  原因:  t时刻不应该看到t时刻以后的东西

                   假设query ,key  特征大小都是N

                   计算attention score 的时候,Q_t 只希望看到k_1,k_2,...k_t,

                  不希望看到[k_{t+1},..k_N]

                   方案: 把之后的score 设置成特别小的数-1e10 ,再通过softmax

             计算得到的结果接近为0

           

                 


 

     4.5  FFN

   

 最后还包含一个全连接的feed-forward network . 由两个线性层组成,激活函数是ReLUa_1=ReLu(xW_1+b_1)W_1 \in R^{[512,2048]}

a_2= a_1W_2+b_2:W_1 \in R^{[2048,512]}


五 Multi-Head Attention  注意力机制

    卷积神经网络多通道输出,Multi-Head 也是利用其特性,实现多通道效果

   5.1 模型结构

      把Q,K,V 投影到一个低维度空间,投影到低维空间(head_size=8),然后单独做

Scaled Dot-Product Attention ,最后对得到的结果重新Concat,

h=8,d_{model}=512,d_k=d_v=\frac{d_{model}}{h}=64

   5.2    Scaled Dot-product Attention

         有两种注意力机制 additive attention & dot-product

     这里主要用的是dot-prodct,区别是除以\sqrt{d_k},   除以 \sqrt{d_k} 原因

  当d_k 较小的时候可以不除,论文里面d_k=512/8

 d_k较大的时候,两个向量的内积较大,值最大的做softmax 后接近为1,其它的接近为0,

计算得到的梯度也小 

   


六    LayNorm

      

      6.1 输入shape X.shape  =[batch, feature]

       Batch Normalizaiton ,按列切分样本, 统计其均值和方差,归一化

       layer  Normalizaition ,  按行切分样本, 统计其均值和方差,归一化

   6.2  输入 X.shape =[batch, seq_length, feature]

     Batch Normalization: 按照黑色方向切分样本,flatten后,统计其均值方差

     Layer Normalization:   按照黑色方向切分样本,flatten后,统计其均值方差

      6.3  原因

          在时序预测的时候,样本的seq_length 可能会发生变化

         Batch Nomralization  切出来的样本如下:样本长度变化较大的时候,算出来的均值和方差变化较大。当预测的时候会使用全局的均值和方差,导致误差较大

  

# -*- coding: utf-8 -*-
"""
Created on Mon Aug  5 22:55:46 2024

@author: cxf
"""

import torch
import torch.nn as nn

x = torch.tensor([   [1.0,1.0,1.0],
                     [1.0,2.0,4.0],
                     [1.0,5.0,5.0],
                     [1.0,3.0,4.0]])

batchNorm = nn.BatchNorm1d(num_features=3)

y = batchNorm(x)
print("\n BatchNorm: ",y)
#layerNorm

layerNorm = nn.LayerNorm(3)
out = layerNorm(x)
print("\n layerNorm: ",out)


七  代码实现

   论文超参数

   

# -*- coding: utf-8 -*-
"""
Created on Sun Aug 25 15:36:03 2024

@author: cxf
"""
import torch
import torch.nn as nn
import math

class  PositionalEncoding(nn.Module):
    def __init__(self,max_seq_len=1e3, d_model=512):
        super(PositionalEncoding,self).__init__()
        
        pe = torch.zeros((max_seq_len,d_model))
        div_even =torch.pow(1e4,torch.arange(0, 512, 2)/d_model)
        div_odd = torch.pow(1e4,torch.arange(1, 512, 2)/d_model)
        position = torch.arange(0, max_seq_len).unsqueeze(1)
        pe[:,0::2]= torch.sin(position/div_even)
        pe[:,1::2]= torch.cos(position/div_odd)
        pe=pe.unsqueeze(0)
        self.register_buffer('pe', pe)
        
    def forward(self, x):
      
        batch_size, seq_len,embedding_size = x.shape
        x =x +self.pe[:,:seq_len,:].clone().detach()
        return x
    
class ScaledDotProduct_Attention(nn.Module):
    def __init__(self):
        super(ScaledDotProduct_Attention,self).__init__()
        
        self.softMax = nn.Softmax(dim=2)

    def forward(self, Q=None, K=None, V=None, attn_fill = None):
        
        batch_size, n_heads, seq_len,d_k = Q.shape
        scale = torch.matmul(Q,K.transpose(2,3))
        score = scale/math.sqrt(d_k**0.5)
        if attn_fill  is not None:
            score = scale.mask_fill(score,-1e9)
        
        attn_score = self.softMax(score)
        out = torch.matmul(attn_score,V)
        return out

class FFN(nn.Module):
    def __init__(self,input_size=512):
        super(FFN, self).__init__()
        
        self.net = nn.Sequential(
            nn.Linear(in_features=input_size, out_features=input_size*2),
            nn.ReLU(),
            nn.Linear(in_features=input_size*2, out_features=input_size)
            )
    def forward(self,x):
        
        out = self.net(x)
        return out
    
class BlockAttention(nn.Module):
    
      def __init__(self, embedding_size, d_k,head_size):
          super(BlockAttention, self).__init__()
          
          self.layer_attention = MultiHeadAttention(embedding_size=512, d_k=64, head_size=8)
          self.layer_normal = nn.LayerNorm(embedding_size)
    
      def forward(self, x):
          
          x_residual = self.layer_attention(x,None)
          out = x_residual+x
          y = self.layer_normal(out)
          return y
      
class BlockFFN(nn.Module):
    
      def __init__(self, embedding_size):
          super(BlockFFN, self).__init__()
          
          self.layer_ffn = FFN()
          self.layer_normal = nn.LayerNorm(embedding_size)
    
      def forward(self, x):
          
          x_residual = self.layer_ffn(x)
          out = x_residual+x
          y = self.layer_normal(out)
          return y
      
        

       
          
    
class Encoder(nn.Module):
    
    def __init__(self,n=5,max_seq_len=1000,embedding_size=512,head_size=8):
        super(Encoder,self).__init__()

        d_k = int(embedding_size/head_size)
        self.layer_pe = PositionalEncoding(seq_len,embedding_size)
        
        layer = nn.Sequential(
            BlockAttention(embedding_size, d_k,head_size),
            BlockFFN(embedding_size))
        
        self.layers = nn.Sequential(*[layer for _ in range(n)])

    
    def forward(self, x):
        
        
        y = self.layers(x)
    
        return y
    
class MultiHeadAttention(nn.Module):
    
    def __init__(self,embedding_size=512, d_k=64, head_size=8):
        super(MultiHeadAttention,self).__init__()
        
        #[batch,seq_len, embedding_size]
        self.W_Q = nn.Linear(embedding_size, embedding_size)
        self.W_k = nn.Linear(embedding_size, embedding_size)
        self.W_V = nn.Linear(embedding_size, embedding_size)
        
        
        self.attention_layer = ScaledDotProduct_Attention()
        self.linear_layer = nn.Linear(in_features=embedding_size, out_features=embedding_size)
        self.head_size = head_size
        self.d_model = embedding_size
        self.d_k = d_k
    
    def forward(self, inputs, attn_mask):
        #inputs.shape  [batch, seq_len, embedding_size]
        batch_size, seq_num, embedding_size = inputs.shape
        Q = self.W_Q(inputs)
        K = self.W_k(inputs)
        V = self.W_V(inputs)
        
        
        #[batch,seq_num,nheads, d_k]->[batch,head_size, seq_num,d_k]
        subQ = Q.view(batch_size, -1,self.head_size,self.d_k).transpose(1,2)
        subK = K.view(batch_size, -1,self.head_size,self.d_k).transpose(1,2)
        subV = V.view(batch_size, -1,self.head_size,self.d_k).transpose(1,2)
        
        #[batch,head_size, seq_len, d_k]
        Z =self.attention_layer(subQ,subK, subV)
        #[batch, seq_len, d_k*n_heads]
        Z= Z.transpose(1,2).contiguous().view(batch_size,-1, self.d_model)
        print(Z.shape)
        out = self.linear_layer(Z)
        
        return out
       
        
        
        
       
    

if __name__ == "__main__":
    max_seq_len =int(1e3)
    batch_size = 2
    embedding_size = 512
    head_size = 8
    d_k = int(embedding_size/head_size)
    seq_len = 3
    N = 5
    
    inputs = torch.rand(batch_size, seq_len, embedding_size)
    encoder = Encoder(N,max_seq_len,embedding_size,head_size)
    print(encoder)
    out = encoder(inputs)
        

参考:

3.【李宏毅机器学习2021】Transformer (上)_哔哩哔哩_bilibili

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

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

相关文章

【软件文档】项目总结报告编制模板(Word原件参考)

1. 项目概要 1.1. 项目基本信息 1.2. 项目期间 1.3. 项目成果 1.4. 开发工具和环境 2. 项目工作分析 2.1. 项目需求变更 2.2. 项目计划与进度实施 2.3. 项目总投入情况 2.4. 项目总收益情况 2.5. 项目质量情况 2.6. 风险管理实施情况 3. 经验与教训 3.1. 经验总结…

position的absolute、relative、fixed

’ 本章基于上图讲解。 代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"><meta name"viewport" content"widt…

信息安全(密码学)---数字证书、kpi体系结构、密钥管理、安全协议、密码学安全应用

数字证书 数字证书 (Digital Certificate,类似身份证的作用)----防伪标志 CA(Certificate Authority,电子商务认证授权机构)----ca用自己私钥进行数字签名 数字证书 姓名&#xff0c;地址&#xff0c;组织 所有者公钥 证书有效期 认证机构数字签名 ■ 公钥证书的种类与用…

10.2寸工业墨水屏平板

可翻页查看订单信息 按键下载订单 WIFI 漫游通信 IP65 防水防尘

【LeetCode面试150】——48旋转图像

博客昵称&#xff1a;沈小农学编程 作者简介&#xff1a;一名在读硕士&#xff0c;定期更新相关算法面试题&#xff0c;欢迎关注小弟&#xff01; PS&#xff1a;哈喽&#xff01;各位CSDN的uu们&#xff0c;我是你的小弟沈小农&#xff0c;希望我的文章能帮助到你。欢迎大家在…

android MutableLiveData 赋值

Android开发中&#xff0c;MutableLiveData是一个用于管理可观察型数据的类&#xff0c;它是LiveData的一个子类&#xff0c;可以用来传递数据给UI层。 要给MutableLiveData赋值&#xff0c;你需要调用它的setValue(T)方法或者postValue(T)方法。 1、声明代码&#xff1a; cl…

5大热度榜网红机型测评,公布开放式耳机哪个牌子的好用

盛夏时节&#xff0c;天气越来越热&#xff0c;小伙伴们都在抱怨&#xff0c;实在没法戴口罩了。实际上&#xff0c;大家只关注了呼吸&#xff0c;却忽视了一个问题&#xff0c;其实&#xff0c;我们的耳朵也是要“呼吸”的&#xff0c;闷热的天气里&#xff0c;长时间佩戴入耳…

七年老玩家《王者荣耀》分析三:【视觉与音效】

目录 视觉设计 音效设计 结论 王者荣耀中裸眼3D观看模式的技术细节和玩家反馈是什么&#xff1f; 王者荣耀的音乐音效设计过程中&#xff0c;有哪些知名音乐家和音效设计师参与&#xff1f; 王者荣耀如何通过音效增强游戏的情感体验和沉浸感&#xff1f; 王者荣耀中的CG动…

微信小程序消息订阅

官方文档 在微信小程序中实现消息订阅功能&#xff0c;开发者需要遵循微信官方提供的规则和API进行开发。以下是开发者实现微信小程序消息订阅的大致步骤&#xff1a; 1. 申请消息订阅权限 首先&#xff0c;开发者需要在微信公众平台&#xff08;mp.weixin.qq.com&#xff09…

期权定价模型(如Black-Scholes模型)和利率模型中的单因子模型的Python实现案例

一&#xff1a;期权定价模型&#xff08;如Black-Scholes模型&#xff09;的实现 期权定价模型&#xff08;如Black-Scholes模型&#xff09;是用来确定期权合理价格的数学模型。这些模型基于一定的假设&#xff0c;考虑了多种因素&#xff0c;如标的资产价格、期权的行权价格…

redis面试(二十五)CountDownLatch实现

CountDownLatch最基本的原理&#xff0c;就是用来阻塞线程的&#xff0c;java本身也有CountDownLatch&#xff0c;用多线程处理分批处理多数据的时候很有用 基本的逻辑就是&#xff0c;同时开多个子线程&#xff0c;然后主线程进入等待&#xff0c;只有当其他子线程全都结束之…

Windows电脑如何搭建HarmonyOS NEXTDeveloper Preview2环境

Windows电脑如何搭建HarmonyOS NEXTDeveloper Preview2环境&#xff0c;Windows电脑搭建HarmonyOS NEXTDeveloper Preview2环境详解如下&#xff0c;共分为七步&#xff0c;一看就会了。 1、电脑要求以及注意事项 操作系统 &#xff1a; Windows10 64 位、 Windows11 64 位 内…

RK3566 GPIO Set High/Low 不能正常设置

GPIO0_A4 口设置高和低都是High&#xff0c;没办法Low&#xff0c; 通过命令查看USB_SWITCH2 &#xff0c;这个pin 一直是high的。设置不了高也设置不了低。 gpio_direction_output(switch_usb_gpio2, 0); 解决办法&#xff1a; Dts配置 增加pcfg_output_low_pull_down 属性…

Numpy布尔索引与掩码

NumPy 是用于科学计算和处理多维数组数据的最流行的 Python 库之一。NumPy 提供了强大的功能&#xff0c;可以根据布尔条件从数组中索引和提取元素&#xff0c;这称为布尔索引或掩码。掌握布尔索引和掩码可以使用 NumPy 进行高效的数据操作和分析。 本综合指南将解释你需要了解…

0.0 C语言被我遗忘的知识点

文章目录 位移运算(>>和<<)函数指针函数指针的应用场景 strcmp的返回值合法的c语言实数表示sizeof 数组字符串的储存 —— 字符数组与字符指针字符串可能缺少 \0 的情况 用二维数组储存字符串数组其他储存字符串数组的方法 位移运算(>>和<<) 右移(>…

【C++】—— 模版初阶

【C】—— 模版初阶 1 泛型编程 2 函数模板2.1 函数模板基础用法2.2 模板的实例化2.2.1 隐式实例化&#xff08;推导实例化&#xff09;2.2.2 显式实例化 2.3、函数模板的原理2.4、模板参数的匹配原则 3 类模板3.1 类模板的定义格式3.2 实现栈类模板3.3 类模板为何优于 typedef…

部署Alertmanager发送告警

1、Alertmanager简介 Prometheus 对指标的收集、存储与告警能力分属于 Prometheus Server 和 AlertManager 两个独立的组件&#xff0c;前者仅负责定义告警规则生成告警通知&#xff0c; 具体的告警操作则由后者完成。 Alertmanager 负责处理由 Prometheus Server 发来的告警…

【Java设计模式】Builder模式:在Java中清晰构建自定义对象

文章目录 【Java设计模式】Builder模式&#xff1a;在Java中清晰构建自定义对象一、概述二、Builder设计模式的意图三、Builder模式的详细解释及实际示例四、Java中Builder模式的编程示例五、Builder模式类图六、Java中何时使用Builder模式七、Builder模式的优点和权衡八、源码…

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决

【STM32开发笔记】STM32H7S78-DK上的CoreMark移植和优化--兼记STM32上的printf重定向实现及常见问题解决 一、CoreMark简介二、创建CubeMX项目2.1 选择MCU2.2 配置CPU时钟2.3 配置串口功能2.4 配置LED引脚2.5 生成CMake项目 三、基础功能支持3.1 支持记录耗时3.2 支持printf输出…

三个令人破防的真理

1、所有的人都倡导正义这是不是一件好事呢&#xff1f; 答案肯定是否定的&#xff0c;因为倡导正义不等于践行正义&#xff0c;很多人都倡导&#xff0c;那你做好事是很不容易拿到结果的&#xff0c;相反&#xff0c;你如果做坏事&#xff0c;你是非常容易拿到结果的。 我们的…