卷积神经网络(CNN)
简介
Convolutional Neural Network(卷积神经网络,简称CNN)是一种专门用来处理具有类似网格结构的数据的神经网络,例如时间序列数据(可以认为是在时间轴上有规律地采样形成的一维网格)和图像数据(可以看作是二维的像素网格)。卷积神经网络在诸多应用领域都表现优异,尤其在大型图像处理方面。
卷积神经网络是一种前馈神经网络,它的人工神经元可以响应一部分覆盖范围内的周围单元。卷积神经网络包括卷积层和池化层,这两个部分是其核心组件。卷积层负责提取图像的特征,而池化层则用于减少数据的维度。在卷积神经网络中,一个神经元会观察局部范围的图片,并将这个范围内的信息转换成一个长的向量输入到神经元中,然后将输出送入下一层的神经元。
卷积神经网络(CNN)是如何工作的
1.假设我们有一张黑白的手写数字图片,这张图片的分辨率是28x28像素,也就是说它是一个28x28的二维矩阵,矩阵中的每个值代表对应像素点的灰度值(0代表黑色,255代表白色)。我们的任务是识别这张图片上的数字是几。
2.现在,我们构建一个卷积神经网络来处理这个任务。网络的第一层是一个卷积层,它包含一些滤波器(也叫卷积核或特征检测器),这些滤波器会在输入图像上滑动,对图像进行卷积运算。每个滤波器都会提取图像的一种特征,比如边缘、角点等。
3.假设我们有一个5x5的滤波器,它会在28x28的图像上滑动,每次移动一个像素。在每个位置上,滤波器都会与其覆盖的图像区域进行对应元素相乘然后求和的操作,得到一个输出值。这样,一个28x28的图像经过一个5x5的滤波器卷积后,会得到一个24x24的输出矩阵(因为28-5+1=24)。这个输出矩阵可以看作是图像的一种特征表示。
4.然后,我们可以再加一个池化层来进一步减少数据的维度。池化层通常会对输入数据进行下采样,比如取每个2x2区域的最大值或平均值。这样,24x24的输出矩阵经过2x2的最大池化后,会得到一个12x12的输出矩阵。通过堆叠多个卷积层和池化层,我们可以提取出图像的多层特征。最后,我们会将这些特征输入到一个全连接层,全连接层会输出一个10维的向量,代表这张图片属于0-9这10个数字的概率。我们可以选择概率最大的那个数字作为最终的识别结果。
流程表示
流程如上:
我们设定一个任务:
任务:识别一张28x28像素的黑白手写数字图片上的数字。
网络结构:
输入层:28x28像素的图片。
卷积层:使用5x5的滤波器(卷积核)进行卷积操作。
池化层:使用2x2的最大池化。
全连接层:输出一个10维向量,代表0-9这10个数字的概率。
现在,我们以表格形式说明每一步的数据维度变化:
网络层 | 数据维度 | 说明 |
---|---|---|
输入层 | 28x28x1 | 输入的原始图片,灰度值,单通道 |
卷积层 | 24x24xC | C是滤波器的数量(假设我们使用多个滤波器以提取多种特征),每个滤波器卷积后得到一个24x24的特征图 |
池化层 | 12x12xC | 对卷积层的输出进行2x2的最大池化操作,宽度和高度减半 |
… | … | 可以继续添加卷积层和池化层,以进一步提取特征和减小数据维度 |
输入层 | 10 | 将最后的特征图展平并连接到一个全连接层,输出一个10维的向量,代表这张图片属于每个数字的概率 |
注意:在实际操作中,可能会有多个卷积层和池化层的堆叠,以便逐步提取更高层次和更抽象的特征。
以下是一个使用pytorch的演示
演示以前请看各api的作用:
-
torch
:- PyTorch的主要命名空间,提供了各种张量操作和神经网络构建工具。
-
torch.nn
:- PyTorch的神经网络模块,包含了用于构建神经网络的各种层和模型。
-
nn.Module
:- PyTorch中所有神经网络模型的基类,提供了模型构建的基本功能,例如参数管理、前向传播等。
-
nn.Conv2d
:- 二维卷积层,用于执行二维卷积操作。它可以通过
kernel_size
、stride
和padding
参数来定义卷积核的大小、步长和填充方式。
- 二维卷积层,用于执行二维卷积操作。它可以通过
-
nn.MaxPool2d
:- 二维最大池化层,用于执行二维最大池化操作。它通过指定池化窗口大小和步长来对输入进行下采样。
-
nn.Linear
:- 线性层,也称为全连接层,用于执行线性变换操作。它将输入张量的每个元素与权重相乘,并加上偏置,从而得到输出张量。
-
torch.relu
:- ReLU激活函数,用于执行ReLU(修正线性单元)操作。它将输入张量中的负值置零,并保持正值不变。
-
torch.randn
:- 生成服从标准正态分布的随机张量,可以用于初始化模型参数或生成随机输入数据。
-
.size()
:- 用于获取张量的形状(尺寸)。
-
.view()
:- 用于调整张量的形状,可以将张量展平成一维向量或改变其维度。
-
print()
:- 用于打印输出,显示模型的输入形状、卷积层输出特征图的形状以及模型输出的形状和值。
代码:
import torch
import torch.nn as nn
# 定义一个简单的CNN模型
class SimpleCNN(nn.Module):
def __init__(self):
super(SimpleCNN, self).__init__()
# 第一个卷积层,输入通道数为3,输出通道数为16,卷积核大小为3x3,步长为1,填充为1
self.conv1 = nn.Conv2d(3, 16, kernel_size=3, stride=1, padding=1)
# 第二个卷积层,输入通道数为16,输出通道数为32,卷积核大小为3x3,步长为1,填充为1
self.conv2 = nn.Conv2d(16, 32, kernel_size=3, stride=1, padding=1)
# 最大池化层,池化窗口大小为2x2,步长为2
self.pool = nn.MaxPool2d(2, 2)
# 第一个全连接层,输入大小为32*8*8,输出大小为128
self.fc1 = nn.Linear(32 * 8 * 8, 128)
# 第二个全连接层,输入大小为128,输出大小为10,对应类别数量
self.fc2 = nn.Linear(128, 10)
def forward(self, x):
# 输出原始输入图像的大小
print("原始输入图像大小:", x.size())
# 第一个卷积层后接ReLU激活函数,然后进行最大池化
x = self.pool(torch.relu(self.conv1(x)))
# 输出第一个卷积层的特征图大小
print("第一个卷积层后的特征图大小:", x.size())
# 第二个卷积层后接ReLU激活函数,然后进行最大池化
x = self.pool(torch.relu(self.conv2(x)))
# 输出第二个卷积层的特征图大小
print("第二个卷积层后的特征图大小:", x.size())
# 将特征张量展平成一维向量
x = x.view(-1, 32 * 8 * 8)
# 第一个全连接层后接ReLU激活函数
x = torch.relu(self.fc1(x))
# 第二个全连接层,不使用激活函数,因为通常在损失函数中使用交叉熵损失函数
x = self.fc2(x)
return x
# 创建一个随机输入张量(模拟图像数据)
input_tensor = torch.randn(1, 3, 32, 32) # 输入张量大小为(batch_size, channels, height, width)
# 初始化模型
model = SimpleCNN()
# 使用模型进行前向传播
output = model(input_tensor)
# 打印模型输出形状和值
print("模型输出形状:", output.shape)
print("模型输出值:", output)
代码说明了CNN模型的结构和各层的参数设置,以及模型输出的形状和值