卷积神经网络
1. 从全连接层到卷积
全连接层的参数量随输入尺寸增长而爆炸式增加,难以处理高维数据(如图像)。卷积神经网络(CNN)通过局部连接、权值共享和空间下采样解决这一问题:
-
局部连接:每个神经元仅连接输入层的局部区域(感受野)。
-
权值共享:同一卷积核在输入的不同位置滑动时使用相同参数。
python
# 全连接层 vs 卷积层示例
import torch
import torch.nn as nn
# 全连接层:输入尺寸需固定
fc = nn.Linear(784, 256) # MNIST图像展平为784维
# 卷积层:处理任意尺寸的2D输入
conv = nn.Conv2d(in_channels=1, out_channels=16, kernel_size=3)
2. 图像卷积
卷积操作通过滑动窗口(卷积核)计算局部区域的加权和,提取边缘、纹理等特征。数学表达式:
python
# 手动实现2D卷积(简化版)
def conv2d(X, K):
h, w = K.shape
Y = torch.zeros((X.shape[0] - h + 1, X.shape[1] - w + 1))
for i in range(Y.shape[0]):
for j in range(Y.shape[1]):
Y[i, j] = (X[i:i+h, j:j+w] * K).sum()
return Y
3. 填充和步幅
-
填充(Padding):在输入周围补零,控制输出尺寸。常见策略:
-
same填充:输出尺寸与输入相同。
-
valid填充:无填充,输出尺寸缩小。
-
-
步幅(Stride):卷积核滑动步长,减少计算量。
输出尺寸公式:
python
# PyTorch中的填充和步幅设置
conv = nn.Conv2d(1, 1, kernel_size=3, padding=1, stride=2)
4. 多输入多输出通道
-
多输入通道:卷积核与输入通道数相同,逐通道卷积后求和。
-
多输出通道:使用多个卷积核,每个核生成一个输出通道。
python
# 多通道卷积示例
conv = nn.Conv2d(in_channels=3, out_channels=10, kernel_size=3)
5. 汇聚层(池化层)
降低空间分辨率,增强平移不变性。常见操作:
-
最大池化:取局部区域最大值,保留显著特征。
-
平均池化:取局部区域平均值,平滑特征。
python
# PyTorch中的池化层
max_pool = nn.MaxPool2d(kernel_size=2, stride=2)
avg_pool = nn.AvgPool2d(kernel_size=2, stride=2)
6. 卷积神经网络(LeNet)
LeNet-5是早期CNN经典结构,包含卷积层、池化层和全连接层:
-
卷积层(C1):6个5×5卷积核,输出6通道特征图。
-
池化层(S2):2×2最大池化。
-
卷积层(C3):16个5×5卷积核。
-
池化层(S4):2×2最大池化。
-
全连接层(C5、F6、Output):分类输出。
python
# LeNet-5 PyTorch实现
class LeNet(nn.Module):
def __init__(self):
super().__init__()
self.net = nn.Sequential(
nn.Conv2d(1, 6, kernel_size=5), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
nn.AvgPool2d(kernel_size=2, stride=2),
nn.Flatten(),
nn.Linear(16*4*4, 120), nn.Sigmoid(),
nn.Linear(120, 84), nn.Sigmoid(),
nn.Linear(84, 10))
def forward(self, X):
return self.net(X)
关键理论:
-
卷积层通过局部感受野和权值共享减少参数量。
-
池化层提供空间不变性并降低维度。
-
堆叠卷积和池化层可逐级提取高阶特征(如纹理→部件→物体)。
现代卷积神经网络
1. 深度卷积神经网络(AlexNet)
关键理论:AlexNet首次证明了深度卷积神经网络在图像分类任务上的有效性,采用ReLU激活函数、Dropout和数据增强技术缓解过拟合,使用局部响应归一化(LRN)和多GPU并行训练。
核心代码(PyTorch实现):
python
import torch.nn as nn
class AlexNet(nn.Module):
def __init__(self, num_classes=1000):
super().__init__()
self.features = nn.Sequential(
nn.Conv2d(3, 96, kernel_size=11, stride=4, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(96, 256, kernel_size=5, padding=2),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
nn.Conv2d(256, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 384, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.Conv2d(384, 256, kernel_size=3, padding=1),
nn.ReLU(inplace=True),
nn.MaxPool2d(kernel_size=3, stride=2),
)
self.classifier = nn.Sequential(
nn.Dropout(),
nn.Linear(256 * 6 * 6, 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
2. 使用块的网络(VGG)
关键理论:VGG通过堆叠多个3×3卷积核代替大卷积核(如5×5或7×7),减少参数量的同时增加网络深度,提出模块化设计思想(VGG-16、VGG-19)。
核心代码:
python
def make_layers(cfg):
layers = []
in_channels = 3
for v in cfg:
if v == 'M':
layers += [nn.MaxPool2d(kernel_size=2, stride=2)]
else:
layers += [
nn.Conv2d(in_channels, v, kernel_size=3, padding=1),
nn.ReLU(inplace=True)
]
in_channels = v
return nn.Sequential(*layers)
cfg = [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512, 512, 'M']
vgg = make_layers(cfg)
3. 网络中的网络(NiN)
关键理论:NiN使用1×1卷积替代全连接层,提出"MLP卷积"结构(多层感知机卷积),减少参数并增强局部非线性。
核心代码:
python
class NiNBlock(nn.Module):
def __init__(self, in_channels, out_channels):
super().__init__()
self.mlpconv = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1),
nn.ReLU(),
nn.Conv2d(out_channels, out_channels, kernel_size=1),
nn.ReLU(),
)
def forward(self, x):
return self.mlpconv(x)
4. 含并行连结的网络(GoogLeNet)
关键理论:提出Inception模块,通过并行多尺度卷积(1×1、3×3、5×5和池化)融合特征,并利用1×1卷积降维控制计算量。
核心代码(简化Inception模块):
python
class Inception(nn.Module):
def __init__(self, in_channels, ch1x1, ch3x3red, ch3x3, ch5x5red, ch5x5, pool_proj):
super().__init__()
self.branch1 = nn.Conv2d(in_channels, ch1x1, kernel_size=1)
self.branch2 = nn.Sequential(
nn.Conv2d(in_channels, ch3x3red, kernel_size=1),
nn.Conv2d(ch3x3red, ch3x3, kernel_size=3, padding=1)
)
self.branch3 = nn.Sequential(
nn.Conv2d(in_channels, ch5x5red, kernel_size=1),
nn.Conv2d(ch5x5red, ch5x5, kernel_size=5, padding=2)
)
self.branch4 = nn.Sequential(
nn.MaxPool2d(kernel_size=3, stride=1, padding=1),
nn.Conv2d(in_channels, pool_proj, kernel_size=1)
)
def forward(self, x):
return torch.cat([
self.branch1(x),
self.branch2(x),
self.branch3(x),
self.branch4(x)
], 1)
5. 批量规范化(BatchNorm)
关键理论:对每层输入进行标准化(均值为0,方差为1),加速训练并减少对初始化的依赖,公式:
代码实现:
python
nn.BatchNorm2d(num_features)
6. 残差网络(ResNet)
关键理论:提出残差连接(Residual Block),解决深层网络梯度消失问题,公式:
核心代码:
python
class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, padding=1)
self.bn2 = nn.BatchNorm2d(out_channels)
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride),
nn.BatchNorm2d(out_channels)
)
def forward(self, x):
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x)
return F.relu(out)
7. 稠密连接网络(DenseNet)
关键理论:每一层的输入来自前面所有层的输出,特征复用,公式:
核心代码(Dense Block):
python
class DenseLayer(nn.Module):
def __init__(self, in_channels, growth_rate):
super().__init__()
self.bn = nn.BatchNorm2d(in_channels)
self.conv = nn.Conv2d(in_channels, growth_rate, kernel_size=3, padding=1)
def forward(self, x):
out = self.conv(F.relu(self.bn(x)))
return torch.cat([x, out], 1)