更新时间:2026-02-05 GMT+08:00
分享

准备训练脚本

在MindSpeed-LLM中不同类型的模型的权重转化、数据处理、微调任务脚本有所差异,具体请参考MindSpeed-LLM/docs/quick_start.md · Ascend/MindSpeed-LLM - AtomGit | GitCode 下每种模型具体的脚本example。

以Qwen3系列模型的训练任务为例,分别准备对应模型的训练脚本,并上传至OBS桶中。具体脚本如下:

  • ckpt_convert_qwen3_hf2mcore.sh:权重转化脚本,由hf格式转化为mg格式的权重,脚本示例参考权重转化脚本(hf2mg)
  • data_convert_qwen3_instruction.sh:数据处理脚本,脚本示例参考数据处理脚本
  • tune_qwen3_32b_4K_full_ptd.sh:微调任务执行脚本,脚本示例参考微调任务执行脚本
  • ckpt_convert_qwen3_mcore2hf.sh:权重转换脚本,由mg格式转化为hf格式的权重,脚本示例参考权重转换脚本(mg2hf)
  • run_distributed_task.sh:训练作业启动脚本,执行时会调用上述所有脚本。多机训练场景下,通过run_distributed_task.sh脚本使得每个节点之间可以互相获取节点IP地址并设置MASTER_PORT。脚本示例参考训练作业启动脚本

脚本中公共参数解释

sh脚本中参数详解如下:
  • ${output_dir} :训练或者格式转化的输出路径。配置obs路径到输出的环境变量output_dir,例如/home/ma-user/modelarts/outputs/output_dir_0。
  • ${model_path}:训练模型的路径,根据此参数配置TOKENIZER_PATH参数。
  • ${dataset_path} 待处理的数据集的路径。

如直接复制本脚本,请注意不同操作系统下换行符的差异。可以使用dos2unix xxx.sh命令将脚本内换行符转换为linux系统的换行符。

Qwen3-32B 为例,准备如下脚本,其中脚本中的注释仅为说明参数含义,实际使用时请去除在每行的\后不要留有空格

权重转化脚本(hf2mg)

ckpt_convert_qwen3_hf2mcore.sh脚本内容如下,脚本中需要修改的参数请参见脚本中的注释。

其中的环境变量统一在run_distributed_task.sh训练任务启动总脚本进行设置。
# 修改 ascend-toolkit 路径
export CUDA_DEVICE_MAX_CONNECTIONS=1
source /usr/local/Ascend/ascend-toolkit/set_env.sh
python /home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM/convert_ckpt.py \ #镜像预装的MindSpeed-LLM的convert代码位置,无需修改
    --use-mcore-models \
    --model-type GPT \
    --load-model-type hf \
    --save-model-type mg \
    --target-tensor-parallel-size 8 \
    --target-pipeline-parallel-size 2 \
    --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
    --load-dir "$TOKENIZER_PATH" \                                   #模型的具体位置,在run_distributed_task.sh中统一设置
    --save-dir "$CKPT_LOAD_DIR" \                   #保存转化完成后的权重位置,在run_distributed_task.sh中统一设置
    --tokenizer-model "$TOKENIZER_PATH/tokenizer.json"  \             #tokenizer.json位置,变量部分在run_distributed_task.sh中统一设置
    --params-dtype bf16 \
    --model-type-hf qwen3

数据处理脚本

data_convert_qwen3_instruction.sh脚本内容如下,脚本中需要修改的参数请参见脚本中的注释。

其中的环境变量统一在run_distributed_task.sh训练任务启动总脚本进行设置。
# 请按照您的真实环境修改 set_env.sh 路径
source /usr/local/Ascend/ascend-toolkit/set_env.sh
mkdir -p "${output_dir}/finetune_dataset" #保持不变
python /home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM/preprocess_data.py \ #镜像预装的MindSpeed-LLM的convert代码位置,无需修改
    --input ${dataset_path}/alpaca_gpt4_data.json \                              #待处理数据集的路径
    --tokenizer-name-or-path "$TOKENIZER_PATH" \                          #用于处理数据集的模型路径,在run_distributed_task.sh中统一设置
    --output-prefix "$DATA_PATH" \                      #输出的数据数据集路径+格式,在run_distributed_task.sh中统一设置
    --handler-name AlpacaStyleInstructionHandler \    #如更换格式需要同步修改
    --tokenizer-type PretrainedFromHF \
    --workers 4 \
    --log-interval 1000 \
    --enable-thinking true \
    --prompt-type qwen3

微调任务执行脚本

tune_qwen3_32b_4K_full_ptd.sh脚本内容如下,脚本中需要修改的参数请参见脚本中的注释。
#!/bin/bash
export HCCL_CONNECT_TIMEOUT=7200   # 最大超时时间,可以根据实际情况调整
export HCCL_EXEC_TIMEOUT=7200
export CUDA_DEVICE_MAX_CONNECTIONS=1
export PYTORCH_NPU_ALLOC_CONF=expandable_segments:True
# =========================================================
# 1. 接收外部环境变量 (如果外部未传递,则使用冒号后的默认值)
此处环境变量建议在run_distributed_task.sh 中设置覆盖
# =========================================================
NPUS_PER_NODE=${NPUS_PER_NODE:-8}
MASTER_ADDR=${MASTER_ADDR:-"localhost"}
MASTER_PORT=${MASTER_PORT:-6000}
NNODES=${NNODES:-1}
NODE_RANK=${NODE_RANK:-0}
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES))
# 路径配置也改为接收环境变量,此处环境变量建议run_distributed_task.sh 中设置覆盖
CKPT_LOAD_DIR=${CKPT_LOAD_DIR:-"${output_dir}/model_weights/qwen3_mcore/"}    #默认参考值,run_distributed_task.sh中覆盖
CKPT_SAVE_DIR=${CKPT_SAVE_DIR:-"${output_dir}/ckpt/qwen3-32b/"}               #默认参考值,run_distributed_task.sh中覆盖
DATA_PATH=${DATA_PATH:-"${output_dir}/finetune_dataset/alpaca"}               #默认参考值,run_distributed_task.sh中覆盖
TOKENIZER_PATH=${TOKENIZER_PATH:-"${model_path}/Qwen3-32B/"}                  #默认参考值,run_distributed_task.sh中覆盖
# =========================================================
# 2. 训练参数 
# =========================================================
TP=8     #与ckpt_convert_qwen3_hf2mcore.sh中保持一致
PP=2     #与ckpt_convert_qwen3_hf2mcore.sh中保持一致
MBS=1
GBS=32
TRAIN_ITERS=50
SEQ_LENGTH=4096
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 1 \
    --global-batch-size 16 \
    --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 qwen3 \
    --variable-seq-lengths
"
# 运行 torchrun,注意日志文件名加入了 NODE_RANK 以防冲突
mkdir -p "$CHECK_LOG_DIR" #校验日志,无需修改
set -o pipefail             #开启pipefail
torchrun $DISTRIBUTED_ARGS /home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM/posttrain_gpt.py \  #镜像预装的MindSpeed-LLM的启动代码位置,无需修改
    $GPT_ARGS \
    $DATA_ARGS \
    $OUTPUT_ARGS \
    $OPTIMIZE_ARGS \
    $TRAIN_ARGS \
    $TUNE_ARGS \
    $MODEL_PARALLEL_ARGS \
    --distributed-backend nccl \
    2>&1 | tee "$CHECK_LOG_PATH" && \
    echo "Training completes" >> "$CHECK_LOG_PATH"  #补充完成标志到日志中,环境变量在run_distributed_task.sh中统一设置,无需修改

sleep 10s
tail -n 500 "$CHECK_LOG_PATH" | grep -q -E "Training completes" || exit 1 #异常状态校验

权重转换脚本(mg2hf)

ckpt_convert_qwen3_mcore2hf.sh脚本内容如下,脚本中需要修改的参数请参见脚本中的注释。

其中的环境变量统一在run_distributed_task.sh训练任务启动总脚本进行设置。

转换成功后的权重保存目录下仅包含模型权重文件,不会生成config.json模型配置文件和tokenizer.model、vocab.json等词表文件。run_distributed_task.sh脚本中会帮助将config.json模型配置文件和tokenizer.model、vocab.json等词表文件复制到转化后的模型文件夹中。

hf2mg格式转换的时候使用convert_ckpt.py,在此处也是用convert_ckpt.py来进行mg2hf。

具体参数说明如下注释。使用时请去除注释和’\’后所有的空格。

# 修改 ascend-toolkit 路径
source /usr/local/Ascend/ascend-toolkit/set_env.sh
export CUDA_DEVICE_MAX_CONNECTIONS=1
mkdir -p "$CHECK_LOG_DIR"
set -o pipefail
python /home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM/convert_ckpt.py \ #镜像预装的MindSpeed-LLM的convert代码位置,无需修改。
    --use-mcore-models \
    --model-type GPT \
    --load-model-type mg \
    --save-model-type hf \
    --target-tensor-parallel-size 1 \#均为1,无需修改
    --target-pipeline-parallel-size 1 \#均为1,无需修改
    --spec mindspeed_llm.tasks.models.spec.qwen3_spec layer_spec \
    --load-dir "$CKPT_SAVE_DIR" \#训练完成时的ckpt保存位置,即为run_distributed_task.sh中的CKPT_SAVE_DIR
    --save-dir "$TOKENIZER_PATH" \#原始的hf格式的模型路径,即为run_distributed_task.sh中的TOKENIZER_PATH
    --params-dtype bf16 \
    --model-type-hf qwen3 \
    2>&1 | tee "$CHECK_LOG_PATH" && \
    echo "Convert mg2hf completes" >> "$CHECK_LOG_PATH"  #补充完成标志到日志中
sleep 10s
tail -n 500 "$CHECK_LOG_PATH" | grep -q -E "Convert mg2hf completes"  || exit 1 #异常状态校验,注意日志名称一致

训练作业启动脚本

run_distributed_task.sh脚本内容如下,脚本中需要修改的参数请参见脚本中的注释。
#!/bin/bash
set -e
# =========================
# 1. 基础环境与网络配置
# =========================
export HCCL_CONNECT_TIMEOUT=7200   # 最大超时时间,可以根据实际情况调整
export HCCL_EXEC_TIMEOUT=7200
export HCCL_IF_BASE_PORT=61000
export HCCL_NPU_SOCKET_PORT_RANGE="61000-61050"
unset https_proxy http_proxy proxy ASCEND_RT_VISIBLE_DEVICES
source /usr/local/Ascend/ascend-toolkit/set_env.sh
source /usr/local/Ascend/nnal/atb/set_env.sh
# 自动获取本机 IP
get_current_ip() {
    local ip
    ip=$(ip -4 addr | grep -v '127.0.0.1' | grep -oP '(?<=inet\s)\d+(\.\d+){3}' | head -n1 2>/dev/null)
    if [[ -z "$ip" ]]; then
        ip=$(ip -4 addr | grep -v '127.0.0.1' | awk '/inet/ {gsub(/\/.*/,""); print $2}' | head -n1 2>/dev/null)
    fi
    echo "${ip:-}"
}
CURRENT_IP=$(get_current_ip)
# 解析 ModelArts 环境变量,自动获取NPU数量和Nodes数量
export NNODES=${VC_WORKER_NUM:-1}
export NPUS_PER_NODE=${MA_NUM_GPUS:-8}
export MASTER_PORT=6000
# 自动计算 NODE_RANK 和 MASTER_ADDR
if [ "$NNODES" -gt 1 ]; then
    MASTER_ADDR_RAW="${VC_WORKER_HOSTS%%,*}"
    export MASTER_ADDR=$(python3 -c "import socket; print(socket.gethostbyname('${MASTER_ADDR_RAW}'))")
    export NODE_RANK=$(python3 -c "import os, socket; hosts = os.environ.get('VC_WORKER_HOSTS', '').split(','); cur='${CURRENT_IP}'; print(next((i for i, h in enumerate(hosts) if socket.gethostbyname(h.strip()) == cur), 0))")
    echo "[INFO] Multi-Node: Master=$MASTER_ADDR, Rank=$NODE_RANK, Total=$NNODES"
else
    export MASTER_ADDR="localhost"
    export NODE_RANK=0
    echo "[INFO] Single-Node Mode"
