ぶつりやAI

物理屋の視点から、原理原則を大事に、ディープラーニングのわかり易い説明を心がけています。

【実践基礎10】PyTorchでモデルを訓練する方法|GPU・DataLoader・訓練ループを体系的に理解

前の記事  


<概要>

GPU + PyTorchを使った教師ありのミニバッチ学習の仕方を説明します。

全体の構造についてフォーカスし、モデルの本体のモジュールクラスやDataLoader等の各論については<関連記事>を参照してください。

細かい設定、例えば torch.optim.lr_scheduler による学習率の管理などは触れません。

<関連記事>

<インポート>

import os
import torch
import torch.nn as nn

ディレクトリ構成

実際のプロジェクトでは、「モデルの定義」や「データの読み込み処理」を別ファイルに分けることで、コードの見通しが良くなり、再利用もしやすくなります。

本記事ではこれらが model.pydataloader.py に記述されているものと仮定し、訓練ループに重点を置きます。

学習を行う本体のコードは以下の train.py にかかれているものとします。

project/
│
├── train.py           # 訓練のメインスクリプト
├── model.py           # MyModelの定義 (モジュールクラス)
└── dataloader.py      # train_loader, val_loader の定義

訓練コードと全体像

本記事のメインである、ディープラーニングで教師ありミニバッチ学習を行う最小限のコードは以下の通り、30 行ほど(コメント除く)になります。コードの下に、コードと対応する形で訓練全体をまとめたフローチャートがあります。

# train.py
import os
import torch

from model import MyModel
from dataloader import train_loader, val_loader

##############
# 1. 初期設定 #
##############
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 1-1 モデルのロード・GPUへの以降
model = MyModel().to(device)
model.train()

# 1-2 データローダー
train_loader = get_dataloader(cfg, train)
val_loader = get_dataloader(cfg, val)

# 1- 3 損失関数と最適化手法(optimizer)
criterion =
optimizer = torch.optim.Adam

#############
# 2 学習開始 #
#############
for epoch in range(num_epochs):
    # 2-1 訓練のループ(バッチ)
    for inputs, targets in train_loader:
        # 2-1-0 勾配を初期化
        optimizer.zero_grad()

        # 2-1-1 データをGPUへ
        inputs = inputs.to(device)
        targets = targets.to(device)

        # 2-1-2 順伝播と損失計算
        outputs = model(inputs)
        loss = criterion(outputs, targets)

        # 2-1-3 勾配計算と誤差逆伝播
        loss.backward()
        optimizer.step()

    # 2-2 検証
    model.eval()
    val_loss = 0.0
    # 勾配計算を無効化(メモリの節約・事故防止)
    with torch.no_grad():
        for inputs, targets in val_loader:
            # 2-2-1 データをGPUへ
            inputs = inputs.to(device)
            targets = targets.to(device)

            # 2-2-2 順伝搬と損失計算
            outputs = model(inputs)
            val_loss += criterion(outputs, targets)
    print(f'val loss: {val_loss}')

def get_dataloader(cfg, train=True):
    dataset = MyDataset(cfg.data_path, train=train)
    return DataLoader(dataset, batch_size=cfg.batch_size, shuffle=train)

ディープラーニングのトレーニングプロセスを示すフローチャート。データベースから入力データを処理し、モデルを用いて出力データを生成。その後、損失関数を通じて誤差を計算し、勾配計算とパラメータ更新を行う流れを視覚的に解説。dataloderからモデル (net)、criterion、loss.backward、optimizerまでの流れがわかる(出典:筆者作成)。

【実践基礎3】PyTorch による学習アルゴリズムとプロセスの全体像より

初期設定

GPU設定

PyTorchでは、GPUが使用可能であればGPUを使い、そうでなければCPUを使うように設定するのが一般的です。

os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

ここでは、複数GPUがある場合に「使いたいGPUを番号で指定」するために環境変数 CUDA_VISIBLE_DEVICES を設定しています。詳細なGPUの扱いについては、PyTorchによるGPU環境設定を参照してください。

モデル

model.py に定義されている MyModel クラスを読み込み、GPUに転送します。

model = MyModel().to(device)
model.train()

.train() はモデルを「訓練モード」に設定するためのものです(例えば Dropout や BatchNorm の挙動が異なります)。推論時は .eval() に切り替えます(後述)。

モデル定義の詳細は 実践基礎9 PyTorchモデルの全体構造と作り方を理解しよう を参照。

DataLoader

訓練データと検証データの読み込みは、dataloader.py に定義されている関数 get_dataloader() を通じて行います。

train_loader = get_dataloader(cfg, train=True)
val_loader = get_dataloader(cfg, train=False)

get_dataloader はコードの最後に定義されています。cfg はDataLoader や Dataset に渡す引数を含み、argparse 等で作ることを想定しています。

引数の渡し方はDataset の設計次第で、例えば辞書形式でも構いません。また、引数 train を元に Dataset が訓練・検証データを適切に準備すると仮定しています。

DataLoaderの基本は 実践基礎6 PyTorchのDatasetとDataLoaderを理解しよう を参照。

損失関数と最適化手法

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

ここでは、回帰タスクを想定して MSELoss(平均二乗誤差)を使用し、Adamオプティマイザを選択しています。

    • criterion: 「正解とのズレを数値で表す」役割。分類なら CrossEntropyLoss など。
    • optimizer: 「どうやってパラメータを更新するか」の方法を定める。

自分で損失関数を定義することも可能ですが、PyTorchの組み込み関数は安定性・高速性の点で優れており、特に複雑な損失関数では自前実装はおすすめしません。

損失関数の自動微分の仕組みは 実践基礎8 Tensorの自動微分を理解しよう を参照。

訓練ループの実装

訓練処理は for epoch in range(num_epochs) のループで構成されており、各エポックにおいて全てのミニバッチに対して以下の手順が実行されます。

  1. 勾配の初期化: optimizer.zero_grad() で前のバッチの勾配情報をクリアします。これをしないと勾配が蓄積されてしまいます。
  2. データの転送: 各バッチの inputstargets をGPUに移します。DataLoaderでは転送せず、GPUが必要になる直前のこのタイミングで転送するのが一般的です。
  3. 順伝播と損失計算: モデルに入力を通して出力を得た後、criterion を使って損失を計算します。
  4. 誤差逆伝播とパラメータ更新: loss.backward() で勾配を計算し、optimizer.step() によりモデルのパラメータを更新します。
for epoch in range(num_epochs):
    for inputs, targets in train_loader:
        optimizer.zero_grad()
        inputs = inputs.to(device)
        targets = targets.to(device)
        outputs = model(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()

この一連の処理をエポック(データセット全体を一巡する単位)ごとに繰り返します。

PyTorchではこのようなミニバッチ単位の訓練ループを明示的に記述することで、学習の挙動を柔軟にカスタマイズできます。

検証

検証のバッチループは「2-1 訓練のループ」とだいたい同じですが、勾配の初期化と計算、誤差逆伝播は行いません。あくまで検証データでの loss 等の計算と出力だけが目的です。with torch.no_grad()でインデントした塊の中では勾配計算を禁止することができます。

まとめ

本記事では、PyTorch + GPU を用いた教師あり学習の最小構成を通して、モデルの訓練全体の流れを解説しました。

ここで取り扱ったポイントは以下の通りです:

    • GPUの設定と活用方法
    • モデルを訓練モードに設定し、GPUに転送する方法
    • 訓練用および検証用のデータローダーの利用
    • 損失関数(criterion)と最適化手法(optimizer)の定義
    • 学習ループと検証ループの実装

このコードをベースにすれば、基本的なモデル訓練はすぐに始められます。複雑なモデルや特殊な訓練条件に進む前に、まずはこの「訓練の全体像」をしっかり体感しておくことが重要です。

次のステップ

本記事は、「理論基礎編」から続く「実践基礎編」の最後の記事であり、初心者向けカテゴリの締めくくりでもあります。ここまで読んできた方は、PyTorchを使った基礎的なモデルの訓練が一通り理解できているはずです。

ここから次に進むおすすめの方向性は:

    • 応用編(CNN、転移学習など)へ進む
    • 実データを用いたプロジェクト構築に挑戦
    • モデルの性能改善(学習率調整、正則化、Early Stoppingなど)

それぞれのステップに対応した記事やチュートリアルは、ブログのカテゴリ「ディープラーニング実践編」にて順次公開していきます。

【実践基礎10】PyTorchでモデルを訓練する方法|GPU・DataLoader・訓練ループを体系的に理解

前の記事  


<概要>

GPU + PyTorchを使った教師ありのミニバッチ学習の仕方を説明します。

全体の構造についてフォーカスし、モデルの本体のモジュールクラスやDataLoader等の各論については<関連記事>を参照してください。

細かい設定、例えば torch.optim.lr_scheduler による学習率の管理などは触れません。

<関連記事>

<インポート>

import os
import torch
import torch.nn as nn

ディレクトリ構成

実際のプロジェクトでは、「モデルの定義」や「データの読み込み処理」を別ファイルに分けることで、コードの見通しが良くなり、再利用もしやすくなります。

本記事ではこれらが model.pydataloader.py に記述されているものと仮定し、訓練ループに重点を置きます。

学習を行う本体のコードは以下の train.py にかかれているものとします。

project/
│
├── train.py           # 訓練のメインスクリプト
├── model.py           # MyModelの定義 (モジュールクラス)
└── dataloader.py      # train_loader, val_loader の定義

訓練コードと全体像

本記事のメインである、ディープラーニングで教師ありミニバッチ学習を行う最小限のコードは以下の通り、30 行ほど(コメント除く)になります。コードの下に、コードと対応する形で訓練全体をまとめたフローチャートがあります。

# train.py
import os
import torch

from model import MyModel
from dataloader import train_loader, val_loader

##############
# 1. 初期設定 #
##############
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 1-1 モデルのロード・GPUへの以降
model = MyModel().to(device)
model.train()

# 1-2 データローダー
train_loader = get_dataloader(cfg, train)
val_loader = get_dataloader(cfg, val)

# 1- 3 損失関数と最適化手法(optimizer)
criterion =
optimizer = torch.optim.Adam

#############
# 2 学習開始 #
#############
for epoch in range(num_epochs):
    # 2-1 訓練のループ(バッチ)
    for inputs, targets in train_loader:
        # 2-1-0 勾配を初期化
        optimizer.zero_grad()

        # 2-1-1 データをGPUへ
        inputs = inputs.to(device)
        targets = targets.to(device)

        # 2-1-2 順伝播と損失計算
        outputs = model(inputs)
        loss = criterion(outputs, targets)

        # 2-1-3 勾配計算と誤差逆伝播
        loss.backward()
        optimizer.step()

    # 2-2 検証
    model.eval()
    val_loss = 0.0
    # 勾配計算を無効化(メモリの節約・事故防止)
    with torch.no_grad():
        for inputs, targets in val_loader:
            # 2-2-1 データをGPUへ
            inputs = inputs.to(device)
            targets = targets.to(device)

            # 2-2-2 順伝搬と損失計算
            outputs = model(inputs)
            val_loss += criterion(outputs, targets)
    print(f'val loss: {val_loss}')

def get_dataloader(cfg, train=True):
    dataset = MyDataset(cfg.data_path, train=train)
    return DataLoader(dataset, batch_size=cfg.batch_size, shuffle=train)

ディープラーニングのトレーニングプロセスを示すフローチャート。データベースから入力データを処理し、モデルを用いて出力データを生成。その後、損失関数を通じて誤差を計算し、勾配計算とパラメータ更新を行う流れを視覚的に解説。dataloderからモデル (net)、criterion、loss.backward、optimizerまでの流れがわかる(出典:筆者作成)。

【実践基礎3】PyTorch による学習アルゴリズムとプロセスの全体像より

初期設定

GPU設定

PyTorchでは、GPUが使用可能であればGPUを使い、そうでなければCPUを使うように設定するのが一般的です。

os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

ここでは、複数GPUがある場合に「使いたいGPUを番号で指定」するために環境変数 CUDA_VISIBLE_DEVICES を設定しています。詳細なGPUの扱いについては、PyTorchによるGPU環境設定を参照してください。

モデル

model.py に定義されている MyModel クラスを読み込み、GPUに転送します。

model = MyModel().to(device)
model.train()

.train() はモデルを「訓練モード」に設定するためのものです(例えば Dropout や BatchNorm の挙動が異なります)。推論時は .eval() に切り替えます(後述)。

モデル定義の詳細は 実践基礎9 PyTorchモデルの全体構造と作り方を理解しよう を参照。

DataLoader

訓練データと検証データの読み込みは、dataloader.py に定義されている関数 get_dataloader() を通じて行います。

train_loader = get_dataloader(cfg, train=True)
val_loader = get_dataloader(cfg, train=False)

get_dataloader はコードの最後に定義されています。cfg はDataLoader や Dataset に渡す引数を含み、argparse 等で作ることを想定しています。

引数の渡し方はDataset の設計次第で、例えば辞書形式でも構いません。また、引数 train を元に Dataset が訓練・検証データを適切に準備すると仮定しています。

DataLoaderの基本は 実践基礎6 PyTorchのDatasetとDataLoaderを理解しよう を参照。

損失関数と最適化手法

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

ここでは、回帰タスクを想定して MSELoss(平均二乗誤差)を使用し、Adamオプティマイザを選択しています。

    • criterion: 「正解とのズレを数値で表す」役割。分類なら CrossEntropyLoss など。
    • optimizer: 「どうやってパラメータを更新するか」の方法を定める。

自分で損失関数を定義することも可能ですが、PyTorchの組み込み関数は安定性・高速性の点で優れており、特に複雑な損失関数では自前実装はおすすめしません。

損失関数の自動微分の仕組みは 実践基礎8 Tensorの自動微分を理解しよう を参照。

訓練ループの実装

訓練処理は for epoch in range(num_epochs) のループで構成されており、各エポックにおいて全てのミニバッチに対して以下の手順が実行されます。

  1. 勾配の初期化: optimizer.zero_grad() で前のバッチの勾配情報をクリアします。これをしないと勾配が蓄積されてしまいます。
  2. データの転送: 各バッチの inputstargets をGPUに移します。DataLoaderでは転送せず、GPUが必要になる直前のこのタイミングで転送するのが一般的です。
  3. 順伝播と損失計算: モデルに入力を通して出力を得た後、criterion を使って損失を計算します。
  4. 誤差逆伝播とパラメータ更新: loss.backward() で勾配を計算し、optimizer.step() によりモデルのパラメータを更新します。
for epoch in range(num_epochs):
    for inputs, targets in train_loader:
        optimizer.zero_grad()
        inputs = inputs.to(device)
        targets = targets.to(device)
        outputs = model(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()

この一連の処理をエポック(データセット全体を一巡する単位)ごとに繰り返します。

PyTorchではこのようなミニバッチ単位の訓練ループを明示的に記述することで、学習の挙動を柔軟にカスタマイズできます。

検証

検証のバッチループは「2-1 訓練のループ」とだいたい同じですが、勾配の初期化と計算、誤差逆伝播は行いません。あくまで検証データでの loss 等の計算と出力だけが目的です。with torch.no_grad()でインデントした塊の中では勾配計算を禁止することができます。

まとめ

本記事では、PyTorch + GPU を用いた教師あり学習の最小構成を通して、モデルの訓練全体の流れを解説しました。

ここで取り扱ったポイントは以下の通りです:

    • GPUの設定と活用方法
    • モデルを訓練モードに設定し、GPUに転送する方法
    • 訓練用および検証用のデータローダーの利用
    • 損失関数(criterion)と最適化手法(optimizer)の定義
    • 学習ループと検証ループの実装

このコードをベースにすれば、基本的なモデル訓練はすぐに始められます。複雑なモデルや特殊な訓練条件に進む前に、まずはこの「訓練の全体像」をしっかり体感しておくことが重要です。

次のステップ

本記事は、「理論基礎編」から続く「実践基礎編」の最後の記事であり、初心者向けカテゴリの締めくくりでもあります。ここまで読んできた方は、PyTorchを使った基礎的なモデルの訓練が一通り理解できているはずです。

ここから次に進むおすすめの方向性は:

    • 応用編(CNN、転移学習など)へ進む
    • 実データを用いたプロジェクト構築に挑戦
    • モデルの性能改善(学習率調整、正則化、Early Stoppingなど)

それぞれのステップに対応した記事やチュートリアルは、ブログのカテゴリ「ディープラーニング実践編」にて順次公開していきます。

【実践基礎10】PyTorchでモデルを訓練する方法|GPU・DataLoader・訓練ループを体系的に理解

前の記事  


<概要>

GPU + PyTorchを使った教師ありのミニバッチ学習の仕方を説明します。

全体の構造についてフォーカスし、モデルの本体のモジュールクラスやDataLoader等の各論については<関連記事>を参照してください。

細かい設定、例えば torch.optim.lr_scheduler による学習率の管理などは触れません。

<関連記事>

<インポート>

import os
import torch
import torch.nn as nn

ディレクトリ構成

実際のプロジェクトでは、「モデルの定義」や「データの読み込み処理」を別ファイルに分けることで、コードの見通しが良くなり、再利用もしやすくなります。

本記事ではこれらが model.pydataloader.py に記述されているものと仮定し、訓練ループに重点を置きます。

学習を行う本体のコードは以下の train.py にかかれているものとします。

project/
│
├── train.py           # 訓練のメインスクリプト
├── model.py           # MyModelの定義 (モジュールクラス)
└── dataloader.py      # train_loader, val_loader の定義

訓練コードと全体像

本記事のメインである、ディープラーニングで教師ありミニバッチ学習を行う最小限のコードは以下の通り、30 行ほど(コメント除く)になります。コードの下に、コードと対応する形で訓練全体をまとめたフローチャートがあります。

# train.py
import os
import torch

from model import MyModel
from dataloader import train_loader, val_loader

##############
# 1. 初期設定 #
##############
os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

# 1-1 モデルのロード・GPUへの以降
model = MyModel().to(device)
model.train()

# 1-2 データローダー
train_loader = get_dataloader(cfg, train)
val_loader = get_dataloader(cfg, val)

# 1- 3 損失関数と最適化手法(optimizer)
criterion =
optimizer = torch.optim.Adam

#############
# 2 学習開始 #
#############
for epoch in range(num_epochs):
    # 2-1 訓練のループ(バッチ)
    for inputs, targets in train_loader:
        # 2-1-0 勾配を初期化
        optimizer.zero_grad()

        # 2-1-1 データをGPUへ
        inputs = inputs.to(device)
        targets = targets.to(device)

        # 2-1-2 順伝播と損失計算
        outputs = model(inputs)
        loss = criterion(outputs, targets)

        # 2-1-3 勾配計算と誤差逆伝播
        loss.backward()
        optimizer.step()

    # 2-2 検証
    model.eval()
    val_loss = 0.0
    # 勾配計算を無効化(メモリの節約・事故防止)
    with torch.no_grad():
        for inputs, targets in val_loader:
            # 2-2-1 データをGPUへ
            inputs = inputs.to(device)
            targets = targets.to(device)

            # 2-2-2 順伝搬と損失計算
            outputs = model(inputs)
            val_loss += criterion(outputs, targets)
    print(f'val loss: {val_loss}')

def get_dataloader(cfg, train=True):
    dataset = MyDataset(cfg.data_path, train=train)
    return DataLoader(dataset, batch_size=cfg.batch_size, shuffle=train)

ディープラーニングのトレーニングプロセスを示すフローチャート。データベースから入力データを処理し、モデルを用いて出力データを生成。その後、損失関数を通じて誤差を計算し、勾配計算とパラメータ更新を行う流れを視覚的に解説。dataloderからモデル (net)、criterion、loss.backward、optimizerまでの流れがわかる(出典:筆者作成)。

【実践基礎3】PyTorch による学習アルゴリズムとプロセスの全体像より

初期設定

GPU設定

PyTorchでは、GPUが使用可能であればGPUを使い、そうでなければCPUを使うように設定するのが一般的です。

os.environ["CUDA_VISIBLE_DEVICES"] = "0"
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')

ここでは、複数GPUがある場合に「使いたいGPUを番号で指定」するために環境変数 CUDA_VISIBLE_DEVICES を設定しています。詳細なGPUの扱いについては、PyTorchによるGPU環境設定を参照してください。

モデル

model.py に定義されている MyModel クラスを読み込み、GPUに転送します。

model = MyModel().to(device)
model.train()

.train() はモデルを「訓練モード」に設定するためのものです(例えば Dropout や BatchNorm の挙動が異なります)。推論時は .eval() に切り替えます(後述)。

モデル定義の詳細は 実践基礎9 PyTorchモデルの全体構造と作り方を理解しよう を参照。

DataLoader

訓練データと検証データの読み込みは、dataloader.py に定義されている関数 get_dataloader() を通じて行います。

train_loader = get_dataloader(cfg, train=True)
val_loader = get_dataloader(cfg, train=False)

get_dataloader はコードの最後に定義されています。cfg はDataLoader や Dataset に渡す引数を含み、argparse 等で作ることを想定しています。

引数の渡し方はDataset の設計次第で、例えば辞書形式でも構いません。また、引数 train を元に Dataset が訓練・検証データを適切に準備すると仮定しています。

DataLoaderの基本は 実践基礎6 PyTorchのDatasetとDataLoaderを理解しよう を参照。

損失関数と最適化手法

criterion = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=1e-3)

ここでは、回帰タスクを想定して MSELoss(平均二乗誤差)を使用し、Adamオプティマイザを選択しています。

    • criterion: 「正解とのズレを数値で表す」役割。分類なら CrossEntropyLoss など。
    • optimizer: 「どうやってパラメータを更新するか」の方法を定める。

自分で損失関数を定義することも可能ですが、PyTorchの組み込み関数は安定性・高速性の点で優れており、特に複雑な損失関数では自前実装はおすすめしません。

損失関数の自動微分の仕組みは 実践基礎8 Tensorの自動微分を理解しよう を参照。

訓練ループの実装

訓練処理は for epoch in range(num_epochs) のループで構成されており、各エポックにおいて全てのミニバッチに対して以下の手順が実行されます。

  1. 勾配の初期化: optimizer.zero_grad() で前のバッチの勾配情報をクリアします。これをしないと勾配が蓄積されてしまいます。
  2. データの転送: 各バッチの inputstargets をGPUに移します。DataLoaderでは転送せず、GPUが必要になる直前のこのタイミングで転送するのが一般的です。
  3. 順伝播と損失計算: モデルに入力を通して出力を得た後、criterion を使って損失を計算します。
  4. 誤差逆伝播とパラメータ更新: loss.backward() で勾配を計算し、optimizer.step() によりモデルのパラメータを更新します。
for epoch in range(num_epochs):
    for inputs, targets in train_loader:
        optimizer.zero_grad()
        inputs = inputs.to(device)
        targets = targets.to(device)
        outputs = model(inputs)
        loss = criterion(outputs, targets)
        loss.backward()
        optimizer.step()

この一連の処理をエポック(データセット全体を一巡する単位)ごとに繰り返します。

PyTorchではこのようなミニバッチ単位の訓練ループを明示的に記述することで、学習の挙動を柔軟にカスタマイズできます。

検証

検証のバッチループは「2-1 訓練のループ」とだいたい同じですが、勾配の初期化と計算、誤差逆伝播は行いません。あくまで検証データでの loss 等の計算と出力だけが目的です。with torch.no_grad()でインデントした塊の中では勾配計算を禁止することができます。

まとめ

本記事では、PyTorch + GPU を用いた教師あり学習の最小構成を通して、モデルの訓練全体の流れを解説しました。

ここで取り扱ったポイントは以下の通りです:

    • GPUの設定と活用方法
    • モデルを訓練モードに設定し、GPUに転送する方法
    • 訓練用および検証用のデータローダーの利用
    • 損失関数(criterion)と最適化手法(optimizer)の定義
    • 学習ループと検証ループの実装

このコードをベースにすれば、基本的なモデル訓練はすぐに始められます。複雑なモデルや特殊な訓練条件に進む前に、まずはこの「訓練の全体像」をしっかり体感しておくことが重要です。

この記事の最新バージョンはこちら:
👉 https://ai-physics-lab.com/ja/pytorch-train-loop-basics/

次のステップ

本記事は、「理論基礎編」から続く「実践基礎編」の最後の記事であり、初心者向けカテゴリの締めくくりでもあります。ここまで読んできた方は、PyTorchを使った基礎的なモデルの訓練が一通り理解できているはずです。

ここから次に進むおすすめの方向性は:

    • 応用編(CNN、転移学習など)へ進む
    • 実データを用いたプロジェクト構築に挑戦
    • モデルの性能改善(学習率調整、正則化、Early Stoppingなど)

それぞれのステップに対応した記事やチュートリアルは、ブログのカテゴリ「ディープラーニング実践編」にて順次公開していきます。

【実践基礎9】PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解

前の記事  次の記事


PyTorch でモデルを構築する場合、主に以下の5つを使います。

  • Class: torch.nn.Module
  • Class: レイヤー (torch.nn.ReLU など)
  • Class: torch.nn.Sequential
  • Class: torch.nn.ModuleList
  • func: torch.nn.functional

多くの場合、nn.Module をベースにモデルを自作します。このとき、nn.Module を継承したサブクラスであるレイヤー、nn.Sequentialnn.ModuleList などを使ってモデルの構造を作ります。また、nn.functional にある関数も補助的に使用されます。

<概要>

本記事では上記の構成要素と nn.functional の関係や使い方をコードとともにまとめ、実際にニューラルネットワークのモデルを自作するための基礎を説明します。

<この記事で扱う主要なモジュール・ライブラリ一覧>
import torch
import torch.nn as nn  # 一般的に"nn"としてインポートされる
import torch.nn.functional as F  # 一般的に"F"という名前でインポートされる
from collections import OrderedDict
<関連記事>

PyTorchのnn.Module、nn.Sequential、nn.ModuleList、レイヤーの継承関係とforwardの有無を示す図(出典:筆者作成)。

「モデルの作り方」より

モデルの作り方 ― nn.Module の思想と構造

PyTorch でニューラルネットワークのモデルを構築する場合、「モデル」とは モジュールクラス(のインスタンス)を作ることを意味します。

nn.Linear などのレイヤーや nn.Sequential は単体でもモデルとして使用可能なモジュールですが、複雑で実用的なモデルを作る際には、自分で基底クラスである nn.Module を継承してモジュールクラスを定義する必要があります。

モジュールはレイヤーを最小単位とし、互いにネストすることでツリー構造を作ることができます。よくある構成としては、自作クラス内でレイヤー、nn.Sequentialnn.ModuleList を使用するというものです。

forward メソッドを定義したモジュール(図中オレンジ枠)は、インスタンスがそのまま「関数」として動作するようになります。こうした forward() をもつモジュールはすべて、ニューラルネットワークのモデルとして使用できます。一方、nn.ModuleListforward を持たず、単体ではモデルとしては機能しません。

PyTorchのnn.Module、nn.Sequential、nn.ModuleList、レイヤーの継承関係とforwardの有無を示す図(出典:筆者作成)。

PyTorchにおける主要なモジュールクラスの関係図。nn.Module を基底とし、そのサブクラスであるSequentialやModuleList、レイヤー(ReLUやConvなど)をネストして構築する。forward() があるもの(オレンジ)はインスタンスが関数として振る舞い、学習・推論で使用できる。イラストはレイヤーの繋がり方を表す(出典:筆者作成)。

モデルの最小単位 ― レイヤー

nn.Module を継承したモジュールクラスとして、「レイヤー」と呼ばれるものが torch.nn公式ページ)にあらかじめ準備されています。

