Comparar commits
67 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| b2e3780e8c | |||
| 0b04ac3117 | |||
| 90d0eb9b88 | |||
| f2aa89f443 | |||
| 2a319c7255 | |||
| 4fb3f1b3f3 | |||
| 072d33599b | |||
| 56f3c85b87 | |||
| 8b42fff90e | |||
| 1dc5d43d32 | |||
| ee2d08ff79 | |||
| 305b3bed74 | |||
| 9f6acd960c | |||
| 672890b1c8 | |||
| c58bcc2c02 | |||
| 82318263a1 | |||
| d90e1db50b | |||
| 8af0264a77 | |||
| 8193287e08 | |||
| 13bd33e73f | |||
| b2e8d5ab7c | |||
| a375cb322f | |||
| d9c4d8a76a | |||
| 79edae58d5 | |||
| 6675776640 | |||
| 40685c3b2a | |||
| 25874ceab2 | |||
| 4b2093ef67 | |||
| 9bc2e60fd5 | |||
| 685ce7573d | |||
| f5ad1c5753 | |||
| cc92025fdc | |||
| f05cd95fad | |||
| 4325843ef0 | |||
| 607635d2ce | |||
| b8fddc862e | |||
| 0df0177437 | |||
| f90cbcd1e3 | |||
| 870d7f7f93 | |||
| 799bec66a2 | |||
| 2321fbbc1d | |||
| 48ae7217e4 | |||
| 6f54b233f1 | |||
| 1bf1055395 | |||
| 6417d90d5c | |||
| c939cebf0d | |||
| 7ae36d132a | |||
| c478409dad | |||
| 109441a708 | |||
| b267e8293d | |||
| 3a4c683d5c | |||
| d5649da5f8 | |||
| 9c28d21b4f | |||
| 9e58b8237b | |||
| b184c76205 | |||
| 065fb2a74c | |||
| a0a0d42630 | |||
| 756153899a | |||
| e02554412f | |||
| ca37e806b9 | |||
| fe0347dbf0 | |||
| 4984c5fc7c | |||
| f605769af9 | |||
| 534f6b7975 | |||
| ee8fd78383 | |||
| fbc4f37037 | |||
| f23f2ff2c9 |
+15
-12
@@ -1,19 +1,21 @@
|
||||
# Keras: Deep Learning library for Theano and TensorFlow
|
||||
# Keras: Deep Learning library for TensorFlow and Theano
|
||||
|
||||
[](https://travis-ci.org/fchollet/keras)
|
||||
[](https://badge.fury.io/py/keras)
|
||||
[](https://github.com/fchollet/keras/blob/master/LICENSE)
|
||||
[](https://gitter.im/Keras-io/Lobby)
|
||||
|
||||
|
||||
## You have just found Keras.
|
||||
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. *Being able to go from idea to result with the least possible delay is key to doing good research.*
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
|
||||
- allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- runs seamlessly on CPU and GPU.
|
||||
- Allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- Supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- Supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- Runs seamlessly on CPU and GPU.
|
||||
|
||||
Read the documentation at [Keras.io](http://keras.io).
|
||||
|
||||
@@ -114,16 +116,17 @@ Keras uses the following dependencies:
|
||||
- HDF5 and h5py (optional, required if you use model saving/loading functions)
|
||||
- Optional but recommended if you use CNNs: cuDNN.
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
*When using the TensorFlow backend:*
|
||||
|
||||
- TensorFlow
|
||||
- [See installation instructions](https://github.com/tensorflow/tensorflow#download-and-setup).
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
To install Keras, `cd` to the Keras folder and run the install command:
|
||||
```sh
|
||||
sudo python setup.py install
|
||||
@@ -137,9 +140,9 @@ sudo pip install keras
|
||||
------------------
|
||||
|
||||
|
||||
## Switching from Theano to TensorFlow
|
||||
## Switching from TensorFlow to Theano
|
||||
|
||||
By default, Keras will use Theano as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
By default, Keras will use TensorFlow as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
+14
-7
@@ -65,6 +65,7 @@ if sys.version[0] == '2':
|
||||
sys.setdefaultencoding('utf8')
|
||||
|
||||
from keras.layers import convolutional
|
||||
from keras.layers import pooling
|
||||
from keras.layers import local
|
||||
from keras.layers import recurrent
|
||||
from keras.layers import core
|
||||
@@ -132,6 +133,8 @@ PAGES = [
|
||||
core.Dense,
|
||||
core.Activation,
|
||||
core.Dropout,
|
||||
core.SpatialDropout2D,
|
||||
core.SpatialDropout3D,
|
||||
core.Flatten,
|
||||
core.Reshape,
|
||||
core.Permute,
|
||||
@@ -149,6 +152,7 @@ PAGES = [
|
||||
'page': 'layers/convolutional.md',
|
||||
'classes': [
|
||||
convolutional.Convolution1D,
|
||||
convolutional.AtrousConvolution1D,
|
||||
convolutional.Convolution2D,
|
||||
convolutional.AtrousConvolution2D,
|
||||
convolutional.SeparableConvolution2D,
|
||||
@@ -165,12 +169,16 @@ PAGES = [
|
||||
{
|
||||
'page': 'layers/pooling.md',
|
||||
'classes': [
|
||||
convolutional.MaxPooling1D,
|
||||
convolutional.MaxPooling2D,
|
||||
convolutional.MaxPooling3D,
|
||||
convolutional.AveragePooling1D,
|
||||
convolutional.AveragePooling2D,
|
||||
convolutional.AveragePooling3D,
|
||||
pooling.MaxPooling1D,
|
||||
pooling.MaxPooling2D,
|
||||
pooling.MaxPooling3D,
|
||||
pooling.AveragePooling1D,
|
||||
pooling.AveragePooling2D,
|
||||
pooling.AveragePooling3D,
|
||||
pooling.GlobalMaxPooling1D,
|
||||
pooling.GlobalAveragePooling1D,
|
||||
pooling.GlobalMaxPooling2D,
|
||||
pooling.GlobalAveragePooling2D,
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -214,7 +222,6 @@ PAGES = [
|
||||
'all_module_classes': [wrappers],
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
'page': 'optimizers.md',
|
||||
'all_module_classes': [optimizers],
|
||||
|
||||
@@ -25,6 +25,7 @@ pages:
|
||||
- Core Layers: layers/core.md
|
||||
- Convolutional Layers: layers/convolutional.md
|
||||
- Pooling Layers: layers/pooling.md
|
||||
- Locally-connected Layers: layers/local.md
|
||||
- Recurrent Layers: layers/recurrent.md
|
||||
- Embedding Layers: layers/embeddings.md
|
||||
- Advanced Activations Layers: layers/advanced-activations.md
|
||||
@@ -41,6 +42,7 @@ pages:
|
||||
- Activations: activations.md
|
||||
- Callbacks: callbacks.md
|
||||
- Datasets: datasets.md
|
||||
- Applications: applications.md
|
||||
- Backend: backend.md
|
||||
- Initializations: initializations.md
|
||||
- Regularizers: regularizers.md
|
||||
|
||||
externo
+260
@@ -0,0 +1,260 @@
|
||||
# Applications
|
||||
|
||||
Keras Applications are deep learning models that are made available alongside pre-trained weights.
|
||||
These models can be used for prediction, feature extraction, and fine-tuning.
|
||||
|
||||
Weights are downloaded automatically when instantiating a model. They are stored at `~/.keras/models/`.
|
||||
|
||||
## Available models
|
||||
|
||||
Models for image classification with weights trained on ImageNet:
|
||||
|
||||
- [VGG16](#vgg16)
|
||||
- [VGG19](#vgg19)
|
||||
- [ResNet50](#resnet50)
|
||||
- [InceptionV3](#inceptionv3)
|
||||
|
||||
All of these architectures are compatible with both TensorFlow and Theano, and upon instantiation the models will be built according to the image dimension ordering set in your Keras configuration file at `~/.keras/keras.json`. For instance, if you have set `image_dim_ordering=tf`, then any model loaded from this repository will get built according to the TensorFlow dimension ordering convention, "Width-Height-Depth".
|
||||
|
||||
-----
|
||||
|
||||
## Examples
|
||||
|
||||
### Classify ImageNet classes with ResNet50
|
||||
|
||||
```python
|
||||
from keras.applications.resnet50 import ResNet50
|
||||
from keras.preprocessing import image
|
||||
from keras.applications.resnet50 import preprocess_input, decode_predictions
|
||||
|
||||
model = ResNet50(weights='imagenet')
|
||||
|
||||
img_path = 'elephant.jpg'
|
||||
img = image.load_img(img_path, target_size=(224, 224))
|
||||
x = image.img_to_array(img)
|
||||
x = np.expand_dims(x, axis=0)
|
||||
x = preprocess_input(x)
|
||||
|
||||
preds = model.predict(x)
|
||||
print('Predicted:', decode_predictions(preds))
|
||||
# print: [[u'n02504458', u'African_elephant']]
|
||||
```
|
||||
|
||||
### Extract features with VGG16
|
||||
|
||||
```python
|
||||
from keras.applications.vgg16 import VGG16
|
||||
from keras.preprocessing import image
|
||||
from keras.applications.vgg16 import preprocess_input
|
||||
|
||||
model = VGG16(weights='imagenet', include_top=False)
|
||||
|
||||
img_path = 'elephant.jpg'
|
||||
img = image.load_img(img_path, target_size=(224, 224))
|
||||
x = image.img_to_array(img)
|
||||
x = np.expand_dims(x, axis=0)
|
||||
x = preprocess_input(x)
|
||||
|
||||
features = model.predict(x)
|
||||
```
|
||||
|
||||
### Extract features from an arbitrary intermediate layer with VGG19
|
||||
|
||||
```python
|
||||
from keras.applications.vgg19 import VGG19
|
||||
from keras.preprocessing import image
|
||||
from keras.applications.vgg19 import preprocess_input
|
||||
from keras.models import Model
|
||||
|
||||
base_model = VGG19(weights='imagenet')
|
||||
model = Model(input=base_model.input, output=base_model.get_layer('block4_pool').output)
|
||||
|
||||
img_path = 'elephant.jpg'
|
||||
img = image.load_img(img_path, target_size=(224, 224))
|
||||
x = image.img_to_array(img)
|
||||
x = np.expand_dims(x, axis=0)
|
||||
x = preprocess_input(x)
|
||||
|
||||
block4_pool_features = model.predict(x)
|
||||
```
|
||||
|
||||
### Fine-tune InceptionV3 on a new set of classes
|
||||
|
||||
```python
|
||||
from keras.applications.inception_v3 import InceptionV3
|
||||
from keras.preprocessing import image
|
||||
from keras.models import Model
|
||||
from keras.layers import Dense, GlobalAveragePooling2D
|
||||
from keras import backend as K
|
||||
|
||||
# create the base pre-trained model
|
||||
base_model = InceptionV3(weights='imagenet', include_top=False)
|
||||
|
||||
# add a global spatial average pooling layer
|
||||
x = base_model.output
|
||||
x = GlobalAveragePooling2D()(x)
|
||||
# let's add a fully-connected layer
|
||||
x = Dense(1024, activation='relu')(x)
|
||||
# and a logistic layer -- let's say we have 200 classes
|
||||
predictions = Dense(200, activation='softmax')(x)
|
||||
|
||||
# this is the model we will train
|
||||
model = Model(input=base_model.input, output=predictions)
|
||||
|
||||
# first: train only the top layers (which were randomly initialized)
|
||||
# i.e. freeze all convolutional InceptionV3 layers
|
||||
for layer in base_model.layers:
|
||||
layer.trainable = False
|
||||
|
||||
# compile the model (should be done *after* setting layers to non-trainable)
|
||||
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
|
||||
|
||||
# train the model on the new data for a few epochs
|
||||
model.fit_generator(...)
|
||||
|
||||
# at this point, the top layers are well trained and we can start fine-tuning
|
||||
# convolutional layers from inception V3. We will freeze the bottom N layers
|
||||
# and train the remaining top layers.
|
||||
|
||||
# let's visualize layer names and layer indices to see how many layers
|
||||
# we should freeze:
|
||||
for i, layer in enumerate(base_model.layers):
|
||||
print(i, layer.name)
|
||||
|
||||
# we chose to train the top 2 inception blocks, i.e. we will freeze
|
||||
# the first 172 layers and unfreeze the rest:
|
||||
for layer in model.layers[:172]:
|
||||
layer.trainable = False
|
||||
for layer in model.layers[172:]:
|
||||
layer.trainable = True
|
||||
|
||||
# we need to recompile the model for these modifications to take effect
|
||||
# we use SGD with a low learning rate
|
||||
from keras.optimizers import SGD
|
||||
model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')
|
||||
|
||||
# we train our model again (this time fine-tuning the top 2 inception blocks
|
||||
# alongside the top Dense layers
|
||||
model.fit_generator(...)
|
||||
```
|
||||
|
||||
|
||||
### Build InceptionV3 over a custom input tensor
|
||||
|
||||
```python
|
||||
from keras.applications.inception_v3 import InceptionV3
|
||||
from keras.layers import Input
|
||||
|
||||
# this could also be the output a different Keras model or layer
|
||||
input_tensor = Input(shape=(224, 224, 3)) # this assumes K.image_dim_ordering() == 'tf'
|
||||
|
||||
model = InceptionV3(input_tensor=input_tensor, weights='imagenet', include_top=True)
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## VGG16
|
||||
|
||||
```python
|
||||
keras.applications.vgg16.VGG16(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
### References
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556): please cite this paper if you use the VGG models in your work.
|
||||
|
||||
### License
|
||||
|
||||
These weights are ported from the ones [released by VGG at Oxford](http://www.robots.ox.ac.uk/~vgg/research/very_deep/) under the [Creative Commons Attribution License](https://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
-----
|
||||
|
||||
## VGG19
|
||||
|
||||
|
||||
```python
|
||||
keras.applications.vgg19.VGG19(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
|
||||
### References
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)
|
||||
|
||||
### License
|
||||
|
||||
These weights are ported from the ones [released by VGG at Oxford](http://www.robots.ox.ac.uk/~vgg/research/very_deep/) under the [Creative Commons Attribution License](https://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
-----
|
||||
|
||||
## ResNet50
|
||||
|
||||
|
||||
```python
|
||||
keras.applications.resnet50.ResNet50(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
### References
|
||||
|
||||
- [Deep Residual Learning for Image Recognition](https://arxiv.org/abs/1512.03385)
|
||||
|
||||
### License
|
||||
|
||||
These weights are ported from the ones [released by Kaiming He](https://github.com/KaimingHe/deep-residual-networks) under the [MIT license](https://github.com/KaimingHe/deep-residual-networks/blob/master/LICENSE).
|
||||
|
||||
-----
|
||||
|
||||
## InceptionV3
|
||||
|
||||
|
||||
```python
|
||||
keras.applications.inception_v3.InceptionV3(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
### References
|
||||
|
||||
- [Rethinking the Inception Architecture for Computer Vision](http://arxiv.org/abs/1512.00567)
|
||||
|
||||
### License
|
||||
|
||||
These weights are trained by ourselves and are released under the MIT license.
|
||||
externo
+14
-6
@@ -4,10 +4,12 @@
|
||||
|
||||
Keras is a model-level library, providing high-level building blocks for developing deep learning models. It does not handle itself low-level operations such as tensor products, convolutions and so on. Instead, it relies on a specialized, well-optimized tensor manipulation library to do so, serving as the "backend engine" of Keras. Rather than picking one single tensor library and making the implementation of Keras tied to that library, Keras handles the problem in a modular way, and several different backend engines can be plugged seamlessly into Keras.
|
||||
|
||||
At this time, Keras has two backend implementations available: the **Theano** backend and the **TensorFlow** backend.
|
||||
At this time, Keras has two backend implementations available: the **TensorFlow** backend and the **Theano** backend.
|
||||
|
||||
- [Theano](http://deeplearning.net/software/theano/) is an open-source symbolic tensor manipulation framework developed by LISA/MILA Lab at Université de Montréal.
|
||||
- [TensorFlow](http://www.tensorflow.org/) is an open-source symbolic tensor manipulation framework developed by Google, Inc.
|
||||
- [Theano](http://deeplearning.net/software/theano/) is an open-source symbolic tensor manipulation framework developed by LISA/MILA Lab at Université de Montréal.
|
||||
|
||||
In the future, we are likely to add more backend options. If you are interested in developing a new backend, get in touch!
|
||||
|
||||
----
|
||||
|
||||
@@ -19,9 +21,16 @@ If you have run Keras at least once, you will find the Keras configuration file
|
||||
|
||||
If it isn't there, you can create it.
|
||||
|
||||
It probably looks like this:
|
||||
The default configuration file looks like this:
|
||||
|
||||
`{"epsilon": 1e-07, "floatx": "float32", "backend": "theano"}`
|
||||
```
|
||||
{
|
||||
"image_dim_ordering": "tf",
|
||||
"epsilon": 1e-07,
|
||||
"floatx": "float32",
|
||||
"backend": "tensorflow"
|
||||
}
|
||||
```
|
||||
|
||||
Simply change the field `backend` to either `"theano"` or `"tensorflow"`, and Keras will use the new configuration next time you run any Keras code.
|
||||
|
||||
@@ -29,9 +38,8 @@ You can also define the environment variable ``KERAS_BACKEND`` and this will
|
||||
override what is defined in your config file :
|
||||
|
||||
```bash
|
||||
KERAS_BACKEND=tensorflow python -c "from keras import backend; print(backend._BACKEND)"
|
||||
KERAS_BACKEND=tensorflow python -c "from keras import backend"
|
||||
Using TensorFlow backend.
|
||||
tensorflow
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
+41
-3
@@ -113,12 +113,39 @@ Note that you will first need to install HDF5 and the Python library h5py, which
|
||||
model.save_weights('my_model_weights.h5')
|
||||
```
|
||||
|
||||
Assuming you have code for instantiating your model, you can then load the weights you saved into a model with the same architecture:
|
||||
Assuming you have code for instantiating your model, you can then load the weights you saved into a model with the *same* architecture:
|
||||
|
||||
```python
|
||||
model.load_weights('my_model_weights.h5')
|
||||
```
|
||||
|
||||
If you need to load weights into a *different* architecture (with some layers in common), for instance for fine-tuning or transfer-learning, you can load weights by *layer name*:
|
||||
|
||||
```python
|
||||
model.load_weights('my_model_weights.h5', by_name=True)
|
||||
```
|
||||
|
||||
For example:
|
||||
|
||||
```python
|
||||
"""
|
||||
Assume original model looks like this:
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="dense_1"))
|
||||
model.add(Dense(3, name="dense_2"))
|
||||
...
|
||||
model.save_weights(fname)
|
||||
"""
|
||||
|
||||
# new model
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="dense_1")) # will be loaded
|
||||
model.add(Dense(10, name="new_dense")) # will not be loaded
|
||||
|
||||
# load weights from first model; will only affect the first layer, dense_1.
|
||||
model.load_weights(fname, by_name=True)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### Why is the training loss much higher than the testing loss?
|
||||
@@ -336,9 +363,20 @@ Code and pre-trained weights are available for the following image classificatio
|
||||
- ResNet50
|
||||
- Inception v3
|
||||
|
||||
Find the code and weights in [this repository](https://github.com/fchollet/deep-learning-models).
|
||||
They can be imported from the module `keras.applications`:
|
||||
|
||||
For an example of how to use such a pre-trained model for feature extraction or for fine-tuning, see [this blog post](http://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html).
|
||||
```python
|
||||
from keras.applications.vgg16 import VGG16
|
||||
from keras.applications.vgg19 import VGG19
|
||||
from keras.applications.resnet50 import ResNet50
|
||||
from keras.applications.inception_v3 import InceptionV3
|
||||
|
||||
model = VGG16(weights='imagenet', include_top=True)
|
||||
```
|
||||
|
||||
For a few simple usage examples, see [the documentation for the Applications module](/applications).
|
||||
|
||||
For a detailed example of how to use such a pre-trained model for feature extraction or for fine-tuning, see [this blog post](http://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html).
|
||||
|
||||
The VGG16 model is also the basis for several Keras example scripts:
|
||||
|
||||
|
||||
@@ -107,7 +107,7 @@ The `Merge` layer supports a number of pre-defined modes:
|
||||
You can also pass a function as the `mode` argument, allowing for arbitrary transformations:
|
||||
|
||||
```python
|
||||
merged = Merge([left_branch, right_branch], mode=lambda x, y: x - y)
|
||||
merged = Merge([left_branch, right_branch], mode=lambda x: x[0] - x[1])
|
||||
```
|
||||
|
||||
Now you know enough to be able to define *almost* any model with Keras. For complex models that cannot be expressed via `Sequential` and `Merge`, you can use [the functional API](/getting-started/functional-api-guide).
|
||||
|
||||
externo
+15
-14
@@ -2,14 +2,14 @@
|
||||
|
||||
## You have just found Keras.
|
||||
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. *Being able to go from idea to result with the least possible delay is key to doing good research.*
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
|
||||
- allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- runs seamlessly on CPU and GPU.
|
||||
- Allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- Supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- Supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- Runs seamlessly on CPU and GPU.
|
||||
|
||||
Read the documentation at [Keras.io](http://keras.io).
|
||||
|
||||
@@ -33,7 +33,6 @@ Keras is compatible with: __Python 2.7-3.5__.
|
||||
------------------
|
||||
|
||||
|
||||
|
||||
## Getting started: 30 seconds to Keras
|
||||
|
||||
The core data structure of Keras is a __model__, a way to organize layers. The main type of model is the [`Sequential`](http://keras.io/getting-started/sequential-model-guide) model, a linear stack of layers. For more complex architectures, you should use the [Keras functional API](http://keras.io/getting-started/functional-api-guide).
|
||||
@@ -98,6 +97,7 @@ For a more in-depth tutorial about Keras, you can check out:
|
||||
|
||||
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repository, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, etc.
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
@@ -110,32 +110,33 @@ Keras uses the following dependencies:
|
||||
- HDF5 and h5py (optional, required if you use model saving/loading functions)
|
||||
- Optional but recommended if you use CNNs: cuDNN.
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
*When using the TensorFlow backend:*
|
||||
|
||||
- TensorFlow
|
||||
- [See installation instructions](https://github.com/tensorflow/tensorflow#download-and-setup).
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
To install Keras, `cd` to the Keras folder and run the install command:
|
||||
```
|
||||
```sh
|
||||
sudo python setup.py install
|
||||
```
|
||||
|
||||
You can also install Keras from PyPI:
|
||||
```
|
||||
```sh
|
||||
sudo pip install keras
|
||||
```
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Switching from Theano to TensorFlow
|
||||
## Switching from TensorFlow to Theano
|
||||
|
||||
By default, Keras will use Theano as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
By default, Keras will use TensorFlow as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
+1
-1
@@ -30,4 +30,4 @@ yaml_string = model.to_yaml()
|
||||
model = model_from_yaml(yaml_string)
|
||||
```
|
||||
- `model.save_weights(filepath)`: saves the weights of the model as a HDF5 file.
|
||||
- `model.load_weights(filepath)`: loads the weights of the model from a HDF5 file (created by `save_weights`).
|
||||
- `model.load_weights(filepath, by_name=False)`: loads the weights of the model from a HDF5 file (created by `save_weights`). By default, the architecture is expected to be unchanged. To load weights into a different architecture (with some layers in common), use `by_name=True` to load only those layers with the same name.
|
||||
+2
-2
@@ -65,11 +65,11 @@ Generate batches of tensor image data with real-time data augmentation. The data
|
||||
- __save_to_dir__: None or str (default: None). This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
|
||||
- __save_prefix__: str (default: `''`). Prefix to use for filenames of saved pictures (only relevant if `save_to_dir` is set).
|
||||
- __save_format__: one of "png", "jpeg" (only relevant if `save_to_dir` is set). Default: "jpeg".
|
||||
- ___yields__: Tuples of `(x, y)` where `x` is a numpy array of image data and `y` is a numpy array of corresponding labels.
|
||||
- __yields__: Tuples of `(x, y)` where `x` is a numpy array of image data and `y` is a numpy array of corresponding labels.
|
||||
The generator loops indefinitely.
|
||||
- __flow_from_directory(directory)__: Takes the path to a directory, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
|
||||
- __Arguments__:
|
||||
- __directory: path to the target directory. It should contain one subdirectory per class,
|
||||
- __directory__: path to the target directory. It should contain one subdirectory per class,
|
||||
and the subdirectories should contain PNG or JPG images. See [this script](https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d) for more details.
|
||||
- __target_size__: tuple of integers, default: `(256, 256)`. The dimensions to which all images found will be resized.
|
||||
- __color_mode__: one of "grayscale", "rbg". Default: "rgb". Whether the images will be converted to have 1 or 3 color channels.
|
||||
|
||||
@@ -95,7 +95,7 @@ def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
|
||||
|
||||
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='https://s3.amazonaws.com/text-datasets/babi_tasks_1-20_v1-2.tar.gz')
|
||||
except:
|
||||
print('Error downloading dataset, please download it manually:\n'
|
||||
'$ wget http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz\n'
|
||||
@@ -173,6 +173,7 @@ match = Sequential()
|
||||
match.add(Merge([input_encoder_m, question_encoder],
|
||||
mode='dot',
|
||||
dot_axes=[2, 2]))
|
||||
match.add(Activation('softmax'))
|
||||
# output: (samples, story_maxlen, query_maxlen)
|
||||
# embed the input into a single vector with size = story_maxlen:
|
||||
input_encoder_c = Sequential()
|
||||
|
||||
@@ -147,7 +147,7 @@ EPOCHS = 40
|
||||
print('RNN / Embed / Sent / Query = {}, {}, {}, {}'.format(RNN, EMBED_HIDDEN_SIZE, SENT_HIDDEN_SIZE, QUERY_HIDDEN_SIZE))
|
||||
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='https://s3.amazonaws.com/text-datasets/babi_tasks_1-20_v1-2.tar.gz')
|
||||
except:
|
||||
print('Error downloading dataset, please download it manually:\n'
|
||||
'$ wget http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz\n'
|
||||
|
||||
@@ -43,7 +43,7 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
model = Sequential()
|
||||
|
||||
model.add(Convolution2D(32, 3, 3, border_mode='same',
|
||||
input_shape=(img_channels, img_rows, img_cols)))
|
||||
input_shape=X_train.shape[1:]))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(32, 3, 3))
|
||||
model.add(Activation('relu'))
|
||||
|
||||
@@ -3,32 +3,21 @@
|
||||
This script can run on CPU in a few minutes (with the TensorFlow backend).
|
||||
|
||||
Results example: http://i.imgur.com/4nj4KjN.jpg
|
||||
|
||||
Before running this script, download the weights for the VGG16 model at:
|
||||
https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
|
||||
(source: https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
|
||||
and make sure the variable `weights_path` in this script matches the location of the file.
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from scipy.misc import imsave
|
||||
import numpy as np
|
||||
import time
|
||||
import os
|
||||
import h5py
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.applications import vgg16
|
||||
from keras import backend as K
|
||||
|
||||
# dimensions of the generated pictures for each filter.
|
||||
img_width = 128
|
||||
img_height = 128
|
||||
|
||||
# path to the model weights file.
|
||||
weights_path = 'vgg16_weights.h5'
|
||||
|
||||
# the name of the layer we want to visualize (see model definition below)
|
||||
layer_name = 'conv5_1'
|
||||
# the name of the layer we want to visualize
|
||||
# (see model definition at keras/applications/vgg16.py)
|
||||
layer_name = 'block5_conv1'
|
||||
|
||||
# util function to convert a tensor into a valid image
|
||||
def deprocess_image(x):
|
||||
@@ -43,70 +32,22 @@ def deprocess_image(x):
|
||||
|
||||
# convert to RGB array
|
||||
x *= 255
|
||||
x = x.transpose((1, 2, 0))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.transpose((1, 2, 0))
|
||||
x = np.clip(x, 0, 255).astype('uint8')
|
||||
return x
|
||||
|
||||
# build the VGG16 network
|
||||
model = Sequential()
|
||||
model.add(ZeroPadding2D((1, 1), batch_input_shape=(1, 3, img_width, img_height)))
|
||||
first_layer = model.layers[-1]
|
||||
# this is a placeholder tensor that will contain our generated images
|
||||
input_img = first_layer.input
|
||||
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
# load the weights of the VGG16 networks
|
||||
# (trained on ImageNet, won the ILSVRC competition in 2014)
|
||||
# note: when there is a complete match between your model definition
|
||||
# and your weight savefile, you can simply call model.load_weights(filename)
|
||||
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
|
||||
f = h5py.File(weights_path)
|
||||
for k in range(f.attrs['nb_layers']):
|
||||
if k >= len(model.layers):
|
||||
# we don't look at the last (fully-connected) layers in the savefile
|
||||
break
|
||||
g = f['layer_{}'.format(k)]
|
||||
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
|
||||
model.layers[k].set_weights(weights)
|
||||
f.close()
|
||||
# build the VGG16 network with ImageNet weights
|
||||
model = vgg16.VGG16(weights='imagenet', include_top=False)
|
||||
print('Model loaded.')
|
||||
|
||||
model.summary()
|
||||
|
||||
# this is the placeholder for the input images
|
||||
input_img = model.input
|
||||
|
||||
# get the symbolic outputs of each "key" layer (we gave them unique names).
|
||||
layer_dict = dict([(layer.name, layer) for layer in model.layers])
|
||||
layer_dict = dict([(layer.name, layer) for layer in model.layers[1:]])
|
||||
|
||||
|
||||
def normalize(x):
|
||||
@@ -124,7 +65,10 @@ for filter_index in range(0, 200):
|
||||
# we build a loss function that maximizes the activation
|
||||
# of the nth filter of the layer considered
|
||||
layer_output = layer_dict[layer_name].output
|
||||
loss = K.mean(layer_output[:, filter_index, :, :])
|
||||
if K.image_dim_ordering() == 'th':
|
||||
loss = K.mean(layer_output[:, filter_index, :, :])
|
||||
else:
|
||||
loss = K.mean(layer_output[:, :, :, filter_index])
|
||||
|
||||
# we compute the gradient of the input picture wrt this loss
|
||||
grads = K.gradients(loss, input_img)[0]
|
||||
@@ -139,7 +83,11 @@ for filter_index in range(0, 200):
|
||||
step = 1.
|
||||
|
||||
# we start from a gray image with some random noise
|
||||
input_img_data = np.random.random((1, 3, img_width, img_height)) * 20 + 128.
|
||||
if K.image_dim_ordering() == 'th':
|
||||
input_img_data = np.random.random((1, 3, img_width, img_height))
|
||||
else:
|
||||
input_img_data = np.random.random((1, img_width, img_height, 3))
|
||||
input_img_data = (input_img_data - 0.5) * 20 + 128
|
||||
|
||||
# we run gradient ascent for 20 steps
|
||||
for i in range(20):
|
||||
|
||||
+37
-9
@@ -61,6 +61,7 @@ OUTPUT_DIR = "image_ocr"
|
||||
|
||||
np.random.seed(55)
|
||||
|
||||
|
||||
# this creates larger "blotches" of noise which look
|
||||
# more realistic than just adding gaussian noise
|
||||
# assumes greyscale with pixels ranging from 0 to 1
|
||||
@@ -73,6 +74,7 @@ def speckle(img):
|
||||
img_speck[img_speck <= 0] = 0
|
||||
return img_speck
|
||||
|
||||
|
||||
# paints the string in a random location the bounding box
|
||||
# also uses a random font, a slight random rotation,
|
||||
# and a random amount of speckle noise
|
||||
@@ -114,6 +116,7 @@ def paint_text(text, w, h):
|
||||
|
||||
return a
|
||||
|
||||
|
||||
def shuffle_mats_or_lists(matrix_list, stop_ind=None):
|
||||
ret = []
|
||||
assert all([len(i) == len(matrix_list[0]) for i in matrix_list])
|
||||
@@ -131,9 +134,11 @@ def shuffle_mats_or_lists(matrix_list, stop_ind=None):
|
||||
elif isinstance(mat, list):
|
||||
ret.append([mat[i] for i in a])
|
||||
else:
|
||||
raise TypeError('shuffle_mats_or_lists only supports numpy.array and list objects')
|
||||
raise TypeError('shuffle_mats_or_lists only supports '
|
||||
'numpy.array and list objects')
|
||||
return ret
|
||||
|
||||
|
||||
def text_to_labels(text, num_classes):
|
||||
ret = []
|
||||
for char in text:
|
||||
@@ -143,6 +148,7 @@ def text_to_labels(text, num_classes):
|
||||
ret.append(26)
|
||||
return ret
|
||||
|
||||
|
||||
# only a-z and space..probably not to difficult
|
||||
# to expand to uppercase and symbols
|
||||
|
||||
@@ -150,14 +156,15 @@ def is_valid_str(in_str):
|
||||
search = re.compile(r'[^a-z\ ]').search
|
||||
return not bool(search(in_str))
|
||||
|
||||
|
||||
# Uses generator functions to supply train/test with
|
||||
# data. Image renderings are text are created on the fly
|
||||
# each time with random perturbations
|
||||
|
||||
class TextImageGenerator(keras.callbacks.Callback):
|
||||
|
||||
def __init__(self, monogram_file, bigram_file, minibatch_size, img_w,
|
||||
img_h, downsample_width, val_split,
|
||||
def __init__(self, monogram_file, bigram_file, minibatch_size,
|
||||
img_w, img_h, downsample_width, val_split,
|
||||
absolute_max_string_len=16):
|
||||
|
||||
self.minibatch_size = minibatch_size
|
||||
@@ -221,7 +228,10 @@ class TextImageGenerator(keras.callbacks.Callback):
|
||||
# each time an image is requested from train/val/test, a new random
|
||||
# painting of the text is performed
|
||||
def get_batch(self, index, size, train):
|
||||
X_data = np.ones([size, 1, self.img_h, self.img_w])
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_data = np.ones([size, 1, self.img_h, self.img_w])
|
||||
else:
|
||||
X_data = np.ones([size, self.img_h, self.img_w, 1])
|
||||
labels = np.ones([size, self.absolute_max_string_len])
|
||||
input_length = np.zeros([size, 1])
|
||||
label_length = np.zeros([size, 1])
|
||||
@@ -231,13 +241,19 @@ class TextImageGenerator(keras.callbacks.Callback):
|
||||
# Mix in some blank inputs. This seems to be important for
|
||||
# achieving translational invariance
|
||||
if train and i > size - 4:
|
||||
X_data[i, 0, :, :] = paint_text('', self.img_w, self.img_h)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_data[i, 0, :, :] = paint_text('', self.img_w, self.img_h)
|
||||
else:
|
||||
X_data[i, :, :, 0] = paint_text('', self.img_w, self.img_h)
|
||||
labels[i, 0] = self.blank_label
|
||||
input_length[i] = self.downsample_width
|
||||
label_length[i] = 1
|
||||
source_str.append('')
|
||||
else:
|
||||
X_data[i, 0, :, :] = paint_text(self.X_text[index + i], self.img_w, self.img_h)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_data[i, 0, :, :] = paint_text(self.X_text[index + i], self.img_w, self.img_h)
|
||||
else:
|
||||
X_data[i, :, :, 0] = paint_text(self.X_text[index + i], self.img_w, self.img_h)
|
||||
labels[i, :] = self.Y_data[index + i]
|
||||
input_length[i] = self.downsample_width
|
||||
label_length[i] = self.Y_len[index + i]
|
||||
@@ -285,6 +301,7 @@ class TextImageGenerator(keras.callbacks.Callback):
|
||||
if epoch == 30:
|
||||
self.build_word_list(64000, 12, 0.5)
|
||||
|
||||
|
||||
# the actual loss calc occurs here despite it not being
|
||||
# an internal Keras loss function
|
||||
|
||||
@@ -295,6 +312,7 @@ def ctc_lambda_func(args):
|
||||
y_pred = y_pred[:, 2:, :]
|
||||
return K.ctc_batch_cost(labels, y_pred, input_length, label_length)
|
||||
|
||||
|
||||
# For a real OCR application, this should be beam search with a dictionary
|
||||
# and language model. For this example, best path is sufficient.
|
||||
|
||||
@@ -314,9 +332,10 @@ def decode_batch(test_func, word_batch):
|
||||
ret.append(outstr)
|
||||
return ret
|
||||
|
||||
|
||||
class VizCallback(keras.callbacks.Callback):
|
||||
|
||||
def __init__(self, test_func, text_img_gen, num_display_words = 6):
|
||||
def __init__(self, test_func, text_img_gen, num_display_words=6):
|
||||
self.test_func = test_func
|
||||
self.output_dir = os.path.join(
|
||||
OUTPUT_DIR, datetime.datetime.now().strftime('%A, %d. %B %Y %I.%M%p'))
|
||||
@@ -350,7 +369,11 @@ class VizCallback(keras.callbacks.Callback):
|
||||
|
||||
for i in range(self.num_display_words):
|
||||
pylab.subplot(self.num_display_words, 1, i + 1)
|
||||
pylab.imshow(word_batch['the_input'][i, 0, :, :], cmap='Greys_r')
|
||||
if K.image_dim_ordering() == 'th':
|
||||
the_input = word_batch['the_input'][i, 0, :, :]
|
||||
else:
|
||||
the_input = word_batch['the_input'][i, :, :, 0]
|
||||
pylab.imshow(the_input, cmap='Greys_r')
|
||||
pylab.xlabel('Truth = \'%s\' Decoded = \'%s\'' % (word_batch['source_str'][i], res[i]))
|
||||
fig = pylab.gcf()
|
||||
fig.set_size_inches(10, 12)
|
||||
@@ -375,6 +398,11 @@ time_dense_size = 32
|
||||
rnn_size = 512
|
||||
time_steps = img_w / (pool_size_1 * pool_size_2)
|
||||
|
||||
if K.image_dim_ordering() == 'th':
|
||||
input_shape = (1, img_h, img_w)
|
||||
else:
|
||||
input_shape = (img_h, img_w, 1)
|
||||
|
||||
fdir = os.path.dirname(get_file('wordlists.tgz',
|
||||
origin='http://www.isosemi.com/datasets/wordlists.tgz', untar=True))
|
||||
|
||||
@@ -387,7 +415,7 @@ img_gen = TextImageGenerator(monogram_file=os.path.join(fdir, 'wordlist_mono_cle
|
||||
val_split=words_per_epoch - val_words)
|
||||
|
||||
act = 'relu'
|
||||
input_data = Input(name='the_input', shape=(1, img_h, img_w), dtype='float32')
|
||||
input_data = Input(name='the_input', shape=input_shape, dtype='float32')
|
||||
inner = Convolution2D(conv_num_filters, filter_size, filter_size, border_mode='same',
|
||||
activation=act, name='conv1')(input_data)
|
||||
inner = MaxPooling2D(pool_size=(pool_size_1, pool_size_1), name='max1')(inner)
|
||||
|
||||
@@ -5,8 +5,9 @@ Based on Joulin et al's paper:
|
||||
Bags of Tricks for Efficient Text Classification
|
||||
https://arxiv.org/abs/1607.01759
|
||||
|
||||
Can achieve accuracy around 88% after 5 epochs in 70s.
|
||||
|
||||
Results on IMDB datasets with uni and bi-gram embeddings:
|
||||
Uni-gram: 0.8813 test accuracy after 5 epochs. 15s/epoch on i7 cpu.
|
||||
Bi-gram : 0.9056 test accuracy after 5 epochs. 5s/epoch on GTX 1080 gpu.
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
@@ -21,17 +22,87 @@ from keras.layers import AveragePooling1D
|
||||
from keras.datasets import imdb
|
||||
|
||||
|
||||
# set parameters:
|
||||
def create_ngram_set(input_list, ngram_value=2):
|
||||
"""
|
||||
Extract a set of n-grams from a list of integers.
|
||||
|
||||
>>> create_ngram_set([1, 4, 9, 4, 1, 4], ngram_value=2)
|
||||
{(4, 9), (4, 1), (1, 4), (9, 4)}
|
||||
|
||||
>>> create_ngram_set([1, 4, 9, 4, 1, 4], ngram_value=3)
|
||||
[(1, 4, 9), (4, 9, 4), (9, 4, 1), (4, 1, 4)]
|
||||
"""
|
||||
return set(zip(*[input_list[i:] for i in range(ngram_value)]))
|
||||
|
||||
|
||||
def add_ngram(sequences, token_indice, ngram_range=2):
|
||||
"""
|
||||
Augment the input list of list (sequences) by appending n-grams values.
|
||||
|
||||
Example: adding bi-gram
|
||||
>>> sequences = [[1, 3, 4, 5], [1, 3, 7, 9, 2]]
|
||||
>>> token_indice = {(1, 3): 1337, (9, 2): 42, (4, 5): 2017}
|
||||
>>> add_ngram(sequences, token_indice, ngram_range=2)
|
||||
[[1, 3, 4, 5, 1337, 2017], [1, 3, 7, 9, 2, 1337, 42]]
|
||||
|
||||
Example: adding tri-gram
|
||||
>>> sequences = [[1, 3, 4, 5], [1, 3, 7, 9, 2]]
|
||||
>>> token_indice = {(1, 3): 1337, (9, 2): 42, (4, 5): 2017, (7, 9, 2): 2018}
|
||||
>>> add_ngram(sequences, token_indice, ngram_range=3)
|
||||
[[1, 3, 4, 5, 1337], [1, 3, 7, 9, 2, 1337, 2018]]
|
||||
"""
|
||||
new_sequences = []
|
||||
for input_list in sequences:
|
||||
new_list = input_list[:]
|
||||
for i in range(len(new_list)-ngram_range+1):
|
||||
for ngram_value in range(2, ngram_range+1):
|
||||
ngram = tuple(new_list[i:i+ngram_value])
|
||||
if ngram in token_indice:
|
||||
new_list.append(token_indice[ngram])
|
||||
new_sequences.append(new_list)
|
||||
|
||||
return new_sequences
|
||||
|
||||
# Set parameters:
|
||||
# ngram_range = 2 will add bi-grams features
|
||||
ngram_range = 1
|
||||
max_features = 20000
|
||||
maxlen = 400
|
||||
batch_size = 32
|
||||
embedding_dims = 20
|
||||
embedding_dims = 50
|
||||
nb_epoch = 5
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
print('Average train sequence length: {}'.format(np.mean(list(map(len, X_train)), dtype=int)))
|
||||
print('Average test sequence length: {}'.format(np.mean(list(map(len, X_test)), dtype=int)))
|
||||
|
||||
if ngram_range > 1:
|
||||
print('Adding {}-gram features'.format(ngram_range))
|
||||
# Create set of unique n-gram from the training set.
|
||||
ngram_set = set()
|
||||
for input_list in X_train:
|
||||
for i in range(2, ngram_range+1):
|
||||
set_of_ngram = create_ngram_set(input_list, ngram_value=i)
|
||||
ngram_set.update(set_of_ngram)
|
||||
|
||||
# Dictionary mapping n-gram token to a unique integer.
|
||||
# Integer values are greater than max_features in order
|
||||
# to avoid collision with existing features.
|
||||
start_index = max_features + 1
|
||||
token_indice = {v: k+start_index for k, v in enumerate(ngram_set)}
|
||||
indice_token = {token_indice[k]: k for k in token_indice}
|
||||
|
||||
# max_features is the highest integer that could be found in the dataset.
|
||||
max_features = np.max(list(indice_token.keys())) + 1
|
||||
|
||||
# Augmenting X_train and X_test with n-grams features
|
||||
X_train = add_ngram(X_train, token_indice, ngram_range)
|
||||
X_test = add_ngram(X_test, token_indice, ngram_range)
|
||||
print('Average train sequence length: {}'.format(np.mean(list(map(len, X_train)), dtype=int)))
|
||||
print('Average test sequence length: {}'.format(np.mean(list(map(len, X_test)), dtype=int)))
|
||||
|
||||
print('Pad sequences (samples x time)')
|
||||
X_train = sequence.pad_sequences(X_train, maxlen=maxlen)
|
||||
|
||||
@@ -38,7 +38,7 @@ print('X_test shape:', X_test.shape)
|
||||
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, 128, input_length=maxlen, dropout=0.2))
|
||||
model.add(Embedding(max_features, 128, dropout=0.2))
|
||||
model.add(LSTM(128, dropout_W=0.2, dropout_U=0.2)) # try using a GRU instead, for fun
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('sigmoid'))
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
'''This script demonstrates how to build the Inception v3 architecture
|
||||
using the Keras functional API.
|
||||
We are not actually training it here, for lack of appropriate data.
|
||||
|
||||
For more information about this architecture, see:
|
||||
|
||||
"Rethinking the Inception Architecture for Computer Vision"
|
||||
Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens, Zbigniew Wojna
|
||||
http://arxiv.org/abs/1512.00567
|
||||
'''
|
||||
from keras.layers import Convolution2D, MaxPooling2D, AveragePooling2D
|
||||
from keras.layers import BatchNormalization, Flatten, Dense, Dropout
|
||||
from keras.layers import Input, merge
|
||||
from keras.models import Model
|
||||
from keras import regularizers
|
||||
|
||||
|
||||
# global constants
|
||||
NB_CLASS = 1000 # number of classes
|
||||
DIM_ORDERING = 'th' # 'th' (channels, width, height) or 'tf' (width, height, channels)
|
||||
WEIGHT_DECAY = 0. # L2 regularization factor
|
||||
USE_BN = False # whether to use batch normalization
|
||||
|
||||
|
||||
def conv2D_bn(x, nb_filter, nb_row, nb_col,
|
||||
border_mode='same', subsample=(1, 1),
|
||||
activation='relu', batch_norm=USE_BN,
|
||||
weight_decay=WEIGHT_DECAY, dim_ordering=DIM_ORDERING):
|
||||
'''Utility function to apply to a tensor a module conv + BN
|
||||
with optional weight decay (L2 weight regularization).
|
||||
'''
|
||||
if weight_decay:
|
||||
W_regularizer = regularizers.l2(weight_decay)
|
||||
b_regularizer = regularizers.l2(weight_decay)
|
||||
else:
|
||||
W_regularizer = None
|
||||
b_regularizer = None
|
||||
x = Convolution2D(nb_filter, nb_row, nb_col,
|
||||
subsample=subsample,
|
||||
activation=activation,
|
||||
border_mode=border_mode,
|
||||
W_regularizer=W_regularizer,
|
||||
b_regularizer=b_regularizer,
|
||||
dim_ordering=dim_ordering)(x)
|
||||
if batch_norm:
|
||||
x = BatchNormalization()(x)
|
||||
return x
|
||||
|
||||
# Define image input layer
|
||||
|
||||
if DIM_ORDERING == 'th':
|
||||
img_input = Input(shape=(3, 299, 299))
|
||||
CONCAT_AXIS = 1
|
||||
elif DIM_ORDERING == 'tf':
|
||||
img_input = Input(shape=(299, 299, 3))
|
||||
CONCAT_AXIS = 3
|
||||
else:
|
||||
raise Exception('Invalid dim ordering: ' + str(DIM_ORDERING))
|
||||
|
||||
# Entry module
|
||||
|
||||
x = conv2D_bn(img_input, 32, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
x = conv2D_bn(x, 32, 3, 3, border_mode='valid')
|
||||
x = conv2D_bn(x, 64, 3, 3)
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
|
||||
x = conv2D_bn(x, 80, 1, 1, border_mode='valid')
|
||||
x = conv2D_bn(x, 192, 3, 3, border_mode='valid')
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
|
||||
# mixed: 35 x 35 x 256
|
||||
|
||||
branch1x1 = conv2D_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2D_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2D_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 32, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed_1: 35 x 35 x 288
|
||||
|
||||
branch1x1 = conv2D_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2D_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2D_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 64, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed2: 35 x 35 x 288
|
||||
|
||||
branch1x1 = conv2D_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2D_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2D_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 64, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed3: 17 x 17 x 768
|
||||
|
||||
branch3x3 = conv2D_bn(x, 384, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
x = merge([branch3x3, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed4: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 128, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 128, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 128, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 128, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed5: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed5: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed6: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed7: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 192, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# Auxiliary head
|
||||
|
||||
aux_logits = AveragePooling2D((5, 5), strides=(3, 3), dim_ordering=DIM_ORDERING)(x)
|
||||
aux_logits = conv2D_bn(aux_logits, 128, 1, 1)
|
||||
aux_logits = conv2D_bn(aux_logits, 728, 5, 5, border_mode='valid')
|
||||
aux_logits = Flatten()(aux_logits)
|
||||
aux_preds = Dense(NB_CLASS, activation='softmax')(aux_logits)
|
||||
|
||||
# mixed8: 8 x 8 x 1280
|
||||
|
||||
branch3x3 = conv2D_bn(x, 192, 1, 1)
|
||||
branch3x3 = conv2D_bn(branch3x3, 320, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch7x7x3 = conv2D_bn(x, 192, 1, 1)
|
||||
branch7x7x3 = conv2D_bn(branch7x7x3, 192, 1, 7)
|
||||
branch7x7x3 = conv2D_bn(branch7x7x3, 192, 7, 1)
|
||||
branch7x7x3 = conv2D_bn(branch7x7x3, 192, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
x = merge([branch3x3, branch7x7x3, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed9: 8 x 8 x 2048
|
||||
|
||||
branch1x1 = conv2D_bn(x, 320, 1, 1)
|
||||
|
||||
branch3x3 = conv2D_bn(x, 384, 1, 1)
|
||||
branch3x3_1 = conv2D_bn(branch3x3, 384, 1, 3)
|
||||
branch3x3_2 = conv2D_bn(branch3x3, 384, 3, 1)
|
||||
branch3x3 = merge([branch3x3_1, branch3x3_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 448, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 384, 3, 3)
|
||||
branch3x3dbl_1 = conv2D_bn(branch3x3dbl, 384, 1, 3)
|
||||
branch3x3dbl_2 = conv2D_bn(branch3x3dbl, 384, 3, 1)
|
||||
branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed10: 8 x 8 x 2048
|
||||
|
||||
branch1x1 = conv2D_bn(x, 320, 1, 1)
|
||||
|
||||
branch3x3 = conv2D_bn(x, 384, 1, 1)
|
||||
branch3x3_1 = conv2D_bn(branch3x3, 384, 1, 3)
|
||||
branch3x3_2 = conv2D_bn(branch3x3, 384, 3, 1)
|
||||
branch3x3 = merge([branch3x3_1, branch3x3_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 448, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 384, 3, 3)
|
||||
branch3x3dbl_1 = conv2D_bn(branch3x3dbl, 384, 1, 3)
|
||||
branch3x3dbl_2 = conv2D_bn(branch3x3dbl, 384, 3, 1)
|
||||
branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# Final pooling and prediction
|
||||
|
||||
x = AveragePooling2D((8, 8), strides=(1, 1), dim_ordering=DIM_ORDERING)(x)
|
||||
x = Dropout(0.5)(x)
|
||||
x = Flatten()(x)
|
||||
preds = Dense(NB_CLASS, activation='softmax')(x)
|
||||
|
||||
# Define model
|
||||
|
||||
model = Model(input=img_input, output=[preds, aux_preds])
|
||||
model.compile('rmsprop', 'categorical_crossentropy')
|
||||
|
||||
# train via e.g. `model.fit(x_train, [y_train] * 2, batch_size=32, nb_epoch=100)`
|
||||
# Note that for a large dataset it would be preferable
|
||||
# to train using `fit_generator` (see Keras docs).
|
||||
+13
-5
@@ -14,6 +14,7 @@ from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
from keras import backend as K
|
||||
|
||||
batch_size = 128
|
||||
nb_classes = 10
|
||||
@@ -24,15 +25,22 @@ img_rows, img_cols = 28, 28
|
||||
# number of convolutional filters to use
|
||||
nb_filters = 32
|
||||
# size of pooling area for max pooling
|
||||
nb_pool = 2
|
||||
pool_size = (2, 2)
|
||||
# convolution kernel size
|
||||
kernel_size = (3, 3)
|
||||
|
||||
# the data, shuffled and split between train and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
|
||||
input_shape = (1, img_rows, img_cols)
|
||||
else:
|
||||
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)
|
||||
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)
|
||||
input_shape = (img_rows, img_cols, 1)
|
||||
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
@@ -49,11 +57,11 @@ model = Sequential()
|
||||
|
||||
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1],
|
||||
border_mode='valid',
|
||||
input_shape=(1, img_rows, img_cols)))
|
||||
input_shape=input_shape))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(nb_pool, nb_pool)))
|
||||
model.add(MaxPooling2D(pool_size=pool_size))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Flatten())
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
'''Trains a stacked what-where autoencoder built on residual blocks on the
|
||||
MNIST dataset. It exemplifies two influential methods that have been developed
|
||||
in the past few years.
|
||||
|
||||
The first is the idea of properly "unpooling." During any max pool, the
|
||||
exact location (the "where") of the maximal value in a pooled receptive field
|
||||
is lost, however it can be very useful in the overall reconstruction of an
|
||||
input image. Therefore, if the "where" is handed from the encoder
|
||||
to the corresponding decoder layer, features being decoded can be "placed" in
|
||||
the right location, allowing for reconstructions of much higher fidelity.
|
||||
|
||||
References:
|
||||
[1]
|
||||
"Visualizing and Understanding Convolutional Networks"
|
||||
Matthew D Zeiler, Rob Fergus
|
||||
https://arxiv.org/abs/1311.2901v3
|
||||
|
||||
[2]
|
||||
"Stacked What-Where Auto-encoders"
|
||||
Junbo Zhao, Michael Mathieu, Ross Goroshin, Yann LeCun
|
||||
https://arxiv.org/abs/1506.02351v8
|
||||
|
||||
The second idea exploited here is that of residual learning. Residual blocks
|
||||
ease the training process by allowing skip connections that give the network
|
||||
the ability to be as linear (or non-linear) as the data sees fit. This allows
|
||||
for much deep networks to be easily trained. The residual element seems to
|
||||
be advantageous in the context of this example as it allows a nice symmetry
|
||||
between the encoder and decoder. Normally, in the decoder, the final
|
||||
projection to the space where the image is reconstructed is linear, however
|
||||
this does not have to be the case for a residual block as the degree to which
|
||||
its output is linear or non-linear is determined by the data it is fed.
|
||||
However, in order to cap the reconstruction in this example, a hard softmax is
|
||||
applied as a bias because we know the MNIST digits are mapped to [0,1].
|
||||
|
||||
References:
|
||||
[3]
|
||||
"Deep Residual Learning for Image Recognition"
|
||||
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
|
||||
https://arxiv.org/abs/1512.03385v1
|
||||
|
||||
[4]
|
||||
"Identity Mappings in Deep Residual Networks"
|
||||
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
|
||||
https://arxiv.org/abs/1603.05027v3
|
||||
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Model
|
||||
from keras.layers import Activation, merge
|
||||
from keras.layers import UpSampling2D, Convolution2D, MaxPooling2D
|
||||
from keras.layers import Input, BatchNormalization
|
||||
import matplotlib.pyplot as plt
|
||||
import keras.backend as K
|
||||
|
||||
|
||||
def convresblock(x, nfeats=8, ksize=3, nskipped=2):
|
||||
''' The proposed residual block from [4]'''
|
||||
y0 = Convolution2D(nfeats, ksize, ksize, border_mode='same')(x)
|
||||
y = y0
|
||||
for i in range(nskipped):
|
||||
y = BatchNormalization(mode=0, axis=1)(y)
|
||||
y = Activation('relu')(y)
|
||||
y = Convolution2D(nfeats, ksize, ksize, border_mode='same')(y)
|
||||
return merge([y0, y], mode='sum')
|
||||
|
||||
|
||||
def getwhere(x):
|
||||
''' Calculate the "where" mask that contains switches indicating which
|
||||
index contained the max value when MaxPool2D was applied. Using the
|
||||
gradient of the sum is a nice trick to keep everything high level.'''
|
||||
y_prepool, y_postpool = x
|
||||
return K.gradients(K.sum(y_postpool), y_prepool)
|
||||
|
||||
# input image dimensions
|
||||
img_rows, img_cols = 28, 28
|
||||
|
||||
# the data, shuffled and split between train and test sets
|
||||
(X_train, _), (X_test, _) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
print('X_train shape:', X_train.shape)
|
||||
print(X_train.shape[0], 'train samples')
|
||||
print(X_test.shape[0], 'test samples')
|
||||
|
||||
# The size of the kernel used for the MaxPooling2D
|
||||
pool_size = 2
|
||||
# The total number of feature maps at each layer
|
||||
nfeats = [8, 16, 32, 64, 128]
|
||||
# The sizes of the pooling kernel at each layer
|
||||
pool_sizes = np.array([1, 1, 1, 1, 1]) * pool_size
|
||||
# The convolution kernel size
|
||||
ksize = 3
|
||||
# Number of epochs to train for
|
||||
nb_epoch = 5
|
||||
# Batch size during training
|
||||
batch_size = 128
|
||||
|
||||
if pool_size == 2:
|
||||
# if using a 5 layer net of pool_size = 2
|
||||
X_train = np.pad(X_train, [[0, 0], [0, 0], [2, 2], [2, 2]],
|
||||
mode='constant')
|
||||
X_test = np.pad(X_test, [[0, 0], [0, 0], [2, 2], [2, 2]], mode='constant')
|
||||
nlayers = 5
|
||||
elif pool_size == 3:
|
||||
# if using a 3 layer net of pool_size = 3
|
||||
X_train = X_train[:, :, :-1, :-1]
|
||||
X_test = X_test[:, :, :-1, :-1]
|
||||
nlayers = 3
|
||||
else:
|
||||
import sys
|
||||
sys.exit("Script supports pool_size of 2 and 3.")
|
||||
|
||||
# Shape of input to train on (note that model is fully convolutional however)
|
||||
input_shape = X_train.shape[1:]
|
||||
# The final list of the size of axis=1 for all layers, including input
|
||||
nfeats_all = [input_shape[0]] + nfeats
|
||||
|
||||
# First build the encoder, all the while keeping track of the "where" masks
|
||||
img_input = Input(shape=input_shape)
|
||||
|
||||
# We push the "where" masks to the following list
|
||||
wheres = [None] * nlayers
|
||||
y = img_input
|
||||
for i in range(nlayers):
|
||||
y_prepool = convresblock(y, nfeats=nfeats_all[i + 1], ksize=ksize)
|
||||
y = MaxPooling2D(pool_size=(pool_sizes[i], pool_sizes[i]))(y_prepool)
|
||||
wheres[i] = merge([y_prepool, y], mode=getwhere,
|
||||
output_shape=lambda x: x[0])
|
||||
|
||||
# Now build the decoder, and use the stored "where" masks to place the features
|
||||
for i in range(nlayers):
|
||||
ind = nlayers - 1 - i
|
||||
y = UpSampling2D(size=(pool_sizes[ind], pool_sizes[ind]))(y)
|
||||
y = merge([y, wheres[ind]], mode='mul')
|
||||
y = convresblock(y, nfeats=nfeats_all[ind], ksize=ksize)
|
||||
|
||||
# Use hard_simgoid to clip range of reconstruction
|
||||
y = Activation('hard_sigmoid')(y)
|
||||
|
||||
# Define the model and it's mean square error loss, and compile it with Adam
|
||||
model = Model(img_input, y)
|
||||
model.compile('adam', 'mse')
|
||||
|
||||
# Fit the model
|
||||
model.fit(X_train, X_train, validation_data=(X_test, X_test),
|
||||
batch_size=batch_size, nb_epoch=nb_epoch)
|
||||
|
||||
# Plot
|
||||
X_recon = model.predict(X_test[:25])
|
||||
X_plot = np.concatenate((X_test[:25], X_recon), axis=1)
|
||||
X_plot = X_plot.reshape((5, 10, input_shape[-2], input_shape[-1]))
|
||||
X_plot = np.vstack([np.hstack(x) for x in X_plot])
|
||||
plt.figure()
|
||||
plt.axis('off')
|
||||
plt.title('Test Samples: Originals/Reconstructions')
|
||||
plt.imshow(X_plot, interpolation='none', cmap='gray')
|
||||
plt.savefig('reconstructions.png')
|
||||
@@ -22,7 +22,7 @@ from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
from keras import backend as K
|
||||
|
||||
now = datetime.datetime.now
|
||||
|
||||
@@ -35,14 +35,19 @@ img_rows, img_cols = 28, 28
|
||||
# number of convolutional filters to use
|
||||
nb_filters = 32
|
||||
# size of pooling area for max pooling
|
||||
nb_pool = 2
|
||||
pool_size = 2
|
||||
# convolution kernel size
|
||||
nb_conv = 3
|
||||
kernel_size = 3
|
||||
|
||||
if K.image_dim_ordering() == 'th':
|
||||
input_shape = (1, img_rows, img_cols)
|
||||
else:
|
||||
input_shape = (img_rows, img_cols, 1)
|
||||
|
||||
|
||||
def train_model(model, train, test, nb_classes):
|
||||
X_train = train[0].reshape(train[0].shape[0], 1, img_rows, img_cols)
|
||||
X_test = test[0].reshape(test[0].shape[0], 1, img_rows, img_cols)
|
||||
X_train = train[0].reshape((train[0].shape[0],) + input_shape)
|
||||
X_test = test[0].reshape((test[0].shape[0],) + input_shape)
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
@@ -86,13 +91,13 @@ y_test_gte5 = y_test[y_test >= 5] - 5
|
||||
|
||||
# define two groups of layers: feature (convolutions) and classification (dense)
|
||||
feature_layers = [
|
||||
Convolution2D(nb_filters, nb_conv, nb_conv,
|
||||
Convolution2D(nb_filters, kernel_size, kernel_size,
|
||||
border_mode='valid',
|
||||
input_shape=(1, img_rows, img_cols)),
|
||||
input_shape=input_shape),
|
||||
Activation('relu'),
|
||||
Convolution2D(nb_filters, nb_conv, nb_conv),
|
||||
Convolution2D(nb_filters, kernel_size, kernel_size),
|
||||
Activation('relu'),
|
||||
MaxPooling2D(pool_size=(nb_pool, nb_pool)),
|
||||
MaxPooling2D(pool_size=(pool_size, pool_size)),
|
||||
Dropout(0.25),
|
||||
Flatten(),
|
||||
]
|
||||
@@ -105,9 +110,7 @@ classification_layers = [
|
||||
]
|
||||
|
||||
# create complete model
|
||||
model = Sequential()
|
||||
for l in feature_layers + classification_layers:
|
||||
model.add(l)
|
||||
model = Sequential(feature_layers + classification_layers)
|
||||
|
||||
# train model for 5-digit classification [0..4]
|
||||
train_model(model,
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
'''Neural doodle with Keras
|
||||
|
||||
Script Usage:
|
||||
# Arguments:
|
||||
```
|
||||
--nlabels: # of regions (colors) in mask images
|
||||
--style-image: image to learn style from
|
||||
--style-mask: semantic labels for style image
|
||||
--target-mask: semantic labels for target image (your doodle)
|
||||
--content-image: optional image to learn content from
|
||||
--target-image-prefix: path prefix for generated target images
|
||||
```
|
||||
|
||||
# Example 1: doodle using a style image, style mask
|
||||
and target mask.
|
||||
```
|
||||
python neural_doodle.py --nlabels 4 --style-image Monet/style.png \
|
||||
--style-mask Monet/style_mask.png --target-mask Monet/target_mask.png \
|
||||
--target-image-prefix generated/monet
|
||||
```
|
||||
|
||||
# Example 2: doodle using a style image, style mask,
|
||||
target mask and an optional content image.
|
||||
```
|
||||
python neural_doodle.py --nlabels 4 --style-image Renoir/style.png \
|
||||
--style-mask Renoir/style_mask.png --target-mask Renoir/target_mask.png \
|
||||
--content-image Renoir/creek.jpg \
|
||||
--target-image-prefix generated/renoir
|
||||
```
|
||||
|
||||
References:
|
||||
[Dmitry Ulyanov's blog on fast-neural-doodle](http://dmitryulyanov.github.io/feed-forward-neural-doodle/)
|
||||
[Torch code for fast-neural-doodle](https://github.com/DmitryUlyanov/fast-neural-doodle)
|
||||
[Torch code for online-neural-doodle](https://github.com/DmitryUlyanov/online-neural-doodle)
|
||||
[Paper Texture Networks: Feed-forward Synthesis of Textures and Stylized Images](http://arxiv.org/abs/1603.03417)
|
||||
[Discussion on parameter tuning](https://github.com/fchollet/keras/issues/3705)
|
||||
|
||||
Resources:
|
||||
Example images can be downloaded from
|
||||
https://github.com/DmitryUlyanov/fast-neural-doodle/tree/master/data
|
||||
'''
|
||||
from __future__ import print_function
|
||||
import time
|
||||
import argparse
|
||||
import numpy as np
|
||||
from scipy.optimize import fmin_l_bfgs_b
|
||||
from scipy.misc import imread, imsave
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import Input, Convolution2D, MaxPooling2D, AveragePooling2D
|
||||
from keras.models import Model
|
||||
from keras.preprocessing.image import load_img, img_to_array
|
||||
from keras.applications import vgg19
|
||||
|
||||
# Command line arguments
|
||||
parser = argparse.ArgumentParser(description='Keras neural doodle example')
|
||||
parser.add_argument('--nlabels', type=int,
|
||||
help='number of semantic labels'
|
||||
' (regions in differnet colors)'
|
||||
' in style_mask/target_mask')
|
||||
parser.add_argument('--style-image', type=str,
|
||||
help='path to image to learn style from')
|
||||
parser.add_argument('--style-mask', type=str,
|
||||
help='path to semantic mask of style image')
|
||||
parser.add_argument('--target-mask', type=str,
|
||||
help='path to semantic mask of target image')
|
||||
parser.add_argument('--content-image', type=str, default=None,
|
||||
help='path to optional content image')
|
||||
parser.add_argument('--target-image-prefix', type=str,
|
||||
help='path prefix for generated results')
|
||||
args = parser.parse_args()
|
||||
|
||||
style_img_path = args.style_image
|
||||
style_mask_path = args.style_mask
|
||||
target_mask_path = args.target_mask
|
||||
content_img_path = args.content_image
|
||||
target_img_prefix = args.target_image_prefix
|
||||
use_content_img = content_img_path is not None
|
||||
|
||||
nb_labels = args.nlabels
|
||||
nb_colors = 3 # RGB
|
||||
# determine image sizes based on target_mask
|
||||
ref_img = imread(target_mask_path)
|
||||
img_nrows, img_ncols = ref_img.shape[:2]
|
||||
|
||||
total_variation_weight = 50.
|
||||
style_weight = 1.
|
||||
content_weight = 0.1 if use_content_img else 0
|
||||
|
||||
content_feature_layers = ['block5_conv2']
|
||||
# To get better generation qualities, use more conv layers for style features
|
||||
style_feature_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1',
|
||||
'block4_conv1', 'block5_conv1']
|
||||
|
||||
|
||||
# helper functions for reading/processing images
|
||||
def preprocess_image(image_path):
|
||||
img = load_img(image_path, target_size=(img_nrows, img_ncols))
|
||||
img = img_to_array(img)
|
||||
img = np.expand_dims(img, axis=0)
|
||||
img = vgg19.preprocess_input(img)
|
||||
return img
|
||||
|
||||
|
||||
def deprocess_image(x):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((3, img_nrows, img_ncols))
|
||||
x = x.transpose((1, 2, 0))
|
||||
else:
|
||||
x = x.reshape((img_nrows, img_ncols, 3))
|
||||
x = x[:, :, ::-1]
|
||||
x[:, :, 0] += 103.939
|
||||
x[:, :, 1] += 116.779
|
||||
x[:, :, 2] += 123.68
|
||||
x = np.clip(x, 0, 255).astype('uint8')
|
||||
return x
|
||||
|
||||
|
||||
def kmeans(xs, k):
|
||||
assert xs.ndim == 2
|
||||
try:
|
||||
from sklearn.cluster import k_means
|
||||
_, labels, _ = k_means(xs.astype("float64"), k)
|
||||
except ImportError:
|
||||
from scipy.cluster.vq import kmeans2
|
||||
_, labels = kmeans2(xs, k, missing='raise')
|
||||
return labels
|
||||
|
||||
|
||||
def load_mask_labels():
|
||||
'''Load both target and style masks.
|
||||
A mask image (nr x nc) with m labels/colors will be loaded
|
||||
as a 4D boolean tensor: (1, m, nr, nc) for 'th' or (1, nr, nc, m) for 'tf'
|
||||
'''
|
||||
target_mask_img = load_img(target_mask_path,
|
||||
target_size=(img_nrows, img_ncols))
|
||||
target_mask_img = img_to_array(target_mask_img)
|
||||
style_mask_img = load_img(style_mask_path,
|
||||
target_size=(img_nrows, img_ncols))
|
||||
style_mask_img = img_to_array(style_mask_img)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
mask_vecs = np.vstack([style_mask_img.reshape((3, -1)).T,
|
||||
target_mask_img.reshape((3, -1)).T])
|
||||
else:
|
||||
mask_vecs = np.vstack([style_mask_img.reshape((-1, 3)),
|
||||
target_mask_img.reshape((-1, 3))])
|
||||
|
||||
labels = kmeans(mask_vecs, nb_labels)
|
||||
style_mask_label = labels[:img_nrows *
|
||||
img_ncols].reshape((img_nrows, img_ncols))
|
||||
target_mask_label = labels[img_nrows *
|
||||
img_ncols:].reshape((img_nrows, img_ncols))
|
||||
|
||||
stack_axis = 0 if K.image_dim_ordering() == 'th' else -1
|
||||
style_mask = np.stack([style_mask_label == r for r in xrange(nb_labels)],
|
||||
axis=stack_axis)
|
||||
target_mask = np.stack([target_mask_label == r for r in xrange(nb_labels)],
|
||||
axis=stack_axis)
|
||||
|
||||
return (np.expand_dims(style_mask, axis=0),
|
||||
np.expand_dims(target_mask, axis=0))
|
||||
|
||||
# Create tensor variables for images
|
||||
if K.image_dim_ordering() == 'th':
|
||||
shape = (1, nb_colors, img_nrows, img_ncols)
|
||||
else:
|
||||
shape = (1, img_nrows, img_ncols, nb_colors)
|
||||
|
||||
style_image = K.variable(preprocess_image(style_img_path))
|
||||
target_image = K.placeholder(shape=shape)
|
||||
if use_content_img:
|
||||
content_image = K.variable(preprocess_image(content_img_path))
|
||||
else:
|
||||
content_image = K.zeros(shape=shape)
|
||||
|
||||
images = K.concatenate([style_image, target_image, content_image], axis=0)
|
||||
|
||||
# Create tensor variables for masks
|
||||
raw_style_mask, raw_target_mask = load_mask_labels()
|
||||
style_mask = K.variable(raw_style_mask.astype("float32"))
|
||||
target_mask = K.variable(raw_target_mask.astype("float32"))
|
||||
masks = K.concatenate([style_mask, target_mask], axis=0)
|
||||
|
||||
# index constants for images and tasks variables
|
||||
STYLE, TARGET, CONTENT = 0, 1, 2
|
||||
|
||||
# Build image model, mask model and use layer outputs as features
|
||||
# image model as VGG19
|
||||
image_model = vgg19.VGG19(include_top=False, input_tensor=images)
|
||||
|
||||
# mask model as a series of pooling
|
||||
mask_input = Input(tensor=masks, shape=(None, None, None), name="mask_input")
|
||||
x = mask_input
|
||||
for layer in image_model.layers[1:]:
|
||||
name = 'mask_%s' % layer.name
|
||||
if 'conv' in layer.name:
|
||||
x = AveragePooling2D((3, 3), strides=(
|
||||
1, 1), name=name, border_mode="same")(x)
|
||||
elif 'pool' in layer.name:
|
||||
x = AveragePooling2D((2, 2), name=name)(x)
|
||||
mask_model = Model(mask_input, x)
|
||||
|
||||
# Collect features from image_model and task_model
|
||||
image_features = {}
|
||||
mask_features = {}
|
||||
for img_layer, mask_layer in zip(image_model.layers, mask_model.layers):
|
||||
if 'conv' in img_layer.name:
|
||||
assert 'mask_' + img_layer.name == mask_layer.name
|
||||
layer_name = img_layer.name
|
||||
img_feat, mask_feat = img_layer.output, mask_layer.output
|
||||
image_features[layer_name] = img_feat
|
||||
mask_features[layer_name] = mask_feat
|
||||
|
||||
|
||||
# Define loss functions
|
||||
def gram_matrix(x):
|
||||
assert K.ndim(x) == 3
|
||||
features = K.batch_flatten(x)
|
||||
gram = K.dot(features, K.transpose(features))
|
||||
return gram
|
||||
|
||||
|
||||
def region_style_loss(style_image, target_image, style_mask, target_mask):
|
||||
'''Calculate style loss between style_image and target_image,
|
||||
for one common region specified by their (boolean) masks
|
||||
'''
|
||||
assert 3 == K.ndim(style_image) == K.ndim(target_image)
|
||||
assert 2 == K.ndim(style_mask) == K.ndim(target_mask)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
masked_style = style_image * style_mask
|
||||
masked_target = target_image * target_mask
|
||||
nb_channels = K.shape(style_image)[0]
|
||||
else:
|
||||
masked_style = K.permute_dimensions(
|
||||
style_image, (2, 0, 1)) * style_mask
|
||||
masked_target = K.permute_dimensions(
|
||||
target_image, (2, 0, 1)) * target_mask
|
||||
nb_channels = K.shape(style_image)[-1]
|
||||
s = gram_matrix(masked_style) / K.mean(style_mask) / nb_channels
|
||||
c = gram_matrix(masked_target) / K.mean(target_mask) / nb_channels
|
||||
return K.mean(K.square(s - c))
|
||||
|
||||
|
||||
def style_loss(style_image, target_image, style_masks, target_masks):
|
||||
'''Calculate style loss between style_image and target_image,
|
||||
in all regions.
|
||||
'''
|
||||
assert 3 == K.ndim(style_image) == K.ndim(target_image)
|
||||
assert 3 == K.ndim(style_masks) == K.ndim(target_masks)
|
||||
loss = K.variable(0)
|
||||
for i in xrange(nb_labels):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
style_mask = style_masks[i, :, :]
|
||||
target_mask = target_masks[i, :, :]
|
||||
else:
|
||||
style_mask = style_masks[:, :, i]
|
||||
target_mask = target_masks[:, :, i]
|
||||
loss += region_style_loss(style_image,
|
||||
target_image, style_mask, target_mask)
|
||||
return loss
|
||||
|
||||
|
||||
def content_loss(content_image, target_image):
|
||||
return K.sum(K.square(target_image - content_image))
|
||||
|
||||
|
||||
def total_variation_loss(x):
|
||||
assert 4 == K.ndim(x)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
a = K.square(x[:, :, :img_nrows - 1, :img_ncols - 1] -
|
||||
x[:, :, 1:, :img_ncols - 1])
|
||||
b = K.square(x[:, :, :img_nrows - 1, :img_ncols - 1] -
|
||||
x[:, :, :img_nrows - 1, 1:])
|
||||
else:
|
||||
a = K.square(x[:, :img_nrows - 1, :img_ncols - 1, :] -
|
||||
x[:, 1:, :img_ncols - 1, :])
|
||||
b = K.square(x[:, :img_nrows - 1, :img_ncols - 1, :] -
|
||||
x[:, :img_nrows - 1, 1:, :])
|
||||
return K.sum(K.pow(a + b, 1.25))
|
||||
|
||||
# Overall loss is the weighted sum of content_loss, style_loss and tv_loss
|
||||
# Each individual loss uses features from image/mask models.
|
||||
loss = K.variable(0)
|
||||
for layer in content_feature_layers:
|
||||
content_feat = image_features[layer][CONTENT, :, :, :]
|
||||
target_feat = image_features[layer][TARGET, :, :, :]
|
||||
loss += content_weight * content_loss(content_feat, target_feat)
|
||||
|
||||
for layer in style_feature_layers:
|
||||
style_feat = image_features[layer][STYLE, :, :, :]
|
||||
target_feat = image_features[layer][TARGET, :, :, :]
|
||||
style_masks = mask_features[layer][STYLE, :, :, :]
|
||||
target_masks = mask_features[layer][TARGET, :, :, :]
|
||||
sl = style_loss(style_feat, target_feat, style_masks, target_masks)
|
||||
loss += (style_weight / len(style_feature_layers)) * sl
|
||||
|
||||
loss += total_variation_weight * total_variation_loss(target_image)
|
||||
loss_grads = K.gradients(loss, target_image)
|
||||
|
||||
# Evaluator class for computing efficiency
|
||||
outputs = [loss]
|
||||
if type(loss_grads) in {list, tuple}:
|
||||
outputs += loss_grads
|
||||
else:
|
||||
outputs.append(loss_grads)
|
||||
|
||||
f_outputs = K.function([target_image], outputs)
|
||||
|
||||
|
||||
def eval_loss_and_grads(x):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((1, 3, img_nrows, img_ncols))
|
||||
else:
|
||||
x = x.reshape((1, img_nrows, img_ncols, 3))
|
||||
outs = f_outputs([x])
|
||||
loss_value = outs[0]
|
||||
if len(outs[1:]) == 1:
|
||||
grad_values = outs[1].flatten().astype('float64')
|
||||
else:
|
||||
grad_values = np.array(outs[1:]).flatten().astype('float64')
|
||||
return loss_value, grad_values
|
||||
|
||||
|
||||
class Evaluator(object):
|
||||
|
||||
def __init__(self):
|
||||
self.loss_value = None
|
||||
self.grads_values = None
|
||||
|
||||
def loss(self, x):
|
||||
assert self.loss_value is None
|
||||
loss_value, grad_values = eval_loss_and_grads(x)
|
||||
self.loss_value = loss_value
|
||||
self.grad_values = grad_values
|
||||
return self.loss_value
|
||||
|
||||
def grads(self, x):
|
||||
assert self.loss_value is not None
|
||||
grad_values = np.copy(self.grad_values)
|
||||
self.loss_value = None
|
||||
self.grad_values = None
|
||||
return grad_values
|
||||
|
||||
evaluator = Evaluator()
|
||||
|
||||
# Generate images by iterative optimization
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = np.random.uniform(0, 255, (1, 3, img_nrows, img_ncols)) - 128.
|
||||
else:
|
||||
x = np.random.uniform(0, 255, (1, img_nrows, img_ncols, 3)) - 128.
|
||||
|
||||
for i in range(50):
|
||||
print('Start of iteration', i)
|
||||
start_time = time.time()
|
||||
x, min_val, info = fmin_l_bfgs_b(evaluator.loss, x.flatten(),
|
||||
fprime=evaluator.grads, maxfun=20)
|
||||
print('Current loss value:', min_val)
|
||||
# save current generated image
|
||||
img = deprocess_image(x.copy())
|
||||
fname = target_img_prefix + '_at_iteration_%d.png' % i
|
||||
imsave(fname, img)
|
||||
end_time = time.time()
|
||||
print('Image saved as', fname)
|
||||
print('Iteration %d completed in %ds' % (i, end_time - start_time))
|
||||
@@ -1,10 +1,5 @@
|
||||
'''Neural style transfer with Keras.
|
||||
|
||||
Before running this script, download the weights for the VGG16 model at:
|
||||
https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
|
||||
(source: https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
|
||||
and make sure the variable `weights_path` in this script matches the location of the file.
|
||||
|
||||
Run the script with:
|
||||
```
|
||||
python neural_style_transfer.py path_to_your_base_image.jpg path_to_your_reference.jpg prefix_for_results
|
||||
@@ -15,7 +10,6 @@ python neural_style_transfer.py img/tuebingen.jpg img/starry_night.jpg results/m
|
||||
```
|
||||
|
||||
It is preferable to run this script on GPU, for speed.
|
||||
If running on CPU, prefer the TensorFlow backend (much faster).
|
||||
|
||||
Example result: https://twitter.com/fchollet/status/686631033085677568
|
||||
|
||||
@@ -49,16 +43,14 @@ keeping the generated image close enough to the original one.
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
from scipy.misc import imread, imresize, imsave
|
||||
from keras.preprocessing.image import load_img, img_to_array
|
||||
from scipy.misc import imsave
|
||||
import numpy as np
|
||||
from scipy.optimize import fmin_l_bfgs_b
|
||||
import time
|
||||
import os
|
||||
import argparse
|
||||
import h5py
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.applications import vgg16
|
||||
from keras import backend as K
|
||||
|
||||
parser = argparse.ArgumentParser(description='Neural style transfer with Keras.')
|
||||
@@ -73,37 +65,36 @@ args = parser.parse_args()
|
||||
base_image_path = args.base_image_path
|
||||
style_reference_image_path = args.style_reference_image_path
|
||||
result_prefix = args.result_prefix
|
||||
weights_path = 'vgg16_weights.h5'
|
||||
|
||||
# these are the weights of the different loss components
|
||||
total_variation_weight = 1.
|
||||
style_weight = 1.
|
||||
content_weight = 0.025
|
||||
|
||||
|
||||
# dimensions of the generated picture.
|
||||
img_width = 400
|
||||
img_height = 400
|
||||
assert img_height == img_width, 'Due to the use of the Gram matrix, width and height must match.'
|
||||
img_nrows = 400
|
||||
img_ncols = 400
|
||||
assert img_ncols == img_nrows, 'Due to the use of the Gram matrix, width and height must match.'
|
||||
|
||||
# util function to open, resize and format pictures into appropriate tensors
|
||||
def preprocess_image(image_path):
|
||||
img = imresize(imread(image_path), (img_width, img_height))
|
||||
img = img[:, :, ::-1].astype('float64')
|
||||
img[:, :, 0] -= 103.939
|
||||
img[:, :, 1] -= 116.779
|
||||
img[:, :, 2] -= 123.68
|
||||
img = img.transpose((2, 0, 1))
|
||||
img = load_img(image_path, target_size=(img_nrows, img_ncols))
|
||||
img = img_to_array(img)
|
||||
img = np.expand_dims(img, axis=0)
|
||||
img = vgg16.preprocess_input(img)
|
||||
return img
|
||||
|
||||
# util function to convert a tensor into a valid image
|
||||
def deprocess_image(x):
|
||||
x = x.transpose((1, 2, 0))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((3, img_nrows, img_ncols))
|
||||
x = x.transpose((1, 2, 0))
|
||||
else:
|
||||
x = x.reshape((img_nrows, img_ncols, 3))
|
||||
x = x[:, :, ::-1]
|
||||
x[:, :, 0] += 103.939
|
||||
x[:, :, 1] += 116.779
|
||||
x[:, :, 2] += 123.68
|
||||
x = x[:, :, ::-1]
|
||||
x = np.clip(x, 0, 255).astype('uint8')
|
||||
return x
|
||||
|
||||
@@ -112,7 +103,10 @@ base_image = K.variable(preprocess_image(base_image_path))
|
||||
style_reference_image = K.variable(preprocess_image(style_reference_image_path))
|
||||
|
||||
# this will contain our generated image
|
||||
combination_image = K.placeholder((1, 3, img_width, img_height))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
combination_image = K.placeholder((1, 3, img_nrows, img_ncols))
|
||||
else:
|
||||
combination_image = K.placeholder((1, img_nrows, img_ncols, 3))
|
||||
|
||||
# combine the 3 images into a single Keras tensor
|
||||
input_tensor = K.concatenate([base_image,
|
||||
@@ -120,60 +114,9 @@ input_tensor = K.concatenate([base_image,
|
||||
combination_image], axis=0)
|
||||
|
||||
# build the VGG16 network with our 3 images as input
|
||||
first_layer = ZeroPadding2D((1, 1))
|
||||
first_layer.set_input(input_tensor, shape=(3, 3, img_width, img_height))
|
||||
|
||||
model = Sequential()
|
||||
model.add(first_layer)
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
# load the weights of the VGG16 networks
|
||||
# (trained on ImageNet, won the ILSVRC competition in 2014)
|
||||
# note: when there is a complete match between your model definition
|
||||
# and your weight savefile, you can simply call model.load_weights(filename)
|
||||
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
|
||||
f = h5py.File(weights_path)
|
||||
for k in range(f.attrs['nb_layers']):
|
||||
if k >= len(model.layers):
|
||||
# we don't look at the last (fully-connected) layers in the savefile
|
||||
break
|
||||
g = f['layer_{}'.format(k)]
|
||||
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
|
||||
model.layers[k].set_weights(weights)
|
||||
f.close()
|
||||
# the model will be loaded with pre-trained ImageNet weights
|
||||
model = vgg16.VGG16(input_tensor=input_tensor,
|
||||
weights='imagenet', include_top=False)
|
||||
print('Model loaded.')
|
||||
|
||||
# get the symbolic outputs of each "key" layer (we gave them unique names).
|
||||
@@ -185,7 +128,10 @@ outputs_dict = dict([(layer.name, layer.output) for layer in model.layers])
|
||||
# the gram matrix of an image tensor (feature-wise outer product)
|
||||
def gram_matrix(x):
|
||||
assert K.ndim(x) == 3
|
||||
features = K.batch_flatten(x)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
features = K.batch_flatten(x)
|
||||
else:
|
||||
features = K.batch_flatten(K.permute_dimensions(x, (2, 0, 1)))
|
||||
gram = K.dot(features, K.transpose(features))
|
||||
return gram
|
||||
|
||||
@@ -200,7 +146,7 @@ def style_loss(style, combination):
|
||||
S = gram_matrix(style)
|
||||
C = gram_matrix(combination)
|
||||
channels = 3
|
||||
size = img_width * img_height
|
||||
size = img_nrows * img_ncols
|
||||
return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))
|
||||
|
||||
# an auxiliary loss function
|
||||
@@ -213,19 +159,25 @@ def content_loss(base, combination):
|
||||
# designed to keep the generated image locally coherent
|
||||
def total_variation_loss(x):
|
||||
assert K.ndim(x) == 4
|
||||
a = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, 1:, :img_height-1])
|
||||
b = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, :img_width-1, 1:])
|
||||
if K.image_dim_ordering() == 'th':
|
||||
a = K.square(x[:, :, :img_nrows-1, :img_ncols-1] - x[:, :, 1:, :img_ncols-1])
|
||||
b = K.square(x[:, :, :img_nrows-1, :img_ncols-1] - x[:, :, :img_nrows-1, 1:])
|
||||
else:
|
||||
a = K.square(x[:, :img_nrows-1, :img_ncols-1, :] - x[:, 1:, :img_ncols-1, :])
|
||||
b = K.square(x[:, :img_nrows-1, :img_ncols-1, :] - x[:, :img_nrows-1, 1:, :])
|
||||
return K.sum(K.pow(a + b, 1.25))
|
||||
|
||||
# combine these loss functions into a single scalar
|
||||
loss = K.variable(0.)
|
||||
layer_features = outputs_dict['conv4_2']
|
||||
layer_features = outputs_dict['block4_conv2']
|
||||
base_image_features = layer_features[0, :, :, :]
|
||||
combination_features = layer_features[2, :, :, :]
|
||||
loss += content_weight * content_loss(base_image_features,
|
||||
combination_features)
|
||||
|
||||
feature_layers = ['conv1_1', 'conv2_1', 'conv3_1', 'conv4_1', 'conv5_1']
|
||||
feature_layers = ['block1_conv1', 'block2_conv1',
|
||||
'block3_conv1', 'block4_conv1',
|
||||
'block5_conv1']
|
||||
for layer_name in feature_layers:
|
||||
layer_features = outputs_dict[layer_name]
|
||||
style_reference_features = layer_features[1, :, :, :]
|
||||
@@ -244,8 +196,12 @@ else:
|
||||
outputs.append(grads)
|
||||
|
||||
f_outputs = K.function([combination_image], outputs)
|
||||
|
||||
def eval_loss_and_grads(x):
|
||||
x = x.reshape((1, 3, img_width, img_height))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((1, 3, img_nrows, img_ncols))
|
||||
else:
|
||||
x = x.reshape((1, img_nrows, img_ncols, 3))
|
||||
outs = f_outputs([x])
|
||||
loss_value = outs[0]
|
||||
if len(outs[1:]) == 1:
|
||||
@@ -283,10 +239,11 @@ evaluator = Evaluator()
|
||||
|
||||
# run scipy-based optimization (L-BFGS) over the pixels of the generated image
|
||||
# so as to minimize the neural style loss
|
||||
x = np.random.uniform(0, 255, (1, 3, img_width, img_height))
|
||||
x[0, 0, :, :] -= 103.939
|
||||
x[0, 1, :, :] -= 116.779
|
||||
x[0, 2, :, :] -= 123.68
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = np.random.uniform(0, 255, (1, 3, img_nrows, img_ncols)) - 128.
|
||||
else:
|
||||
x = np.random.uniform(0, 255, (1, img_nrows, img_ncols, 3)) - 128.
|
||||
|
||||
for i in range(10):
|
||||
print('Start of iteration', i)
|
||||
start_time = time.time()
|
||||
@@ -294,7 +251,7 @@ for i in range(10):
|
||||
fprime=evaluator.grads, maxfun=20)
|
||||
print('Current loss value:', min_val)
|
||||
# save current generated image
|
||||
img = deprocess_image(x.copy().reshape((3, img_width, img_height)))
|
||||
img = deprocess_image(x.copy())
|
||||
fname = result_prefix + '_at_iteration_%d.png' % i
|
||||
imsave(fname, img)
|
||||
end_time = time.time()
|
||||
|
||||
@@ -1,220 +0,0 @@
|
||||
'''This script demonstrates how to build a deep residual network
|
||||
using the Keras functional API.
|
||||
|
||||
get_resnet50() returns the deep residual network model (50 layers)
|
||||
|
||||
Please visit Kaiming He's GitHub homepage:
|
||||
https://github.com/KaimingHe
|
||||
for more information.
|
||||
|
||||
The related paper is
|
||||
'Deep Residual Learning for Image Recognition'
|
||||
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
|
||||
http://arxiv.org/abs/1512.03385
|
||||
|
||||
Pretrained weights were converted from Kaiming He's caffe model directly.
|
||||
|
||||
For now we provide weights for the tensorflow backend only,
|
||||
thus use 'tf' dim_ordering (e.g. input_shape=(224, 224, 3) for 224*224 color image)
|
||||
would accelerate the computation, but we also provide weights for 'th' dim_ordering for compatibility.
|
||||
You can set your default dim ordering in your Keras config file at ~/.keras/keras.json
|
||||
|
||||
please donwload them at:
|
||||
http://pan.baidu.com/s/1o8pO2q2 ('th' dim ordering, for China)
|
||||
http://pan.baidu.com/s/1pLanuTt ('tf' dim ordering, for China)
|
||||
|
||||
https://drive.google.com/open?id=0B4ChsjFJvew3NVQ2U041Q0xHRHM ('th' dim ordering, for other countries)
|
||||
https://drive.google.com/open?id=0B4ChsjFJvew3NWN5THdxcTdSWmc ('tf' dim ordering, for other countries)
|
||||
|
||||
@author: BigMoyan, University of Electronic Science and Technology of China
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from keras.layers import merge
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D, ZeroPadding2D, AveragePooling2D
|
||||
from keras.layers.core import Dense, Activation, Flatten
|
||||
from keras.layers.normalization import BatchNormalization
|
||||
from keras.models import Model
|
||||
from keras.layers import Input
|
||||
from keras.preprocessing.image import load_img, img_to_array
|
||||
import keras.backend as K
|
||||
import numpy as np
|
||||
|
||||
# The names of layers in resnet50 are generated with the following format
|
||||
# [type][stage][block]_branch[branch][layer]
|
||||
# type: 'res' for conv layer, 'bn' and 'scale' for BN layer
|
||||
# stage: from '2' to '5', current stage number
|
||||
# block: 'a','b','c'... for different blocks in a stage
|
||||
# branch: '1' for shortcut and '2' for main path
|
||||
# layer: 'a','b','c'... for different layers in a block
|
||||
|
||||
|
||||
def identity_block(input_tensor, kernel_size, filters, stage, block):
|
||||
'''The identity_block is the block that has no conv layer at shortcut
|
||||
|
||||
# Arguments
|
||||
input_tensor: input tensor
|
||||
kernel_size: defualt 3, the kernel size of middle conv layer at main path
|
||||
filters: list of integers, the nb_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
|
||||
'''
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
nb_filter1, nb_filter2, nb_filter3 = filters
|
||||
if dim_ordering == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
conv_name_base = 'res' + str(stage) + block + '_branch'
|
||||
bn_name_base = 'bn' + str(stage) + block + '_branch'
|
||||
|
||||
out = Convolution2D(nb_filter1, 1, 1, dim_ordering=dim_ordering, name=conv_name_base + '2a')(input_tensor)
|
||||
out = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(out)
|
||||
out = Activation('relu')(out)
|
||||
|
||||
out = Convolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same',
|
||||
dim_ordering=dim_ordering, name=conv_name_base + '2b')(out)
|
||||
out = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(out)
|
||||
out = Activation('relu')(out)
|
||||
|
||||
out = Convolution2D(nb_filter3, 1, 1, dim_ordering=dim_ordering, name=conv_name_base + '2c')(out)
|
||||
out = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(out)
|
||||
|
||||
out = merge([out, input_tensor], mode='sum')
|
||||
out = Activation('relu')(out)
|
||||
return out
|
||||
|
||||
|
||||
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
|
||||
|
||||
# Arguments
|
||||
input_tensor: input tensor
|
||||
kernel_size: defualt 3, the kernel size of middle conv layer at main path
|
||||
filters: list of integers, the nb_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
|
||||
|
||||
Note that from stage 3, the first conv layer at main path is with subsample=(2,2)
|
||||
And the shortcut should has subsample=(2,2) as well
|
||||
'''
|
||||
nb_filter1, nb_filter2, nb_filter3 = filters
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
if dim_ordering == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
conv_name_base = 'res' + str(stage) + block + '_branch'
|
||||
bn_name_base = 'bn' + str(stage) + block + '_branch'
|
||||
|
||||
out = Convolution2D(nb_filter1, 1, 1, subsample=strides,
|
||||
dim_ordering=dim_ordering, name=conv_name_base + '2a')(input_tensor)
|
||||
out = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(out)
|
||||
out = Activation('relu')(out)
|
||||
|
||||
out = Convolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same',
|
||||
dim_ordering=dim_ordering, name=conv_name_base + '2b')(out)
|
||||
out = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(out)
|
||||
out = Activation('relu')(out)
|
||||
|
||||
out = Convolution2D(nb_filter3, 1, 1, dim_ordering=dim_ordering, name=conv_name_base + '2c')(out)
|
||||
out = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(out)
|
||||
|
||||
shortcut = Convolution2D(nb_filter3, 1, 1, subsample=strides,
|
||||
dim_ordering=dim_ordering, name=conv_name_base + '1')(input_tensor)
|
||||
shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut)
|
||||
|
||||
out = merge([out, shortcut], mode='sum')
|
||||
out = Activation('relu')(out)
|
||||
return out
|
||||
|
||||
|
||||
def read_img(img_path):
|
||||
'''This function returns a preprocessed image
|
||||
'''
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
mean = (103.939, 116.779, 123.68)
|
||||
img = load_img(img_path, target_size=(224, 224))
|
||||
img = img_to_array(img, dim_ordering=dim_ordering)
|
||||
|
||||
if dim_ordering == 'th':
|
||||
img[0, :, :] -= mean[0]
|
||||
img[1, :, :] -= mean[1]
|
||||
img[2, :, :] -= mean[2]
|
||||
# 'RGB'->'BGR'
|
||||
img = img[::-1, :, :]
|
||||
else:
|
||||
img[:, :, 0] -= mean[0]
|
||||
img[:, :, 1] -= mean[1]
|
||||
img[:, :, 2] -= mean[2]
|
||||
img = img[:, :, ::-1]
|
||||
|
||||
img = np.expand_dims(img, axis=0)
|
||||
return img
|
||||
|
||||
|
||||
def get_resnet50():
|
||||
'''This function returns the 50-layer residual network model
|
||||
you should load pretrained weights if you want to use it directly.
|
||||
Note that since the pretrained weights is converted from caffemodel
|
||||
the order of channels for input image should be 'BGR' (the channel order of caffe)
|
||||
'''
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
inp = Input(shape=(224, 224, 3))
|
||||
bn_axis = 3
|
||||
else:
|
||||
inp = Input(shape=(3, 224, 224))
|
||||
bn_axis = 1
|
||||
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
out = ZeroPadding2D((3, 3), dim_ordering=dim_ordering)(inp)
|
||||
out = Convolution2D(64, 7, 7, subsample=(2, 2), dim_ordering=dim_ordering, name='conv1')(out)
|
||||
out = BatchNormalization(axis=bn_axis, name='bn_conv1')(out)
|
||||
out = Activation('relu')(out)
|
||||
out = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=dim_ordering)(out)
|
||||
|
||||
out = conv_block(out, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
|
||||
out = identity_block(out, 3, [64, 64, 256], stage=2, block='b')
|
||||
out = identity_block(out, 3, [64, 64, 256], stage=2, block='c')
|
||||
|
||||
out = conv_block(out, 3, [128, 128, 512], stage=3, block='a')
|
||||
out = identity_block(out, 3, [128, 128, 512], stage=3, block='b')
|
||||
out = identity_block(out, 3, [128, 128, 512], stage=3, block='c')
|
||||
out = identity_block(out, 3, [128, 128, 512], stage=3, block='d')
|
||||
|
||||
out = conv_block(out, 3, [256, 256, 1024], stage=4, block='a')
|
||||
out = identity_block(out, 3, [256, 256, 1024], stage=4, block='b')
|
||||
out = identity_block(out, 3, [256, 256, 1024], stage=4, block='c')
|
||||
out = identity_block(out, 3, [256, 256, 1024], stage=4, block='d')
|
||||
out = identity_block(out, 3, [256, 256, 1024], stage=4, block='e')
|
||||
out = identity_block(out, 3, [256, 256, 1024], stage=4, block='f')
|
||||
|
||||
out = conv_block(out, 3, [512, 512, 2048], stage=5, block='a')
|
||||
out = identity_block(out, 3, [512, 512, 2048], stage=5, block='b')
|
||||
out = identity_block(out, 3, [512, 512, 2048], stage=5, block='c')
|
||||
|
||||
out = AveragePooling2D((7, 7), dim_ordering=dim_ordering)(out)
|
||||
out = Flatten()(out)
|
||||
out = Dense(1000, activation='softmax', name='fc1000')(out)
|
||||
|
||||
model = Model(inp, out)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
weights_file = K.image_dim_ordering() + '_dim_ordering_resnet50.h5'
|
||||
resnet_model = get_resnet50()
|
||||
resnet_model.load_weights(weights_file)
|
||||
|
||||
# you may download synset_words from the address given at the begining of this file
|
||||
class_table = open('synset_words.txt', 'r')
|
||||
lines = class_table.readlines()
|
||||
|
||||
test_img1 = read_img('cat.jpg')
|
||||
print('Result for test 1 is:')
|
||||
print(lines[np.argmax(resnet_model.predict(test_img1)[0])])
|
||||
|
||||
test_img2 = read_img('elephant.jpg')
|
||||
print('Result for test 2 is:')
|
||||
print(lines[np.argmax(resnet_model.predict(test_img2)[0])])
|
||||
class_table.close()
|
||||
+1
-1
@@ -15,4 +15,4 @@ from . import objectives
|
||||
from . import optimizers
|
||||
from . import regularizers
|
||||
|
||||
__version__ = '1.0.8'
|
||||
__version__ = '1.1.0'
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from .vgg16 import VGG16
|
||||
from .vgg19 import VGG19
|
||||
from .resnet50 import ResNet50
|
||||
from .inception_v3 import InceptionV3
|
||||
@@ -0,0 +1,43 @@
|
||||
import numpy as np
|
||||
import json
|
||||
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
|
||||
CLASS_INDEX = None
|
||||
CLASS_INDEX_PATH = 'https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json'
|
||||
|
||||
|
||||
def preprocess_input(x, dim_ordering='default'):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
assert dim_ordering in {'tf', 'th'}
|
||||
|
||||
if dim_ordering == 'th':
|
||||
x[:, 0, :, :] -= 103.939
|
||||
x[:, 1, :, :] -= 116.779
|
||||
x[:, 2, :, :] -= 123.68
|
||||
# 'RGB'->'BGR'
|
||||
x = x[:, ::-1, :, :]
|
||||
else:
|
||||
x[:, :, :, 0] -= 103.939
|
||||
x[:, :, :, 1] -= 116.779
|
||||
x[:, :, :, 2] -= 123.68
|
||||
# 'RGB'->'BGR'
|
||||
x = x[:, :, :, ::-1]
|
||||
return x
|
||||
|
||||
|
||||
def decode_predictions(preds):
|
||||
global CLASS_INDEX
|
||||
assert len(preds.shape) == 2 and preds.shape[1] == 1000
|
||||
if CLASS_INDEX is None:
|
||||
fpath = get_file('imagenet_class_index.json',
|
||||
CLASS_INDEX_PATH,
|
||||
cache_subdir='models')
|
||||
CLASS_INDEX = json.load(open(fpath))
|
||||
indices = np.argmax(preds, axis=-1)
|
||||
results = []
|
||||
for i in indices:
|
||||
results.append(CLASS_INDEX[str(i)])
|
||||
return results
|
||||
@@ -0,0 +1,312 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Inception V3 model for Keras.
|
||||
|
||||
Note that the ImageNet weights provided are from a model that had not fully converged.
|
||||
Inception v3 should be able to reach 6.9% top-5 error, but our model
|
||||
only gets to 7.8% (same as a fully-converged ResNet 50).
|
||||
For comparison, VGG16 only gets to 9.9%, quite a bit worse.
|
||||
|
||||
Also, do note that the input image format for this model is different than for
|
||||
other models (299x299 instead of 224x224), and that the input preprocessing function
|
||||
is also different.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Rethinking the Inception Architecture for Computer Vision](http://arxiv.org/abs/1512.00567)
|
||||
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..models import Model
|
||||
from ..layers import Flatten, Dense, Input, BatchNormalization, merge
|
||||
from ..layers import Convolution2D, MaxPooling2D, AveragePooling2D
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
from .imagenet_utils import decode_predictions
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def conv2d_bn(x, nb_filter, nb_row, nb_col,
|
||||
border_mode='same', subsample=(1, 1),
|
||||
name=None):
|
||||
'''Utility function to apply conv + BN.
|
||||
'''
|
||||
if name is not None:
|
||||
bn_name = name + '_bn'
|
||||
conv_name = name + '_conv'
|
||||
else:
|
||||
bn_name = None
|
||||
conv_name = None
|
||||
if K.image_dim_ordering() == 'th':
|
||||
bn_axis = 1
|
||||
else:
|
||||
bn_axis = 3
|
||||
x = Convolution2D(nb_filter, nb_row, nb_col,
|
||||
subsample=subsample,
|
||||
activation='relu',
|
||||
border_mode=border_mode,
|
||||
name=conv_name)(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name)(x)
|
||||
return x
|
||||
|
||||
|
||||
def InceptionV3(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the Inception v3 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
Note that the default input image size for this model is 299x299.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 299, 299)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (299, 299, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
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 K.image_dim_ordering() == 'th':
|
||||
channel_axis = 1
|
||||
else:
|
||||
channel_axis = 3
|
||||
|
||||
x = conv2d_bn(img_input, 32, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
x = conv2d_bn(x, 32, 3, 3, border_mode='valid')
|
||||
x = conv2d_bn(x, 64, 3, 3)
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
x = conv2d_bn(x, 80, 1, 1, border_mode='valid')
|
||||
x = conv2d_bn(x, 192, 3, 3, border_mode='valid')
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
# mixed 0, 1, 2: 35 x 35 x 256
|
||||
for i in range(3):
|
||||
branch1x1 = conv2d_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2d_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2d_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2d_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D(
|
||||
(3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 32, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed' + str(i))
|
||||
|
||||
# mixed 3: 17 x 17 x 768
|
||||
branch3x3 = conv2d_bn(x, 384, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch3x3dbl = conv2d_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3,
|
||||
subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
x = merge([branch3x3, branch3x3dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed3')
|
||||
|
||||
# mixed 4: 17 x 17 x 768
|
||||
branch1x1 = conv2d_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2d_bn(x, 128, 1, 1)
|
||||
branch7x7 = conv2d_bn(branch7x7, 128, 1, 7)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2d_bn(x, 128, 1, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 1, 7)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed4')
|
||||
|
||||
# mixed 5, 6: 17 x 17 x 768
|
||||
for i in range(2):
|
||||
branch1x1 = conv2d_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2d_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2d_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2d_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 1, 7)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D(
|
||||
(3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed' + str(5 + i))
|
||||
|
||||
# mixed 7: 17 x 17 x 768
|
||||
branch1x1 = conv2d_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2d_bn(x, 192, 1, 1)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 1, 7)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2d_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed7')
|
||||
|
||||
# mixed 8: 8 x 8 x 1280
|
||||
branch3x3 = conv2d_bn(x, 192, 1, 1)
|
||||
branch3x3 = conv2d_bn(branch3x3, 320, 3, 3,
|
||||
subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch7x7x3 = conv2d_bn(x, 192, 1, 1)
|
||||
branch7x7x3 = conv2d_bn(branch7x7x3, 192, 1, 7)
|
||||
branch7x7x3 = conv2d_bn(branch7x7x3, 192, 7, 1)
|
||||
branch7x7x3 = conv2d_bn(branch7x7x3, 192, 3, 3,
|
||||
subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(2, 2))(x)
|
||||
x = merge([branch3x3, branch7x7x3, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed8')
|
||||
|
||||
# mixed 9: 8 x 8 x 2048
|
||||
for i in range(2):
|
||||
branch1x1 = conv2d_bn(x, 320, 1, 1)
|
||||
|
||||
branch3x3 = conv2d_bn(x, 384, 1, 1)
|
||||
branch3x3_1 = conv2d_bn(branch3x3, 384, 1, 3)
|
||||
branch3x3_2 = conv2d_bn(branch3x3, 384, 3, 1)
|
||||
branch3x3 = merge([branch3x3_1, branch3x3_2],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed9_' + str(i))
|
||||
|
||||
branch3x3dbl = conv2d_bn(x, 448, 1, 1)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 384, 3, 3)
|
||||
branch3x3dbl_1 = conv2d_bn(branch3x3dbl, 384, 1, 3)
|
||||
branch3x3dbl_2 = conv2d_bn(branch3x3dbl, 384, 3, 1)
|
||||
branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2],
|
||||
mode='concat', concat_axis=channel_axis)
|
||||
|
||||
branch_pool = AveragePooling2D(
|
||||
(3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed' + str(9 + i))
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = AveragePooling2D((8, 8), strides=(8, 8), name='avg_pool')(x)
|
||||
x = Flatten(name='flatten')(x)
|
||||
x = Dense(1000, activation='softmax', name='predictions')(x)
|
||||
|
||||
# Create model
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('inception_v3_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='b3baf3070cc4bf476d43a2ea61b0ca5f')
|
||||
else:
|
||||
weights_path = get_file('inception_v3_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='79aaa90ab4372b4593ba3df64e142f05')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('inception_v3_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='fe114b3ff2ea4bf891e9353d1bbfb32f')
|
||||
else:
|
||||
weights_path = get_file('inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='2f3609166de1d967d1a481094754f691')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
|
||||
|
||||
def preprocess_input(x):
|
||||
x /= 255.
|
||||
x -= 0.5
|
||||
x *= 2.
|
||||
return x
|
||||
@@ -0,0 +1,235 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''ResNet50 model for Keras.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Deep Residual Learning for Image Recognition](https://arxiv.org/abs/1512.03385)
|
||||
|
||||
Adapted from code contributed by BigMoyan.
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..layers import merge, Input
|
||||
from ..layers import Dense, Activation, Flatten
|
||||
from ..layers import Convolution2D, MaxPooling2D, ZeroPadding2D, AveragePooling2D
|
||||
from ..layers import BatchNormalization
|
||||
from ..models import Model
|
||||
from .. import backend as K
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .imagenet_utils import decode_predictions, preprocess_input
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def identity_block(input_tensor, kernel_size, filters, stage, block):
|
||||
'''The identity_block is the block that has no conv layer at shortcut
|
||||
|
||||
# Arguments
|
||||
input_tensor: input tensor
|
||||
kernel_size: defualt 3, the kernel size of middle conv layer at main path
|
||||
filters: list of integers, the nb_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
|
||||
'''
|
||||
nb_filter1, nb_filter2, nb_filter3 = filters
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
conv_name_base = 'res' + str(stage) + block + '_branch'
|
||||
bn_name_base = 'bn' + str(stage) + block + '_branch'
|
||||
|
||||
x = Convolution2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter2, kernel_size, kernel_size,
|
||||
border_mode='same', name=conv_name_base + '2b')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)
|
||||
|
||||
x = merge([x, input_tensor], mode='sum')
|
||||
x = Activation('relu')(x)
|
||||
return x
|
||||
|
||||
|
||||
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
|
||||
|
||||
# Arguments
|
||||
input_tensor: input tensor
|
||||
kernel_size: defualt 3, the kernel size of middle conv layer at main path
|
||||
filters: list of integers, the nb_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
|
||||
|
||||
Note that from stage 3, the first conv layer at main path is with subsample=(2,2)
|
||||
And the shortcut should have subsample=(2,2) as well
|
||||
'''
|
||||
nb_filter1, nb_filter2, nb_filter3 = filters
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
conv_name_base = 'res' + str(stage) + block + '_branch'
|
||||
bn_name_base = 'bn' + str(stage) + block + '_branch'
|
||||
|
||||
x = Convolution2D(nb_filter1, 1, 1, subsample=strides,
|
||||
name=conv_name_base + '2a')(input_tensor)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same',
|
||||
name=conv_name_base + '2b')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)
|
||||
|
||||
shortcut = Convolution2D(nb_filter3, 1, 1, subsample=strides,
|
||||
name=conv_name_base + '1')(input_tensor)
|
||||
shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut)
|
||||
|
||||
x = merge([x, shortcut], mode='sum')
|
||||
x = Activation('relu')(x)
|
||||
return x
|
||||
|
||||
|
||||
def ResNet50(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the ResNet50 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. xput of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 224, 224)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (224, 224, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
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 K.image_dim_ordering() == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
|
||||
x = ZeroPadding2D((3, 3))(img_input)
|
||||
x = Convolution2D(64, 7, 7, subsample=(2, 2), name='conv1')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x)
|
||||
x = Activation('relu')(x)
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
|
||||
x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
|
||||
x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')
|
||||
|
||||
x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')
|
||||
x = identity_block(x, 3, [128, 128, 512], stage=3, block='b')
|
||||
x = identity_block(x, 3, [128, 128, 512], stage=3, block='c')
|
||||
x = identity_block(x, 3, [128, 128, 512], stage=3, block='d')
|
||||
|
||||
x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='c')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='d')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='e')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='f')
|
||||
|
||||
x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a')
|
||||
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')
|
||||
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')
|
||||
|
||||
x = AveragePooling2D((7, 7), name='avg_pool')(x)
|
||||
|
||||
if include_top:
|
||||
x = Flatten()(x)
|
||||
x = Dense(1000, activation='softmax', name='fc1000')(x)
|
||||
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('resnet50_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='1c1f8f5b0c8ee28fe9d950625a230e1c')
|
||||
else:
|
||||
weights_path = get_file('resnet50_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='f64f049c92468c9affcd44b0976cdafe')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('resnet50_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='a7b3fe01876f51b976af0dea6bc144eb')
|
||||
else:
|
||||
weights_path = get_file('resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='a268eb855778b3df3c7506639542a6af')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
@@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''VGG16 model for Keras.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)
|
||||
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..models import Model
|
||||
from ..layers import Flatten, Dense, Input
|
||||
from ..layers import Convolution2D, MaxPooling2D
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
from .imagenet_utils import decode_predictions, preprocess_input
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def VGG16(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the VGG16 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 224, 224)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (224, 224, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
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
|
||||
# Block 1
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv1')(img_input)
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
|
||||
|
||||
# Block 2
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv1')(x)
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
|
||||
|
||||
# Block 3
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv1')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv2')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv3')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
|
||||
|
||||
# Block 4
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv3')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
|
||||
|
||||
# Block 5
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv3')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = Flatten(name='flatten')(x)
|
||||
x = Dense(4096, activation='relu', name='fc1')(x)
|
||||
x = Dense(4096, activation='relu', name='fc2')(x)
|
||||
x = Dense(1000, activation='softmax', name='predictions')(x)
|
||||
|
||||
# Create model
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('vgg16_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg16_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('vgg16_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
@@ -0,0 +1,152 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''VGG19 model for Keras.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)
|
||||
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..models import Model
|
||||
from ..layers import Flatten, Dense, Input
|
||||
from ..layers import Convolution2D, MaxPooling2D
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
from .imagenet_utils import decode_predictions, preprocess_input
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def VGG19(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the VGG19 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 224, 224)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (224, 224, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
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
|
||||
# Block 1
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv1')(img_input)
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
|
||||
|
||||
# Block 2
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv1')(x)
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
|
||||
|
||||
# Block 3
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv1')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv2')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv3')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv4')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
|
||||
|
||||
# Block 4
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv3')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv4')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
|
||||
|
||||
# Block 5
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv3')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv4')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = Flatten(name='flatten')(x)
|
||||
x = Dense(4096, activation='relu', name='fc1')(x)
|
||||
x = Dense(4096, activation='relu', name='fc2')(x)
|
||||
x = Dense(1000, activation='softmax', name='predictions')(x)
|
||||
|
||||
# Create model
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('vgg19_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg19_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('vgg19_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
@@ -23,7 +23,7 @@ _keras_dir = os.path.join(_keras_base_dir, '.keras')
|
||||
if not os.path.exists(_keras_dir):
|
||||
os.makedirs(_keras_dir)
|
||||
|
||||
_BACKEND = 'theano'
|
||||
_BACKEND = 'tensorflow'
|
||||
_config_path = os.path.expanduser(os.path.join(_keras_dir, 'keras.json'))
|
||||
if os.path.exists(_config_path):
|
||||
_config = json.load(open(_config_path))
|
||||
|
||||
@@ -6,7 +6,7 @@ from collections import defaultdict
|
||||
_FLOATX = 'float32'
|
||||
_EPSILON = 10e-8
|
||||
_UID_PREFIXES = defaultdict(int)
|
||||
_IMAGE_DIM_ORDERING = 'th'
|
||||
_IMAGE_DIM_ORDERING = 'tf'
|
||||
_LEGACY_WEIGHT_ORDERING = False
|
||||
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
import tensorflow as tf
|
||||
from tensorflow.python.training import moving_averages
|
||||
try:
|
||||
import tensorflow.contrib.ctc as ctc
|
||||
except ImportError:
|
||||
from tensorflow.python.ops import ctc_ops as ctc
|
||||
import numpy as np
|
||||
import os
|
||||
import copy
|
||||
import warnings
|
||||
from .common import _FLOATX, _EPSILON, _IMAGE_DIM_ORDERING, reset_uids
|
||||
py_all = all
|
||||
|
||||
# INTERNAL UTILS
|
||||
|
||||
@@ -113,6 +118,17 @@ def _to_tensor(x, dtype):
|
||||
return x
|
||||
|
||||
|
||||
def is_sparse(tensor):
|
||||
return isinstance(tensor, tf.SparseTensor)
|
||||
|
||||
|
||||
def to_dense(tensor):
|
||||
if is_sparse(tensor):
|
||||
return tf.sparse_tensor_to_dense(tensor)
|
||||
else:
|
||||
return tensor
|
||||
|
||||
|
||||
def variable(value, dtype=_FLOATX, name=None):
|
||||
'''Instantiates a tensor.
|
||||
|
||||
@@ -124,6 +140,12 @@ def variable(value, dtype=_FLOATX, name=None):
|
||||
# Returns
|
||||
Tensor variable instance.
|
||||
'''
|
||||
if hasattr(value, 'tocoo'):
|
||||
sparse_coo = value.tocoo()
|
||||
indices = np.concatenate((np.expand_dims(sparse_coo.row, 1), np.expand_dims(sparse_coo.col, 1)), 1)
|
||||
# SparseTensor doesn't need initialization
|
||||
return tf.SparseTensor(indices=indices, values=value.data, shape=value.shape)
|
||||
|
||||
v = tf.Variable(value, dtype=_convert_string_dtype(dtype), name=name)
|
||||
if _MANUAL_VAR_INIT:
|
||||
return v
|
||||
@@ -144,7 +166,7 @@ def variable(value, dtype=_FLOATX, name=None):
|
||||
return v
|
||||
|
||||
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, sparse=False, name=None):
|
||||
'''Instantiates a placeholder.
|
||||
|
||||
# Arguments
|
||||
@@ -162,7 +184,11 @@ def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
if not shape:
|
||||
if ndim:
|
||||
shape = tuple([None for _ in range(ndim)])
|
||||
x = tf.placeholder(dtype, shape=shape, name=name)
|
||||
if sparse:
|
||||
tf_shape = tf.constant(np.array(list([0 for _ in range(len(shape))]), dtype=np.int64))
|
||||
x = tf.sparse_placeholder(dtype, shape=tf_shape, name=name)
|
||||
else:
|
||||
x = tf.placeholder(dtype, shape=shape, name=name)
|
||||
x._keras_shape = shape
|
||||
x._uses_learning_phase = False
|
||||
return x
|
||||
@@ -186,6 +212,9 @@ def int_shape(x):
|
||||
def ndim(x):
|
||||
'''Returns the number of axes in a tensor, as an integer.
|
||||
'''
|
||||
if is_sparse(x):
|
||||
return int(x.shape.get_shape()[0])
|
||||
|
||||
dims = x.get_shape()._dims
|
||||
if dims is not None:
|
||||
return len(dims)
|
||||
@@ -202,7 +231,7 @@ def eval(x):
|
||||
'''Evaluates the value of a tensor.
|
||||
Returns a Numpy array.
|
||||
'''
|
||||
return x.eval(session=get_session())
|
||||
return to_dense(x).eval(session=get_session())
|
||||
|
||||
|
||||
def zeros(shape, dtype=_FLOATX, name=None):
|
||||
@@ -314,7 +343,10 @@ def dot(x, y):
|
||||
xt = tf.reshape(x, [-1, x_shape[-1]])
|
||||
yt = tf.reshape(tf.transpose(y, perm=y_permute_dim), [y_shape[-2], -1])
|
||||
return tf.reshape(tf.matmul(xt, yt), x_shape[:-1] + y_shape[:-2] + y_shape[-1:])
|
||||
out = tf.matmul(x, y)
|
||||
if is_sparse(x):
|
||||
out = tf.sparse_tensor_dense_matmul(x, y)
|
||||
else:
|
||||
out = tf.matmul(x, y)
|
||||
return out
|
||||
|
||||
|
||||
@@ -672,11 +704,16 @@ def concatenate(tensors, axis=-1):
|
||||
'''Concantes a list of tensors alongside the specified axis.
|
||||
'''
|
||||
if axis < 0:
|
||||
if len(tensors[0].get_shape()):
|
||||
axis = axis % len(tensors[0].get_shape())
|
||||
dims = ndim(tensors[0])
|
||||
if dims:
|
||||
axis = axis % dims
|
||||
else:
|
||||
axis = 0
|
||||
return tf.concat(axis, tensors)
|
||||
|
||||
if py_all([is_sparse(x) for x in tensors]):
|
||||
return tf.sparse_concat(axis, tensors)
|
||||
else:
|
||||
return tf.concat(axis, [to_dense(x) for x in tensors])
|
||||
|
||||
|
||||
def reshape(x, shape):
|
||||
@@ -807,7 +844,7 @@ def temporal_padding(x, padding=1):
|
||||
return tf.pad(x, pattern)
|
||||
|
||||
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
'''Pads the 2nd and 3rd dimensions of a 4D tensor
|
||||
with "padding[0]" and "padding[1]" (resp.) zeros left and right.
|
||||
'''
|
||||
@@ -821,7 +858,7 @@ def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
return tf.pad(x, pattern)
|
||||
|
||||
|
||||
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering='th'):
|
||||
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
'''Pads 5D tensor with zeros for the depth, height, width dimension with
|
||||
"padding[0]", "padding[1]" and "padding[2]" (resp.) zeros left and right
|
||||
|
||||
@@ -965,8 +1002,13 @@ class Function(object):
|
||||
|
||||
def __call__(self, inputs):
|
||||
assert type(inputs) in {list, tuple}
|
||||
names = [getattr(v, 'name', None) for v in self.inputs]
|
||||
feed_dict = dict(zip(names, inputs))
|
||||
feed_dict = {}
|
||||
for tensor, value in zip(self.inputs, inputs):
|
||||
if is_sparse(tensor):
|
||||
sparse_coo = value.tocoo()
|
||||
indices = np.concatenate((np.expand_dims(sparse_coo.row, 1), np.expand_dims(sparse_coo.col, 1)), 1)
|
||||
value = (indices, value.data, value.shape)
|
||||
feed_dict[tensor] = value
|
||||
session = get_session()
|
||||
updated = session.run(self.outputs + [self.updates_op], feed_dict=feed_dict)
|
||||
return updated[:len(self.outputs)]
|
||||
@@ -993,7 +1035,7 @@ def gradients(loss, variables):
|
||||
'''Returns the gradients of `variables` (list of tensor variables)
|
||||
with regard to `loss`.
|
||||
'''
|
||||
return tf.gradients(loss, variables)
|
||||
return tf.gradients(loss, variables, colocate_gradients_with_ops=True)
|
||||
|
||||
|
||||
def stop_gradient(variables):
|
||||
@@ -1126,17 +1168,26 @@ def rnn(step_function, inputs, initial_states,
|
||||
states = initial_states
|
||||
nb_states = len(states)
|
||||
if nb_states == 0:
|
||||
raise Exception('No initial states provided.')
|
||||
elif nb_states == 1:
|
||||
state = states[0]
|
||||
# use dummy state, otherwise _dynamic_rnn_loop breaks
|
||||
state = inputs[:, 0, :]
|
||||
state_size = state.get_shape()[-1]
|
||||
else:
|
||||
state = tf.concat(1, states)
|
||||
|
||||
state_size = int(states[0].get_shape()[-1])
|
||||
state_size = int(states[0].get_shape()[-1])
|
||||
if nb_states == 1:
|
||||
state = states[0]
|
||||
else:
|
||||
state = tf.concat(1, states)
|
||||
|
||||
if mask is not None:
|
||||
if len(initial_states) == 0:
|
||||
raise ValueError('No initial states provided! '
|
||||
'When using masking in an RNN, you should '
|
||||
'provide initial states '
|
||||
'(and your step function should return '
|
||||
'as its first state at time `t` '
|
||||
'the output at time `t-1`).')
|
||||
if go_backwards:
|
||||
mask = tf.reverse(mask, [True] + [False] * (ndim - 1))
|
||||
mask = tf.reverse(mask, [True] + [False] * (ndim - 2))
|
||||
|
||||
# Transpose not supported by bool tensor types, hence round-trip to uint8.
|
||||
mask = tf.cast(mask, tf.uint8)
|
||||
@@ -1171,20 +1222,28 @@ def rnn(step_function, inputs, initial_states,
|
||||
states = []
|
||||
for i in range(nb_states):
|
||||
states.append(state[:, i * state_size: (i + 1) * state_size])
|
||||
else:
|
||||
elif nb_states == 1:
|
||||
states = [state]
|
||||
else:
|
||||
states = []
|
||||
output, new_states = step_function(input, states + constants)
|
||||
|
||||
if len(new_states) == 1:
|
||||
if len(new_states) > 1:
|
||||
new_state = tf.concat(1, new_states)
|
||||
elif len(new_states) == 1:
|
||||
new_state = new_states[0]
|
||||
else:
|
||||
new_state = tf.concat(1, new_states)
|
||||
# return dummy state, otherwise _dynamic_rnn_loop breaks
|
||||
new_state = output
|
||||
return output, new_state
|
||||
|
||||
# state size is assumed to be the same as output size
|
||||
# (always the case)
|
||||
_step.state_size = state_size * nb_states
|
||||
_step.output_size = state_size
|
||||
# recover output size by calling _step on the first input
|
||||
slice_begin = tf.pack([0] * ndim)
|
||||
slice_size = tf.pack([1] + [-1] * (ndim - 1))
|
||||
first_input = tf.slice(inputs, slice_begin, slice_size)
|
||||
first_input = tf.squeeze(first_input, [0])
|
||||
_step.output_size = int(_step(first_input, state)[0].get_shape()[-1])
|
||||
|
||||
(outputs, final_state) = _dynamic_rnn_loop(
|
||||
_step,
|
||||
@@ -1198,13 +1257,15 @@ def rnn(step_function, inputs, initial_states,
|
||||
new_states = []
|
||||
for i in range(nb_states):
|
||||
new_states.append(final_state[:, i * state_size: (i + 1) * state_size])
|
||||
else:
|
||||
elif nb_states == 1:
|
||||
new_states = [final_state]
|
||||
else:
|
||||
new_states = []
|
||||
|
||||
# all this circus is to recover the last vector in the sequence.
|
||||
begin = tf.pack([tf.shape(outputs)[0] - 1] + [0] * (ndim - 1))
|
||||
size = tf.pack([1] + [-1] * (ndim - 1))
|
||||
last_output = tf.slice(outputs, begin, size)
|
||||
slice_begin = tf.pack([tf.shape(outputs)[0] - 1] + [0] * (ndim - 1))
|
||||
slice_size = tf.pack([1] + [-1] * (ndim - 1))
|
||||
last_output = tf.slice(outputs, slice_begin, slice_size)
|
||||
last_output = tf.squeeze(last_output, [0])
|
||||
|
||||
axes = [1, 0] + list(range(2, len(outputs.get_shape())))
|
||||
@@ -1757,13 +1818,13 @@ def ctc_batch_cost(y_true, y_pred, input_length, label_length):
|
||||
|
||||
y_pred = tf.log(tf.transpose(y_pred, perm=[1, 0, 2]) + 1e-8)
|
||||
|
||||
return tf.expand_dims(tf.contrib.ctc.ctc_loss(inputs=y_pred,
|
||||
labels=sparse_labels,
|
||||
sequence_length=input_length), 1)
|
||||
return tf.expand_dims(ctc.ctc_loss(inputs=y_pred,
|
||||
labels=sparse_labels,
|
||||
sequence_length=input_length), 1)
|
||||
|
||||
|
||||
def ctc_decode(y_pred, input_length, greedy=True, beam_width=None,
|
||||
dict_seq_lens=None, dict_values=None):
|
||||
def ctc_decode(y_pred, input_length, greedy=True, beam_width=100,
|
||||
top_paths=1):
|
||||
'''Decodes the output of a softmax using either
|
||||
greedy (also known as best path) or a constrained dictionary
|
||||
search.
|
||||
@@ -1771,38 +1832,33 @@ def ctc_decode(y_pred, input_length, greedy=True, beam_width=None,
|
||||
# Arguments
|
||||
y_pred: tensor (samples, time_steps, num_categories) containing the prediction,
|
||||
or output of the softmax
|
||||
input_length: tensor (samples,1) containing the sequence length for
|
||||
input_length: tensor (samples,) containing the sequence length for
|
||||
each batch item in y_pred
|
||||
greedy: perform much faster best-path search if true. This does
|
||||
greedy: perform much faster best-path search if true. This does
|
||||
not use a dictionary
|
||||
beam_width: if greedy is false and this value is not none, then
|
||||
the constrained dictionary search uses a beam of this width
|
||||
dict_seq_lens: the length of each element in the dict_values list
|
||||
dict_values: list of lists representing the dictionary.
|
||||
beam_width: if greedy is false: a beam search decoder will be used
|
||||
with a beam of this width
|
||||
top_paths: if greedy is false: how many of the most probable paths will be returned
|
||||
|
||||
# Returns
|
||||
Tensor with shape (samples,time_steps,num_categories) containing the
|
||||
path probabilities (in softmax output format). Note that a function that
|
||||
pulls out the argmax and collapses blank labels is still needed.
|
||||
Tuple:
|
||||
List: if greedy is true, returns a list of one element that contains
|
||||
the decoded sequence. If false, returns the `top_paths` most probable
|
||||
decoded sequences. Important: blank labels are returned as -1
|
||||
Tensor (top_paths,) that contains the log probability of each decoded sequence
|
||||
'''
|
||||
y_pred = tf.log(tf.transpose(y_pred, perm=[1, 0, 2]) + 1e-8)
|
||||
input_length = tf.to_int32(tf.squeeze(input_length))
|
||||
input_length = tf.to_int32(input_length)
|
||||
|
||||
if greedy:
|
||||
(decoded, log_prob) = tf.contrib.ctc.ctc_greedy_decoder(
|
||||
(decoded, log_prob) = ctc.ctc_greedy_decoder(
|
||||
inputs=y_pred,
|
||||
sequence_length=input_length)
|
||||
else:
|
||||
if beam_width is not None:
|
||||
(decoded, log_prob) = tf.contrib.ctc.ctc_beam_search_decoder(
|
||||
inputs=y_pred,
|
||||
sequence_length=input_length,
|
||||
dict_seq_lens=dict_seq_lens, dict_values=dict_values)
|
||||
else:
|
||||
(decoded, log_prob) = tf.contrib.ctc.ctc_beam_search_decoder(
|
||||
inputs=y_pred,
|
||||
sequence_length=input_length, beam_width=beam_width,
|
||||
dict_seq_lens=dict_seq_lens, dict_values=dict_values)
|
||||
(decoded, log_prob) = ctc.ctc_beam_search_decoder(
|
||||
inputs=y_pred,
|
||||
sequence_length=input_length, beam_width=beam_width,
|
||||
top_paths=top_paths)
|
||||
|
||||
decoded_dense = [tf.sparse_to_dense(st.indices, st.shape, st.values, default_value=-1)
|
||||
for st in decoded]
|
||||
|
||||
@@ -4,6 +4,10 @@ from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from theano.tensor.signal import pool
|
||||
from theano.tensor.nnet import conv3d2d
|
||||
from theano.printing import Print
|
||||
try:
|
||||
import theano.sparse as th_sparse_module
|
||||
except ImportError:
|
||||
th_sparse_module = None
|
||||
try:
|
||||
from theano.tensor.nnet.nnet import softsign as T_softsign
|
||||
except ImportError:
|
||||
@@ -11,6 +15,7 @@ except ImportError:
|
||||
import inspect
|
||||
import numpy as np
|
||||
from .common import _FLOATX, _EPSILON, _IMAGE_DIM_ORDERING
|
||||
py_all = all
|
||||
|
||||
|
||||
# INTERNAL UTILS
|
||||
@@ -30,17 +35,38 @@ def set_learning_phase(value):
|
||||
'0 or 1.')
|
||||
_LEARNING_PHASE = value
|
||||
|
||||
|
||||
# VARIABLE MANIPULATION
|
||||
|
||||
|
||||
def _assert_sparse_module():
|
||||
if not th_sparse_module:
|
||||
raise ImportError("Failed to import theano.sparse\n"
|
||||
"You probably need to pip install nose-parameterized")
|
||||
|
||||
|
||||
def is_sparse(tensor):
|
||||
return th_sparse_module and isinstance(tensor.type, th_sparse_module.SparseType)
|
||||
|
||||
|
||||
def to_dense(tensor):
|
||||
if is_sparse(tensor):
|
||||
return th_sparse_module.dense_from_sparse(tensor)
|
||||
else:
|
||||
return tensor
|
||||
|
||||
|
||||
def variable(value, dtype=_FLOATX, name=None):
|
||||
'''Instantiate a tensor variable.
|
||||
'''
|
||||
value = np.asarray(value, dtype=dtype)
|
||||
return theano.shared(value=value, name=name, strict=False)
|
||||
if hasattr(value, 'tocoo'):
|
||||
_assert_sparse_module()
|
||||
return th_sparse_module.as_sparse_variable(value)
|
||||
else:
|
||||
value = np.asarray(value, dtype=dtype)
|
||||
return theano.shared(value=value, name=name, strict=False)
|
||||
|
||||
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, sparse=False, name=None):
|
||||
'''Instantiate an input data placeholder variable.
|
||||
'''
|
||||
if shape is None and ndim is None:
|
||||
@@ -51,7 +77,11 @@ def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
shape = tuple([None for _ in range(ndim)])
|
||||
|
||||
broadcast = (False,) * ndim
|
||||
x = T.TensorType(dtype, broadcast)(name)
|
||||
if sparse:
|
||||
_assert_sparse_module()
|
||||
x = th_sparse_module.csr_matrix(name=name, dtype=dtype)
|
||||
else:
|
||||
x = T.TensorType(dtype, broadcast)(name)
|
||||
x._keras_shape = shape
|
||||
x._uses_learning_phase = False
|
||||
return x
|
||||
@@ -77,7 +107,7 @@ def dtype(x):
|
||||
def eval(x):
|
||||
'''Run a graph.
|
||||
'''
|
||||
return x.eval()
|
||||
return to_dense(x).eval()
|
||||
|
||||
|
||||
def zeros(shape, dtype=_FLOATX, name=None):
|
||||
@@ -156,7 +186,10 @@ Assumed overridden:
|
||||
|
||||
|
||||
def dot(x, y):
|
||||
return T.dot(x, y)
|
||||
if is_sparse(x):
|
||||
return th_sparse_module.basic.structured_dot(x, y)
|
||||
else:
|
||||
return T.dot(x, y)
|
||||
|
||||
|
||||
def batch_dot(x, y, axes=None):
|
||||
@@ -386,7 +419,10 @@ def normalize_batch_in_training(x, gamma, beta,
|
||||
def batch_normalization(x, mean, var, beta, gamma, epsilon=0.0001):
|
||||
'''Apply batch normalization on x given mean, var, beta and gamma.
|
||||
'''
|
||||
if theano.config.device.startswith('cuda') or theano.config.device.startswith('gpu'):
|
||||
ndim = x.ndim
|
||||
dev = theano.config.device
|
||||
use_cudnn = ndim < 5 and (dev.startswith('cuda') or dev.startswith('gpu'))
|
||||
if use_cudnn:
|
||||
try:
|
||||
return theano.sandbox.cuda.dnn.dnn_batch_normalization_test(x, gamma, beta, mean, var,
|
||||
'spatial', epsilon)
|
||||
@@ -399,7 +435,16 @@ def batch_normalization(x, mean, var, beta, gamma, epsilon=0.0001):
|
||||
# SHAPE OPERATIONS
|
||||
|
||||
def concatenate(tensors, axis=-1):
|
||||
return T.concatenate(tensors, axis=axis)
|
||||
if py_all([is_sparse(x) for x in tensors]):
|
||||
axis = axis % ndim(tensors[0])
|
||||
if axis == 0:
|
||||
return th_sparse_module.basic.vstack(tensors, format='csr')
|
||||
elif axis == 1:
|
||||
return th_sparse_module.basic.hstack(tensors, format='csr')
|
||||
else:
|
||||
raise Exception('Invalid concat axis for sparse matrix: ' + axis)
|
||||
else:
|
||||
return T.concatenate([to_dense(x) for x in tensors], axis=axis)
|
||||
|
||||
|
||||
def reshape(x, shape):
|
||||
@@ -528,7 +573,7 @@ def temporal_padding(x, padding=1):
|
||||
return T.set_subtensor(output[:, padding:x.shape[1] + padding, :], x)
|
||||
|
||||
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
'''Pad the 2nd and 3rd dimensions of a 4D tensor
|
||||
with "padding[0]" and "padding[1]" (resp.) zeros left and right.
|
||||
'''
|
||||
@@ -559,7 +604,7 @@ def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
return T.set_subtensor(output[indices], x)
|
||||
|
||||
|
||||
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering='th'):
|
||||
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
'''Pad the 2nd, 3rd and 4th dimensions of a 5D tensor
|
||||
with "padding[0]", "padding[1]" and "padding[2]" (resp.) zeros left and right.
|
||||
'''
|
||||
@@ -646,7 +691,7 @@ def batch_set_value(tuples):
|
||||
|
||||
|
||||
def get_variable_shape(x):
|
||||
return x.get_value().shape
|
||||
return x.get_value(borrow=True, return_internal_type=True).shape
|
||||
|
||||
|
||||
def print_tensor(x, message=''):
|
||||
@@ -1152,7 +1197,7 @@ def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
|
||||
|
||||
|
||||
def conv3d(x, kernel, strides=(1, 1, 1),
|
||||
border_mode='valid', dim_ordering='th',
|
||||
border_mode='valid', dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
volume_shape=None, filter_shape=None):
|
||||
'''
|
||||
Run on cuDNN if available.
|
||||
@@ -1214,7 +1259,7 @@ def conv3d(x, kernel, strides=(1, 1, 1),
|
||||
|
||||
|
||||
def pool2d(x, pool_size, strides=(1, 1), border_mode='valid',
|
||||
dim_ordering='th', pool_mode='max'):
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, pool_mode='max'):
|
||||
if border_mode == 'same':
|
||||
w_pad = pool_size[0] - 2 if pool_size[0] % 2 == 1 else pool_size[0] - 1
|
||||
h_pad = pool_size[1] - 2 if pool_size[1] % 2 == 1 else pool_size[1] - 1
|
||||
@@ -1257,7 +1302,7 @@ def pool2d(x, pool_size, strides=(1, 1), border_mode='valid',
|
||||
|
||||
|
||||
def pool3d(x, pool_size, strides=(1, 1, 1), border_mode='valid',
|
||||
dim_ordering='th', pool_mode='max'):
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, pool_mode='max'):
|
||||
if border_mode == 'same':
|
||||
# TODO: add implementation for border_mode="same"
|
||||
raise Exception('border_mode="same" not supported with Theano.')
|
||||
|
||||
+27
-11
@@ -315,11 +315,13 @@ class EarlyStopping(Callback):
|
||||
patience: number of epochs with no improvement
|
||||
after which training will be stopped.
|
||||
verbose: verbosity mode.
|
||||
mode: one of {auto, min, max}. In 'min' mode,
|
||||
mode: one of {auto, min, max}. In `min` mode,
|
||||
training will stop when the quantity
|
||||
monitored has stopped decreasing; in 'max'
|
||||
monitored has stopped decreasing; in `max`
|
||||
mode it will stop when the quantity
|
||||
monitored has stopped increasing.
|
||||
monitored has stopped increasing; in `auto`
|
||||
mode, the direction is automatically inferred
|
||||
from the name of the monitored quantity.
|
||||
'''
|
||||
def __init__(self, monitor='val_loss', patience=0, verbose=0, mode='auto'):
|
||||
super(EarlyStopping, self).__init__()
|
||||
@@ -451,7 +453,7 @@ class TensorBoard(Callback):
|
||||
write_graph is set to True.
|
||||
'''
|
||||
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0, write_graph=True):
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0, write_graph=True, write_images=False):
|
||||
super(TensorBoard, self).__init__()
|
||||
if K._BACKEND != 'tensorflow':
|
||||
raise Exception('TensorBoard callback only works '
|
||||
@@ -460,6 +462,7 @@ class TensorBoard(Callback):
|
||||
self.histogram_freq = histogram_freq
|
||||
self.merged = None
|
||||
self.write_graph = write_graph
|
||||
self.write_images = write_images
|
||||
|
||||
def _set_model(self, model):
|
||||
import tensorflow as tf
|
||||
@@ -468,14 +471,27 @@ class TensorBoard(Callback):
|
||||
self.model = model
|
||||
self.sess = KTF.get_session()
|
||||
if self.histogram_freq and self.merged is None:
|
||||
layers = self.model.layers
|
||||
for layer in layers:
|
||||
if hasattr(layer, 'W'):
|
||||
tf.histogram_summary('{}_W'.format(layer), layer.W)
|
||||
if hasattr(layer, 'b'):
|
||||
tf.histogram_summary('{}_b'.format(layer), layer.b)
|
||||
for layer in self.model.layers:
|
||||
|
||||
for weight in layer.weights:
|
||||
tf.histogram_summary(weight.name, weight)
|
||||
|
||||
if self.write_images:
|
||||
w_img = tf.squeeze(weight)
|
||||
|
||||
shape = w_img.get_shape()
|
||||
if len(shape) > 1 and shape[0] > shape[1]:
|
||||
w_img = tf.transpose(w_img)
|
||||
|
||||
if len(shape) == 1:
|
||||
w_img = tf.expand_dims(w_img, 0)
|
||||
|
||||
w_img = tf.expand_dims(tf.expand_dims(w_img, 0), -1)
|
||||
|
||||
tf.image_summary(weight.name, w_img)
|
||||
|
||||
if hasattr(layer, 'output'):
|
||||
tf.histogram_summary('{}_out'.format(layer),
|
||||
tf.histogram_summary('{}_out'.format(layer.name),
|
||||
layer.output)
|
||||
self.merged = tf.merge_all_summaries()
|
||||
if self.write_graph:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from .cifar import load_batch
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
@@ -18,8 +19,8 @@ def load_data():
|
||||
for i in range(1, 6):
|
||||
fpath = os.path.join(path, 'data_batch_' + str(i))
|
||||
data, labels = load_batch(fpath)
|
||||
X_train[(i-1)*10000:i*10000, :, :, :] = data
|
||||
y_train[(i-1)*10000:i*10000] = labels
|
||||
X_train[(i - 1) * 10000: i * 10000, :, :, :] = data
|
||||
y_train[(i - 1) * 10000: i * 10000] = labels
|
||||
|
||||
fpath = os.path.join(path, 'test_batch')
|
||||
X_test, y_test = load_batch(fpath)
|
||||
@@ -27,4 +28,8 @@ def load_data():
|
||||
y_train = np.reshape(y_train, (len(y_train), 1))
|
||||
y_test = np.reshape(y_test, (len(y_test), 1))
|
||||
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
X_train = X_train.transpose(0, 2, 3, 1)
|
||||
X_test = X_test.transpose(0, 2, 3, 1)
|
||||
|
||||
return (X_train, y_train), (X_test, y_test)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from .cifar import load_batch
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
@@ -13,9 +14,6 @@ def load_data(label_mode='fine'):
|
||||
origin = "http://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz"
|
||||
path = get_file(dirname, origin=origin, untar=True)
|
||||
|
||||
nb_test_samples = 10000
|
||||
nb_train_samples = 50000
|
||||
|
||||
fpath = os.path.join(path, 'train')
|
||||
X_train, y_train = load_batch(fpath, label_key=label_mode+'_labels')
|
||||
|
||||
@@ -25,4 +23,8 @@ def load_data(label_mode='fine'):
|
||||
y_train = np.reshape(y_train, (len(y_train), 1))
|
||||
y_test = np.reshape(y_test, (len(y_test), 1))
|
||||
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
X_train = X_train.transpose(0, 2, 3, 1)
|
||||
X_test = X_test.transpose(0, 2, 3, 1)
|
||||
|
||||
return (X_train, y_train), (X_test, y_test)
|
||||
|
||||
+98
-28
@@ -5,8 +5,6 @@ from __future__ import division
|
||||
|
||||
import numpy as np
|
||||
|
||||
import sys
|
||||
import marshal
|
||||
import types as python_types
|
||||
import warnings
|
||||
import copy
|
||||
@@ -15,6 +13,7 @@ from six.moves import zip
|
||||
|
||||
from .. import backend as K
|
||||
from ..utils.io_utils import ask_to_proceed_with_overwrite
|
||||
from ..utils.generic_utils import func_dump, func_load
|
||||
|
||||
|
||||
def to_list(x):
|
||||
@@ -948,7 +947,7 @@ class InputLayer(Layer):
|
||||
'''TODO: dosctring
|
||||
'''
|
||||
def __init__(self, input_shape=None, batch_input_shape=None,
|
||||
input_dtype=None, input_tensor=None, name=None):
|
||||
input_dtype=None, input_tensor=None, sparse=False, name=None):
|
||||
self.input_spec = None
|
||||
self.supports_masking = False
|
||||
self.uses_learning_phase = False
|
||||
@@ -965,6 +964,8 @@ class InputLayer(Layer):
|
||||
self.regularizers = []
|
||||
self.constraints = {}
|
||||
|
||||
self.sparse = sparse
|
||||
|
||||
if not name:
|
||||
prefix = 'input'
|
||||
name = prefix + '_' + str(K.get_uid(prefix))
|
||||
@@ -975,11 +976,11 @@ class InputLayer(Layer):
|
||||
'batch_input_shape argument to '
|
||||
'InputLayer, not both at the same time.')
|
||||
if input_tensor is not None:
|
||||
if not input_shape and not batch_input_shape:
|
||||
# attempt automatic input shape inference
|
||||
try:
|
||||
batch_input_shape = K.int_shape(input_tensor)
|
||||
except:
|
||||
# attempt automatic input shape inference
|
||||
try:
|
||||
batch_input_shape = K.int_shape(input_tensor)
|
||||
except:
|
||||
if not input_shape and not batch_input_shape:
|
||||
raise ValueError('InputLayer was provided an input_tensor argument, '
|
||||
'but its input shape cannot be automatically inferred. '
|
||||
'You should pass an input_shape or batch_input_shape '
|
||||
@@ -1005,6 +1006,7 @@ class InputLayer(Layer):
|
||||
if input_tensor is None:
|
||||
input_tensor = K.placeholder(shape=batch_input_shape,
|
||||
dtype=input_dtype,
|
||||
sparse=self.sparse,
|
||||
name=self.name)
|
||||
else:
|
||||
input_tensor._keras_shape = batch_input_shape
|
||||
@@ -1026,12 +1028,13 @@ class InputLayer(Layer):
|
||||
def get_config(self):
|
||||
config = {'batch_input_shape': self.batch_input_shape,
|
||||
'input_dtype': self.input_dtype,
|
||||
'sparse': self.sparse,
|
||||
'name': self.name}
|
||||
return config
|
||||
|
||||
|
||||
def Input(shape=None, batch_shape=None,
|
||||
name=None, dtype=K.floatx(),
|
||||
name=None, dtype=K.floatx(), sparse=False,
|
||||
tensor=None):
|
||||
'''`Input()` is used to instantiate a Keras tensor.
|
||||
A Keras tensor is a tensor object from the underlying backend
|
||||
@@ -1064,6 +1067,7 @@ def Input(shape=None, batch_shape=None,
|
||||
It will be autogenerated if it isn't provided.
|
||||
dtype: The data type expected by the input, as a string
|
||||
(`float32`, `float64`, `int32`...)
|
||||
sparse: a boolean specifying whether this will be a sparse tensor
|
||||
|
||||
# Example usage
|
||||
|
||||
@@ -1079,9 +1083,11 @@ def Input(shape=None, batch_shape=None,
|
||||
' or a `batch_shape` argument. Note that ' +
|
||||
'`shape` does not include the batch '
|
||||
'dimension.')
|
||||
if shape and not batch_shape:
|
||||
batch_shape = (None,) + tuple(shape)
|
||||
input_layer = InputLayer(batch_input_shape=batch_shape,
|
||||
name=name, input_dtype=dtype,
|
||||
sparse=sparse,
|
||||
input_tensor=tensor)
|
||||
# return tensor including _keras_shape and _keras_history
|
||||
# note that in this case train_output and test_output are the same pointer.
|
||||
@@ -1233,7 +1239,7 @@ class Merge(Layer):
|
||||
raise Exception('Invalid format for dot_axes - list elements should be "int".')
|
||||
if shape1[self.dot_axes[0]] != shape2[self.dot_axes[1]]:
|
||||
raise Exception('Dimension incompatibility using dot mode: ' +
|
||||
'%s != %s. ' % (shape1[dot_axes[0]], shape2[dot_axes[1]]) +
|
||||
'%s != %s. ' % (shape1[self.dot_axes[0]], shape2[self.dot_axes[1]]) +
|
||||
'Layer shapes: %s, %s' % (shape1, shape2))
|
||||
elif mode == 'concat':
|
||||
reduced_inputs_shapes = [list(shape) for shape in input_shapes]
|
||||
@@ -1388,7 +1394,7 @@ class Merge(Layer):
|
||||
masks = [K.expand_dims(m, 0) for m in mask if m is not None]
|
||||
return K.all(K.concatenate(masks, axis=0), axis=0, keepdims=False)
|
||||
elif self.mode == 'concat':
|
||||
# Make a list of masks while making sure the dimensionality of each mask
|
||||
# Make a list of masks while making sure the dimensionality of each mask
|
||||
# is the same as the corresponding input.
|
||||
masks = []
|
||||
for input_i, mask_i in zip(inputs, mask):
|
||||
@@ -1414,13 +1420,8 @@ class Merge(Layer):
|
||||
raise Exception('Invalid merge mode: {}'.format(self.mode))
|
||||
|
||||
def get_config(self):
|
||||
py3 = sys.version_info[0] == 3
|
||||
|
||||
if isinstance(self.mode, python_types.LambdaType):
|
||||
if py3:
|
||||
mode = marshal.dumps(self.mode.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
mode = marshal.dumps(self.mode.func_code).decode('raw_unicode_escape')
|
||||
mode = func_dump(self.mode)
|
||||
mode_type = 'lambda'
|
||||
elif callable(self.mode):
|
||||
mode = self.mode.__name__
|
||||
@@ -1430,10 +1431,7 @@ class Merge(Layer):
|
||||
mode_type = 'raw'
|
||||
|
||||
if isinstance(self._output_shape, python_types.LambdaType):
|
||||
if py3:
|
||||
output_shape = marshal.dumps(self._output_shape.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
output_shape = marshal.dumps(self._output_shape.func_code).decode('raw_unicode_escape')
|
||||
output_shape = func_dump(self._output_shape)
|
||||
output_shape_type = 'lambda'
|
||||
elif callable(self._output_shape):
|
||||
output_shape = self._output_shape.__name__
|
||||
@@ -1456,8 +1454,7 @@ class Merge(Layer):
|
||||
if mode_type == 'function':
|
||||
mode = globals()[config['mode']]
|
||||
elif mode_type == 'lambda':
|
||||
mode = marshal.loads(config['mode'].encode('raw_unicode_escape'))
|
||||
mode = python_types.FunctionType(mode, globals())
|
||||
mode = func_load(config['mode'], globs=globals())
|
||||
else:
|
||||
mode = config['mode']
|
||||
|
||||
@@ -1465,8 +1462,7 @@ class Merge(Layer):
|
||||
if output_shape_type == 'function':
|
||||
output_shape = globals()[config['output_shape']]
|
||||
elif output_shape_type == 'lambda':
|
||||
output_shape = marshal.loads(config['output_shape'].encode('raw_unicode_escape'))
|
||||
output_shape = python_types.FunctionType(output_shape, globals())
|
||||
output_shape = func_load(config['output_shape'], globs=globals())
|
||||
else:
|
||||
output_shape = config['output_shape']
|
||||
|
||||
@@ -1950,7 +1946,7 @@ class Container(Layer):
|
||||
cons = {}
|
||||
for layer in self.layers:
|
||||
for key, value in layer.constraints.items():
|
||||
if key in cons:
|
||||
if key in cons and cons[key] != value:
|
||||
raise Exception('Received multiple constraints '
|
||||
'for one weight tensor: ' + str(key))
|
||||
cons[key] = value
|
||||
@@ -2479,14 +2475,30 @@ class Container(Layer):
|
||||
else:
|
||||
param_dset[:] = val
|
||||
|
||||
def load_weights(self, filepath):
|
||||
def load_weights(self, filepath, by_name=False):
|
||||
'''Load all layer weights from a HDF5 save file.
|
||||
|
||||
If `by_name` is False (default) weights are loaded
|
||||
based on the network's topology, meaning the architecture
|
||||
should be the same as when the weights were saved.
|
||||
Note that layers that don't have weights are not taken
|
||||
into account in the topological ordering, so adding or
|
||||
removing layers is fine as long as they don't have weights.
|
||||
|
||||
If `by_name` is True, weights are loaded into layers
|
||||
only if they share the same name. This is useful
|
||||
for fine-tuning or transfer-learning models where
|
||||
some of the layers have changed.
|
||||
'''
|
||||
import h5py
|
||||
f = h5py.File(filepath, mode='r')
|
||||
if 'layer_names' not in f.attrs and 'model_weights' in f:
|
||||
f = f['model_weights']
|
||||
self.load_weights_from_hdf5_group(f)
|
||||
if by_name:
|
||||
self.load_weights_from_hdf5_group_by_name(f)
|
||||
else:
|
||||
self.load_weights_from_hdf5_group(f)
|
||||
|
||||
if hasattr(f, 'close'):
|
||||
f.close()
|
||||
|
||||
@@ -2559,9 +2571,67 @@ class Container(Layer):
|
||||
' weights, but the saved weights have ' +
|
||||
str(len(weight_values)) +
|
||||
' elements.')
|
||||
if layer.__class__.__name__ == 'Convolution1D':
|
||||
# this is for backwards compatibility with
|
||||
# the old Conv1D weights format.
|
||||
w = weight_values[0]
|
||||
shape = w.shape
|
||||
if shape[:2] != (layer.filter_length, 1) or shape[3] != layer.nb_filter:
|
||||
# legacy shape: (self.nb_filter, input_dim, self.filter_length, 1)
|
||||
assert shape[0] == layer.nb_filter and shape[2:] == (layer.filter_length, 1)
|
||||
w = np.transpose(w, (2, 3, 1, 0))
|
||||
weight_values[0] = w
|
||||
weight_value_tuples += zip(symbolic_weights, weight_values)
|
||||
K.batch_set_value(weight_value_tuples)
|
||||
|
||||
def load_weights_from_hdf5_group_by_name(self, f):
|
||||
''' Name-based weight loading
|
||||
(instead of topological weight loading).
|
||||
Layers that have no matching name are skipped.
|
||||
'''
|
||||
if hasattr(self, 'flattened_layers'):
|
||||
# support for legacy Sequential/Merge behavior
|
||||
flattened_layers = self.flattened_layers
|
||||
else:
|
||||
flattened_layers = self.layers
|
||||
|
||||
if 'nb_layers' in f.attrs:
|
||||
raise Exception('The weight file you are trying to load is' +
|
||||
' in a legacy format that does not support' +
|
||||
' name-based weight loading.')
|
||||
else:
|
||||
# new file format
|
||||
layer_names = [n.decode('utf8') for n in f.attrs['layer_names']]
|
||||
|
||||
# Reverse index of layer name to list of layers with name.
|
||||
index = {}
|
||||
for layer in flattened_layers:
|
||||
if layer.name:
|
||||
index.setdefault(layer.name, []).append(layer)
|
||||
|
||||
# we batch weight value assignments in a single backend call
|
||||
# which provides a speedup in TensorFlow.
|
||||
weight_value_tuples = []
|
||||
for k, name in enumerate(layer_names):
|
||||
g = f[name]
|
||||
weight_names = [n.decode('utf8') for n in g.attrs['weight_names']]
|
||||
weight_values = [g[weight_name] for weight_name in weight_names]
|
||||
|
||||
for layer in index.get(name, []):
|
||||
symbolic_weights = layer.weights
|
||||
if len(weight_values) != len(symbolic_weights):
|
||||
raise Exception('Layer #' + str(k) +
|
||||
' (named "' + layer.name +
|
||||
'") expects ' +
|
||||
str(len(symbolic_weights)) +
|
||||
' weight(s), but the saved weights' +
|
||||
' have ' + str(len(weight_values)) +
|
||||
' element(s).')
|
||||
# set values
|
||||
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 _updated_config(self):
|
||||
'''shared between different serialization methods'''
|
||||
from keras import __version__ as keras_version
|
||||
|
||||
+12
-10
@@ -680,6 +680,8 @@ class Model(Container):
|
||||
self.test_function = None
|
||||
self.predict_function = None
|
||||
|
||||
self._collected_trainable_weights = collect_trainable_weights(self)
|
||||
|
||||
def _make_train_function(self):
|
||||
if not hasattr(self, 'train_function'):
|
||||
raise Exception('You must compile your model before using it.')
|
||||
@@ -689,9 +691,9 @@ class Model(Container):
|
||||
else:
|
||||
inputs = self.inputs + self.targets + self.sample_weights
|
||||
|
||||
# get trainable weights
|
||||
trainable_weights = collect_trainable_weights(self)
|
||||
training_updates = self.optimizer.get_updates(trainable_weights, self.constraints, self.total_loss)
|
||||
training_updates = self.optimizer.get_updates(self._collected_trainable_weights,
|
||||
self.constraints,
|
||||
self.total_loss)
|
||||
updates = self.updates + training_updates
|
||||
|
||||
# returns loss and metrics. Updates weights at each call.
|
||||
@@ -763,9 +765,9 @@ class Model(Container):
|
||||
do_validation = True
|
||||
if verbose:
|
||||
print('Train on %d samples, validate on %d samples' %
|
||||
(len(ins[0]), len(val_ins[0])))
|
||||
(ins[0].shape[0], val_ins[0].shape[0]))
|
||||
|
||||
nb_train_sample = len(ins[0])
|
||||
nb_train_sample = ins[0].shape[0]
|
||||
index_array = np.arange(nb_train_sample)
|
||||
|
||||
self.history = cbks.History()
|
||||
@@ -859,7 +861,7 @@ class Model(Container):
|
||||
or list of arrays of predictions
|
||||
(if the model has multiple outputs).
|
||||
'''
|
||||
nb_sample = len(ins[0])
|
||||
nb_sample = ins[0].shape[0]
|
||||
outs = []
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=nb_sample)
|
||||
@@ -904,7 +906,7 @@ class Model(Container):
|
||||
and/or metrics). The attribute `model.metrics_names` will give you
|
||||
the display labels for the scalar outputs.
|
||||
'''
|
||||
nb_sample = len(ins[0])
|
||||
nb_sample = ins[0].shape[0]
|
||||
outs = []
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=nb_sample)
|
||||
@@ -1426,11 +1428,11 @@ class Model(Container):
|
||||
# build batch logs
|
||||
batch_logs = {}
|
||||
if type(x) is list:
|
||||
batch_size = len(x[0])
|
||||
batch_size = x[0].shape[0]
|
||||
elif type(x) is dict:
|
||||
batch_size = len(list(x.values())[0])
|
||||
batch_size = list(x.values())[0].shape[0]
|
||||
else:
|
||||
batch_size = len(x)
|
||||
batch_size = x.shape[0]
|
||||
batch_logs['batch'] = batch_index
|
||||
batch_logs['size'] = batch_size
|
||||
callbacks.on_batch_begin(batch_index, batch_logs)
|
||||
|
||||
+137
-24
@@ -113,7 +113,7 @@ class Convolution1D(Layer):
|
||||
|
||||
def build(self, input_shape):
|
||||
input_dim = input_shape[2]
|
||||
self.W_shape = (self.nb_filter, input_dim, self.filter_length, 1)
|
||||
self.W_shape = (self.filter_length, 1, input_dim, self.nb_filter)
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
@@ -152,15 +152,13 @@ class Convolution1D(Layer):
|
||||
return (input_shape[0], length, self.nb_filter)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
x = K.expand_dims(x, -1) # add a dimension of the right
|
||||
x = K.permute_dimensions(x, (0, 2, 1, 3))
|
||||
x = K.expand_dims(x, 2) # add a dummy dimension
|
||||
output = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='th')
|
||||
dim_ordering='tf')
|
||||
output = K.squeeze(output, 2) # remove the dummy dimension
|
||||
if self.bias:
|
||||
output += K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
output = K.squeeze(output, 3) # remove the dummy 3rd dimension
|
||||
output = K.permute_dimensions(output, (0, 2, 1))
|
||||
output += K.reshape(self.b, (1, 1, self.nb_filter))
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
@@ -183,6 +181,121 @@ class Convolution1D(Layer):
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class AtrousConvolution1D(Convolution1D):
|
||||
'''Atrous Convolution operator for filtering neighborhoods of one-dimensional inputs.
|
||||
A.k.a dilated convolution or convolution with holes.
|
||||
When using this layer as the first layer in a model,
|
||||
either provide the keyword argument `input_dim`
|
||||
(int, e.g. 128 for sequences of 128-dimensional vectors),
|
||||
or `input_shape` (tuples of integers, e.g. (10, 128) for sequences
|
||||
of 10 vectors of 128-dimensional vectors).
|
||||
|
||||
# Example
|
||||
|
||||
```python
|
||||
# apply an atrous convolution 1d with atrous rate 2 of length 3 to a sequence with 10 timesteps,
|
||||
# with 64 output filters
|
||||
model = Sequential()
|
||||
model.add(AtrousConvolution1D(64, 3, atrous_rate=2, border_mode='same', input_shape=(10, 32)))
|
||||
# now model.output_shape == (None, 10, 64)
|
||||
|
||||
# add a new atrous conv1d on top
|
||||
model.add(AtrousConvolution1D(32, 3, atrous_rate=2, border_mode='same'))
|
||||
# now model.output_shape == (None, 10, 32)
|
||||
```
|
||||
|
||||
# Arguments
|
||||
nb_filter: Number of convolution kernels to use
|
||||
(dimensionality of the output).
|
||||
filter_length: The extension (spatial or temporal) of each filter.
|
||||
init: name of initialization function for the weights of the layer
|
||||
(see [initializations](../initializations.md)),
|
||||
or alternatively, Theano function to use for weights initialization.
|
||||
This parameter is only relevant if you don't pass a `weights` argument.
|
||||
activation: name of activation function to use
|
||||
(see [activations](../activations.md)),
|
||||
or alternatively, elementwise Theano function.
|
||||
If you don't specify anything, no activation is applied
|
||||
(ie. "linear" activation: a(x) = x).
|
||||
weights: list of numpy arrays to set as initial weights.
|
||||
border_mode: 'valid' or 'same'.
|
||||
subsample_length: factor by which to subsample output.
|
||||
atrous_rate: Factor for kernel dilation. Also called filter_dilation
|
||||
elsewhere.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the main weights matrix.
|
||||
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
|
||||
applied to the bias.
|
||||
activity_regularizer: instance of [ActivityRegularizer](../regularizers.md),
|
||||
applied to the network output.
|
||||
W_constraint: instance of the [constraints](../constraints.md) module
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
bias: whether to include a bias
|
||||
(i.e. make the layer affine rather than linear).
|
||||
input_dim: Number of channels/dimensions in the input.
|
||||
Either this argument or the keyword argument `input_shape`must be
|
||||
provided when using this layer as the first layer in a model.
|
||||
input_length: Length of input sequences, when it is constant.
|
||||
This argument is required if you are going to connect
|
||||
`Flatten` then `Dense` layers upstream
|
||||
(without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, input_dim)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape: `(samples, new_steps, nb_filter)`.
|
||||
`steps` value might have changed due to padding.
|
||||
'''
|
||||
def __init__(self, nb_filter, filter_length,
|
||||
init='uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample_length=1, atrous_rate=1,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for AtrousConv1D:', border_mode)
|
||||
|
||||
self.atrous_rate = int(atrous_rate)
|
||||
|
||||
super(AtrousConvolution1D, self).__init__(nb_filter, filter_length,
|
||||
init=init, activation=activation,
|
||||
weights=weights, border_mode=border_mode,
|
||||
subsample_length=subsample_length,
|
||||
W_regularizer=W_regularizer, b_regularizer=b_regularizer,
|
||||
activity_regularizer=activity_regularizer,
|
||||
W_constraint=W_constraint, b_constraint=b_constraint,
|
||||
bias=bias, **kwargs)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
length = conv_output_length(input_shape[1],
|
||||
self.filter_length,
|
||||
self.border_mode,
|
||||
self.subsample[0],
|
||||
dilation=self.atrous_rate)
|
||||
return (input_shape[0], length, self.nb_filter)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
x = K.expand_dims(x, 2) # add a dummy dimension
|
||||
output = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='tf',
|
||||
filter_dilation=(self.atrous_rate, self.atrous_rate))
|
||||
output = K.squeeze(output, 2) # remove the dummy dimension
|
||||
if self.bias:
|
||||
output += K.reshape(self.b, (1, 1, self.nb_filter))
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {'atrous_rate': self.atrous_rate}
|
||||
base_config = super(AtrousConvolution1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Convolution2D(Layer):
|
||||
'''Convolution operator for filtering windows of two-dimensional inputs.
|
||||
When using this layer as the first layer in a model,
|
||||
@@ -475,11 +588,12 @@ class Deconvolution2D(Convolution2D):
|
||||
def __init__(self, nb_filter, nb_row, nb_col, output_shape,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
dim_ordering=K.image_dim_ordering(),
|
||||
dim_ordering='default',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Deconvolution2D:', border_mode)
|
||||
|
||||
@@ -517,7 +631,7 @@ class Deconvolution2D(Convolution2D):
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
output = K.deconv2d(x, self.W, self.output_shape_,
|
||||
output = K.deconv2d(x, self.W, self.output_shape_,
|
||||
strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
@@ -721,8 +835,6 @@ class SeparableConvolution2D(Layer):
|
||||
Also called strides elsewhere.
|
||||
depth_multiplier: how many output channel to use per input channel
|
||||
for the depthwise convolution step.
|
||||
atrous_rate: tuple of length 2. Factor for kernel dilation.
|
||||
Also called filter_dilation elsewhere.
|
||||
depthwise_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the depthwise weights matrix.
|
||||
pointwise_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
@@ -1546,13 +1658,13 @@ class Cropping2D(Layer):
|
||||
def call(self, x, mask=None):
|
||||
input_shape = self.input_spec[0].shape
|
||||
if self.dim_ordering == 'th':
|
||||
return x[:,
|
||||
:,
|
||||
return x[:,
|
||||
:,
|
||||
self.cropping[0][0]:input_shape[2]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[3]-self.cropping[1][1]]
|
||||
elif self.dim_ordering == 'tf':
|
||||
return x[:,
|
||||
self.cropping[0][0]:input_shape[1]-self.cropping[0][1],
|
||||
return x[:,
|
||||
self.cropping[0][0]:input_shape[1]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[2]-self.cropping[1][1],
|
||||
:]
|
||||
|
||||
@@ -1626,16 +1738,16 @@ class Cropping3D(Layer):
|
||||
def call(self, x, mask=None):
|
||||
input_shape = self.input_spec[0].shape
|
||||
if self.dim_ordering == 'th':
|
||||
return x[:,
|
||||
:,
|
||||
self.cropping[0][0]:input_shape[2]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[3]-self.cropping[1][1],
|
||||
return x[:,
|
||||
:,
|
||||
self.cropping[0][0]:input_shape[2]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[3]-self.cropping[1][1],
|
||||
self.cropping[2][0]:input_shape[4]-self.cropping[2][1]]
|
||||
elif self.dim_ordering == 'tf':
|
||||
return x[:,
|
||||
self.cropping[0][0]:input_shape[1]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[2]-self.cropping[1][1],
|
||||
self.cropping[2][0]:input_shape[3]-self.cropping[2][1],
|
||||
return x[:,
|
||||
self.cropping[0][0]:input_shape[1]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[2]-self.cropping[1][1],
|
||||
self.cropping[2][0]:input_shape[3]-self.cropping[2][1],
|
||||
:]
|
||||
|
||||
def get_config(self):
|
||||
@@ -1650,5 +1762,6 @@ Conv1D = Convolution1D
|
||||
Conv2D = Convolution2D
|
||||
Conv3D = Convolution3D
|
||||
Deconv2D = Deconvolution2D
|
||||
AtrousConv1D = AtrousConvolution1D
|
||||
AtrousConv2D = AtrousConvolution2D
|
||||
SeparableConv2D = SeparableConvolution2D
|
||||
|
||||
+13
-21
@@ -7,14 +7,13 @@ import numpy as np
|
||||
import copy
|
||||
import inspect
|
||||
import types as python_types
|
||||
import marshal
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from .. import backend as K
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..engine import InputSpec, Layer, Merge
|
||||
from ..regularizers import ActivityRegularizer
|
||||
from ..utils.generic_utils import func_dump, func_load
|
||||
|
||||
|
||||
class Masking(Layer):
|
||||
@@ -484,16 +483,16 @@ class Lambda(Layer):
|
||||
|
||||
# Arguments
|
||||
function: The function to be evaluated.
|
||||
Takes one argument: the output of previous layer
|
||||
Takes input tensor as first argument.
|
||||
output_shape: Expected output shape from function.
|
||||
Can be a tuple or function.
|
||||
If a tuple, it only specifies the first dimension onward;
|
||||
If a tuple, it only specifies the first dimension onward;
|
||||
sample dimension is assumed either the same as the input:
|
||||
`output_shape = (input_shape[0], ) + output_shape`
|
||||
or, the input is `None` and the sample dimension is also `None`:
|
||||
`output_shape = (None, ) + output_shape`
|
||||
If a function, it specifies the entire shape as a function of
|
||||
the input shape: `output_shape = f(input_shape)`
|
||||
If a function, it specifies the entire shape as a function of the
|
||||
input shape: `output_shape = f(input_shape)`
|
||||
arguments: optional dictionary of keyword arguments to be passed
|
||||
to the function.
|
||||
|
||||
@@ -538,7 +537,10 @@ class Lambda(Layer):
|
||||
# otherwise, we default to the input shape
|
||||
return input_shape
|
||||
elif type(self._output_shape) in {tuple, list}:
|
||||
nb_samples = input_shape[0] if input_shape else None
|
||||
if type(input_shape) is list:
|
||||
nb_samples = input_shape[0][0]
|
||||
else:
|
||||
nb_samples = input_shape[0] if input_shape else None
|
||||
return (nb_samples,) + tuple(self._output_shape)
|
||||
else:
|
||||
shape = self._output_shape(input_shape)
|
||||
@@ -554,23 +556,15 @@ class Lambda(Layer):
|
||||
return self.function(x, **arguments)
|
||||
|
||||
def get_config(self):
|
||||
py3 = sys.version_info[0] == 3
|
||||
|
||||
if isinstance(self.function, python_types.LambdaType):
|
||||
if py3:
|
||||
function = marshal.dumps(self.function.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
function = marshal.dumps(self.function.func_code).decode('raw_unicode_escape')
|
||||
function = func_dump(self.function)
|
||||
function_type = 'lambda'
|
||||
else:
|
||||
function = self.function.__name__
|
||||
function_type = 'function'
|
||||
|
||||
if isinstance(self._output_shape, python_types.LambdaType):
|
||||
if py3:
|
||||
output_shape = marshal.dumps(self._output_shape.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
output_shape = marshal.dumps(self._output_shape.func_code).decode('raw_unicode_escape')
|
||||
output_shape = func_dump(self._output_shape)
|
||||
output_shape_type = 'lambda'
|
||||
elif callable(self._output_shape):
|
||||
output_shape = self._output_shape.__name__
|
||||
@@ -593,8 +587,7 @@ class Lambda(Layer):
|
||||
if function_type == 'function':
|
||||
function = globals()[config['function']]
|
||||
elif function_type == 'lambda':
|
||||
function = marshal.loads(config['function'].encode('raw_unicode_escape'))
|
||||
function = python_types.FunctionType(function, globals())
|
||||
function = func_load(config['function'], globs=globals())
|
||||
else:
|
||||
raise Exception('Unknown function type: ' + function_type)
|
||||
|
||||
@@ -602,8 +595,7 @@ class Lambda(Layer):
|
||||
if output_shape_type == 'function':
|
||||
output_shape = globals()[config['output_shape']]
|
||||
elif output_shape_type == 'lambda':
|
||||
output_shape = marshal.loads(config['output_shape'].encode('raw_unicode_escape'))
|
||||
output_shape = python_types.FunctionType(output_shape, globals())
|
||||
output_shape = func_load(config['output_shape'], globs=globals())
|
||||
else:
|
||||
output_shape = config['output_shape']
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ class LocallyConnected1D(Layer):
|
||||
model.add(LocallyConnected1D(32, 3))
|
||||
# now model.output_shape == (None, 6, 32)
|
||||
```
|
||||
|
||||
# Arguments
|
||||
nb_filter: Dimensionality of the output.
|
||||
filter_length: The extension (spatial or temporal) of each filter.
|
||||
@@ -65,8 +66,10 @@ class LocallyConnected1D(Layer):
|
||||
This argument is required if you are going to connect
|
||||
`Flatten` then `Dense` layers upstream
|
||||
(without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, input_dim)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape: `(samples, new_steps, nb_filter)`.
|
||||
`steps` value might have changed due to padding.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from ..engine import Layer, InputSpec
|
||||
from .. import initializations
|
||||
from .. import initializations, regularizers
|
||||
from .. import backend as K
|
||||
|
||||
|
||||
@@ -44,6 +44,10 @@ class BatchNormalization(Layer):
|
||||
[initializations](../initializations.md)), or alternatively,
|
||||
Theano/TensorFlow function to use for weights initialization.
|
||||
This parameter is only relevant if you don't pass a `weights` argument.
|
||||
gamma_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the gamma vector.
|
||||
beta_regularizer: instance of [WeightRegularizer](../regularizers.md),
|
||||
applied to the beta vector.
|
||||
|
||||
# Input shape
|
||||
Arbitrary. Use the keyword argument `input_shape`
|
||||
@@ -57,7 +61,8 @@ class BatchNormalization(Layer):
|
||||
- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](http://jmlr.org/proceedings/papers/v37/ioffe15.html)
|
||||
'''
|
||||
def __init__(self, epsilon=1e-5, mode=0, axis=-1, momentum=0.99,
|
||||
weights=None, beta_init='zero', gamma_init='one', **kwargs):
|
||||
weights=None, beta_init='zero', gamma_init='one',
|
||||
gamma_regularizer=None, beta_regularizer=None, **kwargs):
|
||||
self.supports_masking = True
|
||||
self.beta_init = initializations.get(beta_init)
|
||||
self.gamma_init = initializations.get(gamma_init)
|
||||
@@ -65,6 +70,8 @@ class BatchNormalization(Layer):
|
||||
self.mode = mode
|
||||
self.axis = axis
|
||||
self.momentum = momentum
|
||||
self.gamma_regularizer = regularizers.get(gamma_regularizer)
|
||||
self.beta_regularizer = regularizers.get(beta_regularizer)
|
||||
self.initial_weights = weights
|
||||
if self.mode == 0:
|
||||
self.uses_learning_phase = True
|
||||
@@ -78,6 +85,15 @@ class BatchNormalization(Layer):
|
||||
self.beta = self.beta_init(shape, name='{}_beta'.format(self.name))
|
||||
self.trainable_weights = [self.gamma, self.beta]
|
||||
|
||||
self.regularizers = []
|
||||
if self.gamma_regularizer:
|
||||
self.gamma_regularizer.set_param(self.gamma)
|
||||
self.regularizers.append(self.gamma_regularizer)
|
||||
|
||||
if self.beta_regularizer:
|
||||
self.beta_regularizer.set_param(self.beta)
|
||||
self.regularizers.append(self.beta_regularizer)
|
||||
|
||||
self.running_mean = K.zeros(shape,
|
||||
name='{}_running_mean'.format(self.name))
|
||||
self.running_std = K.ones(shape,
|
||||
@@ -124,7 +140,7 @@ class BatchNormalization(Layer):
|
||||
self.updates = [K.moving_average_update(self.running_mean, mean, self.momentum),
|
||||
K.moving_average_update(self.running_std, std, self.momentum)]
|
||||
|
||||
if sorted(reduction_axes) == range(K.ndim(x))[:-1]:
|
||||
if K.backend() == 'tensorflow' and sorted(reduction_axes) == range(K.ndim(x))[:-1]:
|
||||
x_normed_running = K.batch_normalization(
|
||||
x, self.running_mean, self.running_std,
|
||||
self.beta, self.gamma,
|
||||
@@ -155,6 +171,8 @@ class BatchNormalization(Layer):
|
||||
config = {"epsilon": self.epsilon,
|
||||
"mode": self.mode,
|
||||
"axis": self.axis,
|
||||
"gamma_regularizer": self.gamma_regularizer.get_config() if self.gamma_regularizer else None,
|
||||
"beta_regularizer": self.beta_regularizer.get_config() if self.beta_regularizer else None,
|
||||
"momentum": self.momentum}
|
||||
base_config = super(BatchNormalization, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -398,3 +398,125 @@ class AveragePooling3D(_Pooling3D):
|
||||
output = K.pool3d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='avg')
|
||||
return output
|
||||
|
||||
|
||||
class _GlobalPooling1D(Layer):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(_GlobalPooling1D, self).__init__(**kwargs)
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
return (input_shape[0], input_shape[2])
|
||||
|
||||
def call(self, x, mask=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class GlobalAveragePooling1D(_GlobalPooling1D):
|
||||
'''Global average pooling operation for temporal data.
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape: `(samples, features)`.
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
return K.mean(x, axis=1)
|
||||
|
||||
|
||||
class GlobalMaxPooling1D(_GlobalPooling1D):
|
||||
'''Global max pooling operation for temporal data.
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape: `(samples, features)`.
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
return K.max(x, axis=1)
|
||||
|
||||
|
||||
class _GlobalPooling2D(Layer):
|
||||
|
||||
def __init__(self, dim_ordering='default', **kwargs):
|
||||
super(_GlobalPooling2D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
print(dim_ordering)
|
||||
self.dim_ordering = dim_ordering
|
||||
self.input_spec = [InputSpec(ndim=4)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'tf':
|
||||
return (input_shape[0], input_shape[3])
|
||||
else:
|
||||
return (input_shape[0], input_shape[1])
|
||||
|
||||
def call(self, x, mask=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_config(self):
|
||||
config = {'dim_ordering': self.dim_ordering}
|
||||
base_config = super(_GlobalPooling2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class GlobalAveragePooling2D(_GlobalPooling2D):
|
||||
'''Global average pooling operation for spatial data.
|
||||
|
||||
# Arguments
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
`(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape:
|
||||
`(nb_samples, channels)`
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if self.dim_ordering == 'tf':
|
||||
return K.mean(x, axis=[1, 2])
|
||||
else:
|
||||
return K.mean(x, axis=[2, 3])
|
||||
|
||||
|
||||
class GlobalMaxPooling2D(_GlobalPooling2D):
|
||||
'''Global max pooling operation for spatial data.
|
||||
|
||||
# Arguments
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
`(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape:
|
||||
`(nb_samples, channels)`
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if self.dim_ordering == 'tf':
|
||||
return K.max(x, axis=[1, 2])
|
||||
else:
|
||||
return K.max(x, axis=[2, 3])
|
||||
|
||||
@@ -31,9 +31,11 @@ def time_distributed_dense(x, w, b=None, dropout=None,
|
||||
if b:
|
||||
x = x + b
|
||||
# reshape to 3D tensor
|
||||
x = K.reshape(x, K.pack([-1, timesteps, output_dim]))
|
||||
if K.backend() == 'tensorflow':
|
||||
x = K.reshape(x, K.pack([-1, timesteps, output_dim]))
|
||||
x.set_shape([None, None, output_dim])
|
||||
else:
|
||||
x = K.reshape(x, (-1, timesteps, output_dim))
|
||||
return x
|
||||
|
||||
|
||||
|
||||
+20
-19
@@ -20,6 +20,13 @@ class Wrapper(Layer):
|
||||
self.regularizers = getattr(self.layer, 'regularizers', [])
|
||||
self.constraints = getattr(self.layer, 'constraints', {})
|
||||
|
||||
# properly attribute the current layer to
|
||||
# regularizers that need access to it
|
||||
# (e.g. ActivityRegularizer).
|
||||
for regularizer in self.regularizers:
|
||||
if hasattr(regularizer, 'set_layer'):
|
||||
regularizer.set_layer(self)
|
||||
|
||||
def get_weights(self):
|
||||
weights = self.layer.get_weights()
|
||||
return weights
|
||||
@@ -86,17 +93,6 @@ class TimeDistributed(Wrapper):
|
||||
def build(self, input_shape):
|
||||
assert len(input_shape) >= 3
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
if K._BACKEND == 'tensorflow':
|
||||
if not input_shape[1]:
|
||||
raise Exception('When using TensorFlow, you should define '
|
||||
'explicitly the number of timesteps of '
|
||||
'your sequences.\n'
|
||||
'If your first layer is an Embedding, '
|
||||
'make sure to pass it an "input_length" '
|
||||
'argument. Otherwise, make sure '
|
||||
'the first layer has '
|
||||
'an "input_shape" or "batch_input_shape" '
|
||||
'argument, including the time axis.')
|
||||
child_input_shape = (input_shape[0],) + input_shape[2:]
|
||||
if not self.layer.built:
|
||||
self.layer.build(child_input_shape)
|
||||
@@ -136,20 +132,25 @@ class TimeDistributed(Wrapper):
|
||||
|
||||
|
||||
class Bidirectional(Wrapper):
|
||||
''' Bidirectional wrapper for RNNs
|
||||
''' Bidirectional wrapper for RNNs.
|
||||
|
||||
# Arguments:
|
||||
layer: `Recurrent` instance.
|
||||
merge_mode: Mode by which outputs of the forward and backward RNNs will be combined. One of {'sum', 'mul', 'concat', 'ave', None}. If None, the outputs will not be combined, they will be returned as a list.
|
||||
merge_mode: Mode by which outputs of the
|
||||
forward and backward RNNs will be combined.
|
||||
One of {'sum', 'mul', 'concat', 'ave', None}.
|
||||
If None, the outputs will not be combined,
|
||||
they will be returned as a list.
|
||||
|
||||
# Examples:
|
||||
|
||||
```python
|
||||
model = Sequential()
|
||||
model.add(Bidirectional(LSTM(10, return_sequences=True), input_shape=(5, 10)))
|
||||
model.add(Bidirectional(LSTM(10)))
|
||||
model.add(Dense(5))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
model = Sequential()
|
||||
model.add(Bidirectional(LSTM(10, return_sequences=True), input_shape=(5, 10)))
|
||||
model.add(Bidirectional(LSTM(10)))
|
||||
model.add(Dense(5))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
```
|
||||
'''
|
||||
def __init__(self, layer, merge_mode='concat', weights=None, **kwargs):
|
||||
|
||||
@@ -71,6 +71,26 @@ def cosine_proximity(y_true, y_pred):
|
||||
return -K.mean(y_true * y_pred)
|
||||
|
||||
|
||||
def matthews_correlation(y_true, y_pred):
|
||||
''' Matthews correlation coefficient
|
||||
'''
|
||||
y_pred_pos = K.round(K.clip(y_pred, 0, 1))
|
||||
y_pred_neg = 1 - y_pred_pos
|
||||
|
||||
y_pos = K.round(K.clip(y_true, 0, 1))
|
||||
y_neg = 1 - y_pos
|
||||
|
||||
tp = K.sum(y_pos * y_pred_pos)
|
||||
tn = K.sum(y_neg * y_pred_neg)
|
||||
|
||||
fp = K.sum(1 - y_neg * y_pred_pos)
|
||||
fn = K.sum(1 - y_pos * y_pred_neg)
|
||||
|
||||
numerator = (tp * tn - fp * fn)
|
||||
denominator = K.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))
|
||||
|
||||
return numerator / (denominator + K.epsilon())
|
||||
|
||||
# aliases
|
||||
mse = MSE = mean_squared_error
|
||||
mae = MAE = mean_absolute_error
|
||||
|
||||
+1
-1
@@ -877,7 +877,7 @@ class Sequential(Model):
|
||||
'''Evaluates the model on a data generator. The generator should
|
||||
return the same kind of data as accepted by `test_on_batch`.
|
||||
|
||||
Arguments:
|
||||
# Arguments
|
||||
generator:
|
||||
generator yielding tuples (inputs, targets)
|
||||
or (inputs, targets, sample_weights)
|
||||
|
||||
+55
-11
@@ -135,11 +135,16 @@ class SGD(Optimizer):
|
||||
self.lr = K.variable(lr)
|
||||
self.momentum = K.variable(momentum)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
lr = self.lr * (1. / (1. + self.decay * self.iterations))
|
||||
self.updates = [K.update_add(self.iterations, 1)]
|
||||
self.updates = []
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates .append(K.update_add(self.iterations, 1))
|
||||
|
||||
# momentum
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
@@ -185,12 +190,17 @@ class RMSprop(Optimizer):
|
||||
lr: float >= 0. Learning rate.
|
||||
rho: float >= 0.
|
||||
epsilon: float >= 0. Fuzz factor.
|
||||
decay: float >= 0. Learning rate decay over each update.
|
||||
'''
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, **kwargs):
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, decay=0.,
|
||||
**kwargs):
|
||||
super(RMSprop, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
self.rho = K.variable(rho)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
self.iterations = K.variable(0.)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
@@ -199,11 +209,16 @@ class RMSprop(Optimizer):
|
||||
self.weights = accumulators
|
||||
self.updates = []
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates.append(K.update_add(self.iterations, 1))
|
||||
|
||||
for p, g, a in zip(params, grads, accumulators):
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1. - self.rho) * K.square(g)
|
||||
self.updates.append(K.update(a, new_a))
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
new_p = p - lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
@@ -233,10 +248,13 @@ class Adagrad(Optimizer):
|
||||
# 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, **kwargs):
|
||||
def __init__(self, lr=0.01, epsilon=1e-8, decay=0., **kwargs):
|
||||
super(Adagrad, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
self.iterations = K.variable(0.)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
@@ -245,10 +263,15 @@ class Adagrad(Optimizer):
|
||||
self.weights = accumulators
|
||||
self.updates = []
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates.append(K.update_add(self.iterations, 1))
|
||||
|
||||
for p, g, a in zip(params, grads, accumulators):
|
||||
new_a = a + K.square(g) # update accumulator
|
||||
self.updates.append(K.update(a, new_a))
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
new_p = p - lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
@@ -278,10 +301,14 @@ class Adadelta(Optimizer):
|
||||
# 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, **kwargs):
|
||||
def __init__(self, lr=1.0, rho=0.95, epsilon=1e-8, decay=0.,
|
||||
**kwargs):
|
||||
super(Adadelta, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
self.iterations = K.variable(0.)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
@@ -291,6 +318,11 @@ class Adadelta(Optimizer):
|
||||
self.weights = accumulators + delta_accumulators
|
||||
self.updates = []
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates.append(K.update_add(self.iterations, 1))
|
||||
|
||||
for p, g, a, d_a in zip(params, grads, accumulators, delta_accumulators):
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1. - self.rho) * K.square(g)
|
||||
@@ -299,7 +331,7 @@ class Adadelta(Optimizer):
|
||||
# use the new accumulator and the *old* delta_accumulator
|
||||
update = g * K.sqrt(d_a + self.epsilon) / K.sqrt(new_a + self.epsilon)
|
||||
|
||||
new_p = p - self.lr * update
|
||||
new_p = p - lr * update
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
@@ -333,20 +365,26 @@ class Adam(Optimizer):
|
||||
- [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, **kwargs):
|
||||
epsilon=1e-8, decay=0., **kwargs):
|
||||
super(Adam, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0)
|
||||
self.lr = K.variable(lr)
|
||||
self.beta_1 = K.variable(beta_1)
|
||||
self.beta_2 = K.variable(beta_2)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [K.update_add(self.iterations, 1)]
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
|
||||
t = self.iterations + 1
|
||||
lr_t = self.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))
|
||||
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
ms = [K.zeros(shape) for shape in shapes]
|
||||
@@ -393,18 +431,24 @@ class Adamax(Optimizer):
|
||||
- [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, **kwargs):
|
||||
epsilon=1e-8, decay=0., **kwargs):
|
||||
super(Adamax, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
self.lr = K.variable(lr)
|
||||
self.beta_1 = K.variable(beta_1)
|
||||
self.beta_2 = K.variable(beta_2)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [K.update_add(self.iterations, 1)]
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
|
||||
t = self.iterations + 1
|
||||
lr_t = self.lr / (1. - K.pow(self.beta_1, t))
|
||||
|
||||
|
||||
@@ -161,6 +161,14 @@ def img_to_array(img, dim_ordering='default'):
|
||||
|
||||
|
||||
def load_img(path, grayscale=False, target_size=None):
|
||||
'''Load an image into PIL format.
|
||||
|
||||
# Arguments
|
||||
path: path to image file
|
||||
grayscale: boolean
|
||||
target_size: None (default to original size)
|
||||
or (img_height, img_width)
|
||||
'''
|
||||
from PIL import Image
|
||||
img = Image.open(path)
|
||||
if grayscale:
|
||||
|
||||
@@ -138,7 +138,7 @@ def skipgrams(sequence, vocabulary_size,
|
||||
continue
|
||||
couples.append([wi, wj])
|
||||
if categorical:
|
||||
labels.append([0,1])
|
||||
labels.append([0, 1])
|
||||
else:
|
||||
labels.append(1)
|
||||
|
||||
@@ -149,12 +149,12 @@ def skipgrams(sequence, vocabulary_size,
|
||||
|
||||
couples += [[words[i %len(words)], random.randint(1, vocabulary_size-1)] for i in range(nb_negative_samples)]
|
||||
if categorical:
|
||||
labels += [[1,0]]*nb_negative_samples
|
||||
labels += [[1, 0]]*nb_negative_samples
|
||||
else:
|
||||
labels += [0]*nb_negative_samples
|
||||
|
||||
if shuffle:
|
||||
seed = random.randint(0,10e6)
|
||||
seed = random.randint(0, 10e6)
|
||||
random.seed(seed)
|
||||
random.shuffle(couples)
|
||||
random.seed(seed)
|
||||
|
||||
+20
-5
@@ -1,8 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from . import backend as K
|
||||
from .utils.generic_utils import get_from_module
|
||||
|
||||
|
||||
class Regularizer(object):
|
||||
|
||||
def set_param(self, p):
|
||||
self.p = p
|
||||
|
||||
@@ -29,6 +31,9 @@ class EigenvalueRegularizer(Regularizer):
|
||||
self.uses_learning_phase = True
|
||||
|
||||
def set_param(self, p):
|
||||
if hasattr(self, 'p'):
|
||||
raise Exception('Regularizers cannot be reused. '
|
||||
'Instantiate one regularizer per layer.')
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
@@ -50,23 +55,30 @@ class EigenvalueRegularizer(Regularizer):
|
||||
WWd = K.dot(WW, main_eigenvect)
|
||||
|
||||
# the corresponding dominant eigenvalue:
|
||||
main_eigenval = K.dot(K.transpose(WWd), main_eigenvect) / K.dot(K.transpose(main_eigenvect), main_eigenvect)
|
||||
regularized_loss = loss + (main_eigenval ** 0.5) * self.k # multiplied by the given regularization gain
|
||||
main_eigenval = (K.dot(K.transpose(WWd), main_eigenvect) /
|
||||
K.dot(K.transpose(main_eigenvect), main_eigenvect))
|
||||
# multiplied by the given regularization gain
|
||||
regularized_loss = loss + (main_eigenval ** 0.5) * self.k
|
||||
|
||||
return K.in_train_phase(regularized_loss[0, 0], loss)
|
||||
|
||||
|
||||
class WeightRegularizer(Regularizer):
|
||||
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
self.l1 = K.cast_to_floatx(l1)
|
||||
self.l2 = K.cast_to_floatx(l2)
|
||||
self.uses_learning_phase = True
|
||||
self.p = None
|
||||
|
||||
def set_param(self, p):
|
||||
if self.p is not None:
|
||||
raise Exception('Regularizers cannot be reused. '
|
||||
'Instantiate one regularizer per layer.')
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
if not hasattr(self, 'p'):
|
||||
if self.p is None:
|
||||
raise Exception('Need to call `set_param` on '
|
||||
'WeightRegularizer instance '
|
||||
'before calling the instance. '
|
||||
@@ -89,16 +101,20 @@ class WeightRegularizer(Regularizer):
|
||||
|
||||
|
||||
class ActivityRegularizer(Regularizer):
|
||||
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
self.l1 = K.cast_to_floatx(l1)
|
||||
self.l2 = K.cast_to_floatx(l2)
|
||||
self.uses_learning_phase = True
|
||||
self.layer = None
|
||||
|
||||
def set_layer(self, layer):
|
||||
if self.layer is not None:
|
||||
raise Exception('Regularizers cannot be reused')
|
||||
self.layer = layer
|
||||
|
||||
def __call__(self, loss):
|
||||
if not hasattr(self, 'layer'):
|
||||
if self.layer is None:
|
||||
raise Exception('Need to call `set_layer` on '
|
||||
'ActivityRegularizer instance '
|
||||
'before calling the instance.')
|
||||
@@ -141,7 +157,6 @@ def activity_l1l2(l1=0.01, l2=0.01):
|
||||
return ActivityRegularizer(l1=l1, l2=l2)
|
||||
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'regularizer',
|
||||
instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -65,7 +65,7 @@ def get_file(fname, origin, untar=False,
|
||||
download = True
|
||||
|
||||
if download:
|
||||
print('Downloading data from', origin)
|
||||
print('Downloading data from', origin)
|
||||
global progbar
|
||||
progbar = None
|
||||
|
||||
|
||||
@@ -3,6 +3,8 @@ import numpy as np
|
||||
import time
|
||||
import sys
|
||||
import six
|
||||
import marshal
|
||||
import types as python_types
|
||||
|
||||
|
||||
def get_from_module(identifier, module_params, module_name,
|
||||
@@ -33,6 +35,43 @@ def make_tuple(*args):
|
||||
return args
|
||||
|
||||
|
||||
def func_dump(func):
|
||||
'''Serialize user defined function.'''
|
||||
code = marshal.dumps(func.__code__).decode('raw_unicode_escape')
|
||||
defaults = func.__defaults__
|
||||
if func.__closure__:
|
||||
closure = tuple(c.cell_contents for c in func.__closure__)
|
||||
else:
|
||||
closure = None
|
||||
return code, defaults, closure
|
||||
|
||||
|
||||
def func_load(code, defaults=None, closure=None, globs=None):
|
||||
'''Deserialize user defined function.'''
|
||||
if isinstance(code, (tuple, list)): # unpack previous dump
|
||||
code, defaults, closure = code
|
||||
code = marshal.loads(code.encode('raw_unicode_escape'))
|
||||
if closure is not None:
|
||||
closure = func_reconstruct_closure(closure)
|
||||
if globs is None:
|
||||
globs = globals()
|
||||
return python_types.FunctionType(code, globs, name=code.co_name, argdefs=defaults, closure=closure)
|
||||
|
||||
|
||||
def func_reconstruct_closure(values):
|
||||
'''Deserialization helper that reconstructs a closure.'''
|
||||
nums = range(len(values))
|
||||
src = ["def func(arg):"]
|
||||
src += [" _%d = arg[%d]" % (n, n) for n in nums]
|
||||
src += [" return lambda:(%s)" % ','.join(["_%d" % n for n in nums]), ""]
|
||||
src = '\n'.join(src)
|
||||
try:
|
||||
exec(src)
|
||||
except:
|
||||
raise SyntaxError(src)
|
||||
return func(values).__closure__
|
||||
|
||||
|
||||
class Progbar(object):
|
||||
def __init__(self, target, width=30, verbose=1, interval=0.01):
|
||||
'''
|
||||
|
||||
@@ -13,26 +13,20 @@ norecursedirs= build
|
||||
# E251 unexpected spaces around keyword / parameter equals
|
||||
# E225 missing whitespace around operator
|
||||
# E226 missing whitespace around arithmetic operator
|
||||
# W291 trailing whitespace
|
||||
# W293 blank line contains whitespace
|
||||
# E501 line too long (82 > 79 characters)
|
||||
# E402 module level import not at top of file - temporary measure to coninue adding ros python packaged in sys.path
|
||||
# E731 do not assign a lambda expression, use a def
|
||||
# E302 two blank lines between the functions
|
||||
# E231 missing whitespace after ,
|
||||
# E241 multiple spaces after ','
|
||||
# E261 at least two spaces before inline comment
|
||||
|
||||
|
||||
pep8ignore=* E251 \
|
||||
* E225 \
|
||||
* E226 \
|
||||
* W291 \
|
||||
* W293 \
|
||||
* E501 \
|
||||
* E402 \
|
||||
* E731 \
|
||||
* E302 \
|
||||
* E231 \
|
||||
* E241 \
|
||||
* E261
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@ from setuptools import find_packages
|
||||
|
||||
|
||||
setup(name='Keras',
|
||||
version='1.0.8',
|
||||
version='1.1.0',
|
||||
description='Deep Learning for Python',
|
||||
author='Francois Chollet',
|
||||
author_email='francois.chollet@gmail.com',
|
||||
url='https://github.com/fchollet/keras',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.0.8',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.1.0',
|
||||
license='MIT',
|
||||
install_requires=['theano', 'pyyaml', 'six'],
|
||||
extras_require={
|
||||
|
||||
@@ -16,7 +16,7 @@ def test_image_classification():
|
||||
with convolutional hidden layer.
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
input_shape = (3, 16, 16)
|
||||
input_shape = (16, 16, 3)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=200,
|
||||
input_shape=input_shape,
|
||||
|
||||
@@ -2,6 +2,7 @@ import sys
|
||||
import pytest
|
||||
from numpy.testing import assert_allclose
|
||||
import numpy as np
|
||||
import scipy.sparse as sparse
|
||||
|
||||
from keras.backend import theano_backend as KTH
|
||||
from keras.backend import tensorflow_backend as KTF
|
||||
@@ -429,6 +430,50 @@ class TestBackend(object):
|
||||
assert_allclose(unrolled_masked_th_outputs, masked_th_outputs, atol=1e-04)
|
||||
assert_allclose(unrolled_masked_th_state, masked_th_state, atol=1e-04)
|
||||
|
||||
def test_rnn_no_states(self):
|
||||
# implement a simple RNN without states
|
||||
input_dim = 8
|
||||
output_dim = 4
|
||||
timesteps = 5
|
||||
|
||||
input_val = np.random.random((32, timesteps, input_dim))
|
||||
W_i_val = np.random.random((input_dim, output_dim))
|
||||
|
||||
def rnn_step_fn(input_dim, output_dim, K):
|
||||
W_i = K.variable(W_i_val)
|
||||
|
||||
def step_function(x, states):
|
||||
assert len(states) == 0
|
||||
output = K.dot(x, W_i)
|
||||
return output, []
|
||||
return step_function
|
||||
|
||||
# test default setup
|
||||
th_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTH)
|
||||
th_inputs = KTH.variable(input_val)
|
||||
th_initial_states = []
|
||||
last_output, outputs, new_states = KTH.rnn(th_rnn_step_fn, th_inputs,
|
||||
th_initial_states,
|
||||
go_backwards=False,
|
||||
mask=None)
|
||||
th_last_output = KTH.eval(last_output)
|
||||
th_outputs = KTH.eval(outputs)
|
||||
assert len(new_states) == 0
|
||||
|
||||
tf_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTF)
|
||||
tf_inputs = KTF.variable(input_val)
|
||||
tf_initial_states = []
|
||||
last_output, outputs, new_states = KTF.rnn(tf_rnn_step_fn, tf_inputs,
|
||||
tf_initial_states,
|
||||
go_backwards=False,
|
||||
mask=None)
|
||||
tf_last_output = KTF.eval(last_output)
|
||||
tf_outputs = KTF.eval(outputs)
|
||||
assert len(new_states) == 0
|
||||
|
||||
assert_allclose(tf_last_output, th_last_output, atol=1e-04)
|
||||
assert_allclose(tf_outputs, th_outputs, atol=1e-04)
|
||||
|
||||
def test_switch(self):
|
||||
val = np.random.random()
|
||||
xth = KTH.variable(val)
|
||||
@@ -486,8 +531,8 @@ class TestBackend(object):
|
||||
kernel_th = KTH.variable(convert_kernel(kernel_val))
|
||||
kernel_tf = KTF.variable(kernel_val)
|
||||
|
||||
zth = KTH.eval(KTH.conv2d(xth, kernel_th))
|
||||
ztf = KTF.eval(KTF.conv2d(xtf, kernel_tf))
|
||||
zth = KTH.eval(KTH.conv2d(xth, kernel_th, dim_ordering='th'))
|
||||
ztf = KTF.eval(KTF.conv2d(xtf, kernel_tf, dim_ordering='th'))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
@@ -530,8 +575,8 @@ class TestBackend(object):
|
||||
kernel_th = KTH.variable(convert_kernel(kernel_val))
|
||||
kernel_tf = KTF.variable(kernel_val)
|
||||
|
||||
zth = KTH.eval(KTH.conv3d(xth, kernel_th))
|
||||
ztf = KTF.eval(KTF.conv3d(xtf, kernel_tf))
|
||||
zth = KTH.eval(KTH.conv3d(xth, kernel_th, dim_ordering='th'))
|
||||
ztf = KTF.eval(KTF.conv3d(xtf, kernel_tf, dim_ordering='th'))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
@@ -557,23 +602,23 @@ class TestBackend(object):
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
def test_pool2d(self):
|
||||
check_single_tensor_operation('pool2d', (5, 3, 10, 12), pool_size=(2, 2),
|
||||
check_single_tensor_operation('pool2d', (5, 10, 12, 3), pool_size=(2, 2),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool2d', (5, 3, 9, 11), pool_size=(2, 2),
|
||||
check_single_tensor_operation('pool2d', (5, 9, 11, 3), pool_size=(2, 2),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool2d', (5, 3, 9, 11), pool_size=(2, 3),
|
||||
check_single_tensor_operation('pool2d', (5, 9, 11, 3), pool_size=(2, 3),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
|
||||
def test_pool3d(self):
|
||||
check_single_tensor_operation('pool3d', (5, 3, 10, 12, 5), pool_size=(2, 2, 2),
|
||||
check_single_tensor_operation('pool3d', (5, 10, 12, 5, 3), pool_size=(2, 2, 2),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool3d', (5, 3, 9, 11, 5), pool_size=(2, 2, 2),
|
||||
check_single_tensor_operation('pool3d', (5, 9, 11, 5, 3), pool_size=(2, 2, 2),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool3d', (5, 3, 9, 11, 5), pool_size=(2, 3, 2),
|
||||
check_single_tensor_operation('pool3d', (5, 9, 11, 5, 3), pool_size=(2, 3, 2),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
def test_random_normal(self):
|
||||
@@ -660,6 +705,116 @@ class TestBackend(object):
|
||||
res = KTH.eval(KTH.ctc_batch_cost(labels_th, inputs_th, input_lens_th, label_lens_th))
|
||||
assert_allclose(res[0, :], loss_log_probs_th, atol=1e-05)
|
||||
|
||||
def test_ctc_decode_greedy(self):
|
||||
# Test adapted from tensorflow
|
||||
"""Test two batch entries - best path decoder."""
|
||||
max_time_steps = 6
|
||||
|
||||
seq_len_0 = 4
|
||||
input_prob_matrix_0 = np.asarray(
|
||||
[[1.0, 0.0, 0.0, 0.0], # t=0
|
||||
[0.0, 0.0, 0.4, 0.6], # t=1
|
||||
[0.0, 0.0, 0.4, 0.6], # t=2
|
||||
[0.0, 0.9, 0.1, 0.0], # t=3
|
||||
[0.0, 0.0, 0.0, 0.0], # t=4 (ignored)
|
||||
[0.0, 0.0, 0.0, 0.0]], # t=5 (ignored)
|
||||
dtype=np.float32)
|
||||
input_log_prob_matrix_0 = np.log(input_prob_matrix_0)
|
||||
|
||||
seq_len_1 = 5
|
||||
# dimensions are time x depth
|
||||
|
||||
input_prob_matrix_1 = np.asarray(
|
||||
[[0.1, 0.9, 0.0, 0.0], # t=0
|
||||
[0.0, 0.9, 0.1, 0.0], # t=1
|
||||
[0.0, 0.0, 0.1, 0.9], # t=2
|
||||
[0.0, 0.9, 0.1, 0.1], # t=3
|
||||
[0.9, 0.1, 0.0, 0.0], # t=4
|
||||
[0.0, 0.0, 0.0, 0.0]], # t=5 (ignored)
|
||||
dtype=np.float32)
|
||||
|
||||
# len max_time_steps array of batch_size x depth matrices
|
||||
inputs = [np.vstack([input_prob_matrix_0[t, :],
|
||||
input_prob_matrix_1[t, :]])
|
||||
for t in range(max_time_steps)]
|
||||
|
||||
# change tensorflow order to keras backend order
|
||||
inputs = KTF.variable(np.asarray(inputs).transpose((1, 0, 2)))
|
||||
# batch_size length vector of sequence_lengths
|
||||
input_length = KTF.variable(np.array([seq_len_0, seq_len_1], dtype=np.int32))
|
||||
|
||||
# batch_size length vector of negative log probabilities
|
||||
log_prob_truth = np.array([
|
||||
np.sum(-np.log([1.0, 0.6, 0.6, 0.9])),
|
||||
np.sum(-np.log([0.9, 0.9, 0.9, 0.9, 0.9]))
|
||||
], np.float32)[:, np.newaxis]
|
||||
|
||||
# keras output, unlike tensorflow, is a dense (not sparse) tensor
|
||||
decode_truth = np.array([[0, 1, -1], [1, 1, 0]])
|
||||
|
||||
decode_pred_tf, log_prob_pred_tf = KTF.ctc_decode(inputs,
|
||||
input_length,
|
||||
greedy=True)
|
||||
|
||||
assert len(decode_pred_tf) == 1
|
||||
|
||||
decode_pred = KTF.eval(decode_pred_tf[0])
|
||||
log_prob_pred = KTF.eval(log_prob_pred_tf)
|
||||
|
||||
assert np.alltrue(decode_truth == decode_pred)
|
||||
assert np.allclose(log_prob_truth, log_prob_pred)
|
||||
|
||||
def test_ctc_decode_beam_search(self):
|
||||
"""Test one batch, two beams - hibernating beam search."""
|
||||
|
||||
depth = 6
|
||||
|
||||
seq_len_0 = 5
|
||||
input_prob_matrix_0 = np.asarray(
|
||||
[[0.30999, 0.309938, 0.0679938, 0.0673362, 0.0708352, 0.173908],
|
||||
[0.215136, 0.439699, 0.0370931, 0.0393967, 0.0381581, 0.230517],
|
||||
[0.199959, 0.489485, 0.0233221, 0.0251417, 0.0233289, 0.238763],
|
||||
[0.279611, 0.452966, 0.0204795, 0.0209126, 0.0194803, 0.20655],
|
||||
[0.51286, 0.288951, 0.0243026, 0.0220788, 0.0219297, 0.129878],
|
||||
# Random entry added in at time=5
|
||||
[0.155251, 0.164444, 0.173517, 0.176138, 0.169979, 0.160671]],
|
||||
dtype=np.float32)
|
||||
|
||||
# len max_time_steps array of batch_size x depth matrices
|
||||
inputs = ([input_prob_matrix_0[t, :][np.newaxis, :]
|
||||
for t in range(seq_len_0)] + # Pad to max_time_steps = 8
|
||||
2 * [np.zeros((1, depth), dtype=np.float32)])
|
||||
|
||||
inputs = KTF.variable(np.asarray(inputs).transpose((1, 0, 2)))
|
||||
|
||||
# batch_size length vector of sequence_lengths
|
||||
input_length = KTF.variable(np.array([seq_len_0], dtype=np.int32))
|
||||
# batch_size length vector of negative log probabilities
|
||||
log_prob_truth = np.array([
|
||||
0.584855, # output beam 0
|
||||
0.389139 # output beam 1
|
||||
], np.float32)[np.newaxis, :]
|
||||
|
||||
decode_truth = [np.array([1, 0]), np.array([0, 1, 0])]
|
||||
|
||||
beam_width = 2
|
||||
top_paths = 2
|
||||
|
||||
decode_pred_tf, log_prob_pred_tf = KTF.ctc_decode(inputs,
|
||||
input_length,
|
||||
greedy=False,
|
||||
beam_width=beam_width,
|
||||
top_paths=top_paths)
|
||||
|
||||
assert len(decode_pred_tf) == top_paths
|
||||
|
||||
log_prob_pred = KTF.eval(log_prob_pred_tf)
|
||||
|
||||
for i in range(top_paths):
|
||||
assert np.alltrue(decode_truth[i] == KTF.eval(decode_pred_tf[i]))
|
||||
|
||||
assert np.allclose(log_prob_truth, log_prob_pred)
|
||||
|
||||
def test_one_hot(self):
|
||||
input_length = 10
|
||||
nb_classes = 20
|
||||
@@ -670,6 +825,61 @@ class TestBackend(object):
|
||||
koh = K.eval(K.one_hot(K.variable(indices, dtype='int32'), nb_classes))
|
||||
assert np.all(koh == oh)
|
||||
|
||||
def test_sparse_dot(self):
|
||||
x_d = np.array([0, 7, 2, 3], dtype=np.float32)
|
||||
x_r = np.array([0, 2, 2, 3], dtype=np.int64)
|
||||
x_c = np.array([4, 3, 2, 3], dtype=np.int64)
|
||||
|
||||
x_sparse = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5))
|
||||
x_dense = x_sparse.toarray()
|
||||
|
||||
W = np.random.random((5, 4))
|
||||
|
||||
backends = [KTF]
|
||||
if KTH.th_sparse_module:
|
||||
# Theano has some dependency issues for sparse
|
||||
backends.append(KTH)
|
||||
|
||||
for K in backends:
|
||||
t_W = K.variable(W)
|
||||
k_s = K.eval(K.dot(K.variable(x_sparse), t_W))
|
||||
k_d = K.eval(K.dot(K.variable(x_dense), t_W))
|
||||
|
||||
assert k_s.shape == k_d.shape
|
||||
assert_allclose(k_s, k_d, atol=1e-05)
|
||||
|
||||
def test_sparse_concat(self):
|
||||
x_d = np.array([0, 7, 2, 3], dtype=np.float32)
|
||||
x_r = np.array([0, 2, 2, 3], dtype=np.int64)
|
||||
x_c = np.array([4, 3, 2, 3], dtype=np.int64)
|
||||
|
||||
x_sparse_1 = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5))
|
||||
|
||||
x_d = np.array([0, 7, 2, 3], dtype=np.float32)
|
||||
x_r = np.array([0, 2, 2, 3], dtype=np.int64)
|
||||
x_c = np.array([4, 3, 2, 3], dtype=np.int64)
|
||||
|
||||
x_sparse_2 = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5))
|
||||
|
||||
x_dense_1 = x_sparse_1.toarray()
|
||||
x_dense_2 = x_sparse_2.toarray()
|
||||
|
||||
backends = [KTF]
|
||||
if KTH.th_sparse_module:
|
||||
# Theano has some dependency issues for sparse
|
||||
backends.append(KTH)
|
||||
|
||||
for K in backends:
|
||||
k_s = K.concatenate([K.variable(x_sparse_1), K.variable(x_sparse_2)])
|
||||
assert K.is_sparse(k_s)
|
||||
|
||||
k_s_d = K.eval(k_s)
|
||||
|
||||
k_d = K.eval(K.concatenate([K.variable(x_dense_1), K.variable(x_dense_2)]))
|
||||
|
||||
assert k_s_d.shape == k_d.shape
|
||||
assert_allclose(k_s_d, k_d, atol=1e-05)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -5,7 +5,7 @@ from numpy.testing import assert_allclose
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
from keras.utils.np_utils import conv_input_length
|
||||
from keras import backend as K
|
||||
from keras.layers import convolutional
|
||||
from keras.layers import convolutional, pooling
|
||||
|
||||
|
||||
@keras_test
|
||||
@@ -17,9 +17,10 @@ def test_convolution_1d():
|
||||
nb_filter = 3
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample_length in [1]:
|
||||
for subsample_length in [1, 2]:
|
||||
if border_mode == 'same' and subsample_length != 1:
|
||||
continue
|
||||
|
||||
layer_test(convolutional.Convolution1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
@@ -38,6 +39,42 @@ def test_convolution_1d():
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_atrous_conv_1d():
|
||||
nb_samples = 2
|
||||
nb_steps = 8
|
||||
input_dim = 2
|
||||
filter_length = 3
|
||||
nb_filter = 3
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample_length in [1, 2]:
|
||||
for atrous_rate in [1, 2]:
|
||||
if border_mode == 'same' and subsample_length != 1:
|
||||
continue
|
||||
if subsample_length != 1 and atrous_rate != 1:
|
||||
continue
|
||||
|
||||
layer_test(convolutional.AtrousConv1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
'border_mode': border_mode,
|
||||
'subsample_length': subsample_length,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
layer_test(convolutional.AtrousConv1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
'border_mode': border_mode,
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample_length': subsample_length,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_maxpooling_1d():
|
||||
for stride in [1, 2]:
|
||||
@@ -75,7 +112,7 @@ def test_convolution_2d():
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(convolutional.Convolution2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -86,7 +123,7 @@ def test_convolution_2d():
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
|
||||
@keras_test
|
||||
@@ -110,7 +147,8 @@ def test_deconvolution_2d():
|
||||
'nb_col': 3,
|
||||
'output_shape': (nb_samples, nb_filter, rows, cols),
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample},
|
||||
'subsample': subsample,
|
||||
'dim_ordering': 'th'},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col),
|
||||
fixed_batch_size=True)
|
||||
|
||||
@@ -120,6 +158,7 @@ def test_deconvolution_2d():
|
||||
'nb_col': 3,
|
||||
'output_shape': (nb_samples, nb_filter, rows, cols),
|
||||
'border_mode': border_mode,
|
||||
'dim_ordering': 'th',
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
@@ -151,7 +190,7 @@ def test_atrous_conv_2d():
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(convolutional.AtrousConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -163,7 +202,7 @@ def test_atrous_conv_2d():
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'tensorflow', reason="Requires TF backend")
|
||||
@@ -188,7 +227,7 @@ def test_separable_conv_2d():
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'depth_multiplier': multiplier},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(convolutional.SeparableConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -203,7 +242,31 @@ def test_separable_conv_2d():
|
||||
'depthwise_constraint': 'unitnorm',
|
||||
'subsample': subsample,
|
||||
'depth_multiplier': multiplier},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_globalpooling_1d():
|
||||
layer_test(pooling.GlobalMaxPooling1D,
|
||||
input_shape=(3, 4, 5))
|
||||
layer_test(pooling.GlobalAveragePooling1D,
|
||||
input_shape=(3, 4, 5))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_globalpooling_2d():
|
||||
layer_test(pooling.GlobalMaxPooling2D,
|
||||
kwargs={'dim_ordering': 'th'},
|
||||
input_shape=(3, 4, 5, 6))
|
||||
layer_test(pooling.GlobalMaxPooling2D,
|
||||
kwargs={'dim_ordering': 'tf'},
|
||||
input_shape=(3, 5, 6, 4))
|
||||
layer_test(pooling.GlobalAveragePooling2D,
|
||||
kwargs={'dim_ordering': 'th'},
|
||||
input_shape=(3, 4, 5, 6))
|
||||
layer_test(pooling.GlobalAveragePooling2D,
|
||||
kwargs={'dim_ordering': 'tf'},
|
||||
input_shape=(3, 5, 6, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
@@ -215,7 +278,7 @@ def test_maxpooling_2d():
|
||||
kwargs={'strides': strides,
|
||||
'border_mode': 'valid',
|
||||
'pool_size': pool_size},
|
||||
input_shape=(3, 4, 11, 12))
|
||||
input_shape=(3, 11, 12, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
@@ -229,7 +292,7 @@ def test_averagepooling_2d():
|
||||
kwargs={'strides': strides,
|
||||
'border_mode': border_mode,
|
||||
'pool_size': pool_size},
|
||||
input_shape=(3, 4, 11, 12))
|
||||
input_shape=(3, 11, 12, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
@@ -257,8 +320,9 @@ def test_convolution_3d():
|
||||
'kernel_dim3': kernel_dim3,
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3))
|
||||
input_shape=(nb_samples,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3,
|
||||
stack_size))
|
||||
|
||||
layer_test(convolutional.Convolution3D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -270,8 +334,9 @@ def test_convolution_3d():
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3))
|
||||
input_shape=(nb_samples,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3,
|
||||
stack_size))
|
||||
|
||||
|
||||
@keras_test
|
||||
@@ -305,7 +370,7 @@ def test_zero_padding_2d():
|
||||
input_nb_row = 11
|
||||
input_nb_col = 12
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_nb_row, input_nb_col))
|
||||
input = np.ones((nb_samples, input_nb_row, input_nb_col, stack_size))
|
||||
|
||||
# basic test
|
||||
layer_test(convolutional.ZeroPadding2D,
|
||||
@@ -318,9 +383,9 @@ def test_zero_padding_2d():
|
||||
|
||||
out = K.eval(layer.output)
|
||||
for offset in [0, 1, -1, -2]:
|
||||
assert_allclose(out[:, offset, :, :], 0.)
|
||||
assert_allclose(out[:, :, offset, :], 0.)
|
||||
assert_allclose(out[:, :, :, offset], 0.)
|
||||
assert_allclose(out[:, :, 2:-2, 2:-2], 1.)
|
||||
assert_allclose(out[:, 2:-2, 2:-2, :], 1.)
|
||||
layer.get_config()
|
||||
|
||||
|
||||
@@ -331,8 +396,9 @@ def test_zero_padding_3d():
|
||||
input_len_dim2 = 11
|
||||
input_len_dim3 = 12
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_len_dim1,
|
||||
input_len_dim2, input_len_dim3))
|
||||
input = np.ones((nb_samples,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3,
|
||||
stack_size))
|
||||
|
||||
# basic test
|
||||
layer_test(convolutional.ZeroPadding3D,
|
||||
@@ -344,10 +410,10 @@ def test_zero_padding_3d():
|
||||
layer.set_input(K.variable(input), shape=input.shape)
|
||||
out = K.eval(layer.output)
|
||||
for offset in [0, 1, -1, -2]:
|
||||
assert_allclose(out[:, offset, :, :, :], 0.)
|
||||
assert_allclose(out[:, :, offset, :, :], 0.)
|
||||
assert_allclose(out[:, :, :, offset, :], 0.)
|
||||
assert_allclose(out[:, :, :, :, offset], 0.)
|
||||
assert_allclose(out[:, :, 2:-2, 2:-2, 2:-2], 1.)
|
||||
assert_allclose(out[:, 2:-2, 2:-2, 2:-2, :], 1.)
|
||||
layer.get_config()
|
||||
|
||||
|
||||
@@ -455,19 +521,20 @@ def test_cropping_1d():
|
||||
kwargs={'cropping': (2, 2)},
|
||||
input_shape=input.shape)
|
||||
|
||||
|
||||
def test_cropping_2d():
|
||||
nb_samples = 2
|
||||
stack_size = 2
|
||||
input_len_dim1 = 10
|
||||
input_len_dim2 = 20
|
||||
input_len_dim1 = 8
|
||||
input_len_dim2 = 8
|
||||
cropping = ((2, 2), (3, 3))
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
|
||||
if dim_ordering == 'th':
|
||||
input = np.random.rand(nb_samples, stack_size, input_len_dim1, input_len_dim2)
|
||||
else:
|
||||
input = np.random.rand(nb_samples, input_len_dim1, input_len_dim2, stack_size)
|
||||
# basic test
|
||||
# basic test
|
||||
layer_test(convolutional.Cropping2D,
|
||||
kwargs={'cropping': cropping,
|
||||
'dim_ordering': dim_ordering},
|
||||
@@ -479,14 +546,14 @@ def test_cropping_2d():
|
||||
out = K.eval(layer.output)
|
||||
# compare with numpy
|
||||
if dim_ordering == 'th':
|
||||
expected_out = input[:,
|
||||
:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
expected_out = input[:,
|
||||
:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1]]
|
||||
else:
|
||||
expected_out = input[:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
expected_out = input[:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
:]
|
||||
|
||||
assert_allclose(out, expected_out)
|
||||
@@ -495,17 +562,17 @@ def test_cropping_2d():
|
||||
def test_cropping_3d():
|
||||
nb_samples = 2
|
||||
stack_size = 2
|
||||
input_len_dim1 = 10
|
||||
input_len_dim2 = 20
|
||||
input_len_dim3 = 30
|
||||
input_len_dim1 = 8
|
||||
input_len_dim2 = 8
|
||||
input_len_dim3 = 8
|
||||
cropping = ((2, 2), (3, 3), (2, 3))
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
|
||||
if dim_ordering == 'th':
|
||||
input = np.random.rand(nb_samples, stack_size, input_len_dim1, input_len_dim2, input_len_dim3)
|
||||
else:
|
||||
input = np.random.rand(nb_samples, input_len_dim1, input_len_dim2, input_len_dim3, stack_size)
|
||||
# basic test
|
||||
# basic test
|
||||
layer_test(convolutional.Cropping3D,
|
||||
kwargs={'cropping': cropping,
|
||||
'dim_ordering': dim_ordering},
|
||||
@@ -517,22 +584,19 @@ def test_cropping_3d():
|
||||
out = K.eval(layer.output)
|
||||
# compare with numpy
|
||||
if dim_ordering == 'th':
|
||||
expected_out = input[:,
|
||||
:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
expected_out = input[:,
|
||||
:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
cropping[2][0]:-cropping[2][1]]
|
||||
else:
|
||||
expected_out = input[:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
cropping[2][0]:-cropping[2][1],
|
||||
expected_out = input[:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
cropping[2][0]:-cropping[2][1],
|
||||
:]
|
||||
|
||||
assert_allclose(out, expected_out)
|
||||
|
||||
|
||||
def test_cropping_3d():
|
||||
pass
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -16,8 +16,11 @@ input_shapes = [np.ones((10, 10)), np.ones((10, 10, 10))]
|
||||
|
||||
@keras_test
|
||||
def basic_batchnorm_test():
|
||||
from keras import regularizers
|
||||
layer_test(normalization.BatchNormalization,
|
||||
kwargs={'mode': 1},
|
||||
kwargs={'mode': 1,
|
||||
'gamma_regularizer': regularizers.l2(0.01),
|
||||
'beta_regularizer': regularizers.l2(0.01)},
|
||||
input_shape=(3, 4, 2))
|
||||
layer_test(normalization.BatchNormalization,
|
||||
kwargs={'mode': 0},
|
||||
|
||||
@@ -26,6 +26,15 @@ def _runner(layer_class):
|
||||
'return_sequences': True},
|
||||
input_shape=(nb_samples, timesteps, embedding_dim))
|
||||
|
||||
# check dynamic behavior
|
||||
layer = layer_class(output_dim, input_dim=embedding_dim)
|
||||
model = Sequential()
|
||||
model.add(layer)
|
||||
model.compile('sgd', 'mse')
|
||||
x = np.random.random((nb_samples, timesteps, embedding_dim))
|
||||
y = np.random.random((nb_samples, output_dim))
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
# check dropout
|
||||
layer_test(layer_class,
|
||||
kwargs={'output_dim': output_dim,
|
||||
|
||||
@@ -43,10 +43,10 @@ def test_TimeDistributed():
|
||||
|
||||
# test with Convolution2D
|
||||
model = Sequential()
|
||||
model.add(wrappers.TimeDistributed(convolutional.Convolution2D(5, 2, 2, border_mode='same'), input_shape=(2, 3, 4, 4)))
|
||||
model.add(wrappers.TimeDistributed(convolutional.Convolution2D(5, 2, 2, border_mode='same'), input_shape=(2, 4, 4, 3)))
|
||||
model.add(core.Activation('relu'))
|
||||
model.compile(optimizer='rmsprop', loss='mse')
|
||||
model.train_on_batch(np.random.random((1, 2, 3, 4, 4)), np.random.random((1, 2, 5, 4, 4)))
|
||||
model.train_on_batch(np.random.random((1, 2, 4, 4, 3)), np.random.random((1, 2, 4, 4, 5)))
|
||||
|
||||
model = model_from_json(model.to_json())
|
||||
model.summary()
|
||||
|
||||
@@ -63,7 +63,7 @@ def test_pad_sequences_vector():
|
||||
|
||||
def test_make_sampling_table():
|
||||
a = make_sampling_table(3)
|
||||
assert_allclose(a, np.asarray([0.00315225, 0.00315225, 0.00547597]),
|
||||
assert_allclose(a, np.asarray([0.00315225, 0.00315225, 0.00547597]),
|
||||
rtol=.1)
|
||||
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ def test_softplus():
|
||||
return np.log(np.ones_like(x) + np.exp(x))
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
f = K.function([x], [activations.softplus(x)])
|
||||
f = K.function([x], [activations.softplus(x)])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
@@ -64,7 +64,7 @@ def test_softsign():
|
||||
return np.divide(x, np.ones_like(x) + np.absolute(x))
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
f = K.function([x], [activations.softsign(x)])
|
||||
f = K.function([x], [activations.softsign(x)])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
@@ -85,7 +85,7 @@ def test_sigmoid():
|
||||
sigmoid = np.vectorize(ref_sigmoid)
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
f = K.function([x], [activations.sigmoid(x)])
|
||||
f = K.function([x], [activations.sigmoid(x)])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
@@ -108,7 +108,7 @@ def test_hard_sigmoid():
|
||||
hard_sigmoid = np.vectorize(ref_hard_sigmoid)
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
f = K.function([x], [activations.hard_sigmoid(x)])
|
||||
f = K.function([x], [activations.hard_sigmoid(x)])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
|
||||
@@ -17,6 +17,7 @@ all_metrics = [
|
||||
metrics.binary_crossentropy,
|
||||
metrics.poisson,
|
||||
metrics.cosine_proximity,
|
||||
metrics.matthews_correlation,
|
||||
]
|
||||
|
||||
all_sparse_metrics = [
|
||||
|
||||
@@ -45,22 +45,27 @@ def test_sgd():
|
||||
|
||||
def test_rmsprop():
|
||||
_test_optimizer(RMSprop())
|
||||
_test_optimizer(RMSprop(decay=1e-3))
|
||||
|
||||
|
||||
def test_adagrad():
|
||||
_test_optimizer(Adagrad())
|
||||
_test_optimizer(Adagrad(decay=1e-3))
|
||||
|
||||
|
||||
def test_adadelta():
|
||||
_test_optimizer(Adadelta())
|
||||
_test_optimizer(Adadelta(), target=0.83)
|
||||
_test_optimizer(Adadelta(decay=1e-3), target=0.83)
|
||||
|
||||
|
||||
def test_adam():
|
||||
_test_optimizer(Adam())
|
||||
_test_optimizer(Adam(decay=1e-3))
|
||||
|
||||
|
||||
def test_adamax():
|
||||
_test_optimizer(Adamax())
|
||||
_test_optimizer(Adamax(decay=1e-3))
|
||||
|
||||
|
||||
def test_nadam():
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
|
||||
from keras.models import Model
|
||||
from keras.layers import Dense, Input
|
||||
from keras.utils.test_utils import keras_test
|
||||
from keras import backend as K
|
||||
from keras.backend import theano_backend as KTH
|
||||
from keras.backend import tensorflow_backend as KTF
|
||||
|
||||
import scipy.sparse as sparse
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
|
||||
|
||||
input_dim = 16
|
||||
nb_hidden = 8
|
||||
nb_class = 4
|
||||
batch_size = 32
|
||||
nb_epoch = 1
|
||||
|
||||
|
||||
def do_sparse():
|
||||
return K == KTF or KTH.th_sparse_module
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_sparse_mlp():
|
||||
if not do_sparse():
|
||||
return
|
||||
|
||||
input = Input(batch_shape=(None, input_dim), sparse=True)
|
||||
hidden = Dense(nb_hidden, activation='relu')(input)
|
||||
hidden = Dense(nb_hidden, activation='relu')(hidden)
|
||||
predictions = Dense(nb_class, activation='sigmoid')(hidden)
|
||||
model = Model(input=[input], output=predictions)
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
x = sparse.rand(batch_size, input_dim, density=0.1, format='csr')
|
||||
y = np.random.random((batch_size, nb_class))
|
||||
model.fit(x, y, nb_epoch=1)
|
||||
+112
-41
@@ -1,5 +1,6 @@
|
||||
import pytest
|
||||
import os
|
||||
import tempfile
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
|
||||
@@ -15,41 +16,6 @@ from keras.models import save_model, load_model
|
||||
|
||||
@keras_test
|
||||
def test_sequential_model_saving():
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3))
|
||||
model.add(Dense(3))
|
||||
model.compile(loss='mse', optimizer='rmsprop', metrics=['acc'])
|
||||
|
||||
x = np.random.random((1, 3))
|
||||
y = np.random.random((1, 3))
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
out = model.predict(x)
|
||||
fname = 'tmp_' + str(np.random.randint(10000)) + '.h5'
|
||||
save_model(model, fname)
|
||||
|
||||
new_model = load_model(fname)
|
||||
|
||||
out2 = new_model.predict(x)
|
||||
assert_allclose(out, out2, atol=1e-05)
|
||||
|
||||
# test that new updates are the same with both models
|
||||
x = np.random.random((1, 3))
|
||||
y = np.random.random((1, 3))
|
||||
model.train_on_batch(x, y)
|
||||
new_model.train_on_batch(x, y)
|
||||
out = model.predict(x)
|
||||
out2 = new_model.predict(x)
|
||||
assert_allclose(out, out2, atol=1e-05)
|
||||
|
||||
# test load_weights on model file
|
||||
model.load_weights(fname)
|
||||
os.remove(fname)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_sequential_model_saving_2():
|
||||
# test with funkier config
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3))
|
||||
model.add(RepeatVector(3))
|
||||
@@ -63,7 +29,7 @@ def test_sequential_model_saving_2():
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
out = model.predict(x)
|
||||
fname = 'tmp_' + str(np.random.randint(10000)) + '.h5'
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
save_model(model, fname)
|
||||
|
||||
new_model = load_model(fname)
|
||||
@@ -83,7 +49,7 @@ def test_sequential_model_saving_2():
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_sequential_model_saving_3():
|
||||
def test_sequential_model_saving_2():
|
||||
# test with custom optimizer, loss
|
||||
custom_opt = optimizers.rmsprop
|
||||
custom_loss = objectives.mse
|
||||
@@ -97,7 +63,7 @@ def test_sequential_model_saving_3():
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
out = model.predict(x)
|
||||
fname = 'tmp_' + str(np.random.randint(10000)) + '.h5'
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
save_model(model, fname)
|
||||
|
||||
model = load_model(fname,
|
||||
@@ -124,7 +90,7 @@ def test_fuctional_model_saving():
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
out = model.predict(x)
|
||||
fname = 'tmp_' + str(np.random.randint(10000)) + '.h5'
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
save_model(model, fname)
|
||||
|
||||
model = load_model(fname)
|
||||
@@ -141,7 +107,7 @@ def test_saving_without_compilation():
|
||||
model.add(Dense(3))
|
||||
model.compile(loss='mse', optimizer='sgd', metrics=['acc'])
|
||||
|
||||
fname = 'tmp_' + str(np.random.randint(10000)) + '.h5'
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
save_model(model, fname)
|
||||
model = load_model(fname)
|
||||
os.remove(fname)
|
||||
@@ -155,11 +121,116 @@ def test_saving_right_after_compilation():
|
||||
model.compile(loss='mse', optimizer='sgd', metrics=['acc'])
|
||||
model.model._make_train_function()
|
||||
|
||||
fname = 'tmp_' + str(np.random.randint(10000)) + '.h5'
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
save_model(model, fname)
|
||||
model = load_model(fname)
|
||||
os.remove(fname)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_loading_weights_by_name():
|
||||
"""
|
||||
test loading model weights by name on:
|
||||
- sequential model
|
||||
"""
|
||||
|
||||
# test with custom optimizer, loss
|
||||
custom_opt = optimizers.rmsprop
|
||||
custom_loss = objectives.mse
|
||||
|
||||
# sequential model
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="rick"))
|
||||
model.add(Dense(3, name="morty"))
|
||||
model.compile(loss=custom_loss, optimizer=custom_opt(), metrics=['acc'])
|
||||
|
||||
x = np.random.random((1, 3))
|
||||
y = np.random.random((1, 3))
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
out = model.predict(x)
|
||||
old_weights = [layer.get_weights() for layer in model.layers]
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
|
||||
model.save_weights(fname)
|
||||
|
||||
# delete and recreate model
|
||||
del(model)
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="rick"))
|
||||
model.add(Dense(3, name="morty"))
|
||||
model.compile(loss=custom_loss, optimizer=custom_opt(), metrics=['acc'])
|
||||
|
||||
# load weights from first model
|
||||
model.load_weights(fname, by_name=True)
|
||||
os.remove(fname)
|
||||
|
||||
out2 = model.predict(x)
|
||||
assert_allclose(out, out2, atol=1e-05)
|
||||
for i in range(len(model.layers)):
|
||||
new_weights = model.layers[i].get_weights()
|
||||
for j in range(len(new_weights)):
|
||||
assert_allclose(old_weights[i][j], new_weights[j], atol=1e-05)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_loading_weights_by_name_2():
|
||||
"""
|
||||
test loading model weights by name on:
|
||||
- both sequential and functional api models
|
||||
- different architecture with shared names
|
||||
"""
|
||||
|
||||
# test with custom optimizer, loss
|
||||
custom_opt = optimizers.rmsprop
|
||||
custom_loss = objectives.mse
|
||||
|
||||
# sequential model
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="rick"))
|
||||
model.add(Dense(3, name="morty"))
|
||||
model.compile(loss=custom_loss, optimizer=custom_opt(), metrics=['acc'])
|
||||
|
||||
x = np.random.random((1, 3))
|
||||
y = np.random.random((1, 3))
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
out = model.predict(x)
|
||||
old_weights = [layer.get_weights() for layer in model.layers]
|
||||
_, fname = tempfile.mkstemp('.h5')
|
||||
|
||||
model.save_weights(fname)
|
||||
|
||||
# delete and recreate model using Functional API
|
||||
del(model)
|
||||
data = Input(shape=(3,))
|
||||
rick = Dense(2, name="rick")(data)
|
||||
jerry = Dense(3, name="jerry")(rick) # add 2 layers (but maintain shapes)
|
||||
jessica = Dense(2, name="jessica")(jerry)
|
||||
morty = Dense(3, name="morty")(jessica)
|
||||
|
||||
model = Model(input=[data], output=[morty])
|
||||
model.compile(loss=custom_loss, optimizer=custom_opt(), metrics=['acc'])
|
||||
|
||||
# load weights from first model
|
||||
model.load_weights(fname, by_name=True)
|
||||
os.remove(fname)
|
||||
|
||||
out2 = model.predict(x)
|
||||
assert np.max(np.abs(out - out2)) > 1e-05
|
||||
|
||||
rick = model.layers[1].get_weights()
|
||||
jerry = model.layers[2].get_weights()
|
||||
jessica = model.layers[3].get_weights()
|
||||
morty = model.layers[4].get_weights()
|
||||
|
||||
assert_allclose(old_weights[0][0], rick[0], atol=1e-05)
|
||||
assert_allclose(old_weights[0][1], rick[1], atol=1e-05)
|
||||
assert_allclose(old_weights[1][0], morty[0], atol=1e-05)
|
||||
assert_allclose(old_weights[1][1], morty[1], atol=1e-05)
|
||||
assert_allclose(np.zeros_like(jerry[1]), jerry[1]) # biases init to 0
|
||||
assert_allclose(np.zeros_like(jessica[1]), jessica[1]) # biases init to 0
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário