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

Qwen2.5-7B-Instruct模型训练使用指导

一、 模型概述及场景

Qwen2.5是通义千问大模型系列2024年9月发布,参数量从0.5B到72B不等的多个基础模型和指令微调模型。相比Qwen2,Qwen2.5主要带来以下提升:

  • 通过领域专家模型增强,显著扩充知识储备,大幅提升代码与数学能力
  • 在指令遵循、长文本生成(超8K tokens)、结构化数据理解(如表格)及结构化输出(尤其是JSON格式)方面表现更优
  • 对系统提示词的多样性更具适应性,强化了聊天机器人的角色扮演和条件设定功能
  • 支持128K tokens长上下文,可生成8K tokens内容
  • 支持中英法西葡德意俄日韩越泰阿拉伯等29种语言

本仓库包含7B参数的Qwen2.5指令微调模型,具有以下特性:

  • 类型:因果语言模型
  • 训练阶段:预训练&后训练
  • 架构:采用RoPE位置编码、SwiGLU激活函数、RMSNorm归一化及带偏置的Attention QKV结构
  • 参数量:7.61B(非嵌入层6.53B)
  • 层数:28
  • 注意力头(分组查询注意力):Q头28个/KV头4个
  • 下文长度:完整支持131,072 tokens,生成长度8,192 tokens
  • 长文本处理部署指南详见相关章节

模型huggingface链接:Qwen2.5-7B-Instruct

本案例使用昇腾A3机器上,基于MindspeedLLM 框架完成Qwen2.5-7B-Instruct模型基于业务数据集的SFT以及Lora训练实践。

二、 环境准备

Qwen2.5-7B-Instruct在业务数据集上的全参微调以及Lora微调训练与评测使用到的软件以及硬件环境如下:

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-LLM镜像章节。

三、 数据预处理

3.1. 脚本

业务数据集是ShareGPT风格数据,因此采用ShareGPT风格数据集处理方法进行预处理。

业务当前提供数据集预处理脚本如下:

# 业务数据集预处理
source /usr/local/Ascend/ascend-toolkit/set_env.sh
cd /usr/local/Ascend/llm-train/MindSpeed-LLM
datapath=***
mkdir ${datapath}/train_data_10k

python ./preprocess_data.py \
    --input ${datapath}/train_data_10k.jsonl \
    --tokenizer-name-or-path /apps/hw/weights/Qwen2.5-7B \
    --output-prefix ${datapath}/train_data_10k/train_data_10k \
    --workers 4 \
    --log-interval 1000 \
    --tokenizer-type PretrainedFromHF \
    --handler-name SharegptStyleInstructionHandler \
    --prompt-type qwen \
    --map-keys '{"messages":"messages", "tags":{"role_tag": "role","content_tag": "content","user_tag": "user","assistant_tag": "assistant","system_tag": "system"}}'

关键参数说明:

  1. --input(必须):

    描述: 输入数据文件的路径,通常是一个jsonl(每行一个JSON对象)文件。

    示例: --input /path/to/data.jsonl

  2. --tokenizer-name-or-path(必须):

    描述: 用于分词器的预训练模型的名称或路径。可以是Hugging Face模型仓库的ID,也可以是本地包含tokenizer文件的目录。

    示例: --tokenizer-name-or-path Qwen/Qwen1.5-7B或者 --tokenizer-name-or-path /path/to/tokenizer

  3. --output-prefix(必须):

    描述: 输出文件的前缀。预处理后的数据会被保存为多个文件(例如,后缀为.bin和.idx),这个参数指定这些文件的前缀路径。

    示例: --output-prefix /path/to/output/preprocessed_data

  4. --workers(可选,默认值可能为1):

    描述: 指定数据预处理时使用的进程数(多进程)。更多的进程数可以加快处理速度。

    示例: --workers 4

  5. --log-interval(可选,默认值可能为100):

    描述: 控制日志打印的频率,例如每处理1000条数据打印一次进度日志。

    示例: --log-interval 1000

  6. --tokenizer-type(必须):

    描述: 指定tokenizer的类型。这里使用PretrainedFromHF,表示使用Hugging Face的预训练tokenizer。

    示例: --tokenizer-type PretrainedFromHF

  7. --handler-name(必须):

    描述: 指定数据处理器(handler)的类名。这里使用SharegptStyleInstructionHandler,这是专门为类似ShareGPT格式(对话格式)的指令数据设计的处理器。该处理器会按照指令模板格式化数据。

    示例: --handler-name SharegptStyleInstructionHandler

  8. --prompt-type(必须):

    描述: 指定提示模板类型。不同的提示模板对应不同的格式化方式。这里指定为qwen,表示使用Qwen模型所要求的提示格式。

    示例: --prompt-type qwen

  9. --map-keys(必须):

    描述: 一个JSON字符串,用于将输入数据中的字段映射到处理器所需的字段。这个参数允许我们自定义输入JSON中的键名,使得处理器能够正确获取角色、内容等信息。

    格式: 一个JSON字典,其中至少包括:

    • "messages": 输入数据中对话列表的键名(通常是一个列表,包含多个对话回合)

    • "tags": 一个嵌套字典,用于指定在对话回合中每个字段的键名,例如角色(role)、内容(content)等,以及用户、助手和系统角色的标签。

      示例:

      --map-keys '{"messages":"messages", "tags":{"role_tag":"role", "content_tag":"content", "user_tag":"user", "assistant_tag":"assistant", "system_tag":"system"}}'

      说明:在这个例子中,输入数据中对话列表的键名为"messages"。在每一个对话回合中,角色字段的键名为"role",内容字段的键名为"content",而用户、助手和系统消息则分别用"user"、"assistant"和"system"来标识(这些标签用于区分消息发送者)。

注意:由于--map-keys参数是一个JSON字符串,所以需要用单引号括起来(在shell中),并且确保内部双引号被正确转义或保留(这里使用的是JSON字符串,所以内部用双引号)。

3.2. 处理结果

数据预处理脚本会将数据按照相应的数据风格进行解析,并且根据prompt-type所对应的模板构建成为prompt,再转化为token后保存到.bin .idx 文件中。下图是解析后的文件示例。

image-20250806164146977

四、 权重准备

4.1. 模型权重下载

从HuggingFace下载模型权重Qen2.5-7B-Instruct,下载方式参考HF镜像站,其他模型下载可参考Dense模型、MOE模型和SSM模型文档中对应模型的下载链接。下载完成效果如下:

image-20250807115022600

4.2. 权重转换

随着大规模预训练模型的广泛应用,不同的训练框架和硬件平台之间的适配性问题逐渐显现。专有训练框架如MindSpeed-LLM通常采用定制的并行化策略(例如Tensor Parallelism、Pipeline Parallelism)以应对大规模模型训练中的内存和计算瓶颈。随着训练需求和硬件的变化,模型参数的切分策略也需进行相应的调整。然而,跨框架的权重转换往往面临格式不兼容和切分策略不同等挑战。权重转换旨在促进大规模预训练模型在不同训练框架之间的无缝迁移与评估,解决框架间权重格式不兼容及切分策略差异等问题,从而增强模型迁移的灵活性和可扩展性,支持更广泛的应用场景和业务需求。

权重转换实现了 HuggingFace 权重到 Megatron-LM 格式的转换,支持多种并行策略(如张量并行、流水并行等),确保转换后可以在 MindSpeed-LLM 框架下继续训练和推理。

4.2.1. 全参微调

当前采用TP=4,PP=2进行权重切分。权重切分具体代码如下:

# cd MinspeedLLM path
source /usr/local/Ascend/ascend-toolkit/set_env.sh

# 设置需要的权重转换参数
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 2 \
       --num-layer-list 14, 14
       --add-qkv-bias \
       --load-dir /***/weights/Qwen2.5-7B-Instruct/ \
       --save-dir /***/weights/weight_mg/new_qwen2.5_mcore_tp4_pp2/ \
       --tokenizer-model /***/weights/Qwen2.5-7B-Instruct/tokenizer.json \
       --model-type-hf llama2 \
       --params-dtype bf16
参数说明可选/必选
--target-tensor-parallel-sizeTP 切分数量,默认为 1必选
--target-pipeline-parallel-sizePP 切分数量,默认为 1必选
--num-layer-list动态PP划分,通过列表指定每个PP Stage的层数,默认为None可选
--num-layers-per-virtual-pipeline-stageVPP划分,指定VPP的每个Stage层数,默认为None可选
--target-expert-model-parallel-size专家并行,指定专家并行卡数,默认为1可选
--noop-layers自定义空层操作,指定在模型某层增加空层,转换后层数为原huggingface模型层数+空层数,默认为None可选
--use-mcore-models转换为Megatron-Mcore权重,若不指定,则默认转换为Megatron-Legacy权重可选
--model-type-hfhuggingface模型类别,默认为llama2,参考注意 2可选
--tokenizer-model需要指明到具体的分词器模型文件,如 tokenizer.model、tokenizer.json、qwen.tiktoken、None等,具体取决于huggingface中词表文件的格式形式必选
--params-dtype指定权重转换后的权重精度模式,默认为fp16,如果源格式文件为bf16,则需要对应设置为bf16,影响推理或评估结果必选

注意:

  1. VPP和动态PP划分只能二选一

  2. 目前支持的模型见 model_cfg.json中“model_mappings”下包含的模型。

关键参数说明:

qwen2.5模型这里的--model-type-hf需要设置为:llama2。参考目前支持的模型 model_cfg.json中“model_mappings”下包含的模型参数映射关系。

执行结果如下:

image-20250807163015089

4.2.2. Lora微调

当前采用TP=2,PP=1进行权重切分:

# cd MinspeedLLM path
source /usr/local/Ascend/ascend-toolkit/set_env.sh

# 设置需要的权重转换参数
python convert_ckpt.py \
       --use-mcore-models \
       --model-type GPT \
       --load-model-type hf \
       --save-model-type mg \
       --target-tensor-parallel-size 2 \
       --target-pipeline-parallel-size 1 \
       --add-qkv-bias \
       --load-dir /***/weights/Qwen2.5-7B-Instruct/ \
       --save-dir /***/weights/weight_mg/qwen2.5_7b_instruct_mcore_tp2_pp1/ \
       --tokenizer-model /***/weights/Qwen2.5-7B-Instruct/tokenizer.json \
       --model-type-hf llama2 \
       --params-dtype bf16

关键参数说明:

qwen2.5模型这里的--model-type-hf需要设置为:llama2。参考目前支持的模型 model_cfg.json中“model_mappings”下包含的模型参数映射关系。

执行结果如下:

image-20250807163052533

五、 模型训练

5.1. 全参微调

全参官方参考链接: 大模型指令微调

5.1.1. 训练脚本

# 文件名称scripts/qwen25_7b_instruct/tune_qwen25_7b_full_ptd.sh
set -e
source /usr/local/Ascend/ascend-toolkit/set_env.sh
export CUDA_DEVICE_MAX_CONNECTIONS=1

NPUS_PER_NODE=8
MASTER_ADDR=localhost
MASTER_PORT=1901
NNODES=1
NODE_RANK=0
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES))

# please fill these path configurations
CKPT_LOAD_DIR="***/weights/weight_mg/qwen2.5_7b_instruct_mcore_tp4_pp2"
CKPT_SAVE_DIR="***/weights/ckpt_record/auto_train_test/qwen2.5_mcore_full_tp4_pp2"
DATA_PATH="***"
TOKENIZER_PATH="***/weights/Qwen2.5-7B-Instruct"
tensorboard_dir="***/outputs/qwen2.5-7b/tensorboard_dir/full"
train_log_path="***/outputs/qwen2.5-7b/logs/tune_mcore_qwen25_7b_full_tp4_pp2_train.log"

TP=4
PP=2
SEQ_LEN=2048
MBS=32
GBS=256
TRAIN_ITERS=200

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

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

GPT_ARGS="
    --use-distributed-optimizer \
    --overlap-grad-reduce \
    --overlap-param-gather \
    --use-mcore-models \
    --tensor-model-parallel-size ${TP} \
    --pipeline-model-parallel-size ${PP} \
    --num-layer-list 14,14 \
    --num-layers 28  \
    --hidden-size 3584  \
    --ffn-hidden-size 18944 \
    --num-attention-heads 28  \
    --max-position-embeddings ${SEQ_LEN} \
    --seq-length ${SEQ_LEN} \
    --disable-bias-linear \
    --add-qkv-bias \
    --group-query-attention \
    --num-query-groups 4 \
    --use-flash-attn \
    --swiglu \
    --use-fused-swiglu \
    --normalization RMSNorm \
    --norm-epsilon 1e-6 \
    --use-fused-rmsnorm \
    --position-embedding-type rope \
    --rotary-base 1000000 \
    --use-fused-rotary-pos-emb \
    --untie-embeddings-and-output-weights \
    --micro-batch-size ${MBS} \
    --global-batch-size ${GBS} \
    --make-vocab-size-divisible-by 1 \
    --padded-vocab-size 152064 \
    --tokenizer-type PretrainedFromHF \
    --tokenizer-name-or-path ${TOKENIZER_PATH} \
    --attention-dropout 0.0 \
    --hidden-dropout 0.0 \
    --train-iters ${TRAIN_ITERS} \
    --lr 1.0e-5 \
    --lr-decay-style cosine \
    --lr-warmup-fraction 0.1 \
    --init-method-std 0.01 \
    --weight-decay 0.0 \
    --clip-grad 1.0 \
    --adam-beta1 0.9 \
    --adam-beta2 0.999 \
    --initial-loss-scale 4096 \
    --no-gradient-accumulation-fusion \
    --no-masked-softmax-fusion \
    --attention-softmax-in-fp32 \
    --bf16 \
    --tensorboard-dir $tensorboard_dir \
"

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

CKPT_ARGS="
    --no-load-optim \
    --no-load-rng \
    --no-save-optim \
    --no-save-rng \
    --seed 1234 \
"

OUTPUT_ARGS="
    --log-interval 10 \
    --save-interval 1000 \
    --eval-interval 1000 \
    --eval-iters 0 \
    --log-throughput
"
echo "==========Start train=========="
torchrun $DISTRIBUTED_ARGS posttrain_gpt.py \
    $GPT_ARGS \
    $DATA_ARGS \
    $CKPT_ARGS \
    $OUTPUT_ARGS \
    $TUNE_ARGS \
    --load ${CKPT_LOAD_DIR} \
    --save ${CKPT_SAVE_DIR} \
    --distributed-backend nccl \
    | tee $train_log_path

5.1.2. 启动脚本

cd ***/MindSpeed-LLM
bash scripts/qwen25_7b_instruct/tune_qwen25_7b_full_ptd.sh

5.1.3. 测试结果

NPU设备上业务数据集评分结果:

image-20250804201437046

5.2. Lora微调

全参官方参考链接: LoRA 微调简介

5.2.1. 训练脚本

# 文件名称 scripts/qwen25_7b_instruct/tune_qwen25_7b_lora_ptd.sh
set -e
export CUDA_DEVICE_MAX_CONNECTIONS=1
source /usr/local/Ascend/ascend-toolkit/set_env.sh

NPUS_PER_NODE=2
MASTER_ADDR=localhost
MASTER_PORT=1902
NNODES=1
NODE_RANK=0
WORLD_SIZE=$(($NPUS_PER_NODE*$NNODES))

