组装 LLaMA3
把前面造的新零件拼成完整的 LLaMA3 解码器,堆叠、加载真实权重,让它说出第一句话。
一层 LLaMA3,就是这几个零件的总装
前面几课造的零件,现在拼起来。LLaMA3 一个解码器层的结构是:
对照早期 Transformer 的解码器层,差异一目了然:
还有一处顺序上的差别:归一化采用 「先归一再进子层」的 Pre-Norm 。在「残差与层归一化」里提过,归一化既可以放在子层 之后 (Post-Norm),也可以放在子层 之前 (Pre-Norm)。LLaMA3 用后者——
把这一层画出来:
输入先过 RMSNorm 再进子层,子层输出在相加处回到主通路。竖直的主通路不经过子层,输入沿它原样直通到深层。
堆叠成完整模型
把解码器层堆 N 层,前后配上嵌入和输出,就是完整模型:
整个模型就是这样一条主线:
词嵌入把 token 变成向量,中间 N 个结构相同的解码器层依次堆叠,末尾归一化后由输出线性层映射回词表。
以 LLaMA3-8B 作工业级参照,看看真实规模长什么样:
作为对照,「BERT 与预训练范式」里提到的 BERT-base 约 1.1 亿参数——LLaMA3-8B 是它的约 70 倍,这就是「大」模型的规模感。
结构能自己搭,权重从哪来
真实的 LLaMA3 在 数万亿 token 上预训练而成,成本极高,个人无法复现。但好消息是:模型的 结构 我们已经能亲手搭出来。
动手:逐层组装
把「RMSNorm 与 SwiGLU」「旋转位置编码 RoPE」「KV 缓存与分组查询注意力」里实现的零件拼成一个解码器层:
全程打印张量形状,确认每一层的输入输出形状一致——这是能反复堆叠的前提。
动手:加载权重,让它开口
LLaMA3-8B 有 80 亿参数,普通环境难以运行。所以这里选一个 规模小、但架构相同 的开源模型——它和 LLaMA3-8B 只是 大小 不同, 结构完全一致 (同样的 RMSNorm、RoPE、SwiGLU、GQA、decoder-only)。真正加载权重、跑推理,直接用 transformers 里同一套架构的成熟实现,而不是把参数手动灌进刚搭的 LlamaModel 骨架;正因为两者结构对得上,官方训练好的权重才装得进去、直接能跑。给它一个前缀,让它自回归生成:
这是第一次见到一个「像样的大模型」真的开口说出连贯的话。
generate 内部是一个循环,前向一次接出一个词,把它接到已有内容的末尾,再作为下一次前向的输入。跑起来是这样:
这里的续写是示意文本,模型实际接出什么,由它装的权重和采样方式决定。
LLaMA3 由 Meta 发布,权重与说明见 llama.com ;各类开源权重可在 Hugging Face 找到。
动手:一个有趣的例子
还有一个流传很广的例子:问它「生命、宇宙以及一切的终极答案」:
42 是模型在预训练语料里记住的 梗 ,出自《银河系漫游指南》。能不能接出它,取决于模型有没有见过这个说法,和推理链路搭得对不对无关。
动手:打开内部看一眼
模型跑起来之后,它内部每一层的注意力权重都可以直接取出来看。
取「从前有一座山,山里有一座庙」这 10 个 token,把某一层、某个头的注意力权重排成方阵:行是当前正在生成的词,列是它回头在看的词。
格子颜色按上方色阶对应注意力权重,每一行是一次 softmax 的输出、行内权重之和为 1,右上角是因果掩码屏蔽的未来位置。这里用的是一组示意权重,用来说明典型的注意力模式,数值不取自某个具体权重的真实推理。
切到不同的层和头会看到,有的头几乎把全部权重给了紧挨着的前一个词,有的头把权重投向「山」「庙」这少数几个实词。每个位置的注意力都有明确的侧重,很少把权重均摊给前文所有词。
小结:一套「公共骨架」
现代主流开源大模型(LLaMA、Qwen、Mistral 等)大多是这套 decoder-only + RMSNorm + RoPE + SwiGLU + GQA 的组合。我们搭的,正是它们的「公共骨架」——理解了它,就理解了今天绝大多数开源大模型的内部构造。
很强,但它只会「接着往下写」
这个模型很强,但它此刻只会做一件事—— 接着你的话往下写 。
从「会续写」到「会对话、听指令」,还差最后一步——对齐。这是「从续写到对话助手」要讲的。