評價此頁

學習基礎知識 || 快速入門 || 張量 || 資料集 & 資料載入器 || 變換 || **構建模型** || 自動微分 || 最佳化 || 儲存 & 載入模型

構建神經網路#

建立日期: 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 上)保持不變)。

torch.Size([3, 784])

nn.Linear#

線性層是一個模組,它使用儲存的權重和偏置對輸入應用線性變換。

layer1 = nn.Linear(in_features=28*28, out_features=20)
hidden1 = layer1(flat_image)
print(hidden1.size())
torch.Size([3, 20])

nn.ReLU#

非線性啟用會建立模型輸入和輸出之間的複雜對映。它們線上性變換後應用,以引入非線性,幫助神經網路學習各種現象。

在此模型中,我們線上性層之間使用 nn.ReLU,但還有其他啟用可以引入模型中的非線性。

print(f"Before ReLU: {hidden1}\n\n")
hidden1 = nn.ReLU()(hidden1)
print(f"After ReLU: {hidden1}")
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

nn.Softmax#

神經網路的最後一個線性層返回logits——原始值範圍在 [-infty, infty]——這些值被傳遞給 nn.Softmax 模組。logits 被縮放到 [0, 1] 範圍內的值,表示模型對每個類的預測機率。dim 引數指定了值必須沿哪個維度求和為 1。

模型引數#

神經網路中的許多層都是引數化的,即具有在訓練期間最佳化的關聯權重和偏置。繼承 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 秒)