MiniMind / LLM 工程化训练学习笔记
这是一份面向初学者的学习笔记:用 MicroGPT 的极简原理理解 MiniMind 的真实工程链路,从 tokenizer、dataset、model 到 pretrain、full_sft、LoRA、评估和发布。
先跑通官方链路。
输入前文,预测下一个 token。
让训练可跑、可恢复、可扩展。
loss 不是交付标准。
1. 学习总览
本次学习围绕 minimind 项目展开。它不是极简玩具代码,而是一个小型但完整的 LLM 工程训练项目。
MicroGPT
用于理解 GPT 原理的透明教学代码。重点是看清楚:文本如何变 token、模型如何算 logits、loss 如何反向传播。
MiniMind
用于学习工程化训练。包含 tokenizer、dataset、模型结构、训练脚本、SFT、LoRA、checkpoint、评估与发布。
MicroGPT = 原理最小化
MiniMind = 工程链路完整化
二者核心都是:输入 token → 预测下一个 token → loss → backward → optimizer.step()
2. MiniMind 训练链路
3. Tokenizer:文字与 token id 的翻译器
核心概念
| 术语 | 通俗解释 |
|---|---|
| tokenizer | 文本和 token id 的翻译器。 |
| vocab / 词表 | token 到 id 的映射表。 |
| BPE | 高频片段合并成 token。 |
| ByteLevel | 从字节层面兜底,几乎任何字符都能表示。 |
文本:你好,人工智能
↓ tokenizer.encode
input_ids: [1968, ...]
↓ tokenizer.decode
文本:你好,人工智能
minimind/model/tokenizer.json,不是没有中文,而是 ByteLevel 形式看起来像乱码。只要 encode/decode 可逆,就说明支持中文。词表大小与参数
词表相关参数 ≈ vocab_size × hidden_size
如果 embedding 和 lm_head 不共享:≈ 2 × vocab_size × hidden_size
MiniMind 使用 6400 小词表,是为了降低 embedding 和输出层参数占比;Qwen 约 248k 词表更适合大模型、多语言和代码,但不适合直接塞进 MiniMind 小模型。
4. Dataset:数据如何变成训练样本
JSONL
JSONL 是一行一个 JSON 对象。MiniMind 预训练和 SFT 数据都使用 JSONL。
{"text": "人工智能正在改变世界。"}
{"text": "Transformer 是现代大语言模型的重要结构。"}
PretrainDataset
text
→ tokenizer
→ 加 BOS / EOS / PAD
→ input_ids
→ labels = input_ids.clone()
→ PAD 对应 label 改成 -100
SFTDataset
conversations
→ apply_chat_template
→ input_ids
→ 只让 assistant 回答部分参与 loss
→ user/system 部分 label = -100
5. 模型结构:从 input_ids 到 loss
| 模块 | 作用 | 类比 |
|---|---|---|
| Embedding | token id 变成向量 | 编号变个人档案 |
| Attention | 让 token 看上下文 | 开会交流 |
| MLP | 每个 token 自己加工 | 回座位消化 |
| RMSNorm | 稳定数值 | 统一量纲 |
| lm_head | hidden_states 变词表分数 | 答题卡评分器 |
6. Pretrain:让模型学语言
预训练的目标是 next-token prediction:根据前文预测下一个 token。
看到:BOS 我 喜欢
预测:我 喜欢 AI
MiniMind 中,train_pretrain.py 负责:加载 tokenizer、创建模型、读取 pretrain_t2t_mini.jsonl、训练、保存 pretrain_768.pth。
工程术语速记
- epoch:完整看一遍数据。
- batch_size:一次喂多少样本。
- step:训练一个 batch。
- learning_rate:参数改动幅度。
- optimizer:真正更新参数。
- checkpoint:训练存档,可断点续训。
7. Full SFT:让模型学会当助手
full_sft 是全量监督微调:加载 pretrain 权重,用对话数据继续训练整个模型。
| 项目 | Pretrain | Full SFT |
|---|---|---|
| 数据 | {"text": ...} | {"conversations": [...]} |
| 目标 | 学语言 | 学对话和指令 |
| 默认输入权重 | none | pretrain |
| 默认输出权重 | pretrain | full_sft |
8. LoRA:低成本适配插件
LoRA 冻结原模型大部分参数,只训练低秩小矩阵。
W' = W + ΔW
ΔW = B × A
A: [in_features, rank]
B: [rank, out_features]
| 适合 | 不适合 |
|---|---|
| 风格、格式、角色、领域表达、少量稳定知识 | 大量知识库、实时知识、必须精确引用的事实 |
9. 评估、Benchmark 与人工评审
eval_llm.py
eval_llm.py 是简单人工推理测试脚本,类似冒烟测试,用来观察模型是否能正常回答。
企业级评估链路
人工评审会检查:准确性、相关性、完整性、安全性、格式遵循、业务口吻和是否可交付。
10. 模型发布
MiniMind 训练时得到 .pth,发布时通常转成 Transformers 目录。
minimind-3/
├── config.json
├── generation_config.json
├── pytorch_model.bin 或 model.safetensors
├── tokenizer.json
├── tokenizer_config.json
├── special_tokens_map.json
└── model_minimind.py 可选
| 文件 | 作用 |
|---|---|
| config.json | 模型结构说明书 |
| model.safetensors / pytorch_model.bin | 模型权重 |
| tokenizer.json | 词表和切分规则 |
| tokenizer_config.json | tokenizer 配置和 chat_template |
| generation_config.json | 默认生成参数 |
11. 架构设计、参数量与 layer_types
参数量是训练前设计好的
训练改变参数值,不改变参数数量。参数数量由架构决定。
总参数 ≈ 词表参数 + Transformer 主体参数
词表参数 ≈ vocab_size × hidden_size
Attention ≈ 4H²(普通 MHA)
SwiGLU MLP ≈ 3 × H × I
layer_types
Qwen3.5 中的 layer_types 表示每层使用哪种 block/attention 算法,例如 linear_attention 或 full_attention。
full_attention
标准 attention,表达强,但长文本计算贵,复杂度接近 O(N²)。
linear_attention
线性注意力,适合长上下文,计算更省,但算法和实现更复杂。
训练是否逐层进行?
不是。LLM 通常端到端训练:所有层一起 forward,loss 从最后算出,backward 从后往前传播梯度,optimizer 更新所有可训练参数。
12. 复习卡片
鼠标悬停卡片查看答案。
13. 自测题
1. tokenizer 是否包含知识?
不包含。tokenizer 只负责文本和 token id 的映射,知识主要在模型权重中。
2. full_sft 会改变模型参数数量吗?
不会。它只改变参数值,不改变模型结构和参数个数。
3. 为什么 LoRA 不能随便换 tokenizer?
LoRA 依附于基础模型,基础模型的 embedding 和 token id 含义已经固定,换 tokenizer 会导致 id 语义错乱或越界。
4. logits 是概率吗?
不是。logits 是原始分数,经过 softmax 后才成为概率。
5. 为什么 SFT 只训练 assistant 部分?
因为 user 是题目,assistant 是标准答案;训练目标是让模型学会回答,而不是模仿用户问题。
6. .pth 和 checkpoint 区别?
.pth 通常是模型权重;checkpoint 是训练存档,还包括 optimizer、scaler、epoch、step 等。
7. 企业模型为什么需要 benchmark?
因为 loss 只能反映训练拟合程度,benchmark 和人工评审才能判断是否满足业务交付、安全和质量要求。
8. 训练是一层一层单独训练吗?
不是。通常是端到端训练,所有层一起 forward/backward/update。