Oasis's Cloud

一个人的首要责任,就是要有雄心。雄心是一种高尚的激情,它可以采取多种合理的形式。
—— 《一个数学家的辩白》

从零构建大模型(三)

编码注意力机制

作者:oasis


注意力机制解决的问题

注意力机制的目的是解决上下文丢失的问题。编码器-解码器RNN的一个主要限制是,在解码阶段,RNN无法直接访问编码器中的早期隐藏状态。因此,它只能依赖当前的隐藏状态,这个状态包含了所有相关信息。

自注意力机制允许输入序列中的每个位置关注同一序列中的所有位置。传统的注意力机制关注的是两个不同序列元素之间的关系。而自注意力机制中, 通过关联单个输入序列中的不同位置来计算注意力权重。

基础注意力机制的逻辑

自注意力机制的目标是为每个输入元素计算一个上下文向量,该向量结合了其他所有输入元素的信息。 上下文向量(context vector)可以被理解为一种包含了序列中所有元素信息的嵌入向量。

计算过程: 1. 通过点积计算查询x与其他说有输入元素之间的注意力分数。点积可以表示两个向量之间的对齐程度:点积越大,向量之间的对齐程度或相似度越高。 2. 对计算后的注意力分数进行归一化处理。归一化处理有助于解释结果,能维持大语言模型的训练稳定性。 3. 将嵌入的输入词元与相应的注意力权重相乘,再将得到的向量求和来计算上下文向量。

为什么要进行归一化处理?

归一化的目的是消除奇异样本数据导致的不良影响。例如:

未归一化处理:

张三:10000分(他说自己最饿)
李四:5分
王五:3分
其他人:都是1分

按分数分披萨:
张三:10000/(10000+5+3+1+1+1+1+1) ≈ 99.9%
其他人:总共分到0.1%的披萨

结果:张三吃了几乎整个披萨,其他人饿死了!
归一化后(系统调整):
系统说:“别闹,最高分不能太离谱”
调整后:
张三:10分(原来10000分 ÷ 1000)
李四:5分不变
其他人:1分不变

现在分披萨:
张三:10/(10+5+1+1+1+1+1+1) ≈ 45%
李四:5/... ≈ 23%
其他人:各分到大约4%

结果:大家都吃到披萨了,没人饿死!

可训练权重的自注意力机制

缩放点积注意力(scaled dot-product attention)的实现步骤 1. 计算输入元素的查询向量、键向量、值向量 2. 使用通过各自权重矩阵变换后的查询向量和键向量计算注意力分数 3. 将注意力分数除以键向量的嵌入维度的平方根来进行缩放 4. 对值向量进行加权求和来计算上下文向量

缩放点击注意力怎么体现出可训练权重?可训练权重不再点积计算里,而在生成 Q、K、V的线性变换中。

可训练体现在反向传播阶段,这些用到的参数需要存储下来?

因果注意力机制

因果注意力解决了这样的问题:标准的自注意力机制可以一次性访问整个输入序列,但是我们希望自注意力机制在预测序列中的下一个词元时仅考虑 当前位置之前的词元。因果注意力机制实现了这样的逻辑。

因果注意力的实现基于掩码和归一化,通过掩码实现“只能看左边,不能看右边”的规则。

# 假设有4个词的序列
序列长度 = 4

# 因果掩码矩阵(下三角矩阵)
因果掩码 = [
    [True,  False, False, False],  # 词1只能看自己
    [True,  True,  False, False],  # 词2能看词1和自己
    [True,  True,  True,  False],  # 词3能看词1,2和自己
    [True,  True,  True,  True]    # 词4能看所有前面的词
]

# 在注意力中应用:
# False的位置会用-∞替换,这样softmax后概率为0
# True的位置保留原值

img.png

多头注意力机制

多头注意力的主要思想是并行运行注意力机制,每次使用学到的不同的线性投影(将输入数据乘以权重矩阵得到的)。

多头注意力的结果表示为一个张量,例如两个注意力头会生成一个张量,该张量包含两个上下文向量矩阵。