一、激活函数(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),观察输出形状变化,理解各参数对特征提取的影响。