Skip to content
Projects

philexohf/gleamlm has 67 GitHub stars and 10 forks. GitHot measured 0 stars in 24 hours. Last checked 2026-11-15 06:06 UTC. Last push 2026-09-18.

How these counts are measured

Measured star growth

in 24h
0
in 7 days
Collecting history
in 15 days
Collecting history
in 1 month
Collecting history

Net star changes over overlapping periods, not daily totals. Missing measurements are left blank. Stars measure attention, not software quality.

About

GleamLM大语言模型全栈训练平台——核心代码用 PyTorch 从零实现,最低仅需 12GB 消费级显卡即可完整训练,另有一套工业代码与手写实现消费同一份数据逐层对照。模型训练支持CLI和可视化训练。

AI

README.md

Original

GleamLM —— 大语言模型全栈训练平台

GleamLM 是一套从零实现的 LLM 工程实践项目,覆盖数据管道、BBPE 分词器、模型架构、预训练与后训练,以及推理服务全流程。平台采用双轨设计,手写轨基于 PyTorch 从零实现核心算法,工业轨兼容 Hugging Face 生态,对接 Megatron、TRL、PEFT、DeepSpeed 等框架,推理与服务侧支持 vLLM 部署。它们消费同一份数据,训练方式可逐层对照,并配备可视化训练控制台。项目专注 可解释、可复现和可落地,帮助开发者打通完整的 LLM 工程链路。

