Lecture10 Basic CNN

1 全连接网络

全连接网络Fully Connected Neural Network)是一种基本的人工神经网络模型,也称为多层感知器Multi-Layer Perceptron, MLP)。在全连接神经网络中,神经元之间的连接是完全连接的,每个神经元与上一层的所有神经元相连,且每个神经元都有一个权重,用于计算输入信号的加权和,并通过激活函数进行非线性变换,最终输出一个结果。

但是,由于神经元之间的连接是完全连接的,这导致模型参数数量庞大,容易出现过拟合等问题。因此,全连接神经网络在实际应用中逐渐被其他类型的神经网络模型所取代,如卷积神经网络和循环神经网络。

以下就是全连接神经网络示意图:

在这里插入图片描述
在这里插入图片描述

2 卷积神经网络

2.1 什么是卷积神经网络

卷积神经网络Convolutional Neural Network,CNN)是一种前馈神经网络。它通过卷积convolution)操作来提取图像特征,再通过池化pooling)操作来降低特征图的尺寸和维度。

2.2 卷积神经网络or全连接网络?

卷积神经网络相对于全连接网络有以下优势:

参数共享:卷积层的每个卷积核都对整个输入进行卷积运算,因此参数在不同位置共享。这意味着模型的参数数量较少,训练速度更快,并且具有更好的泛化能力。

位置不变性:卷积运算是一种局部运算,可以有效地处理图像中的平移、旋转和缩放等变换。这种位置不变性是卷积神经网络能够成功应用于图像识别等任务的重要原因之一。

深度可组合性:卷积神经网络由多个卷积层和池化层组成,每个层都可以提取出数据的特定特征。通过将多个层叠加在一起,可以实现更复杂的特征提取和分类任务。

综上所述,卷积神经网络相对于全连接网络具有更好的参数效率、位置不变性和深度可组合性。

2.3 卷积神经网络执行过程

在这里插入图片描述
注:Input图像中 1x28x28表示channel(通道) * width(宽度) * height(高度)

上述过程中的各个层的作用:
C 1 C_1 C1 层,作用是保留图像的空间结构。因为在存取图像数据时,我们默认把图像存储成一维,因此丧失了图像的一些空间结构信息,需要通过该层来复原。

S 1 S_1 S1 层,表示下采样subsampling),作用是减少数据量,降低运算需求。下采样可以减少Feature maps的尺寸,从而减少网络中需要计算的参数数量,从而提高了网络的计算效率。

特征提取(feature extraction):CNN可以自动学习特征,并且可以通过多层卷积和池化操作,逐步提取出输入数据的更加抽象和有意义的特征表示。

分类(classification):将这些特征映射到不同的类别上,从而实现对输入数据的分类。

CNN通过卷积层提取图像特征,最终将特征图展平成一维向量,并通过全连接层将其映射到目标输出空间的维度。比如图中映射成十维输出,于是便可以计算交叉熵损失,然后使用softmax函数将模型的输出转换为一个概率分布,以便与真实标签进行比较,解决分类问题。

2.4 卷积的计算过程

在这里插入图片描述
简单来说,就是将一个图像,分成红绿蓝三个通道。
接着在图像中取一个patch,然后做卷积,卷积就是对于图像中的一个patch来做的。

在卷积神经网络中,通常通过取图像中的一个小区域(称为patch或kernel),并对其进行卷积操作来提取特征。这个小区域的大小通常是正方形或矩形,由用户指定。在卷积操作中,卷积核会在图像上滑动,并将每个小区域与卷积核进行点积运算,产生一个输出值。通过改变卷积核的大小和形状,可以提取不同的特征信息。

卷积的运算过程:
在这里插入图片描述
注意:上图中的红框就相当于一个patch

最终结果:
在这里插入图片描述

多个卷积核参与运算:
在这里插入图片描述
注:卷积核数量必须得和输入的通道数量一样。

在这里插入图片描述

如果想得到n个输出通道,那么就需要n个卷积核:
在这里插入图片描述

m * n * 卷积核的宽度 * 卷积核的高度n是输入的通道,m是卷积核的个数。
比如这里m=4,也就是把卷积核拼成一个四维张量
在这里插入图片描述

2.5 代码详解

import torch

# 定义输入数据
input = [3, 4, 6, 5, 7,
         2, 4, 6, 8, 2,
         1, 6, 7, 8, 4,
         9, 7, 4, 6, 2,
         3, 7, 5, 4, 1]

# 将输入数据转换为张量并设置其维度为 (batch_size=1, channels=1, height=5, width=5)
input = torch.Tensor(input).view(1, 1, 5, 5)

# 定义卷积层,设置卷积核大小为 3*3,填充为 1,且不使用偏置项
conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False)

# 定义卷积核
```这里的view函数是用来对Tensor进行形状的变换,
具体地,[1, 2, 3, 4, 5, 6, 7, 8, 9]
这个一维Tensor被变换成了形状为[1, 1, 3, 3]的四维Tensor。
其中第一个1表示batch_size的维度,
第二个1表示输入通道的维度,
第三个3表示kernel的高度,
第四个3表示kernel的宽度。```
kernel = torch.Tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]).view(1, 1, 3, 3)

# 将卷积核的值赋给卷积层的权重
conv_layer.weight.data = kernel.data

# 对输入数据进行卷积操作
output = conv_layer(input)

# 打印卷积结果
print(output)

输出结果:
在这里插入图片描述

2.6 卷积神经网络各步骤详解

2.6.1 填充

填充操作(padding):
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在卷积过程中,填充Padding)操作是指,在输入数据的周围添加固定数量的虚拟像素点(通常值为0),使得卷积核在卷积时能够完全覆盖输入数据的边界像素点。

