Comparar commits
261 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| df860fdb94 | |||
| 361a7cfe41 | |||
| 8f2d6d2714 | |||
| cbee000b66 | |||
| 7ecd6c3c5f | |||
| 060ef32ce0 | |||
| 36392c75d7 | |||
| 2f01f29995 | |||
| 0ab3a6c00c | |||
| 475fa79ec4 | |||
| e600b0d947 | |||
| 677e15cd02 | |||
| ea2fd6526b | |||
| 26b040effe | |||
| ef3ef71ee6 | |||
| 5c3aea2202 | |||
| b6ea543a46 | |||
| e32436144b | |||
| 2bc900c3d2 | |||
| 6c458ff281 | |||
| 69a8acc05a | |||
| 71c6c83e30 | |||
| 634aedca1a | |||
| 4b39b5f36b | |||
| 25e85b616f | |||
| 47ed18a3af | |||
| febc604fc4 | |||
| 8612da30a9 | |||
| 9c1afbb667 | |||
| 8c9c8ae5ad | |||
| b92cec3d48 | |||
| cbb9d00106 | |||
| aca4a7735e | |||
| 6afce5862a | |||
| f2a14a9b57 | |||
| 4429547354 | |||
| b733951a19 | |||
| 78c61c65c2 | |||
| 242793a223 | |||
| 5c1e5d5e40 | |||
| e34022bf12 | |||
| dac1e8ec65 | |||
| 7867abdd69 | |||
| 2685134832 | |||
| 138e77d0d6 | |||
| 59a30e99a3 | |||
| 71ee360c20 | |||
| 88cc300103 | |||
| b059945195 | |||
| 819f569ca8 | |||
| d322785543 | |||
| 05aecbc0bc | |||
| 37ebbc3a1c | |||
| 252db48746 | |||
| 2d3880dc35 | |||
| 50467e32a2 | |||
| e1cc291a25 | |||
| 71b258d21e | |||
| c1b54159b8 | |||
| 6a231f1a24 | |||
| b82223b2f2 | |||
| 0e69226546 | |||
| 89132a6986 | |||
| 8b75182a17 | |||
| bc5e993ae3 | |||
| 8f2b5f0458 | |||
| 34838cd369 | |||
| 71b00324d8 | |||
| 16590ccce5 | |||
| 2431764fed | |||
| d444b9190f | |||
| 8ad18ce8f5 | |||
| a744b600e9 | |||
| 52dac5e4b3 | |||
| e94f29cac4 | |||
| 4e519f7aa7 | |||
| fd05964135 | |||
| 747d4a30b1 | |||
| ab19cf7b07 | |||
| 6b8970abd3 | |||
| 5ed913da11 | |||
| 6ffa18e390 | |||
| 33ed943ad5 | |||
| 368df8ef04 | |||
| 24b5e80667 | |||
| 15fea0488a | |||
| cda6a998ef | |||
| 653ee91d35 | |||
| eb8b37604c | |||
| e1bd779463 | |||
| 62154fd6c6 | |||
| f8b0c7e2e3 | |||
| 7df515b607 | |||
| b65c665d2a | |||
| dfa6b3a4c3 | |||
| 2e6025d7cc | |||
| 1a721b42c7 | |||
| d0677a1e1f | |||
| f6f8bf643e | |||
| d6aebff5b2 | |||
| e60b7de064 | |||
| cbd8eb7a55 | |||
| 20dc637cd6 | |||
| e037e17557 | |||
| 9ad5bf3a7b | |||
| 9e4e317bcb | |||
| db60707cb8 | |||
| 91ea495b56 | |||
| d9596ae68d | |||
| 1dc1d25a58 | |||
| 527b1ed0dc | |||
| 17d2f5f960 | |||
| 2ef4d698ef | |||
| bde97055c0 | |||
| 3b0e2b0c79 | |||
| 3e3c43d3ee | |||
| cb60477548 | |||
| 3d25fae014 | |||
| 4884595e4d | |||
| 1760ed6cd7 | |||
| b1bbedfb46 | |||
| 227c300a0a | |||
| f5819a0d4e | |||
| 28882a868d | |||
| b32e60cfa0 | |||
| ca360b0d15 | |||
| 10852b2529 | |||
| cc0108097c | |||
| fe14a845ab | |||
| 5964848bdf | |||
| 002a9d5d2b | |||
| eba8530e7b | |||
| 7432034ada | |||
| 99331b83f9 | |||
| 0b326d9688 | |||
| 57612707c1 | |||
| 5352e46e09 | |||
| a5d93bfdc1 | |||
| 742ccaa2cf | |||
| 284ef7b495 | |||
| 02180e881d | |||
| 4a6b03403b | |||
| ccdd5d147d | |||
| 3c95896415 | |||
| 66edb6aea0 | |||
| 5590dc7b0d | |||
| 8f2810bfee | |||
| 42e582b1ba | |||
| 43bf884b5f | |||
| 234408e82e | |||
| 41db741881 | |||
| 46bfa18a57 | |||
| 7e85390d8e | |||
| a2d01238af | |||
| ba982e7ee0 | |||
| 18f122e1d9 | |||
| bae645b65e | |||
| 66ad0bf736 | |||
| 469640bd45 | |||
| 2f8b351c95 | |||
| 8ee2ffd7e1 | |||
| fb24dc1904 | |||
| 79e702ec53 | |||
| bd005d66af | |||
| 0354e64521 | |||
| a4552fb004 | |||
| 455d7d10db | |||
| 1c7585a563 | |||
| 22566c37ce | |||
| 1f0178e793 | |||
| fbe2ea6537 | |||
| 7b0be64757 | |||
| 0edbdcc998 | |||
| 21dcabb6e8 | |||
| c34578aece | |||
| 01a3e298fb | |||
| 42a65d4b83 | |||
| cb836091ec | |||
| 6a05247711 | |||
| c015acb413 | |||
| feac8dba01 | |||
| ba389ffb11 | |||
| c6c3a0247c | |||
| c140939c5a | |||
| a9cecbbe43 | |||
| 0f0d264e55 | |||
| a9d0905897 | |||
| c90d2dfc0c | |||
| 315a12ac58 | |||
| f5896236fa | |||
| 29e788dc2e | |||
| 07f8cef29c | |||
| a069161d0f | |||
| 26b57a6cdd | |||
| 45577f7959 | |||
| 25aab5d405 | |||
| a58e037715 | |||
| eb62075078 | |||
| 3663f64bb4 | |||
| fcd54ac85b | |||
| fb8e80daf4 | |||
| ac3d135b84 | |||
| d876dae965 | |||
| 345d78e27d | |||
| d5827c8917 | |||
| 779bf2a8d2 | |||
| 0fab8ac373 | |||
| b3594ccd5e | |||
| 15b84d375f | |||
| 312120272f | |||
| 97b27bfd1e | |||
| a0c5f5743c | |||
| 688b898dc8 | |||
| 7def993fe2 | |||
| c33a551f97 | |||
| 3f8bfd2b1c | |||
| c6cf4425d3 | |||
| aa6cf91a18 | |||
| 5faef2fc56 | |||
| ad254f99eb | |||
| e6cecb5d12 | |||
| 6106d1fa30 | |||
| ab6b11d86e | |||
| 6e2e6eff89 | |||
| e60680b12c | |||
| 47071f9303 | |||
| 14486397c5 | |||
| 0cd30480fb | |||
| 74b590eff8 | |||
| 25a2a972b1 | |||
| 01bb88513d | |||
| 0d233b2512 | |||
| e704e1578e | |||
| 0c0d91df2e | |||
| 52fd68f4c5 | |||
| 7b0b324041 | |||
| 8b24b3343f | |||
| 084b235c62 | |||
| 9a384888d7 | |||
| 6cc827ca55 | |||
| d2051a5df1 | |||
| e7c6d598a9 | |||
| 1526d81ab3 | |||
| 73c0045815 | |||
| 3981a87b31 | |||
| a78c43033e | |||
| 80e85836c1 | |||
| 569bb74a08 | |||
| a8eda69f3e | |||
| 6f620712b5 | |||
| a19c9ecfbd | |||
| 11e4c4b90f | |||
| 025cd16854 | |||
| 68f619b9f9 | |||
| f1ef9895f5 | |||
| a86b381424 | |||
| 5691912701 | |||
| cc26bc24a9 | |||
| f62c03bdea | |||
| 40a9bd7c2f | |||
| 38a3228999 |
+30
-10
@@ -1,22 +1,42 @@
|
||||
sudo: false
|
||||
sudo: required
|
||||
dist: trusty
|
||||
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
|
||||
python:
|
||||
- "2.7"
|
||||
- "3.4"
|
||||
# command to install dependencies
|
||||
install:
|
||||
- conda install --yes python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib pandas pytest h5py
|
||||
# code below is taken from http://conda.pydata.org/docs/travis.html
|
||||
# We do this conditionally because it saves us some downloading if the
|
||||
# version is the same.
|
||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||
wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh;
|
||||
else
|
||||
wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh;
|
||||
fi
|
||||
- bash miniconda.sh -b -p $HOME/miniconda
|
||||
- export PATH="$HOME/miniconda/bin:$PATH"
|
||||
- hash -r
|
||||
- conda config --set always_yes yes --set changeps1 no
|
||||
- conda update -q conda
|
||||
# Useful for debugging any issues with conda
|
||||
- conda info -a
|
||||
|
||||
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib pandas pytest h5py
|
||||
- source activate test-environment
|
||||
- pip install pytest-cov python-coveralls
|
||||
- pip install git+git://github.com/Theano/Theano.git
|
||||
- python setup.py install
|
||||
|
||||
# install TensorFlow
|
||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.5.0-cp27-none-linux_x86_64.whl;
|
||||
fi
|
||||
# command to run tests
|
||||
script:
|
||||
- PYTHONPATH=$PWD:$PYTHONPATH py.test -v --cov-report term-missing --cov keras tests/
|
||||
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
|
||||
sed -i -e 's/theano/tensorflow/g' ~/.keras/keras.json;
|
||||
PYTHONPATH=$PWD:$PYTHONPATH py.test -v --cov-report term-missing --cov keras tests/;
|
||||
fi
|
||||
after_success:
|
||||
- coveralls
|
||||
|
||||
+19
-2
@@ -1,6 +1,23 @@
|
||||
The MIT License (MIT)
|
||||
COPYRIGHT
|
||||
|
||||
Copyright (c) 2015
|
||||
All contributions by François Chollet:
|
||||
Copyright (c) 2015, François Chollet.
|
||||
All rights reserved.
|
||||
|
||||
All contributions by Google:
|
||||
Copyright (c) 2015, Google, Inc.
|
||||
All rights reserved.
|
||||
|
||||
All other contributions:
|
||||
Copyright (c) 2015, the respective contributors.
|
||||
All rights reserved.
|
||||
|
||||
Each contributor holds copyright over their respective contributions.
|
||||
The project versioning (Git) records all such contribution source information.
|
||||
|
||||
LICENSE
|
||||
|
||||
The MIT License (MIT)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
+106
-168
@@ -1,8 +1,8 @@
|
||||
# Keras: Theano-based Deep Learning library
|
||||
# Keras: Deep Learning library for Theano and TensorFlow
|
||||
|
||||
## You have just found Keras.
|
||||
|
||||
Keras is a minimalist, highly modular neural network library in the spirit of Torch, written in Python / Theano so as not to have to deal with the dearth of ecosystem in Lua. It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running either on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
- allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
@@ -12,200 +12,92 @@ Use Keras if you need a deep learning library that:
|
||||
|
||||
Read the documentation at [Keras.io](http://keras.io).
|
||||
|
||||
Keras is compatible with __Python 2.7-3.4__.
|
||||
Keras is compatible with:
|
||||
- __Python 2.7-3.5__ with the Theano backend
|
||||
- __Python 2.7__ with the TensorFlow backend
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Guiding principles
|
||||
|
||||
- __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. Every piece of code should be transparent upon first reading. No black magic: it hurts iteration speed and ability to innovate.
|
||||
|
||||
- __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 advanced research.
|
||||
- __Easy extensibility.__ New modules are dead simple to add (as new classes and functions), and existing modules provide ample examples. To be able to easily create new modules allows for total expressiveness, making Keras suitable for advanced 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, and allows for ease of extensibility.
|
||||
- __Work with Python__. No separate models configuration files in a declarative format. Models are described in Python code, which is compact, easier to debug, and allows for ease of extensibility.
|
||||
|
||||
## Examples
|
||||
|
||||
### Multilayer Perceptron (MLP):
|
||||
------------------
|
||||
|
||||
|
||||
## Getting started: 30 seconds to Keras
|
||||
|
||||
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
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
|
||||
model = Sequential()
|
||||
```
|
||||
|
||||
Stacking layers is as easy as `.add()`:
|
||||
|
||||
```python
|
||||
from keras.layers.core import Dense, Activation
|
||||
|
||||
model.add(Dense(output_dim=64, input_dim=100, init="glorot_uniform"))
|
||||
model.add(Activation("relu"))
|
||||
model.add(Dense(output_dim=10, init="glorot_uniform"))
|
||||
model.add(Activation("softmax"))
|
||||
```
|
||||
|
||||
Once your model looks good, configure its learning process with `.compile()`:
|
||||
```python
|
||||
model.compile(loss='categorical_crossentropy', optimizer='sgd')
|
||||
```
|
||||
|
||||
If you need to, you can further configure your optimizer. A core principle of Keras is to make things reasonably simple, while allowing the user to be fully in control when they need to (the ultimate control being the easy extensibility of the source code).
|
||||
```python
|
||||
from keras.optimizers import SGD
|
||||
|
||||
model = Sequential()
|
||||
# Dense(64) is a fully-connected layer with 64 hidden units.
|
||||
# in the first layer, you must specify the expected input data shape:
|
||||
# here, 20-dimensional vectors.
|
||||
model.add(Dense(64, input_dim=20, init='uniform'))
|
||||
model.add(Activation('tanh'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(64, init='uniform'))
|
||||
model.add(Activation('tanh'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(2, init='uniform'))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
model.compile(loss='mean_squared_error', optimizer=sgd)
|
||||
|
||||
model.fit(X_train, y_train, nb_epoch=20, batch_size=16)
|
||||
score = model.evaluate(X_test, y_test, batch_size=16)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.01, momentum=0.9, nesterov=True))
|
||||
```
|
||||
|
||||
### Alternative implementation of MLP:
|
||||
|
||||
You can now iterate on your training data in batches:
|
||||
```python
|
||||
model = Sequential()
|
||||
model.add(Dense(64, input_dim=20, init='uniform', activation='tanh'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(64, init='uniform', activation='tanh'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(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)
|
||||
model.fit(X_train, Y_train, nb_epoch=5, batch_size=32)
|
||||
```
|
||||
|
||||
### VGG-like convnet:
|
||||
|
||||
Alternatively, you can feed batches to your model manually:
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.optimizers import SGD
|
||||
|
||||
model = Sequential()
|
||||
# input: 100x100 images with 3 channels -> (3, 100, 100) tensors.
|
||||
# this applies 32 convolution filters of size 3x3 each.
|
||||
model.add(Convolution2D(32, 3, 3, border_mode='full', input_shape=(3, 100, 100)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(32, 3, 3))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Convolution2D(64, 3, 3, border_mode='valid'))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(64, 3, 3))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Flatten())
|
||||
# Note: Keras does automatic shape inference.
|
||||
model.add(Dense(256))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.5))
|
||||
|
||||
model.add(Dense(10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=sgd)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=32, nb_epoch=1)
|
||||
|
||||
model.train_on_batch(X_batch, Y_batch)
|
||||
```
|
||||
|
||||
### Sequence classification with LSTM:
|
||||
|
||||
Evaluate your performance in one line:
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM
|
||||
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, 256, input_length=maxlen))
|
||||
model.add(LSTM(output_dim=128, activation='sigmoid', inner_activation='hard_sigmoid'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('sigmoid'))
|
||||
|
||||
model.compile(loss='binary_crossentropy', optimizer='rmsprop')
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=16, nb_epoch=10)
|
||||
score = model.evaluate(X_test, Y_test, batch_size=16)
|
||||
objective_score = model.evaluate(X_test, Y_test, batch_size=32)
|
||||
```
|
||||
|
||||
### 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 work well will require using a bigger convnet, initialized with pre-trained weights.
|
||||
|
||||
Or generate predictions on new data:
|
||||
```python
|
||||
max_caption_len = 16
|
||||
vocab_size = 10000
|
||||
|
||||
# first, let's define an image model that
|
||||
# will encode pictures into 128-dimensional vectors.
|
||||
# it should be initialized with pre-trained weights.
|
||||
image_model = Sequential()
|
||||
image_model.add(Convolution2D(32, 3, 3, border_mode='full', input_shape=(3, 100, 100)))
|
||||
image_model.add(Activation('relu'))
|
||||
image_model.add(Convolution2D(32, 3, 3))
|
||||
image_model.add(Activation('relu'))
|
||||
image_model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
|
||||
image_model.add(Convolution2D(64, 3, 3, border_mode='full'))
|
||||
image_model.add(Activation('relu'))
|
||||
image_model.add(Convolution2D(64, 3, 3))
|
||||
image_model.add(Activation('relu'))
|
||||
image_model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
|
||||
image_model.add(Flatten())
|
||||
image_model.add(Dense(128))
|
||||
|
||||
# let's load the weights from a save file.
|
||||
image_model.load_weights('weight_file.h5')
|
||||
|
||||
# next, let's define a RNN model that encodes sequences of words
|
||||
# into sequences of 128-dimensional word vectors.
|
||||
language_model = Sequential()
|
||||
language_model.add(Embedding(vocab_size, 256, input_length=max_caption_len))
|
||||
language_model.add(GRU(output_dim=128, return_sequences=True))
|
||||
language_model.add(Dense(128))
|
||||
|
||||
# let's repeat the image vector to turn it into a sequence.
|
||||
image_model.add(RepeatVector(max_caption_len))
|
||||
|
||||
# the output of both models will be tensors of shape (samples, max_caption_len, 128).
|
||||
# let's concatenate these 2 vector sequences.
|
||||
model = Merge([image_model, language_model], mode='concat', concat_axis=-1)
|
||||
# let's encode this vector sequence into a single vector
|
||||
model.add(GRU(256, 256, return_sequences=False))
|
||||
# which will be used to compute a probability
|
||||
# distribution over what the next word in the caption should be!
|
||||
model.add(Dense(vocab_size))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
# "images" is a numpy float array of shape (nb_samples, nb_channels=3, width, height).
|
||||
# "captions" is a numpy integer array of shape (nb_samples, max_caption_len)
|
||||
# containing word index sequences representing partial captions.
|
||||
# "next_words" is a numpy float array of shape (nb_samples, vocab_size)
|
||||
# containing a categorical encoding (0s and 1s) of the next word in the corresponding
|
||||
# partial caption.
|
||||
model.fit([images, partial_captions], next_words, batch_size=16, nb_epoch=100)
|
||||
classes = model.predict_classes(X_test, batch_size=32)
|
||||
proba = model.predict_proba(X_test, batch_size=32)
|
||||
```
|
||||
|
||||
In the examples folder, you will find example models for real datasets:
|
||||
- CIFAR10 small images classification: Convolutional Neural Network (CNN) with realtime data augmentation
|
||||
- IMDB movie review sentiment classification: LSTM over sequences of words
|
||||
- Reuters newswires topic classification: Multilayer Perceptron (MLP)
|
||||
- MNIST handwritten digits classification: MLP & CNN
|
||||
- Character-level text generation with LSTM
|
||||
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?
|
||||
|
||||
...and more.
|
||||
Have a look at these [starter examples](http://keras.io/examples/).
|
||||
|
||||
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repo, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, neural turing machines, etc.
|
||||
|
||||
|
||||
## Current capabilities
|
||||
------------------
|
||||
|
||||
For complete coverage of the API, check out [the Keras documentation](http://keras.io).
|
||||
|
||||
A few highlights: convnets, LSTM, GRU, word2vec-style embeddings, PReLU, BatchNormalization...
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -213,11 +105,22 @@ Keras uses the following dependencies:
|
||||
|
||||
- numpy, scipy
|
||||
- pyyaml
|
||||
- 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.
|
||||
|
||||
When using the Theano backend:
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
**Note**: You should use the latest version of Theano, not the PyPI version. Install it with:
|
||||
```
|
||||
sudo pip install git+git://github.com/Theano/Theano.git
|
||||
```
|
||||
|
||||
When using the TensorFlow backend:
|
||||
- TensorFlow
|
||||
- [See installation instructions](https://github.com/tensorflow/tensorflow#download-and-setup).
|
||||
|
||||
To install, `cd` to the Keras folder and run the install command:
|
||||
```
|
||||
sudo python setup.py install
|
||||
@@ -228,10 +131,45 @@ You can also install Keras from PyPI:
|
||||
sudo pip install keras
|
||||
```
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Switching from Theano to TensorFlow
|
||||
|
||||
By default, Keras will use Theano as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
You can ask questions and join the development discussion on the [Keras Google group](https://groups.google.com/forum/#!forum/keras-users).
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
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.
|
||||
- Any new function or class should have a proper docstring.
|
||||
- The documentation for every new feature should include a usage example in the form of a code snippet.
|
||||
- All changes should be tested. Make sure any new feature you add has a corresponding unit test.
|
||||
- Please no Pull Requests about coding style.
|
||||
- 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).
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Why this name, Keras?
|
||||
|
||||
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 initially 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."_ Homer, Odyssey 19. 562 ff (Shewring translation).
|
||||
|
||||
------------------
|
||||
@@ -24,6 +24,7 @@ pages:
|
||||
- Constraints: constraints.md
|
||||
- Callbacks: callbacks.md
|
||||
- Datasets: datasets.md
|
||||
- Visualization: visualization.md
|
||||
- Layers:
|
||||
- Core Layers: layers/core.md
|
||||
- Convolutional Layers: layers/convolutional.md
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
# Keras backends
|
||||
|
||||
## What is a "backend"?
|
||||
|
||||
Keras is a model-level library, providing high-level building blocks for developing deep learning models. It does not handle itself low-level operations such as tensor products, convolutions and so on. Instead, it relies on a specialized, well-optimized tensor manipulation library to do so, serving as the "backend engine" of Keras. Rather than picking one single tensor library and making the implementation of Keras tied to that library, Keras handles the problem in a modular way, and several different backend engines can be plugged seamlessly into Keras.
|
||||
|
||||
At this time, Keras has two backend implementations available: the **Theano** backend and the **TensorFlow** backend.
|
||||
|
||||
- [Theano](http://deeplearning.net/software/theano/) is an open-source symbolic tensor manipulation framework developed by LISA/MILA Lab at Université de Montréal.
|
||||
- [TensorFlow](http://www.tensorflow.org/) is an open-source symbolic tensor manipulation framework developed by Google, Inc.
|
||||
|
||||
## Switching from one backend to another
|
||||
|
||||
If you have run Keras at least once, you will find the Keras configuration file at:
|
||||
|
||||
`~/.keras/keras.json`
|
||||
|
||||
If it isn't there, you can create it.
|
||||
|
||||
It probably looks like this:
|
||||
|
||||
`{"epsilon": 1e-07, "floatx": "float32", "backend": "theano"}`
|
||||
|
||||
Simply change the field `backend` to either `"theano"` or `"tensorflow"`, and Keras will use the new configuration next time you run any Keras code.
|
||||
|
||||
## Using the abstract Keras backend to write new code
|
||||
|
||||
If you want the Keras modules you write to be compatible with both Theano and TensorFlow, you have to write them via the abstract Keras backend API. Here's an intro.
|
||||
|
||||
You can import the backend module via:
|
||||
```python
|
||||
from keras import backend as K
|
||||
```
|
||||
|
||||
This instantiates an input placeholder. It's equivalent to `tf.placeholder()` or `T.matrix()`, `T.tensor3()`, etc.
|
||||
|
||||
```python
|
||||
input = K.placeholder(shape=(2, 4, 5))
|
||||
# also works:
|
||||
input = K.placeholder(shape=(None, 4, 5))
|
||||
# also works:
|
||||
input = K.placeholder(ndim=3)
|
||||
```
|
||||
|
||||
This instantiates a shared variable. It's equivalent to `tf.variable()` or `theano.shared()`.
|
||||
|
||||
```python
|
||||
val = np.random.random((3, 4, 5))
|
||||
var = K.variable(value=val)
|
||||
|
||||
# all-zeros variable:
|
||||
var = K.ones(shape=(3, 4, 5))
|
||||
# all-ones:
|
||||
var = K.zeros(shape=(3, 4, 5))
|
||||
```
|
||||
|
||||
Most tensor operations you will need can be done as you would in TensorFlow or Theano:
|
||||
|
||||
```python
|
||||
a = b + c * K.abs(d)
|
||||
c = K.dot(a, K.transpose(b))
|
||||
a = K.sum(b, axis=2)
|
||||
a = K.softmax(b)
|
||||
a = concatenate([b, c], axis=-1)
|
||||
# etc...
|
||||
```
|
||||
|
||||
For more information, see the code at `keras/backend/theano_backend.py` and `keras/backend/tensorflow_backend.py`.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
- [Index](documentation.md)
|
||||
- [Examples](examples.md)
|
||||
- [FAQ](faq.md)
|
||||
- [Backend](backend.md)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ image_model.load_weights('weight_file.h5')
|
||||
language_model = Sequential()
|
||||
language_model.add(Embedding(vocab_size, 256, input_length=max_caption_len))
|
||||
language_model.add(GRU(output_dim=128, return_sequences=True))
|
||||
language_model.add(Dense(128))
|
||||
language_model.add(TimeDistributedDense(128))
|
||||
|
||||
# let's repeat the image vector to turn it into a sequence.
|
||||
image_model.add(RepeatVector(max_caption_len))
|
||||
|
||||
+64
-29
@@ -1,33 +1,38 @@
|
||||
# Keras: Theano-based Deep Learning library
|
||||
# Keras: Deep Learning library for Theano and TensorFlow
|
||||
|
||||
## Overview
|
||||
## You have just found Keras.
|
||||
|
||||
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.
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running either on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
|
||||
- allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- runs seamlessly on CPU and GPU.
|
||||
|
||||
Read the documentation at [Keras.io](http://keras.io).
|
||||
|
||||
Keras is compatible with:
|
||||
- __Python 2.7-3.5__ with the Theano backend
|
||||
- __Python 2.7__ with the TensorFlow backend
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Guiding principles
|
||||
|
||||
- __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. Every piece of code should be transparent upon first reading. No black magic: it hurts iteration speed and ability to innovate.
|
||||
|
||||
- __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 advanced research.
|
||||
- __Easy extensibility.__ New modules are dead simple to add (as new classes and functions), and existing modules provide ample examples. To be able to easily create new modules allows for total expressiveness, making Keras suitable for advanced 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, and allows for ease of extensibility.
|
||||
- __Work with Python__. No separate models configuration files in a declarative format. Models are described in Python code, which is compact, easier to debug, and allows for ease of extensibility.
|
||||
|
||||
## Code
|
||||
|
||||
Find the code on Github: [fchollet/keras](https://github.com/fchollet/keras).
|
||||
------------------
|
||||
|
||||
## License
|
||||
|
||||
Keras is licensed under the [MIT license](http://opensource.org/licenses/MIT).
|
||||
|
||||
## Getting started: 30 seconds to Keras
|
||||
|
||||
@@ -57,7 +62,7 @@ Once your model looks good, configure its learning process with `.compile()`:
|
||||
model.compile(loss='categorical_crossentropy', optimizer='sgd')
|
||||
```
|
||||
|
||||
If you need to, you can further configure your optimizer. A core principle of Keras is make things things reasonably simple, while allowing the user to be fully in control when they need to (the ultimate control being the easy extensibility of the source code).
|
||||
If you need to, you can further configure your optimizer. A core principle of Keras is to make things reasonably simple, while allowing the user to be fully in control when they need to (the ultimate control being the easy extensibility of the source code).
|
||||
```python
|
||||
from keras.optimizers import SGD
|
||||
model.compile(loss='categorical_crossentropy', optimizer=SGD(lr=0.01, momentum=0.9, nesterov=True))
|
||||
@@ -86,55 +91,85 @@ proba = model.predict_proba(X_test, batch_size=32)
|
||||
|
||||
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).
|
||||
Have a look at these [starter examples](http://keras.io/examples/).
|
||||
|
||||
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repo, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, neural turing machines, etc.
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
Keras uses the following dependencies:
|
||||
|
||||
- __numpy__, __scipy__
|
||||
- __pyyaml__
|
||||
- __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__.
|
||||
- numpy, scipy
|
||||
- pyyaml
|
||||
- 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
|
||||
git clone https://github.com/fchollet/keras.git
|
||||
When using the Theano backend:
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
**Note**: You should use the latest version of Theano, not the PyPI version. Install it with:
|
||||
```
|
||||
sudo pip install git+git://github.com/Theano/Theano.git
|
||||
```
|
||||
|
||||
When using the TensorFlow backend:
|
||||
- TensorFlow
|
||||
- [See installation instructions](https://github.com/tensorflow/tensorflow#download-and-setup).
|
||||
|
||||
To install, `cd` to the Keras folder and run the install command:
|
||||
```
|
||||
Go to the Keras folder and run the install command:
|
||||
```bash
|
||||
cd keras
|
||||
sudo python setup.py install
|
||||
```
|
||||
|
||||
You can also install Keras from PyPI:
|
||||
```
|
||||
sudo pip install keras
|
||||
```
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Switching from Theano to TensorFlow
|
||||
|
||||
By default, Keras will use Theano as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Support
|
||||
|
||||
You can ask questions and join the development discussion on the [Keras Google group](https://groups.google.com/forum/#!forum/keras-users).
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Contribution Guidelines
|
||||
|
||||
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.
|
||||
- Any new function or class should have a proper docstring.
|
||||
- The documentation for every new feature should include a usage example in the form of a code snippet.
|
||||
- All changes should be tested. Make sure any new feature you add has a corresponding unit test.
|
||||
- Please no Pull Requests about coding style.
|
||||
- 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).
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Why this name, Keras?
|
||||
|
||||
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 initially 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."_
|
||||
>_"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."_ Homer, Odyssey 19. 562 ff (Shewring translation).
|
||||
|
||||
> -- Homer, Odyssey 19. 562 ff (Shewring translation).
|
||||
------------------
|
||||
@@ -35,6 +35,24 @@ Parametrized linear unit. Similar to a LeakyReLU, where each input unit has its
|
||||
|
||||
---
|
||||
|
||||
## ELU
|
||||
|
||||
```python
|
||||
keras.layers.advanced_activations.ELU()
|
||||
```
|
||||
|
||||
Exponential linear unit. Negative values pushes mean unit activations closer to zero, with the advantage of having a noise-robust deactivation state.
|
||||
|
||||
|
||||
- __Input shape__: Arbitrary. Use the keyword argument `input_shape` (tuple of integers, does not include the samples axis) when using this layer as the first layer in a model.
|
||||
|
||||
- __Output shape__: Same as input.
|
||||
|
||||
- __References__:
|
||||
- [Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)](http://arxiv.org/pdf/1511.07289v1.pdf)
|
||||
|
||||
---
|
||||
|
||||
## ParametricSoftplus
|
||||
|
||||
```python
|
||||
|
||||
@@ -3,17 +3,21 @@
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.Convolution1D(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, input_dim=None, input_length=None)
|
||||
init='uniform',
|
||||
activation='linear',
|
||||
weights=None,
|
||||
border_mode='valid',
|
||||
subsample_length=1,
|
||||
W_regularizer=None, b_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
|
||||
Convolution operator for filtering neighborhoods of one-dimensional inputs. When using this layer as the first layer in a model, either provide the keyword argument `input_dim` (int, e.g. 128 for sequences of 128-dimensional vectors), or `input_shape` (tuple of integers, e.g. (10, 128) for sequences of 10 vectors of 128-dimensional vectors).
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, steps, input_dim)`.
|
||||
- __Input shape__: 3D tensor with shape: `(samples, steps, input_dim)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(nb_samples, steps, nb_filter)`. `steps` value might have changed due to padding.
|
||||
- __Output shape__: 3D tensor with shape: `(samples, new_steps, nb_filter)`. `steps` value might have changed due to padding.
|
||||
|
||||
- __Arguments__:
|
||||
- __nb_filter__: Number of convolution kernels to use (dimensionality of the output).
|
||||
@@ -21,7 +25,7 @@ Convolution operator for filtering neighborhoods of one-dimensional inputs. When
|
||||
- __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.
|
||||
- __border_mode__: 'valid' or 'same'.
|
||||
- __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.
|
||||
@@ -37,16 +41,23 @@ Convolution operator for filtering neighborhoods of one-dimensional inputs. When
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.Convolution2D(nb_filter, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
W_regularizer=None, b_regularizer=None, W_constraint=None)
|
||||
init='glorot_uniform',
|
||||
activation='linear',
|
||||
weights=None,
|
||||
border_mode='valid',
|
||||
subsample=(1, 1),
|
||||
W_regularizer=None, b_regularizer=None,
|
||||
W_constraint=None,
|
||||
dim_ordering='th')
|
||||
```
|
||||
|
||||
Convolution operator for filtering windows of two-dimensional inputs. When using this layer as the first layer in a model, provide the keyword argument `input_shape` (tuple of integers, does not include the sample axis), e.g. `input_shape=(3, 128, 128)` for 128x128 RGB pictures.
|
||||
|
||||
- __Input shape__: 4D tensor with shape: `(nb_samples, channels, rows, cols)`.
|
||||
- __Input shape__: 4D tensor with shape: `(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(nb_samples, nb_filter, rows, cols)`. `rows`, `cols` might have changed due to padding.
|
||||
- __Output shape__: 4D tensor with shape: `(samples, nb_filter, nb_row, nb_col)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, nb_row, nb_col, nb_filter)` if dim_ordering='tf'.
|
||||
|
||||
|
||||
- __Arguments__:
|
||||
@@ -57,13 +68,14 @@ Convolution operator for filtering windows of two-dimensional inputs. When using
|
||||
- __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](http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.convolve2d.html).
|
||||
- __border_mode__: 'valid' or 'same'.
|
||||
- __subsample__: tuple of length 2. Factor by which to subsample output. Also called strides elsewhere.
|
||||
- __W_regularizer__: instance of [WeightRegularizer](../regularizers.md) (eg. L1 or L2 regularization), applied to the main weights matrix.
|
||||
- __b_regularizer__: instance of [WeightRegularizer](../regularizers.md), applied to the bias.
|
||||
- __activity_regularizer__: instance of [ActivityRegularizer](../regularizers.md), applied to the network output.
|
||||
- __W_constraint__: instance of the [constraints](../constraints.md) module (eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
- __b_constraint__: instance of the [constraints](../constraints.md) module, applied to the bias.
|
||||
- __dim_ordering__: 'th' or 'tf'. In 'th' mode, the channels dimension (the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
|
||||
|
||||
---
|
||||
@@ -71,33 +83,120 @@ Convolution operator for filtering windows of two-dimensional inputs. When using
|
||||
## MaxPooling1D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.MaxPooling1D(pool_length=2, stride=None, ignore_border=True)
|
||||
keras.layers.convolutional.MaxPooling1D(pool_length=2, stride=None, border_mode='valid')
|
||||
```
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, steps, dim)`.
|
||||
Max pooling operation for temporal data.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(nb_samples, downsampled_steps, dim)`.
|
||||
- __Input shape__: 3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(samples, downsampled_steps, features)`.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __pool_length__: factor by which to downscale. 2 will halve the input.
|
||||
- __stride__: integer or None. Stride value.
|
||||
- __ignore_border__: boolean.
|
||||
- __border_mode__: 'valid' or 'same'. **Note:** 'same' will only work with TensorFlow for the time being.
|
||||
|
||||
---
|
||||
|
||||
## MaxPooling2D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.MaxPooling2D(pool_size=(2, 2), ignore_border=True)
|
||||
keras.layers.convolutional.MaxPooling2D(pool_size=(2, 2), border_mode='valid', dim_ordering='th')
|
||||
```
|
||||
|
||||
- __Input shape__: 4D tensor with shape: `(nb_samples, stack_size, nb_row, nb_col)`.
|
||||
Max pooling operation for spatial data.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(nb_samples, stack_size, new_nb_row, new_nb_col)`.
|
||||
- __Input shape__: 4D tensor with shape: `(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(nb_samples, channels, pooled_rows, pooled_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, pooled_rows, pooled_cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __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.
|
||||
- __pool_size__: tuple of 2 integers, factors by which to downscale (vertical, horizontal). (2, 2) will halve the image in each dimension.
|
||||
- __strides__: tuple of 2 integers, or None. Strides values.
|
||||
- __border_mode__: 'valid' or 'same'. **Note:** 'same' will only work with TensorFlow for the time being.
|
||||
- __dim_ordering__: 'th' or 'tf'. In 'th' mode, the channels dimension (the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
|
||||
|
||||
---
|
||||
|
||||
## UpSampling1D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.UpSampling1D(length=2)
|
||||
```
|
||||
|
||||
Repeats each temporal step `length` times along the time axis.
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(samples, upsampled_steps, features)`.
|
||||
|
||||
- __Arguments__:
|
||||
- __length__: integer. Upsampling factor.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## UpSampling2D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.UpSampling2D(size=(2, 2), dim_ordering='th')
|
||||
```
|
||||
|
||||
Repeats the rows and columns of the data by size[0] and size[1] respectively.
|
||||
|
||||
- __Input shape__: 4D tensor with shape: `(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(samples, channels, upsampled_rows, upsampled_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, upsampled_rows, upsampled_cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __Arguments__:
|
||||
- __size__: tuple of 2 integers. The upsampling factors for rows and columns.
|
||||
- __dim_ordering__: 'th' or 'tf'. In 'th' mode, the channels dimension (the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## ZeroPadding1D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.ZeroPaddding1D(padding=1)
|
||||
```
|
||||
|
||||
Pads the input with zeros left and right along the time axis.
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, steps, dim)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(nb_samples, padded_steps, dim)`.
|
||||
|
||||
- __Arguments__:
|
||||
- __padding__: integer, the size of the padding.
|
||||
|
||||
---
|
||||
|
||||
|
||||
## ZeroPadding2D
|
||||
|
||||
```python
|
||||
keras.layers.convolutional.ZeroPaddding2D(padding=(1, 1), dim_ordering='th')
|
||||
```
|
||||
|
||||
Pads the rows and columns of the input with zeros, left and right.
|
||||
|
||||
- __Input shape__: 4D tensor with shape: `(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __Output shape__: 4D tensor with shape: `(samples, channels, padded_rows, padded_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape: `(samples, padded_rows, padded_cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
- __Arguments__:
|
||||
- __padding__: tuple of 2 integers, the size of the padding for rows and columns respectively.
|
||||
- __dim_ordering__: 'th' or 'tf'. In 'th' mode, the channels dimension (the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
|
||||
---
|
||||
+112
-11
@@ -76,9 +76,13 @@ get_config()
|
||||
|
||||
## Dense
|
||||
```python
|
||||
keras.layers.core.Dense(output_dim, init='glorot_uniform', activation='linear', weights=None
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None)
|
||||
keras.layers.core.Dense(output_dim,
|
||||
init='glorot_uniform',
|
||||
activation='linear',
|
||||
weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None)
|
||||
```
|
||||
|
||||
Standard 1D fully-connect layer.
|
||||
@@ -104,9 +108,13 @@ Standard 1D fully-connect layer.
|
||||
|
||||
## TimeDistributedDense
|
||||
```python
|
||||
keras.layers.core.TimeDistributedDense(output_dim, init='glorot_uniform', activation='linear', weights=None
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None, W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None)
|
||||
keras.layers.core.TimeDistributedDense(output_dim,
|
||||
init='glorot_uniform',
|
||||
activation='linear',
|
||||
weights=None
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
|
||||
Fully-connected layer distributed over the time dimension. Useful after a recurrent network set to `return_sequences=True`.
|
||||
@@ -300,9 +308,12 @@ This layer can be used, for instance, to induce activation sparsity in the previ
|
||||
|
||||
## MaxoutDense
|
||||
```python
|
||||
keras.layers.core.MaxoutDense(output_dim, nb_feature=4, init='glorot_uniform', weights=None,
|
||||
keras.layers.core.MaxoutDense(output_dim, nb_feature=4,
|
||||
init='glorot_uniform',
|
||||
weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None)
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=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.
|
||||
@@ -332,14 +343,20 @@ model.add(MaxoutDense(50, nb_feature=10)) # output shape: (nb_samples, 50)
|
||||
|
||||
## Merge
|
||||
```python
|
||||
keras.layers.core.Merge(models, mode='sum')
|
||||
keras.layers.core.Merge(layers, mode='sum', concat_axis=-1, dot_axes=-1)
|
||||
```
|
||||
|
||||
Merge the output of a list of layers (or containers) into a single tensor, following one of three modes: `sum`, `mul` or `concat`.
|
||||
Merge the output of a list of layers (or containers) into a single tensor.
|
||||
|
||||
- __Arguments__:
|
||||
- __layers__: List of layers or [containers](/layers/containers/).
|
||||
- __mode__: String, one of `{'sum', 'mul', 'concat'}`. `sum` and `mul` will simply sum/multiply 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).
|
||||
- __mode__: String, one of `{'sum', 'mul', 'concat', 'ave', 'dot'}`. `sum`, `mul` and `ave` will simply sum/multiply/average the outputs of the layers (therefore all layers should have an output with the same shape). `concat` will concatenate the outputs along the dimension specified by `concate_axis` (therefore all layers should have an output that only differ along this dimension). `dot` will dot tensor contraction on the axes specified by `dot_axes` (see [the Numpy documentation](http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.tensordot.html) for more details).
|
||||
- __concat_axis__: axis to use in `concat` mode.
|
||||
- __dot_axes__: axis or axes to use in `dot` mode (see [the Numpy documentation](http://docs.scipy.org/doc/numpy-1.10.1/reference/generated/numpy.tensordot.html) for more details).
|
||||
|
||||
|
||||
- __Notes__:
|
||||
- `dot` mode only works with Theano for the time being.
|
||||
|
||||
- __Example__:
|
||||
|
||||
@@ -374,3 +391,87 @@ Given an input of dimensions `(nb_samples, timesteps, input_dim)`, return the in
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, timesteps, features)`.
|
||||
|
||||
- __Output shape__: 3D tensor with shape: `(nb_samples, timesteps, features)`.
|
||||
|
||||
- __Notes__: Masking only works in Theano for the time being.
|
||||
|
||||
## Lambda
|
||||
```python
|
||||
keras.layers.core.Lambda(function, output_shape=None)
|
||||
```
|
||||
|
||||
Used for evaluating an arbitrary Theano expression on the output of the previous layer.
|
||||
|
||||
- __Input shape__: Arbitrary. Use the keyword argument input_shape (tuple of integers, does not include the samples axis) when using this layer as the first layer in a model.
|
||||
|
||||
- __Output shape__: Specified by the `output_shape` argument.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __function__: The expression to be evaluated. Takes one argument: the output of the previous layer.
|
||||
- __output_shape__: Shape of the tensor returned by `function`. Should be a shape tuple (not including the samples dimension) or a function of the full input shape tuple (including samples dimension).
|
||||
|
||||
- __Example__:
|
||||
|
||||
```python
|
||||
# custom softmax function
|
||||
def sharp_softmax(X, beta=1.5):
|
||||
return theano.tensor.nnet.softmax(X * beta)
|
||||
|
||||
def output_shape(input_shape):
|
||||
# here input_shape includes the samples dimension
|
||||
return input_shape # shape is unchanged
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(input_dim=10, output_dim=10))
|
||||
model.add(Lambda(sharp_softmax, output_shape))
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('sigmoid'))
|
||||
```
|
||||
|
||||
|
||||
## LambdaMerge
|
||||
```python
|
||||
keras.layers.core.LambdaMerge(layers, function, output_shape=None)
|
||||
```
|
||||
|
||||
Merge the output of a list of layers (or containers) into a single tensor, using an arbitrary Theano expression.
|
||||
|
||||
- __Arguments__:
|
||||
- __layers__: List of layers or [containers](/layers/containers/).
|
||||
- __function__: The expression to be evaluated. Takes one argument: the list of input tensors.
|
||||
- __output_shape__: Shape of the tensor returned by `function`. Should be a shape tuple (not including samples dimension) or a function of the list of input shape tuples (including samples dimension).
|
||||
|
||||
- __Example__:
|
||||
|
||||
```python
|
||||
# root mean square function
|
||||
def rms(inputs):
|
||||
# inputs is a list of tensors
|
||||
s = inputs[0] ** 2
|
||||
for i in range(1, len(inputs)):
|
||||
s += inputs[i] ** 2
|
||||
s /= len(inputs)
|
||||
s = theano.tensor.sqrt(s)
|
||||
# return a single tensor
|
||||
return s
|
||||
|
||||
def output_shape(input_shapes):
|
||||
# return the shape of the first tensor
|
||||
return input_shapes[0]
|
||||
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim=10, output_dim=10))
|
||||
left.add(Activation('sigmoid'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim=10, output_dim=10))
|
||||
right.add(Activation('sigmoid'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(LambdaMerge([left, right], rms, output_shape))
|
||||
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('sigmoid'))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -2,7 +2,12 @@
|
||||
## Embedding
|
||||
|
||||
```python
|
||||
keras.layers.embeddings.Embedding(input_dim, output_dim, init='uniform', input_length=None, weights=None, W_regularizer=None, W_constraint=None, mask_zero=False)
|
||||
keras.layers.embeddings.Embedding(input_dim, output_dim,
|
||||
init='uniform',
|
||||
weights=None,
|
||||
W_regularizer=None, W_constraint=None,
|
||||
mask_zero=False,
|
||||
input_length=None)
|
||||
```
|
||||
|
||||
Turn positive integers (indexes) into denses vectors of fixed size,
|
||||
@@ -14,7 +19,7 @@ eg. `[[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]`
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __input_dim__: int >= 0. Size of the vocabulary, ie. 1+maximum integer index occuring in the input data.
|
||||
- __input_dim__: int >= 0. Size of the vocabulary, ie. 1+maximum integer index occurring in the input data.
|
||||
- __output_dim__: int >= 0. Dimension of the dense embedding.
|
||||
- __init__: name of initialization function for the weights of the layer (see: [initializations](../initializations.md)), or alternatively, Theano function to use for weights initialization. This parameter is only relevant if you don't pass a `weights` argument.
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 1 element, of shape `(input_dim, output_dim)`.
|
||||
@@ -23,28 +28,4 @@ eg. `[[4], [20]] -> [[0.25, 0.1], [0.6, -0.2]]`
|
||||
- __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.
|
||||
- __input_length__: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
|
||||
## WordContextProduct
|
||||
|
||||
```python
|
||||
keras.layers.embeddings.WordContextProduct(input_dim, proj_dim=128,
|
||||
init='uniform', activation='sigmoid', weights=None)
|
||||
```
|
||||
|
||||
This layer turns a pair of words (a pivot word + a context word, ie. a word from the same context as a pivot, or a random, out-of-context word), indentified by their indices in a vocabulary, into two dense reprensentations (word representation and context representation).
|
||||
|
||||
Then it returns `activation(dot(pivot_embedding, context_embedding))`, which can be trained to encode the probability of finding the context word in the context of the pivot word (or reciprocally depending on your training procedure).
|
||||
|
||||
For more context, see Mikolov et al.: [Efficient Estimation of Word reprensentations in Vector Space](http://arxiv.org/pdf/1301.3781v3.pdf)
|
||||
|
||||
- __Input shape__: 2D tensor with shape: `(nb_samples, 2)`.
|
||||
|
||||
- __Output shape__: 2D tensor with shape: `(nb_samples, 1)`.
|
||||
|
||||
- __Arguments__:
|
||||
|
||||
- __input_dim__: int >= 0. Size of the vocabulary, ie. 1+maximum integer index occuring in the input data.
|
||||
- __proj_dim__: int >= 0. Dimension of the dense embedding used internally.
|
||||
- __init__: name of initialization function for the embeddings (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.
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 2 element, both of shape `(input_dim, proj_dim)`. The first element is the word embedding weights, the second one is the context embedding weights.
|
||||
---
|
||||
|
||||
@@ -2,9 +2,14 @@
|
||||
## SimpleRNN
|
||||
|
||||
```python
|
||||
keras.layers.recurrent.SimpleRNN(output_dim,
|
||||
init='glorot_uniform', inner_init='orthogonal', activation='sigmoid', weights=None,
|
||||
truncate_gradient=-1, return_sequences=False, input_dim=None, input_length=None)
|
||||
keras.layers.recurrent.SimpleRNN(output_dim,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='sigmoid',
|
||||
weights=None,
|
||||
return_sequences=False,
|
||||
go_backwards=False,
|
||||
stateful=False,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
Fully connected RNN where output is to fed back to input.
|
||||
|
||||
@@ -14,7 +19,9 @@ Fully connected RNN where output is to fed back to input.
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, output_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`.
|
||||
- __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`. **Note:** for the time being, masking in only supported with Theano.
|
||||
|
||||
- __Notes__: When using the TensorFlow backend, the number of timesteps used must be fixed. Make sure to pass an `input_length` int argument or a complete `input_shape` tuple argument.
|
||||
|
||||
|
||||
- __Arguments__:
|
||||
@@ -22,50 +29,9 @@ Fully connected RNN where output is to fed back to input.
|
||||
- __init__: weight initialization function. Can be the name of an existing function (str), or a Theano function (see: [initializations](../initializations.md)).
|
||||
- __activation__: activation function. Can be the name of an existing function (str), or a Theano function (see: [activations](../activations.md)).
|
||||
- __weights__: list of numpy arrays to set as initial weights. The list should have 3 elements, of shapes: `[(input_dim, output_dim), (output_dim, output_dim), (output_dim,)]`.
|
||||
- __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.
|
||||
- __input_dim__: dimensionality of the input (integer). This argument (or alternatively, the keyword argument `input_shape`) is required when using this layer as the first layer in a model.
|
||||
- __input_length__: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
---
|
||||
|
||||
## SimpleDeepRNN
|
||||
|
||||
```python
|
||||
keras.layers.recurrent.SimpleDeepRNN(output_dim, depth=3,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='sigmoid', inner_activation='hard_sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
Fully connected RNN where the output of multiple timesteps (up to "depth" steps in the past) is fed back to the input:
|
||||
|
||||
```
|
||||
output = activation( W.x_t + b + inner_activation(U_1.h_tm1) + inner_activation(U_2.h_tm2) + ... )
|
||||
```
|
||||
|
||||
Not a particularly useful model, included for demonstration purposes.
|
||||
|
||||
- __Input shape__: 3D tensor with shape: `(nb_samples, timesteps, input_dim)`.
|
||||
|
||||
- __Output shape__:
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, output_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.
|
||||
- __depth__: int >= 1. Lookback depth (eg. depth=1 is equivalent to SimpleRNN).
|
||||
- __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 depth+2 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.
|
||||
- __go_backwards__: Boolean (default False). If True, rocess the input sequence backwards.
|
||||
- __stateful__: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
|
||||
- __input_dim__: dimensionality of the input (integer). This argument (or alternatively, the keyword argument `input_shape`) is required when using this layer as the first layer in a model.
|
||||
- __input_length__: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
@@ -75,10 +41,12 @@ Not a particularly useful model, included for demonstration purposes.
|
||||
## GRU
|
||||
|
||||
```python
|
||||
keras.layers.recurrent.GRU(input_dim, output_dim=128,
|
||||
keras.layers.recurrent.GRU(output_dim,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
activation='sigmoid', inner_activation='hard_sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False,
|
||||
return_sequences=False,
|
||||
go_backwards=False,
|
||||
stateful=False,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
|
||||
@@ -90,21 +58,24 @@ Gated Recurrent Unit - Cho et al. 2014.
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, output_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.
|
||||
- __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. **Note:** for the time being, masking in only supported with Theano.
|
||||
|
||||
- __Notes__: When using the TensorFlow backend, the number of timesteps used must be fixed. Make sure to pass an `input_length` int argument or a complete `input_shape` tuple argument.
|
||||
|
||||
- __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.
|
||||
- __go_backwards__: Boolean (default False). If True, rocess the input sequence backwards.
|
||||
- __stateful__: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
|
||||
- __input_dim__: dimensionality of the input (integer). This argument (or alternatively, the keyword argument `input_shape`) is required when using this layer as the first layer in a model.
|
||||
- __input_length__: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
|
||||
- __References__:
|
||||
- [On the Properties of Neural Machine Translation: Encoder–Decoder Approaches](http://www.aclweb.org/anthology/W14-4012)
|
||||
- [Empirical Evaluation of Gated Recurrent Neural Networks on Sequence Modeling](http://arxiv.org/pdf/1412.3555v1.pdf)
|
||||
@@ -114,10 +85,13 @@ Gated Recurrent Unit - Cho et al. 2014.
|
||||
## LSTM
|
||||
|
||||
```python
|
||||
keras.layers.recurrent.LSTM(input_dim, output_dim=128,
|
||||
keras.layers.recurrent.LSTM(output_dim,
|
||||
init='glorot_uniform', inner_init='orthogonal', forget_bias_init='one',
|
||||
activation='tanh', inner_activation='hard_sigmoid',
|
||||
weights=None, truncate_gradient=-1, return_sequences=False,
|
||||
weights=None,
|
||||
return_sequences=False,
|
||||
go_backwards=False,
|
||||
stateful=False,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
|
||||
@@ -129,10 +103,11 @@ Long-Short Term Memory unit - Hochreiter 1997.
|
||||
- if `return_sequences`: 3D tensor with shape: `(nb_samples, timesteps, output_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.
|
||||
- __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. **Note:** for the time being, masking in only supported with Theano.
|
||||
|
||||
- __Notes__: When using the TensorFlow backend, the number of timesteps used must be fixed. Make sure to pass an `input_length` int argument or a complete `input_shape` tuple argument.
|
||||
|
||||
- __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.
|
||||
@@ -140,53 +115,16 @@ Long-Short Term Memory unit - Hochreiter 1997.
|
||||
- __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.
|
||||
- __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.
|
||||
- __go_backwards__: Boolean (default False). If True, rocess the input sequence backwards.
|
||||
- __stateful__: Boolean (default False). If True, the last state for each sample at index i in a batch will be used as initial state for the sample of index i in the following batch.
|
||||
- __input_dim__: dimensionality of the input (integer). This argument (or alternatively, the keyword argument `input_shape`) is required when using this layer as the first layer in a model.
|
||||
- __input_length__: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
|
||||
- __References__:
|
||||
- [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,
|
||||
input_dim=None, input_length=None)
|
||||
```
|
||||
|
||||
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, output_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.
|
||||
- __input_dim__: dimensionality of the input (integer). This argument (or alternatively, the keyword argument `input_shape`) is required when using this layer as the first layer in a model.
|
||||
- __input_length__: Length of input sequences, when it is constant. This argument is required if you are going to connect `Flatten` then `Dense` layers upstream (without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
- __References__:
|
||||
- [An Empirical Exploration of Recurrent Network Architectures](http://www.jmlr.org/proceedings/papers/v37/jozefowicz15.pdf)
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -12,9 +12,8 @@ model = keras.models.Sequential()
|
||||
- __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.
|
||||
- __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=[], 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.
|
||||
- __Return__: a history object. It `history` attribute is a record of training loss values at successive epochs, as well as validation loss values (if applicable).
|
||||
- __Arguments__:
|
||||
- __X__: data.
|
||||
- __y__: labels.
|
||||
@@ -142,12 +141,19 @@ model = keras.models.Graph()
|
||||
- __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.
|
||||
- __add_shared_node__(layer, name, inputs=[], merge_mode=None, outputs=[]): Add a shared node connected to `inputs`. A shared node is a layer that will be applied separately to every incoming input, and that uses only one set of weights. The merging operation occurs on the outputs of the layer.
|
||||
- __Arguments__:
|
||||
- __layer__: Layer instance.
|
||||
- __name__: str. unique identifier of the node.
|
||||
- __inputs__: list of str names of the node that the node is connected to.
|
||||
- __merge_mode__: Merge mode for the different inputs.
|
||||
- __outputs__: Optional. List of names for outputs, when merge_mode = None.
|
||||
- __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).
|
||||
- __Return__: a history object. It `history` attribute is 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.
|
||||
|
||||
@@ -19,6 +19,7 @@ For a few examples of such functions, check out the [objectives source](https://
|
||||
## Available objectives
|
||||
|
||||
- __mean_squared_error__ / __mse__
|
||||
- __root_mean_squared_error__ / __rmse__
|
||||
- __mean_absolute_error__ / __mae__
|
||||
- __mean_absolute_percentage_error__ / __mape__
|
||||
- __mean_squared_logarithmic_error__ / __msle__
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
|
||||
## Model visualization
|
||||
|
||||
The `keras.utils.visualize_util` module provides utility functions to plot
|
||||
a Keras model (using graphviz).
|
||||
|
||||
This will plot a graph of the model and save it to a file:
|
||||
```python
|
||||
from keras.utils.visualize_util import plot
|
||||
plot(model, to_file='model.png')
|
||||
```
|
||||
|
||||
You can also directly obtain the `pydot.Graph` object and render it yourself,
|
||||
for example to show it in an ipython notebook :
|
||||
```python
|
||||
from IPython.display import SVG
|
||||
from keras.utils.visualize_util import to_graph
|
||||
|
||||
SVG(to_graph(model).create(prog='dot', format='svg'))
|
||||
```
|
||||
+12
-15
@@ -4,6 +4,7 @@ from keras.models import Sequential, slice_X
|
||||
from keras.layers.core import Activation, TimeDistributedDense, RepeatVector
|
||||
from keras.layers import recurrent
|
||||
import numpy as np
|
||||
from six.moves import range
|
||||
|
||||
"""
|
||||
An implementation of sequence to sequence learning for performing addition
|
||||
@@ -11,11 +12,6 @@ Input: "535+61"
|
||||
Output: "596"
|
||||
Padding is handled by using a repeated sentinel character (space)
|
||||
|
||||
By default, the JZS1 recurrent neural network is used
|
||||
JZS1 was an "evolved" recurrent neural network performing well on arithmetic benchmark in:
|
||||
"An Empirical Exploration of Recurrent Network Architectures"
|
||||
http://jmlr.org/proceedings/papers/v37/jozefowicz15.pdf
|
||||
|
||||
Input may optionally be inverted, shown to increase performance in many tasks in:
|
||||
"Learning to Execute"
|
||||
http://arxiv.org/abs/1410.4615
|
||||
@@ -25,16 +21,16 @@ http://papers.nips.cc/paper/5346-sequence-to-sequence-learning-with-neural-netwo
|
||||
Theoretically it introduces shorter term dependencies between source and target.
|
||||
|
||||
Two digits inverted:
|
||||
+ One layer JZS1 (128 HN), 5k training examples = 99% train/test accuracy in 55 epochs
|
||||
+ One layer LSTM (128 HN), 5k training examples = 99% train/test accuracy in 55 epochs
|
||||
|
||||
Three digits inverted:
|
||||
+ One layer JZS1 (128 HN), 50k training examples = 99% train/test accuracy in 100 epochs
|
||||
+ One layer LSTM (128 HN), 50k training examples = 99% train/test accuracy in 100 epochs
|
||||
|
||||
Four digits inverted:
|
||||
+ One layer JZS1 (128 HN), 400k training examples = 99% train/test accuracy in 20 epochs
|
||||
+ One layer LSTM (128 HN), 400k training examples = 99% train/test accuracy in 20 epochs
|
||||
|
||||
Five digits inverted:
|
||||
+ One layer JZS1 (128 HN), 550k training examples = 99% train/test accuracy in 30 epochs
|
||||
+ One layer LSTM (128 HN), 550k training examples = 99% train/test accuracy in 30 epochs
|
||||
|
||||
"""
|
||||
|
||||
@@ -74,8 +70,8 @@ class colors:
|
||||
TRAINING_SIZE = 50000
|
||||
DIGITS = 3
|
||||
INVERT = True
|
||||
# Try replacing JZS1 with LSTM, GRU, or SimpleRNN
|
||||
RNN = recurrent.JZS1
|
||||
# Try replacing GRU, or SimpleRNN
|
||||
RNN = recurrent.LSTM
|
||||
HIDDEN_SIZE = 128
|
||||
BATCH_SIZE = 128
|
||||
LAYERS = 1
|
||||
@@ -89,7 +85,7 @@ expected = []
|
||||
seen = set()
|
||||
print('Generating data...')
|
||||
while len(questions) < TRAINING_SIZE:
|
||||
f = lambda: int(''.join(np.random.choice(list('0123456789')) for i in xrange(np.random.randint(1, DIGITS + 1))))
|
||||
f = lambda: int(''.join(np.random.choice(list('0123456789')) for i in range(np.random.randint(1, DIGITS + 1))))
|
||||
a, b = f(), f()
|
||||
# Skip any addition questions we've already seen
|
||||
# Also skip any such that X+Y == Y+X (hence the sorting)
|
||||
@@ -122,6 +118,7 @@ indices = np.arange(len(y))
|
||||
np.random.shuffle(indices)
|
||||
X = X[indices]
|
||||
y = y[indices]
|
||||
|
||||
# Explicitly set apart 10% for validation data that we never train over
|
||||
split_at = len(X) - len(X) / 10
|
||||
(X_train, X_val) = (slice_X(X, 0, split_at), slice_X(X, split_at))
|
||||
@@ -135,11 +132,11 @@ model = Sequential()
|
||||
# "Encode" the input sequence using an RNN, producing an output of HIDDEN_SIZE
|
||||
# note: in a situation where your input sequences have a variable length,
|
||||
# use input_shape=(None, nb_feature).
|
||||
model.add(RNN(HIDDEN_SIZE, input_shape=(None, len(chars))))
|
||||
model.add(RNN(HIDDEN_SIZE, input_shape=(MAXLEN, len(chars))))
|
||||
# For the decoder's input, we repeat the encoded input for each time step
|
||||
model.add(RepeatVector(DIGITS + 1))
|
||||
# The decoder RNN could be multiple layers stacked or a single layer
|
||||
for _ in xrange(LAYERS):
|
||||
for _ in range(LAYERS):
|
||||
model.add(RNN(HIDDEN_SIZE, return_sequences=True))
|
||||
|
||||
# For each of step of the output sequence, decide which character should be chosen
|
||||
@@ -156,7 +153,7 @@ for iteration in range(1, 200):
|
||||
model.fit(X_train, y_train, batch_size=BATCH_SIZE, nb_epoch=1, validation_data=(X_val, y_val), show_accuracy=True)
|
||||
###
|
||||
# Select 10 samples from the validation set at random so we can visualize errors
|
||||
for i in xrange(10):
|
||||
for i in range(10):
|
||||
ind = np.random.randint(0, len(X_val))
|
||||
rowX, rowy = X_val[np.array([ind])], y_val[np.array([ind])]
|
||||
preds = model.predict_classes(rowX, verbose=0)
|
||||
|
||||
@@ -0,0 +1,203 @@
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.core import Activation, Dense, Merge, Permute, Dropout
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.datasets.data_utils import get_file
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
from functools import reduce
|
||||
import tarfile
|
||||
import numpy as np
|
||||
import re
|
||||
|
||||
"""
|
||||
Train a memory network on the bAbI dataset.
|
||||
|
||||
References:
|
||||
- Jason Weston, Antoine Bordes, Sumit Chopra, Tomas Mikolov, Alexander M. Rush,
|
||||
"Towards AI-Complete Question Answering: A Set of Prerequisite Toy Tasks",
|
||||
http://arxiv.org/abs/1503.08895
|
||||
|
||||
- Sainbayar Sukhbaatar, Arthur Szlam, Jason Weston, Rob Fergus,
|
||||
"End-To-End Memory Networks",
|
||||
http://arxiv.org/abs/1503.08895
|
||||
|
||||
Reaches 93% accuracy on task 'single_supporting_fact_10k' after 70 epochs.
|
||||
Time per epoch: 3s on CPU (core i7).
|
||||
"""
|
||||
|
||||
|
||||
def tokenize(sent):
|
||||
'''Return the tokens of a sentence including punctuation.
|
||||
|
||||
>>> tokenize('Bob dropped the apple. Where is the apple?')
|
||||
['Bob', 'dropped', 'the', 'apple', '.', 'Where', 'is', 'the', 'apple', '?']
|
||||
'''
|
||||
return [x.strip() for x in re.split('(\W+)?', sent) if x.strip()]
|
||||
|
||||
|
||||
def parse_stories(lines, only_supporting=False):
|
||||
'''Parse stories provided in the bAbi tasks format
|
||||
|
||||
If only_supporting is true, only the sentences that support the answer are kept.
|
||||
'''
|
||||
data = []
|
||||
story = []
|
||||
for line in lines:
|
||||
line = line.decode('utf-8').strip()
|
||||
nid, line = line.split(' ', 1)
|
||||
nid = int(nid)
|
||||
if nid == 1:
|
||||
story = []
|
||||
if '\t' in line:
|
||||
q, a, supporting = line.split('\t')
|
||||
q = tokenize(q)
|
||||
substory = None
|
||||
if only_supporting:
|
||||
# Only select the related substory
|
||||
supporting = map(int, supporting.split())
|
||||
substory = [story[i - 1] for i in supporting]
|
||||
else:
|
||||
# Provide all the substories
|
||||
substory = [x for x in story if x]
|
||||
data.append((substory, q, a))
|
||||
story.append('')
|
||||
else:
|
||||
sent = tokenize(line)
|
||||
story.append(sent)
|
||||
return data
|
||||
|
||||
|
||||
def get_stories(f, only_supporting=False, max_length=None):
|
||||
'''Given a file name, read the file, retrieve the stories, and then convert the sentences into a single story.
|
||||
|
||||
If max_length is supplied, any stories longer than max_length tokens will be discarded.
|
||||
'''
|
||||
data = parse_stories(f.readlines(), only_supporting=only_supporting)
|
||||
flatten = lambda data: reduce(lambda x, y: x + y, data)
|
||||
data = [(flatten(story), q, answer) for story, q, answer in data if not max_length or len(flatten(story)) < max_length]
|
||||
return data
|
||||
|
||||
|
||||
def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
|
||||
X = []
|
||||
Xq = []
|
||||
Y = []
|
||||
for story, query, answer in data:
|
||||
x = [word_idx[w] for w in story]
|
||||
xq = [word_idx[w] for w in query]
|
||||
y = np.zeros(len(word_idx) + 1) # let's not forget that index 0 is reserved
|
||||
y[word_idx[answer]] = 1
|
||||
X.append(x)
|
||||
Xq.append(xq)
|
||||
Y.append(y)
|
||||
return (pad_sequences(X, maxlen=story_maxlen),
|
||||
pad_sequences(Xq, maxlen=query_maxlen), np.array(Y))
|
||||
|
||||
|
||||
path = get_file('babi-tasks-v1-2.tar.gz',
|
||||
origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
tar = tarfile.open(path)
|
||||
|
||||
challenges = {
|
||||
# QA1 with 10,000 samples
|
||||
'single_supporting_fact_10k': 'tasks_1-20_v1-2/en-10k/qa1_single-supporting-fact_{}.txt',
|
||||
# QA2 with 10,000 samples
|
||||
'two_supporting_facts_10k': 'tasks_1-20_v1-2/en-10k/qa2_two-supporting-facts_{}.txt',
|
||||
}
|
||||
challenge_type = 'single_supporting_fact_10k'
|
||||
challenge = challenges[challenge_type]
|
||||
|
||||
print('Extracting stories for the challenge:', challenge_type)
|
||||
train_stories = get_stories(tar.extractfile(challenge.format('train')))
|
||||
test_stories = get_stories(tar.extractfile(challenge.format('test')))
|
||||
|
||||
vocab = sorted(reduce(lambda x, y: x | y, (set(story + q + [answer]) for story, q, answer in train_stories + test_stories)))
|
||||
# Reserve 0 for masking via pad_sequences
|
||||
vocab_size = len(vocab) + 1
|
||||
story_maxlen = max(map(len, (x for x, _, _ in train_stories + test_stories)))
|
||||
query_maxlen = max(map(len, (x for _, x, _ in train_stories + test_stories)))
|
||||
|
||||
print('-')
|
||||
print('Vocab size:', vocab_size, 'unique words')
|
||||
print('Story max length:', story_maxlen, 'words')
|
||||
print('Query max length:', query_maxlen, 'words')
|
||||
print('Number of training stories:', len(train_stories))
|
||||
print('Number of test stories:', len(test_stories))
|
||||
print('-')
|
||||
print('Here\'s what a "story" tuple looks like (input, query, answer):')
|
||||
print(train_stories[0])
|
||||
print('-')
|
||||
print('Vectorizing the word sequences...')
|
||||
|
||||
word_idx = dict((c, i + 1) for i, c in enumerate(vocab))
|
||||
inputs_train, queries_train, answers_train = vectorize_stories(train_stories, word_idx, story_maxlen, query_maxlen)
|
||||
inputs_test, queries_test, answers_test = vectorize_stories(test_stories, word_idx, story_maxlen, query_maxlen)
|
||||
|
||||
print('-')
|
||||
print('inputs: integer tensor of shape (samples, max_length)')
|
||||
print('inputs_train shape:', inputs_train.shape)
|
||||
print('inputs_test shape:', inputs_test.shape)
|
||||
print('-')
|
||||
print('queries: integer tensor of shape (samples, max_length)')
|
||||
print('queries_train shape:', queries_train.shape)
|
||||
print('queries_test shape:', queries_test.shape)
|
||||
print('-')
|
||||
print('answers: binary (1 or 0) tensor of shape (samples, vocab_size)')
|
||||
print('answers_train shape:', answers_train.shape)
|
||||
print('answers_test shape:', answers_test.shape)
|
||||
print('-')
|
||||
print('Compiling...')
|
||||
|
||||
# embed the input sequence into a sequence of vectors
|
||||
input_encoder_m = Sequential()
|
||||
input_encoder_m.add(Embedding(input_dim=vocab_size,
|
||||
output_dim=64,
|
||||
input_length=story_maxlen))
|
||||
# output: (samples, story_maxlen, embedding_dim)
|
||||
# embed the question into a sequence of vectors
|
||||
question_encoder = Sequential()
|
||||
question_encoder.add(Embedding(input_dim=vocab_size,
|
||||
output_dim=64,
|
||||
input_length=query_maxlen))
|
||||
# output: (samples, query_maxlen, embedding_dim)
|
||||
# compute a 'match' between input sequence elements (which are vectors)
|
||||
# and the question vector sequence
|
||||
match = Sequential()
|
||||
match.add(Merge([input_encoder_m, question_encoder],
|
||||
mode='dot',
|
||||
dot_axes=[(2,), (2,)]))
|
||||
# output: (samples, story_maxlen, query_maxlen)
|
||||
# embed the input into a single vector with size = story_maxlen:
|
||||
input_encoder_c = Sequential()
|
||||
input_encoder_c.add(Embedding(input_dim=vocab_size,
|
||||
output_dim=query_maxlen,
|
||||
input_length=story_maxlen))
|
||||
# output: (samples, story_maxlen, query_maxlen)
|
||||
# sum the match vector with the input vector:
|
||||
response = Sequential()
|
||||
response.add(Merge([match, input_encoder_c], mode='sum'))
|
||||
# output: (samples, story_maxlen, query_maxlen)
|
||||
response.add(Permute((2, 1))) # output: (samples, query_maxlen, story_maxlen)
|
||||
|
||||
# concatenate the match vector with the question vector,
|
||||
# and do logistic regression on top
|
||||
answer = Sequential()
|
||||
answer.add(Merge([response, question_encoder], mode='concat', concat_axis=-1))
|
||||
# the original paper uses a matrix multiplication for this reduction step.
|
||||
# we choose to use a RNN instead.
|
||||
answer.add(LSTM(64))
|
||||
# one regularization layer -- more would probably be needed.
|
||||
answer.add(Dropout(0.25))
|
||||
answer.add(Dense(vocab_size))
|
||||
# we output a probability distribution over the vocabulary
|
||||
answer.add(Activation('softmax'))
|
||||
|
||||
answer.compile(optimizer='rmsprop', loss='categorical_crossentropy')
|
||||
# Note: you could use a Graph model to avoid repeat the input twice
|
||||
answer.fit([inputs_train, queries_train, inputs_train], answers_train,
|
||||
batch_size=32,
|
||||
nb_epoch=70,
|
||||
show_accuracy=True,
|
||||
validation_data=([inputs_test, queries_test, inputs_test], answers_test))
|
||||
|
||||
@@ -126,14 +126,14 @@ def get_stories(f, only_supporting=False, max_length=None):
|
||||
return data
|
||||
|
||||
|
||||
def vectorize_stories(data):
|
||||
def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
|
||||
X = []
|
||||
Xq = []
|
||||
Y = []
|
||||
for story, query, answer in data:
|
||||
x = [word_idx[w] for w in story]
|
||||
xq = [word_idx[w] for w in query]
|
||||
y = np.zeros(vocab_size)
|
||||
y = np.zeros(len(word_idx) + 1) # let's not forget that index 0 is reserved
|
||||
y[word_idx[answer]] = 1
|
||||
X.append(x)
|
||||
Xq.append(xq)
|
||||
@@ -168,8 +168,8 @@ word_idx = dict((c, i + 1) for i, c in enumerate(vocab))
|
||||
story_maxlen = max(map(len, (x for x, _, _ in train + test)))
|
||||
query_maxlen = max(map(len, (x for _, x, _ in train + test)))
|
||||
|
||||
X, Xq, Y = vectorize_stories(train)
|
||||
tX, tXq, tY = vectorize_stories(test)
|
||||
X, Xq, Y = vectorize_stories(train, word_idx, story_maxlen, query_maxlen)
|
||||
tX, tXq, tY = vectorize_stories(test, word_idx, story_maxlen, query_maxlen)
|
||||
|
||||
print('vocab = {}'.format(vocab))
|
||||
print('X.shape = {}'.format(X.shape))
|
||||
|
||||
@@ -33,7 +33,7 @@ img_rows, img_cols = 32, 32
|
||||
# the CIFAR10 images are RGB
|
||||
img_channels = 3
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
# the data, shuffled and split between train 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')
|
||||
@@ -45,7 +45,7 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
model = Sequential()
|
||||
|
||||
model.add(Convolution2D(32, 3, 3, border_mode='full',
|
||||
model.add(Convolution2D(32, 3, 3, border_mode='same',
|
||||
input_shape=(img_channels, img_rows, img_cols)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(32, 3, 3))
|
||||
@@ -53,7 +53,7 @@ model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Convolution2D(64, 3, 3, border_mode='full'))
|
||||
model.add(Convolution2D(64, 3, 3, border_mode='same'))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(64, 3, 3))
|
||||
model.add(Activation('relu'))
|
||||
@@ -71,13 +71,13 @@ model.add(Activation('softmax'))
|
||||
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=sgd)
|
||||
|
||||
X_train = X_train.astype("float32")
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
|
||||
if not data_augmentation:
|
||||
print("Not using data augmentation or normalization")
|
||||
|
||||
X_train = X_train.astype("float32")
|
||||
X_test = X_test.astype("float32")
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
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)
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
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.utils.np_utils import accuracy
|
||||
from keras.models import Graph
|
||||
from keras.layers.core import Dense, Dropout
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.datasets import imdb
|
||||
|
||||
'''
|
||||
Train a Bidirectional LSTM on the IMDB sentiment classification task.
|
||||
|
||||
GPU command:
|
||||
THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python imdb_bidirectional_lstm.py
|
||||
|
||||
Output after 4 epochs on CPU: ~0.8146
|
||||
Time per epoch on CPU (Core i7): ~150s.
|
||||
'''
|
||||
|
||||
max_features = 20000
|
||||
maxlen = 100 # cut texts after this number of words (among top max_features most common words)
|
||||
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)
|
||||
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)
|
||||
y_train = np.array(y_train)
|
||||
y_test = np.array(y_test)
|
||||
|
||||
print('Build model...')
|
||||
model = Graph()
|
||||
model.add_input(name='input', input_shape=(maxlen,), dtype=int)
|
||||
model.add_node(Embedding(max_features, 128, input_length=maxlen),
|
||||
name='embedding', input='input')
|
||||
model.add_node(LSTM(64), name='forward', input='embedding')
|
||||
model.add_node(LSTM(64, go_backwards=True), name='backward', input='embedding')
|
||||
model.add_node(Dropout(0.5), name='dropout', inputs=['forward', 'backward'])
|
||||
model.add_node(Dense(1, activation='sigmoid'), name='sigmoid', input='dropout')
|
||||
model.add_output(name='output', input='sigmoid')
|
||||
|
||||
# try using different optimizers and different optimizer configs
|
||||
model.compile('adam', {'output': 'binary_crossentropy'})
|
||||
|
||||
print("Train...")
|
||||
model.fit({'input': X_train, 'output': y_train},
|
||||
batch_size=batch_size,
|
||||
nb_epoch=4)
|
||||
acc = accuracy(y_test,
|
||||
np.round(np.array(model.predict({'input': X_test},
|
||||
batch_size=batch_size)['output'])))
|
||||
print('Test accuracy:', acc)
|
||||
+10
-6
@@ -4,7 +4,6 @@ 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
|
||||
@@ -17,7 +16,7 @@ from keras.datasets import imdb
|
||||
|
||||
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.
|
||||
Get to 0.835 test accuracy after 2 epochs. 100s/epoch on K520 GPU.
|
||||
'''
|
||||
|
||||
# set parameters:
|
||||
@@ -28,7 +27,7 @@ embedding_dims = 100
|
||||
nb_filter = 250
|
||||
filter_length = 3
|
||||
hidden_dims = 250
|
||||
nb_epoch = 3
|
||||
nb_epoch = 2
|
||||
|
||||
print("Loading data...")
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features,
|
||||
@@ -60,7 +59,8 @@ model.add(Convolution1D(nb_filter=nb_filter,
|
||||
# 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:
|
||||
# We flatten the output of the conv layer,
|
||||
# so that we can add a vanilla dense layer:
|
||||
model.add(Flatten())
|
||||
|
||||
# We add a vanilla hidden layer:
|
||||
@@ -72,5 +72,9 @@ model.add(Activation('relu'))
|
||||
model.add(Dense(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))
|
||||
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))
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
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
|
||||
from keras.utils import np_utils
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, GRU, SimpleRNN
|
||||
from keras.layers.convolutional import Convolution1D, MaxPooling1D
|
||||
from keras.datasets import imdb
|
||||
|
||||
'''
|
||||
Train a recurrent convolutional network on the IMDB sentiment classification task.
|
||||
|
||||
GPU command:
|
||||
THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python imdb_lstm.py
|
||||
|
||||
Get to 0.8498 test accuracy after 2 epochs. 41s/epoch on K520 GPU.
|
||||
'''
|
||||
|
||||
# Embedding
|
||||
max_features = 20000
|
||||
maxlen = 100
|
||||
embedding_size = 128
|
||||
|
||||
# Convolution
|
||||
filter_length = 3
|
||||
nb_filter = 64
|
||||
pool_length = 2
|
||||
|
||||
# LSTM
|
||||
lstm_output_size = 70
|
||||
|
||||
# Training
|
||||
batch_size = 30
|
||||
nb_epoch = 2
|
||||
|
||||
'''
|
||||
Note:
|
||||
batch_size is highly sensitive.
|
||||
Only 2 epochs are needed as the dataset is very small.
|
||||
'''
|
||||
|
||||
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()
|
||||
model.add(Embedding(max_features, embedding_size, input_length=maxlen))
|
||||
model.add(Dropout(0.25))
|
||||
model.add(Convolution1D(nb_filter=nb_filter,
|
||||
filter_length=filter_length,
|
||||
border_mode="valid",
|
||||
activation="relu",
|
||||
subsample_length=1))
|
||||
model.add(MaxPooling1D(pool_length=pool_length))
|
||||
model.add(LSTM(lstm_output_size))
|
||||
model.add(Dense(1))
|
||||
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=nb_epoch,
|
||||
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)
|
||||
print('Test accuracy:', acc)
|
||||
+11
-6
@@ -4,12 +4,11 @@ import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.optimizers import SGD, RMSprop, Adagrad
|
||||
from keras.utils import np_utils
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, GRU
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.datasets import imdb
|
||||
|
||||
'''
|
||||
@@ -36,7 +35,8 @@ maxlen = 100 # cut texts after this number of words (among top max_features mos
|
||||
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)
|
||||
(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')
|
||||
|
||||
@@ -55,10 +55,15 @@ model.add(Dense(1))
|
||||
model.add(Activation('sigmoid'))
|
||||
|
||||
# try using different optimizers and different optimizer configs
|
||||
model.compile(loss='binary_crossentropy', optimizer='adam', class_mode="binary")
|
||||
model.compile(loss='binary_crossentropy',
|
||||
optimizer='adam',
|
||||
class_mode="binary")
|
||||
|
||||
print("Train...")
|
||||
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)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=3,
|
||||
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)
|
||||
print('Test accuracy:', acc)
|
||||
|
||||
@@ -51,7 +51,7 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
model = Sequential()
|
||||
|
||||
model.add(Convolution2D(nb_filters, nb_conv, nb_conv,
|
||||
border_mode='full',
|
||||
border_mode='same',
|
||||
input_shape=(1, img_rows, img_cols)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(nb_filters, nb_conv, nb_conv))
|
||||
|
||||
@@ -23,8 +23,8 @@ from keras.utils import np_utils
|
||||
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.)
|
||||
Reaches 0.93 train/test accuracy after 900 epochs
|
||||
(which roughly corresponds to 1687500 steps in the original paper.)
|
||||
'''
|
||||
|
||||
batch_size = 32
|
||||
@@ -34,7 +34,6 @@ 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()
|
||||
@@ -58,8 +57,7 @@ model = Sequential()
|
||||
model.add(SimpleRNN(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,
|
||||
input_shape=(None, 1)))
|
||||
activation='relu', input_shape=X_train.shape[1:]))
|
||||
model.add(Dense(nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
rmsprop = RMSprop(lr=learning_rate)
|
||||
@@ -74,7 +72,7 @@ print('IRNN test accuracy:', scores[1])
|
||||
|
||||
print('Compare to LSTM...')
|
||||
model = Sequential()
|
||||
model.add(LSTM(hidden_units, input_shape=(None, 1)))
|
||||
model.add(LSTM(hidden_units, input_shape=X_train.shape[1:]))
|
||||
model.add(Dense(nb_classes))
|
||||
model.add(Activation('softmax'))
|
||||
rmsprop = RMSprop(lr=learning_rate)
|
||||
|
||||
+11
-6
@@ -12,8 +12,9 @@ from keras.utils import np_utils
|
||||
'''
|
||||
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.
|
||||
Get to 98.40% test accuracy after 20 epochs
|
||||
(there is *a lot* of margin for parameter tuning).
|
||||
2 seconds per epoch on a K520 GPU.
|
||||
'''
|
||||
|
||||
batch_size = 128
|
||||
@@ -37,10 +38,10 @@ Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(128, input_shape=(784,)))
|
||||
model.add(Dense(512, input_shape=(784,)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Dense(128))
|
||||
model.add(Dense(512))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(Dense(10))
|
||||
@@ -49,7 +50,11 @@ model.add(Activation('softmax'))
|
||||
rms = RMSprop()
|
||||
model.compile(loss='categorical_crossentropy', optimizer=rms)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=2, validation_data=(X_test, Y_test))
|
||||
score = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
|
||||
model.fit(X_train, Y_train,
|
||||
batch_size=batch_size, nb_epoch=nb_epoch,
|
||||
show_accuracy=True, verbose=2,
|
||||
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,122 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
import datetime
|
||||
|
||||
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
|
||||
|
||||
'''
|
||||
Transfer learning toy example:
|
||||
1- Train a simple convnet on the MNIST dataset the first 5 digits [0..4].
|
||||
2- Freeze convolutional layers and fine-tune dense layers
|
||||
for the classification of digits [5..9].
|
||||
|
||||
Run on GPU: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python mnist_cnn.py
|
||||
|
||||
Get to 99.8% test accuracy after 5 epochs
|
||||
for the first five digits classifier
|
||||
and 99.2% for the last five digits after transfer + fine-tuning.
|
||||
'''
|
||||
|
||||
now = datetime.datetime.now
|
||||
|
||||
batch_size = 128
|
||||
nb_classes = 5
|
||||
nb_epoch = 5
|
||||
|
||||
# input image dimensions
|
||||
img_rows, img_cols = 28, 28
|
||||
# number of convolutional filters to use
|
||||
nb_filters = 32
|
||||
# size of pooling area for max pooling
|
||||
nb_pool = 2
|
||||
# convolution kernel size
|
||||
nb_conv = 3
|
||||
|
||||
|
||||
def train_model(model, train, test, nb_classes):
|
||||
X_train = train[0].reshape(train[0].shape[0], 1, img_rows, img_cols)
|
||||
X_test = test[0].reshape(test[0].shape[0], 1, img_rows, img_cols)
|
||||
X_train = 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(train[1], nb_classes)
|
||||
Y_test = np_utils.to_categorical(test[1], nb_classes)
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='adadelta')
|
||||
|
||||
t = now()
|
||||
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))
|
||||
print('Training time: %s' % (now() - t))
|
||||
score = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
|
||||
print('Test score:', score[0])
|
||||
print('Test accuracy:', score[1])
|
||||
|
||||
|
||||
# the data, shuffled and split between train and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
# create two datasets one with digits below 5 and one with 5 and above
|
||||
X_train_lt5 = X_train[y_train < 5]
|
||||
y_train_lt5 = y_train[y_train < 5]
|
||||
X_test_lt5 = X_test[y_test < 5]
|
||||
y_test_lt5 = y_test[y_test < 5]
|
||||
|
||||
X_train_gte5 = X_train[y_train >= 5]
|
||||
y_train_gte5 = y_train[y_train >= 5] - 5 # make classes start at 0 for
|
||||
X_test_gte5 = X_test[y_test >= 5] # np_utils.to_categorical
|
||||
y_test_gte5 = y_test[y_test >= 5] - 5
|
||||
|
||||
# define two groups of layers: feature (convolutions) and classification (dense)
|
||||
feature_layers = [
|
||||
Convolution2D(nb_filters, nb_conv, nb_conv,
|
||||
border_mode='valid',
|
||||
input_shape=(1, img_rows, img_cols)),
|
||||
Activation('relu'),
|
||||
Convolution2D(nb_filters, nb_conv, nb_conv),
|
||||
Activation('relu'),
|
||||
MaxPooling2D(pool_size=(nb_pool, nb_pool)),
|
||||
Dropout(0.25),
|
||||
Flatten(),
|
||||
]
|
||||
classification_layers = [
|
||||
Dense(128),
|
||||
Activation('relu'),
|
||||
Dropout(0.5),
|
||||
Dense(nb_classes),
|
||||
Activation('softmax')
|
||||
]
|
||||
|
||||
# create complete model
|
||||
model = Sequential()
|
||||
for l in feature_layers + classification_layers:
|
||||
model.add(l)
|
||||
|
||||
# train model for 5-digit classification [0..4]
|
||||
train_model(model,
|
||||
(X_train_lt5, y_train_lt5),
|
||||
(X_test_lt5, y_test_lt5), nb_classes)
|
||||
|
||||
# freeze feature layers and rebuild model
|
||||
for l in feature_layers:
|
||||
l.trainable = False
|
||||
|
||||
# transfer: train dense layers for new classification task [5..9]
|
||||
train_model(model,
|
||||
(X_train_gte5, y_train_gte5),
|
||||
(X_test_gte5, y_test_gte5), nb_classes)
|
||||
@@ -0,0 +1,168 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(123)
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from theano import function
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import TimeDistributedDense, Activation
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.optimizers import Adam
|
||||
from keras.utils import generic_utils
|
||||
|
||||
from keras.layers.ntm import NeuralTuringMachine as NTM
|
||||
|
||||
"""
|
||||
Copy Problem defined in Graves et. al [0]
|
||||
|
||||
Training data is made of sequences with length 1 to 20.
|
||||
Test data are sequences of length 100.
|
||||
The model is tested every 500 weight updates.
|
||||
After about 3500 updates, the accuracy jumps from around 50% to >90%.
|
||||
|
||||
Estimated compile time: 12 min
|
||||
Estimated time to train Neural Turing Machine and 3 layer LSTM on an NVidia GTX 680: 2h
|
||||
|
||||
[0]: http://arxiv.org/pdf/1410.5401v2.pdf
|
||||
"""
|
||||
|
||||
batch_size = 100
|
||||
|
||||
h_dim = 128
|
||||
n_slots = 128
|
||||
m_length = 20
|
||||
input_dim = 8
|
||||
lr = 1e-3
|
||||
clipvalue = 10
|
||||
|
||||
##### Neural Turing Machine ######
|
||||
|
||||
ntm = NTM(h_dim, n_slots=n_slots, m_length=m_length, shift_range=3,
|
||||
inner_rnn='lstm', return_sequences=True, input_dim=input_dim)
|
||||
model = Sequential()
|
||||
model.add(ntm)
|
||||
model.add(TimeDistributedDense(input_dim))
|
||||
model.add(Activation('sigmoid'))
|
||||
|
||||
sgd = Adam(lr=lr, clipvalue=clipvalue)
|
||||
model.compile(loss='binary_crossentropy', optimizer=sgd)
|
||||
|
||||
# LSTM - Run this for comparison
|
||||
|
||||
sgd2 = Adam(lr=lr, clipvalue=clipvalue)
|
||||
lstm = Sequential()
|
||||
lstm.add(LSTM(input_dim=input_dim, output_dim=h_dim*2, return_sequences=True))
|
||||
lstm.add(LSTM(output_dim=h_dim*2, return_sequences=True))
|
||||
lstm.add(LSTM(output_dim=h_dim*2, return_sequences=True))
|
||||
lstm.add(TimeDistributedDense(input_dim))
|
||||
lstm.add(Activation('sigmoid'))
|
||||
|
||||
lstm.compile(loss='binary_crossentropy', optimizer=sgd)
|
||||
|
||||
###### DATASET ########
|
||||
|
||||
def get_sample(batch_size=128, n_bits=8, max_size=20, min_size=1):
|
||||
# generate samples with random length
|
||||
inp = np.zeros((batch_size, 2*max_size-1, n_bits))
|
||||
out = np.zeros((batch_size, 2*max_size-1, n_bits))
|
||||
sw = np.zeros((batch_size, 2*max_size-1, 1))
|
||||
for i in range(batch_size):
|
||||
t = np.random.randint(low=min_size, high=max_size)
|
||||
x = np.random.uniform(size=(t, n_bits)) > .5
|
||||
for j,f in enumerate(x.sum(axis=-1)): # remove fake flags
|
||||
if f>=n_bits:
|
||||
x[j, :] = 0.
|
||||
del_flag = np.ones((1, n_bits))
|
||||
inp[i, :t+1] = np.concatenate([x, del_flag], axis=0)
|
||||
out[i, t+1:(2*t+1)] = x
|
||||
sw[i, t+1:(2*t+1)] = 1
|
||||
return inp, out, sw
|
||||
|
||||
def show_pattern(inp, out, sw, file_name='ntm_output.png'):
|
||||
''' Helper function to visualize results '''
|
||||
plt.figure(figsize=(10, 10))
|
||||
plt.subplot(131)
|
||||
plt.imshow(inp>.5)
|
||||
plt.subplot(132)
|
||||
plt.imshow(out>.5)
|
||||
plt.subplot(133)
|
||||
plt.imshow(sw>.5)
|
||||
plt.savefig(file_name)
|
||||
plt.close()
|
||||
|
||||
# Show data example:
|
||||
inp, out, sw = get_sample(1, 8, 20)
|
||||
|
||||
plt.subplot(131)
|
||||
plt.title('input')
|
||||
plt.imshow(inp[0], cmap='gray')
|
||||
plt.subplot(132)
|
||||
plt.title('desired')
|
||||
plt.imshow(out[0], cmap='gray')
|
||||
plt.subplot(133)
|
||||
plt.title('sample_weight')
|
||||
plt.imshow(sw[0], cmap='gray')
|
||||
|
||||
# training uses sequences of length 1 to 20. Test uses series of length 100.
|
||||
def test_model(model, file_name, min_size=100):
|
||||
I, V, sw = get_sample(batch_size=500, n_bits=input_dim, max_size=min_size+1, min_size=min_size)
|
||||
Y = np.asarray(model.predict(I, batch_size=100) > .5).astype('float64')
|
||||
acc = (V[:, -min_size:, :] == Y[:, -min_size:, :]).mean() * 100
|
||||
show_pattern(Y[0], V[0], sw[0], file_name)
|
||||
return acc
|
||||
|
||||
##### TRAIN ######
|
||||
nb_epoch = 4000
|
||||
progbar = generic_utils.Progbar(nb_epoch)
|
||||
for e in range(nb_epoch):
|
||||
I, V, sw = get_sample(n_bits=input_dim, max_size=20, min_size=1, batch_size=100)
|
||||
|
||||
loss1 = model.train_on_batch(I, V, sample_weight=sw)
|
||||
loss2 = lstm.train_on_batch(I, V, sample_weight=sw)
|
||||
|
||||
progbar.add(1, values=[("NTM", loss1), ("LSTM", loss2)])
|
||||
|
||||
if e % 500 == 0:
|
||||
print("")
|
||||
acc1 = test_model(model, 'ntm.png')
|
||||
acc2 = test_model(lstm, 'lstm.png')
|
||||
print("NTM test acc: {}".format(acc1))
|
||||
print("LSTM test acc: {}".format(acc2))
|
||||
|
||||
##### VISUALIZATION #####
|
||||
X = model.get_input()
|
||||
Y = ntm.get_full_output()[0:3] # (memory over time, read_vectors, write_vectors)
|
||||
F = function([X], Y, allow_input_downcast=True)
|
||||
|
||||
inp, out, sw = get_sample(1, 8, 21, 20)
|
||||
mem, read, write = F(inp.astype('float32'))
|
||||
Y = model.predict(inp)
|
||||
|
||||
plt.figure(figsize=(15, 12))
|
||||
|
||||
plt.subplot(221)
|
||||
plt.imshow(write[0])
|
||||
plt.xlabel('memory location')
|
||||
plt.ylabel('time')
|
||||
plt.title('write')
|
||||
|
||||
plt.subplot(222)
|
||||
plt.imshow(read[0])
|
||||
plt.title('read')
|
||||
|
||||
plt.subplot(223)
|
||||
plt.title('desired')
|
||||
plt.imshow(out[0])
|
||||
|
||||
plt.subplot(224)
|
||||
plt.imshow(Y[0]>.5)
|
||||
plt.title('output')
|
||||
|
||||
plt.figure(figsize=(15, 10))
|
||||
plt.subplot(325)
|
||||
plt.ylabel('time')
|
||||
plt.xlabel('location')
|
||||
plt.title('memory evolving in time (avg value per location)')
|
||||
plt.imshow(mem[0].mean(axis=-1))
|
||||
@@ -1,221 +0,0 @@
|
||||
|
||||
'''
|
||||
We loop over words in a dataset, and for each word, we look at a context window around the word.
|
||||
We generate pairs of (pivot_word, other_word_from_same_context) with label 1,
|
||||
and pairs of (pivot_word, random_word) with label 0 (skip-gram method).
|
||||
|
||||
We use the layer WordContextProduct to learn embeddings for the word couples,
|
||||
and compute a proximity score between the embeddings (= p(context|word)),
|
||||
trained with our positive and negative labels.
|
||||
|
||||
We then use the weights computed by WordContextProduct to encode words
|
||||
and demonstrate that the geometry of the embedding space
|
||||
captures certain useful semantic properties.
|
||||
|
||||
Read more about skip-gram in this particularly gnomic paper by Mikolov et al.:
|
||||
http://arxiv.org/pdf/1301.3781v3.pdf
|
||||
|
||||
Note: you should run this on GPU, otherwise training will be quite slow.
|
||||
On a EC2 GPU instance, expect 3 hours per 10e6 comments (~10e8 words) per epoch with dim_proj=256.
|
||||
Should be much faster on a modern GPU.
|
||||
|
||||
GPU command:
|
||||
THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python skipgram_word_embeddings.py
|
||||
|
||||
Dataset: 5,845,908 Hacker News comments.
|
||||
Obtain the dataset at:
|
||||
https://mega.co.nz/#F!YohlwD7R!wec0yNO86SeaNGIYQBOR0A
|
||||
(HNCommentsAll.1perline.json.bz2)
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import theano
|
||||
from six.moves import cPickle
|
||||
import os, re, json
|
||||
|
||||
from keras.preprocessing import sequence, text
|
||||
from keras.optimizers import SGD, RMSprop, Adagrad
|
||||
from keras.utils import np_utils, generic_utils
|
||||
from keras.models import Sequential
|
||||
from keras.layers.embeddings import WordContextProduct, Embedding
|
||||
from six.moves import range
|
||||
from six.moves import zip
|
||||
|
||||
max_features = 50000 # vocabulary size: top 50,000 most common words in data
|
||||
skip_top = 100 # ignore top 100 most common words
|
||||
nb_epoch = 1
|
||||
dim_proj = 256 # embedding space dimension
|
||||
|
||||
save = True
|
||||
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"
|
||||
|
||||
data_path = os.path.expanduser("~/")+"HNCommentsAll.1perline.json"
|
||||
|
||||
# text preprocessing utils
|
||||
html_tags = re.compile(r'<.*?>')
|
||||
to_replace = [(''', "'")]
|
||||
hex_tags = re.compile(r'&.*?;')
|
||||
|
||||
|
||||
def clean_comment(comment):
|
||||
c = str(comment.encode("utf-8"))
|
||||
c = html_tags.sub(' ', c)
|
||||
for tag, char in to_replace:
|
||||
c = c.replace(tag, char)
|
||||
c = hex_tags.sub(' ', c)
|
||||
return c
|
||||
|
||||
|
||||
def text_generator(path=data_path):
|
||||
f = open(path)
|
||||
for i, l in enumerate(f):
|
||||
comment_data = json.loads(l)
|
||||
comment_text = comment_data["comment_text"]
|
||||
comment_text = clean_comment(comment_text)
|
||||
if i % 10000 == 0:
|
||||
print(i)
|
||||
yield comment_text
|
||||
f.close()
|
||||
|
||||
# model management
|
||||
if load_tokenizer:
|
||||
print('Load tokenizer...')
|
||||
tokenizer = cPickle.load(open(os.path.join(save_dir, tokenizer_fname), 'rb'))
|
||||
else:
|
||||
print("Fit tokenizer...")
|
||||
tokenizer = text.Tokenizer(nb_words=max_features)
|
||||
tokenizer.fit_on_texts(text_generator())
|
||||
if save:
|
||||
print("Save tokenizer...")
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
cPickle.dump(tokenizer, open(os.path.join(save_dir, tokenizer_fname), "wb"))
|
||||
|
||||
# training process
|
||||
if train_model:
|
||||
if load_model:
|
||||
print('Load model...')
|
||||
model = cPickle.load(open(os.path.join(save_dir, model_load_fname), 'rb'))
|
||||
else:
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(WordContextProduct(max_features, proj_dim=dim_proj, init="uniform"))
|
||||
model.compile(loss='mse', optimizer='rmsprop')
|
||||
|
||||
sampling_table = sequence.make_sampling_table(max_features)
|
||||
|
||||
for e in range(nb_epoch):
|
||||
print('-'*40)
|
||||
print('Epoch', e)
|
||||
print('-'*40)
|
||||
|
||||
progbar = generic_utils.Progbar(tokenizer.document_count)
|
||||
samples_seen = 0
|
||||
losses = []
|
||||
|
||||
for i, seq in enumerate(tokenizer.texts_to_sequences_generator(text_generator())):
|
||||
# get skipgram couples for one text in the dataset
|
||||
couples, labels = sequence.skipgrams(seq, max_features, window_size=4, negative_samples=1., sampling_table=sampling_table)
|
||||
if couples:
|
||||
# one gradient update per sentence (one sentence = a few 1000s of word couples)
|
||||
X = np.array(couples, dtype="int32")
|
||||
loss = model.train_on_batch(X, labels)
|
||||
losses.append(loss)
|
||||
if len(losses) % 100 == 0:
|
||||
progbar.update(i, values=[("loss", np.mean(losses))])
|
||||
losses = []
|
||||
samples_seen += len(labels)
|
||||
print('Samples seen:', samples_seen)
|
||||
print("Training completed!")
|
||||
|
||||
if save:
|
||||
print("Saving model...")
|
||||
if not os.path.exists(save_dir):
|
||||
os.makedirs(save_dir)
|
||||
cPickle.dump(model, open(os.path.join(save_dir, model_save_fname), "wb"))
|
||||
|
||||
|
||||
print("It's test time!")
|
||||
|
||||
# recover the embedding weights trained with skipgram:
|
||||
weights = model.layers[0].get_weights()[0]
|
||||
|
||||
# we no longer need this
|
||||
del model
|
||||
|
||||
weights[:skip_top] = np.zeros((skip_top, dim_proj))
|
||||
norm_weights = np_utils.normalize(weights)
|
||||
|
||||
word_index = tokenizer.word_index
|
||||
reverse_word_index = dict([(v, k) for k, v in list(word_index.items())])
|
||||
|
||||
|
||||
def embed_word(w):
|
||||
i = word_index.get(w)
|
||||
if (not i) or (i < skip_top) or (i >= max_features):
|
||||
return None
|
||||
return norm_weights[i]
|
||||
|
||||
|
||||
def closest_to_point(point, nb_closest=10):
|
||||
proximities = np.dot(norm_weights, point)
|
||||
tups = list(zip(list(range(len(proximities))), proximities))
|
||||
tups.sort(key=lambda x: x[1], reverse=True)
|
||||
return [(reverse_word_index.get(t[0]), t[1]) for t in tups[:nb_closest]]
|
||||
|
||||
|
||||
def closest_to_word(w, nb_closest=10):
|
||||
i = word_index.get(w)
|
||||
if (not i) or (i < skip_top) or (i >= max_features):
|
||||
return []
|
||||
return closest_to_point(norm_weights[i].T, nb_closest)
|
||||
|
||||
|
||||
''' the resuls in comments below were for:
|
||||
5.8M HN comments
|
||||
dim_proj = 256
|
||||
nb_epoch = 2
|
||||
optimizer = rmsprop
|
||||
loss = mse
|
||||
max_features = 50000
|
||||
skip_top = 100
|
||||
negative_samples = 1.
|
||||
window_size = 4
|
||||
and frequency subsampling of factor 10e-5.
|
||||
'''
|
||||
|
||||
words = [
|
||||
"article", # post, story, hn, read, comments
|
||||
"3", # 6, 4, 5, 2
|
||||
"two", # three, few, several, each
|
||||
"great", # love, nice, working, looking
|
||||
"data", # information, memory, database
|
||||
"money", # company, pay, customers, spend
|
||||
"years", # ago, year, months, hours, week, days
|
||||
"android", # ios, release, os, mobile, beta
|
||||
"javascript", # js, css, compiler, library, jquery, ruby
|
||||
"look", # looks, looking
|
||||
"business", # industry, professional, customers
|
||||
"company", # companies, startup, founders, startups
|
||||
"after", # before, once, until
|
||||
"own", # personal, our, having
|
||||
"us", # united, country, american, tech, diversity, usa, china, sv
|
||||
"using", # javascript, js, tools (lol)
|
||||
"here", # hn, post, comments
|
||||
]
|
||||
|
||||
for w in words:
|
||||
res = closest_to_word(w)
|
||||
print('====', w)
|
||||
for r in res:
|
||||
print(r)
|
||||
@@ -0,0 +1,15 @@
|
||||
|
||||
"""
|
||||
Keras: Theano-based Deep Learning library
|
||||
==================================
|
||||
Keras is a minimalist, highly modular neural network library in
|
||||
the spirit of Torch, written in Python / Theano so as not to have
|
||||
to deal with the dearth of ecosystem in Lua. It was developed with
|
||||
a focus on enabling fast experimentation. Being able to go from
|
||||
idea to result with the least possible delay is key to doing
|
||||
good research.
|
||||
|
||||
See http://keras.io/
|
||||
"""
|
||||
|
||||
__version__ = '0.2.0'
|
||||
|
||||
+19
-14
@@ -1,35 +1,40 @@
|
||||
from __future__ import absolute_import
|
||||
import theano.tensor as T
|
||||
from . import backend as K
|
||||
|
||||
|
||||
def softmax(x):
|
||||
return T.nnet.softmax(x.reshape((-1, x.shape[-1]))).reshape(x.shape)
|
||||
|
||||
|
||||
def time_distributed_softmax(x):
|
||||
import warnings
|
||||
warnings.warn("time_distributed_softmax is deprecated. Just use softmax!", DeprecationWarning)
|
||||
return softmax(x)
|
||||
ndim = K.ndim(x)
|
||||
if ndim == 2:
|
||||
return K.softmax(x)
|
||||
elif ndim == 3:
|
||||
# apply softmax to each timestep
|
||||
def step(x, states):
|
||||
return K.softmax(x), []
|
||||
last_output, outputs, states = K.rnn(step, x, [], masking=False)
|
||||
return outputs
|
||||
else:
|
||||
raise Exception('Cannot apply softmax to a tensor that is not 2D or 3D. ' +
|
||||
'Here, ndim=' + str(ndim))
|
||||
|
||||
|
||||
def softplus(x):
|
||||
return T.nnet.softplus(x)
|
||||
return K.softplus(x)
|
||||
|
||||
|
||||
def relu(x):
|
||||
return T.nnet.relu(x)
|
||||
def relu(x, alpha=0., max_value=None):
|
||||
return K.relu(x, alpha=alpha, max_value=max_value)
|
||||
|
||||
|
||||
def tanh(x):
|
||||
return T.tanh(x)
|
||||
return K.tanh(x)
|
||||
|
||||
|
||||
def sigmoid(x):
|
||||
return T.nnet.sigmoid(x)
|
||||
return K.sigmoid(x)
|
||||
|
||||
|
||||
def hard_sigmoid(x):
|
||||
return T.nnet.hard_sigmoid(x)
|
||||
return K.hard_sigmoid(x)
|
||||
|
||||
|
||||
def linear(x):
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import json
|
||||
from .common import epsilon, floatx, set_epsilon, set_floatx
|
||||
|
||||
_keras_dir = os.path.expanduser(os.path.join('~', '.keras'))
|
||||
if not os.path.exists(_keras_dir):
|
||||
os.makedirs(_keras_dir)
|
||||
|
||||
_BACKEND = 'theano'
|
||||
_config_path = os.path.expanduser(os.path.join('~', '.keras', 'keras.json'))
|
||||
if os.path.exists(_config_path):
|
||||
_config = json.load(open(_config_path))
|
||||
_floatx = _config.get('floatx', floatx())
|
||||
assert _floatx in {'float32', 'float64'}
|
||||
_epsilon = _config.get('epsilon', epsilon())
|
||||
assert type(_epsilon) == float
|
||||
_backend = _config.get('backend', _BACKEND)
|
||||
assert _backend in {'theano', 'tensorflow'}
|
||||
|
||||
set_floatx(_floatx)
|
||||
set_epsilon(_epsilon)
|
||||
_BACKEND = _backend
|
||||
else:
|
||||
# save config file, for easy edition
|
||||
_config = {'floatx': floatx(),
|
||||
'epsilon': epsilon(),
|
||||
'backend': _BACKEND}
|
||||
json.dump(_config, open(_config_path, 'w'))
|
||||
|
||||
if _BACKEND == 'theano':
|
||||
print('Using Theano backend.')
|
||||
from .theano_backend import *
|
||||
elif _BACKEND == 'tensorflow':
|
||||
print('Using TensorFlow backend.')
|
||||
from .tensorflow_backend import *
|
||||
else:
|
||||
raise Exception('Unknown backend: ' + str(backend))
|
||||
@@ -0,0 +1,31 @@
|
||||
import numpy as np
|
||||
|
||||
# the type of float to use throughout the session.
|
||||
_FLOATX = 'float32'
|
||||
_EPSILON = 10e-8
|
||||
|
||||
|
||||
def epsilon():
|
||||
return _EPSILON
|
||||
|
||||
|
||||
def set_epsilon(e):
|
||||
global _EPSILON
|
||||
_EPSILON = e
|
||||
|
||||
|
||||
def floatx():
|
||||
return _FLOATX
|
||||
|
||||
|
||||
def set_floatx(floatx):
|
||||
global _FLOATX
|
||||
if floatx not in {'float32', 'float64'}:
|
||||
raise Exception('Unknown floatx type: ' + str(floatx))
|
||||
_FLOATX = floatx
|
||||
|
||||
|
||||
def cast_to_floatx(x):
|
||||
'''Cast a Numpy array to floatx.
|
||||
'''
|
||||
return np.asarray(x, dtype=_FLOATX)
|
||||
@@ -0,0 +1,602 @@
|
||||
import tensorflow as tf
|
||||
import numpy as np
|
||||
from .common import _FLOATX, _EPSILON
|
||||
|
||||
# INTERNAL UTILS
|
||||
|
||||
_SESSION = None
|
||||
|
||||
|
||||
def _get_session():
|
||||
global _SESSION
|
||||
if _SESSION is None:
|
||||
_SESSION = tf.Session('')
|
||||
return _SESSION
|
||||
|
||||
|
||||
def _set_session(session):
|
||||
global _SESSION
|
||||
_SESSION = session
|
||||
|
||||
|
||||
# VARIABLE MANIPULATION
|
||||
|
||||
def variable(value, dtype=_FLOATX, name=None):
|
||||
v = tf.Variable(np.asarray(value, dtype=dtype), name=name)
|
||||
_get_session().run(v.initializer)
|
||||
return v
|
||||
|
||||
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
if not shape:
|
||||
if ndim:
|
||||
shape = [None for _ in range(ndim)]
|
||||
return tf.placeholder(dtype, shape=shape, name=name)
|
||||
|
||||
|
||||
def shape(x):
|
||||
return x.get_shape()
|
||||
|
||||
|
||||
def ndim(x):
|
||||
return len(x.get_shape())
|
||||
|
||||
|
||||
def eval(x):
|
||||
'''Run a graph.
|
||||
'''
|
||||
return x.eval(session=_get_session())
|
||||
|
||||
|
||||
def zeros(shape, dtype=_FLOATX, name=None):
|
||||
return variable(np.zeros(shape), dtype, name)
|
||||
|
||||
|
||||
def ones(shape, dtype=_FLOATX, name=None):
|
||||
return variable(np.ones(shape), dtype, name)
|
||||
|
||||
|
||||
def ones_like(x, name=None):
|
||||
return tf.ones_like(x)
|
||||
|
||||
|
||||
def zeros_like(x, name=None):
|
||||
return tf.zeros_like(x)
|
||||
|
||||
|
||||
def count_params(x):
|
||||
'''Return number of scalars in a tensor.
|
||||
'''
|
||||
shape = x.get_shape()
|
||||
return np.prod([shape[i]._value for i in range(len(shape))])
|
||||
|
||||
|
||||
def cast(x, dtype):
|
||||
return tf.cast(x, dtype)
|
||||
|
||||
|
||||
# LINEAR ALGEBRA
|
||||
|
||||
def dot(x, y):
|
||||
return tf.matmul(x, y)
|
||||
|
||||
|
||||
def transpose(x):
|
||||
return tf.transpose(x)
|
||||
|
||||
|
||||
def gather(reference, indices):
|
||||
'''reference: a tensor.
|
||||
indices: an int tensor of indices.
|
||||
|
||||
Return: a tensor of same type as reference.
|
||||
'''
|
||||
return tf.gather(reference, indices)
|
||||
|
||||
|
||||
# ELEMENT-WISE OPERATIONS
|
||||
|
||||
def max(x, axis=None, keepdims=False):
|
||||
if axis is not None and axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
return tf.reduce_max(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
|
||||
|
||||
def min(x, axis=None, keepdims=False):
|
||||
if axis is not None and axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
return tf.reduce_min(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
|
||||
|
||||
def sum(x, axis=None, keepdims=False):
|
||||
'''Sum of the values in a tensor, alongside the specified axis.
|
||||
'''
|
||||
if axis is not None and axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
return tf.reduce_sum(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
|
||||
|
||||
def prod(x, axis=None, keepdims=False):
|
||||
'''Multiply the values in a tensor, alongside the specified axis.
|
||||
'''
|
||||
return tf.reduce_prod(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
|
||||
|
||||
def std(x, axis=None, keepdims=False):
|
||||
if axis is not None and axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
if x.dtype.base_dtype == tf.bool:
|
||||
x = tf.cast(x, _FLOATX)
|
||||
m = tf.reduce_mean(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
devs_squared = tf.square(x - m)
|
||||
return tf.sqrt(tf.reduce_mean(devs_squared,
|
||||
reduction_indices=axis,
|
||||
keep_dims=keepdims))
|
||||
|
||||
|
||||
def mean(x, axis=None, keepdims=False):
|
||||
if axis is not None and axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
if x.dtype.base_dtype == tf.bool:
|
||||
x = tf.cast(x, _FLOATX)
|
||||
return tf.reduce_mean(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
|
||||
|
||||
def any(x, axis=None, keepdims=False):
|
||||
'''Bitwise reduction (logical OR).
|
||||
|
||||
Return array of int8 (0s and 1s).
|
||||
'''
|
||||
if axis is not None and axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
x = tf.cast(x, tf.bool)
|
||||
x = tf.reduce_any(x, reduction_indices=axis, keep_dims=keepdims)
|
||||
return tf.cast(x, tf.int8)
|
||||
|
||||
|
||||
def argmax(x, axis=-1):
|
||||
if axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
return tf.argmax(x, axis)
|
||||
|
||||
|
||||
def argmin(x, axis=-1):
|
||||
if axis < 0:
|
||||
axis = axis % len(x.get_shape())
|
||||
return tf.argmin(x, axis)
|
||||
|
||||
|
||||
def square(x):
|
||||
return tf.square(x)
|
||||
|
||||
|
||||
def abs(x):
|
||||
return tf.abs(x)
|
||||
|
||||
|
||||
def sqrt(x):
|
||||
x = tf.clip_by_value(x, tf.cast(0., dtype=_FLOATX),
|
||||
tf.cast(np.inf, dtype=_FLOATX))
|
||||
return tf.sqrt(x)
|
||||
|
||||
|
||||
def exp(x):
|
||||
return tf.exp(x)
|
||||
|
||||
|
||||
def log(x):
|
||||
return tf.log(x)
|
||||
|
||||
|
||||
def round(x):
|
||||
return tf.round(x)
|
||||
|
||||
|
||||
def pow(x, a):
|
||||
return tf.pow(x, a)
|
||||
|
||||
|
||||
def clip(x, min_value, max_value):
|
||||
if max_value < min_value:
|
||||
max_value = min_value
|
||||
return tf.clip_by_value(x, tf.cast(min_value, dtype=_FLOATX),
|
||||
tf.cast(max_value, dtype=_FLOATX))
|
||||
|
||||
|
||||
def equal(x, y):
|
||||
return tf.equal(x, y)
|
||||
|
||||
|
||||
def maximum(x, y):
|
||||
return tf.maximum(x, y)
|
||||
|
||||
|
||||
def minimum(x, y):
|
||||
return tf.minimum(x, y)
|
||||
|
||||
|
||||
# SHAPE OPERATIONS
|
||||
|
||||
def concatenate(tensors, axis=-1):
|
||||
if axis < 0:
|
||||
axis = axis % len(tensors[0].get_shape())
|
||||
return tf.concat(axis, tensors)
|
||||
|
||||
|
||||
def reshape(x, shape):
|
||||
return tf.reshape(x, shape)
|
||||
|
||||
|
||||
def permute_dimensions(x, pattern):
|
||||
'''Transpose dimensions.
|
||||
|
||||
pattern should be a tuple or list of
|
||||
dimension indices, e.g. [0, 2, 1].
|
||||
'''
|
||||
return tf.transpose(x, perm=pattern)
|
||||
|
||||
|
||||
def repeat(x, n):
|
||||
'''Repeat a 2D tensor:
|
||||
|
||||
if x has shape (samples, dim) and n=2,
|
||||
the output will have shape (samples, 2, dim)
|
||||
'''
|
||||
tensors = [x] * n
|
||||
stacked = tf.pack(tensors)
|
||||
return tf.transpose(stacked, (1, 0, 2))
|
||||
|
||||
|
||||
def tile(x, n):
|
||||
return tf.tile(x, n)
|
||||
|
||||
|
||||
def flatten(x):
|
||||
'''Turn a n-D tensor into a 2D tensor where
|
||||
the first dimension is conserved.
|
||||
'''
|
||||
x = tf.reshape(x, [-1, np.prod(x.get_shape()[1:].as_list())])
|
||||
return x
|
||||
|
||||
|
||||
def expand_dims(x, dim=-1):
|
||||
'''Add a 1-sized dimension at index "dim".
|
||||
'''
|
||||
return tf.expand_dims(x, dim)
|
||||
|
||||
|
||||
def squeeze(x, axis):
|
||||
'''Remove a 1-dimension from the tensor at index "axis".
|
||||
'''
|
||||
return tf.squeeze(x, [axis])
|
||||
|
||||
|
||||
def temporal_padding(x, padding=1):
|
||||
'''Pad the middle dimension of a 3D tensor
|
||||
with "padding" zeros left and right.
|
||||
|
||||
Appologies for the inane API, but Theano makes this
|
||||
really hard.
|
||||
'''
|
||||
pattern = [[0, 0], [padding, padding], [0, 0]]
|
||||
return tf.pad(x, pattern)
|
||||
|
||||
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
'''Pad the 2nd and 3rd dimensions of a 4D tensor
|
||||
with "padding[0]" and "padding[1]" (resp.) zeros left and right.
|
||||
'''
|
||||
if dim_ordering == 'th':
|
||||
pattern = [[0, 0], [0, 0],
|
||||
[padding[0], padding[0]], [padding[1], padding[1]]]
|
||||
else:
|
||||
pattern = [[0, 0],
|
||||
[padding[0], padding[0]], [padding[1], padding[1]],
|
||||
[0, 0]]
|
||||
return tf.pad(x, pattern)
|
||||
|
||||
|
||||
# VALUE MANIPULATION
|
||||
|
||||
def get_value(x):
|
||||
'''Technically the same as eval() for TF.
|
||||
'''
|
||||
return x.eval(session=_get_session())
|
||||
|
||||
|
||||
def set_value(x, value):
|
||||
tf.assign(x, np.asarray(value)).op.run(session=_get_session())
|
||||
|
||||
|
||||
# GRAPH MANIPULATION
|
||||
|
||||
class Function(object):
|
||||
|
||||
def __init__(self, inputs, outputs, updates=[]):
|
||||
self.inputs = list(inputs)
|
||||
self.outputs = list(outputs)
|
||||
with tf.control_dependencies(self.outputs):
|
||||
self.updates = [tf.assign(p, new_p) for (p, new_p) in updates]
|
||||
|
||||
def __call__(self, inputs):
|
||||
names = [v.name for v in self.inputs]
|
||||
feed_dict = dict(zip(names, inputs))
|
||||
session = _get_session()
|
||||
updated = session.run(self.outputs + self.updates, feed_dict=feed_dict)
|
||||
return updated[:len(self.outputs)]
|
||||
|
||||
|
||||
def function(inputs, outputs, updates=[]):
|
||||
return Function(inputs, outputs, updates=updates)
|
||||
|
||||
|
||||
def gradients(loss, variables):
|
||||
return tf.gradients(loss, variables)
|
||||
|
||||
|
||||
# CONTROL FLOW
|
||||
|
||||
def rnn(step_function, inputs, initial_states,
|
||||
go_backwards=False, masking=True):
|
||||
'''Iterates over the time dimension of a tensor.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
inputs: tensor of temporal data of shape (samples, time, ...)
|
||||
(at least 3D).
|
||||
step_function:
|
||||
Parameters:
|
||||
input: tensor with shape (samples, ...) (no time dimension),
|
||||
representing input for the batch of samples at a certain
|
||||
time step.
|
||||
states: list of tensors.
|
||||
Returns:
|
||||
output: tensor with shape (samples, ...) (no time dimension),
|
||||
new_states: list of tensors, same length and shapes
|
||||
as 'states'.
|
||||
initial_states: tensor with shape (samples, ...) (no time dimension),
|
||||
containing the initial values for the states used in
|
||||
the step function.
|
||||
go_backwards: boolean. If True, do the iteration over
|
||||
the time dimension in reverse order.
|
||||
masking: boolean. If true, any input timestep inputs[s, i]
|
||||
that is all-zeros will be skipped (states will be passed to
|
||||
the next step unchanged) and the corresponding output will
|
||||
be all zeros.
|
||||
|
||||
Returns
|
||||
-------
|
||||
A tuple (last_output, outputs, new_states).
|
||||
last_output: the latest output of the rnn, of shape (samples, ...)
|
||||
outputs: tensor with shape (samples, time, ...) where each
|
||||
entry outputs[s, t] is the output of the step function
|
||||
at time t for sample s.
|
||||
new_states: list of tensors, latest states returned by
|
||||
the step function, of shape (samples, ...).
|
||||
'''
|
||||
inputs = tf.transpose(inputs, (1, 0, 2))
|
||||
input_list = tf.unpack(inputs)
|
||||
|
||||
states = initial_states
|
||||
successive_states = []
|
||||
successive_outputs = []
|
||||
if go_backwards:
|
||||
input_list.reverse()
|
||||
for input in input_list:
|
||||
output, new_states = step_function(input, states)
|
||||
if masking:
|
||||
# for now we raise an exception because tf.reduce_any will not work
|
||||
raise Exception("Masking is Theano-only for the time being.")
|
||||
|
||||
# if all-zero input timestep, return
|
||||
# all-zero output and unchanged states
|
||||
switch = tf.reduce_any(input)
|
||||
output = tf.control_flow_ops.cond(switch,
|
||||
lambda: output,
|
||||
lambda: 0. * output)
|
||||
return_states = []
|
||||
for state, new_state in zip(states, new_states):
|
||||
return_states.append(tf.control_flow_ops.cond(switch,
|
||||
lambda: new_state,
|
||||
lambda: state))
|
||||
states = return_states
|
||||
else:
|
||||
states = new_states
|
||||
successive_outputs.append(output)
|
||||
successive_states.append(states)
|
||||
|
||||
last_output = successive_outputs[-1]
|
||||
outputs = tf.pack(successive_outputs)
|
||||
new_states = successive_states[-1]
|
||||
|
||||
outputs = tf.transpose(outputs, (1, 0, 2))
|
||||
return last_output, outputs, states
|
||||
|
||||
|
||||
def switch(condition, then_expression, else_expression):
|
||||
'''condition: scalar tensor.
|
||||
'''
|
||||
return tf.control_flow_ops.cond(condition,
|
||||
lambda: then_expression,
|
||||
lambda: else_expression)
|
||||
|
||||
|
||||
# NN OPERATIONS
|
||||
|
||||
def relu(x, alpha=0., max_value=None):
|
||||
'''ReLU.
|
||||
|
||||
alpha: slope of negative section.
|
||||
'''
|
||||
negative_part = tf.nn.relu(-x)
|
||||
x = tf.nn.relu(x)
|
||||
if max_value is not None:
|
||||
x = tf.clip_by_value(x, tf.cast(0., dtype=_FLOATX),
|
||||
tf.cast(max_value, dtype=_FLOATX))
|
||||
x -= tf.constant(alpha, dtype=_FLOATX) * negative_part
|
||||
return x
|
||||
|
||||
|
||||
def softmax(x):
|
||||
return tf.nn.softmax(x)
|
||||
|
||||
|
||||
def softplus(x):
|
||||
return tf.nn.softplus(x)
|
||||
|
||||
|
||||
def categorical_crossentropy(output, target, from_logits=False):
|
||||
'''Note: tf.nn.softmax_cross_entropy_with_logits
|
||||
expects logits, Keras expects probabilities.
|
||||
'''
|
||||
if not from_logits:
|
||||
# scale preds so that the class probas of each sample sum to 1
|
||||
output /= tf.reduce_sum(output,
|
||||
reduction_indices=len(output.get_shape())-1,
|
||||
keep_dims=True)
|
||||
# manual computation of crossentropy
|
||||
output = tf.clip_by_value(output, tf.cast(_EPSILON, dtype=_FLOATX),
|
||||
tf.cast(1.-_EPSILON, dtype=_FLOATX))
|
||||
return - tf.reduce_sum(target * tf.log(output),
|
||||
reduction_indices=len(output.get_shape())-1)
|
||||
else:
|
||||
return tf.nn.softmax_cross_entropy_with_logits(output, target)
|
||||
|
||||
|
||||
def binary_crossentropy(output, target, from_logits=False):
|
||||
'''Note: tf.nn.sigmoid_cross_entropy_with_logits
|
||||
expects logits, Keras expects probabilities.
|
||||
'''
|
||||
if not from_logits:
|
||||
# transform back to logits
|
||||
output = tf.clip_by_value(output, tf.cast(_EPSILON, dtype=_FLOATX),
|
||||
tf.cast(1.-_EPSILON, dtype=_FLOATX))
|
||||
output = tf.log(output / (1 - output))
|
||||
return tf.nn.sigmoid_cross_entropy_with_logits(output, target)
|
||||
|
||||
|
||||
def sigmoid(x):
|
||||
return tf.nn.sigmoid(x)
|
||||
|
||||
|
||||
def hard_sigmoid(x):
|
||||
x = (0.2 * x) + 0.5
|
||||
x = tf.clip_by_value(x, tf.cast(0., dtype=_FLOATX),
|
||||
tf.cast(1., dtype=_FLOATX))
|
||||
return x
|
||||
|
||||
|
||||
def tanh(x):
|
||||
return tf.nn.tanh(x)
|
||||
|
||||
|
||||
def dropout(x, level, seed=None):
|
||||
retain_prob = 1. - level
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
# the dummy 1. works around a TF bug
|
||||
# (float32_ref vs. float32 incomptability)
|
||||
return tf.nn.dropout(x * 1., retain_prob, seed=seed)
|
||||
|
||||
|
||||
# CONVOLUTIONS
|
||||
|
||||
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th'):
|
||||
'''
|
||||
Run on cuDNN if available.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: whether to use Theano or TensorFlow dimension ordering
|
||||
in inputs/kernels/ouputs.
|
||||
'''
|
||||
if border_mode == 'same':
|
||||
padding = 'SAME'
|
||||
elif border_mode == 'valid':
|
||||
padding = 'VALID'
|
||||
else:
|
||||
raise Exception('Invalid border mode: ' + str(border_mode))
|
||||
|
||||
strides = (1,) + strides + (1,)
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
# tf conv2d only supports float32
|
||||
x = tf.cast(x, 'float32')
|
||||
kernel = tf.cast(kernel, 'float32')
|
||||
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
x = tf.transpose(x, (0, 2, 3, 1))
|
||||
kernel = tf.transpose(kernel, (2, 3, 1, 0))
|
||||
x = tf.nn.conv2d(x, kernel, strides, padding=padding)
|
||||
x = tf.transpose(x, (0, 3, 1, 2))
|
||||
elif dim_ordering == 'tf':
|
||||
x = tf.nn.conv2d(x, kernel, strides, padding=padding)
|
||||
else:
|
||||
raise Exception('Unknown dim_ordering: ' + str(dim_ordering))
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float64')
|
||||
return x
|
||||
|
||||
|
||||
def maxpool2d(x, pool_size, strides=(1, 1),
|
||||
border_mode='valid', dim_ordering='th'):
|
||||
'''
|
||||
pool_size: tuple of 2 integers.
|
||||
strides: tuple of 2 integers.
|
||||
border_mode: one of "valid", "same".
|
||||
dim_ordering: one of "th", "tf".
|
||||
'''
|
||||
if border_mode == 'same':
|
||||
padding = 'SAME'
|
||||
elif border_mode == 'valid':
|
||||
padding = 'VALID'
|
||||
else:
|
||||
raise Exception('Invalid border mode: ' + str(border_mode))
|
||||
|
||||
strides = (1,) + strides + (1,)
|
||||
pool_size = (1,) + pool_size + (1,)
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
# tf max_pool only supports float32
|
||||
x = tf.cast(x, 'float32')
|
||||
|
||||
if dim_ordering == 'th':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
x = tf.transpose(x, (0, 2, 3, 1))
|
||||
x = tf.nn.max_pool(x, pool_size, strides, padding=padding)
|
||||
x = tf.transpose(x, (0, 3, 1, 2))
|
||||
elif dim_ordering == 'tf':
|
||||
x = tf.nn.max_pool(x, pool_size, strides, padding=padding)
|
||||
else:
|
||||
raise Exception('Unknown dim_ordering: ' + str(dim_ordering))
|
||||
|
||||
if _FLOATX == 'float64':
|
||||
x = tf.cast(x, 'float64')
|
||||
return x
|
||||
|
||||
|
||||
# RANDOMNESS
|
||||
|
||||
def random_normal(shape, mean=0.0, std=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
return tf.random_normal(shape, mean=mean, stddev=std,
|
||||
dtype=dtype, seed=seed)
|
||||
|
||||
|
||||
def random_uniform(shape, low=0.0, high=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
return tf.random_uniform(shape, minval=low, maxval=high,
|
||||
dtype=dtype, seed=seed)
|
||||
@@ -0,0 +1,622 @@
|
||||
import theano
|
||||
from theano import tensor as T
|
||||
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from theano.tensor.signal import downsample
|
||||
import numpy as np
|
||||
from .common import _FLOATX, _EPSILON
|
||||
|
||||
|
||||
# INTERNAL UTILS
|
||||
theano.config.floatX = _FLOATX
|
||||
|
||||
|
||||
def _on_gpu():
|
||||
'''Returns whether the session is set to
|
||||
run on GPU or not (i.e. on CPU).
|
||||
'''
|
||||
return theano.config.device[:3] == 'gpu'
|
||||
|
||||
|
||||
if _on_gpu():
|
||||
'''Import cuDNN only if running on GPU:
|
||||
not having Cuda install should not
|
||||
prevent from running the present code.
|
||||
'''
|
||||
from theano.sandbox.cuda import dnn
|
||||
|
||||
|
||||
# VARIABLE MANIPULATION
|
||||
|
||||
def variable(value, dtype=_FLOATX, name=None):
|
||||
'''Instantiate a tensor variable.
|
||||
'''
|
||||
value = np.asarray(value, dtype=dtype)
|
||||
return theano.shared(value=value, name=name, strict=False)
|
||||
|
||||
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
'''Instantiate an input data placeholder variable.
|
||||
'''
|
||||
if shape is None and ndim is None:
|
||||
raise Exception('Specify either a shape or ndim value.')
|
||||
if shape is not None:
|
||||
ndim = len(shape)
|
||||
if ndim == 0:
|
||||
return T.scalar(name=name, dtype=dtype)
|
||||
elif ndim == 1:
|
||||
return T.vector(name=name, dtype=dtype)
|
||||
elif ndim == 2:
|
||||
return T.matrix(name=name, dtype=dtype)
|
||||
elif ndim == 3:
|
||||
return T.tensor3(name=name, dtype=dtype)
|
||||
elif ndim == 4:
|
||||
return T.tensor4(name=name, dtype=dtype)
|
||||
else:
|
||||
raise Exception('ndim too large: ' + str(ndim))
|
||||
|
||||
|
||||
def shape(x):
|
||||
'''Return the shape of a tensor.
|
||||
|
||||
Warning: type returned will be different for
|
||||
Theano backend (Theano tensor type) and TF backend (TF TensorShape).
|
||||
'''
|
||||
return x.shape
|
||||
|
||||
|
||||
def ndim(x):
|
||||
return x.ndim
|
||||
|
||||
|
||||
def eval(x):
|
||||
'''Run a graph.
|
||||
'''
|
||||
return x.eval()
|
||||
|
||||
|
||||
def zeros(shape, dtype=_FLOATX, name=None):
|
||||
'''Instantiate an all-zeros variable.
|
||||
'''
|
||||
return variable(np.zeros(shape), dtype, name)
|
||||
|
||||
|
||||
def ones(shape, dtype=_FLOATX, name=None):
|
||||
'''Instantiate an all-ones variable.
|
||||
'''
|
||||
return variable(np.ones(shape), dtype, name)
|
||||
|
||||
|
||||
def ones_like(x):
|
||||
return T.ones_like(x)
|
||||
|
||||
|
||||
def zeros_like(x):
|
||||
return T.zeros_like(x)
|
||||
|
||||
|
||||
def count_params(x):
|
||||
'''Return number of scalars in a tensor.
|
||||
|
||||
Return: numpy integer.
|
||||
'''
|
||||
return np.prod(x.shape.eval())
|
||||
|
||||
|
||||
def cast(x, dtype):
|
||||
return T.cast(x, dtype)
|
||||
|
||||
|
||||
# LINEAR ALGEBRA
|
||||
|
||||
'''
|
||||
Assumed overridden:
|
||||
+, -, /, *, +=, -=, *=, /=
|
||||
'''
|
||||
|
||||
|
||||
def dot(x, y):
|
||||
return T.dot(x, y)
|
||||
|
||||
|
||||
def transpose(x):
|
||||
return T.transpose(x)
|
||||
|
||||
|
||||
def gather(reference, indices):
|
||||
'''reference: a tensor.
|
||||
indices: an int tensor of indices.
|
||||
|
||||
Return: a tensor of same type as reference.
|
||||
'''
|
||||
return reference[indices]
|
||||
|
||||
|
||||
# ELEMENT-WISE OPERATIONS
|
||||
|
||||
|
||||
def max(x, axis=None, keepdims=False):
|
||||
return T.max(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def min(x, axis=None, keepdims=False):
|
||||
return T.min(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def sum(x, axis=None, keepdims=False):
|
||||
'''Sum of the values in a tensor, alongside the specified axis.
|
||||
'''
|
||||
return T.sum(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def prod(x, axis=None, keepdims=False):
|
||||
'''Multiply the values in a tensor, alongside the specified axis.
|
||||
'''
|
||||
return T.prod(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def mean(x, axis=None, keepdims=False):
|
||||
return T.mean(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def std(x, axis=None, keepdims=False):
|
||||
return T.std(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def any(x, axis=None, keepdims=False):
|
||||
'''Bitwise reduction (logical OR).
|
||||
'''
|
||||
return T.any(x, axis=axis, keepdims=keepdims)
|
||||
|
||||
|
||||
def argmax(x, axis=-1):
|
||||
return T.argmax(x, axis=axis, keepdims=False)
|
||||
|
||||
|
||||
def argmin(x, axis=-1):
|
||||
return T.argmin(x, axis=axis, keepdims=False)
|
||||
|
||||
|
||||
def square(x):
|
||||
return T.sqr(x)
|
||||
|
||||
|
||||
def abs(x):
|
||||
return T.abs_(x)
|
||||
|
||||
|
||||
def sqrt(x):
|
||||
x = T.clip(x, 0., np.inf)
|
||||
return T.sqrt(x)
|
||||
|
||||
|
||||
def exp(x):
|
||||
return T.exp(x)
|
||||
|
||||
|
||||
def log(x):
|
||||
return T.log(x)
|
||||
|
||||
|
||||
def round(x):
|
||||
return T.round(x)
|
||||
|
||||
|
||||
def pow(x, a):
|
||||
return T.pow(x, a)
|
||||
|
||||
|
||||
def clip(x, min_value, max_value):
|
||||
if max_value < min_value:
|
||||
max_value = min_value
|
||||
return T.clip(x, min_value, max_value)
|
||||
|
||||
|
||||
def equal(x, y):
|
||||
return T.eq(x, y)
|
||||
|
||||
|
||||
def maximum(x, y):
|
||||
return T.maximum(x, y)
|
||||
|
||||
|
||||
def minimum(x, y):
|
||||
return T.minimum(x, y)
|
||||
|
||||
|
||||
# SHAPE OPERATIONS
|
||||
|
||||
def concatenate(tensors, axis=-1):
|
||||
return T.concatenate(tensors, axis=axis)
|
||||
|
||||
|
||||
def reshape(x, shape):
|
||||
return T.reshape(x, shape)
|
||||
|
||||
|
||||
def permute_dimensions(x, pattern):
|
||||
'''Transpose dimensions.
|
||||
|
||||
pattern should be a tuple or list of
|
||||
dimension indices, e.g. [0, 2, 1].
|
||||
'''
|
||||
pattern = tuple(pattern)
|
||||
return x.dimshuffle(pattern)
|
||||
|
||||
|
||||
def repeat(x, n):
|
||||
'''Repeat a 2D tensor:
|
||||
|
||||
if x has shape (samples, dim) and n=2,
|
||||
the output will have shape (samples, 2, dim)
|
||||
'''
|
||||
tensors = [x] * n
|
||||
stacked = T.stack(*tensors)
|
||||
return stacked.dimshuffle((1, 0, 2))
|
||||
|
||||
|
||||
def tile(x, n):
|
||||
return T.tile(x, n)
|
||||
|
||||
|
||||
def flatten(x):
|
||||
'''Turn a n-D tensor into a 2D tensor where
|
||||
the first dimension is conserved.
|
||||
'''
|
||||
x = T.reshape(x, (x.shape[0], T.prod(x.shape) // x.shape[0]))
|
||||
return x
|
||||
|
||||
|
||||
def expand_dims(x, dim=-1):
|
||||
'''Add a 1-sized dimension at index "dim".
|
||||
'''
|
||||
pattern = [i for i in range(x.type.ndim)]
|
||||
if dim < 0:
|
||||
if x.type.ndim == 0:
|
||||
dim = 0
|
||||
else:
|
||||
dim = dim % x.type.ndim + 1
|
||||
pattern.insert(dim, 'x')
|
||||
return x.dimshuffle(pattern)
|
||||
|
||||
|
||||
def squeeze(x, axis):
|
||||
'''Remove a 1-dimension from the tensor at index "axis".
|
||||
'''
|
||||
x = T.addbroadcast(x, axis)
|
||||
return T.squeeze(x)
|
||||
|
||||
|
||||
def temporal_padding(x, padding=1):
|
||||
'''Pad the middle dimension of a 3D tensor
|
||||
with "padding" zeros left and right.
|
||||
|
||||
Appologies for the inane API, but Theano makes this
|
||||
really hard.
|
||||
'''
|
||||
input_shape = x.shape
|
||||
output_shape = (input_shape[0],
|
||||
input_shape[1] + 2 * padding,
|
||||
input_shape[2])
|
||||
output = T.zeros(output_shape)
|
||||
return T.set_subtensor(output[:, padding:x.shape[1] + padding, :], x)
|
||||
|
||||
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
'''Pad the 2nd and 3rd dimensions of a 4D tensor
|
||||
with "padding[0]" and "padding[1]" (resp.) zeros left and right.
|
||||
'''
|
||||
input_shape = x.shape
|
||||
if dim_ordering == 'th':
|
||||
output_shape = (input_shape[0],
|
||||
input_shape[1],
|
||||
input_shape[2] + 2 * padding[0],
|
||||
input_shape[3] + 2 * padding[1])
|
||||
output = T.zeros(output_shape)
|
||||
indices = (slice(None),
|
||||
slice(None),
|
||||
slice(padding[0], input_shape[2] + padding[0]),
|
||||
slice(padding[1], input_shape[3] + padding[1]))
|
||||
|
||||
elif dim_ordering == 'tf':
|
||||
output_shape = (input_shape[0],
|
||||
input_shape[1] + 2 * padding[0],
|
||||
input_shape[2] + 2 * padding[1],
|
||||
input_shape[3])
|
||||
output = T.zeros(output_shape)
|
||||
indices = (slice(None),
|
||||
slice(padding[0], input_shape[1] + padding[0]),
|
||||
slice(padding[1], input_shape[2] + padding[1]),
|
||||
slice(None))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + dim_ordering)
|
||||
return T.set_subtensor(output[indices], x)
|
||||
|
||||
# VALUE MANIPULATION
|
||||
|
||||
|
||||
def get_value(x):
|
||||
if not hasattr(x, 'get_value'):
|
||||
raise Exception("'get_value() can only be called on a variable. " +
|
||||
"If you have an expression instead, use eval().")
|
||||
return x.get_value()
|
||||
|
||||
|
||||
def set_value(x, value):
|
||||
x.set_value(np.asarray(value, dtype=x.dtype))
|
||||
|
||||
|
||||
# GRAPH MANIPULATION
|
||||
|
||||
class Function(object):
|
||||
|
||||
def __init__(self, inputs, outputs, updates=[], **kwargs):
|
||||
self.function = theano.function(inputs, outputs, updates=updates,
|
||||
allow_input_downcast=True, **kwargs)
|
||||
|
||||
def __call__(self, inputs):
|
||||
return self.function(*inputs)
|
||||
|
||||
|
||||
def function(inputs, outputs, updates=[]):
|
||||
return Function(inputs, outputs, updates=updates)
|
||||
|
||||
|
||||
def gradients(loss, variables):
|
||||
return T.grad(loss, variables)
|
||||
|
||||
|
||||
# CONTROL FLOW
|
||||
|
||||
def rnn(step_function, inputs, initial_states,
|
||||
go_backwards=False, masking=True):
|
||||
'''Iterates over the time dimension of a tensor.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
inputs: tensor of temporal data of shape (samples, time, ...)
|
||||
(at least 3D).
|
||||
step_function:
|
||||
Parameters:
|
||||
input: tensor with shape (samples, ...) (no time dimension),
|
||||
representing input for the batch of samples at a certain
|
||||
time step.
|
||||
states: list of tensors.
|
||||
Returns:
|
||||
output: tensor with shape (samples, ...) (no time dimension),
|
||||
new_states: list of tensors, same length and shapes
|
||||
as 'states'.
|
||||
initial_states: tensor with shape (samples, ...) (no time dimension),
|
||||
containing the initial values for the states used in
|
||||
the step function.
|
||||
go_backwards: boolean. If True, do the iteration over
|
||||
the time dimension in reverse order.
|
||||
masking: boolean. If true, any input timestep inputs[s, i]
|
||||
that is all-zeros will be skipped (states will be passed to
|
||||
the next step unchanged) and the corresponding output will
|
||||
be all zeros.
|
||||
|
||||
Returns
|
||||
-------
|
||||
A tuple (last_output, outputs, new_states).
|
||||
last_output: the latest output of the rnn, of shape (samples, ...)
|
||||
outputs: tensor with shape (samples, time, ...) where each
|
||||
entry outputs[s, t] is the output of the step function
|
||||
at time t for sample s.
|
||||
new_states: list of tensors, latest states returned by
|
||||
the step function, of shape (samples, ...).
|
||||
'''
|
||||
inputs = inputs.dimshuffle((1, 0, 2))
|
||||
|
||||
def _step(*args):
|
||||
global single_result
|
||||
input = args[0]
|
||||
states = args[1:]
|
||||
output, new_states = step_function(input, states)
|
||||
if masking:
|
||||
# if all-zero input timestep, return
|
||||
# all-zero output and unchanged states
|
||||
switch = T.any(input)
|
||||
output = T.switch(switch, output, 0. * output)
|
||||
return_states = []
|
||||
for state, new_state in zip(states, new_states):
|
||||
return_states.append(T.switch(switch, new_state, state))
|
||||
return [output] + return_states
|
||||
else:
|
||||
return [output] + new_states
|
||||
|
||||
results, _ = theano.scan(
|
||||
_step,
|
||||
sequences=inputs,
|
||||
outputs_info=[None] + initial_states,
|
||||
go_backwards=go_backwards)
|
||||
|
||||
# deal with Theano API inconsistency
|
||||
if type(results) is list:
|
||||
outputs = results[0]
|
||||
states = results[1:]
|
||||
else:
|
||||
outputs = results
|
||||
states = []
|
||||
|
||||
outputs = T.squeeze(outputs)
|
||||
last_output = outputs[-1]
|
||||
|
||||
outputs = outputs.dimshuffle((1, 0, 2))
|
||||
states = [T.squeeze(state[-1]) for state in states]
|
||||
return last_output, outputs, states
|
||||
|
||||
|
||||
def switch(condition, then_expression, else_expression):
|
||||
'''condition: scalar tensor.
|
||||
'''
|
||||
return T.switch(condition, then_expression, else_expression)
|
||||
|
||||
|
||||
# NN OPERATIONS
|
||||
|
||||
def relu(x, alpha=0., max_value=None):
|
||||
x = T.nnet.relu(x, alpha)
|
||||
if max_value is not None:
|
||||
x = T.minimum(x, max_value)
|
||||
return x
|
||||
|
||||
|
||||
def softmax(x):
|
||||
return T.nnet.softmax(x)
|
||||
|
||||
|
||||
def softplus(x):
|
||||
return T.nnet.softplus(x)
|
||||
|
||||
|
||||
def categorical_crossentropy(output, target, from_logits=False):
|
||||
if from_logits:
|
||||
output = T.nnet.softmax(output)
|
||||
else:
|
||||
# scale preds so that the class probas of each sample sum to 1
|
||||
output /= output.sum(axis=-1, keepdims=True)
|
||||
# avoid numerical instability with _EPSILON clipping
|
||||
output = T.clip(output, _EPSILON, 1.0 - _EPSILON)
|
||||
return T.nnet.categorical_crossentropy(output, target)
|
||||
|
||||
|
||||
def binary_crossentropy(output, target, from_logits=False):
|
||||
if from_logits:
|
||||
output = T.nnet.sigmoid(output)
|
||||
# avoid numerical instability with _EPSILON clipping
|
||||
output = T.clip(output, _EPSILON, 1.0 - _EPSILON)
|
||||
return T.nnet.binary_crossentropy(output, target)
|
||||
|
||||
|
||||
def sigmoid(x):
|
||||
return T.nnet.sigmoid(x)
|
||||
|
||||
|
||||
def hard_sigmoid(x):
|
||||
return T.nnet.hard_sigmoid(x)
|
||||
|
||||
|
||||
def tanh(x):
|
||||
return T.tanh(x)
|
||||
|
||||
|
||||
def dropout(x, level, seed=None):
|
||||
if level < 0. or level >= 1:
|
||||
raise Exception('Dropout level must be in interval [0, 1[.')
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
retain_prob = 1. - level
|
||||
x *= rng.binomial(x.shape, p=retain_prob, dtype=x.dtype)
|
||||
x /= retain_prob
|
||||
return x
|
||||
|
||||
|
||||
# CONVOLUTIONS
|
||||
|
||||
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th'):
|
||||
'''
|
||||
Run on cuDNN if available.
|
||||
border_mode: string, "same" or "valid".
|
||||
'''
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
if dim_ordering == 'tf':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
x = x.dimshuffle((0, 3, 1, 2))
|
||||
kernel = kernel.dimshuffle((3, 2, 0, 1))
|
||||
|
||||
if _on_gpu() and dnn.dnn_available():
|
||||
if border_mode == 'same':
|
||||
assert(strides == (1, 1))
|
||||
pad_x = (kernel.shape[2] - strides[0]) // 2
|
||||
pad_y = (kernel.shape[3] - strides[1]) // 2
|
||||
conv_out = dnn.dnn_conv(img=x,
|
||||
kerns=kernel,
|
||||
border_mode=(pad_x, pad_y))
|
||||
else:
|
||||
conv_out = dnn.dnn_conv(img=x,
|
||||
kerns=kernel,
|
||||
border_mode=border_mode,
|
||||
subsample=strides)
|
||||
else:
|
||||
if border_mode == 'same':
|
||||
th_border_mode = 'full'
|
||||
assert(strides == (1, 1))
|
||||
elif border_mode == 'valid':
|
||||
th_border_mode = 'valid'
|
||||
else:
|
||||
raise Exception('Border mode not supported: ' + str(border_mode))
|
||||
|
||||
conv_out = T.nnet.conv.conv2d(x, kernel,
|
||||
border_mode=th_border_mode,
|
||||
subsample=strides)
|
||||
if border_mode == 'same':
|
||||
shift_x = (kernel.shape[2] - 1) // 2
|
||||
shift_y = (kernel.shape[3] - 1) // 2
|
||||
conv_out = conv_out[:, :,
|
||||
shift_x:x.shape[2] + shift_x,
|
||||
shift_y:x.shape[3] + shift_y]
|
||||
if dim_ordering == 'tf':
|
||||
conv_out = conv_out.dimshuffle((0, 2, 3, 1))
|
||||
return conv_out
|
||||
|
||||
|
||||
def maxpool2d(x, pool_size, strides=(1, 1), border_mode='valid',
|
||||
dim_ordering='th'):
|
||||
if border_mode == 'same':
|
||||
# TODO: add implementation for border_mode="same"
|
||||
raise Exception('border_mode="same" not supported with Theano.')
|
||||
elif border_mode == 'valid':
|
||||
ignore_border = True
|
||||
padding = (0, 0)
|
||||
else:
|
||||
raise Exception('Invalid border mode: ' + str(border_mode))
|
||||
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
if dim_ordering == 'tf':
|
||||
x = x.dimshuffle((0, 3, 1, 2))
|
||||
|
||||
pool_out = downsample.max_pool_2d(x,
|
||||
ds=pool_size,
|
||||
st=strides,
|
||||
ignore_border=ignore_border,
|
||||
padding=padding,
|
||||
mode='average_exc_pad')
|
||||
if dim_ordering == 'tf':
|
||||
pool_out = pool_out.dimshuffle((0, 2, 3, 1))
|
||||
return pool_out
|
||||
|
||||
|
||||
# RANDOMNESS
|
||||
|
||||
def random_normal(shape, mean=0.0, std=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.normal(size=shape, avg=mean, std=std, dtype=dtype)
|
||||
|
||||
|
||||
def random_uniform(shape, low=0.0, high=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.uniform(shape, low=low, high=high, dtype=dtype)
|
||||
|
||||
|
||||
|
||||
'''
|
||||
more TODO:
|
||||
|
||||
tensordot -> soon to be introduced in TF
|
||||
batched_tensordot -> reimplement
|
||||
'''
|
||||
+23
-4
@@ -2,7 +2,9 @@ from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import time, json, warnings
|
||||
import time
|
||||
import json
|
||||
import warnings
|
||||
|
||||
from collections import deque
|
||||
from .utils.generic_utils import Progbar
|
||||
@@ -173,14 +175,31 @@ class History(Callback):
|
||||
|
||||
|
||||
class ModelCheckpoint(Callback):
|
||||
def __init__(self, filepath, monitor='val_loss', verbose=0, save_best_only=False):
|
||||
def __init__(self, filepath, monitor='val_loss', verbose=0, save_best_only=False, mode='auto'):
|
||||
|
||||
super(Callback, self).__init__()
|
||||
self.monitor = monitor
|
||||
self.verbose = verbose
|
||||
self.filepath = filepath
|
||||
self.save_best_only = save_best_only
|
||||
self.best = np.Inf
|
||||
|
||||
if mode not in ['auto', 'min', 'max']:
|
||||
warnings.warn("ModelCheckpoint mode %s is unknown, fallback to auto mode" % (self.mode), RuntimeWarning)
|
||||
mode = 'auto'
|
||||
|
||||
if mode == "min":
|
||||
self.monitor_op = np.less
|
||||
self.best = np.Inf
|
||||
elif mode == "max":
|
||||
self.monitor_op = np.greater
|
||||
self.best = -np.Inf
|
||||
else:
|
||||
if "acc" in self.monitor:
|
||||
self.monitor_op = np.greater
|
||||
self.best = -np.Inf
|
||||
else:
|
||||
self.monitor_op = np.less
|
||||
self.best = np.Inf
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
filepath = self.filepath.format(epoch=epoch, **logs)
|
||||
@@ -189,7 +208,7 @@ class ModelCheckpoint(Callback):
|
||||
if current is None:
|
||||
warnings.warn("Can save best model only with %s available, skipping." % (self.monitor), RuntimeWarning)
|
||||
else:
|
||||
if current < self.best:
|
||||
if self.monitor_op(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, filepath))
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
from . import backend as K
|
||||
|
||||
|
||||
class Constraint(object):
|
||||
@@ -17,8 +15,8 @@ class MaxNorm(Constraint):
|
||||
self.m = m
|
||||
|
||||
def __call__(self, p):
|
||||
norms = T.sqrt(T.sum(T.sqr(p), axis=0))
|
||||
desired = T.clip(norms, 0, self.m)
|
||||
norms = K.sqrt(K.sum(K.square(p), axis=0))
|
||||
desired = K.clip(norms, 0, self.m)
|
||||
p = p * (desired / (1e-7 + norms))
|
||||
return p
|
||||
|
||||
@@ -29,14 +27,13 @@ class MaxNorm(Constraint):
|
||||
|
||||
class NonNeg(Constraint):
|
||||
def __call__(self, p):
|
||||
p = theano.shared(p)
|
||||
p *= T.ge(p, 0.)
|
||||
p *= K.cast(p >= 0., K.floatx())
|
||||
return p
|
||||
|
||||
|
||||
class UnitNorm(Constraint):
|
||||
def __call__(self, p):
|
||||
return p / T.sqrt(T.sum(p**2, axis=-1, keepdims=True))
|
||||
return p / K.sqrt(K.sum(K.square(p), axis=-1, keepdims=True))
|
||||
|
||||
identity = Constraint
|
||||
maxnorm = MaxNorm
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import tarfile, inspect, os
|
||||
import tarfile
|
||||
import os
|
||||
from six.moves.urllib.request import FancyURLopener
|
||||
|
||||
from ..utils.generic_utils import Progbar
|
||||
|
||||
|
||||
class ParanoidURLopener(FancyURLopener):
|
||||
def http_error_default(self, url, fp, errcode, errmsg, headers):
|
||||
raise Exception('URL fetch failure on {}: {} -- {}'.format(url, errcode, errmsg))
|
||||
def http_error_default(self, url, fp, errcode, errmsg, headers):
|
||||
raise Exception('URL fetch failure on {}: {} -- {}'.format(url, errcode, errmsg))
|
||||
|
||||
|
||||
def get_file(fname, origin, untar=False):
|
||||
datadir = os.path.expanduser(os.path.join('~', '.keras', 'datasets'))
|
||||
@@ -21,11 +24,8 @@ def get_file(fname, origin, untar=False):
|
||||
else:
|
||||
fpath = os.path.join(datadir, fname)
|
||||
|
||||
try:
|
||||
f = open(fpath)
|
||||
except:
|
||||
if not os.path.exists(fpath):
|
||||
print('Downloading data from', origin)
|
||||
|
||||
global progbar
|
||||
progbar = None
|
||||
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
from .utils.theano_utils import sharedX, shared_zeros, shared_ones
|
||||
from . import backend as K
|
||||
|
||||
|
||||
def get_fans(shape):
|
||||
@@ -13,11 +10,11 @@ def get_fans(shape):
|
||||
|
||||
|
||||
def uniform(shape, scale=0.05):
|
||||
return sharedX(np.random.uniform(low=-scale, high=scale, size=shape))
|
||||
return K.variable(np.random.uniform(low=-scale, high=scale, size=shape))
|
||||
|
||||
|
||||
def normal(shape, scale=0.05):
|
||||
return sharedX(np.random.randn(*shape) * scale)
|
||||
return K.variable(np.random.randn(*shape) * scale)
|
||||
|
||||
|
||||
def lecun_uniform(shape):
|
||||
@@ -66,22 +63,22 @@ def orthogonal(shape, scale=1.1):
|
||||
# pick the one with the correct shape
|
||||
q = u if u.shape == flat_shape else v
|
||||
q = q.reshape(shape)
|
||||
return sharedX(scale * q[:shape[0], :shape[1]])
|
||||
return K.variable(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]))
|
||||
return K.variable(scale * np.identity(shape[0]))
|
||||
|
||||
|
||||
def zero(shape):
|
||||
return shared_zeros(shape)
|
||||
return K.zeros(shape)
|
||||
|
||||
|
||||
def one(shape):
|
||||
return shared_ones(shape)
|
||||
return K.ones(shape)
|
||||
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
from .. import initializations
|
||||
from ..layers.core import Layer, MaskedLayer
|
||||
from ..utils.theano_utils import shared_zeros, shared_ones, sharedX
|
||||
import theano.tensor as T
|
||||
from .. import backend as K
|
||||
import numpy as np
|
||||
|
||||
|
||||
@@ -12,7 +11,7 @@ class LeakyReLU(MaskedLayer):
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
return T.nnet.relu(X, self.alpha)
|
||||
return K.relu(X, alpha=self.alpha)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -24,7 +23,8 @@ class LeakyReLU(MaskedLayer):
|
||||
class PReLU(MaskedLayer):
|
||||
'''
|
||||
Reference:
|
||||
Delving Deep into Rectifiers: Surpassing Human-Level Performance on ImageNet Classification
|
||||
Delving Deep into Rectifiers: Surpassing Human-Level
|
||||
Performance on ImageNet Classification
|
||||
http://arxiv.org/pdf/1502.01852v1.pdf
|
||||
'''
|
||||
def __init__(self, init='zero', weights=None, **kwargs):
|
||||
@@ -43,7 +43,7 @@ class PReLU(MaskedLayer):
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
pos = T.nnet.relu(X)
|
||||
pos = K.relu(X)
|
||||
neg = self.alphas * (X - abs(X)) * 0.5
|
||||
return pos + neg
|
||||
|
||||
@@ -54,12 +54,31 @@ class PReLU(MaskedLayer):
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class ELU(MaskedLayer):
|
||||
def __init__(self, alpha=1.0, **kwargs):
|
||||
super(ELU, self).__init__(**kwargs)
|
||||
self.alpha = alpha
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
pos = K.relu(X)
|
||||
neg = (X - abs(X)) * 0.5
|
||||
return pos + self.alpha * (K.exp(neg) - 1.)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"alpha": self.alpha}
|
||||
base_config = super(ELU, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class ParametricSoftplus(MaskedLayer):
|
||||
'''
|
||||
Parametric Softplus of the form: alpha * log(1 + exp(beta * X))
|
||||
|
||||
Reference:
|
||||
Inferring Nonlinear Neuronal Computation Based on Physiologically Plausible Inputs
|
||||
Inferring Nonlinear Neuronal Computation
|
||||
Based on Physiologically Plausible Inputs
|
||||
http://journals.plos.org/ploscompbiol/article?id=10.1371/journal.pcbi.1003143
|
||||
'''
|
||||
def __init__(self, alpha_init=0.2, beta_init=5.0,
|
||||
@@ -71,10 +90,9 @@ class ParametricSoftplus(MaskedLayer):
|
||||
|
||||
def build(self):
|
||||
input_shape = self.input_shape[1:]
|
||||
self.alphas = sharedX(self.alpha_init * np.ones(input_shape))
|
||||
self.betas = sharedX(self.beta_init * np.ones(input_shape))
|
||||
self.alphas = K.variable(self.alpha_init * np.ones(input_shape))
|
||||
self.betas = K.variable(self.beta_init * np.ones(input_shape))
|
||||
self.params = [self.alphas, self.betas]
|
||||
self.input_shape = input_shape
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
@@ -82,7 +100,7 @@ class ParametricSoftplus(MaskedLayer):
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
return T.nnet.softplus(self.betas * X) * self.alphas
|
||||
return K.softplus(self.betas * X) * self.alphas
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -106,7 +124,7 @@ class ThresholdedLinear(MaskedLayer):
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
return T.switch(abs(X) < self.theta, 0, X)
|
||||
return K.switch(K.abs(X) < self.theta, 0, X)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -129,7 +147,7 @@ class ThresholdedReLU(MaskedLayer):
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
return T.switch(X > self.theta, X, 0)
|
||||
return K.switch(X > self.theta, X, 0)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
|
||||
+175
-39
@@ -2,9 +2,9 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import theano.tensor as T
|
||||
from ..layers.core import Layer, Merge
|
||||
from ..utils.theano_utils import ndim_tensor
|
||||
from collections import OrderedDict
|
||||
from .. import backend as K
|
||||
from ..layers.core import Layer, Merge, Siamese, SiameseHead
|
||||
from six.moves import range
|
||||
|
||||
|
||||
@@ -20,11 +20,6 @@ class Sequential(Layer):
|
||||
|
||||
def __init__(self, layers=[]):
|
||||
self.layers = []
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
self.updates = []
|
||||
|
||||
for layer in layers:
|
||||
self.add(layer)
|
||||
|
||||
@@ -38,11 +33,37 @@ class Sequential(Layer):
|
||||
if not hasattr(self.layers[0], 'input'):
|
||||
self.set_input()
|
||||
|
||||
params, regularizers, constraints, updates = layer.get_params()
|
||||
self.params += params
|
||||
self.regularizers += regularizers
|
||||
self.constraints += constraints
|
||||
self.updates += updates
|
||||
@property
|
||||
def params(self):
|
||||
params = []
|
||||
for l in self.layers:
|
||||
if l.trainable:
|
||||
params += l.get_params()[0]
|
||||
return params
|
||||
|
||||
@property
|
||||
def regularizers(self):
|
||||
regularizers = []
|
||||
for l in self.layers:
|
||||
if l.trainable:
|
||||
regularizers += l.get_params()[1]
|
||||
return regularizers
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
constraints = []
|
||||
for l in self.layers:
|
||||
if l.trainable:
|
||||
constraints += l.get_params()[2]
|
||||
return constraints
|
||||
|
||||
@property
|
||||
def updates(self):
|
||||
updates = []
|
||||
for l in self.layers:
|
||||
if l.trainable:
|
||||
updates += l.get_params()[3]
|
||||
return updates
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
@@ -54,8 +75,8 @@ class Sequential(Layer):
|
||||
def set_input(self):
|
||||
for l in self.layers:
|
||||
if hasattr(l, 'input'):
|
||||
ndim = l.input.ndim
|
||||
self.layers[0].input = ndim_tensor(ndim)
|
||||
ndim = len(K.get_shape(l.input))
|
||||
self.layers[0].input = K.placeholder(ndim=ndim)
|
||||
break
|
||||
|
||||
def get_input(self, train=False):
|
||||
@@ -63,6 +84,10 @@ class Sequential(Layer):
|
||||
self.set_input()
|
||||
return self.layers[0].get_input(train)
|
||||
|
||||
@property
|
||||
def input_shape(self):
|
||||
return self.layers[0].input_shape
|
||||
|
||||
@property
|
||||
def input(self):
|
||||
return self.get_input()
|
||||
@@ -97,7 +122,6 @@ class Graph(Layer):
|
||||
when it has exactly one input and one output.
|
||||
|
||||
inherited from Layer:
|
||||
- get_params
|
||||
- get_output_mask
|
||||
- supports_masked_input
|
||||
- get_weights
|
||||
@@ -105,7 +129,7 @@ class Graph(Layer):
|
||||
'''
|
||||
def __init__(self):
|
||||
self.namespace = set() # strings
|
||||
self.nodes = {} # layer-like
|
||||
self.nodes = OrderedDict() # layer-like
|
||||
self.inputs = {} # layer-like
|
||||
self.input_order = [] # strings
|
||||
self.outputs = {} # layer-like
|
||||
@@ -114,11 +138,6 @@ class Graph(Layer):
|
||||
self.output_config = [] # dicts
|
||||
self.node_config = [] # dicts
|
||||
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
self.updates = []
|
||||
|
||||
@property
|
||||
def nb_input(self):
|
||||
return len(self.inputs)
|
||||
@@ -127,6 +146,38 @@ class Graph(Layer):
|
||||
def nb_output(self):
|
||||
return len(self.outputs)
|
||||
|
||||
@property
|
||||
def params(self):
|
||||
params = []
|
||||
for l in self.nodes.values():
|
||||
if l.trainable:
|
||||
params += l.get_params()[0]
|
||||
return params
|
||||
|
||||
@property
|
||||
def regularizers(self):
|
||||
regularizers = []
|
||||
for l in self.nodes.values():
|
||||
if l.trainable:
|
||||
regularizers += l.get_params()[1]
|
||||
return regularizers
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
constraints = []
|
||||
for l in self.nodes.values():
|
||||
if l.trainable:
|
||||
constraints += l.get_params()[2]
|
||||
return constraints
|
||||
|
||||
@property
|
||||
def updates(self):
|
||||
updates = []
|
||||
for l in self.nodes.values():
|
||||
if l.trainable:
|
||||
updates += l.get_params()[3]
|
||||
return updates
|
||||
|
||||
def set_previous(self, layer, connection_map={}):
|
||||
if self.nb_input != layer.nb_output:
|
||||
raise Exception('Cannot connect layers: input count does not match output count.')
|
||||
@@ -173,24 +224,23 @@ class Graph(Layer):
|
||||
self.input_order.append(name)
|
||||
layer = Layer() # empty layer
|
||||
layer.set_input_shape(input_shape)
|
||||
ndim = len(input_shape) + 1
|
||||
if dtype == 'float':
|
||||
layer.input = ndim_tensor(ndim)
|
||||
layer.input = K.placeholder(shape=layer.input_shape, name=name)
|
||||
else:
|
||||
if ndim == 2:
|
||||
layer.input = T.imatrix()
|
||||
if len(input_shape) == 1:
|
||||
layer.input = K.placeholder(shape=layer.input_shape,
|
||||
dtype='int32',
|
||||
name=name)
|
||||
else:
|
||||
raise Exception('Type "int" can only be used with ndim==2 (Embedding).')
|
||||
layer.input.name = name
|
||||
self.inputs[name] = layer
|
||||
self.input_config.append({'name': name,
|
||||
'input_shape': input_shape,
|
||||
'dtype': dtype})
|
||||
|
||||
def add_node(self, layer, name, input=None, inputs=[],
|
||||
merge_mode='concat', concat_axis=-1, create_output=False):
|
||||
if hasattr(layer, 'set_name'):
|
||||
layer.set_name(name)
|
||||
merge_mode='concat', concat_axis=-1, dot_axes=-1,
|
||||
create_output=False):
|
||||
if name in self.namespace:
|
||||
raise Exception('Duplicate node identifier: ' + name)
|
||||
if input:
|
||||
@@ -209,7 +259,8 @@ class Graph(Layer):
|
||||
to_merge.append(self.inputs[n])
|
||||
else:
|
||||
raise Exception('Unknown identifier: ' + n)
|
||||
merge = Merge(to_merge, mode=merge_mode, concat_axis=concat_axis)
|
||||
merge = Merge(to_merge, mode=merge_mode,
|
||||
concat_axis=concat_axis, dot_axes=dot_axes)
|
||||
layer.set_previous(merge)
|
||||
|
||||
self.namespace.add(name)
|
||||
@@ -219,18 +270,89 @@ class Graph(Layer):
|
||||
'inputs': inputs,
|
||||
'merge_mode': merge_mode,
|
||||
'concat_axis': concat_axis,
|
||||
'dot_axes': dot_axes,
|
||||
'create_output': create_output})
|
||||
params, regularizers, constraints, updates = layer.get_params()
|
||||
self.params += params
|
||||
self.regularizers += regularizers
|
||||
self.constraints += constraints
|
||||
self.updates += updates
|
||||
|
||||
if create_output:
|
||||
self.add_output(name, input=name)
|
||||
|
||||
def add_shared_node(self, layer, name, inputs=[], merge_mode=None,
|
||||
concat_axis=-1, dot_axes=-1, outputs=[],
|
||||
create_output=False):
|
||||
'''
|
||||
Used to shared / multi input-multi output node
|
||||
|
||||
Arguments
|
||||
------------
|
||||
layer - The layer to be shared across multiple inputs
|
||||
name - Name of the shared layer
|
||||
inputs - List of names of input nodes
|
||||
merge_mode - Similar to merge_mode argument of add_node()
|
||||
concat_axis - Similar to concat_axis argument of add_node()
|
||||
dot_axes - Similar to dot_axes argument of add_node()
|
||||
outputs - Names for output nodes. Used when merge_mode = None
|
||||
create_output - Similar to create_output argument of add_node().
|
||||
Output will be created only if merge_mode is given
|
||||
'''
|
||||
if name in self.namespace:
|
||||
raise Exception('Duplicate node identifier: ' + name)
|
||||
for o in outputs:
|
||||
if o in self.namespace:
|
||||
raise Exception('Duplicate node identifier: ' + o)
|
||||
if merge_mode:
|
||||
if merge_mode not in {'sum', 'ave', 'mul', 'dot', 'cos', 'concat', 'join'}:
|
||||
raise Eception("Invalid merge mode")
|
||||
layers = []
|
||||
for i in range(len(inputs)):
|
||||
input = inputs[i]
|
||||
if input in self.nodes:
|
||||
n = self.nodes[input]
|
||||
if n.__class__.__name__ == 'Siamese':
|
||||
if n.merge_mode is None:
|
||||
for j in range(len(n.inputs)):
|
||||
sh = SiameseHead(j)
|
||||
sh.previous = n
|
||||
layers.append(sh)
|
||||
else:
|
||||
layers.append(n)
|
||||
else:
|
||||
layers.append(n)
|
||||
elif input in self.inputs:
|
||||
n = self.inputs[input]
|
||||
layers.append(n)
|
||||
else:
|
||||
raise Exception('Unknown identifier: ' + input)
|
||||
s = Siamese(layer, layers, merge_mode, concat_axis=concat_axis, dot_axes=dot_axes)
|
||||
s.set_name(name)
|
||||
self.namespace.add(name)
|
||||
self.nodes[name] = s
|
||||
self.node_config.append({'name': name,
|
||||
'inputs': inputs,
|
||||
'merge_mode': merge_mode,
|
||||
'concat_axis': concat_axis,
|
||||
'dot_axes': dot_axes,
|
||||
'create_output': create_output if merge_mode else False})
|
||||
if not merge_mode:
|
||||
for i in range(len(outputs)):
|
||||
sh = SiameseHead(i)
|
||||
sh.previous = s
|
||||
sh_name = outputs[i]
|
||||
sh.set_name(sh_name)
|
||||
self.namespace.add(sh_name)
|
||||
self.nodes[sh_name] = sh
|
||||
self.node_config.append({'name': sh_name,
|
||||
'inputs': [s],
|
||||
'create_output': create_output})
|
||||
if create_output:
|
||||
self.add_output(sh_name, input=sh_name)
|
||||
|
||||
if create_output and merge_mode:
|
||||
if merge_mode == 'join':
|
||||
raise Exception("Output can not be of type OrderedDict")
|
||||
self.add_output(name, input=name)
|
||||
|
||||
def add_output(self, name, input=None, inputs=[],
|
||||
merge_mode='concat', concat_axis=-1):
|
||||
merge_mode='concat', concat_axis=-1, dot_axes=-1):
|
||||
if name in self.output_order:
|
||||
raise Exception('Duplicate output identifier: ' + name)
|
||||
if input:
|
||||
@@ -246,7 +368,8 @@ class Graph(Layer):
|
||||
if n not in self.nodes:
|
||||
raise Exception('Unknown identifier: ' + n)
|
||||
to_merge.append(self.nodes[n])
|
||||
merge = Merge(to_merge, mode=merge_mode, concat_axis=concat_axis)
|
||||
merge = Merge(to_merge, mode=merge_mode,
|
||||
concat_axis=concat_axis, dot_axes=dot_axes)
|
||||
self.outputs[name] = merge
|
||||
|
||||
self.output_order.append(name)
|
||||
@@ -254,7 +377,8 @@ class Graph(Layer):
|
||||
'input': input,
|
||||
'inputs': inputs,
|
||||
'merge_mode': merge_mode,
|
||||
'concat_axis': concat_axis})
|
||||
'concat_axis': concat_axis,
|
||||
'dot_axes': dot_axes})
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
@@ -267,3 +391,15 @@ class Graph(Layer):
|
||||
|
||||
def count_params(self):
|
||||
return sum([layer.count_params() for layer in self.nodes.values()])
|
||||
|
||||
def get_weights(self):
|
||||
weights = []
|
||||
for layer in self.nodes.values():
|
||||
weights += layer.get_weights()
|
||||
return weights
|
||||
|
||||
def set_weights(self, weights):
|
||||
for layer in self.nodes.values():
|
||||
nb_param = len(layer.get_weights())
|
||||
layer.set_weights(weights[:nb_param])
|
||||
weights = weights[nb_param:]
|
||||
|
||||
+174
-173
@@ -1,53 +1,22 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import
|
||||
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
from theano.tensor.signal import downsample
|
||||
|
||||
from .. import backend as K
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..utils.theano_utils import shared_zeros, on_gpu
|
||||
from ..layers.core import Layer
|
||||
|
||||
if on_gpu():
|
||||
from theano.sandbox.cuda import dnn
|
||||
|
||||
|
||||
def conv_output_length(input_length, filter_size, border_mode, stride):
|
||||
if input_length is None:
|
||||
return None
|
||||
assert border_mode in {'same', 'full', 'valid'}
|
||||
assert border_mode in {'same', 'valid'}
|
||||
if border_mode == 'same':
|
||||
output_length = input_length
|
||||
elif border_mode == 'full':
|
||||
output_length = input_length + filter_size - 1
|
||||
elif border_mode == 'valid':
|
||||
output_length = input_length - filter_size + 1
|
||||
return (output_length + stride - 1) // stride
|
||||
|
||||
|
||||
def pool_output_length(input_length, pool_size, ignore_border, stride):
|
||||
if input_length is None:
|
||||
return None
|
||||
if ignore_border:
|
||||
output_length = input_length - pool_size + 1
|
||||
output_length = (output_length + stride - 1) // stride
|
||||
else:
|
||||
if pool_size == input_length:
|
||||
output_length = min(input_length, stride - stride % 2)
|
||||
if output_length <= 0:
|
||||
output_length = 1
|
||||
elif stride >= pool_size:
|
||||
output_length = (input_length + stride - 1) // stride
|
||||
else:
|
||||
output_length = (input_length - pool_size + stride - 1) // stride
|
||||
if output_length <= 0:
|
||||
output_length = 1
|
||||
else:
|
||||
output_length += 1
|
||||
return output_length
|
||||
|
||||
|
||||
class Convolution1D(Layer):
|
||||
input_ndim = 3
|
||||
|
||||
@@ -55,14 +24,16 @@ class Convolution1D(Layer):
|
||||
init='uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample_length=1,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, input_length=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None, **kwargs):
|
||||
|
||||
if border_mode not in {'valid', 'full', 'same'}:
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution1D:', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
self.filter_length = filter_length
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
self.subsample_length = subsample_length
|
||||
|
||||
@@ -82,14 +53,14 @@ class Convolution1D(Layer):
|
||||
self.input_length = input_length
|
||||
if self.input_dim:
|
||||
kwargs['input_shape'] = (self.input_length, self.input_dim)
|
||||
self.input = K.placeholder(ndim=3)
|
||||
super(Convolution1D, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
input_dim = self.input_shape[2]
|
||||
self.input = T.tensor3()
|
||||
self.W_shape = (self.nb_filter, input_dim, self.filter_length, 1)
|
||||
self.W = self.init(self.W_shape)
|
||||
self.b = shared_zeros((self.nb_filter,))
|
||||
self.b = K.zeros((self.nb_filter,))
|
||||
self.params = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
|
||||
@@ -111,44 +82,23 @@ class Convolution1D(Layer):
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
length = conv_output_length(self.input_shape[1], self.filter_length, self.border_mode, self.subsample[0])
|
||||
length = conv_output_length(self.input_shape[1],
|
||||
self.filter_length,
|
||||
self.border_mode,
|
||||
self.subsample[0])
|
||||
return (self.input_shape[0], length, self.nb_filter)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
X = T.reshape(X, (X.shape[0], X.shape[1], X.shape[2], 1)).dimshuffle(0, 2, 1, 3)
|
||||
X = K.expand_dims(X, -1) # add a dimension of the right
|
||||
X = K.permute_dimensions(X, (0, 2, 1, 3))
|
||||
conv_out = K.conv2d(X, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode, dim_ordering='th')
|
||||
|
||||
border_mode = self.border_mode
|
||||
if on_gpu() and dnn.dnn_available():
|
||||
if border_mode == 'same':
|
||||
assert(self.subsample_length == 1)
|
||||
pad_x = (self.filter_length - self.subsample_length) // 2
|
||||
conv_out = dnn.dnn_conv(img=X,
|
||||
kerns=self.W,
|
||||
border_mode=(pad_x, 0))
|
||||
else:
|
||||
conv_out = dnn.dnn_conv(img=X,
|
||||
kerns=self.W,
|
||||
border_mode=border_mode,
|
||||
subsample=self.subsample)
|
||||
else:
|
||||
if border_mode == 'same':
|
||||
assert(self.subsample_length == 1)
|
||||
border_mode = 'full'
|
||||
|
||||
input_shape = self.input_shape
|
||||
image_shape = (input_shape[0], input_shape[2], input_shape[1], 1)
|
||||
conv_out = T.nnet.conv.conv2d(X, self.W,
|
||||
border_mode=border_mode,
|
||||
subsample=self.subsample,
|
||||
image_shape=image_shape,
|
||||
filter_shape=self.W_shape)
|
||||
if self.border_mode == 'same':
|
||||
shift_x = (self.filter_length - 1) // 2
|
||||
conv_out = conv_out[:, :, shift_x:X.shape[2] + shift_x, :]
|
||||
|
||||
output = self.activation(conv_out + self.b.dimshuffle('x', 0, 'x', 'x'))
|
||||
output = T.reshape(output, (output.shape[0], output.shape[1], output.shape[2])).dimshuffle(0, 2, 1)
|
||||
output = conv_out + K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
output = self.activation(output)
|
||||
output = K.squeeze(output, 3) # remove the dummy 3rd dimension
|
||||
output = K.permute_dimensions(output, (0, 2, 1))
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
@@ -175,19 +125,22 @@ class Convolution2D(Layer):
|
||||
|
||||
def __init__(self, nb_filter, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
border_mode='valid', subsample=(1, 1), dim_ordering='th',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, **kwargs):
|
||||
|
||||
if border_mode not in {'valid', 'full', 'same'}:
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution2D:', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
self.nb_row = nb_row
|
||||
self.nb_col = nb_col
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
self.subsample = tuple(subsample)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
|
||||
self.W_regularizer = regularizers.get(W_regularizer)
|
||||
self.b_regularizer = regularizers.get(b_regularizer)
|
||||
@@ -198,14 +151,20 @@ class Convolution2D(Layer):
|
||||
self.constraints = [self.W_constraint, self.b_constraint]
|
||||
|
||||
self.initial_weights = weights
|
||||
self.input = K.placeholder(ndim=4)
|
||||
super(Convolution2D, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
stack_size = self.input_shape[1]
|
||||
self.input = T.tensor4()
|
||||
self.W_shape = (self.nb_filter, stack_size, self.nb_row, self.nb_col)
|
||||
if self.dim_ordering == 'th':
|
||||
stack_size = self.input_shape[1]
|
||||
self.W_shape = (self.nb_filter, stack_size, self.nb_row, self.nb_col)
|
||||
elif self.dim_ordering == 'tf':
|
||||
stack_size = self.input_shape[3]
|
||||
self.W_shape = (self.nb_row, self.nb_col, stack_size, self.nb_filter)
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
self.W = self.init(self.W_shape)
|
||||
self.b = shared_zeros((self.nb_filter,))
|
||||
self.b = K.zeros((self.nb_filter,))
|
||||
self.params = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
|
||||
@@ -228,44 +187,36 @@ class Convolution2D(Layer):
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
rows = input_shape[2]
|
||||
cols = input_shape[3]
|
||||
rows = conv_output_length(rows, self.nb_row, self.border_mode, self.subsample[0])
|
||||
cols = conv_output_length(cols, self.nb_col, self.border_mode, self.subsample[1])
|
||||
return (input_shape[0], self.nb_filter, rows, cols)
|
||||
if self.dim_ordering == 'th':
|
||||
rows = input_shape[2]
|
||||
cols = input_shape[3]
|
||||
elif self.dim_ordering == 'tf':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
rows = conv_output_length(rows, self.nb_row,
|
||||
self.border_mode, self.subsample[0])
|
||||
cols = conv_output_length(cols, self.nb_col,
|
||||
self.border_mode, self.subsample[1])
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0], self.nb_filter, rows, cols)
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0], rows, cols, self.nb_filter)
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
border_mode = self.border_mode
|
||||
if on_gpu() and dnn.dnn_available():
|
||||
if border_mode == 'same':
|
||||
assert(self.subsample == (1, 1))
|
||||
pad_x = (self.nb_row - self.subsample[0]) // 2
|
||||
pad_y = (self.nb_col - self.subsample[1]) // 2
|
||||
conv_out = dnn.dnn_conv(img=X,
|
||||
kerns=self.W,
|
||||
border_mode=(pad_x, pad_y))
|
||||
else:
|
||||
conv_out = dnn.dnn_conv(img=X,
|
||||
kerns=self.W,
|
||||
border_mode=border_mode,
|
||||
subsample=self.subsample)
|
||||
else:
|
||||
if border_mode == 'same':
|
||||
border_mode = 'full'
|
||||
assert(self.subsample == (1, 1))
|
||||
conv_out = K.conv2d(X, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering)
|
||||
|
||||
conv_out = T.nnet.conv.conv2d(X, self.W,
|
||||
border_mode=border_mode,
|
||||
subsample=self.subsample,
|
||||
image_shape=self.input_shape,
|
||||
filter_shape=self.W_shape)
|
||||
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'))
|
||||
output = conv_out + K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -276,6 +227,7 @@ class Convolution2D(Layer):
|
||||
"activation": self.activation.__name__,
|
||||
"border_mode": self.border_mode,
|
||||
"subsample": self.subsample,
|
||||
"dim_ordering": self.dim_ordering,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"activity_regularizer": self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
@@ -288,36 +240,41 @@ class Convolution2D(Layer):
|
||||
class MaxPooling1D(Layer):
|
||||
input_ndim = 3
|
||||
|
||||
def __init__(self, pool_length=2, stride=None, ignore_border=True, **kwargs):
|
||||
def __init__(self, pool_length=2, stride=None,
|
||||
border_mode='valid', **kwargs):
|
||||
super(MaxPooling1D, self).__init__(**kwargs)
|
||||
if stride is None:
|
||||
stride = pool_length
|
||||
self.pool_length = pool_length
|
||||
self.stride = stride
|
||||
self.st = (self.stride, 1)
|
||||
|
||||
self.input = T.tensor3()
|
||||
self.input = K.placeholder(ndim=3)
|
||||
self.pool_size = (pool_length, 1)
|
||||
self.ignore_border = ignore_border
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
length = pool_output_length(input_shape[1], self.pool_length, self.ignore_border, self.stride)
|
||||
length = conv_output_length(input_shape[1], self.pool_length,
|
||||
self.border_mode, self.stride)
|
||||
return (input_shape[0], length, input_shape[2])
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
X = T.reshape(X, (X.shape[0], X.shape[1], X.shape[2], 1)).dimshuffle(0, 2, 1, 3)
|
||||
output = downsample.max_pool_2d(X, ds=self.pool_size, st=self.st, ignore_border=self.ignore_border)
|
||||
output = output.dimshuffle(0, 2, 1, 3)
|
||||
return T.reshape(output, (output.shape[0], output.shape[1], output.shape[2]))
|
||||
X = K.expand_dims(X, -1) # add dummy last dimension
|
||||
X = K.permute_dimensions(X, (0, 2, 1, 3))
|
||||
output = K.maxpool2d(X, pool_size=self.pool_size, strides=self.st,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='th')
|
||||
output = K.permute_dimensions(output, (0, 2, 1, 3))
|
||||
return K.squeeze(output, 3) # remove dummy last dimension
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"stride": self.stride,
|
||||
"pool_length": self.pool_length,
|
||||
"ignore_border": self.ignore_border}
|
||||
"border_mode": self.border_mode}
|
||||
base_config = super(MaxPooling1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -325,43 +282,68 @@ class MaxPooling1D(Layer):
|
||||
class MaxPooling2D(Layer):
|
||||
input_ndim = 4
|
||||
|
||||
def __init__(self, pool_size=(2, 2), stride=None, ignore_border=True, **kwargs):
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
super(MaxPooling2D, self).__init__(**kwargs)
|
||||
self.input = T.tensor4()
|
||||
self.input = K.placeholder(ndim=4)
|
||||
self.pool_size = tuple(pool_size)
|
||||
if stride is None:
|
||||
stride = self.pool_size
|
||||
self.stride = tuple(stride)
|
||||
self.ignore_border = ignore_border
|
||||
if strides is None:
|
||||
strides = self.pool_size
|
||||
self.strides = tuple(strides)
|
||||
assert border_mode in {'valid', 'same'}, 'border_mode must be in {valid, same}'
|
||||
self.border_mode = border_mode
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
rows = pool_output_length(input_shape[2], self.pool_size[0], self.ignore_border, self.stride[0])
|
||||
cols = pool_output_length(input_shape[3], self.pool_size[1], self.ignore_border, self.stride[1])
|
||||
return (input_shape[0], input_shape[1], rows, cols)
|
||||
if self.dim_ordering == 'th':
|
||||
rows = input_shape[2]
|
||||
cols = input_shape[3]
|
||||
elif self.dim_ordering == 'tf':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
rows = conv_output_length(rows, self.pool_size[0],
|
||||
self.border_mode, self.strides[0])
|
||||
cols = conv_output_length(cols, self.pool_size[1],
|
||||
self.border_mode, self.strides[1])
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0], input_shape[1], rows, cols)
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0], rows, cols, input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
output = downsample.max_pool_2d(X, ds=self.pool_size, st=self.stride, ignore_border=self.ignore_border)
|
||||
output = K.maxpool2d(X, pool_size=self.pool_size,
|
||||
strides=self.strides,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"pool_size": self.pool_size,
|
||||
"ignore_border": self.ignore_border,
|
||||
"stride": self.stride}
|
||||
"border_mode": self.border_mode,
|
||||
"strides": self.strides,
|
||||
"dim_ordering": self.dim_ordering}
|
||||
base_config = super(MaxPooling2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class UpSample1D(Layer):
|
||||
class UpSampling1D(Layer):
|
||||
input_ndim = 3
|
||||
|
||||
def __init__(self, length=2, **kwargs):
|
||||
super(UpSample1D, self).__init__(**kwargs)
|
||||
super(UpSampling1D, self).__init__(**kwargs)
|
||||
self.length = length
|
||||
self.input = T.tensor3()
|
||||
self.input = K.placeholder(ndim=3)
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
@@ -370,39 +352,58 @@ class UpSample1D(Layer):
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
output = theano.tensor.extra_ops.repeat(X, self.length, axis=1)
|
||||
output = K.concatenate([X] * self.length, axis=1)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"length": self.length}
|
||||
base_config = super(UpSample1D, self).get_config()
|
||||
base_config = super(UpSampling1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class UpSample2D(Layer):
|
||||
class UpSampling2D(Layer):
|
||||
input_ndim = 4
|
||||
|
||||
def __init__(self, size=(2, 2), **kwargs):
|
||||
super(UpSample2D, self).__init__(**kwargs)
|
||||
self.input = T.tensor4()
|
||||
def __init__(self, size=(2, 2), dim_ordering='th', **kwargs):
|
||||
super(UpSampling2D, self).__init__(**kwargs)
|
||||
self.input = K.placeholder(ndim=4)
|
||||
self.size = tuple(size)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
return (input_shape[0], input_shape[1], self.size[0] * input_shape[2], self.size[1] * input_shape[3])
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
self.size[0] * input_shape[2],
|
||||
self.size[1] * input_shape[3])
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0],
|
||||
self.size[0] * input_shape[1],
|
||||
self.size[1] * input_shape[2],
|
||||
input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
Y = theano.tensor.extra_ops.repeat(X, self.size[0], axis=2)
|
||||
output = theano.tensor.extra_ops.repeat(Y, self.size[1], axis=3)
|
||||
if self.dim_ordering == 'th':
|
||||
output = K.concatenate([X] * self.size[0], axis=2)
|
||||
output = K.concatenate([output] * self.size[1], axis=3)
|
||||
elif self.dim_ordering == 'tf':
|
||||
output = K.concatenate([X] * self.size[0], axis=1)
|
||||
output = K.concatenate([output] * self.size[1], axis=2)
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"size": self.size}
|
||||
base_config = super(UpSample2D, self).get_config()
|
||||
base_config = super(UpSampling2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
@@ -428,21 +429,18 @@ class ZeroPadding1D(Layer):
|
||||
def __init__(self, padding=1, **kwargs):
|
||||
super(ZeroPadding1D, self).__init__(**kwargs)
|
||||
self.padding = padding
|
||||
self.input = T.tensor3()
|
||||
self.input = K.placeholder(ndim=3)
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
return (input_shape[0], input_shape[1] + self.padding * 2, input_shape[2])
|
||||
return (input_shape[0],
|
||||
input_shape[1] + self.padding * 2,
|
||||
input_shape[2])
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
input_shape = X.shape
|
||||
output_shape = (input_shape[0],
|
||||
input_shape[1] + 2 * self.padding,
|
||||
input_shape[2])
|
||||
output = T.zeros(output_shape)
|
||||
return T.set_subtensor(output[:, self.padding:X.shape[1] + self.padding, :], X)
|
||||
return K.temporal_padding(X, padding=self.padding)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -452,15 +450,17 @@ class ZeroPadding1D(Layer):
|
||||
|
||||
|
||||
class ZeroPadding2D(Layer):
|
||||
"""Zero-padding layer for 1D input (e.g. temporal sequence).
|
||||
"""Zero-padding layer for 2D input (e.g. picture).
|
||||
|
||||
Input shape
|
||||
-----------
|
||||
4D tensor with shape (samples, depth, first_axis_to_pad, second_axis_to_pad)
|
||||
4D tensor with shape:
|
||||
(samples, depth, first_axis_to_pad, second_axis_to_pad)
|
||||
|
||||
Output shape
|
||||
------------
|
||||
4D tensor with shape (samples, depth, first_padded_axis, second_padded_axis)
|
||||
4D tensor with shape:
|
||||
(samples, depth, first_padded_axis, second_padded_axis)
|
||||
|
||||
Arguments
|
||||
---------
|
||||
@@ -470,32 +470,33 @@ class ZeroPadding2D(Layer):
|
||||
"""
|
||||
input_ndim = 4
|
||||
|
||||
def __init__(self, padding=(1, 1), **kwargs):
|
||||
def __init__(self, padding=(1, 1), dim_ordering='th', **kwargs):
|
||||
super(ZeroPadding2D, self).__init__(**kwargs)
|
||||
self.padding = tuple(padding)
|
||||
self.input = T.tensor4()
|
||||
self.input = K.placeholder(ndim=4)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
input_shape[2] + 2 * self.padding[0],
|
||||
input_shape[3] + 2 * self.padding[1])
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
input_shape[2] + 2 * self.padding[0],
|
||||
input_shape[3] + 2 * self.padding[1])
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0],
|
||||
input_shape[1] + 2 * self.padding[0],
|
||||
input_shape[2] + 2 * self.padding[1],
|
||||
input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
input_shape = X.shape
|
||||
output_shape = (input_shape[0],
|
||||
input_shape[1],
|
||||
input_shape[2] + 2 * self.padding[0],
|
||||
input_shape[3] + 2 * self.padding[1])
|
||||
output = T.zeros(output_shape)
|
||||
indices = (slice(None),
|
||||
slice(None),
|
||||
slice(self.padding[0], input_shape[2] + self.padding[0]),
|
||||
slice(self.padding[1], input_shape[3] + self.padding[1]))
|
||||
return T.set_subtensor(output[indices], X)
|
||||
return K.spatial_2d_padding(X, padding=self.padding,
|
||||
dim_ordering=self.dim_ordering)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
|
||||
+623
-67
@@ -1,28 +1,30 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from __future__ import absolute_import, division
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
|
||||
from collections import OrderedDict
|
||||
import copy
|
||||
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..utils.theano_utils import shared_zeros, floatX, ndim_tensor
|
||||
from ..utils.generic_utils import make_tuple
|
||||
from ..regularizers import ActivityRegularizer, Regularizer
|
||||
|
||||
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from six.moves import zip
|
||||
|
||||
from .. import backend as K
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..regularizers import ActivityRegularizer
|
||||
|
||||
import marshal
|
||||
import types
|
||||
import sys
|
||||
|
||||
|
||||
class Layer(object):
|
||||
def __init__(self, **kwargs):
|
||||
for kwarg in kwargs:
|
||||
assert kwarg in {'input_shape'}, "Keyword argument not understood: " + kwarg
|
||||
assert kwarg in {'input_shape', 'trainable'}, "Keyword argument not understood: " + kwarg
|
||||
if 'input_shape' in kwargs:
|
||||
self.set_input_shape(kwargs['input_shape'])
|
||||
if 'trainable' in kwargs:
|
||||
self._trainable = kwargs['trainable']
|
||||
if not hasattr(self, 'params'):
|
||||
self.params = []
|
||||
|
||||
@@ -45,6 +47,17 @@ class Layer(object):
|
||||
'''
|
||||
pass
|
||||
|
||||
@property
|
||||
def trainable(self):
|
||||
if hasattr(self, '_trainable'):
|
||||
return self._trainable
|
||||
else:
|
||||
return True
|
||||
|
||||
@trainable.setter
|
||||
def trainable(self, value):
|
||||
self._trainable = value
|
||||
|
||||
@property
|
||||
def nb_input(self):
|
||||
return 1
|
||||
@@ -73,7 +86,7 @@ class Layer(object):
|
||||
raise Exception('Invalid input shape - Layer expects input ndim=' +
|
||||
str(self.input_ndim) + ', was provided with input shape ' + str(input_shape))
|
||||
self._input_shape = input_shape
|
||||
self.input = ndim_tensor(len(self._input_shape))
|
||||
self.input = K.placeholder(shape=self._input_shape)
|
||||
self.build()
|
||||
|
||||
@property
|
||||
@@ -119,20 +132,22 @@ class Layer(object):
|
||||
assert len(self.params) == len(weights), 'Provided weight array does not match layer weights (' + \
|
||||
str(len(self.params)) + ' layer params vs. ' + str(len(weights)) + ' provided weights)'
|
||||
for p, w in zip(self.params, weights):
|
||||
if p.eval().shape != w.shape:
|
||||
raise Exception("Layer shape %s not compatible with weight shape %s." % (p.eval().shape, w.shape))
|
||||
p.set_value(floatX(w))
|
||||
if K.get_value(p).shape != w.shape:
|
||||
raise Exception("Layer shape %s not compatible with weight shape %s." % (K.get_value(p).shape, w.shape))
|
||||
K.set_value(p, w)
|
||||
|
||||
def get_weights(self):
|
||||
weights = []
|
||||
for p in self.params:
|
||||
weights.append(p.get_value())
|
||||
weights.append(K.get_value(p))
|
||||
return weights
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__}
|
||||
if hasattr(self, '_input_shape'):
|
||||
config['input_shape'] = self._input_shape[1:]
|
||||
if hasattr(self, '_trainable'):
|
||||
config['trainable'] = self._trainable
|
||||
return config
|
||||
|
||||
def get_params(self):
|
||||
@@ -160,18 +175,17 @@ class Layer(object):
|
||||
|
||||
return self.params, regularizers, consts, updates
|
||||
|
||||
def set_name(self, name):
|
||||
for i in range(len(self.params)):
|
||||
self.params[i].name = '%s_p%d' % (name, i)
|
||||
|
||||
def count_params(self):
|
||||
return sum([np.prod(p.shape.eval()) for p in self.params])
|
||||
return sum([K.count_params(p) for p in self.params])
|
||||
|
||||
|
||||
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()
|
||||
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
|
||||
@@ -183,8 +197,9 @@ class MaskedLayer(Layer):
|
||||
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'''
|
||||
''' 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)
|
||||
|
||||
|
||||
@@ -202,15 +217,19 @@ class Masking(MaskedLayer):
|
||||
def __init__(self, mask_value=0., **kwargs):
|
||||
super(Masking, self).__init__(**kwargs)
|
||||
self.mask_value = mask_value
|
||||
self.input = T.tensor3()
|
||||
self.input = K.placeholder(ndim=3)
|
||||
|
||||
def get_output_mask(self, train=False):
|
||||
if K._BACKEND == "tensorflow":
|
||||
raise Exception("Masking is Theano-only for the time being.")
|
||||
X = self.get_input(train)
|
||||
return T.any(T.ones_like(X) * (1. - T.eq(X, self.mask_value)), axis=-1)
|
||||
return K.any(K.ones_like(X) * (1. - K.equal(X, self.mask_value)),
|
||||
axis=-1)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
return X * T.shape_padright(T.any((1. - T.eq(X, self.mask_value)), axis=-1))
|
||||
return X * K.any((1. - K.equal(X, self.mask_value)),
|
||||
axis=-1, keepdims=True)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -221,7 +240,6 @@ class Masking(MaskedLayer):
|
||||
|
||||
class TimeDistributedMerge(Layer):
|
||||
'''Sum/multiply/average over the outputs of a TimeDistributed layer.
|
||||
|
||||
mode: {'sum', 'mul', 'ave'}
|
||||
Tensor input dimensions: (nb_sample, time, features)
|
||||
Tensor output dimensions: (nb_sample, features)
|
||||
@@ -242,13 +260,14 @@ class TimeDistributedMerge(Layer):
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
if self.mode == 'sum' or self.mode == 'ave':
|
||||
s = theano.tensor.sum(X, axis=1)
|
||||
if self.mode == 'ave':
|
||||
s /= X.shape[1]
|
||||
if self.mode == 'ave':
|
||||
s = K.mean(X, axis=1)
|
||||
return s
|
||||
if self.mode == 'sum':
|
||||
s = K.sum(X, axis=1)
|
||||
return s
|
||||
elif self.mode == 'mul':
|
||||
s = theano.tensor.mul(X, axis=1)
|
||||
s = K.prod(X, axis=1)
|
||||
return s
|
||||
else:
|
||||
raise Exception('Unknown merge mode')
|
||||
@@ -261,16 +280,63 @@ class TimeDistributedMerge(Layer):
|
||||
|
||||
|
||||
class Merge(Layer):
|
||||
def __init__(self, layers, mode='sum', concat_axis=-1):
|
||||
def __init__(self, layers, mode='sum', concat_axis=-1, dot_axes=-1):
|
||||
''' Merge the output of a list of layers or containers into a single tensor.
|
||||
mode: {'sum', 'mul', 'concat', 'ave'}
|
||||
mode: {'sum', 'mul', 'concat', 'ave', 'join'}
|
||||
'''
|
||||
if len(layers) < 2:
|
||||
raise Exception("Please specify two or more input layers (or containers) to merge")
|
||||
if mode not in {'sum', 'mul', 'concat', 'ave'}:
|
||||
|
||||
if mode not in {'sum', 'mul', 'concat', 'ave', 'join', 'cos', 'dot'}:
|
||||
raise Exception("Invalid merge mode: " + str(mode))
|
||||
|
||||
if mode in {'sum', 'mul', 'ave', 'cos'}:
|
||||
input_shapes = set([l.output_shape for l in layers])
|
||||
if len(input_shapes) > 1:
|
||||
raise Exception("Only layers of same output shape can be merged using " + mode + " mode. " +
|
||||
"Layer shapes: %s" % ([l.output_shape for l in layers]))
|
||||
if mode in {'cos', 'dot'}:
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception('"' + mode + '" merge mode will only work with Theano.')
|
||||
|
||||
if len(layers) > 2:
|
||||
raise Exception(mode + " merge takes exactly 2 layers")
|
||||
shape1 = layers[0].output_shape
|
||||
shape2 = layers[1].output_shape
|
||||
n1 = len(shape1)
|
||||
n2 = len(shape2)
|
||||
if mode == 'dot':
|
||||
if type(dot_axes) == int:
|
||||
if dot_axes < 0:
|
||||
dot_axes = [range(dot_axes % n1, n1), range(dot_axes % n2, n2)]
|
||||
else:
|
||||
dot_axes = [range(n1 - dot_axes, n2), range(1, dot_axes + 1)]
|
||||
if type(dot_axes) not in [list, tuple]:
|
||||
raise Exception("Invalid type for dot_axes - should be a list.")
|
||||
if len(dot_axes) != 2:
|
||||
raise Exception("Invalid format for dot_axes - should contain two elements.")
|
||||
if type(dot_axes[0]) not in [list, tuple, range] or type(dot_axes[1]) not in [list, tuple, range]:
|
||||
raise Exception("Invalid format for dot_axes - list elements should have type 'list' or 'tuple'.")
|
||||
for i in range(len(dot_axes[0])):
|
||||
if shape1[dot_axes[0][i]] != shape2[dot_axes[1][i]]:
|
||||
raise Exception("Dimension incompatibility using dot mode: " +
|
||||
"%s != %s. " % (shape1[dot_axes[0][i]], shape2[dot_axes[1][i]]) +
|
||||
"Layer shapes: %s, %s" % (shape1, shape2))
|
||||
elif mode == 'concat':
|
||||
input_shapes = set()
|
||||
for l in layers:
|
||||
oshape = list(l.output_shape)
|
||||
oshape.pop(concat_axis)
|
||||
oshape = tuple(oshape)
|
||||
input_shapes.add(oshape)
|
||||
if len(input_shapes) > 1:
|
||||
raise Exception("'concat' mode can only merge layers with matching " +
|
||||
"output shapes except for the concat axis. " +
|
||||
"Layer shapes: %s" % ([l.output_shape for l in layers]))
|
||||
|
||||
self.mode = mode
|
||||
self.concat_axis = concat_axis
|
||||
self.dot_axes = dot_axes
|
||||
self.layers = layers
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
@@ -296,6 +362,24 @@ class Merge(Layer):
|
||||
for shape in input_shapes[1:]:
|
||||
output_shape[self.concat_axis] += shape[self.concat_axis]
|
||||
return tuple(output_shape)
|
||||
elif self.mode == 'join':
|
||||
return None
|
||||
elif self.mode == 'dot':
|
||||
shape1 = list(input_shapes[0])
|
||||
shape2 = list(input_shapes[1])
|
||||
dot_axes = []
|
||||
for axes in self.dot_axes:
|
||||
dot_axes.append([index-1 for index in axes])
|
||||
tensordot_output = np.tensordot(np.zeros(tuple(shape1[1:])),
|
||||
np.zeros(tuple(shape2[1:])),
|
||||
axes=dot_axes)
|
||||
if len(tensordot_output.shape) == 0:
|
||||
shape = (1,)
|
||||
else:
|
||||
shape = tensordot_output.shape
|
||||
return (shape1[0],) + shape
|
||||
elif self.mode == 'cos':
|
||||
return tuple(input_shapes[0][0], 1)
|
||||
|
||||
def get_params(self):
|
||||
return self.params, self.regularizers, self.constraints, self.updates
|
||||
@@ -310,7 +394,7 @@ class Merge(Layer):
|
||||
return s
|
||||
elif self.mode == 'concat':
|
||||
inputs = [self.layers[i].get_output(train) for i in range(len(self.layers))]
|
||||
return T.concatenate(inputs, axis=self.concat_axis)
|
||||
return K.concatenate(inputs, axis=self.concat_axis)
|
||||
elif self.mode == 'join':
|
||||
inputs = OrderedDict()
|
||||
for i in range(len(self.layers)):
|
||||
@@ -318,13 +402,34 @@ class Merge(Layer):
|
||||
if X.name is None:
|
||||
raise ValueError("merge_mode='join' only works with named inputs")
|
||||
else:
|
||||
inputs[X.name] = self.layers[i].get_output(train)
|
||||
inputs[X.name] = X
|
||||
return inputs
|
||||
elif self.mode == 'mul':
|
||||
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 == 'dot':
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception('"dot" merge mode will only work with Theano.')
|
||||
from theano import tensor as T
|
||||
l1 = self.layers[0].get_output(train)
|
||||
l2 = self.layers[1].get_output(train)
|
||||
output = T.batched_tensordot(l1, l2, self.dot_axes)
|
||||
output_shape = list(self.output_shape)
|
||||
output_shape[0] = l1.shape[0]
|
||||
output = output.reshape(tuple(output_shape))
|
||||
return output
|
||||
elif self.mode == 'cos':
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception('"dot" merge mode will only work with Theano.')
|
||||
import theano
|
||||
l1 = self.layers[0].get_output(train)
|
||||
l2 = self.layers[1].get_output(train)
|
||||
output, _ = theano.scan(lambda v1, v2: K.dot(v1, v2) / K.sqrt(K.dot(v1, v1) * K.dot(v2, v2)),
|
||||
sequences=[l1, l2],
|
||||
outputs_info=None)
|
||||
return output
|
||||
else:
|
||||
raise Exception('Unknown merge mode')
|
||||
|
||||
@@ -365,7 +470,8 @@ class Merge(Layer):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"layers": [l.get_config() for l in self.layers],
|
||||
"mode": self.mode,
|
||||
"concat_axis": self.concat_axis}
|
||||
"concat_axis": self.concat_axis,
|
||||
"dot_axes": self.dot_axes}
|
||||
base_config = super(Merge, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -377,16 +483,12 @@ class Dropout(MaskedLayer):
|
||||
def __init__(self, p, **kwargs):
|
||||
super(Dropout, self).__init__(**kwargs)
|
||||
self.p = p
|
||||
self.srng = RandomStreams(seed=np.random.randint(10e6))
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
if self.p > 0.:
|
||||
retain_prob = 1. - self.p
|
||||
if train:
|
||||
X *= self.srng.binomial(X.shape, p=retain_prob, dtype=theano.config.floatX)
|
||||
else:
|
||||
X *= retain_prob
|
||||
X = K.dropout(X, level=self.p)
|
||||
return X
|
||||
|
||||
def get_config(self):
|
||||
@@ -435,8 +537,7 @@ class Reshape(Layer):
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
new_shape = (X.shape[0],) + self.dims
|
||||
return theano.tensor.reshape(X, new_shape)
|
||||
return K.reshape(X, (-1,) + self.dims)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -464,7 +565,7 @@ class Permute(Layer):
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
return X.dimshuffle((0,) + self.dims)
|
||||
return K.permute_dimensions(X, (0,) + self.dims)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -488,9 +589,7 @@ class Flatten(Layer):
|
||||
|
||||
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)
|
||||
return theano.tensor.reshape(X, nshape)
|
||||
return K.flatten(X)
|
||||
|
||||
|
||||
class RepeatVector(Layer):
|
||||
@@ -511,9 +610,7 @@ class RepeatVector(Layer):
|
||||
|
||||
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 K.repeat(X, self.n)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -548,14 +645,14 @@ class Dense(Layer):
|
||||
self.input_dim = input_dim
|
||||
if self.input_dim:
|
||||
kwargs['input_shape'] = (self.input_dim,)
|
||||
self.input = K.placeholder(ndim=2)
|
||||
super(Dense, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
input_dim = self.input_shape[1]
|
||||
|
||||
self.input = T.matrix()
|
||||
self.W = self.init((input_dim, self.output_dim))
|
||||
self.b = shared_zeros((self.output_dim,))
|
||||
self.b = K.zeros((self.output_dim,))
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
|
||||
@@ -582,7 +679,7 @@ class Dense(Layer):
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
output = self.activation(T.dot(X, self.W) + self.b)
|
||||
output = self.activation(K.dot(X, self.W) + self.b)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
@@ -635,9 +732,11 @@ class TimeDistributedDense(MaskedLayer):
|
||||
'''
|
||||
input_ndim = 3
|
||||
|
||||
def __init__(self, output_dim, init='glorot_uniform', activation='linear', weights=None,
|
||||
def __init__(self, output_dim,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, input_length=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None, **kwargs):
|
||||
self.output_dim = output_dim
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
@@ -656,14 +755,14 @@ class TimeDistributedDense(MaskedLayer):
|
||||
self.input_length = input_length
|
||||
if self.input_dim:
|
||||
kwargs['input_shape'] = (self.input_length, self.input_dim)
|
||||
self.input = K.placeholder(ndim=3)
|
||||
super(TimeDistributedDense, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
input_dim = self.input_shape[2]
|
||||
|
||||
self.input = T.tensor3()
|
||||
self.W = self.init((input_dim, self.output_dim))
|
||||
self.b = shared_zeros((self.output_dim))
|
||||
self.b = K.zeros((self.output_dim))
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
@@ -691,8 +790,14 @@ class TimeDistributedDense(MaskedLayer):
|
||||
|
||||
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 step(x, states):
|
||||
output = K.dot(x, self.W) + self.b
|
||||
return output, []
|
||||
|
||||
last_output, outputs, states = K.rnn(step, X, [], masking=False)
|
||||
outputs = self.activation(outputs)
|
||||
return outputs
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -771,7 +876,7 @@ class AutoEncoder(Layer):
|
||||
|
||||
@property
|
||||
def input_shape(self):
|
||||
self.encoder.previous.output_shape
|
||||
return self.encoder.input_shape
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
@@ -819,14 +924,14 @@ class MaxoutDense(Layer):
|
||||
self.input_dim = input_dim
|
||||
if self.input_dim:
|
||||
kwargs['input_shape'] = (self.input_dim,)
|
||||
self.input = K.placeholder(ndim=2)
|
||||
super(MaxoutDense, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
input_dim = self.input_shape[1]
|
||||
|
||||
self.input = T.matrix()
|
||||
self.W = self.init((self.nb_feature, input_dim, self.output_dim))
|
||||
self.b = shared_zeros((self.nb_feature, self.output_dim))
|
||||
self.b = K.zeros((self.nb_feature, self.output_dim))
|
||||
|
||||
self.params = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
@@ -854,7 +959,7 @@ class MaxoutDense(Layer):
|
||||
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)
|
||||
output = K.max(K.dot(X, self.W) + self.b, axis=1)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
@@ -870,3 +975,454 @@ class MaxoutDense(Layer):
|
||||
"input_dim": self.input_dim}
|
||||
base_config = super(MaxoutDense, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Lambda(Layer):
|
||||
"""Lambda layer for evaluating arbitrary function
|
||||
|
||||
Input shape
|
||||
-----------
|
||||
output_shape of previous layer
|
||||
|
||||
Output shape
|
||||
------------
|
||||
Specified by output_shape argument
|
||||
|
||||
Arguments
|
||||
---------
|
||||
function - The function to be evaluated. Takes one argument : output of previous layer
|
||||
output_shape - Expected output shape from function. Could be a tuple or a function of the shape of the input
|
||||
"""
|
||||
|
||||
def __init__(self, function, output_shape=None, **kwargs):
|
||||
super(Lambda, self).__init__(**kwargs)
|
||||
py3 = sys.version_info[0] == 3
|
||||
if py3:
|
||||
self.function = marshal.dumps(function.__code__)
|
||||
else:
|
||||
self.function = marshal.dumps(function.func_code)
|
||||
if output_shape is None:
|
||||
self._output_shape = None
|
||||
elif type(output_shape) in {tuple, list} :
|
||||
self._output_shape = tuple(output_shape)
|
||||
else:
|
||||
if py3:
|
||||
self._output_shape = marshal.dumps(output_shape.__code__)
|
||||
else:
|
||||
self._output_shape = marshal.dumps(output_shape.func_code)
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
if self._output_shape is None:
|
||||
return self.input_shape
|
||||
elif type(self._output_shape) == tuple:
|
||||
return (self.input_shape[0], ) + self._output_shape
|
||||
else:
|
||||
output_shape_func = marshal.loads(self._output_shape)
|
||||
output_shape_func = types.FunctionType(output_shape_func, globals())
|
||||
shape = output_shape_func(self.previous.output_shape)
|
||||
if type(shape) not in {list, tuple}:
|
||||
raise Exception("output_shape function must return a tuple")
|
||||
return tuple(shape)
|
||||
|
||||
def get_output(self, train=False):
|
||||
func = marshal.loads(self.function)
|
||||
func = types.FunctionType(func, globals())
|
||||
if hasattr(self, 'previous'):
|
||||
return func(self.previous.get_output(train))
|
||||
else:
|
||||
return func(self.input)
|
||||
|
||||
|
||||
class MaskedLambda(MaskedLayer, Lambda):
|
||||
pass
|
||||
|
||||
|
||||
class LambdaMerge(Lambda):
|
||||
"""LambdaMerge layer for evaluating arbitrary function over multiple inputs
|
||||
|
||||
Input shape
|
||||
-----------
|
||||
None
|
||||
|
||||
Output shape
|
||||
------------
|
||||
Specified by output_shape argument
|
||||
|
||||
Arguments
|
||||
---------
|
||||
layers - Input layers. Similar to layers argument of Merge
|
||||
function - The function to be evaluated. Takes one argument:
|
||||
list of outputs from input layers
|
||||
output_shape - Expected output shape from function.
|
||||
Could be a tuple or a function of list of input shapes
|
||||
"""
|
||||
def __init__(self, layers, function, output_shape=None):
|
||||
if len(layers) < 2:
|
||||
raise Exception("Please specify two or more input layers (or containers) to merge")
|
||||
self.layers = layers
|
||||
self.params = []
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
self.updates = []
|
||||
for l in self.layers:
|
||||
params, regs, consts, updates = l.get_params()
|
||||
self.regularizers += regs
|
||||
self.updates += updates
|
||||
# params and constraints have the same size
|
||||
for p, c in zip(params, consts):
|
||||
if p not in self.params:
|
||||
self.params.append(p)
|
||||
self.constraints.append(c)
|
||||
py3 = sys.version_info[0] == 3
|
||||
if py3:
|
||||
self.function = marshal.dumps(function.__code__)
|
||||
else:
|
||||
self.function = marshal.dumps(function.func_code)
|
||||
if output_shape is None:
|
||||
self._output_shape = None
|
||||
elif type(output_shape) in {tuple, list}:
|
||||
self._output_shape = tuple(output_shape)
|
||||
else:
|
||||
if py3:
|
||||
self._output_shape = marshal.dumps(output_shape.__code__)
|
||||
else:
|
||||
self._output_shape = marshal.dumps(output_shape.func_code)
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shapes = [layer.output_shape for layer in self.layers]
|
||||
if self._output_shape is None:
|
||||
return input_shapes[0]
|
||||
elif type(self._output_shape) == tuple:
|
||||
return (input_shapes[0][0], ) + self._output_shape
|
||||
else:
|
||||
output_shape_func = marshal.loads(self._output_shape)
|
||||
output_shape_func = types.FunctionType(output_shape_func, globals())
|
||||
shape = output_shape_func(input_shapes)
|
||||
if type(shape) not in {list, tuple}:
|
||||
raise Exception("output_shape function must return a tuple")
|
||||
return tuple(shape)
|
||||
|
||||
def get_params(self):
|
||||
return self.params, self.regularizers, self.constraints, self.updates
|
||||
|
||||
def get_output(self, train=False):
|
||||
func = marshal.loads(self.function)
|
||||
func = types.FunctionType(func, globals())
|
||||
inputs = [layer.get_output(train) for layer in self.layers]
|
||||
return func(inputs)
|
||||
|
||||
def get_input(self, train=False):
|
||||
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 l in self.layers:
|
||||
weights += l.get_weights()
|
||||
return weights
|
||||
|
||||
def set_weights(self, weights):
|
||||
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):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"layers": [l.get_config() for l in self.layers],
|
||||
"function": self.function,
|
||||
"output_shape": self._output_shape
|
||||
}
|
||||
base_config = super(LambdaMerge, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Siamese(Layer):
|
||||
'''Shared layer with multiple inputs
|
||||
|
||||
Output shape
|
||||
------------
|
||||
Depends on merge_mode argument
|
||||
|
||||
Arguments
|
||||
---------
|
||||
layer - The layer to be shared across multiple inputs
|
||||
inputs - inputs to the shared layer
|
||||
merge_mode - Similar to mode argument of Merge layer
|
||||
concat_axis - Similar to concat_axis argument of Merge layer
|
||||
dot_axes - Similar to dot_axes argument of Merge layer
|
||||
'''
|
||||
def __init__(self, layer, inputs, merge_mode='concat',
|
||||
concat_axis=1, dot_axes=-1):
|
||||
if merge_mode not in ['sum', 'mul', 'concat', 'ave',
|
||||
'join', 'cos', 'dot', None]:
|
||||
raise Exception("Invalid merge mode: " + str(merge_mode))
|
||||
|
||||
if merge_mode in {'cos', 'dot'}:
|
||||
if len(inputs) > 2:
|
||||
raise Exception(merge_mode + " merge takes exactly 2 layers")
|
||||
|
||||
self.layer = layer
|
||||
self.inputs = inputs
|
||||
self.params = []
|
||||
self.merge_mode = merge_mode
|
||||
self.concat_axis = concat_axis
|
||||
self.dot_axes = dot_axes
|
||||
layer.set_previous(inputs[0])
|
||||
self.regularizers = []
|
||||
self.constraints = []
|
||||
self.updates = []
|
||||
layers = [layer]
|
||||
if merge_mode:
|
||||
layers += inputs
|
||||
for l in layers:
|
||||
params, regs, consts, updates = l.get_params()
|
||||
self.regularizers += regs
|
||||
self.updates += updates
|
||||
# params and constraints have the same size
|
||||
for p, c in zip(params, consts):
|
||||
if p not in self.params:
|
||||
self.params.append(p)
|
||||
self.constraints.append(c)
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
if self.merge_mode is None:
|
||||
return self.layer.output_shape
|
||||
input_shapes = [self.get_output_shape(i) for i in range(len(self.inputs))]
|
||||
|
||||
if self.merge_mode in ['sum', 'mul', 'ave']:
|
||||
return input_shapes[0]
|
||||
|
||||
elif self.merge_mode == 'concat':
|
||||
output_shape = list(input_shapes[0])
|
||||
for shape in input_shapes[1:]:
|
||||
output_shape[self.concat_axis] += shape[self.concat_axis]
|
||||
return tuple(output_shape)
|
||||
|
||||
elif self.merge_mode == 'join':
|
||||
return None
|
||||
|
||||
elif self.merge_mode == 'dot':
|
||||
shape1 = list(input_shapes[0])
|
||||
shape2 = list(input_shapes[1])
|
||||
for i in self.dot_axes[0]:
|
||||
shape1.pop(i)
|
||||
for i in self.dot_axes[1]:
|
||||
shape2.pop(i)
|
||||
shape = shape1 + shape2[1:]
|
||||
if len(shape) == 1:
|
||||
shape.append(1)
|
||||
return tuple(shape)
|
||||
|
||||
elif self.merge_mode == 'cos':
|
||||
return tuple(input_shapes[0][0], 1)
|
||||
|
||||
def get_params(self):
|
||||
return self.params, self.regularizers, self.constraints, self.updates
|
||||
|
||||
def set_layer_input(self, index):
|
||||
l = self.layer
|
||||
while not hasattr(l, 'previous'):
|
||||
l = l.layers[0]
|
||||
l.previous = self.inputs[index]
|
||||
|
||||
def get_output_at(self, head, train=False):
|
||||
self.set_layer_input(head)
|
||||
return self.layer.get_output(train)
|
||||
|
||||
def get_output_shape(self, head, train=False):
|
||||
self.set_layer_input(head)
|
||||
return self.layer.output_shape
|
||||
|
||||
def get_output_join(self, train=False):
|
||||
o = OrderedDict()
|
||||
for i in range(len(self.inputs)):
|
||||
X = self.get_output_at(i, train)
|
||||
if X.name is None:
|
||||
raise ValueError("merge_mode='join' only works with named inputs")
|
||||
o[X.name] = X
|
||||
return o
|
||||
|
||||
def get_output_sum(self, train=False):
|
||||
s = self.get_output_at(0, train)
|
||||
for i in range(1, len(self.inputs)):
|
||||
s += self.get_output_at(i, train)
|
||||
return s
|
||||
|
||||
def get_output_ave(self, train=False):
|
||||
n = len(self.inputs)
|
||||
s = self.get_output_at(0, train)
|
||||
for i in range(1, n):
|
||||
s += self.get_output_at(i, train)
|
||||
s /= n
|
||||
return s
|
||||
|
||||
def get_output_concat(self, train=False):
|
||||
inputs = [self.get_output_at(i, train) for i in range(len(self.inputs))]
|
||||
return K.concatenate(inputs, axis=self.concat_axis)
|
||||
|
||||
def get_output_mul(self, train=False):
|
||||
s = self.get_output_at(0, train)
|
||||
for i in range(1, len(self.inputs)):
|
||||
s *= self.get_output_at(i, train)
|
||||
return s
|
||||
|
||||
def get_output_dot(self, train=False):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception('"dot" merge mode will only work with Theano.')
|
||||
from theano import tensor as T
|
||||
l1 = self.get_output_at(0, train)
|
||||
l2 = self.get_output_at(1, train)
|
||||
output = T.batched_tensordot(l1, l2, self.dot_axes)
|
||||
output = output.dimshuffle((0, 'x'))
|
||||
return output
|
||||
|
||||
def get_output_cos(self, train=False):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception('"cos" merge mode will only work with Theano.')
|
||||
import theano
|
||||
from theano import tensor as T
|
||||
l1 = self.get_output_at(0, train)
|
||||
l2 = self.get_output_at(1, train)
|
||||
cos = lambda v1, v2: T.dot(v1, v2) / T.sqrt(T.dot(v1, v1) * T.dot(v2, v2))
|
||||
output, _ = theano.scan(cos, sequences=[l1, l2], outputs_info=None)
|
||||
output = output.dimshuffle((0, 'x'))
|
||||
return output
|
||||
|
||||
def get_output(self, train=False):
|
||||
mode = self.merge_mode
|
||||
if mode == 'join':
|
||||
return self.get_output_join(train)
|
||||
elif mode == 'concat':
|
||||
return self.get_output_concat(train)
|
||||
elif mode == 'sum':
|
||||
return self.get_output_sum(train)
|
||||
elif mode == 'ave':
|
||||
return self.get_output_ave(train)
|
||||
elif mode == 'mul':
|
||||
return self.get_output_mul(train)
|
||||
elif mode == 'dot':
|
||||
return self.get_output_dot(train)
|
||||
elif mode == 'cos':
|
||||
return self.get_output_dot(train)
|
||||
|
||||
def get_input(self, train=False):
|
||||
res = []
|
||||
for i in range(len(self.inputs)):
|
||||
o = self.inputs[i].get_input(train)
|
||||
if 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 = self.layer.get_weights()
|
||||
if self.merge_mode:
|
||||
for m in self.inputs:
|
||||
weights += m.get_weights()
|
||||
return weights
|
||||
|
||||
def set_weights(self, weights):
|
||||
nb_param = len(self.layer.params)
|
||||
self.layer.set_weights(weights[:nb_param])
|
||||
weights = weights[nb_param:]
|
||||
if self.merge_mode:
|
||||
for i in range(len(self.inputs)):
|
||||
nb_param = len(self.inputs[i].params)
|
||||
self.inputs[i].set_weights(weights[:nb_param])
|
||||
weights = weights[nb_param:]
|
||||
|
||||
def get_config(self):
|
||||
|
||||
config = {"name": self.__class__.__name__,
|
||||
"layer": self.layer.get_config,
|
||||
"inputs": [m.get_config() for m in self.inputs],
|
||||
"merge_mode": self.merge_mode,
|
||||
"concat_axis": self.concat_axis,
|
||||
"dot_axes": self.dot_axes
|
||||
}
|
||||
base_config = super(Siamese, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class SiameseHead(Layer):
|
||||
'''This layer should be added only on top of a Siamese layer
|
||||
with merge_mode = None
|
||||
|
||||
Outputs the output of the Siamese layer at a given index,
|
||||
specified by the head argument
|
||||
|
||||
Arguments
|
||||
---------
|
||||
head - The index at which the output of the Siamese layer
|
||||
should be obtained
|
||||
'''
|
||||
def __init__(self, head):
|
||||
self.head = head
|
||||
self.params = []
|
||||
|
||||
def get_output(self, train=False):
|
||||
return self.get_input(train)
|
||||
|
||||
@property
|
||||
def input_shape(self):
|
||||
return self.previous.get_output_shape(self.head)
|
||||
|
||||
def get_input(self, train=False):
|
||||
return self.previous.get_output_at(self.head, train)
|
||||
|
||||
def get_config(self):
|
||||
|
||||
config = {"name": self.__class__.__name__,
|
||||
"head": self.head}
|
||||
|
||||
base_config = super(SiameseHead, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
def set_previous(self, layer):
|
||||
self.previous = layer
|
||||
|
||||
|
||||
def add_shared_layer(layer, inputs):
|
||||
'''
|
||||
Use this function to add a shared layer across multiple Sequential models
|
||||
without merging the outputs
|
||||
'''
|
||||
input_layers = [l.layers[-1] for l in inputs]
|
||||
s = Siamese(layer, input_layers, merge_mode=None)
|
||||
for i in range(len(inputs)):
|
||||
sh = SiameseHead(i)
|
||||
inputs[i].add(s)
|
||||
inputs[i].add(sh)
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
from .. import backend as K
|
||||
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..layers.core import Layer, MaskedLayer
|
||||
from ..utils.theano_utils import sharedX
|
||||
|
||||
from ..constraints import unitnorm
|
||||
|
||||
@@ -19,9 +17,12 @@ class Embedding(Layer):
|
||||
'''
|
||||
input_ndim = 2
|
||||
|
||||
def __init__(self, input_dim, output_dim, init='uniform', input_length=None,
|
||||
W_regularizer=None, activity_regularizer=None, W_constraint=None,
|
||||
mask_zero=False, weights=None, **kwargs):
|
||||
def __init__(self, input_dim, output_dim,
|
||||
init='uniform', input_length=None,
|
||||
W_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None,
|
||||
mask_zero=False,
|
||||
weights=None, **kwargs):
|
||||
self.input_dim = input_dim
|
||||
self.output_dim = output_dim
|
||||
self.init = initializations.get(init)
|
||||
@@ -39,7 +40,8 @@ class Embedding(Layer):
|
||||
super(Embedding, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
self.input = T.imatrix()
|
||||
self.input = K.placeholder(shape=(None, self.input_length),
|
||||
dtype='int32')
|
||||
self.W = self.init((self.input_dim, self.output_dim))
|
||||
self.params = [self.W]
|
||||
self.regularizers = []
|
||||
@@ -59,7 +61,9 @@ class Embedding(Layer):
|
||||
if not self.mask_zero:
|
||||
return None
|
||||
else:
|
||||
return T.ones_like(X) * (1 - T.eq(X, 0))
|
||||
if K._BACKEND == "tensorflow":
|
||||
raise Exception("Masking is Theano-only for the time being.")
|
||||
return K.ones_like(X) * (1 - K.equal(X, 0))
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
@@ -67,7 +71,7 @@ class Embedding(Layer):
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
out = self.W[X]
|
||||
out = K.gather(self.W, X)
|
||||
return out
|
||||
|
||||
def get_config(self):
|
||||
@@ -82,72 +86,3 @@ class Embedding(Layer):
|
||||
"W_constraint": self.W_constraint.get_config() if self.W_constraint else None}
|
||||
base_config = super(Embedding, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class WordContextProduct(Layer):
|
||||
'''
|
||||
This layer turns a pair of words (a pivot word + a context word,
|
||||
ie. a word from the same context, or a random, out-of-context word),
|
||||
indentified by their index in a vocabulary, into two dense reprensentations
|
||||
(word representation and context representation).
|
||||
|
||||
Then it returns activation(dot(pivot_embedding, context_embedding)),
|
||||
which can be trained to encode the probability
|
||||
of finding the context word in the context of the pivot word
|
||||
(or reciprocally depending on your training procedure).
|
||||
|
||||
The layer ingests integer tensors of shape:
|
||||
(nb_samples, 2)
|
||||
and outputs a float tensor of shape
|
||||
(nb_samples, 1)
|
||||
|
||||
The 2nd dimension encodes (pivot, context).
|
||||
input_dim is the size of the vocabulary.
|
||||
|
||||
For more context, see Mikolov et al.:
|
||||
Efficient Estimation of Word reprensentations in Vector Space
|
||||
http://arxiv.org/pdf/1301.3781v3.pdf
|
||||
'''
|
||||
input_ndim = 2
|
||||
|
||||
def __init__(self, input_dim, proj_dim=128,
|
||||
init='uniform', activation='sigmoid', weights=None, **kwargs):
|
||||
|
||||
super(WordContextProduct, self).__init__(**kwargs)
|
||||
self.input_dim = input_dim
|
||||
self.proj_dim = proj_dim
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
|
||||
self.input = T.imatrix()
|
||||
# two different embeddings for pivot word and its context
|
||||
# because p(w|c) != p(c|w)
|
||||
self.W_w = self.init((input_dim, proj_dim))
|
||||
self.W_c = self.init((input_dim, proj_dim))
|
||||
|
||||
self.params = [self.W_w, self.W_c]
|
||||
|
||||
if weights is not None:
|
||||
self.set_weights(weights)
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
return (self.input_shape[0], 1)
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
w = self.W_w[X[:, 0]] # nb_samples, proj_dim
|
||||
c = self.W_c[X[:, 1]] # nb_samples, proj_dim
|
||||
|
||||
dot = T.sum(w * c, axis=1)
|
||||
dot = theano.tensor.reshape(dot, (X.shape[0], 1))
|
||||
return self.activation(dot)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
"input_dim": self.input_dim,
|
||||
"proj_dim": self.proj_dim,
|
||||
"init": self.init.__name__,
|
||||
"activation": self.activation.__name__}
|
||||
base_config = super(WordContextProduct, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
+8
-10
@@ -1,9 +1,6 @@
|
||||
from __future__ import absolute_import
|
||||
import numpy as np
|
||||
from .core import MaskedLayer
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from .. import backend as K
|
||||
|
||||
|
||||
class GaussianNoise(MaskedLayer):
|
||||
@@ -13,15 +10,15 @@ class GaussianNoise(MaskedLayer):
|
||||
def __init__(self, sigma, **kwargs):
|
||||
super(GaussianNoise, self).__init__(**kwargs)
|
||||
self.sigma = sigma
|
||||
self.srng = RandomStreams(seed=np.random.randint(10e6))
|
||||
|
||||
def get_output(self, train=False):
|
||||
X = self.get_input(train)
|
||||
if not train or self.sigma == 0:
|
||||
return X
|
||||
else:
|
||||
return X + self.srng.normal(size=X.shape, avg=0.0, std=self.sigma,
|
||||
dtype=theano.config.floatX)
|
||||
return X + K.random_normal(shape=K.shape(X),
|
||||
mean=0.,
|
||||
std=self.sigma)
|
||||
|
||||
def get_config(self):
|
||||
config = {"name": self.__class__.__name__,
|
||||
@@ -41,13 +38,14 @@ class GaussianDropout(MaskedLayer):
|
||||
def __init__(self, p, **kwargs):
|
||||
super(GaussianDropout, self).__init__(**kwargs)
|
||||
self.p = p
|
||||
self.srng = RandomStreams(seed=np.random.randint(10e6))
|
||||
|
||||
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 *= self.srng.normal(size=X.shape, avg=1.0, std=T.sqrt(self.p / (1.0 - self.p)), dtype=theano.config.floatX)
|
||||
# self.p refers to drop probability rather than
|
||||
# retain probability (as in paper), for consistency
|
||||
X *= K.random_normal(shape=K.shape(X), mean=1.0,
|
||||
std=self.p / (1.0 - self.p))
|
||||
return X
|
||||
|
||||
def get_config(self):
|
||||
|
||||
@@ -1,22 +1,24 @@
|
||||
from ..layers.core import Layer
|
||||
from ..utils.theano_utils import shared_zeros, shared_ones, ndim_tensor, floatX
|
||||
from .. import initializations
|
||||
|
||||
import theano.tensor as T
|
||||
from .. import backend as K
|
||||
|
||||
|
||||
class BatchNormalization(Layer):
|
||||
'''
|
||||
Reference:
|
||||
Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift
|
||||
Batch Normalization: Accelerating Deep Network Training
|
||||
by Reducing Internal Covariate Shift
|
||||
http://arxiv.org/pdf/1502.03167v3.pdf
|
||||
|
||||
mode: 0 -> featurewise normalization
|
||||
1 -> samplewise normalization (may sometimes outperform featurewise mode)
|
||||
1 -> samplewise normalization
|
||||
(may sometimes outperform featurewise mode)
|
||||
|
||||
momentum: momentum term in the computation of a running estimate of the mean and std of the data
|
||||
momentum: momentum term in the computation
|
||||
of a running estimate of the mean and std of the data
|
||||
'''
|
||||
def __init__(self, epsilon=1e-6, mode=0, momentum=0.9, weights=None, **kwargs):
|
||||
def __init__(self, epsilon=1e-6, mode=0, momentum=0.9,
|
||||
weights=None, **kwargs):
|
||||
self.init = initializations.get("uniform")
|
||||
self.epsilon = epsilon
|
||||
self.mode = mode
|
||||
@@ -27,46 +29,47 @@ class BatchNormalization(Layer):
|
||||
def build(self):
|
||||
input_shape = self.input_shape # starts with samples axis
|
||||
input_shape = input_shape[1:]
|
||||
self.input = ndim_tensor(len(input_shape) + 1)
|
||||
|
||||
self.gamma = self.init((input_shape))
|
||||
self.beta = shared_zeros(input_shape)
|
||||
self.beta = K.zeros(input_shape)
|
||||
|
||||
self.params = [self.gamma, self.beta]
|
||||
self.running_mean = shared_zeros(input_shape)
|
||||
self.running_std = shared_ones((input_shape))
|
||||
self.running_mean = K.zeros(input_shape)
|
||||
self.running_std = K.ones((input_shape))
|
||||
|
||||
# initialize self.updates: batch mean/std computation
|
||||
X = self.get_input(train=True)
|
||||
m = X.mean(axis=0)
|
||||
std = T.mean((X - m) ** 2 + self.epsilon, axis=0) ** 0.5
|
||||
m = K.mean(X, axis=0)
|
||||
std = K.mean(K.square(X - m) + self.epsilon, axis=0)
|
||||
std = K.sqrt(std)
|
||||
mean_update = self.momentum * self.running_mean + (1-self.momentum) * m
|
||||
std_update = self.momentum * self.running_std + (1-self.momentum) * std
|
||||
self.updates = [(self.running_mean, mean_update), (self.running_std, std_update)]
|
||||
self.updates = [(self.running_mean, mean_update),
|
||||
(self.running_std, std_update)]
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
|
||||
def get_weights(self):
|
||||
return super(BatchNormalization, self).get_weights() + [self.running_mean.get_value(), self.running_std.get_value()]
|
||||
super_weights = super(BatchNormalization, self).get_weights()
|
||||
return super_weights + [K.get_value(self.running_mean),
|
||||
K.get_value(self.running_std)]
|
||||
|
||||
def set_weights(self, weights):
|
||||
self.running_mean.set_value(floatX(weights[-2]))
|
||||
self.running_std.set_value(floatX(weights[-1]))
|
||||
K.set_value(self.running_mean, weights[-2])
|
||||
K.set_value(self.running_std, weights[-1])
|
||||
super(BatchNormalization, self).set_weights(weights[:-2])
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
|
||||
if self.mode == 0:
|
||||
X_normed = (X - self.running_mean) / (self.running_std + self.epsilon)
|
||||
|
||||
X_normed = ((X - self.running_mean) /
|
||||
(self.running_std + self.epsilon))
|
||||
elif self.mode == 1:
|
||||
m = X.mean(axis=-1, keepdims=True)
|
||||
std = X.std(axis=-1, keepdims=True)
|
||||
m = K.mean(X, axis=-1, keepdims=True)
|
||||
std = K.std(X, axis=-1, keepdims=True)
|
||||
X_normed = (X - m) / (std + self.epsilon)
|
||||
|
||||
out = self.gamma * X_normed + self.beta
|
||||
return out
|
||||
|
||||
@@ -96,14 +99,17 @@ class LRN2D(Layer):
|
||||
|
||||
def get_output(self, train):
|
||||
X = self.get_input(train)
|
||||
b, ch, r, c = X.shape
|
||||
b, ch, r, c = K.shape(X)
|
||||
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)
|
||||
input_sqr = K.square(X)
|
||||
extra_channels = K.zeros((b, ch + 2 * half_n, r, c))
|
||||
input_sqr = K.concatenate([extra_channels[:, :half_n, :, :],
|
||||
input_sqr,
|
||||
extra_channels[:, half_n + ch:, :, :]],
|
||||
axis=1)
|
||||
scale = self.k
|
||||
for i in range(self.n):
|
||||
scale += self.alpha * input_sqr[:, i:i+ch, :, :]
|
||||
scale += self.alpha * input_sqr[:, i:i + ch, :, :]
|
||||
scale = scale ** self.beta
|
||||
return X / scale
|
||||
|
||||
|
||||
@@ -0,0 +1,326 @@
|
||||
import numpy as np
|
||||
from scipy.linalg import circulant
|
||||
|
||||
from .. import backend as K
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
floatX = theano.config.floatX
|
||||
|
||||
from keras.layers.recurrent import Recurrent, GRU, LSTM
|
||||
from keras.utils.theano_utils import shared_zeros, alloc_zeros_matrix, shared_scalar
|
||||
tol = 1e-4
|
||||
|
||||
|
||||
def _update_controller(self, inp, h_tm1, M, mask):
|
||||
""" Update inner RNN controler
|
||||
We have to update the inner RNN inside the Neural Turing Machine, this
|
||||
is an almost literal copy of keras.layers.recurrent.GRU and
|
||||
keras.layers.recurrent.LSTM see these clases for further details.
|
||||
"""
|
||||
x = T.concatenate([inp, M], axis=-1)
|
||||
# get inputs
|
||||
if self.inner_rnn == 'gru':
|
||||
x_z = T.dot(x, self.rnn.W_z) + self.rnn.b_z
|
||||
x_r = T.dot(x, self.rnn.W_r) + self.rnn.b_r
|
||||
x_h = T.dot(x, self.rnn.W_h) + self.rnn.b_h
|
||||
|
||||
elif self.inner_rnn == 'lstm':
|
||||
xi = T.dot(x, self.rnn.W_i) + self.rnn.b_i
|
||||
xf = T.dot(x, self.rnn.W_f) + self.rnn.b_f
|
||||
xc = T.dot(x, self.rnn.W_c) + self.rnn.b_c
|
||||
xo = T.dot(x, self.rnn.W_o) + self.rnn.b_o
|
||||
|
||||
elif self.inner_rnn == 'simple':
|
||||
x = T.dot(x, self.rnn.W) + self.rnn.b
|
||||
|
||||
# update state
|
||||
if self.inner_rnn == 'gru':
|
||||
h = self.rnn._step(x_z, x_r, x_h, 1., h_tm1[0],
|
||||
self.rnn.U_z,
|
||||
self.rnn.U_r,
|
||||
self.rnn.U_h)
|
||||
h = mask[:, None] * h + (1-mask[:, None])*h_tm1[0]
|
||||
h = (h, )
|
||||
|
||||
elif self.inner_rnn == 'lstm':
|
||||
h = self.rnn._step(xi, xf, xo, xc, 1.,
|
||||
h_tm1[1], h_tm1[0],
|
||||
self.rnn.U_i, self.rnn.U_f,
|
||||
self.rnn.U_o, self.rnn.U_c)
|
||||
h = h[::-1]
|
||||
h = tuple([mask[:, None]*h[i] +
|
||||
(1-mask[:, None])*h_tm1[i] for i in range(len(h))])
|
||||
|
||||
elif self.inner_rnn == 'simple':
|
||||
h = self.rnn._step(x, 1, h_tm1[0], self.rnn.U)
|
||||
h = mask[:, None] * h + (1-mask[:, None])*h_tm1[0]
|
||||
h = (h, )
|
||||
|
||||
return h
|
||||
|
||||
|
||||
def _circulant(leng, n_shifts):
|
||||
""" Generate circulant copies of a vector.
|
||||
This will generate a tensor with `n_shifts` of rotated versions the
|
||||
identity matrix. When this tensor is multiplied by a vector
|
||||
the result are `n_shifts` shifted versions of that vector. Since
|
||||
everything is done with inner products, this operation is differentiable.
|
||||
|
||||
Paramters:
|
||||
----------
|
||||
leng: int > 0, number of memory locations
|
||||
n_shifts: int > 0, number of allowed shifts (if 1, no shift)
|
||||
|
||||
Returns:
|
||||
--------
|
||||
shift operation, a tensor with dimensions (n_shifts, leng, leng)
|
||||
"""
|
||||
eye = np.eye(leng)
|
||||
shifts = range(n_shifts//2, -n_shifts//2, -1)
|
||||
C = np.asarray([np.roll(eye, s, axis=1) for s in shifts])
|
||||
return theano.shared(C.astype(theano.config.floatX))
|
||||
|
||||
|
||||
def _renorm(x):
|
||||
return x / (x.sum(axis=1, keepdims=True))
|
||||
|
||||
|
||||
def _softmax(x):
|
||||
wt = x.flatten(ndim=2)
|
||||
w = T.nnet.softmax(wt)
|
||||
return w.reshape(x.shape) # T.clip(s, 0, 1)
|
||||
|
||||
|
||||
def _cosine_distance(M, k):
|
||||
dot = (M * k[:, None, :]).sum(axis=-1)
|
||||
nM = T.sqrt((M**2).sum(axis=-1))
|
||||
nk = T.sqrt((k**2).sum(axis=-1, keepdims=True))
|
||||
return dot / (nM * nk)
|
||||
|
||||
|
||||
class NeuralTuringMachine(Recurrent):
|
||||
""" Neural Turing Machines
|
||||
|
||||
Parameters:
|
||||
-----------
|
||||
shift_range: int, number of available shifts, ex. if 3, avilable shifts are
|
||||
(-1, 0, 1)
|
||||
n_slots: number of memory locations
|
||||
m_length: memory length at each location
|
||||
inner_rnn: str, supported values are 'gru' and 'lstm'
|
||||
output_dim: hidden state size (RNN controller output_dim)
|
||||
|
||||
Known issues and TODO:
|
||||
----------------------
|
||||
Theano may complain when n_slots == 1.
|
||||
Add multiple reading and writing heads.
|
||||
|
||||
"""
|
||||
def __init__(self, output_dim, n_slots, m_length, shift_range=3,
|
||||
inner_rnn='gru', truncate_gradient=-1, return_sequences=False,
|
||||
init='glorot_uniform', inner_init='orthogonal',
|
||||
input_dim=None, input_length=None, **kwargs):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception('NeuralTuringMachine is only available for Theano for the time being. ' +
|
||||
'It will be adapted to TensorFlow soon.')
|
||||
self.output_dim = output_dim
|
||||
self.n_slots = n_slots
|
||||
self.m_length = m_length
|
||||
self.shift_range = shift_range
|
||||
self.init = init
|
||||
self.inner_init = inner_init
|
||||
self.inner_rnn = inner_rnn
|
||||
self.return_sequences = return_sequences
|
||||
self.truncate_gradient = truncate_gradient
|
||||
|
||||
self.input_dim = input_dim
|
||||
self.input_length = input_length
|
||||
if self.input_dim:
|
||||
kwargs['input_shape'] = (self.input_length, self.input_dim)
|
||||
super(NeuralTuringMachine, self).__init__(**kwargs)
|
||||
|
||||
def build(self):
|
||||
input_leng, input_dim = self.input_shape[1:]
|
||||
self.input = T.tensor3()
|
||||
|
||||
if self.inner_rnn == 'gru':
|
||||
self.rnn = GRU(
|
||||
input_dim=input_dim+self.m_length,
|
||||
input_length=input_leng,
|
||||
output_dim=self.output_dim, init=self.init,
|
||||
inner_init=self.inner_init)
|
||||
elif self.inner_rnn == 'lstm':
|
||||
self.rnn = LSTM(
|
||||
input_dim=input_dim+self.m_length,
|
||||
input_length=input_leng,
|
||||
output_dim=self.output_dim, init=self.init,
|
||||
inner_init=self.inner_init)
|
||||
else:
|
||||
raise ValueError('this inner_rnn is not implemented yet.')
|
||||
|
||||
self.rnn.build()
|
||||
|
||||
# initial memory, state, read and write vecotrs
|
||||
self.M = theano.shared((.001*np.ones((1,)).astype(floatX)))
|
||||
self.init_h = shared_zeros((self.output_dim))
|
||||
self.init_wr = self.rnn.init((self.n_slots,))
|
||||
self.init_ww = self.rnn.init((self.n_slots,))
|
||||
|
||||
# write
|
||||
self.W_e = self.rnn.init((self.output_dim, self.m_length)) # erase
|
||||
self.b_e = shared_zeros((self.m_length))
|
||||
self.W_a = self.rnn.init((self.output_dim, self.m_length)) # add
|
||||
self.b_a = shared_zeros((self.m_length))
|
||||
|
||||
# get_w parameters for reading operation
|
||||
self.W_k_read = self.rnn.init((self.output_dim, self.m_length))
|
||||
self.b_k_read = self.rnn.init((self.m_length, ))
|
||||
self.W_c_read = self.rnn.init((self.output_dim, 3)) # 3 = beta, g, gamma see eq. 5, 7, 9 in Graves et. al 2014
|
||||
self.b_c_read = shared_zeros((3))
|
||||
self.W_s_read = self.rnn.init((self.output_dim, self.shift_range))
|
||||
self.b_s_read = shared_zeros((self.shift_range))
|
||||
|
||||
# get_w parameters for writing operation
|
||||
self.W_k_write = self.rnn.init((self.output_dim, self.m_length))
|
||||
self.b_k_write = self.rnn.init((self.m_length, ))
|
||||
self.W_c_write = self.rnn.init((self.output_dim, 3)) # 3 = beta, g, gamma see eq. 5, 7, 9
|
||||
self.b_c_write = shared_zeros((3))
|
||||
self.W_s_write = self.rnn.init((self.output_dim, self.shift_range))
|
||||
self.b_s_write = shared_zeros((self.shift_range))
|
||||
|
||||
self.C = _circulant(self.n_slots, self.shift_range)
|
||||
|
||||
self.params = self.rnn.params + [
|
||||
self.W_e, self.b_e,
|
||||
self.W_a, self.b_a,
|
||||
self.W_k_read, self.b_k_read,
|
||||
self.W_c_read, self.b_c_read,
|
||||
self.W_s_read, self.b_s_read,
|
||||
self.W_k_write, self.b_k_write,
|
||||
self.W_s_write, self.b_s_write,
|
||||
self.W_c_write, self.b_c_write,
|
||||
self.M,
|
||||
self.init_h, self.init_wr, self.init_ww]
|
||||
|
||||
if self.inner_rnn == 'lstm':
|
||||
self.init_c = shared_zeros((self.output_dim))
|
||||
self.params = self.params + [self.init_c, ]
|
||||
|
||||
def _read(self, w, M):
|
||||
return (w[:, :, None]*M).sum(axis=1)
|
||||
|
||||
def _write(self, w, e, a, M, mask):
|
||||
Mtilda = M * (1 - w[:, :, None]*e[:, None, :])
|
||||
Mout = Mtilda + w[:, :, None]*a[:, None, :]
|
||||
return mask[:, None, None]*Mout + (1-mask[:, None, None])*M
|
||||
|
||||
def _get_content_w(self, beta, k, M):
|
||||
num = beta[:, None] * _cosine_distance(M, k)
|
||||
return _softmax(num)
|
||||
|
||||
def _get_location_w(self, g, s, C, gamma, wc, w_tm1, mask):
|
||||
wg = g[:, None] * wc + (1-g[:, None])*w_tm1
|
||||
Cs = (C[None, :, :, :] * wg[:, None, None, :]).sum(axis=3)
|
||||
wtilda = (Cs * s[:, :, None]).sum(axis=1)
|
||||
wout = _renorm(wtilda ** gamma[:, None])
|
||||
return mask[:, None] * wout + (1-mask[:, None])*w_tm1
|
||||
|
||||
def _get_controller_output(self, h, W_k, b_k, W_c, b_c, W_s, b_s):
|
||||
k = T.tanh(T.dot(h, W_k) + b_k) # + 1e-6
|
||||
c = T.dot(h, W_c) + b_c
|
||||
beta = T.nnet.relu(c[:, 0]) + 1e-6
|
||||
g = T.nnet.sigmoid(c[:, 1])
|
||||
gamma = T.nnet.relu(c[:, 2]) + 1
|
||||
s = T.nnet.softmax(T.dot(h, W_s) + b_s)
|
||||
return k, beta, g, gamma, s
|
||||
|
||||
def _get_initial_states(self, batch_size):
|
||||
init_M = self.M.dimshuffle(0, 'x', 'x').repeat(
|
||||
batch_size, axis=0).repeat(self.n_slots, axis=1).repeat(
|
||||
self.m_length, axis=2)
|
||||
|
||||
init_h = self.init_h.dimshuffle(('x', 0)).repeat(batch_size, axis=0)
|
||||
init_wr = self.init_wr.dimshuffle(('x', 0)).repeat(batch_size, axis=0)
|
||||
init_ww = self.init_ww.dimshuffle(('x', 0)).repeat(batch_size, axis=0)
|
||||
if self.inner_rnn == 'lstm':
|
||||
init_c = self.init_c.dimshuffle(('x', 0)).repeat(batch_size, axis=0)
|
||||
return init_M, T.nnet.softmax(init_wr), T.nnet.softmax(init_ww), init_h, init_c
|
||||
else:
|
||||
return init_M, T.nnet.softmax(init_wr), T.nnet.softmax(init_ww), init_h
|
||||
|
||||
def _step(self, x, mask, M_tm1, wr_tm1, ww_tm1, *args):
|
||||
# read
|
||||
if self.inner_rnn == 'lstm':
|
||||
h_tm1 = args[0:2][::-1] # (cell_tm1, h_tm1)
|
||||
else:
|
||||
h_tm1 = args[0:1] # (h_tm1, )
|
||||
k_read, beta_read, g_read, gamma_read, s_read = self._get_controller_output(
|
||||
h_tm1[-1], self.W_k_read, self.b_k_read, self.W_c_read, self.b_c_read,
|
||||
self.W_s_read, self.b_s_read)
|
||||
wc_read = self._get_content_w(beta_read, k_read, M_tm1)
|
||||
wr_t = self._get_location_w(g_read, s_read, self.C, gamma_read,
|
||||
wc_read, wr_tm1, mask)
|
||||
M_read = self._read(wr_t, M_tm1)
|
||||
|
||||
# update controller
|
||||
h_t = _update_controller(self, x, h_tm1, M_read, mask)
|
||||
|
||||
# write
|
||||
k_write, beta_write, g_write, gamma_write, s_write = self._get_controller_output(
|
||||
h_t[-1], self.W_k_write, self.b_k_write, self.W_c_write,
|
||||
self.b_c_write, self.W_s_write, self.b_s_write)
|
||||
wc_write = self._get_content_w(beta_write, k_write, M_tm1)
|
||||
ww_t = self._get_location_w(g_write, s_write, self.C, gamma_write,
|
||||
wc_write, ww_tm1, mask)
|
||||
e = T.nnet.sigmoid(T.dot(h_t[-1], self.W_e) + self.b_e)
|
||||
a = T.tanh(T.dot(h_t[-1], self.W_a) + self.b_a)
|
||||
M_t = self._write(ww_t, e, a, M_tm1, mask)
|
||||
|
||||
return (M_t, wr_t, ww_t) + h_t
|
||||
|
||||
def get_output(self, train=False):
|
||||
outputs = self.get_full_output(train)
|
||||
|
||||
if self.return_sequences:
|
||||
return outputs[-1]
|
||||
else:
|
||||
return outputs[-1][:, -1]
|
||||
|
||||
@property
|
||||
def output_shape(self):
|
||||
input_shape = self.input_shape
|
||||
if self.return_sequences:
|
||||
return input_shape[0], input_shape[1], self.output_dim
|
||||
else:
|
||||
return input_shape[0], self.output_dim
|
||||
|
||||
def get_full_output(self, train=False):
|
||||
"""
|
||||
This method is for research and visualization purposes. Use it as:
|
||||
X = model.get_input() # full model
|
||||
Y = ntm.get_output() # this layer
|
||||
F = theano.function([X], Y, allow_input_downcast=True)
|
||||
[memory, read_address, write_address, rnn_state] = F(x)
|
||||
|
||||
if inner_rnn == "lstm" use it as:
|
||||
[memory, read_address, write_address, rnn_cell, rnn_state] = F(x)
|
||||
|
||||
"""
|
||||
X = self.get_input(train)
|
||||
padded_mask = self.get_padded_shuffled_mask(train, X, pad=1)[:, :, 0]
|
||||
X = X.dimshuffle((1, 0, 2))
|
||||
|
||||
init_states = self._get_initial_states(X.shape[1])
|
||||
outputs, updates = theano.scan(self._step,
|
||||
sequences=[X, padded_mask],
|
||||
outputs_info=init_states,
|
||||
non_sequences=self.params,
|
||||
truncate_gradient=self.truncate_gradient)
|
||||
|
||||
out = [outputs[0].dimshuffle((1, 0, 2, 3)),
|
||||
outputs[1].dimshuffle(1, 0, 2),
|
||||
outputs[2].dimshuffle((1, 0, 2)),
|
||||
outputs[3].dimshuffle((1, 0, 2))]
|
||||
if self.inner_rnn == 'lstm':
|
||||
out + [outputs[4].dimshuffle((1, 0, 2))]
|
||||
return out
|
||||
+193
-654
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
+115
-100
@@ -1,12 +1,14 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
import warnings, time, copy, pprint
|
||||
import warnings
|
||||
import time
|
||||
import copy
|
||||
import pprint
|
||||
from six.moves import range
|
||||
import six
|
||||
|
||||
from . import backend as K
|
||||
from . import optimizers
|
||||
from . import objectives
|
||||
from . import regularizers
|
||||
@@ -26,11 +28,11 @@ def standardize_y(y):
|
||||
|
||||
|
||||
def batch_shuffle(index_array, batch_size):
|
||||
batch_count = int(len(index_array)/batch_size)
|
||||
batch_count = int(len(index_array) / batch_size)
|
||||
# to reshape we need to be cleanly divisible by batch size
|
||||
# we stash extra items and reappend them after shuffling
|
||||
last_batch = index_array[batch_count*batch_size:]
|
||||
index_array = index_array[:batch_count*batch_size]
|
||||
last_batch = index_array[batch_count * batch_size:]
|
||||
index_array = index_array[:batch_count * batch_size]
|
||||
index_array = index_array.reshape((batch_count, batch_size))
|
||||
np.random.shuffle(index_array)
|
||||
index_array = index_array.flatten()
|
||||
@@ -38,8 +40,8 @@ def batch_shuffle(index_array, batch_size):
|
||||
|
||||
|
||||
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)]
|
||||
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):
|
||||
@@ -52,11 +54,16 @@ def standardize_X(X):
|
||||
def slice_X(X, start=None, stop=None):
|
||||
if type(X) == list:
|
||||
if hasattr(start, '__len__'):
|
||||
# hdf5 dataset only support list object as indices
|
||||
if hasattr(start, 'shape'):
|
||||
start = start.tolist()
|
||||
return [x[start] for x in X]
|
||||
else:
|
||||
return [x[start:stop] for x in X]
|
||||
else:
|
||||
if hasattr(start, '__len__'):
|
||||
if hasattr(start, 'shape'):
|
||||
start = start.tolist()
|
||||
return X[start]
|
||||
else:
|
||||
return X[start:stop]
|
||||
@@ -64,65 +71,71 @@ def slice_X(X, start=None, stop=None):
|
||||
|
||||
def weighted_objective(fn):
|
||||
def weighted(y_true, y_pred, weights, mask=None):
|
||||
# it's important that 0 * Inf == 0, not NaN, so we need to filter
|
||||
# those out first
|
||||
filtered_y_true = y_true[weights.nonzero()[:-1]]
|
||||
filtered_y_pred = y_pred[weights.nonzero()[:-1]]
|
||||
filtered_weights = weights[weights.nonzero()]
|
||||
obj_output = fn(filtered_y_true, filtered_y_pred)
|
||||
weighted = filtered_weights * obj_output
|
||||
if mask is None:
|
||||
# Instead of calling mean() here, we divide by the sum of filtered_weights.
|
||||
return weighted.sum() / filtered_weights.sum()
|
||||
else:
|
||||
filtered_mask = mask[weights.nonzero()[:-1]]
|
||||
return weighted.sum() / (filtered_mask * filtered_weights).sum()
|
||||
'''To be called only with non-zero weights.
|
||||
|
||||
mask: binary
|
||||
'''
|
||||
score_array = fn(y_true, y_pred)
|
||||
if mask is not None:
|
||||
score_array *= mask
|
||||
# the loss per batch should be proportional
|
||||
# to the number of unmasked sampled.
|
||||
score_array /= K.mean(mask)
|
||||
|
||||
# reduce score_array to 1D
|
||||
ndim = K.ndim(score_array)
|
||||
for d in range(ndim-1):
|
||||
score_array = K.mean(score_array, axis=-1)
|
||||
|
||||
if weights is not None:
|
||||
score_array *= weights
|
||||
return K.mean(score_array)
|
||||
return weighted
|
||||
|
||||
|
||||
def standardize_weights(y, sample_weight=None, class_weight=None):
|
||||
if sample_weight is not None:
|
||||
return standardize_y(sample_weight)
|
||||
assert len(sample_weight) == len(y)
|
||||
return sample_weight.flatten()
|
||||
elif isinstance(class_weight, dict):
|
||||
if len(y.shape) > 3:
|
||||
raise Exception('class_weight not supported for 4+ dimensional targets.')
|
||||
yshape = y.shape
|
||||
y = np.reshape(y, (-1, yshape[-1])) # for time-distributed data, collapse time and sample
|
||||
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
|
||||
class_weights = np.asarray([class_weight[cls] for cls in y_classes])
|
||||
return np.reshape(class_weights, yshape[:-1] + (1,)) # uncollapse initial dimensions
|
||||
weights = np.asarray([class_weight[cls] for cls in y_classes])
|
||||
return weights
|
||||
else:
|
||||
return np.ones(y.shape[:-1] + (1,))
|
||||
return np.ones((y.shape[0],))
|
||||
|
||||
|
||||
def model_from_yaml(yaml_string, custom_layers={}):
|
||||
def model_from_yaml(yaml_string, custom_objects={}):
|
||||
'''
|
||||
Returns a model generated from a local yaml file,
|
||||
which is either created by hand or from to_yaml method of Sequential or Graph
|
||||
which is either created by hand or from to_yaml method
|
||||
of Sequential or Graph
|
||||
'''
|
||||
import yaml
|
||||
config = yaml.load(yaml_string)
|
||||
return model_from_config(config, custom_layers=custom_layers)
|
||||
return model_from_config(config, custom_objects=custom_objects)
|
||||
|
||||
|
||||
def model_from_json(json_string, custom_layers={}):
|
||||
def model_from_json(json_string, custom_objects={}):
|
||||
import json
|
||||
config = json.loads(json_string)
|
||||
return model_from_config(config, custom_layers=custom_layers)
|
||||
return model_from_config(config, custom_objects=custom_objects)
|
||||
|
||||
|
||||
def model_from_config(config, custom_layers={}):
|
||||
def model_from_config(config, custom_objects={}):
|
||||
model_name = config.get('name')
|
||||
if model_name not in {'Graph', 'Sequential'}:
|
||||
raise Exception('Unrecognized model:', model_name)
|
||||
|
||||
# Create a container then set class to appropriate model
|
||||
model = container_from_config(config, custom_layers=custom_layers)
|
||||
model = container_from_config(config, custom_objects=custom_objects)
|
||||
if model_name == 'Graph':
|
||||
model.__class__ = Graph
|
||||
elif model_name == 'Sequential':
|
||||
@@ -139,10 +152,11 @@ def model_from_config(config, custom_layers={}):
|
||||
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)
|
||||
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)
|
||||
|
||||
model.compile(loss=loss, optimizer=optimizer,
|
||||
theano_mode=theano_mode)
|
||||
return model
|
||||
|
||||
|
||||
@@ -154,10 +168,12 @@ def get_function_name(o):
|
||||
|
||||
|
||||
class Model(object):
|
||||
def _fit(self, f, ins, out_labels=[], batch_size=128, nb_epoch=100, verbose=1, callbacks=[],
|
||||
def _fit(self, f, ins, out_labels=[], batch_size=128,
|
||||
nb_epoch=100, verbose=1, callbacks=[],
|
||||
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.
|
||||
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:
|
||||
@@ -199,7 +215,7 @@ class Model(object):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
try:
|
||||
ins_batch = slice_X(ins, batch_ids)
|
||||
except TypeError as err:
|
||||
except TypeError:
|
||||
raise Exception('TypeError while preparing batch. \
|
||||
If using HDF5 input data, pass shuffle="batch".\n')
|
||||
|
||||
@@ -207,7 +223,7 @@ class Model(object):
|
||||
batch_logs['batch'] = batch_index
|
||||
batch_logs['size'] = len(batch_ids)
|
||||
callbacks.on_batch_begin(batch_index, batch_logs)
|
||||
outs = f(*ins_batch)
|
||||
outs = f(ins_batch)
|
||||
if type(outs) != list:
|
||||
outs = [outs]
|
||||
for l, o in zip(out_labels, outs):
|
||||
@@ -220,7 +236,9 @@ class Model(object):
|
||||
# validation
|
||||
if do_validation:
|
||||
# replace with self._evaluate
|
||||
val_outs = self._test_loop(val_f, val_ins, batch_size=batch_size, verbose=0)
|
||||
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
|
||||
@@ -248,7 +266,7 @@ class Model(object):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
ins_batch = slice_X(ins, batch_ids)
|
||||
|
||||
batch_outs = f(*ins_batch)
|
||||
batch_outs = f(ins_batch)
|
||||
if type(batch_outs) != list:
|
||||
batch_outs = [batch_outs]
|
||||
if batch_index == 0:
|
||||
@@ -276,7 +294,7 @@ class Model(object):
|
||||
batch_ids = index_array[batch_start:batch_end]
|
||||
ins_batch = slice_X(ins, batch_ids)
|
||||
|
||||
batch_outs = f(*ins_batch)
|
||||
batch_outs = f(ins_batch)
|
||||
if type(batch_outs) == list:
|
||||
if batch_index == 0:
|
||||
for batch_out in enumerate(batch_outs):
|
||||
@@ -340,7 +358,8 @@ class Sequential(Model, containers.Sequential):
|
||||
- set_weights
|
||||
'''
|
||||
|
||||
def compile(self, optimizer, loss, class_mode="categorical", theano_mode=None):
|
||||
def compile(self, optimizer, loss,
|
||||
class_mode="categorical", theano_mode=None):
|
||||
self.optimizer = optimizers.get(optimizer)
|
||||
|
||||
self.loss = objectives.get(loss)
|
||||
@@ -354,9 +373,9 @@ class Sequential(Model, containers.Sequential):
|
||||
self.y_test = self.get_output(train=False)
|
||||
|
||||
# target of model
|
||||
self.y = T.zeros_like(self.y_train)
|
||||
|
||||
self.weights = T.ones_like(self.y_train)
|
||||
self.y = K.placeholder(ndim=K.ndim(self.y_train))
|
||||
# weights: one scalar per sample
|
||||
self.weights = K.placeholder(ndim=1)
|
||||
|
||||
if hasattr(self.layers[-1], "get_output_mask"):
|
||||
mask = self.layers[-1].get_output_mask()
|
||||
@@ -365,17 +384,15 @@ class Sequential(Model, containers.Sequential):
|
||||
train_loss = weighted_loss(self.y, self.y_train, self.weights, mask)
|
||||
test_loss = weighted_loss(self.y, self.y_test, self.weights, mask)
|
||||
|
||||
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)))
|
||||
test_accuracy = T.mean(T.eq(T.argmax(self.y, axis=-1), T.argmax(self.y_test, axis=-1)))
|
||||
train_accuracy = K.mean(K.equal(K.argmax(self.y, axis=-1),
|
||||
K.argmax(self.y_train, axis=-1)))
|
||||
test_accuracy = K.mean(K.equal(K.argmax(self.y, axis=-1),
|
||||
K.argmax(self.y_test, axis=-1)))
|
||||
|
||||
elif class_mode == "binary":
|
||||
train_accuracy = T.mean(T.eq(self.y, T.round(self.y_train)))
|
||||
test_accuracy = T.mean(T.eq(self.y, T.round(self.y_test)))
|
||||
train_accuracy = K.mean(K.equal(self.y, K.round(self.y_train)))
|
||||
test_accuracy = K.mean(K.equal(self.y, K.round(self.y_test)))
|
||||
else:
|
||||
raise Exception("Invalid class mode:" + str(class_mode))
|
||||
self.class_mode = class_mode
|
||||
@@ -383,39 +400,38 @@ class Sequential(Model, containers.Sequential):
|
||||
|
||||
for r in self.regularizers:
|
||||
train_loss = r(train_loss)
|
||||
updates = self.optimizer.get_updates(self.params, self.constraints, train_loss)
|
||||
updates = self.optimizer.get_updates(self.params,
|
||||
self.constraints,
|
||||
train_loss)
|
||||
updates += self.updates
|
||||
|
||||
if type(self.X_train) == list:
|
||||
train_ins = self.X_train + [self.y, self.weights]
|
||||
test_ins = self.X_test + [self.y, self.weights]
|
||||
assert type(self.X_test) == list
|
||||
predict_ins = self.X_test
|
||||
else:
|
||||
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, updates=updates,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
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,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
self._test = theano.function(test_ins, test_loss,
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
self._test_with_acc = theano.function(test_ins, [test_loss, test_accuracy],
|
||||
allow_input_downcast=True, mode=theano_mode)
|
||||
self._train = K.function(train_ins, [train_loss], updates=updates)
|
||||
self._train_with_acc = K.function(train_ins, [train_loss, train_accuracy], updates=updates)
|
||||
self._predict = K.function(predict_ins, [self.y_test])
|
||||
self._test = K.function(test_ins, [test_loss])
|
||||
self._test_with_acc = K.function(test_ins, [test_loss, test_accuracy])
|
||||
|
||||
def train_on_batch(self, X, y, accuracy=False, class_weight=None, sample_weight=None):
|
||||
def train_on_batch(self, X, y, 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)
|
||||
|
||||
sample_weight = standardize_weights(y, class_weight=class_weight,
|
||||
sample_weight=sample_weight)
|
||||
ins = X + [y, sample_weight]
|
||||
if accuracy:
|
||||
return self._train_with_acc(*ins)
|
||||
return self._train_with_acc(ins)
|
||||
else:
|
||||
return self._train(*ins)
|
||||
return self._train(ins)
|
||||
|
||||
def test_on_batch(self, X, y, accuracy=False, sample_weight=None):
|
||||
X = standardize_X(X)
|
||||
@@ -424,17 +440,17 @@ class Sequential(Model, containers.Sequential):
|
||||
|
||||
ins = X + [y, sample_weight]
|
||||
if accuracy:
|
||||
return self._test_with_acc(*ins)
|
||||
return self._test_with_acc(ins)
|
||||
else:
|
||||
return self._test(*ins)
|
||||
return self._test(ins)
|
||||
|
||||
def predict_on_batch(self, X):
|
||||
ins = standardize_X(X)
|
||||
return self._predict(*ins)
|
||||
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,
|
||||
class_weight=None, sample_weight=None):
|
||||
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)
|
||||
@@ -451,12 +467,13 @@ class Sequential(Model, containers.Sequential):
|
||||
X_val, y_val = validation_data
|
||||
X_val = standardize_X(X_val)
|
||||
y_val = standardize_y(y_val)
|
||||
sample_weight_val = np.ones(y_val.shape[:-1] + (1,))
|
||||
sample_weight_val = standardize_weights(y_val)
|
||||
elif len(validation_data) == 3:
|
||||
X_val, y_val, sample_weight_val = validation_data
|
||||
X_val = standardize_X(X_val)
|
||||
y_val = standardize_y(y_val)
|
||||
sample_weight_val = standardize_weights(y_val, sample_weight=sample_weight_val)
|
||||
sample_weight_val = standardize_weights(y_val,
|
||||
sample_weight=sample_weight_val)
|
||||
else:
|
||||
raise Exception("Invalid format for validation data; provide a tuple (X_val, y_val) or (X_val, y_val, sample_weight). \
|
||||
X_val may be a numpy array or a list of numpy arrays depending on your model input.")
|
||||
@@ -470,7 +487,7 @@ class Sequential(Model, containers.Sequential):
|
||||
sample_weight, sample_weight_val = (slice_X(sample_weight, 0, split_at), slice_X(sample_weight, split_at))
|
||||
sample_weight_val = standardize_weights(y_val, sample_weight=sample_weight_val)
|
||||
else:
|
||||
sample_weight_val = np.ones(y_val.shape[:-1] + (1,))
|
||||
sample_weight_val = standardize_weights(y_val)
|
||||
val_ins = X_val + [y_val, sample_weight_val]
|
||||
|
||||
if show_accuracy:
|
||||
@@ -483,7 +500,8 @@ class Sequential(Model, containers.Sequential):
|
||||
sample_weight = standardize_weights(y, class_weight=class_weight, sample_weight=sample_weight)
|
||||
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,
|
||||
return self._fit(f, ins, out_labels=out_labels,
|
||||
batch_size=batch_size, nb_epoch=nb_epoch,
|
||||
verbose=verbose, callbacks=callbacks,
|
||||
val_f=val_f, val_ins=val_ins,
|
||||
shuffle=shuffle, metrics=metrics)
|
||||
@@ -505,7 +523,8 @@ class Sequential(Model, containers.Sequential):
|
||||
else:
|
||||
return (proba > 0.5).astype('int32')
|
||||
|
||||
def evaluate(self, X, y, batch_size=128, show_accuracy=False, verbose=1, sample_weight=None):
|
||||
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)
|
||||
@@ -580,7 +599,7 @@ class Graph(Model, containers.Graph):
|
||||
output = self.outputs[output_name]
|
||||
y_train = output.get_output(True)
|
||||
y_test = output.get_output(False)
|
||||
y = T.zeros_like(y_test)
|
||||
y = K.placeholder(ndim=K.ndim(y_train))
|
||||
ys.append(y)
|
||||
ys_train.append(y_train)
|
||||
ys_test.append(y_test)
|
||||
@@ -590,15 +609,12 @@ class Graph(Model, containers.Graph):
|
||||
else:
|
||||
mask = None
|
||||
|
||||
weight = T.ones_like(y_test)
|
||||
weight = K.placeholder(ndim=1)
|
||||
weights.append(weight)
|
||||
weighted_loss = weighted_objective(objectives.get(loss_fn))
|
||||
train_loss += weighted_loss(y, y_train, weight, mask)
|
||||
test_loss += weighted_loss(y, y_test, weight, mask)
|
||||
|
||||
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 + weights
|
||||
test_ins = ins + ys + weights
|
||||
@@ -611,12 +627,9 @@ class Graph(Model, containers.Graph):
|
||||
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)
|
||||
self._train = K.function(train_ins, [train_loss], updates=updates)
|
||||
self._test = K.function(test_ins, [test_loss])
|
||||
self._predict = K.function(inputs=ins, outputs=ys_test)
|
||||
|
||||
def train_on_batch(self, data, class_weight={}, sample_weight={}):
|
||||
# data is a dictionary mapping output and input names to arrays
|
||||
@@ -624,22 +637,23 @@ class Graph(Model, containers.Graph):
|
||||
sample_weight=sample_weight.get(name),
|
||||
class_weight=class_weight.get(name)) for name in self.output_order]
|
||||
ins = [data[name] for name in self.input_order] + [standardize_y(data[name]) for name in self.output_order] + sample_weight
|
||||
return self._train(*ins)
|
||||
return self._train(ins)
|
||||
|
||||
def test_on_batch(self, data, sample_weight={}):
|
||||
# data is a dictionary mapping input names to arrays
|
||||
sample_weight = [standardize_weights(data[name],
|
||||
sample_weight=sample_weight.get(name)) for name in self.output_order]
|
||||
ins = [data[name] for name in self.input_order] + [standardize_y(data[name]) for name in self.output_order] + sample_weight
|
||||
return self._test(*ins)
|
||||
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)
|
||||
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, class_weight={}, sample_weight={}):
|
||||
validation_split=0., validation_data=None, shuffle=True,
|
||||
class_weight={}, sample_weight={}):
|
||||
X = [data[name] for name in self.input_order]
|
||||
y = [standardize_y(data[name]) for name in self.output_order]
|
||||
|
||||
@@ -653,7 +667,8 @@ class Graph(Model, containers.Graph):
|
||||
val_f = self._test
|
||||
if validation_data:
|
||||
# can't use sample weights with validation data at this point
|
||||
sample_weight = [standardize_weights(validation_data[name]) for name in self.output_order]
|
||||
y_val = [standardize_y(data[name]) for name in self.output_order]
|
||||
sample_weight = [standardize_weights(y_val[i]) for i in range(len(y_val))]
|
||||
val_ins = [validation_data[name] for name in self.input_order] + [standardize_y(validation_data[name]) for name in self.output_order] + sample_weight
|
||||
|
||||
elif 0 < validation_split < 1:
|
||||
|
||||
+18
-23
@@ -1,60 +1,55 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
from six.moves import range
|
||||
|
||||
if theano.config.floatX == 'float64':
|
||||
epsilon = 1.0e-9
|
||||
else:
|
||||
epsilon = 1.0e-7
|
||||
from . import backend as K
|
||||
|
||||
|
||||
def mean_squared_error(y_true, y_pred):
|
||||
return T.sqr(y_pred - y_true).mean(axis=-1)
|
||||
return K.mean(K.square(y_pred - y_true), axis=-1)
|
||||
|
||||
|
||||
def root_mean_squared_error(y_true, y_pred):
|
||||
return K.sqrt(K.mean(K.square(y_pred - y_true), axis=-1))
|
||||
|
||||
|
||||
def mean_absolute_error(y_true, y_pred):
|
||||
return T.abs_(y_pred - y_true).mean(axis=-1)
|
||||
return K.mean(K.abs(y_pred - y_true), 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.
|
||||
diff = K.abs((y_true - y_pred) / K.clip(K.abs(y_true), K._EPSILON, np.inf))
|
||||
return 100. * K.mean(diff, axis=-1)
|
||||
|
||||
|
||||
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)
|
||||
first_log = K.log(K.clip(y_pred, K._EPSILON, np.inf) + 1.)
|
||||
second_log = K.log(K.clip(y_true, K._EPSILON, np.inf) + 1.)
|
||||
return K.mean(K.square(first_log - second_log), axis=-1)
|
||||
|
||||
|
||||
def squared_hinge(y_true, y_pred):
|
||||
return T.sqr(T.maximum(1. - y_true * y_pred, 0.)).mean(axis=-1)
|
||||
return K.mean(K.square(K.maximum(1. - y_true * y_pred, 0.)), axis=-1)
|
||||
|
||||
|
||||
def hinge(y_true, y_pred):
|
||||
return T.maximum(1. - y_true * y_pred, 0.).mean(axis=-1)
|
||||
return K.mean(K.maximum(1. - y_true * y_pred, 0.), 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)
|
||||
cce = T.nnet.categorical_crossentropy(y_pred, y_true)
|
||||
return cce
|
||||
return K.mean(K.categorical_crossentropy(y_pred, y_true), axis=-1)
|
||||
|
||||
|
||||
def binary_crossentropy(y_true, y_pred):
|
||||
y_pred = T.clip(y_pred, epsilon, 1.0 - epsilon)
|
||||
bce = T.nnet.binary_crossentropy(y_pred, y_true).mean(axis=-1)
|
||||
return bce
|
||||
return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)
|
||||
|
||||
|
||||
def poisson_loss(y_true, y_pred):
|
||||
return T.mean(y_pred - y_true * T.log(y_pred + epsilon), axis=-1)
|
||||
return K.mean(y_pred - y_true * K.log(y_pred + K._EPSILON), axis=-1)
|
||||
|
||||
# aliases
|
||||
mse = MSE = mean_squared_error
|
||||
rmse = RMSE = root_mean_squared_error
|
||||
mae = MAE = mean_absolute_error
|
||||
mape = MAPE = mean_absolute_percentage_error
|
||||
msle = MSLE = mean_squared_logarithmic_error
|
||||
|
||||
+59
-58
@@ -1,20 +1,18 @@
|
||||
from __future__ import absolute_import
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
|
||||
from .utils.theano_utils import shared_zeros, shared_scalar, floatX
|
||||
from . import backend as K
|
||||
import numpy as np
|
||||
from .utils.generic_utils import get_from_module
|
||||
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 = K.switch(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 * K.log(p / p_hat)
|
||||
|
||||
|
||||
class Optimizer(object):
|
||||
@@ -23,27 +21,23 @@ class Optimizer(object):
|
||||
self.updates = []
|
||||
|
||||
def get_state(self):
|
||||
return [u[0].get_value() for u in self.updates]
|
||||
return [K.get_value(u[0]) for u in self.updates]
|
||||
|
||||
def set_state(self, value_list):
|
||||
assert len(self.updates) == len(value_list)
|
||||
for u, v in zip(self.updates, value_list):
|
||||
u[0].set_value(floatX(v))
|
||||
K.set_value(u[0], v)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_gradients(self, loss, params):
|
||||
|
||||
grads = T.grad(loss, params)
|
||||
|
||||
grads = K.gradients(loss, params)
|
||||
if hasattr(self, 'clipnorm') and self.clipnorm > 0:
|
||||
norm = T.sqrt(sum([T.sum(g ** 2) for g in grads]))
|
||||
norm = K.sqrt(sum([K.sum(K.square(g)) for g in grads]))
|
||||
grads = [clip_norm(g, self.clipnorm, norm) for g in grads]
|
||||
|
||||
if hasattr(self, 'clipvalue') and self.clipvalue > 0:
|
||||
grads = [T.clip(g, -self.clipvalue, self.clipvalue) for g in grads]
|
||||
|
||||
grads = [K.clip(g, -self.clipvalue, self.clipvalue) for g in grads]
|
||||
return grads
|
||||
|
||||
def get_config(self):
|
||||
@@ -52,13 +46,14 @@ class Optimizer(object):
|
||||
|
||||
class SGD(Optimizer):
|
||||
|
||||
def __init__(self, lr=0.01, momentum=0., decay=0., nesterov=False, *args, **kwargs):
|
||||
def __init__(self, lr=0.01, momentum=0., decay=0., nesterov=False,
|
||||
*args, **kwargs):
|
||||
super(SGD, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = shared_scalar(0)
|
||||
self.lr = shared_scalar(lr)
|
||||
self.momentum = shared_scalar(momentum)
|
||||
self.decay = shared_scalar(decay)
|
||||
self.iterations = K.variable(0.)
|
||||
self.lr = K.variable(lr)
|
||||
self.momentum = K.variable(momentum)
|
||||
self.decay = K.variable(decay)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
@@ -66,7 +61,7 @@ class SGD(Optimizer):
|
||||
self.updates = [(self.iterations, self.iterations + 1.)]
|
||||
|
||||
for p, g, c in zip(params, grads, constraints):
|
||||
m = shared_zeros(p.get_value().shape) # momentum
|
||||
m = K.variable(np.zeros(K.get_value(p).shape)) # momentum
|
||||
v = self.momentum * m - lr * g # velocity
|
||||
self.updates.append((m, v))
|
||||
|
||||
@@ -80,9 +75,9 @@ class SGD(Optimizer):
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(self.lr.get_value()),
|
||||
"momentum": float(self.momentum.get_value()),
|
||||
"decay": float(self.decay.get_value()),
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"momentum": float(K.get_value(self.momentum)),
|
||||
"decay": float(K.get_value(self.decay)),
|
||||
"nesterov": self.nesterov}
|
||||
|
||||
|
||||
@@ -90,26 +85,27 @@ class RMSprop(Optimizer):
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-6, *args, **kwargs):
|
||||
super(RMSprop, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = shared_scalar(lr)
|
||||
self.rho = shared_scalar(rho)
|
||||
self.lr = K.variable(lr)
|
||||
self.rho = K.variable(rho)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
accumulators = [shared_zeros(p.get_value().shape) for p in params]
|
||||
accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
self.updates = []
|
||||
|
||||
for p, g, a, c in zip(params, grads, accumulators, constraints):
|
||||
new_a = self.rho * a + (1 - self.rho) * g ** 2 # update accumulator
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1 - self.rho) * K.square(g)
|
||||
self.updates.append((a, new_a))
|
||||
|
||||
new_p = p - self.lr * g / T.sqrt(new_a + self.epsilon)
|
||||
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
|
||||
self.updates.append((p, c(new_p))) # apply constraints
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(self.lr.get_value()),
|
||||
"rho": float(self.rho.get_value()),
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"rho": float(K.get_value(self.rho)),
|
||||
"epsilon": self.epsilon}
|
||||
|
||||
|
||||
@@ -117,23 +113,23 @@ class Adagrad(Optimizer):
|
||||
def __init__(self, lr=0.01, epsilon=1e-6, *args, **kwargs):
|
||||
super(Adagrad, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = shared_scalar(lr)
|
||||
self.lr = K.variable(lr)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
accumulators = [shared_zeros(p.get_value().shape) for p in params]
|
||||
accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
self.updates = []
|
||||
|
||||
for p, g, a, c in zip(params, grads, accumulators, constraints):
|
||||
new_a = a + g ** 2 # update accumulator
|
||||
new_a = a + K.square(g) # update accumulator
|
||||
self.updates.append((a, new_a))
|
||||
new_p = p - self.lr * g / T.sqrt(new_a + self.epsilon)
|
||||
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
|
||||
self.updates.append((p, c(new_p))) # apply constraints
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(self.lr.get_value()),
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"epsilon": self.epsilon}
|
||||
|
||||
|
||||
@@ -144,35 +140,35 @@ class Adadelta(Optimizer):
|
||||
def __init__(self, lr=1.0, rho=0.95, epsilon=1e-6, *args, **kwargs):
|
||||
super(Adadelta, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = shared_scalar(lr)
|
||||
self.lr = K.variable(lr)
|
||||
|
||||
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]
|
||||
accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
delta_accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
self.updates = []
|
||||
|
||||
for p, g, a, d_a, c in zip(params, grads, accumulators,
|
||||
delta_accumulators, constraints):
|
||||
new_a = self.rho * a + (1 - self.rho) * g ** 2 # update accumulator
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1 - self.rho) * K.square(g)
|
||||
self.updates.append((a, new_a))
|
||||
|
||||
# use the new accumulator and the *old* delta_accumulator
|
||||
update = g * T.sqrt(d_a + self.epsilon) / T.sqrt(new_a +
|
||||
self.epsilon)
|
||||
update = g * K.sqrt(d_a + self.epsilon) / K.sqrt(new_a + self.epsilon)
|
||||
|
||||
new_p = p - self.lr * update
|
||||
self.updates.append((p, c(new_p))) # apply constraints
|
||||
|
||||
# update delta_accumulator
|
||||
new_d_a = self.rho * d_a + (1 - self.rho) * update ** 2
|
||||
new_d_a = self.rho * d_a + (1 - self.rho) * K.square(update)
|
||||
self.updates.append((d_a, new_d_a))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(self.lr.get_value()),
|
||||
"rho": self.rho,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"rho": float(K.get_value(self.rho)),
|
||||
"epsilon": self.epsilon}
|
||||
|
||||
|
||||
@@ -182,26 +178,31 @@ class Adam(Optimizer):
|
||||
|
||||
Default parameters follow those provided in the original paper.
|
||||
'''
|
||||
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-8, *args, **kwargs):
|
||||
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-8,
|
||||
*args, **kwargs):
|
||||
super(Adam, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = shared_scalar(0)
|
||||
self.lr = shared_scalar(lr)
|
||||
self.iterations = K.variable(0)
|
||||
self.lr = K.variable(lr)
|
||||
self.beta_1 = K.variable(beta_1)
|
||||
self.beta_2 = K.variable(beta_2)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [(self.iterations, self.iterations+1.)]
|
||||
|
||||
t = self.iterations + 1
|
||||
lr_t = self.lr * T.sqrt(1-self.beta_2**t)/(1-self.beta_1**t)
|
||||
lr_t = self.lr * K.sqrt(1 - K.pow(self.beta_2, t)) / (1 - K.pow(self.beta_1, t))
|
||||
|
||||
for p, g, c in zip(params, grads, constraints):
|
||||
m = theano.shared(p.get_value() * 0.) # zero init of moment
|
||||
v = theano.shared(p.get_value() * 0.) # zero init of velocity
|
||||
# zero init of moment
|
||||
m = K.variable(np.zeros(K.get_value(p).shape))
|
||||
# zero init of velocity
|
||||
v = K.variable(np.zeros(K.get_value(p).shape))
|
||||
|
||||
m_t = (self.beta_1 * m) + (1 - self.beta_1) * g
|
||||
v_t = (self.beta_2 * v) + (1 - self.beta_2) * (g**2)
|
||||
p_t = p - lr_t * m_t / (T.sqrt(v_t) + self.epsilon)
|
||||
v_t = (self.beta_2 * v) + (1 - self.beta_2) * K.square(g)
|
||||
p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)
|
||||
|
||||
self.updates.append((m, m_t))
|
||||
self.updates.append((v, v_t))
|
||||
@@ -210,9 +211,9 @@ class Adam(Optimizer):
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(self.lr.get_value()),
|
||||
"beta_1": self.beta_1,
|
||||
"beta_2": self.beta_2,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"beta_1": float(K.get_value(self.beta_1)),
|
||||
"beta_2": float(K.get_value(self.beta_2)),
|
||||
"epsilon": self.epsilon}
|
||||
|
||||
# aliases
|
||||
@@ -224,5 +225,5 @@ adam = Adam
|
||||
|
||||
|
||||
def get(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'optimizer', instantiate=True,
|
||||
kwargs=kwargs)
|
||||
return get_from_module(identifier, globals(), 'optimizer',
|
||||
instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -214,17 +214,14 @@ class ImageDataGenerator(object):
|
||||
# channel shifting
|
||||
return x
|
||||
|
||||
|
||||
def fit(self, X,
|
||||
augment=False, # fit on randomly augmented samples
|
||||
rounds=1, # if augment, how many augmentation passes over the data do we use
|
||||
seed=None
|
||||
):
|
||||
def fit(self, X,
|
||||
augment=False, # fit on randomly augmented samples
|
||||
rounds=1, # if augment, how many augmentation passes over the data do we use
|
||||
seed=None):
|
||||
'''
|
||||
Required for featurewise_center, featurewise_std_normalization and zca_whitening.
|
||||
'''
|
||||
X = np.copy(X)
|
||||
|
||||
if augment:
|
||||
aX = np.zeros(tuple([rounds*X.shape[0]]+list(X.shape)[1:]))
|
||||
for r in range(rounds):
|
||||
@@ -247,5 +244,3 @@ class ImageDataGenerator(object):
|
||||
sigma = np.dot(flatX.T, flatX) / flatX.shape[1]
|
||||
U, S, V = linalg.svd(sigma)
|
||||
self.principal_components = np.dot(np.dot(U, np.diag(1. / np.sqrt(S + fudge))), U.T)
|
||||
|
||||
|
||||
|
||||
@@ -24,6 +24,8 @@ def pad_sequences(sequences, maxlen=None, dtype='int32', padding='pre', truncati
|
||||
|
||||
x = (np.ones((nb_samples, maxlen)) * value).astype(dtype)
|
||||
for idx, s in enumerate(sequences):
|
||||
if len(s) == 0:
|
||||
continue # empty list was found
|
||||
if truncating == 'pre':
|
||||
trunc = s[-maxlen:]
|
||||
elif truncating == 'post':
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from __future__ import absolute_import
|
||||
import theano.tensor as T
|
||||
from . import backend as K
|
||||
|
||||
|
||||
class Regularizer(object):
|
||||
@@ -25,8 +25,8 @@ class WeightRegularizer(Regularizer):
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
loss += T.sum(abs(self.p)) * self.l1
|
||||
loss += T.sum(self.p ** 2) * self.l2
|
||||
loss += K.sum(K.abs(self.p)) * self.l1
|
||||
loss += K.sum(K.square(self.p)) * self.l2
|
||||
return loss
|
||||
|
||||
def get_config(self):
|
||||
@@ -44,8 +44,9 @@ class ActivityRegularizer(Regularizer):
|
||||
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))
|
||||
output = self.layer.get_output(True)
|
||||
loss += self.l1 * K.sum(K.mean(K.abs(output), axis=0))
|
||||
loss += self.l2 * K.sum(K.mean(K.square(output), axis=0))
|
||||
return loss
|
||||
|
||||
def get_config(self):
|
||||
@@ -81,4 +82,5 @@ 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)
|
||||
return get_from_module(identifier, globals(), 'regularizer',
|
||||
instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -1,32 +1,35 @@
|
||||
from __future__ import print_function
|
||||
import inspect
|
||||
import numpy as np
|
||||
import theano
|
||||
import copy
|
||||
|
||||
from ..layers.advanced_activations import LeakyReLU, PReLU
|
||||
from ..layers.core import Dense, Merge, Dropout, Activation, Reshape, Flatten, RepeatVector, Layer, AutoEncoder, Masking, Permute
|
||||
from ..layers.core import ActivityRegularization, TimeDistributedDense, AutoEncoder, MaxoutDense
|
||||
from ..layers.convolutional import Convolution1D, Convolution2D, MaxPooling1D, MaxPooling2D, ZeroPadding2D
|
||||
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.advanced_activations import *
|
||||
from ..layers.core import *
|
||||
from ..layers.convolutional import *
|
||||
from ..layers.embeddings import *
|
||||
from ..layers.noise import *
|
||||
from ..layers.normalization import *
|
||||
from ..layers.recurrent import *
|
||||
from ..layers import containers
|
||||
from .. import regularizers
|
||||
from .. import constraints
|
||||
|
||||
|
||||
def container_from_config(original_layer_dict, custom_layers={}):
|
||||
def container_from_config(original_layer_dict, custom_objects={}):
|
||||
layer_dict = copy.deepcopy(original_layer_dict)
|
||||
name = layer_dict.get('name')
|
||||
|
||||
# Insert custom layers into globals so they can
|
||||
# be accessed by `get_from_module`.
|
||||
for cls_key in custom_objects:
|
||||
globals()[cls_key] = custom_objects[cls_key]
|
||||
|
||||
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, custom_layers=custom_layers)
|
||||
init_layer = container_from_config(layer)
|
||||
layer_list.append(init_layer)
|
||||
merge_layer = Merge(layer_list, mode)
|
||||
return merge_layer
|
||||
@@ -35,7 +38,7 @@ def container_from_config(original_layer_dict, custom_layers={}):
|
||||
layers = layer_dict.get('layers')
|
||||
layer_list = []
|
||||
for layer in layers:
|
||||
init_layer = container_from_config(layer, custom_layers=custom_layers)
|
||||
init_layer = container_from_config(layer)
|
||||
layer_list.append(init_layer)
|
||||
seq_layer = containers.Sequential(layer_list)
|
||||
return seq_layer
|
||||
@@ -49,8 +52,7 @@ def container_from_config(original_layer_dict, custom_layers={}):
|
||||
|
||||
nodes = layer_dict.get('node_config')
|
||||
for node in nodes:
|
||||
layer = container_from_config(layer_dict['nodes'].get(node['name']),
|
||||
custom_layers=custom_layers)
|
||||
layer = container_from_config(layer_dict['nodes'].get(node['name']))
|
||||
node['layer'] = layer
|
||||
graph_layer.add_node(**node)
|
||||
|
||||
@@ -60,10 +62,8 @@ def container_from_config(original_layer_dict, custom_layers={}):
|
||||
return graph_layer
|
||||
|
||||
elif name == 'AutoEncoder':
|
||||
kwargs = {'encoder': container_from_config(layer_dict.get('encoder_config'),
|
||||
custom_layers=custom_layers),
|
||||
'decoder': container_from_config(layer_dict.get('decoder_config'),
|
||||
custom_layers=custom_layers)}
|
||||
kwargs = {'encoder': container_from_config(layer_dict.get('encoder_config')),
|
||||
'decoder': container_from_config(layer_dict.get('decoder_config'))}
|
||||
for kwarg in ['output_reconstruction', 'weights']:
|
||||
if kwarg in layer_dict:
|
||||
kwargs[kwarg] = layer_dict[kwarg]
|
||||
@@ -73,59 +73,21 @@ def container_from_config(original_layer_dict, custom_layers={}):
|
||||
layer_dict.pop('name')
|
||||
|
||||
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')
|
||||
vname = 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)]:
|
||||
elif vname in [x for x, y in inspect.getmembers(regularizers, predicate=inspect.isclass)]:
|
||||
layer_dict[k] = regularizers.get(vname, v)
|
||||
else:
|
||||
# not a regularizer of constraint, don't touch it
|
||||
v['name'] = vname
|
||||
|
||||
base_layer = get_layer(name, layer_dict, custom_layers=custom_layers)
|
||||
base_layer = get_layer(name, layer_dict)
|
||||
return base_layer
|
||||
|
||||
|
||||
def print_layer_shapes(model, input_shapes):
|
||||
"""
|
||||
Utility function to print the shape of the output at each layer of a Model
|
||||
|
||||
Arguments:
|
||||
model: instance of Model / Merge
|
||||
input_shapes: dict (Graph), list of tuples (Merge) or tuple (Sequential)
|
||||
"""
|
||||
if model.__class__.__name__ in ['Sequential', 'Merge']:
|
||||
# in this case input_shapes is a tuple, or a list [shape1, shape2]
|
||||
if not isinstance(input_shapes[0], tuple):
|
||||
input_shapes = [input_shapes]
|
||||
|
||||
inputs = model.get_input(train=False)
|
||||
if not isinstance(inputs, list):
|
||||
inputs = [inputs]
|
||||
input_dummy = [np.zeros(shape, dtype=np.float32)
|
||||
for shape in input_shapes]
|
||||
layers = model.layers
|
||||
|
||||
elif model.__class__.__name__ == 'Graph':
|
||||
# in this case input_shapes is a dictionary
|
||||
inputs = [model.inputs[name].input
|
||||
for name in model.input_order]
|
||||
input_dummy = [np.zeros(input_shapes[name], dtype=np.float32)
|
||||
for name in model.input_order]
|
||||
layers = [model.nodes[c['name']] for c in model.node_config]
|
||||
|
||||
print("input shapes : ", input_shapes)
|
||||
for l in layers:
|
||||
shape_f = theano.function(inputs, l.get_output(train=False).shape,
|
||||
on_unused_input='ignore')
|
||||
out_shape = tuple(shape_f(*input_dummy))
|
||||
config = l.get_config()
|
||||
print('shape after %s: %s' % (config['name'], out_shape))
|
||||
|
||||
|
||||
from .generic_utils import get_from_module
|
||||
def get_layer(identifier, kwargs=None, custom_layers={}):
|
||||
# Insert custom layers into globals so they can be accessed by `get_from_module`.
|
||||
for cls_key in custom_layers:
|
||||
globals()[cls_key] = custom_layers[cls_key]
|
||||
return get_from_module(identifier, globals(), 'layer', instantiate=True, kwargs=kwargs)
|
||||
def get_layer(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'layer',
|
||||
instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -34,7 +34,6 @@ def binary_logloss(p, y):
|
||||
|
||||
|
||||
def multiclass_logloss(P, Y):
|
||||
score = 0.
|
||||
npreds = [P[i][Y[i]-1] for i in range(len(Y))]
|
||||
score = -(1. / len(Y)) * np.sum(np.log(npreds))
|
||||
return score
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
from __future__ import absolute_import
|
||||
import numpy as np
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
|
||||
|
||||
def floatX(X):
|
||||
return np.asarray(X, dtype=theano.config.floatX)
|
||||
|
||||
|
||||
def sharedX(X, dtype=theano.config.floatX, name=None):
|
||||
return theano.shared(np.asarray(X, dtype=dtype), name=name)
|
||||
|
||||
|
||||
def shared_zeros(shape, dtype=theano.config.floatX, name=None):
|
||||
return sharedX(np.zeros(shape), dtype=dtype, name=name)
|
||||
|
||||
|
||||
def shared_scalar(val=0., dtype=theano.config.floatX, name=None):
|
||||
return theano.shared(np.cast[dtype](val))
|
||||
|
||||
|
||||
def shared_ones(shape, dtype=theano.config.floatX, name=None):
|
||||
return sharedX(np.ones(shape), dtype=dtype, name=name)
|
||||
|
||||
|
||||
def alloc_zeros_matrix(*dims):
|
||||
return T.alloc(np.cast[theano.config.floatX](0.), *dims)
|
||||
|
||||
|
||||
def ndim_tensor(ndim):
|
||||
if ndim == 1:
|
||||
return T.vector()
|
||||
elif ndim == 2:
|
||||
return T.matrix()
|
||||
elif ndim == 3:
|
||||
return T.tensor3()
|
||||
elif ndim == 4:
|
||||
return T.tensor4()
|
||||
return T.matrix()
|
||||
|
||||
|
||||
def on_gpu():
|
||||
return theano.config.device[:3] == 'gpu'
|
||||
@@ -1,10 +1,9 @@
|
||||
import pydot
|
||||
# old pydot will not work with python3, must use one
|
||||
# that works with python3 such as pydot2 or pydot
|
||||
from keras.models import Sequential, Graph
|
||||
|
||||
|
||||
def plot(model, to_file='model.png'):
|
||||
|
||||
def to_graph(model):
|
||||
graph = pydot.Dot(graph_type='digraph')
|
||||
if type(model) == Sequential:
|
||||
previous_node = None
|
||||
@@ -20,8 +19,6 @@ def plot(model, to_file='model.png'):
|
||||
if previous_node:
|
||||
graph.add_edge(pydot.Edge(previous_node, current_node))
|
||||
previous_node = current_node
|
||||
graph.write_png(to_file)
|
||||
|
||||
elif type(model) == Graph:
|
||||
# don't need to append number for names since all nodes labeled
|
||||
for input_node in model.input_config:
|
||||
@@ -37,5 +34,8 @@ def plot(model, to_file='model.png'):
|
||||
graph.add_edge(pydot.Edge(e, node['name']))
|
||||
else:
|
||||
graph.add_edge(pydot.Edge(node['input'], node['name']))
|
||||
return graph
|
||||
|
||||
graph.write_png(to_file)
|
||||
def plot(model, to_file='model.png'):
|
||||
graph = to_graph(model)
|
||||
graph.write_png(to_file)
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ setup(name='Keras',
|
||||
url='https://github.com/fchollet/keras',
|
||||
download_url='https://github.com/fchollet/keras/tarball/0.2.0',
|
||||
license='MIT',
|
||||
install_requires=['theano', 'pyyaml'],
|
||||
install_requires=['theano', 'pyyaml', 'six'],
|
||||
extras_require={
|
||||
'h5py': ['h5py'],
|
||||
},
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
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,335 @@
|
||||
import sys
|
||||
import unittest
|
||||
from numpy.testing import assert_allclose
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
if sys.version_info.major == 2:
|
||||
from keras.backend import theano_backend as KTH
|
||||
from keras.backend import tensorflow_backend as KTF
|
||||
|
||||
|
||||
def check_single_tensor_operation(function_name, input_shape, **kwargs):
|
||||
val = np.random.random(input_shape) - 0.5
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
|
||||
zth = KTH.eval(getattr(KTH, function_name)(xth, **kwargs))
|
||||
ztf = KTF.eval(getattr(KTF, function_name)(xtf, **kwargs))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-06)
|
||||
|
||||
|
||||
def check_two_tensor_operation(function_name, x_input_shape,
|
||||
y_input_shape, **kwargs):
|
||||
xval = np.random.random(x_input_shape) - 0.5
|
||||
xth = KTH.variable(xval)
|
||||
xtf = KTF.variable(xval)
|
||||
|
||||
yval = np.random.random(y_input_shape) - 0.5
|
||||
yth = KTH.variable(yval)
|
||||
ytf = KTF.variable(yval)
|
||||
|
||||
zth = KTH.eval(getattr(KTH, function_name)(xth, yth, **kwargs))
|
||||
ztf = KTF.eval(getattr(KTF, function_name)(xtf, ytf, **kwargs))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-06)
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.version_info.major != 2, reason="Requires Python 2.7")
|
||||
class TestBackend(unittest.TestCase):
|
||||
|
||||
def test_linear_operations(self):
|
||||
check_two_tensor_operation('dot', (4, 2), (2, 4))
|
||||
check_single_tensor_operation('transpose', (4, 2))
|
||||
|
||||
def test_shape_operations(self):
|
||||
# concatenate
|
||||
xval = np.random.random((4, 3))
|
||||
xth = KTH.variable(xval)
|
||||
xtf = KTF.variable(xval)
|
||||
yval = np.random.random((4, 2))
|
||||
yth = KTH.variable(yval)
|
||||
ytf = KTF.variable(yval)
|
||||
zth = KTH.eval(KTH.concatenate([xth, yth], axis=-1))
|
||||
ztf = KTF.eval(KTF.concatenate([xtf, ytf], axis=-1))
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-06)
|
||||
|
||||
check_single_tensor_operation('reshape', (4, 2), shape=(8, 1))
|
||||
check_single_tensor_operation('permute_dimensions', (4, 2, 3),
|
||||
pattern=(2, 0, 1))
|
||||
check_single_tensor_operation('repeat', (4, 1), n=3)
|
||||
check_single_tensor_operation('flatten', (4, 1))
|
||||
check_single_tensor_operation('expand_dims', (4, 3), dim=-1)
|
||||
check_single_tensor_operation('expand_dims', (4, 3, 2), dim=1)
|
||||
check_single_tensor_operation('squeeze', (4, 3, 1), axis=2)
|
||||
|
||||
def test_value_manipulation(self):
|
||||
val = np.random.random((4, 2))
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
|
||||
# get_value
|
||||
valth = KTH.get_value(xth)
|
||||
valtf = KTF.get_value(xtf)
|
||||
assert valtf.shape == valth.shape
|
||||
assert_allclose(valth, valtf, atol=1e-06)
|
||||
|
||||
# set_value
|
||||
val = np.random.random((4, 2))
|
||||
KTH.set_value(xth, val)
|
||||
KTF.set_value(xtf, val)
|
||||
|
||||
valth = KTH.get_value(xth)
|
||||
valtf = KTF.get_value(xtf)
|
||||
assert valtf.shape == valth.shape
|
||||
assert_allclose(valth, valtf, atol=1e-06)
|
||||
|
||||
# count_params
|
||||
assert KTH.count_params(xth) == KTF.count_params(xtf)
|
||||
|
||||
def test_elementwise_operations(self):
|
||||
check_single_tensor_operation('max', (4, 2))
|
||||
check_single_tensor_operation('max', (4, 2), axis=1, keepdims=True)
|
||||
|
||||
check_single_tensor_operation('min', (4, 2))
|
||||
check_single_tensor_operation('min', (4, 2), axis=1, keepdims=True)
|
||||
|
||||
check_single_tensor_operation('mean', (4, 2))
|
||||
check_single_tensor_operation('mean', (4, 2), axis=1, keepdims=True)
|
||||
check_single_tensor_operation('mean', (4, 2, 3), axis=-1, keepdims=True)
|
||||
|
||||
check_single_tensor_operation('std', (4, 2))
|
||||
check_single_tensor_operation('std', (4, 2), axis=1, keepdims=True)
|
||||
|
||||
check_single_tensor_operation('prod', (4, 2))
|
||||
check_single_tensor_operation('prod', (4, 2), axis=1, keepdims=True)
|
||||
|
||||
# does not work yet, wait for bool <-> int casting in TF (coming soon)
|
||||
# check_single_tensor_operation('any', (4, 2))
|
||||
# check_single_tensor_operation('any', (4, 2), axis=1, keepdims=True)
|
||||
|
||||
check_single_tensor_operation('argmax', (4, 2))
|
||||
check_single_tensor_operation('argmax', (4, 2), axis=1)
|
||||
|
||||
check_single_tensor_operation('argmin', (4, 2))
|
||||
check_single_tensor_operation('argmin', (4, 2), axis=1)
|
||||
|
||||
check_single_tensor_operation('square', (4, 2))
|
||||
check_single_tensor_operation('abs', (4, 2))
|
||||
check_single_tensor_operation('sqrt', (4, 2))
|
||||
check_single_tensor_operation('exp', (4, 2))
|
||||
check_single_tensor_operation('log', (4, 2))
|
||||
check_single_tensor_operation('round', (4, 2))
|
||||
check_single_tensor_operation('pow', (4, 2), a=3)
|
||||
check_single_tensor_operation('clip', (4, 2), min_value=0.4,
|
||||
max_value=0.6)
|
||||
|
||||
# two-tensor ops
|
||||
check_two_tensor_operation('equal', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('maximum', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('minimum', (4, 2), (4, 2))
|
||||
|
||||
def test_gradient(self):
|
||||
val = np.random.random((4, 2))
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
|
||||
expth = xth * KTH.exp(xth)
|
||||
exptf = xtf * KTF.exp(xtf)
|
||||
lossth = KTH.sum(expth)
|
||||
losstf = KTF.sum(exptf)
|
||||
|
||||
gradth = KTH.gradients(lossth, [expth])
|
||||
gradtf = KTF.gradients(losstf, [exptf])
|
||||
|
||||
zth = KTH.eval(gradth[0])
|
||||
ztf = KTF.eval(gradtf[0])
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-06)
|
||||
|
||||
def test_function(self):
|
||||
val = np.random.random((4, 2))
|
||||
input_val = np.random.random((4, 2))
|
||||
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
yth = KTH.placeholder(ndim=2)
|
||||
ytf = KTF.placeholder(ndim=2)
|
||||
|
||||
exp_th = KTH.square(xth) + yth
|
||||
exp_tf = KTF.square(xtf) + ytf
|
||||
|
||||
update_th = xth * 2
|
||||
update_tf = xtf * 2
|
||||
fth = KTH.function([yth], [exp_th], updates=[(xth, update_th)])
|
||||
ftf = KTF.function([ytf], [exp_tf], updates=[(xtf, update_tf)])
|
||||
|
||||
function_outputs_th = fth([input_val])[0]
|
||||
function_outputs_tf = ftf([input_val])[0]
|
||||
assert function_outputs_th.shape == function_outputs_tf.shape
|
||||
assert_allclose(function_outputs_th, function_outputs_tf, atol=1e-06)
|
||||
|
||||
new_val_th = KTH.get_value(xth)
|
||||
new_val_tf = KTF.get_value(xtf)
|
||||
assert new_val_th.shape == new_val_tf.shape
|
||||
assert_allclose(new_val_th, new_val_tf, atol=1e-06)
|
||||
|
||||
def test_rnn(self):
|
||||
# implement a simple RNN
|
||||
input_dim = 8
|
||||
output_dim = 4
|
||||
timesteps = 5
|
||||
|
||||
input_val = np.random.random((32, timesteps, input_dim))
|
||||
init_state_val = np.random.random((32, output_dim))
|
||||
W_i_val = np.random.random((input_dim, output_dim))
|
||||
W_o_val = np.random.random((output_dim, output_dim))
|
||||
|
||||
def rnn_step_fn(input_dim, output_dim, K):
|
||||
W_i = K.variable(W_i_val)
|
||||
W_o = K.variable(W_o_val)
|
||||
|
||||
def step_function(x, states):
|
||||
assert len(states) == 1
|
||||
prev_output = states[0]
|
||||
output = K.dot(x, W_i) + K.dot(prev_output, W_o)
|
||||
return output, [output]
|
||||
return step_function
|
||||
|
||||
th_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTH)
|
||||
inputs = KTH.variable(input_val)
|
||||
initial_states = [KTH.variable(init_state_val)]
|
||||
last_output, outputs, new_states = KTH.rnn(th_rnn_step_fn, inputs,
|
||||
initial_states,
|
||||
go_backwards=False,
|
||||
masking=False)
|
||||
th_last_output = KTH.eval(last_output)
|
||||
th_outputs = KTH.eval(outputs)
|
||||
assert len(new_states) == 1
|
||||
th_state = KTH.eval(new_states[0])
|
||||
|
||||
tf_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTF)
|
||||
inputs = KTF.variable(input_val)
|
||||
initial_states = [KTF.variable(init_state_val)]
|
||||
last_output, outputs, new_states = KTF.rnn(tf_rnn_step_fn, inputs,
|
||||
initial_states,
|
||||
go_backwards=False,
|
||||
masking=False)
|
||||
tf_last_output = KTF.eval(last_output)
|
||||
tf_outputs = KTF.eval(outputs)
|
||||
assert len(new_states) == 1
|
||||
tf_state = KTF.eval(new_states[0])
|
||||
|
||||
assert_allclose(tf_last_output, th_last_output, atol=1e-06)
|
||||
assert_allclose(tf_outputs, th_outputs, atol=1e-06)
|
||||
assert_allclose(tf_state, th_state, atol=1e-06)
|
||||
|
||||
def test_switch(self):
|
||||
val = np.random.random()
|
||||
xth = KTH.variable(val)
|
||||
xth = KTH.switch(xth >= 0.5, xth * 0.1, xth * 0.2)
|
||||
|
||||
xtf = KTF.variable(val)
|
||||
xtf = KTF.switch(xtf >= 0.5, xtf * 0.1, xtf * 0.2)
|
||||
|
||||
zth = KTH.eval(xth)
|
||||
ztf = KTF.eval(xtf)
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-06)
|
||||
|
||||
def test_nn_operations(self):
|
||||
check_single_tensor_operation('relu', (4, 2), alpha=0.1, max_value=0.5)
|
||||
check_single_tensor_operation('softmax', (4, 10))
|
||||
check_single_tensor_operation('softplus', (4, 10))
|
||||
|
||||
check_single_tensor_operation('sigmoid', (4, 2))
|
||||
check_single_tensor_operation('hard_sigmoid', (4, 2))
|
||||
check_single_tensor_operation('tanh', (4, 2))
|
||||
|
||||
# dropout
|
||||
val = np.random.random((20, 20))
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
zth = KTH.eval(KTH.dropout(xth, level=0.2))
|
||||
ztf = KTF.eval(KTF.dropout(xtf, level=0.2))
|
||||
assert zth.shape == ztf.shape
|
||||
# dropout patterns are different, only check mean
|
||||
assert np.abs(zth.mean() - ztf.mean()) < 0.05
|
||||
|
||||
check_two_tensor_operation('binary_crossentropy', (4, 2), (4, 2), from_logits=True)
|
||||
check_two_tensor_operation('categorical_crossentropy', (4, 2), (4, 2), from_logits=True)
|
||||
check_two_tensor_operation('binary_crossentropy', (4, 2), (4, 2), from_logits=False)
|
||||
|
||||
check_two_tensor_operation('categorical_crossentropy', (4, 2), (4, 2), from_logits=False)
|
||||
|
||||
# def test_conv2d(self):
|
||||
# '''conv2d works "properly" with Theano and TF but outputs different
|
||||
# values in each case. Cause unclear (input / kernel shape format?)
|
||||
# '''
|
||||
# # TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# check_two_tensor_operation('conv2d', (5, 3, 10, 12), (4, 3, 2, 2),
|
||||
# strides=(1, 1), border_mode='valid')
|
||||
# check_two_tensor_operation('conv2d', (5, 3, 10, 12), (4, 3, 2, 2),
|
||||
# strides=(1, 1), border_mode='same')
|
||||
|
||||
# # TF kernel shape: (rows, cols, input_depth, depth)
|
||||
# check_two_tensor_operation('conv2d', (5, 10, 12, 3), (2, 2, 3, 4),
|
||||
# strides=(1, 1), border_mode='valid', dim_ordering='tf')
|
||||
# check_two_tensor_operation('conv2d', (5, 10, 12, 3), (2, 2, 3, 4),
|
||||
# strides=(1, 1), border_mode='same', dim_ordering='tf')
|
||||
|
||||
# check_two_tensor_operation('conv2d', (5, 3, 10, 12), (4, 3, 3, 3),
|
||||
# strides=(1, 1), border_mode='valid')
|
||||
# check_two_tensor_operation('conv2d', (5, 3, 10, 12), (4, 3, 3, 3),
|
||||
# strides=(1, 1), border_mode='same')
|
||||
|
||||
# check_two_tensor_operation('conv2d', (5, 3, 10, 12), (4, 3, 3, 3),
|
||||
# strides=(2, 2), border_mode='valid')
|
||||
|
||||
# def test_maxpool2d(self):
|
||||
# '''maxpool2d works "properly" with Theano and TF but outputs different
|
||||
# values in each case. Cause unclear (input shape format?)
|
||||
# '''
|
||||
# check_single_tensor_operation('maxpool2d', (5, 3, 10, 12), pool_size=(2, 2),
|
||||
# strides=(1, 1), border_mode='valid')
|
||||
|
||||
# check_single_tensor_operation('maxpool2d', (5, 3, 9, 11), pool_size=(2, 2),
|
||||
# strides=(1, 1), border_mode='valid')
|
||||
|
||||
# check_single_tensor_operation('maxpool2d', (5, 3, 9, 11), pool_size=(2, 3),
|
||||
# strides=(1, 1), border_mode='valid')
|
||||
|
||||
def test_random_normal(self):
|
||||
mean = 0.
|
||||
std = 1.
|
||||
rand = KTF.get_value(KTF.random_normal((1000, 1000), mean=mean, std=std))
|
||||
assert(rand.shape == (1000, 1000))
|
||||
assert(np.abs(np.mean(rand) - mean) < 0.01)
|
||||
assert(np.abs(np.std(rand) - std) < 0.01)
|
||||
|
||||
rand = KTF.get_value(KTF.random_normal((1000, 1000), mean=mean, std=std))
|
||||
assert(rand.shape == (1000, 1000))
|
||||
assert(np.abs(np.mean(rand) - mean) < 0.01)
|
||||
assert(np.abs(np.std(rand) - std) < 0.01)
|
||||
|
||||
def test_random_uniform(self):
|
||||
mean = 0.
|
||||
std = 1.
|
||||
rand = KTF.get_value(KTF.random_normal((1000, 1000), mean=mean, std=std))
|
||||
assert(rand.shape == (1000, 1000))
|
||||
assert(np.abs(np.mean(rand) - mean) < 0.01)
|
||||
assert(np.abs(np.std(rand) - std) < 0.01)
|
||||
|
||||
rand = KTF.get_value(KTF.random_normal((1000, 1000), mean=mean, std=std))
|
||||
assert(rand.shape == (1000, 1000))
|
||||
assert(np.abs(np.mean(rand) - mean) < 0.01)
|
||||
assert(np.abs(np.std(rand) - std) < 0.01)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
+60
-57
@@ -1,8 +1,8 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
import theano
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import convolutional
|
||||
|
||||
|
||||
@@ -14,31 +14,35 @@ class TestConvolutions(unittest.TestCase):
|
||||
filter_length = 6
|
||||
nb_filter = 5
|
||||
|
||||
weights_in = [np.ones((nb_filter, input_dim, filter_length, 1)), np.ones(nb_filter)]
|
||||
weights_in = [np.ones((nb_filter, input_dim, filter_length, 1)),
|
||||
np.ones(nb_filter)]
|
||||
|
||||
input = np.ones((nb_samples, nb_steps, input_dim))
|
||||
for weight in [None, weights_in]:
|
||||
for border_mode in ['valid', 'full', 'same']:
|
||||
for subsample_length in [1, 3]:
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample_length in [1]:
|
||||
if border_mode == 'same' and subsample_length != 1:
|
||||
continue
|
||||
for W_regularizer in [None, 'l2']:
|
||||
for b_regularizer in [None, 'l2']:
|
||||
for act_regularizer in [None, 'l2']:
|
||||
layer = convolutional.Convolution1D(
|
||||
nb_filter, filter_length, weights=weight,
|
||||
border_mode=border_mode, W_regularizer=W_regularizer,
|
||||
b_regularizer=b_regularizer, activity_regularizer=act_regularizer,
|
||||
subsample_length=subsample_length, input_shape=(None, input_dim))
|
||||
nb_filter, filter_length,
|
||||
weights=weight,
|
||||
border_mode=border_mode,
|
||||
W_regularizer=W_regularizer,
|
||||
b_regularizer=b_regularizer,
|
||||
activity_regularizer=act_regularizer,
|
||||
subsample_length=subsample_length,
|
||||
input_shape=(None, input_dim))
|
||||
|
||||
layer.input = theano.shared(value=input)
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
out = layer.get_output(train).eval()
|
||||
out = K.eval(layer.get_output(train))
|
||||
assert input.shape[0] == out.shape[0]
|
||||
if border_mode == 'same' and subsample_length == 1:
|
||||
assert input.shape[1] == out.shape[1]
|
||||
|
||||
config = layer.get_config()
|
||||
layer.get_config()
|
||||
|
||||
def test_maxpooling_1d(self):
|
||||
nb_samples = 9
|
||||
@@ -46,14 +50,13 @@ class TestConvolutions(unittest.TestCase):
|
||||
input_dim = 10
|
||||
|
||||
input = np.ones((nb_samples, nb_steps, input_dim))
|
||||
for ignore_border in [True, False]:
|
||||
for stride in [1, 2]:
|
||||
layer = convolutional.MaxPooling1D(stride=stride, ignore_border=ignore_border)
|
||||
layer.input = theano.shared(value=input)
|
||||
for train in [True, False]:
|
||||
layer.get_output(train).eval()
|
||||
|
||||
config = layer.get_config()
|
||||
for stride in [1, 2]:
|
||||
layer = convolutional.MaxPooling1D(stride=stride,
|
||||
border_mode='valid')
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
K.eval(layer.get_output(train))
|
||||
layer.get_config()
|
||||
|
||||
def test_convolution_2d(self):
|
||||
nb_samples = 8
|
||||
@@ -69,26 +72,29 @@ class TestConvolutions(unittest.TestCase):
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_nb_row, input_nb_col))
|
||||
for weight in [None, weights_in]:
|
||||
for border_mode in ['valid', 'full', 'same']:
|
||||
for subsample in [(1, 1), (2, 3)]:
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample in [(1, 1), (2, 2)]:
|
||||
if border_mode == 'same' and subsample != (1, 1):
|
||||
continue
|
||||
for W_regularizer in [None, 'l2']:
|
||||
for b_regularizer in [None, 'l2']:
|
||||
for act_regularizer in [None, 'l2']:
|
||||
layer = convolutional.Convolution2D(
|
||||
nb_filter, nb_row, nb_col, weights=weight,
|
||||
border_mode=border_mode, W_regularizer=W_regularizer,
|
||||
b_regularizer=b_regularizer, activity_regularizer=act_regularizer,
|
||||
subsample=subsample, input_shape=(stack_size, None, None))
|
||||
nb_filter, nb_row, nb_col,
|
||||
weights=weight,
|
||||
border_mode=border_mode,
|
||||
W_regularizer=W_regularizer,
|
||||
b_regularizer=b_regularizer,
|
||||
activity_regularizer=act_regularizer,
|
||||
subsample=subsample,
|
||||
input_shape=(stack_size, None, None))
|
||||
|
||||
layer.input = theano.shared(value=input)
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
out = layer.get_output(train).eval()
|
||||
out = K.eval(layer.get_output(train))
|
||||
if border_mode == 'same' and subsample == (1, 1):
|
||||
assert out.shape[2:] == input.shape[2:]
|
||||
|
||||
config = layer.get_config()
|
||||
layer.get_config()
|
||||
|
||||
def test_maxpooling_2d(self):
|
||||
nb_samples = 9
|
||||
@@ -98,14 +104,14 @@ class TestConvolutions(unittest.TestCase):
|
||||
pool_size = (3, 3)
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_nb_row, input_nb_col))
|
||||
for ignore_border in [True, False]:
|
||||
for stride in [(1, 1), (2, 2)]:
|
||||
layer = convolutional.MaxPooling2D(stride=stride, ignore_border=ignore_border, pool_size=pool_size)
|
||||
layer.input = theano.shared(value=input)
|
||||
for train in [True, False]:
|
||||
layer.get_output(train).eval()
|
||||
|
||||
config = layer.get_config()
|
||||
for strides in [(1, 1), (2, 2)]:
|
||||
layer = convolutional.MaxPooling2D(strides=strides,
|
||||
border_mode='valid',
|
||||
pool_size=pool_size)
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
K.eval(layer.get_output(train))
|
||||
layer.get_config()
|
||||
|
||||
def test_zero_padding_2d(self):
|
||||
nb_samples = 9
|
||||
@@ -115,32 +121,30 @@ class TestConvolutions(unittest.TestCase):
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_nb_row, input_nb_col))
|
||||
layer = convolutional.ZeroPadding2D(padding=(2, 2))
|
||||
layer.input = theano.shared(value=input)
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
out = layer.get_output(train).eval()
|
||||
out = K.eval(layer.get_output(train))
|
||||
for offset in [0, 1, -1, -2]:
|
||||
assert_allclose(out[:, :, offset, :], 0.)
|
||||
assert_allclose(out[:, :, :, offset], 0.)
|
||||
assert_allclose(out[:, :, 2:-2, 2:-2], 1.)
|
||||
layer.get_config()
|
||||
|
||||
config = layer.get_config()
|
||||
|
||||
def test_upsample_1d(self):
|
||||
def test_upsampling_1d(self):
|
||||
nb_samples = 9
|
||||
nb_steps = 7
|
||||
input_dim = 10
|
||||
|
||||
input = np.ones((nb_samples, nb_steps, input_dim))
|
||||
for length in [2, 3, 9]:
|
||||
layer = convolutional.UpSample1D(length=length)
|
||||
layer.input = theano.shared(value=input)
|
||||
layer = convolutional.UpSampling1D(length=length)
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
out = layer.get_output(train).eval()
|
||||
assert out.shape[1] == length*nb_steps
|
||||
out = K.eval(layer.get_output(train))
|
||||
assert out.shape[1] == length * nb_steps
|
||||
layer.get_config()
|
||||
|
||||
config = layer.get_config()
|
||||
|
||||
def test_upsample_2d(self):
|
||||
def test_upsampling_2d(self):
|
||||
nb_samples = 9
|
||||
stack_size = 7
|
||||
input_nb_row = 11
|
||||
@@ -150,14 +154,13 @@ class TestConvolutions(unittest.TestCase):
|
||||
|
||||
for length_row in [2, 3, 9]:
|
||||
for length_col in [2, 3, 9]:
|
||||
layer = convolutional.UpSample2D(size=(length_row, length_col))
|
||||
layer.input = theano.shared(value=input)
|
||||
layer = convolutional.UpSampling2D(size=(length_row, length_col))
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
out = layer.get_output(train).eval()
|
||||
assert out.shape[2] == length_row*input_nb_row
|
||||
assert out.shape[3] == length_col*input_nb_col
|
||||
|
||||
config = layer.get_config()
|
||||
out = K.eval(layer.get_output(train))
|
||||
assert out.shape[2] == length_row * input_nb_row
|
||||
assert out.shape[3] == length_col * input_nb_col
|
||||
layer.get_config()
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,8 +1,8 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
import theano
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import core
|
||||
|
||||
|
||||
@@ -15,10 +15,10 @@ class TestLayerBase(unittest.TestCase):
|
||||
# Once an input is provided, it should be reachable through the
|
||||
# appropriate getters
|
||||
input = np.ones((nb_samples, input_dim))
|
||||
layer.input = theano.shared(value=input)
|
||||
layer.input = K.variable(input)
|
||||
for train in [True, False]:
|
||||
assert_allclose(layer.get_input(train).eval(), input)
|
||||
assert_allclose(layer.get_output(train).eval(), input)
|
||||
assert_allclose(K.eval(layer.get_input(train)), input)
|
||||
assert_allclose(K.eval(layer.get_output(train)), input)
|
||||
|
||||
def test_connections(self):
|
||||
nb_samples = 10
|
||||
@@ -27,13 +27,13 @@ class TestLayerBase(unittest.TestCase):
|
||||
layer2 = core.Layer()
|
||||
|
||||
input = np.ones((nb_samples, input_dim))
|
||||
layer1.input = theano.shared(value=input)
|
||||
layer1.input = K.variable(input)
|
||||
|
||||
# After connecting, input of layer1 should be passed through
|
||||
layer2.set_previous(layer1)
|
||||
for train in [True, False]:
|
||||
assert_allclose(layer2.get_input(train).eval(), input)
|
||||
assert_allclose(layer2.get_output(train).eval(), input)
|
||||
assert_allclose(K.eval(layer2.get_input(train)), input)
|
||||
assert_allclose(K.eval(layer2.get_output(train)), input)
|
||||
|
||||
|
||||
class TestConfigParams(unittest.TestCase):
|
||||
@@ -60,6 +60,8 @@ class TestConfigParams(unittest.TestCase):
|
||||
def test_merge(self):
|
||||
layer_1 = core.Layer()
|
||||
layer_2 = core.Layer()
|
||||
layer_1.set_input_shape((None,))
|
||||
layer_2.set_input_shape((None,))
|
||||
layer = core.Merge([layer_1, layer_2])
|
||||
self._runner(layer)
|
||||
|
||||
@@ -116,38 +118,48 @@ class TestMasking(unittest.TestCase):
|
||||
|
||||
def test_sequences(self):
|
||||
"""Test masking sequences with zeroes as padding"""
|
||||
if K._BACKEND == "tensorflow":
|
||||
return
|
||||
# integer inputs, one per timestep, like embeddings
|
||||
layer = core.Masking()
|
||||
func = theano.function([layer.input], layer.get_output_mask())
|
||||
self.assertTrue(np.all(
|
||||
# get mask for this input
|
||||
func(np.array([[[1], [2], [3], [0]],
|
||||
[[0], [4], [5], [0]]], dtype=np.int32)) ==
|
||||
# This is the expected output mask, one dimension less
|
||||
np.array([[1, 1, 1, 0], [0, 1, 1, 0]])))
|
||||
func = K.function([layer.input], [layer.get_output_mask()])
|
||||
input_data = np.array([[[1], [2], [3], [0]],
|
||||
[[0], [4], [5], [0]]], dtype=np.int32)
|
||||
|
||||
# This is the expected output mask, one dimension less
|
||||
expected = np.array([[1, 1, 1, 0], [0, 1, 1, 0]])
|
||||
|
||||
# get mask for this input
|
||||
output = func([input_data])[0]
|
||||
self.assertTrue(np.all(output == expected))
|
||||
|
||||
def test_non_zero(self):
|
||||
"""Test masking with non-zero mask value"""
|
||||
if K._BACKEND == "tensorflow":
|
||||
return
|
||||
layer = core.Masking(5)
|
||||
func = theano.function([layer.input], layer.get_output_mask())
|
||||
self.assertTrue(np.all(
|
||||
# get mask for this input, if not all the values are 5, shouldn't masked
|
||||
func(np.array([[[1, 1], [2, 1], [3, 1], [5, 5]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]], dtype=np.int32)) ==
|
||||
# This is the expected output mask, one dimension less
|
||||
np.array([[1, 1, 1, 0], [1, 1, 1, 1]])))
|
||||
func = K.function([layer.input], [layer.get_output_mask()])
|
||||
input_data = np.array([[[1, 1], [2, 1], [3, 1], [5, 5]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]],
|
||||
dtype=np.int32)
|
||||
output = func([input_data])[0]
|
||||
expected = np.array([[1, 1, 1, 0], [1, 1, 1, 1]])
|
||||
self.assertTrue(np.all(output == expected))
|
||||
|
||||
def test_non_zero_output(self):
|
||||
"""Test output of masking layer with non-zero mask value"""
|
||||
if K._BACKEND == "tensorflow":
|
||||
return
|
||||
layer = core.Masking(5)
|
||||
func = theano.function([layer.input], layer.get_output())
|
||||
self.assertTrue(np.all(
|
||||
# get output for this input, replace padding with 0
|
||||
func(np.array([[[1, 1], [2, 1], [3, 1], [5, 5]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]], dtype=np.int32)) ==
|
||||
# This is the expected output
|
||||
np.array([[[1, 1], [2, 1], [3, 1], [0, 0]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]])))
|
||||
func = K.function([layer.input], [layer.get_output()])
|
||||
|
||||
input_data = np.array([[[1, 1], [2, 1], [3, 1], [5, 5]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]],
|
||||
dtype=np.int32)
|
||||
output = func([input_data])[0]
|
||||
expected = np.array([[[1, 1], [2, 1], [3, 1], [0, 0]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]])
|
||||
self.assertTrue(np.all(output == expected))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -1,24 +1,25 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
import theano
|
||||
|
||||
from keras.layers import recurrent
|
||||
from keras import backend as K
|
||||
|
||||
nb_samples, timesteps, input_dim, output_dim = 3, 3, 10, 5
|
||||
|
||||
|
||||
def _runner(layer_class):
|
||||
"""
|
||||
All the recurrent layers share the same interface, so we can run through them with a single
|
||||
function.
|
||||
All the recurrent layers share the same interface,
|
||||
so we can run through them with a single function.
|
||||
"""
|
||||
for ret_seq in [True, False]:
|
||||
layer = layer_class(output_dim, return_sequences=ret_seq, weights=None, input_shape=(None, input_dim))
|
||||
layer.input = theano.shared(value=np.ones((nb_samples, timesteps, input_dim)))
|
||||
config = layer.get_config()
|
||||
layer = layer_class(output_dim, return_sequences=ret_seq,
|
||||
weights=None, input_shape=(timesteps, input_dim))
|
||||
layer.input = K.variable(np.ones((nb_samples, timesteps, input_dim)))
|
||||
layer.get_config()
|
||||
|
||||
for train in [True, False]:
|
||||
out = layer.get_output(train).eval()
|
||||
out = K.eval(layer.get_output(train))
|
||||
# Make sure the output has the desired shape
|
||||
if ret_seq:
|
||||
assert(out.shape == (nb_samples, timesteps, output_dim))
|
||||
@@ -35,24 +36,12 @@ class TestRNNS(unittest.TestCase):
|
||||
def test_simple(self):
|
||||
_runner(recurrent.SimpleRNN)
|
||||
|
||||
def test_simple_deep(self):
|
||||
_runner(recurrent.SimpleDeepRNN)
|
||||
|
||||
def test_gru(self):
|
||||
_runner(recurrent.GRU)
|
||||
|
||||
def test_lstm(self):
|
||||
_runner(recurrent.LSTM)
|
||||
|
||||
def test_jzs1(self):
|
||||
_runner(recurrent.JZS1)
|
||||
|
||||
def test_jzs2(self):
|
||||
_runner(recurrent.JZS2)
|
||||
|
||||
def test_jzs3(self):
|
||||
_runner(recurrent.JZS3)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -0,0 +1,76 @@
|
||||
import unittest
|
||||
from keras import backend as K
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
|
||||
|
||||
def get_standard_values():
|
||||
'''
|
||||
These are just a set of floats used for testing the activation
|
||||
functions, and are useful in multiple tests.
|
||||
'''
|
||||
return np.array([[0, 0.1, 0.5, 0.9, 1.0]], dtype=K.floatx())
|
||||
|
||||
|
||||
class TestActivations(unittest.TestCase):
|
||||
|
||||
def test_softmax(self):
|
||||
from keras.activations import softmax as s
|
||||
|
||||
# Test using a reference implementation of softmax
|
||||
def softmax(values):
|
||||
m = np.max(values)
|
||||
e = np.exp(values - m)
|
||||
return e / np.sum(e)
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
exp = s(x)
|
||||
f = K.function([x], [exp])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
expected = softmax(test_values)
|
||||
assert_allclose(result, expected, rtol=1e-05)
|
||||
|
||||
def test_relu(self):
|
||||
'''
|
||||
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
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
exp = r(x)
|
||||
f = K.function([x], [exp])
|
||||
|
||||
test_values = get_standard_values()
|
||||
result = f([test_values])[0]
|
||||
|
||||
# because no negatives in test values
|
||||
assert_allclose(result, test_values, rtol=1e-05)
|
||||
|
||||
def test_tanh(self):
|
||||
from keras.activations import tanh as t
|
||||
test_values = get_standard_values()
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
exp = t(x)
|
||||
f = K.function([x], [exp])
|
||||
|
||||
result = f([test_values])[0]
|
||||
expected = np.tanh(test_values)
|
||||
assert_allclose(result, expected, rtol=1e-05)
|
||||
|
||||
def test_linear(self):
|
||||
'''
|
||||
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)
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,7 +1,7 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
from theano import tensor as T
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
class TestConstraints(unittest.TestCase):
|
||||
@@ -16,23 +16,25 @@ class TestConstraints(unittest.TestCase):
|
||||
|
||||
for m in self.some_values:
|
||||
norm_instance = maxnorm(m)
|
||||
normed = norm_instance(self.example_array)
|
||||
assert (np.all(normed.eval() < m))
|
||||
normed = norm_instance(K.variable(self.example_array))
|
||||
assert (np.all(K.eval(normed) < 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)
|
||||
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 = K.eval(norm_instance(K.variable(x)))
|
||||
assert_allclose(x_normed_actual, x_normed_target, rtol=1e-05)
|
||||
|
||||
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.))
|
||||
normed = nonneg_instance(K.variable(self.example_array))
|
||||
assert (np.all(np.min(K.eval(normed), axis=1) == 0.))
|
||||
|
||||
def test_identity(self):
|
||||
from keras.constraints import identity
|
||||
@@ -58,12 +60,13 @@ class TestConstraints(unittest.TestCase):
|
||||
from keras.constraints import unitnorm
|
||||
unitnorm_instance = unitnorm()
|
||||
|
||||
normalized = unitnorm_instance(self.example_array)
|
||||
normalized = unitnorm_instance(K.variable(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.
|
||||
norm_of_normalized = np.sqrt(np.sum(K.eval(normalized)**2, axis=1))
|
||||
# in the unit norm constraint, it should be equal to 1.
|
||||
difference = norm_of_normalized - 1.
|
||||
largest_difference = np.max(np.abs(difference))
|
||||
self.assertAlmostEqual(largest_difference, 0.)
|
||||
assert np.abs(largest_difference) < 10e-5
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
@@ -1,9 +1,9 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
from theano import tensor as T
|
||||
from keras.layers import normalization
|
||||
from keras.models import Sequential
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
class TestBatchNormalization(unittest.TestCase):
|
||||
@@ -19,7 +19,8 @@ class TestBatchNormalization(unittest.TestCase):
|
||||
norm_m1 = normalization.BatchNormalization(input_shape=(10, 10), mode=1)
|
||||
|
||||
# mode 3 does not exist
|
||||
self.assertRaises(Exception, normalization.BatchNormalization(input_shape=(10, 10), mode=3))
|
||||
self.assertRaises(Exception,
|
||||
normalization.BatchNormalization(input_shape=(10, 10), mode=3))
|
||||
|
||||
def test_mode_0(self):
|
||||
model = Sequential()
|
||||
@@ -30,23 +31,23 @@ class TestBatchNormalization(unittest.TestCase):
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 10))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
norm_m0.input = X
|
||||
norm_m0.input = K.variable(X)
|
||||
out = (norm_m0.get_output(train=True) - norm_m0.beta) / norm_m0.gamma
|
||||
|
||||
self.assertAlmostEqual(out.mean().eval(), 0.0, places=1)
|
||||
self.assertAlmostEqual(out.std().eval(), 1.0, places=1)
|
||||
self.assertAlmostEqual(K.eval(K.mean(out)), 0.0, places=1)
|
||||
self.assertAlmostEqual(K.eval(K.std(out)), 1.0, places=1)
|
||||
|
||||
def test_mode_1(self):
|
||||
norm_m1 = normalization.BatchNormalization(input_shape=(10,), mode=1)
|
||||
|
||||
for inp in [self.input_1, self.input_2, self.input_3]:
|
||||
norm_m1.input = inp
|
||||
norm_m1.input = K.variable(inp)
|
||||
out = (norm_m1.get_output(train=True) - norm_m1.beta) / norm_m1.gamma
|
||||
self.assertAlmostEqual(out.mean().eval(), 0.0)
|
||||
self.assertAlmostEqual(K.eval(K.mean(out)), 0.0)
|
||||
if inp.std() > 0.:
|
||||
self.assertAlmostEqual(out.std().eval(), 1.0, places=2)
|
||||
self.assertAlmostEqual(K.eval(K.std(out)), 1.0, places=2)
|
||||
else:
|
||||
self.assertAlmostEqual(out.std().eval(), 0.0, places=2)
|
||||
self.assertAlmostEqual(K.eval(K.std(out)), 0.0, places=2)
|
||||
|
||||
def test_shapes(self):
|
||||
"""
|
||||
@@ -54,11 +55,11 @@ class TestBatchNormalization(unittest.TestCase):
|
||||
"""
|
||||
for inp in self.input_shapes:
|
||||
norm_m0 = normalization.BatchNormalization(input_shape=inp.shape, mode=0)
|
||||
norm_m0.input = inp
|
||||
norm_m0.input = K.variable(inp)
|
||||
out = (norm_m0.get_output(train=True) - norm_m0.beta) / norm_m0.gamma
|
||||
|
||||
norm_m1 = normalization.BatchNormalization(input_shape=inp.shape, mode=1)
|
||||
norm_m1.input = inp
|
||||
norm_m1.input = K.variable(inp)
|
||||
out = (norm_m1.get_output(train=True) - norm_m1.beta) / norm_m1.gamma
|
||||
|
||||
def test_weight_init(self):
|
||||
@@ -69,26 +70,29 @@ class TestBatchNormalization(unittest.TestCase):
|
||||
weights=[np.ones(10), np.ones(10), np.zeros(10), np.zeros(10)])
|
||||
|
||||
for inp in [self.input_1, self.input_2, self.input_3]:
|
||||
norm_m1.input = inp
|
||||
norm_m1.input = K.variable(inp)
|
||||
out = (norm_m1.get_output(train=True) - np.ones(10)) / 1.
|
||||
self.assertAlmostEqual(out.mean().eval(), 0.0)
|
||||
self.assertAlmostEqual(K.eval(K.mean(out)), 0.0)
|
||||
if inp.std() > 0.:
|
||||
self.assertAlmostEqual(out.std().eval(), 1.0, places=2)
|
||||
self.assertAlmostEqual(K.eval(K.std(out)), 1.0, places=2)
|
||||
else:
|
||||
self.assertAlmostEqual(out.std().eval(), 0.0, places=2)
|
||||
self.assertAlmostEqual(K.eval(K.std(out)), 0.0, places=2)
|
||||
|
||||
assert_allclose(norm_m1.gamma.eval(), np.ones(10))
|
||||
assert_allclose(norm_m1.beta.eval(), np.ones(10))
|
||||
assert_allclose(K.eval(norm_m1.gamma), np.ones(10))
|
||||
assert_allclose(K.eval(norm_m1.beta), np.ones(10))
|
||||
|
||||
def test_config(self):
|
||||
norm = normalization.BatchNormalization(input_shape=(10, 10), mode=1, epsilon=0.1, momentum=0.9)
|
||||
norm = normalization.BatchNormalization(input_shape=(10, 10), mode=1,
|
||||
epsilon=0.1, momentum=0.9)
|
||||
conf = norm.get_config()
|
||||
conf_target = {"input_shape": (10, 10), "name": normalization.BatchNormalization.__name__,
|
||||
conf_target = {"input_shape": (10, 10),
|
||||
"name": normalization.BatchNormalization.__name__,
|
||||
"epsilon": 0.1, "mode": 1, "momentum": 0.9}
|
||||
self.assertDictEqual(conf, conf_target)
|
||||
|
||||
def test_save_weights(self):
|
||||
norm = normalization.BatchNormalization(input_shape=(10, 10), mode=1, epsilon=0.1)
|
||||
norm = normalization.BatchNormalization(input_shape=(10, 10), mode=1,
|
||||
epsilon=0.1)
|
||||
weights = norm.get_weights()
|
||||
assert(len(weights) == 4)
|
||||
norm.set_weights(weights)
|
||||
@@ -1,134 +0,0 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential, model_from_config
|
||||
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
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 5
|
||||
activation = 'linear'
|
||||
|
||||
input_dim = 784
|
||||
hidden_dim = 392
|
||||
|
||||
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, input_dim)[:max_train_samples]
|
||||
X_test = X_test.reshape(10000, input_dim)[: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]
|
||||
|
||||
print("X_train: ", X_train.shape)
|
||||
print("X_test: ", X_test.shape)
|
||||
|
||||
|
||||
##########################
|
||||
# dense model test #
|
||||
##########################
|
||||
|
||||
print("Training classical fully connected layer for classification")
|
||||
model_classical = Sequential()
|
||||
model_classical.add(Dense(input_dim, 10, activation=activation))
|
||||
model_classical.add(Activation('softmax'))
|
||||
model_classical.get_config(verbose=1)
|
||||
model_classical.compile(loss='categorical_crossentropy', optimizer='adam')
|
||||
model_classical.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=False, verbose=0, validation_data=(X_test, Y_test))
|
||||
classical_score = model_classical.evaluate(X_test, Y_test, verbose=0, show_accuracy=True)
|
||||
print('\nclassical_score:', classical_score)
|
||||
|
||||
##########################
|
||||
# autoencoder model test #
|
||||
##########################
|
||||
|
||||
|
||||
def build_lstm_autoencoder(autoencoder, X_train, X_test):
|
||||
X_train = X_train[:, np.newaxis, :]
|
||||
X_test = X_test[:, np.newaxis, :]
|
||||
print("Modified X_train: ", X_train.shape)
|
||||
print("Modified X_test: ", X_test.shape)
|
||||
|
||||
# The TimeDistributedDense isn't really necessary, however you need a lot of GPU memory to do 784x394-394x784
|
||||
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))
|
||||
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))
|
||||
return autoencoder
|
||||
|
||||
# Try different things here: 'lstm' or 'classical' or 'denoising'
|
||||
# or 'deep_denoising'
|
||||
|
||||
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)
|
||||
|
||||
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)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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))
|
||||
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
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], '%')
|
||||
|
||||
# check serialization
|
||||
config = autoencoder.get_config(verbose=1)
|
||||
autoencoder = model_from_config(config)
|
||||
@@ -1,236 +0,0 @@
|
||||
import numpy as np
|
||||
import random
|
||||
import theano
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.callbacks import Callback
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.regularizers import l2
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
from keras.datasets import mnist
|
||||
import keras.callbacks as cbks
|
||||
|
||||
from matplotlib import pyplot as plt
|
||||
from matplotlib import animation
|
||||
|
||||
##############################
|
||||
# model DrawActivations test #
|
||||
##############################
|
||||
|
||||
print('Running DrawActivations test')
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 10
|
||||
|
||||
max_train_samples = 512
|
||||
max_test_samples = 1
|
||||
|
||||
np.random.seed(1337)
|
||||
|
||||
# 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(-1,1,28,28)[:max_train_samples]
|
||||
X_train = X_train.astype("float32")
|
||||
X_train /= 255
|
||||
|
||||
X_test = X_test.reshape(-1,1,28,28)[:max_test_samples]
|
||||
X_test = X_test.astype("float32")
|
||||
X_test /= 255
|
||||
|
||||
# convert class vectors to binary class matrices
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)[:max_train_samples]
|
||||
|
||||
class Frames(object):
|
||||
def __init__(self, n_plots=16):
|
||||
self._n_frames = 0
|
||||
self._framedata = []
|
||||
self._titles = []
|
||||
for i in range(n_plots):
|
||||
self._framedata.append([])
|
||||
|
||||
def add_frame(self, i, frame):
|
||||
self._framedata[i].append(frame)
|
||||
|
||||
def set_title(self, title):
|
||||
self._titles.append(title)
|
||||
|
||||
class SubplotTimedAnimation(animation.TimedAnimation):
|
||||
|
||||
def __init__(self, fig, frames, grid=(4, 4), interval=10, blit=False, **kwargs):
|
||||
self.n_plots = grid[0] * grid[1]
|
||||
self.axes = [fig.add_subplot(grid[0], grid[1], i + 1) for i in range(self.n_plots)]
|
||||
for axis in self.axes:
|
||||
axis.get_xaxis().set_ticks([])
|
||||
axis.get_yaxis().set_ticks([])
|
||||
self.frames = frames
|
||||
self.imgs = [self.axes[i].imshow(frames._framedata[i][0], interpolation='nearest', cmap='bone') for i in range(self.n_plots)]
|
||||
self.title = fig.suptitle('')
|
||||
super(SubplotTimedAnimation, self).__init__(fig, interval=interval, blit=blit, **kwargs)
|
||||
|
||||
def _draw_frame(self, j):
|
||||
for i in range(self.n_plots):
|
||||
self.imgs[i].set_data(self.frames._framedata[i][j])
|
||||
if len(self.frames._titles) > j:
|
||||
self.title.set_text(self.frames._titles[j])
|
||||
self._drawn_artists = self.imgs
|
||||
|
||||
def new_frame_seq(self):
|
||||
return iter(range(len(self.frames._framedata[0])))
|
||||
|
||||
def _init_draw(self):
|
||||
for img in self.imgs:
|
||||
img.set_data([[]])
|
||||
|
||||
def combine_imgs(imgs, grid=(1,1)):
|
||||
n_imgs, img_h, img_w = imgs.shape
|
||||
if n_imgs != grid[0] * grid[1]:
|
||||
raise ValueError()
|
||||
combined = np.zeros((grid[0] * img_h, grid[1] * img_w))
|
||||
for i in range(grid[0]):
|
||||
for j in range(grid[1]):
|
||||
combined[img_h*i:img_h*(i+1),img_w*j:img_w*(j+1)] = imgs[grid[0] * i + j]
|
||||
return combined
|
||||
|
||||
class DrawActivations(Callback):
|
||||
def __init__(self, figsize):
|
||||
self.fig = plt.figure(figsize=figsize)
|
||||
|
||||
def on_train_begin(self, logs={}):
|
||||
self.imgs = Frames(n_plots=5)
|
||||
|
||||
layers_0_ids = np.random.choice(32, 16, replace=False)
|
||||
self.test_layer0 = theano.function([self.model.get_input()], self.model.layers[1].get_output(train=False)[0, layers_0_ids])
|
||||
|
||||
layers_1_ids = np.random.choice(64, 36, replace=False)
|
||||
self.test_layer1 = theano.function([self.model.get_input()], self.model.layers[5].get_output(train=False)[0, layers_1_ids])
|
||||
|
||||
self.test_layer2 = theano.function([self.model.get_input()], self.model.layers[10].get_output(train=False)[0])
|
||||
|
||||
def on_epoch_begin(self, epoch, logs={}):
|
||||
self.epoch = epoch
|
||||
|
||||
def on_batch_end(self, batch, logs={}):
|
||||
if batch % 5 == 0:
|
||||
self.imgs.add_frame(0, X_test[0,0])
|
||||
self.imgs.add_frame(1, combine_imgs(self.test_layer0(X_test), grid=(4, 4)))
|
||||
self.imgs.add_frame(2, combine_imgs(self.test_layer1(X_test), grid=(6, 6)))
|
||||
self.imgs.add_frame(3, self.test_layer2(X_test).reshape((16,16)))
|
||||
self.imgs.add_frame(4, self.model._predict(X_test)[0].reshape((1,10)))
|
||||
self.imgs.set_title('Epoch #%d - Batch #%d' % (self.epoch, batch))
|
||||
|
||||
def on_train_end(self, logs={}):
|
||||
anim = SubplotTimedAnimation(self.fig, self.imgs, grid=(1,5), interval=10, blit=False, repeat_delay=1000)
|
||||
# anim.save('test_gif.gif', fps=15, writer='imagemagick')
|
||||
plt.show()
|
||||
|
||||
# model = Sequential()
|
||||
# model.add(Dense(784, 50))
|
||||
# model.add(Activation('relu'))
|
||||
# model.add(Dense(50, 10))
|
||||
# model.add(Activation('softmax'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Convolution2D(32, 1, 3, 3, border_mode='full'))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Convolution2D(64, 32, 3, 3, border_mode='full'))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Flatten())
|
||||
model.add(Dense(64*8*8, 256))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dropout(0.5))
|
||||
|
||||
model.add(Dense(256, 10, W_regularizer = l2(0.1)))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
# Fit the model
|
||||
draw_weights = DrawActivations(figsize=(5.4, 1.35))
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=1, callbacks=[draw_weights])
|
||||
|
||||
|
||||
##########################
|
||||
# model checkpoint tests #
|
||||
##########################
|
||||
|
||||
print('Running ModelCheckpoint test')
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 20
|
||||
|
||||
# small sample size to overfit on training data
|
||||
max_train_samples = 50
|
||||
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]
|
||||
|
||||
|
||||
# Create a slightly larger network than required to test best validation save only
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 500))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(500, 10))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
# test file location
|
||||
path = "/tmp"
|
||||
filename = "model_weights.hdf5"
|
||||
import os
|
||||
f = os.path.join(path, filename)
|
||||
|
||||
print("Test model checkpointer")
|
||||
# only store best validation model in checkpointer
|
||||
checkpointer = cbks.ModelCheckpoint(filepath=f, verbose=1, save_best_only=True)
|
||||
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), callbacks =[checkpointer])
|
||||
|
||||
if not os.path.isfile(f):
|
||||
raise Exception("Model weights were not saved to %s" % (f))
|
||||
|
||||
print("Test model checkpointer without validation data")
|
||||
import warnings
|
||||
warnings.filterwarnings('error')
|
||||
try:
|
||||
passed = False
|
||||
# this should issue a warning
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0, callbacks =[checkpointer])
|
||||
except:
|
||||
passed = True
|
||||
if not passed:
|
||||
raise Exception("Modelcheckpoint tests did not pass")
|
||||
|
||||
print("Test model checkpointer with pattern")
|
||||
filename = "model_weights.{epoch:04d}.hdf5"
|
||||
f = os.path.join(path, filename)
|
||||
nb_epoch = 3
|
||||
checkpointer = cbks.ModelCheckpoint(f)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, verbose=0, callbacks=[checkpointer])
|
||||
for i in range(nb_epoch):
|
||||
if not os.path.isfile(f.format(epoch=i)):
|
||||
raise Exception("Model weights were not saved separately for each epoch")
|
||||
|
||||
print("Tests passed")
|
||||
@@ -1,100 +0,0 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
import keras
|
||||
from keras.datasets import mnist
|
||||
import keras.models
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.regularizers import l2, l1
|
||||
from keras.constraints import maxnorm, nonneg
|
||||
from keras.optimizers import SGD, Adam, RMSprop
|
||||
from keras.utils import np_utils, generic_utils
|
||||
import theano
|
||||
import theano.tensor as T
|
||||
import numpy as np
|
||||
import scipy
|
||||
|
||||
batch_size = 100
|
||||
nb_classes = 10
|
||||
nb_epoch = 10
|
||||
|
||||
# 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.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)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
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(Activation('relu'))
|
||||
model.add(Dropout(0.1))
|
||||
model.add(Dense(20, 10, W_constraint=maxnorm(1)))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
|
||||
rms = RMSprop()
|
||||
model.compile(loss='categorical_crossentropy', optimizer=rms)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch, show_accuracy=True, verbose=0)
|
||||
|
||||
a=model.params[0].eval()
|
||||
if np.isclose(np.max(np.sqrt(np.sum(a**2, axis=0))),1):
|
||||
print('Maxnorm test passed')
|
||||
else:
|
||||
raise ValueError('Maxnorm test failed!')
|
||||
|
||||
b=model.params[2].eval()
|
||||
if np.min(b)==0 and np.min(a)!=0:
|
||||
print('Nonneg test passed')
|
||||
else:
|
||||
raise ValueError('Nonneg test failed!')
|
||||
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 20))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(20, 20, W_regularizer=l1(.01)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(20, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
|
||||
rms = RMSprop()
|
||||
model.compile(loss='categorical_crossentropy', optimizer=rms)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=20, show_accuracy=True, verbose=0)
|
||||
|
||||
a=model.params[2].eval().reshape(400)
|
||||
(D, p1) = scipy.stats.kurtosistest(a)
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 20))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(20, 20, W_regularizer=l2(.01)))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(20, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
|
||||
rms = RMSprop()
|
||||
model.compile(loss='categorical_crossentropy', optimizer=rms)
|
||||
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=20, show_accuracy=True, verbose=0)
|
||||
|
||||
a=model.params[2].eval().reshape(400)
|
||||
(D, p2) = scipy.stats.kurtosistest(a)
|
||||
|
||||
if p1<.01 and p2>.01:
|
||||
print('L1 and L2 regularization tests passed')
|
||||
else:
|
||||
raise ValueError('L1 and L2 regularization tests failed!')
|
||||
@@ -1,130 +0,0 @@
|
||||
# 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))
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential, Graph
|
||||
from keras.layers.core import Layer, Activation, Dense, Flatten, Reshape, Merge
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
import keras.utils.layer_utils as layer_utils
|
||||
|
||||
print('-- Sequential model')
|
||||
left = Sequential()
|
||||
left.add(Convolution2D(32, 1, 3, 3, border_mode='valid'))
|
||||
left.add(MaxPooling2D(pool_size=(2, 2)))
|
||||
left.add(Flatten())
|
||||
left.add(Dense(32 * 13 * 13, 50))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(784, 30))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='concat'))
|
||||
|
||||
model.add(Dense(80, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
layer_utils.print_layer_shapes(model, [(1, 1, 28, 28), (1, 784)])
|
||||
|
||||
print('-- Graph model')
|
||||
graph = Graph()
|
||||
graph.add_input(name='input1', ndim=2)
|
||||
graph.add_input(name='input2', ndim=4)
|
||||
graph.add_node(Dense(32, 16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(16, 4), name='dense3', input='dense1')
|
||||
|
||||
graph.add_node(Convolution2D(32, 1, 3, 3), name='conv1', input='input2')
|
||||
graph.add_node(Flatten(), name='flatten1', input='conv1')
|
||||
graph.add_node(Dense(32 * 13 * 13, 10), name='dense4', input='flatten1')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense1', 'dense3'], merge_mode='sum')
|
||||
graph.add_output(name='output2', inputs=['dense1', 'dense4'], merge_mode='concat')
|
||||
|
||||
layer_utils.print_layer_shapes(graph, {'input1': (1, 32), 'input2': (1, 1, 28, 28)})
|
||||
|
||||
print('Test script complete')
|
||||
@@ -1,40 +0,0 @@
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.optimizers import SGD
|
||||
|
||||
import sys
|
||||
sys.setrecursionlimit(10000) # to be able to pickle Theano compiled functions
|
||||
|
||||
import pickle, numpy
|
||||
|
||||
def create_model():
|
||||
model = Sequential()
|
||||
model.add(Dense(256, 2048, init='uniform', activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(2048, 2048, init='uniform', activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(2048, 2048, init='uniform', activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(2048, 2048, init='uniform', activation='relu'))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(2048, 256, init='uniform', activation='linear'))
|
||||
return model
|
||||
|
||||
model = create_model()
|
||||
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
model.compile(loss='mse', optimizer=sgd)
|
||||
|
||||
pickle.dump(model, open('/tmp/model.pkl', 'wb'))
|
||||
model.save_weights('/tmp/model_weights.hdf5')
|
||||
|
||||
model_loaded = create_model()
|
||||
model_loaded.load_weights('/tmp/model_weights.hdf5')
|
||||
|
||||
for k in range(len(model.layers)):
|
||||
weights_orig = model.layers[k].get_weights()
|
||||
weights_loaded = model_loaded.layers[k].get_weights()
|
||||
for x, y in zip(weights_orig, weights_loaded):
|
||||
if numpy.any(x != y):
|
||||
raise ValueError('Loaded weights are different from pickled weights!')
|
||||
|
||||
|
||||
@@ -1,126 +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
|
||||
from keras.utils import np_utils
|
||||
from keras.wrappers.scikit_learn import *
|
||||
import numpy as np
|
||||
|
||||
batch_size = 128
|
||||
nb_epoch = 1
|
||||
|
||||
nb_classes = 10
|
||||
max_train_samples = 5000
|
||||
max_test_samples = 1000
|
||||
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
############################################
|
||||
# scikit-learn classification wrapper test #
|
||||
############################################
|
||||
print('Beginning scikit-learn classification wrapper test')
|
||||
|
||||
print('Loading data')
|
||||
(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
|
||||
|
||||
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]
|
||||
|
||||
print('Defining model')
|
||||
model = Sequential()
|
||||
model.add(Dense(784, 50))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(50, 10))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
print('Creating wrapper')
|
||||
classifier = KerasClassifier(model, train_batch_size=batch_size, nb_epoch=nb_epoch)
|
||||
|
||||
print('Fitting model')
|
||||
classifier.fit(X_train, Y_train)
|
||||
|
||||
print('Testing score function')
|
||||
score = classifier.score(X_train, Y_train)
|
||||
print('Score: ', score)
|
||||
|
||||
print('Testing predict function')
|
||||
preds = classifier.predict(X_test)
|
||||
print('Preds.shape: ', preds.shape)
|
||||
|
||||
print('Testing predict proba function')
|
||||
proba = classifier.predict_proba(X_test)
|
||||
print('Proba.shape: ', proba.shape)
|
||||
|
||||
print('Testing get params')
|
||||
print(classifier.get_params())
|
||||
|
||||
print('Testing set params')
|
||||
classifier.set_params(optimizer='sgd', loss='binary_crossentropy')
|
||||
print(classifier.get_params())
|
||||
|
||||
print('Testing attributes')
|
||||
print('Classes')
|
||||
print(classifier.classes_)
|
||||
print('Config')
|
||||
print(classifier.config_)
|
||||
print('Weights')
|
||||
print(classifier.weights_)
|
||||
print('Compiled model')
|
||||
print(classifier.compiled_model_)
|
||||
|
||||
########################################
|
||||
# scikit-learn regression wrapper test #
|
||||
########################################
|
||||
print('Beginning scikit-learn regression wrapper test')
|
||||
|
||||
print('Generating data')
|
||||
X_train = np.random.random((5000, 100))
|
||||
X_test = np.random.random((1000, 100))
|
||||
y_train = np.random.random(5000)
|
||||
y_test = np.random.random(1000)
|
||||
|
||||
print('Defining model')
|
||||
model = Sequential()
|
||||
model.add(Dense(100, 50))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Dense(50, 1))
|
||||
model.add(Activation('linear'))
|
||||
|
||||
print('Creating wrapper')
|
||||
regressor = KerasRegressor(model, train_batch_size=batch_size, nb_epoch=nb_epoch)
|
||||
|
||||
print('Fitting model')
|
||||
regressor.fit(X_train, y_train)
|
||||
|
||||
print('Testing score function')
|
||||
score = regressor.score(X_train, y_train)
|
||||
print('Score: ', score)
|
||||
|
||||
print('Testing predict function')
|
||||
preds = regressor.predict(X_test)
|
||||
print('Preds.shape: ', preds.shape)
|
||||
|
||||
print('Testing get params')
|
||||
print(regressor.get_params())
|
||||
|
||||
print('Testing set params')
|
||||
regressor.set_params(optimizer='sgd', loss='mean_absolute_error')
|
||||
print(regressor.get_params())
|
||||
|
||||
print('Testing attributes')
|
||||
print('Config')
|
||||
print(regressor.config_)
|
||||
print('Weights')
|
||||
print(regressor.weights_)
|
||||
print('Compiled model')
|
||||
print(regressor.compiled_model_)
|
||||
|
||||
print('Test script complete.')
|
||||
@@ -1,101 +0,0 @@
|
||||
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(np.sum(new_pred['output1'] - original_pred['output1']) == 0)
|
||||
@@ -1,10 +1,10 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Merge, Dense, Activation, Flatten
|
||||
from keras.layers.core import Dense, Activation, Flatten
|
||||
from keras.layers.embeddings import Embedding
|
||||
from theano import function
|
||||
from keras.constraints import unitnorm
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
class TestEmbedding(unittest.TestCase):
|
||||
@@ -14,13 +14,16 @@ class TestEmbedding(unittest.TestCase):
|
||||
|
||||
def test_unitnorm_constraint(self):
|
||||
lookup = Sequential()
|
||||
lookup.add(Embedding(3, 2, weights=[self.W1], W_constraint=unitnorm(), input_length=1))
|
||||
lookup.add(Embedding(3, 2, weights=[self.W1],
|
||||
W_constraint=unitnorm(),
|
||||
input_length=1))
|
||||
lookup.add(Flatten())
|
||||
lookup.add(Dense(1))
|
||||
lookup.add(Activation('sigmoid'))
|
||||
lookup.compile(loss='binary_crossentropy', optimizer='sgd', class_mode='binary')
|
||||
lookup.compile(loss='binary_crossentropy', optimizer='sgd',
|
||||
class_mode='binary')
|
||||
lookup.train_on_batch(self.X1, np.array([[1], [0]], dtype='int32'))
|
||||
norm = np.linalg.norm(lookup.params[0].get_value(), axis=1)
|
||||
norm = np.linalg.norm(K.get_value(lookup.params[0]), axis=1)
|
||||
self.assertTrue(np.allclose(norm, np.ones_like(norm).astype('float32')))
|
||||
|
||||
if __name__ == '__main__':
|
||||
@@ -13,10 +13,16 @@ 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,))
|
||||
(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):
|
||||
@@ -29,10 +35,13 @@ class TestGraph(unittest.TestCase):
|
||||
graph.add_node(Dense(4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(4), name='dense3', input='dense1')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
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)
|
||||
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)
|
||||
@@ -42,6 +51,14 @@ class TestGraph(unittest.TestCase):
|
||||
print(loss)
|
||||
assert(loss < 2.5)
|
||||
|
||||
# test validation split
|
||||
history = graph.fit({'input1': X_train, 'output1': y_train},
|
||||
validation_split=0.2, nb_epoch=1)
|
||||
# test validation data
|
||||
history = graph.fit({'input1': X_train, 'output1': y_train},
|
||||
validation_data={'input1': X_train, 'output1': y_train},
|
||||
nb_epoch=1)
|
||||
|
||||
def test_1o_1i_2(self):
|
||||
print('test a more complex non-sequential graph with 1 input and 1 output')
|
||||
graph = Graph()
|
||||
@@ -52,12 +69,15 @@ class TestGraph(unittest.TestCase):
|
||||
graph.add_node(Activation('relu'), name='dense2', input='dense2-0')
|
||||
|
||||
graph.add_node(Dense(16), name='dense3', input='dense2')
|
||||
graph.add_node(Dense(4), name='dense4', inputs=['dense1', 'dense3'], merge_mode='sum')
|
||||
graph.add_node(Dense(4), name='dense4', inputs=['dense1', 'dense3'],
|
||||
merge_mode='sum')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense4'], 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)
|
||||
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)
|
||||
@@ -78,10 +98,12 @@ class TestGraph(unittest.TestCase):
|
||||
graph.add_node(Dense(4), name='dense2', input='input2')
|
||||
graph.add_node(Dense(4), name='dense3', input='dense1')
|
||||
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
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)
|
||||
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)
|
||||
@@ -105,7 +127,8 @@ class TestGraph(unittest.TestCase):
|
||||
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)
|
||||
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)
|
||||
@@ -149,7 +172,8 @@ class TestGraph(unittest.TestCase):
|
||||
|
||||
graph.compile('rmsprop', {'output1': 'mse', 'output2': 'mse'})
|
||||
|
||||
history = graph.fit({'input1': X_train, 'output1': y_train, 'output2': y2_train}, nb_epoch=10,
|
||||
history = graph.fit({'input1': X_train, 'output1': y_train, 'output2': y2_train},
|
||||
nb_epoch=10,
|
||||
sample_weight={'output1': weights1, 'output2': weights2})
|
||||
out = graph.predict({'input1': X_test})
|
||||
assert(type(out == dict))
|
||||
@@ -170,7 +194,8 @@ class TestGraph(unittest.TestCase):
|
||||
graph.add_node(Dense(16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(4), name='dense3', input='dense1')
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'], merge_mode='sum')
|
||||
graph.add_output(name='output1', inputs=['dense2', 'dense3'],
|
||||
merge_mode='sum')
|
||||
|
||||
seq = Sequential()
|
||||
seq.add(Dense(32, input_shape=(32,)))
|
||||
@@ -196,10 +221,12 @@ class TestGraph(unittest.TestCase):
|
||||
graph.add_node(Dense(16), name='dense1', input='input1')
|
||||
graph.add_node(Dense(4), name='dense2', input='input1')
|
||||
graph.add_node(Dense(4), name='dense3', input='dense1')
|
||||
graph.add_node(Dense(4), name='output1', inputs=['dense2', 'dense3'], merge_mode='sum', create_output=True)
|
||||
graph.add_node(Dense(4), name='output1', inputs=['dense2', 'dense3'],
|
||||
merge_mode='sum', create_output=True)
|
||||
graph.compile('rmsprop', {'output1': 'mse'})
|
||||
|
||||
history = graph.fit({'input1': X_train, 'output1': y_train}, nb_epoch=10)
|
||||
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)
|
||||
@@ -5,11 +5,14 @@ import unittest
|
||||
from keras.models import Sequential, weighted_objective
|
||||
from keras.layers.core import TimeDistributedDense, Masking
|
||||
from keras import objectives
|
||||
import theano
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
class TestLossMasking(unittest.TestCase):
|
||||
def test_loss_masking(self):
|
||||
class TestMasking(unittest.TestCase):
|
||||
def test_masking(self):
|
||||
if K._BACKEND == 'tensorflow':
|
||||
# skip this test for TF: not supported yet
|
||||
return
|
||||
X = np.array(
|
||||
[[[1, 1], [2, 1], [3, 1], [5, 5]],
|
||||
[[1, 5], [5, 0], [0, 0], [0, 0]]], dtype=np.int32)
|
||||
@@ -18,29 +21,27 @@ class TestLossMasking(unittest.TestCase):
|
||||
model.add(TimeDistributedDense(1, init='one'))
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
y = model.predict(X)
|
||||
loss = model.fit(X, 4*y, nb_epoch=1, batch_size=2, verbose=1).history['loss'][0]
|
||||
assert loss == 285.
|
||||
history = model.fit(X, 4 * y, nb_epoch=1, batch_size=2, verbose=1)
|
||||
assert history.history['loss'][0] == 285.
|
||||
|
||||
def test_loss_masking_time(self):
|
||||
theano.config.mode = 'FAST_COMPILE'
|
||||
weighted_loss = weighted_objective(objectives.get('categorical_crossentropy'))
|
||||
def test_loss_masking(self):
|
||||
weighted_loss = weighted_objective(objectives.get('mae'))
|
||||
shape = (3, 4, 2)
|
||||
X = np.arange(24).reshape(shape)
|
||||
Y = 2 * X
|
||||
|
||||
weights = np.ones((3, 4, 1)) # Normally the trailing 1 is added by standardize_weights
|
||||
weights[0, 0] = 0
|
||||
# Normally the trailing 1 is added by standardize_weights
|
||||
weights = np.ones((3,))
|
||||
mask = np.ones((3, 4))
|
||||
mask[1, 0] = 0
|
||||
|
||||
out = weighted_loss(X, Y, weights, mask).eval()
|
||||
weights[0, 0] = 1e-9 # so that nonzero() doesn't remove this weight
|
||||
out2 = weighted_loss(X, Y, weights, mask).eval()
|
||||
out = K.eval(weighted_loss(K.variable(X),
|
||||
K.variable(Y),
|
||||
K.variable(weights),
|
||||
K.variable(mask)))
|
||||
print(out)
|
||||
print(out2)
|
||||
assert abs(out - out2) < 1e-8
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
print('Test loss masking')
|
||||
print('Test masking')
|
||||
unittest.main()
|
||||
@@ -12,7 +12,7 @@ import unittest
|
||||
|
||||
nb_classes = 10
|
||||
batch_size = 128
|
||||
nb_epoch = 8
|
||||
nb_epoch = 10
|
||||
weighted_class = 9
|
||||
standard_weight = 1
|
||||
high_weight = 5
|
||||
@@ -60,20 +60,29 @@ def create_graph_model():
|
||||
|
||||
def _test_weights_sequential(model, class_weight=None, sample_weight=None):
|
||||
if sample_weight is not None:
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch // 3, verbose=0,
|
||||
model.fit(X_train, Y_train, batch_size=batch_size,
|
||||
nb_epoch=nb_epoch // 3, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch // 3, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight, validation_split=0.1)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch // 3, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight, validation_data=(X_train, Y_train, sample_weight))
|
||||
model.fit(X_train, Y_train, batch_size=batch_size,
|
||||
nb_epoch=nb_epoch // 3, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight,
|
||||
validation_split=0.1)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size,
|
||||
nb_epoch=nb_epoch // 3, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight,
|
||||
validation_data=(X_train, Y_train, sample_weight))
|
||||
else:
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch // 2, verbose=0,
|
||||
model.fit(X_train, Y_train, batch_size=batch_size,
|
||||
nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight, validation_split=0.1)
|
||||
model.fit(X_train, Y_train, batch_size=batch_size,
|
||||
nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight=class_weight, sample_weight=sample_weight,
|
||||
validation_split=0.1)
|
||||
|
||||
model.train_on_batch(X_train[:32], Y_train[:32],
|
||||
class_weight=class_weight, sample_weight=sample_weight[:32] if sample_weight is not None else None)
|
||||
class_weight=class_weight,
|
||||
sample_weight=sample_weight[:32] if sample_weight is not None else None)
|
||||
model.test_on_batch(X_train[:32], Y_train[:32],
|
||||
sample_weight=sample_weight[:32] if sample_weight is not None else None)
|
||||
score = model.evaluate(X_test[test_ids, :], Y_test[test_ids, :], verbose=0)
|
||||
@@ -81,27 +90,34 @@ def _test_weights_sequential(model, class_weight=None, sample_weight=None):
|
||||
|
||||
|
||||
def _test_weights_graph(model, class_weight=None, sample_weight=None):
|
||||
model.fit({'input': X_train, 'output': Y_train}, batch_size=batch_size, nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight={'output': class_weight}, sample_weight={'output': sample_weight})
|
||||
model.fit({'input': X_train, 'output': Y_train}, batch_size=batch_size, nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight={'output': class_weight}, sample_weight={'output': sample_weight}, validation_split=0.1)
|
||||
model.fit({'input': X_train, 'output': Y_train},
|
||||
batch_size=batch_size, nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight={'output': class_weight},
|
||||
sample_weight={'output': sample_weight})
|
||||
model.fit({'input': X_train, 'output': Y_train},
|
||||
batch_size=batch_size, nb_epoch=nb_epoch // 2, verbose=0,
|
||||
class_weight={'output': class_weight},
|
||||
sample_weight={'output': sample_weight}, validation_split=0.1)
|
||||
|
||||
model.train_on_batch({'input': X_train[:32], 'output': Y_train[:32]},
|
||||
class_weight={'output': class_weight}, sample_weight={'output': sample_weight[:32] if sample_weight is not None else None})
|
||||
class_weight={'output': class_weight},
|
||||
sample_weight={'output': sample_weight[:32] if sample_weight is not None else None})
|
||||
model.test_on_batch({'input': X_train[:32], 'output': Y_train[:32]},
|
||||
sample_weight={'output': sample_weight[:32] if sample_weight is not None else None})
|
||||
score = model.evaluate({'input': X_test[test_ids, :], 'output': Y_test[test_ids, :]}, verbose=0)
|
||||
score = model.evaluate({'input': X_test[test_ids, :],
|
||||
'output': Y_test[test_ids, :]},
|
||||
verbose=0)
|
||||
return score
|
||||
|
||||
|
||||
class TestLossWeighting(unittest.TestCase):
|
||||
def test_sequential(self):
|
||||
for loss in ['mae', 'mse', 'categorical_crossentropy']:
|
||||
for loss in ['mae', 'mse']:
|
||||
print('loss:', loss)
|
||||
print('sequential')
|
||||
# no weights: reference point
|
||||
model = create_sequential_model()
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
model.compile(loss=loss, optimizer='rmsprop')
|
||||
standard_score = _test_weights_sequential(model)
|
||||
# test class_weight
|
||||
model = create_sequential_model()
|
||||
@@ -117,22 +133,22 @@ class TestLossWeighting(unittest.TestCase):
|
||||
self.assertTrue(score < standard_score)
|
||||
|
||||
def test_graph(self):
|
||||
for loss in ['mae', 'mse', 'categorical_crossentropy']:
|
||||
for loss in ['mae', 'mse']:
|
||||
print('loss:', loss)
|
||||
print('graph')
|
||||
# no weights: reference point
|
||||
model = create_graph_model()
|
||||
model.compile(loss={'output': 'categorical_crossentropy'}, optimizer='rmsprop')
|
||||
model.compile(loss={'output': loss}, optimizer='rmsprop')
|
||||
standard_score = _test_weights_graph(model)
|
||||
# test class_weight
|
||||
model = create_graph_model()
|
||||
model.compile(loss={'output': 'categorical_crossentropy'}, optimizer='rmsprop')
|
||||
model.compile(loss={'output': loss}, optimizer='rmsprop')
|
||||
score = _test_weights_graph(model, class_weight=class_weight)
|
||||
print('score:', score, ' vs.', standard_score)
|
||||
self.assertTrue(score < standard_score)
|
||||
# test sample_weight
|
||||
model = create_graph_model()
|
||||
model.compile(loss={'output': 'categorical_crossentropy'}, optimizer='rmsprop')
|
||||
model.compile(loss={'output': loss}, optimizer='rmsprop')
|
||||
score = _test_weights_graph(model, sample_weight=sample_weight)
|
||||
print('score:', score, ' vs.', standard_score)
|
||||
self.assertTrue(score < standard_score)
|
||||
@@ -4,10 +4,13 @@ import unittest
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
|
||||
from keras import backend as K
|
||||
from keras.models import Sequential, model_from_json, model_from_yaml
|
||||
from keras.layers.core import Dense, Activation, Merge
|
||||
from keras.layers.core import Dense, Activation, Merge, Lambda, LambdaMerge
|
||||
from keras.utils import np_utils
|
||||
from keras.utils.test_utils import get_test_data
|
||||
import pickle
|
||||
import sys
|
||||
|
||||
input_dim = 32
|
||||
nb_hidden = 16
|
||||
@@ -18,8 +21,11 @@ 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)
|
||||
(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)
|
||||
@@ -47,12 +53,12 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
loss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
if loss > 0.7:
|
||||
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.predict(X_test, verbose=0)
|
||||
model.predict_classes(X_test, verbose=0)
|
||||
model.predict_proba(X_test, verbose=0)
|
||||
model.get_config(verbose=0)
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
@@ -65,7 +71,6 @@ class TestSequential(unittest.TestCase):
|
||||
model.load_weights('temp.h5')
|
||||
|
||||
nloss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
# test json serialization
|
||||
@@ -88,10 +93,8 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='sum'))
|
||||
|
||||
model.add(Dense(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))
|
||||
@@ -105,10 +108,10 @@ class TestSequential(unittest.TestCase):
|
||||
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))
|
||||
model.predict([X_test, X_test], verbose=0)
|
||||
model.predict_classes([X_test, X_test], verbose=0)
|
||||
model.predict_proba([X_test, X_test], verbose=0)
|
||||
model.get_config(verbose=0)
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
@@ -129,6 +132,46 @@ class TestSequential(unittest.TestCase):
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
def test_merge_dot1(self):
|
||||
if K._BACKEND == 'tensorflow':
|
||||
return
|
||||
|
||||
print('Test merge: dot')
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim=input_dim, output_dim=nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim=input_dim, output_dim=nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='dot', dot_axes=1))
|
||||
model.add(Dense(nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
def test_merge_dot2(self):
|
||||
if K._BACKEND == 'tensorflow':
|
||||
return
|
||||
|
||||
print('Test merge: dot')
|
||||
left = Sequential()
|
||||
left.add(Dense(input_dim=input_dim, output_dim=nb_hidden))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(input_dim=input_dim, output_dim=nb_hidden))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='dot', dot_axes=([1], [1])))
|
||||
model.add(Dense(nb_class))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
def test_merge_concat(self):
|
||||
print('Test merge: concat')
|
||||
left = Sequential()
|
||||
@@ -141,10 +184,8 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, right], mode='concat'))
|
||||
|
||||
model.add(Dense(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))
|
||||
@@ -156,12 +197,12 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
loss = model.evaluate([X_train, X_train], y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
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))
|
||||
model.predict([X_test, X_test], verbose=0)
|
||||
model.predict_classes([X_test, X_test], verbose=0)
|
||||
model.predict_proba([X_test, X_test], verbose=0)
|
||||
model.get_config(verbose=0)
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
@@ -183,7 +224,6 @@ class TestSequential(unittest.TestCase):
|
||||
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):
|
||||
@@ -208,10 +248,8 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([intermediate, righter], mode='sum'))
|
||||
|
||||
model.add(Dense(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))
|
||||
@@ -223,12 +261,12 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
loss = model.evaluate([X_train, X_train, X_train], y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
if loss > 0.7:
|
||||
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.predict([X_test, X_test, X_test], verbose=0)
|
||||
model.predict_classes([X_test, X_test, X_test], verbose=0)
|
||||
model.predict_proba([X_test, X_test, X_test], verbose=0)
|
||||
model.get_config(verbose=0)
|
||||
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
model.load_weights('temp.h5')
|
||||
@@ -245,10 +283,8 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
model = Sequential()
|
||||
model.add(Merge([left, left], mode='sum'))
|
||||
|
||||
model.add(Dense(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))
|
||||
@@ -262,12 +298,12 @@ class TestSequential(unittest.TestCase):
|
||||
|
||||
loss = model.evaluate(X_train, y_train, verbose=0)
|
||||
print('loss:', loss)
|
||||
if loss > 0.6:
|
||||
if loss > 0.7:
|
||||
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.predict(X_test, verbose=0)
|
||||
model.predict_classes(X_test, verbose=0)
|
||||
model.predict_proba(X_test, verbose=0)
|
||||
model.get_config(verbose=0)
|
||||
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
model.load_weights('temp.h5')
|
||||
@@ -276,6 +312,71 @@ class TestSequential(unittest.TestCase):
|
||||
print(nloss)
|
||||
assert(loss == nloss)
|
||||
|
||||
def test_lambda(self):
|
||||
print('Test lambda: sum')
|
||||
|
||||
def func(X):
|
||||
s = X[0]
|
||||
for i in range(1, len(X)):
|
||||
s += X[i]
|
||||
return s
|
||||
|
||||
def activation(X):
|
||||
return K.softmax(X)
|
||||
|
||||
def output_shape(input_shapes):
|
||||
return input_shapes[0]
|
||||
|
||||
left = Sequential()
|
||||
left.add(Dense(nb_hidden, input_shape=(input_dim,)))
|
||||
left.add(Activation('relu'))
|
||||
|
||||
right = Sequential()
|
||||
right.add(Dense(nb_hidden, input_shape=(input_dim,)))
|
||||
right.add(Activation('relu'))
|
||||
|
||||
model = Sequential()
|
||||
model.add(LambdaMerge([left, right], function=func,
|
||||
output_shape=output_shape))
|
||||
model.add(Dense(nb_class))
|
||||
model.add(Lambda(activation))
|
||||
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.')
|
||||
model.predict([X_test, X_test], verbose=0)
|
||||
model.predict_classes([X_test, X_test], verbose=0)
|
||||
model.predict_proba([X_test, X_test], verbose=0)
|
||||
model.get_config(verbose=0)
|
||||
|
||||
print('test weight saving')
|
||||
model.save_weights('temp.h5', overwrite=True)
|
||||
left = Sequential()
|
||||
left.add(Dense(nb_hidden, input_shape=(input_dim,)))
|
||||
left.add(Activation('relu'))
|
||||
right = Sequential()
|
||||
right.add(Dense(nb_hidden, input_shape=(input_dim,)))
|
||||
right.add(Activation('relu'))
|
||||
model = Sequential()
|
||||
model.add(LambdaMerge([left, right], function=func,
|
||||
output_shape=output_shape))
|
||||
model.add(Dense(nb_class))
|
||||
model.add(Lambda(activation))
|
||||
model.load_weights('temp.h5')
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
|
||||
nloss = model.evaluate([X_train, X_train], y_train, verbose=0)
|
||||
assert(loss == nloss)
|
||||
|
||||
def test_count_params(self):
|
||||
print('test count params')
|
||||
input_dim = 20
|
||||
@@ -1,7 +1,7 @@
|
||||
import unittest
|
||||
import numpy as np
|
||||
import theano
|
||||
from keras.utils.theano_utils import ndim_tensor
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers.core import *
|
||||
from keras.layers.convolutional import *
|
||||
from keras.layers.recurrent import SimpleRNN
|
||||
@@ -9,13 +9,13 @@ from keras.layers.recurrent import SimpleRNN
|
||||
|
||||
def check_layer_output_shape(layer, input_data):
|
||||
ndim = len(input_data.shape)
|
||||
layer.input = ndim_tensor(ndim)
|
||||
layer.input = K.placeholder(ndim=ndim)
|
||||
layer.set_input_shape(input_data.shape[1:])
|
||||
expected_output_shape = layer.output_shape[1:]
|
||||
|
||||
function = theano.function([layer.input], [layer.get_output()])
|
||||
output = function(input_data)[0]
|
||||
assert output.shape[1:] == expected_output_shape
|
||||
function = K.function([layer.input], [layer.get_output()])
|
||||
output = function([input_data])[0]
|
||||
assert output.shape[1:] == expected_output_shape, str(output.shape[1:]) + ' != ' + str(expected_output_shape)
|
||||
|
||||
|
||||
class TestShapeInference(unittest.TestCase):
|
||||
@@ -56,67 +56,102 @@ class TestShapeInference(unittest.TestCase):
|
||||
# Convolutional #
|
||||
#################
|
||||
def test_Convolution1D(self):
|
||||
for border_mode in ['same', 'full', 'valid']:
|
||||
for border_mode in ['same', 'valid']:
|
||||
for filter_length in [2, 3]:
|
||||
for subsample_length in [1, 2]:
|
||||
for subsample_length in [1]:
|
||||
if subsample_length > 1 and border_mode == 'same':
|
||||
continue
|
||||
for input_data_shape in [(2, 3, 2), (2, 4, 2)]:
|
||||
layer = Convolution1D(nb_filter=1, filter_length=filter_length,
|
||||
border_mode=border_mode, subsample_length=subsample_length)
|
||||
for input_data_shape in [(2, 3, 4), (2, 4, 4)]:
|
||||
layer = Convolution1D(nb_filter=1,
|
||||
filter_length=filter_length,
|
||||
border_mode=border_mode,
|
||||
subsample_length=subsample_length)
|
||||
input_data = np.random.random(input_data_shape)
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_Convolution2D(self):
|
||||
for border_mode in ['same', 'full', 'valid']:
|
||||
for nb_row, nb_col in [(2, 1), (3, 2)]:
|
||||
for border_mode in ['same', 'valid']:
|
||||
for nb_row, nb_col in [(2, 2), (3, 3)]:
|
||||
for subsample in [(1, 1), (2, 2)]:
|
||||
if (subsample[0] > 1 or subsample[1] > 1) and border_mode == 'same':
|
||||
continue
|
||||
for input_data_shape in [(2, 1, 3, 3), (2, 1, 4, 4)]:
|
||||
layer = Convolution2D(nb_filter=1, nb_row=nb_row, nb_col=nb_row,
|
||||
border_mode=border_mode, subsample=subsample)
|
||||
layer = Convolution2D(nb_filter=1, nb_row=nb_row,
|
||||
nb_col=nb_row,
|
||||
border_mode=border_mode,
|
||||
subsample=subsample,
|
||||
dim_ordering='th')
|
||||
input_data = np.random.random(input_data_shape)
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
for input_data_shape in [(2, 3, 3, 1)]:
|
||||
layer = Convolution2D(nb_filter=1, nb_row=nb_row,
|
||||
nb_col=nb_row,
|
||||
border_mode=border_mode,
|
||||
subsample=subsample,
|
||||
dim_ordering='tf')
|
||||
input_data = np.random.random(input_data_shape)
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_MaxPooling1D(self):
|
||||
for ignore_border in [True, False]:
|
||||
for stride in [1, 2]:
|
||||
for pool_length in [1, 2]:
|
||||
for input_data_shape in [(2, 1, 3), (2, 1, 4)]:
|
||||
layer = MaxPooling1D(pool_length=pool_length, stride=stride, ignore_border=ignore_border)
|
||||
for pool_length in [1, 2]:
|
||||
for stride in [1]:
|
||||
for input_data_shape in [(2, 3, 4), (2, 4, 4)]:
|
||||
layer = MaxPooling1D(pool_length=pool_length,
|
||||
stride=stride,
|
||||
border_mode='valid')
|
||||
input_data = np.random.random(input_data_shape)
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_MaxPooling2D(self):
|
||||
for ignore_border in [True, False]:
|
||||
for stride in [(1, 1), (2, 2)]:
|
||||
for strides in [(1, 1), (2, 2)]:
|
||||
for pool_size in [(2, 2), (3, 3), (4, 4)]:
|
||||
for input_data_shape in [(2, 1, 3, 3), (2, 1, 4, 4), (2, 1, 5, 5), (2, 1, 6, 6)]:
|
||||
layer = MaxPooling2D(pool_size=pool_size, stride=stride, ignore_border=ignore_border)
|
||||
for input_data_shape in [(2, 1, 4, 4), (2, 1, 5, 5), (2, 1, 6, 6)]:
|
||||
layer = MaxPooling2D(pool_size=pool_size,
|
||||
strides=strides,
|
||||
border_mode='valid',
|
||||
dim_ordering='th')
|
||||
input_data = np.random.random(input_data_shape)
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_UpSample1D(self):
|
||||
layer = UpSample1D(length=2)
|
||||
for input_data_shape in [(2, 4, 4, 1)]:
|
||||
layer = MaxPooling2D(pool_size=pool_size,
|
||||
strides=strides,
|
||||
border_mode='valid',
|
||||
dim_ordering='tf')
|
||||
input_data = np.random.random(input_data_shape)
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_UpSampling1D(self):
|
||||
layer = UpSampling1D(length=2)
|
||||
input_data = np.random.random((2, 2, 3))
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_UpSample2D(self):
|
||||
layer = UpSample2D(size=(2, 2))
|
||||
def test_UpSampling2D(self):
|
||||
layer = UpSampling2D(size=(2, 2), dim_ordering='th')
|
||||
input_data = np.random.random((2, 1, 2, 3))
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
layer = UpSampling2D(size=(2, 2), dim_ordering='tf')
|
||||
input_data = np.random.random((2, 2, 3, 1))
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_ZeroPadding1D(self):
|
||||
layer = ZeroPadding1D(1)
|
||||
input_data = np.random.random((2, 2, 1))
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
def test_ZeroPadding2D(self):
|
||||
layer = ZeroPadding2D((1, 2))
|
||||
layer = ZeroPadding2D((1, 2), dim_ordering='th')
|
||||
input_data = np.random.random((2, 1, 2, 3))
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
layer = ZeroPadding2D((1, 2), dim_ordering='tf')
|
||||
input_data = np.random.random((2, 2, 3, 1))
|
||||
check_layer_output_shape(layer, input_data)
|
||||
|
||||
# #############
|
||||
# # Recurrent #
|
||||
# #############
|
||||
@@ -16,8 +16,11 @@ class TestTasks(unittest.TestCase):
|
||||
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)
|
||||
(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)
|
||||
@@ -32,14 +35,18 @@ class TestTasks(unittest.TestCase):
|
||||
model.add(Dense(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)
|
||||
history = model.fit(X_train, y_train, nb_epoch=15, batch_size=16,
|
||||
validation_data=(X_test, y_test),
|
||||
show_accuracy=True, verbose=0)
|
||||
self.assertTrue(history.history['val_acc'][-1] > 0.8)
|
||||
|
||||
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,),
|
||||
(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)
|
||||
@@ -51,13 +58,17 @@ class TestTasks(unittest.TestCase):
|
||||
model.add(Activation('tanh'))
|
||||
model.add(Dense(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)
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16,
|
||||
validation_data=(X_test, y_test), verbose=0)
|
||||
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=(3, 5),
|
||||
classification=True, nb_class=2)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000,
|
||||
nb_test=200,
|
||||
input_shape=(3, 5),
|
||||
classification=True,
|
||||
nb_class=2)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
@@ -67,15 +78,20 @@ class TestTasks(unittest.TestCase):
|
||||
y_test = to_categorical(y_test)
|
||||
|
||||
model = Sequential()
|
||||
model.add(GRU(y_train.shape[-1], input_shape=(None, X_train.shape[-1])))
|
||||
model.add(GRU(y_train.shape[-1], input_shape=(X_train.shape[1], X_train.shape[2])))
|
||||
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)
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16,
|
||||
validation_data=(X_test, y_test),
|
||||
show_accuracy=True, verbose=0)
|
||||
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=(3, 5), output_shape=(2,),
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000,
|
||||
nb_test=200,
|
||||
input_shape=(3, 5),
|
||||
output_shape=(2,),
|
||||
classification=False)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
@@ -83,14 +99,18 @@ class TestTasks(unittest.TestCase):
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
model = Sequential()
|
||||
model.add(GRU(y_train.shape[-1], input_shape=(None, X_train.shape[-1])))
|
||||
model.add(GRU(y_train.shape[-1], input_shape=(X_train.shape[1], X_train.shape[2])))
|
||||
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)
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16,
|
||||
validation_data=(X_test, y_test), verbose=0)
|
||||
self.assertTrue(history.history['val_loss'][-1] < 0.8)
|
||||
|
||||
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=(3, 5), output_shape=(3, 5),
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000,
|
||||
nb_test=200,
|
||||
input_shape=(3, 5),
|
||||
output_shape=(3, 5),
|
||||
classification=False)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
@@ -98,15 +118,19 @@ class TestTasks(unittest.TestCase):
|
||||
print('y_test:', y_test.shape)
|
||||
|
||||
model = Sequential()
|
||||
model.add(TimeDistributedDense(y_train.shape[-1], input_shape=(None, X_train.shape[-1])))
|
||||
model.add(TimeDistributedDense(y_train.shape[-1], input_shape=(X_train.shape[1], X_train.shape[2])))
|
||||
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)
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16,
|
||||
validation_data=(X_test, y_test), verbose=0)
|
||||
self.assertTrue(history.history['val_loss'][-1] < 0.8)
|
||||
|
||||
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, 8, 8),
|
||||
classification=True, nb_class=2)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=1000,
|
||||
nb_test=200,
|
||||
input_shape=(3, 8, 8),
|
||||
classification=True,
|
||||
nb_class=2)
|
||||
print('X_train:', X_train.shape)
|
||||
print('X_test:', X_test.shape)
|
||||
print('y_train:', y_train.shape)
|
||||
@@ -122,7 +146,9 @@ class TestTasks(unittest.TestCase):
|
||||
model.add(Dense(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)
|
||||
history = model.fit(X_train, y_train, nb_epoch=12, batch_size=16,
|
||||
validation_data=(X_test, y_test),
|
||||
show_accuracy=True, verbose=0)
|
||||
print(history.history['val_acc'][-1])
|
||||
self.assertTrue(history.history['val_acc'][-1] > 0.9)
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário