def depthwise_block(x, strides, **metaparameters): """ Construct a Depthwise Separable Convolution block x : input to the block strides : strides n_filters : number of filters alpha : width multiplier """ n_filters = metaparameters['n_filters'] alpha = metaparameters['alpha'] del metaparameters['n_filters'] # Apply the width filter to the number of feature maps filters = int(n_filters * alpha) # Strided convolution to match number of filters if strides == (2, 2): x = ZeroPadding2D(padding=((0, 1), (0, 1)))(x) padding = 'valid' else: padding = 'same' # Depthwise Convolution x = Composable.DepthwiseConv2D(x, (3, 3), strides, padding=padding, use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Pointwise Convolution x = Composable.Conv2D(x, filters, (1, 1), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) return x
def residual_block(x, **metaparameters): """ Construct a Residual Block x : input to the block n_filters: number of filters in convolution layer in residual block """ if 'n_filters' in metaparameters: n_filters = metaparameters['n_filters'] del metaparameters['n_filters'] else: n_filters = DenseNet.n_filters # Remember input tensor into residual block shortcut = x # BN-RE-Conv pre-activation form of convolutions # Dimensionality expansion, expand filters by 4 (DenseNet-B) x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, 4 * n_filters, (1, 1), strides=(1, 1), use_bias=False, **metaparameters) # Bottleneck convolution # 3x3 convolution with padding=same to preserve same shape of feature maps x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters, (3, 3), strides=(1, 1), padding='same', use_bias=False, **metaparameters) # Concatenate the input (identity) with the output of the residual block # Concatenation (vs. merging) provides Feature Reuse between layers x = Concatenate()([shortcut, x]) return x
def decoder(x, init_weights=None, **metaparameters): ''' Construct the Decoder x : input to the decoder layers: number of filters per layer reg : kernel regularizer ''' layers = metaparameters['layers'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = AutoEncoder.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = AutoEncoder.init_weights # Progressive Feature Unpooling for _ in range(len(layers)-1, 0, -1): n_filters = layers[_]['n_filters'] x = Conv2DTranspose(n_filters, (3, 3), strides=2, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(x) x = BatchNormalization()(x) x = Composable.ReLU(x) # Last unpooling and match shape to input x = Conv2DTranspose(3, (3, 3), strides=2, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(x) x = BatchNormalization()(x) x = Composable.ReLU(x) # The decoded image return x
def projection_block(x, **metaparameters): """ Create a residual block using Depthwise Separable Convolutions with Projection shortcut x : input into residual block n_filters: number of filters """ n_filters = metaparameters['n_filters'] del metaparameters['n_filters'] # Remember the input shortcut = x # Strided convolution to double number of filters in identity link to # match output of residual block for the add operation (projection shortcut) shortcut = Composable.Conv2D(x, n_filters, (1, 1), strides=(2, 2), padding='same', **metaparameters) shortcut = BatchNormalization()(shortcut) # First Depthwise Separable Convolution x = Composable.SeparableConv2D(x, n_filters, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Second depthwise Separable Convolution x = Composable.SeparableConv2D(x, n_filters, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Create pooled feature maps, reduce size by 75% x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) # Add the projection shortcut to the output of the block x = Add()([x, shortcut]) return x
def residual_block(x, **metaparameters): """ Create a residual block using Depthwise Separable Convolutions x : input into residual block n_filters: number of filters """ n_filters = metaparameters['n_filters'] del metaparameters['n_filters'] # Remember the input shortcut = x # First Depthwise Separable Convolution x = Composable.SeparableConv2D(x, n_filters, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Second depthwise Separable Convolution x = Composable.SeparableConv2D(x, n_filters, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Third depthwise Separable Convolution x = Composable.SeparableConv2D(x, n_filters, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Add the identity link to the output of the block x = Add()([x, shortcut]) return x
def fire_block(x, **metaparameters): ''' Construct a Fire Block with complex bypass x : input to the block n_filters: number of filters in block reg : kernel regularizer ''' n_filters = metaparameters['n_filters'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = SqueezeNetComplex.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = SqueezeNetComplex.init_weights # remember the input (identity) shortcut = x # if the number of input filters does not equal the number of output filters, then use # a transition convolution to match the number of filters in identify link to output if shortcut.shape[3] != 8 * n_filters: shortcut = Conv2D(n_filters * 8, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(shortcut) shortcut = Composable.ReLU(shortcut) # squeeze layer squeeze = Conv2D(n_filters, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(x) squeeze = Composable.ReLU(squeeze) # branch the squeeze layer into a 1x1 and 3x3 convolution and double the number # of filters expand1x1 = Conv2D(n_filters * 4, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(squeeze) expand1x1 = Composable.ReLU(expand1x1) expand3x3 = Conv2D(n_filters * 4, (3, 3), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(squeeze) expand3x3 = Composable.ReLU(expand3x3) # concatenate the feature maps from the 1x1 and 3x3 branches x = Concatenate()([expand1x1, expand3x3]) # if identity link, add (matrix addition) input filters to output filters if shortcut is not None: x = Add()([x, shortcut]) return x
def identity_block(x, **metaparameters): """ Construct a ResNeXT block with identity link x : input to block filters_in : number of filters (channels) at the input convolution filters_out : number of filters (channels) at the output convolution cardinality : width of group convolution """ filters_in = metaparameters['filters_in'] filters_out = metaparameters['filters_out'] if 'cardinality' in metaparameters: cardinality = metaparameters['cardinality'] else: cardinality = ResNeXt.cardinality # Remember the input shortcut = x # Dimensionality Reduction x = Composable.Conv2D(x, filters_in, (1, 1), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Cardinality (Wide) Layer (split-transform) filters_card = filters_in // cardinality groups = [] for i in range(cardinality): group = Lambda(lambda z: z[:, :, :, i * filters_card:i * filters_card + filters_card])(x) groups.append( Composable.Conv2D(group, filters_card, (3, 3), strides=(1, 1), padding='same', use_bias=False, **metaparameters)) # Concatenate the outputs of the cardinality layer together (merge) x = Concatenate()(groups) x = BatchNormalization()(x) x = Composable.ReLU(x) # Dimensionality restoration x = Composable.Conv2D(x, filters_out, (1, 1), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) # Identity Link: Add the shortcut (input) to the output of the block x = Add()([shortcut, x]) x = Composable.ReLU(x) return x
def strided_shuffle_block(x, **metaparameters): ''' Construct a Strided Shuffle Block x : input to the block n_partitions: number of groups to partition feature maps (channels) into. n_filters : number of filters reduction : dimensionality reduction factor (e.g, 0.25) ''' n_partitions = metaparameters['n_partitions'] n_filters = metaparameters['n_filters'] reduction = metaparameters['reduction'] del metaparameters['n_filters'] del metaparameters['n_partitions'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = ShuffleNet.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = ShuffleNet.init_weights # projection shortcut shortcut = x shortcut = AveragePooling2D((3, 3), strides=2, padding='same')(shortcut) # On entry block, we need to adjust the number of output filters # of the entry pointwise group convolution to match the exit # pointwise group convolution, by subtracting the number of input filters n_filters -= int(x.shape[3]) # pointwise group convolution, with dimensionality reduction x = ShuffleNet.pw_group_conv(x, n_partitions, int(reduction * n_filters), **metaparameters) x = Composable.ReLU(x) # channel shuffle layer x = ShuffleNet.channel_shuffle(x, n_partitions) # Depthwise 3x3 Strided Convolution x = DepthwiseConv2D((3, 3), strides=2, padding='same', use_bias=False, kernel_initializer=init_weights, kernel_regularizer=reg)(x) x = BatchNormalization()(x) # pointwise group convolution, with dimensionality restoration x = ShuffleNet.pw_group_conv(x, n_partitions, n_filters, **metaparameters) # Concatenate the projection shortcut to the output x = Concatenate()([shortcut, x]) x = Composable.ReLU(x) return x
def projection_block(x, strides=(2, 2), **metaparameters): """ Create Bottleneck Residual Block with Projection Shortcut Increase the number of filters by 4X x : input into the block strides : whether entry convolution is strided (i.e., (2, 2) vs (1, 1)) n_filters: number of filters """ n_filters = metaparameters['n_filters'] del metaparameters['n_filters'] # Construct the projection shortcut # Increase filters by 4X to match shape when added to output of block shortcut = Composable.Conv2D(x, 4 * n_filters, (1, 1), strides=strides, use_bias=False, **metaparameters) shortcut = BatchNormalization()(shortcut) ## Construct the 1x1, 3x3, 1x1 residual block (fig 3c) # Dimensionality reduction # Feature pooling when strides=(2, 2) x = Composable.Conv2D(x, n_filters, (1, 1), strides=strides, use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Bottleneck layer x = Composable.Conv2D(x, n_filters, (3, 3), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Dimensionality restoration - increase the number of filters by 4X x = Composable.Conv2D(x, 4 * n_filters, (1, 1), strides=(1, 1), use_bias=False, **metaparameters) x = BatchNormalization()(x) # Pass the output through the squeeze and excitation block x = SEResNet.squeeze_excite_block(x, **metaparameters) # Add the projection shortcut link to the output of the residual block x = Add()([x, shortcut]) x = Composable.ReLU(x) return x
def projection_block(x, strides=(2, 2), **metaparameters): """ Construct a Bottleneck Residual Block of Convolutions with Projection Shortcut Increase the number of filters by 4X x : input into the block strides : whether the first convolution is strided n_filters: number of filters reg : kernel regularizer """ n_filters = metaparameters['n_filters'] del metaparameters['n_filters'] # Construct the projection shortcut # Increase filters by 4X to match shape when added to output of block shortcut = BatchNormalization()(x) shortcut = Composable.Conv2D(shortcut, 4 * n_filters, (1, 1), strides=strides, use_bias=False, **metaparameters) ## Construct the 1x1, 3x3, 1x1 convolution block # Dimensionality reduction x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters, (1, 1), strides=(1, 1), use_bias=False, **metaparameters) # Bottleneck layer # Feature pooling when strides=(2, 2) x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters, (3, 3), strides=strides, padding='same', use_bias=False, **metaparameters) # Dimensionality restoration - increase the number of filters by 4X x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, 4 * n_filters, (1, 1), strides=(1, 1), use_bias=False, **metaparameters) # Add the projection shortcut to the output of the residual block x = Add()([x, shortcut]) return x
def fire_block(x, **metaparameters): ''' Construct a Fire Block x : input to the block n_filters: number of filters in the block bypass : whether block has an identity shortcut reg : kernel regularizer ''' n_filters = metaparameters['n_filters'] bypass = metaparameters['bypass'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = SqueezeNetBypass.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = SqueezeNetBypass.init_weights # remember the input shortcut = x # squeeze layer squeeze = Conv2D(n_filters, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(x) squeeze = Composable.ReLU(squeeze) # branch the squeeze layer into a 1x1 and 3x3 convolution and double the number # of filters expand1x1 = Conv2D(n_filters * 4, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(squeeze) expand1x1 = Composable.ReLU(expand1x1) expand3x3 = Conv2D(n_filters * 4, (3, 3), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(squeeze) expand3x3 = Composable.ReLU(expand3x3) # concatenate the feature maps from the 1x1 and 3x3 branches x = Concatenate()([expand1x1, expand3x3]) # if identity link, add (matrix addition) input filters to output filters if bypass: x = Add()([x, shortcut]) return x
def shuffle_block(x, **metaparameters): ''' Construct a shuffle Shuffle block x : input to the block n_partitions: number of groups to partition feature maps (channels) into. n_filters : number of filters reduction : dimensionality reduction factor (e.g, 0.25) reg : kernel regularizer ''' n_partitions = metaparameters['n_partitions'] n_filters = metaparameters['n_filters'] reduction = metaparameters['reduction'] del metaparameters['n_filters'] del metaparameters['n_partitions'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = ShuffleNet.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = ShuffleNet.init_weights # identity shortcut shortcut = x # pointwise group convolution, with dimensionality reduction x = ShuffleNet.pw_group_conv(x, n_partitions, int(reduction * n_filters), **metaparameters) x = Composable.ReLU(x) # channel shuffle layer x = ShuffleNet.channel_shuffle(x, n_partitions) # Depthwise 3x3 Convolution x = Composable.DepthwiseConv2D(x, (3, 3), strides=1, padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) # pointwise group convolution, with dimensionality restoration x = ShuffleNet.pw_group_conv(x, n_partitions, n_filters, **metaparameters) # Add the identity shortcut (input added to output) x = Add()([shortcut, x]) x = Composable.ReLU(x) return x
def classifier(self, x, n_classes): ''' Construct the Classifier x : input to the classifier n_classes: number of output classes ''' # Save the encoding layer self.encoding = x # set the number of filters equal to number of classes x = Conv2D(n_classes, (1, 1), strides=1, padding='same', kernel_initializer=self.init_weights, kernel_regularizer=self.reg)(x) x = Composable.ReLU(x) # reduce each filter (class) to a single value x = GlobalAveragePooling2D()(x) # Save the pre-activation probabilities layer self.probabilities = x outputs = Activation('softmax')(x) # Save the post-activation probabilities layer self.softmax = outputs return outputs
def stem(self, inputs): """ Construct the Stem Convolutional Group inputs : the input vector """ # The 224x224 images are zero padded (black - no signal) to be 230x230 images prior to the first convolution x = ZeroPadding2D(padding=(3, 3))(inputs) # First Convolutional layer which uses a large (coarse) filter x = self.Conv2D(x, 64, (7, 7), strides=(2, 2), padding='valid', use_bias=False) x = BatchNormalization()(x) x = self.ReLU(x) # Pooled feature maps will be reduced by 75% x = ZeroPadding2D(padding=(1, 1))(x) x = MaxPooling2D((3, 3), strides=(2, 2))(x) # Second Convolutional layer which uses a mid-size filter x = self.Conv2D(x, 64, (1, 1), strides=(1, 1), padding='same', use_bias=False) x = BatchNormalization()(x) x = Composable.ReLU(x) x = ZeroPadding2D(padding=(1, 1))(x) x = self.Conv2D(x, 192, (3, 3), strides=(1, 1), padding='valid', use_bias=False) x = BatchNormalization()(x) x = self.ReLU(x) # Pooled feature maps will be reduced by 75% x = ZeroPadding2D(padding=(1, 1))(x) x = MaxPooling2D((3, 3), strides=(2, 2))(x) return x
def encoder(x, init_weights=None, **metaparameters): ''' Construct the Encoder x : input to the encoder layers: number of filters per layer reg : kernel regularizer ''' layers = metaparameters['layers'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = AutoEncoder.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = AutoEncoder.init_weights # Progressive Feature Pooling for layer in layers: n_filters = layer['n_filters'] x = Conv2D(n_filters, (3, 3), strides=2, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(x) x = BatchNormalization()(x) x = Composable.ReLU(x) # The Encoding return x
def stem(inputs): """ Create the stem entry into the neural network inputs : input tensor to neural network """ # Strided convolution - dimensionality reduction # Reduce feature maps by 75% x = Composable.Conv2D(inputs, 32, (3, 3), strides=(2, 2), **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Convolution - dimensionality expansion # Double the number of filters x = Composable.Conv2D(x, 64, (3, 3), strides=(1, 1), **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) return x
def identity_block(x, **metaparameters): """ Create a Bottleneck Residual Block with Identity Link x : input into the block n_filters: number of filters """ n_filters = metaparameters['n_filters'] del metaparameters['n_filters'] # Save input vector (feature maps) for the identity link shortcut = x ## Construct the 1x1, 3x3, 1x1 residual block (fig 3c) # Dimensionality reduction x = Composable.Conv2D(x, n_filters, (1, 1), strides=(1, 1), use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Bottleneck layer x = Composable.Conv2D(x, n_filters, (3, 3), strides=(1, 1), padding="same", use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Dimensionality restoration - increase the number of output filters by 4X x = Composable.Conv2D(x, n_filters * 4, (1, 1), strides=(1, 1), use_bias=False, **metaparameters) x = BatchNormalization()(x) # Pass the output through the squeeze and excitation block x = SEResNet.squeeze_excite_block(x, **metaparameters) # Add the identity link (input) to the output of the residual block x = Add()([shortcut, x]) x = Composable.ReLU(x) return x
def projection_block(x, **metaparameters): """ Construct a B(3,3) style block x : input into the block n_filters: number of filters k : width factor strides : whether the projection shortcut is strided """ n_filters = metaparameters['n_filters'] strides = metaparameters['strides'] k = metaparameters['k'] del metaparameters['n_filters'] del metaparameters['strides'] # Save input vector (feature maps) for the identity link shortcut = BatchNormalization()(x) shortcut = Composable.Conv2D(shortcut, n_filters * k, (3, 3), strides=strides, padding='same', use_bias=False, **metaparameters) ## Construct the 3x3, 3x3 convolution block x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters * k, (3, 3), strides=strides, padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters * k, (3, 3), strides=(1, 1), padding='same', use_bias=False, **metaparameters) # Add the identity link (input) to the output of the residual block x = Add()([shortcut, x]) return x
def exitFlow(x, n_classes, **metaparameters): """ Create the exit flow section x : input to the exit flow section n_classes : number of output classes """ # Remember the input shortcut = x # Strided convolution to double number of filters in identity link to # match output of residual block for the add operation (projection shortcut) shortcut = Composable.Conv2D(x, 1024, (1, 1), strides=(2, 2), padding='same', **metaparameters) shortcut = BatchNormalization()(shortcut) # First Depthwise Separable Convolution # Dimensionality reduction - reduce number of filters x = Composable.SeparableConv2D(x, 728, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) # Second Depthwise Separable Convolution # Dimensionality restoration x = Composable.SeparableConv2D(x, 1024, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Create pooled feature maps, reduce size by 75% x = MaxPooling2D((3, 3), strides=(2, 2), padding='same')(x) # Add the projection shortcut to the output of the pooling layer x = Add()([x, shortcut]) # Third Depthwise Separable Convolution x = Composable.SeparableConv2D(x, 1556, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Fourth Depthwise Separable Convolution x = Composable.SeparableConv2D(x, 2048, (3, 3), padding='same', **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Create classifier section x = Composable.classifier(x, n_classes, **metaparameters) return x
def identity_block(x, **metaparameters): """ Construct a B(3,3) style block x : input into the block n_filters: number of filters k : width factor dropout : dropout rate """ n_filters = metaparameters['n_filters'] k = metaparameters['k'] dropout = metaparameters['dropout'] del metaparameters['n_filters'] del metaparameters['strides'] # Save input vector (feature maps) for the identity link shortcut = x ## Construct the 3x3, 3x3 convolution block x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters * k, (3, 3), strides=(1, 1), padding='same', use_bias=False, **metaparameters) # dropout only in identity link (not projection) if dropout > 0: x = Dropout(dropout) x = BatchNormalization()(x) x = Composable.ReLU(x) x = Composable.Conv2D(x, n_filters * k, (3, 3), strides=(1, 1), padding='same', use_bias=False, **metaparameters) # Add the identity link (input) to the output of the residual block x = Add()([shortcut, x]) return x
def fire_block(x, **metaparameters): ''' Construct a Fire Block x : input to the block n_filters: number of filters reg : kernel regularizer ''' n_filters = metaparameters['n_filters'] if 'reg' in metaparameters: reg = metaparameters['reg'] else: reg = SqueezeNet.reg if 'init_weights' in metaparameters: init_weights = metaparameters['init_weights'] else: init_weights = SqueezeNet.init_weights # squeeze layer squeeze = Conv2D(n_filters, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(x) squeeze = Composable.ReLU(x) # branch the squeeze layer into a 1x1 and 3x3 convolution and double the number # of filters expand1x1 = Conv2D(n_filters * 4, (1, 1), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(squeeze) expand1x1 = Composable.ReLU(expand1x1) expand3x3 = Conv2D(n_filters * 4, (3, 3), strides=1, padding='same', kernel_initializer=init_weights, kernel_regularizer=reg)(squeeze) expand3x3 = Composable.ReLU(expand3x3) # concatenate the feature maps from the 1x1 and 3x3 branches x = Concatenate()([expand1x1, expand3x3]) return x
def stem(self, inputs): ''' Construct the Stem Group inputs : input tensor ''' x = Conv2D(96, (7, 7), strides=2, padding='same', kernel_initializer=self.init_weights, kernel_regularizer=self.reg)(inputs) x = Composable.ReLU(x) x = MaxPooling2D(3, strides=2)(x) return x
def auxiliary(x, n_classes, **metaparameters): """ Construct the auxiliary classier x : input to the auxiliary classifier n_classes: number of output classes """ x = AveragePooling2D((5, 5), strides=(3, 3))(x) x = Composable.Conv2D(x, 128, (1, 1), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) x = Flatten()(x) x = Composable.Dense(x, 1024, activation=Composable.ReLU, **metaparameters) x = Dropout(0.7)(x) output = Composable.Dense(x, n_classes, activation='softmax', **metaparameters) return output
def inception_block(x, f1x1, f3x3, f5x5, fpool, **metaparameters): """ Construct an Inception block (module) x : input to the block f1x1 : filters for 1x1 branch f3x3 : filters for 3x3 branch f5x5 : filters for 5x5 branch fpool: filters for pooling branch """ # 1x1 branch b1x1 = Composable.Conv2D(x, f1x1[0], (1, 1), strides=1, padding='same', use_bias=False, **metaparameters) b1x1 = BatchNormalization()(b1x1) b1x1 = Composable.ReLU(b1x1) # 3x3 branch # 3x3 reduction b3x3 = Composable.Conv2D(x, f3x3[0], (1, 1), strides=1, padding='same', use_bias=False, **metaparameters) b3x3 = BatchNormalization()(b3x3) b3x3 = Composable.ReLU(b3x3) b3x3 = ZeroPadding2D((1,1))(b3x3) b3x3 = Composable.Conv2D(b3x3, f3x3[1], (3, 3), strides=1, padding='valid', use_bias=False, **metaparameters) b3x3 = BatchNormalization()(b3x3) b3x3 = Composable.ReLU(b3x3) # 5x5 branch # 5x5 reduction b5x5 = Composable.Conv2D(x, f5x5[0], (1, 1), strides=1, padding='same', use_bias=False, **metaparameters) b5x5 = BatchNormalization()(b5x5) b5x5 = Composable.ReLU(b5x5) b5x5 = ZeroPadding2D((1,1))(b5x5) b5x5 = Composable.Conv2D(b5x5, f5x5[1], (3, 3), strides=1, padding='valid', use_bias=False, **metaparameters) b5x5 = BatchNormalization()(b5x5) b5x5 = Composable.ReLU(b5x5) # Pooling branch bpool = MaxPooling2D((3, 3), strides=1, padding='same')(x) # 1x1 projection bpool = Composable.Conv2D(bpool, fpool[0], (1, 1), strides=1, padding='same', use_bias=False, **metaparameters) bpool = BatchNormalization()(bpool) bpool = Composable.ReLU(bpool) # Concatenate the outputs (filters) of the branches x = Concatenate()([b1x1, b3x3, b5x5, bpool]) return x
def projection_block(x, strides=1, **metaparameters): """ Construct a ResNeXT block with projection shortcut x : input to the block strides : whether entry convolution is strided (i.e., (2, 2) vs (1, 1)) filters_in : number of filters (channels) at the input convolution filters_out: number of filters (channels) at the output convolution cardinality: width of cardinality layer """ filters_in = metaparameters['filters_in'] filters_out = metaparameters['filters_out'] cardinality = metaparameters['cardinality'] # Construct the projection shortcut # Increase filters by 2X to match shape when added to output of block shortcut = Composable.Conv2D(x, filters_out, kernel_size=(1, 1), strides=strides, padding='same', **metaparameters) shortcut = BatchNormalization()(shortcut) # Dimensionality Reduction x = Composable.Conv2D(x, filters_in, kernel_size=(1, 1), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) x = Composable.ReLU(x) # Cardinality (Wide) Layer (split-transform) filters_card = filters_in // cardinality groups = [] for i in range(cardinality): group = Lambda(lambda z: z[:, :, :, i * filters_card:i * filters_card + filters_card])(x) groups.append( Composable.Conv2D(group, filters_card, kernel_size=(3, 3), strides=strides, padding='same', use_bias=False, **metaparameters)) # Concatenate the outputs of the cardinality layer together (merge) x = Concatenate()(groups) x = BatchNormalization()(x) x = Composable.ReLU(x) # Dimensionality restoration x = Composable.Conv2D(x, filters_out, kernel_size=(1, 1), strides=(1, 1), padding='same', use_bias=False, **metaparameters) x = BatchNormalization()(x) # Pass the output through the squeeze and excitation block x = SEResNeXt.squeeze_excite_block(x, **metaparameters) # Add the projection shortcut (input) to the output of the block x = Add()([shortcut, x]) x = Composable.ReLU(x) return x