【深度學習】PyTorch實現VGG16模型及網絡層數學原理

一、Demo概述

代碼已附在文末

1.1 代碼功能

  • ? 實現VGG16網絡結構
  • ? 在CIFAR10數據集上訓練分類模型

在這里插入圖片描述

1.2 環境配置

詳見【深度學習】Windows系統Anaconda + CUDA + cuDNN + Pytorch環境配置


二、各網絡層概念

2.1 卷積層(nn.Conv2d)

nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, padding=1)
參數含義作用說明
in_channels輸入通道數(如RGB圖為3)接收輸入的維度
out_channels輸出通道數(卷積核數量)提取不同特征類型的數量
kernel_size卷積核尺寸(如3x3)決定感知的局部區域大小
padding邊緣填充像素數保持輸出尺寸與輸入一致

作用:通過滑動窗口提取局部特征(如邊緣、顏色分布)
示例: 輸入3通道224x224圖片 → 通過64個3x3卷積核 → 輸出64通道224x224特征圖

1)卷積后的輸出尺寸

卷積后的輸出尺寸由以下公式決定:
輸出尺寸 = 輸入尺寸 ? 卷積核尺寸 + 2 × 填充 步長 + 1 \text{輸出尺寸} = \frac{\text{輸入尺寸} - \text{卷積核尺寸} + 2 \times \text{填充}}{\text{步長}} + 1 輸出尺寸=步長輸入尺寸?卷積核尺寸+2×填充?+1

在代碼中:

  • 輸入尺寸:224x224
  • 卷積核尺寸:3x3 → (k=3)
  • 填充 (padding):1 → (p=1)
  • 步長 (stride):1 → (s=1)(默認值)

代入公式:
輸出尺寸 = 224 ? 3 + 2 × 1 1 + 1 = 224 \text{輸出尺寸} = \frac{224 - 3 + 2 \times 1}{1} + 1 = 224 輸出尺寸=1224?3+2×1?+1=224
因此,寬度和高度保持不變(仍為224x224)。

2)64個卷積核的輸出不同
  • 參數初始化差異
  • 初始權重隨機:每個卷積核的權重矩陣在訓練前通過隨機初始化生成(如正態分布)
  • 示例
    • 卷積核1初始權重可能偏向檢測水平邊緣
    • 卷積核2初始權重可能隨機偏向檢測紅色區域

在這里插入圖片描述

  • 反向傳播差異:每個卷積核根據其當前權重計算出的梯度不同
    數學表達:
    Δ W k = ? η ? L ? W k \Delta W_k = -\eta \frac{\partial \mathcal{L}}{\partial W_k} ΔWk?=?η?Wk??L?
    • W k W_k Wk?:第k個卷積核的權重
    • η \eta η:學習率
    • 不同位置的梯度導致權重更新方向不同
3)卷積核參數的「通道敏感度」

卷積操作的完整計算式為:
輸出 = ∑ c = 1 C in ( 輸入通道 c ? 卷積核權重 c ) + 偏置 \text{輸出} = \sum_{c=1}^{C_{\text{in}}} (\text{輸入通道}_c \ast \text{卷積核權重}_c) + \text{偏置} 輸出=c=1Cin??(輸入通道c??卷積核權重c?)+偏置
其中:

  • C in C_{\text{in}} Cin?:輸入通道數(例如RGB圖為3)
  • ? \ast ? 表示卷積運算
  • 偏置的意義在于允許激活非零特征
  • 不同的卷積核權重決定了通道敏感度,比如RGB三個通道,R通道權重放大即偏好紅色特征,紅色通道的輸入會被加強
4)卷積核參數的「空間敏感度」?
  • 卷積核矩陣決定空間關注模式,每個卷積核的權重矩陣就像一張「特征檢測模板」,決定了在圖像中的哪些空間位置組合能激活該核的輸出。
    [ [ ? 1 , 0 , 1 ] , [ ? 2 , 0 , 2 ] , [ ? 1 , 0 , 1 ] ] [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]] [[?1,0,1],[?2,0,2],[?1,0,1]]
  • 這是一個經典的Sobel水平邊緣檢測核,當輸入圖像在水平方向有明暗變化時(如水平邊緣),左右兩側的權重差異會放大響應值
5)參數協同工作

例. 綜合檢測紅色水平邊緣
假設一個卷積核的參數如下:

  • 空間權重(與之前Sobel核相同):
    [[-1, 0, 1],[-2, 0, 2],[-1, 0, 1]]
    
  • 通道權重
    • 紅色:0.9, 綠色:0.1, 藍色:-0.2
  • 在紅色通道中檢測水平邊緣 → 高響應
  • 在綠色/藍色通道的同類邊緣 → 響應被抑制
  • 最終輸出:紅色物體的水平邊緣被突出顯示

2.2 激活函數(nn.ReLU)

沒有激活函數的神經網絡等效于單層線性模型

nn.ReLU(inplace=True)

激活函數有很多種,這里是最簡單的一種ReLU
在這里插入圖片描述

1)ReLU 的數學原理

ReLU(Rectified Linear Unit)的數學定義非常簡單:
f ( x ) = max ? ( 0 , x ) f(x) = \max(0, x) f(x)=max(0,x)

  • 正向傳播

    • 當輸入 x > 0 x > 0 x>0 時,輸出 f ( x ) = x f(x) = x f(x)=x(直接傳遞信號)。
    • 當輸入 x < = 0 x <= 0 x<=0 時,輸出 f ( x ) = 0 f(x) = 0 f(x)=0(完全抑制信號)。
  • 反向傳播

    • x > 0 x > 0 x>0 時,梯度為 ? f ? x = 1 \frac{\partial f}{\partial x} = 1 ?x?f?=1(梯度無衰減)。
    • x < = 0 x <= 0 x<=0 時,梯度為 ? f ? x = 0 \frac{\partial f}{\partial x} = 0 ?x?f?=0(梯度歸零)。
2)引入非線性

如果神經網絡只使用線性激活函數(如 ( f(x) = x )),無論堆疊多少層,最終等效于單層線性變換(( W_{\text{total}} = W_1 W_2 \cdots W_n )),無法建模復雜函數。

  • ReLU 的非線性:通過分段處理(保留正信號、抑制負信號),打破線性組合,使網絡能夠學習非線性決策邊界。
  • 實際意義:ReLU 允許網絡在不同區域使用不同的線性函數(正區間為線性,負區間為常數),從而組合出復雜的非線性函數。
3)緩解梯度消失

梯度消失問題通常發生在深層網絡中,當反向傳播時梯度逐層衰減,導致淺層參數無法更新。
ReLU 的緩解機制如下:

  • 導數值恒為 1(正區間): 相比于 Sigmoid(導數最大 0.25)、Tanh(導數最大 1),ReLU 在正區間的梯度恒為 1,避免梯度隨網絡深度指數級衰減。

  • 稀疏激活性: ReLU 會抑制負值信號(輸出 0),導致部分神經元“死亡”,但活躍的神經元梯度保持完整,使有效路徑的梯度穩定傳遞。

  • 對比其他激活函數Sigmoid:導數 ( f’(x) = f(x)(1-f(x)) ),當 ( |x| ) 較大時,導數趨近 0。 ReLU:僅需判斷 ( x > 0 ),計算高效且梯度穩定。

4)輸入與輸出

我們輸入張量尺寸為 [Channels=64, Height=224, Width=224]

  • 維度不變性
    • ReLU 是逐元素操作(element-wise),不會改變輸入輸出的形狀,輸出尺寸仍為 64×224×224
  • 數值變化
    • 正區間:保留原始值,維持特征強度。
    • 負區間:置零,可能造成特征稀疏性(部分像素/通道信息丟失)。
  • 實際影響
    • 如果輸入中存在大量負值(如未規范化的數據),ReLU 會過濾掉這些信息,可能影響模型性能。
    • 通常需配合批歸一化(BatchNorm) 使用,將輸入調整到以 0 為中心,減少負值抑制。
5)局限性與拓展
  • 神經元死亡(Dead ReLU)
    • 當輸入恒為負時,梯度為 0,導致神經元永久失效。
  • 解決方案
    • 使用 Leaky ReLU:允許負區間有微小梯度(如 ( f(x) = \max(0.01x, x) ))。
    • Parametric ReLU (PReLU):將負區間的斜率作為可學習參數。

2.3 池化層(nn.MaxPool2d)

nn.MaxPool2d(kernel_size=2, stride=2)
1)數學原理

最大池化(Max Pooling)是一種非線性下采樣操作,其核心是對輸入張量的局部區域取最大值。以參數 kernel_size=2, stride=2 為例:

  • 窗口劃分:在輸入張量的每個通道上,以 2×2 的窗口(無重疊)滑動。
  • 步長操作:每次滑動 2 個像素(橫向和縱向均移動 2 步),確保窗口不重疊。
  • 計算規則:每個窗口內的最大值作為輸出。

示例
輸入矩陣(2×2 窗口,步長 2):

輸入 (4×4):
[[1,  2,  3,  4],[5,  6,  7,  8],[9,  10, 11, 12],[13, 14, 15, 16]]輸出 (2×2):
[[6,  8],[14, 16]]
  • 第一個窗口(左上角)的值為 [1,2;5,6] → 最大值 6
  • 第二個窗口(右上角)的值為 [3,4;7,8] → 最大值 8
  • 依此類推。
2)核心作用
  1. 降維(下采樣)

    • 降低特征圖的空間分辨率(高度和寬度),減少后續層的計算量和內存消耗。
    • 例如,輸入尺寸 64×224×224 → 輸出 64×112×112(通道數不變)。
  2. 特征不變性增強

    • 平移不變性:即使目標在輸入中有輕微平移,最大池化仍能捕捉到其主要特征。
    • 旋轉/縮放魯棒性:通過保留局部最顯著特征,降低對細節變化的敏感度。
  3. 防止過擬合

    • 減少參數量的同時,抑制噪聲對模型的影響。
  4. 擴大感受野

    • 通過逐步下采樣,后續層的神經元能覆蓋輸入圖像中更大的區域。
3)對輸入輸出的影響

以 PyTorch 的 nn.MaxPool2d(kernel_size=2, stride=2) 為例:

  1. 輸入尺寸[Batch, Channels, Height, Width](如 64×3×224×224)。

  2. 輸出尺寸
    輸出高度 = ? 輸入高度 ? kernel_size stride ? + 1 \text{輸出高度} = \left\lfloor \frac{\text{輸入高度} - \text{kernel\_size}}{\text{stride}} \right\rfloor + 1 輸出高度=?stride輸入高度?kernel_size??+1
    同理計算寬度。

    • 若輸入為 224×224 → 輸出為 112×112(224-2)/2 +1 = 112)。
  3. 通道數不變:池化操作獨立作用于每個通道,不改變通道數。

  4. 數值變化

    • 每個窗口僅保留最大值,其余數值被丟棄。
    • 輸出張量的值域與輸入一致,但稀疏性可能增加(大量低值被過濾)。
4)與卷積層的區別
特性卷積層 (nn.Conv2d)最大池化層 (nn.MaxPool2d)
可學習參數是(權重和偏置)否(固定操作)
作用提取局部特征并組合下采樣,保留顯著特征
輸出通道數可自定義(通過 out_channels與輸入通道數相同
非線性需配合激活函數(如 ReLU)自帶非線性(取最大值)

2.4 全連接層(nn.Linear)

nn.Linear(512*7*7, 4096)
1)數學原理

全連接層(Fully Connected Layer)的數學本質是線性變換 + 偏置,其公式為:
y = W x + b y = Wx + b y=Wx+b

  • 輸入向量 x ∈ R n x \in \mathbb{R}^{n} xRn:將輸入張量展平為一維向量(例如 512×7×7 512 × 7 × 7 = 25088 512 \times 7 \times 7 = 25088 512×7×7=25088維)。

  • 權重矩陣 W ∈ R m × n W \in \mathbb{R}^{m \times n} WRm×n:維度為 [輸出維度, 輸入維度],即 4096 × 25088 4096 \times 25088 4096×25088

  • 偏置向量 b ∈ R m b \in \mathbb{R}^{m} bRm:維度為 4096

  • 輸出向量 y ∈ R m y \in \mathbb{R}^{m} yRm:維度為 4096

  • 假設輸入向量 x ∈ R 25088 x \in \mathbb{R}^{25088} xR25088,權重矩陣 W ∈ R 4096 × 25088 W \in \mathbb{R}^{4096 \times 25088} WR4096×25088,偏置 b ∈ R 4096 b \in \mathbb{R}^{4096} bR4096,則輸出向量的第 i i i 個元素為:
    y i = ∑ j = 1 25088 W i , j ? x j + b i y_i = \sum_{j=1}^{25088} W_{i,j} \cdot x_j + b_i yi?=j=125088?Wi,j??xj?+bi?
    每個輸出元素是輸入向量的加權和,權重矩陣的每一行定義了一個“特征選擇器”。


