Quick Start (Ascend NPU)

在单卡昇腾 NPU 上对 Qwen2.5-3B-Instruct 应用 LoRA、保存并重新加载 PEFT 适配器。

前置条件

硬件

Atlas 900 A2 / A3 训练系列产品或者 Ascend 950 系列产品,并按需完成物理机或容器内的设备挂载。

基础软件

在跑本文档之前,你的机器上需要已经装好并可用:

  • 可用的 Python 环境

  • 可用的 CANN(参考快速安装昇腾环境

  • 与上面 CANN 匹配的 torch + torch_npu,且 torch 能正常 importtorch.npu.is_available() == True(参考 Ascend PyTorch 安装文档,按 torch ↔ torch_npu ↔ CANN 三方兼容矩阵选择版本)

完整 NPU 适配(DDP/DeepSpeed、MindSpeed 等)请参考上游 ms-swift NPU 最佳实践文档

本文档示例使用的版本

配套机器

  • 机器类型:Atlas 900 A2 PODc(Ascend 910B4,64 GB × 1)

  • 操作系统:Ubuntu 22.04

配套镜像

swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:9.1.0-910b-ubuntu22.04-py3.12

软件版本

组件

版本

Python

3.12

CANN

9.1.0

torch

2.9.0+cpu

torch_npu

2.9.0.post2

transformers

<5.0

peft

最新 release 的源码/二进制

modelscope

1.37.0

模型

Qwen/Qwen2.5-3B-Instruct

前置安装

确认能看到 NPU 设备:

npu-smi info

输出类似:

+------------------------------------------------------------------------------------------------+
| npu-smi 25.5.2                   Version: 25.5.2                                               |
+---------------------------+---------------+----------------------------------------------------+
| NPU   Name                | Health        | Power(W)    Temp(C)           Hugepages-Usage(page)|
| Chip                      | Bus-Id        | AICore(%)   Memory-Usage(MB)  HBM-Usage(MB)        |
+===========================+===============+====================================================+
| 5     910B4               | OK            | 89.9        39                0    / 0             |
| 0                         | 0000:41:00.0  | 0           0    / 0          2922 / 32768         |
+===========================+===============+====================================================+
+---------------------------+---------------+----------------------------------------------------+
| NPU     Chip              | Process id    | Process name             | Process memory(MB)      |
+===========================+===============+====================================================+
| No running processes found in NPU 5                                                            |
+===========================+===============+====================================================+

如果 npu-smi 不存在,请回到 Ascend 官方快速安装指南 补装驱动

检查 Python 版本:

python --version

输出结果如下:

Python 3.12.xxx

检查 NPU 设备运行时可用:

python -c "import torch, torch_npu; print(f'torch={torch.__version__}'); print(f'torch_npu={torch_npu.__version__}'); print('is_available:', torch.npu.is_available()); print('count:', torch.npu.device_count())"

输出结果如下:

torch=2.9.0+cpu
torch_npu=2.9.0.post2
is_available: True
count: 1

如果 import torch_npu 失败,回到 Ascend PyTorch 安装文档 检查 torch / torch_npu / CANN 三方兼容矩阵。

安装 transformers / modelscope:

pip install 'transformers<5.0' 'modelscope==1.37.0'

打印安装版本:

python -c "import transformers, modelscope; print(f'transformers={transformers.__version__} modelscope={modelscope.__version__}')"

输出结果如下:

transformers=xxx modelscope=1.37.0

安装 PEFT

使用 uv 进行安装

uv pip install --index-url https://mirrors.aliyun.com/pypi/simple peft
python -c "import peft; print('peft', peft.__version__)"

输出结果类似如下:

peft xxx
  • xxx 表示最新的版本号

从源码安装

克隆上游仓库并 checkout 到工作流注入的最新 release tag,安装并且验证

git clone --depth 1 --branch <ref> https://github.com/huggingface/peft.git
cd peft
uv pip install -e .
python -c "import peft; print('peft', peft.__version__)"

<ref> 为安装的最新的 release 分支

输出结果类似如下:

peft xxx
  • xxx 表示最新的版本号

使用 PEFT 方法(例如 LoRA)准备训练模型

将基础模型和 PEFT 配置包装起来 get_peft_model,并保存适配器。对于 Qwen2.5-3B-Instruct 这种 3B 模型,仅训练约 0.12% 的参数!

下载基础模型

默认使用 ModelScope 进行模型下载。

python -c "from modelscope import snapshot_download; print(snapshot_download('Qwen/Qwen2.5-3B-Instruct'))" | tail -n 1

应用 LoRA 适配器

把基础模型加载到 NPU 上(bfloat16 省显存),构造 LoraConfig 描述要插入的 LoRA 矩阵(rank=16 / alpha=32 / 自回归 LM 任务),再用 get_peft_model 包成 PEFT 模型——底座权重默认冻结,只有新注入的 LoRA 矩阵参与训练。

python << 'PY'
import torch
from transformers import AutoModelForCausalLM
from peft import LoraConfig, TaskType, get_peft_model

model = AutoModelForCausalLM.from_pretrained(
    "<model_path>", torch_dtype=torch.bfloat16,
).to("npu:0")

peft_config = LoraConfig(
    r=16,
    lora_alpha=32,
    task_type=TaskType.CAUSAL_LM,
)
peft_model = get_peft_model(model, peft_config)
peft_model.print_trainable_parameters()
peft_model.save_pretrained("output/peft-adapter")
PY
ls output/peft-adapter/adapter_config.json output/peft-adapter/adapter_model.safetensors

<model_path> 为上面“下载基础模型” 章节对应命令的输出

输出结果如下:

trainable params: xxx || all params: xxx || trainable%: xxx
output/peft-adapter/adapter_config.json
output/peft-adapter/adapter_model.safetensors

加载用于推理的 PEFT 模型

推理的入口。PEFT 把「底座」与「适配器」解耦得很干净——同一份底座可以快速切换不同任务的适配器,无需拷贝整个模型。本节演示:先加载底座(与训练同源),再把上一步保存的 LoRA 适配器「贴」上去,最后用 generate() 端到端跑一次生成验证链路通。

加载 PEFT 模型

推理的第一步:加载 tokenizer + 底座(AutoModelForCausalLM),然后用 PeftModel.from_pretrained(base, "output/peft-adapter") 把适配器「贴」上去——这一步在底座上原地构造 PEFT 包装,权重来自上一步保存的目录。

python << 'PY'
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

base = AutoModelForCausalLM.from_pretrained(
    "<model_path>", torch_dtype=torch.bfloat16,
).to("npu:0")
tokenizer = AutoTokenizer.from_pretrained("<model_path>")
peft_model = PeftModel.from_pretrained(base, "output/peft-adapter")
peft_model.print_trainable_parameters()
PY

输出结果如下:

trainable params: xxx || all params: xxx || trainable%: xxx...

这里的 <model_path> 和上面 apply-lora 块里的一样,由「下载基础模型」一节的 #test-setup store="model_path" 捕获并注入;不需要在本块手动替换。

跑一次生成验证

端到端跑一次生成:tokenizer 把 prompt 编码成 ids,搬到 NPU 上,model.generate(max_new_tokens=20, do_sample=False) 续写 20 个 token,解码回文本。PEFT 模型继承 PreTrainedModel 接口,generate 调用方式与底座完全一致。

python << 'PY'
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
from peft import PeftModel

base = AutoModelForCausalLM.from_pretrained(
    "<model_path>", torch_dtype=torch.bfloat16,
).to("npu:0")
tokenizer = AutoTokenizer.from_pretrained("<model_path>")
peft_model = PeftModel.from_pretrained(base, "output/peft-adapter")

inputs = tokenizer("Preheat the oven to 350 degrees and place the cookie dough", return_tensors="pt").to("npu:0")
outputs = peft_model.generate(**inputs, max_new_tokens=20, do_sample=False)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))
PY

输出结果如下:

Preheat the oven to 350 degrees and place the cookie doughxxx

小贴士:

  • 如果要切换其他 PEFT 方法(如 AdaLoRA、IA3、VeRA 等),只需要把 LoraConfig 换成对应方法的 config 即可,调用方式保持不变。

  • target_modules 接受字符串列表、模块类或正则;不指定时,PEFT 会自动对所有 nn.Linear 子模块注入 LoRA。

  • task_type 用来辅助 PEFT 保存与任务相关的层;自回归 LM 任务填 TaskType.CAUSAL_LM,分类任务填 TaskType.SEQ_CLS

  • 推理段 prompt 选的是英文烘焙场景:base 模型未针对该任务训练,生成内容是 base 的自然续写,验证 PeftModel.from_pretrained 链路可用即可。