PyTorch Ignite 0.4.8 : ガイド : pure PyTorch コードを Ignite に変換する方法

PyTorch Ignite 0.4.8 : How To ガイド : pure PyTorch コードを Ignite に変換する方法 (翻訳/解説)

翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 03/09/2022 (0.4.8)

* 本ページは、Pytorch Ignite AI の以下のドキュメントを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

クラスキャット 人工知能 研究開発支援サービス

クラスキャット は人工知能・テレワークに関する各種サービスを提供しています。お気軽にご相談ください :

◆ 人工知能とビジネスをテーマに WEB セミナーを定期的に開催しています。スケジュール
  • お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。

お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。

  • 株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション
  • sales-info@classcat.com  ;  Web: www.classcat.com  ;   ClassCatJP

 

ガイド : pure PyTorch コードを Ignite に変換する方法

このガイドでは、PyTorch コード・コンポーネントがどのようにコンパクトで柔軟な PyTorch-Ignite コードに変換できるかを示します。

Ignite は訓練と検証パイプラインにフォーカスしていますので、モデル, データセット, optimizer 等のためのコードはユーザ定義されて pure PyTorch 内のままです。

model = ...
train_loader = ...
val_loader = ...
optimizer = ...
criterion = ...

 

訓練ループをトレーナーへ

典型的な PyTorch 訓練ループは下記のようにデータの単一バッチを処理し、それをモデルに渡して、損失を計算する等を行ないます :

for batch in train_loader:
    model.train()
    inputs, targets = batch
    optimizer.zero_grad()
    outputs = model(inputs)
    loss = criterion(outputs, targets)
    loss.backward()
    optimizer.step()

上記のコードを Ignite に変換するには、訓練の間にデータの単一バッチを処理するために取られるコードあるいはステップを関数 (下の train_step()) の下に移動する必要があります。この関数は引数としてエンジンとバッチ (データの現在のバッチ) を取り、そして engine.state.output を通してアクセス可能な任意のデータ (通常は損失) を返すことができます。この関数を Engine に渡します、これは trainer オブジェクトを作成します。

from ignite.engine import Engine


def train_step(engine, batch):
    model.train()
    inputs, targets = batch
    optimizer.zero_grad()
    outputs = model(inputs)
    loss = criterion(outputs, targets)
    loss.backward()
    optimizer.step()
    return loss.item()


trainer = Engine(train_step)

教師あり訓練truncated backprop through time のような幾つかの共通のユースケースについてはカスタム関数を書くことなしに trainer オブジェクトを直接作成する他の ヘルパーメソッド があります。

 

検証ループを evaluator へ

検証ループは典型的には以下のように val_loader 上でバッチ毎に予測 (下では y_pred) を行ない、それを使用して評価メトリクス (Accuracy, Intersection over Union 等) を計算します :

model.eval()
num_correct = 0
num_examples = 0

for batch in val_loader:
    x, y = batch
    y_pred = model(x)

    correct = torch.eq(torch.round(y_pred).type(y.type()), y).view(-1)
    num_correct = torch.sum(correct).item()
    num_examples = correct.shape[0]
    print(f"Epoch: {epoch},  Accuracy: {num_correct / num_examples}")

これを、検証とメトリクスのロジックに分割することで 2 つのステップで Ignite に変換します。モデル評価ロジックは別の関数 (下では validation_step) に移します、これは train_step() と同じパラメータを受け取りデータの単一バッチを処理して engine.state.output にストアされるある出力 (通常はメトリクスを計算するために使用できる予測値と実際の値) を返します。Engine の別のインスタンス (下では evaluator と呼称) は validation_step() 関数を渡すことにより作成されます。

def validation_step(engine, batch):
    model.eval()
    with torch.no_grad():
        x, y = batch
        y_pred = model(x)

    return y_pred, y
    
    
evaluator = Engine(validation_step)

訓練ループと同様に、このカスタム評価関数を書くことを回避するために create_supervised_evaluator のような ヘルパーメソッド があります。

Note: 訓練、検証とテストのために (それらが異なる目的のためにサーブするのであれば) 異なる evaluator を作成できます。コモンプラクティスは訓練と検証のために 2 つの別個の evaluator を持つことです、検証 evaluator の結果は訓練後にセーブする最良モデルを決定するのに役立つからです。

 

組み込みメトリクスに切り替える

それから精度のようなメトリクスを計算するコードを置き換えて、代わりに Ignite が提供する幾つかの out-of-the-box なメトリクス を使用するか、カスタムのものを書くことができます (ここ を参照)。メトリクスは evaluator の出力を使用して計算されます。最後に、これらのメトリクスをキー名 (下では “accuracy”) を提供して evaluator に装着しますので、それらは engine.state.metrics[key_name] を通してアクセス可能です。

from ignite.metrics import Accuracy

Accuracy().attach(evaluator, "accuracy")

 

コードをイベントとハンドラに体系化する

次に、イベントが発生したときにトリガーされる任意のコードを特定する必要があります。イベントの例はイテレーションの開始、エポックの完了、あるいは逆伝播の開始です。幾つかの事前定義されたイベント (完全なリストは こちら) を既に提供していますが、カスタムイベントを作成することもできます (こちら を参照)。イベント固有のコードを異なるハンドラ (名前付き関数, lambda, クラス関数) に移します、これらはこれらのイベントに装着されて特定のイベントが発生するたびに実行されます。ここに幾つかの一般的なハンドラがあります :

 

evaluator の実行

validate_every エポックの後に evaluator を訓練/検証/テストデータセットで実行するコードを変換できます :

if epoch % validate_every == 0:
    # Validation logic

次のように組み込みイベント EPOCH_COMPLETED にハンドラを装着します :

from ignite.engine import Events

validate_every = 10


@trainer.on(Events.EPOCH_COMPLETED(every=validate_every))
def run_validation():
    evaluator.run(val_loader)

 

メトリクスのロギング

同様に、別のハンドラで検証メトリクスをログ記録するか上記のハンドラとそれ連結できます。

@trainer.on(Events.EPOCH_COMPLETED(every=validate_every))
def log_validation():
    metrics = evaluator.state.metrics
    print(f"Epoch: {trainer.state.epoch},  Accuracy: {metrics['accuracy']}")

 

Progress Bar

ProgressBar() と呼ばれる tqdm 回りの組み込みラッパーを使用します。

from ignite.contrib.handlers import ProgressBar

ProgressBar().attach(trainer)

 

チェックポインティング

総てのモデルをセーブする代わりに checkpoint_every エポック後に :

if epoch % checkpoint_every == 0:
    checkpoint(model, optimizer, "checkpoint_dir")

組み込み Checkpoint() を通して (evaluator.state.metrics に依存して) ベストな n_saved 個のモデル, optimizer と trainer の状態をスマートにセーブすることができます。

from ignite.handlers import Checkpoint

checkpoint_every = 5
checkpoint_dir = ...


checkpointer = Checkpoint(
    to_save={'model': model, 'optimizer': optimizer, 'trainer': trainer},
    save_handler=checkpoint_dir, n_saved=2
)
trainer.add_event_handler(
    Events.EPOCH_COMPLETED(every=checkpoint_every), checkpointer
)

 

エポック数の実行

最後に、次の代わりに :

max_epochs = ...

for epoch in range(max_epochs):

以下を通して train_loader 上で訓練を開始します :

trainer.run(train_loader, max_epochs)

An end-to-end example implementing the above principles can be found here.

 

以上