上文:chatGLM3+chatchat实现本地知识库


为什么要微调?

微调的主要目的是通过在特定任务上对预训练模型进行进一步训练,以适应该任务的需求,从而提高模型在该任务上的性能。具体来说,微调可以带来以下好处:

  • 提高模型的精度:预训练模型通常在大规模数据上进行训练,可以获得丰富的语言知识和语境信息。通过在特定任务上对这些预训练模型进行微调,我们可以更好地利用这些知识和信息,并将其适应到特定任务的需求中,从而提高模型在该任务上的精度。

  • 减少训练时间:与从头开始训练模型相比,微调通常只需要在相对较小的数据集上进行,因此训练时间更短。此外,由于预训练模型已经具有较好的参数初始化,微调也可以加速训练过程并提高模型的收敛速度。

  • 增加模型的泛化能力:由于预训练模型已经在大规模数据上进行了训练,因此具有较好的泛化能力。通过微调,我们可以将这种泛化能力应用到特定任务中,从而使模型能够更好地适应未见过的数据。

可以利用预训练模型在特定任务上进行进一步训练,从而提高模型的性能,加速训练过程并增加模型的泛化能力。

注意:ChatGLM3-6B-Base 和 ChatGLM3-6B-32K 模型不支持微调。

啥是泛化能力?

    泛化能力是指机器学习算法对新鲜样本的适应能力,即算法在从原有数据集学习后,对具有同一规律的学习集以外的数据也能给出合适的输出。    

个人理解:比如做题,不会加减乘除,通过不断做题,学会加减乘除,只要出现类似的题目你就会做了,而不用去关注具体输入内容是什么。

有哪些微调方式?

微调方法

名称

GPU占用

备注

LoRA

低(秩)rank 自适应微调方法全称全称是:LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS

14082MiB 显存预计14GB

微软的研究者们于2021年通过论文《LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS》提出了低秩适应LoRA

Fine-Tuning

全参微调,

一般结合:Accelerator和DeepSpeed框

至少上百GB

优点:全面全参微调效最效果比较好

缺点:计算量太大及资用太大

论文来源:https://arxiv.org/pdf/2110.07602.pdf

SFT全量微调

SFT是监督微调(Supervised Fine-Tun-ing)的缩写。这是一种常见的深度学习策略,通常在预训练的大语言模型上使用

4张显卡平均分配,每张显卡占用 48346MiB 显存大约是195GB


P-TuningV2

是ChatGLM模型专有的微调方式,

微调: 1张显卡,占用 18426MiB 显存,大约19GB内

论文来源:https://arxiv.org/pdf/2110.07602.pdf

模型精度

精度

说明

备注

32bit

32 比特全参数微调


FP16

16 比特冻结微调

或基于AQLM/AWQ/GPTQ/LLM.int8

8-bit

8比特

用于运行

4-bit

4比特

用于运行

微调实战

数据集准备

由于个人数据不方便公开这里就不贴具体的内容了,请参考官网的demo。

Tsinghua Cloud 

参考:https://github.com/THUDM/ChatGLM3/blob/main/finetune_demo/README.md

说明:dev.json用于验证数据集的文件,train.json用于训练数据集的文件;

基于LORA微调方法

硬件要求

硬件名称

配置

备注

内存

16GB


GPU

15GB


多论对话模板
[
  {
"conversations": [
      {
"role": "system",
"content": "<system prompt text>"
      },
      {
"role": "user",
"content": "<user prompt text>"
      },
      {
"role": "assistant",
"content": "<assistant response text>"
      },
      // ... Muti Turn
      {
"role": "user",
"content": "<user prompt text>"
      },
      {
"role": "assistant",
"content": "<assistant response text>"
      }
    ]
  }
  // ...
]

工具能力模板

