注意力机制的输入

注意力机制的输入

flyfish

注意力机制用于确定序列中每个组成部分相对于其他部分的相对重要性。在这里插入图片描述
绘图源码

import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatchplt.rcParams['font.sans-serif'] = ['SimHei']
plt.rcParams['axes.unicode_minus'] = False
# 创建一个新的图形
fig, ax = plt.subplots()# 设置背景颜色
ax.set_facecolor('#ffffff')# 添加文本,使用白色和浅灰色来提高可读性和对比度
ax.text(0.5, 0.8, 'The Essence of Attention', fontsize=24, color='#ecf0f1', ha='center', fontweight='bold')
ax.text(0.2, 0.5, 'Attend to All', fontsize=18, color='#bdc3c7', ha='center', fontweight='semibold')
ax.text(0.8, 0.5, 'Focus on Key Points', fontsize=18, color='#e67e22', ha='center', fontweight='semibold')# 添加箭头,使用亮橙色使箭头更加突出
arrow = FancyArrowPatch((0.45, 0.5), (0.55, 0.5), arrowstyle='->', mutation_scale=20, lw=2, color='#e67e22')
ax.add_patch(arrow)# 设置图形的边界
ax.set_xlim(0, 1)
ax.set_ylim(0, 1)
ax.axis('on')  # 关闭坐标轴# 显示图形
plt.show()

注意力机制的输入

以输入句子 "The cat sat on the mat" 为例:


1. 输入的表示 (Tokenization & Embedding)

输入:

句子 "The cat sat on the mat" 通过词汇表转化为 token 索引:
tokens = [ 0 , 1 , 2 , 3 , 4 , 5 ] \text{tokens} = [0, 1, 2, 3, 4, 5] tokens=[0,1,2,3,4,5]

嵌入层公式:

词嵌入矩阵 W e ∈ R V × d model W_e \in \mathbb{R}^{V \times d_{\text{model}}} WeRV×dmodel(其中 V V V是词汇表大小, d model d_{\text{model}} dmodel是嵌入维度)。
对于每个 token,将其映射为一个 d model d_{\text{model}} dmodel-维的嵌入向量:
Embedding ( x ) = W e [ x ] , x ∈ { 0 , 1 , 2 , … , V − 1 } \text{Embedding}(x) = W_e[x], \quad x \in \{0, 1, 2, \dots, V-1\} Embedding(x)=We[x],x{0,1,2,,V1}

代码对应部分:
self.embedding = nn.Embedding(vocab_size, d_model)
x = self.embedding(src)

2. 位置编码 (Positional Encoding)

位置编码的公式如下:
P E pos , 2 i = sin ⁡ ( pos 1000 0 2 i d model ) PE_{\text{pos}, 2i} = \sin\left(\frac{\text{pos}}{10000^{\frac{2i}{d_{\text{model}}}}}\right) PEpos,2i=sin(10000dmodel2ipos)
P E pos , 2 i + 1 = cos ⁡ ( pos 1000 0 2 i d model ) PE_{\text{pos}, 2i+1} = \cos\left(\frac{\text{pos}}{10000^{\frac{2i}{d_{\text{model}}}}}\right) PEpos,2i+1=cos(10000dmodel2ipos)

  • pos \text{pos} pos 表示位置索引(例如,第 0 个单词、第 1 个单词)。
  • 2 i 2i 2i 2 i + 1 2i+1 2i+1 表示奇偶维度。

位置编码加入到嵌入后:
x = Embedding ( x ) + P E x = \text{Embedding}(x) + PE x=Embedding(x)+PE

代码对应部分:
x = self.pos_encoding(self.embedding(src))

3. 多头注意力机制 (Multi-Head Attention)

输入:

输入张量 x ∈ R B × L × d model x \in \mathbb{R}^{B \times L \times d_{\text{model}}} xRB×L×dmodel,其中:

  • B B B: 批量大小。
  • L L L: 序列长度。
  • d model d_{\text{model}} dmodel: 嵌入维度。

通过一个线性变换生成 Query (Q)Key (K)Value (V)
Q = x W Q , K = x W K , V = x W V Q = xW_Q, \quad K = xW_K, \quad V = xW_V Q=xWQ,K=xWK,V=xWV
其中 W Q , W K , W V ∈ R d model × d model W_Q, W_K, W_V \in \mathbb{R}^{d_{\text{model}} \times d_{\text{model}}} WQ,WK,WVRdmodel×dmodel

分头操作:
Q , K , V Q, K, V Q,K,V划分为 h h h个头(头的数量为 num_heads \text{num\_heads} num_heads),每个头的维度为 d k = d model h d_k = \frac{d_{\text{model}}}{h} dk=hdmodel
Q → Q ′ ∈ R B × h × L × d k , K → K ′ , V → V ′ Q \rightarrow Q' \in \mathbb{R}^{B \times h \times L \times d_k}, \quad K \rightarrow K', \quad V \rightarrow V' QQRB×h×L×dk,KK,VV

计算注意力权重:

Attention ( Q , K , V ) = softmax ( Q K T d k ) V \text{Attention}(Q, K, V) = \text{softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V Attention(Q,K,V)=softmax(dk QKT)V

  • Q K T QK^T QKT: 计算相似性分数。
  • d k \sqrt{d_k} dk : 缩放因子,避免分数值过大。
  • softmax: 将分数转换为概率分布。
多头合并:

将每个头的输出重新拼接,并通过线性变换:
MultiHead ( Q , K , V ) = Concat ( head 1 , head 2 , … , head h ) W O \text{MultiHead}(Q, K, V) = \text{Concat}(\text{head}_1, \text{head}_2, \dots, \text{head}_h)W_O MultiHead(Q,K,V)=Concat(head1,head2,,headh)WO
其中 W O ∈ R d model × d model W_O \in \mathbb{R}^{d_{\text{model}} \times d_{\text{model}}} WORdmodel×dmodel

代码对应部分:
qkv = self.qkv_linear(x).reshape(B, L, 3, self.num_heads, self.d_k).permute(2, 0, 3, 1, 4)
Q, K, V = qkv[0], qkv[1], qkv[2]
scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)
attn = torch.softmax(scores, dim=-1)
out = torch.matmul(attn, V)

4. 前馈网络 (Feed Forward Network, FFN)

每个输入通过两个线性变换,中间使用 ReLU 激活函数:
FFN ( x ) = ReLU ( x W 1 + b 1 ) W 2 + b 2 \text{FFN}(x) = \text{ReLU}(xW_1 + b_1)W_2 + b_2 FFN(x)=ReLU(xW1+b1)W2+b2
其中:

  • W 1 ∈ R d model × d f f W_1 \in \mathbb{R}^{d_{\text{model}} \times d_{ff}} W1Rdmodel×dff W 2 ∈ R d f f × d model W_2 \in \mathbb{R}^{d_{ff} \times d_{\text{model}}} W2Rdff×dmodel
    - d f f d_{ff} dff: 前馈网络的中间层维度。
代码对应部分:
return self.linear2(torch.relu(self.linear1(x)))

5. 残差连接与层归一化 (Residual Connection & Layer Normalization)

每一层后加入残差连接和归一化:
Output = LayerNorm ( x + SubLayer ( x ) ) \text{Output} = \text{LayerNorm}(x + \text{SubLayer}(x)) Output=LayerNorm(x+SubLayer(x))

代码对应部分:
attn_out = self.dropout(self.attn(self.norm1(x))) + x
ffn_out = self.dropout(self.ffn(self.norm2(attn_out))) + attn_out

6. 编码器层与堆叠

每一层的处理:

输入依次经过多头注意力机制和前馈网络:
LayerOutput = FFN ( MultiHeadAttention ( x ) + x ) + MultiHeadAttention ( x ) \text{LayerOutput} = \text{FFN}(\text{MultiHeadAttention}(x) + x) + \text{MultiHeadAttention}(x) LayerOutput=FFN(MultiHeadAttention(x)+x)+MultiHeadAttention(x)

堆叠多层:

编码器由多个编码器层堆叠:
x → Layer 1 ( x ) → Layer 2 ( x ) → ⋯ → Layer N ( x ) x \rightarrow \text{Layer}_1(x) \rightarrow \text{Layer}_2(x) \rightarrow \dots \rightarrow \text{Layer}_N(x) xLayer1(x)Layer2(x)LayerN(x)

代码对应部分:
for layer in self.layers:x = layer(x)

完整的输入到输出的流程总结

  1. 输入文本"The cat sat on the mat" 转为 token 序列:[0, 1, 2, 3, 4, 5]
  2. 嵌入层:将 token 映射为嵌入向量 x ∈ R 1 × 6 × 512 x \in \mathbb{R}^{1 \times 6 \times 512} xR1×6×512
  3. 位置编码:加上位置信息,得到加权的嵌入表示。
  4. 编码器层
    • 多头注意力机制:计算每个 token 与其他 token 的关系。
    • 前馈网络:对每个 token 的嵌入进一步提取特征。
    • 残差连接与归一化:稳定训练。
  5. 堆叠层:经过 6 层编码器层,输出最终表示 Output ∈ R 1 × 6 × 512 \text{Output} \in \mathbb{R}^{1 \times 6 \times 512} OutputR1×6×512

输出:

print("输出表示形状:", output.shape)  # (1, 6, 512)

输入句子的每个 token 被转化为一个 512 维的上下文感知表示。

完整代码

import torch
import torch.nn as nn
import math# 定义位置编码模块
class PositionalEncoding(nn.Module):def __init__(self, d_model, max_len=5000):"""参数:- d_model: 每个单词嵌入向量的维度- max_len: 最大序列长度"""super(PositionalEncoding, self).__init__()# 初始化一个 (max_len, d_model) 的零张量,用于存储位置编码pe = torch.zeros(max_len, d_model)# 定义序列中的每个位置 [0, 1, 2, ..., max_len-1]position = torch.arange(0, max_len).unsqueeze(1)# 定义公式中 div_term 的部分,用于计算位置编码div_term = torch.exp(torch.arange(0, d_model, 2) * -(math.log(10000.0) / d_model))# 位置编码:偶数维度用 sin,奇数维度用 cospe[:, 0::2] = torch.sin(position * div_term)  # 偶数维度pe[:, 1::2] = torch.cos(position * div_term)  # 奇数维度# 注册为 buffer,表示模型内部固定参数,不参与训练self.register_buffer("pe", pe)def forward(self, x):"""前向传播:- 将位置编码与输入张量相加"""x = x + self.pe[:x.size(1)]  # 根据输入序列长度截取位置编码return x# 定义多头注意力机制模块
class MultiHeadAttention(nn.Module):def __init__(self, d_model, num_heads):"""参数:- d_model: 输入向量的维度- num_heads: 注意力头的数量"""super(MultiHeadAttention, self).__init__()self.d_model = d_modelself.num_heads = num_headsself.d_k = d_model // num_heads  # 每个注意力头的维度# 确保 d_model 可以被 num_heads 整除assert d_model % num_heads == 0, "d_model 必须能被 num_heads 整除"# 定义用于生成 Q、K、V 的线性层self.qkv_linear = nn.Linear(d_model, 3 * d_model)# 定义最终输出的线性层self.out_linear = nn.Linear(d_model, d_model)def forward(self, x):"""前向传播:- 输入: x, 形状 [B, L, d_model]"""B, L, _ = x.size()  # 获取批量大小 B 和序列长度 L# 通过线性层生成 Q、K、V,并 reshape 成多头格式qkv = self.qkv_linear(x).reshape(B, L, 3, self.num_heads, self.d_k).permute(2, 0, 3, 1, 4)Q, K, V = qkv[0], qkv[1], qkv[2]  # 分别提取 Q、K、V# 计算注意力得分scores = torch.matmul(Q, K.transpose(-2, -1)) / math.sqrt(self.d_k)  # [B, num_heads, L, L]attn = torch.softmax(scores, dim=-1)  # 对最后一个维度进行 softmax 归一化# 通过注意力分数对 V 进行加权求和out = torch.matmul(attn, V)  # [B, num_heads, L, d_k]# 多头输出合并为 [B, L, d_model]out = out.transpose(1, 2).reshape(B, L, self.d_model)return self.out_linear(out)  # 返回线性变换后的结果# 定义前馈网络模块
class FeedForward(nn.Module):def __init__(self, d_model, d_ff):"""参数:- d_model: 输入维度- d_ff: 前馈层的中间层维度"""super(FeedForward, self).__init__()self.linear1 = nn.Linear(d_model, d_ff)  # 第一个全连接层self.linear2 = nn.Linear(d_ff, d_model)  # 第二个全连接层def forward(self, x):"""前向传播:- 使用 ReLU 激活函数"""return self.linear2(torch.relu(self.linear1(x)))# 定义编码器层模块
class EncoderLayer(nn.Module):def __init__(self, d_model, num_heads, d_ff, dropout=0.1):"""参数:- d_model: 输入维度- num_heads: 注意力头的数量- d_ff: 前馈层中间层维度- dropout: dropout 概率"""super(EncoderLayer, self).__init__()self.attn = MultiHeadAttention(d_model, num_heads)  # 多头注意力机制self.ffn = FeedForward(d_model, d_ff)  # 前馈网络self.norm1 = nn.LayerNorm(d_model)  # 层归一化 (注意力)self.norm2 = nn.LayerNorm(d_model)  # 层归一化 (前馈网络)self.dropout = nn.Dropout(dropout)  # dropoutdef forward(self, x):"""前向传播:- 输入 x: [B, L, d_model]"""attn_out = self.dropout(self.attn(self.norm1(x))) + x  # 多头注意力 + 残差连接ffn_out = self.dropout(self.ffn(self.norm2(attn_out))) + attn_out  # 前馈网络 + 残差连接return ffn_out# 定义编码器模块
class Encoder(nn.Module):def __init__(self, vocab_size, d_model, num_heads, d_ff, num_layers, max_len=5000):"""参数:- vocab_size: 词汇表大小- d_model: 嵌入向量维度- num_heads: 注意力头的数量- d_ff: 前馈网络中间层维度- num_layers: 编码器层的数量- max_len: 最大序列长度"""super(Encoder, self).__init__()self.embedding = nn.Embedding(vocab_size, d_model)  # 嵌入层self.pos_encoding = PositionalEncoding(d_model, max_len)  # 位置编码# 创建 num_layers 个编码器层self.layers = nn.ModuleList([EncoderLayer(d_model, num_heads, d_ff) for _ in range(num_layers)])self.norm = nn.LayerNorm(d_model)  # 最终层归一化def forward(self, src):"""前向传播:- 输入 src: [B, L]"""x = self.pos_encoding(self.embedding(src))  # 嵌入 + 位置编码for layer in self.layers:  # 依次通过编码器层x = layer(x)return self.norm(x)# 词汇表与输入句子
vocab = {"The": 0, "cat": 1, "sat": 2, "on": 3, "the": 4, "mat": 5}
sentence = "The cat sat on the mat"
tokens = [vocab[word] for word in sentence.split()]  # 将句子转化为索引列表: [0, 1, 2, 3, 4, 5]# 超参数
vocab_size = len(vocab)
d_model = 512
num_heads = 8
d_ff = 2048
num_layers = 6# 输入处理
src = torch.tensor([tokens])  # 输入形状: [B, L]# 构造编码器
encoder = Encoder(vocab_size, d_model, num_heads, d_ff, num_layers)# 运行编码器
output = encoder(src)# 输出结果
print("输出表示形状:", output.shape)  # 输出形状: (1, 6, 512)

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

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

相关文章

Anaconda创建虚拟环境+CUDA、cuDNN一同安装

文章目录 前言一、CUDA的作用二、下载CUDA的步骤2.1 查看电脑NVIDIA适合的CUDA版本( 两种方法)1)打开NVIDIA控制面板,目前我的CUDA版本是12.12)使用命令行查看,使用命令:nvidia-smi。 2.2 根据p…

数学建模之熵权法

熵权法 概述 **熵权法(Entropy Weight Method,EWM)**是一种客观赋权的方法,原理:指标的变异程度越小,所包含的信息量也越小,其对应的权值应该越低(例如,如果对于所有样本而言,某项指标的值都相…

Python学习第十六天--迭代器和生成器

一、可迭代对象 六大标准数据类型:字符串,列表,元组,字典,集合,数值类型 可迭代对象:字符串,列表,元组,字典,集合。即:通过for...in…

【JavaScript】选项卡切换

选项卡切换 选项卡切换是一种常见的网页设计模式,用于在一个页面内显示和切换不同内容区域,而无需加载页面。用户可以通过点击选项卡切换显示不同的内容,而隐藏其他内容。 多选项显示:页面顶部、侧边或其他地方通常有多个选项卡…

【Spring】Spring 整合 MyBatis

在实际项目开发中,将 Spring 和 MyBatis 进行整合可以提高开发效率、简化配置、增强事务管理和可维护性,同时利用 Spring 的强大功能能提升系统的稳定性。这里从独立使用 MyBatis 开始,逐步实现与 Spring 框架的整合。 MyBatis 独立开发 现…

JavaWeb学习(1)(同步或异步请求、依赖jQuery简单实现Ajax技术)

目录 一、Web的基本流程与页面局部刷新。 (1)web开发时基本流程。 (2)页面的"全局刷新"与"局部刷新"。 二、Ajax技术。 (1)基本介绍。 (2)基本特点。 1、与服务…

win11 vs2022 python3.9环境下运行jupyterlab

jupyter官网及简介:https://jupyter.org/ Jupyter 集合“浏览器 编程 文档 绘图 多媒体 发布”众多功能与一身,适合探究式学习。 JupyterLab是最新的基于网络的笔记本、代码和数据的互动开发环境。 Jupyter Notebook是JupyterLab的上一代版本。 由…

STM32 进阶 定时器 2基本定时器 基本定时器中断案例:LED闪烁

基本定时器 基本定时器TIM6和TIM7各包含一个16位自动装载计数器,由各自的可编程预分频器驱动。 这2个定时器是互相独立的,不共享任何资源。 这个2个基本定时器只能向上计数,由于没有外部IO,所以只能计时,不能对外部…

libaom 源码分析:帧间帧内预测编码

整体流程框架逻辑 帧间帧内预测模式的分区类型 不论是 RD 模式还是 nonRD 模式,libaom 中分区只应用 PARTITION_NONE、PARTITION_HORZ、PARTITION_VERT、PARTITION_SPLIT 四种类型,不像 AV1 标准中介绍的那样有十种类型(其实 libaom 源码中也实现了所有了类型,但在正式版中…

达梦归档文件名与实例对应关系

默认的,达梦归档文件名比较难以看懂,且多实例下不好区分 靠它就行 select upper(to_char((select DB_MAGIC), xxxxxxxxxx)) mag_id; 这样就对上号了。

JavaScript实现圆周运动效果

在 JavaScript 中&#xff0c;可以通过 requestAnimationFrame 和数学公式来实现圆周运动效果。以下是示例代码&#xff1a; 示例代码 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewp…

11.爬虫

前言&#xff1a; 正则表达式的作用&#xff1a; 作用一&#xff1a;校验字符串是否满足规则 作用二&#xff1a;在一段文本中查找满足要求的内容 一.Pattern类和Matcher类&#xff1a; 1.Pattern类&#xff1a;表示正则表达式 a.因此获取Pattern对象就相当于获取正则表达式…

Java项目实战II基于微信小程序的无中介租房系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。 一、前言 随着城市化进程的加速&#xff0c;租房市场日益繁荣&a…

Linux里面实时查看项目的tomcat服务器日志文件

目录 前言 一、查看tomcat服务器日志 二、运行项目验证&#xff08;篇外&#xff09; (一)运行自己的项目 二、发送验证码测试 前言 这个可以查看在Linux系统里面部署运行项目的日志&#xff0c;日志内可以查看到运行和各种错误以及前后端交互传输的各种数据&#xff0c;…

12,攻防世界simple_php

simple_php 题目来源:Cyberpeace-n3k0 题目描述: 小宁听说php是最好的语言,于是她简单学习之后写了几行php代码。 进入靶场 这段PHP代码是一个简单的web应用示例&#xff0c;让我们逐步分析这段代码&#xff1a; show_source(__FILE__);&#xff1a;这行代码会显示当前文件的…

Webpack Tree Shaking 技术原理及应用实战,优化代码,精简产物

前言 在前端开发中&#xff0c;优化代码体积和提升应用性能是至关重要的课题。Webpack 提供了多种优化手段来帮助开发者实现这一目标&#xff0c;Tree Shaking 就是其中一种非常重要的优化技术&#xff0c;它通过在编译阶段移除未被使用的代码模块&#xff0c;从而显著减小最终…

5G CPE核心器件-基带处理器(三)

5G CPE 核心器件 -5G基带芯片 基带芯片简介基带芯片组成与结构技术特点与发展趋势5G基带芯片是5G CPE中最核心的组件,负责接入5G网络,并进行上下行数据业务传输。移动通信从1G发展到5G,终端形态产生了极大的变化,在集成度、功耗、性能等方面都取得巨大的提升。 基带芯片简…

SpringBoot高级-底层原理

目录 1 SpringBoot自动化配置原理 01-SpringBoot2高级-starter依赖管理机制 02-SpringBoot2高级-自动化配置初体验 03-SpringBoot2高级-底层原理-Configuration配置注解 04-SpringBoot2高级-底层原理-Import注解使用1 05-SpringBoot2高级-底层原理-Import注解使用2 06-S…

ES常见问题汇总

ES常见问题汇总 1.Es的作用&#xff08;elasticsearch&#xff09; 作用&#xff1a; elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容 ELK技术栈 elasticsearch结合kibana、Logstash&…

linux环境宝塔服务部署安装及介绍

一、简介 宝塔面板是一款服务器管理软件&#xff0c;支持windows和linux系统&#xff0c;可以通过Web端轻松管理服务器&#xff0c;提升运维效率。例如&#xff1a;创建管理网站、FTP、数据库&#xff0c;拥有可视化文件管理器&#xff0c;可视化软件管理器&#xff0c;可视化C…