卷积神经网络

卷积神经网络 (CNN)

卷积神经网络(Convolutional Neural Network, CNN)是一类特殊的深度神经网络,专为处理具有网格结构的数据而设计,特别是图像数据。自从2012年AlexNet在ImageNet竞赛中取得突破性成功以来,CNN已成为计算机视觉领域的主导技术。

1. CNN的基本原理

卷积神经网络的核心思想是通过卷积操作自动学习空间层次特征。与传统的多层感知机(MLP)不同,CNN具有以下特点:

  • 局部连接:每个神经元只与输入数据的一个局部区域连接
  • 权值共享:同一特征图中的神经元共享相同的权重
  • 空间下采样:通过池化操作减少数据维度并提高鲁棒性

这些特性使CNN在保留空间信息的同时大幅减少了参数数量,提高了计算效率和泛化能力。

2. CNN的基本组成部分

2.1 卷积层(Convolutional Layer)

卷积层是CNN最重要的组成部分,主要通过卷积操作提取输入数据的特征。

卷积操作过程如下:

1
2
3
输入: 一个尺寸为 H×W×C 的数据(高×宽×通道数)
卷积核: K个尺寸为 Kh×Kw×C 的过滤器
输出: 一个尺寸为 H'×W'×K 的特征图

卷积过程示意:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
输入矩阵(5×5):        卷积核(3×3):
┌───┬───┬───┬───┬───┐ ┌───┬───┬───┐
1 1 1 0 0 │ │ 1 0 1
├───┼───┼───┼───┼───┤ ├───┼───┼───┤
0 1 1 1 0 │ │ 0 1 0
├───┼───┼───┼───┼───┤ ├───┼───┼───┤
0 0 1 1 1 │ │ 1 0 1
├───┼───┼───┼───┼───┤ └───┴───┴───┘
0 0 1 1 0
├───┼───┼───┼───┼───┤ 输出矩阵(3×3):
0 1 1 0 0 │ ┌───┬───┬───┐
└───┴───┴───┴───┴───┘ │ 4 3 4
├───┼───┼───┤
2 4 3
├───┼───┼───┤
2 3 3
└───┴───┴───┘

卷积过程计算示例(左上角):

1
2
3
1×1 + 1×0 + 1×1 +
0×0 + 1×1 + 1×0 +
0×1 + 0×0 + 1×1 = 4

卷积核在原始图像上滑动,每个位置执行”乘积求和”操作。卷积过程自动提取特征,如边缘、纹理和形状。不同的卷积核可以检测不同的特征模式,通过学习这些卷积核的权重,CNN能够适应各种视觉识别任务。

卷积的数学表示:

$$F(i,j) = \sum_{m=0}^{k_h-1} \sum_{n=0}^{k_w-1} I(i+m, j+n) \cdot K(m,n)$$

其中$F$是输出特征图,$I$是输入图像,$K$是卷积核。

2.2 激活函数层

卷积层之后通常跟随一个非线性激活函数,常用的有:

  • ReLU (Rectified Linear Unit): $f(x) = \max(0, x)$
  • Leaky ReLU: $f(x) = \max(0.01x, x)$
  • ELU (Exponential Linear Unit): $f(x) = \begin{cases} x, & \text{if } x > 0 \ \alpha(e^x - 1), & \text{if } x \leq 0 \end{cases}$

激活函数的引入为网络带来非线性,提高了模型的表达能力。

2.3 池化层(Pooling Layer)

池化层的主要功能是减少特征图的空间尺寸,降低计算复杂度,同时提高一定的位移不变性。常见的池化操作有:

  • 最大池化(Max Pooling): 取窗口内的最大值
  • 平均池化(Average Pooling): 计算窗口内像素的平均值

2.4 全连接层(Fully Connected Layer)

在经过多个卷积和池化层后,特征图被展平为一维向量,然后通过全连接层进行分类或回归。这与传统神经网络的操作类似,每个神经元与前一层的所有神经元相连。

3. 经典CNN架构

3.1 LeNet-5

由Yann LeCun在1998年提出,是最早的CNN架构之一,用于手写数字识别。

