经典分类CNN模型系列其六:Inception v4与Inception-Resnet v1/v2

介绍

Inception系列模型设计的核心思想讲至Inception v3基本已经尽了。但2015年Resnet的提出及其在ILSVRC 2015的成功使得Google team开始重新评估CNN深度模型的设计。他们自然不肯屈服于Resnet的强大,同行相轻,古今中外皆然,Googlers们也不能免。

他们试着将Residual learning的思想应用在inception网络中,搞出了性能不错的Inception-Resnet v1/v2模型,实验结果表明Residual learning在Inception网络上确实可行,就此他们似乎可以拱手认输了。认输?岂有此理,自视甚高的Googlers们才不干呢。他们做尽实验,费力表明Residual learning并非深度网络走向更深的必需条件,其只是可以使得深度网络的训练速度加快而已。为了表明这一点,他们更是造出了更为复杂、精巧的Inception v4网络,在不使用residual learning的情况下也达到了与Inception-Resnet v2近似的精度。

Inception v4乃至Google team之前搞出来的v3确实强大,理论上的计算所需Flops及训练参数占的内存开销都不算大(在拥有相同能力的情况下)。可相对于Resnet/VGG等网络而言,它显得有些过于复杂、精巧了。对于实际在底层做优化执行的工程师而言(不论是在GPU/CPU上做还是使用FPGA/ASIC专用芯片),过于复杂的网络往往意味着更多的工程设计与思考才能使得其运算得到优良的并行加速、执行。因此当下为止Resnet系列的分类网络还是主流所用的视觉分类网络。

Inception v4

inception v4网络的设计主要沿用了之前在Inception v2/v3中提到的几个CNN网络设计原则(详情请参考上篇inception v2/v3博客)。而因为Google team此次将v4网络执行迁移到了tensorflow上面来执行,因此可不必再像之前在DistBelief上那样受限于他们所用系统的内存、计算等局限而只在几种可行的范围里选择inception 通用模块设计。简单说就是Tensorflow 框架可让他们更好地放飞自我,利用tensorflow天生的并行性,随需地设计data parallel与model parallel的网络(当然也还会受限于底层所用硬件的计算与内存资源)。

这篇paper中图片非常多,下面我们就一一看下图,见识下inception v4中新引入的一些模块形状及其间的连接设计吧。

首先在inception网络设计中,最开始的几层总是不建议使用inception等模块来节省计算以抽取信息的,因此它们多是只采用简单的conv层或者相对简单的inception模块。

应用于Inception_v4与Inception-Resnet网络上的输入模块

下面为inception v4之上的各个不同大小的feature map grid所使用的inception模块及它们之间的连接。细看就会发现它的设计也主要遵循之前在inception v3中所使用的原则,只是更复杂了些。

应用于Inception_v4的inception模块及其之间的连接

汇合以上各个模块就是下图所示最终的Inception v4网络。

Inception_v4网络

Inception-Resnet

在inception-resnet中所用的inception-resnet模块里都在inception子网络的最后加入了一个1x1扩展conv 操作用于使得它的输出宽度(channels数目)与子网络的输入宽度相同,从而方便相加。

inception-resnet v1

inception-resnet v1网络主要被用来与inception v3模型性能进行比较。因此它所用的inception子网络的计算相对常规inception模块有所减少,这是为了保证使得它的整体计算/内存开销与inception v3近似,如此才能保证比较的公平性(毕竟Googler们的观点是:CNN深度网络的设计是追求计算与内存受限的情况下的性能最优化)。

下图中右、下方三小图分别为inception-resnet v1中所用的inception-resnet modules及它们之间的连接模块。包含了inception-resnet A/inception-resnet B及inception-resnet B与inception-resnet C之间的连接。

Inception-Resnet_v1所使用的模块

下图为inception-resnet v1中用的inception-resnet C模块。

Inception-Resnet_v1所用的C模块

最后下面为inception-resnet v1的网络输入模块,注意它与inception v4和inception-resnet v2的并不相同。

Inception-Resnet_v1网络输入模块

inception-resnet v2

相对于inception-resnet v1而言,v2主要被设计来探索residual learning用于inception网络时所极尽可能带来的性能提升。因此它所用的inception 子网络并没有像v1中用的那样偷工减料。

首先下面为inception-resnet v2所使用的各个主要模块。

Inception-Resnet_v2所使用的各个主要模块

最后下面为inception-resnet v1/v2网络的整体结构。

Inception-resnet_v1与inception-resnet_v2的主体网络结构

residual模块的scaling

