Load Diffusion Model (Ascend INT8)
The INT8 loader that earns Ascend's 8-bit bragging rights — or quietly fakes it
- model
- report
Here's the thing about Ascend NPUs: their INT8 throughput is roughly four times their FP16 throughput. That's the whole reason this pack exists - on a Huawei Atlas card, an INT8 diffusion model isn't a compromise you make to fit VRAM, it's the fast way to run. Load Diffusion Model (Ascend INT8) is the node that converts eligible Linear weights to int8 while the model loads from models/diffusion_models, then hands ComfyUI a model whose matmuls can run on the NPU's native 8-bit path.
This is the standalone-diffusion-model sibling of the pack's checkpoint loader. You pick a .safetensors from models/diffusion_models, and it goes through comfy.sd.load_diffusion_model with the pack's custom operations swapped in - which is how the pack replaces every Linear layer with its own INT8-aware version. At load time, each eligible layer's weight is transposed, scaled per output channel (max-abs / 127), rounded and clamped to int8, and stored as an int8 tensor plus a float32 scale. The bias stays as a frozen parameter. Then at forward time it branches on your backend choice.
The inputs that actually matter, in order of "you will touch this":
backend- three modes:auto_torch_npu_with_fallback(default) tries the realtorch_npu.npu_weight_quant_batchmatmuland silently dequantizes on any failure;torch_npu_strictraises if the op is missing, the input isn't onnpu, or the op fails - use it for FaaS validation;fallback_dequant_onlynever touches torch_npu, useful for local NVIDIA smoke tests.scale_mode-per_channel(default) stores one scale per output channel for better accuracy;per_tensoruses a single scale for the whole layer, slightly cheaper and slightly worse.include_regex/exclude_regex/min_in_features/min_out_features- the layer filter. Defaults match everything (.*) and skip any layer under 16×16 features. Regexes are for when you want to quantize only the attention blocks and leave the rest alone.
One output is a normal model (MODEL) that feeds your sampler pipeline exactly like any loader. The second output, report, is a STRING with the load-time stats: linear_seen vs linear_quantized vs linear_skipped, original vs int8+scale byte counts, a rough weight ratio, and full lists of which layers got quantized and why the rest were skipped. That report is your proof the quantization actually happened - check it before you trust a run.
Install is the standard dance: ComfyUI Manager (search "ComfyUI-Ascend-Int8-Test") or
cd ComfyUI/custom_nodes
git clone https://github.com/Aucannot/ComfyUI-Ascend-Int8-Test
then restart. No requirements.txt, no model downloads - just ComfyUI core, plus torch_npu (and Huawei's CANN runtime) if you want the real INT8 path instead of the fallback.
Where people get burned: this is a validation plugin, not a production quantizer - the README says so outright. Only Linear layers are quantized (no conv2d, no attention projections that ComfyUI implements otherwise), quantization happens online at load time so peak memory is not optimal, and any LoRA or weight patch forces the layer back to dequantized math for correctness. So the realistic workflow is: smoke-test on fallback_dequant_only, validate on torch_npu_strict, and treat the report output as the thing you actually ship to whoever owns the deployment.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| unet_name | COMBO | 0 options: | |
| backend | COMBO | auto_torch_npu_with_fallback | 3 options: auto_torch_npu_with_fallback, torch_npu_strict, fallback_dequant_only |
| scale_mode | COMBO | per_channel | 2 options: per_channel, per_tensor |
| include_regex | STRING | .* | — |
| exclude_regex | STRING | — | |
| min_in_features | INT | 161–65536 | — |
| min_out_features | INT | 161–65536 | — |
| reset_runtime_stats | BOOLEAN | true | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| model | MODEL | — |
| report | STRING | — |