Ascend-SACT/Qwen2.5_VL_7B
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

Qwen2.5_VL_7B训练指导

一、 业务背景

  • 项目背景

  • Qwen2.5-VL-7B作为阿里巴巴通义千问团队研发的多模态语言模型,具备70亿参数规模,支持视觉与语言信息的联合理解与生成。该模型在通用多模态基准测试中表现出色,能够处理图像描述、视觉问答、文档解析等多种跨模态任务。随着各行业对智能化视觉理解需求的日益增长,如何将通用模型适配到特定领域场景,成为发挥其实际价值的关键路径。

  • 技术背景

  • 模型架构特点:Qwen2.5-VL-7B采用先进的视觉编码器-语言模型融合架构,通过高效的跨模态注意力机制实现视觉特征与文本语义的深度对齐。其7B参数规模在保持较强推理能力的同时,显著降低了部署门槛和计算成本。

    应用场景适配需求:虽然预训练模型具备广泛的常识理解能力,但在专业领域(如医疗影像分析、工业质检、金融票据处理等)仍存在领域知识不足、任务形式不匹配、专业术语理解偏差等问题。微调训练成为连接通用能力与专业需求的核心技术手段。

    垂直行业驱动:随着数字化转型深入,企业在文档智能化处理、视觉内容审核、多模态数据分析等方面产生大量定制化需求。通过领域数据微调,可使模型掌握特定业务逻辑、术语体系和输出格式要求,显著提升任务完成精度和实用性。

  • 微调价值

  • 本次微调训练项目旨在:

  • 领域知识注入:将行业特有的视觉特征分布、文本表达习惯和业务规则融入模型参数

    任务形式优化:适配特定场景下的输入输出格式、交互流程和性能指标要求

    精度效率平衡:在保持模型推理效率的前提下,提升目标任务的准确率和鲁棒性

本案例使用昇腾A3机器上,基于MindspeedMM 框架完成Qwen2.5_VL_7B模型基于大分辨率数据集微调实践。

二、环境准备

2.1. 硬件环境

硬件名称配置信息备注
机器型号A3 超节点
测试集群8卡Pod单机

2.2. 软件环境

软件版本部署方式
DriverAscendHDK 25.2.0宿主机
FirmwareAscendHDK 25.2.0宿主机
Python3.10.18容器
CANN8.2.RC1容器
Torch2.6.0容器
Torch_npu2.6.0容器
MindSpeed2.1.0_core_r0.8.0容器
MindSpeed-LLM2.1.0容器
Megatron-LMcore_r0.8.0容器
Docker镜像OSUbuntu 20.04.6/

2.3. 镜像准备

MindspeedLLM 镜像已发布,使用方法请参考:昇腾训练镜像构建指导 中 MindSpeed-MM镜像章节。镜像下载链接:Ascend-SACT/ascend_train_image

启动镜像:

docker run -d --net=host --shm-size=128g --privileged --name=qwen2_5vl \
$(for i in {0..15}; do [ -e "/dev/davinci$i" ] && echo --device=/dev/davinci$i; done) \
--device=/dev/davinci_manager \
--device=/dev/hisi_hdc \
--device=/dev/devmm_svm \
-v /usr/local/Ascend/driver:/usr/local/Ascend/driver \
-v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
-v /usr/local/dcmi:/usr/local/dcmi \
-e LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64:$LD_LIBRARY_PATH \
mindspeed-mm2.1.0-pytorch2.6.0-ascend_cann8.2.rc1-py310-ubuntu20.04-arm64:0905 \
/bin/bash -c "tail -f /dev/null"
/bin/bash -c "tail -f /dev/null"

docker start qwen2_5vl
docker exec -it qwen2_5vl bash

三、 权重准备

本章基于算法平台的实验环境,进一步定制化业务场景中权重切分策略。

本章流程基于算法平台的容器环境进行,容器中外挂路径已提供原始模型权重:/data/public/models/base/Qwen/Qwen2.5-VL-7B-Instruct,需根据实际环境选择外挂路径;原容器已提供TP=2,PP=1的切分策略,现假设要定制化修改为TP=2,PP=2的切分策略;

3.1 模型权重目录

从Huggingface库下载

  • 模型地址: Qwen2.5-VL-7B-Instruct;

将下载的模型权重保存到本地的base/Qwen/Qwen2.5-VL-7B-Instruct目录下。

Qwen/
 └──Qwen2.5-VL-7B-Instruct
    ├──chat_template.json
    ├──config.json
    ├──configuration.json
    ├──generation_config.json
    ├──gitattributes
    ├──merges.txt
    ├──model-00001-of-00005.safetensors
    ├──model-00002-of-00005.safetensors
    ├──model-00003-of-00005.safetensors
    ├──model-00004-of-00005.safetensors
    ├──model-00005-of-00005.safetensors
    ├──model.safetensors.index.json
    ├──old-version/
    ├──preprocessor_config.json
    ├──Qwen2.5-VL-7B-Instruct.zip
    ├──README.md
    ├──tokenizer_config.json
    ├──tokenizer.json
    ├──v1/
    └──vocab.json

3.2 脚本修改

/src/train25.10/qwen2.5-vl-7b/scripts下。

修改配置脚本finetune_qwen2_5_vl_7b.sh和model.json,确保端口无冲突,以及权重切分策略正确,需保证finetune_qwen2_5_vl_7b.sh、model.json的切分策略保持一致。

注:无论是权重切分、训练拉起还是结果验证,都要保证权重切分策略一致。

3.2.1 修改训练脚本

# 修改端口,防止端口HCCL冲突
export HCCL_IF_BASE_PORT=30000
# export HCCL_NPU_SOCKET_PORT_RANGE="6000-68050"
export HCCL_PORT_RANGE="38001-39000"
export ASCEND_RT_VISIBLE_DEVICES=0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15
# 定制修改TP、PP切分策略
TP=2
PP=2
CP=1
MBS=4

3.2.2 修改模型文件

image_encoder中:
	"pipeline_num_layers": [32,0],
text_encoder中:
	"pipeline_num_layers": [8,20],

3.2.3 HF权重转换MM权重

MindSpeed-MM修改了部分原始网络的结构名称,使用mm-convert工具对原始预训练权重进行转换。该工具实现了huggingface权重和MindSpeed-MM权重的互相转换以及PP(Pipeline Parallel)权重的重切分。参考权重转换工具:

注意:运行的finetune脚本的切分策略需要和这里的切分策略保持一致,切分后的权重尽量放到容器以外

cd  /usr/local/Ascend/mm-train/MindSpeed-MM
# 生效环境变量
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh

mm-convert  Qwen2_5_VLConverter hf_to_mm \
  --cfg.mm_dir "/src/train25.10/qwen2.5-vl-7b/ckpt/mm_path/tp2_pp2" \
  --cfg.hf_config.hf_dir "base/Qwen/Qwen2.5-VL-7B-Instruct/weights/Qwen2.5-VL-7B-Instruct" \
  --cfg.parallel_config.llm_pp_layers [[8,20]] \
  --cfg.parallel_config.vit_pp_layers [[32,0]] \
  --cfg.parallel_config.tp_size 2
# 其中:
# mm_dir: 转换后保存目录
# hf_dir: huggingface权重目录
# llm_pp_layers: llm在每个卡上切分的层数,注意要和model.json中配置的pipeline_num_layers一致
# vit_pp_layers: vit在每个卡上切分的层数,注意要和model.json中配置的pipeline_num_layers一致
# tp_size: tp并行数量,注意要和微调启动脚本中的配置一致
3.2.4 MM权重转换HF权重

(验证时执行)lora权重训练后,若要使用HF权重进行推理部署,可采用如下脚本进行权重转换:

source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh
cd /usr/local/Ascend/mm-train/MindSpeed-MM/
mm-convert Qwen2_5_VLConverter mm_to_hf \
--cfg.save_hf_dir "/src/train/qwen2.5-vl-7b/mm_to_hf_save/qwen2.5hf" \
--cfg.mm_dir "/src/train25.10/qwen2.5-vl-7b/merge_save_dir/" \
--cfg.hf_config.hf_dir "/src/train25.10/hw/weights/Qwen2.5-VL-7B-Instruct/" \
--cfg.parallel_config.llm_pp_layers [8,20] \
--cfg.parallel_config.vit_pp_layers [32,0] \
--cfg.parallel_config.tp_size 2 \

