查看全课大纲(第 35 / 93 节)
- 1.计算机视觉概述
- 2.计算机视觉应用场景
- 3.困难与挑战
- 4.开源库介绍
- 5.图像显示与存储
- 6.CLAHE
- 7.腐蚀膨胀与开闭运算
- 8.滤波与边缘填充
- 9.各种滤波
- 10.图像金字塔
- 11.傅里叶变换
- 12.短时傅里叶变换与小波变换
- 13.颜色特征与颜色直方图
- 14.几何特征_边缘
- 15.几何特征-角点与斑点
- 16.局部特征-SIFT特征描述子
- 17.局部特征-SURF特征描述子
- 18.局部特征-ORB特征描述子
- 19.其他特征描述子
- 20.传统图像分割技术
- 21.GraphCut
- 22.GrabCut
- 23.人脸检测的传统方法
- 24.行人检测的传统方法HOG+SVM
- 25.行人检测DPM
- 26.人工神经网络的架构
- 27.目标函数与梯度下降
- 28.误差反向传播
- 29.可手算的神经网络
- 30.改进目标函数与克服梯度消散
- 31.神经网络之传统神经网络与深度网络的差异
- 32.各种梯度下降算法
- 33.如何选择合适的梯度下降算法
- 34.避免过适应
- 35.CNN的架构
- 36.CNN的误差反向传播_卷积层
- 37.CNN的误差反向传播_池化层
- 38.分类所用的数据集
- 39.Alexnet详解
- 40.VGG详解
- 41.GoogLeNet_v1
- 42.BatchNormalization
- 43.GoogLeNet_v3v4
- 44.ResNet
- 45.ResNeXt
- 46.CNN设计准则
- 47.图像检索与推土机距离
- 48.基于颜色相似性
- 49.基于形状相似性
- 50.基于纹理相似性
- 51.基于局部特征相似性
- 52.DL的二值哈希编码
- 53.高维空间中检索KDTree
- 54.高维空间中检索LSH
- 55.目标识别任务综述
- 56.RCNN
- 57.SPP-Net
- 58.Fast R-CNN
- 59.Faster R-CNN
- 60.R-CNN系列模型回顾
- 61.R-FCN的设计思路
- 62.R-FCN的实现
- 63.YOLOv1
- 64.YOLOv2_9000
- 65.YOLOv3
- 66.图像分割应用场景与数据集
- 67.上采样的实现方式
- 68.FCN网络架构的由来
- 69.FCN构建细节
- 70.DeepLabv1
- 71.CRF
- 72.DeepLabv2
- 73.DeepLabv3
- 74.特定的医学影像分割任务
- 75.U-Net
- 76.3D U-Net
- 77.V-Net
- 78.DenseNet
- 79.病理切片分析任务及数据集
- 80.病理切片分析
- 81.图说任务及其传统处理方法
- 82.深度语言模型与RNN
- 83.LSTM及其变种
- 84.NIC模型
- 85.SAT模型
- 86.图说的性能指标
- 87.判别模型与生成模型
- 88.KL散度与JS散度
- 89.VAE
- 90.GAN的基本原理
- 91.DCGAN与CGAN
- 92.Wasserstein GAN
- 93.SRGAN
CNN的架构
卷积神经网络的整体架构
小象实战讲义 · 基于深度学习的计算机视觉
在掌握了深度学习的基本概念和优化方法后,我们终于要进入计算机视觉的核心——卷积神经网络(CNN)。本节将为你系统拆解CNN的经典架构,从输入一张图片开始,一步步解析卷积层、激活函数、池化层和全连接层是如何协同工作,最终完成图像识别任务的。学完本节,你将能清晰地描述CNN的完整工作流程,并理解其核心组件的作用。
💡 核心导读
- CNN的三大支柱:理解卷积层、池化层和全连接层在架构中的角色与分工。
- 从3D张量到特征图:掌握图像作为多通道张量输入,以及卷积核如何通过滑动扫描提取局部特征。
- 激活函数的进化:从Sigmoid到ReLU,理解非线性激活如何缓解梯度消失问题,成为深度网络优化的关键。
- 降维与特征融合:剖析池化层(尤其是最大池化)如何在不增加参数的情况下实现降维和特征鲁棒性。
- 从特征到决策:了解全连接层与Softmax层如何将高维特征映射为最终的分类概率。
卷积神经网络的基本组件
卷积神经网络(Convolutional Neural Network, CNN)是专门为处理图像这类网格状数据而设计的深度学习模型。其成功的关键在于它巧妙地利用了图像的空间局部性和平移等变性(再经池化获得一定的平移不变性)。一个典型的CNN由以下几个基本组件构成:
- 卷积层 (Convolutional Layer):这是CNN的核心。其作用是对原始图像或上一层输出的特征图进行卷积加工,以提取局部特征。卷积层内部包含需要学习的权重参数(即卷积核的值),并且通常紧随一个非线性激活函数。
- 激活函数 (Activation Function):为网络引入非线性,使其能够学习复杂的模式。早期常用Sigmoid函数,而现在最主流的是修正线性单元 (ReLU)。
- 池化层 (Pooling Layer):通常接在卷积层之后,用于降维和特征融合。最常用的是最大池化 (Max Pooling),在某些特定场景下也会使用平均池化 (Average Pooling)。
- 全连接层 (Fully-Connected Layer):在网络的末端,将经过多次卷积和池化后得到的二维特征图“展平”成一维向量,并进行全局的综合与判别。其层间神经元两两相连,结构与传统神经网络相同。
这些组件按照“卷积 -> 激活 -> 池化”的顺序反复堆叠,最后连接全连接层,构成了CNN的典型架构。例如,经典的AlexNet就包含了5个卷积层、数个池化层以及3个全连接层。
卷积层:特征提取的引擎
图像的张量表示
图像进入CNN时,本身就是一个三维张量(Tensor)。除了我们熟知的长和宽两个空间维度,还有一个通道(Channel) 维度。
- 彩色图像:通常有3个通道,分别对应红(R)、绿(G)、蓝(B) 三原色。因此输入是一个
[高度, 宽度, 3]的张量。 - 灰度图像:只有1个通道,输入是
[高度, 宽度, 1]的张量。
在使用TensorFlow或PyTorch等框架编程时,我们操作的就是这样的三维张量。
卷积操作详解
卷积层的核心操作是使用一个称为卷积核(Kernel) 或滤波器(Filter) 的小窗口,在输入张量上进行滑动扫描。
import numpy as np
# 模拟一个简单的3x3单通道输入图像
input_2d = np.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]], dtype=np.float32)
# 定义一个2x2的卷积核
kernel = np.array([[1, 0],
[0, -1]], dtype=np.float32)
# 手动实现步长为1,无填充的卷积操作
output_height = input_2d.shape[0] - kernel.shape[0] + 1
output_width = input_2d.shape[1] - kernel.shape[1] + 1
output = np.zeros((output_height, output_width))
for i in range(output_height):
for j in range(output_width):
region = input_2d[i:i+kernel.shape[0], j:j+kernel.shape[1]]
output[i, j] = np.sum(region * kernel) # 对应位置相乘后求和
print("输入图像:")
print(input_2d)
print("\n卷积核:")
print(kernel)
print("\n卷积输出(未加激活):")
print(output)输入图像:
[[1. 2. 3.]
[4. 5. 6.]
[7. 8. 9.]]
卷积核:
[[ 1. 0.]
[ 0. -1.]]
卷积输出(未加激活):
[[-4. -4.]
[-4. -4.]]关键概念解析:
- 滑动扫描:卷积核以一定的步长(Stride) 在输入上移动。步长为1时每次移动1个像素;步长为2时每次移动2个像素,这会导致输出特征图尺寸缩小。
- 多卷积核与输出通道:每一层卷积层都包含多个卷积核。每个卷积核独立地在输入上进行卷积操作,产生一个二维的特征图(Feature Map)。所有卷积核产生的特征图堆叠起来,就构成了该卷积层的输出,其通道数等于卷积核的数量。
- 例如,若输入是
32x32x3的图像,使用6个尺寸为5x5x3的卷积核进行卷积(步长1,无填充),将得到28x28x6的输出特征图。这里卷积核的第三个维度3必须与输入通道数一致。
- 例如,若输入是
- 局部特征提取:每个卷积核本质上是一个特征检测器。例如,一个对角线为1的卷积核,会对图像中对角线模式明显的区域产生高响应(输出值大)。卷积核的具体模式(是检测边缘、角点还是纹理)不是人为设定的,而是在训练过程中通过误差反向传播自动学习得到的。
- 权重共享:同一个卷积核在整个输入图像上滑动使用,其参数(权重)是共享的。这极大地减少了参数量,并赋予了模型平移等变性(输入平移,输出特征同步平移);再配合池化,才能获得一定的平移不变性。
感受野(Receptive Field)
卷积核每一次只“看”输入上的一个小窗口,但在多层堆叠之后,输出特征图上的一个点,实际上间接“看过”了原图上更大的一片区域——这片区域就是该点的感受野。
以连续两层 3x3 卷积(步长1、无填充)为例:第一层输出上的每个点对应原图 3x3 的区域;第二层再做一次 3x3 卷积时,它会覆盖第一层输出的 3x3 个点,而这 9 个点各自又对应原图的 3x3 区域,合起来第二层输出上的一个点就对应原图 5x5 的范围。层数越深,感受野越大,网络能捕捉的语义范围也就越广——这也是深层 CNN 能从边缘、纹理逐步抽象到物体部件乃至整体目标的原因。
反过来看,如果感受野已经覆盖了整张图,再继续堆叠卷积层,对扩大感知范围就没有额外收益了。因此设计网络时,感受野大小需要与目标任务中目标的空间尺度相匹配。
卷积层的超参数与尺寸计算
卷积层的输出尺寸由以下几个超参数共同决定:
- 核尺寸(Kernel Size):如
3x3,5x5,特殊的1x1卷积用于跨通道信息融合。 - 步长(Stride):滑动步长。步长大于1具有降维作用。
- 零填充(Zero Padding):在输入图像边缘补0,以控制输出尺寸,防止边缘信息丢失过快。
- 核数量(Number of Kernels):决定输出特征图的通道数。
输出尺寸的计算公式如下(分别计算高度和宽度,公式相同): 输出尺寸 = (输入尺寸 - 核尺寸 + 2 × 填充) / 步长 + 1
例如,输入为 32x32,使用 5x5 卷积核,步长为1,无填充(padding=0): 输出尺寸 = (32 - 5 + 2*0) / 1 + 1 = 28
激活函数:引入非线性
卷积操作本质上是线性的加权求和。为了让网络能够拟合复杂的非线性函数,必须在卷积后施加非线性激活函数。
- Sigmoid:早期常用的S型函数,将输入压缩到(0,1)之间。但它有两个主要缺点:
- 梯度消失:当输入值很大或很小时,其导数接近0,在深层网络中反向传播的梯度会急剧缩小,导致底层权重难以更新。
- 计算量较大:涉及指数运算。
- ReLU (Rectified Linear Unit):当前最主流的激活函数。公式为
f(x) = max(0, x)。- 优点:
- 计算高效:只有比较和取0操作。
- 缓解梯度消失:在正区间导数为1,梯度可以无衰减地传播。
- 产生稀疏性:使部分神经元输出为0,让网络变得稀疏,可能更有利于特征选择。
- 生物学解释:模拟了神经元“激活”或“抑制”的状态。
- 优点:
在CNN中,标准的流程是:先进行卷积运算,然后立即对结果施加ReLU激活。如果卷积步长大于1,则先完成降维的卷积操作,再对降维后的特征图进行激活。
池化层:降维与特征融合
池化层通常紧跟在卷积-激活层之后,其主要作用是:
- 降维(下采样):减少特征图的空间尺寸(长和宽),从而降低计算量和参数量。
- 特征融合与增强鲁棒性:聚合局部区域的特征,使特征对小的平移、旋转等形变更加鲁棒。
- 无参数需要学习:池化操作是确定性的,没有需要训练的参数。
最大池化(Max Pooling) 是最常用的池化方式。它在一个局部区域(如2x2窗口)内取最大值作为该区域的代表输出。
import numpy as np
# 模拟一个4x4的单通道特征图,模拟ReLU激活后的输出(假设无负值)
feature_map = np.array([[1, 1, 2, 4],
[5, 6, 7, 8],
[3, 2, 1, 0],
[1, 2, 3, 4]], dtype=np.float32)
# 用分块取最大值的方式实现2x2最大池化,步长为2
pool_size = (2, 2)
stride = 2
output_h = feature_map.shape[0] // pool_size[0]
output_w = feature_map.shape[1] // pool_size[1]
max_pool_output = np.zeros((output_h, output_w))
for i in range(0, feature_map.shape[0], stride):
for j in range(0, feature_map.shape[1], stride):
region = feature_map[i:i+pool_size[0], j:j+pool_size[1]]
if region.shape == (pool_size[0], pool_size[1]): # 确保区域完整
max_pool_output[i//stride, j//stride] = np.max(region)
print("ReLU激活后的特征图 (4x4):")
print(feature_map)
print("\n经过2x2最大池化(步长2)后的输出 (2x2):")
print(max_pool_output)ReLU激活后的特征图 (4x4):
[[1. 1. 2. 4.]
[5. 6. 7. 8.]
[3. 2. 1. 0.]
[1. 2. 3. 4.]]
经过2x2最大池化(步长2)后的输出 (2x2):
[[6. 8.]
[3. 4.]]池化层同样有尺寸和步长两个超参数。常见的设置是2x2池化窗口配合步长2,这样可以将特征图尺寸减半,而通道数保持不变。例如,224x224x64的特征图经过这样的池化后,变为112x112x64。
平均池化(Average Pooling) 取局部区域的平均值作为输出,用于降维。它的特殊形式全局平均池化(Global Average Pooling) 把池化窗口设为整张特征图,每个通道只输出一个数,因此在 GoogLeNet 等网络中被用来替代全连接层,大幅减少参数量。
全连接层与Softmax:从特征到分类
经过多次“卷积-激活-池化”的循环后,我们得到了高度抽象但空间尺寸较小的特征图。为了完成分类任务,需要将这些特征转换为一组类别分数。
- 全连接层:首先将最后的特征图展平(Flatten) 成一个长的一维向量。这个向量作为输入,送入一个或多个全连接层。全连接层的作用是综合所有局部特征,进行全局的推理和判别。
- Softmax层:通常作为网络的最后一层,接在最终的全连接层之后。它将全连接层输出的实数向量(称为logits)转换为一个概率分布。
- 公式:对于第
i个类别的输出分数z_i,其Softmax概率为σ(z)_i = exp(z_i) / Σ_j exp(z_j)。 - 作用:
- 突出最大值:通过指数运算放大较大值的相对差距。
- 归一化为概率:将所有输出值压缩到(0,1)之间,且和为1,符合概率解释。
- 可微性:整个函数是可微的,便于使用梯度下降法优化。
- 例如,在ImageNet1000分类任务中,最后一个全连接层输出1000个值,经过Softmax后得到1000个类别的预测概率。
- 公式:对于第
📝 动手练一练
- 概念辨析:请简述卷积层中的“步长(Stride)”和“填充(Padding)”分别有什么作用?如果希望卷积层不改变输入特征图的空间尺寸(高和宽),可以如何设置这些参数?(假设使用
3x3卷积核)
👉 点击查看参考答案
步长(Stride) 决定了卷积核在输入上滑动的间隔。步长越大,输出特征图的尺寸越小,具有降维作用,但可能丢失一些空间信息。
填充(Padding) 是在输入特征图边缘补0(或其他值),主要作用有两个:一是控制输出尺寸,防止因卷积核尺寸和步长导致尺寸收缩过快;二是保留边缘信息,让卷积核能更公平地处理图像边缘的像素。
要使3x3卷积不改变空间尺寸,一个常见的设置是:步长(Stride)= 1,填充(Padding)= 1。根据尺寸计算公式:输出尺寸 = (输入尺寸 - 3 + 2*1) / 1 + 1 = 输入尺寸。
- 手算练习:假设有一个单通道的
5x5输入矩阵I,和一个2x2的卷积核K,均无填充(padding=0),步长(stride)为1。I = [[1,0,1,2,1], [0,2,1,0,1], [1,1,0,2,0], [2,2,1,1,0], [2,0,1,2,1]]K = [[1,0], [0,1]]请手动计算卷积输出特征图左上角第一个值(即卷积核覆盖I的左上角2x2区域时的结果)。
👉 点击查看参考答案
卷积操作是对应位置相乘后求和。 卷积核覆盖的输入区域为 [[1,0], [0,2]]。 计算:(1*1) + (0*0) + (0*0) + (2*1) = 1 + 0 + 0 + 2 = 3。 因此,输出特征图左上角第一个值是 3。
本章小结
本节我们系统构建了卷积神经网络(CNN)的整体架构蓝图。CNN通过卷积层的局部感受野和权重共享高效提取图像特征,经由ReLU激活函数引入非线性并克服梯度消失,利用池化层进行降维和增强特征鲁棒性,最后通过全连接层和Softmax层完成从特征到类别概率的映射。这种“卷积->激活->池化”的模块化堆叠结构,是深度学习在计算机视觉领域取得突破性进展的基石。
📋 行动清单
- 画出数据流图:在白板上画出一个简化CNN的数据流,标注从
[H,W,3]输入到Softmax概率输出的尺寸变化。 - 复现计算过程:使用NumPy手动实现一个包含卷积、ReLU、最大池化的小型前向传播过程,验证尺寸计算公式。
- 对比思考:思考全连接层和卷积层在参数数量和连接方式上的根本区别,理解后者为何更适合图像数据。
—— 小象教研组