File size: 2,922 Bytes
333ff0e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
"""Post-training weight quantization of the SD3 backbone for faster inference (torchao).

Weight-only quantization of the MMDiT transformer's Linear layers — the bulk of inference compute
(``sample_steps`` denoise iterations × CFG). The frozen VAE + style encoder run O(1) per generation,
so they stay bf16. Quantization is POST-TRAINING and INFERENCE-ONLY — it never touches training.

The speedup comes from compiled low-bit matmul kernels, so quantize BEFORE ``Backbone.compile_blocks``
(torchao + ``torch.compile`` is the supported combo; int8 in eager dequantizes and can be SLOWER).
bf16 is the accuracy baseline; int8/fp8 trade a little precision for speed/memory on memory-bound
GEMMs — always validate gen_CER before shipping (``scripts/bench_quant.py``).
"""

from __future__ import annotations

from typing import Literal

import torch

QuantMode = Literal["int8", "int8dq", "fp8", "fp8dq"]


def quantize_backbone(model: torch.nn.Module, mode: QuantMode = "int8") -> None:
    """In-place torchao weight quantization of ``model.backbone.transformer`` Linear layers.

    Args:
        model: a built ``Diffu`` (needs ``.backbone.transformer``).
        mode: ``int8`` = int8 weight-only; ``int8dq`` = int8 dynamic-activation + int8 weight;
            ``fp8`` = float8 weight-only; ``fp8dq`` = float8 dynamic-activation + float8 weight
            (full fp8 GEMM — best on Blackwell's fp8 tensor cores). fp8 modes need CC ≥ 8.9.

    Raises:
        ValueError: unknown ``mode``.
        RuntimeError: an fp8 mode requested on pre-Ada hardware.
    """
    from torchao.quantization import (  # torchao 0.17 config-based API
        Float8DynamicActivationFloat8WeightConfig,
        Float8WeightOnlyConfig,
        Int8DynamicActivationInt8WeightConfig,
        Int8WeightOnlyConfig,
        quantize_,
    )

    # int8 version=2: the maintained Int8Tensor path (torchao 0.17 deprecates the v1 default's legacy
    # AffineQuantizedTensor route). set_inductor_config=False everywhere: the default True flips GLOBAL
    # inductor flags + TF32 at quantize time, which makes any quant-vs-baseline benchmark
    # apples-to-oranges — callers own their global compile settings.
    recipes = {
        "int8": lambda: Int8WeightOnlyConfig(version=2, set_inductor_config=False),
        "int8dq": lambda: Int8DynamicActivationInt8WeightConfig(version=2, set_inductor_config=False),
        "fp8": lambda: Float8WeightOnlyConfig(set_inductor_config=False),
        "fp8dq": lambda: Float8DynamicActivationFloat8WeightConfig(set_inductor_config=False),
    }
    if mode not in recipes:
        raise ValueError(f"unknown quant mode {mode!r}; choose from {sorted(recipes)}")
    if mode.startswith("fp8") and torch.cuda.get_device_capability() < (8, 9):
        raise RuntimeError("fp8 needs compute capability >= 8.9 (Ada/Hopper/Blackwell)")
    quantize_(model.backbone.transformer, recipes[mode]())