可以學習如下內容:
? 介紹神經網絡核心組件。
? 如何構建一個神經網絡。
? 詳細介紹如何構建一個神經網絡。
? 如何使用nn模塊中Module及functional。
? 如何選擇優化器。
? 動態修改學習率參數。
5.1 核心組件
神經網絡核心組件不多,把這些組件確定后,這個神經網絡基本就確定了。這些核心組件包括:
1)層:神經網絡的基本結構,將輸入張量轉換為輸出張量。
2)模型:層構成的網絡。
3)損失函數:參數學習的目標函數,通過最小化損失函數來學習各種參數。
4)優化器:如何使損失函數最小,這就涉及優化器。
多個層鏈接在一起構成一個模型或網絡,輸入數據通過這個模型轉換為預測值,然后損失函數把預測值與真實值進行比較,得到損失值(損失值可以是距離、概率值等)?,該損失值用于衡量預測值與目標結果的匹配或相似程度,優化器利用損失值更新權重參數,從而使損失值越來越小。這是一個循環過程,當損失值達到一個閥值或循環次數到達指定次數,循環結束。接下來利用PyTorch的nn工具箱,構建一個神經網絡實例。nn中對這些組件都有現成包或類,可以直接使用,非常方便。
——————————實現神經網絡實例
構建網絡層可以基于Module類,或函數(nn.functional)。
nn.Module中的大多數層(Layer)在functional中都有與之對應的函數。
nn.functional中函數與nn.Module中的Layer的主要區別是后者繼承Module類,會自動提取可學習的參數。
而nn.functional更像是純函數。
兩者功能相同,且性能也沒有很大區別,那么如何選擇呢?像卷積層、全連接層、Dropout層等因含有可學習參數,一般使用nn.Module,而激活函數、池化層不含可學習參數,可以使用nn.functional中對應的函數。
下面通過實例來說明如何使用nn構建一個網絡模型。
這節將利用神經網絡完成對手寫數字進行識別的實例,來說明如何借助nn工具箱來實現一個神經網絡,并對神經網絡有個直觀了解。在這個基礎上,后續我們將對nn的各模塊進行詳細介紹。實例環境使用PyTorch1.0+,GPU或CPU,源數據集為MNIST。
主要步驟:
1)利用PyTorch內置函數mnist下載數據。
2)利用torchvision對數據進行預處理,調用torch.utils建立一個數據迭代器。
3)可視化源數據。
4)利用nn工具箱構建神經網絡模型。
5)實例化模型,并定義損失函數及優化器。
6)訓練模型。
7)可視化結果。
import numpy as np
import torchfrom torchvision.datasets import mnist#導入預處理模塊
import torchvision.transforms as transforms
from torch.utils.data import DataLoader#導入nn及優化器
import torch.nn.functional as F
import torch.optim as optim
from torch import nn
接下來,定義一些超參數
train_batch_size=64
test_batch_size=128
learning_rate=0.01
num_epoches=20
lr=0.01
momentum=0.5
下載數據并對數據進行預處理
#定義預處理函數,這些預處理依次放在Compose函數中。
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5], [0.5])])
#下載數據,并對數據進行預處理
train_dataset = mnist.MNIST('./data', train=True, transform=transform, download=True)
test_dataset = mnist.MNIST('./data', train=False, transform=transform)#dataloader是一個可迭代對象,可以使用迭代器一樣使用。
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)
-
transforms.Compose
:Compose
?是 PyTorch 中的一個工具,用于將多個預處理操作組合在一起,依次執行。
-
transforms.ToTensor()
:- 將 PIL 圖像或 NumPy 數組轉換為 PyTorch 張量(Tensor)。
- 同時會將圖像的像素值從?
[0, 255]
?轉換到?[0, 1]
?的范圍。
-
transforms.Normalize([0.5], [0.5])
:- 對張量進行歸一化處理。
- 歸一化的公式是:
output = (input - mean) / std
。 - 這里的參數?
[0.5]
?表示均值(mean),[0.5]
?表示標準差(std)。 - 因此,歸一化后數據的范圍會從?
[0, 1]
?變為?[-1, 1]
-
DataLoader
?是 PyTorch 提供的一個工具,用于將數據集分批加載,并支持多線程、打亂順序等功能。
- 參數解釋:
train_dataset
?和?test_dataset
: 分別指定訓練集和測試集。batch_size
: 每次加載的數據批量大小。train_batch_size
?和?test_batch_size
?應該在代碼其他地方定義。shuffle=True
: 是否在每個 epoch 開始時打亂數據順序。通常在訓練集上設置為?True
,以增加模型的泛化能力。shuffle=False
: 測試集一般不需要打亂順序。
——————————————可視化源數據
import matplotlib.pyplot as pltexamples=enumerate(test_loader)
batch_idx,(example_data,example_targets)=next(examples)fig=plt.figure()
for i in range(6):plt.subplot(2,3,i+1)plt.tight_layout()plt.imshow(example_data[i][0],cmap="gray",interpolation='none')plt.title("Ground Truth:{}".format(example_targets[i]))plt.xticks([])plt.yticks([])
_______________________構建模型
數據預處理結束后,開始構建模型
1)構建網絡的類Net
class Net(nn.Module):"""使用sequential構建網絡,Sequential()函數的功能是將網絡的層組合到一起"""def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):super(Net, self).__init__()self.layer1 = nn.Sequential(nn.Linear(in_dim,
n_hidden_1),nn.BatchNorm1d(n_hidden_1))self.layer2 = nn.Sequential(nn.Linear(n_hidden_1, n_hidden_2),nn.BatchNorm1d (n_hidden_2))self.layer3 = nn.Sequential(nn.Linear(n_hidden_2, out_dim))def forward(self, x):x = F.relu(self.layer1(x))x = F.relu(self.layer2(x))x = self.layer3(x)return x
2)創造實例
#檢測是否有可用的GPU,有則使用,否則使用CPU
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#實例化網絡
model = Net(28 * 28, 300, 100, 10)
model.to(device)# 定義損失函數criterion和優化器optimizer
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(model.parameters(), lr=lr, momentum=momentum)
以下內容為大語言模型生成:
這段代碼實現了一個使用nn.Sequential
構建的三層全連接神經網絡,包含批歸一化和ReLU激活函數。以下是對代碼的分析及優化建議:
代碼結構分析
-
網絡定義 :
- Layer1 :線性層(
in_dim
→n_hidden_1
) + 批歸一化。 - Layer2 :線性層(
n_hidden_1
→n_hidden_2
) + 批歸一化。 - Layer3 :線性層(
n_hidden_2
→out_dim
),無批歸一化和激活函數。
- Layer1 :線性層(
-
前向傳播 :
- 前兩層使用ReLU激活,最后一層輸出原始 logits(適用于分類任務結合
CrossEntropyLoss
或回歸任務)。
- 前兩層使用ReLU激活,最后一層輸出原始 logits(適用于分類任務結合
————————訓練模型
這里使用for循環進行迭代。其中包括對訓練數據的訓練模型,然后用測試數據的驗證模型。
1.訓練模型
import torch
import torch.nn as nn
from torch.utils.data import DataLoader
from torchvision import transforms
from tqdm import tqdm# 假設已定義模型、數據集、損失函數和優化器
# model = Net(...)
# train_dataset = ...
# test_dataset = ...# 數據預處理(展平)
class FlattenTransform:def __call__(self, img):return img.view(-1)transform = transforms.Compose([transforms.ToTensor(),FlattenTransform()
])train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=64)# 初始化
losses = []
acces = []
eval_losses = []
eval_acces = []for epoch in range(num_epoches):# 動態調整學習率if epoch > 0 and epoch % 5 == 0:for param_group in optimizer.param_groups:new_lr = max(param_group['lr'] * 0.1, 1e-6)param_group['lr'] = new_lrprint(f"Learning rate updated to {new_lr}")# 訓練階段model.train()train_loss = 0train_correct = 0train_total = 0for img, label in tqdm(train_loader, desc=f"Epoch {epoch+1} Training"):img, label = img.to(device), label.to(device)# 前向傳播output = model(img)loss = criterion(output, label)# 反向傳播optimizer.zero_grad()loss.backward()optimizer.step()# 記錄指標train_loss += loss.item()_, pred = output.max(1)train_correct += (pred == label).sum().item()train_total += label.size(0)# 計算平均指標avg_train_loss = train_loss / len(train_loader)avg_train_acc = train_correct / train_totallosses.append(avg_train_loss)acces.append(avg_train_acc)# 測試階段model.eval()eval_loss, eval_acc = calculate_metrics(test_loader, model, criterion, device)eval_losses.append(eval_loss)eval_acces.append(eval_acc)# 打印日志print(f'Epoch {epoch+1}/{num_epoches}: 'f'Train Loss: {avg_train_loss:.4f}, Train Acc: {avg_train_acc:.4f}, 'f'Test Loss: {eval_loss:.4f}, Test Acc: {eval_acc:.4f}')
以下內容由大語言模型生成
為什么需要 model.eval()
?
在神經網絡中,某些層(如 BatchNorm
、Dropout
)在訓練(training)和推理(evaluation)階段的行為不同:
-
BatchNorm 層 :
- 訓練階段 :使用當前 batch 的均值和方差進行標準化,并更新運行統計量(running mean/variance)。
- 推理階段 :使用訓練階段累積的運行統計量,而非當前 batch 的統計量。
- 若不調用
model.eval()
,推理時會繼續更新統計量,導致結果不穩定。
-
Dropout 層 :
- 訓練階段 :隨機丟棄部分神經元,防止過擬合。
- 推理階段 :關閉 Dropout,使用所有神經元的輸出(權重按概率縮放)。
- 若不調用
model.eval()
,推理時會繼續隨機丟棄神經元,導致結果隨機。
功能詳解
調用 model.eval()
后:
- 關閉訓練相關行為 :
BatchNorm
層停止計算均值/方差,使用累積的統計量。Dropout
層停止隨機丟棄神經元。
- 不影響梯度計算 :
model.eval()
僅改變層的行為,不涉及梯度計算。如果需要禁用梯度,需配合torch.no_grad()
。