def _resnet_block(input_tensor, filters, k=1, strides=(1, 1)): """ Adds a pre-activation resnet block without bottleneck layers Args: input_tensor: input Keras tensor filters: number of output filters k: width factor strides: strides of the convolution layer Returns: a Keras tensor """ init = input_tensor channel_axis = 1 if K.image_data_format() == "channels_first" else -1 x = BatchNormalization(axis=channel_axis)(input_tensor) x = Activation('relu')(x) if strides != (1, 1) or _tensor_shape(init)[channel_axis] != filters * k: init = Conv2D(filters * k, (1, 1), padding='same', kernel_initializer='he_normal', use_bias=False, strides=strides)(x) x = Conv2D(filters * k, (3, 3), padding='same', kernel_initializer='he_normal', use_bias=False, strides=strides)(x) x = BatchNormalization(axis=channel_axis)(x) x = Activation('relu')(x) x = Conv2D(filters * k, (3, 3), padding='same', kernel_initializer='he_normal', use_bias=False)(x) # squeeze and excite block x = squeeze_excite_block(x) m = add([x, init]) return m
def squeeze_excite_block(input_tensor, ratio=16): """ Create a channel-wise squeeze-excite block Args: input_tensor: input Keras tensor ratio: number of output filters Returns: a Keras tensor References - [Squeeze and Excitation Networks](https://arxiv.org/abs/1709.01507) """ init = input_tensor channel_axis = 1 if K.image_data_format() == "channels_first" else -1 filters = _tensor_shape(init)[channel_axis] se_shape = (1, 1, filters) se = GlobalAveragePooling2D()(init) se = Reshape(se_shape)(se) se = Dense(filters // ratio, activation='relu', kernel_initializer='he_normal', use_bias=False)(se) se = Dense(filters, activation='sigmoid', kernel_initializer='he_normal', use_bias=False)(se) if K.image_data_format() == 'channels_first': se = Permute((3, 1, 2))(se) x = multiply([init, se]) return x
def __bottleneck_block(input_tensor, filters=64, cardinality=8, strides=1, weight_decay=5e-4): """ Adds a bottleneck block Args: input_tensor: input Keras tensor filters: number of output filters cardinality: cardinality factor described number of grouped convolutions strides: performs strided convolution for downsampling if > 1 weight_decay: weight decay factor Returns: a Keras tensor """ init = input_tensor grouped_channels = int(filters / cardinality) channel_axis = 1 if K.image_data_format() == 'channels_first' else -1 # Check if input_tensor number of filters is same as 16 * k, else create convolution2d for this input_tensor if K.image_data_format() == 'channels_first': if _tensor_shape(init)[1] != 2 * filters: init = Conv2D(filters * 2, (1, 1), padding='same', strides=(strides, strides), use_bias=False, kernel_initializer='he_normal', kernel_regularizer=l2(weight_decay))(init) init = BatchNormalization(axis=channel_axis)(init) else: if _tensor_shape(init)[-1] != 2 * filters: init = Conv2D(filters * 2, (1, 1), padding='same', strides=(strides, strides), use_bias=False, kernel_initializer='he_normal', kernel_regularizer=l2(weight_decay))(init) init = BatchNormalization(axis=channel_axis)(init) x = Conv2D(filters, (1, 1), padding='same', use_bias=False, kernel_initializer='he_normal', kernel_regularizer=l2(weight_decay))(input_tensor) x = BatchNormalization(axis=channel_axis)(x) x = LeakyReLU()(x) x = __grouped_convolution_block(x, grouped_channels, cardinality, strides, weight_decay) x = Conv2D(filters * 2, (1, 1), padding='same', use_bias=False, kernel_initializer='he_normal', kernel_regularizer=l2(weight_decay))(x) x = BatchNormalization(axis=channel_axis)(x) # squeeze and excite block x = squeeze_excite_block(x) x = add([init, x]) x = LeakyReLU()(x) return x