卷積神經網絡(CNN)是深度學習中的重要組成部分,廣泛應用于圖像處理、語音識別、視頻分析等任務。在這篇博客中,我們將使用 PyTorch 實現一個標準的卷積神經網絡(CNN),并介紹各個部分的作用。
什么是卷積神經網絡(CNN)?
卷積神經網絡(CNN)是一種專門用于處理圖像數據的深度學習模型,它通過卷積層提取圖像的特征。CNN 由多個層次組成,其中包括卷積層(Conv2d)、池化層(MaxPool2d)、全連接層(Linear)、激活函數(ReLU)等。這些層級合作,使得模型能夠從原始圖像中自動學習到重要特征。
CNN 的核心組成部分
- 卷積層(Conv2d):用于提取輸入圖像的局部特征,通過多個卷積核對圖像進行卷積運算。
- 激活函數(ReLU):增加非線性,使得模型能夠學習更復雜的特征。
- 池化層(MaxPool2d):通過對特征圖進行下采樣來減少空間尺寸,降低計算復雜度,同時保留重要的特征。
- 全連接層(Linear):將卷積和池化后得到的特征圖展平,送入全連接層進行分類或回歸預測。
PyTorch 實現 CNN
下面是我們實現的標準卷積神經網絡模型。它包含三個卷積層和兩個全連接層,適用于圖像分類任務,如 MNIST 數據集。
代碼實現
import torch
import torch.nn as nn
import torch.nn.functional as Fclass CNN(nn.Module):def __init__(self):super(CNN, self).__init__()# 卷積層1: 輸入1個通道(灰度圖像),輸出32個通道self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1, padding=1)# 卷積層2: 輸入32個通道,輸出64個通道self.conv2 = nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1)# 卷積層3: 輸入64個通道,輸出128個通道self.conv3 = nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1)# 全連接層1: 輸入128*7*7,輸出1024個節點self.fc1 = nn.Linear(128 * 7 * 7, 1024)# 全連接層2: 輸入1024個節點,輸出10個節點(假設是10分類問題)self.fc2 = nn.Linear(1024, 10)# Dropout層: 避免過擬合self.dropout = nn.Dropout(0.5)def forward(self, x):# 第一層卷積 + ReLU 激活 + 最大池化x = F.relu(self.conv1(x))x = F.max_pool2d(x, 2, 2) # 使用2x2的最大池化# 第二層卷積 + ReLU 激活 + 最大池化x = F.relu(self.conv2(x))x = F.max_pool2d(x, 2, 2)# 第三層卷積 + ReLU 激活 + 最大池化x = F.relu(self.conv3(x))x = F.max_pool2d(x, 2, 2)# 展平層(將卷積后的特征圖展平成1D向量)x = x.view(-1, 128 * 7 * 7) # -1代表自動推算batch size# 第一個全連接層 + ReLU 激活 + Dropoutx = F.relu(self.fc1(x))x = self.dropout(x)# 第二個全連接層(輸出最終分類結果)x = self.fc2(x)return x# 創建CNN模型
model = CNN()# 打印模型架構
print(model)
代碼解析
-
卷積層(Conv2d):
self.conv1 = nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3, stride=1, padding=1)
:該層的輸入為 1 個通道(灰度圖像),輸出 32 個通道,卷積核大小為 3x3,步幅為 1,填充為 1,保持輸出特征圖的大小與輸入相同。- 后續的卷積層類似,只是輸出通道數量逐漸增多。
-
激活函數(ReLU):
F.relu(self.conv1(x))
:ReLU 激活函數將輸入的負值轉為 0,并保留正值,增加了模型的非線性。
-
池化層(MaxPool2d):
F.max_pool2d(x, 2, 2)
:使用 2x2 的池化窗口和步幅為 2 進行池化,將特征圖尺寸縮小一半,減少計算復雜度。
-
展平(Flatten):
x = x.view(-1, 128 * 7 * 7)
:在經過卷積和池化操作后,我們將多維的特征圖展平成一維向量,供全連接層輸入。
-
Dropout:
self.dropout = nn.Dropout(0.5)
:Dropout 正則化技術在訓練時隨機丟棄一些神經元,防止過擬合。
-
全連接層(Linear):
self.fc1 = nn.Linear(128 * 7 * 7, 1024)
:第一個全連接層的輸入是卷積后得到的特征,輸出 1024 個節點。self.fc2 = nn.Linear(1024, 10)
:最后的全連接層將 1024 個節點壓縮為 10 個輸出,代表分類結果。
訓練 CNN 模型
要訓練該模型,我們需要加載一個數據集、定義損失函數和優化器,然后進行訓練。以下是如何使用 MNIST 數據集進行訓練的示例。
import torch.optim as optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms# 加載 MNIST 數據集
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))])
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)# 定義損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 訓練循環
num_epochs = 5
for epoch in range(num_epochs):model.train()running_loss = 0.0for batch_idx, (data, target) in enumerate(train_loader):optimizer.zero_grad()output = model(data)loss = criterion(output, target)loss.backward()optimizer.step()running_loss += loss.item()if batch_idx % 100 == 99: # 每100個batch輸出一次損失print(f'Epoch {epoch+1}, Batch {batch_idx+1}, Loss: {running_loss / 100:.4f}')running_loss = 0.0print("Finished Training")
訓練過程說明
- 數據加載器(DataLoader):用于批量加載訓練數據,支持數據的隨機打亂(shuffle)。
- 損失函數(CrossEntropyLoss):用于多分類問題,計算預測和真實標簽之間的交叉熵損失。
- 優化器(Adam):Adam 優化器自適應調整學習率,通常在深度學習中表現良好。
- 訓練循環:每個 epoch 處理整個數據集,通過前向傳播、計算損失、反向傳播和優化步驟,更新網絡參數。
總結
在這篇文章中,我們實現了一個標準的卷積神經網絡(CNN),并使用 PyTorch 對其進行了定義和訓練。通過使用卷積層、池化層和全連接層,模型能夠自動學習圖像的特征并進行分類。我們還介紹了如何訓練模型、加載數據集以及使用常見的優化器和損失函數。希望這篇文章能幫助你理解 CNN 的基本架構及其實現方式!