ChatGLM大模型的高效微调

8/17/2023 大模型微调高效微调LoRAChatGLM

# 1. 大模型微调概述

# 1.1 什么是大模型微调

大模型微调是一种迁移学习技术,通过在预训练模型的基础上进行额外训练,使其适应特定任务或领域。这一过程包括选择预训练模型,准备目标任务的数据,调整模型结构,进行微调训练,以及评估和部署。微调的优点在于节省时间和资源,提高性能,但也存在过拟合风险和模型选择与调整的复杂性。总体而言,它是一种强大的技术,特别适用于数据受限或计算资源有限的情况。

在 OpenAI 发布的 ChatGPT 中,就主要应用了大模型微调技术,从而获得了惊艳全世界的效果。

ChatGPT应用大模型微调技术

# 1.2 大模型微调的方式

# 1.2.1 全量微调

大模型全量微调通过在预训练的大型模型基础上调整所有层和参数,使其适应特定任务。这一过程使用较小的学习率和特定任务的数据进行,可以充分利用预训练模型的通用特征,但可能需要更多的计算资源。

# 1.2.2 参数高效微调

PEFT技术旨在通过最小化微调参数的数量和计算复杂度,来提高预训练模型在新任务上的性能,从而缓解大型预训练模型的训练成本。这样一来,即使计算资源受限,也可以利用预训练模型的知识来迅速适应新任务,实现高效的迁移学习。因此,PEFT技术可以在提高模型效果的同时,大大缩短模型训练时间和计算成本,让更多人能够参与到深度学习研究中来。

  • Prefix Tuning:与full fine-tuning更新所有参数的方式不同,该方法是在输入token之前构造一段任务相关的virtual tokens作为Prefix,然后训练的时候只更新Prefix部分的参数,而Transformer中的其他部分参数固定。该方法其实和构造Prompt类似,只是Prompt是人为构造的“显式”的提示,并且无法更新参数,而Prefix则是可以学习的“隐式”的提示。同时,为了防止直接更新Prefix的参数导致训练不稳定的情况,他们在Prefix层前面加了MLP结构(相当于将Prefix分解为更小维度的Input与MLP的组合后输出的结果),训练完成后,只保留Prefix的参数。

  • Prompt Tuning:该方法可以看作是Prefix Tuning的简化版本,只在输入层加入prompt tokens,并不需要加入MLP进行调整来解决难训练的问题。随着预训练模型参数量的增加,Prompt Tuning的方法会逼近fine-tuning的结果。

  • P-Tuning:该方法主要是为了解决这样一个问题:大模型的Prompt构造方式严重影响下游任务的效果。P-Tuning将Prompt转换为可以学习的Embedding层,并用MLP+LSTM的方式来对prompt embedding进行一层处理。

  • P-Tuning v2:让Prompt Tuning能够在不同参数规模的预训练模型、针对不同下游任务的结果上都达到匹敌Fine-tuning的结果。相比Prompt Tuning和P-tuning的方法,P-Tuning v2方法在多层加入了Prompts tokens作为输入,带来两个方面的好处:

    1)带来更多可学习的参数(从P-tuning和Prompt Tuning的0.1%增加到0.1%-3%),同时也足够参数高效。

    2)加入到更深层结构中的Prompt能给模型预测带来更直接的影响。

  • Adapter Tuning:该方法设计了Adapter结构(首先是一个down-project层将高维度特征映射到低维特征,然后过一个非线形层之后,再用一个up-project结构将低维特征映射回原来的高维特征;同时也设计了skip-connection结构,确保了在最差的情况下能够退化为identity),并将其嵌入Transformer的结构里面,在训练时,固定住原来预训练模型的参数不变,只对新增的Adapter结构进行微调。同时为了保证训练的高效性(也就是尽可能少的引入更多参数)。

  • LoRA:在涉及到矩阵相乘的模块,引入A、B这样两个低秩矩阵模块去模拟full fine-tuning的过程,相当于只对语言模型中起关键作用的低秩本质维度进行更新。

