
image.png
簡介
一個(gè)典型的神經(jīng)網(wǎng)絡(luò)訓(xùn)練過程包括以下幾點(diǎn):
- 1.定義一個(gè)包含可訓(xùn)練參數(shù)的神經(jīng)網(wǎng)絡(luò)
- 2.迭代整個(gè)輸入
- 3.通過神經(jīng)網(wǎng)絡(luò)處理輸入
- 4.計(jì)算損失(loss)
- 5.反向傳播梯度到神經(jīng)網(wǎng)絡(luò)的參數(shù)
- 6.更新網(wǎng)絡(luò)的參數(shù),典型的用一個(gè)簡單的更新方法:weight = weight - learning_rate *gradient
原理
源碼
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
# 為了實(shí)現(xiàn)手寫數(shù)字識(shí)別(MNIST數(shù)據(jù)集)使用PyTorch,我們需要完成以下幾個(gè)步驟:
# 加載和預(yù)處理MNIST數(shù)據(jù)集。
# 定義神經(jīng)網(wǎng)絡(luò)模型。
# 設(shè)置損失函數(shù)和優(yōu)化器。
# 訓(xùn)練模型。
# 測試模型性能。
# 數(shù)據(jù)預(yù)處理
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])
# 下載訓(xùn)練集和測試集
train_dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST(root='./data', train=False, download=True, transform=transform)
# 創(chuàng)建DataLoader
batch_size = 64
train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(dataset=test_dataset, batch_size=batch_size, shuffle=False)
# 定義簡單的卷積神經(jīng)網(wǎng)絡(luò)
class Net(nn.Module):
def __init__(self):
super(Net, self).__init__()
# --------卷積層的作用是將輸入圖像中的像素值與卷積核中的像素值進(jìn)行相乘,得到特征圖。-----------------
# in_channels=1: 輸入通道數(shù)。對于MNIST數(shù)據(jù)集,每個(gè)圖像都是灰度圖,因此輸入通道數(shù)為1。
# out_channels=32: 輸出通道數(shù)。這是卷積層產(chǎn)生的特征圖的數(shù)量。這里設(shè)置為32。
# kernel_size=3: 卷積核(濾波器)的大小。這里是3x3的卷積核。
# stride=1: 步幅(步長)。表示卷積操作在輸入上移動(dòng)的步數(shù)。這里設(shè)置為1,意味著每次卷積操作會(huì)在輸入上向右和向下各移動(dòng)一步。
# padding=1: 填充。在輸入周圍添加額外的像素,以控制輸出的空間維度。這里設(shè)置為1,這意味著在輸入圖像的上下左右各填充一個(gè)像素,使得輸入和輸出的高度和寬度相同
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
# in_channels=32: 輸入通道數(shù)。這個(gè)值必須等于前一層的輸出通道數(shù),即第一層卷積層的輸出通道數(shù)32。
# out_channels=64: 輸出通道數(shù)。這是第二層卷積層產(chǎn)生的特征圖的數(shù)量。這里設(shè)置為64。
# kernel_size=3: 卷積核的大小仍然是3x3。
# stride=1: 步幅依然是1。
# padding=1: 填充同樣是1,保持輸出空間維度不變。
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
# --------最大池化層的作用是從每個(gè)2x2的區(qū)域中選擇最大的值,從而減少特征圖的空間維度,同時(shí)保留最重要的信息。-----------------
# kernel_size=2: 池化窗口的大小。這里是2x2的窗口。
# stride=2: 步幅(步長)。表示池化操作在輸入上移動(dòng)的步數(shù)。這里設(shè)置為2,意味著每次池化操作會(huì)在輸入上向右和向下各移動(dòng)兩步。
# padding=0: 填充。在輸入周圍添加額外的像素,以控制輸出的空間維度。這里設(shè)置為0,沒有填充。
self.pool = nn.MaxPool2d(kernel_size=2, stride=2, padding=0)
# in_features=64 * 7 * 7: 輸入特征的數(shù)量。這個(gè)值計(jì)算如下:
# 經(jīng)過兩個(gè)卷積層后,特征圖的通道數(shù)變?yōu)?4。
# 每個(gè)卷積層后面有一個(gè)最大池化層,將特征圖的空間維度減半。
# 初始輸入圖像大小為28x28,經(jīng)過第一次卷積和池化后變?yōu)?4x14,再經(jīng)過第二次卷積和池化后變?yōu)?x7。
# 因此,最終的特征圖大小為64x7x7。
# out_features=128: 輸出特征的數(shù)量。這里設(shè)置為128,表示第一層全連接層有128個(gè)神經(jīng)元。
self.fc1 = nn.Linear(64 * 7 * 7, 128)
# in_features=128: 輸入特征的數(shù)量,等于前一層全連接層的輸出特征數(shù)量128。
# out_features=10: 輸出特征的數(shù)量。這里設(shè)置為10,因?yàn)镸NIST數(shù)據(jù)集有10個(gè)類別(數(shù)字0到9),因此最后一層全連接層的輸出對應(yīng)于每個(gè)類別的概率。
self.fc2 = nn.Linear(128, 10)
# ReLU激活函數(shù): 引入非線性,增強(qiáng)模型的學(xué)習(xí)能力。
self.relu = nn.ReLU()
def forward(self, x):
x = self.pool(self.relu(self.conv1(x)))
x = self.pool(self.relu(self.conv2(x)))
x = x.view(-1, 64 * 7 * 7)
x = self.relu(self.fc1(x))
x = self.fc2(x)
return x
# 初始化模型、損失函數(shù)和優(yōu)化器
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
# 訓(xùn)練模型
def train_model(model, train_loader, criterion, optimizer, num_epochs=5):
model.train()
for epoch in range(num_epochs):
running_loss = 0.0
for images, labels in train_loader:
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
loss.backward()
optimizer.step()
running_loss += loss.item()
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {running_loss/len(train_loader):.4f}')
# 測試模型
def test_model(model, test_loader):
model.eval()
correct = 0
total = 0
with torch.no_grad():
for images, labels in test_loader:
outputs = model(images)
_, predicted = torch.max(outputs.data, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
accuracy = 100 * correct / total
print(f'Test Accuracy: {accuracy:.2f}%')
# 開始訓(xùn)練和測試
train_model(model, train_loader, criterion, optimizer)
test_model(model, test_loader)