# メモリ使用量の削減

[Flux](../api/pipelines/flux) や [Wan](../api/pipelines/wan) などの最新の拡散モデルは数十億のパラメータを持ち、推論時にハードウェア上で大量のメモリを消費します。一般的な GPU は十分なメモリを備えていないことが多いため、これは課題となります。メモリ制限を克服するには、利用可能な場合は複数の GPU を使用したり、パイプラインの一部コンポーネントを CPU にオフロードしたり、その他の方法を用いることができます。

このガイドでは、メモリ使用量を削減する方法について説明します。

> [!TIP]
> これらの手法は、モデルによって調整が必要な場合があります。例えば、Transformerベースの拡散モデルは、UNetベースのモデルと比べて、これらのメモリ最適化から同程度の恩恵を受けられない可能性があります。

## 複数のGPU

複数のGPUにアクセスできる場合、大規模なモデルをハードウェア全体に効率的にロードして分散するためのいくつかのオプションがあります。これらの機能は[Accelerate](https://huggingface.co/docs/accelerate/index)ライブラリによってサポートされているため、まずインストールされていることを確認してください。

```bash
pip install -U accelerate
```

### シャード化されたチェックポイント

複数のシャードに分割された大きなチェックポイントをロードすることは有用です。シャードは1つずつロードされるため、メモリ使用量を低く抑えられ、モデルサイズと最大のシャードサイズに必要なメモリだけで済みます。fp32のチェックポイントが5GBを超える場合は、シャード化することを推奨します。デフォルトのシャードサイズは5GBです。

`max_shard_size` パラメータを指定して、[save_pretrained()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.save_pretrained) でチェックポイントをシャード化します。

```py
from diffusers import AutoModel

unet = AutoModel.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0", subfolder="unet"
)
unet.save_pretrained("sdxl-unet-sharded", max_shard_size="5GB")
```

これにより、通常のチェックポイントの代わりにシャード化されたチェックポイントを使用することで、メモリを節約できます。

```py
import torch
from diffusers import AutoModel, StableDiffusionXLPipeline

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

### デバイスの配置

> [!WARNING]
> デバイス配置は実験的な機能であり、APIが変更される可能性があります。現時点では、`balanced`戦略のみがサポートされています。今後、追加のマッピング戦略をサポートする予定です。

`device_map` パラメータは、パイプライン内のモデルコンポーネント、または個別モデルのレイヤーがデバイス間でどのように分散されるかを制御します。

`balanced` デバイス配置戦略では、パイプラインが利用可能なすべてのデバイスに均等に分割されます。

```py
import torch
from diffusers import AutoModel, StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
    device_map="balanced"
)
```

`hf_device_map` を使用して、パイプラインのデバイスマップを確認できます。

```py
print(pipeline.hf_device_map)
{'unet': 1, 'vae': 1, 'safety_checker': 0, 'text_encoder': 0}
```

`device_map` は、12.5B パラメータを持つ Flux diffusion transformer のような大規模モデルの読み込みに便利です。`"auto"` に設定すると、モデルが最も高速なデバイスから順に、遅いデバイスへと自動的に分散配置されます。詳細については、[Sharded checkpoints](#sharded-checkpoints) セクションを参照してください。

```py
import torch
from diffusers import AutoModel

transformer = AutoModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev", 
    subfolder="transformer",
    device_map="auto",
    dtype=torch.bfloat16
)
```

`hf_device_map` を使用して、モデルのデバイスマップを確認できます。

```py
print(transformer.hf_device_map)
```

独自の`device_map`を設計する際は、モデルの特定のモジュール名またはレイヤーと、デバイス識別子（GPUの場合は整数、CPUの場合は`cpu`、ディスクの場合は`disk`）の辞書である必要があります。

モデルに対して`hf_device_map`を呼び出して、モデルのレイヤーがどのように分散されているかを確認し、その後、独自の分散設計を行ってください。

```py
print(transformer.hf_device_map)
{'pos_embed': 0, 'time_text_embed': 0, 'context_embedder': 0, 'x_embedder': 0, 'transformer_blocks': 0, 'single_transformer_blocks.0': 0, 'single_transformer_blocks.1': 0, 'single_transformer_blocks.2': 0, 'single_transformer_blocks.3': 0, 'single_transformer_blocks.4': 0, 'single_transformer_blocks.5': 0, 'single_transformer_blocks.6': 0, 'single_transformer_blocks.7': 0, 'single_transformer_blocks.8': 0, 'single_transformer_blocks.9': 0, 'single_transformer_blocks.10': 'cpu', 'single_transformer_blocks.11': 'cpu', 'single_transformer_blocks.12': 'cpu', 'single_transformer_blocks.13': 'cpu', 'single_transformer_blocks.14': 'cpu', 'single_transformer_blocks.15': 'cpu', 'single_transformer_blocks.16': 'cpu', 'single_transformer_blocks.17': 'cpu', 'single_transformer_blocks.18': 'cpu', 'single_transformer_blocks.19': 'cpu', 'single_transformer_blocks.20': 'cpu', 'single_transformer_blocks.21': 'cpu', 'single_transformer_blocks.22': 'cpu', 'single_transformer_blocks.23': 'cpu', 'single_transformer_blocks.24': 'cpu', 'single_transformer_blocks.25': 'cpu', 'single_transformer_blocks.26': 'cpu', 'single_transformer_blocks.27': 'cpu', 'single_transformer_blocks.28': 'cpu', 'single_transformer_blocks.29': 'cpu', 'single_transformer_blocks.30': 'cpu', 'single_transformer_blocks.31': 'cpu', 'single_transformer_blocks.32': 'cpu', 'single_transformer_blocks.33': 'cpu', 'single_transformer_blocks.34': 'cpu', 'single_transformer_blocks.35': 'cpu', 'single_transformer_blocks.36': 'cpu', 'single_transformer_blocks.37': 'cpu', 'norm_out': 'cpu', 'proj_out': 'cpu'}
```

例えば、以下の`device_map`では、`single_transformer_blocks.10`から`single_transformer_blocks.20`までを2番目のGPU(`1`)に配置します。

```py
import torch
from diffusers import AutoModel

device_map = {
    'pos_embed': 0, 'time_text_embed': 0, 'context_embedder': 0, 'x_embedder': 0, 'transformer_blocks': 0, 'single_transformer_blocks.0': 0, 'single_transformer_blocks.1': 0, 'single_transformer_blocks.2': 0, 'single_transformer_blocks.3': 0, 'single_transformer_blocks.4': 0, 'single_transformer_blocks.5': 0, 'single_transformer_blocks.6': 0, 'single_transformer_blocks.7': 0, 'single_transformer_blocks.8': 0, 'single_transformer_blocks.9': 0, 'single_transformer_blocks.10': 1, 'single_transformer_blocks.11': 1, 'single_transformer_blocks.12': 1, 'single_transformer_blocks.13': 1, 'single_transformer_blocks.14': 1, 'single_transformer_blocks.15': 1, 'single_transformer_blocks.16': 1, 'single_transformer_blocks.17': 1, 'single_transformer_blocks.18': 1, 'single_transformer_blocks.19': 1, 'single_transformer_blocks.20': 1, 'single_transformer_blocks.21': 'cpu', 'single_transformer_blocks.22': 'cpu', 'single_transformer_blocks.23': 'cpu', 'single_transformer_blocks.24': 'cpu', 'single_transformer_blocks.25': 'cpu', 'single_transformer_blocks.26': 'cpu', 'single_transformer_blocks.27': 'cpu', 'single_transformer_blocks.28': 'cpu', 'single_transformer_blocks.29': 'cpu', 'single_transformer_blocks.30': 'cpu', 'single_transformer_blocks.31': 'cpu', 'single_transformer_blocks.32': 'cpu', 'single_transformer_blocks.33': 'cpu', 'single_transformer_blocks.34': 'cpu', 'single_transformer_blocks.35': 'cpu', 'single_transformer_blocks.36': 'cpu', 'single_transformer_blocks.37': 'cpu', 'norm_out': 'cpu', 'proj_out': 'cpu'
}

transformer = AutoModel.from_pretrained(
    "black-forest-labs/FLUX.1-dev", 
    subfolder="transformer",
    device_map=device_map,
    dtype=torch.bfloat16
)
```

各デバイスの最大メモリ使用量をマッピングする辞書を渡すことで、上限を強制できます。`max_memory` にデバイスが含まれていない場合、そのデバイスは無視され、パイプラインのコンポーネントはそこに分配されません。

```py
import torch
from diffusers import AutoModel, StableDiffusionXLPipeline

max_memory = {0:"1GB", 1:"1GB"}
pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
    device_map="balanced",
    max_memory=max_memory
)
```

Diffusers はデフォルトで全デバイスの最大メモリを使用しますが、GPU に収まらない場合は、以下の方法を使用して単一の GPU を使用し、CPU へオフロードする必要があります。

- [enable_model_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_model_cpu_offload) は単一の GPU でのみ動作しますが、非常に大きなモデルは 1 つの GPU に収まらない場合があります。
- [enable_sequential_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_sequential_cpu_offload) は動作する場合がありますが、非常に低速であり、かつ単一の GPU に限定されます。

`device_map`をリセットするには、[reset_device_map()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.reset_device_map)メソッドを使用します。デバイスマップが設定されたパイプラインに対して`.to()`、[enable_sequential_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_sequential_cpu_offload)、[enable_model_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_model_cpu_offload)などのメソッドを使用する場合は、この処理が必要です。

```py
pipeline.reset_device_map()
```

## VAEスライシング

VAE slicingは、大きなバッチの入力を単一のデータバッチに分割して個別に処理することでメモリを節約します。この手法は、一度に複数の画像を生成する場合に最も効果的です。

例えば、一度に4枚の画像を生成する場合、デコードによってピーク時のアクティベーションメモリが4倍に増加します。VAEスライシングでは、4枚すべてを一度にデコードするのではなく、1枚ずつデコードすることで、この増加を軽減します。

スライスされた VAE を有効にするには、`enable_slicing()` を呼び出します。複数画像のバッチをデコードする際にパフォーマンスがわずかに向上し、単一画像のバッチではパフォーマンスへの影響はありません。

```py
import torch
from diffusers import AutoModel, StableDiffusionXLPipeline

pipeline = StableDiffusionXLPipeline.from_pretrained(
    "stabilityai/stable-diffusion-xl-base-1.0",
    dtype=torch.float16,
).to("cuda")  # or "mps", "xpu", "cpu"
pipeline.vae.enable_slicing()
pipeline(["An astronaut riding a horse on Mars"]*32).images[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
```

> [!WARNING]
> [AutoencoderKLWan](/docs/diffusers/v0.43.0/ja/api/models/autoencoder_kl_wan#diffusers.AutoencoderKLWan)クラスと[AsymmetricAutoencoderKL](/docs/diffusers/v0.43.0/ja/api/models/asymmetricautoencoderkl#diffusers.AsymmetricAutoencoderKL)クラスは、スライシングをサポートしていません。

## VAEのタイル分割

VAE tilingは、画像全体を一度に処理するのではなく、より小さな重複するタイルに分割して処理することでメモリを節約します。これにより、GPUが一度に1つのタイルのみを処理するため、ピーク時のメモリ使用量も削減されます。

`enable_tiling()` を呼び出して VAE のタイル分割を有効にします。タイルごとに個別にデコードされるため、生成された画像にはタイル間でわずかなトーンのばらつきが生じることがありますが、タイルの境界に明らかな継ぎ目が生じることはありません。解像度が事前に指定された（ただし設定可能な）閾値を下回る場合は、タイル分割は無効になります。例えば、[StableDiffusionPipeline](/docs/diffusers/v0.43.0/ja/api/pipelines/stable_diffusion/text2img#diffusers.StableDiffusionPipeline) の VAE では、この閾値は 512x512 です。

```py
import torch
from diffusers import AutoPipelineForImage2Image
from diffusers.utils import load_image

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

init_image = load_image("https://huggingface.co/datasets/huggingface/documentation-images/resolve/main/diffusers/img2img-sdxl-init.png")
prompt = "Astronaut in a jungle, cold color palette, muted colors, detailed, 8k"
pipeline(prompt, image=init_image, strength=0.5).images[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
```

> [!WARNING]
> [AutoencoderKLWan](/docs/diffusers/v0.43.0/ja/api/models/autoencoder_kl_wan#diffusers.AutoencoderKLWan) と [AsymmetricAutoencoderKL](/docs/diffusers/v0.43.0/ja/api/models/asymmetricautoencoderkl#diffusers.AsymmetricAutoencoderKL) は、タイル分割をサポートしていません。

GPU上のVAEメモリを完全にスキップするには、[Remote inference](../hybrid_inference/overview)でリモートエンドポイント上でエンコードとデコードを実行します。

## オフローディング

オフローディング戦略では、現在アクティブでないレイヤーやモデルをCPUに移動し、GPUメモリを増加させないようにします。これらの戦略は、量子化やtorch.compileと組み合わせることで、推論速度とメモリ使用量のバランスを取ることができます。

詳細については、[Compile and offloading quantized models](./speed-memory-optims)ガイドを参照してください。

### CPUオフロード

CPU offloadingは、重みをGPUからCPUへ選択的に移動します。コンポーネントが必要になったときにGPUへ転送し、不要になったときにCPUへ移動します。この手法は、モデル全体ではなくサブモジュール単位で動作します。モデル全体をGPU上に保持することを避けることで、メモリを節約します。

CPU offloadingはメモリ使用量を大幅に削減しますが、サブモジュールがデバイス間で何度もやり取りされるため、**非常に遅い**です。その遅さゆえに、実用的でない場合もよくあります。

> [!WARNING]
> [enable_sequential_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_sequential_cpu_offload)を呼び出す前に、パイプラインをCUDAに移動しないでください。そうしないと、メモリ削減の効果がほとんど得られません（詳細はこの[issue](https://github.com/huggingface/diffusers/issues/1934)を参照してください）。これはステートフルな操作であり、モデルにフックをインストールします。

パイプラインでこれを有効にするには、[enable_sequential_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_sequential_cpu_offload)を呼び出します。

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-schnell", dtype=torch.bfloat16
)
pipeline.enable_sequential_cpu_offload()

pipeline(
    prompt="An astronaut riding a horse on Mars",
    guidance_scale=0.,
    height=768,
    width=1360,
    num_inference_steps=4,
    max_sequence_length=256,
).images[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
```

### モデルのオフロード

Model offloading moves entire models to the GPU instead of selectively moving *some* layers or model components. One of the main pipeline models, usually the text encoder, UNet, and VAE, is placed on the GPU while the other components are held on the CPU. Components like the UNet that run multiple times stays on the GPU until its completely finished and no longer needed. This eliminates the communication overhead of [CPU offloading](#cpu-offloading) and makes model offloading a faster alternative. The tradeoff is memory savings won't be as large.

> [!WARNING]
> フックがインストールされた後、パイプラインの外でモデルが再利用される場合（詳細は[フックの削除](https://huggingface.co/docs/accelerate/en/package_reference/big_modeling#accelerate.hooks.remove_hook_from_module)を参照）、モデルを適切にオフロードするには、パイプライン全体とモデルを想定された順序で実行する必要があります。これはモデルにフックをインストールする状態付きの操作です。

パイプラインでこれを有効にするには、[enable_model_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_model_cpu_offload)を呼び出します。

```py
import torch
from diffusers import DiffusionPipeline

pipeline = DiffusionPipeline.from_pretrained(
    "black-forest-labs/FLUX.1-schnell", dtype=torch.bfloat16
)
pipeline.enable_model_cpu_offload()

pipeline(
    prompt="An astronaut riding a horse on Mars",
    guidance_scale=0.,
    height=768,
    width=1360,
    num_inference_steps=4,
    max_sequence_length=256,
).images[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
```

[enable_model_cpu_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_model_cpu_offload) は、[encode_prompt()](/docs/diffusers/v0.43.0/ja/api/pipelines/stable_diffusion/stable_diffusion_xl#diffusers.StableDiffusionXLPipeline.encode_prompt) メソッドを単独で使用してテキストエンコーダーの隠れ状態を生成する場合にも役立ちます。

### グループオフローディング

Group offloadingは、内部レイヤーのグループ（[torch.nn.ModuleList](https://pytorch.org/docs/stable/generated/torch.nn.ModuleList.html)または[torch.nn.Sequential](https://pytorch.org/docs/stable/generated/torch.nn.Sequential.html)）をCPUに移動します。[model offloading](#model-offloading)よりもメモリ使用量が少なく、通信オーバーヘッドを削減できるため、[CPU offloading](#cpu-offloading)よりも高速です。

> [!WARNING]
> グループオフロードは、フォワード実装が重みに依存する入力のデバイスキャストを含む場合、すべてのモデルで動作しない可能性があります。これは、グループオフロードのデバイスキャスト機構と競合する可能性があるためです。

`offload_type` パラメータを `block_level` または `leaf_level` に設定することで、グループオフロードを有効にできます。

- `block_level` は、`num_blocks_per_group` パラメータに基づいてレイヤーのグループをオフロードします。例えば、40 レイヤーのモデルで `num_blocks_per_group=2` の場合、一度に 2 レイヤーがオンロードおよびオフロードされます（オンロード/オフロードの総数は 20 回）。これにより、メモリ要件が大幅に削減されます。
- `leaf_level` は最下位レベルで個々のレイヤーをオフロードし、[CPU オフロード](#cpu-offloading) と同等です。ただし、推論速度を犠牲にすることなくストリームを使用することで、より高速にできます。

グループオフロードは、パイプライン全体または個々のモデルに対して適用できます。パイプライン全体にグループオフロードを適用するのが最も簡単ですが、個々のモデルに対して選択的に適用することで、ユーザーはモデルごとに異なるオフロード手法を使用する柔軟性を得られます。

パイプラインで[enable_group_offload()](/docs/diffusers/v0.43.0/ja/api/pipelines/overview#diffusers.DiffusionPipeline.enable_group_offload)を呼び出します。

```py
import torch
from diffusers import CogVideoXPipeline
from diffusers.hooks import apply_group_offloading
from diffusers.utils import export_to_video

onload_device = torch.device("cuda")
offload_device = torch.device("cpu")

pipeline = CogVideoXPipeline.from_pretrained("THUDM/CogVideoX-5b", dtype=torch.bfloat16)
pipeline.enable_group_offload(
    onload_device=onload_device,
    offload_device=offload_device,
    offload_type="leaf_level",
    use_stream=True
)

prompt = (
    "A panda, dressed in a small, red jacket and a tiny hat, sits on a wooden stool in a serene bamboo forest. "
    "The panda's fluffy paws strum a miniature acoustic guitar, producing soft, melodic tunes. Nearby, a few other "
    "pandas gather, watching curiously and some clapping in rhythm. Sunlight filters through the tall bamboo, "
    "casting a gentle glow on the scene. The panda's face is expressive, showing concentration and joy as it plays. "
    "The background includes a small, flowing stream and vibrant green foliage, enhancing the peaceful and magical "
    "atmosphere of this unique musical performance."
)
video = pipeline(prompt=prompt, guidance_scale=6, num_inference_steps=50).frames[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
export_to_video(video, "output.mp4", fps=8)
```

[ModelMixin](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin) を継承する標準的な Diffusers のモデルコンポーネントに対して [enable_group_offload()](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin.enable_group_offload) を呼び出します。[ModelMixin](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin) を継承しない他のモデルコンポーネント、例えば汎用的な [torch.nn.Module](https://pytorch.org/docs/stable/generated/torch.nn.Module.html) には、代わりに [apply_group_offloading()](/docs/diffusers/v0.43.0/ja/api/utilities#diffusers.hooks.apply_group_offloading) を使用します。

```py
import torch
from diffusers import CogVideoXPipeline
from diffusers.hooks import apply_group_offloading
from diffusers.utils import export_to_video

onload_device = torch.device("cuda")
offload_device = torch.device("cpu")
pipeline = CogVideoXPipeline.from_pretrained("THUDM/CogVideoX-5b", dtype=torch.bfloat16)

# Use the enable_group_offload method for Diffusers model implementations
pipeline.transformer.enable_group_offload(onload_device=onload_device, offload_device=offload_device, offload_type="leaf_level")
pipeline.vae.enable_group_offload(onload_device=onload_device, offload_type="leaf_level")

# Use the apply_group_offloading method for other model components
apply_group_offloading(pipeline.text_encoder, onload_device=onload_device, offload_type="block_level", num_blocks_per_group=2)

prompt = (
    "A panda, dressed in a small, red jacket and a tiny hat, sits on a wooden stool in a serene bamboo forest. "
    "The panda's fluffy paws strum a miniature acoustic guitar, producing soft, melodic tunes. Nearby, a few other "
    "pandas gather, watching curiously and some clapping in rhythm. Sunlight filters through the tall bamboo, "
    "casting a gentle glow on the scene. The panda's face is expressive, showing concentration and joy as it plays. "
    "The background includes a small, flowing stream and vibrant green foliage, enhancing the peaceful and magical "
    "atmosphere of this unique musical performance."
)
video = pipeline(prompt=prompt, guidance_scale=6, num_inference_steps=50).frames[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
export_to_video(video, "output.mp4", fps=8)
```

#### CUDA ストリーム

CUDA デバイスで非同期データ転送ストリームがサポートされている場合、`use_stream` パラメータを有効にすることで、[CPU オフロード](#cpu-offloading)と比較して全体の実行時間を短縮できます。レイヤープリフェッチを使用して、データ転送と計算をオーバーラップさせます。現在のレイヤーの実行中に、次に実行するレイヤーを GPU に読み込みます。CPU メモリが大幅に増加する可能性があるため、モデルサイズの 2 倍のメモリを確保してください。

メモリ使用量がわずかに増加する代わりに、より大きな高速化を得るには、`record_stream=True` を設定してください。詳細については、[torch.Tensor.record_stream](https://pytorch.org/docs/stable/generated/torch.Tensor.record_stream.html) のドキュメントを参照してください。

> [!TIP]
> タイル分割を有効にした VAE で `use_stream=True` を使用する場合、デバイス不一致エラーを回避するために、推論の前にダミーのフォワードパス（ダミー入力でも可）を実行してください。すべての実装で動作するとは限らないため、問題が発生した場合は、お気軽に issue を作成してください。

`block_level` グループオフローディングを使用し、`use_stream` を有効にしている場合、`num_blocks_per_group` パラメータは `1` に設定する必要があります。そうしないと、警告が発生します。

```py
pipeline.transformer.enable_group_offload(onload_device=onload_device, offload_device=offload_device, offload_type="leaf_level", use_stream=True, record_stream=True)
```

`low_cpu_mem_usage` パラメータを `True` に設定すると、グループオフローディング時にストリームを使用している場合の CPU メモリ使用量を削減できます。`leaf_level` オフローディングや、CPU メモリがボトルネックになっている場合に特に有効です。ピン留めされたテンソルを事前に作成するのではなく、必要に応じてピン留めされたテンソルを動的に作成することでメモリを節約します。ただし、これにより全体の実行時間が長くなる可能性があります。

#### ディスクへのオフロード

Group offloading はモデルサイズによって、システムメモリを大量に消費する可能性があります。メモリが限られているシステムでは、セカンダリメモリとしてディスクへの group offloading を試してください。

モデルをディスクにオフロードするには、[enable_group_offload()](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin.enable_group_offload) または [apply_group_offloading()](/docs/diffusers/v0.43.0/ja/api/utilities#diffusers.hooks.apply_group_offloading) のいずれかで `offload_to_disk_path` 引数を設定します。

```py
pipeline.transformer.enable_group_offload(onload_device=onload_device, offload_device=offload_device, offload_type="leaf_level", offload_to_disk_path="path/to/disk")

apply_group_offloading(pipeline.text_encoder, onload_device=onload_device, offload_type="block_level", num_blocks_per_group=2, offload_to_disk_path="path/to/disk")
```

速度とメモリ使用量のトレードオフを比較するには、これらの[2つの](https://github.com/huggingface/diffusers/pull/11682#issue-3129365363)[テーブル](https://github.com/huggingface/diffusers/pull/11682#issuecomment-2955715126)を参照してください。

## レイヤーごとのキャスト

> [!TIP]
> レイヤーごとのキャストを[グループオフローディング](#group-offloading)と組み合わせることで、さらにメモリを節約できます。

Layerwise castingは、重みをより小さいデータ形式（例えば、`torch.float8_e4m3fn`や`torch.float8_e5m2`）で保存することでメモリ使用量を削減し、計算時には`torch.float16`や`torch.bfloat16`などの高精度な形式にアップキャストします。正規化やモジュレーションに関連する重みを含む特定のレイヤーは、fp8で保存すると生成品質が低下する可能性があるため、スキップされます。

> [!WARNING]
> レイヤーワイズキャストは、フォワード実装が重みの内部型キャストを含む場合、すべてのモデルで動作しない可能性があります。現在のレイヤーワイズキャストの実装は、フォワードパスが重みの精度に依存しないこと、および入力データ型が常に`compute_dtype`で指定されることを前提としています（非互換な実装の例は[こちら](https://github.com/huggingface/transformers/blob/7f5077e53682ca855afc826162b204ebf809f1f9/src/transformers/models/t5/modeling_t5.py#L294-L299)を参照）。
>
> [PEFT](https://huggingface.co/docs/peft/index)レイヤーを含むカスタムモデリング実装では、レイヤーごとのキャストが失敗する可能性があります。いくつかのチェックは用意されていますが、これらは十分にテストされておらず、すべてのケースで動作が保証されるものではありません。

[enable_layerwise_casting()](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin.enable_layerwise_casting)を呼び出して、ストレージと計算のデータ型を設定します。

```py
import torch
from diffusers import CogVideoXPipeline, CogVideoXTransformer3DModel
from diffusers.utils import export_to_video

transformer = CogVideoXTransformer3DModel.from_pretrained(
    "THUDM/CogVideoX-5b",
    subfolder="transformer",
    dtype=torch.bfloat16
)
transformer.enable_layerwise_casting(storage_dtype=torch.float8_e4m3fn, compute_dtype=torch.bfloat16)

pipeline = CogVideoXPipeline.from_pretrained("THUDM/CogVideoX-5b",
    transformer=transformer,
    dtype=torch.bfloat16
).to("cuda")  # or "mps", "xpu", "cpu"
prompt = (
    "A panda, dressed in a small, red jacket and a tiny hat, sits on a wooden stool in a serene bamboo forest. "
    "The panda's fluffy paws strum a miniature acoustic guitar, producing soft, melodic tunes. Nearby, a few other "
    "pandas gather, watching curiously and some clapping in rhythm. Sunlight filters through the tall bamboo, "
    "casting a gentle glow on the scene. The panda's face is expressive, showing concentration and joy as it plays. "
    "The background includes a small, flowing stream and vibrant green foliage, enhancing the peaceful and magical "
    "atmosphere of this unique musical performance."
)
video = pipeline(prompt=prompt, guidance_scale=6, num_inference_steps=50).frames[0]
print(f"Max memory reserved: {torch.cuda.max_memory_allocated() / 1024**3:.2f} GB")
export_to_video(video, "output.mp4", fps=8)
```

より細かな制御と柔軟性が必要な場合は、[apply_layerwise_casting()](/docs/diffusers/v0.43.0/ja/api/utilities#diffusers.hooks.apply_layerwise_casting) メソッドも使用できます。特定の内部モジュールに対して呼び出すことで、モデルのレイヤーに部分的に適用できます。正規化レイヤーやモジュレーションレイヤーなど、回避するモジュールを指定するには、`skip_modules_pattern` または `skip_modules_classes` パラメータを使用します。

```python
import torch
from diffusers import CogVideoXTransformer3DModel
from diffusers.hooks import apply_layerwise_casting

transformer = CogVideoXTransformer3DModel.from_pretrained(
    "THUDM/CogVideoX-5b",
    subfolder="transformer",
    dtype=torch.bfloat16
)

# skip the normalization layer
apply_layerwise_casting(
    transformer,
    storage_dtype=torch.float8_e4m3fn,
    compute_dtype=torch.bfloat16,
    skip_modules_classes=["norm"],
    non_blocking=True,
)
```

## torch.channels_last

[torch.channels_last](https://pytorch.org/tutorials/intermediate/memory_format_tutorial.html) は、テンソルの保存形式を `(batch size, channels, height, width)` から `(batch size, height, width, channels)` に反転します。これにより、テンソルはメモリに保存されたテンソルにハードウェアがシーケンシャルにアクセスする方式と整合し、メモリ内でピクセル値にアクセスするために前後に飛び回ることを回避できます。

現在、すべてのオペレーターが channels-last 形式をサポートしているわけではなく、パフォーマンスが最悪になる場合もありますが、試してみる価値はあります。

```py
print(pipeline.unet.conv_out.state_dict()["weight"].stride())  # (2880, 9, 3, 1)
pipeline.unet.to(memory_format=torch.channels_last)  # in-place operation
print(
    pipeline.unet.conv_out.state_dict()["weight"].stride()
)  # (2880, 1, 960, 320) having a stride of 1 for the 2nd dimension proves that it works
```

## メモリ効率の高いアテンション

Diffusers は [set_attention_backend()](/docs/diffusers/v0.43.0/ja/api/models/overview#diffusers.ModelMixin.set_attention_backend) を通じて、複数のメモリ効率に優れたアテンションバックエンド（FlashAttention、xFormers、SageAttention など）をサポートしています。切り替え方については、[Attention backends](./attention_backends) ガイドを参照してください。