[
  {
"tools": [
      // available tools, format is not restricted
    ],
"conversations": [
      {
"role": "system",
"content": "<system prompt text>"
      },
      {
"role": "user",
"content": "<user prompt text>"
      },
      {
"role": "assistant",
"content": "<assistant thought to text>"
      },
      {
"role": "tool",
"name": "<name of the tool to be called",
"parameters": {
"<parameter_name>": "<parameter_value>"
        },
"observation": "<observation>"
        // don't have to be string
      },
      {
"role": "assistant",
"content": "<assistant response to observation>"
      },
      // ... Muti Turn
      {
"role": "user",
"content": "<user prompt text>"
      },
      {
"role": "assistant",
"content": "<assistant response text>"
      }
    ]
  }
  // ...
]

93e969ac65e20897c84cd10c6f26c112.png

训练大约13G

7659df13059773edc3858dfde68937bf.png

43ccdbba4a98d3c831ed56be487ac655.png

基于5000次结果

7ed6fecbd2321552df407601f1696c5b.png

测试微调结果

python inference_hf.py output/checkpoint-3000/ --prompt '类型#裙*材质#网纱*颜色#粉红色*图案#线条*图案#刺绣*裙腰型# 高腰*裙长#连衣裙*裙袖长#短袖*裙领型#圆领'
Loading checkpoint shards: 100%|███████████████████████████████████████████████████████████████████████████████████████████████| 7/7 [01:10<00:00, 10.02s/it]
粉红色连衣裙,高腰版型,让穿着者显得更加娇俏可爱。短袖袖型,让穿着者显得十分精神。圆领设计,修饰颈部线条,更显优雅。网纱刺绣,让连衣裙更加浪漫优雅。

3000次结果

fa238edf63632efe39d27e0d9ca20b78.png

5000次的结果

bf34be4999ae59753e551e316d204609.png

对比结果

训练数据:
{
    "conversations": [
        {
            "role": "user",
            "content": "类型#裙*版型#显瘦*材质#蕾丝*颜色#纯色*风格#知性*风格#高贵*风格#性感*图案#纯色*图案#蕾丝*裙型#背带裙*裙型#包臀裙*裙型#鱼尾裙*裙长#连衣裙*裙袖型#喇叭袖"
        },
        {
            "role": "assistant",
            "content": "蕾丝喇叭袖上衣,搭配鱼尾包臀背带裙,整体造型给人甜美可人的感觉。偏爱蕾丝的浪漫柔情,流露别致女人味。喇叭袖的设计凸显别样浪漫,透露隐约小性感。两件套连衣裙,平添视觉层次感。鱼尾的设计修身显瘦,喇叭袖时尚减龄,纯色设计更加凸显女性知性高贵的气质。"
        }
    ]
}
原版(未训练)

14854de52c6a4fdae8e8a32f43ba2cd2.png

训练后

c7aadf226468158a5afd134fd2b5fa13.png

注:由于微调受限于参数以及存在随机性,所以若想实现FAQ的场景可以考虑使用向量数据库+大模型比如chatchat

基于P-TuningV2微调方法

由于GPU需要18426MiB后续支持

基于SFT 全量微调方法

由于需要GPU4张显卡平均分配,每张显卡占用 48346MiB 显存,后续支持

训练过程中遇到的问题

找不到对应文件:special_tokens_map.json

