项目简介
MiniMind 是一个教学型开源项目,让个人在单张消费级显卡上约 2 小时即可从零训练出 64M 超小语言模型。项目基于原生 PyTorch 实现大模型极简结构与完整训练链路,涵盖 MoE、预训练、SFT、LoRA、DPO、RLAIF、Agentic RL、工具调用与模型蒸馏,并提供开源数据集、模型权重及对主流推理与训练框架的兼容支持。
README 预览
\n\n\n\n\n\n\n\n\n[](https://github.com/jingyaogong/minimind/stargazers)\n[](LICENSE)\n[](https://github.com/jingyaogong/minimind/commits/master)\n[](https://github.com/jingyaogong/minimind/pulls)\n[](https://huggingface.co/collections/jingyaogong/minimind-66caf8d999f5c7fa64f399e5)\n\n\n\n\n\n\n\n\n\n\n "大道至简"\n\n\n\n\n中文 | [English](./README_en.md)\n\n\n\n* 此开源项目旨在完全从 0 开始,仅用 3 块钱成本与 2 小时训练时间,即可训练出规模约为 64M 的超小语言模型 MiniMind。\n* MiniMind 系列极其轻量,主线最小版本体积约为 GPT-3 的 $\frac{1}{2700}$,力求让普通个人 GPU 也能快速完成训练与复现。\n* 项目同时开源了大模型的极简结构与完整训练链路,覆盖 MoE、数据清洗、预训练(Pretrain)、监督微调(SFT)、LoRA、RLHF(DPO)、RLAIF(PPO / GRPO / CISPO)、Tool Use、Agentic RL、自适应思考与模型蒸馏等全过程代码。\n* MiniMind 同时拓展了视觉模态模型 [MiniMind-V](https://github.com/jingyaogong/minimind-v)、多模态 Omni 模型 [MiniMind-O](https://github.com/jingyaogong/minimind-o)、扩散语言模型(MiniMind-dLM)、线性模型(MiniMind-Linear),详见 [Discussion](https://github.com/jingyaogong/minimind/discussions)。\n* 项目所有核心算法代码均从 0 使用 PyTorch 原生实现,不依赖第三方库提供的高层抽象接口。\n* 这不仅是一个大语言模型全阶段开源复现项目,也是一套面向 LLM 入门与实践的教程。\n* 希望此项目能为更多人提供一个可复现、可理解、可扩展的起点,一起感受创造的乐趣,并推动更广泛 AI 社区的进步。\n\n> 注:本项目基于 Apache 2.0 协议开源,完全免费。“2 小时” 指 SFT 阶段在单张 NVIDIA 3090 上跑完 `1 epoch` 的实测耗时,“3 块钱” 指对应时段的 GPU 租用成本。\n\n---\n\n\n\n\n\n[🔗 在线体验](https://www.modelscope.cn/studios/gongjy/MiniMind) | [🔗 视频介绍](https://www.bilibili.com/video/BV12dHPeqE72)\n\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n\n\n\n\n\n---\n\n# 📌 项目介绍\n\n大语言模型(Large Language Model, LLM)的出现,引发了全球范围内对 AI 的空前关注。无论是 ChatGPT、DeepSeek 还是 Qwen,都以惊艳的效果让人真切感受到这场技术浪潮的冲击力。然而,动辄数百亿参数的模型规模,使得它们对个人设备而言不仅难以训练,甚至连部署都显得遥不可及。打开大模型的“黑盒子”,真正去理解其内部运作机制,本应是一件令人心潮澎湃的事。遗憾的是,绝大多数探索最终都止步于使用 LoRA 等技术对现有大模型做少量微调,学习一些新指令或特定任务。这更像是在教牛顿如何使用 21 世纪的智能手机——虽然有趣,却偏离了理解物理本质的初衷。\n\n与此同时,第三方的大模型框架与工具库,如 `transformers` / `trl` / `peft` 等,往往只暴露出高度抽象的接口。只需短短十几行代码,就可以完成“加载模型 + 加载数据集 + 推理 + 强化学习”的全流程训练。这种高效封装固然便利,却也在一定程度上把开发者与底层实现隔离开来,削弱了深入理解 LLM 核心代码的机会。我认为 “用乐高自己拼出一架飞机,远比坐在头等舱里飞行更让人兴奋”,然而更现实的问题是,互联网上充斥着大量付费课程和营销内容,用漏洞百出常见问题 (3)
故障排除为什么在 Windows 上运行 train_agent.py 时,所有工具调用都返回 "tool not found" 错误?
根本原因:signal.SIGALRM 和 signal.alarm() 是 POSIX 专用的,在 Windows 上不存在。在 trainer/train_agent.py 中,execute_tool() 在一个裸 except: 内调用了 signal.signal(signal.SIGALRM, ...),因此产生的 AttributeError 被静默吞掉,函数返回 None。随后 rollout_single 会将这个 None 转换为每一次工具调用的 {"error": "tool not found"} —— 没有崩溃,也没有警告。这还会悄然破坏 Agentic RL 训练:格式奖励仍然正常计分,但主要的 ground-truth 奖励(权重 2.5)变得无法获得,因为模型永远看不到真实的工具结果。
修复(PR #847):更新到包含 trainer/trainer_utils.py 中基于 AST 的 safe_math_eval() 的版本。它替换了对模型生成字符串的原始 eval() 调用,并彻底移除了基于信号的超时机制(AST 求值器不可能进入无限循环,因此 signal.alarm 不再必要 —— 跨平台问题随之消失,无需任何平台防护)。同样的修复已应用到全部三个 eval() 调用点:trainer/train_agent.py、scripts/eval_toolcall.py 和 scripts/web_demo.py。
如果你停留在较旧的提交上,请应用以下最小化的跨平台补丁:
_HAS_ALARM = hasattr(signal, "SIGALRM")
def execute_tool(name, args):
fn = MOCK_RESULTS.get(name)
if not fn: return None
try:
if _HAS_ALARM:
signal.signal(signal.SIGALRM, lambda *_: (_ for _ in ()).throw(TimeoutError()))
signal.alarm(1)
return fn(args)
except Exception as e:
print(f"[tool] {name} failed: {type(e).__name__}: {e}")
return None
finally:
if _HAS_ALARM: signal.alarm(0)
关键规则:永远不要使用裸 except:(它隐藏了 AttributeError,使故障悄无声息),并且在跨平台代码中,始终用 hasattr(signal, 'SIGALRM') 来保护 signal.SIGALRM/signal.alarm。
故障排除如何解决在 24GB GPU(RTX 4090)上运行 train_agent.py 或 train_grpo.py 时出现的 CUDA Out of Memory (OOM) 错误?
有效训练批次大小为 batch_size × num_generations(Agent RL:2×4=8,GRPO:2×6=12),并且训练过程会同时加载 Policy 模型、Reference 模型以及一个 1.8B 的 Reward Model,因此 24GB 显存可能不足。解决方法:
1. 对于 train_agent.py,减小批次大小和总长度:
python train_agent.py --batch_size 1 --max_total_len 1536
2. 对于 train_grpo.py(没有 max_total_len 选项),减小批次大小、生成数量和序列长度:
python train_grpo.py --batch_size 1 --num_generations 4 --max_seq_len 512 --max_gen_len 768
3. 如果 PyTorch 报告大量“已保留但未分配的内存”(reserved but unallocated memory),可通过以下设置减少内存碎片:
export PYTORCH_CUDA_ALLOC_CONF=expandable_segments:True故障排除为什么在 MiniMind 中使用 YaRN rope_scaling 时,original_max_position_embeddings(2048)与预训练的 max_seq_len(340)不同?
original_max_position_embeddings 必须引用启用 YaRN 之前 checkpoint 实际训练所用的上下文长度——而不是 train_pretrain.py 中的值。MiniMind 的流程是:(1) 使用原始 RoPE 以 max_seq_len=340 进行预训练(YaRN 禁用);(2) 使用原始 RoPE 以 max_seq_len=2048 进行 Full SFT(YaRN 禁用——发布的 full_sft 权重是在 2048 个 token 上训练的,而不是快速 mini-dataset 复现脚本中使用的 768);(3) 启用 YaRN 进行推理,从 2048 窗口进行外推(例如 python eval_llm.py --weight full_sft --inference_rope_scaling)。因此,original_max_position_embeddings=2048 与 Full SFT checkpoint 相匹配。RoPE 本身是一种确定性的位置旋转,不包含可训练参数;需要训练的是模型权重对位置范围的适应,而这已经在 2048 token 的 Full SFT 阶段完成了。只有当你跳过 Full SFT,直接将 YaRN 应用于仅在长度 340 上训练的纯预训练 checkpoint 时,才应该设置 original_max_position_embeddings=340。