# 1.3 常见的参数高效微调技术

# 1.3.1 LoRA技术

LoRA,全称Low-Rank Adaptation of Large Language Models,直译大语言模型的低阶适应,这是微软的研究人员为了解决大语言模型微调而开发的一项技术。

比如,GPT-3有1750亿参数,为了让它能干特定领域的活儿,需要做微调,但是如果直接对GPT-3做微调,成本太高太麻烦了。LoRA的做法是,冻结预训练好的模型权重参数,然后在每个Transformer(Transforme就是GPT的那个T)块里注入可训练的层,由于不需要对模型的权重参数重新计算梯度,所以,大大减少了需要训练的计算量。研究发现,LoRA的微调质量与全模型微调相当,就好比是大模型的一个小模型。

LoRA微调技术

# 1.3.2 Freeze技术

Freeze 方法,即参数冻结,对原始模型部分参数进行冻结操作,仅训练部分参数,以达到在单卡或不进行 TP 或 PP 操作,就可以对大模型进行训练。在语言模型模型微调中,Freeze 微调方法仅微调 Transformer 后几层的全连接层参数,而冻结其它所有参数。

# 1.3.3 P-Tuning v2技术

P-Tuning v2 通过在每一层加入Prompts tokens,实现了更多的可学习参数和更深层结构中的Prompt对模型预测的直接影响,提高了模型的灵活性和效率。

ChatGLM微调介绍

# 2. 大模型微调相关项目

# 2.1 大模型微调开源项目

作者后来将各种大模型的高效微调,统一到了一个项目里:https://github.com/hiyouga/LLaMA-Factory (opens new window)

截止2023年10月29日,已经支持微调的模型型号有:

Model Model size Default module Template
LLaMA (opens new window) 7B/13B/33B/65B q_proj,v_proj -
LLaMA-2 (opens new window) 7B/13B/70B q_proj,v_proj llama2
BLOOM (opens new window) 560M/1.1B/1.7B/3B/7.1B/176B query_key_value -
BLOOMZ (opens new window) 560M/1.1B/1.7B/3B/7.1B/176B query_key_value -
Falcon (opens new window) 7B/40B query_key_value -
Baichuan (opens new window) 7B/13B W_pack baichuan
Baichuan2 (opens new window) 7B/13B W_pack baichuan2
InternLM (opens new window) 7B/20B q_proj,v_proj intern
Qwen (opens new window) 7B/14B c_attn chatml
ChatGLM3 (opens new window) 6B query_key_value chatglm3
Phi-1.5 (opens new window) 1.3B Wqkv -

# 2.1.1 ChatGLM大模型微调

# 2.1.2 LLaMA大模型微调

# 2.2 大模型微调开源数据集

典型的数据集格式:{"instruction": "", "input": "", "output": ""},目前通用的中文微调数据集:

数据集 内容
COIG (opens new window) Chinese Open Instruction Generalist project
Stanford Alpaca (Chinese) (opens new window) Alpaca 数据集中文翻译(ChatGPT 辅助翻译)
BELLE (opens new window) BELLE 项目的中文数据集(ChatGPT 生成)
GuanacoDataset (opens new window) Guannaco 模型的对话数据集
WebQA(zh) (opens new window) 中文网络问答
pCLUE (opens new window) 基于提示的大规模预训练数据集,用于多任务学习和零样本学习

注:很多开源数据集里,问题放在 instruction 上,而 input 是空的,这是正常情况,数据字段也没有对应错。这是因为 instruction 与 input 是拼一起用的。比如:“翻译以下这段话:xxx”,翻译以下这段话是 instruction,xxx 是 input。

# 3. ChatGLM2的高效微调

实验环境:租用的揽睿星舟的GPU服务器,NVIDIA RTX 4090 / 24GB,Python 3.10.6, CUDA 11.7

关于GPU服务器租用、Jupyter及HuggingFace的使用,这里就不赘述了,详见我的另一篇博客:常用深度学习平台的使用指南 (opens new window)

