aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorGravatar Francois Chollet <fchollet@google.com>2018-01-25 19:05:28 -0800
committerGravatar TensorFlower Gardener <gardener@tensorflow.org>2018-01-25 19:09:15 -0800
commit0bd0bf02aa15a3238b77053a2f0ad6fe373c7d1c (patch)
tree9419d2e785bdff82110b5bc04326b8c8ae6a5022
parentc2ea7a710c5ec478fcc0150ec0117250c54e601e (diff)
Update tf.keras to the Keras 2.1.3 API.
PiperOrigin-RevId: 183328052
-rw-r--r--tensorflow/contrib/cmake/python_modules.txt2
-rwxr-xr-xtensorflow/python/keras/BUILD32
-rw-r--r--tensorflow/python/keras/_impl/keras/__init__.py2
-rw-r--r--tensorflow/python/keras/_impl/keras/activations.py10
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/__init__.py5
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/densenet.py346
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/densenet_test.py101
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/imagenet_utils.py156
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/inception_resnet_v2.py19
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/inception_v3.py21
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/mobilenet.py70
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/nasnet.py783
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/nasnet_test.py76
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/resnet50.py51
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/vgg16.py60
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/vgg19.py73
-rw-r--r--tensorflow/python/keras/_impl/keras/applications/xception.py90
-rw-r--r--tensorflow/python/keras/_impl/keras/backend.py289
-rw-r--r--tensorflow/python/keras/_impl/keras/backend_test.py12
-rw-r--r--tensorflow/python/keras/_impl/keras/callbacks.py132
-rw-r--r--tensorflow/python/keras/_impl/keras/constraints.py22
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/boston_housing.py10
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/cifar.py3
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/cifar10.py4
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/cifar100.py6
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/fashion_mnist.py7
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/imdb.py63
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/mnist.py10
-rw-r--r--tensorflow/python/keras/_impl/keras/datasets/reuters.py58
-rw-r--r--tensorflow/python/keras/_impl/keras/engine/topology.py61
-rw-r--r--tensorflow/python/keras/_impl/keras/engine/training.py588
-rw-r--r--tensorflow/python/keras/_impl/keras/engine/training_test.py87
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/advanced_activations.py68
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/advanced_activations_test.py6
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/convolutional.py139
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/convolutional_recurrent.py44
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/convolutional_test.py66
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/embeddings.py26
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/local.py110
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/merge.py110
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/noise.py49
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/recurrent.py650
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/recurrent_test.py99
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/wrappers.py58
-rw-r--r--tensorflow/python/keras/_impl/keras/layers/wrappers_test.py125
-rw-r--r--tensorflow/python/keras/_impl/keras/losses.py20
-rw-r--r--tensorflow/python/keras/_impl/keras/metrics.py9
-rw-r--r--tensorflow/python/keras/_impl/keras/models.py4
-rw-r--r--tensorflow/python/keras/_impl/keras/models_test.py29
-rw-r--r--tensorflow/python/keras/_impl/keras/optimizers.py125
-rw-r--r--tensorflow/python/keras/_impl/keras/optimizers_test.py1
-rw-r--r--tensorflow/python/keras/_impl/keras/preprocessing/image.py164
-rw-r--r--tensorflow/python/keras/_impl/keras/preprocessing/sequence.py25
-rw-r--r--tensorflow/python/keras/_impl/keras/preprocessing/text.py51
-rw-r--r--tensorflow/python/keras/_impl/keras/preprocessing/text_test.py16
-rw-r--r--tensorflow/python/keras/_impl/keras/regularizers.py2
-rw-r--r--tensorflow/python/keras/_impl/keras/utils/data_utils.py213
-rw-r--r--tensorflow/python/keras/_impl/keras/utils/generic_utils.py6
-rw-r--r--tensorflow/python/keras/_impl/keras/utils/io_utils.py18
-rw-r--r--tensorflow/python/keras/_impl/keras/utils/layer_utils.py35
-rw-r--r--tensorflow/python/keras/_impl/keras/utils/np_utils.py5
-rw-r--r--tensorflow/python/keras/_impl/keras/utils/vis_utils.py35
-rw-r--r--tensorflow/python/keras/_impl/keras/wrappers/scikit_learn.py71
-rw-r--r--tensorflow/python/keras/applications/__init__.py7
-rw-r--r--tensorflow/python/keras/applications/densenet/__init__.py29
-rw-r--r--tensorflow/python/keras/applications/nasnet/__init__.py28
-rw-r--r--tensorflow/python/keras/layers/__init__.py3
-rw-r--r--tensorflow/python/layers/base.py21
-rw-r--r--tensorflow/python/layers/network.py7
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.-model.pbtxt8
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.applications.densenet.pbtxt23
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.applications.nasnet.pbtxt19
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.applications.pbtxt28
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.backend.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.callbacks.-learning-rate-scheduler.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.datasets.boston_housing.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.datasets.imdb.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.datasets.reuters.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-add.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-alpha-dropout.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-average.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-bidirectional.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-concatenate.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-conv-l-s-t-m2-d.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-dot.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-e-l-u.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-embedding.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u-cell.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-dropout.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-noise.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m-cell.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-leaky-re-l-u.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected1-d.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected2-d.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-maximum.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-multiply.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-p-re-l-u.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-r-n-n.pbtxt6
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv1-d.pbtxt186
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution1-d.pbtxt186
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n-cell.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n.pbtxt4
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-softmax.pbtxt183
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-stacked-r-n-n-cells.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.-thresholded-re-l-u.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.layers.pbtxt12
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.models.-model.pbtxt8
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adadelta.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adagrad.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adam.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adamax.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.optimizers.-nadam.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.optimizers.-r-m-sprop.pbtxt2
-rw-r--r--tensorflow/tools/api/golden/tensorflow.keras.preprocessing.text.-tokenizer.pbtxt2
116 files changed, 4870 insertions, 1616 deletions
diff --git a/tensorflow/contrib/cmake/python_modules.txt b/tensorflow/contrib/cmake/python_modules.txt
index 7db454bd83..9ce8b3cc9c 100644
--- a/tensorflow/contrib/cmake/python_modules.txt
+++ b/tensorflow/contrib/cmake/python_modules.txt
@@ -33,9 +33,11 @@ tensorflow/python/grappler
tensorflow/python/keras
tensorflow/python/keras/activations
tensorflow/python/keras/applications
+tensorflow/python/keras/applications/densenet
tensorflow/python/keras/applications/inception_resnet_v2
tensorflow/python/keras/applications/inception_v3
tensorflow/python/keras/applications/mobilenet
+tensorflow/python/keras/applications/nasnet
tensorflow/python/keras/applications/resnet50
tensorflow/python/keras/applications/vgg16
tensorflow/python/keras/applications/vgg19
diff --git a/tensorflow/python/keras/BUILD b/tensorflow/python/keras/BUILD
index 1f20b3ae0e..6125755775 100755
--- a/tensorflow/python/keras/BUILD
+++ b/tensorflow/python/keras/BUILD
@@ -14,10 +14,12 @@ py_library(
"_impl/keras/__init__.py",
"_impl/keras/activations.py",
"_impl/keras/applications/__init__.py",
+ "_impl/keras/applications/densenet.py",
"_impl/keras/applications/imagenet_utils.py",
"_impl/keras/applications/inception_resnet_v2.py",
"_impl/keras/applications/inception_v3.py",
"_impl/keras/applications/mobilenet.py",
+ "_impl/keras/applications/nasnet.py",
"_impl/keras/applications/resnet50.py",
"_impl/keras/applications/vgg16.py",
"_impl/keras/applications/vgg19.py",
@@ -76,9 +78,11 @@ py_library(
"_impl/keras/wrappers/scikit_learn.py",
"activations/__init__.py",
"applications/__init__.py",
+ "applications/densenet/__init__.py",
"applications/inception_resnet_v2/__init__.py",
"applications/inception_v3/__init__.py",
"applications/mobilenet/__init__.py",
+ "applications/nasnet/__init__.py",
"applications/resnet50/__init__.py",
"applications/vgg16/__init__.py",
"applications/vgg19/__init__.py",
@@ -257,6 +261,18 @@ py_test(
)
py_test(
+ name = "densenet_test",
+ size = "large",
+ srcs = ["_impl/keras/applications/densenet_test.py"],
+ srcs_version = "PY2AND3",
+ deps = [
+ ":keras",
+ "//tensorflow/python:client_testlib",
+ "//third_party/py/numpy",
+ ],
+)
+
+py_test(
name = "inception_resnet_v2_test",
size = "medium",
srcs = ["_impl/keras/applications/inception_resnet_v2_test.py"],
@@ -293,6 +309,18 @@ py_test(
)
py_test(
+ name = "nasnet_test",
+ size = "large",
+ srcs = ["_impl/keras/applications/nasnet_test.py"],
+ srcs_version = "PY2AND3",
+ deps = [
+ ":keras",
+ "//tensorflow/python:client_testlib",
+ "//third_party/py/numpy",
+ ],
+)
+
+py_test(
name = "resnet50_test",
size = "small",
srcs = ["_impl/keras/applications/resnet50_test.py"],
@@ -504,7 +532,7 @@ py_test(
py_test(
name = "recurrent_test",
- size = "small",
+ size = "medium",
srcs = ["_impl/keras/layers/recurrent_test.py"],
srcs_version = "PY2AND3",
deps = [
@@ -527,7 +555,7 @@ py_test(
py_test(
name = "wrappers_test",
- size = "small",
+ size = "medium",
srcs = ["_impl/keras/layers/wrappers_test.py"],
srcs_version = "PY2AND3",
tags = ["notsan"],
diff --git a/tensorflow/python/keras/_impl/keras/__init__.py b/tensorflow/python/keras/_impl/keras/__init__.py
index a70250d796..7311353932 100644
--- a/tensorflow/python/keras/_impl/keras/__init__.py
+++ b/tensorflow/python/keras/_impl/keras/__init__.py
@@ -40,4 +40,4 @@ from tensorflow.python.keras._impl.keras.layers import Input
from tensorflow.python.keras._impl.keras.models import Model
from tensorflow.python.keras._impl.keras.models import Sequential
-__version__ = '2.1.2-tf'
+__version__ = '2.1.3-tf'
diff --git a/tensorflow/python/keras/_impl/keras/activations.py b/tensorflow/python/keras/_impl/keras/activations.py
index f017d2ae85..4852b8c36a 100644
--- a/tensorflow/python/keras/_impl/keras/activations.py
+++ b/tensorflow/python/keras/_impl/keras/activations.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Keras built-in activation functions.
+"""Built-in activation functions.
"""
from __future__ import absolute_import
from __future__ import division
@@ -61,10 +61,12 @@ def selu(x):
x: A tensor or variable to compute the activation function for.
Returns:
- Tensor with the same shape and dtype as `x`.
+ Tensor with the same shape and dtype as `x`.
+
+ # Note
+ - To be used together with the initialization "lecun_normal".
+ - To be used together with the dropout variant "AlphaDropout".
- References:
- - [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515)
"""
alpha = 1.6732632423543772848170429916717
scale = 1.0507009873554804934193349852946
diff --git a/tensorflow/python/keras/_impl/keras/applications/__init__.py b/tensorflow/python/keras/_impl/keras/applications/__init__.py
index c11c52b71e..206a769b37 100644
--- a/tensorflow/python/keras/_impl/keras/applications/__init__.py
+++ b/tensorflow/python/keras/_impl/keras/applications/__init__.py
@@ -18,9 +18,14 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
+from tensorflow.python.keras._impl.keras.applications.densenet import DenseNet121
+from tensorflow.python.keras._impl.keras.applications.densenet import DenseNet169
+from tensorflow.python.keras._impl.keras.applications.densenet import DenseNet201
from tensorflow.python.keras._impl.keras.applications.inception_resnet_v2 import InceptionResNetV2
from tensorflow.python.keras._impl.keras.applications.inception_v3 import InceptionV3
from tensorflow.python.keras._impl.keras.applications.mobilenet import MobileNet
+from tensorflow.python.keras._impl.keras.applications.nasnet import NASNetLarge
+from tensorflow.python.keras._impl.keras.applications.nasnet import NASNetMobile
from tensorflow.python.keras._impl.keras.applications.resnet50 import ResNet50
from tensorflow.python.keras._impl.keras.applications.vgg16 import VGG16
from tensorflow.python.keras._impl.keras.applications.vgg19 import VGG19
diff --git a/tensorflow/python/keras/_impl/keras/applications/densenet.py b/tensorflow/python/keras/_impl/keras/applications/densenet.py
new file mode 100644
index 0000000000..9e40d34930
--- /dev/null
+++ b/tensorflow/python/keras/_impl/keras/applications/densenet.py
@@ -0,0 +1,346 @@
+# Copyright 2018 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.
+# ==============================================================================
+# pylint: disable=invalid-name
+# pylint: disable=unused-import
+"""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
+
+import os
+
+from tensorflow.python.keras._impl.keras import backend as K
+from tensorflow.python.keras._impl.keras.applications import imagenet_utils
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
+from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
+from tensorflow.python.keras._impl.keras.layers import Activation
+from tensorflow.python.keras._impl.keras.layers import AveragePooling2D
+from tensorflow.python.keras._impl.keras.layers import BatchNormalization
+from tensorflow.python.keras._impl.keras.layers import Concatenate
+from tensorflow.python.keras._impl.keras.layers import Conv2D
+from tensorflow.python.keras._impl.keras.layers import Dense
+from tensorflow.python.keras._impl.keras.layers import GlobalAveragePooling2D
+from tensorflow.python.keras._impl.keras.layers import GlobalMaxPooling2D
+from tensorflow.python.keras._impl.keras.layers import Input
+from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
+from tensorflow.python.keras._impl.keras.layers import ZeroPadding2D
+from tensorflow.python.keras._impl.keras.models import Model
+from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+
+
+DENSENET121_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/densenet121_weights_tf_dim_ordering_tf_kernels.h5'
+DENSENET121_WEIGHT_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/densenet121_weights_tf_dim_ordering_tf_kernels_notop.h5'
+DENSENET169_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/densenet169_weights_tf_dim_ordering_tf_kernels.h5'
+DENSENET169_WEIGHT_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/densenet169_weights_tf_dim_ordering_tf_kernels_notop.h5'
+DENSENET201_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/densenet201_weights_tf_dim_ordering_tf_kernels.h5'
+DENSENET201_WEIGHT_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/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 K.image_data_format() == 'channels_last' else 1
+ x = BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name=name + '_bn')(x)
+ x = Activation('relu', name=name + '_relu')(x)
+ x = Conv2D(
+ int(K.int_shape(x)[bn_axis] * reduction),
+ 1,
+ use_bias=False,
+ name=name + '_conv')(
+ x)
+ x = 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 K.image_data_format() == 'channels_last' else 1
+ x1 = BatchNormalization(
+ axis=bn_axis, epsilon=1.001e-5, name=name + '_0_bn')(
+ x)
+ x1 = Activation('relu', name=name + '_0_relu')(x1)
+ x1 = Conv2D(4 * growth_rate, 1, use_bias=False, name=name + '_1_conv')(x1)
+ x1 = BatchNormalization(
+ axis=bn_axis, epsilon=1.001e-5, name=name + '_1_bn')(
+ x1)
+ x1 = Activation('relu', name=name + '_1_relu')(x1)
+ x1 = Conv2D(
+ growth_rate, 3, padding='same', use_bias=False, name=name + '_2_conv')(
+ x1)
+ x = 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 when using TensorFlow,
+ for best performance you should set
+ `image_data_format='channels_last'` in your Keras config
+ at ~/.keras/keras.json.
+
+ The model and the weights are compatible with
+ TensorFlow, Theano, and CNTK. The data format
+ convention used by the model is the one
+ specified in your Keras config file.
+
+ 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.
+ pooling: optional pooling mode for feature extraction
+ when `include_top` is `False`.
+ - `None` means that the output of the model will be
+ the 4D tensor output of the
+ last convolutional layer.
+ - `avg` means that global average pooling
+ will be applied to the output of the
+ last convolutional layer, and thus
+ the output of the model will be a 2D tensor.
+ - `max` means that global max pooling will
+ be applied.
+ classes: optional number of classes to classify images
+ into, only to be specified if `include_top` is True, and
+ if no `weights` argument is specified.
+
+ Returns:
+ A Keras model instance.
+
+ Raises:
+ ValueError: in case of invalid argument for `weights`,
+ or invalid input shape.
+ """
+ if 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 = _obtain_input_shape(
+ input_shape,
+ default_size=224,
+ min_size=221,
+ data_format=K.image_data_format(),
+ require_flatten=include_top,
+ weights=weights)
+
+ if input_tensor is None:
+ img_input = Input(shape=input_shape)
+ else:
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
+
+ bn_axis = 3 if K.image_data_format() == 'channels_last' else 1
+
+ x = ZeroPadding2D(padding=((3, 3), (3, 3)))(img_input)
+ x = Conv2D(64, 7, strides=2, use_bias=False, name='conv1/conv')(x)
+ x = BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='conv1/bn')(x)
+ x = Activation('relu', name='conv1/relu')(x)
+ x = ZeroPadding2D(padding=((1, 1), (1, 1)))(x)
+ x = 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 = BatchNormalization(axis=bn_axis, epsilon=1.001e-5, name='bn')(x)
+
+ if include_top:
+ x = GlobalAveragePooling2D(name='avg_pool')(x)
+ x = Dense(classes, activation='softmax', name='fc1000')(x)
+ else:
+ if pooling == 'avg':
+ x = GlobalAveragePooling2D(name='avg_pool')(x)
+ elif pooling == 'max':
+ x = 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 = get_source_inputs(input_tensor)
+ else:
+ inputs = img_input
+
+ # Create model.
+ if blocks == [6, 12, 24, 16]:
+ model = Model(inputs, x, name='densenet121')
+ elif blocks == [6, 12, 32, 32]:
+ model = Model(inputs, x, name='densenet169')
+ elif blocks == [6, 12, 48, 32]:
+ model = Model(inputs, x, name='densenet201')
+ else:
+ model = Model(inputs, x, name='densenet')
+
+ # Load weights.
+ if weights == 'imagenet':
+ if include_top:
+ if blocks == [6, 12, 24, 16]:
+ weights_path = get_file(
+ 'densenet121_weights_tf_dim_ordering_tf_kernels.h5',
+ DENSENET121_WEIGHT_PATH,
+ cache_subdir='models',
+ file_hash='0962ca643bae20f9b6771cb844dca3b0')
+ elif blocks == [6, 12, 32, 32]:
+ weights_path = get_file(
+ 'densenet169_weights_tf_dim_ordering_tf_kernels.h5',
+ DENSENET169_WEIGHT_PATH,
+ cache_subdir='models',
+ file_hash='bcf9965cf5064a5f9eb6d7dc69386f43')
+ elif blocks == [6, 12, 48, 32]:
+ weights_path = get_file(
+ 'densenet201_weights_tf_dim_ordering_tf_kernels.h5',
+ DENSENET201_WEIGHT_PATH,
+ cache_subdir='models',
+ file_hash='7bb75edd58cb43163be7e0005fbe95ef')
+ else:
+ if blocks == [6, 12, 24, 16]:
+ weights_path = get_file(
+ 'densenet121_weights_tf_dim_ordering_tf_kernels_notop.h5',
+ DENSENET121_WEIGHT_PATH_NO_TOP,
+ cache_subdir='models',
+ file_hash='4912a53fbd2a69346e7f2c0b5ec8c6d3')
+ elif blocks == [6, 12, 32, 32]:
+ weights_path = get_file(
+ 'densenet169_weights_tf_dim_ordering_tf_kernels_notop.h5',
+ DENSENET169_WEIGHT_PATH_NO_TOP,
+ cache_subdir='models',
+ file_hash='50662582284e4cf834ce40ab4dfa58c6')
+ elif blocks == [6, 12, 48, 32]:
+ weights_path = get_file(
+ 'densenet201_weights_tf_dim_ordering_tf_kernels_notop.h5',
+ DENSENET201_WEIGHT_PATH_NO_TOP,
+ cache_subdir='models',
+ file_hash='1c2de60ee40562448dbac34a0737e798')
+ model.load_weights(weights_path)
+ elif weights is not None:
+ model.load_weights(weights)
+
+ return model
+
+
+def DenseNet121(include_top=True,
+ weights='imagenet',
+ input_tensor=None,
+ input_shape=None,
+ pooling=None,
+ classes=1000):
+ return DenseNet([6, 12, 24, 16], include_top, weights, input_tensor,
+ input_shape, pooling, classes)
+
+
+def DenseNet169(include_top=True,
+ weights='imagenet',
+ input_tensor=None,
+ input_shape=None,
+ pooling=None,
+ classes=1000):
+ return DenseNet([6, 12, 32, 32], include_top, weights, input_tensor,
+ input_shape, pooling, classes)
+
+
+def DenseNet201(include_top=True,
+ weights='imagenet',
+ input_tensor=None,
+ input_shape=None,
+ pooling=None,
+ classes=1000):
+ return DenseNet([6, 12, 48, 32], include_top, weights, input_tensor,
+ input_shape, pooling, classes)
+
+
+def preprocess_input(x, data_format=None):
+ """Preprocesses a numpy array encoding a batch of images.
+
+ Arguments:
+ x: a 3D or 4D numpy array consists of RGB values within [0, 255].
+ data_format: data format of the image tensor.
+
+ Returns:
+ Preprocessed array.
+ """
+ return imagenet_utils.preprocess_input(x, data_format, mode='torch')
+
+
+setattr(DenseNet121, '__doc__', DenseNet.__doc__)
+setattr(DenseNet169, '__doc__', DenseNet.__doc__)
+setattr(DenseNet201, '__doc__', DenseNet.__doc__)
diff --git a/tensorflow/python/keras/_impl/keras/applications/densenet_test.py b/tensorflow/python/keras/_impl/keras/applications/densenet_test.py
new file mode 100644
index 0000000000..3b92287a1e
--- /dev/null
+++ b/tensorflow/python/keras/_impl/keras/applications/densenet_test.py
@@ -0,0 +1,101 @@
+# Copyright 2018 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 DenseNet application."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from tensorflow.python.keras._impl import keras
+from tensorflow.python.platform import test
+
+
+class DenseNet121Test(test.TestCase):
+
+ def test_with_top(self):
+ model = keras.applications.DenseNet121(weights=None)
+ self.assertEqual(model.output_shape, (None, 1000))
+
+ def test_no_top(self):
+ model = keras.applications.DenseNet121(weights=None, include_top=False)
+ self.assertEqual(model.output_shape, (None, None, None, 1024))
+
+ def test_with_pooling(self):
+ model = keras.applications.DenseNet121(weights=None,
+ include_top=False,
+ pooling='avg')
+ self.assertEqual(model.output_shape, (None, 1024))
+
+ def test_weight_loading(self):
+ with self.assertRaises(ValueError):
+ keras.applications.DenseNet121(weights='unknown',
+ include_top=False)
+ with self.assertRaises(ValueError):
+ keras.applications.DenseNet121(weights='imagenet',
+ classes=2000)
+
+
+class DenseNet169Test(test.TestCase):
+
+ def test_with_top(self):
+ model = keras.applications.DenseNet169(weights=None)
+ self.assertEqual(model.output_shape, (None, 1000))
+
+ def test_no_top(self):
+ model = keras.applications.DenseNet169(weights=None, include_top=False)
+ self.assertEqual(model.output_shape, (None, None, None, 1664))
+
+ def test_with_pooling(self):
+ model = keras.applications.DenseNet169(weights=None,
+ include_top=False,
+ pooling='max')
+ self.assertEqual(model.output_shape, (None, 1664))
+
+ def test_weight_loading(self):
+ with self.assertRaises(ValueError):
+ keras.applications.DenseNet169(weights='unknown',
+ include_top=False)
+ with self.assertRaises(ValueError):
+ keras.applications.DenseNet169(weights='imagenet',
+ classes=2000)
+
+
+class DenseNet201(test.TestCase):
+
+ def test_with_top(self):
+ model = keras.applications.DenseNet201(weights=None)
+ self.assertEqual(model.output_shape, (None, 1000))
+
+ def test_no_top(self):
+ model = keras.applications.DenseNet201(weights=None, include_top=False)
+ self.assertEqual(model.output_shape, (None, None, None, 1920))
+
+ def test_with_pooling(self):
+ model = keras.applications.DenseNet201(weights=None,
+ include_top=False,
+ pooling='avg')
+ self.assertEqual(model.output_shape, (None, 1920))
+
+ def test_weight_loading(self):
+ with self.assertRaises(ValueError):
+ keras.applications.DenseNet201(weights='unknown',
+ include_top=False)
+ with self.assertRaises(ValueError):
+ keras.applications.DenseNet201(weights='imagenet',
+ classes=2000)
+
+
+if __name__ == '__main__':
+ test.main()
diff --git a/tensorflow/python/keras/_impl/keras/applications/imagenet_utils.py b/tensorflow/python/keras/_impl/keras/applications/imagenet_utils.py
index 63ee83cb51..f1f20f12a8 100644
--- a/tensorflow/python/keras/_impl/keras/applications/imagenet_utils.py
+++ b/tensorflow/python/keras/_impl/keras/applications/imagenet_utils.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Utilities used by models pre-trained on ImageNet.
+"""Utilities for ImageNet data preprocessing & prediction decoding.
"""
from __future__ import absolute_import
from __future__ import division
@@ -35,63 +35,92 @@ _IMAGENET_MEAN = None
def _preprocess_numpy_input(x, data_format, mode):
- """Preprocesses a image tensor as a Numpy array.
+ """Preprocesses a Numpy array encoding a batch of images.
Arguments:
- x: input Numpy, 3D or 4D.
- data_format: data format of the image tensor.
- mode: One of "caffe", "tf".
+ 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 array.
+ Preprocessed Numpy array.
"""
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:
- # 'RGB'->'BGR'
- x = x[::-1, ...]
- # Zero-center by mean pixel
- x[0, :, :] -= 103.939
- x[1, :, :] -= 116.779
- x[2, :, :] -= 123.68
+ 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 = x[:, ::-1, ...]
- x[:, 0, :, :] -= 103.939
- x[:, 1, :, :] -= 116.779
- x[:, 2, :, :] -= 123.68
+ 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:
- # 'RGB'->'BGR'
- x = x[..., ::-1]
- # Zero-center by mean pixel
- x[..., 0] -= 103.939
- x[..., 1] -= 116.779
- x[..., 2] -= 123.68
+ 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 symbolic image tensor.
+ """Preprocesses a tensor encoding a batch of images.
Arguments:
- x: symoblic tensor, 3D or 4D.
- data_format: data format of the image tensor.
- mode: One of "caffe", "tf".
+ 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.
@@ -103,32 +132,42 @@ def _preprocess_symbolic_input(x, data_format, mode):
x -= 1.
return x
- if data_format == 'channels_first':
- # 'RGB'->'BGR'
- if K.ndim(x) == 3:
- x = x[::-1, ...]
- else:
- x = x[:, ::-1, ...]
+ if mode == 'torch':
+ x /= 255.
+ mean = [0.485, 0.456, 0.406]
+ std = [0.229, 0.224, 0.225]
else:
- # 'RGB'->'BGR'
- x = x[..., ::-1]
+ if data_format == 'channels_first':
+ # 'RGB'->'BGR'
+ if K.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
if _IMAGENET_MEAN is None:
- _IMAGENET_MEAN = K.constant(-np.array([103.939, 116.779, 123.68]))
+ _IMAGENET_MEAN = K.constant(-np.array(mean))
+
# Zero-center by mean pixel
if K.dtype(x) != K.dtype(_IMAGENET_MEAN):
x = K.bias_add(x, K.cast(_IMAGENET_MEAN, K.dtype(x)), data_format)
else:
x = K.bias_add(x, _IMAGENET_MEAN, data_format)
+ if std is not None:
+ x /= std
return x
def preprocess_input(x, data_format=None, mode='caffe'):
- """Preprocesses a tensor encoding a batch of images.
+ """Preprocesses a tensor or Numpy array encoding a batch of images.
Arguments:
- x: input Numpy or symoblic tensor, 3D or 4D.
- data_format: data format of the image tensor.
+ x: Input Numpy or symbolic tensor, 3D or 4D.
+ data_format: Data format of the image tensor/array.
mode: One of "caffe", "tf".
- caffe: will convert the images from RGB to BGR,
then will zero-center each color channel with
@@ -138,10 +177,10 @@ def preprocess_input(x, data_format=None, mode='caffe'):
sample-wise.
Returns:
- Preprocessed tensor.
+ Preprocessed tensor or Numpy array.
Raises:
- ValueError: in case of incorrect data_format.
+ ValueError: In case of unknown `data_format` argument.
"""
if data_format is None:
data_format = K.image_data_format()
@@ -159,7 +198,7 @@ def decode_predictions(preds, top=5):
Arguments:
preds: Numpy tensor encoding a batch of predictions.
- top: integer, how many top-guesses to return.
+ top: Integer, how many top-guesses to return.
Returns:
A list of lists of top class prediction tuples
@@ -167,7 +206,7 @@ def decode_predictions(preds, top=5):
One list of tuples per sample in batch input.
Raises:
- ValueError: in case of invalid shape of the `pred` array
+ ValueError: In case of invalid shape of the `pred` array
(must be 2D).
"""
global CLASS_INDEX
@@ -177,10 +216,11 @@ def decode_predictions(preds, top=5):
'(i.e. a 2D array of shape (samples, 1000)). '
'Found array with shape: ' + str(preds.shape))
if CLASS_INDEX is None:
- fpath = get_file('imagenet_class_index.json',
- CLASS_INDEX_PATH,
- cache_subdir='models',
- file_hash='c2c37ea517e94d9795004a39431a14cb')
+ fpath = get_file(
+ 'imagenet_class_index.json',
+ CLASS_INDEX_PATH,
+ cache_subdir='models',
+ file_hash='c2c37ea517e94d9795004a39431a14cb')
CLASS_INDEX = json.load(open(fpath))
results = []
for pred in preds:
@@ -197,17 +237,17 @@ def _obtain_input_shape(input_shape,
data_format,
require_flatten,
weights=None):
- """Internal utility to compute/validate an ImageNet model's input shape.
+ """Internal utility to compute/validate a model's input shape.
Arguments:
- input_shape: either None (will return the default network input shape),
+ 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
+ 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)
+ weights: One of `None` (random initialization)
or 'imagenet' (pre-training on ImageNet).
If weights='imagenet' input channels must be equal to 3.
@@ -215,7 +255,7 @@ def _obtain_input_shape(input_shape,
An integer shape tuple (may include None entries).
Raises:
- ValueError: in case of invalid argument values.
+ ValueError: In case of invalid argument values.
"""
if weights != 'imagenet' and input_shape and len(input_shape) == 3:
if data_format == 'channels_first':
@@ -252,8 +292,8 @@ def _obtain_input_shape(input_shape,
'`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 '
+ 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:
@@ -264,8 +304,8 @@ def _obtain_input_shape(input_shape,
'`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 '
+ 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:
diff --git a/tensorflow/python/keras/_impl/keras/applications/inception_resnet_v2.py b/tensorflow/python/keras/_impl/keras/applications/inception_resnet_v2.py
index 2e73cefb6c..1dc15b5b34 100644
--- a/tensorflow/python/keras/_impl/keras/applications/inception_resnet_v2.py
+++ b/tensorflow/python/keras/_impl/keras/applications/inception_resnet_v2.py
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
+# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""Inception-ResNet V2 model for Keras.
# Reference
@@ -28,7 +30,7 @@ import os
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.applications import imagenet_utils
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
from tensorflow.python.keras._impl.keras.layers import Activation
from tensorflow.python.keras._impl.keras.layers import AveragePooling2D
@@ -43,6 +45,8 @@ from tensorflow.python.keras._impl.keras.layers import Lambda
from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
from tensorflow.python.keras._impl.keras.models import Model
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+from tensorflow.python.platform import tf_logging as logging
+
BASE_WEIGHT_URL = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.7/'
@@ -116,7 +120,8 @@ def inception_resnet_block(x, scale, block_type, block_idx, activation='relu'):
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`.
+ 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
@@ -128,8 +133,7 @@ def inception_resnet_block(x, scale, block_type, block_idx, activation='relu'):
will have `block_type='block35', block_idx=0`, ane the layer names
will have
a common prefix `'block35_0'`.
- activation: activation function to use at the end of the block
- (see [activations](../activations.md)).
+ activation: activation function to use at the end of the block.
When `activation=None`, no activation is applied
(i.e., "linear" activation: `a(x) = x`).
@@ -178,6 +182,7 @@ def inception_resnet_block(x, scale, block_type, block_idx, activation='relu'):
x = Lambda(
lambda inputs, scale: inputs[0] + inputs[1] * scale,
+ output_shape=K.int_shape(x)[1:],
arguments={'scale': scale},
name=block_name)([x, up])
if activation is not None:
@@ -185,7 +190,7 @@ def inception_resnet_block(x, scale, block_type, block_idx, activation='relu'):
return x
-def InceptionResNetV2(include_top=True, # pylint: disable=invalid-name
+def InceptionResNetV2(include_top=True,
weights='imagenet',
input_tensor=None,
input_shape=None,
@@ -211,8 +216,8 @@ def InceptionResNetV2(include_top=True, # pylint: disable=invalid-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.
+ '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
diff --git a/tensorflow/python/keras/_impl/keras/applications/inception_v3.py b/tensorflow/python/keras/_impl/keras/applications/inception_v3.py
index 4424b92804..ff57116f2d 100644
--- a/tensorflow/python/keras/_impl/keras/applications/inception_v3.py
+++ b/tensorflow/python/keras/_impl/keras/applications/inception_v3.py
@@ -13,6 +13,7 @@
# limitations under the License.
# ==============================================================================
# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""Inception V3 model for Keras.
Note that the input image format for this model is different than for
@@ -35,7 +36,7 @@ from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import layers
from tensorflow.python.keras._impl.keras.applications import imagenet_utils
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
from tensorflow.python.keras._impl.keras.layers import Activation
from tensorflow.python.keras._impl.keras.layers import AveragePooling2D
@@ -48,6 +49,7 @@ from tensorflow.python.keras._impl.keras.layers import Input
from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
from tensorflow.python.keras._impl.keras.models import Model
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+from tensorflow.python.platform import tf_logging as logging
WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.5/inception_v3_weights_tf_dim_ordering_tf_kernels.h5'
@@ -92,7 +94,8 @@ def conv2d_bn(x,
strides=strides,
padding=padding,
use_bias=False,
- name=conv_name)(x)
+ name=conv_name)(
+ x)
x = BatchNormalization(axis=bn_axis, scale=False, name=bn_name)(x)
x = Activation('relu', name=name)(x)
return x
@@ -109,7 +112,7 @@ def InceptionV3(include_top=True,
Optionally loads weights pre-trained
on ImageNet. Note that when using TensorFlow,
for best performance you should set
- `image_data_format="channels_last"` in your Keras config
+ `image_data_format='channels_last'` in your Keras config
at ~/.keras/keras.json.
The model and the weights are compatible with both
TensorFlow and Theano. The data format
@@ -121,15 +124,15 @@ def InceptionV3(include_top=True,
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.
+ '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 input channels,
+ It should have exactly 3 inputs channels,
and width and height should be no smaller than 139.
E.g. `(150, 150, 3)` would be one valid value.
pooling: Optional pooling mode for feature extraction
@@ -176,7 +179,10 @@ def InceptionV3(include_top=True,
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
- img_input = Input(tensor=input_tensor, shape=input_shape)
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
if K.image_data_format() == 'channels_first':
channel_axis = 1
@@ -389,6 +395,7 @@ def InceptionV3(include_top=True,
model.load_weights(weights_path)
elif weights is not None:
model.load_weights(weights)
+
return model
diff --git a/tensorflow/python/keras/_impl/keras/applications/mobilenet.py b/tensorflow/python/keras/_impl/keras/applications/mobilenet.py
index 5f97c138fc..790bf8cead 100644
--- a/tensorflow/python/keras/_impl/keras/applications/mobilenet.py
+++ b/tensorflow/python/keras/_impl/keras/applications/mobilenet.py
@@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
+# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""MobileNet v1 models for Keras.
MobileNet is a general architecture and can be used for multiple use cases.
@@ -56,7 +58,7 @@ the 100 % MobileNet on various input sizes:
------------------------------------------------------------------------
The weights for all 16 models are obtained and translated
-from Tensorflow checkpoints found at
+from TensorFlow checkpoints found at
https://github.com/tensorflow/models/blob/master/research/slim/nets/mobilenet_v1.md
# Reference
@@ -75,9 +77,10 @@ from tensorflow.python.keras._impl.keras import initializers
from tensorflow.python.keras._impl.keras import regularizers
from tensorflow.python.keras._impl.keras.applications import imagenet_utils
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
from tensorflow.python.keras._impl.keras.engine import InputSpec
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
from tensorflow.python.keras._impl.keras.layers import Activation
from tensorflow.python.keras._impl.keras.layers import BatchNormalization
from tensorflow.python.keras._impl.keras.layers import Conv2D
@@ -91,6 +94,7 @@ from tensorflow.python.keras._impl.keras.utils import conv_utils
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
from tensorflow.python.platform import tf_logging as logging
+
BASE_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.6/'
@@ -130,7 +134,7 @@ class DepthwiseConv2D(Conv2D):
all spatial dimensions.
Specifying any stride value != 1 is incompatible with specifying
any `dilation_rate` value != 1.
- padding: one of `"valid"` or `"same"` (case-insensitive).
+ padding: one of `'valid'` or `'same'` (case-insensitive).
depth_multiplier: The number of depthwise convolution output channels
for each input channel.
The total number of depthwise convolution output
@@ -144,29 +148,21 @@ class DepthwiseConv2D(Conv2D):
`(batch, channels, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
- If you never set it, then it will be "channels_last".
- activation: Activation function to use
- (see [activations](../activations.md)).
+ If you never set it, then it will be 'channels_last'.
+ activation: Activation function to use.
If you don't specify anything, no activation is applied
- (ie. "linear" activation: `a(x) = x`).
+ (ie. 'linear' activation: `a(x) = x`).
use_bias: Boolean, whether the layer uses a bias vector.
- depthwise_initializer: Initializer for the depthwise kernel matrix
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ depthwise_initializer: Initializer for the depthwise kernel matrix.
+ bias_initializer: Initializer for the bias vector.
depthwise_regularizer: Regularizer function applied to
- the depthwise kernel matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the depthwise kernel matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
activity_regularizer: Regularizer function applied to
- the output of the layer (its "activation").
- (see [regularizer](../regularizers.md)).
+ the output of the layer (its 'activation')..
depthwise_constraint: Constraint function applied to
- the depthwise kernel matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the depthwise kernel matrix.
+ bias_constraint: Constraint function applied to the bias vector.
Input shape:
4D tensor with shape:
@@ -216,6 +212,7 @@ class DepthwiseConv2D(Conv2D):
self.depthwise_constraint = constraints.get(depthwise_constraint)
self.bias_initializer = initializers.get(bias_initializer)
+ @shape_type_conversion
def build(self, input_shape):
if len(input_shape) < 4:
raise ValueError('Inputs to `DepthwiseConv2D` should have rank 4. '
@@ -269,6 +266,7 @@ class DepthwiseConv2D(Conv2D):
return outputs
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
rows = input_shape[2]
@@ -305,7 +303,7 @@ class DepthwiseConv2D(Conv2D):
return config
-def MobileNet(input_shape=None, # pylint: disable=invalid-name
+def MobileNet(input_shape=None,
alpha=1.0,
depth_multiplier=1,
dropout=1e-3,
@@ -334,7 +332,7 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-name
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,
+ 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.
@@ -350,8 +348,8 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-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.
+ '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.
@@ -380,6 +378,12 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-name
RuntimeError: If attempting to run this model with a
backend that does not support separable convolutions.
"""
+
+ if K.backend() != 'tensorflow':
+ raise RuntimeError('Only TensorFlow backend is currently supported, '
+ 'as other backends do not support '
+ 'depthwise convolution.')
+
if not (weights in {'imagenet', None} or os.path.exists(weights)):
raise ValueError('The `weights` argument should be either '
'`None` (random initialization), `imagenet` '
@@ -390,7 +394,7 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-name
raise ValueError('If using `weights` as ImageNet with `include_top` '
'as true, `classes` should be 1000')
- # Determine proper input shape.
+ # Determine proper input shape and default size.
if input_shape is None:
default_size = 224
else:
@@ -400,10 +404,12 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-name
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 = _obtain_input_shape(
input_shape,
default_size=default_size,
@@ -411,6 +417,7 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-name
data_format=K.image_data_format(),
require_flatten=include_top,
weights=weights)
+
if K.image_data_format() == 'channels_last':
row_axis, col_axis = (0, 1)
else:
@@ -536,8 +543,6 @@ def MobileNet(input_shape=None, # pylint: disable=invalid-name
if old_data_format:
K.set_image_data_format(old_data_format)
- elif weights is not None:
- model.load_weights(weights)
return model
@@ -595,7 +600,8 @@ def _conv_block(inputs, filters, alpha, kernel=(3, 3), strides=(1, 1)):
padding='same',
use_bias=False,
strides=strides,
- name='conv1')(inputs)
+ name='conv1')(
+ inputs)
x = BatchNormalization(axis=channel_axis, name='conv1_bn')(x)
return Activation(relu6, name='conv1_relu')(x)
@@ -662,7 +668,8 @@ def _depthwise_conv_block(inputs,
depth_multiplier=depth_multiplier,
strides=strides,
use_bias=False,
- name='conv_dw_%d' % block_id)(inputs)
+ name='conv_dw_%d' % block_id)(
+ inputs)
x = BatchNormalization(axis=channel_axis, name='conv_dw_%d_bn' % block_id)(x)
x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)
@@ -671,6 +678,7 @@ def _depthwise_conv_block(inputs,
padding='same',
use_bias=False,
strides=(1, 1),
- name='conv_pw_%d' % block_id)(x)
+ name='conv_pw_%d' % block_id)(
+ x)
x = BatchNormalization(axis=channel_axis, name='conv_pw_%d_bn' % block_id)(x)
return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)
diff --git a/tensorflow/python/keras/_impl/keras/applications/nasnet.py b/tensorflow/python/keras/_impl/keras/applications/nasnet.py
new file mode 100644
index 0000000000..5dd038c096
--- /dev/null
+++ b/tensorflow/python/keras/_impl/keras/applications/nasnet.py
@@ -0,0 +1,783 @@
+# Copyright 2018 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.
+# ==============================================================================
+# pylint: disable=line-too-long
+# pylint: disable=invalid-name
+# pylint: disable=unused-import
+"""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)
+"""
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+import os
+
+from tensorflow.python.keras._impl.keras import backend as K
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
+from tensorflow.python.keras._impl.keras.applications.inception_v3 import preprocess_input
+from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
+from tensorflow.python.keras._impl.keras.layers import Activation
+from tensorflow.python.keras._impl.keras.layers import add
+from tensorflow.python.keras._impl.keras.layers import AveragePooling2D
+from tensorflow.python.keras._impl.keras.layers import BatchNormalization
+from tensorflow.python.keras._impl.keras.layers import concatenate
+from tensorflow.python.keras._impl.keras.layers import Conv2D
+from tensorflow.python.keras._impl.keras.layers import Cropping2D
+from tensorflow.python.keras._impl.keras.layers import Dense
+from tensorflow.python.keras._impl.keras.layers import GlobalAveragePooling2D
+from tensorflow.python.keras._impl.keras.layers import GlobalMaxPooling2D
+from tensorflow.python.keras._impl.keras.layers import Input
+from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
+from tensorflow.python.keras._impl.keras.layers import SeparableConv2D
+from tensorflow.python.keras._impl.keras.layers import ZeroPadding2D
+from tensorflow.python.keras._impl.keras.models import Model
+from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+from tensorflow.python.platform import tf_logging as logging
+
+
+NASNET_MOBILE_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/NASNet-mobile.h5'
+NASNET_MOBILE_WEIGHT_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/NASNet-mobile-no-top.h5'
+NASNET_LARGE_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/NASNet-large.h5'
+NASNET_LARGE_WEIGHT_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.8/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.
+
+ Note that only TensorFlow is supported for now,
+ therefore it only works with the data format
+ `image_data_format='channels_last'` 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 or
+ `(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.
+ 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. Set to `False` for CIFAR models.
+ 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 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.
+ 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.
+ RuntimeError: If attempting to run this model with a
+ backend that does not support separable convolutions.
+ """
+ if K.backend() != 'tensorflow':
+ raise RuntimeError('Only Tensorflow backend is currently supported, '
+ 'as other backends do not support '
+ 'separable convolution.')
+
+ 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 default_size is None:
+ default_size = 331
+
+ # Determine proper input shape and default size.
+ input_shape = _obtain_input_shape(
+ input_shape,
+ default_size=default_size,
+ min_size=32,
+ data_format=K.image_data_format(),
+ require_flatten=include_top or weights,
+ weights=weights)
+
+ if K.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.')
+ K.set_image_data_format('channels_last')
+ old_data_format = 'channels_first'
+ else:
+ old_data_format = None
+
+ if input_tensor is None:
+ img_input = Input(shape=input_shape)
+ else:
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
+
+ if penultimate_filters % 24 != 0:
+ raise ValueError(
+ 'For NASNet-A models, the value of `penultimate_filters` '
+ 'needs to be divisible by 24. Current value: %d' % penultimate_filters)
+
+ channel_dim = 1 if K.image_data_format() == 'channels_first' else -1
+ filters = penultimate_filters // 24
+
+ if not skip_reduction:
+ x = Conv2D(
+ stem_block_filters, (3, 3),
+ strides=(2, 2),
+ padding='valid',
+ use_bias=False,
+ name='stem_conv1',
+ kernel_initializer='he_normal')(
+ img_input)
+ else:
+ x = Conv2D(
+ stem_block_filters, (3, 3),
+ strides=(1, 1),
+ padding='same',
+ use_bias=False,
+ name='stem_conv1',
+ kernel_initializer='he_normal')(
+ img_input)
+
+ x = BatchNormalization(
+ axis=channel_dim, momentum=0.9997, epsilon=1e-3, name='stem_bn1')(
+ x)
+
+ p = None
+ if not skip_reduction: # imagenet / mobile mode
+ 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 = Activation('relu')(x)
+
+ if include_top:
+ x = GlobalAveragePooling2D()(x)
+ x = Dense(classes, activation='softmax', name='predictions')(x)
+ else:
+ if pooling == 'avg':
+ x = GlobalAveragePooling2D()(x)
+ elif pooling == 'max':
+ x = GlobalMaxPooling2D()(x)
+
+ # Ensure that the model takes into account
+ # any potential predecessors of `input_tensor`.
+ if input_tensor is not None:
+ inputs = get_source_inputs(input_tensor)
+ else:
+ inputs = img_input
+
+ model = Model(inputs, x, name='NASNet')
+
+ # load weights
+ if weights == 'imagenet':
+ if default_size == 224: # mobile version
+ if include_top:
+ weight_path = NASNET_MOBILE_WEIGHT_PATH
+ model_name = 'nasnet_mobile.h5'
+ else:
+ weight_path = NASNET_MOBILE_WEIGHT_PATH_NO_TOP
+ model_name = 'nasnet_mobile_no_top.h5'
+
+ weights_file = get_file(model_name, weight_path, cache_subdir='models')
+ model.load_weights(weights_file)
+
+ elif default_size == 331: # large version
+ if include_top:
+ weight_path = NASNET_LARGE_WEIGHT_PATH
+ model_name = 'nasnet_large.h5'
+ else:
+ weight_path = NASNET_LARGE_WEIGHT_PATH_NO_TOP
+ model_name = 'nasnet_large_no_top.h5'
+
+ weights_file = get_file(model_name, weight_path, cache_subdir='models')
+ model.load_weights(weights_file)
+ 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:
+ K.set_image_data_format(old_data_format)
+
+ return model
+
+
+def NASNetLarge(input_shape=None,
+ include_top=True,
+ weights='imagenet',
+ input_tensor=None,
+ pooling=None,
+ classes=1000):
+ """Instantiates a NASNet model in ImageNet mode.
+
+ Note that only TensorFlow is supported for now,
+ therefore it only works with the data format
+ `image_data_format='channels_last'` 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=False,
+ filter_multiplier=2,
+ include_top=include_top,
+ weights=weights,
+ input_tensor=input_tensor,
+ pooling=pooling,
+ classes=classes,
+ default_size=331)
+
+
+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.
+
+ Note that only TensorFlow is supported for now,
+ therefore it only works with the data format
+ `image_data_format='channels_last'` 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)
+
+
+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 K.image_data_format() == 'channels_first' else -1
+
+ with K.name_scope('separable_conv_block_%s' % block_id):
+ x = Activation('relu')(ip)
+ x = SeparableConv2D(
+ filters,
+ kernel_size,
+ strides=strides,
+ name='separable_conv_1_%s' % block_id,
+ padding='same',
+ use_bias=False,
+ kernel_initializer='he_normal')(
+ x)
+ x = BatchNormalization(
+ axis=channel_dim,
+ momentum=0.9997,
+ epsilon=1e-3,
+ name='separable_conv_1_bn_%s' % (block_id))(
+ x)
+ x = Activation('relu')(x)
+ x = SeparableConv2D(
+ filters,
+ kernel_size,
+ name='separable_conv_2_%s' % block_id,
+ padding='same',
+ use_bias=False,
+ kernel_initializer='he_normal')(
+ x)
+ x = 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 K.image_data_format() == 'channels_first' else -1
+ img_dim = 2 if K.image_data_format() == 'channels_first' else -2
+
+ ip_shape = K.int_shape(ip)
+
+ if p is not None:
+ p_shape = K.int_shape(p)
+
+ with K.name_scope('adjust_block'):
+ if p is None:
+ p = ip
+
+ elif p_shape[img_dim] != ip_shape[img_dim]:
+ with K.name_scope('adjust_reduction_block_%s' % block_id):
+ p = Activation('relu', name='adjust_relu_1_%s' % block_id)(p)
+
+ p1 = AveragePooling2D(
+ (1, 1),
+ strides=(2, 2),
+ padding='valid',
+ name='adjust_avg_pool_1_%s' % block_id)(
+ p)
+ p1 = Conv2D(
+ filters // 2, (1, 1),
+ padding='same',
+ use_bias=False,
+ name='adjust_conv_1_%s' % block_id,
+ kernel_initializer='he_normal')(
+ p1)
+
+ p2 = ZeroPadding2D(padding=((0, 1), (0, 1)))(p)
+ p2 = Cropping2D(cropping=((1, 0), (1, 0)))(p2)
+ p2 = AveragePooling2D(
+ (1, 1),
+ strides=(2, 2),
+ padding='valid',
+ name='adjust_avg_pool_2_%s' % block_id)(
+ p2)
+ p2 = Conv2D(
+ filters // 2, (1, 1),
+ padding='same',
+ use_bias=False,
+ name='adjust_conv_2_%s' % block_id,
+ kernel_initializer='he_normal')(
+ p2)
+
+ p = concatenate([p1, p2], axis=channel_dim)
+ p = BatchNormalization(
+ axis=channel_dim,
+ momentum=0.9997,
+ epsilon=1e-3,
+ name='adjust_bn_%s' % block_id)(
+ p)
+
+ elif p_shape[channel_dim] != filters:
+ with K.name_scope('adjust_projection_block_%s' % block_id):
+ p = Activation('relu')(p)
+ p = 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 = 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 K.image_data_format() == 'channels_first' else -1
+
+ with K.name_scope('normal_A_block_%s' % block_id):
+ p = _adjust_block(p, ip, filters, block_id)
+
+ h = Activation('relu')(ip)
+ h = 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 = BatchNormalization(
+ axis=channel_dim,
+ momentum=0.9997,
+ epsilon=1e-3,
+ name='normal_bn_1_%s' % block_id)(
+ h)
+
+ with K.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 = add([x1_1, x1_2], name='normal_add_1_%s' % block_id)
+
+ with K.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 = add([x2_1, x2_2], name='normal_add_2_%s' % block_id)
+
+ with K.name_scope('block_3'):
+ x3 = AveragePooling2D(
+ (3, 3),
+ strides=(1, 1),
+ padding='same',
+ name='normal_left3_%s' % (block_id))(
+ h)
+ x3 = add([x3, p], name='normal_add_3_%s' % block_id)
+
+ with K.name_scope('block_4'):
+ x4_1 = AveragePooling2D(
+ (3, 3),
+ strides=(1, 1),
+ padding='same',
+ name='normal_left4_%s' % (block_id))(
+ p)
+ x4_2 = AveragePooling2D(
+ (3, 3),
+ strides=(1, 1),
+ padding='same',
+ name='normal_right4_%s' % (block_id))(
+ p)
+ x4 = add([x4_1, x4_2], name='normal_add_4_%s' % block_id)
+
+ with K.name_scope('block_5'):
+ x5 = _separable_conv_block(
+ h, filters, block_id='normal_left5_%s' % block_id)
+ x5 = add([x5, h], name='normal_add_5_%s' % block_id)
+
+ x = 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 K.image_data_format() == 'channels_first' else -1
+
+ with K.name_scope('reduction_A_block_%s' % block_id):
+ p = _adjust_block(p, ip, filters, block_id)
+
+ h = Activation('relu')(ip)
+ h = 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 = BatchNormalization(
+ axis=channel_dim,
+ momentum=0.9997,
+ epsilon=1e-3,
+ name='reduction_bn_1_%s' % block_id)(
+ h)
+
+ with K.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_1_%s' % block_id)
+ x1 = add([x1_1, x1_2], name='reduction_add_1_%s' % block_id)
+
+ with K.name_scope('block_2'):
+ x2_1 = MaxPooling2D(
+ (3, 3),
+ strides=(2, 2),
+ padding='same',
+ name='reduction_left2_%s' % block_id)(
+ h)
+ x2_2 = _separable_conv_block(
+ p,
+ filters, (7, 7),
+ strides=(2, 2),
+ block_id='reduction_right2_%s' % block_id)
+ x2 = add([x2_1, x2_2], name='reduction_add_2_%s' % block_id)
+
+ with K.name_scope('block_3'):
+ x3_1 = AveragePooling2D(
+ (3, 3),
+ strides=(2, 2),
+ padding='same',
+ name='reduction_left3_%s' % block_id)(
+ h)
+ x3_2 = _separable_conv_block(
+ p,
+ filters, (5, 5),
+ strides=(2, 2),
+ block_id='reduction_right3_%s' % block_id)
+ x3 = add([x3_1, x3_2], name='reduction_add3_%s' % block_id)
+
+ with K.name_scope('block_4'):
+ x4 = AveragePooling2D(
+ (3, 3),
+ strides=(1, 1),
+ padding='same',
+ name='reduction_left4_%s' % block_id)(
+ x1)
+ x4 = add([x2, x4])
+
+ with K.name_scope('block_5'):
+ x5_1 = _separable_conv_block(
+ x1, filters, (3, 3), block_id='reduction_left4_%s' % block_id)
+ x5_2 = MaxPooling2D(
+ (3, 3),
+ strides=(2, 2),
+ padding='same',
+ name='reduction_right5_%s' % block_id)(
+ h)
+ x5 = add([x5_1, x5_2], name='reduction_add4_%s' % block_id)
+
+ x = concatenate(
+ [x2, x3, x4, x5],
+ axis=channel_dim,
+ name='reduction_concat_%s' % block_id)
+ return x, ip
diff --git a/tensorflow/python/keras/_impl/keras/applications/nasnet_test.py b/tensorflow/python/keras/_impl/keras/applications/nasnet_test.py
new file mode 100644
index 0000000000..aa1dec670c
--- /dev/null
+++ b/tensorflow/python/keras/_impl/keras/applications/nasnet_test.py
@@ -0,0 +1,76 @@
+# Copyright 2018 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 Nasnet application."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from tensorflow.python.keras._impl import keras
+from tensorflow.python.platform import test
+
+
+class NASNetMobileTest(test.TestCase):
+
+ def test_with_top(self):
+ model = keras.applications.NASNetMobile(weights=None)
+ self.assertEqual(model.output_shape, (None, 1000))
+
+ def test_no_top(self):
+ model = keras.applications.NASNetMobile(weights=None, include_top=False)
+ self.assertEqual(model.output_shape, (None, None, None, 1056))
+
+ def test_with_pooling(self):
+ model = keras.applications.NASNetMobile(weights=None,
+ include_top=False,
+ pooling='avg')
+ self.assertEqual(model.output_shape, (None, 1056))
+
+ def test_weight_loading(self):
+ with self.assertRaises(ValueError):
+ keras.applications.NASNetMobile(weights='unknown',
+ include_top=False)
+ with self.assertRaises(ValueError):
+ keras.applications.NASNetMobile(weights='imagenet',
+ classes=2000)
+
+
+class NASNetLargeTest(test.TestCase):
+
+ def test_with_top(self):
+ model = keras.applications.NASNetLarge(weights=None)
+ self.assertEqual(model.output_shape, (None, 1000))
+
+ def test_no_top(self):
+ model = keras.applications.NASNetLarge(weights=None, include_top=False)
+ self.assertEqual(model.output_shape, (None, None, None, 4032))
+
+ def test_with_pooling(self):
+ model = keras.applications.NASNetLarge(weights=None,
+ include_top=False,
+ pooling='avg')
+ self.assertEqual(model.output_shape, (None, 4032))
+
+ def test_weight_loading(self):
+ with self.assertRaises(ValueError):
+ keras.applications.NASNetLarge(weights='unknown',
+ include_top=False)
+ with self.assertRaises(ValueError):
+ keras.applications.NASNetLarge(weights='imagenet',
+ classes=2000)
+
+
+if __name__ == '__main__':
+ test.main()
diff --git a/tensorflow/python/keras/_impl/keras/applications/resnet50.py b/tensorflow/python/keras/_impl/keras/applications/resnet50.py
index 8ab46693aa..5705b3481a 100644
--- a/tensorflow/python/keras/_impl/keras/applications/resnet50.py
+++ b/tensorflow/python/keras/_impl/keras/applications/resnet50.py
@@ -13,6 +13,7 @@
# limitations under the License.
# ==============================================================================
# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""ResNet50 model for Keras.
# Reference:
@@ -31,8 +32,8 @@ import os
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import layers
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import preprocess_input # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import preprocess_input
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
from tensorflow.python.keras._impl.keras.layers import Activation
from tensorflow.python.keras._impl.keras.layers import AveragePooling2D
@@ -45,7 +46,9 @@ from tensorflow.python.keras._impl.keras.layers import GlobalMaxPooling2D
from tensorflow.python.keras._impl.keras.layers import Input
from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
from tensorflow.python.keras._impl.keras.models import Model
+from tensorflow.python.keras._impl.keras.utils import layer_utils
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+from tensorflow.python.platform import tf_logging as logging
WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels.h5'
@@ -78,7 +81,8 @@ def identity_block(input_tensor, kernel_size, filters, stage, block):
x = Activation('relu')(x)
x = Conv2D(
- filters2, kernel_size, padding='same', name=conv_name_base + '2b')(x)
+ filters2, kernel_size, padding='same', name=conv_name_base + '2b')(
+ x)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
x = Activation('relu')(x)
@@ -92,7 +96,7 @@ def identity_block(input_tensor, kernel_size, filters, stage, block):
def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2,
2)):
- """conv_block is the block that has a conv layer at shortcut.
+ """A block that has a conv layer at shortcut.
Arguments:
input_tensor: input tensor
@@ -100,14 +104,14 @@ def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2,
filters: list of integers, the filters of 3 conv layer at main path
stage: integer, current stage label, used for generating layer names
block: 'a','b'..., current block label, used for generating layer names
- strides: Tuple of integers.
+ strides: Strides for the first conv layer in the block.
Returns:
Output tensor for the block.
- Note that from stage 3, the first conv layer at main path is with
- strides=(2,2)
- And the shortcut should have strides=(2,2) as well
+ Note that from stage 3,
+ the first conv layer at main path is with strides=(2, 2)
+ And the shortcut should have strides=(2, 2) as well
"""
filters1, filters2, filters3 = filters
if K.image_data_format() == 'channels_last':
@@ -118,13 +122,14 @@ def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2,
bn_name_base = 'bn' + str(stage) + block + '_branch'
x = Conv2D(
- filters1, (1, 1), strides=strides,
- name=conv_name_base + '2a')(input_tensor)
+ filters1, (1, 1), strides=strides, name=conv_name_base + '2a')(
+ input_tensor)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
x = Activation('relu')(x)
x = Conv2D(
- filters2, kernel_size, padding='same', name=conv_name_base + '2b')(x)
+ filters2, kernel_size, padding='same', name=conv_name_base + '2b')(
+ x)
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
x = Activation('relu')(x)
@@ -132,8 +137,8 @@ def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2,
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)
shortcut = Conv2D(
- filters3, (1, 1), strides=strides,
- name=conv_name_base + '1')(input_tensor)
+ filters3, (1, 1), strides=strides, name=conv_name_base + '1')(
+ input_tensor)
shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut)
x = layers.add([x, shortcut])
@@ -152,7 +157,7 @@ def ResNet50(include_top=True,
Optionally loads weights pre-trained
on ImageNet. Note that when using TensorFlow,
for best performance you should set
- `image_data_format="channels_last"` in your Keras config
+ `image_data_format='channels_last'` in your Keras config
at ~/.keras/keras.json.
The model and the weights are compatible with both
@@ -164,15 +169,15 @@ def ResNet50(include_top=True,
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.
+ '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,
+ It should have exactly 3 inputs channels,
and width and height should be no smaller than 197.
E.g. `(200, 200, 3)` would be one valid value.
pooling: Optional pooling mode for feature extraction
@@ -219,15 +224,18 @@ def ResNet50(include_top=True,
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
- img_input = Input(tensor=input_tensor, shape=input_shape)
-
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
if K.image_data_format() == 'channels_last':
bn_axis = 3
else:
bn_axis = 1
- x = Conv2D(64, (7, 7),
- strides=(2, 2), padding='same', name='conv1')(img_input)
+ x = Conv2D(
+ 64, (7, 7), strides=(2, 2), padding='same', name='conv1')(
+ img_input)
x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x)
x = Activation('relu')(x)
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
@@ -289,4 +297,5 @@ def ResNet50(include_top=True,
model.load_weights(weights_path)
elif weights is not None:
model.load_weights(weights)
+
return model
diff --git a/tensorflow/python/keras/_impl/keras/applications/vgg16.py b/tensorflow/python/keras/_impl/keras/applications/vgg16.py
index 38dbbdc809..c91c24e6fb 100644
--- a/tensorflow/python/keras/_impl/keras/applications/vgg16.py
+++ b/tensorflow/python/keras/_impl/keras/applications/vgg16.py
@@ -13,6 +13,7 @@
# limitations under the License.
# ==============================================================================
# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""VGG16 model for Keras.
# Reference
@@ -29,8 +30,8 @@ import os
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import preprocess_input # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import preprocess_input
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
from tensorflow.python.keras._impl.keras.layers import Conv2D
from tensorflow.python.keras._impl.keras.layers import Dense
@@ -42,6 +43,7 @@ from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
from tensorflow.python.keras._impl.keras.models import Model
from tensorflow.python.keras._impl.keras.utils import layer_utils
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+from tensorflow.python.platform import tf_logging as logging
WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels.h5'
@@ -59,7 +61,7 @@ def VGG16(include_top=True,
Optionally loads weights pre-trained
on ImageNet. Note that when using TensorFlow,
for best performance you should set
- `image_data_format="channels_last"` in your Keras config
+ `image_data_format='channels_last'` in your Keras config
at ~/.keras/keras.json.
The model and the weights are compatible with both
@@ -71,8 +73,8 @@ def VGG16(include_top=True,
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.
+ '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
@@ -125,48 +127,62 @@ def VGG16(include_top=True,
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
- img_input = Input(tensor=input_tensor, shape=input_shape)
-
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
# Block 1
x = Conv2D(
- 64, (3, 3), activation='relu', padding='same',
- name='block1_conv1')(img_input)
+ 64, (3, 3), activation='relu', padding='same', name='block1_conv1')(
+ img_input)
x = Conv2D(
- 64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
+ 64, (3, 3), activation='relu', padding='same', name='block1_conv2')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
# Block 2
x = Conv2D(
- 128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
+ 128, (3, 3), activation='relu', padding='same', name='block2_conv1')(
+ x)
x = Conv2D(
- 128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
+ 128, (3, 3), activation='relu', padding='same', name='block2_conv2')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
# Block 3
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv1')(
+ x)
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv2')(
+ x)
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv3')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
# Block 4
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv1')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv2')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv3')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
# Block 5
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv1')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv2')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv3')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
if include_top:
@@ -215,6 +231,8 @@ def VGG16(include_top=True,
dense = model.get_layer(name='fc1')
layer_utils.convert_dense_weights_data_format(dense, shape,
'channels_first')
+
elif weights is not None:
model.load_weights(weights)
+
return model
diff --git a/tensorflow/python/keras/_impl/keras/applications/vgg19.py b/tensorflow/python/keras/_impl/keras/applications/vgg19.py
index 126c64260b..223cd79d7b 100644
--- a/tensorflow/python/keras/_impl/keras/applications/vgg19.py
+++ b/tensorflow/python/keras/_impl/keras/applications/vgg19.py
@@ -13,6 +13,7 @@
# limitations under the License.
# ==============================================================================
# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""VGG19 model for Keras.
# Reference
@@ -29,8 +30,8 @@ import os
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import preprocess_input # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import preprocess_input
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
from tensorflow.python.keras._impl.keras.layers import Conv2D
from tensorflow.python.keras._impl.keras.layers import Dense
@@ -42,6 +43,7 @@ from tensorflow.python.keras._impl.keras.layers import MaxPooling2D
from tensorflow.python.keras._impl.keras.models import Model
from tensorflow.python.keras._impl.keras.utils import layer_utils
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
+from tensorflow.python.platform import tf_logging as logging
WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels.h5'
@@ -59,7 +61,7 @@ def VGG19(include_top=True,
Optionally loads weights pre-trained
on ImageNet. Note that when using TensorFlow,
for best performance you should set
- `image_data_format="channels_last"` in your Keras config
+ `image_data_format='channels_last'` in your Keras config
at ~/.keras/keras.json.
The model and the weights are compatible with both
@@ -71,15 +73,15 @@ def VGG19(include_top=True,
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.
+ '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,
+ It should have exactly 3 inputs channels,
and width and height should be no smaller than 48.
E.g. `(200, 200, 3)` would be one valid value.
pooling: Optional pooling mode for feature extraction
@@ -125,54 +127,71 @@ def VGG19(include_top=True,
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
- img_input = Input(tensor=input_tensor, shape=input_shape)
-
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
# Block 1
x = Conv2D(
- 64, (3, 3), activation='relu', padding='same',
- name='block1_conv1')(img_input)
+ 64, (3, 3), activation='relu', padding='same', name='block1_conv1')(
+ img_input)
x = Conv2D(
- 64, (3, 3), activation='relu', padding='same', name='block1_conv2')(x)
+ 64, (3, 3), activation='relu', padding='same', name='block1_conv2')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
# Block 2
x = Conv2D(
- 128, (3, 3), activation='relu', padding='same', name='block2_conv1')(x)
+ 128, (3, 3), activation='relu', padding='same', name='block2_conv1')(
+ x)
x = Conv2D(
- 128, (3, 3), activation='relu', padding='same', name='block2_conv2')(x)
+ 128, (3, 3), activation='relu', padding='same', name='block2_conv2')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
# Block 3
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv1')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv1')(
+ x)
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv2')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv2')(
+ x)
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv3')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv3')(
+ x)
x = Conv2D(
- 256, (3, 3), activation='relu', padding='same', name='block3_conv4')(x)
+ 256, (3, 3), activation='relu', padding='same', name='block3_conv4')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
# Block 4
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv1')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv1')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv2')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv2')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv3')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv3')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block4_conv4')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block4_conv4')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
# Block 5
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv1')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv1')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv2')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv2')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv3')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv3')(
+ x)
x = Conv2D(
- 512, (3, 3), activation='relu', padding='same', name='block5_conv4')(x)
+ 512, (3, 3), activation='relu', padding='same', name='block5_conv4')(
+ x)
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
if include_top:
@@ -211,6 +230,8 @@ def VGG19(include_top=True,
cache_subdir='models',
file_hash='253f8cb515780f3b799900260a226db6')
model.load_weights(weights_path)
+ if K.backend() == 'theano':
+ layer_utils.convert_all_kernels_in_model(model)
if K.image_data_format() == 'channels_first':
if include_top:
@@ -219,6 +240,8 @@ def VGG19(include_top=True,
dense = model.get_layer(name='fc1')
layer_utils.convert_dense_weights_data_format(dense, shape,
'channels_first')
+
elif weights is not None:
model.load_weights(weights)
+
return model
diff --git a/tensorflow/python/keras/_impl/keras/applications/xception.py b/tensorflow/python/keras/_impl/keras/applications/xception.py
index 8219831408..0a6eb4953a 100644
--- a/tensorflow/python/keras/_impl/keras/applications/xception.py
+++ b/tensorflow/python/keras/_impl/keras/applications/xception.py
@@ -1,4 +1,4 @@
-# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2016 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.
@@ -13,6 +13,7 @@
# limitations under the License.
# ==============================================================================
# pylint: disable=invalid-name
+# pylint: disable=unused-import
"""Xception V1 model for Keras.
On ImageNet, this model gets to a top-1 validation accuracy of 0.790
@@ -42,7 +43,7 @@ from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import layers
from tensorflow.python.keras._impl.keras.applications import imagenet_utils
from tensorflow.python.keras._impl.keras.applications.imagenet_utils import _obtain_input_shape
-from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions # pylint: disable=unused-import
+from tensorflow.python.keras._impl.keras.applications.imagenet_utils import decode_predictions
from tensorflow.python.keras._impl.keras.engine.topology import get_source_inputs
from tensorflow.python.keras._impl.keras.layers import Activation
from tensorflow.python.keras._impl.keras.layers import BatchNormalization
@@ -74,7 +75,7 @@ def Xception(include_top=True,
on ImageNet. This model is available for TensorFlow only,
and can only be used with inputs following the TensorFlow
data format `(width, height, channels)`.
- You should set `image_data_format="channels_last"` in your Keras config
+ You should set `image_data_format='channels_last'` in your Keras config
located at ~/.keras/keras.json.
Note that the default input image size for this model is 299x299.
@@ -83,14 +84,14 @@ def Xception(include_top=True,
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.
+ '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 input channels,
+ 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
@@ -155,11 +156,14 @@ def Xception(include_top=True,
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
- img_input = Input(tensor=input_tensor, shape=input_shape)
+ if not K.is_keras_tensor(input_tensor):
+ img_input = Input(tensor=input_tensor, shape=input_shape)
+ else:
+ img_input = input_tensor
x = Conv2D(
- 32, (3, 3), strides=(2, 2), use_bias=False,
- name='block1_conv1')(img_input)
+ 32, (3, 3), strides=(2, 2), use_bias=False, name='block1_conv1')(
+ img_input)
x = BatchNormalization(name='block1_conv1_bn')(x)
x = Activation('relu', name='block1_conv1_act')(x)
x = Conv2D(64, (3, 3), use_bias=False, name='block1_conv2')(x)
@@ -167,53 +171,65 @@ def Xception(include_top=True,
x = Activation('relu', name='block1_conv2_act')(x)
residual = Conv2D(
- 128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
+ 128, (1, 1), strides=(2, 2), padding='same', use_bias=False)(
+ x)
residual = BatchNormalization()(residual)
x = SeparableConv2D(
- 128, (3, 3), padding='same', use_bias=False, name='block2_sepconv1')(x)
+ 128, (3, 3), padding='same', use_bias=False, name='block2_sepconv1')(
+ x)
x = BatchNormalization(name='block2_sepconv1_bn')(x)
x = Activation('relu', name='block2_sepconv2_act')(x)
x = SeparableConv2D(
- 128, (3, 3), padding='same', use_bias=False, name='block2_sepconv2')(x)
+ 128, (3, 3), padding='same', use_bias=False, name='block2_sepconv2')(
+ x)
x = BatchNormalization(name='block2_sepconv2_bn')(x)
x = MaxPooling2D(
- (3, 3), strides=(2, 2), padding='same', name='block2_pool')(x)
+ (3, 3), strides=(2, 2), padding='same', name='block2_pool')(
+ x)
x = layers.add([x, residual])
residual = Conv2D(
- 256, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
+ 256, (1, 1), strides=(2, 2), padding='same', use_bias=False)(
+ x)
residual = BatchNormalization()(residual)
x = Activation('relu', name='block3_sepconv1_act')(x)
x = SeparableConv2D(
- 256, (3, 3), padding='same', use_bias=False, name='block3_sepconv1')(x)
+ 256, (3, 3), padding='same', use_bias=False, name='block3_sepconv1')(
+ x)
x = BatchNormalization(name='block3_sepconv1_bn')(x)
x = Activation('relu', name='block3_sepconv2_act')(x)
x = SeparableConv2D(
- 256, (3, 3), padding='same', use_bias=False, name='block3_sepconv2')(x)
+ 256, (3, 3), padding='same', use_bias=False, name='block3_sepconv2')(
+ x)
x = BatchNormalization(name='block3_sepconv2_bn')(x)
x = MaxPooling2D(
- (3, 3), strides=(2, 2), padding='same', name='block3_pool')(x)
+ (3, 3), strides=(2, 2), padding='same', name='block3_pool')(
+ x)
x = layers.add([x, residual])
residual = Conv2D(
- 728, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
+ 728, (1, 1), strides=(2, 2), padding='same', use_bias=False)(
+ x)
residual = BatchNormalization()(residual)
x = Activation('relu', name='block4_sepconv1_act')(x)
x = SeparableConv2D(
- 728, (3, 3), padding='same', use_bias=False, name='block4_sepconv1')(x)
+ 728, (3, 3), padding='same', use_bias=False, name='block4_sepconv1')(
+ x)
x = BatchNormalization(name='block4_sepconv1_bn')(x)
x = Activation('relu', name='block4_sepconv2_act')(x)
x = SeparableConv2D(
- 728, (3, 3), padding='same', use_bias=False, name='block4_sepconv2')(x)
+ 728, (3, 3), padding='same', use_bias=False, name='block4_sepconv2')(
+ x)
x = BatchNormalization(name='block4_sepconv2_bn')(x)
x = MaxPooling2D(
- (3, 3), strides=(2, 2), padding='same', name='block4_pool')(x)
+ (3, 3), strides=(2, 2), padding='same', name='block4_pool')(
+ x)
x = layers.add([x, residual])
for i in range(8):
@@ -222,46 +238,52 @@ def Xception(include_top=True,
x = Activation('relu', name=prefix + '_sepconv1_act')(x)
x = SeparableConv2D(
- 728, (3, 3), padding='same', use_bias=False,
- name=prefix + '_sepconv1')(x)
+ 728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv1')(
+ x)
x = BatchNormalization(name=prefix + '_sepconv1_bn')(x)
x = Activation('relu', name=prefix + '_sepconv2_act')(x)
x = SeparableConv2D(
- 728, (3, 3), padding='same', use_bias=False,
- name=prefix + '_sepconv2')(x)
+ 728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv2')(
+ x)
x = BatchNormalization(name=prefix + '_sepconv2_bn')(x)
x = Activation('relu', name=prefix + '_sepconv3_act')(x)
x = SeparableConv2D(
- 728, (3, 3), padding='same', use_bias=False,
- name=prefix + '_sepconv3')(x)
+ 728, (3, 3), padding='same', use_bias=False, name=prefix + '_sepconv3')(
+ x)
x = BatchNormalization(name=prefix + '_sepconv3_bn')(x)
x = layers.add([x, residual])
residual = Conv2D(
- 1024, (1, 1), strides=(2, 2), padding='same', use_bias=False)(x)
+ 1024, (1, 1), strides=(2, 2), padding='same', use_bias=False)(
+ x)
residual = BatchNormalization()(residual)
x = Activation('relu', name='block13_sepconv1_act')(x)
x = SeparableConv2D(
- 728, (3, 3), padding='same', use_bias=False, name='block13_sepconv1')(x)
+ 728, (3, 3), padding='same', use_bias=False, name='block13_sepconv1')(
+ x)
x = BatchNormalization(name='block13_sepconv1_bn')(x)
x = Activation('relu', name='block13_sepconv2_act')(x)
x = SeparableConv2D(
- 1024, (3, 3), padding='same', use_bias=False, name='block13_sepconv2')(x)
+ 1024, (3, 3), padding='same', use_bias=False, name='block13_sepconv2')(
+ x)
x = BatchNormalization(name='block13_sepconv2_bn')(x)
x = MaxPooling2D(
- (3, 3), strides=(2, 2), padding='same', name='block13_pool')(x)
+ (3, 3), strides=(2, 2), padding='same', name='block13_pool')(
+ x)
x = layers.add([x, residual])
x = SeparableConv2D(
- 1536, (3, 3), padding='same', use_bias=False, name='block14_sepconv1')(x)
+ 1536, (3, 3), padding='same', use_bias=False, name='block14_sepconv1')(
+ x)
x = BatchNormalization(name='block14_sepconv1_bn')(x)
x = Activation('relu', name='block14_sepconv1_act')(x)
x = SeparableConv2D(
- 2048, (3, 3), padding='same', use_bias=False, name='block14_sepconv2')(x)
+ 2048, (3, 3), padding='same', use_bias=False, name='block14_sepconv2')(
+ x)
x = BatchNormalization(name='block14_sepconv2_bn')(x)
x = Activation('relu', name='block14_sepconv2_act')(x)
@@ -303,8 +325,6 @@ def Xception(include_top=True,
if old_data_format:
K.set_image_data_format(old_data_format)
- elif weights is not None:
- model.load_weights(weights)
return model
diff --git a/tensorflow/python/keras/_impl/keras/backend.py b/tensorflow/python/keras/_impl/keras/backend.py
index 9476085bd8..460c0dc5f3 100644
--- a/tensorflow/python/keras/_impl/keras/backend.py
+++ b/tensorflow/python/keras/_impl/keras/backend.py
@@ -85,7 +85,7 @@ _MANUAL_VAR_INIT = False
_FLOATX = 'float32'
# Epsilon fuzz factor used throughout the codebase.
-_EPSILON = 10e-8
+_EPSILON = 1e-7
# Default image data format, one of "channels_last", "channels_first".
_IMAGE_DATA_FORMAT = 'channels_last'
@@ -116,7 +116,7 @@ def epsilon():
Example:
```python
>>> keras.backend.epsilon()
- 1e-08
+ 1e-07
```
"""
return _EPSILON
@@ -132,7 +132,7 @@ def set_epsilon(value):
```python
>>> from keras import backend as K
>>> K.epsilon()
- 1e-08
+ 1e-07
>>> K.set_epsilon(1e-05)
>>> K.epsilon()
1e-05
@@ -295,7 +295,8 @@ def clear_session():
ops.reset_default_graph()
reset_uids()
_SESSION = None
- phase = array_ops.placeholder(dtype='bool', name='keras_learning_phase')
+ phase = array_ops.placeholder_with_default(
+ False, shape=(), name='keras_learning_phase')
_GRAPH_LEARNING_PHASES = {}
_GRAPH_LEARNING_PHASES[ops.get_default_graph()] = phase
@@ -328,7 +329,8 @@ def learning_phase():
"""
graph = ops.get_default_graph()
if graph not in _GRAPH_LEARNING_PHASES:
- phase = array_ops.placeholder(dtype='bool', name='keras_learning_phase')
+ phase = array_ops.placeholder_with_default(
+ False, shape=(), name='keras_learning_phase')
_GRAPH_LEARNING_PHASES[graph] = phase
return _GRAPH_LEARNING_PHASES[graph]
@@ -876,6 +878,8 @@ def zeros(shape, dtype=None, name=None):
Returns:
A variable (including Keras metadata), filled with `0.0`.
+ Note that if `shape` was symbolic, we cannot return a variable,
+ and will return a dynamically-shaped tensor instead.
Example:
```python
@@ -890,12 +894,14 @@ def zeros(shape, dtype=None, name=None):
if dtype is None:
dtype = floatx()
tf_dtype = dtypes_module.as_dtype(dtype)
- return variable(
- init_ops.constant_initializer(0., dtype=tf_dtype)(shape), dtype, name)
+ v = array_ops.zeros(shape=shape, dtype=tf_dtype, name=name)
+ if py_all(v.get_shape().as_list()):
+ return variable(v, dtype=dtype, name=name)
+ return v
def ones(shape, dtype=None, name=None):
- """Instantiates an all-ones tensor variable and returns it.
+ """Instantiates an all-ones variable and returns it.
Arguments:
shape: Tuple of integers, shape of returned Keras variable.
@@ -904,6 +910,8 @@ def ones(shape, dtype=None, name=None):
Returns:
A Keras variable, filled with `1.0`.
+ Note that if `shape` was symbolic, we cannot return a variable,
+ and will return a dynamically-shaped tensor instead.
Example:
```python
@@ -918,8 +926,10 @@ def ones(shape, dtype=None, name=None):
if dtype is None:
dtype = floatx()
tf_dtype = dtypes_module.as_dtype(dtype)
- return variable(
- init_ops.constant_initializer(1., dtype=tf_dtype)(shape), dtype, name)
+ v = array_ops.ones(shape=shape, dtype=tf_dtype, name=name)
+ if py_all(v.get_shape().as_list()):
+ return variable(v, dtype=dtype, name=name)
+ return v
def eye(size, dtype=None, name=None):
@@ -1185,7 +1195,7 @@ def moving_average_update(x, value, momentum):
An Operation to update the variable.
"""
return moving_averages.assign_moving_average(
- x, value, momentum, zero_debias=False)
+ x, value, momentum, zero_debias=True)
# LINEAR ALGEBRA
@@ -1419,7 +1429,7 @@ def max(x, axis=None, keepdims=False):
Returns:
A tensor with maximum values of `x`.
"""
- return math_ops.reduce_max(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_max(x, axis, keepdims)
def min(x, axis=None, keepdims=False):
@@ -1436,7 +1446,7 @@ def min(x, axis=None, keepdims=False):
Returns:
A tensor with miminum values of `x`.
"""
- return math_ops.reduce_min(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_min(x, axis, keepdims)
def sum(x, axis=None, keepdims=False):
@@ -1453,7 +1463,7 @@ def sum(x, axis=None, keepdims=False):
Returns:
A tensor with sum of `x`.
"""
- return math_ops.reduce_sum(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_sum(x, axis, keepdims)
def prod(x, axis=None, keepdims=False):
@@ -1470,7 +1480,7 @@ def prod(x, axis=None, keepdims=False):
Returns:
A tensor with the product of elements of `x`.
"""
- return math_ops.reduce_prod(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_prod(x, axis, keepdims)
def cumsum(x, axis=0):
@@ -1515,10 +1525,10 @@ def var(x, axis=None, keepdims=False):
"""
if x.dtype.base_dtype == dtypes_module.bool:
x = math_ops.cast(x, floatx())
- m = math_ops.reduce_mean(x, axis=axis, keep_dims=True)
+ m = math_ops.reduce_mean(x, axis, True)
devs_squared = math_ops.square(x - m)
return math_ops.reduce_mean(
- devs_squared, axis=axis, keep_dims=keepdims)
+ devs_squared, axis, keepdims)
def std(x, axis=None, keepdims=False):
@@ -1546,7 +1556,7 @@ def mean(x, axis=None, keepdims=False):
axis: A list of integer. Axes to compute the mean.
keepdims: A boolean, whether to keep the dimensions or not.
If `keepdims` is `False`, the rank of the tensor is reduced
- by 1 for each entry in `axis`. If `keep_dims` is `True`,
+ by 1 for each entry in `axis`. If `keepdims` is `True`,
the reduced dimensions are retained with length 1.
Returns:
@@ -1554,7 +1564,7 @@ def mean(x, axis=None, keepdims=False):
"""
if x.dtype.base_dtype == dtypes_module.bool:
x = math_ops.cast(x, floatx())
- return math_ops.reduce_mean(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_mean(x, axis, keepdims)
def any(x, axis=None, keepdims=False):
@@ -1569,7 +1579,7 @@ def any(x, axis=None, keepdims=False):
A uint8 tensor (0s and 1s).
"""
x = math_ops.cast(x, dtypes_module.bool)
- return math_ops.reduce_any(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_any(x, axis, keepdims)
def all(x, axis=None, keepdims=False):
@@ -1584,7 +1594,7 @@ def all(x, axis=None, keepdims=False):
A uint8 tensor (0s and 1s).
"""
x = math_ops.cast(x, dtypes_module.bool)
- return math_ops.reduce_all(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_all(x, axis, keepdims)
def argmax(x, axis=-1):
@@ -1694,7 +1704,7 @@ def logsumexp(x, axis=None, keepdims=False):
Returns:
The reduced tensor.
"""
- return math_ops.reduce_logsumexp(x, axis=axis, keep_dims=keepdims)
+ return math_ops.reduce_logsumexp(x, axis, keepdims)
def round(x):
@@ -1884,6 +1894,108 @@ def cos(x):
return math_ops.cos(x)
+def _regular_normalize_batch_in_training(x,
+ gamma,
+ beta,
+ reduction_axes,
+ epsilon=1e-3):
+ """Non-fused version of `normalize_batch_in_training`.
+
+ Arguments:
+ x: Input tensor or variable.
+ gamma: Tensor by which to scale the input.
+ beta: Tensor with which to center the input.
+ reduction_axes: iterable of integers,
+ axes over which to normalize.
+ epsilon: Fuzz factor.
+
+ Returns:
+ A tuple length of 3, `(normalized_tensor, mean, variance)`.
+ """
+ mean, var = nn.moments(x, reduction_axes, None, None, False)
+ normed = nn.batch_normalization(x, mean, var, beta, gamma, epsilon)
+ return normed, mean, var
+
+
+def _broadcast_normalize_batch_in_training(x,
+ gamma,
+ beta,
+ reduction_axes,
+ epsilon=1e-3):
+ """Non-fused, broadcast version of `normalize_batch_in_training`.
+
+ Arguments:
+ x: Input tensor or variable.
+ gamma: Tensor by which to scale the input.
+ beta: Tensor with which to center the input.
+ reduction_axes: iterable of integers,
+ axes over which to normalize.
+ epsilon: Fuzz factor.
+
+ Returns:
+ A tuple length of 3, `(normalized_tensor, mean, variance)`.
+ """
+ mean, var = nn.moments(x, reduction_axes, None, None, False)
+ target_shape = []
+ for axis in range(ndim(x)):
+ if axis in reduction_axes:
+ target_shape.append(1)
+ else:
+ target_shape.append(array_ops.shape(x)[axis])
+ target_shape = array_ops.stack(target_shape)
+
+ broadcast_mean = array_ops.reshape(mean, target_shape)
+ broadcast_var = array_ops.reshape(var, target_shape)
+ if gamma is None:
+ broadcast_gamma = None
+ else:
+ broadcast_gamma = array_ops.reshape(gamma, target_shape)
+ if beta is None:
+ broadcast_beta = None
+ else:
+ broadcast_beta = array_ops.reshape(beta, target_shape)
+
+ normed = nn.batch_normalization(x, broadcast_mean, broadcast_var,
+ broadcast_beta, broadcast_gamma, epsilon)
+ return normed, mean, var
+
+
+def _fused_normalize_batch_in_training(x,
+ gamma,
+ beta,
+ reduction_axes,
+ epsilon=1e-3):
+ """Fused version of `normalize_batch_in_training`.
+
+ Arguments:
+ x: Input tensor or variable.
+ gamma: Tensor by which to scale the input.
+ beta: Tensor with which to center the input.
+ reduction_axes: iterable of integers,
+ axes over which to normalize.
+ epsilon: Fuzz factor.
+
+ Returns:
+ A tuple length of 3, `(normalized_tensor, mean, variance)`.
+ """
+ if list(reduction_axes) == [0, 1, 2]:
+ normalization_axis = 3
+ tf_data_format = 'NHWC'
+ else:
+ normalization_axis = 1
+ tf_data_format = 'NCHW'
+
+ if gamma is None:
+ gamma = constant_op.constant(
+ 1.0, dtype=x.dtype, shape=[x.get_shape()[normalization_axis]])
+ if beta is None:
+ beta = constant_op.constant(
+ 0.0, dtype=x.dtype, shape=[x.get_shape()[normalization_axis]])
+
+ return nn.fused_batch_norm(
+ x, gamma, beta, epsilon=epsilon, data_format=tf_data_format)
+
+
def normalize_batch_in_training(x, gamma, beta, reduction_axes, epsilon=1e-3):
"""Computes mean and std for batch then apply batch_normalization on batch.
@@ -1898,33 +2010,19 @@ def normalize_batch_in_training(x, gamma, beta, reduction_axes, epsilon=1e-3):
Returns:
A tuple length of 3, `(normalized_tensor, mean, variance)`.
"""
- mean, var = nn.moments(
- x, reduction_axes, shift=None, name=None, keep_dims=False)
- if sorted(reduction_axes) == list(range(ndim(x)))[:-1]:
- normed = nn.batch_normalization(x, mean, var, beta, gamma, epsilon)
+ if ndim(x) == 4 and list(reduction_axes) in [[0, 1, 2], [0, 2, 3]]:
+ if not _has_nchw_support() and list(reduction_axes) == [0, 2, 3]:
+ return _broadcast_normalize_batch_in_training(
+ x, gamma, beta, reduction_axes, epsilon=epsilon)
+ return _fused_normalize_batch_in_training(
+ x, gamma, beta, reduction_axes, epsilon=epsilon)
else:
- # need broadcasting
- target_shape = []
- for axis in range(ndim(x)):
- if axis in reduction_axes:
- target_shape.append(1)
- else:
- target_shape.append(array_ops.shape(x)[axis])
- target_shape = array_ops.stack(target_shape)
-
- broadcast_mean = array_ops.reshape(mean, target_shape)
- broadcast_var = array_ops.reshape(var, target_shape)
- if gamma is None:
- broadcast_gamma = None
+ if sorted(reduction_axes) == list(range(ndim(x)))[:-1]:
+ return _regular_normalize_batch_in_training(
+ x, gamma, beta, reduction_axes, epsilon=epsilon)
else:
- broadcast_gamma = array_ops.reshape(gamma, target_shape)
- if beta is None:
- broadcast_beta = None
- else:
- broadcast_beta = array_ops.reshape(beta, target_shape)
- normed = nn.batch_normalization(x, broadcast_mean, broadcast_var,
- broadcast_beta, broadcast_gamma, epsilon)
- return normed, mean, var
+ return _broadcast_normalize_batch_in_training(
+ x, gamma, beta, reduction_axes, epsilon=epsilon)
def batch_normalization(x, mean, var, beta, gamma, epsilon=1e-3):
@@ -2619,7 +2717,8 @@ def rnn(step_function,
go_backwards=False,
mask=None,
constants=None,
- unroll=False):
+ unroll=False,
+ input_length=None):
"""Iterates over the time dimension of a tensor.
Arguments:
@@ -2648,6 +2747,7 @@ def rnn(step_function,
constants: a list of constant values passed at each step.
unroll: whether to unroll the RNN or to use a symbolic loop
(`while_loop` or `scan` depending on backend).
+ input_length: Unused; exists for API compatibility.
Returns:
A tuple, `(last_output, outputs, new_states)`.
@@ -2665,6 +2765,7 @@ def rnn(step_function,
ValueError: if `mask` is provided (not `None`) but states is not provided
(`len(states)` == 0).
"""
+ del input_length
ndim = len(inputs.get_shape())
if ndim < 3:
raise ValueError('Input should be at least 3D.')
@@ -3016,7 +3117,7 @@ def elu(x, alpha=1.):
Arguments:
x: A tensor or variable to compute the activation function for.
- alpha: A scalar, slope of positive section.
+ alpha: A scalar, slope of negative section.
Returns:
A tensor.
@@ -3083,7 +3184,7 @@ def categorical_crossentropy(target, output, from_logits=False):
if not from_logits:
# scale preds so that the class probas of each sample sum to 1
output /= math_ops.reduce_sum(
- output, axis=len(output.get_shape()) - 1, keep_dims=True)
+ output, len(output.get_shape()) - 1, True)
# manual computation of crossentropy
epsilon_ = _to_tensor(epsilon(), output.dtype.base_dtype)
output = clip_ops.clip_by_value(output, epsilon_, 1. - epsilon_)
@@ -3248,6 +3349,25 @@ def in_top_k(predictions, targets, k):
# CONVOLUTIONS
+def _preprocess_conv1d_input(x, data_format):
+ """Transpose and cast the input before the conv1d.
+
+ Arguments:
+ x: input tensor.
+ data_format: string, `"channels_last"` or `"channels_first"`.
+
+ Returns:
+ A tensor.
+ """
+ tf_data_format = 'NHWC' # to pass TF Conv2dNative operations
+ if data_format == 'channels_first':
+ if not _has_nchw_support():
+ x = array_ops.transpose(x, (0, 2, 1)) # NCW -> NWC
+ else:
+ tf_data_format = 'NCHW'
+ return x, tf_data_format
+
+
def _preprocess_conv2d_input(x, data_format):
"""Transpose and cast the input before the conv2d.
@@ -3461,6 +3581,66 @@ def conv2d_transpose(x,
return x
+def separable_conv1d(x,
+ depthwise_kernel,
+ pointwise_kernel,
+ strides=1,
+ padding='valid',
+ data_format=None,
+ dilation_rate=1):
+ """1D convolution with separable filters.
+
+ Arguments:
+ x: input tensor
+ depthwise_kernel: convolution kernel for the depthwise convolution.
+ pointwise_kernel: kernel for the 1x1 convolution.
+ strides: stride integer.
+ padding: string, `"same"` or `"valid"`.
+ data_format: string, `"channels_last"` or `"channels_first"`.
+ dilation_rate: integer dilation rate.
+
+ Returns:
+ Output tensor.
+
+ Raises:
+ ValueError: if `data_format` is neither `channels_last` or
+ `channels_first`.
+ """
+ if data_format is None:
+ data_format = image_data_format()
+ if data_format not in {'channels_first', 'channels_last'}:
+ raise ValueError('Unknown data_format ' + str(data_format))
+
+ x, tf_data_format = _preprocess_conv1d_input(x, data_format)
+ padding = _preprocess_padding(padding)
+ if tf_data_format == 'NHWC':
+ spatial_start_dim = 1
+ strides = (1, 1) + strides + (1,)
+ else:
+ spatial_start_dim = 2
+ strides = (1, 1, 1) + strides
+ x = array_ops.expand_dims(x, spatial_start_dim)
+ depthwise_kernel = array_ops.expand_dims(depthwise_kernel, 0)
+ pointwise_kernel = array_ops.expand_dims(pointwise_kernel, 0)
+ dilation_rate = (1,) + dilation_rate
+
+ x = nn.separable_conv2d(
+ x,
+ depthwise_kernel,
+ pointwise_kernel,
+ strides=strides,
+ padding=padding,
+ rate=dilation_rate,
+ data_format=tf_data_format)
+
+ x = array_ops.squeeze(x, [spatial_start_dim])
+
+ if data_format == 'channels_first' and tf_data_format == 'NHWC':
+ x = array_ops.transpose(x, (0, 2, 1)) # NWC -> NCW
+
+ return x
+
+
def separable_conv2d(x,
depthwise_kernel,
pointwise_kernel,
@@ -3921,7 +4101,10 @@ def bias_add(x, bias, data_format=None):
elif ndim(x) == 4:
if data_format == 'channels_first':
if len(bias_shape) == 1:
- x += reshape(bias, (1, bias_shape[0], 1, 1))
+ if _has_nchw_support():
+ x = nn.bias_add(x, bias, data_format='NCHW')
+ else:
+ x += reshape(bias, (1, bias_shape[0], 1, 1))
else:
x += reshape(bias, (1, bias_shape[2]) + bias_shape[:2])
elif data_format == 'channels_last':
@@ -4113,7 +4296,7 @@ def ctc_batch_cost(y_true, y_pred, input_length, label_length):
sparse_labels = math_ops.to_int32(
ctc_label_dense_to_sparse(y_true, label_length))
- y_pred = math_ops.log(array_ops.transpose(y_pred, perm=[1, 0, 2]) + 1e-8)
+ y_pred = math_ops.log(array_ops.transpose(y_pred, perm=[1, 0, 2]) + epsilon())
return array_ops.expand_dims(
ctc.ctc_loss(
@@ -4148,7 +4331,7 @@ def ctc_decode(y_pred, input_length, greedy=True, beam_width=100, top_paths=1):
Tensor `(top_paths, )` that contains
the log probability of each decoded sequence.
"""
- y_pred = math_ops.log(array_ops.transpose(y_pred, perm=[1, 0, 2]) + 1e-8)
+ y_pred = math_ops.log(array_ops.transpose(y_pred, perm=[1, 0, 2]) + epsilon())
input_length = math_ops.to_int32(input_length)
if greedy:
diff --git a/tensorflow/python/keras/_impl/keras/backend_test.py b/tensorflow/python/keras/_impl/keras/backend_test.py
index e34f1b6926..27833e368d 100644
--- a/tensorflow/python/keras/_impl/keras/backend_test.py
+++ b/tensorflow/python/keras/_impl/keras/backend_test.py
@@ -954,7 +954,6 @@ class BackendNNOpsTest(test.TestCase):
x = keras.backend.variable(val)
reduction_axes = (0, 2, 3)
- # case: need broadcasting
g_val = np.random.random((3,))
b_val = np.random.random((3,))
gamma = keras.backend.variable(g_val)
@@ -965,17 +964,6 @@ class BackendNNOpsTest(test.TestCase):
self.assertEqual(mean.get_shape().as_list(), [3,])
self.assertEqual(var.get_shape().as_list(), [3,])
- # case: doesn't need broadcasting
- g_val = np.random.random((1, 3, 1, 1))
- b_val = np.random.random((1, 3, 1, 1))
- gamma = keras.backend.variable(g_val)
- beta = keras.backend.variable(b_val)
- normed, mean, var = keras.backend.normalize_batch_in_training(
- x, gamma, beta, reduction_axes, epsilon=1e-3)
- self.assertEqual(normed.get_shape().as_list(), [10, 3, 10, 10])
- self.assertEqual(mean.get_shape().as_list(), [3,])
- self.assertEqual(var.get_shape().as_list(), [3,])
-
# case: gamma=None
gamma = None
normed, mean, var = keras.backend.normalize_batch_in_training(
diff --git a/tensorflow/python/keras/_impl/keras/callbacks.py b/tensorflow/python/keras/_impl/keras/callbacks.py
index 8da3b85718..f0d9e0b0f5 100644
--- a/tensorflow/python/keras/_impl/keras/callbacks.py
+++ b/tensorflow/python/keras/_impl/keras/callbacks.py
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Keras callbacks: utilities called at certain points during model training.
+# pylint: disable=g-import-not-at-top
+"""Callbacks: utilities called at certain points during model training.
"""
from __future__ import absolute_import
from __future__ import division
@@ -36,12 +37,10 @@ from tensorflow.python.platform import tf_logging as logging
from tensorflow.python.summary import summary as tf_summary
-# pylint: disable=g-import-not-at-top
try:
import requests
except ImportError:
requests = None
-# pylint: enable=g-import-not-at-top
class CallbackList(object):
@@ -109,9 +108,9 @@ class CallbackList(object):
delta_t_median = np.median(self._delta_ts_batch_begin)
if (self._delta_t_batch > 0. and
delta_t_median > 0.95 * self._delta_t_batch and delta_t_median > 0.1):
- logging.warning(
- 'Method on_batch_begin() is slow compared '
- 'to the batch update (%f). Check your callbacks.' % delta_t_median)
+ logging.warning('Method on_batch_begin() is slow compared '
+ 'to the batch update (%f). Check your callbacks.',
+ delta_t_median)
self._t_enter_batch = time.time()
def on_batch_end(self, batch, logs=None):
@@ -132,9 +131,9 @@ class CallbackList(object):
delta_t_median = np.median(self._delta_ts_batch_end)
if (self._delta_t_batch > 0. and
(delta_t_median > 0.95 * self._delta_t_batch and delta_t_median > 0.1)):
- logging.warning(
- 'Method on_batch_end() is slow compared '
- 'to the batch update (%f). Check your callbacks.' % delta_t_median)
+ logging.warning('Method on_batch_end() is slow compared '
+ 'to the batch update (%f). Check your callbacks.',
+ delta_t_median)
def on_train_begin(self, logs=None):
"""Called at the beginning of training.
@@ -246,7 +245,8 @@ class BaseLogger(Callback):
class TerminateOnNaN(Callback):
- """Callback that terminates training when a NaN loss is encountered."""
+ """Callback that terminates training when a NaN loss is encountered.
+ """
def __init__(self):
super(TerminateOnNaN, self).__init__()
@@ -396,7 +396,7 @@ class ModelCheckpoint(Callback):
if mode not in ['auto', 'min', 'max']:
logging.warning('ModelCheckpoint mode %s is unknown, '
- 'fallback to auto mode.' % mode)
+ 'fallback to auto mode.', (mode), RuntimeWarning)
mode = 'auto'
if mode == 'min':
@@ -423,11 +423,11 @@ class ModelCheckpoint(Callback):
current = logs.get(self.monitor)
if current is None:
logging.warning('Can save best model only with %s available, '
- 'skipping.' % (self.monitor))
+ 'skipping.', self.monitor, RuntimeWarning)
else:
if self.monitor_op(current, self.best):
if self.verbose > 0:
- print('Epoch %05d: %s improved from %0.5f to %0.5f,'
+ print('\nEpoch %05d: %s improved from %0.5f to %0.5f,'
' saving model to %s' % (epoch + 1, self.monitor, self.best,
current, filepath))
self.best = current
@@ -437,11 +437,11 @@ class ModelCheckpoint(Callback):
self.model.save(filepath, overwrite=True)
else:
if self.verbose > 0:
- print('Epoch %05d: %s did not improve' % (epoch + 1,
- self.monitor))
+ print('\nEpoch %05d: %s did not improve' % (epoch + 1,
+ self.monitor))
else:
if self.verbose > 0:
- print('Epoch %05d: saving model to %s' % (epoch + 1, filepath))
+ print('\nEpoch %05d: saving model to %s' % (epoch + 1, filepath))
if self.save_weights_only:
self.model.save_weights(filepath, overwrite=True)
else:
@@ -486,7 +486,7 @@ class EarlyStopping(Callback):
if mode not in ['auto', 'min', 'max']:
logging.warning('EarlyStopping mode %s is unknown, '
- 'fallback to auto mode.' % mode)
+ 'fallback to auto mode.', mode, RuntimeWarning)
mode = 'auto'
if mode == 'min':
@@ -514,8 +514,8 @@ class EarlyStopping(Callback):
current = logs.get(self.monitor)
if current is None:
logging.warning('Early stopping conditioned on metric `%s` '
- 'which is not available. Available metrics are: %s' %
- (self.monitor, ','.join(list(logs.keys()))))
+ 'which is not available. Available metrics are: %s',
+ self.monitor, ','.join(list(logs.keys())), RuntimeWarning)
return
if self.monitor_op(current - self.min_delta, self.best):
self.best = current
@@ -544,8 +544,6 @@ class RemoteMonitor(Callback):
path: String; path relative to `root` to which the events will be sent.
field: String; JSON field under which the data will be stored.
headers: Dictionary; optional custom HTTP headers.
- Defaults to:
- `{'Accept': 'application/json', 'Content-Type': 'application/json'}`
"""
def __init__(self,
@@ -554,11 +552,7 @@ class RemoteMonitor(Callback):
field='data',
headers=None):
super(RemoteMonitor, self).__init__()
- if headers is None:
- headers = {
- 'Accept': 'application/json',
- 'Content-Type': 'application/json'
- }
+
self.root = root
self.path = path
self.field = field
@@ -588,11 +582,13 @@ class LearningRateScheduler(Callback):
schedule: a function that takes an epoch index as input
(integer, indexed from 0) and returns a new
learning rate as output (float).
+ verbose: int. 0: quiet, 1: update messages.
"""
- def __init__(self, schedule):
+ def __init__(self, schedule, verbose=0):
super(LearningRateScheduler, self).__init__()
self.schedule = schedule
+ self.verbose = verbose
def on_epoch_begin(self, epoch, logs=None):
if not hasattr(self.model.optimizer, 'lr'):
@@ -602,6 +598,9 @@ class LearningRateScheduler(Callback):
raise ValueError('The output of the "schedule" function '
'should be float.')
K.set_value(self.model.optimizer.lr, lr)
+ if self.verbose > 0:
+ print('\nEpoch %05d: LearningRateScheduler reducing learning '
+ 'rate to %s.' % (epoch + 1, lr))
class TensorBoard(Callback):
@@ -842,7 +841,7 @@ class ReduceLROnPlateau(Callback):
"""
if self.mode not in ['auto', 'min', 'max']:
logging.warning('Learning Rate Plateau Reducing mode %s is unknown, '
- 'fallback to auto mode.' % (self.mode))
+ 'fallback to auto mode.', self.mode, RuntimeWarning)
self.mode = 'auto'
if (self.mode == 'min' or
(self.mode == 'auto' and 'acc' not in self.monitor)):
@@ -853,7 +852,6 @@ class ReduceLROnPlateau(Callback):
self.best = -np.Inf
self.cooldown_counter = 0
self.wait = 0
- self.lr_epsilon = self.min_lr * 1e-4
def on_train_begin(self, logs=None):
self._reset()
@@ -864,8 +862,9 @@ class ReduceLROnPlateau(Callback):
current = logs.get(self.monitor)
if current is None:
logging.warning('Reduce LR on plateau conditioned on metric `%s` '
- 'which is not available. Available metrics are: %s' %
- (self.monitor, ','.join(list(logs.keys()))))
+ 'which is not available. Available metrics are: %s',
+ self.monitor, ','.join(list(logs.keys())), RuntimeWarning)
+
else:
if self.in_cooldown():
self.cooldown_counter -= 1
@@ -877,13 +876,13 @@ class ReduceLROnPlateau(Callback):
elif not self.in_cooldown():
if self.wait >= self.patience:
old_lr = float(K.get_value(self.model.optimizer.lr))
- if old_lr > self.min_lr + self.lr_epsilon:
+ if old_lr > self.min_lr:
new_lr = old_lr * self.factor
new_lr = max(new_lr, self.min_lr)
K.set_value(self.model.optimizer.lr, new_lr)
if self.verbose > 0:
- print('\nEpoch %05d: reducing learning rate to %s.' % (epoch,
- new_lr))
+ print('\nEpoch %05d: ReduceLROnPlateau reducing learning '
+ 'rate to %s.' % (epoch + 1, new_lr))
self.cooldown_counter = self.cooldown
self.wait = 0
self.wait += 1
@@ -899,10 +898,11 @@ class CSVLogger(Callback):
including 1D iterables such as np.ndarray.
Example:
- ```python
- csv_logger = CSVLogger('training.log')
- model.fit(X_train, Y_train, callbacks=[csv_logger])
- ```
+
+ ```python
+ csv_logger = CSVLogger('training.log')
+ model.fit(X_train, Y_train, callbacks=[csv_logger])
+ ```
Arguments:
filename: filename of the csv file, e.g. 'run/log.csv'.
@@ -942,12 +942,14 @@ class CSVLogger(Callback):
else:
return k
+ if self.keys is None:
+ self.keys = sorted(logs.keys())
+
if self.model.stop_training:
# We set NA so that csv parsers do not fail for this last epoch.
logs = dict([(k, logs[k]) if k in logs else (k, 'NA') for k in self.keys])
if not self.writer:
- self.keys = sorted(logs.keys())
class CustomDialect(csv.excel):
delimiter = self.sep
@@ -993,32 +995,32 @@ class LambdaCallback(Callback):
Example:
- ```python
- # Print the batch number at the beginning of every batch.
- batch_print_callback = LambdaCallback(
- on_batch_begin=lambda batch,logs: print(batch))
-
- # Stream the epoch loss to a file in JSON format. The file content
- # is not well-formed JSON but rather has a JSON object per line.
- import json
- json_log = open('loss_log.json', mode='wt', buffering=1)
- json_logging_callback = LambdaCallback(
- on_epoch_end=lambda epoch, logs: json_log.write(
- json.dumps({'epoch': epoch, 'loss': logs['loss']}) + '\n'),
- on_train_end=lambda logs: json_log.close()
- )
-
- # Terminate some processes after having finished model training.
- processes = ...
- cleanup_callback = LambdaCallback(
- on_train_end=lambda logs: [
- p.terminate() for p in processes if p.is_alive()])
-
- model.fit(...,
- callbacks=[batch_print_callback,
- json_logging_callback,
- cleanup_callback])
- ```
+ ```python
+ # Print the batch number at the beginning of every batch.
+ batch_print_callback = LambdaCallback(
+ on_batch_begin=lambda batch,logs: print(batch))
+
+ # Stream the epoch loss to a file in JSON format. The file content
+ # is not well-formed JSON but rather has a JSON object per line.
+ import json
+ json_log = open('loss_log.json', mode='wt', buffering=1)
+ json_logging_callback = LambdaCallback(
+ on_epoch_end=lambda epoch, logs: json_log.write(
+ json.dumps({'epoch': epoch, 'loss': logs['loss']}) + '\n'),
+ on_train_end=lambda logs: json_log.close()
+ )
+
+ # Terminate some processes after having finished model training.
+ processes = ...
+ cleanup_callback = LambdaCallback(
+ on_train_end=lambda logs: [
+ p.terminate() for p in processes if p.is_alive()])
+
+ model.fit(...,
+ callbacks=[batch_print_callback,
+ json_logging_callback,
+ cleanup_callback])
+ ```
"""
def __init__(self,
diff --git a/tensorflow/python/keras/_impl/keras/constraints.py b/tensorflow/python/keras/_impl/keras/constraints.py
index e58e3b0377..4b051c93f3 100644
--- a/tensorflow/python/keras/_impl/keras/constraints.py
+++ b/tensorflow/python/keras/_impl/keras/constraints.py
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Constraints: functions that impose constraints on weights values.
+# pylint: disable=invalid-name
+"""Constraints: functions that impose constraints on weight values.
"""
from __future__ import absolute_import
from __future__ import division
@@ -54,10 +55,6 @@ class MaxNorm(Constraint):
to constrain the weights of each filter tensor of size
`(rows, cols, input_depth)`.
- References:
- - [Dropout: A Simple Way to Prevent Neural Networks from Overfitting
- Srivastava, Hinton, et al.
- 2014](http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf)
"""
def __init__(self, max_value=2, axis=0):
@@ -79,7 +76,7 @@ class NonNeg(Constraint):
"""
def __call__(self, w):
- w *= K.cast(w >= 0., K.floatx())
+ w *= K.cast(K.greater_equal(w, 0.), K.floatx())
return w
@@ -132,7 +129,7 @@ class MinMaxNorm(Constraint):
has shape `(input_dim, output_dim)`,
set `axis` to `0` to constrain each weight vector
of length `(input_dim,)`.
- In a `Conv2D` layer with `dim_ordering="channels_last"`,
+ In a `Conv2D` layer with `data_format="channels_last"`,
the weight tensor has shape
`(rows, cols, input_depth, output_depth)`,
set `axis` to `[0, 1, 2]`
@@ -148,8 +145,9 @@ class MinMaxNorm(Constraint):
def __call__(self, w):
norms = K.sqrt(K.sum(K.square(w), axis=self.axis, keepdims=True))
- desired = (self.rate * K.clip(norms, self.min_value, self.max_value) +
- (1 - self.rate) * norms)
+ desired = (
+ self.rate * K.clip(norms, self.min_value, self.max_value) +
+ (1 - self.rate) * norms)
w *= (desired / (K.epsilon() + norms))
return w
@@ -164,13 +162,15 @@ class MinMaxNorm(Constraint):
# Aliases.
-# pylint: disable=invalid-name
max_norm = MaxNorm
non_neg = NonNeg
unit_norm = UnitNorm
min_max_norm = MinMaxNorm
-# pylint: enable=invalid-name
+# Legacy aliases.
+maxnorm = max_norm
+nonneg = non_neg
+unitnorm = unit_norm
def serialize(constraint):
diff --git a/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py b/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py
index 0570e9bc0c..cfd7df61d5 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/boston_housing.py
@@ -21,29 +21,27 @@ from __future__ import print_function
import numpy as np
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
-from tensorflow.python.util.tf_export import tf_export
-@tf_export('keras.datasets.boston_housing.load_data')
-def load_data(path='boston_housing.npz', seed=113, test_split=0.2):
+def load_data(path='boston_housing.npz', test_split=0.2, seed=113):
"""Loads the Boston Housing dataset.
Arguments:
path: path where to cache the dataset locally
(relative to ~/.keras/datasets).
+ test_split: fraction of the data to reserve as test set.
seed: Random seed for shuffling the data
before computing the test split.
- test_split: fraction of the data to reserve as test set.
Returns:
Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
"""
assert 0 <= test_split < 1
- fh = 'f553886a1f8d56431e820c5b82552d9d95cfcb96d1e678153f8839538947dff5'
path = get_file(
path,
origin='https://s3.amazonaws.com/keras-datasets/boston_housing.npz',
- file_hash=fh)
+ file_hash=
+ 'f553886a1f8d56431e820c5b82552d9d95cfcb96d1e678153f8839538947dff5')
f = np.load(path)
x = f['x']
y = f['y']
diff --git a/tensorflow/python/keras/_impl/keras/datasets/cifar.py b/tensorflow/python/keras/_impl/keras/datasets/cifar.py
index 564709c0ee..7ada3340a5 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/cifar.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/cifar.py
@@ -12,9 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Utilities used by the CIFAR10 and CIFAR100 datasets.
+"""Utilities common to CIFAR10 and CIFAR100 datasets.
"""
-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
diff --git a/tensorflow/python/keras/_impl/keras/datasets/cifar10.py b/tensorflow/python/keras/_impl/keras/datasets/cifar10.py
index 1971f434b9..fb9d98d42c 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/cifar10.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/cifar10.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""CIFAR10 small image classification dataset.
+"""CIFAR10 small images classification dataset.
"""
from __future__ import absolute_import
from __future__ import division
@@ -25,10 +25,8 @@ import numpy as np
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.datasets.cifar import load_batch
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
-from tensorflow.python.util.tf_export import tf_export
-@tf_export('keras.datasets.cifar10.load_data')
def load_data():
"""Loads CIFAR10 dataset.
diff --git a/tensorflow/python/keras/_impl/keras/datasets/cifar100.py b/tensorflow/python/keras/_impl/keras/datasets/cifar100.py
index f4039e9350..95aace599a 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/cifar100.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/cifar100.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""CIFAR100 small image classification dataset.
+"""CIFAR100 small images classification dataset.
"""
from __future__ import absolute_import
from __future__ import division
@@ -25,10 +25,8 @@ import numpy as np
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.datasets.cifar import load_batch
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
-from tensorflow.python.util.tf_export import tf_export
-@tf_export('keras.datasets.cifar100.load_data')
def load_data(label_mode='fine'):
"""Loads CIFAR100 dataset.
@@ -42,7 +40,7 @@ def load_data(label_mode='fine'):
ValueError: in case of invalid `label_mode`.
"""
if label_mode not in ['fine', 'coarse']:
- raise ValueError('label_mode must be one of "fine" "coarse".')
+ raise ValueError('`label_mode` must be one of `"fine"`, `"coarse"`.')
dirname = 'cifar-100-python'
origin = 'https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz'
diff --git a/tensorflow/python/keras/_impl/keras/datasets/fashion_mnist.py b/tensorflow/python/keras/_impl/keras/datasets/fashion_mnist.py
index 17be684e4f..b9ae41a0d4 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/fashion_mnist.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/fashion_mnist.py
@@ -20,7 +20,9 @@ from __future__ import print_function
import gzip
import os
+
import numpy as np
+
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
@@ -38,9 +40,8 @@ def load_data():
]
paths = []
- for given_file in files:
- paths.append(
- get_file(given_file, origin=base + given_file, cache_subdir=dirname))
+ for fname in files:
+ paths.append(get_file(fname, origin=base + fname, cache_subdir=dirname))
with gzip.open(paths[0], 'rb') as lbpath:
y_train = np.frombuffer(lbpath.read(), np.uint8, offset=8)
diff --git a/tensorflow/python/keras/_impl/keras/datasets/imdb.py b/tensorflow/python/keras/_impl/keras/datasets/imdb.py
index 7946c46960..880c9c821b 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/imdb.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/imdb.py
@@ -1,4 +1,4 @@
-# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2015 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,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""IMDB movie review sentiment classification dataset.
+"""IMDB sentiment classification dataset.
"""
from __future__ import absolute_import
from __future__ import division
@@ -21,13 +21,12 @@ from __future__ import print_function
import json
import numpy as np
-from six.moves import zip # pylint: disable=redefined-builtin
+from tensorflow.python.keras._impl.keras.preprocessing.sequence import _remove_long_seq
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
-from tensorflow.python.util.tf_export import tf_export
+from tensorflow.python.platform import tf_logging as logging
-@tf_export('keras.datasets.imdb.load_data')
def load_data(path='imdb.npz',
num_words=None,
skip_top=0,
@@ -35,7 +34,8 @@ def load_data(path='imdb.npz',
seed=113,
start_char=1,
oov_char=2,
- index_from=3):
+ index_from=3,
+ **kwargs):
"""Loads the IMDB dataset.
Arguments:
@@ -52,6 +52,7 @@ def load_data(path='imdb.npz',
oov_char: words that were cut out because of the `num_words`
or `skip_top` limit will be replaced with this character.
index_from: index actual words with this index and higher.
+ **kwargs: Used for backwards compatibility.
Returns:
Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
@@ -66,14 +67,21 @@ def load_data(path='imdb.npz',
Words that were not seen in the training set but are in the test set
have simply been skipped.
"""
+ # Legacy support
+ if 'nb_words' in kwargs:
+ logging.warning('The `nb_words` argument in `load_data` '
+ 'has been renamed `num_words`.')
+ num_words = kwargs.pop('nb_words')
+ if kwargs:
+ raise TypeError('Unrecognized keyword arguments: ' + str(kwargs))
+
path = get_file(
path,
origin='https://s3.amazonaws.com/text-datasets/imdb.npz',
file_hash='599dadb1135973df5b59232a0e9a887c')
- f = np.load(path)
- x_train, labels_train = f['x_train'], f['y_train']
- x_test, labels_test = f['x_test'], f['y_test']
- f.close()
+ with np.load(path) as f:
+ x_train, labels_train = f['x_train'], f['y_train']
+ x_test, labels_test = f['x_test'], f['y_test']
np.random.seed(seed)
indices = np.arange(len(x_train))
@@ -95,14 +103,7 @@ def load_data(path='imdb.npz',
xs = [[w + index_from for w in x] for x in xs]
if maxlen:
- new_xs = []
- new_labels = []
- for x, y in zip(xs, labels):
- if len(x) < maxlen:
- new_xs.append(x)
- new_labels.append(y)
- xs = new_xs
- labels = new_labels
+ xs, labels = _remove_long_seq(maxlen, xs, labels)
if not xs:
raise ValueError('After filtering for sequences shorter than maxlen=' +
str(maxlen) + ', no sequence was kept. '
@@ -114,28 +115,19 @@ def load_data(path='imdb.npz',
# reserve 'index_from' (=3 by default) characters:
# 0 (padding), 1 (start), 2 (OOV)
if oov_char is not None:
- xs = [[oov_char if (w >= num_words or w < skip_top) else w for w in x]
- for x in xs]
+ xs = [
+ [w if (skip_top <= w < num_words) else oov_char for w in x] for x in xs
+ ]
else:
- new_xs = []
- for x in xs:
- nx = []
- for w in x:
- if skip_top <= w < num_words:
- nx.append(w)
- new_xs.append(nx)
- xs = new_xs
-
- x_train = np.array(xs[:len(x_train)])
- y_train = np.array(labels[:len(x_train)])
+ xs = [[w for w in x if skip_top <= w < num_words] for x in xs]
- x_test = np.array(xs[len(x_train):])
- y_test = np.array(labels[len(x_train):])
+ idx = len(x_train)
+ x_train, y_train = np.array(xs[:idx]), np.array(labels[:idx])
+ x_test, y_test = np.array(xs[idx:]), np.array(labels[idx:])
return (x_train, y_train), (x_test, y_test)
-@tf_export('keras.datasets.imdb.get_word_index')
def get_word_index(path='imdb_word_index.json'):
"""Retrieves the dictionary mapping word indices back to words.
@@ -147,7 +139,8 @@ def get_word_index(path='imdb_word_index.json'):
"""
path = get_file(
path,
- origin='https://s3.amazonaws.com/text-datasets/imdb_word_index.json')
+ origin='https://s3.amazonaws.com/text-datasets/imdb_word_index.json',
+ file_hash='bfafd718b763782e994055a2d397834f')
f = open(path)
data = json.load(f)
f.close()
diff --git a/tensorflow/python/keras/_impl/keras/datasets/mnist.py b/tensorflow/python/keras/_impl/keras/datasets/mnist.py
index e9f5348015..ec12a31dcf 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/mnist.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/mnist.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""MNIST handwritten digits classification dataset.
+"""MNIST handwritten digits dataset.
"""
from __future__ import absolute_import
from __future__ import division
@@ -21,10 +21,8 @@ from __future__ import print_function
import numpy as np
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
-from tensorflow.python.util.tf_export import tf_export
-@tf_export('keras.datasets.mnist.load_data')
def load_data(path='mnist.npz'):
"""Loads the MNIST dataset.
@@ -40,9 +38,7 @@ def load_data(path='mnist.npz'):
origin='https://s3.amazonaws.com/img-datasets/mnist.npz',
file_hash='8a61469f7ea1b51cbae51d4f78837e45')
f = np.load(path)
- x_train = f['x_train']
- y_train = f['y_train']
- x_test = f['x_test']
- y_test = f['y_test']
+ x_train, y_train = f['x_train'], f['y_train']
+ x_test, y_test = f['x_test'], f['y_test']
f.close()
return (x_train, y_train), (x_test, y_test)
diff --git a/tensorflow/python/keras/_impl/keras/datasets/reuters.py b/tensorflow/python/keras/_impl/keras/datasets/reuters.py
index 6da5aa4b5e..95cf8852a9 100644
--- a/tensorflow/python/keras/_impl/keras/datasets/reuters.py
+++ b/tensorflow/python/keras/_impl/keras/datasets/reuters.py
@@ -12,9 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Reuters newswire topic classification dataset.
+"""Reuters topic classification dataset.
"""
-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
@@ -22,13 +21,12 @@ from __future__ import print_function
import json
import numpy as np
-from six.moves import zip # pylint: disable=redefined-builtin
+from tensorflow.python.keras._impl.keras.preprocessing.sequence import _remove_long_seq
from tensorflow.python.keras._impl.keras.utils.data_utils import get_file
-from tensorflow.python.util.tf_export import tf_export
+from tensorflow.python.platform import tf_logging as logging
-@tf_export('keras.datasets.reuters.load_data')
def load_data(path='reuters.npz',
num_words=None,
skip_top=0,
@@ -37,7 +35,8 @@ def load_data(path='reuters.npz',
seed=113,
start_char=1,
oov_char=2,
- index_from=3):
+ index_from=3,
+ **kwargs):
"""Loads the Reuters newswire classification dataset.
Arguments:
@@ -55,6 +54,7 @@ def load_data(path='reuters.npz',
oov_char: words that were cut out because of the `num_words`
or `skip_top` limit will be replaced with this character.
index_from: index actual words with this index and higher.
+ **kwargs: Used for backwards compatibility.
Returns:
Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
@@ -65,14 +65,20 @@ def load_data(path='reuters.npz',
Words that were not seen in the training set but are in the test set
have simply been skipped.
"""
+ # Legacy support
+ if 'nb_words' in kwargs:
+ logging.warning('The `nb_words` argument in `load_data` '
+ 'has been renamed `num_words`.')
+ num_words = kwargs.pop('nb_words')
+ if kwargs:
+ raise TypeError('Unrecognized keyword arguments: ' + str(kwargs))
+
path = get_file(
path,
origin='https://s3.amazonaws.com/text-datasets/reuters.npz',
file_hash='87aedbeb0cb229e378797a632c1997b6')
- npzfile = np.load(path)
- xs = npzfile['x']
- labels = npzfile['y']
- npzfile.close()
+ with np.load(path) as f:
+ xs, labels = f['x'], f['y']
np.random.seed(seed)
indices = np.arange(len(xs))
@@ -80,22 +86,13 @@ def load_data(path='reuters.npz',
xs = xs[indices]
labels = labels[indices]
- np.random.shuffle(labels)
-
if start_char is not None:
xs = [[start_char] + [w + index_from for w in x] for x in xs]
elif index_from:
xs = [[w + index_from for w in x] for x in xs]
if maxlen:
- new_xs = []
- new_labels = []
- for x, y in zip(xs, labels):
- if len(x) < maxlen:
- new_xs.append(x)
- new_labels.append(y)
- xs = new_xs
- labels = new_labels
+ xs, labels = _remove_long_seq(maxlen, xs, labels)
if not num_words:
num_words = max([max(x) for x in xs])
@@ -104,28 +101,17 @@ def load_data(path='reuters.npz',
# reserve 'index_from' (=3 by default) characters:
# 0 (padding), 1 (start), 2 (OOV)
if oov_char is not None:
- xs = [[oov_char if (w >= num_words or w < skip_top) else w for w in x]
- for x in xs]
+ xs = [[w if skip_top <= w < num_words else oov_char for w in x] for x in xs]
else:
- new_xs = []
- for x in xs:
- nx = []
- for w in x:
- if skip_top <= w < num_words:
- nx.append(w)
- new_xs.append(nx)
- xs = new_xs
-
- x_train = np.array(xs[:int(len(xs) * (1 - test_split))])
- y_train = np.array(labels[:int(len(xs) * (1 - test_split))])
+ xs = [[w for w in x if skip_top <= w < num_words] for x in xs]
- x_test = np.array(xs[int(len(xs) * (1 - test_split)):])
- y_test = np.array(labels[int(len(xs) * (1 - test_split)):])
+ idx = int(len(xs) * (1 - test_split))
+ x_train, y_train = np.array(xs[:idx]), np.array(labels[:idx])
+ x_test, y_test = np.array(xs[idx:]), np.array(labels[idx:])
return (x_train, y_train), (x_test, y_test)
-@tf_export('keras.datasets.reuters.get_word_index')
def get_word_index(path='reuters_word_index.json'):
"""Retrieves the dictionary mapping word indices back to words.
diff --git a/tensorflow/python/keras/_impl/keras/engine/topology.py b/tensorflow/python/keras/_impl/keras/engine/topology.py
index d6e0be8e43..64aa868f38 100644
--- a/tensorflow/python/keras/_impl/keras/engine/topology.py
+++ b/tensorflow/python/keras/_impl/keras/engine/topology.py
@@ -27,6 +27,7 @@ import numpy as np
from six.moves import zip # pylint: disable=redefined-builtin
from tensorflow.python.eager import context
+from tensorflow.python.framework import tensor_shape
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import constraints
from tensorflow.python.keras._impl.keras import initializers
@@ -712,8 +713,8 @@ class Network(tf_network.GraphNetwork, Layer):
for layer in self._output_layers:
self.output_names.append(layer.name)
- self.internal_input_shapes = [K.int_shape(x) for x in self.inputs]
- self.internal_output_shapes = [K.int_shape(x) for x in self.outputs]
+ self._internal_input_shapes = [K.int_shape(x) for x in self.inputs]
+ self._internal_output_shapes = [K.int_shape(x) for x in self.outputs]
@property
def uses_learning_phase(self):
@@ -1303,18 +1304,17 @@ def preprocess_weights_for_loading(layer,
Returns:
A list of weights values (Numpy arrays).
"""
- if original_keras_version == '1':
- if layer.__class__.__name__ == 'Bidirectional':
- num_weights_per_layer = len(weights) // 2
-
- forward_weights = preprocess_weights_for_loading(
- layer.forward_layer, weights[:num_weights_per_layer],
- original_keras_version, original_backend)
- backward_weights = preprocess_weights_for_loading(
- layer.backward_layer, weights[num_weights_per_layer:],
- original_keras_version, original_backend)
- weights = forward_weights + backward_weights
+ if layer.__class__.__name__ == 'Bidirectional':
+ num_weights_per_layer = len(weights) // 2
+ forward_weights = preprocess_weights_for_loading(
+ layer.forward_layer, weights[:num_weights_per_layer],
+ original_keras_version, original_backend)
+ backward_weights = preprocess_weights_for_loading(
+ layer.backward_layer, weights[num_weights_per_layer:],
+ original_keras_version, original_backend)
+ weights = forward_weights + backward_weights
+ if original_keras_version == '1':
if layer.__class__.__name__ == 'TimeDistributed':
weights = preprocess_weights_for_loading(
layer.layer, weights, original_keras_version, original_backend)
@@ -1418,7 +1418,7 @@ def preprocess_weights_for_loading(layer,
conv_layers = ['Conv1D', 'Conv2D', 'Conv3D', 'Conv2DTranspose', 'ConvLSTM2D']
if layer.__class__.__name__ in conv_layers:
- if original_backend and K.backend() != original_backend:
+ if original_backend == 'theano':
weights[0] = conv_utils.convert_kernel(weights[0])
if layer.__class__.__name__ == 'ConvLSTM2D':
weights[1] = conv_utils.convert_kernel(weights[1])
@@ -1427,10 +1427,9 @@ def preprocess_weights_for_loading(layer,
if layer.__class__.__name__ == 'ConvLSTM2D':
weights[1] = np.transpose(weights[1], (3, 2, 0, 1))
- # convert the weights of CuDNNLSTM so that they could be loaded into LSTM
+ # Convert the weights of CuDNNLSTM so that they could be loaded into LSTM
if layer.__class__.__name__ == 'LSTM' and len(weights) == 3:
- # determine if we're loading a CuDNNLSTM layer from the number of bias
- # weights:
+ # Determine if loading a CuDNNLSTM layer from the number of bias weights:
# CuDNNLSTM has (units * 8) weights; while LSTM has (units * 4)
# if there's no bias weight in the file, skip this conversion
units = weights[1].shape[0]
@@ -1572,3 +1571,31 @@ def load_weights_from_hdf5_group_by_name(f, layers):
for i in range(len(weight_values)):
weight_value_tuples.append((symbolic_weights[i], weight_values[i]))
K.batch_set_value(weight_value_tuples)
+
+
+def shape_type_conversion(fn):
+ """Decorator that handles tuple/TensorShape conversion.
+
+ Used in `compute_output_shape` and `build`.
+
+ Arguments:
+ fn: function to wrap.
+
+ Returns:
+ Wrapped function.
+ """
+
+ def wrapper(instance, input_shape):
+ if input_shape is not None:
+ if isinstance(input_shape, list):
+ input_shape = [
+ tuple(tensor_shape.TensorShape(x).as_list()) for x in input_shape]
+ else:
+ input_shape = tuple(tensor_shape.TensorShape(input_shape).as_list())
+ output_shape = fn(instance, input_shape)
+ if output_shape is not None:
+ if isinstance(output_shape, list):
+ return [tensor_shape.TensorShape(x) for x in output_shape]
+ return tensor_shape.TensorShape(output_shape)
+
+ return wrapper
diff --git a/tensorflow/python/keras/_impl/keras/engine/training.py b/tensorflow/python/keras/_impl/keras/engine/training.py
index debea2503e..699ae2edf0 100644
--- a/tensorflow/python/keras/_impl/keras/engine/training.py
+++ b/tensorflow/python/keras/_impl/keras/engine/training.py
@@ -12,9 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Keras training and evaluation routines.
+"""Training-related part of the Keras engine.
"""
-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
@@ -35,6 +34,11 @@ from tensorflow.python.keras._impl.keras.utils.data_utils import Sequence
from tensorflow.python.keras._impl.keras.utils.generic_utils import Progbar
from tensorflow.python.platform import tf_logging as logging
+try:
+ from scipy.sparse import issparse # pylint: disable=g-import-not-at-top
+except ImportError:
+ issparse = None
+
def _standardize_input_data(data,
names,
@@ -70,89 +74,72 @@ def _standardize_input_data(data,
return []
if data is None:
return [None for _ in range(len(names))]
+
if isinstance(data, dict):
- for key, value in data.items():
- if value.__class__.__name__ == 'DataFrame':
- data[key] = value.values
- arrays = []
- for name in names:
- if name not in data:
- raise ValueError('No data provided for "' + name +
- '". Need data for each key in: ' + str(names))
- arrays.append(data[name])
+ try:
+ data = [
+ data[x].values
+ if data[x].__class__.__name__ == 'DataFrame' else data[x]
+ for x in names
+ ]
+ data = [np.expand_dims(x, 1) if x.ndim == 1 else x for x in data]
+ except KeyError as e:
+ raise ValueError('No data provided for "' + e.args[0] + '". Need data '
+ 'for each key in: ' + str(names))
elif isinstance(data, list):
- for key, value in enumerate(data):
- if value.__class__.__name__ == 'DataFrame':
- data[key] = value.values
- if len(data) != len(names):
- if data and hasattr(data[0], 'shape'):
- raise ValueError(
- 'Error when checking model ' + exception_prefix +
- ': the list of Numpy arrays '
- 'that you are passing to your model '
- 'is not the size the model expected. '
- 'Expected to see ' + str(len(names)) + ' array(s), but instead got '
- 'the following list of ' + str(len(data)) + ' arrays: ' +
- str(data)[:200] + '...')
- else:
- if len(names) == 1:
- data = [np.asarray(data)]
- else:
- raise ValueError('Error when checking model ' + exception_prefix +
- ': you are passing a list as '
- 'input to your model, '
- 'but the model expects '
- 'a list of ' + str(len(names)) +
- ' Numpy arrays instead. '
- 'The list you passed was: ' + str(data)[:200])
- arrays = data
- elif data.__class__.__name__ == 'DataFrame':
- # test if data is a DataFrame, without pandas installed
- arrays = data.values
+ data = [
+ x.values if x.__class__.__name__ == 'DataFrame' else x for x in data
+ ]
+ data = [
+ np.expand_dims(x, 1) if x is not None and x.ndim == 1 else x
+ for x in data
+ ]
else:
- if not hasattr(data, 'shape'):
+ data = data.values if data.__class__.__name__ == 'DataFrame' else data
+ data = [np.expand_dims(data, 1)] if data.ndim == 1 else [data]
+
+ if len(data) != len(names):
+ if data and hasattr(data[0], 'shape'):
+ raise ValueError('Error when checking model ' + exception_prefix +
+ ': the list of Numpy arrays that you are passing to '
+ 'your model is not the size the model expected. '
+ 'Expected to see ' + str(len(names)) + ' array(s), '
+ 'but instead got the following list of ' +
+ str(len(data)) + ' arrays: ' + str(data)[:200] + '...')
+ elif len(names) > 1:
+ raise ValueError(
+ 'Error when checking model ' + exception_prefix +
+ ': you are passing a list as input to your model, '
+ 'but the model expects a list of ' + str(len(names)) +
+ ' Numpy arrays instead. The list you passed was: ' + str(data)[:200])
+ elif len(data) == 1 and not hasattr(data[0], 'shape'):
raise TypeError('Error when checking model ' + exception_prefix +
- ': data should be a Numpy array, '
- 'or list/dict of Numpy arrays. '
- 'Found: ' + str(data)[:200] + '...')
- if len(names) > 1:
- # Case: model expects multiple inputs but only received
- # a single Numpy array.
- raise ValueError('The model expects ' + str(len(names)) + ' ' +
- exception_prefix +
- ' arrays, but only received one array. '
- 'Found: array with shape ' + str(data.shape))
- arrays = [data]
-
- # Make arrays at least 2D.
- for i in range(len(names)):
- array = arrays[i]
- if len(array.shape) == 1:
- array = np.expand_dims(array, 1)
- arrays[i] = array
+ ': data should be a Numpy array, or list/dict of '
+ 'Numpy arrays. Found: ' + str(data)[:200] + '...')
+ elif len(names) == 1:
+ data = [np.asarray(data)]
# Check shapes compatibility.
if shapes:
for i in range(len(names)):
- if shapes[i] is None:
- continue
- array = arrays[i]
- if len(array.shape) != len(shapes[i]):
- raise ValueError(
- 'Error when checking ' + exception_prefix + ': expected ' + names[i]
- + ' to have ' + str(len(shapes[i])) +
- ' dimensions, but got array with shape ' + str(array.shape))
- for j, (dim, ref_dim) in enumerate(zip(array.shape, shapes[i])):
- if not j and not check_batch_axis:
- # skip the first axis
- continue
- if ref_dim:
- if ref_dim != dim:
- raise ValueError('Error when checking ' + exception_prefix +
- ': expected ' + names[i] + ' to have shape ' +
- str(shapes[i]) + ' but got array with shape ' +
- str(array.shape))
- return arrays
+ if shapes[i] is not None:
+ data_shape = data[i].shape
+ shape = shapes[i]
+ if data[i].ndim != len(shape):
+ raise ValueError('Error when checking ' + exception_prefix +
+ ': expected ' + names[i] + ' to have ' +
+ str(len(shape)) + ' dimensions, but got array '
+ 'with shape ' + str(data_shape))
+ if not check_batch_axis:
+ data_shape = data_shape[1:]
+ shape = shape[1:]
+ for dim, ref_dim in zip(data_shape, shape):
+ if ref_dim != dim and ref_dim:
+ raise ValueError(
+ 'Error when checking ' + exception_prefix + ': expected ' +
+ names[i] + ' to have shape ' + str(shape) +
+ ' but got array with shape ' + str(data_shape))
+ return data
def _standardize_sample_or_class_weights(x_weight, output_names, weight_type):
@@ -193,10 +180,10 @@ def _standardize_sample_or_class_weights(x_weight, output_names, weight_type):
x_weights.append(x_weight.get(name))
return x_weights
else:
- raise TypeError('The model has multiple outputs, so `' + weight_type + '` '
- 'should be either a list or a dict. '
- 'Provided `' + weight_type + '` type not understood: ' +
- str(x_weight))
+ raise TypeError(
+ 'The model has multiple outputs, so `' + weight_type + '` '
+ 'should be either a list or a dict. '
+ 'Provided `' + weight_type + '` type not understood: ' + str(x_weight))
def _standardize_class_weights(class_weight, output_names):
@@ -234,12 +221,12 @@ def _check_array_lengths(inputs, targets, weights=None):
set_w = set_of_lengths(weights)
if len(set_x) > 1:
raise ValueError('All input arrays (x) should have '
- 'the same number of samples. Got array shapes: ' + str(
- [x.shape for x in inputs]))
+ 'the same number of samples. Got array shapes: ' +
+ str([x.shape for x in inputs]))
if len(set_y) > 1:
raise ValueError('All target arrays (y) should have '
- 'the same number of samples. Got array shapes: ' + str(
- [y.shape for y in targets]))
+ 'the same number of samples. Got array shapes: ' +
+ str([y.shape for y in targets]))
if set_x and set_y and list(set_x)[0] != list(set_y)[0]:
raise ValueError('Input arrays should have '
'the same number of samples as target arrays. '
@@ -247,8 +234,8 @@ def _check_array_lengths(inputs, targets, weights=None):
'and ' + str(list(set_y)[0]) + ' target samples.')
if len(set_w) > 1:
raise ValueError('All sample_weight arrays should have '
- 'the same number of samples. Got array shapes: ' + str(
- [w.shape for w in weights]))
+ 'the same number of samples. Got array shapes: ' +
+ str([w.shape for w in weights]))
if set_y and set_w and list(set_y)[0] != list(set_w)[0]:
raise ValueError('Sample_weight arrays should have '
'the same number of samples as target arrays. Got ' +
@@ -528,16 +515,16 @@ def _standardize_weights(y,
if sample_weight is not None:
if len(sample_weight.shape) > len(y.shape):
- raise ValueError('Found a sample_weight with shape' +
- str(sample_weight.shape) + '.'
- 'Expected sample_weight with rank '
- 'less than or equal to ' + str(len(y.shape)))
+ raise ValueError(
+ 'Found a sample_weight with shape' + str(sample_weight.shape) + '.'
+ 'Expected sample_weight with rank '
+ 'less than or equal to ' + str(len(y.shape)))
if y.shape[:sample_weight.ndim] != sample_weight.shape:
- raise ValueError('Found a sample_weight array with shape ' +
- str(sample_weight.shape) + ' for an input with shape ' +
- str(y.shape) + '. '
- 'sample_weight cannot be broadcast.')
+ raise ValueError(
+ 'Found a sample_weight array with shape ' + str(sample_weight.shape) +
+ ' for an input with shape ' + str(y.shape) + '. '
+ 'sample_weight cannot be broadcast.')
return sample_weight
elif isinstance(class_weight, dict):
if len(y.shape) > 2:
@@ -632,7 +619,6 @@ class Model(Network):
"""
loss = loss or {}
self.optimizer = optimizers.get(optimizer)
- self.sample_weight_mode = sample_weight_mode
self.loss = loss
self.loss_weights = loss_weights
self.sample_weight_mode = sample_weight_mode
@@ -641,10 +627,10 @@ class Model(Network):
if isinstance(loss, dict):
for name in loss:
if name not in self.output_names:
- raise ValueError('Unknown entry in loss '
- 'dictionary: "' + name + '". '
- 'Only expected the following keys: ' +
- str(self.output_names))
+ raise ValueError(
+ 'Unknown entry in loss '
+ 'dictionary: "' + name + '". '
+ 'Only expected the following keys: ' + str(self.output_names))
loss_functions = []
for name in self.output_names:
if name not in loss:
@@ -657,7 +643,7 @@ class Model(Network):
elif isinstance(loss, list):
if len(loss) != len(self.outputs):
raise ValueError('When passing a list as loss, '
- 'it should have one entry per model output. '
+ 'it should have one entry per model outputs. '
'The model has ' + str(len(self.outputs)) +
' outputs, but you passed loss=' + str(loss))
loss_functions = [losses.get(l) for l in loss]
@@ -690,20 +676,20 @@ class Model(Network):
elif isinstance(loss_weights, dict):
for name in loss_weights:
if name not in self.output_names:
- raise ValueError('Unknown entry in loss_weights '
- 'dictionary: "' + name + '". '
- 'Only expected the following keys: ' +
- str(self.output_names))
+ raise ValueError(
+ 'Unknown entry in loss_weights '
+ 'dictionary: "' + name + '". '
+ 'Only expected the following keys: ' + str(self.output_names))
loss_weights_list = []
for name in self.output_names:
loss_weights_list.append(loss_weights.get(name, 1.))
elif isinstance(loss_weights, list):
if len(loss_weights) != len(self.outputs):
- raise ValueError('When passing a list as loss_weights, '
- 'it should have one entry per model output. '
- 'The model has ' + str(len(self.outputs)) +
- ' outputs, but you passed loss_weights=' +
- str(loss_weights))
+ raise ValueError(
+ 'When passing a list as loss_weights, '
+ 'it should have one entry per model output. '
+ 'The model has ' + str(len(self.outputs)) +
+ ' outputs, but you passed loss_weights=' + str(loss_weights))
loss_weights_list = loss_weights
else:
raise TypeError('Could not interpret loss_weights argument: ' +
@@ -715,22 +701,22 @@ class Model(Network):
if target_tensors is not None:
if isinstance(target_tensors, list):
if len(target_tensors) != len(self.outputs):
- raise ValueError('When passing a list as `target_tensors`, '
- 'it should have one entry per model output. '
- 'The model has ' + str(len(self.outputs)) +
- ' outputs, but you passed target_tensors=' +
- str(target_tensors))
+ raise ValueError(
+ 'When passing a list as `target_tensors`, '
+ 'it should have one entry per model output. '
+ 'The model has ' + str(len(self.outputs)) +
+ ' outputs, but you passed target_tensors=' + str(target_tensors))
elif isinstance(target_tensors, dict):
for name in target_tensors:
if name not in self.output_names:
- raise ValueError('Unknown entry in `target_tensors` '
- 'dictionary: "' + name + '". '
- 'Only expected the following keys: ' +
- str(self.output_names))
- target_tensors_ = []
+ raise ValueError(
+ 'Unknown entry in `target_tensors` '
+ 'dictionary: "' + name + '". '
+ 'Only expected the following keys: ' + str(self.output_names))
+ tmp_target_tensors = []
for name in self.output_names:
- target_tensors_.append(target_tensors.get(name, None))
- target_tensors = target_tensors_
+ tmp_target_tensors.append(target_tensors.get(name, None))
+ target_tensors = tmp_target_tensors
else:
raise TypeError('Expected `target_tensors` to be '
'a list or dict, but got:', target_tensors)
@@ -738,7 +724,7 @@ class Model(Network):
if i in skip_target_indices:
self.targets.append(None)
else:
- shape = self.internal_output_shapes[i]
+ shape = self._internal_output_shapes[i]
name = self.output_names[i]
if target_tensors is not None:
target = target_tensors[i]
@@ -766,19 +752,19 @@ class Model(Network):
if isinstance(sample_weight_mode, dict):
for name in sample_weight_mode:
if name not in self.output_names:
- raise ValueError('Unknown entry in '
- 'sample_weight_mode dictionary: "' + name + '". '
- 'Only expected the following keys: ' +
- str(self.output_names))
+ raise ValueError(
+ 'Unknown entry in '
+ 'sample_weight_mode dictionary: "' + name + '". '
+ 'Only expected the following keys: ' + str(self.output_names))
for i, name in enumerate(self.output_names):
if i in skip_target_weighing_indices:
weight = None
sample_weight_modes.append(None)
else:
if name not in sample_weight_mode:
- raise ValueError('Output "' + name +
- '" missing from sample_weight_modes '
- 'dictionary')
+ raise ValueError(
+ 'Output "' + name + '" missing from sample_weight_modes '
+ 'dictionary')
if sample_weight_mode.get(name) == 'temporal':
weight = K.placeholder(ndim=2, name=name + '_sample_weights')
sample_weight_modes.append('temporal')
@@ -894,23 +880,36 @@ class Model(Network):
metric_name_prefix = 'weighted_' if weights is not None else ''
for metric in metrics:
- if metric == 'accuracy' or metric == 'acc':
- # custom handling of accuracy
+ if metric in ('accuracy', 'acc', 'crossentropy', 'ce'):
+ # custom handling of accuracy/crossentropy
# (because of class mode duality)
- output_shape = self.internal_output_shapes[i]
+ output_shape = self._internal_output_shapes[i]
if (output_shape[-1] == 1 or
self.loss_functions[i] == losses.binary_crossentropy):
- # case: binary accuracy
- acc_fn = metrics_module.binary_accuracy
+ # case: binary accuracy/crossentropy
+ if metric in ('accuracy', 'acc'):
+ acc_fn = metrics_module.binary_accuracy
+ elif metric in ('crossentropy', 'ce'):
+ acc_fn = metrics_module.binary_crossentropy
elif self.loss_functions[
i] == losses.sparse_categorical_crossentropy:
- # case: categorical accuracy with sparse targets
- acc_fn = metrics_module.sparse_categorical_accuracy
+ # case: categorical accuracy/crossentropy with sparse targets
+ if metric in ('accuracy', 'acc'):
+ acc_fn = metrics_module.sparse_categorical_accuracy
+ elif metric in ('crossentropy', 'ce'):
+ acc_fn = metrics_module.sparse_categorical_crossentropy
else:
- acc_fn = metrics_module.categorical_accuracy
-
+ # case: categorical accuracy/crossentropy
+ if metric in ('accuracy', 'acc'):
+ acc_fn = metrics_module.categorical_accuracy
+ elif metric in ('crossentropy', 'ce'):
+ acc_fn = metrics_module.categorical_crossentropy
+ if metric in ('accuracy', 'acc'):
+ suffix = 'acc'
+ elif metric in ('crossentropy', 'ce'):
+ suffix = 'ce'
weighted_metric_fn = _weighted_masked_objective(acc_fn)
- metric_name = metric_name_prefix + 'acc'
+ metric_name = metric_name_prefix + suffix
else:
metric_fn = metrics_module.get(metric)
weighted_metric_fn = _weighted_masked_objective(metric_fn)
@@ -949,7 +948,7 @@ class Model(Network):
"""Check trainable weights count consistency.
This will raise a warning if `trainable_weights` and
- `_collected_trainable_weights` are consistent (i.e. have the same
+ `_collected_trainable_weights` are inconsistent (i.e. have different
number of parameters).
Inconsistency will typically arise when one modifies `model.trainable`
without calling `model.compile` again.
@@ -959,9 +958,10 @@ class Model(Network):
if len(self.trainable_weights) != len(self._collected_trainable_weights):
logging.warning(
- 'Discrepancy between trainable weights and collected trainable'
- ' weights, did you set `model.trainable` without calling'
- ' `model.compile` after ?')
+ UserWarning(
+ 'Discrepancy between trainable weights and collected trainable'
+ ' weights, did you set `model.trainable` without calling'
+ ' `model.compile` after ?'))
def _make_train_function(self):
if not hasattr(self, 'train_function'):
@@ -1050,18 +1050,21 @@ class Model(Network):
processed based on the size of the first dimension of the
first input numpy array. When steps is not `None` and
`batch_size` is `None`, returns `None`.
+
+ Raises:
+ ValueError: In case of invalid arguments.
"""
if steps is not None:
num_samples = None
if batch_size is not None:
- raise ValueError('If ' + steps_name +
- ' is set, the `batch_size` must be None.')
+ raise ValueError(
+ 'If ' + steps_name + ' is set, the `batch_size` must be None.')
elif ins and hasattr(ins[0], 'shape'):
num_samples = ins[0].shape[0]
else:
- raise ValueError('Either the input data should have '
- 'a defined shape, or ' + steps_name +
- ' should be specified.')
+ raise ValueError(
+ 'Either the input data should have '
+ 'a defined shape, or ' + steps_name + ' should be specified.')
return num_samples
def _fit_loop(self,
@@ -1104,31 +1107,33 @@ class Model(Network):
steps_per_epoch: Total number of steps (batches of samples)
before declaring one epoch finished and starting the
next epoch. Ignored with the default value of `None`.
- validation_steps: Number of steps to run validation for (only if doing
- validation from data tensors). Ignored with default value of `None`.
+ validation_steps: Number of steps to run validation for
+ (only if doing validation from data tensors).
+ Ignored with the default value of `None`.
Returns:
`History` object.
Raises:
- ValueError: In case of invalid argument values.
+ ValueError: in case of invalid arguments.
"""
do_validation = False
if val_f and val_ins:
do_validation = True
- if (verbose and ins and
- hasattr(ins[0], 'shape') and hasattr(val_ins[0], 'shape')):
+ if verbose and ins and hasattr(ins[0], 'shape') and hasattr(
+ val_ins[0], 'shape'):
print('Train on %d samples, validate on %d samples' %
(ins[0].shape[0], val_ins[0].shape[0]))
if validation_steps:
- if steps_per_epoch is None:
- raise ValueError('Can only use `validation_steps` when doing step-wise '
- 'training, i.e. `steps_per_epoch` must be set.')
do_validation = True
+ if steps_per_epoch is None:
+ raise ValueError('Can only use `validation_steps` '
+ 'when doing step-wise '
+ 'training, i.e. `steps_per_epoch` '
+ 'must be set.')
num_train_samples = self._check_num_samples(
ins, batch_size, steps_per_epoch, 'steps_per_epoch')
-
if num_train_samples is not None:
index_array = np.arange(num_train_samples)
@@ -1165,6 +1170,13 @@ class Model(Network):
for cbk in callbacks:
cbk.validation_data = val_ins
+ # To prevent a slowdown, we find beforehand the arrays that need conversion.
+ feed = self._feed_inputs + self._feed_targets + self._feed_sample_weights
+ indices_for_conversion_to_dense = []
+ for i in range(len(feed)):
+ if issparse is not None and issparse(ins[i]) and not K.is_sparse(feed[i]):
+ indices_for_conversion_to_dense.append(i)
+
for epoch in range(initial_epoch, epochs):
callbacks.on_epoch_begin(epoch)
epoch_logs = {}
@@ -1220,6 +1232,9 @@ class Model(Network):
batch_logs['batch'] = batch_index
batch_logs['size'] = len(batch_ids)
callbacks.on_batch_begin(batch_index, batch_logs)
+ for i in indices_for_conversion_to_dense:
+ ins_batch[i] = ins_batch[i].toarray()
+
outs = f(ins_batch)
if not isinstance(outs, list):
outs = [outs]
@@ -1268,6 +1283,13 @@ class Model(Network):
progbar = Progbar(target=steps)
else:
progbar = Progbar(target=num_samples)
+
+ indices_for_conversion_to_dense = []
+ for i in range(len(self._feed_inputs)):
+ if (issparse is not None and issparse(ins[i]) and
+ not K.is_sparse(self._feed_inputs[i])):
+ indices_for_conversion_to_dense.append(i)
+
if steps is not None:
# Step-based predictions.
# Since we do not know how many samples
@@ -1305,6 +1327,9 @@ class Model(Network):
ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
else:
ins_batch = _slice_arrays(ins, batch_ids)
+ for i in indices_for_conversion_to_dense:
+ ins_batch[i] = ins_batch[i].toarray()
+
batch_outs = f(ins_batch)
if not isinstance(batch_outs, list):
batch_outs = [batch_outs]
@@ -1341,12 +1366,19 @@ class Model(Network):
"""
num_samples = self._check_num_samples(ins, batch_size, steps, 'steps')
outs = []
-
if verbose == 1:
if steps is not None:
progbar = Progbar(target=steps)
else:
progbar = Progbar(target=num_samples)
+
+ # To prevent a slowdown, we find beforehand the arrays that need conversion.
+ feed = self._feed_inputs + self._feed_targets + self._feed_sample_weights
+ indices_for_conversion_to_dense = []
+ for i in range(len(feed)):
+ if issparse is not None and issparse(ins[i]) and not K.is_sparse(feed[i]):
+ indices_for_conversion_to_dense.append(i)
+
if steps is not None:
for step in range(steps):
batch_outs = f(ins)
@@ -1365,8 +1397,6 @@ class Model(Network):
for i in range(len(outs)):
outs[i] /= steps
else:
- if verbose == 1:
- progbar = Progbar(target=num_samples)
batches = _make_batches(num_samples, batch_size)
index_array = np.arange(num_samples)
for batch_index, (batch_start, batch_end) in enumerate(batches):
@@ -1376,6 +1406,8 @@ class Model(Network):
ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
else:
ins_batch = _slice_arrays(ins, batch_ids)
+ for i in indices_for_conversion_to_dense:
+ ins_batch[i] = ins_batch[i].toarray()
batch_outs = f(ins_batch)
if isinstance(batch_outs, list):
@@ -1484,7 +1516,8 @@ class Model(Network):
sample_weight=None,
initial_epoch=0,
steps_per_epoch=None,
- validation_steps=None):
+ validation_steps=None,
+ **kwargs):
"""Trains the model for a fixed number of epochs (iterations on a dataset).
Arguments:
@@ -1501,10 +1534,9 @@ class Model(Network):
dictionary mapping output names to Numpy arrays.
`y` can be `None` (default) if feeding from
TensorFlow data tensors.
- Can be `None` (default) if feeding from framework-native tensors.
batch_size: Integer or `None`.
Number of samples per gradient update.
- If unspecified, it will default to 32.
+ If unspecified, `batch_size` will default to 32.
epochs: Integer. Number of epochs to train the model.
An epoch is an iteration over the entire `x` and `y`
data provided.
@@ -1513,7 +1545,7 @@ class Model(Network):
The model is not trained for a number of iterations
given by `epochs`, but merely until the epoch
of index `epochs` is reached.
- verbose: 0, 1, or 2. Verbosity mode.
+ verbose: Integer. 0, 1, or 2. Verbosity mode.
0 = silent, 1 = progress bar, 2 = one line per epoch.
callbacks: List of `keras.callbacks.Callback` instances.
List of callbacks to apply during training.
@@ -1530,7 +1562,7 @@ class Model(Network):
`(x_val, y_val, val_sample_weights)` on which to evaluate
the loss and any model metrics at the end of each epoch.
The model will not be trained on this data.
- This will override `validation_split`.
+ `validation_data` will override `validation_split`.
shuffle: Boolean (whether to shuffle the training data
before each epoch) or str (for 'batch').
'batch' is a special option for dealing with the
@@ -1553,17 +1585,20 @@ class Model(Network):
to apply a different weight to every timestep of every sample.
In this case you should make sure to specify
`sample_weight_mode="temporal"` in `compile()`.
- initial_epoch: Epoch at which to start training
+ initial_epoch: Integer.
+ Epoch at which to start training
(useful for resuming a previous training run).
- steps_per_epoch: Total number of steps (batches of samples)
+ steps_per_epoch: Integer or `None`.
+ Total number of steps (batches of samples)
before declaring one epoch finished and starting the
next epoch. When training with input tensors such as
TensorFlow data tensors, the default `None` is equal to
- the number of unique samples in your dataset divided by
+ the number of samples in your dataset divided by
the batch size, or 1 if that cannot be determined.
validation_steps: Only relevant if `steps_per_epoch`
is specified. Total number of steps (batches of samples)
to validate before stopping.
+ **kwargs: Used for backwards compatibility.
Returns:
A `History` object. Its `History.history` attribute is
@@ -1572,12 +1607,21 @@ class Model(Network):
and validation metrics values (if applicable).
Raises:
+ RuntimeError: If the model was never compiled.
ValueError: In case of mismatch between the provided input data
and what the model expects.
"""
# Backwards compatibility
if batch_size is None and steps_per_epoch is None:
batch_size = 32
+ # Legacy support
+ if 'nb_epoch' in kwargs:
+ logging.warning(
+ 'The `nb_epoch` argument in `fit` '
+ 'has been renamed `epochs`.')
+ epochs = kwargs.pop('nb_epoch')
+ if kwargs:
+ raise TypeError('Unrecognized keyword arguments: ' + str(kwargs))
if x is None and y is None and steps_per_epoch is None:
raise ValueError('If fitting from data tensors, '
'you should specify the `steps_per_epoch` '
@@ -1590,10 +1634,8 @@ class Model(Network):
class_weight=class_weight,
check_batch_axis=False,
batch_size=batch_size)
-
# Prepare validation data.
do_validation = False
- val_ins = []
if validation_data:
do_validation = True
if len(validation_data) == 2:
@@ -1657,8 +1699,9 @@ class Model(Network):
'val_' + n for n in out_labels
]
else:
- val_f = None
callback_metrics = copy.copy(out_labels)
+ val_f = None
+ val_ins = []
# Delegate logic to `_fit_loop`.
return self._fit_loop(
@@ -1694,14 +1737,14 @@ class Model(Network):
If input layers in the model are named, you can also pass a
dictionary mapping input names to Numpy arrays.
`x` can be `None` (default) if feeding from
- framework-native tensors (e.g. TensorFlow data tensors).
+ TensorFlow data tensors.
y: Numpy array of target (label) data
(if the model has a single output),
or list of Numpy arrays (if the model has multiple outputs).
If output layers in the model are named, you can also pass a
dictionary mapping output names to Numpy arrays.
`y` can be `None` (default) if feeding from
- framework-native tensors (e.g. TensorFlow data tensors).
+ TensorFlow data tensors.
batch_size: Integer or `None`.
Number of samples per evaluation step.
If unspecified, `batch_size` will default to 32.
@@ -1721,8 +1764,7 @@ class Model(Network):
steps: Integer or `None`.
Total number of steps (batches of samples)
before declaring the evaluation round finished.
- The default `None` is equal to the number of unique samples in
- your dataset divided by the batch size.
+ Ignored with the default value of `None`.
Returns:
Scalar test loss (if the model has a single output and no metrics)
@@ -1731,7 +1773,7 @@ class Model(Network):
the display labels for the scalar outputs.
Raises:
- ValueError: In case of invalid arguments.
+ ValueError: in case of invalid arguments.
"""
# Backwards compatibility.
if batch_size is None and steps is None:
@@ -1890,6 +1932,9 @@ class Model(Network):
or list of scalars (if the model has multiple outputs
and/or metrics). The attribute `model.metrics_names` will give you
the display labels for the scalar outputs.
+
+ Raises:
+ ValueError: in case of invalid arguments.
"""
x, y, sample_weights = self._standardize_user_data(
x, y, sample_weight=sample_weight, check_batch_axis=True)
@@ -1937,8 +1982,7 @@ class Model(Network):
workers=1,
use_multiprocessing=False,
shuffle=True,
- initial_epoch=0,
- **kwargs):
+ initial_epoch=0):
"""Fits the model on data yielded batch-by-batch by a Python generator.
The generator is run in parallel to the model, for efficiency.
@@ -1950,22 +1994,31 @@ class Model(Network):
using `use_multiprocessing=True`.
Arguments:
- generator: A generator or an instance of Sequence (keras.utils.Sequence)
- object in order to avoid duplicate data when using multiprocessing.
+ generator: A generator or an instance of `Sequence`
+ (`keras.utils.Sequence`)
+ object in order to avoid duplicate data
+ when using multiprocessing.
The output of the generator must be either
- - a tuple (inputs, targets)
- - a tuple (inputs, targets, sample_weights).
- All arrays should contain the same number of samples.
+ - a tuple `(inputs, targets)`
+ - a tuple `(inputs, targets, sample_weights)`.
+ This tuple (a single output of the generator) makes a single batch.
+ Therefore, all arrays in this tuple must have the same length (equal
+ to the size of this batch). Different batches may have different
+ sizes.
+ For example, the last batch of the epoch is commonly smaller than
+ the
+ others, if the size of the dataset is not divisible by the batch
+ size.
The generator is expected to loop over its data
indefinitely. An epoch finishes when `steps_per_epoch`
batches have been seen by the model.
steps_per_epoch: Total number of steps (batches of samples)
to yield from `generator` before declaring one epoch
finished and starting the next epoch. It should typically
- be equal to the number of unique samples of your dataset
+ be equal to the number of samples of your dataset
divided by the batch size.
Optional for `Sequence`: if unspecified, will use
- `len(generator)` as a number of steps.
+ the `len(generator)` as a number of steps.
epochs: Integer, total number of iterations on the data.
verbose: Verbosity mode, 0, 1, or 2.
callbacks: List of callbacks to be called during training.
@@ -1977,27 +2030,28 @@ class Model(Network):
is a generator. Total number of steps (batches of samples)
to yield from `generator` before stopping.
Optional for `Sequence`: if unspecified, will use
- `len(generator)` as a number of steps.
+ the `len(validation_data)` as a number of steps.
class_weight: Dictionary mapping class indices to a weight
for the class.
- max_queue_size: Maximum size for the generator queue.
+ max_queue_size: Integer. Maximum size for the generator queue.
+ If unspecified, `max_queue_size` will default to 10.
workers: Integer. Maximum number of processes to spin up
when using process based threading.
If unspecified, `workers` will default to 1. If 0, will
execute the generator on the main thread.
- use_multiprocessing: If True, use process based threading.
+ use_multiprocessing: Boolean. If True, use process based threading.
+ If unspecified, `workers` will default to False.
Note that because
this implementation relies on multiprocessing,
you should not pass
non picklable arguments to the generator
as they can't be passed
easily to children processes.
- shuffle: Whether to shuffle the data at the beginning of each
- epoch. Only used with instances of `Sequence`
- (`keras.utils.Sequence`).
+ shuffle: Whether to shuffle the order of the batches at
+ the beginning of each epoch. Only used with instances
+ of `Sequence` (keras.utils.Sequence).
initial_epoch: Epoch at which to start training
(useful for resuming a previous training run)
- **kwargs: support for legacy arguments.
Returns:
A `History` object.
@@ -2023,19 +2077,6 @@ class Model(Network):
ValueError: In case the generator yields
data in an invalid format.
"""
- # Legacy support
- if 'max_q_size' in kwargs:
- max_queue_size = kwargs.pop('max_q_size')
- logging.warning('The argument `max_q_size` has been renamed '
- '`max_queue_size`. Update your method calls accordingly.')
- if 'pickle_safe' in kwargs:
- use_multiprocessing = kwargs.pop('pickle_safe')
- logging.warning('The argument `pickle_safe` has been renamed '
- '`use_multiprocessing`. '
- 'Update your method calls accordingly.')
- if kwargs:
- raise ValueError('Unrecognized keyword arguments: ' + str(kwargs))
-
wait_time = 0.01 # in seconds
epoch = initial_epoch
@@ -2046,10 +2087,11 @@ class Model(Network):
is_sequence = isinstance(generator, Sequence)
if not is_sequence and use_multiprocessing and workers > 1:
- logging.warning('Using a generator with `use_multiprocessing=True`'
+ logging.warning(
+ UserWarning('Using a generator with `use_multiprocessing=True`'
' and multiple workers may duplicate your data.'
' Please consider using the`keras.utils.Sequence'
- ' class.')
+ ' class.'))
if steps_per_epoch is None:
if is_sequence:
steps_per_epoch = len(generator)
@@ -2098,26 +2140,47 @@ class Model(Network):
})
callbacks.on_train_begin()
- if do_validation and not val_gen:
- if len(validation_data) == 2:
- val_x, val_y = validation_data # pylint: disable=unpacking-non-sequence
- val_sample_weight = None
- elif len(validation_data) == 3:
- val_x, val_y, val_sample_weight = validation_data # pylint: disable=unpacking-non-sequence
- else:
- raise ValueError('`validation_data` should be a tuple '
- '`(val_x, val_y, val_sample_weight)` '
- 'or `(val_x, val_y)`. Found: ' + str(validation_data))
- val_x, val_y, val_sample_weights = self._standardize_user_data(
- val_x, val_y, val_sample_weight)
- val_data = val_x + val_y + val_sample_weights
- if self.uses_learning_phase and not isinstance(K.learning_phase(), int):
- val_data += [0.]
- for cbk in callbacks:
- cbk.validation_data = val_data
enqueuer = None
+ val_enqueuer = None
try:
+ if do_validation:
+ if val_gen:
+ if workers > 0:
+ if isinstance(validation_data, Sequence):
+ val_enqueuer = OrderedEnqueuer(
+ validation_data, use_multiprocessing=use_multiprocessing)
+ if validation_steps is None:
+ validation_steps = len(validation_data)
+ else:
+ val_enqueuer = GeneratorEnqueuer(
+ validation_data,
+ use_multiprocessing=use_multiprocessing,
+ wait_time=wait_time)
+ val_enqueuer.start(workers=workers, max_queue_size=max_queue_size)
+ validation_generator = val_enqueuer.get()
+ else:
+ validation_generator = validation_data
+ else:
+ if len(validation_data) == 2:
+ val_x, val_y = validation_data # pylint: disable=unpacking-non-sequence
+ val_sample_weight = None
+ elif len(validation_data) == 3:
+ val_x, val_y, val_sample_weight = validation_data # pylint: disable=unpacking-non-sequence
+ else:
+ raise ValueError(
+ '`validation_data` should be a tuple '
+ '`(val_x, val_y, val_sample_weight)` '
+ 'or `(val_x, val_y)`. Found: ' + str(validation_data))
+ val_x, val_y, val_sample_weights = self._standardize_user_data(
+ val_x, val_y, val_sample_weight)
+ val_data = val_x + val_y + val_sample_weights
+ if self.uses_learning_phase and not isinstance(
+ K.learning_phase(), int):
+ val_data += [0.]
+ for cbk in callbacks:
+ cbk.validation_data = val_data
+
if workers > 0:
if is_sequence:
enqueuer = OrderedEnqueuer(
@@ -2135,6 +2198,8 @@ class Model(Network):
output_generator = generator
callback_model.stop_training = False
+ # Construct epoch logs.
+ epoch_logs = {}
while epoch < epochs:
callbacks.on_epoch_begin(epoch)
steps_done = 0
@@ -2178,8 +2243,6 @@ class Model(Network):
callbacks.on_batch_end(batch_index, batch_logs)
- # Construct epoch logs.
- epoch_logs = {}
batch_index += 1
steps_done += 1
@@ -2187,11 +2250,7 @@ class Model(Network):
if steps_done >= steps_per_epoch and do_validation:
if val_gen:
val_outs = self.evaluate_generator(
- validation_data,
- validation_steps,
- max_queue_size=max_queue_size,
- workers=workers,
- use_multiprocessing=use_multiprocessing)
+ validation_generator, validation_steps, workers=0)
else:
# No need for try/except because
# data has already been validated.
@@ -2216,8 +2275,12 @@ class Model(Network):
break
finally:
- if enqueuer is not None:
- enqueuer.stop()
+ try:
+ if enqueuer is not None:
+ enqueuer.stop()
+ finally:
+ if val_enqueuer is not None:
+ val_enqueuer.stop()
callbacks.on_train_end()
return self.history
@@ -2227,8 +2290,7 @@ class Model(Network):
steps=None,
max_queue_size=10,
workers=1,
- use_multiprocessing=False,
- **kwargs):
+ use_multiprocessing=False):
"""Evaluates the model on a data generator.
The generator should return the same kind of data
@@ -2256,7 +2318,6 @@ class Model(Network):
non picklable arguments to the generator
as they can't be passed
easily to children processes.
- **kwargs: support for legacy arguments.
Returns:
Scalar test loss (if the model has a single output and no metrics)
@@ -2265,22 +2326,12 @@ class Model(Network):
the display labels for the scalar outputs.
Raises:
+ ValueError: in case of invalid arguments.
+
+ Raises:
ValueError: In case the generator yields
data in an invalid format.
"""
- # Legacy support
- if 'max_q_size' in kwargs:
- max_queue_size = kwargs.pop('max_q_size')
- logging.warning('The argument `max_q_size` has been renamed '
- '`max_queue_size`. Update your method calls accordingly.')
- if 'pickle_safe' in kwargs:
- use_multiprocessing = kwargs.pop('pickle_safe')
- logging.warning('The argument `pickle_safe` has been renamed '
- '`use_multiprocessing`. '
- 'Update your method calls accordingly.')
- if kwargs:
- raise ValueError('Unrecognized keyword arguments: ' + str(kwargs))
-
self._make_test_function()
steps_done = 0
@@ -2289,10 +2340,11 @@ class Model(Network):
batch_sizes = []
is_sequence = isinstance(generator, Sequence)
if not is_sequence and use_multiprocessing and workers > 1:
- logging.warning('Using a generator with `use_multiprocessing=True`'
+ logging.warning(
+ UserWarning('Using a generator with `use_multiprocessing=True`'
' and multiple workers may duplicate your data.'
' Please consider using the`keras.utils.Sequence'
- ' class.')
+ ' class.'))
if steps is None:
if is_sequence:
steps = len(generator)
@@ -2368,8 +2420,7 @@ class Model(Network):
max_queue_size=10,
workers=1,
use_multiprocessing=False,
- verbose=0,
- **kwargs):
+ verbose=0):
"""Generates predictions for the input samples from a data generator.
The generator should return the same kind of data as accepted by
@@ -2377,9 +2428,9 @@ class Model(Network):
Arguments:
generator: Generator yielding batches of input samples
- or an instance of Sequence (keras.utils.Sequence)
- object in order to avoid duplicate data
- when using multiprocessing.
+ or an instance of Sequence (keras.utils.Sequence)
+ object in order to avoid duplicate data
+ when using multiprocessing.
steps: Total number of steps (batches of samples)
to yield from `generator` before stopping.
Optional for `Sequence`: if unspecified, will use
@@ -2397,7 +2448,6 @@ class Model(Network):
as they can't be passed
easily to children processes.
verbose: verbosity mode, 0 or 1.
- **kwargs: support for legacy arguments.
Returns:
Numpy array(s) of predictions.
@@ -2406,17 +2456,6 @@ class Model(Network):
ValueError: In case the generator yields
data in an invalid format.
"""
- # Legacy support
- if 'max_q_size' in kwargs:
- max_queue_size = kwargs.pop('max_q_size')
- logging.warning('The argument `max_q_size` has been renamed '
- '`max_queue_size`. Update your method calls accordingly.')
- if 'pickle_safe' in kwargs:
- use_multiprocessing = kwargs.pop('pickle_safe')
- logging.warning('The argument `pickle_safe` has been renamed '
- '`use_multiprocessing`. '
- 'Update your method calls accordingly.')
-
self._make_predict_function()
steps_done = 0
@@ -2424,10 +2463,11 @@ class Model(Network):
all_outs = []
is_sequence = isinstance(generator, Sequence)
if not is_sequence and use_multiprocessing and workers > 1:
- logging.warn('Using a generator with `use_multiprocessing=True`'
- ' and multiple workers may duplicate your data.'
- ' Please consider using the`keras.utils.Sequence'
- ' class.')
+ logging.warning(
+ UserWarning('Using a generator with `use_multiprocessing=True`'
+ ' and multiple workers may duplicate your data.'
+ ' Please consider using the`keras.utils.Sequence'
+ ' class.'))
if steps is None:
if is_sequence:
steps = len(generator)
@@ -2498,6 +2538,6 @@ class Model(Network):
else:
return np.concatenate(all_outs[0])
if steps_done == 1:
- return [out for out in all_outs]
+ return [out[0] for out in all_outs]
else:
return [np.concatenate(out) for out in all_outs]
diff --git a/tensorflow/python/keras/_impl/keras/engine/training_test.py b/tensorflow/python/keras/_impl/keras/engine/training_test.py
index 7650bfb6e8..5a033a04ad 100644
--- a/tensorflow/python/keras/_impl/keras/engine/training_test.py
+++ b/tensorflow/python/keras/_impl/keras/engine/training_test.py
@@ -28,6 +28,11 @@ from tensorflow.python.keras._impl.keras import testing_utils
from tensorflow.python.keras._impl.keras.engine.training import _weighted_masked_objective
from tensorflow.python.platform import test
+try:
+ import scipy.sparse as scipy_sparse # pylint: disable=g-import-not-at-top
+except ImportError:
+ scipy_sparse = None
+
class TrainingTest(test.TestCase):
@@ -169,7 +174,7 @@ class TrainingTest(test.TestCase):
with self.assertRaises(ValueError):
model.train_on_batch({'input_a': input_a_np},
[output_d_np, output_e_np])
- with self.assertRaises(TypeError):
+ with self.assertRaises(AttributeError):
model.fit(
[input_a_np, input_b_np], [output_d_np, output_e_np],
epochs=1,
@@ -177,7 +182,7 @@ class TrainingTest(test.TestCase):
verbose=0)
with self.assertRaises(ValueError):
model.train_on_batch([input_a_np], [output_d_np, output_e_np])
- with self.assertRaises(TypeError):
+ with self.assertRaises(AttributeError):
model.train_on_batch(1, [output_d_np, output_e_np])
with self.assertRaises(ValueError):
model.train_on_batch(input_a_np, [output_d_np, output_e_np])
@@ -312,6 +317,63 @@ class TrainingTest(test.TestCase):
model.compile(loss=None,
optimizer='rmsprop')
+ def test_training_on_sparse_data_with_dense_placeholders(self):
+ if scipy_sparse is None:
+ return
+
+ test_inputs = [
+ scipy_sparse.random(6, 3, density=0.25).tocsr() for _ in range(2)]
+ test_outputs = [
+ scipy_sparse.random(6, i, density=0.25).tocsr() for i in range(3, 5)]
+ in1 = keras.layers.Input(shape=(3,))
+ in2 = keras.layers.Input(shape=(3,))
+ out1 = keras.layers.Dropout(0.5, name='dropout')(in1)
+ out2 = keras.layers.Dense(4, name='dense_1')(in2)
+ model = keras.Model([in1, in2], [out1, out2])
+ model.predict(test_inputs, batch_size=2)
+ model.compile('rmsprop', 'mse')
+ model.fit(test_inputs, test_outputs,
+ epochs=1, batch_size=2, validation_split=0.5)
+ model.evaluate(test_inputs, test_outputs, batch_size=2)
+
+ def test_that_trainable_disables_updates(self):
+ val_a = np.random.random((10, 4))
+ val_out = np.random.random((10, 4))
+
+ with self.test_session():
+ a = keras.layers.Input(shape=(4,))
+ layer = keras.layers.BatchNormalization(input_shape=(4,))
+ b = layer(a)
+ model = keras.Model(a, b)
+
+ model.trainable = False
+ assert not model.updates
+
+ model.compile('sgd', 'mse')
+ assert not model.updates
+
+ x1 = model.predict(val_a)
+ model.train_on_batch(val_a, val_out)
+ x2 = model.predict(val_a)
+ self.assertAllClose(x1, x2, atol=1e-7)
+
+ model.trainable = True
+ model.compile('sgd', 'mse')
+ assert model.updates
+
+ model.train_on_batch(val_a, val_out)
+ x2 = model.predict(val_a)
+ assert np.abs(np.sum(x1 - x2)) > 1e-5
+
+ layer.trainable = False
+ model.compile('sgd', 'mse')
+ assert not model.updates
+
+ x1 = model.predict(val_a)
+ model.train_on_batch(val_a, val_out)
+ x2 = model.predict(val_a)
+ self.assertAllClose(x1, x2, atol=1e-7)
+
class LossWeightingTest(test.TestCase):
@@ -869,25 +931,6 @@ class TestGeneratorMethods(test.TestCase):
use_multiprocessing=False,
workers=0)
- # Test legacy API
- model.fit_generator(custom_generator(),
- steps_per_epoch=5,
- epochs=1,
- verbose=1,
- max_q_size=10,
- workers=4,
- pickle_safe=True)
- model.predict_generator(custom_generator(),
- steps=5,
- max_q_size=10,
- workers=2,
- pickle_safe=True)
- model.evaluate_generator(custom_generator(),
- steps=5,
- max_q_size=10,
- workers=2,
- pickle_safe=True)
-
def test_generator_methods_with_sample_weights(self):
arr_data = np.random.random((50, 2))
arr_labels = np.random.random((50,))
@@ -960,7 +1003,7 @@ class TestGeneratorMethods(test.TestCase):
use_multiprocessing=False,
validation_data=custom_generator(),
validation_steps=10)
- with self.assertRaises(TypeError):
+ with self.assertRaises(AttributeError):
model.predict_generator(custom_generator(),
steps=5,
max_queue_size=10,
diff --git a/tensorflow/python/keras/_impl/keras/layers/advanced_activations.py b/tensorflow/python/keras/_impl/keras/layers/advanced_activations.py
index e4b9afd38a..ffbf77c4b8 100644
--- a/tensorflow/python/keras/_impl/keras/layers/advanced_activations.py
+++ b/tensorflow/python/keras/_impl/keras/layers/advanced_activations.py
@@ -14,18 +14,18 @@
# ==============================================================================
"""Layers that act as activation functions.
"""
-
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-from tensorflow.python.framework import tensor_shape
+from tensorflow.python.keras._impl.keras import activations
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import constraints
from tensorflow.python.keras._impl.keras import initializers
from tensorflow.python.keras._impl.keras import regularizers
from tensorflow.python.keras._impl.keras.engine import InputSpec
from tensorflow.python.keras._impl.keras.engine import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
class LeakyReLU(Layer):
@@ -61,6 +61,7 @@ class LeakyReLU(Layer):
base_config = super(LeakyReLU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
return input_shape
@@ -114,9 +115,9 @@ class PReLU(Layer):
else:
self.shared_axes = list(shared_axes)
+ @shape_type_conversion
def build(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
- param_shape = input_shape[1:]
+ param_shape = list(input_shape[1:])
self.param_broadcast = [False] * len(param_shape)
if self.shared_axes is not None:
for i in self.shared_axes:
@@ -140,15 +141,13 @@ class PReLU(Layer):
def call(self, inputs, mask=None):
pos = K.relu(inputs)
if K.backend() == 'theano':
- neg = (K.pattern_broadcast(self.alpha, self.param_broadcast) *
- (inputs - K.abs(inputs)) * 0.5)
+ neg = (
+ K.pattern_broadcast(self.alpha, self.param_broadcast) *
+ (inputs - K.abs(inputs)) * 0.5)
else:
neg = -self.alpha * K.relu(-inputs)
return pos + neg
- def compute_output_shape(self, input_shape):
- return input_shape
-
def get_config(self):
config = {
'alpha_initializer': initializers.serialize(self.alpha_initializer),
@@ -159,6 +158,10 @@ class PReLU(Layer):
base_config = super(PReLU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+ @shape_type_conversion
+ def compute_output_shape(self, input_shape):
+ return input_shape
+
class ELU(Layer):
"""Exponential Linear Unit.
@@ -188,14 +191,15 @@ class ELU(Layer):
def call(self, inputs):
return K.elu(inputs, self.alpha)
- def compute_output_shape(self, input_shape):
- return input_shape
-
def get_config(self):
config = {'alpha': float(self.alpha)}
base_config = super(ELU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+ @shape_type_conversion
+ def compute_output_shape(self, input_shape):
+ return input_shape
+
class ThresholdedReLU(Layer):
"""Thresholded Rectified Linear Unit.
@@ -223,12 +227,46 @@ class ThresholdedReLU(Layer):
self.theta = K.cast_to_floatx(theta)
def call(self, inputs, mask=None):
- return inputs * K.cast(inputs > self.theta, K.floatx())
+ return inputs * K.cast(K.greater(inputs, self.theta), K.floatx())
+
+ def get_config(self):
+ config = {'theta': float(self.theta)}
+ base_config = super(ThresholdedReLU, self).get_config()
+ return dict(list(base_config.items()) + list(config.items()))
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
return input_shape
+
+class Softmax(Layer):
+ """Softmax activation function.
+
+ Input shape:
+ Arbitrary. Use the keyword argument `input_shape`
+ (tuple of integers, does not include the samples axis)
+ when using this layer as the first layer in a model.
+
+ Output shape:
+ Same shape as the input.
+
+ Arguments:
+ axis: Integer, axis along which the softmax normalization is applied.
+ """
+
+ def __init__(self, axis=-1, **kwargs):
+ super(Softmax, self).__init__(**kwargs)
+ self.supports_masking = True
+ self.axis = axis
+
+ def call(self, inputs):
+ return activations.softmax(inputs, axis=self.axis)
+
def get_config(self):
- config = {'theta': float(self.theta)}
- base_config = super(ThresholdedReLU, self).get_config()
+ config = {'axis': self.axis}
+ base_config = super(Softmax, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+
+ @shape_type_conversion
+ def compute_output_shape(self, input_shape):
+ return input_shape
diff --git a/tensorflow/python/keras/_impl/keras/layers/advanced_activations_test.py b/tensorflow/python/keras/_impl/keras/layers/advanced_activations_test.py
index 91efab30ed..343b7949ac 100644
--- a/tensorflow/python/keras/_impl/keras/layers/advanced_activations_test.py
+++ b/tensorflow/python/keras/_impl/keras/layers/advanced_activations_test.py
@@ -56,6 +56,12 @@ class AdvancedActivationsTest(test.TestCase):
kwargs={'theta': 0.5},
input_shape=(2, 3, 4))
+ def test_softmax(self):
+ with self.test_session():
+ testing_utils.layer_test(keras.layers.Softmax,
+ kwargs={'axis': 1},
+ input_shape=(2, 3, 4))
+
if __name__ == '__main__':
test.main()
diff --git a/tensorflow/python/keras/_impl/keras/layers/convolutional.py b/tensorflow/python/keras/_impl/keras/layers/convolutional.py
index 22496e8a76..b2ad4c4b65 100644
--- a/tensorflow/python/keras/_impl/keras/layers/convolutional.py
+++ b/tensorflow/python/keras/_impl/keras/layers/convolutional.py
@@ -711,6 +711,144 @@ class Conv3DTranspose(tf_convolutional_layers.Conv3D, Layer):
return dict(list(base_config.items()) + list(config.items()))
+class SeparableConv1D(tf_convolutional_layers.SeparableConv1D, Layer):
+ """Depthwise separable 1D convolution.
+
+ This layer performs a depthwise convolution that acts separately on
+ channels, followed by a pointwise convolution that mixes channels.
+ If `use_bias` is True and a bias initializer is provided,
+ it adds a bias vector to the output.
+ It then optionally applies an activation function to produce the final output.
+
+ Arguments:
+ filters: Integer, the dimensionality of the output space (i.e. the number
+ of filters in the convolution).
+ kernel_size: A single integer specifying the spatial
+ dimensions of the filters.
+ strides: A single integer specifying the strides
+ of the convolution.
+ Specifying any `stride` value != 1 is incompatible with specifying
+ any `dilation_rate` value != 1.
+ padding: One of `"valid"` or `"same"` (case-insensitive).
+ data_format: A string, one of `channels_last` (default) or `channels_first`.
+ The ordering of the dimensions in the inputs.
+ `channels_last` corresponds to inputs with shape
+ `(batch, length, channels)` while `channels_first` corresponds to
+ inputs with shape `(batch, channels, length)`.
+ dilation_rate: A single integer, specifying
+ the dilation rate to use for dilated convolution.
+ Currently, specifying any `dilation_rate` value != 1 is
+ incompatible with specifying any stride value != 1.
+ 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 `num_filters_in * depth_multiplier`.
+ activation: Activation function. Set it to None to maintain a
+ linear activation.
+ use_bias: Boolean, whether the layer uses a bias.
+ depthwise_initializer: An initializer for the depthwise convolution kernel.
+ pointwise_initializer: An initializer for the pointwise convolution kernel.
+ bias_initializer: An initializer for the bias vector. If None, the default
+ initializer will be used.
+ depthwise_regularizer: Optional regularizer for the depthwise
+ convolution kernel.
+ pointwise_regularizer: Optional regularizer for the pointwise
+ convolution kernel.
+ bias_regularizer: Optional regularizer for the bias vector.
+ activity_regularizer: Optional regularizer function for the output.
+ depthwise_constraint: Optional projection function to be applied to the
+ depthwise kernel after being updated by an `Optimizer` (e.g. used for
+ norm constraints or value constraints for layer weights). The function
+ must take as input the unprojected variable and must return the
+ projected variable (which must have the same shape). Constraints are
+ not safe to use when doing asynchronous distributed training.
+ pointwise_constraint: Optional projection function to be applied to the
+ pointwise kernel after being updated by an `Optimizer`.
+ bias_constraint: Optional projection function to be applied to the
+ bias after being updated by an `Optimizer`.
+ trainable: Boolean, if `True` also add variables to the graph collection
+ `GraphKeys.TRAINABLE_VARIABLES` (see `tf.Variable`).
+ name: A string, the name of the layer.
+ """
+
+ def __init__(self,
+ filters,
+ kernel_size,
+ strides=1,
+ padding='valid',
+ data_format=None,
+ dilation_rate=1,
+ depth_multiplier=1,
+ activation=None,
+ use_bias=True,
+ depthwise_initializer='glorot_uniform',
+ pointwise_initializer='glorot_uniform',
+ bias_initializer='zeros',
+ depthwise_regularizer=None,
+ pointwise_regularizer=None,
+ bias_regularizer=None,
+ activity_regularizer=None,
+ depthwise_constraint=None,
+ pointwise_constraint=None,
+ bias_constraint=None,
+ **kwargs):
+ if data_format is None:
+ data_format = K.image_data_format()
+ super(SeparableConv1D, self).__init__(
+ filters=filters,
+ kernel_size=kernel_size,
+ strides=strides,
+ padding=padding,
+ data_format=data_format,
+ dilation_rate=dilation_rate,
+ activation=activations.get(activation),
+ use_bias=use_bias,
+ depthwise_initializer=initializers.get(depthwise_initializer),
+ pointwise_initializer=initializers.get(pointwise_initializer),
+ bias_initializer=initializers.get(bias_initializer),
+ depthwise_regularizer=regularizers.get(depthwise_regularizer),
+ pointwise_regularizer=regularizers.get(pointwise_regularizer),
+ bias_regularizer=regularizers.get(bias_regularizer),
+ activity_regularizer=regularizers.get(activity_regularizer),
+ depthwise_constraint=constraints.get(depthwise_constraint),
+ pointwise_constraint=constraints.get(pointwise_constraint),
+ bias_constraint=constraints.get(bias_constraint),
+ **kwargs)
+
+ def get_config(self):
+ config = {
+ 'filters': self.filters,
+ 'kernel_size': self.kernel_size,
+ 'strides': self.strides,
+ 'padding': self.padding,
+ 'data_format': self.data_format,
+ 'dilation_rate': self.dilation_rate,
+ 'activation': activations.serialize(self.activation),
+ 'use_bias': self.use_bias,
+ 'depthwise_initializer':
+ initializers.serialize(self.depthwise_initializer),
+ 'pointwise_initializer':
+ initializers.serialize(self.pointwise_initializer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'depthwise_regularizer':
+ regularizers.serialize(self.depthwise_regularizer),
+ 'pointwise_regularizer':
+ regularizers.serialize(self.pointwise_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
+ 'activity_regularizer':
+ regularizers.serialize(self.activity_regularizer),
+ 'depthwise_constraint':
+ constraints.serialize(self.depthwise_constraint),
+ 'pointwise_constraint':
+ constraints.serialize(self.pointwise_constraint),
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint)
+ }
+ base_config = super(SeparableConv1D, self).get_config()
+ return dict(list(base_config.items()) + list(config.items()))
+
+
class SeparableConv2D(tf_convolutional_layers.SeparableConv2D, Layer):
"""Depthwise separable 2D convolution.
@@ -1663,6 +1801,7 @@ class Cropping3D(Layer):
Convolution1D = Conv1D
Convolution2D = Conv2D
Convolution3D = Conv3D
+SeparableConvolution1D = SeparableConv1D
SeparableConvolution2D = SeparableConv2D
Convolution2DTranspose = Conv2DTranspose
Convolution3DTranspose = Conv3DTranspose
diff --git a/tensorflow/python/keras/_impl/keras/layers/convolutional_recurrent.py b/tensorflow/python/keras/_impl/keras/layers/convolutional_recurrent.py
index 4f0e9fc691..565db19e41 100644
--- a/tensorflow/python/keras/_impl/keras/layers/convolutional_recurrent.py
+++ b/tensorflow/python/keras/_impl/keras/layers/convolutional_recurrent.py
@@ -20,13 +20,13 @@ from __future__ import print_function
import numpy as np
-from tensorflow.python.framework import tensor_shape
from tensorflow.python.keras._impl.keras import activations
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import constraints
from tensorflow.python.keras._impl.keras import initializers
from tensorflow.python.keras._impl.keras import regularizers
from tensorflow.python.keras._impl.keras.engine import InputSpec
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
from tensorflow.python.keras._impl.keras.layers.recurrent import Recurrent
from tensorflow.python.keras._impl.keras.utils import conv_utils
@@ -127,10 +127,10 @@ class ConvRecurrent2D(Recurrent):
self.input_spec = [InputSpec(ndim=5)]
self.state_spec = None
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if isinstance(input_shape, list):
input_shape = input_shape[0]
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
if self.data_format == 'channels_first':
rows = input_shape[3]
cols = input_shape[4]
@@ -151,30 +151,28 @@ class ConvRecurrent2D(Recurrent):
dilation=self.dilation_rate[1])
if self.return_sequences:
if self.data_format == 'channels_first':
- output_shape = [input_shape[0], input_shape[1],
- self.filters, rows, cols]
+ output_shape = (input_shape[0], input_shape[1], self.filters, rows,
+ cols)
elif self.data_format == 'channels_last':
- output_shape = [input_shape[0], input_shape[1],
- rows, cols, self.filters]
+ output_shape = (input_shape[0], input_shape[1], rows, cols,
+ self.filters)
else:
if self.data_format == 'channels_first':
- output_shape = [input_shape[0], self.filters, rows, cols]
+ output_shape = (input_shape[0], self.filters, rows, cols)
elif self.data_format == 'channels_last':
- output_shape = [input_shape[0], rows, cols, self.filters]
+ output_shape = (input_shape[0], rows, cols, self.filters)
if self.return_state:
if self.data_format == 'channels_first':
- output_shapes = [output_shape] + [(input_shape[0],
- self.filters,
- rows,
- cols) for _ in range(2)]
+ output_shape = [output_shape] + [
+ (input_shape[0], self.filters, rows, cols) for _ in range(2)
+ ]
elif self.data_format == 'channels_last':
- output_shapes = [output_shape] + [(input_shape[0],
- rows,
- cols,
- self.filters) for _ in range(2)]
- return [tensor_shape.TensorShape(shape) for shape in output_shapes]
- return tensor_shape.TensorShape(output_shape)
+ output_shape = [output_shape] + [
+ (input_shape[0], rows, cols, self.filters) for _ in range(2)
+ ]
+
+ return output_shape
def get_config(self):
config = {
@@ -294,11 +292,6 @@ class ConvLSTM2D(ConvRecurrent2D):
Raises:
ValueError: in case of invalid constructor arguments.
- References:
- - [Convolutional LSTM Network: A Machine Learning Approach for
- Precipitation Nowcasting](http://arxiv.org/abs/1506.04214v1)
- The current implementation does not include the feedback loop on the
- cells output
"""
def __init__(self,
@@ -338,7 +331,6 @@ class ConvLSTM2D(ConvRecurrent2D):
return_sequences=return_sequences,
go_backwards=go_backwards,
stateful=stateful,
- activity_regularizer=regularizers.get(activity_regularizer),
**kwargs)
self.activation = activations.get(activation)
self.recurrent_activation = activations.get(recurrent_activation)
@@ -352,6 +344,7 @@ class ConvLSTM2D(ConvRecurrent2D):
self.kernel_regularizer = regularizers.get(kernel_regularizer)
self.recurrent_regularizer = regularizers.get(recurrent_regularizer)
self.bias_regularizer = regularizers.get(bias_regularizer)
+ self.activity_regularizer = regularizers.get(activity_regularizer)
self.kernel_constraint = constraints.get(kernel_constraint)
self.recurrent_constraint = constraints.get(recurrent_constraint)
@@ -361,13 +354,12 @@ class ConvLSTM2D(ConvRecurrent2D):
self.recurrent_dropout = min(1., max(0., recurrent_dropout))
self.state_spec = [InputSpec(ndim=4), InputSpec(ndim=4)]
+ @shape_type_conversion
def build(self, input_shape):
if isinstance(input_shape, list):
input_shape = input_shape[0]
- input_shape = tuple(tensor_shape.TensorShape(input_shape).as_list())
batch_size = input_shape[0] if self.stateful else None
self.input_spec[0] = InputSpec(shape=(batch_size, None) + input_shape[2:])
-
if self.stateful:
self.reset_states()
else:
diff --git a/tensorflow/python/keras/_impl/keras/layers/convolutional_test.py b/tensorflow/python/keras/_impl/keras/layers/convolutional_test.py
index be7da6f2b4..39c9d4f0fb 100644
--- a/tensorflow/python/keras/_impl/keras/layers/convolutional_test.py
+++ b/tensorflow/python/keras/_impl/keras/layers/convolutional_test.py
@@ -311,6 +311,72 @@ class Conv3DTransposeTest(test.TestCase):
self.assertEqual(layer.bias.constraint, b_constraint)
+class SeparableConv1DTest(test.TestCase):
+
+ def test_separable_conv_1d(self):
+ num_samples = 2
+ filters = 6
+ stack_size = 3
+ length = 7
+ strides = 1
+
+ for padding in ['valid', 'same']:
+ for multiplier in [1, 2]:
+ if padding == 'same' and strides != 1:
+ continue
+
+ with self.test_session(use_gpu=True):
+ testing_utils.layer_test(
+ keras.layers.SeparableConv1D,
+ kwargs={
+ 'filters': filters,
+ 'kernel_size': 3,
+ 'padding': padding,
+ 'strides': strides,
+ 'depth_multiplier': multiplier
+ },
+ input_shape=(num_samples, length, stack_size))
+
+ def test_separable_conv1d_regularizers(self):
+ kwargs = {
+ 'filters': 3,
+ 'kernel_size': 3,
+ 'padding': 'valid',
+ 'depthwise_regularizer': 'l2',
+ 'pointwise_regularizer': 'l2',
+ 'bias_regularizer': 'l2',
+ 'activity_regularizer': 'l2',
+ 'strides': 1
+ }
+ with self.test_session(use_gpu=True):
+ layer = keras.layers.SeparableConv1D(**kwargs)
+ layer.build((None, 5, 2))
+ self.assertEqual(len(layer.losses), 3)
+ layer(keras.backend.variable(np.ones((1, 5, 2))))
+ self.assertEqual(len(layer.losses), 4)
+
+ def test_separable_conv1d_constraints(self):
+ d_constraint = lambda x: x
+ p_constraint = lambda x: x
+ b_constraint = lambda x: x
+
+ kwargs = {
+ 'filters': 3,
+ 'kernel_size': 3,
+ 'padding': 'valid',
+ 'pointwise_constraint': p_constraint,
+ 'depthwise_constraint': d_constraint,
+ 'bias_constraint': b_constraint,
+ 'strides': 1
+ }
+ with self.test_session(use_gpu=True):
+ layer = keras.layers.SeparableConv1D(**kwargs)
+ layer.build((None, 5, 2))
+ self.assertEqual(layer.depthwise_kernel.constraint, d_constraint)
+ self.assertEqual(layer.pointwise_kernel.constraint, p_constraint)
+ self.assertEqual(layer.bias.constraint, b_constraint)
+
+
class SeparableConv2DTest(test.TestCase):
def test_separable_conv_2d(self):
diff --git a/tensorflow/python/keras/_impl/keras/layers/embeddings.py b/tensorflow/python/keras/_impl/keras/layers/embeddings.py
index 51c520be38..f8e31068f8 100644
--- a/tensorflow/python/keras/_impl/keras/layers/embeddings.py
+++ b/tensorflow/python/keras/_impl/keras/layers/embeddings.py
@@ -18,12 +18,12 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-from tensorflow.python.framework import tensor_shape
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import constraints
from tensorflow.python.keras._impl.keras import initializers
from tensorflow.python.keras._impl.keras import regularizers
from tensorflow.python.keras._impl.keras.engine import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
class Embedding(Layer):
@@ -58,13 +58,13 @@ class Embedding(Layer):
output_dim: int >= 0. Dimension of the dense embedding.
embeddings_initializer: Initializer for the `embeddings` matrix.
embeddings_regularizer: Regularizer function applied to
- the `embeddings` matrix.
+ the `embeddings` matrix.
embeddings_constraint: Constraint function applied to
- the `embeddings` matrix.
+ the `embeddings` matrix.
mask_zero: Whether or not the input value 0 is a special "padding"
value that should be masked out.
- This is useful when using recurrent layers,
- which may take variable length inputs.
+ This is useful when using recurrent layers
+ which may take variable length input.
If this is `True` then all subsequent layers
in the model need to support masking or an exception will be raised.
If mask_zero is set to True, as a consequence, index 0 cannot be
@@ -81,9 +81,6 @@ class Embedding(Layer):
Output shape:
3D tensor with shape: `(batch_size, sequence_length, output_dim)`.
- References:
- - [A Theoretically Grounded Application of Dropout in Recurrent Neural
- Networks](http://arxiv.org/abs/1512.05287)
"""
def __init__(self,
@@ -101,19 +98,19 @@ class Embedding(Layer):
kwargs['input_shape'] = (input_length,)
else:
kwargs['input_shape'] = (None,)
- super(Embedding, self).__init__(
- activity_regularizer=regularizers.get(activity_regularizer), **kwargs)
+ super(Embedding, self).__init__(**kwargs)
self.input_dim = input_dim
self.output_dim = output_dim
self.embeddings_initializer = initializers.get(embeddings_initializer)
self.embeddings_regularizer = regularizers.get(embeddings_regularizer)
+ self.activity_regularizer = regularizers.get(activity_regularizer)
self.embeddings_constraint = constraints.get(embeddings_constraint)
self.mask_zero = mask_zero
self.input_length = input_length
+ @shape_type_conversion
def build(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
self.embeddings = self.add_weight(
shape=(self.input_dim, self.output_dim),
initializer=self.embeddings_initializer,
@@ -129,10 +126,10 @@ class Embedding(Layer):
else:
return K.not_equal(inputs, 0)
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
if self.input_length is None:
- return tensor_shape.TensorShape(input_shape + [self.output_dim])
+ return input_shape + (self.output_dim,)
else:
# input_length can be tuple if input is 3D or higher
if isinstance(self.input_length, (list, tuple)):
@@ -149,8 +146,7 @@ class Embedding(Layer):
(str(self.input_length), str(input_shape)))
elif s1 is None:
in_lens[i] = s2
- return tensor_shape.TensorShape(
- (input_shape[0],) + tuple(in_lens) + (self.output_dim,))
+ return (input_shape[0],) + tuple(in_lens) + (self.output_dim,)
def call(self, inputs):
if K.dtype(inputs) != 'int32':
diff --git a/tensorflow/python/keras/_impl/keras/layers/local.py b/tensorflow/python/keras/_impl/keras/layers/local.py
index 0a31b87fb5..b844b071e0 100644
--- a/tensorflow/python/keras/_impl/keras/layers/local.py
+++ b/tensorflow/python/keras/_impl/keras/layers/local.py
@@ -18,7 +18,6 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-from tensorflow.python.framework import tensor_shape
from tensorflow.python.keras._impl.keras import activations
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras import constraints
@@ -26,6 +25,7 @@ from tensorflow.python.keras._impl.keras import initializers
from tensorflow.python.keras._impl.keras import regularizers
from tensorflow.python.keras._impl.keras.engine import InputSpec
from tensorflow.python.keras._impl.keras.engine import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
from tensorflow.python.keras._impl.keras.utils import conv_utils
@@ -98,8 +98,7 @@ class LocallyConnected1D(Layer):
kernel_constraint=None,
bias_constraint=None,
**kwargs):
- super(LocallyConnected1D, self).__init__(
- activity_regularizer=regularizers.get(activity_regularizer), **kwargs)
+ super(LocallyConnected1D, self).__init__(**kwargs)
self.filters = filters
self.kernel_size = conv_utils.normalize_tuple(kernel_size, 1, 'kernel_size')
self.strides = conv_utils.normalize_tuple(strides, 1, 'strides')
@@ -114,12 +113,13 @@ class LocallyConnected1D(Layer):
self.bias_initializer = initializers.get(bias_initializer)
self.kernel_regularizer = regularizers.get(kernel_regularizer)
self.bias_regularizer = regularizers.get(bias_regularizer)
+ self.activity_regularizer = regularizers.get(activity_regularizer)
self.kernel_constraint = constraints.get(kernel_constraint)
self.bias_constraint = constraints.get(bias_constraint)
self.input_spec = InputSpec(ndim=3)
+ @shape_type_conversion
def build(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
input_dim = input_shape[2]
if input_dim is None:
raise ValueError('Axis 2 of input should be fully-defined. '
@@ -146,15 +146,14 @@ class LocallyConnected1D(Layer):
self.input_spec = InputSpec(ndim=3, axes={2: input_dim})
self.built = True
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
length = conv_utils.conv_output_length(input_shape[1], self.kernel_size[0],
self.padding, self.strides[0])
- return tensor_shape.TensorShape([input_shape[0], length, self.filters])
+ return (input_shape[0], length, self.filters)
def call(self, inputs):
output = K.local_conv1d(inputs, self.kernel, self.kernel_size, self.strides)
-
if self.use_bias:
output = K.bias_add(output, self.bias)
if self.activation is not None:
@@ -163,20 +162,32 @@ class LocallyConnected1D(Layer):
def get_config(self):
config = {
- 'filters': self.filters,
- 'kernel_size': self.kernel_size,
- 'strides': self.strides,
- 'padding': self.padding,
- 'activation': activations.serialize(self.activation),
- 'use_bias': self.use_bias,
- 'kernel_initializer': initializers.serialize(self.kernel_initializer),
- 'bias_initializer': initializers.serialize(self.bias_initializer),
- 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
- 'bias_regularizer': regularizers.serialize(self.bias_regularizer),
+ 'filters':
+ self.filters,
+ 'kernel_size':
+ self.kernel_size,
+ 'strides':
+ self.strides,
+ 'padding':
+ self.padding,
+ 'activation':
+ activations.serialize(self.activation),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
'activity_regularizer':
regularizers.serialize(self.activity_regularizer),
- 'kernel_constraint': constraints.serialize(self.kernel_constraint),
- 'bias_constraint': constraints.serialize(self.bias_constraint)
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint)
}
base_config = super(LocallyConnected1D, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
@@ -273,8 +284,7 @@ class LocallyConnected2D(Layer):
kernel_constraint=None,
bias_constraint=None,
**kwargs):
- super(LocallyConnected2D, self).__init__(
- activity_regularizer=regularizers.get(activity_regularizer), **kwargs)
+ super(LocallyConnected2D, self).__init__(**kwargs)
self.filters = filters
self.kernel_size = conv_utils.normalize_tuple(kernel_size, 2, 'kernel_size')
self.strides = conv_utils.normalize_tuple(strides, 2, 'strides')
@@ -289,12 +299,13 @@ class LocallyConnected2D(Layer):
self.bias_initializer = initializers.get(bias_initializer)
self.kernel_regularizer = regularizers.get(kernel_regularizer)
self.bias_regularizer = regularizers.get(bias_regularizer)
+ self.activity_regularizer = regularizers.get(activity_regularizer)
self.kernel_constraint = constraints.get(kernel_constraint)
self.bias_constraint = constraints.get(bias_constraint)
self.input_spec = InputSpec(ndim=4)
+ @shape_type_conversion
def build(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
if self.data_format == 'channels_last':
input_row, input_col = input_shape[1:-1]
input_filter = input_shape[3]
@@ -306,7 +317,6 @@ class LocallyConnected2D(Layer):
' a LocallyConnected2D layer '
'should be fully-defined, but layer received '
'the inputs shape ' + str(input_shape))
-
output_row = conv_utils.conv_output_length(input_row, self.kernel_size[0],
self.padding, self.strides[0])
output_col = conv_utils.conv_output_length(input_col, self.kernel_size[1],
@@ -337,33 +347,30 @@ class LocallyConnected2D(Layer):
self.input_spec = InputSpec(ndim=4, axes={-1: input_filter})
self.built = True
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
if self.data_format == 'channels_first':
rows = input_shape[2]
cols = input_shape[3]
elif self.data_format == 'channels_last':
rows = input_shape[1]
cols = input_shape[2]
+
rows = conv_utils.conv_output_length(rows, self.kernel_size[0],
self.padding, self.strides[0])
cols = conv_utils.conv_output_length(cols, self.kernel_size[1],
self.padding, self.strides[1])
if self.data_format == 'channels_first':
- return tensor_shape.TensorShape(
- [input_shape[0], self.filters, rows, cols])
+ return (input_shape[0], self.filters, rows, cols)
elif self.data_format == 'channels_last':
- return tensor_shape.TensorShape(
- [input_shape[0], rows, cols, self.filters])
+ return (input_shape[0], rows, cols, self.filters)
def call(self, inputs):
- output = K.local_conv2d(inputs,
- self.kernel,
- self.kernel_size,
- self.strides,
+ output = K.local_conv2d(inputs, self.kernel, self.kernel_size, self.strides,
(self.output_row, self.output_col),
self.data_format)
+
if self.use_bias:
output = K.bias_add(output, self.bias, data_format=self.data_format)
@@ -372,21 +379,34 @@ class LocallyConnected2D(Layer):
def get_config(self):
config = {
- 'filters': self.filters,
- 'kernel_size': self.kernel_size,
- 'strides': self.strides,
- 'padding': self.padding,
- 'data_format': self.data_format,
- 'activation': activations.serialize(self.activation),
- 'use_bias': self.use_bias,
- 'kernel_initializer': initializers.serialize(self.kernel_initializer),
- 'bias_initializer': initializers.serialize(self.bias_initializer),
- 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
- 'bias_regularizer': regularizers.serialize(self.bias_regularizer),
+ 'filters':
+ self.filters,
+ 'kernel_size':
+ self.kernel_size,
+ 'strides':
+ self.strides,
+ 'padding':
+ self.padding,
+ 'data_format':
+ self.data_format,
+ 'activation':
+ activations.serialize(self.activation),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
'activity_regularizer':
regularizers.serialize(self.activity_regularizer),
- 'kernel_constraint': constraints.serialize(self.kernel_constraint),
- 'bias_constraint': constraints.serialize(self.bias_constraint)
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint)
}
base_config = super(LocallyConnected2D, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
diff --git a/tensorflow/python/keras/_impl/keras/layers/merge.py b/tensorflow/python/keras/_impl/keras/layers/merge.py
index 76eb03cf27..38b0b30297 100644
--- a/tensorflow/python/keras/_impl/keras/layers/merge.py
+++ b/tensorflow/python/keras/_impl/keras/layers/merge.py
@@ -14,15 +14,15 @@
# ==============================================================================
# pylint: disable=not-callable
# pylint: disable=redefined-builtin
-"""Layers can merge several input tensors into a single output tensor.
+"""Layers that can merge several inputs into one.
"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
-from tensorflow.python.framework import tensor_shape
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.engine.topology import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
class _Merge(Layer):
@@ -73,12 +73,13 @@ class _Merge(Layer):
output_shape.append(i)
else:
if i != j:
- raise ValueError('Operands could not be broadcast '
- 'together with shapes ' + str(shape1) + ' ' +
- str(shape2))
+ raise ValueError(
+ 'Operands could not be broadcast '
+ 'together with shapes ' + str(shape1) + ' ' + str(shape2))
output_shape.append(i)
return tuple(output_shape)
+ @shape_type_conversion
def build(self, input_shape):
# Used purely for shape validation.
if not isinstance(input_shape, list):
@@ -87,14 +88,13 @@ class _Merge(Layer):
raise ValueError('A merge layer should be called '
'on a list of at least 2 inputs. '
'Got ' + str(len(input_shape)) + ' inputs.')
- input_shape = [tensor_shape.TensorShape(s).as_list() for s in input_shape]
batch_sizes = [s[0] for s in input_shape if s is not None]
batch_sizes = set(batch_sizes)
batch_sizes -= set([None])
if len(batch_sizes) > 1:
- raise ValueError('Can not merge tensors with different '
- 'batch sizes. Got tensors with shapes : ' +
- str(input_shape))
+ raise ValueError(
+ 'Can not merge tensors with different '
+ 'batch sizes. Got tensors with shapes : ' + str(input_shape))
if input_shape[0] is None:
output_shape = None
else:
@@ -111,9 +111,10 @@ class _Merge(Layer):
self._reshape_required = False
else:
self._reshape_required = True
- self.built = True
def call(self, inputs):
+ if not isinstance(inputs, list):
+ raise ValueError('A merge layer should be called ' 'on a list of inputs.')
if self._reshape_required:
reshaped_inputs = []
input_ndims = list(map(K.ndim, inputs))
@@ -172,6 +173,7 @@ class _Merge(Layer):
else:
return self._merge_function(inputs)
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if input_shape[0] is None:
output_shape = None
@@ -214,6 +216,22 @@ class Add(_Merge):
It takes as input a list of tensors,
all of the same shape, and returns
a single tensor (also of the same shape).
+
+ Examples:
+
+ ```python
+ import keras
+
+ input1 = keras.layers.Input(shape=(16,))
+ x1 = keras.layers.Dense(8, activation='relu')(input1)
+ input2 = keras.layers.Input(shape=(32,))
+ x2 = keras.layers.Dense(8, activation='relu')(input2)
+ added = keras.layers.Add()([x1, x2]) # equivalent to added =
+ keras.layers.add([x1, x2])
+
+ out = keras.layers.Dense(4)(added)
+ model = keras.models.Model(inputs=[input1, input2], outputs=out)
+ ```
"""
def _merge_function(self, inputs):
@@ -247,10 +265,17 @@ class Subtract(_Merge):
```
"""
+ @shape_type_conversion
+ def build(self, input_shape):
+ super(Subtract, self).build(input_shape)
+ if len(input_shape) != 2:
+ raise ValueError('A `Subtract` layer should be called '
+ 'on exactly 2 inputs')
+
def _merge_function(self, inputs):
if len(inputs) != 2:
- raise ValueError('`Subtract` layer should be called '
- 'on exactly 2 inputs. Received: %s' % inputs)
+ raise ValueError('A `Subtract` layer should be called '
+ 'on exactly 2 inputs')
return inputs[0] - inputs[1]
@@ -330,47 +355,43 @@ class Concatenate(_Merge):
super(Concatenate, self).__init__(**kwargs)
self.axis = axis
self.supports_masking = True
+ self._reshape_required = False
+ @shape_type_conversion
def build(self, input_shape):
# Used purely for shape validation.
- if not (isinstance(input_shape, list) and len(input_shape) > 1):
- raise ValueError('`Concatenate` layer should be called '
- 'on a list containing at least two inputs')
+ if not isinstance(input_shape, list) or len(input_shape) < 2:
+ raise ValueError('A `Concatenate` layer should be called '
+ 'on a list of at least 2 inputs')
if all([shape is None for shape in input_shape]):
return
- reduced_inputs_shapes = [
- tensor_shape.TensorShape(shape).as_list() for shape in input_shape
- ]
+ reduced_inputs_shapes = [list(shape) for shape in input_shape]
shape_set = set()
for i in range(len(reduced_inputs_shapes)):
del reduced_inputs_shapes[i][self.axis]
shape_set.add(tuple(reduced_inputs_shapes[i]))
if len(shape_set) > 1:
- raise ValueError('`Concatenate` layer requires '
+ raise ValueError('A `Concatenate` layer requires '
'inputs with matching shapes '
'except for the concat axis. '
'Got inputs shapes: %s' % (input_shape))
- self.built = True
- def call(self, inputs):
- if not isinstance(inputs, list):
- raise ValueError('A `Concatenate` layer should be called '
- 'on a list of inputs.')
+ def _merge_function(self, inputs):
return K.concatenate(inputs, axis=self.axis)
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if not isinstance(input_shape, list):
raise ValueError('A `Concatenate` layer should be called '
'on a list of inputs.')
input_shapes = input_shape
- output_shape = tensor_shape.TensorShape(input_shapes[0]).as_list()
+ output_shape = list(input_shapes[0])
for shape in input_shapes[1:]:
- shape = tensor_shape.TensorShape(shape).as_list()
if output_shape[self.axis] is None or shape[self.axis] is None:
output_shape[self.axis] = None
break
output_shape[self.axis] += shape[self.axis]
- return tensor_shape.TensorShape(output_shape)
+ return tuple(output_shape)
def compute_mask(self, inputs, mask=None):
if mask is None:
@@ -390,7 +411,7 @@ class Concatenate(_Merge):
masks = []
for input_i, mask_i in zip(inputs, mask):
if mask_i is None:
- # Input is unmasked. Append all 1s to masks
+ # Input is unmasked. Append all 1s to masks,
masks.append(K.ones_like(input_i, dtype='bool'))
elif K.ndim(mask_i) < K.ndim(input_i):
# Mask is smaller than the input, expand it
@@ -441,14 +462,16 @@ class Dot(_Merge):
self.axes = axes
self.normalize = normalize
self.supports_masking = True
+ self._reshape_required = False
+ @shape_type_conversion
def build(self, input_shape):
# Used purely for shape validation.
if not isinstance(input_shape, list) or len(input_shape) != 2:
raise ValueError('A `Dot` layer should be called '
'on a list of 2 inputs.')
- shape1 = tensor_shape.TensorShape(input_shape[0]).as_list()
- shape2 = tensor_shape.TensorShape(input_shape[1]).as_list()
+ shape1 = input_shape[0]
+ shape2 = input_shape[1]
if shape1 is None or shape2 is None:
return
if isinstance(self.axes, int):
@@ -462,9 +485,10 @@ class Dot(_Merge):
raise ValueError('Dimension incompatibility '
'%s != %s. ' % (shape1[axes[0]], shape2[axes[1]]) +
'Layer shapes: %s, %s' % (shape1, shape2))
- self.built = True
- def call(self, inputs):
+ def _merge_function(self, inputs):
+ if len(inputs) != 2:
+ raise ValueError('A `Dot` layer should be called ' 'on exactly 2 inputs')
x1 = inputs[0]
x2 = inputs[1]
if isinstance(self.axes, int):
@@ -485,12 +509,13 @@ class Dot(_Merge):
output = K.batch_dot(x1, x2, axes)
return output
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if not isinstance(input_shape, list) or len(input_shape) != 2:
raise ValueError('A `Dot` layer should be called '
'on a list of 2 inputs.')
- shape1 = tensor_shape.TensorShape(input_shape[0]).as_list()
- shape2 = tensor_shape.TensorShape(input_shape[1]).as_list()
+ shape1 = list(input_shape[0])
+ shape2 = list(input_shape[1])
if isinstance(self.axes, int):
if self.axes < 0:
axes = [self.axes % len(shape1), self.axes % len(shape2)]
@@ -504,7 +529,7 @@ class Dot(_Merge):
output_shape = shape1 + shape2
if len(output_shape) == 1:
output_shape += [1]
- return tensor_shape.TensorShape(output_shape)
+ return tuple(output_shape)
def compute_mask(self, inputs, mask=None):
return None
@@ -527,6 +552,21 @@ def add(inputs, **kwargs):
Returns:
A tensor, the sum of the inputs.
+
+ Examples:
+
+ ```python
+ import keras
+
+ input1 = keras.layers.Input(shape=(16,))
+ x1 = keras.layers.Dense(8, activation='relu')(input1)
+ input2 = keras.layers.Input(shape=(32,))
+ x2 = keras.layers.Dense(8, activation='relu')(input2)
+ added = keras.layers.add([x1, x2])
+
+ out = keras.layers.Dense(4)(added)
+ model = keras.models.Model(inputs=[input1, input2], outputs=out)
+ ```
"""
return Add(**kwargs)(inputs)
diff --git a/tensorflow/python/keras/_impl/keras/layers/noise.py b/tensorflow/python/keras/_impl/keras/layers/noise.py
index 459f13145f..04fffcc384 100644
--- a/tensorflow/python/keras/_impl/keras/layers/noise.py
+++ b/tensorflow/python/keras/_impl/keras/layers/noise.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Layers for regularization models via the addition of noise.
+"""Layers that operate regularization via the addition of noise.
"""
from __future__ import absolute_import
from __future__ import division
@@ -22,6 +22,7 @@ import numpy as np
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.engine import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
class GaussianNoise(Layer):
@@ -59,14 +60,15 @@ class GaussianNoise(Layer):
return K.in_train_phase(noised, inputs, training=training)
- def compute_output_shape(self, input_shape):
- return input_shape
-
def get_config(self):
config = {'stddev': self.stddev}
base_config = super(GaussianNoise, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+ @shape_type_conversion
+ def compute_output_shape(self, input_shape):
+ return input_shape
+
class GaussianDropout(Layer):
"""Apply multiplicative 1-centered Gaussian noise.
@@ -86,10 +88,6 @@ class GaussianDropout(Layer):
Output shape:
Same shape as input.
- References:
- - [Dropout: A Simple Way to Prevent Neural Networks from Overfitting
- Srivastava, Hinton, et al.
- 2014](http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf)
"""
def __init__(self, rate, **kwargs):
@@ -108,14 +106,15 @@ class GaussianDropout(Layer):
return K.in_train_phase(noised, inputs, training=training)
return inputs
- def compute_output_shape(self, input_shape):
- return input_shape
-
def get_config(self):
config = {'rate': self.rate}
base_config = super(GaussianDropout, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+ @shape_type_conversion
+ def compute_output_shape(self, input_shape):
+ return input_shape
+
class AlphaDropout(Layer):
"""Applies Alpha Dropout to the input.
@@ -140,8 +139,6 @@ class AlphaDropout(Layer):
Output shape:
Same shape as input.
- References:
- - [Self-Normalizing Neural Networks](https://arxiv.org/abs/1706.02515)
"""
def __init__(self, rate, noise_shape=None, seed=None, **kwargs):
@@ -157,26 +154,34 @@ class AlphaDropout(Layer):
def call(self, inputs, training=None):
if 0. < self.rate < 1.:
noise_shape = self._get_noise_shape(inputs)
- alpha = 1.6732632423543772848170429916717
- scale = 1.0507009873554804934193349852946
- def dropped_inputs(inputs=inputs, rate=self.rate, seed=self.seed):
+ def dropped_inputs(inputs=inputs, rate=self.rate, seed=self.seed): # pylint: disable=missing-docstring
+ alpha = 1.6732632423543772848170429916717
+ scale = 1.0507009873554804934193349852946
alpha_p = -alpha * scale
- kept_idx = K.greater_equal(K.random_uniform(noise_shape, seed=seed),
- rate)
+
+ kept_idx = K.greater_equal(
+ K.random_uniform(noise_shape, seed=seed), rate)
kept_idx = K.cast(kept_idx, K.floatx())
- a = ((1 - rate) * (1 + rate * alpha_p ** 2)) ** -0.5
+
+ # Get affine transformation params
+ a = ((1 - rate) * (1 + rate * alpha_p**2))**-0.5
b = -a * alpha_p * rate
+
+ # Apply mask
x = inputs * kept_idx + alpha_p * (1 - kept_idx)
+
+ # Do affine transformation
return a * x + b
return K.in_train_phase(dropped_inputs, inputs, training=training)
return inputs
- def compute_output_shape(self, input_shape):
- return input_shape
-
def get_config(self):
config = {'rate': self.rate}
base_config = super(AlphaDropout, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+
+ @shape_type_conversion
+ def compute_output_shape(self, input_shape):
+ return input_shape
diff --git a/tensorflow/python/keras/_impl/keras/layers/recurrent.py b/tensorflow/python/keras/_impl/keras/layers/recurrent.py
index 9ea21c9c36..1b0f6cb6cf 100644
--- a/tensorflow/python/keras/_impl/keras/layers/recurrent.py
+++ b/tensorflow/python/keras/_impl/keras/layers/recurrent.py
@@ -1,4 +1,4 @@
-# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2015 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.
@@ -13,7 +13,7 @@
# limitations under the License.
# ==============================================================================
# pylint: disable=protected-access
-"""Recurrent layers.
+"""Recurrent layers and their base classes.
"""
from __future__ import absolute_import
from __future__ import division
@@ -29,6 +29,7 @@ from tensorflow.python.keras._impl.keras import initializers
from tensorflow.python.keras._impl.keras import regularizers
from tensorflow.python.keras._impl.keras.engine import InputSpec
from tensorflow.python.keras._impl.keras.engine import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
from tensorflow.python.keras._impl.keras.utils.generic_utils import has_arg
from tensorflow.python.platform import tf_logging as logging
@@ -109,6 +110,7 @@ class StackedRNNCells(Layer):
states += cell_states
return inputs, states
+ @shape_type_conversion
def build(self, input_shape):
for cell in self.cells:
if isinstance(cell, Layer):
@@ -117,7 +119,7 @@ class StackedRNNCells(Layer):
output_dim = cell.state_size[0]
else:
output_dim = cell.state_size
- input_shape = (input_shape[0], input_shape[1], output_dim)
+ input_shape = (input_shape[0], output_dim)
self.built = True
def get_config(self):
@@ -262,8 +264,7 @@ class RNN(Layer):
(e.g. via the `input_shape` argument)
Input shape:
- 3D tensor with shape `(batch_size, timesteps, input_dim)`,
- (Optional) 2D tensors with shape `(batch_size, output_dim)`.
+ 3D tensor with shape `(batch_size, timesteps, input_dim)`.
Output shape:
- if `return_state`: a list of tensors. The first tensor is
@@ -370,7 +371,6 @@ class RNN(Layer):
go_backwards=False,
stateful=False,
unroll=False,
- activity_regularizer=None,
**kwargs):
if isinstance(cell, (list, tuple)):
cell = StackedRNNCells(cell)
@@ -382,8 +382,7 @@ class RNN(Layer):
'an attribute `state_size` '
'(tuple of integers, '
'one integer per RNN state).')
- super(RNN, self).__init__(
- activity_regularizer=regularizers.get(activity_regularizer), **kwargs)
+ super(RNN, self).__init__(**kwargs)
self.cell = cell
self.return_sequences = return_sequences
self.return_state = return_state
@@ -412,15 +411,16 @@ class RNN(Layer):
def states(self, states):
self._states = states
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if isinstance(input_shape, list):
input_shape = input_shape[0]
- input_shape = tensor_shape.TensorShape(input_shape).as_list()
if hasattr(self.cell.state_size, '__len__'):
- output_dim = self.cell.state_size[0]
+ state_size = self.cell.state_size
else:
- output_dim = self.cell.state_size
+ state_size = [self.cell.state_size]
+ output_dim = state_size[0]
if self.return_sequences:
output_shape = (input_shape[0], input_shape[1], output_dim)
@@ -428,11 +428,10 @@ class RNN(Layer):
output_shape = (input_shape[0], output_dim)
if self.return_state:
- state_shape = [(input_shape[0], output_dim) for _ in self.states]
- output_shape = [output_shape] + state_shape
+ state_shape = [(input_shape[0], dim) for dim in state_size]
+ return [output_shape] + state_shape
else:
- output_shape = output_shape
- return tensor_shape.TensorShape(output_shape)
+ return output_shape
def compute_mask(self, inputs, mask):
if isinstance(mask, list):
@@ -444,6 +443,7 @@ class RNN(Layer):
else:
return output_mask
+ @shape_type_conversion
def build(self, input_shape):
# Note input_shape will be list of shapes of initial states and
# constants if these are passed in __call__.
@@ -454,7 +454,6 @@ class RNN(Layer):
if isinstance(input_shape, list):
input_shape = input_shape[0]
- input_shape = tuple(tensor_shape.TensorShape(input_shape).as_list())
batch_size = input_shape[0] if self.stateful else None
input_dim = input_shape[-1]
@@ -478,9 +477,9 @@ class RNN(Layer):
# initial_state was passed in call, check compatibility
if [spec.shape[-1] for spec in self.state_spec] != state_size:
raise ValueError(
- 'An initial_state was passed that is not compatible with '
+ 'An `initial_state` was passed that is not compatible with '
'`cell.state_size`. Received `state_spec`={}; '
- 'However `cell.state_size` is '
+ 'however `cell.state_size` is '
'{}'.format(self.state_spec, self.cell.state_size))
else:
self.state_spec = [InputSpec(shape=(None, dim)) for dim in state_size]
@@ -610,7 +609,8 @@ class RNN(Layer):
constants=constants,
go_backwards=self.go_backwards,
mask=mask,
- unroll=self.unroll)
+ unroll=self.unroll,
+ input_length=timesteps)
if self.stateful:
updates = []
for i in range(len(states)):
@@ -625,6 +625,8 @@ class RNN(Layer):
# Properly set learning phase
if getattr(last_output, '_uses_learning_phase', False):
output._uses_learning_phase = True
+ for state in states:
+ state._uses_learning_phase = True
if self.return_state:
if not isinstance(states, (list, tuple)):
@@ -636,7 +638,7 @@ class RNN(Layer):
return output
def _standardize_args(self, inputs, initial_state, constants):
- """Standardize `__call__` arguments to a single list of tensor inputs.
+ """Standardize `__call__` to a single list of tensor inputs.
When running a model loaded from file, the input tensors
`initial_state` and `constants` can be passed to `RNN.__call__` as part
@@ -688,7 +690,7 @@ class RNN(Layer):
'a `batch_input_shape` '
'argument to your first layer.\n'
'- If using the functional API, specify '
- 'the time dimension by passing a '
+ 'the batch size by passing a '
'`batch_shape` argument to your Input layer.')
# initialize state if None
if self.states[0] is None:
@@ -788,37 +790,26 @@ class SimpleRNNCell(Layer):
Arguments:
units: Positive integer, dimensionality of the output space.
- activation: Activation function to use
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- If you pass `None`, no activation is applied
+ activation: Activation function to use.
+ If you pass None, no activation is applied
(ie. "linear" activation: `a(x) = x`).
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix,
used for the linear transformation of the inputs.
- (see [initializers](../initializers.md)).
recurrent_initializer: Initializer for the `recurrent_kernel`
weights matrix,
used for the linear transformation of the recurrent state.
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ bias_initializer: Initializer for the bias vector.
kernel_regularizer: Regularizer function applied to
- the `kernel` weights matrix
- (see [regularizer](../regularizers.md)).
+ the `kernel` weights matrix.
recurrent_regularizer: Regularizer function applied to
- the `recurrent_kernel` weights matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
kernel_constraint: Constraint function applied to
- the `kernel` weights matrix
- (see [constraints](../constraints.md)).
+ the `kernel` weights matrix.
recurrent_constraint: Constraint function applied to
- the `recurrent_kernel` weights matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_constraint: Constraint function applied to the bias vector.
dropout: Float between 0 and 1.
Fraction of the units to drop for
the linear transformation of the inputs.
@@ -866,6 +857,7 @@ class SimpleRNNCell(Layer):
self._dropout_mask = None
self._recurrent_dropout_mask = None
+ @shape_type_conversion
def build(self, input_shape):
self.kernel = self.add_weight(
shape=(input_shape[-1], self.units),
@@ -890,33 +882,21 @@ class SimpleRNNCell(Layer):
self.bias = None
self.built = True
- def _generate_dropout_mask(self, inputs, training=None):
- if 0 < self.dropout < 1:
- ones = K.ones_like(K.squeeze(inputs[:, 0:1, :], axis=1))
-
- def dropped_inputs():
- return K.dropout(ones, self.dropout)
-
- self._dropout_mask = K.in_train_phase(
- dropped_inputs, ones, training=training)
- else:
- self._dropout_mask = None
-
- def _generate_recurrent_dropout_mask(self, inputs, training=None):
- if 0 < self.recurrent_dropout < 1:
- ones = K.ones_like(K.reshape(inputs[:, 0, 0], (-1, 1)))
- ones = K.tile(ones, (1, self.units))
-
- def dropped_inputs():
- return K.dropout(ones, self.dropout)
-
- self._recurrent_dropout_mask = K.in_train_phase(
- dropped_inputs, ones, training=training)
- else:
- self._recurrent_dropout_mask = None
-
def call(self, inputs, states, training=None):
prev_output = states[0]
+ if 0 < self.dropout < 1 and self._dropout_mask is None:
+ self._dropout_mask = _generate_dropout_mask(
+ _generate_dropout_ones(inputs,
+ K.shape(inputs)[-1]),
+ self.dropout,
+ training=training)
+ if (0 < self.recurrent_dropout < 1 and
+ self._recurrent_dropout_mask is None):
+ self._recurrent_dropout_mask = _generate_dropout_mask(
+ _generate_dropout_ones(inputs, self.units),
+ self.recurrent_dropout,
+ training=training)
+
dp_mask = self._dropout_mask
rec_dp_mask = self._recurrent_dropout_mask
@@ -939,46 +919,68 @@ class SimpleRNNCell(Layer):
output._uses_learning_phase = True
return output, [output]
+ def get_config(self):
+ config = {
+ 'units':
+ self.units,
+ 'activation':
+ activations.serialize(self.activation),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
+ 'recurrent_initializer':
+ initializers.serialize(self.recurrent_initializer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
+ 'recurrent_regularizer':
+ regularizers.serialize(self.recurrent_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
+ 'recurrent_constraint':
+ constraints.serialize(self.recurrent_constraint),
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint),
+ 'dropout':
+ self.dropout,
+ 'recurrent_dropout':
+ self.recurrent_dropout
+ }
+ base_config = super(SimpleRNNCell, self).get_config()
+ return dict(list(base_config.items()) + list(config.items()))
+
class SimpleRNN(RNN):
"""Fully-connected RNN where the output is to be fed back to input.
Arguments:
units: Positive integer, dimensionality of the output space.
- activation: Activation function to use
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- If you pass `None`, no activation is applied
+ activation: Activation function to use.
+ If you pass None, no activation is applied
(ie. "linear" activation: `a(x) = x`).
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix,
used for the linear transformation of the inputs.
- (see [initializers](../initializers.md)).
recurrent_initializer: Initializer for the `recurrent_kernel`
weights matrix,
used for the linear transformation of the recurrent state.
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ bias_initializer: Initializer for the bias vector.
kernel_regularizer: Regularizer function applied to
- the `kernel` weights matrix
- (see [regularizer](../regularizers.md)).
+ the `kernel` weights matrix.
recurrent_regularizer: Regularizer function applied to
- the `recurrent_kernel` weights matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
activity_regularizer: Regularizer function applied to
- the output of the layer (its "activation").
- (see [regularizer](../regularizers.md)).
+ the output of the layer (its "activation")..
kernel_constraint: Constraint function applied to
- the `kernel` weights matrix
- (see [constraints](../constraints.md)).
+ the `kernel` weights matrix.
recurrent_constraint: Constraint function applied to
- the `recurrent_kernel` weights matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_constraint: Constraint function applied to the bias vector.
dropout: Float between 0 and 1.
Fraction of the units to drop for
the linear transformation of the inputs.
@@ -1052,12 +1054,12 @@ class SimpleRNN(RNN):
go_backwards=go_backwards,
stateful=stateful,
unroll=unroll,
- activity_regularizer=regularizers.get(activity_regularizer),
**kwargs)
+ self.activity_regularizer = regularizers.get(activity_regularizer)
def call(self, inputs, mask=None, training=None, initial_state=None):
- self.cell._generate_dropout_mask(inputs, training=training)
- self.cell._generate_recurrent_dropout_mask(inputs, training=training)
+ self.cell._dropout_mask = None
+ self.cell._recurrent_dropout_mask = None
return super(SimpleRNN, self).call(
inputs, mask=mask, training=training, initial_state=initial_state)
@@ -1119,25 +1121,36 @@ class SimpleRNN(RNN):
def get_config(self):
config = {
- 'units': self.units,
- 'activation': activations.serialize(self.activation),
- 'use_bias': self.use_bias,
- 'kernel_initializer': initializers.serialize(self.kernel_initializer),
+ 'units':
+ self.units,
+ 'activation':
+ activations.serialize(self.activation),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
'recurrent_initializer':
initializers.serialize(self.recurrent_initializer),
- 'bias_initializer': initializers.serialize(self.bias_initializer),
- 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
'recurrent_regularizer':
regularizers.serialize(self.recurrent_regularizer),
- 'bias_regularizer': regularizers.serialize(self.bias_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
'activity_regularizer':
regularizers.serialize(self.activity_regularizer),
- 'kernel_constraint': constraints.serialize(self.kernel_constraint),
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
'recurrent_constraint':
constraints.serialize(self.recurrent_constraint),
- 'bias_constraint': constraints.serialize(self.bias_constraint),
- 'dropout': self.dropout,
- 'recurrent_dropout': self.recurrent_dropout
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint),
+ 'dropout':
+ self.dropout,
+ 'recurrent_dropout':
+ self.recurrent_dropout
}
base_config = super(SimpleRNN, self).get_config()
del base_config['cell']
@@ -1155,43 +1168,28 @@ class GRUCell(Layer):
Arguments:
units: Positive integer, dimensionality of the output space.
- activation: Activation function to use
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- If you pass `None`, no activation is applied
+ activation: Activation function to use.
+ If you pass None, no activation is applied
(ie. "linear" activation: `a(x) = x`).
recurrent_activation: Activation function to use
- for the recurrent step
- (see [activations](../activations.md)).
- Default: hard sigmoid (`hard_sigmoid`).
- If you pass `None`, no activation is applied
- (ie. "linear" activation: `a(x) = x`).
+ for the recurrent step.
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix,
used for the linear transformation of the inputs.
- (see [initializers](../initializers.md)).
recurrent_initializer: Initializer for the `recurrent_kernel`
weights matrix,
used for the linear transformation of the recurrent state.
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ bias_initializer: Initializer for the bias vector.
kernel_regularizer: Regularizer function applied to
- the `kernel` weights matrix
- (see [regularizer](../regularizers.md)).
+ the `kernel` weights matrix.
recurrent_regularizer: Regularizer function applied to
- the `recurrent_kernel` weights matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
kernel_constraint: Constraint function applied to
- the `kernel` weights matrix
- (see [constraints](../constraints.md)).
+ the `kernel` weights matrix.
recurrent_constraint: Constraint function applied to
- the `recurrent_kernel` weights matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_constraint: Constraint function applied to the bias vector.
dropout: Float between 0 and 1.
Fraction of the units to drop for
the linear transformation of the inputs.
@@ -1249,6 +1247,7 @@ class GRUCell(Layer):
self._dropout_mask = None
self._recurrent_dropout_mask = None
+ @shape_type_conversion
def build(self, input_shape):
input_dim = input_shape[-1]
self.kernel = self.add_weight(
@@ -1292,38 +1291,24 @@ class GRUCell(Layer):
self.bias_h = None
self.built = True
- def _generate_dropout_mask(self, inputs, training=None):
- if 0 < self.dropout < 1:
- ones = K.ones_like(K.squeeze(inputs[:, 0:1, :], axis=1))
-
- def dropped_inputs():
- return K.dropout(ones, self.dropout)
-
- self._dropout_mask = [
- K.in_train_phase(dropped_inputs, ones, training=training)
- for _ in range(3)
- ]
- else:
- self._dropout_mask = None
-
- def _generate_recurrent_dropout_mask(self, inputs, training=None):
- if 0 < self.recurrent_dropout < 1:
- ones = K.ones_like(K.reshape(inputs[:, 0, 0], (-1, 1)))
- ones = K.tile(ones, (1, self.units))
-
- def dropped_inputs():
- return K.dropout(ones, self.dropout)
-
- self._recurrent_dropout_mask = [
- K.in_train_phase(dropped_inputs, ones, training=training)
- for _ in range(3)
- ]
- else:
- self._recurrent_dropout_mask = None
-
def call(self, inputs, states, training=None):
h_tm1 = states[0] # previous memory
+ if 0 < self.dropout < 1 and self._dropout_mask is None:
+ self._dropout_mask = _generate_dropout_mask(
+ _generate_dropout_ones(inputs,
+ K.shape(inputs)[-1]),
+ self.dropout,
+ training=training,
+ count=3)
+ if (0 < self.recurrent_dropout < 1 and
+ self._recurrent_dropout_mask is None):
+ self._recurrent_dropout_mask = _generate_dropout_mask(
+ _generate_dropout_ones(inputs, self.units),
+ self.recurrent_dropout,
+ training=training,
+ count=3)
+
# dropout matrices for input units
dp_mask = self._dropout_mask
# dropout matrices for recurrent units
@@ -1387,55 +1372,76 @@ class GRUCell(Layer):
h._uses_learning_phase = True
return h, [h]
+ def get_config(self):
+ config = {
+ 'units':
+ self.units,
+ 'activation':
+ activations.serialize(self.activation),
+ 'recurrent_activation':
+ activations.serialize(self.recurrent_activation),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
+ 'recurrent_initializer':
+ initializers.serialize(self.recurrent_initializer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
+ 'recurrent_regularizer':
+ regularizers.serialize(self.recurrent_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
+ 'recurrent_constraint':
+ constraints.serialize(self.recurrent_constraint),
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint),
+ 'dropout':
+ self.dropout,
+ 'recurrent_dropout':
+ self.recurrent_dropout,
+ 'implementation':
+ self.implementation
+ }
+ base_config = super(GRUCell, self).get_config()
+ return dict(list(base_config.items()) + list(config.items()))
+
class GRU(RNN):
- # pylint: disable=line-too-long
"""Gated Recurrent Unit - Cho et al.
2014.
Arguments:
units: Positive integer, dimensionality of the output space.
- activation: Activation function to use
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- If you pass `None`, no activation is applied
+ activation: Activation function to use.
+ If you pass None, no activation is applied
(ie. "linear" activation: `a(x) = x`).
recurrent_activation: Activation function to use
- for the recurrent step
- (see [activations](../activations.md)).
- Default: hard sigmoid (`hard_sigmoid`).
- If you pass `None`, no activation is applied
- (ie. "linear" activation: `a(x) = x`).
+ for the recurrent step.
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix,
used for the linear transformation of the inputs.
- (see [initializers](../initializers.md)).
recurrent_initializer: Initializer for the `recurrent_kernel`
weights matrix,
used for the linear transformation of the recurrent state.
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ bias_initializer: Initializer for the bias vector.
kernel_regularizer: Regularizer function applied to
- the `kernel` weights matrix
- (see [regularizer](../regularizers.md)).
+ the `kernel` weights matrix.
recurrent_regularizer: Regularizer function applied to
- the `recurrent_kernel` weights matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
activity_regularizer: Regularizer function applied to
- the output of the layer (its "activation").
- (see [regularizer](../regularizers.md)).
+ the output of the layer (its "activation")..
kernel_constraint: Constraint function applied to
- the `kernel` weights matrix
- (see [constraints](../constraints.md)).
+ the `kernel` weights matrix.
recurrent_constraint: Constraint function applied to
- the `recurrent_kernel` weights matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_constraint: Constraint function applied to the bias vector.
dropout: Float between 0 and 1.
Fraction of the units to drop for
the linear transformation of the inputs.
@@ -1465,12 +1471,7 @@ class GRU(RNN):
although it tends to be more memory-intensive.
Unrolling is only suitable for short sequences.
- References:
- - [On the Properties of Neural Machine Translation: Encoder-Decoder Approaches](https://arxiv.org/abs/1409.1259)
- - [Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling](http://arxiv.org/abs/1412.3555v1)
- - [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
"""
- # pylint: enable=line-too-long
def __init__(self,
units,
@@ -1528,8 +1529,8 @@ class GRU(RNN):
self.activity_regularizer = regularizers.get(activity_regularizer)
def call(self, inputs, mask=None, training=None, initial_state=None):
- self.cell._generate_dropout_mask(inputs, training=training)
- self.cell._generate_recurrent_dropout_mask(inputs, training=training)
+ self.cell._dropout_mask = None
+ self.cell._recurrent_dropout_mask = None
return super(GRU, self).call(
inputs, mask=mask, training=training, initial_state=initial_state)
@@ -1599,28 +1600,40 @@ class GRU(RNN):
def get_config(self):
config = {
- 'units': self.units,
- 'activation': activations.serialize(self.activation),
+ 'units':
+ self.units,
+ 'activation':
+ activations.serialize(self.activation),
'recurrent_activation':
activations.serialize(self.recurrent_activation),
- 'use_bias': self.use_bias,
- 'kernel_initializer': initializers.serialize(self.kernel_initializer),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
'recurrent_initializer':
initializers.serialize(self.recurrent_initializer),
- 'bias_initializer': initializers.serialize(self.bias_initializer),
- 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
'recurrent_regularizer':
regularizers.serialize(self.recurrent_regularizer),
- 'bias_regularizer': regularizers.serialize(self.bias_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
'activity_regularizer':
regularizers.serialize(self.activity_regularizer),
- 'kernel_constraint': constraints.serialize(self.kernel_constraint),
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
'recurrent_constraint':
constraints.serialize(self.recurrent_constraint),
- 'bias_constraint': constraints.serialize(self.bias_constraint),
- 'dropout': self.dropout,
- 'recurrent_dropout': self.recurrent_dropout,
- 'implementation': self.implementation
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint),
+ 'dropout':
+ self.dropout,
+ 'recurrent_dropout':
+ self.recurrent_dropout,
+ 'implementation':
+ self.implementation
}
base_config = super(GRU, self).get_config()
del base_config['cell']
@@ -1638,48 +1651,33 @@ class LSTMCell(Layer):
Arguments:
units: Positive integer, dimensionality of the output space.
- activation: Activation function to use
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- If you pass `None`, no activation is applied
+ activation: Activation function to use.
+ If you pass None, no activation is applied
(ie. "linear" activation: `a(x) = x`).
recurrent_activation: Activation function to use
- for the recurrent step
- (see [activations](../activations.md)).
- Default: hard sigmoid (`hard_sigmoid`).
- If you pass `None`, no activation is applied
- (ie. "linear" activation: `a(x) = x`).
+ for the recurrent step.
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix,
used for the linear transformation of the inputs.
- (see [initializers](../initializers.md)).
recurrent_initializer: Initializer for the `recurrent_kernel`
weights matrix,
used for the linear transformation of the recurrent state.
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ bias_initializer: Initializer for the bias vector.
unit_forget_bias: Boolean.
If True, add 1 to the bias of the forget gate at initialization.
Setting it to true will also force `bias_initializer="zeros"`.
This is recommended in [Jozefowicz et
al.](http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf)
kernel_regularizer: Regularizer function applied to
- the `kernel` weights matrix
- (see [regularizer](../regularizers.md)).
+ the `kernel` weights matrix.
recurrent_regularizer: Regularizer function applied to
- the `recurrent_kernel` weights matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
kernel_constraint: Constraint function applied to
- the `kernel` weights matrix
- (see [constraints](../constraints.md)).
+ the `kernel` weights matrix.
recurrent_constraint: Constraint function applied to
- the `recurrent_kernel` weights matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_constraint: Constraint function applied to the bias vector.
dropout: Float between 0 and 1.
Fraction of the units to drop for
the linear transformation of the inputs.
@@ -1739,6 +1737,7 @@ class LSTMCell(Layer):
self._dropout_mask = None
self._recurrent_dropout_mask = None
+ @shape_type_conversion
def build(self, input_shape):
input_dim = input_shape[-1]
self.kernel = self.add_weight(
@@ -1798,36 +1797,22 @@ class LSTMCell(Layer):
self.bias_o = None
self.built = True
- def _generate_dropout_mask(self, inputs, training=None):
- if 0 < self.dropout < 1:
- ones = K.ones_like(K.squeeze(inputs[:, 0:1, :], axis=1))
-
- def dropped_inputs():
- return K.dropout(ones, self.dropout)
-
- self._dropout_mask = [
- K.in_train_phase(dropped_inputs, ones, training=training)
- for _ in range(4)
- ]
- else:
- self._dropout_mask = None
-
- def _generate_recurrent_dropout_mask(self, inputs, training=None):
- if 0 < self.recurrent_dropout < 1:
- ones = K.ones_like(K.reshape(inputs[:, 0, 0], (-1, 1)))
- ones = K.tile(ones, (1, self.units))
-
- def dropped_inputs():
- return K.dropout(ones, self.dropout)
-
- self._recurrent_dropout_mask = [
- K.in_train_phase(dropped_inputs, ones, training=training)
- for _ in range(4)
- ]
- else:
- self._recurrent_dropout_mask = None
-
def call(self, inputs, states, training=None):
+ if 0 < self.dropout < 1 and self._dropout_mask is None:
+ self._dropout_mask = _generate_dropout_mask(
+ _generate_dropout_ones(inputs,
+ K.shape(inputs)[-1]),
+ self.dropout,
+ training=training,
+ count=4)
+ if (0 < self.recurrent_dropout < 1 and
+ self._recurrent_dropout_mask is None):
+ self._recurrent_dropout_mask = _generate_dropout_mask(
+ _generate_dropout_ones(inputs, self.units),
+ self.recurrent_dropout,
+ training=training,
+ count=4)
+
# dropout matrices for input units
dp_mask = self._dropout_mask
# dropout matrices for recurrent units
@@ -1901,59 +1886,81 @@ class LSTMCell(Layer):
h._uses_learning_phase = True
return h, [h, c]
+ def get_config(self):
+ config = {
+ 'units':
+ self.units,
+ 'activation':
+ activations.serialize(self.activation),
+ 'recurrent_activation':
+ activations.serialize(self.recurrent_activation),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
+ 'recurrent_initializer':
+ initializers.serialize(self.recurrent_initializer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'unit_forget_bias':
+ self.unit_forget_bias,
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
+ 'recurrent_regularizer':
+ regularizers.serialize(self.recurrent_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
+ 'recurrent_constraint':
+ constraints.serialize(self.recurrent_constraint),
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint),
+ 'dropout':
+ self.dropout,
+ 'recurrent_dropout':
+ self.recurrent_dropout,
+ 'implementation':
+ self.implementation
+ }
+ base_config = super(LSTMCell, self).get_config()
+ return dict(list(base_config.items()) + list(config.items()))
+
class LSTM(RNN):
- # pylint: disable=line-too-long
"""Long-Short Term Memory layer - Hochreiter 1997.
Arguments:
units: Positive integer, dimensionality of the output space.
- activation: Activation function to use
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- If you pass `None`, no activation is applied
+ activation: Activation function to use.
+ If you pass None, no activation is applied
(ie. "linear" activation: `a(x) = x`).
recurrent_activation: Activation function to use
- for the recurrent step
- (see [activations](../activations.md)).
- Default: hyperbolic tangent (`tanh`).
- Default: hard sigmoid (`hard_sigmoid`).
- If you pass `None`, no activation is applied
- (ie. "linear" activation: `a(x) = x`).
+ for the recurrent step.
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix,
- used for the linear transformation of the inputs.
- (see [initializers](../initializers.md)).
+ used for the linear transformation of the inputs..
recurrent_initializer: Initializer for the `recurrent_kernel`
weights matrix,
- used for the linear transformation of the recurrent state.
- (see [initializers](../initializers.md)).
- bias_initializer: Initializer for the bias vector
- (see [initializers](../initializers.md)).
+ used for the linear transformation of the recurrent state..
+ bias_initializer: Initializer for the bias vector.
unit_forget_bias: Boolean.
If True, add 1 to the bias of the forget gate at initialization.
Setting it to true will also force `bias_initializer="zeros"`.
This is recommended in [Jozefowicz et
al.](http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf)
kernel_regularizer: Regularizer function applied to
- the `kernel` weights matrix
- (see [regularizer](../regularizers.md)).
+ the `kernel` weights matrix.
recurrent_regularizer: Regularizer function applied to
- the `recurrent_kernel` weights matrix
- (see [regularizer](../regularizers.md)).
- bias_regularizer: Regularizer function applied to the bias vector
- (see [regularizer](../regularizers.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_regularizer: Regularizer function applied to the bias vector.
activity_regularizer: Regularizer function applied to
- the output of the layer (its "activation").
- (see [regularizer](../regularizers.md)).
+ the output of the layer (its "activation")..
kernel_constraint: Constraint function applied to
- the `kernel` weights matrix
- (see [constraints](../constraints.md)).
+ the `kernel` weights matrix.
recurrent_constraint: Constraint function applied to
- the `recurrent_kernel` weights matrix
- (see [constraints](../constraints.md)).
- bias_constraint: Constraint function applied to the bias vector
- (see [constraints](../constraints.md)).
+ the `recurrent_kernel` weights matrix.
+ bias_constraint: Constraint function applied to the bias vector.
dropout: Float between 0 and 1.
Fraction of the units to drop for
the linear transformation of the inputs.
@@ -1983,13 +1990,7 @@ class LSTM(RNN):
although it tends to be more memory-intensive.
Unrolling is only suitable for short sequences.
- References:
- - [Long short-term memory](http://www.bioinf.jku.at/publications/older/2604.pdf)
- - [Learning to forget: Continual prediction with LSTM](http://www.mitpressjournals.org/doi/pdf/10.1162/089976600300015015)
- - [Supervised sequence labeling with recurrent neural networks](http://www.cs.toronto.edu/~graves/preprint.pdf)
- - [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
"""
- # pylint: enable=line-too-long
def __init__(self,
units,
@@ -2049,8 +2050,8 @@ class LSTM(RNN):
self.activity_regularizer = regularizers.get(activity_regularizer)
def call(self, inputs, mask=None, training=None, initial_state=None):
- self.cell._generate_dropout_mask(inputs, training=training)
- self.cell._generate_recurrent_dropout_mask(inputs, training=training)
+ self.cell._dropout_mask = None
+ self.cell._recurrent_dropout_mask = None
return super(LSTM, self).call(
inputs, mask=mask, training=training, initial_state=initial_state)
@@ -2124,29 +2125,42 @@ class LSTM(RNN):
def get_config(self):
config = {
- 'units': self.units,
- 'activation': activations.serialize(self.activation),
+ 'units':
+ self.units,
+ 'activation':
+ activations.serialize(self.activation),
'recurrent_activation':
activations.serialize(self.recurrent_activation),
- 'use_bias': self.use_bias,
- 'kernel_initializer': initializers.serialize(self.kernel_initializer),
+ 'use_bias':
+ self.use_bias,
+ 'kernel_initializer':
+ initializers.serialize(self.kernel_initializer),
'recurrent_initializer':
initializers.serialize(self.recurrent_initializer),
- 'bias_initializer': initializers.serialize(self.bias_initializer),
- 'unit_forget_bias': self.unit_forget_bias,
- 'kernel_regularizer': regularizers.serialize(self.kernel_regularizer),
+ 'bias_initializer':
+ initializers.serialize(self.bias_initializer),
+ 'unit_forget_bias':
+ self.unit_forget_bias,
+ 'kernel_regularizer':
+ regularizers.serialize(self.kernel_regularizer),
'recurrent_regularizer':
regularizers.serialize(self.recurrent_regularizer),
- 'bias_regularizer': regularizers.serialize(self.bias_regularizer),
+ 'bias_regularizer':
+ regularizers.serialize(self.bias_regularizer),
'activity_regularizer':
regularizers.serialize(self.activity_regularizer),
- 'kernel_constraint': constraints.serialize(self.kernel_constraint),
+ 'kernel_constraint':
+ constraints.serialize(self.kernel_constraint),
'recurrent_constraint':
constraints.serialize(self.recurrent_constraint),
- 'bias_constraint': constraints.serialize(self.bias_constraint),
- 'dropout': self.dropout,
- 'recurrent_dropout': self.recurrent_dropout,
- 'implementation': self.implementation
+ 'bias_constraint':
+ constraints.serialize(self.bias_constraint),
+ 'dropout':
+ self.dropout,
+ 'recurrent_dropout':
+ self.recurrent_dropout,
+ 'implementation':
+ self.implementation
}
base_config = super(LSTM, self).get_config()
del base_config['cell']
@@ -2159,6 +2173,23 @@ class LSTM(RNN):
return cls(**config)
+def _generate_dropout_ones(inputs, dims):
+ return K.ones((K.shape(inputs)[0], dims))
+
+
+def _generate_dropout_mask(ones, rate, training=None, count=1):
+
+ def dropped_inputs():
+ return K.dropout(ones, rate)
+
+ if count > 1:
+ return [
+ K.in_train_phase(dropped_inputs, ones, training=training)
+ for _ in range(count)
+ ]
+ return K.in_train_phase(dropped_inputs, ones, training=training)
+
+
class Recurrent(Layer):
"""Deprecated abstract base class for recurrent layers.
@@ -2285,6 +2316,7 @@ class Recurrent(Layer):
self.dropout = 0
self.recurrent_dropout = 0
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
if isinstance(input_shape, list):
input_shape = input_shape[0]
diff --git a/tensorflow/python/keras/_impl/keras/layers/recurrent_test.py b/tensorflow/python/keras/_impl/keras/layers/recurrent_test.py
index 7dc4c1db9b..a1407a24ea 100644
--- a/tensorflow/python/keras/_impl/keras/layers/recurrent_test.py
+++ b/tensorflow/python/keras/_impl/keras/layers/recurrent_test.py
@@ -392,6 +392,105 @@ class RNNTest(test.TestCase):
self.assertEqual(len(layer.trainable_weights), 3)
self.assertEqual(len(layer.non_trainable_weights), 0)
+ def test_state_reuse_with_dropout(self):
+ layer_class = keras.layers.SimpleRNN
+ embedding_dim = 4
+ units = 3
+ timesteps = 2
+ num_samples = 2
+
+ with self.test_session():
+ input1 = keras.Input(batch_shape=(num_samples, timesteps, embedding_dim))
+ layer = layer_class(units,
+ return_state=True,
+ return_sequences=True,
+ dropout=0.2)
+ state = layer(input1)[1:]
+
+ input2 = keras.Input(batch_shape=(num_samples, timesteps, embedding_dim))
+ output = layer_class(units)(input2, initial_state=state)
+ model = keras.Model([input1, input2], output)
+
+ inputs = [np.random.random((num_samples, timesteps, embedding_dim)),
+ np.random.random((num_samples, timesteps, embedding_dim))]
+ model.predict(inputs)
+
+ def test_builtin_rnn_cell_serialization(self):
+ for cell_class in [keras.layers.SimpleRNNCell,
+ keras.layers.GRUCell,
+ keras.layers.LSTMCell]:
+ with self.test_session():
+ # Test basic case.
+ x = keras.Input((None, 5))
+ cell = cell_class(32)
+ layer = keras.layers.RNN(cell)
+ y = layer(x)
+ model = keras.models.Model(x, y)
+ model.compile(optimizer='rmsprop', loss='mse')
+
+ # Test basic case serialization.
+ x_np = np.random.random((6, 5, 5))
+ y_np = model.predict(x_np)
+ weights = model.get_weights()
+ config = layer.get_config()
+ layer = keras.layers.RNN.from_config(config)
+ y = layer(x)
+ model = keras.models.Model(x, y)
+ model.set_weights(weights)
+ y_np_2 = model.predict(x_np)
+ self.assertAllClose(y_np, y_np_2, atol=1e-4)
+
+ # Test stacking.
+ cells = [cell_class(8),
+ cell_class(12),
+ cell_class(32)]
+ layer = keras.layers.RNN(cells)
+ y = layer(x)
+ model = keras.models.Model(x, y)
+ model.compile(optimizer='rmsprop', loss='mse')
+
+ # Test stacked RNN serialization.
+ x_np = np.random.random((6, 5, 5))
+ y_np = model.predict(x_np)
+ weights = model.get_weights()
+ config = layer.get_config()
+ layer = keras.layers.RNN.from_config(config)
+ y = layer(x)
+ model = keras.models.Model(x, y)
+ model.set_weights(weights)
+ y_np_2 = model.predict(x_np)
+ self.assertAllClose(y_np, y_np_2, atol=1e-4)
+
+ def test_stacked_rnn_dropout(self):
+ cells = [keras.layers.LSTMCell(3, dropout=0.1, recurrent_dropout=0.1),
+ keras.layers.LSTMCell(3, dropout=0.1, recurrent_dropout=0.1)]
+ layer = keras.layers.RNN(cells)
+
+ with self.test_session():
+ x = keras.Input((None, 5))
+ y = layer(x)
+ model = keras.models.Model(x, y)
+ model.compile('sgd', 'mse')
+ x_np = np.random.random((6, 5, 5))
+ y_np = np.random.random((6, 3))
+ model.train_on_batch(x_np, y_np)
+
+ def test_stacked_rnn_compute_output_shape(self):
+ cells = [keras.layers.LSTMCell(3),
+ keras.layers.LSTMCell(6)]
+ embedding_dim = 4
+ timesteps = 2
+ layer = keras.layers.RNN(cells, return_state=True, return_sequences=True)
+ output_shape = layer.compute_output_shape((None, timesteps, embedding_dim))
+ expected_output_shape = [(None, timesteps, 6),
+ (None, 6),
+ (None, 6),
+ (None, 3),
+ (None, 3)]
+ self.assertEqual(
+ [tuple(o.as_list()) for o in output_shape],
+ expected_output_shape)
+
if __name__ == '__main__':
test.main()
diff --git a/tensorflow/python/keras/_impl/keras/layers/wrappers.py b/tensorflow/python/keras/_impl/keras/layers/wrappers.py
index 452801b656..3667956f80 100644
--- a/tensorflow/python/keras/_impl/keras/layers/wrappers.py
+++ b/tensorflow/python/keras/_impl/keras/layers/wrappers.py
@@ -25,6 +25,7 @@ from tensorflow.python.framework import tensor_shape
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.engine import InputSpec
from tensorflow.python.keras._impl.keras.engine import Layer
+from tensorflow.python.keras._impl.keras.engine.topology import shape_type_conversion
from tensorflow.python.keras._impl.keras.utils.generic_utils import has_arg
from tensorflow.python.layers import utils as tf_layers_util
@@ -291,6 +292,7 @@ class Bidirectional(Wrapper):
self.backward_layer.initial_weights = weights[nw // 2:]
self.stateful = layer.stateful
self.return_sequences = layer.return_sequences
+ self.return_state = layer.return_state
self.supports_masking = True
def get_weights(self):
@@ -301,27 +303,54 @@ class Bidirectional(Wrapper):
self.forward_layer.set_weights(weights[:nw // 2])
self.backward_layer.set_weights(weights[nw // 2:])
+ @shape_type_conversion
def compute_output_shape(self, input_shape):
- input_shape = tuple(tensor_shape.TensorShape(input_shape).as_list())
- if self.merge_mode in ['sum', 'ave', 'mul']:
- return self.forward_layer.compute_output_shape(input_shape)
- elif self.merge_mode == 'concat':
- shape = self.forward_layer.compute_output_shape(input_shape).as_list()
- shape[-1] *= 2
- return tensor_shape.TensorShape(shape)
+ output_shape = tuple(self.forward_layer.compute_output_shape(
+ input_shape).as_list())
+ if self.return_state:
+ state_shape = output_shape[1:]
+ output_shape = output_shape[0]
+
+ if self.merge_mode == 'concat':
+ output_shape = list(output_shape)
+ output_shape[-1] *= 2
+ output_shape = tuple(output_shape)
elif self.merge_mode is None:
- shape = self.forward_layer.compute_output_shape(input_shape)
- return [shape, copy.copy(shape)]
+ output_shape = [output_shape, copy.copy(output_shape)]
- def call(self, inputs, training=None, mask=None):
+ if self.return_state:
+ if self.merge_mode is None:
+ return output_shape + state_shape + copy.copy(state_shape)
+ return [output_shape] + state_shape + copy.copy(state_shape)
+ return output_shape
+
+ def call(self, inputs, training=None, mask=None, initial_state=None):
kwargs = {}
if has_arg(self.layer.call, 'training'):
kwargs['training'] = training
if has_arg(self.layer.call, 'mask'):
kwargs['mask'] = mask
- y = self.forward_layer.call(inputs, **kwargs)
- y_rev = self.backward_layer.call(inputs, **kwargs)
+ if initial_state is not None and has_arg(self.layer.call, 'initial_state'):
+ if not isinstance(initial_state, list):
+ raise ValueError(
+ 'When passing `initial_state` to a Bidirectional RNN, the state '
+ 'should be a list containing the states of the underlying RNNs. '
+ 'Found: ' + str(initial_state))
+ forward_state = initial_state[:len(initial_state) // 2]
+ backward_state = initial_state[len(initial_state) // 2:]
+ y = self.forward_layer.call(inputs, initial_state=forward_state, **kwargs)
+ y_rev = self.backward_layer.call(
+ inputs, initial_state=backward_state, **kwargs)
+ else:
+ y = self.forward_layer.call(inputs, **kwargs)
+ y_rev = self.backward_layer.call(inputs, **kwargs)
+
+ if self.return_state:
+ states = y[1:] + y_rev[1:]
+ y = y[0]
+ y_rev = y_rev[0]
+
if self.return_sequences:
y_rev = K.reverse(y_rev, 1)
if self.merge_mode == 'concat':
@@ -343,6 +372,11 @@ class Bidirectional(Wrapper):
out._uses_learning_phase = True
else:
output._uses_learning_phase = True
+
+ if self.return_state:
+ if self.merge_mode is None:
+ return output + states
+ return [output] + states
return output
def reset_states(self):
diff --git a/tensorflow/python/keras/_impl/keras/layers/wrappers_test.py b/tensorflow/python/keras/_impl/keras/layers/wrappers_test.py
index 0866c4b0ae..f48c8919a1 100644
--- a/tensorflow/python/keras/_impl/keras/layers/wrappers_test.py
+++ b/tensorflow/python/keras/_impl/keras/layers/wrappers_test.py
@@ -238,6 +238,131 @@ class BidirectionalTest(test.TestCase):
model.compile(loss='mse', optimizer='sgd')
model.fit(x, y, epochs=1, batch_size=1)
+ def test_Bidirectional_merged_value(self):
+ rnn = keras.layers.LSTM
+ samples = 2
+ dim = 5
+ timesteps = 3
+ units = 3
+ x = [np.random.rand(samples, timesteps, dim)]
+
+ with self.test_session():
+ for merge_mode in ['sum', 'mul', 'ave', 'concat', None]:
+ if merge_mode == 'sum':
+ merge_func = lambda y, y_rev: y + y_rev
+ elif merge_mode == 'mul':
+ merge_func = lambda y, y_rev: y * y_rev
+ elif merge_mode == 'ave':
+ merge_func = lambda y, y_rev: (y + y_rev) / 2
+ elif merge_mode == 'concat':
+ merge_func = lambda y, y_rev: np.concatenate((y, y_rev), axis=-1)
+ else:
+ merge_func = lambda y, y_rev: [y, y_rev]
+
+ # basic case
+ inputs = keras.Input((timesteps, dim))
+ layer = keras.layers.Bidirectional(
+ rnn(units, return_sequences=True), merge_mode=merge_mode)
+ f_merged = keras.backend.function([inputs], _to_list(layer(inputs)))
+ f_forward = keras.backend.function([inputs],
+ [layer.forward_layer.call(inputs)])
+ f_backward = keras.backend.function(
+ [inputs],
+ [keras.backend.reverse(layer.backward_layer.call(inputs), 1)])
+
+ y_merged = f_merged(x)
+ y_expected = _to_list(merge_func(f_forward(x)[0], f_backward(x)[0]))
+ assert len(y_merged) == len(y_expected)
+ for x1, x2 in zip(y_merged, y_expected):
+ self.assertAllClose(x1, x2, atol=1e-5)
+
+ # test return_state
+ inputs = keras.Input((timesteps, dim))
+ layer = keras.layers.Bidirectional(
+ rnn(units, return_state=True), merge_mode=merge_mode)
+ f_merged = keras.backend.function([inputs], layer(inputs))
+ f_forward = keras.backend.function([inputs],
+ layer.forward_layer.call(inputs))
+ f_backward = keras.backend.function([inputs],
+ layer.backward_layer.call(inputs))
+ n_states = len(layer.layer.states)
+
+ y_merged = f_merged(x)
+ y_forward = f_forward(x)
+ y_backward = f_backward(x)
+ y_expected = _to_list(merge_func(y_forward[0], y_backward[0]))
+ assert len(y_merged) == len(y_expected) + n_states * 2
+ for x1, x2 in zip(y_merged, y_expected):
+ self.assertAllClose(x1, x2, atol=1e-5)
+
+ y_merged = y_merged[-n_states * 2:]
+ y_forward = y_forward[-n_states:]
+ y_backward = y_backward[-n_states:]
+ for state_birnn, state_inner in zip(y_merged, y_forward + y_backward):
+ self.assertAllClose(state_birnn, state_inner, atol=1e-5)
+
+ def test_Bidirectional_dropout(self):
+ rnn = keras.layers.LSTM
+ samples = 2
+ dim = 5
+ timesteps = 3
+ units = 3
+ merge_mode = 'sum'
+ x = [np.random.rand(samples, timesteps, dim)]
+
+ with self.test_session():
+ inputs = keras.Input((timesteps, dim))
+ wrapped = keras.layers.Bidirectional(
+ rnn(units, dropout=0.2, recurrent_dropout=0.2), merge_mode=merge_mode)
+ outputs = _to_list(wrapped(inputs, training=True))
+ assert all(not getattr(x, '_uses_learning_phase') for x in outputs)
+
+ inputs = keras.Input((timesteps, dim))
+ wrapped = keras.layers.Bidirectional(
+ rnn(units, dropout=0.2, return_state=True), merge_mode=merge_mode)
+ outputs = _to_list(wrapped(inputs))
+ assert all(x._uses_learning_phase for x in outputs)
+
+ model = keras.Model(inputs, outputs)
+ assert model.uses_learning_phase
+ y1 = _to_list(model.predict(x))
+ y2 = _to_list(model.predict(x))
+ for x1, x2 in zip(y1, y2):
+ self.assertAllClose(x1, x2, atol=1e-5)
+
+ def test_Bidirectional_state_reuse(self):
+ rnn = keras.layers.LSTM
+ samples = 2
+ dim = 5
+ timesteps = 3
+ units = 3
+
+ with self.test_session():
+ inputs = keras.Input((timesteps, dim))
+ layer = keras.layers.Bidirectional(
+ rnn(units, return_state=True, return_sequences=True))
+ outputs = layer(inputs)
+ output, state = outputs[0], outputs[1:]
+
+ # test passing invalid initial_state: passing a tensor
+ with self.assertRaises(ValueError):
+ output = keras.layers.Bidirectional(
+ rnn(units))(output, initial_state=state[0])
+
+ # test valid usage: passing a list
+ output = keras.layers.Bidirectional(
+ rnn(units))(output, initial_state=state)
+ model = keras.Model(inputs, output)
+ inputs = np.random.rand(samples, timesteps, dim)
+ outputs = model.predict(inputs)
+
+
+def _to_list(ls):
+ if isinstance(ls, list):
+ return ls
+ else:
+ return [ls]
+
if __name__ == '__main__':
test.main()
diff --git a/tensorflow/python/keras/_impl/keras/losses.py b/tensorflow/python/keras/_impl/keras/losses.py
index 1d6319abb1..fe0ef54360 100644
--- a/tensorflow/python/keras/_impl/keras/losses.py
+++ b/tensorflow/python/keras/_impl/keras/losses.py
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Built-in Keras loss functions.
+# pylint: disable=unused-import
+"""Built-in loss functions.
"""
from __future__ import absolute_import
from __future__ import division
@@ -34,7 +35,6 @@ def mean_absolute_error(y_true, y_pred):
def mean_absolute_percentage_error(y_true, y_pred):
- # Equivalent to MAE, but sometimes easier to interpret.
diff = K.abs((y_true - y_pred) / K.clip(K.abs(y_true), K.epsilon(), None))
return 100. * K.mean(diff, axis=-1)
@@ -56,10 +56,24 @@ def hinge(y_true, y_pred):
def categorical_hinge(y_true, y_pred):
pos = K.sum(y_true * y_pred, axis=-1)
neg = K.max((1. - y_true) * y_pred, axis=-1)
- return K.maximum(neg - pos + 1., 0.)
+ return K.maximum(0., neg - pos + 1.)
def logcosh(y_true, y_pred):
+ """Logarithm of the hyperbolic cosine of the prediction error.
+
+ `log(cosh(x))` is approximately equal to `(x ** 2) / 2` for small `x` and
+ to `abs(x) - log(2)` for large `x`. This means that 'logcosh' works mostly
+ like the mean squared error, but will not be so strongly affected by the
+ occasional wildly incorrect prediction.
+
+ Arguments:
+ y_true: tensor of true targets.
+ y_pred: tensor of predicted targets.
+
+ Returns:
+ Tensor with one scalar loss entry per sample.
+ """
def _logcosh(x):
return x + K.softplus(-2. * x) - K.log(2.)
diff --git a/tensorflow/python/keras/_impl/keras/metrics.py b/tensorflow/python/keras/_impl/keras/metrics.py
index 202048f26d..3c18e68260 100644
--- a/tensorflow/python/keras/_impl/keras/metrics.py
+++ b/tensorflow/python/keras/_impl/keras/metrics.py
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Built-in Keras metrics functions.
+# pylint: disable=unused-import
+"""Built-in metrics.
"""
from __future__ import absolute_import
from __future__ import division
@@ -21,7 +22,6 @@ from __future__ import print_function
import six
from tensorflow.python.keras._impl.keras import backend as K
-# pylint: disable=unused-import
from tensorflow.python.keras._impl.keras.losses import binary_crossentropy
from tensorflow.python.keras._impl.keras.losses import categorical_crossentropy
from tensorflow.python.keras._impl.keras.losses import cosine_proximity
@@ -35,7 +35,6 @@ from tensorflow.python.keras._impl.keras.losses import mean_squared_logarithmic_
from tensorflow.python.keras._impl.keras.losses import poisson
from tensorflow.python.keras._impl.keras.losses import sparse_categorical_crossentropy
from tensorflow.python.keras._impl.keras.losses import squared_hinge
-# pylint: disable=unused-import
from tensorflow.python.keras._impl.keras.utils.generic_utils import deserialize_keras_object
@@ -60,8 +59,8 @@ def top_k_categorical_accuracy(y_true, y_pred, k=5):
def sparse_top_k_categorical_accuracy(y_true, y_pred, k=5):
- return K.mean(K.in_top_k(y_pred,
- K.cast(K.max(y_true, axis=-1), 'int32'), k), axis=-1)
+ return K.mean(
+ K.in_top_k(y_pred, K.cast(K.max(y_true, axis=-1), 'int32'), k), axis=-1)
# Aliases
diff --git a/tensorflow/python/keras/_impl/keras/models.py b/tensorflow/python/keras/_impl/keras/models.py
index e262cc8c8e..9cd547200d 100644
--- a/tensorflow/python/keras/_impl/keras/models.py
+++ b/tensorflow/python/keras/_impl/keras/models.py
@@ -492,13 +492,13 @@ class Sequential(Model):
# to the input layer we just created.
layer(x)
- if len(layer.inbound_nodes[-1].output_tensors) != 1:
+ if len(layer._inbound_nodes[-1].output_tensors) != 1:
raise ValueError('All layers in a Sequential model '
'should have a single output tensor. '
'For multi-output layers, '
'use the functional API.')
- self.outputs = [layer.inbound_nodes[-1].output_tensors[0]]
+ self.outputs = [layer._inbound_nodes[-1].output_tensors[0]]
self.inputs = topology.get_source_inputs(self.outputs[0])
# We create an input node, which we will keep updated
diff --git a/tensorflow/python/keras/_impl/keras/models_test.py b/tensorflow/python/keras/_impl/keras/models_test.py
index edfc0ce0eb..04017e4b28 100644
--- a/tensorflow/python/keras/_impl/keras/models_test.py
+++ b/tensorflow/python/keras/_impl/keras/models_test.py
@@ -340,6 +340,35 @@ class TestSequential(test.TestCase):
inner_model.trainable = True
self.assertEqual(len(model.trainable_weights), 4)
+ def test_sequential_update_disabling(self):
+ val_a = np.random.random((10, 4))
+ val_out = np.random.random((10, 4))
+
+ with self.test_session():
+ model = keras.models.Sequential()
+ model.add(keras.layers.BatchNormalization(input_shape=(4,)))
+
+ model.trainable = False
+ assert not model.updates
+
+ model.compile('sgd', 'mse')
+ assert not model.updates
+ assert not model.model.updates
+
+ x1 = model.predict(val_a)
+ model.train_on_batch(val_a, val_out)
+ x2 = model.predict(val_a)
+ self.assertAllClose(x1, x2, atol=1e-7)
+
+ model.trainable = True
+ model.compile('sgd', 'mse')
+ assert model.updates
+ assert model.model.updates
+
+ model.train_on_batch(val_a, val_out)
+ x2 = model.predict(val_a)
+ assert np.abs(np.sum(x1 - x2)) > 1e-5
+
class TestModelCloning(test.TestCase):
diff --git a/tensorflow/python/keras/_impl/keras/optimizers.py b/tensorflow/python/keras/_impl/keras/optimizers.py
index a08073fa86..e47987aadc 100644
--- a/tensorflow/python/keras/_impl/keras/optimizers.py
+++ b/tensorflow/python/keras/_impl/keras/optimizers.py
@@ -12,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Keras optimizer classes (will eventually be replaced with core optimizers).
+# pylint: disable=invalid-name
+"""Built-in optimizer classes.
"""
from __future__ import absolute_import
from __future__ import division
@@ -121,9 +122,9 @@ class Optimizer(object):
param_values = K.batch_get_value(params)
for pv, p, w in zip(param_values, params, weights):
if pv.shape != w.shape:
- raise ValueError('Optimizer weight shape ' + str(pv.shape) +
- ' not compatible with '
- 'provided weight shape ' + str(w.shape))
+ raise ValueError(
+ 'Optimizer weight shape ' + str(pv.shape) + ' not compatible with '
+ 'provided weight shape ' + str(w.shape))
weight_value_tuples.append((p, w))
K.batch_set_value(weight_value_tuples)
@@ -156,7 +157,8 @@ class SGD(Optimizer):
Arguments:
lr: float >= 0. Learning rate.
- momentum: float >= 0. Parameter updates momentum.
+ momentum: float >= 0. Parameter that accelerates SGD
+ in the relevant direction and dampens oscillations.
decay: float >= 0. Learning rate decay over each update.
nesterov: boolean. Whether to apply Nesterov momentum.
"""
@@ -177,9 +179,8 @@ class SGD(Optimizer):
lr = self.lr
if self.initial_decay > 0:
- lr *= (1. / (1. + self.decay * K.cast(self.iterations,
- K.dtype(self.decay))))
-
+ lr *= (1. /
+ (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
# momentum
shapes = [K.int_shape(p) for p in params]
moments = [K.zeros(shape) for shape in shapes]
@@ -224,32 +225,33 @@ class RMSprop(Optimizer):
Arguments:
lr: float >= 0. Learning rate.
rho: float >= 0.
- epsilon: float >= 0. Fuzz factor.
+ epsilon: float >= 0. Fuzz factor. If `None`, defaults to `K.epsilon()`.
decay: float >= 0. Learning rate decay over each update.
+
"""
- def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, decay=0., **kwargs):
+ def __init__(self, lr=0.001, rho=0.9, epsilon=None, decay=0., **kwargs):
super(RMSprop, self).__init__(**kwargs)
with K.name_scope(self.__class__.__name__):
self.lr = K.variable(lr, name='lr')
self.rho = K.variable(rho, name='rho')
self.decay = K.variable(decay, name='decay')
self.iterations = K.variable(0, dtype='int64', name='iterations')
+ if epsilon is None:
+ epsilon = K.epsilon()
self.epsilon = epsilon
self.initial_decay = decay
def get_updates(self, loss, params):
grads = self.get_gradients(loss, params)
- accumulators = [
- K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params
- ]
+ accumulators = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
self.weights = accumulators
self.updates = [K.update_add(self.iterations, 1)]
lr = self.lr
if self.initial_decay > 0:
- lr *= (1. / (1. + self.decay * K.cast(self.iterations,
- K.dtype(self.decay))))
+ lr *= (1. /
+ (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
for p, g, a in zip(params, grads, accumulators):
# update accumulator
@@ -283,20 +285,19 @@ class Adagrad(Optimizer):
Arguments:
lr: float >= 0. Learning rate.
- epsilon: float >= 0.
+ epsilon: float >= 0. If `None`, defaults to `K.epsilon()`.
decay: float >= 0. Learning rate decay over each update.
- References:
- - [Adaptive Subgradient Methods for Online Learning and Stochastic
- Optimization](http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)
"""
- def __init__(self, lr=0.01, epsilon=1e-8, decay=0., **kwargs):
+ def __init__(self, lr=0.01, epsilon=None, decay=0., **kwargs):
super(Adagrad, self).__init__(**kwargs)
with K.name_scope(self.__class__.__name__):
self.lr = K.variable(lr, name='lr')
self.decay = K.variable(decay, name='decay')
self.iterations = K.variable(0, dtype='int64', name='iterations')
+ if epsilon is None:
+ epsilon = K.epsilon()
self.epsilon = epsilon
self.initial_decay = decay
@@ -309,8 +310,8 @@ class Adagrad(Optimizer):
lr = self.lr
if self.initial_decay > 0:
- lr *= (1. / (1. + self.decay * K.cast(self.iterations,
- K.dtype(self.decay))))
+ lr *= (1. /
+ (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
for p, g, a in zip(params, grads, accumulators):
new_a = a + K.square(g) # update accumulator
@@ -344,20 +345,19 @@ class Adadelta(Optimizer):
lr: float >= 0. Learning rate.
It is recommended to leave it at the default value.
rho: float >= 0.
- epsilon: float >= 0. Fuzz factor.
+ epsilon: float >= 0. Fuzz factor. If `None`, defaults to `K.epsilon()`.
decay: float >= 0. Learning rate decay over each update.
- References:
- - [Adadelta - an adaptive learning rate
- method](http://arxiv.org/abs/1212.5701)
"""
- def __init__(self, lr=1.0, rho=0.95, epsilon=1e-8, decay=0., **kwargs):
+ def __init__(self, lr=1.0, rho=0.95, epsilon=None, decay=0., **kwargs):
super(Adadelta, self).__init__(**kwargs)
with K.name_scope(self.__class__.__name__):
self.lr = K.variable(lr, name='lr')
self.decay = K.variable(decay, name='decay')
self.iterations = K.variable(0, dtype='int64', name='iterations')
+ if epsilon is None:
+ epsilon = K.epsilon()
self.rho = rho
self.epsilon = epsilon
self.initial_decay = decay
@@ -372,8 +372,8 @@ class Adadelta(Optimizer):
lr = self.lr
if self.initial_decay > 0:
- lr *= (1. / (1. + self.decay * K.cast(self.iterations,
- K.dtype(self.decay))))
+ lr *= (1. /
+ (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
for p, g, a, d_a in zip(params, grads, accumulators, delta_accumulators):
# update accumulator
@@ -415,20 +415,21 @@ class Adam(Optimizer):
lr: float >= 0. Learning rate.
beta_1: float, 0 < beta < 1. Generally close to 1.
beta_2: float, 0 < beta < 1. Generally close to 1.
- epsilon: float >= 0. Fuzz factor.
+ epsilon: float >= 0. Fuzz factor. If `None`, defaults to `K.epsilon()`.
decay: float >= 0. Learning rate decay over each update.
+ amsgrad: boolean. Whether to apply the AMSGrad variant of this
+ algorithm from the paper "On the Convergence of Adam and
+ Beyond".
- References:
- - [Adam - A Method for Stochastic
- Optimization](http://arxiv.org/abs/1412.6980v8)
"""
def __init__(self,
lr=0.001,
beta_1=0.9,
beta_2=0.999,
- epsilon=1e-8,
+ epsilon=None,
decay=0.,
+ amsgrad=False,
**kwargs):
super(Adam, self).__init__(**kwargs)
with K.name_scope(self.__class__.__name__):
@@ -437,8 +438,11 @@ class Adam(Optimizer):
self.beta_1 = K.variable(beta_1, name='beta_1')
self.beta_2 = K.variable(beta_2, name='beta_2')
self.decay = K.variable(decay, name='decay')
+ if epsilon is None:
+ epsilon = K.epsilon()
self.epsilon = epsilon
self.initial_decay = decay
+ self.amsgrad = amsgrad
def get_updates(self, loss, params):
grads = self.get_gradients(loss, params)
@@ -446,21 +450,30 @@ class Adam(Optimizer):
lr = self.lr
if self.initial_decay > 0:
- lr *= (1. / (1. + self.decay * K.cast(self.iterations,
- K.dtype(self.decay))))
+ lr *= (1. /
+ (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
t = K.cast(self.iterations, K.floatx()) + 1
- lr_t = lr * (K.sqrt(1. - K.pow(self.beta_2, t)) /
- (1. - K.pow(self.beta_1, t)))
+ lr_t = lr * (
+ K.sqrt(1. - K.pow(self.beta_2, t)) / (1. - K.pow(self.beta_1, t)))
ms = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
vs = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
- self.weights = [self.iterations] + ms + vs
+ if self.amsgrad:
+ vhats = [K.zeros(K.int_shape(p), dtype=K.dtype(p)) for p in params]
+ else:
+ vhats = [K.zeros(1) for _ in params]
+ self.weights = [self.iterations] + ms + vs + vhats
- for p, g, m, v in zip(params, grads, ms, vs):
+ for p, g, m, v, vhat in zip(params, grads, ms, vs, vhats):
m_t = (self.beta_1 * m) + (1. - self.beta_1) * g
v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(g)
- p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)
+ if self.amsgrad:
+ vhat_t = K.maximum(vhat, v_t)
+ p_t = p - lr_t * m_t / (K.sqrt(vhat_t) + self.epsilon)
+ self.updates.append(K.update(vhat, vhat_t))
+ else:
+ p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)
self.updates.append(K.update(m, m_t))
self.updates.append(K.update(v, v_t))
@@ -479,7 +492,8 @@ class Adam(Optimizer):
'beta_1': float(K.get_value(self.beta_1)),
'beta_2': float(K.get_value(self.beta_2)),
'decay': float(K.get_value(self.decay)),
- 'epsilon': self.epsilon
+ 'epsilon': self.epsilon,
+ 'amsgrad': self.amsgrad
}
base_config = super(Adam, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
@@ -494,19 +508,16 @@ class Adamax(Optimizer):
Arguments:
lr: float >= 0. Learning rate.
beta_1/beta_2: floats, 0 < beta < 1. Generally close to 1.
- epsilon: float >= 0. Fuzz factor.
+ epsilon: float >= 0. Fuzz factor. If `None`, defaults to `K.epsilon()`.
decay: float >= 0. Learning rate decay over each update.
- References:
- - [Adam - A Method for Stochastic
- Optimization](http://arxiv.org/abs/1412.6980v8)
"""
def __init__(self,
lr=0.002,
beta_1=0.9,
beta_2=0.999,
- epsilon=1e-8,
+ epsilon=None,
decay=0.,
**kwargs):
super(Adamax, self).__init__(**kwargs)
@@ -516,6 +527,8 @@ class Adamax(Optimizer):
self.beta_1 = K.variable(beta_1, name='beta_1')
self.beta_2 = K.variable(beta_2, name='beta_2')
self.decay = K.variable(decay, name='decay')
+ if epsilon is None:
+ epsilon = K.epsilon()
self.epsilon = epsilon
self.initial_decay = decay
@@ -525,8 +538,8 @@ class Adamax(Optimizer):
lr = self.lr
if self.initial_decay > 0:
- lr *= (1. / (1. + self.decay * K.cast(self.iterations,
- K.dtype(self.decay))))
+ lr *= (1. /
+ (1. + self.decay * K.cast(self.iterations, K.dtype(self.decay))))
t = K.cast(self.iterations, K.floatx()) + 1
lr_t = lr / (1. - K.pow(self.beta_1, t))
@@ -580,19 +593,15 @@ class Nadam(Optimizer):
Arguments:
lr: float >= 0. Learning rate.
beta_1/beta_2: floats, 0 < beta < 1. Generally close to 1.
- epsilon: float >= 0. Fuzz factor.
+ epsilon: float >= 0. Fuzz factor. If `None`, defaults to `K.epsilon()`.
- References:
- - [Nadam report](http://cs229.stanford.edu/proj2015/054_report.pdf)
- - [On the importance of initialization and momentum in deep
- learning](http://www.cs.toronto.edu/~fritz/absps/momentum.pdf)
"""
def __init__(self,
lr=0.002,
beta_1=0.9,
beta_2=0.999,
- epsilon=1e-8,
+ epsilon=None,
schedule_decay=0.004,
**kwargs):
super(Nadam, self).__init__(**kwargs)
@@ -602,12 +611,15 @@ class Nadam(Optimizer):
self.lr = K.variable(lr, name='lr')
self.beta_1 = K.variable(beta_1, name='beta_1')
self.beta_2 = K.variable(beta_2, name='beta_2')
+ if epsilon is None:
+ epsilon = K.epsilon()
self.epsilon = epsilon
self.schedule_decay = schedule_decay
def get_updates(self, loss, params):
grads = self.get_gradients(loss, params)
self.updates = [K.update_add(self.iterations, 1)]
+
t = K.cast(self.iterations, K.floatx()) + 1
# Due to the recommendations in [2], i.e. warming momentum schedule
@@ -691,7 +703,6 @@ class TFOptimizer(Optimizer):
# Aliases.
-# pylint: disable=invalid-name
sgd = SGD
rmsprop = RMSprop
adagrad = Adagrad
@@ -700,8 +711,6 @@ adam = Adam
adamax = Adamax
nadam = Nadam
-# pylint: enable=invalid-name
-
def serialize(optimizer):
return serialize_keras_object(optimizer)
diff --git a/tensorflow/python/keras/_impl/keras/optimizers_test.py b/tensorflow/python/keras/_impl/keras/optimizers_test.py
index 6e9e4e6c99..57636afbf0 100644
--- a/tensorflow/python/keras/_impl/keras/optimizers_test.py
+++ b/tensorflow/python/keras/_impl/keras/optimizers_test.py
@@ -102,6 +102,7 @@ class KerasOptimizersTest(test.TestCase):
with self.test_session():
_test_optimizer(keras.optimizers.Adam())
_test_optimizer(keras.optimizers.Adam(decay=1e-3))
+ _test_optimizer(keras.optimizers.Adam(amsgrad=True))
def test_adamax(self):
with self.test_session():
diff --git a/tensorflow/python/keras/_impl/keras/preprocessing/image.py b/tensorflow/python/keras/_impl/keras/preprocessing/image.py
index 82441de592..db1fdd4e6b 100644
--- a/tensorflow/python/keras/_impl/keras/preprocessing/image.py
+++ b/tensorflow/python/keras/_impl/keras/preprocessing/image.py
@@ -12,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
+# pylint: disable=g-import-not-at-top
"""Fairly basic set of tools for real-time data augmentation on image data.
Can easily be extended to include new transformations,
@@ -28,25 +29,22 @@ import re
import threading
import numpy as np
-from six.moves import range # pylint: disable=redefined-builtin
-
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.utils.data_utils import Sequence
from tensorflow.python.platform import tf_logging as logging
-
-# pylint: disable=g-import-not-at-top
-try:
- from PIL import Image as pil_image
-except ImportError:
- pil_image = None
try:
from scipy import linalg
import scipy.ndimage as ndi
except ImportError:
linalg = None
ndi = None
-# pylint: enable=g-import-not-at-top
+
+
+try:
+ from PIL import Image as pil_image
+except ImportError:
+ pil_image = None
if pil_image is not None:
_PIL_INTERPOLATION_METHODS = {
@@ -88,7 +86,7 @@ def random_rotation(x,
Returns:
Rotated Numpy image tensor.
"""
- theta = np.pi / 180 * np.random.uniform(-rg, rg)
+ theta = np.deg2rad(np.random.uniform(-rg, rg))
rotation_matrix = np.array([[np.cos(theta), -np.sin(theta), 0],
[np.sin(theta), np.cos(theta), 0], [0, 0, 1]])
@@ -145,7 +143,7 @@ def random_shear(x,
Arguments:
x: Input tensor. Must be 3D.
- intensity: Transformation intensity.
+ intensity: Transformation intensity in degrees.
row_axis: Index of axis for rows in the input tensor.
col_axis: Index of axis for columns in the input tensor.
channel_axis: Index of axis for channels in the input tensor.
@@ -158,7 +156,7 @@ def random_shear(x,
Returns:
Sheared Numpy image tensor.
"""
- shear = np.random.uniform(-intensity, intensity)
+ shear = np.deg2rad(np.random.uniform(-intensity, intensity))
shear_matrix = np.array([[1, -np.sin(shear), 0], [0, np.cos(shear), 0],
[0, 0, 1]])
@@ -188,8 +186,10 @@ def random_zoom(x,
(one of `{'constant', 'nearest', 'reflect', 'wrap'}`).
cval: Value used for points outside the boundaries
of the input if `mode='constant'`.
+
Returns:
Zoomed Numpy image tensor.
+
Raises:
ValueError: if `zoom_range` isn't a tuple.
"""
@@ -366,7 +366,7 @@ def load_img(path, grayscale=False, target_size=None, interpolation='nearest'):
grayscale: Boolean, whether to load the image as grayscale.
target_size: Either `None` (default to original size)
or tuple of ints `(img_height, img_width)`.
- interpolation: Interpolation method used to resample the image if the
+ interpolation: Interpolation method used to resample the image if the
target size is different from that of the loaded image.
Supported methods are "nearest", "bilinear", and "bicubic".
If PIL version 1.1.3 or newer is installed, "lanczos" is also
@@ -394,11 +394,9 @@ def load_img(path, grayscale=False, target_size=None, interpolation='nearest'):
width_height_tuple = (target_size[1], target_size[0])
if img.size != width_height_tuple:
if interpolation not in _PIL_INTERPOLATION_METHODS:
- raise ValueError(
- 'Invalid interpolation method {} specified. Supported '
- 'methods are {}'.format(
- interpolation,
- ', '.join(_PIL_INTERPOLATION_METHODS.keys())))
+ raise ValueError('Invalid interpolation method {} specified. Supported '
+ 'methods are {}'.format(interpolation, ', '.join(
+ _PIL_INTERPOLATION_METHODS.keys())))
resample = _PIL_INTERPOLATION_METHODS[interpolation]
img = img.resize(width_height_tuple, resample)
return img
@@ -407,7 +405,8 @@ def load_img(path, grayscale=False, target_size=None, interpolation='nearest'):
def list_pictures(directory, ext='jpg|jpeg|bmp|png|ppm'):
return [
os.path.join(root, f)
- for root, _, files in os.walk(directory) for f in files
+ for root, _, files in os.walk(directory)
+ for f in files
if re.match(r'([\w]+\.(?:' + ext + '))', f)
]
@@ -423,9 +422,9 @@ class ImageDataGenerator(object):
zca_whitening: apply ZCA whitening.
zca_epsilon: epsilon for ZCA whitening. Default is 1e-6.
rotation_range: degrees (0 to 180).
- width_shift_range: fraction of total width.
- height_shift_range: fraction of total height.
- shear_range: shear intensity (shear angle in radians).
+ width_shift_range: fraction of total width, if < 1, or pixels if >= 1.
+ height_shift_range: fraction of total height, if < 1, or pixels if >= 1.
+ shear_range: shear intensity (shear angle in degrees).
zoom_range: amount of zoom. if scalar z, zoom will be randomly picked
in the range [1-z, 1+z]. A sequence of two can be passed instead
to select this range.
@@ -433,6 +432,12 @@ class ImageDataGenerator(object):
fill_mode: points outside the boundaries are filled according to the
given mode ('constant', 'nearest', 'reflect' or 'wrap'). Default
is 'nearest'.
+ Points outside the boundaries of the input are filled according to the
+ given mode:
+ 'constant': kkkkkkkk|abcd|kkkkkkkk (cval=k)
+ 'nearest': aaaaaaaa|abcd|dddddddd
+ 'reflect': abcddcba|abcd|dcbaabcd
+ 'wrap': abcdabcd|abcd|abcdabcd
cval: value used for points outside the boundaries when fill_mode is
'constant'. Default is 0.
horizontal_flip: whether to randomly flip images horizontally.
@@ -522,6 +527,32 @@ class ImageDataGenerator(object):
raise ValueError('`zoom_range` should be a float or '
'a tuple or list of two floats. '
'Received arg: ', zoom_range)
+ if zca_whitening:
+ if not featurewise_center:
+ self.featurewise_center = True
+ logging.warning('This ImageDataGenerator specifies '
+ '`zca_whitening`, which overrides '
+ 'setting of `featurewise_center`.')
+ if featurewise_std_normalization:
+ self.featurewise_std_normalization = False
+ logging.warning('This ImageDataGenerator specifies '
+ '`zca_whitening` '
+ 'which overrides setting of'
+ '`featurewise_std_normalization`.')
+ if featurewise_std_normalization:
+ if not featurewise_center:
+ self.featurewise_center = True
+ logging.warning('This ImageDataGenerator specifies '
+ '`featurewise_std_normalization`, '
+ 'which overrides setting of '
+ '`featurewise_center`.')
+ if samplewise_std_normalization:
+ if not samplewise_center:
+ self.samplewise_center = True
+ logging.warning('This ImageDataGenerator specifies '
+ '`samplewise_std_normalization`, '
+ 'which overrides setting of '
+ '`samplewise_center`.')
def flow(self,
x,
@@ -591,7 +622,7 @@ class ImageDataGenerator(object):
if self.samplewise_center:
x -= np.mean(x, keepdims=True)
if self.samplewise_std_normalization:
- x /= np.std(x, keepdims=True) + 1e-7
+ x /= (np.std(x, keepdims=True) + K.epsilon())
if self.featurewise_center:
if self.mean is not None:
@@ -603,7 +634,7 @@ class ImageDataGenerator(object):
'first by calling `.fit(numpy_data)`.')
if self.featurewise_std_normalization:
if self.std is not None:
- x /= (self.std + 1e-7)
+ x /= (self.std + K.epsilon())
else:
logging.warning('This ImageDataGenerator specifies '
'`featurewise_std_normalization`, but it hasn\'t '
@@ -636,7 +667,6 @@ class ImageDataGenerator(object):
"""
if ndi is None:
raise ImportError('Scipy is required for image transformations.')
-
# x is a single image, so it doesn't have image number at index 0
img_row_axis = self.row_axis - 1
img_col_axis = self.col_axis - 1
@@ -648,25 +678,27 @@ class ImageDataGenerator(object):
# use composition of homographies
# to generate final transform that needs to be applied
if self.rotation_range:
- theta = np.pi / 180 * np.random.uniform(-self.rotation_range,
- self.rotation_range)
+ theta = np.deg2rad(
+ np.random.uniform(-self.rotation_range, self.rotation_range))
else:
theta = 0
if self.height_shift_range:
- tx = np.random.uniform(-self.height_shift_range,
- self.height_shift_range) * x.shape[img_row_axis]
+ tx = np.random.uniform(-self.height_shift_range, self.height_shift_range)
+ if self.height_shift_range < 1:
+ tx *= x.shape[img_row_axis]
else:
tx = 0
if self.width_shift_range:
- ty = np.random.uniform(-self.width_shift_range,
- self.width_shift_range) * x.shape[img_col_axis]
+ ty = np.random.uniform(-self.width_shift_range, self.width_shift_range)
+ if self.width_shift_range < 1:
+ ty *= x.shape[img_col_axis]
else:
ty = 0
if self.shear_range:
- shear = np.random.uniform(-self.shear_range, self.shear_range)
+ shear = np.deg2rad(np.random.uniform(-self.shear_range, self.shear_range))
else:
shear = 0
@@ -744,7 +776,7 @@ class ImageDataGenerator(object):
if x.ndim != 4:
raise ValueError('Input to `.fit()` should have rank 4. '
'Got array with shape: ' + str(x.shape))
- if x.shape[self.channel_axis] not in {3, 4}:
+ if x.shape[self.channel_axis] not in {1, 3, 4}:
logging.warning(
'Expected input to be images (as Numpy array) '
'following the data format convention "' + self.data_format + '" '
@@ -784,10 +816,12 @@ class ImageDataGenerator(object):
raise ImportError('Scipy is required for zca_whitening.')
flat_x = np.reshape(x, (x.shape[0], x.shape[1] * x.shape[2] * x.shape[3]))
- sigma = np.dot(flat_x.T, flat_x) / flat_x.shape[0]
- u, s, _ = linalg.svd(sigma)
- self.principal_components = np.dot(
- np.dot(u, np.diag(1. / np.sqrt(s + self.zca_epsilon))), u.T)
+ num_examples = flat_x.shape[0]
+ _, s, vt = linalg.svd(flat_x / np.sqrt(num_examples))
+ s_expand = np.hstack(
+ (s, np.zeros(vt.shape[0] - num_examples, dtype=flat_x.dtype)))
+ self.principal_components = (
+ vt.T / np.sqrt(s_expand**2 + self.zca_epsilon)).dot(vt)
class Iterator(Sequence):
@@ -797,10 +831,10 @@ class Iterator(Sequence):
method.
Arguments:
- n: Integer, total number of samples in the dataset to loop over.
- batch_size: Integer, size of a batch.
- shuffle: Boolean, whether to shuffle the data between epochs.
- seed: Random seeding for data shuffling.
+ n: Integer, total number of samples in the dataset to loop over.
+ batch_size: Integer, size of a batch.
+ shuffle: Boolean, whether to shuffle the data between epochs.
+ seed: Random seeding for data shuffling.
"""
def __init__(self, n, batch_size, shuffle, seed):
@@ -823,15 +857,14 @@ class Iterator(Sequence):
if idx >= len(self):
raise ValueError('Asked to retrieve element {idx}, '
'but the Sequence '
- 'has length {length}'.format(idx=idx,
- length=len(self)))
+ 'has length {length}'.format(idx=idx, length=len(self)))
if self.seed is not None:
np.random.seed(self.seed + self.total_batches_seen)
self.total_batches_seen += 1
if self.index_array is None:
self._set_index_array()
- index_array = self.index_array[self.batch_size * idx:self.batch_size *
- (idx + 1)]
+ index_array = self.index_array[self.batch_size * idx:self.batch_size * (
+ idx + 1)]
return self._get_batches_of_transformed_samples(index_array)
def __len__(self):
@@ -873,6 +906,7 @@ class Iterator(Sequence):
Arguments:
index_array: array of sample indices to include in batch.
+
Returns:
A batch of transformed samples.
"""
@@ -948,8 +982,8 @@ class NumpyArrayIterator(Iterator):
seed)
def _get_batches_of_transformed_samples(self, index_array):
- batch_x = np.zeros(tuple([len(index_array)] + list(self.x.shape)[1:]),
- dtype=K.floatx())
+ batch_x = np.zeros(
+ tuple([len(index_array)] + list(self.x.shape)[1:]), dtype=K.floatx())
for i, j in enumerate(index_array):
x = self.x[j]
x = self.image_data_generator.random_transform(x.astype(K.floatx()))
@@ -959,7 +993,9 @@ class NumpyArrayIterator(Iterator):
for i, j in enumerate(index_array):
img = array_to_img(batch_x[i], self.data_format, scale=True)
fname = '{prefix}_{index}_{hash}.{format}'.format(
- prefix=self.save_prefix, index=j, hash=np.random.randint(1e4),
+ prefix=self.save_prefix,
+ index=j,
+ hash=np.random.randint(1e4),
format=self.save_format)
img.save(os.path.join(self.save_to_dir, fname))
if self.y is None:
@@ -984,10 +1020,11 @@ class NumpyArrayIterator(Iterator):
def _count_valid_files_in_directory(directory, white_list_formats,
follow_links):
- """Count files with extension in `white_list_formats` in a directory.
+ """Count files with extension in `white_list_formats` contained in directory.
Arguments:
- directory: absolute path to the directory containing files to be counted
+ directory: absolute path to the directory
+ containing files to be counted
white_list_formats: set of strings containing allowed extensions for
the files to be counted.
follow_links: boolean.
@@ -1003,7 +1040,7 @@ def _count_valid_files_in_directory(directory, white_list_formats,
samples = 0
for _, _, files in _recursive_list(directory):
- for fname in sorted(files):
+ for fname in files:
is_valid = False
for extension in white_list_formats:
if fname.lower().endswith('.' + extension):
@@ -1043,7 +1080,7 @@ def _list_valid_filenames_in_directory(directory, white_list_formats,
subdir = os.path.basename(directory)
basedir = os.path.dirname(directory)
for root, _, files in _recursive_list(directory):
- for fname in files:
+ for fname in sorted(files):
is_valid = False
for extension in white_list_formats:
if fname.lower().endswith('.' + extension):
@@ -1167,8 +1204,8 @@ class DirectoryIterator(Iterator):
white_list_formats=white_list_formats,
follow_links=follow_links)
self.samples = sum(
- pool.map(function_partial, (os.path.join(directory, subdir)
- for subdir in classes)))
+ pool.map(function_partial,
+ (os.path.join(directory, subdir) for subdir in classes)))
print('Found %d images belonging to %d classes.' % (self.samples,
self.num_classes))
@@ -1181,8 +1218,9 @@ class DirectoryIterator(Iterator):
i = 0
for dirpath in (os.path.join(directory, subdir) for subdir in classes):
results.append(
- pool.apply_async(_list_valid_filenames_in_directory, (
- dirpath, white_list_formats, self.class_indices, follow_links)))
+ pool.apply_async(
+ _list_valid_filenames_in_directory,
+ (dirpath, white_list_formats, self.class_indices, follow_links)))
for res in results:
classes, filenames = res.get()
self.classes[i:i + len(classes)] = classes
@@ -1199,10 +1237,11 @@ class DirectoryIterator(Iterator):
# build batch of image data
for i, j in enumerate(index_array):
fname = self.filenames[j]
- img = load_img(os.path.join(self.directory, fname),
- grayscale=grayscale,
- target_size=self.target_size,
- interpolation=self.interpolation)
+ img = load_img(
+ os.path.join(self.directory, fname),
+ grayscale=grayscale,
+ target_size=self.target_size,
+ interpolation=self.interpolation)
x = img_to_array(img, data_format=self.data_format)
x = self.image_data_generator.random_transform(x)
x = self.image_data_generator.standardize(x)
@@ -1212,7 +1251,9 @@ class DirectoryIterator(Iterator):
for i, j in enumerate(index_array):
img = array_to_img(batch_x[i], self.data_format, scale=True)
fname = '{prefix}_{index}_{hash}.{format}'.format(
- prefix=self.save_prefix, index=j, hash=np.random.randint(1e7),
+ prefix=self.save_prefix,
+ index=j,
+ hash=np.random.randint(1e7),
format=self.save_format)
img.save(os.path.join(self.save_to_dir, fname))
# build batch of labels
@@ -1241,4 +1282,3 @@ class DirectoryIterator(Iterator):
# The transformation of images is not under thread lock
# so it can be done in parallel
return self._get_batches_of_transformed_samples(index_array)
-
diff --git a/tensorflow/python/keras/_impl/keras/preprocessing/sequence.py b/tensorflow/python/keras/_impl/keras/preprocessing/sequence.py
index 642f4f2fac..4d59250af0 100644
--- a/tensorflow/python/keras/_impl/keras/preprocessing/sequence.py
+++ b/tensorflow/python/keras/_impl/keras/preprocessing/sequence.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Preprocessing utilities for sequence data.
+"""Utilities for preprocessing sequence data.
"""
from __future__ import absolute_import
from __future__ import division
@@ -129,7 +129,7 @@ def make_sampling_table(size, sampling_factor=1e-5):
is the probability that a word of rank i should be sampled.
"""
gamma = 0.577
- rank = np.array(list(range(size)))
+ rank = np.arange(size)
rank[0] = 1
inv_fq = rank * (np.log(rank) + gamma) + 0.5 - 1. / (12. * rank)
f = sampling_factor * inv_fq
@@ -170,7 +170,7 @@ def skipgrams(sequence,
if True labels will be categorical eg. [[1,0],[0,1],[0,1] .. ]
sampling_table: 1D array of size `vocabulary_size` where the entry i
encodes the probability to sample a word of rank i.
- seed: Random seed.
+ seed: random seed.
Returns:
couples, labels: where `couples` are int pairs and
@@ -224,3 +224,22 @@ def skipgrams(sequence,
random.shuffle(labels)
return couples, labels
+
+
+def _remove_long_seq(maxlen, seq, label):
+ """Removes sequences that exceed the maximum length.
+
+ Arguments:
+ maxlen: int, maximum length
+ seq: list of lists where each sublist is a sequence
+ label: list where each element is an integer
+
+ Returns:
+ new_seq, new_label: shortened lists for `seq` and `label`.
+ """
+ new_seq, new_label = [], []
+ for x, y in zip(seq, label):
+ if len(x) < maxlen:
+ new_seq.append(x)
+ new_label.append(y)
+ return new_seq, new_label
diff --git a/tensorflow/python/keras/_impl/keras/preprocessing/text.py b/tensorflow/python/keras/_impl/keras/preprocessing/text.py
index 47e5aa064f..8f7f25dc0a 100644
--- a/tensorflow/python/keras/_impl/keras/preprocessing/text.py
+++ b/tensorflow/python/keras/_impl/keras/preprocessing/text.py
@@ -13,8 +13,6 @@
# limitations under the License.
# ==============================================================================
"""Utilities for text input preprocessing.
-
-May benefit from a fast Cython rewrite.
"""
from __future__ import absolute_import
from __future__ import division
@@ -29,6 +27,9 @@ import numpy as np
from six.moves import range # pylint: disable=redefined-builtin
from six.moves import zip # pylint: disable=redefined-builtin
+from tensorflow.python.platform import tf_logging as logging
+
+
if sys.version_info < (3,):
maketrans = string.maketrans
else:
@@ -68,6 +69,21 @@ def one_hot(text,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=' '):
+ """One-hot encodes a text into a list of word indexes of size n.
+
+ This is a wrapper to the `hashing_trick` function using `hash` as the
+ hashing function; unicity of word to index mapping non-guaranteed.
+
+ Arguments:
+ text: Input text (string).
+ n: Dimension of the hashing space.
+ filters: Sequence of characters to filter out.
+ lower: Whether to convert the input to lowercase.
+ split: Sentence split marker (string).
+
+ Returns:
+ A list of integer word indices (unicity non-guaranteed).
+ """
return hashing_trick(
text, n, hash_function=hash, filters=filters, lower=lower, split=split)
@@ -99,6 +115,10 @@ def hashing_trick(text,
Two or more words may be assigned to the same index, due to possible
collisions by the hashing function.
+ The
+ probability
+ of a collision is in relation to the dimension of the hashing space and
+ the number of distinct objects.
"""
if hash_function is None:
hash_function = hash
@@ -127,6 +147,8 @@ class Tokenizer(object):
lower: boolean. Whether to convert the texts to lowercase.
split: character or string to use for token splitting.
char_level: if True, every character will be treated as a token.
+ oov_token: if given, it will be added to word_index and used to
+ replace out-of-vocabulary words during text_to_sequence calls
By default, all punctuation is removed, turning the texts into
space-separated sequences of words
@@ -141,7 +163,17 @@ class Tokenizer(object):
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=' ',
- char_level=False):
+ char_level=False,
+ oov_token=None,
+ **kwargs):
+ # Legacy support
+ if 'nb_words' in kwargs:
+ logging.warning('The `nb_words` argument in `Tokenizer` '
+ 'has been renamed `num_words`.')
+ num_words = kwargs.pop('nb_words')
+ if kwargs:
+ raise TypeError('Unrecognized keyword arguments: ' + str(kwargs))
+
self.word_counts = OrderedDict()
self.word_docs = {}
self.filters = filters
@@ -150,6 +182,7 @@ class Tokenizer(object):
self.num_words = num_words
self.document_count = 0
self.char_level = char_level
+ self.oov_token = oov_token
def fit_on_texts(self, texts):
"""Updates internal vocabulary based on a list of texts.
@@ -181,7 +214,13 @@ class Tokenizer(object):
sorted_voc = [wc[0] for wc in wcounts]
# note that index 0 is reserved, never assigned to an existing word
self.word_index = dict(
- list(zip(sorted_voc, list(range(1, len(sorted_voc) + 1)))))
+ list(zip(sorted_voc, list(range(1,
+ len(sorted_voc) + 1)))))
+
+ if self.oov_token is not None:
+ i = self.word_index.get(self.oov_token)
+ if i is None:
+ self.word_index[self.oov_token] = len(self.word_index) + 1
self.index_docs = {}
for w, c in list(self.word_docs.items()):
@@ -248,6 +287,10 @@ class Tokenizer(object):
continue
else:
vect.append(i)
+ elif self.oov_token is not None:
+ i = self.word_index.get(self.oov_token)
+ if i is not None:
+ vect.append(i)
yield vect
def texts_to_matrix(self, texts, mode='binary'):
diff --git a/tensorflow/python/keras/_impl/keras/preprocessing/text_test.py b/tensorflow/python/keras/_impl/keras/preprocessing/text_test.py
index 17ab48ba3f..a934e331c4 100644
--- a/tensorflow/python/keras/_impl/keras/preprocessing/text_test.py
+++ b/tensorflow/python/keras/_impl/keras/preprocessing/text_test.py
@@ -76,6 +76,22 @@ class TestText(test.TestCase):
self.assertLessEqual(np.max(encoded), 4)
self.assertGreaterEqual(np.min(encoded), 1)
+ def test_tokenizer_oov_flag(self):
+ x_train = ['This text has only known words']
+ x_test = ['This text has some unknown words'] # 2 OOVs: some, unknown
+
+ # Defalut, without OOV flag
+ tokenizer = keras.preprocessing.text.Tokenizer()
+ tokenizer.fit_on_texts(x_train)
+ x_test_seq = tokenizer.texts_to_sequences(x_test)
+ assert len(x_test_seq[0]) == 4 # discards 2 OOVs
+
+ # With OOV feature
+ tokenizer = keras.preprocessing.text.Tokenizer(oov_token='<unk>')
+ tokenizer.fit_on_texts(x_train)
+ x_test_seq = tokenizer.texts_to_sequences(x_test)
+ assert len(x_test_seq[0]) == 6 # OOVs marked in place
+
if __name__ == '__main__':
test.main()
diff --git a/tensorflow/python/keras/_impl/keras/regularizers.py b/tensorflow/python/keras/_impl/keras/regularizers.py
index 161ff9bf5b..c53ee8a1ae 100644
--- a/tensorflow/python/keras/_impl/keras/regularizers.py
+++ b/tensorflow/python/keras/_impl/keras/regularizers.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Keras built-in regularizers.
+"""Built-in regularizers.
"""
from __future__ import absolute_import
from __future__ import division
diff --git a/tensorflow/python/keras/_impl/keras/utils/data_utils.py b/tensorflow/python/keras/_impl/keras/utils/data_utils.py
index d9e8f37e36..fcee9fbcc3 100644
--- a/tensorflow/python/keras/_impl/keras/utils/data_utils.py
+++ b/tensorflow/python/keras/_impl/keras/utils/data_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2018 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,12 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
+# pylint: disable=g-import-not-at-top
"""Utilities for file download and caching."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
from abc import abstractmethod
+from contextlib import closing
import hashlib
import multiprocessing
from multiprocessing.pool import ThreadPool
@@ -38,12 +40,12 @@ from six.moves.urllib.error import URLError
from six.moves.urllib.request import urlopen
from tensorflow.python.keras._impl.keras.utils.generic_utils import Progbar
-from tensorflow.python.util.tf_export import tf_export
+
try:
- import queue # pylint:disable=g-import-not-at-top
+ import queue
except ImportError:
- import Queue as queue # pylint:disable=g-import-not-at-top
+ import Queue as queue
if sys.version_info[0] == 2:
@@ -87,7 +89,7 @@ if sys.version_info[0] == 2:
for chunk in chunk_read(response, reporthook=reporthook):
fd.write(chunk)
else:
- from six.moves.urllib.request import urlretrieve # pylint: disable=g-import-not-at-top
+ from six.moves.urllib.request import urlretrieve
def _extract_archive(file_path, path='.', archive_format='auto'):
@@ -136,7 +138,6 @@ def _extract_archive(file_path, path='.', archive_format='auto'):
return False
-@tf_export('keras.utils.get_file')
def get_file(fname,
origin,
untar=False,
@@ -188,7 +189,7 @@ def get_file(fname,
Path to the downloaded file
"""
if cache_dir is None:
- cache_dir = os.path.expanduser(os.path.join('~', '.keras'))
+ cache_dir = os.path.join(os.path.expanduser('~'), '.keras')
if md5_hash is not None and file_hash is None:
file_hash = md5_hash
hash_algorithm = 'md5'
@@ -317,37 +318,46 @@ def validate_file(fpath, file_hash, algorithm='auto', chunk_size=65535):
return False
-@tf_export('keras.utils.Sequence')
class Sequence(object):
"""Base object for fitting to a sequence of data, such as a dataset.
Every `Sequence` must implements the `__getitem__` and the `__len__` methods.
If you want to modify your dataset between epochs you may implement
- `on_epoch_end`. The method `__getitem__` should return a complete batch.
+ `on_epoch_end`.
+ The method `__getitem__` should return a complete batch.
+
+ # Notes
- Notes:
`Sequence` are a safer way to do multiprocessing. This structure guarantees
- that the network will only train once on each sample per epoch which is not
- the case with generators.
+ that the network will only train once
+ on each sample per epoch which is not the case with generators.
+
Examples:
+
```python
from skimage.io import imread
from skimage.transform import resize
import numpy as np
import math
+
# Here, `x_set` is list of path to the images
# and `y_set` are the associated classes.
+
class CIFAR10Sequence(Sequence):
+
def __init__(self, x_set, y_set, batch_size):
self.x, self.y = x_set, y_set
self.batch_size = batch_size
+
def __len__(self):
return math.ceil(len(self.x) / self.batch_size)
+
def __getitem__(self, idx):
batch_x = self.x[idx * self.batch_size:(idx + 1) *
- self.batch_size]
+ self.batch_size]
batch_y = self.y[idx * self.batch_size:(idx + 1) *
- self.batch_size]
+ self.batch_size]
+
return np.array([
resize(imread(file_name), (200, 200))
for file_name in batch_x]), np.array(batch_y)
@@ -375,7 +385,6 @@ class Sequence(object):
"""
raise NotImplementedError
- @abstractmethod
def on_epoch_end(self):
"""Method called at the end of every epoch.
"""
@@ -405,7 +414,6 @@ def get_index(uid, i):
return _SHARED_SEQUENCES[uid][i]
-@tf_export('keras.utils.SequenceEnqueuer')
class SequenceEnqueuer(object):
"""Base class to enqueue inputs.
@@ -474,35 +482,36 @@ class OrderedEnqueuer(SequenceEnqueuer):
Arguments:
sequence: A `keras.utils.data_utils.Sequence` object.
- use_multiprocessing: Use multiprocessing if True, otherwise threading
- shuffle: Whether to shuffle the data at the beginning of each epoch
+ use_multiprocessing: use multiprocessing if True, otherwise threading
+ shuffle: whether to shuffle the data at the beginning of each epoch
"""
def __init__(self, sequence, use_multiprocessing=False, shuffle=False):
self.sequence = sequence
self.use_multiprocessing = use_multiprocessing
- # Doing Multiprocessing.Value += x is not process-safe.
global _SEQUENCE_COUNTER
if _SEQUENCE_COUNTER is None:
- if self.use_multiprocessing:
+ try:
_SEQUENCE_COUNTER = multiprocessing.Value('i', 0)
- else:
+ except OSError:
+ # In this case the OS does not allow us to use
+ # multiprocessing. We resort to an int
+ # for enqueuer indexing.
_SEQUENCE_COUNTER = 0
- if self.use_multiprocessing:
+ if isinstance(_SEQUENCE_COUNTER, int):
+ self.uid = _SEQUENCE_COUNTER
+ _SEQUENCE_COUNTER += 1
+ else:
+ # Doing Multiprocessing.Value += x is not process-safe.
with _SEQUENCE_COUNTER.get_lock():
self.uid = _SEQUENCE_COUNTER.value
_SEQUENCE_COUNTER.value += 1
- else:
- self.uid = _SEQUENCE_COUNTER
- if isinstance(_SEQUENCE_COUNTER, int):
- _SEQUENCE_COUNTER += 1
- else:
- _SEQUENCE_COUNTER.value += 1
+
self.shuffle = shuffle
self.workers = 0
- self.executor = None
+ self.executor_fn = None
self.queue = None
self.run_thread = None
self.stop_signal = None
@@ -519,9 +528,9 @@ class OrderedEnqueuer(SequenceEnqueuer):
(when full, workers could block on `put()`)
"""
if self.use_multiprocessing:
- self.executor = multiprocessing.Pool(workers)
+ self.executor_fn = lambda: multiprocessing.Pool(workers)
else:
- self.executor = ThreadPool(workers)
+ self.executor_fn = lambda: ThreadPool(workers)
self.workers = workers
self.queue = queue.Queue(max_queue_size)
self.stop_signal = threading.Event()
@@ -537,24 +546,26 @@ class OrderedEnqueuer(SequenceEnqueuer):
return
def _run(self):
- """Function to submit request to the executor & queue `Future` objects."""
+ """Submits request to the executor and queue the `Future` objects."""
sequence = list(range(len(self.sequence)))
self._send_sequence() # Share the initial sequence
while True:
if self.shuffle:
random.shuffle(sequence)
- for i in sequence:
- if self.stop_signal.is_set():
- return
- self.queue.put(
- self.executor.apply_async(get_index, (self.uid, i)), block=True)
- # Done with the current epoch, waiting for the final batches
- self._wait_queue()
+ with closing(self.executor_fn()) as executor:
+ for i in sequence:
+ if self.stop_signal.is_set():
+ return
+ self.queue.put(
+ executor.apply_async(get_index, (self.uid, i)), block=True)
- if self.stop_signal.is_set():
- # We're done
- return
+ # Done with the current epoch, waiting for the final batches
+ self._wait_queue()
+
+ if self.stop_signal.is_set():
+ # We're done
+ return
# Call the internal on epoch end.
self.sequence.on_epoch_end()
@@ -566,8 +577,9 @@ class OrderedEnqueuer(SequenceEnqueuer):
Skip the data if it is `None`.
Yields:
- Tuples (inputs, targets)
- or (inputs, targets, sample_weights)
+ The next element in the queue, i.e. a tuple
+ `(inputs, targets)` or
+ `(inputs, targets, sample_weights)`.
"""
try:
while self.is_running():
@@ -581,14 +593,8 @@ class OrderedEnqueuer(SequenceEnqueuer):
def _send_sequence(self):
"""Send current Sequence to all workers."""
- _SHARED_SEQUENCES[
- self.uid] = self.sequence # For new processes that may spawn
-
- self._close_pool()
- if self.use_multiprocessing:
- self.executor = multiprocessing.Pool(self.workers)
- else:
- self.executor = ThreadPool(self.workers)
+ # For new processes that may spawn
+ _SHARED_SEQUENCES[self.uid] = self.sequence
def stop(self, timeout=None):
"""Stops running threads and wait for them to exit, if necessary.
@@ -603,16 +609,10 @@ class OrderedEnqueuer(SequenceEnqueuer):
self.queue.queue.clear()
self.queue.unfinished_tasks = 0
self.queue.not_full.notify()
- self._close_pool()
self.run_thread.join(timeout)
_SHARED_SEQUENCES[self.uid] = None
- def _close_pool(self):
- self.executor.close()
- self.executor.join()
-
-@tf_export('keras.utils.GeneratorEnqueuer')
class GeneratorEnqueuer(SequenceEnqueuer):
"""Builds a queue out of a data generator.
@@ -636,26 +636,53 @@ class GeneratorEnqueuer(SequenceEnqueuer):
seed=None):
self.wait_time = wait_time
self._generator = generator
- self._use_multiprocessing = use_multiprocessing
+ if os.name is 'nt' and use_multiprocessing is True:
+ # On Windows, avoid **SYSTEMATIC** error in `multiprocessing`:
+ # `TypeError: can't pickle generator objects`
+ # => Suggest multithreading instead of multiprocessing on Windows
+ raise ValueError('Using a generator with `use_multiprocessing=True`'
+ ' is not supported on Windows (no marshalling of'
+ ' generators across process boundaries). Instead,'
+ ' use single thread/process or multithreading.')
+ else:
+ self._use_multiprocessing = use_multiprocessing
self._threads = []
self._stop_event = None
self._manager = None
self.queue = None
self.seed = seed
- def start(self, workers=1, max_queue_size=10):
- """Kicks off threads which add data from the generator into the queue.
-
- Arguments:
- workers: number of worker threads
- max_queue_size: queue size
- (when full, threads could block on `put()`)
- """
-
- def data_generator_task():
+ def _data_generator_task(self):
+ if self._use_multiprocessing is False:
+ while not self._stop_event.is_set():
+ with self.genlock:
+ try:
+ if (self.queue is not None and
+ self.queue.qsize() < self.max_queue_size):
+ # On all OSes, avoid **SYSTEMATIC** error
+ # in multithreading mode:
+ # `ValueError: generator already executing`
+ # => Serialize calls to
+ # infinite iterator/generator's next() function
+ generator_output = next(self._generator)
+ self.queue.put((True, generator_output))
+ else:
+ time.sleep(self.wait_time)
+ except StopIteration:
+ break
+ except Exception as e: # pylint: disable=broad-except
+ # Can't pickle tracebacks.
+ # As a compromise, print the traceback and pickle None instead.
+ if not hasattr(e, '__traceback__'):
+ setattr(e, '__traceback__', sys.exc_info()[2])
+ self.queue.put((False, e))
+ self._stop_event.set()
+ break
+ else:
while not self._stop_event.is_set():
try:
- if self._use_multiprocessing or self.queue.qsize() < max_queue_size:
+ if (self.queue is not None and
+ self.queue.qsize() < self.max_queue_size):
generator_output = next(self._generator)
self.queue.put((True, generator_output))
else:
@@ -663,24 +690,34 @@ class GeneratorEnqueuer(SequenceEnqueuer):
except StopIteration:
break
except Exception as e: # pylint: disable=broad-except
- # Can't pick tracebacks.
+ # Can't pickle tracebacks.
# As a compromise, print the traceback and pickle None instead.
- if self._use_multiprocessing:
- traceback.print_exc()
- setattr(e, '__traceback__', None)
- elif not hasattr(e, '__traceback__'):
- setattr(e, '__traceback__', sys.exc_info()[2])
+ traceback.print_exc()
+ setattr(e, '__traceback__', None)
self.queue.put((False, e))
self._stop_event.set()
break
+ def start(self, workers=1, max_queue_size=10):
+ """Kicks off threads which add data from the generator into the queue.
+
+ Arguments:
+ workers: number of worker threads
+ max_queue_size: queue size
+ (when full, threads could block on `put()`)
+ """
try:
+ self.max_queue_size = max_queue_size
if self._use_multiprocessing:
self._manager = multiprocessing.Manager()
self.queue = self._manager.Queue(maxsize=max_queue_size)
self._stop_event = multiprocessing.Event()
else:
- self.queue = queue.Queue()
+ # On all OSes, avoid **SYSTEMATIC** error in multithreading mode:
+ # `ValueError: generator already executing`
+ # => Serialize calls to infinite iterator/generator's next() function
+ self.genlock = threading.Lock()
+ self.queue = queue.Queue(maxsize=max_queue_size)
self._stop_event = threading.Event()
for _ in range(workers):
@@ -688,12 +725,12 @@ class GeneratorEnqueuer(SequenceEnqueuer):
# Reset random seed else all children processes
# share the same seed
np.random.seed(self.seed)
- thread = multiprocessing.Process(target=data_generator_task)
+ thread = multiprocessing.Process(target=self._data_generator_task)
thread.daemon = True
if self.seed is not None:
self.seed += 1
else:
- thread = threading.Thread(target=data_generator_task)
+ thread = threading.Thread(target=self._data_generator_task)
self._threads.append(thread)
thread.start()
except:
@@ -715,11 +752,15 @@ class GeneratorEnqueuer(SequenceEnqueuer):
self._stop_event.set()
for thread in self._threads:
- if thread.is_alive():
- if self._use_multiprocessing:
+ if self._use_multiprocessing:
+ if thread.is_alive():
thread.terminate()
- else:
- thread.join(timeout)
+ else:
+ # The thread.is_alive() test is subject to a race condition:
+ # the thread could terminate right after the test and before the
+ # join, rendering this test meaningless -> Call thread.join()
+ # always, which is ok no matter what the status of the thread.
+ thread.join(timeout)
if self._manager:
self._manager.shutdown()
@@ -734,7 +775,9 @@ class GeneratorEnqueuer(SequenceEnqueuer):
Skip the data if it is `None`.
Yields:
- Data arrays.
+ The next element in the queue, i.e. a tuple
+ `(inputs, targets)` or
+ `(inputs, targets, sample_weights)`.
"""
while self.is_running():
if not self.queue.empty():
@@ -752,7 +795,7 @@ class GeneratorEnqueuer(SequenceEnqueuer):
else:
time.sleep(self.wait_time)
- # Make sure to rethrow the first exception in the queue, if any
+ # Make sure to rethrow the first exception in the queue, if any
while not self.queue.empty():
success, value = self.queue.get()
if not success:
diff --git a/tensorflow/python/keras/_impl/keras/utils/generic_utils.py b/tensorflow/python/keras/_impl/keras/utils/generic_utils.py
index a805315c94..adbe6c3288 100644
--- a/tensorflow/python/keras/_impl/keras/utils/generic_utils.py
+++ b/tensorflow/python/keras/_impl/keras/utils/generic_utils.py
@@ -17,6 +17,7 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
+import binascii
import codecs
import marshal
import os
@@ -255,7 +256,10 @@ def func_load(code, defaults=None, closure=None, globs=None):
if closure is not None:
closure = tuple(ensure_value_to_cell(_) for _ in closure)
- raw_code = codecs.decode(code.encode('ascii'), 'base64')
+ try:
+ raw_code = codecs.decode(code.encode('ascii'), 'base64')
+ except (UnicodeEncodeError, binascii.Error):
+ raw_code = code.encode('raw_unicode_escape')
code = marshal.loads(raw_code)
if globs is None:
globs = globals()
diff --git a/tensorflow/python/keras/_impl/keras/utils/io_utils.py b/tensorflow/python/keras/_impl/keras/utils/io_utils.py
index e123339f5a..b36c769843 100644
--- a/tensorflow/python/keras/_impl/keras/utils/io_utils.py
+++ b/tensorflow/python/keras/_impl/keras/utils/io_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2018 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,6 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
+# pylint: disable=g-import-not-at-top
"""Utilities related to disk I/O."""
from __future__ import absolute_import
from __future__ import division
@@ -21,16 +22,14 @@ from collections import defaultdict
import sys
import numpy as np
-from tensorflow.python.util.tf_export import tf_export
try:
- import h5py # pylint:disable=g-import-not-at-top
+ import h5py
except ImportError:
h5py = None
-@tf_export('keras.utils.HDF5Matrix')
class HDF5Matrix(object):
"""Representation of HDF5 dataset to be used instead of a Numpy array.
@@ -65,11 +64,11 @@ class HDF5Matrix(object):
'HDF5 and h5py installed.')
if datapath not in list(self.refs.keys()):
- self._f = h5py.File(datapath)
- self.refs[datapath] = self._f
+ f = h5py.File(datapath)
+ self.refs[datapath] = f
else:
- self._f = self.refs[datapath]
- self.data = self._f[dataset]
+ f = self.refs[datapath]
+ self.data = f[dataset]
self.start = start
if end is None:
self.end = self.data.shape[0]
@@ -80,9 +79,6 @@ class HDF5Matrix(object):
def __len__(self):
return self.end - self.start
- def __del__(self):
- self._f.close()
-
def __getitem__(self, key):
if isinstance(key, slice):
start, stop = key.start, key.stop
diff --git a/tensorflow/python/keras/_impl/keras/utils/layer_utils.py b/tensorflow/python/keras/_impl/keras/utils/layer_utils.py
index 30af285cbf..a2d32424b5 100644
--- a/tensorflow/python/keras/_impl/keras/utils/layer_utils.py
+++ b/tensorflow/python/keras/_impl/keras/utils/layer_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2018 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,7 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""Utilities related to Keras layers.
+# pylint: disable=protected-access
+"""Utilities related to layer/model functionality.
"""
from __future__ import absolute_import
from __future__ import division
@@ -22,17 +23,16 @@ import numpy as np
from tensorflow.python.keras._impl.keras import backend as K
from tensorflow.python.keras._impl.keras.utils.conv_utils import convert_kernel
-from tensorflow.python.util.tf_export import tf_export
def count_params(weights):
"""Count the total number of scalars composing the weights.
Arguments:
- weights: An iterable containing the weights on which to compute params
+ weights: An iterable containing the weights on which to compute params
Returns:
- The total number of scalars composing the weights
+ The total number of scalars composing the weights
"""
return int(np.sum([K.count_params(p) for p in set(weights)]))
@@ -47,10 +47,11 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
terminal window sizes).
positions: Relative or absolute positions of log elements in each line.
If not provided, defaults to `[.33, .55, .67, 1.]`.
- print_fn: Print function to use (defaults to `print`).
+ print_fn: Print function to use.
It will be called on each line of the summary.
You can set it to a custom function
in order to capture the string summary.
+ It defaults to `print` (prints to stdout).
"""
if print_fn is None:
print_fn = print
@@ -59,12 +60,13 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
sequential_like = True
else:
sequential_like = True
- nodes_by_depth = model._nodes_by_depth.values() # pylint: disable=protected-access
+ nodes_by_depth = model._nodes_by_depth.values()
nodes = []
for v in nodes_by_depth:
if (len(v) > 1) or (len(v) == 1 and len(v[0].inbound_layers) > 1):
- # If the model has multiple nodes or if the nodes have
- # multiple inbound_layers, the model is no longer sequential.
+ # if the model has multiple nodes
+ # or if the nodes have multiple inbound_layers
+ # the model is no longer sequential
sequential_like = False
break
nodes += v
@@ -72,7 +74,7 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
# search for shared layers
for layer in model.layers:
flag = False
- for node in layer.inbound_nodes:
+ for node in layer._inbound_nodes:
if node in nodes:
if flag:
sequential_like = False
@@ -97,7 +99,7 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
# header names for the different log elements
to_display = ['Layer (type)', 'Output Shape', 'Param #', 'Connected to']
relevant_nodes = []
- for v in model._nodes_by_depth.values(): # pylint: disable=protected-access
+ for v in model._nodes_by_depth.values():
relevant_nodes += v
def print_row(fields, positions):
@@ -135,7 +137,7 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
except AttributeError:
output_shape = 'multiple'
connections = []
- for node in layer._inbound_nodes: # pylint: disable=protected-access
+ for node in layer._inbound_nodes:
if relevant_nodes and node not in relevant_nodes:
# node is not part of the current network
continue
@@ -143,8 +145,8 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
inbound_layer = node.inbound_layers[i].name
inbound_node_index = node.node_indices[i]
inbound_tensor_index = node.tensor_indices[i]
- connections.append(inbound_layer + '[' + str(inbound_node_index) + ']['
- + str(inbound_tensor_index) + ']')
+ connections.append(inbound_layer + '[' + str(inbound_node_index) +
+ '][' + str(inbound_tensor_index) + ']')
name = layer.name
cls_name = layer.__class__.__name__
@@ -173,9 +175,9 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
else:
print_fn('_' * line_length)
- model._check_trainable_weights_consistency() # pylint: disable=protected-access
+ model._check_trainable_weights_consistency()
if hasattr(model, '_collected_trainable_weights'):
- trainable_count = count_params(model._collected_trainable_weights) # pylint: disable=protected-access
+ trainable_count = count_params(model._collected_trainable_weights)
else:
trainable_count = count_params(model.trainable_weights)
@@ -188,7 +190,6 @@ def print_summary(model, line_length=None, positions=None, print_fn=None):
print_fn('_' * line_length)
-@tf_export('keras.utils.convert_all_kernels_in_model')
def convert_all_kernels_in_model(model):
"""Converts all convolution kernels in a model from Theano to TensorFlow.
diff --git a/tensorflow/python/keras/_impl/keras/utils/np_utils.py b/tensorflow/python/keras/_impl/keras/utils/np_utils.py
index 3dddb99191..231833e776 100644
--- a/tensorflow/python/keras/_impl/keras/utils/np_utils.py
+++ b/tensorflow/python/keras/_impl/keras/utils/np_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2018 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.
@@ -18,10 +18,8 @@ from __future__ import division
from __future__ import print_function
import numpy as np
-from tensorflow.python.util.tf_export import tf_export
-@tf_export('keras.utils.to_categorical')
def to_categorical(y, num_classes=None):
"""Converts a class vector (integers) to binary class matrix.
@@ -50,7 +48,6 @@ def to_categorical(y, num_classes=None):
return categorical
-@tf_export('keras.utils.normalize')
def normalize(x, axis=-1, order=2):
"""Normalizes a Numpy array.
diff --git a/tensorflow/python/keras/_impl/keras/utils/vis_utils.py b/tensorflow/python/keras/_impl/keras/utils/vis_utils.py
index 1ec8e3a2bf..0c5f2c19c7 100644
--- a/tensorflow/python/keras/_impl/keras/utils/vis_utils.py
+++ b/tensorflow/python/keras/_impl/keras/utils/vis_utils.py
@@ -1,4 +1,4 @@
-# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
+# Copyright 2018 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,31 +12,29 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
+# pylint: disable=protected-access
+# pylint: disable=g-import-not-at-top
"""Utilities related to model visualization."""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
-import sys
-from tensorflow.python.util.tf_export import tf_export
+
try:
# pydot-ng is a fork of pydot that is better maintained.
- import pydot_ng as pydot # pylint: disable=g-import-not-at-top
+ import pydot_ng as pydot
except ImportError:
- # Fall back on pydot if necessary.
- # Silence a `print` statement that occurs in case of import error,
- # by temporarily replacing sys.stdout.
- _stdout = sys.stdout
- sys.stdout = sys.stderr
+ # pydotplus is an improved version of pydot
try:
- import pydot # pylint: disable=g-import-not-at-top
+ import pydotplus as pydot
except ImportError:
- pydot = None
- finally:
- # Restore sys.stdout.
- sys.stdout = _stdout
+ # Fall back on pydot if necessary.
+ try:
+ import pydot
+ except ImportError:
+ pydot = None
def _check_pydot():
@@ -66,8 +64,8 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True, rankdir='TB'):
Returns:
A `pydot.Dot` instance representing the Keras model.
"""
- from tensorflow.python.keras._impl.keras.layers.wrappers import Wrapper # pylint: disable=g-import-not-at-top
- from tensorflow.python.keras._impl.keras.models import Sequential # pylint: disable=g-import-not-at-top
+ from tensorflow.python.keras._impl.keras.layers.wrappers import Wrapper
+ from tensorflow.python.keras._impl.keras.models import Sequential
_check_pydot()
dot = pydot.Dot()
@@ -119,9 +117,9 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True, rankdir='TB'):
# Connect nodes with edges.
for layer in layers:
layer_id = str(id(layer))
- for i, node in enumerate(layer._inbound_nodes): # pylint: disable=protected-access
+ for i, node in enumerate(layer._inbound_nodes):
node_key = layer.name + '_ib-' + str(i)
- if node_key in model._network_nodes: # pylint: disable=protected-access
+ if node_key in model._container_nodes:
for inbound_layer in node.inbound_layers:
inbound_layer_id = str(id(inbound_layer))
layer_id = str(id(layer))
@@ -129,7 +127,6 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True, rankdir='TB'):
return dot
-@tf_export('keras.utils.plot_model')
def plot_model(model,
to_file='model.png',
show_shapes=False,
diff --git a/tensorflow/python/keras/_impl/keras/wrappers/scikit_learn.py b/tensorflow/python/keras/_impl/keras/wrappers/scikit_learn.py
index bc788d874f..223ceac3de 100644
--- a/tensorflow/python/keras/_impl/keras/wrappers/scikit_learn.py
+++ b/tensorflow/python/keras/_impl/keras/wrappers/scikit_learn.py
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
-"""API wrapper allowing to use certain Keras models with the Scikit-Learn API.
+"""Wrapper for using the Scikit-Learn API with Keras models.
"""
from __future__ import absolute_import
from __future__ import division
@@ -24,8 +24,8 @@ import types
import numpy as np
from tensorflow.python.keras._impl.keras.models import Sequential
+from tensorflow.python.keras._impl.keras.utils.generic_utils import has_arg
from tensorflow.python.keras._impl.keras.utils.np_utils import to_categorical
-from tensorflow.python.util import tf_inspect
class BaseWrapper(object):
@@ -75,7 +75,7 @@ class BaseWrapper(object):
self.check_params(sk_params)
def check_params(self, params):
- """Checks for user typos in "params".
+ """Checks for user typos in `params`.
Arguments:
params: dictionary; the parameters to be checked
@@ -95,13 +95,11 @@ class BaseWrapper(object):
else:
legal_params_fns.append(self.build_fn)
- legal_params = []
- for fn in legal_params_fns:
- legal_params += tf_inspect.getargspec(fn)[0]
- legal_params = set(legal_params)
-
for params_name in params:
- if params_name not in legal_params:
+ for fn in legal_params_fns:
+ if has_arg(fn, params_name):
+ break
+ else:
if params_name != 'nb_epoch':
raise ValueError('{} is not a legal parameter'.format(params_name))
@@ -136,10 +134,10 @@ class BaseWrapper(object):
Arguments:
x : array-like, shape `(n_samples, n_features)`
- Training samples where n_samples in the number of samples
- and n_features is the number of features.
+ Training samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
y : array-like, shape `(n_samples,)` or `(n_samples, n_outputs)`
- True labels for X.
+ True labels for `x`.
**kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.fit`
@@ -170,21 +168,20 @@ class BaseWrapper(object):
return history
def filter_sk_params(self, fn, override=None):
- """Filters `sk_params` and return those in `fn`'s arguments.
+ """Filters `sk_params` and returns those in `fn`'s arguments.
Arguments:
fn : arbitrary function
- override: dictionary, values to override sk_params
+ override: dictionary, values to override `sk_params`
Returns:
- res : dictionary dictionary containing variables
- in both sk_params and fn's arguments.
+ res : dictionary containing variables
+ in both `sk_params` and `fn`'s arguments.
"""
override = override or {}
res = {}
- fn_args = tf_inspect.getargspec(fn)[0]
for name, value in self.sk_params.items():
- if name in fn_args:
+ if has_arg(fn, name):
res.update({name: value})
res.update(override)
return res
@@ -199,10 +196,10 @@ class KerasClassifier(BaseWrapper):
Arguments:
x : array-like, shape `(n_samples, n_features)`
- Training samples where n_samples in the number of samples
- and n_features is the number of features.
+ Training samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
y : array-like, shape `(n_samples,)` or `(n_samples, n_outputs)`
- True labels for X.
+ True labels for `x`.
**kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.fit`
@@ -229,8 +226,8 @@ class KerasClassifier(BaseWrapper):
Arguments:
x: array-like, shape `(n_samples, n_features)`
- Test samples where n_samples in the number of samples
- and n_features is the number of features.
+ Test samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
**kwargs: dictionary arguments
Legal arguments are the arguments
of `Sequential.predict_classes`.
@@ -248,8 +245,8 @@ class KerasClassifier(BaseWrapper):
Arguments:
x: array-like, shape `(n_samples, n_features)`
- Test samples where n_samples in the number of samples
- and n_features is the number of features.
+ Test samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
**kwargs: dictionary arguments
Legal arguments are the arguments
of `Sequential.predict_classes`.
@@ -258,8 +255,8 @@ class KerasClassifier(BaseWrapper):
proba: array-like, shape `(n_samples, n_outputs)`
Class probability estimates.
In the case of binary classification,
- tp match the scikit-learn API,
- will return an array of shape '(n_samples, 2)'
+ to match the scikit-learn API,
+ will return an array of shape `(n_samples, 2)`
(instead of `(n_sample, 1)` as in Keras).
"""
kwargs = self.filter_sk_params(Sequential.predict_proba, kwargs)
@@ -276,16 +273,16 @@ class KerasClassifier(BaseWrapper):
Arguments:
x: array-like, shape `(n_samples, n_features)`
- Test samples where n_samples in the number of samples
- and n_features is the number of features.
+ Test samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
y: array-like, shape `(n_samples,)` or `(n_samples, n_outputs)`
- True labels for x.
+ True labels for `x`.
**kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.evaluate`.
Returns:
score: float
- Mean accuracy of predictions on X wrt. y.
+ Mean accuracy of predictions on `x` wrt. `y`.
Raises:
ValueError: If the underlying model isn't configured to
@@ -321,8 +318,8 @@ class KerasRegressor(BaseWrapper):
Arguments:
x: array-like, shape `(n_samples, n_features)`
- Test samples where n_samples in the number of samples
- and n_features is the number of features.
+ Test samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
**kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.predict`.
@@ -338,16 +335,16 @@ class KerasRegressor(BaseWrapper):
Arguments:
x: array-like, shape `(n_samples, n_features)`
- Test samples where n_samples in the number of samples
- and n_features is the number of features.
+ Test samples where `n_samples` is the number of samples
+ and `n_features` is the number of features.
y: array-like, shape `(n_samples,)`
- True labels for X.
+ True labels for `x`.
**kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.evaluate`.
Returns:
score: float
- Mean accuracy of predictions on X wrt. y.
+ Mean accuracy of predictions on `x` wrt. `y`.
"""
kwargs = self.filter_sk_params(Sequential.evaluate, kwargs)
loss = self.model.evaluate(x, y, **kwargs)
diff --git a/tensorflow/python/keras/applications/__init__.py b/tensorflow/python/keras/applications/__init__.py
index 34f1435ffb..fccedf919a 100644
--- a/tensorflow/python/keras/applications/__init__.py
+++ b/tensorflow/python/keras/applications/__init__.py
@@ -18,16 +18,23 @@ from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
+from tensorflow.python.keras.applications import densenet
from tensorflow.python.keras.applications import inception_resnet_v2
from tensorflow.python.keras.applications import inception_v3
from tensorflow.python.keras.applications import mobilenet
+from tensorflow.python.keras.applications import nasnet
from tensorflow.python.keras.applications import resnet50
from tensorflow.python.keras.applications import vgg16
from tensorflow.python.keras.applications import vgg19
from tensorflow.python.keras.applications import xception
+from tensorflow.python.keras.applications.densenet import DenseNet121
+from tensorflow.python.keras.applications.densenet import DenseNet169
+from tensorflow.python.keras.applications.densenet import DenseNet201
from tensorflow.python.keras.applications.inception_resnet_v2 import InceptionResNetV2
from tensorflow.python.keras.applications.inception_v3 import InceptionV3
from tensorflow.python.keras.applications.mobilenet import MobileNet
+from tensorflow.python.keras.applications.nasnet import NASNetLarge
+from tensorflow.python.keras.applications.nasnet import NASNetMobile
from tensorflow.python.keras.applications.resnet50 import ResNet50
from tensorflow.python.keras.applications.vgg16 import VGG16
from tensorflow.python.keras.applications.vgg19 import VGG19
diff --git a/tensorflow/python/keras/applications/densenet/__init__.py b/tensorflow/python/keras/applications/densenet/__init__.py
new file mode 100644
index 0000000000..6b8ea83920
--- /dev/null
+++ b/tensorflow/python/keras/applications/densenet/__init__.py
@@ -0,0 +1,29 @@
+# Copyright 2018 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.
+# ==============================================================================
+"""DenseNet Keras applications."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from tensorflow.python.keras._impl.keras.applications.densenet import decode_predictions
+from tensorflow.python.keras._impl.keras.applications.densenet import DenseNet121
+from tensorflow.python.keras._impl.keras.applications.densenet import DenseNet169
+from tensorflow.python.keras._impl.keras.applications.densenet import DenseNet201
+from tensorflow.python.keras._impl.keras.applications.densenet import preprocess_input
+
+del absolute_import
+del division
+del print_function
diff --git a/tensorflow/python/keras/applications/nasnet/__init__.py b/tensorflow/python/keras/applications/nasnet/__init__.py
new file mode 100644
index 0000000000..94eb145b85
--- /dev/null
+++ b/tensorflow/python/keras/applications/nasnet/__init__.py
@@ -0,0 +1,28 @@
+# Copyright 2018 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.
+# ==============================================================================
+"""NASNet Keras applications."""
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+
+from tensorflow.python.keras._impl.keras.applications.nasnet import decode_predictions
+from tensorflow.python.keras._impl.keras.applications.nasnet import NASNetLarge
+from tensorflow.python.keras._impl.keras.applications.nasnet import NASNetMobile
+from tensorflow.python.keras._impl.keras.applications.nasnet import preprocess_input
+
+del absolute_import
+del division
+del print_function
diff --git a/tensorflow/python/keras/layers/__init__.py b/tensorflow/python/keras/layers/__init__.py
index b94bf8f0f6..84ee5040dc 100644
--- a/tensorflow/python/keras/layers/__init__.py
+++ b/tensorflow/python/keras/layers/__init__.py
@@ -30,6 +30,7 @@ from tensorflow.python.keras._impl.keras.layers.advanced_activations import Leak
from tensorflow.python.keras._impl.keras.layers.advanced_activations import PReLU
from tensorflow.python.keras._impl.keras.layers.advanced_activations import ELU
from tensorflow.python.keras._impl.keras.layers.advanced_activations import ThresholdedReLU
+from tensorflow.python.keras._impl.keras.layers.advanced_activations import Softmax
# Convolution layers.
from tensorflow.python.keras._impl.keras.layers.convolutional import Conv1D
@@ -37,6 +38,7 @@ from tensorflow.python.keras._impl.keras.layers.convolutional import Conv2D
from tensorflow.python.keras._impl.keras.layers.convolutional import Conv3D
from tensorflow.python.keras._impl.keras.layers.convolutional import Conv2DTranspose
from tensorflow.python.keras._impl.keras.layers.convolutional import Conv3DTranspose
+from tensorflow.python.keras._impl.keras.layers.convolutional import SeparableConv1D
from tensorflow.python.keras._impl.keras.layers.convolutional import SeparableConv2D
# Convolution layer aliases.
@@ -45,6 +47,7 @@ from tensorflow.python.keras._impl.keras.layers.convolutional import Convolution
from tensorflow.python.keras._impl.keras.layers.convolutional import Convolution3D
from tensorflow.python.keras._impl.keras.layers.convolutional import Convolution2DTranspose
from tensorflow.python.keras._impl.keras.layers.convolutional import Convolution3DTranspose
+from tensorflow.python.keras._impl.keras.layers.convolutional import SeparableConvolution1D
from tensorflow.python.keras._impl.keras.layers.convolutional import SeparableConvolution2D
# Image processing layers.
diff --git a/tensorflow/python/layers/base.py b/tensorflow/python/layers/base.py
index d892654ebe..5d9feb07b4 100644
--- a/tensorflow/python/layers/base.py
+++ b/tensorflow/python/layers/base.py
@@ -99,8 +99,16 @@ class Layer(object):
raise TypeError('Keyword argument not understood:', kwarg)
# Mutable properties
+ # Indicates whether the layer's weights are updated during training
+ # and whether the layer's updates are run during training
self.trainable = trainable
+ # A stateful layer is a layer whose updates are run during inference too,
+ # for instance stateful RNNs.
+ self.stateful = False
+ # Indicates whether `build` needs to be called upon layer call, to create
+ # the layer's weights.
self.built = False
+ # Provides information about which inputs are compatible with the layer.
self.input_spec = None
if activity_regularizer and context.in_eager_mode():
@@ -223,6 +231,8 @@ class Layer(object):
def updates(self):
if context.in_eager_mode():
raise RuntimeError('Layer.updates not supported in Eager mode.')
+ if not self.trainable and not self.stateful:
+ return []
return self._updates
def add_update(self, updates, inputs=None):
@@ -284,6 +294,8 @@ class Layer(object):
"""
if context.in_eager_mode():
raise RuntimeError('Layer.get_updates_for not supported in Eager mode.')
+ if not self.trainable and not self.stateful:
+ return []
if inputs is not None:
inputs = nest.flatten(inputs)
if not inputs:
@@ -1269,6 +1281,15 @@ class InputSpec(object):
self.min_ndim = min_ndim
self.axes = axes or {}
+ def __repr__(self):
+ spec = [('dtype=' + str(self.dtype)) if self.dtype else '',
+ ('shape=' + str(self.shape)) if self.shape else '',
+ ('ndim=' + str(self.ndim)) if self.ndim else '',
+ ('max_ndim=' + str(self.max_ndim)) if self.max_ndim else '',
+ ('min_ndim=' + str(self.min_ndim)) if self.min_ndim else '',
+ ('axes=' + str(self.axes)) if self.axes else '']
+ return 'InputSpec(%s)' % ', '.join(x for x in spec if x)
+
class Node(object):
"""A `Node` describes the connectivity between two layers.
diff --git a/tensorflow/python/layers/network.py b/tensorflow/python/layers/network.py
index ade57da411..0a5dd57621 100644
--- a/tensorflow/python/layers/network.py
+++ b/tensorflow/python/layers/network.py
@@ -575,6 +575,11 @@ class GraphNetwork(base.Layer):
raise ValueError('No such layer: ' + name)
@property
+ def stateful(self):
+ return any([(hasattr(layer, 'stateful') and layer.stateful)
+ for layer in self.layers])
+
+ @property
def updates(self):
"""Retrieve the network's updates.
@@ -586,6 +591,8 @@ class GraphNetwork(base.Layer):
Returns:
A list of update ops.
"""
+ if not self.trainable and not self.stateful:
+ return []
updates = []
for layer in self.layers:
if hasattr(layer, 'updates'):
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.-model.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.-model.pbtxt
index 7fe3e2db09..2bf584fa29 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.-model.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.-model.pbtxt
@@ -160,15 +160,15 @@ tf_class {
}
member_method {
name: "evaluate_generator"
- argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'10\', \'1\', \'False\'], "
+ argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'1\', \'False\'], "
}
member_method {
name: "fit"
- argspec: "args=[\'self\', \'x\', \'y\', \'batch_size\', \'epochs\', \'verbose\', \'callbacks\', \'validation_split\', \'validation_data\', \'shuffle\', \'class_weight\', \'sample_weight\', \'initial_epoch\', \'steps_per_epoch\', \'validation_steps\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'1\', \'1\', \'None\', \'0.0\', \'None\', \'True\', \'None\', \'None\', \'0\', \'None\', \'None\'], "
+ argspec: "args=[\'self\', \'x\', \'y\', \'batch_size\', \'epochs\', \'verbose\', \'callbacks\', \'validation_split\', \'validation_data\', \'shuffle\', \'class_weight\', \'sample_weight\', \'initial_epoch\', \'steps_per_epoch\', \'validation_steps\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'None\', \'None\', \'1\', \'1\', \'None\', \'0.0\', \'None\', \'True\', \'None\', \'None\', \'0\', \'None\', \'None\'], "
}
member_method {
name: "fit_generator"
- argspec: "args=[\'self\', \'generator\', \'steps_per_epoch\', \'epochs\', \'verbose\', \'callbacks\', \'validation_data\', \'validation_steps\', \'class_weight\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'shuffle\', \'initial_epoch\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'1\', \'1\', \'None\', \'None\', \'None\', \'None\', \'10\', \'1\', \'False\', \'True\', \'0\'], "
+ argspec: "args=[\'self\', \'generator\', \'steps_per_epoch\', \'epochs\', \'verbose\', \'callbacks\', \'validation_data\', \'validation_steps\', \'class_weight\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'shuffle\', \'initial_epoch\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'1\', \'None\', \'None\', \'None\', \'None\', \'10\', \'1\', \'False\', \'True\', \'0\'], "
}
member_method {
name: "from_config"
@@ -228,7 +228,7 @@ tf_class {
}
member_method {
name: "predict_generator"
- argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'verbose\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'10\', \'1\', \'False\', \'0\'], "
+ argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'verbose\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'1\', \'False\', \'0\'], "
}
member_method {
name: "predict_on_batch"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.applications.densenet.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.applications.densenet.pbtxt
new file mode 100644
index 0000000000..42cb914450
--- /dev/null
+++ b/tensorflow/tools/api/golden/tensorflow.keras.applications.densenet.pbtxt
@@ -0,0 +1,23 @@
+path: "tensorflow.keras.applications.densenet"
+tf_module {
+ member_method {
+ name: "DenseNet121"
+ argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "DenseNet169"
+ argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "DenseNet201"
+ argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "decode_predictions"
+ argspec: "args=[\'preds\', \'top\'], varargs=None, keywords=None, defaults=[\'5\'], "
+ }
+ member_method {
+ name: "preprocess_input"
+ argspec: "args=[\'x\', \'data_format\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.applications.nasnet.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.applications.nasnet.pbtxt
new file mode 100644
index 0000000000..cd75b87540
--- /dev/null
+++ b/tensorflow/tools/api/golden/tensorflow.keras.applications.nasnet.pbtxt
@@ -0,0 +1,19 @@
+path: "tensorflow.keras.applications.nasnet"
+tf_module {
+ member_method {
+ name: "NASNetLarge"
+ argspec: "args=[\'input_shape\', \'include_top\', \'weights\', \'input_tensor\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'None\', \'True\', \'imagenet\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "NASNetMobile"
+ argspec: "args=[\'input_shape\', \'include_top\', \'weights\', \'input_tensor\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'None\', \'True\', \'imagenet\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "decode_predictions"
+ argspec: "args=[\'preds\', \'top\'], varargs=None, keywords=None, defaults=[\'5\'], "
+ }
+ member_method {
+ name: "preprocess_input"
+ argspec: "args=[\'x\'], varargs=None, keywords=None, defaults=None"
+ }
+}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.applications.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.applications.pbtxt
index daeb5aad41..9fc086eb8e 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.applications.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.applications.pbtxt
@@ -1,6 +1,10 @@
path: "tensorflow.keras.applications"
tf_module {
member {
+ name: "densenet"
+ mtype: "<type \'module\'>"
+ }
+ member {
name: "inception_resnet_v2"
mtype: "<type \'module\'>"
}
@@ -13,6 +17,10 @@ tf_module {
mtype: "<type \'module\'>"
}
member {
+ name: "nasnet"
+ mtype: "<type \'module\'>"
+ }
+ member {
name: "resnet50"
mtype: "<type \'module\'>"
}
@@ -29,6 +37,18 @@ tf_module {
mtype: "<type \'module\'>"
}
member_method {
+ name: "DenseNet121"
+ argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "DenseNet169"
+ argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "DenseNet201"
+ argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
name: "InceptionResNetV2"
argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
}
@@ -41,6 +61,14 @@ tf_module {
argspec: "args=[\'input_shape\', \'alpha\', \'depth_multiplier\', \'dropout\', \'include_top\', \'weights\', \'input_tensor\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'None\', \'1.0\', \'1\', \'0.001\', \'True\', \'imagenet\', \'None\', \'None\', \'1000\'], "
}
member_method {
+ name: "NASNetLarge"
+ argspec: "args=[\'input_shape\', \'include_top\', \'weights\', \'input_tensor\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'None\', \'True\', \'imagenet\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
+ name: "NASNetMobile"
+ argspec: "args=[\'input_shape\', \'include_top\', \'weights\', \'input_tensor\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'None\', \'True\', \'imagenet\', \'None\', \'None\', \'1000\'], "
+ }
+ member_method {
name: "ResNet50"
argspec: "args=[\'include_top\', \'weights\', \'input_tensor\', \'input_shape\', \'pooling\', \'classes\'], varargs=None, keywords=None, defaults=[\'True\', \'imagenet\', \'None\', \'None\', \'None\', \'1000\'], "
}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.backend.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.backend.pbtxt
index 44fbe0f7a0..ba2d083a75 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.backend.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.backend.pbtxt
@@ -398,7 +398,7 @@ tf_module {
}
member_method {
name: "rnn"
- argspec: "args=[\'step_function\', \'inputs\', \'initial_states\', \'go_backwards\', \'mask\', \'constants\', \'unroll\'], varargs=None, keywords=None, defaults=[\'False\', \'None\', \'None\', \'False\'], "
+ argspec: "args=[\'step_function\', \'inputs\', \'initial_states\', \'go_backwards\', \'mask\', \'constants\', \'unroll\', \'input_length\'], varargs=None, keywords=None, defaults=[\'False\', \'None\', \'None\', \'False\', \'None\'], "
}
member_method {
name: "round"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.callbacks.-learning-rate-scheduler.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.callbacks.-learning-rate-scheduler.pbtxt
index 8719c07ca3..d4c85a4519 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.callbacks.-learning-rate-scheduler.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.callbacks.-learning-rate-scheduler.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'schedule\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'self\', \'schedule\', \'verbose\'], varargs=None, keywords=None, defaults=[\'0\'], "
}
member_method {
name: "on_batch_begin"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.datasets.boston_housing.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.datasets.boston_housing.pbtxt
index ef08f9b20f..bda31751d4 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.datasets.boston_housing.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.datasets.boston_housing.pbtxt
@@ -2,6 +2,6 @@ path: "tensorflow.keras.datasets.boston_housing"
tf_module {
member_method {
name: "load_data"
- argspec: "args=[\'path\', \'seed\', \'test_split\'], varargs=None, keywords=None, defaults=[\'boston_housing.npz\', \'113\', \'0.2\'], "
+ argspec: "args=[\'path\', \'test_split\', \'seed\'], varargs=None, keywords=None, defaults=[\'boston_housing.npz\', \'0.2\', \'113\'], "
}
}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.datasets.imdb.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.datasets.imdb.pbtxt
index 8b1c17e9da..ff962876b6 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.datasets.imdb.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.datasets.imdb.pbtxt
@@ -6,6 +6,6 @@ tf_module {
}
member_method {
name: "load_data"
- argspec: "args=[\'path\', \'num_words\', \'skip_top\', \'maxlen\', \'seed\', \'start_char\', \'oov_char\', \'index_from\'], varargs=None, keywords=None, defaults=[\'imdb.npz\', \'None\', \'0\', \'None\', \'113\', \'1\', \'2\', \'3\'], "
+ argspec: "args=[\'path\', \'num_words\', \'skip_top\', \'maxlen\', \'seed\', \'start_char\', \'oov_char\', \'index_from\'], varargs=None, keywords=kwargs, defaults=[\'imdb.npz\', \'None\', \'0\', \'None\', \'113\', \'1\', \'2\', \'3\'], "
}
}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.datasets.reuters.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.datasets.reuters.pbtxt
index 6b3ed1e9af..2da4a13067 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.datasets.reuters.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.datasets.reuters.pbtxt
@@ -6,6 +6,6 @@ tf_module {
}
member_method {
name: "load_data"
- argspec: "args=[\'path\', \'num_words\', \'skip_top\', \'maxlen\', \'test_split\', \'seed\', \'start_char\', \'oov_char\', \'index_from\'], varargs=None, keywords=None, defaults=[\'reuters.npz\', \'None\', \'0\', \'None\', \'0.2\', \'113\', \'1\', \'2\', \'3\'], "
+ argspec: "args=[\'path\', \'num_words\', \'skip_top\', \'maxlen\', \'test_split\', \'seed\', \'start_char\', \'oov_char\', \'index_from\'], varargs=None, keywords=kwargs, defaults=[\'reuters.npz\', \'None\', \'0\', \'None\', \'0.2\', \'113\', \'1\', \'2\', \'3\'], "
}
}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-add.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-add.pbtxt
index a32151e22f..770a107b66 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-add.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-add.pbtxt
@@ -115,7 +115,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -127,7 +127,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-alpha-dropout.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-alpha-dropout.pbtxt
index 46b1713196..0ce42b706e 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-alpha-dropout.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-alpha-dropout.pbtxt
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-average.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-average.pbtxt
index 9bfaf27562..b371ad148c 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-average.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-average.pbtxt
@@ -115,7 +115,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -127,7 +127,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-bidirectional.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-bidirectional.pbtxt
index 2b8ac4f1f4..2f5e65a0c5 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-bidirectional.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-bidirectional.pbtxt
@@ -123,7 +123,7 @@ tf_class {
}
member_method {
name: "call"
- argspec: "args=[\'self\', \'inputs\', \'training\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\', \'None\'], "
+ argspec: "args=[\'self\', \'inputs\', \'training\', \'mask\', \'initial_state\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\'], "
}
member_method {
name: "compute_mask"
@@ -131,7 +131,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-concatenate.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-concatenate.pbtxt
index c9a0b88725..ff08def0a0 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-concatenate.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-concatenate.pbtxt
@@ -115,7 +115,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -127,7 +127,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv-l-s-t-m2-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv-l-s-t-m2-d.pbtxt
index b847e224d6..6db22ca032 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv-l-s-t-m2-d.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-conv-l-s-t-m2-d.pbtxt
@@ -116,7 +116,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -128,7 +128,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-dot.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-dot.pbtxt
index 86578d958e..07d3f023e5 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-dot.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-dot.pbtxt
@@ -115,7 +115,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -127,7 +127,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-e-l-u.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-e-l-u.pbtxt
index 348012dcde..92b9760d53 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-e-l-u.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-e-l-u.pbtxt
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-embedding.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-embedding.pbtxt
index 0419251083..83c528b401 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-embedding.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-embedding.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u-cell.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u-cell.pbtxt
index 337e85e812..b329f1c46b 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u-cell.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u-cell.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u.pbtxt
index 1357dc0f0d..d0f6d2a14f 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-g-r-u.pbtxt
@@ -183,7 +183,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -195,7 +195,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-dropout.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-dropout.pbtxt
index b71a08f6c3..57596badf1 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-dropout.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-dropout.pbtxt
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-noise.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-noise.pbtxt
index a01a6067ef..3829353cc3 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-noise.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-gaussian-noise.pbtxt
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m-cell.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m-cell.pbtxt
index 0dbbdf2838..3b171b137a 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m-cell.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m-cell.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m.pbtxt
index 964ef89c2e..0036d6805b 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-l-s-t-m.pbtxt
@@ -187,7 +187,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -199,7 +199,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-leaky-re-l-u.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-leaky-re-l-u.pbtxt
index 6a7b23c540..8134fb7386 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-leaky-re-l-u.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-leaky-re-l-u.pbtxt
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected1-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected1-d.pbtxt
index 324745e5a3..c5d4523009 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected1-d.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected1-d.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected2-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected2-d.pbtxt
index e12ae05054..bcbed9241b 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected2-d.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-locally-connected2-d.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-maximum.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-maximum.pbtxt
index 9e889ca863..ff0db15f19 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-maximum.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-maximum.pbtxt
@@ -115,7 +115,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -127,7 +127,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-multiply.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-multiply.pbtxt
index 932680941d..1d3f33f045 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-multiply.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-multiply.pbtxt
@@ -115,7 +115,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -127,7 +127,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-p-re-l-u.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-p-re-l-u.pbtxt
index db644f958f..c86bc49b22 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-p-re-l-u.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-p-re-l-u.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-r-n-n.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-r-n-n.pbtxt
index 74fa1db020..b29f65d79d 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-r-n-n.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-r-n-n.pbtxt
@@ -94,7 +94,7 @@ tf_class {
}
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'cell\', \'return_sequences\', \'return_state\', \'go_backwards\', \'stateful\', \'unroll\', \'activity_regularizer\'], varargs=None, keywords=kwargs, defaults=[\'False\', \'False\', \'False\', \'False\', \'False\', \'None\'], "
+ argspec: "args=[\'self\', \'cell\', \'return_sequences\', \'return_state\', \'go_backwards\', \'stateful\', \'unroll\'], varargs=None, keywords=kwargs, defaults=[\'False\', \'False\', \'False\', \'False\', \'False\'], "
}
member_method {
name: "add_loss"
@@ -118,7 +118,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -130,7 +130,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv1-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv1-d.pbtxt
new file mode 100644
index 0000000000..dd67b76523
--- /dev/null
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-conv1-d.pbtxt
@@ -0,0 +1,186 @@
+path: "tensorflow.keras.layers.SeparableConv1D"
+tf_class {
+ is_instance: "<class \'tensorflow.python.keras._impl.keras.layers.convolutional.SeparableConv1D\'>"
+ is_instance: "<class \'tensorflow.python.layers.convolutional.SeparableConv1D\'>"
+ is_instance: "<class \'tensorflow.python.layers.convolutional._SeparableConv\'>"
+ is_instance: "<class \'tensorflow.python.layers.convolutional._Conv\'>"
+ is_instance: "<class \'tensorflow.python.keras._impl.keras.engine.topology.Layer\'>"
+ is_instance: "<class \'tensorflow.python.layers.base.Layer\'>"
+ is_instance: "<type \'object\'>"
+ member {
+ name: "activity_regularizer"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "dtype"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "graph"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "inbound_nodes"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input_mask"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input_shape"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "losses"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "name"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "non_trainable_variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "non_trainable_weights"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "outbound_nodes"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output_mask"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output_shape"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "scope_name"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "trainable_variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "trainable_weights"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "updates"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "weights"
+ mtype: "<type \'property\'>"
+ }
+ member_method {
+ name: "__init__"
+ argspec: "args=[\'self\', \'filters\', \'kernel_size\', \'strides\', \'padding\', \'data_format\', \'dilation_rate\', \'depth_multiplier\', \'activation\', \'use_bias\', \'depthwise_initializer\', \'pointwise_initializer\', \'bias_initializer\', \'depthwise_regularizer\', \'pointwise_regularizer\', \'bias_regularizer\', \'activity_regularizer\', \'depthwise_constraint\', \'pointwise_constraint\', \'bias_constraint\'], varargs=None, keywords=kwargs, defaults=[\'1\', \'valid\', \'None\', \'1\', \'1\', \'None\', \'True\', \'glorot_uniform\', \'glorot_uniform\', \'zeros\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\'], "
+ }
+ member_method {
+ name: "add_loss"
+ argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "add_update"
+ argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "add_variable"
+ argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\', \'partitioner\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\', \'None\'], "
+ }
+ member_method {
+ name: "add_weight"
+ argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\'], "
+ }
+ member_method {
+ name: "apply"
+ argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None"
+ }
+ member_method {
+ name: "build"
+ argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "call"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "compute_mask"
+ argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "compute_output_shape"
+ argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "count_params"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "from_config"
+ argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_config"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_mask_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_shape_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_losses_for"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_mask_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_shape_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_updates_for"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_weights"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "set_weights"
+ argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None"
+ }
+}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution1-d.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution1-d.pbtxt
new file mode 100644
index 0000000000..bf62c095e7
--- /dev/null
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-separable-convolution1-d.pbtxt
@@ -0,0 +1,186 @@
+path: "tensorflow.keras.layers.SeparableConvolution1D"
+tf_class {
+ is_instance: "<class \'tensorflow.python.keras._impl.keras.layers.convolutional.SeparableConv1D\'>"
+ is_instance: "<class \'tensorflow.python.layers.convolutional.SeparableConv1D\'>"
+ is_instance: "<class \'tensorflow.python.layers.convolutional._SeparableConv\'>"
+ is_instance: "<class \'tensorflow.python.layers.convolutional._Conv\'>"
+ is_instance: "<class \'tensorflow.python.keras._impl.keras.engine.topology.Layer\'>"
+ is_instance: "<class \'tensorflow.python.layers.base.Layer\'>"
+ is_instance: "<type \'object\'>"
+ member {
+ name: "activity_regularizer"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "dtype"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "graph"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "inbound_nodes"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input_mask"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input_shape"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "losses"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "name"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "non_trainable_variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "non_trainable_weights"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "outbound_nodes"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output_mask"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output_shape"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "scope_name"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "trainable_variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "trainable_weights"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "updates"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "weights"
+ mtype: "<type \'property\'>"
+ }
+ member_method {
+ name: "__init__"
+ argspec: "args=[\'self\', \'filters\', \'kernel_size\', \'strides\', \'padding\', \'data_format\', \'dilation_rate\', \'depth_multiplier\', \'activation\', \'use_bias\', \'depthwise_initializer\', \'pointwise_initializer\', \'bias_initializer\', \'depthwise_regularizer\', \'pointwise_regularizer\', \'bias_regularizer\', \'activity_regularizer\', \'depthwise_constraint\', \'pointwise_constraint\', \'bias_constraint\'], varargs=None, keywords=kwargs, defaults=[\'1\', \'valid\', \'None\', \'1\', \'1\', \'None\', \'True\', \'glorot_uniform\', \'glorot_uniform\', \'zeros\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\', \'None\'], "
+ }
+ member_method {
+ name: "add_loss"
+ argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "add_update"
+ argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "add_variable"
+ argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\', \'partitioner\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\', \'None\'], "
+ }
+ member_method {
+ name: "add_weight"
+ argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\'], "
+ }
+ member_method {
+ name: "apply"
+ argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None"
+ }
+ member_method {
+ name: "build"
+ argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "call"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "compute_mask"
+ argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "compute_output_shape"
+ argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "count_params"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "from_config"
+ argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_config"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_mask_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_shape_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_losses_for"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_mask_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_shape_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_updates_for"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_weights"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "set_weights"
+ argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None"
+ }
+}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n-cell.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n-cell.pbtxt
index 3414810db4..6e3cde3e3e 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n-cell.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n-cell.pbtxt
@@ -114,7 +114,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n.pbtxt
index cf34034ef0..b875898a81 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-simple-r-n-n.pbtxt
@@ -175,7 +175,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
@@ -187,7 +187,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-softmax.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-softmax.pbtxt
new file mode 100644
index 0000000000..ee4b2fa39e
--- /dev/null
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-softmax.pbtxt
@@ -0,0 +1,183 @@
+path: "tensorflow.keras.layers.Softmax"
+tf_class {
+ is_instance: "<class \'tensorflow.python.keras._impl.keras.layers.advanced_activations.Softmax\'>"
+ is_instance: "<class \'tensorflow.python.keras._impl.keras.engine.topology.Layer\'>"
+ is_instance: "<class \'tensorflow.python.layers.base.Layer\'>"
+ is_instance: "<type \'object\'>"
+ member {
+ name: "activity_regularizer"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "dtype"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "graph"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "inbound_nodes"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input_mask"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "input_shape"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "losses"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "name"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "non_trainable_variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "non_trainable_weights"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "outbound_nodes"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output_mask"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "output_shape"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "scope_name"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "trainable_variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "trainable_weights"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "updates"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "variables"
+ mtype: "<type \'property\'>"
+ }
+ member {
+ name: "weights"
+ mtype: "<type \'property\'>"
+ }
+ member_method {
+ name: "__init__"
+ argspec: "args=[\'self\', \'axis\'], varargs=None, keywords=kwargs, defaults=[\'-1\'], "
+ }
+ member_method {
+ name: "add_loss"
+ argspec: "args=[\'self\', \'losses\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "add_update"
+ argspec: "args=[\'self\', \'updates\', \'inputs\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "add_variable"
+ argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\', \'partitioner\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\', \'None\'], "
+ }
+ member_method {
+ name: "add_weight"
+ argspec: "args=[\'self\', \'name\', \'shape\', \'dtype\', \'initializer\', \'regularizer\', \'trainable\', \'constraint\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'True\', \'None\'], "
+ }
+ member_method {
+ name: "apply"
+ argspec: "args=[\'self\', \'inputs\'], varargs=args, keywords=kwargs, defaults=None"
+ }
+ member_method {
+ name: "build"
+ argspec: "args=[\'self\', \'_\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "call"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "compute_mask"
+ argspec: "args=[\'self\', \'inputs\', \'mask\'], varargs=None, keywords=None, defaults=[\'None\'], "
+ }
+ member_method {
+ name: "compute_output_shape"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "count_params"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "from_config"
+ argspec: "args=[\'cls\', \'config\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_config"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_mask_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_input_shape_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_losses_for"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_mask_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_output_shape_at"
+ argspec: "args=[\'self\', \'node_index\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_updates_for"
+ argspec: "args=[\'self\', \'inputs\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "get_weights"
+ argspec: "args=[\'self\'], varargs=None, keywords=None, defaults=None"
+ }
+ member_method {
+ name: "set_weights"
+ argspec: "args=[\'self\', \'weights\'], varargs=None, keywords=None, defaults=None"
+ }
+}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-stacked-r-n-n-cells.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-stacked-r-n-n-cells.pbtxt
index b76499658d..db9f90caef 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-stacked-r-n-n-cells.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-stacked-r-n-n-cells.pbtxt
@@ -118,7 +118,7 @@ tf_class {
}
member_method {
name: "build"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "call"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.-thresholded-re-l-u.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.-thresholded-re-l-u.pbtxt
index 2376d815a6..ef31c5443e 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.-thresholded-re-l-u.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.-thresholded-re-l-u.pbtxt
@@ -126,7 +126,7 @@ tf_class {
}
member_method {
name: "compute_output_shape"
- argspec: "args=[\'self\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
+ argspec: "args=[\'instance\', \'input_shape\'], varargs=None, keywords=None, defaults=None"
}
member_method {
name: "count_params"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.layers.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.layers.pbtxt
index fe336c4be5..088c8e88e2 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.layers.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.layers.pbtxt
@@ -293,10 +293,18 @@ tf_module {
mtype: "<type \'type\'>"
}
member {
+ name: "SeparableConv1D"
+ mtype: "<type \'type\'>"
+ }
+ member {
name: "SeparableConv2D"
mtype: "<type \'type\'>"
}
member {
+ name: "SeparableConvolution1D"
+ mtype: "<type \'type\'>"
+ }
+ member {
name: "SeparableConvolution2D"
mtype: "<type \'type\'>"
}
@@ -309,6 +317,10 @@ tf_module {
mtype: "<type \'type\'>"
}
member {
+ name: "Softmax"
+ mtype: "<type \'type\'>"
+ }
+ member {
name: "SpatialDropout1D"
mtype: "<type \'type\'>"
}
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.models.-model.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.models.-model.pbtxt
index d239098b0b..0b816b5863 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.models.-model.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.models.-model.pbtxt
@@ -160,15 +160,15 @@ tf_class {
}
member_method {
name: "evaluate_generator"
- argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'10\', \'1\', \'False\'], "
+ argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'1\', \'False\'], "
}
member_method {
name: "fit"
- argspec: "args=[\'self\', \'x\', \'y\', \'batch_size\', \'epochs\', \'verbose\', \'callbacks\', \'validation_split\', \'validation_data\', \'shuffle\', \'class_weight\', \'sample_weight\', \'initial_epoch\', \'steps_per_epoch\', \'validation_steps\'], varargs=None, keywords=None, defaults=[\'None\', \'None\', \'None\', \'1\', \'1\', \'None\', \'0.0\', \'None\', \'True\', \'None\', \'None\', \'0\', \'None\', \'None\'], "
+ argspec: "args=[\'self\', \'x\', \'y\', \'batch_size\', \'epochs\', \'verbose\', \'callbacks\', \'validation_split\', \'validation_data\', \'shuffle\', \'class_weight\', \'sample_weight\', \'initial_epoch\', \'steps_per_epoch\', \'validation_steps\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'None\', \'None\', \'1\', \'1\', \'None\', \'0.0\', \'None\', \'True\', \'None\', \'None\', \'0\', \'None\', \'None\'], "
}
member_method {
name: "fit_generator"
- argspec: "args=[\'self\', \'generator\', \'steps_per_epoch\', \'epochs\', \'verbose\', \'callbacks\', \'validation_data\', \'validation_steps\', \'class_weight\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'shuffle\', \'initial_epoch\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'1\', \'1\', \'None\', \'None\', \'None\', \'None\', \'10\', \'1\', \'False\', \'True\', \'0\'], "
+ argspec: "args=[\'self\', \'generator\', \'steps_per_epoch\', \'epochs\', \'verbose\', \'callbacks\', \'validation_data\', \'validation_steps\', \'class_weight\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'shuffle\', \'initial_epoch\'], varargs=None, keywords=None, defaults=[\'None\', \'1\', \'1\', \'None\', \'None\', \'None\', \'None\', \'10\', \'1\', \'False\', \'True\', \'0\'], "
}
member_method {
name: "from_config"
@@ -228,7 +228,7 @@ tf_class {
}
member_method {
name: "predict_generator"
- argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'verbose\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'10\', \'1\', \'False\', \'0\'], "
+ argspec: "args=[\'self\', \'generator\', \'steps\', \'max_queue_size\', \'workers\', \'use_multiprocessing\', \'verbose\'], varargs=None, keywords=None, defaults=[\'None\', \'10\', \'1\', \'False\', \'0\'], "
}
member_method {
name: "predict_on_batch"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adadelta.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adadelta.pbtxt
index ed040c1586..32667cf31e 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adadelta.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adadelta.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'lr\', \'rho\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'1.0\', \'0.95\', \'1e-08\', \'0.0\'], "
+ argspec: "args=[\'self\', \'lr\', \'rho\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'1.0\', \'0.95\', \'None\', \'0.0\'], "
}
member_method {
name: "from_config"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adagrad.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adagrad.pbtxt
index a24651429a..efca59e8e4 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adagrad.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adagrad.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'lr\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.01\', \'1e-08\', \'0.0\'], "
+ argspec: "args=[\'self\', \'lr\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.01\', \'None\', \'0.0\'], "
}
member_method {
name: "from_config"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adam.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adam.pbtxt
index a0d978fded..5546e2067a 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adam.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adam.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'lr\', \'beta_1\', \'beta_2\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.001\', \'0.9\', \'0.999\', \'1e-08\', \'0.0\'], "
+ argspec: "args=[\'self\', \'lr\', \'beta_1\', \'beta_2\', \'epsilon\', \'decay\', \'amsgrad\'], varargs=None, keywords=kwargs, defaults=[\'0.001\', \'0.9\', \'0.999\', \'None\', \'0.0\', \'False\'], "
}
member_method {
name: "from_config"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adamax.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adamax.pbtxt
index 1b70c93ad5..aaa54a1060 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adamax.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-adamax.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'lr\', \'beta_1\', \'beta_2\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.002\', \'0.9\', \'0.999\', \'1e-08\', \'0.0\'], "
+ argspec: "args=[\'self\', \'lr\', \'beta_1\', \'beta_2\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.002\', \'0.9\', \'0.999\', \'None\', \'0.0\'], "
}
member_method {
name: "from_config"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-nadam.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-nadam.pbtxt
index b49dbe5cf8..1fada7fd9c 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-nadam.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-nadam.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'lr\', \'beta_1\', \'beta_2\', \'epsilon\', \'schedule_decay\'], varargs=None, keywords=kwargs, defaults=[\'0.002\', \'0.9\', \'0.999\', \'1e-08\', \'0.004\'], "
+ argspec: "args=[\'self\', \'lr\', \'beta_1\', \'beta_2\', \'epsilon\', \'schedule_decay\'], varargs=None, keywords=kwargs, defaults=[\'0.002\', \'0.9\', \'0.999\', \'None\', \'0.004\'], "
}
member_method {
name: "from_config"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-r-m-sprop.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-r-m-sprop.pbtxt
index c8860d80d4..fd3f97f35d 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-r-m-sprop.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.optimizers.-r-m-sprop.pbtxt
@@ -5,7 +5,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'lr\', \'rho\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.001\', \'0.9\', \'1e-08\', \'0.0\'], "
+ argspec: "args=[\'self\', \'lr\', \'rho\', \'epsilon\', \'decay\'], varargs=None, keywords=kwargs, defaults=[\'0.001\', \'0.9\', \'None\', \'0.0\'], "
}
member_method {
name: "from_config"
diff --git a/tensorflow/tools/api/golden/tensorflow.keras.preprocessing.text.-tokenizer.pbtxt b/tensorflow/tools/api/golden/tensorflow.keras.preprocessing.text.-tokenizer.pbtxt
index 5bc8c40120..ce91caa1af 100644
--- a/tensorflow/tools/api/golden/tensorflow.keras.preprocessing.text.-tokenizer.pbtxt
+++ b/tensorflow/tools/api/golden/tensorflow.keras.preprocessing.text.-tokenizer.pbtxt
@@ -4,7 +4,7 @@ tf_class {
is_instance: "<type \'object\'>"
member_method {
name: "__init__"
- argspec: "args=[\'self\', \'num_words\', \'filters\', \'lower\', \'split\', \'char_level\'], varargs=None, keywords=None, defaults=[\'None\', \'!\"#$%&()*+,-./:;<=>?@[\\\\]^_`{|}~\\t\\n\', \'True\', \' \', \'False\'], "
+ argspec: "args=[\'self\', \'num_words\', \'filters\', \'lower\', \'split\', \'char_level\', \'oov_token\'], varargs=None, keywords=kwargs, defaults=[\'None\', \'!\"#$%&()*+,-./:;<=>?@[\\\\]^_`{|}~\\t\\n\', \'True\', \' \', \'False\', \'None\'], "
}
member_method {
name: "fit_on_sequences"