赞
踩
LLM微调可以对原有预模型进行专业领域知识的训练,相关领域知识需要进行预处理整理成语料,语料越充分相对来说微调后的模型预测越准,还要结合调参,反复地训练,才有可能达到预期的效果。
微调模型有多种,包括P-Tuning、LoRA等。本次实践采用P-Tuning。
序号 | 资源明细 |
---|---|
1 | aliyun PAI-DSW,32G内存,16G显卡(NVidia Tesla V100),Ubuntu20.04。 |
2 | 镜像环境:pytorch=2.1.2、cuda=12.1、python=3.10、Tensorflow=2.14.0 |
3 | 镜像环境:ChatGLM2-6B、P-Tuning V2 |
4 | 数据集:采用公开数据集AdvertiseGen |
在实践前,自行部署好ChatGLM、P-Tuning等,不在此篇赘述。
检查是否在自己安装好的conda chatgml环境中,或者直接激活conda环境。
conda info --envs
conda activate chatglm
重启终端。
安装transformers、jieba、datasets等
# 本次实践进行微调需要 4.27.1 版本的 transformers
install transformers==4.27.1
pip install rouge_chinese nltk jieba datasets
jieba 等库必须安装,否则执行bash train.sh时会报错。
# 禁用 W&B
export WANDB_DISABLED=true
公开数据集,在镜像中直接下载语料库,语料库正常下载下来名为AdvertiseGen.tar.gz。在ubuntu中使用wget:
wget https://cloud.tsinghua.edu.cn/f/b3f119a008264b1cabd1/?dl=1
或者
wget --no-check-certificate --no-cookies --header “Cookie: oraclelicense=accept-securebackup-cookie” https://cloud.tsinghua.edu.cn/f/b3f119a008264b1cabd1/?dl=1
两种方式下载后结果一样,下载到本地的文件都被命名为:index.html?dl=1。这个问题可能是特例。
以为下载错误,但是观察容量大小,16M左右,正好是AdvertiseGen.tar.gz的大小。人工把“.html?dl=1”改成“.tar.gz”后缀,然后用命令解压:
tar -zxvf traindatabase.tar.gz
解压后获得dev.json和train.json,正确,这就是需要的训练数据集和测试数据集。
把两个json文件复制/ChatGLM2-6B/ptuning/AdvertiseGen下,其中AdvertiseGen是人工新建。看其他教程,这个新建的目录可以叫任意名字,但是需要修改sh文件里的默认路径名,这个主要看个人喜好。
1、train_file、validation_file和test_file修改成自己的 JSON 格式数据集路径
本人路径与文件默认路径一致,不需要修改。
2、将 prompt_column 和 response_column 改为 JSON 文件中输入文本和输出文本对应的 KEY
这个KEY指的是json中的key:value,本人下载的与文件默认参数一致,不需要修改。
3、可能还需要增大 max_source_length 和 max_target_length 来匹配你自己的数据集中的最大输入输出长度。
保持默认参数,没有修改。
4、并将模型路径 THUDM/chatglm2-6b 改为你本地的模型路径。
修改为:–model_name_or_path /mnt/workspace/ChatGLM2-6B/THUDM/chatglm2-6b \
说明:
在 P-tuning v2 训练时模型只保存 PrefixEncoder 部分的参数,所以在推理时需要同时加载原 ChatGLM-6B 模型以及 PrefixEncoder 的权重,因此需要指定 evaluate.sh 中的参数:
#仅作为说明使用,具体设置以上述内容为准
--model_name_or_path THUDM/chatglm-6b
--ptuning_checkpoint $CHECKPOINT_PATH
PRE_SEQ_LEN=128: 定义了一个名为PRE_SEQ_LEN的变量,并将其设置为128。这个变量的作用在后续的代码中会用到。
LR=2e-2: 定义了一个名为LR的变量,并将其设置为2e-2,即0.02。这个变量表示学习率,在后续的代码中会用到。
–train_file /root/train.json : 指定训练数据文件的路径和文件名为"/root/train.json"。
–validation_file /root/verify.json : 指定验证数据文件的路径和文件名为"/root/verify.json"。
–prompt_column content : 指定输入数据中作为提示的列名为"content"。
–response_column summary : 指定输入数据中作为响应的列名为"summary"。
–overwrite_cache : 一个命令行参数,指示在缓存存在的情况下覆盖缓存。
–model_name_or_path THUDM/chatglm-6b : 指定使用的模型的名称或路径为"THUDM/chatglm-6b"。
–output_dir output/adgen-chatglm-6b-pt-PRESEQLEN−PRE_SEQ_LEN-PRE
SEQLEN−LR : 指定输出目录的路径和名称为"output/adgen-chatglm-6b-pt-P R E SEQLEN − PRE_SEQ_LEN-PRESEQLEN−LR"。这是训练结果和日志的保存位置。
–overwrite_output_dir : 一个命令行参数,指示在输出目录存在的情况下覆盖输出目录。
–max_source_length 512 : 指定输入序列的最大长度为512。
–max_target_length 512 : 指定输出序列的最大长度为512。
–per_device_train_batch_size 1 : 指定每个训练设备的训练批次大小为1。
–per_device_eval_batch_size 1 : 指定每个评估设备的评估批次大小为1。
–gradient_accumulation_steps 16 : 指定梯度累积的步数为16。在每个更新步骤之前,将计算并累积一定数量的梯度。
–predict_with_generate : 一个命令行参数,指示在生成模型的预测时使用生成模式。
–max_steps 3000 : 指定训练的最大步数为3000。
–logging_steps 10 : 指定每隔10个步骤记录一次日志。
–save_steps 1000 : 指定每隔1000个步骤保存一次模型。
–learning_rate $LR : 指定学习率为之前定义的LR变量的值。
–pre_seq_len $PRE_SEQ_LEN : 指定预设序列长度为之前定义的PRE_SEQ_LEN变量的值。
–quantization_bit 4 : 指定量化位数为4。这个参数可能是与模型相关的特定设置。
cd ptuning
bash train.sh
训练总耗时:5小时
训练耗时请大家自行判断:
网上有教程对AdvertiseGen数据集进行微调,总耗时11个小时。
网上有教程对只有5条Pompt的数据集进行微调训练,总耗时50分钟。
bash evaluate.sh
耗时:58分钟
先加入原始模型
import torch
import os
from transformers import AutoConfig, AutoModel, AutoTokenizer
# 载入Tokenizer
tokenizer = AutoTokenizer.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True)
config = AutoConfig.from_pretrained("THUDM/chatglm2-6b", trust_remote_code=True, pre_seq_len=128)
model = AutoModel.from_pretrained("THUDM/chatglm2-6b", config=config, trust_remote_code=True)
在此步骤后继可以有两种后继处理,一种是加入微调后的模型;一种是直接使用原始LLM预训练模型进行对话。
本实践继续加载微调模型:
#如果要调用微调后的
#checkpoint-3000情况下,模型完全忘记了原始模型,不管问什么回答全是微调内容
prefix_state_dict = torch.load(os.path.join("ptuning/output/adgen-chatglm2-6b-pt-128-2e-2/checkpoint-3000", "pytorch_model.bin"))
new_prefix_state_dict = {}
for k, v in prefix_state_dict.items():
if k.startswith("transformer.prefix_encoder."):
new_prefix_state_dict[k[len("transformer.prefix_encoder."):]] = v
model.transformer.prefix_encoder.load_state_dict(new_prefix_state_dict)
模型继续处理
# Comment out the following line if you don't use quantization
model = model.quantize(4)
model = model.cuda()
model = model.eval()
使用微调后的新模型开始对话
response, history = model.chat(tokenizer, "你好", history=[])
print(response)
对于"<|user|>你好"的<|assistant|>回答,很奇葩。卖个关子,不截图出来了。大家自行体验。
随着对P-Tuning理解加深,微调后的新模型改变了认知,似乎都忘记了,回答变得很奇怪了。
B站上有个官方视频,里面提到了一句关于此种现象的解决办法,大意是:在使用AdvertiseGen数据集时,加入通用数据集一起微调。
一个很意外的错误:在train.sh\evaluate.sh连个文件中–nproc-per-node中划线不对,应该改成下划线,如下:
#--nproc-per-node写的不对
torchrun --standalone --nnodes=1 --nproc-per-node=$NUM_GPUS main.py
改成
torchrun --standalone --nnodes=1 --nproc_per_node=$NUM_GPUS main.py
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。