跳转至

15.4   卷积神经网络

小率和均哥去照片店挑旅行照片。小率发现,自己不是一眼看完整张图,而是会先扫局部:这块像天空,那块像人脸,边缘是不是清楚,纹理是不是重复。均哥把一个透明小方框放在照片上,一格一格移动:“这就是卷积神经网络(Convolutional Neural Network, CNN)的直觉。”

CNN 特别适合图像,因为图像的局部邻近关系很重要:旁边的像素通常比远处的像素更相关。

均哥和小率在照片店理解 CNN 滤波器

15.4.1   卷积核像会滑动的小观察窗

卷积核(Kernel / Filter)是一小块权重矩阵。它在图像上滑动,每到一个位置,就和局部像素做加权求和。

二维卷积可以写成:

\[ S(i,j) = \sum_m \sum_n I(i+m, j+n)K(m,n) \]

其中 \(I\) 是输入图像,\(K\) 是卷积核,\(S(i,j)\) 是当前位置得到的特征值。

一个边缘检测核可能长这样:

\[ \begin{bmatrix} -1 & 0 & 1\\ -1 & 0 & 1\\ -1 & 0 & 1 \end{bmatrix} \]

它会对左右亮度变化特别敏感。

15.4.2   参数共享让图像模型更省

如果把一张 \(224 \times 224\) 的图片直接接到全连接层,参数会非常多。CNN 的妙处是参数共享:同一个卷积核在整张图上反复使用。

这带来两个好处:

  • 局部连接:先看小区域,再组合成大结构。
  • 平移共享:同一种边缘或纹理,出现在左上角和右下角都能被识别。

池化(Pooling)常用于压缩空间尺寸,例如最大池化会保留局部区域里的最大响应,让模型对小位移更稳。

15.4.3   用 PyTorch 看一层卷积的形状

import torch
import torch.nn as nn

image_batch = torch.randn(8, 3, 32, 32)  # batch, channel, height, width

conv = nn.Conv2d(in_channels=3, out_channels=16, kernel_size=3, padding=1)
features = conv(image_batch)

print(features.shape)  # torch.Size([8, 16, 32, 32])

padding=1 让 3×3 卷积后空间尺寸仍保持 32×32;out_channels=16 表示学 16 种滤波器。

小率的笔记本

CNN 把“看局部、共享滤波器、逐层组合”写成了网络结构。浅层常像边缘和纹理检测器,深层会组合出物体局部乃至整体语义。