3、深度学习基础回顾(下):卷积神经网络(CNN)原理、池化层、全连接层、感受野与特征图

好,咱们接着聊。上一节我们把神经网络的“骨架”搭好了,知道了数据怎么往前传、梯度怎么往回传。但说实话,如果只用全连接层去处理图像,那效率太低了。一张 256x256 的彩色图片,拉成一维向量就是 196,608 个像素点。第一层要是 1000 个神经元,光这一层的参数量就接近 2 亿。这谁扛得住?

所以,计算机视觉领域必须要有自己的“专用武器”——卷积神经网络(CNN)。我当年刚接触 CV 时,第一感觉就是:这玩意儿简直是给图像量身定做的。

核心思想:CNN 通过局部连接和权值共享,大幅降低了参数量,同时保留了图像的空间结构信息。说白了,它不再把图像看成是一堆孤立的像素点,而是看成有局部纹理、边缘、形状的“小区域”。

3.1 卷积层:图像特征的“扫描仪”

卷积层在做什么?你可以把它想象成一把小手电筒,在图像上滑动着照。每次只照一个局部小窗口(这个窗口就叫卷积核或滤波器),然后计算这个小窗口里的像素值和卷积核的“匹配程度”。

举个例子,一个 3x3 的卷积核,在 5x5 的输入上滑动,步长为 1,就会生成一个 3x3 的特征图。这个特征图上的每个值,都代表了原图某个局部区域与卷积核的响应强度。

# 一个简单的 2D 卷积操作(伪代码)
import numpy as np

input_image = np.random.randn(5, 5)  # 假设输入是 5x5
kernel = np.array([[1, 0, -1],
                   [1, 0, -1],
                   [1, 0, -1]])      # 垂直边缘检测核

output_feature_map = np.zeros((3, 3))
for i in range(3):
    for j in range(3):
        # 提取局部区域
        region = input_image[i:i+3, j:j+3]
        # 点积运算
        output_feature_map[i, j] = np.sum(region * kernel)

print(output_feature_map)

你看,代码其实不复杂。但这里有几个关键参数,我建议你记牢了:

参数 含义 我的经验
卷积核大小 通常 3x3 或 5x5 YOLOv9 里几乎全是 3x3,效率高、堆叠效果好
步长 卷积核每次滑动的像素数 步长=2 可以快速降采样,但容易丢失细节
填充 在输入边缘补 0,控制输出尺寸 我习惯用 same 填充,保持特征图大小不变
通道数 卷积核的个数,决定输出特征图的深度 越深层的通道数越多,YOLOv9 的 backbone 通道数从 64 涨到 512

我的小技巧:刚开始调参时,别纠结步长和填充的数学公式。你只需要记住:输出尺寸 = (输入尺寸 - 卷积核大小 + 2 * 填充) / 步长 + 1。算不明白?直接写代码打印 shape 看看,比手算快多了。

3.2 池化层:降维打击,保留精华

卷积层提取完特征后,特征图往往还很大。这时候就需要池化层出场了。它的作用很简单:在局部区域内取一个代表值,把特征图“压缩”一下。

最常见的两种:

  • 最大池化:取窗口内的最大值。我特别喜欢用它,因为它能保留最强烈的特征响应,比如边缘、角点。
  • 平均池化:取窗口内的平均值。它更平滑,适合在网络的最后几层使用。

举个例子,一个 2x2 的最大池化,步长为 2,能把 4x4 的特征图直接压缩成 2x2。参数量?零。计算量?几乎可以忽略。这就是池化层的魅力——免费的下采样。

我曾经踩过的坑:有一回做小目标检测,用了太多池化层,结果小目标的特征被“池”没了。后来我改用步长为 2 的卷积来做下采样,效果好了不少。记住:池化层会丢失位置信息,对检测任务要慎用。

3.3 全连接层:特征整合器

卷积和池化把图像变成了高维特征图,但最终我们要输出类别概率或边界框坐标。这时候就需要全连接层来“收尾”。

全连接层会把前面展平的特征向量,通过矩阵乘法映射到输出空间。在 YOLOv9 里,全连接层用得不多,因为检测头通常用卷积来实现。但理解它的原理,对理解分类网络(比如 ResNet)很有帮助。

# 全连接层的前向传播
import torch.nn as nn

fc_layer = nn.Linear(in_features=512, out_features=10)  # 512维 -> 10类
output = fc_layer(feature_vector)  # 输出 logits

说白了,全连接层就是“把所有信息揉在一起,然后做决策”。但它的缺点也很明显:参数量巨大。一个 4096 到 1000 的全连接层,就有 400 万个参数。所以现代检测网络都在尽量用卷积替代全连接。

3.4 感受野:神经元在看多大范围?

这个概念特别重要,尤其是做目标检测时。感受野指的是特征图上的一个点,对应到输入图像上的区域大小。

你想想看,如果感受野太小,网络只能看到局部纹理,认不出大物体。如果感受野太大,又可能忽略细节。YOLOv9 的设计里,就特别注重感受野的平衡。

计算感受野有个递推公式:

r_out = r_in + (kernel_size - 1) * stride_in

其中 r_in 是上一层的感受野,stride_in 是之前所有步长的乘积。举个例子,两层 3x3 卷积(步长=1),感受野是 5x5。三层就是 7x7。所以堆叠小卷积核,可以高效扩大感受野。

关键结论:YOLOv9 的 backbone 通过堆叠 3x3 卷积和 ELAN 结构,让深层特征图拥有足够大的感受野,既能看清大目标,又不丢失小目标的细节。这就是它检测精度高的原因之一。

3.5 特征图:网络眼中的世界

特征图是 CNN 的“中间产物”。每一层卷积都会生成一组特征图,它们代表了网络从不同角度对图像的理解。

  • 浅层特征图:关注边缘、颜色、纹理。比如一个垂直边缘检测核,会在特征图上“点亮”所有垂直边缘的位置。
  • 中层特征图:开始组合出形状、部件。比如车轮、车窗、车灯。
  • 深层特征图:抽象出完整的物体概念。比如“这是一辆车”。

YOLOv9 的一个创新点,就是通过 PGI(可编程梯度信息)机制,让浅层和深层的特征图能更好地协同工作。浅层提供精细的位置信息,深层提供丰富的语义信息,两者结合,检测效果自然更好。

CNN 特征提取流程与感受野变化 输入图像 224x224x3 Conv1 112x112x64 感受野: 3x3 Pool1 56x56x64 感受野: 4x4 Conv2 56x56x128 感受野: 6x6 深层特征 28x28x256 感受野: 14x14 关键观察 1. 随着网络加深,特征图尺寸变小(224→112→56→28),通道数变多(3→64→128→256)。 2. 感受野逐渐增大(3→4→6→14),深层神经元能看到更大的输入区域。 3. YOLOv9 利用多尺度特征图(浅层+深层),兼顾小目标定位和大目标识别。

3.6 本章小结:CNN 的核心三板斧

回顾一下,CNN 能成为 CV 领域的基石,靠的就是这三板斧:

  1. 卷积层:局部连接 + 权值共享,高效提取空间特征。
  2. 池化层:降采样,减少计算量,增强平移不变性。
  3. 全连接层:特征整合,输出最终结果(在检测网络里逐渐被卷积替代)。