LLM入门笔记:注意力机制与输出预测
一、什么是注意力机制?
注意力机制是LLM的"核心大脑",作用类似人类看书时的"选择性聚焦"——让模型在处理每个词时,自动关注句子中最相关的部分。
举个生活化的例子:
- 句子:“小明丢了书包,他很着急”
- 人类会自动知道"他"指的是"小明"
- 注意力机制就是让模型学会这种"关联能力",让"他"重点关注"小明"的信息
二、注意力机制的工作流程(带流程图)
整体流程图
输入向量 → 生成Q、K、V → 计算匹配分数 → 缩放 → 掩码(可选) → Softmax → 加权求和 → 多头拼接 → 输出
分步详解
1. 生成Q、K、V(查询、键、值)
- 输入:经过嵌入向量+位置编码的文本向量(假设是
[x1, x2, x3]
,每个x代表一个词的向量) - 操作:通过3个不同的矩阵(
Wq、Wk、Wv
)转换,得到3组新向量:- Q(Query,查询):
[q1, q2, q3]
→ “我要找什么信息?” - K(Key,键):
[k1, k2, k3]
→ “每个词的特征标签” - V(Value,值):
[v1, v2, v3]
→ “每个词的具体内容”
- Q(Query,查询):
2. 计算匹配分数
- 操作:把Q和K做矩阵乘法(
Q × K^T
) - 作用:计算每个词与其他所有词的"相关性分数"
- 例子:q1(第一个词的查询)和k2(第二个词的键)的分数高,说明第一个词和第二个词相关性强
3. 缩放(Scale)
- 操作:将分数除以
√dk
(dk是K的维度) - 作用:防止分数太大导致后续计算不稳定(比如避免Softmax后概率过于集中)
4. 掩码(Mask,可选)
- 场景:生成式任务(如预测下一个词)
- 操作:给"还没出现的词"(未来位置)的分数加一个极小值(比如-1e9)
- 作用:不让模型"偷看"后面的词(比如预测第3个词时,不能用第4、5个词的信息)
5. Softmax归一化
- 操作:将分数转换为0~1之间的概率(所有位置概率和为1)
- 作用:得到每个词的"关注度权重",权重越高说明越需要关注
6. 加权求和
- 操作:用Softmax得到的权重,对V向量做加权求和(
权重 × V
) - 作用:把"关注度高的词的信息"重点保留下来,得到最终的注意力结果
7. 多头注意力(Multi-Head Attention)
- 操作:把上面的过程重复多次(比如8次,称为8个"头"),然后把结果拼接起来
- 作用:从不同角度捕捉关联(比如一个头关注语义,一个头关注语法),让模型更聪明
注意力机制代码示例(简化版)
import numpy as npdef scaled_dot_product_attention(Q, K, V, mask=None):"""实现缩放点积注意力"""d_k = Q.shape[-1] # K的维度# 1. 计算Q和K的匹配分数scores = np.matmul(Q, K.T) / np.sqrt(d_k)# 2. 应用掩码(如果有)if mask is not None:scores = scores + (mask * -1e9) # 给需要掩盖的位置加一个极小值# 3. Softmax计算权重attention_weights = np.exp(scores) / np.sum(np.exp(scores), axis=-1, keepdims=True)# 4. 加权求和得到结果output = np.matmul(attention_weights, V)return output, attention_weights# 示例:3个词,每个词的向量维度为4
Q = np.random.randn(3, 4) # 3个查询向量,维度4
K = np.random.randn(3, 4) # 3个键向量,维度4
V = np.random.randn(3, 4) # 3个值向量,维度4# 计算注意力
output, weights = scaled_dot_product_attention(Q, K, V)print("注意力权重(每行和为1):\n", weights)
print("注意力输出:\n", output)
三、注意力之后的处理步骤
注意力的输出不会直接用来预测,还需要经过两个重要步骤:
1. 层归一化(Layer Normalization)
- 作用:让向量的数值分布更稳定(比如把数值调整到均值0、方差1附近)
- 为什么需要?:避免训练时数值波动太大,导致模型学不会东西
2. 前馈网络(Feed Forward Network)
- 结构:简单的两层神经网络(中间有激活函数,如ReLU)
- 作用:对每个词的向量单独做"加工",增强模型的表达能力(比如学习更复杂的语义关系)
流程小结
注意力输出 → 层归一化 → 前馈网络 → 再层归一化 → 进入下一层(重复多次)
四、输出预测:从向量到"下一个词"
经过多层注意力和前馈网络处理后,最终要生成具体的词:
预测流程
最终向量 → 线性层 → Softmax → 选择概率最高的词
分步详解
1. 线性层(Linear Layer)
- 操作:把最终的向量(比如维度768)转换为"词汇表大小"的维度(比如词汇表有30000个词,就转成30000维)
- 作用:给每个词分配一个"分数"
2. Softmax生成概率
- 操作:把线性层的分数转换为0~1的概率(所有词的概率和为1)
- 例子:"开心"的概率0.8,"难过"的概率0.1,"吃饭"的概率0.1
3. 选择输出词
- 操作:选概率最高的词作为输出(比如选"开心")
- 扩展:实际中可能会用"采样"的方式(不完全选最高概率),让输出更灵活
输出预测代码示例
def predict_next_word(final_vector, vocab_size, W_linear):"""从最终向量预测下一个词"""# 1. 线性层转换维度logits = np.matmul(final_vector, W_linear) # logits形状:(vocab_size,)# 2. Softmax计算概率probabilities = np.exp(logits) / np.sum(np.exp(logits))# 3. 选概率最高的词next_word_idx = np.argmax(probabilities)return next_word_idx, probabilities# 示例:假设最终向量维度768,词汇表大小30000
final_vector = np.random.randn(768) # 最终处理后的向量
W_linear = np.random.randn(768, 30000) # 线性层权重矩阵# 预测下一个词
word_idx, probs = predict_next_word(final_vector, 30000, W_linear)
print(f"预测的词索引:{word_idx}")
print(f"该词的概率:{probs[word_idx]:.4f}")
五、完整流程总结(从输入到输出)
输入文本 → 嵌入向量(语义)+ 位置编码(顺序) → 多头注意力(聚焦重点) → 层归一化+前馈网络(加工信息) → 重复多层处理 → 线性层+Softmax(预测下一个词)
六、小白必知的注意点
- 注意力是"学"出来的:权重不是人工设定的,而是模型通过数据自己学到的
- 多头注意力不是越多越好:头数太多会增加计算量,通常8~16头比较常见
- 掩码的重要性:没有掩码,生成式模型会"作弊"(提前看到答案)
- 输出预测不止"选最大":实际应用中会用温度系数(temperature)调整随机性,让输出更自然
七、关键概念对照表
概念 | 通俗理解 | 核心作用 |
---|---|---|
Q(Query) | “我要找什么” | 定义当前需要关注的信息 |
K(Key) | “每个词的标签” | 帮助计算与Q的匹配度 |
V(Value) | “每个词的内容” | 提供实际需要提取的信息 |
多头注意力 | “多角度看问题” | 从不同维度捕捉关联 |
层归一化 | “稳定数值” | 让模型训练更稳定 |
线性层 | “转换维度” | 连接特征向量和词汇表 |
通过这部分内容,你应该能理解LLM是如何"思考"并生成下一个词的了~ 注意力机制是LLM最核心的创新,多结合例子理解会更容易哦!