Comparar commits

..

172 Commits

Autor SHA1 Mensagem Data
Francois Chollet d4b618bf23 Prepare new PyPI release. 2017-06-12 11:46:21 -07:00
Taehoon Lee 5012678e17 Fix typos (#6949) 2017-06-11 17:22:16 -07:00
Chen 11d9c995cc fixes #3859 clipnorm tensorflow (#6859)
* make clipnorm work with embeddings layer

* test for embedding + clipnorm

* update embedding_with_clipnorm test nb_epoch to epochs
2017-06-10 12:08:04 -07:00
GPhilo d92fab69a2 Parallel directory iterator initialization (#6890)
* added parallel counting of sample files when initializing DirectoryIterator

* Updated to actually run in parallel.

* Added parallel generation of the filenames and labels lists

* Added documentation and removed commented-out code

* style fixes

* changes discussed in pull request

* Removed trailing spaces

* Switching to thread pool

* fixed broken import
2017-06-09 19:41:44 -07:00
Martin Hallén 19463a19b8 Fine-tuning InceptionV3: Correct number of layers for two last inception blocks. (#6918) 2017-06-09 17:54:06 -07:00
Tang, Cheng ca1122fe80 update with more meaningful error message for CNTK backend (#6915)
* update with more meaningful error message

* fix unclear error message

* fix message format issues.
2017-06-09 13:05:57 -07:00
Jan Zikes 7fc707e13e Fix comments for binary_crossentropy and sparse_crossentropy. (#6919) 2017-06-09 10:55:40 -07:00
Maxim Grechkin 846d25ab97 fix a bug when model.fit assumed that x[0] has len, not true for sparse matrices (#6916) 2017-06-08 21:20:00 -07:00
Erik Smistad 8c0a8b4b04 Use batch_input_shape in input layer even if input_tensor is set (#6883) 2017-06-07 12:35:35 -07:00
Daniel Høyer Iversen 1b1e09a366 Remove duplicated batch_set_value in cntk_backend (#6878) 2017-06-07 00:00:25 -07:00
Taehoon Lee fd427b8cdb Fix typos (#6879) 2017-06-07 00:00:11 -07:00
Somshubra Majumdar 53303fdb10 Improvements to style transfer as discussed in https://github.com/fchollet/keras/pull/6872 (#6877) 2017-06-06 23:40:32 -07:00
fchollet 720ed1adc4 Update README.md 2017-06-06 23:09:41 -07:00
fchollet 43e418d1d2 Deflake TensorBoard callback tests. 2017-06-06 23:08:48 -07:00
Cheng Tang 75d9415c82 Add CNTK backend. 2017-06-06 23:03:04 -07:00
Francois Chollet 552978dc58 Allow arbitrary channel dimensions in ImageDataGenerator 2017-06-06 16:29:08 -07:00
Francois Chollet 508bb8f541 Add new return_state test for RNNs 2017-06-06 13:15:31 -07:00
Francois Chollet c3c97905fe merge return_state keyword in RNN API 2017-06-06 12:41:59 -07:00
Francois Chollet 33cee3f947 Docstring fix. 2017-06-06 12:21:43 -07:00
Francois Chollet f0659766fc Merge branch 'return-state' of https://github.com/Joshua-Chin/keras into Joshua-Chin-return-state 2017-06-06 12:17:21 -07:00
Francois Chollet 62973243ae Fix docstring and comments of Reshape layer. 2017-06-06 11:47:19 -07:00
Ben 6a0c9a617d Raise a descriptive error if inputs are not inputs (#6812)
* Raise a descriptive error if `Model` constructor `inputs` are not inputs.

* Assert that layer attached to input tensors is an InputLayer

* fix pep8

* under-indented

* fix indent

* Update TypError message

* Fix TypeError message
2017-06-06 09:55:05 -07:00
Jeremy Fix 3c180eafed Serializing/Desrializing numpy arrays in Lambda layer arguments (#6816)
* Serialize/Deserialize numpy arrays passed as arguments to Lambda layers

* Serialize/Deserialize numpy arrays passed as arguments to Lambda layers

* Corrections from fchollet comments

* corrections

* Removes warning and adds a unit test

* pep8 corrections
2017-06-06 09:20:49 -07:00
LI YUXIN 763bd6d8f1 added support of pydotplus (#6869)
pydotplus is better supported on windows
2017-06-06 07:21:28 -07:00
Taehoon Lee 36317214ae Add error message for Conv2DTranspose on Theano (#6870) 2017-06-06 07:20:07 -07:00
Andrew Hundt a5f53155a5 Update LICENSE dates for all other contributors (#6867)
Correction at https://github.com/fchollet/keras/pull/6800/files/8a93935d99fae4b8dc2ce0ea1a169906da0a165d#r120219133 also applies to all other contributers. It probably applies François Chollet and Google too, but I'm only a member of "All other contributors" so I figured the other changes should be made by those respective rightsholders. :-)
2017-06-05 17:23:29 -07:00
Rik Nijessen 78be823518 Add an explanation about padding in Conv1d (#6796)
* Add an explanation about padding in Conv1d

* Fix docstring content
2017-06-05 14:49:12 -07:00
Francois Chollet 5810f7a9c7 Update Boston Housing dataset 2017-06-05 10:30:54 -07:00
Vimos Tan 0bc8fac446 Add sparse_top_k_categorical_accuracy and test code (#6840)
* Add top_k_sparse_categorical_accuracy and test_top_k_sparse_categorical_accuracy

* Rename top_k_sparse_categorical_accuracy and sparse_top_k_categorical_accuracy
2017-06-04 16:23:57 -07:00
Francois Chollet aea62d8baf Simplify embedding docstring 2017-06-02 12:01:15 -07:00
Francois Chollet 7819b9c14e Update categorical_hinge loss 2017-06-02 12:01:00 -07:00
Taehoon Lee eede3dc43d Fix docstring typos (#6833) 2017-06-02 09:22:04 -07:00
Hussain Karimi ea29308eaa typo in documentation (#6809)
line 1255:    This layer can add rows and columns of (not 'or') zeros
2017-06-01 09:43:36 -07:00
Edson Medina 21b72a3b13 Missing comma (#6820) 2017-06-01 09:39:19 -07:00
Eric Xihui Lin f3bbf31497 Modify embedding to accept arbitrary input dim (#6392)
* modifed embedding to accept arbitrary input dim

* allowed user specified input lengths

* minor change
2017-05-31 16:05:20 -07:00
Taehoon Lee 17e073d87e Make docstrings consistent (#6798) 2017-05-30 11:37:38 -07:00
alreadytaikeune 60c52ea766 close the opened hdf5 file in load model in case of error (#6749)
* Make sure to close the opened hdf5 file in load model even when an error is raised

* Update models.py

* Update models.py
2017-05-26 14:54:02 -07:00
Taehoon Lee bfa38fb747 Add warning message for redundant outputs (#6738) 2017-05-26 14:28:53 -07:00
Daniel Høyer Iversen 7c73bfc50d Update writing-your-own-keras-layers.md (#6741)
* Update writing-your-own-keras-layers.md

* Update writing-your-own-keras-layers.md
2017-05-26 14:27:52 -07:00
Taehoon Lee fccd4f8055 Docstring style fixes 2017-05-26 14:27:15 -07:00
webzjuyujun 1b67c59de8 Style fix. 2017-05-24 19:27:23 -07:00
nzw a9d2a99500 Style fix (#6748) 2017-05-24 19:25:02 -07:00
Francois Chollet 0bb4e0fad5 Remove unused import. 2017-05-24 15:33:42 -07:00
Francois Chollet 1e09e0a9d4 Style fix. 2017-05-24 15:32:27 -07:00
Francois Chollet 07e0fbc963 Style fixes. 2017-05-24 14:46:15 -07:00
nzw 7ef13165b7 Improve documents (#6727)
* Improve documents

* Fix style
2017-05-23 17:13:09 -07:00
Andrew Hundt d939f14843 stale bot specifies 30 days when it posts (#6735)
Got notified about some stale threads, but realized I forgot to put the number of days in the post's string.
2017-05-23 14:13:32 -07:00
Taehoon Lee ce0f97dbe3 Fix ImageNet weight loading for ResNet50 with channels_first (#6658)
Fix ImageNet weight loading for InceptionV3
2017-05-23 14:12:07 -07:00
cocuh 7e870a97ec Fix edge cases of custom object deserialization 2017-05-23 11:30:45 -07:00
Daniel Høyer Iversen a2c3fa2b96 Small clean ups (#6724)
* Remove unused variables

* progbar
2017-05-23 11:22:34 -07:00
nameless-Chatoyant 7f09d45efb Fix typo in docstring
Corrected a small annotation in Input()
2017-05-23 11:11:29 -07:00
meberstein 85fe6427a5 Added hinge loss for categorical classification (#6687)
* Fix bug in EarlyStopping to reset stopped_epoch in on_train_begin to allow it to be re-used

* Added hinge loss for categorical classification
2017-05-23 10:49:23 -07:00
Andrew Hundt b205ba1270 Automatically close stale issues (#6701)
@fchollet Merge this pull request plus follow https://github.com/integration/probot-stale to automatically mark the many 3 month old issues as stale, then close them after an additional 30 days.

I chose 30 additional days for closing because sometimes people go on vacation for a few weeks, this way they'll have time after being notified.
2017-05-23 10:34:31 -07:00
Arun Lobo e74a37438b Add Chrome timeline support in Tensorflow (#6693)
Fixes #6606
2017-05-22 13:55:03 -07:00
Rusty c8d35caa7f Updated filters in text processing documentation (#6696) 2017-05-22 13:10:27 -07:00
Andrew Hundt cf57d28452 get_file() progbar fix (#6670)
* Fix get_file download progress bar

* Added a comment to clarify the purpose of the "enclosed" dictionary

* pep8

* Fix get_file download progress bar, including no Content-Length header.

* Progbar accepts target None in addition to -1.

* #6670 Remove Progbar implementation details from docstring
Only None should be supported on the Progbar target parameter,
target values of -1 are an unsupported implementation detail
that may be removed in the future.
2017-05-22 12:04:33 -07:00
Indy M c1a1c33ef9 updated fit on texts description (#6699)
fit_on_texts returns a list of words not integer indices as stated. I've corrected this.
2017-05-21 10:52:03 -07:00
Taehoon Lee bac16379a2 Fix typos (#6702) 2017-05-21 10:51:19 -07:00
Matt Gardner b5490b20d2 Fix depth calculation for shared layers (#6668)
* Fixed depth calculation for shared layers

* Added a failing test

* Update the node's depth too
2017-05-19 16:54:03 -07:00
Jun Kim 3061fcce60 Fix a typo in expand_dims() (#6671)
In comment: expended -> expanded
2017-05-18 16:12:48 -07:00
Daniel Høyer Iversen 7a3190de3b Typo in documentation (#6672) 2017-05-18 16:12:37 -07:00
Stefano ed9e8d2ff0 Update image.py (#6618)
Fixes https://github.com/fchollet/keras/issues/6612
2017-05-16 13:40:01 -07:00
Stefano 13303663ff Change save_format from jpg top png, because jpg is a loss format. (#6638)
* Change save_format from jpg top png, because jpg is a loss format.

* Change default format to png, because jpeg is a loss format.
2017-05-16 07:57:50 -07:00
Fariz Rahman 0d27d903c2 Bug fix in convolutional recurrent state setting
* Bug fix: convolutional recurrent (again)

* pep8

* Update convolutional_recurrent.py

* pep8
2017-05-14 10:42:44 -07:00
Kevin Mader 6220e35ccd adding io_utils test for hdf5matrix (#6610)
* adding io_utils test for hdf5matrix

* incorporating pep8 and feedback from @fchollet
2017-05-14 10:40:28 -07:00
Francois Chollet bc9dbc5de0 Style fix in error message 2017-05-12 11:08:46 -07:00
Kyle Dorman d67cf89759 Better error message for invalid functional api inputs (#6589) (#6593)
* Better error message for invalid funcational api inputs (#6589)

* raise ValueError if `inputs` is not a Keras tensor

* Move  to respective backends

* raise error if is_keras_tensor is called on a non-tensor object

* Fix failing tests

* responding to comments

* Update docstring comments to better explain expected behavior
2017-05-12 11:04:27 -07:00
Gökçen Eraslan a2dde60a2f TensorBoard: Embed only given layers (#6565)
* TensorBoard: Embed only given layers.

* TensorBoard: Fix pep8
2017-05-11 14:34:33 -07:00
rejunity e177397427 Small fixes for Neural_Doodle example (#6577)
* Fixed type conversion in neural_doodle example. Shape returns number of channels as int32 however further calculations require it to be float

* Updated neural doodle example to follow Keras2 API. Renamed ‘border_mode’ argument to ‘padding’.

* Fixed apostrophe for consistency.
2017-05-11 14:33:39 -07:00
meberstein 5f4f234f9b In EarlyStopping, reset stopped_epoch in on_train_begin to allow it to be re-used (#6591) 2017-05-11 14:32:49 -07:00
Daniel Høyer Iversen 24db6bfaaf Fix in ZeroPadding3D (#6574)
* Buf fix in ZeroPadding3D

* test_zero_padding_3d
2017-05-11 08:53:15 -07:00
Clara Eng 504bded884 Add callback to terminate training if NaN loss encountered. (Update to #4849) (#6456)
* Added callback TerminateOnNaN.

* Added fixes.
2017-05-10 13:44:57 -07:00
catta202000 08aa6ae555 Added batch histogram computation (#6065)
* Added batch histogram computation

* batch_size_histogram renamed to batch_size, default set to 32, added spaces around operators

* PEP8 fix

* Added batch_size in tests/keras/test_callbacks.py::test_TensorBoard_convnet

* PEP8 fix

* Batch size reduced in tests, targets and sample_weights sliced
2017-05-10 08:16:55 -07:00
popyy0101 737ae88a02 Use OrderedDict instead of normal dict to produce reliable iteration for dict.items() (#6573) 2017-05-10 08:13:53 -07:00
Fariz Rahman 6642d496e5 Recurrent : InputSpec fixes (#6568)
* Recurrent : InputSpec fixes

* Update convolutional_recurrent.py

* pep8 fix

* Update convolutional_recurrent.py
2017-05-09 23:40:57 -07:00
Fariz Rahman 2766074d19 Bug fix + test : Initializing states for ConvLSTM2D (#6564)
* Bug fix

* Update convolutional_recurrent_test.py

* Update convolutional_recurrent.py
2017-05-09 17:32:37 -07:00
Gökçen Eraslan 672028a5f2 Fix hyperlink misrendering in documentation (#6558)
Two hyperlinks (namely `[here]` and `[details]`) are misrendered in TensorBoard documentation, see https://keras.io/callbacks/#tensorboard. Fix exclude `(` in argument names, because otherwise `[link](http://` is rendered as a function/class argument.
2017-05-09 12:13:24 -07:00
Francois Chollet 1a89b13cb4 Try reverting previously merged PR. 2017-05-08 09:33:42 -07:00
Han Lin 268672df65 Don't rate limit final update (#6536) 2017-05-07 17:34:44 -07:00
iddober bfae0a6191 remove unused import in tests folder (#6534) 2017-05-07 14:46:26 -07:00
Moussa Taifi a2a0f66276 Add exception handling when attempting to write keras config file (#6453)
* add exception handling when attempting to write keras config file to disk to match tf.contrib.keras implementation

* Add reliance on exceptions rather than testing write access to the target directory.
2017-05-06 20:02:08 -07:00
Kosuke Kusano ea8e2edf17 fix tuple error message (#6530) 2017-05-06 19:18:29 -07:00
Murat Ambarkutuk d223cc0ff7 Add an option to create dot model in different directions (#5472)
* Add an option to create dot model in different directions

This commit adds an optional argument to functions plot() and model_to_dot() specifying the direction of the dot object

* Rename visualize_util.py to vis_utils.py and and model plot direction

* Format the code in the PEP8 style guide

* Add docstring for plot_model method, format code according to PEP8

pycodestyle and pydocstyle raises no info, warning, or error with this pr.

* Docstring style

* Docstring fixes.
2017-05-05 13:35:09 -07:00
Grégory Châtel 8ac1b1fdc9 Add a directory iterator option to allow to work easily with autoencoders (issue #4260) (#6510)
* identical class_mode code.

* New directory iterator testing function

* class_mode keyword changed to input + clearer doc.
2017-05-05 09:07:31 -07:00
Dr. Kashif Rasul 23833417cf fixed typo (#6523) 2017-05-05 09:05:15 -07:00
Eric Xihui Lin 61c9cdc53c Use axis instead of reduction_indices in logsumexp 2017-05-04 19:47:41 -07:00
Francois Chollet 1c7e63e42c Update docs autogen script. 2017-05-04 17:02:32 -07:00
Francois Chollet 6582043276 Update CONTRIBUTING.md 2017-05-04 17:02:17 -07:00
Parag S. Chandakkar 85221ccd13 Changed l2_normalization in theano_backend.py (#6513) 2017-05-04 15:18:26 -07:00
Gökçen Eraslan cf550db5a5 Visualize grad distributions in TensorBoard (#6313)
* Visualize weight grad distributions in TensorBoard

* TensorBoard: Add learning_phase if needed and fix fit_generator target dimensions.

* TensorBoard: Fix pep8

* TensorBoard: Add a flag to make grad visualization optional.

* TensorBoard: Test grad visualizations as well.

* TensorBoard: Documentation and further pep8 changes.

* TensorBoard: Add dropout layer to test K.learning_phase()

* Add learning_phase check in fit() to fit_generator().

* Tensorboard: Add test for comparing cbk.validation_data for fit() and fit_generator()

* Tensorboard: Fix cbk.val_data test.

* Tensorboard: Enable grad vis in tb convnet test.

* Tensorboard: No linebreak for more readability
2017-05-04 15:17:10 -07:00
SimonMarkWarren 75519651bb Fix error in test_saving_without_compilation (#6504)
* Fix error in test_saving_without_compilation

* Update test_model_saving.py
2017-05-04 13:52:15 -07:00
Stephan Heijl b93d3b23f5 Moved start/end (#6502) 2017-05-04 13:07:26 -07:00
Abhai Kollara Dilip dc3d164c6b Tokenizer docs patch (#6506)
* Tokenizer docs patch

* Minor change
2017-05-04 13:06:26 -07:00
Taehoon Lee 47dddaa7fd Fix valid condition for TF <-> TH conversion of Conv1D (#6497) 2017-05-04 11:49:37 -07:00
Gökçen Eraslan fdd822c03e Tensorboard: Check weight dimensions better in write_images (#6505)
* Tensorboard: Add a convnet test for tensorboard

* Tensorboard: Check weight dimensions better in write_images and make the code more explicit

* Tensorboard: 2 epochs is enough for tb convnet test

* Tensorboard: Fix pep8
2017-05-04 11:48:13 -07:00
Frédéric Bastien a736c2632b Add function names to help profiling/printing of function. (#6463)
* Add function names to help profiling/printing of function.

* Docstring and pass to Theano the new parameter
2017-05-02 08:43:17 -07:00
Daniel Julius Lasiman 1a707ea11e Handle properly values with str type in CSVLogger #6459 (#6460) 2017-05-01 16:56:00 -07:00
Shaofan Lai c430b6c492 Add skip_compile option to keras.models.load_model() (#6436)
* add skip_compile option to keras.models.load_model()

* update document

* change name from skip_compile to compile
2017-04-30 12:20:55 -07:00
Francois Chollet c627fa5bbd Prepare new PyPI release. 2017-04-29 16:18:54 -07:00
Francois Chollet affaa77078 Merge branch 'master' of github.com:fchollet/keras 2017-04-29 15:54:48 -07:00
Ben f1df88737c Fix CSV formatting for Windows with Python 2 (#6311)
* Fix CSV formatting for windows with python 2

* Fix pep8 whitespace

* Fix quote style
2017-04-29 15:50:24 -07:00
Michael R. Kirchner 0ddc3360b7 Update docs and add contributing page (#6432)
* Update docs and add contributing page

* Add space for pep8
2017-04-29 15:37:05 -07:00
Ilya Ivanov eaca5da3e2 Fix indent size of docstring's line (#6440)
Remove excess preceding 4 spaces in Model.fit(..) docstring line
corresponding to verbose parameter.
2017-04-29 11:14:12 -07:00
Francois Chollet 70da22c31f Merge branch 'master' of github.com:fchollet/keras 2017-04-28 12:00:12 -07:00
jcuypers c158410168 Update image.md docs
* Update image.md

Enhancements for _flow_from_directory.  Classes and class_mode None

* Update image.md

Reworked it based on the comments

* Update image.md

* Update image.md

* Update image.md

typos

* Fix docstring
2017-04-28 11:19:01 -07:00
Santiago Castro 0c237ebea2 Fix missing quote mark in Cropping2D docstring (#6428) 2017-04-28 09:54:04 -07:00
Tim O'Shea 8967d16d00 add huber loss function (for robust regression) (#6410)
* add huber loss function (for robust regression)

* rename huber to logcosh (PR comments were correct), fix PEP8 whitespace checks

* logcosh loss: change from lambda to fn def'n, add text coverage
2017-04-27 20:39:05 -07:00
Francois Chollet 964023bec7 Merge branch 'master' of github.com:fchollet/keras 2017-04-27 14:54:53 -07:00
Francois Chollet 16aa56bb1d Small docstring precision 2017-04-27 14:54:48 -07:00
Mako bdf05c48ef Fix typo
* Add a symbol to avoid indent

* Fix typo
2017-04-26 20:44:11 -07:00
Frédéric Branchaud-Charron 653cfd2076 Add test for documentation (#6324)
* Add test for documentation

* Changes according to review

* Changes according to review

* Fix documentation and add Travis task

* Style fixes.

* Fix line length

* PEP8
2017-04-26 11:29:53 -07:00
Andrew Poliakov bcbfcc000c Fix oov_char=None case in IMDB/Reuters datasets (#6397)
Closes: #3688
2017-04-25 19:48:42 -07:00
Nigel 54a417f616 Added support for new pydot versions to fix find_graphviz error (#6398)
* Added support for the new pydot API to fix find_graphviz error

* Simplified pydot installation checking

* Workaround for pydot generic Exception raising

* Removed hacky workaround for pyplot Exception, included comment
2017-04-25 19:20:01 -07:00
Yorwba 5e51d02a94 Use linear time algorithm for topological sorting. (#6347) 2017-04-25 11:30:20 -07:00
nzw d3b9b9d5bb Style Fix in image.md (#6396) 2017-04-25 11:06:19 -07:00
Daniel Høyer Iversen 4f9e7bf93c Bug fix in recurrent layer (#6393)
* Bug fix in recurrent layer

* Add test to recurent layer
2017-04-25 11:05:53 -07:00
Francois Chollet d491dafb80 Merge branch 'master' of github.com:fchollet/keras 2017-04-24 20:21:49 -07:00
Joshua Chin 365f621b24 Fix Specifying Initial States of RNN Layers (#5795)
* fix specify state

* Added documentation for `reset_states`

* Remove unneeded check

* Update Documentation

* pep8

* Fix when initial_states is a tensor

* modify tests for non-list initial states.

* use initial_state instead of initial_states

* pep8

* change get_initial_states to get_initial_state in ConvLSTM2D

* Check for Keras Tensors in Recurrent

* check if initial_state is passed to call

* pep8

* Move state_spec definition to __init__

* Fix reset states

* fix masking when specifying state

* added masking test for RNNs with specified state

* pep8

* remove unnecessary blank line
2017-04-24 20:20:04 -07:00
Francois Chollet 7481b5d060 Update deep dream config. 2017-04-24 19:03:39 -07:00
Francois Chollet 9295efb216 Simplify the deep dream example 2017-04-24 18:23:09 -07:00
Francois Chollet 0d4fb04c7f Style fix in image preprocessing 2017-04-24 18:22:38 -07:00
Francois Chollet 791cba094c Cast kernels as np arrays before TF <-> TH conversion 2017-04-24 18:22:22 -07:00
Francois Chollet 2bb9014c91 Fix a padding bug with Theano average pooling gradients 2017-04-24 18:21:54 -07:00
Francois Chollet 5be73f1ab3 Simplify implementation of BN layer. 2017-04-24 11:47:11 -07:00
Francois Chollet b8134f529c Add “et al” to Keras bibtex entry. 2017-04-24 10:45:31 -07:00
Philipp Gross 7d52af64c0 Added logsumexp to backend. (#6346) 2017-04-22 11:49:33 -07:00
Piasy 70ffba0766 fix stateful RNNs FAQ link (#6336) 2017-04-20 08:30:02 -07:00
nzw e7f3317de6 Style fixes (#6335) 2017-04-20 08:29:45 -07:00
Francois Chollet 47350dc607 Switch to a more reasonable way of initializing LSTM bias 2017-04-19 14:28:49 -07:00
Francois Chollet d498a98465 Make Input importable from root 2017-04-19 14:27:37 -07:00
Francois Chollet 0976afb46d Update add_weight docstring 2017-04-19 14:27:07 -07:00
/c/ympfh 7088ebd294 Fix: doc (#6316) 2017-04-19 09:46:37 -07:00
Andrei Costinescu f71831790f Update check for sequential models (#6305)
* Update layer_utils.py

Model is not sequential if there is a "merge" layer somewhere in the graph. So if a layer has multiple input layers ("inbound_layers"), the whole model is no longer sequential...

* Explanation of changed condition

Added a comment to explain the check for sequentiality in a model:
A model is not sequential if it has multiple nodes or if a layer has multiple inbound_layers
2017-04-18 13:43:31 -07:00
Francois Chollet 83001d195c merge 2017-04-18 11:34:56 -07:00
Francois Chollet 8830c53135 Refactor add_weight to align it with get_variable 2017-04-18 11:34:24 -07:00
HaleyWu d89afdfd82 Update the value of steps_per_epoch of fit_generator to be divided by batch_size (#6301)
* Update the value of 'steps_per_epoch'

* Update the docstring of fit_generator to steps_per_epoch * batch_size

* Update the value of 'steps_per_epoch'

* Update the docstring of fit_generator: when 'steps_per_epoch' batches have been seen
2017-04-18 11:17:26 -07:00
Icyblade Dai 562860ca42 add warnings when advanced activations are passed into Activation (#6280)
* add warnings when advanced activations were passed into Activation

* fix import issue

* warning message beautify

* adopt user-friendly message
2017-04-18 11:01:41 -07:00
Sergey Kojoian fc4874f82c Updated the HDF5Matrix class to support inferred slice indeces such as data[:10] or data[19120:]. (#6299) 2017-04-17 14:24:11 -07:00
nzw 73a620b6e8 Update calback page (#6289) 2017-04-17 14:20:42 -07:00
Andrei Costinescu e0697c3768 Corrected a comment in function "print_layer_summary_with_connections" && Fixed issue #6286 (#6284)
* Corrected a comment in function "print_layer_summary_with_connections"

Changed line 82 from "# node is node part of the current network" to "# node is not part of the current network"

* Fixed issue #6286

Fixed the issue where the summary of non-sequential models would not display content of "Connected to" column
2017-04-17 14:20:23 -07:00
nzw 73bf06fb02 Style fixes (#6271)
* Fix link in FAQ

* Fix link in FAQ

* Style fix

* Rename objectives to losses
2017-04-16 13:08:44 -07:00
Vladimir Alekseichenko 53bee20647 Explicit import of ifelse in Theano backend 2017-04-16 13:08:04 -07:00
Francois Chollet 18ed60b9f2 Fix PEP8 issue. 2017-04-15 17:40:25 -07:00
Russ09 707534e46e Allows preprocess_weights_for_loading() to consider layers wrapped in TimeDistributed or Bidirectional (#5836)
* Allows preprocess_weights_for_loading() to consider layers wrapped in TimeDistributed or Bidirectional.

* fixed whitespace PEP8 issue

* Allows preprocess_weights_for_loading() to consider layers wrapped in TimeDistributed or Bidirectional.

* Allows preprocess_weights_for_loading() to consider layers wrapped in TimeDistributed or Bidirectional.

* Refactored preprocess_weights_for_loading() to allow for loading to TimeDistributed and Bidirectional. PEP8 Fixes.

* PEP8 Fixes

* Recursive implementation of preprocess_weights_for_loading to accomodate Bidirectional and TimeDistributed wrappers.

* Recursive implementation of preprocess_weights_for_loading to accomodate Bidirectional and TimeDistributed wrappers.

* deindentation and doc-string formatting. method argument formating.
2017-04-15 16:11:51 -07:00
Vasilis Vryniotis cd6bbe7290 Adding backwards compatibility for old models by concerting input_dtype to dtype on InputLayers. (#6248) 2017-04-15 16:11:17 -07:00
nzw f6cc059104 Update datasets docs (#6266)
* Update docs

* Style fix
2017-04-15 16:10:31 -07:00
Francois Chollet 6572934f9a Merge branch 'master' of github.com:fchollet/keras 2017-04-14 18:08:35 -07:00
Francois Chollet 2a67506728 Fix GRU bias initializer selection 2017-04-14 18:08:22 -07:00
nzw 4507057e11 Update docs (#6249)
* Fix file path

* Update docs for keras v2
2017-04-14 13:15:30 -07:00
Francois Chollet eee1d90ef2 Merge branch 'master' of github.com:fchollet/keras 2017-04-14 12:31:38 -07:00
Francois Chollet 9d0efc081e Update Travis config 2017-04-14 12:31:21 -07:00
Yorwba 2c284017d4 Fix Model.fit_generator for multiple outputs with same name. (#6239) 2017-04-13 13:00:49 -07:00
alexantoinefortin 90758c3f4e typo in model_from_config error flag (#6238) 2017-04-12 22:11:06 -07:00
John B Nelson dcacdd3747 Update fit_generator docstr for new API (#6230) 2017-04-12 22:10:51 -07:00
Mohanson 5bd3976e79 Spelling errors (#6232) 2017-04-12 22:10:15 -07:00
Francois Chollet 9eb7ecd3e5 Merge branch 'master' of github.com:fchollet/keras 2017-04-11 13:56:43 -07:00
Francois Chollet 05589a7c27 Merge branch 'Spotlight0xff-origin/vae_add_loss' 2017-04-11 13:43:37 -07:00
Francois Chollet 4aa41625bf Switch variational examples to new API. 2017-04-11 13:43:04 -07:00
Francois Chollet b2f0dd4cb2 Improve error messages in data validation checks. 2017-04-11 13:42:18 -07:00
Francois Chollet 17ef113ed7 Add identity op, avoid having input tensors in layer outputs (metadata loss). 2017-04-11 13:41:54 -07:00
Francois Chollet c029fa2f62 Merge branch 'origin/vae_add_loss' of https://github.com/Spotlight0xff/keras into Spotlight0xff-origin/vae_add_loss 2017-04-11 12:57:28 -07:00
Nigel Ng 52b1377fe6 Update mnist_siamese_graph example (#6223)
Take max of squared distance and K.epsilon() because some data points will throw `nan` for euclidean distance.
2017-04-11 12:09:44 -07:00
Francois Chollet 5598fcd33e Merge branch 'master' of github.com:fchollet/keras 2017-04-11 11:33:52 -07:00
Francois Chollet b558a7e97c Add RNN unit test 2017-04-11 11:32:41 -07:00
Francois Chollet 172397ebf4 Simplify param counting in model summary. 2017-04-11 11:32:11 -07:00
Francois Chollet 9adb43e44b Improve style of some comments. 2017-04-11 11:31:42 -07:00
Fariz Rahman ac6fde801c Bug fix: K.batch_dot(); tf backend (#6219)
* Update tensorflow_backend.py

* Update tensorflow_backend.py

* add unit tests
2017-04-10 15:56:00 -07:00
Spotlight0xff e848463347 using .add_loss in custom layer for VAE example 2017-03-15 13:21:45 +01:00
Joshua Chin c469f80f81 Merge pull request #1 from israelg99/patch-1
Fix multiple spaces after operator
2017-03-13 00:12:30 -04:00
Israel Gilyadov 44b25b80b2 Fix multiple spaces after operator 2017-03-13 04:39:22 +02:00
Joshua Chin 12907534f8 Added return_state to config. 2017-03-12 13:48:00 -04:00
Joshua Chin 10d7e21efc Add return_state flag to RNNs. 2017-03-12 13:37:25 -04:00
92 arquivos alterados com 5857 adições e 1565 exclusões
+19
Ver Arquivo
@@ -0,0 +1,19 @@
# Configuration for probot-stale - https://github.com/probot/stale
# Number of days of inactivity before an Issue or Pull Request becomes stale
daysUntilStale: 90
# Number of days of inactivity before a stale Issue or Pull Request is closed
daysUntilClose: 30
# Issues or Pull Requests with these labels will never be considered stale
exemptLabels:
- bug
- Announcement
- help wanted
- To investigate
# Label to use when marking as stale
staleLabel: stale
# Comment to post when marking as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed after 30 days if no further activity
occurs, but feel free to re-open a closed issue if needed.
+27 -3
Ver Arquivo
@@ -7,6 +7,8 @@ matrix:
env: KERAS_BACKEND=tensorflow TEST_MODE=PEP8
- python: 2.7
env: KERAS_BACKEND=tensorflow TEST_MODE=INTEGRATION_TESTS
- python: 3.5
env: KERAS_BACKEND=tensorflow TEST_MODE=DOC
- python: 2.7
env: KERAS_BACKEND=tensorflow
- python: 3.5
@@ -15,6 +17,10 @@ matrix:
env: KERAS_BACKEND=theano
- python: 3.5
env: KERAS_BACKEND=theano
- python: 2.7
env: KERAS_BACKEND=cntk
- python: 3.5
env: KERAS_BACKEND=cntk
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
@@ -34,7 +40,7 @@ install:
- conda create -q -n test-environment python=$TRAVIS_PYTHON_VERSION numpy scipy matplotlib pandas pytest h5py
- source activate test-environment
- pip install git+git://github.com/Theano/Theano.git
- pip install theano
# install PIL for preprocessing tests
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
@@ -45,8 +51,24 @@ install:
- pip install -e .[tests]
# install TensorFlow
# install TensorFlow (CPU version).
- pip install tensorflow
# install cntk
- if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then
pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.0-cp27-cp27mu-linux_x86_64.whl;
elif [[ "$TRAVIS_PYTHON_VERSION" == "3.5" ]]; then
pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.0-cp35-cp35m-linux_x86_64.whl;
fi
#install open mpi
- rm -rf ~/mpi
- mkdir ~/mpi
- pushd ~/mpi
- wget http://cntk.ai/PythonWheel/ForKeras/depends/openmpi_1.10-3.zip
- unzip ./openmpi_1.10-3.zip
- sudo dpkg -i openmpi_1.10-3.deb
- popd
# command to run tests
script:
@@ -61,6 +83,8 @@ script:
PYTHONPATH=$PWD:$PYTHONPATH py.test tests/integration_tests;
elif [[ "$TEST_MODE" == "PEP8" ]]; then
PYTHONPATH=$PWD:$PYTHONPATH py.test --pep8 -m pep8 -n0;
elif [[ "$TEST_MODE" == "DOC" ]]; then
PYTHONPATH=$PWD:$PYTHONPATH py.test tests/test_documentation.py;
else
PYTHONPATH=$PWD:$PYTHONPATH py.test tests/ --ignore=tests/integration_tests --cov=keras tests/ --cov-fail-under 78 --cov-report term-missing;
PYTHONPATH=$PWD:$PYTHONPATH py.test tests/ --ignore=tests/integration_tests --ignore=tests/test_documentation.py --cov=keras tests/ --cov-fail-under 78 --cov-report term-missing;
fi
+16 -9
Ver Arquivo
@@ -19,6 +19,7 @@ To easily update Theano: `pip install git+git://github.com/Theano/Theano.git --u
The more information you provide, the easier it is for us to validate that there is a bug and the faster we'll be able to take action. If you want your issue to be resolved quickly, following the steps above is crucial.
---
## Requesting a Feature
@@ -31,11 +32,15 @@ You can also use Github issues to request features you would like to see in Kera
3. After discussing the feature you may choose to attempt a Pull Request. If you're at all able, start writing some code. We always have more work to do than time to do it. If you can write some code then that will speed the process along.
---
## Requests for Contributions
[This is the board](https://github.com/fchollet/keras/projects/1) where we list current outstanding issues and features to be added. If you want to start contributing to Keras, this is the place to start.
---
## Pull Requests
**Where should I submit my pull request?**
@@ -49,27 +54,29 @@ Here's a quick guide to submitting your improvements:
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.
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. **Docstring style should be respected.** In particular, they should be formatted in MarkDown, and there should be sections for `Arguments`, `Returns`, `Raises` (if applicable). Look at other docstrings in the codebase for examples.
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 the test requirements as well: `pip install -e .[tests]`.
- You will need to install the test requirements as well: `pip install -e .[tests]`.
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
- with the Theano backend, on Python 2.7 and Python 3.5. Make sure you have the development version of Theano.
- with the TensorFlow backend, on Python 2.7 and Python 3.5. Make sure you have the development version of TensorFlow.
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`
- 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. 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.
8. When committing, use appropriate, descriptive commit messages.
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...
10. Submit your PR. If your changes have been approved in a previous discussion, and if you have complete (and passing) unit tests as well as proper docstrings/documentation, your PR is likely to be merged promptly. Otherwise, well...
---
## Adding new examples
+5 -1
Ver Arquivo
@@ -8,8 +8,12 @@ All contributions by Google:
Copyright (c) 2015, Google, Inc.
All rights reserved.
All contributions by Microsoft:
Copyright (c) 2017, Microsoft, Inc.
All rights reserved.
All other contributions:
Copyright (c) 2015, the respective contributors.
Copyright (c) 2015 - 2017, the respective contributors.
All rights reserved.
Each contributor holds copyright over their respective contributions.
+8 -3
Ver Arquivo
@@ -1,11 +1,11 @@
# Keras: Deep Learning library for TensorFlow and Theano
# Keras: Deep Learning for Python
[![Build Status](https://travis-ci.org/fchollet/keras.svg?branch=master)](https://travis-ci.org/fchollet/keras)
[![license](https://img.shields.io/github/license/mashape/apistatus.svg?maxAge=2592000)](https://github.com/fchollet/keras/blob/master/LICENSE)
## You have just found Keras.
Keras is a high-level neural networks API, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. *Being able to go from idea to result with the least possible delay is key to doing good research.*
Keras is a high-level neural networks API, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow), [CNTK](https://github.com/Microsoft/cntk) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. *Being able to go from idea to result with the least possible delay is key to doing good research.*
Use Keras if you need a deep learning library that:
@@ -125,6 +125,11 @@ Keras uses the following dependencies:
- TensorFlow
- [See installation instructions](https://www.tensorflow.org/install/).
*When using the CNTK backend:*
- CNTK
- [See installation instructions](https://docs.microsoft.com/en-us/cognitive-toolkit/setup-cntk-on-your-machine).
*When using the Theano backend:*
- Theano
@@ -143,7 +148,7 @@ sudo pip install keras
------------------
## Switching from TensorFlow to Theano
## Switching from TensorFlow to CNTK or Theano
By default, Keras will use TensorFlow as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
+24 -17
Ver Arquivo
@@ -8,9 +8,7 @@ Index
- Getting started
Getting started with the sequential model
Getting started with the functional api
Examples
FAQ
Installation guide
- Models
About Keras models
@@ -26,18 +24,23 @@ Index
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
Core Layers
Convolutional Layers
Pooling Layers
Locally-connected Layers
Recurrent Layers
Embedding Layers
Merge Layers
Advanced Activations Layers
Normalization Layers
Noise Layers
Layer Wrappers
Writing your own Keras layers
- Preprocessing
Image preprocessing
Text preprocessing
Sequence preprocessing
Sequence Preprocessing
Text Preprocessing
Image Preprocessing
Losses
Metrics
@@ -45,12 +48,15 @@ Optimizers
Activations
Callbacks
Datasets
Applications
Backend
Initializations
Initializers
Regularizers
Constraints
Visualization
Scikit-learn API
Utils
Contributing
'''
from __future__ import print_function
@@ -114,14 +120,13 @@ PAGES = [
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,
models.Sequential.predict_generator,
models.Sequential.get_layer,
],
},
{
@@ -382,7 +387,7 @@ def process_class_docstring(docstring):
r'\n __\1__\n\n',
docstring)
docstring = re.sub(r' ([^\s\\]+):(.*)\n',
docstring = re.sub(r' ([^\s\\\(]+):(.*)\n',
r' - __\1__:\2\n',
docstring)
@@ -400,7 +405,7 @@ def process_function_docstring(docstring):
r'\n __\1__\n\n',
docstring)
docstring = re.sub(r' ([^\s\\]+):(.*)\n',
docstring = re.sub(r' ([^\s\\\(]+):(.*)\n',
r' - __\1__:\2\n',
docstring)
@@ -509,3 +514,5 @@ for page_data in PAGES:
if not os.path.exists(subdir):
os.makedirs(subdir)
open(path, 'w').write(mkdown)
shutil.copyfile('../CONTRIBUTING.md', 'sources/contributing.md')
+1
Ver Arquivo
@@ -51,3 +51,4 @@ pages:
- Visualization: visualization.md
- Scikit-learn API: scikit-learn-api.md
- Utils: utils.md
- Contributing: contributing.md
+7 -7
Ver Arquivo
@@ -15,7 +15,7 @@ Weights are downloaded automatically when instantiating a model. They are stored
- [ResNet50](#resnet50)
- [InceptionV3](#inceptionv3)
All of these architectures (except Xception) are compatible with both TensorFlow and Theano, and upon instantiation the models will be built according to the image data format set in your Keras configuration file at `~/.keras/keras.json`. For instance, if you have set `image_data_format=tf`, then any model loaded from this repository will get built according to the TensorFlow data format convention, "Width-Height-Depth".
All of these architectures (except Xception) are compatible with both TensorFlow and Theano, and upon instantiation the models will be built according to the image data format set in your Keras configuration file at `~/.keras/keras.json`. For instance, if you have set `image_data_format=channels_last`, then any model loaded from this repository will get built according to the TensorFlow data format convention, "Width-Height-Depth".
The Xception model is only available for TensorFlow, due to its reliance on `SeparableConvolution` layers.
@@ -130,10 +130,10 @@ for i, layer in enumerate(base_model.layers):
print(i, layer.name)
# we chose to train the top 2 inception blocks, i.e. we will freeze
# the first 172 layers and unfreeze the rest:
for layer in model.layers[:172]:
# the first 249 layers and unfreeze the rest:
for layer in model.layers[:249]:
layer.trainable = False
for layer in model.layers[172:]:
for layer in model.layers[249:]:
layer.trainable = True
# we need to recompile the model for these modifications to take effect
@@ -253,7 +253,7 @@ The default input size for this model is 224x224.
- input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape
has to be `(224, 224, 3)` (with `channels_last` data format)
or `(3, 224, 244)` (with `channels_first` data format).
or `(3, 224, 224)` (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 48.
E.g. `(200, 200, 3)` would be one valid value.
@@ -309,7 +309,7 @@ The default input size for this model is 224x224.
- input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape
has to be `(224, 224, 3)` (with `channels_last` data format)
or `(3, 224, 244)` (with `channels_first` data format).
or `(3, 224, 224)` (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 48.
E.g. `(200, 200, 3)` would be one valid value.
@@ -367,7 +367,7 @@ The default input size for this model is 224x224.
- input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape
has to be `(224, 224, 3)` (with `channels_last` data format)
or `(3, 224, 244)` (with `channels_first` data format).
or `(3, 224, 224)` (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 197.
E.g. `(200, 200, 3)` would be one valid value.
+5 -4
Ver Arquivo
@@ -4,12 +4,13 @@
Keras is a model-level library, providing high-level building blocks for developing deep learning models. It does not handle itself low-level operations such as tensor products, convolutions and so on. Instead, it relies on a specialized, well-optimized tensor manipulation library to do so, serving as the "backend engine" of Keras. Rather than picking one single tensor library and making the implementation of Keras tied to that library, Keras handles the problem in a modular way, and several different backend engines can be plugged seamlessly into Keras.
At this time, Keras has two backend implementations available: the **TensorFlow** backend and the **Theano** backend.
At this time, Keras has three backend implementations available: the **TensorFlow** backend, the **Theano** backend, and the **CNTK** backend.
- [TensorFlow](http://www.tensorflow.org/) is an open-source symbolic tensor manipulation framework developed by Google, Inc.
- [Theano](http://deeplearning.net/software/theano/) is an open-source symbolic tensor manipulation framework developed by LISA/MILA Lab at Université de Montréal.
- [CNTK](https://www.microsoft.com/en-us/cognitive-toolkit/) is an open-source, commercial-grade toolkit for deep learning developed by Microsoft.
In the future, we are likely to add more backend options. Go ask Microsoft about how their CNTK backend project is doing.
In the future, we are likely to add more backend options.
----
@@ -34,7 +35,7 @@ The default configuration file looks like this:
}
```
Simply change the field `backend` to either `"theano"` or `"tensorflow"`, and Keras will use the new configuration next time you run any Keras code.
Simply change the field `backend` to `"theano"`, `"tensorflow"`, or `"cntk"`, and Keras will use the new configuration next time you run any Keras code.
You can also define the environment variable ``KERAS_BACKEND`` and this will
override what is defined in your config file :
@@ -65,7 +66,7 @@ You can change these settings by editing `$HOME/.keras/keras.json`.
- For 3D data, `"channels_last"` assumes `(conv_dim1, conv_dim2, conv_dim3, channels)` while `"channels_first"` assumes `(channels, conv_dim1, conv_dim2, conv_dim3)`.
* `epsilon`: float, a numeric fuzzing constant used to avoid dividing by zero in some operations.
* `floatx`: string, `"float16"`, `"float32"`, or `"float64"`. Default float precision.
* `backend`: string, `"tensorflow"` or `"theano"`.
* `backend`: string, `"tensorflow"`, `"theano"`, or `"cntk"`.
----
+6 -8
Ver Arquivo
@@ -36,14 +36,14 @@ class LossHistory(keras.callbacks.Callback):
self.losses.append(logs.get('loss'))
model = Sequential()
model.add(Dense(10, input_dim=784, init='uniform'))
model.add(Dense(10, input_dim=784, kernel_initializer='uniform'))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
history = LossHistory()
model.fit(X_train, Y_train, batch_size=128, epochs=20, verbose=0, callbacks=[history])
model.fit(x_train, y_train, batch_size=128, epochs=20, verbose=0, callbacks=[history])
print history.losses
print(history.losses)
# outputs
'''
[0.66047596406559383, 0.3547245744908703, ..., 0.25953155204159617, 0.25901699725311789]
@@ -58,15 +58,13 @@ print history.losses
from keras.callbacks import ModelCheckpoint
model = Sequential()
model.add(Dense(10, input_dim=784, init='uniform'))
model.add(Dense(10, input_dim=784, kernel_initializer='uniform'))
model.add(Activation('softmax'))
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
'''
saves the model weights after each epoch if the validation loss decreased
'''
checkpointer = ModelCheckpoint(filepath="/tmp/weights.hdf5", verbose=1, save_best_only=True)
model.fit(X_train, Y_train, batch_size=128, epochs=20, verbose=0, validation_data=(X_test, Y_test), callbacks=[checkpointer])
checkpointer = ModelCheckpoint(filepath='/tmp/weights.hdf5', verbose=1, save_best_only=True)
model.fit(x_train, y_train, batch_size=128, epochs=20, verbose=0, validation_data=(X_test, Y_test), callbacks=[checkpointer])
```
+8 -8
Ver Arquivo
@@ -55,7 +55,7 @@ As a convention, "0" does not stand for a specific word, but instead is used to
```python
from keras.datasets import imdb
(x_train, y_train), (x_test, y_test) = imdb.load_data(path="imdb_full.pkl",
(x_train, y_train), (x_test, y_test) = imdb.load_data(path="imdb.npz",
num_words=None,
skip_top=0,
maxlen=None,
@@ -72,13 +72,13 @@ from keras.datasets import imdb
- __Arguments:__
- __path__: if you do not have the data locally (at `'~/.keras/datasets/' + path`), it will be downloaded to this location.
- __num_words__: integer or None. Top most frequent words to consider. Any less frequent word will appear as 0 in the sequence data.
- __skip_top__: integer. Top most frequent words to ignore (they will appear as 0s in the sequence data).
- __num_words__: integer or None. Top most frequent words to consider. Any less frequent word will appear as `oov_char` value in the sequence data.
- __skip_top__: integer. Top most frequent words to ignore (they will appear as `oov_char` value in the sequence data).
- __maxlen__: int. Maximum sequence length. Any longer sequence will be truncated.
- __seed__: int. Seed for reproducible data shuffling.
- __start_char__: char. The start of a sequence will be marked with this character.
- __start_char__: int. The start of a sequence will be marked with this character.
Set to 1 because 0 is usually the padding character.
- __oov_char__: char. words that were cut out because of the `num_words`
- __oov_char__: int. words that were cut out because of the `num_words`
or `skip_top` limit will be replaced with this character.
- __index_from__: int. Index actual words with this index and higher.
@@ -94,7 +94,7 @@ Dataset of 11,228 newswires from Reuters, labeled over 46 topics. As with the IM
```python
from keras.datasets import reuters
(x_train, y_train), (x_test, y_test) = reuters.load_data(path="reuters.pkl",
(x_train, y_train), (x_test, y_test) = reuters.load_data(path="reuters.npz",
num_words=None,
skip_top=0,
maxlen=None,
@@ -107,12 +107,12 @@ from keras.datasets import reuters
The specifications are the same as that of the IMDB dataset, with the addition of:
- __test_split__: float. Fraction of the dataset to be used as test data.
- __test_split__: float. Fraction of the dataset to be used as test data.
This dataset also makes available the word index used for encoding the sequences:
```python
word_index = reuters.get_word_index(path="reuters_word_index.pkl")
word_index = reuters.get_word_index(path="reuters_word_index.json")
```
- __Returns:__ A dictionary where key are words (str) and values are indexes (integer). eg. `word_index["giraffe"]` might return `1234`.
+20 -20
Ver Arquivo
@@ -27,7 +27,7 @@ Please cite Keras in your publications if it helps your research. Here is an exa
```
@misc{chollet2015keras,
title={Keras},
author={Chollet, Fran\c{c}ois},
author={Chollet, Fran\c{c}ois and others},
year={2015},
publisher={GitHub},
howpublished={\url{https://github.com/fchollet/keras}},
@@ -38,7 +38,7 @@ Please cite Keras in your publications if it helps your research. Here is an exa
### 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 TensorFlow or CNTK backends, 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:
@@ -153,16 +153,16 @@ For example:
"""
Assume original model looks like this:
model = Sequential()
model.add(Dense(2, input_dim=3, name="dense_1"))
model.add(Dense(3, name="dense_2"))
model.add(Dense(2, input_dim=3, name='dense_1'))
model.add(Dense(3, name='dense_2'))
...
model.save_weights(fname)
"""
# new model
model = Sequential()
model.add(Dense(2, input_dim=3, name="dense_1")) # will be loaded
model.add(Dense(10, name="new_dense")) # will not be loaded
model.add(Dense(2, input_dim=3, name='dense_1')) # will be loaded
model.add(Dense(10, name='new_dense')) # will not be loaded
# load weights from first model; will only affect the first layer, dense_1.
model.load_weights(fname, by_name=True)
@@ -201,7 +201,7 @@ from keras import backend as K
# 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]
layer_output = get_3rd_layer_output([x])[0]
```
Similarly, you could build a Theano and TensorFlow function directly.
@@ -214,17 +214,17 @@ get_3rd_layer_output = K.function([model.layers[0].input, K.learning_phase()],
[model.layers[3].output])
# output in test mode = 0
layer_output = get_3rd_layer_output([X, 0])[0]
layer_output = get_3rd_layer_output([x, 0])[0]
# output in train mode = 1
layer_output = get_3rd_layer_output([X, 1])[0]
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/sequential).
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).
Alternatively, you can write a generator that yields batches of training data and use the method `model.fit_generator(data_generator, steps_per_epoch, epochs)`.
@@ -239,7 +239,7 @@ You can use an `EarlyStopping` callback:
```python
from keras.callbacks import EarlyStopping
early_stopping = EarlyStopping(monitor='val_loss', patience=2)
model.fit(X, y, validation_split=0.2, callbacks=[early_stopping])
model.fit(x, y, validation_split=0.2, callbacks=[early_stopping])
```
Find out more in the [callbacks documentation](/callbacks).
@@ -268,7 +268,7 @@ Validation data is never shuffled.
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)
hist = model.fit(x, y, validation_split=0.2)
print(hist.history)
```
@@ -315,7 +315,7 @@ Making a RNN stateful means that the states for the samples of each batch will b
When using stateful RNNs, it is therefore assumed that:
- all batches have the same number of samples
- If `X1` and `X2` are successive batches of samples, then `X2[i]` is the follow-up sequence to `X1[i]`, for every `i`.
- If `x1` and `x2` are successive batches of samples, then `x2[i]` is the follow-up sequence to `x1[i]`, for every `i`.
To use statefulness in RNNs, you need to:
@@ -332,7 +332,7 @@ Example:
```python
X # this is our input data, of shape (32, 21, 16)
x # this is our input data, of shape (32, 21, 16)
# we will feed it to our model in sequences of length 10
model = Sequential()
@@ -342,10 +342,10 @@ model.add(Dense(16, activation='softmax'))
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
# we train the network to predict the 11th timestep given the first 10:
model.train_on_batch(X[:, :10, :], np.reshape(X[:, 10, :], (32, 16)))
model.train_on_batch(x[:, :10, :], np.reshape(x[:, 10, :], (32, 16)))
# the state of the network has changed. We can feed the follow-up sequences:
model.train_on_batch(X[:, 10:20, :], np.reshape(X[:, 20, :], (32, 16)))
model.train_on_batch(x[:, 10:20, :], np.reshape(x[:, 20, :], (32, 16)))
# let's reset the states of the LSTM layer:
model.reset_states()
@@ -411,15 +411,15 @@ The VGG16 model is also the basis for several Keras example scripts:
### How can I use HDF5 inputs with Keras?
You can use the `HDF5Matrix` class from `keras.utils.io_utils`. See [the HDF5Matrix documentation](/io_utils/#HDF5Matrix) for details.
You can use the `HDF5Matrix` class from `keras.utils.io_utils`. See [the HDF5Matrix documentation](/utils/#hdf5matrix) for details.
You can also directly use a HDF5 dataset:
```python
import h5py
with h5py.File('input/file.hdf5', 'r') as f:
X_data = f['X_data']
model.predict(X_data)
x_data = f['x_data']
model.predict(x_data)
```
---
@@ -451,6 +451,6 @@ It contains the following fields:
- The image data format to be used as default by image processing layers and utilities (either `channels_last` or `channels_first`).
- The `epsilon` numerical fuzz factor to be used to prevent division by zero in some operations.
- The default float data type.
- The default backend. See the (backend documentation)[/backend].
- The default backend. See the [backend documentation](/backend).
Likewise, cached dataset files, such as those downloaded with [`get_file()`](/utils/#get_file), are stored by default in `$HOME/.keras/datasets/`.
+1 -1
Ver Arquivo
@@ -361,7 +361,7 @@ 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(Conv2D(64, (3, 3) activation='relu', padding='same', input_shape=(3, 224, 224)))
vision_model.add(Conv2D(64, (3, 3), activation='relu', padding='same', input_shape=(3, 224, 224)))
vision_model.add(Conv2D(64, (3, 3), activation='relu'))
vision_model.add(MaxPooling2D((2, 2)))
vision_model.add(Conv2D(128, (3, 3), activation='relu', padding='same'))
+1 -1
Ver Arquivo
@@ -354,7 +354,7 @@ A stateful recurrent model is one for which the internal states (memories) obtai
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)
[You can read more about stateful RNNs in the FAQ.](/getting-started/faq/#how-can-i-use-stateful-rnns)
```python
from keras.models import Sequential
+1 -1
Ver Arquivo
@@ -1,3 +1,3 @@
# Keras: Deep Learning library for Theano and TensorFlow
# Keras: The Python Deep Learning library
{{autogenerated}}
+1 -1
Ver Arquivo
@@ -39,5 +39,5 @@ from keras import backend as K
def my_init(shape, dtype=None):
return K.random_normal(shape, dtype=dtype)
model.add(Dense(64, init=my_init))
model.add(Dense(64, kernel_initializer=my_init))
```
+2 -1
Ver Arquivo
@@ -21,7 +21,8 @@ class MyLayer(Layer):
def build(self, input_shape):
# Create a trainable weight variable for this layer.
self.kernel = self.add_weight(shape=(input_shape[1], self.output_dim),
self.kernel = self.add_weight(name='kernel',
shape=(input_shape[1], self.output_dim),
initializer='uniform',
trainable=True)
super(MyLayer, self).build(input_shape) # Be sure to call this somewhere!
+21 -19
Ver Arquivo
@@ -7,6 +7,7 @@ keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
zca_epsilon=1e-6,
rotation_range=0.,
width_shift_range=0.,
height_shift_range=0.,
@@ -29,6 +30,7 @@ Generate batches of tensor image data with real-time data augmentation. The data
- __samplewise_center__: Boolean. Set each sample mean to 0.
- __featurewise_std_normalization__: Boolean. Divide inputs by std of the dataset, feature-wise.
- __samplewise_std_normalization__: Boolean. Divide each input by its std.
- __zca_epsilon__: epsilon for ZCA whitening. Default is 1e-6.
- __zca_whitening__: Boolean. Apply ZCA whitening.
- __rotation_range__: Int. Degree range for random rotations.
- __width_shift_range__: Float (fraction of total width). Range for random horizontal shifts.
@@ -56,19 +58,19 @@ Generate batches of tensor image data with real-time data augmentation. The data
If you never set it, then it will be "channels_last".
- __Methods__:
- __fit(X)__: Compute the internal data stats related to the data-dependent transformations, based on an array of sample data.
- __fit(x)__: Compute the internal data stats related to the data-dependent transformations, based on an array of sample data.
Only required if featurewise_center or featurewise_std_normalization or zca_whitening.
- __Arguments__:
- __X__: sample data. Should have rank 4.
- __x__: sample data. Should have rank 4.
In case of grayscale data,
the channels axis should have value 1, and in case
of RGB data, it should have value 3.
- __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.
- __seed__: int (default: None). Random seed.
- __flow(X, y)__: Takes numpy data & label arrays, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
- __flow(x, y)__: Takes numpy data & label arrays, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
- __Arguments__:
- __X__: data. Should have rank 4.
- __x__: data. Should have rank 4.
In case of grayscale data,
the channels axis should have value 1, and in case
of RGB data, it should have value 3.
@@ -78,7 +80,7 @@ Generate batches of tensor image data with real-time data augmentation. The data
- __seed__: int (default: None).
- __save_to_dir__: None or str (default: None). This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
- __save_prefix__: str (default: `''`). Prefix to use for filenames of saved pictures (only relevant if `save_to_dir` is set).
- __save_format__: one of "png", "jpeg" (only relevant if `save_to_dir` is set). Default: "jpeg".
- __save_format__: one of "png", "jpeg" (only relevant if `save_to_dir` is set). Default: "png".
- __yields__: Tuples of `(x, y)` where `x` is a numpy array of image data and `y` is a numpy array of corresponding labels.
The generator loops indefinitely.
- __flow_from_directory(directory)__: Takes the path to a directory, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
@@ -88,25 +90,25 @@ Generate batches of tensor image data with real-time data augmentation. The data
See [this script](https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d) for more details.
- __target_size__: tuple of integers, default: `(256, 256)`. The dimensions to which all images found will be resized.
- __color_mode__: one of "grayscale", "rbg". Default: "rgb". Whether the images will be converted to have 1 or 3 color channels.
- __classes__: optional list of class subdirectories (e.g. `['dogs', 'cats']`). Default: None. If not provided, the list of classes will be automatically inferred (and the order of the classes, which will map to the label indices, will be alphanumeric).
- __class_mode__: one of "categorical", "binary", "sparse" or None. Default: "categorical". Determines the type of label arrays that are returned: "categorical" will be 2D one-hot encoded labels, "binary" will be 1D binary labels, "sparse" will be 1D integer labels. If None, no labels are returned (the generator will only yield batches of image data, which is useful to use `model.predict_generator()`, `model.evaluate_generator()`, etc.).
- __classes__: optional list of class subdirectories (e.g. `['dogs', 'cats']`). Default: None. If not provided, the list of classes will be automatically inferred from the subdirectory names/structure under `directory`, where each subdirectory will be treated as a different class (and the order of the classes, which will map to the label indices, will be alphanumeric). The dictionary containing the mapping from class names to class indices can be obtained via the attribute `class_indices`.
- __class_mode__: one of "categorical", "binary", "sparse" or None. Default: "categorical". Determines the type of label arrays that are returned: "categorical" will be 2D one-hot encoded labels, "binary" will be 1D binary labels, "sparse" will be 1D integer labels. If None, no labels are returned (the generator will only yield batches of image data, which is useful to use `model.predict_generator()`, `model.evaluate_generator()`, etc.). Please note that in case of class_mode None, the data still needs to reside in a subdirectory of `directory` for it to work correctly.
- __batch_size__: size of the batches of data (default: 32).
- __shuffle__: whether to shuffle the data (default: True)
- __seed__: optional random seed for shuffling and transformations.
- __save_to_dir__: None or str (default: None). This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
- __save_prefix__: str. Prefix to use for filenames of saved pictures (only relevant if `save_to_dir` is set).
- __save_format__: one of "png", "jpeg" (only relevant if `save_to_dir` is set). Default: "jpeg".
- __save_format__: one of "png", "jpeg" (only relevant if `save_to_dir` is set). Default: "png".
- __follow_links__: whether to follow symlinks inside class subdirectories (default: False).
- __Examples__:
Example of using `.flow(X, y)`:
Example of using `.flow(x, y)`:
```python
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
Y_train = np_utils.to_categorical(y_train, num_classes)
Y_test = np_utils.to_categorical(y_test, num_classes)
(x_train, y_train), (x_test, y_test) = cifar10.load_data()
y_train = np_utils.to_categorical(y_train, num_classes)
y_test = np_utils.to_categorical(y_test, num_classes)
datagen = ImageDataGenerator(
featurewise_center=True,
@@ -118,20 +120,20 @@ datagen = ImageDataGenerator(
# compute quantities required for featurewise normalization
# (std, mean, and principal components if ZCA whitening is applied)
datagen.fit(X_train)
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),
steps_per_epoch=len(X_train), epochs=epochs)
model.fit_generator(datagen.flow(x_train, y_train, batch_size=32),
steps_per_epoch=len(x_train) / 32, epochs=epochs)
# here's a more "manual" example
for e in range(epochs):
print 'Epoch', e
print('Epoch', e)
batches = 0
for X_batch, Y_batch in datagen.flow(X_train, Y_train, batch_size=32):
loss = model.train(X_batch, Y_batch)
for x_batch, y_batch in datagen.flow(x_train, y_train, batch_size=32):
model.fit(x_batch, y_batch)
batches += 1
if batches >= len(X_train) / 32:
if batches >= len(x_train) / 32:
# we need to break the loop by hand because
# the generator loops indefinitely
break
+6 -5
Ver Arquivo
@@ -3,7 +3,7 @@
```python
keras.preprocessing.text.text_to_word_sequence(text,
filters=base_filter(), lower=True, split=" ")
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', lower=True, split=" ")
```
Split a sentence into a list of words.
@@ -12,7 +12,7 @@ Split a sentence into a list of words.
- __Arguments__:
- __text__: str.
- __filters__: list (or concatenation) of characters to filter out, such as punctuation. Default: base_filter(), includes basic punctuation, tabs, and newlines.
- __filters__: list (or concatenation) of characters to filter out, such as punctuation. Default: '!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n' , includes basic punctuation, tabs, and newlines.
- __lower__: boolean. Whether to set the text to lowercase.
- __split__: str. Separator for word splitting.
@@ -20,7 +20,7 @@ Split a sentence into a list of words.
```python
keras.preprocessing.text.one_hot(text, n,
filters=base_filter(), lower=True, split=" ")
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', lower=True, split=" ")
```
One-hot encode a text into a list of word indexes in a vocabulary of size n.
@@ -33,14 +33,15 @@ One-hot encode a text into a list of word indexes in a vocabulary of size n.
## Tokenizer
```python
keras.preprocessing.text.Tokenizer(num_words=None, filters=base_filter(),
lower=True, split=" ")
keras.preprocessing.text.Tokenizer(num_words=None, filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True, split=" ", char_level=False)
```
Class for vectorizing texts, or/and turning texts into sequences (=list of word indexes, where the word of rank i in the dataset (starting at 1) has index i).
- __Arguments__: Same as `text_to_word_sequence` above.
- __num_words__: None or int. Maximum number of words to work with (if set, tokenization will be restricted to the top num_words most common words in the dataset).
- __char_level__: if True, every character will be treated as a token.
- __Methods__:
+6 -6
Ver Arquivo
@@ -78,7 +78,7 @@ INVERT = True
# Maximum length of input is 'int + int' (e.g., '345+678'). Maximum length of
# int is DIGITS.
MAxLEN = DIGITS + 1 + DIGITS
MAXLEN = DIGITS + 1 + DIGITS
# All the numbers, plus sign and space for padding.
chars = '0123456789+ '
@@ -98,9 +98,9 @@ while len(questions) < TRAINING_SIZE:
if key in seen:
continue
seen.add(key)
# Pad the data with spaces such that it is always MAxLEN.
# Pad the data with spaces such that it is always MAXLEN.
q = '{}+{}'.format(a, b)
query = q + ' ' * (MAxLEN - len(q))
query = q + ' ' * (MAXLEN - len(q))
ans = str(a + b)
# Answers can be of maximum size DIGITS + 1.
ans += ' ' * (DIGITS + 1 - len(ans))
@@ -113,10 +113,10 @@ while len(questions) < TRAINING_SIZE:
print('Total addition questions:', len(questions))
print('Vectorization...')
x = np.zeros((len(questions), MAxLEN, len(chars)), dtype=np.bool)
x = np.zeros((len(questions), MAXLEN, len(chars)), dtype=np.bool)
y = np.zeros((len(questions), DIGITS + 1, len(chars)), dtype=np.bool)
for i, sentence in enumerate(questions):
x[i] = ctable.encode(sentence, MAxLEN)
x[i] = ctable.encode(sentence, MAXLEN)
for i, sentence in enumerate(expected):
y[i] = ctable.encode(sentence, DIGITS + 1)
@@ -151,7 +151,7 @@ model = Sequential()
# "Encode" the input sequence using an RNN, producing an output of HIDDEN_SIZE.
# Note: In a situation where your input sequences have a variable length,
# use input_shape=(None, num_feature).
model.add(RNN(HIDDEN_SIZE, input_shape=(MAxLEN, len(chars))))
model.add(RNN(HIDDEN_SIZE, input_shape=(MAXLEN, len(chars))))
# As the decoder RNN's input, repeatedly provide with the last hidden state of
# RNN for each time step. Repeat 'DIGITS + 1' times as that's the maximum
# length of output, e.g., when DIGITS=3, max output is 999+999=1998.
+121 -145
Ver Arquivo
@@ -8,24 +8,16 @@ e.g.:
```
python deep_dream.py img/mypic.jpg results/dream
```
It is preferable to run this script on GPU, for speed.
If running on CPU, prefer the TensorFlow backend (much faster).
Example results: http://i.imgur.com/FX6ROg9.jpg
'''
from __future__ import print_function
from keras.preprocessing.image import load_img, img_to_array
import numpy as np
from scipy.misc import imsave
from scipy.optimize import fmin_l_bfgs_b
import time
import scipy
import argparse
from keras.applications import vgg16
from keras.applications import inception_v3
from keras import backend as K
from keras.layers import Input
parser = argparse.ArgumentParser(description='Deep Dreams with Keras.')
parser.add_argument('base_image_path', metavar='base', type=str,
@@ -37,183 +29,167 @@ args = parser.parse_args()
base_image_path = args.base_image_path
result_prefix = args.result_prefix
# dimensions of the generated picture.
img_height = 600
img_width = 600
# some settings we found interesting
saved_settings = {
'bad_trip': {'features': {'block4_conv1': 0.05,
'block4_conv2': 0.01,
'block4_conv3': 0.01},
'continuity': 0.1,
'dream_l2': 0.8,
'jitter': 5},
'dreamy': {'features': {'block5_conv1': 0.05,
'block5_conv2': 0.02},
'continuity': 0.1,
'dream_l2': 0.02,
'jitter': 0},
# These are the names of the layers
# for which we try to maximize activation,
# as well as their weight in the final loss
# we try to maximize.
# You can tweak these setting to obtain new visual effects.
settings = {
'features': {
'mixed2': 0.2,
'mixed3': 0.5,
'mixed4': 2.,
'mixed5': 1.5,
},
}
# the settings we will use in this experiment
settings = saved_settings['dreamy']
def preprocess_image(image_path):
# util function to open, resize and format pictures
# into appropriate tensors
img = load_img(image_path, target_size=(img_height, img_width))
# Util function to open, resize and format pictures
# into appropriate tensors.
img = load_img(image_path)
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = vgg16.preprocess_input(img)
img = inception_v3.preprocess_input(img)
return img
def deprocess_image(x):
# util function to convert a tensor into a valid image
# Util function to convert a tensor into a valid image.
if K.image_data_format() == 'channels_first':
x = x.reshape((3, img_height, img_width))
x = x.reshape((3, x.shape[2], x.shape[3]))
x = x.transpose((1, 2, 0))
else:
x = x.reshape((img_height, img_width, 3))
# Remove zero-center by mean pixel
x[:, :, 0] += 103.939
x[:, :, 1] += 116.779
x[:, :, 2] += 123.68
# 'BGR'->'RGB'
x = x[:, :, ::-1]
x = x.reshape((x.shape[1], x.shape[2], 3))
x /= 2.
x += 0.5
x *= 255.
x = np.clip(x, 0, 255).astype('uint8')
return x
if K.image_data_format() == 'channels_first':
img_size = (3, img_height, img_width)
else:
img_size = (img_height, img_width, 3)
# this will contain our generated image
dream = Input(batch_shape=(1,) + img_size)
K.set_learning_phase(0)
# build the VGG16 network with our placeholder
# the model will be loaded with pre-trained ImageNet weights
model = vgg16.VGG16(input_tensor=dream,
weights='imagenet', include_top=False)
# Build the InceptionV3 network with our placeholder.
# The model will be loaded with pre-trained ImageNet weights.
model = inception_v3.InceptionV3(weights='imagenet',
include_top=False)
dream = model.input
print('Model loaded.')
# get the symbolic outputs of each "key" layer (we gave them unique names).
# 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 continuity_loss(x):
# continuity loss util function
assert K.ndim(x) == 4
if K.image_data_format() == 'channels_first':
a = K.square(x[:, :, :img_height - 1, :img_width - 1] -
x[:, :, 1:, :img_width - 1])
b = K.square(x[:, :, :img_height - 1, :img_width - 1] -
x[:, :, :img_height - 1, 1:])
else:
a = K.square(x[:, :img_height - 1, :img_width - 1, :] -
x[:, 1:, :img_width - 1, :])
b = K.square(x[:, :img_height - 1, :img_width - 1, :] -
x[:, :img_height - 1, 1:, :])
return K.sum(K.pow(a + b, 1.25))
# define the loss
# 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
# 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
# We avoid border artifacts by only involving non-border pixels in the loss.
scaling = K.prod(K.cast(K.shape(x), 'float32'))
if K.image_data_format() == 'channels_first':
loss -= coeff * K.sum(K.square(x[:, :, 2: shape[2] - 2, 2: shape[3] - 2])) / np.prod(shape[1:])
loss += coeff * K.sum(K.square(x[:, :, 2: -2, 2: -2])) / scaling
else:
loss -= coeff * K.sum(K.square(x[:, 2: shape[1] - 2, 2: shape[2] - 2, :])) / np.prod(shape[1:])
loss += coeff * K.sum(K.square(x[:, 2: -2, 2: -2, :])) / scaling
# add continuity loss (gives image local coherence, can result in an artful blur)
loss += settings['continuity'] * continuity_loss(dream) / np.prod(img_size)
# 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)) / np.prod(img_size)
# Compute the gradients of the dream wrt the loss.
grads = K.gradients(loss, dream)[0]
# Normalize gradients.
grads /= K.maximum(K.mean(K.abs(grads)), 1e-7)
# 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 isinstance(grads, (list, tuple)):
outputs += grads
else:
outputs.append(grads)
f_outputs = K.function([dream], outputs)
# Set up function to retrieve the value
# of the loss and gradients given an input image.
outputs = [loss, grads]
fetch_loss_and_grads = K.function([dream], outputs)
def eval_loss_and_grads(x):
x = x.reshape((1,) + img_size)
outs = f_outputs([x])
outs = fetch_loss_and_grads([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')
grad_values = outs[1]
return loss_value, grad_values
class Evaluator(object):
"""Loss and gradients evaluator.
def resize_img(img, size):
img = np.copy(img)
if K.image_data_format() == 'channels_first':
factors = (1, 1,
float(size[0]) / img.shape[2],
float(size[1]) / img.shape[3])
else:
factors = (1,
float(size[0]) / img.shape[1],
float(size[1]) / img.shape[2],
1)
return scipy.ndimage.zoom(img, factors, order=1)
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.
"""
def __init__(self):
self.loss_value = None
self.grad_values = None
def loss(self, x):
assert self.loss_value is None
def gradient_ascent(x, iterations, step, max_loss=None):
for i in range(iterations):
loss_value, grad_values = eval_loss_and_grads(x)
self.loss_value = loss_value
self.grad_values = grad_values
return self.loss_value
if max_loss is not None and loss_value > max_loss:
break
print('..Loss value at', i, ':', loss_value)
x += step * grad_values
return x
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()
def save_img(img, fname):
pil_img = deprocess_image(np.copy(img))
scipy.misc.imsave(fname, pil_img)
# 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(img_size) - 0.5)
x += random_jitter
"""Process:
# 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(img_size)
x -= random_jitter
img = deprocess_image(np.copy(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))
- Load the original image.
- Define a number of processing scales (i.e. image shapes),
from smallest to largest.
- Resize the original image to the smallest scale.
- For every scale, starting with the smallest (i.e. current one):
- Run gradient ascent
- Upscale image to the next scale
- Reinject the detail that was lost at upscaling time
- Stop when we are back to the original size.
To obtain the detail lost during upscaling, we simply
take the original image, shrink it down, upscale it,
and compare the result to the (resized) original image.
"""
# Playing with these hyperparameters will also allow you to achieve new effects
step = 0.01 # Gradient ascent step size
num_octave = 3 # Number of scales at which to run gradient ascent
octave_scale = 1.4 # Size ratio between scales
iterations = 20 # Number of ascent steps per scale
max_loss = 10.
img = preprocess_image(base_image_path)
if K.image_data_format() == 'channels_first':
original_shape = img.shape[2:]
else:
original_shape = img.shape[1:3]
successive_shapes = [original_shape]
for i in range(1, num_octave):
shape = tuple([int(dim / (octave_scale ** i)) for dim in original_shape])
successive_shapes.append(shape)
successive_shapes = successive_shapes[::-1]
original_img = np.copy(img)
shrunk_original_img = resize_img(img, successive_shapes[0])
for shape in successive_shapes:
print('Processing image shape', shape)
img = resize_img(img, shape)
img = gradient_ascent(img,
iterations=iterations,
step=step,
max_loss=max_loss)
upscaled_shrunk_original_img = resize_img(shrunk_original_img, shape)
same_size_original = resize_img(original_img, shape)
lost_detail = same_size_original - upscaled_shrunk_original_img
img += lost_detail
shrunk_original_img = resize_img(original_img, shape)
save_img(img, fname=result_prefix + '.png')
+1 -1
Ver Arquivo
@@ -24,7 +24,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)
+1 -1
Ver Arquivo
@@ -24,7 +24,7 @@ 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))
return K.sqrt(K.maximum(K.sum(K.square(x - y), axis=1, keepdims=True), K.epsilon()))
def eucl_dist_output_shape(shapes):
+3 -2
Ver Arquivo
@@ -196,8 +196,8 @@ x = mask_input
for layer in image_model.layers[1:]:
name = 'mask_%s' % layer.name
if 'conv' in layer.name:
x = AveragePooling2D((3, 3), strides=(
1, 1), name=name, border_mode='same')(x)
x = AveragePooling2D((3, 3), padding='same', strides=(
1, 1), name=name)(x)
elif 'pool' in layer.name:
x = AveragePooling2D((2, 2), name=name)(x)
mask_model = Model(mask_input, x)
@@ -238,6 +238,7 @@ def region_style_loss(style_image, target_image, style_mask, target_mask):
masked_target = K.permute_dimensions(
target_image, (2, 0, 1)) * target_mask
num_channels = K.shape(style_image)[-1]
num_channels = K.cast(num_channels, dtype='float32')
s = gram_matrix(masked_style) / K.mean(style_mask) / num_channels
c = gram_matrix(masked_target) / K.mean(target_mask) / num_channels
return K.mean(K.square(s - c))
+5 -8
Ver Arquivo
@@ -57,7 +57,7 @@ from scipy.optimize import fmin_l_bfgs_b
import time
import argparse
from keras.applications import vgg16
from keras.applications import vgg19
from keras import backend as K
parser = argparse.ArgumentParser(description='Neural style transfer with Keras.')
@@ -99,7 +99,7 @@ def preprocess_image(image_path):
img = load_img(image_path, target_size=(img_nrows, img_ncols))
img = img_to_array(img)
img = np.expand_dims(img, axis=0)
img = vgg16.preprocess_input(img)
img = vgg19.preprocess_input(img)
return img
# util function to convert a tensor into a valid image
@@ -137,7 +137,7 @@ input_tensor = K.concatenate([base_image,
# build the VGG16 network with our 3 images as input
# the model will be loaded with pre-trained ImageNet weights
model = vgg16.VGG16(input_tensor=input_tensor,
model = vgg19.VGG19(input_tensor=input_tensor,
weights='imagenet', include_top=False)
print('Model loaded.')
@@ -199,7 +199,7 @@ def total_variation_loss(x):
# combine these loss functions into a single scalar
loss = K.variable(0.)
layer_features = outputs_dict['block4_conv2']
layer_features = outputs_dict['block5_conv2']
base_image_features = layer_features[0, :, :, :]
combination_features = layer_features[2, :, :, :]
loss += content_weight * content_loss(base_image_features,
@@ -273,10 +273,7 @@ evaluator = Evaluator()
# run scipy-based optimization (L-BFGS) over the pixels of the generated image
# so as to minimize the neural style loss
if K.image_data_format() == 'channels_first':
x = np.random.uniform(0, 255, (1, 3, img_nrows, img_ncols)) - 128.
else:
x = np.random.uniform(0, 255, (1, img_nrows, img_ncols, 3)) - 128.
x = preprocess_image(base_image_path)
for i in range(iterations):
print('Start of iteration', i)
+25 -8
Ver Arquivo
@@ -6,7 +6,7 @@ import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from keras.layers import Input, Dense, Lambda
from keras.layers import Input, Dense, Lambda, Layer
from keras.models import Model
from keras import backend as K
from keras import metrics
@@ -19,6 +19,7 @@ intermediate_dim = 256
epochs = 50
epsilon_std = 1.0
x = Input(batch_shape=(batch_size, original_dim))
h = Dense(intermediate_dim, activation='relu')(x)
z_mean = Dense(latent_dim)(h)
@@ -41,13 +42,29 @@ h_decoded = decoder_h(z)
x_decoded_mean = decoder_mean(h_decoded)
def vae_loss(x, x_decoded_mean):
xent_loss = original_dim * metrics.binary_crossentropy(x, x_decoded_mean)
kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
return xent_loss + kl_loss
# Custom loss layer
class CustomVariationalLayer(Layer):
def __init__(self, **kwargs):
self.is_placeholder = True
super(CustomVariationalLayer, self).__init__(**kwargs)
def vae_loss(self, x, x_decoded_mean):
xent_loss = original_dim * metrics.binary_crossentropy(x, x_decoded_mean)
kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
return K.mean(xent_loss + kl_loss)
def call(self, inputs):
x = inputs[0]
x_decoded_mean = inputs[1]
loss = self.vae_loss(x, x_decoded_mean)
self.add_loss(loss, inputs=inputs)
# We won't actually use the output.
return x
y = CustomVariationalLayer()([x, x_decoded_mean])
vae = Model(x, y)
vae.compile(optimizer='rmsprop', loss=None)
vae = Model(x, x_decoded_mean)
vae.compile(optimizer='rmsprop', loss=vae_loss)
# train the VAE on MNIST digits
(x_train, y_train), (x_test, y_test) = mnist.load_data()
@@ -57,7 +74,7 @@ x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
vae.fit(x_train, x_train,
vae.fit(x_train,
shuffle=True,
epochs=epochs,
batch_size=batch_size,
+26 -12
Ver Arquivo
@@ -7,7 +7,7 @@ import numpy as np
import matplotlib.pyplot as plt
from scipy.stats import norm
from keras.layers import Input, Dense, Lambda, Flatten, Reshape
from keras.layers import Input, Dense, Lambda, Flatten, Reshape, Layer
from keras.layers import Conv2D, Conv2DTranspose
from keras.models import Model
from keras import backend as K
@@ -106,17 +106,31 @@ x_decoded_relu = decoder_deconv_3_upsamp(deconv_2_decoded)
x_decoded_mean_squash = decoder_mean_squash(x_decoded_relu)
def vae_loss(x, x_decoded_mean):
# NOTE: binary_crossentropy expects a batch_size by dim
# for x and x_decoded_mean, so we MUST flatten these!
x = K.flatten(x)
x_decoded_mean = K.flatten(x_decoded_mean)
xent_loss = img_rows * img_cols * metrics.binary_crossentropy(x, x_decoded_mean)
kl_loss = - 0.5 * K.mean(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
return xent_loss + kl_loss
# Custom loss layer
class CustomVariationalLayer(Layer):
def __init__(self, **kwargs):
self.is_placeholder = True
super(CustomVariationalLayer, self).__init__(**kwargs)
vae = Model(x, x_decoded_mean_squash)
vae.compile(optimizer='rmsprop', loss=vae_loss)
def vae_loss(self, x, x_decoded_mean_squash):
x = K.flatten(x)
x_decoded_mean_squash = K.flatten(x_decoded_mean_squash)
xent_loss = img_rows * img_cols * metrics.binary_crossentropy(x, x_decoded_mean_squash)
kl_loss = - 0.5 * K.mean(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
return K.mean(xent_loss + kl_loss)
def call(self, inputs):
x = inputs[0]
x_decoded_mean_squash = inputs[1]
loss = self.vae_loss(x, x_decoded_mean_squash)
self.add_loss(loss, inputs=inputs)
# We don't use this output.
return x
y = CustomVariationalLayer()([x, x_decoded_mean_squash])
vae = Model(x, y)
vae.compile(optimizer='rmsprop', loss=None)
vae.summary()
# train the VAE on MNIST digits
@@ -129,7 +143,7 @@ x_test = x_test.reshape((x_test.shape[0],) + original_img_size)
print('x_train.shape:', x_train.shape)
vae.fit(x_train, x_train,
vae.fit(x_train,
shuffle=True,
epochs=epochs,
batch_size=batch_size,
+3 -1
Ver Arquivo
@@ -17,5 +17,7 @@ from . import models
from . import losses
from . import optimizers
from . import regularizers
# Importable from root because it's technically not a layer
from .layers import Input
__version__ = '2.0.3'
__version__ = '2.0.5'
+9
Ver Arquivo
@@ -1,7 +1,9 @@
from __future__ import absolute_import
import six
import warnings
from . import backend as K
from .utils.generic_utils import deserialize_keras_object
from .engine import Layer
def softmax(x, axis=-1):
@@ -78,6 +80,13 @@ def get(identifier):
identifier = str(identifier)
return deserialize(identifier)
elif callable(identifier):
if isinstance(identifier, Layer):
warnings.warn((
'Do not pass a layer instance (such as {identifier}) as the '
'activation argument of another layer. Instead, advanced '
'activation layers should be used just like any other '
'layer in a model.'
).format(identifier=identifier.__class__.__name__))
return identifier
else:
raise ValueError('Could not interpret '
-3
Ver Arquivo
@@ -27,7 +27,6 @@ from ..layers import AveragePooling2D
from ..layers import GlobalAveragePooling2D
from ..layers import GlobalMaxPooling2D
from ..engine.topology import get_source_inputs
from ..utils.layer_utils import convert_all_kernels_in_model
from ..utils.data_utils import get_file
from .. import backend as K
from .imagenet_utils import decode_predictions
@@ -384,8 +383,6 @@ def InceptionV3(include_top=True,
cache_subdir='models',
md5_hash='bcbd6486424b2319ff4ef7d526e38f63')
model.load_weights(weights_path)
if K.backend() == 'theano':
convert_all_kernels_in_model(model)
return model
+11 -13
Ver Arquivo
@@ -43,7 +43,7 @@ def identity_block(input_tensor, kernel_size, filters, stage, block):
# Arguments
input_tensor: input tensor
kernel_size: defualt 3, the kernel size of middle conv layer at main path
kernel_size: default 3, the kernel size of middle conv layer at main path
filters: list of integers, the filterss of 3 conv layer at main path
stage: integer, current stage label, used for generating layer names
block: 'a','b'..., current block label, used for generating layer names
@@ -81,7 +81,7 @@ def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2))
# Arguments
input_tensor: input tensor
kernel_size: defualt 3, the kernel size of middle conv layer at main path
kernel_size: default 3, the kernel size of middle conv layer at main path
filters: list of integers, the filterss of 3 conv layer at main path
stage: integer, current stage label, used for generating layer names
block: 'a','b'..., current block label, used for generating layer names
@@ -264,21 +264,19 @@ def ResNet50(include_top=True, weights='imagenet',
model.load_weights(weights_path)
if K.backend() == 'theano':
layer_utils.convert_all_kernels_in_model(model)
if K.image_data_format() == 'channels_first':
if include_top:
maxpool = model.get_layer(name='avg_pool')
shape = maxpool.output_shape[1:]
dense = model.get_layer(name='fc1000')
layer_utils.convert_dense_weights_data_format(dense, shape, 'channels_first')
if K.backend() == 'tensorflow':
warnings.warn('You are using the TensorFlow backend, yet you '
'are using the Theano '
'image data format convention '
'(`image_data_format="channels_first"`). '
'For best performance, set '
'`image_data_format="channels_last"` in '
'your Keras config '
'at ~/.keras/keras.json.')
if K.image_data_format() == 'channels_first' and K.backend() == 'tensorflow':
warnings.warn('You are using the TensorFlow backend, yet you '
'are using the Theano '
'image data format convention '
'(`image_data_format="channels_first"`). '
'For best performance, set '
'`image_data_format="channels_last"` in '
'your Keras config '
'at ~/.keras/keras.json.')
return model
+1 -1
Ver Arquivo
@@ -59,7 +59,7 @@ def VGG16(include_top=True, weights='imagenet',
input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape
has to be `(224, 224, 3)` (with `channels_last` data format)
or `(3, 224, 244)` (with `channels_first` data format).
or `(3, 224, 224)` (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 48.
E.g. `(200, 200, 3)` would be one valid value.
+1 -1
Ver Arquivo
@@ -59,7 +59,7 @@ def VGG19(include_top=True, weights='imagenet',
input_shape: optional shape tuple, only to be specified
if `include_top` is False (otherwise the input shape
has to be `(224, 224, 3)` (with `channels_last` data format)
or `(3, 224, 244)` (with `channels_first` data format).
or `(3, 224, 224)` (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 48.
E.g. `(200, 200, 3)` would be one valid value.
+25 -15
Ver Arquivo
@@ -10,7 +10,6 @@ from .common import set_floatx
from .common import cast_to_floatx
from .common import image_data_format
from .common import set_image_data_format
from .common import is_keras_tensor
# Obtain Keras base dir path: either ~/.keras or /tmp.
_keras_base_dir = os.path.expanduser('~')
@@ -33,7 +32,7 @@ if os.path.exists(_config_path):
_epsilon = _config.get('epsilon', epsilon())
assert isinstance(_epsilon, float)
_backend = _config.get('backend', _BACKEND)
assert _backend in {'theano', 'tensorflow'}
assert _backend in {'theano', 'tensorflow', 'cntk'}
_image_data_format = _config.get('image_data_format',
image_data_format())
assert _image_data_format in {'channels_last', 'channels_first'}
@@ -44,28 +43,39 @@ if os.path.exists(_config_path):
_BACKEND = _backend
# Save config file, if possible.
if os.access(_keras_base_dir, os.W_OK):
if not os.path.exists(_keras_dir):
try:
os.makedirs(_keras_dir)
except OSError:
pass
if not os.path.exists(_config_path):
_config = {'floatx': floatx(),
'epsilon': epsilon(),
'backend': _BACKEND,
'image_data_format': image_data_format()}
if not os.path.exists(_keras_dir):
try:
os.makedirs(_keras_dir)
except OSError:
# Except permission denied and potential race conditions
# in multi-threaded environments.
pass
if not os.path.exists(_config_path):
_config = {
'floatx': floatx(),
'epsilon': epsilon(),
'backend': _BACKEND,
'image_data_format': image_data_format()
}
try:
with open(_config_path, 'w') as f:
f.write(json.dumps(_config, indent=4))
except IOError:
# Except permission denied.
pass
# Set backend based on KERAS_BACKEND flag, if applicable.
if 'KERAS_BACKEND' in os.environ:
_backend = os.environ['KERAS_BACKEND']
assert _backend in {'theano', 'tensorflow'}
assert _backend in {'theano', 'tensorflow', 'cntk'}
_BACKEND = _backend
# Import backend functions.
if _BACKEND == 'theano':
if _BACKEND == 'cntk':
sys.stderr.write('Using CNTK backend\n')
from .cntk_backend import *
elif _BACKEND == 'theano':
sys.stderr.write('Using Theano backend.\n')
from .theano_backend import *
elif _BACKEND == 'tensorflow':
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+9 -33
Ver Arquivo
@@ -44,7 +44,7 @@ def set_epsilon(e):
def floatx():
"""Returns the default float type, as a string
"""Returns the default float type, as a string.
(e.g. 'float16', 'float32', 'float64').
# Returns
@@ -109,8 +109,7 @@ def cast_to_floatx(x):
def image_data_format():
"""Returns the default image data format
convention ('channels_first' or 'channels_last').
"""Returns the default image data format convention ('channels_first' or 'channels_last').
# Returns
A string, either `'channels_first'` or `'channels_last'`
@@ -146,42 +145,13 @@ def set_image_data_format(data_format):
_IMAGE_DATA_FORMAT = str(data_format)
def is_keras_tensor(x):
"""Returns whether `x` is a Keras tensor.
# Arguments
x: a potential tensor.
# Returns
A boolean: whether the argument is a Keras tensor.
# Examples
```python
>>> from keras import backend as K
>>> np_var = numpy.array([1, 2])
>>> K.is_keras_tensor(np_var)
False
>>> keras_var = K.variable(np_var)
>>> K.is_keras_tensor(keras_var) # A variable is not a Tensor.
False
>>> keras_placeholder = K.placeholder(shape=(2, 4, 5))
>>> K.is_keras_tensor(keras_placeholder) # A placeholder is a Tensor.
True
```
"""
if hasattr(x, '_keras_shape'):
return True
else:
return False
# Legacy methods
def set_image_dim_ordering(dim_ordering):
"""Legacy setter for `image_data_format`.
# Arguments
dim_ordering: string. `'tf'` or `'th'`.
dim_ordering: string. `tf` or `th`.
# Example
```python
@@ -192,6 +162,9 @@ def set_image_dim_ordering(dim_ordering):
>>> K.image_data_format()
'channels_last'
```
# Raises
ValueError: if `dim_ordering` is invalid.
"""
global _IMAGE_DATA_FORMAT
if dim_ordering not in {'tf', 'th'}:
@@ -205,6 +178,9 @@ def set_image_dim_ordering(dim_ordering):
def image_dim_ordering():
"""Legacy getter for `image_data_format`.
# Returns
string, one of `'th'`, `'tf'`
"""
if _IMAGE_DATA_FORMAT == 'channels_first':
return 'th'
+435 -59
Ver Arquivo
@@ -4,17 +4,20 @@ from tensorflow.python.ops import tensor_array_ops
from tensorflow.python.ops import control_flow_ops
from tensorflow.python.ops import functional_ops
from tensorflow.python.ops import ctc_ops as ctc
from tensorflow.python.ops import variables as tf_variables
from collections import defaultdict
import inspect
import numpy as np
import os
import warnings
from .common import floatx
from .common import _EPSILON
from .common import image_data_format
# Legacy functions
from .common import set_image_dim_ordering, image_dim_ordering
from .common import set_image_dim_ordering
from .common import image_dim_ordering
py_all = all
py_sum = sum
@@ -43,6 +46,14 @@ _MANUAL_VAR_INIT = False
def get_uid(prefix=''):
"""Get the uid for the default graph.
# Arguments
prefix: An optional prefix of the graph.
# Returns
A unique identifier for the graph.
"""
global _GRAPH_UID_DICTS
graph = tf.get_default_graph()
if graph not in _GRAPH_UID_DICTS:
@@ -52,6 +63,7 @@ def get_uid(prefix=''):
def reset_uids():
"""Reset graph identifiers."""
global _GRAPH_UID_DICTS
_GRAPH_UID_DICTS = {}
@@ -169,6 +181,17 @@ def set_session(session):
# VARIABLE MANIPULATION
def _convert_string_dtype(dtype):
"""Get the type from a string.
# Arguments
dtype: A string representation of a type.
# Returns
The type requested.
# Raises
ValueError: if `dtype` is not supported.
"""
if dtype == 'float16':
return tf.float16
if dtype == 'float32':
@@ -190,6 +213,15 @@ def _convert_string_dtype(dtype):
def _to_tensor(x, dtype):
"""Convert the input `x` to a tensor of type `dtype`.
# Arguments
x: An object to be converted (numpy array, list, tensors).
dtype: The destination type.
# Returns
A tensor.
"""
x = tf.convert_to_tensor(x)
if x.dtype != dtype:
x = tf.cast(x, dtype)
@@ -309,11 +341,59 @@ def _initialize_variables():
def constant(value, dtype=None, shape=None, name=None):
"""Creates a constant tensor.
# Arguments
value: A constant value (or list)
dtype: The type of the elements of the resulting tensor.
shape: Optional dimensions of resulting tensor.
name: Optional name for the tensor.
# Returns
A Constant Tensor.
"""
if dtype is None:
dtype = floatx()
return tf.constant(value, dtype=dtype, shape=shape, name=name)
def is_keras_tensor(x):
"""Returns whether `x` is a Keras tensor.
# Arguments
x: a potential tensor.
# Returns
A boolean: whether the argument is a Keras tensor.
# Raises
ValueError: in case `x` is not a symbolic tensor.
# Examples
```python
>>> from keras import backend as K
>>> np_var = numpy.array([1, 2])
>>> K.is_keras_tensor(np_var) # A numpy array is not a symbolic yensor.
ValueError
>>> k_var = tf.placeholder('float32', shape=(1,1))
>>> K.is_keras_tensor(k_var) # A variable created directly from tensorflow/theano is not a Keras tensor.
False
>>> keras_var = K.variable(np_var)
>>> K.is_keras_tensor(keras_var) # A variable created with the keras backend is a Keras tensor.
True
>>> keras_placeholder = K.placeholder(shape=(2, 4, 5))
>>> K.is_keras_tensor(keras_placeholder) # A placeholder is a Keras tensor.
True
```
"""
if not isinstance(x, (tf.Tensor,
tf_variables.Variable,
tf.SparseTensor)):
raise ValueError('Unexpectedly found an instance of type `' + str(type(x)) + '`. '
'Expected a symbolic tensor instance.')
return hasattr(x, '_keras_history')
def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
"""Instantiates a placeholder tensor and returns it.
@@ -626,6 +706,18 @@ def ones_like(x, dtype=None, name=None):
return tf.ones_like(x, dtype=dtype, name=name)
def identity(x):
"""Returns a tensor with the same content as the input tensor.
# Arguments
x: The input tensor.
# Returns
A tensor of the same shape, type and content.
"""
return tf.identity(x)
def random_uniform_variable(shape, low, high, dtype=None,
name=None, seed=None):
"""Instantiates a variable with values drawn from a uniform distribution.
@@ -761,18 +853,54 @@ def cast(x, dtype):
def update(x, new_x):
"""Update the value of `x` to `new_x`.
# Arguments
x: A Variable.
new_x: A tensor of same shape as `x`.
# Returns
The variable `x` updated.
"""
return tf.assign(x, new_x)
def update_add(x, increment):
"""Update the value of `x` by adding `increment`.
# Arguments
x: A Variable.
increment: A tensor of same shape as `x`.
# Returns
The variable `x` updated.
"""
return tf.assign_add(x, increment)
def update_sub(x, decrement):
"""Update the value of `x` by subtracting `decrement`.
# Arguments
x: A Variable.
decrement: A tensor of same shape as `x`.
# Returns
The variable `x` updated.
"""
return tf.assign_sub(x, decrement)
def moving_average_update(x, value, momentum):
"""Compute the moving average of a variable.
# Arguments
x: A Variable.
value: A tensor with the same shape as `variable`.
momentum: The moving average momentum.
# Returns
An Operation to update the variable."""
return moving_averages.assign_moving_average(
x, value, momentum, zero_debias=False)
@@ -902,6 +1030,16 @@ def batch_dot(x, y, axes=None):
"""
if isinstance(axes, int):
axes = (axes, axes)
x_ndim = ndim(x)
y_ndim = ndim(y)
if x_ndim > y_ndim:
diff = x_ndim - y_ndim
y = tf.reshape(y, tf.concat([tf.shape(y), [1] * (diff)], axis=0))
elif y_ndim > x_ndim:
diff = y_ndim - x_ndim
x = tf.reshape(x, tf.concat([tf.shape(x), [1] * (diff)], axis=0))
else:
diff = 0
if ndim(x) == 2 and ndim(y) == 2:
if axes[0] == axes[1]:
out = tf.reduce_sum(tf.multiply(x, y), axes[0])
@@ -915,6 +1053,12 @@ def batch_dot(x, y, axes=None):
adj_x = None
adj_y = None
out = tf.matmul(x, y, adjoint_a=adj_x, adjoint_b=adj_y)
if diff:
if x_ndim > y_ndim:
idx = x_ndim + y_ndim - 3
else:
idx = x_ndim - 1
out = tf.squeeze(out, list(range(idx, idx + diff)))
if ndim(out) == 1:
out = expand_dims(out, 1)
return out
@@ -1276,6 +1420,28 @@ def log(x):
return tf.log(x)
def logsumexp(x, axis=None, keepdims=False):
"""Computes log(sum(exp(elements across dimensions of a tensor))).
This function is more numerically stable than log(sum(exp(x))).
It avoids overflows caused by taking the exp of large inputs and
underflows caused by taking the log of small inputs.
# Arguments
x: A tensor or variable.
axis: An integer, the axis to reduce over.
keepdims: A boolean, whether to keep the dimensions or not.
If `keepdims` is `False`, the rank of the tensor is reduced
by 1. If `keepdims` is `True`, the reduced dimension is
retained with length 1.
# Returns
The reduced tensor.
"""
axis = _normalize_axis(axis, ndim(x))
return tf.reduce_logsumexp(x, axis=axis, keep_dims=keepdims)
def round(x):
"""Element-wise rounding to the closest integer.
@@ -1589,14 +1755,13 @@ def resize_images(x, height_factor, width_factor, data_format):
x: Tensor or variable to resize.
height_factor: Positive integer.
width_factor: Positive integer.
data_format: One of `"channels_first"`, `"channels_last"`.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
# Raises
ValueError: if `data_format` is neither
`channels_last` or `channels_first`.
ValueError: if `data_format` is neither `"channels_last"` or `"channels_first"`.
"""
if data_format == 'channels_first':
original_shape = int_shape(x)
@@ -1628,14 +1793,13 @@ def resize_volumes(x, depth_factor, height_factor, width_factor, data_format):
depth_factor: Positive integer.
height_factor: Positive integer.
width_factor: Positive integer.
data_format: One of `"channels_first"`, `"channels_last"`.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
# Raises
ValueError: if `data_format` is neither
`channels_last` or `channels_first`.
ValueError: if `data_format` is neither `"channels_last"` or `"channels_first"`.
"""
if data_format == 'channels_first':
output = repeat_elements(x, depth_factor, axis=2)
@@ -1774,14 +1938,14 @@ def batch_flatten(x):
def expand_dims(x, axis=-1):
"""Adds a 1-sized dimension at index "dim".
"""Adds a 1-sized dimension at index "axis".
# Arguments
x: A tensor or variable.
axis: Position where to add a new axis.
# Returns
A tensor with expended dimensions.
A tensor with expanded dimensions.
"""
return tf.expand_dims(x, axis)
@@ -1821,14 +1985,13 @@ def spatial_2d_padding(x, padding=((1, 1), (1, 1)), data_format=None):
# Arguments
x: Tensor or variable.
padding: Tuple of 2 tuples, padding pattern.
data_format: One of `channels_last` or `channels_first`.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A padded 4D tensor.
# Raises
ValueError: if `data_format` is neither
`channels_last` or `channels_first`.
ValueError: if `data_format` is neither `"channels_last"` or `"channels_first"`.
"""
assert len(padding) == 2
assert len(padding[0]) == 2
@@ -1864,14 +2027,13 @@ def spatial_3d_padding(x, padding=((1, 1), (1, 1), (1, 1)), data_format=None):
# Arguments
x: Tensor or variable.
padding: Tuple of 3 tuples, padding pattern.
data_format: One of `channels_last` or `channels_first`.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A padded 5D tensor.
# Raises
ValueError: if `data_format` is neither
`channels_last` or `channels_first`.
ValueError: if `data_format` is neither `"channels_last"` or `"channels_first"`.
"""
assert len(padding) == 3
@@ -2061,9 +2223,10 @@ class Function(object):
inputs: Feed placeholders to the computation graph.
outputs: Output tensors to fetch.
updates: Additional update ops to be run at function call.
name: a name to help users identify what this function does.
"""
def __init__(self, inputs, outputs, updates=None):
def __init__(self, inputs, outputs, updates=None, name=None, **session_kwargs):
updates = updates or []
if not isinstance(inputs, (list, tuple)):
raise TypeError('`inputs` to a TensorFlow backend function '
@@ -2086,6 +2249,8 @@ class Function(object):
# assumed already an op
updates_ops.append(update)
self.updates_op = tf.group(*updates_ops)
self.name = name
self.session_kwargs = session_kwargs
def __call__(self, inputs):
if not isinstance(inputs, (list, tuple)):
@@ -2100,7 +2265,8 @@ class Function(object):
feed_dict[tensor] = value
session = get_session()
updated = session.run(self.outputs + [self.updates_op],
feed_dict=feed_dict)
feed_dict=feed_dict,
**self.session_kwargs)
return updated[:len(self.outputs)]
@@ -2111,18 +2277,21 @@ def function(inputs, outputs, updates=None, **kwargs):
inputs: List of placeholder tensors.
outputs: List of output tensors.
updates: List of update ops.
**kwargs: Not used with TensorFlow.
**kwargs: Passed to `tf.Session.run`.
# Returns
Output values as Numpy arrays.
# Raises
ValueError: if invalid kwargs are passed in.
"""
if kwargs:
msg = [
'Expected no kwargs, you passed %s' % len(kwargs),
'kwargs passed to function are ignored with Tensorflow backend'
]
warnings.warn('\n'.join(msg))
return Function(inputs, outputs, updates=updates)
for key in kwargs:
if (key not in inspect.getargspec(tf.Session.run)[0] and
key not in inspect.getargspec(Function.__init__)[0]):
msg = 'Invalid argument "%s" passed to K.function with Tensorflow backend' % key
raise ValueError(msg)
return Function(inputs, outputs, updates=updates, **kwargs)
def gradients(loss, variables):
@@ -2600,7 +2769,7 @@ def sparse_categorical_crossentropy(output, target, from_logits=False):
# Returns
Output tensor.
"""
# Note: tf.nn.softmax_cross_entropy_with_logits
# Note: tf.nn.sparse_softmax_cross_entropy_with_logits
# expects logits, Keras expects probabilities.
if not from_logits:
epsilon = _to_tensor(_EPSILON, output.dtype.base_dtype)
@@ -2633,7 +2802,7 @@ def binary_crossentropy(output, target, from_logits=False):
# Returns
A tensor.
"""
# Note: tf.nn.softmax_cross_entropy_with_logits
# Note: tf.nn.sigmoid_cross_entropy_with_logits
# expects logits, Keras expects probabilities.
if not from_logits:
# transform back to logits
@@ -2707,7 +2876,7 @@ def dropout(x, level, noise_shape=None, seed=None):
if seed is None:
seed = np.random.randint(10e6)
# the dummy 1. works around a TF bug
# (float32_ref vs. float32 incomptability)
# (float32_ref vs. float32 incompatibility)
return tf.nn.dropout(x * 1., retain_prob, noise_shape, seed=seed)
@@ -2745,6 +2914,16 @@ def in_top_k(predictions, targets, k):
# CONVOLUTIONS
def _preprocess_deconv_output_shape(x, shape, data_format):
"""Get the output_shape for the deconvolution.
# Arguments
x: input tensor.
shape: output shape.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
The output shape.
"""
if data_format == 'channels_first':
shape = (shape[0], shape[2], shape[3], shape[1])
@@ -2755,6 +2934,15 @@ def _preprocess_deconv_output_shape(x, shape, data_format):
def _preprocess_conv2d_input(x, data_format):
"""Transpose and cast the input before the conv2d.
# Arguments
x: input tensor.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
"""
if dtype(x) == 'float64':
x = tf.cast(x, 'float32')
if data_format == 'channels_first':
@@ -2767,6 +2955,15 @@ def _preprocess_conv2d_input(x, data_format):
def _preprocess_conv3d_input(x, data_format):
"""Transpose and cast the input before the conv3d.
# Arguments
x: input tensor.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
"""
if dtype(x) == 'float64':
x = tf.cast(x, 'float32')
if data_format == 'channels_first':
@@ -2775,6 +2972,15 @@ def _preprocess_conv3d_input(x, data_format):
def _preprocess_conv2d_kernel(kernel, data_format):
"""Transpose and cast the kernel before the conv2d.
# Arguments
kernel: kernel tensor.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
"""
if dtype(kernel) == 'float64':
kernel = tf.cast(kernel, 'float32')
if data_format == 'channels_first':
@@ -2783,6 +2989,15 @@ def _preprocess_conv2d_kernel(kernel, data_format):
def _preprocess_conv3d_kernel(kernel, data_format):
"""Transpose and cast the kernel before the conv3d.
# Arguments
kernel: kernel tensor.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
"""
if dtype(kernel) == 'float64':
kernel = tf.cast(kernel, 'float32')
if data_format == 'channels_first':
@@ -2791,16 +3006,37 @@ def _preprocess_conv3d_kernel(kernel, data_format):
def _preprocess_padding(padding):
"""Convert keras' padding to tensorflow's padding.
# Arguments
padding: string, `"same"` or `"valid"`.
# Returns
a string, `"SAME"` or `"VALID"`.
# Raises
ValueError: if `padding` is invalid.
"""
if padding == 'same':
padding = 'SAME'
elif padding == 'valid':
padding = 'VALID'
else:
raise ValueError('Invalid border mode:', padding)
raise ValueError('Invalid padding:', padding)
return padding
def _postprocess_conv2d_output(x, data_format):
"""Transpose and cast the output from conv2d if needed.
# Arguments
x: A tensor.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
"""
if data_format == 'channels_first':
x = tf.transpose(x, (0, 3, 1, 2))
@@ -2810,6 +3046,15 @@ def _postprocess_conv2d_output(x, data_format):
def _postprocess_conv3d_output(x, data_format):
"""Transpose and cast the output from conv3d if needed.
# Arguments
x: A tensor.
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
A tensor.
"""
if data_format == 'channels_first':
x = tf.transpose(x, (0, 4, 1, 2, 3))
@@ -2827,7 +3072,7 @@ def conv1d(x, kernel, strides=1, padding='valid',
kernel: kernel tensor.
strides: stride integer.
padding: string, `"same"`, `"causal"` or `"valid"`.
data_format: string, one of "channels_last", "channels_first".
data_format: string, `"channels_last"` or `"channels_first"`.
dilation_rate: integer dilate rate.
# Returns
@@ -2863,9 +3108,9 @@ def conv2d(x, kernel, strides=(1, 1), padding='valid',
kernel: kernel tensor.
strides: strides tuple.
padding: string, `"same"` or `"valid"`.
data_format: `"channels_last"` or `"channels_first"`.
data_format: string, `"channels_last"` or `"channels_first"`.
Whether to use Theano or TensorFlow data format
for inputs/kernels/ouputs.
for inputs/kernels/outputs.
dilation_rate: tuple of 2 integers.
# Returns
@@ -2904,9 +3149,9 @@ def conv2d_transpose(x, kernel, output_shape, strides=(1, 1),
output_shape: 1D int tensor for the output shape.
strides: strides tuple.
padding: string, `"same"` or `"valid"`.
data_format: `"channels_last"` or `"channels_first"`.
data_format: string, `"channels_last"` or `"channels_first"`.
Whether to use Theano or TensorFlow data format
for inputs/kernels/ouputs.
for inputs/kernels/outputs.
# Returns
A tensor, result of transposed 2D convolution.
@@ -2941,8 +3186,8 @@ def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
depthwise_kernel: convolution kernel for the depthwise convolution.
pointwise_kernel: kernel for the 1x1 convolution.
strides: strides tuple (length 2).
padding: padding mode, "valid" or "same".
data_format: data format, "channels_first" or "channels_last".
padding: string, `"same"` or `"valid"`.
data_format: string, `"channels_last"` or `"channels_first"`.
dilation_rate: tuple of integers,
dilation rates for the separable convolution.
@@ -2977,9 +3222,9 @@ def conv3d(x, kernel, strides=(1, 1, 1), padding='valid',
kernel: kernel tensor.
strides: strides tuple.
padding: string, `"same"` or `"valid"`.
data_format: `"channels_last"` or `"channels_first"`.
data_format: string, `"channels_last"` or `"channels_first"`.
Whether to use Theano or TensorFlow data format
for inputs/kernels/ouputs.
for inputs/kernels/outputs.
dilation_rate: tuple of 3 integers.
# Returns
@@ -3017,16 +3262,16 @@ def pool2d(x, pool_size, strides=(1, 1),
x: Tensor or variable.
pool_size: tuple of 2 integers.
strides: tuple of 2 integers.
padding: one of `"valid"`, `"same"`.
data_format: one of `"channels_first"`, `"channels_last"`.
pool_mode: one of `"max"`, `"avg"`.
padding: string, `"same"` or `"valid"`.
data_format: string, `"channels_last"` or `"channels_first"`.
pool_mode: string, `"max"` or `"avg"`.
# Returns
A tensor, result of 2D pooling.
# Raises
ValueError: if `data_format` is neither `channels_last` or `channels_first`.
ValueError: if `pool_mode` is neither `max` or `avg`.
ValueError: if `data_format` is neither `"channels_last"` or `"channels_first"`.
ValueError: if `pool_mode` is neither `"max"` or `"avg"`.
"""
if data_format is None:
data_format = image_data_format()
@@ -3057,17 +3302,16 @@ def pool3d(x, pool_size, strides=(1, 1, 1), padding='valid',
x: Tensor or variable.
pool_size: tuple of 3 integers.
strides: tuple of 3 integers.
padding: one of `"valid"`, `"same"`.
data_format: one of `"channels_first"`, `"channels_last"`.
pool_mode: one of `"max"`, `"avg"`.
padding: string, `"same"` or `"valid"`.
data_format: string, `"channels_last"` or `"channels_first"`.
pool_mode: string, `"max"` or `"avg"`.
# Returns
A tensor, result of 3D pooling.
# Raises
ValueError: if `data_format` is neither
`channels_last` or `channels_first`.
ValueError: if `pool_mode` is neither `max` or `avg`.
ValueError: if `data_format` is neither `"channels_last"` or `"channels_first"`.
ValueError: if `pool_mode` is neither `"max"` or `"avg"`.
"""
if data_format is None:
data_format = image_data_format()
@@ -3096,35 +3340,60 @@ def bias_add(x, bias, data_format=None):
# Arguments
x: Tensor or variable.
bias: Bias tensor to add.
data_format: Data format for 3D, 4D or 5D tensors:
one of "channels_first", "channels_last".
data_format: string, `"channels_last"` or `"channels_first"`.
# Returns
Output tensor.
# Raises
ValueError: In case of invalid `data_format` argument.
ValueError: In one of the two cases below:
1. invalid `data_format` argument.
2. invalid bias shape.
the bias should be either a vector or
a tensor with ndim(x) - 1 dimension
"""
if data_format is None:
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + str(data_format))
bias_shape = int_shape(bias)
if len(bias_shape) != 1 and len(bias_shape) != ndim(x) - 1:
raise ValueError('Unexpected bias dimensions %d, expect to be 1 or %d dimensions'
% (len(bias_shape), ndim(x)))
if ndim(x) == 5:
if data_format == 'channels_first':
x += reshape(bias, (1, int_shape(bias)[0], 1, 1, 1))
if len(bias_shape) == 1:
x += reshape(bias, (1, bias_shape[0], 1, 1, 1))
else:
x += reshape(bias, (1, bias_shape[3]) + bias_shape[:3])
elif data_format == 'channels_last':
x += reshape(bias, (1, 1, 1, 1, int_shape(bias)[0]))
if len(bias_shape) == 1:
x += reshape(bias, (1, 1, 1, bias_shape[0]))
else:
x += reshape(bias, (1,) + bias_shape)
elif ndim(x) == 4:
if data_format == 'channels_first':
x += reshape(bias, (1, int_shape(bias)[0], 1, 1))
if len(bias_shape) == 1:
x += reshape(bias, (1, bias_shape[0], 1, 1))
else:
x += reshape(bias, (1, bias_shape[2]) + bias_shape[:2])
elif data_format == 'channels_last':
x = tf.nn.bias_add(x, bias,
data_format='NHWC')
if len(bias_shape) == 1:
x = tf.nn.bias_add(x, bias,
data_format='NHWC')
else:
x += reshape(bias, (1,) + bias_shape)
elif ndim(x) == 3:
if data_format == 'channels_first':
x += reshape(bias, (1, int_shape(bias)[0], 1))
if len(bias_shape) == 1:
x += reshape(bias, (1, bias_shape[0], 1))
else:
x += reshape(bias, (1, bias_shape[1], bias_shape[0]))
elif data_format == 'channels_last':
x += reshape(bias, (1, 1, int_shape(bias)[0]))
if len(bias_shape) == 1:
x += reshape(bias, (1, 1, bias_shape[0]))
else:
x += reshape(bias, (1, ) + bias_shape)
else:
x = tf.nn.bias_add(x, bias)
return x
@@ -3389,3 +3658,110 @@ def foldr(fn, elems, initializer=None, name=None):
Same type and shape as initializer
"""
return tf.foldr(fn, elems, initializer=initializer, name=name)
def local_conv1d(inputs, kernel, kernel_size, strides, data_format=None):
"""Apply 1D conv with un-shared weights.
# Arguments
inputs: 3D tensor with shape: (batch_size, steps, input_dim)
kernel: the unshared weight for convolution,
with shape (output_length, feature_dim, filters)
kernel_size: a tuple of a single integer,
specifying the length of the 1D convolution window
strides: a tuple of a single integer,
specifying the stride length of the convolution
data_format: the data format, channels_first or channels_last
# Returns
the tensor after 1d conv with un-shared weights, with shape (batch_size, output_lenght, filters)
# Raises
ValueError: if `data_format` is neither `channels_last` or `channels_first`.
"""
if data_format is None:
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + str(data_format))
stride = strides[0]
kernel_shape = int_shape(kernel)
output_length, feature_dim, filters = kernel_shape
xs = []
for i in range(output_length):
slice_length = slice(i * stride,
i * stride + kernel_size[0])
xs.append(reshape(inputs[:, slice_length, :],
(1, -1, feature_dim)))
x_aggregate = concatenate(xs, axis=0)
# Shape: `(output_length, batch_size, filters)`.
output = batch_dot(x_aggregate, kernel)
return permute_dimensions(output, (1, 0, 2))
def local_conv2d(inputs, kernel, kernel_size, strides, output_shape, data_format=None):
"""Apply 2D conv with un-shared weights.
# Arguments
inputs: 4D tensor with shape:
(batch_size, filters, new_rows, new_cols)
if data_format='channels_first'
or 4D tensor with shape:
(batch_size, new_rows, new_cols, filters)
if data_format='channels_last'.
kernel: the unshared weight for convolution,
with shape (output_items, feature_dim, filters)
kernel_size: a tuple of 2 integers, specifying the
width and height of the 2D convolution window.
strides: a tuple of 2 integers, specifying the strides
of the convolution along the width and height.
output_shape: a tuple with (output_row, output_col)
data_format: the data format, channels_first or channels_last
# Returns
A 4d tensor with shape:
(batch_size, filters, new_rows, new_cols)
if data_format='channels_first'
or 4D tensor with shape:
(batch_size, new_rows, new_cols, filters)
if data_format='channels_last'.
# Raises
ValueError: if `data_format` is neither
`channels_last` or `channels_first`.
"""
if data_format is None:
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + str(data_format))
stride_row, stride_col = strides
output_row, output_col = output_shape
kernel_shape = int_shape(kernel)
_, feature_dim, filters = kernel_shape
xs = []
for i in range(output_row):
for j in range(output_col):
slice_row = slice(i * stride_row,
i * stride_row + kernel_size[0])
slice_col = slice(j * stride_col,
j * stride_col + kernel_size[1])
if data_format == 'channels_first':
xs.append(reshape(inputs[:, :, slice_row, slice_col],
(1, -1, feature_dim)))
else:
xs.append(reshape(inputs[:, slice_row, slice_col, :],
(1, -1, feature_dim)))
x_aggregate = concatenate(xs, axis=0)
output = batch_dot(x_aggregate, kernel)
output = reshape(output,
(output_row, output_col, -1, filters))
if data_format == 'channels_first':
output = permute_dimensions(output, (2, 3, 0, 1))
else:
output = permute_dimensions(output, (2, 0, 1, 3))
return output
+194 -14
Ver Arquivo
@@ -1,6 +1,7 @@
from collections import defaultdict
from contextlib import contextmanager
import theano
from theano import ifelse
from theano import tensor as T
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
from theano.tensor.signal import pool
@@ -163,6 +164,42 @@ def constant(value, dtype=None, shape=None, name=None):
return const
def is_keras_tensor(x):
"""Returns whether `x` is a Keras tensor.
# Arguments
x: a potential tensor.
# Returns
A boolean: whether the argument is a Keras tensor.
# Raises
ValueError: in case `x` is not a symbolic tensor.
# Examples
```python
>>> from keras import backend as K
>>> np_var = numpy.array([1, 2])
>>> K.is_keras_tensor(np_var) # A numpy array is not a symbolic tensor.
ValueError
>>> k_var = theano.shared(value=np.array([1,2,3]))
>>> K.is_keras_tensor(k_var) # A variable created directly from tensorflow/theano is not a Keras tensor.
False
>>> keras_var = K.variable(np_var)
>>> K.is_keras_tensor(keras_var) # A variable created with the keras backend is a Keras tensor.
True
>>> keras_placeholder = K.placeholder(shape=(2, 4, 5))
>>> K.is_keras_tensor(keras_placeholder) # A placeholder is a Keras tensor.
True
```
"""
if not isinstance(x, (T.TensorVariable,
T.sharedvar.TensorSharedVariable)):
raise ValueError('Unexpectedly found an instance of type `' + str(type(x)) + '`. '
'Expected a symbolic tensor instance.')
return hasattr(x, '_keras_history')
def placeholder(shape=None, ndim=None, dtype=None, sparse=False, name=None):
"""Instantiate an input data placeholder variable.
"""
@@ -258,6 +295,18 @@ def zeros_like(x, dtype=None, name=None):
return T.zeros_like(x, dtype=dtype)
def identity(x):
"""Returns a tensor with the same content as the input tensor.
# Arguments
x: The input tensor.
# Returns
A tensor of the same shape, type and content.
"""
return x.copy()
def random_uniform_variable(shape, low, high, dtype=None, name=None):
return variable(np.random.uniform(low=low, high=high, size=shape),
dtype=dtype, name=name)
@@ -515,6 +564,29 @@ def log(x):
return T.log(x)
def logsumexp(x, axis=None, keepdims=False):
"""Computes log(sum(exp(elements across dimensions of a tensor))).
This function is more numerically stable than log(sum(exp(x))).
It avoids overflows caused by taking the exp of large inputs and
underflows caused by taking the log of small inputs.
# Arguments
x: A tensor or variable.
axis: An integer, the axis to reduce over.
keepdims: A boolean, whether to keep the dimensions or not.
If `keepdims` is `False`, the rank of the tensor is reduced
by 1. If `keepdims` is `True`, the reduced dimension is
retained with length 1.
# Returns
The reduced tensor.
"""
# Theano has a built-in optimization for logsumexp (see https://github.com/Theano/Theano/pull/4736)
# so we can just write the expression directly:
return T.log(T.sum(T.exp(x), axis=axis, keepdims=keepdims))
def round(x):
return T.round(x, mode='half_to_even')
@@ -1106,7 +1178,7 @@ def print_tensor(x, message=''):
class Function(object):
def __init__(self, inputs, outputs, updates=[], **kwargs):
def __init__(self, inputs, outputs, updates=[], name=None, **kwargs):
unique_variables_to_update = {}
for v, nv in updates:
if v not in unique_variables_to_update:
@@ -1115,7 +1187,9 @@ class Function(object):
self.function = theano.function(inputs, outputs, updates=updates,
allow_input_downcast=True,
on_unused_input='ignore',
name=name,
**kwargs)
self.name = name
def __call__(self, inputs):
assert isinstance(inputs, (list, tuple))
@@ -1127,7 +1201,7 @@ def function(inputs, outputs, updates=[], **kwargs):
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
msg = 'Invalid argument "%s" passed to K.function with Theano backend' % key
raise ValueError(msg)
return Function(inputs, outputs, updates=updates, **kwargs)
@@ -1488,8 +1562,9 @@ def dropout(x, level, noise_shape=None, seed=None):
return x
def l2_normalize(x, axis):
norm = T.sqrt(T.sum(T.square(x), axis=axis, keepdims=True))
def l2_normalize(x, axis, epsilon=1e-12):
square_sum = T.sum(T.square(x), axis=axis, keepdims=True)
norm = T.sqrt(T.maximum(square_sum, epsilon))
return x / norm
@@ -1739,7 +1814,7 @@ def conv2d(x, kernel, strides=(1, 1), padding='valid',
padding: string, "same" or "valid".
data_format: "channels_last" or "channels_first".
Whether to use Theano or TensorFlow data format
in inputs/kernels/ouputs.
in inputs/kernels/outputs.
"""
if data_format is None:
data_format = image_data_format()
@@ -1783,7 +1858,10 @@ def conv2d_transpose(x, kernel, output_shape, strides=(1, 1),
padding: string, "same" or "valid".
data_format: "channels_last" or "channels_first".
Whether to use Theano or TensorFlow data format
in inputs/kernels/ouputs.
in inputs/kernels/outputs.
# Raises
ValueError: if using an even kernel size with padding 'same'.
"""
flip_filters = False
if data_format is None:
@@ -1802,6 +1880,12 @@ def conv2d_transpose(x, kernel, output_shape, strides=(1, 1),
else:
# Will only work if `kernel` is a shared variable.
kernel_shape = kernel.eval().shape
if padding == 'same' and kernel_shape[0] % 2 == 0:
raise ValueError('In `Conv2DTranspose`, with padding mode `same`, '
'even kernel sizes are only supported with Tensorflow. '
'With Theano, set `kernel_size` to an odd number.')
kernel_shape = _preprocess_conv2d_filter_shape(kernel_shape, data_format)
x = _preprocess_conv2d_input(x, data_format)
@@ -1835,7 +1919,7 @@ def conv3d(x, kernel, strides=(1, 1, 1),
padding: string, "same" or "valid".
data_format: "channels_last" or "channels_first".
Whether to use Theano or TensorFlow data format
in inputs/kernels/ouputs.
in inputs/kernels/outputs.
"""
if data_format is None:
data_format = image_data_format()
@@ -1898,10 +1982,14 @@ def pool2d(x, pool_size, strides=(1, 1), padding='valid',
pad=pad,
mode='max')
elif pool_mode == 'avg':
if padding == 'same':
th_avg_pool_mode = 'average_inc_pad'
elif padding == 'valid':
th_avg_pool_mode = 'average_exc_pad'
pool_out = pool.pool_2d(x, ws=pool_size, stride=strides,
ignore_border=True,
pad=pad,
mode='average_exc_pad')
mode=th_avg_pool_mode)
else:
raise ValueError('Invalid pooling mode:', pool_mode)
if padding == 'same':
@@ -1971,21 +2059,44 @@ def bias_add(x, bias, data_format=None):
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + str(data_format))
if ndim(bias) != 1 and ndim(bias) != ndim(x) - 1:
raise ValueError('Unexpected bias dimensions %d, '
'expect to be 1 or %d dimensions'
% (ndim(bias), ndim(x) - 1))
bias_shape = tuple(bias.shape)
if ndim(x) == 5:
if data_format == 'channels_first':
x += reshape(bias, (1, bias.shape[0], 1, 1, 1))
if ndim(bias) == 1:
x += reshape(bias, (1, bias_shape[0], 1, 1, 1))
else:
x += reshape(bias, (1, bias_shape[3]) + bias_shape[:3])
elif data_format == 'channels_last':
x += reshape(bias, (1, 1, 1, 1, bias.shape[0]))
if ndim(bias) == 1:
x += reshape(bias, (1, 1, 1, 1, bias_shape[0]))
else:
x += reshape(bias, (1,) + bias_shape)
elif ndim(x) == 4:
if data_format == 'channels_first':
x += reshape(bias, (1, bias.shape[0], 1, 1))
if ndim(bias) == 1:
x += reshape(bias, (1, bias_shape[0], 1, 1))
else:
x += reshape(bias, (1, bias_shape[2]) + bias_shape[:2])
elif data_format == 'channels_last':
x += reshape(bias, (1, 1, 1, bias.shape[0]))
if ndim(bias) == 1:
x += reshape(bias, (1, 1, 1, bias_shape[0]))
else:
x += reshape(bias, (1,) + bias_shape)
elif ndim(x) == 3:
if data_format == 'channels_first':
x += reshape(bias, (1, bias.shape[0], 1))
if ndim(bias) == 1:
x += reshape(bias, (1, bias_shape[0], 1))
else:
x += reshape(bias, (1, bias_shape[1], bias_shape[0]))
elif data_format == 'channels_last':
x += reshape(bias, (1, 1, bias.shape[0]))
if ndim(bias) == 1:
x += reshape(bias, (1, 1, bias_shape[0]))
else:
x += reshape(bias, (1,) + bias_shape)
else:
x += bias
return x
@@ -2203,3 +2314,72 @@ def foldr(fn, elems, initializer=None, name=None):
fn2 = lambda x, acc: fn(acc, x)
return theano.foldr(fn2, elems, initializer, name=name)[0]
def local_conv1d(inputs, kernel, kernel_size, strides, data_format=None):
if data_format is None:
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + str(data_format))
stride = strides[0]
kernel_shape = int_shape(kernel)
output_length, feature_dim, filters = kernel_shape
xs = []
for i in range(output_length):
slice_length = slice(i * stride,
i * stride + kernel_size[0])
xs.append(reshape(inputs[:, slice_length, :],
(1, -1, feature_dim)))
x_aggregate = concatenate(xs, axis=0)
# Shape: `(output_length, batch_size, filters)`.
output = batch_dot(x_aggregate, kernel)
return permute_dimensions(output, (1, 0, 2))
def local_conv2d(inputs, kernel, kernel_size, strides, output_shape, data_format=None):
if data_format is None:
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + str(data_format))
stride_row, stride_col = strides
output_row, output_col = output_shape
kernel_shape = int_shape(kernel)
_, feature_dim, filters = kernel_shape
if data_format == 'channels_first':
output = []
for i in range(output_row):
for j in range(output_col):
slice_row = slice(i * stride_row,
i * stride_row + kernel_size[0])
slice_col = slice(j * stride_col,
j * stride_col + kernel_size[1])
x_flatten = reshape(inputs[:, :, slice_row, slice_col],
(1, -1, feature_dim))
output.append(dot(x_flatten,
kernel[i * output_col + j, :, :]))
output = concatenate(output, axis=0)
output = reshape(output,
(output_row, output_col, -1, filters))
output = permute_dimensions(output, (2, 3, 0, 1))
else:
xs = []
for i in range(output_row):
for j in range(output_col):
slice_row = slice(i * stride_row,
i * stride_row + kernel_size[0])
slice_col = slice(j * stride_col,
j * stride_col + kernel_size[1])
xs.append(reshape(inputs[:, slice_row, slice_col, :],
(1, -1, feature_dim)))
x_aggregate = concatenate(xs, axis=0)
output = batch_dot(x_aggregate, kernel)
output = reshape(output,
(output_row, output_col, -1, filters))
output = permute_dimensions(output, (2, 0, 1, 3))
return output
+115 -46
Ver Arquivo
@@ -3,6 +3,7 @@ from __future__ import print_function
import os
import csv
import six
import numpy as np
import time
@@ -226,6 +227,21 @@ class BaseLogger(Callback):
logs[k] = self.totals[k] / self.seen
class TerminateOnNaN(Callback):
"""Callback that terminates training when a NaN loss is encountered."""
def __init__(self):
super(TerminateOnNaN, self).__init__()
def on_batch_end(self, batch, logs=None):
logs = logs or {}
loss = logs.get('loss')
if loss is not None:
if np.isnan(loss) or np.isinf(loss):
print('Batch %d: Invalid loss, terminating training' % (batch))
self.model.stop_training = True
class ProgbarLogger(Callback):
"""Callback that prints metrics to stdout.
@@ -466,7 +482,9 @@ class EarlyStopping(Callback):
self.min_delta *= -1
def on_train_begin(self, logs=None):
self.wait = 0 # Allow instances to be re-used
# Allow instances to be re-used
self.wait = 0
self.stopped_epoch = 0
self.best = np.Inf if self.monitor_op == np.less else -np.Inf
def on_epoch_end(self, epoch, logs=None):
@@ -503,8 +521,7 @@ class RemoteMonitor(Callback):
field: String; JSON field under which the data will be stored.
headers: Dictionary; optional custom HTTP headers.
Defaults to:
`{'Accept': 'application/json',
'Content-Type': 'application/json'}`
`{'Accept': 'application/json', 'Content-Type': 'application/json'}`
"""
def __init__(self,
@@ -578,19 +595,24 @@ class TensorBoard(Callback):
tensorboard --logdir=/full_path_to_your_logs
```
You can find more information about TensorBoard
[here](https://www.tensorflow.org/versions/master/how_tos/summaries_and_tensorboard/index.html).
[here](https://www.tensorflow.org/get_started/summaries_and_tensorboard).
# Arguments
log_dir: the path of the directory where to save the log
files to be parsed by Tensorboard.
files to be parsed by TensorBoard.
histogram_freq: frequency (in epochs) at which to compute activation
histograms for the layers of the model. If set to 0,
histograms won't be computed.
write_graph: whether to visualize the graph in Tensorboard.
and weight histograms for the layers of the model. If set to 0,
histograms won't be computed. Validation data (or split) must be
specified for histogram visualizations.
write_graph: whether to visualize the graph in TensorBoard.
The log file can become quite large when
write_graph is set to True.
write_grads: whether to visualize gradient histograms in TensorBoard.
`histogram_freq` must be greater than 0.
batch_size: size of batch of inputs to feed to the network
for histograms computation.
write_images: whether to write model weights to visualize as
image in Tensorboard.
image in TensorBoard.
embeddings_freq: frequency (in epochs) at which selected embedding
layers will be saved.
embeddings_layer_names: a list of names of layers to keep eye on. If
@@ -604,7 +626,9 @@ class TensorBoard(Callback):
def __init__(self, log_dir='./logs',
histogram_freq=0,
batch_size=32,
write_graph=True,
write_grads=False,
write_images=False,
embeddings_freq=0,
embeddings_layer_names=None,
@@ -617,10 +641,12 @@ class TensorBoard(Callback):
self.histogram_freq = histogram_freq
self.merged = None
self.write_graph = write_graph
self.write_grads = write_grads
self.write_images = write_images
self.embeddings_freq = embeddings_freq
self.embeddings_layer_names = embeddings_layer_names
self.embeddings_metadata = embeddings_metadata or {}
self.batch_size = batch_size
def set_model(self, model):
self.model = model
@@ -630,14 +656,42 @@ class TensorBoard(Callback):
for weight in layer.weights:
tf.summary.histogram(weight.name, weight)
if self.write_grads:
grads = model.optimizer.get_gradients(model.total_loss,
weight)
tf.summary.histogram('{}_grad'.format(weight.name), grads)
if self.write_images:
w_img = tf.squeeze(weight)
shape = w_img.get_shape()
if len(shape) > 1 and shape[0] > shape[1]:
w_img = tf.transpose(w_img)
if len(shape) == 1:
w_img = tf.expand_dims(w_img, 0)
w_img = tf.expand_dims(tf.expand_dims(w_img, 0), -1)
shape = K.int_shape(w_img)
if len(shape) == 2: # dense layer kernel case
if shape[0] > shape[1]:
w_img = tf.transpose(w_img)
shape = K.int_shape(w_img)
w_img = tf.reshape(w_img, [1,
shape[0],
shape[1],
1])
elif len(shape) == 3: # convnet case
if K.image_data_format() == 'channels_last':
# switch to channels_first to display
# every kernel as a separate image
w_img = tf.transpose(w_img, perm=[2, 0, 1])
shape = K.int_shape(w_img)
w_img = tf.reshape(w_img, [shape[0],
shape[1],
shape[2],
1])
elif len(shape) == 1: # bias case
w_img = tf.reshape(w_img, [1,
shape[0],
1,
1])
else:
# not possible to handle 3D convnets etc.
continue
shape = K.int_shape(w_img)
assert len(shape) == 4 and shape[-1] in [1, 3, 4]
tf.summary.image(weight.name, w_img)
if hasattr(layer, 'output'):
@@ -652,8 +706,6 @@ class TensorBoard(Callback):
self.writer = tf.summary.FileWriter(self.log_dir)
if self.embeddings_freq:
self.saver = tf.train.Saver()
embeddings_layer_names = self.embeddings_layer_names
if not embeddings_layer_names:
@@ -664,6 +716,8 @@ class TensorBoard(Callback):
for layer in self.model.layers
if layer.name in embeddings_layer_names}
self.saver = tf.train.Saver(list(embeddings.values()))
embeddings_metadata = {}
if not isinstance(self.embeddings_metadata, str):
@@ -673,15 +727,13 @@ class TensorBoard(Callback):
for layer_name in embeddings.keys()}
config = projector.ProjectorConfig()
self.embeddings_logs = []
self.embeddings_ckpt_path = os.path.join(self.log_dir,
'keras_embedding.ckpt')
for layer_name, tensor in embeddings.items():
embedding = config.embeddings.add()
embedding.tensor_name = tensor.name
self.embeddings_logs.append(os.path.join(self.log_dir,
layer_name + '.ckpt'))
if layer_name in embeddings_metadata:
embedding.metadata_path = embeddings_metadata[layer_name]
@@ -692,24 +744,37 @@ class TensorBoard(Callback):
if self.validation_data and self.histogram_freq:
if epoch % self.histogram_freq == 0:
# TODO: implement batched calls to sess.run
# (current call will likely go OOM on GPU)
if self.model.uses_learning_phase:
cut_v_data = len(self.model.inputs)
val_data = self.validation_data[:cut_v_data] + [0]
tensors = self.model.inputs + [K.learning_phase()]
else:
val_data = self.validation_data
tensors = self.model.inputs
feed_dict = dict(zip(tensors, val_data))
result = self.sess.run([self.merged], feed_dict=feed_dict)
summary_str = result[0]
self.writer.add_summary(summary_str, epoch)
if self.embeddings_freq and self.embeddings_logs:
val_data = self.validation_data
tensors = (self.model.inputs +
self.model.targets +
self.model.sample_weights)
if self.model.uses_learning_phase:
tensors += [K.learning_phase()]
assert len(val_data) == len(tensors)
val_size = val_data[0].shape[0]
i = 0
while i < val_size:
step = min(self.batch_size, val_size - i)
batch_val = []
batch_val.append(val_data[0][i:i + step])
batch_val.append(val_data[1][i:i + step])
batch_val.append(val_data[2][i:i + step])
if self.model.uses_learning_phase:
batch_val.append(val_data[3])
feed_dict = dict(zip(tensors, batch_val))
result = self.sess.run([self.merged], feed_dict=feed_dict)
summary_str = result[0]
self.writer.add_summary(summary_str, epoch)
i += self.batch_size
if self.embeddings_freq and self.embeddings_ckpt_path:
if epoch % self.embeddings_freq == 0:
for log in self.embeddings_logs:
self.saver.save(self.sess, log, epoch)
self.saver.save(self.sess,
self.embeddings_ckpt_path,
epoch)
for name, value in logs.items():
if name in ['batch', 'size']:
@@ -735,9 +800,9 @@ class ReduceLROnPlateau(Callback):
# Example
```python
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
patience=5, min_lr=0.001)
model.fit(X_train, Y_train, callbacks=[reduce_lr])
reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.2,
patience=5, min_lr=0.001)
model.fit(X_train, Y_train, callbacks=[reduce_lr])
```
# Arguments
@@ -844,8 +909,8 @@ class CSVLogger(Callback):
# Example
```python
csv_logger = CSVLogger('training.log')
model.fit(X_train, Y_train, callbacks=[csv_logger])
csv_logger = CSVLogger('training.log')
model.fit(X_train, Y_train, callbacks=[csv_logger])
```
# Arguments
@@ -862,23 +927,26 @@ class CSVLogger(Callback):
self.writer = None
self.keys = None
self.append_header = True
self.file_flags = 'b' if six.PY2 and os.name == 'nt' else ''
super(CSVLogger, self).__init__()
def on_train_begin(self, logs=None):
if self.append:
if os.path.exists(self.filename):
with open(self.filename) as f:
with open(self.filename, 'r' + self.file_flags) as f:
self.append_header = not bool(len(f.readline()))
self.csv_file = open(self.filename, 'a')
self.csv_file = open(self.filename, 'a' + self.file_flags)
else:
self.csv_file = open(self.filename, 'w')
self.csv_file = open(self.filename, 'w' + self.file_flags)
def on_epoch_end(self, epoch, logs=None):
logs = logs or {}
def handle_value(k):
is_zero_dim_ndarray = isinstance(k, np.ndarray) and k.ndim == 0
if isinstance(k, Iterable) and not is_zero_dim_ndarray:
if isinstance(k, six.string_types):
return k
elif isinstance(k, Iterable) and not is_zero_dim_ndarray:
return '"[%s]"' % (', '.join(map(str, k)))
else:
return k
@@ -910,6 +978,7 @@ class LambdaCallback(Callback):
This callback is constructed with anonymous functions that will be called
at the appropriate time. Note that the callbacks expects positional
arguments, as:
- `on_epoch_begin` and `on_epoch_end` expect two positional arguments:
`epoch`, `logs`
- `on_batch_begin` and `on_batch_end` expect two positional arguments:
+1 -1
Ver Arquivo
@@ -58,7 +58,7 @@ class NonNeg(Constraint):
"""
def __call__(self, w):
w *= K.cast(w >= 0., K.floatx())
w *= K.cast(K.greater_equal(w, 0.), K.floatx())
return w
+3 -1
Ver Arquivo
@@ -16,7 +16,9 @@ def load_data(path='boston_housing.npz', seed=113, test_split=0.2):
Tuple of Numpy arrays: `(x_train, y_train), (x_test, y_test)`.
"""
assert 0 <= test_split < 1
path = get_file(path, origin='https://s3.amazonaws.com/keras-datasets/boston_housing.npz')
path = get_file(path,
origin='https://s3.amazonaws.com/keras-datasets/boston_housing.npz',
file_hash='f553886a1f8d56431e820c5b82552d9d95cfcb96d1e678153f8839538947dff5')
f = np.load(path)
x = f['x']
y = f['y']
+1 -1
Ver Arquivo
@@ -100,7 +100,7 @@ def load_data(path='imdb.npz', num_words=None, skip_top=0,
for x in xs:
nx = []
for w in x:
if w >= num_words or w < skip_top:
if skip_top <= w < num_words:
nx.append(w)
new_xs.append(nx)
xs = new_xs
+1 -1
Ver Arquivo
@@ -84,7 +84,7 @@ def load_data(path='reuters.npz', num_words=None, skip_top=0,
for x in xs:
nx = []
for w in x:
if w >= num_words or w < skip_top:
if skip_top <= w < num_words:
nx.append(w)
new_xs.append(nx)
xs = new_xs
+152 -57
Ver Arquivo
@@ -360,28 +360,35 @@ class Layer(object):
def non_trainable_weights(self, weights):
self._non_trainable_weights = weights
def add_weight(self, shape, initializer,
name=None,
trainable=True,
@interfaces.legacy_add_weight_support
def add_weight(self,
name,
shape,
dtype=None,
initializer=None,
regularizer=None,
trainable=True,
constraint=None):
"""Adds a weight variable to the layer.
# Arguments
shape: The shape tuple of the weight.
initializer: An Initializer instance (callable).
name: String, the name for the weight variable.
shape: The shape tuple of the weight.
dtype: The dtype of the weight.
initializer: An Initializer instance (callable).
regularizer: An optional Regularizer instance.
trainable: A boolean, whether the weight should
be trained via backprop or not (assuming
that the layer itself is also trainable).
regularizer: An optional Regularizer instance.
constraint: An optional Constraint instance.
# Returns
The created weight variable.
"""
initializer = initializers.get(initializer)
weight = K.variable(initializer(shape), dtype=K.floatx(), name=name)
if dtype is None:
dtype = K.floatx()
weight = K.variable(initializer(shape), dtype=dtype, name=name)
if regularizer is not None:
self.add_loss(regularizer(weight))
if constraint is not None:
@@ -406,13 +413,24 @@ class Layer(object):
ValueError: in case of mismatch between
the provided inputs and the expectations of the layer.
"""
inputs = _to_list(inputs)
for x in inputs:
try:
K.is_keras_tensor(x)
except ValueError:
raise ValueError('Layer ' + self.name + ' was called with '
'an input that isn\'t a symbolic tensor. '
'Received type: ' +
str(type(x)) + '. Full input: ' +
str(inputs) + '. All inputs to the layer '
'should be tensors.')
if not self.input_spec:
return
if not isinstance(self.input_spec, (list, tuple)):
input_spec = _to_list(self.input_spec)
else:
input_spec = self.input_spec
inputs = _to_list(inputs)
if len(inputs) != len(input_spec):
raise ValueError('Layer ' + self.name + ' expects ' +
str(len(input_spec)) + ' inputs, '
@@ -578,6 +596,20 @@ class Layer(object):
output = self.call(inputs, **kwargs)
output_mask = self.compute_mask(inputs, previous_mask)
# If the layer returns tensors from its inputs, unmodified,
# we copy them to avoid loss of tensor metadata.
output_ls = _to_list(output)
inputs_ls = _to_list(inputs)
output_ls_copy = []
for x in output_ls:
if x in inputs_ls:
x = K.identity(x)
output_ls_copy.append(x)
if len(output_ls_copy) == 1:
output = output_ls_copy[0]
else:
output = output_ls_copy
# Infering the output shape is only relevant for Theano.
if all([s is not None for s in _to_list(input_shape)]):
output_shape = self.compute_output_shape(input_shape)
@@ -1056,7 +1088,7 @@ class Layer(object):
if hasattr(self, '_losses'):
self._losses += losses
# Update self._per_input_updates
if inputs == []:
if isinstance(input, list) and inputs == []:
inputs = None
if inputs is not None:
inputs_hash = _object_list_uid(inputs)
@@ -1088,7 +1120,7 @@ class Layer(object):
if hasattr(self, '_updates'):
self._updates += updates
# Update self._per_input_updates
if inputs == []:
if isinstance(inputs, list) and inputs == []:
inputs = None
if inputs is not None:
inputs_hash = _object_list_uid(inputs)
@@ -1249,6 +1281,7 @@ class InputLayer(Layer):
name: Name of the layer (string).
"""
@interfaces.legacy_input_support
def __init__(self, input_shape=None, batch_size=None,
batch_input_shape=None,
dtype=None, input_tensor=None, sparse=False, name=None):
@@ -1265,7 +1298,8 @@ class InputLayer(Layer):
raise ValueError('Only provide the input_shape OR '
'batch_input_shape argument to '
'InputLayer, not both at the same time.')
if input_tensor is not None:
if input_tensor is not None and batch_input_shape is None:
# If input_tensor is set, and batch_input_shape is not set:
# Attempt automatic input shape inference.
try:
batch_input_shape = K.int_shape(input_tensor)
@@ -1337,7 +1371,7 @@ def Input(shape=None, batch_shape=None,
attributes that allow us to build a Keras model
just by knowing the inputs and outputs of the model.
For instance, if a, b and c and Keras tensors,
For instance, if a, b and c are Keras tensors,
it becomes possible to do:
`model = Model(input=[a, b], output=c)`
@@ -1434,6 +1468,9 @@ class Container(Layer):
# Class Methods
from_config
# Raises
TypeError: if input tensors are not Keras tensors from InputLayer objects
"""
@interfaces.legacy_model_constructor_support
@@ -1460,13 +1497,19 @@ class Container(Layer):
self.outputs = [outputs]
# Check for redundancy in inputs.
inputs_set = set(self.inputs)
if len(inputs_set) != len(self.inputs):
if len(set(self.inputs)) != len(self.inputs):
raise ValueError('The list of inputs passed to the model '
'is redundant. '
'All inputs should only appear once.'
' Found: ' + str(self.inputs))
# Check for redundancy in outputs.
if len(set(self.outputs)) != len(self.outputs):
warnings.warn('The list of outputs passed to the model '
'is redundant. '
'All outputs should only appear once.'
' Found: ' + str(self.outputs))
# List of initial layers (1 to 1 mapping with self.inputs,
# hence the same layer might appear twice)
self.input_layers = []
@@ -1568,6 +1611,15 @@ class Container(Layer):
self._feed_inputs = []
self._feed_input_shapes = []
for i, layer in enumerate(self.input_layers):
# Check that layer is an InputLayer.
if not isinstance(layer, InputLayer):
raise TypeError(
'Input layers to a `Model` must be `InputLayer` objects. '
'Received inputs: {}. '
'Input {} (0-based) originates '
'from layer type `{}`.'.format(inputs,
i,
layer.__class__.__name__))
self.input_names.append(layer.name)
if layer.is_placeholder:
self._feed_input_names.append(layer.name)
@@ -1586,72 +1638,92 @@ class Container(Layer):
nodes_depths = {} # dict {node: depth value}
layers_depths = {} # dict {layer: depth value}
layer_indices = {} # dict {layer: index in traversal}
nodes_in_decreasing_depth = []
def make_node_marker(node, depth):
return str(id(node)) + '-' + str(depth)
def build_map_of_graph(tensor, seen_nodes=None, depth=0,
def build_map_of_graph(tensor, finished_nodes, nodes_in_progress,
layer=None, node_index=None, tensor_index=None):
"""Builds a map of the graph of layers.
This recursively updates the maps `nodes_depths`,
`layers_depths` and the set `container_nodes`.
Does not try to detect cycles in the graph.
This recursively updates the map `layer_indices`,
the list `nodes_in_decreasing_depth` and the set `container_nodes`.
# Arguments
tensor: Some tensor in a graph.
seen_nodes: Set of node ids ("{layer.name}_ib-{node_index}")
of nodes seen so far. Useful to prevent infinite loops.
depth: Current depth in the graph (0 = last output).
finished_nodes: Set of nodes whose subgraphs have been traversed
completely. Useful to prevent duplicated work.
nodes_in_progress: Set of nodes that are currently active on the
recursion stack. Useful to detect cycles.
layer: Layer from which `tensor` comes from. If not provided,
will be obtained from `tensor._keras_history`.
node_index: Node index from which `tensor` comes from.
tensor_index: Tensor_index from which `tensor` comes from.
# Raises
RuntimeError: if a cycle is detected.
"""
seen_nodes = seen_nodes or set()
if not layer or node_index is None or tensor_index is None:
layer, node_index, tensor_index = tensor._keras_history
node = layer.inbound_nodes[node_index]
# Prevent cycles.
seen_nodes.add(make_node_marker(node, depth))
if node in nodes_in_progress:
raise RuntimeError(
'The tensor ' + str(tensor) + ' at layer "' +
layer.name + '" is part of a cycle.')
# Don't repeat work for shared subgraphs
if node in finished_nodes:
return
node_key = layer.name + '_ib-' + str(node_index)
# Update container_nodes.
container_nodes.add(node_key)
# Update nodes_depths.
node_depth = nodes_depths.get(node)
if node_depth is None:
nodes_depths[node] = depth
else:
nodes_depths[node] = max(depth, node_depth)
# Update layers_depths.
previously_seen_depth = layers_depths.get(layer)
if previously_seen_depth is None:
current_depth = depth
else:
current_depth = max(depth, previously_seen_depth)
layers_depths[layer] = current_depth
# Store the traversal order for layer sorting.
if layer not in layer_indices:
layer_indices[layer] = len(layer_indices)
nodes_in_progress.add(node)
# Propagate to all previous tensors connected to this node.
for i in range(len(node.inbound_layers)):
x = node.input_tensors[i]
layer = node.inbound_layers[i]
node_index = node.node_indices[i]
tensor_index = node.tensor_indices[i]
next_node = layer.inbound_nodes[node_index]
# use node_marker to prevent cycles
node_marker = make_node_marker(next_node, current_depth + 1)
if node_marker not in seen_nodes:
build_map_of_graph(x, seen_nodes, current_depth + 1,
layer, node_index, tensor_index)
build_map_of_graph(x, finished_nodes, nodes_in_progress,
layer, node_index, tensor_index)
finished_nodes.add(node)
nodes_in_progress.remove(node)
nodes_in_decreasing_depth.append(node)
finished_nodes = set()
nodes_in_progress = set()
for x in self.outputs:
seen_nodes = set()
build_map_of_graph(x, seen_nodes, depth=0)
build_map_of_graph(x, finished_nodes, nodes_in_progress)
for node in reversed(nodes_in_decreasing_depth):
# If the depth is not set, the node has no outbound nodes (depth 0).
depth = nodes_depths.setdefault(node, 0)
# Update the depth of the corresponding layer
previous_depth = layers_depths.get(node.outbound_layer, 0)
# If we've seen this layer before at a higher depth, we should use that depth instead
# of the node depth. This is necessary for shared layers that have inputs at different
# depth levels in the graph.
depth = max(depth, previous_depth)
layers_depths[node.outbound_layer] = depth
nodes_depths[node] = depth
# Update the depth of inbound nodes.
for i in range(len(node.inbound_layers)):
inbound_layer = node.inbound_layers[i]
node_index = node.node_indices[i]
inbound_node = inbound_layer.inbound_nodes[node_index]
previous_depth = nodes_depths.get(inbound_node, 0)
nodes_depths[inbound_node] = max(depth + 1, previous_depth)
# Build a dict {depth: list of nodes with this depth}
nodes_by_depth = {}
@@ -2747,6 +2819,25 @@ def preprocess_weights_for_loading(layer, weights,
A list of weights values (Numpy arrays).
"""
if original_keras_version == '1':
if layer.__class__.__name__ == 'Bidirectional':
num_weights_per_layer = len(weights) // 2
forward_weights = preprocess_weights_for_loading(layer.forward_layer,
weights[:num_weights_per_layer],
original_keras_version,
original_backend)
backward_weights = preprocess_weights_for_loading(layer.backward_layer,
weights[num_weights_per_layer:],
original_keras_version,
original_backend)
weights = forward_weights + backward_weights
if layer.__class__.__name__ == 'TimeDistributed':
weights = preprocess_weights_for_loading(layer.layer,
weights,
original_keras_version,
original_backend)
if layer.__class__.__name__ == 'Conv1D':
shape = weights[0].shape
# Handle Keras 1.1 format
@@ -2832,16 +2923,20 @@ def preprocess_weights_for_loading(layer, weights,
(2, 3, 1, 0))
weights = [kernel, recurrent_kernel, bias]
if original_backend and K.backend() != original_backend:
conv_layers = ['Conv1D',
'Conv2D',
'Conv3D',
'Conv2DTranspose']
if layer.__class__.__name__ in conv_layers:
conv_layers = ['Conv1D',
'Conv2D',
'Conv3D',
'Conv2DTranspose',
'ConvLSTM2D']
if layer.__class__.__name__ in conv_layers:
if original_backend and K.backend() != original_backend:
weights[0] = conv_utils.convert_kernel(weights[0])
if layer.__class__.__name__ == 'ConvLSTM2D':
weights[0] = conv_utils.convert_kernel(weights[0])
weights[1] = conv_utils.convert_kernel(weights[1])
if layer.__class__.__name__ == 'ConvLSTM2D':
weights[1] = conv_utils.convert_kernel(weights[1])
if K.int_shape(layer.weights[0]) != weights[0].shape:
weights[0] = np.transpose(weights[0], (3, 2, 0, 1))
if layer.__class__.__name__ == 'ConvLSTM2D':
weights[1] = np.transpose(weights[1], (3, 2, 0, 1))
return weights
+68 -43
Ver Arquivo
@@ -50,6 +50,8 @@ def _standardize_input_data(data, names, shapes=None,
# Raises
ValueError: in case of improperly formatted user-provided data.
"""
if not names:
return []
if data is None:
return [None for _ in range(len(names))]
if isinstance(data, dict):
@@ -63,7 +65,8 @@ def _standardize_input_data(data, names, shapes=None,
elif isinstance(data, list):
if len(data) != len(names):
if data and hasattr(data[0], 'shape'):
raise ValueError('Error when checking ' + exception_prefix +
raise ValueError('Error when checking model ' +
exception_prefix +
': the list of Numpy arrays '
'that you are passing to your model '
'is not the size the model expected. '
@@ -77,7 +80,8 @@ def _standardize_input_data(data, names, shapes=None,
data = [np.asarray(data)]
else:
raise ValueError(
'Error when checking ' + exception_prefix +
'Error when checking model ' +
exception_prefix +
': you are passing a list as '
'input to your model, '
'but the model expects '
@@ -88,15 +92,17 @@ def _standardize_input_data(data, names, shapes=None,
arrays = data
else:
if not hasattr(data, 'shape'):
raise TypeError('Error when checking ' + exception_prefix +
raise TypeError('Error when checking model ' +
exception_prefix +
': data should be a Numpy array, '
'or list/dict of Numpy arrays. '
'Found: ' + str(data)[:200] + '...')
if len(names) != 1:
if len(names) > 1:
# Case: model expects multiple inputs but only received
# a single Numpy array.
raise ValueError('The model expects ' + str(len(names)) +
' input arrays, but only received one array. '
exception_prefix +
' arrays, but only received one array. '
'Found: array with shape ' + str(data.shape))
arrays = [data]
@@ -235,7 +241,7 @@ def _check_array_lengths(inputs, targets, weights):
def _check_loss_and_target_compatibility(targets, loss_fns, output_shapes):
"""Does validation on the compatiblity of targets and loss functions.
"""Does validation on the compatibility of targets and loss functions.
This helps prevent users from using loss functions incorrectly.
@@ -679,6 +685,8 @@ class Model(Container):
See [losses](/losses).
If the model has multiple outputs, you can use a different loss
on each output by passing a dictionary or a list of losses.
The loss value that will be minimized by the model
will then be the sum of all individual losses.
metrics: list of metrics to be evaluated by the model
during training and testing.
Typically you will use `metrics=['accuracy']`.
@@ -688,6 +696,9 @@ class Model(Container):
loss_weights: Optional list or dictionary specifying scalar
coefficients (Python floats) to weight the loss contributions
of different model outputs.
The loss value that will be minimized by the model
will then be the *weighted sum* of all individual losses,
weighted by the `loss_weights` coefficients.
If a list, it is expected to have a 1:1 mapping
to the model's outputs. If a tensor, it is expected to map
output names (strings) to scalar coefficients.
@@ -698,7 +709,8 @@ class Model(Container):
`sample_weight_mode` on each output by passing a
dictionary or a list of modes.
**kwargs: when using the Theano backend, these arguments
are passed into K.function. Ignored for Tensorflow backend.
are passed into K.function. When using the Tensorflow backend,
these arguments are passed into `tf.Session.run`.
# Raises
ValueError: In case of invalid arguments for
@@ -1005,6 +1017,7 @@ class Model(Container):
self.train_function = K.function(inputs,
[self.total_loss] + self.metrics_tensors,
updates=updates,
name='train_function',
**self._function_kwargs)
def _make_test_function(self):
@@ -1019,6 +1032,7 @@ class Model(Container):
self.test_function = K.function(inputs,
[self.total_loss] + self.metrics_tensors,
updates=self.state_updates,
name='test_function',
**self._function_kwargs)
def _make_predict_function(self):
@@ -1035,6 +1049,7 @@ class Model(Container):
self.predict_function = K.function(inputs,
self.outputs,
updates=self.state_updates,
name='predict_function',
**kwargs)
def _fit_loop(self, f, ins, out_labels=None, batch_size=32,
@@ -1126,7 +1141,7 @@ class Model(Container):
batch_ids = index_array[batch_start:batch_end]
try:
if isinstance(ins[-1], float):
# do not slice the training phase flag
# Do not slice the training phase flag.
ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
else:
ins_batch = _slice_arrays(ins, batch_ids)
@@ -1145,17 +1160,17 @@ class Model(Container):
batch_logs[l] = o
callbacks.on_batch_end(batch_index, batch_logs)
if callback_model.stop_training:
break
if batch_index == len(batches) - 1: # last batch
# validation
if batch_index == len(batches) - 1: # Last batch.
if do_validation:
# replace with self._evaluate
val_outs = self._test_loop(val_f, val_ins,
batch_size=batch_size,
verbose=0)
if not isinstance(val_outs, list):
val_outs = [val_outs]
# same labels assumed
# Same labels assumed.
for l, o in zip(out_labels, val_outs):
epoch_logs['val_' + l] = o
callbacks.on_epoch_end(epoch, epoch_logs)
@@ -1195,7 +1210,7 @@ class Model(Container):
for batch_index, (batch_start, batch_end) in enumerate(batches):
batch_ids = index_array[batch_start:batch_end]
if ins and isinstance(ins[-1], float):
# do not slice the training phase flag
# Do not slice the training phase flag.
ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
else:
ins_batch = _slice_arrays(ins, batch_ids)
@@ -1249,7 +1264,7 @@ class Model(Container):
for batch_index, (batch_start, batch_end) in enumerate(batches):
batch_ids = index_array[batch_start:batch_end]
if isinstance(ins[-1], float):
# do not slice the training phase flag
# Do not slice the training phase flag.
ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
else:
ins_batch = _slice_arrays(ins, batch_ids)
@@ -1293,11 +1308,11 @@ class Model(Container):
x = _standardize_input_data(x, self._feed_input_names,
self._feed_input_shapes,
check_batch_axis=False,
exception_prefix='model input')
exception_prefix='input')
y = _standardize_input_data(y, self._feed_output_names,
output_shapes,
check_batch_axis=False,
exception_prefix='model target')
exception_prefix='target')
sample_weights = _standardize_sample_weights(sample_weight,
self._feed_output_names)
class_weights = _standardize_class_weights(class_weight,
@@ -1318,6 +1333,20 @@ class Model(Container):
str(x[0].shape[0]) + ' samples')
return x, y, sample_weights
def _get_deduped_metrics_names(self):
out_labels = self.metrics_names
# Rename duplicated metrics name
# (can happen with an output layer shared among multiple dataflows).
deduped_out_labels = []
for i, label in enumerate(out_labels):
new_label = label
if out_labels.count(label) > 1:
dup_idx = out_labels[:i].count(label)
new_label += '_' + str(dup_idx + 1)
deduped_out_labels.append(new_label)
return deduped_out_labels
def fit(self, x=None,
y=None,
batch_size=32,
@@ -1347,7 +1376,7 @@ class Model(Container):
batch_size: integer. Number of samples per gradient update.
epochs: integer, the number of times to iterate
over the training data arrays.
verbose: 0, 1, or 2. Verbosity mode.
verbose: 0, 1, or 2. Verbosity mode.
0 = silent, 1 = verbose, 2 = one log line per epoch.
callbacks: list of callbacks to be called during training.
See [callbacks](/callbacks).
@@ -1397,14 +1426,14 @@ class Model(Container):
if kwargs:
raise TypeError('Unrecognized keyword arguments: ' + str(kwargs))
# validate user data
# Validate user data.
x, y, sample_weights = self._standardize_user_data(
x, y,
sample_weight=sample_weight,
class_weight=class_weight,
check_batch_axis=False,
batch_size=batch_size)
# prepare validation data
# Prepare validation data.
if validation_data:
do_validation = True
if len(validation_data) == 2:
@@ -1433,7 +1462,10 @@ class Model(Container):
elif validation_split and 0. < validation_split < 1.:
do_validation = True
split_at = int(len(x[0]) * (1. - validation_split))
if hasattr(x[0], 'shape'):
split_at = int(x[0].shape[0] * (1. - validation_split))
else:
split_at = int(len(x[0]) * (1. - validation_split))
x, val_x = (_slice_arrays(x, 0, split_at), _slice_arrays(x, split_at))
y, val_y = (_slice_arrays(y, 0, split_at), _slice_arrays(y, split_at))
sample_weights, val_sample_weights = (
@@ -1450,7 +1482,7 @@ class Model(Container):
val_f = None
val_ins = None
# prepare input arrays and training function
# Prepare input arrays and training function.
if self.uses_learning_phase and not isinstance(K.learning_phase(), int):
ins = x + y + sample_weights + [1.]
else:
@@ -1458,26 +1490,15 @@ class Model(Container):
self._make_train_function()
f = self.train_function
# prepare display labels
out_labels = self.metrics_names
# rename duplicated metrics name
# (can happen with an output layer shared among multiple dataflows)
deduped_out_labels = []
for i, label in enumerate(out_labels):
new_label = label
if out_labels.count(label) > 1:
dup_idx = out_labels[:i].count(label)
new_label += '_' + str(dup_idx + 1)
deduped_out_labels.append(new_label)
out_labels = deduped_out_labels
# Prepare display labels.
out_labels = self._get_deduped_metrics_names()
if do_validation:
callback_metrics = copy.copy(out_labels) + ['val_' + n for n in out_labels]
else:
callback_metrics = copy.copy(out_labels)
# delegate logic to _fit_loop
# Delegate logic to `_fit_loop`.
return self._fit_loop(f, ins, out_labels=out_labels,
batch_size=batch_size, epochs=epochs,
verbose=verbose, callbacks=callbacks,
@@ -1512,13 +1533,13 @@ class Model(Container):
and/or metrics). The attribute `model.metrics_names` will give you
the display labels for the scalar outputs.
"""
# validate user data
# Validate user data.
x, y, sample_weights = self._standardize_user_data(
x, y,
sample_weight=sample_weight,
check_batch_axis=False,
batch_size=batch_size)
# prepare inputs, delegate logic to _test_loop
# Prepare inputs, delegate logic to `_test_loop`.
if self.uses_learning_phase and not isinstance(K.learning_phase(), int):
ins = x + y + sample_weights + [0.]
else:
@@ -1549,7 +1570,7 @@ class Model(Container):
or in case a stateful model receives a number of samples
that is not a multiple of the batch size.
"""
# validate user data
# Validate user data.
x = _standardize_input_data(x, self._feed_input_names,
self._feed_input_shapes,
check_batch_axis=False)
@@ -1562,7 +1583,7 @@ class Model(Container):
str(x[0].shape[0]) + ' samples. '
'Batch size: ' + str(batch_size) + '.')
# prepare inputs, delegate logic to _predict_loop
# Prepare inputs, delegate logic to `_predict_loop`.
if self.uses_learning_phase and not isinstance(K.learning_phase(), int):
ins = x + [0.]
else:
@@ -1713,7 +1734,7 @@ class Model(Container):
All arrays should contain the same number of samples.
The generator is expected to loop over its data
indefinitely. An epoch finishes when `steps_per_epoch`
samples have been seen by the model.
batches have been seen by the model.
steps_per_epoch: Total number of steps (batches of samples)
to yield from `generator` before declaring one epoch
finished and starting the next epoch. It should typically
@@ -1785,7 +1806,8 @@ class Model(Container):
'you must specify a value for '
'`validation_steps`.')
out_labels = self.metrics_names
# Prepare display labels.
out_labels = self._get_deduped_metrics_names()
callback_metrics = out_labels + ['val_' + n for n in out_labels]
# prepare callbacks
@@ -1823,8 +1845,11 @@ class Model(Container):
str(validation_data))
val_x, val_y, val_sample_weights = self._standardize_user_data(
val_x, val_y, val_sample_weight)
val_data = val_x + val_y + val_sample_weights
if self.uses_learning_phase and not isinstance(K.learning_phase(), int):
val_data += [0.]
for cbk in callbacks:
cbk.validation_data = val_x + [val_y, val_sample_weights]
cbk.validation_data = val_data
enqueuer = None
try:
@@ -1931,7 +1956,7 @@ class Model(Container):
The generator should return the same kind of data
as accepted by `test_on_batch`.
Arguments:
# Arguments
generator: Generator yielding tuples (inputs, targets)
or (inputs, targets, sample_weights)
steps: Total number of steps (batches of samples)
+8
Ver Arquivo
@@ -21,6 +21,14 @@ from ..legacy.layers import *
def serialize(layer):
"""Serialize a layer.
# Arguments
layer: a Layer object.
# Returns
dictionary with config.
"""
return {'class_name': layer.__class__.__name__,
'config': layer.get_config()}
+2 -2
Ver Arquivo
@@ -104,7 +104,7 @@ class PReLU(Layer):
for i in self.shared_axes:
param_shape[i - 1] = 1
self.param_broadcast[i - 1] = True
self.alpha = self.add_weight(param_shape,
self.alpha = self.add_weight(shape=param_shape,
name='alpha',
initializer=self.alpha_initializer,
regularizer=self.alpha_regularizer,
@@ -202,7 +202,7 @@ class ThresholdedReLU(Layer):
self.theta = K.cast_to_floatx(theta)
def call(self, inputs, mask=None):
return inputs * K.cast(inputs > self.theta, K.floatx())
return inputs * K.cast(K.greater(inputs, self.theta), K.floatx())
def get_config(self):
config = {'theta': float(self.theta)}
+18 -15
Ver Arquivo
@@ -127,13 +127,13 @@ class _Conv(Layer):
input_dim = input_shape[channel_axis]
kernel_shape = self.kernel_size + (input_dim, self.filters)
self.kernel = self.add_weight(kernel_shape,
self.kernel = self.add_weight(shape=kernel_shape,
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
if self.use_bias:
self.bias = self.add_weight((self.filters,),
self.bias = self.add_weight(shape=(self.filters,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
@@ -256,6 +256,9 @@ class Conv1D(_Conv):
Specifying any stride value != 1 is incompatible with specifying
any `dilation_rate` value != 1.
padding: One of `"valid"`, `"causal"` or `"same"` (case-insensitive).
`"valid"` means "no padding".
`"same"` results in padding the input such that
the output has the same length as the original input.
`"causal"` results in causal (dilated) convolutions, e.g. output[t]
does not depend on input[t+1:]. Useful when modeling temporal data
where the model should not violate the temporal order.
@@ -721,13 +724,13 @@ class Conv2DTranspose(Conv2D):
input_dim = input_shape[channel_axis]
kernel_shape = self.kernel_size + (self.filters, input_dim)
self.kernel = self.add_weight(kernel_shape,
self.kernel = self.add_weight(shape=kernel_shape,
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
if self.use_bias:
self.bias = self.add_weight((self.filters,),
self.bias = self.add_weight(shape=(self.filters,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
@@ -952,20 +955,20 @@ class SeparableConv2D(Conv2D):
self.filters)
self.depthwise_kernel = self.add_weight(
depthwise_kernel_shape,
shape=depthwise_kernel_shape,
initializer=self.depthwise_initializer,
name='depthwise_kernel',
regularizer=self.depthwise_regularizer,
constraint=self.depthwise_constraint)
self.pointwise_kernel = self.add_weight(
pointwise_kernel_shape,
shape=pointwise_kernel_shape,
initializer=self.pointwise_initializer,
name='pointwise_kernel',
regularizer=self.pointwise_regularizer,
constraint=self.pointwise_constraint)
if self.use_bias:
self.bias = self.add_weight((self.filters,),
self.bias = self.add_weight(shape=(self.filters,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
@@ -1252,7 +1255,7 @@ class ZeroPadding1D(Layer):
class ZeroPadding2D(Layer):
"""Zero-padding layer for 2D input (e.g. picture).
This layer can add rows and columns or zeros
This layer can add rows and columns of zeros
at the top, bottom, left and right side of an image tensor.
# Arguments
@@ -1430,15 +1433,15 @@ class ZeroPadding3D(Layer):
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
if input_shape[2] is not None:
dim1 = input_shape[2] + 2 * self.padding[0][0]
dim1 = input_shape[2] + self.padding[0][0] + self.padding[0][1]
else:
dim1 = None
if input_shape[3] is not None:
dim2 = input_shape[3] + 2 * self.padding[1][0]
dim2 = input_shape[3] + self.padding[1][0] + self.padding[1][1]
else:
dim2 = None
if input_shape[4] is not None:
dim3 = input_shape[4] + 2 * self.padding[2][0]
dim3 = input_shape[4] + self.padding[2][0] + self.padding[2][1]
else:
dim3 = None
return (input_shape[0],
@@ -1448,15 +1451,15 @@ class ZeroPadding3D(Layer):
dim3)
elif self.data_format == 'channels_last':
if input_shape[1] is not None:
dim1 = input_shape[1] + 2 * self.padding[0][1]
dim1 = input_shape[1] + self.padding[0][0] + self.padding[0][1]
else:
dim1 = None
if input_shape[2] is not None:
dim2 = input_shape[2] + 2 * self.padding[1][1]
dim2 = input_shape[2] + self.padding[1][0] + self.padding[1][1]
else:
dim2 = None
if input_shape[3] is not None:
dim3 = input_shape[3] + 2 * self.padding[2][1]
dim3 = input_shape[3] + self.padding[2][0] + self.padding[2][1]
else:
dim3 = None
return (input_shape[0],
@@ -1571,7 +1574,7 @@ class Cropping2D(Layer):
model.add(Cropping2D(cropping=((2, 2), (4, 4)),
input_shape=(28, 28, 3)))
# now model.output_shape == (None, 24, 20, 3)
model.add(Conv2D(64, (3, 3), padding='same))
model.add(Conv2D(64, (3, 3), padding='same'))
model.add(Cropping2D(cropping=((2, 2), (2, 2))))
# now model.output_shape == (None, 20, 16. 64)
```
+18 -9
Ver Arquivo
@@ -105,9 +105,12 @@ class ConvRecurrent2D(Recurrent):
self.return_sequences = return_sequences
self.go_backwards = go_backwards
self.stateful = stateful
self.input_spec = InputSpec(ndim=5)
self.input_spec = [InputSpec(ndim=5)]
self.state_spec = None
def compute_output_shape(self, input_shape):
if isinstance(input_shape, list):
input_shape = input_shape[0]
if self.data_format == 'channels_first':
rows = input_shape[3]
cols = input_shape[4]
@@ -328,11 +331,13 @@ class ConvLSTM2D(ConvRecurrent2D):
self.dropout = min(1., max(0., dropout))
self.recurrent_dropout = min(1., max(0., recurrent_dropout))
self.state_spec = [InputSpec(ndim=4), InputSpec(ndim=4)]
def build(self, input_shape):
# TODO: better handling of input spec
self.input_spec = InputSpec(shape=input_shape)
if isinstance(input_shape, list):
input_shape = input_shape[0]
batch_size = input_shape[0] if self.stateful else None
self.input_spec[0] = InputSpec(shape=(batch_size, None) + input_shape[2:])
if self.stateful:
self.reset_states()
else:
@@ -347,23 +352,27 @@ class ConvLSTM2D(ConvRecurrent2D):
raise ValueError('The channel dimension of the inputs '
'should be defined. Found `None`.')
input_dim = input_shape[channel_axis]
state_shape = [None] * 4
state_shape[channel_axis] = input_dim
state_shape = tuple(state_shape)
self.state_spec = [InputSpec(shape=state_shape), InputSpec(shape=state_shape)]
kernel_shape = self.kernel_size + (input_dim, self.filters * 4)
self.kernel_shape = kernel_shape
recurrent_kernel_shape = self.kernel_size + (self.filters, self.filters * 4)
self.kernel = self.add_weight(kernel_shape,
self.kernel = self.add_weight(shape=kernel_shape,
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
self.recurrent_kernel = self.add_weight(
recurrent_kernel_shape,
shape=recurrent_kernel_shape,
initializer=self.recurrent_initializer,
name='recurrent_kernel',
regularizer=self.recurrent_regularizer,
constraint=self.recurrent_constraint)
if self.use_bias:
self.bias = self.add_weight((self.filters * 4,),
self.bias = self.add_weight(shape=(self.filters * 4,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
@@ -396,7 +405,7 @@ class ConvLSTM2D(ConvRecurrent2D):
self.bias_o = None
self.built = True
def get_initial_states(self, inputs):
def get_initial_state(self, inputs):
# (samples, timesteps, rows, cols, filters)
initial_state = K.zeros_like(inputs)
# (samples, rows, cols, filters)
@@ -413,7 +422,7 @@ class ConvLSTM2D(ConvRecurrent2D):
def reset_states(self):
if not self.stateful:
raise RuntimeError('Layer must be stateful.')
input_shape = self.input_spec.shape
input_shape = self.input_spec[0].shape
output_shape = self.compute_output_shape(input_shape)
if not input_shape[0]:
raise ValueError('If a RNN is stateful, a complete '
+23 -20
Ver Arquivo
@@ -299,13 +299,13 @@ class Reshape(Layer):
"""Reshapes an output to a certain shape.
# Arguments
target_shape: target shape. Tuple of integers,
does not include the samples dimension (batch size).
target_shape: target shape. Tuple of integers.
Does not include the batch axis.
# Input shape
Arbitrary, although all dimensions in the input shaped must be fixed.
Use the keyword argument `input_shape`
(tuple of integers, does not include the samples axis)
(tuple of integers, does not include the batch axis)
when using this layer as the first layer in a model.
# Output shape
@@ -335,27 +335,22 @@ class Reshape(Layer):
self.target_shape = tuple(target_shape)
def _fix_unknown_dimension(self, input_shape, output_shape):
"""Find and replace a missing dimension in an output shape.
"""Finds and replaces a missing dimension in an output shape.
This is a near direct port of the internal Numpy function
`_fix_unknown_dimension` in `numpy/core/src/multiarray/shape.c`
# Arguments
input_shape: shape of array being reshaped
output_shape: desired shape of the array with at most
input_shape: original shape of array being reshaped
output_shape: target shape of the array, with at most
a single -1 which indicates a dimension that should be
derived from the input shape.
# Returns
The new output shape with a -1 replaced with its computed value.
Raises a ValueError if the total array size of the output_shape is
different then the input_shape, or more then one unknown dimension
is specified.
The new output shape with a `-1` replaced with its computed value.
# Raises
ValueError: in case of invalid values
for `input_shape` or `input_shape`.
ValueError: if `input_shape` and `output_shape` do not match.
"""
output_shape = list(output_shape)
msg = 'total size of new array must be unchanged'
@@ -386,13 +381,11 @@ class Reshape(Layer):
def call(self, inputs):
# In case the target shape is not fully defined,
# we need access to the shape of x.
# solution:
# 1) rely on x._keras_shape
# 2) fallback: K.int_shape
# we need access to the shape of `inputs`.
# solution: rely on `K.int_shape`.
target_shape = self.target_shape
if -1 in target_shape:
# target shape not fully defined
# Target shape not fully defined.
input_shape = None
try:
input_shape = K.int_shape(inputs)
@@ -720,6 +713,16 @@ class Lambda(Layer):
else:
output_shape = config['output_shape']
# If arguments were numpy array, they have been saved as
# list. We need to recover the ndarray
if 'arguments' in config:
for key in config['arguments']:
if isinstance(config['arguments'][key], dict):
arg_dict = config['arguments'][key]
if 'type' in arg_dict and arg_dict['type'] == 'ndarray':
# Overwrite the argument with its numpy translation
config['arguments'][key] = np.array(arg_dict['value'])
config['function'] = function
config['output_shape'] = output_shape
return cls(**config)
@@ -820,13 +823,13 @@ class Dense(Layer):
assert len(input_shape) >= 2
input_dim = input_shape[-1]
self.kernel = self.add_weight((input_dim, self.units),
self.kernel = self.add_weight(shape=(input_dim, self.units),
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
if self.use_bias:
self.bias = self.add_weight((self.units,),
self.bias = self.add_weight(shape=(self.units,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
+19 -5
Ver Arquivo
@@ -94,7 +94,7 @@ class Embedding(Layer):
def build(self, input_shape):
self.embeddings = self.add_weight(
(self.input_dim, self.output_dim),
shape=(self.input_dim, self.output_dim),
initializer=self.embeddings_initializer,
name='embeddings',
regularizer=self.embeddings_regularizer,
@@ -108,11 +108,25 @@ class Embedding(Layer):
return K.not_equal(inputs, 0)
def compute_output_shape(self, input_shape):
if not self.input_length:
input_length = input_shape[1]
if self.input_length is None:
return input_shape + (self.output_dim,)
else:
input_length = self.input_length
return (input_shape[0], input_length, self.output_dim)
# input_length can be tuple if input is 3D or higher
if isinstance(self.input_length, (list, tuple)):
in_lens = list(self.input_length)
else:
in_lens = [self.input_length]
if len(in_lens) != len(input_shape) - 1:
ValueError('"input_length" is %s, but received input has shape %s' %
(str(self.input_length), str(input_shape)))
else:
for i, (s1, s2) in enumerate(zip(in_lens, input_shape[1:])):
if s1 is not None and s2 is not None and s1 != s2:
ValueError('"input_length" is %s, but received input has shape %s' %
(str(self.input_length), str(input_shape)))
elif s1 is None:
in_lens[i] = s2
return (input_shape[0],) + tuple(in_lens) + (self.output_dim,)
def call(self, inputs):
if K.dtype(inputs) != 'int32':
+17 -71
Ver Arquivo
@@ -122,14 +122,14 @@ class LocallyConnected1D(Layer):
self.kernel_size[0] * input_dim,
self.filters)
self.kernel = self.add_weight(
self.kernel_shape,
shape=self.kernel_shape,
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
if self.use_bias:
self.bias = self.add_weight(
(output_length, self.filters),
shape=(output_length, self.filters),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
@@ -147,22 +147,11 @@ class LocallyConnected1D(Layer):
return (input_shape[0], length, self.filters)
def call(self, inputs):
stride = self.strides[0]
output_length, feature_dim, filters = self.kernel_shape
xs = []
for i in range(output_length):
slice_length = slice(i * stride,
i * stride + self.kernel_size[0])
xs.append(K.reshape(inputs[:, slice_length, :],
(1, -1, feature_dim)))
x_aggregate = K.concatenate(xs, axis=0)
# Shape: `(output_length, batch_size, filters)`.
output = K.batch_dot(x_aggregate, self.kernel)
output = K.permute_dimensions(output, (1, 0, 2))
output_length, _, filters = self.kernel_shape
output = K.local_conv1d(inputs, self.kernel, self.kernel_size, self.strides)
if self.use_bias:
output += K.reshape(self.bias, (1, output_length, filters))
output = K.bias_add(output, self.bias)
if self.activation is not None:
output = self.activation(output)
return output
@@ -325,13 +314,13 @@ class LocallyConnected2D(Layer):
self.kernel_shape = (output_row * output_col,
self.kernel_size[0] * self.kernel_size[1] * input_filter,
self.filters)
self.kernel = self.add_weight(self.kernel_shape,
self.kernel = self.add_weight(shape=self.kernel_shape,
initializer=self.kernel_initializer,
name='kernel',
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
if self.use_bias:
self.bias = self.add_weight((output_row, output_col, self.filters),
self.bias = self.add_weight(shape=(output_row, output_col, self.filters),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
@@ -363,62 +352,19 @@ class LocallyConnected2D(Layer):
return (input_shape[0], rows, cols, self.filters)
def call(self, inputs):
stride_row, stride_col = self.strides
_, feature_dim, filters = self.kernel_shape
_, _, filters = self.kernel_shape
if self.data_format == 'channels_first':
if K.backend() == 'theano':
output = []
for i in range(self.output_row):
for j in range(self.output_col):
slice_row = slice(i * stride_row,
i * stride_row + self.kernel_size[0])
slice_col = slice(j * stride_col,
j * stride_col + self.kernel_size[1])
x_flatten = K.reshape(inputs[:, :, slice_row, slice_col],
(1, -1, feature_dim))
output.append(K.dot(x_flatten,
self.kernel[i * self.output_col + j, :, :]))
output = K.concatenate(output, axis=0)
else:
xs = []
for i in range(self.output_row):
for j in range(self.output_col):
slice_row = slice(i * stride_row,
i * stride_row + self.kernel_size[0])
slice_col = slice(j * stride_col,
j * stride_col + self.kernel_size[1])
xs.append(K.reshape(inputs[:, :, slice_row, slice_col],
(1, -1, feature_dim)))
x_aggregate = K.concatenate(xs, axis=0)
output = K.batch_dot(x_aggregate, self.kernel)
output = K.reshape(output,
(self.output_row, self.output_col, -1, filters))
output = K.permute_dimensions(output, (2, 3, 0, 1))
elif self.data_format == 'channels_last':
xs = []
for i in range(self.output_row):
for j in range(self.output_col):
slice_row = slice(i * stride_row,
i * stride_row + self.kernel_size[0])
slice_col = slice(j * stride_col,
j * stride_col + self.kernel_size[1])
xs.append(K.reshape(inputs[:, slice_row, slice_col, :],
(1, -1, feature_dim)))
x_aggregate = K.concatenate(xs, axis=0)
output = K.batch_dot(x_aggregate, self.kernel)
output = K.reshape(output,
(self.output_row, self.output_col, -1, filters))
output = K.permute_dimensions(output, (2, 0, 1, 3))
output = K.local_conv2d(inputs,
self.kernel,
self.kernel_size,
self.strides,
(self.output_row, self.output_col),
self.data_format)
if self.use_bias:
if self.data_format == 'channels_first':
output += K.reshape(self.bias,
(1, filters, self.output_row, self.output_col))
elif self.data_format == 'channels_last':
output += K.reshape(self.bias,
(1, self.output_row, self.output_col, filters))
if self.data_format == 'channels_first' or self.data_format == 'channels_last':
output = K.bias_add(output, self.bias, data_format=self.data_format)
output = self.activation(output)
return output
+50 -48
Ver Arquivo
@@ -96,7 +96,7 @@ class BatchNormalization(Layer):
shape = (dim,)
if self.scale:
self.gamma = self.add_weight(shape,
self.gamma = self.add_weight(shape=shape,
name='gamma',
initializer=self.gamma_initializer,
regularizer=self.gamma_regularizer,
@@ -104,7 +104,7 @@ class BatchNormalization(Layer):
else:
self.gamma = None
if self.center:
self.beta = self.add_weight(shape,
self.beta = self.add_weight(shape=shape,
name='beta',
initializer=self.beta_initializer,
regularizer=self.beta_regularizer,
@@ -112,12 +112,12 @@ class BatchNormalization(Layer):
else:
self.beta = None
self.moving_mean = self.add_weight(
shape,
shape=shape,
name='moving_mean',
initializer=self.moving_mean_initializer,
trainable=False)
self.moving_variance = self.add_weight(
shape,
shape=shape,
name='moving_variance',
initializer=self.moving_variance_initializer,
trainable=False)
@@ -135,55 +135,57 @@ class BatchNormalization(Layer):
# Determines whether broadcasting is needed.
needs_broadcasting = (sorted(reduction_axes) != list(range(ndim))[:-1])
normed, mean, variance = K.normalize_batch_in_training(
def normalize_inference():
if needs_broadcasting:
# In this case we must explictly broadcast all parameters.
broadcast_moving_mean = K.reshape(self.moving_mean,
broadcast_shape)
broadcast_moving_variance = K.reshape(self.moving_variance,
broadcast_shape)
if self.center:
broadcast_beta = K.reshape(self.beta, broadcast_shape)
else:
broadcast_beta = None
if self.scale:
broadcast_gamma = K.reshape(self.gamma,
broadcast_shape)
else:
broadcast_gamma = None
return K.batch_normalization(
inputs,
broadcast_moving_mean,
broadcast_moving_variance,
broadcast_beta,
broadcast_gamma,
epsilon=self.epsilon)
else:
return K.batch_normalization(
inputs,
self.moving_mean,
self.moving_variance,
self.beta,
self.gamma,
epsilon=self.epsilon)
# If the learning phase is *static* and set to inference:
if training in {0, False}:
return normalize_inference()
# If the learning is either dynamic, or set to training:
normed_training, mean, variance = K.normalize_batch_in_training(
inputs, self.gamma, self.beta, reduction_axes,
epsilon=self.epsilon)
if training in {0, False}:
return normed
else:
self.add_update([K.moving_average_update(self.moving_mean,
mean,
self.momentum),
K.moving_average_update(self.moving_variance,
variance,
self.momentum)],
inputs)
def normalize_inference():
if needs_broadcasting:
# In this case we must explictly broadcast all parameters.
broadcast_moving_mean = K.reshape(self.moving_mean,
broadcast_shape)
broadcast_moving_variance = K.reshape(self.moving_variance,
broadcast_shape)
if self.center:
broadcast_beta = K.reshape(self.beta, broadcast_shape)
else:
broadcast_beta = None
if self.scale:
broadcast_gamma = K.reshape(self.gamma,
broadcast_shape)
else:
broadcast_gamma = None
return K.batch_normalization(
inputs,
broadcast_moving_mean,
broadcast_moving_variance,
broadcast_beta,
broadcast_gamma,
epsilon=self.epsilon)
else:
return K.batch_normalization(
inputs,
self.moving_mean,
self.moving_variance,
self.beta,
self.gamma,
epsilon=self.epsilon)
self.add_update([K.moving_average_update(self.moving_mean,
mean,
self.momentum),
K.moving_average_update(self.moving_variance,
variance,
self.momentum)],
inputs)
# Pick the normalized form corresponding to the training phase.
return K.in_train_phase(normed,
return K.in_train_phase(normed_training,
normalize_inference,
training=training)
+145 -96
Ver Arquivo
@@ -96,6 +96,8 @@ class Recurrent(Layer):
`[(input_dim, output_dim), (output_dim, output_dim), (output_dim,)]`.
return_sequences: Boolean. Whether to return the last output
in the output sequence, or the full sequence.
return_state: Boolean. Whether to return the last state
in addition to the output.
go_backwards: Boolean (default False).
If True, process the input sequence backwards and return the
reversed sequence.
@@ -139,6 +141,9 @@ class Recurrent(Layer):
(Optional) 2D tensors with shape `(batch_size, output_dim)`.
# Output shape
- if `return_state`: a list of tensors. The first tensor is
the output. The remaining tensors are the last states,
each with shape `(batch_size, units)`.
- if `return_sequences`: 3D tensor with shape
`(batch_size, timesteps, units)`.
- else, 2D tensor with shape `(batch_size, units)`.
@@ -170,14 +175,20 @@ class Recurrent(Layer):
To reset the states of your model, call `.reset_states()` on either
a specific layer, or on your entire model.
# Note on specifying initial states in RNNs
You can specify the initial state of RNN layers by calling them with
the keyword argument `initial_state`. The value of `initial_state`
should be a tensor or list of tensors representing the initial state
of the RNN layer.
# Note on specifying the initial state of RNNs
You can specify the initial state of RNN layers symbolically by
calling them with the keyword argument `initial_state`. The value of
`initial_state` should be a tensor or list of tensors representing
the initial state of the RNN layer.
You can specify the initial state of RNN layers numerically by
calling `reset_states` with the keyword argument `states`. The value of
`states` should be a numpy array or list of numpy arrays representing
the initial state of the RNN layer.
"""
def __init__(self, return_sequences=False,
return_state=False,
go_backwards=False,
stateful=False,
unroll=False,
@@ -185,12 +196,16 @@ class Recurrent(Layer):
**kwargs):
super(Recurrent, self).__init__(**kwargs)
self.return_sequences = return_sequences
self.return_state = return_state
self.go_backwards = go_backwards
if K.backend() == 'cntk' and stateful:
raise ValueError('Stateful RNN is not currently supported with CNTK.')
self.stateful = stateful
self.unroll = unroll
self.implementation = implementation
self.supports_masking = True
self.input_spec = InputSpec(ndim=3)
self.input_spec = [InputSpec(ndim=3)]
self.state_spec = None
self.dropout = 0
self.recurrent_dropout = 0
@@ -198,16 +213,27 @@ class Recurrent(Layer):
def compute_output_shape(self, input_shape):
if isinstance(input_shape, list):
input_shape = input_shape[0]
if self.return_sequences:
return (input_shape[0], input_shape[1], self.units)
output_shape = (input_shape[0], input_shape[1], self.units)
else:
return (input_shape[0], self.units)
output_shape = (input_shape[0], self.units)
if self.return_state:
state_shape = [(input_shape[0], self.units) for _ in self.states]
return [output_shape] + state_shape
else:
return output_shape
def compute_mask(self, inputs, mask):
if self.return_sequences:
return mask
if isinstance(mask, list):
mask = mask[0]
output_mask = mask if self.return_sequences else None
if self.return_state:
state_mask = [None for _ in self.states]
return [output_mask] + state_mask
else:
return None
return output_mask
def step(self, inputs, states):
raise NotImplementedError
@@ -215,14 +241,14 @@ class Recurrent(Layer):
def get_constants(self, inputs, training=None):
return []
def get_initial_states(self, inputs):
def get_initial_state(self, inputs):
# build an all-zero tensor of shape (samples, output_dim)
initial_state = K.zeros_like(inputs) # (samples, timesteps, input_dim)
initial_state = K.sum(initial_state, axis=(1, 2)) # (samples,)
initial_state = K.expand_dims(initial_state) # (samples, 1)
initial_state = K.tile(initial_state, [1, self.units]) # (samples, output_dim)
initial_states = [initial_state for _ in range(len(self.states))]
return initial_states
initial_state = [initial_state for _ in range(len(self.states))]
return initial_state
def preprocess_input(self, inputs, training=None):
return inputs
@@ -232,51 +258,63 @@ class Recurrent(Layer):
# and if it a Keras tensor,
# then add it to the inputs and temporarily
# modify the input spec to include the state.
if initial_state is not None:
if hasattr(initial_state, '_keras_history'):
# Compute the full input spec, including state
input_spec = self.input_spec
state_spec = self.state_spec
if not isinstance(state_spec, list):
state_spec = [state_spec]
self.input_spec = [input_spec] + state_spec
if initial_state is None:
return super(Recurrent, self).__call__(inputs, **kwargs)
# Compute the full inputs, including state
if not isinstance(initial_state, (list, tuple)):
initial_state = [initial_state]
inputs = [inputs] + list(initial_state)
if not isinstance(initial_state, (list, tuple)):
initial_state = [initial_state]
# Perform the call
output = super(Recurrent, self).__call__(inputs, **kwargs)
is_keras_tensor = hasattr(initial_state[0], '_keras_history')
for tensor in initial_state:
if hasattr(tensor, '_keras_history') != is_keras_tensor:
raise ValueError('The initial state of an RNN layer cannot be'
' specified with a mix of Keras tensors and'
' non-Keras tensors')
# Restore original input spec
self.input_spec = input_spec
return output
else:
kwargs['initial_state'] = initial_state
return super(Recurrent, self).__call__(inputs, **kwargs)
if is_keras_tensor:
# Compute the full input spec, including state
input_spec = self.input_spec
state_spec = self.state_spec
if not isinstance(input_spec, list):
input_spec = [input_spec]
if not isinstance(state_spec, list):
state_spec = [state_spec]
self.input_spec = input_spec + state_spec
def call(self, inputs, mask=None, initial_state=None, training=None):
# Compute the full inputs, including state
inputs = [inputs] + list(initial_state)
# Perform the call
output = super(Recurrent, self).__call__(inputs, **kwargs)
# Restore original input spec
self.input_spec = input_spec
return output
else:
kwargs['initial_state'] = initial_state
return super(Recurrent, self).__call__(inputs, **kwargs)
def call(self, inputs, mask=None, training=None, initial_state=None):
# input shape: `(samples, time (padded with zeros), input_dim)`
# note that the .build() method of subclasses MUST define
# self.input_spec and self.state_spec with complete input shapes.
if initial_state is not None:
if not isinstance(initial_state, (list, tuple)):
initial_states = [initial_state]
else:
initial_states = list(initial_state)
if isinstance(inputs, list):
initial_states = inputs[1:]
initial_state = inputs[1:]
inputs = inputs[0]
elif initial_state is not None:
pass
elif self.stateful:
initial_states = self.states
initial_state = self.states
else:
initial_states = self.get_initial_states(inputs)
initial_state = self.get_initial_state(inputs)
if len(initial_states) != len(self.states):
if isinstance(mask, list):
mask = mask[0]
if len(initial_state) != len(self.states):
raise ValueError('Layer has ' + str(len(self.states)) +
' states but was passed ' +
str(len(initial_states)) +
str(len(initial_state)) +
' initial states.')
input_shape = K.int_shape(inputs)
if self.unroll and input_shape[1] is None:
@@ -295,7 +333,7 @@ class Recurrent(Layer):
preprocessed_input = self.preprocess_input(inputs, training=None)
last_output, outputs, states = K.rnn(self.step,
preprocessed_input,
initial_states,
initial_state,
go_backwards=self.go_backwards,
mask=mask,
constants=constants,
@@ -313,17 +351,23 @@ class Recurrent(Layer):
outputs._uses_learning_phase = True
if self.return_sequences:
return outputs
output = outputs
else:
return last_output
output = last_output
def reset_states(self, states_value=None):
if self.return_state:
if not isinstance(states, (list, tuple)):
states = [states]
else:
states = list(states)
return [output] + states
else:
return output
def reset_states(self, states=None):
if not self.stateful:
raise AttributeError('Layer must be stateful.')
if not self.input_spec:
raise RuntimeError('Layer has never been called '
'and thus has no states.')
batch_size = self.input_spec.shape[0]
batch_size = self.input_spec[0].shape[0]
if not batch_size:
raise ValueError('If a RNN is stateful, it needs to know '
'its batch size. Specify the batch size '
@@ -335,34 +379,34 @@ class Recurrent(Layer):
'- If using the functional API, specify '
'the time dimension by passing a '
'`batch_shape` argument to your Input layer.')
if states_value is not None:
if not isinstance(states_value, (list, tuple)):
states_value = [states_value]
if len(states_value) != len(self.states):
raise ValueError('The layer has ' + str(len(self.states)) +
' states, but the `states_value` '
'argument passed '
'only has ' + str(len(states_value)) +
' entries')
# initialize state if None
if self.states[0] is None:
self.states = [K.zeros((batch_size, self.units))
for _ in self.states]
if not states_value:
return
for i, state in enumerate(self.states):
if states_value:
value = states_value[i]
elif states is None:
for state in self.states:
K.set_value(state, np.zeros((batch_size, self.units)))
else:
if not isinstance(states, (list, tuple)):
states = [states]
if len(states) != len(self.states):
raise ValueError('Layer ' + self.name + ' expects ' +
str(len(self.states)) + ' states, '
'but it received ' + str(len(states)) +
' state values. Input received: ' +
str(states))
for index, (value, state) in enumerate(zip(states, self.states)):
if value.shape != (batch_size, self.units):
raise ValueError(
'Expected state #' + str(i) +
' to have shape ' + str((batch_size, self.units)) +
' but got array with shape ' + str(value.shape))
else:
value = np.zeros((batch_size, self.units))
K.set_value(state, value)
raise ValueError('State ' + str(index) +
' is incompatible with layer ' +
self.name + ': expected shape=' +
str((batch_size, self.units)) +
', found shape=' + str(value.shape))
K.set_value(state, value)
def get_config(self):
config = {'return_sequences': self.return_sequences,
'return_state': self.return_state,
'go_backwards': self.go_backwards,
'stateful': self.stateful,
'unroll': self.unroll,
@@ -457,6 +501,7 @@ class SimpleRNN(Recurrent):
self.dropout = min(1., max(0., dropout))
self.recurrent_dropout = min(1., max(0., recurrent_dropout))
self.state_spec = InputSpec(shape=(None, self.units))
def build(self, input_shape):
if isinstance(input_shape, list):
@@ -464,26 +509,25 @@ class SimpleRNN(Recurrent):
batch_size = input_shape[0] if self.stateful else None
self.input_dim = input_shape[2]
self.input_spec = InputSpec(shape=(batch_size, None, self.input_dim))
self.state_spec = InputSpec(shape=(batch_size, self.units))
self.input_spec[0] = InputSpec(shape=(batch_size, None, self.input_dim))
self.states = [None]
if self.stateful:
self.reset_states()
self.kernel = self.add_weight((self.input_dim, self.units),
self.kernel = self.add_weight(shape=(self.input_dim, self.units),
name='kernel',
initializer=self.kernel_initializer,
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
self.recurrent_kernel = self.add_weight(
(self.units, self.units),
shape=(self.units, self.units),
name='recurrent_kernel',
initializer=self.recurrent_initializer,
regularizer=self.recurrent_regularizer,
constraint=self.recurrent_constraint)
if self.use_bias:
self.bias = self.add_weight((self.units,),
self.bias = self.add_weight(shape=(self.units,),
name='bias',
initializer=self.bias_initializer,
regularizer=self.bias_regularizer,
@@ -676,6 +720,7 @@ class GRU(Recurrent):
self.dropout = min(1., max(0., dropout))
self.recurrent_dropout = min(1., max(0., recurrent_dropout))
self.state_spec = InputSpec(shape=(None, self.units))
def build(self, input_shape):
if isinstance(input_shape, list):
@@ -683,29 +728,28 @@ class GRU(Recurrent):
batch_size = input_shape[0] if self.stateful else None
self.input_dim = input_shape[2]
self.input_spec = InputSpec(shape=(batch_size, None, self.input_dim))
self.state_spec = InputSpec(shape=(batch_size, self.units))
self.input_spec[0] = InputSpec(shape=(batch_size, None, self.input_dim))
self.states = [None]
if self.stateful:
self.reset_states()
self.kernel = self.add_weight((self.input_dim, self.units * 3),
self.kernel = self.add_weight(shape=(self.input_dim, self.units * 3),
name='kernel',
initializer=self.kernel_initializer,
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
self.recurrent_kernel = self.add_weight(
(self.units, self.units * 3),
shape=(self.units, self.units * 3),
name='recurrent_kernel',
initializer=self.recurrent_initializer,
regularizer=self.recurrent_regularizer,
constraint=self.recurrent_constraint)
if self.use_bias:
self.bias = self.add_weight((self.units * 3,),
self.bias = self.add_weight(shape=(self.units * 3,),
name='bias',
initializer='zero',
initializer=self.bias_initializer,
regularizer=self.bias_regularizer,
constraint=self.bias_constraint)
else:
@@ -955,6 +999,8 @@ class LSTM(Recurrent):
self.dropout = min(1., max(0., dropout))
self.recurrent_dropout = min(1., max(0., recurrent_dropout))
self.state_spec = [InputSpec(shape=(None, self.units)),
InputSpec(shape=(None, self.units))]
def build(self, input_shape):
if isinstance(input_shape, list):
@@ -962,36 +1008,39 @@ class LSTM(Recurrent):
batch_size = input_shape[0] if self.stateful else None
self.input_dim = input_shape[2]
self.input_spec = InputSpec(shape=(batch_size, None, self.input_dim))
self.state_spec = [InputSpec(shape=(batch_size, self.units)),
InputSpec(shape=(batch_size, self.units))]
self.input_spec[0] = InputSpec(shape=(batch_size, None, self.input_dim))
self.states = [None, None]
if self.stateful:
self.reset_states()
self.kernel = self.add_weight((self.input_dim, self.units * 4),
self.kernel = self.add_weight(shape=(self.input_dim, self.units * 4),
name='kernel',
initializer=self.kernel_initializer,
regularizer=self.kernel_regularizer,
constraint=self.kernel_constraint)
self.recurrent_kernel = self.add_weight(
(self.units, self.units * 4),
shape=(self.units, self.units * 4),
name='recurrent_kernel',
initializer=self.recurrent_initializer,
regularizer=self.recurrent_regularizer,
constraint=self.recurrent_constraint)
if self.use_bias:
self.bias = self.add_weight((self.units * 4,),
if self.unit_forget_bias:
def bias_initializer(shape, *args, **kwargs):
return K.concatenate([
self.bias_initializer((self.units,), *args, **kwargs),
initializers.Ones()((self.units,), *args, **kwargs),
self.bias_initializer((self.units * 2,), *args, **kwargs),
])
else:
bias_initializer = self.bias_initializer
self.bias = self.add_weight(shape=(self.units * 4,),
name='bias',
initializer=self.bias_initializer,
initializer=bias_initializer,
regularizer=self.bias_regularizer,
constraint=self.bias_constraint)
if self.unit_forget_bias:
bias_value = np.zeros((self.units * 4,))
bias_value[self.units: self.units * 2] = 1.
K.set_value(self.bias, bias_value)
else:
self.bias = None
+23 -2
Ver Arquivo
@@ -161,7 +161,7 @@ def recurrent_args_preprocessor(args, kwargs):
kwargs.pop('forget_bias_init')
warnings.warn('The `forget_bias_init` argument '
'has been ignored. Use `unit_forget_bias=True` '
'instead to intialize with ones.', stacklevel=3)
'instead to initialize with ones.', stacklevel=3)
if 'input_dim' in kwargs:
input_length = kwargs.pop('input_length', None)
input_dim = kwargs.pop('input_dim')
@@ -461,7 +461,7 @@ def convlstm2d_args_preprocessor(args, kwargs):
else:
warnings.warn('The `forget_bias_init` argument '
'has been ignored. Use `unit_forget_bias=True` '
'instead to intialize with ones.', stacklevel=3)
'instead to initialize with ones.', stacklevel=3)
args, kwargs, _converted = conv2d_args_preprocessor(args, kwargs)
return args, kwargs, converted + _converted
@@ -602,3 +602,24 @@ legacy_model_constructor_support = generate_legacy_interface(
allowed_positional_args=None,
conversions=[('input', 'inputs'),
('output', 'outputs')])
legacy_input_support = generate_legacy_interface(
allowed_positional_args=None,
conversions=[('input_dtype', 'dtype')])
def add_weight_args_preprocessing(args, kwargs):
if len(args) > 1:
if isinstance(args[1], (tuple, list)):
kwargs['shape'] = args[1]
args = (args[0],) + args[2:]
if len(args) > 1:
if isinstance(args[1], six.string_types):
kwargs['name'] = args[1]
args = (args[0],) + args[2:]
return args, kwargs, []
legacy_add_weight_support = generate_legacy_interface(
allowed_positional_args=['name', 'shape'],
preprocessor=add_weight_args_preprocessing)
+12
Ver Arquivo
@@ -33,6 +33,18 @@ def hinge(y_true, y_pred):
return K.mean(K.maximum(1. - y_true * y_pred, 0.), axis=-1)
def categorical_hinge(y_true, y_pred):
pos = K.sum(y_true * y_pred, axis=-1)
neg = K.max((1. - y_true) * y_pred, axis=-1)
return K.maximum(0., neg - pos + 1.)
def logcosh(y_true, y_pred):
def cosh(x):
return (K.exp(x) + K.exp(-x)) / 2
return K.mean(K.log(cosh(y_pred - y_true)), axis=-1)
def categorical_crossentropy(y_true, y_pred):
return K.categorical_crossentropy(y_pred, y_true)
+6
Ver Arquivo
@@ -6,6 +6,7 @@ from .losses import mean_absolute_error
from .losses import mean_absolute_percentage_error
from .losses import mean_squared_logarithmic_error
from .losses import hinge
from .losses import logcosh
from .losses import squared_hinge
from .losses import categorical_crossentropy
from .losses import sparse_categorical_crossentropy
@@ -35,6 +36,11 @@ def sparse_categorical_accuracy(y_true, y_pred):
def top_k_categorical_accuracy(y_true, y_pred, k=5):
return K.mean(K.in_top_k(y_pred, K.argmax(y_true, axis=-1), k), axis=-1)
def sparse_top_k_categorical_accuracy(y_true, y_pred, k=5):
return K.mean(K.in_top_k(y_pred, K.cast(K.max(y_true, axis=-1), 'int32'), k), axis=-1)
# Aliases
mse = MSE = mean_squared_error
+81 -55
Ver Arquivo
@@ -74,7 +74,11 @@ def save_model(model, filepath, overwrite=True, include_optimizer=True):
# if obj is any numpy type
if type(obj).__module__ == np.__name__:
return obj.item()
if isinstance(obj, np.ndarray):
return {'type': type(obj),
'value': obj.tolist()}
else:
return obj.item()
# misc functions (e.g. loss function)
if callable(obj):
@@ -140,8 +144,8 @@ def save_model(model, filepath, overwrite=True, include_optimizer=True):
weight_values = K.batch_get_value(symbolic_weights)
weight_names = []
for i, (w, val) in enumerate(zip(symbolic_weights, weight_values)):
# Default values of symbolic_weights is /variable for theano
if K.backend() == 'theano':
# Default values of symbolic_weights is /variable for theano and cntk
if K.backend() == 'theano' or K.backend() == 'cntk':
if hasattr(w, 'name') and w.name != "/variable":
name = str(w.name)
else:
@@ -167,7 +171,7 @@ def save_model(model, filepath, overwrite=True, include_optimizer=True):
f.close()
def load_model(filepath, custom_objects=None):
def load_model(filepath, custom_objects=None, compile=True):
"""Loads a model saved via `save_model`.
# Arguments
@@ -175,12 +179,16 @@ def load_model(filepath, custom_objects=None):
custom_objects: Optional dictionary mapping names
(strings) to custom classes or functions to be
considered during deserialization.
compile: Boolean, whether to compile the model
after loading.
# Returns
A Keras model instance. If an optimizer was found
as part of the saved model, the model is already
compiled. Otherwise, the model is uncompiled and
a warning will be displayed.
a warning will be displayed. When `compile` is set
to False, the compilation is omitted without any
warning.
# Raises
ImportError: if h5py is not available.
@@ -229,56 +237,58 @@ def load_model(filepath, custom_objects=None):
if obj in custom_objects:
return custom_objects[obj]
return obj
with h5py.File(filepath, mode='r') as f:
# instantiate model
model_config = f.attrs.get('model_config')
if model_config is None:
raise ValueError('No model found in config file.')
model_config = json.loads(model_config.decode('utf-8'))
model = model_from_config(model_config, custom_objects=custom_objects)
f = h5py.File(filepath, mode='r')
# set weights
topology.load_weights_from_hdf5_group(f['model_weights'], model.layers)
# instantiate model
model_config = f.attrs.get('model_config')
if model_config is None:
raise ValueError('No model found in config file.')
model_config = json.loads(model_config.decode('utf-8'))
model = model_from_config(model_config, custom_objects=custom_objects)
# Early return if compilation is not required.
if not compile:
return model
# set weights
topology.load_weights_from_hdf5_group(f['model_weights'], model.layers)
# instantiate optimizer
training_config = f.attrs.get('training_config')
if training_config is None:
warnings.warn('No training configuration found in save file: '
'the model was *not* compiled. Compile it manually.')
return model
training_config = json.loads(training_config.decode('utf-8'))
optimizer_config = training_config['optimizer_config']
optimizer = optimizers.deserialize(optimizer_config,
custom_objects=custom_objects)
# instantiate optimizer
training_config = f.attrs.get('training_config')
if training_config is None:
warnings.warn('No training configuration found in save file: '
'the model was *not* compiled. Compile it manually.')
f.close()
return model
training_config = json.loads(training_config.decode('utf-8'))
optimizer_config = training_config['optimizer_config']
optimizer = optimizers.deserialize(optimizer_config,
custom_objects=custom_objects)
# Recover loss functions and metrics.
loss = convert_custom_objects(training_config['loss'])
metrics = convert_custom_objects(training_config['metrics'])
sample_weight_mode = training_config['sample_weight_mode']
loss_weights = training_config['loss_weights']
# Recover loss functions and metrics.
loss = convert_custom_objects(training_config['loss'])
metrics = convert_custom_objects(training_config['metrics'])
sample_weight_mode = training_config['sample_weight_mode']
loss_weights = training_config['loss_weights']
# Compile model.
model.compile(optimizer=optimizer,
loss=loss,
metrics=metrics,
loss_weights=loss_weights,
sample_weight_mode=sample_weight_mode)
# Compile model.
model.compile(optimizer=optimizer,
loss=loss,
metrics=metrics,
loss_weights=loss_weights,
sample_weight_mode=sample_weight_mode)
# Set optimizer weights.
if 'optimizer_weights' in f:
# Build train function (to get weight updates).
if isinstance(model, Sequential):
model.model._make_train_function()
else:
model._make_train_function()
optimizer_weights_group = f['optimizer_weights']
optimizer_weight_names = [n.decode('utf8') for n in optimizer_weights_group.attrs['weight_names']]
optimizer_weight_values = [optimizer_weights_group[n] for n in optimizer_weight_names]
model.optimizer.set_weights(optimizer_weight_values)
f.close()
# Set optimizer weights.
if 'optimizer_weights' in f:
# Build train function (to get weight updates).
if isinstance(model, Sequential):
model.model._make_train_function()
else:
model._make_train_function()
optimizer_weights_group = f['optimizer_weights']
optimizer_weight_names = [n.decode('utf8') for n in
optimizer_weights_group.attrs['weight_names']]
optimizer_weight_values = [optimizer_weights_group[n] for n in
optimizer_weight_names]
model.optimizer.set_weights(optimizer_weight_values)
return model
@@ -293,9 +303,12 @@ def model_from_config(config, custom_objects=None):
# Returns
A Keras model instance (uncompiled).
# Raises
TypeError: if `config` is not a dictionary.
"""
if isinstance(config, list):
raise TypeError('`model_fom_config` expects a dictionary, not a list. '
raise TypeError('`model_from_config` expects a dictionary, not a list. '
'Maybe you meant to use '
'`Sequential.from_config(config)`?')
return layer_module.deserialize(config, custom_objects=custom_objects)
@@ -744,7 +757,7 @@ class Sequential(Model):
optimizer: str (name of optimizer) or optimizer object.
See [optimizers](/optimizers).
loss: str (name of objective function) or objective function.
See [objectives](/objectives).
See [losses](/losses).
metrics: list of metrics to be evaluated by the model
during training and testing.
Typically you will use `metrics=['accuracy']`.
@@ -753,7 +766,8 @@ class Sequential(Model):
sample weighting (2D weights), set this to "temporal".
"None" defaults to sample-wise weights (1D).
**kwargs: for Theano backend, these are passed into K.function.
Ignored for Tensorflow backend.
When using the Tensorflow backend, these are passed into
`tf.Session.run`.
# Example
```python
@@ -774,11 +788,14 @@ class Sequential(Model):
**kwargs)
self.optimizer = self.model.optimizer
self.loss = self.model.loss
self.total_loss = self.model.total_loss
self.loss_weights = self.model.loss_weights
self.metrics = self.model.metrics
self.metrics_tensors = self.model.metrics_tensors
self.metrics_names = self.model.metrics_names
self.sample_weight_mode = self.model.sample_weight_mode
self.sample_weights = self.model.sample_weights
self.targets = self.model.targets
def fit(self, x, y, batch_size=32, epochs=10, verbose=1, callbacks=None,
validation_split=0., validation_data=None, shuffle=True,
@@ -1033,8 +1050,8 @@ class Sequential(Model):
- a tuple (inputs, targets, sample_weights).
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.
indefinitely. An epoch finishes when `steps_per_epoch`
batches have been seen by the model.
steps_per_epoch: Total number of steps (batches of samples)
to yield from `generator` before declaring one epoch
finished and starting the next epoch. It should typically
@@ -1087,7 +1104,7 @@ class Sequential(Model):
f.close()
model.fit_generator(generate_arrays_from_file('/my_file.txt'),
samples_per_epoch=10000, epochs=10)
steps_per_epoch=1000, epochs=10)
```
"""
if self.model is None:
@@ -1227,6 +1244,15 @@ class Sequential(Model):
@classmethod
def legacy_from_config(cls, config, layer_cache=None):
"""Load a model from a legacy configuration.
# Arguments
config: dictionary with configuration.
layer_cache: cache to draw pre-existing layer.
# Returns
The loaded Model.
"""
if not layer_cache:
layer_cache = {}
+26 -2
Ver Arquivo
@@ -1,5 +1,6 @@
from __future__ import absolute_import
import six
import copy
from six.moves import zip
from . import backend as K
@@ -11,8 +12,31 @@ if K.backend() == 'tensorflow':
def clip_norm(g, c, n):
if c > 0:
g = K.switch(n >= c, g * c / n, g)
if c <= 0: # if clipnorm == 0 no need to add ops to the graph
return g
# tf require using a special op to multiply IndexedSliced by scalar
if K.backend() == 'tensorflow':
condition = n >= c
then_expression = tf.scalar_mul(c / n, g)
else_expression = g
# saving the shape to avoid converting sparse tensor to dense
if isinstance(then_expression, tf.Tensor):
g_shape = copy.copy(then_expression.get_shape())
elif isinstance(then_expression, tf.IndexedSlices):
g_shape = copy.copy(then_expression.dense_shape)
if condition.dtype != tf.bool:
condition = tf.cast(condition, 'bool')
g = tf.cond(condition,
lambda: then_expression,
lambda: else_expression)
if isinstance(then_expression, tf.Tensor):
g.set_shape(g_shape)
elif isinstance(then_expression, tf.IndexedSlices):
g._dense_shape = g_shape
else:
g = K.switch(K.greater_equal(n, c), g * c / n, g)
return g
+112 -39
Ver Arquivo
@@ -13,6 +13,8 @@ from six.moves import range
import os
import threading
import warnings
import multiprocessing.pool
from functools import partial
from .. import backend as K
@@ -325,9 +327,9 @@ def load_img(path, grayscale=False, target_size=None):
if img.mode != 'RGB':
img = img.convert('RGB')
if target_size:
wh_tuple = (target_size[1], target_size[0])
if img.size != wh_tuple:
img = img.resize(wh_tuple)
hw_tuple = (target_size[1], target_size[0])
if img.size != hw_tuple:
img = img.resize(hw_tuple)
return img
@@ -346,6 +348,7 @@ class ImageDataGenerator(object):
featurewise_std_normalization: divide inputs by std of the dataset.
samplewise_std_normalization: divide each input by its std.
zca_whitening: apply ZCA whitening.
zca_epsilon: epsilon for ZCA whitening. Default is 1e-6.
rotation_range: degrees (0 to 180).
width_shift_range: fraction of total width.
height_shift_range: fraction of total height.
@@ -382,6 +385,7 @@ class ImageDataGenerator(object):
featurewise_std_normalization=False,
samplewise_std_normalization=False,
zca_whitening=False,
zca_epsilon=1e-6,
rotation_range=0.,
width_shift_range=0.,
height_shift_range=0.,
@@ -402,6 +406,7 @@ class ImageDataGenerator(object):
self.featurewise_std_normalization = featurewise_std_normalization
self.samplewise_std_normalization = samplewise_std_normalization
self.zca_whitening = zca_whitening
self.zca_epsilon = zca_epsilon
self.rotation_range = rotation_range
self.width_shift_range = width_shift_range
self.height_shift_range = height_shift_range
@@ -443,7 +448,7 @@ class ImageDataGenerator(object):
'Received arg: ', zoom_range)
def flow(self, x, y=None, batch_size=32, shuffle=True, seed=None,
save_to_dir=None, save_prefix='', save_format='jpeg'):
save_to_dir=None, save_prefix='', save_format='png'):
return NumpyArrayIterator(
x, y, self,
batch_size=batch_size,
@@ -460,7 +465,7 @@ class ImageDataGenerator(object):
batch_size=32, shuffle=True, seed=None,
save_to_dir=None,
save_prefix='',
save_format='jpeg',
save_format='png',
follow_links=False):
return DirectoryIterator(
directory, self,
@@ -633,8 +638,8 @@ class ImageDataGenerator(object):
if x.ndim != 4:
raise ValueError('Input to `.fit()` should have rank 4. '
'Got array with shape: ' + str(x.shape))
if x.shape[self.channel_axis] not in {1, 3, 4}:
raise ValueError(
if x.shape[self.channel_axis] not in {3, 4}:
warnings.warn(
'Expected input to be images (as Numpy array) '
'following the data format convention "' + self.data_format + '" '
'(channels on axis ' + str(self.channel_axis) + '), i.e. expected '
@@ -671,7 +676,7 @@ class ImageDataGenerator(object):
flat_x = np.reshape(x, (x.shape[0], x.shape[1] * x.shape[2] * x.shape[3]))
sigma = np.dot(flat_x.T, flat_x) / flat_x.shape[0]
u, s, _ = linalg.svd(sigma)
self.principal_components = np.dot(np.dot(u, np.diag(1. / np.sqrt(s + 10e-7))), u.T)
self.principal_components = np.dot(np.dot(u, np.diag(1. / np.sqrt(s + self.zca_epsilon))), u.T)
class Iterator(object):
@@ -752,7 +757,7 @@ class NumpyArrayIterator(Iterator):
def __init__(self, x, y, image_data_generator,
batch_size=32, shuffle=False, seed=None,
data_format=None,
save_to_dir=None, save_prefix='', save_format='jpeg'):
save_to_dir=None, save_prefix='', save_format='png'):
if y is not None and len(x) != len(y):
raise ValueError('X (images tensor) and y (labels) '
'should have the same length. '
@@ -818,6 +823,73 @@ class NumpyArrayIterator(Iterator):
return batch_x, batch_y
def _count_valid_files_in_directory(directory, white_list_formats, follow_links):
"""Count files with extension in `white_list_formats` contained in a directory.
# Arguments
directory: absolute path to the directory containing files to be counted
white_list_formats: set of strings containing allowed extensions for
the files to be counted.
# Returns
the count of files with extension in `white_list_formats` contained in
the directory.
"""
def _recursive_list(subpath):
return sorted(os.walk(subpath, followlinks=follow_links), key=lambda tpl: tpl[0])
samples = 0
for root, _, files in _recursive_list(directory):
for fname in files:
is_valid = False
for extension in white_list_formats:
if fname.lower().endswith('.' + extension):
is_valid = True
break
if is_valid:
samples += 1
return samples
def _list_valid_filenames_in_directory(directory, white_list_formats,
class_indices, follow_links):
"""List paths of files in `subdir` relative from `directory` whose extensions are in `white_list_formats`.
# Arguments
directory: absolute path to a directory containing the files to list.
The directory name is used as class label and must be a key of `class_indices`.
white_list_formats: set of strings containing allowed extensions for
the files to be counted.
class_indices: dictionary mapping a class name to its index.
# Returns
classes: a list of class indices
filenames: the path of valid files in `directory`, relative from
`directory`'s parent (e.g., if `directory` is "dataset/class1",
the filenames will be ["class1/file1.jpg", "class1/file2.jpg", ...]).
"""
def _recursive_list(subpath):
return sorted(os.walk(subpath, followlinks=follow_links), key=lambda tpl: tpl[0])
classes = []
filenames = []
subdir = os.path.basename(directory)
basedir = os.path.dirname(directory)
for root, _, files in _recursive_list(directory):
for fname in files:
is_valid = False
for extension in white_list_formats:
if fname.lower().endswith('.' + extension):
is_valid = True
break
if is_valid:
classes.append(class_indices[subdir])
# add filename relative to directory
absolute_path = os.path.join(root, fname)
filenames.append(os.path.relpath(absolute_path, basedir))
return classes, filenames
class DirectoryIterator(Iterator):
"""Iterator capable of reading images from a directory on disk.
@@ -838,6 +910,8 @@ class DirectoryIterator(Iterator):
`"binary"`: binary targets (if there are only two classes),
`"categorical"`: categorical targets,
`"sparse"`: integer targets,
`"input"`: targets are images identical to input images (mainly
used to work with autoencoders),
`None`: no targets get yielded (only input images are yielded).
batch_size: Integer, size of a batch.
shuffle: Boolean, whether to shuffle the data between epochs.
@@ -858,7 +932,7 @@ class DirectoryIterator(Iterator):
classes=None, class_mode='categorical',
batch_size=32, shuffle=True, seed=None,
data_format=None,
save_to_dir=None, save_prefix='', save_format='jpeg',
save_to_dir=None, save_prefix='', save_format='png',
follow_links=False):
if data_format is None:
data_format = K.image_data_format()
@@ -881,10 +955,12 @@ class DirectoryIterator(Iterator):
else:
self.image_shape = (1,) + self.target_size
self.classes = classes
if class_mode not in {'categorical', 'binary', 'sparse', None}:
if class_mode not in {'categorical', 'binary', 'sparse',
'input', None}:
raise ValueError('Invalid class_mode:', class_mode,
'; expected one of "categorical", '
'"binary", "sparse", or None.')
'"binary", "sparse", "input"'
' or None.')
self.class_mode = class_mode
self.save_to_dir = save_to_dir
self.save_prefix = save_prefix
@@ -906,38 +982,33 @@ class DirectoryIterator(Iterator):
def _recursive_list(subpath):
return sorted(os.walk(subpath, followlinks=follow_links), key=lambda tpl: tpl[0])
for subdir in classes:
subpath = os.path.join(directory, subdir)
for root, _, files in _recursive_list(subpath):
for fname in files:
is_valid = False
for extension in white_list_formats:
if fname.lower().endswith('.' + extension):
is_valid = True
break
if is_valid:
self.samples += 1
pool = multiprocessing.pool.ThreadPool()
function_partial = partial(_count_valid_files_in_directory,
white_list_formats=white_list_formats,
follow_links=follow_links)
self.samples = sum(pool.map(function_partial,
(os.path.join(directory, subdir)
for subdir in classes)))
print('Found %d images belonging to %d classes.' % (self.samples, self.num_class))
# second, build an index of the images in the different class subfolders
results = []
self.filenames = []
self.classes = np.zeros((self.samples,), dtype='int32')
i = 0
for subdir in classes:
subpath = os.path.join(directory, subdir)
for root, _, files in _recursive_list(subpath):
for fname in files:
is_valid = False
for extension in white_list_formats:
if fname.lower().endswith('.' + extension):
is_valid = True
break
if is_valid:
self.classes[i] = self.class_indices[subdir]
i += 1
# add filename relative to directory
absolute_path = os.path.join(root, fname)
self.filenames.append(os.path.relpath(absolute_path, directory))
for dirpath in (os.path.join(directory, subdir) for subdir in classes):
results.append(pool.apply_async(_list_valid_filenames_in_directory,
(dirpath, white_list_formats,
self.class_indices, follow_links)))
for res in results:
classes, filenames = res.get()
self.classes[i:i + len(classes)] = classes
self.filenames += filenames
i += len(classes)
pool.close()
pool.join()
super(DirectoryIterator, self).__init__(self.samples, batch_size, shuffle, seed)
def next(self):
@@ -972,7 +1043,9 @@ class DirectoryIterator(Iterator):
format=self.save_format)
img.save(os.path.join(self.save_to_dir, fname))
# build batch of labels
if self.class_mode == 'sparse':
if self.class_mode == 'input':
batch_y = batch_x.copy()
elif self.class_mode == 'sparse':
batch_y = self.classes[index_array]
elif self.class_mode == 'binary':
batch_y = self.classes[index_array].astype(K.floatx())
+5 -4
Ver Arquivo
@@ -11,6 +11,7 @@ import sys
import numpy as np
from six.moves import range
from six.moves import zip
from collections import OrderedDict
import warnings
if sys.version_info < (3,):
@@ -22,7 +23,7 @@ else:
def text_to_word_sequence(text,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True, split=" "):
"""Converts a text to a sequence of word indices.
"""Converts a text to a sequence of words (or tokens).
# Arguments
text: Input text (string).
@@ -31,7 +32,7 @@ def text_to_word_sequence(text,
split: Sentence split marker (string).
# Returns
A list of integer word indices.
A list of words (or tokens).
"""
if lower:
text = text.lower()
@@ -68,7 +69,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.
char_level: if True, every character will be treated as a token.
By default, all punctuation is removed, turning the texts into
space-separated sequences of words
@@ -92,7 +93,7 @@ class Tokenizer(object):
if kwargs:
raise TypeError('Unrecognized keyword arguments: ' + str(kwargs))
self.word_counts = {}
self.word_counts = OrderedDict()
self.word_docs = {}
self.filters = filters
self.split = split
+3 -2
Ver Arquivo
@@ -70,7 +70,7 @@ def convert_kernel(kernel):
Also works reciprocally, since the transformation is its own inverse.
# Arguments
kernel: Numpy array (4D or 5D).
kernel: Numpy array (3D, 4D or 5D).
# Returns
The converted kernel.
@@ -78,7 +78,8 @@ def convert_kernel(kernel):
# Raises
ValueError: in case of invalid kernel shape or invalid data_format.
"""
if not 4 <= kernel.ndim <= 5:
kernel = np.asarray(kernel)
if not 3 <= kernel.ndim <= 5:
raise ValueError('Invalid kernel shape:', kernel.shape)
slices = [slice(None, None, -1) for _ in range(kernel.ndim)]
no_flip = (slice(None, None), slice(None, None))
+17 -11
Ver Arquivo
@@ -2,7 +2,6 @@
from __future__ import absolute_import
from __future__ import print_function
import functools
import tarfile
import zipfile
import os
@@ -36,8 +35,10 @@ if sys.version_info[0] == 2:
data: `data` argument passed to `urlopen`.
"""
def chunk_read(response, chunk_size=8192, reporthook=None):
total_size = response.info().get('Content-Length').strip()
total_size = int(total_size)
content_type = response.info().get('Content-Length')
total_size = -1
if content_type is not None:
total_size = int(content_type.strip())
count = 0
while 1:
chunk = response.read(chunk_size)
@@ -186,19 +187,24 @@ def get_file(fname,
if download:
print('Downloading data from', origin)
progbar = None
def dl_progress(count, block_size, total_size, progbar=None):
if progbar is None:
progbar = Progbar(total_size)
class ProgressTracker(object):
# Maintain progbar for the lifetime of download.
# This design was chosen for Python 2.7 compatibility.
progbar = None
def dl_progress(count, block_size, total_size):
if ProgressTracker.progbar is None:
if total_size is -1:
total_size = None
ProgressTracker.progbar = Progbar(total_size)
else:
progbar.update(count * block_size)
ProgressTracker.progbar.update(count * block_size)
error_msg = 'URL fetch failure on {}: {} -- {}'
try:
try:
urlretrieve(origin, fpath,
functools.partial(dl_progress, progbar=progbar))
urlretrieve(origin, fpath, dl_progress)
except URLError as e:
raise Exception(error_msg.format(origin, e.errno, e.reason))
except HTTPError as e:
@@ -207,7 +213,7 @@ def get_file(fname,
if os.path.exists(fpath):
os.remove(fpath)
raise
progbar = None
ProgressTracker.progbar = None
if untar:
if not os.path.exists(untar_fpath):
+32 -26
Ver Arquivo
@@ -27,8 +27,8 @@ class CustomObjectScope(object):
Consider a custom object `MyObject`
```python
with CustomObjectScope({"MyObject":MyObject}):
layer = Dense(..., W_regularizer="MyObject")
with CustomObjectScope({'MyObject':MyObject}):
layer = Dense(..., kernel_regularizer='MyObject')
# save, load, etc. will recognize custom object by name
```
"""
@@ -63,8 +63,8 @@ def custom_object_scope(*args):
Consider a custom object `MyObject`
```python
with custom_object_scope({"MyObject":MyObject}):
layer = Dense(..., W_regularizer="MyObject")
with custom_object_scope({'MyObject':MyObject}):
layer = Dense(..., kernel_regularizer='MyObject')
# save, load, etc. will recognize custom object by name
```
@@ -89,7 +89,7 @@ def get_custom_objects():
```python
get_custom_objects().clear()
get_custom_objects()["MyObject"] = MyObject
get_custom_objects()['MyObject'] = MyObject
```
# Returns
@@ -133,17 +133,20 @@ def deserialize_keras_object(identifier, module_objects=None,
': ' + class_name)
if hasattr(cls, 'from_config'):
arg_spec = inspect.getargspec(cls.from_config)
custom_objects = custom_objects or {}
if 'custom_objects' in arg_spec.args:
custom_objects = custom_objects or {}
return cls.from_config(config['config'],
custom_objects=dict(list(_GLOBAL_CUSTOM_OBJECTS.items()) +
list(custom_objects.items())))
return cls.from_config(config['config'])
with CustomObjectScope(custom_objects):
return cls.from_config(config['config'])
else:
# Then `cls` may be a function returning a class.
# in this case by convention `config` holds
# the kwargs of the function.
return cls(**config['config'])
custom_objects = custom_objects or {}
with CustomObjectScope(custom_objects):
return cls(**config['config'])
elif isinstance(identifier, six.string_types):
function_name = identifier
if custom_objects and function_name in custom_objects:
@@ -153,7 +156,7 @@ def deserialize_keras_object(identifier, module_objects=None,
else:
fn = module_objects.get(function_name)
if fn is None:
raise ValueError('Unknown ' + printable_module_name,
raise ValueError('Unknown ' + printable_module_name +
':' + function_name)
return fn
else:
@@ -208,12 +211,14 @@ class Progbar(object):
"""Displays a progress bar.
# Arguments
target: Total number of steps expected.
target: Total number of steps expected, None if unknown.
interval: Minimum visual progress update interval (in seconds).
"""
def __init__(self, target, width=30, verbose=1, interval=0.05):
self.width = width
if target is None:
target = -1
self.target = target
self.sum_values = {}
self.unique_values = []
@@ -253,21 +258,22 @@ class Progbar(object):
sys.stdout.write('\b' * prev_total_width)
sys.stdout.write('\r')
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)
if prog_width > 0:
bar += ('=' * (prog_width - 1))
if current < self.target:
bar += '>'
else:
bar += '='
bar += ('.' * (self.width - prog_width))
bar += ']'
sys.stdout.write(bar)
self.total_width = len(bar)
if self.target is not -1:
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)
if prog_width > 0:
bar += ('=' * (prog_width - 1))
if current < self.target:
bar += '>'
else:
bar += '='
bar += ('.' * (self.width - prog_width))
bar += ']'
sys.stdout.write(bar)
self.total_width = len(bar)
if current:
time_per_unit = (now - self.start) / current
@@ -275,7 +281,7 @@ class Progbar(object):
time_per_unit = 0
eta = time_per_unit * (self.target - current)
info = ''
if current < self.target:
if current < self.target and self.target is not -1:
info += ' - ETA: %ds' % eta
else:
info += ' - %ds' % (now - self.start)
+7 -2
Ver Arquivo
@@ -63,8 +63,13 @@ class HDF5Matrix(object):
def __getitem__(self, key):
if isinstance(key, slice):
if key.stop + self.start <= self.end:
idx = slice(key.start + self.start, key.stop + self.start)
start, stop = key.start, key.stop
if start is None:
start = 0
if stop is None:
stop = self.data.shape[0]
if stop + self.start <= self.end:
idx = slice(start + self.start, stop + self.start)
else:
raise IndexError
elif isinstance(key, int):
+13 -38
Ver Arquivo
@@ -19,8 +19,11 @@ def print_summary(model, line_length=None, positions=None):
else:
sequential_like = True
for v in model.nodes_by_depth.values():
if len(v) > 1:
if (len(v) > 1) or (len(v) == 1 and len(v[0].inbound_layers) > 1):
# if the model has multiple nodes or if the nodes have multiple inbound_layers
# the model is no longer sequential
sequential_like = False
break
if sequential_like:
line_length = line_length or 65
@@ -75,12 +78,10 @@ def print_summary(model, line_length=None, positions=None):
except AttributeError:
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 node in layer.inbound_nodes:
if relevant_nodes and node not in relevant_nodes:
# node is not 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]
@@ -111,7 +112,10 @@ def print_summary(model, line_length=None, positions=None):
else:
print('_' * line_length)
trainable_count, non_trainable_count = count_total_params(layers, layer_set=None)
trainable_count = int(
np.sum([K.count_params(p) for p in set(model.trainable_weights)]))
non_trainable_count = int(
np.sum([K.count_params(p) for p in set(model.non_trainable_weights)]))
print('Total params: {:,}'.format(trainable_count + non_trainable_count))
print('Trainable params: {:,}'.format(trainable_count))
@@ -119,35 +123,6 @@ def print_summary(model, line_length=None, positions=None):
print('_' * line_length)
def count_total_params(layers, layer_set=None):
"""Counts the number of parameters in a list of layers.
# Arguments
layers: list of layers.
layer_set: set of layers already seen
(so that we don't count their weights twice).
# Returns
A tuple (count of trainable weights, count of non-trainable weights.)
"""
if layer_set is None:
layer_set = set()
trainable_count = 0
non_trainable_count = 0
for layer in layers:
if layer in layer_set:
continue
layer_set.add(layer)
if hasattr(layer, 'layers'):
t, nt = count_total_params(layer.layers, layer_set)
trainable_count += t
non_trainable_count += nt
else:
trainable_count += np.sum([K.count_params(p) for p in layer.trainable_weights])
non_trainable_count += np.sum([K.count_params(p) for p in layer.non_trainable_weights])
return int(trainable_count), int(non_trainable_count)
def convert_all_kernels_in_model(model):
"""Converts all convolution kernels in a model from Theano to TensorFlow.
@@ -192,7 +167,7 @@ def convert_dense_weights_data_format(dense,
came before the target `Dense` layer.
target_data_format: One of "channels_last", "channels_first".
Set it "channels_last"
if converting a "chnnels_first" model to "channels_last",
if converting a "channels_first" model to "channels_last",
or reciprocally.
"""
assert target_data_format in {'channels_last', 'channels_first'}
+42 -11
Ver Arquivo
@@ -5,26 +5,43 @@ try:
# pydot-ng is a fork of pydot that is better maintained.
import pydot_ng as pydot
except ImportError:
# Fall back on pydot if necessary.
# pydotplus is an improved version of pydot
try:
import pydot
import pydotplus as pydot
except ImportError:
pydot = None
# Fall back on pydot if necessary.
try:
import pydot
except ImportError:
pydot = None
def _check_pydot():
if not (pydot and pydot.find_graphviz()):
try:
# Attempt to create an image of a blank graph
# to check the pydot/graphviz installation.
pydot.Dot.create(pydot.Dot())
except Exception:
# pydot raises a generic Exception here,
# so no specific class can be caught.
raise ImportError('Failed to import pydot. You must install pydot'
' and graphviz for `pydotprint` to work.')
def model_to_dot(model, show_shapes=False, show_layer_names=True):
"""Converts a Keras model to dot format.
def model_to_dot(model,
show_shapes=False,
show_layer_names=True,
rankdir='TB'):
"""Convert a Keras model to dot format.
# Arguments
model: A Keras model instance.
show_shapes: whether to display shape information.
show_layer_names: whether to display layer names.
rankdir: `rankdir` argument passed to PyDot,
a string specifying the format of the plot:
'TB' creates a vertical plot;
'LR' creates a horizontal plot.
# Returns
A `pydot.Dot` instance representing the Keras model.
@@ -34,7 +51,7 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True):
_check_pydot()
dot = pydot.Dot()
dot.set('rankdir', 'TB')
dot.set('rankdir', rankdir)
dot.set('concentrate', True)
dot.set_node_defaults(shape='record')
@@ -75,8 +92,9 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True):
[str(ishape) for ishape in layer.input_shapes])
else:
inputlabels = 'multiple'
label = '%s\n|{input:|output:}|{{%s}|{%s}}' % (label, inputlabels, outputlabels)
label = '%s\n|{input:|output:}|{{%s}|{%s}}' % (label,
inputlabels,
outputlabels)
node = pydot.Node(layer_id, label=label)
dot.add_node(node)
@@ -96,8 +114,21 @@ def model_to_dot(model, show_shapes=False, show_layer_names=True):
def plot_model(model,
to_file='model.png',
show_shapes=False,
show_layer_names=True):
dot = model_to_dot(model, show_shapes, show_layer_names)
show_layer_names=True,
rankdir='TB'):
"""Converts a Keras model to dot format and save to a file.
# Arguments
model: A Keras model instance
to_file: File name of the plot image.
show_shapes: whether to display shape information.
show_layer_names: whether to display layer names.
rankdir: `rankdir` argument passed to PyDot,
a string specifying the format of the plot:
'TB' creates a vertical plot;
'LR' creates a horizontal plot.
"""
dot = model_to_dot(model, show_shapes, show_layer_names, rankdir)
_, extension = os.path.splitext(to_file)
if not extension:
extension = 'png'
+1 -1
Ver Arquivo
@@ -90,7 +90,7 @@ class BaseWrapper(object):
"""Gets parameters for this estimator.
# Arguments
**params: ignored (exists for API compatiblity).
**params: ignored (exists for API compatibility).
# Returns
Dictionary of parameter names mapped to their values.
+2 -2
Ver Arquivo
@@ -3,12 +3,12 @@ from setuptools import find_packages
setup(name='Keras',
version='2.0.3',
version='2.0.5',
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/2.0.3',
download_url='https://github.com/fchollet/keras/tarball/2.0.5',
license='MIT',
install_requires=['theano', 'pyyaml', 'six'],
extras_require={
@@ -6,7 +6,8 @@ import string
from keras.utils.test_utils import get_test_data, keras_test
from keras.utils.np_utils import to_categorical
from keras.models import Sequential
from keras import layers
from keras import layers, optimizers
import keras.backend as K
import keras
@@ -204,5 +205,14 @@ def test_masked_temporal():
ground_truth = -np.log(0.5)
assert(np.abs(history.history['loss'][-1] - ground_truth) < 0.06)
@pytest.mark.skipif(K.backend() != 'tensorflow', reason='Requires TF backend')
@keras_test
def test_embedding_with_clipnorm():
model = Sequential()
model.add(layers.Embedding(input_dim=1, output_dim=1))
model.compile(optimizer=optimizers.SGD(clipnorm=0.1), loss='mse')
model.fit(np.array([[0]]), np.array([[[0.5]]]), epochs=1)
if __name__ == '__main__':
pytest.main([__file__])
+4
Ver Arquivo
@@ -136,6 +136,10 @@ def test_elu():
assert_allclose(result, test_values, rtol=1e-05)
negative_values = np.array([[-1, -2]], dtype=K.floatx())
# cntk can't rebind the input shape, so create the model again to test different batch size
if (K.backend() == 'cntk'):
x2 = K.placeholder(ndim=2)
f = K.function([x2], [activations.elu(x2, 0.5)])
result = f([negative_values])[0]
true_result = (np.exp(negative_values) - 1) / 2
+65 -1
Ver Arquivo
@@ -11,12 +11,24 @@ def test_resnet50():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_resnet50_notop():
model = applications.ResNet50(weights=None, include_top=False)
assert model.output_shape == (None, None, None, 2048)
@keras_test
def test_resnet50_notop_specified_input_shape():
input_shape = (3, 300, 300) if K.image_data_format() == 'channels_first' else (300, 300, 3)
model = applications.ResNet50(weights=None, include_top=False, input_shape=input_shape)
output_shape = (None, 2048, 1, 1) if K.image_data_format() == 'channels_first' else (None, 1, 1, 2048)
assert model.output_shape == output_shape
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_resnet50_pooling():
model = applications.ResNet50(weights=None,
include_top=False,
@@ -24,6 +36,16 @@ def test_resnet50_pooling():
assert model.output_shape == (None, 2048)
@keras_test
def test_resnet50_pooling_specified_input_shape():
input_shape = (3, 300, 300) if K.image_data_format() == 'channels_first' else (300, 300, 3)
model = applications.ResNet50(weights=None,
include_top=False,
pooling='avg',
input_shape=input_shape)
assert model.output_shape == (None, 2048)
@keras_test
def test_vgg16():
model = applications.VGG16(weights=None)
@@ -31,17 +53,36 @@ def test_vgg16():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_vgg16_notop():
model = applications.VGG16(weights=None, include_top=False)
assert model.output_shape == (None, None, None, 512)
@keras_test
def test_vgg16_notop_specified_input_shape():
input_shape = (3, 300, 300) if K.image_data_format() == 'channels_first' else (300, 300, 3)
model = applications.VGG16(weights=None, include_top=False, input_shape=input_shape)
output_shape = (None, 512, 9, 9) if K.image_data_format() == 'channels_first' else (None, 9, 9, 512)
assert model.output_shape == output_shape
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_vgg16_pooling():
model = applications.VGG16(weights=None, include_top=False, pooling='avg')
assert model.output_shape == (None, 512)
@keras_test
def test_vgg16_pooling_specified_input_shape():
input_shape = (3, 300, 300) if K.image_data_format() == 'channels_first' else (300, 300, 3)
model = applications.VGG16(weights=None, include_top=False, pooling='avg', input_shape=input_shape)
assert model.output_shape == (None, 512)
@keras_test
def test_vgg19():
model = applications.VGG19(weights=None)
@@ -49,17 +90,36 @@ def test_vgg19():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_vgg19_notop():
model = applications.VGG16(weights=None, include_top=False)
model = applications.VGG19(weights=None, include_top=False)
assert model.output_shape == (None, None, None, 512)
@keras_test
def test_vgg19_notop_specified_input_shape():
input_shape = (3, 300, 300) if K.image_data_format() == 'channels_first' else (300, 300, 3)
model = applications.VGG19(weights=None, include_top=False, input_shape=input_shape)
output_shape = (None, 512, 9, 9) if K.image_data_format() == 'channels_first' else (None, 9, 9, 512)
assert model.output_shape == output_shape
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_vgg19_pooling():
model = applications.VGG16(weights=None, include_top=False, pooling='avg')
assert model.output_shape == (None, 512)
@keras_test
def test_vgg19_pooling_specified_input_shape():
input_shape = (3, 300, 300) if K.image_data_format() == 'channels_first' else (300, 300, 3)
model = applications.VGG16(weights=None, include_top=False, pooling='avg', input_shape=input_shape)
assert model.output_shape == (None, 512)
@keras_test
@pytest.mark.skipif((K.backend() != 'tensorflow'),
reason='Requires tensorflow backend')
@@ -91,12 +151,16 @@ def test_inceptionv3():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_inceptionv3_notop():
model = applications.InceptionV3(weights=None, include_top=False)
assert model.output_shape == (None, None, None, 2048)
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support padding with non-concrete dimension")
def test_inceptionv3_pooling():
model = applications.InceptionV3(weights=None, include_top=False, pooling='avg')
assert model.output_shape == (None, 2048)
Diferenças do arquivo suprimidas por serem muito extensas Carregar Diff
+93 -3
Ver Arquivo
@@ -77,6 +77,8 @@ def test_trainable_weights():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support add learning_phase() as input")
def test_learning_phase():
a = Input(shape=(32,), name='input_a')
b = Input(shape=(32,), name='input_b')
@@ -439,12 +441,11 @@ def test_recursion():
with pytest.raises(Exception) as e:
Model([j], [m, n])
# redudant outputs
# redundant 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
# this should work with a warning
Model([j, k], [m, n, n])
# redundant inputs
@@ -489,6 +490,68 @@ def test_recursion():
Dense(2)(x)
@keras_test
def test_load_layers():
from keras.layers import ConvLSTM2D, TimeDistributed, Bidirectional, Conv2D, Input
from keras.models import Model
from keras.engine.topology import preprocess_weights_for_loading
if K.backend() == 'tensorflow' or K.backend() == 'cntk':
inputs = Input(shape=(10, 20, 20, 1))
else:
inputs = Input(shape=(10, 1, 20, 20))
td_conv = TimeDistributed(Conv2D(15, (5, 5)))(inputs)
bi_convlstm2d = Bidirectional(ConvLSTM2D(10, (3, 3)), merge_mode='concat')(td_conv)
model = Model(inputs=inputs, outputs=bi_convlstm2d)
weight_value_tuples = []
# TimeDistributed Conv2D layer
# use 'channels_first' data format to check that the function is being called correctly for Conv2D
# old: (filters, stack_size, kernel_rows, kernel_cols)
# new: (kernel_rows, kernel_cols, stack_size, filters)
weight_tensor_td_conv_old = list()
weight_tensor_td_conv_old.append(np.zeros((15, 1, 5, 5)))
weight_tensor_td_conv_old.append(np.zeros((15,)))
td_conv_layer = model.layers[1]
td_conv_layer.layer.data_format = 'channels_first'
weight_tensor_td_conv_new = preprocess_weights_for_loading(td_conv_layer,
weight_tensor_td_conv_old,
original_keras_version='1')
symbolic_weights = td_conv_layer.weights
assert (len(symbolic_weights) == len(weight_tensor_td_conv_new))
weight_value_tuples += zip(symbolic_weights, weight_tensor_td_conv_new)
# Bidirectional ConvLSTM2D layer
# old ConvLSTM2D took a list of 12 weight tensors, returns a list of 3 concatenated larger tensors.
weight_tensor_bi_convlstm_old = []
for j in range(2): # bidirectional
for i in range(4):
weight_tensor_bi_convlstm_old.append(np.zeros((3, 3, 15, 10))) # kernel
weight_tensor_bi_convlstm_old.append(np.zeros((3, 3, 10, 10))) # recurrent kernel
weight_tensor_bi_convlstm_old.append(np.zeros((10,))) # bias
bi_convlstm_layer = model.layers[2]
weight_tensor_bi_convlstm_new = preprocess_weights_for_loading(bi_convlstm_layer,
weight_tensor_bi_convlstm_old,
original_keras_version='1')
symbolic_weights = bi_convlstm_layer.weights
assert (len(symbolic_weights) == len(weight_tensor_bi_convlstm_new))
weight_value_tuples += zip(symbolic_weights, weight_tensor_bi_convlstm_new)
K.batch_set_value(weight_value_tuples)
assert np.all(K.eval(model.layers[1].weights[0]) == weight_tensor_td_conv_new[0])
assert np.all(K.eval(model.layers[1].weights[1]) == weight_tensor_td_conv_new[1])
assert np.all(K.eval(model.layers[2].weights[0]) == weight_tensor_bi_convlstm_new[0])
assert np.all(K.eval(model.layers[2].weights[1]) == weight_tensor_bi_convlstm_new[1])
assert np.all(K.eval(model.layers[2].weights[2]) == weight_tensor_bi_convlstm_new[2])
assert np.all(K.eval(model.layers[2].weights[3]) == weight_tensor_bi_convlstm_new[3])
assert np.all(K.eval(model.layers[2].weights[4]) == weight_tensor_bi_convlstm_new[4])
assert np.all(K.eval(model.layers[2].weights[5]) == weight_tensor_bi_convlstm_new[5])
@keras_test
def test_recursion_with_bn_and_loss():
model1 = Sequential([
@@ -516,5 +579,32 @@ def test_recursion_with_bn_and_loss():
model2.fit(x, y, verbose=0, epochs=1)
def test_shared_layer_depth_is_correct():
# Basic outline here: we have a shared embedding layer, and two inputs that go through
# different depths of computation in the graph before the final output. We need the computed
# depth of the input layers to be the same, because they both pass through the embedding layer
# before anything else happens. That's what we're testing.
from keras.layers import Embedding, Input, Dense, Concatenate
from keras.models import Model
input1 = Input(shape=(10,), name="input1")
input2 = Input(shape=(10,), name="input2")
embedding_layer = Embedding(name="embedding", input_dim=5, output_dim=10)
embedded_input1 = embedding_layer(input1)
embedded_input2 = embedding_layer(input2)
transformed_input2 = Dense(6)(Dense(5)(Dense(3)(embedded_input2)))
final_output = Dense(2)(Concatenate()([embedded_input1, transformed_input2]))
model = Model(inputs=[input1, input2], outputs=final_output)
input1_depth = -1
input2_depth = -1
for depth, layers in model.layers_by_depth.items():
for layer in layers:
if layer.name == 'input1':
input1_depth = depth
if layer.name == 'input2':
input2_depth = depth
assert input1_depth != -1
assert input1_depth == input2_depth
if __name__ == '__main__':
pytest.main([__file__])
+15
Ver Arquivo
@@ -1,6 +1,7 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose
import scipy.sparse as sparse
from keras.layers import Dense, Dropout
from keras.engine.topology import Input
@@ -198,6 +199,18 @@ def test_model_methods():
out = model.predict([input_a_np, input_b_np], batch_size=4)
@pytest.mark.skipif(K.backend() != 'tensorflow', reason='sparse operations supported only by TF')
@keras_test
def test_sparse_input_validation_split():
test_input = sparse.random(6, 3, density=0.25).tocsr()
in1 = Input(shape=(3,), sparse=True)
out1 = Dense(4)(in1)
test_output = np.random.random((6, 4))
model = Model(in1, out1)
model.compile('rmsprop', 'mse')
model.fit(test_input, test_output, epochs=1, batch_size=2, validation_split=0.2)
@keras_test
def test_trainable_argument():
x = np.random.random((5, 3))
@@ -433,6 +446,8 @@ def test_model_with_partial_loss():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support external loss yet")
def test_model_with_external_loss():
# None loss, only regularization loss.
a = Input(shape=(3,), name='input_a')
+70 -55
Ver Arquivo
@@ -3,8 +3,8 @@ import numpy as np
from numpy.testing import assert_allclose
from keras import backend as K
from keras.models import Sequential
from keras.layers import convolutional_recurrent
from keras.models import Sequential, Model
from keras.layers import convolutional_recurrent, Input
from keras.utils.test_utils import layer_test
from keras import regularizers
@@ -43,67 +43,69 @@ def test_convolutional_recurrent():
if data_format == 'channels_first' or return_sequences:
continue
# Tests for statefulness
model = Sequential()
kwargs = {'data_format': data_format,
'return_sequences': return_sequences,
'filters': filters,
'kernel_size': (num_row, num_col),
'stateful': True,
'batch_input_shape': inputs.shape,
'padding': 'same'}
layer = convolutional_recurrent.ConvLSTM2D(**kwargs)
# cntk doesn't support statefulness on LSTM yet, will enable it on cntk later
if K.backend() != 'cntk':
# Tests for statefulness
model = Sequential()
kwargs = {'data_format': data_format,
'return_sequences': return_sequences,
'filters': filters,
'kernel_size': (num_row, num_col),
'stateful': True,
'batch_input_shape': inputs.shape,
'padding': 'same'}
layer = convolutional_recurrent.ConvLSTM2D(**kwargs)
model.add(layer)
model.compile(optimizer='sgd', loss='mse')
out1 = model.predict(np.ones_like(inputs))
model.add(layer)
model.compile(optimizer='sgd', loss='mse')
out1 = model.predict(np.ones_like(inputs))
# train once so that the states change
model.train_on_batch(np.ones_like(inputs),
np.random.random(out1.shape))
out2 = model.predict(np.ones_like(inputs))
# train once so that the states change
model.train_on_batch(np.ones_like(inputs),
np.random.random(out1.shape))
out2 = model.predict(np.ones_like(inputs))
# if the state is not reset, output should be different
assert(out1.max() != out2.max())
# if the state is not reset, output should be different
assert(out1.max() != out2.max())
# check that output changes after states are reset
# (even though the model itself didn't change)
layer.reset_states()
out3 = model.predict(np.ones_like(inputs))
assert(out2.max() != out3.max())
# check that output changes after states are reset
# (even though the model itself didn't change)
layer.reset_states()
out3 = model.predict(np.ones_like(inputs))
assert(out2.max() != out3.max())
# check that container-level reset_states() works
model.reset_states()
out4 = model.predict(np.ones_like(inputs))
assert_allclose(out3, out4, atol=1e-5)
# check that container-level reset_states() works
model.reset_states()
out4 = model.predict(np.ones_like(inputs))
assert_allclose(out3, out4, atol=1e-5)
# check that the call to `predict` updated the states
out5 = model.predict(np.ones_like(inputs))
assert(out4.max() != out5.max())
# check that the call to `predict` updated the states
out5 = model.predict(np.ones_like(inputs))
assert(out4.max() != out5.max())
# check regularizers
kwargs = {'data_format': data_format,
'return_sequences': return_sequences,
'kernel_size': (num_row, num_col),
'stateful': True,
'filters': filters,
'batch_input_shape': inputs.shape,
'kernel_regularizer': regularizers.L1L2(l1=0.01),
'recurrent_regularizer': regularizers.L1L2(l1=0.01),
'bias_regularizer': 'l2',
'activity_regularizer': 'l2',
'kernel_constraint': 'max_norm',
'recurrent_constraint': 'max_norm',
'bias_constraint': 'max_norm',
'padding': 'same'}
# check regularizers
kwargs = {'data_format': data_format,
'return_sequences': return_sequences,
'kernel_size': (num_row, num_col),
'stateful': True,
'filters': filters,
'batch_input_shape': inputs.shape,
'kernel_regularizer': regularizers.L1L2(l1=0.01),
'recurrent_regularizer': regularizers.L1L2(l1=0.01),
'bias_regularizer': 'l2',
'activity_regularizer': 'l2',
'kernel_constraint': 'max_norm',
'recurrent_constraint': 'max_norm',
'bias_constraint': 'max_norm',
'padding': 'same'}
layer = convolutional_recurrent.ConvLSTM2D(**kwargs)
layer.build(inputs.shape)
assert len(layer.losses) == 3
assert layer.activity_regularizer
output = layer(K.variable(np.ones(inputs.shape)))
assert len(layer.losses) == 4
K.eval(output)
layer = convolutional_recurrent.ConvLSTM2D(**kwargs)
layer.build(inputs.shape)
assert len(layer.losses) == 3
assert layer.activity_regularizer
output = layer(K.variable(np.ones(inputs.shape)))
assert len(layer.losses) == 4
K.eval(output)
# check dropout
layer_test(convolutional_recurrent.ConvLSTM2D,
@@ -116,5 +118,18 @@ def test_convolutional_recurrent():
'recurrent_dropout': 0.1},
input_shape=inputs.shape)
# check state initialization
layer = convolutional_recurrent.ConvLSTM2D(filters=filters,
kernel_size=(num_row, num_col),
data_format=data_format,
return_sequences=return_sequences)
layer.build(inputs.shape)
x = Input(batch_shape=inputs.shape)
initial_state = layer.get_initial_state(x)
y = layer(x, initial_state=initial_state)
model = Model(x, y)
assert model.predict(inputs).shape == layer.compute_output_shape(inputs.shape)
if __name__ == '__main__':
pytest.main([__file__])
+55 -13
Ver Arquivo
@@ -17,6 +17,8 @@ else:
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support dilated conv")
def test_causal_dilated_conv():
# Causal:
layer_test(convolutional.Conv1D,
@@ -122,6 +124,8 @@ def test_averagepooling_1d():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support dilated conv")
def test_convolution_2d():
num_samples = 2
filters = 2
@@ -494,20 +498,54 @@ def test_zero_padding_3d():
stack_size))
# basic test
layer_test(convolutional.ZeroPadding3D,
kwargs={'padding': (2, 2, 2)},
input_shape=inputs.shape)
for data_format in ['channels_first', 'channels_last']:
layer_test(convolutional.ZeroPadding3D,
kwargs={'padding': (2, 2, 2), 'data_format': data_format},
input_shape=inputs.shape)
layer_test(convolutional.ZeroPadding3D,
kwargs={'padding': ((1, 2), (3, 4), (0, 2)), 'data_format': data_format},
input_shape=inputs.shape)
# correctness test
layer = convolutional.ZeroPadding3D(padding=(2, 2, 2))
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
for offset in [0, 1, -1, -2]:
assert_allclose(np_output[:, offset, :, :, :], 0.)
assert_allclose(np_output[:, :, offset, :, :], 0.)
assert_allclose(np_output[:, :, :, offset, :], 0.)
assert_allclose(np_output[:, 2:-2, 2:-2, 2:-2, :], 1.)
# correctness test
layer = convolutional.ZeroPadding3D(padding=(2, 2, 2),
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
if data_format == 'channels_last':
for offset in [0, 1, -1, -2]:
assert_allclose(np_output[:, offset, :, :, :], 0.)
assert_allclose(np_output[:, :, offset, :, :], 0.)
assert_allclose(np_output[:, :, :, offset, :], 0.)
assert_allclose(np_output[:, 2:-2, 2:-2, 2:-2, :], 1.)
elif data_format == 'channels_first':
for offset in [0, 1, -1, -2]:
assert_allclose(np_output[:, :, offset, :, :], 0.)
assert_allclose(np_output[:, :, :, offset, :], 0.)
assert_allclose(np_output[:, :, :, :, offset], 0.)
assert_allclose(np_output[:, :, 2:-2, 2:-2, 2:-2], 1.)
layer = convolutional.ZeroPadding3D(padding=((1, 2), (3, 4), (0, 2)),
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
if data_format == 'channels_last':
for dim1_offset in [0, -1, -2]:
assert_allclose(np_output[:, dim1_offset, :, :, :], 0.)
for dim2_offset in [0, 1, 2, -1, -2, -3, -4]:
assert_allclose(np_output[:, :, dim2_offset, :, :], 0.)
for dim3_offset in [-1, -2]:
assert_allclose(np_output[:, :, :, dim3_offset, :], 0.)
assert_allclose(np_output[:, 1:-2, 3:-4, 0:-2, :], 1.)
elif data_format == 'channels_first':
for dim1_offset in [0, -1, -2]:
assert_allclose(np_output[:, :, dim1_offset, :, :], 0.)
for dim2_offset in [0, 1, 2, -1, -2, -3, -4]:
assert_allclose(np_output[:, :, :, dim2_offset, :], 0.)
for dim3_offset in [-1, -2]:
assert_allclose(np_output[:, :, :, :, dim3_offset], 0.)
assert_allclose(np_output[:, :, 1:-2, 3:-4, 0:-2], 1.)
@keras_test
@@ -563,6 +601,8 @@ def test_upsampling_2d():
assert_allclose(np_output, expected_out)
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support it yet")
def test_upsampling_3d():
num_samples = 2
stack_size = 2
@@ -617,6 +657,8 @@ def test_upsampling_3d():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support slice to 0 dimension")
def test_cropping_1d():
num_samples = 2
time_length = 4
+10
Ver Arquivo
@@ -16,6 +16,16 @@ def test_embedding():
input_shape=(3, 2),
input_dtype='int32',
expected_output_dtype=K.floatx())
layer_test(Embedding,
kwargs={'output_dim': 4, 'input_dim': 10, 'mask_zero': True},
input_shape=(3, 2, 5),
input_dtype='int32',
expected_output_dtype=K.floatx())
layer_test(Embedding,
kwargs={'output_dim': 4, 'input_dim': 10, 'mask_zero': True, 'input_length': (None, 5)},
input_shape=(3, 2, 5),
input_dtype='int32',
expected_output_dtype=K.floatx())
if __name__ == '__main__':
+5
Ver Arquivo
@@ -2,9 +2,12 @@ import pytest
from keras.utils.test_utils import layer_test
from keras.utils.test_utils import keras_test
from keras.layers import noise
from keras import backend as K
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support it yet")
def test_GaussianNoise():
layer_test(noise.GaussianNoise,
kwargs={'stddev': 1.},
@@ -12,6 +15,8 @@ def test_GaussianNoise():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support it yet")
def test_GaussianDropout():
layer_test(noise.GaussianDropout,
kwargs={'rate': 0.5},
+26 -1
Ver Arquivo
@@ -2,7 +2,7 @@ import pytest
import numpy as np
from numpy.testing import assert_allclose
from keras.layers import Dense, Activation, Input
from keras.layers import Input
from keras.utils.test_utils import layer_test, keras_test
from keras.layers import normalization
from keras.models import Sequential, Model
@@ -52,6 +52,31 @@ def test_batchnorm_correctness():
assert_allclose(out.std(), 1.0, atol=1e-1)
@keras_test
def test_batchnorm_training_argument():
bn1 = normalization.BatchNormalization(input_shape=(10,))
x1 = Input(shape=(10,))
y1 = bn1(x1, training=True)
assert bn1.updates
model1 = Model(x1, y1)
np.random.seed(123)
x = np.random.normal(loc=5.0, scale=10.0, size=(20, 10))
output_a = model1.predict(x)
model1.compile(loss='mse', optimizer='rmsprop')
model1.fit(x, x, epochs=1, verbose=0)
output_b = model1.predict(x)
assert np.abs(np.sum(output_a - output_b)) > 0.1
assert_allclose(output_b.mean(), 0.0, atol=1e-1)
assert_allclose(output_b.std(), 1.0, atol=1e-1)
bn2 = normalization.BatchNormalization(input_shape=(10,))
x2 = Input(shape=(10,))
bn2(x2, training=False)
assert not bn2.updates
@keras_test
def test_batchnorm_mode_twice():
# This is a regression test for issue #4881 with the old
+96 -8
Ver Arquivo
@@ -57,6 +57,14 @@ def test_dropout(layer_class):
'dropout': 0.1,
'recurrent_dropout': 0.1},
input_shape=(num_samples, timesteps, embedding_dim))
# Test that dropout is not applied during testing
x = np.random.random((num_samples, timesteps, embedding_dim))
layer = layer_class(units, dropout=0.5, recurrent_dropout=0.5,
input_shape=(timesteps, embedding_dim))
model = Sequential([layer])
y1 = model.predict(x)
y2 = model.predict(x)
assert_allclose(y1, y2)
@rnn_test
@@ -69,6 +77,8 @@ def test_implementation_mode(layer_class):
@rnn_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support stateful RNN yet")
def test_statefulness(layer_class):
model = Sequential()
model.add(embeddings.Embedding(embedding_num, embedding_dim,
@@ -139,6 +149,8 @@ def test_regularizer(layer_class):
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support mask on RNN yet")
def test_masking_layer():
''' This test based on a previously failing issue here:
https://github.com/fchollet/keras/issues/1567
@@ -162,36 +174,50 @@ def test_masking_layer():
@rnn_test
def test_from_config(layer_class):
for stateful in (False, True):
# cntk does not support stateful yet.
stateful_flags = (False, True) if K.backend() != 'cntk' else (False,)
for stateful in stateful_flags:
l1 = layer_class(units=1, stateful=stateful)
l2 = layer_class.from_config(l1.get_config())
assert l1.get_config() == l2.get_config()
@rnn_test
def test_specify_initial_state(layer_class):
def test_specify_initial_state_keras_tensor(layer_class):
num_states = 2 if layer_class is recurrent.LSTM else 1
# Test with Keras tensor
inputs = Input((timesteps, embedding_dim))
initial_state = [Input((units,)) for _ in range(num_states)]
layer = layer_class(units)
output = layer(inputs, initial_state=initial_state)
if len(initial_state) == 1:
output = layer(inputs, initial_state=initial_state[0])
else:
output = layer(inputs, initial_state=initial_state)
assert initial_state[0] in layer.inbound_nodes[0].input_tensors
model = Model([inputs] + initial_state, output)
model.compile(loss='categorical_crossentropy', optimizer='adam')
inputs = np.random.random((num_samples, timesteps, embedding_dim))
initial_states = [np.random.random((num_samples, units))
for _ in range(num_states)]
initial_state = [np.random.random((num_samples, units))
for _ in range(num_states)]
targets = np.random.random((num_samples, units))
model.fit([inputs] + initial_states, targets)
model.fit([inputs] + initial_state, targets)
@rnn_test
def test_specify_initial_state_non_keras_tensor(layer_class):
num_states = 2 if layer_class is recurrent.LSTM else 1
# Test with non-Keras tensor
inputs = Input((timesteps, embedding_dim))
initial_state = [K.random_normal_variable((units,), 0, 1) for _ in range(num_states)]
initial_state = [K.random_normal_variable((num_samples, units), 0, 1)
for _ in range(num_states)]
layer = layer_class(units)
output = layer(inputs, initial_state=initial_state)
model = Model([inputs], output)
model = Model(inputs, output)
model.compile(loss='categorical_crossentropy', optimizer='adam')
inputs = np.random.random((num_samples, timesteps, embedding_dim))
@@ -200,6 +226,8 @@ def test_specify_initial_state(layer_class):
@rnn_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support stateful RNN yet")
def test_reset_states_with_values(layer_class):
num_states = 2 if layer_class is recurrent.LSTM else 1
@@ -213,10 +241,70 @@ def test_reset_states_with_values(layer_class):
atol=1e-4)
state_shapes = [K.int_shape(state) for state in layer.states]
values = [np.ones(shape) for shape in state_shapes]
if len(values) == 1:
values = values[0]
layer.reset_states(values)
np.testing.assert_allclose(K.eval(layer.states[0]),
np.ones(K.int_shape(layer.states[0])),
atol=1e-4)
# Test fit with invalid data
with pytest.raises(ValueError):
layer.reset_states([1] * (len(layer.states) + 1))
@rnn_test
def test_specify_state_with_masking(layer_class):
''' This test based on a previously failing issue here:
https://github.com/fchollet/keras/issues/1567
'''
num_states = 2 if layer_class is recurrent.LSTM else 1
inputs = Input((timesteps, embedding_dim))
_ = Masking()(inputs)
initial_state = [Input((units,)) for _ in range(num_states)]
output = layer_class(units)(inputs, initial_state=initial_state)
model = Model([inputs] + initial_state, output)
model.compile(loss='categorical_crossentropy', optimizer='adam')
inputs = np.random.random((num_samples, timesteps, embedding_dim))
initial_state = [np.random.random((num_samples, units))
for _ in range(num_states)]
targets = np.random.random((num_samples, units))
model.fit([inputs] + initial_state, targets)
@rnn_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support stateful RNN yet")
def test_return_state(layer_class):
num_states = 2 if layer_class is recurrent.LSTM else 1
inputs = Input(batch_shape=(num_samples, timesteps, embedding_dim))
layer = layer_class(units, return_state=True, stateful=True)
outputs = layer(inputs)
output, state = outputs[0], outputs[1:]
assert len(state) == num_states
model = Model(inputs, state[0])
inputs = np.random.random((num_samples, timesteps, embedding_dim))
state = model.predict(inputs)
np.testing.assert_allclose(K.eval(layer.states[0]), state, atol=1e-4)
@rnn_test
def test_state_reuse(layer_class):
inputs = Input(batch_shape=(num_samples, timesteps, embedding_dim))
layer = layer_class(units, return_state=True, return_sequences=True)
outputs = layer(inputs)
output, state = outputs[0], outputs[1:]
output = layer_class(units)(output, initial_state=state)
model = Model(inputs, output)
inputs = np.random.random((num_samples, timesteps, embedding_dim))
outputs = model.predict(inputs)
if __name__ == '__main__':
pytest.main([__file__])
+3
Ver Arquivo
@@ -5,6 +5,7 @@ from keras.utils.test_utils import keras_test
from keras.layers import wrappers, Input
from keras.layers import core, convolutional, recurrent, embeddings
from keras.models import Sequential, Model, model_from_json
from keras import backend as K
@keras_test
@@ -108,6 +109,8 @@ def test_regularizers():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support reverse yet")
def test_Bidirectional():
rnn = recurrent.SimpleRNN
samples = 2
+4
Ver Arquivo
@@ -184,6 +184,8 @@ def test_merge():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support stateful RNN yet")
def test_merge_mask_2d():
rand = lambda *shape: np.asarray(np.random.random(shape) > 0.5, dtype='int32')
@@ -217,6 +219,8 @@ def test_merge_mask_2d():
@keras_test
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="cntk does not support stateful RNN yet")
def test_merge_mask_3d():
rand = lambda *shape: np.asarray(np.random.random(shape) > 0.5, dtype='int32')
+15 -2
Ver Arquivo
@@ -10,11 +10,14 @@ allobj = [losses.mean_squared_error,
losses.mean_absolute_percentage_error,
losses.mean_squared_logarithmic_error,
losses.squared_hinge,
losses.hinge, losses.categorical_crossentropy,
losses.hinge,
losses.categorical_crossentropy,
losses.binary_crossentropy,
losses.kullback_leibler_divergence,
losses.poisson,
losses.cosine_proximity]
losses.cosine_proximity,
losses.logcosh,
losses.categorical_hinge]
def test_objective_shapes_3d():
@@ -44,5 +47,15 @@ def test_cce_one_hot():
assert K.eval(losses.sparse_categorical_crossentropy(y_a, y_b)).shape == (6,)
def test_categorical_hinge():
y_pred = K.variable(np.array([[0.3, 0.2, 0.1],
[0.1, 0.2, 0.7]]))
y_true = K.variable(np.array([[0, 1, 0],
[1, 0, 0]]))
expected_loss = ((0.3 - 0.2 + 1) + (0.7 - 0.1 + 1)) / 2.0
loss = K.eval(losses.categorical_hinge(y_true, y_pred))
assert np.isclose(expected_loss, np.mean(loss))
if __name__ == '__main__':
pytest.main([__file__])
+19
Ver Arquivo
@@ -17,6 +17,7 @@ all_metrics = [
metrics.binary_crossentropy,
metrics.poisson,
metrics.cosine_proximity,
metrics.logcosh,
]
all_sparse_metrics = [
@@ -41,6 +42,8 @@ def test_sparse_metrics():
assert K.eval(metric(y_a, y_b)).shape == (6,)
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="keras cntk backend does not support top_k yet")
def test_top_k_categorical_accuracy():
y_pred = K.variable(np.array([[0.3, 0.2, 0.1], [0.1, 0.2, 0.7]]))
y_true = K.variable(np.array([[0, 1, 0], [1, 0, 0]]))
@@ -55,5 +58,21 @@ def test_top_k_categorical_accuracy():
assert failure_result == 0
@pytest.mark.skipif((K.backend() == 'cntk'),
reason="keras cntk backend does not support top_k yet")
def test_sparse_top_k_categorical_accuracy():
y_pred = K.variable(np.array([[0.3, 0.2, 0.1], [0.1, 0.2, 0.7]]))
y_true = K.variable(np.array([[1], [0]]))
success_result = K.eval(metrics.sparse_top_k_categorical_accuracy(y_true, y_pred,
k=3))
assert success_result == 1
partial_result = K.eval(metrics.sparse_top_k_categorical_accuracy(y_true, y_pred,
k=2))
assert partial_result == 0.5
failure_result = K.eval(metrics.sparse_top_k_categorical_accuracy(y_true, y_pred,
k=1))
assert failure_result == 0
if __name__ == '__main__':
pytest.main([__file__])
+27 -12
Ver Arquivo
@@ -73,22 +73,11 @@ class TestImage:
with pytest.raises(ValueError):
x = np.random.random((3, 10, 10))
generator.fit(x)
with pytest.raises(ValueError):
x = np.random.random((32, 3, 10, 10))
generator.fit(x)
with pytest.raises(ValueError):
x = np.random.random((32, 10, 10, 5))
generator.fit(x)
# Test flow with invalid data
with pytest.raises(ValueError):
x = np.random.random((32, 10, 10, 5))
generator.flow(np.arange(x.shape[0]))
with pytest.raises(ValueError):
x = np.random.random((32, 10, 10))
generator.flow(np.arange(x.shape[0]))
with pytest.raises(ValueError):
x = np.random.random((32, 3, 10, 10))
generator.flow(np.arange(x.shape[0]))
def test_image_data_generator_fit(self):
generator = image.ImageDataGenerator(
@@ -160,6 +149,32 @@ class TestImage:
assert(sorted(dir_iterator.filenames) == sorted(filenames))
shutil.rmtree(tmp_folder)
def test_directory_iterator_class_mode_input(self):
tmp_folder = tempfile.mkdtemp(prefix='test_images')
os.mkdir(os.path.join(tmp_folder, 'class-1'))
# save the images in the paths
count = 0
for test_images in self.all_test_images:
for im in test_images:
filename = os.path.join(tmp_folder, 'class-1', 'image-{}.jpg'.format(count))
im.save(os.path.join(tmp_folder, filename))
count += 1
# create iterator
generator = image.ImageDataGenerator()
dir_iterator = generator.flow_from_directory(tmp_folder, class_mode='input')
batch = next(dir_iterator)
# check if input and output have the same shape
assert(batch[0].shape == batch[1].shape)
# check if the input and output images are not the same numpy array
input_img = batch[0][0]
output_img = batch[1][0]
output_img[0][0][0] += 1
assert(input_img[0][0][0] != output_img[0][0][0])
shutil.rmtree(tmp_folder)
def test_img_utils(self):
height, width = 10, 8
+133 -5
Ver Arquivo
@@ -6,9 +6,12 @@ import pytest
from csv import Sniffer
import shutil
from keras import optimizers
from keras import initializers
from keras import callbacks
from keras.models import Sequential
from keras.layers.core import Dense
from keras.layers.core import Dense, Dropout
from keras.layers.convolutional import Conv2D
from keras.layers.pooling import MaxPooling2D, GlobalAveragePooling2D
from keras.utils.test_utils import get_test_data
from keras.utils.test_utils import keras_test
from keras import backend as K
@@ -22,6 +25,34 @@ train_samples = 20
test_samples = 20
@keras_test
def test_TerminateOnNaN():
np.random.seed(1337)
(X_train, y_train), (X_test, y_test) = get_test_data(num_train=train_samples,
num_test=test_samples,
input_shape=(input_dim,),
classification=True,
num_classes=num_class)
y_test = np_utils.to_categorical(y_test)
y_train = np_utils.to_categorical(y_train)
cbks = [callbacks.TerminateOnNaN()]
model = Sequential()
initializer = initializers.Constant(value=1e5)
for _ in range(5):
model.add(Dense(num_hidden, input_dim=input_dim, activation='relu',
kernel_initializer=initializer))
model.add(Dense(num_class, activation='linear'))
model.compile(loss='mean_squared_error',
optimizer='rmsprop')
history = model.fit(X_train, y_train, batch_size=batch_size,
validation_data=(X_test, y_test), callbacks=cbks, epochs=20)
loss = history.history['loss']
assert len(loss) == 1
assert loss[0] == np.inf
@keras_test
def test_ModelCheckpoint():
np.random.seed(1337)
@@ -271,9 +302,9 @@ def test_CSVLogger():
@pytest.mark.skipif((K.backend() != 'tensorflow'),
reason='Requires tensorflow backend')
def test_TensorBoard():
np.random.seed(1337)
np.random.seed(np.random.randint(1, 1e7))
filepath = './logs_' + str(np.random.randint(1, 1e4))
filepath = './logs'
(X_train, y_train), (X_test, y_test) = get_test_data(
num_train=train_samples,
num_test=test_samples,
@@ -309,13 +340,17 @@ def test_TensorBoard():
# case 1 Sequential
model = Sequential()
model.add(Dense(num_hidden, input_dim=input_dim, activation='relu'))
model.add(Dropout(0.1))
model.add(Dense(num_class, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='sgd',
metrics=['accuracy'])
tsb = callbacks.TensorBoard(log_dir=filepath, histogram_freq=1,
write_images=True)
write_images=True, write_grads=True,
embeddings_freq=1,
embeddings_layer_names=['dense_1'],
batch_size=5)
cbks = [tsb]
# fit with validation data
@@ -348,6 +383,97 @@ def test_TensorBoard():
shutil.rmtree(filepath)
@keras_test
@pytest.mark.skipif((K.backend() != 'tensorflow'),
reason='Requires tensorflow backend')
def test_TensorBoard_convnet():
np.random.seed(np.random.randint(1, 1e7))
filepath = './logs_' + str(np.random.randint(1, 1e4))
input_shape = (16, 16, 3)
(x_train, y_train), (x_test, y_test) = get_test_data(num_train=500,
num_test=200,
input_shape=input_shape,
classification=True,
num_classes=4)
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)
model = Sequential([
Conv2D(filters=8, kernel_size=3,
activation='relu',
input_shape=input_shape),
MaxPooling2D(pool_size=2),
Conv2D(filters=4, kernel_size=(3, 3),
activation='relu', padding='same'),
GlobalAveragePooling2D(),
Dense(y_test.shape[-1], activation='softmax')
])
model.compile(loss='categorical_crossentropy',
optimizer='rmsprop',
metrics=['accuracy'])
tsb = callbacks.TensorBoard(log_dir=filepath, histogram_freq=1,
write_images=True, write_grads=True,
batch_size=16)
cbks = [tsb]
model.summary()
history = model.fit(x_train, y_train, epochs=2, batch_size=16,
validation_data=(x_test, y_test),
callbacks=cbks,
verbose=0)
assert os.path.exists(filepath)
shutil.rmtree(filepath)
@keras_test
def test_CallbackValData():
np.random.seed(1337)
(X_train, y_train), (X_test, y_test) = get_test_data(num_train=train_samples,
num_test=test_samples,
input_shape=(input_dim,),
classification=True,
num_classes=num_class)
y_test = np_utils.to_categorical(y_test)
y_train = np_utils.to_categorical(y_train)
model = Sequential()
model.add(Dense(num_hidden, input_dim=input_dim, activation='relu'))
model.add(Dense(num_class, activation='softmax'))
model.compile(loss='categorical_crossentropy',
optimizer='sgd',
metrics=['accuracy'])
cbk = callbacks.LambdaCallback(on_train_end=lambda x: 1)
model.fit(X_train, y_train, batch_size=batch_size,
validation_data=(X_test, y_test), callbacks=[cbk], epochs=1)
def data_generator(train):
if train:
max_batch_index = len(X_train) // batch_size
else:
max_batch_index = len(X_test) // batch_size
i = 0
while 1:
if train:
yield (X_train[i * batch_size: (i + 1) * batch_size],
y_train[i * batch_size: (i + 1) * batch_size])
else:
yield (X_test[i * batch_size: (i + 1) * batch_size],
y_test[i * batch_size: (i + 1) * batch_size])
i += 1
i = i % max_batch_index
cbk2 = callbacks.LambdaCallback(on_train_end=lambda x: 1)
model.fit_generator(data_generator(True), len(X_train), epochs=1,
validation_data=(X_test, y_test),
callbacks=[cbk2])
# callback validation data should always have x, y, and sample weights
assert len(cbk.validation_data) == len(cbk2.validation_data) == 3
assert cbk.validation_data[0] is cbk2.validation_data[0]
assert cbk.validation_data[1] is cbk2.validation_data[1]
assert cbk.validation_data[2].shape == cbk2.validation_data[2].shape
@keras_test
def test_LambdaCallback():
np.random.seed(1337)
@@ -386,7 +512,9 @@ def test_LambdaCallback():
reason="Requires tensorflow backend")
def test_TensorBoard_with_ReduceLROnPlateau():
import shutil
filepath = './logs'
np.random.seed(np.random.randint(1, 1e7))
filepath = './logs_' + str(np.random.randint(1, 1e4))
(X_train, y_train), (X_test, y_test) = get_test_data(num_train=train_samples,
num_test=test_samples,
input_shape=(input_dim,),
-2
Ver Arquivo
@@ -9,8 +9,6 @@ from six.moves.urllib.parse import urljoin
from keras.utils.data_utils import get_file
from keras.utils.data_utils import validate_file
from keras.utils.data_utils import _hash_file
from keras import activations
from keras import regularizers
def test_data_utils():
+65
Ver Arquivo
@@ -0,0 +1,65 @@
'''Tests for functions in io_utils.py.
'''
import os
import pytest
from keras.models import Sequential
from keras.layers import Dense
from keras.utils.io_utils import HDF5Matrix
import numpy as np
import warnings
import h5py
def create_dataset(h5_path='test.h5'):
X = np.random.randn(200, 10).astype('float32')
y = np.random.randint(0, 2, size=(200, 1))
f = h5py.File(h5_path, 'w')
# Creating dataset to store features
X_dset = f.create_dataset('my_data', (200, 10), dtype='f')
X_dset[:] = X
# Creating dataset to store labels
y_dset = f.create_dataset('my_labels', (200, 1), dtype='i')
y_dset[:] = y
f.close()
def test_io_utils():
'''Tests the HDF5Matrix code using the sample from @jfsantos at
https://gist.github.com/jfsantos/e2ef822c744357a4ed16ec0c885100a3
'''
h5_path = 'test.h5'
create_dataset(h5_path)
# Instantiating HDF5Matrix for the training set, which is a slice of the first 150 elements
X_train = HDF5Matrix(h5_path, 'my_data', start=0, end=150)
y_train = HDF5Matrix(h5_path, 'my_labels', start=0, end=150)
# Likewise for the test set
X_test = HDF5Matrix(h5_path, 'my_data', start=150, end=200)
y_test = HDF5Matrix(h5_path, 'my_labels', start=150, end=200)
# HDF5Matrix behave more or less like Numpy matrices with regards to indexing
assert y_train.shape == (150, 1), 'HDF5Matrix shape should match input array'
# But they do not support negative indices, so don't try print(X_train[-1])
model = Sequential()
model.add(Dense(64, input_shape=(10,), activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.compile(loss='binary_crossentropy', optimizer='sgd')
# Note: you have to use shuffle='batch' or False with HDF5Matrix
model.fit(X_train, y_train, batch_size=32, shuffle='batch', verbose=False)
# test that evalutation and prediction don't crash and return reasonable results
out_pred = model.predict(X_test, batch_size=32, verbose=False)
out_eval = model.evaluate(X_test, y_test, batch_size=32, verbose=False)
assert out_pred.shape == (50, 1), 'Prediction shape does not match'
assert out_eval.shape == (), 'Shape of evaluation does not match'
assert out_eval > 0, 'Evaluation value does not meet criteria: {}'.format(out_eval)
os.remove(h5_path)
if __name__ == '__main__':
pytest.main([__file__])
-2
Ver Arquivo
@@ -2,8 +2,6 @@ import pytest
import numpy as np
from keras.utils.test_utils import get_test_data
from keras.utils import np_utils
from keras import backend as K
from keras.models import Sequential
from keras.layers.core import Dense, Activation
+151
Ver Arquivo
@@ -0,0 +1,151 @@
import importlib
import inspect
import re
import sys
from itertools import compress
import pytest
modules = ['keras.layers', 'keras.models', 'keras', 'keras.backend.tensorflow_backend']
accepted_name = ['from_config']
accepted_module = ['keras.legacy.layers', 'keras.utils.generic_utils']
# Functions or classes with less than 'MIN_CODE_SIZE' lines can be ignored
MIN_CODE_SIZE = 10
def handle_class(name, member):
if is_accepted(name, member):
return
if member.__doc__ is None and not member_too_small(member):
raise ValueError("{} class doesn't have any documentation".format(name),
member.__module__, inspect.getmodule(member).__file__)
for n, met in inspect.getmembers(member):
if inspect.ismethod(met):
handle_method(n, met)
def handle_function(name, member):
if is_accepted(name, member):
return
doc = member.__doc__
if doc is None and not member_too_small(member):
raise ValueError("{} function doesn't have any documentation".format(name),
member.__module__, inspect.getmodule(member).__file__)
args = list(inspect.signature(member).parameters.keys())
assert_args_presence(args, doc, member, name)
assert_function_style(name, member, doc, args)
assert_doc_style(name, member, doc)
def assert_doc_style(name, member, doc):
lines = doc.split("\n")
first_line = lines[0]
if len(first_line.strip()) == 0:
raise ValueError("{} the documentation should be on the first line.".format(name),
member.__module__)
if first_line.strip()[-1] != '.':
raise ValueError("{} first line should end with a '.'".format(name),
member.__module__)
def assert_function_style(name, member, doc, args):
code = inspect.getsource(member)
has_return = re.findall(r"\s*return \S+", code, re.MULTILINE)
if has_return and "# Returns" not in doc:
innerfunction = [inspect.getsource(x) for x in member.__code__.co_consts if
inspect.iscode(x)]
return_in_sub = [ret for code_inner in innerfunction for ret in
re.findall(r"\s*return \S+", code_inner, re.MULTILINE)]
if len(return_in_sub) < len(has_return):
raise ValueError("{} needs a '# Returns' section".format(name),
member.__module__)
has_raise = re.findall(r"^\s*raise \S+", code, re.MULTILINE)
if has_raise and "# Raises" not in doc:
innerfunction = [inspect.getsource(x) for x in member.__code__.co_consts if
inspect.iscode(x)]
raise_in_sub = [ret for code_inner in innerfunction for ret in
re.findall(r"\s*raise \S+", code_inner, re.MULTILINE)]
if len(raise_in_sub) < len(has_raise):
raise ValueError("{} needs a '# Raises' section".format(name),
member.__module__)
if len(args) > 0 and "# Arguments" not in doc:
raise ValueError("{} needs a '# Arguments' section".format(name),
member.__module__)
assert_blank_before(name, member, doc, ['# Arguments', '# Raises', '# Returns'])
def assert_blank_before(name, member, doc, keywords):
doc_lines = [x.strip() for x in doc.split('\n')]
for keyword in keywords:
if keyword in doc_lines:
index = doc_lines.index(keyword)
if doc_lines[index - 1] != '':
raise ValueError(
"{} '{}' should have a blank line above.".format(name, keyword),
member.__module__)
def is_accepted(name, member):
if 'keras' not in str(member.__module__):
return True
return name in accepted_name or member.__module__ in accepted_module
def member_too_small(member):
code = inspect.getsource(member).split('\n')
return len(code) < MIN_CODE_SIZE
def assert_args_presence(args, doc, member, name):
args_not_in_doc = [arg not in doc for arg in args]
if any(args_not_in_doc):
raise ValueError(
"{} {} arguments are not present in documentation ".format(name, list(
compress(args, args_not_in_doc))), member.__module__)
words = doc.replace('*', '').split()
# Check arguments styling
styles = [arg + ":" not in words for arg in args]
if any(styles):
raise ValueError(
"{} {} are not style properly 'argument': documentation".format(name, list(
compress(args, styles))), member.__module__)
# Check arguments order
indexes = [words.index(arg + ":") for arg in args]
if indexes != sorted(indexes):
raise ValueError(
"{} arguments order is different from the documentation".format(name),
member.__module__)
def handle_method(name, member):
if name in accepted_name or member.__module__ in accepted_module:
return
handle_function(name, member)
def handle_module(mod):
for name, mem in inspect.getmembers(mod):
if inspect.isclass(mem):
handle_class(name, mem)
elif inspect.isfunction(mem):
handle_function(name, mem)
elif 'keras' in name and inspect.ismodule(mem):
# Only test keras' modules
handle_module(mem)
@pytest.mark.skipif(sys.version_info < (3, 3), reason="requires python3.3")
def test_doc():
for module in modules:
mod = importlib.import_module(module)
handle_module(mod)
if __name__ == '__main__':
pytest.main([__file__])
+48 -2
Ver Arquivo
@@ -4,6 +4,7 @@ import tempfile
import numpy as np
from numpy.testing import assert_allclose
from keras import backend as K
from keras.models import Model, Sequential
from keras.layers import Dense, Lambda, RepeatVector, TimeDistributed
from keras.layers import Input
@@ -76,7 +77,7 @@ def test_sequential_model_saving_2():
@keras_test
def test_fuctional_model_saving():
def test_functional_model_saving():
input = Input(shape=(3,))
x = Dense(2)(input)
output = Dense(3)(x)
@@ -131,10 +132,11 @@ def test_saving_multiple_metrics_outputs():
@keras_test
def test_saving_without_compilation():
"""Test saving model without compiling.
"""
model = Sequential()
model.add(Dense(2, input_shape=(3,)))
model.add(Dense(3))
model.compile(loss='mse', optimizer='sgd', metrics=['acc'])
_, fname = tempfile.mkstemp('.h5')
save_model(model, fname)
@@ -291,5 +293,49 @@ def test_saving_lambda_custom_objects():
assert_allclose(out, out2, atol=1e-05)
@keras_test
def test_saving_lambda_numpy_array_arguments():
mean = np.random.random((4, 2, 3))
std = np.abs(np.random.random((4, 2, 3))) + 1e-5
input = Input(shape=(4, 2, 3))
output = Lambda(lambda image, mu, std: (image - mu) / std,
arguments={'mu': mean, 'std': std})(input)
model = Model(input, output)
model.compile(loss='mse', optimizer='sgd', metrics=['acc'])
_, fname = tempfile.mkstemp('.h5')
save_model(model, fname)
model = load_model(fname)
os.remove(fname)
assert_allclose(mean, model.layers[1].arguments['mu'])
assert_allclose(std, model.layers[1].arguments['std'])
@keras_test
def test_saving_custom_activation_function():
x = Input(shape=(3,))
output = Dense(3, activation=K.cos)(x)
model = Model(x, output)
model.compile(loss=losses.MSE,
optimizer=optimizers.RMSprop(lr=0.0001),
metrics=[metrics.categorical_accuracy])
x = np.random.random((1, 3))
y = np.random.random((1, 3))
model.train_on_batch(x, y)
out = model.predict(x)
_, fname = tempfile.mkstemp('.h5')
save_model(model, fname)
model = load_model(fname, custom_objects={'cos': K.cos})
os.remove(fname)
out2 = model.predict(x)
assert_allclose(out, out2, atol=1e-05)
if __name__ == '__main__':
pytest.main([__file__])