注意
前往 末尾 下載完整的示例程式碼。
學習基礎知識 || 快速入門 || 張量 || 資料集 & 資料載入器 || 變換 || **構建模型** || 自動微分 || 最佳化 || 儲存 & 載入模型
構建神經網路#
建立日期: 2021年02月09日 | 最後更新: 2025年01月24日 | 最後驗證: 未驗證
神經網路由層/模組組成,它們對資料執行操作。torch.nn 名稱空間提供了構建自定義神經網路所需的所有構建塊。PyTorch 中的每個模組都繼承自 nn.Module。神經網路本身也是一個由其他模組(層)組成的模組。這種巢狀結構可以輕鬆地構建和管理複雜的架構。
在接下來的部分中,我們將構建一個神經網路來對 FashionMNIST 資料集中的影像進行分類。
import os
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
獲取用於訓練的裝置#
我們希望能夠在 加速器(如 CUDA、MPS、MTIA 或 XPU)上訓練我們的模型。如果當前加速器可用,我們將使用它。否則,我們將使用 CPU。
device = torch.accelerator.current_accelerator().type if torch.accelerator.is_available() else "cpu"
print(f"Using {device} device")
Using cuda device
定義類#
我們透過繼承 nn.Module 來定義我們的神經網路,並在 __init__ 中初始化神經網路層。每個 nn.Module 子類都在 forward 方法中實現對輸入資料的操作。
class NeuralNetwork(nn.Module):
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.linear_relu_stack = nn.Sequential(
nn.Linear(28*28, 512),
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, 10),
)
def forward(self, x):
x = self.flatten(x)
logits = self.linear_relu_stack(x)
return logits
我們建立一個 NeuralNetwork 例項,將其移至 device,並列印其結構。
model = NeuralNetwork().to(device)
print(model)
NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
要使用模型,我們將輸入資料傳遞給它。這將執行模型的 forward 方法,以及一些 後臺操作。不要直接呼叫 model.forward()!
將模型應用於輸入會返回一個 2D 張量,其中 dim=0 對應於每個類 10 個原始預測值的輸出,dim=1 對應於每個輸出的各個值。我們透過將輸出傳遞給 nn.Softmax 模組的例項來獲得預測機率。
X = torch.rand(1, 28, 28, device=device)
logits = model(X)
pred_probab = nn.Softmax(dim=1)(logits)
y_pred = pred_probab.argmax(1)
print(f"Predicted class: {y_pred}")
Predicted class: tensor([6], device='cuda:0')
模型層#
讓我們分解一下 FashionMNIST 模型中的層。為了說明這一點,我們將使用一個包含 3 個 28x28 影像的樣本小批次,看看當它透過網路時會發生什麼。
input_image = torch.rand(3,28,28)
print(input_image.size())
torch.Size([3, 28, 28])
nn.Flatten#
我們初始化 nn.Flatten 層,將每個 2D 28x28 影像轉換為一個連續的 784 畫素值陣列(小批次維度(在 dim=0 上)保持不變)。
flatten = nn.Flatten()
flat_image = flatten(input_image)
print(flat_image.size())
torch.Size([3, 784])
nn.Linear#
線性層是一個模組,它使用儲存的權重和偏置對輸入應用線性變換。
torch.Size([3, 20])
nn.ReLU#
非線性啟用會建立模型輸入和輸出之間的複雜對映。它們線上性變換後應用,以引入非線性,幫助神經網路學習各種現象。
在此模型中,我們線上性層之間使用 nn.ReLU,但還有其他啟用可以引入模型中的非線性。
Before ReLU: tensor([[ 0.0838, -0.1596, 0.2112, 0.2359, -0.3761, 0.4043, -0.4015, -0.0615,
0.2180, -0.2139, -0.5868, 0.3046, -0.1642, 0.0262, 0.5605, -0.1890,
0.5140, -0.2630, 0.4404, 0.1834],
[-0.0791, -0.3621, -0.0149, 0.4168, -0.0165, 0.3271, -0.0582, -0.1739,
-0.0459, -0.4254, -0.4844, 0.1458, -0.0997, 0.2241, 0.2173, 0.0705,
0.2485, -0.2096, 0.1545, 0.0299],
[ 0.0156, -0.0276, 0.1354, 0.2339, -0.4241, 0.3049, -0.4130, -0.7753,
0.2701, -0.4634, -0.8258, -0.1060, -0.2186, -0.2815, 0.4303, -0.2589,
0.6219, -0.0349, 0.3395, 0.0192]], grad_fn=<AddmmBackward0>)
After ReLU: tensor([[0.0838, 0.0000, 0.2112, 0.2359, 0.0000, 0.4043, 0.0000, 0.0000, 0.2180,
0.0000, 0.0000, 0.3046, 0.0000, 0.0262, 0.5605, 0.0000, 0.5140, 0.0000,
0.4404, 0.1834],
[0.0000, 0.0000, 0.0000, 0.4168, 0.0000, 0.3271, 0.0000, 0.0000, 0.0000,
0.0000, 0.0000, 0.1458, 0.0000, 0.2241, 0.2173, 0.0705, 0.2485, 0.0000,
0.1545, 0.0299],
[0.0156, 0.0000, 0.1354, 0.2339, 0.0000, 0.3049, 0.0000, 0.0000, 0.2701,
0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.4303, 0.0000, 0.6219, 0.0000,
0.3395, 0.0192]], grad_fn=<ReluBackward0>)
nn.Sequential#
nn.Sequential 是一個有序的模組容器。資料按照定義的順序透過所有模組。您可以使用順序容器快速構建網路,例如 seq_modules。
seq_modules = nn.Sequential(
flatten,
layer1,
nn.ReLU(),
nn.Linear(20, 10)
)
input_image = torch.rand(3,28,28)
logits = seq_modules(input_image)
nn.Softmax#
神經網路的最後一個線性層返回logits——原始值範圍在 [-infty, infty]——這些值被傳遞給 nn.Softmax 模組。logits 被縮放到 [0, 1] 範圍內的值,表示模型對每個類的預測機率。dim 引數指定了值必須沿哪個維度求和為 1。
softmax = nn.Softmax(dim=1)
pred_probab = softmax(logits)
模型引數#
神經網路中的許多層都是引數化的,即具有在訓練期間最佳化的關聯權重和偏置。繼承 nn.Module 會自動跟蹤模型物件中定義的所有欄位,並使所有引數可透過模型 的 parameters() 或 named_parameters() 方法進行訪問。
在此示例中,我們遍歷每個引數,並列印其大小和值的預覽。
print(f"Model structure: {model}\n\n")
for name, param in model.named_parameters():
print(f"Layer: {name} | Size: {param.size()} | Values : {param[:2]} \n")
Model structure: NeuralNetwork(
(flatten): Flatten(start_dim=1, end_dim=-1)
(linear_relu_stack): Sequential(
(0): Linear(in_features=784, out_features=512, bias=True)
(1): ReLU()
(2): Linear(in_features=512, out_features=512, bias=True)
(3): ReLU()
(4): Linear(in_features=512, out_features=10, bias=True)
)
)
Layer: linear_relu_stack.0.weight | Size: torch.Size([512, 784]) | Values : tensor([[ 0.0054, 0.0004, 0.0307, ..., -0.0244, -0.0134, 0.0103],
[ 0.0068, -0.0080, -0.0073, ..., 0.0279, 0.0128, 0.0110]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.0.bias | Size: torch.Size([512]) | Values : tensor([-0.0058, 0.0198], device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.weight | Size: torch.Size([512, 512]) | Values : tensor([[-0.0374, 0.0302, 0.0022, ..., 0.0097, -0.0145, 0.0116],
[ 0.0316, 0.0269, 0.0374, ..., -0.0029, -0.0009, 0.0433]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.2.bias | Size: torch.Size([512]) | Values : tensor([-0.0019, -0.0321], device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.weight | Size: torch.Size([10, 512]) | Values : tensor([[ 0.0218, 0.0092, 0.0375, ..., -0.0028, 0.0192, -0.0376],
[ 0.0414, -0.0280, 0.0212, ..., -0.0354, 0.0215, 0.0339]],
device='cuda:0', grad_fn=<SliceBackward0>)
Layer: linear_relu_stack.4.bias | Size: torch.Size([10]) | Values : tensor([-0.0294, -0.0348], device='cuda:0', grad_fn=<SliceBackward0>)
進一步閱讀#
指令碼總執行時間: (0 分鐘 0.513 秒)