一般的には、学習可能なパラメータを持つ線形結合(nn.Linear)や畳み込み(nn.Conv2d)などを指しますが、ここでは活性化関数(nn.ReLUnn.Sigmoid…)や正則化(nn.BatchNorm2d など)も含めて、広義の「レイヤー」として扱います。

これらはニューラルネットワークにおける最も基本的な構成要素です。

# torch.nnをnnとしてインポートする ("nn"でtorch.nnを参照できる)
import torch.nn as nn

net = nn.Linear(2, 4)

上の例では、2次元の入力テンソルから4次元の線形結合出力を得る nn.Linear を使用しています。

このようなレイヤーのインスタンスは、パラメータ(重み・バイアス)を内部に持ち、初期化された状態で順伝播できるようになります。

最も簡単なモデル構築 ― nn.Sequential

nn.Sequential公式ページ)は nn.Module を継承したサブクラスです。Sequential 自体は単なる入れ物で、必要なレイヤーのインスタンスを順番に入れるだけで、それらを1本につなげた「Sequential(逐次的)」なモデルを作ることができます

ただし、nn.Linear などのレイヤーは入力・出力サイズの指定が必要なので、各レイヤー間で形状が一致するように設計する必要があります。

具体的な作り方は、以下のいずれでも問題ありません。

