Skip to content

Transformer 推理图 — 练习

练习 1:绘制单层计算图

阅读 llm_build_llama 函数,为单层 Transformer 绘制完整的计算图(从输入到输出),标注每个 GGML 操作。

参考答案

单层计算图(简化):

input → rms_norm → mul_mat(Wq) → rope → ─┐
         ↓                                  │
      mul_mat(Wk) → rope → store_K ────────┤
         ↓                                  │
      mul_mat(Wv) → store_V ───────────────┤

      attention(Q, K_cache, V_cache) ←──────┘

      mul_mat(Wo) → add(residual) ─┐

      rms_norm → mul_mat(Wgate) → silu → mul → mul_mat(Wdown) → add(residual)
                 mul_mat(Wup)  ──┘

练习 2:理解 RoPE 的维度变换

RoPE 作用于 Q 和 K 的 head 维度上。对于一个 hidden_dim=4096, n_heads=32 的模型,计算每个 head 的维度和 RoPE 作用的部分。

参考答案
  • head_dim = hidden_dim / n_heads = 4096 / 32 = 128
  • RoPE 作用于 head_dim 的一半:n_rot = 128 / 2 = 64 对旋转
  • 对于 GQA 模型(如 n_kv_heads < n_heads),K/V 的 head_dim 相同但 head 数不同
  • RoPE 只影响 Q 和 K,不影响 V

练习 3:对比不同架构的 FFN

llama-model.cpp 中找到至少两种不同的 FFN 实现(如 LLaMA 的 SwiGLU 和 GPT-2 的 GeLU),对比差异。

参考答案

LLaMA (SwiGLU):

cpp
gate = ggml_mul_mat(ctx, layers[il].ffn_gate, cur);
up   = ggml_mul_mat(ctx, layers[il].ffn_up, cur);
gate = ggml_silu(ctx, gate);
cur  = ggml_mul(ctx, gate, up);
cur  = ggml_mul_mat(ctx, layers[il].ffn_down, cur);

GPT-2 (GeLU):

cpp
cur = ggml_mul_mat(ctx, layers[il].ffn_up, cur);
cur = ggml_gelu(ctx, cur);
cur = ggml_mul_mat(ctx, layers[il].ffn_down, cur);

差异:SwiGLU 使用两个投影(gate + up)做门控,GeLU 使用单个投影 + 激活。

拓展挑战

  • 阅读 ggml_rope 的实现,理解旋转矩阵的构造方式
  • 对比 LLaMA 和 Mistral 架构在代码中的差异
  • 理解 GQA (Grouped Query Attention) 如何减少 KV Cache 大小