【6】卷积神经网络的介绍

简介: 【6】卷积神经网络的介绍

1.关于图像的基础知识


灰度图

这里以MINST数据集为例,对于一个手写数字的图像,其由像素为28*28的灰度图构成,如图所示:

image.png

image.png

根据每一个像素点的一个具体的数值,可以将其构造出一副如上述所示的灰度图,由于灰度图的通道只有1,也就是没有其他的通道堆叠,所以对于0-255的数值,其实可以将每一个像素点都除以一个255,然后所得到的就是一个0-1的范围之间的二维数组,这堆小数点排列的二维数组数据便可以构成一幅灰度图片。


彩色图

而对于一张彩色的图片,就代表了其有三个通道,按我个人的理解是由于三种颜色可以组合成其他的任意一种颜色,所以这三通道二维数组便可以构造成一张彩色的图片。也就说,对于红黄蓝三个通道,每一个通道都一个类似灰度图的一个二维数组,来代表每一个通道的数据构成,如下所示:

image.png

image.png

而一般来说,一张彩色的图片,就是这三个通道的叠加组成,主观体现为:

image.png

image.png


2.卷积操作与过滤器


由于全连接层所设计的参数过大,在当时的年代硬件设备提供的能力不足,而卷积神经网络的出现可以较好的降低了参数的总数量,参考了人视野的局部相关性特点。

image.png

而其中的卷积概念,其具体的操作就是对于一个行列维数相同的矩阵,他们之间的卷积运算就相同位置的数据相乘,然后对这些全部相乘的的数据进行一个累加的操作,这个过程就是卷积,信号处理中的数学公式为:

image.png

而对于卷积神经网络来说,做卷积运算的是图片样本与一个个的卷积核(这些卷积核也称为过滤器)。卷积核可以由一个标量拓展成一个3x3的矩阵,然后用卷积核中的每一个元素,乘以对应输入矩阵中的对应元素,每计算出一次,就移动一格,或者几格。这样,卷积核作为输入矩阵上的一个移动窗口。

image.png

其中,每一种这样的卷积核就代表其会提取出图片的某一种特征,比如


  • 锐化过滤器

image.png


  • 边缘检测过滤器

image.png


3.卷积神经网络的具体操作


卷积过程

对于简单的一张灰度图片来说,以手写数据集的数据为例,其是一个通道的灰度图,而且像素点的组成是28*28的,现在假设有一张这样的照片,将其表示为(B,C,H,W),其中的B代表数据的数量,C代表通道数,H与W代表图片的像素组成。


对于这样的一张图片,现在挑选一个过滤器(卷积核)与其进行一个卷积运算,便会得到一个新的矩阵,称为feature map

image.png


如果卷积矩阵是3x3,步长设置为1,这这个新的feature map就会是2626,如果在原来的minst图的上下左右加0变成一个3030的矩阵,则卷积出来feature map就同样是28*28的大小


而如果使用n个卷积核(过滤器),然后将得到的feature map进行叠加,便会得到一个n通道的卷积结果

image.png

使用了多个卷积核,就代表了对原来的图片进行检测n种不同的属性,所以这个维度是会增加的,这个维度的大小取决于使用kernel的数量。


以下区分一下概念:


Input_channels:原始照片的颜色通道数,灰度图片是1,彩色图片是3


Kernel_channels:所使用的卷积核的数量


Kernel_size:卷积核的矩阵大小


Stride:卷积核的步长,也就是卷积核一次移动的距离


Padding:在原始照片周围打0的圈数


  • 对于更常见的现象是,对于彩色的照片做卷积运算

image.png

对于一些参数的解释:


x:[b,3,28,28]


对于彩色的图片,其颜色的通道数是3,而对于minst图片其像素是28*28,其中的b代表的是b张minst图片


one kernel:[3,3,3]


对于一个卷积核,[3,3,3]最后的两个3表示的是卷积核矩阵的大小,而第一个3是与图片的颜色通道相对应,由于彩色的图片是拥有rgb三种通道,如上图所示。对于每一个通道对应一个kernel,这三个通道加起来就是一个Kernel_channels,也就是第一个参数需要完全和输入的通道数匹配起来


multi-kernel:[16,3,3,3]


而对于多卷积核,也就是使用了多个过滤器来对原始的图片作为特征提取,第一个参数就表示假设使用了16个过滤器。


bias:[16]


每一个Kernel_channels都有一个偏置,所以如果用了16个过滤器来进行特征提取,就会有16个偏置


out:[b,16,28,28]


原始的输入数据是b张照片,所以输出也会是b个内容,16代表的是经过了16个过滤器得到的16个特征叠加在一起,由于设置了Padding,所以还是28*28


  • 对卷积结果的解释:

根据以下经验的解释是,低层维度的提取是一些低层的特征

对于中层提取的小维的概念,开始无法解释,高层就是一些更高维的概念等等,越来越抽象,也就是特征的不断提取的过程

image.png


代码实现

  • nn.Conv2d的使用
# 第一个例子
# F.conv2d = nn.Conv2d
# F.conv2d是一个函数的操作,而nn.Conv2d是一个类操作
layer = nn.Conv2d(in_channels=1,out_channels=3,kernel_size=3,stride=1,padding=0)
# Conv2d:函数名字含义就是做一个2d的函数卷积运算
# in_channels=1:表示输入图片的通道数,由于是灰度的图片,所以设置为1
# out_channels=3:表示使用过滤器的数目为3
# kernel_size=3:表示卷积核的矩阵大小是3x3
# stride=1:表示补步长设置为1
# padding=0:表示没有对图片进行补偶读拓展
x = torch.rand(1,1,28,28)
# 输入是2张minst数据图片,通道数为1
out = layer.forward(x)
# out.shape输出为:torch.Size([1, 3, 26, 26])
# 由于没有设置padding与设置了stride=1,所以由原来的28*28变成了26*26
# 由于只输入了1张图片,所以最高位是1,而且由于使用了3个过滤器,所以第二维度是3
# 而且这句可以被替换为
# out = layer(x)
# 第二个例子
layer = nn.Conv2d(in_channels=1,out_channels=3,kernel_size=3,stride=1,padding=1)
# 这次设置了padding=1,也就是进行了一圈的补0操作
x = torch.rand(1,1,28,28)
layer(x).shape
# out.shape输出为:torch.Size([1, 3, 28, 28])
# 由于原图是28*28,还进行了补0操作,所以输出还是28*28
# 第三个例子
layer = nn.Conv2d(in_channels=1,out_channels=3,kernel_size=3,stride=2,padding=1)
# 步长为2,也就是输出的矩阵将会减半操作
x = torch.rand(3,1,28,28)
# 输入设置为3张
layer(x).shape
# out.shape输出为:torch.Size([3, 3, 14, 14])
# 第四个例子
layer = nn.Conv2d(in_channels=3,out_channels=3,kernel_size=3,stride=2,padding=1)
# 设置输入的通道数是3
x = torch.rand(10,3,28,28)
# 过滤器的通道数一定要和输入图片的通道数相等,否则会报错处理
layer(x).shape
# out.shape输出为:torch.Size([10, 3, 14, 14])


  • F.conv2d的使用
# F.conv2d的使用
x = torch.rand(1,3,28,28)
# 图片样本数是1,通道是3,大小是28*28
w = torch.rand(16,3,3,3)
# 过滤器数量是16,通道是3,卷积核大小是3*3
b = torch.rand(16)
# 偏置数量与卷积核数量一致都是16
out = F.conv2d(input=x,weight=w,bias=b,stride=1,padding=1)
# 步长是1,填充1圈
out.shape
# 输出为:torch.Size([1, 16, 28, 28])
# 输出1个结果因为只有1张图片是输入,卷积后的通道数是16由于使用了16个卷积核,大小不变


  • 网络结构参数的查看
# 观察网络结构的参数
layer = nn.Conv2d(in_channels=1,out_channels=3,kernel_size=3,stride=2,padding=1)
x = torch.rand(3,1,28,28)
layer(x).shape
# out.shape输出为:torch.Size([3, 3, 14, 14])
# 查看weight
layer.weight
# Parameter containing:
# tensor([[[[-0.3117,  0.1637,  0.1690],
#           [ 0.0798, -0.1686, -0.0726],
#           [-0.2899,  0.1273,  0.3168]]],
# 
# 
#        [[[ 0.2656,  0.1425, -0.2783],
#           [ 0.1055,  0.2423,  0.0910],
#           [ 0.2852, -0.2426, -0.0128]]],
#
#
#         [[[ 0.2536,  0.0558, -0.2349],
#           [ 0.0722,  0.0460, -0.1613],
#           [ 0.2438, -0.0269,  0.0463]]]], requires_grad=True)
layer.weight.shape
# 输出为:torch.Size([3, 1, 3, 3])
# 由于kernel的大小是3*3,所以最后两个参数是3,3,而由于设置了kernel只有一个通道,所以第二个参数是1
# 第一个参数是3,原因是使用了3个过滤器提取特征
layer.bias.shape
# 输出为:torch.Size([3])
# 有一个卷积核就有几个bias,使用了3个过滤器提取特征所以shape是3


4.池化层(Pooling Sampling)


下采样

  • 下采样操作

也就是隔行采样操作来实现降维

image.png


  • 最大池化操作(Max pooling)

对于单位的窗口中挑选出数值最高的来作为输出值,除了Max pooling还有Avg pooling,就是对于单位的窗口的数值求均值来作为输出值

image.png

测试代码:


# nn.MaxPool2d使用例子
# 其中的2d表示是对二维的图片进行处理
x = out
# x.shape为:torch.Size([1, 16, 14, 14])
# 卷积之后的结果作为池化层的输入
layer = nn.MaxPool2d(kernel_size=2,stride=2)
# kernel_size=2:表达滑动窗口是2*2
# stride=2:表示移动的步长是2
layer(x).shape
# 输出为:torch.Size([1, 16, 7, 7])
# 由于设置了步长是2,所以实现了降维操作,维度也从14*14变成7*7
#  F.avg_pool2d的使用例子
# 其中的2d表示是对二维的图片进行处理
out = F.avg_pool2d(input=x,kernel_size=2,stride=2)
# x是输入,步长为2,窗口大小是2
out.shape
# 输出为:torch.Size([1, 16, 7, 7])
# F.avg_pool2d功能与nn.MaxPool2d是一样的


上采样

  • 上采样操作

其实numpy或者其他的很多工具包都是有这样的操作的,但是pytorch为了满足自身的tensor数据类型还是封装了这样的一个功能。

上采用操作就是实现放大的功能

image.png

测试代码:


# 上采样操作
out.shape
# 原本的输出为:torch.Size([1, 16, 7, 7])
# 进行上采样也就是放大操作
out = F.interpolate(input=out,scale_factor=2,mode='nearest')
# scale_factor=2:表示输出结果放大2倍
# mode='nearest':表示使用某一个模式,nearest是近邻插值
out.shape
# 输出为:torch.Size([1, 16, 14, 14])
# 可以结果放大了1倍
# 进一步放大
out = F.interpolate(input=out,scale_factor=3,mode='nearest')
# scale_factor=2:表示输出结果放大3倍
out.shape
# 输出为:torch.Size([1, 16, 42, 42])
# 可见,在原来的基础上又放大了3倍


5.批处理规范(Batch Norm)


Image Normalization

由于Sigmoid函数大于一定数值或者小于一定数值,也就是不在一段有效区间范围内时或出现梯度弥散情况,对于这种情况的梯度会很多时候得不到更新,所以希望输入的值可以能控制在一个有效的范围之内

image.png

这个方法的主要思路就是将数据的大小最好集中在0附近,然后方差就有一个比较小的范围。而对于彩色的3通道图像来说,对于没一个通道都有一个均值与方差,然后根据计算公式就可以分布在一个接近于0的区域。

image.png


Batch Normalization

image.png


  • Batch Norm

假设输入的数据是[6,3,784],这表示有6张彩色的图片,每张图片的像素分布是28*28,Batch Norm是对通道进行统计处理,去全部实例上的通道1,通道2,通道3的均值,也就是根据3个通道统计出3个均值,也就有3个方差。


  • Layer Norm

简单的来说Batch Norm是根据通道数来计算均值,而Layer Norm就是根据实例数来计算均值,所以对于输入的数据是[6,3,784],由于有6张照片,所以会有6个均值与6个方差。


  • Instance Norm

Instance Norm统计的是当前的实例的当前的均值,同样的,假设输入的数据是[6,3,784],那么根据6个照片就算6个实例,3个通道,所以其会用6*3=18个均值,还有18个方差。

image.png


Batch Norm规范化的过程:

image.png

测试代码:


  • nn.BatchNorm1d操作
# nn.BatchNorm1d的使用例子
x = torch.rand(100,16,784)
# x是来至0-1的均匀分布,表示的是100张图片,16个通道,大小是28*28
layer = nn.BatchNorm1d(16)
# BatchNorm1d的原因是现在已经将28*28的数据表示成1维的了,所以需要用1d
# 而由于Batch Norm是根据通道数来做均值和方差的,所以参数是16
out = layer(x)
# out.shape输出为:torch.Size([100, 16, 784])
layer.running_mean
# 由于x是0-1的均匀分布,所以均值是0.5左右,验证一下
# tensor([0.0499, 0.0499, 0.0499, 0.0500, 0.0500, 0.0500, 0.0500, 0.0500, 0.0501,
#        0.0501, 0.0500, 0.0499, 0.0502, 0.0500, 0.0501, 0.0502])
layer.running_var
# 方差应该是1,验证一下
# tensor([0.9084, 0.9084, 0.9083, 0.9083, 0.9083, 0.9083, 0.9083, 0.9083, 0.9084,
#        0.9084, 0.9084, 0.9084, 0.9084, 0.9083, 0.9083, 0.9084])
# 其中的running_u与running_θ根据当前的μ与θ来更新


  • nn.BatchNorm2d操作
# nn.BatchNorm2d的使用例子
x.shape
# 输出为:torch.Size([1, 16, 7, 7])
layer = nn.BatchNorm2d(16)
# 由于现在是输入x没有将维度变成1维,这个照片还是用2维表示的,所以是2d
# 而参数必须要与输入通道数相同,输入的通道是16,所以这里的参数也必须是16
out = layer(x)
# out.shape输出为:torch.Size([1, 16, 7, 7])
# 因为进行批处理是不会改变维度的
layer.weight
# 可以输出相关参数的信息
# Parameter containing:
# tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
#       requires_grad=True)
layer.weight.shape
# 输出为:torch.Size([16])
layer.bias.shape
# 输出为:torch.Size([16])
# 将layer当前的参数全部打印出来
vars(layer)
# {'training': True,
#  '_parameters': OrderedDict([('weight', Parameter containing:
#                tensor([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.],
#                       requires_grad=True)),
#               ('bias',
#                Parameter containing:
#                tensor([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.],
#                       requires_grad=True))]),
#  '_buffers': OrderedDict([('running_mean',
#                tensor([0.0477, 0.0495, 0.0464, 0.0551, 0.0555, 0.0441, 0.0553, 0.0496, 0.0551,
#                        0.0480, 0.0546, 0.0461, 0.0454, 0.0484, 0.0478, 0.0562])),
#               ('running_var',
#                tensor([0.9099, 0.9076, 0.9070, 0.9073, 0.9073, 0.9079, 0.9089, 0.9092, 0.9087,
#                        0.9077, 0.9074, 0.9085, 0.9096, 0.9076, 0.9070, 0.9089])),
#               ('num_batches_tracked', tensor(1))]),
#  '_non_persistent_buffers_set': set(),
#  '_backward_hooks': OrderedDict(),
#  '_forward_hooks': OrderedDict(),
#  '_forward_pre_hooks': OrderedDict(),
#  '_state_dict_hooks': OrderedDict(),
#  '_load_state_dict_pre_hooks': OrderedDict(),
#  '_modules': OrderedDict(),
#  'num_features': 16,
#  'eps': 1e-05,
#  'momentum': 0.1,
#  'affine': True,
#  'track_running_stats': True}
# running_mean就是是μ,而running_var就是σ;weight相当于是γ,bias相当于是β
# 'affine': False表示不适应β与γ的变换,而且不会自动更新