Sequentialの作り方1 ― レイヤーのインスタンスを直接並べる

import torch.nn as nn

# Sequentialでモデルを定義。レイヤーのインスタンスを並べるだけ。
net = nn.Sequential(
    nn.Linear(20, 256),
    nn.ReLU(),
    nn.Linear(256, 10),
    nn.ReLU(),
)

print(net)

出力例:

Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
  (3): ReLU()
)

この例では、入力が20次元のベクトルで、それを256ノードの層→ReLU→10ノードの層→ReLUと通す構造になります。パラメータがランダムなため、出力も以下のように適当な値になります。

import torch

x = torch.ones(20)
predict = net(x)

print(predict)
# 出力例(ランダムな初期化による)
# tensor([0.0000, 0.2197, 0.0000, 0.0000, 0.0000, 0.0000, 0.1862, 0.2169, 0.0000, 0.0000], grad_fn=)

Sequentialの作り方2 ― リストをアンパック

レイヤーをリストに入れ、アンパック(*)して渡す方法もあります。

import torch.nn as nn

layer_block = [nn.Linear(5, 256), nn.ReLU(), nn.Linear(256, 5), nn.ReLU()]
net = nn.Sequential(*layer_block)

Sequentialの作り方3 ― OrderedDictを使って名前を付ける

OrderedDict を使うと、各レイヤーに明示的な名前をつけることができます。自動的に (0), (1), … と番号が振られる代わりに、'linear_in''relu_in' などを使って管理できます。

from collections import OrderedDict
import torch.nn as nn

layer_block = OrderedDict([
    ('linear_in', nn.Linear(5, 256)),
    ('relu_in', nn.ReLU()),
    ('linear_out', nn.Linear(256, 5)),
    ('relu_out', nn.ReLU())
])
net = nn.Sequential(layer_block)

モデル設計の本質 ― nn.Moduleを継承

nn.Moduleとは?基底クラスの役割

nn.Module公式ページ)自体は、ニューラルネットワークのモデル構築・訓練・推論などに共通する機能を持った、抽象的な基底クラスです。

このままではモデルとして使用できないため、具体的なモデルを構築するには、次に説明するようにnn.Module を継承し、レイヤーや他のモジュールを組み合わせて定義する必要があります。自由度が高く、基本的にどんなモデルでも表現可能です。

レイヤーの定義と forward

nn.Module を継承したクラスでは、以下の2つのメソッドを定義するのが基本です:

  • __init__():クラスの初期化(レイヤー定義)
  • forward():順伝播処理(入力→出力の変換)

__init__() は特殊メソッドで、インスタンス生成時に呼ばれます。ここでレイヤーや SequentialModuleList などを定義しておきます。

先頭に記述する super().__init__() は、親クラスである nn.Module の初期化処理を呼び出すため、必ず必要です。

一方 forward() には、入力をどのように処理して出力するかのロジックを記述します。これは Python の特殊メソッド __call__() によって内部的に呼び出され、インスタンスが「関数のように使える」ようになります。

# https://pytorch.org/docs/stable/generated/torch.nn.Module.html
import torch.nn as nn
import torch.nn.functional as F

class MyModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 3)
        self.conv2 = nn.Conv2d(20, 20, 3)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))

nn.Moduleの諸機能

学習・評価モードの切り替え:.train() / .eval()

学習時と推論時では、Dropout や BatchNorm など一部のレイヤーの挙動が異なる設計なため、.train() / .eval() メソッドでモードを切り替える必要があります。

net = MyModel()

# 学習モード
net.train()

# 推論モード
net.eval()

デバイス管理:.cuda() / .cpu()

モデルのパラメータも Tensor と同様に GPU / CPU 間で移動させることができます。以下のように指定可能です:

net = MyModel()

# GPUのIDを指定して移動
net.cuda(0)

# デバイスオブジェクトで指定
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
net.to(device)

モデルの保存とロード:.state_dict() / .load_state_dict()

公式チュートリアルにあるように、PyTorchでは、モデルのパラメータ(重みやバイアス)を保存・復元するために state_dict() / load_state_dict() が提供されています。

これにより、モデルの構造ではなく、学習の進行状態(チェックポイント)としてパラメータだけを効率的に保存できます。

保存されたパラメータを使用するには、まず訓練時と同じ構造の nn.Module インスタンスを再生成し、その後 load_state_dict() を呼び出して復元します。

保存:torch.save と state_dict()

torch.save(net.state_dict(), 'model.pth')  # 保存先ファイル名

state_dict() によって、モデルのすべての学習可能パラメータが辞書形式で取得され、.pth という形式で保存されます。

ロード:load_state_dict()

net = MyModel()  # モデル構造を再生成
net.load_state_dict(torch.load('model.pth'))  # パラメータを読み込み

モデル構造が保存時と一致している必要があるため、再構築してから読み込みを行います。

実践的な nn.Module の作り方

モジュールは互いにネスト(入れ子構造)にできます。nn.Module を継承したクラスの中で nn.Sequentialnn.ModuleList を使えるのはもちろん、自作したモジュール同士をさらに他のモジュールの中で使うこともできます。

そのため構造の組み合わせは事実上無限にありますが、ここでは代表的な構造として、nn.Module の中で SequentialModuleList を利用する例を紹介します。

nn.Module + nn.Sequential

Sequential はレイヤーを順番に並べて接続するための簡便な仕組みです。以下は MLP(Multilayer Perceptron)nn.Modulenn.Sequential を組み合わせて構築した例です。

この例では以下の3つのレイヤーブロックを使っています:

  • self.input_layer: 入力ノード → 隠れ層ノード
  • self.hidden_layers: 同じサイズの隠れ層を num_layers 回繰り返す(Sequentialで実装)
  • self.output_layer: 隠れ層ノード → 出力ノード
import torch
import torch.nn as nn
import torch.nn.functional as F

class MLP(nn.Module):
    def __init__(self, input_dim=64, hidden_dim=64, num_layers=5, output_dim=1):
        super().__init__()
        
        self.input_layer = nn.Linear(input_dim, hidden_dim)

        layers = []
        for _ in range(num_layers):
            layers.append(nn.Linear(hidden_dim, hidden_dim))
            layers.append(nn.ReLU())

        self.hidden_layers = nn.Sequential(*layers)

        self.output_layer = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        x = self.hidden_layers(x)
        return self.output_layer(x)

nn.Module + nn.ModuleList

ModuleList公式)は、nn.Module のリストのように使えるコンテナです。

Sequential はレイヤーをつなげて1つの大きなモジュールにするのに対して、ModuleList個別のレイヤーをリスト形式で保持します。そのため forward() の中で、ループを用いて手動で処理する必要があります。

class MLP(nn.Module):
    def __init__(self, input_dim=64, hidden_dim=64, num_layers=5, output_dim=1):
        super().__init__()
        self.input_layer = nn.Linear(input_dim, hidden_dim)

        self.hidden_layers = nn.ModuleList([
            nn.Linear(hidden_dim, hidden_dim) for _ in range(num_layers)
        ])

        self.output_layer = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        for layer in self.hidden_layers:
            x = F.relu(layer(x))
        return self.output_layer(x)

先ほどとモデルは全く同じですが、 ModuleList を使えば forward() 中で各層に対して個別に処理を加えたり、途中の出力を取り出す、分岐させるなどといった、柔軟な操作が可能になります。これは Sequential にはない利点です。