能力覆盖

  • 数据管道:多源数据、粗去重、文本清洗、SimHash/MinHash 精细去重和字符级配比均衡;
  • 分词系统:纯 Python 自研 BBPE 分词器,支持按 manual/configs/*.yaml 配比从零训练(词频聚合内存优化,200M 字符仅 ~1.2GB)、编码解码与 HF 格式导出;
  • 模型架构:Decoder-only,原生实现 SwiGLU FFN、GQA、RoPE、QK-Norm 和 Mamba 等结构;
  • 预训练体系:AMP 混合精度(BF16 免 scaler)、DDP 分布式训练、wd 分组(embedding+norm 去 wd)、WSD 调度(decay 可线性)、确定性采样 + consumed_train_samples 精确断点续训,以及稳定收敛调优方案;
  • 后训练对齐:SFT、DPO、PPO、GRPO 和 OPD 全流程,以及 LoRA 微调;
  • 推理部署:KV Cache 流式推理、模型量化、ONNX 导出、vLLM 高性能部署,以及 API 服务化;
  • 模型评测:基于 lm-evaluation-harness 官方框架评测 CEVAL、CMMLU、MMLU 等主流中文/英文能力;安装:pip install -e ".[eval]"。
  • 可视化训练控制台:浏览器里起训与管理实验 —— 任务卡一键启动各阶段、实时 loss / lr 曲线与训练日志、实验历史管理,可加载 checkpoint 直接对话。

项目定位

GleamLM 面向大语言模型预训练与后训练工程师,目标是理解原理和工业实战。

项目解决三个问题:

1. 核心代码如何实现

搞懂 GQA 的 KV Head 怎么复用、QK-Norm 为什么是标配、RoPE 外推怎么做。训练出问题时(loss spike、梯度异常),能定位原因而不是只会调参。

2. 工业框架如何使用

掌握标准工业框架的使用:Megatron做预训练、TRL 做 DPO/GRPO、PEFT 做 LoRA、vLLM 做部署。对接工业界实际使用的工具链,直接进团队协作流程。

3. 预训练和后训练的完整链路

完整走一遍数据筛选、清洗去重、预训练、指令微调、强化对齐、模型量化和服务上线的完整链路。每一步做了什么、为什么这样做,心里有数。

项目采用双轨设计:

manual 手写轨

核心算法、模型结构、训练逻辑全部从零实现。目的是理解技术细节,出问题知道怎么修。

industrial 工业轨

基于 Megatron、TRL、PEFT、DeepSpeed 等框架实现,对接工业界实际使用的工具链。目的是能用标准工具干活,适应团队协作流程。

两轨消费同一份 .bin/.idx 数据,可逐层对照 —— 原理和工程能力都有。


GleamLM 模型架构

组件 实现方式 选型理由
范式 Decoder-only(对标 LLaMA 3 / Qwen3) 当前主流
归一化 Pre-Norm + RMSNorm 训练稳定,Post-Norm 已淘汰
位置编码 RoPE + YaRN 外推 当前主流
注意力 GQA + QK-Norm + KV Cache 2024-2025 标配
注意力变体 NoPE / ALiBi / Sliding Window 理解不同设计选择的代价
激活函数 SwiGLU(FFN) 替代 ReLU 的现代选择
MoE Router + Top-K + aux_loss 稀疏激活,Mixtral 同款
状态空间 Mamba-1 实现 SSM vs Attention 基础知识

验证状态说明:上表中的 注意力变体(NoPE / ALiBi / Sliding Window)、MoE、
状态空间(Mamba-1)为教学实现——代码与单测齐全(可通过 attn_registry / ffn_registry
切换启用),但成品配置(nano / lite / pro / 0.6b)均未启用,属长期实验方向。

模型规格

参数 Nano ~40M Lite ~87M Pro ~126M 0.6B
层数 12 12 18 37
维度 512 768 768 1024
词表 12,002 12,002 12,002 24,002
查询头 / KV 头 8 / 4 12 / 6 12 / 6 16 / 8
数据量 4.47B tokens 4.47B tokens — —
显存需求 单卡 12GB 单卡 12GB 单卡 16GB+ 多卡

Lite 设计原则:测试证实 12 层是中文生成的阈值,且事实知识全部存于 FFN。因此保持 12 层不动,d_model 扩至 768,d_ff 按 SwiGLU 标准公式扩至 2048(3.4× FFN 容量),词表复用 Nano 的 12K。


技术栈与选型

组件 实现方式 选型理由
训练精度 BF16/FP16 AMP(BF16 免 scaler,FP16 才启用) 混合精度训练
分布式 DDP + FSDP + DeepSpeed 三种策略对比
分词器 BBPE 12K(纯 Python 自研) 理解词表构建全流程
推理加速 KV Cache + 流式生成 + Flash Attention 推理延迟优化
对齐 SFT → 对齐(DPO / PPO / GRPO 并列可选)→ OPD(可选) 完整后训练链条
LoRA(可选) 手写 + PEFT 双版本 理解低秩适应的数学原理
HF 集成 from_pretrained / GleamLMForCausalLM 自定义模型接入标准姿势
部署 vLLM + ONNX + FastAPI 模型上线全链路

验证状态说明:分布式(FSDP / DeepSpeed)与 Megatron 工业轨已完成冒烟验证;
全量训练验证目前只在单卡路径上完成,多卡全量训练尚未验证。
另:推测解码(gleamlm/inference/speculative.py)亦为独立教学实现,当前未接入推理链路。


作为库使用(PyPI)

核心组件(附录中 gleamlm/ 目录)已发布到 PyPI,可按库安装用于自有项目或二次开发:

pip install gleamlm

安装后包内自带 BBPE 12K 成品词表,无需下载、开箱即用;模型推理需自备 checkpoint(按下文「快速开始」训练得到,或任一同构产物):

from gleamlm.api import GleamLM

# 从训练 checkpoint 加载模型 + 词表(device="auto" 自动选 CUDA/CPU)
llm = GleamLM.from_checkpoint("checkpoints/nano/final.pt")
print(llm.generate("量子纠缠的本质是", max_new_tokens=128))

也可只消费组件(分词器 / 模型 / 数据 / 训练):

from gleamlm.tokenizer import BBPETokenizer
from gleamlm.utils.config import DEFAULT_TOKENIZER_PATH

tok = BBPETokenizer.load(DEFAULT_TOKENIZER_PATH)   # 包内自带词表
print(tok.decode(tok.encode("你好, 世界", add_bos=True)))

仓库其余目录(manual/ 训练脚本、industrial/ 工业轨、hf/ HF 生态桥)不在 PyPI 包内;
PyPI 包仅含核心库层,完整接口文档完善后提供。


快速开始

环境

  • Python 3.10+
  • PyTorch 2.5+ with CUDA 12.4
  • NVIDIA GPU 12GB显存+
pip install -e ".[train,dev]"

图形界面:WebUI(可选,最快上手)

与下方命令行流程是并行的两条路:面板不重实现训练,它用 subprocess 拉起同一批脚本(manual/pretrain.py、sft.py、dpo.py、opd.py、sft_lora.py、grpo.py、ppo.py)与同一套 manual/configs/*.yaml,两条路覆盖同一批阶段(数据 → 预训练 → 后训练 → 推理),可混用。

WebUI 是浏览器里的图形化训练控制台:预训练 / SFT / DPO 数据生成 / DPO / OPD / GRPO / PPO / LoRA 各阶段任务卡一键启动,实时 loss / lr 曲线与训练日志、实验历史管理;推理 tab 加载 checkpoint 即可对话。

# ① 安装依赖(FastAPI + uvicorn + transformers)
pip install -e ".[serve]"

# ② 启动(默认 http://127.0.0.1:8080)
python webui/main.py

浏览器打开 http://127.0.0.1:8080。常用参数:--port 改端口、--model <checkpoint> 启动即加载推理模型、--no-train 仅保留推理(部署场景)。训练任务需先完成 §0 数据准备;已有后训练产物(如 checkpoints/nano/sft/sft_best.pt)可直接在推理 tab 加载对话。

关闭面板不会停止训练:面板与训练进程分离(面板是遥控器,训练在独立子进程中运行)——关闭或强杀 WebUI 后训练仍在后台继续;重新启动面板时会自动接管仍在运行的训练,状态行标注「重启前启动」,日志回放、实时曲线与停止按钮照常可用。

0. 数据准备

  • 预处理数据已上传 ModelScope:LLM-Pretrain-Data。
  • 复现训练可直接下载该数据集,无需重复执行数据管线。数据下载后,预训练数据(train/val/test)放入本地 data/nano/pretrain 文件夹。
# ① 下载原始数据(仅首次,生成 data/raw/{edu,wiki}_raw.txt)
pip install datasets
python data_tools/download_data.py --sources fineweb wiki

# ② 一键管道:6 阶段标准管线(粗去重 → 清洗 → 质量 → 细去重 → 切分 → 打包)
#    --variant nano 自动读取 nano.yaml 的 data_sources 配比(55/27/12/6)与
#    max_train_chars 字符预算(6.13B),train/valid/test.bin/.idx 输出到
#    data/nano/pretrain(打包用内置 bbpe_12k);中间产物 {name}_dedup.txt
#    落盘 data/raw/(③ 训练分词器的输入)。每阶段产物存在即跳过,可断点续跑。
python data_tools/pretrain/run_pipeline.py --variant nano

# ③ 可选:基于 ② 的 data/raw/{name}_dedup.txt 训练自己的 BBPE 分词器
#    (按 manual/configs/{variant}.yaml 的 data_sources 配比,默认 200M 字符预算)。
#    注意:新词表不会自动参与 ② 已打包的 .bin/.idx —— 需删除旧产物(或换
#    --output-prefix)后重跑 ②,并追加 --tokenizer-path <新词表目录>。
python manual/train_tokenizer.py --variant nano \
    --vocab_size 12002 \
    --save_dir gleamlm/tokenizer/checkpoints/bbpe_12k \
    --max_chars 200000000

# 指定源和配比(不带 --variant 时输出到 data/processed)
python data_tools/pretrain/run_pipeline.py \
    --sources wiki baike edu \
    --ratios wiki:0.4,baike:0.3,edu:0.3 \
    --max-chars 6130000000

0.5 冒烟验收:先跑通,再训全量

数据备好之后(见上),不必等完整训练即可确认代码链路正常:

# Level 1 冒烟测试(~30s):跑通前向/反向,确认 loss 在下降
python tools/quick_run.py --level 1 --variant nano

# Level 2 小规模(~5min):看模型是否开始学、生成是否出现语义
python tools/quick_run.py --level 2 --variant nano

脚本会从 data/nano/pretrain/{train,valid}.txt 取前若干行做小样本,产物落在
data/smoke_splits/ 与 checkpoints_smoke/,不污染正式数据与 checkpoint。
缺少数据文件时会跳过该步并失败——所以要先执行上一节。
三级阶梯的判定标准见 tools/quick_run.py 头部 docstring。

注意:该脚本默认用 conda run -n dl2llm 执行子命令;该环境不存在时会自动回退到
当前解释器并打印提示,因此他人 clone 后可直接运行。也可显式指定 --conda_env <环境名>,
或用 --conda_env "" 完全不用 conda。

1. 预训练

# 单卡(Nano 40M 入门)
# --data 传 .bin/.idx 前缀(推荐:§0 ModelScope 产物 data/nano/pretrain/train);
# 也可传 .txt 路径/目录(小数据示例,文件需自行准备)
python manual/pretrain.py --model manual/configs/nano.yaml --data data/nano/pretrain/train

# 多卡 DDP(Lite 87M,4 卡;数据用 §0 同管线 --variant lite 的产物)
torchrun --nproc_per_node=4 manual/pretrain.py \
    --model manual/configs/lite.yaml --data data/lite/pretrain/train --output_dir ./checkpoints

训练监控(wandb / TensorBoard,可选):manual/pretrain.py 内置 wandb 与 TensorBoard 两条相互独立的日志链路,未装/未开其一不影响另一条,也可同时启用:

日志 启用方式 记录内容 查看方式
wandb 安装 wandb 即自动启用;可选 --wandb_project / --wandb_run_name 覆盖默认 project(gleamlm)与 run 名 train loss / lr / tok/s / GPU 显存 + val loss/ppl wandb 网页
TensorBoard 训练命令加 --tensorboard(无需 wandb) Train/Loss、Train/LR、Train/TokPerSec + Eval/Loss、Eval/Perplexity,事件写入 <output_dir>/runs/ tensorboard --logdir <output_dir>/runs
# 仅 TensorBoard(本地可视化,无需安装 wandb)
python manual/pretrain.py --model manual/configs/nano.yaml --data data/nano/pretrain/train --tensorboard
tensorboard --logdir ./checkpoints/runs

# 仅 wandb(需 pip install wandb 且已登录)
python manual/pretrain.py --model manual/configs/nano.yaml --data data/nano/pretrain/train \
    --wandb_project gleamlm --wandb_run_name nano_pretrain

# 两者同时启用(各记各的,互不影响)
python manual/pretrain.py --model manual/configs/nano.yaml --data data/nano/pretrain/train \
    --tensorboard --wandb_project gleamlm

wandb API key 注入:首次使用需先在 wandb.ai/authorize 生成 API key。客户端按「环境变量 WANDB_API_KEY → ~/.netrc → 交互输入」顺序读取凭据,任选一种方式即可:

# ① 交互式登录(推荐,个人本机):key 写入 ~/.netrc,之后自动生效
wandb login                 # conda 环境找不到命令时改用: python -m wandb login

# ② 直接带 key 登录(同 ①,免交互)
wandb login <你的API_KEY>

# ③ 环境变量 —— Linux/macOS(临时 / 永久写入 ~/.bashrc)
export WANDB_API_KEY=<你的API_KEY>
echo 'export WANDB_API_KEY=<你的API_KEY>' >> ~/.bashrc && source ~/.bashrc
# ④ 环境变量 —— Windows PowerShell(临时 / 永久用户级,新终端生效)
$env:WANDB_API_KEY = "<你的API_KEY>"
[Environment]::SetEnvironmentVariable("WANDB_API_KEY", "<你的API_KEY>", "User")

验证:echo $env:WANDB_API_KEY(PowerShell)或 echo $WANDB_API_KEY(bash)能打印出 key 即成功。API key 等同密码,勿写入代码或提交仓库;个人本机推荐 ①②,环境变量注入适合 CI / 服务器等非交互场景。

说明:手写轨 manual/pretrain.py 支持以上两者;Megatron 工业轨 industrial/pretrain.py 仅支持 wandb(装即启用,无 TensorBoard)。若已安装 wandb 但暂不想记录,可用环境变量 WANDB_MODE=disabled 一键禁用(无需卸载)。

2. SFT 指令微调

# 全量微调(--model_path 指定预训练基座;缺省会找不存在的 checkpoints/nano/best_model.pt)
python manual/sft.py --variant nano --model_path checkpoints/nano/final.pt

# LoRA 微调 —— 可选路线(手写实现,基座用预训练模型),非主链必需
python manual/sft_lora.py --variant nano \
    --model checkpoints/nano/final.pt \
    --output_dir checkpoints/nano/lora
# 数据与超参默认取 nano.yaml 的 lora 段(data/nano/sft/sft_mix.jsonl,lr 2e-4,r 8 / alpha 16),CLI 同名参数可覆写

LoRA 微调(sft_lora.py)为可选实验路线(低成本尝鲜 / 理解低秩适应原理),不构成后训练主链步骤;
主链为 SFT 全量微调 → DPO(→ OPD 可选),下游 DPO / 推理默认消费全量微调产物 sft_best.pt。

3. DPO 偏好对齐

python manual/dpo.py --variant nano --model_path checkpoints/nano/sft/sft_best.pt

DPO 用偏好对做离线对齐,路线(SFT → DPO),对 40M 规模已构成完整后训练链,PPO / GRPO 可跳过。

PPO / GRPO 强化对齐(可选步骤,与 DPO 并列)

与 DPO 并列的后训练对齐方式,从 SFT 产物出发(SFT → PPO/GRPO),按需选择其一,
PPO / GRPO 均需规则/奖励信号:GRPO 无 value network(组内归一化优势),PPO 有 value network(clip + GAE)。
需自行准备数据data/rlhf.jsonl(每行{"prompt": ..., "ground_truth": ...})。

# GRPO(无 value network,DeepSeek 风格)
python manual/grpo.py \
    --model checkpoints/nano/sft/sft_best.pt \
    --data data/rlhf.jsonl \
    --output_dir checkpoints/nano/grpo

# PPO(value network + clip + GAE,经典 RLHF)
python manual/ppo.py \
    --model checkpoints/nano/sft/sft_best.pt \
    --data data/rlhf.jsonl \
    --output_dir checkpoints/nano/ppo

4. OPD 在线策略蒸馏

消费 DPO 产物,学生采样 → 教师对 prompt+completion 打分 → 序列级 reverse KL。

# 教师:本地 HF 模型,如 Qwen3-0.6B,下载的教师模型放在checkpoints目录下
# 教师加载需 transformers,先执行 pip install -e ".[hf]"
python manual/opd.py --variant nano \
    --model checkpoints/nano/dpo/dpo_best.pt \
    --output_dir checkpoints/nano/opd \
    --teacher_model_path checkpoints/Qwen3-0.6B
# 数据与超参默认取 nano.yaml 的 opd 段:data/nano/opd_prompts.jsonl、lr 5e-6、batch 2、T=1.0、n_samples=2、entropy_coeff 0.01(80 步)

ChatML 帧对齐(THUNLP OPD 论文 §5.2):data/nano/opd_prompts.jsonl 存裸 user 输入,
训练时内部套成 <|im_start|>user…<|im_end|>\n<|im_start|>assistant\n 再喂给学生与
教师。学生 SFT 与 Qwen 教师均在 ChatML 下训练,裸文本 rollout 使师生双双 OOD
(教师对每条续写恒定"惊讶",log_pi_T 系统性偏低,优势失真)。BBPE 与 Qwen 的
<|im_start|>/<|im_end|> 标签文本一致,同一字符串在两边编码为各自的 special id,
序列级跨 tokenizer 精确性不受影响。

5. 推理

# 交互式推理(对话模式可以用 SFT、DPO和OPD等后训练模型)
python manual/infer.py --model checkpoints/nano/sft/sft_best.pt --sft

# 网页模式,OpenAI 兼容 API 服务(依赖在 serve extra:先执行 pip install -e ".[serve]")
python serve/api.py --model checkpoints/nano/dpo/dpo_best.pt --port 8000

服务启动后,浏览器直接打开 http://localhost:8000 即可使用网页聊天界面(纯前端,无需额外安装):

  • 多轮对话:自动携带最近 6 轮上下文;模型上下文仅 512 长,对话过长请点右上角「清空对话」
  • 温度滑杆(0.11.5,默认 0.8):小模型答非所问/胡话时调低到 0.50.6 可明显改善稳定性
  • 调试与健康检查:/docs(OpenAPI 交互页)、/health;接口兼容 OpenAI 格式:/v1/chat/completions、/v1/completions
  • 聊天请使用 SFT/DPO/OPD 等后训练产物;裸预训练模型只会文本续写,不适合对话

6. 代码测试

pytest tests/ -v

训练数据

GleamLM-Nano / Lite 四源配比

Nano 与 Lite 同为四源(含 Chinese FineWeb Edu 的 edu 源),edu 55% 主导;news/wiki/baike 为稀缺高价值源,按"全量吃满"取用(其实际占比由各自可用字符量决定):

数据源 字符配比 行均字符
Chinese FineWeb Edu (edu) 55% —
中文新闻 (news) 27% ~752
中文维基 (wiki) 12% ~123
百度百科 (baike) 6% ~145

Nano 实际训练数据 4.47B tokens(train 文本 ≈4.6B 字符;train+valid+test ≈5.2B 字符),训练 1 epoch。
配比由 python data_tools/pretrain/run_pipeline.py --variant nano 按字符占比做 Bernoulli 采样混合(news/wiki/baike 稀缺源全量吃满)。
Lite 数据文件与 Nano 共用,由 python data_tools/pretrain/run_pipeline.py --variant lite 生成。


训练与验证结果

五组 run 的产物、规模与验证口径 —— 数字供复现对照用;跨 run 并列前先看下面这段口径。

口径说明(train/val 不可同框直接取 exp)

  • train loss 含 label_smoothing 项:平滑 CE = (1−ε)·CE + ε·AU,AU 为对全词表均匀分布的平均损失(≥ ln(12002) ≈ 9.4);ε=0.1 时报告值被抬高约 1.0 —— 不要对 train loss 直接取 exp 当 PPL。
  • 验证(周期验证 + 训练后全量验证)走裸 CrossEntropyLoss(无 LS、无 z-loss),可直接取 exp。
  • 所以 loss 图上 train(~3.5,含 LS)与 val(~2.5,裸 CE)约 1.0 的固定落差是口径差,不是过拟合;Nano 的 train final 2.4850 与 val 2.5044 才是同口径可比,差 0.019 是真实泛化 gap。
  • 周期验证是训练内嵌快测(webui 启动时填「验证数据」,每 eval_interval 步自动测;max_val_batches: 200 采样上限 ≈1.6M token(Nano)/ 0.8M(Lite),null = 全量),与训练后独立全量验证共用同一裸 CE 计算,但测量协议不同,跨 run 不可直接并列。

GleamLM-Nano 预训练

配置:40.8M / 12L×512d / GQA(8Q/4KV) / SwiGLU(d_ff=1365) / BBPE 12K(基于四源语料重新训练)/ tie_weights / WSD linear decay / label_smoothing 0.1 / z-loss / torch.compile(mode=default)

项目 值
训练数据 4.47B tokens(四源配比,新 bbpe_12k 重新打包)
有效 batch 64 seqs × 1024(micro 8 × accumulate 8)
训练步数 68,108 step(epoch 1)
训练时长 890.9 min(14.8 hr,单卡 RTX 4070 Ti)
平均吞吐 ~760k tok/s(torch.compile)
train final loss 2.4850(PPL ≈ 12.0)
学习率调度 WSD linear:warmup 2% → stable 80% → linear decay 18%,4e-4 → 4e-5

训练曲线(WSD 三段式:warmup 2% 升温 → stable 80% 恒定 → linear decay 18% 收尾)与 Loss 收敛(step 68108,最终 2.4850):

全量验证(valid 248.3M tokens,全量遍历 30,310 batches)

指标 值
val loss 2.5044
val ppl 12.24
train/val loss 差 0.019(无过拟合)

GleamLM-Nano SFT 指令微调(后训练基线)

项目 值
基座 预训练 final.pt(step 68108)
数据 13,413 条/epoch = 基础 3,415(模板/API 蒸馏/多轮,dedup 清洗后)+ QA→SFT 10,000(知乎知识问答,占 74.5%,均值 197.7 字)
配置 ChatML;loss mask 仅 assistant;lr 1e-4 cosine;3 epochs;batch 8 × accum 4;seq 512
SFT final loss 2.6283(预训练 2.485 → SFT 2.628)

数据零重复、74.5% 为知乎长答,loss 仅比预训练 val 2.5044 高约 0.12,属合理水平。训练集 data/nano/sft/sft_mix.jsonl(data_tools/sft/mix_sft.py 混合基础集与 qa_sft.jsonl;QA 源 20,000 条由 data_tools/sft/qa_to_sft.py 从 qa_dedup 语料规则抽取)。本次 run 用 3 epochs;nano.yaml 的 sft 模板默认已于 2026-09-17 由 3 调为 2。

结论:数据清洗训练达成核心目标;幻觉 / 闲聊 / 算术仍受 40M 容量边界限制。

GleamLM-Nano DPO 偏好对齐

项目 值
基座 SFT sft_best.pt(policy + frozen ref)
数据 1,930 对 chosen/rejected = 闲聊 169 + 单轮知识 1,000 + 多轮对话 761
配置 lr 1e-6 cosine;1 epoch;beta 0.3;batch 2 × accum 2
DPO loss 0.3953(beta 0.3,初始 ln2≈0.693 温和下降)

数据链路:build_dpo_chosen.py 抽 chosen 池 → generate_rejected.py(当前 SFT 模型在 temp 0.95 下自生成 rejected,保证落在 policy 分布内,4 分片并行)→ merge_dpo_data.py 合并清洗 → data/nano/dpo/dpo_data.jsonl;多轮样本的 messages 只含对话历史。

beta 调参:beta 0.1 的 KL 约束在 40M 上偏弱,单次采样即见输出漂移;调至 0.3 后 7 题 × 4 采样 A/B 对比 SFT 基座无退化亦无显著提升,定稿。loss 初始恒为 ln2≈0.693 且随 beta 放大而变小(真实偏好 margin 两版相近 ≈2.5),不可只凭 loss 跨 beta 比较。

结论:后训练链路(预训练 → SFT → DPO)的完整性演示;40M 容量钉死生成能力上限,偏好优化学到排序但难以转化为更优输出。

GleamLM-Nano OPD 在线策略蒸馏

原理:学生自己 rollout(on-policy)→ 本地 HF 教师(Qwen3-0.6B)对轨迹打分 → 序列级 reverse KL 更新。相比 DPO(偏好对)与 RL(稀疏奖励),OPD 每 token 都有教师监督,且自采样消除 exposure bias。

项目 值
基座 DPO dpo_best.pt(beta 0.3)
教师 Qwen3-0.6B(本地 HF,打分 ~0.03s/次)
数据 40 条通用闲聊/知识 prompt × 4 epochs(80 步)
配置 T=1.0;n_samples=2(组内 LOO baseline);batch 2;lr 5e-6;entropy_coeff 0.01
产物 checkpoints/nano/opd/opd_final.pt

关键设计 —— ChatML 帧对齐(THUNLP OPD 论文):数据存裸 user 输入,训练时套成 <|im_start|>user…<|im_end|>\n<|im_start|>assistant\n 再喂给学生与教师。学生 SFT 与 Qwen 教师都在 ChatML 下训练,裸文本 rollout 会让师生双双 OOD(教师对每条续写恒定「惊讶」,log_pi_T 系统性偏低、优势失真);同帧后两边各回各自训练分布。BBPE 与 Qwen 的 <|im_start|> / <|im_end|> 标签文本一致,同一字符串在两边编码为各自的 special id,序列级跨 tokenizer 精确性不受影响。

结论:A/B(8 题 × 3 采样,与 DPO 基座对比)无退化;身份类 / 事实细节仍受 40M 容量边界限制(与 SFT / DPO 同边界)。

GleamLM-Lite 预训练

配置:87.1M / 12L×768d / GQA(12Q/6KV) / SwiGLU(d_ff=2048) / BBPE 12K(与 Nano 共用)/ tie_weights / WSD linear decay / label_smoothing 0.1 / z-loss

项目 值
训练数据 ≈4.46B tokens(与 Nano 同源四源配比,单轮遍历)
有效 batch 64 seqs × 2048(micro 2 × accumulate 32)
训练步数 34,054 step(epoch 0 完成)
训练时长 2,187.2 min(36.5 hr,单卡 RTX 4070 Ti)
train final loss 3.1952(含 label_smoothing)
学习率调度 WSD linear:warmup 2% → stable 80% → linear decay 18%,4e-4 → 4e-5
周期验证最优 val loss 2.4720 / ppl 11.85(step 34,000)

实际训练配置为 manual/my_configs/lite_model.yaml:仓库版 manual/configs/lite.yaml 微批为 4 × 16,本次为省显存调整为 2 × 32,有效 batch 64 不变;口径同 Nano 段(见节首)。训练曲线图与 Lite 全量验证(与 Nano 同口径)待补。


版本路线

版本 参数量 定位 状态
GleamLM-Nano ~40M 单卡 12GB 完整训练 ✅ 已完成
GleamLM-Lite ~87M FFN 3.4× 扩容 ✅ 预训练完成(2026-09-11,step 34,054 / epoch 0 完成);训练曲线与全量验证待补
GleamLM-Pro ~126M 18L×768d / BBPE 12K 开发中
GleamLM-0.6B ~0.6B 工业级验证 / 37L×1024d / BBPE 24K 跨字合并 规划中


与工业预训练实践对齐

手工代码训练持续对齐开源工业实践(以 megatron-core 为基准):

  • Weight decay 分组:embedding + norm 去 wd,矩阵权重正常衰减(Megatron 跳过 1-D 参数)
  • WSD 调度:decay 段支持线性衰减,min_lr_ratio=0 线性降到 0
  • Z-Loss 默认 1e-5:防 logits 爆炸
  • 确定性采样 + 精确断点续训:统一 DistributedSampler(seed),checkpoint 持久化 consumed_train_samples 全局样本计数(与 DP 解耦),恢复逐位续上(对齐 nanotron 确定性契约)
  • BF16 免 GradScaler:仅 FP16 启用 scaler,BF16 无 underflow

数据格式与数据类:与 Megatron 逐层对齐(手写轨数据可直接进工业轨)

预训练数据统一为 Megatron 标准 .bin/.idx,手写轨与工业轨消费同一份数据:

层级 项目实现 Megatron 对应 对齐
token 数据层 .bin:uint16 token 连续流 IndexedDataset 的 .bin 字节一致
索引层 .idx:34B header + int32 sizes + int64 pointers + int64 doc_idx _IndexWriter 布局 完全兼容
数据类 工业轨用官方 GPTDataset + BlendedMegatronDatasetBuilder(含跨文档滑窗、eod_mask_loss、position_ids);hf/hf_megatron_tokenizer.py 将 BBPE 适配为 MegatronTokenizerBase pretrain_gpt.py 主路径 官方类一致
滑窗语义层 手写轨 IndexedMMapDataset 跨文档滑窗 GPTDataset._build_document_sample_shuffle_indices 语义一致

效果:一份 .bin/.idx 数据可被 manual/pretrain.py(手写 IndexedMMapDataset)、industrial/pretrain.py(官方 GPTDataset + megatron IndexedDataset)直接消费;DeepSpeed 的 MMapIndexedDataset 与 Megatron 字节兼容,零转换可用。格式契约由 tests/test_dataset.py::TestMegatronCompat 防回归。

工业预训练脚本的参数 / WSD / 累积 / 断点续训 / EOD 约定见代码配置;工业 checkpoint → HF 产物用 tools/convert_megatron_to_hf.py(含 --verify 等价性校验)。

后训练数据格式:对齐 TRL 工业标准(messages / role-content)

工业后训练(SFT/DPO/GRPO)以 TRL 为事实标准,数据存 role/content 数组、不预渲染 ChatML,由 tokenizer 的 chat template 运行时拼装:

阶段 工业标准字段 项目实现
SFT {"messages": [user, assistant]} 或 {"prompt":[...], "completion":[...]},completion_only_loss=True(只算回答) industrial/sft.py 自动识别 messages → completion-only loss;兼容旧 {"text"} 纯文本
DPO {"prompt":[user], "chosen":[assistant A], "rejected":[assistant B]} industrial/dpo.py(TRL 自动 chat template 渲染)
GRPO/PPO {"prompt": ..., "ground_truth": ...} + 规则 reward_funcs industrial/{grpo,ppo}.py 的 default_reward 支持 ground_truth 精确匹配

tokenizer 导出已含 ChatML chat template(export_to_hf_format → tokenizer_config.json),messages 数据训练时自动渲染,保留 prompt/completion 边界以支持 completion-only loss。

OPD 教师:本地 HF 模型

OPD(On-Policy Distillation)需要教师对 prompt + completion 求序列级 log π_T(y)。本地 HF 因果模型(AutoModelForCausalLM,如 Qwen3-0.6B)经 transformers 直接加载,log_softmax 逐 token 求和可对任意文本打分,打分 ~0.03s/次。运行命令见上文「4. OPD 在线策略蒸馏」。

序列级 reverse KL 语义跨 tokenizer 可比:教师 tokenizer ≠ 学生 BBPE,但整条文本的 logprob 求和与切分无关。产物 opd_final.pt 与 DPO checkpoint 结构同构,可直接复用 deploy/manual_to_qwen3.py 转 HF Qwen3 格式 → vLLM 部署(转换只依赖 model_state_dict + _config,与训练方法无关)。


附录:项目结构

GleamLM/
├── gleamlm/                       # 核心库:完整学习路径(数据 → 模型 → 训练 → 推理)
│   ├── tokenizer/                 # ① BBPE 分词器(训练/编码/解码/HF 导出;checkpoints/bbpe_12k 为成品词表)
│   ├── data/                      # ② 数据层:管线编排 + 各阶段数据集
│   │   ├── pipeline.py            #   预训练 6 阶段管线(粗去重→清洗→质量→细去重→切分→打包)
│   │   ├── pack.py / dataset.py   #   文本 → Megatron .bin/.idx 打包 / mmap 懒加载数据类
│   │   ├── sft_data.py / dpo_data.py / rl_data.py  # 后训练数据集(SFT JSONL / DPO 偏好对 / RL prompt)
│   │   └── preprocess.py          #   文件流式预处理引擎(各变体共用)
│   ├── models/                    # ③ 模型架构
│   │   ├── model.py               #   GleamLMModel(GQA / RoPE / SwiGLU / MoE / QK-Norm)
│   │   ├── attention_variants.py  #   NoPE / ALiBi / Sliding Window GQA
│   │   └── mamba_hybrid.py        #   Mamba-1 教学块 + Mamba×GQA 块级混合解码器
│   ├── trainer/                   # ④ 训练支撑
│   │   ├── base_trainer.py        #   预训练原子原语(optimizer_step / GradScaler)
│   │   ├── rl_trainer.py          #   PPO / GRPO 训练支撑 + 共享奖励函数
│   │   ├── dpo_loss.py / distill_loss.py  # DPO / 蒸馏 loss(独立可测)
│   │   ├── schedulers.py          #   WSD / cosine 等 LR 调度
│   │   └── lora.py                #   LoRA 从零实现
│   ├── inference/                 # ⑤ 推理与生成
│   │   ├── generator.py           #   自回归生成核心(KV Cache + 采样循环)
│   │   ├── generate.py            #   共享生成工具(评估 / 数据生成复用)
│   │   ├── streamer.py / speculative.py  # 流式输出 / 推测解码
│   │   ├── conversation.py        #   多轮对话管理(KV cache 复用)
│   │   └── cli.py                 #   统一推理 CLI
│   ├── rag/                       # ⑥ RAG 检索增强(BM25 + Dense 双路)
│   ├── utils/                     # ⑦ 工具集(config / AMP / ChatML)
│   ├── evaluation/                # ⑧ 评测(PPL 基础指标;标准 benchmark 见 eval/)
│   └── api.py / types.py          #   推理便捷入口 / 共享类型
│
├── manual/                        # 手写轨:完整实现细节
│   ├── pretrain.py                #   预训练(AMP / DDP / 断点续训)
│   ├── sft.py / sft_lora.py       #   SFT 全量微调 / LoRA 微调(手写实现)
│   ├── dpo.py / grpo.py / ppo.py  #   DPO / GRPO / PPO 后训练对齐
│   ├── opd.py                     #   OPD 在线策略蒸馏(学生采样 → 教师打分 → reverse KL)
│   ├── distill.py                 #   知识蒸馏
│   ├── deepspeed.py / fsdp.py     #   分布式训练
│   ├── infer.py                   #   交互式推理(命令行入口)
│   ├── train_tokenizer.py         #   BBPE 分词器训练(--variant 读配比 / --data_dir / 扩展 / 验证)
│   ├── configs/                   #   手写轨专用 YAML(manual 脚本 + WebUI 表单消费,内置只读)
│   │   ├── base.yaml              #   公共默认 / 新配置模板(复制改名即可新建)
│   │   ├── nano.yaml / lite.yaml / pro.yaml  #   各变体独立完整配置(不依赖继承)
│   │   └── deepspeed_config.json / deepspeed_zero2.json  #   DeepSpeed 引擎参数
│   └── my_configs/                #   WebUI「另存为」的用户配置副本(git 忽略,可选)
│
├── industrial/                    # 工业训练脚本(对接 Megatron / TRL / PEFT / DeepSpeed)
│   ├── pretrain.py                #   Megatron 轨预训练(GPTDataset / BlendedMegatronDatasetBuilder)
│   ├── sft.py / dpo.py / grpo.py / ppo.py / sft_lora.py  # 工业后训练(TRL / PEFT)
│   └── configs/                   #   工业轨专用 YAML(nano.yaml / 0.6b.yaml)
│
├── hf/                            # HuggingFace 生态桥梁
│   ├── hf_config.py               #   PretrainedConfig
│   ├── hf_model.py                #   GleamLMForCausalLM(from_pretrained / generate)
│   ├── hf_adapter.py              #   Tokenizer 适配(HF 格式)
│   ├── hf_megatron_tokenizer.py   #   BBPE → MegatronTokenizerBase(工业轨复用)
│   └── api.py                     #   便捷推理 API
│
├── data_tools/                    # 数据管线工具
│   ├── download_data.py           #   原始语料下载(fineweb / wiki / baike)
│   ├── pretrain/                  #   预训练数据(清洗 / 去重 / 切分 / 打包)
│   ├── sft/                       #   SFT 数据生成(API 蒸馏 / QA 规则抽取)
│   ├── dpo/                       #   DPO chosen / rejected 构建
│   └── shared/                    #   API 客户端
│
├── deploy/                        # 部署工具(checkpoint → HF 格式 / 量化 / 导出)
│   ├── manual_to_qwen3.py         #   手写轨 checkpoint → HF Qwen3 格式
│   ├── megatron_to_hf.py          #   Megatron 产物 → HF Qwen3 格式(vLLM 原生加载)
│   ├── quantize.py                #   量化部署(FP16 / INT8 / INT4,torchao)
│   ├── export.py                  #   HF 格式导出(safetensors + vLLM 适配)
│   └── export_onnx.py             #   ONNX 导出
├── serve/                         # FastAPI OpenAI 兼容服务(含网页聊天界面)
├── webui/                         # 图形训练控制台(预训练 / 后训练 / 推理等 tab,启动见快速开始)
├── eval/                          # 评测入口(lm-evaluation-harness:CEVAL / CMMLU / MMLU)
├── tests/                         # 单元测试 + 集成测试
├── tools/                         # 辅助工具(checkpoint 检查/转换、快速运行、RAG demo)
├── CONTEXT.md                   # 项目上下文(术语表 + 领域约定)
├── requirements.txt
├── pyproject.toml
├── LICENSE
└── README.md

安全提示

模型权重加载使用 torch.load(weights_only=True) 确保安全。训练脚本因需加载优化器/GradScaler 状态(Python 对象),使用 weights_only=False —— 请勿加载来源不明的 checkpoint 文件,否则存在 pickle 反序列化攻击风险。仅加载自己训练或可信来源的 checkpoint。

许可证:Apache License 2.0