昇腾910A适配Qwen3.5-27B推理参考 Transformers
收藏回复举报
昇腾910A适配Qwen3.5-27B推理参考 Transformers
发表于2026-06-16 16:36:08
0 查看

Qwen3.5-27B × Ascend 910A × Transformers 适配踩坑总结

环境:Qwen3.5-27B(含多模态 / Linear Attention 变体)/ Ascend 910A ×2 / Transformers + torch_npu / device_map 自动切分

Docker环境准备:

拉取CANN 910A镜像:https://www.hiascend.com/developer/ascendhub/detail/17da20d1c2b6493cb38765adeba85884

比如:

docker pull swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:8.3.rc1-910-ubuntu22.04-py3.11

Docker容器启动:

docker run -itd --privileged \
    --network host \
    --name cann_8.3.rc1 \
    --device /dev/davinci1 \
    --device /dev/davinci_manager \
    --device /dev/devmm_svm \
    --device /dev/hisi_hdc \
    -v /usr/local/dcmi:/usr/local/dcmi \
    -v /usr/local/bin/npu-smi:/usr/local/bin/npu-smi \
    -v /usr/local/Ascend/driver/lib64/:/usr/local/Ascend/driver/lib64/ \
    -v /usr/local/Ascend/driver/version.info:/usr/local/Ascend/driver/version.info \
    -v /etc/ascend_install.info:/etc/ascend_install.info \
    -v /mnt/sdc:/mnt/sdc \
swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:8.3.rc1-910-ubuntu22.04-py3.11 bash

进入容器:

docker exec -it cann_8.3.rc1 bash

更新transformers库到最新版本,安装torch(这里安装了torch2.8.0)

参考 https://www.hiascend.com/document/detail/zh/Pytorch/720/configandinstg/instg/insg_0004.html

# 下载软件包
wget https://download.pytorch.org/whl/cpu/torch-2.8.0%2Bcpu-cp311-cp311-manylinux_2_28_aarch64.whl
# 安装命令
pip3 install torch-2.8.0+cpu-cp311-cp311-manylinux_2_28_aarch64.whl

# 下载插件包
wget https://gitcode.com/Ascend/pytorch/releases/download/v7.2.0-pytorch2.8.0/torch_npu-2.8.0-cp311-cp311-manylinux_2_28_aarch64.whl
# 安装命令
pip3 install torch_npu-2.8.0-cp311-cp311-manylinux_2_28_aarch64.whl

# 更新transformers库
pip install transformers==5.11.0

设置环境变量至少需要2卡,export ASCEND_RT_VISIBLE_DEVICES=0,1,启动以下推理脚本即可:

问答推理:

import time
import threading

import torch
import torch_npu

from transformers import (
    AutoProcessor,
    Qwen3_5ForConditionalGeneration,
    TextIteratorStreamer,
)

# ====================================
# Ascend配置
# ====================================

torch.npu.set_compile_mode(jit_compile=False)

MODEL_PATH = "/mnt/sdc/modelscope/Qwen3.5-27B/"

print("Loading processor...")

processor = AutoProcessor.from_pretrained(
    MODEL_PATH,
    trust_remote_code=True
)

tokenizer = processor.tokenizer

print("Loading model...")

model = Qwen3_5ForConditionalGeneration.from_pretrained(
    MODEL_PATH,
    trust_remote_code=True,
    torch_dtype=torch.float16,
    device_map="auto",
    low_cpu_mem_usage=True,
    attn_implementation="eager",
)

model.eval()

print("Model loaded.")


# ====================================
# 输入
# ====================================

messages = [
    {"role": "system", "content": "你是一个乐于助人的助手。"},
    {"role": "user", "content": "介绍一下你自己。"}
]

prompt = tokenizer.apply_chat_template(
    messages,
    tokenize=False,
    add_generation_prompt=True
)

inputs = tokenizer(
    prompt,
    return_tensors="pt"
)

device = next(model.parameters()).device

inputs = {
    k: v.to(device)
    for k, v in inputs.items()
}

# ====================================
# Streamer
# ====================================

streamer = TextIteratorStreamer(
    tokenizer,
    skip_prompt=True,
    skip_special_tokens=True
)

generate_kwargs = dict(
    **inputs,

    streamer=streamer,

    max_new_tokens=512,

    do_sample=False,      # Ascend避开multinomial

    num_beams=1,

    use_cache=True,

    eos_token_id=tokenizer.eos_token_id,
    pad_token_id=tokenizer.eos_token_id,
)

print("\nAssistant:\n")

start_time = time.time()
first_token_time = None

generated_text = ""

thread = threading.Thread(
    target=model.generate,
    kwargs=generate_kwargs
)

thread.start()

for text in streamer:

    if first_token_time is None:
        first_token_time = time.time()

    print(text, end="", flush=True)

    generated_text += text

thread.join()

end_time = time.time()

print("\n")

# ====================================
# TPS统计
# ====================================

output_tokens = len(
    tokenizer.encode(
        generated_text,
        add_special_tokens=False
    )
)

