# minimind-v1-small **Repository Path**: zhu-wanming/minimind-v1-small ## Basic Information - **Project Name**: minimind-v1-small - **Description**: - 首先声明。本项目基于开源项目:**MiniMind**,基于个人的理解和踩坑。做了个人的理解和注释。完成从小白开始,从0训练一个LLM大语言模型。项目源地址:https://github.com/jingyaogong/minimind - **MiniMind**极其轻量,力求做到最普通的个人GPU也可快速推理甚至训练。 - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 2 - **Forks**: 0 - **Created**: 2025-02-08 - **Last Updated**: 2025-03-29 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 普通人从0开始训练LLM大语言模型 - 首先声明。本项目基于开源项目:**MiniMind**,基于个人的理解和踩坑。做了个人的理解和注释。完成从小白开始,从0训练一个LLM大语言模型。项目源地址:https://github.com/jingyaogong/minimind - **MiniMind**极其轻量,力求做到最普通的个人GPU也可快速推理甚至训练。 - **MiniMind**发布了大模型极简结构,数据集清洗和预处理、监督预训练(Pretrain)、有监督指令微调(SFT)、低秩自适应(LoRA) 微调,无奖励强化学习直接偏好对齐(DPO)的全阶段代码,也包含拓展共享混合专家(MoE) 的稀疏模型。 - 这不仅是一个开源模型的实现,也是入门大语言模型(LLM)的教程。希望此项目能为研究者提供一个抛砖引玉的入门示例,帮助大家快速上手并对LLM领域产生更多的探索与创新。 ## 前言 大语言模型(LLM)领域,如 GPT、LLaMA、GLM 等,虽然它们效果惊艳, 但动辄10 Bilion庞大的模型参数个人设备显存远不够训练,甚至推理困难。 几乎所有人都不会只满足于用Lora等方案fine-tuing大模型学会一些新的指令, 这约等于在教牛顿玩21世纪的智能手机,然而,这远远脱离了学习物理本身的奥妙。 此外,卖课付费订阅的营销号漏洞百出的一知半解讲解AI的教程遍地, 让理解LLM的优质内容雪上加霜,严重阻碍了学习者。 因此,本项目的目标是把上手LLM的门槛无限降低, 直接从0开始训练一个极其轻量的语言模型。 Tip (截至2025-2-8)MiniMind系列已完成了1个型号微小模型的预训练,最小仅需26M(0.02B),即可具备流畅的对话能力! | 模型 (大小) | tokenizer长度 | 推理占用 | release | 主观评分(/100) | | ----------------------- | ------------- | -------- | ---------- | ---------------- | | minimind-v1-small (26M) | 6400 | 0.5 GB | 2025.02.08 | 50' | 该分析在具有Torch 2.1.2、CUDA 12.6 和 NVIDIA GeForce RTX 4060 Laptop GPU上进行。没错,是在本人的笔记本上进行的。 项目包含: - 公开MiniMind模型代码(包含Dense和MoE模型)、Pretrain、SFT指令微调、LoRA微调、DPO偏好优化的全过程代码、数据集和来源。 - 兼容`transformers`、`accelerate`、`trl`、`peft`等流行框架。 - 训练支持单机单卡、单机多卡(DDP、DeepSpeed)训练,使用wandb可视化训练流程。支持在任意位置停止,及在任意位置继续训练。 - 在Ceval数据集上进行模型测试的代码。 - 实现Openai-Api基本的chat接口,便于集成到第三方ChatUI使用(FastGPT、Open-WebUI等)。 希望此开源项目可以帮助LLM初学者快速入门! ## 基础环境 仅是我个人的软硬件环境配置,自行推理或训练,请自行酌情更改: ``` CPU: Intel(R) Core(TM) i7-13620H 内存:32 GB 显卡:NVIDIA GeForce RTX 4060 Laptop GPU 环境:python 3.10 + Torch 2.1.2 + DDP单机多卡训练 系统:win11专业工作站版本 + Anaconda3-2024.02-1-Windows-x86_64 ``` ## 初始化环境安装 本次推理和训练,均采用Anaconda3部署环境,环境要求: ``` # 初始化虚拟环境 conda create -n minimind-v1 python=3.10 # 激活环境 conda activate minimind-v1 # 配置conda环境为国内源,可自行更改 # 设置清华源 conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/free/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/pkgs/main/ conda config --add channels https://mirrors.tuna.tsinghua.edu.cn/anaconda/cloud/conda-forge/ # 部署torch pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu126 # 测试torch是否可用cuda # python解释器下进行 import torch print(torch.cuda.is_available()) ``` cuda、python和操作系统是有严格的关联关系。torch如果不可用,请自行去https://pytorch.org/get-started/locally/ 下载对应的版本。 ## 启动训练 ### 1、克隆项目代码 ``` git clone https://gitee.com/zhu-wanming/minimind-v1-small.git ``` ### 2、环境安装 ``` pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple # 注意torch请根据自身设备情况,安装对应版本 ``` ### 3、下载数据集 - git代码里不包含训练所需的数据集(太大了)。相关数据集我会在下面提供下载方式和对应说明,请自行挂魔法下载。数据集放到`./dataset`目录下 | MiniMind训练数据集 | 下载地址 | | ----------------------- | ------------------------------------------------------------ | | **【tokenizer训练集】** | [HuggingFace](https://huggingface.co/datasets/jingyaogong/minimind_dataset/tree/main) | | **【Pretrain数据】** | [Seq-Monkey官方](http://share.mobvoi.com:5000/sharing/O91blwPkY) / [HuggingFace](https://huggingface.co/datasets/jingyaogong/minimind_dataset/tree/main) | | **【SFT数据】** | [匠数大模型SFT数据集](https://www.modelscope.cn/datasets/deepctrl/deepctrl-sft-data/resolve/master/sft_data_zh.jsonl) | | **【DPO数据】** | [Huggingface](https://huggingface.co/datasets/jingyaogong/minimind_dataset/tree/main/dpo) | 对应下载的数据集信息如下: ``` 【tokenizer训练集】 tokenizer_train.jsonl 大概980M 【Pretrain数据】 pretrain_data.csv 大概4.33G 【SFT数据】 sft_data_zh.jsonl 大概16G 【DPO数据】 ./dpo/* 所有文件大概72M ``` 数据集下载完成后,我们可以开始训练任务了! **注意:关于训练模型的大小和精度,请在./model/LMConfig.py 中调整model的参数配置** **这里仅需调整dim和n_layers和use_moe参数,分别是(512+8)或(768+16),对应于minimind-v1-small和minimind-v1** ### 4、处理数据集 抽取sft_data_zh.jsonl sft数据集抽离qa到csv文件(例如pretrain数据提前进行token-encoder、sft数据集抽离qa到csv文件) ``` # 处理数据集 python data_process.py # 抽取数据时间大概5分钟左右。在./dataset 目录下生成 sft_data_single.csv 文件。 ``` ![](.\images\data_process.png) ### 5、预训练 对Pretrain数据 pretrain_data.csv 执行预训练,得到 pretrain_*.pth 作为预训练的输出权重 ``` python 1-pretrain.py # 因为本地显卡是笔记本型号,显存占用高且训练时间长,预训练时间大概9小时左右。训练完成会在./out 目录下生成pretrain_*.pth权重模型。 ``` ![](.\images\1-pretrain-1.png) ![](.\images\1-pretrain-2.png) ### 6、指令微调 执行指令微调,得到 full_sft_*.pth 作为指令微调的输出权重 ``` python 3-full_sft.py # 因为本地显卡是笔记本型号,显存占用高且微调时间长,微调时间大概9小时左右。微调完成会在./out 目录下生成full_sft_*.pth作为指令微调的输出权重。 ``` ![](.\images\3-full_sft-1.png) ![](.\images\3-full_sft-2.png) ### 7、执行lora微调(非必须) ``` python 4-lora_sft.py # 本次训练旨在快速训练一个LLM大语言小模型,此步骤可不做。后续完全熟悉后可自行调整处理。 ``` ### 8、执行DPO人类偏好强化学习对齐(非必须) ``` python 5-dpo_train.py # 本次训练旨在快速训练一个LLM大语言小模型,此步骤可不做。后续完全熟悉后可自行调整处理。 ``` 以上除了非必须步骤都完成后,专属于个人的LLM大语言小模型就已经训练完成了。接下来可以开始运行测试。 ## 测试LLM训练模型 ### 1、测试预训练模型的接龙效果 ``` python 0-eval_pretrain.py # 本次训练的LLM模型较小,执行推理测试时候,显存占用较低且速度极快。 ``` ![](.\images\0-eval_pretrain-1.png) ![](.\images\0-eval_pretrain-2.png) ### 2、连续对话测试 ``` python 2-eval.py ``` ![](.\images\2-eval.png) ### 3、启动网页聊天界面 ``` # 需要python>=3.10,安装 pip install streamlit==1.27.2 streamlit run fast_inference.py ``` ![](.\images\fast_inference-1.png) ![](.\images\fast_inference-2.png) ## 推理与导出 ### 1、导出模型 ``` python ./export_model.py # 可以导出模型到transformers格式,推送到huggingface ``` ### 2、API推理 ``` python my_openai_api.py # 完成了openai_api的聊天接口,方便将自己的模型接入第三方UI 例如fastgpt、OpenWebUI等 ``` - 模型可用自己的训练模型,也可从[Huggingface](https://huggingface.co/collections/jingyaogong/minimind-66caf8d999f5c7fa64f399e5)下载已经训练好了的模型权重文件 ``` minimind (root dir) ├─minimind | ├── config.json | ├── generation_config.json | ├── LMConfig.py | ├── model.py | ├── pytorch_model.bin | ├── special_tokens_map.json | ├── tokenizer_config.json | ├── tokenizer.json ``` - 启动聊天服务端 ``` python my_openai_api.py ``` - 测试服务接口 ``` python chat_openai_api.py ``` - API接口示例,兼容openai api格式 ``` curl http://ip:port/v1/chat/completions \ -H "Content-Type: application/json" \ -d '{ "model": "model-identifier", "messages": [ { "role": "user", "content": "世界上最高的山是什么?" } ], "temperature": 0.7, "max_tokens": -1, "stream": true }' ``` ## 评测 ``` C-Eval评测代码见:./eval_ceval.py ``` 小模型的测评通常为了避免回复格式的难以固定的特点, 而直接判断`A`,`B`,`C`,`D`四个字母对应token预测概率,取最大的作为回答答案,与标准答案计算正确率。 minimind模型本身没有使用较大的数据集训练,也没有针对回答选择题的指令做微调,测评结果可以当个参考。 > 例如minimind-small的结果细项: | Type | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | | ---- | -------------------------- | ---- | --------------------- | --------------------- | ------------------- | ------------------ | ------------------- | ------------------- | -------------- | ---------------------- | --------------------- | --------------------- | -------------- | ---------------- | ----- | ------------------- | ------------- | ------------------------------- | ------------------- | ---------- | ---------------- | ----------------------- | ------------------ | ------------------- | ------- | -------------------- | ----------------------- | ----------------------- | ------------------ | --------------------------------- | ----------------- | ----------------------- | ---------------------------------------- | --------------------- | ----------------------- | --------------- | ------------------------- | -------------------- | --------- | ----------------- | ------------------- | --------------------- | ---------------------- | ----------------- | ---------------- | -------------- | ----------- | --------------------- | -------------------- | ----------------- | ------------- | ----------------------- | | Data | probability_and_statistics | law | middle_school_biology | high_school_chemistry | high_school_physics | legal_professional | high_school_chinese | high_school_history | tax_accountant | modern_chinese_history | middle_school_physics | middle_school_history | basic_medicine | operating_system | logic | electrical_engineer | civil_servant | chinese_language_and_literature | college_programming | accountant | plant_protection | middle_school_chemistry | metrology_engineer | veterinary_medicine | marxism | advanced_mathematics | high_school_mathematics | business_administration | mao_zedong_thought | ideological_and_moral_cultivation | college_economics | professional_tour_guide | environmental_impact_assessment_engineer | computer_architecture | urban_and_rural_planner | college_physics | middle_school_mathematics | high_school_politics | physician | college_chemistry | high_school_biology | high_school_geography | middle_school_politics | clinical_medicine | computer_network | sports_science | art_studies | teacher_qualification | discrete_mathematics | education_science | fire_engineer | middle_school_geography | | Type | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | | -------- | ------ | ------ | ------ | ------ | ------ | ----- | ------ | ------ | ------ | ------ | ------ | ------ | ----- | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ------ | ----- | | T/A | 3/18 | 5/24 | 4/21 | 7/19 | 5/19 | 2/23 | 4/19 | 6/20 | 10/49 | 4/23 | 4/19 | 4/22 | 1/19 | 3/19 | 4/22 | 7/37 | 11/47 | 5/23 | 10/37 | 9/49 | 7/22 | 4/20 | 3/24 | 6/23 | 5/19 | 5/19 | 4/18 | 8/33 | 8/24 | 5/19 | 17/55 | 10/29 | 7/31 | 6/21 | 11/46 | 5/19 | 3/19 | 4/19 | 13/49 | 3/24 | 5/19 | 4/19 | 6/21 | 6/22 | 2/19 | 2/19 | 14/33 | 12/44 | 6/16 | 7/29 | 9/31 | 1/12 | | Accuracy | 16.67% | 20.83% | 19.05% | 36.84% | 26.32% | 8.70% | 21.05% | 30.00% | 20.41% | 17.39% | 21.05% | 18.18% | 5.26% | 15.79% | 18.18% | 18.92% | 23.40% | 21.74% | 27.03% | 18.37% | 31.82% | 20.00% | 12.50% | 26.09% | 26.32% | 26.32% | 22.22% | 24.24% | 33.33% | 26.32% | 30.91% | 34.48% | 22.58% | 28.57% | 23.91% | 26.32% | 15.79% | 21.05% | 26.53% | 12.50% | 26.32% | 21.05% | 28.57% | 27.27% | 10.53% | 10.53% | 42.42% | 27.27% | 37.50% | 24.14% | 29.03% | 8.33% | ``` 总题数: 1346 总正确数: 316 总正确率: 23.48% ``` 结果汇总: | category | correct | question_count | accuracy | | ----------------- | ------- | -------------- | -------- | | minimind-v1-small | 344 | 1346 | 25.56% | | minimind-v1 | 351 | 1346 | 26.08% | ## 验证 | Model Name | params | len_vocab | batch_size | pretrain_time | sft_single_time | sft_multi_time | | ----------------- | ------ | --------- | ---------- | ----------------- | ----------------- | ------------------- | | minimind-v1-small | 26M | 6400 | 64 | ≈2 hour (1 epoch) | ≈2 hour (1 epoch) | ≈0.5 hour (1 epoch) | | minimind-v1-moe | 4×26M | 6400 | 40 | ≈6 hour (1 epoch) | ≈5 hour (1 epoch) | ≈1 hour (1 epoch) | | minimind-v1 | 108M | 6400 | 16 | ≈6 hour (1 epoch) | ≈4 hour (1 epoch) | ≈1 hour (1 epoch) | ------ 1. **预训练(Text-to-Text)**: - LLM首先要学习的并非直接与人交流,而是让肚子中充满知识的墨水,至于墨水理论上喝的越饱越好,产生大量的对世界的认知积累。 - 预训练就是让Model先埋头苦学大量基本的知识,例如从维基百科、新闻、常识、书籍等。 - 它无监督的从大量的文本数据中压缩知识到自己模型的权重,目的是:学会词语接龙。例如我们输入“秦始皇是”四个字,它在大量学习后能预测出下一句话大概率是“中国的第一位皇帝”。 > pretrain的学习率设置为1e-4到1e-5的动态学习率,预训练epoch数设为5。 ``` torchrun --nproc_per_node 2 1-pretrain.py ``` 2. **单轮次对话有监督微调(Single dialog Fine-tuning)**: - 经过预训练,半成品LLM此时已经掌握了几乎所有的语言知识和百科常识。此时它还不会与人聊天,相反它只会无脑地进行输入词语的接龙,生成下一个词。 - 此时需要对半成品LLM做限制在聊天模板中进行微调,例如当它遇到这样的模板“<聊天开始>秦始皇是<聊天终止> ”后不再无脑接龙,而是意识到这是一段完整的对话结束。 - 我们称这个过程为指令微调,就如同让学富五车的「牛顿」先生适应21世纪的聊天习惯,学习屏幕左侧是对方消息,右侧是本人消息这个规律。 - 在训练时,MiniMind的指令和回答长度被截断在512,是为了节省显存空间。就像我们学习时,会先从短的文章开始,当学会阅读200字作文后,800字长文章就不需要再单独学习。 > 在推理时通过调整RoPE线性差值,实现长度外推到1024或2048及以上很方便。学习率设置为1e-5到1e-6的动态学习率,微调epoch数为6。 ``` # 3-full_sft.py中设置数据集为sft_data_single.csv torchrun --nproc_per_node 2 3-full_sft.py ``` 3. **多轮对话微调(Multi dialog Fine-tuning)**: - 在2的基础上,LLM已经学会一个问题->一个回答的聊天模板。此时仅需在具备历史问答的更长聊天模板上进一步微调即可。 - 我们仅需使用数据集的history_chat 字段,即历史对话,以及history_chat_response字段,即历史对话的回答。 - 构建【问题->回答,问题->回答,问题->】的新聊天模板,然后使用这个数据集进行微调。 - 学习完成的模型不仅仅只能回答当前问题,还能根据历史对话进行连贯的对话。 - 这一步 **并非必须** ,因为小模型长上文对话能力很弱,强行对齐多轮问答模板会损失一定程度的单轮SFT效果。 > 学习率设置为1e-5到1e-6的动态学习率,微调epoch数为5。 ``` # 3-full_sft.py中设置数据集为sft_data.csv torchrun --nproc_per_node 2 3-full_sft.py ``` 4. **人类反馈强化学习(RLHF)之-直接偏好优化(Direct Preference Optimization, DPO)**: - 在前面的训练中,GPT已经具备了基本的对话能力,但是这样的能力完全基于单词接龙,缺少正例反例的激励。 - GPT尚且未知什么回答是好的,什么是差的。我们希望它能够更符合人的偏好,给出更让人满意的回答。 - 这个过程就像是让GPT参加工作培训,从优秀员工的作为例子,消极员工作为反例,学习如何更好地服务客户。 - RLHF系列中,与PPO(Proximal Policy Optimization)这种需要奖励模型、价值模型的RL算法不同; - DPO通过推导PPO奖励模型的显式解,把在线奖励模型换成离线数据,ref输出可以提前保存。 - DPO性能几乎不变,只用跑 actor 和 ref 2 个模型,大大节省显存开销和增加训练稳定性。 - 同样的,LLM的RL步骤也 **并非必须**,有利也有弊。 > 活字三元组(q,chose,reject)数据集,学习率le-5,半精度fp16,共1个epoch,耗时1h。 ``` python 5-dpo_train.py ``` 📋关于LLM的参数配置,有一篇很有意思的论文[MobileLLM](https://arxiv.org/pdf/2402.14905)做了详细的研究和实验。 scaling law在小模型中有自己独特的规律。 引起Transformer参数成规模变化的参数几乎只取决于`d_model`和`n_layers`。 - `d_model`↑+`n_layers`↓->矮胖子 - `d_model`↓+`n_layers`↑->瘦高个 2020年提出Scaling Law的论文认为,训练数据量、参数量以及训练迭代次数才是决定性能的关键因素,而模型架构的影响几乎可以忽视。 然而似乎这个定律对小模型并不完全适用。 MobileLLM提出架构的深度比宽度更重要,「深而窄」的「瘦长」模型可以学习到比「宽而浅」模型更多的抽象概念。 例如当模型参数固定在125M或者350M时,30~42层的「狭长」模型明显比12层左右的「矮胖」模型有更优越的性能, 在常识推理、问答、阅读理解等8个基准测试上都有类似的趋势。 这其实是非常有趣的发现,因为以往为100M左右量级的小模型设计架构时,几乎没人尝试过叠加超过12层。 这与MiniMind在训练过程中,模型参数量在`d_model`和`n_layers`之间进行调整实验观察到的效果是一致的。 然而「深而窄」的「窄」也是有维度极限的,当d_model<512时,词嵌入维度坍塌的劣势非常明显, 增加的layers并不能弥补词嵌入在固定q_head带来d_head不足的劣势。 当d_model>1536时,layers的增加似乎比d_model的优先级更高,更能带来具有“性价比”的参数->效果增益。 因此MiniMind设定small模型的d_model=512,n_layers=8来获取的「极小体积<->更好效果」的平衡。 设定d_model=768,n_layers=16来获取效果的更大收益,更加符合小模型scaling-law的变化曲线。 > 作为参考,GPT3的参数设定见下表: ![](.\images\GPT3.png)