2)核心作用
  1. 全局特征整合

    • 將卷積層提取的局部特征(如邊緣、紋理)通過矩陣乘法整合為全局語義信息(如物體類別)。
    • 例如:將 512×7×7 的特征圖(對應圖像不同區域的特征)映射到更高維度的抽象語義空間(如“貓”“狗”的分類特征)。
  2. 非線性建模能力

    • 通常配合激活函數(如 ReLU)使用,增強網絡的非線性表達能力。
  3. 維度壓縮/擴展

    • 通過調整輸出維度(如 4096),實現特征壓縮(降維)或擴展(升維)。

3)對輸入輸出的影響

nn.Linear(512*7*7, 4096) 為例:

  1. 輸入尺寸

    • 假設輸入為 [Batch=64, Channels=512, Height=7, Width=7],需先展平為 [64, 512×7×7=25088]
  2. 輸出尺寸

    • 輸出為 [Batch=64, 4096],即每個樣本被映射到 4096 維的特征空間。
  3. 參數數量

    • 權重矩陣參數: 25088 × 4096 = 102 , 760 , 448 25088 \times 4096 = 102,760,448 25088×4096=102,760,448
    • 偏置參數: 4096 4096 4096
    • 總計:102,764,544 個可訓練參數。
4)適用場景與局限性
  1. 適用場景

    • 傳統卷積網絡(如 AlexNet、VGG)的分類頭部。
    • 需要全局特征交互的任務(如語義分割中的上下文建模)。
  2. 局限性

    • 參數量過大:例如本例中超過 1 億參數,易導致過擬合和計算成本高。
    • 空間信息丟失:展平操作破壞特征圖的空間結構,不適合需要保留位置信息的任務(如目標檢測)。
  3. 替代方案

    • 全局平均池化(GAP):將 512×7×7 壓縮為 512×1×1,再輸入全連接層,大幅減少參數(例如 ResNet)。
    • 1×1 卷積:保留空間維度,實現局部特征交互。

三、VGG16網絡結構實現

3.1 特征提取層

在這里插入圖片描述

self.features = nn.Sequential(# Block 1 (2 conv layers)nn.Conv2d(3, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),  # 輸出尺寸112x112# 后續Block結構類似,此處省略...
)
3.1.1 特征提取的作用
  • 特征提取的本質:通過卷積核的局部計算、ReLU的非線性激活、池化的降維,將原始像素逐步抽象為高層語義特征。
  • 數學公式的遞進
    像素 → 卷積+ReLU 邊緣 → 卷積+ReLU 紋理 → 池化 物體部件 → ... 語義特征 \text{像素} \xrightarrow{\text{卷積+ReLU}} \text{邊緣} \xrightarrow{\text{卷積+ReLU}} \text{紋理} \xrightarrow{\text{池化}} \text{物體部件} \xrightarrow{\text{...}} \text{語義特征} 像素卷積+ReLU ?邊緣卷積+ReLU ?紋理池化 ?物體部件... ?語義特征
  • 對輸入的影響:空間分辨率降低,通道數增加,特征語義逐步抽象化。
