융합 커널
융합 커널 (Fused Kernels)
이 페이지는 SGLang Diffusion이 제공하는 융합 CUDA/Triton 커널, 각 커널이 무엇을 대체하는지, 그리고 기본적으로 어떤 것들이 켜져 있는지 설명해요. 확산 트랜스포머와 VAE는 비-GEMM 시간의 상당 부분을 짧은 elementwise 및 selection 체인(adaLN modulate, residual gating, QK-norm, RoPE, norm epilogue, MoE 라우팅)에 쓸 수 있는데, eager PyTorch에서는 각각 여러 커널 실행과 HBM 왕복이 필요해요.
출처: 문서
본문
확산 트랜스포머와 VAE는 비-GEMM 시간의 상당 부분을 짧은 elementwise 및 selection 체인 — adaLN modulate, residual gating, QK-norm, RoPE, norm epilogue, MoE 라우팅 — 에 소비하며, eager PyTorch에서는 각각 여러 커널 실행과 HBM 왕복이 필요할 수 있어요. SGLang Diffusion은 이러한 체인을 sglang/kernels/ops/diffusion 아래의 융합 커널로 대체해요.
이 페이지는 인벤토리예요. 각 커널이 무엇을 융합하는지, 수치 계약(numerical contract)이 무엇인지, 어떤 모델이 사용하는지를 설명해요. 조절하는 레버가 아니며, 대부분의 커널은 기본적으로 켜져 있고 플래그가 필요 없어요. 유일한 스위치는 아래 설명하는 --quality예요.
수치 계약과 품질 등급 (Numerical contracts and quality tiers)
다단계 디노이징은 스텝별 반올림 차이를 보이는 품질 손실로 증폭하므로, "충분히 가까운(close enough)" 것과 "비트 정확(bit-exact)"한 것은 여기서 서로 다른 제품이에요. quality 스위치는 무조건적인 비트 정확 대체와 비-비트 정확한 eager-체인 융합을 구분해요:
비트 정확 — 무조건적으로 장착. 커널이 eager 체인의 모든 반올림 경계를 재현하므로 참조에 대해 torch.equal이 성립해요. 몇몇은 거기까지 가기 위해 꽤 멀리 나아가요: 융합 LayerNorm+modulate 커널은 PyTorch의 vectorized_layer_norm_kernel을 Welford 업데이트 순서, 가드된 역수, warp-fold 트리까지 재현해요. 융합 RMSNorm+scale/shift 커널은 FlashInfer의 CuTe-DSL RMSNormKernel 조각 순서와 shfl.bfly 폴드를 재현해요. 이들이 재현하는 디스패치가 그 아래에서 바뀔 수 있으므로 각 커널은 여전히 첫 만남에서 라이브 eager 체인에 대해 스스로 검증하고, 불일치가 있으면 영구적으로 폴백해요.
비트 정확 아님 — 요청 게이팅(request-gated). 이들은 반정밀도 반올림 순서 수준에서만 eager와 다르지만, 그것이 충분히 중요하므로 quality="extra-high" 및 quality="high" 요청에 대해서만, 배치 경계에서, 트랜스포머별로 전부 또는 전무(all-or-nothing) 방식으로 장착돼요. 기본 quality="lossless"는 수정되지 않은 참조 체인을 실행해요.
모델/체크포인트 네이티브. 일반 close-contract 커널, 희소 연산자, FP8/NVFP4 생성기는 모델 구현 또는 별도로 선택된 배포 경로의 일부일 수 있어요. 인벤토리에 문서화되지만 quality는 그 선택을 선택하거나 되돌리지 않아요.
선택 동등 라우팅 — 무조건 활성화. LingBot Video의 융합 group-limited top-k는 가드된 CUDA torch.topk(..., sorted=False) 참조 체인과 동일한 선택된 expert-id 집합을 반환해요. 해당 id의 순서는 두 경로의 계약 일부가 아니에요. 선택된 전문가가 변하지 않으므로 이 경로는 요청 quality 등급에 의존하지 않아요.
Note 일반 fp32 단일 패스 norm 융합은 무해해 보이지만 그렇지 않아요. ERNIE-Image에서 50스텝 궤적을 18.83 dB PSNR로 옮겼는데, 이것이 해당 경로의 비트 정확 재작성의 동기가 됐어요.
품질 레벨은 누적적이에요:
quality |
Included optimization set |
|---|---|
lossless |
선택된 배포의 참조 경로 + 모든 무조건적 비트 정확 대체 |
extra-high |
lossless의 모든 것 + 요청 게이팅된 DiT 및 VAE 커널 융합; 이 레벨 자체로는 sparse, caching, 다른 근사 경로를 활성화하지 않음 |
high |
extra-high의 모든 것 + 감사된 Cache-DiT 정책이나 저정밀 VAE 디코드 같은 모델 소유 고품질 전용 최적화 |
모델에 적격 요청 게이팅 융합이 없으면 extra-high가 lossless와 동일한 경로를 실행할 수 있어요. 마찬가지로 high는 활성 파이프라인이 구현하는 모델별 고품질 전용 경로만 추가해요.
Note
quality는 마스터 정밀도 스위치가 아니에요. 양자화된 체크포인트, 명시적으로 선택된 근사 어텐션 백엔드, 독립적으로 활성화된 캐시는 모든 품질 등급에서 활성 상태로 유지돼요.
요청 게이팅 집합 활성화 (Enabling the request-gated set)
sglang generate --model-path MODEL_PATH --prompt "..." --quality extra-high
서버 기본값은 lossless로 유지되고, OpenAI 호환 엔드포인트는 요청별로 전달해요. 이미지:
curl -X POST http://${HOST}:${PORT}/v1/images/generations \
-H 'Content-Type: application/json' \
-d '{"model": "MODEL_PATH", "prompt": "...", "quality": "extra-high"}'
비디오, 동일 필드:
curl -X POST http://${HOST}:${PORT}/v1/videos \
-H 'Content-Type: application/json' \
-d '{"model": "MODEL_PATH", "prompt": "...", "quality": "extra-high"}'
Warning 비디오 응답 본문의
quality필드는 관련이 없어요. Sora 호환 응답 메타데이터이며 항상"standard"로 보고돼요. 요청이 실행된 샘플링 품질을 반영하지 않아요.
quality는 동적 배치 서명에 참여하므로 혼합 품질 트래픽은 별도로 배칭되고, 전환은 배치 경계에서 안전하게 발생해요. 장착은 all-or-nothing이에요. 트랜스포머의 표시된 사이트 중 하나라도 정적 가드를 실패하면 해당 트랜스포머의 어떤 사이트도 융합되지 않아요.
Warning 요청 게이팅 DiT 융합을
--enable-breakable-cuda-graph와 결합하지 마세요. BCG 워밍업은extra-high또는high요청이 DiT 융합을 장착하기 전에 lossless 모듈 분기를 캡처하므로 재생이 요청된 커널을 우회할 수 있어요. SGLang은 적격 DiT 품질 사이트가 있는 모델에 대해 이 조합을 거부해요. 요청 게이팅 경로가 VAE 디코드만 변경하는 모델은 BCG가 DiT만 캡처하므로 계속 허용돼요.
이 융합 패밀리들은 quality="extra-high"와 quality="high" 둘 모두에서 장착돼요:
| Fusion | What it folds |
|---|---|
| Linear + tanh-GELU | 바이어스 추가와 GELU를 GEMM epilogue(cublasLt)로 통합, [tokens, 4*dim] 중간 왕복 제거 |
| Wan NVFP4 linear + GELU | 바이어스 추가와 GELU를 Wan의 NVFP4 FFN 프로젝션 출력에 융합 |
| Qwen-Image added-QKV | 추가된 Q/K/V 프로젝션을 joint-buffer 생산에 융합 |
| LayerNorm + modulate | affine-free LN + 별도 modulate 대신 layer_norm(x, weight=(1 + scale), bias=shift) |
| LTX-2 RMSNorm + modulate | 한 번의 실행에서 rms_norm(x) * (1 + scale) + shift |
| Gate RMSNorm (BF16-native) | 한 패스에서 RMSNorm + tanh + mul + add |
| HunyuanVideo strided QK RMSNorm | 패킹된 QKV 레이아웃에 대한 헤드별 QK RMSNorm |
| LingBot Video fused RMSNorm | 손으로 쓴 cast, square, mean, rsqrt, multiply 체인을 기존 Triton RMSNorm 커널로 대체 |
| LingBot Video per-token gated residual + RMSNorm modulate | residual + gate * update(토큰별 [B, S, 1] 게이트)와 rmsnorm(x) * (1 + scale) + shift adaLN 체인(strided [B, S, 6D] 청크 뷰)을 단일 커널로 통합 |
| SANA-Video BF16-input linear attention | 첫 linear-attention GEMM 입력을 BF16으로 유지하되 FP32 누적/출력 사용; 두 번째 GEMM은 FP32 유지 |
| FLUX-family VAE fast paths | FLUX.2 및 AutoencoderKL 기반 FLUX.1, Z-Image, SD3 파이프라인용 channels-last decode, GroupNorm(+SiLU), upsample, attention 대체 |
| Wan VAE RMSNorm + SiLU | decode를 channels_last_3d로 유지하면서 channel-first RMSNorm/SiLU 체인 대체 |
커널 인벤토리 (Kernel inventory)
커널 레지스트리에는 51개 구현에 걸쳐 45개 연산자가 등록돼 있어요(일부 연산자는 여러 백엔드를 가짐). 백엔드는 디바이스가 아니라 출처로 이름이 지어져요: KDA는 Kernel Design Agents 구현을, JIT는 nvcc 및 hipcc에서 컴파일하며, TRITON은 Triton 소스를, CUTE_DSL은 CUTLASS가 필요하고, FLYDSL은 ROCm gfx950 전용이며, AOT는 sgl_kernel 휠에서 옵니다. 연산자별 기능 메타데이터가 각 구현을 어떤 디바이스가 로드할 수 있는지 결정해요.
정규화 (Normalization)
| Operator | Backend | Contract | Replaces |
|---|---|---|---|
rmsnorm_scale_shift |
Triton | 비트 정확 | RMSNorm + * (1 + scale) + shift (4개 커널) |
scale_residual_norm_scale_shift |
KDA / Triton / CuTe-DSL / FlyDSL | 비트 정확(Triton) 또는 백엔드별 close contract | 위 항목 + 앞의 residual + gate * update |
scale_residual_norm_scale_shift_nvfp4 |
JIT CUDA | 선택된 NVFP4 생성기 계약과 일치 | Qwen residual LayerNorm/modulation + FC1 NVFP4 양자화 |
layernorm_modulate |
Triton | 비트 정확 | affine-free LayerNorm + adaLN modulate |
qk_head_layernorm |
Triton | 비트 정확 | q/k에 대한 헤드별 LayerNorm |
qk_rmsnorm_native |
Triton | 비트 정확 | Z-Image 헤드별 QK RMSNorm |
norm_scale_shift |
KDA / CuTe-DSL / FlyDSL | 백엔드별 close contract | LN-or-RMS + scale/shift, 다양한 브로드캐스트 모드 |
rmsnorm_scale, rmsnorm_tanh_residual |
Triton | bf16-네이티브 통계 | RMSNorm(x) * scale, x + tanh(gate) * RMSNorm(y) |
apply_group_norm_silu |
Triton | close | GroupNorm + SiLU, NCHW-연속 |
group_norm_silu_4d, group_norm_silu_rows |
Triton | close | channels-last GroupNorm(+SiLU); VAE 디코더가 nchwToNhwc 전치 없이 channels_last를 end-to-end로 실행하게 함 |
wan_rmsnorm_silu |
Triton | close | Wan VAE channels_last_3d RMSNorm + SiLU |
adaLN 변조 및 게이팅 (adaLN modulation and gating)
| Operator | Backend | Contract | Replaces |
|---|---|---|---|
modulate_scale_shift |
JIT CUDA | 비트 정확 | x * (1 + scale) + shift |
residual_gate_add |
KDA (JIT CUDA) | 비트 정확 | residual + gate * update |
timestep_embedding |
JIT CUDA | close | 사인파 timestep 임베딩 |
temb_table_slices |
Triton | 비트 정확 | 아래 주석 참고 |
ltx2_ada_values |
Triton | 비트 정확 | LTX-2 9-way adaLN 값 분할, 슬라이스가 연속으로 나옴 |
Tip
temb_table_slices는 알아둘 가치가 있어요. eager(scale_shift_table + temb.float()).chunk(6, dim=2)은 704p/121f에서 약 8 GB의 fp32를 구체화하며, 다운스트림에 여섯 개의 strided 슬라이스를 전달하는데 그.contiguous()호출이 각각 다시 복사해요. 융합 커널은 여섯 슬라이스를 한 패스로 각각 자연스럽게 연속으로 생성하므로 다운스트림 복사가 no-op이 돼요.
RoPE 및 QK-norm
| Operator | Backend | Contract | Replaces |
|---|---|---|---|
fused_inplace_qknorm_rope |
JIT CUDA | 분할 기준선 대비 bf16 반올림 한 단계; round_norm_before_rope=True에서 정확 |
별도 QK-norm 커널 + RoPE |
flux2_qkv_epilogue |
KDA (JIT CUDA) | 선택된 BF16 참조 체인에 대해 비트 정확 | FLUX.2 QK RMSNorm + RoPE + joint text/image QKV 패킹 |
qwen_qkv_epilogue |
JIT CUDA | 선택된 BF16 참조 체인에 대해 비트 정확 | SM100+에서 Qwen-Image QK RMSNorm + RoPE + joint QKV 쓰기 |
rope_rotate_half |
Triton | 비트 정확 | chunk → cat(-x2, x1) → 두 muls + add → cat(tail), 프로젝션당 약 7개 커널 |
interleaved_rope_fp64 |
JIT CUDA | 비트 정확 | fp64 테이블이 있는 짝지어진 SANA-Video Q/K RoPE, 약 14개 eager 커널 |
helios_qk_rope |
JIT CUDA | 비트 정확 | 전치 주파수 레이아웃이 있는 짝지어진 in-place Helios Q/K RoPE |
ltx2_qknorm_split_rope |
KDA (JIT CUDA) | close (B200에서 검증) | LTX-2 QK-norm + split RoPE |
ltx25_decoder_rope |
JIT CUDA | 비트 정확 | 캐시된 컴팩트 축 테이블에서 짝지어진 LTX-2.5 디코더 3D RoPE |
hunyuan_qkv_rope_pack |
Triton | 비트 정확 | QKV 패킹 및 RoPE를 한 패스로 |
활성화 (Activation)
| Operator | Backend | Contract | Replaces |
|---|---|---|---|
silu_mul |
Triton | 비트 정확 | split-projection SwiGLU용 F.silu(a) * b. 여기서 concatenated silu_and_mul 커널은 추가 전체 폭 cat 없이 적용 불가 |
bias_silu, bias_glu |
Triton | 비트 정확 | Sana GLUMB conv bias + SiLU / GLU 후처리 |
linear_gelu_tanh |
AOT (cublasLt) | 비트 정확 아님, 요청 게이팅 | 바이어스 추가와 tanh-GELU를 GEMM epilogue로 접음 |
어텐션 (Attention)
| Operator | Backend | Notes |
|---|---|---|
sparse_linear_attn_fwd |
Triton | 희소 선형 어텐션용 block-map, 압축 및 forward |
bigdn |
Triton | Sana-WM 양방향 게이트 delta-net; chunkwise 형태는 phase A를 KV와 Z 스트림을 따라 분할해 SM당 두 블록을 상주시키고, (I - P)를 저장해 phase B의 MMA가 identity-add를 접음 |
MoE 라우팅
| Operator | Backend | Contract | Replaces |
|---|---|---|---|
group_limited_topk |
Triton | 선택된 expert-id 집합이 가드된 CUDA 참조와 일치; 출력 순서는 미지정 | LingBot Video의 그룹별 top-2 감소, 그룹 top-k, 마스크 구성, 마스킹된 전문가 점수, 최종 전문가 top-k |
데이터 이동 (Data movement)
여기 있는 모든 커널은 값만 이동해요(제로 채우기와 순서 보존 add 최대 하나 추가). 따라서 대체하는 aten 체인과 비트 단위로 동일해요.
| Operator | Backend | Replaces |
|---|---|---|
usp_merge_heads |
JIT CUDA | USP all-to-all 출력 헤드 병합(permute + contiguous) |
pack_qkv_destination_major |
Triton | Ulysses destination-major QKV 패킹 |
varlen_pack_qkv, varlen_scatter_to_padded |
Triton | 마스크된 어텐션 경로 주변의 varlen gather/scatter |
varlen_pack_segmented_qkv |
Triton | 가상 prefix/main Q/K/V 시퀀스에서 varlen gather |
joint_qkv_cat |
Triton | Joy Image Edit의 3개 이미지/텍스트 Q/K/V 연결, strided packed-V 입력 포함 |
causal_conv3d_cat_pad |
KDA (JIT CUDA) / Triton | 인과적 Conv3d cat + pad |
cat_pad_channels_last_3d |
Triton | Wan 인과적 VAE cat + F.pad + contiguous(3패스 + 캐시 부기)를 한 패스로 |
dup_up3d_add |
Triton | repeat_interleave + permute().contiguous() + add |
Joy Image Edit은 적격 CUDA FP16/BF16 이미지 텐서(최소 32 MiB)에 joint-copy 경로를 사용해요. 이미지-우선 토큰 순서를 보존하고 산술 없이 값을 복사하며, 활성화하기 전에 각 새 형태/스트라이드 시그니처를 네이티브 연결에 대해 검증해요. 작은 입력, 지원되지 않는 레이아웃, 그래디언트 보유 입력, 그래프 캡처 중 미검증 시그니처는 네이티브 경로를 사용해요. 이는 모델 레벨 BCG 지원을 활성화하지 않아요.
큰 Hopper BF16 이미지 Q/K(폭 128의 32 헤드)의 경우 Joy는 기존 out-of-place QK-Norm + RoPE 커널을 사용해 패킹된 프로젝션을 직접 읽어요. 이는 원래 CUDA 산술과 연속 출력을 유지하면서 두 입력 복사를 제거해요. 각 새 시그니처는 비트 단위로 검사되며, 연산 실패 시 입력은 그대로 유지돼요. 다른 형태와 플랫폼, 컴파일, 미검증 캡처, SGLANG_ENABLE_FUSED_QKNORM_ROPE=0은 원래 헬퍼를 유지해요.
양자화 레이아웃 생성기 (Quantized layout producers)
이 커널들은 양자화된 체크포인트 경로의 선택된 참조 연산을 보존해요. FP8 또는 NVFP4가 양자화되지 않은 BF16 체크포인트와 동등하다는 주장이 아니에요.
| Operator | Backend | Replaces |
|---|---|---|
flux2_layernorm_modulate_fp8_quant |
KDA (Triton) | FLUX.2 LayerNorm + adaLN 변조를 정적 FP8 출력으로 직접 |
flux2_token_cat_fp8 |
KDA (Triton) | FLUX.2 단일 블록 어텐션/MLP 연결 + 정적 FP8 양자화 |
flux2_token_cat_nvfp4 |
JIT CUDA | FLUX.2 단일 블록 어텐션/MLP 연결 + NVFP4 양자화 |
모델별 커버리지 (Coverage by model)
커널은 특정 모델의 특정 eager 체인에 맞춰 작성되므로 커버리지는 보편적이 아니라 모델별이에요.
| Model | Fused paths |
|---|---|
| FLUX.1 | LN+modulate, modulate, residual-gate add, linear+GELU |
| FLUX.2 | LN+modulate, fused LN+modulate-to-FP8, packed SwiGLU, gated residual/norm, residual-gate add, QK RMSNorm+RoPE+joint QKV packing, FP8/NVFP4 token-cat producers |
| Qwen-Image | linear+GELU, select-0/1 LN modulation, added-QKV fusion, QK RMSNorm+RoPE+joint QKV writes, residual norm/modulate+NVFP4 producer |
| GLM-Image | LN+modulate, per-head qk LN, residual-gate add, linear+GELU |
| ERNIE-Image | RMSNorm+scale/shift, residual-gated variant, rotate-half RoPE, residual-gate add |
| Joy Image Edit | 비트 단위 이미지/텍스트 QKV 연결; Hopper에서 strided 이미지 QK-Norm + RoPE |
| Z-Image | BF16-네이티브 RMSNorm scale / tanh-residual, 헤드별 QK RMSNorm |
| Ideogram 4 | gate RMSNorm, SwiGLU, rotate-half RoPE, modulate, residual-gate add |
| LTX-2 | QK-norm + split RoPE, ada-values split, RMSNorm+modulate, modulate, residual-gate add, linear+GELU |
| LTX-2.5 decoder | 공유 축-테이블 캐시가 있는 짝지어진 3D RoPE |
| HunyuanVideo / Helios | QKV+RoPE pack, strided QK RMSNorm, linear+GELU; Helios는 pair in-place Q/K RoPE도 보유 |
| LingBot Video MoE | 기본 켜짐 group-limited top-k 전문가 선택; quality=extra-high 또는 quality=high에서 융합 RMSNorm, 토큰별 gated residual, 융합 RMSNorm+modulate |
| Sana | LN+modulate, GLUMB bias+SiLU / bias+GLU, residual-gate add |
| SANA-Video | Packed QKV/KV; pair fp64 interleaved RoPE; BCG 중 LN+modulate, GLUMB bias+SiLU / bias+GLU, residual-gate add; quality=extra-high 또는 quality=high에서 BF16-input linear attention |
| Sana-WM | 양방향 게이트 delta-net, 융합 QK inverse-RMS |
| Wan | temb table slices; VAE cat+pad 및 DupUp3D add, channels_last_3d RMSNorm+SiLU |
| Cosmos3 / Krea2 / MiniMax-H3 | QK-norm + RoPE (Krea2는 CuTe-DSL norm+scale/shift도, MiniMax-H3는 indexed modulation도) |
| FLUX.2 VAE / HunyuanVAE / latent upsampler | GroupNorm + SiLU (FLUX.2는 channels-last 2패스) |
등록된 것 검사하기 (Inspecting what is registered)
모든 커널은 프로세스 전역 레지스트리에서 KernelSpec으로 설명되므로 백엔드를 가져오지 않고 인벤토리를 쿼리할 수 있어요:
from sglang.kernels.registry import registry
diffusion_ops = [op for op in registry.ops() if op.startswith("diffusion.")]
for spec in registry.get("diffusion.scale_residual_norm_scale_shift"):
print(spec.backend, spec.target, spec.capabilities)
등록은 메타데이터만 해요 — torch나 백엔드를 가져오지 않고 JIT 빌드를 트리거하지 않아요. 여러 구현이 있는 연산자의 특정 구현을 선택하려면:
from sglang.kernels import select_kernel, KernelBackend
fn = select_kernel(
"diffusion.scale_residual_norm_scale_shift", backend=KernelBackend.CUTE_DSL
).load()
커널 가져오기 (Importing the kernels)
런타임 코드는 패키지에서 가져오며 하위 모듈에서 가져오지 않아요:
from sglang.kernels.ops.diffusion import fused_rmsnorm_scale_shift_bitexact
해석은 지연적(lazy)이에요. 백엔드는 분리된 무거운 의존성(Triton, CUTLASS/CuTe-DSL, ROCm의 FlyDSL)을 가지므로, eager 재수출은 모든 플랫폼에서 그것들 각각을 가져오기 시점 요구로 만들 거예요. 각 공개 커널은 술어+커널 쌍이에요 — can_use_<op>(...)를 먼저 호출하고 False를 반환하면 참조 체인으로 폴백해요. 커널은 None을 조용히 반환하는 대신 지원되지 않는 입력에서 예외를 발생시켜요.
패키지 README.md는 여러 커널이 서로 교환 가능해 보이지만 그렇지 않은 경우를 위한 선택 매트릭스를 담고 있어요. 정규화 도메인만 해도 수치 계약, 활성화 레이아웃, 백엔드로 속도가 아니라 서로 다른 십수 개 구현을 보유해요.
참고 자료 (References)
- Performance Optimization
- Attention Backends
- Quantization
- Profiling
sglang/kernels/ops/diffusion— 소스 및 선택 매트릭스- RFC #29630 — 통합
sglang.kernels네임스페이스