GPU 服务器训练指南
执行状态一览
内容 状态 在 Apple M5(MPS)上做任务微调 已执行,见 训练记录 在 NVIDIA GPU 上做任务微调(第 1 节) 未执行。命令与本机相同,配置已提供 从零预训练 MiniMind 再做任务微调(第 2 节) 未执行。只提供命令和资源估算 扩大数据后的完整训练(第 3 节) 未执行。只提供估算方法 本文中所有未执行部分的耗时和费用都是估算,来源已逐项注明,不是本项目的实测结果。
1. 在 NVIDIA GPU 上复现任务微调
代码对设备没有特殊假设:device: auto 会依次选择 CUDA、MPS、CPU;在 CUDA 上自动启用 bfloat16 混合精度。
# 1) 取代码与上游
git clone <你的仓库地址> feedlens && cd feedlens
git clone https://github.com/jingyaogong/minimind.git third_party/minimind
git -C third_party/minimind checkout f659b55761b754d306bd140573493a6543cafd7f
# 2) 环境(按服务器的 CUDA 版本安装对应的 torch)
python -m venv .venv && source .venv/bin/activate
pip install torch --index-url https://download.pytorch.org/whl/cu124
pip install -r requirements.txt
# 3) 官方基础权重(各约 138MB),下载后核对校验和
mkdir -p weights/base && cd weights/base
for f in full_sft_768.pth pretrain_768.pth; do
curl -L -o $f https://www.modelscope.cn/models/gongjy/minimind-3-pytorch/resolve/master/$f
done
sha256sum *.pth
# 期望:
# 5b8c49f6c9d965092e651cafeeaeb8705558632b3fd4ac8ab319cbc5a3cbc4a0 full_sft_768.pth
# 0191958e7a96ef7cd1e443d379dc2ebea90cfea72cc4450fbcb4a7b87ff945f6 pretrain_768.pth
cd ../..
# 4) 数据 → 测试 → 训练 → 评测 → 打包
python -m feedlens.data.build --seed 42
python -m pytest tests -q
python -m feedlens.train --config configs/gpu_full.yaml
python -m feedlens.evaluate --systems all
python -m feedlens.package --run ft-full-gpu --system ft-full-gpu --name feedlens-minimind-gpu
configs/gpu_full.yaml 与本机配置的差别只有批大小和运行名。要评测它,在 eval/systems.yaml 里加一项指向 runs/ft-full-gpu/best.pth。
资源估算(未实测):模型 64M 参数、序列长度约 100 token。本机 MPS 上训练时显存占用约 9 GB(批大小 32,float32,见训练记录);在 CUDA 上启用混合精度后应当更低,任何 8 GB 以上显存的显卡都足够。本机完整跑一次是分钟级,GPU 上预计更快,但我没有测过,不给具体数字。
2. 从零训练的路线
本项目交付的模型是基于 MiniMind 官方权重微调得到的。如果想要一个权重完全由自己训练的版本,需要先用上游脚本从随机初始化开始做预训练和对话微调,再接上本项目的任务微调。
cd third_party/minimind
# 2.1 下载上游训练语料到 ./dataset(来自上游 README)
# pretrain_t2t_mini.jsonl 约 1.2GB,sft_t2t_mini.jsonl 约 1.6GB
pip install modelscope
modelscope download --dataset gongjy/minimind_dataset --local_dir ./dataset \
--include pretrain_t2t_mini.jsonl sft_t2t_mini.jsonl
# 2.2 预训练(随机初始化 → out/pretrain_768.pth)
cd trainer
python train_pretrain.py --epochs 1 --data_path ../dataset/pretrain_t2t_mini.jsonl
# 2.3 对话微调(pretrain → out/full_sft_768.pth)
python train_full_sft.py --epochs 2 --data_path ../dataset/sft_t2t_mini.jsonl --from_weight pretrain
# 2.4 中断后续训(上游自带)
python train_full_sft.py --from_resume 1
# 2.5 把自己训练的权重交给本项目做任务微调
cd ../../..
mkdir -p weights/scratch_base
cp third_party/minimind/out/full_sft_768.pth weights/scratch_base/full_sft_768.pth
python -m feedlens.train --config configs/full.yaml \
--set run_name=ft-full-own-base base_weights=weights/scratch_base/full_sft_768.pth
资源估算(来自上游 README 的经验值,非本项目实测)
| 阶段 | 数据 | 单张 RTX 3090 耗时 | 按 1.3 元/小时租卡的费用 |
|---|---|---|---|
| 预训练 1 轮 | pretrain_t2t_mini(1.2GB) |
约 1.21 小时 | 约 1.57 元 |
| 对话微调 1 轮 | sft_t2t_mini(1.6GB) |
约 1.10 小时 | 约 1.43 元 |
| 合计 | 约 2.3 小时 | 约 3 元 | |
| 任务微调 | 本项目 5146 条 | 未实测,预计分钟级 | 可忽略 |
上游说明这些是“经验估算值,用于快速感知训练门槛”。实际耗时取决于显卡型号、数据加载速度和是否使用混合精度。
为什么本项目没有走这条路
- 本机没有 NVIDIA 显卡。Apple MPS 上训练吞吐实测约 35 条/秒(序列长度约 100),而预训练语料有数百万条、序列长度 768,粗略外推需要数十小时以上。
- 对这个任务没有必要:官方权重已经提供了同样结构、同样分词器下的语言能力。
- 作为替代,本项目做了一个可以在本机完成的对照实验:同样的结构随机初始化、只用任务数据训练(
configs/scratch.yaml),用来量化预训练权重的贡献。结果见 评测报告。
注意:用上游语料自己训练出的基础权重,不会与官方发布的权重逐位相同,后续微调结果也会有差异。届时应当把它作为一个新的系统加入评测,而不是直接替换。
3. 扩大规模时的估算方法
如果拿到真实数据或把合成数据扩大一个量级,可以用本机实测吞吐来估算训练时间:
训练时间(秒) ≈ 样本数 × 轮数 ÷ 吞吐(条/秒)
| 场景 | 样本数 × 轮数 | 本机 MPS(按实测约 35 条/秒) |
|---|---|---|
| 当前(已执行) | 5146 × 3 | 约 7 分钟 |
| 数据扩大 10 倍(估算) | 51460 × 3 | 约 74 分钟 |
| 数据扩大 100 倍(估算) | 514600 × 3 | 约 12 小时,建议改用 GPU |
吞吐数字来自无其他任务干扰时的短测;正式训练时如果同时运行评测,速度会明显下降(本项目的第一次正式训练就因此变慢,见训练记录)。
4. 训练时的检查清单
| 检查 | 怎么看 |
|---|---|
| 数据确实被读到了 | 日志首行的 train=… val=… 与数据报告一致 |
| 损失正常下降且有限 | train_log.jsonl 中 loss 逐步下降;出现 NaN 时脚本会直接中止 |
| 参数确实在更新 | summary.json 的 params_updated 为 true,前后指纹不同 |
| 没有过拟合到无效 | 对比训练损失与验证损失;最优检查点的步数 |
| 权重能重新加载 | python -m feedlens.infer --weights runs/<run>/best.pth "测试文本" |
| 续训正确 | tests/test_pipeline.py::test_resume_is_bit_identical |
本页由 docs/12-gpu-training-guide.md 生成。