从零手搓大模型(七)GPT 转 Llama:从教学版 GPT 走向现代 LLM 架构

GPT 转 Llama:从教学版 GPT 走向现代 LLM 架构

这个模块教你把 GPT 骨架逐步改造成 Llama:RMSNorm、RoPE、SwiGLU、GQA、现代 tokenizer、权重加载。

1. GPT 和 Llama 的关系

GPT 和 Llama 都是 decoder-only Transformer。

它们的主干非常像:

text 复制代码
token embedding
-> 多层 Transformer block
-> final norm
-> output head

差异主要在 block 内部细节:

text 复制代码
GPT:   LayerNorm + learned positional embedding + GELU FFN + MHA
Llama: RMSNorm   + RoPE                       + SwiGLU FFN + GQA

这些差异就是现代 LLM 架构演化的重点。

2. 第一个变化:LayerNorm -> RMSNorm

GPT 主线里用的是 LayerNorm。

Llama 用的是 RMSNorm。

LayerNorm 会使用均值和方差:

text 复制代码
(x - mean) / sqrt(var + eps)

RMSNorm 只用均方根:

text 复制代码
x / sqrt(mean(x^2) + eps)

公式可以理解成:

text 复制代码
RMSNorm 不减均值,只按整体大小缩放。

好处是:

text 复制代码
计算更简单
训练效果通常也很好
现代 LLM 大量使用

3. 第二个变化:GELU FFN -> SwiGLU FFN

GPT 的 feed forward 通常是:

text 复制代码
Linear -> GELU -> Linear

Llama 使用 SwiGLU:

python 复制代码
class FeedForward(nn.Module):
    def __init__(self, cfg):
        super().__init__()
        self.fc1 = nn.Linear(cfg["emb_dim"], cfg["hidden_dim"], bias=False)
        self.fc2 = nn.Linear(cfg["emb_dim"], cfg["hidden_dim"], bias=False)
        self.fc3 = nn.Linear(cfg["hidden_dim"], cfg["emb_dim"], bias=False)

    def forward(self, x):
        x_fc1 = self.fc1(x)
        x_fc2 = self.fc2(x)
        x = nn.functional.silu(x_fc1) * x_fc2
        return self.fc3(x)

关键是这行:

python 复制代码
nn.functional.silu(x_fc1) * x_fc2

它是门控结构:

text 复制代码
一路生成内容
一路控制哪些内容通过

SwiGLU 是现代 LLM feed forward 的常见标配。

4. 第三个变化:绝对位置 embedding -> RoPE

GPT 主线里用了 learned positional embedding:

text 复制代码
token embedding + position embedding

Llama 使用 RoPE,Rotary Position Embedding。

RoPE 不再把位置向量直接加到 token embedding 上,而是在 attention 里旋转 query 和 key。

代码路线是:

python 复制代码
cos, sin = compute_rope_params(...)
queries = apply_rope(queries, cos, sin)
keys = apply_rope(keys, cos, sin)

直觉理解:

text 复制代码
RoPE 把位置信息编码进 Q/K 的角度关系里。

这样 attention score 里天然带有相对位置信息。

5. RoPE 的核心代码

先预计算 cos/sin:

python 复制代码
def compute_rope_params(head_dim, theta_base=10_000, context_length=4096, freq_config=None):
    inv_freq = 1.0 / (
        theta_base ** (torch.arange(0, head_dim, 2).float() / head_dim)
    )
    positions = torch.arange(context_length)
    angles = positions.unsqueeze(1) * inv_freq.unsqueeze(0)
    angles = torch.cat([angles, angles], dim=1)
    cos = torch.cos(angles)
    sin = torch.sin(angles)
    return cos, sin

再应用到 Q/K:

python 复制代码
def apply_rope(x, cos, sin):
    x1 = x[..., : head_dim // 2]
    x2 = x[..., head_dim // 2 :]
    rotated = torch.cat((-x2, x1), dim=-1)
    x_rotated = (x * cos) + (rotated * sin)
    return x_rotated.to(dtype=x.dtype)

你不用一开始完全推导数学,先记住:

text 复制代码
RoPE 只作用在 attention 的 Q/K 上,不作用在 V 上。

6. 第四个变化:MHA -> GQA

Llama 3 开始更典型地使用 GQA。

GQA 的核心是:

text 复制代码
query heads 多
key/value groups 少
多个 query heads 共享 K/V

GroupedQueryAttention 里:

python 复制代码
self.W_query = nn.Linear(d_in, d_out, bias=False)
self.W_key = nn.Linear(d_in, num_kv_groups * head_dim, bias=False)
self.W_value = nn.Linear(d_in, num_kv_groups * head_dim, bias=False)

然后:

python 复制代码
keys = keys.repeat_interleave(self.group_size, dim=1)
values = values.repeat_interleave(self.group_size, dim=1)

这让 Llama 更省 KV cache 显存,更适合长上下文推理。

7. Llama TransformerBlock 的结构

Llama block 仍然是:

text 复制代码
norm -> attention -> residual
norm -> feed forward -> residual

示意:

python 复制代码
shortcut = x
x = self.norm1(x)
x = self.att(x, mask, cos, sin)
x = x + shortcut

shortcut = x
x = self.norm2(x)
x = self.ff(x)
x = x + shortcut

这叫 pre-norm 结构。

和 GPT 主线相比,整体骨架没变,变的是 norm、attention、FFN 的内部实现。

8. Llama3Model 主体

standalone-llama32.ipynb 里的模型大致是:

python 复制代码
class Llama3Model(nn.Module):
    def __init__(self, cfg):
        self.tok_emb = nn.Embedding(cfg["vocab_size"], cfg["emb_dim"])
        self.trf_blocks = nn.ModuleList(
            [TransformerBlock(cfg) for _ in range(cfg["n_layers"])]
        )
        self.final_norm = nn.RMSNorm(cfg["emb_dim"])
        self.out_head = nn.Linear(cfg["emb_dim"], cfg["vocab_size"], bias=False)

forward 里动态创建 causal mask:

python 复制代码
mask = torch.triu(
    torch.ones(num_tokens, num_tokens, device=x.device, dtype=torch.bool),
    diagonal=1
)

然后把 x, mask, cos, sin 传进每个 block。

9. 为什么不预存巨大 mask

Llama 3.1 / 3.2 支持很长上下文。

如果预先创建:

text 复制代码
128k x 128k causal mask

内存会非常夸张。

所以 notebook 里强调:mask 可以 forward 时按实际 num_tokens 动态创建。

这是从教学模型走向真实长上下文模型时非常重要的工程意识。

10. Llama 2 -> Llama 3 / 3.1 / 3.2

这个目录里不是只讲 Llama 2。

推荐路线是:

text 复制代码
GPT -> Llama 2
Llama 2 -> Llama 3
Llama 3 -> Llama 3.1 / 3.2

变化主要包括:

  • tokenizer 改变。
  • 词表大小改变。
  • 上下文长度改变。
  • RoPE 频率缩放策略改变。
  • 使用 GQA。
  • 模型配置不同。

你可以把它看成"现代开源模型结构演进"的压缩课。

11. 权重加载为什么重要

主线章节训练的是小模型。

这个 bonus 会加载 Meta / Hugging Face 上的预训练权重。

这一步能帮助你理解:

text 复制代码
从零实现模型结构
然后把官方权重映射到自己的 PyTorch 类里

这是学习开源模型实现非常重要的能力。

权重加载函数常见逻辑:

text 复制代码
检查 shape 是否匹配
把外部权重复制到自己模型的参数里
处理命名差异

12. 建议

text 复制代码
Llama 不是推翻 GPT,而是在 GPT decoder-only 骨架上换成更现代的 norm、位置编码、FFN 和 attention 设计。
相关推荐
冬奇Lab1 分钟前
代码库知识库系列(07):混合检索 BM25 + 向量——Q8 还是失败,而且总分退步了
人工智能
ajassi200016 分钟前
AI语音智能体开发日记(十一)为智能设备“声”临其境——详解音频资源自动化生成流程
人工智能·ai·ai编程
2601_9494999435 分钟前
400G组网低功耗优选!芯瑞科技400G VR4 QSFP112光模块赋能智算中心高速互联
大数据·人工智能·科技
GoAI1 小时前
# AI Agent 记忆框架横向对比报告总结
人工智能·大模型·llm·多模态
李昊哲小课2 小时前
fastapi sse websocket 奶茶店实时订单看板
人工智能·python·websocket·网络协议·fastapi·sse
万邦科技Lafite2 小时前
天猫商品评论API:评价内容中的用户情感倾向分析
人工智能·api·电商开放平台·淘宝开放平台·api开放接口
遇码2 小时前
认识 LakeMind:一款本地优先的开源 AI 数据探索工作台
人工智能·开源
格林威2 小时前
多相机微秒级对齐:硬件触发 vs PTP(IEEE 1588)方案实战对比
开发语言·人工智能·数码相机·机器学习·计算机视觉·视觉检测·机器视觉
三江番长 陀舍古帝2 小时前
AI 相关概念之(基础层级):AI、ANI、AGI、ASI
人工智能·agi
天地会珠海分舵2 小时前
DeepSeek v4 flash vs GPT 5.6 Luna 测评报告!
gpt·deepseek·测评报告