填充操作可以避免输入数据的边缘像素点在卷积过程中被忽略掉,从而使输出特征图的尺寸与输入特征图保持一致或减小得更慢。同时,填充操作也可以增加网络对于特征的提取能力,从而提高了网络的性能。

import torch

input = [3,4,6,5,7,
         2,4,6,8,2,
         1,6,7,8,4,
         9,7,4,6,2,
         3,7,5,4,1]
input = torch.Tensor(input).view(1, 1, 5, 5)

conv_layer = torch.nn.Conv2d(1, 1, kernel_size=3, padding=1, bias=False)
kernel = torch.Tensor([1,2,3,4,5,6,7,8,9]).view(1, 1, 3, 3)
conv_layer.weight.data = kernel.data

output = conv_layer(input)
print(output)

2.6.2 步长

假设步长为2:
在这里插入图片描述
在卷积神经网络中,步长(Stride)指的是卷积核在对输入数据进行卷积时每次滑动的步长。stride越大,每次卷积后输出的特征图尺寸就会减小,从而减少了计算量。相反,stride越小,输出的特征图尺寸就会增大,增加了计算量,但会提高特征图的细节表示能力。
因此,根据实际需要,设置合适的stride值可以在保证准确率的同时,提高计算速度和效率。

2.6.3 池化

最大池化层操作:
在这里插入图片描述
在下采样中用的比较多的一种池化方式,就是将maxpooling尺寸设置成2 * 2,默认stride=2,于是相当于把图像分为四块,在每一块中找到最大值,然后把最大值拼接起来:
在这里插入图片描述
注:使用maxpooling,通道数不变

代码:

import torch

# 定义输入矩阵
input = [3, 4, 6, 5,
         2, 4, 6, 8,
         1, 6, 7, 8,
         9, 7, 4, 6]
# 转换为张量,并设定维度
input = torch.Tensor(input).view(1, 1, 4, 4)

# 定义最大池化层,设定核大小为2
maxpooling_layer = torch.nn.MaxPool2d(kernel_size=2)

# 输入矩阵通过最大池化层处理
output = maxpooling_layer(input)

# 输出处理后的结果
print(output)

2.7 具体实现计算过程

2.7.1 计算过程详解

接下来我们来实现一个简单的神经网络来实现对minist数据集的一个识别与处理:
在这里插入图片描述
我们来具体看一下计算的过程:
在这里插入图片描述

(batch, 1, 28, 28)表示一个大小为batch的数据集,其中每个数据点的形状为(1, 28, 28),数据点的形状(1, 28, 28)表示这个数据点是一个三维数组,包含1个通道(channel)、28行(rows)和28列(columns)的图像数据。

在这里插入图片描述

我们用的第一个卷积核尺寸是5 x 5的,输入通道数为1,输出通道数为10。
经过卷积后的尺寸为(batch,10,12,12)
10代表10个通道,12,12代表经过卷积之后的尺寸(以行为例,卷积后的行数=原行数 - 卷积核行数 + 1)

在这里插入图片描述
接下来经过一次最大池化,尺寸24 x 24各减少一半变成12 x 12

在这里插入图片描述
然后再经过一个5 x 5卷积核,设置输出为20个通道
于是尺寸变为(20,8,8)

在这里插入图片描述
接着进行最大池化,变成(20,4,4)

在这里插入图片描述
最后将多维特征图展平(flatten),将数据转换成一维特征向量。最后通过一个全连接层,把320个元素映射成10个特征值

整个流程如下所示:
在这里插入图片描述

2.7.2 代码实现

整个代码:

# 定义一个名为Net的类,继承自torch.nn.Module类
class Net(torch.nn.Module):
    def __init__(self):
        # 调用父类的构造函数
        super(Net, self).__init__()
        # 定义一个卷积层,输入通道数为1,输出通道数为10,卷积核大小为5
        self.conv1 = torch.nn.Conv2d(1, 10, kernel_size=5)
        # 定义第二个卷积层,输入通道数为10,输出通道数为20,卷积核大小为5
        self.conv2 = torch.nn.Conv2d(10, 20, kernel_size=5)
        # 定义一个最大池化层,池化核大小为2
        self.pooling = torch.nn.MaxPool2d(2)
        # 定义一个全连接层,输入节点数为320,输出节点数为10
        self.fc = torch.nn.Linear(320, 10)

    # 定义模型的前向传播过程
    def forward(self, x):
        # 获取批次大小
        batch_size = x.size(0)
        # 经过第一层卷积层,再通过ReLU激活函数,然后进行最大池化
        x = F.relu(self.pooling(self.conv1(x)))
        # 经过第二层卷积层,再通过ReLU激活函数,然后进行最大池化
        x = F.relu(self.pooling(self.conv2(x)))
        # 将多维特征图展平为一维向量
        x = x.view(batch_size, -1)  # flatten展开成一维向量
        # 经过全连接层,输出结果
        x = self.fc(x)
        return x

# 实例化Net类,创建一个名为model的模型
model = Net()

2.7.3 一些可能的疑难点

为什么要使用RELU?
通过激活函数的作用,可以将特征图中的负值置为零,从而实现非线性映射,增强特征图对于图像的语义表达能力。因此,通常在卷积层之后使用 ReLU 激活函数来增强特征图的表达能力。

x.view(batch_size, -1)中的-1表示什么?
-1表示自动推导的维度大小,使得张量的大小能够被正确地展平为(batch_size, num_features)的形状。在这里,-1的值是根据张量的总元素数和batch_size来自动推导出来的。这个操作将多维的特征图展平成了一维向量,方便之后的全连接层的处理。

3 附送一张壁纸 (^ ^)/~

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值