引言
模型微调是一种低成本、高收益的方式,用于提升预训练模型在特定领域的性能和表现。通过让模型学习少量特定领域的知识库数据,并对模型参数进行适当调整,可在不显著增加成本的前提下提升模型在该领域的应用效果。
模型微调的方式有很多种,例如LoRA、P-tuning、adapter-tuning等,每种微调方式都有适用的场景和任务,大家可根据需求和场景自行测试验证(后续会持续更新各种微调技术的核心原理和实现方式),今天我们使用最常用到的LoRA技术对GLM-4-9B-Chat模型进行微调。
数据处理
数据集格式
模型微调的效果与微调时采用的数据质量有很大关系,所以在微调时我们需要先准备一批高质量的领域数据。LoRA微调GLM-4需要“多轮对话格式”的数据集,可以理解人一问一答式的结构,例如:
{
"messages":
[
{
"role": "user",
"content": "你是谁?"
},
{
"role": "assistant",
"content": "我是您的AI助手Leo,您可以问我任何关于AI相关的知识!"}
]
}
以上的例子中就是一问一答的格式,其中"role":"user"指定了用户的角色、“content”: "你是谁?"指定了用户的相关问题;“role”: "assistant"指定了AI助理的角色,“content”: "我是您的AI助手Leo,您可以问我任何关于AI相关的知识!"制定了AI的回答。
**微调的主要目标就是希望模型能够学会特定领域中的对话风格、专业术语和任务的解决方案。**因此,数据集需要精心设计,否则模型同样会出现幻觉、鲁棒性不够等问题。
数据预处理
这里我们使用常见的excel格式知识库作为源数据为大家演示如何使用代码批量将excel数据转成微调所需的数据,微调GLM-4-9B-Chat时需要准备两份文件:训练数据集"train.jsonl"和评估数据集"dev.jsonl"。首先来处理"train.jsonl":
import json
import pandas as pd
def process_and_transform_file(input_path, output_path):
try:
intermediate_data = []
prompt, response = "", ""
# 读取excel文件
df = pd.read_excel(input_path, engine='openpyxl')
# 遍历读取样本的每行数据
for row in df.itertuples():
if row[1] and row[2]:
prompt, response = row[1].strip(), row[2].strip()
intermediate_data.append({"prompt": prompt, "response": response})
with open(output_path, "w", encoding='utf-8') as output_file:
for entry in intermediate_data:
transformed_data = {
"messages": [
{"role": "user", "content": entry["prompt"]},
{"role": "assistant", "content": entry["response"]}
]
}
output_file.write(json.dumps(transformed_data, ensure_ascii=False) + '\n')
print(f"转换完成,文件保存至:{output_path}")
except Exception as e:
print(f"处理文件时发生错误:{e}")
input_path = "dataset/测试数据_0.1.xlsx"
output_path = "dataset/train.jsonl"
process_and_transform_file(input_path, output_path)
执行完成后将得到类似以下格式的json文件:
评估数据集"dev.jsonl"文件中的数据是从训练数据集"train.jsonl"中随机采集的样本数据,训练过程中用来评估模型学习的效果,这个可以根据训练数据集数量大小灵活采集,以下是处理"dev.jsonl"的示例代码:
import json
import random
import os
# 1、读取train数据集
# 2、随机100条数据作为dev数据集
# 3、将100条dev数据集保存到dev.jsonl文件中
def load_dataset(file_path):
""" 加载train.jsonl数据集集 """
with open(file_path, 'r', encoding='utf-8') as f:
data = [json.loads(line) for line in f]
return data
def select_random_samples(data, num_sample=100):
""" 随机选择样本数据,如果num_sample的数量大于data也仅仅返回data中的全部数据 """
return random.sample(data, min(num_sample, len(data)))
def save_samples_to_file(output_file_path, samples):
os.makedirs(os.path.dirname(output_file_path), exist_ok=True)
with open(output_file_path, 'w', encoding='utf-8') as f:
for item in samples:
json.dump(item, f, ensure_ascii=False)
f.write('\n')
def create_dev_json_from_train_json(input_file_path, output_file_path, num_sample=100):
data = load_dataset(input_file_path)
dev_data = select_random_samples(data, num_sample)
save_samples_to_file(output_file_path, dev_data)
print(f"开发数据集已创建完成,保存至:{output_file_path}")
if __name__ == '__main__':
train_file_path = 'dataset/train.jsonl'
dev_file_path = 'dataset/dev.jsonl'
num_sample = 100
create_dev_json_from_train_json(train_file_path, dev_file_path, num_sample)
执行完成后即可得到"dev.jsonl"文件,至此数据准备和处理阶段就完成了!大家自行根据数据格式修改数据处理的代码,但是要注意不能改变结构,如果使用其他三方微调框架进行模型微调可基于框架约定即可。
环境搭建
基础环境准备
操作系统的基础环境要求跟部署模型要求一致,可沿用部署模型时的环境准备,也可参考上一篇文章:超详细GLM-4-chat模型部署;当然了,如果仅仅是为了学习和验证,也可以直接租赁三方算力平台的机器,会相对简单一些无需再安装和配置CUDA、Python、Pytorch等基础依赖环境,这里我直接租用一台给大家做演示:
直接选择好需要用到的PyTorch、Python、CUDA对应版本镜像即可,不需要自己再折腾一遍了还是比较方便的~
模型环境搭建
准备好基础环境好我们就可以开始搭建模型环境了, 基本上就比较简单了,按照以下步骤执行即可:
-
升级pip版本,确保使用的pip版本是最新的:
python -m pip install --upgrade pip
-
更换pypi源,推荐使用清华大学的TUNA镜像源,在国内环境下载依赖会比较快,可以使用以下命令:
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
-
安装必要的依赖包,主要安装微调时用到的transformers和peft库,如果需要实时下载模型镜像也可以安装ModelScope的依赖,可以使用以下命令:
pip install modelscope==1.9.5 pip install "transformers>=4.40.0" pip install streamlit==1.24.0 pip install sentencepiece==0.1.99 pip install accelerate==0.29.3 pip install datasets==2.13.0 pip install peft==0.10.0 pip install tiktoken==0.7.0
依赖下载完成后整个环境准备就完成了,接下来还是需要准备"GLM-4-9B-Chat"模型文件和GLM-4的代码仓库;如果需要使用ModelScope库进行下载可以使用以下代码:
import torch
from modelscope import snapshot_download, AutoModel, AutoTokenizer
import os
model_dir = snapshot_download('ZhipuAI/glm-4-9b-chat', cache_dir='/root/workspace', revision='master')
将该python文件放在服务器执行即可,其中cache_dir需要改为模型下载到本地的目录,整个下载过程大约30分钟左右;
下载GLM-4的代码仓库可使用以下命令:
git clone https://github.com/THUDM/GLM-4
模型文件和源码仓库下载完成整个环境搭建就完成了,这就可以开始做模型微调了!
模型微调
Lora参数配置
智谱为我们提供了LoRA、P-Tuning V2两种模型微调的相关代码和配置文件,我们不需要再开发一套模型微调的代码;
● 首先找到模型微调的代码文件:finetune_demo文件夹,执行以下命令:
# 进入项目目录
cd GLM-4/
# 进入模型微调代码目录
cd finetune_demo/
文件夹目录如下:
其中configs目录是用于存放模型微调需要用到的配置文件,该文件夹包含如下文件:
LoRA微调时我们只需修改lora.yaml中的配置即可。
● 修改lora.yaml文件,该文件主要内容解释如下:
data_config 部分
train_file: 训练数据集的文件路径。
val_file: 验证数据集的文件路径。
test_file: 测试数据集的文件路径。
num_proc: 在加载数据时使用的进程数量。
max_input_length: 输入序列的最大长度。
max_output_length: 输出序列的最大长度。
training_args 部分
output_dir: 用于保存模型和其他输出的目录。
max_steps: 训练的最大步数。
learning_rate: 学习率
per_device_train_batch_size: 每个设备(如 GPU)的训练批次大小。
dataloader_num_workers: 加载数据时使用的工作线程数量。
remove_unused_columns: 是否移除数据中未使用的列。
save_strategy: 模型保存策略(例如,每隔多少步保存一次)。
save_steps: 每隔多少步保存一次模型。
log_level: 日志级别(如 info)。
logging_strategy: 日志记录策略。
logging_steps: 每隔多少步记录一次日志。
per_device_eval_batch_size: 每个设备的评估批次大小。
evaluation_strategy: 评估策略(例如,每隔多少步进行一次评估)。
eval_steps: 每隔多少步进行一次评估。
predict_with_generate: 是否使用生成模式进行预测。
generation_config 部分
max_new_tokens: 生成的最大新 token 数量。
peft_config 部分
peft_type: 使用的参数有效调整类型 (支持 LORA 和 PREFIX_TUNING)。
task_type: 任务类型,这里是因果语言模型 (不要改动)。
r: LoRA 的秩。
lora_alpha: LoRA 的缩放因子。
lora_dropout: 在 LoRA 层使用的 dropout 概率。
这里我们需要关注几个重要的点:
● data_config 部分:
○ 要把我们在上面生成的数据集(train.jsonl、dev.jsonl)上传到configs目录,如果放在其他目录中请修改对应的文件位置;
● training_args部分
○ output_dir:这个主要是用于指定模型微调完之后输出新模型存放的位置,可以不改如果有需要指定其他位置自行调整即可;
○ max_steps:这个参数的设置取决于多个因素,包括但不限于模型复杂度、训练数据集的复杂度、训练资源等,一般可参考公式:max_steps = (总训练样本数 / batch_size) * num_epochs;
○ learning_rate:学习率也是非常重要的参数,一般是0-1之间;这个值不能太大也不能太小,需要根据模型和数据集复杂度来调控,后面其他章节会详细解释;
● peft_config 部分
○ r:这个是最主要的参数,该参数决定模型降级的矩阵大小,一般为8的倍数;同样该参数没有绝对值,需要根据数据集复杂度和模型复杂度来测试效果,可以从16开始;
○ lora_alpha:LoRA的缩放因子,该参数是在前向传播过程中将LoRA参数以一定的缩放比例应用于模型之中,可以设置为r的倍数或者r的半数,这个同样需要自行调优,后面会详细介绍;
以上是我们在用LoRA微调时需要关注的几个关键参数,对于LoRA微调的细节和参数设置细节这里不做介绍,后面会有专门文章来介绍,感兴趣的同学可以持续关注~
以下为修改后的参数:
data_config:
train_file: train.jsonl
val_file: dev.jsonl
test_file: dev.jsonl
num_proc: 1
combine: True
max_input_length: 512
max_output_length: 512
training_args:
# see `transformers.Seq2SeqTrainingArguments`
output_dir: ./output
max_steps: 2500
# needed to be fit for the dataset
learning_rate: 1e-4
# settings for data loading
per_device_train_batch_size: 1
dataloader_num_workers: 16
remove_unused_columns: false
# settings for saving checkpoints
save_strategy: steps
save_steps: 500
# settings for logging
log_level: info
logging_strategy: steps
logging_steps: 10
# settings for evaluation
per_device_eval_batch_size: 4
eval_strategy: steps
eval_steps: 500
# settings for optimizer
# adam_epsilon: 1e-6
# uncomment the following line to detect nan or inf values
# debug: underflow_overflow
predict_with_generate: true
# see `transformers.GenerationConfig`
generation_config:
max_new_tokens: 512
# set your absolute deepspeed path here
# deepspeed: configs/ds_zero_3.json
peft_config:
peft_type: LORA
task_type: CAUSAL_LM
r: 16
lora_alpha: 32
lora_dropout: 0.1
target_modules: ["query_key_value"]
开始模型训练
修改完lora.yaml的配置文件后就可以开始微调模型了,在开始执行微调命令之前需要先执行以下命令安装相关依赖:
pip install -r requirements.txt
出现以下内容则依赖安装成功:
这就开始训练模型了,训练模型可执行以下命令:
python finetune.py data/AdvertiseGen/ /root/shared-storage/glm-4 configs/lora.yaml
其中finetune.py为智谱开源的模型微调代码文件、data/AdvertiseGen/为数据所在的位置、/root/workspace/GLM-4-9B-Chat 为基础模型所在的位置、configs/lora.yaml是我们修改好的lora.yaml配置文件,这些文件位置大家都可根据需要自行调整!
执行命令时如果出现以上错误说明缺少相关依赖,只需要执行命令安装一下即可:
pip install typer
安装完成后再次执行模型微调命令即可开始模型微调,出现以下输出则说明已经在开始训练了:
这里我们需要关注**'loss’的值,这个值是“损失函数”,可以理解为结果与理想数据之间的差距;这个值越小越好,如果过大则表示欠拟合、先下降后上升表示过拟合**,这个值的变化也是跟很多因素有关系;通过该值可以来发现需要调整的方向,比如模型过于复杂、数据集过于复杂等等,后续也会有专题文章来解释。
接下来就等待模型学习完成就好了~
后面会介绍微调完之后怎么验证模型效果、如何合并模型、如何使用微调后的模型进行推理!感兴趣的同学可以持续关注~