def call(self, x, mask=None): if K.backend() == 'theano': pos = K.relu(x) * ( K.pattern_broadcast(self.alpha, self.param_broadcast) / K.pattern_broadcast(self.beta, self.param_broadcast)) neg = ( K.pattern_broadcast(self.alpha, self.param_broadcast) * (K.exp( (-K.relu(-x)) / K.pattern_broadcast(self.beta, self.param_broadcast)) - 1)) else: pos = K.relu(x) * self.alpha / self.beta neg = self.alpha * (K.exp((-K.relu(-x)) / self.beta) - 1) return neg + pos
def _se_block(inputs, filters, se_ratio, prefix): x = layers.GlobalAveragePooling2D(name=prefix + 'squeeze_excite/AvgPool')(inputs) if backend.image_data_format() == 'channels_first': x = layers.Reshape((filters, 1, 1))(x) else: x = layers.Reshape((1, 1, filters))(x) x = layers.Conv2D(_depth(filters * se_ratio), kernel_size=1, padding='same', name=prefix + 'squeeze_excite/Conv')(x) x = layers.ReLU(name=prefix + 'squeeze_excite/Relu')(x) x = layers.Conv2D(filters, kernel_size=1, padding='same', name=prefix + 'squeeze_excite/Conv_1')(x) x = layers.Activation(hard_sigmoid)(x) if backend.backend() == 'theano': # For the Theano backend, we have to explicitly make # the excitation weights broadcastable. x = layers.Lambda(lambda br: backend.pattern_broadcast( br, [True, True, True, False]), output_shape=lambda input_shape: input_shape, name=prefix + 'squeeze_excite/broadcast')(x) x = layers.Multiply(name=prefix + 'squeeze_excite/Mul')([inputs, x]) return x
def call(self, x, mask=None): # ensure the the right part is always to the right of the left t_right_actual = self.t_left + K.abs(self.t_right) if K.backend() == 'theano': t_left = K.pattern_broadcast(self.t_left, self.param_broadcast) a_left = K.pattern_broadcast(self.a_left, self.param_broadcast) a_right = K.pattern_broadcast(self.a_right, self.param_broadcast) t_right_actual = K.pattern_broadcast(t_right_actual, self.param_broadcast) else: t_left = self.t_left a_left = self.a_left a_right = self.a_right y_left_and_center = t_left + K.relu(x - t_left, a_left, t_right_actual - t_left) y_right = K.relu(x - t_right_actual) * a_right return y_left_and_center + y_right
def call(self, x, mask=None): b, xb = 0., 0. if self.data_format == 'channels_first': kernel_sum_axes = [1, 2, 3] if self.use_bias: b = K.reshape(self.b, (self.filters, 1, 1, 1)) xb = 1. elif self.data_format == 'channels_last': kernel_sum_axes = [0, 1, 2] if self.use_bias: b = K.reshape(self.b, (1, 1, 1, self.filters)) xb = 1. tmp = K.sum(K.square(self.W), axis=kernel_sum_axes, keepdims=True) Wnorm = K.sqrt(tmp + K.square(b) + K.epsilon()) tmp = KC.conv2d(K.square(x), self.kernel_norm, strides=self.strides, padding=self.padding, data_format=self.data_format, filter_shape=self.kernel_norm_shape) xnorm = K.sqrt(tmp + xb + K.epsilon()) W = self.W / Wnorm output = KC.conv2d(x, W, strides=self.strides, padding=self.padding, data_format=self.data_format, filter_shape=self.kernel_shape) if K.backend() == 'theano': xnorm = K.pattern_broadcast(xnorm, [False, True, False, False]) output /= xnorm if self.use_bias: b /= Wnorm if self.data_format == 'channels_first': b = K.reshape(b, (1, self.filters, 1, 1)) elif self.data_format == 'channels_last': b = K.reshape(b, (1, 1, 1, self.filters)) else: raise ValueError('Invalid data_format:', self.data_format) b /= xnorm output += b output = self.activation(output) return output
def mb_conv_block(inputs, block_args, activation, drop_rate=None, prefix='', freeze_bn=False): has_se = (block_args.se_ratio is not None) and (0 < block_args.se_ratio <= 1) bn_axis = 3 Dropout = get_dropout() filters = block_args.input_filters * block_args.expand_ratio if block_args.expand_ratio != 1: x = layers.Conv2D(filters, 1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + 'expand_conv')(inputs) x = layers.BatchNormalization(axis=bn_axis, name=prefix + 'expand_bn')(x) x = layers.Activation(activation, name=prefix + 'expand_activation')(x) else: x = inputs # Depthwise Convolution x = layers.DepthwiseConv2D(block_args.kernel_size, strides=block_args.strides, padding='same', use_bias=False, depthwise_initializer=CONV_KERNEL_INITIALIZER, name=prefix + 'dwconv')(x) x = layers.BatchNormalization(axis=bn_axis, name=prefix + 'bn')(x) x = layers.Activation(activation, name=prefix + 'activation')(x) # Squeeze and Excitation phase if has_se: num_reduced_filters = max(1, int( block_args.input_filters * block_args.se_ratio )) se_tensor = layers.GlobalAveragePooling2D(name=prefix + 'se_squeeze')(x) target_shape = (1, 1, filters) if backend.image_data_format() == 'channels_last' else (filters, 1, 1) se_tensor = layers.Reshape(target_shape, name=prefix + 'se_reshape')(se_tensor) se_tensor = layers.Conv2D(num_reduced_filters, 1, activation=activation, padding='same', use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + 'se_reduce')(se_tensor) se_tensor = layers.Conv2D(filters, 1, activation='sigmoid', padding='same', use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + 'se_expand')(se_tensor) if backend.backend() == 'theano': # For the Theano backend, we have to explicitly make # the excitation weights broadcastable. pattern = ([True, True, True, False] if backend.image_data_format() == 'channels_last' else [True, False, True, True]) se_tensor = layers.Lambda( lambda x: backend.pattern_broadcast(x, pattern), name=prefix + 'se_broadcast')(se_tensor) x = layers.multiply([x, se_tensor], name=prefix + 'se_excite') # Output phase x = layers.Conv2D(block_args.output_filters, 1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + 'project_conv')(x) # x = BatchNormalization(freeze=freeze_bn, axis=bn_axis, name=prefix + 'project_bn')(x) x = layers.BatchNormalization(axis=bn_axis, name=prefix + 'project_bn')(x) if block_args.id_skip and all( s == 1 for s in block_args.strides ) and block_args.input_filters == block_args.output_filters: if drop_rate and (drop_rate > 0): x = Dropout(drop_rate, noise_shape=(None, 1, 1, 1), name=prefix + 'drop')(x) x = layers.add([x, inputs], name=prefix + 'add') return x
def block(inputs, activation_fn=swish, drop_rate=0., name='', filters_in=32, filters_out=16, kernel_size=3, strides=1, expand_ratio=1, se_ratio=0., id_skip=True): """A mobile inverted residual block. # Arguments inputs: input tensor. activation_fn: activation function. drop_rate: float between 0 and 1, fraction of the input units to drop. name: string, block label. filters_in: integer, the number of input filters. filters_out: integer, the number of output filters. kernel_size: integer, the dimension of the convolution window. strides: integer, the stride of the convolution. expand_ratio: integer, scaling coefficient for the input filters. se_ratio: float between 0 and 1, fraction to squeeze the input filters. id_skip: boolean. # Returns output tensor for the block. """ bn_axis = 3 if K.image_data_format() == 'channels_last' else 1 # Expansion phase filters = filters_in * expand_ratio if expand_ratio != 1: x = Conv2D(filters, 1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name=name + 'expand_conv')(inputs) x = BatchNormalization(axis=bn_axis, name=name + 'expand_bn')(x) x = Activation(activation_fn, name=name + 'expand_activation')(x) else: x = inputs # Depthwise Convolution if strides == 2: x = ZeroPadding2D(padding=correct_pad(K, x, kernel_size), name=name + 'dwconv_pad')(x) conv_pad = 'valid' else: conv_pad = 'same' x = DepthwiseConv2D(kernel_size, strides=strides, padding=conv_pad, use_bias=False, depthwise_initializer=CONV_KERNEL_INITIALIZER, name=name + 'dwconv')(x) x = BatchNormalization(axis=bn_axis, name=name + 'bn')(x) x = Activation(activation_fn, name=name + 'activation')(x) # Squeeze and Excitation phase if 0 < se_ratio <= 1: filters_se = max(1, int(filters_in * se_ratio)) se = GlobalAveragePooling2D(name=name + 'se_squeeze')(x) se = Reshape((1, 1, filters), name=name + 'se_reshape')(se) se = Conv2D(filters_se, 1, padding='same', activation=activation_fn, kernel_initializer=CONV_KERNEL_INITIALIZER, name=name + 'se_reduce')(se) se = Conv2D(filters, 1, padding='same', activation='sigmoid', kernel_initializer=CONV_KERNEL_INITIALIZER, name=name + 'se_expand')(se) if K.backend() == 'theano': # For the Theano backend, we have to explicitly make # the excitation weights broadcastable. se = Lambda( lambda x: K.pattern_broadcast(x, [True, True, True, False]), output_shape=lambda input_shape: input_shape, name=name + 'se_broadcast')(se) x = multiply([x, se], name=name + 'se_excite') # Output phase x = Conv2D(filters_out, 1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name=name + 'project_conv')(x) x = BatchNormalization(axis=bn_axis, name=name + 'project_bn')(x) if (id_skip is True and strides == 1 and filters_in == filters_out): if drop_rate > 0: if tf2.enabled(): x = Dropout(drop_rate, noise_shape=(None, 1, 1, 1), name=name + 'drop')(x) else: x = Dropout( drop_rate, #noise_shape=(None, 1, 1, 1), name=name + 'drop')(x) x = add([x, inputs], name=name + 'add') return x
def mb_conv_block( inputs, block_args, drop_rate=None, prefix="", ): """Mobile Inverted Residual Bottleneck.""" has_se = (block_args.se_ratio is not None) and (0 < block_args.se_ratio <= 1) bn_axis = 3 if K.image_data_format() == "channels_last" else 1 # Expansion phase filters = block_args.input_filters * block_args.expand_ratio if block_args.expand_ratio != 1: x = layers.Conv2D(filters, 1, padding="same", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + "expand_conv")(inputs) x = layers.BatchNormalization(axis=bn_axis, name=prefix + "expand_bn")(x) x = layers.Multiply()([x, layers.Activation("sigmoid")(x)]) else: x = inputs # Depthwise Convolution x = layers.DepthwiseConv2D( block_args.kernel_size, strides=block_args.strides, padding="same", use_bias=False, depthwise_initializer=CONV_KERNEL_INITIALIZER, name=prefix + "dwconv", )(x) x = layers.BatchNormalization(axis=bn_axis, name=prefix + "bn")(x) x = layers.Multiply()([x, layers.Activation("sigmoid")(x)]) # Squeeze and Excitation phase if has_se: num_reduced_filters = max( 1, int(block_args.input_filters * block_args.se_ratio)) se_tensor = layers.GlobalAveragePooling2D(name=prefix + "se_squeeze")(x) target_shape = ( 1, 1, filters) if K.image_data_format() == "channels_last" else (filters, 1, 1) se_tensor = layers.Reshape(target_shape, name=prefix + "se_reshape")(se_tensor) se_tensor = layers.Conv2D( num_reduced_filters, 1, padding="same", use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + "se_reduce", )(se_tensor) se_tensor = layers.Multiply()( [se_tensor, layers.Activation("sigmoid")(se_tensor)]) se_tensor = layers.Conv2D( filters, 1, activation="sigmoid", padding="same", use_bias=True, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + "se_expand", )(se_tensor) if K.backend() == "theano": # For the Theano backend, we have to explicitly make # the excitation weights broadcastable. pattern = [True, True, True, False ] if K.image_data_format() == "channels_last" else [ True, False, True, True ] se_tensor = layers.Lambda( lambda x: K.pattern_broadcast(x, pattern), name=prefix + "se_broadcast")(se_tensor) x = layers.multiply([x, se_tensor], name=prefix + "se_excite") # Output phase x = layers.Conv2D( block_args.output_filters, 1, padding="same", use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name=prefix + "project_conv", )(x) x = layers.BatchNormalization(axis=bn_axis, name=prefix + "project_bn")(x) if block_args.id_skip and all( s == 1 for s in block_args.strides ) and block_args.input_filters == block_args.output_filters: if drop_rate and (drop_rate > 0): x = layers.Dropout(drop_rate, noise_shape=(-1, 1, 1, 1), name=prefix + "drop")(x) x = layers.add([x, inputs], name=prefix + "add") return x