Loading checkpoint shards: 100%|██████████████████| 7/7 [01:31<00:00, 13.11s/it]
╭───────────────────── Traceback (most recent call last) ──────────────────────╮
│ /data/llm/llama/ChatGLM3/finetune_demo/finetune_hf.py:446 in main            │
│                                                                              │
│   443 │   │   ),                                                             │
│   444 ):                                                                     │
│   445 │   ft_config = FinetuningConfig.from_file(config_file)                │
│ ❱ 446 │   tokenizer, model = load_tokenizer_and_model(model_dir, peft_config │
│   447 │   data_manager = DataManager(data_dir, ft_config.data_config)        │
│   448 │                                                                      │
│   449 │   train_dataset = data_manager.get_dataset(                          │
│                                                                              │
│ /data/llm/llama/ChatGLM3/finetune_demo/finetune_hf.py:388 in                 │
│ load_tokenizer_and_model                                                     │
│                                                                              │
│   385 │   │   │   │   config=config,                                         │
│   386 │   │   │   )                                                          │
│   387 │   │   if peft_config.peft_type.name == "LORA":                       │
│ ❱ 388 │   │   │   model = AutoModelForCausalLM.from_pretrained(              │
│   389 │   │   │   │   model_dir,                                             │
│   390 │   │   │   │   trust_remote_code=True,                                │
│   391 │   │   │   │   empty_init=False,                                      │
│                                                                              │
│ /home/tools/yes/envs/chatGLM/lib/python3.10/site-packages/transformers/model │
│ s/auto/auto_factory.py:561 in from_pretrained                                │
│                                                                              │
│   558 │   │   │   │   model_class.register_for_auto_class(cls.__name__)      │
│   559 │   │   │   else:                                                      │
│   560 │   │   │   │   cls.register(config.__class__, model_class, exist_ok=T │
│ ❱ 561 │   │   │   return model_class.from_pretrained(                        │
│   562 │   │   │   │   pretrained_model_name_or_path, *model_args, config=con │
│   563 │   │   │   )                                                          │
│   564 │   │   elif type(config) in cls._model_mapping.keys():                │
│                                                                              │
│ /home/tools/yes/envs/chatGLM/lib/python3.10/site-packages/transformers/model │
│ ing_utils.py:3931 in from_pretrained                                         │
│                                                                              │
│   3928 │   │   │   model = quantizer.post_init_model(model)                  │
│   3929 │   │                                                                 │
│   3930 │   │   if _adapter_model_path is not None:                           │
│ ❱ 3931 │   │   │   model.load_adapter(                                       │
│   3932 │   │   │   │   _adapter_model_path,                                  │
│   3933 │   │   │   │   adapter_name=adapter_name,                            │
│   3934 │   │   │   │   token=token,                                          │
│                                                                              │
│ /home/tools/yes/envs/chatGLM/lib/python3.10/site-packages/transformers/integ │
│ rations/peft.py:180 in load_adapter                                          │
│                                                                              │
│   177 │   │   │   │   │   "adapter model."                                   │
│   178 │   │   │   │   )                                                      │
│   179 │   │   │                                                              │
│ ❱ 180 │   │   │   peft_config = PeftConfig.from_pretrained(                  │
│   181 │   │   │   │   peft_model_id,                                         │
│   182 │   │   │   │   token=token,                                           │
│   183 │   │   │   │   **adapter_kwargs,                                      │
│                                                                              │
│ /home/tools/yes/envs/chatGLM/lib/python3.10/site-packages/peft/config.py:137 │
│ in from_pretrained                                                           │
│                                                                              │
│   134 │   │   │   config_cls = cls                                           │
│   135 │   │                                                                  │
│   136 │   │   kwargs = {**class_kwargs, **loaded_attributes}                 │
│ ❱ 137 │   │   config = config_cls(**kwargs)                                  │
│   138 │   │   return config                                                  │
│   139 │                                                                      │
│   140 │   @classmethod                                                       │
╰──────────────────────────────────────────────────────────────────────────────╯
TypeError: PrefixTuningConfig.__init__() got an unexpected keyword argument 
'_name_or_path'

4609d0c90d61b74c80a0fd638160e5e8.png

原因:训练过程中才会生成special_tokens_map.json,所以要把原来的去掉。

最后

    通过训练可以扩展当前模型的泛化能力以及特定知识支持,官方默认为3000可以根据自已进行调整到5000或8000,由于本人的机器配置有点低所以效果,还过得去。当然如果想实现动态数据可以通过function calling方式进行实现,此块在请关注本公众号,后续继续输出。

参考文献:

https://zhuanlan.zhihu.com/p/646791309

https://github.com/THUDM/ChatGLM3/blob/main/finetune_demo/README.md

Logo

更多推荐