文章目录
一、CNN的基本介绍与卷积思想
1. 卷积神经网络(CNN)
卷积神经网络(Convolutional Neural Network,简称 CNN)是一种受生物视觉系统启发的深度学习模型,尤其擅长处理网格结构数据(如图像、视频、音频等),在计算机视觉领域(如图像分类、目标检测、图像分割等)有广泛应用。
局部感知:
CNN通过局部感受野(Local Receptive Field)机制,每个神经元仅与输入数据的局部区域连接(而非全连接),模拟人类视觉系统 “局部感知” 的特性。- 优点:
- 减少参数量,降低计算复杂度。
- 保留空间信息,适合处理网格结构数据(如图像)。
- 优点:
权值共享:
所有神经元共享同一组权重(卷积核),在整个输入上滑动应用相同的权重。- 优点:
- 进一步减少参数数量,避免过拟合。
- 提供平移不变性(Translation Invariance),即使特征位置变化也能识别。
- 优点:
池化操作:通过下采样(如取最大值、平均值)压缩数据维度,增强模型对输入微小变化的鲁棒性(如平移、旋转)。
2. 使用场景
3. 卷积的思想
卷积操作的核心思想是通过一个可学习的卷积核(kernel,也叫滤波器 filter)在输入数据上滑动,对每个位置进行局部的加权求和,从而提取出数据中的局部特征。这种局部连接的方式使得 CNN 能够有效捕捉数据中的空间或时间局部相关性,同时减少参数数量,降低计算复杂度。
二、卷积层
1. 卷积核(Filter/Kernel)
定义:
卷积核是一个小型矩阵(如 3 × 3 3 \times 3 3×3),通过滑动窗口在输入上提取局部特征。通过在训练过程中不断调整这些参数,卷积核能够提取出与特定特征相对应的模式。不同的卷积核可以捕捉不同类型的特征作用:
- 提取特定模式(如边缘、纹理、颜色)。
- 通过多个卷积核生成多通道特征图
2. 卷积计算过程
步骤:
- 滑动窗口:卷积核在输入上按步长(Stride)滑动。
- 逐元素相乘并求和:计算卷积核与输入局部区域的点积。
- 填充(Padding):在输入边缘添加0,控制输出尺寸。
- 无填充(Valid):输出尺寸减小。
- 等宽填充(Same):输出尺寸与输入相同(如
padding=1
时)。
按照设定的步长(stride),将卷积核在输入图像上向右移动一个步长,重复上述元素相乘与求和操作,直到卷积核遍历完输入图像的一行。然后,将卷积核移动到下一行的起始位置,再次进行遍历,直至覆盖整个输入图像。
左上角的点计算方法:
按照上面的计算方法可以得到最终的特征图为:
- 输出尺寸公式:
H o u t = H i n + 2 × padding − kernel_size stride + 1 H_{out} = \frac{H_{in} + 2 \times \text{padding} - \text{kernel\_size}}{\text{stride}} + 1 Hout=strideHin+2×padding−kernel_size+1
3. 基于PyTorch的API实现
代码示例:
import torch import torch.nn as nn # 定义卷积层 conv_layer = nn.Conv2d( in_channels=3, # 输入通道数(如RGB图像) out_channels=16, # 输出通道数(即卷积核数量) kernel_size=3, # 卷积核大小 stride=1, # 步长 padding=1 # 填充 ) # 假设输入一个大小为1x3x224x224的图像张量(1为批量大小) input_image = torch.randn(1, 3, 224, 224) # 进行卷积计算 output = conv_layer(input_image) print(output.shape)
参数说明:
in_channels
:输入数据的通道数(如图像的RGB通道为3)。out_channels
:输出特征图的通道数(即卷积核数量)。kernel_size
:卷积核的大小(如 3 × 3 3 \times 3 3×3)。stride
:卷积核滑动的步长。padding
:输入边缘的填充宽度。
边缘填充
padding
:输入边缘的填充宽度。
假设用 3×3 的卷积核处理 5×5 的输入:
- 不填充(padding=0):输出会变成 3×3(尺寸缩小)
- 边缘信息(如角落、边界像素)只被卷积 1 次,容易丢失
填充后可以:
- 让输出尺寸与输入相同(如 “Same Padding”)
- 减少边缘特征的损失
步长
stride
:卷积核滑动的步长。
按照步长为1来移动卷积核,计算特征图如下所示:
如果我们把 Stride 增大为2,也是可以提取特征图的,如下图所示:
步长越大,输出特征图尺寸越小(下采样效果越明显)。
简化公式(不考虑填充时):
输出尺寸 = (输入尺寸 - 卷积核尺寸) / 步长 + 1
举例:
- 输入 5×5,卷积核 3×3,步长 = 1:输出 =(5-3)/1+1=3×3
- 输入 5×5,卷积核 3×3,步长 = 2:输出 =(5-3)/2+1=2×2
4. 多卷积核卷积计算
多通道特征图:
在实际应用中,通常会使用多个卷积核同时对输入数据进行卷积操作。每个卷积核都独立地在输入数据上滑动并计算,得到一个对应的特征图。
若使用 C o u t C_{out} Cout 个卷积核,则输出特征图有 C o u t C_{out} Cout 个通道。
示例:
- 输入:1x3x224x224 的图像张量
- 卷积层:使用 16 个 3x3 的卷积核进行卷积,每个卷积核生成一个 222x222(假设步长为 1,无填充)的特征图
- 输出:1x16x222x222,其中 16 表示通道数,对应 16 个卷积核生成的 16 个特征图。
5. 多通道卷积计算
在计算机眼中,图象是一个矩阵,通道越多,表达的特征就越多
计算多通道:
- 每个通道的卷积核与对应输入通道做卷积,得到单通道特征图。
- 将所有单通道特征图的对应位置相加,得到最终的单通道输出特征图。
三、池化层(Pooling Layer)
1. 池化的基本概念
池化层(Pooling Layer)也是 CNN 中的重要组成部分,其主要作用是对输入的特征图进行下采样,即减小特征图的空间尺寸(高度和宽度)。池化操作通过对局部区域内的特征进行聚合,保留主要特征信息的同时降低计算量和模型参数数量,并且在一定程度上提高模型的平移不变性和鲁棒性。
作用:
- 降维:通过局部区域的统计操作(如取最大值或平均值),减少特征图的空间尺寸(高度和宽度)。
- 降低计算量:减少后续层的参数数量和计算复杂度。
- 增强鲁棒性:通过降低分辨率,使模型对输入的小幅变化(如平移、旋转、缩放)不敏感,提升泛化能力。
- 防止过拟合:丢弃冗余信息,保留主要特征,降低模型复杂度。
常见类型:
- 最大池化(Max Pooling):取局部区域的最大值。
- 平均池化(Average Pooling):取局部区域的平均值。
整体结构
计算
2. 池化计算过程
步骤:
- 将池化窗口(如 2 × 2 2 \times 2 2×2)在特征图上滑动。
- 对每个窗口执行最大值或平均值操作。
- 生成下采样后的特征图。
输出尺寸公式:
H o u t = H i n − kernel_size stride + 1 H_{out} = \frac{H_{in} - \text{kernel\_size}}{\text{stride}} + 1 Hout=strideHin−kernel_size+1
2.1 最大池化
原理:最大池化是在一个局部窗口内选取最大值作为输出。
max_pool = nn.MaxPool2d
(kernel_size=2, stride=2)
kernel_size
:池化窗口大小stride
:窗口每次滑动的步长padding
:是否在图片边缘补 0(0 就是不补,1 就是补一圈 0)dilation
:窗口内部元素的间距(默认 1,就是正常相邻元素)return_indices
:是否返回最大值的位置(False 不返回,True 返回)ceil_mode
:输出尺寸计算方式(False 向下取整,True 向上取整)
import torch.nn as nn
# 2×2窗口,步长2的最大池化
max_pool = nn.MaxPool2d(kernel_size=2, stride=2)
特点:
- 能突出局部区域中最显著的特征(比如图像中的边缘、纹理的强烈变化)。
- 对噪声更敏感(若窗口内有一个极大值,即使其他值是噪声也会被保留)。
- 更适合需要 “抓细节” 的任务(如目标检测中识别物体的关键部位)。
2.2 平均池化
原理:在指定大小的窗口内,计算所有元素的平均值作为输出。
avg_pool = nn.AvgPool2d
(kernel_size=2, stride=2)
# 3×3窗口,步长1的平均池化
avg_pool = nn.AvgPool2d(kernel_size=3, stride=1)
优点:平滑特征,保留区域整体信息,对噪声容忍度更高。
2.3 自适应池化(输出尺寸固定)
nn.AdaptiveMaxPool2d
/ nn.AdaptiveAvgPool2d
无需手动设置 stride
和 padding
,直接指定输出尺寸:
# 无论输入多大,输出固定为(7,7)的最大池化
adaptive_max = nn.AdaptiveMaxPool2d(output_size=(7,7))
2.4 一维 / 三维池化
- 一维(如文本、音频):
nn.MaxPool1d
、nn.AvgPool1d
- 三维(如视频):
nn.MaxPool3d
、nn.AvgPool3d
用法与二维类似,只是处理的维度不同。
3. 多通道池化计算
在处理多通道输入数据时,池化层对每个输入通道分别池化,并不是将各个通道的输入相加,这表示池化层的输入输出的通道数是相等的。其核心目标是保留每个通道的局部特征,同时降低特征图的空间尺寸。
假设输入为 3×5×53×5×5(3通道,5×5特征图),使用 2×22×2 最大池化,步长为2:
每个通道独立进行池化,输出尺寸为 3×2×23×2×2。
四、CNN的总体框架
1. 典型结构
- 输入 -> 卷积层 + 激活函数 -> 池化层 -> 全连接层 -> 输出
- 卷积层:提取局部特征。
- 激活函数:引入非线性(如ReLU)。
- 池化层:降维并增强鲁棒性。
- 全连接层:将特征映射到最终类别。
特征图变化:
2. 示例模型结构
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
self.conv1 = nn.Conv2d(3, 16, 3, 1, 1)
self.pool = nn.MaxPool2d(2, 2)
self.conv2 = nn.Conv2d(16, 32, 3, 1, 1)
self.fc1 = nn.Linear(32 * 8 * 8, 128)
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
x = torch.relu(self.conv1(x))
x = self.pool(x)
x = torch.relu(self.conv2(x))
x = self.pool(x)
x = x.view(-1, 32 * 8 * 8) # 展平
x = torch.relu(self.fc1(x))
x = self.fc2(x)
return x