Fold Keras Applications into tf.keras, since it is no longer necessary to share
the implementation of Keras Applications across tf.keras and multi-backend Keras. PiperOrigin-RevId: 285302893 Change-Id: I06084c6827df651c68547c488e9fcad908d36796
This commit is contained in:
parent
5eb81ea161
commit
23c3bdaacd
@ -34,7 +34,6 @@ py_library(
|
||||
"//tensorflow/python/keras:backend",
|
||||
"//tensorflow/python/keras:engine",
|
||||
"//tensorflow/python/keras:layers_base",
|
||||
"@keras_applications_archive//:keras_applications",
|
||||
],
|
||||
)
|
||||
|
||||
@ -47,5 +46,17 @@ tf_py_test(
|
||||
"@absl_py//absl/testing:parameterized",
|
||||
"//tensorflow/python:client_testlib",
|
||||
],
|
||||
shard_count = 11,
|
||||
shard_count = 32,
|
||||
)
|
||||
|
||||
tf_py_test(
|
||||
name = "imagenet_utils_test",
|
||||
size = "medium",
|
||||
srcs = ["imagenet_utils_test.py"],
|
||||
additional_deps = [
|
||||
":applications",
|
||||
"@absl_py//absl/testing:parameterized",
|
||||
"//tensorflow/python:client_testlib",
|
||||
],
|
||||
shard_count = 2,
|
||||
)
|
||||
|
@ -13,35 +13,6 @@
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
"""Keras Applications are canned architectures with pre-trained weights."""
|
||||
# pylint: disable=g-import-not-at-top
|
||||
# pylint: disable=g-bad-import-order
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import keras_applications
|
||||
|
||||
|
||||
def keras_modules_injection(base_fun):
|
||||
"""Decorator injecting tf.keras replacements for Keras modules.
|
||||
|
||||
Arguments:
|
||||
base_fun: Application function to decorate (e.g. `MobileNet`).
|
||||
|
||||
Returns:
|
||||
Decorated function that injects keyword argument for the tf.keras
|
||||
modules required by the Applications.
|
||||
"""
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras import models
|
||||
from tensorflow.python.keras.utils import all_utils
|
||||
|
||||
def wrapper(*args, **kwargs):
|
||||
kwargs['backend'] = backend
|
||||
if 'layers' not in kwargs:
|
||||
kwargs['layers'] = layers
|
||||
kwargs['models'] = models
|
||||
kwargs['utils'] = all_utils
|
||||
return base_fun(*args, **kwargs)
|
||||
return wrapper
|
||||
|
@ -20,6 +20,7 @@ from __future__ import print_function
|
||||
|
||||
from absl.testing import parameterized
|
||||
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras.applications import densenet
|
||||
from tensorflow.python.keras.applications import inception_resnet_v2
|
||||
from tensorflow.python.keras.applications import inception_v3
|
||||
@ -34,7 +35,7 @@ from tensorflow.python.keras.applications import xception
|
||||
from tensorflow.python.platform import test
|
||||
|
||||
|
||||
MODEL_LIST = [
|
||||
MODEL_LIST_NO_NASNET = [
|
||||
(resnet.ResNet50, 2048),
|
||||
(resnet.ResNet101, 2048),
|
||||
(resnet.ResNet152, 2048),
|
||||
@ -51,17 +52,70 @@ MODEL_LIST = [
|
||||
(densenet.DenseNet121, 1024),
|
||||
(densenet.DenseNet169, 1664),
|
||||
(densenet.DenseNet201, 1920),
|
||||
(nasnet.NASNetMobile, 1056),
|
||||
]
|
||||
|
||||
NASNET_LIST = [
|
||||
(nasnet.NASNetMobile, 1056),
|
||||
(nasnet.NASNetLarge, 4032),
|
||||
]
|
||||
|
||||
MODEL_LIST = MODEL_LIST_NO_NASNET + NASNET_LIST
|
||||
|
||||
|
||||
class ApplicationsTest(test.TestCase, parameterized.TestCase):
|
||||
|
||||
def assertShapeEqual(self, shape1, shape2):
|
||||
if len(shape1) != len(shape2):
|
||||
raise AssertionError(
|
||||
'Shapes are different rank: %s vs %s' % (shape1, shape2))
|
||||
for v1, v2 in zip(shape1, shape2):
|
||||
if v1 != v2:
|
||||
raise AssertionError('Shapes differ: %s vs %s' % (shape1, shape2))
|
||||
|
||||
@parameterized.parameters(*MODEL_LIST)
|
||||
def test_feature_extration_model(self, model_fn, output_dim):
|
||||
model = model_fn(include_top=False, weights=None)
|
||||
self.assertLen(model.output_shape, 4)
|
||||
self.assertEqual(model.output_shape[-1], output_dim)
|
||||
def test_application_notop(self, app, last_dim):
|
||||
if 'NASNet' in app.__name__:
|
||||
only_check_last_dim = True
|
||||
else:
|
||||
only_check_last_dim = False
|
||||
output_shape = _get_output_shape(
|
||||
lambda: app(weights=None, include_top=False))
|
||||
if only_check_last_dim:
|
||||
self.assertEqual(output_shape[-1], last_dim)
|
||||
else:
|
||||
self.assertShapeEqual(output_shape, (None, None, None, last_dim))
|
||||
backend.clear_session()
|
||||
|
||||
@parameterized.parameters(MODEL_LIST)
|
||||
def test_application_pooling(self, app, last_dim):
|
||||
output_shape = _get_output_shape(
|
||||
lambda: app(weights=None, include_top=False, pooling='avg'))
|
||||
self.assertShapeEqual(output_shape, (None, last_dim))
|
||||
|
||||
@parameterized.parameters(*MODEL_LIST_NO_NASNET)
|
||||
def test_application_variable_input_channels(self, app, last_dim):
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
input_shape = (1, None, None)
|
||||
else:
|
||||
input_shape = (None, None, 1)
|
||||
output_shape = _get_output_shape(
|
||||
lambda: app(weights=None, include_top=False, input_shape=input_shape))
|
||||
self.assertShapeEqual(output_shape, (None, None, None, last_dim))
|
||||
backend.clear_session()
|
||||
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
input_shape = (4, None, None)
|
||||
else:
|
||||
input_shape = (None, None, 4)
|
||||
output_shape = _get_output_shape(
|
||||
lambda: app(weights=None, include_top=False, input_shape=input_shape))
|
||||
self.assertShapeEqual(output_shape, (None, None, None, last_dim))
|
||||
backend.clear_session()
|
||||
|
||||
|
||||
def _get_output_shape(model_fn):
|
||||
model = model_fn()
|
||||
return model.output_shape
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
@ -14,45 +14,381 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""DenseNet models for Keras.
|
||||
|
||||
Reference paper:
|
||||
- [Densely Connected Convolutional Networks]
|
||||
(https://arxiv.org/abs/1608.06993) (CVPR 2017 Best Paper Award)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import densenet
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
BASE_WEIGTHS_PATH = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/densenet/')
|
||||
DENSENET121_WEIGHT_PATH = (
|
||||
BASE_WEIGTHS_PATH + 'densenet121_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
DENSENET121_WEIGHT_PATH_NO_TOP = (
|
||||
BASE_WEIGTHS_PATH +
|
||||
'densenet121_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
DENSENET169_WEIGHT_PATH = (
|
||||
BASE_WEIGTHS_PATH + 'densenet169_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
DENSENET169_WEIGHT_PATH_NO_TOP = (
|
||||
BASE_WEIGTHS_PATH +
|
||||
'densenet169_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
DENSENET201_WEIGHT_PATH = (
|
||||
BASE_WEIGTHS_PATH + 'densenet201_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
DENSENET201_WEIGHT_PATH_NO_TOP = (
|
||||
BASE_WEIGTHS_PATH +
|
||||
'densenet201_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
|
||||
|
||||
def dense_block(x, blocks, name):
|
||||
"""A dense block.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
blocks: integer, the number of building blocks.
|
||||
name: string, block label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the block.
|
||||
"""
|
||||
for i in range(blocks):
|
||||
x = conv_block(x, 32, name=name + '_block' + str(i + 1))
|
||||
return x
|
||||
|
||||
|
||||
def transition_block(x, reduction, name):
|
||||
"""A transition block.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
reduction: float, compression rate at transition layers.
|
||||
name: string, block label.
|
||||
|
||||
Returns:
|
||||
output tensor for the block.
|
||||
"""
|
||||
bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_relu')(x)
|
||||
x = layers.Conv2D(
|
||||
int(backend.int_shape(x)[bn_axis] * reduction),
|
||||
1,
|
||||
use_bias=False,
|
||||
name=name + '_conv')(
|
||||
x)
|
||||
x = layers.AveragePooling2D(2, strides=2, name=name + '_pool')(x)
|
||||
return x
|
||||
|
||||
|
||||
def conv_block(x, growth_rate, name):
|
||||
"""A building block for a dense block.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
growth_rate: float, growth rate at dense layers.
|
||||
name: string, block label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the block.
|
||||
"""
|
||||
bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
|
||||
x1 = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(
|
||||
x)
|
||||
x1 = layers.Activation('relu', name=name + '_0_relu')(x1)
|
||||
x1 = layers.Conv2D(
|
||||
4 * growth_rate, 1, use_bias=False, name=name + '_1_conv')(
|
||||
x1)
|
||||
x1 = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(
|
||||
x1)
|
||||
x1 = layers.Activation('relu', name=name + '_1_relu')(x1)
|
||||
x1 = layers.Conv2D(
|
||||
growth_rate, 3, padding='same', use_bias=False, name=name + '_2_conv')(
|
||||
x1)
|
||||
x = layers.Concatenate(axis=bn_axis, name=name + '_concat')([x, x1])
|
||||
return x
|
||||
|
||||
|
||||
def DenseNet(blocks,
|
||||
include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the DenseNet architecture.
|
||||
|
||||
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:
|
||||
blocks: numbers of building blocks for the four dense layers.
|
||||
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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)` (with `'channels_last'` data format)
|
||||
or `(3, 224, 224)` (with `'channels_first'` data format).
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(200, 200, 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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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 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=224,
|
||||
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
|
||||
|
||||
x = layers.ZeroPadding2D(padding=((3, 3), (3, 3)))(img_input)
|
||||
x = layers.Conv2D(64, 7, strides=2, use_bias=False, name='conv1/conv')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name='conv1/bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name='conv1/relu')(x)
|
||||
x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)))(x)
|
||||
x = layers.MaxPooling2D(3, strides=2, name='pool1')(x)
|
||||
|
||||
x = dense_block(x, blocks[0], name='conv2')
|
||||
x = transition_block(x, 0.5, name='pool2')
|
||||
x = dense_block(x, blocks[1], name='conv3')
|
||||
x = transition_block(x, 0.5, name='pool3')
|
||||
x = dense_block(x, blocks[2], name='conv4')
|
||||
x = transition_block(x, 0.5, name='pool4')
|
||||
x = dense_block(x, blocks[3], name='conv5')
|
||||
|
||||
x = layers.BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='bn')(x)
|
||||
x = layers.Activation('relu', name='relu')(x)
|
||||
|
||||
if include_top:
|
||||
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='fc1000')(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.
|
||||
if blocks == [6, 12, 24, 16]:
|
||||
model = training.Model(inputs, x, name='densenet121')
|
||||
elif blocks == [6, 12, 32, 32]:
|
||||
model = training.Model(inputs, x, name='densenet169')
|
||||
elif blocks == [6, 12, 48, 32]:
|
||||
model = training.Model(inputs, x, name='densenet201')
|
||||
else:
|
||||
model = training.Model(inputs, x, name='densenet')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
if blocks == [6, 12, 24, 16]:
|
||||
weights_path = data_utils.get_file(
|
||||
'densenet121_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
DENSENET121_WEIGHT_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='9d60b8095a5708f2dcce2bca79d332c7')
|
||||
elif blocks == [6, 12, 32, 32]:
|
||||
weights_path = data_utils.get_file(
|
||||
'densenet169_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
DENSENET169_WEIGHT_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='d699b8f76981ab1b30698df4c175e90b')
|
||||
elif blocks == [6, 12, 48, 32]:
|
||||
weights_path = data_utils.get_file(
|
||||
'densenet201_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
DENSENET201_WEIGHT_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='1ceb130c1ea1b78c3bf6114dbdfd8807')
|
||||
else:
|
||||
if blocks == [6, 12, 24, 16]:
|
||||
weights_path = data_utils.get_file(
|
||||
'densenet121_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
DENSENET121_WEIGHT_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='30ee3e1110167f948a6b9946edeeb738')
|
||||
elif blocks == [6, 12, 32, 32]:
|
||||
weights_path = data_utils.get_file(
|
||||
'densenet169_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
DENSENET169_WEIGHT_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='b8c4d4c20dd625c148057b9ff1c1176b')
|
||||
elif blocks == [6, 12, 48, 32]:
|
||||
weights_path = data_utils.get_file(
|
||||
'densenet201_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
DENSENET201_WEIGHT_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='c13680b51ded0fb44dff2d8f86ac8bb1')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.densenet.DenseNet121',
|
||||
'keras.applications.DenseNet121')
|
||||
@keras_modules_injection
|
||||
def DenseNet121(*args, **kwargs):
|
||||
return densenet.DenseNet121(*args, **kwargs)
|
||||
def DenseNet121(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the Densenet121 architecture."""
|
||||
return DenseNet([6, 12, 24, 16], include_top, weights, input_tensor,
|
||||
input_shape, pooling, classes)
|
||||
|
||||
|
||||
@keras_export('keras.applications.densenet.DenseNet169',
|
||||
'keras.applications.DenseNet169')
|
||||
@keras_modules_injection
|
||||
def DenseNet169(*args, **kwargs):
|
||||
return densenet.DenseNet169(*args, **kwargs)
|
||||
def DenseNet169(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the Densenet169 architecture."""
|
||||
return DenseNet([6, 12, 32, 32], include_top, weights, input_tensor,
|
||||
input_shape, pooling, classes)
|
||||
|
||||
|
||||
@keras_export('keras.applications.densenet.DenseNet201',
|
||||
'keras.applications.DenseNet201')
|
||||
@keras_modules_injection
|
||||
def DenseNet201(*args, **kwargs):
|
||||
return densenet.DenseNet201(*args, **kwargs)
|
||||
|
||||
|
||||
@keras_export('keras.applications.densenet.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return densenet.decode_predictions(*args, **kwargs)
|
||||
def DenseNet201(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the Densenet201 architecture."""
|
||||
return DenseNet([6, 12, 48, 32], include_top, weights, input_tensor,
|
||||
input_shape, pooling, classes)
|
||||
|
||||
|
||||
@keras_export('keras.applications.densenet.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return densenet.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(
|
||||
x, data_format=data_format, mode='torch')
|
||||
|
||||
|
||||
@keras_export('keras.applications.densenet.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
||||
|
||||
DOC = """
|
||||
|
||||
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:
|
||||
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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)` (with `'channels_last'` data format)
|
||||
or `(3, 224, 224)` (with `'channels_first'` data format).
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(200, 200, 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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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.
|
||||
"""
|
||||
|
||||
setattr(DenseNet121, '__doc__', DenseNet121.__doc__ + DOC)
|
||||
setattr(DenseNet169, '__doc__', DenseNet169.__doc__ + DOC)
|
||||
setattr(DenseNet201, '__doc__', DenseNet201.__doc__ + DOC)
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
|
||||
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@ -12,25 +12,346 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
"""Utilities for ImageNet data preprocessing & prediction decoding.
|
||||
"""
|
||||
"""Utilities for ImageNet data preprocessing & prediction decoding."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import imagenet_utils
|
||||
import json
|
||||
import warnings
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
import numpy as np
|
||||
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
@keras_export('keras.applications.imagenet_utils.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return imagenet_utils.decode_predictions(*args, **kwargs)
|
||||
CLASS_INDEX = None
|
||||
CLASS_INDEX_PATH = ('https://storage.googleapis.com/download.tensorflow.org/'
|
||||
'data/imagenet_class_index.json')
|
||||
|
||||
|
||||
@keras_export('keras.applications.imagenet_utils.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return imagenet_utils.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None, mode='caffe'):
|
||||
"""Preprocesses a tensor or Numpy array encoding a batch of images.
|
||||
|
||||
Arguments:
|
||||
x: Input Numpy or symbolic tensor, 3D or 4D.
|
||||
The preprocessed data is written over the input data
|
||||
if the data types are compatible. To avoid this
|
||||
behaviour, `numpy.copy(x)` can be used.
|
||||
data_format: Data format of the image tensor/array.
|
||||
mode: One of "caffe", "tf" or "torch".
|
||||
- caffe: will convert the images from RGB to BGR,
|
||||
then will zero-center each color channel with
|
||||
respect to the ImageNet dataset,
|
||||
without scaling.
|
||||
- tf: will scale pixels between -1 and 1,
|
||||
sample-wise.
|
||||
- torch: will scale pixels between 0 and 1 and then
|
||||
will normalize each channel with respect to the
|
||||
ImageNet dataset.
|
||||
|
||||
Returns:
|
||||
Preprocessed tensor or Numpy array.
|
||||
|
||||
Raises:
|
||||
ValueError: In case of unknown `data_format` argument.
|
||||
"""
|
||||
if data_format is None:
|
||||
data_format = backend.image_data_format()
|
||||
if data_format not in {'channels_first', 'channels_last'}:
|
||||
raise ValueError('Unknown data_format ' + str(data_format))
|
||||
|
||||
if isinstance(x, np.ndarray):
|
||||
return _preprocess_numpy_input(
|
||||
x, data_format=data_format, mode=mode)
|
||||
else:
|
||||
return _preprocess_symbolic_input(
|
||||
x, data_format=data_format, mode=mode)
|
||||
|
||||
|
||||
@keras_export('keras.applications.imagenet_utils.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
"""Decodes the prediction of an ImageNet model.
|
||||
|
||||
Arguments:
|
||||
preds: Numpy tensor encoding a batch of predictions.
|
||||
top: Integer, how many top-guesses to return.
|
||||
|
||||
Returns:
|
||||
A list of lists of top class prediction tuples
|
||||
`(class_name, class_description, score)`.
|
||||
One list of tuples per sample in batch input.
|
||||
|
||||
Raises:
|
||||
ValueError: In case of invalid shape of the `pred` array
|
||||
(must be 2D).
|
||||
"""
|
||||
global CLASS_INDEX
|
||||
|
||||
if len(preds.shape) != 2 or preds.shape[1] != 1000:
|
||||
raise ValueError('`decode_predictions` expects '
|
||||
'a batch of predictions '
|
||||
'(i.e. a 2D array of shape (samples, 1000)). '
|
||||
'Found array with shape: ' + str(preds.shape))
|
||||
if CLASS_INDEX is None:
|
||||
fpath = data_utils.get_file(
|
||||
'imagenet_class_index.json',
|
||||
CLASS_INDEX_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='c2c37ea517e94d9795004a39431a14cb')
|
||||
with open(fpath) as f:
|
||||
CLASS_INDEX = json.load(f)
|
||||
results = []
|
||||
for pred in preds:
|
||||
top_indices = pred.argsort()[-top:][::-1]
|
||||
result = [tuple(CLASS_INDEX[str(i)]) + (pred[i],) for i in top_indices]
|
||||
result.sort(key=lambda x: x[2], reverse=True)
|
||||
results.append(result)
|
||||
return results
|
||||
|
||||
|
||||
def _preprocess_numpy_input(x, data_format, mode):
|
||||
"""Preprocesses a Numpy array encoding a batch of images.
|
||||
|
||||
Arguments:
|
||||
x: Input array, 3D or 4D.
|
||||
data_format: Data format of the image array.
|
||||
mode: One of "caffe", "tf" or "torch".
|
||||
- caffe: will convert the images from RGB to BGR,
|
||||
then will zero-center each color channel with
|
||||
respect to the ImageNet dataset,
|
||||
without scaling.
|
||||
- tf: will scale pixels between -1 and 1,
|
||||
sample-wise.
|
||||
- torch: will scale pixels between 0 and 1 and then
|
||||
will normalize each channel with respect to the
|
||||
ImageNet dataset.
|
||||
|
||||
Returns:
|
||||
Preprocessed Numpy array.
|
||||
"""
|
||||
if not issubclass(x.dtype.type, np.floating):
|
||||
x = x.astype(backend.floatx(), copy=False)
|
||||
|
||||
if mode == 'tf':
|
||||
x /= 127.5
|
||||
x -= 1.
|
||||
return x
|
||||
|
||||
if mode == 'torch':
|
||||
x /= 255.
|
||||
mean = [0.485, 0.456, 0.406]
|
||||
std = [0.229, 0.224, 0.225]
|
||||
else:
|
||||
if data_format == 'channels_first':
|
||||
# 'RGB'->'BGR'
|
||||
if x.ndim == 3:
|
||||
x = x[::-1, ...]
|
||||
else:
|
||||
x = x[:, ::-1, ...]
|
||||
else:
|
||||
# 'RGB'->'BGR'
|
||||
x = x[..., ::-1]
|
||||
mean = [103.939, 116.779, 123.68]
|
||||
std = None
|
||||
|
||||
# Zero-center by mean pixel
|
||||
if data_format == 'channels_first':
|
||||
if x.ndim == 3:
|
||||
x[0, :, :] -= mean[0]
|
||||
x[1, :, :] -= mean[1]
|
||||
x[2, :, :] -= mean[2]
|
||||
if std is not None:
|
||||
x[0, :, :] /= std[0]
|
||||
x[1, :, :] /= std[1]
|
||||
x[2, :, :] /= std[2]
|
||||
else:
|
||||
x[:, 0, :, :] -= mean[0]
|
||||
x[:, 1, :, :] -= mean[1]
|
||||
x[:, 2, :, :] -= mean[2]
|
||||
if std is not None:
|
||||
x[:, 0, :, :] /= std[0]
|
||||
x[:, 1, :, :] /= std[1]
|
||||
x[:, 2, :, :] /= std[2]
|
||||
else:
|
||||
x[..., 0] -= mean[0]
|
||||
x[..., 1] -= mean[1]
|
||||
x[..., 2] -= mean[2]
|
||||
if std is not None:
|
||||
x[..., 0] /= std[0]
|
||||
x[..., 1] /= std[1]
|
||||
x[..., 2] /= std[2]
|
||||
return x
|
||||
|
||||
|
||||
def _preprocess_symbolic_input(x, data_format, mode):
|
||||
"""Preprocesses a tensor encoding a batch of images.
|
||||
|
||||
Arguments:
|
||||
x: Input tensor, 3D or 4D.
|
||||
data_format: Data format of the image tensor.
|
||||
mode: One of "caffe", "tf" or "torch".
|
||||
- caffe: will convert the images from RGB to BGR,
|
||||
then will zero-center each color channel with
|
||||
respect to the ImageNet dataset,
|
||||
without scaling.
|
||||
- tf: will scale pixels between -1 and 1,
|
||||
sample-wise.
|
||||
- torch: will scale pixels between 0 and 1 and then
|
||||
will normalize each channel with respect to the
|
||||
ImageNet dataset.
|
||||
|
||||
Returns:
|
||||
Preprocessed tensor.
|
||||
"""
|
||||
if mode == 'tf':
|
||||
x /= 127.5
|
||||
x -= 1.
|
||||
return x
|
||||
|
||||
if mode == 'torch':
|
||||
x /= 255.
|
||||
mean = [0.485, 0.456, 0.406]
|
||||
std = [0.229, 0.224, 0.225]
|
||||
else:
|
||||
if data_format == 'channels_first':
|
||||
# 'RGB'->'BGR'
|
||||
if backend.ndim(x) == 3:
|
||||
x = x[::-1, ...]
|
||||
else:
|
||||
x = x[:, ::-1, ...]
|
||||
else:
|
||||
# 'RGB'->'BGR'
|
||||
x = x[..., ::-1]
|
||||
mean = [103.939, 116.779, 123.68]
|
||||
std = None
|
||||
|
||||
mean_tensor = backend.constant(-np.array(mean))
|
||||
|
||||
# Zero-center by mean pixel
|
||||
if backend.dtype(x) != backend.dtype(mean_tensor):
|
||||
x = backend.bias_add(
|
||||
x, backend.cast(mean_tensor, backend.dtype(x)), data_format=data_format)
|
||||
else:
|
||||
x = backend.bias_add(x, mean_tensor, data_format)
|
||||
if std is not None:
|
||||
x /= std
|
||||
return x
|
||||
|
||||
|
||||
def obtain_input_shape(input_shape,
|
||||
default_size,
|
||||
min_size,
|
||||
data_format,
|
||||
require_flatten,
|
||||
weights=None):
|
||||
"""Internal utility to compute/validate a model's input shape.
|
||||
|
||||
Arguments:
|
||||
input_shape: Either None (will return the default network input shape),
|
||||
or a user-provided shape to be validated.
|
||||
default_size: Default input width/height for the model.
|
||||
min_size: Minimum input width/height accepted by the model.
|
||||
data_format: Image data format to use.
|
||||
require_flatten: Whether the model is expected to
|
||||
be linked to a classifier via a Flatten layer.
|
||||
weights: One of `None` (random initialization)
|
||||
or 'imagenet' (pre-training on ImageNet).
|
||||
If weights='imagenet' input channels must be equal to 3.
|
||||
|
||||
Returns:
|
||||
An integer shape tuple (may include None entries).
|
||||
|
||||
Raises:
|
||||
ValueError: In case of invalid argument values.
|
||||
"""
|
||||
if weights != 'imagenet' and input_shape and len(input_shape) == 3:
|
||||
if data_format == 'channels_first':
|
||||
if input_shape[0] not in {1, 3}:
|
||||
warnings.warn('This model usually expects 1 or 3 input channels. '
|
||||
'However, it was passed an input_shape with ' +
|
||||
str(input_shape[0]) + ' input channels.')
|
||||
default_shape = (input_shape[0], default_size, default_size)
|
||||
else:
|
||||
if input_shape[-1] not in {1, 3}:
|
||||
warnings.warn('This model usually expects 1 or 3 input channels. '
|
||||
'However, it was passed an input_shape with ' +
|
||||
str(input_shape[-1]) + ' input channels.')
|
||||
default_shape = (default_size, default_size, input_shape[-1])
|
||||
else:
|
||||
if data_format == 'channels_first':
|
||||
default_shape = (3, default_size, default_size)
|
||||
else:
|
||||
default_shape = (default_size, default_size, 3)
|
||||
if weights == 'imagenet' and require_flatten:
|
||||
if input_shape is not None:
|
||||
if input_shape != default_shape:
|
||||
raise ValueError('When setting `include_top=True` '
|
||||
'and loading `imagenet` weights, '
|
||||
'`input_shape` should be ' + str(default_shape) + '.')
|
||||
return default_shape
|
||||
if input_shape:
|
||||
if data_format == 'channels_first':
|
||||
if input_shape is not None:
|
||||
if len(input_shape) != 3:
|
||||
raise ValueError('`input_shape` must be a tuple of three integers.')
|
||||
if input_shape[0] != 3 and weights == 'imagenet':
|
||||
raise ValueError('The input must have 3 channels; got '
|
||||
'`input_shape=' + str(input_shape) + '`')
|
||||
if ((input_shape[1] is not None and input_shape[1] < min_size) or
|
||||
(input_shape[2] is not None and input_shape[2] < min_size)):
|
||||
raise ValueError('Input size must be at least ' + str(min_size) +
|
||||
'x' + str(min_size) + '; got `input_shape=' +
|
||||
str(input_shape) + '`')
|
||||
else:
|
||||
if input_shape is not None:
|
||||
if len(input_shape) != 3:
|
||||
raise ValueError('`input_shape` must be a tuple of three integers.')
|
||||
if input_shape[-1] != 3 and weights == 'imagenet':
|
||||
raise ValueError('The input must have 3 channels; got '
|
||||
'`input_shape=' + str(input_shape) + '`')
|
||||
if ((input_shape[0] is not None and input_shape[0] < min_size) or
|
||||
(input_shape[1] is not None and input_shape[1] < min_size)):
|
||||
raise ValueError('Input size must be at least ' + str(min_size) +
|
||||
'x' + str(min_size) + '; got `input_shape=' +
|
||||
str(input_shape) + '`')
|
||||
else:
|
||||
if require_flatten:
|
||||
input_shape = default_shape
|
||||
else:
|
||||
if data_format == 'channels_first':
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
if require_flatten:
|
||||
if None in input_shape:
|
||||
raise ValueError('If `include_top` is True, '
|
||||
'you should specify a static `input_shape`. '
|
||||
'Got `input_shape=' + str(input_shape) + '`')
|
||||
return input_shape
|
||||
|
||||
|
||||
def correct_pad(inputs, kernel_size):
|
||||
"""Returns a tuple for zero-padding for 2D convolution with downsampling.
|
||||
|
||||
Arguments:
|
||||
inputs: Input tensor.
|
||||
kernel_size: An integer or tuple/list of 2 integers.
|
||||
|
||||
Returns:
|
||||
A tuple.
|
||||
"""
|
||||
img_dim = 2 if backend.image_data_format() == 'channels_first' else 1
|
||||
input_size = backend.int_shape(inputs)[img_dim:(img_dim + 2)]
|
||||
if isinstance(kernel_size, int):
|
||||
kernel_size = (kernel_size, kernel_size)
|
||||
if input_size[0] is None:
|
||||
adjust = (1, 1)
|
||||
else:
|
||||
adjust = (1 - input_size[0] % 2, 1 - input_size[1] % 2)
|
||||
correct = (kernel_size[0] // 2, kernel_size[1] // 2)
|
||||
return ((correct[0] - adjust[0], correct[0]),
|
||||
(correct[1] - adjust[1], correct[1]))
|
||||
|
250
tensorflow/python/keras/applications/imagenet_utils_test.py
Normal file
250
tensorflow/python/keras/applications/imagenet_utils_test.py
Normal file
@ -0,0 +1,250 @@
|
||||
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
"""Tests for imagenet_utils."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from absl.testing import parameterized
|
||||
import numpy as np
|
||||
|
||||
from tensorflow.python import keras
|
||||
from tensorflow.python.keras import keras_parameterized
|
||||
from tensorflow.python.keras.applications import imagenet_utils as utils
|
||||
from tensorflow.python.platform import test
|
||||
|
||||
|
||||
class TestImageNetUtils(keras_parameterized.TestCase):
|
||||
|
||||
def test_preprocess_input(self):
|
||||
# Test image batch with float and int image input
|
||||
x = np.random.uniform(0, 255, (2, 10, 10, 3))
|
||||
xint = x.astype('int32')
|
||||
self.assertEqual(utils.preprocess_input(x).shape, x.shape)
|
||||
self.assertEqual(utils.preprocess_input(xint).shape, xint.shape)
|
||||
|
||||
out1 = utils.preprocess_input(x, 'channels_last')
|
||||
out1int = utils.preprocess_input(xint, 'channels_last')
|
||||
out2 = utils.preprocess_input(
|
||||
np.transpose(x, (0, 3, 1, 2)), 'channels_first')
|
||||
out2int = utils.preprocess_input(
|
||||
np.transpose(xint, (0, 3, 1, 2)), 'channels_first')
|
||||
self.assertAllClose(out1, out2.transpose(0, 2, 3, 1))
|
||||
self.assertAllClose(out1int, out2int.transpose(0, 2, 3, 1))
|
||||
|
||||
# Test single image
|
||||
x = np.random.uniform(0, 255, (10, 10, 3))
|
||||
xint = x.astype('int32')
|
||||
self.assertEqual(utils.preprocess_input(x).shape, x.shape)
|
||||
self.assertEqual(utils.preprocess_input(xint).shape, xint.shape)
|
||||
|
||||
out1 = utils.preprocess_input(x, 'channels_last')
|
||||
out1int = utils.preprocess_input(xint, 'channels_last')
|
||||
out2 = utils.preprocess_input(np.transpose(x, (2, 0, 1)), 'channels_first')
|
||||
out2int = utils.preprocess_input(
|
||||
np.transpose(xint, (2, 0, 1)), 'channels_first')
|
||||
self.assertAllClose(out1, out2.transpose(1, 2, 0))
|
||||
self.assertAllClose(out1int, out2int.transpose(1, 2, 0))
|
||||
|
||||
# Test that writing over the input data works predictably
|
||||
for mode in ['torch', 'tf']:
|
||||
x = np.random.uniform(0, 255, (2, 10, 10, 3))
|
||||
xint = x.astype('int')
|
||||
x2 = utils.preprocess_input(x, mode=mode)
|
||||
xint2 = utils.preprocess_input(xint)
|
||||
self.assertAllClose(x, x2)
|
||||
self.assertNotEqual(xint.astype('float').max(), xint2.max())
|
||||
|
||||
# Caffe mode works differently from the others
|
||||
x = np.random.uniform(0, 255, (2, 10, 10, 3))
|
||||
xint = x.astype('int')
|
||||
x2 = utils.preprocess_input(x, data_format='channels_last', mode='caffe')
|
||||
xint2 = utils.preprocess_input(xint)
|
||||
self.assertAllClose(x, x2[..., ::-1])
|
||||
self.assertNotEqual(xint.astype('float').max(), xint2.max())
|
||||
|
||||
def test_preprocess_input_symbolic(self):
|
||||
# Test image batch
|
||||
x = np.random.uniform(0, 255, (2, 10, 10, 3))
|
||||
inputs = keras.layers.Input(shape=x.shape[1:])
|
||||
outputs = keras.layers.Lambda(
|
||||
utils.preprocess_input, output_shape=x.shape[1:])(
|
||||
inputs)
|
||||
model = keras.Model(inputs, outputs)
|
||||
self.assertEqual(model.predict(x).shape, x.shape)
|
||||
|
||||
outputs1 = keras.layers.Lambda(
|
||||
lambda x: utils.preprocess_input(x, 'channels_last'),
|
||||
output_shape=x.shape[1:])(
|
||||
inputs)
|
||||
model1 = keras.Model(inputs, outputs1)
|
||||
out1 = model1.predict(x)
|
||||
x2 = np.transpose(x, (0, 3, 1, 2))
|
||||
inputs2 = keras.layers.Input(shape=x2.shape[1:])
|
||||
outputs2 = keras.layers.Lambda(
|
||||
lambda x: utils.preprocess_input(x, 'channels_first'),
|
||||
output_shape=x2.shape[1:])(
|
||||
inputs2)
|
||||
model2 = keras.Model(inputs2, outputs2)
|
||||
out2 = model2.predict(x2)
|
||||
self.assertAllClose(out1, out2.transpose(0, 2, 3, 1))
|
||||
|
||||
# Test single image
|
||||
x = np.random.uniform(0, 255, (10, 10, 3))
|
||||
inputs = keras.layers.Input(shape=x.shape)
|
||||
outputs = keras.layers.Lambda(
|
||||
utils.preprocess_input, output_shape=x.shape)(
|
||||
inputs)
|
||||
model = keras.Model(inputs, outputs)
|
||||
self.assertEqual(model.predict(x[np.newaxis])[0].shape, x.shape)
|
||||
|
||||
outputs1 = keras.layers.Lambda(
|
||||
lambda x: utils.preprocess_input(x, 'channels_last'),
|
||||
output_shape=x.shape)(
|
||||
inputs)
|
||||
model1 = keras.Model(inputs, outputs1)
|
||||
out1 = model1.predict(x[np.newaxis])[0]
|
||||
x2 = np.transpose(x, (2, 0, 1))
|
||||
inputs2 = keras.layers.Input(shape=x2.shape)
|
||||
outputs2 = keras.layers.Lambda(
|
||||
lambda x: utils.preprocess_input(x, 'channels_first'),
|
||||
output_shape=x2.shape)(
|
||||
inputs2)
|
||||
model2 = keras.Model(inputs2, outputs2)
|
||||
out2 = model2.predict(x2[np.newaxis])[0]
|
||||
self.assertAllClose(out1, out2.transpose(1, 2, 0))
|
||||
|
||||
@parameterized.named_parameters([
|
||||
{'testcase_name': 'channels_last_format',
|
||||
'data_format': 'channels_last'},
|
||||
{'testcase_name': 'channels_first_format',
|
||||
'data_format': 'channels_first'},
|
||||
])
|
||||
def test_obtain_input_shape(self, data_format):
|
||||
# input_shape and default_size are not identical.
|
||||
with self.assertRaises(ValueError):
|
||||
utils.obtain_input_shape(
|
||||
input_shape=(224, 224, 3),
|
||||
default_size=299,
|
||||
min_size=139,
|
||||
data_format='channels_last',
|
||||
require_flatten=True,
|
||||
weights='imagenet')
|
||||
|
||||
# Test invalid use cases
|
||||
|
||||
shape = (139, 139)
|
||||
if data_format == 'channels_last':
|
||||
input_shape = shape + (99,)
|
||||
else:
|
||||
input_shape = (99,) + shape
|
||||
|
||||
# input_shape is smaller than min_size.
|
||||
shape = (100, 100)
|
||||
if data_format == 'channels_last':
|
||||
input_shape = shape + (3,)
|
||||
else:
|
||||
input_shape = (3,) + shape
|
||||
with self.assertRaises(ValueError):
|
||||
utils.obtain_input_shape(
|
||||
input_shape=input_shape,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format=data_format,
|
||||
require_flatten=False)
|
||||
|
||||
# shape is 1D.
|
||||
shape = (100,)
|
||||
if data_format == 'channels_last':
|
||||
input_shape = shape + (3,)
|
||||
else:
|
||||
input_shape = (3,) + shape
|
||||
with self.assertRaises(ValueError):
|
||||
utils.obtain_input_shape(
|
||||
input_shape=input_shape,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format=data_format,
|
||||
require_flatten=False)
|
||||
|
||||
# the number of channels is 5 not 3.
|
||||
shape = (100, 100)
|
||||
if data_format == 'channels_last':
|
||||
input_shape = shape + (5,)
|
||||
else:
|
||||
input_shape = (5,) + shape
|
||||
with self.assertRaises(ValueError):
|
||||
utils.obtain_input_shape(
|
||||
input_shape=input_shape,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format=data_format,
|
||||
require_flatten=False)
|
||||
|
||||
# require_flatten=True with dynamic input shape.
|
||||
with self.assertRaises(ValueError):
|
||||
utils.obtain_input_shape(
|
||||
input_shape=None,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_first',
|
||||
require_flatten=True)
|
||||
|
||||
# test include top
|
||||
self.assertEqual(utils.obtain_input_shape(
|
||||
input_shape=(3, 200, 200),
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_first',
|
||||
require_flatten=True), (3, 200, 200))
|
||||
|
||||
self.assertEqual(utils.obtain_input_shape(
|
||||
input_shape=None,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_last',
|
||||
require_flatten=False), (None, None, 3))
|
||||
|
||||
self.assertEqual(utils.obtain_input_shape(
|
||||
input_shape=None,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_first',
|
||||
require_flatten=False), (3, None, None))
|
||||
|
||||
self.assertEqual(utils.obtain_input_shape(
|
||||
input_shape=None,
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_last',
|
||||
require_flatten=False), (None, None, 3))
|
||||
|
||||
self.assertEqual(utils.obtain_input_shape(
|
||||
input_shape=(150, 150, 3),
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_last',
|
||||
require_flatten=False), (150, 150, 3))
|
||||
|
||||
self.assertEqual(utils.obtain_input_shape(
|
||||
input_shape=(3, None, None),
|
||||
default_size=None,
|
||||
min_size=139,
|
||||
data_format='channels_first',
|
||||
require_flatten=False), (3, None, None))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
test.main()
|
@ -14,31 +14,357 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""Inception-ResNet V2 model for Keras.
|
||||
|
||||
|
||||
Reference paper:
|
||||
- [Inception-v4, Inception-ResNet and the Impact of
|
||||
Residual Connections on Learning](https://arxiv.org/abs/1602.07261)
|
||||
(AAAI 2017)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import inception_resnet_v2
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
BASE_WEIGHT_URL = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/inception_resnet_v2/')
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_resnet_v2.InceptionResNetV2',
|
||||
'keras.applications.InceptionResNetV2')
|
||||
@keras_modules_injection
|
||||
def InceptionResNetV2(*args, **kwargs):
|
||||
return inception_resnet_v2.InceptionResNetV2(*args, **kwargs)
|
||||
def InceptionResNetV2(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the Inception-ResNet v2 architecture.
|
||||
|
||||
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:
|
||||
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` (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 75.
|
||||
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 block.
|
||||
- `'avg'` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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.
|
||||
**kwargs: For backwards compatibility only.
|
||||
|
||||
Returns:
|
||||
A Keras `Model` instance.
|
||||
|
||||
Raises:
|
||||
ValueError: in case of invalid argument for `weights`,
|
||||
or invalid input shape.
|
||||
"""
|
||||
if 'layers' in kwargs:
|
||||
global layers
|
||||
layers = kwargs.pop('layers')
|
||||
if kwargs:
|
||||
raise ValueError('Unknown argument(s): %s' % (kwargs,))
|
||||
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=299,
|
||||
min_size=75,
|
||||
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
|
||||
|
||||
# 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 = layers.MaxPooling2D(3, strides=2)(x)
|
||||
x = conv2d_bn(x, 80, 1, padding='valid')
|
||||
x = conv2d_bn(x, 192, 3, padding='valid')
|
||||
x = layers.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 = layers.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 backend.image_data_format() == 'channels_first' else 3
|
||||
x = layers.Concatenate(axis=channel_axis, name='mixed_5b')(branches)
|
||||
|
||||
# 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 = layers.MaxPooling2D(3, strides=2, padding='valid')(x)
|
||||
branches = [branch_0, branch_1, branch_pool]
|
||||
x = layers.Concatenate(axis=channel_axis, name='mixed_6a')(branches)
|
||||
|
||||
# 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 = layers.MaxPooling2D(3, strides=2, padding='valid')(x)
|
||||
branches = [branch_0, branch_1, branch_2, branch_pool]
|
||||
x = layers.Concatenate(axis=channel_axis, name='mixed_7a')(branches)
|
||||
|
||||
# 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)
|
||||
|
||||
# Final convolution block: 8 x 8 x 1536
|
||||
x = conv2d_bn(x, 1536, 1, name='conv_7b')
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='predictions')(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
|
||||
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='inception_resnet_v2')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
fname = 'inception_resnet_v2_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
weights_path = data_utils.get_file(
|
||||
fname,
|
||||
BASE_WEIGHT_URL + fname,
|
||||
cache_subdir='models',
|
||||
file_hash='e693bd0210a403b3192acc6073ad2e96')
|
||||
else:
|
||||
fname = ('inception_resnet_v2_weights_'
|
||||
'tf_dim_ordering_tf_kernels_notop.h5')
|
||||
weights_path = data_utils.get_file(
|
||||
fname,
|
||||
BASE_WEIGHT_URL + fname,
|
||||
cache_subdir='models',
|
||||
file_hash='d19885ff4a710c122648d3b5c3b684e4')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_resnet_v2.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return inception_resnet_v2.decode_predictions(*args, **kwargs)
|
||||
def conv2d_bn(x,
|
||||
filters,
|
||||
kernel_size,
|
||||
strides=1,
|
||||
padding='same',
|
||||
activation='relu',
|
||||
use_bias=False,
|
||||
name=None):
|
||||
"""Utility function to apply conv + BN.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: filters in `Conv2D`.
|
||||
kernel_size: kernel size as in `Conv2D`.
|
||||
strides: strides in `Conv2D`.
|
||||
padding: padding mode in `Conv2D`.
|
||||
activation: activation in `Conv2D`.
|
||||
use_bias: whether to use a bias in `Conv2D`.
|
||||
name: name of the ops; will become `name + '_ac'` for the activation
|
||||
and `name + '_bn'` for the batch norm layer.
|
||||
|
||||
Returns:
|
||||
Output tensor after applying `Conv2D` and `BatchNormalization`.
|
||||
"""
|
||||
x = layers.Conv2D(
|
||||
filters,
|
||||
kernel_size,
|
||||
strides=strides,
|
||||
padding=padding,
|
||||
use_bias=use_bias,
|
||||
name=name)(
|
||||
x)
|
||||
if not use_bias:
|
||||
bn_axis = 1 if backend.image_data_format() == 'channels_first' else 3
|
||||
bn_name = None if name is None else name + '_bn'
|
||||
x = layers.BatchNormalization(axis=bn_axis, scale=False, name=bn_name)(x)
|
||||
if activation is not None:
|
||||
ac_name = None if name is None else name + '_ac'
|
||||
x = layers.Activation(activation, name=ac_name)(x)
|
||||
return x
|
||||
|
||||
|
||||
def inception_resnet_block(x, scale, block_type, block_idx, activation='relu'):
|
||||
"""Adds a Inception-ResNet block.
|
||||
|
||||
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 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`,
|
||||
and 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: ' + str(block_type))
|
||||
|
||||
block_name = block_type + '_' + str(block_idx)
|
||||
channel_axis = 1 if backend.image_data_format() == 'channels_first' else 3
|
||||
mixed = layers.Concatenate(
|
||||
axis=channel_axis, name=block_name + '_mixed')(
|
||||
branches)
|
||||
up = conv2d_bn(
|
||||
mixed,
|
||||
backend.int_shape(x)[channel_axis],
|
||||
1,
|
||||
activation=None,
|
||||
use_bias=True,
|
||||
name=block_name + '_conv')
|
||||
|
||||
x = layers.Lambda(
|
||||
lambda inputs, scale: inputs[0] + inputs[1] * scale,
|
||||
output_shape=backend.int_shape(x)[1:],
|
||||
arguments={'scale': scale},
|
||||
name=block_name)([x, up])
|
||||
if activation is not None:
|
||||
x = layers.Activation(activation, name=block_name + '_ac')(x)
|
||||
return x
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_resnet_v2.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return inception_resnet_v2.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(x, data_format=data_format, mode='tf')
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_resnet_v2.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -14,31 +14,384 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""Inception V3 model for Keras.
|
||||
|
||||
Reference paper:
|
||||
- [Rethinking the Inception Architecture for Computer Vision](
|
||||
http://arxiv.org/abs/1512.00567) (CVPR 2016)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import inception_v3
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
WEIGHTS_PATH = (
|
||||
'https://storage.googleapis.com/tensorflow/keras-applications/'
|
||||
'inception_v3/inception_v3_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
WEIGHTS_PATH_NO_TOP = (
|
||||
'https://storage.googleapis.com/tensorflow/keras-applications/'
|
||||
'inception_v3/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_v3.InceptionV3',
|
||||
'keras.applications.InceptionV3')
|
||||
@keras_modules_injection
|
||||
def InceptionV3(*args, **kwargs):
|
||||
return inception_v3.InceptionV3(*args, **kwargs)
|
||||
def InceptionV3(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the Inception v3 architecture.
|
||||
|
||||
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:
|
||||
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 (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 75.
|
||||
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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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 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=299,
|
||||
min_size=75,
|
||||
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
|
||||
|
||||
if backend.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 = layers.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 = layers.MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
# mixed 0: 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 = layers.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')
|
||||
|
||||
# mixed 1: 35 x 35 x 288
|
||||
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 = layers.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')
|
||||
|
||||
# mixed 2: 35 x 35 x 288
|
||||
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 = layers.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')
|
||||
|
||||
# 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 = layers.MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
x = layers.concatenate([branch3x3, branch3x3dbl, branch_pool],
|
||||
axis=channel_axis,
|
||||
name='mixed3')
|
||||
|
||||
# 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 = layers.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')
|
||||
|
||||
# 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 = layers.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' + str(5 + i))
|
||||
|
||||
# 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 = layers.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')
|
||||
|
||||
# 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 = layers.MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
x = layers.concatenate([branch3x3, branch7x7x3, branch_pool],
|
||||
axis=channel_axis,
|
||||
name='mixed8')
|
||||
|
||||
# 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_' + str(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 = layers.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' + str(9 + i))
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='predictions')(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
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='inception_v3')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
weights_path = data_utils.get_file(
|
||||
'inception_v3_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='9a0d58056eeedaa3f26cb7ebd46da564')
|
||||
else:
|
||||
weights_path = data_utils.get_file(
|
||||
'inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='bcbd6486424b2319ff4ef7d526e38f63')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_v3.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return inception_v3.decode_predictions(*args, **kwargs)
|
||||
def conv2d_bn(x,
|
||||
filters,
|
||||
num_row,
|
||||
num_col,
|
||||
padding='same',
|
||||
strides=(1, 1),
|
||||
name=None):
|
||||
"""Utility function to apply conv + BN.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: filters in `Conv2D`.
|
||||
num_row: height of the convolution kernel.
|
||||
num_col: width of the convolution kernel.
|
||||
padding: padding mode in `Conv2D`.
|
||||
strides: strides in `Conv2D`.
|
||||
name: name of the ops; will become `name + '_conv'`
|
||||
for the convolution and `name + '_bn'` for the
|
||||
batch norm layer.
|
||||
|
||||
Returns:
|
||||
Output tensor after applying `Conv2D` and `BatchNormalization`.
|
||||
"""
|
||||
if name is not None:
|
||||
bn_name = name + '_bn'
|
||||
conv_name = name + '_conv'
|
||||
else:
|
||||
bn_name = None
|
||||
conv_name = None
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
bn_axis = 1
|
||||
else:
|
||||
bn_axis = 3
|
||||
x = layers.Conv2D(
|
||||
filters, (num_row, num_col),
|
||||
strides=strides,
|
||||
padding=padding,
|
||||
use_bias=False,
|
||||
name=conv_name)(
|
||||
x)
|
||||
x = layers.BatchNormalization(axis=bn_axis, scale=False, name=bn_name)(x)
|
||||
x = layers.Activation('relu', name=name)(x)
|
||||
return x
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_v3.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return inception_v3.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(x, data_format=data_format, mode='tf')
|
||||
|
||||
|
||||
@keras_export('keras.applications.inception_v3.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -14,31 +14,410 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""MobileNet v1 models for Keras.
|
||||
|
||||
MobileNet is a general architecture and can be used for multiple use cases.
|
||||
Depending on the use case, it can use different input layer size and
|
||||
different width factors. This allows different width models to reduce
|
||||
the number of multiply-adds and thereby
|
||||
reduce inference cost on mobile devices.
|
||||
|
||||
MobileNets support any input size greater than 32 x 32, with larger image sizes
|
||||
offering better performance.
|
||||
The number of parameters and number of multiply-adds
|
||||
can be modified by using the `alpha` parameter,
|
||||
which increases/decreases the number of filters in each layer.
|
||||
By altering the image size and `alpha` parameter,
|
||||
all 16 models from the paper can be built, with ImageNet weights provided.
|
||||
|
||||
The paper demonstrates the performance of MobileNets using `alpha` values of
|
||||
1.0 (also called 100 % MobileNet), 0.75, 0.5 and 0.25.
|
||||
For each of these `alpha` values, weights for 4 different input image sizes
|
||||
are provided (224, 192, 160, 128).
|
||||
|
||||
The following table describes the size and accuracy of the 100% MobileNet
|
||||
on size 224 x 224:
|
||||
----------------------------------------------------------------------------
|
||||
Width Multiplier (alpha) | ImageNet Acc | Multiply-Adds (M) | Params (M)
|
||||
----------------------------------------------------------------------------
|
||||
| 1.0 MobileNet-224 | 70.6 % | 529 | 4.2 |
|
||||
| 0.75 MobileNet-224 | 68.4 % | 325 | 2.6 |
|
||||
| 0.50 MobileNet-224 | 63.7 % | 149 | 1.3 |
|
||||
| 0.25 MobileNet-224 | 50.6 % | 41 | 0.5 |
|
||||
----------------------------------------------------------------------------
|
||||
|
||||
The following table describes the performance of
|
||||
the 100 % MobileNet on various input sizes:
|
||||
------------------------------------------------------------------------
|
||||
Resolution | ImageNet Acc | Multiply-Adds (M) | Params (M)
|
||||
------------------------------------------------------------------------
|
||||
| 1.0 MobileNet-224 | 70.6 % | 529 | 4.2 |
|
||||
| 1.0 MobileNet-192 | 69.1 % | 529 | 4.2 |
|
||||
| 1.0 MobileNet-160 | 67.2 % | 529 | 4.2 |
|
||||
| 1.0 MobileNet-128 | 64.4 % | 529 | 4.2 |
|
||||
------------------------------------------------------------------------
|
||||
|
||||
Reference paper:
|
||||
- [MobileNets: Efficient Convolutional Neural Networks for
|
||||
Mobile Vision Applications](https://arxiv.org/abs/1704.04861)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import mobilenet
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.platform import tf_logging as logging
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
BASE_WEIGHT_PATH = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/mobilenet/')
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet.MobileNet',
|
||||
'keras.applications.MobileNet')
|
||||
@keras_modules_injection
|
||||
def MobileNet(*args, **kwargs):
|
||||
return mobilenet.MobileNet(*args, **kwargs)
|
||||
def MobileNet(input_shape=None,
|
||||
alpha=1.0,
|
||||
depth_multiplier=1,
|
||||
dropout=1e-3,
|
||||
include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the MobileNet architecture.
|
||||
|
||||
Arguments:
|
||||
input_shape: optional shape tuple, only to be specified if `include_top`
|
||||
is False (otherwise the input shape has to be `(224, 224, 3)` (with
|
||||
`channels_last` data format) or (3, 224, 224) (with `channels_first`
|
||||
data format). It should have exactly 3 inputs channels, and width and
|
||||
height should be no smaller than 32. E.g. `(200, 200, 3)` would be one
|
||||
valid value.
|
||||
alpha: controls the width of the network. This is known as the width
|
||||
multiplier in the MobileNet paper. - 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: depth multiplier for depthwise convolution. This is
|
||||
called the resolution multiplier in the MobileNet paper.
|
||||
dropout: dropout rate
|
||||
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.
|
||||
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 block. - `avg` means that
|
||||
global average pooling will be applied to the output of the last
|
||||
convolutional block, 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.
|
||||
**kwargs: For backwards compatibility only.
|
||||
|
||||
Returns:
|
||||
A Keras model instance.
|
||||
|
||||
Raises:
|
||||
ValueError: in case of invalid argument for `weights`,
|
||||
or invalid input shape.
|
||||
"""
|
||||
if 'layers' in kwargs:
|
||||
global layers
|
||||
layers = kwargs.pop('layers')
|
||||
if kwargs:
|
||||
raise ValueError('Unknown argument(s): %s' % (kwargs,))
|
||||
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 and default size.
|
||||
if input_shape is None:
|
||||
default_size = 224
|
||||
else:
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
rows = input_shape[0]
|
||||
cols = input_shape[1]
|
||||
|
||||
if rows == cols and rows in [128, 160, 192, 224]:
|
||||
default_size = rows
|
||||
else:
|
||||
default_size = 224
|
||||
|
||||
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 backend.image_data_format() == 'channels_last':
|
||||
row_axis, col_axis = (0, 1)
|
||||
else:
|
||||
row_axis, col_axis = (1, 2)
|
||||
rows = input_shape[row_axis]
|
||||
cols = input_shape[col_axis]
|
||||
|
||||
if weights == 'imagenet':
|
||||
if depth_multiplier != 1:
|
||||
raise ValueError('If imagenet weights are being loaded, '
|
||||
'depth multiplier must be 1')
|
||||
|
||||
if alpha not in [0.25, 0.50, 0.75, 1.0]:
|
||||
raise ValueError('If imagenet weights are being loaded, '
|
||||
'alpha can be one of'
|
||||
'`0.25`, `0.50`, `0.75` or `1.0` only.')
|
||||
|
||||
if rows != cols or rows not in [128, 160, 192, 224]:
|
||||
rows = 224
|
||||
logging.warning('`input_shape` is undefined or non-square, '
|
||||
'or `rows` is not in [128, 160, 192, 224]. '
|
||||
'Weights for input shape (224, 224) will be'
|
||||
' loaded as the default.')
|
||||
|
||||
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
|
||||
|
||||
x = _conv_block(img_input, 32, alpha, strides=(2, 2))
|
||||
x = _depthwise_conv_block(x, 64, alpha, depth_multiplier, block_id=1)
|
||||
|
||||
x = _depthwise_conv_block(
|
||||
x, 128, alpha, depth_multiplier, strides=(2, 2), block_id=2)
|
||||
x = _depthwise_conv_block(x, 128, alpha, depth_multiplier, block_id=3)
|
||||
|
||||
x = _depthwise_conv_block(
|
||||
x, 256, alpha, depth_multiplier, strides=(2, 2), block_id=4)
|
||||
x = _depthwise_conv_block(x, 256, alpha, depth_multiplier, block_id=5)
|
||||
|
||||
x = _depthwise_conv_block(
|
||||
x, 512, alpha, depth_multiplier, strides=(2, 2), block_id=6)
|
||||
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=7)
|
||||
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=8)
|
||||
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=9)
|
||||
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=10)
|
||||
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=11)
|
||||
|
||||
x = _depthwise_conv_block(
|
||||
x, 1024, alpha, depth_multiplier, strides=(2, 2), block_id=12)
|
||||
x = _depthwise_conv_block(x, 1024, alpha, depth_multiplier, block_id=13)
|
||||
|
||||
if include_top:
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
shape = (int(1024 * alpha), 1, 1)
|
||||
else:
|
||||
shape = (1, 1, int(1024 * alpha))
|
||||
|
||||
x = layers.GlobalAveragePooling2D()(x)
|
||||
x = layers.Reshape(shape, name='reshape_1')(x)
|
||||
x = layers.Dropout(dropout, name='dropout')(x)
|
||||
x = layers.Conv2D(classes, (1, 1), padding='same', name='conv_preds')(x)
|
||||
x = layers.Reshape((classes,), name='reshape_2')(x)
|
||||
x = layers.Activation('softmax', name='act_softmax')(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
|
||||
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='mobilenet_%0.2f_%s' % (alpha, rows))
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if alpha == 1.0:
|
||||
alpha_text = '1_0'
|
||||
elif alpha == 0.75:
|
||||
alpha_text = '7_5'
|
||||
elif alpha == 0.50:
|
||||
alpha_text = '5_0'
|
||||
else:
|
||||
alpha_text = '2_5'
|
||||
|
||||
if include_top:
|
||||
model_name = 'mobilenet_%s_%d_tf.h5' % (alpha_text, rows)
|
||||
weight_path = BASE_WEIGHT_PATH + model_name
|
||||
weights_path = data_utils.get_file(
|
||||
model_name, weight_path, cache_subdir='models')
|
||||
else:
|
||||
model_name = 'mobilenet_%s_%d_tf_no_top.h5' % (alpha_text, rows)
|
||||
weight_path = BASE_WEIGHT_PATH + model_name
|
||||
weights_path = data_utils.get_file(
|
||||
model_name, weight_path, cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return mobilenet.decode_predictions(*args, **kwargs)
|
||||
def _conv_block(inputs, filters, alpha, kernel=(3, 3), strides=(1, 1)):
|
||||
"""Adds an initial convolution layer (with batch normalization and relu6).
|
||||
|
||||
Arguments:
|
||||
inputs: Input tensor of shape `(rows, cols, 3)` (with `channels_last`
|
||||
data format) or (3, rows, cols) (with `channels_first` data format).
|
||||
It should have exactly 3 inputs channels, and width and height should
|
||||
be no smaller than 32. E.g. `(224, 224, 3)` would be one valid value.
|
||||
filters: Integer, the dimensionality of the output space (i.e. the
|
||||
number of output filters in the 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.
|
||||
kernel: An integer or tuple/list of 2 integers, specifying the width and
|
||||
height of the 2D convolution window. Can be a single integer to
|
||||
specify the same value for all spatial dimensions.
|
||||
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. # Input shape
|
||||
4D tensor with shape: `(samples, channels, rows, cols)` if
|
||||
data_format='channels_first'
|
||||
or 4D tensor with shape: `(samples, rows, cols, channels)` if
|
||||
data_format='channels_last'. # Output shape
|
||||
4D tensor with shape: `(samples, filters, new_rows, new_cols)` if
|
||||
data_format='channels_first'
|
||||
or 4D tensor with shape: `(samples, 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 backend.image_data_format() == 'channels_first' else -1
|
||||
filters = int(filters * alpha)
|
||||
x = layers.ZeroPadding2D(padding=((0, 1), (0, 1)), name='conv1_pad')(inputs)
|
||||
x = layers.Conv2D(
|
||||
filters,
|
||||
kernel,
|
||||
padding='valid',
|
||||
use_bias=False,
|
||||
strides=strides,
|
||||
name='conv1')(
|
||||
x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='conv1_bn')(x)
|
||||
return layers.ReLU(6., name='conv1_relu')(x)
|
||||
|
||||
|
||||
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: Input 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 of output 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 backend.image_data_format() == 'channels_first' else -1
|
||||
pointwise_conv_filters = int(pointwise_conv_filters * alpha)
|
||||
|
||||
if strides == (1, 1):
|
||||
x = inputs
|
||||
else:
|
||||
x = layers.ZeroPadding2D(((0, 1), (0, 1)), name='conv_pad_%d' % block_id)(
|
||||
inputs)
|
||||
x = layers.DepthwiseConv2D((3, 3),
|
||||
padding='same' if strides == (1, 1) else 'valid',
|
||||
depth_multiplier=depth_multiplier,
|
||||
strides=strides,
|
||||
use_bias=False,
|
||||
name='conv_dw_%d' % block_id)(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name='conv_dw_%d_bn' % block_id)(
|
||||
x)
|
||||
x = layers.ReLU(6., name='conv_dw_%d_relu' % block_id)(x)
|
||||
|
||||
x = layers.Conv2D(
|
||||
pointwise_conv_filters, (1, 1),
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
strides=(1, 1),
|
||||
name='conv_pw_%d' % block_id)(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name='conv_pw_%d_bn' % block_id)(
|
||||
x)
|
||||
return layers.ReLU(6., name='conv_pw_%d_relu' % block_id)(x)
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return mobilenet.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(x, data_format=data_format, mode='tf')
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -14,31 +14,476 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""MobileNet v2 models for Keras.
|
||||
|
||||
MobileNetV2 is a general architecture and can be used for multiple use cases.
|
||||
Depending on the use case, it can use different input layer size and
|
||||
different width factors. This allows different width models to reduce
|
||||
the number of multiply-adds and thereby
|
||||
reduce inference cost on mobile devices.
|
||||
|
||||
MobileNetV2 is very similar to the original MobileNet,
|
||||
except that it uses inverted residual blocks with
|
||||
bottlenecking features. It has a drastically lower
|
||||
parameter count than the original MobileNet.
|
||||
MobileNets support any input size greater
|
||||
than 32 x 32, with larger image sizes
|
||||
offering better performance.
|
||||
|
||||
The number of parameters and number of multiply-adds
|
||||
can be modified by using the `alpha` parameter,
|
||||
which increases/decreases the number of filters in each layer.
|
||||
By altering the image size and `alpha` parameter,
|
||||
all 22 models from the paper can be built, with ImageNet weights provided.
|
||||
|
||||
The paper demonstrates the performance of MobileNets using `alpha` values of
|
||||
1.0 (also called 100 % MobileNet), 0.35, 0.5, 0.75, 1.0, 1.3, and 1.4
|
||||
For each of these `alpha` values, weights for 5 different input image sizes
|
||||
are provided (224, 192, 160, 128, and 96).
|
||||
|
||||
The following table describes the performance of
|
||||
MobileNet on various input sizes:
|
||||
------------------------------------------------------------------------
|
||||
MACs stands for Multiply Adds
|
||||
Classification Checkpoint|MACs (M)|Parameters (M)|Top 1 Accuracy|Top 5 Accuracy
|
||||
--------------------------|------------|---------------|---------|----|---------
|
||||
| [mobilenet_v2_1.4_224] | 582 | 6.06 | 75.0 | 92.5 |
|
||||
| [mobilenet_v2_1.3_224] | 509 | 5.34 | 74.4 | 92.1 |
|
||||
| [mobilenet_v2_1.0_224] | 300 | 3.47 | 71.8 | 91.0 |
|
||||
| [mobilenet_v2_1.0_192] | 221 | 3.47 | 70.7 | 90.1 |
|
||||
| [mobilenet_v2_1.0_160] | 154 | 3.47 | 68.8 | 89.0 |
|
||||
| [mobilenet_v2_1.0_128] | 99 | 3.47 | 65.3 | 86.9 |
|
||||
| [mobilenet_v2_1.0_96] | 56 | 3.47 | 60.3 | 83.2 |
|
||||
| [mobilenet_v2_0.75_224] | 209 | 2.61 | 69.8 | 89.6 |
|
||||
| [mobilenet_v2_0.75_192] | 153 | 2.61 | 68.7 | 88.9 |
|
||||
| [mobilenet_v2_0.75_160] | 107 | 2.61 | 66.4 | 87.3 |
|
||||
| [mobilenet_v2_0.75_128] | 69 | 2.61 | 63.2 | 85.3 |
|
||||
| [mobilenet_v2_0.75_96] | 39 | 2.61 | 58.8 | 81.6 |
|
||||
| [mobilenet_v2_0.5_224] | 97 | 1.95 | 65.4 | 86.4 |
|
||||
| [mobilenet_v2_0.5_192] | 71 | 1.95 | 63.9 | 85.4 |
|
||||
| [mobilenet_v2_0.5_160] | 50 | 1.95 | 61.0 | 83.2 |
|
||||
| [mobilenet_v2_0.5_128] | 32 | 1.95 | 57.7 | 80.8 |
|
||||
| [mobilenet_v2_0.5_96] | 18 | 1.95 | 51.2 | 75.8 |
|
||||
| [mobilenet_v2_0.35_224] | 59 | 1.66 | 60.3 | 82.9 |
|
||||
| [mobilenet_v2_0.35_192] | 43 | 1.66 | 58.2 | 81.2 |
|
||||
| [mobilenet_v2_0.35_160] | 30 | 1.66 | 55.7 | 79.1 |
|
||||
| [mobilenet_v2_0.35_128] | 20 | 1.66 | 50.8 | 75.0 |
|
||||
| [mobilenet_v2_0.35_96] | 11 | 1.66 | 45.5 | 70.4 |
|
||||
|
||||
Reference paper:
|
||||
- [MobileNetV2: Inverted Residuals and Linear Bottlenecks]
|
||||
(https://arxiv.org/abs/1801.04381) (CVPR 2018)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import mobilenet_v2
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.platform import tf_logging as logging
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
BASE_WEIGHT_PATH = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/mobilenet_v2/')
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet_v2.MobileNetV2',
|
||||
'keras.applications.MobileNetV2')
|
||||
@keras_modules_injection
|
||||
def MobileNetV2(*args, **kwargs):
|
||||
return mobilenet_v2.MobileNetV2(*args, **kwargs)
|
||||
def MobileNetV2(input_shape=None,
|
||||
alpha=1.0,
|
||||
include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the MobileNetV2 architecture.
|
||||
|
||||
Arguments:
|
||||
input_shape: optional shape tuple, to be specified if you would
|
||||
like to use a model with an input img resolution that is not
|
||||
(224, 224, 3).
|
||||
It should have exactly 3 inputs channels (224, 224, 3).
|
||||
You can also omit this option if you would like
|
||||
to infer input_shape from an input_tensor.
|
||||
If you choose to include both input_tensor and input_shape then
|
||||
input_shape will be used if they match, if the shapes
|
||||
do not match then we will throw an error.
|
||||
E.g. `(160, 160, 3)` would be one valid value.
|
||||
alpha: controls the width of the network. This is known as the
|
||||
width multiplier in the MobileNetV2 paper, but the name is kept for
|
||||
consistency with MobileNetV1 in Keras.
|
||||
- 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.
|
||||
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.
|
||||
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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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.
|
||||
**kwargs: For backwards compatibility only.
|
||||
|
||||
Returns:
|
||||
A Keras model instance.
|
||||
|
||||
Raises:
|
||||
ValueError: in case of invalid argument for `weights`,
|
||||
or invalid input shape or invalid alpha, rows when
|
||||
weights='imagenet'
|
||||
"""
|
||||
if 'layers' in kwargs:
|
||||
global layers
|
||||
layers = kwargs.pop('layers')
|
||||
if kwargs:
|
||||
raise ValueError('Unknown argument(s): %s' % (kwargs,))
|
||||
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 and default size.
|
||||
# If both input_shape and input_tensor are used, they should match
|
||||
if input_shape is not None and input_tensor is not None:
|
||||
try:
|
||||
is_input_t_tensor = backend.is_keras_tensor(input_tensor)
|
||||
except ValueError:
|
||||
try:
|
||||
is_input_t_tensor = backend.is_keras_tensor(
|
||||
layer_utils.get_source_inputs(input_tensor))
|
||||
except ValueError:
|
||||
raise ValueError('input_tensor: ', input_tensor,
|
||||
'is not type input_tensor')
|
||||
if is_input_t_tensor:
|
||||
if backend.image_data_format == 'channels_first':
|
||||
if backend.int_shape(input_tensor)[1] != input_shape[1]:
|
||||
raise ValueError('input_shape: ', input_shape, 'and input_tensor: ',
|
||||
input_tensor,
|
||||
'do not meet the same shape requirements')
|
||||
else:
|
||||
if backend.int_shape(input_tensor)[2] != input_shape[1]:
|
||||
raise ValueError('input_shape: ', input_shape, 'and input_tensor: ',
|
||||
input_tensor,
|
||||
'do not meet the same shape requirements')
|
||||
else:
|
||||
raise ValueError('input_tensor specified: ', input_tensor,
|
||||
'is not a keras tensor')
|
||||
|
||||
# If input_shape is None, infer shape from input_tensor
|
||||
if input_shape is None and input_tensor is not None:
|
||||
|
||||
try:
|
||||
backend.is_keras_tensor(input_tensor)
|
||||
except ValueError:
|
||||
raise ValueError('input_tensor: ', input_tensor, 'is type: ',
|
||||
type(input_tensor), 'which is not a valid type')
|
||||
|
||||
if input_shape is None and not backend.is_keras_tensor(input_tensor):
|
||||
default_size = 224
|
||||
elif input_shape is None and backend.is_keras_tensor(input_tensor):
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
rows = backend.int_shape(input_tensor)[2]
|
||||
cols = backend.int_shape(input_tensor)[3]
|
||||
else:
|
||||
rows = backend.int_shape(input_tensor)[1]
|
||||
cols = backend.int_shape(input_tensor)[2]
|
||||
|
||||
if rows == cols and rows in [96, 128, 160, 192, 224]:
|
||||
default_size = rows
|
||||
else:
|
||||
default_size = 224
|
||||
|
||||
# If input_shape is None and no input_tensor
|
||||
elif input_shape is None:
|
||||
default_size = 224
|
||||
|
||||
# If input_shape is not None, assume default size
|
||||
else:
|
||||
if backend.image_data_format() == 'channels_first':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
rows = input_shape[0]
|
||||
cols = input_shape[1]
|
||||
|
||||
if rows == cols and rows in [96, 128, 160, 192, 224]:
|
||||
default_size = rows
|
||||
else:
|
||||
default_size = 224
|
||||
|
||||
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 backend.image_data_format() == 'channels_last':
|
||||
row_axis, col_axis = (0, 1)
|
||||
else:
|
||||
row_axis, col_axis = (1, 2)
|
||||
rows = input_shape[row_axis]
|
||||
cols = input_shape[col_axis]
|
||||
|
||||
if weights == 'imagenet':
|
||||
if alpha not in [0.35, 0.50, 0.75, 1.0, 1.3, 1.4]:
|
||||
raise ValueError('If imagenet weights are being loaded, '
|
||||
'alpha can be one of `0.35`, `0.50`, `0.75`, '
|
||||
'`1.0`, `1.3` or `1.4` only.')
|
||||
|
||||
if rows != cols or rows not in [96, 128, 160, 192, 224]:
|
||||
rows = 224
|
||||
logging.warning('`input_shape` is undefined or non-square, '
|
||||
'or `rows` is not in [96, 128, 160, 192, 224].'
|
||||
' Weights for input shape (224, 224) will be'
|
||||
' loaded as the default.')
|
||||
|
||||
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
|
||||
|
||||
channel_axis = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
|
||||
first_block_filters = _make_divisible(32 * alpha, 8)
|
||||
x = layers.ZeroPadding2D(
|
||||
padding=imagenet_utils.correct_pad(img_input, 3),
|
||||
name='Conv1_pad')(img_input)
|
||||
x = layers.Conv2D(
|
||||
first_block_filters,
|
||||
kernel_size=3,
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
use_bias=False,
|
||||
name='Conv1')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, epsilon=1e-3, momentum=0.999, name='bn_Conv1')(
|
||||
x)
|
||||
x = layers.ReLU(6., name='Conv1_relu')(x)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=16, alpha=alpha, stride=1, expansion=1, block_id=0)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=24, alpha=alpha, stride=2, expansion=6, block_id=1)
|
||||
x = _inverted_res_block(
|
||||
x, filters=24, alpha=alpha, stride=1, expansion=6, block_id=2)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=32, alpha=alpha, stride=2, expansion=6, block_id=3)
|
||||
x = _inverted_res_block(
|
||||
x, filters=32, alpha=alpha, stride=1, expansion=6, block_id=4)
|
||||
x = _inverted_res_block(
|
||||
x, filters=32, alpha=alpha, stride=1, expansion=6, block_id=5)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=64, alpha=alpha, stride=2, expansion=6, block_id=6)
|
||||
x = _inverted_res_block(
|
||||
x, filters=64, alpha=alpha, stride=1, expansion=6, block_id=7)
|
||||
x = _inverted_res_block(
|
||||
x, filters=64, alpha=alpha, stride=1, expansion=6, block_id=8)
|
||||
x = _inverted_res_block(
|
||||
x, filters=64, alpha=alpha, stride=1, expansion=6, block_id=9)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=96, alpha=alpha, stride=1, expansion=6, block_id=10)
|
||||
x = _inverted_res_block(
|
||||
x, filters=96, alpha=alpha, stride=1, expansion=6, block_id=11)
|
||||
x = _inverted_res_block(
|
||||
x, filters=96, alpha=alpha, stride=1, expansion=6, block_id=12)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=160, alpha=alpha, stride=2, expansion=6, block_id=13)
|
||||
x = _inverted_res_block(
|
||||
x, filters=160, alpha=alpha, stride=1, expansion=6, block_id=14)
|
||||
x = _inverted_res_block(
|
||||
x, filters=160, alpha=alpha, stride=1, expansion=6, block_id=15)
|
||||
|
||||
x = _inverted_res_block(
|
||||
x, filters=320, alpha=alpha, stride=1, expansion=6, block_id=16)
|
||||
|
||||
# no alpha applied to last conv as stated in the paper:
|
||||
# if the width multiplier is greater than 1 we
|
||||
# increase the number of output channels
|
||||
if alpha > 1.0:
|
||||
last_block_filters = _make_divisible(1280 * alpha, 8)
|
||||
else:
|
||||
last_block_filters = 1280
|
||||
|
||||
x = layers.Conv2D(
|
||||
last_block_filters, kernel_size=1, use_bias=False, name='Conv_1')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, epsilon=1e-3, momentum=0.999, name='Conv_1_bn')(
|
||||
x)
|
||||
x = layers.ReLU(6., name='out_relu')(x)
|
||||
|
||||
if include_top:
|
||||
x = layers.GlobalAveragePooling2D()(x)
|
||||
x = layers.Dense(
|
||||
classes, activation='softmax', use_bias=True, name='Logits')(
|
||||
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
|
||||
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='mobilenetv2_%0.2f_%s' % (alpha, rows))
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
model_name = ('mobilenet_v2_weights_tf_dim_ordering_tf_kernels_' +
|
||||
str(alpha) + '_' + str(rows) + '.h5')
|
||||
weight_path = BASE_WEIGHT_PATH + model_name
|
||||
weights_path = data_utils.get_file(
|
||||
model_name, weight_path, cache_subdir='models')
|
||||
else:
|
||||
model_name = ('mobilenet_v2_weights_tf_dim_ordering_tf_kernels_' +
|
||||
str(alpha) + '_' + str(rows) + '_no_top' + '.h5')
|
||||
weight_path = BASE_WEIGHT_PATH + model_name
|
||||
weights_path = data_utils.get_file(
|
||||
model_name, weight_path, cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet_v2.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return mobilenet_v2.decode_predictions(*args, **kwargs)
|
||||
def _inverted_res_block(inputs, expansion, stride, alpha, filters, block_id):
|
||||
"""Inverted ResNet block."""
|
||||
channel_axis = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
|
||||
in_channels = backend.int_shape(inputs)[channel_axis]
|
||||
pointwise_conv_filters = int(filters * alpha)
|
||||
pointwise_filters = _make_divisible(pointwise_conv_filters, 8)
|
||||
x = inputs
|
||||
prefix = 'block_{}_'.format(block_id)
|
||||
|
||||
if block_id:
|
||||
# Expand
|
||||
x = layers.Conv2D(
|
||||
expansion * in_channels,
|
||||
kernel_size=1,
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
activation=None,
|
||||
name=prefix + 'expand')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis,
|
||||
epsilon=1e-3,
|
||||
momentum=0.999,
|
||||
name=prefix + 'expand_BN')(
|
||||
x)
|
||||
x = layers.ReLU(6., name=prefix + 'expand_relu')(x)
|
||||
else:
|
||||
prefix = 'expanded_conv_'
|
||||
|
||||
# Depthwise
|
||||
if stride == 2:
|
||||
x = layers.ZeroPadding2D(
|
||||
padding=imagenet_utils.correct_pad(x, 3),
|
||||
name=prefix + 'pad')(x)
|
||||
x = layers.DepthwiseConv2D(
|
||||
kernel_size=3,
|
||||
strides=stride,
|
||||
activation=None,
|
||||
use_bias=False,
|
||||
padding='same' if stride == 1 else 'valid',
|
||||
name=prefix + 'depthwise')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis,
|
||||
epsilon=1e-3,
|
||||
momentum=0.999,
|
||||
name=prefix + 'depthwise_BN')(
|
||||
x)
|
||||
|
||||
x = layers.ReLU(6., name=prefix + 'depthwise_relu')(x)
|
||||
|
||||
# Project
|
||||
x = layers.Conv2D(
|
||||
pointwise_filters,
|
||||
kernel_size=1,
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
activation=None,
|
||||
name=prefix + 'project')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis,
|
||||
epsilon=1e-3,
|
||||
momentum=0.999,
|
||||
name=prefix + 'project_BN')(
|
||||
x)
|
||||
|
||||
if in_channels == pointwise_filters and stride == 1:
|
||||
return layers.Add(name=prefix + 'add')([inputs, x])
|
||||
return x
|
||||
|
||||
|
||||
def _make_divisible(v, divisor, min_value=None):
|
||||
if min_value is None:
|
||||
min_value = divisor
|
||||
new_v = max(min_value, int(v + divisor / 2) // divisor * divisor)
|
||||
# Make sure that round down does not go down by more than 10%.
|
||||
if new_v < 0.9 * v:
|
||||
new_v += divisor
|
||||
return new_v
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet_v2.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return mobilenet_v2.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(x, data_format=data_format, mode='tf')
|
||||
|
||||
|
||||
@keras_export('keras.applications.mobilenet_v2.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -14,38 +14,763 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""NASNet-A models for Keras.
|
||||
|
||||
NASNet refers to Neural Architecture Search Network, a family of models
|
||||
that were designed automatically by learning the model architectures
|
||||
directly on the dataset of interest.
|
||||
|
||||
Here we consider NASNet-A, the highest performance model that was found
|
||||
for the CIFAR-10 dataset, and then extended to ImageNet 2012 dataset,
|
||||
obtaining state of the art performance on CIFAR-10 and ImageNet 2012.
|
||||
Only the NASNet-A models, and their respective weights, which are suited
|
||||
for ImageNet 2012 are provided.
|
||||
|
||||
The below table describes the performance on ImageNet 2012:
|
||||
--------------------------------------------------------------------------------
|
||||
Architecture | Top-1 Acc | Top-5 Acc | Multiply-Adds | Params (M)
|
||||
--------------------------------------------------------------------------------
|
||||
| NASNet-A (4 @ 1056) | 74.0 % | 91.6 % | 564 M | 5.3 |
|
||||
| NASNet-A (6 @ 4032) | 82.7 % | 96.2 % | 23.8 B | 88.9 |
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
References:
|
||||
- [Learning Transferable Architectures for Scalable Image Recognition]
|
||||
(https://arxiv.org/abs/1707.07012) (CVPR 2018)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import nasnet
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.platform import tf_logging as logging
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
BASE_WEIGHTS_PATH = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/nasnet/')
|
||||
NASNET_MOBILE_WEIGHT_PATH = BASE_WEIGHTS_PATH + 'NASNet-mobile.h5'
|
||||
NASNET_MOBILE_WEIGHT_PATH_NO_TOP = BASE_WEIGHTS_PATH + 'NASNet-mobile-no-top.h5'
|
||||
NASNET_LARGE_WEIGHT_PATH = BASE_WEIGHTS_PATH + 'NASNet-large.h5'
|
||||
NASNET_LARGE_WEIGHT_PATH_NO_TOP = BASE_WEIGHTS_PATH + 'NASNet-large-no-top.h5'
|
||||
|
||||
|
||||
def NASNet(input_shape=None,
|
||||
penultimate_filters=4032,
|
||||
num_blocks=6,
|
||||
stem_block_filters=96,
|
||||
skip_reduction=True,
|
||||
filter_multiplier=2,
|
||||
include_top=True,
|
||||
weights=None,
|
||||
input_tensor=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
default_size=None):
|
||||
"""Instantiates a NASNet model.
|
||||
|
||||
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:
|
||||
input_shape: Optional shape tuple, the input shape
|
||||
is by default `(331, 331, 3)` for NASNetLarge and
|
||||
`(224, 224, 3)` for NASNetMobile.
|
||||
It should have exactly 3 input channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(224, 224, 3)` would be one valid value.
|
||||
penultimate_filters: Number of filters in the penultimate layer.
|
||||
NASNet models use the notation `NASNet (N @ P)`, where:
|
||||
- N is the number of blocks
|
||||
- P is the number of penultimate filters
|
||||
num_blocks: Number of repeated blocks of the NASNet model.
|
||||
NASNet models use the notation `NASNet (N @ P)`, where:
|
||||
- N is the number of blocks
|
||||
- P is the number of penultimate filters
|
||||
stem_block_filters: Number of filters in the initial stem block
|
||||
skip_reduction: Whether to skip the reduction step at the tail
|
||||
end of the network.
|
||||
filter_multiplier: Controls the width of the network.
|
||||
- If `filter_multiplier` < 1.0, proportionally decreases the number
|
||||
of filters in each layer.
|
||||
- If `filter_multiplier` > 1.0, proportionally increases the number
|
||||
of filters in each layer.
|
||||
- If `filter_multiplier` = 1, default number of filters from the
|
||||
paper are used at each layer.
|
||||
include_top: Whether to include the fully-connected
|
||||
layer at the top of the network.
|
||||
weights: `None` (random initialization) or
|
||||
`imagenet` (ImageNet weights)
|
||||
input_tensor: Optional Keras tensor (i.e. output of
|
||||
`layers.Input()`)
|
||||
to use as image input for the model.
|
||||
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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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.
|
||||
default_size: Specifies the default image size of the model
|
||||
|
||||
Returns:
|
||||
A Keras model instance.
|
||||
|
||||
Raises:
|
||||
ValueError: In case of invalid argument for `weights`,
|
||||
invalid input shape or invalid `penultimate_filters` value.
|
||||
"""
|
||||
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')
|
||||
|
||||
if (isinstance(input_shape, tuple) and None in input_shape and
|
||||
weights == 'imagenet'):
|
||||
raise ValueError('When specifying the input shape of a NASNet'
|
||||
' and loading `ImageNet` weights, '
|
||||
'the input_shape argument must be static '
|
||||
'(no None entries). Got: `input_shape=' +
|
||||
str(input_shape) + '`.')
|
||||
|
||||
if default_size is None:
|
||||
default_size = 331
|
||||
|
||||
# Determine proper input shape and default size.
|
||||
input_shape = imagenet_utils.obtain_input_shape(
|
||||
input_shape,
|
||||
default_size=default_size,
|
||||
min_size=32,
|
||||
data_format=backend.image_data_format(),
|
||||
require_flatten=True,
|
||||
weights=weights)
|
||||
|
||||
if backend.image_data_format() != 'channels_last':
|
||||
logging.warning('The NASNet family of models is only available '
|
||||
'for the input data format "channels_last" '
|
||||
'(width, height, channels). '
|
||||
'However your settings specify the default '
|
||||
'data format "channels_first" (channels, width, height).'
|
||||
' You should set `image_data_format="channels_last"` '
|
||||
'in your Keras config located at ~/.keras/keras.json. '
|
||||
'The model being returned right now will expect inputs '
|
||||
'to follow the "channels_last" data format.')
|
||||
backend.set_image_data_format('channels_last')
|
||||
old_data_format = 'channels_first'
|
||||
else:
|
||||
old_data_format = None
|
||||
|
||||
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
|
||||
|
||||
if penultimate_filters % (24 * (filter_multiplier**2)) != 0:
|
||||
raise ValueError(
|
||||
'For NASNet-A models, the `penultimate_filters` must be a multiple '
|
||||
'of 24 * (`filter_multiplier` ** 2). Current value: %d' %
|
||||
penultimate_filters)
|
||||
|
||||
channel_dim = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
filters = penultimate_filters // 24
|
||||
|
||||
x = layers.Conv2D(
|
||||
stem_block_filters, (3, 3),
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
use_bias=False,
|
||||
name='stem_conv1',
|
||||
kernel_initializer='he_normal')(
|
||||
img_input)
|
||||
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_dim, momentum=0.9997, epsilon=1e-3, name='stem_bn1')(
|
||||
x)
|
||||
|
||||
p = None
|
||||
x, p = _reduction_a_cell(
|
||||
x, p, filters // (filter_multiplier**2), block_id='stem_1')
|
||||
x, p = _reduction_a_cell(
|
||||
x, p, filters // filter_multiplier, block_id='stem_2')
|
||||
|
||||
for i in range(num_blocks):
|
||||
x, p = _normal_a_cell(x, p, filters, block_id='%d' % (i))
|
||||
|
||||
x, p0 = _reduction_a_cell(
|
||||
x, p, filters * filter_multiplier, block_id='reduce_%d' % (num_blocks))
|
||||
|
||||
p = p0 if not skip_reduction else p
|
||||
|
||||
for i in range(num_blocks):
|
||||
x, p = _normal_a_cell(
|
||||
x, p, filters * filter_multiplier, block_id='%d' % (num_blocks + i + 1))
|
||||
|
||||
x, p0 = _reduction_a_cell(
|
||||
x,
|
||||
p,
|
||||
filters * filter_multiplier**2,
|
||||
block_id='reduce_%d' % (2 * num_blocks))
|
||||
|
||||
p = p0 if not skip_reduction else p
|
||||
|
||||
for i in range(num_blocks):
|
||||
x, p = _normal_a_cell(
|
||||
x,
|
||||
p,
|
||||
filters * filter_multiplier**2,
|
||||
block_id='%d' % (2 * num_blocks + i + 1))
|
||||
|
||||
x = layers.Activation('relu')(x)
|
||||
|
||||
if include_top:
|
||||
x = layers.GlobalAveragePooling2D()(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='predictions')(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
|
||||
|
||||
model = training.Model(inputs, x, name='NASNet')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if default_size == 224: # mobile version
|
||||
if include_top:
|
||||
weights_path = data_utils.get_file(
|
||||
'nasnet_mobile.h5',
|
||||
NASNET_MOBILE_WEIGHT_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='020fb642bf7360b370c678b08e0adf61')
|
||||
else:
|
||||
weights_path = data_utils.get_file(
|
||||
'nasnet_mobile_no_top.h5',
|
||||
NASNET_MOBILE_WEIGHT_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='1ed92395b5b598bdda52abe5c0dbfd63')
|
||||
model.load_weights(weights_path)
|
||||
elif default_size == 331: # large version
|
||||
if include_top:
|
||||
weights_path = data_utils.get_file(
|
||||
'nasnet_large.h5',
|
||||
NASNET_LARGE_WEIGHT_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='11577c9a518f0070763c2b964a382f17')
|
||||
else:
|
||||
weights_path = data_utils.get_file(
|
||||
'nasnet_large_no_top.h5',
|
||||
NASNET_LARGE_WEIGHT_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='d81d89dc07e6e56530c4e77faddd61b5')
|
||||
model.load_weights(weights_path)
|
||||
else:
|
||||
raise ValueError('ImageNet weights can only be loaded with NASNetLarge'
|
||||
' or NASNetMobile')
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
if old_data_format:
|
||||
backend.set_image_data_format(old_data_format)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.nasnet.NASNetMobile',
|
||||
'keras.applications.NASNetMobile')
|
||||
@keras_modules_injection
|
||||
def NASNetMobile(*args, **kwargs):
|
||||
return nasnet.NASNetMobile(*args, **kwargs)
|
||||
def NASNetMobile(input_shape=None,
|
||||
include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates a Mobile NASNet model in ImageNet mode.
|
||||
|
||||
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:
|
||||
input_shape: Optional shape tuple, only to be specified
|
||||
if `include_top` is False (otherwise the input shape
|
||||
has to be `(224, 224, 3)` for NASNetMobile
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(224, 224, 3)` would be one valid value.
|
||||
include_top: Whether to include the fully-connected
|
||||
layer at the top of the network.
|
||||
weights: `None` (random initialization) or
|
||||
`imagenet` (ImageNet weights)
|
||||
input_tensor: Optional Keras tensor (i.e. output of
|
||||
`layers.Input()`)
|
||||
to use as image input for the model.
|
||||
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 a
|
||||
backend that does not support separable convolutions.
|
||||
"""
|
||||
return NASNet(
|
||||
input_shape,
|
||||
penultimate_filters=1056,
|
||||
num_blocks=4,
|
||||
stem_block_filters=32,
|
||||
skip_reduction=False,
|
||||
filter_multiplier=2,
|
||||
include_top=include_top,
|
||||
weights=weights,
|
||||
input_tensor=input_tensor,
|
||||
pooling=pooling,
|
||||
classes=classes,
|
||||
default_size=224)
|
||||
|
||||
|
||||
@keras_export('keras.applications.nasnet.NASNetLarge',
|
||||
'keras.applications.NASNetLarge')
|
||||
@keras_modules_injection
|
||||
def NASNetLarge(*args, **kwargs):
|
||||
return nasnet.NASNetLarge(*args, **kwargs)
|
||||
def NASNetLarge(input_shape=None,
|
||||
include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates a NASNet model in ImageNet mode.
|
||||
|
||||
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:
|
||||
input_shape: Optional shape tuple, only to be specified
|
||||
if `include_top` is False (otherwise the input shape
|
||||
has to be `(331, 331, 3)` for NASNetLarge.
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(224, 224, 3)` would be one valid value.
|
||||
include_top: Whether to include the fully-connected
|
||||
layer at the top of the network.
|
||||
weights: `None` (random initialization) or
|
||||
`imagenet` (ImageNet weights)
|
||||
input_tensor: Optional Keras tensor (i.e. output of
|
||||
`layers.Input()`)
|
||||
to use as image input for the model.
|
||||
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 a
|
||||
backend that does not support separable convolutions.
|
||||
"""
|
||||
return NASNet(
|
||||
input_shape,
|
||||
penultimate_filters=4032,
|
||||
num_blocks=6,
|
||||
stem_block_filters=96,
|
||||
skip_reduction=True,
|
||||
filter_multiplier=2,
|
||||
include_top=include_top,
|
||||
weights=weights,
|
||||
input_tensor=input_tensor,
|
||||
pooling=pooling,
|
||||
classes=classes,
|
||||
default_size=331)
|
||||
|
||||
|
||||
@keras_export('keras.applications.nasnet.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return nasnet.decode_predictions(*args, **kwargs)
|
||||
def _separable_conv_block(ip,
|
||||
filters,
|
||||
kernel_size=(3, 3),
|
||||
strides=(1, 1),
|
||||
block_id=None):
|
||||
"""Adds 2 blocks of [relu-separable conv-batchnorm].
|
||||
|
||||
Arguments:
|
||||
ip: Input tensor
|
||||
filters: Number of output filters per layer
|
||||
kernel_size: Kernel size of separable convolutions
|
||||
strides: Strided convolution for downsampling
|
||||
block_id: String block_id
|
||||
|
||||
Returns:
|
||||
A Keras tensor
|
||||
"""
|
||||
channel_dim = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
|
||||
with backend.name_scope('separable_conv_block_%s' % block_id):
|
||||
x = layers.Activation('relu')(ip)
|
||||
if strides == (2, 2):
|
||||
x = layers.ZeroPadding2D(
|
||||
padding=imagenet_utils.correct_pad(x, kernel_size),
|
||||
name='separable_conv_1_pad_%s' % block_id)(x)
|
||||
conv_pad = 'valid'
|
||||
else:
|
||||
conv_pad = 'same'
|
||||
x = layers.SeparableConv2D(
|
||||
filters,
|
||||
kernel_size,
|
||||
strides=strides,
|
||||
name='separable_conv_1_%s' % block_id,
|
||||
padding=conv_pad,
|
||||
use_bias=False,
|
||||
kernel_initializer='he_normal')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_dim,
|
||||
momentum=0.9997,
|
||||
epsilon=1e-3,
|
||||
name='separable_conv_1_bn_%s' % (block_id))(
|
||||
x)
|
||||
x = layers.Activation('relu')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
filters,
|
||||
kernel_size,
|
||||
name='separable_conv_2_%s' % block_id,
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
kernel_initializer='he_normal')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_dim,
|
||||
momentum=0.9997,
|
||||
epsilon=1e-3,
|
||||
name='separable_conv_2_bn_%s' % (block_id))(
|
||||
x)
|
||||
return x
|
||||
|
||||
|
||||
def _adjust_block(p, ip, filters, block_id=None):
|
||||
"""Adjusts the input `previous path` to match the shape of the `input`.
|
||||
|
||||
Used in situations where the output number of filters needs to be changed.
|
||||
|
||||
Arguments:
|
||||
p: Input tensor which needs to be modified
|
||||
ip: Input tensor whose shape needs to be matched
|
||||
filters: Number of output filters to be matched
|
||||
block_id: String block_id
|
||||
|
||||
Returns:
|
||||
Adjusted Keras tensor
|
||||
"""
|
||||
channel_dim = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
img_dim = 2 if backend.image_data_format() == 'channels_first' else -2
|
||||
|
||||
ip_shape = backend.int_shape(ip)
|
||||
|
||||
if p is not None:
|
||||
p_shape = backend.int_shape(p)
|
||||
|
||||
with backend.name_scope('adjust_block'):
|
||||
if p is None:
|
||||
p = ip
|
||||
|
||||
elif p_shape[img_dim] != ip_shape[img_dim]:
|
||||
with backend.name_scope('adjust_reduction_block_%s' % block_id):
|
||||
p = layers.Activation('relu', name='adjust_relu_1_%s' % block_id)(p)
|
||||
p1 = layers.AveragePooling2D((1, 1),
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
name='adjust_avg_pool_1_%s' % block_id)(
|
||||
p)
|
||||
p1 = layers.Conv2D(
|
||||
filters // 2, (1, 1),
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
name='adjust_conv_1_%s' % block_id,
|
||||
kernel_initializer='he_normal')(
|
||||
p1)
|
||||
|
||||
p2 = layers.ZeroPadding2D(padding=((0, 1), (0, 1)))(p)
|
||||
p2 = layers.Cropping2D(cropping=((1, 0), (1, 0)))(p2)
|
||||
p2 = layers.AveragePooling2D((1, 1),
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
name='adjust_avg_pool_2_%s' % block_id)(
|
||||
p2)
|
||||
p2 = layers.Conv2D(
|
||||
filters // 2, (1, 1),
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
name='adjust_conv_2_%s' % block_id,
|
||||
kernel_initializer='he_normal')(
|
||||
p2)
|
||||
|
||||
p = layers.concatenate([p1, p2], axis=channel_dim)
|
||||
p = layers.BatchNormalization(
|
||||
axis=channel_dim,
|
||||
momentum=0.9997,
|
||||
epsilon=1e-3,
|
||||
name='adjust_bn_%s' % block_id)(
|
||||
p)
|
||||
|
||||
elif p_shape[channel_dim] != filters:
|
||||
with backend.name_scope('adjust_projection_block_%s' % block_id):
|
||||
p = layers.Activation('relu')(p)
|
||||
p = layers.Conv2D(
|
||||
filters, (1, 1),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='adjust_conv_projection_%s' % block_id,
|
||||
use_bias=False,
|
||||
kernel_initializer='he_normal')(
|
||||
p)
|
||||
p = layers.BatchNormalization(
|
||||
axis=channel_dim,
|
||||
momentum=0.9997,
|
||||
epsilon=1e-3,
|
||||
name='adjust_bn_%s' % block_id)(
|
||||
p)
|
||||
return p
|
||||
|
||||
|
||||
def _normal_a_cell(ip, p, filters, block_id=None):
|
||||
"""Adds a Normal cell for NASNet-A (Fig. 4 in the paper).
|
||||
|
||||
Arguments:
|
||||
ip: Input tensor `x`
|
||||
p: Input tensor `p`
|
||||
filters: Number of output filters
|
||||
block_id: String block_id
|
||||
|
||||
Returns:
|
||||
A Keras tensor
|
||||
"""
|
||||
channel_dim = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
|
||||
with backend.name_scope('normal_A_block_%s' % block_id):
|
||||
p = _adjust_block(p, ip, filters, block_id)
|
||||
|
||||
h = layers.Activation('relu')(ip)
|
||||
h = layers.Conv2D(
|
||||
filters, (1, 1),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='normal_conv_1_%s' % block_id,
|
||||
use_bias=False,
|
||||
kernel_initializer='he_normal')(
|
||||
h)
|
||||
h = layers.BatchNormalization(
|
||||
axis=channel_dim,
|
||||
momentum=0.9997,
|
||||
epsilon=1e-3,
|
||||
name='normal_bn_1_%s' % block_id)(
|
||||
h)
|
||||
|
||||
with backend.name_scope('block_1'):
|
||||
x1_1 = _separable_conv_block(
|
||||
h, filters, kernel_size=(5, 5), block_id='normal_left1_%s' % block_id)
|
||||
x1_2 = _separable_conv_block(
|
||||
p, filters, block_id='normal_right1_%s' % block_id)
|
||||
x1 = layers.add([x1_1, x1_2], name='normal_add_1_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_2'):
|
||||
x2_1 = _separable_conv_block(
|
||||
p, filters, (5, 5), block_id='normal_left2_%s' % block_id)
|
||||
x2_2 = _separable_conv_block(
|
||||
p, filters, (3, 3), block_id='normal_right2_%s' % block_id)
|
||||
x2 = layers.add([x2_1, x2_2], name='normal_add_2_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_3'):
|
||||
x3 = layers.AveragePooling2D((3, 3),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='normal_left3_%s' % (block_id))(
|
||||
h)
|
||||
x3 = layers.add([x3, p], name='normal_add_3_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_4'):
|
||||
x4_1 = layers.AveragePooling2D((3, 3),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='normal_left4_%s' % (block_id))(
|
||||
p)
|
||||
x4_2 = layers.AveragePooling2D((3, 3),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='normal_right4_%s' % (block_id))(
|
||||
p)
|
||||
x4 = layers.add([x4_1, x4_2], name='normal_add_4_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_5'):
|
||||
x5 = _separable_conv_block(
|
||||
h, filters, block_id='normal_left5_%s' % block_id)
|
||||
x5 = layers.add([x5, h], name='normal_add_5_%s' % block_id)
|
||||
|
||||
x = layers.concatenate([p, x1, x2, x3, x4, x5],
|
||||
axis=channel_dim,
|
||||
name='normal_concat_%s' % block_id)
|
||||
return x, ip
|
||||
|
||||
|
||||
def _reduction_a_cell(ip, p, filters, block_id=None):
|
||||
"""Adds a Reduction cell for NASNet-A (Fig. 4 in the paper).
|
||||
|
||||
Arguments:
|
||||
ip: Input tensor `x`
|
||||
p: Input tensor `p`
|
||||
filters: Number of output filters
|
||||
block_id: String block_id
|
||||
|
||||
Returns:
|
||||
A Keras tensor
|
||||
"""
|
||||
channel_dim = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
|
||||
with backend.name_scope('reduction_A_block_%s' % block_id):
|
||||
p = _adjust_block(p, ip, filters, block_id)
|
||||
|
||||
h = layers.Activation('relu')(ip)
|
||||
h = layers.Conv2D(
|
||||
filters, (1, 1),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='reduction_conv_1_%s' % block_id,
|
||||
use_bias=False,
|
||||
kernel_initializer='he_normal')(
|
||||
h)
|
||||
h = layers.BatchNormalization(
|
||||
axis=channel_dim,
|
||||
momentum=0.9997,
|
||||
epsilon=1e-3,
|
||||
name='reduction_bn_1_%s' % block_id)(
|
||||
h)
|
||||
h3 = layers.ZeroPadding2D(
|
||||
padding=imagenet_utils.correct_pad(h, 3),
|
||||
name='reduction_pad_1_%s' % block_id)(
|
||||
h)
|
||||
|
||||
with backend.name_scope('block_1'):
|
||||
x1_1 = _separable_conv_block(
|
||||
h,
|
||||
filters, (5, 5),
|
||||
strides=(2, 2),
|
||||
block_id='reduction_left1_%s' % block_id)
|
||||
x1_2 = _separable_conv_block(
|
||||
p,
|
||||
filters, (7, 7),
|
||||
strides=(2, 2),
|
||||
block_id='reduction_right1_%s' % block_id)
|
||||
x1 = layers.add([x1_1, x1_2], name='reduction_add_1_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_2'):
|
||||
x2_1 = layers.MaxPooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
name='reduction_left2_%s' % block_id)(
|
||||
h3)
|
||||
x2_2 = _separable_conv_block(
|
||||
p,
|
||||
filters, (7, 7),
|
||||
strides=(2, 2),
|
||||
block_id='reduction_right2_%s' % block_id)
|
||||
x2 = layers.add([x2_1, x2_2], name='reduction_add_2_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_3'):
|
||||
x3_1 = layers.AveragePooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
name='reduction_left3_%s' % block_id)(
|
||||
h3)
|
||||
x3_2 = _separable_conv_block(
|
||||
p,
|
||||
filters, (5, 5),
|
||||
strides=(2, 2),
|
||||
block_id='reduction_right3_%s' % block_id)
|
||||
x3 = layers.add([x3_1, x3_2], name='reduction_add3_%s' % block_id)
|
||||
|
||||
with backend.name_scope('block_4'):
|
||||
x4 = layers.AveragePooling2D((3, 3),
|
||||
strides=(1, 1),
|
||||
padding='same',
|
||||
name='reduction_left4_%s' % block_id)(
|
||||
x1)
|
||||
x4 = layers.add([x2, x4])
|
||||
|
||||
with backend.name_scope('block_5'):
|
||||
x5_1 = _separable_conv_block(
|
||||
x1, filters, (3, 3), block_id='reduction_left4_%s' % block_id)
|
||||
x5_2 = layers.MaxPooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='valid',
|
||||
name='reduction_right5_%s' % block_id)(
|
||||
h3)
|
||||
x5 = layers.add([x5_1, x5_2], name='reduction_add4_%s' % block_id)
|
||||
|
||||
x = layers.concatenate([x2, x3, x4, x5],
|
||||
axis=channel_dim,
|
||||
name='reduction_concat_%s' % block_id)
|
||||
return x, ip
|
||||
|
||||
|
||||
@keras_export('keras.applications.nasnet.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return nasnet.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(x, data_format=data_format, mode='tf')
|
||||
|
||||
|
||||
@keras_export('keras.applications.nasnet.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -13,49 +13,567 @@
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""ResNet models for Keras.
|
||||
"""
|
||||
"""ResNet models for Keras."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import resnet
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
BASE_WEIGHTS_PATH = (
|
||||
'https://storage.googleapis.com/tensorflow/keras-applications/resnet')
|
||||
WEIGHTS_HASHES = {
|
||||
'resnet50': ('2cb95161c43110f7111970584f804107',
|
||||
'4d473c1dd8becc155b73f8504c6f6626'),
|
||||
'resnet101': ('f1aeb4b969a6efcfb50fad2f0c20cfc5',
|
||||
'88cf7a10940856eca736dc7b7e228a21'),
|
||||
'resnet152': ('100835be76be38e30d865e96f2aaae62',
|
||||
'ee4c566cf9a93f14d82f913c2dc6dd0c'),
|
||||
'resnet50v2': ('3ef43a0b657b3be2300d5770ece849e0',
|
||||
'fac2f116257151a9d068a22e544a4917'),
|
||||
'resnet101v2': ('6343647c601c52e1368623803854d971',
|
||||
'c0ed64b8031c3730f411d2eb4eea35b5'),
|
||||
'resnet152v2': ('a49b44d1979771252814e80f8ec446f9',
|
||||
'ed17cf2e0169df9d443503ef94b23b33'),
|
||||
'resnext50': ('67a5b30d522ed92f75a1f16eef299d1a',
|
||||
'62527c363bdd9ec598bed41947b379fc'),
|
||||
'resnext101':
|
||||
('34fb605428fcc7aa4d62f44404c11509', '0f678c91647380debd923963594981b3')
|
||||
}
|
||||
|
||||
|
||||
def ResNet(stack_fn,
|
||||
preact,
|
||||
use_bias,
|
||||
model_name='resnet',
|
||||
include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the ResNet, ResNetV2, and ResNeXt architecture.
|
||||
|
||||
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:
|
||||
stack_fn: a function that returns output tensor for the
|
||||
stacked residual blocks.
|
||||
preact: whether to use pre-activation or not
|
||||
(True for ResNetV2, False for ResNet and ResNeXt).
|
||||
use_bias: whether to use biases for convolutional layers or not
|
||||
(True for ResNet and ResNetV2, False for ResNeXt).
|
||||
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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)` (with `channels_last` data format)
|
||||
or `(3, 224, 224)` (with `channels_first` data format).
|
||||
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.
|
||||
**kwargs: For backwards compatibility only.
|
||||
|
||||
Returns:
|
||||
A Keras model instance.
|
||||
|
||||
Raises:
|
||||
ValueError: in case of invalid argument for `weights`,
|
||||
or invalid input shape.
|
||||
"""
|
||||
if 'layers' in kwargs:
|
||||
global layers
|
||||
layers = kwargs.pop('layers')
|
||||
if kwargs:
|
||||
raise ValueError('Unknown argument(s): %s' % (kwargs,))
|
||||
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=224,
|
||||
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
|
||||
|
||||
x = layers.ZeroPadding2D(
|
||||
padding=((3, 3), (3, 3)), name='conv1_pad')(
|
||||
img_input)
|
||||
x = layers.Conv2D(64, 7, strides=2, use_bias=use_bias, name='conv1_conv')(x)
|
||||
|
||||
if not preact:
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name='conv1_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name='conv1_relu')(x)
|
||||
|
||||
x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)), name='pool1_pad')(x)
|
||||
x = layers.MaxPooling2D(3, strides=2, name='pool1_pool')(x)
|
||||
|
||||
x = stack_fn(x)
|
||||
|
||||
if preact:
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name='post_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name='post_relu')(x)
|
||||
|
||||
if include_top:
|
||||
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
|
||||
x = layers.Dense(classes, activation='softmax', 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') and (model_name in WEIGHTS_HASHES):
|
||||
if include_top:
|
||||
file_name = model_name + '_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
file_hash = WEIGHTS_HASHES[model_name][0]
|
||||
else:
|
||||
file_name = model_name + '_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
file_hash = WEIGHTS_HASHES[model_name][1]
|
||||
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 block1(x, filters, kernel_size=3, stride=1, conv_shortcut=True, name=None):
|
||||
"""A residual block.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: integer, filters of the bottleneck layer.
|
||||
kernel_size: default 3, kernel size of the bottleneck layer.
|
||||
stride: default 1, stride of the first layer.
|
||||
conv_shortcut: default True, use convolution shortcut if True,
|
||||
otherwise identity shortcut.
|
||||
name: string, block label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the residual block.
|
||||
"""
|
||||
bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
|
||||
|
||||
if conv_shortcut:
|
||||
shortcut = layers.Conv2D(
|
||||
4 * filters, 1, strides=stride, name=name + '_0_conv')(
|
||||
x)
|
||||
shortcut = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(
|
||||
shortcut)
|
||||
else:
|
||||
shortcut = x
|
||||
|
||||
x = layers.Conv2D(filters, 1, strides=stride, name=name + '_1_conv')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_1_relu')(x)
|
||||
|
||||
x = layers.Conv2D(
|
||||
filters, kernel_size, padding='SAME', name=name + '_2_conv')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_2_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_2_relu')(x)
|
||||
|
||||
x = layers.Conv2D(4 * filters, 1, name=name + '_3_conv')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_3_bn')(
|
||||
x)
|
||||
|
||||
x = layers.Add(name=name + '_add')([shortcut, x])
|
||||
x = layers.Activation('relu', name=name + '_out')(x)
|
||||
return x
|
||||
|
||||
|
||||
def stack1(x, filters, blocks, stride1=2, name=None):
|
||||
"""A set of stacked residual blocks.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: integer, filters of the bottleneck layer in a block.
|
||||
blocks: integer, blocks in the stacked blocks.
|
||||
stride1: default 2, stride of the first layer in the first block.
|
||||
name: string, stack label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the stacked blocks.
|
||||
"""
|
||||
x = block1(x, filters, stride=stride1, name=name + '_block1')
|
||||
for i in range(2, blocks + 1):
|
||||
x = block1(x, filters, conv_shortcut=False, name=name + '_block' + str(i))
|
||||
return x
|
||||
|
||||
|
||||
def block2(x, filters, kernel_size=3, stride=1, conv_shortcut=False, name=None):
|
||||
"""A residual block.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: integer, filters of the bottleneck layer.
|
||||
kernel_size: default 3, kernel size of the bottleneck layer.
|
||||
stride: default 1, stride of the first layer.
|
||||
conv_shortcut: default False, use convolution shortcut if True,
|
||||
otherwise identity shortcut.
|
||||
name: string, block label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the residual block.
|
||||
"""
|
||||
bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
|
||||
|
||||
preact = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_preact_bn')(
|
||||
x)
|
||||
preact = layers.Activation('relu', name=name + '_preact_relu')(preact)
|
||||
|
||||
if conv_shortcut:
|
||||
shortcut = layers.Conv2D(
|
||||
4 * filters, 1, strides=stride, name=name + '_0_conv')(
|
||||
preact)
|
||||
else:
|
||||
shortcut = layers.MaxPooling2D(1, strides=stride)(x) if stride > 1 else x
|
||||
|
||||
x = layers.Conv2D(
|
||||
filters, 1, strides=1, use_bias=False, name=name + '_1_conv')(
|
||||
preact)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_1_relu')(x)
|
||||
|
||||
x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)), name=name + '_2_pad')(x)
|
||||
x = layers.Conv2D(
|
||||
filters,
|
||||
kernel_size,
|
||||
strides=stride,
|
||||
use_bias=False,
|
||||
name=name + '_2_conv')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_2_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_2_relu')(x)
|
||||
|
||||
x = layers.Conv2D(4 * filters, 1, name=name + '_3_conv')(x)
|
||||
x = layers.Add(name=name + '_out')([shortcut, x])
|
||||
return x
|
||||
|
||||
|
||||
def stack2(x, filters, blocks, stride1=2, name=None):
|
||||
"""A set of stacked residual blocks.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: integer, filters of the bottleneck layer in a block.
|
||||
blocks: integer, blocks in the stacked blocks.
|
||||
stride1: default 2, stride of the first layer in the first block.
|
||||
name: string, stack label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the stacked blocks.
|
||||
"""
|
||||
x = block2(x, filters, conv_shortcut=True, name=name + '_block1')
|
||||
for i in range(2, blocks):
|
||||
x = block2(x, filters, name=name + '_block' + str(i))
|
||||
x = block2(x, filters, stride=stride1, name=name + '_block' + str(blocks))
|
||||
return x
|
||||
|
||||
|
||||
def block3(x,
|
||||
filters,
|
||||
kernel_size=3,
|
||||
stride=1,
|
||||
groups=32,
|
||||
conv_shortcut=True,
|
||||
name=None):
|
||||
"""A residual block.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: integer, filters of the bottleneck layer.
|
||||
kernel_size: default 3, kernel size of the bottleneck layer.
|
||||
stride: default 1, stride of the first layer.
|
||||
groups: default 32, group size for grouped convolution.
|
||||
conv_shortcut: default True, use convolution shortcut if True,
|
||||
otherwise identity shortcut.
|
||||
name: string, block label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the residual block.
|
||||
"""
|
||||
bn_axis = 3 if backend.image_data_format() == 'channels_last' else 1
|
||||
|
||||
if conv_shortcut:
|
||||
shortcut = layers.Conv2D(
|
||||
(64 // groups) * filters,
|
||||
1,
|
||||
strides=stride,
|
||||
use_bias=False,
|
||||
name=name + '_0_conv')(
|
||||
x)
|
||||
shortcut = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(
|
||||
shortcut)
|
||||
else:
|
||||
shortcut = x
|
||||
|
||||
x = layers.Conv2D(filters, 1, use_bias=False, name=name + '_1_conv')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_1_relu')(x)
|
||||
|
||||
c = filters // groups
|
||||
x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)), name=name + '_2_pad')(x)
|
||||
x = layers.DepthwiseConv2D(
|
||||
kernel_size,
|
||||
strides=stride,
|
||||
depth_multiplier=c,
|
||||
use_bias=False,
|
||||
name=name + '_2_conv')(
|
||||
x)
|
||||
x_shape = backend.int_shape(x)[1:-1]
|
||||
x = layers.Reshape(x_shape + (groups, c, c))(x)
|
||||
output_shape = x_shape + (groups,
|
||||
c) if backend.backend() == 'theano' else None
|
||||
x = layers.Lambda(
|
||||
lambda x: sum([x[:, :, :, :, i] for i in range(c)]),
|
||||
output_shape=output_shape,
|
||||
name=name + '_2_reduce')(
|
||||
x)
|
||||
x = layers.Reshape(x_shape + (filters,))(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_2_bn')(
|
||||
x)
|
||||
x = layers.Activation('relu', name=name + '_2_relu')(x)
|
||||
|
||||
x = layers.Conv2D(
|
||||
(64 // groups) * filters, 1, use_bias=False, name=name + '_3_conv')(
|
||||
x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=bn_axis, epsilon=1.001e-5, name=name + '_3_bn')(
|
||||
x)
|
||||
|
||||
x = layers.Add(name=name + '_add')([shortcut, x])
|
||||
x = layers.Activation('relu', name=name + '_out')(x)
|
||||
return x
|
||||
|
||||
|
||||
def stack3(x, filters, blocks, stride1=2, groups=32, name=None):
|
||||
"""A set of stacked residual blocks.
|
||||
|
||||
Arguments:
|
||||
x: input tensor.
|
||||
filters: integer, filters of the bottleneck layer in a block.
|
||||
blocks: integer, blocks in the stacked blocks.
|
||||
stride1: default 2, stride of the first layer in the first block.
|
||||
groups: default 32, group size for grouped convolution.
|
||||
name: string, stack label.
|
||||
|
||||
Returns:
|
||||
Output tensor for the stacked blocks.
|
||||
"""
|
||||
x = block3(x, filters, stride=stride1, groups=groups, name=name + '_block1')
|
||||
for i in range(2, blocks + 1):
|
||||
x = block3(
|
||||
x,
|
||||
filters,
|
||||
groups=groups,
|
||||
conv_shortcut=False,
|
||||
name=name + '_block' + str(i))
|
||||
return x
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet50.ResNet50',
|
||||
'keras.applications.resnet.ResNet50',
|
||||
'keras.applications.ResNet50')
|
||||
@keras_modules_injection
|
||||
def ResNet50(*args, **kwargs):
|
||||
return resnet.ResNet50(*args, **kwargs)
|
||||
def ResNet50(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the ResNet50 architecture."""
|
||||
|
||||
def stack_fn(x):
|
||||
x = stack1(x, 64, 3, stride1=1, name='conv2')
|
||||
x = stack1(x, 128, 4, name='conv3')
|
||||
x = stack1(x, 256, 6, name='conv4')
|
||||
return stack1(x, 512, 3, name='conv5')
|
||||
|
||||
return ResNet(stack_fn, False, True, 'resnet50', include_top, weights,
|
||||
input_tensor, input_shape, pooling, classes, **kwargs)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet.ResNet101',
|
||||
'keras.applications.ResNet101')
|
||||
@keras_modules_injection
|
||||
def ResNet101(*args, **kwargs):
|
||||
return resnet.ResNet101(*args, **kwargs)
|
||||
def ResNet101(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the ResNet101 architecture."""
|
||||
|
||||
def stack_fn(x):
|
||||
x = stack1(x, 64, 3, stride1=1, name='conv2')
|
||||
x = stack1(x, 128, 4, name='conv3')
|
||||
x = stack1(x, 256, 23, name='conv4')
|
||||
return stack1(x, 512, 3, name='conv5')
|
||||
|
||||
return ResNet(stack_fn, False, True, 'resnet101', include_top, weights,
|
||||
input_tensor, input_shape, pooling, classes, **kwargs)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet.ResNet152',
|
||||
'keras.applications.ResNet152')
|
||||
@keras_modules_injection
|
||||
def ResNet152(*args, **kwargs):
|
||||
return resnet.ResNet152(*args, **kwargs)
|
||||
def ResNet152(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000,
|
||||
**kwargs):
|
||||
"""Instantiates the ResNet152 architecture."""
|
||||
|
||||
def stack_fn(x):
|
||||
x = stack1(x, 64, 3, stride1=1, name='conv2')
|
||||
x = stack1(x, 128, 8, name='conv3')
|
||||
x = stack1(x, 256, 36, name='conv4')
|
||||
return stack1(x, 512, 3, name='conv5')
|
||||
|
||||
@keras_export('keras.applications.resnet50.decode_predictions',
|
||||
'keras.applications.resnet.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return resnet.decode_predictions(*args, **kwargs)
|
||||
return ResNet(stack_fn, False, True, 'resnet152', include_top, weights,
|
||||
input_tensor, input_shape, pooling, classes, **kwargs)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet50.preprocess_input',
|
||||
'keras.applications.resnet.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return resnet.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(
|
||||
x, data_format=data_format, mode='caffe')
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet50.decode_predictions',
|
||||
'keras.applications.resnet.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
||||
|
||||
DOC = """
|
||||
|
||||
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:
|
||||
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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)` (with `'channels_last'` data format)
|
||||
or `(3, 224, 224)` (with `'channels_first'` data format).
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(200, 200, 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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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.
|
||||
"""
|
||||
|
||||
setattr(ResNet50, '__doc__', ResNet50.__doc__ + DOC)
|
||||
setattr(ResNet101, '__doc__', ResNet101.__doc__ + DOC)
|
||||
setattr(ResNet152, '__doc__', ResNet152.__doc__ + DOC)
|
||||
|
@ -13,46 +13,121 @@
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""ResNet v2 models for Keras.
|
||||
"""
|
||||
"""ResNet v2 models for Keras."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import resnet_v2
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.applications import resnet
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet_v2.ResNet50V2',
|
||||
'keras.applications.ResNet50V2')
|
||||
@keras_modules_injection
|
||||
def ResNet50V2(*args, **kwargs):
|
||||
return resnet_v2.ResNet50V2(*args, **kwargs)
|
||||
def ResNet50V2(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the ResNet50V2 architecture."""
|
||||
def stack_fn(x):
|
||||
x = resnet.stack2(x, 64, 3, name='conv2')
|
||||
x = resnet.stack2(x, 128, 4, name='conv3')
|
||||
x = resnet.stack2(x, 256, 6, name='conv4')
|
||||
return resnet.stack2(x, 512, 3, stride1=1, name='conv5')
|
||||
return resnet.ResNet(stack_fn, True, True, 'resnet50v2', include_top, weights,
|
||||
input_tensor, input_shape, pooling, classes)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet_v2.ResNet101V2',
|
||||
'keras.applications.ResNet101V2')
|
||||
@keras_modules_injection
|
||||
def ResNet101V2(*args, **kwargs):
|
||||
return resnet_v2.ResNet101V2(*args, **kwargs)
|
||||
def ResNet101V2(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the ResNet101V2 architecture."""
|
||||
def stack_fn(x):
|
||||
x = resnet.stack2(x, 64, 3, name='conv2')
|
||||
x = resnet.stack2(x, 128, 4, name='conv3')
|
||||
x = resnet.stack2(x, 256, 23, name='conv4')
|
||||
return resnet.stack2(x, 512, 3, stride1=1, name='conv5')
|
||||
return resnet.ResNet(stack_fn, True, True, 'resnet101v2', include_top,
|
||||
weights, input_tensor, input_shape, pooling, classes)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet_v2.ResNet152V2',
|
||||
'keras.applications.ResNet152V2')
|
||||
@keras_modules_injection
|
||||
def ResNet152V2(*args, **kwargs):
|
||||
return resnet_v2.ResNet152V2(*args, **kwargs)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet_v2.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return resnet_v2.decode_predictions(*args, **kwargs)
|
||||
def ResNet152V2(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the ResNet152V2 architecture."""
|
||||
def stack_fn(x):
|
||||
x = resnet.stack2(x, 64, 3, name='conv2')
|
||||
x = resnet.stack2(x, 128, 8, name='conv3')
|
||||
x = resnet.stack2(x, 256, 36, name='conv4')
|
||||
return resnet.stack2(x, 512, 3, stride1=1, name='conv5')
|
||||
return resnet.ResNet(stack_fn, True, True, 'resnet152v2', include_top,
|
||||
weights, input_tensor, input_shape, pooling, classes)
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet_v2.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return resnet_v2.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(
|
||||
x, data_format=data_format, mode='caffe')
|
||||
|
||||
|
||||
@keras_export('keras.applications.resnet_v2.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
||||
|
||||
DOC = """
|
||||
|
||||
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:
|
||||
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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)` (with `'channels_last'` data format)
|
||||
or `(3, 224, 224)` (with `'channels_first'` data format).
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(200, 200, 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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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.
|
||||
"""
|
||||
|
||||
setattr(ResNet50V2, '__doc__', ResNet50V2.__doc__ + DOC)
|
||||
setattr(ResNet101V2, '__doc__', ResNet101V2.__doc__ + DOC)
|
||||
setattr(ResNet152V2, '__doc__', ResNet152V2.__doc__ + DOC)
|
||||
|
@ -13,32 +13,196 @@
|
||||
# limitations under the License.
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""VGG16 model for Keras.
|
||||
"""
|
||||
"""VGG16 model for Keras."""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import vgg16
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg16.VGG16',
|
||||
'keras.applications.VGG16')
|
||||
@keras_modules_injection
|
||||
def VGG16(*args, **kwargs):
|
||||
return vgg16.VGG16(*args, **kwargs)
|
||||
WEIGHTS_PATH = ('https://storage.googleapis.com/tensorflow/keras-applications/'
|
||||
'vgg16/vgg16_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
WEIGHTS_PATH_NO_TOP = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/vgg16/'
|
||||
'vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg16.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return vgg16.decode_predictions(*args, **kwargs)
|
||||
@keras_export('keras.applications.vgg16.VGG16', 'keras.applications.VGG16')
|
||||
def VGG16(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the VGG16 architecture.
|
||||
|
||||
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:
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers 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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)`
|
||||
(with `channels_last` data format)
|
||||
or `(3, 224, 224)` (with `channels_first` data format).
|
||||
It should have exactly 3 input channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(200, 200, 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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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 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=224,
|
||||
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
|
||||
# Block 1
|
||||
x = layers.Conv2D(
|
||||
64, (3, 3), activation='relu', padding='same', name='block1_conv1')(
|
||||
img_input)
|
||||
x = layers.Conv2D(
|
||||
64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
|
||||
|
||||
# Block 2
|
||||
x = layers.Conv2D(
|
||||
128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
|
||||
|
||||
# Block 3
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
|
||||
|
||||
# Block 4
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
|
||||
|
||||
# Block 5
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = layers.Flatten(name='flatten')(x)
|
||||
x = layers.Dense(4096, activation='relu', name='fc1')(x)
|
||||
x = layers.Dense(4096, activation='relu', name='fc2')(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='predictions')(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
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='vgg16')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
weights_path = data_utils.get_file(
|
||||
'vgg16_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='64373286793e3c8b2b4e3219cbf3544b')
|
||||
else:
|
||||
weights_path = data_utils.get_file(
|
||||
'vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='6d6bbae143d832006294945121d1f1fc')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg16.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return vgg16.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(
|
||||
x, data_format=data_format, mode='caffe')
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg16.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -14,31 +14,206 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""VGG19 model for Keras.
|
||||
|
||||
Reference:
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](
|
||||
https://arxiv.org/abs/1409.1556) (ICLR 2015)
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import vgg19
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg19.VGG19',
|
||||
'keras.applications.VGG19')
|
||||
@keras_modules_injection
|
||||
def VGG19(*args, **kwargs):
|
||||
return vgg19.VGG19(*args, **kwargs)
|
||||
WEIGHTS_PATH = ('https://storage.googleapis.com/tensorflow/keras-applications/'
|
||||
'vgg19/vgg19_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
WEIGHTS_PATH_NO_TOP = ('https://storage.googleapis.com/tensorflow/'
|
||||
'keras-applications/vgg19/'
|
||||
'vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg19.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return vgg19.decode_predictions(*args, **kwargs)
|
||||
@keras_export('keras.applications.vgg19.VGG19', 'keras.applications.VGG19')
|
||||
def VGG19(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the VGG19 architecture.
|
||||
|
||||
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:
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers 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 (otherwise the input shape
|
||||
has to be `(224, 224, 3)`
|
||||
(with `channels_last` data format)
|
||||
or `(3, 224, 224)` (with `channels_first` data format).
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 32.
|
||||
E.g. `(200, 200, 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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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 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=224,
|
||||
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
|
||||
# Block 1
|
||||
x = layers.Conv2D(
|
||||
64, (3, 3), activation='relu', padding='same', name='block1_conv1')(
|
||||
img_input)
|
||||
x = layers.Conv2D(
|
||||
64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
|
||||
|
||||
# Block 2
|
||||
x = layers.Conv2D(
|
||||
128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
|
||||
|
||||
# Block 3
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
|
||||
x = layers.Conv2D(
|
||||
256, (3, 3), activation='relu', padding='same', name='block3_conv4')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
|
||||
|
||||
# Block 4
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block4_conv4')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
|
||||
|
||||
# Block 5
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
|
||||
x = layers.Conv2D(
|
||||
512, (3, 3), activation='relu', padding='same', name='block5_conv4')(x)
|
||||
x = layers.MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = layers.Flatten(name='flatten')(x)
|
||||
x = layers.Dense(4096, activation='relu', name='fc1')(x)
|
||||
x = layers.Dense(4096, activation='relu', name='fc2')(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='predictions')(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
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='vgg19')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
weights_path = data_utils.get_file(
|
||||
'vgg19_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='cbe5617147190e668d6c5d5026f83318')
|
||||
else:
|
||||
weights_path = data_utils.get_file(
|
||||
'vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='253f8cb515780f3b799900260a226db6')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg19.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return vgg19.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(
|
||||
x, data_format=data_format, mode='caffe')
|
||||
|
||||
|
||||
@keras_export('keras.applications.vgg19.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -14,31 +14,295 @@
|
||||
# ==============================================================================
|
||||
# pylint: disable=invalid-name
|
||||
"""Xception V1 model for Keras.
|
||||
|
||||
On ImageNet, this model gets to a top-1 validation accuracy of 0.790
|
||||
and a top-5 validation accuracy of 0.945.
|
||||
|
||||
Reference paper:
|
||||
- [Xception: Deep Learning with Depthwise Separable Convolutions](
|
||||
https://arxiv.org/abs/1610.02357) (CVPR 2017)
|
||||
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
from keras_applications import xception
|
||||
import os
|
||||
|
||||
from tensorflow.python.keras.applications import keras_modules_injection
|
||||
from tensorflow.python.keras import backend
|
||||
from tensorflow.python.keras import layers
|
||||
from tensorflow.python.keras.applications import imagenet_utils
|
||||
from tensorflow.python.keras.engine import training
|
||||
from tensorflow.python.keras.utils import data_utils
|
||||
from tensorflow.python.keras.utils import layer_utils
|
||||
from tensorflow.python.util.tf_export import keras_export
|
||||
|
||||
|
||||
TF_WEIGHTS_PATH = ('https://github.com/fchollet/deep-learning-models/'
|
||||
'releases/download/v0.4/'
|
||||
'xception_weights_tf_dim_ordering_tf_kernels.h5')
|
||||
TF_WEIGHTS_PATH_NO_TOP = (
|
||||
'https://github.com/fchollet/deep-learning-models/'
|
||||
'releases/download/v0.4/'
|
||||
'xception_weights_tf_dim_ordering_tf_kernels_notop.h5')
|
||||
|
||||
|
||||
@keras_export('keras.applications.xception.Xception',
|
||||
'keras.applications.Xception')
|
||||
@keras_modules_injection
|
||||
def Xception(*args, **kwargs):
|
||||
return xception.Xception(*args, **kwargs)
|
||||
def Xception(include_top=True,
|
||||
weights='imagenet',
|
||||
input_tensor=None,
|
||||
input_shape=None,
|
||||
pooling=None,
|
||||
classes=1000):
|
||||
"""Instantiates the Xception architecture.
|
||||
|
||||
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`.
|
||||
Note that the default input image size for this model is 299x299.
|
||||
|
||||
@keras_export('keras.applications.xception.decode_predictions')
|
||||
@keras_modules_injection
|
||||
def decode_predictions(*args, **kwargs):
|
||||
return xception.decode_predictions(*args, **kwargs)
|
||||
Arguments:
|
||||
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 (otherwise the input shape
|
||||
has to be `(299, 299, 3)`.
|
||||
It should have exactly 3 inputs channels,
|
||||
and width and height should be no smaller than 71.
|
||||
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 block.
|
||||
- `avg` means that global average pooling
|
||||
will be applied to the output of the
|
||||
last convolutional block, 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 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=299,
|
||||
min_size=71,
|
||||
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
|
||||
|
||||
channel_axis = 1 if backend.image_data_format() == 'channels_first' else -1
|
||||
|
||||
x = layers.Conv2D(
|
||||
32, (3, 3),
|
||||
strides=(2, 2),
|
||||
use_bias=False,
|
||||
name='block1_conv1')(img_input)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block1_conv1_bn')(x)
|
||||
x = layers.Activation('relu', name='block1_conv1_act')(x)
|
||||
x = layers.Conv2D(64, (3, 3), use_bias=False, name='block1_conv2')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block1_conv2_bn')(x)
|
||||
x = layers.Activation('relu', name='block1_conv2_act')(x)
|
||||
|
||||
residual = layers.Conv2D(
|
||||
128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
|
||||
residual = layers.BatchNormalization(axis=channel_axis)(residual)
|
||||
|
||||
x = layers.SeparableConv2D(
|
||||
128, (3, 3), padding='same', use_bias=False, name='block2_sepconv1')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block2_sepconv1_bn')(x)
|
||||
x = layers.Activation('relu', name='block2_sepconv2_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
128, (3, 3), padding='same', use_bias=False, name='block2_sepconv2')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block2_sepconv2_bn')(x)
|
||||
|
||||
x = layers.MaxPooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='same',
|
||||
name='block2_pool')(x)
|
||||
x = layers.add([x, residual])
|
||||
|
||||
residual = layers.Conv2D(
|
||||
256, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
|
||||
residual = layers.BatchNormalization(axis=channel_axis)(residual)
|
||||
|
||||
x = layers.Activation('relu', name='block3_sepconv1_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
256, (3, 3), padding='same', use_bias=False, name='block3_sepconv1')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block3_sepconv1_bn')(x)
|
||||
x = layers.Activation('relu', name='block3_sepconv2_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
256, (3, 3), padding='same', use_bias=False, name='block3_sepconv2')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block3_sepconv2_bn')(x)
|
||||
|
||||
x = layers.MaxPooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='same',
|
||||
name='block3_pool')(x)
|
||||
x = layers.add([x, residual])
|
||||
|
||||
residual = layers.Conv2D(
|
||||
728, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
|
||||
residual = layers.BatchNormalization(axis=channel_axis)(residual)
|
||||
|
||||
x = layers.Activation('relu', name='block4_sepconv1_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
728, (3, 3), padding='same', use_bias=False, name='block4_sepconv1')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block4_sepconv1_bn')(x)
|
||||
x = layers.Activation('relu', name='block4_sepconv2_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
728, (3, 3), padding='same', use_bias=False, name='block4_sepconv2')(x)
|
||||
x = layers.BatchNormalization(axis=channel_axis, name='block4_sepconv2_bn')(x)
|
||||
|
||||
x = layers.MaxPooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='same',
|
||||
name='block4_pool')(x)
|
||||
x = layers.add([x, residual])
|
||||
|
||||
for i in range(8):
|
||||
residual = x
|
||||
prefix = 'block' + str(i + 5)
|
||||
|
||||
x = layers.Activation('relu', name=prefix + '_sepconv1_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
728, (3, 3),
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
name=prefix + '_sepconv1')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name=prefix + '_sepconv1_bn')(x)
|
||||
x = layers.Activation('relu', name=prefix + '_sepconv2_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
728, (3, 3),
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
name=prefix + '_sepconv2')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name=prefix + '_sepconv2_bn')(x)
|
||||
x = layers.Activation('relu', name=prefix + '_sepconv3_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
728, (3, 3),
|
||||
padding='same',
|
||||
use_bias=False,
|
||||
name=prefix + '_sepconv3')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name=prefix + '_sepconv3_bn')(x)
|
||||
|
||||
x = layers.add([x, residual])
|
||||
|
||||
residual = layers.Conv2D(
|
||||
1024, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
|
||||
residual = layers.BatchNormalization(axis=channel_axis)(residual)
|
||||
|
||||
x = layers.Activation('relu', name='block13_sepconv1_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
728, (3, 3), padding='same', use_bias=False, name='block13_sepconv1')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name='block13_sepconv1_bn')(x)
|
||||
x = layers.Activation('relu', name='block13_sepconv2_act')(x)
|
||||
x = layers.SeparableConv2D(
|
||||
1024, (3, 3), padding='same', use_bias=False, name='block13_sepconv2')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name='block13_sepconv2_bn')(x)
|
||||
|
||||
x = layers.MaxPooling2D((3, 3),
|
||||
strides=(2, 2),
|
||||
padding='same',
|
||||
name='block13_pool')(x)
|
||||
x = layers.add([x, residual])
|
||||
|
||||
x = layers.SeparableConv2D(
|
||||
1536, (3, 3), padding='same', use_bias=False, name='block14_sepconv1')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name='block14_sepconv1_bn')(x)
|
||||
x = layers.Activation('relu', name='block14_sepconv1_act')(x)
|
||||
|
||||
x = layers.SeparableConv2D(
|
||||
2048, (3, 3), padding='same', use_bias=False, name='block14_sepconv2')(x)
|
||||
x = layers.BatchNormalization(
|
||||
axis=channel_axis, name='block14_sepconv2_bn')(x)
|
||||
x = layers.Activation('relu', name='block14_sepconv2_act')(x)
|
||||
|
||||
if include_top:
|
||||
x = layers.GlobalAveragePooling2D(name='avg_pool')(x)
|
||||
x = layers.Dense(classes, activation='softmax', name='predictions')(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
|
||||
# Create model.
|
||||
model = training.Model(inputs, x, name='xception')
|
||||
|
||||
# Load weights.
|
||||
if weights == 'imagenet':
|
||||
if include_top:
|
||||
weights_path = data_utils.get_file(
|
||||
'xception_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
file_hash='0a58e3b7378bc2990ea3b43d5981f1f6')
|
||||
else:
|
||||
weights_path = data_utils.get_file(
|
||||
'xception_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
file_hash='b0042744bf5b25fce3cb969f33bebb97')
|
||||
model.load_weights(weights_path)
|
||||
elif weights is not None:
|
||||
model.load_weights(weights)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
@keras_export('keras.applications.xception.preprocess_input')
|
||||
@keras_modules_injection
|
||||
def preprocess_input(*args, **kwargs):
|
||||
return xception.preprocess_input(*args, **kwargs)
|
||||
def preprocess_input(x, data_format=None):
|
||||
return imagenet_utils.preprocess_input(x, data_format=data_format, mode='tf')
|
||||
|
||||
|
||||
@keras_export('keras.applications.xception.decode_predictions')
|
||||
def decode_predictions(preds, top=5):
|
||||
return imagenet_utils.decode_predictions(preds, top=top)
|
||||
|
@ -28,7 +28,6 @@ RUN pip install --upgrade astor
|
||||
RUN pip install --upgrade gast
|
||||
RUN pip install --upgrade numpy
|
||||
RUN pip install --upgrade termcolor
|
||||
RUN pip install --upgrade keras_applications
|
||||
RUN pip install --upgrade keras_preprocessing
|
||||
|
||||
# Install golang
|
||||
|
@ -99,8 +99,6 @@ pip2 install --upgrade termcolor
|
||||
pip3 install --upgrade termcolor
|
||||
|
||||
# Keras
|
||||
pip2 install keras_applications==1.0.8 --no-deps
|
||||
pip3 install keras_applications==1.0.8 --no-deps
|
||||
pip2 install keras_preprocessing==1.0.5 --no-deps
|
||||
pip3 install keras_preprocessing==1.0.5 --no-deps
|
||||
pip2 install --upgrade h5py==2.8.0
|
||||
|
@ -127,8 +127,6 @@ pip2 install --upgrade termcolor
|
||||
pip3 install --upgrade termcolor
|
||||
|
||||
# Keras
|
||||
pip2 install keras_applications==1.0.8 --no-deps
|
||||
pip3 install keras_applications==1.0.8 --no-deps
|
||||
pip2 install keras_preprocessing==1.1.0 --no-deps
|
||||
pip3 install keras_preprocessing==1.1.0 --no-deps
|
||||
pip2 install --upgrade h5py==2.8.0
|
||||
|
@ -86,7 +86,6 @@ pip3.5 install --upgrade gast
|
||||
pip3.5 install --upgrade termcolor
|
||||
|
||||
# Keras
|
||||
pip3.5 install keras_applications==1.0.8
|
||||
pip3.5 install keras_preprocessing==1.0.5
|
||||
pip3.5 install --upgrade h5py==2.8.0
|
||||
|
||||
|
@ -104,7 +104,6 @@ pip3 install --upgrade termcolor
|
||||
pip3 install --upgrade h5py==2.8.0
|
||||
|
||||
# Keras
|
||||
pip3 install keras_applications==1.0.8
|
||||
pip3 install keras_preprocessing==1.0.5
|
||||
|
||||
# Estimator
|
||||
|
@ -129,7 +129,6 @@ function install_pip_deps {
|
||||
|
||||
# LINT.IfChange(ubuntu_pip_installations)
|
||||
# TODO(aselle): Change all these to be --user instead of sudo.
|
||||
${SUDO_CMD} ${PIP_CMD} install keras_applications==1.0.8 --no-deps
|
||||
${SUDO_CMD} ${PIP_CMD} install keras_preprocessing==1.1.0 --no-deps
|
||||
${SUDO_CMD} ${PIP_CMD} install gast==0.2.2
|
||||
${SUDO_CMD} ${PIP_CMD} install h5py==2.8.0
|
||||
@ -161,7 +160,6 @@ function install_ubuntu_16_pip_deps {
|
||||
|
||||
# LINT.IfChange(ubuntu_16_pip_installations)
|
||||
"${PIP_CMD}" install --user --upgrade attrs
|
||||
"${PIP_CMD}" install keras_applications==1.0.8 --no-deps --user
|
||||
"${PIP_CMD}" install keras_preprocessing==1.1.0 --no-deps --user
|
||||
"${PIP_CMD}" install numpy==1.14.5 --user
|
||||
"${PIP_CMD}" install --user --upgrade "future>=0.17.1"
|
||||
@ -205,7 +203,6 @@ function install_macos_pip_deps {
|
||||
|
||||
# TODO(aselle): Change all these to be --user instead of sudo.
|
||||
${SUDO_CMD} ${PIP_CMD} install --upgrade setuptools==39.1.0
|
||||
${SUDO_CMD} ${PIP_CMD} install keras_applications==1.0.8 --no-deps
|
||||
${SUDO_CMD} ${PIP_CMD} install keras_preprocessing==1.1.0 --no-deps
|
||||
${SUDO_CMD} ${PIP_CMD} install --upgrade mock portpicker scipy grpcio
|
||||
${SUDO_CMD} ${PIP_CMD} install six==1.12.0
|
||||
|
@ -34,7 +34,6 @@ SET PATH=%PATH%;C:\%PYTHON_DIRECTORY%
|
||||
%PIP_EXE% install opt_einsum --upgrade
|
||||
%PIP_EXE% install pandas --upgrade --no-deps
|
||||
%PIP_EXE% install protobuf --upgrade --no-deps
|
||||
%PIP_EXE% install keras_applications==1.0.8 --upgrade --no-deps
|
||||
%PIP_EXE% install keras_preprocessing==1.1.0 --upgrade --no-deps
|
||||
%PIP_EXE% install wrapt --upgrade --no-deps
|
||||
|
||||
|
@ -86,7 +86,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -86,7 +86,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -119,7 +119,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -119,7 +119,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -84,7 +84,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -84,7 +84,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -85,7 +85,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -85,7 +85,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -118,7 +118,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -118,7 +118,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -11,7 +11,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -10,7 +10,6 @@ RUN apt-get update && apt-get install -y \
|
||||
RUN ${PIP} --no-cache-dir install \
|
||||
Pillow \
|
||||
h5py \
|
||||
keras_applications \
|
||||
keras_preprocessing \
|
||||
matplotlib \
|
||||
mock \
|
||||
|
@ -141,7 +141,6 @@ filegroup(
|
||||
"@highwayhash//:LICENSE",
|
||||
"@hwloc//:COPYING",
|
||||
"@icu//:icu4c/LICENSE",
|
||||
"@keras_applications_archive//:LICENSE",
|
||||
"@kissfft//:COPYING",
|
||||
"@libjpeg_turbo//:LICENSE.md",
|
||||
"@lmdb//:LICENSE",
|
||||
|
@ -56,7 +56,6 @@ REQUIRED_PACKAGES = [
|
||||
'enum34 >= 1.1.6;python_version<"3.4"',
|
||||
'gast == 0.2.2',
|
||||
'google_pasta >= 0.1.8',
|
||||
'keras_applications >= 1.0.8',
|
||||
'keras_preprocessing >= 1.1.0',
|
||||
'numpy >= 1.16.0, < 2.0',
|
||||
'opt_einsum >= 2.3.2',
|
||||
|
@ -34,7 +34,6 @@ load("//third_party/jpeg:workspace.bzl", jpeg = "repo")
|
||||
load("//third_party/nasm:workspace.bzl", nasm = "repo")
|
||||
load("//third_party/opencl_headers:workspace.bzl", opencl_headers = "repo")
|
||||
load("//third_party/kissfft:workspace.bzl", kissfft = "repo")
|
||||
load("//third_party/keras_applications_archive:workspace.bzl", keras_applications = "repo")
|
||||
load("//third_party/pasta:workspace.bzl", pasta = "repo")
|
||||
load("//third_party/psimd:workspace.bzl", psimd = "repo")
|
||||
load("//third_party/pthreadpool:workspace.bzl", pthreadpool = "repo")
|
||||
@ -50,7 +49,6 @@ def initialize_third_party():
|
||||
highwayhash()
|
||||
hwloc()
|
||||
icu()
|
||||
keras_applications()
|
||||
kissfft()
|
||||
jpeg()
|
||||
nasm()
|
||||
|
1
third_party/keras_applications_archive/BUILD
vendored
1
third_party/keras_applications_archive/BUILD
vendored
@ -1 +0,0 @@
|
||||
# This empty BUILD file is required to make Bazel treat this directory as a package.
|
@ -1,35 +0,0 @@
|
||||
# Description: Keras Applications: set of pre-trained deep learning models.
|
||||
|
||||
package(
|
||||
default_visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
exports_files(["LICENSE"])
|
||||
|
||||
py_library(
|
||||
name = "keras_applications",
|
||||
srcs = [
|
||||
"keras_applications/__init__.py",
|
||||
"keras_applications/densenet.py",
|
||||
"keras_applications/imagenet_utils.py",
|
||||
"keras_applications/inception_resnet_v2.py",
|
||||
"keras_applications/inception_v3.py",
|
||||
"keras_applications/mobilenet.py",
|
||||
"keras_applications/mobilenet_v2.py",
|
||||
"keras_applications/nasnet.py",
|
||||
"keras_applications/resnet.py",
|
||||
"keras_applications/resnet50.py",
|
||||
"keras_applications/resnet_common.py",
|
||||
"keras_applications/resnet_v2.py",
|
||||
"keras_applications/resnext.py",
|
||||
"keras_applications/vgg16.py",
|
||||
"keras_applications/vgg19.py",
|
||||
"keras_applications/xception.py",
|
||||
],
|
||||
deps = [
|
||||
"@org_tensorflow//third_party/py/numpy",
|
||||
"@six_archive//:six",
|
||||
],
|
||||
)
|
@ -1,13 +0,0 @@
|
||||
# Description: Keras Applications: set of pre-trained deep learning models.
|
||||
|
||||
licenses(["notice"]) # MIT
|
||||
|
||||
filegroup(
|
||||
name = "LICENSE",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
||||
|
||||
py_library(
|
||||
name = "keras_applications",
|
||||
visibility = ["//visibility:public"],
|
||||
)
|
@ -1,16 +0,0 @@
|
||||
"""Loads Keras-applications python package."""
|
||||
|
||||
load("//third_party:repo.bzl", "third_party_http_archive")
|
||||
|
||||
def repo():
|
||||
third_party_http_archive(
|
||||
name = "keras_applications_archive",
|
||||
strip_prefix = "keras-applications-1.0.8",
|
||||
sha256 = "7c37f9e9ef93efac9b4956301cb21ce46c474ce9da41fac9a46753bab6823dfc",
|
||||
urls = [
|
||||
"https://storage.googleapis.com/mirror.tensorflow.org/github.com/keras-team/keras-applications/archive/1.0.8.tar.gz",
|
||||
"https://github.com/keras-team/keras-applications/archive/1.0.8.tar.gz",
|
||||
],
|
||||
build_file = "//third_party/keras_applications_archive:BUILD.bazel",
|
||||
system_build_file = "//third_party/keras_applications_archive:BUILD.system",
|
||||
)
|
1
third_party/systemlibs/syslibs_configure.bzl
vendored
1
third_party/systemlibs/syslibs_configure.bzl
vendored
@ -29,7 +29,6 @@ VALID_LIBS = [
|
||||
"icu",
|
||||
"jpeg",
|
||||
"jsoncpp_git",
|
||||
"keras_applications_archive",
|
||||
"lmdb",
|
||||
"nasm",
|
||||
"nsync",
|
||||
|
Loading…
Reference in New Issue
Block a user