一张3090两天,我把GPT-2从头训了一遍:普通人离"炼丹"到底还有多远
把这次实验当成一面镜子:它既照出了消费级硬件赋予个体的惊人能力,也照出了从"能跑"到"能用"之间那条还跨不过去的沟。
一、事情的起点
读完 Sebastian Raschka 的《Build a Large Language Model From Scratch》后,一个念头挥之不去:
如果不靠云、不靠集群,仅凭一张家里的消费级显卡,普通人到底能不能从头"炼"出一个像点样的基础模型?
粗略的直觉是不行。但 Andrej Karpathy 已经用 nanoChat 证明过一次——一个 5.61 亿参数的模型,8 张 H100 跑 4 小时、花 100 美元就能训完。他把门槛踩到了地上。
那我们再退一步:1.63 亿参数、GPT-2 small 那个量级,单张 24GB 的游戏显卡,有没有戏?
二、先把靶子钉死
要复现的是 2019 年 OpenAI 那版 GPT-2 small,配置严格照抄:
- 词表 50257(沿用 GPT-2 分词器)
- 上下文长度 1024 token
- 嵌入维度 768、12 个注意力头、12 层 Transformer
- dropout 0.1
- 一个现代实践上的取舍:去掉 QKV 投影里的偏置项
最终参数量卡在 1.63 亿。不多不少,正好卡在"单卡显存能塞下"和"能学出点东西"的甜蜜点上。
三、数据这一关比硬件还狠
原版 GPT-2 用的是约 100 亿 token 的 WebText,早没人维护了。现在 Hugging Face 上现成的 FineWeb 数据集把这个量级补上了,更讲究的还有 FineWeb-Edu——只留"教育性网页"的子集。
真正麻烦的是一个细节:把 FineWeb 整个拉下来看文本长度分布,会发现大量文档本身就超过 1024 token。如果粗暴按文档截断再 padding,直接扔掉 29% 的 token。
两种做法:
- 裁了 pad——简单,但浪费数据;
- 把所有文本用分隔符拼成超长流,再切成 1024 token 的片段——复杂,但更接近原版 GPT-2 当时的训练方式。
选第二种。
四、24GB 显存是条死线
RTX 3090 的显存决定了 batch size 上限,也就决定了吞吐。写个测试脚本在不同精度下实测:
| 精度 | 最大 batch | 吞吐 |
|---|---|---|
| FP32 | 5 | 12599 token/s |
| TF32(开张量核心) | 5 | 15402 token/s |
| 自动混合精度 AMP | 6 | 约 20000 token/s |
最后一档是甜点:吞吐拉到接近 2 万 token/s,batch 还能再往上推一格。这是整个项目能不能在一个周末跑完的生死线。
五、训多少?Chinchilla 定律给的答案
原版 GPT-2 论文语焉不详,外界估算它在那 100 亿 token 上跑了约 40 个 epoch——显然不是单卡能碰的量级。
DeepMind 的 Chinchilla 定律给了一个计算最优的经验值:训练 token 数 ≈ 参数量的 20 倍。
1.63 亿 × 20 ≈ 32.6 亿 token。FineWeb 的 100 亿样本足够覆盖,意味着单 epoch 就能完成,不用反复遍历。
账算一下:32.6 亿 ÷ 20000 ≈ 16.3 万秒,约 45 小时。一个周末,正好。
六、基建比训练本身还磨人
真开跑之前,三件事必须先落地:
数据预处理:从 FineWeb 里抽 32.6 亿训练 token + 1960 万验证 token,拼接、切段、存成张量格式。训练集约 13GB。
检查点机制:一跑就是两天,崩了不能重来。每个检查点要存模型权重、优化器状态、梯度缩放器状态和训练进度——一份就接近 2GB。每半小时存一次,磁盘是贵,但中断重跑更贵。
验证节奏:每 7020 步跑一次验证,单次验证吃 1960 万 token、约 5 分钟。占总时长的比例合理,但不能再频繁。
七、48 小时后,第一个结果出来了
连续跑了约 48 小时,验证损失停在 3.94。
跑个生成测试,prompt 是 "Every effort moves you":
- 未训练模型:"…ワISIS Keectar handling holistic Supply query…"——纯乱码;
- 本次训出来的模型:"…towards a sustainable and holistic diet of water, protein, vitamins, and protein"——语义通顺,但出现了小模型典型的重复(protein 说两遍);
- 原版 GPT-2 权重:"…as far as the hand can go until the end of your turn unless something interrupts your control flow…"——逻辑和想象力都明显高一档。
定量更扎心:同一个验证集上,原版 GPT-2 small 损失 3.50、困惑度约 33.1;本次模型损失 3.94、困惑度 51.4。差距肉眼可见。
八、"更干净的数据"反而更差?
第一个自然的念头是:换 FineWeb-Edu,"最有教育价值"的数据,模型是不是能更好?
于是又一个 48 小时跑起来。结果反直觉:
- 在 FineWeb-Edu 自己的验证集上,损失降到 3.693——看起来更好了;
- 但把它拿回最初的 FineWeb 验证集测,损失 4.16——反而显著更差。
后续用 Alpaca 格式数据做指令微调、再让 GPT-5.1 打分:FineWeb 版微调后 16.14 分,FineWeb-Edu 版只有 15.18。
"更干净"没有直接变成"更强"。合理的推测是:教育子集砍掉了大量真实世界的语料多样性,泛化能力反而被锁死了。
九、那再多训一倍呢?
在 FineWeb-Edu 版基础上,再追加 32.6 亿 token(总算到 65 亿):
- 验证损失 3.693 → 3.661,提升不到 1%;
- FineWeb 验证集 4.16 → 4.13;
- 指令微调评分 16.62,略好但有限。
双倍时间、双倍电费,没有换来质变。收益递减在 1.63 亿这个量级上非常早地就出现了。
十、跟原版差在哪
把自研模型和 OpenAI 原版权重逐项摆开,差距来源基本清楚:
- 数据量与轮次:原版约 4000 亿 token(几十 epoch),本次 32–65 亿(1–2 epoch)。深度"研磨"数据这件事,单卡做不到;
- 架构细节:原版保留了 QKV 偏置和权重绑定,本次按现代实践去掉了。这些"复古"设计在当年的训练动力学里可能有特殊价值;
- 训练技巧:梯度裁剪、更复杂的学习率调度(如余弦退火),本次没完全用上;
- batch size:原版全局 batch 512,单卡物理上只能到 6。更大的 batch 带来更稳的梯度方向;
- 精度:原版很可能全程 FP32,本次为了速度用了混合精度,数值稳定性上让了一步。
十一、这面镜子照出了什么
最初那个问题的答案是"是":单张 3090、两天时间、几十块电费,任何人都能从零训出一个有基本语言能力的 GPT-2 级模型。这件事在五年前不可想象。
但边界也同样清楚:
- Chinchilla 最优是一个高效的起点,不是终点;
- 要逼近工业级模型,需要的是指数级增长的数据、算力和工程打磨;
- 个人开发者能"学会炼丹",但很难"炼出工业级丹"。
最后那个模型会一本正经地搞错《傲慢与偏见》的作者。它是一面镜子:一边照出开源生态和消费硬件给个体的能力天花板已经被顶得很高,另一边照出从"能用"到"卓越"之间,那条仍然需要巨大投入才能跨过的沟。
对独立开发者来说,这个结论其实不亏——你不需要自己训出 GPT-5,你只需要知道这条沟在哪、知道哪些环节可以站在别人肩膀上、把自己的精力放在产品和玩法上。炼丹的故事听个响就好,真要发产品,还是得用现成的强模型。
(本文观点仅代表作者个人。)