fi
# =========================
# 2. 定义全局路径 (供子脚本使用,会覆盖微调脚本中的相应参数)
# =========================
export CKPT_LOAD_DIR="${output_dir}/model_weights/qwen3_mcore/"  #之前转换的mg格式路径
export CKPT_SAVE_DIR="${output_dir}/ckpt/qwen3-32b/"              #ckpt 保存路径
export DATA_PATH="${output_dir}/finetune_dataset/alpaca"         #处理后的微调数据集路径+格式(此处为alpaca),此处结尾无"/"
export TOKENIZER_PATH="${model_path}/Qwen3-32B/"                 #模型路径
export TRAINED_HF_MODELS="${output_dir}/trained_hf_models/"      #训练完成后mg格式转化为hf格式的模型路径

export CHECK_LOG_DIR="/home/ma-user/logs"                        #容器内校验log所在文件夹,容器内路径非挂载路径,无需修改,此处结尾无"/"
export CHECK_LOG_FILE="tune_qwen3_32b_full_ptd.log"              #容器内校验log名称,可以根据模型和任务自行设置名称
export CHECK_LOG_PATH="${CHECK_LOG_DIR}/${CHECK_LOG_FILE}"       #容器内校验log总路径,容器内文件,无需修改

# 确保目录存在
mkdir -p "$CKPT_SAVE_DIR"
mkdir -p "$CHECK_LOG_DIR" #校验日志
# =========================
# 3. 权重转换(hf2mg)与数据处理
# =========================
echo " Starting Checkpoint & Data Conversion..."
# 执行权重转换
echo " Running ckpt_convert_qwen3_hf2mcore.sh..."
bash ckpt_convert_qwen3_hf2mcore.sh                   #本模型的权重转换脚本
# 执行数据处理
echo " Running data_convert_qwen3_instruction.sh..."
bash data_convert_qwen3_instruction.sh                #本模型的数据处理脚本
echo " Preparation Done. Creating flag file."


# =========================
# 4. 启动分布式训练 (所有节点都执行)
# =========================

# 检查是否存在 r+ 模式(OBS挂载需保持本内容)
FILE_PATH="/home/ma-user/MA_Turbo/src/open_source/MindSpeed-LLM/mindspeed_llm/tasks/preprocess/decoder_packed_mtf_dataset.py"
if grep -q "mmap_mode='r+'" "$FILE_PATH"; then
    # 仅针对包含 mmap_mode='r+' 的行进行精准替换
    sed -i.bak "s/\(mmap_mode=['\"]\)\(r+\)\(['\"]\)/\1r\3/g" "$FILE_PATH"
else
    echo "未检测到 mmap_mode='r+',跳过操作。"
fi

echo " Starting Training Script on Rank $NODE_RANK..."
# 执行修改后的训练脚本
bash tune_qwen3_32b_4K_full_ptd.sh                #本模型的微调训练脚本


# =========================
# 5. 权重转换(mg2hf)与保存模型
# =========================

# 仅在主节点执行权重转换(mg2hf)
if [ "$NODE_RANK" -eq 0 ]; then
    echo "[Master] Master. Doing Convert ckpt from mcore to hf models"
    mkdir -p "$TRAINED_HF_MODELS"
    find "$TOKENIZER_PATH" -type f ! -name "*.safetensors" -exec cp {} "$TRAINED_HF_MODELS" \;  #复制原始模型的config.json模型配置文件和tokenizer.model、vocab.json等词表文件
    bash ckpt_convert_qwen3_mcore2hf.sh                                                         #执行mg2hf权重转化脚本
    mv "$TOKENIZER_PATH/mg2hf/"* "$TRAINED_HF_MODELS/"                                          #将转化后权重移动到OBS中的相应位置
    echo "All steps completes" >> "$CHECK_LOG_PATH"
else
    echo "[Worker $NODE_RANK] Task finished. Waiting for Master to complete conversion..."
    echo "All steps completes" >> "$CHECK_LOG_PATH"
fi

sleep 10s
tail -n 500 "$CHECK_LOG_PATH" | grep -q -E "All steps completes"  && exit 0 || exit 1 #异常状态校验反馈给平台,环境变量无需修改

将以上脚本放在自己的OBS桶内的相应位置。

相关文档