Skip to content

Feature Request: Direct int8 Q/K passthrough between Comfy Kitchen and SageAttention #101

Description

@LuXuxue

1. Summary

When an int8-quantized model is served in ComfyUI (weights quantized by
Comfy Kitchen), the Q/K/V projections emit fp16 activations even though the
GEMM itself ran in int8 (int32 accumulator). SageAttention then re-quantizes
Q and K back to int8 with its own mean_seq + quant_qk_int8 kernels. The
fp16 round-trip is pure overhead: it costs two extra quantization passes
(precision loss), two extra kernel launches and full-size fp16 tensor
read/writes on a memory-bandwidth-limited iGPU.

This request is to add a direct int8 Q/K passthrough: Comfy Kitchen's
int8 GEMM optionally emits per-block-int8 Q/K + scale in the exact layout
SageAttention already consumes, and SageAttention exposes the low-level
"external int8 Q/K + scale" entry point it already has internally as a
first-class API. The fp16 intermediate disappears entirely.

Current:  int8 GEMM ──dequant──▶ fp16 Q/K ──mean+quant──▶ int8 Q/K + scale ──▶ int8 attn
Proposed: int8 GEMM ──block-quant──▶ int8 Q/K + scale ───────────────────────▶ int8 attn

2. Motivation

2.1 The fp16 round-trip is redundant

Comfy Kitchen's int8_linear (all backends) works as:

x (fp16) → rowwise int8 quant → int8 GEMM (WMMA i8×i8→i32)
         → int32 result × (x_scale × w_scale) → fp16 output

SageAttention's int8 path (qk_int8_pv_fp16) then does, on the fp16
activations:

mean_seq(k)      → k_mean (smooth_k)
quant_qk_int8    → per-block int8 Q/K + q_scale/k_scale
qk_int8_sv_bf16_attn → int8 QK WMMA + fp16 PV

The Q/K int8 representation that SageAttention wants is exactly the
representation the GEMM already produced internally (before dequantization).
Nothing is gained by materializing fp16 in between; both precision and
bandwidth are lost.

2.2 Measured cost of the quantization stage

Measured on AMD Radeon 780M (gfx1103, 12 CU), ROCm 7.14, torch 2.12,
SageAttention RDNA3 HIP-native backend, all int8-path self-attention cases in

benchmark_attn.py

(full pipeline vs. per-stage, same-process, warmed up):

Case dtype head_dim seq full (ms) mean_seq quant_qk_int8 Q/K quant total
Anima01 bf16 128 4096 18.17 1.4% 12.4% 13.8%
Anima03 bf16 128 6144 38.35 1.0% 8.5% 9.5%
Anima05 bf16 128 9216 82.68 0.7% 5.8% 6.5%
SDXL01 fp16 64 4096 5.24 1.3% 5.1% 6.4%
SDXL07 fp16 64 6144 11.54 0.9% 3.3% 4.2%
SDXL13 fp16 64 9216 24.73 0.7% 2.3% 3.0%

The quantization stage (mean_seq + quant_qk_int8) costs 3–14% of total
attention time
, with the biggest share on head_dim=128 (Anima-class) cases
(6.5–13.8%). The d128 quant_qk_int8 kernel runs ~3.6× slower than its
bandwidth roofline, i.e. there is no cleverness to keep here — the whole stage
is best skipped.

Additional bandwidth (per inference step, Anima01 shape: b=1, h=16, s=4096,
d=128):

Tensor current (fp16 round-trip) proposed (int8 passthrough) saved
Q write (GEMM out) 16 MB fp16 8 MB int8 8 MB
K write (GEMM out) 16 MB fp16 8 MB int8 8 MB
Q read (quant) 16 MB 16 MB
K read (mean+quant) 32 MB 32 MB
int8 Q/K write 16 MB 16 MB (same) 0
Total per step 96 MB 32 MB 64 MB (~67%)

2.3 Precision

The current chain quantizes Q/K twice (fp16 intermediate is only 11-bit
mantissa and truncates the int32 result; then int8 re-quantization). A direct
int32→int8 block quantization is a single rounding step and is strictly
less lossy. (Optionally fused with sm_scale and smooth_k semantics.)


3. Proposed change

3.1 Comfy Kitchen side

Add an "int8 output mode" to the int8 GEMM path (or a separate
int8_linear_qk entry):

  • int32 accumulator is quantized per block (Q: 32 rows, K: 16 rows —
    SageAttention's MIN_BLK_Q / MIN_BLK_K) instead of per-row / per-tensor.
  • Outputs: q_int8, k_int8, q_scale, k_scale (float32), matching
    SageAttention's input contract.
  • q_scale carries sm_scale (SageAttention folds sm_scale·log2e into the
    Q scale); smooth_k (k − k_mean) can be kept as an optional flag.
  • V stays fp16/bf16 (see §5).

3.2 SageAttention side

Expose the existing low-level entry points as public API:

  • Triton path already accepts external int8 via forward(q, k, v, q_scale, k_scale, ...) — wrap it as e.g. sageattn_from_qk_int8(q8, k8, v, q_scale, k_scale, ...).
  • HIP-native path already has qk_int8_sv_bf16_attn_t(q8, k8, v, o, q_scale, k_scale, ...) — same wrapper.
  • The wrapper skips mean_seq + quant_qk_int8 entirely.

3.3 ComfyUI glue

A thin model-patch that, for quantized backbones, routes Q/K projection
outputs through the int8-output GEMM and feeds them to the SageAttention
wrapper. No changes to the attention kernel math.


4. Estimated benefit

Metric Estimate Basis
Attention time saving 3–14%, typical 6–10% measured per-case quant-stage share above
iGPU Q/K bandwidth ~67% reduction in Q/K traffic (64 MB/step saved on Anima01) bandwidth table above
Precision single-rounding int8 vs double-rounding fp16→int8 analysis
Kernel launches −2 (−3) per attention call mean_seq + quant_qk_int8 (+ possibly v.to)

Caveats:

  • The 3–14% is the upper bound (the stage that disappears). The int32→int8
    block quantization fused into the GEMM epilogue costs a small fraction of a
    standalone kernel, so net saving is close to the bound but slightly below.
  • Saving scales with seq length and head_dim: d128/long-seq (Anima-class)
    benefit most; very short cross-attention (kv ≤ 1024, fp16 direct path) is
    unaffected.

5. Backend compatibility analysis

5.1 Comfy Kitchen backends

Backend int8_linear Notes
eager pure-torch reference; block-quant epilogue is expressible in torch ops
cuda torch _int_mm / native kernels
triton Triton GEMM; scale semantics portable
hip WMMA GEMMs (RDNA3/3.5/4); RDNA2 falls back to triton/eager

All four already implement int8_linear (capability matrix in README). A
per-block quantize epilogue is a small, backend-local addition — the scale
layout contract is the only cross-backend interface needed.

5.2 SageAttention backends

Backend HW external int8 entry
Triton CUDA (official focus: RTX 4090/3090), also runs on ROCm forward(..., q_scale, k_scale, ...) exists
HIP native RDNA3 (gfx11xx) fork (sageattention-rdna3) qk_int8_sv_bf16_attn_t exists

5.3 Compatibility matrix for the proposal

Comfy Kitchen \ SageAttention Triton (CUDA) Triton (ROCm) HIP native (RDNA3)
eager ✅ protocol works
cuda
triton
hip ✅ (via protocol) ✅ direct

The key design choice: the integration contract is the data layout
(int8 Q/K + per-block float32 scales), not a kernel ABI.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions