从零开始大模型之编码注意力机制

从零开始大模型之编码注意力机制

  • 1 长序列建模中的问题
  • 2 使用注意力机制捕捉数据依赖关系
  • 3 自注意力机制
  • 4 实现带可训练权重的自注意力机制
  • 5 利用因果注意力隐藏未来词汇
  • 6 将单头注意力扩展到多头注意力
  • 7 Pytorch附录
  • 7.1 torch.nn.Linear

多头+掩码+可训练权重的注意力机制。
为什么要自注意力机制?为什么要带训练权重的自注意力机制?为什么要增加掩码功能?为什么要增加多头功能?

在这里插入图片描述

1 长序列建模中的问题

无注意力机制存在语法不对齐,以及没有联系上下文的缺点。Transformer相比传统的RNN能够解决较长距离的依赖。

2 使用注意力机制捕捉数据依赖关系

自注意力机制是transformer机制中一种重要机制,它通过允许一个序列种的每个位置与同一序列中其他所有位置进行交互并权衡其重要性,能够更高效的输入表示。

3 自注意力机制

自注意力机制是序列token中,当前token与前后上下文的token之间的线性组合关系构成,构成的这个向量叫做上下文向量。上下文向量 = 各个词元嵌入向量的加权和。
在这里插入图片描述
之所以引入注意力机制,就是为了进行语义的连贯,对于每个输入的token词元来说,不是独立的单独词元;这就像我们做阅读理解,总是要结合上下文要推敲某句话的含义是一样的,通过自注意力机制,让我们能够关注到当前文章内容与上下文之间的联系。
自注意力机制详细的操作步骤如下:
1.计算选定token的词元嵌入向量与所有token序列的词元嵌入向量点积就得到注意力分数
2.softmax归一化注意力分数
3.用归一化的注意力分数对词元嵌入向量加权求和,得到该位置的上下文向量,依次类推计算所有位置的上下文向量。
在这里插入图片描述

相关实现代码:

import torch
import torch.nn.functional as F #该类提供了卷积,池化,激活等函数
# 假设对应词序列的token对应的词元嵌入向量为下面张量所示
inputs = torch.tensor([[0.43, 0.15, 0.89], # Your     (x^1)[0.55, 0.87, 0.66], # journey  (x^2)[0.57, 0.85, 0.64], # starts   (x^3)[0.22, 0.58, 0.33], # with     (x^4)[0.77, 0.25, 0.10], # one      (x^5)[0.05, 0.80, 0.55]] # step     (x^6)
)
#计算当前query与其他的token的点积后的点积矩阵,直接考虑矩阵乘法
att_scores = torch.matmul(inputs,inputs.T)#形成6x6的点积矩阵,每一行都是该token与其他token的点积注意力分数
# 对于每一行进行softmax归一化
att_weights = F.softmax(att_scores, dim=1) # 计算每一行的softmax归一化,dim=1表示对行进行归一化
# 计算加权和,每一行即为一个上下文向量
context_vector = torch.matmul(att_weights,inputs)

4 实现带可训练权重的自注意力机制

带可训练权重的自注意力机制是在简单的自注意力机制上引入了可训练权重矩阵Wq,Wk,Wv,通过反向传播算法进行更新,同时带可训练权重的自注意力机制又被称为是缩放点积注意力。引入带可训练权重的自注意力机制一方面是为了能够动态的联系上下文,这是因为简单的自注意力机制只能通过点积静态计算相关权重,另一方面受到人类在数据库中检索信息的启发,其本质是模仿人类搜索查询,其中Q代表query(查询),K代表key(键),V代表value(值)。
实现带可训练权重的自注意力机制仍然是三个核心步骤,计算权重系数,系数归一化,系数线性叠加。
第一步,对于每个词元嵌入向量,将q(query)查询向量依次定为第一个token,第二个token的嵌入向量,在确定某token下的查询向量,然后计算别的token的嵌入向量与权重矩阵Wk和Wv矩阵的乘积,可以得到k(key)键向量,v(value)值向量。
在这里插入图片描述
第二步将得到的当前的查询向量q2,与其他所有token的k向量进行点积就得到每个token在上下文向量的占比分数,将该分数进行softmax归一化后即为权重系数。
在这里插入图片描述
最后,用权重系数对每个token的值向量进行线性叠加就能得到上下文向量,这个上下文向量能够动态理解语义,因为Wq,Wk,Wv是动态训练可更新得到的。
总的来说,上面最后的公式可以总结为:
Attention(Q,K,V)=softmax(QKTdk)VAttention(Q,K,V)=softmax(\frac{QK^T}{\sqrt{d_{k}}})VAttention(Q,K,V)=softmax(dkQKT)V
以下是相关步骤的简练总价:
引入可训练权重矩阵,Wq,Wk,Wv。
1.对当前位置的词元嵌入向量分别与Wq,Wk,Wv相乘得到q,k,v,拿着这个当前位置的q,所有位置的k向量分别相乘,得到权重系数
2.对权重系数进行softmax归一化处理
3.用权重系数对所有v向量进行加权求和得到该位置的上 下文向量,依次类推,计算所有上下文向量。
相关代码如下:

#%% 带训练权重的自注意力机制
import torch
import torch.nn.functional as F #该类提供了卷积,池化,激活等函数
# 假设对应词序列的token对应的词元嵌入向量为下面张量所示
inputs = torch.tensor([[0.43, 0.15, 0.89], # Your     (x^1)[0.55, 0.87, 0.66], # journey  (x^2)[0.57, 0.85, 0.64], # starts   (x^3)[0.22, 0.58, 0.33], # with     (x^4)[0.77, 0.25, 0.10], # one      (x^5)[0.05, 0.80, 0.55]] # step     (x^6)
)
torch.manual_seed(123)#设置随机种子,确保重复实验能够产生相同的效果
# 初始化Wq,Wk,Wv权重矩阵
Wq_matrix = torch.nn.Parameter(torch.rand(3, 2), requires_grad=False) #假设权重矩阵是3x2
Wk_matrix = torch.nn.Parameter(torch.rand(3, 2), requires_grad=False)
Wv_matrix = torch.nn.Parameter(torch.rand(3, 2), requires_grad=False)
# 计算所有token构成的q,k,v矩阵,所有嵌入词元向量矩阵inputs与权重矩阵对应矩阵相乘
q = torch.matmul(inputs, Wq_matrix)
k = torch.matmul(inputs, Wk_matrix)
v = torch.matmul(inputs, Wv_matrix)
# 结合注意力的计算公式
context_vector = torch.matmul(F.softmax(torch.matmul(q, k.T) / torch.sqrt(torch.tensor(k.shape[1])), dim=-1), v)

为了后续的方便,同时考虑到nn.Linear相比于nn.Parameter,提供了优化的初始化方案,在模型上定义了一个抽象的层:

#%% 带训练权重的自注意力机制的抽象类
import torch
import torch.nn.functional as F #该类提供了卷积,池化,激活等函数
class SelfAttention(nn.Module):def __init__(self,d_in=3,d_out=2,qkv_vias=False):super().__init__() #继承神经网络# Wq,Wk,Wv的初始化self.Wq_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.Wk_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.Wv_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵def foward(self,inputs):#前向传播计算q,k,vq = self.Wq_matrix(inputs) #inputs 与 Wq_matrix矩阵相乘k = self.Wk_matrix(inputs)  # inputs 与 Wk_matrix矩阵相乘v = self.Wv_matrix(inputs)  # inputs 与 Wv_matrix矩阵相乘attention_scores = q @ k.T # 注意力分数attention_weights = torch.softmax(attention_scores / k.shape()**0.5,dim=1) #softmax归一化权重系数context_vec_matrix = attention_weights @ v #线性叠加求上下文向量矩阵return context_vec_matrix

5 利用因果注意力隐藏未来词汇

权重系数矩阵右上角进行遮挡,然后归一化,使用dropout随机丢弃(随机置零),防止过拟合。
事实上,考虑到逻辑的时空的连贯性,我们说话的时候是因果关系的,比如当我心里想说“我很想吃西瓜”,但是当我说出“我很想…”的时候,后续的的词你是不知道的,这就是因果关系,只知道当前及过去,当前的词是“想”,过去的词是“我很”,所以理论上来说,对于“我很想吃西瓜”这句话,应该逐个词掩码,说==“我”的时候,掩码”很想吃西瓜“,当说”我很“的时候,掩码”想吃西瓜“==,依次类推,所以因果注意力的本质上是更接近真实自然的真实语境,基于此,事实上我们只要基于可训练权重自注意力机制上,对softmax归一化权重矩阵进行上面部分掩码,然后重新归一化计算系数。
在这里插入图片描述
考虑采用的思路是创建上三角不包含对角线的上三角块,对权重系数矩阵的上三角部分掩码为−∞-\infty,这样再次归一化的时候,由于e−∞e^{-\infty}e为零,就能实现因果+带训练权重的注意力机制,其相关代码如下:

#%% 掩码+带训练权重的自注意力机制的抽象类
import torch
import torch.nn.functional as F #该类提供了卷积,池化,激活等函数
class SelfAttention(nn.Module):def __init__(self,d_in=3,d_out=2,qkv_vias=False):super().__init__() #继承神经网络# Wq,Wk,Wv的初始化self.Wq_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.Wk_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.Wv_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵def foward(self,inputs):#前向传播计算q,k,vq = self.Wq_matrix(inputs) #inputs 与 Wq_matrix矩阵相乘k = self.Wk_matrix(inputs)  # inputs 与 Wk_matrix矩阵相乘v = self.Wv_matrix(inputs)  # inputs 与 Wv_matrix矩阵相乘attention_scores = q @ k.T # 注意力分数attention_weights = torch.softmax(attention_scores / k.shape()**0.5,dim=1) #softmax归一化权重系数mask = torch.triu(torch.ones(6,6),diagonal=1)#上三角(不包含对角线)矩阵创建masked = attention_weights.masked_fill(mask.bool(),-torch.inf)#对矩阵中为1的上半部分不包含对角线进行掩码为-infattention_weights = torch.softmax(masked/k.shape()**0.5,dim=-1)#再次使用softmax归一化context_vec_matrix = attention_weights @ v #线性叠加求上下文向量矩阵return context_vec_matrix

在这里插入图片描述

为了防止过拟合,也就是数据只在训练集上表现较好的效果,事实上是模型过于复杂,举个简单列子来理解,就好比原来是三次函数的趋势,你要了7次函数,虽然也可以拟合训练集,但是模型更加复杂了,这样预测的时候,容易陷入局部更加详细的部分,为了解决这个问题,使用了dropout来随机丢弃权重矩阵系数中的部分系数,或者说叫置零,通常设置随机丢弃率来合理调整丢弃的比列,以下是增加了dropout后的代码:

#%% dropout掩码+带训练权重的自注意力机制的抽象类
import torch
import torch.nn.functional as F #该类提供了卷积,池化,激活等函数
class SelfAttention(nn.Module):def __init__(self,d_in=3,d_out=2,qkv_vias=False):super().__init__() #继承神经网络# Wq,Wk,Wv的初始化self.Wq_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.Wk_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.Wv_matrix = nn.Linear(d_in, d_out, bias=qkv_vias) #3x2全连接层的抽象层,默认会有一个初始化权重矩阵self.dropout = nn.Dropout(0.1) #dropout随机丢弃10%def foward(self,inputs):#前向传播计算q,k,vq = self.Wq_matrix(inputs) #inputs 与 Wq_matrix矩阵相乘k = self.Wk_matrix(inputs)  # inputs 与 Wk_matrix矩阵相乘v = self.Wv_matrix(inputs)  # inputs 与 Wv_matrix矩阵相乘attention_scores = q @ k.T # 注意力分数attention_weights = torch.softmax(attention_scores / k.shape()**0.5,dim=1) #softmax归一化权重系数mask = torch.triu(torch.ones(6,6),diagonal=1)#上三角(不包含对角线)矩阵创建masked = attention_weights.masked_fill(mask.bool(),-torch.inf)#对矩阵中为1的进行掩码为-infattention_weights = torch.softmax(masked/k.shape()**0.5,dim=-1)#再次使用softmax归一化attention_weights = self.dropout(attention_weights)  # 先对归一化得权重系数进行随机丢弃dropout,防止过拟合context_vec_matrix = attention_weights @ v #线性叠加求上下文向量矩阵return context_vec_matrix

6 将单头注意力扩展到多头注意力

将多个来源的上下文向量进行线性叠加。
在这里插入图片描述

class MultiHeadAttention(nn.Module):def __init__(self, d_in, d_out, context_length, dropout, num_heads, qkv_bias=False):super().__init__()assert (d_out % num_heads == 0), \"d_out must be divisible by num_heads"self.d_out = d_outself.num_heads = num_headsself.head_dim = d_out // num_heads # Reduce the projection dim to match desired output dimself.W_query = nn.Linear(d_in, d_out, bias=qkv_bias)self.W_key = nn.Linear(d_in, d_out, bias=qkv_bias)self.W_value = nn.Linear(d_in, d_out, bias=qkv_bias)self.out_proj = nn.Linear(d_out, d_out)  # Linear layer to combine head outputsself.dropout = nn.Dropout(dropout)self.register_buffer("mask",torch.triu(torch.ones(context_length, context_length),diagonal=1))def forward(self, x):b, num_tokens, d_in = x.shape# As in `CausalAttention`, for inputs where `num_tokens` exceeds `context_length`, # this will result in errors in the mask creation further below. # In practice, this is not a problem since the LLM (chapters 4-7) ensures that inputs  # do not exceed `context_length` before reaching this forwarkeys = self.W_key(x) # Shape: (b, num_tokens, d_out)queries = self.W_query(x)values = self.W_value(x)# We implicitly split the matrix by adding a `num_heads` dimension# Unroll last dim: (b, num_tokens, d_out) -> (b, num_tokens, num_heads, head_dim)keys = keys.view(b, num_tokens, self.num_heads, self.head_dim) values = values.view(b, num_tokens, self.num_heads, self.head_dim)queries = queries.view(b, num_tokens, self.num_heads, self.head_dim)# Transpose: (b, num_tokens, num_heads, head_dim) -> (b, num_heads, num_tokens, head_dim)keys = keys.transpose(1, 2)queries = queries.transpose(1, 2)values = values.transpose(1, 2)# Compute scaled dot-product attention (aka self-attention) with a causal maskattn_scores = queries @ keys.transpose(2, 3)  # Dot product for each head# Original mask truncated to the number of tokens and converted to booleanmask_bool = self.mask.bool()[:num_tokens, :num_tokens]# Use the mask to fill attention scoresattn_scores.masked_fill_(mask_bool, -torch.inf)attn_weights = torch.softmax(attn_scores / keys.shape[-1]**0.5, dim=-1)attn_weights = self.dropout(attn_weights)# Shape: (b, num_tokens, num_heads, head_dim)context_vec = (attn_weights @ values).transpose(1, 2) # Combine heads, where self.d_out = self.num_heads * self.head_dimcontext_vec = context_vec.contiguous().view(b, num_tokens, self.d_out)context_vec = self.out_proj(context_vec) # optional projectionreturn context_vectorch.manual_seed(123)batch_size, context_length, d_in = batch.shape
d_out = 2
mha = MultiHeadAttention(d_in, d_out, context_length, 0.0, num_heads=2)context_vecs = mha(batch)print(context_vecs)
print("context_vecs.shape:", context_vecs.shape)

7 Pytorch附录

7.1 torch.nn.Linear

定义了一个全连接层,torch.nn.Linear(in_features,out_features,bias)
在这里插入图片描述
torch.nn.Linear(in_features,out_features,bias)是一个抽象全连接神经网络层,输入x,经过y=xwT+by=xw^{T}+by=xwT+b,输出y,特别地当偏置项为0的时候y=xwTy=xw^{T}y=xwT,事实上就是一个矩阵的乘法,输入x与wTw^{T}wT相乘,而当这个抽象全连接神经网络层被定义的时候,权重矩阵wTw^{T}wT以及偏置项b就会自动初始化。

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

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

相关文章

小架构step系列26:Spring提供的validator

1 概述对于Web服务,需要对请求的参数进行校验,可以对不合法的参数进行提示,提高用户体验。也可以防止有人恶意用一些非法的参数对网站造成破坏。如果是对每个参数都写一段代码来判断值是否合法,那校验的代码就很多,也很…

0编程基础:用TRAE写出了会蹦跳躲避散发炫光的贪吃蛇小游戏

在某个深夜的代码深渊里,一个从未写过print("Hello World")的小白开发者,竟用自然语言指令让贪吃蛇跳起了"光棱华尔兹"——蛇身折射出彩虹轨迹,食物像星舰般自动规避追击,甚至实现了四头蛇的"量子纠缠式…

在Word和WPS文字中要同时查看和编辑一个文档的两个地方?拆分窗口

如果要在Word或WPS文字的长文档中同时查看两部同步的地方(文档位置),来回跳转和滚动费时费力,使用拆分窗口的功能即可搞定。将窗口一分为二,上下对照非常方便。一、拆分窗口的路径Word和WPS基本一样,就是菜…

Windows系统下安装mujoco环境的教程【原创】

在学习Mujoco仿真的过程中,我先前是在linux系统下进行的研究与学习,今天来试试看在windows系统中安装mujoco仿真环境。 先前在linux中的一些关于mujoco学习记录的博客:Mujoco仿真【xml文件的学习 3】_mujoco打开xml文件-CSDN博客 下面开始wi…

CSS中篇

#Flex布局#1、什么是flex布局?flex 布局,全称弹性布局(Flexible Box Layout),是 CSS3 中引入的一种新的布局模式。它主要通过给容器设置相关属性,来控制容器内部子元素的排列方式。相比传统的浮动布局和定位…

《云计算蓝皮书 2025 》发布:云计算加速成为智能时代核心引擎

近日,中国信息通信研究院发布了《云计算蓝皮书(2025 年)》,全面剖析了云计算领域的发展现状与未来趋势。在人工智能蓬勃发展的当下,云计算正从基础资源供给向智能时代的核心引擎加速转变,成为重塑全球数字竞…

excel删除重复项场景

问题描述 问题描述:因为表格中存在多条相同的数据,我现在excel有一列,值为#N/A 。另外有列叫做药品名称、规格、厂家 我要删除值为 #N/A,并且 药品名称、规格、厂家相等的数据,那条相同的删掉,只保留一条,…

Vue 3 与 Element Plus 中的 /deep/ 选择器问题

Vue 3 与 Element Plus 中的 /deep/ 选择器问题 在 Vue3 中使用 Element Plus 组件时,使用 ::v-deep或 :deep()的场景取决于 ​​样式作用域​​ 和 ​​选择器目标​​。以下是关键区别:

2025暑期—06神经网络-常见网络

六个滤波核提取特征Maps5X5 卷积核,1个阈值 6个元素,卷积后两边各少两个,28*28像素 又有6个卷积核,所以有122304个连接,连接数不多是因为很多都是公用参数的。池化是参数池化,和当前平均最大不一样。编程14…

硅基计划3.0 学习总结 叁 栈和队列

文章目录一、栈1. 模拟实现栈2. 小试牛刀1. 判断一个栈的出栈顺序是否为题目给定情况2. 括号匹配3. 逆波兰表达式求值4. 求最小栈元素3. 单链表实现栈二、队列1. 官方队列类Queue2. 双向链表模拟实现Queue类3. 顺序表模拟实现Queue类4. 双端队列5. 队列实现栈6. 栈实现队列一、…

飞行控制领军者 | 边界智控携高安全级飞控系统亮相2025深圳eVTOL展

2025深圳eVTOL展将于2025年9月23日至25日在深圳坪山燕子湖国际会展中心盛大举办。本届展会以 “低空经济・eVTOL・航空应急救援・商载大型无人运输机” 为核心,预计将汇聚200余位发言嘉宾、500 余家顶尖展商及15,000余名专业观众,规模盛大,精…

React状态管理——Dva

目录 一、安装依赖 二、Dva注册model方式 2.1 自动注册models 2.2 手动注册model方式 三、创建 dva 实例 四、创建 model 五、在组件中使用 六、动态加载Dva Model Dva 是一个基于 redux 和 redux-saga 的轻量级前端框架,可以方便地在 React 应用中管理状态…

编程与数学 03-002 计算机网络 05_以太网技术

编程与数学 03-002 计算机网络 05_以太网技术一、以太网的基本原理(一)CSMA/CD协议的工作原理(二)以太网的帧结构二、以太网的拓扑结构与设备(一)传统以太网的拓扑结构(二)交换机的工…

解决英文版Windows10安装WireShark报错

问题点击WireShark安装包进行安装时报错原因编码方式故障解决方式修改操作系统编码1.WinR,输入Control,打开控制面板2.点击Small icons3.点击Region4.设置编码UTF-8

利用aruco标定板标定相机

1、生成aruco标定板#include <opencv2/opencv.hpp> #include <opencv2/aruco.hpp> #include <opencv2/objdetect/aruco_detector.hpp> #include <iostream> #include <string>using namespace cv; using namespace std;int main() {int markers…

C/C++语言程序使用三种主要的内存分配方式,和python语言一样么?

这是一个很好的比较问题&#xff01;C/C 和 Python 在内存分配方式上有本质的区别&#xff0c;虽然它们最终使用的都是计算机的物理内存&#xff08;堆、栈等&#xff09;&#xff0c;但语言层面提供的抽象和管理机制完全不同。核心区别&#xff1a;控制权&#xff1a; C/C 程序…

小电流驱动大电流:原理、实现方式与应用前景

目录 一、什么是“小电流驱动大电流”&#xff1f; 举个例子&#xff1a; 二、核心原理与实现方式 1. 电流放大原理 2. 电子开关元件 3. 控制电路设计 4. 附加保护措施 三、为什么采用“小电流驱动大电流”&#xff1f; 1. 提高安全性 2. 降低能耗 3. 改善效率 4. …

【DM数据守护集群搭建-读写分离】

DM数据守护集群搭建-读写分离 读写分离集群由一个主库以及一个或者多个配置了即时&#xff08;Timely&#xff09;归档或实时&#xff08;Realtime&#xff09;归档的备库组成&#xff0c;其主要目标是在保障数据库可用性基础上&#xff0c;实现读、写操作的自动分离&#xff0…

earth靶场

1、找ip和端口主机是192.168.6.213&#xff0c;因此靶场ip就是192.168.6.34&#xff0c;三个端口开放&#xff0c;我们去访问一下页面。三个端口都无法访问。我们使用nmap进行dns解析。nmap -A -p- -T4 -sV 192.168.6.34把这两条解析添加到hosts文件中去&#xff0c;这样我们才…

Kafka——Java消费者是如何管理TCP连接的?

引言在分布式消息系统中&#xff0c;网络连接是数据流转的"血管"&#xff0c;其管理效率直接决定了系统的吞吐量、延迟与稳定性。作为Kafka生态中负责数据消费的核心组件&#xff0c;Java消费者&#xff08;KafkaConsumer&#xff09;的TCP连接管理机制一直是开发者理…