• tensorflow2 inceptionv3训练猫狗数据
2019-09-25 22:00:32

这里用迁移的inceptionv3网络来实现猫狗数据的训练
具体的inceptionv3网络结构可以在我的上一篇博客中找到
从kaggle上面下载数据，用其他数据也行，准确度可达99%左右，好评给个star
数据放置结构按我的GitHub上面的就行，地址在这里
导入相应的包

from tensorflow.keras.models import *
from tensorflow.keras.layers import *
from tensorflow.keras.applications import *
from tensorflow.keras.preprocessing.image import *
from tensorflow import keras as keras
import numpy as np
import cv2
from  PIL import Image
import matplotlib.pyplot as plt


导入inceptionv3模型，重新添加一个最后的全连接层，并进行训练

base_model = InceptionV3(input_tensor=Input(shape=(299, 299, 3)),weights='imagenet', include_top=False)
#base_model.summary()
x = base_model.output
x = GlobalAveragePooling2D()(x)
# let's add a fully-connected layer
x = Dense(1024, activation='relu')(x)
# and a logistic layer -- let's say we have 200 classes
predictions = Dense(2, activation='softmax')(x)
model = Model(base_model.input, predictions)



定义迁移学习函数，冻结所有的 base_model 层，不训练。
要训练也行，博主没有去训练，效果也还行

    for layer in base_model.layers:
layer.trainable = False
model.compile(
optimizer=keras.optimizers.SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy', metrics=[keras.metrics.SparseCategoricalAccuracy()]
)