# 3.1 拉取仓库并安装依赖

拉取ChatGLM-Efficient-Tuning项目并安装依赖。

$ git clone https://github.com/hiyouga/ChatGLM-Efficient-Tuning.git
$ cd ChatGLM-Efficient-Tuning
$ pip3 config set global.index-url http://mirrors.aliyun.com/pypi/simple/
$ pip3 config set install.trusted-host mirrors.aliyun.com
$ pip3 install -r requirements.txt
1
2
3
4
5

# 3.2 单GPU微调训练模型

该项目支持使用多个 GPU 进行分布式微调,但我这里的服务器环境只有一个GPU,就不尝试了。

创建个checkpoint目录用于保存微调后的模型。

$ mkdir /home/user/checkpoint
1

制作测试数据集(复制一份alpaca_gpt4_data_zh.json数据集,就保留几条数据),然后在 /home/user/ChatGLM-Efficient-Tuning/data/dataset_info.json文件里再加一条配置。

  "alpaca_gpt4_zh_test": {
    "file_name": "alpaca_gpt4_data_zh_test.json",
    "file_sha1": "3eaa3bda364ccdd59925d7448a698256c31ef846"
  },
1
2
3
4

这里使用官方示例的数据集和参数运行(为了加快训练速度,使用刚刚制作的测试数据集,规模进行了阉割):

$ cd /home/user/ChatGLM-Efficient-Tuning
$ CUDA_VISIBLE_DEVICES=0 python3 src/train_bash.py \
  --stage sft \
  --model_name_or_path THUDM/chatglm2-6b \
  --do_train \
  --dataset alpaca_gpt4_zh_test \
  --finetuning_type lora \
  --output_dir /home/user/checkpoint \
  --per_device_train_batch_size 4 \
  --gradient_accumulation_steps 4 \
  --lr_scheduler_type cosine \
  --logging_steps 10 \
  --save_steps 1000 \
  --learning_rate 5e-5 \
  --num_train_epochs 3.0 \
  --plot_loss \
  --fp16
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

注意事项:GPU服务器厂商提供的预训练模型在/home/user/imported_models/chatglm2-6b/huggingface/THUDM/chatglm2-6b目录下,但是这个模型亲测没法用。报错“ValueError: Please update the model files of ChatGLM2-6B.”。模型文件应该从 https://huggingface.co/THUDM/chatglm2-6b/tree/main (opens new window) 下载,我这里直接填写了 THUDM/chatglm2-6b,程序执行时会自动下载模型。

ChatGLM2的高效微调训练过程

常用参数说明:这里只解释官方命令里用到的,其余的自己看源码里的说明吧。

--stage sft:在训练过程中要执行的阶段。(默认值: sft,可选值:sft、rm、ppo)
--model_name_or_path:模型文件名称(例如THUDM/chatglm2-6b,从huggingface下载)或者本地路径
--do_train:是否进行训练。(默认值:False)
--dataset:要使用的提供的数据集名称,用逗号分隔多个数据集。(默认值:alpaca_zh)
--finetuning_type:要使用的微调方法。(默认值: lora,可选值:freeze,p_tuning,lora,full)
--output_dir:用于输出训练后模型checkpoint的目录。(默认值:None)
--per_device_train_batch_size:每个GPU/TPU核心/CPU用于训练的批量大小。(默认值:8)
--gradient_accumulation_steps:在执行向后/更新传递之前累积的更新步数。(默认值:1)
--lr_scheduler_type:要使用的调度程序类型。(默认值:linear,可选值:linear,cosine,cosine_with_restarts,polynomial,constant,constant_with_warmup,inverse_sqrt,reduce_lr_on_plateau)
--logging_steps:每X次更新步骤记录一次。应为整数或范围为[0,1)的浮点数。如果小于1,将被解释为总训练步骤的比例。(默认值:500)
--save_steps:每X次更新步骤保存一个检查点。应为整数或范围为[0,1)的浮点数。如果小于1,将被解释为总训练步骤的比例。(默认值:500)
--learning_rate:AdamW的初始学习率。(默认值:5e-05)
--num_train_epochs:执行的总训练时代数。(默认值:3.0)
--plot_loss:是否在微调后绘制训练损失。(默认值:False)
--fp16:是否使用fp16(混合)精度而不是32位。(默认值:False)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