total_time = end_time - start_time

if first_token_time:
    ttft = first_token_time - start_time
else:
    ttft = total_time

gen_time = max(end_time - first_token_time, 1e-6)

tps = output_tokens / gen_time

print("====================================")
print(f"Output Tokens : {output_tokens}")
print(f"TTFT          : {ttft:.3f} sec")
print(f"Generation    : {gen_time:.3f} sec")
print(f"Tokens/sec    : {tps:.2f}")
print("====================================")

运行问答:

python qwen3.5_inference.py

测试回答速度: 文本推理:约首字时延 4571 ms | 每秒 5 tokens 图片推理:首字时延 15812 ms | 每秒 4 tokens


坑一:模型加载类不匹配 → 大量 UNEXPECTED 权重警告

现象

加载时控制台输出大量 UNEXPECTED 权重警告,visual 模块和 mtp 模块未能正确建模,但仍参与初始化流程,不报错、不中断,极难察觉。

根因

使用了 AutoModelForCausalLM 加载一个 ConditionalGeneration(多模态)模型。两者的权重映射表不同,视觉编码器等模块被当作"意外权重"跳过。

解决方案

# ❌ 错误
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained(MODEL_PATH, ...)

# ✅ 正确
from transformers import Qwen3_5ForConditionalGeneration
model = Qwen3_5ForConditionalGeneration.from_pretrained(MODEL_PATH, ...)

坑二:bf16 在 910A 上部分算子不支持 → inplace 初始化报错

现象

模型加载阶段报错,错误涉及 uniform_ / A_log 等 inplace 随机初始化操作:

RuntimeError: "uniform_" not implemented for 'BFloat16' on NPU

根因

Ascend 910A 对 bfloat16 的支持不完整,部分 inplace 随机初始化算子(uniform_normal_ 等)在 bf16 精度下未实现。

解决方案

# ❌ 错误
model = ...from_pretrained(..., torch_dtype=torch.bfloat16)

# ✅ 正确:强制使用 float16
model = ...from_pretrained(..., torch_dtype=torch.float16)

坑三:Flash Linear Attention 依赖缺失 → 性能严重退化

现象

模型可以正常推理,但速度极慢(实测约 2.45 tokens/s),日志中出现 fallback 到纯 Torch 实现的提示。

根因

Qwen3.5 的 Linear Attention 变体依赖 flash-linear-attentioncausal-conv1d 两个库实现高效 kernel。这两个库底层基于 CUDA Triton 生态,Ascend 910A 无法使用,强制 fallback 到纯 Python/Torch 实现,性能损失极大。

影响

路径速度
flash-linear-attention(CUDA)正常水平
fallback Torch 实现(910A 当前状态)~2.45 tokens/s

结论

这是当前 910A 部署该模型最核心的性能瓶颈,属于生态缺失问题,无法通过调参解决,需等待 CANN 官方适配或 Ascend 专用 kernel 实现。


坑四:SDPA attention 维度不匹配 → shape mismatch 报错

现象

推理时报错:

RuntimeError: tensor shape mismatch (24 vs 4)

错误发生在 attention 计算阶段。

根因

Qwen3.5 使用 GQA(Grouped Query Attention),query heads 与 key/value heads 数量不同。sdpa(Scaled Dot-Product Attention)的实现在处理 GQA 时未正确适配 kv heads 的广播逻辑,导致维度对不上。

解决方案

model = ...from_pretrained(
    ...,
    attn_implementation="eager",   # 放弃 sdpa,回退到标准实现
)

坑五:multinomial 采样触发 AICPU 崩溃

现象

调用 model.generate() 时崩溃,错误信息:

RuntimeError: MultinomialWithReplacement is not supported on this device

或 AICPU 异常退出。

根因

do_sample=True 时 generate 内部调用 multinomial 随机采样 kernel,Ascend AICPU 对该 kernel 的支持不稳定,在某些输入形状下直接崩溃。

解决方案

outputs = model.generate(
    **inputs,
    do_sample=False,    # 关闭随机采样,改用贪心解码
    num_beams=1,        # 配合贪心,避免 beam search 相关算子
    ...
)

注意:关闭 do_sample 会使输出确定性更强,如需多样性可在应用层做多次调用变通。



本质结论

当前速度慢的问题不是单一调参问题,而是 Qwen3.5 模型需要的 Attention 融合算子 Ascend 910A系列产品 生态缺失的问题。

性能瓶颈主要来自 融合算子缺失 fallback到torch基本算子过慢 算力问题通过参数调整可以缓解,但 flash-linear-attention / causal-conv1d 的 Ascend 适配需等待官方支持。

希望昇腾官方MINDIE等支持910系列产品

问题类型可解决?
加载类错误坑一✅ 换正确的 class
bf16 算子缺失坑二✅ 改 float16
Linear Attn kernel 缺失坑三❌ 等官方适配
GQA 维度不匹配坑四✅ 用 eager
multinomial 采样崩溃坑五✅ 用贪心解码

本帖最后由 匿名用户2026/06/16 16:42:30 编辑

我要发帖子