# please fill these path configurations
CKPT_LOAD_DIR="***/weights/weight_mg/qwen2.5_7b_instruct_mcore_tp2_pp1"
CKPT_SAVE_DIR="***/weights/ckpt_record/auto_train_test/qwen2.5_mcore_lora_tp2_pp1"
DATA_PATH="***"
TOKENIZER_PATH="***/weights/Qwen2.5-7B-Instruct"
tensorboard_dir="***/outputs/qwen2.5-7b/tensorboard_dir/full"
train_log_path="***/outputs/qwen2.5-7b/logs/tune_mcore_qwen25_7b_lora_tp2_pp1_train.log"

TP=2
PP=1
SEQ_LEN=2048
MBS=16
GBS=64
TRAIN_ITERS=785

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

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

GPT_ARGS="
    --use-mcore-models \
    --use-distributed-optimizer \
    --overlap-grad-reduce \
    --tensor-model-parallel-size ${TP} \
    --pipeline-model-parallel-size ${PP} \
    --num-layers 28 \
    --hidden-size 3584 \
    --ffn-hidden-size 18944 \
    --num-attention-heads 28 \
    --tokenizer-type PretrainedFromHF \
    --tokenizer-name-or-path ${TOKENIZER_PATH} \
    --seq-length ${SEQ_LEN} \
    --max-position-embeddings ${SEQ_LEN} \
    --micro-batch-size ${MBS} \
    --global-batch-size ${GBS} \
    --make-vocab-size-divisible-by 1 \
    --padded-vocab-size 152064 \
    --rotary-base 1000000 \
    --lr 1.0e-5 \
    --lr-warmup-fraction 0.1 \
    --train-iters ${TRAIN_ITERS} \
    --lr-decay-style cosine \
    --untie-embeddings-and-output-weights \
    --disable-bias-linear \
    --attention-dropout 0.0 \
    --init-method-std 0.02 \
    --hidden-dropout 0.0 \
    --position-embedding-type rope \
    --normalization RMSNorm \
    --swiglu \
    --use-flash-attn \
    --weight-decay 0.0 \
    --use-rotary-position-embeddings \
    --no-masked-softmax-fusion \
    --attention-softmax-in-fp32 \
    --clip-grad 1.0 \
    --adam-beta1 0.9 \
    --adam-beta2 0.999 \
    --add-qkv-bias \
    --initial-loss-scale 4096 \
    --no-gradient-accumulation-fusion \
    --bf16 \
    --group-query-attention \
    --num-query-groups 4 \
    --norm-epsilon 1e-06 \
    --use-fused-rmsnorm \
    --use-fused-swiglu \
    --use-fused-rotary-pos-emb \
    --tensorboard-dir $tensorboard_dir \
"

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

CKPT_ARGS="
    --no-load-optim \
    --no-load-rng \
    --no-save-optim \
    --no-save-rng \
    --seed 1234 \
"

OUTPUT_ARGS="
    --log-interval 10 \
    --save-interval 1000 \
    --eval-interval 1000 \
    --eval-iters 0 \
    --log-throughput
"

torchrun $DISTRIBUTED_ARGS posttrain_gpt.py \
    $GPT_ARGS \
    $DATA_ARGS \
    $CKPT_ARGS \
    $OUTPUT_ARGS \
    $TUNE_ARGS \
    --distributed-backend nccl \
    --load ${CKPT_LOAD_DIR} \
    --save ${CKPT_SAVE_DIR} \
    | tee $train_log_path

5.2.2. 启动脚本

cd ***/MindSpeed-LLM
bash scripts/qwen25_7b_instruct/tune_qwen25_7b_lora_ptd.sh

5.2.3. 测试结果

NPU设备上业务数据评分

image-20250805141548227

六、 MG权重转换HF格式

权重转换实现了 Megatron-LM 权重到 HuggingFace 格式的转换,支持多种并行策略(如张量并行、流水并行等)。转换过程中,模型的权重会被适配为 HuggingFace 的标准格式,确保可以在 HuggingFace 环境下继续进行训练和推理。

6.1. 全参微调

Megatron-LM权重转换到Huggingface格式参考链接

6.1.1. 转换脚本

# 文件名 scripts/qwen25_7b_instruct/ckpt_convert_qwen25_mcore2hf_4_full.sh
source /usr/local/Ascend/ascend-toolkit/set_env.sh
python convert_ckpt.py \
    --model-type GPT \
    --load-model-type mg \
    --save-model-type hf \
    --model-type-hf llama2 \
    --use-mcore-models \
    --add-qkv-bias \
    --load-dir ***/weights/ckpt_record/auto_train_test/qwen2.5_mcore_full_tp4_pp2 \
    --target-tensor-parallel-size 1 \
    --target-pipeline-parallel-size 1 \
    --save-dir ***/weights/Qwen2.5-7B-Instruct  # <-- 需要填入原始HF模型路径,新权重会存于 ***/weights/Qwen2.5-7B-Instruct/mg2hf/

mv ***/weights/Qwen2.5-7B-Instruct/mg2hf/ $mg2hf_path

6.1.2. 执行命令

cd ***/MindSpeed-LLM
bash scripts/qwen25_7b_instruct/ckpt_convert_qwen25_mcore2hf_4_full.sh

6.1.3. 测试结果

GPU精度基线:93.20%,当前评分:93.9%。

image-20250808111653418

6.2. Lora微调

lora权重转换参考链接

注意:

  • Lora在权重转换前,需要将Config.json中的数据类型改为float16,推理时采用fp16加载,否则会有精度误差。

    image-20250804161221172

6.2.1. 转换脚本

# 文件名 scripts/qwen25_7b_instruct/ckpt_convert_qwen25_mcore2hf_lora.sh
source /usr/local/Ascend/ascend-toolkit/set_env.sh

python convert_ckpt.py \
    --model-type GPT \
    --use-mcore-models \
    --load-model-type mg \
    --save-model-type hf \
    --load-dir /***/weights/weight_mg/qwen2.5_7b_instruct_mcore_tp2_pp1 \
    --lora-load ***/weights/ckpt_record/auto_train_test/qwen2.5_mcore_lora_tp2_pp1 \
    --lora-r 16 \
    --lora-alpha 32 \
    --lora-target-modules linear_qkv linear_proj linear_fc1 linear_fc2 \
    --target-tensor-parallel-size 1 \
    --target-pipeline-parallel-size 1 \
    --add-qkv-bias \
    --save-dir ***/weights/Qwen2.5-7B-Instruct  # <-- 需要填入原始HF模型路径,新权重会存于 ***/weights/Qwen2.5-7B-Instruct/mg2hf/
    
mg2hf_path="***/hw/weights/ckpt_record/mg2hf/Qwen25_7B_Instruct_mcore2hf"
[ -d $mg2hf_path ] && rm -r $mg2hf_path
mv /apps/shared_storage/hw_test/hw/weights/Qwen2.5-7B-Instruct/mg2hf $mg2hf_path

6.2.2. 执行命令

cd /***/MindSpeed-LLM
bash scripts/qwen25_7b_instruct/ckpt_convert_qwen25_mcore2hf_lora.sh

6.2.3. 测试结果

GPU精度基线:88.70%,当前评分:88.8%。

image-20250808111805264

6.3. 评测结果总结

由下表的测试结果可知,在业务数据集上,当前全参微调和Lora微调均获得较好的评分,相比基线评分都有所提升。

微调方式GPU精度基线NPU评分NPU误差GPU评分GPU误差
全参微调93.20%93.90%+0.70%93.90%+0.70%
Lora微调88.70%88.80%+0.10%88.80%+0.10%