3.1.2 數學原理
  • 卷積層(核心操作)
    每個卷積核(如 3×3)在輸入特征圖上滑動,計算局部區域的加權和:
    輸出 ( x , y ) = ∑ i = ? 1 1 ∑ j = ? 1 1 輸入 ( x + i , y + j ) ? 權重 ( i , j ) + 偏置 \text{輸出}(x,y) = \sum_{i=-1}^{1}\sum_{j=-1}^{1} \text{輸入}(x+i, y+j) \cdot \text{權重}(i,j) + \text{偏置} 輸出(x,y)=i=?11?j=?11?輸入(x+i,y+j)?權重(i,j)+偏置

    • 權重共享:同一卷積核在不同位置使用相同權重,捕捉空間不變性特征。
    • 多通道:每個卷積核輸出一個通道,多個卷積核組合可提取多維度特征。
  • ReLU 激活函數
    ReLU ( x ) = max ? ( 0 , x ) \text{ReLU}(x) = \max(0, x) ReLU(x)=max(0,x)

    • 作用:引入非線性,增強模型對復雜特征的表達能力。
  • 最大池化層
    輸出 ( x , y ) = max ? i , j ∈ 窗口 輸入 ( x + i , y + j ) \text{輸出}(x,y) = \max_{i,j \in \text{窗口}} \text{輸入}(x+i, y+j) 輸出(x,y)=i,j窗口max?輸入(x+i,y+j)

    • 作用:降維并保留最顯著特征,提升模型對位置變化的魯棒性。

以輸入圖像 [Batch, 3, 224, 224] 為例,逐層分析變化:

層類型輸入尺寸輸出尺寸數學影響
Conv2d(3→64)[B,3,224,224][B,64,224,224]提取 64 種基礎特征(邊緣/顏色)
ReLU[B,64,224,224][B,64,224,224]非線性激活,抑制負響應
Conv2d(64→64)[B,64,224,224][B,64,224,224]細化特征,增強局部模式組合
MaxPool2d[B,64,224,224][B,64,112,112]下采樣,保留最顯著特征
重復塊(128→256→512)逐層增加通道數,提取更復雜特征
最終輸出[B,512,7,7][B,512,7,7]高層語義特征,輸入分類器或檢測頭
  • 通道數變化3 → 64 → 128 → 256 → 512,表示特征復雜度遞增。
  • 空間分辨率下降224x224 → 7x7,通過池化逐步聚焦全局語義。

3.2 分類器層

在這里插入圖片描述

self.classifier = nn.Sequential(nn.Dropout(p=0.5),  # 防止過擬合nn.Linear(512*7*7, 4096),  # 特征圖維度計算nn.ReLU(inplace=True),nn.Dropout(p=0.5),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Linear(4096, num_classes)
)
3.2.1 分類器層作用

分類器層(Classifier)是網絡的最后階段,負責將卷積層提取的高級語義特征映射到類別概率空間。其核心功能包括:

  1. 特征整合:將全局特征轉化為與任務相關的判別性表示。
  2. 分類決策:通過全連接層(Linear)和激活函數(ReLU)生成類別得分。
  3. 正則化:通過Dropout減少過擬合,提升模型泛化能力。
3.2.2 數學原理

假設輸入特征為 x ∈ R 512 × 7 × 7 x \in \mathbb{R}^{512 \times 7 \times 7} xR512×7×7(展平后為25088維),分類器層的計算流程如下:

  1. Dropout層(訓練階段):
    x drop = Dropout ( x , p = 0.5 ) x_{\text{drop}} = \text{Dropout}(x, p=0.5) xdrop?=Dropout(x,p=0.5)

    • 隨機將50%的神經元輸出置零,防止過擬合。
  2. 全連接層1(降維):
    y 1 = W 1 x drop + b 1 ( W 1 ∈ R 4096 × 25088 , b 1 ∈ R 4096 ) y_1 = W_1 x_{\text{drop}} + b_1 \quad (W_1 \in \mathbb{R}^{4096 \times 25088}, \, b_1 \in \mathbb{R}^{4096}) y1?=W1?xdrop?+b1?(W1?R4096×25088,b1?R4096)

    • 將25088維特征壓縮到4096維。
  3. ReLU激活
    a 1 = max ? ( 0 , y 1 ) a_1 = \max(0, y_1) a1?=max(0,y1?)

  4. 重復Dropout和全連接層
    y 2 = W 2 ( Dropout ( a 1 ) ) + b 2 ( W 2 ∈ R 4096 × 4096 ) y_2 = W_2 (\text{Dropout}(a_1)) + b_2 \quad (W_2 \in \mathbb{R}^{4096 \times 4096}) y2?=W2?(Dropout(a1?))+b2?(W2?R4096×4096)
    a 2 = max ? ( 0 , y 2 ) a_2 = \max(0, y_2) a2?=max(0,y2?)

  5. 最終分類層
    y logits = W 3 a 2 + b 3 ( W 3 ∈ R 10 × 4096 ) y_{\text{logits}} = W_3 a_2 + b_3 \quad (W_3 \in \mathbb{R}^{10 \times 4096}) ylogits?=W3?a2?+b3?(W3?R10×4096)

    • 輸出10維向量(CIFAR-10的類別數)。