作者们实验发现如果对inception-resnet网络中的residual模块的输出进行scaling(如以0.1-0.3),那么可以让它的整个训练过程更加地稳定。如下图为scaling的具体做法示意。

Residuals模块的scaling操作

实验结果

下图为inception v3/v4与inception-resnet v1/v2模型的收敛速度对比图。从中我们可以看出residual learning的引入可以使得inception网络收敛速度更快,但最终它们达到的精度却类似。

inception系列模型与inception-resnet系列模型的收敛趋势图对比

最后我们看下几个模型的分类精度对比。

五个分类模型的结果对比

代码分析

我们可以在tensorflow的官方github里面找到Inception系列及inception-resnet系列模型的实现。
不得不说tensorflow给的API写起CNN网络来还是比较方便的,代码非常可读。

首先是inception v4里的一些实现。可参考:https://github.com/tensorflow/models/blob/master/research/slim/nets/inception_v4.py

以下为block b的实现,非常易懂。

def block_inception_b(inputs, scope=None, reuse=None):
  """Builds Inception-B block for Inception v4 network."""
  # By default use stride=1 and SAME padding
  with slim.arg_scope([slim.conv2d, slim.avg_pool2d, slim.max_pool2d],
                      stride=1, padding='SAME'):
    with tf.variable_scope(scope, 'BlockInceptionB', [inputs], reuse=reuse):
      with tf.variable_scope('Branch_0'):
        branch_0 = slim.conv2d(inputs, 384, [1, 1], scope='Conv2d_0a_1x1')
      with tf.variable_scope('Branch_1'):
        branch_1 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1')
        branch_1 = slim.conv2d(branch_1, 224, [1, 7], scope='Conv2d_0b_1x7')
        branch_1 = slim.conv2d(branch_1, 256, [7, 1], scope='Conv2d_0c_7x1')
      with tf.variable_scope('Branch_2'):
        branch_2 = slim.conv2d(inputs, 192, [1, 1], scope='Conv2d_0a_1x1')
        branch_2 = slim.conv2d(branch_2, 192, [7, 1], scope='Conv2d_0b_7x1')
        branch_2 = slim.conv2d(branch_2, 224, [1, 7], scope='Conv2d_0c_1x7')
        branch_2 = slim.conv2d(branch_2, 224, [7, 1], scope='Conv2d_0d_7x1')
        branch_2 = slim.conv2d(branch_2, 256, [1, 7], scope='Conv2d_0e_1x7')
      with tf.variable_scope('Branch_3'):
        branch_3 = slim.avg_pool2d(inputs, [3, 3], scope='AvgPool_0a_3x3')
        branch_3 = slim.conv2d(branch_3, 128, [1, 1], scope='Conv2d_0b_1x1')
      return tf.concat(axis=3, values=[branch_0, branch_1, branch_2, branch_3])

然后我们可以看下inception-resnet v2的模型实现,可见:https://github.com/tensorflow/models/blob/master/research/slim/nets/inception_resnet_v2.py

下面为它在feature map size为17x17的block上的具体写法。其它模块类似。可以看出它对inception子网络的输出使用了scaling操作以加强训练时的稳定性。

def block17(net, scale=1.0, activation_fn=tf.nn.relu, scope=None, reuse=None):
  """Builds the 17x17 resnet block."""
  with tf.variable_scope(scope, 'Block17', [net], reuse=reuse):
    with tf.variable_scope('Branch_0'):
      tower_conv = slim.conv2d(net, 192, 1, scope='Conv2d_1x1')
    with tf.variable_scope('Branch_1'):
      tower_conv1_0 = slim.conv2d(net, 128, 1, scope='Conv2d_0a_1x1')
      tower_conv1_1 = slim.conv2d(tower_conv1_0, 160, [1, 7],
                                  scope='Conv2d_0b_1x7')
      tower_conv1_2 = slim.conv2d(tower_conv1_1, 192, [7, 1],
                                  scope='Conv2d_0c_7x1')
    mixed = tf.concat(axis=3, values=[tower_conv, tower_conv1_2])
    up = slim.conv2d(mixed, net.get_shape()[3], 1, normalizer_fn=None,
                     activation_fn=None, scope='Conv2d_1x1')

    scaled_up = up * scale
    if activation_fn == tf.nn.relu6:
      # Use clip_by_value to simulate bandpass activation.
      scaled_up = tf.clip_by_value(scaled_up, -6.0, 6.0)

    net += scaled_up
    if activation_fn:
      net = activation_fn(net)
  return net

参考文献

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342

推荐阅读更多精彩内容