L1G5-XTuner 微调个人小助手认知

L1G5-XTuner 微调个人小助手认知

1. 概念明晰

1.1 指令微调的概念

首先我们要认清指令微调的大模型训练过程中所属的位置:

大模型的训练过程可以分成预训练和后训练两个阶段:

image-20250217124512992

而指令微调就是后训练的第一步:

image-20250217123824893

指令微调这一步有三种范式,要注意第三种范式也叫做指令微调。

其中第二和第三种范式类似于培养专才和通才的区别。

img

1.2 微调与强化学习偏好优化

通常,微调(Fine-tuning)指的是在预训练模型的基础上,使用特定任务的数据继续训练,以适应该任务。而强化学习偏好优化,比如RLHF(基于人类反馈的强化学习),则是通过强化学习的框架,利用奖励模型来调整模型的行为,使其符合人类偏好,

(1) 狭义 vs 广义的“微调”

  • 狭义微调:仅指监督学习框架下的参数调整(如分类、生成任务)。
  • 广义微调:涵盖所有基于预训练模型的参数更新(包括监督学习、强化学习、甚至prompt tuning)。

(2) 学术界与工业界的术语差异

  • 部分文献严格区分“Fine-tuning”和“RLHF”,认为二者分属不同范式;
  • 工程实践中常将RLHF视为“对齐阶段的微调”,因其共享底层技术栈(如PyTorch训练流程)。

(3)深度学习的分类和参数更新方式两种角度

  • 从深度学习的分类来看:后训练中的第一步指令微调是监督学习框架下的微调(SFT,Supervised Fine-Turing),属于严格意义上的微调。;第二步偏好优化是通过强化学习框架,利用奖励信号来优化模型,不属于严格意义上的微调。

  • 从参数更新方式来看:指令微调在更新预训练模型的参数可以分为全参数更新和参数高效两种方式;强化学习偏好优化一般是全参数更新,但也可以结合参数高效方法。

1.3 教程中提到的增量预训练微调和指令跟随微调

在1.1和1.2的理论框架下,我们来理解教程中提到的增量预训练微调和指令跟随微调。

  • 基座模型:指的是经过预训练阶段得到的模型;

  • 增量预训练微调:这一步算是二次预训练,拓充基座模型的潜能,严格来说不属于后训练阶段。

  • 指令跟随微调:就是后训练阶段的第一步指令微调,从教程中具体的训练数据来看,是指令微调的第二种范式,先通过预训练获得足够强的先验,然后在目标任务上进行微调,培养“专才”。

两种finetune范式

2. 任务步骤

2.1 创建虚拟环境

conda create -n xtuner-env-l1 python=3.10 -y
conda activate xtuner-env-l1

安装依赖

pip install -r requirements.txt

验证安装:

为了验证 XTuner 是否安装正确,我们将使用命令打印配置文件。

打印配置文件:在命令行中使用 xtuner list-cfg 验证是否能打印配置文件列表,输出内容为 XTuner 支持微调的模型。

xtuner list-cfg

image-20250217153328447

2.2 修改提供的数据

2.2.1 创建一个新的文件夹用于存储微调数据

image-20250217135639614

2.2.2 创建修改脚本并执行

创建change_script.py文件并修改如下:

import json
import argparse
from tqdm import tqdm

def process_line(line, old_text, new_text):
    # 解析 JSON 行
    data = json.loads(line)
    
    # 递归函数来处理嵌套的字典和列表
    def replace_text(obj):
        if isinstance(obj, dict):
            return {k: replace_text(v) for k, v in obj.items()}
        elif isinstance(obj, list):
            return [replace_text(item) for item in obj]
        elif isinstance(obj, str):
            return obj.replace(old_text, new_text)
        else:
            return obj
    
    # 处理整个 JSON 对象
    processed_data = replace_text(data)
    
    # 将处理后的对象转回 JSON 字符串
    return json.dumps(processed_data, ensure_ascii=False)

def main(input_file, output_file, old_text, new_text):
    with open(input_file, 'r', encoding='utf-8') as infile, \
         open(output_file, 'w', encoding='utf-8') as outfile:
        
        # 计算总行数用于进度条
        total_lines = sum(1 for _ in infile)
        infile.seek(0)  # 重置文件指针到开头
        
        # 使用 tqdm 创建进度条
        for line in tqdm(infile, total=total_lines, desc="Processing"):
            processed_line = process_line(line.strip(), old_text, new_text)
            outfile.write(processed_line + '\n')

