PyTorch FSDP の「optim_state_dict」関数:詳細解説とサンプルコード


torch.distributed.fsdp.FullyShardedDataParallel.optim_state_dict() は、"Fully Sharded Data Parallel" (FSDP) トレーニングで使用される重要な関数です。この関数は、分散化された最適化ステート دیکショナリーを生成し、モデルのパラメータを更新するために使用されます。

詳細

FSDP は、大規模なモデルを複数の TPU または GPU に分散してトレーニングするための PyTorch ライブラリです。 torch.distributed.fsdp.FullyShardedDataParallel は、FSDP トレーニングの中核となるクラスであり、モデルのパラメータをシャード化し、各ワーカーに分散させる役割を担います。

optim_state_dict() 関数は、モデルのパラメータと最適化アルゴリズムの状態をカプセル化した辞書を生成します。この辞書は、モデルのチェックポイント保存や、異なるデバイス間でのモデルのロードに使用されます。

FSDP トレーニングでは、各ワーカーはモデルのパラメータの一部のみを保持します。そのため、optim_state_dict() 関数は、各ワーカーが保持するパラメータの状態のみを含む分散化されたステート دیکショナリーを生成する必要があります。

import torch
import torch.distributed as dist
import torch.distributed.fsdp as fsdp

model = ...  # モデルを定義
optimizer = ...  # オプティマイザを定義

fsdp = fsdp.FullyShardedDataParallel(model, optimizer=optimizer)

# モデルを訓練
...

# 分散化されたステート دیکショナリーを取得
optim_state_dict = fsdp.optim_state_dict()

# ステート دیکショナリーを保存
torch.save(optim_state_dict, "checkpoint.optim")
  • optim_state_dict() 関数は、FSDP トレーニング専用の関数です。標準の PyTorch トレーニングでは使用できません。
  • 分散化されたステート دیکショナリーをロードするには、optim_state_dict_to_load() 関数を使用する必要があります。
  • optim_state_dict() 関数は、モデルのパラメータの状態のみを含むステート دیکショナリーを生成します。モデルのすべての状態を取得するには、state_dict() 関数を使用する必要があります。


コード

import torch
import torch.distributed as dist
import torch.distributed.fsdp as fsdp

# モデルを定義
model = torch.nn.Sequential(
    torch.nn.Linear(10, 64),
    torch.nn.ReLU(),
    torch.nn.Linear(64, 10),
)

# オプティマイザを定義
optimizer = torch.optim.SGD(model.parameters(), lr=0.01)

# FSDP を初期化
fsdp = fsdp.FullyShardedDataParallel(model, optimizer=optimizer)

# モデルを訓練
for _ in range(10):
    # データを取得
    x = torch.randn(10, 10)
    y = torch.randn(10)

    # モデルを推論
    output = fsdp(x)

    # 損失を計算
    loss = (output - y).pow(2).mean()

    # 勾配を計算
    loss.backward()

    # パラメータを更新
    optimizer.step()

# 分散化されたステート دیکショナリーを取得
optim_state_dict = fsdp.optim_state_dict()

# ステート دیکショナリーを保存
torch.save(optim_state_dict, "checkpoint.optim")

説明

このコードは、以下の手順を実行します。

  1. モデルとオプティマイザを定義します。
  2. FSDP を初期化します。
  3. モデルを訓練します。
  4. 分散化されたステート دیکショナリーを取得します。
  5. ステート دیکショナリーを保存します。

このコードは、FSDP トレーニングにおける optim_state_dict() 関数の基本的な使用方法を示しています。実際の使用例では、モデルやオプティマイザの設定が異なる場合があります。

  • 詳細については、PyTorch FSDP ドキュメントを参照してください。
  • 分散化されたトレーニングを実行するには、複数の GPU または TPU を使用し、torch.distributed モジュールを使用して初期化する必要があります。
  • このコードは、単一の GPU または TPU で実行できます。


しかしながら、状況によっては、この関数の代替方法が必要になる場合があります。 以下、代替方法の選択肢とそれぞれの利点・欠点をご紹介します。

個別の状態 دیکショナリーをマージする

各 FSDP ユニットから個別に state_dict() を取得し、それらをマージすることで、分散化されたステート دیکショナリーを構築できます。

利点

  • 柔軟性が高い
  • シンプルで理解しやすい

欠点

  • パフォーマンスが劣化する可能性がある
  • コードが煩雑になる可能性がある

コード例

import torch
import torch.distributed as dist
import torch.distributed.fsdp as fsdp

model = ...  # モデルを定義
optimizer = ...  # オプティマイザを定義

fsdp = fsdp.FullyShardedDataParallel(model, optimizer=optimizer)

# 各 FSDP ユニットから `state_dict()` を取得
optim_state_dicts = []
for unit in fsdp.all_units:
    optim_state_dicts.append(unit.optimizer.state_dict())

# 分散化されたステート دیکショナリーを構築
global_optim_state_dict = {}
for local_state_dict in optim_state_dicts:
    for key, value in local_state_dict.items():
        if key not in global_optim_state_dict:
            global_optim_state_dict[key] = []
        global_optim_state_dict[key].append(value)

# ステート دیکショナリーをマージ
for key, value_list in global_optim_state_dict.items():
    global_optim_state_dict[key] = torch.stack(value_list)

「SHARDED_STATE_DICT」を使用する

FSDP v0.22.0 以降では、SHARDED_STATE_DICT という新しいステート دیکショナリー タイプが導入されました。このタイプを使用すると、FSDP が分散化されたステート دیکショナリーを自動的に生成してくれます。

利点

  • パフォーマンスが向上する可能性がある
  • コードが簡潔になる

欠点

  • すべての状況で利用可能とは限らない
  • 新しいバージョンの FSDP が必要

コード例

import torch
import torch.distributed as dist
import torch.distributed.fsdp as fsdp
from accelerate import Accelerator

accelerator = Accelerator(state_dict_type="SHARDED_STATE_DICT")

model = ...  # モデルを定義
optimizer = ...  # オプティマイザを定義

fsdp = fsdp.FullyShardedDataParallel(model, optimizer=optimizer)

# モデルを訓練
...

# 分散化されたステート دیکショナリーを取得
optim_state_dict = accelerator.state_dict["optimizer"]

# ステート دیکショナリーを保存
torch.save(optim_state_dict, "checkpoint.optim")

サードパーティ製のライブラリを使用する

分散化されたステート دیکショナリーを扱うためのサードパーティ製のライブラリもいくつか存在します。

利点

  • FSDP に特化した機能を提供している場合がある
  • 既存のコードを流用できる可能性がある

欠点

  • メンテナンスされていない場合がある
  • ライブラリの使用方法を習得する必要がある

最適な代替方法の選択

最適な代替方法は、状況によって異なります。 以下の要素を考慮する必要があります。

  • 開発者の経験
  • パフォーマンス要件
  • モデルの複雑性
  • FSDP のバージョン