冻结连接层前面的172层之前的网络，去训练我们的数据

    model.compile(keras.optimizers.SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy', metrics=['accuracy'])
history_ft = model.fit_generator(
train_generator,
steps_per_epoch=100,
epochs=10,
validation_data=validation_generator,
validation_steps=50,
)

更多相关内容
• GoogLeNet Inception v1 结构 及 pytorch、tensorflow、keras、paddle实现ImageNet...# @File : InceptionV1-tensorflow.py import sys, cv2, os import numpy as np import pandas as pd from PIL import Image impo
• class InceptionV1(object): def __init__(self): self.n_input = 224*224*3 self.n_classes = 2 self.batch_size = 10 self.training_iters = 20 self.display_step = 20 self.learning_rate = 0.001 def...

总结参考：

https://blog.csdn.net/weixin_43624538/article/details/84863685

https://blog.csdn.net/mao_xiao_feng/article/details/53350798

重点:

A fundamental way of solving both of these issues would be to introduce sparsity and replace the fully connected layers by the sparse ones, even inside the convolutions. Besides mimicking biological systems, this would also have the advantage of firmer theoretical underpinnings due to the groundbreaking work of Arora et al. [2]. Their main result states that if the probability distribution of the dataset is representable by a large, very sparse deep neural network, then the optimal network topology can be constructed layer after layer by analyzing the correlation statistics of the preceding layer activations and clustering neurons with highly correlated outputs. Although the strict mathematical proof requires very strong conditions, the fact that this statement resonates with the well known Hebbian principle —— neurons that fire together, wire together —— suggests that the underlying idea is applicable even under less strict conditions, in practice.
解决这两个问题的一个基本的方式就是将全连接层替换为稀疏的全连接层，甚至在卷积层内部。除了模仿生物系统之外，由于Arora等人的开创性工作，这也将具有更坚实的理论基础的优势[2]。它们的主要结果是，如果数据集的概率分布可以用一个大的、非常稀疏的深层神经网络来表示， 则最优的网络拓扑结构可以通过分析前一层激活的相关性统计和聚类高度相关的神经元来一层层的构建。尽管严格的数学证明需要很强的条件，但这一说法与众所周知的Hebbian原理产生了共鸣-神经元一起激发、一起连接-这表明，即使在实际中，在不太严格的条件下，这种基本思想也是适用的。
Hebbian principle
目前图像领域的深度学习，是使用更深的网络提升representation power，从而提高准确率，但是这会导致网络需要更新的参数爆炸式增长，导致两个严重的问题：
1、网络更容易过拟合，当数据集不全的时候，过拟合更容易发生，于是我们需要为网络feed大量的数据，但是制作样本集本身就是一件复杂的事情。
2、大量需要更新的参数就会导致需要大量的计算资源，而当下即使硬件快速发展，这样庞大的计算也是很昂贵的

解决以上问题的根本方法就是把全连接的网络变为稀疏连接（卷积层其实就是一个稀疏连接），当某个数据集的分布可以用一个稀疏网络表达的时候就可以通过分析某些激活值的相关性，将相关度高的神经元聚合，来获得一个稀疏的表示。
这种方法也呼应了Hebbian principle，一个很通俗的现象，先摇铃铛，之后给一只狗喂食，久而久之，狗听到铃铛就会口水连连。这也就是狗的“听到”铃铛的神经元与“控制”流口水的神经元之间的链接被加强了，而Hebbian principle的精确表达就是如果两个神经元常常同时产生动作电位，或者说同时激动（fire），这两个神经元之间的连接就会变强，反之则变弱（neurons that fire together, wire together）
四、Inception结构
通过上述的分析，作者提出了Inception结构，这是一种高效表达特征的稀疏性结构。基于底层的相关性高的单元，通常会聚集在图像的局部区域（因为通常CNN底层卷积提取的都是局部特征），这就相当于在单个局部区域上，我们去学习它的特征，然后在高层用1*1卷积代替这个区域，当然某些相关性可能是隔得比较远的，通过使用大的卷积核学习即可。
最后就是这样的一个结构：

模型结构：

代码(命名冲突那里bug了挺久):

import tensorflow as tf
import cv2
import numpy as np
import os
from PIL import Image
from sklearn.model_selection import train_test_split
class InceptionV1(object):
def __init__(self):
self.n_input = 224*224*3
self.n_classes = 2
self.batch_size = 10
self.training_iters = 20
self.display_step = 20
self.learning_rate = 0.001

return tf.layers.conv2d(inputs=x,filters=filters,kernel_size=k_size,

def dropoutx(self,x,d_rate):
return tf.layers.dropout(x,rate=d_rate)

def inception_moudle_v1(self,x,filters_num,scope='layers'):
with tf.variable_scope(scope):
# tf.reset_default_graph()
bh1 = self.conv2d(x,filters=filters_num[0],k_size=[1,1],strides=[1,1],scope=scope+'1')

bh2 = self.conv2d(x,filters=filters_num[1],k_size=[1,1],strides=[1,1],scope=scope+'2')
bh2 = self.conv2d(bh2,filters=filters_num[2],k_size=[3,3],strides=[1,1],scope=scope+'3')

bh3 = self.conv2d(x,filters=filters_num[3],k_size=[1,1],strides=[1,1],scope=scope+'4')
bh3 = self.conv2d(bh3,filters=filters_num[4],k_size=[5,5],strides=[1,1],scope=scope+'5')

bh4 = self.maxpool2d(x,pool_size=[3,3],strides=[1,1])
bh4 = self.conv2d(bh4,filters=filters_num[5],k_size=[1,1],strides=[1,1],scope=scope+'6')

return tf.concat([bh1,bh2,bh3,bh4],axis=3)

def set_net(self,x,keep_prob,is_train=True):
check_point = {}
net = tf.reshape(x,[-1,224,224,3])
print(net)
net = self.conv2d(net,filters=64,k_size=[7,7],strides=[2,2],scope='conv1_1')
net = self.maxpool2d(net,pool_size=[3,3],scope='pool1')

net = self.conv2d(net,filters=64,k_size=[1,1],strides=[1,1],scope='conv2_1')
net = self.conv2d(net,filters=192,k_size=[3,3],strides=[1,1],scope='conv2_2')
net = self.maxpool2d(net,pool_size=[3,3],scope='pool2')

net = self.inception_moudle_v1(net,[64,96,128,16,32,32],scope='layer1')
net = self.inception_moudle_v1(net,[128,128,192,32,96,64],scope='layer2')
net = self.maxpool2d(net,pool_size=[3,3],scope='pool3')

net = self.inception_moudle_v1(net, [192, 96, 208, 16, 48, 64],scope='layer3')
net = self.inception_moudle_v1(net, [160, 112, 224, 24, 64, 64],scope='layer4')
net_1 = net
net = self.inception_moudle_v1(net,  [128, 18, 256, 24, 64, 64],scope='layer5')
net = self.inception_moudle_v1(net,  [112, 144, 288, 32, 64, 64],scope='layer6')
net_2 = net
net = self.inception_moudle_v1(net, [256, 160, 320, 32, 128, 128],scope='layer7')
net = self.maxpool2d(net, pool_size=[3,3], scope='pool4')
net = self.inception_moudle_v1(net,  [256, 160, 320, 32, 128, 128],scope='layer8')
net = self.inception_moudle_v1(net, [384, 192, 384, 48, 128, 128],scope='layer9')

net = self.avgpool2d(net, pool_size=[7,7], strides=[1,1], padding='VALID', scope='layer26')
net = self.dropoutx(net,d_rate=keep_prob)
net = self.conv2d(net, filters=2, k_size=[1,1],strides=[1,1], activation=None, scope='layer27')
net = tf.squeeze(net, [1, 2], name='squeeze')
# 该函数返回一个张量，这个张量是将原始input中所有维度为1的那些维都删掉的结果
# axis可以用来指定要删掉的为1的维度，此处要注意指定的维度必须确保其是1，否则会报错
# #  't' 是一个维度是[1, 2, 1, 3, 1, 1]的张量
# tf.shape(tf.squeeze(t))  # [2, 3]， 默认删除所有为1的维度
# # 't' 是一个维度[1, 2, 1, 3, 1, 1]的张量
# tf.shape(tf.squeeze(t, [2, 4]))  # [1, 2, 3, 1]，标号从零开始，只删掉了2和4维的1

net = tf.nn.softmax(net)

if is_train:
net_1 = self.avgpool2d(net_1, pool_size=[5,5], padding='VALID', strides=[1,1], scope='auxiliary0_avg')
net_1 = self.conv2d(net_1, filters=128, k_size=[1,1],strides=[1,1],scope='auxiliary0_conv_1X1')
net_1 = tf.layers.flatten(net_1)
net_1 = tf.layers.dense(net_1, 1024)
net_1 = self.dropoutx(net_1, 0.7)
net_1 = tf.layers.dense(net_1, 2,activation=None)
net_1 = tf.nn.softmax(net_1)

net_2 = self.avgpool2d(net_2, pool_size=[5,5], padding='VALID', strides=[3,3], scope='auxiliary1_avg')
net_2 = self.conv2d(net_2, filters=128, k_size=[1,1],strides=[1,1],scope='auxiliary1_conv_1X1')
net_2 = tf.layers.flatten(net_2)
net_2 = tf.layers.dense(net_2, 1024)
net_2 = self.dropoutx(net_2, 0.7)
net_2 = tf.layers.dense(net_2, 2, activation=None)
net_2 = tf.nn.softmax(net_2)

net = net_1 * 0.3 + net_2 * 0.3 + net * 0.4
return net

def inceptionv1_prediction(self, X,Y, scope='vgg'):
X_train, X_vaild, y_train, y_vaild = train_test_split(X, Y, test_size=0.2)
x = tf.placeholder(tf.float32, [None, self.n_input])
y = tf.placeholder(tf.float32, [None, self.n_classes])

pred = self.set_net(x,0.8)  # pred是计算完的值，此时还没归一化
a = tf.nn.softmax(pred)  # a是归一化后的值。

# 定义损失函数和学习步骤
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=y))  # 这个是损失loss
# 测试网络
correct_pred = tf.equal(tf.argmax(pred, 1), tf.argmax(y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))
# 初始化所有的共享变量
init = tf.initialize_all_variables()
with tf.Session() as sess:
sess.run(init)
step = 1
# Keep training until reach max iterations
while step * self.batch_size < self.training_iters:  # 直到达到最大迭代次数，没考虑梯度！！！
batch_xs, batch_ys = X_train[self.batch_size*(step-1):self.batch_size*step],y_train[self.batch_size*(step-1):self.batch_size*step]
batch_xs = np.reshape(batch_xs,(-1,self.n_input))
print('~!!!!!!!!',batch_xs.shape)
print(batch_ys.shape)
# 获取批数据
sess.run(optimizer, feed_dict={x: batch_xs, y: batch_ys})
if step % self.display_step == 0:  # 每一步里有64batch，64*20=1280
# 计算精度
acc = sess.run(accuracy, feed_dict={x: batch_xs, y: batch_ys})
# 计算损失值
loss = sess.run(cost, feed_dict={x: batch_xs, y: batch_ys})
print("Iter " + str(step * self.batch_size) + ", Minibatch Loss= " + "{:.6f}".format(
loss) + ", Training Accuracy = " + "{:.5f}".format(acc))
step += 1
print("Optimization Finished!")
# 计算测试精度
X_vaild = np.reshape(X_vaild, (-1, self.n_input))
print("Testing Accuracy:", sess.run(accuracy,
feed_dict={x: X_vaild[:256], y: y_vaild[:256],
}))  # 拿前256个来测试
print("Testing Result:", sess.run(a, feed_dict={x: X_vaild[63:64], y: y_vaild[63:64],
}))  # 数组范围，从0开始，含左不含右

展开全文
• tensorflow实现Inception v3源代码，只有模型构建的代码，还没有训练和测试，不过套路都一样的。
• 本例提取了猫狗大战数据集中的部分数据做数据集，演示tensorflow2.X版本如何使用Keras实现图像分类，分类的模型使用InceptionV3。本文实现的算法有一下几个特点： 1、自定义了图片加载方式，更加灵活高效，不用将...
• 本文所包含代码GitHub地址：https://github.com/shankezh/DL_HotNet_Tensorflow 如果对机器学习有兴趣，不仅仅满足将深度学习模型当黑盒模型使用的，想了解为何机器学习可以训练拟合最佳模型，可以看我过往的博客，...

论文地址：（V1）https://arxiv.org/abs/1409.4842

本文所包含代码GitHub地址：https://github.com/shankezh/DL_HotNet_Tensorflow

如果对机器学习有兴趣，不仅仅满足将深度学习模型当黑盒模型使用的，想了解为何机器学习可以训练拟合最佳模型，可以看我过往的博客，使用数学知识推导了机器学习中比较经典的案例，并且使用了python撸了一套简单的神经网络的代码框架用来加深理解：https://blog.csdn.net/shankezh/article/category/7279585
项目帮忙或工作机会请邮件联系：cloud_happy@163.com

本文将会提取论文Inception V1的关键点，并直接使用代码来复现InceptionV1的分类网络,但不对InceptionV1结构的网络进行训练展示，但我将会在近期的InceptionV3进行训练复现展示;

