💻
QMMMS的笔记
博客
  • QMMMS的笔记
  • agent
    • MCP的背景、原理和开发
    • Agent 历史与背景
    • Agentic Workflows
    • 环境检查与基础工具
    • Tool Call
    • 工具与运行时的值
    • temp
    • 处理 Tool Call error
    • trick
  • algorithm
    • 线性结构
    • 二叉树
    • 图
    • 查找
    • 排序
    • 动态规划
    • 优化方法
    • 数学
    • 迁移至Java
  • computer_composition
    • 系统总线
    • 存储器
    • 输入输出系统
    • 计算机的运算方法
    • 指令系统
    • 补充
  • computer_network
    • 引入
    • 应用层
    • 传输层
    • 网络层(数据平面)
    • 网络层(控制平面)
    • 链路层
    • 常见问答
    • 实验
  • database
    • SQL实战
    • 关系代数
    • 数据库设计
    • 规范化
    • 数据库基本概念
    • 查询原理
    • 数据库恢复技术
    • 并发控制
  • dev_tools
    • Git
    • Nginx
    • Spring
    • LangChain
    • PyTorch Cheat Sheet
    • MyBatis
    • MySQL Cheat Sheet
    • MySQL 补充
    • Redis
    • Docker
    • RocketMQ
    • Chrome
  • linux
    • Linux基础命令与使用
    • 文件与权限
    • 文件与目录操作
    • 权限属性高级
    • 命令与文件的查找
    • 文件压缩和打包
    • vim编辑器
    • shell变量
    • 命令补充
    • 数据流重定向
    • 管道命令
    • shell脚本
    • 用户管理
    • 用户间交流
    • 计划任务
    • 进程管理
    • 软件管理
    • 认识系统服务
    • 运维常用命令
    • 常用命令
  • llm
    • 大规模语言模型概述
    • 分布式训练概述
    • 有监督微调概述
    • 强化学习与LLM
    • LLM评估概述
    • 大模型应用
    • 理解大模型
    • 量化
    • 预训练
    • 上下文学习
  • machine_learning
    • 引入
    • 大致正确学习
    • 一致收敛
    • 偏差还是过拟合?
    • 可学习的充要条件
    • 非均匀可学习性
    • 计算复杂性
  • mathematics
    • 概率与统计基础
    • 线性代数基础
  • operating_system
    • 操作系统基本概念
    • 进程和线程
    • 同步,互斥与死锁
    • 内存管理
    • 文件系统
    • I/O系统
    • 保护与安全
    • 《现代操作系统》
  • statistical_learning
    • 统计学习引入
    • 线性回归
    • 分类
    • 重抽样方法
    • 线性模型选择与正则化
    • 非线性模型
    • 基于树的方法
    • 支持向量机
    • 无指导学习
    • 马尔科夫链和蒙托卡罗方法简明理解
    • R语言速查
  • deep_learning
    • basic_concepts
      • 逻辑回归与损失函数
      • 神经网络
      • 正则化、预处理、权重初始化
      • 优化算法
      • 机器学习策略
      • 复习:从计算机视觉的角度
      • 卷积神经网络
      • 深度卷积网络示例
      • 计算机视觉任务
      • 循环神经网络
      • 自然语言处理任务
      • 注意力
      • Transformers 家族
      • 显卡扫盲
      • 强化学习概述
    • semi-supervise
      • 半监督学习简介
      • Consistency Regularization
      • Proxy-label Methods
      • Holistic Methods
      • Generative Models
      • Graph-Based SSL
      • Self-Supervision for SSL
      • Other SSL methods
  • programming
    • cpp
      • STL
      • C++基础
      • 内存管理
      • 面向对象
    • java
      • 环境和介绍
      • 注释
      • String
      • 面向对象思想
      • Object
      • 包
      • 访问权限修饰符
      • 初始化块
      • 接口
      • 内部类
      • 注解
      • 枚举
      • 集合框架
      • List
      • Map
      • 泛型
      • 迭代
      • IO与流
      • 序列化
      • 异常
      • Lambda
      • Stream流
      • Socket
      • 缓冲
      • 命名规范
      • 拆箱装箱
      • 值传递
      • 深拷贝
      • 反射
      • JVM
      • 并发编程基础
    • python
      • 并发编程
      • 环境管理
  • software_engineering
    • basic_concepts
      • 系统分析与设计概述
      • 规划
      • 需求分析与原型设计
      • 项目管理
      • 建模
      • 数据库设计
      • 架构
      • 配置管理
      • 测试管理
      • 安全
      • 编码原则
      • 微服务
      • 补充内容
    • software_testing
      • CMMI基础
      • PPQA与SQA
      • 软件测试基础
      • 黑盒测试
      • 白盒测试
      • 集成测试
      • 系统测试
      • 测开面试补充
由 GitBook 提供支持
在本页
  • 句子翻译
  • 直观理解
  • 图像描述
  • 自注意力
  • 公式
  • Multi-head attention
  • 并行化
在GitHub上编辑
  1. deep_learning
  2. basic_concepts

