Python深度学习基于Tensorflow(9)注意力机制

news2024/11/28 0:35:43

文章目录

        • 注意力机制是怎么工作的
        • 注意力机制的类型
      • 构建Transformer模型
        • Embedding层
        • 注意力机制的实现
        • Encoder实现
        • Decoder实现
        • Transformer实现

注意力机制的主要思想是将注意力集中在信息的重要部分,对重要部分投入更多的资源,以获取更多所关注目标的细节信息,抑制其他无用信息;

在注意力机制的背景下,我们将自主性提示称为查询(Query)。对于给定任何查询,注意力机制通过集中注意力(Attention Pooling)选择感官输入(Sensory Input),这些感官输入被称为值(Value)。每个值都与其对应的非自主提示的一个键(Key)成对。通过集中注意力,为给定的查询(自主性提示)与键(非自主性提示)进行交互,从而引导选择偏向值;

注意力机制计算过程如下:

![[Pasted image 20240512132525.png]]

注意力机制是怎么工作的

图中有四个东西,QueryKeyValueAttention,图中把KeyValue放在了一起是因为其产生的output是与KeyValue的维度是无关的,只与Query的维度有关;文中把KeyValue称作为Context sequenceQuery还是称作为Query sequence;为什么要这么做?可以看模型中右上方的Multi-Head Attention和左下角的Multi-Head Attention的区别进行分析;

QueryKeyValue这三个东西可以用python中的字典来解释,KeyValue表示字典中的键值对,而Query表示我们需要查询的键,QueryKeyValue匹配其得到的结果就是我们需要的信息;但是在这里并不要求QueryKey严格匹配,只需要模糊匹配就可以;Query对每一个Key进行一次模糊的匹配,并给出匹配程度,越适配权重就越大,然后根据权重再与每一个Value进行组合,得到最后的结果;其匹配程度的权重就代表了注意力机制的权重;

多头注意力机制就是把QueryKeyValue多个维度的向量分为几个少数维度的向量组合,再在Query_iKey_iValue_i上进行操作,最后把结果合并;

注意力机制的类型

Transformer模型中Multi-Head Attention有三个, 这三个分别对应三种Multi-Head Attention Layerthe cross attention layerthe global self attention layerthe causal self attention layer,从图中也可以发现每一层都有各自的不同,下面来一一介绍;

the cross attention layer:模型右上角(解码器)的Multi-Head Attention是注意力机制最直接的使用,其将编码器的信息和解码器的信息充分的结合了起来,文中把这一层叫做the cross attention layer;其context sequenceEncoder中得到的;

在这里要注意的是,每一次的查询是可以看得到所有的KeyValue的,但是查询与查询相互之间是看不到的,即独立的;

the global self attention layer:模型左下角(编码器)的Multi-Head Attention,这一层负责处理上下文序列,并沿着他的长度去传播信息即QueryQuery之间的信息;

Query与Query之间的信息传播有很多种方式,例如在Transformer没出来之间我们普遍采用Bidirectional RNNsCNNs的方式来处理;

但是为什么这里不使用RNN和CNN的方法呢?

RNNCNN的限制

  • RNN 允许信息沿着序列一路流动,但是它要经过许多处理步骤才能到达那里(限制梯度流动)。这些 RNN 步骤必须按顺序运行,因此 RNN 不太能够利用现代并行设备的优势。
  • 在 CNN 中,每个位置都可以并行处理,但它只提供有限的接收场。接收场只随着 CNN 层数的增加而线性增长,需要叠加许多卷积层来跨序列传输信息(小波网通过使用扩张卷积来减少这个问题)。

the global self attention layer允许每个序列元素直接访问每个其他序列元素,只需少量操作,并且所有输出都可以并行计算。 就像下图这样:

虽然图像类似于线性层,其本质好像也是线性层,但是其信息传播能力要比普通的线性层要强;

the causal self attention layer:因果自注意层,这一层与the global self attention layer类似,其不同的特点是需要maskMasked Multi-Head Attention;这里要注意的是Transformer是一个自回归模型,每次产生一个输出并且把输出当作输入用来继续产生输出,因此这些模型确保每个序列元素的输出仅依赖于先前的序列元素,所以需要对Attention weights进行处理;