nn.Module + nn.functional

nn.functional には、パラメータを持たない演算関数が多数含まれています(例:F.reluF.softmax など)。

一見すると F.linearF.conv2d のようにパラメータを含むように見える関数もありますが、これらは「学習用のパラメータ」ではなく、引数として外部から渡す形式になります。

つまり nn.functional は、学習用ではない固定的された演算を手動で設計する場合などに使用します。

まとめ

  • nn.Module は PyTorch モデル構築の基底クラスで、全てのモデルの土台。
  • レイヤー(nn.Linear や nn.ReLU など)は nn.Module を継承した最小単位。
  • nn.Sequential は直列構造に特化し、最も簡単に使えるモデル構築法。
  • nn.ModuleList は柔軟な繰り返しや構造操作に強く、for文と併用される。
  • nn.functional は演算関数の集合で、設計上の固定処理や補助的な役割に活用。
  • forward() を持つモジュールは関数のように使え、モデルとして使用可能。
  • モジュールは自由にネスト可能で、複雑な構造でも柔軟に対応できる。

【実践基礎9】PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解

前の記事  次の記事


PyTorch でモデルを構築する場合、主に以下の5つを使います。

  • Class: torch.nn.Module
  • Class: レイヤー (torch.nn.ReLU など)
  • Class: torch.nn.Sequential
  • Class: torch.nn.ModuleList
  • func: torch.nn.functional

多くの場合、nn.Module をベースにモデルを自作します。このとき、nn.Module を継承したサブクラスであるレイヤー、nn.Sequentialnn.ModuleList などを使ってモデルの構造を作ります。また、nn.functional にある関数も補助的に使用されます。

<概要>

本記事では上記の構成要素と nn.functional の関係や使い方をコードとともにまとめ、実際にニューラルネットワークのモデルを自作するための基礎を説明します。

<この記事で扱う主要なモジュール・ライブラリ一覧>
import torch
import torch.nn as nn  # 一般的に"nn"としてインポートされる
import torch.nn.functional as F  # 一般的に"F"という名前でインポートされる
from collections import OrderedDict
<関連記事>

PyTorchのnn.Module、nn.Sequential、nn.ModuleList、レイヤーの継承関係とforwardの有無を示す図(出典:筆者作成)。

「モデルの作り方」より

モデルの作り方 ― nn.Module の思想と構造

PyTorch でニューラルネットワークのモデルを構築する場合、「モデル」とは モジュールクラス(のインスタンス)を作ることを意味します。

nn.Linear などのレイヤーや nn.Sequential は単体でもモデルとして使用可能なモジュールですが、複雑で実用的なモデルを作る際には、自分で基底クラスである nn.Module を継承してモジュールクラスを定義する必要があります。

モジュールはレイヤーを最小単位とし、互いにネストすることでツリー構造を作ることができます。よくある構成としては、自作クラス内でレイヤー、nn.Sequentialnn.ModuleList を使用するというものです。

forward メソッドを定義したモジュール(図中オレンジ枠)は、インスタンスがそのまま「関数」として動作するようになります。こうした forward() をもつモジュールはすべて、ニューラルネットワークのモデルとして使用できます。一方、nn.ModuleListforward を持たず、単体ではモデルとしては機能しません。

PyTorchのnn.Module、nn.Sequential、nn.ModuleList、レイヤーの継承関係とforwardの有無を示す図(出典:筆者作成)。

PyTorchにおける主要なモジュールクラスの関係図。nn.Module を基底とし、そのサブクラスであるSequentialやModuleList、レイヤー(ReLUやConvなど)をネストして構築する。forward() があるもの(オレンジ)はインスタンスが関数として振る舞い、学習・推論で使用できる。イラストはレイヤーの繋がり方を表す(出典:筆者作成)。

モデルの最小単位 ― レイヤー

nn.Module を継承したモジュールクラスとして、「レイヤー」と呼ばれるものが torch.nn公式ページ)にあらかじめ準備されています。

一般的には、学習可能なパラメータを持つ線形結合(nn.Linear)や畳み込み(nn.Conv2d)などを指しますが、ここでは活性化関数(nn.ReLUnn.Sigmoid…)や正則化(nn.BatchNorm2d など)も含めて、広義の「レイヤー」として扱います。

これらはニューラルネットワークにおける最も基本的な構成要素です。

# torch.nnをnnとしてインポートする ("nn"でtorch.nnを参照できる)
import torch.nn as nn

net = nn.Linear(2, 4)

上の例では、2次元の入力テンソルから4次元の線形結合出力を得る nn.Linear を使用しています。

このようなレイヤーのインスタンスは、パラメータ(重み・バイアス)を内部に持ち、初期化された状態で順伝播できるようになります。

最も簡単なモデル構築 ― nn.Sequential

nn.Sequential公式ページ)は nn.Module を継承したサブクラスです。Sequential 自体は単なる入れ物で、必要なレイヤーのインスタンスを順番に入れるだけで、それらを1本につなげた「Sequential(逐次的)」なモデルを作ることができます

ただし、nn.Linear などのレイヤーは入力・出力サイズの指定が必要なので、各レイヤー間で形状が一致するように設計する必要があります。

具体的な作り方は、以下のいずれでも問題ありません。

Sequentialの作り方1 ― レイヤーのインスタンスを直接並べる

import torch.nn as nn

# Sequentialでモデルを定義。レイヤーのインスタンスを並べるだけ。
net = nn.Sequential(
    nn.Linear(20, 256),
    nn.ReLU(),
    nn.Linear(256, 10),
    nn.ReLU(),
)

print(net)

出力例:

Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
  (3): ReLU()
)

この例では、入力が20次元のベクトルで、それを256ノードの層→ReLU→10ノードの層→ReLUと通す構造になります。パラメータがランダムなため、出力も以下のように適当な値になります。

import torch

x = torch.ones(20)
predict = net(x)

print(predict)
# 出力例(ランダムな初期化による)
# tensor([0.0000, 0.2197, 0.0000, 0.0000, 0.0000, 0.0000, 0.1862, 0.2169, 0.0000, 0.0000], grad_fn=)

Sequentialの作り方2 ― リストをアンパック

レイヤーをリストに入れ、アンパック(*)して渡す方法もあります。

import torch.nn as nn

layer_block = [nn.Linear(5, 256), nn.ReLU(), nn.Linear(256, 5), nn.ReLU()]
net = nn.Sequential(*layer_block)

Sequentialの作り方3 ― OrderedDictを使って名前を付ける

OrderedDict を使うと、各レイヤーに明示的な名前をつけることができます。自動的に (0), (1), … と番号が振られる代わりに、'linear_in''relu_in' などを使って管理できます。

from collections import OrderedDict
import torch.nn as nn

layer_block = OrderedDict([
    ('linear_in', nn.Linear(5, 256)),
    ('relu_in', nn.ReLU()),
    ('linear_out', nn.Linear(256, 5)),
    ('relu_out', nn.ReLU())
])
net = nn.Sequential(layer_block)

モデル設計の本質 ― nn.Moduleを継承

nn.Moduleとは?基底クラスの役割

nn.Module公式ページ)自体は、ニューラルネットワークのモデル構築・訓練・推論などに共通する機能を持った、抽象的な基底クラスです。

このままではモデルとして使用できないため、具体的なモデルを構築するには、次に説明するようにnn.Module を継承し、レイヤーや他のモジュールを組み合わせて定義する必要があります。自由度が高く、基本的にどんなモデルでも表現可能です。

レイヤーの定義と forward

nn.Module を継承したクラスでは、以下の2つのメソッドを定義するのが基本です:

  • __init__():クラスの初期化(レイヤー定義)
  • forward():順伝播処理(入力→出力の変換)

__init__() は特殊メソッドで、インスタンス生成時に呼ばれます。ここでレイヤーや SequentialModuleList などを定義しておきます。

先頭に記述する super().__init__() は、親クラスである nn.Module の初期化処理を呼び出すため、必ず必要です。

一方 forward() には、入力をどのように処理して出力するかのロジックを記述します。これは Python の特殊メソッド __call__() によって内部的に呼び出され、インスタンスが「関数のように使える」ようになります。

# https://pytorch.org/docs/stable/generated/torch.nn.Module.html
import torch.nn as nn
import torch.nn.functional as F

class MyModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 3)
        self.conv2 = nn.Conv2d(20, 20, 3)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))

nn.Moduleの諸機能

学習・評価モードの切り替え:.train() / .eval()

学習時と推論時では、Dropout や BatchNorm など一部のレイヤーの挙動が異なる設計なため、.train() / .eval() メソッドでモードを切り替える必要があります。

net = MyModel()

# 学習モード
net.train()

# 推論モード
net.eval()

デバイス管理:.cuda() / .cpu()

モデルのパラメータも Tensor と同様に GPU / CPU 間で移動させることができます。以下のように指定可能です:

net = MyModel()

# GPUのIDを指定して移動
net.cuda(0)

# デバイスオブジェクトで指定
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
net.to(device)

モデルの保存とロード:.state_dict() / .load_state_dict()