if __name__ == "__main__":
    parser = argparse.ArgumentParser(description="Replace text in a JSONL file.")
    parser.add_argument("input_file", help="Input JSONL file to process")
    parser.add_argument("output_file", help="Output file for processed JSONL")
    parser.add_argument("--old_text", default="尖米", help="Text to be replaced")
    parser.add_argument("--new_text", default="sakuralggm", help="Text to replace with")
    args = parser.parse_args()

    main(args.input_file, args.output_file, args.old_text, args.new_text)

该脚本的作用是将微调数据文件assistant_Tuner.jsonl中的“尖米”改为“sakuralggm”,来训练预训练模型的自我认知。

执行命令:

# usage:python change_script.py {input_file.jsonl} {output_file.jsonl}
cd ~/finetune/data
python change_script.py ./assistant_Tuner.jsonl ./assistant_Tuner_change.jsonl

得到结果:

image-20250217140400616

2.3 训练启动

2.3.1 复制模型

在InternStudio开发机中的已经提供了要被微调的模型,可以直接软链接即可。

本模型位于/root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat

mkdir /root/finetune/models

ln -s /root/share/new_models/Shanghai_AI_Laboratory/internlm2_5-7b-chat /root/finetune/models/internlm2_5-7b-chat

结果如下:

image-20250217140646792

2.3.2 修改 Config

获取官方写好的 config

# cd {path/to/finetune}
cd /root/finetune
mkdir ./config
cd config
xtuner copy-cfg internlm2_5_chat_7b_qlora_alpaca_e3 ./

2.3.3 启动微调

当我们准备好了所有内容,我们只需要将使用 xtuner train 命令令即可开始训练。

xtuner train 命令用于启动模型微调进程。该命令需要一个参数:CONFIG 用于指定微调配置文件。这里我们使用修改好的配置文件 internlm2_5_chat_7b_qlora_alpaca_e3_copy.py
训练过程中产生的所有文件,包括日志、配置文件、检查点文件、微调后的模型等,默认保存在 work_dirs 目录下,我们也可以通过添加 --work-dir 指定特定的文件保存位置。--deepspeed 则为使用 deepspeed, deepspeed 可以节约显存。

运行命令进行微调

cd /root/finetune
conda activate xtuner-env

xtuner train ./config/internlm2_5_chat_7b_qlora_alpaca_e3_copy.py --deepspeed deepspeed_zero2 --work-dir ./work_dirs/assistTuner

微调得到的权重如下:

image-20250217165924503

2.3.4 权重转换

模型转换的本质其实就是将原本使用 Pytorch 训练出来的模型权重文件转换为目前通用的 HuggingFace 格式文件,那么我们可以通过以下命令来实现一键转换。

我们可以使用 xtuner convert pth_to_hf 命令来进行模型格式转换。

xtuner convert pth_to_hf 命令用于进行模型格式转换。该命令需要三个参数:CONFIG 表示微调的配置文件, PATH_TO_PTH_MODEL 表示微调的模型权重文件路径,即要转换的模型权重, SAVE_PATH_TO_HF_MODEL 表示转换后的 HuggingFace 格式文件的保存路径。

除此之外,我们其实还可以在转换的命令中添加几个额外的参数,包括:

参数名 解释
--fp32 代表以fp32的精度开启,假如不输入则默认为fp16
--max-shard-size 代表每个权重文件最大的大小(默认为2GB)
cd /root/finetune/work_dirs/assistTuner

conda activate xtuner-env

# 先获取最后保存的一个pth文件
pth_file=`ls -t /root/finetune/work_dirs/assistTuner/*.pth | head -n 1 | sed 's/:$//'`
export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
xtuner convert pth_to_hf ./internlm2_5_chat_7b_qlora_alpaca_e3_copy.py ${pth_file} ./hf

模型格式转换完成后,我们得到的hugging face格式如下:

image-20250217175618033

转换完成后,可以看到模型被转换为 HuggingFace 中常用的 .bin 格式文件,这就代表着文件成功被转化为 HuggingFace 格式了。

此时,hf 文件夹即为我们平时所理解的所谓 “LoRA 模型文件”

可以简单理解:LoRA 模型文件 = Adapter

bug fix:pytorch版本不对
  1. 问题的发现:

    一开始直接使用pip install -r requirements.txt,在微调阶段没有报错,但在权重转换时出错:

    /root/.conda/envs/xtuner-env-l1/lib/python3.10/site-packages/mmengine/optim/optimizer/zero_optimizer.py:11: DeprecationWarning: TorchScript support for functional optimizers is deprecated and will be removed in a future PyTorch release. Consider using the torch.compile optimizer instead.
      from torch.distributed.optim import \
    [2025-02-17 17:13:38,172] [INFO] [real_accelerator.py:191:get_accelerator] Setting ds_accelerator to cuda (auto detect)
    /root/.conda/envs/xtuner-env-l1/lib/python3.10/site-packages/deepspeed/runtime/zero/linear.py:49: FutureWarning: torch.cuda.amp.custom_fwd(args...) is deprecated. Please use torch.amp.custom_fwd(args..., device_type='cuda') instead.
      def forward(ctx, input, weight, bias=None):
    /root/.conda/envs/xtuner-env-l1/lib/python3.10/site-packages/deepspeed/runtime/zero/linear.py:67: FutureWarning: torch.cuda.amp.custom_bwd(args...) is deprecated. Please use torch.amp.custom_bwd(args..., device_type='cuda') instead.
      def backward(ctx, grad_output):
    02/17 17:13:45 - mmengine - WARNING - WARNING: command error: 'cannot import name 'log' from 'torch.distributed.elastic.agent.server.api' (/root/.conda/envs/xtuner-env-l1/lib/python3.10/site-packages/torch/distributed/elastic/agent/server/api.py)'!
    02/17 17:13:45 - mmengine - WARNING - 
        Arguments received: ['xtuner', 'convert', 'pth_to_hf', './internlm2_5_chat_7b_qlora_alpaca_e3_copy.py', '/root/finetune/work_dirs/assistTuner/iter_927.pth', './hf']. xtuner commands use the following syntax:
    
            xtuner MODE MODE_ARGS ARGS
    
            Where   MODE (required) is one of ('list-cfg', 'copy-cfg', 'log-dataset', 'check-custom-dataset', 'train', 'test', 'chat', 'convert', 'preprocess', 'mmbench', 'eval_refcoco')
                    MODE_ARG (optional) is the argument for specific mode
                    ARGS (optional) are the arguments for specific command
    
        Some usages for xtuner commands: (See more by using -h for specific command!)
    
            1. List all predefined configs:
                xtuner list-cfg
            2. Copy a predefined config to a given path:
                xtuner copy-cfg $CONFIG $SAVE_FILE
            3-1. Fine-tune LLMs by a single GPU:
                xtuner train $CONFIG
            3-2. Fine-tune LLMs by multiple GPUs:
                NPROC_PER_NODE=$NGPUS NNODES=$NNODES NODE_RANK=$NODE_RANK PORT=$PORT ADDR=$ADDR xtuner dist_train $CONFIG $GPUS
            4-1. Convert the pth model to HuggingFace's model:
                xtuner convert pth_to_hf $CONFIG $PATH_TO_PTH_MODEL $SAVE_PATH_TO_HF_MODEL
            4-2. Merge the HuggingFace's adapter to the pretrained base model:
                xtuner convert merge $LLM $ADAPTER $SAVE_PATH
                xtuner convert merge $CLIP $ADAPTER $SAVE_PATH --is-clip
            4-3. Split HuggingFace's LLM to the smallest sharded one:
                xtuner convert split $LLM $SAVE_PATH
            5-1. Chat with LLMs with HuggingFace's model and adapter:
                xtuner chat $LLM --adapter $ADAPTER --prompt-template $PROMPT_TEMPLATE --system-template $SYSTEM_TEMPLATE
            5-2. Chat with VLMs with HuggingFace's model and LLaVA:
                xtuner chat $LLM --llava $LLAVA --visual-encoder $VISUAL_ENCODER --image $IMAGE --prompt-template $PROMPT_TEMPLATE --system-template $SYSTEM_TEMPLATE
            6-1. Preprocess arxiv dataset:
                xtuner preprocess arxiv $SRC_FILE $DST_FILE --start-date $START_DATE --categories $CATEGORIES
            6-2. Preprocess refcoco dataset:
                xtuner preprocess refcoco --ann-path $RefCOCO_ANN_PATH --image-path $COCO_IMAGE_PATH --save-path $SAVE_PATH
            7-1. Log processed dataset:
                xtuner log-dataset $CONFIG
            7-2. Verify the correctness of the config file for the custom dataset:
                xtuner check-custom-dataset $CONFIG
            8. MMBench evaluation:
                xtuner mmbench $LLM --llava $LLAVA --visual-encoder $VISUAL_ENCODER --prompt-template $PROMPT_TEMPLATE --data-path $MMBENCH_DATA_PATH
            9. Refcoco evaluation:
                xtuner eval_refcoco $LLM --llava $LLAVA --visual-encoder $VISUAL_ENCODER --prompt-template $PROMPT_TEMPLATE --data-path $REFCOCO_DATA_PATH
            10. List all dataset formats which are supported in XTuner
    
        Run special commands:
    
            xtuner help
            xtuner version
    
        GitHub: https://github.com/InternLM/xtuner
    

    给gpt分析的原因是pytorch版本不兼容。

  2. 问题解决过程:

    1. 原来的README中有这行,pip install torch==2.4.1 torchvision==0.19.1 torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu121,但后续删掉了,我把这行命令运行,torch相关依赖被覆盖。

      1. 结果:仍然报错
    2. 重新执行pip install -r requirements.txt,观察日志,其执行过程是把原来的包删掉,然后重新安装。

      1. 结果:成功了
    3. 在成功的环境中,列出torch相关依赖:

      pip list |  grep torch
      

      image-20250217180422993

      requirements.txt中,没有torchaudio这个依赖:

      image-20250217180455821

      但由于第1步中将其安装了。

    4. 猜测报错的原因:原始的requirements.txt中没有的torchaudio这个依赖导致的。

  3. 可能的解决方法:额外执行pip install torchaudio==2.4.1 --index-url https://download.pytorch.org/whl/cu121

2.3.5 模型合并

对于 LoRA 或者 QLoRA 微调出来的模型其实并不是一个完整的模型,而是一个额外的层(Adapter),训练完的这个层最终还是要与原模型进行合并才能被正常的使用。

对于全量微调的模型(full)其实是不需要进行整合这一步的,因为全量微调修改的是原模型的权重而非微调一个新的 Adapter ,因此是不需要进行模型整合的。

在 XTuner 中提供了一键合并的命令 xtuner convert merge,在使用前我们需要准备好三个路径,包括原模型的路径、训练好的 Adapter 层的(模型格式转换后的)路径以及最终保存的路径。

xtuner convert merge命令用于合并模型。该命令需要三个参数:LLM 表示原模型路径,ADAPTER 表示 Adapter 层的路径, SAVE_PATH 表示合并后的模型最终的保存路径。

在模型合并这一步还有其他很多的可选参数,包括:

参数名 解释
--max-shard-size 代表每个权重文件最大的大小(默认为2GB)
--device 这里指的就是device的名称,可选择的有cuda、cpu和auto,默认为cuda即使用gpu进行运算
--is-clip 这个参数主要用于确定模型是不是CLIP模型,假如是的话就要加上,不是就不需要添加
cd /root/finetune/work_dirs/assistTuner
conda activate xtuner-env-l1

export MKL_SERVICE_FORCE_INTEL=1
export MKL_THREADING_LAYER=GNU
xtuner convert merge /root/finetune/models/internlm2_5-7b-chat ./hf ./merged --max-shard-size 2GB

模型合并完成后,我们的目录结构应该是这样子的。

image-20250217181747265

在模型合并完成后,我们就可以看到最终的模型和原模型文件夹非常相似,包括了分词器、权重文件、配置信息等等。

2.4 模型 WebUI 对话

微调完成后,我们可以运行/root/Tutorial/tools/L1_XTuner_code/xtuner_streamlit_demo.py 脚本来观察微调后的对话效果,不过在运行之前,我们需要将脚本中的模型路径修改为微调后的模型的路径。

image-20250217202529533

先安装依赖:

pip install streamlit==1.31.0

启动服务:

streamlit run /root/Tutorial/tools/L1_XTuner_code/xtuner_streamlit_demo.py

用vscode终端做端口转发:

image-20250217203423016

image-20250217203403977

成功:

image-20250217204213337

posted @ 2025-02-17 20:48  sakuraLGGM  阅读(105)  评论(0)    收藏  举报