卷积神经网络(CNN,Convolutional Neural Network)是专门用于处理图像数据的神经网络。
图像的基本概念
图像其实是数组: ndarray -> [高,宽,3通道] --> uint8
每个值取值范围0-255,那么正好是 uint8 (无符号8位整型)的类型取值范围
一个数组,能变成图片,全靠渲染器进行渲染。
现阶段:学习阶段我们暂时使用 matplotlib 来渲染·输出图像。
python
import numpy as np
import matplotlib.pyplot as plt
# mac 电脑设置。
# 设置全局字体为 PingFang HK
plt.rcParams['font.family'] = 'PingFang HK'
plt.rcParams['axes.unicode_minus'] = False # 解决负号显示问题
# 创建一个包含1行3列的子图布局
fig, axes = plt.subplots(1, 3, figsize=(12, 4))
# 全0的图像数据,黑色
img1 = np.full((200, 200, 3), 0)
axes[0].imshow(img1)
axes[0].set_title('全0 - 黑色')
# 全128的图像数据,灰色
img2 = np.full((200, 200, 3), 128)
axes[1].imshow(img2)
axes[1].set_title('全128 - 灰色')
# 全255的图像数据,白色
img3 = np.full((200, 200, 3), 255)
axes[2].imshow(img3)
axes[2].set_title('全255 - 白色')
# 显示图像
plt.show()
好的,接下来我们查看一个图片的数值:
把图片复制到文件夹命名
data/花朵.jpeg
python
import numpy as np
import matplotlib.pyplot as plt
img = plt.imread('./data/花朵.jpeg')
print(img.shape)
plt.imshow(img)
plt.show()
可见图片是一个4080 *3060 像素,3通道的图片
新建一个图像,命名为img.jpg
python
import numpy as np
import matplotlib.pyplot as plt
# 读取图像
img = plt.imread('./data/img.jpg')
# 输出图像的形状
print("图像的形状:", img.shape)
# 输出完整的图像数组
# print("图像的数值:", img)
# 只输出图像的前5个像素值,避免输出过多数据
print("图像前5个像素值:", img[:5, :5, :])
# 显示图像
plt.imshow(img)
plt.show()
代码的输出:可以看到每个像素的值,这样就不是全0,全128,全255的图了。
python
图像的形状: (640, 640, 3)
图像前5个像素值: [[[212 113 94]
[212 113 94]
[212 113 94]
[213 112 94]
[213 112 94]]
[[212 113 94]
[212 113 94]
[212 113 94]
[213 112 94]
[213 112 94]]
[[212 113 94]
[211 112 93]
[211 112 93]
[212 111 93]
[212 111 93]]
[[211 112 93]
[211 112 93]
[210 111 92]
[211 110 92]
[211 110 92]]
[[211 112 93]
[210 111 92]
[210 111 92]
[211 110 92]
[211 110 92]]]
<Figure size 640x480 with 1 Axes>
图片在卷积神经网络(CNN,Convolutional Neural Network)中的处理原理是基于图像的像素点及其颜色信息。首先,图像是由像素点构成的,每个像素点在RGB(红、绿、蓝)三个通道上都有一个值,取值范围为0到255,这就是你在图中看到的R、G、B矩阵。
CNN是专门用于处理这种图像数据的神经网络,它通过一系列的卷积、池化(Pooling)、激活函数等操作,提取图像中的特征。
具体步骤如下:
-
输入图像:输入的图像通常是由三通道的RGB图像构成。每个像素的颜色由红色(R)、绿色(G)和蓝色(B)通道的强度值表示。图中的示例表示,图像会被拆分为R、G、B三张单通道的图像。
-
卷积操作:CNN通过应用卷积核(Kernel/Filter)来提取图像中的局部特征。卷积核是一个小矩阵(例如3x3或5x5),它会逐步在输入图像上滑动,计算对应区域的加权和,从而提取到边缘、角点等局部特征。
-
激活函数(ReLU):卷积操作完成后,通常会通过ReLU(Rectified Linear Unit)激活函数对结果进行非线性变换,消除负值,这有助于引入网络的非线性,从而使模型能够处理更加复杂的模式。
-
池化(Pooling):池化层的作用是对特征图进行下采样,减小特征图的尺寸。最常见的是最大池化(Max Pooling),它会在一个小区域(如2x2)的特征图中,取该区域内的最大值,这样可以减少数据量,同时保留重要的特征。
-
全连接层(Fully Connected Layer):经过多个卷积层和池化层之后,图像的特征被逐渐提取出来。最终,图像的特征图被展平为一个一维向量,输入到全连接层进行分类或回归任务。
-
输出层:在图像分类任务中,输出层通常是一个Softmax层,用来输出各个类别的概率。对于其他任务,比如目标检测或图像分割,输出层会有所不同。
总之,CNN通过一系列的卷积操作提取图像的局部特征,再通过池化降低计算复杂度,最后通过全连接层进行特征整合,达到对图像内容的理解。
这张图展示的RGB图像表示就是典型的卷积神经网络中的输入形式。
卷积神经网络(CNN,Convolutional Neural Network)的概述
卷积神经网络概述
什么是卷积神经网络(CNN, Convolutional Neural Network)?
卷积神经网络(CNN)是一种深度学习模型,主要用于处理图像和视频等数据。与传统的神经网络不同,CNN 利用了卷积运算,通过自动提取局部特征来简化图像处理任务,尤其适合处理高维数据(如图像)的问题。
CNN的主要构成部分
-
卷积层(Convolutional Layer):
-
作用:卷积层是 CNN 中的核心组件,负责从输入图像中自动提取局部特征。通过卷积操作,卷积层可以捕捉到图像中的边缘、纹理、轮廓等低级特征。在较深的卷积层中,模型可以提取到更复杂的模式,如图像中的物体形状、位置等高级特征。
-
卷积操作:卷积核(Kernel)是一个小尺寸的矩阵(如 3x3 或 5x5),它会遍历图像的不同位置,通过加权求和的方式提取局部信息。
-
ReLU 激活函数:通常在卷积层之后会使用 ReLU 激活函数,这是一种非线性函数,用于引入非线性特征并加速训练。
-
-
池化层(Pooling Layer):
-
作用:池化层的主要作用是对卷积层输出的特征图进行降维,减少特征图的大小,同时保留关键特征。池化层可以减少计算量,防止过拟合。
-
最大池化(Max Pooling):最常用的池化方式之一是最大池化,它会从一个局部区域(如 2x2 的窗口)中选取最大值。这种操作既减少了数据维度,又保留了最显著的特征。
-
平均池化(Average Pooling):有时也会使用平均池化,它会取窗口内所有像素值的平均值,但一般来说最大池化更常用。
-
-
全连接层(Fully Connected Layer, FC):
-
作用:全连接层位于网络的最后部分,负责将卷积层和池化层提取的特征组合起来,输出最终的分类或回归结果。全连接层与传统的神经网络相似,每个神经元与前一层的所有神经元相连接。
-
作用机制:在经过多个卷积层和池化层后,特征图被展平(flatten)为一维向量,并输入到全连接层。最后,网络的输出通常通过 Softmax 函数进行归一化,用于图像分类任务。
-
CNN的附加组成
-
批量归一化(Batch Normalization):用于加速模型的训练速度,减少训练时间,还能提高模型的性能。批量归一化通过调整和缩放网络中每一层的激活值,解决了深度网络训练中的梯度消失或爆炸问题。
-
Dropout:一种正则化技术,用来防止模型过拟合。在训练时,随机丢弃一定比例的神经元,使得模型更具鲁棒性。在测试时,所有神经元参与运算。
CNN的运作流程
-
输入图像 :输入一个 RGB 图像,该图像被表示为一个三维数组(形状为
height x width x channels
)。 -
卷积层提取特征:第一个卷积层提取基本特征,如边缘、角点等;随着网络加深,后续卷积层提取更高级的语义信息。
-
池化层降维:池化层逐步降低特征图的维度,保留显著特征,减少计算量。
-
全连接层整合特征:池化后的特征被展平,通过全连接层,最终整合成分类结果。
-
输出结果:通过 Softmax 函数等将最终结果转化为各个类别的概率分布。
总结:
-
什么是卷积神经网络?
- 含有卷积层的神经网络,专用于从图像中自动提取特征。适用于图像分类、目标检测等任务。
-
卷积神经网络的构成:
-
卷积层(Convolutional Layer):提取图像特征。
-
池化层(Pooling Layer):降维,减少计算量。
-
全连接层(Fully Connected Layer):输出最终的分类或回归结果。
-
通过卷积、池化和全连接操作,卷积神经网络(CNN, Convolutional Neural Network) 能够有效地从复杂的高维数据中提取有意义的模式和特征,是现代计算机视觉任务的核心模型。
卷积层的介绍
为什么需要padding,因为我们的卷积核是有大小的,是一个形状的,如果我们不在原始图片周围加0来扩大图片的话,那么边缘信息,就不会在卷积核的中心,导致学习内容缺失或者说和中心数据学习不一样,所以padding 的主要作用是用于学习边缘信息。也就是说,padding是对原始特征外圈补几圈零。因为在卷积计算的时候0是不会影响计算结果的。
接下来我们创建一个卷积层来看看生成的特征大小:
python
import matplotlib.pyplot as plt
import torch
from torch import nn
# 1. 读取图像
# 使用 matplotlib 库中的 imread 函数读取图像。读取的图像通常是一个 NumPy 数组,
# 形状为 (height, width, channels),其中 channels 为 3(RGB 颜色通道)。
img = plt.imread('./data/img.jpg')
# 打印图像的原始形状,方便确认图像的维度信息
print(img.shape) # 输出形状如 (高度, 宽度, 通道数)
# 2. 转换图像数据
# 将读取的图像数据转换为 PyTorch 张量。
# 在图像处理中,PyTorch 期望的输入数据形式是 (batch_size, channels, height, width),
# 而不是通常的 (height, width, channels)。
# 通过 permute 操作调整图像维度顺序 (channels, height, width),然后使用 unsqueeze 在最前面添加 batch_size 维度。
# 转换为 float32 类型以符合 PyTorch 处理需求,默认的图像数据通常是 uint8 类型(0-255)。
img = torch.tensor(img).permute(2, 0, 1).unsqueeze(0).to(torch.float32)
# 打印调整后的张量形状,应该是 (1, channels, height, width),即 (batch_size, 通道数, 高度, 宽度)
print(img.shape)
# 3. 定义卷积层
# 使用 nn.Conv2d 来定义一个二维卷积层。
# 参数说明:
# - in_channels:输入图像的通道数,这里是 3,表示 RGB 图像有三个颜色通道。
# - out_channels:卷积层的输出通道数,设置为 5,表示会有 5 个输出的特征图。
# - kernel_size:卷积核的大小,设置为 (3, 5),表示卷积核的大小为 3x5。
# - stride:卷积核在图像上滑动的步长,这里设置为 (1, 2),表示在高度方向步长为 1,宽度方向步长为 2。
# - padding:填充大小,这里设置为 2,表示在高度和宽度方向上各自填充 2 像素,保持图像特征图的尺寸。
conv = nn.Conv2d(in_channels=3, out_channels=5, kernel_size=(3, 5), stride=(1, 2), padding=2)
# 4. 处理图像
# 将图像张量 img 输入到卷积层 conv 中,生成特征图 fm。
# fm 是卷积操作后得到的输出张量,其形状为 (batch_size, out_channels, new_height, new_width)。
# 其中 new_height 和 new_width 由卷积层的卷积核大小、步长和填充方式决定。
fm = conv(img)
# 打印卷积后的特征图形状,输出的 shape 应该是 (1, 5, new_height, new_width),
# 其中 1 表示 batch_size,5 表示输出的通道数(out_channels),new_height 和 new_width 是卷积后的特征图尺寸。
print(fm.shape)
关键点总结:
-
读取和调整图像数据:
-
使用
plt.imread()
读取图像,默认返回一个形状为(height, width, channels)
的 NumPy 数组。 -
转换为 PyTorch 张量并调整维度,使其符合 PyTorch 中卷积层的输入要求
(batch_size, channels, height, width)
。
-
-
卷积层的参数:
-
in_channels=3
:输入图像的通道数,即 RGB 图像的 3 个通道。 -
out_channels=5
:输出 5 个特征图。 -
kernel_size=(3, 5)
:卷积核的尺寸为 3x5。 -
stride=(1, 2)
:高度方向步长为 1,宽度方向步长为 2。 -
padding=2
:在卷积操作前对输入图像进行 2 像素的填充。
-
-
卷积操作:
-
卷积层将输入图像通过卷积核操作生成多个特征图。
-
卷积后输出特征图的尺寸取决于输入图像的尺寸、卷积核大小、步长、填充量等。
-
这个过程展示了如何使用 PyTorch 读取图像、处理图像并通过卷积层生成特征图的整个流程。
输出:
这个输出表示在不同步骤中张量(图像)的形状,具体解释如下:
-
(640, 640, 3):
-
这是读取的原始图像的形状。
-
640 x 640 表示图像的高度和宽度均为 640 像素。
-
3 表示图像的通道数,3 通道通常代表 RGB 图像(红、绿、蓝)。
-
-
torch.Size([1, 3, 640, 640])
:-
这是图像在被转换为 PyTorch 张量并调整维度后的形状。
-
1:表示批处理的大小(batch size),这里设置为 1,表示只有一张图像。
-
3:表示图像的通道数,仍然是 RGB 图像的 3 个通道。
-
640 x 640:表示图像的高度和宽度,依然是 640x640 像素。
-
总的来说,这个形状表示 PyTorch 中标准的 4 维图像张量
(batch_size, channels, height, width)
。
-
-
torch.Size([1, 5, 642, 320])
:-
这是经过卷积层后的输出张量的形状。
-
1:表示批处理的大小,仍然是 1。
-
5 :表示输出的通道数(卷积核的数量),即卷积层有 5 个输出特征图(因为卷积层设置了
out_channels=5
)。 -
642:表示卷积操作后特征图的高度,原始高度为 640,经过了卷积运算后变为 642。这是由于卷积核和填充的设置造成的。
- 卷积层的
padding=2
和kernel_size=(3, 5)
影响了输出的尺寸,导致高度增加。
- 卷积层的
-
320:表示卷积操作后特征图的宽度,原始宽度为 640,经过步长为 2 的卷积操作后宽度减少到 320(宽度缩小了大约一半)。
-
卷积后的特征图尺寸的计算:
卷积层的输出尺寸可以通过公式计算:
高度的计算:
宽度的计算:
对高度(H_in = 640,kernel_size = 3,padding = 2,stride = 1):
对宽度(W_in = 640,kernel_size = 5,padding = 2,stride = 2):
因此,卷积层的输出张量形状为 (1, 5, 642, 320)
,即批处理大小为 1,输出通道为 5,高度为 642,宽度为 320。
总结:
-
(640, 640, 3):原始 RGB 图像的形状。
-
torch.Size([1, 3, 640, 640])
:转换后的 PyTorch 张量的形状,批大小为 1,通道数为 3,高宽为 640x640。 -
torch.Size([1, 5, 642, 320])
:经过卷积层后的输出特征图,批大小为 1,输出 5 个特征图,特征图大小为 642x320。
池化层的介绍
python
import torch
from torch import nn
# 设置随机种子以保证每次运行得到相同的随机数
torch.random.manual_seed(22)
# 创建一个 3x3 的张量,值在 [0, 10) 范围内,数据类型为 float32,batch_size = 1,通道数 = 1
data = torch.randint(0, 10, [1, 3, 3], dtype=torch.float32)
# 打印生成的 3x3 张量,初始数据为随机生成的
print(data)
# 输出的张量如下:
# tensor([[[9., 6., 6.],
# [4., 2., 2.],
# [2., 1., 8.]]])
# 定义一个最大池化层,池化窗口大小为 (2, 2),步长为 (1, 1),不使用填充
pool = nn.MaxPool2d(kernel_size=(2, 2), stride=(1, 1), padding=0)
# 对数据应用最大池化操作,并打印结果
print(pool(data))
# 最大池化过程:从每个 2x2 的窗口取最大值
# 1. 第一个窗口 [9, 6, 4, 2],最大值为 9
# 2. 第二个窗口 [6, 6, 2, 2],最大值为 6
# 3. 第三个窗口 [4, 2, 2, 1],最大值为 4
# 4. 第四个窗口 [2, 2, 1, 8],最大值为 8
# 输出如下:
# tensor([[[9., 6.],
# [4., 8.]]])
# 定义一个平均池化层,池化窗口大小为 (2, 2),步长为 (1, 1),不使用填充
pool2 = nn.AvgPool2d(kernel_size=(2, 2), stride=(1, 1), padding=0)
# 对数据应用平均池化操作,并打印结果
print(pool2(data))
# 平均池化过程:从每个 2x2 的窗口取平均值
# 1. 第一个窗口 [9, 6, 4, 2],平均值为 (9+6+4+2)/4 = 5.25
# 2. 第二个窗口 [6, 6, 2, 2],平均值为 (6+6+2+2)/4 = 4.00
# 3. 第三个窗口 [4, 2, 2, 1],平均值为 (4+2+2+1)/4 = 2.25
# 4. 第四个窗口 [2, 2, 1, 8],平均值为 (2+2+1+8)/4 = 3.25
# 输出如下:
# tensor([[[5.2500, 4.0000],
# [2.2500, 3.2500]]])
代码输出:
输出解释:
-
随机生成的数据:一个 1x3x3 的张量,表示一个批次中的单张图像,大小为 3x3,数据值为随机生成的 0 到 9 之间的浮点数。
-
最大池化的结果:
• 将 3x3 的数据分为若干个 2x2 的区域,对每个区域选取最大值作为输出。最终输出的是 2x2 的张量,表示池化后的图像。
- 平均池化的结果:
• 同样的 2x2 窗口区域,对每个区域计算其平均值,输出同样是 2x2 的张量。
这段代码展示了在 PyTorch 中如何使用最大池化和平均池化操作,并通过实例演示了池化过程中的计算方式。
我们以一个3*3*3 的案例来讲解多通道池化层的计算过程,但是实际中肯定不会出现这么小的图像数据,实际中我们的池化窗口一般是 3*3
kernel_size=(3,3)
步长一般设计为 2*2
stride=(2,2)
然后 padding的话,一般没有特别要求,建议自己超参数,多设计几次,炼丹。
python
import torch
from torch import nn
# 设置随机种子以保证每次运行生成相同的随机数,确保结果可复现
torch.random.manual_seed(22)
# 创建一个 3x3x3 的张量,值在 [0, 10) 范围内,数据类型为 float32。
# 这里 3x3 表示每张图像的大小(3x3 像素),有 3 个通道(类似 RGB 三通道)。
data = torch.randint(0, 10, [3, 3, 3], dtype=torch.float32)
# 打印生成的张量
print(data)
# 输出的张量数据如下:
# tensor([[[9., 6., 6.],
# [4., 2., 2.],
# [2., 1., 8.]],
# [[0., 1., 0.],
# [3., 2., 4.],
# [4., 9., 0.]],
# [[0., 1., 3.],
# [2., 9., 7.],
# [8., 4., 1.]]])
# 这个张量表示 3 个通道,每个通道是 3x3 的二维图像数据。
# 定义一个最大池化层,窗口大小为 (2, 2),步长为 (1, 1),不进行填充。
pool = nn.MaxPool2d(kernel_size=(2, 2), stride=(1, 1), padding=0)
# 对数据应用最大池化操作
print(pool(data))
# 定义一个平均池化层,窗口大小为 (2, 2),步长为 (1, 1),不进行填充。
pool = nn.AvgPool2d(kernel_size=(2, 2), stride=(1, 1), padding=0)
# 对数据应用平均池化操作
print(pool(data))
多通道池化层代码输出
python
tensor([[[9., 6., 6.],
[4., 2., 2.],
[2., 1., 8.]],
[[0., 1., 0.],
[3., 2., 4.],
[4., 9., 0.]],
[[0., 1., 3.],
[2., 9., 7.],
[8., 4., 1.]]])
tensor([[[9., 6.],
[4., 8.]],
[[3., 4.],
[9., 9.]],
[[9., 9.],
[9., 9.]]])
tensor([[[5.2500, 4.0000],
[2.2500, 3.2500]],
[[1.5000, 1.7500],
[4.5000, 3.7500]],
[[3.0000, 5.0000],
[5.7500, 5.2500]]])
解释:
输入张量的形状:
-
输入张量的形状是
(3, 3, 3)
,表示 3 个通道,每个通道的图像大小为 3x3。 -
张量的内容表示 3x3 图像的像素值,生成的 3 个通道张量如下:
通道 1: 9 6 6 4 2 2 2 1 8 通道 2: 0 1 0 3 2 4 4 9 0 通道 3: 0 1 3 2 9 7 8 4 1
最大池化操作(Max Pooling):
最大池化计算过程:
最大池化后的输出:
tensor([[[9., 6.], [4., 8.]], [[3., 4.], [9., 9.]], [[9., 9.], [9., 9.]]])
-
nn.MaxPool2d(kernel_size=(2, 2), stride=(1, 1), padding=0)
:-
kernel_size=(2, 2):表示 2x2 的池化窗口。
-
stride=(1, 1):表示每次滑动 1 个像素。
-
padding=0:表示不进行填充,池化窗口完全在图像内移动。
-
-
对每个 2x2 的窗口,选择其中的最大值作为输出:
-
通道 1:
-
窗口
[9, 6, 4, 2]
,最大值为 9。 -
窗口
[6, 6, 2, 2]
,最大值为 6。 -
窗口
[4, 2, 2, 1]
,最大值为 4。 -
窗口
[2, 2, 1, 8]
,最大值为 8。
-
-
通道 2:
-
窗口
[0, 1, 3, 2]
,最大值为 3。 -
窗口
[1, 0, 2, 4]
,最大值为 4。 -
窗口
[3, 2, 4, 9]
,最大值为 9。 -
窗口
[2, 4, 9, 0]
,最大值为 9。
-
-
通道 3:
-
窗口
[0, 1, 2, 9]
,最大值为 9。 -
窗口
[1, 3, 9, 7]
,最大值为 9。 -
窗口
[2, 9, 8, 4]
,最大值为 9。 -
窗口
[9, 7, 4, 1]
,最大值为 9。
-
平均池化操作(Average Pooling):
平均池化计算过程:
平均池化后的输出:
tensor([[[5.2500, 4.0000], [2.2500, 3.2500]], [[1.5000, 1.7500], [4.5000, 3.7500]], [[3.0000, 5.0000], [5.7500, 5.2500]]])
-
nn.AvgPool2d(kernel_size=(2, 2), stride=(1, 1), padding=0)
: -
和最大池化的窗口大小、步长、填充方式相同,但池化时计算的是窗口内像素的平均值。
-
对每个 2x2 的窗口,计算其中的像素平均值作为输出:
通道 1:
-
窗口
[9, 6, 4, 2]
,平均值为(9 + 6 + 4 + 2) / 4 = 5.25
。窗口
[6, 6, 2, 2]
,平均值为(6 + 6 + 2 + 2) / 4 = 4.00
。窗口
[4, 2, 2, 1]
,平均值为(4 + 2 + 2 + 1) / 4 = 2.25
。窗口
[2, 2, 1, 8]
,平均值为(2 + 2 + 1 + 8) / 4 = 3.25
。 -
通道 2:
-
窗口
[0, 1, 3, 2]
,平均值为(0 + 1 + 3 + 2) / 4 = 1.50
。 -
窗口
[1, 0, 2, 4]
,平均值为(1 + 0 + 2 + 4) / 4 = 1.75
。 -
窗口
[3, 2, 4, 9]
,平均值为(3 + 2 + 4 + 9) / 4 = 4.50
。 -
窗口
[2, 4, 9, 0]
,平均值为(2 + 4 + 9 + 0) / 4 = 3.75
。 -
通道 3:
窗口
[0, 1, 2, 9]
,平均值为(0 + 1 + 2 + 9) / 4 = 3.00
。窗口
[1, 3, 9, 7]
,平均值为(1 + 3 + 9 + 7) / 4 = 5.00
。窗口
[2, 9, 8, 4]
,平均值为(2 + 9 + 8 + 4) / 4 = 5.75
。窗口
[9, 7, 4, 1]
,平均值为(9 + 7 + 4 + 1) / 4 = 5.25
。
总结:
-
最大池化:对于每个 2x2 的窗口,选取最大值,保留图像中特征最显著的部分。
-
平均池化:对于每个 2x2 的窗口
池化层(Pooling Layer)在卷积神经网络中的作用和机制
背景与历史
池化层最早应用于卷积神经网络(CNN)中,用来降低特征图的尺寸,减少模型参数,并加快计算速度。卷积神经网络的最初版本如LeNet(由Yann LeCun在1990年代提出)就已经引入了池化层的概念。池化层作为卷积层的补充,可以避免过拟合,并增强模型的泛化能力。
池化层的作用
-
降低维度:池化层通过下采样的方式,减少特征图的大小(如从 4x4 到 2x2),从而减少数据量。这对于后续的计算有很大的帮助。
-
减少计算量:随着特征图的尺寸减小,后续层所需的计算量也会随之减小。这使得模型在处理大规模数据时更加高效。
-
防止过拟合:池化层通过对特征进行下采样,可以避免网络过度拟合训练数据的细节,提高模型的泛化能力。
-
位置不变性:池化层保留了重要特征,同时忽略了小范围内的位移。因此,模型在面对同一物体在不同位置时具有更强的鲁棒性。
池化机制
池化层通常使用固定大小的窗口滑动于输入特征图之上,并对窗口内的值进行某种操作(如最大值或平均值)。最常用的池化方法有两种:
-
最大池化(Max Pooling):
-
从窗口内取最大值。最大池化可以保留局部区域中最强的激活特征,通常用于提取边缘、角点等显著特征。
-
例如在2x2的窗口中,如果输入为 [0, 1, 3, 2],则最大池化的结果为 3。
-
-
平均池化(Average Pooling):
-
从窗口内取平均值。平均池化对于平滑特征图、减少噪声有一定的帮助,但通常在现代的 CNN 中,最大池化比平均池化使用得更多。
-
例如在2x2的窗口中,如果输入为 [0, 1, 3, 2],则平均池化的结果为 (0+1+3+2)/4 = 1.5。
-
池化操作中的关键参数
-
池化核大小(Kernel Size):池化操作的窗口大小,常见的是 2x2 或 3x3 的核。
-
步长(Stride):池化核在输入特征图上滑动的步长。较大的步长可以减少池化后的特征图尺寸。一般常用步长与池化核大小相同,例如步长为 2 的 2x2 池化。
-
填充(Padding):在边界处是否进行填充操作。如果使用填充,输入特征图的边界会被增加一些值(通常是 0),以便在边缘区域也能进行池化操作。
PyTorch中的池化层API
在 PyTorch 中,使用 torch.nn
模块可以非常方便地实现池化层,最常用的是 nn.MaxPool2d
和 nn.AvgPool2d
。
-
MaxPool2d 示例:
pythonimport torch import torch.nn as nn # 定义一个2x2的最大池化层 max_pool = nn.MaxPool2d(kernel_size=2, stride=2) # 假设输入是一个4x4的特征图 input_tensor = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]).unsqueeze(0).unsqueeze(0) # 应用最大池化操作 output_tensor = max_pool(input_tensor) print(output_tensor)
-
AvgPool2d 示例:
pythonimport torch import torch.nn as nn # 定义一个2x2的平均池化层 avg_pool = nn.AvgPool2d(kernel_size=2, stride=2) # 假设输入是一个4x4的特征图 input_tensor = torch.tensor([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12], [13, 14, 15, 16]]).unsqueeze(0).unsqueeze(0) # 应用平均池化操作 output_tensor = avg_pool(input_tensor) print(output_tensor)
池化层的历史与问题解决
-
背景:在早期的神经网络中,直接使用全连接层处理图像特征,导致了巨大的参数量。池化层通过降低特征图的维度,显著减少了参数数量,同时提升了计算效率。
-
解决的问题:
-
降低特征图的尺寸:池化层通过下采样减少特征图的尺寸。
-
减少模型的计算量:池化降低了特征图尺寸,从而减少了计算量。
-
增强模型的泛化能力:池化通过忽略一些不重要的细节,增强了模型的泛化能力。
-
减少过拟合的风险:池化层在减少参数数量的同时,降低了过拟合的风险。
-
总结
池化层是卷积神经网络中的关键组件,用于通过下采样操作来减少特征图的维度和模型计算量。它能增强模型对输入图像位置变化的鲁棒性,同时避免模型过拟合。在现代的 CNN 中,最大池化(Max Pooling)是最常用的池化方法,而 PyTorch 提供了灵活的 API 让用户轻松实现池化操作。
通过掌握池化的机制与原理,你可以更好地理解 CNN 如何高效地处理大规模图像数据,并进一步优化深度学习模型。
好的到这里我们已经讲解完了卷积神经网络中的卷积层和池化层, 然后再加一个全连接层(深度学习03神经网络有讲过)
【深度学习】03-神经网络 5 (完结篇) 一文讲解 pytroch手机价格神经网络分类与准确率优化案例-CSDN博客
因此全连接层,卷积层,池化层 三者一起我们就可以实现一个图像分类的案例了。
图像分类案例
具体代码和数据集我会另开一个文章来讲解。预知后续如何请听下回分解。