3.2.3 與特征提取層的對比
特性特征提取層(卷積層)分類器層(全連接層)
輸入類型原始像素或低級特征高級語義特征(如512×7×7)
操作類型局部卷積、池化全局線性變換、非線性激活
參數分布權重共享(卷積核)全連接權重(無共享)
主要功能提取空間局部特征(邊緣→紋理→語義部件)整合全局特征,輸出類別概率
維度變化通道數增加,空間分辨率降低特征維度壓縮,最終輸出類別數

三,完整代碼

import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, transforms, models
from torch.utils.data import DataLoader
import time# 數據預處理
# 將CIFAR-10的32x32圖像縮放至224x224(VGG16的標準輸入尺寸)。
# 使用ImageNet的均值和標準差進行歸一化。
# 缺少數據增強(如隨機裁剪、翻轉等)。
transform = transforms.Compose([transforms.Resize(224),  # VGG16 需要 224x224 的輸入transforms.ToTensor(),transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])# 加載 CIFAR-10 數據集
train_dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)
test_dataset = datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True, num_workers=4)
test_loader = DataLoader(test_dataset, batch_size=64, shuffle=False, num_workers=4)# 定義 VGG16 模型
# 自定義VGG16模型,包含13個卷積層和3個全連接層。
# 輸入尺寸為224x224,經過5次最大池化后特征圖尺寸為7x7,全連接層輸入維度為512 * 7 * 7=25088,符合原版VGG16設計。
# ?特征提取層:13個卷積層(含ReLU激活)+ 5個最大池化層
# ?分類層:3個全連接層(含Dropout)
# ?輸出維度:num_classes(CIFAR-10為10)
class VGG16(nn.Module):def __init__(self, num_classes=10):super(VGG16, self).__init__()# VGG16 的卷積層部分self.features = nn.Sequential(nn.Conv2d(3, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(64, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(128, 128, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(128, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(256, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=3, padding=1),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2))# VGG16 的全連接層部分self.classifier = nn.Sequential(nn.Dropout(),nn.Linear(512 * 7 * 7, 4096),nn.ReLU(inplace=True),nn.Dropout(),nn.Linear(4096, 4096),nn.ReLU(inplace=True),nn.Linear(4096, num_classes))def forward(self, x):x = self.features(x)  # 通過卷積層x = torch.flatten(x, 1)  # 展平x = self.classifier(x)  # 通過全連接層return x# 實例化模型
model = VGG16(num_classes=10)# 使用 GPU 如果可用
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)# 損失函數和優化器
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)# 訓練函數
def train(model, train_loader, criterion, optimizer, num_epochs=10):model.train()  # 切換到訓練模式epoch_times = []for epoch in range(num_epochs):start_time = time.time()running_loss = 0.0correct = 0total = 0for i, (inputs, labels) in enumerate(train_loader):inputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()  # 清空梯度outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()  # 反向傳播optimizer.step()  # 參數更新running_loss += loss.item()_, predicted = outputs.max(1)total += labels.size(0)correct += predicted.eq(labels).sum().item()epoch_loss = running_loss / len(train_loader)epoch_acc = 100. * correct / totalepoch_end_time = time.time()epoch_duration = epoch_end_time - start_timeepoch_times.append(epoch_duration)print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.2f}%, Time: {epoch_duration:.2f}s')avg_epoch_time = sum(epoch_times) / num_epochsprint(f'\nAverage Epoch Time: {avg_epoch_time:.2f}s')# 測試函數
def test(model, test_loader):model.eval()  # 切換到評估模式correct = 0total = 0with torch.no_grad():for inputs, labels in test_loader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)_, predicted = outputs.max(1)total += labels.size(0)correct += predicted.eq(labels).sum().item()accuracy = 100. * correct / totalprint(f'Test Accuracy: {accuracy:.2f}%')# 訓練和測試模型
train(model, train_loader, criterion, optimizer, num_epochs=10)
test(model, test_loader)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/76670.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/76670.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/76670.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

