经典卷积架构:MobileNet-v2
MobileNet V2MobileNet V2在MobileNet V1的基础上,引入了线性瓶颈层(Linear Bottlenecks)和倒残差结构(Inverted residuals)。
Linear Bottlenecks作者认为,非线性的激活函数,比如ReLU,会导致信息的丢失。
具体地,作者将一个二维空间的流形( manifolds)通过一个后接ReLU激活的变换矩阵,嵌入到另一个维度的空间中,然后再投影回原来的二维空间。
结果显示:当另一个空间的维度较低(n=2,3,5)时,还原效果很差;当另一个空间维度高一些(n=15,30)时,才能够基本还原。
但是,在接下来你会看到,这里采用的Inverted residuals中的通道数会被最后一个1x1进行压缩,也就是要将3x3卷积提取的特征进行压缩,但这样做就对应了上述实验中另一个空间维度较低时的情况,即”信息丢失”。
针对这个问题,作者提出将卷积后的激活函数设置为线性的。实验证明,该方法能够有效保留信息。具体实现时,只需去掉本来在卷积后的非线性激活函数即可。
Inverted residuals在ResNet中,你已经见过 ...
经典卷积架构:MobileNet-v1
MobileNet V1MobileNet V1 有点像VGG,它们的网络结构都是单分支的,通俗点说就是:一条路走到底。
只不过,相比于VGG,MobileNet V1 大量使用了深度可分离卷积,在模型的预测能力变化很小的前提下,极大地提升了模型的速度。
ps:关于深度可分离卷积,可以查看这篇文章;关于VGG,可以查看这篇文章。
MobileNet V1 的网络结构如下:
其中,Conv表示普通卷积,Conv dw表示逐通道卷积,s1表示卷积步长为1,s2表示卷积步长为2。
PyTorch 实现 MobileNet V1对于普通的卷积,即上面结构图中的Conv直接调用torch.nn.Conv2d就可以了;
而在上面的网络结构图中,每一个蓝色框起来的两部分组合起来就是深度可分离卷积,它包括了逐通道卷积(Conv dw)和逐点卷积(Conv,kernel_size=1),其结构如下(左侧是普通卷积,右侧是深度可分离卷积):
根据这个结构,就可以写代码实现深度可分离卷积了:
1234567891011121314151617181920212223242526272829303132333 ...
经典卷积架构:Xception
XceptionXception将Inception中的Inception模块替换为深度可分离卷积。在几乎不增加参数量的前提下,Xception在一些图像分类任务中的表现超越了Inception V3。
我们之前介绍的深度可分离卷积是先做逐通道卷积,再做逐点卷积,而在Xception的论文描述中,这两步的顺序正好相反(见下图)。不过没关系,论文中也指出,这里的顺序并不影响效果(理由:in particular because these operations are meant to be used in a stacked setting.)。
同时,经过实验发现,深度可分离卷积中的卷积层之间不加非线性激活函数的效果相较于加入非线性激活函数来说会更好一些。
Xception的网络结构如下:
网络总共可以分为3个部分:Entry flow,Middle flow,以及Exit flow,并且借鉴了ResNet的思想,引入了跳连(skip connection)。注意每个卷积(包括普通卷积与深度可分离卷积)之后都做了批归一化操作,只是没在网络结构图中画出。
PyTorch 实现Xce ...
分组卷积与深度可分离卷积
分组卷积(Group Convolution)分组卷积将输入特征图进行分组,分别对每组的特征图进行卷积操作,得到输出的特征图,最后再将每组卷积后得到的特征图拼接在一起,就完成了整个卷积操作。
在PyTorch中,输入特征图个数与输出特征图个数需要能够被分组数整除,因为输出特征图个数需要均摊给每一组。比如输入特征图个数为X,输出特征图个数为Y,分组数为g,且g可整除X和Y,那么每一组的输入特征图个数为X/g,输出特征图个数为Y/g,总的输出特征图个数为(Y/g)*g=Y
假设输入特征图个数为6,卷积核尺寸为3*3,输出特征图个数为10,不考虑偏置项。以下操作基于本例》
普通卷积:当分组数为1时,就是普通的卷积
12345678910import torchimport torch.nn as nnfrom torchsummary import summaryclass Model(nn.Module): def __init__(self): super().__init__() self.conv=nn.Conv2d(in_channels=6,o ...
经典卷积架构:ResNet
ResNet一般来说,网络越深越复杂,同时网络提取特征的能力也就越强。但是,实验发现,当继续增加网络层数,使得网络越来越深时,网络能力不增反减。
似乎,当网络层数达到一定程度时,就达到了深度学习的天花板了?
ResNet的提出,解决了这一问题。深度学习的天花板还远着呢!
对于一个浅层网络,我们想在此基础上加深网络,同时希望加深后的网络至少能力不能退化。也就是说,新加进来的几层即使不能提升网络的能力,也不要影响到加入这些新的层之前的网络的能力。
具体地,直接将添加新的层之前的网络输出与添加新的层之后的网络输出做一个加法,然后让网络自己去学习新加进来的层是否起作用,起多大的作用。
这样,如果新加进来的层不怎么起作用,那么网络最终的输出就是添加新的层之前的输出,这样就能保证网络的能力至少不会因为网络的加深而退化。
这张图描绘了上述文字所要传达的思想:
对于浅层网络的输出x,有两个分支,一个分支直线向下,代表映射F,它将x映射为F(x);另一个分支直接将x连接到F(x)处,这被称之为skip connection(跳连)。这样,输出等于浅层网络的输出x与加深后的网络输出F(x)之和,即F(x ...
经典卷积架构:GoogLeNet
GoogLeNetGoogLeNet,也叫做Inception,没错,翻译过来就是《盗梦空间》。
相较于之前的网络,GoogLeNet网络层数更多,网络变得更深,网络结构也变得更加复杂。
不过,虽然网络结构复杂,但由于使用了1*1卷积来减少通道数,GoogLeNet所包含的参数不增反减,这也是GoogLeNet表现如此出众的重要原因之一。
GoogleNet的网络结构参数表如下:
type:网络层类型patch size/stride:(卷积核or池化窗口)尺寸/(卷积/池化)步长output size:该层输出特征图的shape
GoogLeNet重复使用了inception,和NiN基础块一样,它也是一个单独的块,不妨记作inception block,蓝色框起来的是便是inception block需要的参数。
inception block结构如下:
inception block使用了4个并行的分支,最后在通道维度上将4个分支的结果做了concat融合。这样,网络变宽了,我们无需考虑到底是用卷积层还是池化层,卷积核的尺寸是3x3还是5x5比较好,这一切,都交给模型,让模型自己 ...
语义分割中的IoU理论讲解+PyTorch实现
语义分割中的IoU之前的文章介绍过目标检测中的IoU,它等于预测框与真实框的交集区域面积除以并集区域面积。
在语义分割问题中,IoU经常被作为指标来评估模型学习的好坏。和目标检测中的IoU一样,语义分割中的IoU也是用预测结果和真实结果的交集除以并集。
只不过,语义分割问题并不像目标检测问题那样存在所谓的框,它通常是对每个像素进行分类,然后根据分类结果分别计算每个类别的交集和并集,从而进一步计算得到IoU。
因此,语义分割问题的IoU计算方式会与目标检测中IoU的计算方式会有所不同(两者思想一样,具体计算方式不一样)。
计算IoU需要预测类别和真实类别,后者是已知的,而前者需要模型去预测,再经过一些后处理得到。将模型预测值转为我们需要的预测类别的步骤(即:后处理过程)如下:
输入1张shape为C*H*W的图片,输出的shape为C'*H*W。C表示图片通道数,一般是3,C'表示语义分割问题的总类别数,比如一共有4类,那么C'=4。在C'所在维度上做个切片,比如C'[:,3,3]取了坐标为[3,3]的像素点在C'维度上的取值,该取值是一个 ...
经典卷积架构:NiN
NiNNiN在已有网络的基础上进行了改进,并且这些改进影响了后续网络模型的发展。经典之作,值得回味,今天我们就来一起实现它~
NiN的网络结构主要由多个NiN基础块堆叠而成。
1*1卷积NiN基础块含有3个卷积层,除了第一个卷积层,其余两个卷积层的卷积核尺寸都是1*1的,这种卷积核不会改变特征图的尺寸,并且可以在不增加太多参数量的前提下,实现通道数的变化,相当于是将每个通道上的特征图做了一个融合(比如,卷之前,维度是[C,224*224],卷之后,维度是[D,224*224],看吧,只有通道数发生了变化)。
全局平均池化在网络尾部进行分类结果输出时,NiN使用了全局平均池化层来代替之前的网络中使用的全连接层,这种提取全局信息的方式极大的减少了网络参数量,同时也不会像全连接层那样容易导致模型过拟合。你可以对比之前介绍的AlexNet,它在最后使用全连接层来输出分类结果,而这里的NiN使用的是全局平均池化。
NiN将网络最后一个NiN基础块的输出通道数设置为总类别数,紧接其后的全局平均池化层会在通道维度上对每张特征图求平均。假设总类别为10,那么就会有10个通道,经过全局平均池化层就能得到 ...
经典卷积架构:VGG系列
VGGVGG的提出者所在实验室名字为Visual Geometry Group ,因此就地取名,VGG诞生了。
VGG通过堆叠大量的VGG块,实现了更深的网络结构。
这里的VGG块,包含了多个卷积层一个池化层:
卷积层的卷积核尺寸为3*3,stride为1,padding为1;这种结构保证了输入图片(或特征图)经过卷积后得到的特征图的尺寸与输入尺寸是一样的。也就是或,卷积仅仅改变通道数,而不改变图像(特征图)的尺寸。
池化层的池化窗口尺寸和stride都是2,从而使得特征图的尺寸减半。
在堆叠的多个VGG块之后,是一些全连接层,负责最后的分类结果输出。
根据网络层数的不同,VGG有多个版本,如下图:
可以看出,不同版本之间的差异体现在卷积层(VGG 块个数不同),而全连接层是通用的。
在代码实现时,我们将写一个基本通用的框架,它可以帮助我们快捷实现不同版本的VGG。
注意:
我们将忽略现在已经不怎么使用的LRN,并且会添加一些现在常用的网络层,如ReLU,BN等。
对于图中的第4列(C),该框架不是通用的,因为含有1*1卷积。不过这对于实现来说完全不是问题,比如将全部层堆叠 ...
经典卷积架构:AlexNet
AlexNet在2012年的Imagenet竞赛中,AlexNet以低于第二名10.8个百分点的top-5错误率赢得了冠军,自此以后,基于CNN的图像分类算法开始流行起来,深度学习时代到来了。
AlexNet的网络结构如上图所示。相比于之前的LeNet-5,AlexNet堆叠了更多的卷积块,从而网络更深。同时,它还引入了Dropout的技巧,以及ReLU激活函数等。
在AlexNet刚被提出时,受限于当时的算力,作者采用了多个GPU进行训练。而随着技术的发展,现在的算力已经可以在单卡上训练AlexNet了,且显存绰绰有余。
更多细节,将在代码实现中体现。
PyTorch 实现AlexNet代码实现时,去除了现在已经很少被使用的LRN(局部响应归一化);并且将最后一个池化层由最大池化改为自适应平均池化,这种池化方法可以将不同尺寸的输入图片固定到特定尺寸,于是就可以固定住该池化层后面紧挨着的第一个全连接层的参数(最后一个池化层到第一个全连接之间有一个flatten操作,由于池化层输出的尺寸是固定的,因此flatten后再输入到这个全连接层的神经元个数也是固定的),使用起来更加方便。
12 ...