# 推論を高速化

Diffusionモデルは、ノイズが一定の「ステップ」数にわたって徐々に洗練され、画像や動画として生成される反復プロセスであるため、推論が遅くなります。このプロセスを高速化するには、異なる[schedulers](../api/schedulers/overview)の実験、モデル重みの精度を下げた高速な計算、よりメモリ効率の高いアテンション機構の使用などが考えられます。

これらの技術を組み合わせて使用することで、単一の技術のみを使用する場合よりも推論を高速化できます。

このガイドでは、推論を高速化する方法について説明します。

## モデルのデータ型

モデルの重みの精度とデータ型は推論速度に影響します。精度が高いほど、読み込みに必要なメモリ量が増え、計算に要する時間も長くなるためです。PyTorch はデフォルトで float32（フル精度）でモデルの重みをロードするため、データ型を変更することは、推論を素早く高速化する簡単な方法です。

bfloat16はfloat16に似ていますが、数値エラーに対してより頑健です。bfloat16のハードウェアサポートは環境によって異なりますが、ほとんどの最新のGPUはbfloat16をサポートしています。

```py
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

float16 は bfloat16 と似ていますが、数値エラーが発生しやすくなる場合があります。

```py
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

[TensorFloat-32 (tf32)](https://blogs.nvidia.com/blog/2020/05/14/tensorfloat-32-precision-format/) モードは NVIDIA Ampere GPU でサポートされており、畳み込みおよび行列積の演算を tf32 で実行します。ストレージおよびその他の演算は float32 のまま維持されます。これにより、bfloat16 または float16 と組み合わせることで、計算が大幅に高速化されます。

PyTorchではデフォルトで畳み込みのみtf32モードが有効化されており、行列積に対しては明示的に有効化する必要があります。

```py
import torch
from diffusers import StableDiffusionXLPipeline

torch.backends.cuda.matmul.allow_tf32 = True

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

詳細については、[混合精度トレーニング](https://huggingface.co/docs/transformers/en/perf_train_gpu_one#mixed-precision)のドキュメントを参照してください。

## スケーリングドットプロダクトアテンション

> [!TIP]
> Memory-efficient attention は、推論速度*と*[メモリ使用量](./memory#memory-efficient-attention)の両方を最適化します!

[Scaled dot product attention (SDPA)](https://pytorch.org/docs/stable/generated/torch.nn.functional.scaled_dot_product_attention.html) は、[FlashAttention](https://github.com/Dao-AILab/flash-attention)、[xFormers](https://github.com/facebookresearch/xformers)、およびネイティブの C++ 実装という複数のアテンションバックエンドを実装しています。ハードウェアに応じて最適なバックエンドを自動的に選択します。

PyTorch >= 2.0 を使用している場合、SDPA はデフォルトで有効化され、コードに追加の変更は不要です。ただし、独自のバックエンドを選択したい場合は、他のアテンションバックエンドを試すこともできます。以下の例では、[torch.nn.attention.sdpa_kernel](https://pytorch.org/docs/stable/generated/torch.nn.attention.sdpa_kernel.html) コンテキストマネージャーを使用して、効率的なアテンションを有効にしています。

```py
from torch.nn.attention import SDPBackend, sdpa_kernel
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"

with sdpa_kernel(SDPBackend.EFFICIENT_ATTENTION):
  image = pipeline(prompt, num_inference_steps=30).images[0]
```

## torch.compile

[torch.compile](https://pytorch.org/tutorials/intermediate/torch_compile_tutorial.html) は、PyTorch のコードと演算を最適化されたカーネルにコンパイルすることで推論を高速化します。Diffusers は通常、UNet、transformer、VAE など、計算負荷の高いモデルをコンパイルします。

最大速度を実現するために、以下のコンパイラ設定を有効にしてください（その他のオプションについては、[完全なリスト](https://github.com/pytorch/pytorch/blob/main/torch/_inductor/config.py)を参照してください）。

```py
import torch
from diffusers import StableDiffusionXLPipeline

torch._inductor.config.conv_1x1_as_mm = True
torch._inductor.config.coordinate_descent_tuning = True
torch._inductor.config.epilogue_fusion = False
torch._inductor.config.coordinate_descent_check_all_directions = True
```

UNetとVAEを読み込み、コンパイルします。選択できるモードはいくつかありますが、`"max-autotune"`はCUDAグラフへコンパイルすることで最速の速度を最適化します。CUDAグラフは、単一のCPU操作で複数のGPU操作を発行することにより、オーバーヘッドを実質的に削減します。

> [!TIP]
> PyTorch 2.3.1 では、torch.compile のキャッシュ動作を制御できます。これは、複数のコンパイルフラグをグリッドサーチして最適な設定を見つける `"max-autotune"` などのコンパイルモードにおいて特に有益です。詳細は、[torch.compile におけるコンパイルタイムキャッシュ](https://pytorch.org/tutorials/recipes/torch_compile_caching_tutorial.html) チュートリアルを参照してください。

メモリレイアウトを[channels_last](./memory#torchchannelslast)に変更すると、メモリと推論速度が最適化されます。

```py
pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet.to(memory_format=torch.channels_last)
pipeline.vae.to(memory_format=torch.channels_last)
pipeline.unet = torch.compile(
    pipeline.unet, mode="max-autotune", fullgraph=True
)
pipeline.vae.decode = torch.compile(
    pipeline.vae.decode,
    mode="max-autotune",
    fullgraph=True
)

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

コンパイルは初回に時間がかかりますが、一度コンパイルが完了すると、その後の処理は大幅に高速化されます。コンパイル済みパイプラインは、同じ種類の推論操作にのみ使用することをお勧めします。異なる画像サイズに対してコンパイル済みパイプラインを呼び出すと、コンパイルが再実行され、これが遅く非効率になるためです。

### 動的形状コンパイル

> [!TIP]
> より良いサポートを得るために、常に PyTorch の nightly バージョンを使用してください。

`torch.compile` は入力形状と条件をトラッキングし、これらが異なる場合はモデルを再コンパイルします。例えば、1024x1024 の解像度の画像でモデルをコンパイルし、異なる解像度の画像で使用した場合、再コンパイルがトリガーされます。

再コンパイルを回避するために、`dynamic=True` を追加し、条件が変更された際に再コンパイルを回避するためのより動的なカーネルの生成を試みてください。

```diff
+ torch.fx.experimental._config.use_duck_shape = False
+ pipeline.unet = torch.compile(
    pipeline.unet, fullgraph=True, dynamic=True
)
```

`use_duck_shape=False` を指定すると、コンパイラに、同じである入力サイズを表すのに同じシンボリック変数を使用すべきかどうかを指示します。詳細については、この[コメント](https://github.com/huggingface/diffusers/pull/11327#discussion_r2047659790)を参照してください。

すべてのモデルが、そのままの状態で動的コンパイルの恩恵を受けられるとは限りません。変更が必要な場合があります。[AuraFlowPipeline](/docs/diffusers/v0.43.0/ja/api/pipelines/aura_flow#diffusers.AuraFlowPipeline)の実装を改善し、動的コンパイルの恩恵を受けられるようにしたこの[PR](https://github.com/huggingface/diffusers/pull/11297/)を参照してください。

Diffusersモデルで動的コンパイルが期待通りに動作しない場合は、お気軽にissueを作成してください。

### 地域別コンパイル

[Regional compilation](https://docs.pytorch.org/tutorials/recipes/regional_compilation.html)は、モデルの*小さく頻繁に繰り返されるブロック*（通常はtransformer層）のみをコンパイルすることで、コールドスタートのレイテンシを削減します。これにより、以降のすべての出現箇所に対してコンパイル済み成果物を再利用できます。多くの拡散アーキテクチャにおいて、これはグラフ全体のコンパイルと同等のランタイム高速化を実現し、コンパイル時間を8〜10分の1に短縮します。

以下に示すように、[compile_repeated_blocks()](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) メソッドは `torch.compile` をラップするヘルパーであり、transformer モデルなどのコンポーネントに適用できます。

```py
# pip install -U diffusers
import torch
from diffusers import StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"

# compile only the repeated transformer layers inside the UNet
pipeline.unet.compile_repeated_blocks(fullgraph=True)
```

新しいモデルでリージョナルコンパイルを有効にするには、コンパイル対象のブロックのクラス名（文字列）を含む`_repeated_blocks`属性をモデルクラスに追加します。

```py
class MyUNet(ModelMixin):
    _repeated_blocks = ("Transformer2DModel",)  # ← compiled by default
```

> [!TIP]
> 地域別のコンパイルの例については、[PR](https://github.com/huggingface/diffusers/pull/11705)を参照してください。

[Accelerate](https://huggingface.co/docs/accelerate/index) には、モデル内でコンパイルする候補ブロックを自動的に選択する [compile_regions](https://github.com/huggingface/accelerate/blob/273799c85d849a1954a4f2e65767216eb37fa089/src/accelerate/utils/other.py#L78) メソッドもあります。残りのグラフは個別にコンパイルされます。コンパイル対象のブロックを指定したり、コンパイルフラグを調整したりするオプションが少ないため、クイックな実験に便利です。

```py
# pip install -U accelerate
import torch
from diffusers import StableDiffusionXLPipeline
from accelerate.utils import compile_regions

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.float16
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.unet = compile_regions(pipeline.unet, mode="reduce-overhead", fullgraph=True)
```

[compile_repeated_blocks()](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin.compile_repeated_blocks) は意図的に明示的な設計です。`_repeated_blocks` に反復するブロックを列挙し、ヘルパーはそれらのブロックのみをコンパイルします。これにより、1 行のコードでキャッシュ再利用について予測可能な動作と容易な推論が可能になります。

### グラフのブレイク

torch.compile で `fullgraph=True` を指定することは、基盤となるモデルにグラフの中断が発生しないことを保証するために重要です。これにより、パフォーマンスの低下なしで torch.compile の恩恵を受けることができます。UNet と VAE については、戻り値の変数へのアクセス方法が変更されます。

```diff
- latents = unet(
-   latents, timestep=timestep, encoder_hidden_states=prompt_embeds
-).sample

+ latents = unet(
+   latents, timestep=timestep, encoder_hidden_states=prompt_embeds, return_dict=False
+)[0]
```

### GPU同期

`step()` 関数は、デノイザーが予測を行うたびにスケジューラーに対して[呼び出され](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/pipelines/stable_diffusion_xl/pipeline_stable_diffusion_xl.py#L1228)、`sigmas` 変数が[インデックス付け](https://github.com/huggingface/diffusers/blob/1d686bac8146037e97f3fd8c56e4063230f71751/src/diffusers/schedulers/scheduling_euler_discrete.py#L476)られます。GPU に配置すると、CPU と GPU 間の通信同期によりレイテンシが発生します。デノイザーがすでにコンパイルされている場合、この影響はより顕著になります。

一般的に、`sigmas`は通信の同期とレイテンシを避けるために、[CPU上に保持しておく](https://github.com/huggingface/diffusers/blob/35a969d297cba69110d175ee79c59312b9f49e1e/src/diffusers/schedulers/scheduling_euler_discrete.py#L240)必要があります。

> [!TIP]
> 拡散モデルで`torch.compile`によるパフォーマンスの最大化については、[torch.compile と Diffusers: ピークパフォーマンスを実現する実践ガイド](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)というブログ記事をご参照ください。

### ベンチマーク

コンパイル済みパイプラインの推論レイテンシとメモリ使用量のデータを確認するには、[diffusers/benchmarks](https://huggingface.co/datasets/diffusers/benchmarks) データセットを参照してください。

[diffusers-torchao](https://github.com/sayakpaul/diffusers-torchao#benchmarking-results) リポジトリには、Flux と CogVideoX のコンパイル済みバージョンに関するベンチマーク結果も含まれています。

## カーネル

[Kernels](https://huggingface.co/docs/kernels/index) は、[Hub](https://huggingface.co/kernels-community) 上で最適化された計算カーネルを構築・配布・読み込むためのライブラリです。[attention](./attention_backends#setattentionbackend) カーネルや、RMSNorm、GEGLU、RoPE、AdaLN などの演算用のカスタム CUDA カーネルに対応しています。

[Diffusers Pipeline Integration](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/references/diffusers-integration.md)ガイドでは、[add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md)スキルを使用してカーネルを統合する方法を示しています。このスキルにより、ClaudeやCodexなどのエージェントが、特定のモデルやお使いのハードウェア向けのカスタムカーネルを作成できるようになります。

> [!TIP]
> Install the [add cuda-kernels](https://github.com/huggingface/kernels/blob/main/kernel-builder/skills/cuda-kernels/SKILL.md) skill to teach an agent how to write a kernel. The [Custom kernels for all from Codex and Claude](https://huggingface.co/blog/custom-cuda-kernels-agent-skills) blog post covers this in more detail.

例えば、`add cuda-kernels` スキルによって生成されたカスタム RMSNorm カーネルに [torch.compile](#torchcompile) を組み合わせることで、H100 上で LTX-Video の生成を 1.43 倍高速化できます。

<iframe src="https://huggingface.co/datasets/docs-benchmarks/kernel-ltx-video/embed/viewer/default/train" frameborder="0" width="100%" height="560px"
>

## 動的量子化

[Dynamic quantization](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html)は、精度を低減してより高速な数学演算を可能にすることで、推論速度を向上させます。このタイプの量子化は、固定のスケーリング係数を使用するのではなく、実行時のデータに基づいてアクティベーションのスケーリング方法を決定します。その結果、スケーリング係数がデータにより正確に整合するようになります。

以下の例では、[torchao](../quantization/torchao) ライブラリを使用して、UNet と VAE に[動的 int8 量子化](https://docs.pytorch.org/ao/main/api_reference/generated/torchao.quantization.Int8DynamicActivationInt8WeightConfig.html)を適用します。

> [!TIP]
> Diffusersのtorchao統合の使用方法については、[torchao](../quantization/torchao)のドキュメントを参照してください。

最大速度を達成するためにコンパイラタグを設定します。

```py
import torch
from torchao import apply_dynamic_quant
from diffusers import StableDiffusionXLPipeline

torch._inductor.config.conv_1x1_as_mm = True
torch._inductor.config.coordinate_descent_tuning = True
torch._inductor.config.epilogue_fusion = False
torch._inductor.config.coordinate_descent_check_all_directions = True
torch._inductor.config.force_fuse_int_mm_with_mul = True
torch._inductor.config.use_mixed_mm = True
```

[dynamic_quant_filter_fn](https://github.com/huggingface/diffusion-fast/blob/0f169640b1db106fe6a479f78c1ed3bfaeba3386/utils/pipeline_utils.py#L16) を使用して、動的量子化の恩恵を受けない UNet と VAE の一部の線形層を除外します。

```py
pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"

apply_dynamic_quant(pipeline.unet, dynamic_quant_filter_fn)
apply_dynamic_quant(pipeline.vae, dynamic_quant_filter_fn)

prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, num_inference_steps=30).images[0]
```

## 融合された射影行列

> [!WARNING]
> [fuse_qkv_projections](https://github.com/huggingface/diffusers/blob/58431f102cf39c3c8a569f32d71b2ea8caa461e1/src/diffusers/pipelines/pipeline_utils.py#L2034) メソッドは実験的な機能であり、サポートは主に Stable Diffusion パイプラインに限定されています。他のパイプラインでこれを有効にする方法については、この [PR](https://github.com/huggingface/diffusers/pull/6179) をご覧ください。

Q、K、Vの射影行列によって表される3つの部分空間に、アテンションブロック内で入力が射影されます。これらの射影は通常、個別に計算されますが、これらを水平方向に結合して単一の行列にし、1ステップで射影を実行することもできます。これにより、入力射影の行列積のサイズが増大し、量子化の影響も向上します。

```py
pipeline.fuse_qkv_projections()
```

## リソース

- [Presenting Flux Fast: Making Flux go brrr on H100s](https://pytorch.org/blog/presenting-flux-fast-making-flux-go-brrr-on-h100s/) のブログ記事を読み、[TorchInductor](https://docs.pytorch.org/docs/stable/torch.compiler.html) と [AOTInductor](https://docs.pytorch.org/docs/stable/torch.compiler_aot_inductor.html) をこれらの最適化すべてと組み合わせることで、[flux-fast](https://github.com/huggingface/flux-fast) のレシピを使用して約2.5倍の高速化を実現する方法について詳しく学びましょう。

    これらのレシピは、AMD ハードウェアおよび [Flux.1 Kontext Dev](https://huggingface.co/black-forest-labs/FLUX.1-Kontext-dev) をサポートしています。
- [torch.compileとDiffusers: 最高性能を実現する実践ガイド](https://pytorch.org/blog/torch-compile-and-diffusers-a-hands-on-guide-to-peak-performance/)のブログ記事をお読みください
`torch.compile` を使用してパフォーマンスを最大化するには。

