Comparar commits

..

479 Commits

Autor SHA1 Mensagem Data
Francois Chollet df42e997b7 Merge branch 'master' into keras-1 2016-04-11 09:20:52 -07:00
Francois Chollet 1e71732600 Replace master branch with Keras 1.0 2016-04-11 09:19:03 -07:00
Francois Chollet 141e05e3a7 Update Theano installation instruction 2016-04-11 08:51:01 -07:00
Francois Chollet cadd3e4e2c Make TimeDistributed accept a mask 2016-04-11 08:18:39 -07:00
Francois Chollet 09034d9e17 Add badges to README 2016-04-11 07:49:29 -07:00
Francois Chollet 5706d1d688 Bugfix 2016-04-10 08:36:00 -07:00
Francois Chollet 41b9777746 Clean up training a bit 2016-04-10 07:45:54 -07:00
Francois Chollet d31fe1ac34 Fix LSTM regularizers 2016-04-10 07:45:54 -07:00
Francois Chollet c0eedfeca0 change optimizer in example 2016-04-10 07:45:54 -07:00
Francois Chollet dc8b5509f3 Small fixes in topology engine 2016-04-10 07:45:54 -07:00
Nic Eggert ddec052dab Remove restriction on strides in theano backend conv2d. (#2238)
Previously, strides were required to be smaller than the convolution
kernel. Usually, this is what a user wants, but there are edge
cases where one might want to do this (for instance, projection
shortcuts in Residual Networks).
2016-04-09 18:48:05 -07:00
Francois Chollet 2e45022c95 Clarify interface of in_train_phase 2016-04-08 14:14:22 -07:00
Francois Chollet cec7f73bca Fix irnn example 2016-04-08 14:11:40 -07:00
Francois Chollet 30989dc997 Fix generator methods. 2016-04-08 12:59:09 -07:00
Fariz Rahman 50a0d1cad4 Update topology.py (#2239) 2016-04-08 10:40:58 -07:00
Fariz Rahman 3db1f132a7 call : remove train arg from doc string (#2235) 2016-04-08 08:59:55 -07:00
Fariz Rahman 3b196feda5 Typo fix (#2234) 2016-04-08 08:59:43 -07:00
berleon dd766c68d9 Fix LeakyReLU return dtype (#2214)
LeakyReLU returns a tensor with float64 dtype.
It is stupid, but this line actually produces a float64 array:

```
    0.5*np.array(0.2, dtype=np.float32)
```

The theano nnet.relu function does something similar like this with the
LeakyReLU alpha parameter, which lead to a float64 tensor.
The solution is to not cast the alpha to float32.

Furthermore I tighten the `test_utils.layer_test`. It is now
required that the layer's output dtype is equal to the input dtype.
2016-04-07 17:02:03 -07:00
Francois Chollet 599e070824 Small fixes to the docs. 2016-04-07 16:52:09 -07:00
Francois Chollet 04c998a742 Fix typos 2016-04-07 14:25:41 -07:00
Francois Chollet cc985c3a9c Update docs, visualization utils 2016-04-07 14:23:34 -07:00
Francois Chollet 36cc508030 New documentation 2016-04-06 17:34:25 -07:00
Francois Chollet 444cd56740 Update README 2016-04-06 17:33:39 -07:00
Francois Chollet 88a86f7e45 Merge branch 'keras-1' of https://github.com/fchollet/keras into keras-1 2016-04-06 17:23:21 -07:00
Francois Chollet d6f94c0bc9 Fix docstring 2016-04-06 17:21:31 -07:00
Francois Chollet 2157aa6172 Make function compilation lazy 2016-04-06 17:21:21 -07:00
Francois Chollet 2013527840 Add docstrings to TF backend 2016-04-06 17:21:00 -07:00
Francois Chollet 8c73c6f218 Simplify lstm example 2016-04-06 17:20:43 -07:00
Michael Oliver 63059f6063 Bug fix to set correct uses_learning_phase flag
```test_on_batch``` and ```predict_on_batch``` had the wrong ```uses_learning_phase``` flag
2016-04-06 16:56:31 -07:00
Francois Chollet e179198410 Cache recursive calls in build_map_of_graph 2016-04-06 13:30:07 -07:00
Francois Chollet ed4a95bdad Slight cleanup of build_map_of_graph 2016-04-06 11:46:18 -07:00
Francois Chollet 1baddb9094 Docstrings cleanup 2016-04-06 11:46:01 -07:00
Francois Chollet 3160a445a8 Merge branch 'keras-1' of https://github.com/fchollet/keras into keras-1 2016-04-06 09:05:04 -07:00
Francois Chollet d627fd8781 Docstrings improvements 2016-04-06 09:04:53 -07:00
Michael Oliver b4bdc5a0fa add in predict_generator and tests
* add in predict_generator and tests

* fix PEP8 details

* Pre-allocate predictions

* make predictions return list if neccessary

* reset batch_size for other tests, make less wonky generator
2016-04-06 09:03:37 -07:00
Francois Chollet 6911fa2cba Fix typos in functional API guide 2016-04-05 10:27:11 -07:00
Francois Chollet 0d7c8711bd Fix JSON serialization issue 2016-04-05 10:26:57 -07:00
Francois Chollet d8b0fe0957 Correct functional API guide 2016-04-04 21:49:16 -07:00
Francois Chollet 263de77a5a Improve README, functional API guide 2016-04-04 21:46:27 -07:00
Francois Chollet d3615e682e Small fixes. 2016-04-04 15:00:06 -07:00
Michael Oliver 35da9d6ef2 Make tensorflow backend fully mimic theano.dot
* Squashed commit of the following:

commit f25b56f3a7547da94ffecee8701da5b34e757104
Author: Michael Oliver <michael.d.oliver@gmail.com>
Date:   Mon Apr 4 19:01:49 2016 +0000

    add proper shape inference

commit 5544f66148676d86cb53309701eee6a4e99a3aeb
Author: Michael Oliver <michael.d.oliver@gmail.com>
Date:   Mon Apr 4 18:03:05 2016 +0000

    Make PEP8 compliant and use int_shape

commit 0fe6e02699e2da553f8f1a866aaaa081c26a1cbd
Author: Michael Oliver <michael.d.oliver@gmail.com>
Date:   Mon Apr 4 03:35:29 2016 +0000

    Make tensorflow backend fully mimic theano dot

* fix None comparison
2016-04-04 14:30:55 -07:00
cmyr dbe7662e72 add sparse_categorical_crossentropy 2016-04-04 14:24:41 -07:00
Francois Chollet 30118bbab0 Improve docstrings, UX of common user mistakes 2016-04-04 14:22:28 -07:00
Francois Chollet 2902149f77 Finish PR backporting 2016-04-04 11:30:24 -07:00
Francois Chollet eb8b40cccd Fix captioning example in docs 2016-04-04 11:09:20 -07:00
Francois Chollet 76da13dff6 Backport of conv2d PRs by @ns 2016-04-04 11:09:06 -07:00
Francois Chollet f7cbdff79c Improve model training tests 2016-04-04 10:25:58 -07:00
Francois Chollet 81233b3cd3 Fix lambda serialization issue in Py3 2016-04-04 10:11:29 -07:00
Fariz Rahman af88e051fa Typo fix 2016-04-04 07:38:54 -07:00
berleon 6ad6b19bd6 Merge layer handle none in input_shapes 2016-04-04 07:34:36 -07:00
Francois Chollet 0242ca59ac Update version numbers 2016-04-03 20:58:13 -07:00
Francois Chollet c064963ef8 Fix Py3 compatibility issue in test 2016-04-03 20:22:29 -07:00
Francois Chollet 4318718769 Fix PEP8 2016-04-03 20:22:17 -07:00
Francois Chollet f981bdb551 Update functional API guide 2016-04-03 20:04:14 -07:00
Francois Chollet 3860e078a5 Small fixes in optimizers docstrings 2016-04-03 20:04:14 -07:00
Eder Santana d09e2a67bb fix batch_dot tests on backend
* Fix merge_dot tests

* Make batch_dot unique

batch_dot is not tensordot! It only accepts one reduce dimension at a
time. Other reduce dimensions should be dome afterwards with K.sum
This means that K.batch_dot will have the same behavior in both
tensorflow and theano. This also means that we have less parenthesis and
less nested lists.

New usage:

merge_mode = 'dot', dot_axes=[axis1, axis2]

Before:

merge_mode = 'dot', dot_axes=[[axis1], [axis2]]

* Backport sign by @the-moliver

* Fix docstrings

* Fix backend batch_dot tests
2016-04-03 20:04:00 -07:00
Francois Chollet 56ba6b9c7e Merge branch 'keras-1' of https://github.com/fchollet/keras into keras-1 2016-04-03 18:58:18 -07:00
berleon a9c6f26412 Add defaults for _gather_[list/dict]_attr
For example the Dense Layer does not have a update attribute, which

results in an error.
2016-04-03 18:58:08 -07:00
Francois Chollet 73817b8b77 More thorough tests for TimeDistributed 2016-04-03 13:38:46 -07:00
Francois Chollet 3f128b9838 Merge branch 'keras-1' of https://github.com/fchollet/keras into keras-1 2016-04-03 13:19:38 -07:00
berleon 9621bb5b8e fix h5py string encoding
When saving the weights a TypeError is raised by h5py.

See this issue https://github.com/h5py/h5py/issues/289 for details.

As it is recommended in the issue, the strings are now encoded as utf8.
2016-04-03 13:19:12 -07:00
Francois Chollet 836fb03aa0 Merge branch 'keras-1' of https://github.com/fchollet/keras into keras-1 2016-04-03 10:32:38 -07:00
Eder Santana c3aaf50b64 Update complete_guide_to_the_keras_functional_api.md
small changes
2016-04-03 10:29:02 -07:00
Francois Chollet fe00f5ff64 Fix learning phase issue with regularizers 2016-04-03 10:28:06 -07:00
Eder Santana 8b3543fca9 Fix merge_dot tests
* Fix merge_dot tests

* Make batch_dot unique

batch_dot is not tensordot! It only accepts one reduce dimension at a
time. Other reduce dimensions should be dome afterwards with K.sum
This means that K.batch_dot will have the same behavior in both
tensorflow and theano. This also means that we have less parenthesis and
less nested lists.

New usage:

merge_mode = 'dot', dot_axes=[axis1, axis2]

Before:

merge_mode = 'dot', dot_axes=[[axis1], [axis2]]

* Backport sign by @the-moliver

* Fix docstrings
2016-04-03 10:03:09 -07:00
Leon Chen a6fe2ae341 test against latest tensorflow in travis 2016-04-03 10:02:31 -07:00
graham 3ca7751445 fixed slice_X import location 2016-04-02 19:00:26 -07:00
Francois Chollet ebfde534c0 Add weight deduping before updates computation 2016-04-02 10:37:57 -07:00
Eder Santana f8c7dbb758 Backport #2123 by @carlthome
Backport #2123 by @carlthome
2016-04-01 21:27:20 -07:00
Francois Chollet 62f9053330 Fix babi_rnn example 2016-04-01 21:14:05 -07:00
Francois Chollet c429e651c1 Fix weight regularizers 2016-04-01 21:13:57 -07:00
Francois Chollet dacf017d38 Fix potential issue in topology engine 2016-04-01 21:13:34 -07:00
Francois Chollet dc3c1488bb Fix unit tests for Merge 2016-04-01 18:01:41 -07:00
Francois Chollet 4d7ff76cfb Fix some more tests 2016-04-01 16:45:05 -07:00
Francois Chollet 8ad6865952 Fix conv3d tests 2016-04-01 16:12:04 -07:00
Francois Chollet 2a4f6b942d Add more tests 2016-04-01 15:58:19 -07:00
Francois Chollet 91a819fb34 Fix engine issue 2016-04-01 15:58:07 -07:00
Francois Chollet 52dbeb1f26 Reintroduce failing siamese test 2016-04-01 15:57:45 -07:00
Francois Chollet 0836e47dfc Theano: warn on unused input 2016-04-01 15:56:30 -07:00
Francois Chollet 75bef59016 Unify dot behavior in TF and Theano 2016-04-01 15:56:19 -07:00
Francois Chollet 337c0c66cf Remove shape infer test (now incl in layers tests) 2016-04-01 13:36:28 -07:00
Francois Chollet f8e2df16f1 Fix TF batch_dot 2016-04-01 13:36:03 -07:00
Francois Chollet 10deb8f267 Add batchnorm unit tests 2016-04-01 13:25:59 -07:00
Francois Chollet efe5916109 Fix convolutional tests 2016-04-01 13:25:48 -07:00
Francois Chollet 64449c196e Fix recurrent tests 2016-04-01 13:25:37 -07:00
Francois Chollet f57128bd3d Fix wrappers 2016-04-01 13:25:13 -07:00
Francois Chollet 8740791d5c Small fixes to core layers 2016-04-01 13:24:48 -07:00
François Chollet 6ddb5a0452 Merge pull request #2158 from EderSantana/keras-1
Add batch_dot to backend
2016-04-01 08:38:29 -07:00
EderSantana 133699c2f3 keras.engine.topology.Merge uses K.batch_dot 2016-04-01 10:56:12 -04:00
EderSantana b0ea92bc12 Add batch_dot to backend 2016-04-01 00:15:28 -04:00
fchollet b587aeee1c Remove badge from README 2016-03-31 19:13:22 -07:00
Francois Chollet e754581ecb Fix noise layers 2016-03-31 19:08:07 -07:00
Francois Chollet fcb6ae8eed Fix activity regularization 2016-03-31 18:46:24 -07:00
Francois Chollet bf4dab3501 Update core layers 2016-03-31 18:17:17 -07:00
Francois Chollet a066cf8680 Fix advanced activations. 2016-03-31 16:43:10 -07:00
Francois Chollet 7448dcea65 Fix optimizers tests 2016-03-31 13:41:30 -07:00
Francois Chollet cf3b3dff32 Fix regularizers 2016-03-31 13:41:21 -07:00
Francois Chollet ca96737b20 Fix callbacks 2016-03-31 13:41:07 -07:00
Francois Chollet 61ade48343 Some cleanup 2016-03-31 11:50:30 -07:00
Francois Chollet 295bfe4e3a Keras 1.0 preview. 2016-03-31 11:35:27 -07:00
Francois Chollet bdd70d06d3 Prepare 0.3.3 release (last release before 1.0). 2016-03-31 11:15:44 -07:00
François Chollet 39a3be60c0 Merge pull request #2109 from the-moliver/sign
add sign operation to backends
2016-03-31 11:07:02 -07:00
François Chollet d81e4127fb Merge pull request #2123 from carlthome/master
Support low-precision floats
2016-03-31 11:04:11 -07:00
Carl Thomé 122be6e30b Support low-precision floats 2016-03-29 20:13:45 +02:00
Michael Oliver 8056f0dd37 add sign operation to backends 2016-03-28 19:43:49 +00:00
François Chollet 3a61ace619 Merge pull request #2098 from kylemcdonald/patch-4
roll jitter instead of pixel jitter for deep dream
2016-03-28 09:49:57 -07:00
Kyle McDonald 8661e78f08 roll jitter instead of pixel jitter for deep dream 2016-03-27 11:21:23 -04:00
François Chollet 90aafca585 Merge pull request #2055 from EderSantana/batch_dot
Batch dot
2016-03-25 17:18:50 -07:00
EderSantana d2ce350657 2D tensor support for batch_dot 2016-03-25 10:12:55 -04:00
EderSantana d4fce4f5f1 batch_dot supports arbitrary sized arrays 2016-03-24 15:35:21 -04:00
François Chollet 5e301d1f63 Merge pull request #2044 from NasenSpray/conv2d
Use T.nnet.conv2d interface
2016-03-24 08:53:42 -07:00
EderSantana 4e5348c5ca Add batch_dot to core.py layers 2016-03-23 18:52:57 -04:00
EderSantana a19db7b672 Add batch_dot to backend 2016-03-23 18:46:00 -04:00
François Chollet 85ebccfcc8 Merge pull request #2049 from grahamannett/patch-1
prevent UnicodeDecodeError
2016-03-23 13:59:30 -07:00
graham 677e9ee8ba prevent UnicodeDecodeError
Fix error that arises on some systems where python tries to read text as ascii
2016-03-23 05:49:16 -07:00
ns 0f4c7864ba fixed weird performance regression with up-to-date Theano 2016-03-23 09:27:29 +01:00
ns 63c099714b PEP8 fix 2016-03-23 08:53:36 +01:00
ns 3dd27c61fb fixed output shape for even kernels 2016-03-23 08:37:11 +01:00
ns 6543b67509 use Theano's new T.nnet.conv2d interface 2016-03-23 04:53:54 +01:00
François Chollet d0b348a55a Merge pull request #2037 from TheRushingWookie/master
Fixed the image captioning example
2016-03-22 19:03:29 -07:00
Quinn Jarrell 9f8d3cb399 Changed the image captioning example so it works with current keras. It was misusing the merge layer and had an incorrect parameter in of the GRU layers. Should fix issue #1522. 2016-03-22 15:40:55 -04:00
François Chollet deb4c06df8 Merge pull request #2013 from carlthome/master
Warn when epoch sees more samples than expected
2016-03-21 22:44:21 -07:00
François Chollet d3cc1de2d7 Merge pull request #2027 from sudeepraja/master
Added fix for training h5py dataset on Graph model
2016-03-21 22:43:20 -07:00
Sudeep Raja 404a30df88 Update models.py
Added fix for training h5py dataset on Graph model
2016-03-22 03:51:02 +05:30
Carl Thomé 3bd7d11170 Don't assume what a batch generator does 2016-03-21 15:59:07 +01:00
Carl Thomé 9ac50e0050 Warn when epoch sees more samples than expected 2016-03-20 19:51:24 +01:00
Francois Chollet 1145fec39f Update backend 2016-03-19 09:06:52 -07:00
François Chollet b0303f03ff Merge pull request #1968 from cadurosar/master
Fix Reproducibility with ImageDataGenerator
2016-03-14 18:34:34 -07:00
François Chollet 2716dcd6ab Merge pull request #1963 from jnphilipp/fix_config
Fixed get_config for SReLU.
2016-03-14 18:33:52 -07:00
François Chollet fef9de0d17 Merge pull request #1961 from giorgiop/typos_examples
typos in examples
2016-03-14 18:33:40 -07:00
Carlos Eduardo Rosar Kos Lassance 2dcafafcf9 change all instances of python random to numpy random in keras/preprocessing/image 2016-03-14 16:55:57 +01:00
jnphilipp 775664fdb8 Fixed nulls in input_shape. 2016-03-14 13:36:05 +01:00
jnphilipp a67034ee7c Fixed get_config for SReLU. 2016-03-14 12:48:08 +01:00
giorgiop e72bb9506a fixed typos 2016-03-14 11:27:20 +11:00
Francois Chollet ecd414d716 Fix RNN regularizers 2016-03-11 21:29:37 -08:00
Francois Chollet 80a831de1a Fix failing Lambda test 2016-03-11 17:54:19 -08:00
Francois Chollet 37fd456a5c Lambda layer improvements 2016-03-11 17:29:37 -08:00
Francois Chollet 0c1af0901d Remove class_mode, add support for acc in Graph 2016-03-11 17:29:17 -08:00
François Chollet 70431a5336 Merge pull request #1953 from tjrileywisc/master
Added os import so that check for weights file runs.
2016-03-11 11:06:10 -08:00
Francois Chollet cf3ab771d3 Cleanup of image processing utils. 2016-03-11 11:01:25 -08:00
Francois Chollet 524090e600 Cleanup of text/sequence preprocessing utils. 2016-03-11 10:50:57 -08:00
tim riley 9c9318ff6b Added os import so that check for weights file runs. 2016-03-11 12:57:14 -05:00
fchollet f75f70a60d Update examples in documentation 2016-03-10 21:31:35 -08:00
fchollet e3c31aa762 Merge branch 'master' of ssh://github.com/fchollet/keras 2016-03-10 20:57:18 -08:00
fchollet ef1e959505 Update visualize_util 2016-03-10 20:49:01 -08:00
François Chollet c5b8a1df80 Merge pull request #1943 from matt-peters/compile_kwargs
Allow passing kwargs down to K.function
2016-03-10 16:43:35 -08:00
Matthew Peters e73cf505a7 Add helpful error messages for invalid kwargs in K.function 2016-03-10 16:18:48 -08:00
Matthew Peters 8606edf3bf Allow passing kwargs down to K.function 2016-03-10 15:20:18 -08:00
Francois Chollet 71d46b7153 Fix docstring 2016-03-10 13:28:21 -08:00
Francois Chollet 7f3b2067bc Merge branch 'sklearn' of https://github.com/ipod825/keras into ipod825-sklearn 2016-03-10 13:22:55 -08:00
François Chollet ed882f4064 Merge pull request #1934 from danieldk/tf-backwards-fix
Tensorflow: reverse mask on go_backwards.
2016-03-09 11:17:06 -08:00
Daniël de Kok 126b820561 Tensorflow: reverse mask on go_backwards. 2016-03-09 10:27:25 +01:00
ipod825 b50624debd Add code to avoid user's typo in sk_params 2016-03-08 12:12:45 +08:00
François Chollet 709390dfdb Merge pull request #1918 from snurkabill/allow_soft_placement
by allowing soft placement into keras, we can run whole keras model u…
2016-03-07 19:27:28 -08:00
Jiří Vahala 56c492cbcc by allowing soft placement into keras, we can run whole keras model using tensorflow's "with("/:gpu42")" syntax 2016-03-08 03:34:17 +01:00
fchollet bde45eff87 Split model tests, fix create_output graph bug 2016-03-07 17:48:54 -08:00
Francois Chollet ce7276bc55 Merge branch 'master' of https://github.com/fchollet/keras 2016-03-07 16:48:30 -08:00
Francois Chollet fc476840fa Style fixes 2016-03-07 16:46:19 -08:00
Francois Chollet cfcb1e8703 Switch to symbolic shapes for TF in K.shape() 2016-03-07 16:46:11 -08:00
fchollet 8ba647c196 Fix PEP8 2016-03-06 19:07:49 -08:00
fchollet a86057d91c Improve error messages in TF backend. 2016-03-06 17:32:07 -08:00
fchollet 1ebeff8ee3 Move data_utils to utils.data_utils. 2016-03-06 17:31:57 -08:00
Francois Chollet be4a86f6dc Fix PEP8 2016-03-05 22:41:25 -08:00
Francois Chollet e5ccf53531 Fix typo 2016-03-05 22:24:18 -08:00
Francois Chollet ef93e2cffd Merge branch 'timedistributed' 2016-03-05 21:48:56 -08:00
Francois Chollet b8c59acd77 Improve tests for TimeDistributed 2016-03-05 21:48:41 -08:00
Francois Chollet 3cc242615d TimeDistributed: +docstring, perf improv, TF warn 2016-03-05 21:48:29 -08:00
Francois Chollet 6596cc79d6 Fix variable-size shape inference in padding layer 2016-03-05 21:18:12 -08:00
Francois Chollet cd28c6d07e Merge branch 'master' of https://github.com/fchollet/keras 2016-03-04 14:11:17 -08:00
Francois Chollet b883761820 Neural style transfer: remove input preprocessing. 2016-03-04 14:10:45 -08:00
François Chollet b2b04b0fff Merge pull request #1893 from kylemcdonald/patch-3
changed doc `(input_dim,)` to `(output_dim,)`
2016-03-04 13:41:56 -08:00
Francois Chollet 9e2628e811 Fix neural style transfer example 2016-03-04 13:41:01 -08:00
Kyle McDonald 537fb1cc01 changed doc (input_dim,) to (output_dim,) 2016-03-04 15:54:11 -05:00
François Chollet 99891c0cc8 Merge pull request #1892 from kylemcdonald/patch-2
corrected documentation of "weights" argument
2016-03-04 12:45:03 -08:00
Kyle McDonald d748db43ae corrected documentation of "weights" argument 2016-03-04 15:29:28 -05:00
fchollet 4ec84541e3 Fixes in imagedatagenerator 2016-03-02 20:44:07 -08:00
François Chollet ca05efc76f Merge pull request #1862 from qdbp/issue_1857
Fixing issue 1857
2016-03-01 11:30:19 -08:00
Francois Chollet 7768ae04a2 actually use nb_[val_]_worker args 2016-03-01 13:48:29 -05:00
Francois Chollet 0daec53acb Style fixes 2016-03-01 10:14:56 -08:00
berleon d9ca798c60 fix initialization of BatchNormalization
Currently the scaling parameter gamma is uniformly sampled between
-0.05 and 0.05. This also brings the std -0.05 and 0.05 and not to
1 as claimed by the docstring of the BatchNormalization class.

This commit fixes it by initializing gamma to 1.  The same
initialization is used by
(lasagne)[http://lasagne.readthedocs.org/en/latest/modules/layers/normalization.html#lasagne.layers.BatchNormLayer]
2016-03-01 13:47:00 +00:00
Francois Chollet 990ef92a60 Merge branch 'master' of https://github.com/fchollet/keras 2016-02-29 20:25:19 -08:00
Francois Chollet becc5f3a2c Add support for dim_ordering in initializations 2016-02-29 20:18:17 -08:00
François Chollet e5d0dc65e0 Merge pull request #1856 from GregorySenay/master
Update Siamese layer set weights function
2016-02-29 18:48:03 -08:00
Francois Chollet 48ce23086b Fix recurrent dropout 2016-02-29 16:41:54 -08:00
Francois Chollet a3c9d2d7c9 Merge branch 'master' of https://github.com/fchollet/keras 2016-02-29 10:50:21 -08:00
Francois Chollet 9efe17aeea Fix RNN get initial states recursion issue 2016-02-29 10:50:08 -08:00
fchollet 763a2a9536 Style and dosctring fixes, sklearn wrapper. 2016-02-28 11:54:00 -08:00
Francois Chollet 4a43567cea Update FAQ 2016-02-28 10:13:52 -08:00
ipod825 be24159959 Refactoring of sklearn 2016-02-28 13:46:20 +08:00
Francois Chollet 943d2d4cf8 Add native names to weight tensors 2016-02-27 17:43:18 -08:00
Francois Chollet c4361d2246 Improve Lambda layer shape inference for TF 2016-02-27 12:10:58 -08:00
Francois Chollet 80927fa958 Fix Theano backend pool 2016-02-27 11:54:48 -08:00
Francois Chollet f3f19146f9 Remove dummy inputs in layers 2016-02-27 11:24:04 -08:00
fchollet 3799660504 Update pool module import for Theano 2016-02-27 10:46:46 -08:00
Francois Chollet 9b4f973d57 Fix lstm regularizers 2016-02-26 13:04:14 -08:00
Francois Chollet 567fdccd0b Add Merge input_shape property 2016-02-26 11:38:36 -08:00
Francois Chollet cf755a9c7c Merge branch 'master' of https://github.com/fchollet/keras 2016-02-26 10:46:40 -08:00
Francois Chollet ff2f8ac69b Fix stateful LSTM example 2016-02-26 10:45:12 -08:00
François Chollet 428f4bfde6 Merge pull request #1832 from NasenSpray/fix_mean
T.mean() on int tensors returns float64; use _FLOATX instead
2016-02-26 09:15:48 -08:00
François Chollet 7552f2c26d Merge pull request #1834 from farizrahman4u/patch-5
Fix imports : bAbI Example
2016-02-26 08:45:37 -08:00
Fariz Rahman 0eea5f8867 Fix imports : bAbI Example 2016-02-26 22:13:06 +05:30
ns 47c67ac19a T.mean() on int tensors returns float64; use _FLOATX instead 2016-02-26 16:50:57 +01:00
François Chollet 55d9374961 Merge pull request #1824 from farizrahman4u/patch-2
bAbI: Doubling the FB LSTM baseline :)
2016-02-25 12:51:04 -08:00
Francois Chollet 045e47174f Add generic TimeDistributed layer. 2016-02-25 12:41:53 -08:00
Fariz Rahman 22c091ae3f bAbI: Doubling the FB LSTM baseline :) 2016-02-26 01:06:52 +05:30
François Chollet d20fe64a69 Merge pull request #1823 from EderSantana/patch-6
Update SiameseHead
2016-02-25 11:33:42 -08:00
Eder Santana c6c150b042 Update SiameseHead
We forgot to pass the train parameter to the layer.__call__ inside get_output_at. This is a bug.
2016-02-25 13:50:08 -05:00
Francois Chollet ababd95210 Fix merge conflicts 2016-02-25 10:36:24 -08:00
François Chollet ff676f10f6 Merge pull request #1811 from fchollet/faster-rnn
Possibly faster RNNs
2016-02-25 10:15:45 -08:00
Fariz Rahman 73e563ecaf Speed up RNNs
Update core.py

Fix TF indexing issue

Update recurrent.py

TF slicing issue workaround

Update recurrent.py

Update core.py

Update core.py

Remove all backend specific code

shape[-1] instead of input_dim

Update core.py

space fix

Update core.py

Fix TF reshape issue

Update recurrent.py

Update core.py

Fix overflow issue in 3D softmax

Improve readability
2016-02-25 23:31:28 +05:30
François Chollet 3f905e4a35 Merge pull request #1817 from AIshb/patch-1
Fix a little bug in pad_sequences
2016-02-25 09:51:48 -08:00
Francois Chollet 98e2789db9 Readability improvements 2016-02-25 09:05:59 -08:00
François Chollet 8a6cf4c13e Merge pull request #1816 from smohsensh/patch-1
fix add_shared_node SiameseHead naming
2016-02-25 08:22:52 -08:00
AIshb f4af11c730 Update sequence.py
fix a little mistake in pad_sequences
2016-02-25 20:31:28 +08:00
mohsen 9f2aa1b6ae fix add_shared_node SiameseHead naming 2016-02-25 15:31:33 +03:30
Francois Chollet abca83373d Possibly faster RNNs
Forgot dropout.

Various fixes

Fix SimpleRNN dropout typo
2016-02-24 22:15:05 -08:00
Fariz Rahman 3aa807a0c8 Speed up softmax too
Update core.py

Update core.py

Update core.py

Update core.py

Update core.py

Update theano_backend.py

Update tensorflow_backend.py
2016-02-25 10:39:36 +05:30
Fariz Rahman 089fa11752 TimeDistributedDense Speed up
Update core.py
2016-02-25 10:38:49 +05:30
Francois Chollet 06a1545645 Style fixes 2016-02-24 13:05:47 -08:00
François Chollet 461573a8d9 Merge pull request #1790 from neggert/call-layer-cache
Enable cache optimization for __call__
2016-02-24 12:45:29 -08:00
François Chollet db8f43128b Merge pull request #1801 from farizrahman4u/patch-26
Lambda layer: Bug Fix
2016-02-23 20:53:56 -08:00
Fariz Rahman 80ddb5b3b8 Update core.py 2016-02-24 03:10:33 +05:30
Gregory 3ffba42466 Update core.py
Change Siamese set_weights function to avoid false nb layers value
2016-02-23 11:07:38 -08:00
François Chollet 2c49115cd3 Merge pull request #1792 from neggert/pool-border-same
Implement border_mode="same" for pool2d in Theano
2016-02-22 15:55:24 -08:00
z001qdp bbaa66c530 Implement border_mode="same" for pool2d in Theano 2016-02-22 16:30:02 -06:00
François Chollet 784d81d2c8 Merge pull request #1623 from oeway/master
Convolutional layers for 3D
2016-02-22 12:47:06 -08:00
z001qdp 523e9845d7 Make layer and shape caches more robust
Move caches to properties so that containers can override the
implementation to ensure that the cache gets propagated correctly
to child layers when it is changed.

Reset instead of disabling layer and shape cache  in __call__

Previously, __call__ did not get the speed benefits from caching
because it disabled it in order to feed the layer new input. This
meant that __call__ could be very slow on complicated structures.
Now, instead of disabling it, we temporarily empty it, then restore
the original when we're done.
2016-02-22 14:21:21 -06:00
François Chollet 47bd0af702 Merge pull request #1721 from neggert/graph-call
Make __call__ work properly for Graph
2016-02-22 11:09:52 -08:00
François Chollet 82d3489764 Merge pull request #1789 from yaringal/BRNN_latest
Update example file `imdb_lstm.py` to use dropout in RNNs
2016-02-22 10:23:03 -08:00
z001qdp 44d558ad7f Refactor implementation of __call__.
This refactor allows the inherited method to work properly for
Sequential and Graph (with single input) containers in addition
to normal layers, so there's no need to override the method.
Previously, __call__ did not work correctly for Graph containers.

Implement Graph.__call__ for multiple inputs

Add option (re-)initialize weights in set_previous

This allows us to use set_previous in places where we previously
manually adjusted the previous layer, which means that layers
that have non-standard set_previous implementations (like Graph)
work properly when they are, for example, the first layer in a
Sequential model.

This commit also adds a clear_previous method.

Add input_shape property to Graph container
2016-02-22 12:21:07 -06:00
Yarin cbd11315b7 Update example file imdb_lstm.py to use dropout in RNNs 2016-02-22 17:55:59 +00:00
Yarin 1588998ee8 Merge https://github.com/fchollet/keras into BRNN_latest 2016-02-22 17:54:23 +00:00
fchollet 58ca064f93 Use MSE in stateful example. 2016-02-22 09:10:28 -08:00
Wei OUYANG 3ecf201aea Add 3D Convolutional layers(Convolution3D, MaxPooling3D, AveragePooling3D, UpSampling3D and ZeroPadding3D, working with theano backend)
---------------------------------------
Squashed from the following commits
add Convolution3D and MaxPooling3D layers
fix 5D tensor in theano, add examples
update conv3d, pool3d, add resize_volumes and spatial_3d_padding
update Convolution3D, MaxPooling3D and AveragePooling3D, add UpSampling3D and ZeroPadding3D
add test functions for Convolution3D, MaxPooling3D, AveragePooling3D, ZeroPadding3D and UpSampling3D
small fix by changing pad_z to pad_t
update comment
skip some tests for tenforflow, @pytest.mark.skipif(K._BACKEND != theano, reason="Requires Theano backend")
use autopep8 to fix the code to match pep8 coding style
small fix (caused by autopep8)
small fix (caused by autopep8)
small fix (caused by autopep8)
fixed the document string for all newly added layers
remove the example and the dataset for 3d
add error messge for tensorflow backend
support stride in pool3d
Rename "params" to "trainable_weights"
change notations and docstrings for 3D layers
fix pep8 error
change variable name in test code
small fix for pep8
add error message and docstring for strides in conv3d
fix test error caused by wrong strides in conv3d
support strides in conv3d by slicing the output
add if statement for stride (1,1,1)
fix get_config according to mdering, and other small fix
fix model_from_json issue by passing a 3d border_mode
fix according to jruales' review
change docstring in Convolution3D
delete docstring about TensorFlow
change docstring in Convolution3D and theano_backend
---------------------------------------

Author:    Wei OUYANG <oeway007@gmail.com>
2016-02-22 16:02:11 +01:00
fchollet 654404c2ed Add a few explanatory comments in recurrent.py 2016-02-21 19:46:06 -08:00
fchollet 7896ef7143 Style standardization 2016-02-21 19:31:22 -08:00
François Chollet 0c75006d12 Merge pull request #1782 from EderSantana/patch-5
Sensible activation for RNNs
2016-02-21 19:20:47 -08:00
Eder Santana c7f7ffe7c4 Sensible activation for RNNs
Have noticed how default GRUs works usually worse than LSTMs? It seems that "tanh" is a more sensible activation choice. Also for GRUs, tanh seems to be the default:
see http://arxiv.org/pdf/1412.3555v1.pdf Section 3.2
2016-02-21 19:59:05 -05:00
Francois Chollet f10c430731 Style fixes, fix flaky test 2016-02-21 16:53:15 -08:00
Francois Chollet ea5cb74414 Merge branch 'BRNN_latest' of https://github.com/yaringal/keras into yaringal-BRNN_latest 2016-02-21 16:34:16 -08:00
Yarin 606a9b6810 Merge https://github.com/fchollet/keras into BRNN_latest 2016-02-21 23:51:52 +00:00
Yarin 35c5fa911d clean up 2016-02-21 23:31:32 +00:00
fchollet d4e9696447 Merge branch 'master' of ssh://github.com/fchollet/keras 2016-02-21 12:16:49 -08:00
fchollet 4cff0623de Update documentation. 2016-02-21 12:16:39 -08:00
François Chollet bc82613eae Merge pull request #1767 from neggert/seq-set-weights
Fix `Sequential.set_weights` for nested containers
2016-02-21 11:49:50 -08:00
fchollet 0ec57f28bc Fix fit_generator docstring 2016-02-21 11:35:13 -08:00
fchollet 860e4e9177 Various fixes in evaluate_generator/fit_generator. 2016-02-21 11:23:07 -08:00
Yarin a2fdc32381 use less memory when dropout is disabled 2016-02-21 17:57:58 +00:00
shmo d1a3842b3d implement validate_generator and the use of validation generators in fit_generator 2016-02-21 10:24:27 -05:00
Yarin 5406bd3ad2 updated dropout test 2016-02-21 03:21:20 +00:00
Yarin 941c3f6ae8 fixes following fchollet's comments 2016-02-21 03:04:37 +00:00
Yarin bec2701214 remove new line at end of file 2016-02-20 06:00:32 +00:00
Yarin bc60832dcf lint 2016-02-20 05:41:50 +00:00
Yarin 96483326d8 fixed tensorflow bug 2016-02-20 05:20:37 +00:00
Yarin fed7cc257e switched from broadcasting to K.expand_dim and from slicing to K.gather, and adapted test_recurrent to test with dropout 2016-02-20 03:56:00 +00:00
François Chollet d03f7768b8 Merge pull request #1769 from tboquet/modelckpoint_deb
ModelCheckPoint references nonexistent attribute
2016-02-19 19:14:39 -08:00
Yarin ce79e0a8ef test random_binomial, fix rnn backend 2016-02-20 03:03:35 +00:00
Yarin 5b3809394c Dropout for LSTM, GRU, SimpleRNN, and Embedding layers.
Squashed commit of the following:

commit 39a59192e96fe4098f1d663384b79b10e3bcc979
Author: Yarin <yaringal@gmail.com>
Date:   Sat Feb 20 02:15:29 2016 +0000

    Squashed commit of the following:

    commit 88faa440d02df8ff356011258e3e89ce44a13e1d
    Author: Yarin <yaringal@gmail.com>
    Date:   Sat Feb 20 02:13:24 2016 +0000

        Clean up

    commit f55245199a11a202857efb1413ffa3b97c1dcfaf
    Author: Yarin <yaringal@gmail.com>
    Date:   Sat Feb 20 01:57:50 2016 +0000

        Ported dropout for LSTM, GRU, SimpleRNN, and Embedding layer to latest Keras (turned off by default).

        Squashed commit of the following:

        commit 574c4549da69f8c0831f02dce1ad05331d8b38ed
        Merge: 19ef51c bdb149d
        Author: Yarin <yaringal@gmail.com>
        Date:   Sat Feb 20 01:23:54 2016 +0000

            Merge branch 'BRNN_latest' of https://github.com/yaringal/keras into BRNN_latest

        commit 19ef51c633544f847cddebeb7a3add0936051f19
        Author: Yarin <yaringal@gmail.com>
        Date:   Sat Feb 20 01:12:23 2016 +0000

            implemented dropout in GRU and SimpleRNN

        commit bdb149d1bbff64cc6b4d694090b905153d28e33a
        Author: Yarin <yaringal@gmail.com>
        Date:   Sat Feb 20 01:12:23 2016 +0000

            implemented dropout in GRU and SimpleLSTM

        commit 72ade3f493dd725fb414cbc65a847259360be138
        Author: Yarin <yaringal@gmail.com>
        Date:   Sat Feb 20 00:52:01 2016 +0000

            clean up

        commit 9f3d213c91906b3be5c876d539819a8577bc438c
        Author: Yarin <yaringal@gmail.com>
        Date:   Sat Feb 20 00:42:58 2016 +0000

            Model test callback

        commit d4ffffc26cf24c8b7927209caad4379aac3db9c5
        Author: Yarin <yaringal@gmail.com>
        Date:   Fri Feb 19 23:47:40 2016 +0000

            removed dependence on theano

        commit 89a4e6576278564ffb882032d5a7ec5758fe00e4
        Author: Yarin <yg279@cam.ac.uk>
        Date:   Fri Feb 19 23:25:13 2016 +0000

            working BayesianLSTM and embedding dropout for theano backend

        commit 1ab4e19dfe9d49defd5575a5c2b0b880b5c46eb5
        Author: Yarin <yg279@cam.ac.uk>
        Date:   Fri Feb 19 16:41:48 2016 +0000

            working BayesianLSTM with dependence on theano

        commit 672c27401ee345a69592771cfc9ab017642b6af3
        Merge: 9360ea6 b8a9f84
        Author: Yarin <yaringal@gmail.com>
        Date:   Fri Feb 19 00:30:44 2016 +0000

            Merge https://github.com/fchollet/keras into BRNN_latest

        commit 9360ea6c25eab90e83aebb32eb187c65ed63c01d
        Author: Yarin <yaringal@gmail.com>
        Date:   Thu Feb 18 23:28:35 2016 +0000

            work in progress on BayesianLSTM

        commit b8a9f84fad
        Merge: a154495 0f3f563
        Author: François Chollet <francois.chollet@gmail.com>
        Date:   Thu Feb 18 11:24:42 2016 -0800

            Merge pull request #1756 from gw0/fix-for-refactor-callbacks

            Fix missing callback refactoring.

        commit 0f3f56327b
        Author: gw0 [http://gw.tnode.com/] <gw.2016@tnode.com>
        Date:   Thu Feb 18 17:01:45 2016 +0100

            Fix missing callback refactoring.
2016-02-20 02:15:59 +00:00
tboquet e501cd664e changed ref to attribute ModelCheckPoint 2016-02-19 20:14:18 -05:00
z001qdp 47aafaaca0 Fix Sequential.set_weights
`Sequential.set_weights` would fail for nested `Sequential`
containers. Borrow the implementation of `Graph.set_weights` to
get it working. Also add tests for triply-nested `Sequential`
models.
2016-02-19 14:23:04 -06:00
François Chollet b8a9f84fad Merge pull request #1756 from gw0/fix-for-refactor-callbacks
Fix missing callback refactoring.
2016-02-18 11:24:42 -08:00
gw0 [http://gw.tnode.com/] 0f3f56327b Fix missing callback refactoring. 2016-02-18 17:01:45 +01:00
François Chollet a154495a2a Merge pull request #1751 from DingKe/master
Support saving/loading sample_weight_mode(s)
2016-02-17 18:26:29 -08:00
Francois Chollet 25e5f7531a Add ISSUE_TEMPLATE.md 2016-02-17 16:56:18 -08:00
Francois Chollet ab179fab89 data_utils cleanup 2016-02-17 16:39:37 -08:00
Francois Chollet 59a714abe8 Style fixes 2016-02-17 16:39:24 -08:00
Ke Ding e432d10be5 Merge branch 'master' of https://github.com/fchollet/keras.git 2016-02-17 18:48:06 +08:00
Ke Ding eeb576b12f Add support for saving/loading sample_weight_mode(s) 2016-02-17 18:47:29 +08:00
François Chollet 1019e50e7f Merge pull request #1626 from MatthieuPerrot/master
retrieve datasets behind http/https proxy
2016-02-16 15:19:22 -08:00
Francois Chollet 1a6cb71732 Make history an attribute of models 2016-02-16 14:22:41 -08:00
Francois Chollet 9048b5cbba Merge branch 'master' of https://github.com/fchollet/keras 2016-02-16 13:23:25 -08:00
Francois Chollet c9642571c2 Refactor callbacks 2016-02-16 13:22:53 -08:00
François Chollet cda80c790b Merge pull request #1719 from barvinograd/general-pad-sequences
generalize pad_sequences
2016-02-16 11:57:34 -08:00
Bar Vinograd 46a5b3cb36 generalize pad_sequences #1718 2016-02-16 10:56:33 +02:00
Francois Chollet 5b23dd8a2f Style fixes 2016-02-15 13:30:28 -08:00
Francois Chollet 2b26389188 Merge branch 'master' of https://github.com/fchollet/keras 2016-02-15 13:29:09 -08:00
Francois Chollet 44e0a7bbf9 Style fixes 2016-02-15 13:27:06 -08:00
Francois Chollet 87cc39d99f Merge branch 'master' of https://github.com/barvinograd/keras into barvinograd-master 2016-02-15 13:18:51 -08:00
François Chollet 55aacd1905 Merge pull request #1736 from bryan-lunt/fix_load_weights
Fixed load_weights to not create empty/corrupt .h5 files
2016-02-15 12:57:41 -08:00
Francois Chollet 3df101cc77 Merge branch 'master' of https://github.com/fchollet/keras 2016-02-15 12:56:59 -08:00
Bryan Lunt c23579e059 Fixed load_weights to not create empty/corrupt .h5 files
Fixes issue #1734 non-existant .h5 files will not be created, IOError will be raised.
2016-02-15 12:13:23 -06:00
François Chollet 6a41ac1c36 Merge pull request #1724 from bmabey/master
updates docstring for Merge to include cos and join
2016-02-14 15:47:34 -08:00
Ben Mabey b78ade7e36 updates docstring for Merge to include cos and join 2016-02-14 16:40:54 -06:00
Matthieu Perrot 61800be9a0 Add http/https proxy management for dataset downloading 2016-02-13 21:14:55 +01:00
Bar Vinograd 3925eabaaf SReLU activation (#1662, #1681) 2016-02-13 12:07:57 +02:00
Francois Chollet 34296ec961 Update FAQ 2016-02-12 17:10:51 -08:00
Francois Chollet 52f48e1f46 Merge branch 'master' of https://github.com/fchollet/keras 2016-02-12 12:17:20 -08:00
Francois Chollet 20728c95fa Make it possible to configure nb of threads in TF 2016-02-12 12:17:00 -08:00
François Chollet 6181ca8aae Merge pull request #1701 from stas-sl/patch-2
more concise random_shift and fix axis order
2016-02-12 11:56:33 -08:00
François Chollet 68115cc25f Merge pull request #1705 from neggert/cache_input_size
Add caching for layer input/output sizes
2016-02-12 11:40:55 -08:00
Francois Chollet c192beaf43 Merge branch 'master' of https://github.com/fchollet/keras 2016-02-12 09:45:21 -08:00
Francois Chollet 27dd1e939c Add dim_ordering tests 2016-02-12 09:44:55 -08:00
Francois Chollet 1e46a5d3ec Improve error message 2016-02-12 09:44:31 -08:00
Francois Chollet 0bf2b1b075 Improve TF backend docstrings 2016-02-12 09:44:16 -08:00
François Chollet ab3ef3efe5 Merge pull request #1704 from brmson/f/cosmerge
Merge(cos): Fix bad import
2016-02-12 09:43:33 -08:00
Petr Baudis 4d3ee897da Merge(cos): Fix bad import 2016-02-12 16:07:19 +01:00
stas-sl 8e591d228c more concise random_shift and fix axis order 2016-02-12 13:34:45 +03:00
z001qdp 6429a57a3c Add caching for layer output sizes
This dramatically speeds up constructing large networks.
Implementation follows that of layer caching introduced in e8e8f7.
2016-02-11 16:48:17 -06:00
Francois Chollet 9ad5ed8103 Fix indentation in code examples in docs 2016-02-11 11:42:34 -08:00
Francois Chollet 209b42c5ee Fix code comments for method example in online doc 2016-02-11 11:00:12 -08:00
Francois Chollet 23147de72b Convs tests touch-ups 2016-02-10 14:35:34 -08:00
Francois Chollet 7b72163073 Theano: support for strides with border_mode=same 2016-02-10 13:57:09 -08:00
Francois Chollet 6279544dc3 0.3.2 PyPI release 2016-02-09 13:57:16 -08:00
François Chollet 657b9fb48e Merge pull request #1651 from tboquet/fit_gen_tensorb
Support + tests for fit_generator + tensorboard
2016-02-08 14:01:02 -08:00
tboquet d68e3316da Support for fit_generator + tensorboard 2016-02-08 14:55:00 -05:00
François Chollet cae797b803 Merge pull request #1668 from jstypka/master
docs: update "pad_sequences()" parameters in the docs
2016-02-08 10:14:17 -08:00
Jan Stypka 21492a292a docs: update "pad_sequences()" parameters in the docs 2016-02-08 15:20:12 +01:00
fchollet f27c5b0500 merge conflict 2016-02-07 22:56:59 -08:00
fchollet 523e24e8ac Simplify Theano RNN when no mask is passed 2016-02-07 22:34:24 -08:00
François Chollet 8d393f766b Merge pull request #1645 from oraac/master
added more detail to the building documentation instructions
2016-02-07 21:17:11 -08:00
Francois Chollet c450089de9 Documentation improvements 2016-02-07 15:42:18 -08:00
Francois Chollet 1b22915f85 Documentation improvements 2016-02-07 15:38:20 -08:00
Francois Chollet 5824f2eb99 Provide None as default value for layer names 2016-02-06 18:45:15 -08:00
David McInnis 27754d2a5f changed to make compatible with more browsers 2016-02-06 14:32:52 -08:00
Francois Chollet 99991779e5 TF fixes and style fixes 2016-02-06 13:49:57 -08:00
Mikael Rousson 652f2eb56d add siamese example
use graph model
take pairs of digits as input
2016-02-06 22:06:22 +01:00
Francois Chollet 359f91ff6c Fix py3 test 2016-02-06 11:21:44 -08:00
Francois Chollet f3fd56db50 Improve input validation in graph.compile 2016-02-06 11:03:02 -08:00
Francois Chollet 6f5f3d3fb6 Fix join mode in Merge / Siamese 2016-02-06 11:02:44 -08:00
Francois Chollet 9b10ab2980 Style fixes 2016-02-05 15:37:36 -08:00
Francois Chollet 113f20e7e5 Merge branch 'rescale-objective' of https://github.com/wxs/keras into wxs-rescale-objective 2016-02-05 15:34:57 -08:00
Francois Chollet f2443de96d Merge branch 'master' of https://github.com/fchollet/keras 2016-02-05 10:34:48 -08:00
Francois Chollet e14deedd78 Temporarily disable image preprocessing tests 2016-02-05 10:34:36 -08:00
François Chollet 7a708c305c Merge pull request #1648 from gw0/fix-fit_generator-terminate
Fix program termination when threads are used in fit_generator().
2016-02-05 10:00:32 -08:00
Xavier Snelgrove 9a4a931d32 Merge remote-tracking branch 'origin/master' into rescale-objective 2016-02-05 11:31:52 -05:00
gw0 [http://gw.tnode.com/] f854dcb83f Fix program termination when threads are used in fit_generator(). 2016-02-05 15:36:14 +01:00
David McInnis b74e4a9f2d added more detail to the building documentation instructions 2016-02-04 15:15:55 -08:00
Francois Chollet 217cdd8b85 Fix objective tests 2016-02-04 14:41:29 -08:00
Xavier Snelgrove 7e678b8315 Objective outputs should rescale based on sample_weights
If sample_weights is to be used as a mask as well as for re-weighting
then it's important that, at least when used as a mask, the output be
rescaled. Otherwise the order of magnitude of your objective changes
purely based on the number of masked entries in your training data.
2016-02-04 15:57:57 -05:00
Francois Chollet 65b5899d06 Remove RMSE objective (use MSE instead). 2016-02-04 10:59:01 -08:00
Francois Chollet 02d5f72be4 Simplify Theano tensor instantiation 2016-02-03 18:40:13 -08:00
Francois Chollet cd2e36392c Rename "params" to "trainable_weights" 2016-02-03 17:52:05 -08:00
Matthias Plappert ff4a9b7b24 fix BN serialization 2016-02-03 17:27:14 -08:00
François Chollet 8acf4de764 Merge pull request #1621 from DingKe/master
fix issue #1363
2016-02-02 20:44:05 -08:00
Ke Ding 7b789c7fa0 fix issue when loading stateful RNNs if they are not the first layer 2016-02-03 10:07:30 +08:00
Francois Chollet ef22fcf548 Fix TF dim check 2016-02-02 11:58:48 -08:00
Francois Chollet de8a0133f0 Improve "repeat" in backends 2016-02-02 11:26:03 -08:00
Xavier Snelgrove 095b6c118c Fix merge conflicts 2016-02-01 14:16:54 -08:00
Francois Chollet 827ec65111 Fix stateful RNN serialization 2016-02-01 13:48:40 -08:00
Xavier Snelgrove c94cf4b32a Auto-expand mask dims. Fix categorical_crossentropy.
- Categorical_crossentropy was taking an extra mean, the function
      already removes the final dimension of your input, so you don't need
      to take a mean as you would with, say, L2 loss.

     - The RNN backend call can now take a mask with or without the same
      number of dimensions as the input data

     - Fix Masking layer for Tensorflow

     - Add some tests to confirm objective function shapes
2016-02-01 14:47:10 -05:00
Francois Chollet b688192cbd 15% more efficient RNNs with TensorFlow 2016-01-31 15:30:20 -08:00
Francois Chollet 64374c98fb Merge branch 'master' of https://github.com/fchollet/keras 2016-01-31 14:10:31 -08:00
Francois Chollet 361c52c527 Merge branch 'udibr-imageDataGen_thread' 2016-01-31 14:10:16 -08:00
Francois Chollet 04d7504537 Style fixes 2016-01-31 14:09:52 -08:00
fchollet a07efd4b5c Update examples in doc 2016-01-31 10:19:39 -08:00
fchollet 0ca4a0fbae Add binary classification example in doc 2016-01-31 10:13:14 -08:00
Ehud Ben-Reuven 6e33b516ef ImageDataGenerator thread safe 2016-01-30 23:43:56 -05:00
fchollet 3d85402ca5 Fix various typos 2016-01-30 18:19:37 -08:00
fchollet 9720db9566 Fix typo 2016-01-30 18:13:25 -08:00
fchollet c5d11f1da3 Fix AutoEncoder; cleaner API. 2016-01-30 18:10:33 -08:00
François Chollet 5d3c267398 Merge pull request #1596 from agitter/master
Minor typos in example commands
2016-01-29 14:23:54 -08:00
Anthony Gitter eb8e8b281e Minor typos in example commands 2016-01-29 15:31:53 -06:00
Francois Chollet 001f29cf54 Merge branch 'master' of https://github.com/fchollet/keras 2016-01-29 10:47:08 -08:00
Francois Chollet bb2b3ada3d Improve docs of conv_filter_vis example 2016-01-29 10:03:07 -08:00
fchollet 92b1948d51 Fix typo 2016-01-28 22:05:25 -08:00
Francois Chollet 14b109072a Merge branch 'master' of https://github.com/fchollet/keras 2016-01-28 19:22:37 -08:00
Francois Chollet 027a018210 Add convolution filter visualization example 2016-01-28 19:22:24 -08:00
Francois Chollet 4341c623ff Test cleanup 2016-01-28 19:21:45 -08:00
François Chollet 7a3122c154 Merge pull request #1583 from awentzonline/fix-random-tests
Fixed backend tests for `random_uniform` and `random_normal`
2016-01-28 15:16:43 -08:00
François Chollet 282e634f3a Merge pull request #1582 from fchollet/temporal_sample_weighting
Temporal sample weighting
2016-01-28 14:18:53 -08:00
Adam Wentz 3882f32f09 Fixed backend tests for random_uniform and random_normal 2016-01-28 15:59:24 -06:00
Francois Chollet efe4fc72e5 Fix loss weighting tests 2016-01-28 13:50:19 -08:00
Francois Chollet 1623ea6166 Support for temporal sample weighting + tests 2016-01-28 11:20:04 -08:00
François Chollet b2681804f8 Merge pull request #1577 from jocicmarko/master
Speed up random shifts in data augmentation
2016-01-28 10:39:38 -08:00
Marko Jocić 9bc8ab169a Speed up random shifts in data augmentation
Currently, polynomial interpolation of 3rd order is done when shifting. However, that is not needed because the images are shifted by integer values (crop_left_pixels, crop_top_pixels), and there is nothing to interpolate.
Setting ```order=0``` will speed up random shifts significantly.
2016-01-28 14:18:05 +01:00
François Chollet 59dcd7ba7a Merge pull request #1566 from tpsatish95/master
added random_shear() to random_transform
2016-01-27 23:07:25 -08:00
tpsatish95 5cf50f6a6c added the random_shear transformation for images. 2016-01-28 11:35:50 +05:30
Francois Chollet ecdce975d3 Fix inaccuracy in FAQ 2016-01-27 19:15:40 -08:00
Francois Chollet aceded7bfb Merge branch 'master' of https://github.com/fchollet/keras 2016-01-27 19:10:45 -08:00
Francois Chollet 45955be120 Update FAQ 2016-01-27 19:10:23 -08:00
François Chollet 829886eb16 Merge pull request #1552 from udibr/ImageDataGenerator_shuffle
In ImageDataGenerator.flow shuffle before every epoch
2016-01-27 18:50:57 -08:00
Francois Chollet 4922a67f09 Add support for temporal sample weights 2016-01-27 18:41:35 -08:00
François Chollet 41d07f5ba9 Merge pull request #1560 from jnphilipp/master
Fixed ImageDataGenerator.flow
2016-01-27 10:56:00 -08:00
jnphilipp 05fe5f564a Fixed image save. 2016-01-26 21:18:04 +01:00
Ehud Ben-Reuven 403b4fc7a2 In ImageDataGenerator.flow shuffle before every epoch 2016-01-26 15:06:06 -05:00
Francois Chollet c61d075abc Fix ImageDataGenerator docs 2016-01-26 09:36:35 -08:00
fchollet 2e90ae18a6 Update Theano install instructions 2016-01-24 16:53:29 -08:00
fchollet ed1297b393 Update Theano install instructions 2016-01-24 16:09:51 -08:00
François Chollet a53577205f Merge pull request #1543 from Joshua-Chin/master
Fix documentation of output shape for Convolution2D
2016-01-24 12:49:38 -08:00
Joshua Chin 26ab219159 fix documentation for Convolution2D 2016-01-24 13:24:16 -05:00
Francois Chollet 399c00c7f8 Update sample_weight documentation 2016-01-22 22:06:49 -08:00
Francois Chollet 36892dba8f Introduce relu exception for old Theano versions 2016-01-22 15:17:03 -08:00
Francois Chollet 1e58b89523 Fix BN tests 2016-01-21 12:17:25 -08:00
Francois Chollet 4f530ab5f8 Merge branch 'master' of https://github.com/fchollet/keras 2016-01-21 11:54:58 -08:00
Francois Chollet 8823fa520b Add axis to BN config 2016-01-21 11:54:46 -08:00
François Chollet 1dab54c1c3 Merge pull request #1527 from the-moliver/master
add axis arguments to constraints
2016-01-21 11:23:16 -08:00
Michael Oliver e2e281e14f add axis arguments to constraints 2016-01-21 10:53:46 -08:00
François Chollet 3f599b9204 Merge pull request #1525 from wxs/fix-masking-3d+
Support >3d mask matrices.
2016-01-21 10:39:21 -08:00
Xavier Snelgrove ea7f400d57 Support >3d mask matrices.
The change to the dimshuffle/transpose call to support >3d inputs was
correct for the inputs array but did not apply to the mask array. This
fixes that.
2016-01-21 12:52:36 -05:00
François Chollet d7f870a47f Merge pull request #1507 from wb14123/char-tokenizer
make Tokenizer supports char level
2016-01-20 20:39:05 -08:00
François Chollet 1f0adb7ed7 Merge pull request #1514 from DingKe/master
Check gpu status correctly when using theano's cuda.use to choose gpu
2016-01-20 18:45:13 -08:00
DingKe 5657a38515 Check gpu correctly when using theano.sandbox.cuda.use to set gpu 2016-01-21 10:19:50 +08:00
Francois Chollet 2143046261 Improve error message in recurrent.py 2016-01-20 17:59:26 -08:00
Francois Chollet 571f1d4fcf Fix py3 compatibility 2016-01-20 15:28:09 -08:00
Francois Chollet f834c59290 Merge branch 'master' of https://github.com/fchollet/keras 2016-01-20 15:04:17 -08:00
Francois Chollet 0300ae2f4c Style fixes 2016-01-20 15:04:12 -08:00
François Chollet a67fb21e56 Merge pull request #1512 from farizrahman4u/patch-26
RNN : Support for nD data
2016-01-20 12:39:30 -08:00
Francois Chollet d9c4c02601 Fix image preprocessing tests 2016-01-20 12:25:36 -08:00
François Chollet 3ed897332f Merge pull request #1501 from farizrahman4u/patch-25
Remove output_dim argument from RNN API
2016-01-20 10:25:14 -08:00
François Chollet 52cb803deb Merge pull request #1511 from farizrahman4u/patch-24
White space fix
2016-01-20 10:18:09 -08:00
Fariz Rahman ace7b7fe7f RNN : Support for nD data
Currently,  only 3D input is supported by the rnn function.

Update theano_backend.py

Fix tf too

Avoid slicing

assert ndim>=3

Update theano_backend.py

typo

Update theano_backend.py
2016-01-20 23:29:57 +05:30
Fariz Rahman d08b0efc80 White space fix 2016-01-20 22:03:00 +05:30
Bin Wang 371dcc9071 add doc 2016-01-20 17:19:04 +08:00
Bin Wang 05dcfe15fe make Tokenizer supports char level 2016-01-20 16:56:57 +08:00
Fariz Rahman 73f1ef2e95 Update activations.py
Update tensorflow_backend.py

Update theano_backend.py

Update core.py

Update recurrent.py

Update test_backends.py
2016-01-20 12:41:41 +05:30
François Chollet 5bcac37553 Merge pull request #1503 from the-moliver/gaussnoisefix
Add sqrt for proper noise sigma calculation
2016-01-19 16:38:02 -08:00
Michael Oliver 34c54cb19c Add sqrt for proper noise sigma calculation 2016-01-19 15:43:36 -08:00
François Chollet fb99e04f86 Merge pull request #1502 from tboquet/from_config_deb
Added the name of the model when loading it from config
2016-01-19 14:36:15 -08:00
Francois Chollet 262c8ce1a0 Merge branch 'cassianokc-master' 2016-01-19 14:19:45 -08:00
Francois Chollet 2091bfe911 Fix stateful LSTM example 2016-01-19 14:18:11 -08:00
Francois Chollet 5e9aafca33 Merge branch 'master' of https://github.com/cassianokc/keras into cassianokc-master 2016-01-19 13:57:26 -08:00
tboquet e31d26b33f + name of th loaded models 2016-01-19 16:44:42 -05:00
Francois Chollet 45714e343f Improve real time data augmentation, cifar10 ex 2016-01-19 13:43:41 -08:00
Fariz Rahman c8f2633109 Merge pull request #6 from fchollet/master
update
2016-01-19 13:49:38 -05:00
Francois Chollet 852fe9cc7b Fix time distributed softmax 2016-01-19 09:34:41 -08:00
Francois Chollet d1af488d10 Minor style fixes 2016-01-17 17:10:04 -08:00
Francois Chollet c59b0e936d Merge branch 'wxs-backend-masking' 2016-01-17 16:48:53 -08:00
Francois Chollet c98633cd7c Fix normalization tests 2016-01-17 16:48:20 -08:00
Xavier Snelgrove ac773ed243 Fix masking in RNNs 2016-01-17 16:29:07 -08:00
Francois Chollet 9d120bf9e0 Fix py3 compatibility 2016-01-17 16:09:00 -08:00
Cassiano Kleinert Casagrande e443527d28 Add example of stateful LSTM sequence prediction 2016-01-17 21:56:21 -02:00
Francois Chollet 8c103559a6 Update tests 2016-01-17 15:41:15 -08:00
Francois Chollet 85a1225cb3 Fix batchnorm 2016-01-17 15:41:08 -08:00
Francois Chollet 160196137f Add support for axis lists in element wise ops 2016-01-17 15:40:46 -08:00
Francois Chollet 040e1ef628 Merge branch 'master' of https://github.com/fchollet/keras 2016-01-17 12:13:27 -08:00
Francois Chollet 0debec1c11 Fix batch normalization 2016-01-17 12:13:15 -08:00
Francois Chollet 0abed354b5 Add/subtract mean in style transfer script 2016-01-17 12:12:24 -08:00
fchollet d00140862e Fix conv2d mode in doc examples 2016-01-15 19:35:57 -08:00
Francois Chollet 5c3839a950 Merge branch 'consciousnesss-add_pep8' 2016-01-15 16:32:41 -08:00
Francois Chollet 2006ec2873 Newline. 2016-01-15 16:32:23 -08:00
Francois Chollet 036d5c8dc2 Merge branch 'add_pep8' of https://github.com/consciousnesss/keras into consciousnesss-add_pep8 2016-01-15 16:30:32 -08:00
Francois Chollet 3bfe4eace9 Normalize layer importing 2016-01-15 16:19:00 -08:00
Francois Chollet 83aaadaa9d Log backend type to stderr 2016-01-15 16:18:42 -08:00
Francois Chollet a18932cb65 Improve neural style example 2016-01-15 16:17:18 -08:00
Francois Chollet 70f0fe515a Improve deep dream example 2016-01-15 16:17:05 -08:00
olegsinyavskiy a563a8446e Add an automatic PEP8 check on the pull request submission:\n - ignore most of the errors to avoid disrupting others\n - add a separate job to avoid confusion that all jobs fail because of a single pep error\n - fix few small pep errors 2016-01-14 08:32:37 -08:00
Oleg Sinyavskiy bd2ff26b37 Merge pull request #5 from fchollet/master
update
2016-01-13 17:34:42 -08:00
Francois Chollet 58a94a9b05 Add deep dream example 2016-01-13 10:46:45 -08:00
Francois Chollet 3d3b8c52e9 Cleanup of neural style transfer example 2016-01-13 10:46:19 -08:00
François Chollet 558605a363 Merge pull request #1422 from jakebian/json-fix
models: when dumping config to json, parse unhandled types correctly
2016-01-12 13:46:11 -08:00
François Chollet a696513cfb Merge pull request #1448 from keunwoochoi/patch-1
Remove cv2 dependency and use scipy.misc
2016-01-11 16:09:11 -08:00
Keunwoo Choi ee6bad63b0 Remove cv2 dependency and use scipy.misc
to read, resize, and save images.
2016-01-11 23:33:25 +00:00
Francois Chollet cb13a33a31 Fix neural style comments 2016-01-11 11:43:10 -08:00
Francois Chollet 1fdcc370b6 Remove unnecessary commented code. 2016-01-11 11:30:10 -08:00
Francois Chollet 94c9183179 Merge branch 'master' of https://github.com/fchollet/keras 2016-01-11 11:23:44 -08:00
Francois Chollet ada6dd2943 Add neural style transfer example 2016-01-11 11:23:38 -08:00
Francois Chollet a5c07d796a Update theano backend 2016-01-11 11:22:29 -08:00
François Chollet d2f7593a35 Merge pull request #1442 from jfsantos/patch-8
FIxed Tensorboard callback for Python 3
2016-01-10 21:20:42 -08:00
João Felipe Santos 314ee54e60 FIxed Tensorboard callback for Python 3
Adding `dict_items` [does not work](https://stackoverflow.com/questions/13361510/typeerror-unsupported-operand-types-for-dict-items-and-dict-items) in Python 3. Workaround is to create a copy of the dict and `update` it with the other dict.
2016-01-10 13:12:00 -05:00
François Chollet 5d1789c805 Merge pull request #1430 from tboquet/fix_custom_obj_load
Added compatibility for custom loss functions
2016-01-08 12:16:12 -08:00
tboquet 42cd4d6b62 Added support for both Sequential and Graph 2016-01-08 14:16:27 -05:00
tboquet 6bb4cbbf5e added compatibility for custom loss functions 2016-01-08 13:19:25 -05:00
Francois Chollet 998efc04ee Merge branch 'master' of https://github.com/fchollet/keras 2016-01-08 10:02:45 -08:00
Francois Chollet 037e592f2b Naming, batch_flatten 2016-01-08 10:02:28 -08:00
fchollet ced84d53bc Fix example docstring 2016-01-07 22:24:40 -08:00
fchollet d0b98a2cb5 Antirectifier example style fixes 2016-01-07 21:18:34 -08:00
fchollet 09d91fccb9 Add antirectifier example 2016-01-07 20:22:33 -08:00
jake e947a56c52 models: when dumping config to json, parse unhandled types correctly
- properly convert numpy types
- handle python 'type' objects
2016-01-07 18:02:02 -08:00
François Chollet 887178bd02 Merge pull request #1417 from farizrahman4u/patch-21
Lambda layer:get_output should use get_input.
2016-01-07 17:24:13 -08:00
Fariz Rahman e21a6a9ebf Fix output_shape too. 2016-01-08 01:13:00 +05:30
François Chollet f31f85a720 Merge pull request #1419 from ozancaglayan/fix-mask-cast
models: Cast the mask to floatX to avoid theano upcasting
2016-01-07 11:14:22 -08:00
Fariz Rahman bf2f64bfd5 Update core.py 2016-01-08 00:27:43 +05:30
Ozan Caglayan f800e448a2 models: Cast the mask to floatX to avoid theano upcasting
Issue #1416
2016-01-07 20:19:24 +02:00
Fariz Rahman fe18ad8dde Lambda layer:get_output should use get_input. 2016-01-07 17:06:43 +05:30
François Chollet 6167d17aeb Merge pull request #1414 from tboquet/conv_same_conv2d
Evaluate the kernel of base Theano conv2d with the same border mode
2016-01-06 19:28:26 -08:00
tboquet f8dd6da08d Eval kernel base Theano conv2d same border mode 2016-01-06 21:59:50 -05:00
François Chollet c6a1c01a08 Merge pull request #1411 from jarfo/patch-1
Update models.py
2016-01-06 10:55:15 -08:00
jarfo d02ea03462 Update models.py
Model evaluation (test) using the _test K.function should be also stateful for stateful recurrent networks
2016-01-06 13:27:28 +01:00
Francois Chollet 13379da81b Fix kernel shape type in theano conv2d 2016-01-05 15:44:15 -08:00
Francois Chollet 87f62dc6cf Merge branch 'master' of https://github.com/fchollet/keras 2016-01-05 10:36:15 -08:00
Francois Chollet 6cb1172668 Add cosine proximity objective 2016-01-05 10:35:29 -08:00
Francois Chollet 458641f33a Add K.l2_normalization 2016-01-05 10:35:10 -08:00
François Chollet e2fa1d56c0 Merge pull request #1396 from julienr/resize_images
Add K.resize_images backend op.
2016-01-03 14:51:44 -08:00
Julien Rebetez 01395f13ed Figure out tensor shape automatically in K.resize_images 2016-01-03 22:36:28 +01:00
Francois Chollet 6445d385ee Update CONTRIBUTING.md 2016-01-03 13:17:36 -08:00
Julien Rebetez 4330fd78e9 Fix theano_backend.resize_images 2016-01-03 19:04:49 +01:00
Francois Chollet f447644900 Update PyPi release to 0.3.1 2016-01-03 09:41:04 -08:00
Julien Rebetez 9d15c96115 Add K.resize_images backend op.
This allows to take advantage of tensorflow’s resize_images operator in UpSampling2D.
2016-01-03 12:37:14 +01:00
farizrahman4u 611c4851e3 Merge pull request #1 from fchollet/master
Update fork
2015-10-25 15:36:42 +05:30
124 arquivos alterados com 15633 adições e 7994 exclusões
+9 -4
Ver Arquivo
@@ -12,7 +12,9 @@ matrix:
- python: 2.7
env: KERAS_BACKEND=tensorflow
- python: 2.7
env: KERAS_BACKEND=theano INTEGRATION_TESTS=true
env: KERAS_BACKEND=theano TEST_MODE=INTEGRATION_TESTS
- python: 2.7
env: KERAS_BACKEND=theano TEST_MODE=PEP8
install:
# code below is taken from http://conda.pydata.org/docs/travis.html
# We do this conditionally because it saves us some downloading if the
@@ -33,6 +35,7 @@ install:
- 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 pytest-xdist coverage==3.7.1 #we need this version of coverage for coveralls.io to work
- pip install pep8 pytest-pep8
- pip install git+git://github.com/Theano/Theano.git
# install PIL for preprocessing tests
@@ -46,9 +49,9 @@ install:
# install TensorFlow
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.6.0-cp27-none-linux_x86_64.whl;
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.7.1-cp27-none-linux_x86_64.whl;
elif [[ "$TRAVIS_PYTHON_VERSION" == "3.4" ]]; then
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.6.0-cp34-none-linux_x86_64.whl;
pip install https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.7.1-cp34-none-linux_x86_64.whl;
fi
# command to run tests
script:
@@ -57,8 +60,10 @@ script:
# set up keras backend
- sed -i -e 's/"backend":[[:space:]]*"[^"]*/"backend":\ "'$KERAS_BACKEND'/g' ~/.keras/keras.json;
- echo -e "Running tests with the following config:\n$(cat ~/.keras/keras.json)"
- if [[ "$INTEGRATION_TESTS" == "true" ]]; then
- if [[ "$TEST_MODE" == "INTEGRATION_TESTS" ]]; then
PYTHONPATH=$PWD:$PYTHONPATH py.test tests/integration_tests;
elif [[ "$TEST_MODE" == "PEP8" ]]; then
PYTHONPATH=$PWD:$PYTHONPATH py.test --pep8 -m pep8 -n0;
else
PYTHONPATH=$PWD:$PYTHONPATH py.test tests/ --ignore=tests/integration_tests;
fi
+11 -6
Ver Arquivo
@@ -36,25 +36,30 @@ We love pull requests. Here's a quick guide:
1. If your PR introduces a change in functionality, make sure you start by opening an issue to discuss whether the change should be made, and how to handle it. This will save you from having your PR closed down the road! Of course, if your PR is a simple bug fix, you don't need to do that.
2. Write the code. This is the hard part! We use PEP8 syntax conventions, but we aren't dogmatic when it comes to line length. Make sure your lines stay reasonably sized, though. To make your life easier, we recommend installing a PEP8 linter.
2. Write the code. This is the hard part!
3. Make sure any new function or class you introduce has proper docstrings. Make sure any code you touch still has up-to-date docstrings and documentation.
4. Write tests. Your code should have full unit test coverage. If you want to see your PR merged promptly, this is crucial.
5. Run our test suite locally. It's easy: from the Keras folder, simply run: `py.test tests/`.
- You will need to install `pytest`, `coveralls`, `pytest-cov`, `pytest-xdist`: `pip install pytest pytest-cov python-coveralls pytest-xdist`
- You will need to install `pytest`, `coveralls`, `pytest-cov`, `pytest-xdist`: `pip install pytest pytest-cov python-coveralls pytest-xdist pep8 pytest-pep8`
6. Make sure all tests are passing:
- with the Theano backend, on Python 2.7 and Python 3.5
- with the TensorFlow backend, on Python 2.7
7. When committing, use appropriate, descriptive commit messages. Make sure that your branch history is not a string of "bug fix", "fix", "oops", etc. When submitting your PR, squash your commits into a single commit with an appropriate commit message, to make sure the project history stays clean and readable. See ['rebase and squash'](http://rebaseandsqua.sh/) for technical help on how to squash your commits.
7. We use PEP8 syntax conventions, but we aren't dogmatic when it comes to line length. Make sure your lines stay reasonably sized, though. To make your life easier, we recommend running a PEP8 linter:
- Install PEP8 packages: `pip install pep8 pytest-pep8 autopep8`
- Run a standalone PEP8 check: `py.test --pep8 -m pep8`
- You can automatically fix some PEP8 error by running: `autopep8 -i --select <errors> <FILENAME>` for example: `autopep8 -i --select E128 tests/keras/backend/test_backends.py`
8. Update the documentation. If introducing new functionality, make sure you include code snippets demonstrating the usage of your new feature.
8. When committing, use appropriate, descriptive commit messages. Make sure that your branch history is not a string of "bug fix", "fix", "oops", etc. When submitting your PR, squash your commits into a single commit with an appropriate commit message, to make sure the project history stays clean and readable. See ['rebase and squash'](http://rebaseandsqua.sh/) for technical help on how to squash your commits.
9. Submit your PR. If your changes have been approved in a previous discussion, and if you have have complete (and passing) unit tests, your PR is likely to be merged promptly. Otherwise, well...
9. Update the documentation. If introducing new functionality, make sure you include code snippets demonstrating the usage of your new feature.
10. Submit your PR. If your changes have been approved in a previous discussion, and if you have complete (and passing) unit tests, your PR is likely to be merged promptly. Otherwise, well...
## Adding new examples
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. Existing examples show idiomatic Keras code: make sure to keep your own script in the same spirit.
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. [Existing examples](https://github.com/fchollet/keras/tree/master/examples) show idiomatic Keras code: make sure to keep your own script in the same spirit.
+9
Ver Arquivo
@@ -0,0 +1,9 @@
Please make sure that the boxes below are checked before you submit your issue. Thank you!
- [ ] Check that you are up-to-date with the master branch of Keras. You can update with:
pip install git+git://github.com/fchollet/keras.git --upgrade --no-deps
- [ ] If running on Theano, check that you are up-to-date with the master branch of Theano. You can update with:
pip install git+git://github.com/Theano/Theano.git --upgrade --no-deps
- [ ] Provide a link to a GitHub Gist of a Python script that can reproduce your issue (or just copy the script here if it is short).
+14 -15
Ver Arquivo
@@ -1,6 +1,7 @@
# Keras: Deep Learning library for Theano and TensorFlow
![Build status](https://api.travis-ci.org/fchollet/keras.svg)
[![Build Status](https://travis-ci.org/fchollet/keras.svg?branch=master)](https://travis-ci.org/fchollet/keras)
[![PyPI version](https://badge.fury.io/py/keras.svg)](https://badge.fury.io/py/keras)
## You have just found Keras.
@@ -37,9 +38,9 @@ Keras is compatible with: __Python 2.7-3.5__.
## Getting started: 30 seconds to Keras
The core data structure of Keras is a __model__, a way to organize layers. There are two types of models: [`Sequential`](http://keras.io/models/#sequential) and [`Graph`](http://keras.io/models/#graph).
The core data structure of Keras is a __model__, a way to organize layers. The main type of model is the [`Sequential`](http://keras.io/getting-started/sequential-model-guide) model, a linear stack of layers. For more complex architectures, you should use the [Keras function API](http://keras.io/getting-started/functional-api-guide).
Here's the `Sequential` model (a linear pile of layers):
Here's the `Sequential` model:
```python
from keras.models import Sequential
@@ -52,15 +53,15 @@ 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(Dense(output_dim=64, input_dim=100))
model.add(Activation("relu"))
model.add(Dense(output_dim=10, init="glorot_uniform"))
model.add(Dense(output_dim=10))
model.add(Activation("softmax"))
```
Once your model looks good, configure its learning process with `.compile()`:
```python
model.compile(loss='categorical_crossentropy', optimizer='sgd')
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
```
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).
@@ -81,7 +82,7 @@ model.train_on_batch(X_batch, Y_batch)
Evaluate your performance in one line:
```python
objective_score = model.evaluate(X_test, Y_test, batch_size=32)
loss_and_metrics = model.evaluate(X_test, Y_test, batch_size=32)
```
Or generate predictions on new data:
@@ -90,11 +91,14 @@ classes = model.predict_classes(X_test, batch_size=32)
proba = model.predict_proba(X_test, batch_size=32)
```
Building a network of LSTMs, a deep CNN, a 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?
Building a question answering system, an image classification model, 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 these [starter examples](http://keras.io/examples/).
For a more in-depth tutorial about Keras, you can check out:
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repo, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, neural turing machines, etc.
- [Getting started with the Sequential model](http://keras.io/getting-started/sequential-model-guide)
- [Getting started with the functional API](http://keras.io/getting-started/functional-api-guide)
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repository, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, etc.
------------------
@@ -114,11 +118,6 @@ Keras uses the following dependencies:
- 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
+2 -1
Ver Arquivo
@@ -8,4 +8,5 @@ Our documentation uses extended Markdown, as implemented by [MkDocs](http://mkdo
- install MkDocs: `pip install mkdocs`
- `cd` to the `docs/` folder and run:
- `python autogen.py`
- `mkdocs serve`
- `mkdocs serve` # Starts a local webserver: [localhost:8000](localhost:8000)
- `mkdocs build` # Builds a static site in "site" directory
+372 -112
Ver Arquivo
@@ -1,4 +1,57 @@
# -*- coding: utf-8 -*-
'''
General documentation architecture:
Home
Index
- Getting started
Getting started with the sequential model
Getting started with the functional api
Examples
FAQ
Installation guide
- Models
About Keras models
explain when one should use Sequential or functional API
explain compilation step
explain weight saving, weight loading
explain serialization, deserialization
Sequential
Model (functional API)
- Layers
About Keras layers
explain common layer functions: get_weights, set_weights, get_config
explain input_shape
explain usage on non-Keras tensors
Core layers
Convolutional
Recurrent
Embeddings
Normalization
Advanced activations
Noise
- Preprocessing
Image preprocessing
Text preprocessing
Sequence preprocessing
Objectives
Optimizers
Activations
Callbacks
Datasets
Backend
Initializations
Regularizers
Constraints
Visualization
Scikit-learn API
'''
from __future__ import print_function
import re
import inspect
@@ -11,35 +64,147 @@ from keras.layers import core
from keras.layers import noise
from keras.layers import normalization
from keras.layers import advanced_activations
from keras.layers import containers
from keras.layers import embeddings
from keras.layers import wrappers
from keras import optimizers
from keras import callbacks
from keras import models
from keras.engine import topology
from keras import objectives
from keras import backend
from keras import constraints
from keras import activations
from keras import regularizers
MODULES = [(convolutional, 'keras.layers.convolutional'),
(recurrent, 'keras.layers.recurrent'),
(noise, 'keras.layers.noise'),
(normalization, 'keras.layers.normalization'),
(advanced_activations, 'keras.layers.advanced_activations'),
(containers, 'keras.layers.containers'),
(core, 'keras.layers.core'),
(embeddings, 'keras.layers.embeddings'),
(optimizers, 'keras.optimizers'),
(callbacks, 'keras.callbacks'),
(models, 'keras.models')]
EXCLUDE = {
'Optimizer',
'Wrapper',
'get_session',
'set_session',
}
SKIP = ['build', 'get_params', 'MaskedLayer',
'SiameseHead', 'MaskedLambda',
'CallbackList']
ROOT = 'http://keras.io/'
INCLUDE_METHODS_FOR = [
'Layer',
'Graph',
'Sequential',
'Callback',
PAGES = [
{
'page': 'models/sequential.md',
'functions': [
models.Sequential.compile,
models.Sequential.fit,
models.Sequential.evaluate,
models.Sequential.predict,
models.Sequential.predict_classes,
models.Sequential.predict_proba,
models.Sequential.train_on_batch,
models.Sequential.test_on_batch,
models.Sequential.predict_on_batch,
models.Sequential.fit_generator,
models.Sequential.evaluate_generator,
],
},
{
'page': 'models/model.md',
'functions': [
models.Model.compile,
models.Model.fit,
models.Model.evaluate,
models.Model.predict,
models.Model.train_on_batch,
models.Model.test_on_batch,
models.Model.predict_on_batch,
models.Model.fit_generator,
models.Model.evaluate_generator,
models.Model.get_layer,
]
},
{
'page': 'layers/core.md',
'classes': [
core.Dense,
core.Activation,
core.Dropout,
core.Flatten,
core.Reshape,
core.Permute,
core.RepeatVector,
topology.Merge,
core.Lambda,
core.ActivityRegularization,
core.Masking,
core.Highway,
core.MaxoutDense,
core.TimeDistributedDense,
],
},
{
'page': 'layers/convolutional.md',
'classes': [
convolutional.Convolution1D,
convolutional.Convolution2D,
convolutional.Convolution3D,
convolutional.MaxPooling1D,
convolutional.MaxPooling2D,
convolutional.MaxPooling3D,
convolutional.AveragePooling1D,
convolutional.AveragePooling2D,
convolutional.AveragePooling3D,
convolutional.UpSampling1D,
convolutional.UpSampling2D,
convolutional.UpSampling3D,
convolutional.ZeroPadding1D,
convolutional.ZeroPadding2D,
convolutional.ZeroPadding3D,
],
},
{
'page': 'layers/recurrent.md',
'classes': [
recurrent.Recurrent,
recurrent.SimpleRNN,
recurrent.GRU,
recurrent.LSTM,
],
},
{
'page': 'layers/embeddings.md',
'classes': [
embeddings.Embedding,
],
},
{
'page': 'layers/normalization.md',
'classes': [
normalization.BatchNormalization,
],
},
{
'page': 'layers/advanced-activations.md',
'all_module_classes': [advanced_activations],
},
{
'page': 'layers/noise.md',
'all_module_classes': [noise],
},
{
'page': 'layers/wrappers.md',
'all_module_classes': [wrappers],
},
{
'page': 'optimizers.md',
'all_module_classes': [optimizers],
},
{
'page': 'callbacks.md',
'all_module_classes': [callbacks],
},
{
'page': 'backend.md',
'all_module_functions': [backend],
},
]
ROOT = 'http://keras.io/'
def get_earliest_class_that_defined_member(member, cls):
ancestors = get_classes_ancestors([cls])
@@ -67,20 +232,23 @@ def get_classes_ancestors(classes):
return filtered_ancestors
def get_method_signature(method):
signature = inspect.getargspec(method)
def get_function_signature(function, method=True):
signature = inspect.getargspec(function)
defaults = signature.defaults
args = signature.args[1:]
if method:
args = signature.args[1:]
else:
args = signature.args
if defaults:
kwargs = zip(args[-len(defaults):], defaults)
args = args[:-len(defaults)]
else:
kwargs = []
st = '%s.%s(' % (method.__module__, method.__name__)
st = '%s.%s(' % (function.__module__, function.__name__)
for a in args:
st += str(a) + ', '
for a, v in kwargs:
if type(v) == str:
if type(v) == str:
v = '\'' + v + '\''
elif type(v) == unicode:
v = 'u\'' + v + '\''
@@ -91,6 +259,17 @@ def get_method_signature(method):
return st + ')'
def get_class_signature(cls):
try:
class_signature = get_function_signature(cls.__init__)
class_signature = class_signature.replace('__init__', cls.__name__)
except:
# in case the class inherits from object and does not
# define __init__
class_signature = cls.__module__ + '.' + cls.__name__ + '()'
return class_signature
def class_to_docs_link(cls):
module_name = cls.__module__
assert module_name[:6] == 'keras.'
@@ -117,26 +296,33 @@ def code_snippet(snippet):
def process_class_docstring(docstring):
docstring = re.sub(r' # (.*)\n',
r' __\1__\n\n',
docstring = re.sub(r'\n # (.*)\n',
r'\n __\1__\n\n',
docstring)
docstring = re.sub(r' ([^\s\\]+):(.*)\n',
r' - __\1__:\2\n',
docstring)
docstring = docstring.replace(' ' * 5, '\t\t')
docstring = docstring.replace(' ' * 3, '\t')
docstring = docstring.replace(' ', '')
return docstring
def process_method_docstring(docstring):
docstring = re.sub(r' # (.*)\n',
r' __\1__\n\n',
def process_function_docstring(docstring):
docstring = re.sub(r'\n # (.*)\n',
r'\n __\1__\n\n',
docstring)
docstring = re.sub(r'\n # (.*)\n',
r'\n __\1__\n\n',
docstring)
docstring = re.sub(r' ([^\s\\]+):(.*)\n',
r' - __\1__:\2\n',
docstring)
docstring = docstring.replace(' ' * 6, '\t\t')
docstring = docstring.replace(' ' * 4, '\t')
docstring = docstring.replace(' ', '')
return docstring
@@ -156,101 +342,175 @@ for subdir, dirs, fnames in os.walk('templates'):
shutil.copy(fpath, new_fpath)
print('Starting autogeneration.')
covered_so_far = set()
for module, module_name in MODULES:
class_pages = []
for name in dir(module):
if name in SKIP:
continue
if name[0] == '_':
continue
module_member = getattr(module, name)
if module_member in covered_so_far:
continue
if inspect.isclass(module_member):
cls = module_member
if cls.__module__ == module_name:
for page_data in PAGES:
blocks = []
classes = page_data.get('classes', [])
for module in page_data.get('all_module_classes', []):
module_classes = []
for name in dir(module):
if name[0] == '_' or name in EXCLUDE:
continue
module_member = getattr(module, name)
if inspect.isclass(module_member):
cls = module_member
if cls.__module__ == module.__name__:
if cls not in module_classes:
module_classes.append(cls)
module_classes.sort(key=lambda x: id(x))
classes += module_classes
try:
class_signature = get_method_signature(cls.__init__)
class_signature = class_signature.replace('__init__', cls.__name__)
except:
# in case the class inherits from object and does not
# define __init__
class_signature = module_name + '.' + cls.__name__ + '()'
for cls in classes:
subblocks = []
signature = get_class_signature(cls)
subblocks.append('<span style="float:right;">' + class_to_source_link(cls) + '</span>')
subblocks.append('### ' + cls.__name__ + '\n')
subblocks.append(code_snippet(signature))
docstring = cls.__doc__
if docstring:
subblocks.append(process_class_docstring(docstring))
blocks.append('\n'.join(subblocks))
methods = []
methods_not_defined_here = []
for name in dir(cls):
if name in SKIP:
continue
if name[0] == '_':
continue
cls_member = getattr(cls, name)
if inspect.ismethod(cls_member):
method = cls_member
signature = inspect.getargspec(method)
defaults = signature.defaults
args = signature.args[1:]
if defaults:
kwargs = zip(args[-len(defaults):], defaults)
args = args[:-len(defaults)]
else:
kwargs = []
functions = page_data.get('functions', [])
for module in page_data.get('all_module_functions', []):
module_functions = []
for name in dir(module):
if name[0] == '_' or name in EXCLUDE:
continue
module_member = getattr(module, name)
if inspect.isfunction(module_member):
function = module_member
if module.__name__ in function.__module__:
if function not in module_functions:
module_functions.append(function)
module_functions.sort(key=lambda x: id(x))
functions += module_functions
defined_by = get_earliest_class_that_defined_member(method.__name__, cls)
if cls == defined_by:
methods.append(method)
else:
methods_not_defined_here.append((method, defined_by))
blocks = []
blocks.append('<span style="float:right;">' + class_to_source_link(cls) + '</span>')
blocks.append('# ' + cls.__name__ + '\n')
blocks.append(code_snippet(class_signature))
docstring = cls.__doc__
if docstring:
blocks.append(process_class_docstring(docstring))
if cls.__name__ in INCLUDE_METHODS_FOR:
if methods or methods_not_defined_here:
blocks.append('### Methods\n')
for method in methods:
signature = get_method_signature(method)
signature = signature.replace(module_name + '.', '')
blocks.append(code_snippet(signature))
docstring = method.__doc__
if docstring:
blocks.append(process_method_docstring(docstring))
for method, defined_by in methods_not_defined_here:
signature = get_method_signature(method)
method_module_name = method.__module__
signature = signature.replace(method_module_name + '.', '')
link = '[' + defined_by.__name__ + '](' + class_to_docs_link(defined_by) + ')'
blocks.append(code_snippet(signature))
blocks.append('Defined by ' + link + '.\n')
mkdown = '\n'.join(blocks)
class_pages.append((id(cls), mkdown))
covered_so_far.add(module_member)
class_pages.sort(key=lambda x: x[0])
class_pages = [x[1] for x in class_pages]
module_page = '\n----\n\n'.join(class_pages)
for function in functions:
subblocks = []
signature = get_function_signature(function, method=False)
signature = signature.replace(function.__module__ + '.', '')
subblocks.append('### ' + function.__name__ + '\n')
subblocks.append(code_snippet(signature))
docstring = function.__doc__
if docstring:
subblocks.append(process_function_docstring(docstring))
blocks.append('\n\n'.join(subblocks))
mkdown = '\n----\n\n'.join(blocks)
# save module page.
# Either insert content into existing page,
# or create page otherwise
path = 'sources/' + module_name.replace('.', '/')[6:] + '.md'
page_name = page_data['page']
path = os.path.join('sources', page_name)
if os.path.exists(path):
template = open(path).read()
assert '{{autogenerated}}' in template, ('Template found for ' + path +
' but missing {{autogenerated}} tag.')
module_page = template.replace('{{autogenerated}}', module_page)
mkdown = template.replace('{{autogenerated}}', mkdown)
print('...inserting autogenerated content into template:', path)
else:
print('...creating new page with autogenerated content:', path)
subdir = os.path.dirname(path)
if not os.path.exists(subdir):
os.makedirs(subdir)
open(path, 'w').write(module_page)
open(path, 'w').write(mkdown)
# covered_so_far = set()
# for module, module_name in MODULES:
# class_pages = []
# for name in dir(module):
# if name in SKIP:
# continue
# if name[0] == '_':
# continue
# module_member = getattr(module, name)
# if module_member in covered_so_far:
# continue
# if inspect.isclass(module_member):
# cls = module_member
# if cls.__module__ == module_name:
# try:
# class_signature = get_function_signature(cls.__init__)
# class_signature = class_signature.replace('__init__', cls.__name__)
# except:
# # in case the class inherits from object and does not
# # define __init__
# class_signature = module_name + '.' + cls.__name__ + '()'
# functions = []
# functions_not_defined_here = []
# for name in dir(cls):
# if name in SKIP:
# continue
# if name[0] == '_':
# continue
# cls_member = getattr(cls, name)
# if inspect.isfunction(cls_member):
# function = cls_member
# signature = inspect.getargspec(function)
# defaults = signature.defaults
# args = signature.args[1:]
# if defaults:
# kwargs = zip(args[-len(defaults):], defaults)
# args = args[:-len(defaults)]
# else:
# kwargs = []
# defined_by = get_earliest_class_that_defined_member(function.__name__, cls)
# if cls == defined_by:
# functions.append(function)
# else:
# functions_not_defined_here.append((function, defined_by))
# blocks = []
# blocks.append('<span style="float:right;">' + class_to_source_link(cls) + '</span>')
# blocks.append('# ' + cls.__name__ + '\n')
# blocks.append(code_snippet(class_signature))
# docstring = cls.__doc__
# if docstring:
# blocks.append(process_class_docstring(docstring))
# if cls.__name__ in INCLUDE_functionS_FOR:
# if functions or functions_not_defined_here:
# blocks.append('### functions\n')
# for function in functions:
# signature = get_function_signature(function)
# signature = signature.replace(module_name + '.', '')
# blocks.append(code_snippet(signature))
# docstring = function.__doc__
# if docstring:
# blocks.append(process_function_docstring(docstring))
# for function, defined_by in functions_not_defined_here:
# signature = get_function_signature(function)
# function_module_name = function.__module__
# signature = signature.replace(function_module_name + '.', '')
# link = '[' + defined_by.__name__ + '](' + class_to_docs_link(defined_by) + ')'
# blocks.append(code_snippet(signature))
# blocks.append('Defined by ' + link + '.\n')
# mkdown = '\n'.join(blocks)
# class_pages.append((id(cls), mkdown))
# covered_so_far.add(module_member)
# class_pages.sort(key=lambda x: x[0])
# class_pages = [x[1] for x in class_pages]
# module_page = '\n----\n\n'.join(class_pages)
# # save module page.
# # Either insert content into existing page,
# # or create page otherwise
# path = 'sources/' + module_name.replace('.', '/')[6:] + '.md'
# if os.path.exists(path):
# template = open(path).read()
# assert '{{autogenerated}}' in template, ('Template found for ' + path +
# ' but missing {{autogenerated}} tag.')
# module_page = template.replace('{{autogenerated}}', module_page)
# print('...inserting autogenerated content into template:', path)
# else:
# print('...creating new page with autogenerated content:', path)
# subdir = os.path.dirname(path)
# if not os.path.exists(subdir):
# os.makedirs(subdir)
# open(path, 'w').write(module_page)
+29 -19
Ver Arquivo
@@ -3,8 +3,8 @@ theme: readthedocs
docs_dir: sources
repo_url: http://github.com/fchollet/keras
site_url: http://keras.io/
#theme_dir: theme
site_description: Documentation for fast and lightweight Keras Deep Learning library.
# theme_dir: theme
site_description: 'Documentation for Keras, the Python Deep Learning library.'
dev_addr: '0.0.0.0:8000'
google_analytics: ['UA-61785484-1', 'keras.io']
@@ -12,31 +12,41 @@ google_analytics: ['UA-61785484-1', 'keras.io']
pages:
- Home: index.md
- Index: documentation.md
- Examples: examples.md
- FAQ: faq.md
- Backends: backend.md
- Optimizers: optimizers.md
- Objectives: objectives.md
- Models: models.md
- Activations: activations.md
- Initializations: initializations.md
- Regularizers: regularizers.md
- Constraints: constraints.md
- Callbacks: callbacks.md
- Datasets: datasets.md
- Visualization: visualization.md
- Getting started:
- Guide to the Sequential model: getting-started/sequential-model-guide.md
- Guide to the Functional API: getting-started/functional-api-guide.md
- FAQ: getting-started/faq.md
- Models:
- About Keras models: models/about-keras-models.md
- Sequential: models/sequential.md
- Model (functional API): models/model.md
- Layers:
- About Keras layers: layers/about-keras-layers.md
- Core Layers: layers/core.md
- Convolutional Layers: layers/convolutional.md
- Recurrent Layers: layers/recurrent.md
- Advanced Activations Layers: layers/advanced_activations.md
- Normalization Layers: layers/normalization.md
- Embedding Layers: layers/embeddings.md
- Advanced Activations Layers: layers/advanced-activations.md
- Normalization Layers: layers/normalization.md
- Noise layers: layers/noise.md
- Containers: layers/containers.md
- Layer wrappers: layers/wrappers.md
- Writing your own Keras layers: layers/writing-your-own-keras-layers.md
- Preprocessing:
- Sequence Preprocessing: preprocessing/sequence.md
- Text Preprocessing: preprocessing/text.md
- Image Preprocessing: preprocessing/image.md
- Objectives: objectives.md
- Optimizers: optimizers.md
- Activations: activations.md
- Callbacks: callbacks.md
- Datasets: datasets.md
- Backend: backend.md
- Initializations: initializations.md
- Regularizers: regularizers.md
- Constraints: constraints.md
- Visualization: visualization.md
- Scikit-learn API: scikit-learn-api.md
+5 -3
Ver Arquivo
@@ -14,11 +14,13 @@ is equivalent to:
model.add(Dense(64, activation='tanh'))
```
You can also pass an element-wise Theano function as an activation:
You can also pass an element-wise Theano/TensorFlow function as an activation:
```python
from keras import backend as K
def tanh(x):
return theano.tensor.tanh(x)
return K.tanh(x)
model.add(Dense(64, activation=tanh))
model.add(Activation(tanh))
@@ -36,4 +38,4 @@ model.add(Activation(tanh))
## On Advanced Activations
Activations that are more complex than a simple Theano function (eg. learnable activations, configurable activations, etc.) are available as [Advanced Activation layers](layers/advanced_activations.md), and can be found in the module `keras.layers.advanced_activations`. These include PReLU and LeakyReLU.
Activations that are more complex than a simple Theano/TensorFlow function (eg. learnable activations, configurable activations, etc.) are available as [Advanced Activation layers](layers/advanced-activations.md), and can be found in the module `keras.layers.advanced_activations`. These include PReLU and LeakyReLU.
+10 -2
Ver Arquivo
@@ -9,6 +9,8 @@ At this time, Keras has two backend implementations available: the **Theano** ba
- [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:
@@ -32,6 +34,8 @@ Using TensorFlow backend.
tensorflow
```
----
## 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.
@@ -74,8 +78,12 @@ 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`.
----
## Backend functions
{{autogenerated}}
+20 -14
Ver Arquivo
@@ -2,13 +2,13 @@
## CIFAR10 small image classification
`keras.datasets.cifar10`
Dataset of 50,000 32x32 color training images, labeled over 10 categories, and 10,000 test images.
### Usage:
```python
from keras.datasets import cifar10
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
```
@@ -21,13 +21,13 @@ Dataset of 50,000 32x32 color training images, labeled over 10 categories, and 1
## CIFAR100 small image classification
`keras.datasets.cifar100`
Dataset of 50,000 32x32 color training images, labeled over 100 categories, and 10,000 test images.
### Usage:
```python
from keras.datasets import cifar100
(X_train, y_train), (X_test, y_test) = cifar100.load_data(label_mode='fine')
```
@@ -44,8 +44,6 @@ Dataset of 50,000 32x32 color training images, labeled over 100 categories, and
## IMDB Movie reviews sentiment classification
`keras.datasets.imdb`
Dataset of 25,000 movies reviews from IMDB, labeled by sentiment (positive/negative). Reviews have been preprocessed, and each review is encoded as a [sequence](preprocessing/sequence.md) of word indexes (integers). For convenience, words are indexed by overall frequency in the dataset, so that for instance the integer "3" encodes the 3rd most frequent word in the data. This allows for quick filtering operations such as: "only consider the top 10,000 most common words, but eliminate the top 20 most common words".
As a convention, "0" does not stand for a specific word, but instead is used to encode any unknown word.
@@ -53,8 +51,13 @@ As a convention, "0" does not stand for a specific word, but instead is used to
### Usage:
```python
(X_train, y_train), (X_test, y_test) = imdb.load_data(path="imdb.pkl", \
nb_words=None, skip_top=0, maxlen=None, test_split=0.1, seed=113)
from keras.datasets import imdb
(X_train, y_train), (X_test, y_test) = imdb.load_data(path="imdb.pkl",
nb_words=None,
skip_top=0,
maxlen=None,
test_split=0.1)
```
- __Return:__
- 2 tuples:
@@ -74,15 +77,18 @@ nb_words=None, skip_top=0, maxlen=None, test_split=0.1, seed=113)
## Reuters newswire topics classification
`keras.datasets.reuters`
Dataset of 11,228 newswires from Reuters, labeled over 46 topics. As with the IMDB dataset, each wire is encoded as a sequence of word indexes (same conventions).
### Usage:
```python
(X_train, y_train), (X_test, y_test) = reuters.load_data(path="reuters.pkl", \
nb_words=None, skip_top=0, maxlen=None, test_split=0.1, seed=113)
from keras.datasets import reuters
(X_train, y_train), (X_test, y_test) = reuters.load_data(path="reuters.pkl",
nb_words=None,
skip_top=0,
maxlen=None,
test_split=0.1)
```
The specifications are the same as that of the IMDB dataset.
@@ -101,13 +107,13 @@ word_index = reuters.get_word_index(path="reuters_word_index.pkl")
## MNIST database of handwritten digits
`keras.datasets.mnist`
Dataset of 60,000 28x28 grayscale images of the 10 digits, along with a test set of 10,000 images.
### Usage:
```python
from keras.datasets import mnist
(X_train, y_train), (X_test, y_test) = mnist.load_data()
```
-40
Ver Arquivo
@@ -1,40 +0,0 @@
# Keras Documentation Index
## Introduction
- [Home](index.md)
- [Index](documentation.md)
- [Examples](examples.md)
- [FAQ](faq.md)
- [Backend](backend.md)
---
## Base functionality
- [Optimizers](optimizers.md)
- [Objectives](objectives.md)
- [Models](models.md)
- [Activations](activations.md)
- [Initializations](initializations.md)
- [Regularizers](regularizers.md)
- [Constraints](constraints.md)
- [Callbacks](callbacks.md)
- [Datasets](datasets.md)
---
## Layers
- [Core](layers/core.md)
- [Convolutional](layers/convolutional.md)
- [Recurrent](layers/recurrent.md)
- [Advanced Activations](layers/advanced_activations.md)
- [Normalization](layers/normalization.md)
- [Embeddings](layers/embeddings.md)
---
## Preprocessing
- [Sequence](preprocessing/sequence.md)
- [Text](preprocessing/text.md)
- [Image](preprocessing/image.md)
-177
Ver Arquivo
@@ -1,177 +0,0 @@
Here are a few examples to get you started!
### Multilayer Perceptron (MLP):
```python
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
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)
```
### Alternative implementation of MLP:
```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)
```
### VGG-like convnet:
```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)
```
### Sequence classification with LSTM:
```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)
```
### 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.
```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(TimeDistributedDense(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)
```
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
...and more.
@@ -1,31 +1,39 @@
# Keras FAQ: Frequently Asked Keras Questions
[How can I run Keras on GPU?](#how-can-i-run-keras-on-gpu)
[How can I save a Keras model?](#how-can-i-save-a-keras-model)
[Why is the training loss much higher than the testing loss?](#why-is-the-training-loss-much-higher-than-the-testing-loss)
[How can I visualize the output of an intermediate layer?](#how-can-i-visualize-the-output-of-an-intermediate-layer)
[Isn't there a bug with Merge or Graph related to input concatenation?](#isnt-there-a-bug-with-merge-or-graph-related-to-input-concatenation)
[How can I use Keras with datasets that don't fit in memory?](#how-can-i-use-keras-with-datasets-that-dont-fit-in-memory)
[How can I interrupt training when the validation loss isn't decreasing anymore?](#how-can-i-interrupt-training-when-the-validation-loss-isnt-decreasing-anymore)
[How is the validation split computed?](#how-is-the-validation-split-computed)
[Is the data shuffled during training?](#is-the-data-shuffled-during-training)
[How can I record the training / validation loss / accuracy at each epoch?](#how-can-i-record-the-training-validation-loss-accuracy-at-each-epoch)
[How can I use stateful RNNs?](#how-can-i-use-stateful-rnns)
- [How should I cite Keras?](#how-should-i-cite-keras)
- [How can I run Keras on GPU?](#how-can-i-run-keras-on-gpu)
- [How can I save a Keras model?](#how-can-i-save-a-keras-model)
- [Why is the training loss much higher than the testing loss?](#why-is-the-training-loss-much-higher-than-the-testing-loss)
- [How can I visualize the output of an intermediate layer?](#how-can-i-visualize-the-output-of-an-intermediate-layer)
- [How can I use Keras with datasets that don't fit in memory?](#how-can-i-use-keras-with-datasets-that-dont-fit-in-memory)
- [How can I interrupt training when the validation loss isn't decreasing anymore?](#how-can-i-interrupt-training-when-the-validation-loss-isnt-decreasing-anymore)
- [How is the validation split computed?](#how-is-the-validation-split-computed)
- [Is the data shuffled during training?](#is-the-data-shuffled-during-training)
- [How can I record the training / validation loss / accuracy at each epoch?](#how-can-i-record-the-training-validation-loss-accuracy-at-each-epoch)
- [How can I use stateful RNNs?](#how-can-i-use-stateful-rnns)
---
### How should I cite Keras?
Please cite Keras in your publications if it helps your research. Here is an example BibTeX entry:
```
@misc{chollet2015keras,
author = {Chollet, François},
title = {Keras},
year = {2015},
publisher = {GitHub},
journal = {GitHub repository},
howpublished = {\url{https://github.com/fchollet/keras}}
}
```
### How can I run Keras on GPU?
If you are running on the TensorFlow backend, your code will automatically run on GPU if any available GPU is detected.
If you are running on the Theano backend, you can use one of the following methods:
Method 1: use Theano flags.
```bash
THEANO_FLAGS=device=gpu,floatX=float32 python my_keras_script.py
@@ -69,7 +77,10 @@ model = model_from_json(json_string)
model = model_from_yaml(yaml_string)
```
If you need to save the weights of a model, you can do so in HDF5:
If you need to save the weights of a model, you can do so in HDF5 with the code below.
Note that you will first need to install HDF5 and the Python library h5py, which do not come bundled with Keras.
```python
model.save_weights('my_model_weights.h5')
```
@@ -103,39 +114,42 @@ Besides, the training loss is the average of the losses over each batch of train
### How can I visualize the output of an intermediate layer?
You can build a Theano function that will return the output of a certain layer given a certain input, for example:
You can build a Keras function that will return the output of a certain layer given a certain input, for example:
```python
# with a Sequential model
get_3rd_layer_output = theano.function([model.layers[0].input],
model.layers[3].get_output(train=False))
layer_output = get_3rd_layer_output(X)
from keras import backend as K
# with a Graph model
get_conv_layer_output = theano.function([model.inputs[i].input for i in model.input_order],
model.nodes['conv'].get_output(train=False),
on_unused_input='ignore')
conv_output = get_conv_layer_output([input_data_dict[i] for i in model.input_order])
# with a Sequential model
get_3rd_layer_output = K.function([model.layers[0].input],
[model.layers[3].output])
layer_output = get_3rd_layer_output([X])[0]
```
---
Similarly, you could build a Theano and TensorFlow function directly.
### Isn't there a bug with Merge or Graph related to input concatenation?
Note that if your model has a different behavior in training and testing phase (e.g. if it uses `Dropout`, `BatchNormalization`, etc.), you will need
to pass the learning phase flag to your function:
Yes, there was a known bug with tensor concatenation in Theano that was fixed early 2015.
Please upgrade to the latest version of Theano:
```python
get_3rd_layer_output = K.function([model.layers[0].input, K.learning_phase()],
[model.layers[3].output])
```bash
sudo pip install git+git://github.com/Theano/Theano.git
# output in train mode
layer_output = get_3rd_layer_output([X, 1])[0]
# output in test mode
layer_output = get_3rd_layer_output([X, 1])[0]
```
---
### How can I use Keras with datasets that don't fit in memory?
You can do batch training using `model.train_on_batch(X, y)` and `model.test_on_batch(X, y)`. See the [models documentation](models.md).
You can do batch training using `model.train_on_batch(X, y)` and `model.test_on_batch(X, y)`. See the [models documentation](/models/sequential).
You can also see batch training in action in our [CIFAR10 example](https://github.com/fchollet/keras/blob/master/examples/cifar10_cnn.py).
Alternatively, you can write a generator that yields batches of training data and use the method `model.fit_generator(data_generator, samples_per_epoch, nb_epoch)`.
You can see batch training in action in our [CIFAR10 example](https://github.com/fchollet/keras/blob/master/examples/cifar10_cnn.py).
---
@@ -149,7 +163,7 @@ early_stopping = EarlyStopping(monitor='val_loss', patience=2)
model.fit(X, y, validation_split=0.2, callbacks=[early_stopping])
```
Find out more in the [callbacks documentation](callbacks.md).
Find out more in the [callbacks documentation](/callbacks).
---
@@ -164,14 +178,14 @@ If you set the `validation_split` argument in `model.fit` to e.g. 0.1, then the
Yes, if the `shuffle` argument in `model.fit` is set to `True` (which is the default), the training data will be randomly shuffled at each epoch.
Validation data isn't shuffled.
Validation data is never shuffled.
---
### How can I record the training / validation loss / accuracy at each epoch?
The `model.fit` method returns an `History` callback, which has a `history` attribute containing the lists of successive losses / accuracies.
The `model.fit` method returns an `History` callback, which has a `history` attribute containing the lists of successive losses and other metrics.
```python
hist = model.fit(X, y, validation_split=0.2)
+421
Ver Arquivo
@@ -0,0 +1,421 @@
# Getting started with the Keras functional API
The Keras functional API is the way to go for defining complex models, such as multi-output models, directed acyclic graphs, or models with shared layers.
This guide assumes that you are already familiar with the `Sequential` model.
Let's start with something simple.
-----
## First example: fully connected network
The `Sequential` model is probably a better choice to implement such a network, but it helps to start with something really simple.
- A layer instance is callable (on a tensor), and it returns a tensor
- Input tensor(s) and output tensor(s) can then be used to define a `Model`
- Such a model can be trained just like Keras `Sequential` models.
```python
from keras.layers import Input, Dense
from keras.models import Model
# this returns a tensor
inputs = Input(shape=(784,))
# a layer instance is callable on a tensor, and returns a tensor
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# this creates a model that includes
# the Input layer and three Dense layers
model = Model(input=inputs, output=predictions)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.fit(data, labels) # starts training
```
-----
## All models are callable, just like layers
With the functional API, it is easy to re-use trained models: you can treat any model as if it were a layer, by calling it on a tensor. Note that by calling a model you aren't just re-using the *architecture* of the model, you are also re-using its weights.
```python
x = Input(shape=(784,))
# this works, and returns the 10-way softmax we defined above.
y = model(x)
```
This can allow, for instance, to quickly create models that can process *sequences* of inputs. You could turn an image classification model into a video classification model, in just one line.
```python
from keras.layers import TimeDistributed
# input tensor for sequences of 20 timesteps,
# each containing a 784-dimensional vector
input_sequences = Input(shape=(20, 784))
# this applies our previous model to every timestep in the input sequences.
# the output of the previous model was a 10-way softmax,
# so the output of the layer below will be a sequence of 20 vectors of size 10.
processed_sequences = TimeDistributed(model)(input_sequences)
```
-----
## Multi-input and multi-output models
Here's a good use case for the functional API: models with multiple inputs and outputs. The functional API makes it easy to manipulate a large number of intertwined datastreams.
Let's consider the following model. We seek to predict how many retweets and likes a news headline will receive on Twitter. The main input to the model will be the headline itself, as a sequence of words, but to spice things up, our model will also have an auxiliary input, receiving extra data such as the time of day when the headline was posted, etc.
The model will also be supervised via two loss functions. Using the main loss function earlier in a model is a good regularization mechanism for deep models.
Here's what our model looks like:
<img src="http://s3.amazonaws.com/keras.io/img/multi-input-multi-output-graph.png" alt="multi-input-multi-output-graph" style="width: 400px;"/>
Let's implement it with the functional API.
The main input will receive the headline, as a sequence of integers (each integer encodes a word).
The integers will be between 1 and 10,000 (a vocabulary of 10,000 words) and the sequences will be 100 words long.
```python
from keras.layers import Input, Embedding, LSTM, Dense, merge
from keras.models import Model
# headline input: meant to receive sequences of 100 integers, between 1 and 10000.
# note that we can name any layer by passing it a "name" argument.
main_input = Input(shape=(100,), dtype='int32', name='main_input')
# this embedding layer will encode the input sequence
# into a sequence of dense 512-dimensional vectors.
x = Embedding(output_dim=512, input_dim=10000, input_length=100)(main_input)
# a LSTM will transform the vector sequence into a single vector,
# containing information about the entire sequence
lstm_out = LSTM(32)(x)
```
Here we insert the auxiliary loss, allowing the LSTM and Embedding layer to be trained smoothly even though the main loss will be much higher in the model.
```python
auxiliary_loss = Dense(1, activation='sigmoid', name='aux_output')(lstm_out)
```
At this point, we feed into the model our auxiliary input data by concatenating it with the LSTM output:
```python
auxiliary_input = Input(shape=(5,), name='aux_input')
x = merge([lstm_out, auxiliary_input], mode='concat')
# we stack a deep fully-connected network on top
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
x = Dense(64, activation='relu')(x)
# and finally we add the main logistic regression layer
main_loss = Dense(1, activation='sigmoid', name='main_output')(x)
```
This defines a model with two inputs and two outputs:
```python
model = Model(input=[main_input, auxiliary_input], output=[main_loss, auxiliary_loss])
```
We compile the model and assign a weight of 0.2 to the auxiliary loss.
To specify different `loss_weight` or `loss` for each different output, you can use a list or a dictionary.
Here we pass a single loss as the `loss` argument, so the same loss will be used on all outputs.
```python
model.compile(optimizer='rmsprop', loss='binary_crossentropy',
loss_weight=[1., 0.2])
```
We can train the model by passing it lists of input arrays and target arrays:
```python
model.fit([headline_data, additional_data], [labels, labels],
nb_epoch=50, batch_size=32)
```
Since our inputs and outputs are named (we passed them a "name" argument),
We could also have compiled the model via:
```python
model.compile(optimizer='rmsprop',
loss={'main_output': 'binary_crossentropy', 'aux_output': 'binary_crossentropy'},
loss_weight={'main_output': 1., 'aux_output': 0.2})
# and trained it via:
model.fit({'main_input': headline_data, 'aux_input': additional_data},
{'main_output': labels, 'aux_output': labels},
nb_epoch=50, batch_size=32)
```
-----
## Shared layers
Another good use for the functional API are models that use shared layers. Let's take a look at shared layers.
Let's consider a dataset of tweets. We want to build a model that can tell whether two tweets are from the same person or not (this can allow us to compare users by the similarity of their tweets, for instance).
One way to achieve this is to build a model that encodes two tweets into two vectors, concatenates the vectors and adds a logistic regression of top, outputting a probability that the two tweets share the same author. The model would then be trained on positive tweet pairs and negative tweet pairs.
Because the problem is symetric, the mechanism that encodes the first tweet should be reused (weights and all) to encode the second tweet. Here we use a shared LSTM layer to encode the tweets.
Let's build this with the functional API. We will take as input for a tweet a binary matrix of shape `(140, 256)`, i.e. a sequence of 140 vectors of size 256, where each dimension in the 256-dimensional vector encodes the presence/absence of a character (out of an alphabet of 256 frequent characters).
```python
from keras.layers import Input, LSTM, Dense, merge
from keras.models import Model
tweet_a = Input(shape=(140, 256))
tweet_b = Input(shape=(140, 256))
```
To share a layer across different inputs, simply instantiate the layer once, then call it on as many inputs as you want:
```python
# this layer can take as input a matrix
# and will return a vector of size 64
shared_lstm = LSTM(64)
# when we reuse the same layer instance
# multiple times, the weights of the layer
# are also being reused
# (it is effectively *the same* layer)
encoded_a = shared_lstm(tweet_a)
encoded_b = shared_lstm(tweet_b)
# we can then concatenate the two vectors:
merged_vector = merge([encoded_a, encoded_b], mode='concat', concat_axis=-1)
# and add a logistic regression on top
predictions = Dense(1, activation='sigmoid')(merged_vector)
# we define a trainable model linking the
# tweet inputs to the predictions
model = Model(input=[tweet_a, tweet_b], output=predictions)
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
model.fit([data_a, data_b], labels, nb_epoch=10)
```
Let's pause to take a look at how to read the shared layer's output or output shape.
-----
## The concept of layer "node"
Whenever you are calling a layer on some input, you are creating a new tensor (the output of the layer), and you are adding a "node" to the layer, linking the input tensor to the output tensor. When you are calling the same layer multiple times, that layer owns multiple nodes indexed as 0, 1, 2...
In previous versions of Keras, you could obtain the output tensor of a layer instance via `layer.get_output()`, or its output shape via `layer.output_shape`. You still can (except `get_output()` has been replaced by the property `output`). But what if a layer is connected to multiple inputs?
As long as a layer is only connected to one input, there is no confusion, and `.output` will return the one output of the layer:
```python
a = Input(shape=(140, 256))
lstm = LSTM(32)
encoded_a = lstm(a)
assert lstm.output == encoded_a
```
Not so if the layer has multiple inputs:
```python
a = Input(shape=(140, 256))
b = Input(shape=(140, 256))
lstm = LSTM(32)
encoded_a = lstm(a)
encoded_b = lstm(b)
lstm.output
```
```
>> AssertionError: Layer lstm_1 has multiple inbound nodes,
hence the notion of "layer output" is ill-defined.
Use `get_output_at(node_index)` instead.
```
Okay then. The following works:
```python
assert lstm.get_output_at(0) == encoded_a
assert lstm.get_output_at(1) == encoded_b
```
Simple enough, right?
The same is true for the properties `input_shape` and `output_shape`: as long as the layer has only one node, or as long as all nodes have the same input/output shape, then the notion of "layer output/input shape" is well defined, and that one shape will be returned by `layer.output_shape`/`layer.input_shape`. But if, for instance, you apply a same `Convolution2D` layer to an input of shape `(3, 32, 32)`, and then to an input of shape `(3, 64, 64)`, the layer will have multiple input/output shapes, and you will have to fetch them by specifying the index of the node they belong to:
```python
a = Input(shape=(3, 32, 32))
b = Input(shape=(3, 64, 64))
conv = Convolution2D(16, 3, 3, border_mode='same')
conved_a = conv(a)
# only one input so far, the following will work:
assert conv.input_shape == (None, 3, 32, 32)
conved_b = conv(b)
# now the `.input_shape` property wouldn't work, but this does:
assert conv.get_input_shape_at(0) == (None, 3, 32, 32)
assert conv.get_input_shape_at(1) == (None, 3, 64, 64)
```
-----
## More examples
Code examples are still the best way to get started, so here are a few more.
### Inception module
For more information about the Inception architecture, see [Going Deeper with Convolutions](http://arxiv.org/abs/1409.4842).
```python
from keras.layers import merge, Convolution2D, MaxPooling2D, Input
input_img = Input(shape=(3, 256, 256))
tower_1 = Convolution2D(64, 1, 1, border_mode='same', activation='relu')(input_img)
tower_1 = Convolution2D(64, 3, 3, border_mode='same', activation='relu')(tower_1)
tower_2 = Convolution2D(64, 1, 1, border_mode='same', activation='relu')(input_img)
tower_2 = Convolution2D(64, 5, 5, border_mode='same', activation='relu')(tower_2)
tower_3 = MaxPooling2D((3, 3), strides=(1, 1), border_mode='same')(input_img)
tower_3 = Convolution2D(64, 1, 1, border_mode='same', activation='relu')(tower_3)
output = merge([tower_1, tower_2, tower_3], mode='concat', concat_axis=1)
```
### Residual connection on a convolution layer
For more information about residual networks, see [Deep Residual Learning for Image Recognition](http://arxiv.org/abs/1512.03385).
```python
from keras.layers import merge, Convolution2D, Input
# input tensor for a 3-channel 256x256 image
x = Input(shape=(3, 256, 256))
# 3x3 conv with 16 output channels
y = Convolution2D(16, 3, 3, border_mode='same')
# this returns x + y.
z = merge([x, y], mode='sum')
```
### Shared vision model
This model re-uses the same image-processing module on two inputs, to classify whether two MNIST digits are the same digit or different digits.
```python
from keras.layers import merge, Convolution2D, MaxPooling2D, Input, Dense, Flatten
from keras.models import Model
# first, define the vision modules
digit_input = Input(shape=(1, 27, 27))
x = Convolution2D(64, 3, 3)(digit_input)
x = Convolution2D(64, 3, 3)(x)
x = MaxPooling2D((2, 2))(x)
out = Flatten()(x)
vision_model = Model(digit_input, out)
# then define the tell-digits-apart model
digit_a = Input(shape=(1, 27, 27))
digit_b = Input(shape=(1, 27, 27))
# the vision model will be shared, weights and all
out_a = vision_model(digit_a)
out_b = vision_model(digit_b)
concatenated = merge([out_a, out_b], mode='concat')
out = Dense(1, activation='sigmoid')(concatenated)
classification_model = Model([digit_a, digit_b], out)
```
### Visual question answering model
This model can select the correct one-word answer when asked a natural-language question about a picture.
It works by encoding the question into a vector, encoding the image into a vector, concatenating the two, and training on top a logistic regression over some vocabulary of potential answers.
```python
from keras.layers import Convolution2D, MaxPooling2D, Flatten
from keras.layers import Input, LSTM, Embedding, Dense, merge
from keras.models import Model, Sequential
# first, let's define a vision model using a Sequential model.
# this model will encode an image into a vector.
vision_model = Sequential()
vision_model.add(Convolution2D(64, 3, 3, activation='relu', border_mode='same', input_shape=(3, 224, 224)))
vision_model.add(Convolution2D(64, 3, 3, activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Convolution2D(128, 3, 3, activation='relu', border_mode='same'))
vision_model.add(Convolution2D(128, 3, 3, activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Convolution2D(256, 3, 3, activation='relu', border_mode='same'))
vision_model.add(Convolution2D(256, 3, 3, activation='relu'))
vision_model.add(Convolution2D(256, 3, 3, activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Flatten())
# now let's get a tensor with the output of our vision model:
image_input = Input(shape=(3, 224, 224))
encoded_image = vision_model(image_input)
# next, let's define a language model to encode the question into a vector.
# each question will be at most 100 word long,
# and we will index words as integers from 1 to 9999.
question_input = Input(shape=(100,), dtype='int32')
embedded_question = Embedding(input_dim=10000, output_dim=256, input_length=100)(question_input)
encoded_question = LSTM(256)(embedded_question)
# let's concatenate the question vector and the image vector:
merged = merge([encoded_question, encoded_image], mode='concat')
# and let's train a logistic regression over 1000 words on top:
output = Dense(1000, activation='softmax')(merged)
# this is our final model:
vqa_model = Model(input=[image_input, question_input], output=output)
# the next stage would be training this model on actual data.
```
### Video question answering model
Now that we have trained our image QA model, we can quickly turn it into a video QA model. With appropriate training, you will be able to show it a short video (e.g. 100-frame human action) and ask a natural language question about the video (e.g. "what sport is the boy playing?" -> "football").
```python
from keras.layers import TimeDistributed
video_input = Input(shape=(100, 3, 224, 224))
# this is our video encoded via the previously trained vision_model (weights are reused)
encoded_frame_sequence = TimeDistributed(vision_model)(video_input) # the output will be a sequence of vectors
encoded_video = LSTM(256)(encoded_frame_sequence) # the output will be a vector
# this is a model-level representation of the question encoder, reusing the same weights as before:
question_encoder = Model(input=question_input, output=encoded_question)
# let's use it to encode the question:
video_question_input = Input(shape=(100,), dtype='int32')
encoded_video_question = question_encoder(video_question_input)
# and this is our video question answering model:
merged = merge([encoded_video, encoded_video_question], mode='concat')
output = Dense(1000, activation='softmax')(merged)
video_qa_model = Model(input=[video_input, video_question_input], output=output)
```
+541
Ver Arquivo
@@ -0,0 +1,541 @@
# Getting started with the Keras Sequential model
The `Sequential` model is a linear stack of layers.
You can create a `Sequential` model by passing a list of layer instances to the constructor:
```python
from keras.models import Sequential
model = Sequential([
Dense(32, input_dim=784),
Activation('relu'),
Dense(10),
Activation('softmax'),
])
```
You can also simply add layers via the `.add()` method:
```python
model = Sequential()
model.add(Dense(32, input_dim=784))
model.add(Activation('relu'))
```
----
## Specifying the input shape
The model needs to know what input shape it should expect. For this reason, the first layer in a `Sequential` model (and only the first, because following layers can do automatic shape inference) needs to receive information about its input shape. There are several possible ways to do this:
- pass an `input_shape` argument to the first layer. This is a shape tuple (a tuple of integers or `None` entries, where `None` indicates that any positive integer may be expected). In `input_shape`, the batch dimension is not included.
- pass instead a `batch_input_shape` argument, where the batch dimension is included. This is useful for specifying a fixed batch size (e.g. with stateful RNNs).
- some 2D layers, such as `Dense`, support the specification of their input shape via the argument `input_dim`, and some 3D temporal layers support the arguments `input_dim` and `input_length`.
As such, the following three snippets are strictly equivalent:
```python
model = Sequential()
model.add(Dense(32, input_shape=(784,)))
```
```python
model = Sequential()
model.add(Dense(32, batch_input_shape=(None, 784)))
# note that batch dimension is "None" here,
# so the model will be able to process batches of any size.
```
```python
model = Sequential()
model.add(Dense(32, input_dim=784))
```
And so are the following three snippets:
```python
model = Sequential()
model.add(LSTM(32, input_shape=(10, 64)))
```
```python
model = Sequential()
model.add(LSTM(32, batch_input_shape=(None, 10, 64)))
```
```python
model = Sequential()
model.add(LSTM(32, input_length=10, input_dim=64))
```
----
## The Merge layer
Multiple `Sequential` instances can be merged into a single output via a `Merge` layer. The output is a layer that can be added as first layer in a new `Sequential` model. For instance, here's a model with two separate input branches getting merged:
```python
from keras.layers import Merge
left_branch = Sequential()
left_branch.add(Dense(32, input_dim=784))
right_branch = Sequential()
right_branch.add(Dense(32, input_dim=784))
merged = Merge([left_branch, right_branch], mode='concat')
final_model = Sequential()
final_model.add(merged)
final_model.add(Dense(10, activation='softmax'))
```
<img src="http://s3.amazonaws.com/keras.io/img/two_branches_sequential_model.png" alt="two branch Sequential" style="width: 400px;"/>
The `Merge` layer supports a number of pre-defined modes:
- `sum` (default): element-wise sum
- `concat`: tensor concatenation. You can specify the concatenation axis via the argument `concat_axis`.
- `mul`: element-wise multiplication
- `ave`: tensor average
- `dot`: dot product. You can specify which axes to reduce along via the argument `dot_axes`.
- `cos`: cosine proximity between vectors in 2D tensors.
You can also pass a function as the `mode` argument, allowing for arbitrary transformations:
```python
merged = Merge([left_branch, right_branch], mode=lambda x, y: x - y)
```
Now you know enough to be able to define *almost* any model with Keras. For complex models that cannot be expressed via `Sequential` and `Merge`, you can use [the functional API](/getting-started/functional-api-guide).
----
## Compilation
Before training a model, you need to configure the learning process, which is done via the `compile` method. It receives three arguments:
- an optimizer. This could be the string identifier of an existing optimizer (such as `rmsprop` or `adagrad`), or an instance of the `Optimizer` class. See: [optimizers](/optimizers).
- a loss function. This is the objective that the model will try to minimize. If can be the string identifier of an existing loss function (such as `categorical_crossentropy` or `mse`), or it can be an objective function. See: [objectives](/objectives).
- a list of metrics. For any classification problem you will want to set this to `metrics=['accuracy']`. A metric could be the string identifier of an existing metric (only `accuracy` is supported at this point), or a custom metric function.
```python
# for a multi-class classification problem
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
# for a binary classification problem
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
# for a mean squared error regression problem
model.compile(optimizer='rmsprop',
loss='mse')
```
----
## Training
Keras models are trained on Numpy arrays of input data and labels. For training a model, you will typically use the `fit` function. [Read its documentation here](/models/sequential).
```python
# for a single-input model with 2 classes (binary):
model = Sequential()
model.add(Dense(1, input_dim=784, activation='softmax'))
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
# generate dummy data
import numpy as np
data = np.random.random((1000, 784))
labels = np.random.randint(2, size=(1000, 1))
# train the model, iterating on the data in batches
# of 32 samples
model.fit(data, labels, nb_epoch=10, batch_size=32)
```
```python
# for a multi-input model with 10 classes:
left_branch = Sequential()
left_branch.add(Dense(32, input_dim=784))
right_branch = Sequential()
right_branch.add(Dense(32, input_dim=784))
merged = Merge([left_branch, right_branch], mode='concat')
model = Sequential()
model.add(merged)
model.add(Dense(10, activation='softmax'))
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
# generate dummy data
import numpy as np
from keras.utils.np_utils import to_categorical
data_1 = np.random.random((1000, 784))
data_2 = np.random.random((1000, 784))
# these are integers between 0 and 9
labels = np.random.randint(10, size=(1000, 1))
# we convert the labels to a binary matrix of size (1000, 10)
# for use with categorical_crossentropy
labels = to_categorical(labels, 10)
# train the model
# note that we are passing a list of Numpy arrays as training data
# since the model has 2 inputs
model.fit([data_1, data_2], labels, nb_epoch=10, batch_size=32)
```
----
## Examples
Here are a few examples to get you started!
In the examples folder, you will also 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
...and more.
### Multilayer Perceptron (MLP) for multi-class softmax classification:
```python
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
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(10, init='uniform'))
model.add(Activation('softmax'))
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy',
optimizer=sgd,
metrics=['accuracy'])
model.fit(X_train, y_train,
nb_epoch=20,
batch_size=16)
score = model.evaluate(X_test, y_test, batch_size=16)
```
### Alternative implementation of a similar MLP:
```python
model = Sequential()
model.add(Dense(64, input_dim=20, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])
```
### MLP for binary classification:
```python
model = Sequential()
model.add(Dense(64, input_dim=20, init='uniform', activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
```
### VGG-like convnet:
```python
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers 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='valid', 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)
```
### Sequence classification with LSTM:
```python
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation
from keras.layers import Embedding
from keras.layers 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',
metrics=['accuracy'])
model.fit(X_train, Y_train, batch_size=16, nb_epoch=10)
score = model.evaluate(X_test, Y_test, batch_size=16)
```
### Architecture for learning image captions with a convnet and a Gated Recurrent Unit:
(word-level embedding, caption of maximum length 16 words).
Note that getting this to work well will require using a bigger convnet, initialized with pre-trained weights.
```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='valid', 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='valid'))
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(TimeDistributedDense(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 = Sequential()
model.add(Merge([image_model, language_model], mode='concat', concat_axis=-1))
# let's encode this vector sequence into a single vector
model.add(GRU(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)
```
### Stacked LSTM for sequence classification
In this model, we stack 3 LSTM layers on top of each other,
making the model capable of learning higher-level temporal representations.
The first two LSTMs return their full output sequences, but the last one only returns
the last step in its output sequence, thus dropping the temporal dimension
(i.e. converting the input sequence into a single vector).
<img src="http://keras.io/img/regular_stacked_lstm.png" alt="stacked LSTM" style="width: 300px;"/>
```python
from keras.models import Sequential
from keras.layers import LSTM, Dense
import numpy as np
data_dim = 16
timesteps = 8
nb_classes = 10
# expected input data shape: (batch_size, timesteps, data_dim)
model = Sequential()
model.add(LSTM(32, return_sequences=True,
input_shape=(timesteps, data_dim))) # returns a sequence of vectors of dimension 32
model.add(LSTM(32, return_sequences=True)) # returns a sequence of vectors of dimension 32
model.add(LSTM(32)) # return a single vector of dimension 32
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# generate dummy training data
x_train = np.random.random((1000, timesteps, data_dim))
y_train = np.random.random((1000, nb_classes))
# generate dummy validation data
x_val = np.random.random((100, timesteps, data_dim))
y_val = np.random.random((100, nb_classes))
model.fit(x_train, y_train,
batch_size=64, nb_epoch=5,
validation_data=(x_val, y_val))
```
### Same stacked LSTM model, rendered "stateful"
A stateful recurrent model is one for which the internal states (memories) obtained after processing a batch
of samples are reused as initial states for the samples of the next batch. This allows to process longer sequences
while keeping computational complexity manageable.
[You can read more about stateful RNNs in the FAQ.](/faq/#how-can-i-use-stateful-rnns)
```python
from keras.models import Sequential
from keras.layers import LSTM, Dense
import numpy as np
data_dim = 16
timesteps = 8
nb_classes = 10
batch_size = 32
# expected input batch shape: (batch_size, timesteps, data_dim)
# note that we have to provide the full batch_input_shape since the network is stateful.
# the sample of index i in batch k is the follow-up for the sample i in batch k-1.
model = Sequential()
model.add(LSTM(32, return_sequences=True, stateful=True,
batch_input_shape=(batch_size, timesteps, data_dim)))
model.add(LSTM(32, return_sequences=True, stateful=True))
model.add(LSTM(32, stateful=True))
model.add(Dense(10, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# generate dummy training data
x_train = np.random.random((batch_size * 10, timesteps, data_dim))
y_train = np.random.random((batch_size * 10, nb_classes))
# generate dummy validation data
x_val = np.random.random((batch_size * 3, timesteps, data_dim))
y_val = np.random.random((batch_size * 3, nb_classes))
model.fit(x_train, y_train,
batch_size=batch_size, nb_epoch=5,
validation_data=(x_val, y_val))
```
### Two merged LSTM encoders for classification over two parallel sequences
In this model, two input sequences are encoded into vectors by two separate LSTM modules.
These two vectors are then concatenated, and a fully connected network is trained on top of the concatenated representations.
<img src="http://keras.io/img/dual_lstm.png" alt="Dual LSTM" style="width: 600px;"/>
```python
from keras.models import Sequential
from keras.layers import Merge, LSTM, Dense
import numpy as np
data_dim = 16
timesteps = 8
nb_classes = 10
encoder_a = Sequential()
encoder_a.add(LSTM(32, input_shape=(timesteps, data_dim)))
encoder_b = Sequential()
encoder_b.add(LSTM(32, input_shape=(timesteps, data_dim)))
decoder = Sequential()
decoder.add(Merge([encoder_a, encoder_b], mode='concat'))
decoder.add(Dense(32, activation='relu'))
decoder.add(Dense(nb_classes, activation='softmax'))
decoder.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# generate dummy training data
x_train_a = np.random.random((1000, timesteps, data_dim))
x_train_b = np.random.random((1000, timesteps, data_dim))
y_train = np.random.random((1000, nb_classes))
# generate dummy validation data
x_val_a = np.random.random((100, timesteps, data_dim))
x_val_b = np.random.random((100, timesteps, data_dim))
y_val = np.random.random((100, nb_classes))
decoder.fit([x_train_a, x_train_b], y_train,
batch_size=64, nb_epoch=5,
validation_data=([x_val_a, x_val_b], y_val))
```
+12 -14
Ver Arquivo
@@ -33,11 +33,12 @@ Keras is compatible with: __Python 2.7-3.5__.
------------------
## 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`](http://keras.io/models/#sequential) and [`Graph`](http://keras.io/models/#graph).
The core data structure of Keras is a __model__, a way to organize layers. The main type of model is the [`Sequential`](http://keras.io/getting-started/sequential-model-guide) model, a linear stack of layers. For more complex architectures, you should use the [Keras function API](http://keras.io/getting-started/functional-api-guide).
Here's the `Sequential` model (a linear pile of layers):
Here's the `Sequential` model:
```python
from keras.models import Sequential
@@ -50,15 +51,15 @@ 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(Dense(output_dim=64, input_dim=100))
model.add(Activation("relu"))
model.add(Dense(output_dim=10, init="glorot_uniform"))
model.add(Dense(output_dim=10))
model.add(Activation("softmax"))
```
Once your model looks good, configure its learning process with `.compile()`:
```python
model.compile(loss='categorical_crossentropy', optimizer='sgd')
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
```
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).
@@ -79,7 +80,7 @@ model.train_on_batch(X_batch, Y_batch)
Evaluate your performance in one line:
```python
objective_score = model.evaluate(X_test, Y_test, batch_size=32)
loss_and_metrics = model.evaluate(X_test, Y_test, batch_size=32)
```
Or generate predictions on new data:
@@ -88,12 +89,14 @@ classes = model.predict_classes(X_test, batch_size=32)
proba = model.predict_proba(X_test, batch_size=32)
```
Building a network of LSTMs, a deep CNN, a 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?
Building a question answering system, an image classification model, 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 these [starter examples](http://keras.io/examples/).
For a more in-depth tutorial about Keras, you can check out:
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repo, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, neural turing machines, etc.
- [Getting started with the Sequential model](http://keras.io/getting-started/sequential-model-guide)
- [Getting started with the functional API](http://keras.io/getting-started/functional-api-guide)
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repository, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, etc.
------------------
@@ -112,11 +115,6 @@ Keras uses the following dependencies:
- 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
+27
Ver Arquivo
@@ -0,0 +1,27 @@
# About Keras layers
All Keras layers have a number of methods in common:
- `layer.get_weights()`: returns the weights of the layer as a list of Numpy arrays.
- `layer.set_weights(weights)`: sets the weights of the layer from a list of Numpy arrays (with the same shapes as the output of `get_weights`).
- `layer.get_config()`: returns a dictionary containing the configuration of the layer. The layer can be reinstantiated from its config via:
```python
from keras.utils.layer_utils import layer_from_config
config = layer.get_config()
layer = layer_from_config(config)
```
If a layer has a single node (i.e. if it isn't a shared layer), you can get its input tensor, output tensor, input shape and output shape via:
- `layer.input`
- `layer.output`
- `layer.input_shape`
- `layer.output_shape`
If the layer has multiple nodes (see: [the concept of layer node and shared layers](/getting-started/functional-api-guide/#the-concept-of-layer-node)), you can use the following methods:
- `layer.get_input_at(node_index)`
- `layer.get_output_at(node_index)`
- `layer.get_input_shape_at(node_index)`
- `layer.get_output_shape_at(node_index)`
-114
Ver Arquivo
@@ -1,114 +0,0 @@
Keras has two models: __Sequential__, a linear stack of layers, and __Graph__, a directed acyclic graph of layers.
# Using the Sequential model
```python
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.optimizers import SGD
model = Sequential()
model.add(Dense(2, init='uniform', input_dim=64))
model.add(Activation('softmax'))
model.compile(optimizer='sgd', loss='mse')
'''
Train the model for 3 epochs, in batches of 16 samples,
on data stored in the Numpy array X_train,
and labels stored in the Numpy array y_train:
'''
model.fit(X_train, y_train, nb_epoch=3, batch_size=16, verbose=1)
'''
What you will see with mode verbose=1:
Train on 37800 samples, validate on 4200 samples
Epoch 0
37800/37800 [==============================] - 7s - loss: 0.0385
Epoch 1
37800/37800 [==============================] - 8s - loss: 0.0140
Epoch 2
10960/37800 [=======>......................] - ETA: 4s - loss: 0.0109
'''
model.fit(X_train, y_train, nb_epoch=3, batch_size=16, verbose=2)
'''
What you will see with mode verbose=2:
Train on 37800 samples, validate on 4200 samples
Epoch 0
loss: 0.0190
Epoch 1
loss: 0.0146
Epoch 2
loss: 0.0049
'''
'''
Demonstration of the show_accuracy argument
'''
model.fit(X_train, y_train, nb_epoch=3, batch_size=16, verbose=2, show_accuracy=True)
'''
Train on 37800 samples, validate on 4200 samples
Epoch 0
loss: 0.0190 - acc.: 0.8750
Epoch 1
loss: 0.0146 - acc.: 0.8750
Epoch 2
loss: 0.0049 - acc.: 1.0000
'''
'''
Demonstration of the validation_split argument
'''
model.fit(X_train, y_train, nb_epoch=3, batch_size=16,
validation_split=0.1, show_accuracy=True, verbose=1)
'''
Train on 37800 samples, validate on 4200 samples
Epoch 0
37800/37800 [==============================] - 7s - loss: 0.0385 - acc.: 0.7258 - val. loss: 0.0160 - val. acc.: 0.9136
Epoch 1
37800/37800 [==============================] - 8s - loss: 0.0140 - acc.: 0.9265 - val. loss: 0.0109 - val. acc.: 0.9383
Epoch 2
10960/37800 [=======>......................] - ETA: 4s - loss: 0.0109 - acc.: 0.9420
'''
```
# Using the Graph model
```python
# graph model with one input and two outputs
graph = Graph()
graph.add_input(name='input', input_shape=(32,))
graph.add_node(Dense(16), name='dense1', input='input')
graph.add_node(Dense(4), name='dense2', input='input')
graph.add_node(Dense(4), name='dense3', input='dense1')
graph.add_output(name='output1', input='dense2')
graph.add_output(name='output2', input='dense3')
graph.compile(optimizer='rmsprop', loss={'output1':'mse', 'output2':'mse'})
history = graph.fit({'input':X_train, 'output1':y_train, 'output2':y2_train}, nb_epoch=10)
```
```python
# graph model with two inputs and one output
graph = Graph()
graph.add_input(name='input1', input_shape=(32,))
graph.add_input(name='input2', input_shape=(32,))
graph.add_node(Dense(16), name='dense1', input='input1')
graph.add_node(Dense(4), name='dense2', input='input2')
graph.add_node(Dense(4), name='dense3', input='dense1')
graph.add_output(name='output', inputs=['dense2', 'dense3'], merge_mode='sum')
graph.compile(optimizer='rmsprop', loss={'output':'mse'})
history = graph.fit({'input1':X_train, 'input2':X2_train, 'output':y_train}, nb_epoch=10)
predictions = graph.predict({'input1':X_test, 'input2':X2_test}) # {'output':...}
```
----
# Model API documentation
{{autogenerated}}
+33
Ver Arquivo
@@ -0,0 +1,33 @@
# About Keras models
There are two types of models available in Keras: [the Sequential model](/models/sequential) and [the Model class used with functional API](/models/model).
These models have a number of methods in common:
- `model.summary()`: prints a summary representation of your model.
- `model.get_config()`: returns a dictionary containing the configuration of the model. The model can be reinstantiated from its config via:
```python
config = model.get_config()
model = Model.from_config(config)
# or, for Sequential:
model = Sequential.from_config(config)
```
- `model.get_weights()`: returns a list of all weight tensors in the model, as Numpy arrays.
- `model.set_weights(weights)`: sets the values of the weights of the model, from a list of Numpy arrays. The arrays in the list should have the same shape as those returned by `get_weights()`.
- `model.to_json()`: returns a representation of the model as a JSON string. Note that the representation does not include the weights, only the architecture. You can reinstantiate the same model (with reinitialized weights) from the JSON string via:
```python
from models import model_from_json
json_string = model.to_json()
model = model_from_json(json_string)
```
- `model.to_yaml()`: returns a representation of the model as a YAML string. Note that the representation does not include the weights, only the architecture. You can reinstantiate the same model (with reinitialized weights) from the YAML string via:
```python
from models import model_from_yaml
yaml_string = model.to_yaml()
model = model_from_yaml(yaml_string)
```
- `model.save_weights(filepath)`: saves the weights of the model as a HDF5 file.
- `model.load_weights(filepath)`: loads the weights of the model from a HDF5 file (created by `save_weights`).
+32
Ver Arquivo
@@ -0,0 +1,32 @@
# Model class API
In the functional API, given an input tensor and output tensor, you can instantiate a `Model` via:
```python
from keras.models import Model
from keras.layers import Input, Dense
a = Input(shape=(32,))
b = Dense(32)(a)
model = Model(input=a, output=b)
```
This model will include all layers required in the computation of `a` given `b`.
In the case of multi-input or multi-output models, you can use lists as well:
```python
model = Model(input=[a1, a2], output=[b1, b3, b3])
```
For a detailed introduction of what `Model` can do, read [this guide to the Keras functional API](/getting-started/functional-api-guide).
## Useful attributes of Model
- `model.layers` is a flattened list of the layers comprising the model graph.
- `model.inputs` is the list of input tensors.
- `model.outputs` is the list of output tensors.
## Methods
{{autogenerated}}
+14
Ver Arquivo
@@ -0,0 +1,14 @@
# The Sequential model API
To get started, read [this guide to the Keras Sequential model](/getting-started/sequential-model-guide).
## Useful attributes of Model
- `model.layers` is a list of the layers added to the model.
----
## Sequential model methods
{{autogenerated}}
+5 -4
Ver Arquivo
@@ -7,10 +7,10 @@ An objective function (or loss function, or optimization score function) is one
model.compile(loss='mean_squared_error', optimizer='sgd')
```
You can either pass the name of an existing objective, or pass a Theano symbolic function that returns a scalar for each data-point and takes the following two arguments:
You can either pass the name of an existing objective, or pass a Theano/TensorFlow symbolic function that returns a scalar for each data-point and takes the following two arguments:
- __y_true__: True labels. Theano tensor.
- __y_pred__: Predictions. Theano tensor of the same shape as y_true.
- __y_true__: True labels. Theano/TensorFlow tensor.
- __y_pred__: Predictions. Theano/TensorFlow tensor of the same shape as y_true.
The actual optimized objective is the mean of the output array across all datapoints.
@@ -19,7 +19,6 @@ 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__
@@ -27,3 +26,5 @@ For a few examples of such functions, check out the [objectives source](https://
- __hinge__
- __binary_crossentropy__: Also known as logloss.
- __categorical_crossentropy__: Also known as multiclass logloss. __Note__: using this objective requires that your labels are binary arrays of shape `(nb_samples, nb_classes)`.
- __poisson__: mean of `(predictions - targets * log(predictions))`
- __cosine_proximity__: the opposite (negative) of the mean cosine proximity between predictions and targets.
+21 -9
Ver Arquivo
@@ -10,11 +10,12 @@ keras.preprocessing.image.ImageDataGenerator(featurewise_center=True,
rotation_range=0.,
width_shift_range=0.,
height_shift_range=0.,
shear_range=0.,
horizontal_flip=False,
vertical_flip=False)
```
Generate batches of tensor image data with real-time data augmentation.
Generate batches of tensor image data with real-time data augmentation. The data will be looped over (in batches) indefinitely.
- __Arguments__:
- __featurewise_center__: Boolean. Set input mean to 0 over the dataset.
@@ -25,24 +26,25 @@ Generate batches of tensor image data with real-time data augmentation.
- __rotation_range__: Int. Degree range for random rotations.
- __width_shift_range__: Float (fraction of total width). Range for random horizontal shifts.
- __height_shift_range__: Float (fraction of total height). Range for random vertical shifts.
- __shear_range__: Float. Shear Intensity (Shear angle in counter-clockwise direction as radians)
- __horizontal_flip__: Boolean. Randomly flip inputs horizontally.
- __vertical_flip__: Boolean. Randomly flip inputs vertically.
- __Methods__:
- __fit(X)__: Required if featurewise_center or featurewise_std_normalization or zca_whitening. Compute necessary quantities on some sample data.
- __Arguments__:
- __Arguments__:
- __X__: sample data.
- __augment__: Boolean (default: False). Whether to fit on randomly augmented samples.
- __rounds__: int (default: 1). If augment, how many augmentation passes over the data to use.
- __flow(X, y)__:
- __Arguments__:
- __Arguments__:
- __X__: data.
- __y__: labels.
- __batch_size__: int (default: 32).
- __shuffle__: boolean (defaut: False).
- __save_to_dir__: None or str. This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
- __save_to_dir__: None or str. This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
- __save_prefix__: str. Prefix to use for filenames of saved pictures.
- __save_format__: one of "png", jpeg".
- __save_format__: one of "png", jpeg".
- __Example__:
```python
@@ -58,13 +60,23 @@ datagen = ImageDataGenerator(
height_shift_range=0.2,
horizontal_flip=True)
# compute quantities required for featurewise normalization
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(X_train)
# fits the model on batches with real-time data augmentation:
model.fit_generator(datagen.flow(X_train, Y_train, batch_size=32),
samples_per_epoch=len(X_train), nb_epoch=nb_epoch)
# here's a more "manual" example
for e in range(nb_epoch):
print 'Epoch', e
# batch train with realtime data augmentation
for X_batch, Y_batch in datagen.flow(X_train, Y_train):
batches = 0
for X_batch, Y_batch in datagen.flow(X_train, Y_train, batch_size=32):
loss = model.train(X_batch, Y_batch)
```
batches += 1
if batches >= len(X_train) / 32:
# we need to break the loop by hand because
# the generator loops indefinitely
break
```
+3
Ver Arquivo
@@ -12,6 +12,9 @@ Transform a list of `nb_samples sequences` (lists of scalars) into a 2D numpy ar
- __sequences__: List of lists of int or float.
- __maxlen__: None or int. Maximum sequence length, longer sequences are truncated and shorter sequences are padded with zeros at the end.
- __dtype__: datatype of the numpy array returned.
- __padding__: 'pre' or 'post', pad either before or after each sequence.
- __truncating__: 'pre' or 'post', remove values from sequences larger than maxlen either in the beginning or in the end of the sequence
- __value__: float, value to pad the sequences to the desired value.
---
+45
Ver Arquivo
@@ -0,0 +1,45 @@
# Wrappers for the Sciki-Learn API
You can use `Sequential` Keras models (single-input only) as part of your Scikit-Learn workflow via the wrappers found at `keras.wrappers.sklearn.py`.
There are two wrappers available:
`keras.wrappers.sklearn.KerasClassifier(build_fn=None, **sk_params)`, which implements the sklearn classifier interface,
`keras.wrappers.sklearn.KerasRegressor(build_fn=None, **sk_params)`, which implements the sklearn regressor interface.
### Arguments
- __build_fn__: callable function or class instance
- __sk_params__: model parameters & fitting parameters
`build_fn` should construct, compile and return a Keras model, which
will then be used to fit/predict. One of the following
three values could be passed to build_fn:
1. A function
2. An instance of a class that implements the __call__ method
3. None. This means you implement a class that inherits from either
`KerasClassifier` or `KerasRegressor`. The __call__ method of the
present class will then be treated as the default build_fn.
`sk_params` takes both model parameters and fitting parameters. Legal model
parameters are the arguments of `build_fn`. Note that like all other
estimators in scikit-learn, 'build_fn' should provide defalult values for
its arguments, so that you could create the estimator without passing any
values to `sk_params`.
`sk_params` could also accept parameters for calling `fit`, `predict`,
`predict_proba`, and `score` methods (e.g., `nb_epoch`, `batch_size`).
fitting (predicting) parameters are selected in the following order:
1. Values passed to the dictionary arguments of
`fit`, `predict`, `predict_proba`, and `score` methods
2. Values passed to `sk_params`
3. The default values of the `keras.models.Sequential`
`fit`, `predict`, `predict_proba` and `score` methods
When using scikit-learn's `grid_search` API, legal tunable parameters are
those you could pass to `sk_params`, including fitting parameters.
In other words, you could use `grid_search` to search for the best
`batch_size` or `nb_epoch` as well as the model parameters.
+6 -2
Ver Arquivo
@@ -10,11 +10,15 @@ from keras.utils.visualize_util import plot
plot(model, to_file='model.png')
```
`plot` takes one optional arguments:
- `show_shapes` (defaults to False) controls whether output shapes are shown in the graph.
You can also directly obtain the `pydot.Graph` object and render it yourself,
for example to show it in an ipython notebook :
```python
from IPython.display import SVG
from keras.utils.visualize_util import to_graph
from keras.utils.visualize_util import model_to_dot
SVG(to_graph(model).create(prog='dot', format='svg'))
SVG(model_to_dot(model).create(prog='dot', format='svg'))
```
+6 -3
Ver Arquivo
@@ -27,7 +27,8 @@ Five digits inverted:
'''
from __future__ import print_function
from keras.models import Sequential, slice_X
from keras.models import Sequential
from keras.engine.training import slice_X
from keras.layers.core import Activation, TimeDistributedDense, RepeatVector
from keras.layers import recurrent
import numpy as np
@@ -142,7 +143,9 @@ for _ in range(LAYERS):
model.add(TimeDistributedDense(len(chars)))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
# Train the model each generation and show predictions against the validation dataset
for iteration in range(1, 200):
@@ -150,7 +153,7 @@ for iteration in range(1, 200):
print('-' * 50)
print('Iteration', iteration)
model.fit(X_train, y_train, batch_size=BATCH_SIZE, nb_epoch=1,
validation_data=(X_val, y_val), show_accuracy=True)
validation_data=(X_val, y_val))
###
# Select 10 samples from the validation set at random so we can visualize errors
for i in range(10):
+104
Ver Arquivo
@@ -0,0 +1,104 @@
'''The example demonstrates how to write custom layers for Keras.
We build a custom activation layer called 'Antirectifier',
which modifies the shape of the tensor that passes through it.
We need to specify two methods: `output_shape` and `get_output`.
Note that the same result can also be achieved via a Lambda layer.
Because our custom layer is written with primitives from the Keras
backend (`K`), our code can run both on TensorFlow and Theano.
'''
from __future__ import print_function
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Layer, Activation
from keras.datasets import mnist
from keras import backend as K
from keras.utils import np_utils
class Antirectifier(Layer):
'''This is the combination of a sample-wise
L2 normalization with the concatenation of the
positive part of the input with the negative part
of the input. The result is a tensor of samples that are
twice as large as the input samples.
It can be used in place of a ReLU.
# Input shape
2D tensor of shape (samples, n)
# Output shape
2D tensor of shape (samples, 2*n)
# Theoretical justification
When applying ReLU, assuming that the distribution
of the previous output is approximately centered around 0.,
you are discarding half of your input. This is inefficient.
Antirectifier allows to return all-positive outputs like ReLU,
without discarding any data.
Tests on MNIST show that Antirectifier allows to train networks
with twice less parameters yet with comparable
classification accuracy as an equivalent ReLU-based network.
'''
def get_output_shape_for(self, input_shape):
shape = list(input_shape)
assert len(shape) == 2 # only valid for 2D tensors
shape[-1] *= 2
return tuple(shape)
def call(self, x, mask=None):
x -= K.mean(x, axis=1, keepdims=True)
x = K.l2_normalize(x, axis=1)
pos = K.relu(x)
neg = K.relu(-x)
return K.concatenate([pos, neg], axis=1)
# global parameters
batch_size = 128
nb_classes = 10
nb_epoch = 40
# the data, shuffled and split between train and test sets
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(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
print(X_train.shape[0], 'train samples')
print(X_test.shape[0], 'test samples')
# convert class vectors to binary class matrices
Y_train = np_utils.to_categorical(y_train, nb_classes)
Y_test = np_utils.to_categorical(y_test, nb_classes)
# build the model
model = Sequential()
model.add(Dense(256, input_shape=(784,)))
model.add(Antirectifier())
model.add(Dropout(0.1))
model.add(Dense(256))
model.add(Antirectifier())
model.add(Dropout(0.1))
model.add(Dense(10))
model.add(Activation('softmax'))
# compile the model
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
# train the model
model.fit(X_train, Y_train,
batch_size=batch_size, nb_epoch=nb_epoch,
verbose=1, validation_data=(X_test, Y_test))
# next, compare with an equivalent network
# with2x bigger Dense layers and ReLU
+5 -5
Ver Arquivo
@@ -1,4 +1,4 @@
'''Train a memory network on the bAbI dataset.
'''Trains a memory network on the bAbI dataset.
References:
- Jason Weston, Antoine Bordes, Sumit Chopra, Tomas Mikolov, Alexander M. Rush,
@@ -18,7 +18,7 @@ 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.utils.data_utils import get_file
from keras.preprocessing.sequence import pad_sequences
from functools import reduce
import tarfile
@@ -167,7 +167,7 @@ question_encoder.add(Dropout(0.3))
match = Sequential()
match.add(Merge([input_encoder_m, question_encoder],
mode='dot',
dot_axes=[(2,), (2,)]))
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()
@@ -195,10 +195,10 @@ answer.add(Dense(vocab_size))
# we output a probability distribution over the vocabulary
answer.add(Activation('softmax'))
answer.compile(optimizer='rmsprop', loss='categorical_crossentropy')
answer.compile(optimizer='rmsprop', loss='categorical_crossentropy',
metrics=['accuracy'])
# 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=120,
show_accuracy=True,
validation_data=([inputs_test, queries_test, inputs_test], answers_test))
+24 -16
Ver Arquivo
@@ -7,8 +7,8 @@ http://arxiv.org/abs/1502.05698
Task Number | FB LSTM Baseline | Keras QA
--- | --- | ---
QA1 - Single Supporting Fact | 50 | 52.1
QA2 - Two Supporting Facts | 20 | 37.0
QA1 - Single Supporting Fact | 50 | 100.0
QA2 - Two Supporting Facts | 20 | 50.0
QA3 - Three Supporting Facts | 20 | 20.5
QA4 - Two Arg. Relations | 61 | 62.9
QA5 - Three Arg. Relations | 70 | 61.9
@@ -34,8 +34,8 @@ https://research.facebook.com/researchers/1543934539189348
Notes:
- With default word, sentence, and query vector sizes, the GRU model achieves:
- 52.1% test accuracy on QA1 in 20 epochs (2 seconds per epoch on CPU)
- 37.0% test accuracy on QA2 in 20 epochs (16 seconds per epoch on CPU)
- 100% test accuracy on QA1 in 20 epochs (2 seconds per epoch on CPU)
- 50% test accuracy on QA2 in 20 epochs (16 seconds per epoch on CPU)
In comparison, the Facebook paper achieves 50% and 20% for the LSTM baseline.
- The task does not traditionally parse the question separately. This likely
@@ -64,9 +64,9 @@ import tarfile
import numpy as np
np.random.seed(1337) # for reproducibility
from keras.datasets.data_utils import get_file
from keras.utils.data_utils import get_file
from keras.layers.embeddings import Embedding
from keras.layers.core import Dense, Merge
from keras.layers.core import Dense, Merge, Dropout, RepeatVector
from keras.layers import recurrent
from keras.models import Sequential
from keras.preprocessing.sequence import pad_sequences
@@ -138,12 +138,12 @@ def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
Y.append(y)
return pad_sequences(X, maxlen=story_maxlen), pad_sequences(Xq, maxlen=query_maxlen), np.array(Y)
RNN = recurrent.GRU
RNN = recurrent.LSTM
EMBED_HIDDEN_SIZE = 50
SENT_HIDDEN_SIZE = 100
QUERY_HIDDEN_SIZE = 100
BATCH_SIZE = 32
EPOCHS = 20
EPOCHS = 40
print('RNN / Embed / Sent / Query = {}, {}, {}, {}'.format(RNN, EMBED_HIDDEN_SIZE, SENT_HIDDEN_SIZE, QUERY_HIDDEN_SIZE))
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
@@ -178,20 +178,28 @@ print('story_maxlen, query_maxlen = {}, {}'.format(story_maxlen, query_maxlen))
print('Build model...')
sentrnn = Sequential()
sentrnn.add(Embedding(vocab_size, EMBED_HIDDEN_SIZE, mask_zero=True))
sentrnn.add(RNN(SENT_HIDDEN_SIZE, return_sequences=False))
sentrnn.add(Embedding(vocab_size, EMBED_HIDDEN_SIZE,
input_length=story_maxlen))
sentrnn.add(Dropout(0.3))
qrnn = Sequential()
qrnn.add(Embedding(vocab_size, EMBED_HIDDEN_SIZE))
qrnn.add(RNN(QUERY_HIDDEN_SIZE, return_sequences=False))
qrnn.add(Embedding(vocab_size, EMBED_HIDDEN_SIZE,
input_length=query_maxlen))
qrnn.add(Dropout(0.3))
qrnn.add(RNN(EMBED_HIDDEN_SIZE, return_sequences=False))
qrnn.add(RepeatVector(story_maxlen))
model = Sequential()
model.add(Merge([sentrnn, qrnn], mode='concat'))
model.add(Merge([sentrnn, qrnn], mode='sum'))
model.add(RNN(EMBED_HIDDEN_SIZE, return_sequences=False))
model.add(Dropout(0.3))
model.add(Dense(vocab_size, activation='softmax'))
model.compile(optimizer='adam', loss='categorical_crossentropy', class_mode='categorical')
model.compile(optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy'])
print('Training')
model.fit([X, Xq], Y, batch_size=BATCH_SIZE, nb_epoch=EPOCHS, validation_split=0.05, show_accuracy=True)
loss, acc = model.evaluate([tX, tXq], tY, batch_size=BATCH_SIZE, show_accuracy=True)
model.fit([X, Xq], Y, batch_size=BATCH_SIZE, nb_epoch=EPOCHS, validation_split=0.05)
loss, acc = model.evaluate([tX, tXq], tY, batch_size=BATCH_SIZE)
print('Test loss / test accuracy = {:.4f} / {:.4f}'.format(loss, acc))
+23 -32
Ver Arquivo
@@ -17,9 +17,8 @@ from keras.preprocessing.image import ImageDataGenerator
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation, Flatten
from keras.layers.convolutional import Convolution2D, MaxPooling2D
from keras.optimizers import SGD, Adadelta, Adagrad
from keras.utils import np_utils, generic_utils
from six.moves import range
from keras.optimizers import SGD
from keras.utils import np_utils
batch_size = 32
nb_classes = 10
@@ -67,7 +66,9 @@ model.add(Activation('softmax'))
# let's train the model using SGD + momentum (how original).
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
model.compile(loss='categorical_crossentropy', optimizer=sgd)
model.compile(loss='categorical_crossentropy',
optimizer=sgd,
metrics=['accuracy'])
X_train = X_train.astype('float32')
X_test = X_test.astype('float32')
@@ -75,24 +76,25 @@ X_train /= 255
X_test /= 255
if not data_augmentation:
print('Not using data augmentation or normalization')
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)
print('Not using data augmentation.')
model.fit(X_train, Y_train,
batch_size=batch_size,
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test),
shuffle=True)
else:
print('Using real time data augmentation')
print('Using real-time data augmentation.')
# this will do preprocessing and realtime data augmentation
datagen = ImageDataGenerator(
featurewise_center=True, # set input mean to 0 over the dataset
featurewise_center=False, # set input mean to 0 over the dataset
samplewise_center=False, # set each sample mean to 0
featurewise_std_normalization=True, # divide inputs by std of the dataset
featurewise_std_normalization=False, # divide inputs by std of the dataset
samplewise_std_normalization=False, # divide each input by its std
zca_whitening=False, # apply ZCA whitening
rotation_range=20, # randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.2, # randomly shift images horizontally (fraction of total width)
height_shift_range=0.2, # randomly shift images vertically (fraction of total height)
rotation_range=0, # randomly rotate images in the range (degrees, 0 to 180)
width_shift_range=0.1, # randomly shift images horizontally (fraction of total width)
height_shift_range=0.1, # randomly shift images vertically (fraction of total height)
horizontal_flip=True, # randomly flip images
vertical_flip=False) # randomly flip images
@@ -100,20 +102,9 @@ else:
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(X_train)
for e in range(nb_epoch):
print('-'*40)
print('Epoch', e)
print('-'*40)
print('Training...')
# batch train with realtime data augmentation
progbar = generic_utils.Progbar(X_train.shape[0])
for X_batch, Y_batch in datagen.flow(X_train, Y_train):
loss = model.train_on_batch(X_batch, Y_batch)
progbar.add(X_batch.shape[0], values=[('train loss', loss[0])])
print('Testing...')
# test time!
progbar = generic_utils.Progbar(X_test.shape[0])
for X_batch, Y_batch in datagen.flow(X_test, Y_test):
score = model.test_on_batch(X_batch, Y_batch)
progbar.add(X_batch.shape[0], values=[('test loss', score[0])])
# fit the model on the batches generated by datagen.flow()
model.fit_generator(datagen.flow(X_train, Y_train,
batch_size=batch_size),
samples_per_epoch=X_train.shape[0],
nb_epoch=nb_epoch,
validation_data=(X_test, Y_test))
+184
Ver Arquivo
@@ -0,0 +1,184 @@
'''Visualization of the filters of VGG16, via gradient ascent in input space.
This script can run on CPU in a few minutes (with the TensorFlow backend).
Results example: http://i.imgur.com/4nj4KjN.jpg
Before running this script, download the weights for the VGG16 model at:
https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
(source: https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
and make sure the variable `weights_path` in this script matches the location of the file.
'''
from __future__ import print_function
from scipy.misc import imsave
import numpy as np
import time
import os
import h5py
from keras.models import Sequential
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
from keras import backend as K
# dimensions of the generated pictures for each filter.
img_width = 128
img_height = 128
# path to the model weights file.
weights_path = 'vgg16_weights.h5'
# the name of the layer we want to visualize (see model definition below)
layer_name = 'conv5_1'
# util function to convert a tensor into a valid image
def deprocess_image(x):
# normalize tensor: center on 0., ensure std is 0.1
x -= x.mean()
x /= (x.std() + 1e-5)
x *= 0.1
# clip to [0, 1]
x += 0.5
x = np.clip(x, 0, 1)
# convert to RGB array
x *= 255
x = x.transpose((1, 2, 0))
x = np.clip(x, 0, 255).astype('uint8')
return x
# build the VGG16 network
model = Sequential()
model.add(ZeroPadding2D((1, 1), batch_input_shape=(1, 3, img_width, img_height)))
first_layer = model.layers[-1]
# this is a placeholder tensor that will contain our generated images
input_img = first_layer.input
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
# load the weights of the VGG16 networks
# (trained on ImageNet, won the ILSVRC competition in 2014)
# note: when there is a complete match between your model definition
# and your weight savefile, you can simply call model.load_weights(filename)
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
f = h5py.File(weights_path)
for k in range(f.attrs['nb_layers']):
if k >= len(model.layers):
# we don't look at the last (fully-connected) layers in the savefile
break
g = f['layer_{}'.format(k)]
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
model.layers[k].set_weights(weights)
f.close()
print('Model loaded.')
# get the symbolic outputs of each "key" layer (we gave them unique names).
layer_dict = dict([(layer.name, layer) for layer in model.layers])
def normalize(x):
# utility function to normalize a tensor by its L2 norm
return x / (K.sqrt(K.mean(K.square(x))) + 1e-5)
kept_filters = []
for filter_index in range(0, 200):
# we only scan through the first 200 filters,
# but there are actually 512 of them
print('Processing filter %d' % filter_index)
start_time = time.time()
# we build a loss function that maximizes the activation
# of the nth filter of the layer considered
layer_output = layer_dict[layer_name].output
loss = K.mean(layer_output[:, filter_index, :, :])
# we compute the gradient of the input picture wrt this loss
grads = K.gradients(loss, input_img)[0]
# normalization trick: we normalize the gradient
grads = normalize(grads)
# this function returns the loss and grads given the input picture
iterate = K.function([input_img], [loss, grads])
# step size for gradient ascent
step = 1.
# we start from a gray image with some random noise
input_img_data = np.random.random((1, 3, img_width, img_height)) * 20 + 128.
# we run gradient ascent for 20 steps
for i in range(20):
loss_value, grads_value = iterate([input_img_data])
input_img_data += grads_value * step
print('Current loss value:', loss_value)
if loss_value <= 0.:
# some filters get stuck to 0, we can skip them
break
# decode the resulting input image
if loss_value > 0:
img = deprocess_image(input_img_data[0])
kept_filters.append((img, loss_value))
end_time = time.time()
print('Filter %d processed in %ds' % (filter_index, end_time - start_time))
# we will stich the best 64 filters on a 8 x 8 grid.
n = 8
# the filters that have the highest loss are assumed to be better-looking.
# we will only keep the top 64 filters.
kept_filters.sort(key=lambda x: x[1], reverse=True)
kept_filters = kept_filters[:n * n]
# build a black picture with enough space for
# our 8 x 8 filters of size 128 x 128, with a 5px margin in between
margin = 5
width = n * img_width + (n - 1) * margin
height = n * img_height + (n - 1) * margin
stitched_filters = np.zeros((width, height, 3))
# fill the picture with our saved filters
for i in range(n):
for j in range(n):
img, loss = kept_filters[i * n + j]
stitched_filters[(img_width + margin) * i: (img_width + margin) * i + img_width,
(img_height + margin) * j: (img_height + margin) * j + img_height, :] = img
# save the result to disk
imsave('stitched_filters_%dx%d.png' % (n, n), stitched_filters)
+233
Ver Arquivo
@@ -0,0 +1,233 @@
'''Deep Dreaming in Keras.
Run the script with:
```
python deep_dream.py path_to_your_base_image.jpg prefix_for_results
```
e.g.:
```
python deep_dream.py img/mypic.jpg results/dream
```
It is preferrable to run this script on GPU, for speed.
If running on CPU, prefer the TensorFlow backend (much faster).
Example results: http://i.imgur.com/FX6ROg9.jpg
'''
from __future__ import print_function
from scipy.misc import imread, imresize, imsave
import numpy as np
from scipy.optimize import fmin_l_bfgs_b
import time
import argparse
import h5py
import os
from keras.models import Sequential
from keras.layers.convolutional import Convolution2D, ZeroPadding2D, MaxPooling2D
from keras import backend as K
parser = argparse.ArgumentParser(description='Deep Dreams with Keras.')
parser.add_argument('base_image_path', metavar='base', type=str,
help='Path to the image to transform.')
parser.add_argument('result_prefix', metavar='res_prefix', type=str,
help='Prefix for the saved results.')
args = parser.parse_args()
base_image_path = args.base_image_path
result_prefix = args.result_prefix
# dimensions of the generated picture.
img_width = 600
img_height = 600
# path to the model weights file.
weights_path = 'vgg16_weights.h5'
# some settings we found interesting
saved_settings = {
'bad_trip': {'features': {'conv4_1': 0.05,
'conv4_2': 0.01,
'conv4_3': 0.01},
'continuity': 0.1,
'dream_l2': 0.8,
'jitter': 5},
'dreamy': {'features': {'conv5_1': 0.05,
'conv5_2': 0.02},
'continuity': 0.1,
'dream_l2': 0.02,
'jitter': 0},
}
# the settings we will use in this experiment
settings = saved_settings['dreamy']
# util function to open, resize and format pictures into appropriate tensors
def preprocess_image(image_path):
img = imresize(imread(image_path), (img_width, img_height))
img = img.transpose((2, 0, 1)).astype('float64')
img = np.expand_dims(img, axis=0)
return img
# util function to convert a tensor into a valid image
def deprocess_image(x):
x = x.transpose((1, 2, 0))
x = np.clip(x, 0, 255).astype('uint8')
return x
# build the VGG16 network
model = Sequential()
model.add(ZeroPadding2D((1, 1), batch_input_shape=(1, 3, img_width, img_height)))
first_layer = model.layers[-1]
# this is a placeholder tensor that will contain our generated images
dream = first_layer.input
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
# load the weights of the VGG16 networks
# (trained on ImageNet, won the ILSVRC competition in 2014)
# note: when there is a complete match between your model definition
# and your weight savefile, you can simply call model.load_weights(filename)
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
f = h5py.File(weights_path)
for k in range(f.attrs['nb_layers']):
if k >= len(model.layers):
# we don't look at the last (fully-connected) layers in the savefile
break
g = f['layer_{}'.format(k)]
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
model.layers[k].set_weights(weights)
f.close()
print('Model loaded.')
# get the symbolic outputs of each "key" layer (we gave them unique names).
layer_dict = dict([(layer.name, layer) for layer in model.layers])
# continuity loss util function
def continuity_loss(x):
assert K.ndim(x) == 4
a = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, 1:, :img_height-1])
b = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, :img_width-1, 1:])
return K.sum(K.pow(a + b, 1.25))
# define the loss
loss = K.variable(0.)
for layer_name in settings['features']:
# add the L2 norm of the features of a layer to the loss
assert layer_name in layer_dict.keys(), 'Layer ' + layer_name + ' not found in model.'
coeff = settings['features'][layer_name]
x = layer_dict[layer_name].output
shape = layer_dict[layer_name].output_shape
# we avoid border artifacts by only involving non-border pixels in the loss
loss -= coeff * K.sum(K.square(x[:, :, 2: shape[2]-2, 2: shape[3]-2])) / np.prod(shape[1:])
# add continuity loss (gives image local coherence, can result in an artful blur)
loss += settings['continuity'] * continuity_loss(dream) / (3 * img_width * img_height)
# add image L2 norm to loss (prevents pixels from taking very high values, makes image darker)
loss += settings['dream_l2'] * K.sum(K.square(dream)) / (3 * img_width * img_height)
# feel free to further modify the loss as you see fit, to achieve new effects...
# compute the gradients of the dream wrt the loss
grads = K.gradients(loss, dream)
outputs = [loss]
if type(grads) in {list, tuple}:
outputs += grads
else:
outputs.append(grads)
f_outputs = K.function([dream], outputs)
def eval_loss_and_grads(x):
x = x.reshape((1, 3, img_width, img_height))
outs = f_outputs([x])
loss_value = outs[0]
if len(outs[1:]) == 1:
grad_values = outs[1].flatten().astype('float64')
else:
grad_values = np.array(outs[1:]).flatten().astype('float64')
return loss_value, grad_values
# this Evaluator class makes it possible
# to compute loss and gradients in one pass
# while retrieving them via two separate functions,
# "loss" and "grads". This is done because scipy.optimize
# requires separate functions for loss and gradients,
# but computing them separately would be inefficient.
class Evaluator(object):
def __init__(self):
self.loss_value = None
self.grads_values = None
def loss(self, x):
assert self.loss_value is None
loss_value, grad_values = eval_loss_and_grads(x)
self.loss_value = loss_value
self.grad_values = grad_values
return self.loss_value
def grads(self, x):
assert self.loss_value is not None
grad_values = np.copy(self.grad_values)
self.loss_value = None
self.grad_values = None
return grad_values
evaluator = Evaluator()
# run scipy-based optimization (L-BFGS) over the pixels of the generated image
# so as to minimize the loss
x = preprocess_image(base_image_path)
for i in range(5):
print('Start of iteration', i)
start_time = time.time()
# add a random jitter to the initial image. This will be reverted at decoding time
random_jitter = (settings['jitter'] * 2) * (np.random.random((3, img_width, img_height)) - 0.5)
x += random_jitter
# run L-BFGS for 7 steps
x, min_val, info = fmin_l_bfgs_b(evaluator.loss, x.flatten(),
fprime=evaluator.grads, maxfun=7)
print('Current loss value:', min_val)
# decode the dream and save it
x = x.reshape((3, img_width, img_height))
x -= random_jitter
img = deprocess_image(x)
fname = result_prefix + '_at_iteration_%d.png' % i
imsave(fname, img)
end_time = time.time()
print('Image saved as', fname)
print('Iteration %d completed in %ds' % (i, end_time - start_time))
+24 -25
Ver Arquivo
@@ -1,8 +1,5 @@
'''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.
'''
@@ -12,11 +9,8 @@ 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.models import Model
from keras.layers import Dense, Dropout, Embedding, LSTM, Input, merge
from keras.datasets import imdb
@@ -38,25 +32,30 @@ 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')
# this is the placeholder tensor for the input sequences
sequence = Input(shape=(maxlen,), dtype='int32')
# this embedding layer will transform the sequences of integers
# into vectors of size 128
embedded = Embedding(max_features, 128, input_length=maxlen)(sequence)
# apply forwards LSTM
forwards = LSTM(64)(embedded)
# apply backwards LSTM
backwards = LSTM(64, go_backwards=True)(embedded)
# concatenate the outputs of the 2 LSTMs
merged = merge([forwards, backwards], mode='concat', concat_axis=-1)
after_dp = Dropout(0.5)(merged)
output = Dense(1, activation='sigmoid')(after_dp)
model = Model(input=sequence, output=output)
# try using different optimizers and different optimizer configs
model.compile('adam', {'output': 'binary_crossentropy'})
model.compile('adam', 'binary_crossentropy', metrics=['accuracy'])
print('Train...')
model.fit({'input': X_train, 'output': y_train},
model.fit(X_train, 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)
nb_epoch=4,
validation_data=[X_test, y_test])
+5 -6
Ver Arquivo
@@ -1,8 +1,6 @@
'''This example demonstrates the use of Convolution1D for text classification.
Run on GPU: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python imdb_cnn.py
Get to 0.835 test accuracy after 2 epochs. 100s/epoch on K520 GPU.
Gets to 0.835 test accuracy after 2 epochs. 100s/epoch on K520 GPU.
'''
from __future__ import print_function
@@ -72,7 +70,8 @@ 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,
metrics=['accuracy'])
model.fit(X_train, y_train,
batch_size=batch_size,
nb_epoch=nb_epoch,
validation_data=(X_test, y_test))
+4 -9
Ver Arquivo
@@ -1,12 +1,8 @@
'''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.
Gets to 0.8498 test accuracy after 2 epochs. 41s/epoch on K520 GPU.
'''
from __future__ import print_function
import numpy as np
np.random.seed(1337) # for reproducibility
@@ -71,12 +67,11 @@ model.add(Activation('sigmoid'))
model.compile(loss='binary_crossentropy',
optimizer='adam',
class_mode='binary')
metrics=['accuracy'])
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)
validation_data=(X_test, y_test))
score, acc = model.evaluate(X_test, y_test, batch_size=batch_size)
print('Test score:', score)
print('Test accuracy:', acc)
+13 -17
Ver Arquivo
@@ -1,4 +1,4 @@
'''Train a LSTM on the IMDB sentiment classification task.
'''Trains a LSTM on the IMDB sentiment classification task.
The dataset is actually too small for LSTM to be of any advantage
compared to simpler, much faster methods such as TF-IDF+LogReg.
@@ -11,11 +11,7 @@ Some configurations won't converge.
- LSTM loss decrease patterns during training can be quite different
from what you see with CNNs/MLPs/etc.
GPU command:
THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python imdb_lstm.py
'''
from __future__ import print_function
import numpy as np
np.random.seed(1337) # for reproducibility
@@ -25,11 +21,11 @@ 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
from keras.layers.recurrent import LSTM, SimpleRNN, GRU
from keras.datasets import imdb
max_features = 20000
maxlen = 100 # cut texts after this number of words (among top max_features most common words)
maxlen = 80 # cut texts after this number of words (among top max_features most common words)
batch_size = 32
print('Loading data...')
@@ -38,7 +34,7 @@ print('Loading data...')
print(len(X_train), 'train sequences')
print(len(X_test), 'test sequences')
print("Pad sequences (samples x time)")
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)
@@ -46,22 +42,22 @@ print('X_test shape:', X_test.shape)
print('Build model...')
model = Sequential()
model.add(Embedding(max_features, 128, input_length=maxlen))
model.add(LSTM(128)) # try using a GRU instead, for fun
model.add(Dropout(0.5))
model.add(Embedding(max_features, 128, input_length=maxlen, dropout=0.2))
model.add(LSTM(128, dropout_W=0.2, dropout_U=0.2)) # try using a GRU instead, for fun
model.add(Dense(1))
model.add(Activation('sigmoid'))
# try using different optimizers and different optimizer configs
model.compile(loss='binary_crossentropy',
optimizer='adam',
class_mode="binary")
metrics=['accuracy'])
print("Train...")
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=3,
validation_data=(X_test, y_test), show_accuracy=True)
print('Train...')
print(X_train.shape)
print(y_train.shape)
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=15,
validation_data=(X_test, y_test))
score, acc = model.evaluate(X_test, y_test,
batch_size=batch_size,
show_accuracy=True)
batch_size=batch_size)
print('Test score:', score)
print('Test accuracy:', acc)
-121
Ver Arquivo
@@ -1,121 +0,0 @@
'''This demonstrates how to reach a score of 0.4890 (local validation)
on the Kaggle Otto challenge, with a deep net using Keras.
Requires Scikit-Learn and Pandas.
Recommended to run on GPU:
Command: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python kaggle_otto_nn.py
On EC2 g2.2xlarge instance: 19s/epoch. 6-7 minutes total training time.
Best validation score at epoch 21: 0.4881
Try it at home:
- with/without BatchNormalization (BatchNormalization helps!)
- with ReLU or with PReLU (PReLU helps!)
- with smaller layers, largers layers
- with more layers, less layers
- with different optimizers (SGD+momentum+decay is probably better than Adam!)
Get the data from Kaggle:
https://www.kaggle.com/c/otto-group-product-classification-challenge/data
'''
from __future__ import print_function
import numpy as np
import pandas as pd
np.random.seed(1337) # for reproducibility
from keras.models import Sequential
from keras.layers.core import Dense, Dropout, Activation
from keras.layers.normalization import BatchNormalization
from keras.layers.advanced_activations import PReLU
from keras.utils import np_utils, generic_utils
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import StandardScaler
def load_data(path, train=True):
df = pd.read_csv(path)
X = df.values.copy()
if train:
np.random.shuffle(X) # https://youtu.be/uyUXoap67N8
X, labels = X[:, 1:-1].astype(np.float32), X[:, -1]
return X, labels
else:
X, ids = X[:, 1:].astype(np.float32), X[:, 0].astype(str)
return X, ids
def preprocess_data(X, scaler=None):
if not scaler:
scaler = StandardScaler()
scaler.fit(X)
X = scaler.transform(X)
return X, scaler
def preprocess_labels(labels, encoder=None, categorical=True):
if not encoder:
encoder = LabelEncoder()
encoder.fit(labels)
y = encoder.transform(labels).astype(np.int32)
if categorical:
y = np_utils.to_categorical(y)
return y, encoder
def make_submission(y_prob, ids, encoder, fname):
with open(fname, 'w') as f:
f.write('id,')
f.write(','.join([str(i) for i in encoder.classes_]))
f.write('\n')
for i, probs in zip(ids, y_prob):
probas = ','.join([i] + [str(p) for p in probs.tolist()])
f.write(probas)
f.write('\n')
print('Wrote submission to file {}.'.format(fname))
print('Loading data...')
X, labels = load_data('train.csv', train=True)
X, scaler = preprocess_data(X)
y, encoder = preprocess_labels(labels)
X_test, ids = load_data('test.csv', train=False)
X_test, _ = preprocess_data(X_test, scaler)
nb_classes = y.shape[1]
print(nb_classes, 'classes')
dims = X.shape[1]
print(dims, 'dims')
print('Building model...')
model = Sequential()
model.add(Dense(512, input_shape=(dims,)))
model.add(PReLU())
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(512))
model.add(PReLU())
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(512))
model.add(PReLU())
model.add(BatchNormalization())
model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
print('Training model...')
model.fit(X, y, nb_epoch=20, batch_size=128, validation_split=0.15)
print('Generating submission...')
proba = model.predict_proba(X_test)
make_submission(proba, ids, encoder, fname='keras-otto.csv')
+2 -2
Ver Arquivo
@@ -14,7 +14,7 @@ from __future__ import print_function
from keras.models import Sequential
from keras.layers.core import Dense, Activation, Dropout
from keras.layers.recurrent import LSTM
from keras.datasets.data_utils import get_file
from keras.utils.data_utils import get_file
import numpy as np
import random
import sys
@@ -29,7 +29,7 @@ char_indices = dict((c, i) for i, c in enumerate(chars))
indices_char = dict((i, c) for i, c in enumerate(chars))
# cut the text in semi-redundant sequences of maxlen characters
maxlen = 20
maxlen = 40
step = 3
sentences = []
next_chars = []
+9 -8
Ver Arquivo
@@ -1,8 +1,7 @@
'''Train a simple convnet on the MNIST dataset.
'''Trains a simple convnet on the MNIST dataset.
Run on GPU: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python mnist_cnn.py
Get to 99.25% test accuracy after 12 epochs (there is still a lot of margin for parameter tuning).
Gets to 99.25% test accuracy after 12 epochs
(there is still a lot of margin for parameter tuning).
16 seconds per epoch on a GRID K520 GPU.
'''
@@ -29,7 +28,7 @@ nb_pool = 2
# convolution kernel size
nb_conv = 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) = mnist.load_data()
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
@@ -64,10 +63,12 @@ model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta')
model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epoch,
show_accuracy=True, verbose=1, validation_data=(X_test, Y_test))
score = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
verbose=1, validation_data=(X_test, Y_test))
score = model.evaluate(X_test, Y_test, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])
+10 -25
Ver Arquivo
@@ -14,18 +14,15 @@ Reaches 0.93 train/test accuracy after 900 epochs
'''
from __future__ import print_function
import numpy as np
np.random.seed(1337) # for reproducibility
from keras.datasets import mnist
from keras.models import Sequential
from keras.layers.core import Dense, Activation
from keras.initializations import normal, identity
from keras.layers.recurrent import SimpleRNN, LSTM
from keras.layers.recurrent import SimpleRNN
from keras.optimizers import RMSprop
from keras.utils import np_utils
batch_size = 32
nb_classes = 10
nb_epochs = 200
@@ -54,32 +51,20 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)
print('Evaluate IRNN...')
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', input_shape=X_train.shape[1:]))
init=lambda shape, name: normal(shape, scale=0.001, name=name),
inner_init=lambda shape, name: identity(shape, scale=1.0, name=name),
activation='relu',
input_shape=X_train.shape[1:]))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
rmsprop = RMSprop(lr=learning_rate)
model.compile(loss='categorical_crossentropy', optimizer=rmsprop)
model.compile(loss='categorical_crossentropy',
optimizer=rmsprop,
metrics=['accuracy'])
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epochs,
show_accuracy=True, verbose=1, validation_data=(X_test, Y_test))
verbose=1, validation_data=(X_test, Y_test))
scores = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
scores = model.evaluate(X_test, Y_test, verbose=0)
print('IRNN test score:', scores[0])
print('IRNN test accuracy:', scores[1])
print('Compare to LSTM...')
model = Sequential()
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)
model.compile(loss='categorical_crossentropy', optimizer=rmsprop)
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epochs,
show_accuracy=True, verbose=1, validation_data=(X_test, Y_test))
scores = model.evaluate(X_test, Y_test, show_accuracy=True, verbose=0)
print('LSTM test score:', scores[0])
print('LSTM test accuracy:', scores[1])
+12 -11
Ver Arquivo
@@ -1,6 +1,6 @@
'''Train a simple deep NN on the MNIST dataset.
'''Trains a simple deep NN on the MNIST dataset.
Get to 98.40% test accuracy after 20 epochs
Gets 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.
'''
@@ -20,7 +20,7 @@ batch_size = 128
nb_classes = 10
nb_epoch = 20
# 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) = mnist.load_data()
X_train = X_train.reshape(60000, 784)
@@ -46,14 +46,15 @@ model.add(Dropout(0.2))
model.add(Dense(10))
model.add(Activation('softmax'))
rms = RMSprop()
model.compile(loss='categorical_crossentropy', optimizer=rms)
model.summary()
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.compile(loss='categorical_crossentropy',
optimizer=RMSprop(),
metrics=['accuracy'])
history = model.fit(X_train, Y_train,
batch_size=batch_size, nb_epoch=nb_epoch,
verbose=1, validation_data=(X_test, Y_test))
score = model.evaluate(X_test, Y_test, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])
+125
Ver Arquivo
@@ -0,0 +1,125 @@
'''Train a Siamese MLP on pairs of digits from the MNIST dataset.
It follows Hadsell-et-al.'06 [1] by computing the Euclidean distance on the
output of the shared network and by optimizing the contrastive loss (see paper
for mode details).
[1] "Dimensionality Reduction by Learning an Invariant Mapping"
http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf
Gets to 99.5% test accuracy after 20 epochs.
3 seconds per epoch on a Titan X GPU
'''
from __future__ import absolute_import
from __future__ import print_function
import numpy as np
np.random.seed(1337) # for reproducibility
import random
from keras.datasets import mnist
from keras.models import Sequential, Model
from keras.layers import Dense, Dropout, Input, Lambda
from keras.optimizers import SGD, RMSprop
from keras import backend as K
def euclidean_distance(vects):
x, y = vects
return K.sqrt(K.sum(K.square(x - y), axis=1, keepdims=True))
def contrastive_loss(y_true, y_pred):
'''Contrastive loss from Hadsell-et-al.'06
http://yann.lecun.com/exdb/publis/pdf/hadsell-chopra-lecun-06.pdf
'''
margin = 1
return K.mean(y_true * K.square(y_pred) + (1 - y_true) * K.square(K.maximum(margin - y_pred, 0)))
def create_pairs(x, digit_indices):
'''Positive and negative pair creation.
Alternates between positive and negative pairs.
'''
pairs = []
labels = []
n = min([len(digit_indices[d]) for d in range(10)]) - 1
for d in range(10):
for i in range(n):
z1, z2 = digit_indices[d][i], digit_indices[d][i+1]
pairs += [[x[z1], x[z2]]]
inc = random.randrange(1, 10)
dn = (d + inc) % 10
z1, z2 = digit_indices[d][i], digit_indices[dn][i]
pairs += [[x[z1], x[z2]]]
labels += [1, 0]
return np.array(pairs), np.array(labels)
def create_base_network(input_dim):
'''Base network to be shared (eq. to feature extraction).
'''
seq = Sequential()
seq.add(Dense(128, input_shape=(input_dim,), activation='relu'))
seq.add(Dropout(0.1))
seq.add(Dense(128, activation='relu'))
seq.add(Dropout(0.1))
seq.add(Dense(128, activation='relu'))
return seq
def compute_accuracy(predictions, labels):
'''Compute classification accuracy with a fixed threshold on distances.
'''
return labels[predictions.ravel() < 0.5].mean()
# the data, shuffled and split between train and test sets
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_train = X_train.reshape(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
input_dim = 784
nb_epoch = 20
# create training+test positive and negative pairs
digit_indices = [np.where(y_train == i)[0] for i in range(10)]
tr_pairs, tr_y = create_pairs(X_train, digit_indices)
digit_indices = [np.where(y_test == i)[0] for i in range(10)]
te_pairs, te_y = create_pairs(X_test, digit_indices)
# network definition
base_network = create_base_network(input_dim)
input_a = Input(shape=(input_dim,))
input_b = Input(shape=(input_dim,))
# because we re-use the same instance `base_network`,
# the weights of the network
# will be shared across the two branches
processed_a = base_network(input_a)
processed_b = base_network(input_b)
distance = Lambda(euclidean_distance)([processed_a, processed_b])
model = Model(input=[input_a, input_b], output=distance)
# train
rms = RMSprop()
model.compile(loss=contrastive_loss, optimizer=rms)
model.fit([tr_pairs[:, 0], tr_pairs[:, 1]], tr_y,
validation_data=([te_pairs[:, 0], te_pairs[:, 1]], te_y),
batch_size=128,
nb_epoch=nb_epoch)
# compute final accuracy on training and test sets
pred = model.predict([tr_pairs[:, 0], tr_pairs[:, 1]])
tr_acc = compute_accuracy(pred, tr_y)
pred = model.predict([te_pairs[:, 0], te_pairs[:, 1]])
te_acc = compute_accuracy(pred, te_y)
print('* Accuracy on training set: %0.2f%%' % (100 * tr_acc))
print('* Accuracy on test set: %0.2f%%' % (100 * te_acc))
+6 -4
Ver Arquivo
@@ -4,7 +4,7 @@
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
Run on GPU: THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python mnist_transfer_cnn.py
Get to 99.8% test accuracy after 5 epochs
for the first five digits classifier
@@ -55,15 +55,17 @@ def train_model(model, train, test, nb_classes):
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')
model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])
t = now()
model.fit(X_train, Y_train,
batch_size=batch_size, nb_epoch=nb_epoch,
show_accuracy=True, verbose=1,
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)
score = model.evaluate(X_test, Y_test, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])
+290
Ver Arquivo
@@ -0,0 +1,290 @@
'''Neural style transfer with Keras.
Before running this script, download the weights for the VGG16 model at:
https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
(source: https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
and make sure the variable `weights_path` in this script matches the location of the file.
Run the script with:
```
python neural_style_transfer.py path_to_your_base_image.jpg path_to_your_reference.jpg prefix_for_results
```
e.g.:
```
python neural_style_transfer.py img/tuebingen.jpg img/starry_night.jpg results/my_result
```
It is preferrable to run this script on GPU, for speed.
If running on CPU, prefer the TensorFlow backend (much faster).
Example result: https://twitter.com/fchollet/status/686631033085677568
# Details
Style transfer consists in generating an image
with the same "content" as a base image, but with the
"style" of a different picture (typically artistic).
This is achieved through the optimization of a loss function
that has 3 components: "style loss", "content loss",
and "total variation loss":
- The total variation loss imposes local spatial continuity between
the pixels of the combination image, giving it visual coherence.
- The style loss is where the deep learning keeps in --that one is defined
using a deep convolutional neural network. Precisely, it consists in a sum of
L2 distances betwen the Gram matrices of the representations of
the base image and the style reference image, extracted from
different layers of a convnet (trained on ImageNet). The general idea
is to capture color/texture information at different spatial
scales (fairly large scales --defined by the depth of the layer considered).
- The content loss is a L2 distance between the features of the base
image (extracted from a deep layer) and the features of the combination image,
keeping the generated image close enough to the original one.
# References
- [A Neural Algorithm of Artistic Style](http://arxiv.org/abs/1508.06576)
'''
from __future__ import print_function
from scipy.misc import imread, imresize, imsave
import numpy as np
from scipy.optimize import fmin_l_bfgs_b
import time
import os
import argparse
import h5py
from keras.models import Sequential
from keras.layers.convolutional import Convolution2D, ZeroPadding2D, MaxPooling2D
from keras import backend as K
parser = argparse.ArgumentParser(description='Neural style transfer with Keras.')
parser.add_argument('base_image_path', metavar='base', type=str,
help='Path to the image to transform.')
parser.add_argument('style_reference_image_path', metavar='ref', type=str,
help='Path to the style reference image.')
parser.add_argument('result_prefix', metavar='res_prefix', type=str,
help='Prefix for the saved results.')
args = parser.parse_args()
base_image_path = args.base_image_path
style_reference_image_path = args.style_reference_image_path
result_prefix = args.result_prefix
weights_path = 'vgg16_weights.h5'
# these are the weights of the different loss components
total_variation_weight = 1.
style_weight = 1.
content_weight = 0.025
# dimensions of the generated picture.
img_width = 400
img_height = 400
assert img_height == img_width, 'Due to the use of the Gram matrix, width and height must match.'
# util function to open, resize and format pictures into appropriate tensors
def preprocess_image(image_path):
img = imresize(imread(image_path), (img_width, img_height))
img = img.transpose((2, 0, 1)).astype('float64')
img = np.expand_dims(img, axis=0)
return img
# util function to convert a tensor into a valid image
def deprocess_image(x):
x = x.transpose((1, 2, 0))
x = np.clip(x, 0, 255).astype('uint8')
return x
# get tensor representations of our images
base_image = K.variable(preprocess_image(base_image_path))
style_reference_image = K.variable(preprocess_image(style_reference_image_path))
# this will contain our generated image
combination_image = K.placeholder((1, 3, img_width, img_height))
# combine the 3 images into a single Keras tensor
input_tensor = K.concatenate([base_image,
style_reference_image,
combination_image], axis=0)
# build the VGG16 network with our 3 images as input
first_layer = ZeroPadding2D((1, 1))
first_layer.set_input(input_tensor, shape=(3, 3, img_width, img_height))
model = Sequential()
model.add(first_layer)
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(64, 3, 3, activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(128, 3, 3, activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(256, 3, 3, activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(ZeroPadding2D((1, 1)))
model.add(Convolution2D(512, 3, 3, activation='relu'))
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
# load the weights of the VGG16 networks
# (trained on ImageNet, won the ILSVRC competition in 2014)
# note: when there is a complete match between your model definition
# and your weight savefile, you can simply call model.load_weights(filename)
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
f = h5py.File(weights_path)
for k in range(f.attrs['nb_layers']):
if k >= len(model.layers):
# we don't look at the last (fully-connected) layers in the savefile
break
g = f['layer_{}'.format(k)]
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
model.layers[k].set_weights(weights)
f.close()
print('Model loaded.')
# get the symbolic outputs of each "key" layer (we gave them unique names).
outputs_dict = dict([(layer.name, layer.output) for layer in model.layers])
# compute the neural style loss
# first we need to define 4 util functions
# the gram matrix of an image tensor (feature-wise outer product)
def gram_matrix(x):
assert K.ndim(x) == 3
features = K.batch_flatten(x)
gram = K.dot(features, K.transpose(features))
return gram
# the "style loss" is designed to maintain
# the style of the reference image in the generated image.
# It is based on the gram matrices (which capture style) of
# feature maps from the style reference image
# and from the generated image
def style_loss(style, combination):
assert K.ndim(style) == 3
assert K.ndim(combination) == 3
S = gram_matrix(style)
C = gram_matrix(combination)
channels = 3
size = img_width * img_height
return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))
# an auxiliary loss function
# designed to maintain the "content" of the
# base image in the generated image
def content_loss(base, combination):
return K.sum(K.square(combination - base))
# the 3rd loss function, total variation loss,
# designed to keep the generated image locally coherent
def total_variation_loss(x):
assert K.ndim(x) == 4
a = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, 1:, :img_height-1])
b = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, :img_width-1, 1:])
return K.sum(K.pow(a + b, 1.25))
# combine these loss functions into a single scalar
loss = K.variable(0.)
layer_features = outputs_dict['conv4_2']
base_image_features = layer_features[0, :, :, :]
combination_features = layer_features[2, :, :, :]
loss += content_weight * content_loss(base_image_features,
combination_features)
feature_layers = ['conv1_1', 'conv2_1', 'conv3_1', 'conv4_1', 'conv5_1']
for layer_name in feature_layers:
layer_features = outputs_dict[layer_name]
style_reference_features = layer_features[1, :, :, :]
combination_features = layer_features[2, :, :, :]
sl = style_loss(style_reference_features, combination_features)
loss += (style_weight / len(feature_layers)) * sl
loss += total_variation_weight * total_variation_loss(combination_image)
# get the gradients of the generated image wrt the loss
grads = K.gradients(loss, combination_image)
outputs = [loss]
if type(grads) in {list, tuple}:
outputs += grads
else:
outputs.append(grads)
f_outputs = K.function([combination_image], outputs)
def eval_loss_and_grads(x):
x = x.reshape((1, 3, img_width, img_height))
outs = f_outputs([x])
loss_value = outs[0]
if len(outs[1:]) == 1:
grad_values = outs[1].flatten().astype('float64')
else:
grad_values = np.array(outs[1:]).flatten().astype('float64')
return loss_value, grad_values
# this Evaluator class makes it possible
# to compute loss and gradients in one pass
# while retrieving them via two separate functions,
# "loss" and "grads". This is done because scipy.optimize
# requires separate functions for loss and gradients,
# but computing them separately would be inefficient.
class Evaluator(object):
def __init__(self):
self.loss_value = None
self.grads_values = None
def loss(self, x):
assert self.loss_value is None
loss_value, grad_values = eval_loss_and_grads(x)
self.loss_value = loss_value
self.grad_values = grad_values
return self.loss_value
def grads(self, x):
assert self.loss_value is not None
grad_values = np.copy(self.grad_values)
self.loss_value = None
self.grad_values = None
return grad_values
evaluator = Evaluator()
# run scipy-based optimization (L-BFGS) over the pixels of the generated image
# so as to minimize the neural style loss
x = np.random.uniform(0, 255, (1, 3, img_width, img_height))
for i in range(10):
print('Start of iteration', i)
start_time = time.time()
x, min_val, info = fmin_l_bfgs_b(evaluator.loss, x.flatten(),
fprime=evaluator.grads, maxfun=20)
print('Current loss value:', min_val)
# save current generated image
img = deprocess_image(x.reshape((3, img_width, img_height)))
fname = result_prefix + '_at_iteration_%d.png' % i
imsave(fname, img)
end_time = time.time()
print('Image saved as', fname)
print('Iteration %d completed in %ds' % (i, end_time - start_time))
+10 -8
Ver Arquivo
@@ -1,8 +1,5 @@
'''Train and evaluate a simple MLP on the Reuters newswire topic classification task.
GPU run command:
THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 python examples/reuters_mlp.py
CPU run command:
python examples/reuters_mlp.py
'''Trains and evaluate a simple MLP
on the Reuters newswire topic classification task.
'''
from __future__ import print_function
@@ -49,9 +46,14 @@ model.add(Dropout(0.5))
model.add(Dense(nb_classes))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['accuracy'])
history = model.fit(X_train, Y_train, nb_epoch=nb_epoch, batch_size=batch_size, verbose=1, show_accuracy=True, validation_split=0.1)
score = model.evaluate(X_test, Y_test, batch_size=batch_size, verbose=1, show_accuracy=True)
history = model.fit(X_train, Y_train,
nb_epoch=nb_epoch, batch_size=batch_size,
verbose=1, validation_split=0.1)
score = model.evaluate(X_test, Y_test,
batch_size=batch_size, verbose=1)
print('Test score:', score[0])
print('Test accuracy:', score[1])
+85
Ver Arquivo
@@ -0,0 +1,85 @@
'''Example script showing how to use stateful RNNs
to model long sequences efficiently.
'''
from __future__ import print_function
import numpy as np
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers.core import Dense
from keras.layers.recurrent import LSTM
# since we are using stateful rnn tsteps can be set to 1
tsteps = 1
batch_size = 25
epochs = 25
# number of elements ahead that are used to make the prediction
lahead = 1
def gen_cosine_amp(amp=100, period=25, x0=0, xn=50000, step=1, k=0.0001):
"""Generates an absolute cosine time series with the amplitude
exponentially decreasing
Arguments:
amp: amplitude of the cosine function
period: period of the cosine function
x0: initial x of the time series
xn: final x of the time series
step: step of the time series discretization
k: exponential rate
"""
cos = np.zeros(((xn - x0) * step, 1, 1))
for i in range(len(cos)):
idx = x0 + i * step
cos[i, 0, 0] = amp * np.cos(idx / (2 * np.pi * period))
cos[i, 0, 0] = cos[i, 0, 0] * np.exp(-k * idx)
return cos
print('Generating Data')
cos = gen_cosine_amp()
print('Input shape:', cos.shape)
expected_output = np.zeros((len(cos), 1))
for i in range(len(cos) - lahead):
expected_output[i, 0] = np.mean(cos[i + 1:i + lahead + 1])
print('Output shape')
print(expected_output.shape)
print('Creating Model')
model = Sequential()
model.add(LSTM(50,
batch_input_shape=(batch_size, tsteps, 1),
return_sequences=True,
stateful=True))
model.add(LSTM(50,
batch_input_shape=(batch_size, tsteps, 1),
return_sequences=False,
stateful=True))
model.add(Dense(1))
model.compile(loss='mse', optimizer='rmsprop')
print('Training')
for i in range(epochs):
print('Epoch', i, '/', epochs)
model.fit(cos,
expected_output,
batch_size=batch_size,
verbose=1,
nb_epoch=1,
shuffle=False)
model.reset_states()
print('Predicting')
predicted_output = model.predict(cos, batch_size=batch_size)
print('Ploting Results')
plt.subplot(2, 1, 1)
plt.plot(expected_output)
plt.title('Expected')
plt.subplot(2, 1, 2)
plt.plot(predicted_output)
plt.title('Predicted')
plt.show()
+1 -1
Ver Arquivo
@@ -1 +1 @@
__version__ = '0.3.0'
__version__ = '1.0.0'
+3 -5
Ver Arquivo
@@ -7,11 +7,9 @@ def softmax(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
e = K.exp(x - K.max(x, axis=-1, keepdims=True))
s = K.sum(e, axis=-1, keepdims=True)
return e / s
else:
raise Exception('Cannot apply softmax to a tensor that is not 2D or 3D. ' +
'Here, ndim=' + str(ndim))
+10 -4
Ver Arquivo
@@ -2,7 +2,13 @@ from __future__ import absolute_import
from __future__ import print_function
import os
import json
from .common import epsilon, floatx, set_epsilon, set_floatx
import sys
from .common import epsilon
from .common import floatx
from .common import set_epsilon
from .common import set_floatx
from .common import get_uid
from .common import cast_to_floatx
_keras_base_dir = os.path.expanduser('~')
if not os.access(_keras_base_dir, os.W_OK):
@@ -17,7 +23,7 @@ _config_path = os.path.expanduser(os.path.join(_keras_dir, 'keras.json'))
if os.path.exists(_config_path):
_config = json.load(open(_config_path))
_floatx = _config.get('floatx', floatx())
assert _floatx in {'float32', 'float64'}
assert _floatx in {'float16', 'float32', 'float64'}
_epsilon = _config.get('epsilon', epsilon())
assert type(_epsilon) == float
_backend = _config.get('backend', _BACKEND)
@@ -41,10 +47,10 @@ if 'KERAS_BACKEND' in os.environ:
_BACKEND = _backend
if _BACKEND == 'theano':
print('Using Theano backend.')
sys.stderr.write('Using Theano backend.\n')
from .theano_backend import *
elif _BACKEND == 'tensorflow':
print('Using TensorFlow backend.')
sys.stderr.write('Using TensorFlow backend.\n')
from .tensorflow_backend import *
else:
raise Exception('Unknown backend: ' + str(_BACKEND))
+14 -1
Ver Arquivo
@@ -3,6 +3,7 @@ import numpy as np
# the type of float to use throughout the session.
_FLOATX = 'float32'
_EPSILON = 10e-8
_UID_PREFIXES = {}
def epsilon():
@@ -15,12 +16,15 @@ def set_epsilon(e):
def floatx():
'''Returns the default float type, as a string
(e.g. 'float16', 'float32', 'float64').
'''
return _FLOATX
def set_floatx(floatx):
global _FLOATX
if floatx not in {'float32', 'float64'}:
if floatx not in {'float16', 'float32', 'float64'}:
raise Exception('Unknown floatx type: ' + str(floatx))
floatx = str(floatx)
_FLOATX = floatx
@@ -30,3 +34,12 @@ def cast_to_floatx(x):
'''Cast a Numpy array to floatx.
'''
return np.asarray(x, dtype=_FLOATX)
def get_uid(prefix=''):
if prefix not in _UID_PREFIXES:
_UID_PREFIXES[prefix] = 1
return 1
else:
_UID_PREFIXES[prefix] += 1
return _UID_PREFIXES[prefix]
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+512 -137
Ver Arquivo
@@ -1,28 +1,21 @@
import theano
from theano import tensor as T
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
from theano.tensor.signal import downsample
from theano.tensor.signal import pool
from theano.tensor.nnet import conv3d2d
import inspect
import numpy as np
from .common import _FLOATX, _EPSILON
# INTERNAL UTILS
theano.config.floatX = _FLOATX
_LEARNING_PHASE = T.scalar(dtype='uint8', name='keras_learning_phase') # 0 = test, 1 = train
def _on_gpu():
'''Return 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 installed should not
prevent from running the present code.
'''
from theano.sandbox.cuda import dnn
def learning_phase():
# False = test, True = train
return _LEARNING_PHASE
# VARIABLE MANIPULATION
@@ -41,18 +34,14 @@ def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=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))
shape = tuple([None for _ in range(ndim)])
broadcast = (False,) * ndim
x = T.TensorType(dtype, broadcast)(name)
x._keras_shape = shape
x._uses_learning_phase = False
return x
def shape(x):
@@ -68,6 +57,10 @@ def ndim(x):
return x.ndim
def dtype(x):
return x.dtype
def eval(x):
'''Run a graph.
'''
@@ -118,6 +111,38 @@ def dot(x, y):
return T.dot(x, y)
def batch_dot(x, y, axes=None):
'''batchwise dot product
batch_dot results in a tensor with less dimensions than the input.
If the number of dimensions is reduced to 1, we use `expand_dims` to
make sure that ndim is at least 2.
# Example
Assume x = [[1, 2] and y = [[5, 6]
[3, 4]] [7, 8]]
batch_dot(x, y, axes=1) = [[17, 53]] which is the main diagonal
of x.dot(y.T), although we never have to calculate the off-diagonal
elements.
# Arguments
x, y: tensors with ndim >= 2
axes: list (or single) int with target dimensions
# Returns
Tensor with ndim >= 2
'''
if type(axes) == int:
axes = (axes, axes)
if axes is None:
# behaves like tf.batch_matmul as default
axes = [x.ndim - 1, y.ndim - 2]
out = T.batched_tensordot(x, y, axes=axes)
if ndim(out) == 1:
out = expand_dims(out, 1)
return out
def transpose(x):
return T.transpose(x)
@@ -155,7 +180,10 @@ def prod(x, axis=None, keepdims=False):
def mean(x, axis=None, keepdims=False):
return T.mean(x, axis=axis, keepdims=keepdims)
dtype = None
if 'int' in x.dtype:
dtype = _FLOATX
return T.mean(x, axis=axis, keepdims=keepdims, dtype=dtype)
def std(x, axis=None, keepdims=False):
@@ -201,6 +229,10 @@ def round(x):
return T.round(x)
def sign(x):
return T.sgn(x)
def pow(x, a):
return T.pow(x, a)
@@ -215,6 +247,10 @@ def equal(x, y):
return T.eq(x, y)
def not_equal(x, y):
return T.neq(x, y)
def maximum(x, y):
return T.maximum(x, y)
@@ -251,15 +287,56 @@ def repeat_elements(x, rep, axis):
'''
return T.repeat(x, rep, axis=axis)
def resize_images(X, height_factor, width_factor, dim_ordering):
'''Resize the images contained in a 4D tensor of shape
- [batch, channels, height, width] (for 'th' dim_ordering)
- [batch, height, width, channels] (for 'tf' dim_ordering)
by a factor of (height_factor, width_factor). Both factors should be
positive integers.
'''
if dim_ordering == 'th':
output = repeat_elements(X, height_factor, axis=2)
output = repeat_elements(output, width_factor, axis=3)
return output
elif dim_ordering == 'tf':
output = repeat_elements(X, height_factor, axis=1)
output = repeat_elements(output, width_factor, axis=2)
return output
else:
raise Exception('Invalid dim_ordering: ' + dim_ordering)
def resize_volumes(X, depth_factor, height_factor, width_factor, dim_ordering):
'''Resize the volume contained in a 5D tensor of shape
- [batch, channels, depth, height, width] (for 'th' dim_ordering)
- [batch, depth, height, width, channels] (for 'tf' dim_ordering)
by a factor of (depth_factor, height_factor, width_factor).
Both factors should be positive integers.
'''
if dim_ordering == 'th':
output = repeat_elements(X, depth_factor, axis=2)
output = repeat_elements(output, height_factor, axis=3)
output = repeat_elements(output, width_factor, axis=4)
return output
elif dim_ordering == 'tf':
output = repeat_elements(X, depth_factor, axis=1)
output = repeat_elements(output, height_factor, axis=2)
output = repeat_elements(output, width_factor, axis=3)
return output
else:
raise Exception('Invalid dim_ordering: ' + dim_ordering)
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))
assert x.ndim == 2
x = x.dimshuffle((0, 'x', 1))
return T.extra_ops.repeat(x, n, axis=1)
def tile(x, n):
@@ -267,6 +344,10 @@ def tile(x, n):
def flatten(x):
return T.flatten(x)
def batch_flatten(x):
'''Turn a n-D tensor into a 2D tensor where
the first dimension is conserved.
'''
@@ -339,6 +420,45 @@ def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
raise Exception('Invalid dim_ordering: ' + dim_ordering)
return T.set_subtensor(output[indices], x)
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering='th'):
'''Pad the 2nd, 3rd and 4th dimensions of a 5D tensor
with "padding[0]", "padding[1]" and "padding[2]" (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],
input_shape[4] + 2 * padding[2])
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]),
slice(padding[2], input_shape[4] + padding[2]))
elif dim_ordering == 'tf':
output_shape = (input_shape[0],
input_shape[1] + 2 * padding[0],
input_shape[2] + 2 * padding[1],
input_shape[3] + 2 * padding[2],
input_shape[4])
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(padding[2], input_shape[3] + padding[2]),
slice(None))
else:
raise Exception('Invalid dim_ordering: ' + dim_ordering)
return T.set_subtensor(output[indices], x)
def pack(x):
return T.stack(*x)
# VALUE MANIPULATION
@@ -359,14 +479,23 @@ class Function(object):
def __init__(self, inputs, outputs, updates=[], **kwargs):
self.function = theano.function(inputs, outputs, updates=updates,
allow_input_downcast=True, **kwargs)
allow_input_downcast=True,
on_unused_input='warn',
**kwargs)
def __call__(self, inputs):
assert type(inputs) in {list, tuple}
return self.function(*inputs)
def function(inputs, outputs, updates=[]):
return Function(inputs, outputs, updates=updates)
def function(inputs, outputs, updates=[], **kwargs):
if len(kwargs) > 0:
function_args = inspect.getargspec(theano.function)[0]
for key in kwargs.keys():
if key not in function_args:
msg = "Invalid argument '%s' passed to K.function" % key
raise ValueError(msg)
return Function(inputs, outputs, updates=updates, **kwargs)
def gradients(loss, variables):
@@ -376,77 +505,164 @@ def gradients(loss, variables):
# CONTROL FLOW
def rnn(step_function, inputs, initial_states,
go_backwards=False, masking=True):
'''Iterate over the time dimension of a tensor.
go_backwards=False, mask=None, constants=None,
unroll=False, input_length=None):
'''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.
# Arguments
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.
mask: binary tensor with shape (samples, time),
with a zero for every element that is masked.
constants: a list of constant values passed at each step.
unroll: whether to unroll the RNN or to use a symbolic loop (`scan`).
input_length: must be specified if using `unroll`.
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, ...).
# 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))
ndim = inputs.ndim
assert ndim >= 3, 'Input should be at least 3D.'
def _step(input, *states):
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, axis=-1, keepdims=True)
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
if unroll:
if input_length is None:
raise Exception('When specifying `unroll=True`, an `input_length` '
'must be provided to `rnn`.')
axes = [1, 0] + list(range(2, ndim))
inputs = inputs.dimshuffle(axes)
if mask is not None:
if mask.ndim == ndim-1:
mask = expand_dims(mask)
assert mask.ndim == ndim
mask = mask.dimshuffle(axes)
if constants is None:
constants = []
if unroll:
indices = list(range(input_length))
if go_backwards:
indices = indices[::-1]
successive_outputs = []
successive_states = []
states = initial_states
for i in indices:
output, new_states = step_function(inputs[i], states)
if len(successive_outputs) == 0:
prev_output = zeros_like(output)
else:
prev_output = successive_outputs[-1]
output = T.switch(mask[i], output, prev_output)
kept_states = []
for state, new_state in zip(states, new_states):
kept_states.append(T.switch(mask[i], new_state, state))
states = kept_states
successive_outputs.append(output)
successive_states.append(states)
outputs = T.stack(*successive_outputs)
states = []
for i in range(len(successive_states[-1])):
states.append(T.stack(*[states_at_step[i] for states_at_step in successive_states]))
else:
return [output] + new_states
# build an all-zero tensor of shape (samples, output_dim)
initial_output = step_function(inputs[0], initial_states + constants)[0] * 0
# Theano gets confused by broadcasting patterns in the scan op
initial_output = T.unbroadcast(initial_output, 0, 1)
results, _ = theano.scan(
_step,
sequences=inputs,
outputs_info=[None] + initial_states,
go_backwards=go_backwards)
def _step(input, mask, output_tm1, *states):
output, new_states = step_function(input, states)
# output previous output if masked.
output = T.switch(mask, output, output_tm1)
return_states = []
for state, new_state in zip(states, new_states):
return_states.append(T.switch(mask, new_state, state))
return [output] + return_states
# deal with Theano API inconsistency
if type(results) is list:
outputs = results[0]
states = results[1:]
results, _ = theano.scan(
_step,
sequences=[inputs, mask],
outputs_info=[initial_output] + initial_states,
non_sequences=constants,
go_backwards=go_backwards)
# deal with Theano API inconsistency
if type(results) is list:
outputs = results[0]
states = results[1:]
else:
outputs = results
states = []
else:
outputs = results
states = []
if unroll:
indices = list(range(input_length))
if go_backwards:
indices = indices[::-1]
successive_outputs = []
successive_states = []
states = initial_states
for i in indices:
output, states = step_function(inputs[i], states)
successive_outputs.append(output)
successive_states.append(states)
outputs = T.stack(*successive_outputs)
states = []
for i in range(len(successive_states[-1])):
states.append(T.stack(*[states_at_step[i] for states_at_step in successive_states]))
else:
def _step(input, *states):
output, new_states = step_function(input, states)
return [output] + new_states
results, _ = theano.scan(
_step,
sequences=inputs,
outputs_info=[None] + initial_states,
non_sequences=constants,
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))
axes = [1, 0] + list(range(2, outputs.ndim))
outputs = outputs.dimshuffle(axes)
states = [T.squeeze(state[-1]) for state in states]
return last_output, outputs, states
@@ -457,9 +673,25 @@ def switch(condition, then_expression, else_expression):
return T.switch(condition, then_expression, else_expression)
def in_train_phase(x, alt):
x = T.switch(_LEARNING_PHASE, x, alt)
x._uses_learning_phase = True
return x
def in_test_phase(x, alt):
x = T.switch(_LEARNING_PHASE, alt, x)
x._uses_learning_phase = True
return x
# NN OPERATIONS
def relu(x, alpha=0., max_value=None):
assert hasattr(T.nnet, 'relu'), ('It looks like like your version of '
'Theano is out of date. '
'Install the latest version with:\n'
'pip install git+git://github.com/Theano/Theano.git --upgrade --no-deps')
x = T.nnet.relu(x, alpha)
if max_value is not None:
x = T.minimum(x, max_value)
@@ -485,6 +717,13 @@ def categorical_crossentropy(output, target, from_logits=False):
return T.nnet.categorical_crossentropy(output, target)
def sparse_categorical_crossentropy(output, target, from_logits=False):
target = T.cast(T.flatten(target), 'int32')
target = T.extra_ops.to_one_hot(target, nb_class=output.shape[-1])
target = reshape(target, shape(output))
return categorical_crossentropy(output, target, from_logits)
def binary_crossentropy(output, target, from_logits=False):
if from_logits:
output = T.nnet.sigmoid(output)
@@ -517,13 +756,16 @@ def dropout(x, level, seed=None):
return x
# CONVOLUTIONS
def l2_normalize(x, axis):
norm = T.sqrt(T.sum(T.square(x), axis=axis, keepdims=True))
return x / norm
# CONVOLUTIONS
def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th',
image_shape=None, filter_shape=None):
'''
Run on cuDNN if available.
border_mode: string, "same" or "valid".
'''
if dim_ordering not in {'th', 'tf'}:
@@ -545,49 +787,151 @@ def conv2d(x, kernel, strides=(1, 1), border_mode='valid', dim_ordering='th',
filter_shape = (filter_shape[3], filter_shape[2],
filter_shape[0], filter_shape[1])
if _on_gpu() and dnn.dnn_available():
if border_mode == 'same':
assert(strides == (1, 1))
conv_out = dnn.dnn_conv(img=x,
kerns=kernel,
border_mode='full')
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]
else:
conv_out = dnn.dnn_conv(img=x,
kerns=kernel,
border_mode=border_mode,
subsample=strides)
if border_mode == 'same':
th_border_mode = 'half'
np_kernel = kernel.eval()
elif border_mode == 'valid':
th_border_mode = 'valid'
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))
raise Exception('Border mode not supported: ' + str(border_mode))
# Theano might not accept long type
def int_or_none(value):
try:
return int(value)
except TypeError:
return None
if image_shape is not None:
image_shape = tuple(int_or_none(v) for v in image_shape)
if filter_shape is not None:
filter_shape = tuple(int_or_none(v) for v in filter_shape)
conv_out = T.nnet.conv2d(x, kernel,
border_mode=th_border_mode,
subsample=strides,
input_shape=image_shape,
filter_shape=filter_shape)
if border_mode == 'same':
if np_kernel.shape[2] % 2 == 0:
conv_out = conv_out[:, :, :(x.shape[2] + strides[0] - 1) // strides[0], :]
if np_kernel.shape[3] % 2 == 0:
conv_out = conv_out[:, :, :, :(x.shape[3] + strides[1] - 1) // strides[1]]
conv_out = T.nnet.conv.conv2d(x, kernel,
border_mode=th_border_mode,
subsample=strides,
image_shape=image_shape,
filter_shape=filter_shape)
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 conv3d(x, kernel, strides=(1, 1, 1),
border_mode='valid', dim_ordering='th',
volume_shape=None, filter_shape=None):
'''
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 border_mode not in {'same', 'valid'}:
raise Exception('Invalid border mode: ' + str(border_mode))
if dim_ordering == 'tf':
# TF uses the last dimension as channel dimension,
# instead of the 2nd one.
# TH input shape: (samples, input_depth, conv_dim1, conv_dim2, conv_dim3)
# TF input shape: (samples, conv_dim1, conv_dim2, conv_dim3, input_depth)
# TH kernel shape: (out_depth, input_depth, kernel_dim1, kernel_dim2, kernel_dim3)
# TF kernel shape: (kernel_dim1, kernel_dim2, kernel_dim3, input_depth, out_depth)
x = x.dimshuffle((0, 4, 1, 2, 3))
kernel = kernel.dimshuffle((4, 3, 0, 1, 2))
if volume_shape:
volume_shape = (volume_shape[0], volume_shape[4],
volume_shape[1], volume_shape[2], volume_shape[3])
if filter_shape:
filter_shape = (filter_shape[4], filter_shape[3],
filter_shape[0], filter_shape[1], filter_shape[2])
if border_mode == 'same':
assert(strides == (1, 1, 1))
pad_dim1 = (kernel.shape[2] - 1)
pad_dim2 = (kernel.shape[3] - 1)
pad_dim3 = (kernel.shape[4] - 1)
output_shape = (x.shape[0], x.shape[1],
x.shape[2] + pad_dim1,
x.shape[3] + pad_dim2,
x.shape[4] + pad_dim3)
output = T.zeros(output_shape)
indices = (slice(None), slice(None),
slice(pad_dim1 // 2, x.shape[2] + pad_dim1 // 2),
slice(pad_dim2 // 2, x.shape[3] + pad_dim2 // 2),
slice(pad_dim3 // 2, x.shape[4] + pad_dim3 // 2))
x = T.set_subtensor(output[indices], x)
border_mode = 'valid'
border_mode_3d = (border_mode, border_mode, border_mode)
conv_out = conv3d2d.conv3d(signals=x.dimshuffle(0, 2, 1, 3, 4),
filters=kernel.dimshuffle(0, 2, 1, 3, 4),
border_mode=border_mode_3d)
conv_out = conv_out.dimshuffle(0, 2, 1, 3, 4)
# support strides by manually slicing the output
if strides != (1, 1, 1):
conv_out = conv_out[:, :, ::strides[0], ::strides[1], ::strides[2]]
if dim_ordering == 'tf':
conv_out = conv_out.dimshuffle((0, 2, 3, 4, 1))
return conv_out
def pool2d(x, pool_size, strides=(1, 1), border_mode='valid',
dim_ordering='th', pool_mode='max'):
if border_mode == 'same':
w_pad = pool_size[0] - 2 if pool_size[0] % 2 == 1 else pool_size[0] - 1
h_pad = pool_size[1] - 2 if pool_size[1] % 2 == 1 else pool_size[1] - 1
padding = (w_pad, h_pad)
elif border_mode == 'valid':
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))
if pool_mode == 'max':
pool_out = pool.pool_2d(x, ds=pool_size, st=strides,
ignore_border=True,
padding=padding,
mode='max')
elif pool_mode == 'avg':
pool_out = pool.pool_2d(x, ds=pool_size, st=strides,
ignore_border=True,
padding=padding,
mode='average_exc_pad')
else:
raise Exception('Invalid pooling mode: ' + str(pool_mode))
if border_mode == 'same':
expected_width = (x.shape[2] + strides[0] - 1) // strides[0]
expected_height = (x.shape[3] + strides[1] - 1) // strides[1]
pool_out = pool_out[:, :,
: expected_width,
: expected_height]
if dim_ordering == 'tf':
pool_out = pool_out.dimshuffle((0, 2, 3, 1))
return pool_out
def pool3d(x, pool_size, strides=(1, 1, 1), border_mode='valid',
dim_ordering='th', pool_mode='max'):
if border_mode == 'same':
# TODO: add implementation for border_mode="same"
raise Exception('border_mode="same" not supported with Theano.')
@@ -601,25 +945,49 @@ def pool2d(x, pool_size, strides=(1, 1), border_mode='valid',
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
if dim_ordering == 'tf':
x = x.dimshuffle((0, 3, 1, 2))
x = x.dimshuffle((0, 4, 1, 2, 3))
if pool_mode == 'max':
pool_out = downsample.max_pool_2d(x, ds=pool_size, st=strides,
ignore_border=ignore_border,
padding=padding,
mode='max')
# pooling over conv_dim2, conv_dim1 (last two channels)
output = pool.pool_2d(input=x.dimshuffle(0, 1, 4, 3, 2),
ds=(pool_size[1], pool_size[0]),
st=(strides[1], strides[0]),
ignore_border=ignore_border,
padding=padding,
mode='max')
# pooling over conv_dim3
pool_out = pool.pool_2d(input=output.dimshuffle(0, 1, 4, 3, 2),
ds=(1, pool_size[2]),
st=(1, strides[2]),
ignore_border=ignore_border,
padding=padding,
mode='max')
elif pool_mode == 'avg':
pool_out = downsample.max_pool_2d(x, ds=pool_size, st=strides,
ignore_border=ignore_border,
padding=padding,
mode='average_exc_pad')
# pooling over conv_dim2, conv_dim1 (last two channels)
output = pool.pool_2d(input=x.dimshuffle(0, 1, 4, 3, 2),
ds=(pool_size[1], pool_size[0]),
st=(strides[1], strides[0]),
ignore_border=ignore_border,
padding=padding,
mode='average_exc_pad')
# pooling over conv_dim3
pool_out = pool.pool_2d(input=output.dimshuffle(0, 1, 4, 3, 2),
ds=(1, pool_size[2]),
st=(1, strides[2]),
ignore_border=ignore_border,
padding=padding,
mode='average_exc_pad')
else:
raise Exception('Invalid pooling mode: ' + str(pool_mode))
if dim_ordering == 'tf':
pool_out = pool_out.dimshuffle((0, 2, 3, 1))
pool_out = pool_out.dimshuffle((0, 2, 3, 4, 1))
return pool_out
# RANDOMNESS
@@ -636,6 +1004,13 @@ def random_uniform(shape, low=0.0, high=1.0, dtype=_FLOATX, seed=None):
rng = RandomStreams(seed=seed)
return rng.uniform(shape, low=low, high=high, dtype=dtype)
def random_binomial(shape, p=0.0, dtype=_FLOATX, seed=None):
if seed is None:
seed = np.random.randint(10e6)
rng = RandomStreams(seed=seed)
return rng.binomial(shape, p=p, dtype=dtype)
'''
more TODO:
+47 -86
Ver Arquivo
@@ -92,7 +92,8 @@ class Callback(object):
will include the following quantities in the `logs` that
it passes to its callbacks:
on_epoch_end: logs optionally include `val_loss`
on_epoch_end: logs include `acc` and `loss`, and
optionally include `val_loss`
(if validation is enabled in `fit`), and `val_acc`
(if validation and accuracy monitoring are enabled).
on_batch_begin: logs include `size`,
@@ -129,11 +130,35 @@ class Callback(object):
class BaseLogger(Callback):
'''Callback that prints events to the standard output.
'''Callback that accumulates epoch averages of
the metrics being monitored.
This callback is automatically applied to
every Keras model (it is the basis of the verbosity modes
in models).
every Keras model.
'''
def on_epoch_begin(self, epoch, logs={}):
self.seen = 0
self.totals = {}
def on_batch_end(self, batch, logs={}):
batch_size = logs.get('size', 0)
self.seen += batch_size
for k, v in logs.items():
if k in self.totals:
self.totals[k] += v * batch_size
else:
self.totals[k] = v * batch_size
def on_epoch_end(self, epoch, logs={}):
for k in self.params['metrics']:
if k in self.totals:
# make value available to next callbacks
logs[k] = self.totals[k] / self.seen
class ProgbarLogger(Callback):
'''Callback that prints metrics to stdout.
'''
def on_train_begin(self, logs={}):
self.verbose = self.params['verbose']
@@ -145,7 +170,6 @@ class BaseLogger(Callback):
self.progbar = Progbar(target=self.params['nb_sample'],
verbose=self.verbose)
self.seen = 0
self.totals = {}
def on_batch_begin(self, batch, logs={}):
if self.seen < self.params['nb_sample']:
@@ -155,11 +179,6 @@ class BaseLogger(Callback):
batch_size = logs.get('size', 0)
self.seen += batch_size
for k, v in logs.items():
if k in self.totals:
self.totals[k] += v * batch_size
else:
self.totals[k] = v * batch_size
for k in self.params['metrics']:
if k in logs:
self.log_values.append((k, logs[k]))
@@ -171,8 +190,6 @@ class BaseLogger(Callback):
def on_epoch_end(self, epoch, logs={}):
for k in self.params['metrics']:
if k in self.totals:
self.log_values.append((k, self.totals[k] / self.seen))
if k in logs:
self.log_values.append((k, logs[k]))
if self.verbose:
@@ -191,26 +208,8 @@ class History(Callback):
self.epoch = []
self.history = {}
def on_epoch_begin(self, epoch, logs={}):
self.seen = 0
self.totals = {}
def on_batch_end(self, batch, logs={}):
batch_size = logs.get('size', 0)
self.seen += batch_size
for k, v in logs.items():
if k in self.totals:
self.totals[k] += v * batch_size
else:
self.totals[k] = v * batch_size
def on_epoch_end(self, epoch, logs={}):
self.epoch.append(epoch)
for k, v in self.totals.items():
if k not in self.history:
self.history[k] = []
self.history[k].append(v / self.seen)
for k, v in logs.items():
if k not in self.history:
self.history[k] = []
@@ -256,7 +255,7 @@ class ModelCheckpoint(Callback):
if mode not in ['auto', 'min', 'max']:
warnings.warn('ModelCheckpoint mode %s is unknown, '
'fallback to auto mode.' % (self.mode),
'fallback to auto mode.' % (mode),
RuntimeWarning)
mode = 'auto'
@@ -373,26 +372,10 @@ class RemoteMonitor(Callback):
def __init__(self, root='http://localhost:9000'):
self.root = root
def on_epoch_begin(self, epoch, logs={}):
self.seen = 0
self.totals = {}
def on_batch_end(self, batch, logs={}):
batch_size = logs.get('size', 0)
self.seen += batch_size
for k, v in logs.items():
if k in self.totals:
self.totals[k] += v * batch_size
else:
self.totals[k] = v * batch_size
def on_epoch_end(self, epoch, logs={}):
import requests
send = {}
send['epoch'] = epoch
for k, v in self.totals.items():
send[k] = v / self.seen
for k, v in logs.items():
send[k] = v
@@ -456,64 +439,42 @@ class TensorBoard(Callback):
'with the TensorFlow backend.')
self.log_dir = log_dir
self.histogram_freq = histogram_freq
self.merged = None
def _set_model(self, model):
import tensorflow as tf
import keras.backend.tensorflow_backend as KTF
self.model = model
self.sess = KTF._get_session()
if self.histogram_freq:
mod_type = self.model.get_config()['name']
if mod_type == 'Sequential':
layers = {l.get_config()['name']: l for l in self.model.layers}
elif mod_type == 'Graph':
layers = self.model.nodes
else:
raise Exception('Unrecognized model:',
self.model.get_config()['name'])
for l in layers:
cur_layer = layers[l]
if hasattr(cur_layer, 'W'):
tf.histogram_summary('{}_W'.format(l), cur_layer.W)
if hasattr(cur_layer, 'b'):
tf.histogram_summary('{}_b'.format(l), cur_layer.b)
if hasattr(cur_layer, 'get_output'):
tf.histogram_summary('{}_out'.format(l),
cur_layer.get_output())
self.sess = KTF.get_session()
if self.histogram_freq and not self.merged:
layers = self.model.layers
for layer in layers:
if hasattr(layer, 'W'):
tf.histogram_summary('{}_W'.format(layer), layer.W)
if hasattr(layer, 'b'):
tf.histogram_summary('{}_b'.format(layer), layer.b)
if hasattr(layer, 'output'):
tf.histogram_summary('{}_out'.format(layer),
layer.output)
self.merged = tf.merge_all_summaries()
self.writer = tf.train.SummaryWriter(self.log_dir,
self.sess.graph_def)
def on_epoch_begin(self, epoch, logs={}):
self.seen = 0
self.totals = {}
def on_batch_end(self, batch, logs={}):
batch_size = logs.get('size', 0)
self.seen += batch_size
for k, v in logs.items():
if k in self.totals:
self.totals[k] += v * batch_size
else:
self.totals[k] = v * batch_size
def on_epoch_end(self, epoch, logs={}):
import tensorflow as tf
if self.model.validation_data and self.histogram_freq:
if epoch % self.histogram_freq == 0:
if self.params.get('show_accuracy'):
test_function = self.model._test_with_acc
else:
test_function = self.model._test
names = [v.name for v in test_function.inputs]
feed_dict = dict(zip(names, self.model.validation_data))
# TODO: implement batched calls to sess.run
# (current call will likely go OOM on GPU)
feed_dict = dict(zip(self.model.inputs,
self.model.validation_data))
result = self.sess.run([self.merged], feed_dict=feed_dict)
summary_str = result[0]
self.writer.add_summary(summary_str, epoch)
for name, value in self.totals.items() + logs.items():
for name, value in logs.items():
if name in ['batch', 'size']:
continue
summary = tf.Summary()
+58 -10
Ver Arquivo
@@ -7,39 +7,87 @@ class Constraint(object):
return p
def get_config(self):
return {"name": self.__class__.__name__}
return {'name': self.__class__.__name__}
class MaxNorm(Constraint):
def __init__(self, m=2):
'''Constrain the weights incident to each hidden unit to have a norm less than or equal to a desired value.
# Arguments
m: the maximum norm for the incoming weights.
axis: integer, axis along which to calculate weight norms. For instance,
in a `Dense` layer the weight matrix has shape (input_dim, output_dim),
set `axis` to `0` to constrain each weight vector of length (input_dim).
In a `MaxoutDense` layer the weight tensor has shape (nb_feature, input_dim, output_dim),
set `axis` to `1` to constrain each weight vector of length (input_dim),
i.e. constrain the filters incident to the `max` operation.
In a `Convolution2D` layer with the Theano backend, the weight tensor
has shape (nb_filter, stack_size, nb_row, nb_col), set `axis` to `[1,2,3]`
to constrain the weights of each filter tensor of size (stack_size, nb_row, nb_col).
In a `Convolution2D` layer with the TensorFlow backend, the weight tensor
has shape (nb_row, nb_col, stack_size, nb_filter), set `axis` to `[0,1,2]`
to constrain the weights of each filter tensor of size (nb_row, nb_col, stack_size).
# References
- [Dropout: A Simple Way to Prevent Neural Networks from Overfitting Srivastava, Hinton, et al. 2014](http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf)
'''
def __init__(self, m=2, axis=0):
self.m = m
self.axis = axis
def __call__(self, p):
norms = K.sqrt(K.sum(K.square(p), axis=0))
norms = K.sqrt(K.sum(K.square(p), axis=self.axis, keepdims=True))
desired = K.clip(norms, 0, self.m)
p = p * (desired / (1e-7 + norms))
p = p * (desired / (K.epsilon() + norms))
return p
def get_config(self):
return {"name": self.__class__.__name__,
"m": self.m}
return {'name': self.__class__.__name__,
'm': self.m,
'axis': self.axis}
class NonNeg(Constraint):
'''Constrain the weights to be non-negative.
'''
def __call__(self, p):
p *= K.cast(p >= 0., K.floatx())
return p
class UnitNorm(Constraint):
def __call__(self, p):
return p / K.sqrt(K.sum(K.square(p), axis=-1, keepdims=True))
'''Constrain the weights incident to each hidden unit to have unit norm.
# Arguments
axis: integer, axis along which to calculate weight norms. For instance,
in a `Dense` layer the weight matrix has shape (input_dim, output_dim),
set `axis` to `0` to constrain each weight vector of length (input_dim).
In a `MaxoutDense` layer the weight tensor has shape (nb_feature, input_dim, output_dim),
set `axis` to `1` to constrain each weight vector of length (input_dim),
i.e. constrain the filters incident to the `max` operation.
In a `Convolution2D` layer with the Theano backend, the weight tensor
has shape (nb_filter, stack_size, nb_row, nb_col), set `axis` to `[1,2,3]`
to constrain the weights of each filter tensor of size (stack_size, nb_row, nb_col).
In a `Convolution2D` layer with the TensorFlow backend, the weight tensor
has shape (nb_row, nb_col, stack_size, nb_filter), set `axis` to `[0,1,2]`
to constrain the weights of each filter tensor of size (nb_row, nb_col, stack_size).
'''
def __init__(self, axis=0):
self.axis = axis
def __call__(self, p):
return p / (K.epsilon() + K.sqrt(K.sum(K.square(p), axis=self.axis, keepdims=True)))
def get_config(self):
return {'name': self.__class__.__name__,
'axis': self.axis}
identity = Constraint
maxnorm = MaxNorm
nonneg = NonNeg
unitnorm = UnitNorm
from .utils.generic_utils import get_from_module
def get(identifier, kwargs=None):
return get_from_module(identifier, globals(), 'constraint', instantiate=True, kwargs=kwargs)
return get_from_module(identifier, globals(), 'constraint',
instantiate=True, kwargs=kwargs)
+1
Ver Arquivo
@@ -4,6 +4,7 @@ import sys
from six.moves import cPickle
from six.moves import range
def load_batch(fpath, label_key='labels'):
f = open(fpath, 'rb')
if sys.version_info < (3,):
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
from __future__ import absolute_import
from .cifar import load_batch
from .data_utils import get_file
from ..utils.data_utils import get_file
import numpy as np
import os
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
from __future__ import absolute_import
from .cifar import load_batch
from .data_utils import get_file
from ..utils.data_utils import get_file
import numpy as np
import os
+3 -52
Ver Arquivo
@@ -1,53 +1,4 @@
from __future__ import absolute_import
from __future__ import print_function
from ..utils.data_utils import *
import warnings
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 get_file(fname, origin, untar=False):
datadir_base = os.path.expanduser(os.path.join('~', '.keras'))
if not os.access(datadir_base, os.W_OK):
datadir_base = os.path.join('/tmp', '.keras')
datadir = os.path.join(datadir_base, 'datasets')
if not os.path.exists(datadir):
os.makedirs(datadir)
if untar:
untar_fpath = os.path.join(datadir, fname)
fpath = untar_fpath + '.tar.gz'
else:
fpath = os.path.join(datadir, fname)
if not os.path.exists(fpath):
print('Downloading data from', origin)
global progbar
progbar = None
def dl_progress(count, block_size, total_size):
global progbar
if progbar is None:
progbar = Progbar(total_size)
else:
progbar.update(count*block_size)
ParanoidURLopener().retrieve(origin, fpath, dl_progress)
progbar = None
if untar:
if not os.path.exists(untar_fpath):
print('Untaring file...')
tfile = tarfile.open(fpath, 'r:gz')
tfile.extractall(path=datadir)
tfile.close()
return untar_fpath
return fpath
warnings.warn('data_utils has been moved to keras.utils.data_utils.')
+5 -5
Ver Arquivo
@@ -1,7 +1,7 @@
from __future__ import absolute_import
from six.moves import cPickle
import gzip
from .data_utils import get_file
from ..utils.data_utils import get_file
from six.moves import zip
import numpy as np
@@ -60,10 +60,10 @@ def load_data(path="imdb.pkl", nb_words=None, skip_top=0,
nX.append(nx)
X = nX
X_train = X[:int(len(X) * (1 - test_split))]
y_train = labels[:int(len(X) * (1 - test_split))]
X_train = np.array(X[:int(len(X) * (1 - test_split))])
y_train = np.array(labels[:int(len(X) * (1 - test_split))])
X_test = X[int(len(X) * (1 - test_split)):]
y_test = labels[int(len(X) * (1 - test_split)):]
X_test = np.array(X[int(len(X) * (1 - test_split)):])
y_test = np.array(labels[int(len(X) * (1 - test_split)):])
return (X_train, y_train), (X_test, y_test)
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
import gzip
from .data_utils import get_file
from ..utils.data_utils import get_file
from six.moves import cPickle
import sys
+1 -1
Ver Arquivo
@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from .data_utils import get_file
from ..utils.data_utils import get_file
from six.moves import cPickle
from six.moves import zip
import numpy as np
+10
Ver Arquivo
@@ -0,0 +1,10 @@
# note: topology.Node is an internal class,
# it isn't meant to be used by Keras users.
from .topology import InputSpec
from .topology import Input
from .topology import InputLayer
from .topology import Layer
from .topology import Merge
from .topology import merge
from .topology import get_source_inputs
from .training import Model
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+52 -32
Ver Arquivo
@@ -3,58 +3,77 @@ import numpy as np
from . import backend as K
def get_fans(shape):
fan_in = shape[0] if len(shape) == 2 else np.prod(shape[1:])
fan_out = shape[1] if len(shape) == 2 else shape[0]
def get_fans(shape, dim_ordering='th'):
if len(shape) == 2:
fan_in = shape[0]
fan_out = shape[1]
elif len(shape) == 4 or len(shape) == 5:
# assuming convolution kernels (2D or 3D).
# TH kernel shape: (depth, input_depth, ...)
# TF kernel shape: (..., input_depth, depth)
if dim_ordering == 'th':
fan_in = np.prod(shape[1:])
fan_out = shape[0]
elif dim_ordering == 'tf':
fan_in = np.prod(shape[:-1])
fan_out = shape[-1]
else:
raise Exception('Invalid dim_ordering: ' + dim_ordering)
else:
# no specific assumptions
fan_in = np.sqrt(np.prod(shape))
fan_out = np.sqrt(np.prod(shape))
return fan_in, fan_out
def uniform(shape, scale=0.05):
return K.variable(np.random.uniform(low=-scale, high=scale, size=shape))
def uniform(shape, scale=0.05, name=None):
return K.variable(np.random.uniform(low=-scale, high=scale, size=shape),
name=name)
def normal(shape, scale=0.05):
return K.variable(np.random.normal(loc=0.0, scale=scale, size=shape))
def normal(shape, scale=0.05, name=None):
return K.variable(np.random.normal(loc=0.0, scale=scale, size=shape),
name=name)
def lecun_uniform(shape):
def lecun_uniform(shape, name=None, dim_ordering='th'):
''' Reference: LeCun 98, Efficient Backprop
http://yann.lecun.com/exdb/publis/pdf/lecun-98b.pdf
'''
fan_in, fan_out = get_fans(shape)
fan_in, fan_out = get_fans(shape, dim_ordering=dim_ordering)
scale = np.sqrt(3. / fan_in)
return uniform(shape, scale)
return uniform(shape, scale, name=name)
def glorot_normal(shape):
def glorot_normal(shape, name=None, dim_ordering='th'):
''' Reference: Glorot & Bengio, AISTATS 2010
'''
fan_in, fan_out = get_fans(shape)
fan_in, fan_out = get_fans(shape, dim_ordering=dim_ordering)
s = np.sqrt(2. / (fan_in + fan_out))
return normal(shape, s)
return normal(shape, s, name=name)
def glorot_uniform(shape):
fan_in, fan_out = get_fans(shape)
def glorot_uniform(shape, name=None, dim_ordering='th'):
fan_in, fan_out = get_fans(shape, dim_ordering=dim_ordering)
s = np.sqrt(6. / (fan_in + fan_out))
return uniform(shape, s)
return uniform(shape, s, name=name)
def he_normal(shape):
def he_normal(shape, name=None, dim_ordering='th'):
''' Reference: He et al., http://arxiv.org/abs/1502.01852
'''
fan_in, fan_out = get_fans(shape)
fan_in, fan_out = get_fans(shape, dim_ordering=dim_ordering)
s = np.sqrt(2. / fan_in)
return normal(shape, s)
return normal(shape, s, name=name)
def he_uniform(shape):
fan_in, fan_out = get_fans(shape)
def he_uniform(shape, name=None, dim_ordering='th'):
fan_in, fan_out = get_fans(shape, dim_ordering=dim_ordering)
s = np.sqrt(6. / fan_in)
return uniform(shape, s)
return uniform(shape, s, name=name)
def orthogonal(shape, scale=1.1):
def orthogonal(shape, scale=1.1, name=None):
''' From Lasagne. Reference: Saxe et al., http://arxiv.org/abs/1312.6120
'''
flat_shape = (shape[0], np.prod(shape[1:]))
@@ -63,25 +82,26 @@ 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 K.variable(scale * q[:shape[0], :shape[1]])
return K.variable(scale * q[:shape[0], :shape[1]], name=name)
def identity(shape, scale=1):
def identity(shape, scale=1, name=None):
if len(shape) != 2 or shape[0] != shape[1]:
raise Exception('Identity matrix initialization can only be used '
'for 2D square matrices.')
else:
return K.variable(scale * np.identity(shape[0]))
return K.variable(scale * np.identity(shape[0]), name=name)
def zero(shape):
return K.zeros(shape)
def zero(shape, name=None):
return K.zeros(shape, name=name)
def one(shape):
return K.ones(shape)
def one(shape, name=None):
return K.ones(shape, name=name)
from .utils.generic_utils import get_from_module
def get(identifier):
return get_from_module(identifier, globals(), 'initialization')
def get(identifier, **kwargs):
return get_from_module(identifier, globals(),
'initialization', kwargs=kwargs)
+10
Ver Arquivo
@@ -0,0 +1,10 @@
from __future__ import absolute_import
from ..engine import Layer, Input, InputLayer, Merge, merge, InputSpec
from .core import *
from .convolutional import *
from .recurrent import *
from .normalization import *
from .embeddings import *
from .noise import *
from .advanced_activations import *
from .wrappers import *
+132 -90
Ver Arquivo
@@ -1,13 +1,14 @@
from .. import initializations
from ..layers.core import MaskedLayer
from ..engine import Layer
from .. import backend as K
import numpy as np
class LeakyReLU(MaskedLayer):
class LeakyReLU(Layer):
'''Special version of a Rectified Linear Unit
that allows a small gradient when the unit is not active
(`f(x) = alpha*x for x < 0`).
that allows a small gradient when the unit is not active:
`f(x) = alpha * x for x < 0`,
`f(x) = x for x >= 0`.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
@@ -21,22 +22,25 @@ class LeakyReLU(MaskedLayer):
alpha: float >= 0. Negative slope coefficient.
'''
def __init__(self, alpha=0.3, **kwargs):
super(LeakyReLU, self).__init__(**kwargs)
self.supports_masking = True
self.alpha = alpha
super(LeakyReLU, self).__init__(**kwargs)
def get_output(self, train):
X = self.get_input(train)
return K.relu(X, alpha=self.alpha)
def call(self, x, mask=None):
return K.relu(x, alpha=self.alpha)
def get_config(self):
config = {"name": self.__class__.__name__,
"alpha": self.alpha}
config = {'alpha': self.alpha}
base_config = super(LeakyReLU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class PReLU(MaskedLayer):
'''
class PReLU(Layer):
'''Parametric Rectified Linear Unit:
`f(x) = alphas * x for x < 0`,
`f(x) = x for x >= 0`,
where `alphas` is a learned array with the same shape as x.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
@@ -45,42 +49,44 @@ class PReLU(MaskedLayer):
# Output shape
Same shape as the input.
# Arguments:
# Arguments
init: initialization function for the weights.
weights: initial weights, as a list of a single numpy array.
# References:
# References
- [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):
self.supports_masking = True
self.init = initializations.get(init)
self.initial_weights = weights
super(PReLU, self).__init__(**kwargs)
def build(self):
input_shape = self.input_shape[1:]
self.alphas = self.init(input_shape)
self.params = [self.alphas]
def build(self, input_shape):
self.alphas = self.init(input_shape[1:],
name='{}_alphas'.format(self.name))
self.trainable_weights = [self.alphas]
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
def get_output(self, train):
X = self.get_input(train)
pos = K.relu(X)
neg = self.alphas * (X - abs(X)) * 0.5
def call(self, x, mask=None):
pos = K.relu(x)
neg = self.alphas * (x - abs(x)) * 0.5
return pos + neg
def get_config(self):
config = {"name": self.__class__.__name__,
"init": self.init.__name__}
config = {'init': self.init.__name__}
base_config = super(PReLU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class ELU(MaskedLayer):
'''
class ELU(Layer):
'''Exponential Linear Unit:
`f(x) = alpha * (exp(x) - 1.) for x < 0`,
`f(x) = x for x >= 0`.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
@@ -96,24 +102,24 @@ class ELU(MaskedLayer):
- [Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs)](http://arxiv.org/pdf/1511.07289v1.pdf)
'''
def __init__(self, alpha=1.0, **kwargs):
self.supports_masking = True
self.alpha = K.cast_to_floatx(alpha)
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
def call(self, x, mask=None):
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}
config = {'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))
class ParametricSoftplus(Layer):
'''Parametric Softplus:
`alpha * log(1 + exp(beta * x))`
# Input shape
Arbitrary. Use the keyword argument `input_shape`
@@ -128,40 +134,43 @@ class ParametricSoftplus(MaskedLayer):
beta_init: float. Initial values of the beta weights.
weights: initial weights, as a list of 2 numpy arrays.
# References:
# References
- [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,
weights=None, **kwargs):
self.alpha_init = alpha_init
self.beta_init = beta_init
self.supports_masking = True
self.alpha_init = K.cast_to_floatx(alpha_init)
self.beta_init = K.cast_to_floatx(beta_init)
self.initial_weights = weights
super(ParametricSoftplus, self).__init__(**kwargs)
def build(self):
input_shape = self.input_shape[1:]
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]
def build(self, input_shape):
input_shape = input_shape[1:]
self.alphas = K.variable(self.alpha_init * np.ones(input_shape),
name='{}_alphas'.format(self.name))
self.betas = K.variable(self.beta_init * np.ones(input_shape),
name='{}_betas'.format(self.name))
self.trainable_weights = [self.alphas, self.betas]
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
def get_output(self, train):
X = self.get_input(train)
return K.softplus(self.betas * X) * self.alphas
def call(self, x, mask=None):
return K.softplus(self.betas * x) * self.alphas
def get_config(self):
config = {"name": self.__class__.__name__,
"alpha_init": self.alpha_init,
"beta_init": self.beta_init}
config = {'alpha_init': self.alpha_init,
'beta_init': self.beta_init}
base_config = super(ParametricSoftplus, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class ThresholdedLinear(MaskedLayer):
'''Thresholded Linear Activation.
class ThresholdedReLU(Layer):
'''Thresholded Rectified Linear Unit:
`f(x) = x for x > theta`
`f(x) = 0 otherwise`.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
@@ -175,50 +184,83 @@ class ThresholdedLinear(MaskedLayer):
theta: float >= 0. Threshold location of activation.
# References
[Zero-Bias Autoencoders and the Benefits of Co-Adapting Features](http://arxiv.org/pdf/1402.3337.pdf)
'''
def __init__(self, theta=1.0, **kwargs):
super(ThresholdedLinear, self).__init__(**kwargs)
self.theta = theta
def get_output(self, train):
X = self.get_input(train)
return K.switch(K.abs(X) < self.theta, 0, X)
def get_config(self):
config = {"name": self.__class__.__name__,
"theta": self.theta}
base_config = super(ThresholdedLinear, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class ThresholdedReLU(MaskedLayer):
'''Thresholded Rectified Activation.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
when using this layer as the first layer in a model.
# Output shape
Same shape as the input.
# Arguments
theta: float >= 0. Threshold location of activation.
# References
[Zero-Bias Autoencoders and the Benefits of Co-Adapting Features](http://arxiv.org/pdf/1402.3337.pdf)
- [Zero-Bias Autoencoders and the Benefits of Co-Adapting Features](http://arxiv.org/pdf/1402.3337.pdf)
'''
def __init__(self, theta=1.0, **kwargs):
self.supports_masking = True
self.theta = K.cast_to_floatx(theta)
super(ThresholdedReLU, self).__init__(**kwargs)
self.theta = theta
def get_output(self, train):
X = self.get_input(train)
return K.switch(X > self.theta, X, 0)
def call(self, x, mask=None):
return x * K.cast(x > self.theta, K.floatx())
def get_config(self):
config = {"name": self.__class__.__name__,
"theta": self.theta}
config = {'theta': self.theta}
base_config = super(ThresholdedReLU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class SReLU(Layer):
'''S-shaped Rectified Linear Unit.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
when using this layer as the first layer in a model.
# Output shape
Same shape as the input.
# Arguments
t_left_init: initialization function for the left part intercept
a_left_init: initialization function for the left part slope
t_right_init: initialization function for the right part intercept
a_right_init: initialization function for the right part slope
# References
- [Deep Learning with S-shaped Rectified Linear Activation Units](http://arxiv.org/abs/1512.07030)
'''
def __init__(self, t_left_init='zero', a_left_init='glorot_uniform',
t_right_init='glorot_uniform', a_right_init='one', **kwargs):
self.supports_masking = True
self.t_left_init = t_left_init
self.a_left_init = a_left_init
self.t_right_init = t_right_init
self.a_right_init = a_right_init
super(SReLU, self).__init__(**kwargs)
def build(self, input_shape):
input_shape = input_shape[1:]
t_left_init = initializations.get(self.t_left_init)
a_left_init = initializations.get(self.a_left_init)
t_right_init = initializations.get(self.t_right_init)
a_right_init = initializations.get(self.a_right_init)
self.t_left = t_left_init(input_shape,
name='{}_t_left'.format(self.name))
self.a_left = a_left_init(input_shape,
name='{}_a_left'.format(self.name))
self.t_right = t_right_init(input_shape,
name='{}_t_right'.format(self.name))
self.a_right = a_right_init(input_shape,
name='{}_a_right'.format(self.name))
# ensure the the right part is always to the right of the left
self.t_right_actual = self.t_left + abs(self.t_right)
self.trainable_weights = [self.t_left, self.a_left,
self.t_right, self.a_right]
def call(self, x, mask=None):
Y_left_and_center = self.t_left + K.relu(x - self.t_left,
self.a_left,
self.t_right_actual - self.t_left)
Y_right = K.relu(x - self.t_right_actual) * self.a_right
return Y_left_and_center + Y_right
def get_config(self):
config = {'t_left_init': self.t_left_init,
'a_left_init': self.a_left_init,
't_right_init': self.t_right_init,
'a_right_init': self.a_right_init}
base_config = super(SReLU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
-529
Ver Arquivo
@@ -1,529 +0,0 @@
# -*- coding: utf-8 -*-
from __future__ import absolute_import
from __future__ import print_function
from collections import OrderedDict
from .. import backend as K
from ..layers.core import Layer, Merge, Siamese, SiameseHead
from six.moves import range
class Sequential(Layer):
'''The Sequential container is a linear stack of layers.
Apart from the `add` methods and the `layers` constructor argument,
the API is identical to that of the `Layer` class.
This class is also the basis for the `keras.models.Sequential` model.
# Arguments
layers: list of layers to be added to the container.
'''
def __init__(self, layers=[]):
self.layers = []
self.layer_cache = {}
for layer in layers:
self.add(layer)
self._cache_enabled = True
def __call__(self, X, mask=None, train=False):
# turn off layer cache temporarily
tmp_cache_enabled = self.cache_enabled
self.cache_enabled = False
# recursively search for a layer which is not a Sequential model
layer = self
while issubclass(layer.__class__, Sequential):
layer = layer.layers[0]
# set temporary input to first layer
tmp_input = layer.get_input
tmp_mask = None
layer.get_input = lambda _: X
if hasattr(layer, 'get_input_mask'):
tmp_mask = layer.get_input_mask
layer.get_input_mask = lambda _: mask
Y = self.get_output(train=train)
# return input from first layer to what it was
layer.get_input = tmp_input
if hasattr(layer, 'get_input_mask'):
layer.get_input_mask = tmp_mask
self.cache_enabled = tmp_cache_enabled
return Y
@property
def cache_enabled(self):
return self._cache_enabled
@cache_enabled.setter
def cache_enabled(self, value):
self._cache_enabled = value
for l in self.layers:
l.cache_enabled = value
def set_previous(self, layer):
self.layers[0].previous = layer
def add(self, layer):
layer.layer_cache = self.layer_cache
self.layers.append(layer)
if len(self.layers) > 1:
self.layers[-1].set_previous(self.layers[-2])
if not hasattr(self.layers[0], 'input'):
self.set_input()
@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 state_updates(self):
"""
Return the `updates` from all layers in the sequence that are
stateful. This is useful for separating _training_ updates and
_prediction_ updates for when we need to update a layers internal state
during a stateful prediction.
"""
state_updates = []
for l in self.layers:
if getattr(l, 'stateful', False):
state_updates += l.get_params()[3]
return state_updates
def reset_states(self):
for l in self.layers:
if hasattr(l, 'reset_states') and getattr(l, 'stateful', False):
l.reset_states()
@property
def output_shape(self):
return self.layers[-1].output_shape
def get_output(self, train=False):
return self.layers[-1].get_output(train)
def set_input(self):
for l in self.layers:
if hasattr(l, 'input'):
ndim = K.ndim(l.input)
self.layers[0].input = K.placeholder(ndim=ndim)
break
def get_input(self, train=False):
if not hasattr(self.layers[0], 'input'):
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()
def get_weights(self):
weights = []
for layer in self.layers:
weights += layer.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):
return {'name': self.__class__.__name__,
'layers': [layer.get_config() for layer in self.layers]}
def count_params(self):
return sum([layer.count_params() for layer in self.layers])
class Graph(Layer):
'''Implement a NN graph with arbitrary layer connections,
arbitrary number of inputs and arbitrary number of outputs.
This class is also the basis for the `keras.models.Graph` model.
Note: `Graph` can only be used as a layer
(connect, input, get_input, get_output)
when it has exactly one input and one output.
'''
def __init__(self):
self.namespace = set() # strings
self.nodes = OrderedDict() # layer-like
self.inputs = {} # layer-like
self.input_order = [] # strings
self.outputs = {} # layer-like
self.output_order = [] # strings
self.input_config = [] # dicts
self.output_config = [] # dicts
self.node_config = [] # dicts
self.layer_cache = {}
@property
def nb_input(self):
return len(self.inputs)
@property
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
@property
def state_updates(self):
"""
Return the `updates` from all nodes in that graph for nodes that are
stateful. This is useful for separating _training_ updates and
_prediction_ updates for when we need to update a layers internal state
during a stateful prediction.
"""
state_updates = []
for l in self.nodes.values():
if getattr(l, 'stateful', False):
state_updates += l.get_params()[3]
return state_updates
def reset_states(self):
for l in self.nodes.values():
if hasattr(l, 'reset_states') and getattr(l, 'stateful', False):
l.reset_states()
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.')
if self.nb_input == 1:
self.inputs[self.input_order[0]].set_previous(layer)
else:
if not connection_map:
raise Exception('Cannot attach multi-input layer: '
'no connection_map provided.')
for k, v in connection_map.items():
if k in self.inputs and v in layer.outputs:
self.inputs[k].set_previous(layer.outputs[v])
else:
raise Exception('Invalid connection map.')
def get_input(self, train=False):
if len(self.inputs) == len(self.outputs) == 1:
return self.inputs[self.input_order[0]].get_input(train)
else:
return dict([(k, v.get_input(train)) for k, v in self.inputs.items()])
@property
def input(self):
return self.get_input()
@property
def output_shape(self):
if self.nb_output == 1:
# return tuple
return self.outputs[self.output_order[0]].output_shape
else:
# return dictionary mapping output names to shape tuples
return dict([(k, v.output_shape) for k, v in self.outputs.items()])
def get_output(self, train=False):
if len(self.inputs) == len(self.outputs) == 1:
return self.outputs[self.output_order[0]].get_output(train)
else:
return dict([(k, v.get_output(train)) for k, v in self.outputs.items()])
def add_input(self, name, input_shape=None,
batch_input_shape=None, dtype='float'):
'''Add an input to the graph.
# Arguments:
name: string. The name of the new input. Must be unique in the graph.
input_shape: a tuple of integers, the expected shape of the input samples.
Does not include the batch size.
batch_input_shape: a tuple of integers, the expected shape of the
whole input batch, including the batch size.
dtype: 'float' or 'int'.
'''
if name in self.namespace:
raise Exception('Duplicate node identifier: ' + name)
self.namespace.add(name)
self.input_order.append(name)
layer = Layer() # empty layer
if input_shape:
layer.set_input_shape((None,) + tuple(input_shape))
elif batch_input_shape:
layer.set_input_shape(batch_input_shape)
if dtype == 'float':
layer.input = K.placeholder(shape=layer.input_shape, name=name)
else:
if (input_shape and len(input_shape) == 1) or (batch_input_shape and len(batch_input_shape) == 2):
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).')
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, dot_axes=-1,
create_output=False):
'''Add a node in the graph. It can be connected to multiple
inputs, which will first be merged into one tensor
according to the mode specified.
# Arguments
layer: the layer at the node.
name: name for the node.
input: when connecting the layer to a single input,
this is the name of the incoming node.
inputs: when connecting the layer to multiple inputs,
this is a list of names of incoming nodes.
merge_mode: one of {concat, sum, dot, ave, mul}
concat_axis: when `merge_mode=='concat'`, this is the
input concatenation axis.
dot_axes: when `merge_mode='dot'`, this is the contraction axes
specification; see the `Merge layer for details.
create_output: boolean. Set this to `True` if you want the output
of your node to be an output of the graph.
'''
if name in self.namespace:
raise Exception('Duplicate node identifier: ' + name)
if input:
if input not in self.namespace:
raise Exception('Unknown node/input identifier: ' + input)
if input in self.nodes:
layer.set_previous(self.nodes[input])
elif input in self.inputs:
layer.set_previous(self.inputs[input])
if inputs:
to_merge = []
for n in inputs:
if n in self.nodes:
to_merge.append(self.nodes[n])
elif n in self.inputs:
to_merge.append(self.inputs[n])
else:
raise Exception('Unknown identifier: ' + n)
merge = Merge(to_merge, mode=merge_mode,
concat_axis=concat_axis, dot_axes=dot_axes)
layer.set_previous(merge)
self.namespace.add(name)
layer.layer_cache = self.layer_cache
self.nodes[name] = layer
self.node_config.append({'name': name,
'input': input,
'inputs': inputs,
'merge_mode': merge_mode,
'concat_axis': concat_axis,
'dot_axes': dot_axes,
'create_output': create_output})
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 share a same layer across multiple nodes.
Supposed, for instance, that you want to apply one same `Dense`
layer after to the output of two different nodes.
You can then add the `Dense` layer as a shared node.
# Arguments
layer: The layer to be shared across multiple inputs
name: Name of the shared node
inputs: List of names of input nodes
merge_mode: Same meaning as `merge_mode` argument of `add_node()`
concat_axis: Same meaning as `concat_axis` argument of `add_node()`
dot_axes: Same meaning as `dot_axes` argument of `add_node()`
outputs: Used when `merge_mode=None`. Names for the output nodes.
create_output: Same meaning as `create_output` argument of `add_node()`.
'''
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 Exception('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,
is_graph=True)
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]
self.namespace.add(sh_name)
self.nodes[sh_name] = sh
self.node_config.append({'name': sh_name,
'inputs': [name],
'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, dot_axes=-1):
'''Add an output to the graph.
This output can merge several node outputs into a single output.
# Arguments
name: name of the output.
input: when connecting the layer to a single input,
this is the name of the incoming node.
inputs: when connecting the layer to multiple inputs,
this is a list of names of incoming nodes.
merge_mode: one of {concat, sum, dot, ave, mul}
concat_axis: when `merge_mode=='concat'`, this is the
input concatenation axis.
dot_axes: when `merge_mode='dot'`, this is the contraction axes
specification; see the `Merge layer for details.
'''
if name in self.output_order:
raise Exception('Duplicate output identifier: ' + name)
if input:
if input not in self.namespace:
raise Exception('Unknown node/input identifier: ' + input)
if input in self.nodes:
self.outputs[name] = self.nodes[input]
elif input in self.inputs:
self.outputs[name] = self.inputs[input]
if inputs:
to_merge = []
for n in inputs:
if n not in self.nodes:
raise Exception('Unknown identifier: ' + n)
to_merge.append(self.nodes[n])
merge = Merge(to_merge, mode=merge_mode,
concat_axis=concat_axis, dot_axes=dot_axes)
self.outputs[name] = merge
self.output_order.append(name)
self.output_config.append({'name': name,
'input': input,
'inputs': inputs,
'merge_mode': merge_mode,
'concat_axis': concat_axis,
'dot_axes': dot_axes})
def get_config(self):
return {'name': self.__class__.__name__,
'input_config': self.input_config,
'node_config': self.node_config,
'output_config': self.output_config,
'input_order': self.input_order,
'output_order': self.output_order,
'nodes': dict([(c['name'], self.nodes[c['name']].get_config()) for c in self.node_config])}
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:]
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+672 -1505
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+59 -36
Ver Arquivo
@@ -1,10 +1,8 @@
from __future__ import absolute_import
from .. import backend as K
from .. import activations, initializations, regularizers, constraints
from ..layers.core import Layer, MaskedLayer
from ..constraints import unitnorm
from .. import initializations, regularizers, constraints
from ..engine import Layer
class Embedding(Layer):
@@ -13,11 +11,21 @@ class Embedding(Layer):
This layer can only be used as the first layer in a model.
# Input shape
2D tensor with shape: `(nb_samples, sequence_length)`.
# Example
# Output shape
3D tensor with shape: `(nb_samples, sequence_length, output_dim)`.
```python
model = Sequential()
model.add(Embedding(1000, 64, input_length=10))
# the model will take as input an integer matrix of size (batch, input_length).
# the largest integer (i.e. word index) in the input should be no larger than 1000 (vocabulary size).
# now model.output_shape == (None, 10, 64), where None is the batch dimension.
input_array = np.random.randint(1000, size=(32, 10))
model.compile('rmsprop', 'mse')
output_array = model.predict(input_array)
assert output_array.shape == (32, 10, 64)
```
# Arguments
input_dim: int >= 0. Size of the vocabulary, ie.
@@ -42,6 +50,16 @@ class Embedding(Layer):
This argument is required if you are going to connect
`Flatten` then `Dense` layers upstream
(without it, the shape of the dense outputs cannot be computed).
dropout: float between 0 and 1. Fraction of the embeddings to drop.
# Input shape
2D tensor with shape: `(nb_samples, sequence_length)`.
# Output shape
3D tensor with shape: `(nb_samples, sequence_length, output_dim)`.
# References
- [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
'''
input_ndim = 2
@@ -50,12 +68,13 @@ class Embedding(Layer):
W_regularizer=None, activity_regularizer=None,
W_constraint=None,
mask_zero=False,
weights=None, **kwargs):
weights=None, dropout=0., **kwargs):
self.input_dim = input_dim
self.output_dim = output_dim
self.init = initializations.get(init)
self.input_length = input_length
self.mask_zero = mask_zero
self.dropout = dropout
self.W_constraint = constraints.get(W_constraint)
self.constraints = [self.W_constraint]
@@ -63,15 +82,17 @@ class Embedding(Layer):
self.W_regularizer = regularizers.get(W_regularizer)
self.activity_regularizer = regularizers.get(activity_regularizer)
if 0. < self.dropout < 1.:
self.uses_learning_phase = True
self.initial_weights = weights
kwargs['input_shape'] = (self.input_dim,)
kwargs['input_shape'] = (self.input_length,)
kwargs['input_dtype'] = 'int32'
super(Embedding, self).__init__(**kwargs)
def build(self):
self.input = K.placeholder(shape=(self.input_shape[0], self.input_length),
dtype='int32')
self.W = self.init((self.input_dim, self.output_dim))
self.params = [self.W]
def build(self, input_shape):
self.W = self.init((self.input_dim, self.output_dim),
name='{}_W'.format(self.name))
self.trainable_weights = [self.W]
self.regularizers = []
if self.W_regularizer:
self.W_regularizer.set_param(self.W)
@@ -84,33 +105,35 @@ class Embedding(Layer):
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
def get_output_mask(self, train=None):
X = self.get_input(train)
def compute_mask(self, x, mask=None):
if not self.mask_zero:
return None
else:
if K._BACKEND == "tensorflow":
raise Exception("Masking is Theano-only for the time being.")
return K.ones_like(X) * (1 - K.equal(X, 0))
return K.not_equal(x, 0)
@property
def output_shape(self):
return (self.input_shape[0], self.input_length, self.output_dim)
def get_output_shape_for(self, input_shape):
return (input_shape[0], self.input_length, self.output_dim)
def get_output(self, train=False):
X = self.get_input(train)
out = K.gather(self.W, X)
def call(self, x, mask=None):
if 0. < self.dropout < 1.:
retain_p = 1. - self.dropout
B = K.random_binomial((self.input_dim,), p=retain_p) * (1. / retain_p)
B = K.expand_dims(B)
W = K.in_train_phase(self.W * B, self.W)
else:
W = self.W
out = K.gather(W, x)
return out
def get_config(self):
config = {"name": self.__class__.__name__,
"input_dim": self.input_dim,
"output_dim": self.output_dim,
"init": self.init.__name__,
"input_length": self.input_length,
"mask_zero": self.mask_zero,
"activity_regularizer": self.activity_regularizer.get_config() if self.activity_regularizer else None,
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
"W_constraint": self.W_constraint.get_config() if self.W_constraint else None}
config = {'input_dim': self.input_dim,
'output_dim': self.output_dim,
'init': self.init.__name__,
'input_length': self.input_length,
'mask_zero': self.mask_zero,
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
'dropout': self.dropout}
base_config = super(Embedding, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+52 -46
Ver Arquivo
@@ -1,9 +1,9 @@
from __future__ import absolute_import
from .core import MaskedLayer
from ..engine import Layer
from .. import backend as K
class GaussianNoise(MaskedLayer):
class GaussianNoise(Layer):
'''Apply to the input an additive zero-centred gaussian noise with
standard deviation `sigma`. This is useful to mitigate overfitting
(you could see it as a kind of random data augmentation).
@@ -12,6 +12,44 @@ class GaussianNoise(MaskedLayer):
As it is a regularization layer, it is only active at training time.
# Arguments
sigma: float, standard deviation of the noise distribution.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
when using this layer as the first layer in a model.
# Output shape
Same shape as input.
'''
def __init__(self, sigma, **kwargs):
self.supports_masking = True
self.sigma = sigma
self.uses_learning_phase = True
super(GaussianNoise, self).__init__(**kwargs)
def call(self, x, mask=None):
noise_x = x + K.random_normal(shape=K.shape(x),
mean=0.,
std=self.sigma)
return K.in_train_phase(noise_x, x)
def get_config(self):
config = {'sigma': self.sigma}
base_config = super(GaussianNoise, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class GaussianDropout(Layer):
'''Apply to the input an multiplicative one-centred gaussian noise
with standard deviation `sqrt(p/(1-p))`.
As it is a regularization layer, it is only active at training time.
# Arguments
p: float, drop probability (as with `Dropout`).
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
@@ -20,56 +58,24 @@ class GaussianNoise(MaskedLayer):
# Output shape
Same shape as input.
# Arguments
sigma: float, standard deviation of the noise distribution.
'''
def __init__(self, sigma, **kwargs):
super(GaussianNoise, self).__init__(**kwargs)
self.sigma = sigma
def get_output(self, train=False):
X = self.get_input(train)
if not train or self.sigma == 0:
return X
else:
return X + K.random_normal(shape=K.shape(X),
mean=0.,
std=self.sigma)
def get_config(self):
config = {"name": self.__class__.__name__,
"sigma": self.sigma}
base_config = super(GaussianNoise, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class GaussianDropout(MaskedLayer):
'''Apply to the input an multiplicative one-centred gaussian noise
with standard deviation `sqrt(p/(1-p))`.
As it is a regularization layer, it is only active at training time.
# Arguments
p: float, drop probability (as with `Dropout`).
# References:
# References
[Dropout: A Simple Way to Prevent Neural Networks from Overfitting Srivastava, Hinton, et al. 2014](http://www.cs.toronto.edu/~rsalakhu/papers/srivastava14a.pdf)
'''
def __init__(self, p, **kwargs):
super(GaussianDropout, self).__init__(**kwargs)
self.supports_masking = True
self.p = p
if 0 < p < 1:
self.uses_learning_phase = True
super(GaussianDropout, self).__init__(**kwargs)
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), for consistency
X *= K.random_normal(shape=K.shape(X), mean=1.0,
std=self.p / (1.0 - self.p))
return X
def call(self, x, mask=None):
if 0 < self.p < 1:
noise_x = x * K.random_normal(shape=K.shape(x), mean=1.0,
std=K.sqrt(self.p / (1.0 - self.p)))
return K.in_train_phase(noise_x, x)
return x
def get_config(self):
config = {"name": self.__class__.__name__,
"p": self.p}
config = {'p': self.p}
base_config = super(GaussianDropout, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+80 -53
Ver Arquivo
@@ -1,4 +1,4 @@
from ..layers.core import Layer
from ..engine import Layer, InputSpec
from .. import initializations
from .. import backend as K
@@ -8,6 +8,36 @@ class BatchNormalization(Layer):
i.e. applies a transformation that maintains the mean activation
close to 0 and the activation standard deviation close to 1.
# Arguments
epsilon: small float > 0. Fuzz parameter.
mode: integer, 0 or 1.
- 0: feature-wise normalization.
Each feature map in the input will
be normalized separately. The axis on which
to normalize is specified by the `axis` argument.
Note that if the input is a 4D image tensor
using Theano conventions (samples, channels, rows, cols)
then you should set `axis` to `1` to normalize along
the channels axis.
- 1: sample-wise normalization. This mode assumes a 2D input.
axis: integer, axis along which to normalize in mode 0. For instance,
if your input tensor has shape (samples, channels, rows, cols),
set axis to 1 to normalize per feature map (channels axis).
momentum: momentum in the computation of the
exponential average of the mean and standard deviation
of the data, for feature-wise normalization.
weights: Initialization weights.
List of 2 numpy arrays, with shapes:
`[(input_shape,), (input_shape,)]`
beta_init: name of initialization function for shift parameter
(see [initializations](../initializations.md)), or alternatively,
Theano/TensorFlow function to use for weights initialization.
This parameter is only relevant if you don't pass a `weights` argument.
gamma_init: name of initialization function for scale parameter (see
[initializations](../initializations.md)), or alternatively,
Theano/TensorFlow function to use for weights initialization.
This parameter is only relevant if you don't pass a `weights` argument.
# Input shape
Arbitrary. Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
@@ -16,84 +46,81 @@ class BatchNormalization(Layer):
# Output shape
Same shape as input.
# Arguments
epsilon: small float > 0. Fuzz parameter.
mode: integer, 0 or 1.
- 0: feature-wise normalization.
If the input has multiple feature dimensions,
each will be normalized separately
(e.g. for an image input with shape
`(channels, rows, cols)`,
each combination of a channel, row and column
will be normalized separately).
- 1: sample-wise normalization. This mode assumes a 2D input.
momentum: momentum in the computation of the
exponential average of the mean and standard deviation
of the data, for feature-wise normalization.
weights: Initialization weights.
List of 2 numpy arrays, with shapes:
`[(input_shape,), (input_shape,)]`
# References
- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](http://arxiv.org/pdf/1502.03167v3.pdf)
'''
def __init__(self, epsilon=1e-6, mode=0, momentum=0.9,
weights=None, **kwargs):
self.init = initializations.get("uniform")
def __init__(self, epsilon=1e-6, mode=0, axis=-1, momentum=0.9,
weights=None, beta_init='zero', gamma_init='one', **kwargs):
self.beta_init = initializations.get(beta_init)
self.gamma_init = initializations.get(gamma_init)
self.epsilon = epsilon
self.mode = mode
self.axis = axis
self.momentum = momentum
self.initial_weights = weights
self.uses_learning_phase = True
super(BatchNormalization, self).__init__(**kwargs)
def build(self):
input_shape = self.input_shape # starts with samples axis
input_shape = input_shape[1:]
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
shape = (input_shape[self.axis],)
self.gamma = self.init(input_shape)
self.beta = K.zeros(input_shape)
self.gamma = self.gamma_init(shape, name='{}_gamma'.format(self.name))
self.beta = self.beta_init(shape, name='{}_beta'.format(self.name))
self.trainable_weights = [self.gamma, self.beta]
self.params = [self.gamma, self.beta]
self.running_mean = K.zeros(input_shape)
self.running_std = K.ones(input_shape)
self.running_mean = K.zeros(shape,
name='{}_running_mean'.format(self.name))
self.running_std = K.ones(shape,
name='{}_running_std'.format(self.name))
self.non_trainable_weights = [self.running_mean, self.running_std]
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
del self.initial_weights
def get_weights(self):
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):
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)
def call(self, x, mask=None):
if self.mode == 0:
m = K.mean(X, axis=0)
std = K.mean(K.square(X - m) + self.epsilon, axis=0)
input_shape = self.input_spec[0].shape
reduction_axes = list(range(len(input_shape)))
del reduction_axes[self.axis]
broadcast_shape = [1] * len(input_shape)
broadcast_shape[self.axis] = input_shape[self.axis]
# case: train mode (uses stats of the current batch)
mean = K.mean(x, axis=reduction_axes)
brodcast_mean = K.reshape(mean, broadcast_shape)
std = K.mean(K.square(x - brodcast_mean) + self.epsilon, axis=reduction_axes)
std = K.sqrt(std)
mean_update = self.momentum * self.running_mean + (1-self.momentum) * m
brodcast_std = K.reshape(std, broadcast_shape)
mean_update = self.momentum * self.running_mean + (1-self.momentum) * mean
std_update = self.momentum * self.running_std + (1-self.momentum) * std
self.updates = [(self.running_mean, mean_update),
(self.running_std, std_update)]
X_normed = ((X - self.running_mean) /
(self.running_std + self.epsilon))
x_normed = (x - brodcast_mean) / (brodcast_std + self.epsilon)
# case: test mode (uses running averages)
brodcast_running_mean = K.reshape(self.running_mean, broadcast_shape)
brodcast_running_std = K.reshape(self.running_std, broadcast_shape)
x_normed_running = ((x - brodcast_running_mean) / (brodcast_running_std + self.epsilon))
# pick the normalized form of x corresponding to the training phase
x_normed = K.in_train_phase(x_normed, x_normed_running)
out = K.reshape(self.gamma, broadcast_shape) * x_normed + K.reshape(self.beta, broadcast_shape)
elif self.mode == 1:
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
# sample-wise normalization
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
def get_config(self):
config = {"name": self.__class__.__name__,
"epsilon": self.epsilon,
config = {"epsilon": self.epsilon,
"mode": self.mode,
"axis": self.axis,
"momentum": self.momentum}
base_config = super(BatchNormalization, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+472 -131
Ver Arquivo
@@ -3,25 +3,67 @@ from __future__ import absolute_import
import numpy as np
from .. import backend as K
from .. import activations, initializations
from ..layers.core import MaskedLayer
from .. import activations, initializations, regularizers
from ..engine import Layer, InputSpec
class Recurrent(MaskedLayer):
def time_distributed_dense(x, w, b=None, dropout=None,
input_dim=None, output_dim=None, timesteps=None):
'''Apply y.w + b for every temporal slice y of x.
'''
if not input_dim:
# won't work with TensorFlow
input_dim = K.shape(x)[2]
if not timesteps:
# won't work with TensorFlow
timesteps = K.shape(x)[1]
if not output_dim:
# won't work with TensorFlow
output_dim = K.shape(w)[1]
if dropout is not None and 0. < dropout < 1.:
# apply the same dropout pattern at every timestep
ones = K.ones_like(K.reshape(x[:, 0, :], (-1, input_dim)))
dropout_matrix = K.dropout(ones, dropout)
expanded_dropout_matrix = K.repeat(dropout_matrix, timesteps)
x = K.in_train_phase(x * expanded_dropout_matrix, x)
# collapse time dimension and batch dimension together
x = K.reshape(x, (-1, input_dim))
x = K.dot(x, w)
if b:
x = x + b
# reshape to 3D tensor
x = K.reshape(x, (-1, timesteps, output_dim))
return x
class Recurrent(Layer):
'''Abstract base class for recurrent layers.
Do not use in a model -- it's not a functional layer!
Do not use in a model -- it's not a valid layer!
Use its children classes `LSTM`, `GRU` and `SimpleRNN` instead.
All recurrent layers (GRU, LSTM, SimpleRNN) also
All recurrent layers (`LSTM`, `GRU`, `SimpleRNN`) also
follow the specifications of this class and accept
the keyword arguments listed below.
# Input shape
3D tensor with shape `(nb_samples, timesteps, input_dim)`.
# Example
# Output shape
- if `return_sequences`: 3D tensor with shape
`(nb_samples, timesteps, output_dim)`.
- else, 2D tensor with shape `(nb_samples, output_dim)`.
```python
# as the first layer in a Sequential model
model = Sequential()
model.add(LSTM(32, input_shape=(10, 64)))
# now model.output_shape == (None, 10, 32)
# note: `None` is the batch dimension.
# the following is identical:
model = Sequential()
model.add(LSTM(32, input_dim=64, input_length=10))
# for subsequent layers, not need to specify the input size:
model.add(LSTM(16))
```
# Arguments
weights: list of numpy arrays to set as initial weights.
@@ -34,6 +76,17 @@ class Recurrent(MaskedLayer):
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.
unroll: Boolean (default False). If True, the network will be unrolled,
else a symbolic loop will be used. When using TensorFlow, the network
is always unrolled, so this argument does not do anything.
Unrolling can speed-up a RNN, although it tends to be more memory-intensive.
Unrolling is only suitable for short sequences.
consume_less: one of "cpu", "mem". If set to "cpu", the RNN will use
an implementation that uses fewer, larger matrix products,
thus running faster (at least on CPU) but consuming more memory.
If set to "mem", the RNN will use more matrix products,
but smaller ones, thus running slower (may actually be faster on GPU)
while consuming less memory.
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.
@@ -47,12 +100,19 @@ class Recurrent(MaskedLayer):
at the level of the first layer
(e.g. via the `input_shape` argument)
# 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`.
**Note:** for the time being, masking is only supported with Theano.
# TensorFlow warning
For the time being, when using the TensorFlow backend,
@@ -79,77 +139,92 @@ class Recurrent(MaskedLayer):
To reset the states of your model, call `.reset_states()` on either
a specific layer, or on your entire model.
'''
input_ndim = 3
# Note on using dropout with TensorFlow
When using the TensorFlow backend, specify a fixed batch size for your model
following the notes on statefulness RNNs.
'''
def __init__(self, weights=None,
return_sequences=False, go_backwards=False, stateful=False,
unroll=False, consume_less='cpu',
input_dim=None, input_length=None, **kwargs):
self.return_sequences = return_sequences
self.initial_weights = weights
self.go_backwards = go_backwards
self.stateful = stateful
self.unroll = unroll
self.consume_less = consume_less
self.supports_masking = True
self.input_spec = [InputSpec(ndim=3)]
self.input_dim = input_dim
self.input_length = input_length
if self.input_dim:
kwargs['input_shape'] = (self.input_length, self.input_dim)
super(Recurrent, self).__init__(**kwargs)
def get_output_mask(self, train=False):
if self.return_sequences:
return super(Recurrent, self).get_output_mask(train)
else:
return None
@property
def output_shape(self):
input_shape = self.input_shape
def get_output_shape_for(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 compute_mask(self, input, mask):
if self.return_sequences:
return mask
else:
return None
def step(self, x, states):
raise NotImplementedError
def get_initial_states(self, X):
def get_constants(self, x):
return []
def get_initial_states(self, x):
# build an all-zero tensor of shape (samples, output_dim)
initial_state = K.zeros_like(X) # (samples, timesteps, input_dim)
initial_state = K.zeros_like(x) # (samples, timesteps, input_dim)
initial_state = K.sum(initial_state, axis=1) # (samples, input_dim)
reducer = K.zeros((self.input_dim, self.output_dim))
initial_state = K.dot(initial_state, reducer) # (samples, output_dim)
initial_states = [initial_state for _ in range(len(self.states))]
return initial_states
def get_output(self, train=False):
def preprocess_input(self, x):
return x
def call(self, x, mask=None):
# input shape: (nb_samples, time (padded with zeros), input_dim)
X = self.get_input(train)
assert K.ndim(X) == 3
# note that the .build() method of subclasses MUST define
# self.input_sepc with a complete input shape.
input_shape = self.input_spec[0].shape
if K._BACKEND == 'tensorflow':
if not self.input_shape[1]:
raise Exception('When using TensorFlow, you should define ' +
'explicitly the number of timesteps of ' +
'your sequences. Make sure the first layer ' +
'has a "batch_input_shape" argument ' +
'including the samples axis.')
mask = self.get_output_mask(train)
if mask:
# apply mask
X *= K.cast(K.expand_dims(mask), X.dtype)
masking = True
else:
masking = False
if not input_shape[1]:
raise Exception('When using TensorFlow, you should define '
'explicitly the number of timesteps of '
'your sequences.\n'
'If your first layer is an Embedding, '
'make sure to pass it an "input_length" '
'argument. Otherwise, make sure '
'the first layer has '
'an "input_shape" or "batch_input_shape" '
'argument, including the time axis. '
'Found input shape at layer ' + self.name +
': ' + str(input_shape))
if self.stateful:
initial_states = self.states
else:
initial_states = self.get_initial_states(X)
initial_states = self.get_initial_states(x)
constants = self.get_constants(x)
preprocessed_input = self.preprocess_input(x)
last_output, outputs, states = K.rnn(self.step, X, initial_states,
last_output, outputs, states = K.rnn(self.step, preprocessed_input,
initial_states,
go_backwards=self.go_backwards,
masking=masking)
mask=mask,
constants=constants,
unroll=self.unroll,
input_length=input_shape[1])
if self.stateful:
self.updates = []
for i in range(len(states)):
@@ -161,18 +236,23 @@ class Recurrent(MaskedLayer):
return last_output
def get_config(self):
config = {"name": self.__class__.__name__,
"return_sequences": self.return_sequences,
"input_dim": self.input_dim,
"input_length": self.input_length,
"go_backwards": self.go_backwards,
"stateful": self.stateful}
config = {'return_sequences': self.return_sequences,
'go_backwards': self.go_backwards,
'stateful': self.stateful,
'unroll': self.unroll,
'consume_less': self.consume_less}
if self.stateful:
config['batch_input_shape'] = self.input_spec[0].shape
else:
config['input_dim'] = self.input_dim
config['input_length'] = self.input_length
base_config = super(Recurrent, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
class SimpleRNN(Recurrent):
'''Fully-connected RNN where the output is to fed back to input.
'''Fully-connected RNN where the output is to be fed back to input.
# Arguments
output_dim: dimension of the internal projections and the final output.
@@ -183,18 +263,38 @@ class SimpleRNN(Recurrent):
activation: activation function.
Can be the name of an existing function (str),
or a Theano function (see: [activations](../activations.md)).
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the input weights matrices.
U_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the recurrent weights matrices.
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
applied to the bias.
dropout_W: float between 0 and 1. Fraction of the input units to drop for input gates.
dropout_U: float between 0 and 1. Fraction of the input units to drop for recurrent connections.
# References
- [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
'''
def __init__(self, output_dim,
init='glorot_uniform', inner_init='orthogonal',
activation='sigmoid', **kwargs):
activation='tanh',
W_regularizer=None, U_regularizer=None, b_regularizer=None,
dropout_W=0., dropout_U=0., **kwargs):
self.output_dim = output_dim
self.init = initializations.get(init)
self.inner_init = initializations.get(inner_init)
self.activation = activations.get(activation)
self.W_regularizer = regularizers.get(W_regularizer)
self.U_regularizer = regularizers.get(U_regularizer)
self.b_regularizer = regularizers.get(b_regularizer)
self.dropout_W, self.dropout_U = dropout_W, dropout_U
if self.dropout_W or self.dropout_U:
self.uses_learning_phase = True
super(SimpleRNN, self).__init__(**kwargs)
def build(self):
input_shape = self.input_shape
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
if self.stateful:
self.reset_states()
else:
@@ -203,10 +303,24 @@ class SimpleRNN(Recurrent):
input_dim = input_shape[2]
self.input_dim = input_dim
self.W = self.init((input_dim, self.output_dim))
self.U = self.inner_init((self.output_dim, self.output_dim))
self.b = K.zeros((self.output_dim,))
self.params = [self.W, self.U, self.b]
self.W = self.init((input_dim, self.output_dim),
name='{}_W'.format(self.name))
self.U = self.inner_init((self.output_dim, self.output_dim),
name='{}_U'.format(self.name))
self.b = K.zeros((self.output_dim,), name='{}_b'.format(self.name))
self.regularizers = []
if self.W_regularizer:
self.W_regularizer.set_param(self.W)
self.regularizers.append(self.W_regularizer)
if self.U_regularizer:
self.U_regularizer.set_param(self.U)
self.regularizers.append(self.U_regularizer)
if self.b_regularizer:
self.b_regularizer.set_param(self.b)
self.regularizers.append(self.b_regularizer)
self.trainable_weights = [self.W, self.U, self.b]
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
@@ -214,30 +328,70 @@ class SimpleRNN(Recurrent):
def reset_states(self):
assert self.stateful, 'Layer must be stateful.'
input_shape = self.input_shape
input_shape = self.input_spec[0].shape
if not input_shape[0]:
raise Exception('If a RNN is stateful, a complete ' +
'input_shape must be provided ' +
'(including batch size).')
'input_shape must be provided (including batch size).')
if hasattr(self, 'states'):
K.set_value(self.states[0],
np.zeros((input_shape[0], self.output_dim)))
else:
self.states = [K.zeros((input_shape[0], self.output_dim))]
def preprocess_input(self, x):
if self.consume_less == 'cpu':
input_shape = self.input_spec[0].shape
input_dim = input_shape[2]
timesteps = input_shape[1]
return time_distributed_dense(x, self.W, self.b, self.dropout_W,
input_dim, self.output_dim,
timesteps)
else:
return x
def step(self, x, states):
# states only contains the previous output.
assert len(states) == 1
prev_output = states[0]
h = K.dot(x, self.W) + self.b
output = self.activation(h + K.dot(prev_output, self.U))
B_U = states[1]
B_W = states[2]
if self.consume_less == 'cpu':
h = x
else:
h = K.dot(x * B_W, self.W) + self.b
output = self.activation(h + K.dot(prev_output * B_U, self.U))
return output, [output]
def get_constants(self, x):
constants = []
if 0 < self.dropout_U < 1:
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
ones = K.concatenate([ones] * self.output_dim, 1)
B_U = K.in_train_phase(K.dropout(ones, self.dropout_U), ones)
constants.append(B_U)
else:
constants.append(K.cast_to_floatx(1.))
if self.consume_less == 'cpu' and 0 < self.dropout_W < 1:
input_shape = self.input_spec[0].shape
input_dim = input_shape[-1]
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
ones = K.concatenate([ones] * input_dim, 1)
B_W = K.in_train_phase(K.dropout(ones, self.dropout_W), ones)
constants.append(B_W)
else:
constants.append(K.cast_to_floatx(1.))
return constants
def get_config(self):
config = {"output_dim": self.output_dim,
"init": self.init.__name__,
"inner_init": self.inner_init.__name__,
"activation": self.activation.__name__}
"activation": self.activation.__name__,
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
"dropout_W": self.dropout_W,
"dropout_U": self.dropout_U}
base_config = super(SimpleRNN, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
@@ -255,44 +409,82 @@ class GRU(Recurrent):
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.
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the input weights matrices.
U_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the recurrent weights matrices.
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
applied to the bias.
dropout_W: float between 0 and 1. Fraction of the input units to drop for input gates.
dropout_U: float between 0 and 1. Fraction of the input units to drop for recurrent connections.
# 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)
- [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
'''
def __init__(self, output_dim,
init='glorot_uniform', inner_init='orthogonal',
activation='sigmoid', inner_activation='hard_sigmoid',
**kwargs):
activation='tanh', inner_activation='hard_sigmoid',
W_regularizer=None, U_regularizer=None, b_regularizer=None,
dropout_W=0., dropout_U=0., **kwargs):
self.output_dim = output_dim
self.init = initializations.get(init)
self.inner_init = initializations.get(inner_init)
self.activation = activations.get(activation)
self.inner_activation = activations.get(inner_activation)
self.W_regularizer = regularizers.get(W_regularizer)
self.U_regularizer = regularizers.get(U_regularizer)
self.b_regularizer = regularizers.get(b_regularizer)
self.dropout_W, self.dropout_U = dropout_W, dropout_U
if self.dropout_W or self.dropout_U:
self.uses_learning_phase = True
super(GRU, self).__init__(**kwargs)
def build(self):
input_shape = self.input_shape
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
input_dim = input_shape[2]
self.input_dim = input_dim
self.input = K.placeholder(input_shape)
self.W_z = self.init((input_dim, self.output_dim))
self.U_z = self.inner_init((self.output_dim, self.output_dim))
self.b_z = K.zeros((self.output_dim,))
self.W_z = self.init((input_dim, self.output_dim),
name='{}_W_z'.format(self.name))
self.U_z = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_z'.format(self.name))
self.b_z = K.zeros((self.output_dim,), name='{}_b_z'.format(self.name))
self.W_r = self.init((input_dim, self.output_dim))
self.U_r = self.inner_init((self.output_dim, self.output_dim))
self.b_r = K.zeros((self.output_dim,))
self.W_r = self.init((input_dim, self.output_dim),
name='{}_W_r'.format(self.name))
self.U_r = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_r'.format(self.name))
self.b_r = K.zeros((self.output_dim,), name='{}_b_r'.format(self.name))
self.W_h = self.init((input_dim, self.output_dim))
self.U_h = self.inner_init((self.output_dim, self.output_dim))
self.b_h = K.zeros((self.output_dim,))
self.W_h = self.init((input_dim, self.output_dim),
name='{}_W_h'.format(self.name))
self.U_h = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_h'.format(self.name))
self.b_h = K.zeros((self.output_dim,), name='{}_b_h'.format(self.name))
self.params = [self.W_z, self.U_z, self.b_z,
self.W_r, self.U_r, self.b_r,
self.W_h, self.U_h, self.b_h]
self.regularizers = []
if self.W_regularizer:
self.W_regularizer.set_param(K.concatenate([self.W_z,
self.W_r,
self.W_h]))
self.regularizers.append(self.W_regularizer)
if self.U_regularizer:
self.U_regularizer.set_param(K.concatenate([self.U_z,
self.U_r,
self.U_h]))
self.regularizers.append(self.U_regularizer)
if self.b_regularizer:
self.b_regularizer.set_param(K.concatenate([self.b_z,
self.b_r,
self.b_h]))
self.regularizers.append(self.b_regularizer)
self.trainable_weights = [self.W_z, self.U_z, self.b_z,
self.W_r, self.U_r, self.b_r,
self.W_h, self.U_h, self.b_h]
if self.stateful:
self.reset_states()
else:
@@ -305,37 +497,85 @@ class GRU(Recurrent):
def reset_states(self):
assert self.stateful, 'Layer must be stateful.'
input_shape = self.input_shape
input_shape = self.input_spec[0].shape
if not input_shape[0]:
raise Exception('If a RNN is stateful, a complete ' +
'input_shape must be provided ' +
'(including batch size).')
'input_shape must be provided (including batch size).')
if hasattr(self, 'states'):
K.set_value(self.states[0],
np.zeros((input_shape[0], self.output_dim)))
else:
self.states = [K.zeros((input_shape[0], self.output_dim))]
def preprocess_input(self, x):
if self.consume_less == 'cpu':
input_shape = self.input_spec[0].shape
input_dim = input_shape[2]
timesteps = input_shape[1]
x_z = time_distributed_dense(x, self.W_z, self.b_z, self.dropout_W,
input_dim, self.output_dim, timesteps)
x_r = time_distributed_dense(x, self.W_r, self.b_r, self.dropout_W,
input_dim, self.output_dim, timesteps)
x_h = time_distributed_dense(x, self.W_h, self.b_h, self.dropout_W,
input_dim, self.output_dim, timesteps)
return K.concatenate([x_z, x_r, x_h], axis=2)
else:
return x
def step(self, x, states):
assert len(states) == 1
x_z = K.dot(x, self.W_z) + self.b_z
x_r = K.dot(x, self.W_r) + self.b_r
x_h = K.dot(x, self.W_h) + self.b_h
h_tm1 = states[0] # previous memory
B_U = states[1] # dropout matrices for recurrent units
B_W = states[2]
h_tm1 = states[0]
z = self.inner_activation(x_z + K.dot(h_tm1, self.U_z))
r = self.inner_activation(x_r + K.dot(h_tm1, self.U_r))
if self.consume_less == 'cpu':
x_z = x[:, :self.output_dim]
x_r = x[:, self.output_dim: 2 * self.output_dim]
x_h = x[:, 2 * self.output_dim:]
else:
x_z = K.dot(x * B_W[0], self.W_z) + self.b_z
x_r = K.dot(x * B_W[1], self.W_r) + self.b_r
x_h = K.dot(x * B_W[2], self.W_h) + self.b_h
hh = self.activation(x_h + K.dot(r * h_tm1, self.U_h))
z = self.inner_activation(x_z + K.dot(h_tm1 * B_U[0], self.U_z))
r = self.inner_activation(x_r + K.dot(h_tm1 * B_U[1], self.U_r))
hh = self.activation(x_h + K.dot(r * h_tm1 * B_U[2], self.U_h))
h = z * h_tm1 + (1 - z) * hh
return h, [h]
def get_constants(self, x):
constants = []
if 0 < self.dropout_U < 1:
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
ones = K.concatenate([ones] * self.output_dim, 1)
B_U = [K.dropout(ones, self.dropout_U) for _ in range(3)]
constants.append(B_U)
else:
constants.append([K.cast_to_floatx(1.) for _ in range(4)])
if self.consume_less == 'cpu' and 0 < self.dropout_W < 1:
input_shape = self.input_spec[0].shape
input_dim = input_shape[-1]
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
ones = K.concatenate([ones] * input_dim, 1)
B_W = [K.dropout(ones, self.dropout_W) for _ in range(3)]
constants.append(B_W)
else:
constants.append([K.cast_to_floatx(1.) for _ in range(4)])
return constants
def get_config(self):
config = {"output_dim": self.output_dim,
"init": self.init.__name__,
"inner_init": self.inner_init.__name__,
"activation": self.activation.__name__,
"inner_activation": self.inner_activation.__name__}
"inner_activation": self.inner_activation.__name__,
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
"dropout_W": self.dropout_W,
"dropout_U": self.dropout_U}
base_config = super(GRU, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
@@ -359,56 +599,102 @@ class LSTM(Recurrent):
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.
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the input weights matrices.
U_regularizer: instance of [WeightRegularizer](../regularizers.md)
(eg. L1 or L2 regularization), applied to the recurrent weights matrices.
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
applied to the bias.
dropout_W: float between 0 and 1. Fraction of the input units to drop for input gates.
dropout_U: float between 0 and 1. Fraction of the input units to drop for recurrent connections.
# 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)
- [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
'''
def __init__(self, output_dim,
init='glorot_uniform', inner_init='orthogonal',
forget_bias_init='one', activation='tanh',
inner_activation='hard_sigmoid', **kwargs):
inner_activation='hard_sigmoid',
W_regularizer=None, U_regularizer=None, b_regularizer=None,
dropout_W=0., dropout_U=0., **kwargs):
self.output_dim = output_dim
self.init = initializations.get(init)
self.inner_init = initializations.get(inner_init)
self.forget_bias_init = initializations.get(forget_bias_init)
self.activation = activations.get(activation)
self.inner_activation = activations.get(inner_activation)
self.W_regularizer = regularizers.get(W_regularizer)
self.U_regularizer = regularizers.get(U_regularizer)
self.b_regularizer = regularizers.get(b_regularizer)
self.dropout_W, self.dropout_U = dropout_W, dropout_U
if self.dropout_W or self.dropout_U:
self.uses_learning_phase = True
super(LSTM, self).__init__(**kwargs)
def build(self):
input_shape = self.input_shape
def build(self, input_shape):
self.input_spec = [InputSpec(shape=input_shape)]
input_dim = input_shape[2]
self.input_dim = input_dim
self.input = K.placeholder(input_shape)
if self.stateful:
self.reset_states()
else:
# initial states: 2 all-zero tensor of shape (output_dim)
# initial states: 2 all-zero tensors of shape (output_dim)
self.states = [None, None]
self.W_i = self.init((input_dim, self.output_dim))
self.U_i = self.inner_init((self.output_dim, self.output_dim))
self.b_i = K.zeros((self.output_dim,))
self.W_i = self.init((input_dim, self.output_dim),
name='{}_W_i'.format(self.name))
self.U_i = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_i'.format(self.name))
self.b_i = K.zeros((self.output_dim,), name='{}_b_i'.format(self.name))
self.W_f = self.init((input_dim, self.output_dim))
self.U_f = self.inner_init((self.output_dim, self.output_dim))
self.b_f = self.forget_bias_init((self.output_dim,))
self.W_f = self.init((input_dim, self.output_dim),
name='{}_W_f'.format(self.name))
self.U_f = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_f'.format(self.name))
self.b_f = self.forget_bias_init((self.output_dim,),
name='{}_b_f'.format(self.name))
self.W_c = self.init((input_dim, self.output_dim))
self.U_c = self.inner_init((self.output_dim, self.output_dim))
self.b_c = K.zeros((self.output_dim,))
self.W_c = self.init((input_dim, self.output_dim),
name='{}_W_c'.format(self.name))
self.U_c = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_c'.format(self.name))
self.b_c = K.zeros((self.output_dim,), name='{}_b_c'.format(self.name))
self.W_o = self.init((input_dim, self.output_dim))
self.U_o = self.inner_init((self.output_dim, self.output_dim))
self.b_o = K.zeros((self.output_dim,))
self.W_o = self.init((input_dim, self.output_dim),
name='{}_W_o'.format(self.name))
self.U_o = self.inner_init((self.output_dim, self.output_dim),
name='{}_U_o'.format(self.name))
self.b_o = K.zeros((self.output_dim,), name='{}_b_o'.format(self.name))
self.params = [self.W_i, self.U_i, self.b_i,
self.W_c, self.U_c, self.b_c,
self.W_f, self.U_f, self.b_f,
self.W_o, self.U_o, self.b_o]
self.regularizers = []
if self.W_regularizer:
self.W_regularizer.set_param(K.concatenate([self.W_i,
self.W_f,
self.W_c,
self.W_o]))
self.regularizers.append(self.W_regularizer)
if self.U_regularizer:
self.U_regularizer.set_param(K.concatenate([self.U_i,
self.U_f,
self.U_c,
self.U_o]))
self.regularizers.append(self.U_regularizer)
if self.b_regularizer:
self.b_regularizer.set_param(K.concatenate([self.b_i,
self.b_f,
self.b_c,
self.b_o]))
self.regularizers.append(self.b_regularizer)
self.trainable_weights = [self.W_i, self.U_i, self.b_i,
self.W_c, self.U_c, self.b_c,
self.W_f, self.U_f, self.b_f,
self.W_o, self.U_o, self.b_o]
if self.initial_weights is not None:
self.set_weights(self.initial_weights)
@@ -416,11 +702,10 @@ class LSTM(Recurrent):
def reset_states(self):
assert self.stateful, 'Layer must be stateful.'
input_shape = self.input_shape
input_shape = self.input_spec[0].shape
if not input_shape[0]:
raise Exception('If a RNN is stateful, a complete ' +
'input_shape must be provided ' +
'(including batch size).')
'input_shape must be provided (including batch size).')
if hasattr(self, 'states'):
K.set_value(self.states[0],
np.zeros((input_shape[0], self.output_dim)))
@@ -430,29 +715,85 @@ class LSTM(Recurrent):
self.states = [K.zeros((input_shape[0], self.output_dim)),
K.zeros((input_shape[0], self.output_dim))]
def preprocess_input(self, x, train=False):
if self.consume_less == 'cpu':
if train and (0 < self.dropout_W < 1):
dropout = self.dropout_W
else:
dropout = 0
input_shape = self.input_spec[0].shape
input_dim = input_shape[2]
timesteps = input_shape[1]
x_i = time_distributed_dense(x, self.W_i, self.b_i, dropout,
input_dim, self.output_dim, timesteps)
x_f = time_distributed_dense(x, self.W_f, self.b_f, dropout,
input_dim, self.output_dim, timesteps)
x_c = time_distributed_dense(x, self.W_c, self.b_c, dropout,
input_dim, self.output_dim, timesteps)
x_o = time_distributed_dense(x, self.W_o, self.b_o, dropout,
input_dim, self.output_dim, timesteps)
return K.concatenate([x_i, x_f, x_c, x_o], axis=2)
else:
return x
def step(self, x, states):
assert len(states) == 2
h_tm1 = states[0]
c_tm1 = states[1]
B_U = states[2]
B_W = states[3]
x_i = K.dot(x, self.W_i) + self.b_i
x_f = K.dot(x, self.W_f) + self.b_f
x_c = K.dot(x, self.W_c) + self.b_c
x_o = K.dot(x, self.W_o) + self.b_o
if self.consume_less == 'cpu':
x_i = x[:, :self.output_dim]
x_f = x[:, self.output_dim: 2 * self.output_dim]
x_c = x[:, 2 * self.output_dim: 3 * self.output_dim]
x_o = x[:, 3 * self.output_dim:]
else:
x_i = K.dot(x * B_W[0], self.W_i) + self.b_i
x_f = K.dot(x * B_W[1], self.W_f) + self.b_f
x_c = K.dot(x * B_W[2], self.W_c) + self.b_c
x_o = K.dot(x * B_W[3], self.W_o) + self.b_o
i = self.inner_activation(x_i + K.dot(h_tm1 * B_U[0], self.U_i))
f = self.inner_activation(x_f + K.dot(h_tm1 * B_U[1], self.U_f))
c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * B_U[2], self.U_c))
o = self.inner_activation(x_o + K.dot(h_tm1 * B_U[3], self.U_o))
i = self.inner_activation(x_i + K.dot(h_tm1, self.U_i))
f = self.inner_activation(x_f + K.dot(h_tm1, self.U_f))
c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1, self.U_c))
o = self.inner_activation(x_o + K.dot(h_tm1, self.U_o))
h = o * self.activation(c)
return h, [h, c]
def get_constants(self, x):
constants = []
if 0 < self.dropout_U < 1:
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
ones = K.concatenate([ones] * self.output_dim, 1)
B_U = [K.dropout(ones, self.dropout_U) for _ in range(4)]
constants.append(B_U)
else:
constants.append([K.cast_to_floatx(1.) for _ in range(4)])
if self.consume_less == 'cpu' and 0 < self.dropout_W < 1:
input_shape = self.input_spec[0].shape
input_dim = input_shape[-1]
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
ones = K.concatenate([ones] * input_dim, 1)
B_W = [K.dropout(ones, self.dropout_W) for _ in range(4)]
constants.append(B_W)
else:
constants.append([K.cast_to_floatx(1.) for _ in range(4)])
return constants
def get_config(self):
config = {"output_dim": self.output_dim,
"init": self.init.__name__,
"inner_init": self.inner_init.__name__,
"forget_bias_init": self.forget_bias_init.__name__,
"activation": self.activation.__name__,
"inner_activation": self.inner_activation.__name__}
"inner_activation": self.inner_activation.__name__,
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
"dropout_W": self.dropout_W,
"dropout_U": self.dropout_U}
base_config = super(LSTM, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
+132
Ver Arquivo
@@ -0,0 +1,132 @@
from ..engine import Layer, InputSpec
from .. import backend as K
class Wrapper(Layer):
def __init__(self, layer, **kwargs):
self.layer = layer
super(Wrapper, self).__init__(**kwargs)
def build(self, input_shape=None):
'''Assumes that self.layer is already set.
Should be called at the end of .build() in the
children classes.
'''
self.trainable_weights = getattr(self.layer, 'trainable_weights', [])
self.non_trainable_weights = getattr(self.layer, 'non_trainable_weights', [])
self.updates = getattr(self.layer, 'updates', [])
self.regularizers = getattr(self.layer, 'regularizers', [])
self.constraints = getattr(self.layer, 'constraints', {})
def get_weights(self):
weights = self.layer.get_weights()
return weights
def set_weights(self, weights):
self.layer.set_weights(weights)
def get_config(self):
config = {'layer': {'class_name': self.layer.__class__.__name__,
'config': self.layer.get_config()}}
base_config = super(Wrapper, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
@classmethod
def from_config(cls, config):
from keras.utils.layer_utils import layer_from_config
layer = layer_from_config(config.pop('layer'))
return cls(layer, **config)
class TimeDistributed(Wrapper):
"""This wrapper allows to apply a layer to every
temporal slice of an input.
The input should be at least 3D,
and the dimension of index one will be considered to be
the temporal dimension.
Consider a batch of 32 samples, where each sample is a sequence of 10
vectors of 16 dimensions. The batch input shape of the layer is then `(32, 10, 16)`
(and the `input_shape`, not including the samples dimension, is `(10, 16)`).
You can then use `TimeDistributed` to apply a `Dense` layer to each of the 10 timesteps, independently:
```python
# as the first layer in a model
model = Sequential()
model.add(TimeDistributed(Dense(8), input_shape=(10, 16)))
# now model.output_shape == (None, 10, 8)
# subsequent layers: no need for input_shape
model.add(TimeDistributed(Dense(32)))
# now model.output_shape == (None, 10, 32)
```
The output will then have shape `(32, 10, 8)`.
Note this is strictly equivalent to using `layers.core.TimeDistributedDense`.
However what is different about `TimeDistributed`
is that it can be used with arbitrary layers, not just `Dense`,
for instance with a `Convolution2D` layer:
```python
model = Sequential()
model.add(TimeDistributed(Convolution2D(64, 3, 3), input_shape=(10, 3, 299, 299)))
```
# Arguments
layer: a layer instance.
"""
def __init__(self, layer, **kwargs):
self.supports_masking = True
super(TimeDistributed, self).__init__(layer, **kwargs)
def build(self, input_shape):
assert len(input_shape) >= 3
self.input_spec = [InputSpec(shape=input_shape)]
if K._BACKEND == 'tensorflow':
if not input_shape[1]:
raise Exception('When using TensorFlow, you should define '
'explicitly the number of timesteps of '
'your sequences.\n'
'If your first layer is an Embedding, '
'make sure to pass it an "input_length" '
'argument. Otherwise, make sure '
'the first layer has '
'an "input_shape" or "batch_input_shape" '
'argument, including the time axis.')
child_input_shape = (input_shape[0],) + input_shape[2:]
self.layer.build(child_input_shape)
super(TimeDistributed, self).build()
def get_output_shape_for(self, input_shape):
child_input_shape = (input_shape[0],) + input_shape[2:]
child_output_shape = self.layer.get_output_shape_for(child_input_shape)
timesteps = input_shape[1]
return (child_output_shape[0], timesteps) + child_output_shape[1:]
def call(self, X, mask=None):
input_shape = self.input_spec[0].shape
if input_shape[0]:
# batch size matters, use rnn-based implementation
def step(x, states):
output = self.layer.call(x)
return output, []
last_output, outputs, states = K.rnn(step, X,
initial_states=[])
y = outputs
else:
# no batch size specified, therefore the layer will be able
# to process batches of any size
# we can go with reshape-based implementation for performance
X = K.reshape(X, (-1, ) + input_shape[2:]) # (nb_samples * timesteps, ...)
y = self.layer.call(X) # (nb_samples * timesteps, ...)
input_length = input_shape[1]
if not input_length:
input_length = K.shape(X)[1]
# (nb_samples, timesteps, ...)
output_shape = self.get_output_shape_for(input_shape)
y = K.reshape(y, (-1, input_length) + output_shape[2:])
return y
Ver Arquivo
+768
Ver Arquivo
@@ -0,0 +1,768 @@
from collections import OrderedDict
import warnings
import copy
from .. import backend as K
from ..layers import InputLayer, Layer, Merge
from ..engine.training import Model
class Graph(Model):
'''Arbitrary connection graph.
THIS IS A LEGACY MODEL AND SHOULD NOT BE USED
except for backwards compatibility support.
For multi-inputs/multi-outputs models, or
models using shared layers, use the functional API instead.
'''
def __init__(self, name=None):
# model attributes
self.inbound_nodes = []
self.outbound_nodes = []
self.built = False
self.supports_masking = False
# legacy attributes (we prefix them with _graph_)
self._graph_namespace = set() # strings
self._graph_nodes = OrderedDict() # layer-like
self._graph_inputs = OrderedDict() # layer-like
self._graph_outputs = OrderedDict() # layer-like
self._graph_input_config = [] # dicts
self._graph_output_config = [] # dicts
self._graph_node_config = [] # dicts
self._graph_shared_nodes_names = []
if not name:
prefix = 'graph_'
name = prefix + str(K.get_uid(prefix))
self.name = name
def __call__(self, x, mask=None):
self.build()
return super(Graph, self).__call__(x, mask)
def build(self, input_shape=None):
# this will crash if the input/output layers have multiple nodes
# no plans to support that case since Graph is deprecated
input_tensors = [layer.output for layer in self._graph_inputs.values()]
output_tensors = [layer.output for layer in self._graph_outputs.values()]
# actually create the model
super(Graph, self).__init__(input_tensors,
output_tensors,
name=self.name)
self.built = True
def compile(self, optimizer, loss,
metrics=[],
sample_weight_modes=None,
loss_weights=None,
**kwargs):
'''Configures the learning process.
# 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)).
metrics: list of str (name of metrics) or
list of metrics functions. See [metrics](metrics.md).
sample_weight_modes: optional dictionary mapping certain
output names to a sample weight mode ("temporal" and None
are the only supported modes). If you need to do
timestep-wise loss weighting on one of your graph outputs,
you will need to set the sample weight mode for this output
to "temporal".
loss_weights: dictionary you can pass to specify a weight
coefficient for each loss function (in a multi-output model).
If no loss weight is specified for an output,
the weight for this output's loss will be considered to be 1.
kwargs: for Theano backend, these are passed into K.function.
Ignored for Tensorflow backend.
'''
# create the underlying Model
if not self.built:
self.build()
super(Graph, self).compile(optimizer, loss,
metrics=metrics,
sample_weight_mode=sample_weight_modes,
loss_weights=loss_weights,
**kwargs)
def add_input(self, name, input_shape=None,
batch_input_shape=None, dtype='float'):
'''Adds an input to the graph.
# Arguments:
name: string. The name of the new input.
Must be unique in the graph.
input_shape: a tuple of integers,
the expected shape of the input samples.
Does not include the batch size.
batch_input_shape: a tuple of integers,
the expected shape of the whole input batch,
including the batch size.
dtype: 'float', or 'int'.
'''
if name in self._graph_namespace:
raise Exception('Duplicate node identifier: ' + name)
self._graph_namespace.add(name)
self.built = False
if dtype[:3] == 'int':
dtype = 'int32'
elif dtype[:5] == 'float':
dtype = K.floatx()
else:
raise Exception('Uknown dtype (should be "int" or "float"): ' +
str(dtype))
# create input layer
input_layer = InputLayer(input_shape=input_shape,
batch_input_shape=batch_input_shape,
name=name, input_dtype=dtype)
self._graph_inputs[name] = input_layer
# append input config to self._graph_input_config
config = {'name': name, 'dtype': dtype}
if batch_input_shape:
config['batch_input_shape'] = batch_input_shape
else:
config['input_shape'] = input_shape
self._graph_input_config.append(config)
def add_node(self, layer, name, input=None, inputs=[],
merge_mode='concat', concat_axis=-1, dot_axes=-1,
create_output=False):
'''Adds a node in the graph. It can be connected to multiple
inputs, which will first be merged into one tensor
according to the mode specified.
# Arguments
layer: the layer at the node.
name: name for the node.
input: when connecting the layer to a single input,
this is the name of the incoming node.
inputs: when connecting the layer to multiple inputs,
this is a list of names of incoming nodes.
merge_mode: one of {concat, sum, dot, ave, mul}
concat_axis: when `merge_mode=='concat'`, this is the
input concatenation axis.
dot_axes: when `merge_mode='dot'`,
this is the contraction axes specification;
see the `Merge` layer for details.
create_output: boolean. Set this to `True` if you want the output
of your node to be an output of the graph.
'''
if name in self._graph_namespace:
raise Exception('Duplicate node identifier: ' + name)
self._graph_namespace.add(name)
layer.name = name
self.built = False
if input:
if input not in self._graph_namespace:
raise Exception('Unknown node/input identifier: ' + input)
if input in self._graph_nodes:
layer.add_inbound_node(self._graph_nodes[input])
elif input in self._graph_inputs:
layer.add_inbound_node(self._graph_inputs[input])
if inputs:
to_merge = []
for n in inputs:
if n in self._graph_nodes:
to_merge.append(self._graph_nodes[n])
elif n in self._graph_inputs:
to_merge.append(self._graph_inputs[n])
else:
raise Exception('Unknown identifier: ' + n)
merge = Merge(to_merge, mode=merge_mode,
concat_axis=concat_axis, dot_axes=dot_axes,
name='merge_inputs_for_' + name)
layer.add_inbound_node(merge)
self._graph_nodes[name] = layer
self._graph_node_config.append({'name': name,
'input': input,
'inputs': inputs,
'merge_mode': merge_mode,
'concat_axis': concat_axis,
'dot_axes': dot_axes,
'create_output': create_output})
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 share a same layer across multiple nodes.
Supposed, for instance, that you want to apply one same `Dense` layer
after two different nodes ('node_a' and 'node_b').
You can then add the dense layer as a shared node by calling:
```python
model.add_shared_node(my_dense, name='shared_dense', inputs=['node_a', 'node_b'], ...)
```
If you want access to the output of dense(node_a) and dense(node_b) separately,
you can add these outputs to the Graph by passing an `outputs` argument:
```python
model.add_shared_node(my_dense, name='shared_dense', inputs=['node_a', 'node_b'],
outputs=['dense_output_a', 'dense_outputs_b'])
```
Otherwise you can merge these different outputs via `merge_mode`.
In that case you can access the merged output
under the identifier `name`.
# Arguments
layer: The layer to be shared across multiple inputs
name: Name of the shared node
inputs: List of names of input nodes
merge_mode: Same meaning as `merge_mode` argument of `add_node()`
concat_axis: Same meaning as `concat_axis` argument of `add_node()`
dot_axes: Same meaning as `dot_axes` argument of `add_node()`
outputs: Used when `merge_mode=None`. Names for the output nodes.
create_output: Same meaning as `create_output` argument of `add_node()`.
'''
if name in self._graph_namespace:
raise Exception('Duplicate node identifier: ' + name)
self._graph_namespace.add(name)
self.built = False
for o in outputs:
if o in self._graph_namespace:
raise Exception('Duplicate node identifier: ' + o)
if merge_mode:
if merge_mode not in {'sum', 'ave', 'mul', 'dot', 'cos', 'concat'}:
raise Exception('Invalid merge mode:', merge_mode)
input_layers = []
for i in range(len(inputs)):
input = inputs[i]
if input in self._graph_nodes:
n = self._graph_nodes[input]
input_layers.append(n)
elif input in self._graph_inputs:
n = self._graph_inputs[input]
input_layers.append(n)
else:
raise Exception('Unknown identifier: ' + input)
created_node_indices = []
for input_layer in input_layers:
created_node_indices.append(len(layer.inbound_nodes))
layer.add_inbound_node(input_layer)
if merge_mode:
layer.name = 'input_for_' + name
# collect all output nodes of layer and merge them into a single output
merge = Merge([layer for _ in range(len(inputs))],
mode=merge_mode,
concat_axis=concat_axis, dot_axes=dot_axes,
node_indices=created_node_indices,
name=name)
self._graph_nodes[name] = merge
if create_output:
self.add_output(name, input=name)
else:
layer.name = name
# create one new layer per output node of layer,
# and add them to the Graph with their own identifiers
if len(outputs) != len(inputs):
raise Exception('When using merge_mode=None, '
'you should provide a list of '
'output names (`output` argument) '
'the same size as `input`.')
for i in range(len(outputs)):
output_layer_name = outputs[i]
output_layer = Layer(name=output_layer_name)
output_layer.add_inbound_node(layer, created_node_indices[i])
self._graph_namespace.add(output_layer_name)
self._graph_nodes[output_layer_name] = output_layer
if create_output:
self.add_output(output_layer_name, input=output_layer_name)
self._graph_node_config.append({'name': name,
'layer': {
'config': layer.get_config(),
'class_name': layer.__class__.__name__,
},
'inputs': inputs,
'merge_mode': merge_mode,
'concat_axis': concat_axis,
'dot_axes': dot_axes,
'outputs': outputs,
'create_output': create_output if merge_mode else False})
self._graph_shared_nodes_names.append(name)
def add_output(self, name, input=None, inputs=[],
merge_mode='concat', concat_axis=-1, dot_axes=-1):
'''Adds an output to the graph.
This output can merge several node outputs into a single output.
# Arguments
name: name of the output.
input: when connecting the layer to a single input,
this is the name of the incoming node.
inputs: when connecting the layer to multiple inputs,
this is a list of names of incoming nodes.
merge_mode: one of {concat, sum, dot, ave, mul}
concat_axis: when `merge_mode=='concat'`, this is the
input concatenation axis.
dot_axes: when `merge_mode='dot'`,
this is the contraction axes specification;
see the `Merge layer for details.
'''
if name not in self._graph_namespace:
self._graph_namespace.add(name)
if name in self._graph_outputs:
raise Exception('Duplicate output identifier:', name)
self.built = False
if input:
if input in self._graph_nodes:
layer = self._graph_nodes[input]
elif input in self._graph_inputs:
layer = self._graph_inputs[input]
else:
raise Exception('Unknown node/input identifier: ' + input)
if layer.name == name:
self._graph_outputs[name] = layer
else:
layer.name = name
self._graph_outputs[name] = layer
if inputs:
to_merge = []
for n in inputs:
if n not in self._graph_nodes:
raise Exception('Unknown identifier: ' + n)
to_merge.append(self._graph_nodes[n])
merge = Merge(to_merge, mode=merge_mode,
concat_axis=concat_axis, dot_axes=dot_axes,
name=name)
self._graph_outputs[name] = merge
self._graph_output_config.append({'name': name,
'input': input,
'inputs': inputs,
'merge_mode': merge_mode,
'concat_axis': concat_axis,
'dot_axes': dot_axes})
def _get_x(self, data):
x = []
for key in self._graph_inputs.keys():
if key not in data:
raise Exception('Expected to be provided an array '
'(in dict argument `data`) for input "' +
key + '".')
x.append(data[key])
return x
def _get_y(self, data):
y = []
for key in self._graph_outputs.keys():
if key not in data:
raise Exception('Expected to be provided an array '
'(in dict argument `data`) for output "' +
key + '".')
y.append(data[key])
return y
def fit(self, data, batch_size=32, nb_epoch=10, verbose=1, callbacks=[],
validation_split=0., validation_data=None, shuffle=True,
class_weight=None, sample_weight=None, **kwargs):
'''Trains the model for a fixed number of epochs.
Returns a history object. Its `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 and outputs names to
appropriate numpy arrays. All arrays should contain
the same number of samples.
batch_size: int. Number of samples per gradient update.
nb_epoch: int.
verbose: 0 for no logging to stdout,
1 for progress bar logging, 2 for one log line per epoch.
callbacks: `keras.callbacks.Callback` list. List of callbacks
to apply during training. See [callbacks](callbacks.md).
validation_split: float (0. < x < 1). Fraction of the data to
use as held-out validation data.
validation_data: dictionary mapping input names and outputs names
to appropriate numpy arrays to be used as
held-out validation data.
All arrays should contain the same number of samples.
Will override validation_split.
shuffle: boolean. Whether to shuffle the samples at each epoch.
class_weight: dictionary mapping output names to
class weight dictionaries.
sample_weight: dictionary mapping output names to
numpy arrays of sample weights.
'''
if 'show_accuracy' in kwargs:
kwargs.pop('show_accuracy')
warnings.warn('The "show_accuracy" argument is deprecated, '
'instead you should pass the "accuracy" metric to '
'the model at compile time:\n'
'`model.compile(optimizer, loss, '
'metrics=["accuracy"])`')
if kwargs:
raise Exception('Received unknown keyword arguments: ' +
str(kwargs))
x = self._get_x(data)
y = self._get_y(data)
if type(validation_data) is tuple:
raise Exception('Cannot used sample_weight with '
'validation data with legacy Graph model. '
'validation_data should be a dictionary.')
if validation_data:
val_x = self._get_x(validation_data)
val_y = self._get_y(validation_data)
validation_data = (val_x, val_y)
return super(Graph, self).fit(x, y,
batch_size=batch_size,
nb_epoch=nb_epoch,
verbose=verbose,
callbacks=callbacks,
validation_split=validation_split,
validation_data=validation_data,
shuffle=shuffle,
class_weight=class_weight,
sample_weight=sample_weight)
def evaluate(self, data, batch_size=128,
verbose=0, sample_weight={}, **kwargs):
'''Computes the loss on some input data, batch by batch.
Returns the scalar test loss over the data,
or a list of metrics values (starting with the test loss)
if applicable.
Arguments: see `fit` method.
'''
if 'show_accuracy' in kwargs:
kwargs.pop('show_accuracy')
warnings.warn('The "show_accuracy" argument is deprecated, '
'instead you should pass the "accuracy" metric to '
'the model at compile time:\n'
'`model.compile(optimizer, loss, '
'metrics=["accuracy"])`')
if kwargs:
raise Exception('Received unknown keyword arguments: ' +
str(kwargs))
x = self._get_x(data)
y = self._get_y(data)
return super(Graph, self).evaluate(x, y,
batch_size=batch_size,
verbose=verbose,
sample_weight=sample_weight)
def predict(self, data, batch_size=128, verbose=0):
'''Generates output predictions for the input samples
batch by batch.
Arguments: see `fit` method.
'''
x = self._get_x(data)
output_list = super(Graph, self).predict(x, batch_size=batch_size,
verbose=verbose)
return dict(zip(self._graph_outputs, output_list))
def train_on_batch(self, data,
class_weight={},
sample_weight={}, **kwargs):
'''Single gradient update on a batch of samples.
Returns the scalar train loss over the data,
or a list of metrics values (starting with the test loss)
if applicable.
Arguments: see `fit` method.
'''
if 'accuracy' in kwargs:
kwargs.pop('accuracy')
warnings.warn('The "accuracy" argument is deprecated, '
'instead you should pass the "accuracy" metric to '
'the model at compile time:\n'
'`model.compile(optimizer, loss, '
'metrics=["accuracy"])`')
if kwargs:
raise Exception('Received unknown keyword arguments: ' +
str(kwargs))
x = self._get_x(data)
y = self._get_y(data)
return super(Graph, self).train_on_batch(x, y,
sample_weight=sample_weight,
class_weight=class_weight)
def test_on_batch(self, data, sample_weight={}, **kwargs):
'''Test the network on a single batch of samples.
Returns the scalar test loss over the data,
or a list of metrics values (starting with the test loss)
if applicable.
Arguments: see `fit` method.
'''
if 'accuracy' in kwargs:
kwargs.pop('accuracy')
warnings.warn('The "accuracy" argument is deprecated, '
'instead you should pass the "accuracy" metric to '
'the model at compile time:\n'
'`model.compile(optimizer, loss, '
'metrics=["accuracy"])`')
if kwargs:
raise Exception('Received unknown keyword arguments: ' +
str(kwargs))
x = self._get_x(data)
y = self._get_y(data)
return super(Graph, self).test_on_batch(x, y,
sample_weight=sample_weight)
def predict_on_batch(self, data):
output_list = super(Graph, self).predict_on_batch(data)
return dict(zip(self._graph_outputs, output_list))
def fit_generator(self, generator, samples_per_epoch, nb_epoch,
verbose=1, callbacks=[],
validation_data=None, nb_val_samples=None,
class_weight={}, **kwargs):
'''Fits a model on data generated batch-by-batch by a Python generator.
The generator is run in parallel to the model, for efficiency.
For instance, this allows you to do real-time data augmentation
on images on CPU in parallel to training your model on GPU.
# Arguments
generator: a generator.
The output of the generator must be either a tuple
of dictionaries `(input_data, sample_weight)`
or a dictionary `input_data`
(mapping names of inputs and outputs to Numpy arrays).
All arrays should contain the same number of samples.
The generator is expected to loop over its data
indefinitely. An epoch finishes when `samples_per_epoch`
samples have been seen by the model.
samples_per_epoch: integer, number of samples to process before
going to the next epoch.
nb_epoch: integer, total number of iterations on the data.
verbose: verbosity mode, 0, 1, or 2.
callbacks: list of callbacks to be called during training.
validation_data: dictionary mapping input names and outputs names
to appropriate numpy arrays to be used as
held-out validation data, or a generator yielding such
dictionaries. All arrays should contain the same number
of samples. If a generator, will be called until more than
`nb_val_samples` examples have been generated at the
end of every epoch. These examples will then be used
as the validation data.
nb_val_samples: number of samples to use from validation
generator at the end of every epoch.
class_weight: dictionary mapping class indices to a weight
for the class.
# Returns
A `History` object.
# Examples
```python
def generate_arrays_from_file(path):
while 1:
f = open(path)
for line in f:
# create numpy arrays of input data
# and labels, from each line in the file
x1, x2, y = process_line(line)
yield ({'input_1': x1, 'input_2': x2, 'output': y})
f.close()
graph.fit_generator(generate_arrays_from_file('/my_file.txt'),
samples_per_epoch=10000, nb_epoch=10)
```
'''
if 'show_accuracy' in kwargs:
kwargs.pop('show_accuracy')
warnings.warn('The "show_accuracy" argument is deprecated, '
'instead you should pass the "accuracy" metric to '
'the model at compile time:\n'
'`model.compile(optimizer, loss, '
'metrics=["accuracy"])`')
if 'nb_worker' in kwargs:
kwargs.pop('nb_worker')
warnings.warn('The "nb_worker" argument is deprecated, '
'please remove it from your code.')
if 'nb_val_worker' in kwargs:
kwargs.pop('nb_val_worker')
warnings.warn('The "nb_val_worker" argument is deprecated, '
'please remove it from your code.')
if kwargs:
raise Exception('Received unknown keyword arguments: ' +
str(kwargs))
self._train_on_batch = self.train_on_batch
self.train_on_batch = super(Graph, self).train_on_batch
self._evaluate = self.evaluate
self.evaluate = super(Graph, self).evaluate
if validation_data and type(validation_data) is tuple:
raise Exception('Cannot use sample_weight with '
'validation_data in legacy Graph model.')
if validation_data and type(validation_data) is dict:
validation_data = (self._get_x(validation_data),
self._get_y(validation_data))
original_generator = generator
def fixed_generator():
while 1:
data = next(original_generator)
if type(data) is tuple:
data, sample_weight = data
x = self._get_x(data)
y = self._get_y(data)
yield x, y, sample_weight
else:
x = self._get_x(data)
y = self._get_y(data)
yield x, y
generator = fixed_generator()
history = super(Graph, self).fit_generator(generator,
samples_per_epoch,
nb_epoch,
verbose=verbose,
callbacks=callbacks,
validation_data=validation_data,
nb_val_samples=nb_val_samples,
class_weight=class_weight)
self.train_on_batch = self._train_on_batch
self.evaluate = self._evaluate
return history
def evaluate_generator(self, generator, val_samples,
verbose=1, **kwargs):
'''Evaluates the model on a generator. The generator should
return the same kind of data with every yield as accepted
by `evaluate`.
If `show_accuracy`, it returns a tuple `(loss, accuracy)`,
otherwise it returns the loss value.
Arguments:
generator:
generator yielding dictionaries of the kind accepted
by `evaluate`, or tuples of such dictionaries and
associated dictionaries of sample weights.
val_samples:
total number of samples to generate from `generator`
to use in validation.
Other arguments are the same as for `fit`.
'''
if 'show_accuracy' in kwargs:
kwargs.pop('show_accuracy')
warnings.warn('The "show_accuracy" argument is deprecated, '
'instead you should pass the "accuracy" metric to '
'the model at compile time:\n'
'`model.compile(optimizer, loss, '
'metrics=["accuracy"])`')
if 'verbose' in kwargs:
kwargs.pop('verbose')
warnings.warn('The "verbose" argument is deprecated.')
if kwargs:
raise Exception('Received unknown keyword arguments: ' +
str(kwargs))
self._test_on_batch = self.test_on_batch
self.test_on_batch = super(Graph, self).test_on_batch
original_generator = generator
def fixed_generator():
while 1:
data = next(original_generator)
if type(data) is tuple:
data, sample_weight = data
x = self._get_x(data)
y = self._get_y(data)
yield x, y, sample_weight
else:
x = self._get_x(data)
y = self._get_y(data)
yield x, y
generator = fixed_generator()
history = super(Graph, self).evaluate_generator(generator,
val_samples)
self.test_on_batch = self._test_on_batch
return history
# get_weights, set_weights: inherited
def get_config(self):
config = {'input_config': self._graph_input_config,
'node_config': self._graph_node_config,
'output_config': self._graph_output_config}
nodes = {}
for name, node in self._graph_nodes.items():
nodes[name] = {'class_name': node.__class__.__name__,
'config': node.get_config()}
if name in self._graph_shared_nodes_names:
nodes[name]['shared'] = True
config['nodes'] = nodes
return copy.deepcopy(config)
@classmethod
def from_config(cls, config):
# TODO: test legacy support
from keras.utils.layer_utils import layer_from_config
def normalize_legacy_config(conf):
if 'class_name' not in conf:
class_name = conf['name']
name = conf.get('custom_name')
conf['name'] = name
new_config = {
'class_name': class_name,
'config': conf,
}
return new_config
return conf
graph = cls()
inputs = config.get('input_config')
for input in inputs:
graph.add_input(**input)
nodes = config.get('node_config')
for node in nodes:
layer_config = config['nodes'][node['name']]
layer_config = normalize_legacy_config(layer_config)
if 'layer' in node:
# for add_shared_node
node['layer'] = layer_from_config(node['layer'])
else:
layer = layer_from_config(layer_config)
node['layer'] = layer
node['create_output'] = False # outputs will be added below
if layer_config.get('shared'):
graph.add_shared_node(**node)
else:
graph.add_node(**node)
outputs = config.get('output_config')
for output in outputs:
graph.add_output(**output)
return graph
def load_weights(self, fname):
if not self.built:
self.build()
super(Graph, self).load_weights(fname)
+10
Ver Arquivo
@@ -0,0 +1,10 @@
from . import backend as K
def binary_accuracy(y_true, y_pred):
return K.mean(K.equal(y_true, K.round(y_pred)))
def categorical_accuracy(y_true, y_pred):
return K.mean(K.equal(K.argmax(y_true, axis=-1),
K.argmax(y_pred, axis=-1)))
+632 -1317
Ver Arquivo
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+16 -7
Ver Arquivo
@@ -7,10 +7,6 @@ def mean_squared_error(y_true, y_pred):
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 K.mean(K.abs(y_pred - y_true), axis=-1)
@@ -37,22 +33,35 @@ def hinge(y_true, y_pred):
def categorical_crossentropy(y_true, y_pred):
'''Expects a binary class matrix instead of a vector of scalar classes.
'''
return K.mean(K.categorical_crossentropy(y_pred, y_true), axis=-1)
return K.categorical_crossentropy(y_pred, y_true)
def sparse_categorical_crossentropy(y_true, y_pred):
'''expects a 1-D or 2-D array of integer classes.
'''
return K.sparse_categorical_crossentropy(y_pred, y_true)
def binary_crossentropy(y_true, y_pred):
return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)
def poisson_loss(y_true, y_pred):
def poisson(y_true, y_pred):
return K.mean(y_pred - y_true * K.log(y_pred + K.epsilon()), axis=-1)
def cosine_proximity(y_true, y_pred):
y_true = K.l2_normalize(y_true, axis=-1)
y_pred = K.l2_normalize(y_pred, axis=-1)
return -K.mean(y_true * y_pred, 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
cosine = cosine_proximity
from .utils.generic_utils import get_from_module
def get(identifier):
+108 -38
Ver Arquivo
@@ -31,6 +31,7 @@ class Optimizer(object):
def __init__(self, **kwargs):
self.__dict__.update(kwargs)
self.updates = []
self.weights = []
def get_state(self):
return [K.get_value(u[0]) for u in self.updates]
@@ -52,13 +53,48 @@ class Optimizer(object):
grads = [K.clip(g, -self.clipvalue, self.clipvalue) for g in grads]
return grads
def set_weights(self, weights):
'''Sets the weights of the optimizer, from Numpy arrays.
Should only be called after computing the gradients
(otherwise the optimizer has no weights).
# Arguments
weights: a list of Numpy arrays. The number
of arrays and their shape must match
number of the dimensions of the weights
of the optimizer (i.e. it should match the
output of `get_weights`).
'''
params = self.weights
if len(params) != len(weights):
raise Exception('Provided weight array does not match weights (' +
str(len(params)) + ' optimizer params vs. ' +
str(len(weights)) + ' provided weights)')
for p, w in zip(params, weights):
if K.get_value(p).shape != w.shape:
raise Exception('Optimizer weight shape ' +
str(K.get_value(p).shape) +
' not compatible with '
'provided weight shape ' + str(w.shape))
K.set_value(p, w)
def get_weights(self):
'''Returns the current weights of the optimizer,
as a list of numpy arrays.
'''
weights = []
for p in self.weights:
weights.append(K.get_value(p))
return weights
def get_config(self):
return {"name": self.__class__.__name__}
class SGD(Optimizer):
'''Stochastic gradient descent, with support for momentum,
decay, and Nesterov momentum.
learning rate decay, and Nesterov momentum.
# Arguments
lr: float >= 0. Learning rate.
@@ -77,10 +113,10 @@ class SGD(Optimizer):
def get_updates(self, params, constraints, loss):
grads = self.get_gradients(loss, params)
lr = self.lr * (1.0 / (1.0 + self.decay * self.iterations))
lr = self.lr * (1. / (1. + self.decay * self.iterations))
self.updates = [(self.iterations, self.iterations + 1.)]
for p, g, c in zip(params, grads, constraints):
for p, g in zip(params, grads):
m = K.variable(np.zeros(K.get_value(p).shape)) # momentum
v = self.momentum * m - lr * g # velocity
self.updates.append((m, v))
@@ -90,7 +126,11 @@ class SGD(Optimizer):
else:
new_p = p + v
self.updates.append((p, c(new_p))) # apply constraints
# apply constraints
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append((p, new_p))
return self.updates
def get_config(self):
@@ -105,7 +145,8 @@ class RMSprop(Optimizer):
'''RMSProp optimizer.
It is recommended to leave the parameters of this optimizer
at their default values.
at their default values
(except the learning rate, which can be freely tuned).
This optimizer is usually a good choice for recurrent
neural networks.
@@ -123,16 +164,21 @@ class RMSprop(Optimizer):
def get_updates(self, params, constraints, loss):
grads = self.get_gradients(loss, params)
accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
# accumulators
self.weights = [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):
for p, g, a in zip(params, grads, self.weights):
# update accumulator
new_a = self.rho * a + (1 - self.rho) * K.square(g)
new_a = self.rho * a + (1. - self.rho) * K.square(g)
self.updates.append((a, new_a))
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
self.updates.append((p, c(new_p))) # apply constraints
# apply constraints
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append((p, new_p))
return self.updates
def get_config(self):
@@ -159,14 +205,19 @@ class Adagrad(Optimizer):
def get_updates(self, params, constraints, loss):
grads = self.get_gradients(loss, params)
accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
# accumulators
self.weights = [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):
for p, g, a in zip(params, grads, self.weights):
new_a = a + K.square(g) # update accumulator
self.updates.append((a, new_a))
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
self.updates.append((p, c(new_p))) # apply constraints
# apply constraints
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append((p, new_p))
return self.updates
def get_config(self):
@@ -182,7 +233,8 @@ class Adadelta(Optimizer):
at their default values.
# Arguments
lr: float >= 0. Learning rate. It is recommended to leave it at the default value.
lr: float >= 0. Learning rate.
It is recommended to leave it at the default value.
rho: float >= 0.
epsilon: float >= 0. Fuzz factor.
@@ -198,19 +250,23 @@ class Adadelta(Optimizer):
grads = self.get_gradients(loss, 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.weights = accumulators + delta_accumulators
self.updates = []
for p, g, a, d_a, c in zip(params, grads, accumulators,
delta_accumulators, constraints):
for p, g, a, d_a in zip(params, grads, accumulators, delta_accumulators):
# update accumulator
new_a = self.rho * a + (1 - self.rho) * K.square(g)
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 * 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
# apply constraints
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append((p, new_p))
# update delta_accumulator
new_d_a = self.rho * d_a + (1 - self.rho) * K.square(update)
@@ -248,24 +304,29 @@ class Adam(Optimizer):
def get_updates(self, params, constraints, loss):
grads = self.get_gradients(loss, params)
self.updates = [(self.iterations, self.iterations+1.)]
self.updates = [(self.iterations, self.iterations + 1)]
t = self.iterations + 1
lr_t = self.lr * K.sqrt(1 - K.pow(self.beta_2, t)) / (1 - K.pow(self.beta_1, t))
lr_t = 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):
# 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))
ms = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
vs = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
self.weights = ms + vs
m_t = (self.beta_1 * m) + (1 - self.beta_1) * g
v_t = (self.beta_2 * v) + (1 - self.beta_2) * K.square(g)
for p, g, m, v in zip(params, grads, ms, vs):
m_t = (self.beta_1 * m) + (1. - self.beta_1) * g
v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(g)
p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)
self.updates.append((m, m_t))
self.updates.append((v, v_t))
self.updates.append((p, c(p_t))) # apply constraints
new_p = p_t
# apply constraints
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append((p, new_p))
return self.updates
def get_config(self):
@@ -275,6 +336,7 @@ class Adam(Optimizer):
"beta_2": float(K.get_value(self.beta_2)),
"epsilon": self.epsilon}
class Adamax(Optimizer):
'''Adamax optimizer from Adam paper's Section 7. It is a variant
of Adam based on the infinity norm.
@@ -293,31 +355,39 @@ class Adamax(Optimizer):
*args, **kwargs):
super(Adamax, self).__init__(**kwargs)
self.__dict__.update(locals())
self.iterations = K.variable(0)
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.)]
self.updates = [(self.iterations, self.iterations + 1)]
t = self.iterations + 1
lr_t = self.lr / (1 - K.pow(self.beta_1, t))
lr_t = self.lr / (1. - K.pow(self.beta_1, t))
for p, g, c in zip(params, grads, constraints):
# zero init of 1st moment
m = K.variable(np.zeros(K.get_value(p).shape))
# zero init of exponentially weighted infinity norm
u = K.variable(np.zeros(K.get_value(p).shape))
# zero init of 1st moment
ms = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
# zero init of exponentially weighted infinity norm
us = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
self.weights = ms + us
m_t = (self.beta_1 * m) + (1 - self.beta_1) * g
for p, g, m, u in zip(params, grads, ms, us):
m_t = (self.beta_1 * m) + (1. - self.beta_1) * g
u_t = K.maximum(self.beta_2 * u, K.abs(g))
p_t = p - lr_t * m_t / (u_t + self.epsilon)
self.updates.append((m, m_t))
self.updates.append((u, u_t))
self.updates.append((p, c(p_t))) # apply constraints
new_p = p_t
# apply constraints
if p in constraints:
c = constraints[p]
new_p = c(new_p)
self.updates.append((p, new_p))
return self.updates
def get_config(self):
+174 -108
Ver Arquivo
@@ -1,3 +1,7 @@
'''Fairly basic set of tools for realtime data augmentation on image data.
Can easily be extended to include new transformations,
new preprocessing methods, etc...
'''
from __future__ import absolute_import
import numpy as np
@@ -7,48 +11,41 @@ from scipy import linalg
from os import listdir
from os.path import isfile, join
import random, math
import math
from six.moves import range
import threading
'''
Fairly basic set of tools for realtime data augmentation on image data.
Can easily be extended to include new transforms, new preprocessing methods, etc...
'''
def random_rotation(x, rg, fill_mode="nearest", cval=0.):
angle = random.uniform(-rg, rg)
x = ndimage.interpolation.rotate(x, angle, axes=(1,2), reshape=False, mode=fill_mode, cval=cval)
def random_rotation(x, rg, fill_mode='nearest', cval=0.):
angle = np.random.uniform(-rg, rg)
x = ndimage.interpolation.rotate(x, angle,
axes=(1, 2),
reshape=False,
mode=fill_mode,
cval=cval)
return x
def random_shift(x, wrg, hrg, fill_mode="nearest", cval=0.):
crop_left_pixels = 0
crop_right_pixels = 0
crop_top_pixels = 0
crop_bottom_pixels = 0
original_w = x.shape[1]
original_h = x.shape[2]
def random_shift(x, wrg, hrg, fill_mode='nearest', cval=0.):
shift_x = shift_y = 0
if wrg:
crop = random.uniform(0., wrg)
split = random.uniform(0, 1)
crop_left_pixels = int(split*crop*x.shape[1])
crop_right_pixels = int((1-split)*crop*x.shape[1])
shift_x = np.random.uniform(-wrg, wrg) * x.shape[2]
if hrg:
crop = random.uniform(0., hrg)
split = random.uniform(0, 1)
crop_top_pixels = int(split*crop*x.shape[2])
crop_bottom_pixels = int((1-split)*crop*x.shape[2])
x = ndimage.interpolation.shift(x, (0, crop_left_pixels, crop_top_pixels), mode=fill_mode, cval=cval)
shift_y = np.random.uniform(-hrg, hrg) * x.shape[1]
x = ndimage.interpolation.shift(x, (0, shift_y, shift_x),
order=0,
mode=fill_mode,
cval=cval)
return x
def horizontal_flip(x):
for i in range(x.shape[0]):
x[i] = np.fliplr(x[i])
return x
def vertical_flip(x):
for i in range(x.shape[0]):
x[i] = np.flipud(x[i])
@@ -59,41 +56,51 @@ def random_barrel_transform(x, intensity):
# TODO
pass
def random_shear(x, intensity):
# TODO
pass
def random_shear(x, intensity, fill_mode='nearest', cval=0.):
shear = np.random.uniform(-intensity, intensity)
shear_matrix = np.array([[1.0, -math.sin(shear), 0.0],
[0.0, math.cos(shear), 0.0],
[0.0, 0.0, 1.0]])
x = ndimage.interpolation.affine_transform(x, shear_matrix,
mode=fill_mode,
order=3,
cval=cval)
return x
def random_channel_shift(x, rg):
# TODO
pass
def random_zoom(x, rg, fill_mode="nearest", cval=0.):
zoom_w = random.uniform(1.-rg, 1.)
zoom_h = random.uniform(1.-rg, 1.)
x = ndimage.interpolation.zoom(x, zoom=(1., zoom_w, zoom_h), mode=fill_mode, cval=cval)
return x # shape of result will be different from shape of input!
def random_zoom(x, rg, fill_mode='nearest', cval=0.):
zoom_w = np.random.uniform(1.-rg, 1.)
zoom_h = np.random.uniform(1.-rg, 1.)
x = ndimage.interpolation.zoom(x, zoom=(1., zoom_w, zoom_h),
mode=fill_mode,
cval=cval)
return x # shape of result will be different from shape of input!
def array_to_img(x, scale=True):
from PIL import Image
x = x.transpose(1, 2, 0)
x = x.transpose(1, 2, 0)
if scale:
x += max(-np.min(x), 0)
x /= np.max(x)
x *= 255
if x.shape[2] == 3:
# RGB
return Image.fromarray(x.astype("uint8"), "RGB")
return Image.fromarray(x.astype('uint8'), 'RGB')
else:
# grayscale
return Image.fromarray(x[:,:,0].astype("uint8"), "L")
return Image.fromarray(x[:, :, 0].astype('uint8'), 'L')
def img_to_array(img):
x = np.asarray(img, dtype='float32')
if len(x.shape)==3:
if len(x.shape) == 3:
# RGB: height, width, channel -> channel, height, width
x = x.transpose(2, 0, 1)
else:
@@ -107,128 +114,179 @@ def load_img(path, grayscale=False):
img = Image.open(path)
if grayscale:
img = img.convert('L')
else: # Assure 3 channel even when loaded image is grayscale
else: # Ensure 3 channel even when loaded image is grayscale
img = img.convert('RGB')
return img
def list_pictures(directory, ext='jpg|jpeg|bmp|png'):
return [join(directory,f) for f in listdir(directory) \
if isfile(join(directory,f)) and re.match('([\w]+\.(?:' + ext + '))', f)]
return [join(directory, f) for f in listdir(directory)
if isfile(join(directory, f)) and re.match('([\w]+\.(?:' + ext + '))', f)]
class ImageDataGenerator(object):
'''
Generate minibatches with
realtime data augmentation.
'''
def __init__(self,
featurewise_center=True, # set input mean to 0 over the dataset
samplewise_center=False, # set each sample mean to 0
featurewise_std_normalization=True, # divide inputs by std of the dataset
samplewise_std_normalization=False, # divide each input by its std
'''Generate minibatches with
real-time data augmentation.
zca_whitening=False, # apply ZCA whitening
rotation_range=0., # degrees (0 to 180)
width_shift_range=0., # fraction of total width
height_shift_range=0., # fraction of total height
horizontal_flip=False,
vertical_flip=False,
):
# Arguments
featurewise_center: set input mean to 0 over the dataset.
samplewise_center: set each sample mean to 0.
featurewise_std_normalization: divide inputs by std of the dataset.
samplewise_std_normalization: divide each input by its std.
zca_whitening: apply ZCA whitening.
rotation_range: degrees (0 to 180).
width_shift_range: fraction of total width.
height_shift_range: fraction of total height.
shear_range: shear intensity (shear angle in radians).
horizontal_flip: whether to randomly flip images horizontally.
vertical_flip: whether to randomly flip images vertically.
'''
def __init__(self,
featurewise_center=True,
samplewise_center=False,
featurewise_std_normalization=True,
samplewise_std_normalization=False,
zca_whitening=False,
rotation_range=0.,
width_shift_range=0.,
height_shift_range=0.,
shear_range=0.,
horizontal_flip=False,
vertical_flip=False):
self.__dict__.update(locals())
self.mean = None
self.std = None
self.principal_components = None
self.lock = threading.Lock()
def _flow_index(self, N, batch_size=32, shuffle=False, seed=None):
b = 0
total_b = 0
while 1:
if b == 0:
if seed is not None:
np.random.seed(seed + total_b)
def flow(self, X, y, batch_size=32, shuffle=False, seed=None, save_to_dir=None, save_prefix="", save_format="jpeg"):
if seed:
random.seed(seed)
if shuffle:
index_array = np.random.permutation(N)
else:
index_array = np.arange(N)
if shuffle:
seed = random.randint(1, 10e6)
np.random.seed(seed)
np.random.shuffle(X)
np.random.seed(seed)
np.random.shuffle(y)
nb_batch = int(math.ceil(float(X.shape[0])/batch_size))
for b in range(nb_batch):
batch_end = (b+1)*batch_size
if batch_end > X.shape[0]:
nb_samples = X.shape[0] - b*batch_size
current_index = (b * batch_size) % N
if N >= current_index + batch_size:
current_batch_size = batch_size
else:
nb_samples = batch_size
current_batch_size = N - current_index
bX = np.zeros(tuple([nb_samples]+list(X.shape)[1:]))
for i in range(nb_samples):
x = X[b*batch_size+i]
x = self.random_transform(x.astype("float32"))
x = self.standardize(x)
bX[i] = x
if current_batch_size == batch_size:
b += 1
else:
b = 0
total_b += 1
yield (index_array[current_index: current_index + current_batch_size],
current_index, current_batch_size)
if save_to_dir:
for i in range(nb_samples):
img = array_to_img(bX[i], scale=True)
img.save(save_to_dir + "/" + save_prefix + "_" + str(i) + "." + save_format)
def flow(self, X, y, batch_size=32, shuffle=False, seed=None,
save_to_dir=None, save_prefix='', save_format='jpeg'):
assert len(X) == len(y)
self.X = X
self.y = y
self.save_to_dir = save_to_dir
self.save_prefix = save_prefix
self.save_format = save_format
self.flow_generator = self._flow_index(X.shape[0], batch_size,
shuffle, seed)
return self
yield bX, y[b*batch_size:b*batch_size+nb_samples]
def __iter__(self):
# needed if we want to do something like:
# for x, y in data_gen.flow(...):
return self
def next(self):
# for python 2.x.
# Keeps under lock only the mechanism which advances
# the indexing of each batch
# see # http://anandology.com/blog/using-iterators-and-generators/
with self.lock:
index_array, current_index, current_batch_size = next(self.flow_generator)
# The transformation of images is not under thread lock so it can be done in parallel
bX = np.zeros(tuple([current_batch_size] + list(self.X.shape)[1:]))
for i, j in enumerate(index_array):
x = self.X[j]
x = self.random_transform(x.astype('float32'))
x = self.standardize(x)
bX[i] = x
if self.save_to_dir:
for i in range(current_batch_size):
img = array_to_img(bX[i], scale=True)
img.save(self.save_to_dir + '/' + self.save_prefix + '_' + str(current_index + i) + '.' + self.save_format)
bY = self.y[index_array]
return bX, bY
def __next__(self):
# for python 3.x.
return self.next()
def standardize(self, x):
if self.samplewise_center:
x -= np.mean(x, axis=1, keepdims=True)
if self.samplewise_std_normalization:
x /= (np.std(x, axis=1, keepdims=True) + 1e-7)
if self.featurewise_center:
x -= self.mean
if self.featurewise_std_normalization:
x /= self.std
x /= (self.std + 1e-7)
if self.zca_whitening:
flatx = np.reshape(x, (x.shape[0]*x.shape[1]*x.shape[2]))
flatx = np.reshape(x, (x.shape[0] * x.shape[1] * x.shape[2]))
whitex = np.dot(flatx, self.principal_components)
x = np.reshape(whitex, (x.shape[0], x.shape[1], x.shape[2]))
if self.samplewise_center:
x -= np.mean(x)
if self.samplewise_std_normalization:
x /= np.std(x)
return x
def random_transform(self, x):
if self.rotation_range:
x = random_rotation(x, self.rotation_range)
if self.width_shift_range or self.height_shift_range:
x = random_shift(x, self.width_shift_range, self.height_shift_range)
if self.horizontal_flip:
if random.random() < 0.5:
if np.random.random() < 0.5:
x = horizontal_flip(x)
if self.vertical_flip:
if random.random() < 0.5:
if np.random.random() < 0.5:
x = vertical_flip(x)
if self.shear_range:
x = random_shear(x, self.shear_range)
# TODO:
# zoom
# barrel/fisheye
# shearing
# 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
augment=False,
rounds=1,
seed=None):
'''
Required for featurewise_center, featurewise_std_normalization and zca_whitening.
'''Required for featurewise_center, featurewise_std_normalization
and zca_whitening.
# Arguments
X: Numpy array, the data to fit on.
augment: whether to fit on randomly augmented samples
rounds: if `augment`,
how many augmentation passes to do over the data
seed: random seed.
'''
X = np.copy(X)
if augment:
aX = np.zeros(tuple([rounds*X.shape[0]]+list(X.shape)[1:]))
aX = np.zeros(tuple([rounds * X.shape[0]] + list(X.shape)[1:]))
for r in range(rounds):
for i in range(X.shape[0]):
img = array_to_img(X[i])
img = self.random_transform(img)
aX[i+r*X.shape[0]] = img_to_array(img)
aX[i + r * X.shape[0]] = img_to_array(img)
X = aX
if self.featurewise_center:
@@ -236,11 +294,19 @@ class ImageDataGenerator(object):
X -= self.mean
if self.featurewise_std_normalization:
self.std = np.std(X, axis=0)
X /= self.std
X /= (self.std + 1e-7)
if self.zca_whitening:
flatX = np.reshape(X, (X.shape[0], X.shape[1]*X.shape[2]*X.shape[3]))
fudge = 10e-6
flatX = np.reshape(X, (X.shape[0], X.shape[1] * X.shape[2] * X.shape[3]))
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)
self.principal_components = np.dot(np.dot(U, np.diag(1. / np.sqrt(S + 10e-7))), U.T)
class GraphImageDataGenerator(ImageDataGenerator):
'''Example of how to build a generator for a Graph model
'''
def next(self):
bX, bY = super(GraphImageDataGenerator, self).next()
return {'input': bX, 'output': bY}
+57 -45
Ver Arquivo
@@ -4,19 +4,20 @@ import numpy as np
import random
from six.moves import range
def pad_sequences(sequences, maxlen=None, dtype='int32', padding='pre', truncating='pre', value=0.):
"""
Pad each sequence to the same length:
the length of the longest sequence.
If maxlen is provided, any sequence longer
than maxlen is truncated to maxlen. Truncation happens off either the beginning (default) or
the end of the sequence.
def pad_sequences(sequences, maxlen=None, dtype='int32',
padding='pre', truncating='pre', value=0.):
'''Pads each sequence to the same length:
the length of the longest sequence.
Supports post-padding and pre-padding (default).
If maxlen is provided, any sequence longer
than maxlen is truncated to maxlen.
Truncation happens off either the beginning (default) or
the end of the sequence.
Parameters:
-----------
Supports post-padding and pre-padding (default).
# Arguments
sequences: list of lists where each element is a sequence
maxlen: int, maximum length
dtype: type to cast the resulting sequence.
@@ -25,53 +26,64 @@ def pad_sequences(sequences, maxlen=None, dtype='int32', padding='pre', truncati
maxlen either in the beginning or in the end of the sequence
value: float, value to pad the sequences to the desired value.
Returns:
# Returns
x: numpy array with dimensions (number_of_sequences, maxlen)
"""
'''
lengths = [len(s) for s in sequences]
nb_samples = len(sequences)
if maxlen is None:
maxlen = np.max(lengths)
x = (np.ones((nb_samples, maxlen)) * value).astype(dtype)
# take the sample shape from the first non empty sequence
# checking for consistency in the main loop below.
sample_shape = tuple()
for s in sequences:
if len(s) > 0:
sample_shape = np.asarray(s).shape[1:]
break
x = (np.ones((nb_samples, maxlen) + sample_shape) * value).astype(dtype)
for idx, s in enumerate(sequences):
if len(s) == 0:
continue # empty list was found
continue # empty list was found
if truncating == 'pre':
trunc = s[-maxlen:]
elif truncating == 'post':
trunc = s[:maxlen]
else:
raise ValueError("Truncating type '%s' not understood" % padding)
raise ValueError('Truncating type "%s" not understood' % truncating)
# check `trunc` has expected shape
trunc = np.asarray(trunc, dtype=dtype)
if trunc.shape[1:] != sample_shape:
raise ValueError('Shape of sample %s of sequence at position %s is different from expected shape %s' %
(trunc.shape[1:], idx, sample_shape))
if padding == 'post':
x[idx, :len(trunc)] = trunc
elif padding == 'pre':
x[idx, -len(trunc):] = trunc
else:
raise ValueError("Padding type '%s' not understood" % padding)
raise ValueError('Padding type "%s" not understood' % padding)
return x
def make_sampling_table(size, sampling_factor=1e-5):
'''
This generates an array where the ith element
is the probability that a word of rank i would be sampled,
according to the sampling distribution used in word2vec.
'''This generates an array where the ith element
is the probability that a word of rank i would be sampled,
according to the sampling distribution used in word2vec.
The word2vec formula is:
p(word) = min(1, sqrt(word.frequency/sampling_factor) / (word.frequency/sampling_factor))
The word2vec formula is:
p(word) = min(1, sqrt(word.frequency/sampling_factor) / (word.frequency/sampling_factor))
We assume that the word frequencies follow Zipf's law (s=1) to derive
a numerical approximation of frequency(rank):
frequency(rank) ~ 1/(rank * (log(rank) + gamma) + 1/2 - 1/(12*rank))
We assume that the word frequencies follow Zipf's law (s=1) to derive
a numerical approximation of frequency(rank):
frequency(rank) ~ 1/(rank * (log(rank) + gamma) + 1/2 - 1/(12*rank))
where gamma is the Euler-Mascheroni constant.
Parameters:
-----------
size: int, number of possible words to sample.
# Arguments
size: int, number of possible words to sample.
'''
gamma = 0.577
rank = np.array(list(range(size)))
@@ -85,28 +97,28 @@ def make_sampling_table(size, sampling_factor=1e-5):
def skipgrams(sequence, vocabulary_size,
window_size=4, negative_samples=1., shuffle=True,
categorical=False, sampling_table=None):
'''
Take a sequence (list of indexes of words),
returns couples of [word_index, other_word index] and labels (1s or 0s),
where label = 1 if 'other_word' belongs to the context of 'word',
and label=0 if 'other_word' is ramdomly sampled
'''Take a sequence (list of indexes of words),
returns couples of [word_index, other_word index] and labels (1s or 0s),
where label = 1 if 'other_word' belongs to the context of 'word',
and label=0 if 'other_word' is ramdomly sampled
Paramaters:
-----------
# Arguments
vocabulary_size: int. maximum possible word index + 1
window_size: int. actually half-window. The window of a word wi will be [i-window_size, i+window_size+1]
negative_samples: float >= 0. 0 for no negative (=random) samples. 1 for same number as positive samples. etc.
categorical: bool. if False, labels will be integers (eg. [0, 1, 1 .. ]),
window_size: int. actually half-window.
The window of a word wi will be [i-window_size, i+window_size+1]
negative_samples: float >= 0. 0 for no negative (=random) samples.
1 for same number as positive samples. etc.
categorical: bool. if False, labels will be
integers (eg. [0, 1, 1 .. ]),
if True labels will be categorical eg. [[1,0],[0,1],[0,1] .. ]
Returns:
--------
# Returns
couples, lables: where `couples` are int pairs and
`labels` are either 0 or 1.
Notes:
------
By convention, index 0 in the vocabulary is a non-word and will be skipped.
# Notes
By convention, index 0 in the vocabulary is
a non-word and will be skipped.
'''
couples = []
labels = []
@@ -135,7 +147,7 @@ def skipgrams(sequence, vocabulary_size,
words = [c[0] for c in couples]
random.shuffle(words)
couples += [[words[i%len(words)], random.randint(1, vocabulary_size-1)] for i in range(nb_negative_samples)]
couples += [[words[i %len(words)], random.randint(1, vocabulary_size-1)] for i in range(nb_negative_samples)]
if categorical:
labels += [[1,0]]*nb_negative_samples
else:
+51 -39
Ver Arquivo
@@ -1,11 +1,11 @@
# -*- coding: utf-8 -*-
'''
These preprocessing utils would greatly benefit
from a fast Cython rewrite.
'''These preprocessing utilities would greatly benefit
from a fast Cython rewrite.
'''
from __future__ import absolute_import
import string, sys
import string
import sys
import numpy as np
from six.moves import range
from six.moves import zip
@@ -40,7 +40,7 @@ def one_hot(text, n, filters=base_filter(), lower=True, split=" "):
class Tokenizer(object):
def __init__(self, nb_words=None, filters=base_filter(),
lower=True, split=' '):
lower=True, split=' ', char_level=False):
'''The class allows to vectorize a text corpus, by turning each
text into either a sequence of integers (each integer being the index
of a token in a dictionary) or into a vector where the coefficient
@@ -55,6 +55,7 @@ class Tokenizer(object):
tabs and line breaks, minus the `'` character.
lower: boolean. Whether to convert the texts to lowercase.
split: character or string to use for token splitting.
char_level: if True, every character will be treated as a word.
By default, all punctuation is removed, turning the texts into
space-separated sequences of words
@@ -70,10 +71,10 @@ class Tokenizer(object):
self.lower = lower
self.nb_words = nb_words
self.document_count = 0
self.char_level = char_level
def fit_on_texts(self, texts):
'''
required before using texts_to_sequences or texts_to_matrix
'''Required before using texts_to_sequences or texts_to_matrix
# Arguments
texts: can be a list of strings,
@@ -82,7 +83,7 @@ class Tokenizer(object):
self.document_count = 0
for text in texts:
self.document_count += 1
seq = text_to_word_sequence(text, self.filters, self.lower, self.split)
seq = text if self.char_level else text_to_word_sequence(text, self.filters, self.lower, self.split)
for w in seq:
if w in self.word_counts:
self.word_counts[w] += 1
@@ -104,9 +105,8 @@ class Tokenizer(object):
self.index_docs[self.word_index[w]] = c
def fit_on_sequences(self, sequences):
'''
required before using sequences_to_matrix
(if fit_on_texts was never called)
'''Required before using sequences_to_matrix
(if fit_on_texts was never called)
'''
self.document_count = len(sequences)
self.index_docs = {}
@@ -119,12 +119,11 @@ class Tokenizer(object):
self.index_docs[i] += 1
def texts_to_sequences(self, texts):
'''
Transform each text in texts in a sequence of integers.
Only top "nb_words" most frequent words will be taken into account.
Only words known by the tokenizer will be taken into account.
'''Transforms each text in texts in a sequence of integers.
Only top "nb_words" most frequent words will be taken into account.
Only words known by the tokenizer will be taken into account.
Returns a list of sequences.
Returns a list of sequences.
'''
res = []
for vect in self.texts_to_sequences_generator(texts):
@@ -132,71 +131,84 @@ class Tokenizer(object):
return res
def texts_to_sequences_generator(self, texts):
'''
Transform each text in texts in a sequence of integers.
Only top "nb_words" most frequent words will be taken into account.
Only words known by the tokenizer will be taken into account.
'''Transforms each text in texts in a sequence of integers.
Only top "nb_words" most frequent words will be taken into account.
Only words known by the tokenizer will be taken into account.
Yields individual sequences.
Yields individual sequences.
# Arguments:
texts: list of strings.
'''
nb_words = self.nb_words
for text in texts:
seq = text_to_word_sequence(text, self.filters, self.lower, self.split)
seq = text if self.char_level else text_to_word_sequence(text, self.filters, self.lower, self.split)
vect = []
for w in seq:
i = self.word_index.get(w)
if i is not None:
if nb_words and i >= nb_words:
pass
continue
else:
vect.append(i)
yield vect
def texts_to_matrix(self, texts, mode="binary"):
'''
modes: binary, count, tfidf, freq
def texts_to_matrix(self, texts, mode='binary'):
'''Convert a list of texts to a Numpy matrix,
according to some vectorization mode.
# Arguments:
texts: list of strings.
modes: one of "binary", "count", "tfidf", "freq"
'''
sequences = self.texts_to_sequences(texts)
return self.sequences_to_matrix(sequences, mode=mode)
def sequences_to_matrix(self, sequences, mode="binary"):
'''
modes: binary, count, tfidf, freq
def sequences_to_matrix(self, sequences, mode='binary'):
'''Converts a list of sequences into a Numpy matrix,
according to some vectorization mode.
# Arguments:
sequences: list of sequences
(a sequence is a list of integer word indices).
modes: one of "binary", "count", "tfidf", "freq"
'''
if not self.nb_words:
if self.word_index:
nb_words = len(self.word_index) + 1
else:
raise Exception("Specify a dimension (nb_words argument), or fit on some text data first.")
raise Exception('Specify a dimension (nb_words argument), '
'or fit on some text data first.')
else:
nb_words = self.nb_words
if mode == "tfidf" and not self.document_count:
raise Exception("Fit the Tokenizer on some data before using tfidf mode.")
if mode == 'tfidf' and not self.document_count:
raise Exception('Fit the Tokenizer on some data '
'before using tfidf mode.')
X = np.zeros((len(sequences), nb_words))
for i, seq in enumerate(sequences):
if not seq:
pass
continue
counts = {}
for j in seq:
if j >= nb_words:
pass
continue
if j not in counts:
counts[j] = 1.
else:
counts[j] += 1
for j, c in list(counts.items()):
if mode == "count":
if mode == 'count':
X[i][j] = c
elif mode == "freq":
elif mode == 'freq':
X[i][j] = c / len(seq)
elif mode == "binary":
elif mode == 'binary':
X[i][j] = 1
elif mode == "tfidf":
elif mode == 'tfidf':
tf = np.log(c / len(seq))
df = (1 + np.log(1 + self.index_docs.get(j, 0) / (1 + self.document_count)))
X[i][j] = tf / df
else:
raise Exception("Unknown vectorization mode: " + str(mode))
raise Exception('Unknown vectorization mode: ' + str(mode))
return X
+33 -19
Ver Arquivo
@@ -13,46 +13,61 @@ class Regularizer(object):
return loss
def get_config(self):
return {"name": self.__class__.__name__}
return {'name': self.__class__.__name__}
class WeightRegularizer(Regularizer):
def __init__(self, l1=0., l2=0.):
self.l1 = l1
self.l2 = l2
self.l1 = K.cast_to_floatx(l1)
self.l2 = K.cast_to_floatx(l2)
self.uses_learning_phase = True
def set_param(self, p):
self.p = p
def __call__(self, loss):
loss += K.sum(K.abs(self.p)) * self.l1
loss += K.sum(K.square(self.p)) * self.l2
return loss
if not hasattr(self, 'p'):
raise Exception('Need to call `set_param` on '
'WeightRegularizer instance '
'before calling the instance. '
'Check that you are not passing '
'a WeightRegularizer instead of an '
'ActivityRegularizer '
'(i.e. activity_regularizer="l2" instead '
'of activity_regularizer="activity_l2".')
regularized_loss = loss + K.sum(K.abs(self.p)) * self.l1
regularized_loss += K.sum(K.square(self.p)) * self.l2
return K.in_train_phase(regularized_loss, loss)
def get_config(self):
return {"name": self.__class__.__name__,
"l1": self.l1,
"l2": self.l2}
return {'name': self.__class__.__name__,
'l1': self.l1,
'l2': self.l2}
class ActivityRegularizer(Regularizer):
def __init__(self, l1=0., l2=0.):
self.l1 = l1
self.l2 = l2
self.l1 = K.cast_to_floatx(l1)
self.l2 = K.cast_to_floatx(l2)
self.uses_learning_phase = True
def set_layer(self, layer):
self.layer = layer
def __call__(self, loss):
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
if not hasattr(self, 'layer'):
raise Exception('Need to call `set_layer` on '
'ActivityRegularizer instance '
'before calling the instance.')
output = self.layer.output
regularized_loss = loss + self.l1 * K.sum(K.mean(K.abs(output), axis=0))
regularized_loss += self.l2 * K.sum(K.mean(K.square(output), axis=0))
return K.in_train_phase(regularized_loss, loss)
def get_config(self):
return {"name": self.__class__.__name__,
"l1": self.l1,
"l2": self.l2}
return {'name': self.__class__.__name__,
'l1': self.l1,
'l2': self.l2}
def l1(l=0.01):
@@ -78,7 +93,6 @@ def activity_l2(l=0.01):
def activity_l1l2(l1=0.01, l2=0.01):
return ActivityRegularizer(l1=l1, l2=l2)
identity = Regularizer
from .utils.generic_utils import get_from_module
def get(identifier, kwargs=None):
+95
Ver Arquivo
@@ -0,0 +1,95 @@
from __future__ import absolute_import
from __future__ import print_function
import tarfile
import os
import sys
import shutil
from six.moves.urllib.request import urlopen
from six.moves.urllib.error import URLError, HTTPError
from ..utils.generic_utils import Progbar
# Under Python 2, 'urlretrieve' relies on FancyURLopener from legacy
# urllib module, known to have issues with proxy management
if sys.version_info[0] == 2:
def urlretrieve(url, filename, reporthook=None, data=None):
def chunk_read(response, chunk_size=8192, reporthook=None):
total_size = response.info().get('Content-Length').strip()
total_size = int(total_size)
count = 0
while 1:
chunk = response.read(chunk_size)
if not chunk:
break
count += 1
if reporthook:
reporthook(count, chunk_size, total_size)
yield chunk
response = urlopen(url, data)
with open(filename, 'wb') as fd:
for chunk in chunk_read(response, reporthook=reporthook):
fd.write(chunk)
else:
from six.moves.urllib.request import urlretrieve
def get_file(fname, origin, untar=False):
datadir_base = os.path.expanduser(os.path.join('~', '.keras'))
if not os.access(datadir_base, os.W_OK):
datadir_base = os.path.join('/tmp', '.keras')
datadir = os.path.join(datadir_base, 'datasets')
if not os.path.exists(datadir):
os.makedirs(datadir)
if untar:
untar_fpath = os.path.join(datadir, fname)
fpath = untar_fpath + '.tar.gz'
else:
fpath = os.path.join(datadir, fname)
if not os.path.exists(fpath):
print('Downloading data from', origin)
global progbar
progbar = None
def dl_progress(count, block_size, total_size):
global progbar
if progbar is None:
progbar = Progbar(total_size)
else:
progbar.update(count*block_size)
error_msg = 'URL fetch failure on {}: {} -- {}'
try:
try:
urlretrieve(origin, fpath, dl_progress)
except URLError as e:
raise Exception(error_msg.format(origin, e.errno, e.reason))
except HTTPError as e:
raise Exception(error_msg.format(origin, e.code, e.msg))
except (Exception, KeyboardInterrupt) as e:
if os.path.exists(fpath):
os.remove(fpath)
raise e
progbar = None
if untar:
if not os.path.exists(untar_fpath):
print('Untaring file...')
tfile = tarfile.open(fpath, 'r:gz')
try:
tfile.extractall(path=datadir)
except (Exception, KeyboardInterrupt) as e:
if os.path.exists(untar_fpath):
if os.path.isfile(untar_fpath):
os.remove(untar_fpath)
else:
shutil.rmtree(untar_fpath)
raise e
tfile.close()
return untar_fpath
return fpath
+29 -7
Ver Arquivo
@@ -18,6 +18,14 @@ def get_from_module(identifier, module_params, module_name,
return res(**kwargs)
else:
return res
elif type(identifier) is dict:
name = identifier.pop('name')
res = module_params.get(name)
if res:
return res(**identifier)
else:
raise Exception('Invalid ' + str(module_name) + ': ' +
str(identifier))
return identifier
@@ -63,15 +71,15 @@ class Progbar(object):
numdigits = int(np.floor(np.log10(self.target))) + 1
barstr = '%%%dd/%%%dd [' % (numdigits, numdigits)
bar = barstr % (current, self.target)
prog = float(current)/self.target
prog_width = int(self.width*prog)
prog = float(current) / self.target
prog_width = int(self.width * prog)
if prog_width > 0:
bar += ('='*(prog_width-1))
bar += ('=' * (prog_width-1))
if current < self.target:
bar += '>'
else:
bar += '='
bar += ('.'*(self.width-prog_width))
bar += ('.' * (self.width - prog_width))
bar += ']'
sys.stdout.write(bar)
self.total_width = len(bar)
@@ -80,7 +88,7 @@ class Progbar(object):
time_per_unit = (now - self.start) / current
else:
time_per_unit = 0
eta = time_per_unit*(self.target - current)
eta = time_per_unit * (self.target - current)
info = ''
if current < self.target:
info += ' - ETA: %ds' % eta
@@ -99,7 +107,7 @@ class Progbar(object):
self.total_width += len(info)
if prev_total_width > self.total_width:
info += ((prev_total_width-self.total_width) * " ")
info += ((prev_total_width - self.total_width) * " ")
sys.stdout.write(info)
sys.stdout.flush()
@@ -120,4 +128,18 @@ class Progbar(object):
sys.stdout.write(info + "\n")
def add(self, n, values=[]):
self.update(self.seen_so_far+n, values)
self.update(self.seen_so_far + n, values)
def display_table(rows, positions):
def display_row(objects, positions):
line = ''
for i in range(len(objects)):
line += str(objects[i])
line = line[:positions[i]]
line += ' ' * (positions[i] - len(line))
print(line)
for objects in rows:
display_row(objects, positions)
+73 -130
Ver Arquivo
@@ -1,154 +1,97 @@
from __future__ import print_function
import inspect
import numpy as np
import copy
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
from .generic_utils import get_from_module
from ..layers import *
from ..models import Model, Sequential, Graph
from .. import backend as K
def container_from_config(original_layer_dict, custom_objects={}):
layer_dict = copy.deepcopy(original_layer_dict)
name = layer_dict.get('name')
def layer_from_config(config, custom_objects={}):
'''
# Arguments
config: dict of the form {'class_name': str, 'config': dict}
custom_objects: dict mapping class names (or function names)
of custom (non-Keras) objects to class/functions
# Returns
Layer instance (may be Model, Sequential, Graph, Layer...)
'''
# 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')
concat_axis = layer_dict.get('concat_axis')
dot_axes = layer_dict.get('dot_axes')
layers = layer_dict.get('layers')
layer_list = []
for layer in layers:
init_layer = container_from_config(layer)
layer_list.append(init_layer)
merge_layer = Merge(layer_list, mode, concat_axis, dot_axes)
return merge_layer
elif name == 'Sequential':
layers = layer_dict.get('layers')
layer_list = []
for layer in layers:
init_layer = container_from_config(layer)
layer_list.append(init_layer)
seq_layer = containers.Sequential(layer_list)
return seq_layer
elif name == 'Graph':
graph_layer = containers.Graph()
inputs = layer_dict.get('input_config')
for input in inputs:
graph_layer.add_input(**input)
nodes = layer_dict.get('node_config')
for node in nodes:
layer = container_from_config(layer_dict['nodes'].get(node['name']))
node['layer'] = layer
graph_layer.add_node(**node)
outputs = layer_dict.get('output_config')
for output in outputs:
graph_layer.add_output(**output)
return graph_layer
elif name == 'AutoEncoder':
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]
return AutoEncoder(**kwargs)
class_name = config['class_name']
if class_name == 'Sequential':
layer_class = Sequential
elif class_name == 'Graph':
layer_class = Graph
elif class_name in ['Model', 'Container']:
layer_class = Model
else:
layer_dict.pop('name')
for k, v in layer_dict.items():
if isinstance(v, dict):
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)
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)
return base_layer
layer_class = get_from_module(class_name, globals(), 'layer',
instantiate=False)
return layer_class.from_config(config['config'])
def model_summary(model):
param_count = 0 # param count in the model
def print_summary(layers, relevant_nodes=None):
line_length = 100 # total length of printed lines
positions = [35, 55, 67, 100] # absolute positions of log elements in each line
# header names for the different log elements
to_display = ['Layer (type)', 'Output Shape', 'Param #', 'Connected to']
def display(objects, positions):
def print_row(fields, positions):
line = ''
for i in range(len(objects)):
line += str(objects[i])
for i in range(len(fields)):
line += str(fields[i])
line = line[:positions[i]]
line += ' ' * (positions[i] - len(line))
print(line)
def display_layer_info(layer, name, positions):
layer_type = layer.__class__.__name__
output_shape = layer.output_shape
params = layer.count_params()
to_display = ['%s (%s)' % (layer_type, name), output_shape, params]
display(to_display, positions)
print('_' * line_length)
print_row(to_display, positions)
print('=' * line_length)
line_length = 80 # total length of printed lines
positions = [30, 60, 80] # absolute positions of log elements in each line
# header names for the different log elements
to_display = ['Layer (name)', 'Output Shape', 'Param #']
def print_layer_summary(layer):
try:
output_shape = layer.output_shape
except:
output_shape = 'multiple'
connections = []
for node_index, node in enumerate(layer.inbound_nodes):
if relevant_nodes:
node_key = layer.name + '_ib-' + str(node_index)
if node_key not in relevant_nodes:
# node is node part of the current network
continue
for i in range(len(node.inbound_layers)):
inbound_layer = node.inbound_layers[i].name
inbound_node_index = node.node_indices[i]
inbound_tensor_index = node.tensor_indices[i]
connections.append(inbound_layer + '[' + str(inbound_node_index) + '][' + str(inbound_tensor_index) + ']')
# for sequential models, we start by printing
# the expect input shape
if model.__class__.__name__ == 'Sequential':
print('-' * line_length)
print('Initial input shape: ' + str(model.input_shape))
name = layer.name
cls_name = layer.__class__.__name__
if not connections:
first_connection = ''
else:
first_connection = connections[0]
fields = [name + ' (' + cls_name + ')', output_shape, layer.count_params(), first_connection]
print_row(fields, positions)
if len(connections) > 1:
for i in range(1, len(connections)):
fields = ['', '', '', connections[i]]
print_row(fields, positions)
# print header
print('-' * line_length)
display(to_display, positions)
print('-' * line_length)
total_params = 0
for i in range(len(layers)):
print_layer_summary(layers[i])
if i == len(layers) - 1:
print('=' * line_length)
else:
print('_' * line_length)
total_params += layers[i].count_params()
if model.__class__.__name__ == 'Sequential':
for layer in model.layers:
name = getattr(layer, 'name', 'Unnamed')
display_layer_info(layer, name, positions)
param_count += layer.count_params()
elif model.__class__.__name__ == 'Graph':
for name in model.input_order:
layer = model.inputs[name]
display_layer_info(layer, name, positions)
for name in model.nodes:
layer = model.nodes[name]
display_layer_info(layer, name, positions)
param_count += layer.count_params()
for name in model.output_order:
layer = model.outputs[name]
display_layer_info(layer, name, positions)
print('-' * line_length)
print('Total params: %s' % param_count)
print('-' * line_length)
from .generic_utils import get_from_module
def get_layer(identifier, kwargs=None):
return get_from_module(identifier, globals(), 'layer',
instantiate=True, kwargs=kwargs)
print('Total params: %s' % total_params)
print('_' * line_length)
+79 -2
Ver Arquivo
@@ -1,7 +1,14 @@
import numpy as np
from numpy.testing import assert_allclose
import inspect
from ..engine import Model, Input
from ..models import Sequential, model_from_json
from .. import backend as K
def get_test_data(nb_train=1000, nb_test=500, input_shape=(10,), output_shape=(2,),
def get_test_data(nb_train=1000, nb_test=500, input_shape=(10,),
output_shape=(2,),
classification=True, nb_class=2):
'''
classification=True overrides output_shape
@@ -12,7 +19,7 @@ def get_test_data(nb_train=1000, nb_test=500, input_shape=(10,), output_shape=(2
'''
nb_sample = nb_train + nb_test
if classification:
y = np.random.randint(0, nb_class, size=(nb_sample, 1))
y = np.random.randint(0, nb_class, size=(nb_sample,))
X = np.zeros((nb_sample,) + input_shape)
for i in range(nb_sample):
X[i] = np.random.normal(loc=y[i], scale=0.7, size=input_shape)
@@ -25,3 +32,73 @@ def get_test_data(nb_train=1000, nb_test=500, input_shape=(10,), output_shape=(2
y[i] = np.random.normal(loc=y_loc[i], scale=0.7, size=output_shape)
return (X[:nb_train], y[:nb_train]), (X[nb_train:], y[nb_train:])
def layer_test(layer_cls, kwargs={}, input_shape=None, input_dtype=None,
input_data=None, expected_output=None, expected_output_dtype=None):
'''Test routine for a layer with a single input tensor
and single output tensor.
'''
if input_data is None:
assert input_shape
if not input_dtype:
input_dtype = K.floatx()
input_data = (10 * np.random.random(input_shape)).astype(input_dtype)
elif input_shape is None:
input_shape = input_data.shape
if expected_output_dtype is None:
expected_output_dtype = input_dtype
# instantiation
layer = layer_cls(**kwargs)
# test get_weights , set_weights
weights = layer.get_weights()
layer.set_weights(weights)
# test and instantiation from weights
if 'weights' in inspect.getargspec(layer_cls.__init__):
kwargs['weights'] = weights
layer = layer_cls(**kwargs)
# test in functional API
x = Input(shape=input_shape[1:], dtype=input_dtype)
y = layer(x)
assert K.dtype(y) == expected_output_dtype
model = Model(input=x, output=y)
model.compile('rmsprop', 'mse')
expected_output_shape = layer.get_output_shape_for(input_shape)
actual_output = model.predict(input_data)
actual_output_shape = actual_output.shape
assert expected_output_shape == actual_output_shape
if expected_output is not None:
assert_allclose(actual_output, expected_output, rtol=1e-3)
# test serialization
model_config = model.get_config()
model = Model.from_config(model_config)
model.compile('rmsprop', 'mse')
# test as first layer in Sequential API
layer_config = layer.get_config()
layer_config['batch_input_shape'] = input_shape
layer = layer.__class__.from_config(layer_config)
model = Sequential()
model.add(layer)
model.compile('rmsprop', 'mse')
actual_output = model.predict(input_data)
actual_output_shape = actual_output.shape
assert expected_output_shape == actual_output_shape
if expected_output is not None:
assert_allclose(actual_output, expected_output, rtol=1e-3)
# test JSON serialization
json_model = model.to_json()
model = model_from_json(json_model)
# for further checks in the caller function
return actual_output
+44 -137
Ver Arquivo
@@ -1,7 +1,3 @@
import itertools
from keras.layers.containers import Graph, Sequential
from keras.layers.core import Merge
try:
# pydot-ng is a fork of pydot that is better maintained
import pydot_ng as pydot
@@ -9,146 +5,57 @@ except ImportError:
# fall back on pydot if necessary
import pydot
if not pydot.find_graphviz():
raise RuntimeError("Failed to import pydot. You must install pydot"
" and graphviz for `pydotprint` to work.")
raise RuntimeError('Failed to import pydot. You must install pydot'
' and graphviz for `pydotprint` to work.')
def layer_typename(layer):
return type(layer).__module__ + "." + type(layer).__name__
def model_to_dot(model, show_shapes=False):
dot = pydot.Dot()
dot.set('rankdir', 'TB')
dot.set('concentrate', True)
dot.set_node_defaults(shape='record')
if model.__class__.__name__ == 'Sequential':
if not model.built:
model.build()
model = model.model
layers = model.layers
def get_layer_to_name(model):
"""Returns a dict mapping layer to their name in the model"""
if not isinstance(model, Graph):
return {}
else:
node_to_name = itertools.chain(
model.nodes.items(), model.inputs.items(), model.outputs.items()
)
return {v: k for k, v in node_to_name}
# first, populate the nodes of the graph
for layer in layers:
layer_id = str(id(layer))
label = str(layer.name) + ' (' + layer.__class__.__name__ + ')'
class ModelToDot(object):
"""
This is a helper class which visits a keras model (Sequential or Graph) and
returns a pydot.Graph representation.
This is implemented as a class because we need to maintain various states.
Use it as ```ModelToDot()(model)```
Keras models can have an arbitrary number of inputs and outputs. A given
layer can have multiple inputs but has a single output. We therefore
explore the model by starting at its output and crawling "up" the tree.
"""
def _pydot_node_for_layer(self, layer, label):
"""
Returns the pydot.Node corresponding to the given layer.
`label` specify the name of the layer (only used if the layer isn't yet
associated with a pydot.Node)
"""
# Check if this already exists (will be the case for nodes that
# serve as input to more than one layer)
if layer in self.layer_to_pydotnode:
node = self.layer_to_pydotnode[layer]
else:
layer_id = 'layer%d' % self.idgen
self.idgen += 1
label = label + " (" + layer_typename(layer) + ")"
if self.show_shape:
# Build the label that will actually contain a table with the
# input/output
outputlabels = str(layer.output_shape)
if hasattr(layer, 'input_shape'):
inputlabels = str(layer.input_shape)
elif hasattr(layer, 'input_shapes'):
inputlabels = ', '.join(
[str(ishape) for ishape in layer.input_shapes])
else:
inputlabels = ''
label = "%s\n|{input:|output:}|{{%s}|{%s}}" % (
label, inputlabels, outputlabels)
node = pydot.Node(layer_id, label=label)
self.g.add_node(node)
self.layer_to_pydotnode[layer] = node
return node
def _process_layer(self, layer, layer_to_name=None, connect_to=None):
"""
Process a layer, adding its node to the graph and creating edges to its
outputs.
`connect_to` specify where the output of the current layer will be
connected
`layer_to_name` is a dict mapping layer to their name in the Graph
model. Should be {} when processing a Sequential model
"""
# The layer can be a container layer, in which case we can recurse
is_graph = isinstance(layer, Graph)
is_seq = isinstance(layer, Sequential)
if self.recursive and (is_graph or is_seq):
# We got a container layer, recursively transform it
if is_graph:
child_layers = layer.outputs.values()
if show_shapes:
# Build the label that will actually contain a table with the
# input/output
outputlabels = str(layer.output_shape)
if hasattr(layer, 'input_shape'):
inputlabels = str(layer.input_shape)
elif hasattr(layer, 'input_shapes'):
inputlabels = ', '.join(
[str(ishape) for ishape in layer.input_shapes])
else:
child_layers = [layer.layers[-1]]
for l in child_layers:
self._process_layer(l, layer_to_name=get_layer_to_name(layer),
connect_to=connect_to)
else:
# This is a simple layer.
label = layer_to_name.get(layer, '')
layer_node = self._pydot_node_for_layer(layer, label=label)
inputlabels = ''
label = '%s\n|{input:|output:}|{{%s}|{%s}}' % (label, inputlabels, outputlabels)
if connect_to is not None:
self.g.add_edge(pydot.Edge(layer_node, connect_to))
node = pydot.Node(layer_id, label=label)
dot.add_node(node)
# Proceed upwards to the parent(s). Only Merge layers have more
# than one parent
if isinstance(layer, Merge): # Merge layer
for l in layer.layers:
self._process_layer(l, layer_to_name,
connect_to=layer_node)
elif hasattr(layer, 'previous') and layer.previous is not None:
self._process_layer(layer.previous, layer_to_name,
connect_to=layer_node)
def __call__(self, model, recursive=True, show_shape=False,
connect_to=None):
self.idgen = 0
# Maps keras layer to the pydot.Node representing them
self.layer_to_pydotnode = {}
self.recursive = recursive
self.show_shape = show_shape
self.g = pydot.Dot()
self.g.set('rankdir', 'TB')
self.g.set('concentrate', True)
self.g.set_node_defaults(shape='record')
if hasattr(model, 'outputs'):
# Graph
for name, l in model.outputs.items():
self._process_layer(l, get_layer_to_name(model),
connect_to=connect_to)
else:
# Sequential container
self._process_layer(model.layers[-1], {}, connect_to=connect_to)
return self.g
# second, add the edges
for layer in layers:
layer_id = str(id(layer))
for i, node in enumerate(layer.inbound_nodes):
node_key = layer.name + '_ib-' + str(i)
if node_key in model.container_nodes:
# add edges
for inbound_layer in node.inbound_layers:
inbound_layer_id = str(id(inbound_layer))
layer_id = str(id(layer))
dot.add_edge(pydot.Edge(inbound_layer_id, layer_id))
return dot
def to_graph(model, **kwargs):
"""
`recursive` controls whether we recursively explore container layers
`show_shape` controls whether the shape is shown in the graph
"""
return ModelToDot()(model, **kwargs)
def plot(model, to_file='model.png'):
graph = to_graph(model)
graph.write_png(to_file)
def plot(model, to_file='model.png', show_shapes=False):
dot = model_to_dot(model, show_shapes)
dot.write_png(to_file)
+224 -212
Ver Arquivo
@@ -1,266 +1,278 @@
from __future__ import absolute_import
import abc
import copy
import inspect
import types
import numpy as np
from ..utils.np_utils import to_categorical
from ..models import Sequential
class BaseWrapper(object):
"""
Base class for the Keras scikit-learn wrapper.
'''Base class for the Keras scikit-learn wrapper.
Warning: This class should not be used directly. Use derived classes instead.
Warning: This class should not be used directly.
Use descendant classes instead.
Parameters
----------
train_batch_size : int, optional
Number of training samples evaluated at a time.
test_batch_size : int, optional
Number of test samples evaluated at a time.
nb_epochs : int, optional
Number of training epochs.
shuffle : boolean, optional
Whether to shuffle the samples at each epoch.
show_accuracy : boolean, optional
Whether to display class accuracy in the logs at each epoch.
validation_split : float [0, 1], optional
Fraction of the data to use as held-out validation data.
validation_data : tuple (X, y), optional
Data to be used as held-out validation data. Will override validation_split.
callbacks : list, optional
List of callbacks to apply during training.
verbose : int, optional
Verbosity level.
"""
__metaclass__ = abc.ABCMeta
# Arguments
build_fn: callable function or class instance
sk_params: model parameters & fitting parameters
@abc.abstractmethod
def __init__(self, model, optimizer, loss,
train_batch_size=128, test_batch_size=128,
nb_epoch=100, shuffle=True, show_accuracy=False,
validation_split=0, validation_data=None, callbacks=None,
verbose=0,):
self.model = model
self.optimizer = optimizer
self.loss = loss
self.compiled_model_ = None
self.classes_ = []
self.config_ = []
self.weights_ = []
The build_fn should construct, compile and return a Keras model, which
will then be used to fit/predict. One of the following
three values could be passed to build_fn:
1. A function
2. An instance of a class that implements the __call__ method
3. None. This means you implement a class that inherits from either
`KerasClassifier` or `KerasRegressor`. The __call__ method of the
present class will then be treated as the default build_fn.
self.train_batch_size = train_batch_size
self.test_batch_size = test_batch_size
self.nb_epoch = nb_epoch
self.shuffle = shuffle
self.show_accuracy = show_accuracy
self.validation_split = validation_split
self.validation_data = validation_data
self.callbacks = [] if callbacks is None else callbacks
`sk_params` takes both model parameters and fitting parameters. Legal model
parameters are the arguments of `build_fn`. Note that like all other
estimators in scikit-learn, 'build_fn' should provide defalult values for
its arguments, so that you could create the estimator without passing any
values to `sk_params`.
self.verbose = verbose
`sk_params` could also accept parameters for calling `fit`, `predict`,
`predict_proba`, and `score` methods (e.g., `nb_epoch`, `batch_size`).
fitting (predicting) parameters are selected in the following order:
1. Values passed to the dictionary arguments of
`fit`, `predict`, `predict_proba`, and `score` methods
2. Values passed to `sk_params`
3. The default values of the `keras.models.Sequential`
`fit`, `predict`, `predict_proba` and `score` methods
When using scikit-learn's `grid_search` API, legal tunable parameters are
those you could pass to `sk_params`, including fitting parameters.
In other words, you could use `grid_search` to search for the best
`batch_size` or `nb_epoch` as well as the model parameters.
'''
def __init__(self, build_fn=None, **sk_params):
self.build_fn = build_fn
self.sk_params = sk_params
self.check_params(sk_params)
def check_params(self, params):
'''Check for user typos in "params" keys to avoid
unwanted usage of default values
# Arguments
params: dictionary
The parameters to be checked
'''
legal_params_fns = [Sequential.fit, Sequential.predict,
Sequential.predict_classes, Sequential.evaluate]
if self.build_fn is None:
legal_params_fns.append(self.__call__)
elif not isinstance(self.build_fn, types.FunctionType):
legal_params_fns.append(self.build_fn.__call__)
else:
legal_params_fns.append(self.build_fn)
legal_params = []
for fn in legal_params_fns:
legal_params += inspect.getargspec(fn)[0]
legal_params = set(legal_params)
for params_name in params:
if params_name not in legal_params:
assert False, '{} is not a legal parameter'.format(params_name)
def get_params(self, deep=True):
"""
Get parameters for this estimator.
'''Get parameters for this estimator.
Parameters
----------
deep: boolean, optional
If True, will return the parameters for this estimator and
contained subobjects that are estimators.
# Arguments
deep: boolean, optional
If True, will return the parameters for this estimator and
contained sub-objects that are estimators.
Returns
-------
params : dict
Dictionary of parameter names mapped to their values.
"""
return {'model': self.model, 'optimizer': self.optimizer, 'loss': self.loss}
# Returns
params : dict
Dictionary of parameter names mapped to their values.
'''
res = copy.deepcopy(self.sk_params)
res.update({'build_fn': self.build_fn})
return res
def set_params(self, **params):
"""
Set the parameters of this estimator.
'''Set the parameters of this estimator.
Parameters
----------
# Arguments
params: dict
Dictionary of parameter names mapped to their values.
Returns
-------
self
"""
for parameter, value in params.items():
setattr(self, parameter, value)
# Returns
self
'''
self.check_params(params)
self.sk_params.update(params)
return self
def fit(self, X, y):
"""
Fit the model according to the given training data.
def fit(self, X, y, **kwargs):
'''Construct a new model with build_fn and fit the model according
to the given training data.
Makes a copy of the un-compiled model definition to use for
compilation and fitting, leaving the original definition
intact.
# Arguments
X : array-like, shape `(n_samples, n_features)`
Training samples where n_samples in the number of samples
and n_features is the number of features.
y : array-like, shape `(n_samples,)` or `(n_samples, n_outputs)`
True labels for X.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.fit`
Parameters
----------
X : array-like, shape = (n_samples, n_features)
Training samples where n_samples in the number of samples
and n_features is the number of features.
y : array-like, shape = (n_samples) or (n_samples, n_outputs)
True labels for X.
# Returns
history : object
details about the training history at each epoch.
'''
Returns
-------
history : object
Returns details about the training history at each epoch.
"""
if len(y.shape) == 1:
self.classes_ = list(np.unique(y))
if self.loss == 'categorical_crossentropy':
y = to_categorical(y)
if self.build_fn is None:
self.model = self.__call__(**self.filter_sk_params(self.__call__))
elif not isinstance(self.build_fn, types.FunctionType):
self.model = self.build_fn(
**self.filter_sk_params(self.build_fn.__call__))
else:
self.classes_ = np.arange(0, y.shape[1])
self.model = self.build_fn(**self.filter_sk_params(self.build_fn))
self.compiled_model_ = copy.deepcopy(self.model)
self.compiled_model_.compile(optimizer=self.optimizer, loss=self.loss)
history = self.compiled_model_.fit(
X, y, batch_size=self.train_batch_size, nb_epoch=self.nb_epoch, verbose=self.verbose,
shuffle=self.shuffle, show_accuracy=self.show_accuracy,
validation_split=self.validation_split, validation_data=self.validation_data,
callbacks=self.callbacks)
loss_name = self.model.loss
if hasattr(loss_name, '__name__'):
loss_name = loss_name.__name__
if loss_name == 'categorical_crossentropy' and len(y.shape) != 2:
y = to_categorical(y)
self.config_ = self.model.get_config()
self.weights_ = self.model.get_weights()
fit_args = copy.deepcopy(self.filter_sk_params(Sequential.fit))
fit_args.update(kwargs)
history = self.model.fit(X, y, **fit_args)
return history
def filter_sk_params(self, fn, override={}):
'''Filter sk_params and return those in fn's arguments
# Arguments
fn : arbitrary function
override: dictionary, values to overrid sk_params
# Returns
res : dictionary dictionary containing variabls
in both sk_params and fn's arguments.
'''
res = {}
fn_args = inspect.getargspec(fn)[0]
for name, value in self.sk_params.items():
if name in fn_args:
res.update({name: value})
res.update(override)
return res
class KerasClassifier(BaseWrapper):
"""
Implementation of the scikit-learn classifier API for Keras.
'''Implementation of the scikit-learn classifier API for Keras.
'''
Parameters
----------
model : object
An un-compiled Keras model object is required to use the scikit-learn wrapper.
optimizer : string
Optimization method used by the model during compilation/training.
loss : string
Loss function used by the model during compilation/training.
"""
def __init__(self, model, optimizer='adam', loss='categorical_crossentropy', **kwargs):
super(KerasClassifier, self).__init__(model, optimizer, loss, **kwargs)
def predict(self, X, **kwargs):
'''Returns the class predictions for the given test data.
def predict(self, X):
"""
Returns the class predictions for the given test data.
# Arguments
X: array-like, shape `(n_samples, n_features)`
Test samples where n_samples in the number of samples
and n_features is the number of features.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.predict_classes`.
Parameters
----------
X : array-like, shape = (n_samples, n_features)
Test samples where n_samples in the number of samples
and n_features is the number of features.
# Returns
preds: array-like, shape `(n_samples,)`
Class predictions.
'''
kwargs = self.filter_sk_params(Sequential.predict_classes, kwargs)
return self.model.predict_classes(X, **kwargs)
Returns
-------
preds : array-like, shape = (n_samples)
Class predictions.
"""
return self.compiled_model_.predict_classes(
X, batch_size=self.test_batch_size, verbose=self.verbose)
def predict_proba(self, X, **kwargs):
'''Returns class probability estimates for the given test data.
def predict_proba(self, X):
"""
Returns class probability estimates for the given test data.
# Arguments
X: array-like, shape `(n_samples, n_features)`
Test samples where n_samples in the number of samples
and n_features is the number of features.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.predict_classes`.
Parameters
----------
X : array-like, shape = (n_samples, n_features)
Test samples where n_samples in the number of samples
and n_features is the number of features.
# Returns
proba: array-like, shape `(n_samples, n_outputs)`
Class probability estimates.
'''
kwargs = self.filter_sk_params(Sequential.predict_proba, kwargs)
return self.model.predict_proba(X, **kwargs)
Returns
-------
proba : array-like, shape = (n_samples, n_outputs)
Class probability estimates.
"""
return self.compiled_model_.predict_proba(
X, batch_size=self.test_batch_size, verbose=self.verbose)
def score(self, X, y, **kwargs):
'''Returns the mean accuracy on the given test data and labels.
def score(self, X, y):
"""
Returns the mean accuracy on the given test data and labels.
# Arguments
X: array-like, shape `(n_samples, n_features)`
Test samples where n_samples in the number of samples
and n_features is the number of features.
y: array-like, shape `(n_samples,)` or `(n_samples, n_outputs)`
True labels for X.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.evaluate`.
Parameters
----------
X : array-like, shape = (n_samples, n_features)
Test samples where n_samples in the number of samples
and n_features is the number of features.
y : array-like, shape = (n_samples) or (n_samples, n_outputs)
True labels for X.
Returns
-------
score : float
Mean accuracy of predictions on X wrt. y.
"""
loss, accuracy = self.compiled_model_.evaluate(
X, y, batch_size=self.test_batch_size, show_accuracy=True, verbose=self.verbose)
return accuracy
# Returns
score: float
Mean accuracy of predictions on X wrt. y.
'''
kwargs = self.filter_sk_params(Sequential.evaluate, kwargs)
outputs = self.model.evaluate(X, y, **kwargs)
if type(outputs) is not list:
outputs = [outputs]
for name, output in zip(self.model.metrics_names, outputs):
if name == 'acc':
return output
raise Exception('The model is not configured to compute accuracy. '
'You should pass `metrics=["accuracy"]` to '
'the `model.compile()` method.')
class KerasRegressor(BaseWrapper):
"""
Implementation of the scikit-learn regressor API for Keras.
'''Implementation of the scikit-learn regressor API for Keras.
'''
Parameters
----------
model : object
An un-compiled Keras model object is required to use the scikit-learn wrapper.
optimizer : string
Optimization method used by the model during compilation/training.
loss : string
Loss function used by the model during compilation/training.
"""
def __init__(self, model, optimizer='adam', loss='mean_squared_error', **kwargs):
super(KerasRegressor, self).__init__(model, optimizer, loss, **kwargs)
def predict(self, X, **kwargs):
'''Returns predictions for the given test data.
def predict(self, X):
"""
Returns predictions for the given test data.
# Arguments
X: array-like, shape `(n_samples, n_features)`
Test samples where n_samples in the number of samples
and n_features is the number of features.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.predict`.
# Returns
preds: array-like, shape `(n_samples,)`
Predictions.
'''
kwargs = self.filter_sk_params(Sequential.predict, kwargs)
return self.model.predict(X, **kwargs)
Parameters
----------
X : array-like, shape = (n_samples, n_features)
Test samples where n_samples in the number of samples
and n_features is the number of features.
def score(self, X, y, **kwargs):
'''Returns the mean loss on the given test data and labels.
Returns
-------
preds : array-like, shape = (n_samples)
Predictions.
"""
return self.compiled_model_.predict(
X, batch_size=self.test_batch_size, verbose=self.verbose).ravel()
# Arguments
X: array-like, shape `(n_samples, n_features)`
Test samples where n_samples in the number of samples
and n_features is the number of features.
y: array-like, shape `(n_samples,)`
True labels for X.
kwargs: dictionary arguments
Legal arguments are the arguments of `Sequential.evaluate`.
def score(self, X, y):
"""
Returns the mean accuracy on the given test data and labels.
Parameters
----------
X : array-like, shape = (n_samples, n_features)
Test samples where n_samples in the number of samples
and n_features is the number of features.
y : array-like, shape = (n_samples)
True labels for X.
Returns
-------
score : float
Loss from predictions on X wrt. y.
"""
loss = self.compiled_model_.evaluate(
X, y, batch_size=self.test_batch_size, show_accuracy=False, verbose=self.verbose)
# Returns
score: float
Mean accuracy of predictions on X wrt. y.
'''
kwargs = self.filter_sk_params(Sequential.evaluate, kwargs)
loss = self.model.evaluate(X, y, **kwargs)
if type(loss) is list:
return loss[0]
return loss
+31
Ver Arquivo
@@ -5,3 +5,34 @@ addopts=-v
--durations=10
--cov-report term-missing
--cov=keras
# Do not run tests in the build folder
norecursedirs= build
# PEP-8 The following are ignored:
# E251 unexpected spaces around keyword / parameter equals
# E225 missing whitespace around operator
# E226 missing whitespace around arithmetic operator
# W291 trailing whitespace
# W293 blank line contains whitespace
# E501 line too long (82 > 79 characters)
# E402 module level import not at top of file - temporary measure to coninue adding ros python packaged in sys.path
# E731 do not assign a lambda expression, use a def
# E302 two blank lines between the functions
# E231 missing whitespace after ,
# E241 multiple spaces after ','
# E261 at least two spaces before inline comment
pep8ignore=* E251 \
* E225 \
* E226 \
* W291 \
* W293 \
* E501 \
* E402 \
* E731 \
* E302 \
* E231 \
* E241 \
* E261
+3 -3
Ver Arquivo
@@ -3,12 +3,12 @@ from setuptools import find_packages
setup(name='Keras',
version='0.3.0',
description='Theano-based Deep Learning library',
version='1.0.0',
description='Deep Learning for Python',
author='Francois Chollet',
author_email='francois.chollet@gmail.com',
url='https://github.com/fchollet/keras',
download_url='https://github.com/fchollet/keras/tarball/0.3.0',
download_url='https://github.com/fchollet/keras/tarball/1.0.0',
license='MIT',
install_requires=['theano', 'pyyaml', 'six'],
extras_require={
@@ -35,10 +35,12 @@ def test_image_classification():
Activation('relu'),
Dense(y_test.shape[-1], activation='softmax')
])
model.compile(loss='categorical_crossentropy', optimizer='sgd')
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
history = model.fit(X_train, y_train, nb_epoch=10, batch_size=16,
validation_data=(X_test, y_test),
show_accuracy=True, verbose=0)
verbose=0)
assert(history.history['val_acc'][-1] > 0.85)
@@ -4,16 +4,22 @@ import pytest
import string
from keras.utils.test_utils import get_test_data
from keras.models import Sequential
from keras.layers.core import TimeDistributedDense, Dropout, Dense
from keras.layers.recurrent import GRU, LSTM
from keras.utils.np_utils import to_categorical
from keras.models import Sequential
from keras.layers import TimeDistributedDense
from keras.layers import Dense
from keras.layers import Activation
from keras.layers import GRU
from keras.layers import LSTM
from keras.layers import Embedding
def test_temporal_classification():
'''
Classify temporal sequences of float numbers of length 3 into 2 classes using
single layer of GRU units and softmax applied to the last activations of the units
Classify temporal sequences of float numbers
of length 3 into 2 classes using
single layer of GRU units and softmax applied
to the last activations of the units
'''
np.random.seed(1337)
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
@@ -28,17 +34,19 @@ def test_temporal_classification():
model.add(GRU(y_train.shape[-1],
input_shape=(X_train.shape[1], X_train.shape[2]),
activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adadelta')
model.compile(loss='categorical_crossentropy',
optimizer='adadelta',
metrics=['accuracy'])
history = model.fit(X_train, y_train, nb_epoch=5, batch_size=16,
validation_data=(X_test, y_test),
show_accuracy=True, verbose=0)
verbose=0)
assert(history.history['val_acc'][-1] > 0.9)
def test_temporal_regression():
'''
Predict float numbers (regression) based on sequences of float numbers of length 3 using
single layer of GRU units
Predict float numbers (regression) based on sequences
of float numbers of length 3 using a single layer of GRU units
'''
np.random.seed(1337)
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
@@ -48,7 +56,7 @@ def test_temporal_regression():
classification=False)
model = Sequential()
model.add(GRU(y_train.shape[-1],
input_shape=(X_train.shape[1], X_train.shape[2])))
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=5, batch_size=16,
validation_data=(X_test, y_test), verbose=0)
@@ -71,7 +79,7 @@ def test_sequence_to_sequence():
model = Sequential()
model.add(TimeDistributedDense(y_train.shape[-1],
input_shape=(X_train.shape[1], X_train.shape[2])))
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=20, batch_size=16,
validation_data=(X_test, y_test), verbose=0)
@@ -127,5 +135,51 @@ def test_stacked_lstm_char_prediction():
assert(generated == alphabet)
def test_masked_temporal():
'''
Confirm that even with masking on both inputs and outputs, cross-entropies are
of the expected scale.
In this task, there are variable length inputs of integers from 1-9, and a random
subset of unmasked outputs. Each of these outputs has a 50% probability of being
the input number unchanged, and a 50% probability of being 2*input%10.
The ground-truth best cross-entropy loss should, then be -log(0.5) = 0.69
'''
np.random.seed(55318)
model = Sequential()
model.add(Embedding(10, 20, mask_zero=True, input_length=20))
model.add(TimeDistributedDense(10))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='adam',
sample_weight_mode='temporal')
X = np.random.random_integers(1, 9, (50000, 20))
for rowi in range(X.shape[0]):
padding = np.random.random_integers(X.shape[1] / 2)
X[rowi, :padding] = 0
# 50% of the time the correct output is the input.
# The other 50% of the time it's 2 * input % 10
y = (X * np.random.random_integers(1, 2, X.shape)) % 10
Y = np.zeros((y.size, 10), dtype='int32')
for i, target in enumerate(y.flat):
Y[i, target] = 1
Y = Y.reshape(y.shape + (10,))
# Mask 50% of the outputs via sample weights
sample_weight = np.random.random_integers(0, 1, y.shape)
print('X shape:', X.shape)
print('Y shape:', Y.shape)
print('sample_weight shape:', Y.shape)
history = model.fit(X, Y, validation_split=0.05,
sample_weight=None,
verbose=1, nb_epoch=2)
ground_truth = -np.log(0.5)
assert(np.abs(history.history['val_loss'][-1] - ground_truth) < 0.06)
if __name__ == '__main__':
pytest.main([__file__])
@@ -28,10 +28,12 @@ def test_vector_classification():
Dense(nb_hidden, input_shape=(X_train.shape[-1],), activation='relu'),
Dense(y_train.shape[-1], activation='softmax')
])
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
history = model.fit(X_train, y_train, nb_epoch=15, batch_size=16,
validation_data=(X_test, y_test),
show_accuracy=True, verbose=0)
verbose=0)
assert(history.history['val_acc'][-1] > 0.8)
+123 -22
Ver Arquivo
@@ -40,6 +40,10 @@ class TestBackend(object):
def test_linear_operations(self):
check_two_tensor_operation('dot', (4, 2), (2, 4))
check_two_tensor_operation('dot', (4, 2), (5, 2, 3))
check_two_tensor_operation('batch_dot', (4, 2, 3), (4, 5, 3),
axes=(2, 2))
check_single_tensor_operation('transpose', (4, 2))
def test_shape_operations(self):
@@ -114,16 +118,20 @@ class TestBackend(object):
check_single_tensor_operation('min', (4, 2))
check_single_tensor_operation('min', (4, 2), axis=1, keepdims=True)
check_single_tensor_operation('min', (4, 2, 3), axis=[1, -1])
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('mean', (4, 2, 3), axis=[1, -1])
check_single_tensor_operation('std', (4, 2))
check_single_tensor_operation('std', (4, 2), axis=1, keepdims=True)
check_single_tensor_operation('std', (4, 2, 3), axis=[1, -1])
check_single_tensor_operation('prod', (4, 2))
check_single_tensor_operation('prod', (4, 2), axis=1, keepdims=True)
check_single_tensor_operation('prod', (4, 2, 3), axis=[1, -1])
# does not work yet, wait for bool <-> int casting in TF (coming soon)
# check_single_tensor_operation('any', (4, 2))
@@ -141,6 +149,7 @@ class TestBackend(object):
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('sign', (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)
@@ -218,24 +227,24 @@ class TestBackend(object):
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,
th_inputs = KTH.variable(input_val)
th_initial_states = [KTH.variable(init_state_val)]
last_output, outputs, new_states = KTH.rnn(th_rnn_step_fn, th_inputs,
th_initial_states,
go_backwards=False,
masking=False)
mask=None)
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,
tf_inputs = KTF.variable(input_val)
tf_initial_states = [KTF.variable(init_state_val)]
last_output, outputs, new_states = KTF.rnn(tf_rnn_step_fn, tf_inputs,
tf_initial_states,
go_backwards=False,
masking=False)
mask=None)
tf_last_output = KTF.eval(last_output)
tf_outputs = KTF.eval(outputs)
assert len(new_states) == 1
@@ -245,6 +254,80 @@ class TestBackend(object):
assert_allclose(tf_outputs, th_outputs, atol=1e-04)
assert_allclose(tf_state, th_state, atol=1e-04)
# test unroll
unrolled_last_output, unrolled_outputs, unrolled_new_states = KTH.rnn(
th_rnn_step_fn, th_inputs,
th_initial_states,
go_backwards=False,
mask=None,
unroll=True,
input_length=timesteps)
unrolled_th_last_output = KTH.eval(unrolled_last_output)
unrolled_th_outputs = KTH.eval(unrolled_outputs)
assert len(unrolled_new_states) == 1
unrolled_th_state = KTH.eval(unrolled_new_states[0])
assert_allclose(th_last_output, unrolled_th_last_output, atol=1e-04)
assert_allclose(th_outputs, unrolled_th_outputs, atol=1e-04)
assert_allclose(th_state, unrolled_th_state, atol=1e-04)
# test unroll with backwards = True
bwd_last_output, bwd_outputs, bwd_new_states = KTH.rnn(
th_rnn_step_fn, th_inputs,
th_initial_states,
go_backwards=True,
mask=None)
bwd_th_last_output = KTH.eval(bwd_last_output)
bwd_th_outputs = KTH.eval(bwd_outputs)
assert len(bwd_new_states) == 1
bwd_th_state = KTH.eval(bwd_new_states[0])
bwd_unrolled_last_output, bwd_unrolled_outputs, bwd_unrolled_new_states = KTH.rnn(
th_rnn_step_fn, th_inputs,
th_initial_states,
go_backwards=True,
mask=None,
unroll=True,
input_length=timesteps)
bwd_unrolled_th_last_output = KTH.eval(bwd_unrolled_last_output)
bwd_unrolled_th_outputs = KTH.eval(bwd_unrolled_outputs)
assert len(bwd_unrolled_new_states) == 1
bwd_unrolled_th_state = KTH.eval(bwd_unrolled_new_states[0])
assert_allclose(bwd_th_last_output, bwd_unrolled_th_last_output, atol=1e-04)
assert_allclose(bwd_th_outputs, bwd_unrolled_th_outputs, atol=1e-04)
assert_allclose(bwd_th_state, bwd_unrolled_th_state, atol=1e-04)
# test unroll with masking
np_mask = np.random.randint(2, size=(32, timesteps))
th_mask = KTH.variable(np_mask)
masked_last_output, masked_outputs, masked_new_states = KTH.rnn(
th_rnn_step_fn, th_inputs,
th_initial_states,
go_backwards=False,
mask=th_mask)
masked_th_last_output = KTH.eval(masked_last_output)
masked_th_outputs = KTH.eval(masked_outputs)
assert len(masked_new_states) == 1
masked_th_state = KTH.eval(masked_new_states[0])
unrolled_masked_last_output, unrolled_masked_outputs, unrolled_masked_new_states = KTH.rnn(
th_rnn_step_fn, th_inputs,
th_initial_states,
go_backwards=False,
mask=th_mask,
unroll=True,
input_length=timesteps)
unrolled_masked_th_last_output = KTH.eval(unrolled_masked_last_output)
unrolled_masked_th_outputs = KTH.eval(unrolled_masked_outputs)
assert len(unrolled_masked_new_states) == 1
unrolled_masked_th_state = KTH.eval(unrolled_masked_new_states[0])
assert_allclose(unrolled_masked_th_last_output, masked_th_last_output, atol=1e-04)
assert_allclose(unrolled_masked_th_outputs, masked_th_outputs, atol=1e-04)
assert_allclose(unrolled_masked_th_state, masked_th_state, atol=1e-04)
def test_switch(self):
val = np.random.random()
xth = KTH.variable(val)
@@ -269,7 +352,7 @@ class TestBackend(object):
check_single_tensor_operation('tanh', (4, 2))
# dropout
val = np.random.random((20, 20))
val = np.random.random((100, 100))
xth = KTH.variable(val)
xtf = KTF.variable(val)
zth = KTH.eval(KTH.dropout(xth, level=0.2))
@@ -281,9 +364,11 @@ class TestBackend(object):
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)
check_single_tensor_operation('l2_normalize', (4, 3), axis=-1)
check_single_tensor_operation('l2_normalize', (4, 3), axis=1)
# def test_conv2d(self):
# '''conv2d works "properly" with Theano and TF but outputs different
# values in each case. Cause unclear (input / kernel shape format?)
@@ -324,28 +409,44 @@ class TestBackend(object):
def test_random_normal(self):
mean = 0.
std = 1.
rand = KTF.get_value(KTF.random_normal((1000, 1000), mean=mean, std=std))
rand = KTF.eval(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))
rand = KTH.eval(KTH.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))
min = -1.
max = 1.
rand = KTF.eval(KTF.random_uniform((1000, 1000), min, max))
assert(rand.shape == (1000, 1000))
assert(np.abs(np.mean(rand) - mean) < 0.01)
assert(np.abs(np.std(rand) - std) < 0.01)
assert(np.abs(np.mean(rand)) < 0.01)
assert(np.max(rand) <= max)
assert(np.min(rand) >= min)
rand = KTF.get_value(KTF.random_normal((1000, 1000), mean=mean, std=std))
rand = KTH.eval(KTH.random_uniform((1000, 1000), min, max))
assert(rand.shape == (1000, 1000))
assert(np.abs(np.mean(rand) - mean) < 0.01)
assert(np.abs(np.std(rand) - std) < 0.01)
assert(np.abs(np.mean(rand)) < 0.01)
assert(np.max(rand) <= max)
assert(np.min(rand) >= min)
def test_random_binomial(self):
p = 0.5
rand = KTF.eval(KTF.random_binomial((1000, 1000), p))
assert(rand.shape == (1000, 1000))
assert(np.abs(np.mean(rand) - p) < 0.01)
assert(np.max(rand) == 1)
assert(np.min(rand) == 0)
rand = KTH.eval(KTH.random_binomial((1000, 1000), p))
assert(rand.shape == (1000, 1000))
assert(np.abs(np.mean(rand) - p) < 0.01)
assert(np.max(rand) == 1)
assert(np.min(rand) == 0)
if __name__ == '__main__':
+565
Ver Arquivo
@@ -0,0 +1,565 @@
import pytest
import json
import numpy as np
from keras.layers import Dense, Dropout
from keras.engine import merge, Input, get_source_inputs
from keras.models import Model
from keras import backend as K
from keras.models import model_from_json, model_from_yaml
def test_learning_phase():
a = Input(shape=(32,), name='input_a')
b = Input(shape=(32,), name='input_b')
a_2 = Dense(16, name='dense_1')(a)
dp = Dropout(0.5, name='dropout')
b_2 = dp(b)
assert dp.uses_learning_phase
assert not a_2._uses_learning_phase
assert b_2._uses_learning_phase
# test merge
m = merge([a_2, b_2], mode='concat')
assert m._uses_learning_phase
# Test recursion
model = Model([a, b], [a_2, b_2])
print(model.input_spec)
assert model.uses_learning_phase
c = Input(shape=(32,), name='input_c')
d = Input(shape=(32,), name='input_d')
c_2, b_2 = model([c, d])
assert c_2._uses_learning_phase
assert b_2._uses_learning_phase
# try actually running graph
fn = K.function(model.inputs + [K.learning_phase()], model.outputs)
input_a_np = np.random.random((10, 32))
input_b_np = np.random.random((10, 32))
fn_outputs_no_dp = fn([input_a_np, input_b_np, 0])
fn_outputs_dp = fn([input_a_np, input_b_np, 1])
# output a: nothing changes
assert fn_outputs_no_dp[0].sum() == fn_outputs_dp[0].sum()
# output b: dropout applied
assert fn_outputs_no_dp[1].sum() != fn_outputs_dp[1].sum()
def test_node_construction():
####################################################
# test basics
a = Input(shape=(32,), name='input_a')
b = Input(shape=(32,), name='input_b')
assert a._keras_shape == (None, 32)
a_layer, a_node_index, a_tensor_index = a._keras_history
b_layer, b_node_index, b_tensor_index = b._keras_history
assert len(a_layer.inbound_nodes) == 1
assert a_tensor_index is 0
node = a_layer.inbound_nodes[a_node_index]
assert node.outbound_layer == a_layer
assert type(node.inbound_layers) is list
assert node.inbound_layers == []
assert type(node.input_tensors) is list
assert node.input_tensors == [a]
assert type(node.input_masks) is list
assert node.input_masks == [None]
assert type(node.input_shapes) is list
assert node.input_shapes == [(None, 32)]
assert type(node.output_tensors) is list
assert node.output_tensors == [a]
assert type(node.output_shapes) is list
assert node.output_shapes == [(None, 32)]
assert type(node.output_masks) is list
assert node.output_masks == [None]
dense = Dense(16, name='dense_1')
a_2 = dense(a)
b_2 = dense(b)
assert len(dense.inbound_nodes) == 2
assert len(dense.outbound_nodes) == 0
assert dense.inbound_nodes[0].inbound_layers == [a_layer]
assert dense.inbound_nodes[0].outbound_layer == dense
assert dense.inbound_nodes[1].inbound_layers == [b_layer]
assert dense.inbound_nodes[1].outbound_layer == dense
assert dense.inbound_nodes[0].input_tensors == [a]
assert dense.inbound_nodes[1].input_tensors == [b]
# test layer properties
test_layer = Dense(16, name='test_layer')
a_test = test_layer(a)
assert test_layer.input == a
assert test_layer.output == a_test
assert test_layer.input_mask is None
assert test_layer.output_mask is None
assert test_layer.input_shape == (None, 32)
assert test_layer.output_shape == (None, 16)
with pytest.raises(Exception):
dense.input
with pytest.raises(Exception):
dense.output
with pytest.raises(Exception):
dense.input_mask
with pytest.raises(Exception):
dense.output_mask
assert dense.get_input_at(0) == a
assert dense.get_input_at(1) == b
assert dense.get_output_at(0) == a_2
assert dense.get_output_at(1) == b_2
assert dense.get_input_shape_at(0) == (None, 32)
assert dense.get_input_shape_at(1) == (None, 32)
assert dense.get_output_shape_at(0) == (None, 16)
assert dense.get_output_shape_at(1) == (None, 16)
assert dense.get_input_mask_at(0) is None
assert dense.get_input_mask_at(1) is None
assert dense.get_output_mask_at(0) is None
assert dense.get_output_mask_at(1) is None
def test_multi_input_layer():
####################################################
# test multi-input layer
a = Input(shape=(32,), name='input_a')
b = Input(shape=(32,), name='input_b')
dense = Dense(16, name='dense_1')
a_2 = dense(a)
b_2 = dense(b)
merged = merge([a_2, b_2], mode='concat', name='merge')
assert merged._keras_shape == (None, 16 * 2)
merge_layer, merge_node_index, merge_tensor_index = merged._keras_history
assert merge_node_index == 0
assert merge_tensor_index == 0
assert len(merge_layer.inbound_nodes) == 1
assert len(merge_layer.outbound_nodes) == 0
assert len(merge_layer.inbound_nodes[0].input_tensors) == 2
assert len(merge_layer.inbound_nodes[0].inbound_layers) == 2
c = Dense(64, name='dense_2')(merged)
d = Dense(5, name='dense_3')(c)
model = Model(input=[a, b], output=[c, d], name='model')
assert len(model.layers) == 6
print('model.input_layers:', model.input_layers)
print('model.input_layers_node_indices:', model.input_layers_node_indices)
print('model.input_layers_tensor_indices:', model.input_layers_tensor_indices)
print('model.output_layers', model.output_layers)
print('output_shape:', model.get_output_shape_for([(None, 32), (None, 32)]))
assert model.get_output_shape_for([(None, 32), (None, 32)]) == [(None, 64), (None, 5)]
assert model.compute_mask([a, b], [None, None]) == [None, None]
print('output_shape:', model.get_output_shape_for([(None, 32), (None, 32)]))
assert model.get_output_shape_for([(None, 32), (None, 32)]) == [(None, 64), (None, 5)]
# we don't check names of first 2 layers (inputs) because
# ordering of same-level layers is not fixed
print('layers:', [layer.name for layer in model.layers])
assert [l.name for l in model.layers][2:] == ['dense_1', 'merge', 'dense_2', 'dense_3']
print('input_layers:', [l.name for l in model.input_layers])
assert [l.name for l in model.input_layers] == ['input_a', 'input_b']
print('output_layers:', [l.name for l in model.output_layers])
assert [l.name for l in model.output_layers] == ['dense_2', 'dense_3']
# actually run model
fn = K.function(model.inputs, model.outputs)
input_a_np = np.random.random((10, 32))
input_b_np = np.random.random((10, 32))
fn_outputs = fn([input_a_np, input_b_np])
assert [x.shape for x in fn_outputs] == [(10, 64), (10, 5)]
# test get_source_inputs
print(get_source_inputs(c))
assert get_source_inputs(c) == [a, b]
# serialization / deserialization
json_config = model.to_json()
recreated_model = model_from_json(json_config)
recreated_model.compile('rmsprop', 'mse')
print('recreated:')
print([layer.name for layer in recreated_model.layers])
print([layer.name for layer in recreated_model.input_layers])
print([layer.name for layer in recreated_model.output_layers])
assert [l.name for l in recreated_model.layers][2:] == ['dense_1', 'merge', 'dense_2', 'dense_3']
assert [l.name for l in recreated_model.input_layers] == ['input_a', 'input_b']
assert [l.name for l in recreated_model.output_layers] == ['dense_2', 'dense_3']
fn = K.function(recreated_model.inputs, recreated_model.outputs)
input_a_np = np.random.random((10, 32))
input_b_np = np.random.random((10, 32))
fn_outputs = fn([input_a_np, input_b_np])
assert [x.shape for x in fn_outputs] == [(10, 64), (10, 5)]
def test_recursion():
####################################################
# test recursion
a = Input(shape=(32,), name='input_a')
b = Input(shape=(32,), name='input_b')
dense = Dense(16, name='dense_1')
a_2 = dense(a)
b_2 = dense(b)
merged = merge([a_2, b_2], mode='concat', name='merge')
c = Dense(64, name='dense_2')(merged)
d = Dense(5, name='dense_3')(c)
model = Model(input=[a, b], output=[c, d], name='model')
e = Input(shape=(32,), name='input_e')
f = Input(shape=(32,), name='input_f')
g, h = model([e, f])
# g2, h2 = model([e, f])
assert g._keras_shape == c._keras_shape
assert h._keras_shape == d._keras_shape
# test separate manipulation of different layer outputs
i = Dense(7, name='dense_4')(h)
final_model = Model(input=[e, f], output=[i, g], name='final')
assert len(final_model.inputs) == 2
assert len(final_model.outputs) == 2
assert len(final_model.layers) == 4
# we don't check names of first 2 layers (inputs) because
# ordering of same-level layers is not fixed
print('final_model layers:', [layer.name for layer in final_model.layers])
assert [layer.name for layer in final_model.layers][2:] == ['model', 'dense_4']
print(model.compute_mask([e, f], [None, None]))
assert model.compute_mask([e, f], [None, None]) == [None, None]
print(final_model.get_output_shape_for([(10, 32), (10, 32)]))
assert final_model.get_output_shape_for([(10, 32), (10, 32)]) == [(10, 7), (10, 64)]
# run recursive model
fn = K.function(final_model.inputs, final_model.outputs)
input_a_np = np.random.random((10, 32))
input_b_np = np.random.random((10, 32))
fn_outputs = fn([input_a_np, input_b_np])
assert [x.shape for x in fn_outputs] == [(10, 7), (10, 64)]
# test serialization
model_config = final_model.get_config()
print(json.dumps(model_config, indent=4))
recreated_model = Model.from_config(model_config)
fn = K.function(recreated_model.inputs, recreated_model.outputs)
input_a_np = np.random.random((10, 32))
input_b_np = np.random.random((10, 32))
fn_outputs = fn([input_a_np, input_b_np])
assert [x.shape for x in fn_outputs] == [(10, 7), (10, 64)]
####################################################
# test multi-input multi-output
j = Input(shape=(32,), name='input_j')
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
o = Input(shape=(32,), name='input_o')
p = Input(shape=(32,), name='input_p')
q, r = model([o, p])
assert n._keras_shape == (None, 5)
assert q._keras_shape == (None, 64)
s = merge([n, q], mode='concat', name='merge_nq')
assert s._keras_shape == (None, 64 + 5)
# test with single output as 1-elem list
multi_io_model = Model([j, k, o, p], [s])
fn = K.function(multi_io_model.inputs, multi_io_model.outputs)
fn_outputs = fn([np.random.random((10, 32)), np.random.random((10, 32)),
np.random.random((10, 32)), np.random.random((10, 32))])
assert [x.shape for x in fn_outputs] == [(10, 69)]
# test with single output as tensor
multi_io_model = Model([j, k, o, p], s)
fn = K.function(multi_io_model.inputs, multi_io_model.outputs)
fn_outputs = fn([np.random.random((10, 32)), np.random.random((10, 32)),
np.random.random((10, 32)), np.random.random((10, 32))])
# note that the output of the K.function will still be a 1-elem list
assert [x.shape for x in fn_outputs] == [(10, 69)]
# test serialization
print('multi_io_model.layers:', multi_io_model.layers)
print('len(model.inbound_nodes):', len(model.inbound_nodes))
print('len(model.outbound_nodes):', len(model.outbound_nodes))
model_config = multi_io_model.get_config()
print(model_config)
print(json.dumps(model_config, indent=4))
recreated_model = Model.from_config(model_config)
fn = K.function(recreated_model.inputs, recreated_model.outputs)
fn_outputs = fn([np.random.random((10, 32)), np.random.random((10, 32)),
np.random.random((10, 32)), np.random.random((10, 32))])
# note that the output of the K.function will still be a 1-elem list
assert [x.shape for x in fn_outputs] == [(10, 69)]
config = model.get_config()
new_model = Model.from_config(config)
model.summary()
json_str = model.to_json()
new_model = model_from_json(json_str)
yaml_str = model.to_yaml()
new_model = model_from_yaml(yaml_str)
####################################################
# test invalid graphs
# input is not an Input tensor
j = Input(shape=(32,), name='input_j')
j = Dense(32)(j)
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
with pytest.raises(Exception):
invalid_model = Model([j, k], [m, n])
# disconnected graph
j = Input(shape=(32,), name='input_j')
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
with pytest.raises(Exception) as e:
invalid_model = Model([j], [m, n])
# redudant outputs
j = Input(shape=(32,), name='input_j')
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
# this should work lol
# TODO: raise a warning
invalid_model = Model([j, k], [m, n, n])
# redundant inputs
j = Input(shape=(32,), name='input_j')
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
with pytest.raises(Exception):
invalid_model = Model([j, k, j], [m, n])
# i have not idea what I'm doing: garbage as inputs/outputs
j = Input(shape=(32,), name='input_j')
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
with pytest.raises(Exception):
invalid_model = Model([j, k], [m, n, 0])
####################################################
# test calling layers/models on TF tensors
if K._BACKEND == 'tensorflow':
import tensorflow as tf
j = Input(shape=(32,), name='input_j')
k = Input(shape=(32,), name='input_k')
m, n = model([j, k])
tf_model = Model([j, k], [m, n])
# magic
j_tf = tf.placeholder(dtype=K.floatx())
k_tf = tf.placeholder(dtype=K.floatx())
m_tf, n_tf = tf_model([j_tf, k_tf])
assert not hasattr(m_tf, '_keras_shape')
assert not hasattr(n_tf, '_keras_shape')
assert K.int_shape(m_tf) == (None, 64)
assert K.int_shape(n_tf) == (None, 5)
def test_functional_guide():
# MNIST
from keras.layers import Input, Dense, LSTM
from keras.models import Model
from keras.utils import np_utils
# this returns a tensor
inputs = Input(shape=(784,))
# a layer instance is callable on a tensor, and returns a tensor
x = Dense(64, activation='relu')(inputs)
x = Dense(64, activation='relu')(x)
predictions = Dense(10, activation='softmax')(x)
# this creates a model that includes
# the Input layer and three Dense layers
model = Model(input=inputs, output=predictions)
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
# the data, shuffled and split between tran and test sets
X_train = np.random.random((100, 784))
Y_train = np.random.random((100, 10))
model.fit(X_train, Y_train, nb_epoch=2, batch_size=128)
assert model.inputs == [inputs]
assert model.outputs == [predictions]
assert model.input == inputs
assert model.output == predictions
assert model.input_shape == (None, 784)
assert model.output_shape == (None, 10)
# try calling the sequential model
inputs = Input(shape=(784,))
new_outputs = model(inputs)
new_model = Model(input=inputs, output=new_outputs)
new_model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
##################################################
# multi-io
##################################################
tweet_a = Input(shape=(4, 25))
tweet_b = Input(shape=(4, 25))
# this layer can take as input a matrix
# and will return a vector of size 64
shared_lstm = LSTM(64)
# when we reuse the same layer instance
# multiple times, the weights of the layer
# are also being reused
# (it is effectively *the same* layer)
encoded_a = shared_lstm(tweet_a)
encoded_b = shared_lstm(tweet_b)
# we can then concatenate the two vectors:
merged_vector = merge([encoded_a, encoded_b],
mode='concat', concat_axis=-1)
# and add a logistic regression on top
predictions = Dense(1, activation='sigmoid')(merged_vector)
# we define a trainable model linking the
# tweet inputs to the predictions
model = Model(input=[tweet_a, tweet_b], output=predictions)
model.compile(optimizer='rmsprop',
loss='binary_crossentropy',
metrics=['accuracy'])
data_a = np.random.random((1000, 4, 25))
data_b = np.random.random((1000, 4, 25))
labels = np.random.random((1000,))
model.fit([data_a, data_b], labels, nb_epoch=1)
model.summary()
assert model.inputs == [tweet_a, tweet_b]
assert model.outputs == [predictions]
assert model.input == [tweet_a, tweet_b]
assert model.output == predictions
assert model.output == predictions
assert model.input_shape == [(None, 4, 25), (None, 4, 25)]
assert model.output_shape == (None, 1)
assert shared_lstm.get_output_at(0) == encoded_a
assert shared_lstm.get_output_at(1) == encoded_b
assert shared_lstm.input_shape == (None, 4, 25)
def test_sequential_regression():
from keras.models import Sequential, Model
from keras.layers import Merge, Embedding, BatchNormalization, LSTM, InputLayer, Input
# start with a basic example of using a Sequential model
# inside the functional API
seq = Sequential()
seq.add(Dense(input_dim=10, output_dim=10))
x = Input(shape=(10,))
y = seq(x)
model = Model(x, y)
model.compile('rmsprop', 'mse')
weights = model.get_weights()
# test serialization
config = model.get_config()
model = Model.from_config(config)
model.compile('rmsprop', 'mse')
model.set_weights(weights)
# more advanced model with multiple branches
branch_1 = Sequential(name='branch_1')
branch_1.add(Embedding(input_dim=100,
output_dim=10,
input_length=2,
name='embed_1'))
branch_1.add(LSTM(32, name='lstm_1'))
branch_1.add(BatchNormalization())
branch_2 = Sequential(name='branch_2')
branch_2.add(Dense(32, input_shape=(8,), name='dense_2'))
branch_3 = Sequential(name='branch_3')
branch_3.add(Dense(32, input_shape=(6,), name='dense_3'))
branch_1_2 = Sequential([Merge([branch_1, branch_2], mode='concat')], name='branch_1_2')
branch_1_2.add(Dense(16, name='dense_1_2-0'))
# test whether impromtu input_shape breaks the model
branch_1_2.add(Dense(16, input_shape=(16,), name='dense_1_2-1'))
model = Sequential([Merge([branch_1_2, branch_3], mode='concat')], name='final')
model.add(Dense(16, name='dense_final'))
model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
model.summary()
x = (100 * np.random.random((100, 2))).astype('int32')
y = np.random.random((100, 8))
z = np.random.random((100, 6))
labels = np.random.random((100, 16))
model.fit([x, y, z], labels, nb_epoch=1)
# test if Sequential can be called in the functional API
a = Input(shape=(2,), dtype='int32')
b = Input(shape=(8,))
c = Input(shape=(6,))
o = model([a, b, c])
outer_model = Model([a, b, c], o)
outer_model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
outer_model.fit([x, y, z], labels, nb_epoch=1)
# test serialization
config = outer_model.get_config()
outer_model = Model.from_config(config)
outer_model.compile(optimizer='rmsprop',
loss='categorical_crossentropy',
metrics=['accuracy'])
outer_model.fit([x, y, z], labels, nb_epoch=1)
if __name__ == "__main__":
pytest.main([__file__])
+157
Ver Arquivo
@@ -0,0 +1,157 @@
import pytest
import numpy as np
from keras.layers import Dense, Dropout
from keras.engine.topology import merge, Input
from keras.engine.training import Model
from keras import backend as K
def test_model_methods():
a = Input(shape=(3,), name='input_a')
b = Input(shape=(3,), name='input_b')
a_2 = Dense(4, name='dense_1')(a)
dp = Dropout(0.5, name='dropout')
b_2 = dp(b)
model = Model([a, b], [a_2, b_2])
optimizer = 'rmsprop'
loss = 'mse'
loss_weights = [1., 0.5]
model.compile(optimizer, loss, metrics=[], loss_weights=loss_weights,
sample_weight_mode=None)
input_a_np = np.random.random((10, 3))
input_b_np = np.random.random((10, 3))
output_a_np = np.random.random((10, 4))
output_b_np = np.random.random((10, 3))
# test train_on_batch
out = model.train_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
out = model.train_on_batch({'input_a': input_a_np, 'input_b': input_b_np},
[output_a_np, output_b_np])
out = model.train_on_batch({'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np})
# test fit
out = model.fit([input_a_np, input_b_np],
[output_a_np, output_b_np], nb_epoch=1, batch_size=4)
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
[output_a_np, output_b_np], nb_epoch=1, batch_size=4)
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np},
nb_epoch=1, batch_size=4)
# test validation_split
out = model.fit([input_a_np, input_b_np],
[output_a_np, output_b_np],
nb_epoch=1, batch_size=4, validation_split=0.5)
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
[output_a_np, output_b_np],
nb_epoch=1, batch_size=4, validation_split=0.5)
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np},
nb_epoch=1, batch_size=4, validation_split=0.5)
# test validation data
out = model.fit([input_a_np, input_b_np],
[output_a_np, output_b_np],
nb_epoch=1, batch_size=4,
validation_data=([input_a_np, input_b_np], [output_a_np, output_b_np]))
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
[output_a_np, output_b_np],
nb_epoch=1, batch_size=4, validation_split=0.5,
validation_data=({'input_a': input_a_np, 'input_b': input_b_np}, [output_a_np, output_b_np]))
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np},
nb_epoch=1, batch_size=4, validation_split=0.5,
validation_data=({'input_a': input_a_np, 'input_b': input_b_np}, {'dense_1': output_a_np, 'dropout': output_b_np}))
# test_on_batch
out = model.test_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
out = model.test_on_batch({'input_a': input_a_np, 'input_b': input_b_np},
[output_a_np, output_b_np])
out = model.test_on_batch({'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np})
# predict_on_batch
out = model.predict_on_batch([input_a_np, input_b_np])
out = model.predict_on_batch({'input_a': input_a_np, 'input_b': input_b_np})
# predict, evaluate
input_a_np = np.random.random((10, 3))
input_b_np = np.random.random((10, 3))
output_a_np = np.random.random((10, 4))
output_b_np = np.random.random((10, 3))
out = model.evaluate([input_a_np, input_b_np], [output_a_np, output_b_np], batch_size=4)
out = model.predict([input_a_np, input_b_np], batch_size=4)
# with sample_weight
input_a_np = np.random.random((10, 3))
input_b_np = np.random.random((10, 3))
output_a_np = np.random.random((10, 4))
output_b_np = np.random.random((10, 3))
sample_weight = [None, np.random.random((10,))]
out = model.train_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np],
sample_weight=sample_weight)
out = model.test_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np],
sample_weight=sample_weight)
# test accuracy metric
model.compile(optimizer, loss, metrics=['acc'],
sample_weight_mode=None)
out = model.train_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
assert len(out) == 3
out = model.test_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
assert len(out) == 3
# this should also work
model.compile(optimizer, loss, metrics={'dense_1': 'acc'},
sample_weight_mode=None)
out = model.train_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
assert len(out) == 2
out = model.test_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
assert len(out) == 2
# and this as well
model.compile(optimizer, loss, metrics={'dense_1': ['acc']},
sample_weight_mode=None)
out = model.train_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
assert len(out) == 2
out = model.test_on_batch([input_a_np, input_b_np],
[output_a_np, output_b_np])
assert len(out) == 2
input_a_np = np.random.random((10, 3))
input_b_np = np.random.random((10, 3))
output_a_np = np.random.random((10, 4))
output_b_np = np.random.random((10, 3))
out = model.fit([input_a_np, input_b_np], [output_a_np, output_b_np], batch_size=4, nb_epoch=1)
out = model.evaluate([input_a_np, input_b_np], [output_a_np, output_b_np], batch_size=4)
out = model.predict([input_a_np, input_b_np], batch_size=4)
if __name__ == '__main__':
pytest.main([__file__])

Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais