def __transition_block(ip, nb_filter, compression=1.0, weight_decay=1e-4): """ Apply BatchNorm, Relu 1x1, Conv2D, optional compression, dropout and Maxpooling2D Args: ip: keras tensor nb_filter: number of filters compression: calculated as 1 - reduction. Reduces the number of feature maps in the transition block. weight_decay: weight decay factor Returns: keras tensor, after applying batch_norm, relu-conv, dropout, maxpool """ concat_axis = 1 if K.image_data_format() == 'channels_first' else -1 x = BatchNormalization(axis=concat_axis, epsilon=1.1e-5)(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) x = AveragePooling2D((2, 2), strides=(2, 2))(x) # squeeze and excite block x = squeeze_excite_block(x) return x
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): """ Build a dense_block where the output of each conv_block is fed to subsequent ones Args: x: keras tensor nb_layers: the number of layers of conv_block to append to the weights. nb_filter: number of filters growth_rate: growth rate bottleneck: bottleneck block dropout_rate: dropout rate weight_decay: weight decay factor grow_nb_filters: flag to decide to allow number of filters to grow return_concat_list: return the list of feature maps along with the actual output Returns: keras tensor with nb_layers of conv_block appended """ concat_axis = 1 if K.image_data_format() == 'channels_first' else -1 x_list = [x] for i in range(nb_layers): cb = __conv_block(x, growth_rate, bottleneck, dropout_rate, weight_decay) x_list.append(cb) x = concatenate([x, cb], axis=concat_axis) if grow_nb_filters: nb_filter += growth_rate # squeeze and excite block x = squeeze_excite_block(x) if return_concat_list: return x, nb_filter, x_list else: return x, nb_filter
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 __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
def SEInceptionV3(include_top=True, weights=None, input_tensor=None, input_shape=None, pooling=None, classes=1000): """Instantiates the Squeeze and Excite Inception v3 architecture. # Arguments include_top: whether to include the fully-connected layer at the top of the network. weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet). input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the weights. input_shape: optional shape tuple, only to be specified if `include_top` is False (otherwise the input shape has to be `(299, 299, 3)` (with `channels_last` insight_data format) or `(3, 299, 299)` (with `channels_first` insight_data format). It should have exactly 3 inputs channels, and width and height should be no smaller than 139. E.g. `(150, 150, 3)` would be one valid value. pooling: Optional pooling mode for feature extraction when `include_top` is `False`. - `None` means that the output of the weights will be the 4D tensor output of the last convolutional layer. - `avg` means that global average pooling will be applied to the output of the last convolutional layer, and thus the output of the weights will be a 2D tensor. - `max` means that global max pooling will be applied. classes: optional number of classes to classify images into, only to be specified if `include_top` is True, and if no `weights` argument is specified. # Returns A Keras weights instance. # Raises ValueError: in case of invalid argument for `weights`, or invalid input shape. """ if weights not in {'imagenet', None}: raise ValueError('The `weights` argument should be either ' '`None` (random initialization) or `imagenet` ' '(pre-training on ImageNet).') if weights == 'imagenet' and include_top and classes != 1000: raise ValueError('If using `weights` as imagenet with `include_top`' ' as true, `classes` should be 1000') # Determine proper input shape input_shape = _obtain_input_shape(input_shape, default_size=299, min_size=139, data_format=K.image_data_format(), require_flatten=include_top) if input_tensor is None: img_input = Input(shape=input_shape) else: if not is_keras_tensor(input_tensor): img_input = Input(tensor=input_tensor, shape=input_shape) else: img_input = input_tensor if K.image_data_format() == 'channels_first': channel_axis = 1 else: channel_axis = 3 x = _conv2d_bn(img_input, 32, 3, 3, strides=(2, 2), padding='valid') x = _conv2d_bn(x, 32, 3, 3, padding='valid') x = _conv2d_bn(x, 64, 3, 3) x = MaxPooling2D((3, 3), strides=(2, 2))(x) x = _conv2d_bn(x, 80, 1, 1, padding='valid') x = _conv2d_bn(x, 192, 3, 3, padding='valid') x = MaxPooling2D((3, 3), strides=(2, 2))(x) # mixed 0, 1, 2: 35 x 35 x 256 branch1x1 = _conv2d_bn(x, 64, 1, 1) branch5x5 = _conv2d_bn(x, 48, 1, 1) branch5x5 = _conv2d_bn(branch5x5, 64, 5, 5) branch3x3dbl = _conv2d_bn(x, 64, 1, 1) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 32, 1, 1) x = layers.concatenate([branch1x1, branch5x5, branch3x3dbl, branch_pool], axis=channel_axis, name='mixed0') # squeeze and excite block x = squeeze_excite_block(x) # mixed 1: 35 x 35 x 256 branch1x1 = _conv2d_bn(x, 64, 1, 1) branch5x5 = _conv2d_bn(x, 48, 1, 1) branch5x5 = _conv2d_bn(branch5x5, 64, 5, 5) branch3x3dbl = _conv2d_bn(x, 64, 1, 1) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 64, 1, 1) x = layers.concatenate([branch1x1, branch5x5, branch3x3dbl, branch_pool], axis=channel_axis, name='mixed1') # squeeze and excite block x = squeeze_excite_block(x) # mixed 2: 35 x 35 x 256 branch1x1 = _conv2d_bn(x, 64, 1, 1) branch5x5 = _conv2d_bn(x, 48, 1, 1) branch5x5 = _conv2d_bn(branch5x5, 64, 5, 5) branch3x3dbl = _conv2d_bn(x, 64, 1, 1) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 64, 1, 1) x = layers.concatenate([branch1x1, branch5x5, branch3x3dbl, branch_pool], axis=channel_axis, name='mixed2') # squeeze and excite block x = squeeze_excite_block(x) # mixed 3: 17 x 17 x 768 branch3x3 = _conv2d_bn(x, 384, 3, 3, strides=(2, 2), padding='valid') branch3x3dbl = _conv2d_bn(x, 64, 1, 1) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3) branch3x3dbl = _conv2d_bn(branch3x3dbl, 96, 3, 3, strides=(2, 2), padding='valid') branch_pool = MaxPooling2D((3, 3), strides=(2, 2))(x) x = layers.concatenate([branch3x3, branch3x3dbl, branch_pool], axis=channel_axis, name='mixed3') # squeeze and excite block x = squeeze_excite_block(x) # mixed 4: 17 x 17 x 768 branch1x1 = _conv2d_bn(x, 192, 1, 1) branch7x7 = _conv2d_bn(x, 128, 1, 1) branch7x7 = _conv2d_bn(branch7x7, 128, 1, 7) branch7x7 = _conv2d_bn(branch7x7, 192, 7, 1) branch7x7dbl = _conv2d_bn(x, 128, 1, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 128, 7, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 128, 1, 7) branch7x7dbl = _conv2d_bn(branch7x7dbl, 128, 7, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 192, 1, 7) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 192, 1, 1) x = layers.concatenate([branch1x1, branch7x7, branch7x7dbl, branch_pool], axis=channel_axis, name='mixed4') # squeeze and excite block x = squeeze_excite_block(x) # mixed 5, 6: 17 x 17 x 768 for i in range(2): branch1x1 = _conv2d_bn(x, 192, 1, 1) branch7x7 = _conv2d_bn(x, 160, 1, 1) branch7x7 = _conv2d_bn(branch7x7, 160, 1, 7) branch7x7 = _conv2d_bn(branch7x7, 192, 7, 1) branch7x7dbl = _conv2d_bn(x, 160, 1, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 160, 7, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 160, 1, 7) branch7x7dbl = _conv2d_bn(branch7x7dbl, 160, 7, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 192, 1, 7) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 192, 1, 1) x = layers.concatenate( [branch1x1, branch7x7, branch7x7dbl, branch_pool], axis=channel_axis, name='mixed{}'.format(5 + i)) # squeeze and excite block x = squeeze_excite_block(x) # mixed 7: 17 x 17 x 768 branch1x1 = _conv2d_bn(x, 192, 1, 1) branch7x7 = _conv2d_bn(x, 192, 1, 1) branch7x7 = _conv2d_bn(branch7x7, 192, 1, 7) branch7x7 = _conv2d_bn(branch7x7, 192, 7, 1) branch7x7dbl = _conv2d_bn(x, 192, 1, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 192, 7, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 192, 1, 7) branch7x7dbl = _conv2d_bn(branch7x7dbl, 192, 7, 1) branch7x7dbl = _conv2d_bn(branch7x7dbl, 192, 1, 7) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 192, 1, 1) x = layers.concatenate([branch1x1, branch7x7, branch7x7dbl, branch_pool], axis=channel_axis, name='mixed7') # squeeze and excite block x = squeeze_excite_block(x) # mixed 8: 8 x 8 x 1280 branch3x3 = _conv2d_bn(x, 192, 1, 1) branch3x3 = _conv2d_bn(branch3x3, 320, 3, 3, strides=(2, 2), padding='valid') branch7x7x3 = _conv2d_bn(x, 192, 1, 1) branch7x7x3 = _conv2d_bn(branch7x7x3, 192, 1, 7) branch7x7x3 = _conv2d_bn(branch7x7x3, 192, 7, 1) branch7x7x3 = _conv2d_bn(branch7x7x3, 192, 3, 3, strides=(2, 2), padding='valid') branch_pool = MaxPooling2D((3, 3), strides=(2, 2))(x) x = layers.concatenate([branch3x3, branch7x7x3, branch_pool], axis=channel_axis, name='mixed8') # squeeze and excite block x = squeeze_excite_block(x) # mixed 9: 8 x 8 x 2048 for i in range(2): branch1x1 = _conv2d_bn(x, 320, 1, 1) branch3x3 = _conv2d_bn(x, 384, 1, 1) branch3x3_1 = _conv2d_bn(branch3x3, 384, 1, 3) branch3x3_2 = _conv2d_bn(branch3x3, 384, 3, 1) branch3x3 = layers.concatenate([branch3x3_1, branch3x3_2], axis=channel_axis, name='mixed9_{i}'.format(i=i)) branch3x3dbl = _conv2d_bn(x, 448, 1, 1) branch3x3dbl = _conv2d_bn(branch3x3dbl, 384, 3, 3) branch3x3dbl_1 = _conv2d_bn(branch3x3dbl, 384, 1, 3) branch3x3dbl_2 = _conv2d_bn(branch3x3dbl, 384, 3, 1) branch3x3dbl = layers.concatenate([branch3x3dbl_1, branch3x3dbl_2], axis=channel_axis) branch_pool = AveragePooling2D((3, 3), strides=(1, 1), padding='same')(x) branch_pool = _conv2d_bn(branch_pool, 192, 1, 1) x = layers.concatenate( [branch1x1, branch3x3, branch3x3dbl, branch_pool], axis=channel_axis, name='mixed{}'.format(9 + i)) # squeeze and excite block x = squeeze_excite_block(x) if include_top: # Classification block x = GlobalAveragePooling2D(name='avg_pool')(x) x = Dense(classes, activation='softmax', name='predictions')(x) else: if pooling == 'avg': x = GlobalAveragePooling2D()(x) elif pooling == 'max': x = GlobalMaxPooling2D()(x) # Ensure that the weights takes into account # any potential predecessors of `input_tensor`. if input_tensor is not None: inputs = get_source_inputs(input_tensor) else: inputs = img_input # Create weights. model = Model(inputs, x, name='inception_v3') return model
def _depthwise_conv_block(inputs, pointwise_conv_filters, alpha, depth_multiplier=1, strides=(1, 1), block_id=1): """Adds a depthwise convolution block. A depthwise convolution block consists of a depthwise conv, batch normalization, relu6, pointwise convolution, batch normalization and relu6 activation. # Arguments inputs: Tensor of shape `(rows, cols, channels)` (with `channels_last` data format) or (channels, rows, cols) (with `channels_first` data format). pointwise_conv_filters: Integer, the dimensionality of the output space (i.e. the number output of filters in the pointwise convolution). alpha: controls the width of the network. - If `alpha` < 1.0, proportionally decreases the number of filters in each layer. - If `alpha` > 1.0, proportionally increases the number of filters in each layer. - If `alpha` = 1, default number of filters from the paper are used at each layer. depth_multiplier: The number of depthwise convolution output channels for each input channel. The total number of depthwise convolution output channels will be equal to `filters_in * depth_multiplier`. strides: An integer or tuple/list of 2 integers, specifying the strides of the convolution along the width and height. Can be a single integer to specify the same value for all spatial dimensions. Specifying any stride value != 1 is incompatible with specifying any `dilation_rate` value != 1. block_id: Integer, a unique identification designating the block number. # Input shape 4D tensor with shape: `(batch, channels, rows, cols)` if data_format='channels_first' or 4D tensor with shape: `(batch, rows, cols, channels)` if data_format='channels_last'. # Output shape 4D tensor with shape: `(batch, filters, new_rows, new_cols)` if data_format='channels_first' or 4D tensor with shape: `(batch, new_rows, new_cols, filters)` if data_format='channels_last'. `rows` and `cols` values might have changed due to stride. # Returns Output tensor of block. """ channel_axis = 1 if K.image_data_format() == 'channels_first' else -1 pointwise_conv_filters = int(pointwise_conv_filters * alpha) x = DepthwiseConv2D((3, 3), padding='same', depth_multiplier=depth_multiplier, strides=strides, use_bias=False, name='conv_dw_%d' % block_id)(inputs) x = BatchNormalization(axis=channel_axis, name='conv_dw_%d_bn' % block_id)(x) x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x) x = Conv2D(pointwise_conv_filters, (1, 1), padding='same', use_bias=False, strides=(1, 1), name='conv_pw_%d' % block_id)(x) x = BatchNormalization(axis=channel_axis, name='conv_pw_%d_bn' % block_id)(x) x = Activation(relu6, name='conv_pw_%d_relu' % block_id)(x) # squeeze and excite block x = squeeze_excite_block(x) return x
def inception_resnet_block(x, scale, block_type, block_idx, activation='relu'): """Adds a Inception-ResNet block with Squeeze and Excitation block at the end. This function builds 3 types of Inception-ResNet blocks mentioned in the paper, controlled by the `block_type` argument (which is the block name used in the official TF-slim implementation): - Inception-ResNet-A: `block_type='block35'` - Inception-ResNet-B: `block_type='block17'` - Inception-ResNet-C: `block_type='block8'` # Arguments x: input keras tensor. scale_: scaling factor to scale_ the residuals (i.e., the output of passing `x` through an inception module) before adding them to the shortcut branch. Let `r` be the output from the residual branch, the output of this block will be `x + scale_ * r`. block_type: `'block35'`, `'block17'` or `'block8'`, determines the network structure in the residual branch. block_idx: an `int` used for generating layer names. The Inception-ResNet blocks are repeated many times in this network. We use `block_idx` to identify each of the repetitions. For example, the first Inception-ResNet-A block will have `block_type='block35', block_idx=0`, ane the layer names will have a common prefix `'block35_0'`. activation: activation function to use at the end of the block (see [activations](../activations.md)). When `activation=None`, no activation is applied (i.e., "linear" activation: `a(x) = x`). # Returns Output tensor for the block. # Raises ValueError: if `block_type` is not one of `'block35'`, `'block17'` or `'block8'`. """ if block_type == 'block35': branch_0 = conv2d_bn(x, 32, 1) branch_1 = conv2d_bn(x, 32, 1) branch_1 = conv2d_bn(branch_1, 32, 3) branch_2 = conv2d_bn(x, 32, 1) branch_2 = conv2d_bn(branch_2, 48, 3) branch_2 = conv2d_bn(branch_2, 64, 3) branches = [branch_0, branch_1, branch_2] elif block_type == 'block17': branch_0 = conv2d_bn(x, 192, 1) branch_1 = conv2d_bn(x, 128, 1) branch_1 = conv2d_bn(branch_1, 160, [1, 7]) branch_1 = conv2d_bn(branch_1, 192, [7, 1]) branches = [branch_0, branch_1] elif block_type == 'block8': branch_0 = conv2d_bn(x, 192, 1) branch_1 = conv2d_bn(x, 192, 1) branch_1 = conv2d_bn(branch_1, 224, [1, 3]) branch_1 = conv2d_bn(branch_1, 256, [3, 1]) branches = [branch_0, branch_1] else: raise ValueError('Unknown Inception-ResNet block type. ' 'Expects "block35", "block17" or "block8", ' 'but got: {block_type}'.format(block_type=block_type)) block_name = '{block_type}_{block_idx}'.format(block_type=block_type, block_idx=block_idx) channel_axis = 1 if K.image_data_format() == 'channels_first' else 3 mixed = Concatenate(axis=channel_axis, name='{block_name}_mixed'.format(block_name=block_name))(branches) up = conv2d_bn(mixed, K.int_shape(x)[channel_axis], 1, activation=None, use_bias=True, name='{block_name}_conv'.format(block_name=block_name)) x = Lambda(lambda inputs, scale_: inputs[0] + inputs[1] * scale_, output_shape=K.int_shape(x)[1:], arguments={'scale': scale}, name=block_name)([x, up]) if activation is not None: x = Activation(activation, name='{block_name}_ac'.format(block_name=block_name))(x) # squeeze and excite block x = squeeze_excite_block(x) return x
def SEInceptionResNetV2(include_top=True, weights=None, input_tensor=None, input_shape=None, pooling=None, classes=1000): """Instantiates the SE-Inception-ResNet v2 architecture. Optionally loads weights pre-trained on ImageNet. Note that when using TensorFlow, for best performance you should set `"image_data_format": "channels_last"` in your Keras config at `~/.keras/keras.json`. The model and the weights are compatible with both TensorFlow and Theano backends (but not CNTK). The data format convention used by the model is the one specified in your Keras config file. Note that the default input image size for this model is 299x299, instead of 224x224 as in the VGG16 and ResNet models. Also, the input preprocessing function is different (i.e., do not use `imagenet_utils.preprocess_input()` with this model. Use `preprocess_input()` defined in this module instead). # Arguments include_top: whether to include the fully-connected layer at the top of the network. weights: one of `None` (random initialization) or `'imagenet'` (pre-training on ImageNet). input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model. input_shape: optional shape tuple, only to be specified if `include_top` is `False` (otherwise the input shape has to be `(299, 299, 3)` (with `'channels_last'` data format) or `(3, 299, 299)` (with `'channels_first'` data format). It should have exactly 3 inputs channels, and width and height should be no smaller than 139. E.g. `(150, 150, 3)` would be one valid value. pooling: Optional pooling mode for feature extraction when `include_top` is `False`. - `None` means that the output of the model will be the 4D tensor output of the last convolutional layer. - `'avg'` means that global average pooling will be applied to the output of the last convolutional layer, and thus the output of the model will be a 2D tensor. - `'max'` means that global max pooling will be applied. classes: optional number of classes to classify images into, only to be specified if `include_top` is `True`, and if no `weights` argument is specified. # Returns A Keras `Model` instance. # Raises ValueError: in case of invalid argument for `weights`, or invalid input shape. RuntimeError: If attempting to run this model with an unsupported backend. """ if K.backend() in {'cntk'}: raise RuntimeError('{backend} backend is currently unsupported for this model.'.format(backend=K.backend())) if weights not in {'imagenet', None}: raise ValueError('The `weights` argument should be either ' '`None` (random initialization) or `imagenet` ' '(pre-training on ImageNet).') if weights == 'imagenet' and include_top and classes != 1000: raise ValueError('If using `weights` as imagenet with `include_top`' ' as true, `classes` should be 1000') # Determine proper input shape input_shape = _obtain_input_shape( input_shape, default_size=299, min_size=139, data_format=K.image_data_format(), require_flatten=False, weights=weights) if input_tensor is None: img_input = Input(shape=input_shape) else: if not is_keras_tensor(input_tensor): img_input = Input(tensor=input_tensor, shape=input_shape) else: img_input = input_tensor # Stem block: 35 x 35 x 192 x = conv2d_bn(img_input, 32, 3, strides=2, padding='valid') x = conv2d_bn(x, 32, 3, padding='valid') x = conv2d_bn(x, 64, 3) x = MaxPooling2D(3, strides=2)(x) x = conv2d_bn(x, 80, 1, padding='valid') x = conv2d_bn(x, 192, 3, padding='valid') x = MaxPooling2D(3, strides=2)(x) # Mixed 5b (Inception-A block): 35 x 35 x 320 branch_0 = conv2d_bn(x, 96, 1) branch_1 = conv2d_bn(x, 48, 1) branch_1 = conv2d_bn(branch_1, 64, 5) branch_2 = conv2d_bn(x, 64, 1) branch_2 = conv2d_bn(branch_2, 96, 3) branch_2 = conv2d_bn(branch_2, 96, 3) branch_pool = AveragePooling2D(3, strides=1, padding='same')(x) branch_pool = conv2d_bn(branch_pool, 64, 1) branches = [branch_0, branch_1, branch_2, branch_pool] channel_axis = 1 if K.image_data_format() == 'channels_first' else 3 x = Concatenate(axis=channel_axis, name='mixed_5b')(branches) # squeeze and excite block x = squeeze_excite_block(x) # 10x block35 (Inception-ResNet-A block): 35 x 35 x 320 for block_idx in range(1, 11): x = inception_resnet_block(x, scale=0.17, block_type='block35', block_idx=block_idx) # Mixed 6a (Reduction-A block): 17 x 17 x 1088 branch_0 = conv2d_bn(x, 384, 3, strides=2, padding='valid') branch_1 = conv2d_bn(x, 256, 1) branch_1 = conv2d_bn(branch_1, 256, 3) branch_1 = conv2d_bn(branch_1, 384, 3, strides=2, padding='valid') branch_pool = MaxPooling2D(3, strides=2, padding='valid')(x) branches = [branch_0, branch_1, branch_pool] x = Concatenate(axis=channel_axis, name='mixed_6a')(branches) # squeeze and excite block x = squeeze_excite_block(x) # 20x block17 (Inception-ResNet-B block): 17 x 17 x 1088 for block_idx in range(1, 21): x = inception_resnet_block(x, scale=0.1, block_type='block17', block_idx=block_idx) # Mixed 7a (Reduction-B block): 8 x 8 x 2080 branch_0 = conv2d_bn(x, 256, 1) branch_0 = conv2d_bn(branch_0, 384, 3, strides=2, padding='valid') branch_1 = conv2d_bn(x, 256, 1) branch_1 = conv2d_bn(branch_1, 288, 3, strides=2, padding='valid') branch_2 = conv2d_bn(x, 256, 1) branch_2 = conv2d_bn(branch_2, 288, 3) branch_2 = conv2d_bn(branch_2, 320, 3, strides=2, padding='valid') branch_pool = MaxPooling2D(3, strides=2, padding='valid')(x) branches = [branch_0, branch_1, branch_2, branch_pool] x = Concatenate(axis=channel_axis, name='mixed_7a')(branches) # squeeze and excite block x = squeeze_excite_block(x) # 10x block8 (Inception-ResNet-C block): 8 x 8 x 2080 for block_idx in range(1, 10): x = inception_resnet_block(x, scale=0.2, block_type='block8', block_idx=block_idx) x = inception_resnet_block(x, scale=1., activation=None, block_type='block8', block_idx=10) # squeeze and excite block x = squeeze_excite_block(x) # Final convolution block: 8 x 8 x 1536 x = conv2d_bn(x, 1536, 1, name='conv_7b') if include_top: # Classification block x = GlobalAveragePooling2D(name='avg_pool')(x) x = Dense(classes, activation='softmax', name='predictions')(x) else: if pooling == 'avg': x = GlobalAveragePooling2D()(x) elif pooling == 'max': x = GlobalMaxPooling2D()(x) # Ensure that the model takes into account # any potential predecessors of `input_tensor` if input_tensor is not None: inputs = get_source_inputs(input_tensor) else: inputs = img_input # Create model model = Model(inputs, x, name='se_inception_resnet_v2') return model