From 03e649dbca7b1e6c59e52f250f3ca8ea728e560c Mon Sep 17 00:00:00 2001 From: Somshubra Majumdar Date: Fri, 17 Nov 2017 12:32:22 -0600 Subject: [PATCH] Add name scopes and correct a flaw with assertion --- keras_contrib/applications/nasnet.py | 134 +++++++++++++++------------ 1 file changed, 74 insertions(+), 60 deletions(-) diff --git a/keras_contrib/applications/nasnet.py b/keras_contrib/applications/nasnet.py index 4ab5210..c7f52f8 100644 --- a/keras_contrib/applications/nasnet.py +++ b/keras_contrib/applications/nasnet.py @@ -1,14 +1,14 @@ -"""NASNet (Neural Architecture Search Networks) for Keras - -# References +"""Collection of NASNet models +The reference paper: - [Learning Transferable Architectures for Scalable Image Recognition] (https://arxiv.org/abs/1707.07012) -Reference material for extended functionality: - +The reference implementation: +1. TF Slim - https://github.com/tensorflow/models/blob/master/research/slim/nets/ nasnet/nasnet.py +2. TensorNets - https://github.com/taehoonlee/tensornets/blob/master/tensornets/nasnets.py """ from __future__ import print_function @@ -170,13 +170,15 @@ def NASNet(input_shape=None, else: img_input = input_tensor - assert penultimate_filters % ((2 ** nb_blocks) * 6), "`penultimate_filters` needs to be divisible " \ - "by 6 * (2^N)." + assert penultimate_filters % 24 == 0, "`penultimate_filters` needs to be divisible by 24" - filters = penultimate_filters // ((2 ** nb_blocks) * 6) + channel_dim = 1 if K.image_data_format() == 'channels_first' else -1 + filters = penultimate_filters // 24 x = Conv2D(stem_filters, (3, 3), strides=(2, 2), padding='valid', use_bias=False, name='stem_conv1', kernel_initializer='he_normal')(img_input) + x = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, + name='stem_bn1')(x) x, p = _reduction_A(x, None, filters // (filters_multiplier ** 2), id='stem_1') x, p = _reduction_A(x, p, filters // filters_multiplier, id='stem_2') @@ -193,7 +195,6 @@ def NASNet(input_shape=None, auxilary_x = None if use_auxilary_branch: - channel_dim = 1 if K.image_data_format() == 'channels_first' else -1 img_dim = 2 if K.image_data_format() == 'channels_first' else -2 auxilary_x = Activation('relu')(x) @@ -411,16 +412,17 @@ def _separable_conv_block(ip, filters, kernel_size=(3, 3), strides=(1, 1), id=No ''' channel_dim = 1 if K.image_data_format() == 'channels_first' else -1 - x = Activation('relu')(ip) - x = SeparableConv2D(filters, kernel_size, strides=strides, name='separable_conv_1_%s' % id, - padding='same', use_bias=False, kernel_initializer='he_normal')(x) - x = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, - name="separable_conv_1_bn_%s" % (id))(x) - x = Activation('relu')(x) - x = SeparableConv2D(filters, kernel_size, name='separable_conv_2_%s' % id, - padding='same', use_bias=False, kernel_initializer='he_normal')(x) - x = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, - name="separable_conv_2_bn_%s" % (id))(x) + with K.name_scope('separable_conv_block_%s' % id): + x = Activation('relu')(ip) + x = SeparableConv2D(filters, kernel_size, strides=strides, name='separable_conv_1_%s' % id, + padding='same', use_bias=False, kernel_initializer='he_normal')(x) + x = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, + name="separable_conv_1_bn_%s" % (id))(x) + x = Activation('relu')(x) + x = SeparableConv2D(filters, kernel_size, name='separable_conv_2_%s' % id, + padding='same', use_bias=False, kernel_initializer='he_normal')(x) + x = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, + name="separable_conv_2_bn_%s" % (id))(x) return x @@ -446,26 +448,28 @@ def _adjust_block(p, ip, filters, id=None): p = ip elif p._keras_shape[img_dim] != ip._keras_shape[img_dim]: - p = Activation('relu', name='adjust_relu_1_%s' % id)(p) + with K.name_scope('adjust_reduction_block_%s' % id): + p = Activation('relu', name='adjust_relu_1_%s' % id)(p) - p1 = AveragePooling2D((1, 1), strides=(2, 2), padding='valid', name='adjust_avg_pool_1_%s' % id)(p) - p1 = Conv2D(filters // 2, (1, 1), padding='same', use_bias=False, - name='adjust_conv_1_%s' % id, kernel_initializer='he_normal')(p1) + p1 = AveragePooling2D((1, 1), strides=(2, 2), padding='valid', name='adjust_avg_pool_1_%s' % id)(p) + p1 = Conv2D(filters // 2, (1, 1), padding='same', use_bias=False, + name='adjust_conv_1_%s' % id, kernel_initializer='he_normal')(p1) - p2 = AveragePooling2D((1, 1), strides=(2, 2), padding='valid', name='adjust_avg_pool_2_%s' % id)(p) - p2 = Conv2D(filters // 2, (1, 1), padding='same', use_bias=False, - name='adjust_conv_2_%s' % id, kernel_initializer='he_normal')(p2) + p2 = AveragePooling2D((1, 1), strides=(2, 2), padding='valid', name='adjust_avg_pool_2_%s' % id)(p) + p2 = Conv2D(filters // 2, (1, 1), padding='same', use_bias=False, + name='adjust_conv_2_%s' % id, kernel_initializer='he_normal')(p2) - p = concatenate([p1, p2], axis=channel_dim) - p = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, - name='adjust_bn_%s' % id)(p) + p = concatenate([p1, p2], axis=channel_dim) + p = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, + name='adjust_bn_%s' % id)(p) elif p._keras_shape[channel_dim] != filters: - p = Activation('relu')(p) - p = Conv2D(filters, (1, 1), strides=(1, 1), padding='same', name='adjust_conv_projection_%s' % id, - use_bias=False, kernel_initializer='he_normal')(p) - p = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, - name='adjust_bn_%s' % id)(p) + with K.name_scope('adjust_projection_block_%s' % id): + p = Activation('relu')(p) + p = Conv2D(filters, (1, 1), strides=(1, 1), padding='same', name='adjust_conv_projection_%s' % id, + use_bias=False, kernel_initializer='he_normal')(p) + p = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, + name='adjust_bn_%s' % id)(p) return p @@ -491,23 +495,28 @@ def _normal_A(ip, p, filters, id=None): h = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, name='normal_bn_1_%s' % id)(h) - x1 = _separable_conv_block(h, filters, id='normal_left1_%s' % id) - x1 = add([x1, h], name='normal_add_1_%s' % id) + with K.name_scope('normal_A_block_1'): + x1 = _separable_conv_block(h, filters, id='normal_left1_%s' % id) + x1 = add([x1, h], name='normal_add_1_%s' % id) - x2_1 = _separable_conv_block(p, filters, id='normal_left2_%s' % id) - x2_2 = _separable_conv_block(h, filters, kernel_size=(5, 5), id='normal_right2_%s' % id) - x2 = add([x2_1, x2_2], name='normal_add_2_%s' % id) + with K.name_scope('normal_A_block_2'): + x2_1 = _separable_conv_block(p, filters, id='normal_left2_%s' % id) + x2_2 = _separable_conv_block(h, filters, kernel_size=(5, 5), id='normal_right2_%s' % id) + x2 = add([x2_1, x2_2], name='normal_add_2_%s' % id) - x3 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='normal_left3_%s' % (id))(h) - x3 = add([x3, p], name='normal_add_3_%s' % id) + with K.name_scope('normal_A_block_3'): + x3 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='normal_left3_%s' % (id))(h) + x3 = add([x3, p], name='normal_add_3_%s' % id) - x4_1 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='normal_left4_%s' % (id))(p) - x4_2 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='normal_right4_%s' % (id))(p) - x4 = add([x4_1, x4_2], name='normal_add_4_%s' % id) + with K.name_scope('normal_A_block_4'): + x4_1 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='normal_left4_%s' % (id))(p) + x4_2 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='normal_right4_%s' % (id))(p) + x4 = add([x4_1, x4_2], name='normal_add_4_%s' % id) - x5_1 = _separable_conv_block(p, filters, (5, 5), id='normal_left5_%s' % id) - x5_2 = _separable_conv_block(p, filters, (3, 3), id='normal_right5_%s' % id) - x5 = add([x5_1, x5_2], name='normal_add_5_%s' % id) + with K.name_scope('normal_A_block_5'): + x5_1 = _separable_conv_block(p, filters, (5, 5), id='normal_left5_%s' % id) + x5_2 = _separable_conv_block(p, filters, (3, 3), id='normal_right5_%s' % id) + x5 = add([x5_1, x5_2], name='normal_add_5_%s' % id) x = concatenate([p, x2, x5, x3, x4, x1], axis=channel_dim, name='normal_concat_%s' % id) return x, ip @@ -536,23 +545,28 @@ def _reduction_A(ip, p, filters, id=None): h = BatchNormalization(axis=channel_dim, momentum=_BN_DECAY, epsilon=_BN_EPSILON, name='reduction_bn_1_%s' % id)(h) - x1_1 = _separable_conv_block(p, filters, (7, 7), strides=(2, 2), id='reduction_left1_%s' % id) - x1_2 = _separable_conv_block(h, filters, (5, 5), strides=(2, 2), id='reduction_right1_%s' % id) - x1 = add([x1_1, x1_2], name='reduction_add_1_%s' % id) + with K.name_scope('reduction_A_block_1'): + x1_1 = _separable_conv_block(p, filters, (7, 7), strides=(2, 2), id='reduction_left1_%s' % id) + x1_2 = _separable_conv_block(h, filters, (5, 5), strides=(2, 2), id='reduction_right1_%s' % id) + x1 = add([x1_1, x1_2], name='reduction_add_1_%s' % id) - x2_1 = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='reduction_left2_%s' % id)(h) - x2_2 = _separable_conv_block(p, filters, (7, 7), strides=(2, 2), id='reduction_right2_%s' % id) - x2 = add([x2_1, x2_2], name='reduction_add_2_%s' % id) + with K.name_scope('reduction_A_block_2'): + x2_1 = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='reduction_left2_%s' % id)(h) + x2_2 = _separable_conv_block(p, filters, (7, 7), strides=(2, 2), id='reduction_right2_%s' % id) + x2 = add([x2_1, x2_2], name='reduction_add_2_%s' % id) - x3_1 = AveragePooling2D((3, 3), strides=(2, 2), padding='same', name='reduction_left3_%s' % id)(h) - x3_2 = _separable_conv_block(p, filters, (5, 5), strides=(2, 2), id='reduction_right3_%s' % id) - x3 = add([x3_1, x3_2], name='reduction_add3_%s' % id) + with K.name_scope('reduction_A_block_3'): + x3_1 = AveragePooling2D((3, 3), strides=(2, 2), padding='same', name='reduction_left3_%s' % id)(h) + x3_2 = _separable_conv_block(p, filters, (5, 5), strides=(2, 2), id='reduction_right3_%s' % id) + x3 = add([x3_1, x3_2], name='reduction_add3_%s' % id) - x4_1 = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='reduction_left4_%s' % id)(h) - x4_2 = _separable_conv_block(x1, filters, (3, 3), id='reduction_right4_%s' % id) - x4 = add([x4_1, x4_2], name='reduction_add4_%s' % id) + with K.name_scope('reduction_A_block_4'): + x4_1 = MaxPooling2D((3, 3), strides=(2, 2), padding='same', name='reduction_left4_%s' % id)(h) + x4_2 = _separable_conv_block(x1, filters, (3, 3), id='reduction_right4_%s' % id) + x4 = add([x4_1, x4_2], name='reduction_add4_%s' % id) - x5 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='reduction_left5_%s' % id)(x1) + with K.name_scope('reduction_A_block_5'): + x5 = AveragePooling2D((3, 3), strides=(1, 1), padding='same', name='reduction_left5_%s' % id)(x1) x = concatenate([x2, x3, x5, x4], axis=channel_dim, name='reduction_concat_%s' % id) return x, ip