TensorFlow实现经典深度学习网络(3):TensorFlow实现Google Inception Net
Google Inception Net作为ILSVRC 2014比赛中的第一名(这年的Google Inception Net通常被称为Inception V1),其在控制计算量和参数量的同时,获得非常好的分类性能——top-5错误率6.67%,只有AlexNet的一半不到。Inception V1有22层(AlexNet 8层,VGGNet 19层),计算量却只有15亿次浮点运算,500万参数(AlexNet 6000万),准确率却远高于AlexNet。Inception V1降低参数量是因为(1)参数越多模型越庞大,需数据量越大,高质量数据昂贵;(2)参数越多,耗费计算资源越大。Inception V1参数少但效果好的原因除了模型层数更深、表达能力更强外,还有一点就是(1)去除最后全连接层,用全局平均池化层(图片尺寸变1x1),参数大减,模型训练更快,减轻过拟合(《Network in Network》论文);(2)Inception Module提高参数利用效率,大网络中小网络。增加分支网络,NIN级联卷积层、NLPConv层。一般来说卷积层增加输出通道数可以提升表达能力,但缺点是计算量增大和过拟合。每个输出通道对应一个滤波器,同一滤波器共享参数,只能提取一类特征。Google Inception Net发展至今,已成为一个大家族Inception V1(top-5错误率6.67%)、Inception V2(top-5错误率4.8%)、Inception V3(top-5错误率3.5%)、Inception V4(top-5错误率3.08%)。
Inception Module结构图
Google Inception Net模型参数详细如下:
本文要构建的网络为Inception V3:
• 核心组件
• 非对称卷积:N x N 分解成 1 x N 、 N x 1
• 降低参数数量和计算量
• 使用3×3的已经很小了,那么更小的2×2呢?2×2虽然能使得参数进一步降低,但是不如另一种方式更加有效,那就是Asymmetric方式,即使用1×3和3×1两种来代替3×3。使用2个2×2的话能节省11%的计算量,而使用这种方式则可以节省33%。如下图所示:
• 高效的降尺寸(Grid size)
• 避免表达瓶颈
• 降尺寸前增加特征通道
• 2个并行分支
• 卷积分支+池化分支
• 串接分支结果
• Grid就是图像在某一层的激活值,即feature_map,一般情况下,如果想让图像缩小,可以有如下两种方式:
右图是正常的缩小,但计算量很大。左图先pooling会导致特征表征遇到瓶颈,违反上面所说的第一个规则,为了同时达到不违反规则且降低计算量的作用,将网络改为下图:
使用两个并行化的模块可以降低计算量
• 取消浅层的辅助分类器
• 完全无用
• 深层辅助分类器只在训练后期有用
• 加上BN和Dropout,主分类器Top1性能提升0.4%
• 正则化作用
• 用在最后一层17x17后
• 不增加计算量
• 避免表达瓶颈
• 增强结构(表达力)
Inception V3网络结构
图中的Figure 4是指没有进化的Inception,Figure 5是指smaller conv版的Inception,Figure 6是指Asymmetric版的Inception。
V3一个最重要的改进就是分解(也就是Factorization into small convolutions),将一个较大的二维卷积拆成两个较小的一维卷积,比如将7x7分解成两个一维的卷积(1x7,7x1),3x3也是一样(1x3,3x1),这样的好处,既可以加速计算(多余的计算能力可以用来加深网络),又可以将1个conv拆成2个conv,使得网络深度进一步增加,增加了网络的非线性;还有值得注意的地方是V3网络优化了Inception Module的结构,输入从224x224变为了299x299,更加精细设计了35x35/17x17/8x8的模块。
# -*- coding: utf-8 -*-
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# Inception V3 42层深
# 载入模块、TensorFlow,定义截断正态分布函数trunc_normal
from datetime import datetime
import math
import time
import tensorflow as tf
slim = tf.contrib.slim
trunc_normal = lambda stddev: tf.truncated_normal_initializer(0.0, stddev)
# 定义用来生成网络默认参数的函数inception_v3_arg_scope
def inception_v3_arg_scope(weight_decay=0.00004,
stddev=0.1,
batch_norm_var_collection='moving_vars'):
batch_norm_params = {
'decay': 0.9997,
'epsilon': 0.001,
'updates_collections': tf.GraphKeys.UPDATE_OPS,
'variables_collections': {
'beta': None,
'gamma': None,
'moving_mean': [batch_norm_var_collection],
'moving_variance': [batch_norm_var_collection],
}
}
# 定义slim.arg_scope给函数的参数自动赋予默认值
with slim.arg_scope([slim.conv2d, slim.fully_connected],
weights_regularizer=slim.l2_regularizer(weight_decay)):
with slim.arg_scope(