← 全部作业
← → 翻页 · O 总览 · ? 帮助
NJU DeepEngine

大语言模型基础
从零到一

理论 × 实现 · 作业链路 A0→A5 · 通勤可刷的演示稿

HTML 幻灯片 你的进度:A3 左右滑 / 点按钮
01 · 课程

不是调 API,是造零件

亲手实现类 LLaMA 的 decoder-only 组件,最后拼成完整 Transformer。

你将获得

  • 组件级理解:Norm / Emb / MLP / Attn
  • 工程手感:shape · seed · dtype
  • 现代技巧:LoRA · MoE · KVCache

评分

  • 5 次作业 80%
  • 大作业 20%
  • GitHub Classroom 提交
02 · 主线

一条链,不要跳着做

A0 梯度 A1 Matmul A2 Norm/Emb A3 MLP A4 Attn A5 Block
后面的仓库会 import 前面的模块。A3 起「跳关」几乎不可行。
03 · 依赖

拼装时谁依赖谁

A2 GroupRMSNorm ──► A4 QK-Norm ──► A5 Layer A2 Vocab / ParallelEmb ─────────────► A5 Block A2 RoPE (可选) ─────────────────────► A5 位置 A3 DenseMLP+LoRA ──► SparseMLP ─────► A5 mlp A4 Offline Attn ───► Online (可选) ─► A5 attn A5 KVCache ─────────────────────────► 推理 decoding
分仓提醒:a0–a5 是独立 repo,通过的模块要手动同步到后续作业。
04 · 工作流

通勤复习 · 工位输出

🚇 路上(手机)

  • 默写数据流与 shape
  • 记 learnable 有哪些
  • 过踩坑清单
  • 不写复杂代码

💻 图书馆

  • 写一点就 pytest
  • 边界条件补测
  • push 看 score
  • 模块同步到后仓
05 · 方法

手写主干,AI 当副驾

自己写

  • 数据流 / shape
  • seed 约定
  • LoRA / MoE 分支

可问 AI

  • API 签名
  • 报错解读
  • 局部改写
判断:纸上能否画出 shape?能 → 写;不能 → 先画图。
A0 · 已完成

Onboarding = 环境 + 梯度直觉

Y = X @ W loss = sum(Y²) dY = 2Y dW = Xᵀ @ dY # shape 与 W 相同 dX = dY @ Wᵀ # shape 与 X 相同

分母布局:梯度 shape 永远跟变量一致。后面 A1 Task3 会再用到。

A1 · 已完成

Matmul:多头与筛选

  • T1 多头:[b,s,h]×[h,e] → [b,s,nh,e],禁止 for
  • T2 importance:top_p ∧ top_k → [t,nh,e]
  • T3 有 grad_output 才反传
A2 = view(b,s,nh,hd); W2 = view(nh,hd,e) O2 = einsum("bshd,hde -> bshe", A2, W2)
A2 · 待补强

表示层三件套

必修

  • GroupRMSNorm
  • VocabEmbedding
  • ParallelVocabEmb

可选

  • NTK-aware RoPE
  • apply_rotary_pos_emb
  • dynamic 外推
A4/A5 强依赖这里。时间紧:必修先满分,RoPE 可后置。
当前主战场
A3

Modeling MLP

Dense GLU-MLP → +LoRA → Sparse MoE

你在这里 mlp.py empty 权重已写
A3 · Dense

GLU 前向,四步

X: [b, s, d] up = X @ W_up # W_up [d, ffh] gate = φ(X @ W_gate) # W_gate [d, ffh] h = up ⊙ gate # 逐元乘 O = h @ W_down # W_down [ffh, d] # O: [b,s,d] 与 X 同 dtype/device · 无 bias

φ 由 activation_type 决定:SILU / GELU / RELU / SIGMOID / BILINEAR…

A3 · 参数

哪些是 learnable?

Dense 基座

  • W_up
  • W_gate
  • W_down

扩展

  • LoRA:A、B(rank>0)
  • MoE:各 expert + G
  • G 固定 float32
不是 learnable:激活函数本身、top-k 路由逻辑、mask 规则。
A3 · 关键习惯

reset_parameters 怎么调?

__init__: 创建 empty Parameter(W_up / gate / down) self.reset_parameters() # ← 只调用一次 reset_parameters: 内部把所有权重 init 完 # 不是每个 weight 对外各调一次 reset

nn.Linear 同一套习惯:创建结构 → 一次初始化。

A3 · 初始化

选 Xavier 还是 Kaiming?

Xavier normal

  • SIGMOID
  • BILINEAR

Kaiming normal

  • RELU / GELU / SILU…
  • mode = fan_in
seed:up +1 · gate +2 · down +3(相对 init_base_seed)
每个矩阵 init 前单独 manual_seed。
A3 · 进度

你已经走到哪了

  • ✅ 保存全部构造参数到 self
  • ✅ empty:W_up[d,ffh] · W_gate · W_down[ffh,d]
  • 🟡 reset:分支有了,待补 seed + 三次 init_
  • ⬜ __init__ 末尾调用 reset
  • ⬜ forward(先无 LoRA)
  • ⬜ LoRA → SparseMLP
下一刀:写完 reset → 能实例化 → print(W.std())。
A3 · 动手提示

reset 的伪代码骨架

use_xavier = activation in {SIGMOID, BILINEAR} for weight, offset in [ (W_up, 1), (W_gate, 2), (W_down, 3) ]: torch.manual_seed(init_base_seed + offset) if use_xavier: xavier_normal_(weight) else: kaiming_normal_(weight, mode="fan_in", ...) # 注意:[in,out] 存法 vs Linear 的 [out,in] # 写完用 std ≈ √(2/fan_in) 自检
A3 · LoRA

低秩增量,不是重训全家桶

ΔW ≈ (α / r) · A @ B # 作业简化:整段 MLP 只挂一次 LoRA # rank == 0 → 完全跳过 # α is None → α = rank # A,B:uniform;seed = lora_init +1 / +2 # dropout 用 lora_dropout_seed 可复现

先 Dense 过测,再开 LoRA。别两步揉在一起 debug。

A3 · Sparse

MoE = 路由 + 多个小 Dense

  1. G:[d, ne] → logits → softmax → P
  2. 每 token top-k,再 renormalize
  3. expert ≈ DenseMLP(ffh = ffh/ne)
  4. 只算本地 rank 分片;否则输出 0
G 用 float32;expert seed 按全局 expert index 偏移。
A4 · 最难一关

Attention:mask 的艺术

  • Offline Sliding-Window + causal/full/window
  • Pack / Layout / GQA / QK-Norm
  • 矩形 Q/K:bottom-right causal
  • 可选 Online:分块 + lse 合并
工期建议 4–6 天;赶进度只保 Offline 满分。
A5 · 拼装

汉堡:面包 + 牛肉饼

I[b,s] token ids → VocabEmb → (DecoderLayer × L) # Attn + MLP + 残差 → FinalNorm → LMHead → Logits[b,s,vocab] 推理时:KVCache 跨 step 复用 K/V

seed 偏移按层号加表;lm_head_tied 可能共享 Embedding 权重。

速查

Shape 一张表

Multi-head matmul [b,s,h]×[h,e] → [b,s,nh,e] Importance out [t,nh,e] GroupRMSNorm [b,s,h] → [b,s,h] VocabEmb [b,s] → [b,s,e] DenseMLP [b,s,d] → [b,s,d] Attn Q [b,sq,hq,hd] → O 同 Q DecoderBlock ids[b,s] → logits[b,s,V]
避雷

高频扣分点

  • 多个矩阵共用一个 seed
  • Xavier / Kaiming 分支反了
  • fan_in 与 layout 不一致
  • 输出 dtype/device 漂了
  • LoRA rank=0 没短路
  • α=None 没当成 rank
  • MoE 忘了 renorm
  • Attention mask 对齐错边
  • 分仓模块没同步
节奏

快速推进参考

W1

A2 必修满分 · A3 开干

W2

A3 满分 · A4 offline 主干

W3

A4 收尾 · A5 拼装 · 回归

砍 scope

先弃 Online / 后补 RoPE

Action

回到工位,只做这一刀

写完 reset_parameters 三权重初始化
挂上 self.reset_parameters()
实例化成功 · 打印 std · 再写 forward

pytest test_toy.py 一次只改一个点
资源

需要联网时打开

  • 讲义:njudeepengine.github.io/llm-course-lecture
  • 作业:njudeepengine.github.io/LLM-Blog
  • A3:…/A3-modeling-mlp
  • PyTorch init:pytorch.org/docs → nn.init
本地代码:~/Documents/nju-llm/{a0..a5}
本演示稿:~/Documents/nju-llm/handbook/slides.html
End

先把零件造好
再拼巨型汉堡

左右滑继续刷 · 工位上打开 a3/mlp.py

O 键总览 ? 快捷键
1 / 1

快捷键