Qwen25大模型微调实战系列



一、SFT微调定义

监督微调(Supervised Fine-Tuning):是一种大语言模型(LLM)微调技术。它通过在高质量的人工标注数据上进行有监督训练,使预训练模型具备更强的指令遵循能力、领域知识或特定风格。

二、不同框架的实现方式

本文中将以分类任务为例,介绍不同框架的微调过程。

2.1 LLaMAfactory框架

2.1.1 框架使用方法

>> unzip LLaMA-Factory-main.zip
>> pip install deepspeed==0.16.9    # 要求
>> cd LLaMA-Factory-main/
>> pip install -e ".[torch,metrics]"
  • Step3 :测试是否安装成功
>> llamafactory-cli version

安装成功,如下返回

  • Step4 :后续执行linux命令行时,建议把工作目录切换到解压的目录(LLaMA-Factory-main/)下。

2.1.2 数据格式

LLaMA-Factory-main/data/ 路径下存储数据格式文件、数据集文件等。

  • 数据按照所需格式生成json文件后,存放至LLaMA-Factory-main/data/ 路径下,并修改dataset_info.json文件。该文件包含所有经过预处理的本地数据集/在线数据集。如果使用自定义数据集,需要在dataset_info.json 文件中添加对数据集及其内容的定义。
2.1.2.1 Alpaca格式

生成的json文件中每行是一个json对象,其中instruction 对应的内容为人类指令input 对应的内容为人类输入output 对应的内容为模型回答。多轮对话场景中可以使用history,该列由多个字符串二元组构成的列表,分别代表历史消息中每轮对话的指令和回答。

  • 注意:在指令监督微调时,历史消息中的回答内容也会被用于模型学习。
{
  # 必填
  "instruction": "场景前提介绍,如:## 角色\n XXX。\n## 任务\n XXX。",
  # 选填
  "input": "人类输入",
  # 必填
  "output": "类别标签",
  # 选填
  "system": "系统提示词",
  # 选填
  "history": [
    ["第一轮指令", "第一轮回答"],
    ["第二轮指令", "第二轮回答"]
},

数据集按上述格式准备好之后上传至LLaMA-Factory-main/data/目录下,并修改目录下的dataset_info.json 文件。

,"数据集名称": {
  "file_name": "test_demo.json",
  "columns": {
    "prompt": "instruction",
    "query": "input",
    "response": "output",
    "system": "system",
    "history": "history"
  }
}
2.1.2.2 ShareGPT格式

sharegpt 格式支持 更多 的角色种类,例如 human、gpt、observation、function 等等。它们构成一个对象列表呈现在 conversations 列中。 下面只介绍ShareGPT格式中的特殊情况openai格式。生成的json文件是由多个json对象组成的List。

[
  {
    "messages": [
      # 人类指令,提示词
      {
        "role": "system",
        "content": ""
      },
      # 人类输入
      {
        "role": "user",
        "content": ""
      },
      # 模型回答
      {
        "role": "assistant",
        "content": ""
      }
    ]
  },{
     ...
  }
]

数据集按上述格式准备好之后上传至LLaMA-Factory-main/data/目录下,并修改目录下的dataset_info.json 文件。

,
"数据集名称": {
  "file_name": "数据集文件名",
  "formatting": "sharegpt",
  "columns": {
    "messages": "messages"
  },
  "tags": {
    "role_tag": "role",
    "content_tag": "content",
    "user_tag": "user",
    "assistant_tag": "assistant",
    "system_tag": "system"
  }
}

2.1.3 SFT 微调

  1. 编辑yaml配置文件(git仓库demo:examples/train_lora/llama3_lora_sft.yaml)。下述代码以lora微调为例。
  2. 执行微调命令。
  • sft-lora微调配置文件qwen25_72b_lora_sft.yaml,内容如下:
### model
model_name_or_path: ./qwen25-72B  # 基模路径
trust_remote_code: true

### method
stage: sft
do_train: true
finetuning_type: lora
lora_rank: 8
lora_alpha: 16
lora_dropout: 0.1
# lora_target: all # 默认是all

### dataset
dataset: 训练集数据集名称
template: qwen
cutoff_len: 8125  # 输入的最大 token 数,超过该长度会被截断。
overwrite_cache: true
preprocessing_num_workers: 16
# dataloader_num_workers: 4
# max_samples: 每个数据集的最大样本数:设置后,每个数据集的样本数将被截断至指定的 max_samples。

### output
output_dir: ./output/llamafactory-sft-72b  # 微调得到的lora module 存储路径
logging_steps: 10
save_steps: 500
plot_loss: true
overwrite_output_dir: true
save_only_model: false
report_to: tensorboard            # choices: [none, wandb, tensorboard, swanlab, mlflow]

### train
per_device_train_batch_size: 2    # 训练batchsize
gradient_accumulation_steps: 2    # 梯度累计步数
learning_rate: 3.0e-4             # 学习率
num_train_epochs: 5.0             # 训练epoch
bf16: true                        # 是否启用bf16精度
warmup_ratio: 0.05                # 预热比例
weight_decay: 0.01                # 梯度衰减
lr_scheduler_type: cosine
train_from_scratch: true          # 是否随机初始化模型权重,默认 false。
deepspeed: ./ds_z3_config.json    # 启用deepspeed zero-3 加速训练
ddp_timeout: 180000000            # 分布式数据并行的超时时间
resume_from_checkpoint: null      # 从断点模型恢复训练
# flash_attn: [“auto”, “disabled”, “sdpa”, “fa2”] 是否启用 FlashAttention 来加速训练和推理。

### eval
eval_dataset: 验证集数据集名称
# val_size: 0.1                   # 如果传入eval_dataset则无需传入该参数
# per_device_eval_batch_size: 1
# eval_strategy: steps            # 默认steps
eval_steps: 10
  • 命令行代码
>> NPROC_PER_NODE=4 ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 CUDA_VISIBLE_DEVICES=0,1,2,3 \
>> nohup llamafactory-cli train qwen25_72b_lora_sft.yaml > \
>> run.log 2>&1 & // 定向输出日志

2.1.4 部署

LLaMAfactory支持融合模型部署:先将训练后得到的lora module与基模融合,然后部署融合模型。
LLaMAfactory不支持并行部署多个lora module,仅支持多个lora module依次叠加部署。

  • adapter动态部署
>> API_PORT=8000 API_MODEL_NAME=qwen25_72-sft \
>> llamafactory-cli api qwen25_72b_sft_deploy.yaml

其中,部署配置文件qwen25_72b_sft_deploy.yaml内容如下:

model_name_or_path: 基模路径/基模名称
adapter_name_or_path: lora module 1 路径,...
template: qwen           # 训练和推理时构造 prompt 的模板
finetuning_type: lora
# 推理时使用的后端引擎,支持 huggingface 或 vllm,此处的vllm不支持多适配器并行部署。
infer_backend: huggingface 

# vLLM 特定配置
vllm_config: {
    max_model_len: 8125,
    gpu_memory_utilization: 0.9,
    # 自动截断相关配置
    enforce_eager: true,
    max_seq_len_to_capture: 8125
}

# 推理参数 infer_params
temperature: 0.01
max_new_tokens: 50  # 控制生成长度
# 添加截断策略
cutoff_len: 8125
  • 模型融合
// Llamafactory框架
> llamafactory-cli export ./merge_params.yaml

所需配置文件 merge_params.yaml 内容如下:

### model
model_name_or_path: 基模路径
# 说明:多个 adapter_name_or_path 按序顺序融合
adapter_name_or_path: 待融合的lora module 1, 待融合的lora module 2,... 
template: qwen
trust_remote_code: true

### export
export_dir: 融合模型输出路径
export_size: 5
export_device: cpu  # choices: [cpu, auto]
export_legacy_format: false

2.1.5 调用

from openai import OpenAI
# 部署命令中的端口号
API_PORT = 8000
client = OpenAI(
    api_key='EMPTY',
    base_url=f'http://0.0.0.0:{API_PORT}/v1',
)

# 调用
messages = "" # 人类输入
response = client.chat.completions.create(
                   messages=messages, 
                   temperature=0)

2.2 Swift框架

2.2.1 数据格式

数据文件中每行是一条message标准格式、文件类型是jsonl格式。

{"messages": [
   {"role": "system", "content": "人类指令"}, 
   {"role": "user", "content": "人类输入"}, 
   {"role": "assistant", "content": "llm输出"}
   ]
},{"messages": []
}

2.2.2 SFT 训练命令

>> NPROC_PER_NODE=4 ASCEND_RT_VISIBLE_DEVICES=0,1,2,3 \
>> nohup swift sft --torch_dtype 'bfloat16' --model '/mnt/basemodel/qwen25-72B-instruct' \
>> --model_type 'qwen2_5' --template 'qwen2_5' \
>> --dataset '数据集路径' --split_dataset_ratio '0.1' --max_length '8125' --init_weights 'True' --per_device_train_batch_size '2' --learning_rate '3e-4' --attn_impl 'flash_attn' --gradient_accumulation_steps '2' --eval_steps '10' \
>> --output_dir '输出路径' --truncation_strategy 'delete' --lora_alpha '16' --lora_dropout '0.1' --deepspeed 'zero3' --report_to 'tensorboard' --num_train_epochs '5' --warmup_ratio '0.05' --weight_decay '0.01' --save_strategy 'epoch' --add_version False \
>> --logging_dir 日志存储路径 --ignore_args_error True > run.log 2>&1 &

2.2.3 部署

2.2.3.1 融合模型部署

先将训练后得到的lora module与基模融合,然后部署融合模型。

  • 模型融合
>> swift export \
>> --adapters [lora module 路径,如:/checkpoint-2/] \
>> --merge_lora true
  • adapter动态部署
>> vllm serve './checkpoint-2-merged' --tensor-parallel-size 4 --gpu-memory-utilization 0.98 \
>> --served-model-name qwen72b-sft

2.2.3.2 lora module动态部署

采用VLLM框架,支持多个lora module 并行部署,一个基模同时挂载多个lora module,提供不同接口进行调用。

> vllm serve 基模路径 \
> --tensor-parallel-size 4 --enable-lora \
> --lora-modules \
>           模型1调用名 = lora module 1 所在路径 \
>           模型2调用名 = lora module 2 所在路径
>           ...

2.2.4 调用

from openai import OpenAI
# 部署命令中的端口号
API_PORT = 8000
client = OpenAI(
    api_key='EMPTY',
    base_url=f'http://0.0.0.0:{API_PORT}/v1',
)

# 调用
model_name = "模型1调用名" # /"模型2调用名"
messages = "" # 人类输入
response = client.chat.completions.create(
                   model=model_name, 
                   messages=messages, 
                   temperature=0)

Done

更多推荐