總結:學習了 PyTorch 中的基本概念和常用功能,張量(Tensor)的操作、自動微分(Autograd)、正向傳播、反向傳播。通過了解認識LeNet 模型,定義神經網絡類,熟悉卷積神經網絡的基本結構和訓練過程,卷積層和全連接層的創建和運用。在訓練網絡中,通過反向傳播計算梯度,利用優化器根據計算出的梯度更新網絡中的參數。--2025/02/12
目錄
1. 實驗環境
1.1. 導入庫
1.2. 版本
2. 基本概念
2.1. Tensor 張量
2.2. Scalar 標量
2.3. Autograd 自動微分
2.3.1. 啟動自動微分
2.3.2. 反向傳播
2.3.3. 梯度累加和清零
3. LeNet 神經網絡
3.1. 基本概念
3.1.1. torch.nn
3.1.2. nn.Module 類
3.1.3. 卷積層 (nn.Conv2d)
3.1.4. 全連接層 (nn.Linear)
3.2. 定義神經網絡類 Net
3.2.1?__init__ 構造函數
3.2.2. forward 向前傳播函數
3.3. 訓練網絡
3.3.1. 可學習參數
3.3.2. 批量處理(Mini-Batch)
3.3.3. 損失函數
3.3.4. 反向傳播
3.3.5. 優化器:SGD
總結
1. 實驗環境
1.1. 導入庫
-
Import numpy as np:?用于處理數組和矩陣運算
Import torch as t :pytorch的核心庫,構建和訓練深度學習模型
import torch.optim as optim:pytorch的優化器模塊,根據計算出的梯度更新神經網絡的參數
import torch.nn as nn:PyTorch 提供的神經網絡模塊,專門用于構建和訓練神經網絡模型
import torch.nn.functional as F:包含函數操作,如激活函數、損失函數、卷積操作等)
1.2. 版本
-
torch:2.6.0
Python 3.8.8
jupyter-notebook : 6.3.0
2. 基本概念
2.1. Tensor 張量
Tensor是PyTorch中重要的數據結構,可認為是一個高維數組。它可以是一個數(標量)、一維數組(向量)、二維數組(矩陣)以及更高維的數組。
- 標量(0 維):一個數值,例如 3.14。
- 向量(1 維):一組有序的數值,例如 [1, 2, 3]。
- 矩陣(2 維):一個二維的數值表格,例如 [[1, 2], [3, 4]]。
- 高維數組(n 維):更高維的數組,用于存儲更復雜的數據結構,例如圖像數據(通常為 4 維:batch_size, channels, height, width)。
# 初始化一個 5x3 的張量
x = t.Tensor(5, 3)# 賦值為一個 2x2 的初始化矩陣
x = t.Tensor([[1, 2], [3, 4]])# 獲取張量的行數(即第一個維度)
x.size(0)# 獲取張量的列數(即第二個維度)
x.size(1)# 獲取列數的另一種方式
x.size()[1]# 隨機生成一個 5x3 的張量
x = t.rand(5, 3)
y = t.rand(5, 3)# 三種方法來進行兩個矩陣相加:
a = x + y # 方法 1:直接相加
b = t.add(x, y) # 方法 2:使用 PyTorch 自帶的加法函數
c = t.Tensor(5, 3) # 初始化一個空張量
t.add(x, y, out=c) # 方法 3:將結果存儲到 c 中
Tensor 與 NumPy 的轉換
# 創建一個全為 1 的張量
a = t.ones(5)# 將張量轉換為 NumPy 數組
b = a.numpy()# 創建一個全為 1 的 NumPy 數組
a = np.ones(5)# 將 NumPy 數組轉換為張量
b = t.from_numpy(a)
2.2. Scalar 標量
Scalar(標量)是一個沒有維度的單一數值,它是零維的張量。標量在 PyTorch 中通常表示為一個只有一個元素的 Tensor。
2.2.1. 獲取標量值
(1) 使用 .item()
從包含單一元素的張量中提取該元素的值:
(2) 使用 .tolist()
將標量張量轉換為列表:
# 使用 item() 方法獲取標量值
scalar = b[0]
scalar_value = scalar.item()# 使用 tolist() 方法將標量張量轉換為列表
x = t.Tensor([3.14]) # 創建一個包含單一值的張量
scalar_list = x.tolist() # 將其轉換為列表
print(scalar_list) # 輸出: [3.14]
2.3. Autograd 自動微分
深度學習中的訓練過程本質上是通過反向傳播求導數,而 PyTorch 提供的 autograd
模塊自動為張量計算梯度,從而避免了手動計算導數的復雜過程。
2.3.1. 啟動自動微分
在創建張量時,可以通過 requires_grad=True
來啟動自動微分功能,表示該張量需要計算梯度。
x = t.ones(2, 2, requires_grad=True) # 創建一個可以計算梯度的張量
2.3.2. 反向傳播
反向傳播通過調用 backward()
來計算梯度。以下示例展示了如何計算梯度:
2.3.3. 梯度累加和清零
在每次執行 backward()
之后,PyTorch 會將梯度值累加,因此每次反向傳播之前需要手動清零梯度。
#清零梯度,以下劃線結束的函數是inplace操作,修改自身的值
x.grad.zero_()
3. LeNet 神經網絡
LeNet 是一種經典的卷積神經網絡(CNN)結構,廣泛應用于圖像分類任務。LeNet 模型通常由兩個卷積層、兩個池化層以及三個全連接層組成。
3.1. 基本概念
3.1.1. torch.nn
torch.nn
是 PyTorch 中專門為構建神經網絡設計的模塊,封裝了構建和訓練神經網絡所需的大量工具,包括各種層(如卷積層、全連接層、激活函數等)和常用的操作(如損失函數、優化器等)。
3.1.2. nn.Module
類
nn.Module
是 torch.nn
中最重要的類,所有的神經網絡模型都應該繼承自 nn.Module
。我們可以通過繼承 nn.Module
來定義自己的網絡模型。在繼承 nn.Module
時,需要定義以下兩個方法:
__init__
:用于定義模型的結構,初始化網絡的各個層。forward
:定義前向傳播,描述數據如何通過網絡流動。
3.1.3. 卷積層 (nn.Conv2d
)
卷積層用于從輸入數據中提取空間特征。nn.Conv2d
用于定義二維卷積層。它的常用參數包括:
- in_channels:輸入數據的通道數(例如,RGB圖像的通道數為3,灰度圖像為1)。
- out_channels:卷積層輸出的通道數(卷積核的數量)。
- kernel_size:卷積核的大小,通常是一個整數或元組(
height, width
)。
# 卷積層 '1'表示輸入通道數為1→灰度圖像, '6'表示輸出通道數→卷積核的數量,'5'表示卷積核為5*5
self.conv1 = nn.Conv2d(1, 6, 5)?
# 卷積層
self.conv2 = nn.Conv2d(6, 16, 5)?
3.1.4. 全連接層 (nn.Linear
)
全連接層是神經網絡中非常重要的一部分,主要用于將提取到的特征映射到最終的輸出。nn.Linear
定義了一個全連接層,其常用參數為:
- in_features:輸入特征的數量。
- out_features:輸出特征的數量。
? # 仿射層/全連接層,y = Wx + b
? ? ? ? #16*5*5是卷積層輸出的特征圖像展平后的維度,表示每個樣本通過卷積層處理后的大小。
? ? ? ? self.fc1 ? = nn.Linear(16*5*5, 120)?
? ? ? ? #120,84,10全連接層的輸出維度。10表示模型的預測類別數。10類
? ? ? ? self.fc2 ? = nn.Linear(120, 84)
? ? ? ? self.fc3 ? = nn.Linear(84, 10)
3.2. 定義神經網絡類 Net
import torch.nn as nn
import torch.nn.functional as F
#包含常見函數,比如激活函數relu,池化操作maxpool
class Net(nn.Module):#定義神經網絡類Net,繼承于nn.Moduledef __init__(self):#定義構造函數,用來定義網絡各個層super(Net, self).__init__()#調用父類nn.module的構造函數# 卷積層 '1'表示輸入圖片為單通道的灰度圖像, '6'表示輸出通道數,'5'表示卷積核為5*5self.conv1 = nn.Conv2d(1, 6, 5) # 卷積層self.conv2 = nn.Conv2d(6, 16, 5) # 仿射層/全連接層,y = Wx + b#16*5*5是卷積層輸出的特征圖像展平后的維度,表示每個樣本通過卷積層處理后的大小。self.fc1 = nn.Linear(16*5*5, 120) #120,84,10全連接層的輸出維度。10表示模型的預測類別數。10類self.fc2 = nn.Linear(120, 84)self.fc3 = nn.Linear(84, 10)def forward(self, x): #定義向前傳播# 卷積 -> 激活函數(ReLU) -> 池化(MaxPool)x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2))#self.conv1(x):通過卷積層conv1,將輸入x進行卷積操作#F.relu():relu激活函數,將輸入的負值變為0,正值不變。#F.max_pool2d(...,(2,2)):最大池化操作,池化窗口大小2*2x = F.max_pool2d(F.relu(self.conv2(x)), 2) # reshape,展平數據,輸入全連接層,‘-1’表示自適應x = x.view(x.size()[0], -1) #展平的數據進入全連接層,relu激活函數增加非線性#最后一層輸出類別的預測值x = F.relu(self.fc1(x))x = F.relu(self.fc2(x))x = self.fc3(x) return x
#創建Net對象,神經網絡
net = Net()
#打印出網絡的結構顯示每一層參數
print(net)
Net((conv1): Conv2d(1, 6, kernel_size=(5, 5), stride=(1, 1))(conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))(fc1): Linear(in_features=400, out_features=120, bias=True)(fc2): Linear(in_features=120, out_features=84, bias=True)(fc3): Linear(in_features=84, out_features=10, bias=True) )
3.2.1?__init__
構造函數
在 __init__
方法中,我們定義了網絡的各個層(卷積層、池化層、全連接層)。LeNet 網絡一般包含兩個卷積層和三個全連接層。
3.2.2. forward
向前傳播函數
在 forward
方法中,我們定義了數據如何在網絡中流動,包括卷積、池化、激活函數、展平和全連接層的應用。
3.3. 訓練網絡
3.3.1. 可學習參數
- 權重(weight):網絡中的參數,決定了輸入和輸出之間的關系,影響每一層的輸出結果。
- 偏置(bias):每個神經元的額外參數,與權重一起決定神經元的激活值。
3.3.2. 批量處理(Mini-Batch)
批量處理mini-batch:多個樣本組成的小批量.
PyTorch 的神經網絡層(如卷積層)要求輸入的形狀是一個 4D 張量(batch_size, channels, height, width)。
只想輸入一個樣本,input.unsqueeze(0)將batch_size設為1
3.3.3. 損失函數
-
損失函數:衡量網絡輸出(預測值)與目標值之間的差距
均方誤差 (MSE, Mean Squared Error):用于回歸問題,計算預測值與真實值之間的平均平方誤差。
交叉熵損失 (Cross-Entropy Loss):用于分類問題,衡量真實標簽與預測概率分布之間的差異。
3.3.4. 反向傳播
反向傳播包括三個步驟:
- 正向傳播:先通過前向傳播計算出模型的輸出和損失。
- 計算梯度:然后通過反向傳播計算出每個參數的梯度。梯度的絕對值較大,該參數對損失有很大影響,需要大幅調整
- 參數更新:使用這些梯度來調整網絡的參數,使得損失最小化。
#梯度變化
print('反向傳播前conv1.bias偏置的梯度')
print(net.conv1.bias.grad)# 執行一次前向傳播
output = net(input)
target = t.arange(0,10).view(1,10).float()
criterion = nn.MSELoss()# 計算損失
loss = criterion(output, target)# 執行反向傳播(retain_graph=True)用于保留計算圖
loss.backward(retain_graph=True)# 打印反向傳播后的梯度
print('反向傳播后conv1.bias偏置的梯度')
print(net.conv1.bias.grad)# 如果需要繼續進行其他操作,記得清零梯度
net.zero_grad()
梯度的符號(正負)表示了參數調整的方向:
負梯度:表示 如果減小 當前參數的值,損失函數會減少。當前參數的值較大,應該減少它來減小損失。
正梯度:表示 如果增大 當前參數的值,損失函數會減少。意味著當前參數的值較小,應該增加它來減小損失。
3.3.5. 優化器:SGD
主要任務是 根據反向傳播計算出的梯度更新網絡中的參數(如權重和偏置),從而使得損失函數逐步降低,最終達到優化目標。
SGD(隨機梯度下降)優化器
SGD 是最常見的一種優化器,它的基本思路是每次使用一個 mini-batch(小批量)計算梯度,并使用這個梯度更新網絡參數。
import torch.optim as optim
#SGD隨機梯度下降,創建優化器,將需要優化的參數傳入優化器
#指定學習率learning rate
optimizer = optim.SGD(net.parameters(),lr = 0.01)
#先梯度清零
optimizer.zero_grad()
#前向傳播
output = net(input)
#計算損失函數
loss = criterion(output,target)
#反向傳播
loss.backward()
#更新參數
optimizer.step()
總結
- LeNet 網絡結構:包含卷積層、池化層、全連接層。
nn.Module
和forward
:通過繼承nn.Module
和定義forward
方法來實現網絡結構。- 損失函數和優化器:通過損失函數(如交叉熵損失)和優化器(如 SGD)來訓練網絡。