VGG16
VGG: VGG16模型的复现详解
但 VGG-16 的结构并不复杂,这点非常吸引人,而且这种网络结构很规整,都是
几个卷积层后面跟着可以压缩图像大小的池化层,池化层缩小图像的高度和宽度。同时,卷
积层的过滤器数量变化存在一定的规律,由 64 翻倍变成 128,再到 256 和 512。作者可能认
为 512 已经足够大了,所以后面的层就不再翻倍了。无论如何,每一步都进行翻倍,或者说
在每一组卷积层进行过滤器翻倍操作,正是设计此种网络结构的另一个简单原则。这种相对
一致的网络结构对研究者很有吸引力,而它的主要缺点是需要训练的特征数量非常巨大。
代码地址:https://github.com/bubbliiiing/classic-convolution-network/blob/master/VGG16.py
ResNet50
resnet50: ResNet50模型的复现详解
非常非常深的神经网络是很难训练的,因为存在梯度消失和梯度爆炸问题。这节课我们
学习跳跃连接(Skip connection),它可以从某一层网络层获取激活,然后迅速反馈给另外
一层,甚至是神经网络的更深层。我们可以利用跳跃连接构建能够训练深度网络的 ResNets,
有时深度能够超过 100 层,让我们开始吧
包含一个 shortcut connection 的几层网络被称为一个残差块(residual block)
如果没有残差,没有这些捷径或者跳跃连接,凭经验你会发现随着网络深度的加深,
训练错误会先减少,然后增多。而理论上,随着网络深度的加深,应该训练得越来越好才对。
也就是说,理论上网络深度越深越好。但实际上,如果没有残差网络,对于一个普通网络来
说,深度越深意味着用优化算法越难训练。实际上,随着网络深度的加深,训练错误会越来
越多。但有了 ResNets 就不一样了,即使网络再深,训练的表现却不错,比如说训练误差减少,
就算是训练深达 100 层的网络也不例外。
残差网络为什么有用?
我认为残差网络起作用的主要原因就是这些残差块学习恒等函数非常容易,你能确定网
络性能不会受到影响,很多时候甚至可以提高效率
resnet50的网络结构
代码地址:https://github.com/bubbliiiing/classic-convolution-network/blob/master/resnet50.py
bottleneck(瓶颈)的结构如下:
图2 两种ResNet设计
这两种结构分别针对ResNet34(左图)和ResNet50/101/152(右图),一般称整个结构为一个”building block“。其中右图又称为”bottleneck design”,目的一目了然,就是为了降低参数的数目,第一个1x1的卷积把256维channel降到64维,然后在最后通过1x1卷积恢复,整体上用的参数数目:1x1x256x64 + 3x3x64x64 + 1x1x64x256 = 69632,而不使用bottleneck的话就是两个3x3x256的卷积,参数数目: 3x3x256x256x2 = 1179648,差了16.94倍
对CNN模型,Param的计算方法如下:
(卷积核长度 * 卷积核宽度 *通道数+1)*卷积核个数
InceptionV3(Inception(盗梦空间))
而Inception网络则是采用不同大小的卷积核,使得存在不同大小的感受野,最后实现拼接达到不同尺度特征的融合。
Inception v1
参考: 一文概览Inception家族的「奋斗史」
总结一下,如果你在构建神经网络层的时候,不想决定池化层是使用 1×1,3×3 还是 5×5
的过滤器,那么 Inception 模块就是最好的选择。我们可以应用各种类型的过滤器,只需要
把输出连接起来。之后我们讲到计算成本问题,我们学习了如何通过使用 1×1 卷积来构建瓶
颈层,从而大大降低计算成本。
Google Inception Net在2014年的 ImageNet Large Scale Visual Recognition Competition (ILSVRC)中取得第一名,该网络以结构上的创新取胜,通过采用全局平均池化层取代全连接层,极大的降低了参数量,是非常实用的模型,一般称该网络模型为Inception V1。随后的Inception V2中,引入了Batch Normalization方法,加快了训练的收敛速度。在Inception V3模型中,通过将二维卷积层拆分成两个一维卷积层,不仅降低了参数数量,同时减轻了过拟合现象。
代码地址:https://github.com/bubbliiiing/classic-convolution-network/blob/master/Inception_v3.py
Xception
Xception是谷歌公司继Inception后,提出的InceptionV3的一种改进模型,其改进的主要内容为采用depthwise separable convolution来替换原来Inception v3中的多尺寸卷积核特征响应操作。
不过Xception模型中的depthwise separable convolution和普通的不太一样,普通的depthwise separable convolution是先进行3x3操作再进行1x1操作(就好像mobileNet中的一样),而Xception模型中则是先进行1x1操作然后再进行3x3操作,中间为了保证数据不被破坏,没有添加relu层,而mobileNet添加了relu层。在建立模型的时候,可以使用Keras中的SeparableConv2D层建立相应的功能。
注意:
keras中的深度可分离卷积有SeparableConv2D与c两种,
其中SeparableConv2D实现整个深度分离卷积过程,即深度方向的空间卷积 (分别作用于每个输入通道)+ 输出通道混合在一起的逐点卷积,
而DepthwiseConv2D仅仅实现前半部分的空间卷积 (分别作用于每个输入通道)。
2. 先前的工作
VGG-nets:模块堆叠的思想
Inception架构的网络族:最先证实多分支进行空间和通道关系映射的优势
深度可分离卷积:Xception架构正是基于此。深度可分离卷积用于神经网络的历史久远实现方式也有很多。
残差连接:也就是ResNet恒等快速连接和残差连接
代码地址:https://github.com/bubbliiiing/classic-convolution-network/blob/master/Xception.py
参考 :关于「Inception」和「Xception」的那些事
MobileNetV1
MobileNet是一种轻量级网络,相比于其它结构网络,它不一定是最准的,但是它真的很轻!
假设有一个3×3大小的卷积层,其输入通道为16、输出通道为32。具体为,32个3×3大小的卷积核会遍历16个通道中的每个数据,最后可得到所需的32个输出通道,所需参数为16×32×3×3=4608个。
应用深度可分离卷积,用16个3×3大小的卷积核分别遍历16通道的数据,得到了16个特征图谱。在融合操作之前,接着用32个1×1大小的卷积核遍历这16个特征图谱,所需参数为16×3×3+16×32×1×1=656个。
可以看出来depthwise separable convolution可以减少模型的参数。
代码地址:https://github.com/bubbliiiing/classic-convolution-network/blob/master/mobilenet.py
参考 : 轻量级神经网络“巡礼”(二)—— MobileNet,从V1到V3
MobileNetV2
创新点:
Linear bottleneck
也就是说,对低维度做ReLU运算,很容易造成信息的丢失。而在高维度进行ReLU运算的话,信息的丢失则会很少。
这就解释了为什么深度卷积的卷积核有不少是空。发现了问题,我们就能更好地解决问题。针对这个问题,可以这样解决:既然是ReLU导致的信息损耗,将ReLU替换成线性激活函数。
我们当然不能把所有的激活层都换成线性的啊,所以我们就悄咪咪的把最后的那个ReLU6换成Linear。(至于为什么换最后一个ReLU6而不换第一个和第二个ReLU6,看到后面就知道了。)
Expansion layer
现在还有个问题是,深度卷积本身没有改变通道的能力,来的是多少通道输出就是多少通道。如果来的通道很少的话,DW深度卷积只能在低维度上工作,这样效果并不会很好,所以我们要“扩张”通道。既然我们已经知道PW逐点卷积也就是1×1卷积可以用来升维和降维,那就可以在DW深度卷积之前使用PW卷积进行升维(升维倍数为t,t=6),再在一个更高维的空间中进行卷积操作来提取特征:
Inverted residuals
回顾V1的网络结构,我们发现V1很像是一个直筒型的VGG网络。我们想像Resnet一样复用我们的特征,所以我们引入了shortcut结构,这样V2的block就是如下图形式:
# 用于计算padding的大小,使其能被卷积核为(3,3),stride=2,后,长和宽变为原来的一半
def correct_pad(inputs, kernel_size):
img_dim = 1
input_size = backend.int_shape(inputs)[img_dim:(img_dim + 2)]
if isinstance(kernel_size, int):
kernel_size = (kernel_size, kernel_size)
if input_size[0] is None:
adjust = (1, 1)
else:
adjust = (1 - input_size[0] % 2, 1 - input_size[1] % 2)
correct = (kernel_size[0] // 2, kernel_size[1] // 2)
return ((correct[0] - adjust[0], correct[0]),
(correct[1] - adjust[1], correct[1]))
# 使其结果可以被8整除,因为使用到了膨胀系数α
def _make_divisible(v, divisor, min_value=None):
if min_value is None:
min_value = divisor
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
if new_v < 0.9 * v:
new_v += divisor
return new_v
代码地址:https://github.com/bubbliiiing/classic-convolution-network/blob/master/mobilenetV2.py#L63
参考 :https://zhuanlan.zhihu.com/p/70703846
自动下载后模型的位置在C:\Users\Sun.keras\models