来自一个编程都不懂的小白深度学习逆袭之路,关于Keras图像分类,轻量级MobileNetv1网络结构,训练预测和测试
当自己的电脑配置不这么好时,想快速实现代码,想试试调每个超参对网络带来怎么样的loss,acc改变可以采用MobileNet网络。优势在于快,轻便。同样的数据集训练,Mobilenet比VGG16快4倍左右!精度只比VGG差了0.2%(本人的测试,论文中比VGG16差了1%)
对于MobileNetv1的理解:
该网络最具代表性的就是深度可分离卷积模块(depthwise separable convolutions)
先来讲讲深度可分离卷积和普通卷积的计算
普通的卷积
输入特征图尺寸为H * W * C,被尺寸为h * w * k卷积,得到输出特征图为尺寸H’ * H’ * k’。(这里就不解释拉,自觉baidu卷积哈)
普通卷积的计算量为:H * W * C * K 3 3(这里拿33卷积)
深度卷积(depthwise):
把input feature分为 g组,每组尺寸为H * W (C/g),假设可整除,下同
把kernel也分为g组,每组尺寸为h * w * (k/g)
按顺序,每组input feature和kernel分别做普通卷积,输出 g组H’ * W’ * (k/g)特征,
即一共H’ * W’ * k
Depthwise的计算量为H * W * C 3 * 3
(个人的看图见解)
可以想象成输入为66 * 3的RGB图像,我此时需要拿一个同样是RGB的卷积核对他进行卷积,
这里我用4 * 4 * 3(RGB)卷积核对他进行卷积。然后将输入的图像和卷积核的RGB3层图像分离(看下左图)
然后一个对应着一个(RR)(BB)(GG)卷积。
卷积后你会发现你卷积核的通道数(可以理解成上面的RGB的3)取决于你输入图像的通道数,
当你输入进来的图像是灰度图(只有一个通道)那我的卷积核也只能是一个通道数,
这样就不能对图像进行一个比较好的特征提取。
伟大的发明家就想到可以采用一个1 * 1的卷积核对图像进行一个通道数的调整,增加目标的特征(下右图)
在MobileNet中这个11卷积操作名字叫做(Pointwise)命个名可能更加高大上把!
Pointwise计算量为:H * W * C *k
通过Depthwise+Pointwise的拆分,相当于将普通卷积的计算量压缩为:
可以看出,深度可分离卷积比普通卷积的参数量减少了9倍多
举个例子,大家会好理解一点!
当输入为6 X 6 X 3,要求输出为4 X 4 X 256,有两种方法:
第一:直接拿一个33256的卷积核,参数量为6 X 6 X 3 X 3 X 3 X 256=248832(6 X 6 X 3为图像大小,3 X 3 X 256为卷积核大小)
第二:使用深度可分离卷积,为为两步,先用3 * 3卷积然后1 * 1卷积
参数量为6 X 6 X 3 X 3 X 3 + 6 X 6 X 3 X 1 X 1 X 256 = 972+28620=29592
深度可分离卷积结构
左边是普通的卷积结果,一层3*3的卷积然后跟着Batch Normalization(归一化的作用:防止过拟合)和激活函数(Relu)
右边是深度可分离卷积结构:先是深度卷积对图像进行目标的提取,这里的目标提取不能改变通道数!(输入和输出的通道数一样)后面一样跟着Batch Normalization(归一化的作用:防止过拟合)和激活函数(Relu),拿1*1的卷积核对图像调整通道数!后来还是BN和激活
(这里不明白没用关系,看代码就好了)
注意:如果是需要下采样,则在第一个深度卷积上取步长为2.
MobileNet网络结构![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/dd9f358d4349e866bf95cf4bf9e6df3d.png)
超参数one:Mobilenet v1已经非常小了,但是还可以对所有卷积层统一乘以缩小因子 (其中 )以压缩网络。这样Depthwise+Pointwise总计算量可以进一降低(个人认为作用不太,代码depth_multiplier取值为1就好)
超参数tow:分辨率因子ρρ \rhoρ(resolution multiplier ).用于控制输入和内部层表示。即用分辨率因子控制输入的分辨率。(不太理解,希望大神评论区讲解。)
代码部分
'''
利于了深度可分离卷积,
正常的卷积核:输入的通道数是16 输出图像需要32,卷积核大小3*3*32 3*3*16*32=4608
深度可分离卷积核:输入的通道数是16 输出图像需要32,卷积核大小3*3*16和1*1*32
先用3*3*16对输入卷积,由于卷积后的通道数不足,在加上一个1*1*32的卷积增加通道数,3*3*16+16*32*1*1=656
depthwise conv最大的优势!
'''
import warnings
import numpy as np
import os
# os.environ['TF_CPP_MIN_LOG_LEVEL'] = '1'
from keras.preprocessing import image #数据增强
from keras.models import Model
from keras.layers import DepthwiseConv2D, Input, Activation, Dropout, Reshape, BatchNormalization, \
GlobalAveragePooling2D, GlobalMaxPooling2D, Conv2D,Dense,Flatten
from keras.applications.imagenet_utils import decode_predictions
from keras import backend as K
# _depthwise_conv_block 深度可分离卷积块
def MobileNet(input_shape=[224, 224, 3], # 导入图片的大小
depth_multiplier=1, #有时你需要更小的模型时就需要将输入和输出的计算量都减少,一般会取值1,0.75,0.5,0.25。缩小你的卷积大小和通道
dropout=1e-3, #dropout 带多少神经元进行训练
classes=1000): #分类1000,这个后面可以改的
img_input = Input(shape=input_shape) #转换为张量的形式,在tf和keras输入的值都是应该张量的形式
# 一阶的张量[1,2,3]的shape是(3,);一个二阶的张量[[1,2,3],[4,5,6]]的shape是(2,3);一个三阶的张量[[[1],[2],[3]],[[4],[5],[6]]]的shape是(2,3,1)。
# 224,224,3 -> 112,112,32
x = _conv_block(img_input, 32, strides=(2, 2)) # 输入 通道数 步数
# 112,112,32 -> 112,112,64
x = _depthwise_conv_block(x, 64, depth_multiplier, block_id=1) # 输入 通道数 depth_multiplier不进行缩小卷积核(计算量), block_id=1
# 112,112,64 -> 56,56,128
x = _depthwise_conv_block(x, 128, depth_multiplier,
strides=(2, 2), block_id=2)
# 56,56,128 -> 56,56,128
x = _depthwise_conv_block(x, 128, depth_multiplier, block_id=3)
# 56,56,128 -> 28,28,256
x = _depthwise_conv_block(x, 256, depth_multiplier,
strides=(2, 2), block_id=4)
# 28,28,256 -> 28,28,256
x = _depthwise_conv_block(x, 256, depth_multiplier, block_id=5)
# 28,28,256 -> 14,14,512
x = _depthwise_conv_block(x, 512, depth_multiplier,
strides=(2, 2), block_id=6)
# 14,14,512 -> 14,14,512
x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=7)
x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=8)
x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=9)
x = _depthwise_conv_block(x, 512, depth_multiplier, block_id=10)
x