结构:

  • 输入: 32×32 灰度图像
  • 两个卷积层和池化层的组合
  • 三个全连接层

3.2 AlexNet

2012年ImageNet竞赛冠军,标志着深度学习时代的到来。

主要创新:

  • 使用ReLU激活函数
  • 使用Dropout防止过拟合
  • 使用数据增强技术
  • 在GPU上进行训练

3.3 VGG

由牛津大学提出,以简洁的网络结构著称。

特点:

  • 使用3×3的小卷积核
  • 网络深度达到16-19层
  • 结构规整,便于理解与修改

3.4 GoogLeNet(Inception)

谷歌提出的网络架构,引入了Inception模块。

特点:

  • 使用1×1卷积减少计算量
  • 并行使用多种尺寸的卷积核
  • 中间层添加辅助分类器

3.5 ResNet

微软研究院提出的残差网络,通过残差连接解决了深层网络的梯度消失问题。

残差块结构:

1
2
3
x ---> Conv ---> BN ---> ReLU ---> Conv ---> BN --->+---> ReLU ---> output
| ^
+----------------------------------------------------+

4. CNN的简单实现

下面是一个使用PyTorch实现的简单卷积神经网络示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torchvision import datasets, transforms

# 定义CNN模型
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 第一个卷积层,输入通道1,输出通道32,卷积核大小3x3
self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
# 第二个卷积层,输入通道32,输出通道64,卷积核大小3x3
self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
# 池化层
self.pool = nn.MaxPool2d(kernel_size=2)
# 全连接层
self.fc1 = nn.Linear(64 * 7 * 7, 128)
self.fc2 = nn.Linear(128, 10)
self.dropout = nn.Dropout(0.25)

def forward(self, x):
# 第一个卷积层 + 激活函数 + 池化
x = F.relu(self.conv1(x))
x = self.pool(x)
# 第二个卷积层 + 激活函数 + 池化
x = F.relu(self.conv2(x))
x = self.pool(x)
# 展平
x = x.view(-1, 64 * 7 * 7)
# 全连接层
x = F.relu(self.fc1(x))
x = self.dropout(x)
x = self.fc2(x)
return F.log_softmax(x, dim=1)

# 训练函数
def train_model(model, device, train_loader, optimizer, epoch):
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
data, target = data.to(device), target.to(device)
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if batch_idx % 100 == 0:
print(f'Train Epoch: {epoch} [{batch_idx * len(data)}/{len(train_loader.dataset)}]\tLoss: {loss.item():.6f}')

# 测试函数
def test_model(model, device, test_loader):
model.eval()
test_loss = 0
correct = 0
with torch.no_grad():
for data, target in test_loader:
data, target = data.to(device), target.to(device)
output = model(data)
test_loss += F.nll_loss(output, target, reduction='sum').item()
pred = output.argmax(dim=1, keepdim=True)
correct += pred.eq(target.view_as(pred)).sum().item()

test_loss /= len(test_loader.dataset)
print(f'\nTest set: Average loss: {test_loss:.4f}, Accuracy: {correct}/{len(test_loader.dataset)} ({100. * correct / len(test_loader.dataset):.2f}%)\n')

# 主函数
def main():
# 检查是否有可用的GPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 准备数据
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])

# 加载MNIST数据集
train_dataset = datasets.MNIST('../data', train=True, download=True, transform=transform)
test_dataset = datasets.MNIST('../data', train=False, transform=transform)

train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=64, shuffle=True)
test_loader = torch.utils.data.DataLoader(test_dataset, batch_size=1000)

# 创建模型
model = SimpleCNN().to(device)
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练和测试模型
for epoch in range(1, 6):
train_model(model, device, train_loader, optimizer, epoch)
test_model(model, device, test_loader)

if __name__ == '__main__':
main()

这个简单的CNN实现可用于MNIST手写数字识别,包含了两个卷积层、两个池化层和两个全连接层。模型结构简洁,易于理解,是入门CNN的理想示例。


卷积神经网络
http://neutrino.top/2025/03/27/卷积神经网络/
作者
Neutrin1
发布于
2025年3月27日
许可协议