Comparar commits
197 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 892d9fae84 | |||
| 796f895f01 | |||
| 489bb4eb10 | |||
| 8f458066bb | |||
| 5dd7454260 | |||
| 571db82371 | |||
| d971e0cca5 | |||
| fde0aac733 | |||
| b9d904c12f | |||
| aa2ec42da6 | |||
| d90d473104 | |||
| 5a1e63990a | |||
| e836c10c6f | |||
| 47c09d9557 | |||
| b35b943364 | |||
| ca467cc50e | |||
| 51f7cf0367 | |||
| 642eaca618 | |||
| 55e5680535 | |||
| 52ea31b65c | |||
| b3a26a5b30 | |||
| 98974efa5f | |||
| b6a776b242 | |||
| 1ea3f44f06 | |||
| 64e1320ca0 | |||
| 6e0b50fbdc | |||
| 22502a8fe8 | |||
| a78ad01bb4 | |||
| 729e802e85 | |||
| 3ffff6d579 | |||
| 6e5f97fca5 | |||
| eaff5bdfd7 | |||
| 28819d36a4 | |||
| f9a4f6f306 | |||
| 27c83c693d | |||
| d106908a57 | |||
| b4adce34dc | |||
| 3927505d1a | |||
| ede79f818e | |||
| 742ac53262 | |||
| ee17ccc374 | |||
| 835a02c037 | |||
| ee8ff00a2a | |||
| 229f13a864 | |||
| 0d60d637af | |||
| c20e34a8b0 | |||
| 8d3f39852a | |||
| aa45dee5a4 | |||
| 885e6e621b | |||
| dc122c31ef | |||
| 3bc80d3db4 | |||
| 439f2f3b2b | |||
| a1610eb274 | |||
| 6b90eff03c | |||
| 4d404d1a54 | |||
| fffa6a80ca | |||
| 3f6b38b34f | |||
| 8166a55761 | |||
| 89f6d374e9 | |||
| 9b3c2cf348 | |||
| 76406dd0c2 | |||
| d266b75423 | |||
| 5bb5eb1657 | |||
| 258cf3b0f7 | |||
| cdb5b09cd7 | |||
| cb3469215a | |||
| 703c2925b3 | |||
| b6ca3ef051 | |||
| b235f91cc7 | |||
| 3513472467 | |||
| 60e0c96f6c | |||
| e37df7ca85 | |||
| a13a35fe52 | |||
| f421600218 | |||
| 2a4492d74f | |||
| 10368d867f | |||
| 936360020c | |||
| c53c64d7fa | |||
| 6b122ba25f | |||
| 6501b587c0 | |||
| 53aaa842ed | |||
| dc569e952d | |||
| c9aee4126e | |||
| 7397f4b0d0 | |||
| 3b83a1b1ac | |||
| 8f8e4574dc | |||
| c30432a665 | |||
| c4c2d8bbd4 | |||
| e49ba233f9 | |||
| cea6c1821f | |||
| ab4bf447c6 | |||
| 4e0c8cf25b | |||
| e4b3a052a4 | |||
| 825beb42c4 | |||
| c8d605db55 | |||
| f6ecab58cb | |||
| d7e39347b9 | |||
| 25c10af596 | |||
| ded23f14c7 | |||
| b0d52d930a | |||
| af5c5b6a55 | |||
| ce51e19970 | |||
| 97e31b6090 | |||
| 62053e68e2 | |||
| 489c07e748 | |||
| 604ea8d68a | |||
| fd3cfb196b | |||
| b71f6ba864 | |||
| dfc128b89a | |||
| 34b8b57c2f | |||
| 3bba409d9e | |||
| 7869cdccec | |||
| 0e18e345b0 | |||
| e5b99c7512 | |||
| 7d4c85018a | |||
| edbec2dbc9 | |||
| 973ece9809 | |||
| 90f441a6a0 | |||
| 5a71090476 | |||
| 76cae0ec44 | |||
| 273f0dda9d | |||
| 882b5a1d89 | |||
| 8c84ad1a86 | |||
| 80bfec7253 | |||
| 91b930298b | |||
| 9c56b91548 | |||
| 7b5bab83f4 | |||
| c5e2116ead | |||
| d9db73a791 | |||
| 01ece4ef7b | |||
| 601f3e7cdb | |||
| a9ca2c547f | |||
| 594cbed03b | |||
| 3938a905a1 | |||
| 88d523e01b | |||
| 0419fe67fc | |||
| 33ddeb5cbe | |||
| 1f5d5b391b | |||
| 198c515208 | |||
| 5156673e17 | |||
| 1529c9c438 | |||
| 32b10a8832 | |||
| 24501d4361 | |||
| bf0c08e24a | |||
| 34d8cce6bc | |||
| f0bfc24adc | |||
| 2f8acfe4bf | |||
| e2fb8b2786 | |||
| ebbc4d9fb8 | |||
| 8fc5b90e9a | |||
| 8a717f5b6c | |||
| aa91994166 | |||
| 2091347a71 | |||
| e0ed174f2c | |||
| 8c2a573ebf | |||
| d7ff7cde92 | |||
| 15d0b0ea08 | |||
| 3695bc2db5 | |||
| a08995a90d | |||
| aea00258e7 | |||
| b581eb3f27 | |||
| 610ccba9f5 | |||
| d5ae6f32dd | |||
| 5308033936 | |||
| e2abb5ef2c | |||
| 1b11b4eeb6 | |||
| 39357b3045 | |||
| ed7a5a1418 | |||
| ae682a71f9 | |||
| 8327b37a0b | |||
| 973b5570aa | |||
| 7cb41fc5cc | |||
| 595d67ad7d | |||
| bb626c120e | |||
| ba8fefa8ec | |||
| 4b24f6d7b1 | |||
| 1c460e1e08 | |||
| 7b4e157356 | |||
| 5749f1b971 | |||
| 3c57aff85b | |||
| 18504bcc86 | |||
| d8864bfe48 | |||
| 078b20169b | |||
| 5f7e78df65 | |||
| fc470db7ab | |||
| f576f37801 | |||
| b74118a766 | |||
| 1c7a0248b9 | |||
| 36a829c20d | |||
| 33af75aa39 | |||
| 844420425e | |||
| da57a530f9 | |||
| 1f17013949 | |||
| f18899cb36 | |||
| 877f946e24 | |||
| a981a8c42c | |||
| ed365e94fd |
+2
-2
@@ -49,9 +49,9 @@ install:
|
||||
|
||||
# install TensorFlow
|
||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.7.1-cp27-none-linux_x86_64.whl;
|
||||
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.9.0-cp27-none-linux_x86_64.whl;
|
||||
elif [[ "$TRAVIS_PYTHON_VERSION" == "3.4" ]]; then
|
||||
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.7.1-cp34-none-linux_x86_64.whl;
|
||||
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.9.0-cp34-cp34m-linux_x86_64.whl;
|
||||
fi
|
||||
# command to run tests
|
||||
script:
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@
|
||||
|
||||
[](https://travis-ci.org/fchollet/keras)
|
||||
[](https://badge.fury.io/py/keras)
|
||||
[](https://github.com/fchollet/keras/blob/master/LICENSE)
|
||||
|
||||
## You have just found Keras.
|
||||
|
||||
@@ -51,7 +52,7 @@ model = Sequential()
|
||||
Stacking layers is as easy as `.add()`:
|
||||
|
||||
```python
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.layers import Dense, Activation
|
||||
|
||||
model.add(Dense(output_dim=64, input_dim=100))
|
||||
model.add(Activation("relu"))
|
||||
|
||||
+14
-106
@@ -82,6 +82,7 @@ from keras import constraints
|
||||
from keras import activations
|
||||
from keras import regularizers
|
||||
|
||||
|
||||
EXCLUDE = {
|
||||
'Optimizer',
|
||||
'Wrapper',
|
||||
@@ -145,13 +146,8 @@ PAGES = [
|
||||
'classes': [
|
||||
convolutional.Convolution1D,
|
||||
convolutional.Convolution2D,
|
||||
convolutional.AtrousConv2D,
|
||||
convolutional.Convolution3D,
|
||||
convolutional.MaxPooling1D,
|
||||
convolutional.MaxPooling2D,
|
||||
convolutional.MaxPooling3D,
|
||||
convolutional.AveragePooling1D,
|
||||
convolutional.AveragePooling2D,
|
||||
convolutional.AveragePooling3D,
|
||||
convolutional.UpSampling1D,
|
||||
convolutional.UpSampling2D,
|
||||
convolutional.UpSampling3D,
|
||||
@@ -160,6 +156,17 @@ PAGES = [
|
||||
convolutional.ZeroPadding3D,
|
||||
],
|
||||
},
|
||||
{
|
||||
'page': 'layers/pooling.md',
|
||||
'classes': [
|
||||
convolutional.MaxPooling1D,
|
||||
convolutional.MaxPooling2D,
|
||||
convolutional.MaxPooling3D,
|
||||
convolutional.AveragePooling1D,
|
||||
convolutional.AveragePooling2D,
|
||||
convolutional.AveragePooling3D,
|
||||
],
|
||||
},
|
||||
{
|
||||
'page': 'layers/recurrent.md',
|
||||
'classes': [
|
||||
@@ -334,6 +341,7 @@ def process_function_docstring(docstring):
|
||||
print('Cleaning up existing sources directory.')
|
||||
if os.path.exists('sources'):
|
||||
shutil.rmtree('sources')
|
||||
|
||||
print('Populating sources directory with templates.')
|
||||
for subdir, dirs, fnames in os.walk('templates'):
|
||||
for fname in fnames:
|
||||
@@ -418,103 +426,3 @@ for page_data in PAGES:
|
||||
if not os.path.exists(subdir):
|
||||
os.makedirs(subdir)
|
||||
open(path, 'w').write(mkdown)
|
||||
|
||||
|
||||
# covered_so_far = set()
|
||||
# for module, module_name in MODULES:
|
||||
# class_pages = []
|
||||
# for name in dir(module):
|
||||
# if name in SKIP:
|
||||
# continue
|
||||
# if name[0] == '_':
|
||||
# continue
|
||||
# module_member = getattr(module, name)
|
||||
# if module_member in covered_so_far:
|
||||
# continue
|
||||
# if inspect.isclass(module_member):
|
||||
# cls = module_member
|
||||
# if cls.__module__ == module_name:
|
||||
|
||||
# try:
|
||||
# class_signature = get_function_signature(cls.__init__)
|
||||
# class_signature = class_signature.replace('__init__', cls.__name__)
|
||||
# except:
|
||||
# # in case the class inherits from object and does not
|
||||
# # define __init__
|
||||
# class_signature = module_name + '.' + cls.__name__ + '()'
|
||||
|
||||
# functions = []
|
||||
# functions_not_defined_here = []
|
||||
# for name in dir(cls):
|
||||
# if name in SKIP:
|
||||
# continue
|
||||
# if name[0] == '_':
|
||||
# continue
|
||||
# cls_member = getattr(cls, name)
|
||||
# if inspect.isfunction(cls_member):
|
||||
# function = cls_member
|
||||
# signature = inspect.getargspec(function)
|
||||
# defaults = signature.defaults
|
||||
# args = signature.args[1:]
|
||||
# if defaults:
|
||||
# kwargs = zip(args[-len(defaults):], defaults)
|
||||
# args = args[:-len(defaults)]
|
||||
# else:
|
||||
# kwargs = []
|
||||
|
||||
# defined_by = get_earliest_class_that_defined_member(function.__name__, cls)
|
||||
# if cls == defined_by:
|
||||
# functions.append(function)
|
||||
# else:
|
||||
# functions_not_defined_here.append((function, defined_by))
|
||||
|
||||
# blocks = []
|
||||
# blocks.append('<span style="float:right;">' + class_to_source_link(cls) + '</span>')
|
||||
# blocks.append('# ' + cls.__name__ + '\n')
|
||||
# blocks.append(code_snippet(class_signature))
|
||||
# docstring = cls.__doc__
|
||||
# if docstring:
|
||||
# blocks.append(process_class_docstring(docstring))
|
||||
|
||||
# if cls.__name__ in INCLUDE_functionS_FOR:
|
||||
# if functions or functions_not_defined_here:
|
||||
# blocks.append('### functions\n')
|
||||
# for function in functions:
|
||||
# signature = get_function_signature(function)
|
||||
# signature = signature.replace(module_name + '.', '')
|
||||
# blocks.append(code_snippet(signature))
|
||||
# docstring = function.__doc__
|
||||
# if docstring:
|
||||
# blocks.append(process_function_docstring(docstring))
|
||||
# for function, defined_by in functions_not_defined_here:
|
||||
# signature = get_function_signature(function)
|
||||
# function_module_name = function.__module__
|
||||
# signature = signature.replace(function_module_name + '.', '')
|
||||
# link = '[' + defined_by.__name__ + '](' + class_to_docs_link(defined_by) + ')'
|
||||
# blocks.append(code_snippet(signature))
|
||||
# blocks.append('Defined by ' + link + '.\n')
|
||||
|
||||
# mkdown = '\n'.join(blocks)
|
||||
# class_pages.append((id(cls), mkdown))
|
||||
# covered_so_far.add(module_member)
|
||||
|
||||
# class_pages.sort(key=lambda x: x[0])
|
||||
# class_pages = [x[1] for x in class_pages]
|
||||
# module_page = '\n----\n\n'.join(class_pages)
|
||||
|
||||
# # save module page.
|
||||
# # Either insert content into existing page,
|
||||
# # or create page otherwise
|
||||
# path = 'sources/' + module_name.replace('.', '/')[6:] + '.md'
|
||||
# if os.path.exists(path):
|
||||
# template = open(path).read()
|
||||
# assert '{{autogenerated}}' in template, ('Template found for ' + path +
|
||||
# ' but missing {{autogenerated}} tag.')
|
||||
# module_page = template.replace('{{autogenerated}}', module_page)
|
||||
# print('...inserting autogenerated content into template:', path)
|
||||
# else:
|
||||
# print('...creating new page with autogenerated content:', path)
|
||||
# subdir = os.path.dirname(path)
|
||||
# if not os.path.exists(subdir):
|
||||
# os.makedirs(subdir)
|
||||
# open(path, 'w').write(module_page)
|
||||
|
||||
@@ -24,6 +24,7 @@ pages:
|
||||
- About Keras layers: layers/about-keras-layers.md
|
||||
- Core Layers: layers/core.md
|
||||
- Convolutional Layers: layers/convolutional.md
|
||||
- Pooling Layers: layers/pooling.md
|
||||
- Recurrent Layers: layers/recurrent.md
|
||||
- Embedding Layers: layers/embeddings.md
|
||||
- Advanced Activations Layers: layers/advanced-activations.md
|
||||
|
||||
externo
+1
@@ -30,6 +30,7 @@ model.add(Activation(tanh))
|
||||
|
||||
- __softmax__: Softmax applied across inputs last dimension. Expects shape either `(nb_samples, nb_timesteps, nb_dims)` or `(nb_samples, nb_dims)`.
|
||||
- __softplus__
|
||||
- __softsign__
|
||||
- __relu__
|
||||
- __tanh__
|
||||
- __sigmoid__
|
||||
|
||||
+93
-9
@@ -10,7 +10,10 @@
|
||||
- [How is the validation split computed?](#how-is-the-validation-split-computed)
|
||||
- [Is the data shuffled during training?](#is-the-data-shuffled-during-training)
|
||||
- [How can I record the training / validation loss / accuracy at each epoch?](#how-can-i-record-the-training-validation-loss-accuracy-at-each-epoch)
|
||||
- [How can I "freeze" layers?](#how-can-i-freeze-keras-layers)
|
||||
- [How can I use stateful RNNs?](#how-can-i-use-stateful-rnns)
|
||||
- [How can I remove a layer from a Sequential model?](#how-can-i-remove-a-layer-from-a-sequential-model)
|
||||
- [How can I use pre-trained models in Keras?](#how-can-i-use-pre-trained-models-in-keras)
|
||||
|
||||
---
|
||||
|
||||
@@ -20,12 +23,11 @@ Please cite Keras in your publications if it helps your research. Here is an exa
|
||||
|
||||
```
|
||||
@misc{chollet2015keras,
|
||||
author = {Chollet, François},
|
||||
title = {Keras},
|
||||
year = {2015},
|
||||
publisher = {GitHub},
|
||||
journal = {GitHub repository},
|
||||
howpublished = {\url{https://github.com/fchollet/keras}}
|
||||
title={Keras},
|
||||
author={Chollet, Fran\c{c}ois},
|
||||
year={2015},
|
||||
publisher={GitHub},
|
||||
howpublished={\url{https://github.com/fchollet/keras}},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -139,14 +141,28 @@ to pass the learning phase flag to your function:
|
||||
get_3rd_layer_output = K.function([model.layers[0].input, K.learning_phase()],
|
||||
[model.layers[3].output])
|
||||
|
||||
# output in train mode = 0
|
||||
# output in test mode = 0
|
||||
layer_output = get_3rd_layer_output([X, 0])[0]
|
||||
|
||||
# output in test mode = 1
|
||||
# output in train mode = 1
|
||||
layer_output = get_3rd_layer_output([X, 1])[0]
|
||||
```
|
||||
|
||||
Another more flexible way of getting output from intermediate layers is to use the [functional API](/getting-started/functional-api-guide).
|
||||
Another more flexible way of getting output from intermediate layers is to use the [functional API](/getting-started/functional-api-guide). For example, if you have created an autoencoder for MNIST:
|
||||
|
||||
```python
|
||||
inputs = Input(shape=(784,))
|
||||
encoded = Dense(32, activation='relu')(inputs)
|
||||
decoded = Dense(784)(encoded)
|
||||
model = Model(input=inputs, output=decoded)
|
||||
```
|
||||
|
||||
After compiling and training the model, you can get the output of the data from the encoder like this:
|
||||
|
||||
```python
|
||||
encoder = Model(input=inputs, output=encoded)
|
||||
X_encoded = encoder.predict(X)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -201,6 +217,40 @@ print(hist.history)
|
||||
|
||||
---
|
||||
|
||||
### How can I "freeze" Keras layers?
|
||||
|
||||
To "freeze" a layer means to exclude it from training, i.e. its weights will never be updated. This is useful in the context of fine-tuning a model, or using fixed embeddings for a text input.
|
||||
|
||||
You can pass a `trainable` argument (boolean) to a layer constructor to set a layer to be non-trainable:
|
||||
|
||||
```python
|
||||
frozen_layer = Dense(32, trainable=False)
|
||||
```
|
||||
|
||||
Additionally, you can set the `trainable` property of a layer to `True` or `False` after instantiation. For this to take effect, you will need to call `compile()` on your model after modifying the `trainable` property. Here's an example:
|
||||
|
||||
```python
|
||||
x = Input(shape=(32,))
|
||||
layer = Dense(32)
|
||||
layer.trainable = False
|
||||
y = layer(x)
|
||||
|
||||
frozen_model = Model(x, y)
|
||||
# in the model below, the weights of `layer` will not be updated during training
|
||||
frozen_model.compile(optimizer='rmsprop', loss='mse')
|
||||
|
||||
layer.trainable = True
|
||||
trainable_model = Model(x, y)
|
||||
# with this model the weights of the layer will be updated during training
|
||||
# (which will also affect the above model since it uses the same layer instance)
|
||||
trainable_model.compile(optimizer='rmsprop', loss='mse')
|
||||
|
||||
frozen_model.fit(data, labels) # this does NOT update the weights of `layer`
|
||||
trainable_model.fit(data, labels) # this updates the weights of `layer`
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### How can I use stateful RNNs?
|
||||
|
||||
Making a RNN stateful means that the states for the samples of each batch will be reused as initial states for the samples in the next batch.
|
||||
@@ -248,3 +298,37 @@ model.layers[0].reset_states()
|
||||
|
||||
Notes that the methods `predict`, `fit`, `train_on_batch`, `predict_classes`, etc. will *all* update the states of the stateful layers in a model. This allows you to do not only stateful training, but also stateful prediction.
|
||||
|
||||
---
|
||||
|
||||
### How can I remove a layer from a Sequential model?
|
||||
|
||||
You can remove the last added layer in a Sequential model by calling `.pop()`:
|
||||
|
||||
```python
|
||||
model = Sequential()
|
||||
model.add(Dense(32, activation='relu', input_dim=784))
|
||||
model.add(Dense(32, activation='relu'))
|
||||
|
||||
print(len(model.layers)) # "2"
|
||||
|
||||
model.pop()
|
||||
print(len(model.layers)) # "1"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### How can I use pre-trained models in Keras?
|
||||
|
||||
Code and pre-trained weights are available for the following image classification models:
|
||||
|
||||
- [VGG-16](https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
|
||||
- [VGG-19](https://gist.github.com/baraldilorenzo/8d096f48a1be4a2d660d)
|
||||
- [AlexNet](https://github.com/heuritech/convnets-keras)
|
||||
|
||||
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).
|
||||
|
||||
The VGG-16 model is also the basis for several Keras example scripts:
|
||||
|
||||
- [Style transfer](https://github.com/fchollet/keras/blob/master/examples/neural_style_transfer.py)
|
||||
- [Feature visualization](https://github.com/fchollet/keras/blob/master/examples/conv_filter_visualization.py)
|
||||
- [Deep dream](https://github.com/fchollet/keras/blob/master/examples/deep_dream.py)
|
||||
|
||||
@@ -166,7 +166,7 @@ Let's consider a dataset of tweets. We want to build a model that can tell wheth
|
||||
|
||||
One way to achieve this is to build a model that encodes two tweets into two vectors, concatenates the vectors and adds a logistic regression of top, outputting a probability that the two tweets share the same author. The model would then be trained on positive tweet pairs and negative tweet pairs.
|
||||
|
||||
Because the problem is symetric, the mechanism that encodes the first tweet should be reused (weights and all) to encode the second tweet. Here we use a shared LSTM layer to encode the tweets.
|
||||
Because the problem is symmetric, the mechanism that encodes the first tweet should be reused (weights and all) to encode the second tweet. Here we use a shared LSTM layer to encode the tweets.
|
||||
|
||||
Let's build this with the functional API. We will take as input for a tweet a binary matrix of shape `(140, 256)`, i.e. a sequence of 140 vectors of size 256, where each dimension in the 256-dimensional vector encodes the presence/absence of a character (out of an alphabet of 256 frequent characters).
|
||||
|
||||
@@ -309,8 +309,8 @@ from keras.layers import merge, Convolution2D, Input
|
||||
|
||||
# input tensor for a 3-channel 256x256 image
|
||||
x = Input(shape=(3, 256, 256))
|
||||
# 3x3 conv with 16 output channels
|
||||
y = Convolution2D(16, 3, 3, border_mode='same')
|
||||
# 3x3 conv with 3 output channels (same as input channels)
|
||||
y = Convolution2D(3, 3, 3, border_mode='same')
|
||||
# this returns x + y.
|
||||
z = merge([x, y], mode='sum')
|
||||
```
|
||||
|
||||
@@ -6,6 +6,7 @@ You can create a `Sequential` model by passing a list of layer instances to the
|
||||
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Activation
|
||||
|
||||
model = Sequential([
|
||||
Dense(32, input_dim=784),
|
||||
@@ -87,6 +88,13 @@ final_model.add(Dense(10, activation='softmax'))
|
||||
|
||||
<img src="http://s3.amazonaws.com/keras.io/img/two_branches_sequential_model.png" alt="two branch Sequential" style="width: 400px;"/>
|
||||
|
||||
Such a two-branch model can then be trained via e.g.:
|
||||
|
||||
```python
|
||||
final_model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
|
||||
final_model.fit([input_data_1, input_data_2], targets) # we pass one data array per model input
|
||||
```
|
||||
|
||||
The `Merge` layer supports a number of pre-defined modes:
|
||||
|
||||
- `sum` (default): element-wise sum
|
||||
@@ -373,7 +381,7 @@ image_model.load_weights('weight_file.h5')
|
||||
language_model = Sequential()
|
||||
language_model.add(Embedding(vocab_size, 256, input_length=max_caption_len))
|
||||
language_model.add(GRU(output_dim=128, return_sequences=True))
|
||||
language_model.add(TimeDistributedDense(128))
|
||||
language_model.add(TimeDistributed(Dense(128)))
|
||||
|
||||
# let's repeat the image vector to turn it into a sequence.
|
||||
image_model.add(RepeatVector(max_caption_len))
|
||||
|
||||
externo
+2
-2
@@ -36,7 +36,7 @@ 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 function API](http://keras.io/getting-started/functional-api-guide).
|
||||
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).
|
||||
|
||||
Here's the `Sequential` model:
|
||||
|
||||
@@ -49,7 +49,7 @@ model = Sequential()
|
||||
Stacking layers is as easy as `.add()`:
|
||||
|
||||
```python
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.layers import Dense, Activation
|
||||
|
||||
model.add(Dense(output_dim=64, input_dim=100))
|
||||
model.add(Activation("relu"))
|
||||
|
||||
+28
-1
@@ -1,7 +1,7 @@
|
||||
|
||||
## Usage of initializations
|
||||
|
||||
Initializations define the probability distribution used to set the initial random weights of Keras layers.
|
||||
Initializations define the way to set the initial random weights of Keras layers.
|
||||
|
||||
The keyword arguments used for passing initializations to layers will depend on the layer. Usually it is simply `init`:
|
||||
|
||||
@@ -21,3 +21,30 @@ model.add(Dense(64, init='uniform'))
|
||||
- __glorot_uniform__
|
||||
- __he_normal__: Gaussian initialization scaled by fan_in (He et al., 2014)
|
||||
- __he_uniform__
|
||||
|
||||
|
||||
An initialization may be passed as a string (must match one of the available initializations above), or as a callable.
|
||||
If a callable, then it must take two arguments: `shape` (shape of the variable to initialize) and `name` (name of the variable),
|
||||
and it must return a variable (e.g. output of `K.variable()`):
|
||||
|
||||
```python
|
||||
from keras import backend as K
|
||||
import numpy as np
|
||||
|
||||
def my_init(shape, name=None):
|
||||
value = np.random.random(shape)
|
||||
return K.variable(value, name=name)
|
||||
|
||||
model.add(Dense(64, init=my_init))
|
||||
```
|
||||
|
||||
You could also use functions from `keras.initializations` in this way:
|
||||
|
||||
```python
|
||||
from keras import initializations
|
||||
|
||||
def my_init(shape, name=None):
|
||||
return initializations.normal(shape, scale=0.01, name=name)
|
||||
|
||||
model.add(Dense(64, init=my_init))
|
||||
```
|
||||
@@ -0,0 +1,34 @@
|
||||
# Writing your own Keras layers
|
||||
|
||||
For simple, stateless custom operations, you are probably better off using `layers.core.Lambda` layers. But for any custom operation that has trainable weights, you should implement your own layer.
|
||||
|
||||
Here is the skeleton of a Keras layer. There are only three methods you need to implement:
|
||||
|
||||
- `build(input_shape)`: this is where you will define your weights. Trainable weights should be added to the list `self.trainable_weights`. Other attributes of note are: `self.non_trainable_weights` (list) and `self.updates` (list of update tuples (tensor, new_tensor)). For an example of how to use `non_trainable_weights` and `updates`, see the code for the `BatchNormalization` layer.
|
||||
- `call(x)`: this is where the layer's logic lives. Unless you want your layer to support masking, you only have to care about the first argument passed to `call`: the input tensor.
|
||||
- `get_output_shape_for(input_shape)`: in case your layer modifies the shape of its input, you should specify here the shape transformation logic. This allows Keras to do automatic shape inference.
|
||||
|
||||
```python
|
||||
from keras import backend as K
|
||||
from keras.engine.topology import Layer
|
||||
import numpy as np
|
||||
|
||||
class MyLayer(Layer):
|
||||
def __init__(self, output_dim, **kwargs):
|
||||
self.output_dim = output_dim
|
||||
super(MyLayer, self).__init__(**kwargs)
|
||||
|
||||
def build(self, input_shape):
|
||||
input_dim = input_shape[1]
|
||||
initial_weight_value = np.random.random((input_dim, output_dim))
|
||||
self.W = K.variable(initial_weight_value)
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
def call(self, x, mask=None):
|
||||
return K.dot(x, self.W)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
return (input_shape[0], self.output_dim)
|
||||
```
|
||||
|
||||
The existing Keras layers provide ample examples of how to implement almost anything. Never hesitate to read the source code!
|
||||
externo
+3
-2
@@ -27,5 +27,6 @@ For a few examples of such functions, check out the [objectives source](https://
|
||||
- __binary_crossentropy__: Also known as logloss.
|
||||
- __categorical_crossentropy__: Also known as multiclass logloss. __Note__: using this objective requires that your labels are binary arrays of shape `(nb_samples, nb_classes)`.
|
||||
- __sparse_categorical_crossentropy__: As above but accepts sparse labels. __Note__: this objective still requires that your labels have the same number of dimensions as your outputs; you may need to add a length-1 dimension to the shape of your labels, e.g with `np.expand_dims(y, -1)`.
|
||||
- __poisson__: mean of `(predictions - targets * log(predictions))`
|
||||
- __cosine_proximity__: the opposite (negative) of the mean cosine proximity between predictions and targets.
|
||||
- __kullback_leibler_divergence__ / __kld__: Information gain from a predicted probability distribution Q to a true probability distribution P. Gives a measure of difference between both distributions.
|
||||
- __poisson__: Mean of `(predictions - targets * log(predictions))`
|
||||
- __cosine_proximity__: The opposite (negative) of the mean cosine proximity between predictions and targets.
|
||||
|
||||
+74
-11
@@ -2,18 +2,23 @@
|
||||
## ImageDataGenerator
|
||||
|
||||
```python
|
||||
keras.preprocessing.image.ImageDataGenerator(featurewise_center=True,
|
||||
keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,
|
||||
samplewise_center=False,
|
||||
featurewise_std_normalization=True,
|
||||
featurewise_std_normalization=False,
|
||||
samplewise_std_normalization=False,
|
||||
zca_whitening=False,
|
||||
rotation_range=0.,
|
||||
width_shift_range=0.,
|
||||
height_shift_range=0.,
|
||||
shear_range=0.,
|
||||
zoom_range=0.,
|
||||
channel_shift_range=0.,
|
||||
fill_mode='nearest',
|
||||
cval=0.,
|
||||
horizontal_flip=False,
|
||||
vertical_flip=False,
|
||||
dim_ordering='th')
|
||||
rescale=None,
|
||||
dim_ordering=K.image_dim_ordering())
|
||||
```
|
||||
|
||||
Generate batches of tensor image data with real-time data augmentation. The data will be looped over (in batches) indefinitely.
|
||||
@@ -30,31 +35,58 @@ Generate batches of tensor image data with real-time data augmentation. The data
|
||||
- __shear_range__: Float. Shear Intensity (Shear angle in counter-clockwise direction as radians)
|
||||
- __zoom_range__: Float or [lower, upper]. Range for random zoom. If a float, `[lower, upper] = [1-zoom_range, 1+zoom_range]`.
|
||||
- __channel_shift_range__: Float. Range for random channel shifts.
|
||||
- __fill_mode__: One of {"constant", "nearest", "reflect" or "wrap"}.
|
||||
- __cval__: Float or Int. Value used for points outside the boundaries when `fill_mode` is "constant".
|
||||
- __fill_mode__: One of {"constant", "nearest", "reflect" or "wrap"}. Points outside the boundaries of the input are filled according to the given mode.
|
||||
- __cval__: Float or Int. Value used for points outside the boundaries when `fill_mode = "constant"`.
|
||||
- __horizontal_flip__: Boolean. Randomly flip inputs horizontally.
|
||||
- __vertical_flip__: Boolean. Randomly flip inputs vertically.
|
||||
- __rescale__: rescaling factor. Defaults to None. If None or 0, no rescaling is applied,
|
||||
otherwise we multiply the data by the value provided (before applying
|
||||
any other transformation).
|
||||
- __dim_ordering__: One of {"th", "tf"}.
|
||||
"tf" mode means that the images should have shape `(samples, width, height, channels)`,
|
||||
"th" mode means that the images should have shape `(samples, channels, width, height)`.
|
||||
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".
|
||||
|
||||
- __Methods__:
|
||||
- __fit(X)__: Required if featurewise_center or featurewise_std_normalization or zca_whitening. Compute necessary quantities on some sample data.
|
||||
- __fit(X)__: Compute the internal data stats related to the data-dependent transformations, based on an array of sample data.
|
||||
Only required if featurewise_center or featurewise_std_normalization or zca_whitening.
|
||||
- __Arguments__:
|
||||
- __X__: sample data.
|
||||
- __augment__: Boolean (default: False). Whether to fit on randomly augmented samples.
|
||||
- __rounds__: int (default: 1). If augment, how many augmentation passes over the data to use.
|
||||
- __flow(X, y)__:
|
||||
- __flow(X, y)__: Takes numpy data & label arrays, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
|
||||
- __Arguments__:
|
||||
- __X__: data.
|
||||
- __y__: labels.
|
||||
- __batch_size__: int (default: 32).
|
||||
- __shuffle__: boolean (defaut: False).
|
||||
- __save_to_dir__: None or str. 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. Prefix to use for filenames of saved pictures.
|
||||
- __save_format__: one of "png", jpeg".
|
||||
- __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.
|
||||
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,
|
||||
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.
|
||||
- __classes__: optional list of class subdirectories (e.g. `['dogs', 'cats']`). Default: None. If not provided, the list of classes will be automatically inferred (and the order of the classes, which will map to the label indices, will be alphanumeric).
|
||||
- __class_mode__: one of "categorical", "binary", "sparse" or None. Default: "categorical". Determines the type of label arrays that are returned: "categorical" will be 2D one-hot encoded labels, "binary" will be 1D binary labels, "sparse" will be 1D integer labels. If None, no labels are returned (the generator will only yield batches of image data, which is useful to use `model.predict_generator()`, `model.evaluate_generator()`, etc.).
|
||||
- __batch_size__: size of the batches of data (default: 32).
|
||||
- __shuffle__: whether to shuffle the data (default: True)
|
||||
- __seed__: optional random seed for shuffling.
|
||||
- __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. 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".
|
||||
|
||||
|
||||
- __Examples__:
|
||||
|
||||
Example of using `.flow(X, y)`:
|
||||
|
||||
- __Example__:
|
||||
```python
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data(test_split=0.1)
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
@@ -88,3 +120,34 @@ for e in range(nb_epoch):
|
||||
# the generator loops indefinitely
|
||||
break
|
||||
```
|
||||
|
||||
Example of using `.flow_from_directory(directory)`:
|
||||
|
||||
```python
|
||||
train_datagen = ImageDataGenerator(
|
||||
rescale=1./255,
|
||||
shear_range=0.2,
|
||||
zoom_range=0.2,
|
||||
horizontal_flip=True)
|
||||
|
||||
test_datagen = ImageDataGenerator(rescale=1./255)
|
||||
|
||||
train_generator = train_datagen.flow_from_directory(
|
||||
'data/train',
|
||||
target_size=(150, 150),
|
||||
batch_size=32,
|
||||
class_mode='binary')
|
||||
|
||||
validation_generator = test_datagen.flow_from_directory(
|
||||
'data/validation',
|
||||
target_size=(150, 150),
|
||||
batch_size=32,
|
||||
class_mode='binary')
|
||||
|
||||
model.fit_generator(
|
||||
train_generator,
|
||||
samples_per_epoch=2000,
|
||||
nb_epoch=50,
|
||||
validation_data=validation_generator,
|
||||
nb_val_samples=800)
|
||||
```
|
||||
|
||||
+10
-10
@@ -4,14 +4,14 @@
|
||||
keras.preprocessing.sequence.pad_sequences(sequences, maxlen=None, dtype='int32')
|
||||
```
|
||||
|
||||
Transform a list of `nb_samples sequences` (lists of scalars) into a 2D numpy array of shape `(nb_samples, nb_timesteps)`. `nb_timesteps` is either the `maxlen` argument if provided, or the length of the longest sequence otherwise. Sequences that are shorter than `nb_timesteps` are padded with zeros at the end.
|
||||
Transform a list of `nb_samples sequences` (lists of scalars) into a 2D Numpy array of shape `(nb_samples, nb_timesteps)`. `nb_timesteps` is either the `maxlen` argument if provided, or the length of the longest sequence otherwise. Sequences that are shorter than `nb_timesteps` are padded with zeros at the end.
|
||||
|
||||
- __Return__: 2D numpy array of shape `(nb_samples, nb_timesteps)`.
|
||||
- __Return__: 2D Numpy array of shape `(nb_samples, nb_timesteps)`.
|
||||
|
||||
- __Arguments__:
|
||||
- __sequences__: List of lists of int or float.
|
||||
- __maxlen__: None or int. Maximum sequence length, longer sequences are truncated and shorter sequences are padded with zeros at the end.
|
||||
- __dtype__: datatype of the numpy array returned.
|
||||
- __dtype__: datatype of the Numpy array returned.
|
||||
- __padding__: 'pre' or 'post', pad either before or after each sequence.
|
||||
- __truncating__: 'pre' or 'post', remove values from sequences larger than maxlen either in the beginning or in the end of the sequence
|
||||
- __value__: float, value to pad the sequences to the desired value.
|
||||
@@ -21,12 +21,12 @@ Transform a list of `nb_samples sequences` (lists of scalars) into a 2D numpy ar
|
||||
## skipgrams
|
||||
|
||||
```python
|
||||
keras.preprocessing.sequence.skipgrams(sequence, vocabulary_size,
|
||||
window_size=4, negative_samples=1., shuffle=True,
|
||||
keras.preprocessing.sequence.skipgrams(sequence, vocabulary_size,
|
||||
window_size=4, negative_samples=1., shuffle=True,
|
||||
categorical=False, sampling_table=None)
|
||||
```
|
||||
|
||||
Transforms a sequence of word indexes (list of int) into couples of the form:
|
||||
Transforms a sequence of word indexes (list of int) into couples of the form:
|
||||
|
||||
- (word, word in the same window), with label 1 (positive samples).
|
||||
- (word, random word from the vocabulary), with label 0 (negative samples).
|
||||
@@ -34,8 +34,8 @@ Transforms a sequence of word indexes (list of int) into couples of the form:
|
||||
Read more about Skipgram in this gnomic paper by Mikolov et al.: [Efficient Estimation of Word Representations in
|
||||
Vector Space](http://arxiv.org/pdf/1301.3781v3.pdf)
|
||||
|
||||
- __Return__: tuple `(couples, labels)`.
|
||||
- `couples` is a list of 2-elements lists of int: `[word_index, other_word_index]`.
|
||||
- __Return__: tuple `(couples, labels)`.
|
||||
- `couples` is a list of 2-elements lists of int: `[word_index, other_word_index]`.
|
||||
- `labels` is a list of 0 and 1, where 1 indicates that `other_word_index` was found in the same window as `word_index`, and 0 indicates that `other_word_index` was random.
|
||||
- if categorical is set to True, the labels are categorical, ie. 1 becomes [0,1], and 0 becomes [1, 0].
|
||||
|
||||
@@ -46,7 +46,7 @@ Vector Space](http://arxiv.org/pdf/1301.3781v3.pdf)
|
||||
- __negative_samples__: float >= 0. 0 for no negative (=random) samples. 1 for same number as positive samples. etc.
|
||||
- __shuffle__: boolean. Whether to shuffle the samples.
|
||||
- __categorical__: boolean. Whether to make the returned labels categorical.
|
||||
- __sampling_table__: numpy array of shape `(vocabulary_size,)` where `sampling_table[i]` is the probability of sampling the word with index i (assumed to be i-th most common word in the dataset).
|
||||
- __sampling_table__: Numpy array of shape `(vocabulary_size,)` where `sampling_table[i]` is the probability of sampling the word with index i (assumed to be i-th most common word in the dataset).
|
||||
|
||||
|
||||
---
|
||||
@@ -59,7 +59,7 @@ keras.preprocessing.sequence.make_sampling_table(size, sampling_factor=1e-5)
|
||||
|
||||
Used for generating the `sampling_table` argument for `skipgrams`. `sampling_table[i]` is the probability of sampling the word i-th most common word in a dataset (more common words should be sampled less frequently, for balance).
|
||||
|
||||
- __Return__: numpy array of shape `(size,)`.
|
||||
- __Return__: Numpy array of shape `(size,)`.
|
||||
|
||||
- __Arguments__:
|
||||
- __size__: size of the vocabulary considered.
|
||||
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
# Wrappers for the Sciki-Learn API
|
||||
# Wrappers for the Scikit-Learn API
|
||||
|
||||
You can use `Sequential` Keras models (single-input only) as part of your Scikit-Learn workflow via the wrappers found at `keras.wrappers.sklearn.py`.
|
||||
|
||||
@@ -25,7 +25,7 @@ present class will then be treated as the default build_fn.
|
||||
|
||||
`sk_params` takes both model parameters and fitting parameters. Legal model
|
||||
parameters are the arguments of `build_fn`. Note that like all other
|
||||
estimators in scikit-learn, 'build_fn' should provide defalult values for
|
||||
estimators in scikit-learn, 'build_fn' should provide default values for
|
||||
its arguments, so that you could create the estimator without passing any
|
||||
values to `sk_params`.
|
||||
|
||||
@@ -42,4 +42,4 @@ fitting (predicting) parameters are selected in the following order:
|
||||
When using scikit-learn's `grid_search` API, legal tunable parameters are
|
||||
those you could pass to `sk_params`, including fitting parameters.
|
||||
In other words, you could use `grid_search` to search for the best
|
||||
`batch_size` or `nb_epoch` as well as the model parameters.
|
||||
`batch_size` or `nb_epoch` as well as the model parameters.
|
||||
|
||||
externo
+2
-1
@@ -10,9 +10,10 @@ from keras.utils.visualize_util import plot
|
||||
plot(model, to_file='model.png')
|
||||
```
|
||||
|
||||
`plot` takes one optional arguments:
|
||||
`plot` takes two optional arguments:
|
||||
|
||||
- `show_shapes` (defaults to False) controls whether output shapes are shown in the graph.
|
||||
- `show_layer_names` (defaults to True) controls whether layer names are shown in the graph.
|
||||
|
||||
You can also directly obtain the `pydot.Graph` object and render it yourself,
|
||||
for example to show it in an ipython notebook :
|
||||
|
||||
@@ -29,8 +29,7 @@ Five digits inverted:
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.engine.training import slice_X
|
||||
from keras.layers.core import Activation, TimeDistributedDense, RepeatVector
|
||||
from keras.layers import recurrent
|
||||
from keras.layers import Activation, TimeDistributed, Dense, RepeatVector, recurrent
|
||||
import numpy as np
|
||||
from six.moves import range
|
||||
|
||||
@@ -40,7 +39,7 @@ class CharacterTable(object):
|
||||
Given a set of characters:
|
||||
+ Encode them to a one hot integer representation
|
||||
+ Decode the one hot integer representation to their character output
|
||||
+ Decode a vector of probabilties to their character output
|
||||
+ Decode a vector of probabilities to their character output
|
||||
'''
|
||||
def __init__(self, chars, maxlen):
|
||||
self.chars = sorted(set(chars))
|
||||
@@ -140,7 +139,7 @@ for _ in range(LAYERS):
|
||||
model.add(RNN(HIDDEN_SIZE, return_sequences=True))
|
||||
|
||||
# For each of step of the output sequence, decide which character should be chosen
|
||||
model.add(TimeDistributedDense(len(chars)))
|
||||
model.add(TimeDistributed(Dense(len(chars))))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
|
||||
@@ -12,7 +12,7 @@ backend (`K`), our code can run both on TensorFlow and Theano.
|
||||
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Layer, Activation
|
||||
from keras.layers import Dense, Dropout, Layer, Activation
|
||||
from keras.datasets import mnist
|
||||
from keras import backend as K
|
||||
from keras.utils import np_utils
|
||||
|
||||
@@ -16,8 +16,8 @@ Time per epoch: 3s on CPU (core i7).
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.core import Activation, Dense, Merge, Permute, Dropout
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers import Activation, Dense, Merge, Permute, Dropout
|
||||
from keras.layers import LSTM
|
||||
from keras.utils.data_utils import get_file
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
from functools import reduce
|
||||
@@ -94,8 +94,13 @@ def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
|
||||
pad_sequences(Xq, maxlen=query_maxlen), np.array(Y))
|
||||
|
||||
|
||||
path = get_file('babi-tasks-v1-2.tar.gz',
|
||||
origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/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'
|
||||
'$ mv tasks_1-20_v1-2.tar.gz ~/.keras/datasets/babi-tasks-v1-2.tar.gz')
|
||||
raise
|
||||
tar = tarfile.open(path)
|
||||
|
||||
challenges = {
|
||||
|
||||
@@ -66,7 +66,7 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.utils.data_utils import get_file
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.core import Dense, Merge, Dropout, RepeatVector
|
||||
from keras.layers import Dense, Merge, Dropout, RepeatVector
|
||||
from keras.layers import recurrent
|
||||
from keras.models import Sequential
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
@@ -146,7 +146,13 @@ BATCH_SIZE = 32
|
||||
EPOCHS = 40
|
||||
print('RNN / Embed / Sent / Query = {}, {}, {}, {}'.format(RNN, EMBED_HIDDEN_SIZE, SENT_HIDDEN_SIZE, QUERY_HIDDEN_SIZE))
|
||||
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/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'
|
||||
'$ mv tasks_1-20_v1-2.tar.gz ~/.keras/datasets/babi-tasks-v1-2.tar.gz')
|
||||
raise
|
||||
tar = tarfile.open(path)
|
||||
# Default QA1 with 1000 samples
|
||||
# challenge = 'tasks_1-20_v1-2/en/qa1_single-supporting-fact_{}.txt'
|
||||
|
||||
@@ -15,8 +15,8 @@ from __future__ import print_function
|
||||
from keras.datasets import cifar10
|
||||
from keras.preprocessing.image import ImageDataGenerator
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.optimizers import SGD
|
||||
from keras.utils import np_utils
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ e.g.:
|
||||
python deep_dream.py img/mypic.jpg results/dream
|
||||
```
|
||||
|
||||
It is preferrable to run this script on GPU, for speed.
|
||||
It is preferable to run this script on GPU, for speed.
|
||||
If running on CPU, prefer the TensorFlow backend (much faster).
|
||||
|
||||
Example results: http://i.imgur.com/FX6ROg9.jpg
|
||||
@@ -24,7 +24,7 @@ import h5py
|
||||
import os
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.convolutional import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras import backend as K
|
||||
|
||||
parser = argparse.ArgumentParser(description='Deep Dreams with Keras.')
|
||||
@@ -189,7 +189,7 @@ def eval_loss_and_grads(x):
|
||||
class Evaluator(object):
|
||||
def __init__(self):
|
||||
self.loss_value = None
|
||||
self.grads_values = None
|
||||
self.grad_values = None
|
||||
|
||||
def loss(self, x):
|
||||
assert self.loss_value is None
|
||||
|
||||
@@ -12,9 +12,9 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Lambda
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.convolutional import Convolution1D
|
||||
from keras.layers import Dense, Dropout, Activation, Lambda
|
||||
from keras.layers import Embedding
|
||||
from keras.layers import Convolution1D
|
||||
from keras.datasets import imdb
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, GRU, SimpleRNN
|
||||
from keras.layers.convolutional import Convolution1D, MaxPooling1D
|
||||
from keras.layers import Dense, Dropout, Activation
|
||||
from keras.layers import Embedding
|
||||
from keras.layers import LSTM, GRU, SimpleRNN
|
||||
from keras.layers import Convolution1D, MaxPooling1D
|
||||
from keras.datasets import imdb
|
||||
|
||||
|
||||
|
||||
@@ -19,9 +19,8 @@ np.random.seed(1337) # for reproducibility
|
||||
from keras.preprocessing import sequence
|
||||
from keras.utils import np_utils
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, SimpleRNN, GRU
|
||||
from keras.layers import Dense, Dropout, Activation, Embedding
|
||||
from keras.layers import LSTM, SimpleRNN, GRU
|
||||
from keras.datasets import imdb
|
||||
|
||||
max_features = 20000
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
'''Compare LSTM implementations on the IMDB sentiment classification task.
|
||||
|
||||
consume_less='cpu' preprocesses input to the LSTM which typically results in
|
||||
faster computations at the expense of increased peak memory usage as the
|
||||
preprocessed input must be kept in memory.
|
||||
|
||||
consume_less='mem' does away with the preprocessing, meaning that it might take
|
||||
a little longer, but should require less peak memory.
|
||||
|
||||
consume_less='gpu' concatenates the input, output and forget gate's weights
|
||||
into one, large matrix, resulting in faster computation time as the GPU can
|
||||
utilize more cores, at the expense of reduced regularization because the same
|
||||
dropout is shared across the gates.
|
||||
|
||||
Note that the relative performance of the different `consume_less` modes
|
||||
can vary depending on your device, your model and the size of your data.
|
||||
'''
|
||||
|
||||
import time
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Embedding, Dense, LSTM
|
||||
from keras.datasets import imdb
|
||||
|
||||
max_features = 20000
|
||||
max_length = 80
|
||||
embedding_dim = 256
|
||||
batch_size = 128
|
||||
epochs = 10
|
||||
modes = ['cpu', 'mem', 'gpu']
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
X_train = sequence.pad_sequences(X_train, max_length)
|
||||
X_test = sequence.pad_sequences(X_test, max_length)
|
||||
|
||||
# Compile and train different models while meauring performance.
|
||||
results = []
|
||||
for mode in modes:
|
||||
print('Testing mode: consume_less="{}"'.format(mode))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, embedding_dim, input_length=max_length, dropout=0.2))
|
||||
model.add(LSTM(embedding_dim, dropout_W=0.2, dropout_U=0.2, consume_less=mode))
|
||||
model.add(Dense(1, activation='sigmoid'))
|
||||
model.compile(loss='binary_crossentropy',
|
||||
optimizer='adam',
|
||||
metrics=['accuracy'])
|
||||
|
||||
start_time = time.time()
|
||||
history = model.fit(X_train, y_train,
|
||||
batch_size=batch_size,
|
||||
nb_epoch=epochs,
|
||||
validation_data=(X_test, y_test))
|
||||
average_time_per_epoch = (time.time() - start_time) / epochs
|
||||
|
||||
results.append((history, average_time_per_epoch))
|
||||
|
||||
# Compare models' accuracy, loss and elapsed time per epoch.
|
||||
plt.style.use('ggplot')
|
||||
ax1 = plt.subplot2grid((2, 2), (0, 0))
|
||||
ax1.set_title('Accuracy')
|
||||
ax1.set_ylabel('Validation Accuracy')
|
||||
ax1.set_xlabel('Epochs')
|
||||
ax2 = plt.subplot2grid((2, 2), (1, 0))
|
||||
ax2.set_title('Loss')
|
||||
ax2.set_ylabel('Validation Loss')
|
||||
ax2.set_xlabel('Epochs')
|
||||
ax3 = plt.subplot2grid((2, 2), (0, 1), rowspan=2)
|
||||
ax3.set_title('Time')
|
||||
ax3.set_ylabel('Seconds')
|
||||
for mode, result in zip(modes, results):
|
||||
ax1.plot(result[0].epoch, result[0].history['val_acc'], label=mode)
|
||||
ax2.plot(result[0].epoch, result[0].history['val_loss'], label=mode)
|
||||
ax1.legend()
|
||||
ax2.legend()
|
||||
ax3.bar(np.arange(len(results)), [x[1] for x in results],
|
||||
tick_label=modes, align='center')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
@@ -12,8 +12,8 @@ has at least ~100k characters. ~1M is better.
|
||||
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation, Dropout
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers import Dense, Activation, Dropout
|
||||
from keras.layers import LSTM
|
||||
from keras.utils.data_utils import get_file
|
||||
import numpy as np
|
||||
import random
|
||||
@@ -23,7 +23,7 @@ path = get_file('nietzsche.txt', origin="https://s3.amazonaws.com/text-datasets/
|
||||
text = open(path).read().lower()
|
||||
print('corpus length:', len(text))
|
||||
|
||||
chars = set(text)
|
||||
chars = sorted(list(set(text)))
|
||||
print('total chars:', len(chars))
|
||||
char_indices = dict((c, i) for i, c in enumerate(chars))
|
||||
indices_char = dict((i, c) for i, c in enumerate(chars))
|
||||
@@ -51,7 +51,6 @@ for i, sentence in enumerate(sentences):
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(LSTM(512, return_sequences=True, input_shape=(maxlen, len(chars))))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(LSTM(512, return_sequences=False))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Dense(len(chars)))
|
||||
|
||||
@@ -11,8 +11,8 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
batch_size = 128
|
||||
|
||||
@@ -3,7 +3,7 @@ with pixel-by-pixel sequential MNIST in
|
||||
"A Simple Way to Initialize Recurrent Networks of Rectified Linear Units"
|
||||
by Quoc V. Le, Navdeep Jaitly, Geoffrey E. Hinton
|
||||
|
||||
arXiv:1504.00941v2 [cs.NE] 7 Apr 201
|
||||
arXiv:1504.00941v2 [cs.NE] 7 Apr 2015
|
||||
http://arxiv.org/pdf/1504.00941v2.pdf
|
||||
|
||||
Optimizer is replaced with RMSprop which yields more stable and steady
|
||||
@@ -17,9 +17,9 @@ from __future__ import print_function
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.layers import Dense, Activation
|
||||
from keras.layers import SimpleRNN
|
||||
from keras.initializations import normal, identity
|
||||
from keras.layers.recurrent import SimpleRNN
|
||||
from keras.optimizers import RMSprop
|
||||
from keras.utils import np_utils
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ def euclidean_distance(vects):
|
||||
|
||||
def eucl_dist_output_shape(shapes):
|
||||
shape1, shape2 = shapes
|
||||
return shape1
|
||||
return (shape1[0], 1)
|
||||
|
||||
|
||||
def contrastive_loss(y_true, y_pred):
|
||||
|
||||
@@ -9,8 +9,8 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
from keras.wrappers.scikit_learn import KerasClassifier
|
||||
from sklearn.grid_search import GridSearchCV
|
||||
|
||||
@@ -19,8 +19,8 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ e.g.:
|
||||
python neural_style_transfer.py img/tuebingen.jpg img/starry_night.jpg results/my_result
|
||||
```
|
||||
|
||||
It is preferrable to run this script on GPU, for speed.
|
||||
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
|
||||
@@ -34,7 +34,7 @@ the pixels of the combination image, giving it visual coherence.
|
||||
|
||||
- The style loss is where the deep learning keeps in --that one is defined
|
||||
using a deep convolutional neural network. Precisely, it consists in a sum of
|
||||
L2 distances betwen the Gram matrices of the representations of
|
||||
L2 distances between the Gram matrices of the representations of
|
||||
the base image and the style reference image, extracted from
|
||||
different layers of a convnet (trained on ImageNet). The general idea
|
||||
is to capture color/texture information at different spatial
|
||||
@@ -58,7 +58,7 @@ import argparse
|
||||
import h5py
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.convolutional import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras import backend as K
|
||||
|
||||
parser = argparse.ArgumentParser(description='Neural style transfer with Keras.')
|
||||
|
||||
@@ -8,8 +8,7 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import reuters
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.normalization import BatchNormalization
|
||||
from keras.layers import Dense, Dropout, Activation
|
||||
from keras.utils import np_utils
|
||||
from keras.preprocessing.text import Tokenizer
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ from __future__ import print_function
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers import Dense, LSTM
|
||||
|
||||
|
||||
# since we are using stateful rnn tsteps can be set to 1
|
||||
@@ -75,7 +74,7 @@ for i in range(epochs):
|
||||
print('Predicting')
|
||||
predicted_output = model.predict(cos, batch_size=batch_size)
|
||||
|
||||
print('Ploting Results')
|
||||
print('Plotting Results')
|
||||
plt.subplot(2, 1, 1)
|
||||
plt.plot(expected_output)
|
||||
plt.title('Expected')
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
'''This script demonstrates how to build a variational autoencoder with Keras.
|
||||
|
||||
Reference: "Auto-Encoding Variational Bayes" https://arxiv.org/abs/1312.6114
|
||||
'''
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from keras.layers import Input, Dense, Lambda
|
||||
from keras.models import Model
|
||||
from keras import backend as K
|
||||
from keras import objectives
|
||||
from keras.datasets import mnist
|
||||
|
||||
batch_size = 16
|
||||
original_dim = 784
|
||||
latent_dim = 2
|
||||
intermediate_dim = 128
|
||||
epsilon_std = 0.01
|
||||
nb_epoch = 40
|
||||
|
||||
x = Input(batch_shape=(batch_size, original_dim))
|
||||
h = Dense(intermediate_dim, activation='relu')(x)
|
||||
z_mean = Dense(latent_dim)(h)
|
||||
z_log_std = Dense(latent_dim)(h)
|
||||
|
||||
def sampling(args):
|
||||
z_mean, z_log_std = args
|
||||
epsilon = K.random_normal(shape=(batch_size, latent_dim),
|
||||
mean=0., std=epsilon_std)
|
||||
return z_mean + K.exp(z_log_std) * epsilon
|
||||
|
||||
# note that "output_shape" isn't necessary with the TensorFlow backend
|
||||
# so you could write `Lambda(sampling)([z_mean, z_log_std])`
|
||||
z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_std])
|
||||
|
||||
# we instantiate these layers separately so as to reuse them later
|
||||
decoder_h = Dense(intermediate_dim, activation='relu')
|
||||
decoder_mean = Dense(original_dim, activation='sigmoid')
|
||||
h_decoded = decoder_h(z)
|
||||
x_decoded_mean = decoder_mean(h_decoded)
|
||||
|
||||
def vae_loss(x, x_decoded_mean):
|
||||
xent_loss = objectives.binary_crossentropy(x, x_decoded_mean)
|
||||
kl_loss = - 0.5 * K.mean(1 + z_log_std - K.square(z_mean) - K.exp(z_log_std), axis=-1)
|
||||
return xent_loss + kl_loss
|
||||
|
||||
vae = Model(x, x_decoded_mean)
|
||||
vae.compile(optimizer='rmsprop', loss=vae_loss)
|
||||
|
||||
# train the VAE on MNIST digits
|
||||
(x_train, y_train), (x_test, y_test) = mnist.load_data()
|
||||
|
||||
x_train = x_train.astype('float32') / 255.
|
||||
x_test = x_test.astype('float32') / 255.
|
||||
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
|
||||
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
|
||||
|
||||
vae.fit(x_train, x_train,
|
||||
shuffle=True,
|
||||
nb_epoch=nb_epoch,
|
||||
batch_size=batch_size,
|
||||
validation_data=(x_test, x_test))
|
||||
|
||||
# build a model to project inputs on the latent space
|
||||
encoder = Model(x, z_mean)
|
||||
|
||||
# display a 2D plot of the digit classes in the latent space
|
||||
x_test_encoded = encoder.predict(x_test, batch_size=batch_size)
|
||||
plt.figure(figsize=(6, 6))
|
||||
plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_test)
|
||||
plt.colorbar()
|
||||
plt.show()
|
||||
|
||||
# build a digit generator that can sample from the learned distribution
|
||||
decoder_input = Input(shape=(latent_dim,))
|
||||
_h_decoded = decoder_h(decoder_input)
|
||||
_x_decoded_mean = decoder_mean(_h_decoded)
|
||||
generator = Model(decoder_input, _x_decoded_mean)
|
||||
|
||||
# display a 2D manifold of the digits
|
||||
n = 15 # figure with 15x15 digits
|
||||
digit_size = 28
|
||||
figure = np.zeros((digit_size * n, digit_size * n))
|
||||
# we will sample n points within [-15, 15] standard deviations
|
||||
grid_x = np.linspace(-15, 15, n)
|
||||
grid_y = np.linspace(-15, 15, n)
|
||||
|
||||
for i, yi in enumerate(grid_x):
|
||||
for j, xi in enumerate(grid_y):
|
||||
z_sample = np.array([[xi, yi]]) * epsilon_std
|
||||
x_decoded = generator.predict(z_sample)
|
||||
digit = x_decoded[0].reshape(digit_size, digit_size)
|
||||
figure[i * digit_size: (i + 1) * digit_size,
|
||||
j * digit_size: (j + 1) * digit_size] = digit
|
||||
|
||||
plt.figure(figsize=(10, 10))
|
||||
plt.imshow(figure)
|
||||
plt.show()
|
||||
+2
-1
@@ -1,5 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
__version__ = '1.0.2'
|
||||
from . import backend
|
||||
from . import datasets
|
||||
from . import engine
|
||||
@@ -15,3 +14,5 @@ from . import models
|
||||
from . import objectives
|
||||
from . import optimizers
|
||||
from . import regularizers
|
||||
|
||||
__version__ = '1.0.6'
|
||||
|
||||
@@ -19,6 +19,10 @@ def softplus(x):
|
||||
return K.softplus(x)
|
||||
|
||||
|
||||
def softsign(x):
|
||||
return K.softsign(x)
|
||||
|
||||
|
||||
def relu(x, alpha=0., max_value=None):
|
||||
return K.relu(x, alpha=alpha, max_value=max_value)
|
||||
|
||||
@@ -44,4 +48,6 @@ def linear(x):
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier):
|
||||
if identifier is None:
|
||||
return linear
|
||||
return get_from_module(identifier, globals(), 'activation function')
|
||||
|
||||
@@ -9,6 +9,8 @@ from .common import set_epsilon
|
||||
from .common import set_floatx
|
||||
from .common import get_uid
|
||||
from .common import cast_to_floatx
|
||||
from .common import image_dim_ordering
|
||||
from .common import set_image_dim_ordering
|
||||
|
||||
_keras_base_dir = os.path.expanduser('~')
|
||||
if not os.access(_keras_base_dir, os.W_OK):
|
||||
@@ -28,24 +30,28 @@ if os.path.exists(_config_path):
|
||||
assert type(_epsilon) == float
|
||||
_backend = _config.get('backend', _BACKEND)
|
||||
assert _backend in {'theano', 'tensorflow'}
|
||||
_image_dim_ordering = _config.get('image_dim_ordering', image_dim_ordering())
|
||||
assert _image_dim_ordering in {'tf', 'th'}
|
||||
|
||||
set_floatx(_floatx)
|
||||
set_epsilon(_epsilon)
|
||||
set_image_dim_ordering(_image_dim_ordering)
|
||||
_BACKEND = _backend
|
||||
else:
|
||||
# save config file, for easy edition
|
||||
_config = {'floatx': floatx(),
|
||||
'epsilon': epsilon(),
|
||||
'backend': _BACKEND}
|
||||
with open(_config_path, 'w') as f:
|
||||
# add new line in order for bash 'cat' display the content correctly
|
||||
f.write(json.dumps(_config) + '\n')
|
||||
|
||||
# save config file
|
||||
_config = {'floatx': floatx(),
|
||||
'epsilon': epsilon(),
|
||||
'backend': _BACKEND,
|
||||
'image_dim_ordering': image_dim_ordering()}
|
||||
with open(_config_path, 'w') as f:
|
||||
f.write(json.dumps(_config, indent=4))
|
||||
|
||||
if 'KERAS_BACKEND' in os.environ:
|
||||
_backend = os.environ['KERAS_BACKEND']
|
||||
assert _backend in {'theano', 'tensorflow'}
|
||||
_BACKEND = _backend
|
||||
|
||||
# import backend
|
||||
if _BACKEND == 'theano':
|
||||
sys.stderr.write('Using Theano backend.\n')
|
||||
from .theano_backend import *
|
||||
|
||||
@@ -1,16 +1,25 @@
|
||||
import numpy as np
|
||||
|
||||
from collections import defaultdict
|
||||
|
||||
# the type of float to use throughout the session.
|
||||
_FLOATX = 'float32'
|
||||
_EPSILON = 10e-8
|
||||
_UID_PREFIXES = {}
|
||||
_UID_PREFIXES = defaultdict(int)
|
||||
_IMAGE_DIM_ORDERING = 'th'
|
||||
|
||||
|
||||
def epsilon():
|
||||
'''Returns the value of the fuzz
|
||||
factor used in numeric expressions.
|
||||
'''
|
||||
return _EPSILON
|
||||
|
||||
|
||||
def set_epsilon(e):
|
||||
'''Sets the value of the fuzz
|
||||
factor used in numeric expressions.
|
||||
'''
|
||||
global _EPSILON
|
||||
_EPSILON = e
|
||||
|
||||
@@ -26,8 +35,7 @@ def set_floatx(floatx):
|
||||
global _FLOATX
|
||||
if floatx not in {'float16', 'float32', 'float64'}:
|
||||
raise Exception('Unknown floatx type: ' + str(floatx))
|
||||
floatx = str(floatx)
|
||||
_FLOATX = floatx
|
||||
_FLOATX = str(floatx)
|
||||
|
||||
|
||||
def cast_to_floatx(x):
|
||||
@@ -36,10 +44,23 @@ def cast_to_floatx(x):
|
||||
return np.asarray(x, dtype=_FLOATX)
|
||||
|
||||
|
||||
def image_dim_ordering():
|
||||
'''Returns the image dimension ordering
|
||||
convention ('th' or 'tf').
|
||||
'''
|
||||
return _IMAGE_DIM_ORDERING
|
||||
|
||||
|
||||
def set_image_dim_ordering(dim_ordering):
|
||||
'''Sets the value of the image dimension
|
||||
ordering convention ('th' or 'tf').
|
||||
'''
|
||||
global _IMAGE_DIM_ORDERING
|
||||
if dim_ordering not in {'tf', 'th'}:
|
||||
raise Exception('Unknown dim_ordering:', dim_ordering)
|
||||
_IMAGE_DIM_ORDERING = str(dim_ordering)
|
||||
|
||||
|
||||
def get_uid(prefix=''):
|
||||
if prefix not in _UID_PREFIXES:
|
||||
_UID_PREFIXES[prefix] = 1
|
||||
return 1
|
||||
else:
|
||||
_UID_PREFIXES[prefix] += 1
|
||||
return _UID_PREFIXES[prefix]
|
||||
_UID_PREFIXES[prefix] += 1
|
||||
return _UID_PREFIXES[prefix]
|
||||
|
||||
@@ -3,12 +3,23 @@ import numpy as np
|
||||
import os
|
||||
import copy
|
||||
import warnings
|
||||
from .common import _FLOATX, _EPSILON
|
||||
from .common import _FLOATX, _EPSILON, _IMAGE_DIM_ORDERING
|
||||
|
||||
# INTERNAL UTILS
|
||||
|
||||
_SESSION = None
|
||||
_LEARNING_PHASE = tf.placeholder(dtype='uint8', name='keras_learning_phase') # 0 = test, 1 = train
|
||||
_MANUAL_VAR_INIT = False
|
||||
|
||||
|
||||
def manual_variable_initialization(value):
|
||||
'''Whether variables should be initialized
|
||||
as they are instantiated (default), or if
|
||||
the user should handle the initialization
|
||||
(e.g. via tf.initialize_all_variables()).
|
||||
'''
|
||||
global _MANUAL_VAR_INIT
|
||||
_MANUAL_VAR_INIT = value
|
||||
|
||||
|
||||
def learning_phase():
|
||||
@@ -61,6 +72,23 @@ def set_session(session):
|
||||
|
||||
# VARIABLE MANIPULATION
|
||||
|
||||
def _convert_string_dtype(dtype):
|
||||
if dtype == 'float16':
|
||||
return tf.float16
|
||||
if dtype == 'float32':
|
||||
return tf.float32
|
||||
elif dtype == 'float64':
|
||||
return tf.float64
|
||||
elif dtype == 'int32':
|
||||
return tf.int32
|
||||
elif dtype == 'int64':
|
||||
return tf.int64
|
||||
elif dtype == 'uint8':
|
||||
return tf.int8
|
||||
else:
|
||||
raise ValueError('Unsupported dtype:', dtype)
|
||||
|
||||
|
||||
def variable(value, dtype=_FLOATX, name=None):
|
||||
'''Instantiates a tensor.
|
||||
|
||||
@@ -72,7 +100,9 @@ def variable(value, dtype=_FLOATX, name=None):
|
||||
# Returns
|
||||
Tensor variable instance.
|
||||
'''
|
||||
v = tf.Variable(np.asarray(value, dtype=dtype), name=name)
|
||||
v = tf.Variable(value, dtype=_convert_string_dtype(dtype), name=name)
|
||||
if _MANUAL_VAR_INIT:
|
||||
return v
|
||||
if tf.get_default_graph() is get_session().graph:
|
||||
try:
|
||||
get_session().run(v.initializer)
|
||||
@@ -123,6 +153,7 @@ def shape(x):
|
||||
def int_shape(x):
|
||||
'''Returns the shape of a tensor as a tuple of
|
||||
integers or None entries.
|
||||
Note that this function only works with TensorFlow.
|
||||
'''
|
||||
shape = x.get_shape()
|
||||
return tuple([i.__int__() for i in shape])
|
||||
@@ -153,13 +184,15 @@ def eval(x):
|
||||
def zeros(shape, dtype=_FLOATX, name=None):
|
||||
'''Instantiates an all-zeros tensor variable.
|
||||
'''
|
||||
return variable(np.zeros(shape), dtype, name)
|
||||
return variable(lambda: tf.cast(tf.constant_initializer(0.)(shape), dtype),
|
||||
dtype, name)
|
||||
|
||||
|
||||
def ones(shape, dtype=_FLOATX, name=None):
|
||||
'''Instantiates an all-ones tensor variable.
|
||||
'''
|
||||
return variable(np.ones(shape), dtype, name)
|
||||
return variable(lambda: tf.cast(tf.constant_initializer(1.)(shape), dtype),
|
||||
dtype, name)
|
||||
|
||||
|
||||
def eye(size, dtype=_FLOATX, name=None):
|
||||
@@ -223,8 +256,7 @@ def batch_dot(x, y, axes=None):
|
||||
make sure that ndim is at least 2.
|
||||
|
||||
# Example
|
||||
Assume x = [[1, 2] and y = [[5, 6]
|
||||
[3, 4]] [7, 8]]
|
||||
Assume x = [[1, 2], [3, 4]] and y = [[5, 6], [7, 8]]
|
||||
batch_dot(x, y, axes=1) = [[17, 53]] which is the main diagonal
|
||||
of x.dot(y.T), although we never have to calculate the off-diagonal
|
||||
elements.
|
||||
@@ -314,21 +346,27 @@ def prod(x, axis=None, keepdims=False):
|
||||
return tf.reduce_prod(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
|
||||
|
||||
def std(x, axis=None, keepdims=False):
|
||||
'''Standard deviation of a tensor, alongside the specificied axis.
|
||||
def var(x, axis=None, keepdims=False):
|
||||
'''Variance of a tensor, alongside the specified axis.
|
||||
'''
|
||||
axis = _normalize_axis(axis, ndim(x))
|
||||
if x.dtype.base_dtype == tf.bool:
|
||||
x = tf.cast(x, _FLOATX)
|
||||
m = tf.reduce_mean(x, reduction_indices=axis, keep_dims=True)
|
||||
devs_squared = tf.square(x - m)
|
||||
return tf.sqrt(tf.reduce_mean(devs_squared,
|
||||
reduction_indices=axis,
|
||||
keep_dims=keepdims))
|
||||
return tf.reduce_mean(devs_squared,
|
||||
reduction_indices=axis,
|
||||
keep_dims=keepdims)
|
||||
|
||||
|
||||
def std(x, axis=None, keepdims=False):
|
||||
'''Standard deviation of a tensor, alongside the specified axis.
|
||||
'''
|
||||
return tf.sqrt(var(x, axis=axis, keepdims=keepdims))
|
||||
|
||||
|
||||
def mean(x, axis=None, keepdims=False):
|
||||
'''Mean of a tensor, alongside the specificied axis.
|
||||
'''Mean of a tensor, alongside the specified axis.
|
||||
'''
|
||||
axis = _normalize_axis(axis, ndim(x))
|
||||
if x.dtype.base_dtype == tf.bool:
|
||||
@@ -347,6 +385,17 @@ def any(x, axis=None, keepdims=False):
|
||||
return tf.cast(x, tf.uint8)
|
||||
|
||||
|
||||
def all(x, axis=None, keepdims=False):
|
||||
'''Bitwise reduction (logical AND).
|
||||
|
||||
Returns an uint8 tensor
|
||||
'''
|
||||
axis = _normalize_axis(axis, ndim(x))
|
||||
x = tf.cast(x, tf.bool)
|
||||
x = tf.reduce_all(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
return tf.cast(x, tf.uint8)
|
||||
|
||||
|
||||
def argmax(x, axis=-1):
|
||||
'''Returns the index of the maximum value
|
||||
along a tensor axis.
|
||||
@@ -462,6 +511,42 @@ def cos(x):
|
||||
return tf.cos(x)
|
||||
|
||||
|
||||
def normalize_batch_in_training(x, gamma, beta,
|
||||
reduction_axes, epsilon=0.0001):
|
||||
'''Compute mean and std for batch then apply batch_normalization on batch.
|
||||
'''
|
||||
mean, std = tf.nn.moments(x, reduction_axes,
|
||||
shift=None, name=None, keep_dims=False)
|
||||
if sorted(reduction_axes) == range(ndim(x))[:-1]:
|
||||
normed = tf.nn.batch_normalization(x, mean, std,
|
||||
beta, gamma,
|
||||
epsilon)
|
||||
else:
|
||||
# need broadcasting
|
||||
target_shape = []
|
||||
for axis in range(ndim(x)):
|
||||
if axis in reduction_axes:
|
||||
target_shape.append(1)
|
||||
else:
|
||||
target_shape.append(tf.shape(x)[axis])
|
||||
target_shape = tf.pack(target_shape)
|
||||
|
||||
broadcast_mean = tf.reshape(mean, target_shape)
|
||||
broadcast_std = tf.reshape(std, target_shape)
|
||||
broadcast_gamma = tf.reshape(gamma, target_shape)
|
||||
broadcast_beta = tf.reshape(beta, target_shape)
|
||||
normed = tf.nn.batch_normalization(x, broadcast_mean, broadcast_std,
|
||||
broadcast_beta, broadcast_gamma,
|
||||
epsilon)
|
||||
return normed, mean, std
|
||||
|
||||
|
||||
def batch_normalization(x, mean, std, beta, gamma, epsilon=0.0001):
|
||||
'''Apply batch normalization on x given mean, std, beta and gamma.
|
||||
'''
|
||||
return tf.nn.batch_normalization(x, mean, std, beta, gamma, epsilon)
|
||||
|
||||
|
||||
# SHAPE OPERATIONS
|
||||
|
||||
def concatenate(tensors, axis=-1):
|
||||
@@ -499,15 +584,21 @@ def resize_images(X, height_factor, width_factor, dim_ordering):
|
||||
positive integers.
|
||||
'''
|
||||
if dim_ordering == 'th':
|
||||
original_shape = int_shape(X)
|
||||
new_shape = tf.shape(X)[2:]
|
||||
new_shape *= tf.constant(np.array([height_factor, width_factor]).astype('int32'))
|
||||
X = permute_dimensions(X, [0, 2, 3, 1])
|
||||
X = tf.image.resize_nearest_neighbor(X, new_shape)
|
||||
return permute_dimensions(X, [0, 3, 1, 2])
|
||||
X = permute_dimensions(X, [0, 3, 1, 2])
|
||||
X.set_shape((None, None, original_shape[2] * height_factor, original_shape[3] * width_factor))
|
||||
return X
|
||||
elif dim_ordering == 'tf':
|
||||
original_shape = int_shape(X)
|
||||
new_shape = tf.shape(X)[1:3]
|
||||
new_shape *= tf.constant(np.array([height_factor, width_factor]).astype('int32'))
|
||||
return tf.image.resize_nearest_neighbor(X, new_shape)
|
||||
X = tf.image.resize_nearest_neighbor(X, new_shape)
|
||||
X.set_shape((None, original_shape[1] * height_factor, original_shape[2] * width_factor, None))
|
||||
return X
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + dim_ordering)
|
||||
|
||||
@@ -539,6 +630,8 @@ def repeat(x, n):
|
||||
|
||||
|
||||
def tile(x, n):
|
||||
if not hasattr(n, 'shape') and not hasattr(n, '__len__'):
|
||||
n = [n]
|
||||
return tf.tile(x, n)
|
||||
|
||||
|
||||
@@ -602,6 +695,16 @@ def get_value(x):
|
||||
return x.eval(session=get_session())
|
||||
|
||||
|
||||
def batch_get_value(xs):
|
||||
'''Returns the value of more than one tensor variable,
|
||||
as a list of Numpy arrays.
|
||||
'''
|
||||
if xs:
|
||||
return get_session().run(xs)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def set_value(x, value):
|
||||
'''Sets the value of a tensor variable,
|
||||
from a Numpy array.
|
||||
@@ -620,6 +723,7 @@ def batch_set_value(tuples):
|
||||
ops = [tf.assign(x, np.asarray(value)) for x, value in tuples]
|
||||
get_session().run(ops)
|
||||
|
||||
|
||||
# GRAPH MANIPULATION
|
||||
|
||||
class Function(object):
|
||||
@@ -666,6 +770,13 @@ def gradients(loss, variables):
|
||||
return tf.gradients(loss, variables)
|
||||
|
||||
|
||||
def stop_gradient(variables):
|
||||
'''Returns `variables` but with zero gradient with respect to every other
|
||||
variables.
|
||||
'''
|
||||
return tf.stop_gradient(variables)
|
||||
|
||||
|
||||
# CONTROL FLOW
|
||||
|
||||
def rnn(step_function, inputs, initial_states,
|
||||
@@ -852,6 +963,10 @@ def softplus(x):
|
||||
return tf.nn.softplus(x)
|
||||
|
||||
|
||||
def softsign(x):
|
||||
return tf.nn.softsign(x)
|
||||
|
||||
|
||||
def categorical_crossentropy(output, target, from_logits=False):
|
||||
'''Categorical crossentropy between an output tensor
|
||||
and a target tensor, where the target is a tensor of the same
|
||||
@@ -949,7 +1064,7 @@ def dropout(x, level, seed=None):
|
||||
|
||||
|
||||
def l2_normalize(x, axis):
|
||||
'''Normalizes a tensor wrt the L2 norm alonside the specified axis.
|
||||
'''Normalizes a tensor wrt the L2 norm alongside the specified axis.
|
||||
'''
|
||||
if axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
@@ -958,55 +1073,205 @@ def l2_normalize(x, axis):
|
||||
|
||||
# CONVOLUTIONS
|
||||
|
||||
def _preprocess_conv2d_input(x, dim_ordering):
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float32')
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
x = tf.transpose(x, (0, 2, 3, 1))
|
||||
return x
|
||||
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th',
|
||||
image_shape=None, filter_shape=None):
|
||||
'''2D convolution.
|
||||
|
||||
# Arguments
|
||||
kernel: kernel tensor.
|
||||
strides: strides tuple.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: "tf" or "th". Whether to use Theano or TensorFlow dimension ordering
|
||||
in inputs/kernels/ouputs.
|
||||
'''
|
||||
def _preprocess_conv3d_input(x, dim_ordering):
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float32')
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, conv_dim1, conv_dim2, conv_dim3)
|
||||
# TF input shape: (samples, conv_dim1, conv_dim2, conv_dim3, input_depth)
|
||||
x = tf.transpose(x, (0, 2, 3, 4, 1))
|
||||
return x
|
||||
|
||||
|
||||
def _preprocess_conv2d_kernel(kernel, dim_ordering):
|
||||
if _FLOATX == 'float64':
|
||||
kernel = tf.cast(kernel, 'float32')
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
kernel = tf.transpose(kernel, (2, 3, 1, 0))
|
||||
return kernel
|
||||
|
||||
|
||||
def _preprocess_conv3d_kernel(kernel, dim_ordering):
|
||||
if _FLOATX == 'float64':
|
||||
kernel = tf.cast(kernel, 'float32')
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH kernel shape: (out_depth, input_depth, kernel_dim1, kernel_dim2, kernel_dim3)
|
||||
# TF kernel shape: (kernel_dim1, kernel_dim2, kernel_dim3, input_depth, out_depth)
|
||||
kernel = tf.transpose(kernel, (2, 3, 4, 1, 0))
|
||||
return kernel
|
||||
|
||||
|
||||
def _preprocess_border_mode(border_mode):
|
||||
if border_mode == 'same':
|
||||
padding = 'SAME'
|
||||
elif border_mode == 'valid':
|
||||
padding = 'VALID'
|
||||
else:
|
||||
raise Exception('Invalid border mode: ' + str(border_mode))
|
||||
return padding
|
||||
|
||||
strides = (1,) + strides + (1,)
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
# tf conv2d only supports float32
|
||||
x = tf.cast(x, 'float32')
|
||||
kernel = tf.cast(kernel, 'float32')
|
||||
|
||||
def _postprocess_conv2d_output(x, dim_ordering):
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
x = tf.transpose(x, (0, 2, 3, 1))
|
||||
kernel = tf.transpose(kernel, (2, 3, 1, 0))
|
||||
x = tf.nn.conv2d(x, kernel, strides, padding=padding)
|
||||
x = tf.transpose(x, (0, 3, 1, 2))
|
||||
elif dim_ordering == 'tf':
|
||||
x = tf.nn.conv2d(x, kernel, strides, padding=padding)
|
||||
else:
|
||||
raise Exception('Unknown dim_ordering: ' + str(dim_ordering))
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float64')
|
||||
return x
|
||||
|
||||
|
||||
def _postprocess_conv3d_output(x, dim_ordering):
|
||||
if dim_ordering == 'th':
|
||||
x = tf.transpose(x, (0, 4, 1, 2, 3))
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float64')
|
||||
return x
|
||||
|
||||
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
image_shape=None, filter_shape=None, filter_dilation=(1, 1)):
|
||||
'''2D convolution.
|
||||
|
||||
# Arguments
|
||||
kernel: kernel tensor.
|
||||
strides: strides tuple.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: "tf" or "th".
|
||||
Whether to use Theano or TensorFlow dimension ordering
|
||||
for inputs/kernels/ouputs.
|
||||
'''
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
kernel = _preprocess_conv2d_kernel(kernel, dim_ordering)
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
if filter_dilation == (1, 1):
|
||||
strides = (1,) + strides + (1,)
|
||||
x = tf.nn.conv2d(x, kernel, strides, padding=padding)
|
||||
else:
|
||||
assert filter_dilation[0] == filter_dilation[1]
|
||||
assert strides == (1, 1), 'Invalid strides for dilated convolution'
|
||||
x = tf.nn.atrous_conv2d(x, kernel, filter_dilation[0], padding=padding)
|
||||
return _postprocess_conv2d_output(x, dim_ordering)
|
||||
|
||||
|
||||
def deconv2d(x, kernel, output_shape, strides=(1, 1),
|
||||
border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
image_shape=None, filter_shape=None):
|
||||
'''2D deconvolution (i.e. transposed convolution).
|
||||
|
||||
# Arguments
|
||||
x: input tensor.
|
||||
kernel: kernel tensor.
|
||||
output_shape: 1D int tensor for the output shape.
|
||||
strides: strides tuple.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: "tf" or "th".
|
||||
Whether to use Theano or TensorFlow dimension ordering
|
||||
for inputs/kernels/ouputs.
|
||||
'''
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
kernel = _preprocess_conv2d_kernel(kernel, dim_ordering)
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
strides = (1,) + strides + (1,)
|
||||
|
||||
# TODO: pre-process output_shape if dim_ordering == th
|
||||
x = tf.nn.conv2d_transpose(x, kernel, output_shape, strides,
|
||||
padding=padding)
|
||||
return _postprocess_conv2d_output(x, dim_ordering)
|
||||
|
||||
|
||||
def atrous_conv2d(x, kernel, rate=1,
|
||||
border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
image_shape=None, filter_shape=None):
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
if rate == 1:
|
||||
return conv2d(x, kernel, strides=(1, 1), border_mode=border_mode,
|
||||
dim_ordering=dim_ordering)
|
||||
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
kernel = _preprocess_conv2d_kernel(kernel, dim_ordering)
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
|
||||
x = tf.nn.atrous_conv2d(x, kernel, rate, padding)
|
||||
return _postprocess_conv2d_output(x, dim_ordering)
|
||||
|
||||
|
||||
def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
|
||||
border_mode='valid', dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
depthwise_kernel = _preprocess_conv2d_kernel(depthwise_kernel,
|
||||
dim_ordering)
|
||||
pointwise_kernel = _preprocess_conv2d_kernel(pointwise_kernel,
|
||||
dim_ordering)
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
strides = (1,) + strides + (1,)
|
||||
|
||||
x = tf.nn.separable_conv2d(x, depthwise_kernel, pointwise_kernel,
|
||||
strides, padding)
|
||||
return _postprocess_conv2d_output(x, dim_ordering)
|
||||
|
||||
|
||||
def conv3d(x, kernel, strides=(1, 1, 1),
|
||||
border_mode='valid', dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
volume_shape=None, filter_shape=None):
|
||||
'''3D convolution.
|
||||
|
||||
# Arguments
|
||||
kernel: kernel tensor.
|
||||
strides: strides tuple.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: "tf" or "th".
|
||||
Whether to use Theano or TensorFlow dimension ordering
|
||||
for inputs/kernels/ouputs.
|
||||
'''
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
x = _preprocess_conv3d_input(x, dim_ordering)
|
||||
kernel = _preprocess_conv3d_kernel(kernel, dim_ordering)
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
strides = (1,) + strides + (1,)
|
||||
|
||||
x = tf.nn.conv3d(x, kernel, strides, padding)
|
||||
return _postprocess_conv3d_output(x, dim_ordering)
|
||||
|
||||
|
||||
def pool2d(x, pool_size, strides=(1, 1),
|
||||
border_mode='valid', dim_ordering='th', pool_mode='max'):
|
||||
border_mode='valid', dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
pool_mode='max'):
|
||||
'''2D Pooling.
|
||||
|
||||
# Arguments
|
||||
@@ -1016,43 +1281,53 @@ def pool2d(x, pool_size, strides=(1, 1),
|
||||
dim_ordering: one of "th", "tf".
|
||||
pool_mode: one of "max", "avg".
|
||||
'''
|
||||
if border_mode == 'same':
|
||||
padding = 'SAME'
|
||||
elif border_mode == 'valid':
|
||||
padding = 'VALID'
|
||||
else:
|
||||
raise Exception('Invalid border mode: ' + str(border_mode))
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
strides = (1,) + strides + (1,)
|
||||
pool_size = (1,) + pool_size + (1,)
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
# tf max_pool only supports float32
|
||||
x = tf.cast(x, 'float32')
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
|
||||
if dim_ordering in {'tf', 'th'}:
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
x = tf.transpose(x, (0, 2, 3, 1))
|
||||
if pool_mode == 'max':
|
||||
x = tf.nn.max_pool(x, pool_size, strides, padding=padding)
|
||||
elif pool_mode == 'avg':
|
||||
x = tf.nn.avg_pool(x, pool_size, strides, padding=padding)
|
||||
else:
|
||||
raise Exception('Invalid pooling mode: ' + str(pool_mode))
|
||||
if dim_ordering == 'th':
|
||||
x = tf.transpose(x, (0, 3, 1, 2))
|
||||
if pool_mode == 'max':
|
||||
x = tf.nn.max_pool(x, pool_size, strides, padding=padding)
|
||||
elif pool_mode == 'avg':
|
||||
x = tf.nn.avg_pool(x, pool_size, strides, padding=padding)
|
||||
else:
|
||||
raise Exception('Unknown dim_ordering: ' + str(dim_ordering))
|
||||
raise Exception('Invalid pooling mode: ' + str(pool_mode))
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float64')
|
||||
return x
|
||||
return _postprocess_conv2d_output(x, dim_ordering)
|
||||
|
||||
|
||||
def pool3d(x, pool_size, strides=(1, 1, 1), border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, pool_mode='max'):
|
||||
'''3D Pooling.
|
||||
|
||||
# Arguments
|
||||
pool_size: tuple of 3 integers.
|
||||
strides: tuple of 3 integers.
|
||||
border_mode: one of "valid", "same".
|
||||
dim_ordering: one of "th", "tf".
|
||||
pool_mode: one of "max", "avg".
|
||||
'''
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
padding = _preprocess_border_mode(border_mode)
|
||||
strides = (1,) + strides + (1,)
|
||||
pool_size = (1,) + pool_size + (1,)
|
||||
|
||||
x = _preprocess_conv3d_input(x, dim_ordering)
|
||||
|
||||
if pool_mode == 'max':
|
||||
x = tf.nn.max_pool3d(x, pool_size, strides, padding=padding)
|
||||
elif pool_mode == 'avg':
|
||||
x = tf.nn.avg_pool3d(x, pool_size, strides, padding=padding)
|
||||
else:
|
||||
raise Exception('Invalid pooling mode: ' + str(pool_mode))
|
||||
|
||||
return _postprocess_conv3d_output(x, dim_ordering)
|
||||
|
||||
|
||||
# RANDOMNESS
|
||||
@@ -1075,4 +1350,5 @@ def random_binomial(shape, p=0.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
return tf.select(tf.random_uniform(shape, dtype=dtype, seed=seed) <= p,
|
||||
tf.ones(shape), tf.zeros(shape))
|
||||
tf.ones(shape, dtype=dtype),
|
||||
tf.zeros(shape, dtype=dtype))
|
||||
|
||||
@@ -3,9 +3,13 @@ from theano import tensor as T
|
||||
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from theano.tensor.signal import pool
|
||||
from theano.tensor.nnet import conv3d2d
|
||||
try:
|
||||
from theano.tensor.nnet.nnet import softsign as T_softsign
|
||||
except ImportError:
|
||||
from theano.sandbox.softsign import softsign as T_softsign
|
||||
import inspect
|
||||
import numpy as np
|
||||
from .common import _FLOATX, _EPSILON
|
||||
from .common import _FLOATX, _EPSILON, _IMAGE_DIM_ORDERING
|
||||
|
||||
|
||||
# INTERNAL UTILS
|
||||
@@ -124,8 +128,7 @@ def batch_dot(x, y, axes=None):
|
||||
make sure that ndim is at least 2.
|
||||
|
||||
# Example
|
||||
Assume x = [[1, 2] and y = [[5, 6]
|
||||
[3, 4]] [7, 8]]
|
||||
Assume x = [[1, 2], [3, 4]] and y = [[5, 6], [7, 8]]
|
||||
batch_dot(x, y, axes=1) = [[17, 53]] which is the main diagonal
|
||||
of x.dot(y.T), although we never have to calculate the off-diagonal
|
||||
elements.
|
||||
@@ -196,12 +199,22 @@ def std(x, axis=None, keepdims=False):
|
||||
return T.std(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def var(x, axis=None, keepdims=False):
|
||||
return T.var(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def any(x, axis=None, keepdims=False):
|
||||
'''Bitwise reduction (logical OR).
|
||||
'''
|
||||
return T.any(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def all(x, axis=None, keepdims=False):
|
||||
'''Bitwise reduction (logical AND).
|
||||
'''
|
||||
return T.all(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def argmax(x, axis=-1):
|
||||
return T.argmax(x, axis=axis, keepdims=False)
|
||||
|
||||
@@ -273,6 +286,38 @@ def cos(x):
|
||||
return T.cos(x)
|
||||
|
||||
|
||||
def normalize_batch_in_training(x, gamma, beta,
|
||||
reduction_axes, epsilon=0.0001):
|
||||
'''Compute mean and std for batch then apply batch_normalization on batch.
|
||||
'''
|
||||
std = T.sqrt(x.var(reduction_axes) + epsilon)
|
||||
mean = x.mean(reduction_axes)
|
||||
|
||||
target_shape = []
|
||||
for axis in range(ndim(x)):
|
||||
if axis in reduction_axes:
|
||||
target_shape.append(1)
|
||||
else:
|
||||
target_shape.append(x.shape[axis])
|
||||
target_shape = T.stack(*target_shape)
|
||||
|
||||
broadcast_mean = T.reshape(mean, target_shape)
|
||||
broadcast_std = T.reshape(std, target_shape)
|
||||
broadcast_beta = T.reshape(beta, target_shape)
|
||||
broadcast_gamma = T.reshape(gamma, target_shape)
|
||||
normed = batch_normalization(x, broadcast_mean, broadcast_std,
|
||||
broadcast_beta, broadcast_gamma,
|
||||
epsilon)
|
||||
return normed, mean, std
|
||||
|
||||
|
||||
def batch_normalization(x, mean, std, beta, gamma, epsilon=0.0001):
|
||||
'''Apply batch normalization on x given mean, std, beta and gamma.
|
||||
'''
|
||||
normed = (x - mean) * (gamma * T.inv(std + epsilon)) + beta
|
||||
return normed
|
||||
|
||||
|
||||
# SHAPE OPERATIONS
|
||||
|
||||
def concatenate(tensors, axis=-1):
|
||||
@@ -385,15 +430,18 @@ def expand_dims(x, dim=-1):
|
||||
def squeeze(x, axis):
|
||||
'''Remove a 1-dimension from the tensor at index "axis".
|
||||
'''
|
||||
x = T.addbroadcast(x, axis)
|
||||
return T.squeeze(x)
|
||||
broadcastable = x.broadcastable[:axis] + x.broadcastable[axis+1:]
|
||||
x = T.patternbroadcast(x, [i == axis for i in range(x.type.ndim)])
|
||||
x = T.squeeze(x)
|
||||
x = T.patternbroadcast(x, broadcastable)
|
||||
return x
|
||||
|
||||
|
||||
def temporal_padding(x, padding=1):
|
||||
'''Pad the middle dimension of a 3D tensor
|
||||
with "padding" zeros left and right.
|
||||
|
||||
Appologies for the inane API, but Theano makes this
|
||||
Apologies for the inane API, but Theano makes this
|
||||
really hard.
|
||||
'''
|
||||
input_shape = x.shape
|
||||
@@ -483,6 +531,13 @@ def get_value(x):
|
||||
return x.get_value()
|
||||
|
||||
|
||||
def batch_get_value(xs):
|
||||
'''Returns the value of more than one tensor variable,
|
||||
as a list of Numpy arrays.
|
||||
'''
|
||||
return [get_value(x) for x in xs]
|
||||
|
||||
|
||||
def set_value(x, value):
|
||||
x.set_value(np.asarray(value, dtype=x.dtype))
|
||||
|
||||
@@ -521,6 +576,13 @@ def gradients(loss, variables):
|
||||
return T.grad(loss, variables)
|
||||
|
||||
|
||||
def stop_gradient(variables):
|
||||
'''Returns `variables` but with zero gradient with respect to every other
|
||||
variables.
|
||||
'''
|
||||
return theano.gradient.disconnected_grad(variables)
|
||||
|
||||
|
||||
# CONTROL FLOW
|
||||
|
||||
def rnn(step_function, inputs, initial_states,
|
||||
@@ -725,6 +787,10 @@ def softplus(x):
|
||||
return T.nnet.softplus(x)
|
||||
|
||||
|
||||
def softsign(x):
|
||||
return T_softsign(x)
|
||||
|
||||
|
||||
def categorical_crossentropy(output, target, from_logits=False):
|
||||
if from_logits:
|
||||
output = T.nnet.softmax(output)
|
||||
@@ -767,7 +833,7 @@ def dropout(x, level, seed=None):
|
||||
if level < 0. or level >= 1:
|
||||
raise Exception('Dropout level must be in interval [0, 1[.')
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
retain_prob = 1. - level
|
||||
x *= rng.binomial(x.shape, p=retain_prob, dtype=x.dtype)
|
||||
@@ -782,10 +848,18 @@ def l2_normalize(x, axis):
|
||||
|
||||
# CONVOLUTIONS
|
||||
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th',
|
||||
image_shape=None, filter_shape=None):
|
||||
'''
|
||||
border_mode: string, "same" or "valid".
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, image_shape=None,
|
||||
filter_shape=None, filter_dilation=(1, 1)):
|
||||
'''2D convolution.
|
||||
|
||||
# Arguments
|
||||
kernel: kernel tensor.
|
||||
strides: strides tuple.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: "tf" or "th".
|
||||
Whether to use Theano or TensorFlow dimension ordering
|
||||
in inputs/kernels/ouputs.
|
||||
'''
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
@@ -827,11 +901,20 @@ def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th',
|
||||
if filter_shape is not None:
|
||||
filter_shape = tuple(int_or_none(v) for v in filter_shape)
|
||||
|
||||
conv_out = T.nnet.conv2d(x, kernel,
|
||||
border_mode=th_border_mode,
|
||||
subsample=strides,
|
||||
input_shape=image_shape,
|
||||
filter_shape=filter_shape)
|
||||
# TODO: remove the if statement when theano with no filter dilation is deprecated.
|
||||
if filter_dilation == (1, 1):
|
||||
conv_out = T.nnet.conv2d(x, kernel,
|
||||
border_mode=th_border_mode,
|
||||
subsample=strides,
|
||||
input_shape=image_shape,
|
||||
filter_shape=filter_shape)
|
||||
else:
|
||||
conv_out = T.nnet.conv2d(x, kernel,
|
||||
border_mode=th_border_mode,
|
||||
subsample=strides,
|
||||
input_shape=image_shape,
|
||||
filter_shape=filter_shape,
|
||||
filter_dilation=filter_dilation)
|
||||
|
||||
if border_mode == 'same':
|
||||
if np_kernel.shape[2] % 2 == 0:
|
||||
@@ -844,6 +927,25 @@ def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th',
|
||||
return conv_out
|
||||
|
||||
|
||||
def deconv2d(x, kernel, output_shape, strides=(1, 1),
|
||||
border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
image_shape=None, filter_shape=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def atrous_conv2d(x, kernel, rate=1,
|
||||
border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
image_shape=None, filter_shape=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
|
||||
border_mode='valid', dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
def conv3d(x, kernel, strides=(1, 1, 1),
|
||||
border_mode='valid', dim_ordering='th',
|
||||
volume_shape=None, filter_shape=None):
|
||||
@@ -1012,20 +1114,20 @@ def pool3d(x, pool_size, strides=(1, 1, 1), border_mode='valid',
|
||||
|
||||
def random_normal(shape, mean=0.0, std=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.normal(size=shape, avg=mean, std=std, dtype=dtype)
|
||||
|
||||
|
||||
def random_uniform(shape, low=0.0, high=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.uniform(shape, low=low, high=high, dtype=dtype)
|
||||
|
||||
|
||||
def random_binomial(shape, p=0.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.binomial(shape, p=p, dtype=dtype)
|
||||
|
||||
+37
-23
@@ -192,7 +192,7 @@ class ProgbarLogger(Callback):
|
||||
if k in logs:
|
||||
self.log_values.append((k, logs[k]))
|
||||
if self.verbose:
|
||||
self.progbar.update(self.seen, self.log_values)
|
||||
self.progbar.update(self.seen, self.log_values, force=True)
|
||||
|
||||
|
||||
class History(Callback):
|
||||
@@ -210,10 +210,7 @@ class History(Callback):
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
self.epoch.append(epoch)
|
||||
for k, v in logs.items():
|
||||
if k not in self.history:
|
||||
self.history[k] = []
|
||||
self.history[k].append(v)
|
||||
|
||||
self.history.setdefault(k, []).append(v)
|
||||
|
||||
class ModelCheckpoint(Callback):
|
||||
'''Save the model after every epoch.
|
||||
@@ -246,7 +243,7 @@ class ModelCheckpoint(Callback):
|
||||
def __init__(self, filepath, monitor='val_loss', verbose=0,
|
||||
save_best_only=False, mode='auto'):
|
||||
|
||||
super(Callback, self).__init__()
|
||||
super(ModelCheckpoint, self).__init__()
|
||||
self.monitor = monitor
|
||||
self.verbose = verbose
|
||||
self.filepath = filepath
|
||||
@@ -313,7 +310,7 @@ class EarlyStopping(Callback):
|
||||
monitored has stopped increasing.
|
||||
'''
|
||||
def __init__(self, monitor='val_loss', patience=0, verbose=0, mode='auto'):
|
||||
super(Callback, self).__init__()
|
||||
super(EarlyStopping, self).__init__()
|
||||
|
||||
self.monitor = monitor
|
||||
self.patience = patience
|
||||
@@ -327,17 +324,17 @@ class EarlyStopping(Callback):
|
||||
|
||||
if mode == 'min':
|
||||
self.monitor_op = np.less
|
||||
self.best = np.Inf
|
||||
elif mode == 'max':
|
||||
self.monitor_op = np.greater
|
||||
self.best = -np.Inf
|
||||
else:
|
||||
if 'acc' in self.monitor:
|
||||
self.monitor_op = np.greater
|
||||
self.best = -np.Inf
|
||||
else:
|
||||
self.monitor_op = np.less
|
||||
self.best = np.Inf
|
||||
|
||||
def on_train_begin(self, logs={}):
|
||||
self.wait = 0 # Allow instances to be re-used
|
||||
self.best = np.Inf if self.monitor_op == np.less else -np.Inf
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
current = logs.get(self.monitor)
|
||||
@@ -364,12 +361,19 @@ class RemoteMonitor(Callback):
|
||||
# Arguments
|
||||
root: root url to which the events will be sent (at the end
|
||||
of every epoch). Events are sent to
|
||||
`root + '/publish/epoch/end/'`. Calls are HTTP POST,
|
||||
with a `data` argument which is a JSON-encoded dictionary
|
||||
of event data.
|
||||
`root + '/publish/epoch/end/'` by default. Calls are
|
||||
HTTP POST, with a `data` argument which is a
|
||||
JSON-encoded dictionary of event data.
|
||||
'''
|
||||
def __init__(self, root='http://localhost:9000'):
|
||||
|
||||
def __init__(self,
|
||||
root='http://localhost:9000',
|
||||
path='/publish/epoch/end/',
|
||||
field='data'):
|
||||
super(RemoteMonitor, self).__init__()
|
||||
self.root = root
|
||||
self.path = path
|
||||
self.field = field
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
import requests
|
||||
@@ -377,10 +381,9 @@ class RemoteMonitor(Callback):
|
||||
send['epoch'] = epoch
|
||||
for k, v in logs.items():
|
||||
send[k] = v
|
||||
|
||||
try:
|
||||
requests.post(self.root + '/publish/epoch/end/',
|
||||
{'data': json.dumps(send)})
|
||||
requests.post(self.root + self.path,
|
||||
{self.field: json.dumps(send)})
|
||||
except:
|
||||
print('Warning: could not reach RemoteMonitor '
|
||||
'root server at ' + str(self.root))
|
||||
@@ -426,19 +429,23 @@ class TensorBoard(Callback):
|
||||
|
||||
# Arguments
|
||||
log_dir: the path of the directory where to save the log
|
||||
files to be parsed by tensorboard
|
||||
files to be parsed by Tensorboard
|
||||
histogram_freq: frequency (in epochs) at which to compute activation
|
||||
histograms for the layers of the model. If set to 0,
|
||||
histograms won't be computed.
|
||||
write_graph: whether to visualize the graph in Tensorboard. The log file can
|
||||
become quite large when write_graph is set to True.
|
||||
'''
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0):
|
||||
super(Callback, self).__init__()
|
||||
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0, write_graph=True):
|
||||
super(TensorBoard, self).__init__()
|
||||
if K._BACKEND != 'tensorflow':
|
||||
raise Exception('TensorBoard callback only works '
|
||||
'with the TensorFlow backend.')
|
||||
self.log_dir = log_dir
|
||||
self.histogram_freq = histogram_freq
|
||||
self.merged = None
|
||||
self.write_graph = write_graph
|
||||
|
||||
def _set_model(self, model):
|
||||
import tensorflow as tf
|
||||
@@ -457,8 +464,15 @@ class TensorBoard(Callback):
|
||||
tf.histogram_summary('{}_out'.format(layer),
|
||||
layer.output)
|
||||
self.merged = tf.merge_all_summaries()
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph_def)
|
||||
if self.write_graph:
|
||||
if tf.__version__ >= '0.8.0':
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph)
|
||||
else:
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph_def)
|
||||
else:
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir)
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
import tensorflow as tf
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
from __future__ import absolute_import
|
||||
import sys
|
||||
from six.moves import cPickle
|
||||
from six.moves import range
|
||||
|
||||
|
||||
def load_batch(fpath, label_key='labels'):
|
||||
|
||||
@@ -4,6 +4,7 @@ from ..utils.data_utils import get_file
|
||||
from six.moves import cPickle
|
||||
from six.moves import zip
|
||||
import numpy as np
|
||||
import sys
|
||||
|
||||
|
||||
def load_data(path="reuters.pkl", nb_words=None, skip_top=0,
|
||||
@@ -64,4 +65,11 @@ def load_data(path="reuters.pkl", nb_words=None, skip_top=0,
|
||||
def get_word_index(path="reuters_word_index.pkl"):
|
||||
path = get_file(path, origin="https://s3.amazonaws.com/text-datasets/reuters_word_index.pkl")
|
||||
f = open(path, 'rb')
|
||||
return cPickle.load(f)
|
||||
|
||||
if sys.version_info < (3,):
|
||||
data = cPickle.load(f)
|
||||
else:
|
||||
data = cPickle.load(f, encoding="latin1")
|
||||
|
||||
f.close()
|
||||
return data
|
||||
|
||||
+200
-112
@@ -281,7 +281,7 @@ class Layer(object):
|
||||
self.outbound_nodes = []
|
||||
|
||||
# these properties will be set upon call of self.build(),
|
||||
# which itself will be calld upon self.add_inbound_node if necessary.
|
||||
# which itself will be called upon self.add_inbound_node if necessary.
|
||||
self.trainable_weights = []
|
||||
self.non_trainable_weights = []
|
||||
self.regularizers = []
|
||||
@@ -512,7 +512,7 @@ class Layer(object):
|
||||
where to connect the current layer.
|
||||
tensor_indices: integer or list of integers.
|
||||
The output of the inbound node might be a list/tuple
|
||||
of tensor, and we might only be interested in one sepcific entry.
|
||||
of tensor, and we might only be interested in one specific entry.
|
||||
This index allows you to specify the index of the entry in the output list
|
||||
(if applicable). "None" means that we take all outputs (as a list).
|
||||
'''
|
||||
@@ -847,10 +847,11 @@ class Layer(object):
|
||||
if not params:
|
||||
return
|
||||
weight_value_tuples = []
|
||||
for p, w in zip(params, weights):
|
||||
if K.get_value(p).shape != w.shape:
|
||||
param_values = K.batch_get_value(params)
|
||||
for pv, p, w in zip(param_values, params, weights):
|
||||
if pv.shape != w.shape:
|
||||
raise Exception('Layer weight shape ' +
|
||||
str(K.get_value(p).shape) +
|
||||
str(pv.shape) +
|
||||
' not compatible with '
|
||||
'provided weight shape ' + str(w.shape))
|
||||
weight_value_tuples.append((p, w))
|
||||
@@ -861,10 +862,7 @@ class Layer(object):
|
||||
as a list of numpy arrays.
|
||||
'''
|
||||
params = self.trainable_weights + self.non_trainable_weights
|
||||
weights = []
|
||||
for p in params:
|
||||
weights.append(K.get_value(p))
|
||||
return weights
|
||||
return K.batch_get_value(params)
|
||||
|
||||
def get_config(self):
|
||||
'''Returns a Python dictionary (serializable)
|
||||
@@ -916,7 +914,7 @@ class InputLayer(Layer):
|
||||
'''TODO: dosctring
|
||||
'''
|
||||
def __init__(self, input_shape=None, batch_input_shape=None,
|
||||
input_dtype=None, name=None):
|
||||
input_dtype=None, input_tensor=None, name=None):
|
||||
self.input_spec = None
|
||||
self.supports_masking = False
|
||||
self.uses_learning_phase = False
|
||||
@@ -936,25 +934,48 @@ class InputLayer(Layer):
|
||||
name = prefix + '_' + str(K.get_uid(prefix))
|
||||
self.name = name
|
||||
|
||||
if input_shape and batch_input_shape:
|
||||
raise ValueError('Only provide the input_shape OR '
|
||||
'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:
|
||||
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 '
|
||||
'argument.')
|
||||
if not batch_input_shape:
|
||||
assert input_shape, 'An Input layer should be passed either a `batch_input_shape` or an `input_shape`.'
|
||||
batch_input_shape = (None,) + tuple(input_shape)
|
||||
if not input_shape:
|
||||
raise ValueError('An Input layer should be passed either '
|
||||
'a `batch_input_shape` or an `input_shape`.')
|
||||
else:
|
||||
batch_input_shape = (None,) + tuple(input_shape)
|
||||
else:
|
||||
batch_input_shape = tuple(batch_input_shape)
|
||||
|
||||
if not input_dtype:
|
||||
input_dtype = K.floatx()
|
||||
if input_tensor is None:
|
||||
input_dtype = K.floatx()
|
||||
else:
|
||||
input_dtype = K.dtype(input_tensor)
|
||||
|
||||
self.batch_input_shape = batch_input_shape
|
||||
self.input_dtype = input_dtype
|
||||
|
||||
input_tensor = K.placeholder(shape=batch_input_shape,
|
||||
dtype=input_dtype,
|
||||
name=self.name)
|
||||
if input_tensor is None:
|
||||
input_tensor = K.placeholder(shape=batch_input_shape,
|
||||
dtype=input_dtype,
|
||||
name=self.name)
|
||||
else:
|
||||
input_tensor._keras_shape = batch_input_shape
|
||||
# create an input node to add to self.outbound_node
|
||||
# and set output_tensors' _keras_history
|
||||
input_tensor._uses_learning_phase = False
|
||||
input_tensor._keras_history = (self, 0, 0)
|
||||
shape = input_tensor._keras_shape
|
||||
Node(self,
|
||||
inbound_layers=[],
|
||||
node_indices=[],
|
||||
@@ -963,8 +984,8 @@ class InputLayer(Layer):
|
||||
output_tensors=[input_tensor],
|
||||
input_masks=[None],
|
||||
output_masks=[None],
|
||||
input_shapes=[shape],
|
||||
output_shapes=[shape])
|
||||
input_shapes=[batch_input_shape],
|
||||
output_shapes=[batch_input_shape])
|
||||
|
||||
def get_config(self):
|
||||
config = {'batch_input_shape': self.batch_input_shape,
|
||||
@@ -974,7 +995,8 @@ class InputLayer(Layer):
|
||||
|
||||
|
||||
def Input(shape=None, batch_shape=None,
|
||||
name=None, dtype=K.floatx()):
|
||||
name=None, dtype=K.floatx(),
|
||||
tensor=None):
|
||||
'''`Input()` is used to instantiate a Keras tensor.
|
||||
A Keras tensor is a tensor object from the underlying backend
|
||||
(Theano or TensorFlow), which we augment with certain
|
||||
@@ -1005,7 +1027,7 @@ def Input(shape=None, batch_shape=None,
|
||||
Should be unique in a model (do not reuse the same name twice).
|
||||
It will be autogenerated if it isn't provided.
|
||||
dtype: The data type expected by the input, as a string
|
||||
(`float32`, `flaot64`, `int32`...)
|
||||
(`float32`, `float64`, `int32`...)
|
||||
|
||||
# Example usage
|
||||
|
||||
@@ -1016,14 +1038,15 @@ def Input(shape=None, batch_shape=None,
|
||||
model = Model(input=a, output=b)
|
||||
```
|
||||
'''
|
||||
if not batch_shape:
|
||||
assert shape, ('Please provide to Input either an `input_shape`' +
|
||||
' or `batch_input_shape` argument. Note that ' +
|
||||
'`input_shape` does not include the batch '
|
||||
if not batch_shape and tensor is None:
|
||||
assert shape, ('Please provide to Input either a `shape`' +
|
||||
' or a `batch_shape` argument. Note that ' +
|
||||
'`shape` does not include the batch '
|
||||
'dimension.')
|
||||
batch_shape = (None,) + tuple(shape)
|
||||
input_layer = InputLayer(batch_input_shape=batch_shape,
|
||||
name=name, input_dtype=dtype)
|
||||
name=name, input_dtype=dtype,
|
||||
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.
|
||||
outputs = input_layer.inbound_nodes[0].output_tensors
|
||||
@@ -1057,15 +1080,19 @@ class Merge(Layer):
|
||||
a list of layer instances. Must be more
|
||||
than one layer/tensor.
|
||||
mode: string or lambda/function. If string, must be one
|
||||
of: 'sum', 'mul', 'concat', 'ave', 'cos', 'dot'.
|
||||
of: 'sum', 'mul', 'concat', 'ave', 'cos', 'dot', 'max'.
|
||||
If lambda/function, it should take as input a list of tensors
|
||||
and return a single tensor.
|
||||
concat_axis: integer, axis to use in mode `concat`.
|
||||
dot_axes: integer or tuple of integers, axes to use in mode `dot`.
|
||||
output_shape: shape tuple (tuple of integers), or lambda/function
|
||||
to compute output_shape (only if merge mode is a lambda/function).
|
||||
If the latter case, it should take as input a list of shape tuples
|
||||
(1:1 mapping to input tensors) and return a single shape tuple.
|
||||
output_shape: either a shape tuple (tuple of integers), or a lambda/function
|
||||
to compute `output_shape` (only if merge mode is a lambda/function).
|
||||
If the argument is a tuple,
|
||||
it should be expected output shape, *not* including the batch size
|
||||
(same convention as the `input_shape` argument in layers).
|
||||
If the argument is callable, it should take as input a list of shape tuples
|
||||
(1:1 mapping to input tensors) and return a single shape tuple, including the
|
||||
batch size (same convention as the `get_output_shape_for` method of layers).
|
||||
node_indices: optional list of integers containing
|
||||
the output node index for each input layer
|
||||
(in case some input layers have multiple output nodes).
|
||||
@@ -1073,9 +1100,12 @@ class Merge(Layer):
|
||||
tensor_indices: optional list of indices of output tensors
|
||||
to consider for merging
|
||||
(in case some input layer node returns multiple tensors).
|
||||
output_mask: mask or lambda/function to compute the output mask (only
|
||||
if merge mode is a lambda/function). If the latter case, it should
|
||||
take as input a list of masks and return a single mask.
|
||||
'''
|
||||
def __init__(self, layers=None, mode='sum', concat_axis=-1,
|
||||
dot_axes=-1, output_shape=None,
|
||||
dot_axes=-1, output_shape=None, output_mask=None,
|
||||
node_indices=None, tensor_indices=None, name=None):
|
||||
self.layers = layers
|
||||
self.mode = mode
|
||||
@@ -1085,6 +1115,7 @@ class Merge(Layer):
|
||||
self.dot_axes = [self.dot_axes, ] * 2
|
||||
self._output_shape = output_shape
|
||||
self.node_indices = node_indices
|
||||
self._output_mask = output_mask
|
||||
|
||||
# layer parameters
|
||||
self.inbound_nodes = []
|
||||
@@ -1093,7 +1124,7 @@ class Merge(Layer):
|
||||
self.regularizers = []
|
||||
self.trainable_weights = []
|
||||
self.non_trainable_weights = []
|
||||
self.supports_masking = False
|
||||
self.supports_masking = True
|
||||
self.uses_learning_phase = False
|
||||
self.input_spec = None # compatible with whatever
|
||||
if not name:
|
||||
@@ -1112,7 +1143,6 @@ class Merge(Layer):
|
||||
node_indices = [0 for _ in range(len(layers))]
|
||||
self._arguments_validation(layers, mode,
|
||||
concat_axis, dot_axes,
|
||||
output_shape,
|
||||
node_indices, tensor_indices)
|
||||
self.built = True
|
||||
self.add_inbound_node(layers, node_indices, tensor_indices)
|
||||
@@ -1120,12 +1150,12 @@ class Merge(Layer):
|
||||
self.built = False
|
||||
|
||||
def _arguments_validation(self, layers, mode, concat_axis, dot_axes,
|
||||
output_shape, node_indices, tensor_indices):
|
||||
node_indices, tensor_indices):
|
||||
'''Validates user-passed arguments and raises exceptions
|
||||
as appropriate.
|
||||
'''
|
||||
if not hasattr(mode, '__call__'):
|
||||
if mode not in {'sum', 'mul', 'concat', 'ave', 'cos', 'dot'}:
|
||||
if mode not in {'sum', 'mul', 'concat', 'ave', 'cos', 'dot', 'max'}:
|
||||
raise Exception('Invalid merge mode: ' + str(mode))
|
||||
if type(layers) not in {list, tuple} or len(layers) < 2:
|
||||
raise Exception('A Merge should only be applied to a list of '
|
||||
@@ -1143,7 +1173,7 @@ class Merge(Layer):
|
||||
layer_output_shape = layer_output_shape[tensor_indices[i]]
|
||||
input_shapes.append(layer_output_shape)
|
||||
|
||||
if mode in {'sum', 'mul', 'ave', 'cos'}:
|
||||
if mode in {'sum', 'mul', 'ave', 'cos', 'max'}:
|
||||
input_shapes_set = set(input_shapes)
|
||||
if len(input_shapes_set) > 1:
|
||||
raise Exception('Only layers of same output shape can '
|
||||
@@ -1156,22 +1186,21 @@ class Merge(Layer):
|
||||
shape2 = input_shapes[1]
|
||||
n1 = len(shape1)
|
||||
n2 = len(shape2)
|
||||
if mode == 'dot':
|
||||
if type(dot_axes) == int:
|
||||
if dot_axes < 0:
|
||||
dot_axes = [dot_axes % n1, dot_axes % n2]
|
||||
else:
|
||||
dot_axes = [n1 - dot_axes, n2-dot_axes]
|
||||
if type(dot_axes) not in [list, tuple]:
|
||||
raise Exception('Invalid type for dot_axes - should be a list.')
|
||||
if len(dot_axes) != 2:
|
||||
raise Exception('Invalid format for dot_axes - should contain two elements.')
|
||||
if type(dot_axes[0]) is not int or type(dot_axes[1]) is not int:
|
||||
raise Exception('Invalid format for dot_axes - list elements should be "int".')
|
||||
if shape1[dot_axes[0]] != shape2[dot_axes[1]]:
|
||||
raise Exception('Dimension incompatibility using dot mode: ' +
|
||||
'%s != %s. ' % (shape1[dot_axes[0]], shape2[dot_axes[1]]) +
|
||||
'Layer shapes: %s, %s' % (shape1, shape2))
|
||||
if type(dot_axes) == int:
|
||||
if dot_axes < 0:
|
||||
dot_axes = [dot_axes % n1, dot_axes % n2]
|
||||
else:
|
||||
dot_axes = [n1 - dot_axes, n2-dot_axes]
|
||||
if type(dot_axes) not in [list, tuple]:
|
||||
raise Exception('Invalid type for dot_axes - should be a list.')
|
||||
if len(dot_axes) != 2:
|
||||
raise Exception('Invalid format for dot_axes - should contain two elements.')
|
||||
if type(dot_axes[0]) is not int or type(dot_axes[1]) is not int:
|
||||
raise Exception('Invalid format for dot_axes - list elements should be "int".')
|
||||
if shape1[dot_axes[0]] != shape2[dot_axes[1]]:
|
||||
raise Exception('Dimension incompatibility using dot mode: ' +
|
||||
'%s != %s. ' % (shape1[dot_axes[0]], shape2[dot_axes[1]]) +
|
||||
'Layer shapes: %s, %s' % (shape1, shape2))
|
||||
elif mode == 'concat':
|
||||
reduced_inputs_shapes = [list(shape) for shape in input_shapes]
|
||||
shape_set = set()
|
||||
@@ -1210,7 +1239,11 @@ class Merge(Layer):
|
||||
for i in range(1, len(inputs)):
|
||||
s *= inputs[i]
|
||||
return s
|
||||
|
||||
elif self.mode == 'max':
|
||||
s = inputs[0]
|
||||
for i in range(1, len(inputs)):
|
||||
s = K.maximum(s, inputs[i])
|
||||
return s
|
||||
elif self.mode == 'dot':
|
||||
l1 = inputs[0]
|
||||
l2 = inputs[1]
|
||||
@@ -1222,6 +1255,7 @@ class Merge(Layer):
|
||||
l2 = inputs[1]
|
||||
denominator = K.sqrt(K.batch_dot(l1, l1, self.dot_axes) *
|
||||
K.batch_dot(l2, l2, self.dot_axes))
|
||||
denominator = K.maximum(denominator, K.epsilon())
|
||||
output = K.batch_dot(l1, l2, self.dot_axes) / denominator
|
||||
output = K.expand_dims(output, 1)
|
||||
return output
|
||||
@@ -1231,8 +1265,8 @@ class Merge(Layer):
|
||||
def __call__(self, inputs, mask=None):
|
||||
'''We disable successive calls to __call__ for Merge layers.
|
||||
Although there is no technical obstacle to
|
||||
making it possible to __call__ a Merge intance many times
|
||||
(it is just a layer), it would make for a rather unelegant API.
|
||||
making it possible to __call__ a Merge instance many times
|
||||
(it is just a layer), it would make for a rather inelegant API.
|
||||
'''
|
||||
if type(inputs) is not list:
|
||||
raise Exception('Merge can only be called on a list of tensors, '
|
||||
@@ -1260,25 +1294,24 @@ class Merge(Layer):
|
||||
tensor_indices.append(tensor_index)
|
||||
self._arguments_validation(layers, self.mode,
|
||||
self.concat_axis, self.dot_axes,
|
||||
self._output_shape,
|
||||
node_indices, tensor_indices)
|
||||
self.built = True
|
||||
self.add_inbound_node(layers, node_indices, tensor_indices)
|
||||
|
||||
outputs = self.inbound_nodes[-1].output_tensors
|
||||
return outputs[0] # merge only returns a single tensor
|
||||
return outputs[0] # merge only returns a single tensor
|
||||
else:
|
||||
return self.call(inputs, mask)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
assert type(input_shape) is list # must have mutiple input shape tuples
|
||||
assert type(input_shape) is list # must have multiple input shape tuples
|
||||
# case: callable self._output_shape
|
||||
if hasattr(self.mode, '__call__'):
|
||||
if hasattr(self._output_shape, '__call__'):
|
||||
output_shape = self._output_shape(input_shape)
|
||||
return output_shape
|
||||
elif self._output_shape is not None:
|
||||
return self._output_shape
|
||||
return (input_shape[0][0],) + tuple(self._output_shape)
|
||||
else:
|
||||
# TODO: consider shape auto-inference with TF
|
||||
raise Exception('The Merge layer ' + self.name +
|
||||
@@ -1289,7 +1322,7 @@ class Merge(Layer):
|
||||
'`output_shape` to Merge.')
|
||||
# pre-defined merge modes
|
||||
input_shapes = input_shape
|
||||
if self.mode in ['sum', 'mul', 'ave']:
|
||||
if self.mode in ['sum', 'mul', 'ave', 'max']:
|
||||
# all tuples in input_shapes should be the same
|
||||
return input_shapes[0]
|
||||
elif self.mode == 'concat':
|
||||
@@ -1300,12 +1333,10 @@ class Merge(Layer):
|
||||
break
|
||||
output_shape[self.concat_axis] += shape[self.concat_axis]
|
||||
return tuple(output_shape)
|
||||
elif self.mode == 'join':
|
||||
return None
|
||||
elif self.mode == 'dot':
|
||||
elif self.mode in ['dot', 'cos']:
|
||||
shape1 = list(input_shapes[0])
|
||||
shape2 = list(input_shapes[1])
|
||||
dot_axes = [a-1 for a in self.dot_axes]
|
||||
dot_axes = [a - 1 for a in self.dot_axes]
|
||||
tensordot_output = np.tensordot(np.zeros(tuple(shape1[1:])),
|
||||
np.zeros(tuple(shape2[1:])),
|
||||
axes=dot_axes)
|
||||
@@ -1314,25 +1345,40 @@ class Merge(Layer):
|
||||
else:
|
||||
shape = tensordot_output.shape
|
||||
return (shape1[0],) + shape
|
||||
elif self.mode == 'cos':
|
||||
return (input_shapes[0][0], 1)
|
||||
|
||||
def compute_mask(self, input, mask=None):
|
||||
'''TODO: add mask merging support
|
||||
'''
|
||||
if mask is not None and any(mask):
|
||||
raise Exception('Merge does not support masking, ' +
|
||||
'but was passed an input mask: ' + str(mask))
|
||||
return None
|
||||
def compute_mask(self, inputs, mask=None):
|
||||
if mask is None or all([m is None for m in mask]):
|
||||
return None
|
||||
|
||||
assert hasattr(mask, '__len__') and len(mask) == len(inputs)
|
||||
|
||||
if self.mode in ['sum', 'mul', 'ave']:
|
||||
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':
|
||||
masks = [K.ones_like(inputs[i][:-1]) if m is None else m for i, m in zip(inputs, mask)]
|
||||
expanded_dims = [K.expand_dims(m) for m in masks]
|
||||
concatenated = K.concatenate(expanded_dims, axis=self.concat_axis)
|
||||
return K.all(concatenated, axis=-1, keepdims=False)
|
||||
elif self.mode in ['cos', 'dot']:
|
||||
return None
|
||||
elif hasattr(self.mode, '__call__'):
|
||||
if hasattr(self._output_mask, '__call__'):
|
||||
return self._output_mask(mask)
|
||||
else:
|
||||
return self._output_mask
|
||||
else:
|
||||
# this should have been caught earlier
|
||||
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__)
|
||||
mode = marshal.dumps(self.mode.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
mode = marshal.dumps(self.mode.func_code)
|
||||
mode = marshal.dumps(self.mode.func_code).decode('raw_unicode_escape')
|
||||
mode_type = 'lambda'
|
||||
elif callable(self.mode):
|
||||
mode = self.mode.__name__
|
||||
@@ -1343,9 +1389,9 @@ class Merge(Layer):
|
||||
|
||||
if isinstance(self._output_shape, python_types.LambdaType):
|
||||
if py3:
|
||||
output_shape = marshal.dumps(self._output_shape.__code__)
|
||||
output_shape = marshal.dumps(self._output_shape.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
output_shape = marshal.dumps(self._output_shape.func_code)
|
||||
output_shape = marshal.dumps(self._output_shape.func_code).decode('raw_unicode_escape')
|
||||
output_shape_type = 'lambda'
|
||||
elif callable(self._output_shape):
|
||||
output_shape = self._output_shape.__name__
|
||||
@@ -1368,7 +1414,7 @@ class Merge(Layer):
|
||||
if mode_type == 'function':
|
||||
mode = globals()[config['mode']]
|
||||
elif mode_type == 'lambda':
|
||||
mode = marshal.loads(config['mode'])
|
||||
mode = marshal.loads(config['mode'].encode('raw_unicode_escape'))
|
||||
mode = python_types.FunctionType(mode, globals())
|
||||
else:
|
||||
mode = config['mode']
|
||||
@@ -1377,7 +1423,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'])
|
||||
output_shape = marshal.loads(config['output_shape'].encode('raw_unicode_escape'))
|
||||
output_shape = python_types.FunctionType(output_shape, globals())
|
||||
else:
|
||||
output_shape = config['output_shape']
|
||||
@@ -1388,7 +1434,7 @@ class Merge(Layer):
|
||||
|
||||
|
||||
def merge(inputs, mode='sum', concat_axis=-1,
|
||||
dot_axes=-1, output_shape=None, name=None):
|
||||
dot_axes=-1, output_shape=None, output_mask=None, name=None):
|
||||
'''Functional merge, to apply to Keras tensors (NOT layers).
|
||||
Returns a Keras tensor.
|
||||
|
||||
@@ -1402,7 +1448,7 @@ def merge(inputs, mode='sum', concat_axis=-1,
|
||||
|
||||
# Arguments
|
||||
mode: string or lambda/function. If string, must be one
|
||||
of: 'sum', 'mul', 'concat', 'ave', 'join', 'cos', 'dot'.
|
||||
of: 'sum', 'mul', 'concat', 'ave', 'cos', 'dot'.
|
||||
If lambda/function, it should take as input a list of tensors
|
||||
and return a single tensor.
|
||||
concat_axis: integer, axis to use in mode `concat`.
|
||||
@@ -1410,7 +1456,8 @@ def merge(inputs, mode='sum', concat_axis=-1,
|
||||
output_shape: shape tuple (tuple of integers), or lambda/function
|
||||
to compute output_shape (only if merge mode is a lambda/function).
|
||||
If the latter case, it should take as input a list of shape tuples
|
||||
(1:1 mapping to input tensors) and return a single shape tuple.
|
||||
(1:1 mapping to input tensors) and return a single shape tuple, including the
|
||||
batch size (same convention as the `get_output_shape_for` method of layers).
|
||||
node_indices: optional list of integers containing
|
||||
the output node index for each input layer
|
||||
(in case some input layers have multiple output nodes).
|
||||
@@ -1437,6 +1484,7 @@ def merge(inputs, mode='sum', concat_axis=-1,
|
||||
concat_axis=concat_axis,
|
||||
dot_axes=dot_axes,
|
||||
output_shape=output_shape,
|
||||
output_mask=output_mask,
|
||||
node_indices=node_indices,
|
||||
tensor_indices=tensor_indices,
|
||||
name=name)
|
||||
@@ -1446,6 +1494,7 @@ def merge(inputs, mode='sum', concat_axis=-1,
|
||||
concat_axis=concat_axis,
|
||||
dot_axes=dot_axes,
|
||||
output_shape=output_shape,
|
||||
output_mask=output_mask,
|
||||
name=name)
|
||||
return merge_layer(inputs)
|
||||
|
||||
@@ -1575,7 +1624,29 @@ class Container(Layer):
|
||||
self.output_layers.append(layer)
|
||||
self.output_layers_node_indices.append(node_index)
|
||||
self.output_layers_tensor_indices.append(tensor_index)
|
||||
# build self.output_layers:
|
||||
|
||||
# fill in the output mask cache
|
||||
masks = []
|
||||
for x in self.inputs:
|
||||
layer, node_index, tensor_index = x._keras_history
|
||||
node = layer.inbound_nodes[node_index]
|
||||
mask = node.output_masks[tensor_index]
|
||||
masks.append(mask)
|
||||
mask_cache_key = ','.join([str(id(x)) for x in self.inputs])
|
||||
mask_cache_key += '_' + ','.join([str(id(x)) for x in masks])
|
||||
masks = []
|
||||
for x in self.outputs:
|
||||
layer, node_index, tensor_index = x._keras_history
|
||||
node = layer.inbound_nodes[node_index]
|
||||
mask = node.output_masks[tensor_index]
|
||||
masks.append(mask)
|
||||
if len(masks) == 1:
|
||||
mask = masks[0]
|
||||
else:
|
||||
mask = masks
|
||||
self._output_mask_cache[mask_cache_key] = mask
|
||||
|
||||
# build self.input_layers:
|
||||
for x in self.inputs:
|
||||
layer, node_index, tensor_index = x._keras_history
|
||||
# it's supposed to be an input layer, so only one node
|
||||
@@ -1603,7 +1674,7 @@ class Container(Layer):
|
||||
nodes_depths = {} # map {node: depth value}
|
||||
layers_depths = {} # map {layer: depth value}
|
||||
|
||||
def make_node_key(node, depth):
|
||||
def make_node_marker(node, depth):
|
||||
return str(id(node)) + '-' + str(depth)
|
||||
|
||||
def build_map_of_graph(tensor, seen_nodes=set(), depth=0,
|
||||
@@ -1627,7 +1698,7 @@ class Container(Layer):
|
||||
node = layer.inbound_nodes[node_index]
|
||||
|
||||
# prevent cycles
|
||||
seen_nodes.add(make_node_key(node, depth))
|
||||
seen_nodes.add(make_node_marker(node, depth))
|
||||
|
||||
node_key = layer.name + '_ib-' + str(node_index)
|
||||
# update container_nodes
|
||||
@@ -1639,11 +1710,12 @@ class Container(Layer):
|
||||
else:
|
||||
nodes_depths[node] = max(depth, node_depth)
|
||||
# update layers_depths
|
||||
layer_depth = layers_depths.get(layer)
|
||||
if layer_depth is None:
|
||||
layers_depths[layer] = depth
|
||||
previously_seen_depth = layers_depths.get(layer)
|
||||
if previously_seen_depth is None:
|
||||
current_depth = depth
|
||||
else:
|
||||
layers_depths[layer] = max(depth, layer_depth)
|
||||
current_depth = max(depth, previously_seen_depth)
|
||||
layers_depths[layer] = current_depth
|
||||
|
||||
# propagate to all previous tensors connected to this node
|
||||
for i in range(len(node.inbound_layers)):
|
||||
@@ -1652,9 +1724,10 @@ class Container(Layer):
|
||||
node_index = node.node_indices[i]
|
||||
tensor_index = node.tensor_indices[i]
|
||||
next_node = layer.inbound_nodes[node_index]
|
||||
node_key = make_node_key(next_node, depth + 1)
|
||||
if node_key not in seen_nodes:
|
||||
build_map_of_graph(x, seen_nodes, depth + 1,
|
||||
# use node_marker to prevent cycles
|
||||
node_marker = make_node_marker(next_node, current_depth + 1)
|
||||
if node_marker not in seen_nodes:
|
||||
build_map_of_graph(x, seen_nodes, current_depth + 1,
|
||||
layer, node_index, tensor_index)
|
||||
|
||||
for x in self.outputs:
|
||||
@@ -2064,6 +2137,8 @@ class Container(Layer):
|
||||
for x, s in zip(output_tensors, shapes):
|
||||
x._keras_shape = s
|
||||
x._uses_learning_phase = uses_learning_phase
|
||||
|
||||
# update tensor_map
|
||||
for x, y, mask in zip(reference_output_tensors, output_tensors, output_masks):
|
||||
tensor_map[str(id(x))] = (y, mask)
|
||||
|
||||
@@ -2109,8 +2184,6 @@ class Container(Layer):
|
||||
return output_tensors, output_masks, output_shapes
|
||||
|
||||
def get_config(self):
|
||||
'''TODO: add keras version information
|
||||
'''
|
||||
config = {
|
||||
'name': self.name,
|
||||
}
|
||||
@@ -2191,9 +2264,9 @@ class Container(Layer):
|
||||
# the graph reconstruction process
|
||||
created_layers = {}
|
||||
|
||||
# iterate over saved layers, instantiate them,
|
||||
# then call them on appropriate inputs to create graph nodes
|
||||
for layer_data in config['layers']:
|
||||
def process_layer(layer_data):
|
||||
# iterate over saved layers, instantiate them,
|
||||
# then call them on appropriate inputs to create graph nodes
|
||||
layer_name = layer_data['name']
|
||||
|
||||
# instantiate layer
|
||||
@@ -2218,6 +2291,10 @@ class Container(Layer):
|
||||
layer(input_tensors[0])
|
||||
else:
|
||||
layer(input_tensors)
|
||||
|
||||
for layer_data in config['layers']:
|
||||
process_layer(layer_data)
|
||||
|
||||
name = config.get('name')
|
||||
input_tensors = []
|
||||
output_tensors = []
|
||||
@@ -2275,7 +2352,7 @@ class Container(Layer):
|
||||
for layer in flattened_layers:
|
||||
g = f.create_group(layer.name)
|
||||
symbolic_weights = layer.trainable_weights + layer.non_trainable_weights
|
||||
weight_values = layer.get_weights()
|
||||
weight_values = K.batch_get_value(symbolic_weights)
|
||||
weight_names = []
|
||||
for i, (w, val) in enumerate(zip(symbolic_weights, weight_values)):
|
||||
if hasattr(w, 'name') and w.name:
|
||||
@@ -2350,6 +2427,26 @@ class Container(Layer):
|
||||
K.batch_set_value(weight_value_tuples)
|
||||
f.close()
|
||||
|
||||
def _updated_config(self):
|
||||
'''shared between different serialization methods'''
|
||||
from keras import __version__ as keras_version
|
||||
|
||||
config = self.get_config()
|
||||
model_config = {
|
||||
'class_name': self.__class__.__name__,
|
||||
'config': config,
|
||||
'keras_version': keras_version
|
||||
}
|
||||
|
||||
if hasattr(self, 'optimizer'):
|
||||
model_config['optimizer'] = self.optimizer.get_config()
|
||||
model_config['loss'] = getattr(self.loss, '__name__', self.loss)
|
||||
model_config['sample_weight_mode'] = self.sample_weight_mode
|
||||
|
||||
if hasattr(self, 'loss_weights'):
|
||||
model_config['loss_weights'] = self.loss_weights
|
||||
return model_config
|
||||
|
||||
def to_json(self, **kwargs):
|
||||
'''Returns a JSON string containing the network configuration.
|
||||
|
||||
@@ -2369,11 +2466,7 @@ class Container(Layer):
|
||||
|
||||
raise TypeError('Not JSON Serializable')
|
||||
|
||||
config = self.get_config()
|
||||
model_config = {
|
||||
'class_name': self.__class__.__name__,
|
||||
'config': config,
|
||||
}
|
||||
model_config = self._updated_config()
|
||||
return json.dumps(model_config, default=get_json_type, **kwargs)
|
||||
|
||||
def to_yaml(self, **kwargs):
|
||||
@@ -2387,14 +2480,9 @@ class Container(Layer):
|
||||
functions / classes.
|
||||
'''
|
||||
import yaml
|
||||
config = self.get_config()
|
||||
model_config = {
|
||||
'class_name': self.__class__.__name__,
|
||||
'config': config,
|
||||
}
|
||||
return yaml.dump(model_config, **kwargs)
|
||||
return yaml.dump(self._updated_config(), **kwargs)
|
||||
|
||||
def summary(self):
|
||||
def summary(self, line_length=100, positions=[.33, .55, .67, 1.]):
|
||||
from keras.utils.layer_utils import print_summary
|
||||
|
||||
if hasattr(self, 'flattened_layers'):
|
||||
@@ -2403,7 +2491,7 @@ class Container(Layer):
|
||||
else:
|
||||
flattened_layers = self.layers
|
||||
|
||||
print_summary(flattened_layers, getattr(self, 'container_nodes', None))
|
||||
print_summary(flattened_layers, getattr(self, 'container_nodes', None), line_length=line_length, positions=positions)
|
||||
|
||||
|
||||
def get_source_inputs(tensor, layer=None, node_index=None):
|
||||
|
||||
+157
-71
@@ -5,6 +5,7 @@ import warnings
|
||||
import copy
|
||||
import time
|
||||
import numpy as np
|
||||
import multiprocessing
|
||||
import threading
|
||||
try:
|
||||
import queue
|
||||
@@ -20,7 +21,8 @@ from ..utils.generic_utils import Progbar
|
||||
from .. import callbacks as cbks
|
||||
|
||||
|
||||
def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
|
||||
def standardize_input_data(data, names, shapes=None,
|
||||
check_batch_dim=True,
|
||||
exception_prefix=''):
|
||||
'''Users may pass data as a list of arrays, dictionary of arrays,
|
||||
or as a single array. We normalize this to an ordered list of
|
||||
@@ -54,7 +56,7 @@ def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
|
||||
raise Exception('Error when checking ' + exception_prefix +
|
||||
': you are passing a list as '
|
||||
'input to your model, '
|
||||
'but the model expects a '
|
||||
'but the model expects '
|
||||
'a list of ' + str(len(names)) +
|
||||
' Numpy arrays instead. '
|
||||
'The list you passed was: ' +
|
||||
@@ -84,8 +86,7 @@ def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
|
||||
# check shapes compatibility
|
||||
if shapes:
|
||||
for i in range(len(names)):
|
||||
if not i and not check_batch_dim:
|
||||
# skip the first axis
|
||||
if shapes[i] is None:
|
||||
continue
|
||||
array = arrays[i]
|
||||
if len(array.shape) != len(shapes[i]):
|
||||
@@ -94,7 +95,10 @@ def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
|
||||
' to have ' + str(len(shapes[i])) +
|
||||
' dimensions, but got array with shape ' +
|
||||
str(array.shape))
|
||||
for dim, ref_dim in zip(array.shape, shapes[i]):
|
||||
for j, (dim, ref_dim) in enumerate(zip(array.shape, shapes[i])):
|
||||
if not j and not check_batch_dim:
|
||||
# skip the first axis
|
||||
continue
|
||||
if ref_dim:
|
||||
if ref_dim != dim:
|
||||
raise Exception('Error when checking ' + exception_prefix +
|
||||
@@ -202,12 +206,12 @@ def check_loss_and_target_compatibility(targets, losses, output_shapes):
|
||||
'`sparse_categorical_crossentropy` instead, '
|
||||
'which does expect integer targets.')
|
||||
if loss.__name__ in key_losses and shape[1] is not None and y.shape[1] != shape[1]:
|
||||
raise Exception('A target array with shape ' + str(y.shape) +
|
||||
' was passed for an output of shape ' + str(shape) +
|
||||
' while using as loss `' + loss.__name__ + '`. '
|
||||
'This loss expects '
|
||||
'targets to have the same shape '
|
||||
'as the output.')
|
||||
raise Exception('A target array with shape ' + str(y.shape) +
|
||||
' was passed for an output of shape ' + str(shape) +
|
||||
' while using as loss `' + loss.__name__ + '`. '
|
||||
'This loss expects '
|
||||
'targets to have the same shape '
|
||||
'as the output.')
|
||||
|
||||
|
||||
def collect_metrics(metrics, output_names):
|
||||
@@ -231,11 +235,17 @@ def collect_metrics(metrics, output_names):
|
||||
|
||||
|
||||
def collect_trainable_weights(layer):
|
||||
'''Collects all `trainable_weights` attributes,
|
||||
excluding any sublayers where `trainable` is set the `False`.
|
||||
'''
|
||||
trainable = getattr(layer, 'trainable', True)
|
||||
if not trainable:
|
||||
return []
|
||||
weights = []
|
||||
if layer.__class__.__name__ in ['Sequential', 'Model']:
|
||||
if layer.__class__.__name__ == 'Sequential':
|
||||
for sublayer in layer.flattened_layers:
|
||||
weights += collect_trainable_weights(sublayer)
|
||||
elif layer.__class__.__name__ == 'Model':
|
||||
for sublayer in layer.layers:
|
||||
weights += collect_trainable_weights(sublayer)
|
||||
elif layer.__class__.__name__ == 'Graph':
|
||||
@@ -243,6 +253,9 @@ def collect_trainable_weights(layer):
|
||||
weights += collect_trainable_weights(sublayer)
|
||||
else:
|
||||
weights += layer.trainable_weights
|
||||
# dedupe weights
|
||||
weights = list(set(weights))
|
||||
weights.sort(key=lambda x: x.name)
|
||||
return weights
|
||||
|
||||
|
||||
@@ -383,40 +396,64 @@ def standardize_weights(y, sample_weight=None, class_weight=None,
|
||||
return weights
|
||||
else:
|
||||
if sample_weight_mode is None:
|
||||
return np.ones((y.shape[0],))
|
||||
return np.ones((y.shape[0],), dtype=K.floatx())
|
||||
else:
|
||||
return np.ones((y.shape[0], y.shape[1]))
|
||||
return np.ones((y.shape[0], y.shape[1]), dtype=K.floatx())
|
||||
|
||||
|
||||
def generator_queue(generator, max_q_size=10,
|
||||
wait_time=0.05, nb_worker=1):
|
||||
'''Builds a threading queue out of a data generator.
|
||||
wait_time=0.05, nb_worker=1, pickle_safe=False):
|
||||
'''Builds a queue out of a data generator.
|
||||
If pickle_safe, use a multiprocessing approach. Else, use threading.
|
||||
Used in `fit_generator`, `evaluate_generator`, `predict_generator`.
|
||||
|
||||
'''
|
||||
q = queue.Queue()
|
||||
_stop = threading.Event()
|
||||
|
||||
def data_generator_task():
|
||||
while not _stop.is_set():
|
||||
try:
|
||||
if q.qsize() < max_q_size:
|
||||
try:
|
||||
generator_output = next(generator)
|
||||
except ValueError:
|
||||
continue
|
||||
q.put(generator_output)
|
||||
else:
|
||||
time.sleep(wait_time)
|
||||
except Exception:
|
||||
_stop.set()
|
||||
raise
|
||||
generator_threads = []
|
||||
if pickle_safe:
|
||||
q = multiprocessing.Queue(maxsize=max_q_size)
|
||||
_stop = multiprocessing.Event()
|
||||
else:
|
||||
q = queue.Queue()
|
||||
_stop = threading.Event()
|
||||
|
||||
generator_threads = [threading.Thread(target=data_generator_task)
|
||||
for _ in range(nb_worker)]
|
||||
try:
|
||||
|
||||
for thread in generator_threads:
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
def data_generator_task():
|
||||
while not _stop.is_set():
|
||||
try:
|
||||
if q.qsize() < max_q_size:
|
||||
try:
|
||||
generator_output = next(generator)
|
||||
except ValueError:
|
||||
continue
|
||||
q.put(generator_output)
|
||||
else:
|
||||
time.sleep(wait_time)
|
||||
except Exception:
|
||||
_stop.set()
|
||||
raise
|
||||
|
||||
for i in range(nb_worker):
|
||||
if pickle_safe:
|
||||
# Reset random seed else all children processes share the same seed
|
||||
np.random.seed()
|
||||
thread = multiprocessing.Process(target=data_generator_task)
|
||||
else:
|
||||
thread = threading.Thread(target=data_generator_task)
|
||||
generator_threads.append(thread)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
except:
|
||||
_stop.set()
|
||||
if pickle_safe:
|
||||
# Terminate all daemon processes
|
||||
for p in generator_threads:
|
||||
if p.is_alive():
|
||||
p.terminate()
|
||||
q.close()
|
||||
raise
|
||||
|
||||
return q, _stop
|
||||
|
||||
@@ -452,6 +489,7 @@ class Model(Container):
|
||||
self.optimizer = optimizers.get(optimizer)
|
||||
self.sample_weight_mode = sample_weight_mode
|
||||
self.loss = loss
|
||||
self.loss_weights = loss_weights
|
||||
|
||||
# prepare loss weights
|
||||
if loss_weights is None:
|
||||
@@ -472,7 +510,7 @@ class Model(Container):
|
||||
'it should have one entry per model outputs. '
|
||||
'The model has ' + str(len(self.outputs)) +
|
||||
' outputs, but you passed loss_weights=' +
|
||||
str(loss))
|
||||
str(loss_weights))
|
||||
loss_weights_list = loss_weights
|
||||
else:
|
||||
raise Exception('Could not interpret loss_weights argument: ' +
|
||||
@@ -571,6 +609,10 @@ class Model(Container):
|
||||
name = self.output_names[i]
|
||||
self.targets.append(K.placeholder(ndim=len(shape), name=name + '_target'))
|
||||
|
||||
# prepare metrics
|
||||
self.metrics_names = ['loss']
|
||||
self.metrics = []
|
||||
|
||||
# compute total loss
|
||||
total_loss = None
|
||||
for i in range(len(self.outputs)):
|
||||
@@ -580,19 +622,20 @@ class Model(Container):
|
||||
sample_weight = sample_weights[i]
|
||||
mask = masks[i]
|
||||
loss_weight = loss_weights_list[i]
|
||||
output_loss = loss_weight * weighted_loss(y_true, y_pred,
|
||||
sample_weight, mask)
|
||||
output_loss = weighted_loss(y_true, y_pred,
|
||||
sample_weight, mask)
|
||||
if len(self.outputs) > 1:
|
||||
self.metrics.append(output_loss)
|
||||
self.metrics_names.append(self.output_names[i] + '_loss')
|
||||
if total_loss is None:
|
||||
total_loss = output_loss
|
||||
total_loss = loss_weight * output_loss
|
||||
else:
|
||||
total_loss += output_loss
|
||||
total_loss += loss_weight * output_loss
|
||||
|
||||
# add regularization penalties to the loss
|
||||
for r in self.regularizers:
|
||||
total_loss = r(total_loss)
|
||||
|
||||
# prepare metrics
|
||||
self.metrics_names = ['loss']
|
||||
self.metrics = []
|
||||
# list of same size as output_names.
|
||||
# contains tuples (metrics for output, names of metrics)
|
||||
nested_metrics = collect_metrics(metrics, self.output_names)
|
||||
@@ -605,7 +648,7 @@ class Model(Container):
|
||||
if metric == 'accuracy' or metric == 'acc':
|
||||
# custom handling of accuracy (because of class mode duality)
|
||||
output_shape = self.internal_output_shapes[i]
|
||||
if output_shape[-1] == 1:
|
||||
if output_shape[-1] == 1 or self.loss_functions[i] == objectives.binary_crossentropy:
|
||||
# case: binary accuracy
|
||||
self.metrics.append(metrics_module.binary_accuracy(y_true, y_pred))
|
||||
elif self.loss_functions[i] == objectives.sparse_categorical_crossentropy:
|
||||
@@ -651,10 +694,7 @@ class Model(Container):
|
||||
inputs = self.inputs + self.targets + self.sample_weights
|
||||
|
||||
# get trainable weights
|
||||
trainable_weights = []
|
||||
for layer in self.layers:
|
||||
trainable_weights += collect_trainable_weights(layer)
|
||||
|
||||
trainable_weights = collect_trainable_weights(self)
|
||||
training_updates = self.optimizer.get_updates(trainable_weights, self.constraints, self.total_loss)
|
||||
updates = self.updates + training_updates
|
||||
|
||||
@@ -681,7 +721,7 @@ class Model(Container):
|
||||
|
||||
def _make_predict_function(self):
|
||||
if not hasattr(self, 'predict_function'):
|
||||
raise Exception('You must compile your model before using it.')
|
||||
self.predict_function = None
|
||||
if self.predict_function is None:
|
||||
if self.uses_learning_phase:
|
||||
inputs = self.inputs + [K.learning_phase()]
|
||||
@@ -689,10 +729,11 @@ class Model(Container):
|
||||
inputs = self.inputs
|
||||
# returns network outputs. Does not update weights.
|
||||
# Does update the network states.
|
||||
kwargs = getattr(self, '_function_kwargs', {})
|
||||
self.predict_function = K.function(inputs,
|
||||
self.outputs,
|
||||
updates=self.state_updates,
|
||||
**self._function_kwargs)
|
||||
**kwargs)
|
||||
|
||||
def _fit_loop(self, f, ins, out_labels=[], batch_size=32,
|
||||
nb_epoch=100, verbose=1, callbacks=[],
|
||||
@@ -765,6 +806,7 @@ class Model(Container):
|
||||
np.random.shuffle(index_array)
|
||||
|
||||
batches = make_batches(nb_train_sample, batch_size)
|
||||
epoch_logs = {}
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
try:
|
||||
@@ -789,7 +831,6 @@ class Model(Container):
|
||||
|
||||
callbacks.on_batch_end(batch_index, batch_logs)
|
||||
|
||||
epoch_logs = {}
|
||||
if batch_index == len(batches) - 1: # last batch
|
||||
# validation
|
||||
if do_validation:
|
||||
@@ -818,7 +859,7 @@ class Model(Container):
|
||||
verbose: verbosity mode.
|
||||
|
||||
# Returns
|
||||
Array of prections (if the model has a single output)
|
||||
Array of predictions (if the model has a single output)
|
||||
or list of arrays of predictions
|
||||
(if the model has multiple outputs).
|
||||
'''
|
||||
@@ -842,7 +883,7 @@ class Model(Container):
|
||||
if batch_index == 0:
|
||||
for batch_out in batch_outs:
|
||||
shape = (nb_sample,) + batch_out.shape[1:]
|
||||
outs.append(np.zeros(shape))
|
||||
outs.append(np.zeros(shape, dtype=K.floatx()))
|
||||
|
||||
for i, batch_out in enumerate(batch_outs):
|
||||
outs[i][batch_start:batch_end] = batch_out
|
||||
@@ -908,12 +949,20 @@ class Model(Container):
|
||||
raise Exception('You must compile a model before training/testing.'
|
||||
' Use `model.compile(optimizer, loss)`.')
|
||||
|
||||
output_shapes = []
|
||||
for output_shape, loss_fn in zip(self.internal_output_shapes, self.loss_functions):
|
||||
if loss_fn.__name__ == 'sparse_categorical_crossentropy':
|
||||
output_shapes.append(output_shape[:-1] + (1,))
|
||||
elif getattr(objectives, loss_fn.__name__, None) is None:
|
||||
output_shapes.append(None)
|
||||
else:
|
||||
output_shapes.append(output_shape)
|
||||
x = standardize_input_data(x, self.input_names,
|
||||
self.internal_input_shapes,
|
||||
check_batch_dim=False,
|
||||
exception_prefix='model input')
|
||||
y = standardize_input_data(y, self.output_names,
|
||||
self.internal_output_shapes,
|
||||
output_shapes,
|
||||
check_batch_dim=False,
|
||||
exception_prefix='model target')
|
||||
sample_weights = standardize_sample_weights(sample_weight,
|
||||
@@ -962,7 +1011,7 @@ class Model(Container):
|
||||
at the end of each epoch. The model will not be trained on this data.
|
||||
This could be a tuple (x_val, y_val) or a tuple (val_x, val_y, val_sample_weights).
|
||||
shuffle: boolean, whether to shuffle the training data before each epoch.
|
||||
class_weight: optional dictionary mapping classe indices (integers) to
|
||||
class_weight: optional dictionary mapping class indices (integers) to
|
||||
a weight (float) to apply to the model's loss for the samples
|
||||
from this class during training.
|
||||
This can be useful to tell the model to "pay more attention" to
|
||||
@@ -1011,7 +1060,8 @@ class Model(Container):
|
||||
split_at = int(len(x[0]) * (1. - validation_split))
|
||||
x, val_x = (slice_X(x, 0, split_at), slice_X(x, split_at))
|
||||
y, val_y = (slice_X(y, 0, split_at), slice_X(y, split_at))
|
||||
sample_weights, val_sample_weights = (slice_X(sample_weights, 0, split_at), slice_X(sample_weights, split_at))
|
||||
sample_weights, val_sample_weights = (
|
||||
slice_X(sample_weights, 0, split_at), slice_X(sample_weights, split_at))
|
||||
self._make_test_function()
|
||||
val_f = self.test_function
|
||||
if self.uses_learning_phase:
|
||||
@@ -1033,6 +1083,18 @@ class Model(Container):
|
||||
|
||||
# prepare display labels
|
||||
out_labels = self.metrics_names
|
||||
|
||||
# rename duplicated metrics name
|
||||
# (can happen with an output layer shared among multiple dataflows)
|
||||
deduped_out_labels = []
|
||||
for i, label in enumerate(out_labels):
|
||||
new_label = label
|
||||
if out_labels.count(label) > 1:
|
||||
dup_idx = out_labels[:i].count(label)
|
||||
new_label += '_' + str(dup_idx + 1)
|
||||
deduped_out_labels.append(new_label)
|
||||
out_labels = deduped_out_labels
|
||||
|
||||
if do_validation:
|
||||
callback_metrics = copy.copy(out_labels) + ['val_' + n for n in out_labels]
|
||||
else:
|
||||
@@ -1047,7 +1109,7 @@ class Model(Container):
|
||||
|
||||
def evaluate(self, x, y, batch_size=32, verbose=1, sample_weight=None):
|
||||
'''Returns the loss value and metrics values for the model
|
||||
in test mode. Computation in done in batches.
|
||||
in test mode. Computation is done in batches.
|
||||
|
||||
# Arguments
|
||||
x: Numpy array of test data,
|
||||
@@ -1137,7 +1199,7 @@ class Model(Container):
|
||||
with shape (samples, sequence_length),
|
||||
to apply a different weight to every timestep of every sample.
|
||||
In this case you should make sure to specify sample_weight_mode="temporal" in compile().
|
||||
class_weight: optional dictionary mapping classe indices (integers) to
|
||||
class_weight: optional dictionary mapping class indices (integers) to
|
||||
a weight (float) to apply to the model's loss for the samples
|
||||
from this class during training.
|
||||
This can be useful to tell the model to "pay more attention" to
|
||||
@@ -1219,7 +1281,7 @@ class Model(Container):
|
||||
def fit_generator(self, generator, samples_per_epoch, nb_epoch,
|
||||
verbose=1, callbacks=[],
|
||||
validation_data=None, nb_val_samples=None,
|
||||
class_weight={}, max_q_size=10):
|
||||
class_weight={}, max_q_size=10, nb_worker=1, pickle_safe=False):
|
||||
'''Fits the model on data generated batch-by-batch by
|
||||
a Python generator.
|
||||
The generator is run in parallel to the model, for efficiency.
|
||||
@@ -1250,6 +1312,11 @@ class Model(Container):
|
||||
class_weight: dictionary mapping class indices to a weight
|
||||
for the class.
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up when using process based threading
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
# Returns
|
||||
A `History` object.
|
||||
@@ -1328,7 +1395,8 @@ class Model(Container):
|
||||
self.validation_data = None
|
||||
|
||||
# start generator thread storing batches into a queue
|
||||
data_gen_queue, _stop = generator_queue(generator, max_q_size=max_q_size)
|
||||
data_gen_queue, _stop = generator_queue(generator, max_q_size=max_q_size, nb_worker=nb_worker,
|
||||
pickle_safe=pickle_safe)
|
||||
|
||||
callback_model.stop_training = False
|
||||
while epoch < nb_epoch:
|
||||
@@ -1375,7 +1443,7 @@ class Model(Container):
|
||||
outs = self.train_on_batch(x, y,
|
||||
sample_weight=sample_weight,
|
||||
class_weight=class_weight)
|
||||
except Exception as e:
|
||||
except:
|
||||
_stop.set()
|
||||
raise
|
||||
|
||||
@@ -1421,10 +1489,12 @@ class Model(Container):
|
||||
break
|
||||
|
||||
_stop.set()
|
||||
if pickle_safe:
|
||||
data_gen_queue.close()
|
||||
callbacks.on_train_end()
|
||||
return self.history
|
||||
|
||||
def evaluate_generator(self, generator, val_samples, max_q_size=10):
|
||||
def evaluate_generator(self, generator, val_samples, max_q_size=10, nb_worker=1, pickle_safe=False):
|
||||
'''Evaluates the model on a data generator. The generator should
|
||||
return the same kind of data as accepted by `test_on_batch`.
|
||||
|
||||
@@ -1436,6 +1506,11 @@ class Model(Container):
|
||||
total number of samples to generate from `generator`
|
||||
before returning.
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up when using process based threading
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
# Returns
|
||||
Scalar test loss (if the model has a single output and no metrics)
|
||||
@@ -1449,7 +1524,8 @@ class Model(Container):
|
||||
wait_time = 0.01
|
||||
all_outs = []
|
||||
weights = []
|
||||
data_gen_queue, _stop = generator_queue(generator, max_q_size=max_q_size)
|
||||
data_gen_queue, _stop = generator_queue(generator, max_q_size=max_q_size, nb_worker=nb_worker,
|
||||
pickle_safe=pickle_safe)
|
||||
|
||||
while processed_samples < val_samples:
|
||||
generator_output = None
|
||||
@@ -1477,7 +1553,7 @@ class Model(Container):
|
||||
'or (x, y). Found: ' + str(generator_output))
|
||||
try:
|
||||
outs = self.test_on_batch(x, y, sample_weight=sample_weight)
|
||||
except Exception as e:
|
||||
except:
|
||||
_stop.set()
|
||||
raise
|
||||
|
||||
@@ -1493,6 +1569,8 @@ class Model(Container):
|
||||
weights.append(nb_samples)
|
||||
|
||||
_stop.set()
|
||||
if pickle_safe:
|
||||
data_gen_queue.close()
|
||||
if type(outs) is not list:
|
||||
return np.average(np.asarray(all_outs),
|
||||
weights=weights)
|
||||
@@ -1500,10 +1578,10 @@ class Model(Container):
|
||||
averages = []
|
||||
for i in range(len(outs)):
|
||||
averages.append(np.average([out[i] for out in all_outs],
|
||||
weights=weights))
|
||||
weights=weights))
|
||||
return averages
|
||||
|
||||
def predict_generator(self, generator, val_samples, max_q_size=10):
|
||||
def predict_generator(self, generator, val_samples, max_q_size=10, nb_worker=1, pickle_safe=False):
|
||||
'''Generates predictions for the input samples from a data generator.
|
||||
The generator should return the same kind of data as accepted by
|
||||
`predict_on_batch`.
|
||||
@@ -1513,6 +1591,11 @@ class Model(Container):
|
||||
val_samples: total number of samples to generate from `generator`
|
||||
before returning.
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up when using process based threading
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
# Returns
|
||||
Numpy array(s) of predictions.
|
||||
@@ -1522,7 +1605,8 @@ class Model(Container):
|
||||
processed_samples = 0
|
||||
wait_time = 0.01
|
||||
all_outs = []
|
||||
data_gen_queue, _stop = generator_queue(generator, max_q_size=max_q_size)
|
||||
data_gen_queue, _stop = generator_queue(generator, max_q_size=max_q_size, nb_worker=nb_worker,
|
||||
pickle_safe=pickle_safe)
|
||||
|
||||
while processed_samples < val_samples:
|
||||
generator_output = None
|
||||
@@ -1549,7 +1633,7 @@ class Model(Container):
|
||||
|
||||
try:
|
||||
outs = self.predict_on_batch(x)
|
||||
except Exception as e:
|
||||
except:
|
||||
_stop.set()
|
||||
raise
|
||||
|
||||
@@ -1566,7 +1650,7 @@ class Model(Container):
|
||||
if len(all_outs) == 0:
|
||||
for out in outs:
|
||||
shape = (val_samples,) + out.shape[1:]
|
||||
all_outs.append(np.zeros(shape))
|
||||
all_outs.append(np.zeros(shape, dtype=K.floatx()))
|
||||
|
||||
for i, out in enumerate(outs):
|
||||
all_outs[i][processed_samples:(processed_samples + nb_samples)] = out
|
||||
@@ -1574,6 +1658,8 @@ class Model(Container):
|
||||
processed_samples += nb_samples
|
||||
|
||||
_stop.set()
|
||||
if pickle_safe:
|
||||
data_gen_queue.close()
|
||||
if len(all_outs) == 1:
|
||||
return all_outs[0]
|
||||
return all_outs
|
||||
|
||||
@@ -12,11 +12,13 @@ def get_fans(shape, dim_ordering='th'):
|
||||
# TH kernel shape: (depth, input_depth, ...)
|
||||
# TF kernel shape: (..., input_depth, depth)
|
||||
if dim_ordering == 'th':
|
||||
fan_in = np.prod(shape[1:])
|
||||
fan_out = shape[0]
|
||||
receptive_field_size = np.prod(shape[2:])
|
||||
fan_in = shape[1] * receptive_field_size
|
||||
fan_out = shape[0] * receptive_field_size
|
||||
elif dim_ordering == 'tf':
|
||||
fan_in = np.prod(shape[:-1])
|
||||
fan_out = shape[-1]
|
||||
receptive_field_size = np.prod(shape[:2])
|
||||
fan_in = shape[-2] * receptive_field_size
|
||||
fan_out = shape[-1] * receptive_field_size
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + dim_ordering)
|
||||
else:
|
||||
|
||||
@@ -2,6 +2,8 @@ from __future__ import absolute_import
|
||||
from ..engine import Layer, Input, InputLayer, Merge, merge, InputSpec
|
||||
from .core import *
|
||||
from .convolutional import *
|
||||
from .pooling import *
|
||||
from .local import *
|
||||
from .recurrent import *
|
||||
from .normalization import *
|
||||
from .embeddings import *
|
||||
|
||||
@@ -51,7 +51,7 @@ class PReLU(Layer):
|
||||
|
||||
# Arguments
|
||||
init: initialization function for the weights.
|
||||
weights: initial weights, as a list of a single numpy array.
|
||||
weights: initial weights, as a list of a single Numpy array.
|
||||
|
||||
# References
|
||||
- [Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification](http://arxiv.org/pdf/1502.01852v1.pdf)
|
||||
|
||||
+495
-466
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+83
-50
@@ -161,7 +161,7 @@ class Reshape(Layer):
|
||||
'''Find and replace a single missing dimension in an output shape
|
||||
given an input shape.
|
||||
|
||||
A near direct port of the internal numpy function _fix_unknown_dimension
|
||||
A near direct port of the internal Numpy function _fix_unknown_dimension
|
||||
in numpy/core/src/multiarray/shape.c
|
||||
|
||||
# Arguments
|
||||
@@ -387,7 +387,14 @@ class Lambda(Layer):
|
||||
function: The function to be evaluated.
|
||||
Takes one argument: the output of previous layer
|
||||
output_shape: Expected output shape from function.
|
||||
Could be a tuple or a function of the shape of the input
|
||||
Can be a tuple or function.
|
||||
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)`
|
||||
arguments: optional dictionary of keyword arguments to be passed
|
||||
to the function.
|
||||
|
||||
@@ -402,6 +409,8 @@ class Lambda(Layer):
|
||||
def __init__(self, function, output_shape=None, arguments={}, **kwargs):
|
||||
self.function = function
|
||||
self.arguments = arguments
|
||||
self.supports_masking = False
|
||||
|
||||
if output_shape is None:
|
||||
self._output_shape = None
|
||||
elif type(output_shape) in {tuple, list}:
|
||||
@@ -460,9 +469,9 @@ class Lambda(Layer):
|
||||
|
||||
if isinstance(self._output_shape, python_types.LambdaType):
|
||||
if py3:
|
||||
output_shape = marshal.dumps(self._output_shape.__code__)
|
||||
output_shape = marshal.dumps(self._output_shape.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
output_shape = marshal.dumps(self._output_shape.func_code)
|
||||
output_shape = marshal.dumps(self._output_shape.func_code).decode('raw_unicode_escape')
|
||||
output_shape_type = 'lambda'
|
||||
elif callable(self._output_shape):
|
||||
output_shape = self._output_shape.__name__
|
||||
@@ -494,7 +503,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'])
|
||||
output_shape = marshal.loads(config['output_shape'].encode('raw_unicode_escape'))
|
||||
output_shape = python_types.FunctionType(output_shape, globals())
|
||||
else:
|
||||
output_shape = config['output_shape']
|
||||
@@ -537,7 +546,7 @@ class Dense(Layer):
|
||||
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.
|
||||
weights: list of Numpy arrays to set as initial weights.
|
||||
The list should have 2 elements, of shape `(input_dim, output_dim)`
|
||||
and (output_dim,) for weights and biases respectively.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
@@ -550,12 +559,10 @@ class Dense(Layer):
|
||||
(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: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
bias: boolean
|
||||
Default True;
|
||||
Setting it to False will remove the bias (b) from all calculations.
|
||||
|
||||
# Input shape
|
||||
2D tensor with shape: `(nb_samples, input_dim)`.
|
||||
@@ -565,7 +572,8 @@ class Dense(Layer):
|
||||
'''
|
||||
def __init__(self, output_dim, init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, bias=True, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, **kwargs):
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
self.output_dim = output_dim
|
||||
@@ -606,7 +614,7 @@ class Dense(Layer):
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer and self.bias:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -617,7 +625,7 @@ class Dense(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint and self.bias:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -643,8 +651,8 @@ class Dense(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'input_dim': self.input_dim,
|
||||
'bias': self.bias}
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim}
|
||||
base_config = super(Dense, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -670,10 +678,10 @@ class ActivityRegularization(Layer):
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
|
||||
super(ActivityRegularization, self).__init__(**kwargs)
|
||||
activity_regularizer = ActivityRegularizer(l1=l1, l2=l2)
|
||||
activity_regularizer.set_layer(self)
|
||||
self.regularizers = [activity_regularizer]
|
||||
super(ActivityRegularization, self).__init__(**kwargs)
|
||||
|
||||
def get_config(self):
|
||||
config = {'l1': self.l1,
|
||||
@@ -703,12 +711,7 @@ class MaxoutDense(Layer):
|
||||
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.
|
||||
weights: list of Numpy arrays to set as initial weights.
|
||||
The list should have 2 elements, of shape `(input_dim, output_dim)`
|
||||
and (output_dim,) for weights and biases respectively.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
@@ -721,6 +724,7 @@ class MaxoutDense(Layer):
|
||||
(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: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
@@ -737,7 +741,8 @@ class MaxoutDense(Layer):
|
||||
def __init__(self, output_dim, nb_feature=4,
|
||||
init='glorot_uniform', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, **kwargs):
|
||||
self.output_dim = output_dim
|
||||
self.nb_feature = nb_feature
|
||||
self.init = initializations.get(init)
|
||||
@@ -749,6 +754,7 @@ class MaxoutDense(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.initial_weights = weights
|
||||
self.input_spec = [InputSpec(ndim=2)]
|
||||
|
||||
@@ -764,17 +770,19 @@ class MaxoutDense(Layer):
|
||||
|
||||
self.W = self.init((self.nb_feature, input_dim, self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.nb_feature, self.output_dim),
|
||||
name='{}_b'.format(self.name))
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_feature, self.output_dim),
|
||||
name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -785,7 +793,7 @@ class MaxoutDense(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -798,7 +806,10 @@ class MaxoutDense(Layer):
|
||||
|
||||
def call(self, x, mask=None):
|
||||
# no activation, this layer is only linear.
|
||||
output = K.max(K.dot(x, self.W) + self.b, axis=1)
|
||||
output = K.dot(x, self.W)
|
||||
if self.bias:
|
||||
output += self.b
|
||||
output = K.max(output, axis=1)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
@@ -810,6 +821,7 @@ class MaxoutDense(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim}
|
||||
base_config = super(MaxoutDense, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
@@ -831,7 +843,7 @@ class Highway(Layer):
|
||||
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.
|
||||
weights: list of Numpy arrays to set as initial weights.
|
||||
The list should have 2 elements, of shape `(input_dim, output_dim)`
|
||||
and (output_dim,) for weights and biases respectively.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
@@ -844,6 +856,7 @@ class Highway(Layer):
|
||||
(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: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
@@ -860,7 +873,8 @@ class Highway(Layer):
|
||||
def __init__(self, init='glorot_uniform', transform_bias=-2,
|
||||
activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, **kwargs):
|
||||
self.init = initializations.get(init)
|
||||
self.transform_bias = transform_bias
|
||||
self.activation = activations.get(activation)
|
||||
@@ -872,6 +886,7 @@ class Highway(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.initial_weights = weights
|
||||
self.input_spec = [InputSpec(ndim=2)]
|
||||
|
||||
@@ -890,19 +905,21 @@ class Highway(Layer):
|
||||
self.W_carry = self.init((input_dim, input_dim),
|
||||
name='{}_W_carry'.format(self.name))
|
||||
|
||||
self.b = K.zeros((input_dim,), name='{}_b'.format(self.name))
|
||||
# initialize with a vector of values `transform_bias`
|
||||
self.b_carry = K.variable(np.ones((input_dim,)) * self.transform_bias,
|
||||
name='{}_b_carry'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W, self.b, self.W_carry, self.b_carry]
|
||||
if self.bias:
|
||||
self.b = K.zeros((input_dim,), name='{}_b'.format(self.name))
|
||||
# initialize with a vector of values `transform_bias`
|
||||
self.b_carry = K.variable(np.ones((input_dim,)) * self.transform_bias,
|
||||
name='{}_b_carry'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b, self.W_carry, self.b_carry]
|
||||
else:
|
||||
self.trainable_weights = [self.W, self.W_carry]
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -913,7 +930,7 @@ class Highway(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -921,8 +938,14 @@ class Highway(Layer):
|
||||
del self.initial_weights
|
||||
|
||||
def call(self, x, mask=None):
|
||||
transform_weight = activations.sigmoid(K.dot(x, self.W_carry) + self.b_carry)
|
||||
act = self.activation(K.dot(x, self.W) + self.b)
|
||||
y = K.dot(x, self.W_carry)
|
||||
if self.bias:
|
||||
y += self.b_carry
|
||||
transform_weight = activations.sigmoid(y)
|
||||
y = K.dot(x, self.W)
|
||||
if self.bias:
|
||||
y += self.b
|
||||
act = self.activation(y)
|
||||
act *= transform_weight
|
||||
output = act + (1 - transform_weight) * x
|
||||
return output
|
||||
@@ -936,6 +959,7 @@ class Highway(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim}
|
||||
base_config = super(Highway, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
@@ -952,8 +976,10 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape `(nb_sample, time_dimension, input_dim)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape `(nb_sample, time_dimension, output_dim)`.
|
||||
|
||||
# Arguments
|
||||
output_dim: int > 0.
|
||||
init: name of initialization function for the weights of the layer
|
||||
@@ -966,7 +992,7 @@ class TimeDistributedDense(Layer):
|
||||
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.
|
||||
weights: list of Numpy arrays to set as initial weights.
|
||||
The list should have 2 elements, of shape `(input_dim, output_dim)`
|
||||
and (output_dim,) for weights and biases respectively.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
@@ -979,16 +1005,19 @@ class TimeDistributedDense(Layer):
|
||||
(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: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
input_length: length of inputs sequences
|
||||
(integer, or None for variable-length sequences).
|
||||
'''
|
||||
|
||||
def __init__(self, output_dim,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None, **kwargs):
|
||||
bias=True, input_dim=None, input_length=None, **kwargs):
|
||||
warnings.warn('TimeDistributedDense is deprecated, '
|
||||
'please use TimeDistributed(Dense(...)) instead.')
|
||||
self.output_dim = output_dim
|
||||
@@ -1002,6 +1031,7 @@ class TimeDistributedDense(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.initial_weights = weights
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
self.supports_masking = True
|
||||
@@ -1019,17 +1049,17 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
self.W = self.init((input_dim, self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.output_dim,),
|
||||
name='{}_b'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.output_dim,),
|
||||
name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -1040,7 +1070,7 @@ class TimeDistributedDense(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -1070,7 +1100,9 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
# Squash samples and timesteps into a single axis
|
||||
x = K.reshape(x, (-1, input_shape[-1])) # (samples * timesteps, input_dim)
|
||||
y = K.dot(x, self.W) + self.b # (samples * timesteps, output_dim)
|
||||
y = K.dot(x, self.W) # (samples * timesteps, output_dim)
|
||||
if self.bias:
|
||||
y += self.b
|
||||
# We have to reshape Y to (samples, timesteps, output_dim)
|
||||
y = K.reshape(y, (-1, input_length, self.output_dim)) # (samples, timesteps, output_dim)
|
||||
y = self.activation(y)
|
||||
@@ -1085,6 +1117,7 @@ class TimeDistributedDense(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim,
|
||||
'input_length': self.input_length}
|
||||
base_config = super(TimeDistributedDense, self).get_config()
|
||||
|
||||
@@ -17,7 +17,7 @@ class Embedding(Layer):
|
||||
model = Sequential()
|
||||
model.add(Embedding(1000, 64, input_length=10))
|
||||
# the model will take as input an integer matrix of size (batch, input_length).
|
||||
# the largest integer (i.e. word index) in the input should be no larger than 1000 (vocabulary size).
|
||||
# the largest integer (i.e. word index) in the input should be no larger than 999 (vocabulary size).
|
||||
# now model.output_shape == (None, 10, 64), where None is the batch dimension.
|
||||
|
||||
input_array = np.random.randint(1000, size=(32, 10))
|
||||
@@ -28,14 +28,14 @@ class Embedding(Layer):
|
||||
```
|
||||
|
||||
# Arguments
|
||||
input_dim: int >= 0. Size of the vocabulary, ie.
|
||||
input_dim: int > 0. Size of the vocabulary, ie.
|
||||
1 + maximum integer index occurring in the input data.
|
||||
output_dim: int >= 0. Dimension of the dense embedding.
|
||||
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.
|
||||
weights: list of numpy arrays to set as initial weights.
|
||||
weights: list of Numpy arrays to set as initial weights.
|
||||
The list should have 1 element, of shape `(input_dim, output_dim)`.
|
||||
W_regularizer: instance of the [regularizers](../regularizers.md) module
|
||||
(eg. L1 or L2 regularization), applied to the embedding matrix.
|
||||
@@ -46,6 +46,8 @@ class Embedding(Layer):
|
||||
This is useful for [recurrent layers](recurrent.md) which may take
|
||||
variable length input. If this is `True` then all subsequent layers
|
||||
in the model need to support masking or an exception will be raised.
|
||||
If mask_zero is set to True, as a consequence, index 0 cannot be
|
||||
used in the vocabulary (input_dim should equal |vocabulary| + 2).
|
||||
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
|
||||
|
||||
@@ -0,0 +1,421 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import activations, initializations, regularizers, constraints
|
||||
from keras.engine import Layer, InputSpec
|
||||
from ..utils.np_utils import conv_output_length
|
||||
|
||||
|
||||
class LocallyConnected1D(Layer):
|
||||
'''LocallyConnected1D layer works almost the same as Convolution1D layer,
|
||||
except that weights are unshared, that is, a different set of filters is
|
||||
applied at each different patch of the input. 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`
|
||||
(tuple of integers, e.g. (10, 128) for sequences of 10 vectors of
|
||||
128-dimensional vectors). Also, you will need to fix shape of the previous
|
||||
layer, since the weights can only be defined with determined output shape.
|
||||
|
||||
# Example
|
||||
```python
|
||||
# apply a unshared weight convolution 1d of length 3 to a sequence with
|
||||
# 10 timesteps, with 64 output filters
|
||||
model = Sequential()
|
||||
model.add(LocallyConnected1D(64, 3, input_shape=(10, 32)))
|
||||
# now model.output_shape == (None, 8, 64)
|
||||
# add a new conv1d on top
|
||||
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.
|
||||
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: Only support 'valid'. Please make good use of
|
||||
ZeroPadding1D to achieve same output length.
|
||||
subsample_length: factor by which to subsample output.
|
||||
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,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, input_length=None, **kwargs):
|
||||
if border_mode != 'valid':
|
||||
raise Exception('Invalid border mode for Convolution2D '
|
||||
'(only "valid" is supported):', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
self.filter_length = filter_length
|
||||
self.init = initializations.get(init, dim_ordering='th')
|
||||
self.activation = activations.get(activation)
|
||||
|
||||
self.border_mode = border_mode
|
||||
self.subsample_length = subsample_length
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
self.initial_weights = weights
|
||||
self.input_dim = input_dim
|
||||
self.input_length = input_length
|
||||
if self.input_dim:
|
||||
kwargs['input_shape'] = (self.input_length, self.input_dim)
|
||||
super(LocallyConnected1D, self).__init__(**kwargs)
|
||||
|
||||
def build(self, input_shape):
|
||||
input_dim = input_shape[2]
|
||||
_, output_length, nb_filter = self.get_output_shape_for(input_shape)
|
||||
|
||||
self.W_shape = (output_length, self.filter_length * input_dim, nb_filter)
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
if self.bias:
|
||||
self.b = K.zeros((output_length, self.nb_filter), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
length = conv_output_length(input_shape[1],
|
||||
self.filter_length,
|
||||
self.border_mode,
|
||||
self.subsample_length)
|
||||
return (input_shape[0], length, self.nb_filter)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
stride = self.subsample_length
|
||||
output_length, feature_dim, nb_filter = self.W_shape
|
||||
|
||||
xs = []
|
||||
for i in range(output_length):
|
||||
slice_length = slice(i * stride, i * stride + self.filter_length)
|
||||
xs.append(K.reshape(x[:, slice_length, :], (1, -1, feature_dim)))
|
||||
x_aggregate = K.concatenate(xs, axis=0)
|
||||
# (output_length, batch_size, nb_filter)
|
||||
output = K.batch_dot(x_aggregate, self.W)
|
||||
output = K.permute_dimensions(output, (1, 0, 2))
|
||||
|
||||
if self.bias:
|
||||
output += K.reshape(self.b, (1, output_length, nb_filter))
|
||||
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {'nb_filter': self.nb_filter,
|
||||
'filter_length': self.filter_length,
|
||||
'init': self.init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'border_mode': self.border_mode,
|
||||
'subsample_length': self.subsample_length,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim,
|
||||
'input_length': self.input_length}
|
||||
base_config = super(LocallyConnected1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class LocallyConnected2D(Layer):
|
||||
'''LocallyConnected2D layer works almost the same as Convolution2D layer,
|
||||
except that weights are unshared, that is, a different set of filters is
|
||||
applied at each different patch of the input. When using this layer as the
|
||||
first layer in a model, provide the keyword argument `input_shape` (tuple
|
||||
of integers, does not include the sample axis), e.g.
|
||||
`input_shape=(3, 128, 128)` for 128x128 RGB pictures. Also, you will need
|
||||
to fix shape of the previous layer, since the weights can only be defined
|
||||
with determined output shape.
|
||||
|
||||
# Examples
|
||||
```python
|
||||
# apply a 3x3 unshared weights convolution with 64 output filters on a 32x32 image:
|
||||
model = Sequential()
|
||||
model.add(LocallyConnected2D(64, 3, 3, input_shape=(3, 32, 32)))
|
||||
# now model.output_shape == (None, 64, 30, 30)
|
||||
# notice that this layer will consume (30*30)*(3*3*3*64) + (30*30)*64 parameters
|
||||
|
||||
# add a 3x3 unshared weights convolution on top, with 32 output filters:
|
||||
model.add(LocallyConnected2D(32, 3, 3))
|
||||
# now model.output_shape == (None, 32, 28, 28)
|
||||
```
|
||||
|
||||
# Arguments
|
||||
nb_filter: Number of convolution filters to use.
|
||||
nb_row: Number of rows in the convolution kernel.
|
||||
nb_col: Number of columns in the convolution kernel.
|
||||
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: Only support 'valid'. Please make good use of
|
||||
ZeroPadding2D to achieve same output shape.
|
||||
subsample: tuple of length 2. Factor by which to subsample output.
|
||||
Also called strides 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.
|
||||
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.
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
|
||||
# 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
|
||||
4D tensor with shape:
|
||||
`(samples, nb_filter, new_rows, new_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, new_rows, new_cols, nb_filter)` if dim_ordering='tf'.
|
||||
`rows` and `cols` values might have changed due to padding.
|
||||
'''
|
||||
def __init__(self, nb_filter, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
dim_ordering=K.image_dim_ordering(),
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
if border_mode != 'valid':
|
||||
raise Exception('Invalid border mode for Convolution2D '
|
||||
'(only "valid" is supported):', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
self.nb_row = nb_row
|
||||
self.nb_col = nb_col
|
||||
self.init = initializations.get(init, dim_ordering=dim_ordering)
|
||||
self.activation = activations.get(activation)
|
||||
|
||||
self.border_mode = border_mode
|
||||
self.subsample = tuple(subsample)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.input_spec = [InputSpec(ndim=4)]
|
||||
self.initial_weights = weights
|
||||
super(LocallyConnected2D, self).__init__(**kwargs)
|
||||
|
||||
def build(self, input_shape):
|
||||
output_shape = self.get_output_shape_for(input_shape)
|
||||
if self.dim_ordering == 'th':
|
||||
_, nb_filter, output_row, output_col = output_shape
|
||||
input_filter = input_shape[1]
|
||||
elif self.dim_ordering == 'tf':
|
||||
_, output_row, output_col, nb_filter = output_shape
|
||||
input_filter = input_shape[3]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
self.output_row = output_row
|
||||
self.output_col = output_col
|
||||
self.W_shape = (output_row * output_col, self.nb_row * self.nb_col * input_filter, nb_filter)
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
|
||||
if self.bias:
|
||||
self.b = K.zeros((output_row, output_col, nb_filter), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
rows = input_shape[2]
|
||||
cols = input_shape[3]
|
||||
elif self.dim_ordering == 'tf':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
rows = conv_output_length(rows, self.nb_row,
|
||||
self.border_mode, self.subsample[0])
|
||||
cols = conv_output_length(cols, self.nb_col,
|
||||
self.border_mode, self.subsample[1])
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0], self.nb_filter, rows, cols)
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0], rows, cols, self.nb_filter)
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
stride_row, stride_col = self.subsample
|
||||
_, feature_dim, nb_filter = self.W_shape
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
if K._backend == 'theano':
|
||||
output = []
|
||||
for i in range(self.output_row):
|
||||
for j in range(self.output_col):
|
||||
slice_row = slice(i * stride_row,
|
||||
i * stride_row + self.nb_row)
|
||||
slice_col = slice(j * stride_col,
|
||||
j * stride_col + self.nb_col)
|
||||
x_flatten = K.reshape(x[:, :, slice_row, slice_col], (1, -1, feature_dim))
|
||||
output.append(K.dot(x_flatten, self.W[i * self.output_col + j, :, :]))
|
||||
output = K.concatenate(output, axis=0)
|
||||
else:
|
||||
xs = []
|
||||
for i in range(self.output_row):
|
||||
for j in range(self.output_col):
|
||||
slice_row = slice(i * stride_row,
|
||||
i * stride_row + self.nb_row)
|
||||
slice_col = slice(j * stride_col,
|
||||
j * stride_col + self.nb_col)
|
||||
xs.append(K.reshape(x[:, :, slice_row, slice_col], (1, -1, feature_dim)))
|
||||
x_aggregate = K.concatenate(xs, axis=0)
|
||||
output = K.batch_dot(x_aggregate, self.W)
|
||||
output = K.reshape(output, (self.output_row, self.output_col, -1, nb_filter))
|
||||
output = K.permute_dimensions(output, (2, 3, 0, 1))
|
||||
elif self.dim_ordering == 'tf':
|
||||
xs = []
|
||||
for i in range(self.output_row):
|
||||
for j in range(self.output_col):
|
||||
slice_row = slice(i * stride_row,
|
||||
i * stride_row + self.nb_row)
|
||||
slice_col = slice(j * stride_col,
|
||||
j * stride_col + self.nb_col)
|
||||
xs.append(K.reshape(x[:, slice_row, slice_col, :], (1, -1, feature_dim)))
|
||||
x_aggregate = K.concatenate(xs, axis=0)
|
||||
output = K.batch_dot(x_aggregate, self.W)
|
||||
output = K.reshape(output, (self.output_row, self.output_col, -1, nb_filter))
|
||||
output = K.permute_dimensions(output, (2, 0, 1, 3))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
if self.bias:
|
||||
if self.dim_ordering == 'th':
|
||||
output += K.reshape(self.b, (1, nb_filter, self.output_row, self.output_col))
|
||||
elif self.dim_ordering == 'tf':
|
||||
output += K.reshape(self.b, (1, self.output_row, self.output_col, nb_filter))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {'nb_filter': self.nb_filter,
|
||||
'nb_row': self.nb_row,
|
||||
'nb_col': self.nb_col,
|
||||
'init': self.init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'border_mode': self.border_mode,
|
||||
'subsample': self.subsample,
|
||||
'dim_ordering': self.dim_ordering,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias}
|
||||
base_config = super(LocallyConnected2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
@@ -4,7 +4,7 @@ from .. import backend as K
|
||||
|
||||
|
||||
class GaussianNoise(Layer):
|
||||
'''Apply to the input an additive zero-centred gaussian noise with
|
||||
'''Apply to the input an additive zero-centered Gaussian noise with
|
||||
standard deviation `sigma`. This is useful to mitigate overfitting
|
||||
(you could see it as a kind of random data augmentation).
|
||||
Gaussian Noise (GS) is a natural choice as corruption process
|
||||
@@ -42,7 +42,7 @@ class GaussianNoise(Layer):
|
||||
|
||||
|
||||
class GaussianDropout(Layer):
|
||||
'''Apply to the input an multiplicative one-centred gaussian noise
|
||||
'''Apply to the input an multiplicative one-centered Gaussian noise
|
||||
with standard deviation `sqrt(p/(1-p))`.
|
||||
|
||||
As it is a regularization layer, it is only active at training time.
|
||||
|
||||
@@ -10,7 +10,7 @@ class BatchNormalization(Layer):
|
||||
|
||||
# Arguments
|
||||
epsilon: small float > 0. Fuzz parameter.
|
||||
mode: integer, 0 or 1.
|
||||
mode: integer, 0, 1 or 2.
|
||||
- 0: feature-wise normalization.
|
||||
Each feature map in the input will
|
||||
be normalized separately. The axis on which
|
||||
@@ -19,7 +19,13 @@ class BatchNormalization(Layer):
|
||||
using Theano conventions (samples, channels, rows, cols)
|
||||
then you should set `axis` to `1` to normalize along
|
||||
the channels axis.
|
||||
During training we use per-batch statistics to normalize
|
||||
the data, and during testing we use running averages
|
||||
computed during the training phase.
|
||||
- 1: sample-wise normalization. This mode assumes a 2D input.
|
||||
- 2: feature-wise normalization, like mode 0, but
|
||||
using per-batch statistics to normalize the data during both
|
||||
testing and training.
|
||||
axis: integer, axis along which to normalize in mode 0. For instance,
|
||||
if your input tensor has shape (samples, channels, rows, cols),
|
||||
set axis to 1 to normalize per feature map (channels axis).
|
||||
@@ -27,7 +33,7 @@ class BatchNormalization(Layer):
|
||||
exponential average of the mean and standard deviation
|
||||
of the data, for feature-wise normalization.
|
||||
weights: Initialization weights.
|
||||
List of 2 numpy arrays, with shapes:
|
||||
List of 2 Numpy arrays, with shapes:
|
||||
`[(input_shape,), (input_shape,)]`
|
||||
beta_init: name of initialization function for shift parameter
|
||||
(see [initializations](../initializations.md)), or alternatively,
|
||||
@@ -47,10 +53,11 @@ class BatchNormalization(Layer):
|
||||
Same shape as input.
|
||||
|
||||
# References
|
||||
- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](http://arxiv.org/pdf/1502.03167v3.pdf)
|
||||
- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](http://jmlr.org/proceedings/papers/v37/ioffe15.html)
|
||||
'''
|
||||
def __init__(self, epsilon=1e-6, mode=0, axis=-1, momentum=0.9,
|
||||
weights=None, beta_init='zero', gamma_init='one', **kwargs):
|
||||
self.supports_masking = True
|
||||
self.beta_init = initializations.get(beta_init)
|
||||
self.gamma_init = initializations.get(gamma_init)
|
||||
self.epsilon = epsilon
|
||||
@@ -58,7 +65,8 @@ class BatchNormalization(Layer):
|
||||
self.axis = axis
|
||||
self.momentum = momentum
|
||||
self.initial_weights = weights
|
||||
self.uses_learning_phase = True
|
||||
if self.mode == 0:
|
||||
self.uses_learning_phase = True
|
||||
super(BatchNormalization, self).__init__(**kwargs)
|
||||
|
||||
def build(self, input_shape):
|
||||
@@ -78,9 +86,12 @@ class BatchNormalization(Layer):
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
self.built = True
|
||||
self.called_with = None
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if self.mode == 0:
|
||||
if self.mode == 0 or self.mode == 2:
|
||||
assert self.built, 'Layer must be built before being called'
|
||||
input_shape = self.input_spec[0].shape
|
||||
|
||||
reduction_axes = list(range(len(input_shape)))
|
||||
@@ -88,34 +99,64 @@ class BatchNormalization(Layer):
|
||||
broadcast_shape = [1] * len(input_shape)
|
||||
broadcast_shape[self.axis] = input_shape[self.axis]
|
||||
|
||||
# case: train mode (uses stats of the current batch)
|
||||
mean = K.mean(x, axis=reduction_axes)
|
||||
brodcast_mean = K.reshape(mean, broadcast_shape)
|
||||
std = K.mean(K.square(x - brodcast_mean) + self.epsilon, axis=reduction_axes)
|
||||
std = K.sqrt(std)
|
||||
brodcast_std = K.reshape(std, broadcast_shape)
|
||||
mean_update = self.momentum * self.running_mean + (1-self.momentum) * mean
|
||||
std_update = self.momentum * self.running_std + (1-self.momentum) * std
|
||||
self.updates = [(self.running_mean, mean_update),
|
||||
(self.running_std, std_update)]
|
||||
x_normed = (x - brodcast_mean) / (brodcast_std + self.epsilon)
|
||||
# # case: train mode (uses stats of the current batch)
|
||||
# mean = K.mean(x, axis=reduction_axes)
|
||||
# brodcast_mean = K.reshape(mean, broadcast_shape)
|
||||
# std = K.mean(K.square(x - brodcast_mean) + self.epsilon, axis=reduction_axes)
|
||||
# std = K.sqrt(std)
|
||||
# brodcast_std = K.reshape(std, broadcast_shape)
|
||||
|
||||
# case: test mode (uses running averages)
|
||||
brodcast_running_mean = K.reshape(self.running_mean, broadcast_shape)
|
||||
brodcast_running_std = K.reshape(self.running_std, broadcast_shape)
|
||||
x_normed_running = ((x - brodcast_running_mean) / (brodcast_running_std + self.epsilon))
|
||||
if self.mode == 2:
|
||||
x_normed, mean, std = K.normalize_batch_in_training(x, self.gamma, self.beta, reduction_axes, epsilon=self.epsilon)
|
||||
mean_update = self.momentum * self.running_mean + (1 - self.momentum) * mean
|
||||
std_update = self.momentum * self.running_std + (1 - self.momentum) * std
|
||||
else:
|
||||
# mode 0
|
||||
if self.called_with not in {None, x}:
|
||||
raise Exception('You are attempting to share a '
|
||||
'same `BatchNormalization` layer across '
|
||||
'different data flows. '
|
||||
'This is not possible. '
|
||||
'You should use `mode=2` in '
|
||||
'`BatchNormalization`, which has '
|
||||
'a similar behavior but is shareable '
|
||||
'(see docs for a description of '
|
||||
'the behavior).')
|
||||
self.called_with = x
|
||||
x_normed, mean, std = K.normalize_batch_in_training(x, self.gamma, self.beta, reduction_axes, epsilon=self.epsilon)
|
||||
mean_update = self.momentum * self.running_mean + (1 - self.momentum) * mean
|
||||
std_update = self.momentum * self.running_std + (1 - self.momentum) * std
|
||||
self.updates = [(self.running_mean, mean_update),
|
||||
(self.running_std, std_update)]
|
||||
|
||||
# pick the normalized form of x corresponding to the training phase
|
||||
x_normed = K.in_train_phase(x_normed, x_normed_running)
|
||||
out = K.reshape(self.gamma, broadcast_shape) * x_normed + K.reshape(self.beta, broadcast_shape)
|
||||
if 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,
|
||||
epsilon=self.epsilon)
|
||||
else:
|
||||
# need broadcasting
|
||||
broadcast_running_mean = K.reshape(self.running_mean, broadcast_shape)
|
||||
broadcast_running_std = K.reshape(self.running_std, broadcast_shape)
|
||||
broadcast_beta = K.reshape(self.beta, broadcast_shape)
|
||||
broadcast_gamma = K.reshape(self.gamma, broadcast_shape)
|
||||
x_normed_running = K.batch_normalization(x, broadcast_running_mean,
|
||||
broadcast_running_std,
|
||||
broadcast_beta,
|
||||
broadcast_gamma,
|
||||
epsilon=self.epsilon)
|
||||
|
||||
# pick the normalized form of x corresponding to the training phase
|
||||
x_normed = K.in_train_phase(x_normed, x_normed_running)
|
||||
|
||||
elif self.mode == 1:
|
||||
# sample-wise normalization
|
||||
m = K.mean(x, axis=-1, keepdims=True)
|
||||
std = K.std(x, axis=-1, keepdims=True)
|
||||
std = K.sqrt(K.var(x, axis=-1, keepdims=True) + self.epsilon)
|
||||
x_normed = (x - m) / (std + self.epsilon)
|
||||
out = self.gamma * x_normed + self.beta
|
||||
return out
|
||||
x_normed = self.gamma * x_normed + self.beta
|
||||
return x_normed
|
||||
|
||||
def get_config(self):
|
||||
config = {"epsilon": self.epsilon,
|
||||
|
||||
@@ -0,0 +1,395 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
|
||||
from .. import backend as K
|
||||
from ..engine import Layer, InputSpec
|
||||
from ..utils.np_utils import conv_output_length
|
||||
|
||||
|
||||
class _Pooling1D(Layer):
|
||||
'''Abstract class for different pooling 1D layers.
|
||||
'''
|
||||
input_dim = 3
|
||||
|
||||
def __init__(self, pool_length=2, stride=None,
|
||||
border_mode='valid', **kwargs):
|
||||
super(_Pooling1D, self).__init__(**kwargs)
|
||||
if stride is None:
|
||||
stride = pool_length
|
||||
self.pool_length = pool_length
|
||||
self.stride = stride
|
||||
self.st = (self.stride, 1)
|
||||
self.pool_size = (pool_length, 1)
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
length = conv_output_length(input_shape[1], self.pool_length,
|
||||
self.border_mode, self.stride)
|
||||
return (input_shape[0], length, input_shape[2])
|
||||
|
||||
def _pooling_function(self, back_end, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
raise NotImplementedError
|
||||
|
||||
def call(self, x, mask=None):
|
||||
x = K.expand_dims(x, -1) # add dummy last dimension
|
||||
x = K.permute_dimensions(x, (0, 2, 1, 3))
|
||||
output = self._pooling_function(inputs=x, pool_size=self.pool_size,
|
||||
strides=self.st,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='th')
|
||||
output = K.permute_dimensions(output, (0, 2, 1, 3))
|
||||
return K.squeeze(output, 3) # remove dummy last dimension
|
||||
|
||||
def get_config(self):
|
||||
config = {'stride': self.stride,
|
||||
'pool_length': self.pool_length,
|
||||
'border_mode': self.border_mode}
|
||||
base_config = super(_Pooling1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class MaxPooling1D(_Pooling1D):
|
||||
'''Max pooling operation for temporal data.
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape: `(samples, downsampled_steps, features)`.
|
||||
|
||||
# Arguments
|
||||
pool_length: factor by which to downscale. 2 will halve the input.
|
||||
stride: integer, or None. Stride value.
|
||||
If None, it will default to `pool_length`.
|
||||
border_mode: 'valid' or 'same'.
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_length=2, stride=None,
|
||||
border_mode='valid', **kwargs):
|
||||
super(MaxPooling1D, self).__init__(pool_length, stride,
|
||||
border_mode, **kwargs)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
output = K.pool2d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='max')
|
||||
return output
|
||||
|
||||
|
||||
class AveragePooling1D(_Pooling1D):
|
||||
'''Average pooling for temporal data.
|
||||
|
||||
# Arguments
|
||||
pool_length: factor by which to downscale. 2 will halve the input.
|
||||
stride: integer, or None. Stride value.
|
||||
If None, it will default to `pool_length`.
|
||||
border_mode: 'valid' or 'same'.
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape: `(samples, downsampled_steps, features)`.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_length=2, stride=None,
|
||||
border_mode='valid', **kwargs):
|
||||
super(AveragePooling1D, self).__init__(pool_length, stride,
|
||||
border_mode, **kwargs)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
output = K.pool2d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='avg')
|
||||
return output
|
||||
|
||||
|
||||
class _Pooling2D(Layer):
|
||||
'''Abstract class for different pooling 2D layers.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(_Pooling2D, self).__init__(**kwargs)
|
||||
self.pool_size = tuple(pool_size)
|
||||
if strides is None:
|
||||
strides = self.pool_size
|
||||
self.strides = tuple(strides)
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
self.input_spec = [InputSpec(ndim=4)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
rows = input_shape[2]
|
||||
cols = input_shape[3]
|
||||
elif self.dim_ordering == 'tf':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
rows = conv_output_length(rows, self.pool_size[0],
|
||||
self.border_mode, self.strides[0])
|
||||
cols = conv_output_length(cols, self.pool_size[1],
|
||||
self.border_mode, self.strides[1])
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0], input_shape[1], rows, cols)
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0], rows, cols, input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
raise NotImplementedError
|
||||
|
||||
def call(self, x, mask=None):
|
||||
output = self._pooling_function(inputs=x, pool_size=self.pool_size,
|
||||
strides=self.strides,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {'pool_size': self.pool_size,
|
||||
'border_mode': self.border_mode,
|
||||
'strides': self.strides,
|
||||
'dim_ordering': self.dim_ordering}
|
||||
base_config = super(_Pooling2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class MaxPooling2D(_Pooling2D):
|
||||
'''Max pooling operation for spatial data.
|
||||
|
||||
# Arguments
|
||||
pool_size: tuple of 2 integers,
|
||||
factors by which to downscale (vertical, horizontal).
|
||||
(2, 2) will halve the image in each dimension.
|
||||
strides: tuple of 2 integers, or None. Strides values.
|
||||
If None, it will default to `pool_size`.
|
||||
border_mode: 'valid' or 'same'.
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
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
|
||||
4D tensor with shape:
|
||||
`(nb_samples, channels, pooled_rows, pooled_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, pooled_rows, pooled_cols, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(MaxPooling2D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
output = K.pool2d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='max')
|
||||
return output
|
||||
|
||||
|
||||
class AveragePooling2D(_Pooling2D):
|
||||
'''Average pooling operation for spatial data.
|
||||
|
||||
# Arguments
|
||||
pool_size: tuple of 2 integers,
|
||||
factors by which to downscale (vertical, horizontal).
|
||||
(2, 2) will halve the image in each dimension.
|
||||
strides: tuple of 2 integers, or None. Strides values.
|
||||
If None, it will default to `pool_size`.
|
||||
border_mode: 'valid' or 'same'.
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
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
|
||||
4D tensor with shape:
|
||||
`(nb_samples, channels, pooled_rows, pooled_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, pooled_rows, pooled_cols, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(AveragePooling2D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
output = K.pool2d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='avg')
|
||||
return output
|
||||
|
||||
|
||||
class _Pooling3D(Layer):
|
||||
'''Abstract class for different pooling 3D layers.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(_Pooling3D, self).__init__(**kwargs)
|
||||
self.pool_size = tuple(pool_size)
|
||||
if strides is None:
|
||||
strides = self.pool_size
|
||||
self.strides = tuple(strides)
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
self.input_spec = [InputSpec(ndim=5)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
len_dim1 = input_shape[2]
|
||||
len_dim2 = input_shape[3]
|
||||
len_dim3 = input_shape[4]
|
||||
elif self.dim_ordering == 'tf':
|
||||
len_dim1 = input_shape[1]
|
||||
len_dim2 = input_shape[2]
|
||||
len_dim3 = input_shape[3]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
len_dim1 = conv_output_length(len_dim1, self.pool_size[0],
|
||||
self.border_mode, self.strides[0])
|
||||
len_dim2 = conv_output_length(len_dim2, self.pool_size[1],
|
||||
self.border_mode, self.strides[1])
|
||||
len_dim3 = conv_output_length(len_dim3, self.pool_size[2],
|
||||
self.border_mode, self.strides[2])
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0], input_shape[1], len_dim1, len_dim2, len_dim3)
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0], len_dim1, len_dim2, len_dim3, input_shape[4])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
raise NotImplementedError
|
||||
|
||||
def call(self, x, mask=None):
|
||||
output = self._pooling_function(inputs=x, pool_size=self.pool_size,
|
||||
strides=self.strides,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {'pool_size': self.pool_size,
|
||||
'border_mode': self.border_mode,
|
||||
'strides': self.strides,
|
||||
'dim_ordering': self.dim_ordering}
|
||||
base_config = super(_Pooling3D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class MaxPooling3D(_Pooling3D):
|
||||
'''Max pooling operation for 3D data (spatial or spatio-temporal).
|
||||
|
||||
# Arguments
|
||||
pool_size: tuple of 3 integers,
|
||||
factors by which to downscale (dim1, dim2, dim3).
|
||||
(2, 2, 2) will halve the size of the 3D input in each dimension.
|
||||
strides: tuple of 3 integers, or None. Strides values.
|
||||
border_mode: 'valid' or 'same'.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 4.
|
||||
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
|
||||
5D tensor with shape:
|
||||
`(samples, channels, len_pool_dim1, len_pool_dim2, len_pool_dim3)` if dim_ordering='th'
|
||||
or 5D tensor with shape:
|
||||
`(samples, len_pool_dim1, len_pool_dim2, len_pool_dim3, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
5D tensor with shape:
|
||||
`(nb_samples, channels, pooled_dim1, pooled_dim2, pooled_dim3)` if dim_ordering='th'
|
||||
or 5D tensor with shape:
|
||||
`(samples, pooled_dim1, pooled_dim2, pooled_dim3, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(MaxPooling3D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
output = K.pool3d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='max')
|
||||
return output
|
||||
|
||||
|
||||
class AveragePooling3D(_Pooling3D):
|
||||
'''Average pooling operation for 3D data (spatial or spatio-temporal).
|
||||
|
||||
# Arguments
|
||||
pool_size: tuple of 3 integers,
|
||||
factors by which to downscale (dim1, dim2, dim3).
|
||||
(2, 2, 2) will halve the size of the 3D input in each dimension.
|
||||
strides: tuple of 3 integers, or None. Strides values.
|
||||
border_mode: 'valid' or 'same'.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 4.
|
||||
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
|
||||
5D tensor with shape:
|
||||
`(samples, channels, len_pool_dim1, len_pool_dim2, len_pool_dim3)` if dim_ordering='th'
|
||||
or 5D tensor with shape:
|
||||
`(samples, len_pool_dim1, len_pool_dim2, len_pool_dim3, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
5D tensor with shape:
|
||||
`(nb_samples, channels, pooled_dim1, pooled_dim2, pooled_dim3)` if dim_ordering='th'
|
||||
or 5D tensor with shape:
|
||||
`(samples, pooled_dim1, pooled_dim2, pooled_dim3, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(AveragePooling3D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
def _pooling_function(self, inputs, pool_size, strides,
|
||||
border_mode, dim_ordering):
|
||||
output = K.pool3d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='avg')
|
||||
return output
|
||||
+201
-142
@@ -54,7 +54,7 @@ class Recurrent(Layer):
|
||||
# as the first layer in a Sequential model
|
||||
model = Sequential()
|
||||
model.add(LSTM(32, input_shape=(10, 64)))
|
||||
# now model.output_shape == (None, 10, 32)
|
||||
# now model.output_shape == (None, 32)
|
||||
# note: `None` is the batch dimension.
|
||||
|
||||
# the following is identical:
|
||||
@@ -66,7 +66,7 @@ class Recurrent(Layer):
|
||||
```
|
||||
|
||||
# Arguments
|
||||
weights: list of numpy arrays to set as initial weights.
|
||||
weights: list of Numpy arrays to set as initial weights.
|
||||
The list should have 3 elements, of shapes:
|
||||
`[(input_dim, output_dim), (output_dim, output_dim), (output_dim,)]`.
|
||||
return_sequences: Boolean. Whether to return the last output
|
||||
@@ -81,12 +81,18 @@ class Recurrent(Layer):
|
||||
is always unrolled, so this argument does not do anything.
|
||||
Unrolling can speed-up a RNN, although it tends to be more memory-intensive.
|
||||
Unrolling is only suitable for short sequences.
|
||||
consume_less: one of "cpu", "mem". If set to "cpu", the RNN will use
|
||||
consume_less: one of "cpu", "mem", or "gpu" (LSTM/GRU only).
|
||||
If set to "cpu", the RNN will use
|
||||
an implementation that uses fewer, larger matrix products,
|
||||
thus running faster (at least on CPU) but consuming more memory.
|
||||
thus running faster on CPU but consuming more memory.
|
||||
If set to "mem", the RNN will use more matrix products,
|
||||
but smaller ones, thus running slower (may actually be faster on GPU)
|
||||
while consuming less memory.
|
||||
If set to "gpu" (LSTM/GRU only), the RNN will combine the input gate,
|
||||
the forget gate and the output gate into a single matrix,
|
||||
enabling more time-efficient parallelization on the GPU. Note: RNN
|
||||
dropout must be shared for all gates, resulting in a slightly
|
||||
reduced regularization.
|
||||
input_dim: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
@@ -184,9 +190,9 @@ class Recurrent(Layer):
|
||||
def get_initial_states(self, x):
|
||||
# build an all-zero tensor of shape (samples, output_dim)
|
||||
initial_state = K.zeros_like(x) # (samples, timesteps, input_dim)
|
||||
initial_state = K.sum(initial_state, axis=1) # (samples, input_dim)
|
||||
reducer = K.zeros((self.input_dim, self.output_dim))
|
||||
initial_state = K.dot(initial_state, reducer) # (samples, output_dim)
|
||||
initial_state = K.sum(initial_state, axis=(1, 2)) # (samples,)
|
||||
initial_state = K.expand_dims(initial_state) # (samples, 1)
|
||||
initial_state = K.tile(initial_state, [1, self.output_dim]) # (samples, output_dim)
|
||||
initial_states = [initial_state for _ in range(len(self.states))]
|
||||
return initial_states
|
||||
|
||||
@@ -383,15 +389,15 @@ class SimpleRNN(Recurrent):
|
||||
return constants
|
||||
|
||||
def get_config(self):
|
||||
config = {"output_dim": self.output_dim,
|
||||
"init": self.init.__name__,
|
||||
"inner_init": self.inner_init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"dropout_W": self.dropout_W,
|
||||
"dropout_U": self.dropout_U}
|
||||
config = {'output_dim': self.output_dim,
|
||||
'init': self.init.__name__,
|
||||
'inner_init': self.inner_init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'U_regularizer': self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'dropout_W': self.dropout_W,
|
||||
'dropout_U': self.dropout_U}
|
||||
base_config = super(SimpleRNN, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -444,53 +450,66 @@ class GRU(Recurrent):
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
input_dim = input_shape[2]
|
||||
self.input_dim = input_dim
|
||||
self.input_dim = input_shape[2]
|
||||
|
||||
self.W_z = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_z'.format(self.name))
|
||||
self.U_z = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_z'.format(self.name))
|
||||
self.b_z = K.zeros((self.output_dim,), name='{}_b_z'.format(self.name))
|
||||
|
||||
self.W_r = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_r'.format(self.name))
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_r'.format(self.name))
|
||||
self.b_r = K.zeros((self.output_dim,), name='{}_b_r'.format(self.name))
|
||||
|
||||
self.W_h = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_h'.format(self.name))
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_h'.format(self.name))
|
||||
self.b_h = K.zeros((self.output_dim,), name='{}_b_h'.format(self.name))
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(K.concatenate([self.W_z,
|
||||
self.W_r,
|
||||
self.W_h]))
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.U_regularizer:
|
||||
self.U_regularizer.set_param(K.concatenate([self.U_z,
|
||||
self.U_r,
|
||||
self.U_h]))
|
||||
self.regularizers.append(self.U_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(K.concatenate([self.b_z,
|
||||
self.b_r,
|
||||
self.b_h]))
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.trainable_weights = [self.W_z, self.U_z, self.b_z,
|
||||
self.W_r, self.U_r, self.b_r,
|
||||
self.W_h, self.U_h, self.b_h]
|
||||
if self.stateful:
|
||||
self.reset_states()
|
||||
else:
|
||||
# initial states: all-zero tensor of shape (output_dim)
|
||||
self.states = [None]
|
||||
|
||||
if self.consume_less == 'gpu':
|
||||
|
||||
self.W = self.init((self.input_dim, 3 * self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.U = self.inner_init((self.output_dim, 3 * self.output_dim),
|
||||
name='{}_U'.format(self.name))
|
||||
|
||||
self.b = K.variable(np.hstack((np.zeros(self.output_dim),
|
||||
np.zeros(self.output_dim),
|
||||
np.zeros(self.output_dim))),
|
||||
name='{}_b'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W, self.U, self.b]
|
||||
else:
|
||||
|
||||
self.W_z = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_z'.format(self.name))
|
||||
self.U_z = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_z'.format(self.name))
|
||||
self.b_z = K.zeros((self.output_dim,), name='{}_b_z'.format(self.name))
|
||||
|
||||
self.W_r = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_r'.format(self.name))
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_r'.format(self.name))
|
||||
self.b_r = K.zeros((self.output_dim,), name='{}_b_r'.format(self.name))
|
||||
|
||||
self.W_h = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_h'.format(self.name))
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_h'.format(self.name))
|
||||
self.b_h = K.zeros((self.output_dim,), name='{}_b_h'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W_z, self.U_z, self.b_z,
|
||||
self.W_r, self.U_r, self.b_r,
|
||||
self.W_h, self.U_h, self.b_h]
|
||||
|
||||
self.W = K.concatenate([self.W_z, self.W_r, self.W_h])
|
||||
self.U = K.concatenate([self.U_z, self.U_r, self.U_h])
|
||||
self.b = K.concatenate([self.b_z, self.b_r, self.b_h])
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.U_regularizer:
|
||||
self.U_regularizer.set_param(self.U)
|
||||
self.regularizers.append(self.U_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
@@ -528,19 +547,37 @@ class GRU(Recurrent):
|
||||
B_U = states[1] # dropout matrices for recurrent units
|
||||
B_W = states[2]
|
||||
|
||||
if self.consume_less == 'cpu':
|
||||
x_z = x[:, :self.output_dim]
|
||||
x_r = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_h = x[:, 2 * self.output_dim:]
|
||||
if self.consume_less == 'gpu':
|
||||
|
||||
matrix_x = K.dot(x * B_W[0], self.W) + self.b
|
||||
matrix_inner = K.dot(h_tm1 * B_U[0], self.U[:, :2 * self.output_dim])
|
||||
|
||||
x_z = matrix_x[:, :self.output_dim]
|
||||
x_r = matrix_x[:, self.output_dim: 2 * self.output_dim]
|
||||
inner_z = matrix_inner[:, :self.output_dim]
|
||||
inner_r = matrix_inner[:, self.output_dim: 2 * self.output_dim]
|
||||
|
||||
z = self.inner_activation(x_z + inner_z)
|
||||
r = self.inner_activation(x_r + inner_r)
|
||||
|
||||
x_h = matrix_x[:, 2 * self.output_dim:]
|
||||
inner_h = K.dot(r * h_tm1 * B_U[0], self.U[:, 2 * self.output_dim:])
|
||||
hh = self.activation(x_h + inner_h)
|
||||
else:
|
||||
x_z = K.dot(x * B_W[0], self.W_z) + self.b_z
|
||||
x_r = K.dot(x * B_W[1], self.W_r) + self.b_r
|
||||
x_h = K.dot(x * B_W[2], self.W_h) + self.b_h
|
||||
if self.consume_less == 'cpu':
|
||||
x_z = x[:, :self.output_dim]
|
||||
x_r = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_h = x[:, 2 * self.output_dim:]
|
||||
elif self.consume_less == 'mem':
|
||||
x_z = K.dot(x * B_W[0], self.W_z) + self.b_z
|
||||
x_r = K.dot(x * B_W[1], self.W_r) + self.b_r
|
||||
x_h = K.dot(x * B_W[2], self.W_h) + self.b_h
|
||||
else:
|
||||
raise Exception('Unknown `consume_less` mode.')
|
||||
z = self.inner_activation(x_z + K.dot(h_tm1 * B_U[0], self.U_z))
|
||||
r = self.inner_activation(x_r + K.dot(h_tm1 * B_U[1], self.U_r))
|
||||
|
||||
z = self.inner_activation(x_z + K.dot(h_tm1 * B_U[0], self.U_z))
|
||||
r = self.inner_activation(x_r + K.dot(h_tm1 * B_U[1], self.U_r))
|
||||
|
||||
hh = self.activation(x_h + K.dot(r * h_tm1 * B_U[2], self.U_h))
|
||||
hh = self.activation(x_h + K.dot(r * h_tm1 * B_U[2], self.U_h))
|
||||
h = z * h_tm1 + (1 - z) * hh
|
||||
return h, [h]
|
||||
|
||||
@@ -566,16 +603,16 @@ class GRU(Recurrent):
|
||||
return constants
|
||||
|
||||
def get_config(self):
|
||||
config = {"output_dim": self.output_dim,
|
||||
"init": self.init.__name__,
|
||||
"inner_init": self.inner_init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"inner_activation": self.inner_activation.__name__,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"dropout_W": self.dropout_W,
|
||||
"dropout_U": self.dropout_U}
|
||||
config = {'output_dim': self.output_dim,
|
||||
'init': self.init.__name__,
|
||||
'inner_init': self.inner_init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'inner_activation': self.inner_activation.__name__,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'U_regularizer': self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'dropout_W': self.dropout_W,
|
||||
'dropout_U': self.dropout_U}
|
||||
base_config = super(GRU, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -637,8 +674,7 @@ class LSTM(Recurrent):
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
input_dim = input_shape[2]
|
||||
self.input_dim = input_dim
|
||||
self.input_dim = input_shape[2]
|
||||
|
||||
if self.stateful:
|
||||
self.reset_states()
|
||||
@@ -646,56 +682,64 @@ class LSTM(Recurrent):
|
||||
# initial states: 2 all-zero tensors of shape (output_dim)
|
||||
self.states = [None, None]
|
||||
|
||||
self.W_i = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_i'.format(self.name))
|
||||
self.U_i = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_i'.format(self.name))
|
||||
self.b_i = K.zeros((self.output_dim,), name='{}_b_i'.format(self.name))
|
||||
if self.consume_less == 'gpu':
|
||||
self.W = self.init((self.input_dim, 4 * self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.U = self.inner_init((self.output_dim, 4 * self.output_dim),
|
||||
name='{}_U'.format(self.name))
|
||||
|
||||
self.W_f = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_f'.format(self.name))
|
||||
self.U_f = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_f'.format(self.name))
|
||||
self.b_f = self.forget_bias_init((self.output_dim,),
|
||||
name='{}_b_f'.format(self.name))
|
||||
self.b = K.variable(np.hstack((np.zeros(self.output_dim),
|
||||
K.get_value(self.forget_bias_init((self.output_dim,))),
|
||||
np.zeros(self.output_dim),
|
||||
np.zeros(self.output_dim))),
|
||||
name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.U, self.b]
|
||||
else:
|
||||
self.W_i = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_i'.format(self.name))
|
||||
self.U_i = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_i'.format(self.name))
|
||||
self.b_i = K.zeros((self.output_dim,), name='{}_b_i'.format(self.name))
|
||||
|
||||
self.W_c = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_c'.format(self.name))
|
||||
self.U_c = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_c'.format(self.name))
|
||||
self.b_c = K.zeros((self.output_dim,), name='{}_b_c'.format(self.name))
|
||||
self.W_f = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_f'.format(self.name))
|
||||
self.U_f = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_f'.format(self.name))
|
||||
self.b_f = self.forget_bias_init((self.output_dim,),
|
||||
name='{}_b_f'.format(self.name))
|
||||
|
||||
self.W_o = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_o'.format(self.name))
|
||||
self.U_o = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_o'.format(self.name))
|
||||
self.b_o = K.zeros((self.output_dim,), name='{}_b_o'.format(self.name))
|
||||
self.W_c = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_c'.format(self.name))
|
||||
self.U_c = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_c'.format(self.name))
|
||||
self.b_c = K.zeros((self.output_dim,), name='{}_b_c'.format(self.name))
|
||||
|
||||
self.W_o = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_o'.format(self.name))
|
||||
self.U_o = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_o'.format(self.name))
|
||||
self.b_o = K.zeros((self.output_dim,), name='{}_b_o'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W_i, self.U_i, self.b_i,
|
||||
self.W_c, self.U_c, self.b_c,
|
||||
self.W_f, self.U_f, self.b_f,
|
||||
self.W_o, self.U_o, self.b_o]
|
||||
|
||||
self.W = K.concatenate([self.W_i, self.W_f, self.W_c, self.W_o])
|
||||
self.U = K.concatenate([self.U_i, self.U_f, self.U_c, self.U_o])
|
||||
self.b = K.concatenate([self.b_i, self.b_f, self.b_c, self.b_o])
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(K.concatenate([self.W_i,
|
||||
self.W_f,
|
||||
self.W_c,
|
||||
self.W_o]))
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.U_regularizer:
|
||||
self.U_regularizer.set_param(K.concatenate([self.U_i,
|
||||
self.U_f,
|
||||
self.U_c,
|
||||
self.U_o]))
|
||||
self.U_regularizer.set_param(self.U)
|
||||
self.regularizers.append(self.U_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(K.concatenate([self.b_i,
|
||||
self.b_f,
|
||||
self.b_c,
|
||||
self.b_o]))
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.trainable_weights = [self.W_i, self.U_i, self.b_i,
|
||||
self.W_c, self.U_c, self.b_c,
|
||||
self.W_f, self.U_f, self.b_f,
|
||||
self.W_o, self.U_o, self.b_o]
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
@@ -743,21 +787,36 @@ class LSTM(Recurrent):
|
||||
B_U = states[2]
|
||||
B_W = states[3]
|
||||
|
||||
if self.consume_less == 'cpu':
|
||||
x_i = x[:, :self.output_dim]
|
||||
x_f = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_c = x[:, 2 * self.output_dim: 3 * self.output_dim]
|
||||
x_o = x[:, 3 * self.output_dim:]
|
||||
else:
|
||||
x_i = K.dot(x * B_W[0], self.W_i) + self.b_i
|
||||
x_f = K.dot(x * B_W[1], self.W_f) + self.b_f
|
||||
x_c = K.dot(x * B_W[2], self.W_c) + self.b_c
|
||||
x_o = K.dot(x * B_W[3], self.W_o) + self.b_o
|
||||
if self.consume_less == 'gpu':
|
||||
z = K.dot(x * B_W[0], self.W) + K.dot(h_tm1 * B_U[0], self.U) + self.b
|
||||
|
||||
i = self.inner_activation(x_i + K.dot(h_tm1 * B_U[0], self.U_i))
|
||||
f = self.inner_activation(x_f + K.dot(h_tm1 * B_U[1], self.U_f))
|
||||
c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * B_U[2], self.U_c))
|
||||
o = self.inner_activation(x_o + K.dot(h_tm1 * B_U[3], self.U_o))
|
||||
z0 = z[:, :self.output_dim]
|
||||
z1 = z[:, self.output_dim: 2 * self.output_dim]
|
||||
z2 = z[:, 2 * self.output_dim: 3 * self.output_dim]
|
||||
z3 = z[:, 3 * self.output_dim:]
|
||||
|
||||
i = self.inner_activation(z0)
|
||||
f = self.inner_activation(z1)
|
||||
c = f * c_tm1 + i * self.activation(z2)
|
||||
o = self.inner_activation(z3)
|
||||
else:
|
||||
if self.consume_less == 'cpu':
|
||||
x_i = x[:, :self.output_dim]
|
||||
x_f = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_c = x[:, 2 * self.output_dim: 3 * self.output_dim]
|
||||
x_o = x[:, 3 * self.output_dim:]
|
||||
elif self.consume_less == 'mem':
|
||||
x_i = K.dot(x * B_W[0], self.W_i) + self.b_i
|
||||
x_f = K.dot(x * B_W[1], self.W_f) + self.b_f
|
||||
x_c = K.dot(x * B_W[2], self.W_c) + self.b_c
|
||||
x_o = K.dot(x * B_W[3], self.W_o) + self.b_o
|
||||
else:
|
||||
raise Exception('Unknown `consume_less` mode.')
|
||||
|
||||
i = self.inner_activation(x_i + K.dot(h_tm1 * B_U[0], self.U_i))
|
||||
f = self.inner_activation(x_f + K.dot(h_tm1 * B_U[1], self.U_f))
|
||||
c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * B_U[2], self.U_c))
|
||||
o = self.inner_activation(x_o + K.dot(h_tm1 * B_U[3], self.U_o))
|
||||
|
||||
h = o * self.activation(c)
|
||||
return h, [h, c]
|
||||
@@ -784,16 +843,16 @@ class LSTM(Recurrent):
|
||||
return constants
|
||||
|
||||
def get_config(self):
|
||||
config = {"output_dim": self.output_dim,
|
||||
"init": self.init.__name__,
|
||||
"inner_init": self.inner_init.__name__,
|
||||
"forget_bias_init": self.forget_bias_init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"inner_activation": self.inner_activation.__name__,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"dropout_W": self.dropout_W,
|
||||
"dropout_U": self.dropout_U}
|
||||
config = {'output_dim': self.output_dim,
|
||||
'init': self.init.__name__,
|
||||
'inner_init': self.inner_init.__name__,
|
||||
'forget_bias_init': self.forget_bias_init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'inner_activation': self.inner_activation.__name__,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'U_regularizer': self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'dropout_W': self.dropout_W,
|
||||
'dropout_U': self.dropout_U}
|
||||
base_config = super(LSTM, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -384,7 +384,7 @@ class Graph(Model):
|
||||
|
||||
# Arguments
|
||||
data: dictionary mapping input names and outputs names to
|
||||
appropriate numpy arrays. All arrays should contain
|
||||
appropriate Numpy arrays. All arrays should contain
|
||||
the same number of samples.
|
||||
batch_size: int. Number of samples per gradient update.
|
||||
nb_epoch: int.
|
||||
@@ -395,7 +395,7 @@ class Graph(Model):
|
||||
validation_split: float (0. < x < 1). Fraction of the data to
|
||||
use as held-out validation data.
|
||||
validation_data: dictionary mapping input names and outputs names
|
||||
to appropriate numpy arrays to be used as
|
||||
to appropriate Numpy arrays to be used as
|
||||
held-out validation data.
|
||||
All arrays should contain the same number of samples.
|
||||
Will override validation_split.
|
||||
@@ -473,6 +473,8 @@ class Graph(Model):
|
||||
x = self._get_x(data)
|
||||
output_list = super(Graph, self).predict(x, batch_size=batch_size,
|
||||
verbose=verbose)
|
||||
if not isinstance(output_list, list):
|
||||
output_list = [output_list]
|
||||
return dict(zip(self._graph_outputs, output_list))
|
||||
|
||||
def train_on_batch(self, data,
|
||||
@@ -528,6 +530,8 @@ class Graph(Model):
|
||||
|
||||
def predict_on_batch(self, data):
|
||||
output_list = super(Graph, self).predict_on_batch(data)
|
||||
if not isinstance(output_list, list):
|
||||
output_list = [output_list]
|
||||
return dict(zip(self._graph_outputs, output_list))
|
||||
|
||||
def fit_generator(self, generator, samples_per_epoch, nb_epoch,
|
||||
@@ -556,7 +560,7 @@ class Graph(Model):
|
||||
verbose: verbosity mode, 0, 1, or 2.
|
||||
callbacks: list of callbacks to be called during training.
|
||||
validation_data: dictionary mapping input names and outputs names
|
||||
to appropriate numpy arrays to be used as
|
||||
to appropriate Numpy arrays to be used as
|
||||
held-out validation data, or a generator yielding such
|
||||
dictionaries. All arrays should contain the same number
|
||||
of samples. If a generator, will be called until more than
|
||||
@@ -578,7 +582,7 @@ class Graph(Model):
|
||||
while 1:
|
||||
f = open(path)
|
||||
for line in f:
|
||||
# create numpy arrays of input data
|
||||
# create Numpy arrays of input data
|
||||
# and labels, from each line in the file
|
||||
x1, x2, y = process_line(line)
|
||||
yield ({'input_1': x1, 'input_2': x2, 'output': y})
|
||||
|
||||
+88
-21
@@ -10,6 +10,9 @@ from .legacy.models import Graph
|
||||
|
||||
def model_from_config(config, custom_objects={}):
|
||||
from keras.utils.layer_utils import layer_from_config
|
||||
if isinstance(config, list):
|
||||
raise Exception('`model_fom_config` expects a dictionary, not a list. '
|
||||
'Maybe you meant to use `Sequential.from_config(config)`?')
|
||||
return layer_from_config(config, custom_objects=custom_objects)
|
||||
|
||||
|
||||
@@ -79,6 +82,7 @@ class Sequential(Model):
|
||||
self.inbound_nodes = []
|
||||
self.outbound_nodes = []
|
||||
self.built = False
|
||||
self._flattened_layers = None
|
||||
|
||||
if not name:
|
||||
prefix = 'sequential_'
|
||||
@@ -152,6 +156,23 @@ class Sequential(Model):
|
||||
|
||||
self.layers.append(layer)
|
||||
self.built = False
|
||||
self._flattened_layers = None
|
||||
|
||||
def pop(self):
|
||||
'''Removes the last layer in the model.
|
||||
'''
|
||||
if not self.layers:
|
||||
raise Exception('There are no layers in the model.')
|
||||
|
||||
self.layers.pop()
|
||||
if not self.layers:
|
||||
self.outputs = []
|
||||
self.inbound_nodes = []
|
||||
self.outbound_nodes = []
|
||||
else:
|
||||
self.layers[-1].outbound_nodes = []
|
||||
self.outputs = [self.layers[-1].output]
|
||||
self.built = False
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if not self.built:
|
||||
@@ -194,6 +215,8 @@ class Sequential(Model):
|
||||
|
||||
@property
|
||||
def flattened_layers(self):
|
||||
if self._flattened_layers is not None:
|
||||
return self._flattened_layers
|
||||
layers = []
|
||||
if self.layers[0].__class__.__name__ == 'Merge':
|
||||
merge = self.layers[0]
|
||||
@@ -215,6 +238,7 @@ class Sequential(Model):
|
||||
for layer in self.layers[1:]:
|
||||
if layer not in layers:
|
||||
layers.append(layer)
|
||||
self._flattened_layers = layers
|
||||
return layers
|
||||
|
||||
def _gather_list_attr(self, attr):
|
||||
@@ -452,12 +476,14 @@ class Sequential(Model):
|
||||
A Numpy array of predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
self.build()
|
||||
return self.model.predict(x, batch_size=batch_size, verbose=verbose)
|
||||
|
||||
def predict_on_batch(self, x):
|
||||
'''Returns predictions for a single batch of samples.
|
||||
'''
|
||||
if self.model is None:
|
||||
self.build()
|
||||
return self.model.predict_on_batch(x)
|
||||
|
||||
def train_on_batch(self, x, y, class_weight=None,
|
||||
@@ -478,6 +504,8 @@ class Sequential(Model):
|
||||
The attribute `model.metrics_names` will give you
|
||||
the display labels for the scalar outputs.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
if 'accuracy' in kwargs:
|
||||
kwargs.pop('accuracy')
|
||||
warnings.warn('The "accuracy" argument is deprecated, '
|
||||
@@ -508,6 +536,8 @@ class Sequential(Model):
|
||||
The attribute `model.metrics_names` will give you
|
||||
the display labels for the scalar outputs.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
if 'accuracy' in kwargs:
|
||||
kwargs.pop('accuracy')
|
||||
warnings.warn('The "accuracy" argument is deprecated, '
|
||||
@@ -534,8 +564,6 @@ class Sequential(Model):
|
||||
# Returns
|
||||
A Numpy array of probability predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
preds = self.predict(x, batch_size, verbose)
|
||||
if preds.min() < 0. or preds.max() > 1.:
|
||||
warnings.warn('Network returning invalid probability values. '
|
||||
@@ -557,8 +585,6 @@ class Sequential(Model):
|
||||
# Returns
|
||||
A numpy array of class predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
proba = self.predict(x, batch_size=batch_size, verbose=verbose)
|
||||
if proba.shape[-1] > 1:
|
||||
return proba.argmax(axis=-1)
|
||||
@@ -568,7 +594,7 @@ class Sequential(Model):
|
||||
def fit_generator(self, generator, samples_per_epoch, nb_epoch,
|
||||
verbose=1, callbacks=[],
|
||||
validation_data=None, nb_val_samples=None,
|
||||
class_weight=None, max_q_size=10, **kwargs):
|
||||
class_weight=None, max_q_size=10, nb_worker=1, pickle_safe=False, **kwargs):
|
||||
'''Fits the model on data generated batch-by-batch by
|
||||
a Python generator.
|
||||
The generator is run in parallel to the model, for efficiency.
|
||||
@@ -599,6 +625,11 @@ class Sequential(Model):
|
||||
class_weight: dictionary mapping class indices to a weight
|
||||
for the class.
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
# Returns
|
||||
A `History` object.
|
||||
@@ -610,7 +641,7 @@ class Sequential(Model):
|
||||
while 1:
|
||||
f = open(path)
|
||||
for line in f:
|
||||
# create numpy arrays of input data
|
||||
# create Numpy arrays of input data
|
||||
# and labels, from each line in the file
|
||||
x, y = process_line(line)
|
||||
yield (x, y)
|
||||
@@ -622,6 +653,9 @@ class Sequential(Model):
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
if nb_worker > 1 and not pickle_safe:
|
||||
warnings.warn('The "nb_worker" argument is deprecated when pickle_safe is False')
|
||||
nb_worker = 1 # For backward compatibility
|
||||
if 'show_accuracy' in kwargs:
|
||||
kwargs.pop('show_accuracy')
|
||||
warnings.warn('The "show_accuracy" argument is deprecated, '
|
||||
@@ -629,10 +663,6 @@ class Sequential(Model):
|
||||
'the model at compile time:\n'
|
||||
'`model.compile(optimizer, loss, '
|
||||
'metrics=["accuracy"])`')
|
||||
if 'nb_worker' in kwargs:
|
||||
kwargs.pop('nb_worker')
|
||||
warnings.warn('The "nb_worker" argument is deprecated, '
|
||||
'please remove it from your code.')
|
||||
if 'nb_val_worker' in kwargs:
|
||||
kwargs.pop('nb_val_worker')
|
||||
warnings.warn('The "nb_val_worker" argument is deprecated, '
|
||||
@@ -648,9 +678,11 @@ class Sequential(Model):
|
||||
validation_data=validation_data,
|
||||
nb_val_samples=nb_val_samples,
|
||||
class_weight=class_weight,
|
||||
max_q_size=max_q_size)
|
||||
max_q_size=max_q_size,
|
||||
nb_worker=nb_worker,
|
||||
pickle_safe=pickle_safe)
|
||||
|
||||
def evaluate_generator(self, generator, val_samples, max_q_size=10, **kwargs):
|
||||
def evaluate_generator(self, generator, val_samples, max_q_size=10, nb_worker=1, pickle_safe=False, **kwargs):
|
||||
'''Evaluates the model on a data generator. The generator should
|
||||
return the same kind of data as accepted by `test_on_batch`.
|
||||
|
||||
@@ -662,9 +694,17 @@ class Sequential(Model):
|
||||
total number of samples to generate from `generator`
|
||||
before returning.
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
if nb_worker > 1 and not pickle_safe:
|
||||
warnings.warn('The "nb_worker" argument is deprecated when pickle_safe is False')
|
||||
nb_worker = 1 # For backward compatibility
|
||||
if 'show_accuracy' in kwargs:
|
||||
kwargs.pop('show_accuracy')
|
||||
warnings.warn('The "show_accuracy" argument is deprecated, '
|
||||
@@ -680,9 +720,11 @@ class Sequential(Model):
|
||||
str(kwargs))
|
||||
return self.model.evaluate_generator(generator,
|
||||
val_samples,
|
||||
max_q_size=max_q_size)
|
||||
max_q_size=max_q_size,
|
||||
nb_worker=nb_worker,
|
||||
pickle_safe=pickle_safe)
|
||||
|
||||
def predict_generator(self, generator, val_samples, max_q_size=10):
|
||||
def predict_generator(self, generator, val_samples, max_q_size=10, nb_worker=1, pickle_safe=False):
|
||||
'''Generates predictions for the input samples from a data generator.
|
||||
The generator should return the same kind of data as accepted by
|
||||
`predict_on_batch`.
|
||||
@@ -692,18 +734,28 @@ class Sequential(Model):
|
||||
val_samples: total number of samples to generate from `generator`
|
||||
before returning.
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
# Returns
|
||||
A Numpy array of predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
self.build()
|
||||
if nb_worker > 1 and not pickle_safe:
|
||||
warnings.warn('The "nb_worker" argument is deprecated when pickle_safe is False')
|
||||
nb_worker = 1 # For backward compatibility
|
||||
return self.model.predict_generator(generator, val_samples,
|
||||
max_q_size=max_q_size)
|
||||
max_q_size=max_q_size,
|
||||
nb_worker=nb_worker,
|
||||
pickle_safe=pickle_safe)
|
||||
|
||||
def get_config(self):
|
||||
'''Returns the model configuration
|
||||
as a Python dictionary.
|
||||
as a Python list.
|
||||
'''
|
||||
config = []
|
||||
if self.layers[0].__class__.__name__ == 'Merge':
|
||||
@@ -725,13 +777,16 @@ class Sequential(Model):
|
||||
return copy.deepcopy(config)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config):
|
||||
def from_config(cls, config, layer_cache=None):
|
||||
'''Supports legacy formats
|
||||
'''
|
||||
from keras.utils.layer_utils import layer_from_config
|
||||
from keras.layers import Merge
|
||||
assert type(config) is list
|
||||
|
||||
if not layer_cache:
|
||||
layer_cache = {}
|
||||
|
||||
def normalize_legacy_config(conf):
|
||||
if 'class_name' not in conf:
|
||||
class_name = conf['name']
|
||||
@@ -744,8 +799,20 @@ class Sequential(Model):
|
||||
return new_config
|
||||
return conf
|
||||
|
||||
# the model we will return
|
||||
model = cls()
|
||||
|
||||
def get_or_create_layer(layer_data):
|
||||
if layer_data['class_name'] == 'Sequential':
|
||||
return Sequential.from_config(layer_data['config'],
|
||||
layer_cache=layer_cache)
|
||||
name = layer_data['config'].get('name')
|
||||
if name in layer_cache:
|
||||
return layer_cache[name]
|
||||
layer = layer_from_config(layer_data)
|
||||
layer_cache[name] = layer
|
||||
return layer
|
||||
|
||||
first_layer = config[0]
|
||||
first_layer = normalize_legacy_config(first_layer)
|
||||
if first_layer['class_name'] == 'Merge':
|
||||
@@ -758,11 +825,11 @@ class Sequential(Model):
|
||||
merge = Merge.from_config(first_layer_config)
|
||||
model.add(merge)
|
||||
else:
|
||||
layer = layer_from_config(first_layer)
|
||||
layer = get_or_create_layer(first_layer)
|
||||
model.add(layer)
|
||||
|
||||
for conf in config[1:]:
|
||||
conf = normalize_legacy_config(conf)
|
||||
layer = layer_from_config(conf)
|
||||
layer = get_or_create_layer(conf)
|
||||
model.add(layer)
|
||||
return model
|
||||
|
||||
@@ -48,6 +48,12 @@ def binary_crossentropy(y_true, y_pred):
|
||||
return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)
|
||||
|
||||
|
||||
def kullback_leibler_divergence(y_true, y_pred):
|
||||
y_true = K.clip(y_true, K.epsilon(), 1)
|
||||
y_pred = K.clip(y_pred, K.epsilon(), 1)
|
||||
return K.sum(y_true * K.log(y_true / y_pred), axis=-1)
|
||||
|
||||
|
||||
def poisson(y_true, y_pred):
|
||||
return K.mean(y_pred - y_true * K.log(y_pred + K.epsilon()), axis=-1)
|
||||
|
||||
@@ -63,6 +69,7 @@ mse = MSE = mean_squared_error
|
||||
mae = MAE = mean_absolute_error
|
||||
mape = MAPE = mean_absolute_percentage_error
|
||||
msle = MSLE = mean_squared_logarithmic_error
|
||||
kld = KLD = kullback_leibler_divergence
|
||||
cosine = cosine_proximity
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
|
||||
+135
-38
@@ -29,6 +29,11 @@ class Optimizer(object):
|
||||
when their absolute value exceeds this value.
|
||||
'''
|
||||
def __init__(self, **kwargs):
|
||||
allowed_kwargs = {'clipnorm', 'clipvalue'}
|
||||
for k in kwargs:
|
||||
if k not in allowed_kwargs:
|
||||
raise Exception('Unexpected keyword argument '
|
||||
'passed to optimizer: ' + str(k))
|
||||
self.__dict__.update(kwargs)
|
||||
self.updates = []
|
||||
self.weights = []
|
||||
@@ -89,7 +94,12 @@ class Optimizer(object):
|
||||
return weights
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__}
|
||||
config = {'name': self.__class__.__name__}
|
||||
if hasattr(self, 'clipnorm'):
|
||||
config['clipnorm'] = self.clipnorm
|
||||
if hasattr(self, 'clipvalue'):
|
||||
config['clipvalue'] = self.clipvalue
|
||||
return config
|
||||
|
||||
|
||||
class SGD(Optimizer):
|
||||
@@ -102,8 +112,8 @@ class SGD(Optimizer):
|
||||
decay: float >= 0. Learning rate decay over each update.
|
||||
nesterov: boolean. Whether to apply Nesterov momentum.
|
||||
'''
|
||||
def __init__(self, lr=0.01, momentum=0., decay=0., nesterov=False,
|
||||
*args, **kwargs):
|
||||
def __init__(self, lr=0.01, momentum=0., decay=0.,
|
||||
nesterov=False, **kwargs):
|
||||
super(SGD, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
@@ -135,11 +145,12 @@ class SGD(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"momentum": float(K.get_value(self.momentum)),
|
||||
"decay": float(K.get_value(self.decay)),
|
||||
"nesterov": self.nesterov}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'momentum': float(K.get_value(self.momentum)),
|
||||
'decay': float(K.get_value(self.decay)),
|
||||
'nesterov': self.nesterov}
|
||||
base_config = super(SGD, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class RMSprop(Optimizer):
|
||||
@@ -157,7 +168,7 @@ class RMSprop(Optimizer):
|
||||
rho: float >= 0.
|
||||
epsilon: float >= 0. Fuzz factor.
|
||||
'''
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-6, *args, **kwargs):
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, **kwargs):
|
||||
super(RMSprop, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
@@ -173,7 +184,7 @@ class RMSprop(Optimizer):
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1. - self.rho) * K.square(g)
|
||||
self.updates.append((a, new_a))
|
||||
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
@@ -183,10 +194,11 @@ class RMSprop(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"rho": float(K.get_value(self.rho)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'rho': float(K.get_value(self.rho)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(RMSprop, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adagrad(Optimizer):
|
||||
@@ -199,7 +211,7 @@ class Adagrad(Optimizer):
|
||||
lr: float >= 0. Learning rate.
|
||||
epsilon: float >= 0.
|
||||
'''
|
||||
def __init__(self, lr=0.01, epsilon=1e-6, *args, **kwargs):
|
||||
def __init__(self, lr=0.01, epsilon=1e-8, **kwargs):
|
||||
super(Adagrad, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
@@ -213,7 +225,7 @@ class Adagrad(Optimizer):
|
||||
for p, g, a in zip(params, grads, self.weights):
|
||||
new_a = a + K.square(g) # update accumulator
|
||||
self.updates.append((a, new_a))
|
||||
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
@@ -222,9 +234,10 @@ class Adagrad(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adagrad, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adadelta(Optimizer):
|
||||
@@ -242,7 +255,7 @@ 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-6, *args, **kwargs):
|
||||
def __init__(self, lr=1.0, rho=0.95, epsilon=1e-8, **kwargs):
|
||||
super(Adadelta, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
@@ -275,10 +288,11 @@ class Adadelta(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"rho": self.rho,
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'rho': self.rho,
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adadelta, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adam(Optimizer):
|
||||
@@ -294,8 +308,8 @@ class Adam(Optimizer):
|
||||
# References
|
||||
- [Adam - A Method for Stochastic Optimization](http://arxiv.org/abs/1412.6980v8)
|
||||
'''
|
||||
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-8,
|
||||
*args, **kwargs):
|
||||
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999,
|
||||
epsilon=1e-8, **kwargs):
|
||||
super(Adam, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0)
|
||||
@@ -331,11 +345,12 @@ class Adam(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"beta_1": float(K.get_value(self.beta_1)),
|
||||
"beta_2": float(K.get_value(self.beta_2)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'beta_1': float(K.get_value(self.beta_1)),
|
||||
'beta_2': float(K.get_value(self.beta_2)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adam, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adamax(Optimizer):
|
||||
@@ -352,8 +367,8 @@ class Adamax(Optimizer):
|
||||
# References
|
||||
- [Adam - A Method for Stochastic Optimization](http://arxiv.org/abs/1412.6980v8)
|
||||
'''
|
||||
def __init__(self, lr=0.002, beta_1=0.9, beta_2=0.999, epsilon=1e-8,
|
||||
*args, **kwargs):
|
||||
def __init__(self, lr=0.002, beta_1=0.9, beta_2=0.999,
|
||||
epsilon=1e-8, **kwargs):
|
||||
super(Adamax, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
@@ -392,11 +407,92 @@ class Adamax(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"beta_1": float(K.get_value(self.beta_1)),
|
||||
"beta_2": float(K.get_value(self.beta_2)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'beta_1': float(K.get_value(self.beta_1)),
|
||||
'beta_2': float(K.get_value(self.beta_2)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adamax, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Nadam(Optimizer):
|
||||
'''
|
||||
Nesterov Adam optimizer: Much like Adam is essentially RMSprop with momentum,
|
||||
Nadam is Adam RMSprop with Nesterov momentum.
|
||||
|
||||
Default parameters follow those provided in the paper.
|
||||
It is recommended to leave the parameters of this optimizer
|
||||
at their default values.
|
||||
|
||||
# Arguments
|
||||
lr: float >= 0. Learning rate.
|
||||
beta_1/beta_2: floats, 0 < beta < 1. Generally close to 1.
|
||||
epsilon: float >= 0. Fuzz factor.
|
||||
|
||||
# References
|
||||
[1] Nadam report - http://cs229.stanford.edu/proj2015/054_report.pdf
|
||||
[2] On the importance of initialization and momentum in deep learning -
|
||||
http://www.cs.toronto.edu/~fritz/absps/momentum.pdf
|
||||
'''
|
||||
def __init__(self, lr=0.002, beta_1=0.9, beta_2=0.999,
|
||||
epsilon=1e-8, schedule_decay=0.004, **kwargs):
|
||||
super(Nadam, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
self.m_schedule = K.variable(1.)
|
||||
self.lr = K.variable(lr)
|
||||
self.beta_1 = K.variable(beta_1)
|
||||
self.beta_2 = K.variable(beta_2)
|
||||
self.schedule_decay = schedule_decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [(self.iterations, self.iterations + 1)]
|
||||
|
||||
t = self.iterations + 1
|
||||
|
||||
# Due to the recommendations in [2], i.e. warming momentum schedule
|
||||
momentum_cache_t = self.beta_1 * (1. - 0.5 * (K.pow(0.96, t * self.schedule_decay)))
|
||||
momentum_cache_t_1 = self.beta_1 * (1. - 0.5 * (K.pow(0.96, (t + 1) * self.schedule_decay)))
|
||||
m_schedule_new = self.m_schedule * momentum_cache_t
|
||||
m_schedule_next = self.m_schedule * momentum_cache_t * momentum_cache_t_1
|
||||
self.updates.append((self.m_schedule, m_schedule_new))
|
||||
|
||||
ms = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
vs = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
|
||||
self.weights = ms + vs
|
||||
|
||||
for p, g, m, v in zip(params, grads, ms, vs):
|
||||
# the following equations given in [1]
|
||||
g_prime = g / (1. - m_schedule_new)
|
||||
m_t = self.beta_1 * m + (1. - self.beta_1) * g
|
||||
m_t_prime = m_t / (1. - m_schedule_next)
|
||||
v_t = self.beta_2 * v + (1. - self.beta_2) * K.square(g)
|
||||
v_t_prime = v_t / (1. - K.pow(self.beta_2, t))
|
||||
m_t_bar = (1. - momentum_cache_t) * g_prime + momentum_cache_t_1 * m_t_prime
|
||||
|
||||
self.updates.append((m, m_t))
|
||||
self.updates.append((v, v_t))
|
||||
|
||||
p_t = p - self.lr * m_t_bar / (K.sqrt(v_t_prime) + self.epsilon)
|
||||
new_p = p_t
|
||||
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'beta_1': float(K.get_value(self.beta_1)),
|
||||
'beta_2': float(K.get_value(self.beta_2)),
|
||||
'epsilon': self.epsilon,
|
||||
'schedule_decay': self.schedule_decay}
|
||||
base_config = super(Nadam, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
# aliases
|
||||
@@ -406,6 +502,7 @@ adagrad = Adagrad
|
||||
adadelta = Adadelta
|
||||
adam = Adam
|
||||
adamax = Adamax
|
||||
nadam = Nadam
|
||||
|
||||
|
||||
def get(identifier, kwargs=None):
|
||||
|
||||
+245
-83
@@ -1,8 +1,9 @@
|
||||
'''Fairly basic set of tools for realtime data augmentation on image data.
|
||||
'''Fairly basic set of tools for real-time data augmentation on image data.
|
||||
Can easily be extended to include new transformations,
|
||||
new preprocessing methods, etc...
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import re
|
||||
@@ -12,6 +13,8 @@ from six.moves import range
|
||||
import os
|
||||
import threading
|
||||
|
||||
from .. import backend as K
|
||||
|
||||
|
||||
def random_rotation(x, rg, row_index=1, col_index=2, channel_index=0,
|
||||
fill_mode='nearest', cval=0.):
|
||||
@@ -115,7 +118,7 @@ def flip_axis(x, axis):
|
||||
return x
|
||||
|
||||
|
||||
def array_to_img(x, dim_ordering='th', scale=True):
|
||||
def array_to_img(x, dim_ordering=K.image_dim_ordering(), scale=True):
|
||||
from PIL import Image
|
||||
if dim_ordering == 'th':
|
||||
x = x.transpose(1, 2, 0)
|
||||
@@ -133,8 +136,7 @@ def array_to_img(x, dim_ordering='th', scale=True):
|
||||
raise Exception('Unsupported channel number: ', x.shape[2])
|
||||
|
||||
|
||||
# only used by tests/keras/preprocessing/test_image.py to convert PIL.Image to numpy array
|
||||
def img_to_array(img, dim_ordering='th'):
|
||||
def img_to_array(img, dim_ordering=K.image_dim_ordering()):
|
||||
if dim_ordering not in ['th', 'tf']:
|
||||
raise Exception('Unknown dim_ordering: ', dim_ordering)
|
||||
# image has dim_ordering (height, width, channel)
|
||||
@@ -152,13 +154,15 @@ def img_to_array(img, dim_ordering='th'):
|
||||
return x
|
||||
|
||||
|
||||
def load_img(path, grayscale=False):
|
||||
def load_img(path, grayscale=False, target_size=None):
|
||||
from PIL import Image
|
||||
img = Image.open(path)
|
||||
if grayscale:
|
||||
img = img.convert('L')
|
||||
else: # Ensure 3 channel even when loaded image is grayscale
|
||||
img = img.convert('RGB')
|
||||
if target_size:
|
||||
img = img.resize(target_size)
|
||||
return img
|
||||
|
||||
|
||||
@@ -192,8 +196,14 @@ class ImageDataGenerator(object):
|
||||
'constant'. Default is 0.
|
||||
horizontal_flip: whether to randomly flip images horizontally.
|
||||
vertical_flip: whether to randomly flip images vertically.
|
||||
rescale: rescaling factor. If None or 0, no rescaling is applied,
|
||||
otherwise we multiply the data by the value provided (before applying
|
||||
any other transformation).
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode it is 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".
|
||||
'''
|
||||
def __init__(self,
|
||||
featurewise_center=False,
|
||||
@@ -211,23 +221,24 @@ class ImageDataGenerator(object):
|
||||
cval=0.,
|
||||
horizontal_flip=False,
|
||||
vertical_flip=False,
|
||||
dim_ordering='th'):
|
||||
rescale=None,
|
||||
dim_ordering=K.image_dim_ordering()):
|
||||
self.__dict__.update(locals())
|
||||
self.mean = None
|
||||
self.std = None
|
||||
self.principal_components = None
|
||||
self.lock = threading.Lock()
|
||||
self.rescale = rescale
|
||||
|
||||
if dim_ordering not in {'tf', 'th'}:
|
||||
raise Exception('dim_ordering should be "tf" (channel after row and '
|
||||
'column) or "th" (channel before row and column). '
|
||||
'Received arg: ', dim_ordering)
|
||||
self.dim_ordering = dim_ordering
|
||||
if dim_ordering == "th":
|
||||
if dim_ordering == 'th':
|
||||
self.channel_index = 1
|
||||
self.row_index = 2
|
||||
self.col_index = 3
|
||||
if dim_ordering == "tf":
|
||||
if dim_ordering == 'tf':
|
||||
self.channel_index = 3
|
||||
self.row_index = 1
|
||||
self.col_index = 2
|
||||
@@ -241,79 +252,30 @@ class ImageDataGenerator(object):
|
||||
'a tuple or list of two floats. '
|
||||
'Received arg: ', zoom_range)
|
||||
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen = 0
|
||||
|
||||
def reset(self):
|
||||
self.batch_index = 0
|
||||
|
||||
def _flow_index(self, N, batch_size=32, shuffle=False, seed=None):
|
||||
while 1:
|
||||
index_array = np.arange(N)
|
||||
if self.batch_index == 0:
|
||||
if shuffle:
|
||||
if seed is not None:
|
||||
np.random.seed(seed + self.total_batches_seen)
|
||||
index_array = np.random.permutation(N)
|
||||
|
||||
current_index = (self.batch_index * batch_size) % N
|
||||
if N >= current_index + batch_size:
|
||||
current_batch_size = batch_size
|
||||
self.batch_index += 1
|
||||
else:
|
||||
current_batch_size = N - current_index
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen += 1
|
||||
yield (index_array[current_index: current_index + current_batch_size],
|
||||
current_index, current_batch_size)
|
||||
|
||||
def flow(self, X, y, batch_size=32, shuffle=False, seed=None,
|
||||
def flow(self, X, y=None, batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
assert len(X) == len(y)
|
||||
self.X = X
|
||||
self.y = y
|
||||
self.save_to_dir = save_to_dir
|
||||
self.save_prefix = save_prefix
|
||||
self.save_format = save_format
|
||||
self.reset()
|
||||
self.flow_generator = self._flow_index(X.shape[0], batch_size,
|
||||
shuffle, seed)
|
||||
return self
|
||||
return NumpyArrayIterator(
|
||||
X, y, self,
|
||||
batch_size=batch_size, shuffle=shuffle, seed=seed,
|
||||
dim_ordering=self.dim_ordering,
|
||||
save_to_dir=save_to_dir, save_prefix=save_prefix, save_format=save_format)
|
||||
|
||||
def __iter__(self):
|
||||
# needed if we want to do something like:
|
||||
# for x, y in data_gen.flow(...):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
# for python 2.x.
|
||||
# Keeps under lock only the mechanism which advances
|
||||
# the indexing of each batch
|
||||
# see # http://anandology.com/blog/using-iterators-and-generators/
|
||||
with self.lock:
|
||||
index_array, current_index, current_batch_size = next(self.flow_generator)
|
||||
# The transformation of images is not under thread lock so it can be done in parallel
|
||||
bX = np.zeros(tuple([current_batch_size] + list(self.X.shape)[1:]))
|
||||
for i, j in enumerate(index_array):
|
||||
x = self.X[j]
|
||||
x = self.random_transform(x.astype('float32'))
|
||||
x = self.standardize(x)
|
||||
bX[i] = x
|
||||
if self.save_to_dir:
|
||||
for i in range(current_batch_size):
|
||||
img = array_to_img(bX[i], self.dim_ordering, scale=True)
|
||||
fname = '{prefix}_{index}.{format}'.format(prefix=self.save_prefix,
|
||||
index=current_index + i,
|
||||
format=self.save_format)
|
||||
img.save(os.path.join(self.save_to_dir, fname))
|
||||
bY = self.y[index_array]
|
||||
return bX, bY
|
||||
|
||||
def __next__(self):
|
||||
# for python 3.x.
|
||||
return self.next()
|
||||
def flow_from_directory(self, directory,
|
||||
target_size=(256, 256), color_mode='rgb',
|
||||
classes=None, class_mode='categorical',
|
||||
batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
return DirectoryIterator(
|
||||
directory, self,
|
||||
target_size=target_size, color_mode=color_mode,
|
||||
classes=classes, class_mode=class_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
batch_size=batch_size, shuffle=shuffle, seed=seed,
|
||||
save_to_dir=save_to_dir, save_prefix=save_prefix, save_format=save_format)
|
||||
|
||||
def standardize(self, x):
|
||||
if self.rescale:
|
||||
x *= self.rescale
|
||||
# x is a single image, so it doesn't have image number at index 0
|
||||
img_channel_index = self.channel_index - 1
|
||||
if self.samplewise_center:
|
||||
@@ -435,9 +397,209 @@ class ImageDataGenerator(object):
|
||||
self.principal_components = np.dot(np.dot(U, np.diag(1. / np.sqrt(S + 10e-7))), U.T)
|
||||
|
||||
|
||||
class GraphImageDataGenerator(ImageDataGenerator):
|
||||
'''Example of how to build a generator for a Graph model
|
||||
'''
|
||||
class Iterator(object):
|
||||
|
||||
def __init__(self, N, batch_size, shuffle, seed):
|
||||
self.N = N
|
||||
self.batch_size = batch_size
|
||||
self.shuffle = shuffle
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen = 0
|
||||
self.lock = threading.Lock()
|
||||
self.index_generator = self._flow_index(N, batch_size, shuffle, seed)
|
||||
|
||||
def reset(self):
|
||||
self.batch_index = 0
|
||||
|
||||
def _flow_index(self, N, batch_size=32, shuffle=False, seed=None):
|
||||
# ensure self.batch_index is 0
|
||||
self.reset()
|
||||
while 1:
|
||||
if self.batch_index == 0:
|
||||
index_array = np.arange(N)
|
||||
if shuffle:
|
||||
if seed is not None:
|
||||
np.random.seed(seed + self.total_batches_seen)
|
||||
index_array = np.random.permutation(N)
|
||||
|
||||
current_index = (self.batch_index * batch_size) % N
|
||||
if N >= current_index + batch_size:
|
||||
current_batch_size = batch_size
|
||||
self.batch_index += 1
|
||||
else:
|
||||
current_batch_size = N - current_index
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen += 1
|
||||
yield (index_array[current_index: current_index + current_batch_size],
|
||||
current_index, current_batch_size)
|
||||
|
||||
def __iter__(self):
|
||||
# needed if we want to do something like:
|
||||
# for x, y in data_gen.flow(...):
|
||||
return self
|
||||
|
||||
def __next__(self, *args, **kwargs):
|
||||
return self.next(*args, **kwargs)
|
||||
|
||||
|
||||
class NumpyArrayIterator(Iterator):
|
||||
|
||||
def __init__(self, X, y, image_data_generator,
|
||||
batch_size=32, shuffle=False, seed=None,
|
||||
dim_ordering=K.image_dim_ordering(),
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
if y is not None and len(X) != len(y):
|
||||
raise Exception('X (images tensor) and y (labels) '
|
||||
'should have the same length. '
|
||||
'Found: X.shape = %s, y.shape = %s' % (np.asarray(X).shape, np.asarray(y).shape))
|
||||
self.X = X
|
||||
self.y = y
|
||||
self.image_data_generator = image_data_generator
|
||||
self.dim_ordering = dim_ordering
|
||||
self.save_to_dir = save_to_dir
|
||||
self.save_prefix = save_prefix
|
||||
self.save_format = save_format
|
||||
super(NumpyArrayIterator, self).__init__(X.shape[0], batch_size, shuffle, seed)
|
||||
|
||||
def next(self):
|
||||
bX, bY = super(GraphImageDataGenerator, self).next()
|
||||
return {'input': bX, 'output': bY}
|
||||
# for python 2.x.
|
||||
# Keeps under lock only the mechanism which advances
|
||||
# the indexing of each batch
|
||||
# see http://anandology.com/blog/using-iterators-and-generators/
|
||||
with self.lock:
|
||||
index_array, current_index, current_batch_size = next(self.index_generator)
|
||||
# The transformation of images is not under thread lock so it can be done in parallel
|
||||
batch_x = np.zeros(tuple([current_batch_size] + list(self.X.shape)[1:]))
|
||||
for i, j in enumerate(index_array):
|
||||
x = self.X[j]
|
||||
x = self.image_data_generator.random_transform(x.astype('float32'))
|
||||
x = self.image_data_generator.standardize(x)
|
||||
batch_x[i] = x
|
||||
if self.save_to_dir:
|
||||
for i in range(current_batch_size):
|
||||
img = array_to_img(batch_x[i], self.dim_ordering, scale=True)
|
||||
fname = '{prefix}_{index}_{hash}.{format}'.format(prefix=self.save_prefix,
|
||||
index=current_index + i,
|
||||
hash=np.random.randint(1e4),
|
||||
format=self.save_format)
|
||||
img.save(os.path.join(self.save_to_dir, fname))
|
||||
if self.y is None:
|
||||
return batch_x
|
||||
batch_y = self.y[index_array]
|
||||
return batch_x, batch_y
|
||||
|
||||
|
||||
class DirectoryIterator(Iterator):
|
||||
|
||||
def __init__(self, directory, image_data_generator,
|
||||
target_size=(256, 256), color_mode='rgb',
|
||||
dim_ordering=K.image_dim_ordering,
|
||||
classes=None, class_mode='categorical',
|
||||
batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
self.directory = directory
|
||||
self.image_data_generator = image_data_generator
|
||||
self.target_size = tuple(target_size)
|
||||
if color_mode not in {'rgb', 'grayscale'}:
|
||||
raise ValueError('Invalid color mode:', color_mode,
|
||||
'; expected "rgb" or "grayscale".')
|
||||
self.color_mode = color_mode
|
||||
self.dim_ordering = dim_ordering
|
||||
if self.color_mode == 'rgb':
|
||||
if self.dim_ordering == 'tf':
|
||||
self.image_shape = self.target_size + (3,)
|
||||
else:
|
||||
self.image_shape = (3,) + self.target_size
|
||||
else:
|
||||
if self.dim_ordering == 'tf':
|
||||
self.image_shape = self.target_size + (1,)
|
||||
else:
|
||||
self.image_shape = (1,) + self.target_size
|
||||
self.classes = classes
|
||||
if class_mode not in {'categorical', 'binary', 'sparse', None}:
|
||||
raise ValueError('Invalid class_mode:', class_mode,
|
||||
'; expected one of "categorical", '
|
||||
'"binary", "sparse", or None.')
|
||||
self.class_mode = class_mode
|
||||
self.save_to_dir = save_to_dir
|
||||
self.save_prefix = save_prefix
|
||||
self.save_format = save_format
|
||||
|
||||
white_list_formats = {'png', 'jpg', 'jpeg', 'bmp'}
|
||||
|
||||
# first, count the number of samples and classes
|
||||
self.nb_sample = 0
|
||||
|
||||
if not classes:
|
||||
classes = []
|
||||
for subdir in sorted(os.listdir(directory)):
|
||||
if os.path.isdir(os.path.join(directory, subdir)):
|
||||
classes.append(subdir)
|
||||
self.nb_class = len(classes)
|
||||
self.class_indices = dict(zip(classes, range(len(classes))))
|
||||
|
||||
for subdir in classes:
|
||||
subpath = os.path.join(directory, subdir)
|
||||
for fname in os.listdir(subpath):
|
||||
is_valid = False
|
||||
for extension in white_list_formats:
|
||||
if fname.lower().endswith('.' + extension):
|
||||
is_valid = True
|
||||
break
|
||||
if is_valid:
|
||||
self.nb_sample += 1
|
||||
print('Found %d images belonging to %d classes.' % (self.nb_sample, self.nb_class))
|
||||
|
||||
# second, build an index of the images in the different class subfolders
|
||||
self.filenames = []
|
||||
self.classes = np.zeros((self.nb_sample,), dtype='int32')
|
||||
i = 0
|
||||
for subdir in classes:
|
||||
subpath = os.path.join(directory, subdir)
|
||||
for fname in os.listdir(subpath):
|
||||
is_valid = False
|
||||
for extension in white_list_formats:
|
||||
if fname.lower().endswith('.' + extension):
|
||||
is_valid = True
|
||||
break
|
||||
if is_valid:
|
||||
self.classes[i] = self.class_indices[subdir]
|
||||
self.filenames.append(os.path.join(subdir, fname))
|
||||
i += 1
|
||||
super(DirectoryIterator, self).__init__(self.nb_sample, batch_size, shuffle, seed)
|
||||
|
||||
def next(self):
|
||||
with self.lock:
|
||||
index_array, current_index, current_batch_size = next(self.index_generator)
|
||||
# The transformation of images is not under thread lock so it can be done in parallel
|
||||
batch_x = np.zeros((current_batch_size,) + self.image_shape)
|
||||
grayscale = self.color_mode == 'grayscale'
|
||||
# build batch of image data
|
||||
for i, j in enumerate(index_array):
|
||||
fname = self.filenames[j]
|
||||
img = load_img(os.path.join(self.directory, fname), grayscale=grayscale, target_size=self.target_size)
|
||||
x = img_to_array(img, dim_ordering=self.dim_ordering)
|
||||
x = self.image_data_generator.random_transform(x)
|
||||
x = self.image_data_generator.standardize(x)
|
||||
batch_x[i] = x
|
||||
# optionally save augmented images to disk for debugging purposes
|
||||
if self.save_to_dir:
|
||||
for i in range(current_batch_size):
|
||||
img = array_to_img(batch_x[i], self.dim_ordering, scale=True)
|
||||
fname = '{prefix}_{index}_{hash}.{format}'.format(prefix=self.save_prefix,
|
||||
index=current_index + i,
|
||||
hash=np.random.randint(1e4),
|
||||
format=self.save_format)
|
||||
img.save(os.path.join(self.save_to_dir, fname))
|
||||
# build batch of labels
|
||||
if self.class_mode == 'sparse':
|
||||
batch_y = self.classes[index_array]
|
||||
elif self.class_mode == 'binary':
|
||||
batch_y = self.classes[index_array].astype('float32')
|
||||
elif self.class_mode == 'categorical':
|
||||
batch_y = np.zeros((len(batch_x), self.nb_class), dtype='float32')
|
||||
for i, label in enumerate(self.classes[index_array]):
|
||||
batch_y[i, label] = 1.
|
||||
else:
|
||||
return batch_x
|
||||
return batch_x, batch_y
|
||||
|
||||
@@ -100,7 +100,7 @@ def skipgrams(sequence, vocabulary_size,
|
||||
'''Take a sequence (list of indexes of words),
|
||||
returns couples of [word_index, other_word index] and labels (1s or 0s),
|
||||
where label = 1 if 'other_word' belongs to the context of 'word',
|
||||
and label=0 if 'other_word' is ramdomly sampled
|
||||
and label=0 if 'other_word' is randomly sampled
|
||||
|
||||
# Arguments
|
||||
vocabulary_size: int. maximum possible word index + 1
|
||||
@@ -113,7 +113,7 @@ def skipgrams(sequence, vocabulary_size,
|
||||
if True labels will be categorical eg. [[1,0],[0,1],[0,1] .. ]
|
||||
|
||||
# Returns
|
||||
couples, lables: where `couples` are int pairs and
|
||||
couples, labels: where `couples` are int pairs and
|
||||
`labels` are either 0 or 1.
|
||||
|
||||
# Notes
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
from a fast Cython rewrite.
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
import string
|
||||
import sys
|
||||
@@ -206,9 +207,11 @@ class Tokenizer(object):
|
||||
elif mode == 'binary':
|
||||
X[i][j] = 1
|
||||
elif mode == 'tfidf':
|
||||
tf = np.log(c / len(seq))
|
||||
df = (1 + np.log(1 + self.index_docs.get(j, 0) / (1 + self.document_count)))
|
||||
X[i][j] = tf / df
|
||||
# Use weighting scheme 2 in
|
||||
# https://en.wikipedia.org/wiki/Tf%E2%80%93idf
|
||||
tf = 1 + np.log(c)
|
||||
idf = np.log(1 + self.document_count / (1 + self.index_docs.get(j, 0)))
|
||||
X[i][j] = tf * idf
|
||||
else:
|
||||
raise Exception('Unknown vectorization mode: ' + str(mode))
|
||||
return X
|
||||
|
||||
+49
-7
@@ -16,6 +16,46 @@ class Regularizer(object):
|
||||
return {'name': self.__class__.__name__}
|
||||
|
||||
|
||||
class EigenvalueRegularizer(Regularizer):
|
||||
'''This takes a constant that controls
|
||||
the regularization by Eigenvalue Decay on the
|
||||
current layer and outputs the regularized
|
||||
loss (evaluated on the training data) and
|
||||
the original loss (evaluated on the
|
||||
validation data).
|
||||
'''
|
||||
def __init__(self, k):
|
||||
self.k = k
|
||||
self.uses_learning_phase = True
|
||||
|
||||
def set_param(self, p):
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
power = 9 # number of iterations of the power method
|
||||
W = self.p
|
||||
if K.ndim(W) > 2:
|
||||
raise Exception('Eigenvalue Decay regularizer '
|
||||
'is only available for dense '
|
||||
'and embedding layers.')
|
||||
WW = K.dot(K.transpose(W), W)
|
||||
dim1, dim2 = K.eval(K.shape(WW)) # number of neurons in the layer
|
||||
|
||||
# power method for approximating the dominant eigenvector:
|
||||
o = K.ones([dim1, 1]) # initial values for the dominant eigenvector
|
||||
domin_eigenvect = K.dot(WW, o)
|
||||
for n in range(power - 1):
|
||||
domin_eigenvect = K.dot(WW, domin_eigenvect)
|
||||
|
||||
WWd = K.dot(WW, domin_eigenvect)
|
||||
|
||||
# the corresponding dominant eigenvalue:
|
||||
domin_eigenval = K.dot(K.transpose(WWd), domin_eigenvect) / K.dot(K.transpose(domin_eigenvect), domin_eigenvect)
|
||||
regularized_loss = loss + (domin_eigenval ** 0.5) * self.k # multiplied by the given regularization gain
|
||||
|
||||
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)
|
||||
@@ -41,8 +81,8 @@ class WeightRegularizer(Regularizer):
|
||||
|
||||
def get_config(self):
|
||||
return {'name': self.__class__.__name__,
|
||||
'l1': self.l1,
|
||||
'l2': self.l2}
|
||||
'l1': float(self.l1),
|
||||
'l2': float(self.l2)}
|
||||
|
||||
|
||||
class ActivityRegularizer(Regularizer):
|
||||
@@ -59,15 +99,17 @@ class ActivityRegularizer(Regularizer):
|
||||
raise Exception('Need to call `set_layer` on '
|
||||
'ActivityRegularizer instance '
|
||||
'before calling the instance.')
|
||||
output = self.layer.output
|
||||
regularized_loss = loss + self.l1 * K.sum(K.mean(K.abs(output), axis=0))
|
||||
regularized_loss += self.l2 * K.sum(K.mean(K.square(output), axis=0))
|
||||
regularized_loss = loss
|
||||
for i in range(len(self.layer.inbound_nodes)):
|
||||
output = self.layer.get_output_at(i)
|
||||
regularized_loss += self.l1 * K.sum(K.mean(K.abs(output), axis=0))
|
||||
regularized_loss += self.l2 * K.sum(K.mean(K.square(output), axis=0))
|
||||
return K.in_train_phase(regularized_loss, loss)
|
||||
|
||||
def get_config(self):
|
||||
return {'name': self.__class__.__name__,
|
||||
'l1': self.l1,
|
||||
'l2': self.l2}
|
||||
'l1': float(self.l1),
|
||||
'l2': float(self.l2)}
|
||||
|
||||
|
||||
def l1(l=0.01):
|
||||
|
||||
@@ -34,24 +34,28 @@ def make_tuple(*args):
|
||||
|
||||
|
||||
class Progbar(object):
|
||||
def __init__(self, target, width=30, verbose=1):
|
||||
def __init__(self, target, width=30, verbose=1, interval=0.01):
|
||||
'''
|
||||
@param target: total number of steps expected
|
||||
@param interval: minimum visual progress update interval (in seconds)
|
||||
'''
|
||||
self.width = width
|
||||
self.target = target
|
||||
self.sum_values = {}
|
||||
self.unique_values = []
|
||||
self.start = time.time()
|
||||
self.last_update = 0
|
||||
self.interval = interval
|
||||
self.total_width = 0
|
||||
self.seen_so_far = 0
|
||||
self.verbose = verbose
|
||||
|
||||
def update(self, current, values=[]):
|
||||
def update(self, current, values=[], force=False):
|
||||
'''
|
||||
@param current: index of current step
|
||||
@param values: list of tuples (name, value_for_last_step).
|
||||
The progress bar will display averages for these values.
|
||||
@param force: force visual progress update
|
||||
'''
|
||||
for k, v in values:
|
||||
if k not in self.sum_values:
|
||||
@@ -64,6 +68,9 @@ class Progbar(object):
|
||||
|
||||
now = time.time()
|
||||
if self.verbose == 1:
|
||||
if not force and (now - self.last_update) < self.interval:
|
||||
return
|
||||
|
||||
prev_total_width = self.total_width
|
||||
sys.stdout.write("\b" * prev_total_width)
|
||||
sys.stdout.write("\r")
|
||||
@@ -127,6 +134,8 @@ class Progbar(object):
|
||||
info += ' %.4e' % avg
|
||||
sys.stdout.write(info + "\n")
|
||||
|
||||
self.last_update = now
|
||||
|
||||
def add(self, n, values=[]):
|
||||
self.update(self.seen_so_far + n, values)
|
||||
|
||||
|
||||
@@ -35,9 +35,11 @@ def layer_from_config(config, custom_objects={}):
|
||||
return layer_class.from_config(config['config'])
|
||||
|
||||
|
||||
def print_summary(layers, relevant_nodes=None):
|
||||
line_length = 100 # total length of printed lines
|
||||
positions = [35, 55, 67, 100] # absolute positions of log elements in each line
|
||||
def print_summary(layers, relevant_nodes=None, line_length=100, positions=[.33, .55, .67, 1.]):
|
||||
# line_length: total length of printed lines
|
||||
# positions: relative or absolute positions of log elements in each line
|
||||
if positions[-1] <= 1:
|
||||
positions = [int(line_length * p) for p in positions]
|
||||
# header names for the different log elements
|
||||
to_display = ['Layer (type)', 'Output Shape', 'Param #', 'Connected to']
|
||||
|
||||
|
||||
+60
-14
@@ -53,24 +53,70 @@ def categorical_probas_to_classes(p):
|
||||
|
||||
|
||||
def convert_kernel(kernel, dim_ordering='th'):
|
||||
'''Converts a kernel matrix (numpy array)
|
||||
'''Converts a kernel matrix (Numpy array)
|
||||
from Theano format to TensorFlow format
|
||||
(or reciprocally, since the transformation
|
||||
is its own inverse).
|
||||
'''
|
||||
new_kernel = np.copy(kernel)
|
||||
if dim_ordering == 'th':
|
||||
w = kernel.shape[2]
|
||||
h = kernel.shape[3]
|
||||
for i in range(w):
|
||||
for j in range(h):
|
||||
new_kernel[:, :, i, j] = kernel[:, :, w - i - 1, h - j - 1]
|
||||
elif dim_ordering == 'tf':
|
||||
w = kernel.shape[0]
|
||||
h = kernel.shape[1]
|
||||
for i in range(w):
|
||||
for j in range(h):
|
||||
new_kernel[i, j, :, :] = kernel[w - i - 1, h - j - 1, :, :]
|
||||
if kernel.ndim == 4:
|
||||
# conv 2d
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
if dim_ordering == 'th':
|
||||
w = kernel.shape[2]
|
||||
h = kernel.shape[3]
|
||||
for i in range(w):
|
||||
for j in range(h):
|
||||
new_kernel[:, :, i, j] = kernel[:, :, w - i - 1, h - j - 1]
|
||||
elif dim_ordering == 'tf':
|
||||
w = kernel.shape[0]
|
||||
h = kernel.shape[1]
|
||||
for i in range(w):
|
||||
for j in range(h):
|
||||
new_kernel[i, j, :, :] = kernel[w - i - 1, h - j - 1, :, :]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + str(dim_ordering))
|
||||
elif kernel.ndim == 5:
|
||||
# conv 3d
|
||||
# TH kernel shape: (out_depth, input_depth, kernel_dim1, kernel_dim2, kernel_dim3)
|
||||
# TF kernel shape: (kernel_dim1, kernel_dim2, kernel_dim3, input_depth, out_depth)
|
||||
if dim_ordering == 'th':
|
||||
w = kernel.shape[2]
|
||||
h = kernel.shape[3]
|
||||
z = kernel.shape[4]
|
||||
for i in range(w):
|
||||
for j in range(h):
|
||||
for k in range(z):
|
||||
new_kernel[:, :, i, j, k] = kernel[:, :,
|
||||
w - i - 1,
|
||||
h - j - 1,
|
||||
z - k - 1]
|
||||
elif dim_ordering == 'tf':
|
||||
w = kernel.shape[0]
|
||||
h = kernel.shape[1]
|
||||
z = kernel.shape[2]
|
||||
for i in range(w):
|
||||
for j in range(h):
|
||||
for k in range(z):
|
||||
new_kernel[i, j, k, :, :] = kernel[w - i - 1,
|
||||
h - j - 1,
|
||||
z - k - 1,
|
||||
:, :]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + str(dim_ordering))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + str(dim_ordering))
|
||||
raise ValueError('Invalid kernel shape:', kernel.shape)
|
||||
return new_kernel
|
||||
|
||||
|
||||
def conv_output_length(input_length, filter_size, border_mode, stride, dilation=1):
|
||||
if input_length is None:
|
||||
return None
|
||||
assert border_mode in {'same', 'valid'}
|
||||
dilated_filter_size = filter_size + (filter_size - 1) * (dilation - 1)
|
||||
if border_mode == 'same':
|
||||
output_length = input_length
|
||||
elif border_mode == 'valid':
|
||||
output_length = input_length - dilated_filter_size + 1
|
||||
return (output_length + stride - 1) // stride
|
||||
|
||||
@@ -9,7 +9,7 @@ if not pydot.find_graphviz():
|
||||
' and graphviz for `pydotprint` to work.')
|
||||
|
||||
|
||||
def model_to_dot(model, show_shapes=False):
|
||||
def model_to_dot(model, show_shapes=False, show_layer_names=True):
|
||||
dot = pydot.Dot()
|
||||
dot.set('rankdir', 'TB')
|
||||
dot.set('concentrate', True)
|
||||
@@ -24,7 +24,10 @@ def model_to_dot(model, show_shapes=False):
|
||||
# first, populate the nodes of the graph
|
||||
for layer in layers:
|
||||
layer_id = str(id(layer))
|
||||
label = str(layer.name) + ' (' + layer.__class__.__name__ + ')'
|
||||
if show_layer_names:
|
||||
label = str(layer.name) + ' (' + layer.__class__.__name__ + ')'
|
||||
else:
|
||||
label = layer.__class__.__name__
|
||||
|
||||
if show_shapes:
|
||||
# Build the label that will actually contain a table with the
|
||||
@@ -59,6 +62,6 @@ def model_to_dot(model, show_shapes=False):
|
||||
return dot
|
||||
|
||||
|
||||
def plot(model, to_file='model.png', show_shapes=False):
|
||||
dot = model_to_dot(model, show_shapes)
|
||||
def plot(model, to_file='model.png', show_shapes=False, show_layer_names=True):
|
||||
dot = model_to_dot(model, show_shapes, show_layer_names)
|
||||
dot.write_png(to_file)
|
||||
|
||||
@@ -29,7 +29,7 @@ class BaseWrapper(object):
|
||||
|
||||
`sk_params` takes both model parameters and fitting parameters. Legal model
|
||||
parameters are the arguments of `build_fn`. Note that like all other
|
||||
estimators in scikit-learn, 'build_fn' should provide defalult values for
|
||||
estimators in scikit-learn, 'build_fn' should provide default values for
|
||||
its arguments, so that you could create the estimator without passing any
|
||||
values to `sk_params`.
|
||||
|
||||
@@ -154,10 +154,10 @@ class BaseWrapper(object):
|
||||
|
||||
# Arguments
|
||||
fn : arbitrary function
|
||||
override: dictionary, values to overrid sk_params
|
||||
override: dictionary, values to override sk_params
|
||||
|
||||
# Returns
|
||||
res : dictionary dictionary containing variabls
|
||||
res : dictionary dictionary containing variables
|
||||
in both sk_params and fn's arguments.
|
||||
'''
|
||||
res = {}
|
||||
@@ -203,9 +203,19 @@ class KerasClassifier(BaseWrapper):
|
||||
# Returns
|
||||
proba: array-like, shape `(n_samples, n_outputs)`
|
||||
Class probability estimates.
|
||||
In the case of binary classification,
|
||||
tp match the scikit-learn API,
|
||||
will return an array of shape '(n_samples, 2)'
|
||||
(instead of `(n_sample, 1)` as in Keras).
|
||||
'''
|
||||
kwargs = self.filter_sk_params(Sequential.predict_proba, kwargs)
|
||||
return self.model.predict_proba(X, **kwargs)
|
||||
probs = self.model.predict_proba(X, **kwargs)
|
||||
|
||||
# check if binary classification
|
||||
if probs.shape[1] == 1:
|
||||
# first column is probability of class 0 and second is of class 1
|
||||
probs = np.hstack([1 - probs, probs])
|
||||
return probs
|
||||
|
||||
def score(self, X, y, **kwargs):
|
||||
'''Returns the mean accuracy on the given test data and labels.
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@ from setuptools import find_packages
|
||||
|
||||
|
||||
setup(name='Keras',
|
||||
version='1.0.2',
|
||||
version='1.0.6',
|
||||
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.2',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.0.6',
|
||||
license='MIT',
|
||||
install_requires=['theano', 'pyyaml', 'six'],
|
||||
extras_require={
|
||||
|
||||
@@ -23,7 +23,7 @@ def test_temporal_classification():
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=200,
|
||||
nb_test=500,
|
||||
input_shape=(3, 5),
|
||||
classification=True,
|
||||
nb_class=2)
|
||||
@@ -35,12 +35,12 @@ def test_temporal_classification():
|
||||
input_shape=(X_train.shape[1], X_train.shape[2]),
|
||||
activation='softmax'))
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer='adadelta',
|
||||
optimizer='adagrad',
|
||||
metrics=['accuracy'])
|
||||
history = model.fit(X_train, y_train, nb_epoch=5, batch_size=16,
|
||||
history = model.fit(X_train, y_train, nb_epoch=20, batch_size=32,
|
||||
validation_data=(X_test, y_test),
|
||||
verbose=0)
|
||||
assert(history.history['val_acc'][-1] > 0.9)
|
||||
assert(history.history['val_acc'][-1] >= 0.85)
|
||||
|
||||
|
||||
def test_temporal_regression():
|
||||
@@ -182,4 +182,5 @@ def test_masked_temporal():
|
||||
assert(np.abs(history.history['val_loss'][-1] - ground_truth) < 0.06)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
# pytest.main([__file__])
|
||||
test_temporal_classification()
|
||||
|
||||
@@ -38,6 +38,26 @@ def check_two_tensor_operation(function_name, x_input_shape,
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
def check_composed_tensor_operations(first_function_name, first_function_args,
|
||||
second_function_name, second_function_args,
|
||||
input_shape):
|
||||
''' Creates a random tensor t0 with shape input_shape and compute
|
||||
t1 = first_function_name(t0, **first_function_args)
|
||||
t2 = second_function_name(t1, **second_function_args)
|
||||
with both Theano and TensorFlow backends and ensures the answers match.
|
||||
'''
|
||||
val = np.random.random(input_shape) - 0.5
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
|
||||
yth = getattr(KTH, first_function_name)(xth, **first_function_args)
|
||||
ytf = getattr(KTF, first_function_name)(xtf, **first_function_args)
|
||||
|
||||
zth = KTH.eval(getattr(KTH, second_function_name)(yth, **second_function_args))
|
||||
ztf = KTF.eval(getattr(KTF, second_function_name)(ytf, **second_function_args))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
class TestBackend(object):
|
||||
|
||||
@@ -70,6 +90,9 @@ class TestBackend(object):
|
||||
check_single_tensor_operation('expand_dims', (4, 3), dim=-1)
|
||||
check_single_tensor_operation('expand_dims', (4, 3, 2), dim=1)
|
||||
check_single_tensor_operation('squeeze', (4, 3, 1), axis=2)
|
||||
check_composed_tensor_operations('reshape', {'shape':(4,3,1,1)},
|
||||
'squeeze', {'axis':2},
|
||||
(4, 3, 1, 1))
|
||||
|
||||
def test_repeat_elements(self):
|
||||
reps = 3
|
||||
@@ -91,6 +114,17 @@ class TestBackend(object):
|
||||
assert_allclose(np_rep, th_rep, atol=1e-05)
|
||||
assert_allclose(np_rep, tf_rep, atol=1e-05)
|
||||
|
||||
def test_tile(self):
|
||||
shape = (3, 4)
|
||||
arr = np.arange(np.prod(shape)).reshape(shape)
|
||||
arr_th = KTH.variable(arr)
|
||||
arr_tf = KTF.variable(arr)
|
||||
|
||||
n = (2, 1)
|
||||
th_rep = KTH.eval(KTH.tile(arr_th, n))
|
||||
tf_rep = KTF.eval(KTF.tile(arr_tf, n))
|
||||
assert_allclose(tf_rep, th_rep, atol=1e-05)
|
||||
|
||||
def test_value_manipulation(self):
|
||||
val = np.random.random((4, 2))
|
||||
xth = KTH.variable(val)
|
||||
@@ -139,6 +173,9 @@ class TestBackend(object):
|
||||
# does not work yet, wait for bool <-> int casting in TF (coming soon)
|
||||
# check_single_tensor_operation('any', (4, 2))
|
||||
# check_single_tensor_operation('any', (4, 2), axis=1, keepdims=True)
|
||||
#
|
||||
# check_single_tensor_operation('any', (4, 2))
|
||||
# check_single_tensor_operation('any', (4, 2), axis=1, keepdims=True)
|
||||
|
||||
check_single_tensor_operation('argmax', (4, 2))
|
||||
check_single_tensor_operation('argmax', (4, 2), axis=1)
|
||||
@@ -171,14 +208,24 @@ class TestBackend(object):
|
||||
exptf = xtf * KTF.exp(xtf)
|
||||
lossth = KTH.sum(expth)
|
||||
losstf = KTF.sum(exptf)
|
||||
zero_lossth = KTH.stop_gradient(lossth)
|
||||
zero_losstf = KTF.stop_gradient(losstf)
|
||||
|
||||
gradth = KTH.gradients(lossth, [expth])
|
||||
gradtf = KTF.gradients(losstf, [exptf])
|
||||
zero_gradth = KTH.gradients(lossth + zero_lossth, [expth])
|
||||
zero_gradtf = KTF.gradients(losstf + zero_losstf, [exptf])
|
||||
|
||||
zth = KTH.eval(gradth[0])
|
||||
ztf = KTF.eval(gradtf[0])
|
||||
zero_zth = KTH.eval(zero_gradth[0])
|
||||
zero_ztf = KTF.eval(zero_gradtf[0])
|
||||
assert zth.shape == ztf.shape
|
||||
assert zero_zth.shape == zero_ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
assert_allclose(zero_zth, zero_ztf, atol=1e-05)
|
||||
assert_allclose(zero_zth, zth, atol=1e-05)
|
||||
assert_allclose(zero_ztf, ztf, atol=1e-05)
|
||||
|
||||
def test_function(self):
|
||||
val = np.random.random((4, 2))
|
||||
@@ -413,6 +460,51 @@ class TestBackend(object):
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
def test_conv3d(self):
|
||||
# TH input shape: (samples, input_depth, conv_dim1, conv_dim2, conv_dim3)
|
||||
# TF input shape: (samples, conv_dim1, conv_dim2, conv_dim3, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, x, y, z)
|
||||
# TF kernel shape: (x, y, z, input_depth, depth)
|
||||
|
||||
# test in dim_ordering = th
|
||||
for input_shape in [(2, 3, 4, 5, 4), (2, 3, 5, 4, 6)]:
|
||||
for kernel_shape in [(4, 3, 2, 2, 2), (4, 3, 3, 2, 4)]:
|
||||
xval = np.random.random(input_shape)
|
||||
|
||||
xth = KTH.variable(xval)
|
||||
xtf = KTF.variable(xval)
|
||||
|
||||
kernel_val = np.random.random(kernel_shape) - 0.5
|
||||
|
||||
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))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
# test in dim_ordering = tf
|
||||
input_shape = (1, 2, 2, 2, 1)
|
||||
kernel_shape = (2, 2, 2, 1, 1)
|
||||
|
||||
xval = np.random.random(input_shape)
|
||||
|
||||
xth = KTH.variable(xval)
|
||||
xtf = KTF.variable(xval)
|
||||
|
||||
kernel_val = np.random.random(kernel_shape) - 0.5
|
||||
|
||||
kernel_th = KTH.variable(convert_kernel(kernel_val, dim_ordering='tf'))
|
||||
kernel_tf = KTF.variable(kernel_val)
|
||||
|
||||
zth = KTH.eval(KTH.conv3d(xth, kernel_th, dim_ordering='tf'))
|
||||
ztf = KTF.eval(KTF.conv3d(xtf, kernel_tf, dim_ordering='tf'))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
def test_pool2d(self):
|
||||
check_single_tensor_operation('pool2d', (5, 3, 10, 12), pool_size=(2, 2),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
@@ -423,6 +515,16 @@ class TestBackend(object):
|
||||
check_single_tensor_operation('pool2d', (5, 3, 9, 11), 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),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool3d', (5, 3, 9, 11, 5), 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),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
def test_random_normal(self):
|
||||
mean = 0.
|
||||
std = 1.
|
||||
|
||||
@@ -1,26 +1,44 @@
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
import time
|
||||
import random
|
||||
from keras.datasets import cifar10, cifar100, reuters, imdb, mnist
|
||||
|
||||
|
||||
def test_cifar():
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
|
||||
(X_train, y_train), (X_test, y_test) = cifar100.load_data('fine')
|
||||
(X_train, y_train), (X_test, y_test) = cifar100.load_data('coarse')
|
||||
# only run data download tests 20% of the time
|
||||
# to speed up frequent testing
|
||||
random.seed(time.time())
|
||||
if random.random() > 0.8:
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
|
||||
(X_train, y_train), (X_test, y_test) = cifar100.load_data('fine')
|
||||
(X_train, y_train), (X_test, y_test) = cifar100.load_data('coarse')
|
||||
|
||||
|
||||
def test_reuters():
|
||||
(X_train, y_train), (X_test, y_test) = reuters.load_data()
|
||||
(X_train, y_train), (X_test, y_test) = reuters.load_data(maxlen=10)
|
||||
# only run data download tests 20% of the time
|
||||
# to speed up frequent testing
|
||||
random.seed(time.time())
|
||||
if random.random() > 0.8:
|
||||
(X_train, y_train), (X_test, y_test) = reuters.load_data()
|
||||
(X_train, y_train), (X_test, y_test) = reuters.load_data(maxlen=10)
|
||||
|
||||
|
||||
def test_mnist():
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
# only run data download tests 20% of the time
|
||||
# to speed up frequent testing
|
||||
random.seed(time.time())
|
||||
if random.random() > 0.8:
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
|
||||
def test_imdb():
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data()
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(maxlen=40)
|
||||
# only run data download tests 20% of the time
|
||||
# to speed up frequent testing
|
||||
random.seed(time.time())
|
||||
if random.random() > 0.8:
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data()
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(maxlen=40)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -2,7 +2,7 @@ import pytest
|
||||
import json
|
||||
import numpy as np
|
||||
|
||||
from keras.layers import Dense, Dropout
|
||||
from keras.layers import Dense, Dropout, InputLayer
|
||||
from keras.engine import merge, Input, get_source_inputs
|
||||
from keras.models import Model
|
||||
from keras import backend as K
|
||||
@@ -392,6 +392,13 @@ def test_recursion():
|
||||
# test merge
|
||||
o_tf = merge([j_tf, k_tf], mode='concat', concat_axis=1)
|
||||
|
||||
# test tensor input
|
||||
x = tf.placeholder(shape=(None, 2), dtype=K.floatx())
|
||||
input_layer = InputLayer(input_tensor=x)
|
||||
|
||||
x = Input(tensor=x)
|
||||
y = Dense(2)(x)
|
||||
|
||||
|
||||
def test_functional_guide():
|
||||
# MNIST
|
||||
@@ -515,8 +522,6 @@ def test_sequential_regression():
|
||||
name='embed_1'))
|
||||
branch_1.add(LSTM(32, name='lstm_1'))
|
||||
|
||||
branch_1.add(BatchNormalization())
|
||||
|
||||
branch_2 = Sequential(name='branch_2')
|
||||
branch_2.add(Dense(32, input_shape=(8,), name='dense_2'))
|
||||
|
||||
|
||||
@@ -117,10 +117,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
|
||||
# this should also work
|
||||
model.compile(optimizer, loss, metrics={'dense_1': 'acc'},
|
||||
@@ -128,10 +128,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
|
||||
# and this as well
|
||||
model.compile(optimizer, loss, metrics={'dense_1': ['acc']},
|
||||
@@ -139,10 +139,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
|
||||
# test with a custom metric function
|
||||
mse = lambda y_true, y_pred: K.mean(K.pow(y_true - y_pred, 2))
|
||||
@@ -151,10 +151,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
|
||||
input_a_np = np.random.random((10, 3))
|
||||
input_b_np = np.random.random((10, 3))
|
||||
|
||||
@@ -53,7 +53,7 @@ def test_averagepooling_1d():
|
||||
|
||||
|
||||
def test_convolution_2d():
|
||||
nb_samples = 8
|
||||
nb_samples = 2
|
||||
nb_filter = 3
|
||||
stack_size = 4
|
||||
nb_row = 10
|
||||
@@ -84,6 +84,82 @@ def test_convolution_2d():
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
|
||||
|
||||
def test_atrous_conv_2d():
|
||||
nb_samples = 2
|
||||
nb_filter = 3
|
||||
stack_size = 4
|
||||
nb_row = 10
|
||||
nb_col = 6
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample in [(1, 1), (2, 2)]:
|
||||
for atrous_rate in [(1, 1), (2, 2)]:
|
||||
if border_mode == 'same' and subsample != (1, 1):
|
||||
continue
|
||||
if subsample != (1, 1) and atrous_rate != (1, 1):
|
||||
continue
|
||||
|
||||
layer_test(convolutional.AtrousConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
|
||||
layer_test(convolutional.AtrousConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'tensorflow', reason="Requires TF backend")
|
||||
def test_separable_conv_2d():
|
||||
nb_samples = 2
|
||||
nb_filter = 8
|
||||
stack_size = 4
|
||||
nb_row = 10
|
||||
nb_col = 6
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample in [(1, 1), (2, 2)]:
|
||||
for multiplier in [1, 2]:
|
||||
if border_mode == 'same' and subsample != (1, 1):
|
||||
continue
|
||||
|
||||
layer_test(convolutional.SeparableConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'depth_multiplier': multiplier},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
|
||||
layer_test(convolutional.SeparableConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'depthwise_regularizer': 'l2',
|
||||
'pointwise_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'pointwise_constraint': 'unitnorm',
|
||||
'depthwise_constraint': 'unitnorm',
|
||||
'subsample': subsample,
|
||||
'depth_multiplier': multiplier},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
|
||||
|
||||
def test_maxpooling_2d():
|
||||
pool_size = (3, 3)
|
||||
|
||||
@@ -108,7 +184,6 @@ def test_averagepooling_2d():
|
||||
input_shape=(3, 4, 11, 12))
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_convolution_3d():
|
||||
nb_samples = 2
|
||||
nb_filter = 5
|
||||
@@ -150,7 +225,6 @@ def test_convolution_3d():
|
||||
input_len_dim1, input_len_dim2, input_len_dim3))
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_maxpooling_3d():
|
||||
pool_size = (3, 3, 3)
|
||||
|
||||
@@ -162,7 +236,6 @@ def test_maxpooling_3d():
|
||||
input_shape=(3, 4, 11, 12, 10))
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_averagepooling_3d():
|
||||
pool_size = (3, 3, 3)
|
||||
|
||||
@@ -175,7 +248,7 @@ def test_averagepooling_3d():
|
||||
|
||||
|
||||
def test_zero_padding_2d():
|
||||
nb_samples = 9
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
input_nb_row = 11
|
||||
input_nb_col = 12
|
||||
@@ -201,7 +274,7 @@ def test_zero_padding_2d():
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_zero_padding_3d():
|
||||
nb_samples = 9
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
input_len_dim1 = 10
|
||||
input_len_dim2 = 11
|
||||
@@ -234,7 +307,7 @@ def test_upsampling_1d():
|
||||
|
||||
|
||||
def test_upsampling_2d():
|
||||
nb_samples = 9
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
input_nb_row = 11
|
||||
input_nb_col = 12
|
||||
@@ -275,7 +348,7 @@ def test_upsampling_2d():
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_upsampling_3d():
|
||||
nb_samples = 9
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
input_len_dim1 = 10
|
||||
input_len_dim2 = 11
|
||||
@@ -320,5 +393,4 @@ def test_upsampling_3d():
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
# pytest.main([__file__])
|
||||
test_convolution_3d()
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import pytest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import core
|
||||
@@ -22,7 +21,7 @@ def test_merge():
|
||||
inputs = [np.random.random(shape) for shape in input_shapes]
|
||||
|
||||
# test functional API
|
||||
for mode in ['sum', 'mul', 'concat', 'ave']:
|
||||
for mode in ['sum', 'mul', 'concat', 'ave', 'max']:
|
||||
print(mode)
|
||||
input_a = Input(shape=input_shapes[0][1:])
|
||||
input_b = Input(shape=input_shapes[1][1:])
|
||||
@@ -84,6 +83,60 @@ def test_merge():
|
||||
model.compile('rmsprop', 'mse')
|
||||
|
||||
|
||||
def test_merge_mask_2d():
|
||||
from keras.layers import Input, merge, Masking
|
||||
from keras.models import Model
|
||||
|
||||
rand = lambda *shape: np.asarray(np.random.random(shape) > 0.5, dtype='int32')
|
||||
|
||||
# inputs
|
||||
input_a = Input(shape=(3,))
|
||||
input_b = Input(shape=(3,))
|
||||
|
||||
# masks
|
||||
masked_a = Masking(mask_value=0)(input_a)
|
||||
masked_b = Masking(mask_value=0)(input_b)
|
||||
|
||||
# two different types of merging
|
||||
merged_sum = merge([masked_a, masked_b], mode='sum')
|
||||
merged_concat = merge([masked_a, masked_b], mode='concat', concat_axis=1)
|
||||
|
||||
# test sum
|
||||
model_sum = Model([input_a, input_b], [merged_sum])
|
||||
model_sum.compile(loss='mse', optimizer='sgd')
|
||||
model_sum.fit([rand(2,3), rand(2,3)], [rand(2,3)], nb_epoch=1)
|
||||
|
||||
# test concatenation
|
||||
model_concat = Model([input_a, input_b], [merged_concat])
|
||||
model_concat.compile(loss='mse', optimizer='sgd')
|
||||
model_concat.fit([rand(2,3), rand(2,3)], [rand(2,6)], nb_epoch=1)
|
||||
|
||||
|
||||
def test_merge_mask_3d():
|
||||
from keras.layers import Input, merge, Embedding, SimpleRNN
|
||||
from keras.models import Model
|
||||
|
||||
rand = lambda *shape: np.asarray(np.random.random(shape) > 0.5, dtype='int32')
|
||||
|
||||
# embeddings
|
||||
input_a = Input(shape=(3,), dtype='int32')
|
||||
input_b = Input(shape=(3,), dtype='int32')
|
||||
embedding = Embedding(3, 4, mask_zero=True)
|
||||
embedding_a = embedding(input_a)
|
||||
embedding_b = embedding(input_b)
|
||||
|
||||
# rnn
|
||||
rnn = SimpleRNN(3, return_sequences=True)
|
||||
rnn_a = rnn(embedding_a)
|
||||
rnn_b = rnn(embedding_b)
|
||||
|
||||
# concatenation
|
||||
merged_concat = merge([rnn_a, rnn_b], mode='concat', concat_axis=-1)
|
||||
model = Model([input_a, input_b], [merged_concat])
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
model.fit([rand(2,3), rand(2,3)], [rand(2,3,6)])
|
||||
|
||||
|
||||
def test_dropout():
|
||||
layer_test(core.Dropout,
|
||||
kwargs={'p': 0.5},
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
import pytest
|
||||
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.layers import local
|
||||
|
||||
|
||||
def test_locallyconnected_1d():
|
||||
nb_samples = 2
|
||||
nb_steps = 8
|
||||
input_dim = 5
|
||||
filter_length = 3
|
||||
nb_filter = 4
|
||||
|
||||
for border_mode in ['valid']:
|
||||
for subsample_length in [1]:
|
||||
if border_mode == 'same' and subsample_length != 1:
|
||||
continue
|
||||
layer_test(local.LocallyConnected1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
'border_mode': border_mode,
|
||||
'subsample_length': subsample_length},
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
layer_test(local.LocallyConnected1D,
|
||||
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},
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
|
||||
def test_locallyconnected_2d():
|
||||
nb_samples = 8
|
||||
nb_filter = 3
|
||||
stack_size = 4
|
||||
nb_row = 6
|
||||
nb_col = 10
|
||||
|
||||
for border_mode in ['valid']:
|
||||
for subsample in [(1, 1), (2, 2)]:
|
||||
if border_mode == 'same' and subsample != (1, 1):
|
||||
continue
|
||||
|
||||
layer_test(local.LocallyConnected2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample,
|
||||
'dim_ordering': 'tf'},
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(local.LocallyConnected2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample,
|
||||
'dim_ordering': 'th'},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
@@ -24,22 +24,22 @@ def basic_batchnorm_test():
|
||||
input_shape=(3, 4, 2))
|
||||
|
||||
|
||||
def test_batchnorm_mode_0():
|
||||
model = Sequential()
|
||||
norm_m0 = normalization.BatchNormalization(mode=0, input_shape=(10,))
|
||||
model.add(norm_m0)
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
def test_batchnorm_mode_0_or_2():
|
||||
for mode in [0, 2]:
|
||||
model = Sequential()
|
||||
norm_m0 = normalization.BatchNormalization(mode=mode, input_shape=(10,))
|
||||
model.add(norm_m0)
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 10))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
out = norm_m0.call(K.variable(X))
|
||||
out -= norm_m0.beta
|
||||
out /= norm_m0.gamma
|
||||
np_out = K.function([K.learning_phase()], [out])([1.])[0]
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 10))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
out = model.predict(X)
|
||||
out -= K.eval(norm_m0.beta)
|
||||
out /= K.eval(norm_m0.gamma)
|
||||
|
||||
assert_allclose(np_out.mean(), 0.0, atol=1e-1)
|
||||
assert_allclose(np_out.std(), 1.0, atol=1e-1)
|
||||
assert_allclose(out.mean(), 0.0, atol=1e-1)
|
||||
assert_allclose(out.std(), 1.0, atol=1e-1)
|
||||
|
||||
|
||||
def test_batchnorm_mode_0_convnet():
|
||||
@@ -51,13 +51,12 @@ def test_batchnorm_mode_0_convnet():
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 3, 4, 4))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
out = norm_m0.call(K.variable(X))
|
||||
out -= K.reshape(norm_m0.beta, (1, 3, 1, 1))
|
||||
out /= K.reshape(norm_m0.gamma, (1, 3, 1, 1))
|
||||
np_out = K.function([K.learning_phase()], [out])([1.])[0]
|
||||
out = model.predict(X)
|
||||
out -= np.reshape(K.eval(norm_m0.beta), (1, 3, 1, 1))
|
||||
out /= np.reshape(K.eval(norm_m0.gamma), (1, 3, 1, 1))
|
||||
|
||||
assert_allclose(np.mean(np_out, axis=(0, 2, 3)), 0.0, atol=1e-1)
|
||||
assert_allclose(np.std(np_out, axis=(0, 2, 3)), 1.0, atol=1e-1)
|
||||
assert_allclose(np.mean(out, axis=(0, 2, 3)), 0.0, atol=1e-1)
|
||||
assert_allclose(np.std(out, axis=(0, 2, 3)), 1.0, atol=1e-1)
|
||||
|
||||
|
||||
def test_batchnorm_mode_1():
|
||||
|
||||
@@ -32,6 +32,13 @@ def _runner(layer_class):
|
||||
'dropout_W': 0.1},
|
||||
input_shape=(3, 2, 3))
|
||||
|
||||
# check implementation modes
|
||||
for mode in ['cpu', 'mem', 'gpu']:
|
||||
layer_test(layer_class,
|
||||
kwargs={'output_dim': output_dim,
|
||||
'consume_less': mode},
|
||||
input_shape=(3, 2, 3))
|
||||
|
||||
# check statefulness
|
||||
model = Sequential()
|
||||
model.add(embeddings.Embedding(embedding_num, embedding_dim,
|
||||
|
||||
@@ -56,6 +56,22 @@ def test_softplus():
|
||||
assert_allclose(result, expected, rtol=1e-05)
|
||||
|
||||
|
||||
def test_softsign():
|
||||
'''
|
||||
Test using a reference softsign implementation
|
||||
'''
|
||||
def softsign(x):
|
||||
return np.divide(x, np.ones_like(x) + np.absolute(x))
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
f = K.function([x], [activations.softsign(x)])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
expected = softsign(test_values)
|
||||
assert_allclose(result, expected, rtol=1e-05)
|
||||
|
||||
|
||||
def test_sigmoid():
|
||||
'''
|
||||
Test using a numerically stable reference sigmoid implementation
|
||||
|
||||
@@ -105,6 +105,27 @@ def test_EarlyStopping():
|
||||
validation_data=(X_test, y_test), callbacks=cbks, nb_epoch=20)
|
||||
|
||||
|
||||
def test_EarlyStopping_reuse():
|
||||
patience = 3
|
||||
data = np.random.random((100, 1))
|
||||
labels = np.where(data > 0.5, 1, 0)
|
||||
model = Sequential((
|
||||
Dense(1, input_dim=1, activation='relu'),
|
||||
Dense(1, activation='sigmoid'),
|
||||
))
|
||||
model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['accuracy'])
|
||||
stopper = callbacks.EarlyStopping(monitor='acc', patience=patience)
|
||||
weights = model.get_weights()
|
||||
|
||||
hist = model.fit(data, labels, callbacks=[stopper])
|
||||
assert len(hist.epoch) >= patience
|
||||
|
||||
# This should allow training to go for at least `patience` epochs
|
||||
model.set_weights(weights)
|
||||
hist = model.fit(data, labels, callbacks=[stopper])
|
||||
assert len(hist.epoch) >= patience
|
||||
|
||||
|
||||
def test_LearningRateScheduler():
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=train_samples,
|
||||
nb_test=test_samples,
|
||||
|
||||
@@ -93,7 +93,7 @@ def test_1o_1i():
|
||||
assert(len(out) == 1)
|
||||
loss = graph.test_on_batch({'input1': X_test_graph, 'output1': y_test_graph})
|
||||
loss = graph.train_on_batch({'input1': X_test_graph, 'output1': y_test_graph})
|
||||
loss = graph.evaluate({'input1': X_test_graph, 'output1': y_test_graph}, verbose=0)
|
||||
loss = graph.evaluate({'input1': X_test_graph, 'output1': y_test_graph}, verbose=0)
|
||||
|
||||
# test accuracy:
|
||||
graph.compile('rmsprop', {'output1': 'mse'}, metrics=['accuracy'])
|
||||
@@ -209,7 +209,7 @@ def test_siamese_1():
|
||||
loss = graph.test_on_batch({'input1': X_test_graph, 'input2': X2_test_graph, 'output1': y_test_graph})
|
||||
loss = graph.train_on_batch({'input1': X_test_graph, 'input2': X2_test_graph, 'output1': y_test_graph})
|
||||
loss = graph.evaluate({'input1': X_test_graph, 'input2': X2_test_graph, 'output1': y_test_graph})
|
||||
assert(loss < 3.0)
|
||||
assert(loss < 5.0)
|
||||
|
||||
# test serialization
|
||||
config = graph.get_config()
|
||||
|
||||
@@ -4,8 +4,14 @@ import numpy as np
|
||||
from keras import initializations
|
||||
from keras import backend as K
|
||||
|
||||
SHAPE = (100, 100)
|
||||
# 2D tensor test fixture
|
||||
FC_SHAPE = (100, 100)
|
||||
|
||||
# 4D convolution in th order. This shape has the same effective shape as FC_SHAPE
|
||||
CONV_SHAPE = (25, 25, 2, 2)
|
||||
|
||||
# The equivalent shape of both test fixtures
|
||||
SHAPE = (100, 100)
|
||||
|
||||
def _runner(init, shape, target_mean=None, target_std=None,
|
||||
target_max=None, target_min=None):
|
||||
@@ -22,62 +28,78 @@ def _runner(init, shape, target_mean=None, target_std=None,
|
||||
assert abs(output.min() - target_min) < lim
|
||||
|
||||
|
||||
def test_uniform():
|
||||
_runner(initializations.uniform, SHAPE, target_mean=0.,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_uniform(tensor_shape):
|
||||
_runner(initializations.uniform, tensor_shape, target_mean=0.,
|
||||
target_max=0.05, target_min=-0.05)
|
||||
|
||||
|
||||
def test_normal():
|
||||
_runner(initializations.normal, SHAPE, target_mean=0., target_std=0.05)
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_normal(tensor_shape):
|
||||
_runner(initializations.normal, tensor_shape, target_mean=0., target_std=0.05)
|
||||
|
||||
|
||||
def test_lecun_uniform():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_lecun_uniform(tensor_shape):
|
||||
scale = np.sqrt(3. / SHAPE[0])
|
||||
_runner(initializations.lecun_uniform, SHAPE,
|
||||
_runner(initializations.lecun_uniform, tensor_shape,
|
||||
target_mean=0., target_max=scale, target_min=-scale)
|
||||
|
||||
|
||||
def test_glorot_uniform():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_glorot_uniform(tensor_shape):
|
||||
scale = np.sqrt(6. / (SHAPE[0] + SHAPE[1]))
|
||||
_runner(initializations.glorot_uniform, SHAPE, target_mean=0.,
|
||||
_runner(initializations.glorot_uniform, tensor_shape, target_mean=0.,
|
||||
target_max=scale, target_min=-scale)
|
||||
|
||||
|
||||
def test_glorot_normal():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_glorot_normal(tensor_shape):
|
||||
scale = np.sqrt(2. / (SHAPE[0] + SHAPE[1]))
|
||||
_runner(initializations.glorot_normal, SHAPE,
|
||||
_runner(initializations.glorot_normal, tensor_shape,
|
||||
target_mean=0., target_std=scale)
|
||||
|
||||
|
||||
def test_he_uniform():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_he_uniform(tensor_shape):
|
||||
scale = np.sqrt(6. / SHAPE[0])
|
||||
_runner(initializations.he_uniform, SHAPE, target_mean=0.,
|
||||
_runner(initializations.he_uniform, tensor_shape, target_mean=0.,
|
||||
target_max=scale, target_min=-scale)
|
||||
|
||||
|
||||
def test_he_normal():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_he_normal(tensor_shape):
|
||||
scale = np.sqrt(2. / SHAPE[0])
|
||||
_runner(initializations.he_normal, SHAPE,
|
||||
_runner(initializations.he_normal, tensor_shape,
|
||||
target_mean=0., target_std=scale)
|
||||
|
||||
|
||||
def test_orthogonal():
|
||||
_runner(initializations.orthogonal, SHAPE,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_orthogonal(tensor_shape):
|
||||
_runner(initializations.orthogonal, tensor_shape,
|
||||
target_mean=0.)
|
||||
|
||||
|
||||
def test_identity():
|
||||
_runner(initializations.identity, SHAPE,
|
||||
target_mean=1./SHAPE[0], target_max=1.)
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_identity(tensor_shape):
|
||||
if len(tensor_shape) > 2:
|
||||
with pytest.raises(Exception):
|
||||
_runner(initializations.identity, tensor_shape,
|
||||
target_mean=1./SHAPE[0], target_max=1.)
|
||||
else:
|
||||
_runner(initializations.identity, tensor_shape,
|
||||
target_mean=1./SHAPE[0], target_max=1.)
|
||||
|
||||
|
||||
def test_zero():
|
||||
_runner(initializations.zero, SHAPE,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_zero(tensor_shape):
|
||||
_runner(initializations.zero, tensor_shape,
|
||||
target_mean=0., target_max=0.)
|
||||
|
||||
|
||||
def test_one():
|
||||
_runner(initializations.one, SHAPE,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_one(tensor_shape):
|
||||
_runner(initializations.one, tensor_shape,
|
||||
target_mean=1., target_max=1.)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
from __future__ import print_function
|
||||
import pytest
|
||||
import numpy as np
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation
|
||||
|
||||
|
||||
def test_multiprocessing_training():
|
||||
|
||||
reached_end = False
|
||||
|
||||
arr_data = np.random.randint(0,256, (500, 200))
|
||||
arr_labels = np.random.randint(0, 2, 500)
|
||||
|
||||
def myGenerator():
|
||||
|
||||
batch_size = 32
|
||||
n_samples = 500
|
||||
|
||||
while True:
|
||||
batch_index = np.random.randint(0, n_samples - batch_size)
|
||||
start = batch_index
|
||||
end = start + batch_size
|
||||
X = arr_data[start: end]
|
||||
y = arr_labels[start: end]
|
||||
yield X, y
|
||||
|
||||
# Build a NN
|
||||
model = Sequential()
|
||||
model.add(Dense(10, input_shape=(200, )))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('linear'))
|
||||
model.compile(loss='mse', optimizer='adadelta')
|
||||
|
||||
model.fit_generator(myGenerator(),
|
||||
samples_per_epoch=320,
|
||||
nb_epoch=1,
|
||||
verbose=1,
|
||||
max_q_size=10,
|
||||
nb_worker=4,
|
||||
pickle_safe=True)
|
||||
|
||||
model.fit_generator(myGenerator(),
|
||||
samples_per_epoch=320,
|
||||
nb_epoch=1,
|
||||
verbose=1,
|
||||
max_q_size=10,
|
||||
pickle_safe=False)
|
||||
|
||||
reached_end = True
|
||||
|
||||
assert reached_end
|
||||
|
||||
|
||||
def test_multiprocessing_training_fromfile():
|
||||
|
||||
reached_end = False
|
||||
|
||||
arr_data = np.random.randint(0,256, (500, 200))
|
||||
arr_labels = np.random.randint(0, 2, 500)
|
||||
np.savez("data.npz", **{"data": arr_data, "labels": arr_labels})
|
||||
|
||||
def myGenerator():
|
||||
|
||||
batch_size = 32
|
||||
n_samples = 500
|
||||
|
||||
arr = np.load("data.npz")
|
||||
|
||||
while True:
|
||||
batch_index = np.random.randint(0, n_samples - batch_size)
|
||||
start = batch_index
|
||||
end = start + batch_size
|
||||
X = arr["data"][start: end]
|
||||
y = arr["labels"][start: end]
|
||||
yield X, y
|
||||
|
||||
# Build a NN
|
||||
model = Sequential()
|
||||
model.add(Dense(10, input_shape=(200, )))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('linear'))
|
||||
model.compile(loss='mse', optimizer='adadelta')
|
||||
|
||||
model.fit_generator(myGenerator(),
|
||||
samples_per_epoch=320,
|
||||
nb_epoch=1,
|
||||
verbose=1,
|
||||
max_q_size=10,
|
||||
nb_worker=2,
|
||||
pickle_safe=True)
|
||||
|
||||
model.fit_generator(myGenerator(),
|
||||
samples_per_epoch=320,
|
||||
nb_epoch=1,
|
||||
verbose=1,
|
||||
max_q_size=10,
|
||||
pickle_safe=False)
|
||||
reached_end = True
|
||||
|
||||
assert reached_end
|
||||
|
||||
|
||||
def test_multiprocessing_predicting():
|
||||
|
||||
reached_end = False
|
||||
|
||||
arr_data = np.random.randint(0,256, (500, 200))
|
||||
|
||||
def myGenerator():
|
||||
|
||||
batch_size = 32
|
||||
n_samples = 500
|
||||
|
||||
while True:
|
||||
batch_index = np.random.randint(0, n_samples - batch_size)
|
||||
start = batch_index
|
||||
end = start + batch_size
|
||||
X = arr_data[start: end]
|
||||
yield X
|
||||
|
||||
# Build a NN
|
||||
model = Sequential()
|
||||
model.add(Dense(10, input_shape=(200, )))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('linear'))
|
||||
model.compile(loss='mse', optimizer='adadelta')
|
||||
model.predict_generator(myGenerator(),
|
||||
val_samples=320,
|
||||
max_q_size=10,
|
||||
nb_worker=2,
|
||||
pickle_safe=True)
|
||||
model.predict_generator(myGenerator(),
|
||||
val_samples=320,
|
||||
max_q_size=10,
|
||||
pickle_safe=False)
|
||||
reached_end = True
|
||||
|
||||
assert reached_end
|
||||
|
||||
|
||||
def test_multiprocessing_evaluating():
|
||||
|
||||
reached_end = False
|
||||
|
||||
arr_data = np.random.randint(0,256, (500, 200))
|
||||
arr_labels = np.random.randint(0, 2, 500)
|
||||
|
||||
def myGenerator():
|
||||
|
||||
batch_size = 32
|
||||
n_samples = 500
|
||||
|
||||
while True:
|
||||
batch_index = np.random.randint(0, n_samples - batch_size)
|
||||
start = batch_index
|
||||
end = start + batch_size
|
||||
X = arr_data[start: end]
|
||||
y = arr_labels[start: end]
|
||||
yield X, y
|
||||
|
||||
# Build a NN
|
||||
model = Sequential()
|
||||
model.add(Dense(10, input_shape=(200, )))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('linear'))
|
||||
model.compile(loss='mse', optimizer='adadelta')
|
||||
|
||||
model.evaluate_generator(myGenerator(),
|
||||
val_samples=320,
|
||||
max_q_size=10,
|
||||
nb_worker=2,
|
||||
pickle_safe=True)
|
||||
model.evaluate_generator(myGenerator(),
|
||||
val_samples=320,
|
||||
max_q_size=10,
|
||||
pickle_safe=False)
|
||||
reached_end = True
|
||||
|
||||
assert reached_end
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
pytest.main([__file__])
|
||||
@@ -12,6 +12,7 @@ allobj = [objectives.mean_squared_error,
|
||||
objectives.squared_hinge,
|
||||
objectives.hinge, objectives.categorical_crossentropy,
|
||||
objectives.binary_crossentropy,
|
||||
objectives.kullback_leibler_divergence,
|
||||
objectives.poisson,
|
||||
objectives.cosine_proximity]
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ from __future__ import print_function
|
||||
import pytest
|
||||
|
||||
from keras.utils.test_utils import get_test_data
|
||||
from keras.optimizers import SGD, RMSprop, Adagrad, Adadelta, Adam, Adamax
|
||||
from keras.optimizers import SGD, RMSprop, Adagrad, Adadelta, Adam, Adamax, Nadam
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.utils.np_utils import to_categorical
|
||||
@@ -26,7 +26,7 @@ def get_model(input_dim, nb_hidden, output_dim):
|
||||
return model
|
||||
|
||||
|
||||
def _test_optimizer(optimizer, target=0.9):
|
||||
def _test_optimizer(optimizer, target=0.89):
|
||||
model = get_model(X_train.shape[1], 10, y_train.shape[1])
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer=optimizer,
|
||||
@@ -35,7 +35,7 @@ def _test_optimizer(optimizer, target=0.9):
|
||||
validation_data=(X_test, y_test), verbose=2)
|
||||
config = optimizer.get_config()
|
||||
assert type(config) == dict
|
||||
assert history.history['val_acc'][-1] > target
|
||||
assert history.history['val_acc'][-1] >= target
|
||||
|
||||
|
||||
def test_sgd():
|
||||
@@ -63,5 +63,9 @@ def test_adamax():
|
||||
_test_optimizer(Adamax())
|
||||
|
||||
|
||||
def test_nadam():
|
||||
_test_optimizer(Nadam())
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -51,6 +51,15 @@ def create_model(weight_reg=None, activity_reg=None):
|
||||
return model
|
||||
|
||||
|
||||
def test_Eigenvalue_reg():
|
||||
(X_train, Y_train), (X_test, Y_test), test_ids = get_data()
|
||||
reg = regularizers.EigenvalueRegularizer(0.01)
|
||||
model = create_model(weight_reg=reg)
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.evaluate(X_test[test_ids, :], Y_test[test_ids, :], verbose=0)
|
||||
|
||||
|
||||
def test_W_reg():
|
||||
(X_train, Y_train), (X_test, Y_test), test_ids = get_data()
|
||||
for reg in [regularizers.l1(),
|
||||
|
||||
@@ -59,6 +59,8 @@ def test_sequential_fit_generator():
|
||||
model.add(Dense(nb_hidden, input_shape=(input_dim,)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(nb_class))
|
||||
model.pop()
|
||||
model.add(Dense(nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
|
||||
@@ -10,16 +10,16 @@ from keras import backend as K
|
||||
|
||||
def test_masking():
|
||||
np.random.seed(1337)
|
||||
X = np.array(
|
||||
[[[1, 1], [2, 1], [3, 1], [5, 5]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]], dtype=np.int32)
|
||||
X = np.array([[[1], [1]],
|
||||
[[0], [0]]])
|
||||
model = Sequential()
|
||||
model.add(Masking(mask_value=0, input_shape=(4, 2)))
|
||||
model.add(Masking(mask_value=0, input_shape=(2, 1)))
|
||||
model.add(TimeDistributedDense(1, init='one'))
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
y = model.predict(X)
|
||||
history = model.fit(X, 4 * y, nb_epoch=1, batch_size=2, verbose=1)
|
||||
assert history.history['loss'][0] == 285.
|
||||
y = np.array([[[1], [1]],
|
||||
[[1], [1]]])
|
||||
loss = model.train_on_batch(X, y)
|
||||
assert loss == 0
|
||||
|
||||
|
||||
def test_loss_masking():
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário