微网站的搭建,企业建设网站目的是什么意思,购物网站开发可行性分析怎么写,莱芜网站设计公司CNN
视觉处理三大任务#xff1a;分类、目标检测、图像分割上游#xff1a;提取特征#xff0c;CNN下游#xff1a;分类、目标、分割等#xff0c;具体的任务 概述
卷积神经网络是深度学习在计算机视觉领域的突破性成果。在计算机视觉领域, 往往我们输入的图像都很大分类、目标检测、图像分割上游提取特征CNN下游分类、目标、分割等具体的任务 概述
卷积神经网络是深度学习在计算机视觉领域的突破性成果。在计算机视觉领域, 往往我们输入的图像都很大使用全连接网络的话计算的代价较高。另外图像也很难保留原有的特征导致图像处理的准确率不高。卷积神经网络Convolutional Neural NetworkCNN是一种专门用于处理具有网格状结构数据的深度学习模型。最初CNN主要应用于计算机视觉任务但它的成功启发了在其他领域应用如自然语言处理等。卷积神经网络Convolutional Neural Network是含有卷积层的神经网络. 卷积层的作用就是用来自动学习、提取图像的特征。
CNN网络主要有三部分构成卷积层、池化层和全连接层构成其中卷积层负责提取图像中的局部特征池化层用来大幅降低运算量并特征增强全连接层类似神经网络的部分用来输出想要的结果。
全连接的局限性
全连接神经网络并不太适合处理图像数据 参数量巨大
全连接结构计算量非常大假设我们有1000×1000的输入如果隐藏层也是1000×1000大小的神经元由于神经元和图像每一个像素连接则参数量会达到惊人的1000×1000×1000×1000仅仅一层网络就已经有个参数。
表达能力太有限
全连接神经网络的角色只是一个分类器如果将整个图片直接输入网络不仅参数量大也没有利用好图片中像素的空间特性增加了学习难度降低了学习效果。
卷积思想
卷从左往右从上往下积乘积求和
概念
局部连接
局部连接可以更好地利用图像中的结构信息空间距离越相近的像素其相互影响越大。根据局部特征完成目标的可辨识性。
权重共享
图像从一个局部区域学习到的信息应用到其他区域。减少参数降低学习难度。
卷积层
卷积核
1.卷积核是卷积运算过程中必不可少的一个“工具”在卷积神经网络中卷积核是非常重要的它们被用来提取图像中的特征。
2.卷积核其实是一个小矩阵在定义时需要考虑以下几方面的内容
卷积核的个数卷积核过滤器的个数决定了其输出特征矩阵的通道数。卷积核的值卷积核的值是自定义的根据想要提取的特征来进行设置后续进行更新。卷积核的大小常见的卷积核有1×1、3×3、5×5等一般都是奇数 × 奇数。
3.下图就是一个3×3的卷积核 卷积计算
卷积计算过程
1.卷积的过程是将卷积核在图像上进行滑动计算每次滑动到一个新的位置时卷积核和图像进行点对点的计算并将其求和得到一个新的值然后将这个新的值加入到特征图中最终得到一个新的特征图。 input 表示输入的图像filter 表示卷积核, 也叫做滤波器input 经过 filter 的得到输出为最右侧的图像该图叫做特征图左上角的点计算方法 按照上面的计算方法可以得到最终的特征图为: 2.卷积的重要性在于它可以将图像中的特征与卷积核进行卷积操作从而提取出图像中的特征。
3.可以通过不断调整卷积核的大小、卷积核的值和卷积操作的步长可以提取出不同尺度和位置的特征。
# 面相对象的模块化编程
from matplotlib import pyplot as plt
import os
import torch.nn as nn
import torchdef test001():# __file__当前文件current_path os.path.dirname(__file__)print(current_path)img_path os.path.join(current_path, ..\data,1.png)print(img_path:,img_path)# 转换为相对路径img_path os.path.realpath(img_path)print(img_realpath:,img_path)# 使用plt读取图片img plt.imread(img_path)print(img.shape)# 转换为张量:HWC--CHW--NCHW 链式调用# 深拷贝原图在进行链式操作返回一个新值img torch.Tensor(img).permute(2,0,1).unsqueeze(0)# 创建卷积核conv nn.Conv2d(in_channels4,# 输入通道数out_channels1,# 输出通道数# 如果要产出32个特征图那么就需要32个卷积核每个卷积核的通道数为这个卷积核的通道数为4# out_channels32,# 输出通道数kernel_size3,# 卷积核大小# kernel_size(5,3),# 卷积核大小stride1,# 步长padding0 # 填充# biasTrue
)# 使用卷积核对图像进行卷积操作out conv(img)# 把图片显示出来print(out.shape)# out[0][0]: 806, 574# out[0][0]:其中含有梯度等元素# detach叶子结点数据的引用只指向源数据不包含梯度等其他元素plt.imshow(out[0][0].detach().numpy(), cmapgray)# 取第32个卷积核的输出显示# plt.imshow(out[0][31].detach().numpy(), cmapgray)plt.show()# 作为主机模块执行
if __name__ __main__:test001()
# 面相对象的模块化编程
from matplotlib import pyplot as plt
import os
import torch.nn as nn
import torchdef test001():# __file__当前文件current_path os.path.dirname(__file__)print(current_path)img_path os.path.join(current_path, ..\data,1.png)print(img_path:,img_path)# 转换为相对路径img_path os.path.realpath(img_path)print(img_realpath:,img_path)# 使用plt读取图片img plt.imread(img_path)print(img.shape)# 转换为张量:HWC--CHW--NCHW 链式调用# 深拷贝原图在进行链式操作返回一个新值img torch.Tensor(img).permute(2,0,1).unsqueeze(0)# 创建卷积核conv nn.Conv2d(in_channels4,# 输入通道数# 如果要产出32个特征图那么就需要32个卷积核每个卷积核的通道数为这个卷积核的通道数为4out_channels32,# 输出通道数kernel_size(5,3),# 卷积核大小stride1,# 步长padding0,# 填充biasTrue
)# 使用卷积核对图像进行卷积操作out conv(img)# 输出128个特征图conv2 nn.Conv2d(in_channels32,# 输入通道数out_channels128,# 输出通道数# 如果要产出32个特征图那么就需要32个卷积核每个卷积核的通道数为这个卷积核的通道数为4kernel_size(5,3),# 卷积核大小stride1,# 步长padding0,biasTrue)out conv2(out)# 把图片显示出来print(out.shape)# out[0][0]: 806, 574# out[0][0]:其中含有梯度等元素# detach叶子结点数据的引用只指向源数据不包含梯度等其他元素# 取第32个卷积核的输出显示plt.imshow(out[0][31].detach().numpy(), cmapgray)plt.show()# 作为主机模块执行
if __name__ __main__:test001()
卷积计算底层实现
并不是水平和垂直方向的循环。下图是卷积的基本运算方式 卷积真正的计算过程如下图 边缘填充
Padding
通过上面的卷积计算我们发现最终的特征图比原始图像要小如果想要保持图像大小不变, 可在原图周围添加padding来实现更重要的边缘填充还更好的保护了图像边缘数据的特征。
步长Stride
按照步长为1来移动卷积核 如果我们把 Stride 增大为2 stride太小重复计算较多计算量大训练效率降低 stride太大会造成信息遗漏无法有效提炼数据背后的特征
多通道卷积计算
数字图像的标识
图像在计算机眼中是一个矩阵通道越多可以表达的特征就越丰富 具体计算实现
1.计算方法
当输入有多个通道(Channel), 例如RGB三通道, 此时要求卷积核需要有相同的通道数。卷积核通道与对应的输入图像通道进行卷积。将每个通道的卷积结果按位相加得到最终的特征图。 多卷积核卷积计算
实际对图像进行特征提取时, 我们需要使用多个卷积核进行特征提取。这个多个卷积核可以理解为从不同到的视角、不同的角度对图像特征进行提取。所有卷积核输出值决定了卷积和有几个 特征图大小
1.输出特征图的大小与以下参数息息相关:
size: 卷积核/过滤器大小一般会选择为奇数比如有 1×1, 3×3 5×5Padding: 零填充的方式Stride: 步长
2.例:
输入图像大小: W x W卷积核大小: F x FStride: SPadding: P输出图像大小: N x N 3.例:
图像大小: 5 x 5卷积核大小: 3 x 3Stride: 1Padding: 1(5 - 3 2) / 1 1 5, 即得到的特征图大小为: 5 x 5 连续卷积 卷积参数共享
数据是32×32×3的图像用 10 个 5×5×3 的filter来进行卷积操作所需的权重参数有多少个呢
5×5×3 75表示每个卷积核只需要75个参数。10个不同的卷积核就需要10*75 750个卷积核参数。如果还考虑偏置参数b最终需要 75010760 个参数。
局部特征提取
通过卷积操作CNN具有局部感知性能够捕捉输入数据的局部特征这在处理图像等具有空间结构的数据时非常有用。
PyTorch卷积层神经网络
import torch
import torch.nn.functional as Fclass MyNet(torch.nn.Module):def __init__(self):super(MyNet, self).__init__()# 第一层卷积30 (W - K 2P) /S 1输出的宽高因为此时是矩阵就计算一个表就行self.conv1 torch.nn.Conv2d(in_channels1, # 输入通道out_channels32, # 输出的通道kernel_size3, # 卷积核大小padding 0, # 填充stride1, # 步长)# 第二层输出128个通道:28 (W - K 2P) /S 1self.conv2 torch.nn.Conv2d(in_channels32, # 输入通道out_channels128, # 输出的通道kernel_size3, # 卷积核大小padding 0, # 填充stride1, # 步长)# 第三个通道输出512个通道:26 (W - K 2P) /S 1self.conv3 torch.nn.Conv2d(in_channels128, # 输入通道out_channels512, # 输出的通道kernel_size3, # 卷积核大小padding 0, # 填充stride1, # 步长)# 线性层做分类判断,10分类self.fc torch.nn.Linear(512*26*26, 10)def forward(self, x):# 卷积层x F.relu(self.conv1(x))print(x.shape)x F.relu(self.conv2(x))x F.relu(self.conv3(x))# 输出NCHW然后做全连接# x.size(0)输出的有几个Nx x.view(x.size(0), -1)print(x.shape)# 输入的数据有四条每条数据10个输出值x self.fc(x)# 每条数据进行激活每条数据有10分类x torch.nn.Softmax(dim1)(x)return xif __name__ __main__:# N 4 C1 H32 W32input torch.randn(4,1,32,32)model MyNet()out model(input)print(out)
池化层
概述
1.池化层 (Pooling) 降低维度, 缩减模型大小提高计算速度. 即: 主要对卷积层学习到的特征图进行下采样SubSampling处理。
2.池化层主要有两种:
1最大池化 max pooling
最大池化是从每个局部区域中选择最大值作为池化后的值这样可以保留局部区域中最显著的特征。最大池化在提取图像中的纹理、形状等方面具有很好的效果。
2平均池化 avgPooling
平均池化是将局部区域中的值取平均作为池化后的值这样可以得到整体特征的平均值。平均池化在提取图像中的整体特征、减少噪声等方面具有较好的效果。
池化层计算
整体结构 计算 步长Stride
计算方法和卷积核步长计算方法一致
边缘填充Padding 多通道池化计算
在处理多通道输入数据时池化层对每个输入通道分别池化而不是像卷积层那样将各个通道的输入相加。这意味着池化层的输出和输入的通道数是相等。 池化层的作用
1.池化操作的优势有
通过降低特征图的尺寸池化层能够减少计算量从而提升模型的运行效率。池化操作可以带来特征的平移、旋转等不变性这有助于提高模型对输入数据的鲁棒性。池化层通常是非线性操作例如最大值池化这样可以增强网络的表达能力进一步提升模型的性能。
2.池化也有缺点
池化操作会丢失一些信息这是它最大的缺点
池化API
API请参考具体官方文档torch.nn — PyTorch 2.5 documentationhttps://pytorch.org/docs/stable/nn.html#padding-layers
import torch
import torch.nn as nndef test01():torch.manual_seed(1)# 输入的特征图数据input torch.randint(0, 255, (1, 64, 224, 224), dtypetorch.float)print(input[0][0][0:4,:5])# 池化核pool nn.MaxPool2d(kernel_size2, # 池化核大小stride2, # 步长return_indicesTrue# 返回索引)# 对数据进行池化操作out, indices pool(input)print(indices)print(out.shape)if __name__ __main__:test01()
整体结构 卷积池化全连接神经网络框架
import torch
import torch.nn as nnclass numberModel(nn.Module):def __init__(self):super(numberModel, self).__init__()# 卷积层self.C1 nn.Sequential(nn.Conv2d(in_channels1, # 输入通道out_channels6, # 输出通道kernel_size5, # 卷积核大小stride1, # 步长padding0 # 填充), nn.ReLU())# 池化层self.S2 nn.MaxPool2d(kernel_size2,stride2,padding0)# 卷积层self.C3 nn.Sequential(nn.Conv2d(in_channels6, # 输入通道out_channels16, # 输出通道kernel_size5, # 卷积核大小stride1, # 步长padding0 # 填充), nn.ReLU())# 全连接层self.FC1 nn.Sequential(nn.Linear(16*5*5,120, biasTrue), nn.ReLU())self.FC2 nn.Sequential(nn.Linear(120,84, biasTrue), nn.ReLU())self.out nn.Sequential(nn.Linear(84,10, biasTrue), nn.Softmax(dim1))def forward(self, x):x self.C1(x)x self.S2(x)x self.C3(x)x self.S2(x)x x.view(x.size()[0],-1) # 自动计算的数量批次Batchx self.FC1(x)x self.FC2(x)x self.out(x)return x
if __name__ __main__:torch.manual_seed(1)# 网络model numberModel()# 输入数据 NCHWinput torch.randn(1, 1, 32, 32)# 输出结果output model(input)print(output)tensor([[0.1055, 0.0958, 0.1093, 0.0939, 0.0942, 0.0990, 0.1092, 0.0956, 0.0874,0.1102]], grad_fnSoftmaxBackward0)特征图变化 卷积知识扩展
卷积结果
二维卷积
分单通道版本和多通道版本。
单通道版本
之前所讲卷积相关内容其实真正意义上叫做二维卷积单通道卷积版本,即只有一个通道的卷积。 多通道版本
彩色图像拥有R、G、B这三层通道因此我们在卷积时需要分别针对这三层进行卷积 最后将三个通道的卷积结果进行合并元素相加得到卷积结果 三维卷积3D
二维卷积是在单通道的一帧图像上进行滑窗操作输入是高度H宽度W的二维矩阵。而如果涉及到视频上的连续帧或者立体图像中的不同切片就需要引入深度通道此时输入就变为高度H宽度W*深度C的三维矩阵。不同于二维卷积核只在两个方向上运动三维卷积的卷积核会在三个方向上运动因此需要有三个自由度。这种特性使得三维卷积能够有效地描述3D空间中的对象关系它在一些应用中具有显著的优势例如3D对象的分割以及医学图像的重构等。 反卷积
卷积是对输入图像及进行特征提取这样会导致尺寸会越变越小而反卷积是进行相反操作。并不会完全还原到跟输入图一样只是保证了与输入图像尺寸一致主要用于向上采样。从数学上看反卷积相当于是将卷积核转换为稀疏矩阵后进行转置计算。也被称为转置卷积。
反卷积计算过程
在2x2的输入图像上使用【步长1、边界全0填充】的3x3卷积核进行转置卷积反卷积计算向上采样后输出的图像大小为4x4。语义分割里面就需要反卷积还原到原始图像大小。 反卷积底层计算 空洞卷积膨胀卷积
为扩大感受野在卷积核矩阵的元素之间插入空格“膨胀”内核形成“空洞卷积”或称膨胀卷积并用膨胀率参dilationL表示要扩大内核的范围即在内核元素之间插入dilation-1个空格。当dilation1时则内核元素之间没有插入空格变为标准卷积。图中是dilation2的空洞卷积。 代码实现过程
import torch
import torch.nn as nndef test01():torch.manual_seed(1)#输入数据x torch.randn(1, 1, 7, 7)# 创建一个卷积核conv nn.Conv2d(in_channels1, # 输入通道数out_channels1, # 输出通道数kernel_size3, # 卷积核大小stride1, # 步长padding0, # 填充dilation2 # 卷积核的步长)out conv(x)print(out.shape)if __name__ __main__:test01()
torch.Size([1, 1, 3, 3])可分离卷积
空间可分离卷积
空间可分离卷积是将卷积核分解为两项独立的核分别进行操作。在数学中我们可以将矩阵分解 所以对3x3的卷积核我们同样可以拆分成 3x1 和 1x3 的两个卷积核对其进行卷积且采用可分离卷积的计算量比标准卷积要少。 代码实现过程
import torch
import torch.nn as nnclass nomalModel(nn.Module):def __init__(self):super(nomalModel, self).__init__()self.conv1 nn.Conv2d(in_channels1, # 输入通道out_channels1, # 输出通道kernel_size3, # 卷积核大小stride1, # 步长padding0,# 填充biasFalse # 是否使用偏置)def forward(self, x):out self.conv1(x)return outclass waveModel(nn.Module):def __init__(self):super(waveModel, self).__init__()self.conv1 nn.Conv2d(in_channels1, # 输入通道out_channels1, # 输出通道kernel_size(3,1), # 卷积核大小stride1, # 步长padding0,# 填充biasFalse, # 是否使用偏置groups1 # 分组卷积)self.conv2 nn.Conv2d(in_channels1, # 输入通道out_channels1, # 输出通道kernel_size(1,3), # 卷积核大小stride1, # 步长padding0,# 填充biasFalse, # 是否使用偏置groups1 # 分组卷积)def forward(self, x):out self.conv1(x)out self.conv2(out)return outif __name__ __main__:model1 nomalModel()# 打印参数for name, param in model1.named_parameters():print(name, param.shape)print()model2 waveModel()for name, param in model2.named_parameters():print(name, param.shape)
conv1.weight torch.Size([1, 1, 3, 3]) 3*3conv1.weight torch.Size([1, 1, 3, 1])3
conv2.weight torch.Size([1, 1, 1, 3])3 33深度可分离卷积
1.深度可分离卷积由两部组成深度卷积核1x1卷积
输入图的每一个通道我们都使用了对应的卷积核进行卷积。 通道数量 卷积核个数完成卷积后对输出内容进行1x1的卷积 代码实现
import torch
import torch.nn as nnclass normalModel(nn.Module):def __init__(self):super(normalModel, self).__init__()self.conv1 nn.Conv2d(in_channels8, # 输入通道out_channels8,# 输出通道kernel_size3, # 卷积核大小stride1, # 步长padding0, # 填充biasFalse # 是否使用偏置)def forward(self, x):out self.conv1(x)return outclass deepModel(nn.Module):def __init__(self) - None:super(deepModel, self).__init__()self.conv1 nn.Conv2d(in_channels8, # 输入通道out_channels8,# 输出通道kernel_size3, # 卷积核大小stride1, # 步长padding0, # 填充biasFalse, # 是否使用偏置groups8 # 分组卷积 卷积核数量等于输入通道的数量8/8 1)self.conv2 nn.Conv2d(in_channels8, # 输入通道out_channels8,# 输出通道kernel_size1, # 卷积核大小stride1, # 步长padding0, # 填充biasFalse # 是否使用偏置)def forward(self, x):x self.conv1(x)out self.conv2(out)return out
if __name__ __main__:conv1 normalModel()for name, param in conv1.named_parameters():print(name, param.shape) # 576print()conv2 deepModel()for name, param in conv2.named_parameters():print(name, param.shape) # 136
conv1.weight torch.Size([8, 8, 3, 3])conv1.weight torch.Size([8, 1, 3, 3])
conv2.weight torch.Size([8, 8, 1, 1])扁平卷积
扁平卷积是将标准卷积拆分成为3个1x1的卷积核然后再分别对输入层进行卷积计算。 标准卷积参数量XYC计算量为MNCXY拆分卷积参数量(XYC)计算量为MN(CXY)
分组卷积
2012年AlexNet论文中最先提出来的概念当时主要为了解决GPU显存不足问题将卷积分组放到两个GPU中并行执行。在分组卷积中卷积核被分成不同的组每组负责对相应的输入层进行卷积计算最后再进行合并。
混洗分组卷积
分组卷积中最终结果会按照原先的顺序进行合并组合阻碍了模型在训练时特征信息在通道间流动削弱了特征表示。混洗分组卷积主要是将分组卷积后的计算结果混合交叉在一起输出。 多通道卷积与偏执
卷积核卷完之后偏置矩阵就会与输出特征矩阵相加得到本次卷积的最终结果。
有两个结论
输入特征的通道数决定了卷积核的通道数卷积核通道个数输入特征通道个数。卷积核的个数决定了输出特征矩阵的通道数与偏置矩阵的通道数卷积核个数输出特征通道数偏置矩阵通道数。
感受野
理解感受野
字面意思是感受的视野范围,如果堆叠3个3 x 3的卷积层并且保持滑动窗口步长为1其感受野就是7×7的了 这跟一个使用7x7卷积核的结果是一样的 感受野的作用
假设输入大小都是h × w × C并且都使用C个卷积核(得到C个特征图)可以来计算 一下其各自所需参数