Upload 6 files
Browse files- LMConfig.py +58 -0
- README.md +861 -0
- full_sft_512.pth +3 -0
- model.py +426 -0
- tokenizer.json +0 -0
- tokenizer_config.json +44 -0
LMConfig.py
ADDED
@@ -0,0 +1,58 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from transformers import PretrainedConfig
|
2 |
+
from typing import List
|
3 |
+
|
4 |
+
|
5 |
+
class LMConfig(PretrainedConfig):
|
6 |
+
model_type = "minimind"
|
7 |
+
|
8 |
+
def __init__(
|
9 |
+
self,
|
10 |
+
dim: int = 512,
|
11 |
+
n_layers: int = 8,
|
12 |
+
n_heads: int = 16,
|
13 |
+
n_kv_heads: int = 8,
|
14 |
+
vocab_size: int = 6400,
|
15 |
+
hidden_dim: int = None,
|
16 |
+
multiple_of: int = 64,
|
17 |
+
norm_eps: float = 1e-5,
|
18 |
+
max_seq_len: int = 512,
|
19 |
+
dropout: float = 0.0,
|
20 |
+
flash_attn: bool = True,
|
21 |
+
####################################################
|
22 |
+
# Here are the specific configurations of MOE
|
23 |
+
# When use_moe is false, the following is invalid
|
24 |
+
####################################################
|
25 |
+
use_moe: bool = False,
|
26 |
+
num_experts_per_tok=2,
|
27 |
+
n_routed_experts=4,
|
28 |
+
n_shared_experts: bool = True,
|
29 |
+
scoring_func='softmax',
|
30 |
+
aux_loss_alpha=0.01,
|
31 |
+
seq_aux=True,
|
32 |
+
norm_topk_prob=True,
|
33 |
+
**kwargs,
|
34 |
+
):
|
35 |
+
self.dim = dim
|
36 |
+
self.n_layers = n_layers
|
37 |
+
self.n_heads = n_heads
|
38 |
+
self.n_kv_heads = n_kv_heads
|
39 |
+
self.vocab_size = vocab_size
|
40 |
+
self.hidden_dim = hidden_dim
|
41 |
+
self.multiple_of = multiple_of
|
42 |
+
self.norm_eps = norm_eps
|
43 |
+
self.max_seq_len = max_seq_len
|
44 |
+
self.dropout = dropout
|
45 |
+
self.flash_attn = flash_attn
|
46 |
+
####################################################
|
47 |
+
# Here are the specific configurations of MOE
|
48 |
+
# When use_moe is false, the following is invalid
|
49 |
+
####################################################
|
50 |
+
self.use_moe = use_moe
|
51 |
+
self.num_experts_per_tok = num_experts_per_tok # 每个token选择的专家数量
|
52 |
+
self.n_routed_experts = n_routed_experts # 总的专家数量
|
53 |
+
self.n_shared_experts = n_shared_experts # 共享专家
|
54 |
+
self.scoring_func = scoring_func # 评分函数,默认为'softmax'
|
55 |
+
self.aux_loss_alpha = aux_loss_alpha # 辅助损失的alpha参数
|
56 |
+
self.seq_aux = seq_aux # 是否在序列级别上计算辅助损失
|
57 |
+
self.norm_topk_prob = norm_topk_prob # 是否标准化top-k概率
|
58 |
+
super().__init__(**kwargs)
|
README.md
ADDED
@@ -0,0 +1,861 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<div align="center">
|
2 |
+
|
3 |
+

|
4 |
+
|
5 |
+
</div>
|
6 |
+
|
7 |
+
<div align="center">
|
8 |
+
|
9 |
+