根据论文公式: A t t e n t i o n ( Q , K , V ) = s o f t m a x ( Q K T d k ) V Attention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_k}})V Attention(Q,K,V)=softmax(dk QKT)V
可以发现 Q Q Q K K K是做矩阵运算的, A t t e n t i o n Attention Attention中的单个元素计算是 Q Q Q中的某行和 K K K中的某行做点积运算;论文中是计算 A t t e n t i o n Attention Attention后在相应掩码位置乘一个无穷小,这里其实可以优化一下,只计算 A t t e n t i o n Attention Attention有效的位置,可以加快速度;

这一层根据训练和推理有一点不同,如上文所说,在训练时,我们不需要每一次新产生的输出做为输入,我们直接用真值(shift)代替新产生的输出进行训练就好,这样可以在缺失一点稳定性的情况下,加快训练速度,并得到每一个位置上的损失大小;

在推理时,我们并没有真值,我们只能以每一次新产生的输出作为输入进行计算,这里有两种自回归的处理方式;一个是RNN,一个是CNN:Fast Wavenet;

以下是该层的简要表示,即每个序列元素的输出仅依赖于先前的序列元素;

构建Transformer模型

模型结构如下:

Embedding层

Embedding层分为两个部分:input_embeddingposition_embedding

首先是input_embedding,假设 “注意力机制是Transformer的核心” 这句话分词得到 [注意力机制, 是, Transformer, 的, 核心];用序号表示为[1,2,3,4,5],由于是分类变量,需要转化为独热编码再使用权重矩阵映射到某一维度,然而这里可以直接用tf.kears.layers.Embedding一步实现上述两步功能;其需要一个input_dim:表示分类个数,也就是序号的最大值;output_dim:表示隐藏层维度,也就是d_model

其次是position_embedding,论文中采用的是绝对位置编码的方式:

![[Pasted image 20240512143453.png]]

其需要两个参数,一个是pos,这是表示位置,也就是 输入序列的长度 范围内的值,第二个是i,这表示嵌入向量的位置,也就是d_model 隐藏维度范围内的值;实现代码如下:

def absolute_position_embedding(n_len, d_model):
    positions = tf.range(n_len, dtype=tf.float32)[:,tf.newaxis]
    depths = tf.range(d_model//2, dtype=tf.float32)[tf.newaxis, :]/(d_model//2)
    angle_rads = positions / (10000**depths)
    pos_embedding = tf.concat([tf.sin(angle_rads), tf.cos(angle_rads)], axis=-1)
    return pos_embedding

# position_input = absolute_position_embedding(n_len=2048, d_model=512)
# plt.pcolormesh(position_input.numpy().T, cmap='RdBu')
# plt.ylabel('Depth')
# plt.xlabel('Position')
# plt.colorbar()
# plt.show()

结合起来获得Embeding,使用 tf.keras.layers.Layer 类表达如下:

class Embedding(tf.keras.layers.Layer):
    def __init__(self, n_len, input_dim, d_model):
        super(Embedding, self).__init__()
        self.input_embedding = tf.keras.layers.Embedding(input_dim=input_dim, output_dim=d_model)
        self.position_embedding = self.absolute_position_embedding(n_len=n_len, d_model=d_model)
        
    def absolute_position_embedding(self, n_len, d_model):
        positions = tf.range(n_len, dtype=tf.float32)[:,tf.newaxis]
        depths = tf.range(d_model//2, dtype=tf.float32)[tf.newaxis, :]/(d_model//2)
        angle_rads = positions / (10000**depths)
        pos_embedding = tf.concat([tf.sin(angle_rads), tf.cos(angle_rads)], axis=-1)
        return pos_embedding

    def call(self, x):
        x = self.input_embedding(x)
        output = x + self.position_embedding
        return output
注意力机制的实现

由于要适应三种注意力机制,我们需要分离 maskqkv功能

class MultiHeadAttention(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads):
        super(Self_Attention_Mechanism, self).__init__()

        self.num_heads = num_heads
        self.wq = tf.keras.layers.Dense(d_model)
        self.wk = tf.keras.layers.Dense(d_model)
        self.wv = tf.keras.layers.Dense(d_model)

        self.wo = tf.keras.layers.Dense(d_model)

    def split_head(self, x):
        """(batch_size, heads, len, depth)"""
        output = tf.reshape(x, [x.shape[0], x.shape[1], self.num_heads, -1])
        output = tf.transpose(output, [0,2,1,3])
        return output

    def scaled_dot_product_attention(self, q, k, v, mask=False):
        dk = tf.cast(k.shape[-1], tf.float32)
        matmul_qk = tf.matmul(q, k, transpose_b=True) / tf.math.sqrt(dk)
        if mask:
            matmul_qk += -(1 - tf.linalg.band_part(tf.ones_like(matmul_qk), 0, -1)) * 1e9
    
        attention_weighs = tf.nn.softmax(matmul_qk, axis=-1)
        outputs = tf.matmul(attention_weighs, v)
        return attention_weighs, outputs
        
    def call(self, q, k, v, mask=False, return_attention_weights=False):
        q = self.split_head(self.wq(q))
        k = self.split_head(self.wk(k))
        v = self.split_head(self.wv(v))
        attention_weighs, output = self.scaled_dot_product_attention(q, k, v, mask=mask)
        output = tf.transpose(output, [0,2,1,3])
        output = tf.reshape(output, [output.shape[0], output.shape[1], -1])
        output = self.wo(output)
        if return_attention_weights:
            return attention_weighs, output
        else:
            return output
Encoder实现

由于 Encoder 有六个相同的子块 EncoderLayer,这里先实现一下 EncoderLayer

EncoderLayer 中 包含一个自注意力机制以及一个前反馈层,所以需要三个参数初始化:d_modelnum_headsdff

这里 dff 表示前反馈层中的投影维度;

class EncoderLayer(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads, dff):
        super(EncoderLayer, self).__init__()
        self.mha = MultiHeadAttention(d_model, num_heads)
        self.fnn_in = tf.keras.layers.Dense(dff, activation='relu')
        self.fnn_out = tf.keras.layers.Dense(d_model)
        self.layernorm1 = tf.keras.layers.LayerNormalization()
        self.layernorm2 = tf.keras.layers.LayerNormalization()

    def call(self, x):
        x1 = self.mha(q=x, k=x, v=x)
        x1 = self.layernorm1(x + x1)
        x2 = self.fnn_in(x1)
        x2 = self.fnn_out(x2)
        output = self.layernorm2(x1 + x2)
        return output

Encoder 从本质来说就是 EncoderLayer 的累加:

class Encoder(tf.keras.layers.Layer):
    def __init__(self, num_encoder_layer, d_model, num_heads, dff):
        super(Encoder, self).__init__()
        self.encoder_layers = [EncoderLayer(d_model, num_heads, dff) for _ in range(num_encoder_layer)]

    def call(self, x):
        for encoder_layer in self.encoder_layers:
            x = encoder_layer(x)
        return x
Decoder实现

同样按照Encoder中一样实现,但是不同的是:首先多了一个 Mask MutliHead Attention,其次第二个MHA中 kv 是来自于Encoder

class Decoder_layer(tf.keras.layers.Layer):
    def __init__(self, d_model, num_heads, dff):
        super(Decoder_layer, self).__init__()
        self.mha1 = MultiHeadAttention(d_model, num_heads)
        self.mha2 = MultiHeadAttention(d_model, num_heads)

        self.fnn_in = tf.keras.layers.Dense(dff, activation='relu')
        self.fnn_out = tf.keras.layers.Dense(d_model)
        
        self.layernorm1 = tf.keras.layers.LayerNormalization()
        self.layernorm2 = tf.keras.layers.LayerNormalization()
        self.layernorm3 = tf.keras.layers.LayerNormalization()

    def call(self, x, enc_output):
        x1 = self.mha1(q=x, k=x, v=x, mask=True)
        x1 = self.layernorm1(x + x1)
        x2 = self.mha2(q=x1, k=enc_output, v=enc_output)
        x2 = self.layernorm2(x1 + x2)
        x3 = self.fnn_in(x2)
        x3 = self.fnn_out(x3)
        output = self.layernorm3(x2 + x3)
        return output

循环 DecoderLayer 得到 Decoder

class Decoder(tf.keras.layers.Layer):
    def __init__(self, num_decoder_layer, d_model, num_heads, dff):
        super(Decoder, self).__init__()
        self.decoder_layers = [Decoder_layer(d_model, num_heads, dff) for _ in range(num_decoder_layer)]

    def call(self, x, enc_output):
        for decoder_layer in self.decoder_layers:
            x = decoder_layer(x, enc_output)
        return x
Transformer实现

结合一下前面实现的东西,很轻松可以得到:

class Transformer(tf.keras.Model):
    def __init__(self, num_encoder_layer, num_decoder_layer, input_dim, n_len, d_model, num_heads, dff):
        super(Transformers, self).__init__()
        self.embedding_1 = Embedding(n_len, input_dim, d_model)
        self.embedding_2 = Embedding(n_len, input_dim, d_model)
        self.encoder = Encoder(num_encoder_layer, d_model, num_heads, dff)
        self.decoder = Decoder(num_decoder_layer, d_model, num_heads, dff)
        self.final_dense = tf.keras.layers.Dense(input_dim, activation='softmax')

    def call(self, x1, x2):
        x1 = self.embedding_1(x1)
        x2 = self.embedding_2(x2)
        x1 = self.encoder(x1)
        x2 = self.decoder(x2, x1)
        output = self.final_dense(x2)
        return output

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

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

相关文章

2024最新商业视频打赏系统源码 多套模板 有代理后台 已对接支付

简介: 2024最新商业视频打赏系统源码 多套模板 有代理后台 已对接支付 图片: 源码下载

清华发布Temporal Scaling Law,解释时间尺度对大模型表现的影响

众所周知, 语言模型调参! 预训练语言模型调参!! 预训练大语言模型调参!!! 简直就是一个指数级递增令人炸毛的事情,小编也常常在做梦,要是只训练几步就知道现在的超参…

【优选算法】—Leetcode—11—— 盛最多水的容器

1.题目 11. 盛最多水的容器 给定一个长度为 n 的整数数组 height 。有 n 条垂线,第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线,使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#…

K邻近算法

简介 介绍了非常简单的算法:K邻近算法,即KNN。 基本介绍 K-近邻算法(K-Nearest Neighbors,简称KNN)是一种基本且广泛应用的监督学习算法,主要用于分类和回归任务。 工作原理非常简答直观:所谓…

改变浏览器大小,图片(img)内容居中显示img标签,不是背景图

改变浏览器大小,图片&#xff08;img&#xff09;内容居中显示&#xff0c;img标签&#xff0c;不是背景图 效果直接上图&#xff1a; 上代码&#xff1a; <!DOCTYPE html> <html> <head><title>测试图片居中显示&#xff0c;高度不变只变宽度<…

面试集中营—Seata分布式事务

一、分布式事务 本地事务 在计算机系统中&#xff0c;更多的是通过关系型数据库来控制事务&#xff0c;这是利用数据库本身的事务特性来实现的&#xff0c; 因此叫数据库事务&#xff0c;由于应用主要靠关系数据库来控制事务&#xff0c;而数据库通常和应用在同一个服务器&am…

SQLite利用事务实现批量插入(提升效率)

在尝试过SQLite批量插入一百万条记录&#xff0c;执行时长高达20多分钟后&#xff0c;就在想一个问题&#xff0c;这样的性能是不可能被广泛应用的&#xff0c;更不可能出现在真实的生产环境中&#xff0c;那么对此应该如何优化一下呢&#xff1f; 首先分析一下批量插入的逻辑 …

社交媒体数据恢复:脉脉

在使用社交软件脉脉的过程中&#xff0c;可能会遇到数据丢失的情况&#xff0c;如误删了重要信息或者更换手机后数据未能同步等问题。那么如何恢复脉脉中的数据呢&#xff1f;本文将为您提供详细的步骤指导。 注意&#xff1a;以下操作需要在脉脉账户登录状态下进行。 登录脉…

红米K60Pro/K50/K40系列澎湃OS解锁BL降级出厂MIUI14稳定版本方法

最新红米K60/60pro/K50/K50至尊/K40等多个系列手机都已经推送了澎湃OS系统&#xff0c;但新版的系统适配周期短或者等其他原因&#xff0c;导致很多小伙伴希望降级回到MIUI14系统&#xff0c;多个小米售后都拒绝降级服务&#xff0c;并且官方也没有开通1个自助降级的方法&#…

速戳!高考生做近视手术须知,避免错过心仪大学

距离高考还有不到一个月的时间&#xff0c;考生们在紧张复习的同时&#xff0c;不要忘了了解意向专业、院校的视力要求。一些专业和院校录取不仅靠实力,还需要“视力”,考了个好成绩却因视力不达标而被专业、院校退档,这样的结果是我们不想看到的。如果你想圆军旅梦、警校梦、航…

软考--信息系统项目管理师课程笔记

第一章 信息化发展 1.国家信息化&#xff1a;应用&#xff08;上&#xff09;&#xff0c;技术&#xff08;下&#xff09;&#xff0c;人才&#xff08;左&#xff09;&#xff0c;规范&#xff08;右&#xff09; 2.广域网协议包括&#xff1a;ISDN&#xff0c;ASDL&#xf…

Android的视图显示和管理机制:layout view window WindowManager Canvas Surface

在Android系统中&#xff0c;Layout view window WindowManager Canvas Surface SurfaceFlinger这些组件协同工作&#xff0c;以实现图形的绘制和显示。需要搞明白这些组件是什么时候创建的以及他们之间的结构关系。 从上到下的层级关系&#xff1a;用户在View上进行操作&…

SQLite .journal 文件

在之前插入大量数据测试的时候&#xff0c;发现在数据库文件同级目录下会产生一个同名.journal的文件&#xff0c;并且不是一直会存在&#xff0c;而是生成一会就会自动删除&#xff0c;然后继续生成继续删除&#xff0c;直到数据插入完成。 初步猜测&#xff0c;应该是类似 re…

代码-功能-Python-运用bs4技术爬取汽车之家新闻信息

第三方库安装指令&#xff1a; pip install requests -i https://pypi.tuna.tsinghua.edu.cn/simple pip install BeautifulSoup4 -i https://pypi.tuna.tsinghua.edu.cn/simple 运行代码&#xff1a; #这个代码并不完整&#xff0c;有很大的问题&#xff0c;但目前不知道怎么…

05-Fortran基础--Fortran文件操作

05-Fortran基础--Fortran文件操作 0 引言1 文件操作有关的关键字介绍1.1 打开文件&#xff08;OPEN&#xff09;1.2 文件关闭&#xff08;CLOSE&#xff09;1.3 文件查询&#xff08;INQUIRE&#xff09;1.3 文件读写&#xff08;read/write&#xff09;1.4 文件操作符&#xf…

机器学习作业4——朴素贝叶斯分类器

目录 一、理论 一个例子&#xff1a; 二、代码 对于代码的解释&#xff1a; 1.fit函数&#xff1a; 2.predict函数: 三、实验结果 原因分析&#xff1a; 一、理论 朴素贝叶斯分类器基于贝叶斯定理进行分类&#xff0c;通过后验概率来判断将新数据归为哪一类。通过利用贝…

设计模式——结构型模式——代理模式(静态代理、动态代理:JDK、CGLIB)

目录 代理模式 代理模式简介 代理模式的分类 代理模式组成 代理模式的优缺点 静态代理 背景前置 编写代码 JDK动态代理 编写代码 使用Arthas分析JDK动态代理底层原理 CGLIB动态代理 编写代码 三种代理的对比 代理模式使用场景 代理模式 代理模式简介 代理模式属…

测试萌新三天速通python基础(二)列表,字符串,元组,字典,遍历,容器,集合,函数

python基础 字符串下标(索引)切片字符串的替换 replace()字符串拆分 split()字符串的连接 join列表 list列表的增删改查列表的反转 reverse()排序列表嵌套元组 tuple 排序 升序降序交换变量字典 dict查询遍历容器集合函数参数函数的嵌套调⽤函数的返回值模块导⼊的⽅法____name…

重发布和路由策略实验(课堂练习)

需求&#xff1a; 将1.1.1.0/24网段&#xff08;不在OSPF中&#xff09;重发布到网络中&#xff0c;不允许出现次优路径&#xff0c;实现全网可达。 需求分析&#xff1a; 1、在R1上重发布1.1.1.0/24网段&#xff0c;但是需要过滤192.168.12.0/24和192.168.13.0/24 2、在R2和R3…

【论文阅读笔记】MapReduce: Simplified Data Processing on Large Clusters

文章目录 1 概念2 编程模型3 实现3.1 MapReduce执行流程3.2 master数据结构3.3 容错机制3.3.1 worker故障3.3.2 master故障3.3.3 出现故障时的语义 3.4 存储位置3.5 任务粒度3.6 备用任务 4 扩展技巧4.1 分区函数4.2 顺序保证4.3 Combiner函数4.4 输入和输出的类型4.5 副作用4.…