/ MemoAI / readme.md
readme.md
  1  # 大模型训练指南
  2  
  3  ## 一、导出聊天记录
  4  
  5  导出json格式的聊天记录。
  6  
  7  ![img.png](../doc/images/img10.png)
  8  
  9  如果你想合并多个联系人的数据,可以直接运行下面的代码合并
 10  
 11  ```python
 12  import json
 13  import os
 14  
 15  data_dir = r'E:\Project\Python\MemoTrace\data\聊天记录'
 16  
 17  dev_res = []
 18  train_res = []
 19  
 20  for filepath, dirnames, filenames in os.walk(data_dir):
 21      for filename in filenames:
 22          if filename.endswith('.json'):
 23              print(filename, filepath)
 24              filepath_ = os.path.join(filepath, filename)
 25              with open(filepath_, 'r', encoding='utf-8') as f:
 26                  data = json.load(f)
 27              if data:
 28                  if filename.endswith('train.json'):
 29                      train_res += data
 30                  else:
 31                      dev_res += data
 32  
 33  with open('train.json', 'w', encoding='utf-8') as f:
 34      json.dump(train_res, f, ensure_ascii=False, indent=4)
 35  
 36  with open('dev.json', 'w', encoding='utf-8') as f:
 37      json.dump(dev_res, f, ensure_ascii=False, indent=4)
 38  
 39  ```
 40  
 41  你现在应该有两个文件,dev.json(验证集)和train.json(训练集)
 42  
 43  ## 二、下载ChatGLM3-6B模型
 44  
 45  下载地址:[https://github.com/THUDM/ChatGLM3](https://github.com/THUDM/ChatGLM3)
 46  
 47  ## 使用方式
 48  
 49  ### 环境安装
 50  
 51  首先需要下载本仓库:
 52  
 53  ```shell
 54  git clone https://github.com/THUDM/ChatGLM3
 55  cd ChatGLM3
 56  ```
 57  
 58  然后使用 pip 安装依赖:
 59  
 60  ```
 61  pip install -r requirements.txt
 62  ```
 63  
 64  + 为了保证 `torch` 的版本正确,请严格按照 [官方文档](https://pytorch.org/get-started/locally/) 的说明安装。
 65  + **如果遇到问题,请参照ChatGLM3项目的解决方案,不要在本项目中提问**
 66  
 67  ## 三、ChatGLM3-6B 微调
 68  
 69  本目录提供 ChatGLM3-6B 模型的微调示例,包括全量微调和 P-Tuning v2。格式上,提供多轮对话微调样例和输入输出格式微调样例。
 70  
 71  如果将模型下载到了本地,本文和代码中的 `THUDM/chatglm3-6b` 字段均应替换为相应地址以从本地加载模型。
 72  
 73  运行示例需要 `python>=3.10`,除基础的 `torch` 依赖外,示例代码运行还需要依赖。
 74  
 75  
 76  ```bash
 77  pip install -r requirements.txt
 78  ```
 79  
 80  ## 测试硬件标准
 81  
 82  我们仅提供了单机多卡/多机多卡的运行示例,因此您需要至少一台具有多个 GPU 的机器。本仓库中的**默认配置文件**中,我们记录了显存的占用情况:
 83  
 84  + SFT 全量微调: 4张显卡平均分配,每张显卡占用 `48346MiB` 显存。
 85  + P-TuningV2 微调: 1张显卡,占用 `18426MiB` 显存。
 86  + LORA 微调: 1张显卡,占用 `14082MiB` 显存。
 87  
 88  > 请注意,该结果仅供参考,对于不同的参数,显存占用可能会有所不同。请结合你的硬件情况进行调整。
 89  
 90  > 请注意,我们仅仅使用英伟达 Hopper(代表显卡:H100) 和 Ampère(代表显卡:A100) 架构和系列显卡做过测试。如果您使用其他架构的显卡,可能会出现
 91  > 1. 未知的训练问题 / 显存占用与上述有误差。
 92  > 2. 架构过低而不支持某些特性。
 93  > 3. 推理效果问题。
 94       > 以上三种情况为社区曾经遇到过的问题,虽然概率极地,如果您遇到了以上问题,可以尝试在社区中解决。
 95  
 96  ## 多轮对话格式
 97  
 98  多轮对话微调示例采用 ChatGLM3 对话格式约定,对不同角色添加不同 `loss_mask` 从而在一遍计算中为多轮回复计算 `loss`。
 99  
100  对于数据文件,样例采用如下格式
101  
102  如果您仅希望微调模型的对话能力,而非工具能力,您应该按照以下格式整理数据。
103  
104  ```json
105  [
106    {
107      "conversations": [
108        {
109          "role": "system",
110          "content": "<system prompt text>"
111        },
112        {
113          "role": "user",
114          "content": "<user prompt text>"
115        },
116        {
117          "role": "assistant",
118          "content": "<assistant response text>"
119        },
120        // ... Muti Turn
121        {
122          "role": "user",
123          "content": "<user prompt text>"
124        },
125        {
126          "role": "assistant",
127          "content": "<assistant response text>"
128        }
129      ]
130    }
131    // ...
132  ]
133  ```
134  
135  **请注意,这种方法在微调的step较多的情况下会影响到模型的工具调用功能**
136  
137  - `system` 角色为可选角色,但若存在 `system` 角色,其必须出现在 `user`
138    角色之前,且一个完整的对话数据(无论单轮或者多轮对话)只能出现一次 `system` 角色。
139  
140  ## 数据集格式示例
141  
142  这里以 AdvertiseGen 数据集为例,
143  您可以从 [Google Drive](https://drive.google.com/file/d/13_vf0xRTQsyneRKdD1bZIr93vBGOczrk/view?usp=sharing)
144  或者 [Tsinghua Cloud](https://cloud.tsinghua.edu.cn/f/b3f119a008264b1cabd1/?dl=1) 下载 AdvertiseGen 数据集。
145  将解压后的 AdvertiseGen 目录放到 `data` 目录下并自行转换为如下格式数据集。
146  
147  > 请注意,现在的微调代码中加入了验证集,因此,对于一组完整的微调数据集,必须包含训练数据集和验证数据集,测试数据集可以不填写。或者直接用验证数据集代替。
148  
149  ```
150  {"conversations": [{"role": "user", "content": "类型#裙*裙长#半身裙"}, {"role": "assistant", "content": "这款百搭时尚的仙女半身裙,整体设计非常的飘逸随性,穿上之后每个女孩子都能瞬间变成小仙女啦。料子非常的轻盈,透气性也很好,穿到夏天也很舒适。"}]}
151  ```
152  
153  ## 配置文件
154  
155  微调配置文件位于 `config` 目录下,包括以下文件:
156  
157  1. `ds_zereo_2 / ds_zereo_3.json`: deepspeed 配置文件。
158  2. `lora.yaml / ptuning.yaml / sft.yaml`: 模型不同方式的配置文件,包括模型参数、优化器参数、训练参数等。 部分重要参数解释如下:
159      + data_config 部分
160          + train_file: 训练数据集的文件路径。
161          + val_file: 验证数据集的文件路径。
162          + test_file: 测试数据集的文件路径。
163          + num_proc: 在加载数据时使用的进程数量。
164      + max_input_length: 输入序列的最大长度。
165      + max_output_length: 输出序列的最大长度。
166      + training_args 部分
167          + output_dir: 用于保存模型和其他输出的目录。
168          + max_steps: 训练的最大步数。
169          + per_device_train_batch_size: 每个设备(如 GPU)的训练批次大小。
170          + dataloader_num_workers: 加载数据时使用的工作线程数量。
171          + remove_unused_columns: 是否移除数据中未使用的列。
172          + save_strategy: 模型保存策略(例如,每隔多少步保存一次)。
173          + save_steps: 每隔多少步保存一次模型。
174          + log_level: 日志级别(如 info)。
175          + logging_strategy: 日志记录策略。
176          + logging_steps: 每隔多少步记录一次日志。
177          + per_device_eval_batch_size: 每个设备的评估批次大小。
178          + evaluation_strategy: 评估策略(例如,每隔多少步进行一次评估)。
179          + eval_steps: 每隔多少步进行一次评估。
180          + predict_with_generate: 是否使用生成模式进行预测。
181      + generation_config 部分
182          + max_new_tokens: 生成的最大新 token 数量。
183      + peft_config 部分
184          + peft_type: 使用的参数有效调整类型(如 LORA)。
185          + task_type: 任务类型,这里是因果语言模型(CAUSAL_LM)。
186      + Lora 参数:
187          + r: LoRA 的秩。
188          + lora_alpha: LoRA 的缩放因子。
189          + lora_dropout: 在 LoRA 层使用的 dropout 概率
190      + P-TuningV2 参数:
191          + num_virtual_tokens: 虚拟 token 的数量。
192  
193  ## 开始微调
194  
195  通过以下代码执行 **单机多卡/多机多卡** 运行,这是使用 `deepspeed` 作为加速方案的,您需要安装 `deepspeed`。
196  
197  ```angular2html
198  cd finetune_demo
199  OMP_NUM_THREADS=1 torchrun --standalone --nnodes=1 --nproc_per_node=8  finetune_hf.py  data/AdvertiseGen/  THUDM/chatglm3-6b  configs/lora.yaml configs/ds_zero_2.json
200  ```
201  
202  通过以下代码执行 **单机单卡** 运行。
203  
204  ```angular2html
205  cd finetune_demo
206  python finetune_hf.py  data/AdvertiseGen/  THUDM/chatglm3-6b  configs/lora.yaml
207  ```
208  
209  ## 从保存点进行微调
210  
211  如果按照上述方式进行训练,每次微调都会从头开始,如果你想从训练一半的模型开始微调,你可以加入第四个参数,这个参数有两种传入方式:
212  
213  1. `yes`, 自动从最后一个保存的 Checkpoint开始训练
214  2. `XX`, 断点号数字 例 `600` 则从序号600 Checkpoint开始训练
215  
216  例如,这就是一个从最后一个保存点继续微调的示例代码
217  
218  ```angular2html
219  cd finetune_demo
220  python finetune_hf.py  data/AdvertiseGen/  THUDM/chatglm3-6b  configs/lora.yaml yes
221  ```
222  
223  ## 使用微调后的模型
224  
225  ### 在 inference_hf.py 中验证微调后的模型
226  
227  您可以在 `finetune_demo/inference_hf.py` 中使用我们的微调后的模型,仅需要一行代码就能简单的进行测试。
228  
229  ```angular2html
230  python inference_hf.py your_finetune_path --prompt your prompt
231  ```
232  
233  这样,得到的回答就微调后的回答了。
234  
235  ### 在本仓库的其他 demo 或者外部仓库使用微调后的模型
236  
237  您可以在任何一个 demo 内使用我们的 `lora` 和 全参微调的模型。这需要你自己按照以下教程进行修改代码。
238  
239  1. 使用`finetune_demo/inference_hf.py`中读入模型的方式替换 demo 中读入模型的方式。
240  
241  > 请注意,对于 LORA 和 P-TuningV2 我们没有合并训练后的模型,而是在`adapter_config.json`
242  > 中记录了微调型的路径,如果你的原始模型位置发生更改,则你应该修改`adapter_config.json`中`base_model_name_or_path`的路径。
243  
244  ```python
245  def load_model_and_tokenizer(
246          model_dir: Union[str, Path], trust_remote_code: bool = True
247  ) -> tuple[ModelType, TokenizerType]:
248      model_dir = _resolve_path(model_dir)
249      if (model_dir / 'adapter_config.json').exists():
250          model = AutoPeftModelForCausalLM.from_pretrained(
251              model_dir, trust_remote_code=trust_remote_code, device_map='auto'
252          )
253          tokenizer_dir = model.peft_config['default'].base_model_name_or_path
254      else:
255          model = AutoModelForCausalLM.from_pretrained(
256              model_dir, trust_remote_code=trust_remote_code, device_map='auto'
257          )
258          tokenizer_dir = model_dir
259      tokenizer = AutoTokenizer.from_pretrained(
260          tokenizer_dir, trust_remote_code=trust_remote_code
261      )
262      return model, tokenizer
263  ```
264  
265  2. 读取微调的模型,请注意,你应该使用微调模型的位置,例如,若你的模型位置为`/path/to/finetune_adapter_model`
266     ,原始模型地址为`path/to/base_model`,则你应该使用`/path/to/finetune_adapter_model`作为`model_dir`。
267  3. 完成上述操作后,就能正常使用微调的模型了,其他的调用方式没有变化。
268  
269  ### 提示
270  
271  1. 微调代码在开始训练前,会先打印首条训练数据的预处理信息(默认已经注释,可以解除注释),显示为
272  
273  ```log
274  Sanity
275  Check >> >> >> >> >> >> >
276  '[gMASK]': 64790 ->   -100
277  'sop': 64792 ->   -100
278  '<|system|>': 64794 ->   -100
279  '': 30910 ->   -100
280  '\n': 13 ->   -100
281  'Answer': 20115 ->   -100
282  'the': 267 ->   -100
283  'following': 1762 ->   -100
284  ...
285  'know': 683 ->   -100
286  'the': 267 ->   -100
287  'response': 3010 ->   -100
288  'details': 3296 ->   -100
289  '.': 30930 ->   -100
290  '<|assistant|>': 64796 ->   -100
291  '': 30910 ->  30910
292  '\n': 13 ->     13
293  'I': 307 ->    307
294  'need': 720 ->    720
295  'to': 289 ->    289
296  'use': 792 ->    792
297  ...
298  << << << << << << < Sanity
299  Check
300  ```
301  
302  字样,每行依次表示一个 detokenized string, token_id 和 target_id。其中,`target_id`为`token_id`在模型词表中的索引,`-100`表示该
303  token 不参与 `loss` 计算。
304  
305  2. `_prepare_model_for_training` 的作用是遍历模型的所有可训练参数,并确保它们的数据类型为`torch.float32`。
306     这在某些情况下是必要的,因为混合精度训练或其他操作可能会更改模型参数的数据类型。该代码默打开,可以注释,但是如果使用
307     `half` 格式训练出现问题,可以切换回这个代码,显存可能增加。
308  3. 在我们的[Huggingface模型代码](https://huggingface.co/THUDM/chatglm3-6b/blob/main/modeling_chatglm.py)中,有以下内容:
309      ```python
310     if self.gradient_checkpointing and self.training:
311                  layer_ret = torch.utils.checkpoint.checkpoint(
312                      layer,
313                      hidden_states,
314                      attention_mask,
315                      rotary_pos_emb,
316                      kv_caches[index],
317                      use_cache,
318                      use_reentrant=False
319                  )
320     ```
321     这可能导致训练的时候显存增加,因此,如果您的显存不足,可以尝试将``` use_reentrant``` 修改为`True`。
322  4. 微调后的模型可以使用任何支持 `peft` 载入的模型加速框架,在这里,我们没有提供demo。
323  5. 本仓库的微调数据集格式与 API 微调数据集格式有一定区别
324      + ZhipuAI API 微调数据集中的 `messages` 字段在本仓库为 `conversation` 字段。
325      + ZhipuAI API 中的微调文件为 `jsonl`, 在本仓库,需要简单的将文件名改为 `json`。
326  
327  > 以上内容来自ChatGLM3项目
328  
329  ## 微调示例
330  
331  配置文件
332  
333  config/lora.yaml
334  
335  ```yaml
336  data_config:
337    train_file: train.json
338    val_file: dev.json
339    test_file: dev.json
340    num_proc: 10
341  max_input_length: 512
342  max_output_length: 128
343  training_args:
344    # see `transformers.Seq2SeqTrainingArguments`
345    output_dir: ./output03-24
346    max_steps: 100000
347    # settings for data loading
348    per_device_train_batch_size: 4
349    dataloader_num_workers: 10
350    remove_unused_columns: false
351    # settings for saving checkpoints
352    save_strategy: steps
353    save_steps: 2000
354    # settings for logging
355    log_level: info
356    logging_strategy: steps
357    logging_steps: 10
358    # settings for evaluation
359    per_device_eval_batch_size: 4
360    evaluation_strategy: steps
361    eval_steps: 5200
362    # settings for optimizer
363    # adam_epsilon: 1e-6
364    # uncomment the following line to detect nan or inf values
365    # debug: underflow_overflow
366    predict_with_generate: yes
367    # see `transformers.GenerationConfig`
368    generation_config:
369      max_new_tokens: 256
370    # set your absolute deepspeed path here
371    #deepspeed: ds_zero_2.json
372    # set to true if train with cpu.
373    use_cpu: false
374  peft_config:
375    peft_type: LORA
376    task_type: CAUSAL_LM
377    r: 8
378    lora_alpha: 32
379    lora_dropout: 0.1
380  ```
381  
382  硬件配置:4090 24G、64G内存、CPU 14700KF 20核28线程
383  
384  你需要根据你的硬件配置修改上述参数,各个参数含义上面有说
385  
386  微调命令(需要指定数据集路径和ChatGLM3基础大模型的路径)
387  
388  ```shell
389  python finetune_hf.py  data/  E:\\Project\\Python\\Langchain-Chatchat\\chatglm3-6b  configs/lora.yaml yes
390  ```
391  
392  ## 部署
393  
394  在api_server.py修改微调保存路径
395  ```python
396  model, tokenizer = load_model_and_tokenizer(
397          r'E:\Project\Python\ChatGLM3\finetune_demo\output03-24\checkpoint-224000'
398      )
399  ```
400  
401  直接运行即可
402  
403  ```shell
404  python api_server.py
405  ```
406  
407  调用示例(你可以在任意一个支持ChatGPT的应用中使用它):
408  
409  ```python
410  from openai import OpenAI
411  
412  base_url = "http://127.0.0.1:8002/v1/"
413  client = OpenAI(api_key="EMPTY", base_url=base_url)
414  
415  def simple_chat(use_stream=True):
416      messages = [
417          {
418              "role": "user",
419              "content": "你好啊"
420          }
421      ]
422      response = client.chat.completions.create(
423          model="chatglm3-6b",
424          messages=messages,
425          stream=use_stream,
426          max_tokens=256,
427          temperature=0.8,
428          presence_penalty=1.1,
429          top_p=0.8)
430      if response:
431          if use_stream:
432              for chunk in response:
433                  print(chunk.choices[0].delta.content, end='')
434          else:
435              content = response.choices[0].message.content
436              print(content)
437      else:
438          print("Error:", response.status_code)
439  
440  if __name__ == "__main__":
441      simple_chat(use_stream=True)
442  ```
443  
444  ## 体验地址
445  
446  [https://chat.memotrace.cn/](https://chat.memotrace.cn/)
447  
448  ![img.png](img/img.png)
449  
450  ![img.png](img/img2.png)