原文:大模型LLM-微调经验分享&总结 - 知乎

写在前面

大型语言模型横行,之前非常焦虑,现在全面拥抱。目前也有很多开源项目进行大模型微调等,笔者也做了一阵子大模型了,特此来介绍一下ChatGLM-6B模型微调经验,并汇总了一下目前开源项目&数据。笔者与很多人微调结论不同,本人在采用单指令上进行模型微调,发现模型微调之后,「并没有出现灾难性遗忘现象」。

项目地址​github.com/liucongg/ChatGLM-Finetuning

update-2023.04.18增加文本生成任务评测 ChatGLM-6B模型微调

模型越大对显卡的要求越高,目前主流对大模型进行微调方法有三种:Freeze方法、P-Tuning方法和Lora方法。笔者也通过这三种方法,在信息抽取任务上,对ChatGLM-6B大模型进行模型微调。为了防止大模型的数据泄露,采用一个领域比赛数据集-汽车工业故障模式关系抽取,随机抽取50条作为测试集。

详细代码见上面的GitHub链接,并且也被ChatGLM官方收录。

Freeze方法

Freeze方法,即参数冻结,对原始模型部分参数进行冻结操作,仅训练部分参数,以达到在单卡或不进行TP或PP操作,就可以对大模型进行训练。

微调代码,见finetuning_freeze.py,核心部分如下:

for name, param in model.named_parameters():
    if not any(nd in name for nd in ["layers.27", "layers.26", "layers.25", "layers.24", "layers.23"]):
        param.requires_grad = False

针对模型不同层进行修改,可以自行修改。训练代码均采用DeepSpeed进行训练,可设置参数包含train_path、model_dir、num_train_epochs、train_batch_size、gradient_accumulation_steps、output_dir、prompt_text等,可根据自己的任务配置。

CUDA_VISIBLE_DEVICES=0 deepspeed finetuning_freeze.py --num_train_epochs 5 --train_batch_size 2

三元组抽取的推理代码,见predict_freeze.py,其他任务可以根据自己的评价标准进行推理预测。

PT方法

PT方法,即P-Tuning方法,参考ChatGLM官方代码,是一种针对于大模型的soft-prompt方法。

微调代码,见finetuning_pt.py,核心部分如下:

config = ChatGLMConfig.from_pretrained(args.model_dir)
config.pre_seq_len = args.pre_seq_len
config.prefix_projection = args.prefix_projection
model = ChatGLMForConditionalGeneration.from_pretrained(args.model_dir, config=config)
for name, param in model.named_parameters():
    if not any(nd in name for nd in ["prefix_encoder"]):
        param.requires_grad = False

当prefix_projection为True时,为P-Tuning-V2方法,在大模型的Embedding和每一层前都加上新的参数;为False时,为P-Tuning方法,仅在大模型的Embedding上新的参数。

可设置参数包含train_path、model_dir、num_train_epochs、train_batch_size、gradient_accumulation_steps、output_dir、prompt_text、pre_seq_len、prompt_text等, 可根据自己的任务配置。

CUDA_VISIBLE_DEVICES=0 deepspeed finetuning_pt.py --num_train_epochs 5 --train_batch_size 2 --pre_seq_len 16

三元组抽取的推理代码,见predict_pt.py,其他任务可以根据自己的评价标准进行推理预测。

Lora方法

Lora方法,即在大型语言模型上对指定参数增加额外的低秩矩阵,并在模型训练过程中,仅训练而外增加的参数。当“秩值”远小于原始参数维度时,新增的低秩矩阵参数量很小,达到仅训练很小的参数,就能获取较好的结果。

微调代码,见finetuning_lora.py,核心部分如下:

model = ChatGLMForConditionalGeneration.from_pretrained(args.model_dir)
config = LoraConfig(r=args.lora_r,
                    lora_alpha=32,
                    target_modules=["query_key_value"],
                    lora_dropout=0.1,
                    bias="none",
                    task_type="CAUSAL_LM",
                    inference_mode=False,
                    )
model = get_peft_model(model, config)

可设置参数包含train_path、model_dir、num_train_epochs、train_batch_size、gradient_accumulation_steps、output_dir、prompt_text、lora_r等,可根据自己的任务配置。

CUDA_VISIBLE_DEVICES=0 deepspeed finetuning_lora.py --num_train_epochs 5 --train_batch_size 2 --lora_r 8

三元组抽取的推理代码,见predict_lora.py,其他任务可以根据自己的评价标准进行推理预测。

注意:对于结果需要保持一致的任务(即关掉dropout,解码关掉do_sample),需要保存模型的adapter_config.json文件中,inference_mode参数修改成false,并将模型执行model.eval()操作。 主要原因是chatglm模型代码中,没有采用Conv1D函数。

三元组抽取实验结果

prompt_text:你现在是一个信息抽取模型,请你帮我抽取出关系内容为\"性能故障\", \"部件故障\", \"组成\"和 \"检测工具\"的相关三元组,三元组内部用\"_\"连接,三元组之间用\\n分割。文本:
输入:故障现象:发动机水温高,风扇始终是低速转动,高速档不工作,开空调尤其如此。
输出:发动机_部件故障_水温高\n风扇_部件故障_低速转动

时间换空间,可用很好的解决显卡的资源问题,简单玩玩还可以,如果想要模型达到最优效果或可用快速看到效果,还不如租张A100卡,快速实验,推理阶段再用自己的小破卡。

