LLM 到底在做什么 例如输入法国 的 首都 是模型要预测巴黎训练时模型会不断看到类似样本输入法国 的 首都 是目标巴黎如果模型给“巴黎”的概率高loss 就小如果模型把“伦敦”预测得更高loss 就大。训练过程就是不断调整参数让正确 token 的概率越来越高。整体流程可以画成这样输入文本Tokenizer 切成 tokenToken Embedding多层 Transformer Blocks最后位置 hidden state输出层 W_out / LM Headlogitssoftmax下一个 token 概率分布选择或采样 token注意模型内部不是直接处理汉字或单词而是处理 token id 和高维向量。Token、Embedding 和 Hidden State一句话进入模型前会先经过 tokenizer“法国的首都是” → [“法国”, “的”, “首都”, “是”]每个 token 会被映射成一个向量这一步叫 embedding法国 → [0.12, -0.08, 0.31, …]的 → [0.03, 0.22, -0.11, …]首都 → [0.44, -0.19, 0.07, …]是 → [-0.21, 0.16, 0.28, …]如果模型的 hidden size 是 4096那么每个 token 就会对应一个 4096 维向量。一开始的 embedding 只是比较基础的 token 表示。经过多层 Transformer 之后每个 token 的向量会融合上下文变成 hidden state。例如最后一个 token “是”的 hidden state经过多层加工后可以粗略理解为h_last ≈ “当前上下文在问法国的首都是哪个城市”当然模型里实际存的是高维数字向量不是中文句子。中文解释只是帮助我们理解。Transformer Block 的整体结构LLM 通常不是只有一个 Transformer Block而是很多层 Block 堆叠起来。常见数量大致是小模型6 - 12 层中等模型24 - 32 层大模型40 - 80 层超大模型80 层以上例如GPT-2 small12 层GPT-2 medium24 层GPT-3 175B96 层LLaMA 7B32 层LLaMA 13B40 层LLaMA 65B80 层一个现代 Decoder-only Transformer Block 通常包含NormSelf-AttentionResidual AddNormMLP / FFNResidual Add图示如下输入 xLayerNorm / RMSNormSelf-Attention残差相加 x Attention(…)LayerNorm / RMSNormMLP / FFN残差相加 x’ MLP(…)输出 y传给下一层公式可以简化为x’ x SelfAttention(Norm(x))y x’ MLP(Norm(x’))其中 y 就是这一层 Block 的最终输出会作为下一层 Block 的输入。每一层的输出会作为下一层输入吗是的。可以写成X0 Embedding(tokens)X1 Block1(X0)X2 Block2(X1)X3 Block3(X2)…XN BlockN(XN-1)每一层都会拿上一层输出的 hidden states 作为输入并重新计算自己的 Q、K、V第 1 层Q1 X0 Wq1, K1 X0 Wk1, V1 X0 Wv1第 2 层Q2 X1 Wq2, K2 X1 Wk2, V2 X1 Wv2第 3 层Q3 X2 Wq3, K3 X2 Wk3, V3 X2 Wv3重点是每一层输入不同每一层 Q/K/V 参数也不同每一层都会重新做一次注意力计算。低层可能更偏局部搭配、词法和位置中层可能更偏语法和实体关系高层可能更偏语义、任务意图和预测。这个说法只是直觉不是人工规定。Self-Attention让 token 理解上下文Self-Attention 要解决的问题是当前 token 应该重点关注上下文里的哪些 token例如小明 把 苹果 放进 书包 因为 它 太甜 了“它太甜”里的“它”更可能指“苹果”因为“甜”和“苹果”的语义关系更强。如果句子变成小明 把 苹果 放进 书包 因为 它 太小 了“它太小”更可能指“书包”因为“太小”更像是在描述容器容量。模型并不是写死规则而是在大量训练中学到这些统计和语义关系。Q、K、V 到底是什么Q、K、V 分别是Q Query查询K Key键 / 标签V Value值 / 内容一句话记Q我想找什么K我有什么标签能不能被别人匹配到V如果别人关注我我能提供什么内容每个 token 都会同时生成 Q、K、V。例如 token “它”Q(“它”) ≈ 我指代的是前面哪个东西前面的 token 有各自的 KK(“苹果”) ≈ 水果、物体、可被描述味道K(“书包”) ≈ 容器、物体、可被描述大小和容量如果后面出现“太甜”那么“它”的 Q 会更匹配“苹果”的 K。模型就会更多读取“苹果”的 V。如果后面出现“太小”那么“它”的 Q 会更匹配“书包”的 K。模型就会更多读取“书包”的 V。QKV 计算公式是Q X WqK X WkV X Wv注意力公式是Attention(Q, K, V) softmax(QK^T / sqrt(d_k)) V流程图输入 hidden states XQ X WqK X WkV X WvQK^T 计算相似度除以 sqrt(d_k) 缩放softmax 得到注意力权重权重加权求和 V融合上下文后的表示为什么要除以 sqrt(d_k)因为维度较大时Q 和 K 点积的数值可能很大softmax 会变得过于尖锐训练不稳定。除以 sqrt(d_k) 可以稳定数值范围。用一个例子看模型如何理解上下文输入法国 的 首都 是模型要预测下一个 token巴黎在最后一个 token “是”的位置模型可能需要关注法国首都可以粗略理解为Q(“是”)这个句子需要补充什么事实K(“法国”)国家实体K(“首都”)需要城市答案V(“法国”)法国相关语义信息V(“首都”)首都关系相关信息Attention 聚合之后最后位置的 hidden state 逐渐包含国家 法国关系 首都答案类型 城市最后输出层再把这个 hidden state 映射到词表得到巴黎: 高分伦敦: 低分苹果: 极低分这就是“理解上下文”和“预测下一个 token”之间的桥。Multi-Head Attention从多个角度看上下文一个注意力头只能从一种子空间理解关系。多个头可以同时关注不同关系。例如Head 1关注语法关系Head 2关注实体关系Head 3关注指代关系Head 4关注位置关系Multi-Head Attention 的直觉是让模型从多个角度同时理解上下文。每个 head 都有自己的 Q/K/V 投影最后多个 head 的结果会拼接或合并再经过一个输出投影矩阵 Wo。输入 XHead 1 AttentionHead 2 AttentionHead 3 AttentionHead 4 AttentionConcat / 合并输出投影 WoAttention 输出MLP / FFN对信息做加工Self-Attention 更像“信息检索”当前 token 应该从哪些上下文 token 里拿信息MLP / FFN 更像“信息加工”拿到信息之后如何进一步变换、提炼、组合MLP 和 FFN 在 Transformer 语境下基本可以认为是同一个模块MLP Multi-Layer Perceptron多层感知机FFN Feed-Forward Network前馈神经网络它通常对每个 token 的 hidden state 单独处理不负责 token 之间互相通信。token 之间的信息交换主要发生在 Attention 里。传统 FFN 结构hidden_size → intermediate_size → hidden_size例如4096 → 11008 → 4096公式FFN(x) W2 * activation(W1 * x b1) b2常见激活函数有GELUSiLUReLUSwiGLU现代 LLM 常用 SwiGLU 一类门控结构可以理解为哪些特征应该通过哪些特征应该被抑制。Attention 和 MLP 的区别可以这样记Attentiontoken mixing不同 token 之间交换信息MLPchannel mixing同一个 token 向量的不同维度之间加工组合一句话Attention 负责“看谁”MLP 负责“想明白”。残差相加是什么残差连接不是让一层完全替换输入而是输出 原输入 本层新加工的信息在 Attention 后x’ x Attention(Norm(x))在 MLP 后y x’ MLP(Norm(x’))直觉是新表示 旧理解 本层补充的新理解这有几个好处保留原始信息让每一层学习增量修改缓解深层网络梯度传播困难让模型在某层没学到有用东西时也可以近似保持原样你可能会问处理后的向量会不会盖过原向量理论上会。如果 Attention(x) 或 MLP(x) 数值特别大确实可能主导结果。但实际模型有机制控制LayerNorm / RMSNorm 稳定数值范围参数初始化控制初始输出幅度训练过程会惩罚不合适的过大修改有些模型还会使用残差缩放、门控或 Dropout所以残差连接不是简单粗暴地覆盖而是让每层在旧表示上做可学习的增量修正。输出层 W_out从 hidden state 到 token 概率经过最后一层 Transformer 后每个位置都有一个 hidden state。对于自回归语言模型预测下一个 token 时通常使用最后一个位置的 hidden stateh_last例如输入法国 的 首都 是最后位置“是”的 hidden state 可以理解为h_last ≈ “这个句子在问法国的首都是哪个城市”输出层的任务是把 h_last 映射成整个词表上每个 token 的分数。公式logits h_last W_out b如果hidden_size 4096vocab_size 50000那么h_last shape 4096W_out shape 4096 × 50000logits shape 50000也就是说一个 4096 维向量→ 输出层→ 50000 个 token 的原始分数这些原始分数叫 logits巴黎: 15.2伦敦: 7.1苹果: -2.5的: 0.8logits 还不是概率需要经过 softmaxP(token_i) exp(logit_i) / sum(exp(logit_j))得到巴黎: 0.86伦敦: 0.04柏林: 0.03苹果: 0.000001图示最后位置 hidden state h_last线性输出层 W_outlogits每个 token 的原始分数softmax概率分布选择或采样下一个 token输出层可以理解为当前 hidden state 和词表中每个 token 的“答案向量”做匹配。很多模型会让输入 embedding 和输出层权重共享参数这叫 weight tying。直觉上就是输入层把 token 变成向量输出层把向量再匹配回 token12. Wq/Wk/Wv 和 W_out 的关系