Ascend-SACT/Qwen3-32B
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

Qwen3-32B大语言模型基于MindSpeed-LLM框架训练部署指导

本文介绍在HCS ModelArts控制台基于MindSpeed-LLM框架进行Qwen3模型微调(全参/Lora)训练全过程。

目录

[TOC]

前言

本文基于MindSpeed-LLM框架对Qwen3-32B模型适配进行微调,MindSpeed开源社区地址:https://gitee.com/ascend/MindSpeed-LLM,主要分为以下几个部分。

  • ModelArts基于MindSpeed-LLM框架训练镜像制作
  • 训练原始权重准备
  • 训练数据准备
  • 训练参数及脚本准备
  • 在ModelArts创建训练任务并启动训练

注:本教程同样适用于Qwen3其他参数量模型,按需从MindSpeed-LLM中获取example训练脚本修改即可。

一、制作训练镜像

基于MindSpeed进行开源模型微调训练时,需根据MindSpeed要求的配套版本制作镜像并适配ModelArts。参考MindSpeed-LLM配置环境要求:https://gitee.com/ascend/MindSpeed-LLM/blob/2.1.0/docs/pytorch/install_guide.md,具体配置要求如下:

MindSpeed-LLM的主要依赖配套如下表,安装步骤参考安装指导。(以下仅供参考,请参照MindSpeed最新文档的环境要求准备环境)

使用约束

依赖软件版本
昇腾NPU驱动>=25.0.RC1.1商发版本
昇腾NPU固件>=25.0.RC1.1商发版本
CANN Toolkit>=8.1.RC1商发版本
CANN Kernel>=8.1.RC1商发版本
CANN NNAL>=8.1.RC1商发版本
Python>=3.10
PyTorch>=2.1.0
torch_npu插件>=2.1.0
apex商发版本
transformers>=4.51.0(与模型配套,Qwen3要求4.51.0及以上版本)

硬件设备

设备型号NPU配置
Atlas 800I A2 910B16/32卡

镜像制作步骤:

Python

准备配套Python源码包,根据需要下载对应版本,下载地址: https://www.python.org/downloads/。

使用./configure --prefix=/usr/local/python3 & make & make install命令安装Python。

CANN安装

下载CANN配套版本,根据需要下载对应版本,下载地址: https://www.hiascend.com/developer/download/community/result?module=cann&cann=8.2.RC1。

使用下列命令安装CANN toolkit、kernels、nnal:

chmod +x Ascend-cann-*.run 
./$(ls -t Ascend-cann-toolkit*.run|head -n 1) --install --quiet
./$(ls -t Ascend-cann-kernels*.run|head -n 1) --install --quiet
source /usr/local/Ascend/ascend-toolkit/set_env.sh
./$(ls -t Ascend-cann-nnal*.run|head -n 1) --install --quiet
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh

Torch&torch_npu安装

下载配套torch、torch-npu依赖包,根据需要下载对应版本,下载地址:https://www.hiascend.com/document/detail/zh/Pytorch/710/configandinstg/instg/insg_0004.html。

使用下列命令安装Torch&torch_npu:

pip install --upgrade pip 
pip install $(ls -t /tmp/torch*.whl|grep -v "torch_npu"|head -n 1)
pip install $(ls -t /tmp/torch_npu*.whl|head -n 1)

MindSpeed-LLM及相关依赖安装

参照社区依赖安装MindSpeed-LLM,社区安装指导链接:https://gitee.com/ascend/MindSpeed-LLM/blob/2.1.0/docs/pytorch/install_guide.md

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

# 安装MindSpeed加速库
git clone https://gitee.com/ascend/MindSpeed.git
cd MindSpeed
git checkout 2c085cc9  # checkout commit from MindSpeed core_r0.8.0 in 2025.04.01
pip install -r requirements.txt 
pip3 install -e .
cd ..

# 准备MindSpeed-LLM及Megatron-LM源码
git clone https://gitee.com/ascend/MindSpeed-LLM.git 
# megatron从github下载,请确保网络能访问
git clone https://github.com/NVIDIA/Megatron-LM.git  
cd Megatron-LM
git checkout core_r0.8.0
cp -r megatron ../MindSpeed-LLM/
cd ../MindSpeed-LLM
git checkout 2.1.0

pip install -r requirements.txt  # 安装其余依赖库

适配ModelArts

在ModelArts上运行的镜像需要进行ModelArts适配(参考https://support.huaweicloud.com/usermanual-standard-modelarts/docker-modelarts_0029.html) 添加用户组ma-group(gid:100)、用户ma-user(uid:1000),并设置/usr/local目录权限。

# add ma user group if not exists
groupadd ma-group -g 100

# add and chown ma user if not exists
useradd -m -d /home/ma-user -s /bin/bash -g 100 -u 1000 ma-user

# add permission
chown -R ma-user:100 /usr/local/*

一键制作镜像脚本

为简化上述镜像制作流程,本文提供基于OpenEuler基础镜像从零制作MindSpeed-LLM镜像

基于OpenEuler基础镜像从零制作MindSpeed-LLM镜像

镜像制作脚本

基于OpenEuler基础镜像,从零开始制作,根据上述环境配置要求制作MA训练镜像:(以下脚本在基于Arm64架构的Mac上制作镜像验证通过)。常用依赖直接使用ma-user安装,不需要重新适配MA,可以有效控制镜像体积。安装CANN部署参考CANN社区制作。

镜像制作步骤脚本及使用方法同上一节,不适配MA即可。

Docker一键构建脚本仅供参考,可按需修改配套版本,以使用不同模型。

ARG BASE_IMAGE=openeuler-22.03-lts-sp3:latest
FROM ${BASE_IMAGE}

# Install basic software
RUN yum update -y && \
    yum install -y \
        gcc \
        gcc-c++ \
        make \
        cmake \
        curl \
        zlib-devel \
        bzip2-devel \
        openssl-devel \
        ncurses-devel \
        sqlite-devel \
        readline-devel \
        tk-devel \
        gdbm-devel \
        libpcap-devel \
        xz-devel \
        libev-devel \
        expat-devel \
        libffi-devel \
        systemtap-sdt-devel \
        unzip \
        pciutils \
        net-tools \
        lapack-devel \
        gcc-gfortran \
        util-linux \
        findutils \
        wget \
        ca-certificates \
        bash \
        glibc \
        git \
        patch \
    && yum clean all \
    && rm -rf /var/cache/yum \
    && rm -rf /tmp/*

# Install Python
ENV PATH=/usr/local/python3/bin:${PATH}
ADD ./Python-3* /tmp
RUN cd /tmp/Python-3* && \
    mkdir -p /usr/local/python3/lib && \
    ./configure --enable-shared --enable-shared LDFLAGS="-Wl,-rpath /usr/local/python3/lib" --prefix=/usr/local/python3 && \
    make -j $(nproc) && \
    make altinstall && \
    ln -sf $(ls -t /usr/local/python3/bin/python3.*[0-9]|head -n 1) /usr/local/python3/bin/python3 && \
    ln -sf $(ls -t /usr/local/python3/bin/pip3.*[0-9]|head -n 1) /usr/local/python3/bin/pip3 && \
    ln -sf /usr/local/python3/bin/python3 /usr/local/python3/bin/python && \
    ln -sf /usr/local/python3/bin/pip3 /usr/local/python3/bin/pip && \
    rm -rf /tmp/* 

# Stage 2: Install CANN
# Note: Install CANN runtime dependencies
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && pip config set global.timeout 6000
RUN pip install --no-cache-dir --upgrade pip && \
    pip install --no-cache-dir \
        attrs \
        cython \
        numpy \
        decorator \
        sympy \
        cffi \
        pyyaml \
        pathlib2 \
        psutil \
        protobuf \
        scipy \
        requests \
        absl-py

COPY ./Ascend-cann*.run /tmp/
RUN cd /tmp && if (ls Ascend-cann*.run 1>/dev/null 2>&1); then \
        ls && chmod +x Ascend-cann-*.run \
                && ./$(ls -t Ascend-cann-toolkit*.run|head -n 1) --quiet --install --install-for-all \
                && ./$(ls -t Ascend-cann-kernels*.run|head -n 1)  --quiet --install --install-for-all \
                && source /usr/local/Ascend/ascend-toolkit/set_env.sh \
                && ./$(ls -t Ascend-cann-nnal*.run|head -n 1) --quiet --install --install-for-all \
                && source /usr/local/Ascend/ascend-toolkit/set_env.sh \
                && source /usr/local/Ascend/nnal/atb/set_env.sh; \
    else \
        echo "CANN install package does not exist, skip."; \
    fi \
    && rm -f /tmp/Ascend-cann*.run

# Note: Toolkit Environment variables, obtained from /usr/local/Ascend/ascend-toolkit/set_env.sh
ENV ASCEND_TOOLKIT_HOME=/usr/local/Ascend/ascend-toolkit/latest
ENV LD_LIBRARY_PATH=/usr/local/Ascend/driver/lib64/common/:/usr/local/Ascend/driver/lib64/driver/:$LD_LIBRARY_PATH
ENV LD_LIBRARY_PATH=${ASCEND_TOOLKIT_HOME}/lib64:${ASCEND_TOOLKIT_HOME}/lib64/plugin/opskernel:${ASCEND_TOOLKIT_HOME}/lib64/plugin/nnengine:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe/op_tiling:$LD_LIBRARY_PATH
ENV LD_LIBRARY_PATH=${ASCEND_TOOLKIT_HOME}/tools/aml/lib64:${ASCEND_TOOLKIT_HOME}/tools/aml/lib64/plugin:$LD_LIBRARY_PATH
ENV PYTHONPATH=${ASCEND_TOOLKIT_HOME}/python/site-packages:${ASCEND_TOOLKIT_HOME}/opp/built-in/op_impl/ai_core/tbe:$PYTHONPATH
ENV PATH=${ASCEND_TOOLKIT_HOME}/bin:${ASCEND_TOOLKIT_HOME}/compiler/ccec_compiler/bin:${ASCEND_TOOLKIT_HOME}/tools/ccec_compiler/bin:$PATH
ENV ASCEND_AICPU_PATH=${ASCEND_TOOLKIT_HOME}
ENV ASCEND_OPP_PATH=${ASCEND_TOOLKIT_HOME}/opp
ENV TOOLCHAIN_HOME=${ASCEND_TOOLKIT_HOME}/toolkit
ENV ASCEND_HOME_PATH=${ASCEND_TOOLKIT_HOME}

# Note: NNAL Environment variables, obtained from /usr/local/Ascend/nnal/set_env.sh
ENV ATB_HOME_PATH=/usr/local/Ascend/nnal/atb/latest/atb/cxx_abi_0
ENV LD_LIBRARY_PATH=${ATB_HOME_PATH}/lib:${ATB_HOME_PATH}/examples:${ATB_HOME_PATH}/tests/atbopstest:${LD_LIBRARY_PATH}
ENV PATH=${ATB_HOME_PATH}/bin:$PATH
ENV ATB_STREAM_SYNC_EVERY_KERNEL_ENABLE=0
ENV ATB_STREAM_SYNC_EVERY_RUNNER_ENABLE=0
ENV ATB_STREAM_SYNC_EVERY_OPERATION_ENABLE=0
ENV ATB_OPSRUNNER_SETUP_CACHE_ENABLE=1
ENV ATB_OPSRUNNER_KERNEL_CACHE_LOCAL_COUNT=1
ENV ATB_OPSRUNNER_KERNEL_CACHE_GLOABL_COUNT=5
ENV ATB_WORKSPACE_MEM_ALLOC_ALG_TYPE=1
ENV ATB_WORKSPACE_MEM_ALLOC_GLOBAL=0
ENV ATB_COMPARE_TILING_EVERY_KERNEL=0
ENV ATB_HOST_TILING_BUFFER_BLOCK_NUM=128
ENV ATB_DEVICE_TILING_BUFFER_BLOCK_NUM=32
ENV ATB_SHARE_MEMORY_NAME_SUFFIX=""
ENV ATB_MATMUL_SHUFFLE_K_ENABLE=1
ENV ASDOPS_LOG_LEVEL=ERROR
ENV ASDOPS_LOG_TO_STDOUT=0
ENV ASDOPS_LOG_TO_FILE=1
ENV ASDOPS_LOG_TO_FILE_FLUSH=0
ENV ASDOPS_LOG_TO_BOOST_TYPE=atb
ENV ASDOPS_LOG_PATH=/root
ENV LCCL_DETERMINISTIC=0
ENV LCCL_PARALLEL=0
ENV PYTHONUNBUFFERED=1

SHELL [ "/bin/bash", "-c" ]

# Note: Set environment variables
RUN CANN_TOOLKIT_ENV_FILE="/usr/local/Ascend/ascend-toolkit/set_env.sh" && \
    CANN_NNAL_ENV_FILE="/usr/local/Ascend/nnal/atb/set_env.sh" && \
    echo "source ${CANN_TOOLKIT_ENV_FILE}" >> /etc/profile && \
    echo "source ${CANN_TOOLKIT_ENV_FILE}" >> ~/.bashrc && \
    echo "source ${CANN_NNAL_ENV_FILE}" >> /etc/profile && \
    echo "source ${CANN_NNAL_ENV_FILE}" >> ~/.bashrc

# 3. install torth & torth_npu
COPY ./torch*.whl /tmp/
RUN pip install --upgrade pip \
        && pip install $(ls -t /tmp/torch*.whl|grep -v "torch_npu"|head -n 1) \
        && pip install $(ls -t /tmp/torch_npu*.whl|head -n 1)

# 4. 适配MA
RUN useradd -m -d /home/ma-user -s /bin/bash -g 100 -u 1000 ma-user
USER ma-user
WORKDIR /home/ma-user
RUN pip config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && pip config set global.timeout 6000
# RUN git config --global --unset http.proxy && git config --global --unset https.proxy
# 4. install Megatron-LM & MindSpeed & MindSpeed LLM
RUN cd ~ \
        && git clone https://github.com/NVIDIA/Megatron-LM.git \
        && git clone https://gitee.com/ascend/MindSpeed.git \
        && git clone https://gitee.com/ascend/MindSpeed-LLM.git

ARG MEGATRON_LM_TAG=core_r0.8.0
ARG MINDSPEED_TAG=2c085cc9
ARG MINDSPEED_LLM_TAG=2.1.0
RUN cd ~ && cd Megatron-LM && git checkout ${MEGATRON_LM_TAG} && cp -r megatron ../MindSpeed-LLM/ \
        && cd ../MindSpeed && git checkout ${MINDSPEED_TAG} && pip install -r requirements.txt && pip install -e . \
        && cd ../MindSpeed-LLM && git checkout ${MINDSPEED_LLM_TAG} && pip install -r requirements.txt

# 5. install transformer
ARG TRANSFORMERS_VERSION=
RUN if [ -n "$TRANSFORMERS_VERSION" ]; then echo "transformers is ${TRANSFORMERS_VERSION}" && pip install transformers==${TRANSFORMERS_VERSION}; else echo "transformers version is empty, skip"; fi

# 6. install apex
ARG APEX_TAG=master
RUN cd ~ && git clone https://gitee.com/ascend/apex.git \
        && export TORCH_DEVICE_BACKEND_AUTOLOAD=0 \
        && cd apex && git checkout ${APEX_TAG} && bash scripts/build.sh --python=$(python3 -V|awk '{print $2}'|cut -d. -f1,2) && cd apex/dist \
        && pip uninstall apex && pip install --upgrade $(ls -t apex*.whl|head -n 1) \
        && unset TORCH_DEVICE_BACKEND_AUTOLOAD

使用方法:

(1)准备配套Python源码包,根据需要下载对应版本,并放到与build_mindspeeed_image.sh相同的目录下,下载地址: https://www.python.org/downloads/

(2)下载CANN配套版本(仅支持run后缀文件),并放到与build_mindspeeed_image.sh相同的目录下,下载地址: https://www.hiascend.com/developer/download/community/result?module=cann&cann=8.2.RC1。

(3)下载配套torch、torch-npu依赖包,并放到与build_mindspeeed_image.sh相同的目录下,下载地址:https://www.hiascend.com/document/detail/zh/Pytorch/710/configandinstg/instg/insg_0004.html;文件夹结构如下图所示,脚本会自动识别Python、torch及torch-npu安装包。

(4)通过bash执行一键构建脚本,脚本参数为构建镜像的tag:

文件存放目录参考下图:

image.png

bash build_mindspeeed_image.sh mindspeed:2025.rc1-arm_qwen3_for_ma 脚本需要依赖参数,参数说明如下:

Please enter the base image of MindSpeed:

Please enter the tag or branch of Megatron-LM.git: (default: core_r0.8.0): 模型依赖Megatron-LM分支或者tag
Please enter the tag or branch of MindSpeed.git: (default: 2c085cc9): 模型依赖昇腾MindSpeed release分支或者tag
Please enter the tag or branch of MindSpeed-LLM.git: (default: 2.1.0): 模型依赖昇腾MindSpeed-LLM release分支或者tag
Please enter the version of transformers(nullable, skip when empty): 模型依赖transformers版本号,不设置跳过更新transformers
Please enter the tag or branch of apex.git: (default: master): 模型依赖昇腾apex release分支或者tag

(5)根据提示完成构建即可

镜像制作完成后上传至SWR中。脚本归档参见: https://ai.gitcode.com/Ascend-SACT/Qwen3-32B/blob/main/build_mindspeeed_image.sh

镜像准备并上传至SWR

将mindspeed-llm:${version}上传到SWR仓库。

创建一台ecs服务器/或者找到一台可以连通SWR的linux服务器,需要安装docker环境

上传镜像文件mindspeed-llm_${version}.tar到linux服务器,并登录机器执行 docker load -i mindspeed-llm:${version}.tar

镜像打标签,和swr上的仓库地址和组织名保持一致docker tag mindspeed-llm:${version} <镜像仓库地址>/<swr组织名>/mindspeed-llm:${version}

获取swr登录信息

进入HCS环境,选择SWR服务,点击总览页下的 登录“登录指令” 按钮获取SWR临时登录指令:docker login xxxxxxxxx

推送镜像至SWR仓库

获取上一步的镜像tag信息,执行如下命令将镜像推送至SWR仓库: docker push <镜像仓库地址>/<swr组织名>/mindspeed-llm:${version}

二、训练原始权重准备

权重可以从魔乐、魔塔社区及huggingface等途径获取需要的开源镜像。

魔乐社区Qwen3-32B下载地址:https://www.modelscope.cn/models/Qwen/Qwen3-32B/files

使用OBSUtil上传模型权重至OBS:

创建一台ecs服务器/或者找到一台可以连通OBS的Linux服务器 从HCS环境OBS下载OBSUtil安装包并上传到Linux服务 解压OBSUtil并copy到/usr/local/bin

tar -xvf obsutil_xxx.tar.gz
cp -f obsutil_xxx/obsutil /usr/local/bin/

登录OBS并上传文件至OBS

obsutil config -i=<ak> -k=<sk> -e=<endpoint>
obsutil cp -r -f <local_weight_path> <obs_weight_path>

三、训练数据准备

训练数据由行内老师提供,本文仅提供训练方法,以开源数据集alpaca为例,进行训练过程验证。alpaca训练数据集:https://huggingface.co/datasets/tatsu-lab/alpaca/,下载后使用OBSUtil上传至OBS。

obsutil cp -r -f <local_data_path> <obs_data_path>

四、训练参数及脚本准备

训练任务分为数据预处理、huggingface权重转换为mcore、启动训练及mcore权重转换回huggingface四个阶段。本文基于MindSpeed适配example脚本修改,下载对应模型权重训练脚本https://gitee.com/ascend/MindSpeed-LLM/tree/2.1.0/examples/mcore,具体参数可参考MindSpeed-LLM文档。

按照训练要求进行修改,修改过程如下,仅作参考。修改完之后上传至OBS。

obsutil cp -r -f <local_script_path> <obs_script_path>

数据预处理脚本

# set_env
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh

export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH
cd ~/MindSpeed-LLM/

# copy train origin data to dataset
cp $DATA_PATH/* ~/MindSpeed-LLM/dataset/
mkdir ./finetune_dataset
python ./preprocess_data.py \
    --input ./dataset \
    --tokenizer-name-or-path /home/mind/model/Qwen3-32B/ \
    --output-prefix ./finetune_dataset/alpaca \
    --handler-name AlpacaStyleInstructionHandler \
    --tokenizer-type PretrainedFromHF \
    --workers 16 \
    --log-interval 1000 \
    --prompt-type qwen

注:

参数说明

参数说明必填
--input支持输入数据集目录或文件,目录则处理全部文件, 支持.parquet、.csv、.json、.jsonl、.txt、.arrow格式,同一目录要求数据格式保持一致✅
--tokenizer-type说明使用tokenizer类别,参数值为PretrainedFromHF时,词表路径填写模型目录即可✅
--tokenizer-name-or-path配合tokenizer-type,目标模型的tokenizer原数据文件夹,用于数据集的转换
--tokenizer-model配合指定分词器模型的路径,路径具体到tokenizer.model文件
--output-prefix转换后输出的数据集文件的文件名前缀✅
--workers多进程数据集处理✅

Huggingface权重转换mcore

# set_env
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh

export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH
cd ~/MindSpeed-LLM/

mkdir -p $OUTPUT_PATH/qwen3_mcore
 
python convert_ckpt.py \
    --use-mcore-models \
    --model-type GPT \
    --load-model-type hf \
    --save-model-type mg \
    --target-tensor-parallel-size 4 \
    --target-pipeline-parallel-size 4 \
    --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
    --load-dir /home/mind/model/Qwen3-32B/ \
    --save-dir $OUTPUT_PATH/qwen3_mcore/ \
    --tokenizer-model /home/mind/model/Qwen3-32B/tokenizer.json \
    --model-type-hf qwen3 \
    --params-dtype bf16

注:

参数说明必填
--model-type GPT指定模型类型为GPT系列✅
--use-mcore-models转换为Megatron-Mcore格式✅
--target-tensor-parallel-size 1张量并行度设置(建议配置1)✅
--target-pipeline-parallel-size 4流水线并行度设置(建议保持4)✅
--tokenizer-model指定分词器路径✅
--load-model-type加载权重的类别(可以是hf、mg)✅
--save-model-type存储权重的类别(可以是hf、mg)✅
--load-dir权重文件加载路径✅
--save-dir权重文件保存路径✅
--model-type-hfhuggingface模型类别,默认为llama2
--params-dtype指定权重转换后的权重精度模式,默认为fp16,如果源文件格式为bf16,则需要设置为bf16✅

这里TP/PP并行需要跟实际训练使用的卡数对应,这里以A2双机16卡为例。

训练脚本&多机多卡配置

ModelArts在启动容器时注入相关多机环境变量,可以直接使用MA中的环境变量来进行MindSpeed多机配置,避免人为修改脚本容器IP,设置主节点等操作,提升训练便捷程度。

注:多机配置解析解读 ModelArts环境变量:

环境变量说明
VC_WORKER_HOSTS环境变量由ModelArts注入,包含所有worker节点hostname,以英文逗号分隔。这个统一取第一个节点为MASTER节点
MA_NUM_HOSTS环境变量由ModelArts注入,为训练节点数
VC_TASK_INDEX环境变量由ModelArts注入,为Worker节点序号
MA_NUM_GPUS环境变量由ModelArts注入,为每个节点卡数

MindSpeed-LLM多机配置:

# Change for multinode config
NPUS_PER_NODE="$MA_NUM_GPUS"           # 读取ModelArts下发的卡数
MASTER_ADDR="${VC_WORKER_HOSTS%%,*}"   # 设置MASTER节点HOST
MASTER_PORT=6000
NNODES="$MA_NUM_HOSTS"                 # 设置训练节点数
NODE_RANK="$VC_TASK_INDEX"             # 分配的节点索引
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES)) # 计算总卡数
全参微调

创建全参微调训练任务脚本,修改多机训练脚本tune_qwen3_32b_4K_full_ptd.sh,多机推理可参考本脚本指定主节点IP、节点序号、节点数等信息,直接与ModelArts页面选择资源对接,无需手动修改:

#!/bin/bash
export CUDA_DEVICE_MAX_CONNECTIONS=1
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
 
# set_env
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh

export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH
cd ~/MindSpeed-LLM/

mkdir -p $OUTPUT_PATH/ckpt

# Change for multinode config
# 读取ModelArts下发的卡数
NPUS_PER_NODE="$MA_NUM_GPUS"
# 设置MASTER节点HOST
MASTER_ADDR="${VC_WORKER_HOSTS%%,*}"
MASTER_PORT=6000
# 设置MA下发的节点数
NNODES="$MA_NUM_HOSTS"
# 设置MA分配的节点索引
NODE_RANK="$VC_TASK_INDEX"
# 计算总卡数
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES))
 
# please fill these path configurations
CKPT_LOAD_DIR="$OUTPUT_PATH/qwen3_mcore/"
CKPT_SAVE_DIR="$OUTPUT_PATH/ckpt/"
DATA_PATH="./finetune_dataset/alpaca "
TOKENIZER_PATH="/home/mind/model/Qwen3-32B"
 
# TP\PP\MBS\GBS\SEQ_LENGTH\TRAIN_ITERS 按照需求设置
TP=4
PP=4
MBS=2
GBS=16
SEQ_LENGTH=4096
TRAIN_ITERS=2000


DISTRIBUTED_ARGS="
    --nproc_per_node $NPUS_PER_NODE \
    --nnodes $NNODES \
    --node_rank $NODE_RANK \
    --master_addr $MASTER_ADDR \
    --master_port $MASTER_PORT
"

OPTIMIZE_ARGS="
    --use-flash-attn \
    --use-fused-rotary-pos-emb \
    --use-rotary-position-embeddings \
    --use-fused-swiglu \
    --use-fused-rmsnorm \
    --no-masked-softmax-fusion \
    --use-distributed-optimizer
"

TRAIN_ARGS="
    --micro-batch-size ${MBS} \
    --global-batch-size ${GBS} \
    --lr 1.25e-6 \
    --lr-decay-style cosine \
    --min-lr 1.25e-7 \
    --weight-decay 1e-1 \
    --lr-warmup-fraction 0.01 \
    --attention-dropout 0.0 \
    --init-method-std 0.01 \
    --hidden-dropout 0.0 \
    --clip-grad 1.0 \
    --adam-beta1 0.9 \
    --adam-beta2 0.95 \
    --initial-loss-scale 4096 \
    --seed 42 \
    --bf16 \
    --train-iters ${TRAIN_ITERS} \
    --seq-length ${SEQ_LENGTH} \
    --no-shared-storage
"

MODEL_PARALLEL_ARGS="
    --tensor-model-parallel-size ${TP} \
    --pipeline-model-parallel-size ${PP}
"

GPT_ARGS="
    --use-mcore-models \
    --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
    --kv-channels 128 \
    --qk-layernorm \
    --tokenizer-name-or-path ${TOKENIZER_PATH} \
    --max-position-embeddings ${SEQ_LENGTH} \
    --num-layers 64 \
    --hidden-size 5120 \
    --ffn-hidden-size 25600 \
    --num-attention-heads 64 \
    --tokenizer-type PretrainedFromHF \
    --make-vocab-size-divisible-by 1 \
    --padded-vocab-size 151936 \
    --rotary-base 1000000 \
    --untie-embeddings-and-output-weights \
    --disable-bias-linear \
    --position-embedding-type rope \
    --normalization RMSNorm \
    --swiglu \
    --attention-softmax-in-fp32 \
    --no-gradient-accumulation-fusion \
    --group-query-attention \
    --num-query-groups 8
"

DATA_ARGS="
    --data-path $DATA_PATH \
    --split 100,0,0
"

OUTPUT_ARGS="
    --load ${CKPT_LOAD_DIR} \
	--save ${CKPT_SAVE_DIR} \
    --log-interval 1 \
    --save-interval ${TRAIN_ITERS} \
    --eval-interval ${TRAIN_ITERS} \
    --eval-iters 0 \
    --no-load-optim \
    --no-load-rng
"

TUNE_ARGS="
    --finetune \
    --stage sft \
    --is-instruction-dataset \
    --tokenizer-not-use-fast \
    --prompt-type qwen \
    --variable-seq-lengths
"

torchrun $DISTRIBUTED_ARGS posttrain_gpt.py \
    $GPT_ARGS \
    $DATA_ARGS \
    $OUTPUT_ARGS \
    $OPTIMIZE_ARGS \
    $TRAIN_ARGS \
    $TUNE_ARGS \
    $MODEL_PARALLEL_ARGS \
    --distributed-backend nccl \
    | tee logs/tune_qwen3_32b_full_ptd.log

以上脚本训练调优配置按需修改,本文不涉及训练参数调优过程。

Lora微调

创建Lora微调训练任务脚本,修改多机训练脚本tune_qwen3_32b_4K_lora_ptd.sh,多机推理可参考本脚本指定主节点IP,节点序号,节点数等信息,直接与ModelArts页面选择资源对接,无需手动修改:

#!/bin/bash
export CUDA_DEVICE_MAX_CONNECTIONS=1
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
 
# set_env
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh

export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH

cd ~/MindSpeed-LLM/

mkdir -p $OUTPUT_PATH/ckpt

export HCCL_CONNECT_TIMEOUT=1800

# Change for multinode config
# 读取ModelArts下发的卡数
NPUS_PER_NODE="$MA_NUM_GPUS"
# 设置MA节点HOST
MASTER_ADDR="${VC_WORKER_HOSTS%%,*}"
MASTER_PORT=6014
# 设置MA下发的节点数
NNODES="$MA_NUM_HOSTS"
# 设置MA分配的节点索引
NODE_RANK="$VC_TASK_INDEX"
# 计算总卡数
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES))

# please fill these path configurations
CKPT_LOAD_DIR="$OUTPUT_PATH/qwen3_mcore/"
CKPT_SAVE_DIR="$OUTPUT_PATH/ckpt/"
DATA_PATH="./finetune_dataset/alpaca "
TOKENIZER_PATH="/home/mind/model/Qwen3-32B"

TP=4
PP=4
SEQ_LENGTH=4096
TRAIN_ITERS=2000


DISTRIBUTED_ARGS="
    --nproc_per_node $NPUS_PER_NODE \
    --nnodes $NNODES \
    --node_rank $NODE_RANK \
    --master_addr $MASTER_ADDR \
    --master_port $MASTER_PORT
"

OPTIMIZE_ARGS="
    --use-flash-attn \
    --use-fused-rotary-pos-emb \
    --use-rotary-position-embeddings \
    --use-fused-swiglu \
    --use-fused-rmsnorm \
    --no-masked-softmax-fusion \
    --use-distributed-optimizer
"

TRAIN_ARGS="
    --micro-batch-size 4 \
    --global-batch-size 16 \
    --lr 1.25e-5 \
    --lr-decay-style cosine \
    --min-lr 1.25e-7 \
    --weight-decay 1e-1 \
    --lr-warmup-fraction 0.01 \
    --attention-dropout 0.0 \
    --init-method-std 0.01 \
    --hidden-dropout 0.0 \
    --clip-grad 1.0 \
    --adam-beta1 0.9 \
    --adam-beta2 0.95 \
    --initial-loss-scale 4096 \
    --seed 42 \
    --bf16 \
    --train-iters ${TRAIN_ITERS} \
    --seq-length ${SEQ_LENGTH} \
    --no-shared-storage
"

MODEL_PARALLEL_ARGS="
    --tensor-model-parallel-size ${TP} \
    --pipeline-model-parallel-size ${PP}
"

GPT_ARGS="
    --use-mcore-models \
    --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
    --kv-channels 128 \
    --qk-layernorm \
    --tokenizer-name-or-path ${TOKENIZER_PATH} \
    --max-position-embeddings ${SEQ_LENGTH} \
    --num-layers 64 \
    --hidden-size 5120 \
    --ffn-hidden-size 25600 \
    --num-attention-heads 64 \
    --tokenizer-type PretrainedFromHF \
    --make-vocab-size-divisible-by 1 \
    --padded-vocab-size 151936 \
    --rotary-base 1000000 \
    --untie-embeddings-and-output-weights \
    --disable-bias-linear \
    --position-embedding-type rope \
    --normalization RMSNorm \
    --swiglu \
    --attention-softmax-in-fp32 \
    --no-gradient-accumulation-fusion \
    --group-query-attention \
    --num-query-groups 8
"

DATA_ARGS="
    --data-path $DATA_PATH \
    --split 100,0,0
"

OUTPUT_ARGS="
    --load ${CKPT_LOAD_DIR} \
	--save ${CKPT_SAVE_DIR} \
    --log-interval 1 \
    --save-interval ${TRAIN_ITERS} \
    --eval-interval ${TRAIN_ITERS} \
    --eval-iters 0 \
    --no-load-optim \
    --no-load-rng
"

TUNE_ARGS="
    --finetune \
    --stage sft \
    --is-instruction-dataset \
    --tokenizer-not-use-fast \
    --prompt-type qwen \
    --variable-seq-lengths \
    --lora-r 16 \
    --lora-alpha 32 \
    --lora-fusion \
    --lora-target-modules linear_qkv linear_proj linear_fc1 linear_fc2
"

torchrun $DISTRIBUTED_ARGS posttrain_gpt.py \
    $GPT_ARGS \
    $DATA_ARGS \
    $OUTPUT_ARGS \
    $OPTIMIZE_ARGS \
    $TRAIN_ARGS \
    $TUNE_ARGS \
    $MODEL_PARALLEL_ARGS \
    --distributed-backend nccl \
    | tee logs/tune_qwen3_32b_lora_ptd.log

以上脚本训练调优配置按需修改,本文不涉及训练参数调优过程。

mcore权重转换huggingface

全参微调结果权重转换

全参微调权重转换脚本:ckpt_convert_qwen3_mcore2hf.sh

# set_env
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh

export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH

# master节点进行最后的权重转换
if [[ "$VC_TASK_INDEX" == 0 ]]; then
    # 汇总权重到OBS挂载路径,需要自行汇总
    echo "This is master, doing mcore to hf"
    # 汇总所有节点权重,OBS地址可以从MA_OUTPUTS环境变量中获取romote,主要需要登录,todo:可以使用moxing解决,目前已跟产品线沟通发布外部商发版本
    obsutil cp -r -f obs://qwen3/llmd/ckpt/ $OUTPUT_PATH/
    mkdir -p $OUTPUT_PATH/qwen3_hf
    # 这个转换需要目录下有原始权重,cp到output下
    cp -rf /home/mind/model/Qwen3-32B/* $OUTPUT_PATH/qwen3_hf

    python convert_ckpt.py \
        --use-mcore-models \
        --model-type GPT \
        --load-model-type mg \
        --save-model-type hf \
        --target-tensor-parallel-size 1 \
        --target-pipeline-parallel-size 1 \
        --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
        --load-dir $OUTPUT_PATH/ckpt/ \
        --save-dir $OUTPUT_PATH/qwen3_hf/ \
        --model-type-hf qwen3 \
        --params-dtype bf16
    else
        echo "This is slave, ignore mcore to hf"
fi

将准备好的脚本上传至OBS。

Lora微调结果权重转换

Lora权重转换脚本:ckpt_convert_qwen3_mcore2hf_lora.sh

# 修改 ascend-toolkit 路径
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh

export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH

if [[ "$VC_TASK_INDEX" == 0 ]]; then
    # 汇总权重到OBS挂载路径,需要自行汇总
    echo "This is master, doing mcore to hf"
    # 汇总所有节点权重,OBS地址可以从MA_OUTPUTS环境变量中获取romote,主要需要登录,todo:可以使用moxing解决,目前已跟产品线沟通发布外部商发版本
    obsutil cp -r -f obs://qwen3/llmd/ckpt/ $OUTPUT_PATH/
    mkdir -p $OUTPUT_PATH/qwen3_hf
    # 这个转换需要目录下有原始权重
    cp -rf /home/mind/model/Qwen3-32B/* $OUTPUT_PATH/qwen3_hf

    python convert_ckpt.py \
        --use-mcore-models \
        --model-type GPT \
        --load-model-type mg \
        --save-model-type hf \
        --target-tensor-parallel-size 1 \
        --target-pipeline-parallel-size 1 \
        --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
        --lora-r 16 \
        --lora-alpha 32 \
        --lora-target-modules linear_qkv linear_proj linear_fc1 linear_fc2 \
        --load-dir $OUTPUT_PATH/qwen3_mcore/ \
        --lora-load $OUTPUT_PATH/ckpt/ \
        --save-dir $OUTPUT_PATH/qwen3_hf/ \
        --model-type-hf qwen3 \
fi

如需单独转换Lora权重,添加如下参数:

参数说明可选/必选
--save-lora-to-hflora转hf时设置此参数以指定仅转换lora权重可选
--load-checkpoint-loosely允许松弛加载,转换lora权重时,需要设置此参数可选

五、在ModelArts上创建训练任务并启动训练

创建训练作业并启动训练。

输入训练任务“名称” image.png

创建方式选择”自定义算法”

启动方式选择“自定义”

镜像选择 “步骤一制作训练镜像上传至SWR的镜像”

代码目录选择“步骤二上传的权重目录”

启动命令输入:

bash $SCRIPT_PATH/data_convert_qwen3_32b_instruction.sh \
&& bash $SCRIPT_PATH/ckpt_convert_qwen3_32b_hf2mcore.sh \
&& bash $SCRIPT_PATH/tune_qwen3_32b_4K_full_ptd.sh \
&& sleep 1000 && bash $SCRIPT_PATH/ckpt_convert_qwen3_mcore2hf.sh

image.png

在“输入”中添加变量SCRIPT_PATH,数据存储位置选择步骤4中上传OBS的脚本路径,获取方式选择环境变量。

在“输入”中添加变量DATA_PATH,数据存储位置选择步骤3中上传OBS的训练数据集路径,获取方式选择环境变量。

根据训练要求按需添加其他环境变量及超参等输入。

在“输出”中添加变量OUTPUT_PATH,数据存储位置训练完需要保存至OBS的路径,获取方式选择环境变量。

根据训练要求按需添加其他环境变量及超参等输出。

根据训练要求按需添加“超参”及“环境变量”。 image.png

选择训练需要的“专属资源池”,规格,计算节点个数等。 image.png

点击“创建”任务开始执行模型训练,当看到迭代信息时说明任务开始正常训练,可以关注loss曲线查看训练情况,等待模型训练完成。

注:调试脚本过程中可以选择调试模式,待脚本运行正常后可以创建生成模式正式开始训练。

以上截图来自公有云环境,页面略有区别。

模型部署

可参考MindIE部署文档,注意训练转换完的权重不包含vocab.json、tokenizer.json、tokenizer_config.json等配置,需要手动拷贝。

附录

参考文档:

https://gitee.com/ascend/MindSpeed-LLM/blob/master/docs/quick_start.md

问题记录:

报错1:Import Error: libhccl.so: cannot open shared object file: No such file or dictory. Import Error: libascend_hal.so: cannot open shared object file: No such file or dictory

答:经定位未source相应环境变量及PATH未添加driver路径,解决方案如下:

在脚本中添加如下代码,初始化环境:

# set_env
source /usr/local/Ascend/driver/bin/setenv.bash
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/set_env.sh
export LD_LIBARY_PATH=/usr/local/Ascend/driver/lib64/driver:$LD_LIBARY_PATH

报错2:import torchair ModuleNotFoundError: No module named torchair.

答:经查看代码、比对环境等操作后,最终定位到问题原因是镜像中的torch及torch-npu小版本存在错误,未使用官方适配推荐的版本。更换镜像后,问题得以解决。因此,在制作镜像时务必按照官方指导进行配置,以避免此类问题的发生。