PyTorch 畳み込みニューラルネットワーク
PyTorch 畳み込みニューラルネットワーク(Convolutional Neural Networks, CNN)は、画像などのグリッド状のトポロジー構造を持つデータを処理するために特化したディープラーニングモデルの一種です。
CNN は、画像分類、物体検出、セグメンテーションなどのコンピュータビジョンタスクにおける中核技術です。
次の図は、画像認識タスクに使用される典型的な畳み込みニューラルネットワーク(CNN)の構造と処理の流れを示しています。

図では、CNN の出力層が Donald(0.2)、Goofy(0.1)、Tweety(0.7)の3つのカテゴリの確率を出力しており、ネットワークが入力画像は最も Tweety である可能性が高いと判断していることを示しています。
以下は各構成要素の簡単な説明です:
-
入力画像(Input Image):ネットワークが受け取る生の画像データ。
-
畳み込み(Convolution):カーネル(Kernel)を入力画像上でスライドさせて特徴を抽出し、特徴マップ(Feature Maps)を生成します。
-
プーリング(Pooling):通常は畳み込み層の後に、最大プーリングまたは平均プーリングによって特徴マップのサイズを縮小し、重要な特徴を保持しながらプーリング済み特徴マップ(Pooled Feature Maps)を生成します。
-
特徴抽出(Feature Extraction):複数の畳み込み層とプーリング層の組み合わせにより、画像の高次特徴を段階的に抽出します。
-
フラット化層(Flatten Layer):多次元の特徴マップを1次元ベクトルに変換し、全結合層に入力できるようにします。
-
全結合層(Fully Connected Layer):従来のニューラルネットワーク層に似ており、抽出された特徴を出力カテゴリにマッピングします。
-
分類(Classification):ネットワークの出力層であり、全結合層の出力に基づいて分類を行います。
-
確率分布(Probabilistic Distribution):出力層が各カテゴリの確率を出力し、入力画像が各カテゴリに属する可能性を示します。
畳み込みニューラルネットワークの基本構造
1、入力層(Input Layer)
生の画像データを受け取ります。画像は通常3次元配列で表され、2つの次元は画像の幅と高さ、3つ目の次元は色チャンネル(例えば、RGB画像は3チャンネル)を表します。
2、畳み込み層(Convolutional Layer)
畳み込みカーネルを使用して、エッジやテクスチャなどの局所特徴を抽出します。
公式:

- x:入力画像。
- k:畳み込みカーネル(重み行列)。
- b:バイアス。
学習可能なフィルタ(または畳み込みカーネル)のセットを入力画像に適用して畳み込み演算を行い、局所特徴を抽出します。
各フィルタは入力画像上をスライドし、フィルタの各位置での活性化を表す特徴マップ(Feature Map)を生成します。
畳み込み層は複数のフィルタを持つことができ、各フィルタが特徴マップを生成し、すべての特徴マップが特徴マップのセットを構成します。
3、活性化関数(Activation Function)
通常は畳み込み層の後に ReLU(Rectified Linear Unit)などの非線形活性化関数を適用して、非線形性を導入し、ネットワークがより複雑なパターンを学習できるようにします。
ReLU 関数は次のように定義されます:f(x)=max(0,x)つまり、入力が0未満の場合は0を出力し、それ以外の場合は入力値を出力します。
4、プーリング層(Pooling Layer)
- 特徴マップの空間次元を低減し、計算量とパラメータ数を減らすとともに、最も重要な特徴情報を保持します。
- 最も一般的なプーリング操作は、最大プーリング(Max Pooling)と平均プーリング(Average Pooling)です。
- 最大プーリングは領域内の最大値を選択し、平均プーリングは領域内の平均値を計算します。
5、正規化層(Normalization Layer、オプション)
- 例として、局所応答正規化(Local Response Normalization, LRN)やバッチ正規化(Batch Normalization)があります。
- これらの層はトレーニングプロセスを高速化し、モデルの安定性を向上させるのに役立ちます。
6、全結合層(Fully Connected Layer)
- CNN の末端では、前の層で抽出された特徴マップをフラット化(Flatten)して1次元ベクトルにし、全結合層に入力します。
- 全結合層の各ニューロンは前の層のすべてのニューロンと結合されており、特徴を総合して最終的な分類または回帰を行います。
7、出力層(Output Layer)
タスクに応じて、出力層は異なる形式を持つことができます。
分類タスクでは、通常 Softmax 関数を使用して出力を確率分布に変換し、入力が各カテゴリに属する確率を表します。
8、損失関数(Loss Function)
モデルの予測と真のラベルとの間の差異を測定するために使用されます。
一般的な損失関数には、多クラス分類タスクに使用される交差エントロピー損失(Cross-Entropy Loss)や、回帰タスクに使用される平均二乗誤差(Mean Squared Error, MSE)があります。
9、オプティマイザ(Optimizer)
損失関数の勾配に基づいてネットワークの重みを更新するために使用されます。一般的なオプティマイザには、確率的勾配降下法(SGD)、Adam、RMSprop などがあります。
10、正則化(Regularization、オプション)
ドロップアウトや L1/L2 正則化などの技術が含まれ、モデルの過学習を防ぐために使用されます。
これらの層は積み重ねてより深いネットワーク構造を形成し、モデルの学習能力を高めることができます。
CNN の深さと複雑さは、タスクの要件に応じて調整できます。
PyTorch で CNN の例を実装する
次の例では、PyTorch を使用して、MNIST データセットの数字分類用の簡単な CNN モデルを構築する方法を示します。
主な手順:
- データの読み込みと前処理:使用し、
torchvisionMNIST データを読み込んで前処理します。 - モデルの構築:畳み込み層、プーリング層、全結合層を定義します。
- トレーニング:損失関数とオプティマイザを使用してモデルをトレーニングします。
- 評価:テストセット上でモデルの精度を計算します。
- 可視化:テストサンプルの一部とその予測結果を表示します。
1、必要なライブラリをインポート
import torch import torch.nn as nn import torch.nn.functional as F import torch.optim as optim
2、データ読み込み
torchvision が提供する MNIST データセットを使用して、データを読み込み、前処理します。
例
transforms.ToTensor(), # テンソルに変換
transforms.Normalize((0.5,), (0.5,)) # [-1, 1] に正規化
])
# MNIST データセットを読み込む
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)
3、CNN モデルを定義
使用してnn.ModuleCNN を構築します。例
def __init__(self):
super(SimpleCNN, self).__init__()
# 畳み込み層を定義:入力1チャンネル、出力32チャンネル、カーネルサイズ3x3
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
# 畳み込み層を定義:入力32チャンネル、出力64チャンネル
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
# 全結合層を定義
self.fc1 = nn.Linear(64 * 7 * 7, 128) # 入力サイズ = 特徴マップサイズ * チャンネル数
self.fc2 = nn.Linear(128, 10) # 10 クラス
def forward(self, x):
x = F.relu(self.conv1(x)) # 1層目の畳み込み + ReLU
x = F.max_pool2d(x, 2) # 最大プーリング
x = F.relu(self.conv2(x)) # 2層目の畳み込み + ReLU
x = F.max_pool2d(x, 2) # 最大プーリング
x = x.view(-1, 64 * 7 * 7) # フラット化操作
x = F.relu(self.fc1(x)) # 全結合層 + ReLU
x = self.fc2(x) # 全結合層の出力
return x
# モデルインスタンスを作成
model = SimpleCNN()
4、損失関数とオプティマイザを定義
交差エントロピー損失と確率的勾配降下法オプティマイザを使用します。
criterion = nn.CrossEntropyLoss() # 多分类交叉熵损失 optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9) # 学习率和动量
5、モデルの訓練
モデルを5エポック訓練し、各エポック後に訓練損失を出力します。
例
model.train() # 訓練モードに設定
for epoch in range(num_epochs):
total_loss = 0
for images, labels in train_loader:
# 順伝播
outputs = model(images)
loss = criterion(outputs, labels)
# 逆伝播
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_loss += loss.item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss / len(train_loader):.4f}")
6、モデルのテスト
テストセット上でモデルの精度を評価します。
例
correct = 0
total = 0
with torch.no_grad(): # 評価時は勾配を計算する必要はない
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs, 1) # クラスを予測
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
print(f"Test Accuracy: {accuracy:.2f}%")
7、完全なコード
完全なコードは以下のとおりです:
例
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
# 1. データの読み込みと前処理
transform = transforms.Compose([
transforms.ToTensor(), # テンソルに変換
transforms.Normalize((0.5,), (0.5,)) # [-1, 1] に正規化
])
# MNIST データセットを読み込み
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)
# 2. CNN モデルの定義
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チャンネル、出力32チャンネル
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1) # 入力32チャンネル、出力64チャンネル
# 全結合層を定義
self.fc1 = nn.Linear(64 * 7 * 7, 128) # フラット化して全結合層に入力
self.fc2 = nn.Linear(128, 10) # 10クラス
def forward(self, x):
x = F.relu(self.conv1(x)) # 最初の畳み込み層 + ReLU
x = F.max_pool2d(x, 2) # 最大プーリング
x = F.relu(self.conv2(x)) # 2番目の畳み込み層 + ReLU
x = F.max_pool2d(x, 2) # 最大プーリング
x = x.view(-1, 64 * 7 * 7) # フラット化
x = F.relu(self.fc1(x)) # 全結合層 + ReLU
x = self.fc2(x) # 最後の層の出力
return x
# モデルインスタンスを作成
model = SimpleCNN()
# 3. 損失関数とオプティマイザの定義
criterion = nn.CrossEntropyLoss() # 多クラス交差エントロピー損失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 4. モデルの訓練
num_epochs = 5
model.train() # モデルを訓練モードに設定
for epoch in range(num_epochs):
total_loss = 0
for images, labels in train_loader:
outputs = model(images) # 順伝播
loss = criterion(outputs, labels) # 損失を計算
optimizer.zero_grad() # 勾配をゼロ化
loss.backward() # 逆伝播
optimizer.step() # パラメータを更新
total_loss += loss.item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss / len(train_loader):.4f}")
# 5. モデルのテスト
model.eval() # モデルを評価モードに設定
correct = 0
total = 0
with torch.no_grad(): # 勾配計算をオフにする
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
print(f"Test Accuracy: {accuracy:.2f}%")
実行結果の説明
1. 出力された訓練損失
コードでは各エポックごとに平均損失が一度出力されます。例:
Epoch [1/5], Loss: 0.2325 Epoch [2/5], Loss: 0.0526 Epoch [3/5], Loss: 0.0366 Epoch [4/5], Loss: 0.0273 Epoch [5/5], Loss: 0.0221
説明:損失が徐々に減少することは、モデルが段階的に収束していることを示します。
2. テストセットの精度
コードはテストセット上で最終的な分類精度を出力します。例:
Test Accuracy: 98.96%
説明:MNIST テストセットに対するモデルの分類精度は 98.96% であり、シンプルな CNN モデルとしては良い結果です。
7、結果の可視化
テストデータ内のいくつかのサンプルとその予測結果を可視化できます。
例
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms
import matplotlib.pyplot as plt
# 1. データの読み込みと前処理
transform = transforms.Compose([
transforms.ToTensor(), # テンソルに変換
transforms.Normalize((0.5,), (0.5,)) # [-1, 1] に正規化
])
# MNIST データセットを読み込み
train_dataset = datasets.MNIST(root='./data', train=True, transform=transform, download=True)
test_dataset = datasets.MNIST(root='./data', train=False, transform=transform, download=True)
train_loader = torch.utils.data.DataLoader(dataset=train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset, batch_size=64, shuffle=False)
# 2. CNN モデルの定義
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チャンネル、出力32チャンネル
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1) # 入力32チャンネル、出力64チャンネル
# 全結合層を定義
self.fc1 = nn.Linear(64 * 7 * 7, 128) # フラット化して全結合層に入力
self.fc2 = nn.Linear(128, 10) # 10クラス
def forward(self, x):
x = F.relu(self.conv1(x)) # 最初の畳み込み層 + ReLU
x = F.max_pool2d(x, 2) # 最大プーリング
x = F.relu(self.conv2(x)) # 2番目の畳み込み層 + ReLU
x = F.max_pool2d(x, 2) # 最大プーリング
x = x.view(-1, 64 * 7 * 7) # フラット化
x = F.relu(self.fc1(x)) # 全結合層 + ReLU
x = self.fc2(x) # 最後の層の出力
return x
# モデルインスタンスを作成
model = SimpleCNN()
# 3. 損失関数とオプティマイザの定義
criterion = nn.CrossEntropyLoss() # 多クラス交差エントロピー損失
optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
# 4. モデルの訓練
num_epochs = 5
model.train() # モデルを訓練モードに設定
for epoch in range(num_epochs):
total_loss = 0
for images, labels in train_loader:
outputs = model(images) # 順伝播
loss = criterion(outputs, labels) # 損失を計算
optimizer.zero_grad() # 勾配をゼロ化
loss.backward() # 逆伝播
optimizer.step() # パラメータを更新
total_loss += loss.item()
print(f"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss / len(train_loader):.4f}")
# 5. モデルのテスト
model.eval() # モデルを評価モードに設定
correct = 0
total = 0
with torch.no_grad(): # 勾配計算をオフにする
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
print(f"Test Accuracy: {accuracy:.2f}%")
# 6. テスト結果の可視化
dataiter = iter(test_loader)
images, labels = next(dataiter)
outputs = model(images)
_, predictions = torch.max(outputs, 1)
fig, axes = plt.subplots(1, 6, figsize=(12, 4))
for i in range(6):
axes[i].imshow(images[i][0], cmap='gray')
axes[i].set_title(f"Label: {labels[i]}\nPred: {predictions[i]}")
axes[i].axis('off')
plt.show()
可視化結果は、6つのテストサンプルの実際のラベルと予測値を示しています。例:

画像の左上隅は手書き数字です。
タイトル部分にはモデルの予測値と正解ラベルが表示されます。
注意すべきエラー
MNIST データセットのダウンロード時に、SSL 証明書の検証に失敗してデータをダウンロードできない場合があります。
Downloading http://yann.lecun.com/exdb/mnist/train-images-idx3-ubyte.gz Failed to download (trying next): <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1129)> ...
解決策
ターミナルを開き、以下のコマンドを実行して SSL 証明書をインストール/更新します:
/Applications/Python\ 3.x/Install\ Certificates.command
その中の 3.x は、実際にインストールされている Python バージョンに置き換えてください。
このコマンドを実行した後、Python コードを再実行すると、MNIST データセットを正常にダウンロードできるはずです。
その他の拡張