Comparar commits
346 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 6a4aab453f | |||
| 46e19b95d8 | |||
| 8824f1b469 | |||
| 43d84368c6 | |||
| 08abc317f2 | |||
| 036d968ad6 | |||
| 510068b83e | |||
| 43736166a4 | |||
| 9e25669843 | |||
| 12eba1333a | |||
| 6336567c84 | |||
| a3ebda96c3 | |||
| 37fe48b744 | |||
| fd1d5908c6 | |||
| 08b1964b77 | |||
| 6a0bf4833b | |||
| 7af168d81a | |||
| 5998b5dcff | |||
| af845d55a4 | |||
| 200a006262 | |||
| 705694a870 | |||
| 7da91d94ef | |||
| 2b7a3cbaa9 | |||
| c90f98eaec | |||
| 6c695493c9 | |||
| eef82c486a | |||
| 53331e43c2 | |||
| 94c930e99e | |||
| 2d0e84a857 | |||
| c8a2f46f79 | |||
| 6899a9db16 | |||
| 238d390932 | |||
| 22bd7cfab6 | |||
| 2603fa37d2 | |||
| 319e18ad8f | |||
| 848e1fb5c5 | |||
| 38c4cb2ac2 | |||
| 493e6d2852 | |||
| 03e512a3f4 | |||
| a3dadff38f | |||
| 65ebd8aa6a | |||
| 9f71949d6d | |||
| 0bf62784cb | |||
| afc5adbfe1 | |||
| 94d857f3cb | |||
| d77175fb2e | |||
| f142d34ffc | |||
| ca22bb7db5 | |||
| 3909e783b9 | |||
| 46f591d4bb | |||
| 472f8ba94b | |||
| 5bf2718580 | |||
| 9a649d2b27 | |||
| c06b746704 | |||
| b4c62ffbab | |||
| 5cbe62c248 | |||
| f0aedaf4e8 | |||
| 1bfbb33c0d | |||
| bc05a25b1b | |||
| 1e73e1bc54 | |||
| 07f2253ff2 | |||
| f817e2e71c | |||
| 4b07e77828 | |||
| c0a44daabc | |||
| 7ff158de41 | |||
| 8213e515d3 | |||
| c353dfc5f9 | |||
| 0cae63accb | |||
| 5ed7f78b42 | |||
| c354b9be5c | |||
| df331cc5e0 | |||
| 14b014883a | |||
| 7094be1b44 | |||
| d4f39c8f53 | |||
| 337f39bd02 | |||
| 7c8d9aaf6b | |||
| 6c55dbd6d5 | |||
| ab8f7da83f | |||
| 1f21e61a40 | |||
| 16f737ffc2 | |||
| 1fe6556ab8 | |||
| aeb954dd49 | |||
| 35bcd5a45a | |||
| b1d9448908 | |||
| fe3c4d73eb | |||
| c315b0d7a9 | |||
| ddd5f47640 | |||
| 63f9a7955d | |||
| 8995b50a96 | |||
| e014b9435f | |||
| b22e547e98 | |||
| 8bd8ae1daa | |||
| 1530f31c1d | |||
| f2c97d817b | |||
| 53a05b6e4c | |||
| dab55518ba | |||
| be75548ca3 | |||
| 32f483fe33 | |||
| 553a7c0265 | |||
| 60daee5674 | |||
| 47fd945cf1 | |||
| 66b8f37175 | |||
| f1cd436574 | |||
| f30223096e | |||
| 76b9877ccb | |||
| 243d4737d1 | |||
| 9e4e432822 | |||
| c7c5372509 | |||
| 2baa9a8e57 | |||
| e63644cf82 | |||
| af0899ded7 | |||
| a5f4bd33c9 | |||
| 522201ec9e | |||
| 506aaf1721 | |||
| 8e1e32a906 | |||
| 0332b95cdf | |||
| f53c3195e7 | |||
| 940bd47bc9 | |||
| ee730496ee | |||
| 06d7c7dab2 | |||
| 91d86c355b | |||
| 98f055074c | |||
| bba5379305 | |||
| acef252703 | |||
| 514ac06c2e | |||
| f184db8c53 | |||
| d59f2519fa | |||
| 4956ed9e97 | |||
| b48e39aafd | |||
| a808ae6ff8 | |||
| 2805413653 | |||
| 2d5b86d7a8 | |||
| 12a5c6fe46 | |||
| e50462e71f | |||
| 2f98bed389 | |||
| 24be9eb88b | |||
| e15f722558 | |||
| c9fd2c8a8c | |||
| 42497d9fda | |||
| 278618281c | |||
| 4ae4c9c8df | |||
| 89ad3c726c | |||
| 3af4d2fd33 | |||
| a4329aa4b0 | |||
| 24df6a9f9b | |||
| 560cb94519 | |||
| 2ab9f0ef61 | |||
| d148ff11c2 | |||
| 256a908250 | |||
| 11d3335dcc | |||
| 1b7ce160e2 | |||
| c7aac3ce39 | |||
| 7e06995678 | |||
| ce659e568b | |||
| e8a6ae298d | |||
| e3d3d62218 | |||
| 877d44740c | |||
| cc9edcf472 | |||
| 5e5bff0510 | |||
| bc4e47e689 | |||
| d9357646e2 | |||
| c4735f59c4 | |||
| 3af40ba584 | |||
| 36e5a17b29 | |||
| cbde35fdf5 | |||
| 76b28524d1 | |||
| 090ada4e77 | |||
| 8ef90a03b3 | |||
| f04fdec9e6 | |||
| 0d6575c7f9 | |||
| cc750adf60 | |||
| 752037c140 | |||
| ba11d9ca75 | |||
| 499a05003b | |||
| c9addefa28 | |||
| 0f12e0119b | |||
| 4d267f5ba3 | |||
| 5719322573 | |||
| 5b6f56a040 | |||
| 3e08814118 | |||
| 9c8e0d43f3 | |||
| ea0b7d263c | |||
| 99c20e25c9 | |||
| 2abb4b2316 | |||
| 0d6c55d5f0 | |||
| 45e444cc63 | |||
| 5d1976c46d | |||
| 3ff19e2a62 | |||
| 95a363f3d8 | |||
| 3995b18f43 | |||
| d57206dfd9 | |||
| 71787762db | |||
| da20a4ccd2 | |||
| 90c4edefd3 | |||
| ad99af7be7 | |||
| aaceb11b9e | |||
| 7d7085d523 | |||
| 33ca877821 | |||
| 15055483ff | |||
| c3d90020fc | |||
| ed8448df7b | |||
| 81822d3e52 | |||
| 7a6cec902e | |||
| 37e3ffed85 | |||
| 7fafc8ec9d | |||
| 91aa190ceb | |||
| 4eb8346df5 | |||
| 9083dd088d | |||
| 4e78c9e758 | |||
| 93ff2240f3 | |||
| 867253e5d8 | |||
| 31a303c38f | |||
| e1a39b80a9 | |||
| 1564343c6e | |||
| 62392a4b5e | |||
| 11685f68d5 | |||
| b4c7aded69 | |||
| 182c827433 | |||
| 59e345501e | |||
| 56e09ad736 | |||
| 4d39c08c42 | |||
| 4962f18857 | |||
| 11e961fdf8 | |||
| 413663f03f | |||
| 433f56f35d | |||
| 6420c59f1b | |||
| c35780557e | |||
| 4ba83caef2 | |||
| 13715c49c3 | |||
| 7ef71ec944 | |||
| 4e19cd29c9 | |||
| 1d02231a49 | |||
| 333e85f6b1 | |||
| 6d82ba75c9 | |||
| 135dccfeea | |||
| 4c5f8e364c | |||
| 515c430f43 | |||
| 8a2ae93ba7 | |||
| 4c3495896e | |||
| 86a9445ffd | |||
| 271e2b7f84 | |||
| ce6728d9ce | |||
| 85c915bd7e | |||
| 2603b95c8c | |||
| d9e76bdeca | |||
| 28285ceda7 | |||
| be22591e32 | |||
| a9f94c94a7 | |||
| 155369711c | |||
| 3dd4b2e8ab | |||
| a1912b0774 | |||
| 99cdd12bf7 | |||
| 2384aa4c97 | |||
| b9fbc458ed | |||
| e3519221b4 | |||
| 3f3a1f0e9b | |||
| 852f5d977f | |||
| a1ab9769ec | |||
| ef4250fc05 | |||
| 76328bedd1 | |||
| f8ee81d89e | |||
| 83419e644f | |||
| c274cb990b | |||
| b0b3ff13b0 | |||
| 384634d321 | |||
| 3e0b09e819 | |||
| e0f58c976b | |||
| dd82a3944e | |||
| 9763f81185 | |||
| ae13539a88 | |||
| cbcb3b96ef | |||
| 0a21abc810 | |||
| 1fc3c4b22e | |||
| 5a1a00e69e | |||
| 97f23268c2 | |||
| fd5b68dbe3 | |||
| ac0a9db039 | |||
| 1d586440a8 | |||
| b44ecab225 | |||
| 34cbc1d401 | |||
| 0e6fd3d306 | |||
| ccbe381dcd | |||
| 1f224de9b1 | |||
| e23e86ae7a | |||
| 06f22db69a | |||
| 824f9f5e80 | |||
| a12510ba97 | |||
| c13154933e | |||
| 981d23a66e | |||
| 7278db105d | |||
| 1b9f35f535 | |||
| c4f0f8b394 | |||
| d7a612bb8c | |||
| a8f1a6a11b | |||
| bde9ff8232 | |||
| 32c507eaf8 | |||
| 36676451c9 | |||
| e369559170 | |||
| 7f445d9a21 | |||
| 4cc03dd4ef | |||
| 2727198f94 | |||
| 88b0c8e067 | |||
| a75a31381e | |||
| d550232458 | |||
| 6329378ca3 | |||
| b3402f5011 | |||
| 4cfb5d7971 | |||
| a51d7ae145 | |||
| bd361595be | |||
| 668eeebdda | |||
| cf49d59aff | |||
| 31a6ee342b | |||
| fecedb02cf | |||
| 8e5cdd1689 | |||
| 45775e36b1 | |||
| 4830b4be27 | |||
| 702e9d3bec | |||
| 1857a6af5e | |||
| 4b065a28a0 | |||
| 33334883fa | |||
| 2165fd03dc | |||
| 872a9faf18 | |||
| d2b229df2e | |||
| 35c2f36759 | |||
| 24d735ecb1 | |||
| 8c93ba860a | |||
| bf4822f675 | |||
| ed6e351953 | |||
| 368ad61236 | |||
| 829b7ab289 | |||
| ce20955379 | |||
| fabfdb868e | |||
| b82ab804da | |||
| 0a10e20959 | |||
| ffeefb2a1b | |||
| eb33c9a18c | |||
| 39f05c3436 | |||
| c0b7044ce6 | |||
| bde147ce3a | |||
| d6eb8a47d7 | |||
| 206f29ea6e | |||
| a6824931e4 | |||
| 7bcc4cb257 | |||
| a4af21d588 | |||
| 12f7f374c3 | |||
| f4df2240c1 |
+5
-1
@@ -1,6 +1,10 @@
|
||||
*.DS_Store
|
||||
*.pyc
|
||||
*.swp
|
||||
temp/*
|
||||
dist/*
|
||||
build/*
|
||||
keras/datasets/data/*
|
||||
keras/datasets/temp/*
|
||||
keras/datasets/temp/*
|
||||
docs/site/*
|
||||
docs/theme/*
|
||||
@@ -0,0 +1,20 @@
|
||||
language: python
|
||||
# Setup anaconda
|
||||
before_install:
|
||||
- wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh
|
||||
- chmod +x miniconda.sh
|
||||
- ./miniconda.sh -b
|
||||
- export PATH=/home/travis/miniconda/bin:$PATH
|
||||
- conda update --yes conda
|
||||
# The next couple lines fix a crash with multiprocessing on Travis and are not specific to using Miniconda
|
||||
- sudo rm -rf /dev/shm
|
||||
- sudo ln -s /run/shm /dev/shm
|
||||
python:
|
||||
- "3.4"
|
||||
# command to install dependencies
|
||||
install:
|
||||
- conda install --yes python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib pandas pytest
|
||||
# Coverage packages are on my binstar channel
|
||||
- python setup.py install
|
||||
# command to run tests
|
||||
script: py.test
|
||||
+30
-32
@@ -1,43 +1,41 @@
|
||||
site_name: Keras Documentation
|
||||
theme: readthedocs
|
||||
#theme: readthedocs
|
||||
docs_dir: sources
|
||||
repo_url: http://github.com/fchollet/keras
|
||||
site_url: /
|
||||
#theme_dir: theme
|
||||
site_url: http://keras.io/
|
||||
theme_dir: theme
|
||||
site_description: Documentation for fast and lightweight Keras Deep Learning library.
|
||||
include_404: true
|
||||
include_search: true
|
||||
|
||||
dev_addr: '0.0.0.0:8000'
|
||||
google_analytics: ['UA-61785484-1', 'keras.io']
|
||||
|
||||
|
||||
pages:
|
||||
- [index.md, Home]
|
||||
- [documentation.md, Index]
|
||||
- Home: index.md
|
||||
- Index: documentation.md
|
||||
- Examples: examples.md
|
||||
- Optimizers: optimizers.md
|
||||
- Objectives: objectives.md
|
||||
- Models: models.md
|
||||
- Activations: activations.md
|
||||
- Initializations: initializations.md
|
||||
- Regularizers: regularizers.md
|
||||
- Constraints: constraints.md
|
||||
- Callbacks: callbacks.md
|
||||
- Datasets: datasets.md
|
||||
- Layers:
|
||||
- Core Layers: layers/core.md
|
||||
- Convolutional Layers: layers/convolutional.md
|
||||
- Recurrent Layers: layers/recurrent.md
|
||||
- Advanced Activations Layers: layers/advanced_activations.md
|
||||
- Normalization Layers: layers/normalization.md
|
||||
- Embedding Layers: layers/embeddings.md
|
||||
- Noise layers: layers/noise.md
|
||||
- Containers: layers/containers.md
|
||||
- Preprocessing:
|
||||
- Sequence Preprocessing: preprocessing/sequence.md
|
||||
- Text Preprocessing: preprocessing/text.md
|
||||
- Image Preprocessing: preprocessing/image.md
|
||||
- Utils:
|
||||
- Visualization Utilities: utils/visualization.md
|
||||
|
||||
- [examples.md, Examples]
|
||||
- [optimizers.md, Optimizers]
|
||||
- [objectives.md, Objectives]
|
||||
- [models.md, Models]
|
||||
- [activations.md, Activations]
|
||||
- [initializations.md, Initializations]
|
||||
- [regularizers.md, Regularizers]
|
||||
- [constraints.md, Constraints]
|
||||
- [callbacks.md, Callbacks]
|
||||
|
||||
- [datasets.md, Datasets]
|
||||
|
||||
- [layers/core.md, Layers, Core Layers]
|
||||
- [layers/convolutional.md, Layers, Convolutional Layers]
|
||||
- [layers/recurrent.md, Layers, Recurrent Layers]
|
||||
- [layers/advanced_activations.md, Layers, Advanced Activations Layers]
|
||||
- [layers/normalization.md, Layers, Normalization Layers]
|
||||
- [layers/embeddings.md, Layers, Embedding Layers]
|
||||
- [layers/containers.md, Layers, Containers]
|
||||
|
||||
- [preprocessing/sequence.md, Preprocessing, Sequence Preprocessing]
|
||||
- [preprocessing/text.md, Preprocessing, Text Preprocessing]
|
||||
- [preprocessing/image.md, Preprocessing, Image Preprocessing]
|
||||
|
||||
- [utils/visualization.md, Utils, Visualization Utilities]
|
||||
|
||||
@@ -26,8 +26,7 @@ model.add(Activation(tanh))
|
||||
|
||||
## Available activations
|
||||
|
||||
- __softmax__: Should only be applied to 2D layers (expected shape: `(nb_samples, nb_dims)`).
|
||||
- __time_distributed_softmax__: Softmax applied to every sample at every timestep of a layer of shape `(nb_samples, nb_timesteps, nb_dims)`.
|
||||
- __softmax__: Softmax applied across inputs last dimension. Expects shape either `(nb_samples, nb_timesteps, nb_dims)` or `(nb_samples, nb_dims)`.
|
||||
- __softplus__
|
||||
- __relu__
|
||||
- __tanh__
|
||||
@@ -37,4 +36,4 @@ model.add(Activation(tanh))
|
||||
|
||||
## On Advanced Activations
|
||||
|
||||
Activations that are more complex than a simple Theano function (eg. learnable activations, configurable activations, etc.) are available as [Advanced Activation layers](layers/advanced_activations.md), and can be found in the module `keras.layers.advanced_activations`. These include PReLU and LeakyReLU.
|
||||
Activations that are more complex than a simple Theano function (eg. learnable activations, configurable activations, etc.) are available as [Advanced Activation layers](layers/advanced_activations.md), and can be found in the module `keras.layers.advanced_activations`. These include PReLU and LeakyReLU.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
## Usage of callbacks
|
||||
|
||||
A callback is a set of functions to be applied at given stages of the training procedure. You can use callbacks to get a view on internal states and statistics of the model during training. You can pass a list of callback (as the keyword argument `callbacks`) to the `.fit()` method of the `Sequential` model. The relevant methods of the callbacks will then be called at each stage of the training.
|
||||
A callback is a set of functions to be applied at given stages of the training procedure. You can use callbacks to get a view on internal states and statistics of the model during training. You can pass a list of callbacks (as the keyword argument `callbacks`) to the `.fit()` method of the `Sequential` model. The relevant methods of the callbacks will then be called at each stage of the training.
|
||||
|
||||
---
|
||||
|
||||
@@ -27,6 +27,23 @@ The `logs` dictionary will contain keys for quantities relevant to the current b
|
||||
|
||||
---
|
||||
|
||||
## Available callbacks
|
||||
|
||||
```python
|
||||
keras.callbacks.ModelCheckpoint(filepath, verbose=0, save_best_only=False)
|
||||
```
|
||||
|
||||
Save the model after every epoch. If `save_best_only=True`, the latest best model according to the validation loss will not be overwritten.
|
||||
|
||||
|
||||
```python
|
||||
keras.callbacks.EarlyStopping(monitor='val_loss', patience=0, verbose=0)
|
||||
```
|
||||
|
||||
Stop training after no improvement of the metric `monitor` is seen for `patience` epochs.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Create a callback
|
||||
|
||||
@@ -44,11 +61,11 @@ class LossHistory(keras.callbacks.Callback):
|
||||
|
||||
---
|
||||
|
||||
### Example to record the loss history
|
||||
### Example: recording loss history
|
||||
|
||||
```python
|
||||
class LossHistory(keras.callbacks.Callback):
|
||||
def on_train_begin(self):
|
||||
def on_train_begin(self, logs={}):
|
||||
self.losses = []
|
||||
|
||||
def on_batch_end(self, batch, logs={}):
|
||||
@@ -71,7 +88,7 @@ print history.losses
|
||||
|
||||
---
|
||||
|
||||
### Example to checkpoint models
|
||||
### Example: model checkpoints
|
||||
|
||||
```python
|
||||
from keras.callbacks import ModelCheckpoint
|
||||
|
||||
@@ -2,9 +2,12 @@
|
||||
|
||||
Functions from the `constraints` module allow setting constraints (eg. non-negativity) on network parameters during optimization.
|
||||
|
||||
The keyword arguments used for passing constraints to parameters in a layer will depend on the layer.
|
||||
The penalties are applied on a per-layer basis. The exact API will depend on the layer, but the layers `Dense`, `TimeDistributedDense`, `MaxoutDense`, `Convolution1D` and `Convolution2D` have a unified API.
|
||||
|
||||
In the `Dense` layer it is simply `W_constraint` for the main weights matrix, and `b_constraint` for the bias.
|
||||
These layers expose 2 keyword arguments:
|
||||
|
||||
- `W_constraint` for the main weights matrix
|
||||
- `b_constraint` for the bias.
|
||||
|
||||
|
||||
```python
|
||||
|
||||
@@ -15,6 +15,9 @@
|
||||
- [Models](models.md)
|
||||
- [Activations](activations.md)
|
||||
- [Initializations](initializations.md)
|
||||
- [Regularizers](regularizers.md)
|
||||
- [Constraints](constraints.md)
|
||||
- [Callbacks](callbacks.md)
|
||||
- [Datasets](datasets.md)
|
||||
|
||||
---
|
||||
@@ -33,3 +36,8 @@
|
||||
- [Sequence](preprocessing/sequence.md)
|
||||
- [Text](preprocessing/text.md)
|
||||
- [Image](preprocessing/image.md)
|
||||
|
||||
---
|
||||
|
||||
## Utils
|
||||
- [Visualization](utils/visualization.md)
|
||||
@@ -35,7 +35,7 @@ model.add(Dense(20, 64, init='uniform', activation='tanh'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(64, 64, init='uniform', activation='tanh'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(64, 2, init='uniform', activation='softmax')
|
||||
model.add(Dense(64, 2, init='uniform', activation='softmax'))
|
||||
|
||||
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
model.compile(loss='mean_squared_error', optimizer=sgd)
|
||||
@@ -92,6 +92,7 @@ from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM
|
||||
|
||||
model = Sequential()
|
||||
# Add a mask_zero=True to the Embedding connstructor if 0 is a left-padding value in your data
|
||||
model.add(Embedding(max_features, 256))
|
||||
model.add(LSTM(256, 128, activation='sigmoid', inner_activation='hard_sigmoid'))
|
||||
model.add(Dropout(0.5))
|
||||
@@ -106,8 +107,9 @@ score = model.evaluate(X_test, Y_test, batch_size=16)
|
||||
|
||||
---
|
||||
|
||||
### Architecture for learning image captions with a convnet and a Gated Recurrent Unit
|
||||
(word-level embedding, caption of maximum length 16 words).
|
||||
### Image captioning
|
||||
|
||||
Architecture for learning image captions with a convnet and a Gated Recurrent Unit (word-level embedding, caption of maximum length 16 words).
|
||||
|
||||
Note that getting this to actually "work" will require using a bigger convnet, initialized with pre-trained weights.
|
||||
Displaying readable results will also require an embedding decoder.
|
||||
|
||||
+18
-16
@@ -2,7 +2,7 @@
|
||||
|
||||
## Overview
|
||||
|
||||
Keras is a minimalist, highly modular neural network library in the spirit of Torch, written in Python, that uses [Theano](http://deeplearning.net/software/theano/) under the hood for fast tensor manipulation on GPU and CPU. It was developed with a focus on enabling fast experimentation.
|
||||
Keras is a minimalist, highly modular neural network library in the spirit of Torch, written in Python, that uses [Theano](http://deeplearning.net/software/theano/) under the hood for optimized tensor manipulation on GPU and CPU. It was developed with a focus on enabling fast experimentation.
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
|
||||
@@ -12,13 +12,13 @@ Use Keras if you need a deep learning library that:
|
||||
|
||||
## Guiding principles
|
||||
|
||||
- __Modularity.__ A model is understood as a sequence of standalone, fully-configurable modules that can be plugged together with as little restrictions as possible. In particular, neural layers, cost functions, optimizers, initialization schemes, activation functions and dropout are all standalone modules that you can combine to create new models.
|
||||
- __Modularity.__ A model is understood as a sequence or a graph of standalone, fully-configurable modules that can be plugged together with as little restrictions as possible. In particular, neural layers, cost functions, optimizers, initialization schemes, activation functions, regularization schemes are all standalone modules that you can combine to create new models.
|
||||
|
||||
- __Minimalism.__ Each module should be kept short and simple (<100 lines of code). Every piece of code should be transparent upon first reading. No black magic: it hurts iteration speed and ability to innovate.
|
||||
- __Minimalism.__ Each module should be kept short and simple (<100 lines of code). Every piece of code should be transparent upon first reading. No black magic: it hurts iteration speed and ability to innovate.
|
||||
|
||||
- __Easy extensibility.__ A new feature (a new module, per the above definition, or a new way to combine modules together) are dead simple to add (as new classes/functions), and existing modules provide ample examples.
|
||||
- __Easy extensibility.__ New modules are dead simple to add (as new classes/functions), and existing modules provide ample examples. To be able to easily create new modules allows for total expressiveness, making Keras suitable for adavanced research.
|
||||
|
||||
- __Work with Python__. No separate models configuration files in a declarative format (like in Caffe or PyLearn2). Models are described in Python code, which is compact, easier to debug, benefits from syntax highlighting, and most of all, allows for ease of extensibility.
|
||||
- __Work with Python__. No separate models configuration files in a declarative format (like in Caffe or PyLearn2). Models are described in Python code, which is compact, easier to debug, and allows for ease of extensibility.
|
||||
|
||||
## Code
|
||||
|
||||
@@ -30,7 +30,9 @@ Keras is licensed under the [MIT license](http://opensource.org/licenses/MIT).
|
||||
|
||||
## Getting started: 30 seconds to Keras
|
||||
|
||||
The core datastructure of Keras is a __model__, a way to organize layers. Here's a sequential model (a linear pile of layers).
|
||||
The core datastructure of Keras is a __model__, a way to organize layers. There are two types of models: [`Sequential`](/models/#sequential) and [`Graph`](/models/#graph).
|
||||
|
||||
Here's the `Sequential` model (a linear pile of layers):
|
||||
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
@@ -43,9 +45,9 @@ Stacking layers is as easy as `.add()`:
|
||||
```python
|
||||
from keras.layers.core import Dense, Activation
|
||||
|
||||
model.add(Dense(input_dim=100, output_dim=64, init="uniform"))
|
||||
model.add(Dense(input_dim=100, output_dim=64, init="glorot_uniform"))
|
||||
model.add(Activation("relu"))
|
||||
model.add(Dense(input_dim=64, output_dim=10, init="uniform"))
|
||||
model.add(Dense(input_dim=64, output_dim=10, init="glorot_uniform"))
|
||||
model.add(Activation("softmax"))
|
||||
```
|
||||
|
||||
@@ -67,7 +69,7 @@ model.fit(X_train, Y_train, nb_epoch=5, batch_size=32)
|
||||
|
||||
Alternatively, you can feed batches to your model manually:
|
||||
```python
|
||||
model.train(X_batch, Y_batch)
|
||||
model.train_on_batch(X_batch, Y_batch)
|
||||
```
|
||||
|
||||
Evaluate your performance in one line:
|
||||
@@ -81,7 +83,7 @@ classes = model.predict_classes(X_test, batch_size=32)
|
||||
proba = model.predict_proba(X_test, batch_size=32)
|
||||
```
|
||||
|
||||
Building a network of LSTMs, a deep CNN, a word2vec embedder or any other model is just as fast. The ideas behind deep learning are simple, so why should their implementation be painful?
|
||||
Building a network of LSTMs, a deep CNN, a Neural Turing Machine, a word2vec embedder or any other model is just as fast. The ideas behind deep learning are simple, so why should their implementation be painful?
|
||||
|
||||
Have a look at the [examples](examples.md).
|
||||
|
||||
@@ -89,11 +91,11 @@ Have a look at the [examples](examples.md).
|
||||
|
||||
Keras uses the following dependencies:
|
||||
|
||||
- numpy, scipy
|
||||
- Theano
|
||||
- __numpy__, __scipy__
|
||||
- __Theano__
|
||||
- See [installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
- HDF5 and h5py (optional, required if you use model saving/loading functions)
|
||||
- Optional but recommended if you use CNNs: cuDNN.
|
||||
- __HDF5__ and __h5py__ (optional, required if you use model saving/loading functions)
|
||||
- Optional but recommended if you use CNNs: __cuDNN__.
|
||||
|
||||
Once you have the dependencies installed, clone the repo:
|
||||
```bash
|
||||
@@ -116,7 +118,7 @@ Keras welcomes all contributions from the community.
|
||||
- Keep a pragmatic mindset and avoid bloat. Only add to the source if that is the only path forward.
|
||||
- New features should be documented. Make sure you update the documentation along with your Pull Request.
|
||||
- The documentation for every new feature should include a usage example in the form of a code snippet.
|
||||
- All changes should be tested. A formal test process will be introduced very soon.
|
||||
- All changes should be tested. Make sure any new feature you add has a corresponding unit test.
|
||||
- Even if you don't contribute to the Keras source code, if you have an application of Keras that is concise and powerful, please consider adding it to our collection of [examples](https://github.com/fchollet/keras/tree/master/examples).
|
||||
|
||||
|
||||
@@ -124,7 +126,7 @@ Keras welcomes all contributions from the community.
|
||||
|
||||
Keras (κέρας) means _horn_ in Greek. It is a reference to a literary image from ancient Greek and Latin literature, first found in the _Odyssey_, where dream spirits (_Oneiroi_, singular _Oneiros_) are divided between those who deceive men with false visions, who arrive to Earth through a gate of ivory, and those who announce a future that will come to pass, who arrive through a gate of horn. It's a play on the words κέρας (horn) / κραίνω (fulfill), and ἐλέφας (ivory) / ἐλεφαίρομαι (deceive).
|
||||
|
||||
Keras was developed as part of the research effort of project ONEIROS (Open-ended Neuro-Electronic Intelligent Robot Operating System).
|
||||
Keras was developed as part of the research effort of project __ONEIROS__ (*Open-ended Neuro-Electronic Intelligent Robot Operating System*).
|
||||
|
||||
> _"Oneiroi are beyond our unravelling --who can be sure what tale they tell? Not all that men look for comes to pass. Two gates there are that give passage to fleeting Oneiroi; one is made of horn, one of ivory. The Oneiroi that pass through sawn ivory are deceitful, bearing a message that will not be fulfilled; those that come out through polished horn have truth behind them, to be accomplished for men who see them."_
|
||||
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
# Initializations
|
||||
|
||||
## Usage of initializations
|
||||
|
||||
@@ -15,6 +14,7 @@ model.add(Dense(64, 64, init='uniform'))
|
||||
- __uniform__
|
||||
- __lecun_uniform__: Uniform initialization scaled by the square root of the number of inputs (LeCun 98).
|
||||
- __normal__
|
||||
- __identity__: Use with square 2D layers (`shape[0] == shape[1]`).
|
||||
- __orthogonal__: Use with square 2D layers (`shape[0] == shape[1]`).
|
||||
- __zero__
|
||||
- __glorot_normal__: Gaussian initialization scaled by fan_in + fan_out (Glorot 2010)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
# Containers
|
||||
|
||||
Containers are ensembles of layers that can be interacted with through the same API as `Layer` objects.
|
||||
|
||||
## Sequential
|
||||
|
||||
@@ -1,13 +1,89 @@
|
||||
|
||||
## Convolution1D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.Convolution1D(input_dim, nb_filter, filter_length,
|
||||
init='uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample_length=1,
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None,
|
||||
b_constraint=None)
|
||||
```
|
||||
|
||||
Convolution operator for filtering neighborhoods of one-dimensional inputs.
|
||||
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, steps, input_dim)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(nb_samples, steps, nb_filter)`. `steps` value might have changed due to padding.
|
||||
|
||||
- __Arguments__:
|
||||
- __input_dim__: Number of channels/dimensions in the input.
|
||||
- __nb_filter__: Number of convolution kernels to use (dimensionality of the output).
|
||||
- __filter_length__: The extension (spatial or temporal) of each filter.
|
||||
- __init__: name of initialization function for the weights of the layer (see: [initializations](../initializations.md)), or alternatively, Theano function to use for weights initialization. This parameter is only relevant if you don't pass a `weights` argument.
|
||||
- __activation__: name of activation function to use (see: [activations](../activations.md)), or alternatively, elementwise Theano function. If you don't specify anything, no activation is applied (ie. "linear" activation: a(x) = x).
|
||||
- __weights__: list of numpy arrays to set as initial weights.
|
||||
- __border_mode__: 'valid' or 'full'. see scipy.signal.convolve2d.
|
||||
- __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.
|
||||
|
||||
---
|
||||
|
||||
## Convolution2D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.Convolution2D(nb_filter, stack_size, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
image_shape=None, border_mode='valid', subsample=(1,1))
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None)
|
||||
```
|
||||
|
||||
This is a wrapper for Theano's [conv2d](http://deeplearning.net/software/theano/library/tensor/nnet/conv.html#theano.tensor.nnet.conv.conv2d).
|
||||
Convolution operator for filtering windows of two-dimensional inputs.
|
||||
|
||||
- __Input shape__: 4D tensor with shape: `(nb_samples, stack_size, nb_row, nb_col)`.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(nb_samples, nb_filter, nb_row, nb_col)`. `nb_row`, `nb_col` might have changed due to padding.
|
||||
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __nb_filter__: Number of convolution kernels to use.
|
||||
- __stack_size__: Number of channels in the input.
|
||||
- __nb_row__: Number of rows in the convolution kernels
|
||||
- __nb_col__: Number of columns in the convolution kernels
|
||||
- __init__: name of initialization function for the weights of the layer (see: [initializations](../initializations.md)), or alternatively, Theano function to use for weights initialization. This parameter is only relevant if you don't pass a `weights` argument.
|
||||
- __activation__: name of activation function to use (see: [activations](../activations.md)), or alternatively, elementwise Theano function. If you don't specify anything, no activation is applied (ie. "linear" activation: a(x) = x).
|
||||
- __weights__: list of numpy arrays to set as initial weights.
|
||||
- __border_mode__: 'valid', 'full', or 'same'. See scipy.signal.convolve2d.
|
||||
- __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.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## MaxPooling1D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.MaxPooling1D(pool_length=2, stride=None, ignore_border=True)
|
||||
```
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, steps, dim)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(nb_samples, steps, new_dim)`.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __pool_length__: factor by which to downscale. 2 will halve the input.
|
||||
- __stride__: integer or None. Stride value.
|
||||
- __ignore_border__: boolean.
|
||||
|
||||
---
|
||||
|
||||
@@ -17,4 +93,12 @@ This is a wrapper for Theano's [conv2d](http://deeplearning.net/software/theano/
|
||||
keras.layers.convolutional.MaxPooling2D(poolsize=(2, 2), ignore_border=True)
|
||||
```
|
||||
|
||||
This is a wrapper for Theano's [max_pool_2d](http://deeplearning.net/software/theano/library/tensor/signal/downsample.html).
|
||||
- __Input shape__: 4D tensor with shape: `(nb_samples, stack_size, nb_row, nb_col)`.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(nb_samples, stack_size, new_nb_row, new_nb_col)`.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __pool_size__: factor by which to downscale (vertical ds, horizontal ds). (2, 2) will halve the image in each dimension.
|
||||
- __ignore_border__: boolean. When True, (5, 5) input with pool_size=(2, 2) will generate a (2, 2) output, (3, 3) otherwise.
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ Set the weights of the parameters of the layer.
|
||||
## Dense
|
||||
```python
|
||||
keras.layers.core.Dense(input_dim, output_dim, init='glorot_uniform', activation='linear', weights=None \
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None)
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None)
|
||||
```
|
||||
|
||||
Standard 1D fully-connect layer.
|
||||
@@ -87,8 +87,9 @@ Standard 1D fully-connect layer.
|
||||
- __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. 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 main weights matrix.
|
||||
- __b_regularizer__: instance of the [regularizers](../regularizers.md) module, applied to the bias.
|
||||
- __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.
|
||||
|
||||
@@ -97,7 +98,7 @@ Standard 1D fully-connect layer.
|
||||
## TimeDistributedDense
|
||||
```python
|
||||
keras.layers.core.TimeDistributedDense(input_dim, output_dim, init='glorot_uniform', activation='linear', weights=None \
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None)
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None)
|
||||
```
|
||||
|
||||
Fully-connected layer distributed over the time dimension. Useful after a recurrent network set to `return_sequences=True`.
|
||||
@@ -110,8 +111,9 @@ Fully-connected layer distributed over the time dimension. Useful after a recurr
|
||||
- __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. 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 main weights matrix.
|
||||
- __b_regularizer__: instance of the [regularizers](../regularizers.md) module, applied to the bias.
|
||||
- __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.
|
||||
|
||||
@@ -127,7 +129,7 @@ model.add(TimeDistributedDense(5, 10)) # output shape: (nb_samples, nb_timesteps
|
||||
|
||||
## AutoEncoder
|
||||
```python
|
||||
keras.layers.core.AutoEncoder(encoder, decoder, output_reconstruction=True, tie_weights=False, weights=None):
|
||||
keras.layers.core.AutoEncoder(encoder, decoder, output_reconstruction=True, weights=None):
|
||||
```
|
||||
|
||||
A customizable autoencoder model. If `output_reconstruction = True` then dim(input) = dim(output) else dim(output) = dim(hidden)
|
||||
@@ -145,8 +147,6 @@ A customizable autoencoder model. If `output_reconstruction = True` then dim(inp
|
||||
|
||||
- __output_reconstruction__: If this is False the when .predict() is called the output is the deepest hidden layer's activation. Otherwise the output of the final decoder layer is presented. Be sure your validation data confirms to this logic if you decide to use any.
|
||||
|
||||
- __tie_weights__: If True then the encoder bias is tied to the decoder bias. **Note**: This required the encoder layer corresponding to this decoder layer to be of the same time, eg: Dense:Dense
|
||||
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 1 element, of shape `(input_dim, output_dim)`.
|
||||
|
||||
- __Example__:
|
||||
@@ -156,45 +156,9 @@ from keras.layers import containers
|
||||
# input shape: (nb_samples, 32)
|
||||
encoder = containers.Sequential([Dense(32, 16), Dense(16, 8)])
|
||||
decoder = containers.Sequential([Dense(8, 16), Dense(16, 32)])
|
||||
autoencoder.add(AutoEncoder(encoder=encoder, decoder=decoder, output_reconstruction=False, tie_weights=True))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## DenoisingAutoEncoder
|
||||
```python
|
||||
keras.layers.core.AutoEncoder(encoder, decoder, output_reconstruction=True, tie_weights=False, weights=None, corruption_level=0.3):
|
||||
```
|
||||
|
||||
A denoising autoencoder model that inherits the base features from autoencoder.
|
||||
Since this layer uses similar logic to Dropout it cannot be the first layer in a pipeline.
|
||||
|
||||
- __Input shape__: The layer shape is defined by the encoder definitions
|
||||
|
||||
- __Output shape__: The layer shape is defined by the decoder definitions
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __encoder__: A [layer](./) or [layer container](./containers.md).
|
||||
|
||||
- __decoder__: A [layer](./) or [layer container](./containers.md).
|
||||
|
||||
- __output_reconstruction__: If this is False the when .predict() is called the output is the deepest hidden layer's activation. Otherwise the output of the final decoder layer is presented. Be sure your validation data confirms to this logic if you decide to use any.
|
||||
|
||||
- __tie_weights__: If True then the encoder bias is tied to the decoder bias. **Note**: This required the encoder layer corresponding to this decoder layer to be of the same time, eg: Dense:Dense
|
||||
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 1 element, of shape `(input_dim, output_dim)`.
|
||||
|
||||
- __corruption_level__: the amount of binomial noise added to the input layer of the model.
|
||||
|
||||
- __Example__:
|
||||
```python
|
||||
# input shape: (nb_samples, 32)
|
||||
autoencoder.add(Dense(32, 32))
|
||||
autoencoder.add(DenoisingAutoEncoder(encoder=Dense(32, 16),
|
||||
decoder=Dense(16, 32),
|
||||
output_reconstruction=False, tie_weights=True,
|
||||
corruption_level=0.3))
|
||||
autoencoder = Sequential()
|
||||
autoencoder.add(AutoEncoder(encoder=encoder, decoder=decoder, output_reconstruction=False))
|
||||
```
|
||||
|
||||
|
||||
@@ -231,9 +195,9 @@ Apply dropout to the input. Dropout consists in randomly setting a fraction `p`
|
||||
|
||||
- __p__: float (0 <= p < 1). Fraction of the input that gets dropped out at training time.
|
||||
|
||||
|
||||
---
|
||||
|
||||
|
||||
## Reshape
|
||||
```python
|
||||
keras.layers.core.Reshape(*dims)
|
||||
@@ -276,7 +240,9 @@ Convert a nD input to 1D.
|
||||
keras.layers.core.RepeatVector(n)
|
||||
```
|
||||
|
||||
Repeat the 1D input n times. Dimensions of input are assumed to be (nb_samples, dim). Output will have the shape (nb_samples, n, dim).
|
||||
Repeat the 1D input n times. Dimensions of input are assumed to be `(nb_samples, dim)`. Output will have the shape `(nb_samples, n, dim)`.
|
||||
|
||||
Note that the output is still a single tensor; `RepeatVector` does not split the data flow.
|
||||
|
||||
- __Input shape__: This layer does not assume a specific input shape. This layer cannot be used as the first layer in a model.
|
||||
|
||||
@@ -289,10 +255,21 @@ Repeat the 1D input n times. Dimensions of input are assumed to be (nb_samples,
|
||||
|
||||
---
|
||||
|
||||
## ActivityRegularization
|
||||
```python
|
||||
keras.layers.core.ActivityRegularization(l1=0., l2=0.)
|
||||
```
|
||||
|
||||
Leaves the input unchanged, but adds a term to the loss function based on the input activity. L1 and L2 regularization supported.
|
||||
|
||||
This layer can be used, for instance, to induce activation sparsity in the previous layer.
|
||||
|
||||
---
|
||||
|
||||
## MaxoutDense
|
||||
```python
|
||||
keras.layers.core.MaxoutDense(input_dim, output_dim, nb_feature=4, init='glorot_uniform', weights=None, \
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None)
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None)
|
||||
```
|
||||
|
||||
A dense maxout layer. A `MaxoutDense` layer takes the element-wise maximum of `nb_feature` `Dense(input_dim, output_dim)` linear layers. This allows the layer to learn a convex, piecewise linear activation function over the inputs. See [this paper](http://arxiv.org/pdf/1302.4389.pdf) for more details. Note that this is a *linear* layer -- if you wish to apply activation function (you shouldn't need to -- they are universal function approximators), an `Activation` layer must be added after.
|
||||
@@ -308,8 +285,9 @@ A dense maxout layer. A `MaxoutDense` layer takes the element-wise maximum of `n
|
||||
- __nb_feature__: int >= 0. the number of features to create for the maxout. This is equivalent to the number of piecewise elements to be allowed for the activation function.
|
||||
- __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. 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 main weights matrix.
|
||||
- __b_regularizer__: instance of the [regularizers](../regularizers.md) module, applied to the bias.
|
||||
- __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.
|
||||
|
||||
@@ -325,11 +303,11 @@ model.add(RepeatVector(2)) # output shape: (nb_samples, 2, 10)
|
||||
keras.layers.core.Merge(models, mode='sum')
|
||||
```
|
||||
|
||||
Merge the output of a list of models into a single tensor, following one of two modes: `sum` or `concat`.
|
||||
Merge the output of a list of layers (or containers) into a single tensor, following one of two modes: `sum` or `concat`.
|
||||
|
||||
- __Arguments__:
|
||||
- __models__: List of `Sequential` models.
|
||||
- __mode__: String, one of `{'sum', 'concat'}`. `sum` will simply sum the outputs of the models (therefore all models should have an output with the same shape). `concat` will concatenate the outputs along the last dimension (therefore all models should have an output that only differ along the last dimension).
|
||||
- __layers__: List of layers or [containers](/layers/containers/).
|
||||
- __mode__: String, one of `{'sum', 'concat'}`. `sum` will simply sum the outputs of the layers (therefore all layers should have an output with the same shape). `concat` will concatenate the outputs along the last dimension (therefore all layers should have an output that only differ along the last dimension).
|
||||
|
||||
- __Example__:
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
## Embedding
|
||||
|
||||
```python
|
||||
keras.layers.embeddings.Embedding(input_dim, output_dim, init='uniform', weights=None, W_regularizer=None, W_constraint=None)
|
||||
keras.layers.embeddings.Embedding(input_dim, output_dim, init='uniform', weights=None, W_regularizer=None, W_constraint=None, mask_zero=False)
|
||||
```
|
||||
|
||||
Turn positive integers (indexes) into denses vectors of fixed size,
|
||||
@@ -20,6 +20,7 @@ eg. `[[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]`
|
||||
- __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.
|
||||
- __W_constraint__: instance of the [constraints](../constraints.md) module (eg. maxnorm, nonneg), applied to the embedding matrix.
|
||||
- __mask_zero__: Whether or not the input value 0 is a special "padding" value that should be masked out. 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.
|
||||
|
||||
|
||||
## WordContextProduct
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
|
||||
|
||||
## GaussianNoise
|
||||
```python
|
||||
keras.layers.noise.GaussianNoise(sigma)
|
||||
```
|
||||
Apply to the input an additive zero-centred 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 for real valued inputs.
|
||||
|
||||
The Gaussian noise is only added at training time.
|
||||
|
||||
- __Input shape__: This layer does not assume a specific input shape.
|
||||
|
||||
- __Output shape__: Same as input.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __sigma__: float, standard deviation of the noise distribution.
|
||||
|
||||
---
|
||||
|
||||
## GaussianDropout
|
||||
```python
|
||||
keras.layers.noise.GaussianDropout(p)
|
||||
```
|
||||
Apply to the input an multiplicative one-centred gaussian noise with standard deviation `sqrt(p/(1-p))`. p refers to drop probability to match Dropout layer syntax.
|
||||
|
||||
http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf
|
||||
|
||||
The Gaussian noise is only used at training time.
|
||||
|
||||
- __Input shape__: This layer does not assume a specific input shape.
|
||||
|
||||
- __Output shape__: Same as input.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __p__: float, drop probability as with Dropout.
|
||||
|
||||
@@ -6,7 +6,7 @@ keras.layers.recurrent.SimpleRNN(input_dim, output_dim,
|
||||
init='glorot_uniform', inner_init='orthogonal', activation='sigmoid', weights=None,
|
||||
truncate_gradient=-1, return_sequences=False)
|
||||
```
|
||||
Fully connected RNN where output is to fed back to input. Not a particularly useful model, included for demonstration purposes.
|
||||
Fully connected RNN where output is to fed back to input.
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, timesteps, input_dim)`.
|
||||
|
||||
@@ -14,6 +14,9 @@ Fully connected RNN where output is to fed back to input. Not a particularly use
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, ouput_dim)`.
|
||||
- else: 2D tensor with shape: `(nb_samples, output_dim)`.
|
||||
|
||||
- __Masking__: This layer supports masking for input data with a variable number of timesteps To introduce masks to your data, use an [Embedding](embeddings.md) layer with the `mask_zero` parameter set to `True`.
|
||||
|
||||
|
||||
- __Arguments__:
|
||||
- __input_dim__: dimension of the input.
|
||||
- __output_dim__: dimension of the internal projections and the final output.
|
||||
@@ -47,6 +50,9 @@ Not a particularly useful model, included for demonstration purposes.
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, ouput_dim)`.
|
||||
- else: 2D tensor with shape: `(nb_samples, output_dim)`.
|
||||
|
||||
- __Masking__: This layer supports masking for input data with a variable number of timesteps To introduce masks to your data, use an [Embedding](embeddings.md) layer with the `mask_zero` parameter set to `True`.
|
||||
|
||||
|
||||
- __Arguments__:
|
||||
- __input_dim__: dimension of the input.
|
||||
- __output_dim__: dimension of the internal projections and the final output.
|
||||
@@ -79,6 +85,8 @@ Gated Recurrent Unit - Cho et al. 2014.
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, ouput_dim)`.
|
||||
- else: 2D tensor with shape: `(nb_samples, output_dim)`.
|
||||
|
||||
- __Masking__: This layer supports masking for input data with a variable number of timesteps To introduce masks to your data, use an [Embedding](embeddings.md) layer with the `mask_zero` parameter set to true.
|
||||
|
||||
- __Arguments__:
|
||||
- __input_dim__: dimension of the input.
|
||||
- __output_dim__: dimension of the internal projections and the final output.
|
||||
@@ -100,7 +108,7 @@ Gated Recurrent Unit - Cho et al. 2014.
|
||||
|
||||
```python
|
||||
keras.layers.recurrent.LSTM(input_dim, output_dim=128,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
init='glorot_uniform', inner_init='orthogonal', forget_bias_init='one',
|
||||
activation='tanh', inner_activation='hard_sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False)
|
||||
```
|
||||
@@ -113,11 +121,14 @@ Long-Short Term Memory unit - Hochreiter 1997.
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, ouput_dim)`.
|
||||
- else: 2D tensor with shape: `(nb_samples, output_dim)`.
|
||||
|
||||
- __Masking__: This layer supports masking for input data with a variable number of timesteps To introduce masks to your data, use an [Embedding](embeddings.md) layer with the `mask_zero` parameter set to true.
|
||||
|
||||
- __Arguments__:
|
||||
- __input_dim__: dimension of the input.
|
||||
- __input_dim__: dimension of the input.
|
||||
- __output_dim__: dimension of the internal projections and the final output.
|
||||
- __init__: weight initialization function for the output cell. Can be the name of an existing function (str), or a Theano function (see: [initializations](../initializations.md)).
|
||||
- __inner_init__: weight initialization function for the inner cells.
|
||||
- __forget_bias_init__: initialization function for the bias of the forget gate. [Jozefowicz et al.](http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf) recommend initializing with ones.
|
||||
- __activation__: activation function for the output. Can be the name of an existing function (str), or a Theano function (see: [activations](../activations.md)).
|
||||
- __inner_activation__: activation function for the inner cells.
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 12 elements.
|
||||
@@ -128,6 +139,41 @@ Long-Short Term Memory unit - Hochreiter 1997.
|
||||
- [Long short-term memory](http://deeplearning.cs.cmu.edu/pdfs/Hochreiter97_lstm.pdf) (original 1997 paper)
|
||||
- [Learning to forget: Continual prediction with LSTM](http://www.mitpressjournals.org/doi/pdf/10.1162/089976600300015015)
|
||||
- [Supervised sequence labelling with recurrent neural networks](http://www.cs.toronto.edu/~graves/preprint.pdf)
|
||||
|
||||
---
|
||||
|
||||
## JZS1, JZS2, JZS3
|
||||
|
||||
```python
|
||||
keras.layers.recurrent.JZS1(input_dim, output_dim=128,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='tanh', inner_activation='sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False)
|
||||
```
|
||||
|
||||
Top 3 RNN architectures evolved from the evaluation of thousands of models. Serves as alternatives to LSTMs and GRUs. Corresponds to `MUT1`, `MUT2`, and `MUT3` architectures described in the paper: An Empirical Exploration of Recurrent Network Architectures, Jozefowicz et al. 2015.
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, timesteps, input_dim)`.
|
||||
|
||||
- __Output shape__:
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, ouput_dim)`.
|
||||
- else: 2D tensor with shape: `(nb_samples, output_dim)`.
|
||||
|
||||
- __Masking__: This layer supports masking for input data with a variable number of timesteps To introduce masks to your data, use an [Embedding](embeddings.md) layer with the `mask_zero` parameter set to true.
|
||||
|
||||
- __Arguments__:
|
||||
- __input_dim__: dimension of the input.
|
||||
- __output_dim__: dimension of the internal projections and the final output.
|
||||
- __init__: weight initialization function for the output cell. Can be the name of an existing function (str), or a Theano function (see: [initializations](../initializations.md)).
|
||||
- __inner_init__: weight initialization function for the inner cells.
|
||||
- __activation__: activation function for the output. Can be the name of an existing function (str), or a Theano function (see: [activations](../activations.md)).
|
||||
- __inner_activation__: activation function for the inner cells.
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 9 elements.
|
||||
- __truncate_gradient__: Number of steps to use in truncated BPTT. See: [Theano "scan"](http://deeplearning.net/software/theano/library/scan.html).
|
||||
- __return_sequences__: Boolean. Whether to return the last output in the output sequence, or the full sequence.
|
||||
|
||||
- __References__:
|
||||
- [An Empirical Exploration of Recurrent Network Architectures](http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+103
-12
@@ -7,40 +7,42 @@ model = keras.models.Sequential()
|
||||
```
|
||||
- __Methods__:
|
||||
- __add__(layer): Add a layer to the model.
|
||||
- __compile__(optimizer, loss, class_mode="categorical"):
|
||||
- __Arguments__:
|
||||
- __compile__(optimizer, loss, class_mode="categorical"):
|
||||
- __Arguments__:
|
||||
- __optimizer__: str (name of optimizer) or optimizer object. See [optimizers](optimizers.md).
|
||||
- __loss__: str (name of objective function) or objective function. See [objectives](objectives.md).
|
||||
- __class_mode__: one of "categorical", "binary". This is only used for computing classification accuracy or using the predict_classes method.
|
||||
- __class_mode__: one of "categorical", "binary". This is only used for computing classification accuracy or using the predict_classes method.
|
||||
- __theano_mode__: A `theano.compile.mode.Mode` ([reference](http://deeplearning.net/software/theano/library/compile/mode.html)) instance controlling specifying compilation options.
|
||||
- __fit__(X, y, batch_size=128, nb_epoch=100, verbose=1, validation_split=0., validation_data=None, shuffle=True, show_accuracy=False, callbacks=[]): Train a model for a fixed number of epochs.
|
||||
- __fit__(X, y, batch_size=128, nb_epoch=100, verbose=1, validation_split=0., validation_data=None, shuffle=True, show_accuracy=False, callbacks=[], class_weight=None, sample_weight=None): Train a model for a fixed number of epochs.
|
||||
- __Return__: a history dictionary with a record of training loss values at successive epochs, as well as validation loss values (if applicable), accuracy (if applicable), etc.
|
||||
- __Arguments__:
|
||||
- __Arguments__:
|
||||
- __X__: data.
|
||||
- __y__: labels.
|
||||
- __batch_size__: int. Number of samples per gradient update.
|
||||
- __nb_epoch__: int.
|
||||
- __nb_epoch__: int.
|
||||
- __verbose__: 0 for no logging to stdout, 1 for progress bar logging, 2 for one log line per epoch.
|
||||
- __callbacks__: `keras.callbacks.Callback` list. List of callbacks to apply during training. See [callbacks](callbacks.md).
|
||||
- __validation_split__: float (0. < x < 1). Fraction of the data to use as held-out validation data.
|
||||
- __validation_data__: tuple (X, y) to be used as held-out validation data. Will override validation_split.
|
||||
- __shuffle__: boolean. Whether to shuffle the samples at each epoch.
|
||||
- __show_accuracy__: boolean. Whether to display class accuracy in the logs to stdout at each epoch.
|
||||
- __callbacks__: `keras.callbacks.Callback` list. List of callbacks to apply during training. See [callbacks](callbacks.md).
|
||||
- __class_weight__: dictionary mapping classes to a weight value, used for scaling the loss function (during training only).
|
||||
- __sample_weight__: list or numpy array with 1:1 mapping to the training samples, used for scaling the loss function (during training only).
|
||||
- __evaluate__(X, y, batch_size=128, show_accuracy=False, verbose=1): Show performance of the model over some validation data.
|
||||
- __Return__: The loss score over the data.
|
||||
- __Return__: The loss score over the data, or a `(loss, accuracy)` tuple if `show_accuracy=True`.
|
||||
- __Arguments__: Same meaning as fit method above. verbose is used as a binary flag (progress bar or nothing).
|
||||
- __predict__(X, batch_size=128, verbose=1):
|
||||
- __predict__(X, batch_size=128, verbose=1):
|
||||
- __Return__: An array of predictions for some test data.
|
||||
- __Arguments__: Same meaning as fit method above.
|
||||
- __predict_classes__(X, batch_size=128, verbose=1): Return an array of class predictions for some test data.
|
||||
- __Return__: An array of labels for some test data.
|
||||
- __Arguments__: Same meaning as fit method above. verbose is used as a binary flag (progress bar or nothing).
|
||||
- __train__(X, y, accuracy=False): Single gradient update on one batch. if accuracy==False, return tuple (loss_on_batch, accuracy_on_batch). Else, return loss_on_batch.
|
||||
- __train_on_batch__(X, y, accuracy=False): Single gradient update on one batch.
|
||||
- __Return__: loss over the data, or tuple `(loss, accuracy)` if `accuracy=True`.
|
||||
- __test__(X, y, accuracy=False): Single performance evaluation on one batch. if accuracy==False, return tuple (loss_on_batch, accuracy_on_batch). Else, return loss_on_batch.
|
||||
- __test_on_batch__(X, y, accuracy=False): Single performance evaluation on one batch.
|
||||
- __Return__: loss over the data, or tuple `(loss, accuracy)` if `accuracy=True`.
|
||||
- __save_weights__(fname, overwrite=False): Store the weights of all layers to a HDF5 file. If overwrite==False and the file already exists, an exception will be thrown.
|
||||
- __load_weights__(fname): Sets the weights of a model, based to weights stored by __save__weights__. You can only __load__weights__ on a savefile from a model with an identical architecture. __load_weights__ can be called either before or after the __compile__ step.
|
||||
- __load_weights__(fname): Sets the weights of a model, based to weights stored by __save_weights__. You can only __load_weights__ on a savefile from a model with an identical architecture. __load_weights__ can be called either before or after the __compile__ step.
|
||||
|
||||
__Examples__:
|
||||
|
||||
@@ -112,3 +114,92 @@ Epoch 2
|
||||
10960/37800 [=======>......................] - ETA: 4s - loss: 0.0109 - acc.: 0.9420
|
||||
'''
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Graph
|
||||
|
||||
Arbitrary connection graph. It can have any number of inputs and outputs, with each output trained with its own loss function. The quantity being optimized by a Graph model is the sum of all loss functions over the different outputs.
|
||||
|
||||
```python
|
||||
model = keras.models.Graph()
|
||||
```
|
||||
- __Methods__:
|
||||
- __add_input__(name, ndim=2, dtype='float'): Add an input with shape dimensionality `ndim`.
|
||||
- __Arguments__:
|
||||
- __ndim__: Use `ndim=2` for vector input `(samples, features)`, ndim=3 for temporal input `(samples, time, features)`, ndim=4 for image input `(samples, channels, height, width)`.
|
||||
- __dtype__: `float` or `int`. Use `int` if the input is connected to an Embedding layer, `float` otherwise.
|
||||
- __add_output__(name, input=None, inputs=[], merge_mode='concat'): Add an output connect to `input` or `inputs`.
|
||||
- __Arguments__:
|
||||
- __name__: str. unique identifier of the output.
|
||||
- __input__: str name of the node that the output is connected to. Only specify *one* of either `input` or `inputs`.
|
||||
- __inputs__: list of str names of the node that the output is connected to.
|
||||
- __merge_mode__: "sum" or "concat". Only applicable if `inputs` list is specified. Merge mode for the different inputs.
|
||||
- __add_node__(layer, name, input=None, inputs=[], merge_mode='concat'): Add an output connect to `input` or `inputs`.
|
||||
- __Arguments__:
|
||||
- __layer__: Layer instance.
|
||||
- __name__: str. unique identifier of the node.
|
||||
- __input__: str name of the node/input that the node is connected to. Only specify *one* of either `input` or `inputs`.
|
||||
- __inputs__: list of str names of the node that the node is connected to.
|
||||
- __merge_mode__: "sum" or "concat". Only applicable if `inputs` list is specified. Merge mode for the different inputs.
|
||||
- __compile__(optimizer, loss):
|
||||
- __Arguments__:
|
||||
- __optimizer__: str (name of optimizer) or optimizer object. See [optimizers](optimizers.md).
|
||||
- __loss__: dictionary mapping the name(s) of the output(s) to a loss function (string name of objective function or objective function. See [objectives](objectives.md)).
|
||||
- __fit__(data, batch_size=128, nb_epoch=100, verbose=1, validation_split=0., validation_data=None, shuffle=True, callbacks=[]): Train a model for a fixed number of epochs.
|
||||
- __Return__: a history dictionary with a record of training loss values at successive epochs, as well as validation loss values (if applicable).
|
||||
- __Arguments__:
|
||||
- __data__:dictionary mapping input names out outputs names to appropriate numpy arrays. All arrays should contain the same number of samples.
|
||||
- __batch_size__: int. Number of samples per gradient update.
|
||||
- __nb_epoch__: int.
|
||||
- __verbose__: 0 for no logging to stdout, 1 for progress bar logging, 2 for one log line per epoch.
|
||||
- __callbacks__: `keras.callbacks.Callback` list. List of callbacks to apply during training. See [callbacks](callbacks.md).
|
||||
- __validation_split__: float (0. < x < 1). Fraction of the data to use as held-out validation data.
|
||||
- __validation_data__: tuple (X, y) to be used as held-out validation data. Will override validation_split.
|
||||
- __shuffle__: boolean. Whether to shuffle the samples at each epoch.
|
||||
- __evaluate__(data, batch_size=128, verbose=1): Show performance of the model over some validation data.
|
||||
- __Return__: The loss score over the data.
|
||||
- __Arguments__: Same meaning as fit method above. verbose is used as a binary flag (progress bar or nothing).
|
||||
- __predict__(data, batch_size=128, verbose=1):
|
||||
- __Return__: A dictionary mapping output names to arrays of predictions over the data.
|
||||
- __Arguments__: Same meaning as fit method above. Only inputs need to be specified in `data`.
|
||||
- __train_on_batch__(data): Single gradient update on one batch.
|
||||
- __Return__: loss over the data.
|
||||
- __test_on_batch__(data): Single performance evaluation on one batch.
|
||||
- __Return__: loss over the data.
|
||||
- __save_weights__(fname, overwrite=False): Store the weights of all layers to a HDF5 file. If `overwrite==False` and the file already exists, an exception will be thrown.
|
||||
- __load_weights__(fname): Sets the weights of a model, based to weights stored by __save_weights__. You can only __load_weights__ on a savefile from a model with an identical architecture. __load_weights__ can be called either before or after the __compile__ step.
|
||||
|
||||
|
||||
__Examples__:
|
||||
|
||||
```python
|
||||
# graph model with one input and two outputs
|
||||
graph = Graph()
|
||||
graph.add_input(name='input', ndim=2)
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
graph.add_output(name='output1', input='dense2')
|
||||
graph.add_output(name='output2', input='dense3')
|
||||
|
||||
graph.compile('rmsprop', {'output1':'mse', 'output2':'mse'})
|
||||
history = graph.fit({'input':X_train, 'output1':y_train, 'output2':y2_train}, nb_epoch=10)
|
||||
|
||||
```
|
||||
|
||||
```python
|
||||
# graph model with two inputs and one output
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
graph.add_input(name='input2', ndim=2)
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input2')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
graph.add_output(name='output', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
graph.compile('rmsprop', {'output':'mse'})
|
||||
|
||||
history = graph.fit({'input1':X_train, 'input2':X2_train, 'output':y_train}, nb_epoch=10)
|
||||
predictions = graph.predict({'input1':X_test, 'input2':X2_test}) # {'output':...}
|
||||
|
||||
```
|
||||
@@ -7,18 +7,22 @@ An objective function (or loss function, or optimization score function) is one
|
||||
model.compile(loss='mean_squared_error', optimizer='sgd')
|
||||
```
|
||||
|
||||
You can either pass the name of an existing objective, or pass a Theano symbolic function that returns a scalar and takes the following two arguments:
|
||||
You can either pass the name of an existing objective, or pass a Theano symbolic function that returns a scalar for each data-point and takes the following two arguments:
|
||||
|
||||
- __y_true__: True labels. Theano tensor.
|
||||
- __y_pred__: Predictions. Theano tensor of the same shape as y_true.
|
||||
|
||||
The actual optimized objective is the mean of the output array across all datapoints.
|
||||
|
||||
For a few examples of such functions, check out the [objectives source](https://github.com/fchollet/keras/blob/master/keras/objectives.py).
|
||||
|
||||
## Available objectives
|
||||
|
||||
- __mean_squared_error__ / __mse__
|
||||
- __mean_absolute_error__ / __mae__
|
||||
- __mean_absolute_percentage_error__ / __mape__
|
||||
- __mean_squared_logarithmic_error__ / __msle__
|
||||
- __squared_hinge__
|
||||
- __hinge__
|
||||
- __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)`.
|
||||
- __categorical_crossentropy__: Also known as multiclass logloss. __Note__: using this objective requires that your labels are binary arrays of shape `(nb_samples, nb_classes)`.
|
||||
|
||||
@@ -1,18 +1,40 @@
|
||||
## Usage of regularizers
|
||||
|
||||
Regularizers allow to apply penalties on network parameters during optimization.
|
||||
Regularizers allow to apply penalties on layer parameters or layer activity during optimization. These penalties are incorporated in the loss function that the network optimizes.
|
||||
|
||||
The keyword arguments used for passing penalties to parameters in a layer will depend on the layer.
|
||||
The penalties are applied on a per-layer basis. The exact API will depend on the layer, but the layers `Dense`, `TimeDistributedDense`, `MaxoutDense`, `Convolution1D` and `Convolution2D` have a unified API.
|
||||
|
||||
In the `Dense` layer it is simply `W_regularizer` for the main weights matrix, and `b_regularizer` for the bias.
|
||||
These layers expose 3 keyword arguments:
|
||||
|
||||
- `W_regularizer`: instance of `keras.regularizers.WeightRegularizer`
|
||||
- `b_regularizer`: instance of `keras.regularizers.WeightRegularizer`
|
||||
- `activity_regularizer`: instance of `keras.regularizers.ActivityRegularizer`
|
||||
|
||||
|
||||
## Example
|
||||
|
||||
```python
|
||||
from keras.regularizers import l2
|
||||
model.add(Dense(64, 64, W_regularizer = l2(.01)))
|
||||
from keras.regularizers import l2, activity_l2
|
||||
model.add(Dense(64, 64, W_regularizer=l2(0.01), activity_regularizer=activity_l2(0.01)))
|
||||
```
|
||||
|
||||
## Available penalties
|
||||
|
||||
- __l1__(l=0.01): L1 regularization penalty, also known as LASSO
|
||||
- __l2__(l=0.01): L2 regularization penalty, also known as weight decay, or Ridge
|
||||
- __l1l2__(l1=0.01, l2=0.01): L1-L2 regularization penalty, also known as ElasticNet
|
||||
```python
|
||||
keras.regularizers.WeightRegularizer(l1=0., l2=0.)
|
||||
```
|
||||
|
||||
```python
|
||||
keras.regularizers.ActivityRegularizer(l1=0., l2=0.)
|
||||
```
|
||||
|
||||
## Shortcuts
|
||||
|
||||
These are shortcut functions available in `keras.regularizers`.
|
||||
|
||||
- __l1__(l=0.01): L1 weight regularization penalty, also known as LASSO
|
||||
- __l2__(l=0.01): L2 weight regularization penalty, also known as weight decay, or Ridge
|
||||
- __l1l2__(l1=0.01, l2=0.01): L1-L2 weight regularization penalty, also known as ElasticNet
|
||||
- __activity_l1__(l=0.01): L1 activity regularization
|
||||
- __activity_l2__(l=0.01): L2 activity regularization
|
||||
- __activity_l1l2__(l1=0.01, l2=0.01): L1+L2 activity regularization
|
||||
|
||||
@@ -30,6 +30,7 @@ data_augmentation = True
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
|
||||
print('X_train shape:', X_train.shape)
|
||||
print(X_train.shape[0], 'train samples')
|
||||
print(X_test.shape[0], 'test samples')
|
||||
|
||||
@@ -54,11 +55,11 @@ model.add(MaxPooling2D(poolsize=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Flatten())
|
||||
model.add(Dense(64*8*8, 512, init='normal'))
|
||||
model.add(Dense(64*8*8, 512))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.5))
|
||||
|
||||
model.add(Dense(512, nb_classes, init='normal'))
|
||||
model.add(Dense(512, nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
# let's train the model using SGD + momentum (how original).
|
||||
@@ -72,7 +73,7 @@ if not data_augmentation:
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=10)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch)
|
||||
score = model.evaluate(X_test, Y_test, batch_size=batch_size)
|
||||
print('Test score:', score)
|
||||
|
||||
@@ -104,14 +105,14 @@ else:
|
||||
# batch train with realtime data augmentation
|
||||
progbar = generic_utils.Progbar(X_train.shape[0])
|
||||
for X_batch, Y_batch in datagen.flow(X_train, Y_train):
|
||||
loss = model.train(X_batch, Y_batch)
|
||||
loss = model.train_on_batch(X_batch, Y_batch)
|
||||
progbar.add(X_batch.shape[0], values=[("train loss", loss)])
|
||||
|
||||
print("Testing...")
|
||||
# test time!
|
||||
progbar = generic_utils.Progbar(X_test.shape[0])
|
||||
for X_batch, Y_batch in datagen.flow(X_test, Y_test):
|
||||
score = model.test(X_batch, Y_batch)
|
||||
score = model.test_on_batch(X_batch, Y_batch)
|
||||
progbar.add(X_batch.shape[0], values=[("test loss", score)])
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.optimizers import RMSprop
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.convolutional import Convolution1D, MaxPooling1D
|
||||
from keras.datasets import imdb
|
||||
|
||||
'''
|
||||
This example demonstrates the use of Convolution1D
|
||||
for text classification.
|
||||
|
||||
Run on GPU: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python imdb_cnn.py
|
||||
|
||||
Get to 0.8330 test accuracy after 3 epochs. 100s/epoch on K520 GPU.
|
||||
'''
|
||||
|
||||
# set parameters:
|
||||
max_features = 5000
|
||||
maxlen = 100
|
||||
batch_size = 32
|
||||
embedding_dims = 100
|
||||
nb_filters = 250
|
||||
filter_length = 3
|
||||
hidden_dims = 250
|
||||
nb_epoch = 3
|
||||
|
||||
print("Loading data...")
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features,
|
||||
test_split=0.2)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
|
||||
print("Pad sequences (samples x time)")
|
||||
X_train = sequence.pad_sequences(X_train, maxlen=maxlen)
|
||||
X_test = sequence.pad_sequences(X_test, maxlen=maxlen)
|
||||
print('X_train shape:', X_train.shape)
|
||||
print('X_test shape:', X_test.shape)
|
||||
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
|
||||
# we start off with an efficient embedding layer which maps
|
||||
# our vocab indices into embedding_dims dimensions
|
||||
model.add(Embedding(max_features, embedding_dims))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
# we add a Convolution1D, which will learn nb_filters
|
||||
# word group filters of size filter_length:
|
||||
model.add(Convolution1D(input_dim=embedding_dims,
|
||||
nb_filter=nb_filters,
|
||||
filter_length=filter_length,
|
||||
border_mode="valid",
|
||||
activation="relu",
|
||||
subsample_length=1))
|
||||
|
||||
# we use standard max pooling (halving the output of the previous layer):
|
||||
model.add(MaxPooling1D(pool_length=2))
|
||||
|
||||
# We flatten the output of the conv layer, so that we can add a vanilla dense layer:
|
||||
model.add(Flatten())
|
||||
|
||||
# Computing the output shape of a conv layer can be tricky;
|
||||
# for a good tutorial, see: http://cs231n.github.io/convolutional-networks/
|
||||
output_size = nb_filters * (((maxlen - filter_length) / 1) + 1) / 2
|
||||
|
||||
# We add a vanilla hidden layer:
|
||||
model.add(Dense(output_size, hidden_dims))
|
||||
model.add(Dropout(0.25))
|
||||
model.add(Activation('relu'))
|
||||
|
||||
# We project onto a single unit output layer, and squash it with a sigmoid:
|
||||
model.add(Dense(hidden_dims, 1))
|
||||
model.add(Activation('sigmoid'))
|
||||
|
||||
model.compile(loss='binary_crossentropy', optimizer='rmsprop', class_mode="binary")
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, validation_data=(X_test, y_test))
|
||||
+10
-16
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.optimizers import SGD, RMSprop, Adagrad
|
||||
@@ -21,21 +22,18 @@ from keras.datasets import imdb
|
||||
|
||||
- RNNs are tricky. Choice of batch size is important,
|
||||
choice of loss and optimizer is critical, etc.
|
||||
Most configurations won't converge.
|
||||
Some configurations won't converge.
|
||||
|
||||
- LSTM loss decrease during training can be quite different
|
||||
from what you see with CNNs/MLPs/etc. It's more or less a sigmoid
|
||||
instead of an inverse exponential.
|
||||
- LSTM loss decrease patterns during training can be quite different
|
||||
from what you see with CNNs/MLPs/etc.
|
||||
|
||||
GPU command:
|
||||
THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python imdb_lstm.py
|
||||
|
||||
250s/epoch on GPU (GT 650M), vs. 400s/epoch on CPU (2.4Ghz Core i7).
|
||||
'''
|
||||
|
||||
max_features=20000
|
||||
max_features = 20000
|
||||
maxlen = 100 # cut texts after this number of words (among top max_features most common words)
|
||||
batch_size = 16
|
||||
batch_size = 32
|
||||
|
||||
print("Loading data...")
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features, test_split=0.2)
|
||||
@@ -50,8 +48,8 @@ print('X_test shape:', X_test.shape)
|
||||
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, 256))
|
||||
model.add(LSTM(256, 128)) # try using a GRU instead, for fun
|
||||
model.add(Embedding(max_features, 128))
|
||||
model.add(LSTM(128, 128)) # try using a GRU instead, for fun
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(128, 1))
|
||||
model.add(Activation('sigmoid'))
|
||||
@@ -60,11 +58,7 @@ model.add(Activation('sigmoid'))
|
||||
model.compile(loss='binary_crossentropy', optimizer='adam', class_mode="binary")
|
||||
|
||||
print("Train...")
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=5, validation_split=0.1, show_accuracy=True)
|
||||
score = model.evaluate(X_test, y_test, batch_size=batch_size)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=4, validation_data=(X_test, y_test), show_accuracy=True)
|
||||
score, acc = model.evaluate(X_test, y_test, batch_size=batch_size, show_accuracy=True)
|
||||
print('Test score:', score)
|
||||
|
||||
classes = model.predict_classes(X_test, batch_size=batch_size)
|
||||
acc = np_utils.accuracy(classes, y_test)
|
||||
print('Test accuracy:', acc)
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
@@ -17,7 +18,7 @@ from sklearn.preprocessing import StandardScaler
|
||||
This demonstrates how to reach a score of 0.4890 (local validation)
|
||||
on the Kaggle Otto challenge, with a deep net using Keras.
|
||||
|
||||
Compatible Python 2.7-3.4
|
||||
Compatible Python 2.7-3.4. Requires Scikit-Learn and Pandas.
|
||||
|
||||
Recommended to run on GPU:
|
||||
Command: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python kaggle_otto_nn.py
|
||||
@@ -35,8 +36,6 @@ from sklearn.preprocessing import StandardScaler
|
||||
Get the data from Kaggle: https://www.kaggle.com/c/otto-group-product-classification-challenge/data
|
||||
'''
|
||||
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
def load_data(path, train=True):
|
||||
df = pd.read_csv(path)
|
||||
X = df.values.copy()
|
||||
@@ -121,4 +120,3 @@ print("Generating submission...")
|
||||
|
||||
proba = model.predict_proba(X_test)
|
||||
make_submission(proba, ids, encoder, fname='keras-otto.csv')
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
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.datasets.data_utils import get_file
|
||||
import numpy as np
|
||||
import random, sys
|
||||
|
||||
'''
|
||||
Example script to generate text from Nietzsche's writings.
|
||||
|
||||
At least 20 epochs are required before the generated text
|
||||
starts sounding coherent.
|
||||
|
||||
It is recommended to run this script on GPU, as recurrent
|
||||
networks are quite computationally intensive.
|
||||
|
||||
If you try this script on new data, make sure your corpus
|
||||
has at least ~100k characters. ~1M is better.
|
||||
'''
|
||||
|
||||
path = get_file('nietzsche.txt', origin="https://s3.amazonaws.com/text-datasets/nietzsche.txt")
|
||||
text = open(path).read().lower()
|
||||
print('corpus length:', len(text))
|
||||
|
||||
chars = 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))
|
||||
|
||||
# cut the text in semi-redundant sequences of maxlen characters
|
||||
maxlen = 20
|
||||
step = 3
|
||||
sentences = []
|
||||
next_chars = []
|
||||
for i in range(0, len(text) - maxlen, step):
|
||||
sentences.append(text[i : i + maxlen])
|
||||
next_chars.append(text[i + maxlen])
|
||||
print('nb sequences:', len(sentences))
|
||||
|
||||
print('Vectorization...')
|
||||
X = np.zeros((len(sentences), maxlen, len(chars)), dtype=np.bool)
|
||||
y = np.zeros((len(sentences), len(chars)), dtype=np.bool)
|
||||
for i, sentence in enumerate(sentences):
|
||||
for t, char in enumerate(sentence):
|
||||
X[i, t, char_indices[char]] = 1
|
||||
y[i, char_indices[next_chars[i]]] = 1
|
||||
|
||||
|
||||
# build the model: 2 stacked LSTM
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(LSTM(len(chars), 512, return_sequences=True))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(LSTM(512, 512, return_sequences=False))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Dense(512, len(chars)))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
# helper function to sample an index from a probability array
|
||||
def sample(a, diversity=0.75):
|
||||
if random.random() > diversity:
|
||||
return np.argmax(a)
|
||||
while 1:
|
||||
i = random.randint(0, len(a)-1)
|
||||
if a[i] > random.random():
|
||||
return i
|
||||
|
||||
# train the model, output generated text after each iteration
|
||||
for iteration in range(1, 60):
|
||||
print()
|
||||
print('-' * 50)
|
||||
print('Iteration', iteration)
|
||||
model.fit(X, y, batch_size=128, nb_epoch=1)
|
||||
|
||||
start_index = random.randint(0, len(text) - maxlen - 1)
|
||||
|
||||
for diversity in [0.2, 0.4, 0.6, 0.8]:
|
||||
print()
|
||||
print('----- diversity:', diversity)
|
||||
|
||||
generated = ''
|
||||
sentence = text[start_index : start_index + maxlen]
|
||||
generated += sentence
|
||||
print('----- Generating with seed: "' + sentence + '"')
|
||||
sys.stdout.write(generated)
|
||||
|
||||
for iteration in range(400):
|
||||
x = np.zeros((1, maxlen, len(chars)))
|
||||
for t, char in enumerate(sentence):
|
||||
x[0, t, char_indices[char]] = 1.
|
||||
|
||||
preds = model.predict(x, verbose=0)[0]
|
||||
next_index = sample(preds, diversity)
|
||||
next_char = indices_char[next_index]
|
||||
|
||||
generated += next_char
|
||||
sentence = sentence[1:] + next_char
|
||||
|
||||
sys.stdout.write(next_char)
|
||||
sys.stdout.flush()
|
||||
print()
|
||||
@@ -0,0 +1,64 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
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.utils import np_utils
|
||||
|
||||
'''
|
||||
Train a simple convnet on the MNIST dataset.
|
||||
|
||||
Run on GPU: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python mnist_cnn.py
|
||||
|
||||
Get to 99.25% test accuracy after 12 epochs (there is still a lot of margin for parameter tuning).
|
||||
16 seconds per epoch on a GRID K520 GPU.
|
||||
'''
|
||||
|
||||
batch_size = 128
|
||||
nb_classes = 10
|
||||
nb_epoch = 12
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, 28, 28)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, 28, 28)
|
||||
X_train = X_train.astype("float32")
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
print('X_train shape:', X_train.shape)
|
||||
print(X_train.shape[0], 'train samples')
|
||||
print(X_test.shape[0], 'test samples')
|
||||
|
||||
# convert class vectors to binary class matrices
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
model = Sequential()
|
||||
|
||||
model.add(Convolution2D(32, 1, 3, 3, border_mode='full'))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(32, 32, 3, 3))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(poolsize=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Flatten())
|
||||
model.add(Dense(32*196, 128))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.5))
|
||||
|
||||
model.add(Dense(128, nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='adadelta')
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=1, validation_data=(X_test, Y_test))
|
||||
score = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
|
||||
print('Test score:', score[0])
|
||||
print('Test accuracy:', score[1])
|
||||
@@ -0,0 +1,87 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.initializations import normal, identity
|
||||
from keras.layers.recurrent import SimpleRNN, LSTM
|
||||
from keras.optimizers import RMSprop
|
||||
from keras.utils import np_utils
|
||||
|
||||
'''
|
||||
This is a reproduction of the IRNN experiment
|
||||
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
|
||||
http://arxiv.org/pdf/1504.00941v2.pdf
|
||||
|
||||
Optimizer is replaced with RMSprop which yields more stable and steady
|
||||
improvement.
|
||||
|
||||
Reaches 0.93 train/test accuracy after 900 epochs (which roughly corresponds
|
||||
to 1687500 steps in the original paper.)
|
||||
'''
|
||||
|
||||
batch_size = 32
|
||||
nb_classes = 10
|
||||
nb_epochs = 200
|
||||
hidden_units = 100
|
||||
|
||||
learning_rate = 1e-6
|
||||
clip_norm = 1.0
|
||||
BPTT_truncate = 28*28
|
||||
|
||||
# the data, shuffled and split between train and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], -1, 1)
|
||||
X_test = X_test.reshape(X_test.shape[0], -1, 1)
|
||||
X_train = X_train.astype("float32")
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
print('X_train shape:', X_train.shape)
|
||||
print(X_train.shape[0], 'train samples')
|
||||
print(X_test.shape[0], 'test samples')
|
||||
|
||||
# convert class vectors to binary class matrices
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
print('Evaluate IRNN...')
|
||||
model = Sequential()
|
||||
model.add(SimpleRNN(input_dim=1, output_dim=hidden_units,
|
||||
init=lambda shape: normal(shape, scale=0.001),
|
||||
inner_init=lambda shape: identity(shape, scale=1.0),
|
||||
activation='relu', truncate_gradient=BPTT_truncate))
|
||||
model.add(Dense(hidden_units, nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
rmsprop = RMSprop(lr=learning_rate)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=rmsprop)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epochs,
|
||||
show_accuracy=True, verbose=1, validation_data=(X_test, Y_test))
|
||||
|
||||
scores = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
|
||||
print('IRNN test score:', scores[0])
|
||||
print('IRNN test accuracy:', scores[1])
|
||||
|
||||
print('Compare to LSTM...')
|
||||
model = Sequential()
|
||||
model.add(LSTM(1, hidden_units))
|
||||
model.add(Dense(hidden_units, nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
rmsprop = RMSprop(lr=learning_rate)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=rmsprop)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epochs,
|
||||
show_accuracy=True, verbose=1, validation_data=(X_test, Y_test))
|
||||
|
||||
scores = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
|
||||
print('LSTM test score:', scores[0])
|
||||
print('LSTM test accuracy:', scores[1])
|
||||
@@ -1,29 +1,32 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.regularizers import l2, l1
|
||||
from keras.constraints import maxnorm
|
||||
from keras.optimizers import SGD, Adam, RMSprop
|
||||
from keras.utils import np_utils
|
||||
import numpy as np
|
||||
|
||||
'''
|
||||
Train a simple deep NN on the MNIST dataset.
|
||||
|
||||
Get to 98.30% test accuracy after 20 epochs (there is *a lot* of margin for parameter tuning).
|
||||
2 seconds per epoch on a GRID K520 GPU.
|
||||
'''
|
||||
|
||||
batch_size = 64
|
||||
batch_size = 128
|
||||
nb_classes = 10
|
||||
nb_epoch = 20
|
||||
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(60000,784)
|
||||
X_test = X_test.reshape(10000,784)
|
||||
X_train = X_train.reshape(60000, 784)
|
||||
X_test = X_test.reshape(10000, 784)
|
||||
X_train = X_train.astype("float32")
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import reuters
|
||||
from keras.models import Sequential
|
||||
@@ -19,6 +20,7 @@ from keras.preprocessing.text import Tokenizer
|
||||
|
||||
max_words = 1000
|
||||
batch_size = 32
|
||||
nb_epoch = 5
|
||||
|
||||
print("Loading data...")
|
||||
(X_train, y_train), (X_test, y_test) = reuters.load_data(nb_words=max_words, test_split=0.2)
|
||||
@@ -43,15 +45,15 @@ print('Y_test shape:', Y_test.shape)
|
||||
|
||||
print("Building model...")
|
||||
model = Sequential()
|
||||
model.add(Dense(max_words, 256, init='normal'))
|
||||
model.add(Dense(max_words, 512))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(256, nb_classes, init='normal'))
|
||||
model.add(Dense(512, nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='adam')
|
||||
|
||||
history = model.fit(X_train, Y_train, nb_epoch=4, batch_size=batch_size, verbose=1, show_accuracy=True, validation_split=0.1)
|
||||
history = model.fit(X_train, Y_train, nb_epoch=nb_epoch, batch_size=batch_size, verbose=1, show_accuracy=True, validation_split=0.1)
|
||||
score = model.evaluate(X_test, Y_test, batch_size=batch_size, verbose=1, show_accuracy=True)
|
||||
print('Test score:', score[0])
|
||||
print('Test accuracy:', score[1])
|
||||
|
||||
@@ -53,6 +53,8 @@ load_model = False
|
||||
load_tokenizer = False
|
||||
train_model = True
|
||||
save_dir = os.path.expanduser("~/.keras/models")
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
model_load_fname = "HN_skipgram_model.pkl"
|
||||
model_save_fname = "HN_skipgram_model.pkl"
|
||||
tokenizer_fname = "HN_tokenizer.pkl"
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import types
|
||||
|
||||
def softmax(x):
|
||||
return T.nnet.softmax(x)
|
||||
return T.nnet.softmax(x.reshape((-1, x.shape[-1]))).reshape(x.shape)
|
||||
|
||||
def time_distributed_softmax(x):
|
||||
xshape = x.shape
|
||||
X = x.reshape((xshape[0] * xshape[1], xshape[2]))
|
||||
return T.nnet.softmax(X).reshape(xshape)
|
||||
import warnings
|
||||
warnings.warn("time_distributed_softmax is deprecated. Just use softmax!", DeprecationWarning)
|
||||
return softmax(x)
|
||||
|
||||
def softplus(x):
|
||||
return T.nnet.softplus(x)
|
||||
@@ -27,8 +25,11 @@ def hard_sigmoid(x):
|
||||
return T.nnet.hard_sigmoid(x)
|
||||
|
||||
def linear(x):
|
||||
'''
|
||||
The function returns the variable that is passed in, so all types work
|
||||
'''
|
||||
return x
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier):
|
||||
return get_from_module(identifier, globals(), 'activation function')
|
||||
return get_from_module(identifier, globals(), 'activation function')
|
||||
|
||||
+113
-68
@@ -4,7 +4,7 @@ import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
import warnings
|
||||
import time
|
||||
import time, json
|
||||
from collections import deque
|
||||
|
||||
from .utils.generic_utils import Progbar
|
||||
@@ -109,110 +109,155 @@ class BaseLogger(Callback):
|
||||
print('Epoch %d' % epoch)
|
||||
self.progbar = Progbar(target=self.params['nb_sample'], \
|
||||
verbose=self.verbose)
|
||||
self.current = 0
|
||||
self.tot_loss = 0.
|
||||
self.tot_acc = 0.
|
||||
self.seen = 0
|
||||
self.totals = {}
|
||||
|
||||
def on_batch_begin(self, batch, logs={}):
|
||||
if self.current < self.params['nb_sample']:
|
||||
if self.seen < self.params['nb_sample']:
|
||||
self.log_values = []
|
||||
|
||||
def on_batch_end(self, batch, logs={}):
|
||||
batch_size = logs.get('size', 0)
|
||||
self.current += batch_size
|
||||
self.seen += batch_size
|
||||
|
||||
for k, v in logs.items():
|
||||
if k in self.totals:
|
||||
self.totals[k] += v * batch_size
|
||||
else:
|
||||
self.totals[k] = v * batch_size
|
||||
for k in self.params['metrics']:
|
||||
if k in logs:
|
||||
self.log_values.append((k, logs[k]))
|
||||
|
||||
loss = logs.get('loss')
|
||||
self.log_values.append(('loss', loss))
|
||||
self.tot_loss += loss * batch_size
|
||||
if self.params['show_accuracy']:
|
||||
accuracy = logs.get('accuracy')
|
||||
self.log_values.append(('acc.', accuracy))
|
||||
self.tot_acc += accuracy * batch_size
|
||||
# skip progbar update for the last batch; will be handled by on_epoch_end
|
||||
if self.verbose and self.current < self.params['nb_sample']:
|
||||
self.progbar.update(self.current, self.log_values)
|
||||
if self.verbose and self.seen < self.params['nb_sample']:
|
||||
self.progbar.update(self.seen, self.log_values)
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
self.log_values.append(('loss', self.tot_loss / self.current))
|
||||
if self.params['show_accuracy']:
|
||||
self.log_values.append(('acc.', self.tot_acc / self.current))
|
||||
if self.params['do_validation']:
|
||||
val_loss = logs.get('val_loss')
|
||||
self.log_values.append(('val. loss', val_loss))
|
||||
if self.params['show_accuracy']:
|
||||
val_acc = logs.get('val_accuracy')
|
||||
self.log_values.append(('val. acc.', val_acc))
|
||||
self.progbar.update(self.current, self.log_values)
|
||||
for k in self.params['metrics']:
|
||||
if k in self.totals:
|
||||
self.log_values.append((k, self.totals[k] / self.seen))
|
||||
if k in logs:
|
||||
self.log_values.append((k, logs[k]))
|
||||
if self.verbose:
|
||||
self.progbar.update(self.seen, self.log_values)
|
||||
|
||||
|
||||
class History(Callback):
|
||||
|
||||
def on_train_begin(self, logs={}):
|
||||
self.epoch = []
|
||||
self.loss = []
|
||||
if self.params['show_accuracy']:
|
||||
self.accuracy = []
|
||||
if self.params['do_validation']:
|
||||
self.validation_loss = []
|
||||
if self.params['show_accuracy']:
|
||||
self.validation_accuracy = []
|
||||
self.history = {}
|
||||
|
||||
def on_epoch_begin(self, epoch, logs={}):
|
||||
self.seen = 0
|
||||
self.tot_loss = 0.
|
||||
self.tot_accuracy = 0.
|
||||
self.totals = {}
|
||||
|
||||
def on_batch_end(self, batch, logs={}):
|
||||
batch_size = logs.get('size', 0)
|
||||
self.seen += batch_size
|
||||
self.tot_loss += logs.get('loss', 0.) * batch_size
|
||||
if self.params['show_accuracy']:
|
||||
self.tot_accuracy += logs.get('accuracy', 0.) * batch_size
|
||||
for k, v in logs.items():
|
||||
if k in self.totals:
|
||||
self.totals[k] += v * batch_size
|
||||
else:
|
||||
self.totals[k] = v * batch_size
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
val_loss = logs.get('val_loss')
|
||||
val_acc = logs.get('val_accuracy')
|
||||
self.epoch.append(epoch)
|
||||
self.loss.append(self.tot_loss / self.seen)
|
||||
if self.params['show_accuracy']:
|
||||
self.accuracy.append(self.tot_accuracy / self.seen)
|
||||
if self.params['do_validation']:
|
||||
self.validation_loss.append(val_loss)
|
||||
if self.params['show_accuracy']:
|
||||
self.validation_accuracy.append(val_acc)
|
||||
for k, v in self.totals.items():
|
||||
if k not in self.history:
|
||||
self.history[k] = []
|
||||
self.history[k].append(v / self.seen)
|
||||
|
||||
for k, v in logs.items():
|
||||
if k not in self.history:
|
||||
self.history[k] = []
|
||||
self.history[k].append(v)
|
||||
|
||||
|
||||
class ModelCheckpoint(Callback):
|
||||
def __init__(self, filepath, verbose=0, save_best_only=False):
|
||||
def __init__(self, filepath, monitor='val_loss', verbose=0, save_best_only=False):
|
||||
super(Callback, self).__init__()
|
||||
|
||||
self.monitor = monitor
|
||||
self.verbose = verbose
|
||||
self.filepath = filepath
|
||||
self.save_best_only = save_best_only
|
||||
self.loss = []
|
||||
self.best_loss = np.Inf
|
||||
self.val_loss = []
|
||||
self.best_val_loss = np.Inf
|
||||
self.best = np.Inf
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
'''currently, on_epoch_end receives epoch_logs from keras.models.Sequential.fit
|
||||
which does only contain, if at all, the validation loss and validation accuracy'''
|
||||
if self.save_best_only and self.params['do_validation']:
|
||||
cur_val_loss = logs.get('val_loss')
|
||||
self.val_loss.append(cur_val_loss)
|
||||
if cur_val_loss < self.best_val_loss:
|
||||
if self.verbose > 0:
|
||||
print("Epoch %05d: valdidation loss improved from %0.5f to %0.5f, saving model to %s"
|
||||
% (epoch, self.best_val_loss, cur_val_loss, self.filepath))
|
||||
self.best_val_loss = cur_val_loss
|
||||
self.model.save_weights(self.filepath, overwrite=True)
|
||||
if self.save_best_only:
|
||||
current = logs.get(self.monitor)
|
||||
if current is None:
|
||||
warnings.warn("Can save best model only with %s available, skipping." % (self.monitor), RuntimeWarning)
|
||||
else:
|
||||
if self.verbose > 0:
|
||||
print("Epoch %05d: validation loss did not improve" % (epoch))
|
||||
elif self.save_best_only and not self.params['do_validation']:
|
||||
import warnings
|
||||
warnings.warn("Can save best model only with validation data, skipping", RuntimeWarning)
|
||||
elif not self.save_best_only:
|
||||
if current < self.best:
|
||||
if self.verbose > 0:
|
||||
print("Epoch %05d: %s improved from %0.5f to %0.5f, saving model to %s"
|
||||
% (epoch, self.monitor, self.best, current, self.filepath))
|
||||
self.best = current
|
||||
self.model.save_weights(self.filepath, overwrite=True)
|
||||
else:
|
||||
if self.verbose > 0:
|
||||
print("Epoch %05d: %s did not improve" % (epoch, self.monitor))
|
||||
else:
|
||||
if self.verbose > 0:
|
||||
print("Epoch %05d: saving model to %s" % (epoch, self.filepath))
|
||||
self.model.save_weights(self.filepath, overwrite=True)
|
||||
|
||||
|
||||
class EarlyStopping(Callback):
|
||||
def __init__(self, monitor='val_loss', patience=0, verbose=0):
|
||||
super(Callback, self).__init__()
|
||||
|
||||
self.monitor = monitor
|
||||
self.patience = patience
|
||||
self.verbose = verbose
|
||||
self.best = np.Inf
|
||||
self.wait = 0
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
current = logs.get(self.monitor)
|
||||
if current is None:
|
||||
warnings.warn("Early stopping requires %s available!" % (self.monitor), RuntimeWarning)
|
||||
|
||||
if current < self.best:
|
||||
self.best = current
|
||||
self.wait = 0
|
||||
else:
|
||||
if self.wait >= self.patience:
|
||||
if self.verbose > 0:
|
||||
print("Epoch %05d: early stopping" % (epoch))
|
||||
self.model.stop_training = True
|
||||
self.wait += 1
|
||||
|
||||
|
||||
class RemoteMonitor(Callback):
|
||||
def __init__(self, root='http://localhost:9000'):
|
||||
self.root = root
|
||||
|
||||
def on_epoch_begin(self, epoch, logs={}):
|
||||
self.seen = 0
|
||||
self.totals = {}
|
||||
|
||||
|
||||
def on_batch_end(self, batch, logs={}):
|
||||
batch_size = logs.get('size', 0)
|
||||
self.seen += batch_size
|
||||
for k, v in logs.items():
|
||||
if k in self.totals:
|
||||
self.totals[k] += v * batch_size
|
||||
else:
|
||||
self.totals[k] = v * batch_size
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
import requests
|
||||
send = {}
|
||||
send['epoch'] = epoch
|
||||
|
||||
for k, v in self.totals.items():
|
||||
send[k] = v / self.seen
|
||||
for k, v in self.logs:
|
||||
send[k] = v
|
||||
|
||||
r = requests.post(self.root + '/publish/epoch/end/', {'data':json.dumps(send)})
|
||||
|
||||
+32
-11
@@ -3,20 +3,41 @@ import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
def maxnorm(m=2):
|
||||
def maxnorm_wrap(p):
|
||||
class Constraint(object):
|
||||
def __call__(self, p):
|
||||
return p
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__}
|
||||
|
||||
class MaxNorm(Constraint):
|
||||
def __init__(self, m=2):
|
||||
self.m = m
|
||||
|
||||
def __call__(self, p):
|
||||
norms = T.sqrt(T.sum(T.sqr(p), axis=0))
|
||||
desired = T.clip(norms, 0, m)
|
||||
desired = T.clip(norms, 0, self.m)
|
||||
p = p * (desired / (1e-7 + norms))
|
||||
return p
|
||||
return maxnorm_wrap
|
||||
|
||||
def nonneg(p):
|
||||
p *= T.ge(p, 0)
|
||||
return p
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"m":self.m}
|
||||
|
||||
def identity(g):
|
||||
return g
|
||||
class NonNeg(Constraint):
|
||||
def __call__(self, p):
|
||||
p *= T.ge(p, 0)
|
||||
return p
|
||||
|
||||
def unitnorm(e):
|
||||
return e / T.sqrt(T.sum(e**2, axis=-1, keepdims=True))
|
||||
class UnitNorm(Constraint):
|
||||
def __call__(self, p):
|
||||
return p / T.sqrt(T.sum(p**2, axis=-1, keepdims=True))
|
||||
|
||||
identity = Constraint
|
||||
maxnorm = MaxNorm
|
||||
nonneg = NonNeg
|
||||
unitnorm = UnitNorm
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'constraint', instantiate=True, kwargs=kwargs)
|
||||
@@ -4,8 +4,11 @@ import gzip
|
||||
from .data_utils import get_file
|
||||
import random
|
||||
from six.moves import zip
|
||||
import numpy as np
|
||||
|
||||
def load_data(path="imdb.pkl", nb_words=None, skip_top=0, maxlen=None, test_split=0.2, seed=113,
|
||||
start_char=1, oov_char=2, index_from=3):
|
||||
|
||||
def load_data(path="imdb.pkl", nb_words=None, skip_top=0, maxlen=None, test_split=0.2, seed=113):
|
||||
path = get_file(path, origin="https://s3.amazonaws.com/text-datasets/imdb.pkl")
|
||||
|
||||
if path.endswith(".gz"):
|
||||
@@ -16,10 +19,15 @@ def load_data(path="imdb.pkl", nb_words=None, skip_top=0, maxlen=None, test_spli
|
||||
X, labels = six.moves.cPickle.load(f)
|
||||
f.close()
|
||||
|
||||
random.seed(seed)
|
||||
random.shuffle(X)
|
||||
random.seed(seed)
|
||||
random.shuffle(labels)
|
||||
np.random.seed(seed)
|
||||
np.random.shuffle(X)
|
||||
np.random.seed(seed)
|
||||
np.random.shuffle(labels)
|
||||
|
||||
if start_char is not None:
|
||||
X = [[start_char] + [w + index_from for w in x] for x in X]
|
||||
elif index_from:
|
||||
X = [[w + index_from for w in x] for x in X]
|
||||
|
||||
if maxlen:
|
||||
new_X = []
|
||||
@@ -34,7 +42,20 @@ def load_data(path="imdb.pkl", nb_words=None, skip_top=0, maxlen=None, test_spli
|
||||
if not nb_words:
|
||||
nb_words = max([max(x) for x in X])
|
||||
|
||||
X = [[0 if (w >= nb_words or w < skip_top) else w for w in x] for x in X]
|
||||
# by convention, use 2 as OOV word
|
||||
# reserve 'index_from' (=3 by default) characters: 0 (padding), 1 (start), 2 (OOV)
|
||||
if oov_char is not None:
|
||||
X = [[oov_char if (w >= nb_words or w < skip_top) else w for w in x] for x in X]
|
||||
else:
|
||||
nX = []
|
||||
for x in X:
|
||||
nx = []
|
||||
for w in x:
|
||||
if (w >= nb_words or w < skip_top):
|
||||
nx.append(w)
|
||||
nX.append(nx)
|
||||
X = nX
|
||||
|
||||
X_train = X[:int(len(X)*(1-test_split))]
|
||||
y_train = labels[:int(len(X)*(1-test_split))]
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import random
|
||||
import os
|
||||
import six.moves.cPickle
|
||||
from six.moves import zip
|
||||
import numpy as np
|
||||
|
||||
def make_reuters_dataset(path=os.path.join('datasets', 'temp', 'reuters21578'), min_samples_per_topic=15):
|
||||
import re
|
||||
@@ -18,7 +19,7 @@ def make_reuters_dataset(path=os.path.join('datasets', 'temp', 'reuters21578'),
|
||||
|
||||
for fname in os.listdir(path):
|
||||
if 'sgm' in fname:
|
||||
s = open(path + fname).read()
|
||||
s = open(os.path.join(path, fname)).read()
|
||||
tag = '<TOPICS>'
|
||||
while tag in s:
|
||||
s = s[s.find(tag)+len(tag):]
|
||||
@@ -70,25 +71,36 @@ def make_reuters_dataset(path=os.path.join('datasets', 'temp', 'reuters21578'),
|
||||
print('Sanity check:')
|
||||
for w in ["banana", "oil", "chocolate", "the", "dsft"]:
|
||||
print('...index of', w, ':', tokenizer.word_index.get(w))
|
||||
print('text reconstruction:')
|
||||
reverse_word_index = dict([(v, k) for k, v in tokenizer.word_index.items()])
|
||||
print(' '.join(reverse_word_index[i] for i in X[10]))
|
||||
|
||||
dataset = (X, labels)
|
||||
print('-')
|
||||
print('Saving...')
|
||||
six.moves.cPickle.dump(dataset, open(os.path.join('datasets', 'data', 'reuters.pkl'), 'w'))
|
||||
six.moves.cPickle.dump(tokenizer.word_index, open(os.path.join('datasets','data', 'reuters_word_index.pkl'), 'w'))
|
||||
six.moves.cPickle.dump(tokenizer.word_index, open(os.path.join('datasets', 'data', 'reuters_word_index.pkl'), 'w'))
|
||||
|
||||
|
||||
|
||||
def load_data(path="reuters.pkl", nb_words=None, skip_top=0, maxlen=None, test_split=0.2, seed=113):
|
||||
def load_data(path="reuters.pkl", nb_words=None, skip_top=0, maxlen=None, test_split=0.2, seed=113,
|
||||
start_char=1, oov_char=2, index_from=3):
|
||||
|
||||
path = get_file(path, origin="https://s3.amazonaws.com/text-datasets/reuters.pkl")
|
||||
f = open(path, 'rb')
|
||||
|
||||
X, labels = six.moves.cPickle.load(f)
|
||||
f.close()
|
||||
random.seed(seed)
|
||||
random.shuffle(X)
|
||||
random.seed(seed)
|
||||
random.shuffle(labels)
|
||||
|
||||
np.random.seed(seed)
|
||||
np.random.shuffle(X)
|
||||
np.random.seed(seed)
|
||||
np.random.shuffle(labels)
|
||||
|
||||
if start_char is not None:
|
||||
X = [[start_char] + [w + index_from for w in x] for x in X]
|
||||
elif index_from:
|
||||
X = [[w + index_from for w in x] for x in X]
|
||||
|
||||
if maxlen:
|
||||
new_X = []
|
||||
@@ -103,7 +115,20 @@ def load_data(path="reuters.pkl", nb_words=None, skip_top=0, maxlen=None, test_s
|
||||
if not nb_words:
|
||||
nb_words = max([max(x) for x in X])
|
||||
|
||||
X = [[0 if (w >= nb_words or w < skip_top) else w for w in x] for x in X]
|
||||
# by convention, use 2 as OOV word
|
||||
# reserve 'index_from' (=3 by default) characters: 0 (padding), 1 (start), 2 (OOV)
|
||||
if oov_char is not None:
|
||||
X = [[oov_char if (w >= nb_words or w < skip_top) else w for w in x] for x in X]
|
||||
else:
|
||||
nX = []
|
||||
for x in X:
|
||||
nx = []
|
||||
for w in x:
|
||||
if (w >= nb_words or w < skip_top):
|
||||
nx.append(w)
|
||||
nX.append(nx)
|
||||
X = nX
|
||||
|
||||
X_train = X[:int(len(X)*(1-test_split))]
|
||||
y_train = labels[:int(len(X)*(1-test_split))]
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
from .utils.theano_utils import sharedX, shared_zeros
|
||||
from .utils.theano_utils import sharedX, shared_zeros, shared_ones
|
||||
|
||||
def get_fans(shape):
|
||||
fan_in = shape[0] if len(shape) == 2 else np.prod(shape[1:])
|
||||
@@ -22,7 +22,7 @@ def lecun_uniform(shape):
|
||||
http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
|
||||
'''
|
||||
fan_in, fan_out = get_fans(shape)
|
||||
scale = 1./np.sqrt(fan_in)
|
||||
scale = np.sqrt(3. / fan_in)
|
||||
return uniform(shape, scale)
|
||||
|
||||
def glorot_normal(shape):
|
||||
@@ -34,7 +34,7 @@ def glorot_normal(shape):
|
||||
|
||||
def glorot_uniform(shape):
|
||||
fan_in, fan_out = get_fans(shape)
|
||||
s = np.sqrt(2. / (fan_in + fan_out))
|
||||
s = np.sqrt(6. / (fan_in + fan_out))
|
||||
return uniform(shape, s)
|
||||
|
||||
def he_normal(shape):
|
||||
@@ -46,7 +46,7 @@ def he_normal(shape):
|
||||
|
||||
def he_uniform(shape):
|
||||
fan_in, fan_out = get_fans(shape)
|
||||
s = np.sqrt(2. / fan_in)
|
||||
s = np.sqrt(6. / fan_in)
|
||||
return uniform(shape, s)
|
||||
|
||||
def orthogonal(shape, scale=1.1):
|
||||
@@ -59,9 +59,18 @@ def orthogonal(shape, scale=1.1):
|
||||
q = q.reshape(shape)
|
||||
return sharedX(scale * q[:shape[0], :shape[1]])
|
||||
|
||||
def identity(shape, scale=1):
|
||||
if len(shape) != 2 or shape[0] != shape[1]:
|
||||
raise Exception("Identity matrix initialization can only be used for 2D square matrices")
|
||||
else:
|
||||
return sharedX(scale * np.identity(shape[0]))
|
||||
|
||||
def zero(shape):
|
||||
return shared_zeros(shape)
|
||||
|
||||
def one(shape):
|
||||
return shared_ones(shape)
|
||||
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier):
|
||||
|
||||
+158
-10
@@ -1,8 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import theano.tensor as T
|
||||
from ..layers.core import Layer
|
||||
from ..layers.core import Layer, Merge
|
||||
from six.moves import range
|
||||
|
||||
def ndim_tensor(ndim):
|
||||
@@ -15,22 +16,32 @@ def ndim_tensor(ndim):
|
||||
return T.matrix()
|
||||
|
||||
class Sequential(Layer):
|
||||
'''
|
||||
Simple linear stack of layers.
|
||||
|
||||
inherited from Layer:
|
||||
- get_params
|
||||
- get_output_mask
|
||||
- supports_masked_input
|
||||
'''
|
||||
|
||||
def __init__(self, layers=[]):
|
||||
self.layers = []
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
|
||||
for layer in layers:
|
||||
self.add(layer)
|
||||
|
||||
def connect(self, layer):
|
||||
def set_previous(self, layer):
|
||||
self.layers[0].previous = layer
|
||||
|
||||
def add(self, layer):
|
||||
self.layers.append(layer)
|
||||
if len(self.layers) > 1:
|
||||
self.layers[-1].connect(self.layers[-2])
|
||||
|
||||
self.layers[-1].set_previous(self.layers[-2])
|
||||
|
||||
params, regularizers, constraints = layer.get_params()
|
||||
self.params += params
|
||||
self.regularizers += regularizers
|
||||
@@ -39,13 +50,16 @@ class Sequential(Layer):
|
||||
def get_output(self, train=False):
|
||||
return self.layers[-1].get_output(train)
|
||||
|
||||
def set_input(self):
|
||||
for l in self.layers:
|
||||
if hasattr(l, 'input'):
|
||||
ndim = l.input.ndim
|
||||
self.layers[0].input = ndim_tensor(ndim)
|
||||
break
|
||||
|
||||
def get_input(self, train=False):
|
||||
if not hasattr(self.layers[0], 'input'):
|
||||
for l in self.layers:
|
||||
if hasattr(l, 'input'):
|
||||
break
|
||||
ndim = l.input.ndim
|
||||
self.layers[0].input = ndim_tensor(ndim)
|
||||
self.set_input()
|
||||
return self.layers[0].get_input(train)
|
||||
|
||||
@property
|
||||
@@ -66,4 +80,138 @@ class Sequential(Layer):
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"layers":[layer.get_config() for layer in self.layers]}
|
||||
"layers":[layer.get_config() for layer in self.layers]}
|
||||
|
||||
|
||||
class Graph(Layer):
|
||||
'''
|
||||
Implement a NN graph with arbitrary layer connections,
|
||||
arbitrary number of inputs and arbitrary number of outputs.
|
||||
|
||||
Note: Graph can only be used as a layer
|
||||
(connect, input, get_input, get_output)
|
||||
when it has exactly one input and one output.
|
||||
|
||||
inherited from Layer:
|
||||
- get_params
|
||||
- get_output_mask
|
||||
- supports_masked_input
|
||||
- get_weights
|
||||
- set_weights
|
||||
'''
|
||||
def __init__(self):
|
||||
self.namespace = set() # strings
|
||||
self.nodes = {} # layer-like
|
||||
self.inputs = {} # layer-like
|
||||
self.input_order = [] # strings
|
||||
self.outputs = {} # layer-like
|
||||
self.output_order = [] # strings
|
||||
self.input_config = [] # dicts
|
||||
self.output_config = [] # dicts
|
||||
self.node_config = [] # dicts
|
||||
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
|
||||
def set_previous(self, layer):
|
||||
if len(self.inputs) != 1 or len(self.outputs) != 1:
|
||||
raise Exception('The Graph container can only be used as a layer \
|
||||
when it has exactly one input and one output.')
|
||||
self.inputs[self.input_order[0]].set_previous(layer)
|
||||
|
||||
def get_input(self, train=False):
|
||||
if len(self.inputs) != 1 or len(self.outputs) != 1:
|
||||
raise Exception('The Graph container can only be used as a layer \
|
||||
when it has exactly one input and one output.')
|
||||
return self.inputs[self.input_order[0]].get_input(train)
|
||||
|
||||
@property
|
||||
def input(self):
|
||||
return self.get_input()
|
||||
|
||||
def get_output(self, train=False):
|
||||
if len(self.inputs) != 1 or len(self.outputs) != 1:
|
||||
raise Exception('The Graph container can only be used as a layer \
|
||||
when it has exactly one input and one output.')
|
||||
return self.outputs[self.output_order[0]].get_output(train)
|
||||
|
||||
def add_input(self, name, ndim=2, dtype='float'):
|
||||
if name in self.namespace:
|
||||
raise Exception('Duplicate node identifier: ' + name)
|
||||
self.namespace.add(name)
|
||||
self.input_order.append(name)
|
||||
layer = Layer() # empty layer
|
||||
if dtype == 'float':
|
||||
layer.input = ndim_tensor(ndim)
|
||||
else:
|
||||
if ndim == 2:
|
||||
layer.input = T.imatrix()
|
||||
else:
|
||||
raise Exception('Type "int" can only be used with ndim==2.')
|
||||
layer.input.name = name
|
||||
self.inputs[name] = layer
|
||||
self.input_config.append({'name':name, 'ndim':ndim, 'dtype':dtype})
|
||||
|
||||
def add_node(self, layer, name, input=None, inputs=[], merge_mode='concat'):
|
||||
if hasattr(layer, 'set_name'):
|
||||
layer.set_name(name)
|
||||
if name in self.namespace:
|
||||
raise Exception('Duplicate node identifier: ' + name)
|
||||
if input:
|
||||
if input not in self.namespace:
|
||||
raise Exception('Unknown identifier: ' + input)
|
||||
if input in self.nodes:
|
||||
layer.set_previous(self.nodes[input])
|
||||
elif input in self.inputs:
|
||||
layer.set_previous(self.inputs[input])
|
||||
if inputs:
|
||||
to_merge = []
|
||||
for n in inputs:
|
||||
if n in self.nodes:
|
||||
to_merge.append(self.nodes[n])
|
||||
elif n in self.inputs:
|
||||
to_merge.append(self.inputs[n])
|
||||
else:
|
||||
raise Exception('Unknown identifier: ' + n)
|
||||
merge = Merge(to_merge, mode=merge_mode)
|
||||
layer.set_previous(merge)
|
||||
|
||||
self.namespace.add(name)
|
||||
self.nodes[name] = layer
|
||||
self.node_config.append({'name':name, 'input':input, 'inputs':inputs, 'merge_mode':merge_mode})
|
||||
params, regularizers, constraints = layer.get_params()
|
||||
self.params += params
|
||||
self.regularizers += regularizers
|
||||
self.constraints += constraints
|
||||
|
||||
def add_output(self, name, input=None, inputs=[], merge_mode='concat'):
|
||||
if name in self.namespace:
|
||||
raise Exception('Duplicate node identifier: ' + name)
|
||||
if input:
|
||||
if input not in self.namespace:
|
||||
raise Exception('Unknown identifier: ' + input)
|
||||
if input in self.nodes:
|
||||
self.outputs[name] = self.nodes[input]
|
||||
elif input in self.inputs:
|
||||
self.ouputs[name] = self.inputs[input]
|
||||
if inputs:
|
||||
to_merge = []
|
||||
for n in inputs:
|
||||
if n not in self.nodes:
|
||||
raise Exception('Unknown identifier: ' + n)
|
||||
to_merge.append(self.nodes[n])
|
||||
merge = Merge(to_merge, mode=merge_mode)
|
||||
self.outputs[name] = merge
|
||||
self.namespace.add(name)
|
||||
self.output_order.append(name)
|
||||
self.output_config.append({'name':name, 'input':input, 'inputs':inputs, 'merge_mode':merge_mode})
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_config":self.input_config,
|
||||
"node_config":self.node_config,
|
||||
"output_config":self.output_config,
|
||||
"input_order":self.input_order,
|
||||
"output_order":self.output_order,
|
||||
"nodes":dict([(c["name"], self.nodes[c["name"]].get_config()) for c in self.node_config])}
|
||||
|
||||
+129
-52
@@ -5,98 +5,130 @@ import theano
|
||||
import theano.tensor as T
|
||||
from theano.tensor.signal import downsample
|
||||
|
||||
from .. import activations, initializations
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..utils.theano_utils import shared_zeros
|
||||
from ..layers.core import Layer
|
||||
|
||||
|
||||
class Convolution1D(Layer):
|
||||
def __init__(self, nb_filter, stack_size, filter_length,
|
||||
def __init__(self, input_dim, nb_filter, filter_length,
|
||||
init='uniform', activation='linear', weights=None,
|
||||
image_shape=None, border_mode='valid', subsample_length=1,
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
border_mode='valid', subsample_length=1,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
|
||||
nb_row = 1
|
||||
nb_col = filter_length
|
||||
|
||||
if border_mode not in {'valid', 'full'}:
|
||||
raise Exception('Invalid border mode for Convolution1D:', border_mode)
|
||||
|
||||
super(Convolution1D,self).__init__()
|
||||
self.nb_filter = nb_filter
|
||||
self.stack_size = stack_size
|
||||
self.input_dim = input_dim
|
||||
self.filter_length = filter_length
|
||||
self.subsample_length = subsample_length
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
self.subsample = (1, subsample_length)
|
||||
self.border_mode = border_mode
|
||||
self.image_shape = image_shape
|
||||
|
||||
self.input = T.tensor4()
|
||||
self.W_shape = (nb_filter, stack_size, nb_row, nb_col)
|
||||
self.input = T.tensor3()
|
||||
self.W_shape = (nb_filter, input_dim, filter_length, 1)
|
||||
self.W = self.init(self.W_shape)
|
||||
self.b = shared_zeros((nb_filter,))
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
|
||||
self.regularizers = [W_regularizer, b_regularizer]
|
||||
self.constraints = [W_constraint, b_constraint]
|
||||
self.regularizers = []
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
self.constraints = [self.W_constraint, self.b_constraint]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
|
||||
conv_out = theano.tensor.nnet.conv.conv2d(X, self.W,
|
||||
border_mode=self.border_mode, subsample=self.subsample, image_shape=self.image_shape)
|
||||
X = theano.tensor.reshape(X, (X.shape[0], X.shape[1], X.shape[2], 1)).dimshuffle(0, 2, 1, 3)
|
||||
conv_out = theano.tensor.nnet.conv.conv2d(X, self.W, border_mode=self.border_mode, subsample=self.subsample)
|
||||
output = self.activation(conv_out + self.b.dimshuffle('x', 0, 'x', 'x'))
|
||||
return output
|
||||
return theano.tensor.reshape(output, (output.shape[0], output.shape[1], output.shape[2])).dimshuffle(0, 2, 1)
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_dim":self.input_dim,
|
||||
"nb_filter":self.nb_filter,
|
||||
"stack_size":self.stack_size,
|
||||
"filter_length":self.filter_length,
|
||||
"init":self.init.__name__,
|
||||
"activation":self.activation.__name__,
|
||||
"image_shape":self.image_shape,
|
||||
"border_mode":self.border_mode,
|
||||
"subsample_length":self.subsample_length}
|
||||
"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}
|
||||
|
||||
|
||||
class MaxPooling1D(Layer):
|
||||
def __init__(self, pool_length=2, ignore_border=True):
|
||||
def __init__(self, pool_length=2, stride=None, ignore_border=True):
|
||||
super(MaxPooling1D,self).__init__()
|
||||
self.pool_length = pool_length
|
||||
self.stride = stride
|
||||
if self.stride:
|
||||
self.st = (1, self.stride)
|
||||
else:
|
||||
self.st = None
|
||||
|
||||
self.input = T.tensor3()
|
||||
self.poolsize = (1, pool_length)
|
||||
self.ignore_border = ignore_border
|
||||
|
||||
self.input = T.tensor4()
|
||||
self.params = []
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
output = downsample.max_pool_2d(X, self.poolsize, ignore_border=self.ignore_border)
|
||||
return output
|
||||
X = theano.tensor.reshape(X, (X.shape[0], X.shape[1], X.shape[2], 1)).dimshuffle(0, 1, 3, 2)
|
||||
output = downsample.max_pool_2d(X, ds=self.poolsize, st=self.st, ignore_border=self.ignore_border)
|
||||
output = output.dimshuffle(0, 1, 3, 2)
|
||||
return theano.tensor.reshape(output, (output.shape[0], output.shape[1], output.shape[2]))
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"pool_length":self.pool_length,
|
||||
"ignore_border":self.ignore_border}
|
||||
"stride":self.stride,
|
||||
"pool_length":self.pool_length,
|
||||
"ignore_border":self.ignore_border,
|
||||
"subsample_length": self.subsample_length}
|
||||
|
||||
|
||||
|
||||
class Convolution2D(Layer):
|
||||
def __init__(self, nb_filter, stack_size, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
image_shape=None, border_mode='valid', subsample=(1,1),
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
super(Convolution2D,self).__init__()
|
||||
def __init__(self, nb_filter, stack_size, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
|
||||
if border_mode not in {'valid', 'full', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution2D:', border_mode)
|
||||
|
||||
super(Convolution2D,self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
self.subsample = subsample
|
||||
self.border_mode = border_mode
|
||||
self.image_shape = image_shape
|
||||
self.nb_filter = nb_filter
|
||||
self.stack_size = stack_size
|
||||
|
||||
self.nb_row = nb_row
|
||||
self.nb_col = nb_col
|
||||
|
||||
@@ -107,19 +139,46 @@ class Convolution2D(Layer):
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
|
||||
self.regularizers = [W_regularizer, b_regularizer]
|
||||
self.constraints = [W_constraint, b_constraint]
|
||||
self.regularizers = []
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
self.constraints = [self.W_constraint, self.b_constraint]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
border_mode = self.border_mode
|
||||
if border_mode == 'same':
|
||||
border_mode = 'full'
|
||||
|
||||
conv_out = theano.tensor.nnet.conv.conv2d(X, self.W,
|
||||
border_mode=border_mode, subsample=self.subsample)
|
||||
|
||||
if self.border_mode == 'same':
|
||||
shift_x = (self.nb_row - 1) // 2
|
||||
shift_y = (self.nb_col - 1) // 2
|
||||
conv_out = conv_out[:, :, shift_x:X.shape[2] + shift_x, shift_y:X.shape[3] + shift_y]
|
||||
|
||||
return self.activation(conv_out + self.b.dimshuffle('x', 0, 'x', 'x'))
|
||||
|
||||
conv_out = theano.tensor.nnet.conv.conv2d(X, self.W,
|
||||
border_mode=self.border_mode, subsample=self.subsample, image_shape=self.image_shape)
|
||||
output = self.activation(conv_out + self.b.dimshuffle('x', 0, 'x', 'x'))
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
@@ -129,33 +188,51 @@ class Convolution2D(Layer):
|
||||
"nb_col":self.nb_col,
|
||||
"init":self.init.__name__,
|
||||
"activation":self.activation.__name__,
|
||||
"image_shape":self.image_shape,
|
||||
"border_mode":self.border_mode,
|
||||
"subsample":self.subsample}
|
||||
"subsample":self.subsample,
|
||||
"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}
|
||||
|
||||
|
||||
class MaxPooling2D(Layer):
|
||||
def __init__(self, poolsize=(2, 2), ignore_border=True):
|
||||
def __init__(self, poolsize=(2, 2), stride=None, ignore_border=True):
|
||||
super(MaxPooling2D,self).__init__()
|
||||
self.input = T.tensor4()
|
||||
self.poolsize = poolsize
|
||||
self.stride = stride
|
||||
self.ignore_border = ignore_border
|
||||
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
output = downsample.max_pool_2d(X, self.poolsize, ignore_border=self.ignore_border)
|
||||
output = downsample.max_pool_2d(X, ds=self.poolsize, st=self.stride, ignore_border=self.ignore_border)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"poolsize":self.poolsize,
|
||||
"ignore_border":self.ignore_border}
|
||||
"poolsize":self.poolsize,
|
||||
"ignore_border":self.ignore_border,
|
||||
"stride": self.stride}
|
||||
|
||||
|
||||
class ZeroPadding2D(Layer):
|
||||
def __init__(self, width=1):
|
||||
super(ZeroPadding2D, self).__init__()
|
||||
self.width = width
|
||||
self.input = T.tensor4()
|
||||
|
||||
# class ZeroPadding2D(Layer): TODO
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
width = self.width
|
||||
in_shape = X.shape
|
||||
out_shape = (in_shape[0], in_shape[1], in_shape[2] + 2 * width, in_shape[3] + 2 * width)
|
||||
out = T.zeros(out_shape)
|
||||
indices = (slice(None), slice(None), slice(width, in_shape[2] + width), slice(width, in_shape[3] + width))
|
||||
return T.set_subtensor(out[indices], X)
|
||||
|
||||
# class Convolution3D: TODO
|
||||
|
||||
# class MaxPooling3D: TODO
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"width":self.width}
|
||||
|
||||
+248
-140
@@ -3,33 +3,57 @@ from __future__ import absolute_import, division
|
||||
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
from .. import activations, initializations
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..utils.theano_utils import shared_zeros, floatX
|
||||
from ..utils.generic_utils import make_tuple
|
||||
from .. import regularizers
|
||||
from .. import constraints
|
||||
from ..regularizers import ActivityRegularizer, Regularizer
|
||||
|
||||
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from six.moves import zip
|
||||
srng = RandomStreams()
|
||||
srng = RandomStreams(seed=np.random.randint(10e6))
|
||||
|
||||
class Layer(object):
|
||||
def __init__(self):
|
||||
self.params = []
|
||||
|
||||
def connect(self, layer):
|
||||
def set_previous(self, layer):
|
||||
if not self.supports_masked_input() and layer.get_output_mask() is not None:
|
||||
raise Exception("Attached non-masking layer to layer with masked output")
|
||||
self.previous = layer
|
||||
|
||||
def get_output(self, train):
|
||||
raise NotImplementedError
|
||||
def get_output(self, train=False):
|
||||
return self.get_input(train)
|
||||
|
||||
def get_input(self, train):
|
||||
def get_input(self, train=False):
|
||||
if hasattr(self, 'previous'):
|
||||
return self.previous.get_output(train=train)
|
||||
else:
|
||||
return self.input
|
||||
|
||||
def supports_masked_input(self):
|
||||
''' Whether or not this layer respects the output mask of its previous layer in its calculations. If you try
|
||||
to attach a layer that does *not* support masked_input to a layer that gives a non-None output_mask() that is
|
||||
an error'''
|
||||
return False
|
||||
|
||||
def get_output_mask(self, train=None):
|
||||
'''
|
||||
For some models (such as RNNs) you want a way of being able to mark some output data-points as
|
||||
"masked", so they are not used in future calculations. In such a model, get_output_mask() should return a mask
|
||||
of one less dimension than get_output() (so if get_output is (nb_samples, nb_timesteps, nb_dimensions), then the mask
|
||||
is (nb_samples, nb_timesteps), with a one for every unmasked datapoint, and a zero for every masked one.
|
||||
|
||||
If there is *no* masking then it shall return None. For instance if you attach an Activation layer (they support masking)
|
||||
to a layer with an output_mask, then that Activation shall also have an output_mask. If you attach it to a layer with no
|
||||
such mask, then the Activation's get_output_mask shall return None.
|
||||
|
||||
Some layers have an output_mask even if their input is unmasked, notably Embedding which can turn the entry "0" into
|
||||
a mask.
|
||||
'''
|
||||
return None
|
||||
|
||||
def set_weights(self, weights):
|
||||
for p, w in zip(self.params, weights):
|
||||
if p.eval().shape != w.shape:
|
||||
@@ -46,107 +70,131 @@ class Layer(object):
|
||||
return {"name":self.__class__.__name__}
|
||||
|
||||
def get_params(self):
|
||||
regs = []
|
||||
consts = []
|
||||
|
||||
if hasattr(self, 'regularizers') and len(self.regularizers) == len(self.params):
|
||||
for r in self.regularizers:
|
||||
if r:
|
||||
regs.append(r)
|
||||
else:
|
||||
regs.append(regularizers.identity)
|
||||
elif hasattr(self, 'regularizer') and self.regularizer:
|
||||
regs += [self.regularizer for _ in range(len(self.params))]
|
||||
if hasattr(self, 'regularizers'):
|
||||
regularizers = self.regularizers
|
||||
else:
|
||||
regs += [regularizers.identity for _ in range(len(self.params))]
|
||||
regularizers = []
|
||||
|
||||
if hasattr(self, 'constraints') and len(self.constraints) == len(self.params):
|
||||
for c in self.constraints:
|
||||
if c:
|
||||
consts.append(c)
|
||||
else:
|
||||
consts.append(constraints.identity)
|
||||
consts.append(constraints.identity())
|
||||
elif hasattr(self, 'constraint') and self.constraint:
|
||||
consts += [self.constraint for _ in range(len(self.params))]
|
||||
else:
|
||||
consts += [constraints.identity for _ in range(len(self.params))]
|
||||
consts += [constraints.identity() for _ in range(len(self.params))]
|
||||
|
||||
return self.params, regs, consts
|
||||
return self.params, regularizers, consts
|
||||
|
||||
|
||||
class MaskedLayer(Layer):
|
||||
'''
|
||||
If your layer trivially supports masking (by simply copying the input mask to the output), then subclass MaskedLayer
|
||||
instead of Layer, and make sure that you incorporate the input mask into your calculation of get_output()
|
||||
'''
|
||||
def supports_masked_input(self):
|
||||
return True
|
||||
|
||||
def get_input_mask(self, train=False):
|
||||
if hasattr(self, 'previous'):
|
||||
return self.previous.get_output_mask(train)
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_output_mask(self, train=False):
|
||||
''' The default output mask is just the input mask unchanged. Override this in your own
|
||||
implementations if, for instance, you are reshaping the input'''
|
||||
return self.get_input_mask(train)
|
||||
|
||||
|
||||
class Merge(object):
|
||||
def __init__(self, models, mode='sum'):
|
||||
''' Merge the output of a list of models into a single tensor.
|
||||
def __init__(self, layers, mode='sum'):
|
||||
''' Merge the output of a list of layers or containers into a single tensor.
|
||||
mode: {'sum', 'concat'}
|
||||
'''
|
||||
if len(models) < 2:
|
||||
raise Exception("Please specify two or more input models to merge")
|
||||
if len(layers) < 2:
|
||||
raise Exception("Please specify two or more input layers (or containers) to merge")
|
||||
self.mode = mode
|
||||
self.models = models
|
||||
self.layers = layers
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
for m in self.models:
|
||||
self.params += m.params
|
||||
self.regularizers += m.regularizers
|
||||
self.constraints += m.constraints
|
||||
for l in self.layers:
|
||||
params, regs, consts = l.get_params()
|
||||
self.regularizers += regs
|
||||
# params and constraints have the same size
|
||||
for p, c in zip(params, consts):
|
||||
if not p in self.params:
|
||||
self.params.append(p)
|
||||
self.constraints.append(c)
|
||||
|
||||
def get_params(self):
|
||||
return self.params, self.regularizers, self.constraints
|
||||
|
||||
def get_output(self, train=False):
|
||||
if self.mode == 'sum':
|
||||
s = self.models[0].get_output(train)
|
||||
for i in range(1, len(self.models)):
|
||||
s += self.models[i].get_output(train)
|
||||
s = self.layers[0].get_output(train)
|
||||
for i in range(1, len(self.layers)):
|
||||
s += self.layers[i].get_output(train)
|
||||
return s
|
||||
elif self.mode == 'concat':
|
||||
inputs = [self.models[i].get_output(train) for i in range(len(self.models))]
|
||||
inputs = [self.layers[i].get_output(train) for i in range(len(self.layers))]
|
||||
return T.concatenate(inputs, axis=-1)
|
||||
else:
|
||||
raise Exception('Unknown merge mode')
|
||||
|
||||
def get_input(self, train=False):
|
||||
res = []
|
||||
for i in range(len(self.models)):
|
||||
o = self.models[i].get_input(train)
|
||||
if type(o) == list:
|
||||
res += o
|
||||
else:
|
||||
res.append(o)
|
||||
return res
|
||||
for i in range(len(self.layers)):
|
||||
o = self.layers[i].get_input(train)
|
||||
if not type(o) == list:
|
||||
o = [o]
|
||||
for output in o:
|
||||
if output not in res:
|
||||
res.append(output)
|
||||
return res
|
||||
|
||||
@property
|
||||
def input(self):
|
||||
return self.get_input()
|
||||
|
||||
def supports_masked_input(self):
|
||||
return False
|
||||
|
||||
def get_output_mask(self, train=None):
|
||||
return None
|
||||
|
||||
def get_weights(self):
|
||||
weights = []
|
||||
for m in self.models:
|
||||
weights += m.get_weights()
|
||||
for l in self.layers:
|
||||
weights += l.get_weights()
|
||||
return weights
|
||||
|
||||
def set_weights(self, weights):
|
||||
for i in range(len(self.models)):
|
||||
nb_param = len(self.models[i].params)
|
||||
self.models[i].set_weights(weights[:nb_param])
|
||||
for i in range(len(self.layers)):
|
||||
nb_param = len(self.layers[i].params)
|
||||
self.layers[i].set_weights(weights[:nb_param])
|
||||
weights = weights[nb_param:]
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"models":[m.get_config() for m in self.models],
|
||||
"layers":[l.get_config() for l in self.layers],
|
||||
"mode":self.mode}
|
||||
|
||||
|
||||
|
||||
class Dropout(Layer):
|
||||
class Dropout(MaskedLayer):
|
||||
'''
|
||||
Hinton's dropout.
|
||||
'''
|
||||
def __init__(self, p):
|
||||
super(Dropout,self).__init__()
|
||||
super(Dropout, self).__init__()
|
||||
self.p = p
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
if self.p > 0.:
|
||||
retain_prob = 1. - self.p
|
||||
@@ -161,17 +209,17 @@ class Dropout(Layer):
|
||||
"p":self.p}
|
||||
|
||||
|
||||
class Activation(Layer):
|
||||
class Activation(MaskedLayer):
|
||||
'''
|
||||
Apply an activation function to an output.
|
||||
'''
|
||||
def __init__(self, activation, target=0, beta=0.1):
|
||||
super(Activation,self).__init__()
|
||||
super(Activation, self).__init__()
|
||||
self.activation = activations.get(activation)
|
||||
self.target = target
|
||||
self.beta = beta
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
return self.activation(X)
|
||||
|
||||
@@ -189,10 +237,10 @@ class Reshape(Layer):
|
||||
First dimension is assumed to be nb_samples.
|
||||
'''
|
||||
def __init__(self, *dims):
|
||||
super(Reshape,self).__init__()
|
||||
super(Reshape, self).__init__()
|
||||
self.dims = dims
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
nshape = make_tuple(X.shape[0], *self.dims)
|
||||
return theano.tensor.reshape(X, nshape)
|
||||
@@ -208,9 +256,9 @@ class Flatten(Layer):
|
||||
First dimension is assumed to be nb_samples.
|
||||
'''
|
||||
def __init__(self):
|
||||
super(Flatten,self).__init__()
|
||||
super(Flatten, self).__init__()
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
size = theano.tensor.prod(X.shape) // X.shape[0]
|
||||
nshape = (X.shape[0], size)
|
||||
@@ -225,14 +273,14 @@ class RepeatVector(Layer):
|
||||
Return tensor of shape (nb_samples, n, dim).
|
||||
'''
|
||||
def __init__(self, n):
|
||||
super(RepeatVector,self).__init__()
|
||||
super(RepeatVector, self).__init__()
|
||||
self.n = n
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
tensors = [X]*self.n
|
||||
stacked = theano.tensor.stack(*tensors)
|
||||
return stacked.dimshuffle((1,0,2))
|
||||
return stacked.dimshuffle((1, 0, 2))
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
@@ -243,10 +291,10 @@ class Dense(Layer):
|
||||
'''
|
||||
Just your regular fully connected NN layer.
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim, init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
def __init__(self, input_dim, output_dim, init='glorot_uniform', activation='linear', weights=None, name=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
|
||||
super(Dense,self).__init__()
|
||||
super(Dense, self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
self.input_dim = input_dim
|
||||
@@ -258,13 +306,38 @@ class Dense(Layer):
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
|
||||
self.regularizers = [W_regularizer, b_regularizer]
|
||||
self.constraints = [W_constraint, b_constraint]
|
||||
self.regularizers = []
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
self.constraints = [self.W_constraint, self.b_constraint]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def get_output(self, train):
|
||||
if name is not None:
|
||||
self.set_name(name)
|
||||
|
||||
def set_name(self, name):
|
||||
self.W.name = '%s_W' % name
|
||||
self.b.name = '%s_b' % name
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
output = self.activation(T.dot(X, self.W) + self.b)
|
||||
return output
|
||||
@@ -274,10 +347,38 @@ class Dense(Layer):
|
||||
"input_dim":self.input_dim,
|
||||
"output_dim":self.output_dim,
|
||||
"init":self.init.__name__,
|
||||
"activation":self.activation.__name__}
|
||||
"activation":self.activation.__name__,
|
||||
"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}
|
||||
|
||||
|
||||
class TimeDistributedDense(Layer):
|
||||
class ActivityRegularization(Layer):
|
||||
'''
|
||||
Layer that passes through its input unchanged, but applies an update
|
||||
to the cost function based on the activity.
|
||||
'''
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
super(ActivityRegularization, self).__init__()
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
|
||||
activity_regularizer = ActivityRegularizer(l1=l1, l2=l2)
|
||||
activity_regularizer.set_layer(self)
|
||||
self.regularizers = [activity_regularizer]
|
||||
|
||||
def get_output(self, train=False):
|
||||
return self.get_input(train)
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"l1":self.l1,
|
||||
"l2":self.l2}
|
||||
|
||||
|
||||
class TimeDistributedDense(MaskedLayer):
|
||||
'''
|
||||
Apply a same DenseLayer for each dimension[1] (shared_dimension) input
|
||||
Especially useful after a recurrent network with 'return_sequence=True'
|
||||
@@ -286,9 +387,9 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim, init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
|
||||
super(TimeDistributedDense,self).__init__()
|
||||
super(TimeDistributedDense, self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
self.input_dim = input_dim
|
||||
@@ -300,29 +401,48 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
|
||||
self.regularizers = [W_regularizer, b_regularizer]
|
||||
self.constraints = [W_constraint, b_constraint]
|
||||
self.regularizers = []
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
self.constraints = [self.W_constraint, self.b_constraint]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
output = self.activation(T.dot(X.dimshuffle(1, 0, 2), self.W) + self.b)
|
||||
return output.dimshuffle(1, 0, 2)
|
||||
|
||||
def act_func(X):
|
||||
return self.activation(T.dot(X, self.W) + self.b)
|
||||
|
||||
output, _ = theano.scan(fn = act_func,
|
||||
sequences = X.dimshuffle(1,0,2),
|
||||
outputs_info=None)
|
||||
return output.dimshuffle(1,0,2)
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_dim":self.input_dim,
|
||||
"output_dim":self.output_dim,
|
||||
"init":self.init.__name__,
|
||||
"activation":self.activation.__name__}
|
||||
"activation":self.activation.__name__,
|
||||
"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}
|
||||
|
||||
|
||||
class AutoEncoder(Layer):
|
||||
'''
|
||||
@@ -330,32 +450,32 @@ class AutoEncoder(Layer):
|
||||
If output_reconstruction then dim(input) = dim(output)
|
||||
else dim(output) = dim(hidden)
|
||||
'''
|
||||
def __init__(self, encoder, decoder, output_reconstruction=True, tie_weights=False, weights=None):
|
||||
def __init__(self, encoder, decoder, output_reconstruction=True, weights=None):
|
||||
|
||||
super(AutoEncoder,self).__init__()
|
||||
super(AutoEncoder, self).__init__()
|
||||
|
||||
self.output_reconstruction = output_reconstruction
|
||||
self.tie_weights = tie_weights
|
||||
self.encoder = encoder
|
||||
self.decoder = decoder
|
||||
|
||||
self.decoder.connect(self.encoder)
|
||||
self.decoder.set_previous(self.encoder)
|
||||
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
for layer in [self.encoder, self.decoder]:
|
||||
self.params += layer.params
|
||||
if hasattr(layer, 'regularizers'):
|
||||
self.regularizers += layer.regularizers
|
||||
if hasattr(layer, 'constraints'):
|
||||
self.constraints += layer.constraints
|
||||
params, regularizers, constraints = layer.get_params()
|
||||
self.constraints += constraints
|
||||
for p, r in zip(params, regularizers):
|
||||
if p not in self.params:
|
||||
self.params.append(p)
|
||||
self.regularizers.append(r)
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def connect(self, node):
|
||||
self.encoder.previous = node
|
||||
def set_previous(self, node):
|
||||
self.encoder.set_previous(node)
|
||||
|
||||
def get_weights(self):
|
||||
weights = []
|
||||
@@ -375,57 +495,22 @@ class AutoEncoder(Layer):
|
||||
def input(self):
|
||||
return self.encoder.input
|
||||
|
||||
def _get_hidden(self, train):
|
||||
def _get_hidden(self, train=False):
|
||||
return self.encoder.get_output(train)
|
||||
|
||||
def get_output(self, train):
|
||||
decoded = self.decoder.get_output(train)
|
||||
def get_output(self, train=False):
|
||||
if not train and not self.output_reconstruction:
|
||||
return self.encoder.get_output(train)
|
||||
|
||||
if self.tie_weights:
|
||||
encoder_params = self.encoder.get_weights()
|
||||
decoder_params = self.decoder.get_weights()
|
||||
for dec_param, enc_param in zip(decoder_params, encoder_params):
|
||||
if len(dec_param.shape) > 1:
|
||||
enc_param = dec_param.T
|
||||
|
||||
return decoded
|
||||
return self.decoder.get_output(train)
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"encoder_config":self.encoder.get_config(),
|
||||
"decoder_config":self.decoder.get_config(),
|
||||
"output_reconstruction":self.output_reconstruction,
|
||||
"tie_weights":self.tie_weights}
|
||||
"output_reconstruction":self.output_reconstruction}
|
||||
|
||||
|
||||
class DenoisingAutoEncoder(AutoEncoder):
|
||||
'''
|
||||
A denoising autoencoder model that inherits the base features from autoencoder
|
||||
'''
|
||||
def __init__(self, encoder=None, decoder=None, output_reconstruction=True, tie_weights=False, weights=None, corruption_level=0.3):
|
||||
super(DenoisingAutoEncoder, self).__init__(encoder, decoder, output_reconstruction, tie_weights, weights)
|
||||
self.corruption_level = corruption_level
|
||||
|
||||
def _get_corrupted_input(self, input):
|
||||
"""
|
||||
http://deeplearning.net/tutorial/dA.html
|
||||
"""
|
||||
return srng.binomial(size=(self.input_dim, 1), n=1,
|
||||
p=1-self.corruption_level,
|
||||
dtype=theano.config.floatX) * input
|
||||
|
||||
def get_input(self, train=False):
|
||||
uncorrupted_input = super(DenoisingAutoEncoder, self).get_input(train)
|
||||
return self._get_corrupted_input(uncorrupted_input)
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"encoder_config":self.encoder.get_config(),
|
||||
"decoder_config":self.decoder.get_config(),
|
||||
"corruption_level":self.corruption_level,
|
||||
"output_reconstruction":self.output_reconstruction,
|
||||
"tie_weights":self.tie_weights}
|
||||
|
||||
|
||||
class MaxoutDense(Layer):
|
||||
'''
|
||||
@@ -433,9 +518,9 @@ class MaxoutDense(Layer):
|
||||
Refer to http://arxiv.org/pdf/1302.4389.pdf
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim, nb_feature=4, init='glorot_uniform', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None):
|
||||
|
||||
super(MaxoutDense,self).__init__()
|
||||
super(MaxoutDense, self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.input_dim = input_dim
|
||||
self.output_dim = output_dim
|
||||
@@ -447,13 +532,31 @@ class MaxoutDense(Layer):
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
|
||||
self.regularizers = [W_regularizer, b_regularizer]
|
||||
self.constraints = [W_constraint, b_constraint]
|
||||
self.regularizers = []
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
self.constraints = [self.W_constraint, self.b_constraint]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
# -- don't need activation since it's just linear.
|
||||
output = T.max(T.dot(X, self.W) + self.b, axis=1)
|
||||
@@ -464,4 +567,9 @@ class MaxoutDense(Layer):
|
||||
"input_dim":self.input_dim,
|
||||
"output_dim":self.output_dim,
|
||||
"init":self.init.__name__,
|
||||
"nb_feature" : self.nb_feature}
|
||||
"nb_feature" : self.nb_feature,
|
||||
"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}
|
||||
|
||||
@@ -2,8 +2,10 @@ from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
|
||||
from .. import activations, initializations
|
||||
from ..layers.core import Layer
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..layers.core import Layer, MaskedLayer
|
||||
from ..utils.theano_utils import sharedX
|
||||
|
||||
from ..constraints import unitnorm
|
||||
|
||||
|
||||
@@ -15,7 +17,10 @@ class Embedding(Layer):
|
||||
@input_dim: size of vocabulary (highest input integer + 1)
|
||||
@out_dim: size of dense representation
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim, init='uniform', weights=None, W_regularizer=None, W_constraint=None):
|
||||
def __init__(self, input_dim, output_dim, init='uniform',
|
||||
W_regularizer=None, activity_regularizer=None, W_constraint=None,
|
||||
mask_zero=False, weights=None):
|
||||
|
||||
super(Embedding,self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.input_dim = input_dim
|
||||
@@ -23,13 +28,35 @@ class Embedding(Layer):
|
||||
|
||||
self.input = T.imatrix()
|
||||
self.W = self.init((self.input_dim, self.output_dim))
|
||||
self.mask_zero = mask_zero
|
||||
|
||||
self.params = [self.W]
|
||||
self.constraints = [W_constraint]
|
||||
self.regularizers = [W_regularizer]
|
||||
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.constraints = [self.W_constraint]
|
||||
|
||||
self.regularizers = []
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
self.activity_regularizer = regularizers.get(activity_regularizer)
|
||||
if self.activity_regularizer:
|
||||
self.activity_regularizer.set_layer(self)
|
||||
self.regularizers.append(self.activity_regularizer)
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def get_output_mask(self, train=None):
|
||||
X = self.get_input(train)
|
||||
if not self.mask_zero:
|
||||
return None
|
||||
else:
|
||||
return T.ones_like(X) * (1 - T.eq(X,0))
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
out = self.W[X]
|
||||
@@ -39,7 +66,10 @@ class Embedding(Layer):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_dim":self.input_dim,
|
||||
"output_dim":self.output_dim,
|
||||
"init":self.init.__name__}
|
||||
"init":self.init.__name__,
|
||||
"activity_regularizer":self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
"W_regularizer":self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"W_constraint":self.W_constraint.get_config() if self.W_constraint else None}
|
||||
|
||||
|
||||
class WordContextProduct(Layer):
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
from __future__ import absolute_import
|
||||
from .core import srng, MaskedLayer
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
|
||||
class GaussianNoise(MaskedLayer):
|
||||
'''
|
||||
Corruption process with GaussianNoise
|
||||
'''
|
||||
def __init__(self, sigma):
|
||||
super(GaussianNoise, self).__init__()
|
||||
self.sigma = sigma
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
if not train or self.sigma == 0:
|
||||
return X
|
||||
else:
|
||||
return X + srng.normal(size=X.shape, avg=0.0, std=self.sigma,
|
||||
dtype=theano.config.floatX)
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"sigma":self.sigma}
|
||||
|
||||
class GaussianDropout(MaskedLayer):
|
||||
'''
|
||||
Multiplicative Gaussian Noise
|
||||
Reference:
|
||||
Dropout: A Simple Way to Prevent Neural Networks from Overfitting
|
||||
Srivastava, Hinton, et al. 2014
|
||||
http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf
|
||||
'''
|
||||
def __init__(self, p):
|
||||
super(GaussianDropout,self).__init__()
|
||||
self.p = p
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
if train:
|
||||
# self.p refers to drop probability rather than retain probability (as in paper) to match Dropout layer syntax
|
||||
X *= srng.normal(size=X.shape, avg=1.0, std=T.sqrt(self.p / (1.0 - self.p)), dtype=theano.config.floatX)
|
||||
return X
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"p":self.p}
|
||||
@@ -6,7 +6,7 @@ import theano.tensor as T
|
||||
|
||||
class BatchNormalization(Layer):
|
||||
'''
|
||||
Reference:
|
||||
Reference:
|
||||
Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
|
||||
http://arxiv.org/pdf/1502.03167v3.pdf
|
||||
|
||||
@@ -67,3 +67,39 @@ class BatchNormalization(Layer):
|
||||
"input_shape":self.input_shape,
|
||||
"epsilon":self.epsilon,
|
||||
"mode":self.mode}
|
||||
|
||||
|
||||
class LRN2D(Layer):
|
||||
"""
|
||||
This code is adapted from pylearn2.
|
||||
License at: https://github.com/lisa-lab/pylearn2/blob/master/LICENSE.txt
|
||||
"""
|
||||
|
||||
def __init__(self, alpha=1e-4, k=2, beta=0.75, n=5):
|
||||
if n % 2 == 0:
|
||||
raise NotImplementedError("LRN2D only works with odd n. n provided: " + str(n))
|
||||
super(LRN2D, self).__init__()
|
||||
self.alpha = alpha
|
||||
self.k = k
|
||||
self.beta = beta
|
||||
self.n = n
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
b, ch, r, c = X.shape
|
||||
half_n = self.n // 2
|
||||
input_sqr = T.sqr(X)
|
||||
extra_channels = T.alloc(0., b, ch + 2*half_n, r, c)
|
||||
input_sqr = T.set_subtensor(extra_channels[:, half_n:half_n+ch, :, :], input_sqr)
|
||||
scale = self.k
|
||||
for i in range(self.n):
|
||||
scale += self.alpha * input_sqr[:, i:i+ch, :, :]
|
||||
scale = scale ** self.beta
|
||||
return X / scale
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"alpha":self.alpha,
|
||||
"k":self.k,
|
||||
"beta":self.beta,
|
||||
"n": self.n}
|
||||
+412
-45
@@ -5,11 +5,35 @@ import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
from .. import activations, initializations
|
||||
from ..utils.theano_utils import shared_zeros, alloc_zeros_matrix
|
||||
from ..layers.core import Layer
|
||||
from ..utils.theano_utils import shared_scalar, shared_zeros, alloc_zeros_matrix
|
||||
from ..layers.core import Layer, MaskedLayer
|
||||
from six.moves import range
|
||||
|
||||
class SimpleRNN(Layer):
|
||||
class Recurrent(MaskedLayer):
|
||||
def get_output_mask(self, train=None):
|
||||
if self.return_sequences:
|
||||
return super(Recurrent, self).get_output_mask(train)
|
||||
else:
|
||||
return None
|
||||
|
||||
def get_padded_shuffled_mask(self, train, X, pad=0):
|
||||
mask = self.get_input_mask(train)
|
||||
if mask is None:
|
||||
mask = T.ones_like(X.sum(axis=-1)) # is there a better way to do this without a sum?
|
||||
|
||||
# mask is (nb_samples, time)
|
||||
mask = T.shape_padright(mask) # (nb_samples, time, 1)
|
||||
mask = T.addbroadcast(mask, -1) # (time, nb_samples, 1) matrix.
|
||||
mask = mask.dimshuffle(1, 0, 2) # (time, nb_samples, 1)
|
||||
|
||||
if pad > 0:
|
||||
# left-pad in time with 0
|
||||
padding = alloc_zeros_matrix(pad, mask.shape[1], 1)
|
||||
mask = T.concatenate([padding, mask], axis=0)
|
||||
return mask.astype('int8')
|
||||
|
||||
|
||||
class SimpleRNN(Recurrent):
|
||||
'''
|
||||
Fully connected RNN where output is to fed back to input.
|
||||
|
||||
@@ -20,6 +44,7 @@ class SimpleRNN(Layer):
|
||||
def __init__(self, input_dim, output_dim,
|
||||
init='glorot_uniform', inner_init='orthogonal', activation='sigmoid', weights=None,
|
||||
truncate_gradient=-1, return_sequences=False):
|
||||
|
||||
super(SimpleRNN,self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.inner_init = initializations.get(inner_init)
|
||||
@@ -38,19 +63,19 @@ class SimpleRNN(Layer):
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self, x_t, h_tm1, u):
|
||||
def _step(self, x_t, mask_tm1, h_tm1, u):
|
||||
'''
|
||||
Variable names follow the conventions from:
|
||||
http://deeplearning.net/software/theano/library/scan.html
|
||||
|
||||
'''
|
||||
return self.activation(x_t + T.dot(h_tm1, u))
|
||||
return self.activation(x_t + mask_tm1 * T.dot(h_tm1, u))
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train) # shape: (nb_samples, time (padded with zeros at the end), input_dim)
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train) # shape: (nb_samples, time (padded with zeros), input_dim)
|
||||
# new shape: (time, nb_samples, input_dim) -> because theano.scan iterates over main dimension
|
||||
X = X.dimshuffle((1,0,2))
|
||||
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
x = T.dot(X, self.W) + self.b
|
||||
|
||||
# scan = theano symbolic loop.
|
||||
@@ -58,14 +83,15 @@ class SimpleRNN(Layer):
|
||||
# Iterate over the first dimension of the x array (=time).
|
||||
outputs, updates = theano.scan(
|
||||
self._step, # this will be called with arguments (sequences[i], outputs[i-1], non_sequences[i])
|
||||
sequences=x, # tensors to iterate over, inputs to _step
|
||||
sequences=[x, dict(input=padded_mask, taps=[-1])], # tensors to iterate over, inputs to _step
|
||||
# initialization of the output. Input to _step with default tap=-1.
|
||||
outputs_info=T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1),
|
||||
non_sequences=self.U, # static inputs to _step
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1,0,2))
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
@@ -79,7 +105,7 @@ class SimpleRNN(Layer):
|
||||
"return_sequences":self.return_sequences}
|
||||
|
||||
|
||||
class SimpleDeepRNN(Layer):
|
||||
class SimpleDeepRNN(Recurrent):
|
||||
'''
|
||||
Fully connected RNN where the output of multiple timesteps
|
||||
(up to "depth" steps in the past) is fed back to the input:
|
||||
@@ -93,6 +119,7 @@ class SimpleDeepRNN(Layer):
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='sigmoid', inner_activation='hard_sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False):
|
||||
|
||||
super(SimpleDeepRNN,self).__init__()
|
||||
self.init = initializations.get(init)
|
||||
self.inner_init = initializations.get(inner_init)
|
||||
@@ -113,30 +140,43 @@ class SimpleDeepRNN(Layer):
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self, *args):
|
||||
o = args[0]
|
||||
for i in range(1, self.depth+1):
|
||||
o += self.inner_activation(T.dot(args[i], args[i+self.depth]))
|
||||
def _step(self, x_t, *args):
|
||||
o = x_t
|
||||
for i in range(self.depth):
|
||||
mask_tmi = args[i]
|
||||
h_tmi = args[i + self.depth]
|
||||
U_tmi = args[i + 2*self.depth]
|
||||
o += mask_tmi*self.inner_activation(T.dot(h_tmi, U_tmi))
|
||||
return self.activation(o)
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
X = X.dimshuffle((1,0,2))
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=self.depth)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
x = T.dot(X, self.W) + self.b
|
||||
|
||||
if self.depth == 1:
|
||||
initial = T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1)
|
||||
else:
|
||||
initial = T.unbroadcast(T.unbroadcast(alloc_zeros_matrix(self.depth, X.shape[1], self.output_dim), 0), 2)
|
||||
|
||||
outputs, updates = theano.scan(
|
||||
self._step,
|
||||
sequences=x,
|
||||
sequences=[x, dict(
|
||||
input = padded_mask,
|
||||
taps = [(-i) for i in range(self.depth)]
|
||||
)],
|
||||
outputs_info=[dict(
|
||||
initial=T.alloc(np.cast[theano.config.floatX](0.), self.depth, X.shape[1], self.output_dim),
|
||||
initial = initial,
|
||||
taps = [(-i-1) for i in range(self.depth)]
|
||||
)],
|
||||
non_sequences=self.Us,
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1,0,2))
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
@@ -152,8 +192,7 @@ class SimpleDeepRNN(Layer):
|
||||
"return_sequences":self.return_sequences}
|
||||
|
||||
|
||||
|
||||
class GRU(Layer):
|
||||
class GRU(Recurrent):
|
||||
'''
|
||||
Gated Recurrent Unit - Cho et al. 2014
|
||||
|
||||
@@ -214,31 +253,34 @@ class GRU(Layer):
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self,
|
||||
xz_t, xr_t, xh_t,
|
||||
xz_t, xr_t, xh_t, mask_tm1,
|
||||
h_tm1,
|
||||
u_z, u_r, u_h):
|
||||
z = self.inner_activation(xz_t + T.dot(h_tm1, u_z))
|
||||
r = self.inner_activation(xr_t + T.dot(h_tm1, u_r))
|
||||
hh_t = self.activation(xh_t + T.dot(r * h_tm1, u_h))
|
||||
h_t = z * h_tm1 + (1 - z) * hh_t
|
||||
h_mask_tm1 = mask_tm1 * h_tm1
|
||||
z = self.inner_activation(xz_t + T.dot(h_mask_tm1, u_z))
|
||||
r = self.inner_activation(xr_t + T.dot(h_mask_tm1, u_r))
|
||||
hh_t = self.activation(xh_t + T.dot(r * h_mask_tm1, u_h))
|
||||
h_t = z * h_mask_tm1 + (1 - z) * hh_t
|
||||
return h_t
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
X = X.dimshuffle((1,0,2))
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
x_z = T.dot(X, self.W_z) + self.b_z
|
||||
x_r = T.dot(X, self.W_r) + self.b_r
|
||||
x_h = T.dot(X, self.W_h) + self.b_h
|
||||
outputs, updates = theano.scan(
|
||||
self._step,
|
||||
sequences=[x_z, x_r, x_h],
|
||||
sequences=[x_z, x_r, x_h, padded_mask],
|
||||
outputs_info=T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1),
|
||||
non_sequences=[self.U_z, self.U_r, self.U_h],
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1,0,2))
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
@@ -254,7 +296,7 @@ class GRU(Layer):
|
||||
|
||||
|
||||
|
||||
class LSTM(Layer):
|
||||
class LSTM(Recurrent):
|
||||
'''
|
||||
Acts as a spatiotemporal projection,
|
||||
turning a sequence of vectors into a single vector.
|
||||
@@ -280,7 +322,7 @@ class LSTM(Layer):
|
||||
http://www.cs.toronto.edu/~graves/preprint.pdf
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim=128,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
init='glorot_uniform', inner_init='orthogonal', forget_bias_init='one',
|
||||
activation='tanh', inner_activation='hard_sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False):
|
||||
|
||||
@@ -292,6 +334,7 @@ class LSTM(Layer):
|
||||
|
||||
self.init = initializations.get(init)
|
||||
self.inner_init = initializations.get(inner_init)
|
||||
self.forget_bias_init = initializations.get(forget_bias_init)
|
||||
self.activation = activations.get(activation)
|
||||
self.inner_activation = activations.get(inner_activation)
|
||||
self.input = T.tensor3()
|
||||
@@ -302,7 +345,7 @@ class LSTM(Layer):
|
||||
|
||||
self.W_f = self.init((self.input_dim, self.output_dim))
|
||||
self.U_f = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_f = shared_zeros((self.output_dim))
|
||||
self.b_f = self.forget_bias_init((self.output_dim))
|
||||
|
||||
self.W_c = self.init((self.input_dim, self.output_dim))
|
||||
self.U_c = self.inner_init((self.output_dim, self.output_dim))
|
||||
@@ -323,19 +366,23 @@ class LSTM(Layer):
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self,
|
||||
xi_t, xf_t, xo_t, xc_t,
|
||||
xi_t, xf_t, xo_t, xc_t, mask_tm1,
|
||||
h_tm1, c_tm1,
|
||||
u_i, u_f, u_o, u_c):
|
||||
i_t = self.inner_activation(xi_t + T.dot(h_tm1, u_i))
|
||||
f_t = self.inner_activation(xf_t + T.dot(h_tm1, u_f))
|
||||
c_t = f_t * c_tm1 + i_t * self.activation(xc_t + T.dot(h_tm1, u_c))
|
||||
o_t = self.inner_activation(xo_t + T.dot(h_tm1, u_o))
|
||||
h_mask_tm1 = mask_tm1 * h_tm1
|
||||
c_mask_tm1 = mask_tm1 * c_tm1
|
||||
|
||||
i_t = self.inner_activation(xi_t + T.dot(h_mask_tm1, u_i))
|
||||
f_t = self.inner_activation(xf_t + T.dot(h_mask_tm1, u_f))
|
||||
c_t = f_t * c_mask_tm1 + i_t * self.activation(xc_t + T.dot(h_mask_tm1, u_c))
|
||||
o_t = self.inner_activation(xo_t + T.dot(h_mask_tm1, u_o))
|
||||
h_t = o_t * self.activation(c_t)
|
||||
return h_t, c_t
|
||||
|
||||
def get_output(self, train):
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
X = X.dimshuffle((1,0,2))
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
xi = T.dot(X, self.W_i) + self.b_i
|
||||
xf = T.dot(X, self.W_f) + self.b_f
|
||||
@@ -344,7 +391,7 @@ class LSTM(Layer):
|
||||
|
||||
[outputs, memories], updates = theano.scan(
|
||||
self._step,
|
||||
sequences=[xi, xf, xo, xc],
|
||||
sequences=[xi, xf, xo, xc, padded_mask],
|
||||
outputs_info=[
|
||||
T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1),
|
||||
T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1)
|
||||
@@ -352,8 +399,117 @@ class LSTM(Layer):
|
||||
non_sequences=[self.U_i, self.U_f, self.U_o, self.U_c],
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1,0,2))
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_dim":self.input_dim,
|
||||
"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__,
|
||||
"truncate_gradient":self.truncate_gradient,
|
||||
"return_sequences":self.return_sequences}
|
||||
|
||||
|
||||
|
||||
class JZS1(Recurrent):
|
||||
'''
|
||||
Evolved recurrent neural network architectures from the evaluation of thousands
|
||||
of models, serving as alternatives to LSTMs and GRUs. See Jozefowicz et al. 2015.
|
||||
|
||||
This corresponds to the `MUT1` architecture described in the paper.
|
||||
|
||||
Takes inputs with shape:
|
||||
(nb_samples, max_sample_length (samples shorter than this are padded with zeros at the end), input_dim)
|
||||
|
||||
and returns outputs with shape:
|
||||
if not return_sequences:
|
||||
(nb_samples, output_dim)
|
||||
if return_sequences:
|
||||
(nb_samples, max_sample_length, output_dim)
|
||||
|
||||
References:
|
||||
An Empirical Exploration of Recurrent Network Architectures
|
||||
http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim=128,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='tanh', inner_activation='sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False):
|
||||
|
||||
super(JZS1,self).__init__()
|
||||
self.input_dim = input_dim
|
||||
self.output_dim = output_dim
|
||||
self.truncate_gradient = truncate_gradient
|
||||
self.return_sequences = return_sequences
|
||||
|
||||
self.init = initializations.get(init)
|
||||
self.inner_init = initializations.get(inner_init)
|
||||
self.activation = activations.get(activation)
|
||||
self.inner_activation = activations.get(inner_activation)
|
||||
self.input = T.tensor3()
|
||||
|
||||
self.W_z = self.init((self.input_dim, self.output_dim))
|
||||
self.b_z = shared_zeros((self.output_dim))
|
||||
|
||||
self.W_r = self.init((self.input_dim, self.output_dim))
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_r = shared_zeros((self.output_dim))
|
||||
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_h = shared_zeros((self.output_dim))
|
||||
|
||||
# P_h used to project X onto different dimension, using sparse random projections
|
||||
if self.input_dim == self.output_dim:
|
||||
self.Pmat = theano.shared(np.identity(self.output_dim, dtype=theano.config.floatX), name=None)
|
||||
else:
|
||||
P = np.random.binomial(1, 0.5, size=(self.input_dim, self.output_dim)).astype(theano.config.floatX) * 2 - 1
|
||||
P = 1 / np.sqrt(self.input_dim) * P
|
||||
self.Pmat = theano.shared(P, name=None)
|
||||
|
||||
self.params = [
|
||||
self.W_z, self.b_z,
|
||||
self.W_r, self.U_r, self.b_r,
|
||||
self.U_h, self.b_h,
|
||||
]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self,
|
||||
xz_t, xr_t, xh_t, mask_tm1,
|
||||
h_tm1,
|
||||
u_r, u_h):
|
||||
h_mask_tm1 = mask_tm1 * h_tm1
|
||||
z = self.inner_activation(xz_t)
|
||||
r = self.inner_activation(xr_t + T.dot(h_mask_tm1, u_r))
|
||||
hh_t = self.activation(xh_t + T.dot(r * h_mask_tm1, u_h))
|
||||
h_t = hh_t * z + h_mask_tm1 * (1 - z)
|
||||
return h_t
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
x_z = T.dot(X, self.W_z) + self.b_z
|
||||
x_r = T.dot(X, self.W_r) + self.b_r
|
||||
x_h = T.tanh(T.dot(X, self.Pmat)) + self.b_h
|
||||
outputs, updates = theano.scan(
|
||||
self._step,
|
||||
sequences=[x_z, x_r, x_h, padded_mask],
|
||||
outputs_info=T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1),
|
||||
non_sequences=[self.U_r, self.U_h],
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
@@ -366,5 +522,216 @@ class LSTM(Layer):
|
||||
"inner_activation":self.inner_activation.__name__,
|
||||
"truncate_gradient":self.truncate_gradient,
|
||||
"return_sequences":self.return_sequences}
|
||||
|
||||
|
||||
|
||||
|
||||
class JZS2(Recurrent):
|
||||
'''
|
||||
Evolved recurrent neural network architectures from the evaluation of thousands
|
||||
of models, serving as alternatives to LSTMs and GRUs. See Jozefowicz et al. 2015.
|
||||
|
||||
This corresponds to the `MUT2` architecture described in the paper.
|
||||
|
||||
Takes inputs with shape:
|
||||
(nb_samples, max_sample_length (samples shorter than this are padded with zeros at the end), input_dim)
|
||||
|
||||
and returns outputs with shape:
|
||||
if not return_sequences:
|
||||
(nb_samples, output_dim)
|
||||
if return_sequences:
|
||||
(nb_samples, max_sample_length, output_dim)
|
||||
|
||||
References:
|
||||
An Empirical Exploration of Recurrent Network Architectures
|
||||
http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim=128,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='tanh', inner_activation='sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False):
|
||||
|
||||
super(JZS2,self).__init__()
|
||||
self.input_dim = input_dim
|
||||
self.output_dim = output_dim
|
||||
self.truncate_gradient = truncate_gradient
|
||||
self.return_sequences = return_sequences
|
||||
|
||||
self.init = initializations.get(init)
|
||||
self.inner_init = initializations.get(inner_init)
|
||||
self.activation = activations.get(activation)
|
||||
self.inner_activation = activations.get(inner_activation)
|
||||
self.input = T.tensor3()
|
||||
|
||||
self.W_z = self.init((self.input_dim, self.output_dim))
|
||||
self.U_z = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_z = shared_zeros((self.output_dim))
|
||||
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_r = shared_zeros((self.output_dim))
|
||||
|
||||
self.W_h = self.init((self.input_dim, self.output_dim))
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_h = shared_zeros((self.output_dim))
|
||||
|
||||
# P_h used to project X onto different dimension, using sparse random projections
|
||||
if self.input_dim == self.output_dim:
|
||||
self.Pmat = theano.shared(np.identity(self.output_dim, dtype=theano.config.floatX), name=None)
|
||||
else:
|
||||
P = np.random.binomial(1, 0.5, size=(self.input_dim, self.output_dim)).astype(theano.config.floatX) * 2 - 1
|
||||
P = 1 / np.sqrt(self.input_dim) * P
|
||||
self.Pmat = theano.shared(P, name=None)
|
||||
|
||||
self.params = [
|
||||
self.W_z, self.U_z, self.b_z,
|
||||
self.U_r, self.b_r,
|
||||
self.W_h, self.U_h, self.b_h,
|
||||
]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self,
|
||||
xz_t, xr_t, xh_t, mask_tm1,
|
||||
h_tm1,
|
||||
u_z, u_r, u_h):
|
||||
h_mask_tm1 = mask_tm1 * h_tm1
|
||||
z = self.inner_activation(xz_t + T.dot(h_mask_tm1, u_z))
|
||||
r = self.inner_activation(xr_t + T.dot(h_mask_tm1, u_r))
|
||||
hh_t = self.activation(xh_t + T.dot(r * h_mask_tm1, u_h))
|
||||
h_t = hh_t * z + h_mask_tm1 * (1 - z)
|
||||
return h_t
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
x_z = T.dot(X, self.W_z) + self.b_z
|
||||
x_r = T.dot(X, self.Pmat) + self.b_r
|
||||
x_h = T.dot(X, self.W_h) + self.b_h
|
||||
outputs, updates = theano.scan(
|
||||
self._step,
|
||||
sequences=[x_z, x_r, x_h, padded_mask],
|
||||
outputs_info=T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1),
|
||||
non_sequences=[self.U_z, self.U_r, self.U_h],
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_dim":self.input_dim,
|
||||
"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__,
|
||||
"truncate_gradient":self.truncate_gradient,
|
||||
"return_sequences":self.return_sequences}
|
||||
|
||||
|
||||
|
||||
class JZS3(Recurrent):
|
||||
'''
|
||||
Evolved recurrent neural network architectures from the evaluation of thousands
|
||||
of models, serving as alternatives to LSTMs and GRUs. See Jozefowicz et al. 2015.
|
||||
|
||||
This corresponds to the `MUT3` architecture described in the paper.
|
||||
|
||||
Takes inputs with shape:
|
||||
(nb_samples, max_sample_length (samples shorter than this are padded with zeros at the end), input_dim)
|
||||
|
||||
and returns outputs with shape:
|
||||
if not return_sequences:
|
||||
(nb_samples, output_dim)
|
||||
if return_sequences:
|
||||
(nb_samples, max_sample_length, output_dim)
|
||||
|
||||
References:
|
||||
An Empirical Exploration of Recurrent Network Architectures
|
||||
http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf
|
||||
'''
|
||||
def __init__(self, input_dim, output_dim=128,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='tanh', inner_activation='sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False):
|
||||
|
||||
super(JZS3,self).__init__()
|
||||
self.input_dim = input_dim
|
||||
self.output_dim = output_dim
|
||||
self.truncate_gradient = truncate_gradient
|
||||
self.return_sequences = return_sequences
|
||||
|
||||
self.init = initializations.get(init)
|
||||
self.inner_init = initializations.get(inner_init)
|
||||
self.activation = activations.get(activation)
|
||||
self.inner_activation = activations.get(inner_activation)
|
||||
self.input = T.tensor3()
|
||||
|
||||
self.W_z = self.init((self.input_dim, self.output_dim))
|
||||
self.U_z = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_z = shared_zeros((self.output_dim))
|
||||
|
||||
self.W_r = self.init((self.input_dim, self.output_dim))
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_r = shared_zeros((self.output_dim))
|
||||
|
||||
self.W_h = self.init((self.input_dim, self.output_dim))
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim))
|
||||
self.b_h = shared_zeros((self.output_dim))
|
||||
|
||||
self.params = [
|
||||
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 weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
def _step(self,
|
||||
xz_t, xr_t, xh_t, mask_tm1,
|
||||
h_tm1,
|
||||
u_z, u_r, u_h):
|
||||
h_mask_tm1 = mask_tm1 * h_tm1
|
||||
z = self.inner_activation(xz_t + T.dot(T.tanh(h_mask_tm1), u_z))
|
||||
r = self.inner_activation(xr_t + T.dot(h_mask_tm1, u_r))
|
||||
hh_t = self.activation(xh_t + T.dot(r * h_mask_tm1, u_h))
|
||||
h_t = hh_t * z + h_mask_tm1 * (1 - z)
|
||||
return h_t
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
x_z = T.dot(X, self.W_z) + self.b_z
|
||||
x_r = T.dot(X, self.W_r) + self.b_r
|
||||
x_h = T.dot(X, self.W_h) + self.b_h
|
||||
outputs, updates = theano.scan(
|
||||
self._step,
|
||||
sequences=[x_z, x_r, x_h, padded_mask],
|
||||
outputs_info=T.unbroadcast(alloc_zeros_matrix(X.shape[1], self.output_dim), 1),
|
||||
non_sequences=[self.U_z, self.U_r, self.U_h],
|
||||
truncate_gradient=self.truncate_gradient
|
||||
)
|
||||
if self.return_sequences:
|
||||
return outputs.dimshuffle((1, 0, 2))
|
||||
return outputs[-1]
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"input_dim":self.input_dim,
|
||||
"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__,
|
||||
"truncate_gradient":self.truncate_gradient,
|
||||
"return_sequences":self.return_sequences}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
+473
-179
@@ -3,32 +3,41 @@ from __future__ import print_function
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
import warnings, time, copy
|
||||
import warnings, time, copy, yaml
|
||||
|
||||
from . import optimizers
|
||||
from . import objectives
|
||||
from . import regularizers
|
||||
from . import constraints
|
||||
from . import callbacks as cbks
|
||||
|
||||
import time, copy, pprint
|
||||
from .utils.layer_utils import container_from_config
|
||||
from .utils.generic_utils import Progbar, printv
|
||||
from .layers import containers
|
||||
from six.moves import range
|
||||
|
||||
|
||||
def standardize_y(y):
|
||||
if not hasattr(y, 'shape'):
|
||||
y = np.asarray(y)
|
||||
if len(y.shape) == 1:
|
||||
y = np.reshape(y, (len(y), 1))
|
||||
y = np.expand_dims(y, 1)
|
||||
return y
|
||||
|
||||
|
||||
def make_batches(size, batch_size):
|
||||
nb_batch = int(np.ceil(size/float(batch_size)))
|
||||
return [(i*batch_size, min(size, (i+1)*batch_size)) for i in range(0, nb_batch)]
|
||||
|
||||
|
||||
def standardize_X(X):
|
||||
if type(X) == list:
|
||||
return X
|
||||
else:
|
||||
return [X]
|
||||
|
||||
|
||||
def slice_X(X, start=None, stop=None):
|
||||
if type(X) == list:
|
||||
if hasattr(start, '__len__'):
|
||||
@@ -42,13 +51,236 @@ def slice_X(X, start=None, stop=None):
|
||||
return X[start:stop]
|
||||
|
||||
|
||||
def weighted_objective(fn):
|
||||
def weighted(y_true, y_pred, weights):
|
||||
# it's important that 0 * Inf == 0, not NaN, so I need to mask first
|
||||
masked_y_true = y_true[weights.nonzero()[:-1]]
|
||||
masked_y_pred = y_pred[weights.nonzero()[:-1]]
|
||||
masked_weights = weights[weights.nonzero()]
|
||||
obj_output = fn(masked_y_true, masked_y_pred)
|
||||
return (masked_weights.flatten() * obj_output.flatten()).mean()
|
||||
return weighted
|
||||
|
||||
|
||||
def standardize_weights(y, sample_weight=None, class_weight=None):
|
||||
if sample_weight is not None:
|
||||
return standardize_y(sample_weight)
|
||||
elif isinstance(class_weight, dict):
|
||||
if len(y.shape) > 2:
|
||||
raise Exception('class_weight not supported for 3+ dimensional targets.')
|
||||
if y.shape[1] > 1:
|
||||
y_classes = y.argmax(axis=1)
|
||||
elif y.shape[1] == 1:
|
||||
y_classes = np.reshape(y, y.shape[0])
|
||||
else:
|
||||
y_classes = y
|
||||
return np.expand_dims(np.array(list(map(lambda x: class_weight[x], y_classes))), 1)
|
||||
else:
|
||||
return np.ones(y.shape[:-1] + (1,))
|
||||
|
||||
|
||||
def model_from_yaml(yaml_string):
|
||||
'''
|
||||
Returns a model generated from a local yaml file,
|
||||
which is either created by hand or from to_yaml method of Sequential or Graph
|
||||
'''
|
||||
model_params = yaml.load(yaml_string)
|
||||
model_name = model_params.get('name')
|
||||
if not model_name in {'Graph', 'Sequential'}:
|
||||
raise Exception('Unrecognized model:', model_name)
|
||||
|
||||
# Create a container then set class to appropriate model
|
||||
model = container_from_config(model_params)
|
||||
model.__class__ = get(model_name)
|
||||
|
||||
if 'optimizer' in model_params: # if it has an optimizer, the model is assumed to be compiled
|
||||
loss = objectives.get(model_params.get('loss'))
|
||||
class_mode = model_params.get('class_mode')
|
||||
theano_mode = model_params.get('theano_mode')
|
||||
|
||||
optimizer_params = model_params.get('optimizer')
|
||||
optimizer_name = optimizer_params.pop('name')
|
||||
optimizer = optimizers.get(optimizer_name, optimizer_params)
|
||||
|
||||
if model_name == 'Sequential':
|
||||
model.compile(loss=loss, optimizer=optimizer, class_mode=class_mode, theano_mode=theano_mode)
|
||||
elif model_name == 'Graph':
|
||||
model.compile(loss=loss, optimizer=optimizer, theano_mode=theano_mode)
|
||||
|
||||
return model
|
||||
|
||||
|
||||
class Model(object):
|
||||
def _fit(self, f, ins, out_labels=[], batch_size=128, nb_epoch=100, verbose=1, callbacks=[], \
|
||||
validation_split=0., val_f=None, val_ins=None, shuffle=True, metrics=[]):
|
||||
'''
|
||||
Abstract fit function for f(*ins). Assume that f returns a list, labelled by out_labels.
|
||||
'''
|
||||
do_validation = False
|
||||
if val_f and val_ins:
|
||||
do_validation = True
|
||||
if verbose:
|
||||
print("Train on %d samples, validate on %d samples" % (len(ins[0]), len(val_ins[0])))
|
||||
else:
|
||||
if 0 < validation_split < 1:
|
||||
do_validation = True
|
||||
split_at = int(len(ins[0]) * (1 - validation_split))
|
||||
(ins, val_ins) = (slice_X(ins, 0, split_at), slice_X(ins, split_at))
|
||||
if verbose:
|
||||
print("Train on %d samples, validate on %d samples" % (len(ins[0]), len(val_ins[0])))
|
||||
|
||||
nb_train_sample = len(ins[0])
|
||||
index_array = np.arange(nb_train_sample)
|
||||
|
||||
history = cbks.History()
|
||||
if verbose:
|
||||
callbacks = [history, cbks.BaseLogger()] + callbacks
|
||||
else:
|
||||
callbacks = [history] + callbacks
|
||||
callbacks = cbks.CallbackList(callbacks)
|
||||
|
||||
callbacks._set_model(self)
|
||||
callbacks._set_params({
|
||||
'batch_size': batch_size,
|
||||
'nb_epoch': nb_epoch,
|
||||
'nb_sample': nb_train_sample,
|
||||
'verbose': verbose,
|
||||
'do_validation': do_validation,
|
||||
'metrics':metrics,
|
||||
})
|
||||
callbacks.on_train_begin()
|
||||
|
||||
self.stop_training = False
|
||||
for epoch in range(nb_epoch):
|
||||
callbacks.on_epoch_begin(epoch)
|
||||
if shuffle:
|
||||
np.random.shuffle(index_array)
|
||||
|
||||
batches = make_batches(nb_train_sample, batch_size)
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
ins_batch = slice_X(ins, batch_ids)
|
||||
|
||||
batch_logs = {}
|
||||
batch_logs['batch'] = batch_index
|
||||
batch_logs['size'] = len(batch_ids)
|
||||
callbacks.on_batch_begin(batch_index, batch_logs)
|
||||
outs = f(*ins_batch)
|
||||
if type(outs) != list:
|
||||
outs = [outs]
|
||||
for l, o in zip(out_labels, outs):
|
||||
batch_logs[l] = o
|
||||
|
||||
callbacks.on_batch_end(batch_index, batch_logs)
|
||||
|
||||
if batch_index == len(batches) - 1: # last batch
|
||||
# validation
|
||||
epoch_logs = {}
|
||||
if do_validation:
|
||||
# replace with self._evaluate
|
||||
val_outs = self._test_loop(val_f, val_ins, batch_size=batch_size, verbose=0)
|
||||
if type(val_outs) != list:
|
||||
val_outs = [val_outs]
|
||||
# same labels assumed
|
||||
for l, o in zip(out_labels, val_outs):
|
||||
epoch_logs['val_' + l] = o
|
||||
|
||||
callbacks.on_epoch_end(epoch, epoch_logs)
|
||||
if self.stop_training:
|
||||
break
|
||||
|
||||
callbacks.on_train_end()
|
||||
return history
|
||||
|
||||
def _predict_loop(self, f, ins, batch_size=128, verbose=0):
|
||||
'''
|
||||
Abstract method to loop over some data in batches.
|
||||
'''
|
||||
nb_sample = len(ins[0])
|
||||
outs = []
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=nb_sample)
|
||||
batches = make_batches(nb_sample, batch_size)
|
||||
index_array = np.arange(nb_sample)
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
ins_batch = slice_X(ins, batch_ids)
|
||||
|
||||
batch_outs = f(*ins_batch)
|
||||
if type(batch_outs) != list:
|
||||
batch_outs = [batch_outs]
|
||||
if batch_index == 0:
|
||||
for batch_out in batch_outs:
|
||||
shape = (nb_sample,) + batch_out.shape[1:]
|
||||
outs.append(np.zeros(shape))
|
||||
|
||||
for i, batch_out in enumerate(batch_outs):
|
||||
outs[i][batch_start:batch_end] = batch_out
|
||||
if verbose == 1:
|
||||
progbar.update(batch_end)
|
||||
return outs
|
||||
|
||||
def _test_loop(self, f, ins, batch_size=128, verbose=0):
|
||||
'''
|
||||
Abstract method to loop over some data in batches.
|
||||
'''
|
||||
nb_sample = len(ins[0])
|
||||
outs = []
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=nb_sample)
|
||||
batches = make_batches(nb_sample, batch_size)
|
||||
index_array = np.arange(nb_sample)
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
ins_batch = slice_X(ins, batch_ids)
|
||||
|
||||
batch_outs = f(*ins_batch)
|
||||
if type(batch_outs) == list:
|
||||
if batch_index == 0:
|
||||
for batch_out in enumerate(batch_outs):
|
||||
outs.append(0.)
|
||||
for i, batch_out in enumerate(batch_outs):
|
||||
outs[i] += batch_out * len(batch_ids)
|
||||
else:
|
||||
if batch_index == 0:
|
||||
outs.append(0.)
|
||||
outs[0] += batch_outs * len(batch_ids)
|
||||
|
||||
if verbose == 1:
|
||||
progbar.update(batch_end)
|
||||
for i, out in enumerate(outs):
|
||||
outs[i] /= nb_sample
|
||||
return outs
|
||||
|
||||
def get_config(self, verbose=0):
|
||||
config = super(Model, self).get_config()
|
||||
if verbose:
|
||||
pp = pprint.PrettyPrinter(indent=4)
|
||||
pp.pprint(config)
|
||||
return config
|
||||
|
||||
class Sequential(Model, containers.Sequential):
|
||||
'''
|
||||
Inherits from Model the following methods:
|
||||
- _fit
|
||||
- _predict
|
||||
- _evaluate
|
||||
Inherits from containers.Sequential the following methods:
|
||||
- __init__
|
||||
- add
|
||||
- get_output
|
||||
- get_input
|
||||
- get_weights
|
||||
- set_weights
|
||||
'''
|
||||
|
||||
def compile(self, optimizer, loss, class_mode="categorical", theano_mode=None):
|
||||
self.optimizer = optimizers.get(optimizer)
|
||||
self.loss = objectives.get(loss)
|
||||
|
||||
# input of model
|
||||
self.unweighted_loss = objectives.get(loss)
|
||||
self.loss = weighted_objective(objectives.get(loss))
|
||||
|
||||
# input of model
|
||||
self.X_train = self.get_input(train=True)
|
||||
self.X_test = self.get_input(train=False)
|
||||
|
||||
@@ -58,8 +290,14 @@ class Model(object):
|
||||
# target of model
|
||||
self.y = T.zeros_like(self.y_train)
|
||||
|
||||
train_loss = self.loss(self.y, self.y_train)
|
||||
test_score = self.loss(self.y, self.y_test)
|
||||
self.weights = T.ones_like(self.y_train)
|
||||
|
||||
train_loss = self.loss(self.y, self.y_train, self.weights)
|
||||
test_loss = self.loss(self.y, self.y_test, self.weights)
|
||||
|
||||
train_loss.name = 'train_loss'
|
||||
test_loss.name = 'test_loss'
|
||||
self.y.name = 'y'
|
||||
|
||||
if class_mode == "categorical":
|
||||
train_accuracy = T.mean(T.eq(T.argmax(self.y, axis=-1), T.argmax(self.y_train, axis=-1)))
|
||||
@@ -71,160 +309,114 @@ class Model(object):
|
||||
else:
|
||||
raise Exception("Invalid class mode:" + str(class_mode))
|
||||
self.class_mode = class_mode
|
||||
self.theano_mode = theano_mode
|
||||
|
||||
updates = self.optimizer.get_updates(self.params, self.regularizers, self.constraints, train_loss)
|
||||
for r in self.regularizers:
|
||||
train_loss = r(train_loss)
|
||||
updates = self.optimizer.get_updates(self.params, self.constraints, train_loss)
|
||||
|
||||
if type(self.X_train) == list:
|
||||
train_ins = self.X_train + [self.y]
|
||||
test_ins = self.X_test + [self.y]
|
||||
train_ins = self.X_train + [self.y, self.weights]
|
||||
test_ins = self.X_test + [self.y, self.weights]
|
||||
predict_ins = self.X_test
|
||||
else:
|
||||
train_ins = [self.X_train, self.y]
|
||||
test_ins = [self.X_test, self.y]
|
||||
train_ins = [self.X_train, self.y, self.weights]
|
||||
test_ins = [self.X_test, self.y, self.weights]
|
||||
predict_ins = [self.X_test]
|
||||
|
||||
self._train = theano.function(train_ins, train_loss,
|
||||
self._train = theano.function(train_ins, train_loss,
|
||||
updates=updates, allow_input_downcast=True, mode=theano_mode)
|
||||
self._train_with_acc = theano.function(train_ins, [train_loss, train_accuracy],
|
||||
self._train_with_acc = theano.function(train_ins, [train_loss, train_accuracy],
|
||||
updates=updates, allow_input_downcast=True, mode=theano_mode)
|
||||
self._predict = theano.function(predict_ins, self.y_test,
|
||||
self._predict = theano.function(predict_ins, self.y_test,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
self._test = theano.function(test_ins, test_score,
|
||||
self._test = theano.function(test_ins, test_loss,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
self._test_with_acc = theano.function(test_ins, [test_score, test_accuracy],
|
||||
self._test_with_acc = theano.function(test_ins, [test_loss, test_accuracy],
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
|
||||
def train(self, X, y, accuracy=False, sample_weight=None):
|
||||
warnings.warn('The "train" method is deprecated, use "train_on_batch" instead.')
|
||||
return self.train_on_batch(X, y, accuracy, sample_weight)
|
||||
|
||||
def train(self, X, y, accuracy=False):
|
||||
def test(self, X, y, accuracy=False):
|
||||
warnings.warn('The "test" method is deprecated, use "test_on_batch" instead.')
|
||||
return self.test_on_batch(X, y, accuracy)
|
||||
|
||||
def train_on_batch(self, X, y, accuracy=False, sample_weight=None):
|
||||
X = standardize_X(X)
|
||||
y = standardize_y(y)
|
||||
ins = X + [y]
|
||||
|
||||
if sample_weight is None:
|
||||
sample_weight = np.ones(list(y.shape[0:-1]) + [1])
|
||||
else:
|
||||
sample_weight = standardize_y(sample_weight)
|
||||
|
||||
ins = X + [y, sample_weight]
|
||||
if accuracy:
|
||||
return self._train_with_acc(*ins)
|
||||
else:
|
||||
return self._train(*ins)
|
||||
|
||||
|
||||
def test(self, X, y, accuracy=False):
|
||||
def test_on_batch(self, X, y, accuracy=False):
|
||||
X = standardize_X(X)
|
||||
y = standardize_y(y)
|
||||
ins = X + [y]
|
||||
sample_weight = np.ones(y.shape[:-1] + (1,))
|
||||
ins = X + [y, sample_weight]
|
||||
if accuracy:
|
||||
return self._test_with_acc(*ins)
|
||||
else:
|
||||
return self._test(*ins)
|
||||
|
||||
|
||||
def predict_on_batch(self, X):
|
||||
ins = standardize_X(X)
|
||||
return self._predict(*ins)
|
||||
|
||||
|
||||
def fit(self, X, y, batch_size=128, nb_epoch=100, verbose=1, callbacks=[],
|
||||
validation_split=0., validation_data=None, shuffle=True, show_accuracy=False):
|
||||
|
||||
validation_split=0., validation_data=None, shuffle=True, show_accuracy=False,
|
||||
class_weight=None, sample_weight=None):
|
||||
|
||||
X = standardize_X(X)
|
||||
y = standardize_y(y)
|
||||
sample_weight = standardize_weights(y, class_weight=class_weight, sample_weight=sample_weight)
|
||||
|
||||
do_validation = False
|
||||
val_f = None
|
||||
val_ins = None
|
||||
if validation_data or validation_split:
|
||||
if show_accuracy:
|
||||
val_f = self._test_with_acc
|
||||
else:
|
||||
val_f = self._test
|
||||
if validation_data:
|
||||
try:
|
||||
X_val, y_val = validation_data
|
||||
except:
|
||||
raise Exception("Invalid format for validation data; provide a tuple (X_val, y_val). \
|
||||
X_val may be a numpy array or a list of numpy arrays depending on your model input.")
|
||||
do_validation = True
|
||||
X_val = standardize_X(X_val)
|
||||
y_val = standardize_y(y_val)
|
||||
if verbose:
|
||||
print("Train on %d samples, validate on %d samples" % (len(y), len(y_val)))
|
||||
val_ins = X_val + [y_val, np.ones(y_val.shape[:-1] + (1,))]
|
||||
|
||||
if show_accuracy:
|
||||
f = self._train_with_acc
|
||||
out_labels = ['loss', 'acc']
|
||||
else:
|
||||
if 0 < validation_split < 1:
|
||||
# If a validation split size is given (e.g. validation_split=0.2)
|
||||
# then split X into smaller X and X_val,
|
||||
# and split y into smaller y and y_val.
|
||||
do_validation = True
|
||||
split_at = int(len(y) * (1 - validation_split))
|
||||
(X, X_val) = (slice_X(X, 0, split_at), slice_X(X, split_at))
|
||||
(y, y_val) = (y[0:split_at], y[split_at:])
|
||||
if verbose:
|
||||
print("Train on %d samples, validate on %d samples" % (len(y), len(y_val)))
|
||||
f = self._train
|
||||
out_labels = ['loss']
|
||||
|
||||
index_array = np.arange(len(y))
|
||||
ins = X + [y, sample_weight]
|
||||
metrics = ['loss', 'acc', 'val_loss', 'val_acc']
|
||||
return self._fit(f, ins, out_labels=out_labels, batch_size=batch_size, nb_epoch=nb_epoch, verbose=verbose, callbacks=callbacks, \
|
||||
validation_split=validation_split, val_f=val_f, val_ins=val_ins, shuffle=shuffle, metrics=metrics)
|
||||
|
||||
callbacks = cbks.CallbackList(callbacks)
|
||||
if verbose:
|
||||
callbacks.append(cbks.BaseLogger())
|
||||
callbacks.append(cbks.History())
|
||||
|
||||
callbacks._set_model(self)
|
||||
callbacks._set_params({
|
||||
'batch_size': batch_size,
|
||||
'nb_epoch': nb_epoch,
|
||||
'nb_sample': len(y),
|
||||
'verbose': verbose,
|
||||
'do_validation': do_validation,
|
||||
'show_accuracy': show_accuracy
|
||||
})
|
||||
callbacks.on_train_begin()
|
||||
|
||||
for epoch in range(nb_epoch):
|
||||
callbacks.on_epoch_begin(epoch)
|
||||
if shuffle:
|
||||
np.random.shuffle(index_array)
|
||||
|
||||
batches = make_batches(len(y), batch_size)
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
X_batch = slice_X(X, batch_ids)
|
||||
y_batch = y[batch_ids]
|
||||
|
||||
batch_logs = {}
|
||||
batch_logs['batch'] = batch_index
|
||||
batch_logs['size'] = len(batch_ids)
|
||||
callbacks.on_batch_begin(batch_index, batch_logs)
|
||||
|
||||
ins = X_batch + [y_batch]
|
||||
if show_accuracy:
|
||||
loss, acc = self._train_with_acc(*ins)
|
||||
batch_logs['accuracy'] = acc
|
||||
else:
|
||||
loss = self._train(*ins)
|
||||
batch_logs['loss'] = loss
|
||||
|
||||
callbacks.on_batch_end(batch_index, batch_logs)
|
||||
|
||||
if batch_index == len(batches) - 1: # last batch
|
||||
# validation
|
||||
epoch_logs = {}
|
||||
if do_validation:
|
||||
if show_accuracy:
|
||||
val_loss, val_acc = self.evaluate(X_val, y_val, batch_size=batch_size, \
|
||||
verbose=0, show_accuracy=True)
|
||||
epoch_logs['val_accuracy'] = val_acc
|
||||
else:
|
||||
val_loss = self.evaluate(X_val, y_val, batch_size=batch_size, verbose=0)
|
||||
epoch_logs['val_loss'] = val_loss
|
||||
|
||||
callbacks.on_epoch_end(epoch, epoch_logs)
|
||||
|
||||
callbacks.on_train_end()
|
||||
# return history
|
||||
return callbacks.callbacks[-1]
|
||||
|
||||
def predict(self, X, batch_size=128, verbose=1):
|
||||
def predict(self, X, batch_size=128, verbose=0):
|
||||
X = standardize_X(X)
|
||||
batches = make_batches(len(X[0]), batch_size)
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=len(X[0]))
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
X_batch = slice_X(X, batch_start, batch_end)
|
||||
batch_preds = self._predict(*X_batch)
|
||||
return self._predict_loop(self._predict, X, batch_size, verbose)[0]
|
||||
|
||||
if batch_index == 0:
|
||||
shape = (len(X[0]),) + batch_preds.shape[1:]
|
||||
preds = np.zeros(shape)
|
||||
preds[batch_start:batch_end] = batch_preds
|
||||
|
||||
if verbose == 1:
|
||||
progbar.update(batch_end)
|
||||
|
||||
return preds
|
||||
|
||||
def predict_proba(self, X, batch_size=128, verbose=1):
|
||||
preds = self.predict(X, batch_size, verbose)
|
||||
@@ -241,77 +433,21 @@ class Model(object):
|
||||
return (proba > 0.5).astype('int32')
|
||||
|
||||
|
||||
def evaluate(self, X, y, batch_size=128, show_accuracy=False, verbose=1):
|
||||
def evaluate(self, X, y, batch_size=128, show_accuracy=False, verbose=1, sample_weight=None):
|
||||
X = standardize_X(X)
|
||||
y = standardize_y(y)
|
||||
sample_weight = standardize_weights(y, sample_weight=sample_weight)
|
||||
|
||||
ins = X + [y, sample_weight]
|
||||
if show_accuracy:
|
||||
tot_acc = 0.
|
||||
tot_score = 0.
|
||||
seen = 0
|
||||
|
||||
batches = make_batches(len(y), batch_size)
|
||||
if verbose:
|
||||
progbar = Progbar(target=len(y), verbose=verbose)
|
||||
for batch_index, (batch_start, batch_end) in enumerate(batches):
|
||||
X_batch = slice_X(X, batch_start, batch_end)
|
||||
y_batch = y[batch_start:batch_end]
|
||||
|
||||
ins = X_batch + [y_batch]
|
||||
if show_accuracy:
|
||||
loss, acc = self._test_with_acc(*ins)
|
||||
tot_acc += acc * len(y_batch)
|
||||
log_values = [('loss', loss), ('acc.', acc)]
|
||||
else:
|
||||
loss = self._test(*ins)
|
||||
log_values = [('loss', loss)]
|
||||
tot_score += loss * len(y_batch)
|
||||
seen += len(y_batch)
|
||||
|
||||
# logging
|
||||
if verbose:
|
||||
progbar.update(batch_end, log_values)
|
||||
|
||||
if show_accuracy:
|
||||
return tot_score / seen, tot_acc / seen
|
||||
f = self._test_with_acc
|
||||
else:
|
||||
return tot_score / seen
|
||||
|
||||
|
||||
class Sequential(Model, containers.Sequential):
|
||||
'''
|
||||
Inherits from Model the following methods:
|
||||
- compile
|
||||
- train
|
||||
- test
|
||||
- evaluate
|
||||
- fit
|
||||
- predict
|
||||
- predict_proba
|
||||
- predict_classes
|
||||
|
||||
Inherits from containers.Sequential the following methods:
|
||||
- add
|
||||
- get_output
|
||||
- get_input
|
||||
- get_weights
|
||||
- set_weights
|
||||
'''
|
||||
def __init__(self):
|
||||
self.layers = []
|
||||
self.params = [] # learnable
|
||||
self.regularizers = [] # same size as params
|
||||
self.constraints = [] # same size as params
|
||||
|
||||
|
||||
def get_config(self, verbose=0):
|
||||
layers = []
|
||||
for i, l in enumerate(self.layers):
|
||||
config = l.get_config()
|
||||
layers.append(config)
|
||||
if verbose:
|
||||
printv(layers)
|
||||
return layers
|
||||
f = self._test
|
||||
outs = self._test_loop(f, ins, batch_size, verbose)
|
||||
if show_accuracy:
|
||||
return outs
|
||||
else:
|
||||
return outs[0]
|
||||
|
||||
|
||||
def save_weights(self, filepath, overwrite=False):
|
||||
@@ -344,7 +480,12 @@ class Sequential(Model, containers.Sequential):
|
||||
f.flush()
|
||||
f.close()
|
||||
|
||||
|
||||
def load_weights(self, filepath):
|
||||
'''
|
||||
This method does not make use of Sequential.set_weights()
|
||||
for backwards compatibility.
|
||||
'''
|
||||
# Loads weights from HDF5 file
|
||||
import h5py
|
||||
f = h5py.File(filepath)
|
||||
@@ -353,4 +494,157 @@ class Sequential(Model, containers.Sequential):
|
||||
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
|
||||
self.layers[k].set_weights(weights)
|
||||
f.close()
|
||||
|
||||
|
||||
|
||||
def to_yaml(self):
|
||||
'''
|
||||
Stores a model to yaml string, optionally with all learnable parameters
|
||||
If the model is compiled, it will also serialize the necessary components
|
||||
'''
|
||||
model_params = self.get_config()
|
||||
if hasattr(self, 'optimizer'):
|
||||
model_params['class_mode'] = self.class_mode
|
||||
model_params['theano_mode'] = self.theano_mode
|
||||
model_params['loss'] = self.unweighted_loss.__name__
|
||||
model_params['optimizer'] = self.optimizer.get_config()
|
||||
|
||||
return yaml.dump(model_params)
|
||||
|
||||
|
||||
class Graph(Model, containers.Graph):
|
||||
def compile(self, optimizer, loss, theano_mode=None):
|
||||
# loss is a dictionary mapping output name to loss functions
|
||||
ys = []
|
||||
ys_train = []
|
||||
ys_test = []
|
||||
train_loss = 0.
|
||||
test_loss = 0.
|
||||
for output_name in self.output_order:
|
||||
loss_fn = loss[output_name]
|
||||
output = self.outputs[output_name]
|
||||
y_train = output.get_output(True)
|
||||
y_test = output.get_output(False)
|
||||
y = T.zeros_like(y_test)
|
||||
ys.append(y)
|
||||
ys_train.append(y_train)
|
||||
ys_test.append(y_test)
|
||||
|
||||
train_loss += objectives.get(loss_fn)(y, y_train).mean()
|
||||
test_loss += objectives.get(loss_fn)(y, y_test).mean()
|
||||
|
||||
train_loss.name = 'train_loss'
|
||||
test_loss.name = 'test_loss'
|
||||
|
||||
ins = [self.inputs[name].input for name in self.input_order]
|
||||
train_ins = ins + ys
|
||||
test_ins = ins + ys
|
||||
|
||||
for r in self.regularizers:
|
||||
train_loss = r(train_loss)
|
||||
self.optimizer = optimizers.get(optimizer)
|
||||
updates = self.optimizer.get_updates(self.params, self.constraints, train_loss)
|
||||
self.theano_mode = theano_mode
|
||||
self.loss = loss
|
||||
|
||||
self._train = theano.function(train_ins, train_loss,
|
||||
updates=updates, allow_input_downcast=True, mode=theano_mode)
|
||||
self._test = theano.function(test_ins, test_loss,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
self._predict = theano.function(inputs=ins, outputs=ys_test,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
|
||||
def train_on_batch(self, data):
|
||||
# data is a dictionary mapping output and input names to arrays
|
||||
ins = [data[name] for name in self.input_order] + [standardize_y(data[name]) for name in self.output_order]
|
||||
return self._train(*ins)
|
||||
|
||||
def test_on_batch(self, data):
|
||||
# data is a dictionary mapping input names to arrays
|
||||
ins = [data[name] for name in self.input_order] + [standardize_y(data[name]) for name in self.output_order]
|
||||
return self._test(*ins)
|
||||
|
||||
def predict_on_batch(self, data):
|
||||
# data is a dictionary mapping input names to arrays
|
||||
ins = [data[name] for name in self.input_order]
|
||||
return self._predict(*ins)
|
||||
|
||||
def fit(self, data, batch_size=128, nb_epoch=100, verbose=1, callbacks=[],
|
||||
validation_split=0., validation_data=None, shuffle=True):
|
||||
ins = [data[name] for name in self.input_order] + [standardize_y(data[name]) for name in self.output_order]
|
||||
|
||||
val_f = None
|
||||
val_ins = None
|
||||
if validation_data or validation_split:
|
||||
val_f = self._test
|
||||
if validation_data:
|
||||
val_ins = [validation_data[name] for name in self.input_order] + [standardize_y(validation_data[name]) for name in self.output_order]
|
||||
|
||||
f = self._train
|
||||
out_labels = self.output_order
|
||||
metrics = self.output_order + ['val_' + m for m in self.output_order]
|
||||
history = self._fit(f, ins, out_labels=out_labels, batch_size=batch_size, nb_epoch=nb_epoch, verbose=verbose, callbacks=callbacks, \
|
||||
validation_split=validation_split, val_f=val_f, val_ins=val_ins, shuffle=shuffle, metrics=metrics)
|
||||
return history
|
||||
|
||||
def evaluate(self, data, batch_size=128, verbose=0):
|
||||
ins = [data[name] for name in self.input_order] + [standardize_y(data[name]) for name in self.output_order]
|
||||
outs = self._test_loop(self._test, ins, batch_size, verbose)
|
||||
return outs[0]
|
||||
|
||||
def predict(self, data, batch_size=128, verbose=0):
|
||||
ins = [data[name] for name in self.input_order]
|
||||
outs = self._predict_loop(self._predict, ins, batch_size, verbose)
|
||||
return dict(zip(self.output_order, outs))
|
||||
|
||||
def save_weights(self, filepath, overwrite=False):
|
||||
# Save weights from all layers to HDF5
|
||||
import h5py
|
||||
import os.path
|
||||
# if file exists and should not be overwritten
|
||||
if not overwrite and os.path.isfile(filepath):
|
||||
import sys
|
||||
get_input = input
|
||||
if sys.version_info[:2] <= (2, 7):
|
||||
get_input = raw_input
|
||||
overwrite = get_input('[WARNING] %s already exists - overwrite? [y/n]' % (filepath))
|
||||
while overwrite not in ['y', 'n']:
|
||||
overwrite = get_input('Enter "y" (overwrite) or "n" (cancel).')
|
||||
if overwrite == 'n':
|
||||
return
|
||||
print('[TIP] Next time specify overwrite=True in save_weights!')
|
||||
|
||||
f = h5py.File(filepath, 'w')
|
||||
g = f.create_group('graph')
|
||||
weights = self.get_weights()
|
||||
g.attrs['nb_params'] = len(weights)
|
||||
for n, param in enumerate(weights):
|
||||
param_name = 'param_{}'.format(n)
|
||||
param_dset = g.create_dataset(param_name, param.shape, dtype=param.dtype)
|
||||
param_dset[:] = param
|
||||
f.flush()
|
||||
f.close()
|
||||
|
||||
def load_weights(self, filepath):
|
||||
# Loads weights from HDF5 file
|
||||
import h5py
|
||||
f = h5py.File(filepath)
|
||||
g = f['graph']
|
||||
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
|
||||
self.set_weights(weights)
|
||||
f.close()
|
||||
|
||||
def to_yaml(self):
|
||||
'''
|
||||
Stores a model to yaml string, optionally with all learnable parameters
|
||||
If the model is compiled, it will also serialize the necessary components
|
||||
'''
|
||||
model_params = self.get_config()
|
||||
if hasattr(self, 'optimizer'):
|
||||
model_params['theano_mode'] = self.theano_mode
|
||||
model_params['loss'] = self.loss
|
||||
model_params['optimizer'] = self.optimizer.get_config()
|
||||
return yaml.dump(model_params)
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier):
|
||||
return get_from_module(identifier, globals(), 'model')
|
||||
|
||||
+21
-17
@@ -4,46 +4,50 @@ import theano.tensor as T
|
||||
import numpy as np
|
||||
from six.moves import range
|
||||
|
||||
epsilon = 1.0e-15
|
||||
if theano.config.floatX == 'float64':
|
||||
epsilon = 1.0e-9
|
||||
else:
|
||||
epsilon = 1.0e-7
|
||||
|
||||
def mean_squared_error(y_true, y_pred):
|
||||
return T.sqr(y_pred - y_true).mean()
|
||||
return T.sqr(y_pred - y_true).mean(axis=-1)
|
||||
|
||||
def mean_absolute_error(y_true, y_pred):
|
||||
return T.abs_(y_pred - y_true).mean()
|
||||
return T.abs_(y_pred - y_true).mean(axis=-1)
|
||||
|
||||
def mean_absolute_percentage_error(y_true, y_pred):
|
||||
return T.abs_((y_true - y_pred) / T.clip(T.abs_(y_true), epsilon, np.inf)).mean(axis=-1) * 100.
|
||||
|
||||
def mean_squared_logarithmic_error(y_true, y_pred):
|
||||
return T.sqr(T.log(T.clip(y_pred, epsilon, np.inf) + 1.) - T.log(T.clip(y_true, epsilon, np.inf) + 1.)).mean(axis=-1)
|
||||
|
||||
def squared_hinge(y_true, y_pred):
|
||||
return T.sqr(T.maximum(1. - y_true * y_pred, 0.)).mean()
|
||||
return T.sqr(T.maximum(1. - y_true * y_pred, 0.)).mean(axis=-1)
|
||||
|
||||
def hinge(y_true, y_pred):
|
||||
return T.maximum(1. - y_true * y_pred, 0.).mean()
|
||||
return T.maximum(1. - y_true * y_pred, 0.).mean(axis=-1)
|
||||
|
||||
def categorical_crossentropy(y_true, y_pred):
|
||||
'''Expects a binary class matrix instead of a vector of scalar classes
|
||||
'''
|
||||
y_pred = T.clip(y_pred, epsilon, 1.0 - epsilon)
|
||||
# scale preds so that the class probas of each sample sum to 1
|
||||
y_pred /= y_pred.sum(axis=1, keepdims=True)
|
||||
return T.nnet.categorical_crossentropy(y_pred, y_true).mean()
|
||||
y_pred /= y_pred.sum(axis=-1, keepdims=True)
|
||||
cce = T.nnet.categorical_crossentropy(y_pred, y_true)
|
||||
return cce
|
||||
|
||||
def binary_crossentropy(y_true, y_pred):
|
||||
y_pred = T.clip(y_pred, epsilon, 1.0 - epsilon)
|
||||
return T.nnet.binary_crossentropy(y_pred, y_true).mean()
|
||||
bce = T.nnet.binary_crossentropy(y_pred, y_true).mean(axis=-1)
|
||||
return bce
|
||||
|
||||
# aliases
|
||||
mse = MSE = mean_squared_error
|
||||
mae = MAE = mean_absolute_error
|
||||
mape = MAPE = mean_absolute_percentage_error
|
||||
msle = MSLE = mean_squared_logarithmic_error
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier):
|
||||
return get_from_module(identifier, globals(), 'objective')
|
||||
|
||||
def to_categorical(y):
|
||||
'''Convert class vector (integers from 0 to nb_classes)
|
||||
to binary class matrix, for use with categorical_crossentropy
|
||||
'''
|
||||
nb_classes = np.max(y)+1
|
||||
Y = np.zeros((len(y), nb_classes))
|
||||
for i in range(len(y)):
|
||||
Y[i, y[i]] = 1.
|
||||
return Y
|
||||
|
||||
+52
-25
@@ -8,31 +8,29 @@ from six.moves import zip
|
||||
|
||||
def clip_norm(g, c, n):
|
||||
if c > 0:
|
||||
g = T.switch(T.ge(n, c), g*c/n, g)
|
||||
g = T.switch(T.ge(n, c), g * c / n, g)
|
||||
return g
|
||||
|
||||
def kl_divergence(p, p_hat):
|
||||
return p_hat - p + p*T.log(p/p_hat)
|
||||
return p_hat - p + p * T.log(p / p_hat)
|
||||
|
||||
class Optimizer(object):
|
||||
|
||||
def get_updates(self, params, grads):
|
||||
def get_updates(self, params, constraints, loss):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_gradients(self, cost, params, regularizers):
|
||||
grads = T.grad(cost, params)
|
||||
def get_gradients(self, loss, params):
|
||||
|
||||
grads = T.grad(loss, params)
|
||||
|
||||
if hasattr(self, 'clipnorm') and self.clipnorm > 0:
|
||||
norm = T.sqrt(sum([T.sum(g**2) for g in grads]))
|
||||
norm = T.sqrt(sum([T.sum(g ** 2) for g in grads]))
|
||||
grads = [clip_norm(g, self.clipnorm, norm) for g in grads]
|
||||
|
||||
new_grads = []
|
||||
for p, g, r in zip(params, grads, regularizers):
|
||||
g = r(g, p)
|
||||
new_grads.append(g)
|
||||
|
||||
return new_grads
|
||||
return grads
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__}
|
||||
|
||||
class SGD(Optimizer):
|
||||
|
||||
@@ -41,10 +39,10 @@ class SGD(Optimizer):
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = shared_scalar(0)
|
||||
|
||||
def get_updates(self, params, regularizers, constraints, cost):
|
||||
grads = self.get_gradients(cost, params, regularizers)
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
lr = self.lr * (1.0 / (1.0 + self.decay * self.iterations))
|
||||
updates = [(self.iterations, self.iterations+1.)]
|
||||
updates = [(self.iterations, self.iterations + 1.)]
|
||||
|
||||
for p, g, c in zip(params, grads, constraints):
|
||||
m = shared_zeros(p.get_value().shape) # momentum
|
||||
@@ -59,6 +57,13 @@ class SGD(Optimizer):
|
||||
updates.append((p, c(new_p))) # apply constraints
|
||||
return updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"lr":self.lr,
|
||||
"momentum":self.momentum,
|
||||
"decay":self.decay,
|
||||
"nesterov":self.nesterov}
|
||||
|
||||
|
||||
class RMSprop(Optimizer):
|
||||
|
||||
@@ -66,8 +71,8 @@ class RMSprop(Optimizer):
|
||||
self.__dict__.update(kwargs)
|
||||
self.__dict__.update(locals())
|
||||
|
||||
def get_updates(self, params, regularizers, constraints, cost):
|
||||
grads = self.get_gradients(cost, params, regularizers)
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
accumulators = [shared_zeros(p.get_value().shape) for p in params]
|
||||
updates = []
|
||||
|
||||
@@ -80,6 +85,11 @@ class RMSprop(Optimizer):
|
||||
|
||||
return updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"lr":self.lr,
|
||||
"rho":self.rho,
|
||||
"epsilon":self.epsilon}
|
||||
|
||||
class Adagrad(Optimizer):
|
||||
|
||||
@@ -87,8 +97,8 @@ class Adagrad(Optimizer):
|
||||
self.__dict__.update(kwargs)
|
||||
self.__dict__.update(locals())
|
||||
|
||||
def get_updates(self, params, regularizers, constraints, cost):
|
||||
grads = self.get_gradients(cost, params, regularizers)
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
accumulators = [shared_zeros(p.get_value().shape) for p in params]
|
||||
updates = []
|
||||
|
||||
@@ -100,6 +110,10 @@ class Adagrad(Optimizer):
|
||||
updates.append((p, c(new_p))) # apply constraints
|
||||
return updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"lr":self.lr,
|
||||
"epsilon":self.epsilon}
|
||||
|
||||
class Adadelta(Optimizer):
|
||||
'''
|
||||
@@ -109,8 +123,8 @@ class Adadelta(Optimizer):
|
||||
self.__dict__.update(kwargs)
|
||||
self.__dict__.update(locals())
|
||||
|
||||
def get_updates(self, params, regularizers, constraints, cost):
|
||||
grads = self.get_gradients(cost, params, regularizers)
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
accumulators = [shared_zeros(p.get_value().shape) for p in params]
|
||||
delta_accumulators = [shared_zeros(p.get_value().shape) for p in params]
|
||||
updates = []
|
||||
@@ -130,6 +144,11 @@ class Adadelta(Optimizer):
|
||||
updates.append((d_a, new_d_a))
|
||||
return updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"lr":self.lr,
|
||||
"rho":self.rho,
|
||||
"epsilon":self.epsilon}
|
||||
|
||||
class Adam(Optimizer):
|
||||
'''
|
||||
@@ -144,8 +163,8 @@ class Adam(Optimizer):
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = shared_scalar(0)
|
||||
|
||||
def get_updates(self, params, regularizers, constraints, cost):
|
||||
grads = self.get_gradients(cost, params, regularizers)
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
updates = [(self.iterations, self.iterations+1.)]
|
||||
|
||||
i = self.iterations
|
||||
@@ -171,6 +190,14 @@ class Adam(Optimizer):
|
||||
updates.append((p, c(p_t))) # apply constraints
|
||||
return updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"lr":self.lr,
|
||||
"beta_1":self.beta_1,
|
||||
"beta_2":self.beta_2,
|
||||
"epsilon":self.epsilon,
|
||||
"kappa":self.kappa}
|
||||
|
||||
# aliases
|
||||
sgd = SGD
|
||||
rmsprop = RMSprop
|
||||
@@ -179,5 +206,5 @@ adadelta = Adadelta
|
||||
adam = Adam
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier):
|
||||
return get_from_module(identifier, globals(), 'optimizer', instantiate=True)
|
||||
def get(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'optimizer', instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -4,13 +4,17 @@ import numpy as np
|
||||
import random
|
||||
from six.moves import range
|
||||
|
||||
def pad_sequences(sequences, maxlen=None, dtype='int32'):
|
||||
def pad_sequences(sequences, maxlen=None, dtype='int32', padding='pre', truncating='pre', value=0.):
|
||||
"""
|
||||
Pad each sequence to the same length:
|
||||
the length of the longuest sequence.
|
||||
|
||||
If maxlen is provided, any sequence longer
|
||||
than maxlen is truncated to maxlen.
|
||||
than maxlen is truncated to maxlen. Truncation happens off either the beginning (default) or
|
||||
the end of the sequence.
|
||||
|
||||
Supports post-padding and pre-padding (default).
|
||||
|
||||
"""
|
||||
lengths = [len(s) for s in sequences]
|
||||
|
||||
@@ -18,9 +22,21 @@ def pad_sequences(sequences, maxlen=None, dtype='int32'):
|
||||
if maxlen is None:
|
||||
maxlen = np.max(lengths)
|
||||
|
||||
x = np.zeros((nb_samples, maxlen)).astype(dtype)
|
||||
x = (np.ones((nb_samples, maxlen)) * value).astype(dtype)
|
||||
for idx, s in enumerate(sequences):
|
||||
x[idx, :lengths[idx]] = s[:maxlen]
|
||||
if truncating == 'pre':
|
||||
trunc = s[-maxlen:]
|
||||
elif truncating == 'post':
|
||||
trunc = s[:maxlen]
|
||||
else:
|
||||
raise ValueError("Truncating type '%s' not understood" % padding)
|
||||
|
||||
if padding == 'post':
|
||||
x[idx, :len(trunc)] = trunc
|
||||
elif padding == 'pre':
|
||||
x[idx, -len(trunc):] = trunc
|
||||
else:
|
||||
raise ValueError("Padding type '%s' not understood" % padding)
|
||||
return x
|
||||
|
||||
|
||||
|
||||
+69
-20
@@ -1,26 +1,75 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
def l1(l=.01):
|
||||
def l1wrap(g, p):
|
||||
g += T.sgn(p) * l
|
||||
return g
|
||||
return l1wrap
|
||||
class Regularizer(object):
|
||||
def set_param(self, p):
|
||||
self.p = p
|
||||
|
||||
def l2(l=.01):
|
||||
def l2wrap(g, p):
|
||||
g += p * l
|
||||
return g
|
||||
return l2wrap
|
||||
def set_layer(self, layer):
|
||||
self.layer = layer
|
||||
|
||||
def l1l2(l1=.01, l2=.01):
|
||||
def l1l2wrap(g, p):
|
||||
g += T.sgn(p) * l1
|
||||
g += p * l2
|
||||
return g
|
||||
return l1l2wrap
|
||||
def __call__(self, loss):
|
||||
return loss
|
||||
|
||||
def identity(g, p):
|
||||
return g
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__}
|
||||
|
||||
class WeightRegularizer(Regularizer):
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
|
||||
def set_param(self, p):
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
loss += T.sum(abs(self.p)) * self.l1
|
||||
loss += T.sum(self.p ** 2) * self.l2
|
||||
return loss
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"l1":self.l1,
|
||||
"l2":self.l2}
|
||||
|
||||
class ActivityRegularizer(Regularizer):
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
|
||||
def set_layer(self, layer):
|
||||
self.layer = layer
|
||||
|
||||
def __call__(self, loss):
|
||||
loss += self.l1 * T.sum(T.mean(abs(self.layer.get_output(True)), axis=0))
|
||||
loss += self.l2 * T.sum(T.mean(self.layer.get_output(True) ** 2, axis=0))
|
||||
return loss
|
||||
|
||||
def get_config(self):
|
||||
return {"name":self.__class__.__name__,
|
||||
"l1":self.l1,
|
||||
"l2":self.l2}
|
||||
|
||||
def l1(l=0.01):
|
||||
return WeightRegularizer(l1=l)
|
||||
|
||||
def l2(l=0.01):
|
||||
return WeightRegularizer(l2=l)
|
||||
|
||||
def l1l2(l1=0.01, l2=0.01):
|
||||
return WeightRegularizer(l1=l1, l2=l2)
|
||||
|
||||
def activity_l1(l=0.01):
|
||||
return ActivityRegularizer(l1=l)
|
||||
|
||||
def activity_l2(l=0.01):
|
||||
return ActivityRegularizer(l2=l)
|
||||
|
||||
def activity_l1l2(l1=0.01, l2=0.01):
|
||||
return ActivityRegularizer(l1=l1, l2=l2)
|
||||
|
||||
identity = Regularizer
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'regularizer', instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -2,14 +2,17 @@ from __future__ import absolute_import
|
||||
import numpy as np
|
||||
import time
|
||||
import sys
|
||||
import six
|
||||
|
||||
def get_from_module(identifier, module_params, module_name, instantiate=False):
|
||||
if type(identifier) is str:
|
||||
def get_from_module(identifier, module_params, module_name, instantiate=False, kwargs=None):
|
||||
if isinstance(identifier, six.string_types):
|
||||
res = module_params.get(identifier)
|
||||
if not res:
|
||||
raise Exception('Invalid ' + str(module_name) + ': ' + str(identifier))
|
||||
if instantiate:
|
||||
if instantiate and not kwargs:
|
||||
return res()
|
||||
elif instantiate and kwargs:
|
||||
return res(**kwargs)
|
||||
else:
|
||||
return res
|
||||
return identifier
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
import inspect
|
||||
import numpy as np
|
||||
|
||||
from ..layers.advanced_activations import LeakyReLU, PReLU
|
||||
from ..layers.core import Dense, Merge, Dropout, Activation, Reshape, Flatten, RepeatVector, Layer
|
||||
from ..layers.core import ActivityRegularization, TimeDistributedDense, AutoEncoder, MaxoutDense
|
||||
from ..layers.embeddings import Embedding, WordContextProduct
|
||||
from ..layers.noise import GaussianNoise, GaussianDropout
|
||||
from ..layers.normalization import BatchNormalization
|
||||
from ..layers.recurrent import SimpleRNN, SimpleDeepRNN, GRU, LSTM, JZS1, JZS2, JZS3
|
||||
from ..layers import containers
|
||||
|
||||
from .. import regularizers
|
||||
from .. import constraints
|
||||
|
||||
|
||||
def container_from_config(layer_dict):
|
||||
name = layer_dict.get('name')
|
||||
hasParams = False
|
||||
|
||||
if name == 'Merge':
|
||||
mode = layer_dict.get('mode')
|
||||
layers = layer_dict.get('layers')
|
||||
layer_list = []
|
||||
for layer in layers:
|
||||
init_layer = container_from_config(layer)
|
||||
layer_list.append(init_layer)
|
||||
merge_layer = Merge(layer_list, mode)
|
||||
return merge_layer
|
||||
|
||||
elif name == 'Sequential':
|
||||
layers = layer_dict.get('layers')
|
||||
layer_list = []
|
||||
for layer in layers:
|
||||
init_layer = container_from_config(layer)
|
||||
layer_list.append(init_layer)
|
||||
seq_layer = containers.Sequential(layer_list)
|
||||
return seq_layer
|
||||
|
||||
elif name == 'Graph':
|
||||
graph_layer = containers.Graph()
|
||||
inputs = layer_dict.get('input_config')
|
||||
|
||||
for input in inputs:
|
||||
graph_layer.add_input(**input)
|
||||
|
||||
nodes = layer_dict.get('node_config')
|
||||
for node in nodes:
|
||||
layer = container_from_config(layer_dict['nodes'].get(node['name']))
|
||||
node['layer'] = layer
|
||||
graph_layer.add_node(**node)
|
||||
|
||||
outputs = layer_dict.get('output_config')
|
||||
for output in outputs:
|
||||
graph_layer.add_output(**output)
|
||||
return graph_layer
|
||||
|
||||
else: # The case in which layer_dict represents an "atomic" layer
|
||||
layer_dict.pop('name')
|
||||
if 'parameters' in layer_dict:
|
||||
params = layer_dict.get('parameters')
|
||||
layer_dict.pop('parameters')
|
||||
hasParams = True
|
||||
|
||||
for k, v in layer_dict.items():
|
||||
# For now, this can only happen for regularizers and constraints
|
||||
if isinstance(v, dict):
|
||||
vname = v.get('name')
|
||||
v.pop('name')
|
||||
if vname in [x for x,y in inspect.getmembers(constraints, predicate=inspect.isclass)]:
|
||||
layer_dict[k] = constraints.get(vname, v)
|
||||
if vname in [x for x,y in inspect.getmembers(regularizers, predicate=inspect.isclass)]:
|
||||
layer_dict[k] = regularizers.get(vname, v)
|
||||
|
||||
base_layer = get_layer(name, layer_dict)
|
||||
if hasParams:
|
||||
shaped_params = []
|
||||
for param in params:
|
||||
data = np.asarray(param.get('data'))
|
||||
shape = tuple(param.get('shape'))
|
||||
shaped_params.append(data.reshape(shape))
|
||||
base_layer.set_weights(shaped_params)
|
||||
return base_layer
|
||||
|
||||
|
||||
from .generic_utils import get_from_module
|
||||
def get_layer(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'layer', instantiate=True, kwargs=kwargs)
|
||||
@@ -21,7 +21,6 @@ def normalize(a, axis=-1, order=2):
|
||||
l2[l2==0] = 1
|
||||
return a / np.expand_dims(l2, axis)
|
||||
|
||||
|
||||
def binary_logloss(p, y):
|
||||
epsilon = 1e-15
|
||||
p = sp.maximum(epsilon, p)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import numpy as np
|
||||
|
||||
def get_test_data(nb_train=1000, nb_test=500, input_shape=(10,), output_shape=(2,),
|
||||
classification=True, nb_class=2):
|
||||
'''
|
||||
classification=True overrides output_shape
|
||||
(i.e. output_shape is set to (1,)) and the output
|
||||
consists in integers in [0, nb_class-1].
|
||||
|
||||
Otherwise: float output with shape output_shape.
|
||||
'''
|
||||
nb_sample = nb_train + nb_test
|
||||
if classification:
|
||||
y = np.random.randint(0, nb_class, size=(nb_sample, 1))
|
||||
X = np.zeros((nb_sample,) + input_shape)
|
||||
for i in range(nb_sample):
|
||||
X[i] = np.random.normal(loc=y[i], scale=1.0, size=input_shape)
|
||||
else:
|
||||
y_loc = np.random.random((nb_sample,))
|
||||
X = np.zeros((nb_sample,) + input_shape)
|
||||
y = np.zeros((nb_sample,) + output_shape)
|
||||
for i in range(nb_sample):
|
||||
X[i] = np.random.normal(loc=y_loc[i], scale=1.0, size=input_shape)
|
||||
y[i] = np.random.normal(loc=y_loc[i], scale=1.0, size=output_shape)
|
||||
|
||||
return (X[:nb_train], y[:nb_train]), (X[nb_train:], y[nb_train:])
|
||||
@@ -20,3 +20,4 @@ def shared_ones(shape, dtype=theano.config.floatX, name=None):
|
||||
|
||||
def alloc_zeros_matrix(*dims):
|
||||
return T.alloc(np.cast[theano.config.floatX](0.), *dims)
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
[metadata]
|
||||
description-file = README.md
|
||||
+11
-10
@@ -1,13 +1,14 @@
|
||||
from setuptools import setup
|
||||
from setuptools import find_packages
|
||||
|
||||
setup(name='Keras',
|
||||
version='0.0.1',
|
||||
description='Theano-based Deep Learning',
|
||||
author='Francois Chollet',
|
||||
author_email='francois.chollet@gmail.com',
|
||||
url='https://github.com/fchollet/keras',
|
||||
license='MIT',
|
||||
install_requires=['theano'],
|
||||
packages=find_packages(),
|
||||
)
|
||||
setup(name = 'Keras',
|
||||
version = '0.1.1',
|
||||
description = 'Theano-based Deep Learning library',
|
||||
author = 'Francois Chollet',
|
||||
author_email = 'francois.chollet@gmail.com',
|
||||
url = 'https://github.com/fchollet/keras',
|
||||
download_url = 'https://github.com/fchollet/keras/tarball/0.1.1',
|
||||
license = 'MIT',
|
||||
install_requires = ['theano', 'pyyaml'],
|
||||
packages = find_packages(),
|
||||
)
|
||||
@@ -1,184 +0,0 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation, Merge
|
||||
from keras.utils import np_utils
|
||||
import numpy as np
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 1
|
||||
|
||||
max_train_samples = 5000
|
||||
max_test_samples = 1000
|
||||
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(60000,784)[:max_train_samples]
|
||||
X_test = X_test.reshape(10000,784)[:max_test_samples]
|
||||
X_train = X_train.astype("float32")
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
|
||||
# convert class vectors to binary class matrices
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)[:max_train_samples]
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)[:max_test_samples]
|
||||
|
||||
#########################
|
||||
# sequential model test #
|
||||
#########################
|
||||
print('Test sequential')
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 50))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(50, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=(X_test, Y_test))
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=(X_test, Y_test))
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
score = model.evaluate(X_train, Y_train, verbose=0)
|
||||
print('score:', score)
|
||||
if score < 0.25:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict(X_test, verbose=0)
|
||||
classes = model.predict_classes(X_test, verbose=0)
|
||||
|
||||
model.get_config(verbose=1)
|
||||
|
||||
###################
|
||||
# merge test: sum #
|
||||
###################
|
||||
print('Test merge: sum')
|
||||
left = Sequential()
|
||||
left.add(Dense(784, 50))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(784, 50))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='sum'))
|
||||
|
||||
model.add(Dense(50, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=([X_test, X_test], Y_test))
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=([X_test, X_test], Y_test))
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
score = model.evaluate([X_train, X_train], Y_train, verbose=0)
|
||||
print('score:', score)
|
||||
if score < 0.22:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict([X_test, X_test], verbose=0)
|
||||
classes = model.predict_classes([X_test, X_test], verbose=0)
|
||||
|
||||
model.get_config(verbose=1)
|
||||
|
||||
###################
|
||||
# merge test: concat #
|
||||
###################
|
||||
print('Test merge: concat')
|
||||
left = Sequential()
|
||||
left.add(Dense(784, 50))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(784, 50))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='concat'))
|
||||
|
||||
model.add(Dense(50*2, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=([X_test, X_test], Y_test))
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=([X_test, X_test], Y_test))
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit([X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
score = model.evaluate([X_train, X_train], Y_train, verbose=0)
|
||||
print('score:', score)
|
||||
if score < 0.22:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict([X_test, X_test], verbose=0)
|
||||
classes = model.predict_classes([X_test, X_test], verbose=0)
|
||||
|
||||
model.get_config(verbose=1)
|
||||
|
||||
##########################
|
||||
# test merge recursivity #
|
||||
##########################
|
||||
print('Test merge recursivity')
|
||||
|
||||
left = Sequential()
|
||||
left.add(Dense(784, 50))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(784, 50))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
righter = Sequential()
|
||||
righter.add(Dense(784, 50))
|
||||
righter.add(Activation('relu'))
|
||||
|
||||
intermediate = Sequential()
|
||||
intermediate.add(Merge([left, right], mode='sum'))
|
||||
intermediate.add(Dense(50, 50))
|
||||
intermediate.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([intermediate, righter], mode='sum'))
|
||||
|
||||
model.add(Dense(50, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit([X_train, X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=([X_test, X_test, X_test], Y_test))
|
||||
model.fit([X_train, X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=([X_test, X_test, X_test], Y_test))
|
||||
model.fit([X_train, X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit([X_train, X_train, X_train], Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
score = model.evaluate([X_train, X_train, X_train], Y_train, verbose=0)
|
||||
print('score:', score)
|
||||
if score < 0.19:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict([X_test, X_test, X_test], verbose=0)
|
||||
classes = model.predict_classes([X_test, X_test, X_test], verbose=0)
|
||||
|
||||
model.get_config(verbose=1)
|
||||
|
||||
model.save_weights('temp.h5')
|
||||
model.load_weights('temp.h5')
|
||||
|
||||
score = model.evaluate([X_train, X_train, X_train], Y_train, verbose=0)
|
||||
print('score:', score)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
import math
|
||||
|
||||
import keras
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
|
||||
import numpy
|
||||
|
||||
def list_assert_equal(a, b, round_to=7):
|
||||
'''
|
||||
This will do a pairwise, rounded equality test across two lists of
|
||||
numbers.
|
||||
'''
|
||||
pairs = zip(a, b)
|
||||
for i, j in pairs:
|
||||
assert round(i, round_to) == round(j, round_to)
|
||||
|
||||
def get_standard_values():
|
||||
'''
|
||||
These are just a set of floats used for testing the activation
|
||||
functions, and are useful in multiple tests.
|
||||
'''
|
||||
|
||||
return [0,0.1,0.5,0.9,1.0]
|
||||
|
||||
def test_softmax():
|
||||
|
||||
from keras.activations import softmax as s
|
||||
|
||||
# Test using a reference implementation of softmax
|
||||
def softmax(values):
|
||||
m = max(values)
|
||||
values = numpy.array(values)
|
||||
e = numpy.exp(values - m)
|
||||
dist = list(e / numpy.sum(e))
|
||||
|
||||
return dist
|
||||
|
||||
x = T.vector()
|
||||
exp = s(x)
|
||||
f = theano.function([x], exp)
|
||||
test_values=get_standard_values()
|
||||
|
||||
result = f(test_values)
|
||||
expected = softmax(test_values)
|
||||
|
||||
print(str(result))
|
||||
print(str(expected))
|
||||
|
||||
list_assert_equal(result, expected)
|
||||
|
||||
def test_relu():
|
||||
'''
|
||||
Relu implementation doesn't depend on the value being
|
||||
a theano variable. Testing ints, floats and theano tensors.
|
||||
'''
|
||||
|
||||
from keras.activations import relu as r
|
||||
|
||||
assert r(5) == 5
|
||||
assert r(-5) == 0
|
||||
assert r(-0.1) == 0
|
||||
assert r(0.1) == 0.1
|
||||
|
||||
x = T.vector()
|
||||
exp = r(x)
|
||||
f = theano.function([x], exp)
|
||||
|
||||
test_values = get_standard_values()
|
||||
result = f(test_values)
|
||||
|
||||
list_assert_equal(result, test_values) # because no negatives in test values
|
||||
|
||||
|
||||
def test_tanh():
|
||||
|
||||
from keras.activations import tanh as t
|
||||
test_values = get_standard_values()
|
||||
|
||||
x = T.vector()
|
||||
exp = t(x)
|
||||
f = theano.function([x], exp)
|
||||
|
||||
result = f(test_values)
|
||||
expected = [math.tanh(v) for v in test_values]
|
||||
|
||||
print(result)
|
||||
print(expected)
|
||||
|
||||
list_assert_equal(result, expected)
|
||||
|
||||
|
||||
def test_linear():
|
||||
'''
|
||||
This function does no input validation, it just returns the thing
|
||||
that was passed in.
|
||||
'''
|
||||
|
||||
from keras.activations import linear as l
|
||||
|
||||
xs = [1, 5, True, None, 'foo']
|
||||
|
||||
for x in xs:
|
||||
assert x == l(x)
|
||||
@@ -0,0 +1,69 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
from theano import tensor as T
|
||||
|
||||
|
||||
class TestConstraints(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.some_values = [0.1, 0.5, 3, 8, 1e-7]
|
||||
np.random.seed(3537)
|
||||
self.example_array = np.random.random((100, 100)) * 100. - 50.
|
||||
self.example_array[0, 0] = 0. # 0 could possibly cause trouble
|
||||
|
||||
def test_maxnorm(self):
|
||||
from keras.constraints import maxnorm
|
||||
|
||||
for m in self.some_values:
|
||||
norm_instance = maxnorm(m)
|
||||
normed = norm_instance(self.example_array)
|
||||
assert (np.all(normed.eval() < m))
|
||||
|
||||
# a more explicit example
|
||||
norm_instance = maxnorm(2.0)
|
||||
x = np.array([[0, 0, 0], [1.0, 0, 0], [3, 0, 0], [3, 3, 3]]).T
|
||||
x_normed_target = np.array([[0, 0, 0], [1.0, 0, 0], [2.0, 0, 0], [2./np.sqrt(3), 2./np.sqrt(3), 2./np.sqrt(3)]]).T
|
||||
x_normed_actual = norm_instance(x).eval()
|
||||
assert_allclose(x_normed_actual, x_normed_target)
|
||||
|
||||
def test_nonneg(self):
|
||||
from keras.constraints import nonneg
|
||||
|
||||
nonneg_instance = nonneg()
|
||||
|
||||
normed = nonneg_instance(self.example_array)
|
||||
assert (np.all(np.min(normed.eval(), axis=1) == 0.))
|
||||
|
||||
def test_identity(self):
|
||||
from keras.constraints import identity
|
||||
|
||||
identity_instance = identity()
|
||||
|
||||
normed = identity_instance(self.example_array)
|
||||
assert (np.all(normed == self.example_array))
|
||||
|
||||
def test_identity_oddballs(self):
|
||||
"""
|
||||
test the identity constraint on some more exotic input.
|
||||
this does not need to pass for the desired real life behaviour,
|
||||
but it should in the current implementation.
|
||||
"""
|
||||
from keras.constraints import identity
|
||||
identity_instance = identity()
|
||||
|
||||
oddball_examples = ["Hello", [1], -1, None]
|
||||
assert(oddball_examples == identity_instance(oddball_examples))
|
||||
|
||||
def test_unitnorm(self):
|
||||
from keras.constraints import unitnorm
|
||||
unitnorm_instance = unitnorm()
|
||||
|
||||
normalized = unitnorm_instance(self.example_array)
|
||||
|
||||
norm_of_normalized = np.sqrt(np.sum(normalized.eval()**2, axis=1))
|
||||
difference = norm_of_normalized - 1. #in the unit norm constraint, it should be equal to 1.
|
||||
largest_difference = np.max(np.abs(difference))
|
||||
self.assertAlmostEqual(largest_difference, 0.)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -14,7 +14,7 @@ class TestConcatenation(unittest.TestCase):
|
||||
|
||||
def test_unitnorm_constraint(self):
|
||||
lookup = Sequential()
|
||||
lookup.add(Embedding(3, 2, weights=[self.W1], W_constraint=unitnorm))
|
||||
lookup.add(Embedding(3, 2, weights=[self.W1], W_constraint=unitnorm()))
|
||||
lookup.add(Flatten())
|
||||
lookup.add(Dense(2, 1))
|
||||
lookup.add(Activation('sigmoid'))
|
||||
@@ -0,0 +1,160 @@
|
||||
from __future__ import print_function
|
||||
import unittest
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
from keras.models import Graph, Sequential
|
||||
from keras.layers import containers
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.utils.test_utils import get_test_data
|
||||
|
||||
X = np.random.random((100, 32))
|
||||
X2 = np.random.random((100, 32))
|
||||
y = np.random.random((100, 4))
|
||||
y2 = np.random.random((100,))
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(32,),
|
||||
classification=False, output_shape=(4,))
|
||||
(X2_train, y2_train), (X2_test, y2_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(32,),
|
||||
classification=False, output_shape=(1,))
|
||||
|
||||
class TestGraph(unittest.TestCase):
|
||||
def test_1o_1i(self):
|
||||
print('test a non-sequential graph with 1 input and 1 output')
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
graph.compile('rmsprop', {'output1':'mse'})
|
||||
|
||||
history = graph.fit({'input1':X_train, 'output1':y_train}, nb_epoch=10)
|
||||
out = graph.predict({'input1':X_test})
|
||||
assert(type(out == dict))
|
||||
assert(len(out) == 1)
|
||||
loss = graph.test_on_batch({'input1':X_test, 'output1':y_test})
|
||||
loss = graph.train_on_batch({'input1':X_test, 'output1':y_test})
|
||||
loss = graph.evaluate({'input1':X_test, 'output1':y_test})
|
||||
print(loss)
|
||||
assert(loss < 2.5)
|
||||
|
||||
def test_1o_1i_2(self):
|
||||
print('test a more complex non-sequential graph with 1 input and 1 output')
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2-0', input='input1')
|
||||
graph.add_node(Activation('relu'), name='dense2', input='dense2-0')
|
||||
|
||||
graph.add_node(Dense(4, 16), name='dense3', input='dense2')
|
||||
graph.add_node(Dense(16, 4), name='dense4', inputs=['dense1', 'dense3'], merge_mode='sum')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense4'], merge_mode='sum')
|
||||
graph.compile('rmsprop', {'output1':'mse'})
|
||||
|
||||
history = graph.fit({'input1':X_train, 'output1':y_train}, nb_epoch=10)
|
||||
out = graph.predict({'input1':X_train})
|
||||
assert(type(out == dict))
|
||||
assert(len(out) == 1)
|
||||
loss = graph.test_on_batch({'input1':X_test, 'output1':y_test})
|
||||
loss = graph.train_on_batch({'input1':X_test, 'output1':y_test})
|
||||
loss = graph.evaluate({'input1':X_test, 'output1':y_test})
|
||||
print(loss)
|
||||
assert(loss < 2.5)
|
||||
graph.get_config(verbose=1)
|
||||
|
||||
def test_1o_2i(self):
|
||||
print('test a non-sequential graph with 2 inputs and 1 output')
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
graph.add_input(name='input2', ndim=2)
|
||||
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input2')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
graph.compile('rmsprop', {'output1':'mse'})
|
||||
|
||||
history = graph.fit({'input1':X_train, 'input2':X2_train, 'output1':y_train}, nb_epoch=10)
|
||||
out = graph.predict({'input1':X_test, 'input2':X2_test})
|
||||
assert(type(out == dict))
|
||||
assert(len(out) == 1)
|
||||
loss = graph.test_on_batch({'input1':X_test, 'input2':X2_test, 'output1':y_test})
|
||||
loss = graph.train_on_batch({'input1':X_test, 'input2':X2_test, 'output1':y_test})
|
||||
loss = graph.evaluate({'input1':X_test, 'input2':X2_test, 'output1':y_test})
|
||||
print(loss)
|
||||
assert(loss < 3.0)
|
||||
graph.get_config(verbose=1)
|
||||
|
||||
def test_2o_1i_weights(self):
|
||||
print('test a non-sequential graph with 1 input and 2 outputs')
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(16, 1), name='dense3', input='dense1')
|
||||
|
||||
graph.add_output(name='output1', input='dense2')
|
||||
graph.add_output(name='output2', input='dense3')
|
||||
graph.compile('rmsprop', {'output1':'mse', 'output2':'mse'})
|
||||
|
||||
history = graph.fit({'input1':X_train, 'output1':y_train, 'output2':y2_train}, nb_epoch=10)
|
||||
out = graph.predict({'input1':X_test})
|
||||
assert(type(out == dict))
|
||||
assert(len(out) == 2)
|
||||
loss = graph.test_on_batch({'input1':X_test, 'output1':y_test, 'output2':y2_test})
|
||||
loss = graph.train_on_batch({'input1':X_test, 'output1':y_test, 'output2':y2_test})
|
||||
loss = graph.evaluate({'input1':X_test, 'output1':y_test, 'output2':y2_test})
|
||||
print(loss)
|
||||
assert(loss < 4.)
|
||||
|
||||
print('test weight saving')
|
||||
graph.save_weights('temp.h5', overwrite=True)
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(16, 1), name='dense3', input='dense1')
|
||||
graph.add_output(name='output1', input='dense2')
|
||||
graph.add_output(name='output2', input='dense3')
|
||||
graph.compile('rmsprop', {'output1':'mse', 'output2':'mse'})
|
||||
graph.load_weights('temp.h5')
|
||||
nloss = graph.evaluate({'input1':X_test, 'output1':y_test, 'output2':y2_test})
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
def test_recursive(self):
|
||||
print('test layer-like API')
|
||||
|
||||
graph = containers.Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
|
||||
seq = Sequential()
|
||||
seq.add(Dense(32, 32, name='first_seq_dense'))
|
||||
seq.add(graph)
|
||||
seq.add(Dense(4, 4, name='last_seq_dense'))
|
||||
|
||||
seq.compile('rmsprop', 'mse')
|
||||
|
||||
history = seq.fit(X_train, y_train, batch_size=10, nb_epoch=10)
|
||||
loss = seq.evaluate(X_test, y_test)
|
||||
print(loss)
|
||||
assert(loss < 2.5)
|
||||
|
||||
loss = seq.evaluate(X_test, y_test, show_accuracy=True)
|
||||
pred = seq.predict(X_test)
|
||||
seq.get_config(verbose=1)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Test graph model')
|
||||
unittest.main()
|
||||
@@ -0,0 +1,79 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.utils import np_utils
|
||||
import numpy as np
|
||||
import unittest
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 5
|
||||
weighted_class = 9
|
||||
standard_weight = 1
|
||||
high_weight = 5
|
||||
max_train_samples = 5000
|
||||
max_test_samples = 1000
|
||||
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
X_train = X_train.reshape(60000, 784)[:max_train_samples]
|
||||
X_test = X_test.reshape(10000, 784)[:max_test_samples]
|
||||
X_train = X_train.astype("float32") / 255
|
||||
X_test = X_test.astype("float32") / 255
|
||||
|
||||
# convert class vectors to binary class matrices
|
||||
y_train = y_train[:max_train_samples]
|
||||
y_test = y_test[:max_test_samples]
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
test_ids = np.where(y_test == np.array(weighted_class))[0]
|
||||
|
||||
def create_model():
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 50))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(50, 10))
|
||||
model.add(Activation('softmax'))
|
||||
return model
|
||||
|
||||
def _test_weights(model, class_weight=None, sample_weight=None):
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, \
|
||||
class_weight=class_weight, sample_weight=sample_weight)
|
||||
score = model.evaluate(X_test[test_ids, :], Y_test[test_ids, :], verbose=0)
|
||||
return score
|
||||
|
||||
class TestConcatenation(unittest.TestCase):
|
||||
|
||||
def test_loss_weighting(self):
|
||||
class_weight = dict([(i, standard_weight) for i in range(nb_classes)])
|
||||
class_weight[weighted_class] = high_weight
|
||||
|
||||
sample_weight = np.ones((y_train.shape[0])) * standard_weight
|
||||
sample_weight[y_train == weighted_class] = high_weight
|
||||
|
||||
for loss in ['mae', 'mse', 'categorical_crossentropy']:
|
||||
print('loss:', loss)
|
||||
# no weights: reference point
|
||||
model = create_model()
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
standard_score = _test_weights(model)
|
||||
# test class_weight
|
||||
model = create_model()
|
||||
model.compile(loss=loss, optimizer='rmsprop')
|
||||
score = _test_weights(model, class_weight=class_weight)
|
||||
print('score:', score, ' vs.', standard_score)
|
||||
self.assertTrue(score < standard_score)
|
||||
# test sample_weight
|
||||
model = create_model()
|
||||
model.compile(loss=loss, optimizer='rmsprop')
|
||||
score = _test_weights(model, sample_weight=sample_weight)
|
||||
print('score:', score, ' vs.', standard_score)
|
||||
self.assertTrue(score < standard_score)
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Test class_weight and sample_weight')
|
||||
unittest.main()
|
||||
@@ -0,0 +1,61 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Merge, Dense, Activation, Flatten, ActivityRegularization
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.datasets import mnist
|
||||
from keras.utils import np_utils
|
||||
from keras import regularizers
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 5
|
||||
weighted_class = 9
|
||||
standard_weight = 1
|
||||
high_weight = 5
|
||||
max_train_samples = 5000
|
||||
max_test_samples = 1000
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
X_train = X_train.reshape(60000, 784)[:max_train_samples]
|
||||
X_test = X_test.reshape(10000, 784)[:max_test_samples]
|
||||
X_train = X_train.astype("float32") / 255
|
||||
X_test = X_test.astype("float32") / 255
|
||||
|
||||
# convert class vectors to binary class matrices
|
||||
y_train = y_train[:max_train_samples]
|
||||
y_test = y_test[:max_test_samples]
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
test_ids = np.where(y_test == np.array(weighted_class))[0]
|
||||
|
||||
def create_model(weight_reg=None, activity_reg=None):
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 50))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(50, 10, W_regularizer=weight_reg, activity_regularizer=activity_reg))
|
||||
model.add(Activation('softmax'))
|
||||
return model
|
||||
|
||||
|
||||
class TestRegularizers(unittest.TestCase):
|
||||
def test_W_reg(self):
|
||||
for reg in [regularizers.identity(), regularizers.l1(), regularizers.l2(), regularizers.l1l2()]:
|
||||
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_A_reg(self):
|
||||
for reg in [regularizers.activity_l1(), regularizers.activity_l2()]:
|
||||
model = create_model(activity_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)
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Test weight and activity regularizers')
|
||||
unittest.main()
|
||||
@@ -0,0 +1,278 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import unittest
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation, Merge
|
||||
from keras.utils import np_utils
|
||||
from keras.utils.test_utils import get_test_data
|
||||
|
||||
input_dim = 32
|
||||
nb_hidden = 16
|
||||
nb_class = 4
|
||||
batch_size = 64
|
||||
nb_epoch = 1
|
||||
|
||||
train_samples = 5000
|
||||
test_samples = 1000
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=train_samples, nb_test=test_samples, input_shape=(input_dim,),
|
||||
classification=True, nb_class=4)
|
||||
y_test = np_utils.to_categorical(y_test)
|
||||
y_train = np_utils.to_categorical(y_train)
|
||||
print(X_train.shape)
|
||||
print(y_train.shape)
|
||||
|
||||
class TestSequential(unittest.TestCase):
|
||||
def test_sequential(self):
|
||||
print('Test sequential')
|
||||
model = Sequential()
|
||||
model.add(Dense(input_dim, nb_hidden))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(nb_hidden, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=1, validation_data=(X_test, y_test))
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=2, validation_data=(X_test, y_test))
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=2, validation_split=0.1)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=1, validation_split=0.1)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=1, shuffle=False)
|
||||
|
||||
model.train_on_batch(X_train[:32], y_train[:32])
|
||||
|
||||
loss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict(X_test, verbose=0)
|
||||
classes = model.predict_classes(X_test, verbose=0)
|
||||
probas = model.predict_proba(X_test, verbose=0)
|
||||
print(model.get_config(verbose=1))
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
model = Sequential()
|
||||
model.add(Dense(input_dim, nb_hidden))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(nb_hidden, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
model.load_weights('temp.h5')
|
||||
|
||||
nloss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
|
||||
def test_merge_sum(self):
|
||||
print('Test merge: sum')
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim, nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim, nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='sum'))
|
||||
|
||||
model.add(Dense(nb_hidden, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=([X_test, X_test], y_test))
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=([X_test, X_test], y_test))
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
loss = model.evaluate([X_train, X_train], y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.7:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict([X_test, X_test], verbose=0)
|
||||
classes = model.predict_classes([X_test, X_test], verbose=0)
|
||||
probas = model.predict_proba([X_test, X_test], verbose=0)
|
||||
print(model.get_config(verbose=1))
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim, nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim, nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='sum'))
|
||||
model.add(Dense(nb_hidden, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
model.load_weights('temp.h5')
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
nloss = model.evaluate([X_train, X_train], y_train, verbose=0)
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
|
||||
def test_merge_concat(self):
|
||||
print('Test merge: concat')
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim, nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim, nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='concat'))
|
||||
|
||||
model.add(Dense(nb_hidden * 2, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=([X_test, X_test], y_test))
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=([X_test, X_test], y_test))
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit([X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
loss = model.evaluate([X_train, X_train], y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict([X_test, X_test], verbose=0)
|
||||
classes = model.predict_classes([X_test, X_test], verbose=0)
|
||||
probas = model.predict_proba([X_test, X_test], verbose=0)
|
||||
print(model.get_config(verbose=1))
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim, nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim, nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='concat'))
|
||||
|
||||
model.add(Dense(nb_hidden * 2, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
model.load_weights('temp.h5')
|
||||
|
||||
nloss = model.evaluate([X_train, X_train], y_train, verbose=0)
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
|
||||
def test_merge_recursivity(self):
|
||||
print('Test merge recursivity')
|
||||
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim, nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim, nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
righter = Sequential()
|
||||
righter.add(Dense(input_dim, nb_hidden))
|
||||
righter.add(Activation('relu'))
|
||||
|
||||
intermediate = Sequential()
|
||||
intermediate.add(Merge([left, right], mode='sum'))
|
||||
intermediate.add(Dense(nb_hidden, nb_hidden))
|
||||
intermediate.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([intermediate, righter], mode='sum'))
|
||||
|
||||
model.add(Dense(nb_hidden, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit([X_train, X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_data=([X_test, X_test, X_test], y_test))
|
||||
model.fit([X_train, X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=([X_test, X_test, X_test], y_test))
|
||||
model.fit([X_train, X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_split=0.1)
|
||||
model.fit([X_train, X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit([X_train, X_train, X_train], y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, shuffle=False)
|
||||
|
||||
loss = model.evaluate([X_train, X_train, X_train], y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict([X_test, X_test, X_test], verbose=0)
|
||||
classes = model.predict_classes([X_test, X_test, X_test], verbose=0)
|
||||
probas = model.predict_proba([X_test, X_test, X_test], verbose=0)
|
||||
print(model.get_config(verbose=1))
|
||||
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
model.load_weights('temp.h5')
|
||||
|
||||
nloss = model.evaluate([X_train, X_train, X_train], y_train, verbose=0)
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
|
||||
def test_merge_overlap(self):
|
||||
print('Test merge overlap')
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim, nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, left], mode='sum'))
|
||||
|
||||
model.add(Dense(nb_hidden, nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=1, validation_data=(X_test, y_test))
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=2, validation_data=(X_test, y_test))
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=2, validation_split=0.1)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=1, validation_split=0.1)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=1, shuffle=False)
|
||||
|
||||
model.train_on_batch(X_train[:32], y_train[:32])
|
||||
|
||||
loss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
raise Exception('Score too low, learning issue.')
|
||||
preds = model.predict(X_test, verbose=0)
|
||||
classes = model.predict_classes(X_test, verbose=0)
|
||||
probas = model.predict_proba(X_test, verbose=0)
|
||||
print(model.get_config(verbose=1))
|
||||
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
model.load_weights('temp.h5')
|
||||
|
||||
nloss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Test Sequential model')
|
||||
unittest.main()
|
||||
@@ -0,0 +1,131 @@
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
from keras.utils.test_utils import get_test_data
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation, TimeDistributedDense, Flatten
|
||||
from keras.layers.recurrent import GRU
|
||||
from keras.layers.convolutional import Convolution2D
|
||||
from keras.utils.np_utils import to_categorical
|
||||
import unittest
|
||||
|
||||
class TestRegularizers(unittest.TestCase):
|
||||
def test_vector_clf(self):
|
||||
nb_hidden = 10
|
||||
|
||||
print('vector classification data:')
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(10,),
|
||||
classification=True, nb_class=2)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
y_train = to_categorical(y_train)
|
||||
y_test = to_categorical(y_test)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(X_train.shape[-1], nb_hidden))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(nb_hidden, y_train.shape[-1]))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16, validation_data=(X_test, y_test), show_accuracy=True, verbose=2)
|
||||
print(history.history)
|
||||
self.assertTrue(history.history['val_acc'][-1] > 0.9)
|
||||
|
||||
def test_vector_reg(self):
|
||||
nb_hidden = 10
|
||||
print('vector regression data:')
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(10,), output_shape=(2,),
|
||||
classification=False)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(X_train.shape[-1], nb_hidden))
|
||||
model.add(Activation('tanh'))
|
||||
model.add(Dense(nb_hidden, y_train.shape[-1]))
|
||||
model.compile(loss='hinge', optimizer='adagrad')
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16, validation_data=(X_test, y_test), verbose=2)
|
||||
self.assertTrue(history.history['val_loss'][-1] < 0.9)
|
||||
|
||||
def test_temporal_clf(self):
|
||||
print('temporal classification data:')
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(5,10),
|
||||
classification=True, nb_class=2)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
y_train = to_categorical(y_train)
|
||||
y_test = to_categorical(y_test)
|
||||
|
||||
model = Sequential()
|
||||
model.add(GRU(X_train.shape[-1], y_train.shape[-1]))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='adadelta')
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16, validation_data=(X_test, y_test), show_accuracy=True, verbose=2)
|
||||
self.assertTrue(history.history['val_acc'][-1] > 0.9)
|
||||
|
||||
def test_temporal_reg(self):
|
||||
print('temporal regression data:')
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(5, 10), output_shape=(2,),
|
||||
classification=False)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
model = Sequential()
|
||||
model.add(GRU(X_train.shape[-1], y_train.shape[-1]))
|
||||
model.compile(loss='hinge', optimizer='adam')
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16, validation_data=(X_test, y_test), verbose=2)
|
||||
self.assertTrue(history.history['val_loss'][-1] < 0.75)
|
||||
|
||||
|
||||
def test_seq_to_seq(self):
|
||||
print('sequence to sequence data:')
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(5, 10), output_shape=(5, 10),
|
||||
classification=False)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
model = Sequential()
|
||||
model.add(TimeDistributedDense(X_train.shape[-1], y_train.shape[-1]))
|
||||
model.compile(loss='hinge', optimizer='rmsprop')
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16, validation_data=(X_test, y_test), verbose=2)
|
||||
self.assertTrue(history.history['val_loss'][-1] < 0.75)
|
||||
|
||||
|
||||
def test_img_clf(self):
|
||||
print('image classification data:')
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(3, 32, 32),
|
||||
classification=True, nb_class=2)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
y_train = to_categorical(y_train)
|
||||
y_test = to_categorical(y_test)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Convolution2D(32, 3, 32, 32))
|
||||
model.add(Activation('sigmoid'))
|
||||
model.add(Flatten())
|
||||
model.add(Dense(32, y_test.shape[-1]))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='sgd')
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16, validation_data=(X_test, y_test), show_accuracy=True, verbose=2)
|
||||
self.assertTrue(history.history['val_acc'][-1] > 0.9)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Test different types of classification and regression tasks')
|
||||
unittest.main()
|
||||
@@ -2,18 +2,14 @@ from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import DenoisingAutoEncoder, AutoEncoder, Dense, Activation, TimeDistributedDense, Flatten
|
||||
from keras.layers.core import AutoEncoder, Dense, Activation, TimeDistributedDense, Flatten
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.core import Layer
|
||||
from keras.layers import containers
|
||||
from keras.utils import np_utils
|
||||
|
||||
import numpy as np
|
||||
|
||||
# Try different things here: 'lstm' or 'classical' or 'denoising'
|
||||
autoencoder_type = 'denoising'
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 5
|
||||
@@ -42,6 +38,7 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)[:max_test_samples]
|
||||
print("X_train: ", X_train.shape)
|
||||
print("X_test: ", X_test.shape)
|
||||
|
||||
|
||||
##########################
|
||||
# dense model test #
|
||||
##########################
|
||||
@@ -70,70 +67,66 @@ def build_lstm_autoencoder(autoencoder, X_train, X_test):
|
||||
autoencoder.add(TimeDistributedDense(input_dim, 16))
|
||||
autoencoder.add(AutoEncoder(encoder=LSTM(16, 8, activation=activation, return_sequences=True),
|
||||
decoder=LSTM(8, input_dim, activation=activation, return_sequences=True),
|
||||
output_reconstruction=False, tie_weights=True))
|
||||
output_reconstruction=False))
|
||||
return autoencoder, X_train, X_test
|
||||
|
||||
def build_deep_classical_autoencoder(autoencoder):
|
||||
encoder = containers.Sequential([Dense(input_dim, hidden_dim, activation=activation), Dense(hidden_dim, hidden_dim/2, activation=activation)])
|
||||
decoder = containers.Sequential([Dense(hidden_dim/2, hidden_dim, activation=activation), Dense(hidden_dim, input_dim, activation=activation)])
|
||||
autoencoder.add(AutoEncoder(encoder=encoder, decoder=decoder, output_reconstruction=False, tie_weights=True))
|
||||
autoencoder.add(AutoEncoder(encoder=encoder, decoder=decoder, output_reconstruction=False))
|
||||
return autoencoder
|
||||
|
||||
def build_denoising_autoencoder(autoencoder):
|
||||
# You need another layer before a denoising autoencoder
|
||||
# This is similar to the dropout layers, etc..
|
||||
autoencoder.add(Dense(input_dim, input_dim))
|
||||
autoencoder.add(DenoisingAutoEncoder(encoder=Dense(input_dim, hidden_dim, activation=activation),
|
||||
decoder=Dense(hidden_dim, input_dim, activation=activation),
|
||||
output_reconstruction=False, tie_weights=True, corruption_level=0.3))
|
||||
return autoencoder
|
||||
|
||||
# Build our autoencoder model
|
||||
autoencoder = Sequential()
|
||||
if autoencoder_type == 'lstm':
|
||||
print("Training LSTM AutoEncoder")
|
||||
autoencoder, X_train, X_test = build_lstm_autoencoder(autoencoder, X_train, X_test)
|
||||
elif autoencoder_type == 'denoising':
|
||||
print("Training Denoising AutoEncoder")
|
||||
autoencoder = build_denoising_autoencoder(autoencoder)
|
||||
elif autoencoder_type == 'classical':
|
||||
print("Training Classical AutoEncoder")
|
||||
autoencoder = build_deep_classical_autoencoder(autoencoder)
|
||||
else:
|
||||
print("Error: unknown autoencoder type!")
|
||||
exit(-1)
|
||||
|
||||
autoencoder.get_config(verbose=1)
|
||||
autoencoder.compile(loss='mean_squared_error', optimizer='adam')
|
||||
# Do NOT use validation data with return output_reconstruction=True
|
||||
autoencoder.fit(X_train, X_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=1)
|
||||
# Try different things here: 'lstm' or 'classical' or 'denoising'
|
||||
# or 'deep_denoising'
|
||||
|
||||
# Do an inference pass
|
||||
prefilter_train = autoencoder.predict(X_train, verbose=0)
|
||||
prefilter_test = autoencoder.predict(X_test, verbose=0)
|
||||
print("prefilter_train: ", prefilter_train.shape)
|
||||
print("prefilter_test: ", prefilter_test.shape)
|
||||
for autoencoder_type in ['classical', 'lstm']:
|
||||
print(autoencoder_type)
|
||||
print('-'*40)
|
||||
# Build our autoencoder model
|
||||
autoencoder = Sequential()
|
||||
if autoencoder_type == 'lstm':
|
||||
print("Training LSTM AutoEncoder")
|
||||
autoencoder, X_train, X_test = build_lstm_autoencoder(autoencoder, X_train, X_test)
|
||||
elif autoencoder_type == 'classical':
|
||||
print("Training Classical AutoEncoder")
|
||||
autoencoder = build_deep_classical_autoencoder(autoencoder)
|
||||
else:
|
||||
print("Error: unknown autoencoder type!")
|
||||
exit(-1)
|
||||
|
||||
# Classify results from Autoencoder
|
||||
print("Building classical fully connected layer for classification")
|
||||
model = Sequential()
|
||||
if autoencoder_type == 'lstm':
|
||||
model.add(TimeDistributedDense(8, nb_classes, activation=activation))
|
||||
model.add(Flatten())
|
||||
elif autoencoder_type == 'classical':
|
||||
model.add(Dense(prefilter_train.shape[1], nb_classes, activation=activation))
|
||||
else:
|
||||
model.add(Dense(prefilter_train.shape[1], nb_classes, activation=activation))
|
||||
autoencoder.get_config(verbose=1)
|
||||
autoencoder.compile(loss='mean_squared_error', optimizer='adam')
|
||||
# Do NOT use validation data with return output_reconstruction=True
|
||||
autoencoder.fit(X_train, X_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=1)
|
||||
|
||||
model.add(Activation('softmax'))
|
||||
# Do an inference pass
|
||||
prefilter_train = autoencoder.predict(X_train, verbose=0)
|
||||
prefilter_test = autoencoder.predict(X_test, verbose=0)
|
||||
print("prefilter_train: ", prefilter_train.shape)
|
||||
print("prefilter_test: ", prefilter_test.shape)
|
||||
|
||||
model.get_config(verbose=1)
|
||||
model.compile(loss='categorical_crossentropy', optimizer='adam')
|
||||
model.fit(prefilter_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=(prefilter_test, Y_test))
|
||||
# Classify results from Autoencoder
|
||||
print("Building classical fully connected layer for classification")
|
||||
model = Sequential()
|
||||
if autoencoder_type == 'lstm':
|
||||
model.add(TimeDistributedDense(8, nb_classes, activation=activation))
|
||||
model.add(Flatten())
|
||||
elif autoencoder_type == 'classical':
|
||||
model.add(Dense(prefilter_train.shape[1], nb_classes, activation=activation))
|
||||
else:
|
||||
model.add(Dense(prefilter_train.shape[1], nb_classes, activation=activation))
|
||||
|
||||
score = model.evaluate(prefilter_test, Y_test, verbose=0, show_accuracy=True)
|
||||
print('\nscore:', score)
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
print('Loss change:', (score[0] - classical_score[0])/classical_score[0], '%')
|
||||
print('Accuracy change:', (score[1] - classical_score[1])/classical_score[1], '%')
|
||||
model.get_config(verbose=1)
|
||||
model.compile(loss='categorical_crossentropy', optimizer='adam')
|
||||
model.fit(prefilter_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=(prefilter_test, Y_test))
|
||||
|
||||
score = model.evaluate(prefilter_test, Y_test, verbose=0, show_accuracy=True)
|
||||
print('\nscore:', score)
|
||||
|
||||
print('Loss change:', (score[0] - classical_score[0])/classical_score[0], '%')
|
||||
print('Accuracy change:', (score[1] - classical_score[1])/classical_score[1], '%')
|
||||
|
||||
@@ -35,7 +35,7 @@ model = Sequential()
|
||||
model.add(Dense(784, 20, W_constraint=maxnorm(1)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.1))
|
||||
model.add(Dense(20, 20, W_constraint=nonneg))
|
||||
model.add(Dense(20, 20, W_constraint=nonneg()))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.1))
|
||||
model.add(Dense(20, 10, W_constraint=maxnorm(1)))
|
||||
@@ -0,0 +1,130 @@
|
||||
# Dummy test data as input to RNN. This input is 3 timesteps long where the third timestep always matches the
|
||||
# first. Without masking it should be able to learn it, with masking it should fail.
|
||||
|
||||
import numpy as np
|
||||
from keras.utils.theano_utils import sharedX
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation, Merge, Dropout, TimeDistributedDense
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import SimpleRNN, SimpleDeepRNN, LSTM, GRU
|
||||
import theano
|
||||
|
||||
theano.config.exception_verbosity = 'high'
|
||||
|
||||
# (nb_samples, timesteps, dimensions)
|
||||
X = np.random.random_integers(1, 4, size=(500000, 15))
|
||||
|
||||
print("About to compile the first model")
|
||||
model = Sequential()
|
||||
model.add(Embedding(5, 4, mask_zero=True))
|
||||
model.add(TimeDistributedDense(4, 4)) # obviously this is redundant. Just testing.
|
||||
model.add(SimpleRNN(4, 4, activation='relu', return_sequences=True))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(SimpleDeepRNN(4, 4, depth=2, activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(4, 4, activation='softmax'))
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer='rmsprop', theano_mode=theano.compile.mode.FAST_RUN)
|
||||
print("Compiled model")
|
||||
|
||||
W = model.get_weights() # We'll save these so we can reset it later
|
||||
|
||||
X[:, : 10] = 0
|
||||
Xmask0 = X.copy()
|
||||
Xmask0[:, 10] = 0
|
||||
|
||||
Xmask12 = X.copy()
|
||||
Xmask12[:, 11] = 0
|
||||
Xmask12[:, 12] = 0
|
||||
|
||||
X0_onehot = np.zeros((X.shape[0], 4))
|
||||
X1_onehot = np.zeros((X.shape[0], 4))
|
||||
for i, row in enumerate(X):
|
||||
X0_onehot[i, row[10] - 1] = 1
|
||||
X1_onehot[i, row[11] - 1] = 1
|
||||
|
||||
# Uniform score: 4 options = ln(4) nats (2 bits)
|
||||
# we should not do better than this when we mask out the part of the input
|
||||
# that gives us the correct answer
|
||||
uniform_score = np.log(4)
|
||||
batch_size=512
|
||||
|
||||
# Train it to guess 0th dim
|
||||
model.fit(X, X0_onehot, nb_epoch=1, batch_size=batch_size)
|
||||
score = model.evaluate(X, X0_onehot, batch_size=batch_size)
|
||||
if score > uniform_score * 0.9:
|
||||
raise Exception('Failed to learn to copy timestep 0, score %f' % score)
|
||||
|
||||
|
||||
model.set_weights(W)
|
||||
|
||||
# Train without showing it the 0th dim to learn 1st dim
|
||||
model.fit(X[: , 1:], X1_onehot, nb_epoch=1, batch_size=batch_size)
|
||||
score = model.evaluate(X[:, 1:], X1_onehot, batch_size=batch_size)
|
||||
if score > uniform_score * 0.9:
|
||||
raise Exception('Failed to learn to copy timestep 1, score %f' % score)
|
||||
|
||||
model.set_weights(W)
|
||||
|
||||
# Train to guess 0th dim when 0th dim has been masked (should fail)
|
||||
model.fit(Xmask0, X0_onehot, nb_epoch=1, batch_size=batch_size)
|
||||
score = model.evaluate(Xmask0, X0_onehot, batch_size=batch_size)
|
||||
if score < uniform_score * 0.9:
|
||||
raise Exception('Somehow learned to copy timestep 0 despite mask, score %f' % score)
|
||||
|
||||
model.set_weights(W)
|
||||
|
||||
# Train to guess 1st dim when 0th dim has been masked (should succeed)
|
||||
model.fit(Xmask0, X1_onehot, nb_epoch=1, batch_size=batch_size)
|
||||
score = model.evaluate(Xmask0, X1_onehot, batch_size=batch_size)
|
||||
if score > uniform_score * 0.9:
|
||||
raise Exception('Failed to learn to copy timestep 1 in masked model, score %f' % score)
|
||||
|
||||
model.set_weights(W)
|
||||
|
||||
# Finally, make sure the mask is actually blocking input, mask out timesteps 1 and 2, and see if
|
||||
# it can learn timestep 0 (should fail)
|
||||
model.fit(Xmask12, X0_onehot, nb_epoch=1, batch_size=batch_size)
|
||||
|
||||
score = model.evaluate(Xmask12, X0_onehot, batch_size=batch_size)
|
||||
if score < uniform_score * 0.9:
|
||||
raise Exception('Somehow learned to copy timestep 0 despite masking 1, score %f' % score)
|
||||
|
||||
# Another testing approach, just initialize models and make sure that prepending zeros doesn't affect
|
||||
# their output
|
||||
print("About to compile the second model")
|
||||
model2 = Sequential()
|
||||
model2.add(Embedding(5, 4, mask_zero=True))
|
||||
model2.add(TimeDistributedDense(4, 4))
|
||||
model2.add(Activation('time_distributed_softmax'))
|
||||
model2.add(LSTM(4, 4, return_sequences=True))
|
||||
model2.add(Activation('tanh'))
|
||||
model2.add(GRU(4, 4, activation='softmax', return_sequences=True))
|
||||
model2.add(SimpleDeepRNN(4, 4, depth=2, activation='relu', return_sequences=True))
|
||||
model2.add(SimpleRNN(4, 4, activation='relu', return_sequences=True))
|
||||
model2.compile(loss='categorical_crossentropy',
|
||||
optimizer='rmsprop', theano_mode=theano.compile.mode.FAST_RUN)
|
||||
print("Compiled model2")
|
||||
|
||||
X2 = np.random.random_integers(1, 4, size=(2, 5))
|
||||
y2 = np.random.random((X2.shape[0], X2.shape[1], 4))
|
||||
|
||||
ref = model2.predict(X2)
|
||||
ref_eval = model2.evaluate(X2, y2)
|
||||
mask = np.ones((y2.shape[0], y2.shape[1], 1))
|
||||
|
||||
for pre_zeros in range(1, 10):
|
||||
padded_X2 = np.concatenate((np.zeros((X2.shape[0], pre_zeros)), X2), axis=1)
|
||||
padded_mask = np.concatenate((np.zeros((mask.shape[0], pre_zeros, mask.shape[2])), mask), axis=1)
|
||||
padded_y2 = np.concatenate((np.zeros((y2.shape[0], pre_zeros, y2.shape[2])), y2), axis=1)
|
||||
|
||||
pred = model2.predict(padded_X2)
|
||||
if not np.allclose(ref[:, -1, :], pred[:, -1, :]):
|
||||
raise Exception("Different result after left-padding %d zeros. Ref: %s, Pred: %s" % (pre_zeros, ref, pred))
|
||||
|
||||
pad_eval = model2.evaluate(padded_X2, padded_y2, weights=padded_mask)
|
||||
if not np.allclose([pad_eval], [ref_eval]):
|
||||
raise Exception("Got dissimilar categorical_crossentropy after left-padding %d zeros. Ref: %f, Pred %f" %\
|
||||
(pref_eval, pred_val))
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
|
||||
from keras.utils.test_utils import get_test_data
|
||||
from keras.preprocessing import sequence
|
||||
from keras.optimizers import SGD, RMSprop, Adagrad
|
||||
from keras.utils import np_utils
|
||||
from keras.models import Sequential, Graph
|
||||
from keras.layers.core import Dense, Dropout, Activation, Merge
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, GRU
|
||||
from keras.datasets import imdb
|
||||
from keras.models import model_from_yaml
|
||||
|
||||
'''
|
||||
This is essentially the IMDB test. Deserialized models should yield
|
||||
the same config as the original one.
|
||||
'''
|
||||
|
||||
max_features = 10000
|
||||
maxlen = 100
|
||||
batch_size = 32
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features, test_split=0.2)
|
||||
|
||||
X_train = sequence.pad_sequences(X_train, maxlen=maxlen)
|
||||
X_test = sequence.pad_sequences(X_test, maxlen=maxlen)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, 128))
|
||||
model.add(LSTM(128, 128))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(128, 1, W_regularizer='identity', b_constraint='maxnorm'))
|
||||
model.add(Activation('sigmoid'))
|
||||
|
||||
model.get_config(verbose=1)
|
||||
|
||||
#####################################
|
||||
# save model w/o parameters to yaml #
|
||||
#####################################
|
||||
|
||||
yaml_no_params = model.to_yaml()
|
||||
|
||||
no_param_model = model_from_yaml(yaml_no_params)
|
||||
no_param_model.get_config(verbose=1)
|
||||
|
||||
######################################
|
||||
# save multi-branch sequential model #
|
||||
######################################
|
||||
|
||||
seq = Sequential()
|
||||
seq.add(Merge([model, model], mode='sum'))
|
||||
seq.get_config(verbose=1)
|
||||
merge_yaml = seq.to_yaml()
|
||||
merge_model = model_from_yaml(merge_yaml)
|
||||
|
||||
large_model = Sequential()
|
||||
large_model.add(Merge([seq,model], mode='concat'))
|
||||
large_model.get_config(verbose=1)
|
||||
large_model.to_yaml()
|
||||
|
||||
####################
|
||||
# save graph model #
|
||||
####################
|
||||
|
||||
X = np.random.random((100, 32))
|
||||
X2 = np.random.random((100, 32))
|
||||
y = np.random.random((100, 4))
|
||||
y2 = np.random.random((100,))
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000, nb_test=200, input_shape=(32,),
|
||||
classification=False, output_shape=(4,))
|
||||
|
||||
graph = Graph()
|
||||
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(32, 4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
graph.compile('rmsprop', {'output1':'mse'})
|
||||
|
||||
graph.get_config(verbose=1)
|
||||
|
||||
history = graph.fit({'input1':X_train, 'output1':y_train}, nb_epoch=10)
|
||||
original_pred = graph.predict({'input1':X_test})
|
||||
|
||||
graph_yaml = graph.to_yaml()
|
||||
graph.save_weights('temp.h5', overwrite=True)
|
||||
|
||||
reloaded_graph = model_from_yaml(graph_yaml)
|
||||
reloaded_graph.load_weights('temp.h5')
|
||||
reloaded_graph.get_config(verbose=1)
|
||||
|
||||
reloaded_graph.compile('rmsprop', {'output1':'mse'})
|
||||
new_pred = reloaded_graph.predict({'input1':X_test})
|
||||
|
||||
assert(new_pred['output1'][3][1] == original_pred['output1'][3][1])
|
||||
Referência em uma Nova Issue
Bloquear um usuário