一、激活函數(Activation Functions)

爲什麼需要激活函數?
神經網絡的基本單元是神經元,每個神經元的輸出是輸入的加權和(線性變換)。如果沒有激活函數,無論堆疊多少層神經元,輸出始終是輸入的線性組合,無法擬合複雜的非線性關係(比如圖像中的邊緣、紋理等)。激活函數的作用就是引入非線性變換,讓網絡具備“學習複雜模式”的能力。

1. 常見激活函數及PyTorch實現

(1)ReLU(Rectified Linear Unit)
  • 公式y = max(0, x)
  • 當輸入x > 0時,輸出等於輸入;當x ≤ 0時,輸出爲0。
  • 特點:計算簡單,解決了傳統Sigmoid/Tanh的梯度消失問題,訓練速度快,是目前最常用的激活函數。
  • PyTorch實現
  import torch
  import torch.nn as nn

  # 創建ReLU激活函數實例
  relu = nn.ReLU()

  # 測試:輸入一個張量
  x = torch.tensor([-1.0, 0.0, 1.5, -0.3])
  y = relu(x)
  print("ReLU輸出:", y)  # 輸出:tensor([0.0000, 0.0000, 1.5000, 0.0000])
(2)Sigmoid函數
  • 公式y = 1 / (1 + exp(-x))
  • 輸出範圍在(0, 1)之間,常用於二分類問題的輸出層(將結果轉爲概率)。
  • 特點:輸出是概率值,但當x很大或很小時,梯度趨近於0,容易出現梯度消失,深層網絡訓練困難。
  • PyTorch實現
  sigmoid = nn.Sigmoid()
  x = torch.tensor([-2.0, 0.0, 2.0])
  y = sigmoid(x)
  print("Sigmoid輸出:", y)  # 輸出:tensor([0.1192, 0.5000, 0.8808])
(3)Tanh函數
  • 公式y = (exp(x) - exp(-x)) / (exp(x) + exp(-x))
  • 輸出範圍在(-1, 1)之間,均值爲0,理論上比Sigmoid更易訓練。
  • 特點:仍存在梯度消失問題,應用場景較少,主要用於RNN等序列模型的隱藏層。
  • PyTorch實現
  tanh = nn.Tanh()
  x = torch.tensor([-1.0, 0.0, 1.0])
  y = tanh(x)
  print("Tanh輸出:", y)  # 輸出:tensor([-0.7616, 0.0000, 0.7616])

二、卷積層(Convolutional Layers)

卷積層是什麼?
卷積層是CNN(卷積神經網絡)的核心,通過滑動一個“濾鏡”(卷積核)在輸入數據上,提取局部特徵(如邊緣、紋理)。例如,用不同的卷積核可以識別圖像中的“邊緣”“條紋”等模式。

1. 卷積操作的基本概念
  • 輸入:假設輸入是一張灰度圖像(單通道,二維矩陣),形狀爲(H, W)
  • 卷積核(Filter/Kernel):一個小矩陣(如3x3),用於特徵提取。
  • 步長(Stride):卷積核每次滑動的像素數(默認1)。
  • 填充(Padding):在輸入邊緣添加0,控制輸出尺寸(避免特徵丟失)。

簡單示例
輸入:3x3矩陣(像素值)

[[1, 2, 3],
 [4, 5, 6],
 [7, 8, 9]]

卷積核:2x2矩陣

[[a, b],
 [c, d]]

輸出計算:每個位置是卷積核覆蓋區域的像素乘積之和
- 左上角:1*a + 2*b + 4*c + 5*d
- 右上角:2*a + 3*b + 5*c + 6*d
- 左下角:4*a + 5*b + 7*c + 8*d
- 右下角:5*a + 6*b + 8*c + 9*d

2. PyTorch中的卷積層(nn.Conv2d)

在PyTorch中,卷積層通過nn.Conv2d實現,用於處理二維圖像數據(如RGB圖像)。輸入形狀(batch_size, in_channels, height, width),其中:
- batch_size:批量樣本數(如一次處理16張圖像);
- in_channels:輸入通道數(RGB圖像爲3,灰度圖爲1);
- height/width:圖像高度和寬度。

關鍵參數
- in_channels:輸入通道數;
- out_channels:輸出通道數(卷積核數量,決定特徵圖複雜度);
- kernel_size:卷積核大小(如3表示3x3);
- stride:步長(默認1);
- padding:填充(默認0)。

輸出形狀計算
輸出高度/寬度 = (輸入高度/寬度 + 2*padding - kernel_size) // stride + 1

代碼示例
假設輸入是一張RGB圖像(batch=1,通道數=3,尺寸=28x28),用3x3卷積核,輸出16個通道:

# 1. 導入庫
import torch
import torch.nn as nn

# 2. 創建輸入張量(batch=1, 通道=3, 高=28, 寬=28)
x = torch.randn(1, 3, 28, 28)  # 隨機生成數據

# 3. 定義卷積層
conv = nn.Conv2d(
    in_channels=3,     # 輸入3個通道(RGB)
    out_channels=16,   # 輸出16個通道(16個卷積核)
    kernel_size=3,     # 3x3卷積核
    stride=1,          # 步長1
    padding=1          # 填充1,保持輸出尺寸不變
)

# 4. 前向傳播(應用卷積)
y = conv(x)

# 5. 打印輸入和輸出形狀
print("輸入形狀:", x.shape)    # 輸出:torch.Size([1, 3, 28, 28])
print("輸出形狀:", y.shape)    # 輸出:torch.Size([1, 16, 28, 28])
3. 卷積層 + 激活函數實戰

通常卷積層後接激活函數(如ReLU),形成“卷積→激活”的基本單元:

# 創建卷積層+ReLU
conv_relu = nn.Sequential(
    nn.Conv2d(3, 16, 3, 1, 1),  # 卷積層
    nn.ReLU()                   # 激活函數
)

y = conv_relu(x)
print("卷積+ReLU輸出:", y.shape)  # 仍爲torch.Size([1, 16, 28, 28])

總結:激活函數讓神經網絡引入非線性,卷積層通過滑動窗口提取圖像特徵。兩者結合是CNN模型的核心結構,後續可進一步學習池化層(如MaxPooling)和全連接層,構建完整的圖像識別模型。

小練習:嘗試修改卷積核大小(如kernel_size=5)或步長(stride=2),觀察輸出形狀變化,理解各參數對特徵提取的影響。

小夜