# 论文精华（V1）

## 关键信息提取

InceptionV1：

1.提出了新的神经网络卷积结构叫做Incetpion（注意是卷积，不是整体网路），并且在2014年ImageNet的分类和检测任务中获得了新高度;

3.感慨了下许多设计网络对小数据集mnist,cifar分类比较好，大数据集的解决方法则是这段时期(2014年之前)通过增加网络深度以及使用dropout来预防过拟合;

4.使用1x1卷积可以维度式的消除网络计算瓶颈，防止限制网络的大小；同时也是增加了网络深度，却不会影响正确率;

5.当前（2014）主要的对象检测方法是R-CNN，R-CNN分解了检测问题一拆为二，首先利用低层次提示（如颜色，像素一致性）在不知类别的对象中找潜在可能对象，然后在定位地方使用CNN分类器识别对象类别；二阶段利用边界框分割分数和底层次提示,及强大的CNN分类能力;我们使用了了相似的方法在我们的检测提交中，但是增强了各阶段的观察能力，例如更好地对象边界框复用的多盒预测，总体上实现了更好地边界框建议;

6.提高正确率最直接了当的方式为增加深度神经网络的尺寸，包括了增加深度（层级数量）和宽度（每一层的单元数量）,但是这两种简单的解决方法会带来两种不利因素;ａ）带来过大的参数量和过拟合风险;ｂ）大大增加计算资源的消耗;

7.解决上面问题的根本办法为，将全连接替换为稀疏结构，甚至为内部卷积层；

8.基于自己的inception结构思想设计了最初的网络，训练，调参，并且认为在上下文定位和对象检测非常有用，并且多数质疑和测试都通过了，起码时获得了局部的最优效果；

9.需要注意，虽然提出的结构可以成功应用于计算机视觉，但依旧存在疑问--质量能否归功于构建原则，这件事的确定需要更多的研究和分析，

10.假设平移不变性，我们的网络将有卷积块构建而成;

11.建议层次化构建，分析最后一层的统计相关性，同时聚类它们形成高相关性的单元组;

12.假设来自早期层的每个单元对应于输入图像的某个区域，并且这些单元被分组到滤波器组中；

13.更低层的相关单元则会集中在局部区域;

14.觉的最终大量的簇单元聚集在一个区域，并且可以被下一层的1x1的卷积覆盖;

15.为了避免块对齐问题，限制Incepiton结构使用的滤波器尺寸在1x1,3x3,5x5,然而这个决定是基于便利比需求更好;

16.在当前计数水平下，卷积网络的池化操作是必要的;

17.网络设计的思想是计算效率和实用性，因此可以运行资源有限的个人设备上,特别是低内存占用；

## 结构细节

1.试过增加Inception结构的宽度和深度，但结果并没有很理想，最成功的结构，见Figure1.

2.所有的卷积层，包括Inception模块，都使用线性激活；

3.接收模板224x224,RGB3通道与均值消除;

4.Figure1.中 #3x3 reduce 和 #5x5 reduce 表示的是3x3和5x5之前的1x1卷积层及数量;pool proj列中是最大池化层后跟的1x1卷积滤波器的数量;他们都是用了线性激活；

5.网络是22层，如果算池化层则是27层；

6.使用的均值池化层在分类器之前;

7.发现了从全连接层到均值池化层，top-1正确率提升了0.6%,然后使用dropout仍然必不可少，即使后来移除了全连接层;

8.通过添加辅助分类器到中间层，预计将会在分类器中的较低阶段激发辨别能力,增加梯度信号到反向传播,提供增加正则项;

9.这些辅助分类器以更小的卷积网络形式输出到Inception 4a和4d模块后;训练期间，它们的损失通过引入一个系数权重后加入总网络损失中（辅助分类器的权重是 0.3），但在正式的推理阶段，权重不进行计算；

10.辅助分类器信息：a）均值池化层使用5x5滤波,步长为3,结果为4x4x512输出（从4a输出）,和结果为4x4x528输出（从4d输出）;b)1x1的卷积有128个用来降维，使用ReLU激活;c）全连接使用1024个单元，使用ReLU激活;d）dropout系数0.7；e）softmax线性激活分类器（预测同样的种类计算损失，但推理阶段不使用）

## 训练细节

1.使用momentum,冲量0.9，固定学习速率，每8个epoch就减少4%（注意，这是针对imageNet数据集）;

2.训练了很久，有时会同时改变超参数，如dropout和lr，很难找到一个具有决定性效果指引的方法去训练网络QAQ;

3.发现Andrew Howard的方法对防止过拟合很有效(论文名:Some Improvements on Deep Convolutional Neural network Based Image Classification)

# Tensorflow代码实现

## 代码

### 模型

InceptionV1.py

def inception_moudle_v1(net,scope,filters_num):
with tf.variable_scope(scope):
with tf.variable_scope('bh1'):
bh1 = slim.conv2d(net,filters_num[0],1,scope='bh1_conv1_1x1')
with tf.variable_scope('bh2'):
bh2 = slim.conv2d(net,filters_num[1],1,scope='bh2_conv1_1x1')
bh2 = slim.conv2d(bh2,filters_num[2],3,scope='bh2_conv2_3x3')
with tf.variable_scope('bh3'):
bh3 = slim.conv2d(net,filters_num[3],1,scope='bh3_conv1_1x1')
bh3 = slim.conv2d(bh3,filters_num[4],5,scope='bh3_conv2_5x5')
with tf.variable_scope('bh4'):
bh4 = slim.max_pool2d(net,3,scope='bh4_max_3x3')
bh4 = slim.conv2d(bh4,filters_num[5],1,scope='bh4_conv_1x1')
net = tf.concat([bh1,bh2,bh3,bh4],axis=3)
return net

def V1_slim(inputs,num_cls,is_train = False,keep_prob=0.4,spatital_squeeze=True):
with tf.name_scope('reshape'):
net = tf.reshape(inputs, [-1, 224, 224, 3])

with slim.arg_scope(
[slim.conv2d, slim.fully_connected],
weights_regularizer=slim.l2_regularizer(5e-4),
weights_initializer=slim.xavier_initializer(),
):
with slim.arg_scope(
[slim.conv2d,slim.max_pool2d,slim.avg_pool2d],
stride=1,
):
net = slim.conv2d(net,64,7,stride=2,scope='layer1')
net = slim.max_pool2d(net,3,stride=2,scope='layer2')
net = tf.nn.lrn(net)
net = slim.conv2d(net,64,1,scope='layer3')
net = slim.conv2d(net,192,3,scope='layer4')
net = tf.nn.lrn(net)
net = slim.max_pool2d(net,3,stride=2,scope='layer5')
net = inception_moudle_v1(net,'layer6',[64,96,128,16,32,32])
net = inception_moudle_v1(net,'layer8',[128,128,192,32,96,64])
net = slim.max_pool2d(net,3,stride=2,scope='layer10')
net = inception_moudle_v1(net,'layer11',[192,96,208,16,48,64])
net = inception_moudle_v1(net,'layer13',[160,112,224,24,64,64])
net_1 = net
net = inception_moudle_v1(net,'layer15',[128,128,256,24,64,64])
net = inception_moudle_v1(net,'layer17',[112,144,288,32,64,64])
net_2 = net
net = inception_moudle_v1(net,'lauer19',[256,160,320,32,128,128])
net = slim.max_pool2d(net,3,stride=2,scope='layer21')
net = inception_moudle_v1(net,'layer22',[256,160,320,32,128,128])
net = inception_moudle_v1(net,'layer24',[384,192,384,48,128,128])

net = slim.dropout(net,keep_prob=keep_prob,scope='dropout')
net = slim.conv2d(net,num_cls,1,activation_fn=None, normalizer_fn=None,scope='layer27')
if spatital_squeeze:
net = tf.squeeze(net,[1,2],name='squeeze')
net = slim.softmax(net,scope='softmax2')

if is_train:
net_1 = slim.avg_pool2d(net_1, 5, padding='VALID', stride=3, scope='auxiliary0_avg')
net_1 = slim.conv2d(net_1, 128, 1, scope='auxiliary0_conv_1X1')
net_1 = slim.flatten(net_1)
net_1 = slim.fully_connected(net_1,1024,scope='auxiliary0_fc1')
net_1 = slim.dropout(net_1, 0.7)
net_1 = slim.fully_connected(net_1,num_cls,activation_fn=None,scope='auxiliary0_fc2')
net_1 = slim.softmax(net_1, scope='softmax0')

net_2 = slim.avg_pool2d(net_2, 5, padding='VALID', stride=3, scope='auxiliary1_avg')
net_2 = slim.conv2d(net_2, 128, 1, scope='auxiliary1_conv_1X1')
net_2 = slim.flatten(net_2)
net_2 = slim.fully_connected(net_2,1024,scope='auxiliary1_fc1')
net_2 = slim.dropout(net_2, 0.7)
net_2 = slim.fully_connected(net_2,num_cls,activation_fn=None,scope='auxiliary1_fc2')
net_2 = slim.softmax(net_2, scope='softmax1')

net = net_1 * 0.3 + net_2 * 0.3 + net * 0.4
print(net.shape)

return net

## 结论

这篇文章最大的贡献个人认为不仅仅是提供了Inception的卷积组合结构，更大的贡献在于，去掉了全连接，使得全局参数最多的地方被去除，这样网络参数量减少，极大地利于网络的运算，使得在算力差的设备也有了更好地运行效果；之前我曾使用过InceptionV1进行对cifar10数据的训练，结果是成功的，只是由于是很久之前的事情，并未对当时的结果和过程予以保存，同时由于时间的关系，我也不再复现InceptionV1训练过程，我将在InceptionV3进行复现训练过程；

本篇博客的代码依旧放在Github中，地址见文章开头。

展开全文
• ## Tensorflow2.0 Inceptionv3实现图片分类

千次阅读 多人点赞 2020-06-16 13:37:38
1.InceptionV3网络结构 论文：《Rethinking the Inception Architecture for Computer Vision》 论文链接：https://arxiv.org/abs/1512.00567 tensorflow.keras.applications模块内置了许多模型，包括Xception、...

# 1.InceptionV3网络结构

论文：《Rethinking the Inception Architecture for Computer Vision》
论文链接：https://arxiv.org/abs/1512.00567
在2015年，谷歌发布了Inception V3版本，Inception V3 的创新点是将大的卷积分解成小卷积，即 5x5 卷积可以用两个 3x3 卷积代替（Inception 模块 A），3x3 卷积可以用 3×1 卷积后接一个 1×3 卷积代替（Inception 模块 B），作者还提出了一种使用非对称分解的卷积模块（Inception 模块 C），如下图所示：
Inception 模块 A：

Inception 模块 B：

Inception 模块 C：

Inception 整体结构：

图源 : medium

除此之外，Inception V3 还用了RMSProp优化器，标签平滑（防止过度拟合），辅助分类器中加入了BatchNorm，可以提高大网络的收敛速度。

tensorflow.keras.applications模块内置了许多模型，包括Xception、MobileNet、VGG等，我们可以使用内置的InceptionV3模型,只需修改最后的全连接层输出类别即可。

# 2.数据集

链接：https://pan.baidu.com/s/17HsGlsIB2xP8oeUywuwf3A
提取码：kl0h
采用kaggle上的猴子数据集，包含两个文件：训练集和验证集。每个文件夹包含10个标记为n0-n9的猴子。图像尺寸为400x300像素或更大，并且为JPEG格式（近1400张图像）。

图片样本

图片类别标签，训练集，验证集划分说明：

# 3.代码

### 3.1 数据读取

#导入相应的库
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from sklearn.metrics import confusion_matrix
import matplotlib.pyplot as plt
import tensorflow as tf
import pandas as pd
import numpy as np
import itertools
import os

#设置图片的高和宽，一次训练所选取的样本数，迭代次数
im_height = 224
im_width = 224
batch_size = 64
epochs = 13

image_path = "../input/10-monkey-species/"  # monkey数据集路径
train_dir = image_path + "training/training"  #训练集路径
validation_dir = image_path + "validation/validation" #验证集路径

# 定义训练集图像生成器，并进行图像增强
train_image_generator = ImageDataGenerator( rescale=1./255, # 归一化
rotation_range=40, #旋转范围
width_shift_range=0.2, #水平平移范围
height_shift_range=0.2, #垂直平移范围
shear_range=0.2, #剪切变换的程度
zoom_range=0.2, #剪切变换的程度
horizontal_flip=True,  #水平翻转
fill_mode='nearest')

# 使用图像生成器从文件夹train_dir中读取样本，对标签进行one-hot编码
train_data_gen = train_image_generator.flow_from_directory(directory=train_dir, #从训练集路径读取图片
batch_size=batch_size, #一次训练所选取的样本数
shuffle=True, #打乱标签
target_size=(im_height, im_width), #图片resize到224x224大小
class_mode='categorical') #one-hot编码

# 训练集样本数
total_train = train_data_gen.n

# 定义验证集图像生成器，并对图像进行预处理
validation_image_generator = ImageDataGenerator(rescale=1./255) # 归一化

# 使用图像生成器从验证集validation_dir中读取样本
val_data_gen = validation_image_generator.flow_from_directory(directory=validation_dir,#从验证集路径读取图片
batch_size=batch_size, #一次训练所选取的样本数
shuffle=False,  #不打乱标签
target_size=(im_height, im_width), #图片resize到224x224大小
class_mode='categorical') #one-hot编码

# 验证集样本数
total_val = val_data_gen.n


执行结果：

Found 1098 images belonging to 10 classes.
Found 272 images belonging to 10 classes.


训练集一共有1098张图片，验证集一共有272张图片，总共10个类别

### 3.2 构建模型

#使用tf.keras.applications中的InceptionV3网络，并且使用官方的预训练模型
covn_base = tf.keras.applications.InceptionV3(weights='imagenet',include_top=False,input_shape=(224,224,3))
covn_base.trainable = True

#冻结前面的层，训练最后20层
for layers in covn_base.layers[:-20]:
layers.trainable = False

#构建模型
model = tf.keras.Sequential()
model.summary() # 打印每层参数信息

#编译模型
loss=tf.keras.losses.CategoricalCrossentropy(from_logits=False), #交叉熵损失函数
metrics=["accuracy"]) #评价函数


执行结果：

Downloading data from https://storage.googleapis.com/tensorflow/keras-applications/inception_v3/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5
87916544/87910968 [==============================] - 1s 0us/step:
311
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
inception_v3 (Model)         (None, 5, 5, 2048)        21802784
_________________________________________________________________
global_average_pooling2d (Gl (None, 2048)              0
_________________________________________________________________
dense (Dense)                (None, 10)                20490
=================================================================
Total params: 21,823,274
Trainable params: 1,955,850
Non-trainable params: 19,867,424
_________________________________________________________________


由于大部分层被冻结了，所以可训练的参数很少，只有1,955,850个参数

### 3.3 训练模型

history = model.fit(x=train_data_gen,   #输入训练集
steps_per_epoch=total_train // batch_size, #一个epoch包含的训练步数
epochs=epochs, #训练模型迭代次数
validation_data=val_data_gen,  #输入验证集
validation_steps=total_val // batch_size) #一个epoch包含的训练步数

# 记录训练集和验证集的准确率和损失值
history_dict = history.history
train_loss = history_dict["loss"] #训练集损失值
train_accuracy = history_dict["accuracy"] #训练集准确率
val_loss = history_dict["val_loss"] #验证集损失值
val_accuracy = history_dict["val_accuracy"] #验证集准确率


执行结果：

Epoch 1/13
17/17 [==============================] - 91s 5s/step - loss: 1.4246 - accuracy: 0.6267 - val_loss: 0.4937 - val_accuracy: 0.8945
Epoch 2/13
17/17 [==============================] - 88s 5s/step - loss: 0.4829 - accuracy: 0.9188 - val_loss: 0.2047 - val_accuracy: 0.9531
Epoch 3/13
17/17 [==============================] - 87s 5s/step - loss: 0.2874 - accuracy: 0.9420 - val_loss: 0.1497 - val_accuracy: 0.9648
Epoch 4/13
17/17 [==============================] - 87s 5s/step - loss: 0.2041 - accuracy: 0.9662 - val_loss: 0.1212 - val_accuracy: 0.9727
Epoch 5/13
17/17 [==============================] - 89s 5s/step - loss: 0.2079 - accuracy: 0.9565 - val_loss: 0.1061 - val_accuracy: 0.9766
Epoch 6/13
17/17 [==============================] - 86s 5s/step - loss: 0.1675 - accuracy: 0.9594 - val_loss: 0.1078 - val_accuracy: 0.9766
Epoch 7/13
17/17 [==============================] - 88s 5s/step - loss: 0.1500 - accuracy: 0.9652 - val_loss: 0.0957 - val_accuracy: 0.9688
Epoch 8/13
17/17 [==============================] - 87s 5s/step - loss: 0.1330 - accuracy: 0.9671 - val_loss: 0.0938 - val_accuracy: 0.9727
Epoch 9/13
17/17 [==============================] - 87s 5s/step - loss: 0.1228 - accuracy: 0.9778 - val_loss: 0.0875 - val_accuracy: 0.9805
Epoch 10/13
17/17 [==============================] - 86s 5s/step - loss: 0.1320 - accuracy: 0.9710 - val_loss: 0.0848 - val_accuracy: 0.9766
Epoch 11/13
17/17 [==============================] - 87s 5s/step - loss: 0.1122 - accuracy: 0.9758 - val_loss: 0.0798 - val_accuracy: 0.9727
Epoch 12/13
17/17 [==============================] - 86s 5s/step - loss: 0.1206 - accuracy: 0.9681 - val_loss: 0.0755 - val_accuracy: 0.9766
Epoch 13/13
17/17 [==============================] - 85s 5s/step - loss: 0.1056 - accuracy: 0.9778 - val_loss: 0.0796 - val_accuracy: 0.9766


从结果可以看出，使用迁移学习的时候模型收敛的速度很快，当训练第13个epoch时训练集准确率为97.78%,验证集的准确率为97.66%

### 3.4 评估模型

##### 3.4.1 绘制损失值曲线
plt.figure()
plt.plot(range(epochs), train_loss, label='train_loss')
plt.plot(range(epochs), val_loss, label='val_loss')
plt.legend()
plt.xlabel('epochs')
plt.ylabel('loss')


记录每个epoch的训练集和验证集损失值并绘制出来进行对比，可以看到从第4个epoch开始逐渐趋于稳定

##### 3.4.2 绘制准确率曲线
plt.figure()
plt.plot(range(epochs), train_accuracy, label='train_accuracy')
plt.plot(range(epochs), val_accuracy, label='val_accuracy')
plt.legend()
plt.xlabel('epochs')
plt.ylabel('accuracy')
plt.show()


记录每个epoch的训练集和验证集准确率并绘制出来进行对比，同样从第4个epoch开始逐渐趋于稳定

##### 3.4.3 绘制混淆矩阵
def plot_confusion_matrix(cm, target_names,title='Confusion matrix',cmap=None,normalize=False):
accuracy = np.trace(cm) / float(np.sum(cm)) #计算准确率
misclass = 1 - accuracy #计算错误率
if cmap is None:
cmap = plt.get_cmap('Blues') #颜色设置成蓝色
plt.figure(figsize=(10, 8)) #设置窗口尺寸
plt.imshow(cm, interpolation='nearest', cmap=cmap) #显示图片
plt.title(title) #显示标题
plt.colorbar() #绘制颜色条

if target_names is not None:
tick_marks = np.arange(len(target_names))
plt.xticks(tick_marks, target_names, rotation=45) #x坐标标签旋转45度
plt.yticks(tick_marks, target_names) #y坐标

if normalize:
cm = cm.astype('float32') / cm.sum(axis=1)
cm = np.round(cm,2) #对数字保留两位小数

thresh = cm.max() / 1.5 if normalize else cm.max() / 2
for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])): #将cm.shape[0]、cm.shape[1]中的元素组成元组，遍历元组中每一个数字
if normalize: #标准化
plt.text(j, i, "{:0.2f}".format(cm[i, j]), #保留两位小数
horizontalalignment="center",  #数字在方框中间
color="white" if cm[i, j] > thresh else "black")  #设置字体颜色
else:  #非标准化
plt.text(j, i, "{:,}".format(cm[i, j]),
horizontalalignment="center",  #数字在方框中间
color="white" if cm[i, j] > thresh else "black") #设置字体颜色

plt.tight_layout() #自动调整子图参数,使之填充整个图像区域
plt.ylabel('True label') #y方向上的标签
plt.xlabel("Predicted label\naccuracy={:0.4f}\n misclass={:0.4f}".format(accuracy, misclass)) #x方向上的标签
plt.show() #显示图片

#读取'Common Name'列的猴子类别，并存入到labels中
cols = ['Label','Latin Name', 'Common Name','Train Images', 'Validation Images']
labels = labels['Common Name']

# 预测验证集数据整体准确率
Y_pred = model.predict_generator(val_data_gen, total_val // batch_size + 1)
# 将预测的结果转化为one hit向量
Y_pred_classes = np.argmax(Y_pred, axis = 1)
# 计算混淆矩阵
confusion_mtx = confusion_matrix(y_true = val_data_gen.classes,y_pred = Y_pred_classes)
# 绘制混淆矩阵
plot_confusion_matrix(confusion_mtx, normalize=True, target_names=labels)


可以看出，验证集中有五类猴子预测的准确率为百分之百，剩下的五类猴子预测的准确率在百分之90以上，整体预测的准确率为97.79%，说明效果还是不错的

展开全文
• 结构表2.InceptionV1提升网络性能的方法3.InceptionV1模块（1）模块一（2）模块二 （改进模块）4.网络结构5.关于1x1的作用6.Multi-scale processing 1.结构表 2.InceptionV1提升网络性能的方法 传统的模块提升网络...
• Inception第一次亮相是在 2014 年的 ILSVRC 比赛中，并且以 top-5 错误率（为 6.67% ）略低于 VGGNet 的优势取得了第一名，这一代的Inception网络通常称为GoogleNet，也叫InceptionV1网络。InceptionV2与InceptionV3...
• 本文主要通过tensorflow的contrib.slim模块来实现Google Inception V3来减少设计Inception V3的代码量，使用contrib.slim模块便可以通过少量的代码来构建有42层深的Inception V3。一、Inception V3网络结构介绍...
• 使用TensorFlow实现Inception-V3卷积神经网络，InceptionModule将不同的卷积层通过并行连接的方式结合在一起。同时使用所有不同尺寸的过滤器，然后再将得到的矩阵拼接起来。如下图，Inception V3 模型总共...
• 1、导入相关包 import tensorflow as tf import numpy as np from matplotlib import pyplot as plt from tensorflow.keras.layers import Conv2D, BatchNormalization, Activation, MaxPool2D, Dropout, Flatten, ...
• 文章目录1.输出结果2.InceptionV4网络结构细节3.代码复现 1.输出结果 从原始论文中可以看到这个结构设计没有什么问题。 2.InceptionV4网络结构细节 3.代码复现 以下代码有点多，希望读者在阅读的时候最好对应每...
• branch_3=tf.nn.avg_pool(input,ksize = (1,3,3,1),strides = [1,1,1,1],padding = 'SAME',name = 'Avgpool_0a_3x3') branch_3=conv_inception(branch_3,shape = [1,1,288,64],name = '0b_1x1') inception_out=tf...
• tensorflow+inceptionv3图像分类网络结构的解析与代码实现 论文链接:论文地址 ResNet传送门：Resnet-cifar10 DenseNet传送门：DenseNet SegNet传送门：Segnet-segmentation 深度学习的火热，使得...
• https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/image_retraining/retrain.py 源码分析： [python] view plain copy """简单调用Inception V3架构...
• import tensorflow as tf from tensorflow.python.framework import graph_util logdir="E:\DeepLearning\Git\cnn\inception_dec_2015\\" output_graph_path = logdir +'tensorflow_inception_graph.pb'...
• 文章目录1.论文下载地址2.结构表3.改进的三种inception（1）改进inception模块1：（1）改进inception模块2：（1）改进inception模块3：4....原始的InceptionV1模块： 关于以下模块的数量和计算的计算量可以参考

...