LLMs之minimind:minimind的简介、安装和使用方法、案例应用之详细攻略
导读:2024年8月27日发布MiniMind,MiniMind是一个轻量级开源语言模型,旨在降低LLM的上手门槛,提供从0开始训练LLM的完整流程和代码。它具有模型体积小、训练速度快、性能表现良好等特点,适合个人设备进行推理和训练。MiniMind最小仅需26M (0.02B),最大可达108M (0.1B)。最低仅需2G显卡即可推理训练,训练环境为RTX 3090 (24GB)。预训练约2小时 (1 epoch),指令微调约2小时 (1 epoch)。自定义的minimind_tokenizer词表大小为6400。
>> 性能表现:尽管模型非常小,但在对话能力上表现流畅。不同型号评分从50到60不等。
>> 数据构成:
● 预训练数据:使用Seq-Monkey通用文本数据集,约10B tokens。或 SkyPile-150B数据集的可公开访问部分。
● SFT数据:匠数大模型SFT数据集,10M条数据的中文数据集和包含2M条数据的英文数据集,约3B tokens。
● DPO数据:活字模型提供的人工标注的偏好数据,约8万条偏好数据。
>> 数据预处理流程及策略:数据需要经过预处理,包括token-encoder和抽离QA到CSV文件。采用自定义的minimind_tokenizer以控制词表长度,避免模型参数比例失衡。
>> 模型结构:
● MiniMind-Dense:基于Transformer的Decoder-Only结构。使用RMSNorm归一化(借鉴GPT-3)和SwiGLU激活函数。采用旋转位置嵌入(RoPE)。
● MiniMind-MoE: 基于Llama3和Deepseek-V2中的MixFFN混合专家模块,在FFN方面采用了更细粒度的专家分割和共享的专家隔离技术。
>> 优化策略:支持LoRA微调和DPO偏好优化。训练支持多卡加速(DDP+DeepSpeed),使用动态学习率进行微调。使用wandb可视化训练流程。
本开源项目旨在完全从0开始,最快仅用3小时!即可训练出仅为26M大小的微型语言模型MiniMind。MiniMind极其轻量,体积约是 GPT3 的1/7000,力求做到最普通的个人GPU也可快速推理甚至训练。MiniMind改进自DeepSeek-V2、Llama3结构,项目包含整个数据处理、pretrain、sft、dpo的全部阶段,包含混合专家(MoE)模型。这是一个既是开源项目,又是入门LLM教程,同时也是一个初具雏形的开源模型,希望能起到抛砖引玉的作用。
大语言模型(LLM)领域,如 GPT、LLaMA、GLM 等,虽然它们效果惊艳, 但动辄10 Bilion庞大的模型参数个人设备显存远不够训练,甚至推理困难。 几乎所有人都不会只满足于用Lora等方案fine-tuing大模型学会一些新的指令, 这约等于在教牛顿玩21世纪的智能手机,然而,这远远脱离了学习物理本身的奥妙。 此外,卖课付费订阅的营销号漏洞百出的一知半解讲解AI的教程遍地, 让理解LLM的优质内容雪上加霜,严重阻碍了学习者。因此,本项目的目标是把上手LLM的门槛无限降低,直接从0开始训练一个极其轻量的语言模型。
GitHub地址:GitHub - jingyaogong/minimind: 【大模型】3小时完全从0训练一个仅有26M的小参数GPT,最低仅需2G显卡即可推理训练!
2024-09-17 (new��):更新minimind-v1-moe模型。为了防止歧义,不再使用mistral_tokenizer分词,全部采用自定义的minimind_tokenizer作为分词器。
2024-09-01:更新minimind-v1 (108M)模型,采用minimind_tokenizer,预训练轮次3 + SFT轮次10,更充分训练,性能更强。
项目已部署至ModelScope创空间,可以在此网站上体验:
ModelScope在线体验
2024-08-27:项目首次开源
>> 公开MiniMind模型代码(包含Dense和MoE模型)、Pretrain、SFT指令微调、LoRA微调、DPO偏好优化的全过程代码、数据集和来源。
>> 兼容transformers、accelerate、trl、peft等流行框架。
>> 训练支持单机单卡、单机多卡(DDP、DeepSpeed)训练。训练过程中支持在任意位置停止,及在任意位置继续训练。
>> 在Ceval数据集上进行模型测试的代码。
>> 实现Openai-Api基本的chat接口,便于集成到第三方ChatUI使用(FastGPT、Open-WebUI等)。
(截至2024-9-17)minimind训练了3个型号模型,最小仅需26M(0.02B),即可具备流畅的对话能力!
模型 (大小)
tokenizer长度
推理占用
release
主观评分(/100)
minimind-v1-small (26M)
6400
0.5 GB
2024.08.28
50'
minimind-v1-moe (4×26M)
6400
1.0 GB
2024.09.17
55'
minimind-v1 (108M)
6400
1.0 GB
2024.09.01
60'
该分析在一个带有Torch 2.1.2、CUDA 12.2和Flash Attention 2的RTX 3090 GPU上运行。
仅是我个人的软硬件环境配置,自行酌情更改:
*0、环境安装
*1、克隆项目代码
*2、如果你需要自己训练
2.1 下载数据集下载地址放到./dataset目录下
数据集地址:GitHub - jingyaogong/minimind: 【大模型】3小时完全从0训练一个仅有26M的小参数GPT,最低仅需2G显卡即可推理训练!
2.2 python data_process.py处理数据集,例如pretrain数据提前进行token-encoder、sft数据集抽离qa到csv文件
2.3 在./model/LMConfig.py 中调整model的参数配置
2.4 python 1-pretrain.py 执行预训练
LLMs之minimind:minimind源码解读(pretrain.py)——实现基于Transformer架构的大规模语言模型预训练及wandb监控—支持余弦退火学习率调度/分布式预训练/自动混合精度优化/梯度累积/梯度裁剪/定期保存模型
https://yunyaniu.blog.csdn.net/article/details/142472414
2.5 python 3-full_sft.py 执行指令微调
2.6 python 4-lora_sft.py 执行lora微调(非必须)
2.7 python 5-dpo_train.py 执行DPO人类偏好强化学习对齐(非必须)
*3、测试模型推理效果
确保需要使用的,训练完成的参数权重位于./out/目录下
也可以直接去训练完成的模型权重下载使用我训练好的
python 0-eval_pretrain.py测试预训练模型的接龙效果
python 2-eval.py测试模型的对话效果 2-eval
【Tip】预训练和全参微调pretrain和full_sft均支持多卡加速
单机N卡启动训练(DDP)
单机N卡启动训练(DeepSpeed)
分词器
nlp中的Tokenizer类似于词典,将单词从自然语言通过“词典”映射到0,1,36这样的数字,可以理解为数字就代表了单词在“词典”中的页码。 LLM分词器的构建方式有两种:
T1、自训练:一种是自己构造词表训练一个分词器,代码可见;
T2、采用开源模型训练好的分词器:另一种是选择开源模型训练好的分词器。
“词典”当然可以直接选择用新华词典或是牛津词典,优点是token转化压缩率很好,但缺点是词表太长,动辄数十万个词汇短语; 也可以使用自己训练的分词器,优点是词表随意控制,缺点是压缩率不够理想,且生僻词不容易面面俱到。 当然,“词典”的选择很重要,LLM的输出本质上是SoftMax到词典N个词的多分类问题,然后通过“词典”解码到自然语言。 因为LLM体积非常小,为了避免模型头重脚轻(词嵌入embedding层参数占整个LLM比太高),所以词表长度需要选择比较小。 强大的开源模型例如01万物、千问、chatglm、mistral、Llama3等,它们的tokenizer词表长度如下:
[!TIP] 2024-09-17更新:为了防止过去的版本歧义&控制体积,minimind所有模型均使用minimind_tokenizer分词,废弃所有mistral_tokenizer版本。
尽管minimind_tokenizer长度很小,编解码效率弱于qwen2、glm等中文友好型分词器。 但minimind模型选择了自己训练的minimind_tokenizer作为分词器,以保持整体参数轻量,避免编码层和计算层占比失衡,头重脚轻,因为minimind的词表大小只有6400。 且minimind在实际测试中没有出现过生僻词汇解码失败的情况,效果良好。 由于自定义词表压缩长度到6400,使得LLM总参数量最低只有26M。
【Pretrain数据】:统一的JSONL格式→严格的筛选和去重→10B的token
Seq-Monkey通用文本数据集 / Seq-Monkey百度网盘 是由多种公开来源的数据(如网页、百科、博客、开源代码、书籍等)汇总清洗而成。整理成统一的JSONL格式,并经过了严格的筛选和去重,确保数据的全面性、规模、可信性和高质量。总量大约在10B token,适合中文大语言模型的预训练。
第2种选择:SkyPile-150B数据集 的可公开访问部分包含约2.33亿个独立网页,每个网页平均包含1000多个汉字。数据集包括大约1500亿个令牌和620GB的纯文本数据。 如果着急的话,可以尝试只挑选SkyPile-150B的部分jsonl下载(并在./data_process.py中对文本tokenizer生成* .bin文件),以便快速跑通预训练流程。
【SFT数据】:12M条, 包含10M条数据的中文数据集和包含2M条数据的英文数据集
匠数大模型SFT数据集 是一个完整、格式统一、安全的大模型训练和研究资源。 从网络上的公开数据源收集并整理了大量开源数据集,对其进行了格式统一,数据清洗, 包含10M条数据的中文数据集和包含2M条数据的英文数据集。 总量大约在3B token,适合中文大语言模型的SFT。 数据集整合来源于以下所有数据(仅供参考,因此无需单独下载,仅需下载一个完整的【SFT数据】):
- BelleGroup/train_3.5M_CN
- linkSoul/instruction_merge_set
- stingning/ultrachat
- BAAI/COIG-PC-core
- shibing624/sharegpt_gpt4
- shareAI/ShareGPT-Chinese-English-90k
- Tiger Research
- BelleGroup/school_math_0.25M
- YeungNLP/moss-003-sft-data
【DPO数据】:8万条
大约合并后共8万条dpo数据,人工标注的偏好数据,均来自活字模型 ,可以用于训练奖励模型,优化模型回复质量,使其更加符合人类偏好。
【更多数据集】
目前已经有HqWu-HITCS/Awesome-Chinese-LLM 在收集和梳理中文LLM相关的开源模型、应用、数据集及教程等资料,并持续更新这方面的最新进展。全面且专业,Respect!
数据集下载地址
下载到目录下
MiniMind的整体结构一致,只是在RoPE计算、推理函数和FFN层的代码上做了一些小调整。 其结构如下图(重绘版):
MiniMind-Dense
MiniMind-Dense(和Llama3.1一样)使用了Transformer的Decoder-Only结构,跟GPT-3的区别在于:
- 采用了GPT-3的预标准化方法,也就是在每个Transformer子层的输入上进行归一化,而不是在输出上。具体来说,使用的是RMSNorm归一化函数。
- 用SwiGLU激活函数替代了ReLU,这样做是为了提高性能。
- 像GPT-Neo一样,去掉了绝对位置嵌入,改用了旋转位置嵌入(RoPE),这样在处理超出训练长度的推理时效果更好。
MiniMind-Dense结构示意图—非常棒:Tokenizer Encoder→Input Embedding→TransformerLaye(MHSA+FFN)*k→RMSNorm→Linear→SoftMax→Tokenizer DecoderTo
MiniMind-MoE
MiniMind-MoE模型,它的结构基于Llama3和Deepseek-V2中的MixFFN混合专家模块。
- DeepSeek-V2在前馈网络(FFN)方面,采用了更细粒度的专家分割和共享的专家隔离技术,以提高Experts的效果。
MiniMind-MoE结构示意图:Tokenizer Encoder→Input Embedding→TransformerLaye(MHSA+MoE-FFN【共享专家+路由专家】)*k→RMSNorm→Linear→SoftMax
修改模型配置见./model/LMConfig.py。 minimind目前训练的模型版本见下表:
依赖环境
CPU: Intel(R) Core(TM) i9-10980XE CPU @ 3.00GHz 内存:128 GB 显卡:NVIDIA GeForce RTX 3090(24GB) * 2 环境:python 3.9 + Torch 2.1.2 + DDP多卡训练
耗时对比
预训练(Text-to-Text):动态学习率,epoch=5
pretrain的学习率设置为1e-4到1e-5的动态学习率,预训练epoch数设为5。
torchrun --nproc_per_node 2 1-pretrain.py
- LLM首先要学习的并非直接与人交流,而是让肚子中充满知识的墨水,至于墨水理论上喝的越饱越好,产生大量的对世界的认知积累。
- 预训练就是让Model先埋头苦学大量基本的知识,例如从维基百科、新闻、常识、书籍等。
- 它无监督的从大量的文本数据中压缩知识到自己模型的权重,目的是:学会词语接龙。例如我们输入“秦始皇是”四个字,它在大量学习后能预测出下一句话大概率是“中国的第一位皇帝”。
单轮次对话有监督微调(Single dialog Fine-tuning):RoPE+推到长度为2K,动态学习率,epoch=6
在推理时通过调整RoPE线性差值,实现长度外推到1024或2048及以上很方便。学习率设置为1e-5到1e-6的动态学习率,微调epoch数为6。
# 3-full_sft.py中设置数据集为sft_data_single.csv
- 经过预训练,半成品LLM此时已经掌握了几乎所有的语言知识和百科常识。此时它还不会与人聊天,相反它只会无脑地进行输入词语的接龙,生成下一个词。
- 此时需要对半成品LLM做限制在聊天模板中进行微调,例如当它遇到这样的模板“<聊天开始>秦始皇是<聊天终止> ”后不再无脑接龙,而是意识到这是一段完整的对话结束。
- 我们称这个过程为指令微调,就如同让学富五车的「牛顿」先生适应21世纪的聊天习惯,学习屏幕左侧是对方消息,右侧是本人消息这个规律。
- 在训练时,MiniMind的指令和回答长度被截断在512,是为了节省显存空间。就像我们学习时,会先从短的文章开始,当学会阅读200字作文后,800字长文章就不需要再单独学习。
多轮对话微调(Multi dialog Fine-tuning):动态学习率,epoch=5
学习率设置为1e-5到1e-6的动态学习率,微调epoch数为5。
# 3-full_sft.py中设置数据集为sft_data.csv
- 在2的基础上,LLM已经学会一个问题->一个回答的聊天模板。此时仅需在具备历史问答的更长聊天模板上进一步微调即可。
- 我们仅需使用数据集的history_chat 字段,即历史对话,以及history_chat_response字段,即历史对话的回答。
- 构建【问题->回答,问题->回答,问题->】的新聊天模板,然后使用这个数据集进行微调。
- 学习完成的模型不仅仅只能回答当前问题,还能根据历史对话进行连贯的对话。
- 这一步并非必须,因为小模型长上文对话能力很弱,强行对齐多轮问答模板会损失一定程度的单轮SFT效果。
直接偏好优化,强化学习微调(Direct Preference Optimization, DPO):
活字三元组(q,chose,reject)数据集,学习率le-5,半精度fp16,共1个epoch,耗时1h。
python 5-dpo_train.py
- 在前面的训练中,机器人已经具备了基本的对话能力。但是,我们希望它能够更符合人的偏好,给出更让人满意的回答。
- 这个过程就像是让机器人参加工作培训,从优秀员工的作为例子,消极员工作为反例,学习如何更好地服务客户。
LLM的参数配置
关于LLM的参数配置,有一篇很有意思的论文MobileLLM做了详细的研究和实验。 scaling law在小模型中有自己独特的规律。 引起Transformer参数成规模变化的参数几乎只取决于和。
- ↑+↓->矮胖子
- ↓+↑->瘦高个
2020年提出Scaling Law的论文认为,训练数据量、参数量以及训练迭代次数才是决定性能的关键因素,而模型架构的影响几乎可以忽视。 然而似乎这个定律对小模型并不完全适用。 MobileLLM提出架构的深度比宽度更重要,「深而窄」的「瘦长」模型可以学习到比「宽而浅」模型更多的抽象概念。 例如当模型参数固定在125M或者350M时,30~42层的「狭长」模型明显比12层左右的「矮胖」模型有更优越的性能, 在常识推理、问答、阅读理解等8个基准测试上都有类似的趋势。 这其实是非常有趣的发现,因为以往为100M左右量级的小模型设计架构时,几乎没人尝试过叠加超过12层。 这与MiniMind在训练过程中,模型参数量在和之间进行调整实验观察到的效果是一致的。 然而「深而窄」的「窄」也是有维度极限的,当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的参数设定见下表:
训练完成的模型权重
百度网盘
n_layers=8
n_layers=8
n_layers=16
测试多个版本模型的内容输出
以下测试于2024-09-17完成,此日期后发布的新模型,无特殊需要时将不加入测试。
[A] minimind-v1-small(0.02B)
[B] minimind-v1-moe(0.1B)
[C] minimind-v1(0.1B)
[D] baby-llama2-chinese(0.2B)
[E] chatlm-mini-chinese(0.2B)
Note
🙋♂️直接把上述模型的回答丢给GPT-4o,让它帮忙打个分:
基于GPT-4o的模型表现点评:
-
模型A:
- 表现:模型A的回答通常简洁明了,但在某些问题上缺乏详细信息和准确性。例如,在长江的长度问题上,模型A的回答是错误的。
- 评分:60
-
模型B:
- 表现:模型B的回答在某些问题上提供了额外的信息,但这些信息有时是不准确的或多余的。例如,在长江的长度问题上,模型B提供了不准确的长度和流域面积。
- 评分:65
-
模型C:
- 表现:模型C的回答通常较为详细,且在大多数问题上提供了准确的信息。例如,在长江和泰山的问题上,模型C的回答是准确的。
- 评分:75
-
模型D:
- 表现:模型D的回答在某些问题上显得混乱,且缺乏准确性。例如,在泰山的问题上,模型D的回答完全偏离了主题。
- 评分:50
-
模型E:
- 表现:模型E的回答通常非常详细,但在某些问题上过于冗长,且包含了一些不必要的信息。例如,在万有引力的问题上,模型E的回答过于复杂。
- 评分:70
排序(从高到低):
效果总结
-
minimind系列(ABC)的排序符合直觉,minimind-v1(0.1B)评分最高,常识性问题的回答基本没有错误和幻觉。
- 出乎意料的是,minimind-v1-small(0.02B)仅有26M参数,却可以接近minimind-v1(0.1B)的表现。
- minimind-v1(0.1B)的sft轮数仅有不到2,偷懒提前kill腾出资源给小模型,0.1B没有得到充分训练的情况下依然做到了最强,其实还是底大一级压死人。
- minimind-v1-moe(0.1B)表现只比minimind-v1-small(0.02B) 略好,同样是因为偷懒早停腾出资源做其它训练了,但是MoE模型这种稀疏多Experts模式需要的训练轮次需要酌情更高,让所有FFN层专家得到路由的激活充分训练,在目前epochs设置为3时训练的还不够充足。 minimind在早期实验验证阶段在Yi-Tokenizer上试验过moe的充分训练版本,可以做到比dense小模型表现肉眼可见地更好。此部分可能需要留给日后腾出服务器再训练并更新v2、v3版本。
-
E模型的回答肉眼看起来是非常不错的,尽管存在些许幻觉瞎编的情况。但GPT-4o和Deepseek的评分都一致认为它“信息过度冗长,且有重复内容,存在幻觉”。 其实这种评价略显严格,100个字中哪怕有10个字是幻觉,就很容易把它归到低分。由于E模型预训练文本长度更长,数据集大得多,所以回答的看起来很完备。在体积近似的情况下,数据数量和质量都很重要。
🙋♂️个人主观评价:E>C>B≈A>D
🤖 GPT-4o 评价:C>E>B>A>D
Scaling Law:模型参数越大,训练数据越多模型的性能越强。
Objective dataset: C-eval
LLMs之minimind:minimind源码解读(eval_ceval.py)——基于Transformer模型的自动化考试评估系统(C-eval)
https://yunyaniu.blog.csdn.net/article/details/142472364
C-eval评测代码见:, 小模型的测评通常为了避免回复格式的难以固定的特点, 而直接判断,,,四个字母对应token预测概率,取最大的作为回答答案,与标准答案计算正确率。 minimind模型本身没有使用较大的数据集训练,也没有针对回答选择题的指令做微调,测评结果可以当个参考。
例如minimind-small的结果细项:
结果汇总:
以下来自GPT-4o对minimind表现的瞎猜:
推理与导出
-
./export_model.py可以导出模型到transformers格式,推送到huggingface
-
MiniMind的huggingface集合地址: MiniMind
API推理
-
my_openai_api.py完成了openai_api的聊天接口,方便将自己的模型接入第三方UI 例如fastgpt、OpenWebUI等
-
从Huggingface下载模型权重文件
-
启动聊天服务端
-
测试服务接口
-
API接口示例,兼容openai api格式
在fastgpt中接入使用minimind api
本地快速推理和测试
# step 1
# step 2
# or step 3, use streamlit