赞
踩
https://arxiv.org/pdf/1409.4842.pdf
传统的模块提升网络性能的方法是增加网络深度和宽度(卷积核的个数),但是会存在一些问题:
1.参数量太大,如果训练数据集有限,很容易产生过拟合
。
2.网络模型越大,参数越多,则计算复杂度越大,对内存的占用和计算量的要求很高
。
3.网络结构越深,容易出现梯度弥散问题(最后的梯度为0),导致难以优化模型
。
有一种解决方式是增加网络的深度和宽度的同时减少参数,为了减少参数一种方式是将全连接变成稀疏连接(Dropout)。但实际上稀疏连接的计算性能并不会有质的提升。这是因为大部分硬件是针对密集矩阵计算优化的。
GooLeNet提出了一种Inception网络结构,构造一种“基础神经元”结构,来搭建一个稀疏性,高计算性能的网络结构。既能保持网络结构的稀疏性,又能利用密集矩阵的高计算性能。
注:上一层的卷积输入(Previous layer)经过并行的四个不同大小卷积核进行卷积运算,最后将经过卷积运算的特征图进行拼接(注意:拼接的特征图height和width相同,output_channels可以不同),最后输出Filter concatenation
计算量:假设输入的图像是 28x28x256的图像大小:
(1)第一个卷积核1x1x128: 28x28x128x1x1x256=25,690,112
(2)第二个卷积核3x3x192:28x28x192x3x3x256=346,816,512
(3)第三个卷积核5x5x96:28x28x96x5x5x256=481,689,600
总的计算量约等于为:855M
结构原理:
注: 这样的结构的缺点是随着网络结构的加深,最后叠加的厚度越来越厚,导致最后的计算量爆炸。
注:改进的inception模块,上一层的卷积输入(Previous layer)首先需要经过1x1的卷积进行升维,最后经过不同大小的卷积核再进行卷积运算,最后得到的特征图进行拼接,得到Filter concatenation.
改进模块计算量:假设输入的图像是 28x28x256的图像大小:
(1)第一个1x1x128卷积核:28x28x128x1x1x256=25,690,112
(2)第二个1x1x64卷积核:28x28x64x1x1x256=12,845,056
第二个1x1x64卷积核之后的3x3x192卷积核:28x28x192x3x3x64=86,704,128
(3)第三个1x1x64卷积核:28x28x64x1x1x256=12,845,056
第三个1x1x64卷积核之后的5x5x96卷积核:28x28x96x5x5x64=120,422,400
(4)第四个1x1x64卷积核:28x28x64x1x1x256=12,845,056
总的计算量约等于:272M
对比:通过上面的计算量结果可以看出,使用1x1的卷积核对于降维和降低
计算量非常的重要
可以参考我的这篇博文:
https://mydreamambitious.blog.csdn.net/article/details/123027344
(1)采用多尺度的卷积运算不管图片中的物体是大还是小,都能提取到相应的特征进行学习和训练
;
(2)如果图片中的物体很大,甚至差不多占据了整个图片,那么这个时候采用大的卷积核进行卷积,能获取更大的感受野,很好的提取图片中物体的特征
;
(3)如果是小物体,那么采用小的卷积核进行特征的提取,当然也可以使用多个小的卷积核达到大卷积核的效果,并且计算量更加的低
;
(4)最后将经过较大的卷积核卷积和经过较小的卷积核卷积之后叠加在一起,那么最终的特征将更加的丰富,既包含了提取大物体的特征,也包含了提取小物体的特征
。
注:卷积神经网络中,感受野(Receptive Field)的定义是卷积神经网络每一层输出的特征图(feature map)上的像素点在输入图片上映射的区域大小。
提高模型性能的传统方法:
适用大规模标注好的数据集。
两个相连的卷积层,两层同步增加卷积核的个数,那么计算机量将平方增加;
如果很多权重训练后接近0的话,那么这部分计算就被浪费,所以不能考虑计算效率不计成本的追求精度。
(1)将稀疏矩阵分解为密集的子矩阵,能加速矩阵乘法运算(在inception中使用密集的木块取代稀疏模块);
使用全局平均池化层代替了全连接层(GlobalAveragePooling):
注:Top-1表示第一个预测的就是正确结果;Top-5表示前五个预测的结果中包含正确结果。
注:浅层的辅助分类器在后面被证实没有太大的用处,作者在InceptionV2/InceptionV3去掉了浅层辅助分类器。
(1)7个模型集成,每个模型使用相同的初始化方法,甚至是相同的初始值,相同的学习策略,仅在图像采样和输入顺序有区别;
(2)将图像缩放为边长度为256 288 320 352的四个尺度,每个尺度裁剪出左,中,右(或者上中下)三张小图片,每张小图取其四个角和中央的五张224x224的patch,以及每张小图缩放至224x224共6个patch,同时取其镜像得到:4x3x6x2=144个patch。
(3)对144个patch的softmax分类结果取平均值。
使用mAP作为模型评估指标,每个类别不同阈值下的precision-recall曲线图围成的面积——AP;不同类别的AP求平均——mAP.
注:其中的两个辅助分类器这里并没有给出来。
import os import keras import numpy as np import tensorflow as tf from tensorflow.keras import layers from tensorflow.keras.applications.inception_v3 import preprocess_input,decode_predictions def load_model(): model_inception=tf.keras.applications.inception_v3.InceptionV3(weights='imagenet') return model_inception #搭建inceptionV1模块(实现的是改进的模块) class InceptionV1Block(tf.keras.Model): """ filter11:1x1的卷积核个数 filter13:3x3卷积之前的1x1卷积核个数 filter33:3x3卷积个数 filter15:5x5卷积之前的1x1卷积核个数 filter55:5x5卷积个数 filtermax:最大池化之后的1x1卷积核个数 """ def __init__(self,filter11,filter13,filter33,filter15,filter55,filtermaxpool11): super(InceptionV1Block, self).__init__() self.conv11=layers.Conv2D(filter11,kernel_size=[1,1],strides=[1,1],padding='same') self.conv13=layers.Conv2D(filter13,kernel_size=[1,1],strides=[1,1],padding='same') self.conv33=layers.Conv2D(filter33,kernel_size=[3,3],strides=[1,1],padding='same') self.conv15=layers.Conv2D(filter15,kernel_size=[1,1],strides=[1,1],padding='same') self.conv55=layers.Conv2D(filter55,kernel_size=[5,5],strides=[1,1],padding='same') self.maxpool=layers.MaxPool2D(pool_size=[3,3],strides=[1,1],padding='same') self.maxconv11=layers.Conv2D(filtermaxpool11,kernel_size=[1,1],strides=[1,1],padding='same') self.relu=layers.Activation('relu') def call(self,inputs,training=None): x11=self.conv11(inputs) x11=self.relu(x11) x13=self.conv13(inputs) x13=self.relu(x13) x33=self.conv33(x13) x33=self.relu(x33) x15=self.conv15(inputs) x15 = self.relu(x15) x55=self.conv55(x15) x55 = self.relu(x55) xmaxpool=self.maxpool(inputs) xmaxconv11=self.maxconv11(xmaxpool) xmaxconv11 = self.relu(xmaxconv11) #对通道数进行堆叠 output_x=tf.concat([x11,x55,x33,xmaxconv11],axis=3) return output_x # inceptionModule=InceptionV1Block(128,64,192,64,96,64) # inceptionModule.build(input_shape=(None,28,28,256)) # inceptionModule.summary() class GoogLeNet(tf.keras.Model): def __init__(self,layersFilters,num_classes): super(GoogLeNet, self).__init__() #输入部分 self.Input1=keras.Sequential([ layers.Conv2D(64, kernel_size=[7, 7], strides=[2, 2], padding='same'), layers.Activation('relu'), layers.MaxPool2D(pool_size=[3, 3], strides=[2, 2], padding='same'), layers.BatchNormalization(), ]) self.Input2=keras.Sequential([ layers.Conv2D(64, kernel_size=[1, 1], strides=[1, 1], padding='same'), layers.Activation('relu'), layers.Conv2D(192, kernel_size=[3, 3], strides=[1, 1], padding='same'), layers.Activation('relu'), layers.BatchNormalization() ]) #中间的模块 self.maxpool = layers.MaxPool2D(pool_size=[3, 3], strides=[2, 2], padding='same') self.build_inceptionModule3a = self.build_InceptionModuels(0, layersFilters) self.build_inceptionModule3b = self.build_InceptionModuels(1, layersFilters) self.build_inceptionModule4a = self.build_InceptionModuels(2, layersFilters) self.build_inceptionModule4b = self.build_InceptionModuels(3, layersFilters) self.build_inceptionModule4c = self.build_InceptionModuels(4, layersFilters) self.build_inceptionModule4d = self.build_InceptionModuels(5, layersFilters) self.build_inceptionModule4e = self.build_InceptionModuels(6, layersFilters) self.build_inceptionModule5a = self.build_InceptionModuels(7, layersFilters) self.build_inceptionModule5b = self.build_InceptionModuels(8, layersFilters) #输出部分 self.globalaveragepooling=layers.GlobalAveragePooling2D() self.dropout=layers.Dropout(0.4) self.dense=layers.Dense(num_classes) self.softmax=layers.Activation('softmax') def build_InceptionModuels(self,i,layersFilters): self.resInceptinBlocks = keras.Sequential([]) key = (list)(layersFilters.keys()) print(key[i]) if i==7 or i==2: #在模块中间插入的最大池化 self.maxpool=keras.Sequential([ layers.MaxPool2D(pool_size=[3,3],strides=[2,2],padding='same') ]) self.resInceptinBlocks.add(self.maxpool) self.resInceptinBlocks.add(InceptionV1Block((int)(layersFilters[key[i]][0]), (int)(layersFilters[key[i]][1]), (int)(layersFilters[key[i]][2]), (int)(layersFilters[key[i]][3]), (int)(layersFilters[key[i]][4]), (int)(layersFilters[key[i]][5]))) return self.resInceptinBlocks def call(self,inputs,training=None): x = self.Input1(inputs) x = self.Input2(x) x = self.maxpool(x) x = self.build_inceptionModule3a(x) x = self.build_inceptionModule3b(x) x = self.build_inceptionModule4a(x) x = self.build_inceptionModule4b(x) x = self.build_inceptionModule4c(x) x = self.build_inceptionModule4d(x) x = self.build_inceptionModule4e(x) x = self.build_inceptionModule5a(x) x = self.build_inceptionModule5b(x) x = self.globalaveragepooling(x) x = self.dropout(x) x = self.dense(x) output_1000=self.softmax(x) return output_1000 layerFilters={} layerFilters.update({'3a':[64,96,128,16,32,32]}) layerFilters.update({'3b':[128,128,192,32,96,64]}) layerFilters.update({'4a':[192,96,208,16,48,64]}) layerFilters.update({'4b':[160,112,224,24,64,64]}) layerFilters.update({'4c':[128,128,256,24,64,64]}) layerFilters.update({'4d':[112,144,288,32,64,64]}) layerFilters.update({'4e':[256,160,320,32,128,128]}) layerFilters.update({'5a':[256,160,320,32,128,128]}) layerFilters.update({'5b':[384,192,384,48,128,128]}) keys=(list)(layerFilters.keys()) print(keys[0]) print(layerFilters[keys[0]][0]) model_GoogLeNet=GoogLeNet(layersFilters=layerFilters,num_classes=1000) model_GoogLeNet.build(input_shape=(None,224,224,3)) model_GoogLeNet.summary() if __name__ == '__main__': print('Pycharm') # model_inception=load_model() # model_inception.summary()
关于数据集和训练的代码参考这篇文章:
https://mydreamambitious.blog.csdn.net/article/details/123966676
只需要将代码中的网络结构换成上面的这个InceptionV1结构即可训练。但是有一点要注意就是我给出的这个网络结构最后输出类别为1000,而训练数据集的代码只有两个类别。
训练完两代之后的结果。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。