最近重新部署了一套 ComfyUI 0.30.2 环境,用于在 Ascend 910B3 上运行 MiniMax-H3 INT8。由于重新创建了 Python 虚拟环境,之前针对 Ascend 做过的部分适配被覆盖,重新踩了一遍几个比较典型的问题。

最终主要解决了三个问题:

  1. MiniMax-H3 文本编码器加载卡死
  2. ComfyUI 错误进入 NVIDIA CUDA 判断逻辑
  3. INT8 矩阵乘法回退 CPU

最终 MiniMax-H3 可以正常加载并使用 Ascend NPU 执行 INT8 计算。

环境

Ascend 910B3
CANN 9.1.0-beta.1

Python 3.13.14
PyTorch 2.12.0+cu130
torch_npu 2.12.0

ComfyUI 0.30.2
comfy-kitchen 0.2.26

启动后 ComfyUI 可以正常识别 NPU:

Total VRAM 62420 MB
pytorch version: 2.12.0+cu130
Device: npu
Using pytorch attention

1. MiniMaxH3TEModel 加载一直卡住

执行工作流后日志停在:

Requested to load MiniMaxH3TEModel_

NPUCachingAllocator.cpp:
The current CANN and Soc versions require processing
for 32 padding size, with memory allocation.

之后没有模型加载进度。

一开始看起来像模型加载很慢,但进一步观察进程发现:

CPU system 使用率约 100%
minflt/s 超过 30 万
磁盘读取 0 KB/s
RSS 基本不变化
NPU 显存基本不变化

这说明并不是正常读取模型,而是进程大量消耗在内核态的 page fault / mmap 处理上。

最终解决方法是在 ComfyUI 启动参数中加入:

--disable-mmap

例如:

ASCEND_RT_VISIBLE_DEVICES=6 \
PYTORCH_NPU_ALLOC_CONF=expandable_segments:True \
python main.py \
    --listen 0.0.0.0 \
    --disable-smart-memory \
    --disable-mmap

加入之后文本编码器可以正常加载:

Requested to load MiniMaxH3TEModel_

loaded completely;
60846.53 MB usable,
25883.83 MB loaded,
full load: True

所以在当前这套 Ascend + ComfyUI 0.30.2 环境中,我最终保留了 --disable-mmap


2. ComfyUI 错误调用 torch.cuda

文本编码器解决以后,又遇到了:

RuntimeError:
Found no NVIDIA driver on your system.

调用栈最终是:

comfy.ops.pick_operations()

supports_fp8_compute()

torch.cuda.get_device_properties(device)

torch._C._cuda_init()

问题在于当前 PyTorch 是:

2.12.0+cu130

因此:

torch.version.cuda

是有值的。

但这台机器实际运行设备是:

torch.npu.is_available() == True
torch.cuda.is_available() == False

也就是说:

PyTorch 编译信息带 CUDA
≠
当前设备就是 NVIDIA GPU

ComfyUI 的部分设备判断因此错误进入了 CUDA 专属逻辑。

修复 is_nvidia

修改:

comfy/model_management.py

将 NVIDIA 判断增加 Ascend 和 CUDA availability 检查:

def is_nvidia():
    global cpu_state

    if cpu_state != CPUState.GPU:
        return False

    if is_ascend_npu():
        return False

    if torch.version.cuda and torch.cuda.is_available():
        return True

    return False

同时给 supports_fp8_compute() 增加设备保护:

if device is None:
    device = get_torch_device()

if getattr(device, "type", None) != "cuda":
    return False

这样 NPU 就不会再执行:

torch.cuda.get_device_properties()

处理后 MiniMax-H3 diffusion model 可以正常加载。


3. INT8 计算回退 CPU

模型加载成功后开始采样:

0%| | 0/20

但出现:

The operator 'aten::_int_mm'
is not currently supported on the NPU backend
and will fall back to run on the CPU.

这个问题对性能影响很大。

原因是 comfy-kitchen 的 eager INT8 路径最终使用:

torch._int_mm()

而当前 torch_npu 没有为:

aten::_int_mm

提供对应的 NPU 实现,因此自动 fallback 到 CPU。

对于 MiniMax-H3 这种大量使用 INT8 Linear 的模型,CPU fallback 会直接导致采样速度大幅下降。


4. 使用 Ascend 原生 npu_quant_matmul

Ascend 本身提供了:

torch_npu.npu_dynamic_quant

以及:

torch_npu.npu_quant_matmul

因此可以直接修改:

comfy_kitchen/backends/eager/quantization.py

int8_linear() 中增加 NPU 分支。

核心逻辑:

if x.device.type == "npu":
    import torch_npu

    x_2d = x.reshape(-1, x.shape[-1]).contiguous()

    x_8, x_scale = torch_npu.npu_dynamic_quant(x_2d)

    x_scale = (
        x_scale.reshape(-1)
        .to(device=x.device, dtype=torch.float32)
        .contiguous()
    )

    result = torch_npu.npu_quant_matmul(
        x_8.contiguous(),
        weight.T.contiguous(),
        weight_scale.reshape(-1)
            .to(device=x.device, dtype=torch.float32)
            .contiguous(),
        pertoken_scale=x_scale,
        output_dtype=out_dtype,
    )

其他设备继续保留原来的:

_int8_matmul_accumulate()

路径即可。


5. 一个容易踩的点:不要重复执行 scale

原来的 torch._int_mm 路径通常是:

INT8 MatMul
→ INT32
→ activation scale
→ weight scale
→ BF16 / FP16

但是:

torch_npu.npu_quant_matmul()

调用时已经传入:

weight_scale

以及:

pertoken_scale=x_scale

所以 NPU 分支执行完成后,不能再执行原来那段手工 scale:

result * x_scale * weight_scale

否则会重复缩放,导致结果错误。

因此代码结构应该明确分开:

if device == "npu":
    # npu_quant_matmul
    # 不再手动 scale

else:
    # 原 comfy-kitchen 路径
    # 保留手动 scale

6. 验证 Ascend INT8 算子

可以先单独验证:

import torch
import torch_npu

device = "npu:0"

x = torch.randn(
    128,
    2048,
    dtype=torch.bfloat16,
    device=device
)

w = torch.randint(
    -127,
    128,
    (2048, 2048),
    dtype=torch.int8,
    device=device
)

weight_scale = torch.ones(
    2048,
    dtype=torch.float32,
    device=device
) * 0.01

x8, x_scale = torch_npu.npu_dynamic_quant(x)

y = torch_npu.npu_quant_matmul(
    x8.contiguous(),
    w.T.contiguous(),
    weight_scale.contiguous(),
    pertoken_scale=x_scale.reshape(-1).float().contiguous(),
    output_dtype=torch.bfloat16,
)

print(y.shape)
print(y.dtype)
print(y.device)

正常输出:

torch.Size([128, 2048])
torch.bfloat16
npu:0

说明 INT8 GEMM 已经真正运行在 NPU 上。


最终启动参数

目前我使用:

ASCEND_RT_VISIBLE_DEVICES=6 \
PYTORCH_NPU_ALLOC_CONF=expandable_segments:True \
python main.py \
    --listen 0.0.0.0 \
    --disable-smart-memory \
    --disable-mmap

正常加载后日志类似:

Requested to load MiniMaxH3TEModel_

loaded completely;
25883.83 MB loaded

Detected mixed precision quantization

loaded completely;
19996.14 MB loaded

并且采样时不再出现:

aten::_int_mm
will fall back to run on the CPU

总结

这次 ComfyUI 0.30.2 + MiniMax-H3 在 Ascend 910B3 上主要涉及三类兼容性问题:

模型 mmap
    ↓
--disable-mmap

CUDA / NPU 设备判断
    ↓
避免 NPU 调用 torch.cuda.*

INT8 Linear
    ↓
torch._int_mm
    ↓
CPU fallback
    ↓
npu_dynamic_quant
+
npu_quant_matmul

最终实际运行链路变成:

MiniMax-H3 INT8 Weight
        ↓
ComfyUI
        ↓
comfy-kitchen
        ↓
npu_dynamic_quant
        ↓
npu_quant_matmul
        ↓
Ascend 910B3

还有一个值得注意的问题:

comfy-kitchen 的修改位于 Python 虚拟环境:

.venv/lib/python3.13/site-packages/

因此重新创建虚拟环境或者升级 comfy-kitchen 后,这部分 NPU 适配会被覆盖。

最终文生图速度:
默认文生图工作流:
时长:5秒
清晰度:| 0.4 | 16:9 | 864 x 480 |
步长:20
运行时长(第二次):[INFO] Prompt executed in 161.81 seconds
工作流模型配置如下:
在这里插入图片描述

Logo

鲲鹏昇腾开发者社区是面向全社会开放的“联接全球计算开发者,聚合华为+生态”的社区,内容涵盖鲲鹏、昇腾资源,帮助开发者快速获取所需的知识、经验、软件、工具、算力,支撑开发者易学、好用、成功,成为核心开发者。

更多推荐