def build_model(self): # Build stem x = self.img_input x = layers.Rescaling(1. / 255.)(x) x = layers.Normalization(axis=self.bn_axis)(x) x = tf.keras.layers.ZeroPadding2D(padding=imagenet_utils.correct_pad( x, 3), name='stem_conv_pad')(x) x = tf.keras.layers.Conv2D(self.round_filters(32), 3, strides=2, padding='valid', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name='stem_conv')(x) x = build_normalization(**self.normalization, name='stem_bn')(x) x = build_activation(**self.activation, name='stem_activation')(x) block_outputs = [x] # Build blocks blocks_args = copy.deepcopy(self.blocks_args) b = 0 blocks = float(sum(args['repeats'] for args in blocks_args)) output_stages = [1, 2, 4, 6] for (i, args) in enumerate(blocks_args): assert args['repeats'] > 0 # Update block input and output filters based on depth multiplier. args['filters_in'] = self.round_filters(args['filters_in']) args['filters_out'] = self.round_filters(args['filters_out']) strides = args["strides"] for j in range(self.round_repeats(args.pop('repeats'))): # The first block needs to take care of stride and filter size increase. if j > 0: args['strides'] = 1 args['filters_in'] = args['filters_out'] x = self.block(x, self.activation, self.drop_connect_rate * b / blocks, name='block{}{}_'.format(i + 1, chr(j + 97)), **args) b += 1 if i in output_stages: block_outputs.append(x) # Build top x = tf.keras.layers.Conv2D(self.round_filters(1280), 1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name='top_conv')(x) x = build_normalization(**self.normalization, name='top_bn')(x) x = build_activation(**self.activation, name='top_activation')(x) if -1 in self.output_indices: x = tf.keras.layers.GlobalAveragePooling2D(name='avg_pool')(x) if self.dropout_rate > 0: x = tf.keras.layers.Dropout(self.dropout_rate, name='top_dropout')(x) x = tf.keras.layers.Dense( 1000, activation=self.classifier_activation, kernel_initializer=DENSE_KERNEL_INITIALIZER, name='predictions')(x) # Ensure that the model takes into account # any potential predecessors of `input_tensor`. if self.input_tensor is not None: inputs = tf.keras.utils.get_source_inputs(self.input_tensor) else: inputs = self.img_input # Create model. return tf.keras.Model(inputs=self.img_input, outputs=x, name=model_name) return [block_outputs[i - 1] for i in self.output_indices]
def EfficientNet(width_coefficient, depth_coefficient, default_size, dropout_rate=0.2, drop_connect_rate=0.2, depth_divisor=8, activation='swish', blocks_args='default', model_name='efficientnet', include_top=True, weights='imagenet', input_tensor=None, input_shape=None, pooling=None, classes=1000): """Instantiates the EfficientNet architecture using given scaling coefficients. Optionally loads weights pre-trained on ImageNet. Note that the data format convention used by the model is the one specified in your Keras config at `~/.keras/keras.json`. Arguments: width_coefficient: float, scaling coefficient for network width. depth_coefficient: float, scaling coefficient for network depth. default_size: integer, default input image size. dropout_rate: float, dropout rate before final classifier layer. drop_connect_rate: float, dropout rate at skip connections. depth_divisor: integer, a unit of network width. activation: activation function. blocks_args: list of dicts, parameters to construct block modules. model_name: string, model name. include_top: whether to include the fully-connected layer at the top of the network. weights: one of `None` (random initialization), 'imagenet' (pre-training on ImageNet), or the path to the weights file to be loaded. 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. It should have exactly 3 inputs channels. 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. """ if blocks_args == 'default': blocks_args = DEFAULT_BLOCKS_ARGS if not (weights in {'imagenet', None} or os.path.exists(weights)): raise ValueError('The `weights` argument should be either ' '`None` (random initialization), `imagenet` ' '(pre-training on ImageNet), ' 'or the path to the weights file to be loaded.') 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 = imagenet_utils.obtain_input_shape( input_shape, default_size=default_size, min_size=32, data_format=backend.image_data_format(), require_flatten=include_top, weights=weights) if input_tensor is None: img_input = layers.Input(shape=input_shape) else: if not backend.is_keras_tensor(input_tensor): img_input = layers.Input(tensor=input_tensor, shape=input_shape) else: img_input = input_tensor bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1 def round_filters(filters, divisor=depth_divisor): """Round number of filters based on depth multiplier.""" filters *= width_coefficient new_filters = max(divisor, int(filters + divisor / 2) // divisor * divisor) # Make sure that round down does not go down by more than 10%. if new_filters < 0.9 * filters: new_filters += divisor return int(new_filters) def round_repeats(repeats): """Round number of repeats based on depth multiplier.""" return int(math.ceil(depth_coefficient * repeats)) # Build stem x = img_input x = layers.Rescaling(1. / 255.)(x) x = layers.Normalization(axis=bn_axis)(x) x = layers.ZeroPadding2D( padding=imagenet_utils.correct_pad(x, 3), name='stem_conv_pad')(x) x = layers.Conv2D( round_filters(32), 3, strides=2, padding='valid', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name='stem_conv')(x) x = layers.BatchNormalization(axis=bn_axis, name='stem_bn')(x) x = layers.Activation(activation, name='stem_activation')(x) # Build blocks blocks_args = copy.deepcopy(blocks_args) b = 0 blocks = float(sum(args['repeats'] for args in blocks_args)) for (i, args) in enumerate(blocks_args): assert args['repeats'] > 0 # Update block input and output filters based on depth multiplier. args['filters_in'] = round_filters(args['filters_in']) args['filters_out'] = round_filters(args['filters_out']) for j in range(round_repeats(args.pop('repeats'))): # The first block needs to take care of stride and filter size increase. if j > 0: args['strides'] = 1 args['filters_in'] = args['filters_out'] x = block( x, activation, drop_connect_rate * b / blocks, name='block{}{}_'.format(i + 1, chr(j + 97)), **args) b += 1 # Build top x = layers.Conv2D( round_filters(1280), 1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER, name='top_conv')(x) x = layers.BatchNormalization(axis=bn_axis, name='top_bn')(x) x = layers.Activation(activation, name='top_activation')(x) if include_top: x = layers.GlobalAveragePooling2D(name='avg_pool')(x) if dropout_rate > 0: x = layers.Dropout(dropout_rate, name='top_dropout')(x) x = layers.Dense( classes, activation='softmax', kernel_initializer=DENSE_KERNEL_INITIALIZER, name='probs')(x) else: if pooling == 'avg': x = layers.GlobalAveragePooling2D(name='avg_pool')(x) elif pooling == 'max': x = layers.GlobalMaxPooling2D(name='max_pool')(x) # Ensure that the model takes into account # any potential predecessors of `input_tensor`. if input_tensor is not None: inputs = layer_utils.get_source_inputs(input_tensor) else: inputs = img_input # Create model. model = training.Model(inputs, x, name=model_name) # Load weights. if weights == 'imagenet': if include_top: file_suffix = '.h5' file_hash = WEIGHTS_HASHES[model_name[-2:]][0] else: file_suffix = '_notop.h5' file_hash = WEIGHTS_HASHES[model_name[-2:]][1] file_name = model_name + file_suffix weights_path = data_utils.get_file( file_name, BASE_WEIGHTS_PATH + file_name, cache_subdir='models', file_hash=file_hash) model.load_weights(weights_path) elif weights is not None: model.load_weights(weights) return model
def efficientnetB0(width_coeff=1, depth_coeff=1, default_img_size=224, dropoutrate=0.2, drop_connect_rate=0.2, depth_divisor=8, activations='swish', block_args='default', include_top=True, weights='imagenet', input_tensor=None, input_shape=None, pooling=None, classes=1000, classifier_activation='softmax'): if block_args == 'default': block_args = DEFAULT_BLOCKS_ARGS if not (weights in {'imagenet', None} or file_io.file_exists(weights)): raise ValueError('The `weights` argument should be either ' '`None` (random initialization), `imagenet` ' '(pre-training on ImageNet), ' 'or the path to the weights file to be loaded.') 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') # proper input shape check input_shape = imagenet_utils.obtain_input_shape( input_shape, default_size=default_img_size, min_size=32, data_format=backend.image_data_format(), require_flatten=include_top, weights=weights) if input_tensor is None: img_input = layers.Input(shape=input_shape) else: if not backend.is_keras_tensor(input_tensor): img_input = layers.Input(tensor=input_tensor, shape=input_shape) else: img_input = input_tensor bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1 def round_filters(filters, divisor=depth_divisor): """ round number of filters based on depth multiplier""" filters *= width_coeff new_filters = max(divisor, int(filters + divisor / 2) // divisor * divisor) #making sure round down does not go down by 10% if new_filters < 0.9 * filters: new_filters += divisor return int(new_filters) def round_repeats(repeats): """Round number of repeats based on depth multiplier.""" return int(math.ceil(depth_coeff * repeats)) #building stem x = img_input x = layers.Rescaling(1. / 255.)(x) x = layers.Normalization(axis=bn_axis)(x) x = layers.ZeroPadding2D(padding=imagenet_utils.correct_pad(x, 3))(x) x = layers.Conv2D(round_filters(32), kernel_size=3, strides=2, padding='valid', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(x) x = layers.BatchNormalization(axis=bn_axis)(x) x = layers.Activation(activations)(x) #building blocks block_args = copy.deepcopy(block_args) b = 0 blocks = float(sum(round_repeats(args['repeats']) for args in block_args)) for (i, args) in enumerate(block_args): assert args['repeats'] > 0 args['filters_in'] = round_filters(args['filters_in']) args['filters_out'] = round_filters(args['filters_out']) for j in range(round_repeats(args.pop('repeats'))): # The first block needs to take care of stride and filter size increase. if j > 0: args['strides'] = 1 args['filters_in'] = args['filters_out'] x = mbconvblock(inputs=x, activations=activations, droprate=drop_connect_rate * b / blocks, name=str(i), **args) b += 1 #build top x = layers.Conv2D(round_filters(1280), kernel_size=1, padding='same', use_bias=False, kernel_initializer=CONV_KERNEL_INITIALIZER)(x) x = layers.BatchNormalization(axis=bn_axis)(x) x = layers.Activation(activations)(x) if include_top: x = layers.GlobalAveragePooling2D()(x) if dropoutrate > 0: x = layers.Dropout(dropoutrate)(x) imagenet_utils.validate_activation(classifier_activation, weights) x = layers.Dense(classes, activation=classifier_activation, kernel_initializer=DENSE_KERNEL_INITIALIZER)(x) else: if pooling == 'avg': x = layers.GlobalAveragePooling2D()(x) elif pooling == 'max': x = layers.GlobalMaxPooling2D()(x) # Ensure that the model takes into account # any potential predecessors of `input_tensor`. if input_tensor is not None: inputs = layer_utils.get_source_inputs(input_tensor) else: inputs = img_input #creating model model = training.Model(inputs, x) return model