PyTorch学習ノート4 - CNNの構築

投稿日: 2025/09/22

OGP

前回は、PyTorchを使った基本的なニューラルネットワークの構築と学習方法を学びました。
今回は、畳み込みニューラルネットワーク(CNN: Convolutional Neural Network)の構築方法を紹介します。

1. CNNの基本構造

畳み込みニューラルネットワーク(CNN)は、画像認識や映像処理などで広く使われているニューラルネットワークの一種です。
CNNは、以下の主要な層で構成されます。

  • 畳み込み層(Convolutional Layer): 画像から特徴を抽出する層
  • プーリング層(Pooling Layer): 特徴マップのサイズを縮小化する層
  • 全結合層(Fully Connected Layer): 最終的な分類を行う層

1.1 畳み込み層とは

畳み込み層は、フィルター(カーネル)を使って入力画像から特徴を抽出します。
フィルターは、画像の一部に対して畳み込み演算を行い、特徴マップを生成します。

1.2 プーリング層とは

プーリング層は、特徴マップの空間的なサイズを縮小し、計算量を削減します。
ここでは、最大プーリング(Max Pooling)を使用しています。

1.3 全結合層とは

全結合層は、前の層からの出力を1次元ベクトルに変換し、最終的な分類を行います。

2. PyTorchでのCNN構築

2.1 モデルの定義

まず、torch.nn.Moduleを継承したクラスを作成し、CNNの構造を定義します。

import torch
import torch.nn as nn
import torch.nn.functional as F

class SimpleCNN(nn.Module):
    def __init__(self):
        super(SimpleCNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)  # 畳み込み層1
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)       # プーリング層
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1) # 畳み込み層2
        self.fc1 = nn.Linear(64 * 7 * 7, 128)                              # 全結合層1
        self.fc2 = nn.Linear(128, 10)                                      # 全結合層2

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))  # 畳み込み層1 + ReLU + プーリング
        x = self.pool(F.relu(self.conv2(x)))  # 畳み込み層2 + ReLU + プーリング
        x = x.view(-1, 64 * 7 * 7)             # フラット化
        x = F.relu(self.fc1(x))                # 全結合層1 + ReLU
        x = self.fc2(x)                        # 全結合層2
        return x

nn.Conv2dは2次元畳み込み層を定義するためのクラスです。
ここでは、1チャネルの入力画像から32チャネルの特徴マップを生成する畳み込み層を定義しています。
nn.MaxPool2dは2次元最大プーリング層を定義するためのクラスです。
ここでは、2x2のカーネルを使って特徴マップのサイズを半分に縮小しています。
nn.Linearは全結合層を定義するためのクラスです。
ここでは、畳み込み層の出力を128次元に変換し、最終的に10クラスの分類を行う全結合層を定義しています。

self.conv1(x)は、入力データxを畳み込み層conv1に通し、その出力を次の層に渡します。
F.reluはReLU活性化関数を適用します。
self.pool(x)は、ReLUの出力をプーリング層に通します。
つまり、self.pool(F.relu(self.conv1(x)))は、畳み込み層1の出力にReLUを適用し、その後プーリングを行う一連の操作を表しています。

x.view(-1, 64 * 7 * 7)は、テンソルをフラット化して全結合層に入力できる形に変換します。
-1はバッチサイズを自動的に計算するための指定です。

self.fc1(x)は、フラット化されたデータを全結合層fc1に通し、その出力を次の層に渡します。
つまり、F.relu(self.fc1(x))は、全結合層1の出力にReLUを適用する操作を表しています。

self.fc2(x)は、全結合層2の出力をそのまま返しています。

2.2 モデルのインスタンス化

次に、モデルのインスタンスを作成します。

model = SimpleCNN()

2.3 損失関数と最適化手法の定義

ニューラルネットワークの学習には、損失関数と最適化手法が必要です。

criterion = nn.CrossEntropyLoss()  # クロスエントロピー損失
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)  # Adam最適化手法

ここでは、損失関数としてクロスエントロピー損失を使用し、最適化手法としてAdamを選択しています。
クロスエントロピー損失は、分類問題でよく使われる損失関数で、予測確率と実際のラベルとの間の差を測定します。
Adamは、適応的な学習率を持つ最適化手法で、収束が速く、ハイパーパラメータの調整が比較的容易です。

2.4 モデルの学習

モデルの学習は、前回と同様に行います。

# ダミーデータの作成
inputs = torch.randn(100, 1, 28, 28)  # 100サンプル、1チャネル、28x28画像
targets = torch.randint(0, 10, (100,)) # 100サンプル、0-9のラベル

# 学習ループ
for epoch in range(100):  # 100エポック
    model.train()  # モデルを訓練モードに設定
    optimizer.zero_grad()  # 勾配の初期化
    outputs = model(inputs)  # 順伝播
    loss = criterion(outputs, targets)  # 損失の計算
    loss.backward()  # 逆伝播
    optimizer.step()  # パラメータの更新

    if (epoch+1) % 10 == 0:
        print(f'Epoch [{epoch+1}/100], Loss: {loss.item():.4f}')

このコードでは、100エポックにわたってモデルを学習させています。
各エポックで、入力データに対するモデルの出力を計算し、損失を評価し、勾配を計算してパラメータを更新します。
10エポックごとに損失を表示しています。

実際に実行すると、損失が徐々に減少していくことが確認できます。

これで、PyTorchを使った基本的な畳み込みニューラルネットワーク(CNN)の構築と学習方法を学びました。
次回は、より複雑なモデルやデータセットを使った実践的な例を紹介します。
続きは、PyTorch学習ノート5 - 実践的なCNNの応用へ。