从零训练一个“小”语言模型:llm-madness 完全实操指南
“
把实验室里那套“高大上”的 LLM 流程,装进一台普通笔记本里
”
先回答你最想问的 3 个问题
| 问题 | 一句话答案 |
|---|---|
| 这玩意能干嘛? | 在本地就能跑完“数据→分词→训练→看结果”全链路,最适合练手、做原型、写论文 baseline。 |
| 需要多好的机器? | 没有 GPU 也能跑;一张 8 GB 显存的消费级显卡就能训练 30 M 参数以内的模型。 |
| 跟 ChatGPT 差距多大? | 它只有“几十兆”体量,生成效果肯定追不上千亿级怪兽,但你能看到每一层 attention 在干嘛,这是黑盒大模型永远给不了的洞察力。 |
目录
-
项目速览:一张图看懂流程 -
安装 & 环境:3 行命令搞定 -
数据准备:把你的 .txt变成“数据集快照” -
训练分词器:为什么 BPE 不是“暴力切词” -
配置模型:n_layer、n_head 到底怎么选? -
启动训练:让 loss 曲线在浏览器里实时跳舞 -
检查结果:loss、perplexity、attention 三张图 -
常见问题 FAQ:踩坑 20 例 -
下一步:如何把 30 M 模型压缩到 8 MB 并塞进手机
1. 项目速览:一张图看懂流程
(截图来自 README,浏览器打开 http://localhost:8080 即可看到同款界面)
| 阶段 | 产出物 | 关键文件 |
|---|---|---|
| ① 数据快照 | data/<name>.manifest + *.sha256 |
llm_madness/datasets/manifest.py |
| ② 分词器 | runs/tokenizer/<id>/vocab.json |
llm_madness/tokenizer.py |
| ③ 预编码 | runs/tokens/<id>/train.bin |
llm_madness/stages/tokenize_dataset.py |
| ④ 训练 | runs/train/<id>/checkpt.pt + run.json |
llm_madness/stages/train.py |
| ⑤ 可视化 | 浏览器里实时 loss / sample / attention | scripts/web_ui.py |
2. 安装 & 环境:3 行命令搞定
# ① 克隆
git clone https://github.com/your-username/llm-madness.git
cd llm-madness
# ② 装依赖(Python≥3.9)
pip install -r requirements.txt
# ③ 验证
python -c "import llm_madness; print('OK')"
“
Windows 用户:如果在
torch安装环节卡住,先去 pytorch.org 复制带 CUDA 的 pip 指令即可,其余包不变。”
3. 数据准备:把你的 .txt 变成“数据集快照”
3.1 最低格式要求
-
纯文本 .txt,UTF-8 编码 -
一行一段或一行一句都行,不需要额外清洗标点,代码仓库会帮你做正则拆分。
3.2 创建快照(2 选 1)
| 方式 | 命令 | 适合人群 |
|---|---|---|
| Web 界面 | python -m scripts.web_ui → 点“Datasets”→“Create Snapshot” |
鼠标党 |
| CLI 一行 | python -m scripts.dataset_snapshot --input data/my_corpus.txt --split 0.9 |
脚本党 |
执行完会在 data/ 下同时出现
-
my_corpus.manifest(JSON,记录文件 lineage) -
my_corpus.sha256(校验和,保证可复现)
4. 训练分词器:为什么 BPE 不是“暴力切词”
BPE(Byte-Pair Encoding)核心思想只有一句:把出现频率最高的相邻字节对合并成新符号,循环到 vocab 满为止。
好处:
-
天然平衡中文、英文、代码、emoji——因为底层是字节。 -
词表大小可控,30 k、50 k、100 k 随你定。
4.1 配置参数速查表
| 参数 | 示例值 | 备注 |
|---|---|---|
vocab_size |
32000 | 常见起点 |
pretokenizer |
"digits" |
把 1234 拆成 1 2 3 4,减少数字长尾 |
regex_pattern |
`\w+ | \s+` |
4.2 一键训练
python -m scripts.train_tokenizer \
--config configs/tokenizer/default__v002.json \
--input data/my_corpus.txt \
--set vocab_size=32000
跑完会生成
-
runs/tokenizer/<id>/vocab.json -
runs/tokenizer/<id>/merges.txt
“
小技巧:同一批数据先跑 16 k、32 k 两份词表,用 Web UI 里的“Tokenizer Compare”功能,看压缩率(bytes per token)差多少,再决定用谁。
”
5. 配置模型:n_layer、n_head 到底怎么选?
llm-madness 的 GPT 骨架就是经典三联:
Embedding → Transformer Block ×N → LayerNorm → Linear
每个 Block 里又拆成 SelfAttention + MLP。
5.1 先给一张“经验表”
| 参数量级 | n_layer | n_head | emb_dim | 显存≈ |
|---|---|---|---|---|
| 10 M | 6 | 6 | 512 | 2 GB |
| 30 M | 8 | 8 | 768 | 4 GB |
| 100 M | 12 | 12 | 1024 | 8 GB |
“
显存是
fp32粗算,开mixed-precision再打 6 折。”
5.2 现代小模型三件套开关
在配置里把下列字段改成 true 即可启用
-
use_rmsnorm:用 RMSNorm 代替 LayerNorm,提速 5% 显存↓ -
use_swiglu:SwiGLU 替代 GELU,相同参数略涨 PPL↓ -
use_rope:旋转位置编码,长文本外推更好,但把pos_emb关掉。
// configs/training/moderntiny__v007.json 片段
{
"model": {
"n_layer": 8,
"n_head": 8,
"n_embd": 768,
"use_rmsnorm": true,
"use_swiglu": true,
"use_rope": true
}
}
6. 启动训练:让 loss 曲线在浏览器里实时跳舞
# 如果前面步骤都用默认文件名,可直接:
python -m scripts.pipeline --config configs/pipeline.json
# 想手动指定路径:
python -m scripts.train_model \
--config configs/training/moderntiny__v007.json \
--data data/my_corpus.txt \
--set max_iters=50000
训练脚本会自动:
-
找最新的 tokenizer → tokens → 加载 .bin -
每 100 iter 写一次 checkpoint -
每 500 iter 在 runs/train/<id>/samples.txt里生成 10 条样本 -
把 loss、perplexity、lr 写进 logs.jsonl
6.1 实时查看
python -m scripts.web_ui
# 浏览器打开 http://localhost:8080
# 点“Runs”→ 选中最新 run → 看“Loss Curve”标签页
7. 检查结果:loss、perplexity、attention 三张图
| 指标 | 怎么看 | 正常范围 |
|---|---|---|
| loss | 平滑下降 → 底部横盘 | 中文 30 M 模型 2.8–3.2 |
| perplexity | 约等于 exp(loss) |
同上例≈16–24 |
| attention | 点开“Attention Inspect”→选层→选头 | 对角线亮斑表示因果,竖线表示“复制前文” |
如果 loss 高台跳水后立刻反弹,90% 是 lr 太大;把 learning_rate 从 6e-4 调到 3e-4 再试。
8. 常见问题 FAQ:踩坑 20 例
| 问题 | 原因 | 解决 |
|---|---|---|
| 显存溢出 | batch_size 太大 | 在 config 里把 batch_size=64→32 |
| 训练卡住 | token_cache 损坏 | 删 runs/tokens/*/train.bin 重新跑 |
| 中文乱码 | 原始 txt 不是 UTF-8 | iconv -f gbk -t utf-8 old.txt > new.txt |
| 样本全是重复 | temperature=0 | 把 sample_temperature 调到 0.8 |
| 找不到最新 run | 误删 latest 软链 |
手动 ln -s runs/train/<id> runs/train/latest |
9. 下一步:如何把 30 M 模型压缩到 8 MB 并塞进手机
llm-madness 原生只负责“训练+调试”,并不自带量化。但走完上面流程后,你手里已有:
-
checkpoint.pt(fp32,约 120 MB) -
vocab.json(明文,1 MB)
后续可接任何开源压缩工具链:
-
post-training dynamic-quant → torch.quantization一键 int8,体积↓ 4× -
QAT(Quantization Aware Training) → 复用同一训练脚本,把 forward包一层 fake-quant,再训 5 k step,PPL 几乎不掉。 -
导出到 ONNX → MLC-LLM → 安卓 30 ms/token 不是梦。
结语:小模型不是“玩具”,而是显微镜
当你能用肉眼看到 attention 为什么把“新冠”和“病毒”连到一起时,再回头去读百亿级论文,会突然明白“原来那行公式背后干的是同一件事”。
llm-madness 的价值正是把“黑盒”变“白盒”,让每一次超参调整都能秒级反馈。祝你玩得开心,记得把踩到的新坑也提 PR 补回文档,下一位同学会感谢你。