解決RecyclerView在調用smoothScrollToPosition后最后一個item底部超出屏幕的問題

要解決RecyclerView在調用smoothScrollToPosition后最后一個item底部超出屏幕的問題&#xff0c;可以使用自定義的LinearSmoothScroller&#xff0c;使其底部對齊屏幕。步驟如下&#xff1a; 創建自定義的SmoothScroller類&#xff1a; 繼承LinearSmoothScroller并重寫getVerti…

k8s親和力和非親和力

在 Kubernetes 中&#xff0c;親和力&#xff08;Affinity&#xff09;和非親和力&#xff08;Anti-Affinity&#xff09;是用于控制 Pod 調度策略的機制&#xff0c;它們可以幫助優化資源利用率、提高應用性能和可用性。以下是親和力和非親和力的詳細解釋&#xff1a; 親和力…

開發一款游戲需要哪些崗位角色參與?

常見分類 1. 游戲策劃&#xff08;Game Designer&#xff09; 核心職責&#xff1a;設計游戲的玩法、規則、內容和整體體驗。 具體工作&#xff1a; 系統設計&#xff1a;設計游戲的戰斗、經濟、成長、社交等核心系統。 數值設計&#xff1a;平衡角色屬性、裝備數值、經濟系…

Asp.NET Core WebApi 創建帶鑒權機制的Api

構建一個包含 JWT&#xff08;JSON Web Token&#xff09;鑒權的 Web API 是一種常見的做法&#xff0c;用于保護 API 端點并驗證用戶身份。以下是一個基于 ASP.NET Core 的完整示例&#xff0c;展示如何實現 JWT 鑒權。 1. 創建 ASP.NET Core Web API 項目 使用 .NET CLI 或 …

Jenkins 發送釘釘消息

這里不介紹 Jenkins 的安裝&#xff0c;可以網上找到很多安裝教程&#xff0c;重點介紹如何集成釘釘消息。 需要提前準備釘釘機器人的 webhook 地址。&#xff08;網上找下&#xff0c;很多教程&#xff09; 下面開始配置釘釘機器人&#xff0c;登錄 Jenkins&#xff0c;下載 …

CentOS中離線安裝DockerCompos并用其部署Rabbitmq(使用離線導入導出docker鏡像方式)

場景 DockerDockerCompose實現部署jenkins,并實現jenkinsfile打包SpringBootVue流水線項目過程詳解、踩坑記錄(附鏡像資源、離線包資源下載)&#xff1a; DockerDockerCompose實現部署jenkins,并實現jenkinsfile打包SpringBootVue流水線項目過程詳解、踩坑記錄(附鏡像資源、離…

stm32week11

stm32學習 八.stm32基礎 2.stm32內核和芯片 F1系統架構&#xff1a;4個主動單元和4個被動單元 AHB是內核高性能總線&#xff0c;APB是外圍總線 總線矩陣將總線和各個主動被動單元連到一起 ICode總線直接連接Flash接口&#xff0c;不需要經過總線矩陣 AHB&#xff1a;72MHz&am…

貪心算法:部分背包問題深度解析

簡介&#xff1a; 該Java代碼基于貪心算法實現了分數背包問題的求解&#xff0c;核心通過單位價值降序排序和分階段裝入策略實現最優解。首先對Product數組執行雙重循環冒泡排序&#xff0c;按wm(價值/重量比)從高到低重新排列物品&#xff1b;隨后分兩階段裝入&#xff1a;循環…

13. Langchain異步處理:提升應用性能的關鍵技巧

引言&#xff1a;從"順序等待"到"并行加速" 2025年某電商平臺引入LangChain異步處理后&#xff0c;大促期間訂單處理能力提升5倍&#xff0c;系統響應延遲降低70%。本文將基于LangChain的異步架構&#xff0c;詳解如何通過并行執行流式處理&#xff0c;讓…

ros2-rviz2控制unity仿真的6關節機械臂,探索從仿真到實際應用的過程

文章目錄 前言&#xff08;Introduction&#xff09;搭建開發環境&#xff08;Setup Development Environment&#xff09;在window中安裝Unity&#xff08;Install Unity in window&#xff09;創建Docker容器&#xff0c;并安裝相關軟件&#xff08;Create Docker containers…