训练过程:微调训练过程所需时间较长,具体取决于所选的基础大模型、微调方式、参数设置以及数据集规模。如果只是为了体验流程的话,可以专门弄个两三条的测试数据集,几秒就能跑完。

ChatGLM2的高效微调训练完毕

训练完的模型,被保存在 /home/user/checkpoint 目录,文件列表如下:

README.md                88 B
adapter_config.json      435 B
adapter_model.bin        7.45 MB
all_results.json         162 B
finetuning_args.json     254 B
train_results.json       162 B
trainer_log.jsonl        224 B
trainer_state.json       578 B
training_args.bin        3.23 KB
1
2
3
4
5
6
7
8
9

# 3.3 对微调后的模型进行指标评估

指标评估(BLEU分数和汉语ROUGE分数),创建个eval_result目录用于保存微调模型的指标评估结果。

$ mkdir /home/user/eval_result
$ cd /home/user/ChatGLM-Efficient-Tuning
$ CUDA_VISIBLE_DEVICES=0 python3 src/train_bash.py \
    --stage sft \
    --model_name_or_path THUDM/chatglm2-6b \
    --do_eval \
    --dataset alpaca_gpt4_zh_test \
    --finetuning_type lora \
    --checkpoint_dir /home/user/checkpoint \
    --output_dir /home/user/eval_result \
    --per_device_eval_batch_size 8 \
    --max_samples 50 \
    --predict_with_generate
1
2
3
4
5
6
7
8
9
10
11
12
13

评估过程:因为我这里使用的是只有3条数据的测试数据集,所以评估过程也很快。

对微调后的模型进行指标评估

评估结果:保存的评估结果JSON文件也是这个内容。

***** eval metrics *****
  eval_accuracy           =        0.0
  eval_bleu-4             =     9.1284
  eval_rouge-1            =    36.5252
  eval_rouge-2            =    10.9344
  eval_rouge-l            =    22.3205
  eval_runtime            = 0:00:06.50
  eval_samples_per_second =      0.461
  eval_steps_per_second   =      0.154
1
2
3
4
5
6
7
8
9

# 3.4 使用微调后的模型进行预测

创建个predict_result目录用于保存微调模型的预测结果。

$ mkdir /home/user/predict_result
$ cd /home/user/ChatGLM-Efficient-Tuning
$ CUDA_VISIBLE_DEVICES=0 python3 src/train_bash.py \
    --stage sft \
    --model_name_or_path THUDM/chatglm2-6b \
    --do_predict \
    --dataset alpaca_gpt4_zh_test \
    --finetuning_type lora \
    --checkpoint_dir /home/user/checkpoint \
    --output_dir /home/user/predict_result \
    --per_device_eval_batch_size 8 \
    --max_samples 100 \
    --predict_with_generate
1
2
3
4
5
6
7
8
9
10
11
12
13

预测过程:因为我这里使用的是只有3条数据的测试数据集,所以预测过程也很快。

使用微调后的模型进行预测

预测结果,被保存在 /home/user/predict_result 目录,文件列表如下:

all_results.json                311 B
generated_predictions.jsonl     3.93 KB
predict_results.json            311 B
1
2
3

其中 generated_predictions.jsonl 的内容如下:

{
    "label": "以下是保持健康的三个提示:\n\n1. 保持身体活动。每天做适当的身体运动,如散步、跑步或游泳,能促进心血管健康,增强肌肉力量,并有助于减少体重。\n\n2. 均衡饮食。每天食用新鲜的蔬菜、水果、全谷物和脂肪含量低的蛋白质食物,避免高糖、高脂肪和加工食品,以保持健康的饮食习惯。\n\n3. 睡眠充足。睡眠对人体健康至关重要,成年人每天应保证 7-8 小时的睡眠。良好的睡眠有助于减轻压力,促进身体恢复,并提高注意力和记忆力。",
    "predict": "保持健康对于我们的身体和心理健康都非常重要。以下是三个保持健康的提示:\n\n1. 积极心态:积极心态可以帮助我们减轻压力,增强自信心,提高心理韧性,从而有助于保持心理健康。\n\n2. 均衡饮食:均衡饮食是保持健康的关键,我们应该吃各种颜色的蔬菜和水果,适量摄入优质蛋白质、健康脂肪和碳水化合物,避免过度食用或饮用高热量、高脂肪和高糖分的食物。\n\n3. 充足睡眠:睡眠是恢复身体和大脑功能的重要环节,我们应该尽量保证每晚7-8小时的睡眠时间,并创造一个安静、舒适的睡眠环境,避免过度使用电子设备、过度饮食和过度运动等不良睡眠习惯。"
}{
    "label": "三原色通常指的是红色、绿色和蓝色(RGB)。它们是通过加色混合原理创建色彩的三种基础颜色。在以发光为基础的显示设备中(如电视、计算机显示器、智能手机和平板电脑显示屏), 三原色可混合产生大量色彩。其中红色和绿色可以混合生成黄色,红色和蓝色可以混合生成品红色,蓝色和绿色可以混合生成青色。当红色、绿色和蓝色按相等比例混合时,可以产生白色或灰色。\n\n此外,在印刷和绘画中,三原色指的是以颜料为基础的红、黄和蓝颜色(RYB)。这三种颜色用以通过减色混合原理来创建色彩。不过,三原色的具体定义并不唯一,不同的颜色系统可能会采用不同的三原色。",
    "predict": "三原色是红色、绿色和蓝色,分别对应波长范围为约620-750纳米的红光、约495-570纳米的绿光和约450-495纳米的蓝光。在彩色显示、打印和电视技术中,我们通常使用红、绿、蓝三原色作为基本颜色,通过它们的不同组合可以产生各种颜色,这种方式也被称为“加色混合”。"
}{
    "label": "原子是物质的基本单位,它由三种基本粒子组成:质子、中子和电子。质子和中子形成原子核,位于原子中心,核外的电子围绕着原子核运动。\n\n原子结构具有层次性。原子核中,质子带正电,中子不带电(中性)。原子核非常小且致密,占据了原子总质量的绝大部分。电子带负电,通常围绕核运动,形成若干层次,称为壳层或电子层。电子数量与质子数量相等,使原子呈电中性。\n\n电子在每个壳层中都呈规律分布,并且不同壳层所能容纳的电子数也不同。在最里面的壳层一般只能容纳2个电子,其次一层最多可容纳8个电子,再往外的壳层可容纳的电子数逐层递增。\n\n原子核主要受到两种相互作用力的影响:强力和电磁力。强力的作用范围非常小,主要限制在原子核内,具有极强的吸引作用,使核子(质子和中子)紧密结合在一起。电磁力的作用范围较大,主要通过核外的电子与原子核相互作用,发挥作用。\n\n这就是原子的基本结构。原子内部结构复杂多样,不同元素的原子核中质子、中子数量不同,核外电子排布分布也不同,形成了丰富多彩的化学世界。",
    "predict": "原子由位于原子核中的质子与核外电子组成。质子带正电荷,电子带负电荷,质子与电子数目相等。因此,原子的结构可以用质子、中子、电子和核来描述。"
}
1
2
3
4
5
6
7
8
9
10

# 3.5 导出微调后的模型

创建个predict_result目录用于保存微调后的模型。

$ mkdir /home/user/export_models
$ cd /home/user/ChatGLM-Efficient-Tuning
$ python3 src/export_model.py \
    --model_name_or_path THUDM/chatglm2-6b \
    --finetuning_type lora \
    --checkpoint_dir /home/user/checkpoint \
    --output_dir /home/user/export_models
1
2
3
4
5
6
7