公式チュートリアルにあるように、PyTorchでは、モデルのパラメータ(重みやバイアス)を保存・復元するために state_dict() / load_state_dict() が提供されています。

これにより、モデルの構造ではなく、学習の進行状態(チェックポイント)としてパラメータだけを効率的に保存できます。

保存されたパラメータを使用するには、まず訓練時と同じ構造の nn.Module インスタンスを再生成し、その後 load_state_dict() を呼び出して復元します。

保存:torch.save と state_dict()

torch.save(net.state_dict(), 'model.pth')  # 保存先ファイル名

state_dict() によって、モデルのすべての学習可能パラメータが辞書形式で取得され、.pth という形式で保存されます。

ロード:load_state_dict()

net = MyModel()  # モデル構造を再生成
net.load_state_dict(torch.load('model.pth'))  # パラメータを読み込み

モデル構造が保存時と一致している必要があるため、再構築してから読み込みを行います。

実践的な nn.Module の作り方

モジュールは互いにネスト(入れ子構造)にできます。nn.Module を継承したクラスの中で nn.Sequentialnn.ModuleList を使えるのはもちろん、自作したモジュール同士をさらに他のモジュールの中で使うこともできます。

そのため構造の組み合わせは事実上無限にありますが、ここでは代表的な構造として、nn.Module の中で SequentialModuleList を利用する例を紹介します。

nn.Module + nn.Sequential

Sequential はレイヤーを順番に並べて接続するための簡便な仕組みです。以下は MLP(Multilayer Perceptron)nn.Modulenn.Sequential を組み合わせて構築した例です。

この例では以下の3つのレイヤーブロックを使っています:

  • self.input_layer: 入力ノード → 隠れ層ノード
  • self.hidden_layers: 同じサイズの隠れ層を num_layers 回繰り返す(Sequentialで実装)
  • self.output_layer: 隠れ層ノード → 出力ノード
import torch
import torch.nn as nn
import torch.nn.functional as F

class MLP(nn.Module):
    def __init__(self, input_dim=64, hidden_dim=64, num_layers=5, output_dim=1):
        super().__init__()
        
        self.input_layer = nn.Linear(input_dim, hidden_dim)

        layers = []
        for _ in range(num_layers):
            layers.append(nn.Linear(hidden_dim, hidden_dim))
            layers.append(nn.ReLU())

        self.hidden_layers = nn.Sequential(*layers)

        self.output_layer = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        x = self.hidden_layers(x)
        return self.output_layer(x)

nn.Module + nn.ModuleList

ModuleList公式)は、nn.Module のリストのように使えるコンテナです。

Sequential はレイヤーをつなげて1つの大きなモジュールにするのに対して、ModuleList個別のレイヤーをリスト形式で保持します。そのため forward() の中で、ループを用いて手動で処理する必要があります。

class MLP(nn.Module):
    def __init__(self, input_dim=64, hidden_dim=64, num_layers=5, output_dim=1):
        super().__init__()
        self.input_layer = nn.Linear(input_dim, hidden_dim)

        self.hidden_layers = nn.ModuleList([
            nn.Linear(hidden_dim, hidden_dim) for _ in range(num_layers)
        ])

        self.output_layer = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        for layer in self.hidden_layers:
            x = F.relu(layer(x))
        return self.output_layer(x)

先ほどとモデルは全く同じですが、 ModuleList を使えば forward() 中で各層に対して個別に処理を加えたり、途中の出力を取り出す、分岐させるなどといった、柔軟な操作が可能になります。これは Sequential にはない利点です。

nn.Module + nn.functional

nn.functional には、パラメータを持たない演算関数が多数含まれています(例:F.reluF.softmax など)。

一見すると F.linearF.conv2d のようにパラメータを含むように見える関数もありますが、これらは「学習用のパラメータ」ではなく、引数として外部から渡す形式になります。

つまり nn.functional は、学習用ではない固定的された演算を手動で設計する場合などに使用します。

まとめ

  • nn.Module は PyTorch モデル構築の基底クラスで、全てのモデルの土台。
  • レイヤー(nn.Linear や nn.ReLU など)は nn.Module を継承した最小単位。
  • nn.Sequential は直列構造に特化し、最も簡単に使えるモデル構築法。
  • nn.ModuleList は柔軟な繰り返しや構造操作に強く、for文と併用される。
  • nn.functional は演算関数の集合で、設計上の固定処理や補助的な役割に活用。
  • forward() を持つモジュールは関数のように使え、モデルとして使用可能。
  • モジュールは自由にネスト可能で、複雑な構造でも柔軟に対応できる。

【実践基礎9】PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解

前の記事  次の記事


PyTorch でモデルを構築する場合、主に以下の5つを使います。

  • Class: torch.nn.Module
  • Class: レイヤー (torch.nn.ReLU など)
  • Class: torch.nn.Sequential
  • Class: torch.nn.ModuleList
  • func: torch.nn.functional

多くの場合、nn.Module をベースにモデルを自作します。このとき、nn.Module を継承したサブクラスであるレイヤー、nn.Sequentialnn.ModuleList などを使ってモデルの構造を作ります。また、nn.functional にある関数も補助的に使用されます。

<概要>

本記事では上記の構成要素と nn.functional の関係や使い方をコードとともにまとめ、実際にニューラルネットワークのモデルを自作するための基礎を説明します。

<この記事で扱う主要なモジュール・ライブラリ一覧>
import torch
import torch.nn as nn  # 一般的に"nn"としてインポートされる
import torch.nn.functional as F  # 一般的に"F"という名前でインポートされる
from collections import OrderedDict

この記事の最新バージョンはこちら:
👉 https://ai-physics-lab.com/ja/pytorch-module-model-structure/

<関連記事>

PyTorchのnn.Module、nn.Sequential、nn.ModuleList、レイヤーの継承関係とforwardの有無を示す図(出典:筆者作成)。

「モデルの作り方」より

モデルの作り方 ― nn.Module の思想と構造

PyTorch でニューラルネットワークのモデルを構築する場合、「モデル」とは モジュールクラス(のインスタンス)を作ることを意味します。

nn.Linear などのレイヤーや nn.Sequential は単体でもモデルとして使用可能なモジュールですが、複雑で実用的なモデルを作る際には、自分で基底クラスである nn.Module を継承してモジュールクラスを定義する必要があります。

モジュールはレイヤーを最小単位とし、互いにネストすることでツリー構造を作ることができます。よくある構成としては、自作クラス内でレイヤー、nn.Sequentialnn.ModuleList を使用するというものです。

forward メソッドを定義したモジュール(図中オレンジ枠)は、インスタンスがそのまま「関数」として動作するようになります。こうした forward() をもつモジュールはすべて、ニューラルネットワークのモデルとして使用できます。一方、nn.ModuleListforward を持たず、単体ではモデルとしては機能しません。

PyTorchのnn.Module、nn.Sequential、nn.ModuleList、レイヤーの継承関係とforwardの有無を示す図(出典:筆者作成)。

PyTorchにおける主要なモジュールクラスの関係図。nn.Module を基底とし、そのサブクラスであるSequentialやModuleList、レイヤー(ReLUやConvなど)をネストして構築する。forward() があるもの(オレンジ)はインスタンスが関数として振る舞い、学習・推論で使用できる。イラストはレイヤーの繋がり方を表す(出典:筆者作成)。

モデルの最小単位 ― レイヤー

nn.Module を継承したモジュールクラスとして、「レイヤー」と呼ばれるものが torch.nn公式ページ)にあらかじめ準備されています。

一般的には、学習可能なパラメータを持つ線形結合(nn.Linear)や畳み込み(nn.Conv2d)などを指しますが、ここでは活性化関数(nn.ReLUnn.Sigmoid…)や正則化(nn.BatchNorm2d など)も含めて、広義の「レイヤー」として扱います。

これらはニューラルネットワークにおける最も基本的な構成要素です。

# torch.nnをnnとしてインポートする ("nn"でtorch.nnを参照できる)
import torch.nn as nn

net = nn.Linear(2, 4)

上の例では、2次元の入力テンソルから4次元の線形結合出力を得る nn.Linear を使用しています。

このようなレイヤーのインスタンスは、パラメータ(重み・バイアス)を内部に持ち、初期化された状態で順伝播できるようになります。

最も簡単なモデル構築 ― nn.Sequential

nn.Sequential公式ページ)は nn.Module を継承したサブクラスです。Sequential 自体は単なる入れ物で、必要なレイヤーのインスタンスを順番に入れるだけで、それらを1本につなげた「Sequential(逐次的)」なモデルを作ることができます

ただし、nn.Linear などのレイヤーは入力・出力サイズの指定が必要なので、各レイヤー間で形状が一致するように設計する必要があります。

具体的な作り方は、以下のいずれでも問題ありません。

Sequentialの作り方1 ― レイヤーのインスタンスを直接並べる

import torch.nn as nn

# Sequentialでモデルを定義。レイヤーのインスタンスを並べるだけ。
net = nn.Sequential(
    nn.Linear(20, 256),
    nn.ReLU(),
    nn.Linear(256, 10),
    nn.ReLU(),
)

print(net)

出力例:

Sequential(
  (0): Linear(in_features=20, out_features=256, bias=True)
  (1): ReLU()
  (2): Linear(in_features=256, out_features=10, bias=True)
  (3): ReLU()
)

この例では、入力が20次元のベクトルで、それを256ノードの層→ReLU→10ノードの層→ReLUと通す構造になります。パラメータがランダムなため、出力も以下のように適当な値になります。

import torch

x = torch.ones(20)
predict = net(x)

print(predict)
# 出力例(ランダムな初期化による)
# tensor([0.0000, 0.2197, 0.0000, 0.0000, 0.0000, 0.0000, 0.1862, 0.2169, 0.0000, 0.0000], grad_fn=)

Sequentialの作り方2 ― リストをアンパック

レイヤーをリストに入れ、アンパック(*)して渡す方法もあります。

import torch.nn as nn

layer_block = [nn.Linear(5, 256), nn.ReLU(), nn.Linear(256, 5), nn.ReLU()]
net = nn.Sequential(*layer_block)

Sequentialの作り方3 ― OrderedDictを使って名前を付ける

OrderedDict を使うと、各レイヤーに明示的な名前をつけることができます。自動的に (0), (1), … と番号が振られる代わりに、'linear_in''relu_in' などを使って管理できます。

from collections import OrderedDict
import torch.nn as nn

layer_block = OrderedDict([
    ('linear_in', nn.Linear(5, 256)),
    ('relu_in', nn.ReLU()),
    ('linear_out', nn.Linear(256, 5)),
    ('relu_out', nn.ReLU())
])
net = nn.Sequential(layer_block)

モデル設計の本質 ― nn.Moduleを継承

nn.Moduleとは?基底クラスの役割

nn.Module公式ページ)自体は、ニューラルネットワークのモデル構築・訓練・推論などに共通する機能を持った、抽象的な基底クラスです。

このままではモデルとして使用できないため、具体的なモデルを構築するには、次に説明するようにnn.Module を継承し、レイヤーや他のモジュールを組み合わせて定義する必要があります。自由度が高く、基本的にどんなモデルでも表現可能です。

レイヤーの定義と forward

nn.Module を継承したクラスでは、以下の2つのメソッドを定義するのが基本です:

  • __init__():クラスの初期化(レイヤー定義)
  • forward():順伝播処理(入力→出力の変換)

__init__() は特殊メソッドで、インスタンス生成時に呼ばれます。ここでレイヤーや SequentialModuleList などを定義しておきます。

先頭に記述する super().__init__() は、親クラスである nn.Module の初期化処理を呼び出すため、必ず必要です。

一方 forward() には、入力をどのように処理して出力するかのロジックを記述します。これは Python の特殊メソッド __call__() によって内部的に呼び出され、インスタンスが「関数のように使える」ようになります。

# https://pytorch.org/docs/stable/generated/torch.nn.Module.html
import torch.nn as nn
import torch.nn.functional as F

class MyModel(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.conv1 = nn.Conv2d(1, 20, 3)
        self.conv2 = nn.Conv2d(20, 20, 3)

    def forward(self, x):
        x = F.relu(self.conv1(x))
        return F.relu(self.conv2(x))

nn.Moduleの諸機能

学習・評価モードの切り替え:.train() / .eval()

学習時と推論時では、Dropout や BatchNorm など一部のレイヤーの挙動が異なる設計なため、.train() / .eval() メソッドでモードを切り替える必要があります。

net = MyModel()

# 学習モード
net.train()

# 推論モード
net.eval()

デバイス管理:.cuda() / .cpu()

モデルのパラメータも Tensor と同様に GPU / CPU 間で移動させることができます。以下のように指定可能です:

net = MyModel()

# GPUのIDを指定して移動
net.cuda(0)

# デバイスオブジェクトで指定
device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
net.to(device)

モデルの保存とロード:.state_dict() / .load_state_dict()

公式チュートリアルにあるように、PyTorchでは、モデルのパラメータ(重みやバイアス)を保存・復元するために state_dict() / load_state_dict() が提供されています。

これにより、モデルの構造ではなく、学習の進行状態(チェックポイント)としてパラメータだけを効率的に保存できます。

保存されたパラメータを使用するには、まず訓練時と同じ構造の nn.Module インスタンスを再生成し、その後 load_state_dict() を呼び出して復元します。

保存:torch.save と state_dict()

torch.save(net.state_dict(), 'model.pth')  # 保存先ファイル名

state_dict() によって、モデルのすべての学習可能パラメータが辞書形式で取得され、.pth という形式で保存されます。

ロード:load_state_dict()

net = MyModel()  # モデル構造を再生成
net.load_state_dict(torch.load('model.pth'))  # パラメータを読み込み

モデル構造が保存時と一致している必要があるため、再構築してから読み込みを行います。

実践的な nn.Module の作り方

モジュールは互いにネスト(入れ子構造)にできます。nn.Module を継承したクラスの中で nn.Sequentialnn.ModuleList を使えるのはもちろん、自作したモジュール同士をさらに他のモジュールの中で使うこともできます。

そのため構造の組み合わせは事実上無限にありますが、ここでは代表的な構造として、nn.Module の中で SequentialModuleList を利用する例を紹介します。

nn.Module + nn.Sequential

Sequential はレイヤーを順番に並べて接続するための簡便な仕組みです。以下は MLP(Multilayer Perceptron)nn.Modulenn.Sequential を組み合わせて構築した例です。

この例では以下の3つのレイヤーブロックを使っています:

  • self.input_layer: 入力ノード → 隠れ層ノード
  • self.hidden_layers: 同じサイズの隠れ層を num_layers 回繰り返す(Sequentialで実装)
  • self.output_layer: 隠れ層ノード → 出力ノード
import torch
import torch.nn as nn
import torch.nn.functional as F

class MLP(nn.Module):
    def __init__(self, input_dim=64, hidden_dim=64, num_layers=5, output_dim=1):
        super().__init__()
        
        self.input_layer = nn.Linear(input_dim, hidden_dim)

        layers = []
        for _ in range(num_layers):
            layers.append(nn.Linear(hidden_dim, hidden_dim))
            layers.append(nn.ReLU())

        self.hidden_layers = nn.Sequential(*layers)

        self.output_layer = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        x = self.hidden_layers(x)
        return self.output_layer(x)

nn.Module + nn.ModuleList

ModuleList公式)は、nn.Module のリストのように使えるコンテナです。

Sequential はレイヤーをつなげて1つの大きなモジュールにするのに対して、ModuleList個別のレイヤーをリスト形式で保持します。そのため forward() の中で、ループを用いて手動で処理する必要があります。

class MLP(nn.Module):
    def __init__(self, input_dim=64, hidden_dim=64, num_layers=5, output_dim=1):
        super().__init__()
        self.input_layer = nn.Linear(input_dim, hidden_dim)

        self.hidden_layers = nn.ModuleList([
            nn.Linear(hidden_dim, hidden_dim) for _ in range(num_layers)
        ])

        self.output_layer = nn.Linear(hidden_dim, output_dim)

    def forward(self, x):
        x = F.relu(self.input_layer(x))
        for layer in self.hidden_layers:
            x = F.relu(layer(x))
        return self.output_layer(x)

先ほどとモデルは全く同じですが、 ModuleList を使えば forward() 中で各層に対して個別に処理を加えたり、途中の出力を取り出す、分岐させるなどといった、柔軟な操作が可能になります。これは Sequential にはない利点です。

nn.Module + nn.functional

nn.functional には、パラメータを持たない演算関数が多数含まれています(例:F.reluF.softmax など)。

一見すると F.linearF.conv2d のようにパラメータを含むように見える関数もありますが、これらは「学習用のパラメータ」ではなく、引数として外部から渡す形式になります。

つまり nn.functional は、学習用ではない固定的された演算を手動で設計する場合などに使用します。

まとめ

  • nn.Module は PyTorch モデル構築の基底クラスで、全てのモデルの土台。
  • レイヤー(nn.Linear や nn.ReLU など)は nn.Module を継承した最小単位。
  • nn.Sequential は直列構造に特化し、最も簡単に使えるモデル構築法。
  • nn.ModuleList は柔軟な繰り返しや構造操作に強く、for文と併用される。
  • nn.functional は演算関数の集合で、設計上の固定処理や補助的な役割に活用。
  • forward() を持つモジュールは関数のように使え、モデルとして使用可能。
  • モジュールは自由にネスト可能で、複雑な構造でも柔軟に対応できる。

【実践基礎8】PyTorchの「自動微分」と「誤差逆伝播」を徹底解説|Tensorとoptimizerで学ぶ学習の流れ

前の記事  次の記事


ディープラーニングで Numpy ではなく Tensor が使われる大きな理由の一つが「自動微分」です。学習の際には、何百万、何千万パラメータについてチェインルールに基づいて微分を行う必要があり、自動微分は必須となります。これは、さらに Tensor の機能で GPU を利用することで大きな威力を発揮します。

<概要>

  • Tensor の backward() による自動微分の計算方法
  • optimizer.step() による誤差逆伝播法

を中心に、実際のコードとその挙動を、グラフや図を交えながらビジュアルに説明します。

<この記事で扱う主要なモジュール・ライブラリ一覧>

import torch

<関連記事>

<コード>

PyTorchにおける自動微分とoptimizerの学習ステップ。zero_gradで勾配初期化、backwardで勾配計算、stepでパラメータ更新を行う流れ。

PyTorchにおける自動微分とoptimizerによる学習ステップの流れ (コードで実践より)

計算グラフ

Tensor では、複雑な関数に含まれる大量のパラメータについて自動微分を行うために、計算グラフを使います。グラフは普段は隠れて見えず、特に意識しないでいいですが、Tensor のイメージを掴むために、1次関数の計算グラフを簡単に眺めてみましょう。

PyTorch Tensor で自作した1次関数の計算グラフ。torchvizのmake_dotで作成(出典:筆者作成)。

Tensor で作成した1次関数の計算グラフ。torchviz の make_dot を使用(出典:筆者作成)。

水色の ”linear.bias” が切片、”linear.weight“ が傾き、そして緑の箱が出力です。データのサンプル数の次元があるため、データの形がスカラーではなく (1, 1) となっています。矢印を遡って出力(緑)からパラメータ(青)までたどることで、チェインルールに則って偏微分を行う経路がわかります

グラフ中の “AccumulateGrad” は、自動微分を行うたびに、モデル(関数)の各パラメータに関する偏微分の値が加算されながら、その値が保持されることを表しています。ミニバッチ学習などでは、ある程度まとまったデータ毎に勾配を平均してから誤差逆伝播をするため、値が加算されるのは理にかなっています。

※ モデルを正しく作れているかを視覚的に確認するのに torchviz は便利ですが、ディープラーニングの学習には特に必要ありません。

Tensorの自動微分

requires_grad

ある Tensor を使って関数を作るときに、Tensor を requires_grad=True とすることで、関数を微分するときの変数として扱われます。教師あり学習で使われる損失関数は、「入力データ」、「重みやバイアスなどモデルのパラメータ」、そして「正解データ」を Tensor として持っています。入力データと正解データは変えることのできない所与の値であり「定数」ですが、調整すべきモデルのパラメータは「変数」なのでrequires_grad=Trueと設定します。

# パラメータ "w" を、勾配を求めるときに変数として扱うことを宣言
import torch
w = torch.tensor([1.0], requires_grad=True)

PyTorch の torch.nn.Module を用いてモデルを構築する場合、パラメータは自動的に requires_grad になるため、普通の学習では requires_grad を気にする必要はありません。しかし、遷移学習 (Transfer learning) やニューラルネットワークモデルを損失関数の計算に使う perceptual loss などでは、パラメータ(の一部)を固定するため、requires_grad = False として勾配計算をオフにするなど、細かい設定が必要となります

loss.backward()

Tensor 変数 loss についての微分を計算します。値は 各 Tensor 変数 (パラメータ) の grad という属性に格納されます。属性とは numpy であれば .shape がそれに当たります。たとえばあるパラメータ w の微分値は w.grad となります。.backward() で微分を計算すると、毎回新しい微分値に更新されるのではなく、現在の .grad の値に加算されていきます。

loss.backward()

ここで loss は単に Tensor からなる関数であり、backward() は任意の Tensor からなる関数でできる操作であることに注意してください。

optimizerで誤差逆伝播

Optimizerの設定

.backward() を使えば、損失関数をすべてのモデルパラメータについて一行で微分できることがわかりました。次に、勾配をもとにすべてのパラメータを更新する必要があります。まずは以下のように、最適化アルゴリズムを指定して optimizer オブジェクトを作ります 。

optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # SGDで最適化
optimizer = torch.optim.Adam([var1, var2], lr=0.001) # Adamで最適化

optimizer の最初の引数は全パラメータを含んだ iterable (イテラブル; リストなどのように、for loop で値を取り出せる)です。ここで学習率なども必要に応じて指定します (公式リンク)。

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

Optimizer オブジェクト optimizer には step() メソッドがあります。step() は、先程のloss.backward() で求めた 勾配の値 (.grad) を使ってパラメータを更新します。


    optimizer.step()

optimizer.zero_grad()

パラメータの grad 属性にある勾配を初期化します。backward() で説明したように、微分値は計算されるたびに加算されていくので、例えばミニバッチ毎に学習する場合、バッチ毎に最初にzero_grad による初期化が必要です。

optimizer.zero_grad()

コードで実践

一般的な学習の仕組みと手順は以下の通り、1. zero_grad() でパラメータを初期化、2. backward() で勾配計算、 3. step() でパラメータを更新、となります。オレンジ色 (モデルから損失関数、optimizer 、 loss) は計算グラフ上、すべて Tensor 型のパラメータ wb で繋がっています。

PyTorchにおける自動微分とoptimizerの学習ステップ。zero_gradで勾配初期化、backwardで勾配計算、stepでパラメータ更新を行う流れ。

PyTorchにおける自動微分とoptimizerによる学習ステップの流れ

より具体的に Tensor による微分を理解するために、上の手順に沿って、手作りの 1 次関数で学習の様子を見てみましょう。といっても肝心の部分は 10 行ほどです。Tensor の具体的な挙動の理解は、単にイメージを掴むためだけでなく、遷移学習など、後々の応用でも必要になってきます。

Tensorでデータとモデルの準備 (requires_grad, zero_grad)

まずは訓練用の入力データ (x_train)、正解データ (y_train)、そして傾き w = 1 の一次関数モデルを Tensor で準備します。

import torch

# 訓練データ
x_train = torch.tensor([0, 1, 2, 3])  # 入力(テンソル)データ
y_train = torch.tensor([0, 2, 3, 3]) # 正解(テンソル)データ

# 傾きwの1次関数のモデル
def net(x, w):
  return w * x
  
# パラメータの初期設定 (テンソル w)。勾配を計算したいので requires_grad=True を設定
w = torch.tensor([1.0], requires_grad=True)

# 最適化アルゴリズム
optimizer = torch.optim.SGD([w], lr=0.01) # パラメータ w を iterable (list) :[w] として optimizer にわたす 
optimizer.zero_grad() # パラメータの勾配を初期化

訓練では最初、パラメータにランダムな値が振られます。今回はその値がたまたま 1 としました。下のプロットを見ると、データ点がモデルよりやや上に分布しているので、理想的な傾きは 1 よりやや大きいことがわかります。

最適化アルゴリズムとして、挙動がわかりやすい SGD を学習率 lr = 0.01 で使用しています。今回は初期化は特に必要ないですが、ループを回すときなどは zero_grad() を最初に書く必要があります。

初期パラメータでのTensorの1次関数モデルと訓練データのプロット。学習前のモデルがデータ点にフィットしていない様子。出典:筆者作成。

PyTorchにおける自動微分とoptimizerによる学習ステップの流れ(出典:筆者作成)

Tensorで誤差逆伝播 (loss.backward, optimizer.step)

以下、順伝播、損失の計算、勾配計算からパラメータの更新までのコードです。

# 順伝播
y_pred = net(x_train, w)

# 損失関数
loss = torch.sum((y_pred - y_train)**2)

# 勾配計算 (requires_grad で変数とみなされた w についてのみ勾配を計算)
loss.backward()

# 勾配の確認
print(f"w.grad: {w.grad}") # 全データについて勾配が足し合わされ、grad属性に値が入る

optimizer.step() # パラメータの更新
print(f"w: {w}") # 先ほど求めた勾配 x (-1) x lr になる

loss.backward() の際、損失関数 loss には3種類の Tensor (x_train, y_train, w) が含まれていますが、requires_grad = True としたパラメータ w のみが変数とみなされ、lossw について偏微分した値 w.grad のみが計算されます。

勾配の値 w.grad は今回は “-6” となります。optimizer.step() では、新しいパラメータは

 \displaystyle w \to w - \eta \frac{\partial l}{\partial w} = w - lr \times w.grad

となるため、更新したパラメータの値は 1.06 と表示されます (最適化の基礎と勾配降下法についてはこちら)。

誤差逆伝播の結果

今回はデータセットが1セット (x_train, y_train) ですべてなので、これで 1 エポック分の学習が終わったことになります。上で学習したモデルをプロットすると、傾きがやや増加して、データ点に近づいていることがわかります。大量のデータでミニバッチ学習をする場合は、このデータ点はバッチごとに変わり、データに合わせて傾きが少しずつ変化していきます。複雑なニューラルネットワークの学習も、原理的には全く同じです。

optimizer.step() 実行後のTensorの1次関数モデルと訓練データのプロット。モデルがデータ点に近づいた様子。出典:筆者作成。

PyTorchにおける自動微分とoptimizerによる学習ステップの流れ(出典:筆者作成)

まとめ

  • Tensor はデータ構造+自動微分を担う重要な要素。
  • requires_grad=True で自動微分の対象を明示。
  • backward() で勾配計算、optimizer.step() でパラメータ更新。
  • optimizer.zero_grad() を忘れずにリセット。

前の記事: PyTorchのTensorとは?Numpyとの違いと基本操作を初心者向けに徹底解説

次の記事: PyTorchモデルの全体構造と作り方|nn.Module・Sequential・ModuleListを図解で理解