下面实验结果均是在租的80G-A100上进行的实验,与Github里用的A40的实验结果会有些差异,主要在训练时长(纯训练速度,剔除模型保存的时间)。说实话,真的要训练一个大模型,多个A100是必不可少的,可以减少很多模型并行的操作,效果上也更好把控一些。

微调方法PT-Only-EmbeddingPTFreezeLora

显卡占用

37G

56G

24G

39G

总参数

6.259B

7.211B

6.255B

6.259B

可训练参数占比

0.0586%

13.26%

16.10%

0.0586%

训练耗时

20min

52min

46min

25min

测试结果F1

0.0

0.6283

0.5675

0.5359

结果分析:

很多同学在微调后出现了灾难性遗忘现象,但我这边并没有出现,对“翻译任务”、“代码任务”、“问答任务”进行测试,采用freeze模型,可以用test_forgetting.py进行测试,具体测试效果如下:

后面会把生成任务、分类任务做完,请持续关注Github,会定期更新。(太忙了,会抓紧时间更新,并且官方代码也在持续更新,如遇到代码代码调不通的情况,请及时联系我,我在github也给出了我的代码版本和模型版本)

文本生成

prompt_text:你现在是一个问题生成模型,请根据下面文档生成一个问题,文档:
输入:紫色红薯是近年从日本引进的新品种红薯,中国农业大学农学与生物技术学院副院长刘庆昌指出,紫薯中的花青素具有显著的抗生物氧化作用,在延缓人体衰老方面具有非常好的效果。紫薯中所含赖氨酸、铜、锰、钾、锌的含量高于一般红薯5-8倍,尤其是抗癌物质碘、硒的含量比其他红薯高出20倍以上,占食物中的第一位。
输出:紫薯和红薯吃哪个好?

模型训练,以freeze方法为例:

CUDA_VISIBLE_DEVICES=0 nohup deepspeed --master_port 5555 finetuning_freeze.py --train_path "data/d2q_0.json" --output_dir "output_dir_freeze/" --prompt_text "你现在是一个问题生成模型,请根据下面文档生成一个问题,文档:" > log_fz.log 2>&1 &

由于生成模型的内容不能想信息抽取任务一样评价,用现有的BLUE或者Rouge来评价也是不合适,因此制定了评分规则。 通过多样性和准确性两个角度判断D2Q模型好坏,每个样本总计5分,共20个样本。

准确性:

测试数据见d2q_result_data/,测试代码见predict_d2q.py

微调方法原始模型PT-Only-EmbeddingPTFreezeLora

分数

51.75

73.75

87.75

79.25

86.75

中文开源大模型&项目

虽然出来很多大模型,但Open的&中文可直接使用的并不多,下面对中文开源大模型、数据集和项目进行一下汇总。

中文开源大模型

直接可微调,无需指令增量训练:

原始模型多语言or英文,需要中文指令数据集增量训练:

中文开源指令数据

下面中文指令集,大多数从Alpaca翻译而来,请看下面项目中data目录。目前通过ChatGPT或者GPT4作为廉价标注工为自己的数据进行数据标注一个不错的思路。

开源项目

总结下面较火的开源项目:

总结

目前各大厂的大模型陆陆续续放出,堪称百家争鸣!个人玩家也是全面拥抱,想尽一切办法来训练微调大模型。只愿大家以后可以实现“大模型”自由。愿再无“model-as-a-service”。

欢迎多多转发,点赞,关注,有问题的朋友也欢迎加我微信「logCong」私聊,交个朋友吧,一起学习,一起进步。

我们的口号是“生命不止,学习不停”。

往期回顾

刘聪NLP:ChatGPT-所见、所闻、所感

刘聪NLP:AAAI2023 | 基于统一语义匹配的通用信息抽取框架-USM

刘聪NLP:CC-Riddle:汉字谜语问答数据集

刘聪NLP:中文NER数据集整理

刘聪NLP:ACL2022 | DCSR:一种面向开放域段落检索的句子感知的对比学习方法

刘聪NLP:ACL2022 | NoisyTune:微调前加入少量噪音可能会有意想不到的效果

刘聪NLP:ACL2022|DictBERT:通过低频词典增强预训练模型表征方法

刘聪NLP:ACL2022论文分类汇总-Prompt、句子表征、检索排序&摘要

刘聪NLP:总结|Prompt在NER场景的应用

刘聪NLP:PolyLoss:一种将分类损失函数加入泰勒展开式的损失函数

刘聪NLP:PERT:一种基于乱序语言模型的预训练模型

刘聪NLP:DiffCSE:结合句子间差异的无监督句子嵌入对比学习方法

刘聪NLP:SIGIR2022论文筛选

刘聪NLP:PairSCL:句子对级别的有监督对比学习方法

刘聪NLP:COLD:中文冒犯性语言检测数据集

刘聪NLP:SNCSE:一种基于软负例的无监督句向量对比学习方法

刘聪NLP:CPT模型:一种中文兼顾NLU和NLG的非平衡预训练语言模型

刘聪NLP:SimCSE论文精读

刘聪NLP:常用预训练语言模型(PTMs)总结

刘聪NLP:ACL2021论文之ChineseBERT:融合字形与拼音信息的中文预训练模型

刘聪NLP:Sentence-Bert论文笔记

刘聪NLP:MacBERT:MLM as correction BERT

刘聪NLP:智能扩充机器人的“标准问”库之Query生成

刘聪NLP:短文本相似度算法研究


本文由转载于互联网,如有侵权请联系删除!