导出过程:大概耗时1min,将微调后的模型导出来了。

导出微调后的模型

导出模型,被保存在 /home/user/export_models 目录,文件列表如下:

config.json                          1.38 KB
configuration_chatglm.py             2.25 KB
generation_config.json               111 B
modeling_chatglm.py                  49.55 KB
pytorch_model-00001-of-00015.bin     932.95 MB
pytorch_model-00002-of-00015.bin     810.33 MB
pytorch_model-00003-of-00015.bin     777.67 MB
pytorch_model-00004-of-00015.bin     777.67 MB
pytorch_model-00005-of-00015.bin     777.67 MB
pytorch_model-00006-of-00015.bin     777.67 MB
pytorch_model-00007-of-00015.bin     777.67 MB
pytorch_model-00008-of-00015.bin     777.67 MB
pytorch_model-00009-of-00015.bin     777.67 MB
pytorch_model-00010-of-00015.bin     777.67 MB
pytorch_model-00011-of-00015.bin     777.67 MB
pytorch_model-00012-of-00015.bin     777.67 MB
pytorch_model-00013-of-00015.bin     777.67 MB
pytorch_model-00014-of-00015.bin     777.67 MB
pytorch_model-00015-of-00015.bin     827.70 MB
pytorch_model.bin.index.json         20.00 KB
quantization.py                      14.35 KB
special_tokens_map.json              3 B
tokenization_chatglm.py              9.84 KB
tokenizer.model                      994.54 KB
tokenizer_config.json                325 B
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

# 4. 参考资料

[1] 使用 Amazon SageMaker 微调和部署 ChatGLM 模型 from Amazon (opens new window)

[2] 大语言模型微调技术:SFT 监督微调、LoRA 微调方法、P-tuning v2 微调方法、Freeze 监督微调方法 from 稀土掘金 (opens new window)

[3] 大模型训练数据集介绍 from 知乎 (opens new window)

[4] 大模型LLM-微调经验分享&总结 from 知乎 (opens new window)

[5] 大模型参数高效微调技术原理综述(一)-背景、参数高效微调简介 from 吃果冻不吐果冻皮 (opens new window)

[6] 大模型参数高效微调技术原理综述(二)-BitFit、Prefix Tuning、Prompt Tuning from 吃果冻不吐果冻皮 (opens new window)

[7] 大模型参数高效微调技术原理综述(三)-P-Tuning、P-Tuning v2 from 吃果冻不吐果冻皮 (opens new window)

[8] 大模型参数高效微调技术原理综述(四)-Adapter Tuning及其变体 from 吃果冻不吐果冻皮 (opens new window)

[9] 大模型参数高效微调技术原理综述(五)-LoRA、AdaLoRA、QLoRA from 吃果冻不吐果冻皮 (opens new window)

[10] 大模型参数高效微调技术原理综述(六)-MAM Adapter、UniPELT from 吃果冻不吐果冻皮 (opens new window)

[11] 大模型实践总结 from 吃果冻不吐果冻皮 (opens new window)

[12] 分享大模型相关技术原理以及实战经验 from 吃果冻不吐果冻皮 (opens new window)

[13] 大模型微调方法综述 from 古月居 (opens new window)

[14] 落地领域大模型应知必会 (1) :主要微调方法总览 from 稀土掘金 (opens new window)

[15] 多模态大型语言模型的最新论文和数据集 from Github (opens new window)

[16] 大语言模型(LLM)微调技术笔记 from Github (opens new window)

[17] LLM大模型 指令微调、peft高效参数微调 from CSDN (opens new window)

[18] 人工智能大语言模型微调技术:SFT 、LoRA 、Freeze 监督微调方法 from Bilibili (opens new window)

[19] LLM时代,数据为王,19个开源数据集下载网站汇总 from 吃果冻不吐果冻皮 (opens new window)

[20] 使用LLaMa-Factory简单高效微调大模型 from 知乎 (opens new window)

Last Updated: 4/22/2024, 11:56:04 PM