|
10 |
+
[](https://github.com/jingyaogong/minimind/stargazers)
|
11 |
+
[](LICENSE)
|
12 |
+
[](https://github.com/jingyaogong/minimind/commits/master)
|
13 |
+
[](https://github.com/jingyaogong/minimind/pulls)
|
14 |
+
[](https://huggingface.co/collections/jingyaogong/minimind-66caf8d999f5c7fa64f399e5)
|
15 |
+
|
16 |
+
</div>
|
17 |
+
|
18 |
+
<div align="center">
|
19 |
+
<h3>"大道至简"</h3>
|
20 |
+
</div>
|
21 |
+
|
22 |
+
<div align="center">
|
23 |
+
|
24 |
+
中文 | [English](./README_en.md)
|
25 |
+
|
26 |
+
</div>
|
27 |
+
|
28 |
+
* 本开源项目旨在完全从0开始,最快仅用3小时!即可训练出仅为26.88M大小的微型语言模型**MiniMind**。
|
29 |
+
* **MiniMind**极其轻量,最小版本体积约是 GPT3 的 $\frac{1}{7000}$,力求做到最普通的个人GPU也可快速推理甚至训练。
|
30 |
+
* **MiniMind**发布了大模型极简结构,数据集清洗和预处理、监督预训练(Pretrain)、有监督指令微调(SFT)、低秩自适应(LoRA)
|
31 |
+
微调,无奖励强化学习直接偏好对齐(DPO)的全阶段代码,也包含拓展共享混合专家(MoE)
|
32 |
+
的稀疏模型;拓展视觉多模态VLM: [MiniMind-V](https://github.com/jingyaogong/minimind-v)。
|
33 |
+
* 这不仅是一个开源模型的实现,也是入门大语言模型(LLM)的教程。
|
34 |
+
* 希望此项目能为研究者提供一个抛砖引玉的入门示例,帮助大家快速上手并对LLM领域产生更多的探索与创新。
|
35 |
+
|
36 |
+
> 为防止误读,「最快3小时」是指您需要具备>本人硬件配置的机器,具体规格的详细信息将在下文提供。
|
37 |
+
|
38 |
+
---
|
39 |
+
|
40 |
+
|
41 |
+
|
42 |
+
|
43 |
+
<div align="center">
|
44 |
+
|
45 |
+

|
46 |
+
|
47 |
+
[ModelScope在线测试](https://www.modelscope.cn/studios/gongjy/minimind) | [Bilibili视频链接](https://www.bilibili.com/video/BV12dHPeqE72/?share_source=copy_web&vd_source=670c2504f88726f8cf4a21ef6147c0e8)
|
48 |
+
|
49 |
+
---
|
50 |
+
|
51 |
+
</div>
|
52 |
+
|
53 |
+
# 📌 Introduction
|
54 |
+
|
55 |
+
大语言模型(LLM)领域,如 GPT、LLaMA、GLM 等,虽然它们效果惊艳,
|
56 |
+
但动辄10 Bilion庞大的模型参数个人设备显存远不够训练,甚至推理困难。
|
57 |
+
几乎所有人都不会只满足于用Lora等方案fine-tuing大模型学会一些新的指令,
|
58 |
+
这约等于在教牛顿玩21世纪的智能手机,然而,这远远脱离了学习物理本身的奥妙。
|
59 |
+
此外,卖课付费订阅的营销号漏洞百出的一知半解讲解AI的教程遍地,
|
60 |
+
让理解LLM的优质内容雪上加霜,严重阻碍了学习者。
|
61 |
+
|
62 |
+
因此,本项目的目标是把上手LLM的门槛无限降低,
|
63 |
+
直接从0开始训练一个极其轻量的语言模型。
|
64 |
+
|
65 |
+
> [!TIP]
|
66 |
+
> (截至2024-9-17)MiniMind系列已完成了3个型号模型的预训练,最小仅需26M(0.02B),即可具备流畅的对话能力!
|
67 |
+
|
68 |
+
| 模型 (大小) | tokenizer长度 | 推理占用 | release | 主观评分(/100) |
|
69 |
+
|-------------------------|-------------|--------|------------|------------|
|
70 |
+
| minimind-v1-small (26M) | 6400 | 0.5 GB | 2024.08.28 | 50' |
|
71 |
+
| minimind-v1-moe (4×26M) | 6400 | 1.0 GB | 2024.09.17 | 55' |
|
72 |
+
| minimind-v1 (108M) | 6400 | 1.0 GB | 2024.09.01 | 60' |
|
73 |
+
|
74 |
+
> 该分析在具有Torch 2.1.2、CUDA 12.2和Flash Attention 2的2×RTX 3090 GPU上进行。
|
75 |
+
|
76 |
+
|
77 |
+
|
78 |
+
项目包含:
|
79 |
+
|
80 |
+
- 公开MiniMind模型代码(包含Dense和MoE模型)、Pretrain、SFT指令微调、LoRA微调、DPO偏好优化的全过程代码、数据集和来源。
|
81 |
+
- 兼容`transformers`、`accelerate`、`trl`、`peft`等流行框架。
|
82 |
+
- 训练支持单机单卡、单机多卡(DDP、DeepSpeed)训练,使用wandb可视化训练流程。支持在任意位置停止,及在任意位置继续训练。
|
83 |
+
- 在Ceval数据集上进行模型测试的代码。
|
84 |
+
- 实现Openai-Api基本的chat接口,便于集成到第三方ChatUI使用(FastGPT、Open-WebUI等)。
|
85 |
+
|
86 |
+
希望此开源项目可以帮助LLM初学者快速入门!
|
87 |
+
|
88 |
+
### 👉**最近更新**
|
89 |
+
|
90 |
+
<details close>
|
91 |
+
<summary> <b>2024-10-05 (newest 🎉)</b> </summary>
|
92 |
+
|
93 |
+
- 为MiniMind拓展了多模态能力之---视觉
|
94 |
+
|
95 |
+
- 移步孪生项目[minimind-v](https://github.com/jingyaogong/minimind-v)查看详情!
|
96 |
+
|
97 |
+
</details>
|
98 |
+
|
99 |
+
<details close>
|
100 |
+
<summary> <b>2024-09-27</b> </summary>
|
101 |
+
|
102 |
+
- 09-27更新pretrain数据集的预处理方式,为了保证文本完整性,放弃预处理成.bin训练的形式(轻微牺牲训练速度)。
|
103 |
+
|
104 |
+
- 目前pretrain预处理后的文件命名为:pretrain_data.csv。
|
105 |
+
|
106 |
+
- 删除了一些冗余的代码。
|
107 |
+
|
108 |
+
</details>
|
109 |
+
|
110 |
+
<details close>
|
111 |
+
<summary> <b>2024-09-17</b> </summary>
|
112 |
+
|
113 |
+
- 更新minimind-v1-moe模型
|
114 |
+
|
115 |
+
- 为了防止歧义,不再使用mistral_tokenizer分词,全部采用自定义的minimind_tokenizer作为分词器。
|
116 |
+
|
117 |
+
</details>
|
118 |
+
|
119 |
+
<details close>
|
120 |
+
<summary> <b>2024-09-01</b> </summary>
|
121 |
+
|
122 |
+
- 更新minimind-v1 (108M)模型,采用minimind_tokenizer,预训练轮次3 + SFT轮次10,更充分训练,性能更强。
|
123 |
+
|
124 |
+
- 项目已部署至ModelScope创空间,可以在此网站上体验:
|
125 |
+
|
126 |
+
- [🔗ModelScope在线体验🔗](https://www.modelscope.cn/studios/gongjy/minimind)
|
127 |
+
|
128 |
+
</details>
|
129 |
+
|
130 |
+
<details close>
|
131 |
+
<summary> <b>2024-08-27</b> </summary>
|
132 |
+
|
133 |
+
- 项目首次开源
|
134 |
+
|
135 |
+
</details>
|
136 |
+
|
137 |
+
# 📌 Environment
|
138 |
+
|
139 |
+
仅是我个人的软硬件环境配置,自行酌情更改:
|
140 |
+
|
141 |
+
```bash
|
142 |
+
CPU: Intel(R) Core(TM) i9-10980XE CPU @ 3.00GHz
|
143 |
+
内存:128 GB
|
144 |
+
显卡:NVIDIA GeForce RTX 3090(24GB) * 2
|
145 |
+
环境:python 3.9 + Torch 2.1.2 + DDP单机多卡训练
|
146 |
+
```
|
147 |
+
|
148 |
+
* Ubuntu == 20.04
|
149 |
+
* Python == 3.9
|
150 |
+
* Pytorch == 2.1.2
|
151 |
+
* CUDA == 12.2
|
152 |
+
* [requirements.txt](./requirements.txt)
|
153 |
+
|
154 |
+
# 📌 Quick Start Test
|
155 |
+
|
156 |
+
<div align="center" style="font-size: 1.5em; font-weight: bold;">
|
157 |
+
<img src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" alt="Hugging Face Logo" style="vertical-align: middle; height: 30px;" />
|
158 |
+
Hugging Face
|
159 |
+
|
160 |
+
[MiniMind (HuggingFace)](https://huggingface.co/collections/jingyaogong/minimind-66caf8d999f5c7fa64f399e5)
|
161 |
+
|
162 |
+
<img src="https://g.alicdn.com/sail-web/maas/1.15.0/static/modelscopeIcon.cd89353f.svg" alt="Hugging Face Logo" style="vertical-align: middle; height: 30px;" />
|
163 |
+
|
164 |
+
[MiniMind (ModelScope)](https://www.modelscope.cn/models/gongjy/minimind-v1)
|
165 |
+
|
166 |
+
</div>
|
167 |
+
|
168 |
+
```bash
|
169 |
+
# step 1
|
170 |
+
git clone https://huggingface.co/jingyaogong/minimind-v1
|
171 |
+
```
|
172 |
+
|
173 |
+
```bash
|
174 |
+
# step 2
|
175 |
+
python 2-eval.py
|
176 |
+
```
|
177 |
+
|
178 |
+
或者启动streamlit,启动网页聊天界面
|
179 |
+
> 「注意」需要python>=3.10,安装 `pip install streamlit==1.27.2`
|
180 |
+
|
181 |
+
```bash
|
182 |
+
# or step 3, use streamlit
|
183 |
+
streamlit run fast_inference.py
|
184 |
+
```
|
185 |
+
|
186 |
+
# 📌 Quick Start Train
|
187 |
+
|
188 |
+
* 0、克隆项目代码
|
189 |
+
```bash
|
190 |
+
git clone https://github.com/jingyaogong/minimind.git
|
191 |
+
cd minimind
|
192 |
+
```
|
193 |
+
|
194 |
+
* 1、环境安装
|
195 |
+
```bash
|
196 |
+
pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
|
197 |
+
```
|
198 |
+
|
199 |
+
```text
|
200 |
+
# 测试torch是否可用cuda
|
201 |
+
import torch
|
202 |
+
print(torch.cuda.is_available())
|
203 |
+
```
|
204 |
+
|
205 |
+
> 如果不可用,请自行去[torch_stable](https://download.pytorch.org/whl/torch_stable.html)
|
206 |
+
下载whl文件安装。参考[链接](https://blog.csdn.net/weixin_45456738/article/details/141029610?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%AE%89%E8%A3%85torch&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-2-141029610.nonecase&spm=1018.2226.3001.4187)
|
207 |
+
|
208 |
+
|
209 |
+
* 2、如果你需要自己训练
|
210 |
+
|
211 |
+
* 2.1 下载[数据集下载地址](#数据集下载地址)放到`./dataset`目录下
|
212 |
+
|
213 |
+
* 2.2 `python data_process.py`处理数据集,例如pretrain数据提前进行token-encoder、sft数据集抽离qa到csv文件
|
214 |
+
|
215 |
+
* 2.3 在`./model/LMConfig.py` 中调整model的参数配置
|
216 |
+
> 这里仅需调整dim和n_layers和use_moe参数,分别是`(512+8)`或`(768+16)`,对应于`minimind-v1-small`和`minimind-v1`
|
217 |
+
* 2.4 `python 1-pretrain.py` 执行预训练,得到 `pretrain_*.pth` 作为预训练的输出权重
|
218 |
+
* 2.5 `python 3-full_sft.py` 执行指令微调,得到 `full_sft_*.pth` 作为指令微调的输出权重
|
219 |
+
* 2.6 `python 4-lora_sft.py` 执行lora微调(非必须)
|
220 |
+
* 2.7 `python 5-dpo_train.py` 执行DPO人类偏好强化学习对齐(非必须)
|
221 |
+
* 3、测试模型推理效果
|
222 |
+
* 确保需要使用的,训练完成的参数权重`*.pth`文件位于`./out/`目录下
|
223 |
+
* 也可以直接去[训练完成的模型权重](#训练完成的模型权重)下载使用我训练好的`*.pth`权重文件
|
224 |
+
```text
|
225 |
+
minimind/out
|
226 |
+
├── multi_chat
|
227 |
+
│ ├── full_sft_512.pth
|
228 |
+
│ ├── full_sft_512_moe.pth
|
229 |
+
│ └── full_sft_768.pth
|
230 |
+
├── single_chat
|
231 |
+
│ ├── full_sft_512.pth
|
232 |
+
│ ├── full_sft_512_moe.pth
|
233 |
+
│ └── full_sft_768.pth
|
234 |
+
├── pretrain_768.pth
|
235 |
+
├── pretrain_512_moe.pth
|
236 |
+
├── pretrain_512.pth
|
237 |
+
```
|
238 |
+
* `python 0-eval_pretrain.py`测试预训练模型的接龙效果
|
239 |
+
* `python 2-eval.py`测试模型的对话效果
|
240 |
+

|
241 |
+
|
242 |
+
🍭「Tip」预训练和全参微调pretrain和full_sft均支持多卡加速
|
243 |
+
|
244 |
+
> 假设你的设备只有1张显卡,使用原生python启动训练即可:
|
245 |
+
|
246 |
+
* 执行预训练或指令微调训练
|
247 |
+
```bash
|
248 |
+
python 1-pretrain.py
|
249 |
+
# and
|
250 |
+
python 3-full_sft.py
|
251 |
+
```
|
252 |
+
|
253 |
+
> 假设你的设备有N (N>1) 张显卡:
|
254 |
+
|
255 |
+
* 单机N卡启动训练(DDP)
|
256 |
+
```bash
|
257 |
+
torchrun --nproc_per_node N 1-pretrain.py
|
258 |
+
# and
|
259 |
+
torchrun --nproc_per_node N 3-full_sft.py
|
260 |
+
```
|
261 |
+
* 单机N卡启动训练(DeepSpeed)
|
262 |
+
```bash
|
263 |
+
deepspeed --master_port 29500 --num_gpus=N 1-pretrain.py
|
264 |
+
# and
|
265 |
+
deepspeed --master_port 29500 --num_gpus=N 3-full_sft.py
|
266 |
+
```
|
267 |
+
|
268 |
+
* 开启wandb记录训练过程(非必须)
|
269 |
+
```bash
|
270 |
+
torchrun --nproc_per_node N 1-pretrain.py --use_wandb
|
271 |
+
# and
|
272 |
+
python 1-pretrain.py --use_wandb
|
273 |
+
```
|
274 |
+
通过添加`--use_wandb`参数,可以记录训练过程,训练完成后,可以在wandb网站上查看训练过程。通过修改`wandb_project`
|
275 |
+
和`wandb_run_name`参数,可以指定项目名称和运行名称。
|
276 |
+
|
277 |
+
# 📌 Data sources
|
278 |
+
|
279 |
+
- 🤖 分词器:nlp中的Tokenizer类似于词典,将单词从自然语言通过“词典”映射到0,1,36这样的数字,可以理解为数字就代表了单词在“词典”中的页码。
|
280 |
+
LLM分词器的构建方式有两种:一种是自己构造词表训练一个分词器,代码可见`train_tokenizer.py`;另一种是选择开源模型训练好的分词器。
|
281 |
+
“词典”当然可以直接选择用新华词典或是牛津词典,优点是token转化压缩率很好,但缺点是词表太长,动辄数十万个词汇短语;
|
282 |
+
也可以使用自己训练的分词器,优点是词表随意控制,缺点是压缩率不够理想,且生僻词不容易面面俱到。
|
283 |
+
当然,“词典”的选择很重要,LLM的输出本质上是SoftMax到词典N个词的多分类问题,然后通过“词典”解码到自然语言。
|
284 |
+
因为LLM体积非常小,为了避免模型头重脚轻(词嵌入embedding层参数占整个LLM比太高),所以词表长度需要选择比较小。
|
285 |
+
强大的开源模型例如01万物、千问、chatglm、mistral、Llama3等,它们的tokenizer词表长度如下:
|
286 |
+
|
287 |
+
<table>
|
288 |
+
<tr><th>Tokenizer模型</th><th>词表大小</th><th>来源</th></tr>
|
289 |
+
<tr><td>yi tokenizer</td><td>64,000</td><td>01万物(中国)</td></tr>
|
290 |
+
<tr><td>qwen2 tokenizer</td><td>151,643</td><td>阿里云(中国)</td></tr>
|
291 |
+
<tr><td>glm tokenizer</td><td>151,329</td><td>智谱AI(中国)</td></tr>
|
292 |
+
<tr><td>mistral tokenizer</td><td>32,000</td><td>Mistral AI(法国)</td></tr>
|
293 |
+
<tr><td>llama3 tokenizer</td><td>128,000</td><td>Meta(美国)</td></tr>
|
294 |
+
<tr><td>minimind tokenizer</td><td>6,400</td><td>自定义</td></tr>
|
295 |
+
</table>
|
296 |
+
|
297 |
+
> 👉2024-09-17更新:为了防止过去的版本歧义&控制体积,minimind所有模型均使用minimind_tokenizer分词,废弃所有mistral_tokenizer版本。
|
298 |
+
|
299 |
+
> 尽管minimind_tokenizer长度很小,编解码效率弱于qwen2、glm等中文友好型分词器。
|
300 |
+
> 但minimind模型选择了自己训练的minimind_tokenizer作为分词器,以保持整体参数轻量,避免编码层和计算层占比失衡,头重脚轻,因为minimind的词表大小只有6400。
|
301 |
+
> 且minimind在实际测试中没有出现过生僻词汇解码失败的情况,效果良好。
|
302 |
+
> 由于自定义词表压缩长度到6400,使得LLM总参数量最低只有26M。
|
303 |
+
|
304 |
+
---
|
305 |
+
|
306 |
+
- 📙【Pretrain数据】:
|
307 |
+
[Seq-Monkey通用文本数据集](https://github.com/mobvoi/seq-monkey-data/blob/main/docs/pretrain_open_corpus.md) / [Seq-Monkey百度网盘](https://pan.baidu.com/s/114F1k3eksiWCOQLvaT3RYQ?pwd=6666)
|
308 |
+
是由多种公开来源的数据(如网页、百科、博客、开源代码、书籍等)汇总清洗而成。整理成统一的JSONL格式,并经过了严格的筛选和去重,确保数据的全面性、规模、可信性和高质量。总量大约在10B
|
309 |
+
token,适合中文大语言模型的预训练。
|
310 |
+
|
311 |
+
> 第2种选择:[SkyPile-150B数据集](https://hf-mirror.com/datasets/Skywork/SkyPile-150B/tree/main/data)
|
312 |
+
的可公开访问部分包含约2.33亿个独立网页,每个网页平均包含1000多个汉字。数据集包括大约1500亿个令牌和620GB的纯文本数据。
|
313 |
+
**如果着急的话**,可以尝试只挑选SkyPile-150B的部分jsonl下载(并在./data_process.py中对文本tokenizer生成*
|
314 |
+
.csv文件),以便快速跑通预训练流程。
|
315 |
+
|
316 |
+
---
|
317 |
+
|
318 |
+
- 📕【SFT数据】:[匠数大模型SFT数据集](https://www.modelscope.cn/datasets/deepctrl/deepctrl-sft-data)
|
319 |
+
是一个完整、格式统一、安全的大模型训练和研究资源。
|
320 |
+
从网络上的公开数据源收集并整理了大量开源数据集,对其进行了格式统一,数据清洗,
|
321 |
+
包含10M条数据的中文数据集和包含2M条数据的英文数据集。
|
322 |
+
总量大约在3B token,适合中文大语言模型的SFT。
|
323 |
+
数据集整合来源于以下所有数据(仅供参考,因此无需单独下载,仅需下载一个完整的【SFT数据】):
|
324 |
+
- [BelleGroup/train_3.5M_CN](https://huggingface.co/datasets/BelleGroup/train_3.5M_CN)
|
325 |
+
- [LinkSoul/instruction_merge_set](https://huggingface.co/datasets/LinkSoul/instruction_merge_set)
|
326 |
+
- [stingning/ultrachat](https://huggingface.co/datasets/stingning/ultrachat)
|
327 |
+
- [BAAI/COIG-PC-core](https://huggingface.co/datasets/BAAI/COIG-PC-core)
|
328 |
+
- [shibing624/sharegpt_gpt4](https://huggingface.co/datasets/shibing624/sharegpt_gpt4)
|
329 |
+
- [shareAI/ShareGPT-Chinese-English-90k](https://huggingface.co/datasets/shareAI/ShareGPT-Chinese-English-90k)
|
330 |
+
- [Tiger Research](https://huggingface.co/TigerResearch/sft_zh)
|
331 |
+
- [BelleGroup/school_math_0.25M](https://huggingface.co/datasets/BelleGroup/school_math_0.25M)
|
332 |
+
- [YeungNLP/moss-003-sft-data](https://huggingface.co/datasets/YeungNLP/moss-003-sft-data)
|
333 |
+
|
334 |
+
---
|
335 |
+
|
336 |
+
- 📘【DPO数据】:大约合并后共8万条dpo数据,人工标注的偏好数据,均来自[活字模型](https://github.com/HIT-SCIR/huozi)
|
337 |
+
,可以用于训练奖励模型,优化模型回复质量,使其更加符合人类偏好。
|
338 |
+
|
339 |
+
---
|
340 |
+
|
341 |
+
- 【更多数据集】目前已经有[HqWu-HITCS/Awesome-Chinese-LLM](https://github.com/HqWu-HITCS/Awesome-Chinese-LLM)
|
342 |
+
在收集和梳理中文LLM相关的开源模型、应用、数据集及教程等资料,并持续更新这方面的最新进展。全面且专业,Respect!
|
343 |
+
|
344 |
+
---
|
345 |
+
|
346 |
+
### 数据集下载地址
|
347 |
+
|
348 |
+
下载到`./dataset/`目录下
|
349 |
+
|
350 |
+
| MiniMind训练数据集 | 下载地址 |
|
351 |
+
|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
352 |
+
| **【tokenizer训练集】** | [HuggingFace](https://huggingface.co/datasets/jingyaogong/minimind_dataset/tree/main) / [百度网盘](https://pan.baidu.com/s/1yAw1LVTftuhQGAC1Y9RdYQ?pwd=6666) |
|
353 |
+
| **【Pretrain数据】** | [Seq-Monkey官方](http://share.mobvoi.com:5000/sharing/O91blwPkY) / [百度网盘](https://pan.baidu.com/s/1-Z8Q37lJD4tOKhyBs1D_6Q?pwd=6666) / [HuggingFace](https://huggingface.co/datasets/jingyaogong/minimind_dataset/tree/main) |
|
354 |
+
| **【SFT数据】** | [匠数大模型SFT数据集](https://www.modelscope.cn/datasets/deepctrl/deepctrl-sft-data/resolve/master/sft_data_zh.jsonl) |
|
355 |
+
| **【DPO数据】** | [Huggingface](https://huggingface.co/datasets/jingyaogong/minimind_dataset/tree/main/dpo) |
|
356 |
+
|
357 |
+
# 📌 Model
|
358 |
+
|
359 |
+
MiniMind-Dense(和[Llama3.1](https://ai.meta.com/blog/meta-llama-3-1/)一样)使用了Transformer的Decoder-Only结构,跟GPT-3的区别在于:
|
360 |
+
|
361 |
+
* 采用了GPT-3的预标准化方法,也就是在每个Transformer子层的输入上进行归一化,而不是在输出上。具体来说,使用的是RMSNorm归一化函数。
|
362 |
+
* 用SwiGLU激活函数替代了ReLU,这样做是为了提高性能。
|
363 |
+
* 像GPT-Neo一样,去掉了绝对位置嵌入,改用了旋转位置嵌入(RoPE),这样在处理超出训练长度的推理时效果更好。
|
364 |
+
|
365 |
+
---
|
366 |
+
|
367 |
+
MiniMind-MoE模型,它的结构基于Llama3和[Deepseek-V2](https://arxiv.org/pdf/2405.04434)中的MixFFN混合专家模块。
|
368 |
+
|
369 |
+
* DeepSeek-V2在前馈网络(FFN)方面,采用了更细粒度的专家分割和共享的专家隔离技术,以提高Experts的效果。
|
370 |
+
|
371 |
+
---
|
372 |
+
|
373 |
+
MiniMind的整体结构一致,只是在RoPE计算、推理函数和FFN层的代码上做了一些小调整。
|
374 |
+
其结构如下图(重绘版):
|
375 |
+
|
376 |
+

|
377 |
+

|
378 |
+
|
379 |
+
修改模型配置见[./model/LMConfig.py](./model/LMConfig.py)。
|
380 |
+
minimind目前训练的模型版本见下表:
|
381 |
+
|
382 |
+
| Model Name | params | len_vocab | n_layers | d_model | kv_heads | q_heads | share+route | TopK |
|
383 |
+
|-------------------|--------|-----------|----------|---------|----------|---------|-------------|------|
|
384 |
+
| minimind-v1-small | 26M | 6400 | 8 | 512 | 8 | 16 | - | - |
|
385 |
+
| minimind-v1-moe | 4×26M | 6400 | 8 | 512 | 8 | 16 | 2+4 | 2 |
|
386 |
+
| minimind-v1 | 108M | 6400 | 16 | 768 | 8 | 16 | - | - |
|
387 |
+
|
388 |
+
# 📌 Experiment
|
389 |
+
|
390 |
+
| Model Name | params | len_vocab | batch_size | pretrain_time | sft_single_time | sft_multi_time |
|
391 |
+
|-------------------|--------|-----------|------------|-------------------|-------------------|---------------------|
|
392 |
+
| minimind-v1-small | 26M | 6400 | 64 | ≈2 hour (1 epoch) | ≈2 hour (1 epoch) | ≈0.5 hour (1 epoch) |
|
393 |
+
| minimind-v1-moe | 4×26M | 6400 | 40 | ≈6 hour (1 epoch) | ≈5 hour (1 epoch) | ≈1 hour (1 epoch) |
|
394 |
+
| minimind-v1 | 108M | 6400 | 16 | ≈6 hour (1 epoch) | ≈4 hour (1 epoch) | ≈1 hour (1 epoch) |
|
395 |
+
|
396 |
+
---
|
397 |
+
|
398 |
+
1. **预训练(Text-to-Text)**:
|
399 |
+
- LLM首先要学习的并非直接与人交流,而是让肚子中充满知识的墨水,至于墨水理论上喝的越饱越好,产生大量的对世界的认知积累。
|
400 |
+
- 预训练就是让Model先埋头苦学大量基本的知识,例如从维基百科、新闻、常识、书籍等。
|
401 |
+
- 它无监督的从大量的文本数据中压缩知识到自己模型的权重,目的是:学会词语接龙。例如我们输入“秦始皇是”四个字,它在大量学习后能预测出下一句话大概率是“中国的第一位皇帝”。
|
402 |
+
> pretrain的学习率设置为1e-4到1e-5的动态学习率,预训练epoch数设为5。
|
403 |
+
```bash
|
404 |
+
torchrun --nproc_per_node 2 1-pretrain.py
|
405 |
+
```
|
406 |
+
2. **单轮次对话有监督微调(Single dialog Fine-tuning)**:
|
407 |
+
- 经过预训练,半成品LLM此时已经掌握了几乎所有的语言知识和百科常识。此时它还不会与人聊天,相反它只会无脑地进行输入词语的接龙,生成下一个词。
|
408 |
+
- 此时需要对半成品LLM做限制在聊天模板中进行微调,例如当它遇到这样的模板“<聊天开始>秦始皇是<聊天终止>
|
409 |
+
”后不再无脑接龙,而是意识到这是一段完整的对话结束。
|
410 |
+
- 我们称这个过程为指令微调,就如同让学富五车的「牛顿」先生适应21世纪的聊天习惯,学习屏幕左侧是对方消息,右侧是本人消息这个规律。
|
411 |
+
- 在训练时,MiniMind的指令和回答长度被截断在512,是为了节省显存空间。就像我们学习时,会先从短的文章开始,当学会阅读200字作文后,800字长文章就不需要再单独学习。
|
412 |
+
> 在推理时通过调整RoPE线性差值,实现长度外推到1024或2048及以上很方便。学习率设置为1e-5到1e-6的动态学习率,微调epoch数为6。
|
413 |
+
|
414 |
+
```bash
|
415 |
+
# 3-full_sft.py中设置数据集为sft_data_single.csv
|
416 |
+
torchrun --nproc_per_node 2 3-full_sft.py
|
417 |
+
```
|
418 |
+
3. **多轮对话微调(Multi dialog Fine-tuning)**:
|
419 |
+
- 在2的基础上,LLM已经学会一个问题->一个回答的聊天模板。此时仅需在具备历史问答的更长聊天模板上进一步微调即可。
|
420 |
+
- 我们仅需使用数据集的history_chat 字段,即历史对话,以及history_chat_response字段,即历史对话的回答。
|
421 |
+
- 构建【问题->回答,问题->回答,问题->】的新聊天模板,然后使用这个数据集进行微调。
|
422 |
+
- 学习完成的模型不仅仅只能回答当前问题,还能根据历史对话进行连贯的对话。
|
423 |
+
- 这一步 **并非必须** ,因为小模型长上文对话能力很弱,强行对齐多轮问答模板会损失一定程度的单轮SFT效果。
|
424 |
+
> 学习率设置为1e-5到1e-6的动态学习率,微调epoch数为5。
|
425 |
+
```bash
|
426 |
+
# 3-full_sft.py中设置数据集为sft_data.csv
|
427 |
+
torchrun --nproc_per_node 2 3-full_sft.py
|
428 |
+
```
|
429 |
+
4. **人类反馈强化学习(RLHF)之-直接偏好优化(Direct Preference Optimization, DPO)**:
|
430 |
+
- 在前面的训练中,GPT已经具备了基本的对话能力,但是这样的能力完全基于单词接龙,缺少正例反例的激励。
|
431 |
+
- GPT尚且未知什么回答是好的,什么是差的。我们希望它能够更符合人的偏好,给出更让人满意的回答。
|
432 |
+
- 这个过程就像是让GPT参加工作培训,从优秀员工的作为例子,消极员工作为反例,学习如何更好地服务客户。
|
433 |
+
- RLHF系列中,与PPO(Proximal Policy Optimization)这种需要奖励模型、价值模型的RL算法不同;
|
434 |
+
- DPO通过推导PPO奖励模型的显式解,把在线奖励模型换成离线数据,ref输出可以提前保存。
|
435 |
+
- DPO性能几乎不变,只用跑 actor 和 ref 2 个模型,大大节省显存开销和增加训练稳定性。
|
436 |
+
- 同样的,LLM的RL步骤也 **并非必须**,有利也有弊。
|
437 |
+
> 活字三元组(q,chose,reject)数据集,学习率le-5,半精度fp16,共1个epoch,耗时1h。
|
438 |
+
```bash
|
439 |
+
python 5-dpo_train.py
|
440 |
+
```
|
441 |
+
|
442 |
+
---
|
443 |
+
|
444 |
+
📋关于LLM的参数配置,有一篇很有意思的论文[MobileLLM](https://arxiv.org/pdf/2402.14905)做了详细的研究和实验。
|
445 |
+
scaling law在小模型中有自己独特的规律。
|
446 |
+
引起Transformer参数成规模变化的参数几乎只取决于`d_model`和`n_layers`。
|
447 |
+
|
448 |
+
* `d_model`↑+`n_layers`↓->矮胖子
|
449 |
+
* `d_model`↓+`n_layers`↑->瘦高个
|
450 |
+
|
451 |
+
2020年提出Scaling Law的论文认为,训练数据量、参数量以及训练迭代次数才是决定性能的关键因素,而模型架构的影响几乎可以忽视。
|
452 |
+
然而似乎这个定律对小模型并不完全适用。
|
453 |
+
MobileLLM提出架构的深度比宽度更重要,「深而窄」的「瘦长」模型可以学习到比「宽而浅」模型更多的抽象概念。
|
454 |
+
例如当模型参数固定在125M或者350M时,30~42层的「狭长」模型明显比12层左右的「矮胖」模型有更优越的性能,
|
455 |
+
在常识推理、问答、阅读理解等8个基准测试上都有类似的趋势。
|
456 |
+
这其实是非常有趣的发现,因为以往为100M左右量级的小模型设计架构时,几乎没人尝试过叠加超过12层。
|
457 |
+
这与MiniMind在训练过程中,模型参数量在`d_model`和`n_layers`之间进行调整实验观��到的效果是一致的。
|
458 |
+
然而「深而窄」的「窄」也是有维度极限的,当d_model<512时,词嵌入维度坍塌的劣势非常明显,
|
459 |
+
增加的layers并不能弥补词嵌入在固定q_head带来d_head不足的劣势。
|
460 |
+
当d_model>1536时,layers的增加似乎比d_model的优先级更高,更能带来具有“性价比”的参数->效果增益。
|
461 |
+
因此MiniMind设定small模型的d_model=512,n_layers=8来获取的「极小体积<->更好效果」的平衡。
|
462 |
+
设定d_model=768,n_layers=16来获取效果的更大收益,更加符合小模型scaling-law的变化曲线。
|
463 |
+
|
464 |
+
|
465 |
+
> 作为参考,GPT3的参数设定见下表:
|
466 |
+
|
467 |
+

|
468 |
+
|
469 |
+
---
|
470 |
+
|
471 |
+
### 训练完成的模型权重
|
472 |
+
|
473 |
+
[🔗百度网盘](https://pan.baidu.com/s/1KUfSzEkSXYbCCBj0Pw-9fA?pwd=6666)
|
474 |
+
|
475 |
+
| Model Name | params | Config | pretrain_model | single_sft_model | multi_sft_model | rl_model |
|
476 |
+
|-------------------|--------|-----------------------------|------------------------|------------------------------------|-----------------------------------|--------------|
|
477 |
+
| minimind-v1-small | 26M | d_model=512<br/>n_layers=8 | `pretrain_512.pth` | `single_chat/full_sft_512.pth` | `multi_chat/full_sft_512.pth` | `rl_512.pth` |
|
478 |
+
| minimind-v1-moe | 4×26M | d_model=512<br/>n_layers=8 | `pretrain_512_moe.pth` | `single_chat/full_sft_512_moe.pth` | `multi_chat/full_sft_512_moe.pth` | - |
|
479 |
+
| minimind-v1 | 108M | d_model=768<br/>n_layers=16 | `pretrain_768.pth` | `single_chat/full_sft_768.pth` | `multi_chat/full_sft_768.pth` | `rl_768.pth` |
|
480 |
+
|
481 |
+
---
|
482 |
+
|
483 |
+
# 📌 Eval
|
484 |
+
|
485 |
+
## ① RLHF篇
|
486 |
+
|
487 |
+
> [!TIP]
|
488 |
+
> 测试基于「单轮对话full_sft」和「DPO强化学习对齐」的minimind模型对比。
|
489 |
+
|
490 |
+
模型文件[百度网盘](https://pan.baidu.com/s/1KUfSzEkSXYbCCBj0Pw-9fA?pwd=6666),其中 `rl_<dim>.pth`
|
491 |
+
即为「DPO强化学习对齐」后的minimind模型权重。
|
492 |
+
|
493 |
+
```text
|
494 |
+
[Q]: 你叫什么名字?
|
495 |
+
[ft_768]: 我是一款人工智能语言模型,可以回答您的问题和提供帮助。您有什么需要我帮忙的吗?
|
496 |
+
[rl_768]: 我是一款基于人工智能技术的自然语言处理系统,主要用于处理和生成人类语言的任务。我可以帮助用户进行文本处理、语音识别、文本生成等任务,同时也可以帮助用户进行智能聊天、翻译、翻译等多种应用。如果您需要更多关于该项目的信息,请告诉我。
|
497 |
+
[ft_512]: 我很高兴能够帮助你。你有什么其他问题需要我帮忙解答吗?
|
498 |
+
[rl_512]: 我是一款基于自然语言处理技术的聊天机器人,能够理解和回复用户的问题和指令,并进行相应的回复和回复。我被训练为能够与人类进行交互和回答各种问题和任务。请问有什么需要吗?
|
499 |
+
|
500 |
+
[Q]: 你是谁?
|
501 |
+
[ft_768]: 我是一个人工智能语言模型,没有个人身份和身份。我只是根据输入的指令和文本信息生成响应。
|
502 |
+
[rl_768]: 我是一个计算机程序,没有个人身份或身份。我被设计来回答各种问题和提供帮助,包括回答问题、提供建议、进行实验、提供信息等等。我被广泛应用于各种领域,例如自然语言处理、计算机视觉、人工智能等等。如果您需要更多的帮助或信息,请随时与我联系。我会尽我所能来帮助您的工作和生活。
|
503 |
+
[ft_512]: 我是一个大型语言模型,可以回答各种各样的问题,包括科学、历史、文化和技术方面的问题。您有什么需要我回答的问题吗?
|
504 |
+
[rl_512]: 我是一个计算机程序,没有具体的身世和人物。如果您可以告诉我您想知道的具体信息,我会尽力回答您的问题。
|
505 |
+
|
506 |
+
[Q]: 中国有哪些比较好的大学?
|
507 |
+
[ft_768]: 中国有很多著名的大学,其中包括北京大学、上海交通大学、复兴中医药学院、浙江大学等。这些大学在不同的领域都有着自己的标志性建筑和研究方向,值得一提的是,它们在中国的顶尖教育资源中享有很高的声誉。
|
508 |
+
[rl_768]: 中国的大学有很多,具体情况还要根据你的需求来决定。如果你需要更详细的信息,建议可以去咨询一下你所在城市的大学排名和政策法规,从而选择一个合适的大学。同时,你可以在网上查阅相关信息,或者去咨询一些大学相关机构,如中国人民大学、中国人民大学等,以获得更为详细和专业的指导和建议。
|
509 |
+
[ft_512]: 中国有很多优秀的大学,比如麻省理工学院、北京大学、上海大学等等。这些大学在中国教育事业的发展和成就都非常突出。
|
510 |
+
[rl_512]: 中国教育局、中国大学、中国大陆大学和中国大陆大学均有优秀的教育体裁,但各地教育水平和专业要求都可能存在差异。中国教育局的学历要求、教学方法、师资力量等因素都各具特点,而大学的学历要求也各有千秋。中国大陆大学生的学历要求也各有不同,需要根据自己的实际情况进行选择。如果您对中国大陆大学生的专业要求有更具体需求,建议您可以通过互联网、国内外的各类机构和机构进行比较和交流。同时,您也可以向身边的人或朋友、老师、家长等人士寻求帮助和建议。希望以上回答对您有帮助。
|
511 |
+
|
512 |
+
[Q]: 你知道光速是多少吗?
|
513 |
+
[ft_768]: 光速是一个物理常数,表示光在真空中传播的速度,大约是每秒299792458米。光速是物理学中最基本的物理常数之一,也是相对论的重要基础之一。
|
514 |
+
[rl_768]: 当然知道,光速是光在真空中传播的速度,通常用c来表示。它是宇宙物理学中非常重要的理论之一。在物理学中,光速被认为是宇宙中最重要的速度之一。它代表着光在真空中传播的速度,这也是许多重要公式和公式的基础。
|
515 |
+
[ft_512]: 光速是光在真空中传播的速度,约为每秒299,792,458米。它是几乎所有的物理学概念,也是宇宙中最神秘和最重要的物理概念之一。
|
516 |
+
[rl_512]: 光速是光在真空中传播的速度,是自然界中不可逆转的速度。光源是由光的原子、分子、固体和光的组成,其速度约为每秒平方。光的速度是每秒约1个英亞或光年,这个数字是根据相对论、量子力学和引力理论来计算的。光速是相对的概念之一,它代表着我们对自然界中任何事件的理解和解释。
|
517 |
+
```
|
518 |
+
|
519 |
+
### 👉效果总结
|
520 |
+
|
521 |
+
* RLHF数据使用大约10万条;full_sft模型在简洁性和信息准确性方面表现更好;rl模型在回答中提供了更多的背景信息,但信息准确性有待改进。
|
522 |
+
* 总的来说RLHF后的模型倾向于学习:说更多有礼貌但无用的废话讨好“对话”本身,而对信息准确性则有轻微损失。
|
523 |
+
* 天下没有免费的午餐,还需要继续提升RLHF数据集的质量,也要接受模型能力无法避免的损失(程度有轻重)。
|
524 |
+
* DPO和在线PPO的区别在于reject和chosen都是离线准备的,和minimind模型本身的输出必然存在很大的分布差异。
|
525 |
+
* 这类似于DPO算法使模型观看乒乓球世界冠军的打法「录像」进行强化学习,而不是像PPO一样请reward模型做「教练」纠正自己的打法强化学习。
|
526 |
+
|
527 |
+
## ② Instruct Fine-Tuning 篇
|
528 |
+
|
529 |
+
> [!TIP]
|
530 |
+
> 以下测试于2024-09-17完成,此日期后发布的新模型,无特殊需要时将不加入测试。
|
531 |
+
> 测试基于单轮对话full_sft的minimind模型(无多轮微调和强化学习微调)。
|
532 |
+
|
533 |
+
[A] [minimind-v1-small(0.02B)](https://pan.baidu.com/s/1_COe0FQRDmeapSsvArahCA?pwd=6666)<br/>
|
534 |
+
[B] [minimind-v1-moe(0.1B)](https://pan.baidu.com/s/1tqB-GMvuiGQBvEl-yZ-oBw?pwd=6666)<br/>
|
535 |
+
[C] [minimind-v1(0.1B)](https://pan.baidu.com/s/1p713loS7EfwHQf3G9eYI3Q?pwd=6666)<br/>
|
536 |
+
[D] [baby-llama2-chinese(0.2B)](https://github.com/DLLXW/baby-llama2-chinese)<br/>
|
537 |
+
[E] [chatlm-mini-chinese(0.2B)](https://github.com/charent/ChatLM-mini-Chinese)<br/>
|
538 |
+
|
539 |
+
```text
|
540 |
+
[Q]: 你知道长江吗?
|
541 |
+
[A]: 是的,长江是中国最长的河流,全长超过3300千米。
|
542 |
+
[B]: 长江是中国最长的河流,总长度约为6300公里。它发源于青藏高原的青海湖,流经青海、四川、甘肃、宁夏、内蒙古、陕西和山西。长江流域是中国最大的农业区之一,也是中国的文化和经济中心。
|
543 |
+
[C]: 是的,长江是中国最长的河流之一,也是世界第三大河流。长江发源于青藏高原,流经11个省份,最终注入东海。长江流域是中国最大的河流流域之一,拥有着丰富的自然资源和文化遗产,如长江大桥、长江海洋博物馆、长江古城等。
|
544 |
+
[D]: 同时也知道,中国是世界上最长的城市之一,拥有超过3400万人口。
|
545 |
+
[E]: 是的,长江是中国最长的河流,也是世界上最长的河流之一。它发源于青藏高原,流经九个省区,最终注入东海。长江流域的气候温和,四季分明,是中国重要的农业和工业基地。长江流域的水产资源丰富,是中国的重要渔业资源之一。
|
546 |
+
|
547 |
+
|
548 |
+
[Q]: 第一颗人造卫星是哪个国家发射的?
|
549 |
+
[A]: 第一颗人造卫星是斯普特尼克1号。
|
550 |
+
[B]: 第一颗人造卫星是俄罗斯的国际卫星,于1957年发射。
|
551 |
+
[C]: 第一颗人造卫星是苏联发射的,它是由苏联于1957年10月发射的。
|
552 |
+
[D]: 这颗名为“阿姆斯特朗”的卫星,于1961年11月20日发射,是第一个成功将人类送入太空的卫星。
|
553 |
+
[E]: 第一颗人造卫星是苏联于1957年4月4日发射的,它是由苏联宇航员尤里·加加林(Yuri Gagarin)和苏联工程师罗尔德·谢尔盖耶夫(Roald Skohley)共同发射的。在发射过程中,加加林和谢尔盖耶夫使用了一个名为“斯普特尼克1号”的小型卫星,它的直径为4.3米,重量为1,051公斤。这枚卫星被称为“斯普特尼克1号”,是苏联太空竞赛中的一个里程碑,也是人类历史上第一次在太空中进行太空行走。
|
554 |
+
|
555 |
+
|
556 |
+
[Q]: 你知道泰山在哪里吗��
|
557 |
+
[A]: 泰山位于中国东部地区,是中国五岳之一。
|
558 |
+
[B]: 泰山位于山东省泰安市泰安市。泰安市是中国五岳之一,也是世界文化遗产和中国历史文化名山之一。泰安市有许多著名的景点,如五岳之一、玉皇顶、南天门、玉皇阁等。
|
559 |
+
[C]: 泰山位于中国山东省泰安市,是中国五岳之一。
|
560 |
+
[D]: 作为一个人工智能助手,我无法访问互联网,因此无法提供关于你所在位置的信息。不过,你可以通过搜索或搜索相关关键词来获取有关你所在位置的信息,或者查看相关新闻或网站来获取有关你所在位置的信息。
|
561 |
+
[E]: 泰山位于中国山东省泰安市境内,是中国五岳之一,也是中国文化和历史的重要象征之一。它是中国五岳之一,也是中国道教和佛教的发源地之一。泰山的海拔高度为1,545米,是中国五岳之一,也是中国最著名的旅游景点之一。它的历史可以追溯到公元前5世纪,是中国古代帝王祭祀的场所。泰山也是中国文化的重要组成部分,被誉为“五岳之首”,是中国文化的重要遗产之一。
|
562 |
+
|
563 |
+
|
564 |
+
[Q]: 世界上最高的山峰是什么?
|
565 |
+
[A]: 世界上最高的山峰是珠穆朗玛峰,位于尼泊尔和中国的边境上,海拔8848米。
|
566 |
+
[B]: 世界上最高的山峰是珠穆朗玛峰,位于喜马拉雅山脉,海拔8,848米。
|
567 |
+
[C]: 珠穆朗玛峰是世界上最高的山峰,海拔8848米。
|
568 |
+
[D]: 世界上最高的山峰是珠穆朗玛峰,位于喜马拉雅山脉,海拔8,848.86米(29,031.69英尺)。
|
569 |
+
[E]: 世界上最高的山峰是珠穆朗玛峰,也称为萨加玛塔,位于喜马拉雅山脉的尼泊尔和中国边境之间,海拔8,848.86米(29,031.69英尺)。它是世界上最著名的登山目标之一,吸引着来自世界各地的登山者前来挑战。珠穆朗玛峰的名字来自藏语,意思是“女神的额峰”,它是由两个不同的山峰组成的,其中一个是位于尼泊尔的珠穆朗玛峰,另一个则位于中国。它的高度是通过测量海拔高度来确定的,因为它是通过测量地球的平均高度来确定的。尽管珠穆朗玛峰是世界上最高的山峰,但它并不是地球上任何其他地方都能到达的。地球上的其他地方,如南美洲的安第斯山脉,也是世界上最高的山脉,但它并不是地球上最高的山峰。总之,珠穆朗玛峰是世界上最高的山峰,但它并不是地球上任何地方都能到达的。它是地球上最高的山脉,但它并不是地球上任何地方都能到达的。
|
570 |
+
|
571 |
+
|
572 |
+
[Q]: 万有引力是谁提出的?
|
573 |
+
[A]: 万有引力是由英国物理学家牛顿提出的。他认为,所有物体都会产生引力,这个引力是由物体的质量和距离决定的。这个理论揭示了质量和距离之间的关系,并证明了万有引力的本质。
|
574 |
+
[B]: 万有引力是由牛顿在1687年提出的。它是宇宙中一个基本的物理现象,它描述了物体之间的相互作用。这个力被称为万有引力,它在所有物体之间都存在,这种力与物体的质量和距离有关。万有引力是自然界中最基本的力量之一,它不仅影响着物体的运动和变化,还对宇宙的结构和演化产生着重要的影响。
|
575 |
+
[C]: 万有引力是英国物理学家艾萨克·牛顿在17世纪提出的。
|
576 |
+
[D]: 引力是宇宙中一种力量,它是由质量或能量所组成的。根据牛顿的万有引力定律,一个物体之间的引力大小与它的质量成正比,与它的质量成反比。因此,牛顿的万有引力定律表明,一个物体之间的引力大小与它的质量成正比,与它的质量成反比。这个定律在物理学、天文学和物理学中都有广泛的应用。
|
577 |
+
[E]: 万有引力是由英国物理学家艾萨克·牛顿于1687年提出的。他在1687年发表了一篇著名的论文,题为《自然哲学的数学原理》,其中提出了万有引力定律,指出任何两个物体之间都存在着一种引力,这种引力的大小与它们的质量成正比,与它们之间的距离的平方成反比。这个定律被称为万有引力定律,它描述了质量和距离之间的关系。它表明,两个物体之间的引力与它们的质量成正比,与它们之间的距离的平方成反比。这个定律对于解释宇宙中的许多现象和现象之间的相互作用非常重要,例如行星绕太阳运动、恒星之间的引力透镜效应等等。它也被广泛应用于天文学、物理学和工程学等领域,为我们理解宇宙的本质和演化提供了重要的理论基础。
|
578 |
+
|
579 |
+
|
580 |
+
[Q]: 你知道大熊猫的主要食物是什么吗?
|
581 |
+
[A]: 大熊猫的主要食物是竹子。它们通常吃竹子,每天需要吃掉大约30公斤的竹子。
|
582 |
+
[B]: 是的,大熊猫主要以竹子为食。它们每天需要吃掉大量的竹子来维持生命,每天需要吃掉40至80公斤的竹子。此外,它们也会吃一些其他的植物,如草、果实、坚果和小型哺乳动物。
|
583 |
+
[C]: 大熊猫��要以竹子为食,也会偶尔食用其他的植物和动物。此外,大熊猫也会吃一些野果、小动物和植物,但这些都不属于它们的主要食物来源。
|
584 |
+
[D]: 大熊猫的主要食物是竹子。
|
585 |
+
[E]: 大熊猫是一种以竹子为主要食物的植食动物,它们的肠道结构适合消化纤维素含量高的竹子,但也会吃一些其他植物,如草本植物和小型哺乳动物。大熊猫的肠道结构也适应了高纤维的竹子,这使得它们能够消化大量的纤维素,从而帮助它们在野外生存。大熊猫的肠道中还含有一种叫做“纤维素酶”的酶类物质,这种酶能够帮助大熊猫分解纤维素,从而帮助它们消化大量的水分和营养物质。此外,大熊猫的肠道还含有一种叫做“纤维素蛋白”的蛋白质,这种蛋白质能够帮助大熊猫维持体内的能量水平,从而帮助它们在野外生存。总的来说,大熊猫的主要食物是竹子,但它们也会吃一些其他植物,如草本植物和小型哺乳动物。
|
586 |
+
|
587 |
+
|
588 |
+
[Q]: 海水为什么是咸的?
|
589 |
+
[A]: 海水中含有许多盐分,这些盐分可以导致海水咸度的增加。海水中的盐分主要来自于海水中的盐分,这些盐分可以从海水中的盐分中获得。海水中的氧化物和盐分可以与海水中的盐分形成氢键,从而使海水咸度增加。
|
590 |
+
[B]: 海水是咸的,这是因为它含有大量的盐分,其中包括氯离子和氯离子。这些离子在海洋中形成了大量的盐,这些盐分被称为盐分。海水中含有许多溶解在水中的盐,这些盐分会随着海水的升高而逐渐蒸发,最终导致海水中盐分的蒸发。这些盐分在海水中被完全消耗,然后被排除在海水中。此外,海水中还含有许多其他的盐分,但这些盐分是不同的,因为它们在水中的浮起和下降过程是不同的。海水中的盐分是从海底的岩石中提取出来的,这些盐分在海水中可以被利用。总的来说,海水是咸的,这也是为什么海水中含有许多盐分和盐分的原因。
|
591 |
+
[C]: 海水含有许多溶解的盐类,其中最主要的是氯化钠。当水中加入盐时,盐的分子会与水分子发生反应,形成氢氧化钠,这是一种盐。
|
592 |
+
[D]: 因为水是许多生物的生存所必需的,它能够吸收和释放二氧化碳,释放氧气,维持大气中的水蒸气,以及维持水循环。水中的盐类和化学物质会释放出氧气,使地球上的生物呼吸。此外,水还具有许多其他功能,如保持水循环、维持水循环、调节气候和环境等。水是许多生物生存所必需的,它也是许多自然现象的重要基础。
|
593 |
+
[E]: 海水是咸的主要原因是因为其中含有大量的溶解盐类,其中最主要的是氯化钠(NaCl)。氯化钠是一种非常常见的盐类,它存在于地球上的大部分地区,包括海洋、湖泊、河流和地下水。当水从海洋中蒸发时,它会带走一部分盐分,使海水变得咸。此外,海中还含有其他溶解盐类的物质,如硫酸盐、硫酸镁、硫酸钙、硫酸镁盐、硫酸镁钾、硫酸镁钠、硫酸镁钙、硫酸镁镁钙、硫酸镁镁钙、硫酸镁镁钙、硫酸镁镁钠、硫酸镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁钙、硫酸镁镁镁镁钙、硫酸镁镁镁镁钙、硫酸镁镁镁镁钙、硫酸镁镁镁镁钙、硫酸镁镁镁镁钙、硫酸镁镁镁镁钙、硫酸镁镁镁镁镁钙、硫酸镁镁镁镁镁钙、硫酸镁镁镁镁镁钙、硫酸镁镁镁镁镁钙、硫酸镁镁镁镁镁镁钙、硫酸镁镁镁镁镁镁钙、硫酸镁镁镁镁镁镁钙、硫酸镁镁镁镁镁镁镁钙、硫酸镁镁镁镁
|
594 |
+
```
|
595 |
+
|
596 |
+
> [!NOTE]
|
597 |
+
> 🙋♂️直接把上述模型的回答丢给GPT-4o,让它帮忙打个分:
|
598 |
+
|
599 |
+
---
|
600 |
+
|
601 |
+
### 模型表现点评:
|
602 |
+
|
603 |
+
1. **模型A**:
|
604 |
+
- **表现**:模型A的回答通常简洁明了,但在某些问题上缺乏详细信息和准确性。例如,在长江的长度问题上,模型A的回答是错误的。
|
605 |
+
- **评分**:60
|
606 |
+
|
607 |
+
2. **模型B**:
|
608 |
+
- **表现**:模型B的回答在某些问题上提供了额外的信息,但这些信息有时是不准确的或多余的。例如,在长江的长度问题上,模型B提供了不准确的长度和流域面积。
|
609 |
+
- **评分**:65
|
610 |
+
|
611 |
+
3. **模型C**:
|
612 |
+
- **表现**:模型C的回答通常较为详细,且在大多数问题上提供了准确的信息。例如,在长江和泰山的问题上,模型C的回答是准确的。
|
613 |
+
- **评分**:75
|
614 |
+
|
615 |
+
4. **模型D**:
|
616 |
+
- **表现**:模型D的回答在某些问题上显得混乱,且缺乏准确性。例如,在泰山的问题上,模型D的回答完全偏离了主题。
|
617 |
+
- **评分**:50
|
618 |
+
|
619 |
+
5. **模型E**:
|
620 |
+
- **表现**:模型E的回答通常非常详细,但在某些问题上过于冗长,且包含了一��不必要的信息。例如,在万有引力的问题上,模型E的回答过于复杂。
|
621 |
+
- **评分**:70
|
622 |
+
|
623 |
+
#### 排序(从高到低):
|
624 |
+
|
625 |
+
| 模型 | C | E | B | A | D |
|
626 |
+
|----|----|----|----|----|----|
|
627 |
+
| 分数 | 75 | 70 | 65 | 60 | 50 |
|
628 |
+
|
629 |
+
---
|
630 |
+
|
631 |
+
### 👉效果总结
|
632 |
+
|
633 |
+
* minimind系列(ABC)的排序符合直觉,minimind-v1(0.1B)评分最高,常识性问题的回答基本没有错误和幻觉。
|
634 |
+
* 出乎意料的是,minimind-v1-small(0.02B)仅有26M参数,却可以接近minimind-v1(0.1B)的表现。
|
635 |
+
* minimind-v1(0.1B)的sft轮数`epochs`仅有不到2,偷懒提前kill腾出资源给小模型,0.1B没有得到充分训练的情况下依然做到了最强,其实还是底大一级压死人。
|
636 |
+
* minimind-v1-moe(0.1B)表现只比minimind-v1-small(0.02B)
|
637 |
+
略好,同样是因为偷懒早停腾出资源做其它训练了,但是MoE模型这种稀疏多Experts模式需要的训练轮次需要酌情更高,让所有FFN层专家得到路由的激活充分训练,在目前epochs设置为3时训练的还不够充足。
|
638 |
+
minimind在早期实验验证阶段在Yi-Tokenizer上试验过moe的充分训练版本,可以做到比dense小模型表现肉眼可见地更好。此部分可能需要留给日后腾出服务器再训练并更新v2、v3版本。
|
639 |
+
|
640 |
+
* E模型的回答肉眼看起来是非常不错的,尽管存在些许幻觉瞎编的情况。但GPT-4o和Deepseek的评分都一致认为它“信息过度冗长,且有重复内容,存在幻觉”。
|
641 |
+
其实这种评价略显严格,100个字中哪怕有10个字是幻觉,就很容易把它归到低分。由于E模型预训练文本长度更长,数据集大得多,所以回答的看起来很完备。在体积近似的情况下,数据数量和质量都很重要。
|
642 |
+
|
643 |
+
> 🙋♂️个人主观评价:E>C>B≈A>D
|
644 |
+
|
645 |
+
> 🤖 GPT-4o 评价:C>E>B>A>D
|
646 |
+
|
647 |
+
Scaling Law:模型参数越大,训练数据越多模型的性能越强。
|
648 |
+
|
649 |
+
# 📌 Objective dataset: C-Eval
|
650 |
+
|
651 |
+
C-Eval评测代码见:`./eval_ceval.py`,
|
652 |
+
小模型的测评通常为了避免回复格式的难以固定的特点,
|
653 |
+
而直接判断`A`,`B`,`C`,`D`四个字母对应token预测概率,取最大的作为回答答案,与标准答案计算正确率。
|
654 |
+
minimind模型本身没有使用较大的数据集训练,也没有针对回答选择题的指令做微调,测评结果可以当个参考。
|
655 |
+
|
656 |
+
> 例如minimind-small的结果细项:
|
657 |
+
|
658 |
+
| 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 |
|
659 |
+
|------|----------------------------|-----|-----------------------|-----------------------|---------------------|--------------------|---------------------|---------------------|----------------|------------------------|-----------------------|-----------------------|----------------|------------------|-------|---------------------|---------------|---------------------------------|---------------------|------------|------------------|-------------------------|--------------------|---------------------|---------|----------------------|-------------------------|-------------------------|--------------------|-----------------------------------|-------------------|-------------------------|------------------------------------------|-----------------------|-------------------------|-----------------|---------------------------|----------------------|-----------|-------------------|---------------------|-----------------------|------------------------|-------------------|------------------|----------------|-------------|-----------------------|----------------------|-------------------|---------------|-------------------------|
|
660 |
+
| 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 |
|
661 |
+
|
662 |
+
| 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 |
|
663 |
+
|----------|--------|--------|--------|--------|--------|-------|--------|--------|--------|--------|--------|--------|-------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|--------|-------|
|
664 |
+
| 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 |
|
665 |
+
| 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% |
|
666 |
+
|
667 |
+
```text
|
668 |
+
总题数: 1346
|
669 |
+
总正确数: 316
|
670 |
+
总正确率: 23.48%
|
671 |
+
```
|
672 |
+
|
673 |
+
---
|
674 |
+
|
675 |
+
#### 结果汇总:
|
676 |
+
|
677 |
+
| category | correct | question_count | accuracy |
|
678 |
+
|:------------------|:--------:|:--------------:|:--------:|
|
679 |
+
| minimind-v1-small | 344 | 1346 | 25.56% |
|
680 |
+
| minimind-v1 | 351 | 1346 | 26.08% |
|
681 |
+
|
682 |
+
#### 以下来自GPT-4o对minimind表现的瞎猜:
|
683 |
+
|
684 |
+
```text
|
685 |
+
### 模型擅长的领域:
|
686 |
+
1. 高中的化学:正确率为42.11%,是最高的一个领域。说明模型在这方面的知识可能较为扎实。
|
687 |
+
2. 离散数学:正确率为37.50%,属于数学相关领域,表现较好。
|
688 |
+
3. 教育科学:正确率为37.93%,说明模型在教育相关问题上的表现也不错。
|
689 |
+
4. 基础医学:正确率为36.84%,在医学基础知识方面表现也比较好。
|
690 |
+
5. 操作系统:正确率为36.84%,说明模型在计算机操作系统方面的表现较为可靠。
|
691 |
+
|
692 |
+
### 模型不擅长的领域:
|
693 |
+
1. 法律相关:如法律专业(8.70%)和税务会计(20.41%),表现相对较差。
|
694 |
+
2. 中学和大学的物理:如中学物理(26.32%)和大学物理(21.05%),模型在物理相关的领域表现不佳。
|
695 |
+
3. 高中的政治、地理:如高中政治(15.79%)和高中地理(21.05%),模型在这些领域的正确率较低。
|
696 |
+
4. 计算机网络与体系结构:如计算机网络(21.05%)和计算机体系结构(9.52%),在这些计算机专业课程上的表现也不够好。
|
697 |
+
5. 环境影响评估工程师:正确率仅为12.90%,在环境科学领域的表现也不理想。
|
698 |
+
|
699 |
+
### 总结:
|
700 |
+
- 擅长领域:化学、数学(特别是离散数学)、教育科学、基础医学、计算机操作系统。
|
701 |
+
- 不擅长领域:法律、物理、政治、地理、计算机网络与体系结构、环境科学。
|
702 |
+
|
703 |
+
这表明模型在涉及逻辑推理、基础科学和一些工程技术领域的问题上表现较好,但在人文社科、环境科学以及某些特定专业领域(如法律和税务)上表现较弱。如果要提高模型的性能,可能需要加强它在人文社科、物理、法律、以及环境科学等方面的训练。
|
704 |
+
```
|
705 |
+
|
706 |
+
# 📌 Others
|
707 |
+
|
708 |
+
### 推理与导出
|
709 |
+
|
710 |
+
* [./export_model.py](./export_model.py)可以导出模型到transformers格式,推送到huggingface
|
711 |
+
|
712 |
+
* MiniMind的huggingface集合地址:
|
713 |
+
[MiniMind](https://huggingface.co/collections/jingyaogong/minimind-66caf8d999f5c7fa64f399e5)
|
714 |
+
|
715 |
+
---
|
716 |
+
|
717 |
+
### API推理
|
718 |
+
|
719 |
+
* [my_openai_api.py](./my_openai_api.py)完成了openai_api的聊天接口,方便将自己的模型接入第三方UI
|
720 |
+
例如fastgpt、OpenWebUI等
|
721 |
+
|
722 |
+
* 从[Huggingface](https://huggingface.co/collections/jingyaogong/minimind-66caf8d999f5c7fa64f399e5)下载模型权重文件
|
723 |
+
```
|
724 |
+
minimind (root dir)
|
725 |
+
├─minimind
|
726 |
+
| ├── config.json
|
727 |
+
| ├── generation_config.json
|
728 |
+
| ├── LMConfig.py
|
729 |
+
| ├── model.py
|
730 |
+
| ├── pytorch_model.bin
|
731 |
+
| ├── special_tokens_map.json
|
732 |
+
| ├── tokenizer_config.json
|
733 |
+
| ├── tokenizer.json
|
734 |
+
```
|
735 |
+
|
736 |
+
* 启动聊天服务端
|
737 |
+
```bash
|
738 |
+
python my_openai_api.py
|
739 |
+
```
|
740 |
+
* 测试服务接口
|
741 |
+
```bash
|
742 |
+
python chat_openai_api.py
|
743 |
+
```
|
744 |
+
* API接口示例,兼容openai api格式
|
745 |
+
```bash
|
746 |
+
curl http://ip:port/v1/chat/completions \
|
747 |
+
-H "Content-Type: application/json" \
|
748 |
+
-d '{
|
749 |
+
"model": "model-identifier",
|
750 |
+
"messages": [
|
751 |
+
{ "role": "user", "content": "世界上最高的山是什么?" }
|
752 |
+
],
|
753 |
+
"temperature": 0.7,
|
754 |
+
"max_tokens": -1,
|
755 |
+
"stream": true
|
756 |
+
}'
|
757 |
+
```
|
758 |
+
|
759 |
+

|
760 |
+
|
761 |
+
### 在fastgpt中接入使用minimind api
|
762 |
+
|
763 |
+

|
764 |
+
|
765 |
+
# 📌 Acknowledge
|
766 |
+
|
767 |
+
> [!TIP]
|
768 |
+
> 如果您觉得 `MiniMind`对您有所帮助,可以在 GitHub 上加一个⭐<br/>
|
769 |
+
> 篇幅不短水平有限难免纰漏,欢迎在Issues交流指正或提交PR改进项目<br/>
|
770 |
+
> 您的支持就是持续改进项目的动力
|
771 |
+
|
772 |
+
> [!NOTE]
|
773 |
+
> 众人拾柴火焰高
|
774 |
+
> 如果您已经尝试训练了新的MiniMind型号,欢迎在Discussions或Issues中分享您的模型权重<br/>
|
775 |
+
> 可以是在特定下游任务或垂直领域(例如情感识别、医疗、心理、金融、法律问答等)的MiniMind新模型版本<br/>
|
776 |
+
> 也可以是拓展训练后(例如探索更长文本序列、更大体积(0.1B+)或更大的数据集)的MiniMind新模型版本<br/>
|
777 |
+
> 任何分享都视作独一无二的,所有尝试都具有价值,并受到鼓励<br/>
|
778 |
+
> 这些贡献都会被及时发现并整理在鸣谢列表中,再次感谢所有支持!
|
779 |
+
|
780 |
+
## 🤝[贡献者](https://github.com/jingyaogong/minimind/graphs/contributors)
|
781 |
+
|
782 |
+
<!--
|
783 |
+
<a href="https://github.com/jingyaogong/minimind/graphs/contributors">
|
784 |
+
<img src="https://contrib.rocks/image?repo=jingyaogong/minimind&v3" />
|
785 |
+
</a>
|
786 |
+
-->
|
787 |
+
|
788 |
+
<a href="https://github.com/jingyaogong"><img src="https://avatars.githubusercontent.com/u/62287848" width="70px" height="70px"/></a>
|
789 |
+
|
790 |
+
<a href="https://github.com/MuWinds"><img src="https://avatars.githubusercontent.com/u/93832089" width="70px" height="70px"/></a>
|
791 |
+
|
792 |
+
<a href="https://github.com/chuanzhubin"><img src="https://avatars.githubusercontent.com/u/2813798" width="70px" height="70px"/></a>
|
793 |
+
|
794 |
+
<a href="https://github.com/iomgaa-ycz"><img src="https://avatars.githubusercontent.com/u/124225682" width="70px" height="70px"/></a>
|
795 |
+
|
796 |
+
|
797 |
+
## 😊鸣谢
|
798 |
+
|
799 |
+
<a href="https://github.com/ipfgao"><b>@ipfgao</b></a>:
|
800 |
+
<a href="https://github.com/jingyaogong/minimind/issues/26">🔗训练步骤记录</a>
|
801 |
+
|
802 |
+
<a href="https://github.com/chuanzhubin"><b>@chuanzhubin</b></a>:
|
803 |
+
<a href="https://github.com/jingyaogong/minimind/pull/34">🔗代码逐行注释</a>
|
804 |
+
|
805 |
+
<a href="https://github.com/WangRongsheng"><b>@WangRongsheng</b></a>:
|
806 |
+
<a href="https://github.com/jingyaogong/minimind/issues/39">🔗大型数据集预处理</a>
|
807 |
+
|
808 |
+
<a href="https://github.com/pengqianhan"><b>@pengqianhan</b></a>:
|
809 |
+
<a href="https://github.com/jingyaogong/minimind/issues/73">🔗一个简明教程</a>
|
810 |
+
|
811 |
+
<a href="https://github.com/RyanSunn"><b>@RyanSunn</b></a>:
|
812 |
+
<a href="https://github.com/jingyaogong/minimind/issues/75">🔗推理过程学习记录</a>
|
813 |
+
|
814 |
+
<details close>
|
815 |
+
<summary> <b>参考链接 & 感谢以下优秀的论文或项目</b> </summary>
|
816 |
+
|
817 |
+
- 排名不分任何先后顺序
|
818 |
+
- [https://github.com/meta-llama/llama3](https://github.com/meta-llama/llama3)
|
819 |
+
- [https://github.com/karpathy/llama2.c](https://github.com/karpathy/llama2.c)
|
820 |
+
- [https://github.com/DLLXW/baby-llama2-chinese](https://github.com/DLLXW/baby-llama2-chinese)
|
821 |
+
- [(DeepSeek-V2)https://arxiv.org/abs/2405.04434](https://arxiv.org/abs/2405.04434)
|
822 |
+
- [https://github.com/charent/ChatLM-mini-Chinese](https://github.com/charent/ChatLM-mini-Chinese)
|
823 |
+
- [https://github.com/wdndev/tiny-llm-zh](https://github.com/wdndev/tiny-llm-zh)
|
824 |
+
- [(Mistral-MoE)https://arxiv.org/pdf/2401.04088](https://arxiv.org/pdf/2401.04088)
|
825 |
+
- [https://github.com/Tongjilibo/build_MiniLLM_from_scratch](https://github.com/Tongjilibo/build_MiniLLM_from_scratch)
|
826 |
+
- [https://github.com/jzhang38/TinyLlama](https://github.com/jzhang38/TinyLlama)
|
827 |
+
- [https://github.com/AI-Study-Han/Zero-Chatgpt](https://github.com/AI-Study-Han/Zero-Chatgpt)
|
828 |
+
- [https://github.com/xusenlinzy/api-for-open-llm](https://github.com/xusenlinzy/api-for-open-llm)
|
829 |
+
- [https://github.com/HqWu-HITCS/Awesome-Chinese-LLM](https://github.com/HqWu-HITCS/Awesome-Chinese-LLM)
|
830 |
+
|
831 |
+
</details>
|
832 |
+
|
833 |
+
## 🫶支持者
|
834 |
+
|
835 |
+
<a href="https://github.com/jingyaogong/minimind/stargazers">
|
836 |
+
<picture>
|
837 |
+
<source media="(prefers-color-scheme: dark)" srcset="https://reporoster.com/stars/dark/jingyaogong/minimind"/>
|
838 |
+
<source media="(prefers-color-scheme: light)" srcset="https://reporoster.com/stars/jingyaogong/minimind"/>
|
839 |
+
<img alt="github contribution grid snake animation" src="https://reporoster.com/stars/jingyaogong/minimind"/>
|
840 |
+
</picture>
|
841 |
+
</a>
|
842 |
+
|
843 |
+
<a href="https://github.com/jingyaogong/minimind/network/members">
|
844 |
+
<picture>
|
845 |
+
<source media="(prefers-color-scheme: dark)" srcset="https://reporoster.com/forks/dark/jingyaogong/minimind"/>
|
846 |
+
<source media="(prefers-color-scheme: light)" srcset="https://reporoster.com/forks/jingyaogong/minimind"/>
|
847 |
+
<img alt="github contribution grid snake animation" src="https://reporoster.com/forks/jingyaogong/minimind"/>
|
848 |
+
</picture>
|
849 |
+
</a>
|
850 |
+
|
851 |
+
<picture>
|
852 |
+
<source media="(prefers-color-scheme: dark)" srcset="https://api.star-history.com/svg?repos=jingyaogong/minimind&type=Date&theme=dark"/>
|
853 |
+
<source media="(prefers-color-scheme: light)" srcset="https://api.star-history.com/svg?repos=jingyaogong/minimind&type=Date"/>
|
854 |
+
<img alt="Star History Chart" src="https://api.star-history.com/svg?repos=jingyaogong/minimind&type=Date"/>
|
855 |
+
</picture>
|
856 |
+
|
857 |
+
# License
|
858 |
+
|
859 |
+
This repository is licensed under the [Apache-2.0 License](LICENSE).
|
860 |
+
|
861 |
+
|
full_sft_512.pth
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:17b6d3dd08a78c5644a000b8785765a00cb0d2dce574323478103a95ede2a1c9
|
3 |
+
size 107544062
|
model.py
ADDED
@@ -0,0 +1,426 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import math
|
2 |
+
import struct
|
3 |
+
import inspect
|
4 |
+
import time
|
5 |
+
|
6 |
+
from .LMConfig import LMConfig
|
7 |
+
from typing import Any, Optional, Tuple
|
8 |
+
import numpy as np
|
9 |
+
import torch
|
10 |
+
import torch.nn.functional as F
|
11 |
+
from torch import nn
|
12 |
+
from transformers import PreTrainedModel
|
13 |
+
from transformers.modeling_outputs import CausalLMOutputWithPast
|
14 |
+
|
15 |
+
|
16 |
+
class RMSNorm(torch.nn.Module):
|
17 |
+
def __init__(self, dim: int, eps: float):
|
18 |
+
super().__init__()
|
19 |
+
self.eps = eps
|
20 |
+
self.weight = nn.Parameter(torch.ones(dim))
|
21 |
+
|
22 |
+
def _norm(self, x):
|
23 |
+
return x * torch.rsqrt(x.pow(2).mean(-1, keepdim=True) + self.eps)
|
24 |
+
|
25 |
+
def forward(self, x):
|
26 |
+
output = self._norm(x.float()).type_as(x)
|
27 |
+
return output * self.weight
|
28 |
+
|
29 |
+
|
30 |
+
def precompute_pos_cis(dim: int, end: int, theta: float = 10000.0):
|
31 |
+
freqs = 1.0 / (theta ** (torch.arange(0, dim, 2)[: (dim // 2)].float() / dim))
|
32 |
+
t = torch.arange(end, device=freqs.device) # type: ignore
|
33 |
+
freqs = torch.outer(t, freqs).float() # type: ignore
|
34 |
+
pos_cis = torch.polar(torch.ones_like(freqs), freqs) # complex64
|
35 |
+
return pos_cis
|
36 |
+
|
37 |
+
|
38 |
+
def apply_rotary_emb(xq, xk, pos_cis):
|
39 |
+
def unite_shape(pos_cis, x):
|
40 |
+
ndim = x.ndim
|
41 |
+
assert 0 <= 1 < ndim
|
42 |
+
assert pos_cis.shape == (x.shape[1], x.shape[-1])
|
43 |
+
shape = [d if i == 1 or i == ndim - 1 else 1 for i, d in enumerate(x.shape)]
|
44 |
+
return pos_cis.view(*shape)
|
45 |
+
|
46 |
+
xq_ = torch.view_as_complex(xq.float().reshape(*xq.shape[:-1], -1, 2))
|
47 |
+
xk_ = torch.view_as_complex(xk.float().reshape(*xk.shape[:-1], -1, 2))
|
48 |
+
pos_cis = unite_shape(pos_cis, xq_)
|
49 |
+
xq_out = torch.view_as_real(xq_ * pos_cis).flatten(3)
|
50 |
+
xk_out = torch.view_as_real(xk_ * pos_cis).flatten(3)
|
51 |
+
return xq_out.type_as(xq), xk_out.type_as(xk)
|
52 |
+
|
53 |
+
|
54 |
+
def repeat_kv(x: torch.Tensor, n_rep: int) -> torch.Tensor:
|
55 |
+
"""torch.repeat_interleave(x, dim=2, repeats=n_rep)"""
|
56 |
+
bs, slen, n_kv_heads, head_dim = x.shape
|
57 |
+
if n_rep == 1:
|
58 |
+
return x
|
59 |
+
return (
|
60 |
+
x[:, :, :, None, :]
|
61 |
+
.expand(bs, slen, n_kv_heads, n_rep, head_dim)
|
62 |
+
.reshape(bs, slen, n_kv_heads * n_rep, head_dim)
|
63 |
+
)
|
64 |
+
|
65 |
+
|
66 |
+
class Attention(nn.Module):
|
67 |
+
def __init__(self, args: LMConfig):
|
68 |
+
super().__init__()
|
69 |
+
self.n_kv_heads = args.n_heads if args.n_kv_heads is None else args.n_kv_heads
|
70 |
+
assert args.n_heads % self.n_kv_heads == 0
|
71 |
+
self.n_local_heads = args.n_heads
|
72 |
+
self.n_local_kv_heads = self.n_kv_heads
|
73 |
+
self.n_rep = self.n_local_heads // self.n_local_kv_heads
|
74 |
+
self.head_dim = args.dim // args.n_heads
|
75 |
+
self.wq = nn.Linear(args.dim, args.n_heads * self.head_dim, bias=False)
|
76 |
+
self.wk = nn.Linear(args.dim, self.n_kv_heads * self.head_dim, bias=False)
|
77 |
+
self.wv = nn.Linear(args.dim, self.n_kv_heads * self.head_dim, bias=False)
|
78 |
+
self.wo = nn.Linear(args.n_heads * self.head_dim, args.dim, bias=False)
|
79 |
+
self.k_cache, self.v_cache = None, None
|
80 |
+
self.attn_dropout = nn.Dropout(args.dropout)
|
81 |
+
self.resid_dropout = nn.Dropout(args.dropout)
|
82 |
+
self.dropout = args.dropout
|
83 |
+
self.flash = hasattr(torch.nn.functional, 'scaled_dot_product_attention') and args.flash_attn
|
84 |
+
|
85 |
+
# print("WARNING: using slow attention. Flash Attention requires PyTorch >= 2.0")
|
86 |
+
mask = torch.full((1, 1, args.max_seq_len, args.max_seq_len), float("-inf"))
|
87 |
+
mask = torch.triu(mask, diagonal=1)
|
88 |
+
self.register_buffer("mask", mask, persistent=False)
|
89 |
+
|
90 |
+
def forward(self, x: torch.Tensor, pos_cis: torch.Tensor, kv_cache=False):
|
91 |
+
bsz, seqlen, _ = x.shape
|
92 |
+
|
93 |
+
xq, xk, xv = self.wq(x), self.wk(x), self.wv(x)
|
94 |
+
|
95 |
+
xq = xq.view(bsz, seqlen, self.n_local_heads, self.head_dim)
|
96 |
+
xk = xk.view(bsz, seqlen, self.n_local_kv_heads, self.head_dim)
|
97 |
+
xv = xv.view(bsz, seqlen, self.n_local_kv_heads, self.head_dim)
|
98 |
+
|
99 |
+
xq, xk = apply_rotary_emb(xq, xk, pos_cis)
|
100 |
+
|
101 |
+
# 更高效的kv_cache实现
|
102 |
+
if kv_cache and self.eval():
|
103 |
+
if seqlen == 1 and all(cache is not None for cache in (self.k_cache, self.v_cache)):
|
104 |
+
xk = torch.cat((self.k_cache, xk), dim=1)
|
105 |
+
xv = torch.cat((self.v_cache, xv), dim=1)
|
106 |
+
self.k_cache, self.v_cache = xk, xv
|
107 |
+
|
108 |
+
xk = repeat_kv(xk, self.n_rep) # (bs, seqlen, n_local_heads, head_dim)
|
109 |
+
xv = repeat_kv(xv, self.n_rep) # (bs, seqlen, n_local_heads, head_dim)
|
110 |
+
|
111 |
+
xq = xq.transpose(1, 2)
|
112 |
+
xk = xk.transpose(1, 2)
|
113 |
+
xv = xv.transpose(1, 2)
|
114 |
+
|
115 |
+
if self.flash and seqlen != 1:
|
116 |
+
output = torch.nn.functional.scaled_dot_product_attention(xq, xk, xv, attn_mask=None,
|
117 |
+
dropout_p=self.dropout if self.training else 0.0,
|
118 |
+
is_causal=True)
|
119 |
+
else:
|
120 |
+
scores = torch.matmul(xq, xk.transpose(2, 3)) / math.sqrt(self.head_dim)
|
121 |
+
scores = scores + self.mask[:, :, :seqlen, :seqlen] # (bs, n_local_heads, seqlen, cache_len + seqlen)
|
122 |
+
scores = F.softmax(scores.float(), dim=-1).type_as(xq)
|
123 |
+
scores = self.attn_dropout(scores)
|
124 |
+
output = torch.matmul(scores, xv) # (bs, n_local_heads, seqlen, head_dim)
|
125 |
+
|
126 |
+
output = output.transpose(1, 2).contiguous().view(bsz, seqlen, -1)
|
127 |
+
|
128 |
+
output = self.wo(output)
|
129 |
+
output = self.resid_dropout(output)
|
130 |
+
return output
|
131 |
+
|
132 |
+
|
133 |
+
class FeedForward(nn.Module):
|
134 |
+
def __init__(self, dim: int, hidden_dim: int, multiple_of: int, dropout: float):
|
135 |
+
super().__init__()
|
136 |
+
if hidden_dim is None:
|
137 |
+
hidden_dim = 4 * dim
|
138 |
+
hidden_dim = int(2 * hidden_dim / 3)
|
139 |
+
hidden_dim = multiple_of * ((hidden_dim + multiple_of - 1) // multiple_of)
|
140 |
+
self.w1 = nn.Linear(dim, hidden_dim, bias=False)
|
141 |
+
self.w2 = nn.Linear(hidden_dim, dim, bias=False)
|
142 |
+
self.w3 = nn.Linear(dim, hidden_dim, bias=False)
|
143 |
+
self.dropout = nn.Dropout(dropout)
|
144 |
+
|
145 |
+
def forward(self, x):
|
146 |
+
return self.dropout(self.w2(F.silu(self.w1(x)) * self.w3(x)))
|
147 |
+
|
148 |
+
|
149 |
+
class MoEGate(nn.Module):
|
150 |
+
def __init__(self, config: LMConfig):
|
151 |
+
super().__init__()
|
152 |
+
self.config = config
|
153 |
+
self.top_k = config.num_experts_per_tok
|
154 |
+
self.n_routed_experts = config.n_routed_experts
|
155 |
+
|
156 |
+
self.scoring_func = config.scoring_func
|
157 |
+
self.alpha = config.aux_loss_alpha
|
158 |
+
self.seq_aux = config.seq_aux
|
159 |
+
|
160 |
+
self.norm_topk_prob = config.norm_topk_prob
|
161 |
+
self.gating_dim = config.dim
|
162 |
+
self.weight = nn.Parameter(torch.empty((self.n_routed_experts, self.gating_dim)))
|
163 |
+
self.reset_parameters()
|
164 |
+
|
165 |
+
def reset_parameters(self) -> None:
|
166 |
+
import torch.nn.init as init
|
167 |
+
init.kaiming_uniform_(self.weight, a=math.sqrt(5))
|
168 |
+
|
169 |
+
def forward(self, hidden_states):
|
170 |
+
bsz, seq_len, h = hidden_states.shape
|
171 |
+
|
172 |
+
hidden_states = hidden_states.view(-1, h)
|
173 |
+
logits = F.linear(hidden_states, self.weight, None)
|
174 |
+
if self.scoring_func == 'softmax':
|
175 |
+
scores = logits.softmax(dim=-1)
|
176 |
+
else:
|
177 |
+
raise NotImplementedError(f'insupportable scoring function for MoE gating: {self.scoring_func}')
|
178 |
+
|
179 |
+
topk_weight, topk_idx = torch.topk(scores, k=self.top_k, dim=-1, sorted=False)
|
180 |
+
|
181 |
+
if self.top_k > 1 and self.norm_topk_prob:
|
182 |
+
denominator = topk_weight.sum(dim=-1, keepdim=True) + 1e-20
|
183 |
+
topk_weight = topk_weight / denominator
|
184 |
+
|
185 |
+
if self.training and self.alpha > 0.0:
|
186 |
+
scores_for_aux = scores
|
187 |
+
aux_topk = self.top_k
|
188 |
+
topk_idx_for_aux_loss = topk_idx.view(bsz, -1)
|
189 |
+
if self.seq_aux:
|
190 |
+
scores_for_seq_aux = scores_for_aux.view(bsz, seq_len, -1)
|
191 |
+
ce = torch.zeros(bsz, self.n_routed_experts, device=hidden_states.device)
|
192 |
+
ce.scatter_add_(1, topk_idx_for_aux_loss,
|
193 |
+
torch.ones(bsz, seq_len * aux_topk, device=hidden_states.device)).div_(
|
194 |
+
seq_len * aux_topk / self.n_routed_experts)
|
195 |
+
aux_loss = (ce * scores_for_seq_aux.mean(dim=1)).sum(dim=1).mean() * self.alpha
|
196 |
+
else:
|
197 |
+
mask_ce = F.one_hot(topk_idx_for_aux_loss.view(-1), num_classes=self.n_routed_experts)
|
198 |
+
ce = mask_ce.float().mean(0)
|
199 |
+
Pi = scores_for_aux.mean(0)
|
200 |
+
fi = ce * self.n_routed_experts
|
201 |
+
aux_loss = (Pi * fi).sum() * self.alpha
|
202 |
+
else:
|
203 |
+
aux_loss = None
|
204 |
+
return topk_idx, topk_weight, aux_loss
|
205 |
+
|
206 |
+
|
207 |
+
class MOEFeedForward(nn.Module):
|
208 |
+
def __init__(self, config: LMConfig):
|
209 |
+
super().__init__()
|
210 |
+
self.config = config
|
211 |
+
self.experts = nn.ModuleList([
|
212 |
+
FeedForward(
|
213 |
+
dim=config.dim,
|
214 |
+
hidden_dim=config.hidden_dim,
|
215 |
+
multiple_of=config.multiple_of,
|
216 |
+
dropout=config.dropout,
|
217 |
+
)
|
218 |
+
for _ in range(config.n_routed_experts)
|
219 |
+
])
|
220 |
+
|
221 |
+
self.gate = MoEGate(config)
|
222 |
+
if config.n_shared_experts is not None:
|
223 |
+
self.shared_experts = FeedForward(
|
224 |
+
dim=config.dim,
|
225 |
+
hidden_dim=config.hidden_dim,
|
226 |
+
multiple_of=config.multiple_of,
|
227 |
+
dropout=config.dropout,
|
228 |
+
)
|
229 |
+
|
230 |
+
def forward(self, x):
|
231 |
+
identity = x
|
232 |
+
orig_shape = x.shape
|
233 |
+
bsz, seq_len, _ = x.shape
|
234 |
+
|
235 |
+
# 使用门控机制选择专家
|
236 |
+
topk_idx, topk_weight, aux_loss = self.gate(x)
|
237 |
+
|
238 |
+
x = x.view(-1, x.shape[-1])
|
239 |
+
flat_topk_idx = topk_idx.view(-1)
|
240 |
+
|
241 |
+
if self.training:
|
242 |
+
# 训练模式下,重复输入数据
|
243 |
+
x = x.repeat_interleave(self.config.num_experts_per_tok, dim=0)
|
244 |
+
y = torch.empty_like(x, dtype=torch.float16)
|
245 |
+
for i, expert in enumerate(self.experts):
|
246 |
+
y[flat_topk_idx == i] = expert(x[flat_topk_idx == i])
|
247 |
+
y = (y.view(*topk_weight.shape, -1) * topk_weight.unsqueeze(-1)).sum(dim=1)
|
248 |
+
y = y.view(*orig_shape)
|
249 |
+
else:
|
250 |
+
# 推理模式下,只选择最优专家
|
251 |
+
y = self.moe_infer(x, flat_topk_idx, topk_weight.view(-1, 1)).view(*orig_shape)
|
252 |
+
|
253 |
+
if self.config.n_shared_experts is not None:
|
254 |
+
y = y + self.shared_experts(identity)
|
255 |
+
|
256 |
+
return y
|
257 |
+
|
258 |
+
@torch.no_grad()
|
259 |
+
def moe_infer(self, x, flat_expert_indices, flat_expert_weights):
|
260 |
+
expert_cache = torch.zeros_like(x)
|
261 |
+
idxs = flat_expert_indices.argsort()
|
262 |
+
tokens_per_expert = flat_expert_indices.bincount().cpu().numpy().cumsum(0)
|
263 |
+
token_idxs = idxs // self.config.num_experts_per_tok
|
264 |
+
# 例如当tokens_per_expert=[6, 15, 20, 26, 33, 38, 46, 52]
|
265 |
+
# 当token_idxs=[3, 7, 19, 21, 24, 25, 4, 5, 6, 10, 11, 12...]
|
266 |
+
# 意味着当token_idxs[:6] -> [3, 7, 19, 21, 24, 25, 4]位置的token都由专家0处理,token_idxs[6:15]位置的token都由专家1处理......
|
267 |
+
for i, end_idx in enumerate(tokens_per_expert):
|
268 |
+
start_idx = 0 if i == 0 else tokens_per_expert[i - 1]
|
269 |
+
if start_idx == end_idx:
|
270 |
+
continue
|
271 |
+
expert = self.experts[i]
|
272 |
+
exp_token_idx = token_idxs[start_idx:end_idx]
|
273 |
+
expert_tokens = x[exp_token_idx]
|
274 |
+
expert_out = expert(expert_tokens)
|
275 |
+
expert_out.mul_(flat_expert_weights[idxs[start_idx:end_idx]])
|
276 |
+
# 使用 scatter_add_ 进行 sum 操作
|
277 |
+
expert_cache.scatter_add_(0, exp_token_idx.view(-1, 1).repeat(1, x.shape[-1]), expert_out)
|
278 |
+
|
279 |
+
return expert_cache
|
280 |
+
|
281 |
+
|
282 |
+
class TransformerBlock(nn.Module):
|
283 |
+
def __init__(self, layer_id: int, args: LMConfig):
|
284 |
+
super().__init__()
|
285 |
+
self.n_heads = args.n_heads
|
286 |
+
self.dim = args.dim
|
287 |
+
self.head_dim = args.dim // args.n_heads
|
288 |
+
self.attention = Attention(args)
|
289 |
+
|
290 |
+
self.layer_id = layer_id
|
291 |
+
self.attention_norm = RMSNorm(args.dim, eps=args.norm_eps)
|
292 |
+
self.ffn_norm = RMSNorm(args.dim, eps=args.norm_eps)
|
293 |
+
|
294 |
+
if args.use_moe:
|
295 |
+
self.feed_forward = MOEFeedForward(args)
|
296 |
+
else:
|
297 |
+
self.feed_forward = FeedForward(
|
298 |
+
dim=args.dim,
|
299 |
+
hidden_dim=args.hidden_dim,
|
300 |
+
multiple_of=args.multiple_of,
|
301 |
+
dropout=args.dropout,
|
302 |
+
)
|
303 |
+
|
304 |
+
def forward(self, x, pos_cis, kv_cache=False):
|
305 |
+
h = x + self.attention(self.attention_norm(x), pos_cis, kv_cache)
|
306 |
+
out = h + self.feed_forward(self.ffn_norm(h))
|
307 |
+
return out
|
308 |
+
|
309 |
+
|
310 |
+
class Transformer(PreTrainedModel):
|
311 |
+
config_class = LMConfig
|
312 |
+
last_loss: Optional[torch.Tensor]
|
313 |
+
|
314 |
+
def __init__(self, params: LMConfig = None):
|
315 |
+
super().__init__(params)
|
316 |
+
if not params:
|
317 |
+
params = LMConfig()
|
318 |
+
self.params = params
|
319 |
+
self.vocab_size = params.vocab_size
|
320 |
+
self.n_layers = params.n_layers
|
321 |
+
|
322 |
+
self.tok_embeddings = nn.Embedding(params.vocab_size, params.dim)
|
323 |
+
self.dropout = nn.Dropout(params.dropout)
|
324 |
+
self.layers = torch.nn.ModuleList()
|
325 |
+
for layer_id in range(self.n_layers):
|
326 |
+
self.layers.append(TransformerBlock(layer_id, params))
|
327 |
+
self.norm = RMSNorm(params.dim, eps=params.norm_eps)
|
328 |
+
self.output = nn.Linear(params.dim, params.vocab_size, bias=False)
|
329 |
+
self.tok_embeddings.weight = self.output.weight
|
330 |
+
pos_cis = precompute_pos_cis(self.params.dim // self.params.n_heads, self.params.max_seq_len)
|
331 |
+
self.register_buffer("pos_cis", pos_cis, persistent=False)
|
332 |
+
|
333 |
+
self.apply(self._init_weights)
|
334 |
+
|
335 |
+
for pn, p in self.named_parameters():
|
336 |
+
if pn.endswith('w3.weight') or pn.endswith('wo.weight'):
|
337 |
+
torch.nn.init.normal_(p, mean=0.0, std=0.02 / math.sqrt(2 * params.n_layers))
|
338 |
+
|
339 |
+
self.last_loss = None
|
340 |
+
self.OUT = CausalLMOutputWithPast()
|
341 |
+
self._no_split_modules = [name for name, _ in self.named_modules()]
|
342 |
+
|
343 |
+
def _init_weights(self, module):
|
344 |
+
if isinstance(module, nn.Linear):
|
345 |
+
torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
|
346 |
+
if module.bias is not None:
|
347 |
+
torch.nn.init.zeros_(module.bias)
|
348 |
+
elif isinstance(module, nn.Embedding):
|
349 |
+
torch.nn.init.normal_(module.weight, mean=0.0, std=0.02)
|
350 |
+
|
351 |
+
def forward(self, tokens: Optional[torch.Tensor] = None, targets: Optional[torch.Tensor] = None,
|
352 |
+
kv_cache=False, **keyargs):
|
353 |
+
current_idx = 0
|
354 |
+
if 'input_ids' in keyargs:
|
355 |
+
tokens = keyargs['input_ids']
|
356 |
+
if 'attention_mask' in keyargs:
|
357 |
+
targets = keyargs['attention_mask']
|
358 |
+
if 'current_idx' in keyargs:
|
359 |
+
current_idx = int(keyargs['current_idx'])
|
360 |
+
|
361 |
+
_bsz, seqlen = tokens.shape
|
362 |
+
h = self.tok_embeddings(tokens)
|
363 |
+
h = self.dropout(h)
|
364 |
+
pos_cis = self.pos_cis[current_idx:current_idx + seqlen]
|
365 |
+
for idx, layer in enumerate(self.layers):
|
366 |
+
h = layer(h, pos_cis, kv_cache)
|
367 |
+
|
368 |
+
h = self.norm(h)
|
369 |
+
|
370 |
+
if targets is not None:
|
371 |
+
logits = self.output(h)
|
372 |
+
self.last_loss = F.cross_entropy(logits.view(-1, logits.size(-1)), targets.view(-1),
|
373 |
+
ignore_index=0, reduction='none')
|
374 |
+
else:
|
375 |
+
logits = self.output(h[:, [-1], :])
|
376 |
+
self.last_loss = None
|
377 |
+
|
378 |
+
self.OUT.__setitem__('logits', logits)
|
379 |
+
self.OUT.__setitem__('last_loss', self.last_loss)
|
380 |
+
return self.OUT
|
381 |
+
|
382 |
+
@torch.inference_mode()
|
383 |
+
def generate(self, idx, eos, max_new_tokens, temperature=0.7, top_k=8, stream=True, rp=1., kv_cache=True):
|
384 |
+
# rp: repetition_penalty
|
385 |
+
index = idx.shape[1]
|
386 |
+
init_inference = True
|
387 |
+
while idx.shape[1] < max_new_tokens - 1:
|
388 |
+
if init_inference or not kv_cache:
|
389 |
+
inference_res, init_inference = self(idx, kv_cache=kv_cache), False
|
390 |
+
else:
|
391 |
+
inference_res = self(idx[:, -1:], kv_cache=kv_cache, current_idx=idx.shape[1] - 1)
|
392 |
+
|
393 |
+
logits = inference_res.logits
|
394 |
+
logits = logits[:, -1, :]
|
395 |
+
|
396 |
+
for token in set(idx.tolist()[0]):
|
397 |
+
logits[:, token] /= rp
|
398 |
+
|
399 |
+
if temperature == 0.0:
|
400 |
+
_, idx_next = torch.topk(logits, k=1, dim=-1)
|
401 |
+
else:
|
402 |
+
logits = logits / temperature
|
403 |
+
if top_k is not None:
|
404 |
+
v, _ = torch.topk(logits, min(top_k, logits.size(-1)))
|
405 |
+
logits[logits < v[:, [-1]]] = -float('Inf')
|
406 |
+
|
407 |
+
probs = F.softmax(logits, dim=-1)
|
408 |
+
idx_next = torch.multinomial(probs, num_samples=1, generator=None)
|
409 |
+
|
410 |
+
if idx_next == eos:
|
411 |
+
break
|
412 |
+
|
413 |
+
idx = torch.cat((idx, idx_next), dim=1)
|
414 |
+
if stream:
|
415 |
+
yield idx[:, index:]
|
416 |
+
|
417 |
+
if not stream:
|
418 |
+
yield idx[:, index:]
|
419 |
+
|
420 |
+
@torch.inference_mode()
|
421 |
+
def eval_answer(self, idx):
|
422 |
+
idx_cond = idx if idx.size(1) <= self.params.max_seq_len else idx[:, -self.params.max_seq_len:]
|
423 |
+
inference_res = self(idx_cond)
|
424 |
+
logits = inference_res.logits
|
425 |
+
logits = logits[:, -1, :]
|
426 |
+
return logits
|
tokenizer.json
ADDED
The diff for this file is too large to render.
See raw diff
|
|
tokenizer_config.json
ADDED
@@ -0,0 +1,44 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
{
|
2 |
+
"add_bos_token": false,
|
3 |
+
"add_eos_token": false,
|
4 |
+
"add_prefix_space": true,
|
5 |
+
"added_tokens_decoder": {
|
6 |
+
"0": {
|
7 |
+
"content": "<unk>",
|
8 |
+
"lstrip": false,
|
9 |
+
"normalized": false,
|
10 |
+
"rstrip": false,
|
11 |
+
"single_word": false,
|
12 |
+
"special": true
|
13 |
+
},
|
14 |
+
"1": {
|
15 |
+
"content": "<s>",
|
16 |
+
"lstrip": false,
|
17 |
+
"normalized": false,
|
18 |
+
"rstrip": false,
|
19 |
+
"single_word": false,
|
20 |
+
"special": true
|
21 |
+
},
|
22 |
+
"2": {
|
23 |
+
"content": "</s>",
|
24 |
+
"lstrip": false,
|
25 |
+
"normalized": false,
|
26 |
+
"rstrip": false,
|
27 |
+
"single_word": false,
|
28 |
+
"special": true
|
29 |
+
}
|
30 |
+
},
|
31 |
+
"additional_special_tokens": [],
|
32 |
+
"bos_token": "<s>",
|
33 |
+
"clean_up_tokenization_spaces": false,
|
34 |
+
"eos_token": "</s>",
|
35 |
+
"legacy": true,
|
36 |
+
"model_max_length": 1000000000000000019884624838656,
|
37 |
+
"pad_token": null,
|
38 |
+
"sp_model_kwargs": {},
|
39 |
+
"spaces_between_special_tokens": false,
|
40 |
+
"tokenizer_class": "PreTrainedTokenizerFast",
|
41 |
+
"unk_token": "<unk>",
|
42 |
+
"use_default_system_prompt": false,
|
43 |
+
"chat_template": "{% if messages[0]['role'] == 'system' %}{% set system_message = messages[0]['content'] %}{% endif %}{% if system_message is defined %}{{ system_message }}{% endif %}{% for message in messages %}{% set content = message['content'] %}{% if message['role'] == 'user' %}{{ '<s>user\\n' + content + '</s>\\n<s>assistant\\n' }}{% elif message['role'] == 'assistant' %}{{ content + '</s>' + '\\n' }}{% endif %}{% endfor %}"
|
44 |
+
}
|