注意,Batch Norm与Drop Out的使用例子一样,train与test的使用例子是不一样的,test是不需要跟新权值的,因为其只是作为测试效果,没有β与γ可以更新,而实现这种行为需要将test的行为调整过来之后,再使用batchnorm进行变换,如图所示

image.png


  • 使用Batch Norm的效果:

1)收敛速度更快

2)得到更好的结果

3)更加的稳定


6.经典神经网络的介绍


LeNet-5

image.png

这个卷积神经网络是80年代的产物。其有两个卷积层与一个池化层,最后再连接两个全连接层所组成。大概有5-6层组成。


AlexNet

image.png

由于当时的显卡性能不算出色,不能在一块上面完成任务,所以必须分为两个部分去训练,来讲显存分配开来。输入图像为3通道224*224。


模型特点:

1)由5个卷积层与3个全连接层组成

2)使用了Max pooling的操作

3)使用ReLU激活函数

4)使用Dropout来防止过拟合

5)具备一些很好的训练技巧,包括数据增广,学习率策略,Weight Decay等


VGG

VGG-Nets是有牛津大学VGG(Visual Geometry Group)提出,层数高达16或19层,一共有六个版本。

image.png

模型特点:

1)具有更深的网络结构

2)使用了较小的3x3的卷积核或者是1x1的小窗口


ps:1x1的卷积核实现了维度的改变,这是因为输出的维度只取决于使用使用多少个卷积核,而去输入的维度是没有关系的,输入的维度只有使用卷积核的通道数有关系。

image.png


GoogLeNet

image.png

模型特点:

1)使用了大小更小的卷积和,33或者甚至是11

2)采用全局平均池化层

3)使用了多个不同size的卷积核去提取特征,然后将结果聚合

image.png


ResNet

层数越高的网络其实在当时并没有提升准确率,有时时候甚至网络的层数越多,准确率越低,而ResNet可以解决这个问题,使其使用更深层次的网络的时候不至于比浅层次的网络的准确率要低。

image.png

其结构如下图,也就是ResNet是可以简化成VGG-19或者是其他的网络的

image.png


DenseNet

DenseNet是在ResNet的基础上拓展的,也就是后面的每一层都不仅仅与前一层有联系,还可以与前面的所有层有联系,结构图改变如下:

image.png


这样改变之后,通道数会越来越大,这一点需要注意


