前回は、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の応用へ。