第16章:CNN 基础与卷积操作 | Chapter 16: CNN Basics & Convolution
阶段定位 | Stage: 第四阶段 — ML 策略与 CNN 预计学时 | Duration: 5~6 小时
---
学习目标 | Learning Objectives
中文:
- 理解卷积操作的数学本质与参数共享机制
- 掌握 Padding 和 Stride 对输出尺寸的影响
- 理解通道维度的意义与多通道卷积的计算过程
- 掌握池化层的作用与 Max/Avg Pooling 的区别
- 能在 NumPy 中实现完整的卷积前向传播
English:
- Understand the mathematical essence of convolution and parameter sharing
- Master how Padding and Stride affect output dimensions
- Understand channel dimensions and multi-channel convolution computation
- Master pooling layer roles and Max vs Avg Pooling differences
- Implement complete convolution forward pass in NumPy
---
16.1 为什么需要 CNN | Why CNN?
中文解释
全连接网络的问题
对于 1000×1000 像素的图像:
- 输入维度 = 1,000,000
- 第一层 1000 个神经元 → 权重 = 10⁹
- 参数爆炸!
CNN 的三大优势
| 特性 | 含义 | 效果 |
|---|---|---|
| 参数共享 | 同一个滤波器扫完整张图 | 大幅减少参数量 |
| 稀疏连接 | 每个输出只连局部区域 | 捕捉局部特征 |
| 平移等变 | 物体移动,特征跟着移动 | 位置无关性 |
类比
- 全连接 = 每个像素都配一个专属侦探
- CNN = 一个侦探拿着放大镜扫描整张照片,发现相同模式
English Explanation
Fully connected problem: 1000×1000 image → 10⁹ parameters
CNN advantages:
- Parameter sharing: one filter scans entire image
- Sparse connectivity: local receptive fields
- Translation equivariance: features move with objects
---
16.2 卷积操作详解 | Convolution Operation
中文解释
数学定义
滤波器(卷积核)在图像上滑动,逐元素相乘再求和:
output[i,j] = Σ_m Σ_n filter[m,n] * input[i+m, j+n]输出尺寸公式
output_size = floor((n + 2p - f) / s) + 1n: 输入尺寸f: 滤波器尺寸p: paddings: stride
Padding 的作用
| Padding | 公式 | 输出尺寸 | 用途 |
|---|---|---|---|
| Valid (p=0) | (n - f) / s + 1 | 缩小 | 无需保持尺寸 |
| Same | p = (f-1)/2 | = 输入尺寸 | 常用,保持空间分辨率 |
Stride 的作用
- stride=1:精细扫描,输出尺寸大
- stride=2:下采样,输出尺寸减半
English Explanation
Output size: floor((n + 2p - f) / s) + 1
Padding:
- Valid: no padding, output shrinks
- Same:
p = (f-1)/2, output = input size
---
16.3 多通道卷积 | Multi-Channel Convolution
中文解释
单通道(灰度图)
- 输入:(H, W, 1)
- 滤波器:(f, f, 1)
- 输出:(H', W', 1)
多通道(RGB图)
- 输入:(H, W, 3)
- 滤波器:(f, f, 3) — 每个通道有独立的权重
- 输出:(H', W', 1) — 所有通道求和后得到单通道输出
多个滤波器
- 输入:(H, W, 3)
- 8 个滤波器,每个 (f, f, 3)
- 输出:(H', W', 8) — 每个滤波器产生一个输出通道
参数计算
参数 = f × f × c_in × c_out + c_out (权重 + 偏置)例如:3×3 滤波器,输入 3 通道,输出 16 通道:
参数 = 3 × 3 × 3 × 16 + 16 = 448English Explanation
Multi-channel:
- Input: (H, W, c_in)
- Filter: (f, f, c_in)
- Output: (H', W', 1) per filter
- With c_out filters: output (H', W', c_out)
Parameters: f × f × c_in × c_out + c_out
---
16.4 池化层 | Pooling Layers
中文解释
Max Pooling
在局部窗口中取最大值:
[1, 3, 2, 1]
[4, 5, 1, 2] → MaxPool(2×2) → [5, 6]
[2, 3, 6, 1] [7, 4]
[1, 7, 2, 4]作用:保留最显著特征,提供微小平移不变性。
Average Pooling
在局部窗口中取平均值:
→ AvgPool(2×2) → [3.25, 2.5]
[3.25, 3.25]作用:保留整体信息,平滑特征图。
对比
| 特性 | Max Pooling | Average Pooling |
|---|---|---|
| 保留 | 最显著特征 | 平均信息 |
| 效果 | 更强特征选择 | 更平滑 |
| 现代使用 | 默认选择 | 很少用(除最后一层) |
English Explanation
Max Pooling: keeps most salient features, provides slight translation invariance Average Pooling: keeps overall information, smoother Modern default: Max Pooling
---
16.5 完整实现:NumPy 卷积
代码案例
python
import numpy as np
np.random.seed(1)
def conv_single_step(a_slice_prev, W, b):
"""单步卷积:滤波器与局部区域逐元素乘后求和"""
return np.sum(a_slice_prev * W) + float(b)
def conv_forward(A_prev, W, b, hparameters):
"""
A_prev: (m, n_H_prev, n_W_prev, n_C_prev)
W: (f, f, n_C_prev, n_C)
b: (1, 1, 1, n_C)
"""
(m, n_H_prev, n_W_prev, n_C_prev) = A_prev.shape
(f, f, n_C_prev, n_C) = W.shape
stride = hparameters['stride']
pad = hparameters['pad']
n_H = int((n_H_prev + 2*pad - f) / stride) + 1
n_W = int((n_W_prev + 2*pad - f) / stride) + 1
# Padding
A_prev_pad = np.pad(A_prev,
((0,0), (pad,pad), (pad,pad), (0,0)),
mode='constant', constant_values=0)
Z = np.zeros((m, n_H, n_W, n_C))
for i in range(m):
for h in range(n_H):
for w in range(n_W):
for c in range(n_C):
v_start = h * stride
v_end = v_start + f
h_start = w * stride
h_end = h_start + f
a_slice = A_prev_pad[i, v_start:v_end, h_start:h_end, :]
Z[i, h, w, c] = conv_single_step(a_slice, W[:,:,:,c], b[:,:,:,c])
return Z
# ========== 测试 ==========
print("=" * 50)
print("卷积操作测试")
print("=" * 50)
A_prev = np.random.randn(2, 5, 5, 3) # 2张5x5 RGB图
W = np.random.randn(3, 3, 3, 8) # 8个3x3滤波器
b = np.random.randn(1, 1, 1, 8)
hparameters = {"stride": 1, "pad": 1}
Z = conv_forward(A_prev, W, b, hparameters)
print(f"输入: {A_prev.shape}")
print(f"滤波器: {W.shape}")
print(f"Padding: {hparameters['pad']}, Stride: {hparameters['stride']}")
print(f"\n输出尺寸计算:")
print(f" n_H = ({A_prev.shape[1]} + 2*{hparameters['pad']} - {W.shape[0]}) / {hparameters['stride']} + 1 = {Z.shape[1]}")
print(f" n_W = ({A_prev.shape[2]} + 2*{hparameters['pad']} - {W.shape[1]}) / {hparameters['stride']} + 1 = {Z.shape[2]}")
print(f" n_C = {W.shape[3]} (滤波器数量)")
print(f"\n输出: {Z.shape}")
# 参数统计
n_params = np.prod(W.shape) + np.prod(b.shape)
print(f"\n参数量: {n_params}")
print(f"对比全连接: 输入 5×5×3=75, 输出 5×5×8=200 → 全连接需要 75×200=15000 参数")
print(f"卷积仅需 {n_params} 参数 —— 减少了 {15000/n_params:.1f} 倍!")输出:
==================================================
卷积操作测试
==================================================
输入: (2, 5, 5, 3)
滤波器: (3, 3, 3, 8)
Padding: 1, Stride: 1
输出尺寸计算:
n_H = (5 + 2*1 - 3) / 1 + 1 = 5
n_W = (5 + 2*1 - 3) / 1 + 1 = 5
n_C = 8 (滤波器数量)
输出: (2, 5, 5, 8)
参数量: 224
对比全连接: 输入 5×5×3=75, 输出 5×5×8=200 → 全连接需要 75×200=15000 参数
卷积仅需 224 参数 —— 减少了 67.0 倍!---
本章总结 | Chapter Summary
中文:
- CNN 三大优势:参数共享、稀疏连接、平移等变
- 卷积 = 滤波器滑动,逐元素相乘再求和
- 输出尺寸 = floor((n + 2p - f) / s) + 1
- Padding 保持尺寸,Stride 控制下采样
- 多通道:每个滤波器跨所有输入通道,输出一个通道
- 池化层降维 + 提供平移不变性,Max Pooling 是默认选择
- 卷积参数量远小于全连接
English:
- CNN advantages: parameter sharing, sparse connectivity, translation equivariance
- Convolution = filter slides, element-wise multiply then sum
- Output size = floor((n + 2p - f) / s) + 1
- Padding preserves size, stride controls downsampling
- Multi-channel: each filter spans all input channels
- Pooling reduces dimensions + translation invariance
- Convolution has far fewer parameters than fully connected
---
课后练习 | Homework
- 卷积计算:给定 4×4 输入和 2×2 滤波器,手动计算 Valid/Same padding、stride=1/2 时的输出。
- 感受野:计算 3 层 CNN(每层 3×3 conv + 2×2 maxpool)的感受野大小。输入中多大的区域会影响输出的一个像素?
- 参数量对比:对比 VGG-16(138M 参数)和 AlexNet(60M 参数)的层结构,分析为什么 VGG 更深但参数量不是指数增长。
- 空洞卷积:实现 Dilated Convolution(空洞率=2),对比标准卷积的感受野差异。
- 可分离卷积:实现 Depthwise Separable Convolution(MobileNet 核心),对比与普通卷积的参数和计算量差异。