PyTorchでモデルを訓練する:TorchScript ScriptModule.train()メソッドの包括的なチュートリアル

2024-06-04

PyTorch の Torch Script における torch.jit.ScriptModule.train() の詳細解説

torch.jit.ScriptModule.train() は、PyTorch の Torch Script における重要なメソッドの一つです。このメソッドは、モデルをトレーニングモードに切り替え、勾配計算を有効にします。つまり、モデルのパラメータを更新するために必要な勾配情報を計算できるようにします。

使用方法

このメソッドは、ScriptModule インスタンスに対して呼び出されます。構文は次のとおりです。

module.train()

ここで、module はトレーニング対象の ScriptModule インスタンスです。

動作

train() メソッドが呼び出されると、ScriptModule インスタンス内のすべての BatchNorm 層と Dropout 層がトレーニングモードに切り替えられます。

  • BatchNorm 層: トレーニングモードでは、BatchNorm 層は統計情報を更新し、バッチ正規化を実行します。
  • Dropout 層: トレーニングモードでは、Dropout 層はランダムなユニットをドロップアウトします。

次の例は、シンプルなモデルをトレーニングモードに切り替える方法を示しています。

import torch
import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super().__init__()
        self.fc1 = nn.Linear(10, 20)
        self.bn1 = nn.BatchNorm1d(20)
        self.fc2 = nn.Linear(20, 10)

model = MyModel()

# トレーニングモードに切り替える
model.train()

# モデルに入力とターゲットを渡す
input = torch.randn(10, 20)
target = torch.randn(10, 10)

# モデルを出力する
output = model(input)

# 損失を計算してバックプロパゲートする
loss = nn.MSELoss()(output, target)
loss.backward()

補足

  • train() メソッドは、モデルの評価モードを切り替える eval() メソッドと対照的なものです。
  • train() メソッドは、モデルがトレーニングされていることを示すフラグを設定します。このフラグは、BatchNorm 層や Dropout 層などのモジュールで使用されます。
  • train() メソッドは、モデルのパラメータの更新を制御しません。パラメータの更新は、optimizer.step() メソッドを使用して行われます。


    この例は、シンプルなモデルをトレーニングモードに切り替え、勾配計算を有効にする方法を示しています。

    import torch
    import torch.nn as nn
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # トレーニングモードに切り替える
    model.train()
    
    # モデルに入力とターゲットを渡す
    input = torch.randn(10, 20)
    target = torch.randn(10, 10)
    
    # モデルを出力する
    output = model(input)
    
    # 損失を計算してバックプロパゲートする
    loss = nn.MSELoss()(output, target)
    loss.backward()
    

    カスタムモジュールのトレーニング

    この例は、カスタムモジュールをトレーニングモードに切り替える方法を示しています。

    import torch
    import torch.nn as nn
    
    class MyCustomModule(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
    
        def forward(self, input):
            output = self.fc1(input)
            output = self.bn1(output)
            return output
    
    model = MyModel()
    model.custom_module = MyCustomModule()
    
    # トレーニングモードに切り替える
    model.train()
    
    # モデルに入力とターゲットを渡す
    input = torch.randn(10, 20)
    target = torch.randn(10, 10)
    
    # モデルを出力する
    output = model(input)
    
    # 損失を計算してバックプロパゲートする
    loss = nn.MSELoss()(output, target)
    loss.backward()
    

    モデルの保存とロード

    この例は、トレーニング済みのモデルを保存してロードする方法を示しています。

    import torch
    import torch.nn as nn
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # トレーニングモードに切り替える
    model.train()
    
    # モデルに入力とターゲットを渡す
    input = torch.randn(10, 20)
    target = torch.randn(10, 10)
    
    # モデルを出力する
    output = model(input)
    
    # 損失を計算してバックプロパゲートする
    loss = nn.MSELoss()(output, target)
    loss.backward()
    
    # モデルを保存する
    torch.jit.save(model, "my_model.pt")
    
    # モデルをロードする
    loaded_model = torch.jit.load("my_model.pt")
    
    # モデルに入力とターゲットを渡す
    input = torch.randn(10, 20)
    target = torch.randn(10, 10)
    
    # モデルを出力する
    output = loaded_model(input)
    
    # 損失を計算してバックプロパゲートする
    loss = nn.MSELoss()(output, target)
    loss.backward()
    

    トレーニングループ

    この例は、トレーニングループを実装する方法を示しています。

    import torch
    import torch.nn as nn
    import torch.optim as optim
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # オプティマイザを作成する
    optimizer = optim.Adam
    


    torch.jit.ScriptModule.train() の代替方法

    with torch.no_grad(): コンテキストマネージャーを使用すると、コードブロック内では勾配計算が無効化されます。これは、モデルを評価モードに切り替える効果と同じです。

    import torch
    import torch.nn as nn
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # モデルを評価モードに切り替える
    with torch.no_grad():
        # モデルに入力とターゲットを渡す
        input = torch.randn(10, 20)
        target = torch.randn(10, 10)
    
        # モデルを出力する
        output = model(input)
    
        # 損失を計算する
        loss = nn.MSELoss()(output, target)
    
    # 勾配計算を有効にする
    model.train()
    

    model.eval() メソッドは、モデルを評価モードに切り替えます。これは、with torch.no_grad(): コンテキストマネージャーと同じ効果です。

    import torch
    import torch.nn as nn
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # モデルを評価モードに切り替える
    model.eval()
    
    # モデルに入力とターゲットを渡す
    input = torch.randn(10, 20)
    target = torch.randn(10, 10)
    
    # モデルを出力する
    output = model(input)
    
    # 損失を計算する
    loss = nn.MSELoss()(output, target)
    

    model.requires_grad = False を設定すると、モデルのパラメータに対して勾配計算が行われなくなります。これは、モデルを評価モードに切り替える効果と同じです。

    import torch
    import torch.nn as nn
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # モデルのパラメータに対して勾配計算を行わないように設定する
    for param in model.parameters():
        param.requires_grad = False
    
    # モデルに入力とターゲットを渡す
    input = torch.randn(10, 20)
    target = torch.randn(10, 10)
    
    # モデルを出力する
    output = model(input)
    
    # 損失を計算する
    loss = nn.MSELoss()(output, target)
    

    torch.jit.trace() を使用すると、モデルのトレースを作成できます。このトレースは、モデルを評価モードに切り替えた後でも、モデルの出力を計算するために使用できます。

    import torch
    import torch.nn as nn
    import torch.jit
    
    class MyModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.fc1 = nn.Linear(10, 20)
            self.bn1 = nn.BatchNorm1d(20)
            self.fc2 = nn.Linear(20, 10)
    
    model = MyModel()
    
    # モデルのトレースを作成する
    input = torch.randn(1, 10)
    trace = torch.jit.trace(model, input)
    
    # モデルを