mirror of
https://github.com/Comfy-Org/comfy-kitchen.git
synced 2026-11-04 23:37:42 +00:00
[GH-ISSUE #101] Feature Request: Direct int8 Q/K passthrough between Comfy Kitchen and SageAttention #32
Labels
No labels
pull-request
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
Comfy-Org/comfy-kitchen#32
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @LuXuxue on GitHub (Aug 9, 2026).
Original GitHub issue: https://github.com/Comfy-Org/comfy-kitchen/issues/101
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_int8kernels. Thefp16 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.
2. Motivation
2.1 The fp16 round-trip is redundant
Comfy Kitchen's
int8_linear(all backends) works as:SageAttention's int8 path (
qk_int8_pv_fp16) then does, on the fp16activations:
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):
The quantization stage (
mean_seq+quant_qk_int8) costs 3–14% of totalattention time, with the biggest share on head_dim=128 (Anima-class) cases
(6.5–13.8%). The d128
quant_qk_int8kernel runs ~3.6× slower than itsbandwidth 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):
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_scaleand 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_qkentry):SageAttention's
MIN_BLK_Q/MIN_BLK_K) instead of per-row / per-tensor.q_int8,k_int8,q_scale,k_scale(float32), matchingSageAttention's input contract.
q_scalecarriessm_scale(SageAttention foldssm_scale·log2einto theQ scale); smooth_k (
k − k_mean) can be kept as an optional flag.3.2 SageAttention side
Expose the existing low-level entry points as public API:
forward(q, k, v, q_scale, k_scale, ...)— wrap it as e.g.sageattn_from_qk_int8(q8, k8, v, q_scale, k_scale, ...).qk_int8_sv_bf16_attn_t(q8, k8, v, o, q_scale, k_scale, ...)— same wrapper.mean_seq+quant_qk_int8entirely.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
mean_seq+quant_qk_int8(+ possiblyv.to)Caveats:
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.
benefit most; very short cross-attention (kv ≤ 1024, fp16 direct path) is
unaffected.
5. Backend compatibility analysis
5.1 Comfy Kitchen backends
eagercuda_int_mm/ native kernelstritonhipAll four already implement
int8_linear(capability matrix in README). Aper-block quantize epilogue is a small, backend-local addition — the scale
layout contract is the only cross-backend interface needed.
5.2 SageAttention backends
forward(..., q_scale, k_scale, ...)existssageattention-rdna3)qk_int8_sv_bf16_attn_texists5.3 Compatibility matrix for the proposal
The key design choice: the integration contract is the data layout
(int8 Q/K + per-block float32 scales), not a kernel ABI.
@0xDELUXA commented on GitHub (Aug 11, 2026):
Don’t open issues when the HIP side of comfy-kitchen’s int8 attention hasn’t even been merged yet.
@0xDELUXA commented on GitHub (Aug 11, 2026):
Beyond timing, there is a structural problem with this as specified.
The diagram assumes
int8 GEMM -> attention, but for every modern DiT the real path isint8 GEMM -> fp16 -> RMSNorm + RoPE -> attention. That is why comfy-kitchen ships nine rope variants (apply_rope, rms_rope, rms_rope_split_half, ...). RoPE rotates channel pairs, so it cannot run on int8 with block scales without dequantizing, which is the round trip this asks to remove. The fp16 intermediate is loadbearing, not redundant.
The benefit also lands on the wrong side of that: the largest wins listed are the d128 long sequence Anima cases, which are RoPE models. The cases where passthrough could work (UNet cross attention with no RoPE on Q/K) are the ones measured at 3-6%.
"The contract is the data layout" also does not hold. The CUDA and HIP backends already use different scale layouts on purpose: the HIP one is per query row and per 16 keys because it follows RDNA's WMMA fragment layout, which is not m16n8k16. One shared layout would force a backend onto foreign fragment geometry and give back what it is trying to win.
Note also that
mean_seqis already gone: upstream removedsmooth_k, and--use-ck-attentionroutes to comfy-kitchen's own kernel, which quantizes once internally.