SilverIce Toolbox
Back to course

Stage 4 / Chapter 16

第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) + 1
  • n: 输入尺寸
  • f: 滤波器尺寸
  • p: padding
  • s: stride

Padding 的作用

Padding公式输出尺寸用途
Valid (p=0)(n - f) / s + 1缩小无需保持尺寸
Samep = (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 = 448

English 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 PoolingAverage 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

  1. 卷积计算:给定 4×4 输入和 2×2 滤波器,手动计算 Valid/Same padding、stride=1/2 时的输出。
  1. 感受野:计算 3 层 CNN(每层 3×3 conv + 2×2 maxpool)的感受野大小。输入中多大的区域会影响输出的一个像素?
  1. 参数量对比:对比 VGG-16(138M 参数)和 AlexNet(60M 参数)的层结构,分析为什么 VGG 更深但参数量不是指数增长。
  1. 空洞卷积:实现 Dilated Convolution(空洞率=2),对比标准卷积的感受野差异。
  1. 可分离卷积:实现 Depthwise Separable Convolution(MobileNet 核心),对比与普通卷积的参数和计算量差异。