# SDNQ

[SDNQ](https://github.com/Disty0/sdnq)（SD.Next Quantization）は、トレーニング不要の量子化バックエンドです。int8から2ビット、FP8、その他の低ビット浮動小数点形式まで幅広い重みのdtypeをサポートし、任意でSVD補正、Hadamard回転、および高速推論のための量子化INT8/FP8行列積を実行できます。CUDA、ROCm、XPU、MPS、CPUで動作します。

このバックエンドを使用するには、`sdnq` ライブラリをインストールしてください。

```bash
pip install sdnq
```

## 事前量子化済みチェックポイントを読み込む

事前量子化済みの SDNQ チェックポイントの量子化設定は、その `config.json` に保存されているため、`quantization_config` 引数を必要とせず、他のモデルと同様に読み込むことができます。唯一の要件は、`sdnq` がインストールされていることです。

```python
import torch
from diffusers import DiffusionPipeline

pipe = DiffusionPipeline.from_pretrained(
    "Disty0/Z-Image-Turbo-SDNQ-uint4-svd-r32",
    dtype=torch.bfloat16,
).to("cuda")  # or "mps", "xpu", "cpu"

image = pipe("a cat holding a sign that says hello").images[0]
image.save("output.png")
```

> [!TIP]
> `DIFFUSERS_SDNQ_TRANSFORMERS=1` を設定してください（Diffusers をインポートする前に）。これは、SDNQ 量子化された Transformers モデルを単独で読み込む場合、例えば量子化されたテキストエンコーダーや、モジュール型パイプラインにおけるスタンドアロンの LLM コンポーネントを読み込む場合に必要です。これにより、`sdnq` が Transformers に自身を登録し、量子化モデルが正しく読み込まれるようになります。SDNQ 量子化された diffusers transformer が同時に読み込まれる場合は不要です。その transformer の読み込み時に `sdnq` がインポートされ、登録されるためです。デフォルトでは無効にされており、SDNQ を使用しないパイプラインでは `sdnq` がインポートされることはありません。

## モデルをオンザフライで量子化

`from_pretrained` に [SDNQConfig](/docs/diffusers/main/ja/api/quantization#diffusers.SDNQConfig) を渡すことで、モデルの読み込み時に量子化を実行できます。特定のパイプラインコンポーネントを量子化するには、[PipelineQuantizationConfig](/docs/diffusers/main/ja/api/quantization#diffusers.PipelineQuantizationConfig) を使用します。

```python
import torch
from diffusers import DiffusionPipeline, PipelineQuantizationConfig, SDNQConfig

pipeline_quant_config = PipelineQuantizationConfig(
    quant_mapping={"transformer": SDNQConfig(weights_dtype="uint4", use_svd=True)}
)
pipe = DiffusionPipeline.from_pretrained(
    "Tongyi-MAI/Z-Image-Turbo",
    quantization_config=pipeline_quant_config,
    dtype=torch.bfloat16,
).to("cuda")  # or "mps", "xpu", "cpu"
```

単一のモデルコンポーネントを直接量子化することもできます。

```python
import torch
from diffusers import ZImageTransformer2DModel, SDNQConfig

transformer = ZImageTransformer2DModel.from_pretrained(
    "Tongyi-MAI/Z-Image-Turbo",
    subfolder="transformer",
    quantization_config=SDNQConfig(weights_dtype="int8"),
    dtype=torch.bfloat16,
)
```

すべての引数は [`sdnq.SDNQConfig`](https://github.com/Disty0/sdnq) に転送されます。サポートされている dtype およびオプションの完全なリストについては、SDNQ のドキュメントを参照してください。

## 量子化対象のレイヤーの選択

一部のレイヤーは他のレイヤーよりも量子化の影響を受けやすく、これらの影響を受けやすいレイヤーをスキップすることで、メモリコストをほとんど増やさずに品質を向上させることができます。SDNQ はこれを標準でサポートしており、汎用的なスキップリストと多くのアーキテクチャ向けのモデル固有のスキップリストが組み込まれており、これらは自動的に適用されるため、通常は影響を受けやすいレイヤーは設定なしで量子化されません。より細かい制御が必要な場合は、レイヤーごとの量子化誤差を測定し、損失閾値を超えるレイヤーをスキップする動的なレイヤー選択も可能です。詳細については、[SDNQ 動的量子化ガイド](https://github.com/vladmandic/sdnext/wiki/SDNQ-Quantization#dynamic-loss-threshold)を参照してください。

## 量子化 matmul による高速な推論

デフォルトでは、SDNQは各matmulの前に、重みを計算用のdtypeにデクォアンタイズします。代わりにquantized matmulを有効にすると、matmulが低精度のdtype（INT8/FP8/FP16）で直接実行され、[Triton](https://github.com/triton-lang/triton)が正常にインストールされているハードウェア（CUDA、ROCm、またはXPU）では高速になります。

`apply_sdnq_options_to_model` を使用して、読み込まれたモデルに対して有効化します。この関数は、モデルの既存の量子化設定を読み取り、オプションをその場で再適用します。この方法は、`SDNQConfig` が渡されない事前量子化済みチェックポイントにも適用できます。

```python
import torch
from diffusers import DiffusionPipeline
from sdnq.common import use_torch_compile as triton_is_available
from sdnq.loader import apply_sdnq_options_to_model

pipe = DiffusionPipeline.from_pretrained(
    "Disty0/Z-Image-Turbo-SDNQ-uint4-svd-r32",
    dtype=torch.bfloat16,
).to("cuda")  # or "mps", "xpu", "cpu"

if triton_is_available and (torch.cuda.is_available() or torch.xpu.is_available()):
    pipe.transformer = apply_sdnq_options_to_model(pipe.transformer, use_quantized_matmul=True)
    pipe.text_encoder = apply_sdnq_options_to_model(pipe.text_encoder, use_quantized_matmul=True)
```

## torch.compile

SDNQ量子化モデルは、[group offloading](../optimization/memory#group-offloading)との組み合わせを含む、さらなる高速化のために[torch.compile](../optimization/fp16#torchcompile)と互換性があります。

```python
transformer.compile(fullgraph=True)
```

## 量子化モデルを保存する

量子化されたモデルは`save_pretrained`でシリアライズでき、`quantization_config`なしで再読み込みできます。

```python
transformer.save_pretrained("z-image-turbo-sdnq-int8")
```

## リソース

- [SDNQリポジトリ](https://github.com/Disty0/sdnq)
- [Hub上の事前量子化済みSDNQモデル](https://huggingface.co/models?search=sdnq)