計算機組成原理筆記(十四)——3.4指令類型

一臺計算機的指令系統可以有上百條指令&#xff0c;這些指令按其功能可以分成幾種類型&#xff0c;下面分別介紹。 3.4.1數據傳送類指令 一、核心概念與功能定位 數據傳送類指令是計算機指令系統中最基礎的指令類型&#xff0c;負責在 寄存器、主存、I/O設備 之間高效復制數…

各開源協議一覽

在 GitHub 上&#xff0c;開源項目通常會使用一些常見的開源協議來定義項目的使用、修改和分發規則。以下是目前 GitHub 上最常見的幾種開源協議及其差異和示例說明&#xff1a; TL;DR 協議寬松程度是否強制開源專利保護適用場景MIT最寬松否無希望代碼被廣泛使用Apache 2.0寬松…

51c自動駕駛~合集17

我自己的原文哦~ https://blog.51cto.com/whaosoft/13793157 #匯聚感知、定位、規劃控制的自動駕駛系統 自動駕駛技術在應用到車輛上之后可以通過提高吞吐量來緩解道路擁堵&#xff0c;通過消除人為錯誤來提高道路安全性&#xff0c;并減輕駕駛員的駕駛負擔&#xff0c;從…

小程序開發指南

小程序開發指南 目錄 1. 小程序開發概述 1.1 什么是小程序1.2 小程序的優勢1.3 小程序的發展歷程 2. 開發準備工作 2.1 選擇開發平臺2.2 開發環境搭建2.3 開發模式選擇 3. 小程序開發流程 3.1 項目規劃3.2 界面設計3.3 代碼開發3.4 基本開發示例3.5 數據存儲3.6 網絡請求3.7 …

Day15:關于MySQL的編程技術——基礎知識

前言&#xff1a;先創建一個練習的數據庫和數據 1.創建數據庫并創建數據表的基本結構 -- 創建練習數據庫 CREATE DATABASE db_programming; USE db_programming;-- 創建員工表&#xff08;包含各種數據類型&#xff09; CREATE TABLE employees (emp_id INT PRIMARY KEY AUTO…

批處理腳本bat丨遍歷一個包含項目名稱的數組,并對每個文件中的項目執行 git pull 操作 (一鍵拉很多文件的代碼)

文章目錄 前言一、操作方式二、文件展示三、分析代碼結構四、代碼五、需要注意的潛在問題六、改進后的代碼七、改進說明八、感謝 前言 由于之前git服務部署在本地服務器&#xff0c;處于代碼安全角度考慮。領導讓我將所有的項目代碼手動物理備份一份并且發給他。 這種傻傻的操…

【C++】C與C++、C++內存空間、堆與棧

C嘎嘎嘎嘎嘎~ C與C的區別與聯系 C內存空間 int global_var; // 未初始化全局變量&#xff0c;BSS段 const char* str "Hello"; // 字符串常量text段 in數據段void func() {static int static_var; // 未初始化的靜態變量&#xff0c;數據段int local_var; …

舵機:機器人領域的“關節革命者”

機器人的技術&#xff0c;每一個細微的進步都可能引領一場行業變革。而在這場變革中&#xff0c;舵機作為機器人關節的核心部件&#xff0c;正悄然上演著一場革命性的應用風暴。從簡單的關節運動到復雜的姿態控制&#xff0c;舵機以其卓越的性能和無限的可能&#xff0c;重新定…

微前端的不斷探索之路—— qiankun 實戰與思考!

全文目錄&#xff1a; 開篇語&#x1f4dd; 前言&#x1f6e0;? 微前端是什么&#xff1f;為什么需要它&#xff1f;&#x1f4a1; 先從“前端痛點”說起&#x1f9d0; 微前端的優勢 &#x1f939;?♀? qiankun 簡介與核心概念&#x1f31f; 為什么選擇 qiankun&#xff1f;…

拆解加密黑盒

在Web安全與數據爬取領域&#xff0c;JavaScript加密黑盒的逆向工程是核心技術之一。本文基于行業通用方法論與實戰案例&#xff0c;提煉出一套標準化的五步逆向流程&#xff0c;涵蓋目標定位、代碼提取、邏輯分析、算法復現到自動化集成的全鏈路解決方案&#xff0c;幫助開發者…