Merge pull request #158 from vfdev-5/densenet-naming

* Add names for layers of dense/transition blocks [DenseNet]
This commit is contained in:
Andrew Hundt
2017-11-18 13:44:22 -05:00
committed by GitHub
+50 -32
View File
@@ -506,7 +506,11 @@ def DenseNetImageNet161(input_shape=None,
pooling=pooling, classes=classes, activation=activation)
def __conv_block(ip, nb_filter, bottleneck=False, dropout_rate=None, weight_decay=1e-4):
def name_or_none(prefix, name):
return prefix + name if (prefix is not None and name is not None) else None
def __conv_block(ip, nb_filter, bottleneck=False, dropout_rate=None, weight_decay=1e-4, block_prefix=None):
'''
Adds a convolution layer (with batch normalization and relu),
and optionally a bottleneck layer.
@@ -518,6 +522,7 @@ def __conv_block(ip, nb_filter, bottleneck=False, dropout_rate=None, weight_deca
bottleneck: if True, adds a bottleneck convolution block
dropout_rate: dropout rate
weight_decay: weight decay factor
block_prefix: str, for unique layer naming
# Input shape
4D tensor with shape:
@@ -538,18 +543,20 @@ def __conv_block(ip, nb_filter, bottleneck=False, dropout_rate=None, weight_deca
with K.name_scope('ConvBlock'):
concat_axis = 1 if K.image_data_format() == 'channels_first' else -1
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(ip)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5, name=name_or_none(block_prefix, '_bn'))(ip)
x = Activation('relu')(x)
if bottleneck:
inter_channel = nb_filter * 4
x = Conv2D(inter_channel, (1, 1), kernel_initializer='he_normal', padding='same', use_bias=False,
kernel_regularizer=l2(weight_decay))(x)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(x)
kernel_regularizer=l2(weight_decay), name=name_or_none(block_prefix, '_bottleneck_conv2D'))(x)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5,
name=name_or_none(block_prefix, '_bottleneck_bn'))(x)
x = Activation('relu')(x)
x = Conv2D(nb_filter, (3, 3), kernel_initializer='he_normal', padding='same', use_bias=False)(x)
x = Conv2D(nb_filter, (3, 3), kernel_initializer='he_normal', padding='same', use_bias=False,
name=name_or_none(block_prefix, '_conv2D'))(x)
if dropout_rate:
x = Dropout(dropout_rate)(x)
@@ -557,7 +564,7 @@ def __conv_block(ip, nb_filter, bottleneck=False, dropout_rate=None, weight_deca
def __dense_block(x, nb_layers, nb_filter, growth_rate, bottleneck=False, dropout_rate=None,
weight_decay=1e-4, grow_nb_filters=True, return_concat_list=False):
weight_decay=1e-4, grow_nb_filters=True, return_concat_list=False, block_prefix=None):
'''
Build a dense_block where the output of each conv_block is fed
to subsequent ones
@@ -575,6 +582,7 @@ def __dense_block(x, nb_layers, nb_filter, growth_rate, bottleneck=False, dropou
grow_nb_filters: if True, allows number of filters to grow
return_concat_list: set to True to return the list of
feature maps along with the actual output
block_prefix: str, for block unique naming
# Return
If return_concat_list is True, returns a list of the output
@@ -590,7 +598,8 @@ def __dense_block(x, nb_layers, nb_filter, growth_rate, bottleneck=False, dropou
x_list = [x]
for i in range(nb_layers):
cb = __conv_block(x, growth_rate, bottleneck, dropout_rate, weight_decay)
cb = __conv_block(x, growth_rate, bottleneck, dropout_rate, weight_decay,
block_prefix=name_or_none(block_prefix, '_%i' % i))
x_list.append(cb)
x = concatenate([x, cb], axis=concat_axis)
@@ -604,7 +613,7 @@ def __dense_block(x, nb_layers, nb_filter, growth_rate, bottleneck=False, dropou
return x, nb_filter
def __transition_block(ip, nb_filter, compression=1.0, weight_decay=1e-4):
def __transition_block(ip, nb_filter, compression=1.0, weight_decay=1e-4, block_prefix=None):
'''
Adds a pointwise convolution layer (with batch normalization and relu),
and an average pooling layer. The number of output convolution filters
@@ -617,6 +626,7 @@ def __transition_block(ip, nb_filter, compression=1.0, weight_decay=1e-4):
compression: calculated as 1 - reduction. Reduces the number
of feature maps in the transition block.
weight_decay: weight decay factor
block_prefix: str, for block unique naming
# Input shape
4D tensor with shape:
@@ -638,16 +648,16 @@ def __transition_block(ip, nb_filter, compression=1.0, weight_decay=1e-4):
with K.name_scope('Transition'):
concat_axis = 1 if K.image_data_format() == 'channels_first' else -1
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(ip)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5, name=name_or_none(block_prefix, '_bn'))(ip)
x = Activation('relu')(x)
x = Conv2D(int(nb_filter * compression), (1, 1), kernel_initializer='he_normal', padding='same',
use_bias=False, kernel_regularizer=l2(weight_decay))(x)
use_bias=False, kernel_regularizer=l2(weight_decay), name=name_or_none(block_prefix, '_conv2D'))(x)
x = AveragePooling2D((2, 2), strides=(2, 2))(x)
return x
def __transition_up_block(ip, nb_filters, type='deconv', weight_decay=1E-4):
def __transition_up_block(ip, nb_filters, type='deconv', weight_decay=1E-4, block_prefix=None):
'''Adds an upsampling block. Upsampling operation relies on the the type parameter.
# Arguments
@@ -657,6 +667,7 @@ def __transition_up_block(ip, nb_filters, type='deconv', weight_decay=1E-4):
type: can be 'upsampling', 'subpixel', 'deconv'. Determines
type of upsampling performed
weight_decay: weight decay factor
block_prefix: str, for block unique naming
# Input shape
4D tensor with shape:
@@ -676,17 +687,17 @@ def __transition_up_block(ip, nb_filters, type='deconv', weight_decay=1E-4):
with K.name_scope('TransitionUp'):
if type == 'upsampling':
x = UpSampling2D()(ip)
x = UpSampling2D(name=name_or_none(block_prefix, '_upsampling'))(ip)
elif type == 'subpixel':
x = Conv2D(nb_filters, (3, 3), activation='relu', padding='same', kernel_regularizer=l2(weight_decay),
use_bias=False, kernel_initializer='he_normal')(ip)
x = SubPixelUpscaling(scale_factor=2)(x)
use_bias=False, kernel_initializer='he_normal', name=name_or_none(block_prefix, '_conv2D'))(ip)
x = SubPixelUpscaling(scale_factor=2, name=name_or_none(block_prefix, '_subpixel'))(x)
x = Conv2D(nb_filters, (3, 3), activation='relu', padding='same', kernel_regularizer=l2(weight_decay),
use_bias=False, kernel_initializer='he_normal')(x)
use_bias=False, kernel_initializer='he_normal', name=name_or_none(block_prefix, '_conv2D'))(x)
else:
x = Conv2DTranspose(nb_filters, (3, 3), activation='relu', padding='same', strides=(2, 2),
kernel_initializer='he_normal', kernel_regularizer=l2(weight_decay))(ip)
kernel_initializer='he_normal', kernel_regularizer=l2(weight_decay),
name=name_or_none(block_prefix, '_conv2DT'))(ip)
return x
@@ -781,27 +792,30 @@ def __create_dense_net(nb_classes, img_input, include_top, depth=40, nb_dense_bl
initial_kernel = (3, 3)
initial_strides = (1, 1)
x = Conv2D(nb_filter, initial_kernel, kernel_initializer='he_normal', padding='same',
x = Conv2D(nb_filter, initial_kernel, kernel_initializer='he_normal', padding='same', name='initial_conv2D',
strides=initial_strides, use_bias=False, kernel_regularizer=l2(weight_decay))(img_input)
if subsample_initial_block:
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(x)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5, name='initial_bn')(x)
x = Activation('relu')(x)
x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x)
# Add dense blocks
for block_idx in range(nb_dense_block - 1):
x, nb_filter = __dense_block(x, nb_layers[block_idx], nb_filter, growth_rate, bottleneck=bottleneck,
dropout_rate=dropout_rate, weight_decay=weight_decay)
dropout_rate=dropout_rate, weight_decay=weight_decay,
block_prefix='dense_%i' % block_idx)
# add transition_block
x = __transition_block(x, nb_filter, compression=compression, weight_decay=weight_decay)
x = __transition_block(x, nb_filter, compression=compression, weight_decay=weight_decay,
block_prefix='tr_%i' % block_idx)
nb_filter = int(nb_filter * compression)
# The last dense_block does not have a transition_block
x, nb_filter = __dense_block(x, final_nb_layer, nb_filter, growth_rate, bottleneck=bottleneck,
dropout_rate=dropout_rate, weight_decay=weight_decay)
dropout_rate=dropout_rate, weight_decay=weight_decay,
block_prefix='dense_%i' % (nb_dense_block - 1))
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(x)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5, name='final_bn')(x)
x = Activation('relu')(x)
if include_top:
@@ -889,7 +903,7 @@ def __create_fcn_dense_net(nb_classes, img_input, include_top, nb_dense_block=5,
# Initial convolution
x = Conv2D(init_conv_filters, (7, 7), kernel_initializer='he_normal', padding='same', name='initial_conv2D',
use_bias=False, kernel_regularizer=l2(weight_decay))(img_input)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(x)
x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5, name='initial_bn')(x)
x = Activation('relu')(x)
nb_filter = init_conv_filters
@@ -899,13 +913,14 @@ def __create_fcn_dense_net(nb_classes, img_input, include_top, nb_dense_block=5,
# Add dense blocks and transition down block
for block_idx in range(nb_dense_block):
x, nb_filter = __dense_block(x, nb_layers[block_idx], nb_filter, growth_rate, dropout_rate=dropout_rate,
weight_decay=weight_decay)
weight_decay=weight_decay, block_prefix='dense_%i' % block_idx)
# Skip connection
skip_list.append(x)
# add transition_block
x = __transition_block(x, nb_filter, compression=compression, weight_decay=weight_decay)
x = __transition_block(x, nb_filter, compression=compression, weight_decay=weight_decay,
block_prefix='tr_%i' % block_idx)
nb_filter = int(nb_filter * compression) # this is calculated inside transition_down_block
@@ -913,7 +928,8 @@ def __create_fcn_dense_net(nb_classes, img_input, include_top, nb_dense_block=5,
# return the concatenated feature maps without the concatenation of the input
_, nb_filter, concat_list = __dense_block(x, bottleneck_nb_layers, nb_filter, growth_rate,
dropout_rate=dropout_rate, weight_decay=weight_decay,
return_concat_list=True)
return_concat_list=True,
block_prefix='dense_%i' % nb_dense_block)
skip_list = skip_list[::-1] # reverse the skip list
@@ -925,16 +941,18 @@ def __create_fcn_dense_net(nb_classes, img_input, include_top, nb_dense_block=5,
# not the concatenation of the input with the feature maps (concat_list[0].
l = concatenate(concat_list[1:], axis=concat_axis)
t = __transition_up_block(l, nb_filters=n_filters_keep, type=upsampling_type, weight_decay=weight_decay)
t = __transition_up_block(l, nb_filters=n_filters_keep, type=upsampling_type, weight_decay=weight_decay,
block_prefix='tr_up_%i' % block_idx)
# concatenate the skip connection with the transition block
x = concatenate([t, skip_list[block_idx]], axis=concat_axis)
# Dont allow the feature map size to grow in upsampling dense blocks
x_up, nb_filter, concat_list = __dense_block(x, nb_layers[nb_dense_block + block_idx + 1], nb_filter=growth_rate,
growth_rate=growth_rate, dropout_rate=dropout_rate,
weight_decay=weight_decay, return_concat_list=True,
grow_nb_filters=False)
x_up, nb_filter, concat_list = __dense_block(x, nb_layers[nb_dense_block + block_idx + 1],
nb_filter=growth_rate, growth_rate=growth_rate,
dropout_rate=dropout_rate, weight_decay=weight_decay,
return_concat_list=True, grow_nb_filters=False,
block_prefix='dense_%i' % (nb_dense_block + 1 + block_idx))
if include_top:
x = Conv2D(nb_classes, (1, 1), activation='linear', padding='same', use_bias=False)(x_up)