jingyaogong/minimind
"大道至简"
中文 | English
- 此开源项目旨在完全从 0 开始,仅用 3 块钱成本与 2 小时训练时间,即可训练出规模约为 64M 的超小语言模型 MiniMind。
- MiniMind 系列极其轻量,主线最小版本体积约为 GPT-3 的 $\frac{1}{2700}$,力求让普通个人 GPU 也能快速完成训练与复现。
- 项目同时开源了大模型的极简结构与完整训练链路,覆盖 MoE、数据清洗、预训练(Pretrain)、监督微调(SFT)、LoRA、RLHF(DPO)、RLAIF(PPO / GRPO / CISPO)、Tool Use、Agentic RL、自适应思考与模型蒸馏等全过程代码。
- MiniMind 同时拓展了视觉模态模型 MiniMind-V、多模态 Omni 模型 MiniMind-O、扩散语言模型(MiniMind-dLM)、线性模型(MiniMind-Linear),详见 Discussion。
- 项目所有核心算法代码均从 0 使用 PyTorch 原生实现,不依赖第三方库提供的高层抽象接口。
- 这不仅是一个大语言模型全阶段开源复现项目,也是一套面向 LLM 入门与实践的教程。
- 希望此项目能为更多人提供一个可复现、可理解、可扩展的起点,一起感受创造的乐趣,并推动更广泛 AI 社区的进步。
注:本项目基于 Apache 2.0 协议开源,完全免费。“2 小时” 指 SFT 阶段在单张 NVIDIA 3090 上跑完
1 epoch的实测耗时,“3 块钱” 指对应时段的 GPU 租用成本。
📌 项目介绍
大语言模型(Large Language Model, LLM)的出现,引发了全球范围内对 AI 的空前关注。无论是 ChatGPT、DeepSeek 还是 Qwen,都以惊艳的效果让人真切感受到这场技术浪潮的冲击力。然而,动辄数百亿参数的模型规模,使得它们对个人设备而言不仅难以训练,甚至连部署都显得遥不可及。打开大模型的“黑盒子”,真正去理解其内部运作机制,本应是一件令人心潮澎湃的事。遗憾的是,绝大多数探索最终都止步于使用 LoRA 等技术对现有大模型做少量微调,学习一些新指令或特定任务。这更像是在教牛顿如何使用 21 世纪的智能手机——虽然有趣,却偏离了理解物理本质的初衷。
与此同时,第三方的大模型框架与工具库,如 transformers / trl / peft 等,往往只暴露出高度抽象的接口。只需短短十几行代码,就可以完成“加载模型 + 加载数据集 + 推理 + 强化学习”的全流程训练。这种高效封装固然便利,却也在一定程度上把开发者与底层实现隔离开来,削弱了深入理解 LLM 核心代码的机会。我认为 “用乐高自己拼出一架飞机,远比坐在头等舱里飞行更让人兴奋”,然而更现实的问题是,互联网上充斥着大量付费课程和营销内容,用漏洞百出、一知半解的讲解包装所谓的 AI 教程。正因如此,本项目的初衷就是尽可能降低 LLM 的学习门槛,让每个人都能从理解每一行代码开始,从 0 开始亲手训练一个极小的语言模型。是的,从零开始训练,而不是仅仅停留在推理层面。最低只需不到 3 块钱的服务器成本,就能亲身体验从 0 到 1 构建一个语言模型的全过程。
😊 一起感受创造的乐趣吧!
🎉 本项目包含以下内容
- 提供完整的 MiniMind-LLM 结构代码(Dense + MoE),当前主线结构对齐
Qwen3 / Qwen3-MoE生态。 - 提供 Tokenizer 与分词器训练代码,支持
<tool_call>、<tool_response>、<think>等模板标记。 - 覆盖 Pretrain、SFT、LoRA、RLHF-DPO、RLAIF(PPO / GRPO / CISPO)、Tool Use、Agentic RL、自适应思考与模型蒸馏等完整训练流程。
- 提供全阶段开源数据,覆盖收集、蒸馏、清洗与去重后的高质量数据集。
- 关键训练算法与核心模块均从 0 实现,不依赖第三方框架封装。
- 兼容
transformers、trl、peft等主流框架,以及llama.cpp、vllm、ollama等常用推理引擎与Llama-Factory等训练框架。 - 支持单机单卡与单机多卡(DDP、DeepSpeed)训练,支持 wandb / swanlab 可视化与动态启停训练。
- 支持在 C-Eval、C-MMLU、OpenBookQA 等第三方测评集上进行评测,并支持通过 YaRN 实现 RoPE 长文本外推。
- 提供兼容 OpenAI API 协议的极简服务端,便于接入 FastGPT、Open-WebUI 等第三方 Chat UI,并支持
reasoning_content、tool_calls、open_thinking。 - 提供基于 Streamlit 的极简聊天 WebUI,支持思考展示、工具选择与多轮 Tool Call。
- 包含实验性拓展:离散扩散语言模型(dLM)与线性注意力模型(Linear Attention),均可基于主线 AR 模型进行续训。
🎉 已发布模型列表
| 模型 | 参数量 | Release |
|---|---|---|
| minimind-3 | 64M | 2026.04.01 |
| minimind-3-moe | 198M-A64M | 2026.04.01 |
| minimind2-small | 26M | 2025.04.26 |
| minimind2-moe | 145M | 2025.04.26 |
| minimind2 | 104M | 2025.04.26 |
| minimind-v1-small | 26M | 2024.08.28 |
| minimind-v1-moe | 4×26M | 2024.09.17 |
| minimind-v1 | 108M | 2024.09.01 |
📝 更新日志
🔥 2026-04-01
- 发布
minimind-3/minimind-3-moe:结构、Tokenizer、训练链路、推理接口与默认配置全面更新 - 结构主线对齐
Qwen3 / Qwen3-MoE生态:Dense 约64M,MoE 约198M-A64M,并移除了 shared expert 设计 - 默认训练数据切换为
pretrain_t2t(_mini).jsonl、sft_t2t(_mini).jsonl、rlaif.jsonl、agent_rl.jsonl与agent_rl_math.jsonl - 移除独立
train_reason.py;思考能力统一由chat_template + <think>与open_thinking自适应开关控制 toolcall能力已混入sft_t2t / sft_t2t_mini主线数据,默认full_sft即具备基础 Tool Call 能力;同时新增scripts/chat_api.py等推理示例- 新增原生
Agentic RL训练脚本train_agent.py,支持多轮 Tool-Use 场景下的GRPO / CISPO - RLAIF / Agentic RL 训练流程完成
rollout engine解耦,支持更灵活地切换生成后端 serve_openai_api.py与web_demo.py新增reasoning_content/tool_calls/open_thinking支持- Tokenizer 基于
BPE + ByteLevel更新,并新增工具调用与思考标记,预留 buffer token 便于后续扩展 - 新增 LoRA 权重合并导出流程,可通过
scripts/convert_model.py将基础模型与 LoRA 权重合并为新的完整模型权重 - 结构图资源更新,README 大面积更新
2025-10-24
- 🔥 新增RLAIF训练算法:PPO、GRPO、SPO(从0原生实现)
- 新增断点续训功能:支持训练自动恢复、跨GPU数量恢复、wandb记录连续性
- 新增RLAIF数据集:rlaif-mini.jsonl(从SFT数据随机采样1万条);简化DPO数据集,加入中文数据
- 新增YaRN算法:支持RoPE长文本外推,提升长序列处理能力
- Adaptive Thinking:Reason模型可选是否启用思考链
- chat_template全面支持Tool Calling和Reasoning标签(
<tool_call>、<think>等) - 新增RLAIF完整章节、训练曲线对比、算法原理折叠说明
- SwanLab替代WandB(国内访问友好,API完全兼容)
- 规范化所有代码 & 修复一些已知bugs
2025-04-26
- 重要更新
- 如有兼容性需要,可访问🔗旧仓库内容🔗。
- MiniMind模型参数完全改名,对齐Transformers库模型(统一命名)。
- generate方式重构,继承自GenerationMixin类。
- 🔥支持llama.cpp、vllm、ollama等热门三方生态。
- 规范代码和目录结构。
- 改动词表
<s></s>-><|im_start|><|im_end|>
|
|
More...
2025-02-09
- 迎来发布以来重大更新,Release minimind2 Series。
- 代码几乎全部重构,使用更简洁明了的统一结构。 如有旧代码的兼容性需要,可访问🔗旧仓库内容🔗。
- 免去数据预处理步骤。统一数据集格式,更换为
jsonl格式杜绝数据集下载混乱的问题。 - minimind2系列效果相比MiniMind-V1显著提升。
- 小问题:{kv-cache写法更标准、MoE的负载均衡loss被考虑等等}
- 提供模型迁移到私有数据集的训练方案(医疗模型、自我认知样例)。
- 精简预训练数据集,并大幅提升预训练数据质量,大幅缩短个人快速训练所需时间,单卡3090即可2小时复现!
- 更新:LoRA微调脱离peft包装,从0实现LoRA过程;DPO算法从0使用PyTorch原生实现;模型白盒蒸馏原生实现。
- minimind2-DeepSeek-R1系列蒸馏模型诞生!
- minimind2具备一定的英文能力!
- 更新minimind2与第三方模型的基于更多大模型榜单测试性能的结果。
2024-10-05
- 为MiniMind拓展了多模态能力之—视觉
- 移步孪生项目minimind-v查看详情!
2024-09-27
- 09-27更新pretrain数据集的预处理方式,为了保证文本完整性,放弃预处理成.bin训练的形式(轻微牺牲训练速度)。
- 目前pretrain预处理后的文件命名为:pretrain_data.csv。
- 删除了一些冗余的代码。
2024-09-17
- 更新minimind-v1-moe模型
- 为了防止歧义,不再使用mistral_tokenizer分词,全部采用自定义的minimind_tokenizer作为分词器。
2024-09-01
- 更新minimind-v1 (108M)模型,采用minimind_tokenizer,预训练轮次3 + SFT轮次10,更充分训练,性能更强。
- 项目已部署至ModelScope创空间,可以在此网站上体验:
- 🔗ModelScope在线体验🔗
2024-08-27
- 项目首次开源
📌 快速开始
本人的软硬件配置(供参考)
- CPU: Intel(R) Core(TM) i9-10980XE CPU @ 3.00GHz
- RAM: 128 GB
- GPU: NVIDIA GeForce RTX 3090 (24GB) * 8
- Ubuntu==20.04
- CUDA==12.2
- Python==3.10.16
- requirements.txt
第0步
|
|
Ⅰ 🚀 模型推理
1’ 下载模型
在项目根目录:
|
|
2’ CLI 推理
|
|
3’(可选)WebUI
|
|
4’(可选)第三方推理框架
|
|
Ⅱ 🛠️ 模型训练
注:提前确认 Torch 的可用后端
|
|
若你计划使用 CUDA 训练,建议先确认当前环境是否已正确识别 GPU。
若 cuda 不可用,也仍可根据自身设备选择 CPU 或 MPS 运行,但训练速度与兼容性会有非常大的差异。
如需安装或更换 PyTorch 版本,可参考 torch_stable 与链接
1’ 下载数据
从下文提供的数据集下载链接 下载所需数据文件,并放入 ./dataset 目录
当前默认仅需下载
pretrain_t2t_mini.jsonl与sft_t2t_mini.jsonl,即可较快复现MiniMind Zero对话模型。 如有更多需求,下文提供多种搭配方案,可根据自身任务目标与 GPU 资源灵活选择。
2’ 开始训练
💡 检查点暂停续训
所有训练脚本均支持检查点保存。添加 --from_resume 1 参数后,即可自动检测并恢复训练进度:
|
|
断点续训说明:
- 训练过程会自动在
./checkpoints/目录保存完整检查点(模型、优化器、训练进度等) - 检查点文件命名:
<权重名>_<维度>_resume.pth(如:full_sft_512_resume.pth) - 支持跨不同 GPU 数量恢复(自动调整 step)
- 支持 wandb 训练记录连续性(自动恢复同一个 run)
适合长时间训练或不稳定环境,无需担心训练中断导致进度丢失
2.1 预训练(必须)
|
|
训练后,将得到
out/pretrain_*.pth作为输出权重(其中*为模型 dimension,默认为768)
2.2 指令微调(必须)
|
|
训练后,将得到
out/full_sft_*.pth作为输出权重(其中full表示全参数微调)
2.3 测试已训练模型(可选)
确保待测试的模型 *.pth 文件位于 ./out/ 目录下;也可直接前往此处下载我已训练好的 *.pth 权重。
|
|
--weight用于指定权重名称前缀,例如pretrain、full_sft等;更多参数可直接参考eval_llm.py
注:其它须知
1、所有训练脚本均基于 PyTorch 原生实现,并支持多卡加速。
2、若你的设备有 N (N > 1) 张显卡,可通过以下方式启动单机 N 卡训练(DDP,也支持扩展到多机多卡):
|
|
3、可根据需要开启 wandb 记录训练过程。
|
|
2025 年 6 月后,国内网络环境通常无法直连 WandB。MiniMind 当前默认转为使用 SwanLab 作为训练可视化工具,其接口与 WandB 基本兼容;通常只需将 import wandb 替换为 import swanlab as wandb,其余调用方式基本无需改动。
📌 数据介绍
Ⅰ Tokenizer
分词器可以粗略理解成 LLM 使用的一本“词典”,负责把自然语言映射成 token id,再把 token id 解码回文本;项目中也提供了train_tokenizer.py作为词表训练示例。不建议重新训练 tokenizer,因为词表和切分规则一旦变化,模型权重、数据格式、推理接口与社区生态的兼容性都会下降,也会削弱模型的传播性。同时,tokenizer 还会影响 PPL 这类按 token 统计的指标,因此跨 tokenizer 比较时,BPB(Bits Per Byte)往往更有参考价值,可参考这篇。
对 MiniMind 这类小模型来说,词表大小还会直接影响 embedding 层和输出层的参数占比,因此保持词表精简通常是更合适的取舍。
Tokenizer介绍
第三方强大的开源模型例如 Yi、Qwen2、ChatGLM、Mistral、Llama 3 的 tokenizer 词表长度如下:
| Tokenizer模型 | 词表大小 | 来源 |
|---|---|---|
| Yi | 64,000 | 01万物(中国) |
| Qwen2 | 151,643 | 阿里云(中国) |
| ChatGLM | 151,329 | 智谱AI(中国) |
| Mistral | 32,000 | Mistral AI(法国) |
| Llama 3 | 128,000 | Meta(美国) |
| MiniMind | 6,400 | 自定义 |
当前主线为避免历史版本歧义并控制整体体积,统一使用
minimind_tokenizer,不再维护mistral_tokenizer版本。
尽管 minimind_tokenizer 的词表只有 6400,编解码效率弱于 qwen2、glm 等更偏中文友好的 tokenizer,但它能显著压缩 embedding 层和输出层的参数占比,更适合 MiniMind 这类小模型的体积约束。
从实际使用效果看,这套 tokenizer 并没有明显带来生僻词解码失败的问题,整体仍然足够稳定可用;因此当前主线训练也统一沿用这套词表,而不再额外分叉维护其他 tokenizer 版本。
Ⅱ Pretrain数据
MiniMind-3 当前主线预训练数据为 pretrain_t2t.jsonl / pretrain_t2t_mini.jsonl。
这两份数据已经整理成统一的 text -> next token prediction 训练格式,目标是在较小算力下兼顾:
- 文本质量;
- 长度分布;
- 中英混合能力;
- 与后续 SFT / Tool Calling / RLAIF 阶段的模板衔接。
数据来源包括但不限于通用文本语料、对话整理语料、蒸馏补充语料,以及各类宽松开源协议可用的数据集;主线数据会在清洗、去重、长度控制与格式统一后再进入训练。主要来源包括:匠数大模型数据集、Magpie-Align 等公开数据源。
其中:
pretrain_t2t_mini.jsonl更适合快速复现;pretrain_t2t.jsonl更适合完整训练MiniMind-3主线模型。
文件数据格式为
|
|
Ⅲ SFT数据
MiniMind-3 当前主线 SFT 数据为 sft_t2t.jsonl / sft_t2t_mini.jsonl。相比更早期的 sft_512 / sft_1024 / sft_2048 方案,当前版本更强调:
- 统一模板;
- 更适合对话 + 思考标签 + Tool Calling 的混合训练;
- 尽量减少数据预处理分叉,降低复现成本。
其数据来源包括但不限于高质量指令跟随数据、公开对话数据、模型蒸馏合成数据,以及协议友好的开源数据集;在进入 t2t 主线前,会统一为当前仓库使用的多轮对话格式。当前主线中也包含大量合成数据,例如本人基于 qwen3-4b 合成的约 10w 条 tool call 数据,以及 qwen3 系列的 reasoning 数据等。其中社区主要来源有:匠数大模型数据集、Magpie-Align、R1-Distill-SFT、COIG、Step-3.5-Flash-SFT 等。公布版本会确保数据来源与处理链路符合对应开源协议的可传递性约束,并遵守 Apache-2.0、CC-BY-NC-2.0 等相关协议要求。
其中:
sft_t2t_mini.jsonl:适合快速训练对话模型;sft_t2t.jsonl:适合完整复现主线版本;toolcall能力已经并入主线 SFT 数据。
所有 SFT 文件数据格式均为(包含对话数据、Tool Use 数据)
|
|
Ⅳ RL 数据
MiniMind 当前主线 RL 数据为 dpo.jsonl。数据抽样自 DPO-En-Zh-20k。
主线中会将这部分样本统一重组为当前仓库使用的偏好学习格式,用于奖励模型或偏好优化阶段训练;其中 chosen 表示更符合偏好的回复,rejected 表示相对较差的回复。
其中 dpo.jsonl 数据格式为
|
|
除此之外,其他 RL 数据与 SFT 数据格式保持一致,通常是从 SFT 数据中按总长度和对话轮次筛选得到,并将最后一个 assistant 位置留空,供 rollout 阶段续写使用。
Ⅴ MiniMind 训练数据集
[!NOTE] 当前主线训练所需的核心数据集已开源,因此无需再自行预处理大规模数据集,避免重复性的数据处理工作。
MiniMind训练数据集下载地址: ModelScope | HuggingFace
无需全部clone,可单独下载所需的文件
将下载的数据集文件放到./dataset/目录下(✨为推荐的必须项)
|
|
注:各数据集简介
agent_rl.jsonl–Agentic RL 主线训练数据,用于train_agent.py的多轮 Tool-Use / CISPO / GRPO 训练agent_rl_math.jsonl–Agentic RL 纯数学补充数据,适合带最终校验目标的多轮推理/工具使用场景(用于RLVR)dpo.jsonl–RLHF阶段偏好训练数据(DPO)pretrain_t2t_mini✨ –minimind-3轻量预训练数据,适合快速复现(推荐设置max_seq_len≈768)pretrain_t2t–minimind-3主线预训练数据(推荐设置max_seq_len≈380)rlaif.jsonl✨ –RLAIF训练数据集,用于PPO/GRPO/CISPO等强化学习算法训练sft_t2t_mini.jsonl✨ –minimind-3轻量SFT数据(用于快速训练Zero模型),推荐设置max_seq_len≈768,其中已混入一部分 Tool Call 样本sft_t2t.jsonl–minimind-3主线SFT数据,适合完整复现,其中同样已混入 Tool Call 样本
训练参数 max_seq_len 目前指的是 tokens 长度,而非绝对字符数。
本项目tokenizer在中文文本上大约1.5~1.7 字符/token,纯英文的压缩比在4~5 字符/token,不同数据分布会有波动。
数据集命名标注的“最大长度”均为字符数,100长度的字符串可粗略换算成100/1.5≈67的tokens长度。
例如:
- 中文:
白日依山尽5个字符可能被拆分为[白日,依,山,尽] 4个tokens; - 英文:
The sun sets in the west24个字符可能被拆分为[The,sun,sets,in,the,west] 6个tokens
“推荐设置”给出了各个数据集上最大tokens长度的粗略估计。
须知 max_seq_len 可以激进 / 保守 / 均衡地调整,因为更大或更小均无法避免副作用:一些样本短于 max_seq_len 后被 padding 浪费算力,一些样本长于 max_seq_len 后被截断语义。
在算力效率与语义完整性之间找到平衡点即可
MiniMind 主线训练数据组成与推荐组合示意图
说明 & 推荐训练方案
-
minimind-3主线推荐采用pretrain_t2t+sft_t2t+rlaif/agent_rl的阶段式训练组合。 -
想要最快速度从0实现Zero模型,推荐使用
pretrain_t2t_mini.jsonl+sft_t2t_mini.jsonl的数据组合 -
推荐具备一定算力资源或更在意效果的朋友完整复现
minimind-3;仅有单卡GPU或更在意快速复现的朋友强烈推荐 mini 组合。 -
当前
sft_t2t / sft_t2t_mini已经混入 Tool Call 数据,因此通常不需要再额外做一轮独立的 Tool Calling 监督微调。
📌 模型
结构
minimind-3 Dense 使用 Transformer Decoder-Only 结构,整体配置已经向 Qwen3 生态对齐,方便后续转换到 transformers / llama.cpp / ollama / vllm:
- 采用预标准化(Pre-Norm)+ RMSNorm。
- 使用 SwiGLU 激活函数。
- 使用 RoPE 旋转位置编码,并支持 YaRN 外推。
q_heads=8、kv_heads=4,max_position_embeddings=32768,rope_theta=1e6。
minimind-3-moe 在相同结构上扩展 MoE 前馈层,实现上兼容 Qwen3-MoE 风格配置(去除 shared expert)。
- 当前默认配置为
4 experts / top-1 routing,用于以更低激活参数获得更高容量。 - Experts 继续增加后,实际耗时往往比同尺寸规模的 dense 模型高非常多,这和 “MoE 推理更快” 放在一起看会有点反直觉,但训练时 token 先按专家分桶、再分别做 forward,原生训练时带来的
kernel启停和调度开销会急剧变重,这本身是很自然的事情。得靠支持 MoE kernel-fused 的算子库来优化,比如基于Triton的自定义 kernel、DeepSpeed-MoE、Megatron-LM等等。当然,这个项目还是希望保留原生 PyTorch 的普适性,所以这里做的是现实的折中,在当前实现下,4 experts / top-1这个甜点配置大约只比 dense 模型慢50%左右。
minimind-3 系列结构如下图:
修改模型配置见./model/model_minimind.py,参考模型参数版本见下表:
| Model Name | params | len_vocab | max_pos | rope_theta | n_layers | d_model | kv_heads | q_heads | note |
|---|---|---|---|---|---|---|---|---|---|
| minimind-3 | 64M | 6400 | 32768 | 1e6 | 8 | 768 | 4 | 8 | Dense |
| minimind-3-moe | 198M-A64M | 6400 | 32768 | 1e6 | 8 | 768 | 4 | 8 | 4 experts / top-1 |
| minimind2-small | 26M | 6400 | 32768 | 1e6 | 8 | 512 | 2 | 8 | 历史版本 |
| minimind2-moe | 145M | 6400 | 32768 | 1e6 | 8 | 640 | 2 | 8 | 历史版本 |
| minimind2 | 104M | 6400 | 32768 | 1e6 | 16 | 768 | 2 | 8 | 历史版本 |
模型配置
关于 LLM 的参数配置,MobileLLM 对小模型做过一组很有代表性的系统研究。对 MiniMind 这类百M级模型而言,d_model 与 n_layers 的取舍不只是参数分配问题,也会直接影响训练稳定性与最终效果。
当前 minimind-3 主线选择 dim=768, n_layers=8,本质上是一种工程取舍:更浅的网络训练更快,同时 dim 也不至于过小而导致模式崩溃,因此能在训练效率、稳定性与最终效果之间取得相对均衡。
查看详细说明
Scaling Law 在小模型上往往会呈现出一些不同于大模型的现象。决定 Transformer 参数规模变化的核心参数,通常主要就是 d_model 和 n_layers:
d_model↑ +n_layers↓ -> 矮胖子d_model↓ +n_layers↑ -> 瘦高个
经典 Scaling Law 更强调训练数据量、参数量和训练步数的决定性作用,通常会弱化架构差异本身的影响;但在小模型区间,这个结论并不总是完全成立。
MobileLLM 的一个核心观察是:在参数量固定时,深度往往比宽度更重要。也就是说,相比“宽而浅”的结构,“深而窄”的模型更容易学到抽象概念。
例如当模型参数量固定在 125M 或 350M 时,30~42 层的狭长结构通常会优于 12 层左右的矮胖结构,在常识推理、问答、阅读理解等多个基准上都呈现出相近趋势。
这和 MiniMind 在训练过程中围绕 d_model 与 n_layers 做参数分配实验时观察到的现象是一致的。不过“深而窄”里的“窄”也有下限:当 d_model < 512 时,词嵌入维度过窄带来的劣势会明显放大,额外增加 layers 往往不足以完全弥补固定 q_head 下 d_head 偏小的问题。
相对地,当 d_model > 1536 时,继续增加层数往往比单纯继续加宽更划算,更容易带来更高的参数-效果收益。
作为参考,GPT-3 的参数设定如下:
📌 实验
Ⅰ 训练开销
- 时间单位:小时(h)
- 成本单位:人民币(¥);
7¥ ≈ 1 美元 - 3090 租卡单价:约
1.3¥/h(实际价格可自行参考) - 说明:以下结果为
minimind模型在单卡3090上的经验估算值,用于快速感知训练门槛
| Model Name | params | pretrain_t2t_mini | sft_t2t_mini | toolcall | RLAIF |
|---|---|---|---|---|---|
| minimind-3 | 64M | ≈1.21h ≈1.57¥ |
≈1.10h ≈1.43¥ |
≈0.9h ≈1.17¥ |
≈1.1h ≈1.43¥ |
| minimind-3-moe | 198M-A64M | ≈1.69h ≈2.20¥ |
≈1.54h ≈2.00¥ |
≈1.26h ≈1.64¥ |
≈1.54h ≈2.00¥ |
训练开销总结&预测
minimind-3
pretrain_t2t_mini+sft_t2t_mini
单卡3090,1 epoch预计约2.31小时,成本约3.0元人民币
可从 0 训练出minimind-3 Zero对话模型。
minimind-3-moe
pretrain_t2t_mini+sft_t2t_mini
单卡3090,1 epoch预计约3.23小时,成本约4.2元人民币
可快速得到minimind-3-moe的基础对话版本。
以上均为估算值,仅用于快速感知训练门槛。
基于单卡 NVIDIA 3090,minimind zero 从 0 训练依然可以控制在约 2 小时量级,个人开发者也能较低门槛地快速上手。
若采用更高规格的多卡环境,例如 8x H100,总训练时长还可进一步压缩至分钟级。以尽可能低的门槛实现可复现、可上手、可持续迭代的 LLM 训练体验,这也是 MiniMind 系列一直希望坚持的方向。低成本快速复现并不是噱头,下面保留一个早期的 Zero 风格样例对话供参考:
|
|
尽管该版本已经具备基础对话能力,但事实知识与泛化效果仍较有限;它更适合作为 Zero 训练路线可行性的早期参考。
Zero 模型权重保存为 full_sft_zero_768.pth(见下文 MiniMind 模型文件链接),如有兴趣可下载体验其对话效果。
Ⅱ 主要训练(必须)
所有训练脚本均
cd ./trainer目录执行
1’ 预训练 (Pretrain):
LLM 首先要学会的是先把尽可能多的基础知识和语言规律吸收到参数里。只有这一步打稳了,模型后面才有能力去理解问题、组织表达,并逐步形成像样的生成能力。预训练做的事情,本质上就是让模型先埋头读大量文本,例如 Wiki 百科、新闻、书籍、对话语料等,从中学习事实知识、语言模式以及上下文之间的统计关系。这个阶段通常是“无监督”的:人类不需要逐条告诉模型哪里对、哪里错,而是让它自己从海量文本里总结规律,逐步建立起对世界知识和语言结构的内部表征。 更直白地说,模型在这一阶段的核心目标就是学会高质量地词语接龙。例如输入“秦始皇”,它要能够继续生成“是中国历史上的第一位皇帝”这类符合语义与常识的后续内容。
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:pretrain_*.pth(*为模型具体dimension,每次保存时新文件会覆盖旧文件)
768dim配置在预训练阶段的 loss 曲线
|
|
2’ 有监督微调 (Supervised Fine-Tuning):
SFT 并不只是把模型调成“更会聊天”,它同样可以继续向模型中灌入新的知识、行为模式和回答风格。尤其是像 MiniMind 当前主线这样体量达到 14GB 的 SFT 数据,本身就已经不只是简单的格式对齐,而更接近一种带有 mid training 性质的持续强化过程。
如果把预训练理解为先让模型广泛地读书、积累基础语言能力,那么 SFT 更像是在高质量、更有目标的数据上继续深加工。一方面,它会让模型适应多轮对话、问答、工具调用和思考标签等交互形式;另一方面,它也会继续把特定知识分布、任务模式和助手风格压进参数里。
具体到 MiniMind 里,SFT 阶段会让模型适应当前仓库使用的多轮对话模板。模型会逐渐理解 user / assistant / system / tool 等角色结构,同时进一步强化指令跟随、稳定回复和任务完成能力。
当前训练时会对指令和回答长度做截断控制,主要是为了兼顾显存占用与训练效率;如果后续需要更长上下文,只需要继续准备少量长样本做增量微调即可。在推理时通过启用 YaRN 外推,可以免训练地将上下文长度扩展到 2048 及以上。
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:full_sft_*.pth(*为模型具体dimension,每次保存时新文件会覆盖旧文件)
768dim配置在 SFT 阶段的 loss 曲线
|
|
Ⅲ 其它训练(可选)
所有训练脚本均
cd ./trainer目录执行
3’ 知识蒸馏 (Knowledge Distillation, KD)
知识蒸馏大体可以分成黑盒和白盒两类,MiniMind 当前主线两种思路都有涉及,只是侧重点不同。
- 黑盒蒸馏:更常见,也更贴近当前主线的实际做法。严格来说,它本质上仍然是面向教师输出结果的监督微调,也就是基于硬标签继续训练;只是随着 LLM 的流行,这类“对着强模型输出做 FT”的做法也逐渐被广义地归入了蒸馏范畴,因此通常被称为黑盒蒸馏。它重点学习的是答案、风格和行为模式,学生模型只能看到“老师说了什么”,却看不到老师内部是如何做出这个判断的。像
DeepSeek R1、Qwen3的高质量回答,以及tool call、reasoning、思维链等数据,都可以看作黑盒蒸馏信号;MiniMind 当前主线full_sft数据里,其实已经混入了相当一部分这样的思路。 - 白盒蒸馏:更进一步,不只学习教师给出的最终输出,还去学习教师在 token 分布层面的偏好。相比黑盒蒸馏,它额外利用了教师模型输出层更细粒度的分布信息,因此学生模型学到的不只是“标准答案”,还包括教师在候选 token 之间的相对倾向。对应到
train_distillation.py,当前实现是在已经完成 SFT 的权重基础上,继续用教师模型提供的分布信号来训练学生模型,因此更适合作为理解 MiniMind 蒸馏流程的参考实现。
黑盒蒸馏本质上等价于对 teacher 生成答案做监督微调:
|
|
白盒蒸馏则通常在监督损失之外,再额外拟合教师分布:
|
|
仓库中提供的 train_distillation.py 更适合作为理解白盒蒸馏流程的参考实现:它完整展示了教师/学生双模型加载、CE + KL 混合损失、温度缩放、MoE 与 dense 组合蒸馏,以及断点续训和分布式训练等关键细节。
|
|
4’ LoRA (Low-Rank Adaptation)
LoRA 是一种常见的参数高效微调(Parameter-Efficient Fine-Tuning, PEFT)方法。相比全参数微调,它只更新少量新增参数,而保留原始模型主体权重不变,因此训练成本更低,也更适合做垂直场景适配。
它的核心思想是在原有权重矩阵旁引入低秩增量分支,仅训练这部分低秩参数,从而用较小代价完成能力迁移。相关实现可见 model_lora.py 和 train_lora.py,整个流程均为纯手写实现,不依赖第三方封装。
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:lora_xxx_*.pth(*为模型具体dimension,每次保存时新文件会覆盖旧文件)
LoRA 很适合处理“如何在尽量保留通用能力的前提下,让模型快速适应私有领域或垂直场景”这类问题。例如基础模型医学知识不足时,就可以在原有模型之上叠加一层面向医疗场景的 LoRA 权重,以较小代价获得更好的领域表现。
通常只需要准备同样的多轮对话格式数据,放置到 lora_xxx.jsonl,再从仓库根目录执行 cd trainer && python train_lora.py,即可得到新的 LoRA 模型权重。
例1:垂域数据
|
|
例2:自我认知数据
|
|
此时可将【基模 + LoRA 权重】组合使用,从而在保留基础模型通用能力的同时,增强特定领域表现。训练完成后也可以通过 eval_llm.py 做简单测试。
|
|
PS:如果有更充足的数据,也可以直接做 full_sft 全参微调;不过这通常需要更谨慎地混合通用数据与领域数据,否则很容易因为过拟合垂域样本而损失模型原有的通用性。
LoRA权重可合并回基础模型并导出为新的完整模型权重,可使用scripts/convert_model.py中的convert_merge_base_lora:
|
|
5’ 工具调用 & 自适应思考
2026-03 起,仓库移除了独立的 train_reason.py。
当前版本不再单独维护 reason_*.pth 权重,而是统一通过 chat_template、<think> 标签、open_thinking 开关以及后续 SFT / RLAIF 流程来建模“是否显式输出思考过程”。
5.1 Tool Calling
当前 toolcall 能力已经并入 sft_t2t / sft_t2t_mini 主线数据,因此通常不再需要额外单独训练一轮 Tool Calling;默认的 full_sft 权重已经具备基础 Tool Call 能力。当前这部分训练数据主要由 qwen3-4b 采样约 10w 条构成,工具列表也主要覆盖约 10 个模拟的自定义工具(例如查询时间、数学计算、获取天气等),因此目前还谈不上明确的泛化能力。其中 Tool Calling 样本统一沿用了 OpenAI 风格的多轮消息格式:
|
|
其中 tools 挂在 system 消息上,tool_calls 挂在 assistant 消息上;训练时再由 chat_template 自动展开为 <tool_call>...</tool_call> 与 <tool_response>...</tool_response> 片段,因此现在可以直接学习原生 tool call 格式。
Tool Calling 的 chat template 已统一支持解析为:
|
|
也可以直接通过 eval_toolcall.py 做简单测试:
|
|
5.2 Adaptive Thinking
minimind 将显式思考能力统一到了模板层,这也和当前很多主流大模型的模板设计保持一致:
open_thinking=0:默认注入空的<think>\n\n</think>,模型更倾向于直接回答;open_thinking=1:模板会预先注入<think>起始标签,模型再继续输出显式思考过程与最终回答;- CLI、OpenAI-API、WebUI 三个入口均支持该开关。
更准确地说,目前不再“单独训一个思考模型”,而是把“是否显式思考”下沉到 chat_template。模板层会先预留 <think></think> 这一结构,同一个模型在推理时再通过 open_thinking 动态切换;在训练时,则通过混合空 think、显式 reasoning_content 与 thinking_ratio 采样,让模型逐步见过“该想时想、该直答时直答”的混合模式。
|
|
OpenAI-API-SDK 用法:
|
|
注:当前同时开启 Tool Call 与显式思考时,模型通常并不太会稳定地输出思考过程。原因在于现阶段训练数据里还缺少“reasoning 与 tool call 同时存在”的联合蒸馏样本,因此模型尚未充分学会这两种能力的协同表达。
Ⅳ 强化学习(可选)
在 LLM 的后训练实践中,常见的强化学习路径主要有两条:
- 基于人类反馈的强化学习 (Reinforcement Learning from Human Feedback, RLHF)
- 通过人类对模型输出的偏好进行评价来训练模型,使其生成更符合人类价值观和偏好的内容。
- 基于AI反馈的强化学习 (Reinforcement Learning from AI Feedback, RLAIF)
- 使用AI模型或其他可自动验证的机制来提供反馈,而不直接依赖人类标注。
- 这里的“AI feedback”在广义上也可以扩展到规则奖励、Ground Truth 校验、代码解释器、环境反馈等自动化信号。
| 类型 | 裁判 | 优点 | 缺点 |
|---|---|---|---|
| RLHF | 人类 | 更贴近真实人类偏好 | 成本高、效率低 |
| RLAIF | 模型 | 自动化、可扩展性强 | 可能偏离人类真实偏好 |
二者本质上都属于利用某种形式的"反馈“来优化模型行为的强化学习范式。
不过在具体实践里,它们并不只是反馈来源不同:奖励是否可验证、是否连续、是否依赖环境交互、是否延迟到整轮结算,都会直接影响训练形态与工程实现。
👀 PO算法的统一视角
在介绍实现具体算法之前,我先以个人理解的极简视角,阐述所有Policy Optimization (PO)算法的统一共性。
说到底,这里讨论的 PO 算法都只是在优化一个期望:
$$\mathcal{J}_{PO} = \mathbb{E}_{q \sim P(Q),\, o \sim \pi_\theta(\cdot \mid q)} \left[ \underbrace{\Phi(r_t, A_t)}_{\text{策略目标}} - \underbrace{h(\text{KL}_t)}_{\text{正则项}} \right]$$训练时,只需最小化负目标函数,即:
$$\mathcal{L}_{PO} = -\mathcal{J}_{PO}$$这个框架只包含三个核心组件:
- 策略项 $\Phi(r_t, A_t)$: 如何结合概率比 $r_t$ 和优势 $A_t$ 更新策略
- 优势项 $A_t$: 如何计算优势,这很重要!大模型算对定积分也不足为奇,小模型回答对加减法优势通常都是正的
- 正则项 $h(\text{KL}_t)$: 如何约束变化幅度 $\text{KL}_t$, 既防止跑偏又防止管的太死
(展开)符号说明
| 符号 | 含义 | 说明 | 值域 |
|---|---|---|---|
| $q$ | 问题/提示词 | 从数据集 $P(Q)$ 中采样 | - |
| $o$ | 模型输出序列 | 由策略 $\pi$ 生成 | - |
| $r_t$ | 概率比 | $r_t = \frac{\pi_\theta(o_t \mid q, o_{<t})}{\pi_{\mathrm{old}}(o_t \mid q, o_{<t})}$ | $(0, +\infty)$ |
| $A_t$ | 优势函数 | 衡量某个动作相比基线有多好 | $(-\infty, +\infty)$ |
| $\text{KL}_t$ | KL散度 | 防止策略偏离参考模型太远 | $[0, +\infty)$ |
不同的xxPO算法本质上只是对这三个组件的不同设计的实例化!
6’ 基于人类反馈的强化学习 (Reinforcement Learning from Human Feedback, RLHF)
在前面的训练步骤中,模型已经具备了基本的对话能力,但是这样的能力完全基于单词接龙,缺少正反样例的激励。 模型此时尚未知什么回答是好的,什么是差的。希望它能够更符合人的偏好,降低让人类不满意答案的产生概率。 这个过程就像是让模型参加新的培训,从优秀员工的作为例子,消极员工作为反例,学习如何更好地回复。
6.1 Direct Preference Optimization
直接偏好优化(DPO)算法,损失为:
$$\mathcal{L}_{DPO} = -\mathbb{E}\left[\log \sigma\left(\beta \left[\log \frac{\pi_\theta(y_w|x)}{\pi_{ref}(y_w|x)} - \log \frac{\pi_\theta(y_l|x)}{\pi_{ref}(y_l|x)}\right]\right)\right]$$其中:
- 策略项: $f(r_t) = \log r_w - \log r_l$ (对比chosen vs rejected的概率比)
- 优势项: $g(A_t)$ = 无显式优势项(通过偏好对比隐式体现)
- 正则项: $h(\text{KL}_t)$ = 隐含在 $\beta$ 中 (控制偏离参考模型程度)
特别地,
- DPO从PPO带KL约束的目标推导出对偏好对的解析训练目标,直接最大化"chosen优于rejected"的对数几率;无需同步训练Reward/Value模型。DPO只需跑
actor与ref两个模型,显存占用低、收敛稳定、实现简单。 - 训练范式:off‑policy,使用静态偏好数据集,可反复多轮epoch;Ref模型固定(预先缓存输出)。
- DPO的局限在于不做在线探索,更多用于"偏好/安全"的人类价值对齐;对"能不能做对题"的智力能力提升有限(当然这也取决于数据集,大规模收集正反样本并人类评估很困难)。
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:dpo_*.pth(*为模型具体dimension,每次保存时新文件会覆盖旧文件)
7’ 基于 AI 反馈的强化学习 (Reinforcement Learning from AI Feedback, RLAIF)
稍微花篇幅解释一下,我还是更想把这一节叫作 RLAIF,虽然严格来说,这个命名并不完全准确。像 RLVR 这类依赖可验证奖励的路线,本身有相对独立的脉络,很难被简单并进狭义的 AI feedback 里。
但如果把“AI”理解得稍微宽一点,我又觉得这个名字并非完全说不通:奖励既可以来自奖励模型、judge model 这类显式的智能体,也可以来自规则函数、Ground Truth校验、工具调用结果、环境返回状态这类可自动获得的信号。规则足够复杂、符号系统足够丰富时,它们和“智能反馈”之间的边界,本来就未必那么泾渭分明。
因此这一章更想讨论的,其实是 LLM 在 SFT 之后,借助各种非人工、可自动获得的反馈信号继续做强化学习优化的方法。比如数学题答案是否正确、工具调用执行代码能否通过测试用例、推理过程是否符合格式…都可以自动化判断。
对于单轮可验证任务,这类反馈往往更接近“即时打分”;而在 Agentic RL 场景中,奖励则更常表现为多步交互后的延迟结算,甚至直接来自环境本身。
它们共同的特点通常都是On-Policy与可扩展性强——不需要昂贵的人工标注,可以生成海量训练样本,让模型在在线大量试错中快速进化。
MiniMind 着手实现2+N种基本+前沿的RLAIF方法:
- PPO、GRPO 被大规模验证的经典RL算法
- N种前沿RL算法(不定期以Exp性质更新)
1️⃣ 数据集准备 (必须)
当前主线使用 rlaif.jsonl 作为 RLAIF 训练数据,体量约 20MB,比早期 rlaif-mini.jsonl 更完整,更适合直接验证 PPO / GRPO / CISPO 的训练效果。
数据格式与 SFT 一致,但 assistant 字段不需要真实内容,因为训练过程中完全由 $\Pi$ 策略模型实时采样生成。因此形如:
|
|
RLAIF的训练过程中,模型会基于user的问题生成1或多个候选回答,然后由奖励函数/模型对回答打分, 分数高的回答会被鼓励(增加 $\Pi$ 策略概率),分数低的回答会被抑制(降低 $\Pi$ 策略概率)。这个"打分->调整"的循环就是强化学习的核心。
2️⃣ 奖励机制准备 (必须)
RLAIF训练需要某种可计算的奖励信号;它可以来自奖励模型,也可以来自规则函数、Ground Truth 校验或环境反馈。MiniMind 当前默认演示的是 Reward Model 路线。
此处选取小型且高质量的 InternLM2-1.8B-Reward (ModelScope | HuggingFace) 作为基础奖励模型。
下载奖励模型后需要放置在minimind项目的同级目录下,推荐结构如下:
|
|
奖励机制选择与MiniMind限制说明(点击展开)
1. 奖励机制的多样性
RLAIF中的"奖励信号"来源可以非常灵活:
-
Model-based奖励:可使用专门的Reward Model(如InternLM2-Reward),也可使用通用LLM+提示词进行打分(如Qwen3-as-a-Judge)。奖励模型规模和架构均可自由选择。
-
Rule-based奖励:可以基于规则函数构造奖励信号,例如:
- 数学题答案正确性验证(Ground Truth对比)
- SQL执行成功率与结果准确性
- 代码解释器运行结果(pass@k)
- 工具调用返回状态(API成功/失败)
- 格式合规性检查(JSON/XML解析)
- 推理链完整性评估(CoT步骤数)
-
Environment-based奖励:在Agent场景中,环境反馈本身即为天然奖励(如游戏得分、Research完整度、任务完成度)。
任何能够量化"回答质量"的机制都可作为RL的奖励来源。DeepSeek R1就是典型案例:使用规则函数验证数学答案正确性作为奖励,无需额外的Reward Model。
2. MiniMind限制:奖励稀疏问题
RLAIF训练既可以针对推理模型也可以针对非推理模型,区别仅在于格式。
然而对于 MiniMind 这种 0.1B 参数量、能力较弱的模型,在通用任务(如 R1 风格的数学数据集)上会遇到严重的奖励稀疏(Reward Sparsity)问题:
- 现象:模型生成的候选回答几乎全部错误,导致所有奖励分数 $r(x,y) \approx 0$
- 后果:优势函数 $A(x,y) = r(x,y) - b(x) \approx 0$,策略梯度信号消失,无法有效更新参数 $\theta$
如同让小学生做高考数学题,无论尝试多少次都得零分,无法通过分数差异学习改进策略。这属于 RL 算法在奖励稀疏场景下的根本限制。
为缓解此问题,MiniMind的实现选择了model-based的连续性奖励信号:
- Reward Model输出连续分数(如-2.5到+3.0),而非二元的0/1
- 即使回答质量都差,也仍能区分“更差”(-3.0)和“没那么差”(-2.8)的细微差异。所以这种稠密且连续的奖励信号能够为优势函数 $A(x,y)$ 提供非零梯度,使得策略网络得以渐进式优化
- 也可以混合多种奖励源: $r_{\text{total}} = \alpha \cdot r_{\text{model}} + \beta \cdot r_{\text{rule}}$ (例如既可以检测 thinking 标签格式奖励,又可以综合回答本身质量的 reward 分数)
- MiniMind 实践中避免直接使用 rule-based 二元奖励 + 超纲难度数据(如 MATH500),易导致奖励全零;
- 监控训练时观察奖励分数的方差 $\text{Var}(r)$,若持续接近0则需调整数据或奖励机制
对于生产级大模型的Agentic RL场景:
在真实Agent系统(代码生成、工具调用、检索-规划-执行的多轮链路)中,奖励是“延迟整轮结算”的不同范式:
- LLM需要逐token生成工具调用指令(tool_call),经历解析(tool_parse)、工具执行(tool_exec),再把结果拼接回上下文继续下一步;循环往复直到完成。
- 一次完整的任务链路包含多次调用+思考,直到终止条件满足时计算一次总reward(如任务是否完成、测试是否通过、目标是否命中)。
因此,Agentic RL更接近稀疏/延迟奖励设定:梯度回传在“整轮结束后”才发生,和非Agentic RL任务在对话单轮上“即时评分即时更新”有很大不同。 这也解释了Agent任务上更偏向环境反馈(environment-based reward),而非凭Reward Model进行静态打分。
- 环境交互反馈:最终以执行结果为准(代码是否跑通、API是否返回成功、子目标是否完成);
- Model-based奖励局限:对长链路、可执行语义的全貌捕捉有限,且大概率和真实环境反馈不一致(reward hacking)。
7.1 Proximal Policy Optimization
PPO 是 2017 年 OpenAI 提出的非常经典的强化学习算法,也是 LLM RL 领域最常见的基线方法之一。
PPO损失:
$$\mathcal{L}_{PPO} = -\mathbb{E}\left[\min(r_t \cdot A_t, \text{clip}(r_t, 1-\varepsilon, 1+\varepsilon) \cdot A_t)\right] + \beta \cdot \mathbb{E}[\text{KL}]$$其中:
- 策略项: $f(r_t) = \min(r_t, \text{clip}(r_t, 1-\varepsilon, 1+\varepsilon))$ (裁剪概率比防止更新过激)
- 优势项: $A_t$ 通常由Critic网络估计,也可以使用GAE进行计算
- 正则项: $h(\text{KL}_t) = \beta \cdot \mathbb{E}[\text{KL}]$ (全局KL散度约束)
对比DPO而言,
- DPO (Off-Policy):训练数据是静态偏好对(chosen vs rejected),可以反复使用同一批数据训练多个 epoch,像传统监督学习一样。数据效率高、成本低,且无需 Reward Model。
- PPO (On-Policy):必须用当前策略实时采样新数据,旧策略数据只能有限复用,否则就会出现 distribution shift。虽然 importance sampling 和 clip 允许轻微偏移,但本质上仍要求数据来自较新的策略。数据效率更低,但更适合探索式学习。
简单来说:
- 前者按离线预定的「好/坏标准」学习;
- 后者则基于最新 policy 在线采样并实时纠偏。
MiniMind 的 PPO 实现包含 Actor(生成回答)、Critic(评估回答价值)以及完整的 GAE(Generalized Advantage Estimation)优势函数计算。
训练方式:
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:ppo_actor_*.pth(*为模型具体dimension)
MiniMind 在 PPO 训练阶段的优化走势
从训练曲线可以看出,PPO存在reward提升缓慢的问题。私以为这主要源于PPO双网络联合优化方法:Critic需要逐步收敛以准确估计价值函数,而Actor的策略更新依赖Critic提供的优势估计,两者相互依赖形成复杂的优化过程。训练初期Critic估计不准会影响Actor梯度方向,导致整体收敛缓慢。此外,PPO 需要同时维护两个网络,在当前实现下显存占用约为单网络方法的 1.5–2 倍。
7.2 Group Relative Policy Optimization
2025 年初,随着 DeepSeek-R1 火爆出圈,来自 DeepSeekMath 论文的 GRPO 也迅速进入主流视野,一度成为最受关注的 RL 算法之一。不过 AI 领域向来迭代极快。时至今日,GRPO 更多已经演变成各类 XXPO 变体(如 DAPO、GSPO、CISPO 等)的共同基线。一句话概括它的核心创新,就是“分组相对价值估计”。
GRPO损失:
$$\mathcal{L}_{GRPO} = -\mathbb{E}\left[\min(r_t \cdot A_t, \mathrm{clip}(r_t, 1-\varepsilon, 1+\varepsilon) \cdot A_t) - \beta \cdot \text{KL}_t\right]$$其中:
- 策略项: $f(r_t, A_t) = \min(r_t \cdot A_t, \mathrm{clip}(r_t, 1-\varepsilon, 1+\varepsilon) \cdot A_t)$ (对概率比和优势项一起做裁剪,防止更新过激)
- 优势项: $g(A_{i,j}) = \frac{R_{i,j} - \mu_i}{\sigma_i + \epsilon}$ (组内归一化,消除Critic网络)
- 正则项: $h(\text{KL}_t) = \beta \cdot \text{KL}_t$ (token级KL散度约束)
对于同一个问题,模型生成 N 个回答并计算各自奖励,再用组内平均奖励作为 baseline。高于 baseline 的回答被鼓励,低于 baseline 的回答被抑制,因此无需额外训练 critic 网络。
GRPO 更显著的问题是退化组(Degenerate Groups):如果某个问题上 N 个回答的奖励几乎一样,那么这一组的学习信号就会接近 0。在 MiniMind 这种超小模型上,这个问题尤其明显,所以训练必须限制在合理的能力边界内。
训练方式:
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:grpo_*.pth
MiniMind 在 GRPO 训练阶段的优化走势
从训练曲线可以看出,GRPO的reward呈现更加稳定的上升趋势,达到4左右,说明GRPO本身能更好地利用RLAIF信号。Policy Loss整体下降平稳,相比PPO的双网络优化,GRPO单网络架构训练更稳定且收敛上限更高。
7.3 Clipped Importance Sampling Policy Optimization
我自己在众多眼花缭乱的XXPO里反而对它印象很深,CISPO没有重新发明一整套复杂框架,而是抓住了 PPO/GRPO 里一个长期让人别扭的问题——ratio 被 clip 之后,梯度流直接就被硬截断了。 CISPO 的关注点并不是重新设计 group baseline,而是用非常小的 loss 改动,更直接地修正这个问题。
CISPO损失:
$$\mathcal{L}_{CISPO} = -\mathbb{E}\left[\min(r_t, \varepsilon_{\mathrm{high}}) \cdot A_t \cdot \log \pi_\theta(a_t|s) - \beta \cdot \text{KL}_t\right]$$其中:
- 策略项: $f(r_t) = \min(r_t, \varepsilon_{\mathrm{high}}) \cdot \log \pi_\theta(a_t|s)$ (ratio 只作为裁剪后的权重)
- 优势项: $g(A_{i,j}) = \frac{R_{i,j} - \mu_i}{\sigma_i + \epsilon}$ (可直接沿用 GRPO 的组内相对优势)
- 正则项: $h(\text{KL}_t) = \beta \cdot \text{KL}_t$ (token级KL散度约束)
CISPO在GRPO基础上,把原本容易被clip成常数的策略项改写成“裁剪权重 × log 概率”的形式。这样ratio即使被截断,也不会把梯度路径一起截断。因此可以直接把CISPO视作GRPO的loss变体来实现,而不是单独维护一套独立脚本。这里不再单列实验。只需在 train_grpo.py 把 loss_type 配置为 cispo,其余训练流程仍沿用 GRPO 的分组采样、奖励计算与优势构造逻辑即可。
7.4 Agentic RL 🔥
“Agentic”的概念其实很大,所以这里说的 Agentic 只能是一个相对狭义的版本:它更聚焦于让 MiniMind 这样的~百M小模型在有限工具集上学会基础的调用、观察与再规划能力,而不是去覆盖完整 Agent 系统里更大范围的状态管理、长期记忆与复杂工作流编排。
2026-03 起,仓库新增 train_agent,开始支持一种更贴近真实交互流程的多轮 Tool-Use RL。这是我自己很喜欢的一个训练脚本:它把 RLVR / RLAIF 风格的数据组织方式与 online RL 的 rollout 过程揉在了一起,中间来回调过很多版,也踩过收敛失败、奖励 hack、多轮上下文错位之类的 bug,最后仍然保持了 MiniMind 一贯的简洁性和可读性。
此部分的数据为 agent_rl.jsonl / agent_rl_math.jsonl。它们相比普通对话数据多了 gt 作为最终校验目标;若把一条样本记作 $(x, \mathcal{T}, gt)$,那么训练时优化的对象就不再是单轮回答 $y$,而是一条多轮轨迹 $\tau$:
其中 chat_template 统一组织 tools / tool_calls / tool 消息;若某一步生成了 tool_call,就执行工具并把 observation 拼回上下文,再继续 rollout。
主线流程可以压缩成:
$$ \texttt{rollout batch} \rightarrow \texttt{calculate rewards} \rightarrow \texttt{policy update} $$reward 也是对整条轨迹联合打分:
$$ R(\tau) = R_{\text{answer}} + R_{\text{tool}} + R_{\text{format}} + R_{\text{rm}} - R_{\text{unfinished}} $$这里同时考虑工具调用合法性、gt 命中、格式闭合、未完成惩罚与 Reward Model 分数。和普通 PPO / GRPO 相比,这里是多轮 rollout、延迟 reward。
训练方式:
|
|
|
|
训练后的模型权重文件默认每隔
save_interval步保存为:agent_*.pth
MiniMind 在 Agentic RL 训练阶段的优化走势
这里顺带提一下 rollout_engine。所谓“训推分离”,就是把 参数更新 和 轨迹展开 拆开:训练侧负责优化 policy,rollout 侧负责高吞吐采样,对上统一表现为“给我 prompt,我返回 rollout 结果;训练完以后,再把新权重同步回来”。因此训练脚本并不需要关心底层到底是本地 generate 还是远端 inference 引擎。需要说明的是,当前实现仍是同步模式(采样完一批再更新),还不是纯 rollout buffer 的异步训练。
MiniMind 中训练侧、轨迹侧与 rollout 侧解耦的 RL 结构示意图
如果类比到更大规模系统里,它其实已经具备 openrlhf/verl/slime 等大规模RL框架的味道:
- 左边是训练侧,负责 policy 更新
- 右边是 rollout / inference 侧,负责吞吐采样
- 中间通过轨迹与权重同步完成衔接
- 工具执行与环境反馈本身不直接进入 loss,但会直接影响整条轨迹的 reward 质量
所以我自己会把这套实现视为 MiniMind 里一个很有意思的过渡版本:虽然还远不是工业级 Agent 训练框架,但已经把 模板组织、工具执行、多轮 rollout、延迟奖励、训推分离 这些关键元素真正实现了最小串联(也许目前没有比它更简洁的了)。
|
|
基于AgentRL训练结果测试,支持思考展示、工具选择与多轮 Tool Use 交互
🖊️ RL小结
我们收束回“统一框架”:不同 PO 算法本质上只是对三个核心组件的不同实例化,见下表。
| 算法 | 策略项 $f(r_t)$ | 优势项 $g(A_t)$ | 正则项 $h(\text{KL}_t)$ | 训练模型数 |
|---|---|---|---|---|
| DPO | $\log r_w - \log r_l$ | 无显式优势项 | 隐含在 $\beta$ 中 | 1 (前向参与 2) |
| PPO | $\min(r_t \cdot A_t, \mathrm{clip}(r_t, 1-\varepsilon, 1+\varepsilon) \cdot A_t)$ | $A_t$(通常由 Critic 估计,也可以使用 GAE) | $\beta \cdot \mathbb{E}[\text{KL}]$ | 2 |
| GRPO | $\min(r_t \cdot A_t, \mathrm{clip}(r_t, 1-\varepsilon, 1+\varepsilon) \cdot A_t)$ | $A_{i,j}=\frac{R_{i,j}-\mu_i}{\sigma_i+\epsilon}$ | $\beta \cdot \text{KL}_t$ | 1 |
| CISPO | $\mathrm{clip}(r, 0, \varepsilon_{\mathrm{high}}) \cdot A_t \cdot \log \pi_\theta$ | $\frac{R - \mu}{\sigma}$ | $\beta \cdot \text{KL}_t$ | 1 |
说白了,这些 RL 算法不是割裂独立的,而是在统一优化视角下,对同一目标函数进行不同设计权衡后形成的自然变体,呈现为一种优美自洽的统一。
Ⅴ 训练结果开源 📦
① PyTorch模型 (ModelScope | HuggingFace)
注:模型权重以实际 release 为准。并非所有训练阶段或实验分支(如 DPO、PPO、GRPO、CISPO、Agent、LoRA 等)的权重都会持续维护并单独公开;部分权重仅用于实验验证或学习用途,随着数据迭代或模型调整,逐一同步更新所有版本的必要性有限,且会带来较高的维护与训练成本。
Torch文件命名对照
-
Dense:
- Pretrain:
pretrain_{hidden_size}.pth - SFT:
full_sft_{hidden_size}.pth - DPO:
dpo_{hidden_size}.pth - PPO:
ppo_actor_{hidden_size}.pth - GRPO:
grpo_{hidden_size}.pth - Agent:
agent_{hidden_size}.pth - LoRA:
lora_xxx_{hidden_size}.pth
- Pretrain:
-
MoE:
- 对应同名权重在末尾追加了
_moe后缀,例如:pretrain_{hidden_size}_moe.pth、full_sft_{hidden_size}_moe.pth
- 对应同名权重在末尾追加了
② Transformers模型 (ModelScope | HuggingFace)
注:如无特殊说明,
transformers版本通常由full_sft权重转换而来。RL 类后训练更偏向围绕特定奖励目标优化,虽然通常能提升 reward score,但会牺牲部分通用能力和知识;这类 reward hacking / capability trade-off 在所有模型上都很难避免,更多是程度上的差异。
📌 评估
Ⅰ RL模型对比
基于minimind-3 (64M)在相同随机种子等超参下的主/客观对比,供参考:
[A] minimind-3 (64M, SFT)
[B] minimind-3 (64M, GRPO)
[C] minimind-3 (64M, Agent-CISPO)
测试1:主观问答对比
|
|
测试2:轻 Agent 任务对比
一个基于 eval_toolcall 脚本改出来的测试,用一组数学 ToolUse 任务,对比当前 agent 权重和 full_sft 权重的表现:
|
|
👉 综合评价1
从这组结果看,当前 agent 相比 full_sft,在带工具调用的轻量 Agent 任务上已经明显拉开差距了。尤其是这类“先决定要不要调工具,再把可验证结果做对”的题型里,agent 的成功率更高,说明 RL 之后模型在 ToolUse 这条线上确实学到了更强的调用与利用能力。
但这个提升并不是没有代价。agent 更适合这类轻 Agent / ToolUse 场景,并不意味着它在通用问答上也同步变强。实际体验里,这类权重在事实性问题上的稳定性通常会下降一些,知识幻觉也会更明显,更容易出现“工具任务做得更好,但开放问答反而更敢编”的现象。
所以如果任务目标是 ToolUse、轻量多步调用、可验证求解,那么当前 agent 会比 full_sft 更合适;但如果更看重日常聊天、知识问答的事实性和整体稳健性,full_sft 仍然会是更稳一点的选择。往大一点看,这其实也是当前业界后训练模型里很常见的一类现象:后训练往往能把某一条能力线拉得很高,但几乎都会伴随比较明显的“对齐税”。也就是说,模型在特定奖励目标上变强的同时,通常会牺牲掉一部分通用性、事实性或者自然分布下的稳定性。这个问题并不新,也很难彻底避免,本质上就是优化目标变窄之后,模型会越来越擅长“迎合当前奖励定义”,却不一定等价于整体能力无损提升。
Ⅱ 与其他模型对比
注:以下对比仅为体验参考,非严格 benchmark,样本量有限且带有主观性。
[A] minimind-3 (0.06B)
[B] minimind-3-moe (0.2B-A0.06B)
[C] baby-llama2-chinese (0.2B)
[D] chatlm-mini-chinese (0.2B)
测试3:问答
|
|
🙋直接把以上所有问题和模型的回答丢给 GPT-5.4 Thinking,让它帮忙点评和排名打分:
具体点评
|
|
| 排名 | 模型 | 准确性 (30分) | 完整性 (30分) | 逻辑性 (20分) | 代码质量 (20分) | 总分 (100分) |
|---|---|---|---|---|---|---|
| 1 | B | 11 | 23 | 16 | 18 | 68 |
| 2 | D | 25 | 19 | 15 | 3 | 62 |
| 3 | A | 10 | 21 | 13 | 17 | 61 |
| 4 | C | 8 | 6 | 5 | 2 | 21 |
👉 综合评价2
从主观观感而言,会把 minimind-3-moe 放第一,chatlm-mini-chinese 放在第二,minimind-3 放在第三,baby-llama2-chinese 第四。B 虽然在知识准确性上幻觉严重(大熊猫吃海产品),但胜在表达流畅、结构清晰、代码题实现正确,综合输出质量最高;D 的知识储备明显领先(牛顿1687年、长江发源地等全部正确),但代码题条件写反导致完全不可用,摘要题也直接放弃,拖了不少后腿;A 和 B 风格接近,代码同样可用,但稳定性和知识准确性都不如 B,属于"什么都能说两句但细看全在编"的典型;C 则在事实性、展开能力和整体可读性上都有明显差距,仅在最简单的事实题上偶尔答对。值得注意的是,D 和 A 的总分非常接近(62 vs 61),但优劣势分布几乎是互补的:D 赢在知识准确性(25 vs 10),A 赢在代码能力(17 vs 3)。这其实也反映了小参数模型的一个典型现象——在有限的参数预算下,“说得好"和"说得对"往往很难兼得。
Ⅳ RoPE长度外推
MiniMind 支持通过 YaRN 算法进行 RoPE 位置编码的长度外推,使模型能够更稳定地处理超出训练长度的文本序列。
原生 torch 模型在使用 eval_llm.py 进行推理时,只需添加 --inference_rope_scaling 参数即可启用 RoPE 外推:
|
|
对于 Transformers 格式的模型,则可以在 config.json 中添加以下配置实现长度外推:
|
|
下面以 MiniMind 为例,使用不同长度的《西游记》白话文本作为输入,对比启用 RoPE scaling 前后的困惑度(PPL)变化。可以看到,在长文本场景下,启用 YaRN 外推后模型的 PPL 明显下降:
MiniMind 在不同文本长度下启用 YaRN 前后的 PPL 对比
Ⅴ 客观评测
下面就到喜闻乐见的 benchmark 环节,这里选取了一些微型模型进行横评比较,测试集选择 C-Eval、CMMLU、ARC-Easy、PIQA、OpenBookQA、HellaSwag、Social-IQa(除了前 2 个都是英文数据集)。
测评框架选择lm-evaluation
|
|
|
|
注:这类选择题测评通常不是让模型自由生成完整答案,而是给定题目上下文
y和若干候选项x,直接比较各候选项的条件概率p(x | y),并取概率最大的选项作为预测结果。若候选项只对应单个token,那么直接比较该token的预测概率即可;若候选项会分成多个token,那么更常见的做法是比较整段候选项的条件对数概率之和。这里的候选项并不一定是A、B、C、D,有些数据集也可能只有两个选项。因此从结果上看,随机作答的准确率往往就是很强的下界,而这个量级的模型也确实长期徘徊在这个附近。
MiniMind 的数据规模远小于表中其他模型,且训练比例偏向中文,因此英文表现不佳,此外默认没有专门针对这类选择题评测格式做对齐微调,所以表现会相对弱,结果仅供娱乐:
| model name | from | params | zh (ceval / cmmlu) | en (arc / piqa / obqa / hellaswag / siqa) |
|---|---|---|---|---|
| minimind-3 | current | 64M | 24.89 / 25.38 | 28.49 / 50.65 / 23.60 / 28.28 / 34.19 |
| minimind-3-moe | current | 198M | 25.48 / 24.32 | 27.74 / 50.71 / 26.20 / 27.43 / 34.03 |
| minimind-3-exam | current | 64M | 30.98 / 26.12 | 35.61 / 56.26 / 24.20 / 28.40 / 34.19 |
| Steel-LLM | ZhanShiJin | 1121M | 24.89 / 25.32 | 39.69 / 65.13 / 26.00 / 35.73 / 39.15 |
| gpt2-medium | OpenAI | 360M | 23.18 / 25.00 | 43.60 / 66.38 / 30.20 / 39.38 / 39.10 |
| TinyLlama-1.1B | TinyLlama | 1100M | 25.71 / 25.03 | 54.80 / 74.43 / 35.60 / 60.38 / 43.09 |
| SmolLM2-135M | HuggingFace | 135M | 24.44 / 24.71 | 58.50 / 68.17 / 32.80 / 43.15 / 39.46 |
| Aquila-135M | BAAI | 135M | 25.19 / 25.10 | 54.59 / 67.52 / 34.40 / 41.67 / 39.66 |
补充说明(来源/无污染/复现)
minimind-3-exam 不是更大的基座模型,也几乎没有额外注入新知识。它仅基于 minimind-3 在 lora_exam.jsonl 上做了一次轻量 LoRA 对齐,再将 lora_exam_768.pth 合并回基模后的结果。这部分数据由 ceval 与 mmlu (英文) 的 test 子集抽样构成,并做了前缀、后缀等格式增强,主要作用是对齐选择题评测中常见的上下文与候选项组织形式,而不是学习题目答案。
本节评估所用的 7 个数据集与上述对齐数据无样本交集,因此可以认为不存在数据污染。相反,若直接在有交集的数据上微调,这类小模型的分数往往会明显失真;例如 minimind-3 在有污染的 ceval / cmmlu 子集上实验跑到过约 97% 准确率,但这种结果没有参考意义。
这个实验想说明的只是:对这类评测,小模型的瓶颈未必完全在知识本身,也可能在于输入格式没有对齐。仅做少量格式对齐后,minimind-3-exam 在上面 7 个任务上平均提升约 2.9 个百分点。
📌 其他
🔧 模型转换
- ./scripts/convert_model.py 可用于
torch / transformers两种模型格式之间的相互转换。 - 如无特殊说明,
MiniMind主线发布的开源模型通常以Transformers格式提供;若使用原生torch权重,请先执行torch2transformers转换。
🖥️ 基于 MiniMind 的 API 服务接口
-
./scripts/serve_openai_api.py 提供了一个兼容 OpenAI API 的轻量聊天服务,便于将自己的模型接入 FastGPT、OpenWebUI、Dify 等第三方 UI。
-
当前接口额外支持
reasoning_content、tool_calls、open_thinking等字段,适合直接用于 Tool Calling / Thinking 场景。 -
从 HuggingFace 下载模型权重后,目录结构示例如下:
1 2 3 4 5 6 7 8 9minimind (root dir) ├─<MiniMind-Model-Name>(例如minimind-3) | ├── config.json | ├── generation_config.json | ├── model_minimind.py (可选,取决于模型导出形式) | ├── pytorch_model.bin or model.safetensors | ├── special_tokens_map.json | ├── tokenizer_config.json | ├── tokenizer.json -
启动服务端
1cd scripts && python serve_openai_api.py -
测试服务接口
1cd scripts && python chat_api.py -
API 请求示例(兼容 OpenAI API 格式)
1 2 3 4 5 6 7 8 9 10 11 12curl http://localhost:8998/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "model-identifier", "messages": [ { "role": "user", "content": "世界上最高的山是什么?" } ], "temperature": 0.7, "max_tokens": 1024, "stream": true, "open_thinking": true }'
SGLang
SGLang 是高性能大模型推理引擎,支持 RadixAttention、连续批处理等优化技术,能够提供较低延迟与较高吞吐。
⚠️ 需要 CUDA 环境,按需使用。也可在 RL 训练脚本中选择 SGLang 作为 rollout / 推理引擎以提升训练吞吐。
以 OpenAI-compatible API server 形式启动模型:
|
|
vllm
vLLM 是目前非常常用的高效推理框架,适合快速部署大模型,并在显存利用率与吞吐量之间取得较好平衡。
⚠️ 需要 CUDA 环境,按需使用。
以 OpenAI-compatible API server 形式启动模型:
|
|
llama.cpp
llama.cpp 是一个轻量且实用的 C++ 推理框架,可直接在命令行中使用,支持多线程推理,也支持部分 GPU 加速方案。
目录结构:建议将 llama.cpp 与模型目录放在同级路径下
|
|
0、参考 llama.cpp 官方文档完成安装(如 cmake 等依赖)
1、在 convert_hf_to_gguf.py 的 get_vocab_base_pre 函数末尾插入:
|
|
2、将 HuggingFace 格式的 minimind 模型转换为 GGUF:
|
|
3、量化模型(可选)
|
|
4、命令行推理测试
|
|
ollama
Ollama 是本地运行大模型的常用工具,支持多种开源 LLM,使用方式简洁,部署门槛较低。
1、通过 Ollama 加载自定义 GGUF 模型
在模型目录下新建 minimind.modelfile 文件,并写入如下配置模板:
minimind.modelfile (template)
|
|
2、加载并命名本地模型
|
|
3、启动推理
|
|
📤 推送你的模型到 Ollama Hub
|
|
⭐️ 也可以直接使用我提供的 Ollama 模型快速启动:
|
|
MNN
MNN 是面向端侧的 AI 推理引擎,支持多种开源 LLM 的轻量化部署与高性能推理。
- 模型转换
|
|
- 在 Mac 或手机端测试
|
|
或者下载 APP 进行测试
以上第三方框架的更多用法请参考对应官方文档😊
👨💻 更多内容
📌 致谢
[!NOTE] 如果
MiniMind系列项目对您有所帮助,欢迎在 GitHub 上点亮一个 ⭐
文档篇幅较长,难免存在疏漏之处,欢迎通过 Issues 交流反馈,或提交 PR 一起改进项目
您的支持与建议,都是这个项目持续迭代的重要动力!
🤝贡献者
😊鸣谢
感谢以下贡献者在训练记录、数据处理、教程整理与项目拆解等方面提供的帮助与分享:
致谢以下优秀的论文与项目:
- https://github.com/meta-llama/llama3
- https://github.com/karpathy/llama2.c
- https://github.com/DLLXW/baby-llama2-chinese
- DeepSeek-V2
- https://github.com/charent/ChatLM-mini-Chinese
- https://github.com/wdndev/tiny-llm-zh
- Mistral-MoE
- https://github.com/Tongjilibo/build_MiniLLM_from_scratch
- https://github.com/jzhang38/TinyLlama
- https://github.com/AI-Study-Han/Zero-Chatgpt
- https://github.com/xusenlinzy/api-for-open-llm
- https://github.com/HqWu-HITCS/Awesome-Chinese-LLM
🫶支持者
🎉 MiniMind 相关成果
本模型抛砖引玉地促成了一些可喜成果的落地,感谢研究者们的认可:
-
ECG-Expert-QA: A Benchmark for Evaluating Medical Large Language Models in Heart Disease Diagnosis [arxiv]
-
Binary-Integer-Programming Based Algorithm for Expert Load Balancing in Mixture-of-Experts Models [arxiv]
-
LegalEval-Q: A New Benchmark for The Quality Evaluation of LLM-Generated Legal Text [arxiv]
-
On the Generalization Ability of Next-Token-Prediction Pretraining [ICML 2025]
-
《从零开始写大模型:从神经网络到Transformer》王双、牟晨、王昊怡 编著 - 清华大学出版社
-
FedBRB: A Solution to the Small-to-Large Scenario in Device-Heterogeneity Federated Learning [TMC 2025]
-
SKETCH: Semantic Key-Point Conditioning for Long-Horizon Vessel Trajectory Prediction [arxiv]
-
A Built-in Crypto Expert for Artificial Intelligence: How Far is the Horizon? [IACR ePrint 2026]
-
RetryTrigger: Intelligent Inference Duplication for Enhancing LLM Resilience to Hardware Transient Faults [FITEE 2026]
-
进行中…
🎓 引用
如果 MiniMind 对您的研究或工作有所帮助,欢迎引用:
|
|
⚖️ 开源协议
本项目采用 Apache License 2.0 开源协议。