NanoChat:数据预训练SFT流程 | AI生成和翻译

首页 2026.07

这是完整的流程分解:


流程概览

prepare_data.sh  →  fineweb-code-sec-gpt.sh  →  sft_code_sec.sh
   (数据)                (预训练)                (SFT)

1. 数据管道 (prepare_data.sh)

来源(总计 32 亿 token):

来源 大小 内容
github-code 38 个分片,约 390 万文件 Python、Go、SQL、JS 等
fineweb-edu 8 个训练 + 1 个验证分片 约 43 亿 token CommonCrawl(已过滤)
sec-edgar 17 个 Parquet 文件 10-K 申报文本

分词器:在混合数据的 20 亿字符上训练的 BPE,词汇量 = 32768

数据划分:最后一个 fineweb 分片为验证集,其余全部为训练集。所有数据通过符号链接到 nanochat-mixed/


2. 预训练 (fineweb-code-sec-gpt.sh)

架构 (d12)

参数
层数 12
n_embd 768(深度 × 64)
注意力头数 6(n_kv_head=6,MHA)
词汇量 32,768
序列长度 2,048
窗口 L(滑动窗口,所有层)
总参数量 约 1.1 亿(嵌入层 2500 万 + 12 个块 × 700 万 + 最终层归一化)

脚本头部写着“286M”,但那是过时的估算——实际约为 1.1 亿(嵌入层 + 12 个变换器块,每个约 700 万 + 权重共享的语言模型头)。

训练配置

设置
步数 50,000
批次 65,536 token/步
设备批次 8(梯度累积 = 4)
总 token 数 50k × 65K = 32.8 亿
数据:参数比 29.8 倍(超过 Chinchilla 的 20 倍)
时长 在 RTX 4070 上约 16.5 小时
指标 val_bpb 约 1.418(凭记忆)

采样--sample-every=5000--save-every=5000--eval-every=2000


3. SFT (sft_code_sec.sh)

起点:在步数 50,000 处的预训练 d12 检查点

SFT 数据:SmolTalk(约 46 万通用聊天)+ 1000 个自定义代码/SEC 示例 + MMLU + GSM8K + SpellingBee

自定义 SFT 示例 (prepare_sft_data.py):14 个生成器,随机采样 1000 次:

SFT 配置

设置
步数 8,985(数据集耗尽,num_iterations=-1
批次 65,536 token/步
设备批次 4
学习率调度 cosine:init_lr_frac=0.8,warmdown_ratio=0.5,final_lr_frac=0.0
时长 184.7 分钟(约 3 小时)
评估 每 500 步
验证 bpb 0.4053(从第 7 步的 0.9536)

4. 推理结果解读

考虑到约 1.1 亿参数规模和 3 小时的 SFT 训练,再次审视结果:

提示 结果 分析
回文代码 通过 SFT 数据中有 3 个代码生成器具有类似模式。在代码分布中具有高概率延续性。
法国首都 通过 网络数据中极其常见的事实。小模型记住了高频 n-gram。
梯度下降 失败 约 1.1 亿参数无法存储概念级知识。只有高频事实幸存。
2+2 失败 算术需要激活中的工作记忆。此规模的 Transformer 无法维持状态。
斐波那契 失败 模式识别需要多步推理。
SQL 查询 (2023) 失败 SFT 的 SQL 示例使用了 ORDER BY ... LIMIT 模式,但模型未泛化到 YEAR(hire_date)
诗歌 重复 Softmax 头卡住。在此规模常见——需要在推理时使用重复惩罚。
平均速度 部分 结构化推理开始正确。模型知道数学解法的形式但丢失了一个数字。

结论:SFT 成功教会了聊天格式和代码模式。约 1.1 亿参数的上限是瓶颈——而非训练本身。对于计算预算(RTX 4070 上 3 小时 SFT),结果完全符合预期。


AI生成和翻译,但整理分享仍需精力。如果觉得有帮助,欢迎 捐助支持。 微信:@lzwjavaWeChat QR · X: @lzwjava · 打个招呼 👋

返回 捐助