注意力

上一页自然语言处理任务下一页Transformers 家族

最后更新于9个月前

句子翻译

我要对机器翻译做一些改进,称为注意力模型(the Attention Model)。人工翻译并不会记住整个法语句子再开始翻译,而是看一部分,翻译一部分,一点一点地翻译,因为记忆整个的长句子是非常困难的。注意力模型如何让一个神经网络只注意到一部分的输入句子。当它在生成句子的时候,更像人类翻译。以下为计算流程:

  1. 我们使用一个RNN计算输入的法语,这一步没有输出,我们计算好每一个时间步$t$的状态 $h_t$

  2. 我们定义 $e_{ij}$为翻译到第i个英文词时,与第j个法语词的关联有多大,这个生成e的函数可以用一个小神经网络来完成

  3. 经过softmax,得到 $e_{ij}$的概率解释 $a_{ij}$

  4. 现在我们来生成第i个英文词$y_i$,这是第二个RNN,每个时间步输入是上下文$C_i$

Ci=∑j=1TaijhiC_i=\sum_{j=1}^T a_{ij} h_iCi​=j=1∑T​aij​hi​

例如,e可以如下图计算:

然后,我们计算上下文C

换一种图示看看能不能看懂!展示了英语转西班牙语的句子翻译中生成第一个词的例子:

注意力机制运用在机器翻译中,<源语言词,目标语言词>的注意力权重基本与两个词互为翻译的情况一致。下图展示了注意力矩阵,抓住了不同语言中的词序。

注意力机制运用在机器阅读中,给文章中每句话一个attention权重,根据问题选出最有可能包含答案的句子

直观理解

注意力函数将 query 和 key-value 对映射成输出 output 。具体来说,output 是 value 的一个加权和,权重等价于 query 和对应的 key 的相似度 ,输出的维度与 value 的维度相同。

即使 key-value 并没有变,但是随着 query 的改变,因为权重的分配不一样,导致输出会有不一样,这就是注意力机制。

Transfomer 首先将 token 映射成向量,这种多维向量本身带有信息,但还没有综合上下文信息。注意力机制可以看作让每个 token 都能够关注到其他 token 的信息,从而综合上下文。例如假期和假货的假代表不同的意义,但这种区别只有通过上下文才能体现出来。

例如,在一句句子中,一个名词的 query 可能代表:有没有修饰我的形容词?某个形容词的 key 可能代表:我在这!我们希望这两个向量相似度大(在高维空间中指向同一个方向),这样放在他们上面的注意力权重就会大,这个名词就会被修饰。换句话说,上下文被考虑到了。

value 可以看作,如果 query 和 key 相似度高,那么这个形容词是修饰名词的,那么名词的向量应该偏移多少来表示这个形容词的影响。例如“塔”这个字,如果出现了“埃菲尔铁塔”作为修饰,那么这个“塔”的名词对应的向量应该偏移以代表更高更大的东西,如果又出现了“埃菲尔铁塔玩具”,那么这个“塔”的名词对应的向量应该再次偏移以代表更小的东西。

自注意力和交叉注意力:

  • 自注意力的 Q和K 都来自同一个句子(Transformer编码器)

  • 交叉注意力的 Q 和 K 来自不同的地方,例如一个英语句子和一个法语句子,这种情况下交叉注意力可以代表英语句子中的一个词对应法语句子中的一个词。

留意一下,在Transformer解码器中,查询q是通过解码器前一层的输出进行投影的,而键k和值v是使用编码器的输出进行 投影的。根据解码器的输入的不一样,会根据当前的 query 向量,去在编码器的输出里面去挑query感兴趣的东西。

举个例子 在翻译Hello World 到 你好世界 的过程中,计算 “好” 的时候,“好”作为 query ,会跟 “hello” 向量更相近一点,给 “hello” 向量一个比较大的权重。但是 “world” 跟后面的词相关, “world” 跟 当前的query (“好” )相关度没那么高。

在算 query “世” 的时候,会给第二个 “world” 向量,一个比较大的权重。

图像描述

在朴素的图像描述网络架构中,模型需要在 c (即上下文) 中对它图片所有内容进行编码,如果我们想生成非常长的描述,比如100多字,这个c限制了网络的发挥。

思路:每个时间步都有新的上下文向量。每个上下文向量将处理不同的图像区域。类似于上面的注意力思想,下图为生成第一个词的图例:

图像中的注意力例子:

自注意力

在上面图像描述的例子中,h可以看作 query,这和自注意力已经有点像了,事实上,我们稍加改造就可以得到自注意力。

为什么不把CNN丢掉?这样我们得到了类似Vision Transformer的模型:

公式

类似思想,在 Transformer 的大模型应用中有温度 T 这个参数,体现在 softmax 的公式中:

温度 T 越大,分布越平滑,越容易取到原先小概率的东西,在GPT的应用中,T 越大,越容易取到低概率的词,输出会更加多样化。

实际计算中,会把多个 query 写成 一个矩阵,并行化运算。

具体举个例子:

第一步计算输入(序列长度为2,两个节点)通过Input Embedding也就是图中的f(x)得到a,然后通过权重W得到QKV

第二步根据公式计算注意力

接着进行加权得到最终结果

Multi-head attention

为什么要做多头注意力机制呢?一个点乘的注意力里面,没有什么可以学的参数。为了识别不一样的模式,希望有不一样的计算相似度的办法。

先投影到低维,投影的 W 是可以学习的。 multi-head attention 给 h 次机会去学习 不一样的投影的方法,使得在投影进去的度量空间里面能够去匹配不同模式需要的一些相似函数,然后把 h 个 heads 拼接起来,最后再做一次投影。

后续为了权重共享,有两种改进。Multi-Query Attention(MQA)是一种共享机制的Attention,相比Multi-Head Attention,其Query部分没有区别,Key和Value可以只用一个Head。计算时,对Key和Value进行expand或者repeat操作,使它们填充到与Query一样的维度,后续计算就与Multi-Head Attention没区别。

GQA 觉得这样是不是有点太暴力,于是选择了 MQA(共享一个) 和 MHA(完全不共享) 的一个中间形态,按组来共享。如下图所示:

目前使用 GQA 的越来越多了,比如 Llama2,deepseek,yi等。

并行化

参考:https://mp.weixin.qq.com/s/Nv9iS96J7pVZRvH7U8fWsA

MultiHead 的机制很适合并行计算,这里就不展开了。Attention 的并行计算主要解决两个问题:

  1. 矩阵的并行计算。

  2. Softmax 的并行计算。

矩阵的并行算法已经比较成熟,GPU 上也有 TensorCore 来加速计算,这里不再展开。但是这里面有个 Softmax 的操作,这个操作让并行计算有些棘手。

从上面的式子可以注意到,所有的操作都变成了累加操作。加法的结合律决定了可以很方便的执行并行计算。 因为先加或者后加,分组加还是累计加,都不影响最终的结果。

但是第3步的计算依赖第2步的结果,所以不能合在一起。但巧合的是,Attention 中的 softmax 求完之后,softmax 每一项的值会与 V 中向量相乘,然后累加。如下图所示:

如果没有这个累加,比如单纯的计算 softmax,反而没有办法并行。这里的累加非常关键,有了这个累加的操作,所有的计算又符合结合律了,这就是 FlashAttention 并行加速的的理论根基。就可以将 Attention 所有的操作,都放到一个for 循环里(一个 Kernel 就可以实现)

按照这样的思路,我们可以把图像描述模型中的注意力换成 block,这样的另一个好处是:它不再是一个序列模型,转而一次计算完成。

Attention(Q,K,V)=Softmax(QKTdk)×VAttention(Q,K,V) = Softmax(\frac{QK^T}{\sqrt{d_k}}) \times VAttention(Q,K,V)=Softmax(dk​​QKT​)×V

dkd_kdk​ 是向量的长度。为什么要除以$\sqrt{d_k}$?是为了防止softmax函数的梯度消失。 可以证明QKTQK^TQKT的方差为dkd_kdk​ ,因此dkd_kdk​ 比较大时 (2 个向量的长度比较长的时候),点积方差大,即相对的差距会变大,导致最大值 softmax会更加靠近于1,剩下那些值就会更加靠近于0(退化为argmax)。算梯度的时候,梯度比较小。在 trasformer 里面一般用的 $d_k$ 比较大 (本文 512) ,除以$\sqrt{d_k}$是不错的选择。

Softmax(xi)=exi/T∑jexj/TSoftmax(x_i)=\frac{e^{x_i/T}}{\sum_{j}e^{x_j/T}}Softmax(xi​)=∑j​exj​/Texi​/T​

Q维度:(n,dk)Q维度:(n,d_k)Q维度:(n,dk​)

K维度:(m,dk)K维度: (m, d_k)K维度:(m,dk​)

QKT维度:(n,dk)×(m,dk)T=(n,m)QK^T维度:(n, d_k) \times (m, d_k)^T = (n, m)QKT维度:(n,dk​)×(m,dk​)T=(n,m)

headi=Attention(QWiQ,KWiK,VWiV)head_i=Attention(QW_i^Q,KW_i^K,VW_i^V)headi​=Attention(QWiQ​,KWiK​,VWiV​)
MutiHead(Q,K,V)=Concat(head1,...,headh)WOMutiHead(Q,K,V) = Concat(head_1 ,...,head_h)W^OMutiHead(Q,K,V)=Concat(head1​,...,headh​)WO

softmax 有个问题,那就是很容易溢出。比如采用半精度,由于float16的最大值为65504,所以只要 x≥11x\geq11x≥11 , 那么softmax就溢出了。即使是float32,x也不能超过88。

好在 exp 有这么一个性质,那就是 ex−y=exeye^{x-y}=\frac{e^x}{e^y}ex−y=eyex​ 根据这个性质,可以在softmax公式中分子分母上同时除以一个数,这样 exe^xex 不容易溢出。这个算法可以分成三次迭代来执行:

具体实现可以参考

Transformer
代码