# 其中:
# save_hf_dir: mm微调后转换回hf模型格式的目录
# mm_dir: 微调后保存的权重目录
# hf_dir: huggingface权重目录
# llm_pp_layers: llm在每个卡上切分的层数,注意要和微调时model.json中配置的pipeline_num_layers一致
# vit_pp_layers: vit在每个卡上切分的层数,注意要和微调时model.json中配置的pipeline_num_layers一致
# tp_size: tp并行数量,注意要和微调启动脚本中的配置一致

**使用MindSpeed-MM进行模型训练,需使用MM权重。**执行HF权重转换MM权重后,转换的权重会在--cfg.mm_dir 参数指定的/src/train25.10/qwen2.5-vl-7b/ckpt/mm_path/tp2_pp2路径下生成,在执行训练任务前需同步修改examples/qwen2.5vl/finetune_qwen2_5_vl_7b.sh中的LOAD_PATH参数,该路径为转换后或者切分后的权重,注意与原始权重 /data/public/base/Qwen/Qwen2.5-VL-7B-Instruct进行区分。

修改内容如下:

LOAD_PATH="/src/train25.10/qwen2.5-vl-7b/ckpt/mm_path/tp2_pp2"

image-20250903164558713

3.2.5 指定lora训练

在finetune_qwen2_5_vl_7b.sh脚本中指定lora目标时,即选择lora进行微调;去掉则默认使用SFT进行全参微调;

image-20250908153541674

四、 Qwen2.5-VL-7B数据预处理

4.1 业务训练集样例

当前业务训练集地址:/src/train25.10/hw/dataset/0622_dataset/0516_gpt.json

若需更换业务训练集地址,可修改/src/train25.10/qwen2.5-vl-7b/scripts/data_7b.json

[
    {
        "system": "",
        "instruction": "你是一名物流隐患识别专家,你的任务是根据输入图片识别以下四类对象的隐患:叉车、夹抱车、作业工人、纸皮箱。请根据以下图片回答问题:",
        "input": "<image>图中有几辆特种作业车?",
        "output": "2辆",
        "images": "/apps/wuliu/dataset/叉车夹抱车0516/夹抱车(数据增强9)/违规夹抱_置信度[0.0]_master1_camera-7_20250428213654.jpeg"
    },
    {
        "system": "",
        "instruction": "你是一名物流隐患识别专家,你的任务是根据输入图片识别以下四类对象的隐患:叉车、夹抱车、作业工人、纸皮箱。请根据以下图片回答问题:",
        "input": "<image>黑色车顶,蓝色车身装载有货物的特种作业车的类型是什么?",
        "output": "图中没有特种作业车",
        "images": "/apps/wuliu/dataset/叉车夹抱车0516/无叉车无夹抱车(数据增强7)/未穿反光衣_置信度[0.0]_master1_camera15_20250411171434.jpeg"
    },
    {
        "system": "",
        "instruction": "你是一名物流隐患识别专家,你的任务是根据输入图片识别以下四类对象的隐患:叉车、夹抱车、作业工人、纸皮箱。请根据以下图片回答问题:",
        "input": "<image>图像右下角区域的特种作业车的类型是什么?",
        "output": "图中没有特种作业车",
        "images": "/apps/wuliu/dataset/叉车夹抱车0516/无叉车无夹抱车(数据增强5)/破损_置信度[0.95]_master1_camera3_20250328174129.jpeg"
    },

4.2 业务训练集格式转换

MindSpeed-MM当前支持ShareGPT格式的数据集,4.1节中样例训练集为alpaca格式,因此需要先转换格式。转换过程中,需注意确保数据集中图片路径的格式要和开源数据集格式一致;且转换中,要根据提供的业务数据集样例中的关键字段针对性形成相应的转换脚本。

以4.1节中的样例为例,对应的转换脚本(脚本所在目录:/src/train25.10/qwen2.5-vl-7b/scripts/alpaca2shareGPT.py)内容如下:

import json
import os
from typing import Dict

PATH_PREFIX="./0622_dataset/"


def convert_path(ori_path: str) -> str:
    # 分割路径
    parts = ori_path.strip("/").split('/')
    return os.path.join(PATH_PREFIX, *parts[-3:])


def convert_alpaca_to_mindspeed_mm(alpaca_item: Dict) -> Dict:
    """单条数据转换函数(修正版)"""
    # 提取原始字段
    system_prompt = alpaca_item.get("system", "")
    instruction = alpaca_item.get("instruction", "")
    input_text = alpaca_item.get("input", "")
    output = alpaca_item.get("output", "")
    images = alpaca_item.get("images", "")

    # 构建messages列表(仅包含user和assistant)
    messages = []

    # 合并用户指令和输入
    user_content = instruction
    if input_text:
        user_content += f"\n\n{input_text}"
    messages.append({"role": "user", "content": user_content})

    # 添加助手回复
    messages.append({"role": "assistant", "content": output})

   # 图片路径处理
    images = convert_path(images)
    # 构建最终输出结构(system字段独立)
    return {
        "images":[images],
        "messages": messages,
        "system": system_prompt  # 作为顶级字段
    }


def batch_convert(input_path: str, output_path: str):
    """批量转换主函数"""
    # 读取原始数据
    with open(input_path, "r", encoding="utf-8") as f:
        alpaca_data = json.load(f)

    print("Total item num in dataset:")
    print(len(alpaca_data))
    # 转换数据
    converted_data = []
    for item in alpaca_data:
        converted_item = convert_alpaca_to_mindspeed_mm(item)
        converted_data.append(converted_item)

    # 保存结果
    os.makedirs(os.path.dirname(output_path), exist_ok=True)
    with open(output_path, "w", encoding="utf-8") as f:
        json.dump(converted_data, f, indent=4, ensure_ascii=False)

    print(f"转换完成!输出文件:{output_path}")


if __name__ == "__main__":
    # # 输入输出路径配置
    input_json = "./0622_dataset/0626_handle.json"
    output_json = "./0622_dataset/0626_gpt.json"

    # # 执行转换
    batch_convert(input_json, output_json)

进入/src/train25.10/hw/wuliu/dataset目录后,执行权重转换脚本

python /src/train25.10/qwen2.5-vl-7b/scripts/alpaca2shareGPT.py

完成格式转换后,替换训练脚本中的数据集路径 /usr/local/Ascend/mm-train/MindSpeed-MM/examples/qwen2.5vl/data_7b.json,配置如下:

{
    "dataset_param": {
        "dataset_type": "huggingface",
        "preprocess_parameters": {
            "model_name_or_path": "/src/train25.10/hw/weights/Qwen2.5-VL-7B-Instruct",
             ...
        },
        "basic_parameters": {
            "template": "qwen2vl",
            "dataset_dir": "/src/train25.10/hw/wuliu/dataset",
            "dataset": "/src/train25.10/hw/wuliu/dataset/0622_dataset/0516_gpt.json",
            "cache_dir": "/src/train25.10/qwen2.5-vl-7b/data_cache_dir", 
            ...
        },
        ...
    },
    ...
}

参数说明

参数名称说明
dataset_type当前值 "huggingface": 表示将使用 Hugging Face 的 datasets库来加载和处理数据集。mindspeed-mm 会调用 Hugging Face 的相关 API 来读取数据
model_name_or_path指向本地存储的 Qwen2.5-VL-7B-Instruct 模型的目录。这个路径下的模型包含了分词器(Tokenizer) 和模型配置(Config) 信息
dataset_dir数据集文件所在的根目录,与数据集描述文件中图片路径拼接成为实际图片访问路径
dataset最关键参数之一。 指定包含实际训练/验证数据的文件路径。这个文件定义了样本的结构和内容(如图像路径、问题、答案等)。
cache_dir指定用于存储预处理后数据缓存的目录 表示缓存将存储在 /src/train25.10/qwen2.5-vl-7b/data_cache_dir目录下。

转换后的ShareGPT格式的数据集如下:

[
    {
        "images": [
            "0622_dataset/叉车夹抱车0516/夹抱车(数据增强9)/违规夹抱_置信度[0.0]_master1_camera-7_20250428213654.jpeg"
        ],
        "messages": [
            {
                "role": "user",
                "content": "你是一名物流隐患识别专家,你的任务是根据输入图片识别以下四类对象的隐患:叉车、夹抱车、作业工人、纸皮箱。请根据以下图片回答问题:\n\n<image>图中有几辆特种作业车?"
            },
            {
                "role": "assistant",
                "content": "2辆"
            }
        ],
        "system": ""
    },
    {
        "images": [
            "0622_dataset/叉车夹抱车0516/无叉车无夹抱车(数据增强7)/未穿反光衣_置信度[0.0]_master1_camera15_20250411171434.jpeg"
        ],
        "messages": [
            {
                "role": "user",
                "content": "你是一名物流隐患识别专家,你的任务是根据输入图片识别以下四类对象的隐患:叉车、夹抱车、作业工人、纸皮箱。请根据以下图片回答问题:\n\n<image>黑色车顶,蓝色车身装载有货物的特种作业车的类型是什么?"
            },
            {
                "role": "assistant",
                "content": "图中没有特种作业车"
            }
        ],
        "system": ""
    },
    {
        "images": [
            "0622_dataset/叉车夹抱车0516/无叉车无夹抱车(数据增强5)/破损_置信度[0.95]_master1_camera3_20250328174129.jpeg"
        ],
        "messages": [
            {
                "role": "user",
                "content": "你是一名物流隐患识别专家,你的任务是根据输入图片识别以下四类对象的隐患:叉车、夹抱车、作业工人、纸皮箱。请根据以下图片回答问题:\n\n<image>图像右下角区域的特种作业车的类型是什么?"
            },
            {
                "role": "assistant",
                "content": "图中没有特种作业车"
            }
        ],
        "system": ""
    },

该业务数据集中存在关键字段:"system"、"images"、"messages"、"role"、"user"、"assistant"、"content",需要修改data_7b.json中的关键字如下:

image-20250903164530368

注:经过以上步骤,即可使用样例业务数据集进行模型训练;针对其他格式的数据集,需针对性实现数据集格式转换脚本,并修改相应的数据集文件配置。

4.3 大数据集单独缓存

在训练集较大时,当前版本的代码框架(MindSpeed-MM 2.1.0)进行数据预处理缓存可能会导致多进程超时。当前设置HCCL等待时间最多为2h,对应finetune_qwen2_5_vl_7b.json脚本中的HCCL设置,支持120-7200s范围的超时选项。如果多卡拉起任务,且数据集预处理超过2h,则会出现进程空等待,HCCL报错。

image-20250920103322241

因此,当前版本在大训练集进行训练时,需要先设置为单卡进行数据缓存,然后再基于已有的缓存进行训练。

临时修改finetune_qwen2_5_vl_7b.sh脚本,设置为单卡,不加载权重,切分策略指定为不切分:

image-20250920104419335

临时修改model.json,将text和vit的层数指定为1,保证模型可以被单卡加载:

image-20250920104607422 image-20250920104650390

在data_7b.json中指定数据缓存路径,下一次拉起训练时默认直接拉起。

image-20250920104855237

完成以上修改后,可以通过托管平台拉起数据预处理,预处理完成后,将设置恢复(数据cache保持不变),即可正常拉起模型训练。

注:修改分辨率、seq-length数据相关参数会导致重新缓存,可先更换缓存目录,避免原有缓存被覆盖。

4.4 数据集训练步数计算

当前MindSpeed-MM框架仅支持指定训练迭代步数,可以根据Epoch数计算得到对应的训练步数,关键参数设置在训练拉起脚本:

DP = 总调度单元数 / TP / PP / CP

Global batch size = MBS * GRAD_ACC_STEP * DP

Iteration = Epochs * 数据集条数 / Global batch size

五、运行训练任务

5.1 启动脚本

为便于快速体验训练过程,Qwen2.5-VL-7B模型的权重切分脚本、数据集转换脚本、训练脚本,已提前打包放置镜像内。

权重切分脚本/src/train25.1.0/qwen2.5-vl-7b/scripts/mm_convert_hf_to_mm.sh
训练脚本/src/train25.1.0/qwen2.5-vl-7b/scripts/finetune_qwen2_5_vl_7b.sh

5.2 托管环境验证

5.2.1 脚本目录

/src/train25.1.0/qwen2.5-vl-7b

qwen2.5-vl-7b
	├──ckpt
		└──mm_path
			└──Qwen2.5-VL-7B-Instruct            		 #切分后权重
	├──data_cache_dir                            #数据集处理后缓存目录
	├──merge_save_dir                            #合并权重保存目录
	├──logs                                      #训练日志存放目录
	├──save_dir                                  #权重训练后存放目录
	└──scripts                                   #脚本存放目录
		├──data_7b.json                            #数据目录配置文件
		├──finetune_qwen2_5_vl_7b.sh               #训练脚本
		├──mm_convert_hf_to_mm.sh                  #权重切分脚本
		├──image_first.py                          #推理测评脚本
		└──merge_lora.py                           #合并脚本

运行命令输入如下启动命令(容器内已完成数据集转换,输入启动训练命令即可)

# 启动权重切分命令
cd /usr/local/Ascend/mm-train/MindSpeed-MM/ && bash /src/train25.1.0/qwen2.5-vl-7b/scripts/mm_convert_hf_to_mm.sh

# 单机启动训练命令
# 若使用公共镜像,切换工作目录至/src/train25.1.0
source /root/miniconda3/etc/profile.d/conda.sh && 
conda activate python310 && 
cd /usr/local/Ascend/mm-train/MindSpeed-MM/ && 
bash /src/train25.1.0/qwen2.5-vl-7b/scripts/finetune_qwen2_5_vl_7b.sh

# 多机启动训练命令
source /root/miniconda3/etc/profile.d/conda.sh && 
conda activate python310 && 
cd /usr/local/Ascend/mm-train/MindSpeed-MM/ && 
bash /src/train25.1.0/qwen2.5-vl-7b/scripts/multi_finetune_qwen2_5_vl_7b.sh

多机下发场景中,需要更改/src/train25.1.0/qwen2.5-vl-7b/scripts/finetune_qwen2_5_vl_7b.sh脚本中的部分配置,将红色框单机配置注释,替换成绿色框,指定为多机运行脚本:

# 基础配置

NPUS_PER_NODE=16  #使用单节点的8卡NPU
MASTER_ADDR=$(cat /etc/volcano/worker.host | head -n 1 | awk '{print $1}') #以本节点ip地址为master_ip
echo master_addr=${MASTER_ADDR}
MASTER_PORT=6016 #本节点端口号为6015
NNODES=${VC_WORKER_NUM}  #单机,即一台节点,多机即多节点
NODE_RANK=${VC_TASK_INDEX}  #单机RANK为0,多机为(0,NNODES-1),不同节点不可重复
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES)) #最终使用的NPU数
echo world_size:${WORLD_SIZE}

image-20250829114223855

5.2.3 运行结果

5.2.3.1 权重切分运行结果

权重转化目录:/src/train25.1.0/qwen2.5-vl-7b/ckpt/mm_path/Qwen2.5-VL-7B-Instruct

# 该样例为TP=2,PP=2
Qwen2.5-VL-7B-Instruct
     ├──latest_checkpointed_iteration.txt
     └──release
     		├──mp_rank_00_000
     		├──mp_rank_00_001
     		├──mp_rank_01_000
				└──mp_rank_01_001
5.2.3.2 训练启动

训练任务下发后,日志回显

image-20250824194224205

输出结果

qwen2.5-vl-7b
	├──logs
		└──train_20250824_193239.log                              #训练输出日志
	├──data_cache_dir
		├──_data_share_qwen2.5-vl-7b_data_cache_dir...b1092.lock  #数据集处理后缓存文件
		├──json                                                   #数据集处理后缓存文件
	└──save_dir
		├──iter_0002464                                           #训练后模型权重文件
		├──iter_0004928                                           #训练后模型权重文件
		├──iter_0007392                                           #训练后模型权重文件
		└──latest_checkpointed_iteration.txt                      #模型检查点记录文件

5.2.4 loss曲线

image-20250825094502993

image-20250825094613351

六、业务数据评测

使用业务数据集验证需将mm权重与lora权重合并,并转回HuggingFace格式权重验证

6.1 Lora权重合并

在实验环境中,修改保存lora权重的latest_checkpointed_iteration.txt 下的版本后,Lora权重合并

vi /src/train25.10/qwen2.5-vl-7b/save_dir/latest_checkpointed_iteration.txt

将其中的数字改为训练后模型权重文件的后四位数字,此处填写的为“iter_0007392”的后四位,托管环境已做修改

image-20250825103139303

修改merger_lora.py文件

vi /src/train25.10/qwen2.5-vl-7b/scripts/merge_lora.py 

需修改base_save_dir、lora_save_dir、merge_save_dir、lora_alpha、lora_r 、pp_size、tp_size等参数,托管环境已做修改如下所示:

...
if __name__ == '__main__':
    base_save_dir = "/src/train25.10/qwen2.5-vl-7b/ckpt/mm_path/Qwen2.5-VL-7B-Instruct"
    lora_save_dir = "/src/train25.10/qwen2.5-vl-7b/save_dir/"
    merge_save_dir = "/src/train25.10/qwen2.5-vl-7b/merge_save_dir/"
    lora_target_modules = ['linear_qkv', 'linear_proj', 'linear_fc1', 'linear_fc2']

    lora_alpha = 12
    lora_r = 6          # 保持和训练一致
    scaling = lora_alpha / lora_r

    pp_size = 1
    tp_size = 2
...    
export LD_LIBRARY_PATH=/usr/local/Ascend/ascend-toolkit/latest/lib64:$LD_LIBRARY_PATH && 
export PATH=/usr/local/Ascend/ascend-toolkit/latest/bin:$PATH && 
source /usr/local/Ascend/ascend-toolkit/set_env.sh && 
python /src/train25.10/qwen2.5-vl-7b/scripts/merge_lora.py 

6.2 合并权重转为HuggingFace格式

合并后权重转回HuggingFace格式,需指定HF权重保存路径(cfg.save_hf_dir),已合并权重路径(cfg.save_mm_dir)以及原始HF权重路径(cfg.hf_config.hf_dir),这里的评测切分策略需与model.json中切分策略保持一致:

cd  /usr/local/Ascend/mm-train/MindSpeed-MM
# 生效环境变量
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh

mm-convert Qwen2_5_VLConverter mm_to_hf \
    --cfg.save_hf_dir "/src/train25.10/qwen2.5-vl-7b/mm_to_hf_save/" \
    --cfg.mm_dir "/src/train25.10/qwen2.5-vl-7b/merge_save_dir" \
    --cfg.hf_config.hf_dir "/src/train25.10/hw/weights/Qwen2.5-VL-7B-Instruct" \
    --cfg.parallel_config.llm_pp_layers [28] \
    --cfg.parallel_config.vit_pp_layers [32] \
    --cfg.parallel_config.tp_size 2
    
# 其中:
# save_hf_dir: mm微调后转换回hf模型格式的目录
# mm_dir: 微调后保存的权重目录
# hf_dir: huggingface权重目录
# llm_pp_layers: llm在每个卡上切分的层数,注意要和微调时model.json中配置的pipeline_num_layers一致
# vit_pp_layers: vit在每个卡上切分的层数,注意要和微调时model.json中配置的pipeline_num_layers一致
# tp_size: tp并行数量,注意要和微调启动脚本中的配置一致

6.3 启动评测

使用业务验证集推理:

cd /hw_test/hw/wuliu/dataset/

# 修改验证脚本加载权重路径,指定验证集:vi image_first.py

python image_first.py    # image_first.py是自定义的推理脚本,需要权重转回Huggingface格式

6.4 一键评测脚本样例

为了简化评测流程,可以编写一键评测脚本,自动实现6.1-5.3节的评测内容。样例代码已提供在/src/train25.10/qwen2.5-vl-7b/scripts/eval.sh,以验证500步训练的lora权重的为例,可执行

bash eval.sh --step 500

完整一键评测脚本:

#!/bin/bash

# ==============================================

# LoRA Weight Version Automation Script

# Usage: ./eval.sh <version_number> 

# Example: ./eval.sh 1500

# ==============================================

# Validate input argument

if [ $# -eq 0 ]; then
    echo "ERROR: Version number argument missing"
    echo "Usage: $0 <version_number> (e.g. 1500)"
    exit 1
fi
DEFAULT_VERSION="2000"
VERSION="${1:-$DEFAULT_VERSION}"
CHECKPOINT_FILE="/src/train25.10/qwen2.5-vl-7b/save_dir/2node/latest_checkpointed_iteration.txt"

echo "=== STARTING PIPELINE FOR VERSION: $VERSION ==="

source /usr/local/Ascend/ascend-toolkit/set_env.sh

# -------------------------------------------------------------------

# STEP 1: Overwrite version number in checkpoint file

# -------------------------------------------------------------------

echo "[1/4] Writing version $VERSION to $CHECKPOINT_FILE..."
echo "$VERSION" > "$CHECKPOINT_FILE" || {
    echo "ERROR: Failed to write to $CHECKPOINT_FILE"
    exit 1
}

# -------------------------------------------------------------------

# STEP 2: Run LoRA weight merging script

# -------------------------------------------------------------------

echo "[2/4] Executing merge_lora.py..."
cd  /usr/local/Ascend/mm-train/MindSpeed-MM
python examples/qwen2vl/merge_lora.py || {
    echo "ERROR: merge_lora.py execution failed"
    exit 1
}

# -------------------------------------------------------------------

# STEP 3: Convert model format using mm-convert

# -------------------------------------------------------------------

echo "[3/4] Running mm-convert for version $VERSION..."
mm-convert Qwen2_5_VLConverter mm_to_hf \
    --cfg.save_hf_dir "/src/train25.10/qwen2.5-vl-7b/mm_to_hf_save/$VERSION" \
    --cfg.mm_dir "/src/train25.10/qwen2.5-vl-7b/merge_save_dir" \
    --cfg.hf_config.hf_dir "/src/train25.10/hw/weights/Qwen2.5-VL-7B-Instruct" \
    --cfg.parallel_config.llm_pp_layers [28] \
    --cfg.parallel_config.vit_pp_layers [32] \
    --cfg.parallel_config.tp_size 2 || {
    echo "ERROR: mm-convert operation failed"
    exit 1
}

# -------------------------------------------------------------------

# STEP 4: Process dataset with version-specific parameter

# -------------------------------------------------------------------

echo "[4/4] Running image_first.py with step=$VERSION..."
cd /src/train25.10/qwen2.5-vl-7b/scripts || {
    echo "ERROR: Failed to access dataset directory"
    exit 1
}
python image_first.py --step "$VERSION" || {
    echo "ERROR: image_first.py execution failed"
    exit 1
}

# -------------------------------------------------------------------

# SUCCESS OUTPUT

# -------------------------------------------------------------------

echo "=== PIPELINE COMPLETED SUCCESSFULLY FOR VERSION $VERSION ==="
exit 0

七、 其他参考

参考链接
昇腾社区https://gitee.com/ascend
Mindspeed LLM 官网(大模型)https://gitee.com/ascend/MindSpeed-LLM
昇腾大模型加速库https://gitee.com/ascend/MindSpeed
MindSpeed-MM 官网(多模态大模型)https://gitee.com/ascend/MindSpeed-MM
MindSpeed RL 官网(强化学习加速框架)https://gitee.com/ascend/MindSpeed-RL
基于MindSpeed LLM训练和微调Qwen2.5(教程)https://www.hiascend.com/developer/blog/details/02115183735165287002
MindSpeed LLM开发实践(原理讲解)https://www.hiascend.com/developer/courses/detail/1910963014913622017
Ascend华为官网https://www.hiascend.com/