目录
相关文章
|
21天前
|
机器学习/深度学习 计算机视觉 Python
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力本文提出了一种简单且高效的卷积神经网络(ConvNets)注意力模块——SimAM。与现有模块不同,SimAM通过优化能量函数推断特征图的3D注意力权重,无需添加额外参数。SimAM基于空间抑制理论设计,通过简单的解决方案实现高效计算,提升卷积神经网络的表征能力。代码已在Pytorch-SimAM开源。
【YOLOv11改进 - 注意力机制】SimAM:轻量级注意力机制,解锁卷积神经网络新潜力
|
15天前
|
机器学习/深度学习 人工智能 自然语言处理
深度学习中的卷积神经网络:从理论到实践
【10月更文挑战第35天】在人工智能的浪潮中,深度学习技术以其强大的数据处理能力成为科技界的宠儿。其中,卷积神经网络(CNN)作为深度学习的一个重要分支,在图像识别和视频分析等领域展现出了惊人的潜力。本文将深入浅出地介绍CNN的工作原理,并结合实际代码示例,带领读者从零开始构建一个简单的CNN模型,探索其在图像分类任务中的应用。通过本文,读者不仅能够理解CNN背后的数学原理,还能学会如何利用现代深度学习框架实现自己的CNN模型。
|
14天前
|
机器学习/深度学习 人工智能 算法框架/工具
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【10月更文挑战第36天】探索卷积神经网络(CNN)的神秘面纱,揭示其在图像识别领域的威力。本文将带你了解CNN的核心概念,并通过实际代码示例,展示如何构建和训练一个简单的CNN模型。无论你是深度学习的初学者还是希望深化理解,这篇文章都将为你提供有价值的见解。
|
25天前
|
机器学习/深度学习 监控 自动驾驶
卷积神经网络有什么应用场景
【10月更文挑战第23天】卷积神经网络有什么应用场景
40 2
|
25天前
|
机器学习/深度学习 自然语言处理 算法
什么是卷积神经网络
【10月更文挑战第23天】什么是卷积神经网络
35 1
|
28天前
|
机器学习/深度学习 人工智能 算法
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
车辆车型识别,使用Python作为主要编程语言,通过收集多种车辆车型图像数据集,然后基于TensorFlow搭建卷积网络算法模型,并对数据集进行训练,最后得到一个识别精度较高的模型文件。再基于Django搭建web网页端操作界面,实现用户上传一张车辆图片识别其类型。
72 0
【车辆车型识别】Python+卷积神经网络算法+深度学习+人工智能+TensorFlow+算法模型
|
15天前
|
机器学习/深度学习 人工智能 自动驾驶
深入解析深度学习中的卷积神经网络(CNN)
深入解析深度学习中的卷积神经网络(CNN)
32 0
|
18天前
|
机器学习/深度学习 人工智能 TensorFlow
深度学习中的卷积神经网络(CNN)及其在图像识别中的应用
【10月更文挑战第32天】本文将介绍深度学习中的一个重要分支——卷积神经网络(CNN),以及其在图像识别领域的应用。我们将通过一个简单的代码示例,展示如何使用Python和TensorFlow库构建一个基本的CNN模型,并对其进行训练和测试。
|
24天前
|
机器学习/深度学习 自然语言处理 TensorFlow
深度学习中的卷积神经网络(CNN)及其应用
【10月更文挑战第26天】在这篇文章中,我们将深入探讨卷积神经网络(CNN)的基本原理、结构和应用。CNN是深度学习领域的一个重要分支,广泛应用于图像识别、语音处理等领域。我们将通过代码示例和实际应用案例,帮助读者更好地理解CNN的概念和应用。
|
26天前
|
机器学习/深度学习 算法 计算机视觉
深度学习与生活:如何利用卷积神经网络识别日常物品
【10月更文挑战第24天】在这篇文章中,我们将探索深度学习如何从理论走向实践,特别是卷积神经网络(CNN)在图像识别中的应用。通过一个简单的示例,我们将了解如何使用CNN来识别日常生活中的物体,如水果和家具。这不仅是对深度学习概念的一次直观体验,也是对技术如何融入日常生活的一次深刻反思。文章将引导读者思考技术背后的哲理,以及它如何影响我们的生活和思维方式。
下一篇
无影云桌面