Comparar commits

...

62 Commits

Autor SHA1 Mensagem Data
Francois Chollet d135eda40e Update backend docs. 2017-06-30 16:38:16 -07:00
Francois Chollet 49f7649036 Fix backend tests 2017-06-30 15:40:14 -07:00
Francois Chollet 6b16f3c135 Style cleanup, in particular crossentropy backend API 2017-06-30 15:07:09 -07:00
Francois Chollet d9255f15a4 Redirect mobilenet weights path. 2017-06-30 13:59:04 -07:00
Francois Chollet b42f6760bc Fix mobilenet weight preprocessing. 2017-06-30 13:52:14 -07:00
Francois Chollet 6b51d149ca Merge branch 'master' of github.com:fchollet/keras 2017-06-30 12:24:54 -07:00
Francois Chollet 8040ad72dd Fix mobilenet bugs. 2017-06-30 12:24:40 -07:00
nzw ec048edffc Fix typo (#7191) 2017-06-30 11:05:59 -07:00
Francois Chollet 23269507fd CI now fails for test coverage below 80%. 2017-06-29 12:14:04 -07:00
Francois Chollet eafdffff75 Fix NotImplementedError in data_utils.py 2017-06-29 12:13:34 -07:00
jorgecarleitao 5834747dc7 Make load_model's convert_custom_objects recursive 2017-06-29 11:51:56 -07:00
NC Cullen 6c2dea64fc conv3d_transpose in tf, th, and cntk (#7161)
* conv3d_tranpose in tf and th

* fix _preprocess_deconv_output_shape error

* cntk conv3d_tranpose

* conv3d_tranpose test

* formatting

* cleanup tests

* fix incorrect axis ordering and docs

* fix incorrect axis ordering and docs

* deconv3d_output_shape to fix errors

* remove conv2d_transpose reference in theano backend

* remove kernel_size loop from test

* put depth first in test and add dim to invalid use case input

* formatting - removed extra line

* fix pep8

* remove extraneous args from tf conv3d_transpose function

* default val for data_format=None
2017-06-29 09:09:12 -07:00
Alan Yee ddcf66fbe8 Update README.md (#7163)
Remove incorrect usage of "either"
2017-06-29 09:05:17 -07:00
Dapid 5edd96a9f8 Don't warn of repeated data with one worker (#7175)
* Don't warn of repeated data with one worker

If there is only one worker there is no risk of duplicated data.

* Update training.py
2017-06-29 09:03:24 -07:00
Taehoon Lee c6ec39258b Fix styles (#7154) 2017-06-28 06:33:21 -07:00
Kongsea 7866fbaa1a Fix some typos. (#7144)
* Fix some typos.

* Fix a typo
2017-06-27 18:00:58 -07:00
Francois Chollet 94397e08ae Further style fixes. 2017-06-27 16:40:12 -07:00
Francois Chollet 98db0285ee Style fix (avoid use of reserved variable name). 2017-06-27 16:08:10 -07:00
Francois Chollet 7413956e7e Merge branch 'master' of github.com:fchollet/keras 2017-06-27 15:46:05 -07:00
Francois Chollet 9a4598da50 Further style fixes in mobilenet 2017-06-27 15:45:51 -07:00
Frédéric Branchaud-Charron a09c9f6c2d Fix test in training (#7149) 2017-06-27 13:19:54 -07:00
nzw e4ab777d07 Improve documentation (#7150) 2017-06-27 13:19:24 -07:00
Francois Chollet 4fab0bf9a8 Style fixes. 2017-06-27 11:18:57 -07:00
Somshubra Majumdar 49a7c7376d Addition of MobileNet to application (#7009)
* Add MobileNet to application

* Add support for 1001 classes in imagenet utils

* Revert a mistake in the tests

* Setup application test for mobilenet to run only when on tensorflow

* Correct pytest.mark.skipif explanation for skipping tests if not on tensorflow

* Corrected mobilenet to support 1000 classes and reverted imagenet_utils to prior state

* Fix tensorflow test

* Restrict mobilenets to data format "channels_last"

* Add review fixes

* PEP8 fix

* Add relu6 to activations.py

* Corrected imports in mobilenet.py

* Rolled back activation relu6 and inlined it to mobilenet.py

* Refactored DepthwiseConv2D and other corrections

* Fixed tests

* PEP8 correction

* Add docs to private functions and other fixes

* Fix failed test where input shape is None

* Fix value of size for model name
2017-06-27 11:11:48 -07:00
Francois Chollet fb9dbdb10c Remove name-based trainable weight sorting, as it was a source of bugs. 2017-06-26 19:52:14 -07:00
Hideaki Kanehara a85263fb3e unify coding style (#7129) 2017-06-26 11:16:03 -07:00
Gleb Sidora f6c1730cf3 better error message when ReduceLROnPlateau conditioned on non-existing metric (#7134) 2017-06-26 11:15:22 -07:00
vfdev 598954d2c8 * Replace tensorflow deprecated attribute : reduction_indices -> axis (#7126) 2017-06-25 15:17:56 -07:00
nzw 21c5e5479b Add Sequence section in utils page (#7123) 2017-06-25 10:33:25 -07:00
Francois Chollet d1ad183770 Merge branch 'master' of github.com:fchollet/keras 2017-06-23 13:57:34 -07:00
Francois Chollet 9dca90e705 Fix PEP8 2017-06-23 13:56:54 -07:00
Ben 5a7f6b0e74 fix dtype handling in 2 optimizers and 1 layer (#7088)
* fix dtype handling in 2 optimizers and 1 layer

* fix zeros

* Add base_dtype argument

* Fix base_dtype

* remove base_dtype
2017-06-23 13:41:11 -07:00
Francois Chollet 7dcd2982b2 Allow custom print functions for summary 2017-06-23 13:24:20 -07:00
Francois Chollet 3462835597 Improve formatting of CONTRIBUTING.md. 2017-06-22 16:04:52 -07:00
Francois Chollet 585f33f6b7 Add API design review process to CONTRIBUTING.md 2017-06-22 16:03:51 -07:00
Tang, Cheng 1aa9e9199b Add more meaningful message when cnkt can't handle variable length input (#7094)
* return meaningful message when variable input length detected.

* ignore scalar input

* update the recommandation.
2017-06-22 13:11:45 -07:00
Andrew Hundt fb97b6e0fa _check_array_lengths properly handles corner cases with None (#7063)
* _check_array_lengths properly handles corner cases with None

* test_training.py _check_array_lengths() unit test

* set_of_lengths if/else + whitespace

* training.py pep8 whitespace

* training.py restate set more cleanly
2017-06-21 21:29:33 -07:00
Taehoon Lee 60cf7ca6b2 Fix typos (#7087) 2017-06-21 21:28:57 -07:00
Andrew Hundt 1b539993aa training.py _slice_arrays() fix crash when arrays are None (#7069)
* training.py _slice_arrays() fix crash when arrays are None

* training.py test _slice_arrays()
2017-06-21 18:01:30 -07:00
Andrew Hundt de73eda89a .gitignore visual studio code IDE excluded (#7070) 2017-06-21 13:47:52 -07:00
Andrew Hundt 219d6ee5be training.py _weighted_masked_objective fix crash when weights is None (#7068)
* training.py _weighted_masked_objective fix crash when weights is None

* unit test _weighted_masked_objective function
2017-06-21 13:46:55 -07:00
Taehoon Lee f430de10fb Style fixes (#7073) 2017-06-21 10:58:38 -07:00
nzw a2f6ae2c66 Style fix (#7079) 2017-06-21 10:53:59 -07:00
Andrew Hundt b713122e77 wrappers_test.py quick fix for flaky TimeDistributed test (#7062)
full issue: https://github.com/fchollet/keras/pull/7033
2017-06-21 10:50:58 -07:00
Gökçen Eraslan 75470e380f join() OrderedEnqueuer.executor to prevent zombies (#7059) 2017-06-21 10:50:10 -07:00
moi90 b5ad5334fc Add more numpy-style attributes to HDF5Matrix (#6982)
* Add more numpy-style attributes to HDF5Matrix

* Improve docstrings

* Add test coverage

* Add a ´# Returns´ section to shape, dtype, ndim, size.

* Remove whitespace in blank lines

* Use third-person and close docstrings on a new line.
2017-06-21 09:59:29 -07:00
Chris 04a20177cf Avoid DeprecationWarning from inspect.getargspec (rebased) (#7035)
* Utility function to check if a callable has a given keyword argument

* Added unit tests for the has_arg function

* Replace uses of getargspec with the new has_arg function

Not changing keras.backend, because that gives ImportErrors due to
a circular import (conv_utils uses the backend, and is imported
before generic_utils in utils/__init__.py)

Not changing keras.utils.test_utils, because that change exposes
(what looks to me like) a latent bug

* Replace incorrect use of getargspec in test_utils.py

The previous code would always fail to detect the 'weights' argument.
Simply replacing getargspec would cause the tests for some of the legacy
layers to fail because the passed 'weights' argument is bad.

Instead, I have added a check for whether the passed `weights` array
is empty, this avoids tripping the bug.

* Replacing getargspec with has_arg in the backend modules

This requires reordering imports to avoid errors caused by
conv_utils trying to import the backend, the backend wanting to
import generic_utils, and utils/__init__.py listing conv_utils
before generic_utils.

* Removed getargspec from legacy wrapping function

Instead save the wrapped function in an attribute and call
getargspec on this attribute during documentation generation.
2017-06-21 09:58:38 -07:00
Frédéric Branchaud-Charron 58d1d0678f Fix test in multiprocessing (#7058) 2017-06-20 15:56:45 -07:00
Francois Chollet abf8691ade Temp fix to multiprocessing tests 2017-06-20 12:48:18 -07:00
Francois Chollet 7425e68cd6 Style fixes 2017-06-20 12:47:52 -07:00
Frédéric Branchaud-Charron ab6b82c2db Fix the ordering bugs when using pickle_safe=True (#6891)
* Initial support for Datasets

* Fix warnings

* Fix for python2

* Fix travis deps

* Fix python2 indexing

* Fix test and docs

* Avoir use of future, use multiprocessing.pool

* Changed warning and better moduling

* fix threading test

* Move Dataset and enqueuers to utils.data_utils

* Skip None input, add seed for generators

* Skip None input fix

* pep8

* Fix example

* Add test in training and changed Dataset to hold item

* Revert to batch handling

* Docs update

* PEP8

* Rename in test

* Better documentation in Sequence

* Typo in sequence warning

* Rename pickle_safe and max_q_size, typos

* Typo in docstring

* Fix tests in training
2017-06-20 10:55:46 -07:00
Andrea Esuli 6814506528 Renamed one_hot function to hashing_trick, made hashing stable (#6887)
* Replaced one_hot function with hashing_trick

* Update text_test.py

* PEP8 fix

* Update text.py

* Put one_hot back, added documentation

* Changes following the review comments

* PEP8

* Chages after second review

* fixed wrong default for hashing_trick

* formatted documentation

* typo
2017-06-20 10:22:02 -07:00
Shaofan Lai 1ddf23528e Fix bug in preprocess_weights_for_loading (#6960)
* add skip_compile option to keras.models.load_model()

* update document

* change name from skip_compile to compile

* fix bug in `preprocess_weights_for_loading` so that layer of type `Model` can be coverted correctly

* update codestyle

* updated

* fix indent

* revert changing

* update spacing
2017-06-20 10:21:14 -07:00
Sebastian Brandes 86c8d1dd45 Fixed default header in RemoteMonitor callback. (#7040)
* Fixed default header in RemoteMonitor callback.

* Removed default headers from RemoteMonitor

The requests library automatically adds the appropriate headers by default.

* Fixed PEP8 warning in RemoteMonitor constructor
2017-06-20 10:20:28 -07:00
Andrew Hundt 929ae992c2 test_multiprocessing.py fix incorrect use of numpy.random.randint (#7030)
* test_multiprocessing.py fix test which actually throws two exceptions

* test_multiprocessing.py fixed incorrect usage of np.random.randint()
https://docs.scipy.org/doc/numpy-1.11.0/reference/generated/numpy.random.randint.html

* test_multiprocessing.py remove extra parens
2017-06-20 10:18:28 -07:00
Taehoon Lee 3d9428d344 Increase test coverage (#7037) 2017-06-19 12:12:50 -07:00
Rik Nijessen e0543fbfc8 throw an error when receiving empty batch, instead of returning nans at the end (#7038) 2017-06-19 11:23:41 -07:00
Stefan Schweter 767846e642 fix url to LSTM paper (#7025) 2017-06-18 15:59:05 -07:00
Andrey M d852c2d772 Replace plot_loss_callback example with json_logging_callback (#4116) (#6941)
The original plotting example doesn't work and a working version is somewhat too involved for a lambda.
2017-06-18 14:21:39 -07:00
Elliot Saba ff45159b69 Rename tensorboard histogram names to silence warnings (#7017) 2017-06-17 18:22:58 -07:00
Taehoon Lee 7766ab341f Speed up Theano tests (#7011) 2017-06-17 16:26:07 -07:00
François Chollet 4135aeebc4 Revert "Avoid DeprecationWarning from inspect.getargspec (#6817)" (#7018)
This reverts commit ced84c4b42.
2017-06-16 20:47:14 -07:00
52 arquivos alterados com 2570 adições e 533 exclusões
+1
Ver Arquivo
@@ -19,3 +19,4 @@ examples/img/*
# developer environments
.idea
.vscode
+3 -3
Ver Arquivo
@@ -14,9 +14,9 @@ matrix:
- python: 3.5
env: KERAS_BACKEND=tensorflow
- python: 2.7
env: KERAS_BACKEND=theano
env: KERAS_BACKEND=theano THEANO_FLAGS=optimizer=fast_compile
- python: 3.5
env: KERAS_BACKEND=theano
env: KERAS_BACKEND=theano THEANO_FLAGS=optimizer=fast_compile
- python: 2.7
env: KERAS_BACKEND=cntk
- python: 3.5
@@ -86,5 +86,5 @@ script:
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 --ignore=tests/test_documentation.py --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 80 --cov-report term-missing;
fi
+10 -3
Ver Arquivo
@@ -46,13 +46,20 @@ You can also use Github issues to request features you would like to see in Kera
**Where should I submit my pull request?**
1. **Keras improvements and bugfixes** go to the [Keras `master` branch](https://github.com/fchollet/keras/tree/master).
2. **New features** such as layers and datasets go to [keras-contrib](https://github.com/farizrahman4u/keras-contrib). Unless it is a new feature listed in [Requests for Contributions](https://github.com/fchollet/keras/projects/1), in which case it belongs in core Keras.
2. **Experimental new features** such as layers and datasets go to [keras-contrib](https://github.com/farizrahman4u/keras-contrib). Unless it is a new feature listed in [Requests for Contributions](https://github.com/fchollet/keras/projects/1), in which case it belongs in core Keras. If you think your feature belongs in core Keras, you can submit a design doc to explain your feature and argue for it (see explainations below).
Here's a quick guide to submitting your improvements:
1. If your PR introduces a change in functionality, make sure you start by opening an issue to discuss whether the change should be made, and how to handle it. This will save you from having your PR closed down the road! Of course, if your PR is a simple bug fix, you don't need to do that.
1. If your PR introduces a change in functionality, make sure you start by writing a design doc and sending it to the Keras mailing list to discuss whether the change should be made, and how to handle it. This will save you from having your PR closed down the road! Of course, if your PR is a simple bug fix, you don't need to do that. The process for writing and submitting design docs is as follow:
- Start from [this Google Doc template](https://docs.google.com/document/d/1ZXNfce77LDW9tFAj6U5ctaJmI5mT7CQXOFMEAZo-mAA/edit#), and copy it to new Google doc.
- Fill in the content. Note that you will need to insert code examples. To insert code, use a Google Doc extension such as [CodePretty](https://chrome.google.com/webstore/detail/code-pretty/igjbncgfgnfpbnifnnlcmjfbnidkndnh?hl=en) (there are several such extensions available).
- Set sharing settings to "everyone with the link is allowed to comment"
- Send the document to `keras-users@googlegroups.com` with a subject that starts with `[API DESIGN REVIEW]` (all caps) so that we notice it.
- Wait for comments, and answer them as they come. Edit the proposal as necessary.
- The proposal will finally be approved or rejected. Once approved, you can send out Pull Requests or ask others to write Pull Requests.
2. Write the code. This is the hard part!
2. Write the code (or get others to write it). 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. **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.
+1 -1
Ver Arquivo
@@ -5,7 +5,7 @@
## 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), [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.*
Keras is a high-level neural networks API, written in Python and capable of running on top of [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:
+6 -3
Ver Arquivo
@@ -286,7 +286,8 @@ PAGES = [
'page': 'utils.md',
'all_module_functions': [utils],
'classes': [utils.CustomObjectScope,
utils.HDF5Matrix]
utils.HDF5Matrix,
utils.Sequence]
},
]
@@ -320,9 +321,11 @@ def get_classes_ancestors(classes):
def get_function_signature(function, method=True):
signature = getattr(function, '_legacy_support_signature', None)
if signature is None:
wrapped = getattr(function, '_original_function', None)
if wrapped is None:
signature = inspect.getargspec(function)
else:
signature = inspect.getargspec(wrapped)
defaults = signature.defaults
if method:
args = signature.args[1:]
+4 -3
Ver Arquivo
@@ -17,6 +17,7 @@ model.add(Dense(64, kernel_constraint=max_norm(2.)))
## Available constraints
- __max_norm__(max_value=2, axis=0): maximum-norm constraint
- __non_neg__(): non-negativity constraint
- __unit_norm__(): unit-norm constraint, enforces the matrix to have unit norm along the last axis
- __max_norm(max_value=2, axis=0)__: maximum-norm constraint
- __non_neg()__: non-negativity constraint
- __unit_norm(axis=0)__: unit-norm constraint
- __min_max_norm(min_value=0.0, max_value=1.0, rate=1.0, axis=0)__: minimum/maximum-norm constraint
+56 -9
Ver Arquivo
@@ -2,8 +2,10 @@
## text_to_word_sequence
```python
keras.preprocessing.text.text_to_word_sequence(text,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', lower=True, split=" ")
keras.preprocessing.text.text_to_word_sequence(text,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=" ")
```
Split a sentence into a list of words.
@@ -12,29 +14,74 @@ Split a sentence into a list of words.
- __Arguments__:
- __text__: str.
- __filters__: list (or concatenation) of characters to filter out, such as punctuation. Default: '!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n' , 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.
## one_hot
```python
keras.preprocessing.text.one_hot(text, n,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n', lower=True, split=" ")
keras.preprocessing.text.one_hot(text,
n,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=" ")
```
One-hot encode a text into a list of word indexes in a vocabulary of size n.
One-hot encodes a text into a list of word indexes in a vocabulary of size n.
This is a wrapper to the `hashing_trick` function using `hash` as the hashing function.
- __Return__: List of integers in [1, n]. Each integer encodes a word (unicity non-guaranteed).
- __Arguments__: Same as `text_to_word_sequence` above.
- __Arguments__:
- __text__: str.
- __n__: int. Size of vocabulary.
- __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.
## hashing_trick
```python
keras.preprocessing.text.hashing_trick(text,
n,
hash_function=None,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=' ')
```
Converts a text to a sequence of indices in a fixed-size hashing space
- __Return__:
A list of integer word indices (unicity non-guaranteed).
- __Arguments__:
- __text__: str.
- __n__: Dimension of the hashing space.
- __hash_function__: defaults to python `hash` function, can be 'md5' or
any function that takes in input a string and returns a int.
Note that 'hash' is not a stable hashing function, so
it is not consistent across different runs, while 'md5'
is a stable hashing function.
- __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.
## Tokenizer
```python
keras.preprocessing.text.Tokenizer(num_words=None, filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True, split=" ", char_level=False)
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).
+2 -2
Ver Arquivo
@@ -136,8 +136,8 @@ def shuffle_mats_or_lists(matrix_list, stop_ind=None):
elif isinstance(mat, list):
ret.append([mat[i] for i in a])
else:
raise TypeError('shuffle_mats_or_lists only supports '
'numpy.array and list objects')
raise TypeError('`shuffle_mats_or_lists` only supports '
'numpy.array and list objects.')
return ret
+2 -1
Ver Arquivo
@@ -79,7 +79,8 @@ decoder_deconv_1 = Conv2DTranspose(filters,
padding='same',
strides=1,
activation='relu')
decoder_deconv_2 = Conv2DTranspose(filters, num_conv,
decoder_deconv_2 = Conv2DTranspose(filters,
kernel_size=num_conv,
padding='same',
strides=1,
activation='relu')
+1
Ver Arquivo
@@ -3,3 +3,4 @@ from .vgg19 import VGG19
from .resnet50 import ResNet50
from .inception_v3 import InceptionV3
from .xception import Xception
from .mobilenet import MobileNet
+641
Ver Arquivo
@@ -0,0 +1,641 @@
"""MobileNet v1 models for Keras.
MobileNet is a general architecture and can be used for multiple use cases.
Depending on the use case, it can use different input layer size and
different width factors. This allows different width models to reduce
the number of multiply-adds and thereby
reduce inference cost on mobile devices.
MobileNets support any input size greater than 32 x 32, with larger image sizes
offering better performance.
The number of parameters and number of multiply-adds
can be modified by using the `alpha` parameter,
which increases/decreases the number of filters in each layer.
By altering the image size and `alpha` parameter,
all 16 models from the paper can be built, with ImageNet weights provided.
The paper demonstrates the performance of MobileNets using `alpha` values of
1.0 (also called 100 % MobileNet), 0.75, 0.5 and 0.25.
For each of these `alpha` values, weights for 4 different input image sizes
are provided (224, 192, 160, 128).
The following table describes the size and accuracy of the 100% MobileNet
on size 224 x 224:
----------------------------------------------------------------------------
Width Multiplier (alpha) | ImageNet Acc | Multiply-Adds (M) | Params (M)
----------------------------------------------------------------------------
| 1.0 MobileNet-224 | 70.6 % | 529 | 4.2 |
| 0.75 MobileNet-224 | 68.4 % | 325 | 2.6 |
| 0.50 MobileNet-224 | 63.7 % | 149 | 1.3 |
| 0.25 MobileNet-224 | 50.6 % | 41 | 0.5 |
----------------------------------------------------------------------------
The following table describes the performance of
the 100 % MobileNet on various input sizes:
------------------------------------------------------------------------
Resolution | ImageNet Acc | Multiply-Adds (M) | Params (M)
------------------------------------------------------------------------
| 1.0 MobileNet-224 | 70.6 % | 529 | 4.2 |
| 1.0 MobileNet-192 | 69.1 % | 529 | 4.2 |
| 1.0 MobileNet-160 | 67.2 % | 529 | 4.2 |
| 1.0 MobileNet-128 | 64.4 % | 529 | 4.2 |
------------------------------------------------------------------------
The weights for all 16 models are obtained and translated
from Tensorflow checkpoints found at
https://github.com/tensorflow/models/blob/master/slim/nets/mobilenet_v1.md
# Reference
- [MobileNets: Efficient Convolutional Neural Networks for
Mobile Vision Applications](https://arxiv.org/pdf/1704.04861.pdf))
"""
from __future__ import print_function
from __future__ import absolute_import
from __future__ import division
import warnings
from ..models import Model
from ..layers import Input
from ..layers import Activation
from ..layers import Dropout
from ..layers import Reshape
from ..layers import BatchNormalization
from ..layers import GlobalAveragePooling2D
from ..layers import GlobalMaxPooling2D
from ..layers import Conv2D
from .. import initializers
from .. import regularizers
from .. import constraints
from ..utils import conv_utils
from ..utils.data_utils import get_file
from ..engine.topology import get_source_inputs
from ..engine import InputSpec
from ..applications.imagenet_utils import _obtain_input_shape
from ..applications.imagenet_utils import decode_predictions
from .. import backend as K
BASE_WEIGHT_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.6/'
def relu6(x):
return K.relu(x, max_value=6)
def preprocess_input(x):
x /= 255.
x -= 0.5
x *= 2.
return x
class DepthwiseConv2D(Conv2D):
"""Depthwise separable 2D convolution.
Depthwise Separable convolutions consists in performing
just the first step in a depthwise spatial convolution
(which acts on each input channel separately).
The `depth_multiplier` argument controls how many
output channels are generated per input channel in the depthwise step.
# Arguments
kernel_size: An integer or tuple/list of 2 integers, specifying the
width and height of the 2D convolution window.
Can be a single integer to specify the same value for
all spatial dimensions.
strides: An integer or tuple/list of 2 integers,
specifying the strides of the convolution along the width and height.
Can be a single integer to specify the same value for
all spatial dimensions.
Specifying any stride value != 1 is incompatible with specifying
any `dilation_rate` value != 1.
padding: one of `"valid"` or `"same"` (case-insensitive).
depth_multiplier: The number of depthwise convolution output channels
for each input channel.
The total number of depthwise convolution output
channels will be equal to `filters_in * depth_multiplier`.
data_format: A string,
one of `channels_last` (default) or `channels_first`.
The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape
`(batch, height, width, channels)` while `channels_first`
corresponds to inputs with shape
`(batch, channels, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
If you never set it, then it will be "channels_last".
activation: Activation function to use
(see [activations](../activations.md)).
If you don't specify anything, no activation is applied
(ie. "linear" activation: `a(x) = x`).
use_bias: Boolean, whether the layer uses a bias vector.
depthwise_initializer: Initializer for the depthwise kernel matrix
(see [initializers](../initializers.md)).
bias_initializer: Initializer for the bias vector
(see [initializers](../initializers.md)).
depthwise_regularizer: Regularizer function applied to
the depthwise kernel matrix
(see [regularizer](../regularizers.md)).
bias_regularizer: Regularizer function applied to the bias vector
(see [regularizer](../regularizers.md)).
activity_regularizer: Regularizer function applied to
the output of the layer (its "activation").
(see [regularizer](../regularizers.md)).
depthwise_constraint: Constraint function applied to
the depthwise kernel matrix
(see [constraints](../constraints.md)).
bias_constraint: Constraint function applied to the bias vector
(see [constraints](../constraints.md)).
# Input shape
4D tensor with shape:
`[batch, channels, rows, cols]` if data_format='channels_first'
or 4D tensor with shape:
`[batch, rows, cols, channels]` if data_format='channels_last'.
# Output shape
4D tensor with shape:
`[batch, filters, new_rows, new_cols]` if data_format='channels_first'
or 4D tensor with shape:
`[batch, new_rows, new_cols, filters]` if data_format='channels_last'.
`rows` and `cols` values might have changed due to padding.
"""
def __init__(self,
kernel_size,
strides=(1, 1),
padding='valid',
depth_multiplier=1,
data_format=None,
activation=None,
use_bias=True,
depthwise_initializer='glorot_uniform',
bias_initializer='zeros',
depthwise_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
depthwise_constraint=None,
bias_constraint=None,
**kwargs):
super(DepthwiseConv2D, self).__init__(
filters=None,
kernel_size=kernel_size,
strides=strides,
padding=padding,
data_format=data_format,
activation=activation,
use_bias=use_bias,
bias_regularizer=bias_regularizer,
activity_regularizer=activity_regularizer,
bias_constraint=bias_constraint,
**kwargs)
self.depth_multiplier = depth_multiplier
self.depthwise_initializer = initializers.get(depthwise_initializer)
self.depthwise_regularizer = regularizers.get(depthwise_regularizer)
self.depthwise_constraint = constraints.get(depthwise_constraint)
self.bias_initializer = initializers.get(bias_initializer)
def build(self, input_shape):
if len(input_shape) < 4:
raise ValueError('Inputs to `DepthwiseConv2D` should have rank 4. '
'Received input shape:', str(input_shape))
if self.data_format == 'channels_first':
channel_axis = 1
else:
channel_axis = 3
if input_shape[channel_axis] is None:
raise ValueError('The channel dimension of the inputs to '
'`DepthwiseConv2D` '
'should be defined. Found `None`.')
input_dim = int(input_shape[channel_axis])
depthwise_kernel_shape = (self.kernel_size[0],
self.kernel_size[1],
input_dim,
self.depth_multiplier)
self.depthwise_kernel = self.add_weight(
shape=depthwise_kernel_shape,
initializer=self.depthwise_initializer,
name='depthwise_kernel',
regularizer=self.depthwise_regularizer,
constraint=self.depthwise_constraint)
if self.use_bias:
self.bias = self.add_weight(shape=(input_dim * self.depth_multiplier,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
constraint=self.bias_constraint)
else:
self.bias = None
# Set input spec.
self.input_spec = InputSpec(ndim=4, axes={channel_axis: input_dim})
self.built = True
def call(self, inputs, training=None):
outputs = K.depthwise_conv2d(
inputs,
self.depthwise_kernel,
strides=self.strides,
padding=self.padding,
dilation_rate=self.dilation_rate,
data_format=self.data_format)
if self.bias:
outputs = K.bias_add(
outputs,
self.bias,
data_format=self.data_format)
if self.activation is not None:
return self.activation(outputs)
return outputs
def compute_output_shape(self, input_shape):
if self.data_format == 'channels_first':
rows = input_shape[2]
cols = input_shape[3]
out_filters = input_shape[1] * self.depth_multiplier
elif self.data_format == 'channels_last':
rows = input_shape[1]
cols = input_shape[2]
out_filters = input_shape[3] * self.depth_multiplier
rows = conv_utils.conv_output_length(rows, self.kernel_size[0],
self.padding,
self.strides[0])
cols = conv_utils.conv_output_length(cols, self.kernel_size[1],
self.padding,
self.strides[1])
if self.data_format == 'channels_first':
return (input_shape[0], out_filters, rows, cols)
elif self.data_format == 'channels_last':
return (input_shape[0], rows, cols, out_filters)
def get_config(self):
config = super(DepthwiseConv2D, self).get_config()
config.pop('filters')
config.pop('kernel_initializer')
config.pop('kernel_regularizer')
config.pop('kernel_constraint')
config['depth_multiplier'] = self.depth_multiplier
config['depthwise_initializer'] = initializers.serialize(self.depthwise_initializer)
config['depthwise_regularizer'] = regularizers.serialize(self.depthwise_regularizer)
config['depthwise_constraint'] = constraints.serialize(self.depthwise_constraint)
return config
def MobileNet(input_shape=None,
alpha=1.0,
depth_multiplier=1,
dropout=1e-3,
include_top=True,
weights='imagenet',
input_tensor=None,
pooling=None,
classes=1000):
"""Instantiates the MobileNet architecture.
Note that only TensorFlow is supported for now,
therefore it only works with the data format
`image_data_format='channels_last'` in your Keras config
at `~/.keras/keras.json`.
To load a MobileNet model via `load_model`, import the custom
objects `relu6` and `DepthwiseConv2D` and pass them to the
`custom_objects` parameter.
E.g.
model = load_model('mobilenet.h5', custom_objects={
'relu6': mobilenet.relu6,
'DepthwiseConv2D': mobilenet.DepthwiseConv2D})
# Arguments
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, 224) (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 32.
E.g. `(200, 200, 3)` would be one valid value.
alpha: controls the width of the network.
- If `alpha` < 1.0, proportionally decreases the number
of filters in each layer.
- If `alpha` > 1.0, proportionally increases the number
of filters in each layer.
- If `alpha` = 1, default number of filters from the paper
are used at each layer.
depth_multiplier: depth multiplier for depthwise convolution
(also called the resolution multiplier)
dropout: dropout rate
include_top: whether to include the fully-connected
layer at the top of the network.
weights: `None` (random initialization) or
`imagenet` (ImageNet weights)
input_tensor: optional Keras tensor (i.e. output of
`layers.Input()`)
to use as image input for the model.
pooling: Optional pooling mode for feature extraction
when `include_top` is `False`.
- `None` means that the output of the model
will be the 4D tensor output of the
last convolutional layer.
- `avg` means that global average pooling
will be applied to the output of the
last convolutional layer, and thus
the output of the model will be a
2D tensor.
- `max` means that global max pooling will
be applied.
classes: optional number of classes to classify images
into, only to be specified if `include_top` is True, and
if no `weights` argument is specified.
# Returns
A Keras model instance.
# Raises
ValueError: in case of invalid argument for `weights`,
or invalid input shape.
RuntimeError: If attempting to run this model with a
backend that does not support separable convolutions.
"""
if K.backend() != 'tensorflow':
raise RuntimeError('Only Tensorflow backend is currently supported, '
'as other backends do not support '
'depthwise convolution.')
if weights not in {'imagenet', None}:
raise ValueError('The `weights` argument should be either '
'`None` (random initialization) or `imagenet` '
'(pre-training on ImageNet).')
if weights == 'imagenet' and include_top and classes != 1000:
raise ValueError('If using `weights` as ImageNet with `include_top` '
'as true, `classes` should be 1000')
# Determine proper input shape.
input_shape = _obtain_input_shape(input_shape,
default_size=224,
min_size=32,
data_format=K.image_data_format(),
include_top=include_top or weights)
if K.image_data_format() == 'channels_last':
row_axis, col_axis = (0, 1)
else:
row_axis, col_axis = (1, 2)
rows = input_shape[row_axis]
cols = input_shape[col_axis]
if weights == 'imagenet':
if depth_multiplier != 1:
raise ValueError('If imagenet weights are being loaded, '
'depth multiplier must be 1')
if alpha not in [0.25, 0.50, 0.75, 1.0]:
raise ValueError('If imagenet weights are being loaded, '
'alpha can be one of'
'`0.25`, `0.50`, `0.75` or `1.0` only.')
if rows != cols or rows not in [128, 160, 192, 224]:
raise ValueError('If imagenet weights are being loaded, '
'input must have a static square shape (one of '
'(128,128), (160,160), (192,192), or (224, 224)).'
' Input shape provided = %s' % (input_shape,))
if K.image_data_format() != 'channels_last':
warnings.warn('The MobileNet family of models is only available '
'for the input data format "channels_last" '
'(width, height, channels). '
'However your settings specify the default '
'data format "channels_first" (channels, width, height).'
' You should set `image_data_format="channels_last"` '
'in your Keras config located at ~/.keras/keras.json. '
'The model being returned right now will expect inputs '
'to follow the "channels_last" data format.')
K.set_image_data_format('channels_last')
old_data_format = 'channels_first'
else:
old_data_format = None
if input_tensor is None:
img_input = Input(shape=input_shape)
else:
if not K.is_keras_tensor(input_tensor):
img_input = Input(tensor=input_tensor, shape=input_shape)
else:
img_input = input_tensor
x = _conv_block(img_input, 32, alpha, strides=(2, 2))
x = _depthwise_conv_block(x, 64, alpha, depth_multiplier, block_id=1)
x = _depthwise_conv_block(x, 128, alpha, depth_multiplier,
strides=(2, 2), block_id=2)
x = _depthwise_conv_block(x, 128, alpha, depth_multiplier, block_id=3)
x = _depthwise_conv_block(x, 256, alpha, depth_multiplier,
strides=(2, 2), block_id=4)
x = _depthwise_conv_block(x, 256, alpha, depth_multiplier, block_id=5)
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier,
strides=(2, 2), block_id=6)
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=7)
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=8)
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=9)
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=10)
x = _depthwise_conv_block(x, 512, alpha, depth_multiplier, block_id=11)
x = _depthwise_conv_block(x, 1024, alpha, depth_multiplier,
strides=(2, 2), block_id=12)
x = _depthwise_conv_block(x, 1024, alpha, depth_multiplier, block_id=13)
if include_top:
if K.image_data_format() == 'channels_first':
shape = (int(1024 * alpha), 1, 1)
else:
shape = (1, 1, int(1024 * alpha))
x = GlobalAveragePooling2D()(x)
x = Reshape(shape, name='reshape_1')(x)
x = Dropout(dropout, name='dropout')(x)
x = Conv2D(classes, (1, 1),
padding='same', name='conv_preds')(x)
x = Activation('softmax', name='act_softmax')(x)
x = Reshape((classes,), name='reshape_2')(x)
else:
if pooling == 'avg':
x = GlobalAveragePooling2D()(x)
elif pooling == 'max':
x = GlobalMaxPooling2D()(x)
# Ensure that the model takes into account
# any potential predecessors of `input_tensor`.
if input_tensor is not None:
inputs = get_source_inputs(input_tensor)
else:
inputs = img_input
# Create model.
model = Model(inputs, x, name='mobilenet_%0.2f_%s' % (alpha, rows))
# load weights
if weights == 'imagenet':
if K.image_data_format() == 'channels_first':
raise ValueError('Weights for "channels_last" format '
'are not available.')
if alpha == 1.0:
alpha_text = '1_0'
elif alpha == 0.75:
alpha_text = '7_5'
elif alpha == 0.50:
alpha_text = '5_0'
else:
alpha_text = '2_5'
if include_top:
model_name = 'mobilenet_%s_%d_tf.h5' % (alpha_text, rows)
weigh_path = BASE_WEIGHT_PATH + model_name
weights_path = get_file(model_name,
weigh_path,
cache_subdir='models')
else:
model_name = 'mobilenet_%s_%d_tf_no_top.h5' % (alpha_text, rows)
weigh_path = BASE_WEIGHT_PATH + model_name
weights_path = get_file(model_name,
weigh_path,
cache_subdir='models')
model.load_weights(weights_path)
if old_data_format:
K.set_image_data_format(old_data_format)
return model
def _conv_block(inputs, filters, alpha, kernel=(3, 3), strides=(1, 1)):
"""Adds an initial convolution layer (with batch normalization and relu6).
# Arguments
inputs: Input tensor of shape `(rows, cols, 3)`
(with `channels_last` data format) or
(3, rows, cols) (with `channels_first` data format).
It should have exactly 3 inputs channels,
and width and height should be no smaller than 32.
E.g. `(224, 224, 3)` would be one valid value.
filters: Integer, the dimensionality of the output space
(i.e. the number output of filters in the convolution).
alpha: controls the width of the network.
- If `alpha` < 1.0, proportionally decreases the number
of filters in each layer.
- If `alpha` > 1.0, proportionally increases the number
of filters in each layer.
- If `alpha` = 1, default number of filters from the paper
are used at each layer.
kernel: An integer or tuple/list of 2 integers, specifying the
width and height of the 2D convolution window.
Can be a single integer to specify the same value for
all spatial dimensions.
strides: An integer or tuple/list of 2 integers,
specifying the strides of the convolution along the width and height.
Can be a single integer to specify the same value for
all spatial dimensions.
Specifying any stride value != 1 is incompatible with specifying
any `dilation_rate` value != 1.
# Input shape
4D tensor with shape:
`(samples, channels, rows, cols)` if data_format='channels_first'
or 4D tensor with shape:
`(samples, rows, cols, channels)` if data_format='channels_last'.
# Output shape
4D tensor with shape:
`(samples, filters, new_rows, new_cols)` if data_format='channels_first'
or 4D tensor with shape:
`(samples, new_rows, new_cols, filters)` if data_format='channels_last'.
`rows` and `cols` values might have changed due to stride.
# Returns
Output tensor of block.
"""
channel_axis = 1 if K.image_data_format() == 'channels_first' else -1
filters = int(filters * alpha)
x = Conv2D(filters, kernel,
padding='same',
use_bias=False,
strides=strides,
name='conv1')(inputs)
x = BatchNormalization(axis=channel_axis, name='conv1_bn')(x)
return Activation(relu6, name='conv1_relu')(x)
def _depthwise_conv_block(inputs, pointwise_conv_filters, alpha,
depth_multiplier=1, strides=(1, 1), block_id=1):
"""Adds a depthwise convolution block.
A depthwise convolution block consists of a depthwise conv,
batch normalization, relu6, pointwise convolution,
batch normalization and relu6 activation.
# Arguments
inputs: Input tensor of shape `(rows, cols, channels)`
(with `channels_last` data format) or
(channels, rows, cols) (with `channels_first` data format).
pointwise_conv_filters: Integer, the dimensionality of the output space
(i.e. the number output of filters in the pointwise convolution).
alpha: controls the width of the network.
- If `alpha` < 1.0, proportionally decreases the number
of filters in each layer.
- If `alpha` > 1.0, proportionally increases the number
of filters in each layer.
- If `alpha` = 1, default number of filters from the paper
are used at each layer.
depth_multiplier: The number of depthwise convolution output channels
for each input channel.
The total number of depthwise convolution output
channels will be equal to `filters_in * depth_multiplier`.
strides: An integer or tuple/list of 2 integers,
specifying the strides of the convolution along the width and height.
Can be a single integer to specify the same value for
all spatial dimensions.
Specifying any stride value != 1 is incompatible with specifying
any `dilation_rate` value != 1.
block_id: Integer, a unique identification designating the block number.
# Input shape
4D tensor with shape:
`(batch, channels, rows, cols)` if data_format='channels_first'
or 4D tensor with shape:
`(batch, rows, cols, channels)` if data_format='channels_last'.
# Output shape
4D tensor with shape:
`(batch, filters, new_rows, new_cols)` if data_format='channels_first'
or 4D tensor with shape:
`(batch, new_rows, new_cols, filters)` if data_format='channels_last'.
`rows` and `cols` values might have changed due to stride.
# Returns
Output tensor of block.
"""
channel_axis = 1 if K.image_data_format() == 'channels_first' else -1
pointwise_conv_filters = int(pointwise_conv_filters * alpha)
x = DepthwiseConv2D((3, 3),
padding='same',
depth_multiplier=depth_multiplier,
strides=strides,
use_bias=False,
name='conv_dw_%d' % block_id)(inputs)
x = BatchNormalization(axis=channel_axis, name='conv_dw_%d_bn' % block_id)(x)
x = Activation(relu6, name='conv_dw_%d_relu' % block_id)(x)
x = Conv2D(pointwise_conv_filters, (1, 1),
padding='same',
use_bias=False,
strides=(1, 1),
name='conv_pw_%d' % block_id)(x)
x = BatchNormalization(axis=channel_axis, name='conv_pw_%d_bn' % block_id)(x)
return Activation(relu6, name='conv_pw_%d_relu' % block_id)(x)
+1 -1
Ver Arquivo
@@ -77,7 +77,7 @@ def identity_block(input_tensor, kernel_size, filters, stage, block):
def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):
"""conv_block is the block that has a conv layer at shortcut
"""A block that has a conv layer at shortcut.
# Arguments
input_tensor: input tensor
+123 -36
Ver Arquivo
@@ -1,7 +1,7 @@
from __future__ import print_function
import cntk as C
import numpy as np
from .common import _FLOATX, _EPSILON, image_dim_ordering, image_data_format
from .common import floatx, epsilon, image_dim_ordering, image_data_format
from collections import defaultdict
from contextlib import contextmanager
import warnings
@@ -130,7 +130,10 @@ def _convert_dtype_string(dtype):
'float64.' % dtype)
def variable(value, dtype=_FLOATX, name=None):
def variable(value, dtype=None, name=None):
if dtype is None:
dtype = floatx()
if name is None:
name = ''
@@ -227,10 +230,12 @@ def eval(x):
def placeholder(
shape=None,
ndim=None,
dtype=_FLOATX,
dtype=None,
sparse=False,
name=None,
dynamic_axis_num=1):
if dtype is None:
dtype = floatx()
if not shape:
if ndim:
shape = tuple([None for _ in range(ndim)])
@@ -304,7 +309,7 @@ def _prepare_name(name, default):
def constant(value, dtype=None, shape=None, name=None):
if dtype is None:
dtype = _FLOATX
dtype = floatx()
if shape is None:
shape = ()
np_value = value * np.ones(shape)
@@ -351,8 +356,10 @@ def random_uniform(shape, minval=0.0, maxval=1.0, dtype=None, seed=None):
return random_uniform_variable(shape, minval, maxval, dtype, seed)
def random_uniform_variable(shape, low, high, dtype=_FLOATX,
name=None, seed=None):
def random_uniform_variable(shape, low, high,
dtype=None, name=None, seed=None):
if dtype is None:
dtype = floatx()
if seed is None:
# ensure that randomness is conditioned by the Numpy RNG
seed = np.random.randint(10e3)
@@ -380,9 +387,11 @@ def random_normal_variable(
shape,
mean,
scale,
dtype=_FLOATX,
dtype=None,
name=None,
seed=None):
if dtype is None:
dtype = floatx()
if seed is None:
# ensure that randomness is conditioned by the Numpy RNG
seed = np.random.randint(10e7)
@@ -403,7 +412,9 @@ def random_normal_variable(
name=name)
def random_normal(shape, mean=0.0, stddev=1.0, dtype=_FLOATX, seed=None):
def random_normal(shape, mean=0.0, stddev=1.0, dtype=None, seed=None):
if dtype is None:
dtype = floatx()
for _ in shape:
if _ is None:
raise ValueError('CNTK Backend: randomness op with '
@@ -435,17 +446,23 @@ def dtype(x):
return _convert_dtype_string(x.dtype)
def zeros(shape, dtype=_FLOATX, name=None):
def zeros(shape, dtype=None, name=None):
if dtype is None:
dtype = floatx()
ctype = _convert_string_dtype(dtype)
return variable(value=np.zeros(shape, ctype), dtype=dtype, name=name)
def ones(shape, dtype=_FLOATX, name=None):
def ones(shape, dtype=None, name=None):
if dtype is None:
dtype = floatx()
ctype = _convert_string_dtype(dtype)
return variable(value=np.ones(shape, ctype), dtype=dtype, name=name)
def eye(size, dtype=_FLOATX, name=None):
def eye(size, dtype=None, name=None):
if dtype is None:
dtype = floatx()
return variable(np.eye(size), dtype, name)
@@ -652,16 +669,16 @@ def _normalize_axis(axis, x):
nones = _get_dynamic_axis_num(x)
if type(axis) is tuple:
if isinstance(axis, tuple):
_axis = list(axis)
elif type(axis) is int:
elif isinstance(axis, int):
_axis = [axis]
elif type(axis) is list:
elif isinstance(axis, list):
_axis = list(axis)
else:
_axis = axis
if type(_axis) is list:
if isinstance(_axis, list):
for i, a in enumerate(_axis):
if a is not None and a < 0:
_axis[i] = (a % ndim)
@@ -729,7 +746,7 @@ def all(x, axis=None, keepdims=False):
return all_matrix
def classification_error(output, target, axis=-1):
def classification_error(target, output, axis=-1):
return C.ops.reduce_mean(
C.equal(
argmax(
@@ -801,10 +818,10 @@ def clip(x, min_value, max_value):
return C.clip(x, min_value, max_value)
def binary_crossentropy(output, target, from_logits=False):
def binary_crossentropy(target, output, from_logits=False):
if from_logits:
output = C.sigmoid(output)
output = C.clip(output, _EPSILON, 1.0 - _EPSILON)
output = C.clip(output, epsilon(), 1.0 - epsilon())
output = -target * C.log(output) - (1.0 - target) * C.log(1.0 - output)
return output
@@ -1352,6 +1369,16 @@ def conv2d(x, kernel, strides=(1, 1), padding='valid',
return _postprocess_conv2d_output(x, data_format)
def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
padding='valid', data_format=None, dilation_rate=(1, 1)):
raise NotImplementedError
def depthwise_conv2d(x, depthwise_kernel, strides=(1, 1), padding='valid',
data_format=None, dilation_rate=(1, 1)):
raise NotImplementedError
def conv3d(x, kernel, strides=(1, 1, 1), padding='valid',
data_format=None, dilation_rate=(1, 1, 1)):
if data_format is None:
@@ -1376,6 +1403,41 @@ def conv3d(x, kernel, strides=(1, 1, 1), padding='valid',
return _postprocess_conv3d_output(x, data_format)
def conv3d_transpose(x, kernel, output_shape, strides=(1, 1, 1),
padding='valid', 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))
x = _preprocess_conv3d_input(x, data_format)
kernel = _preprocess_conv3d_kernel(kernel, data_format)
padding = _preprocess_border_mode(padding)
strides = (1,) + strides
# cntk output_shape does not include batch axis
output_shape = output_shape[1:]
# in keras2, need handle output shape in different format
if data_format == 'channels_last':
shape = list(output_shape)
shape[0] = output_shape[3]
shape[1] = output_shape[0]
shape[2] = output_shape[1]
shape[3] = output_shape[2]
output_shape = tuple(shape)
x = C.convolution_transpose(
kernel,
x,
strides,
auto_padding=[
False,
padding,
padding,
padding],
output_shape=output_shape)
return _postprocess_conv3d_output(x, data_format)
def pool2d(x, pool_size, strides=(1, 1),
padding='valid', data_format=None,
pool_mode='max'):
@@ -1477,7 +1539,7 @@ def softsign(x):
return x / (1 + C.abs(x))
def categorical_crossentropy(output, target, from_logits=False):
def categorical_crossentropy(target, output, from_logits=False):
if from_logits:
result = C.cross_entropy_with_softmax(output, target)
# cntk's result shape is (batch, 1), while keras expect (batch, )
@@ -1485,18 +1547,19 @@ def categorical_crossentropy(output, target, from_logits=False):
else:
# scale preds so that the class probas of each sample sum to 1
output /= C.reduce_sum(output, axis=-1)
# avoid numerical instability with _EPSILON clipping
output = C.clip(output, _EPSILON, 1.0 - _EPSILON)
# avoid numerical instability with epsilon clipping
output = C.clip(output, epsilon(), 1.0 - epsilon())
return -sum(target * C.log(output), axis=-1)
def sparse_categorical_crossentropy(output, target, from_logits=False):
def sparse_categorical_crossentropy(target, output, from_logits=False):
target = C.one_hot(target, output.shape[-1])
target = C.reshape(target, output.shape)
return categorical_crossentropy(output, target, from_logits)
class Function(object):
def __init__(self, inputs, outputs, updates=[], **kwargs):
self.placeholders = inputs
self.trainer = None
@@ -1533,11 +1596,12 @@ class Function(object):
p_list.append(grad_parameter_dict[g])
u_list.append(g)
else:
raise ValueError('CNTK backend: when constructing trainer, '
'found gradient node `%s` which is not '
'related to any parameters in the model. '
'Please double check how the gradient node '
'is constructed.' % g)
raise ValueError(
'CNTK backend: when constructing trainer, '
'found gradient node `%s` which is not '
'related to any parameters in the model. '
'Please double check how the gradient node '
'is constructed.' % g)
if len(u_list) > 0:
learner = C.cntk_py.universal_learner(p_list, u_list, update_func)
@@ -1567,6 +1631,17 @@ class Function(object):
else:
self.metrics_func = None
@staticmethod
def _is_input_shape_compatible(input, placeholder):
if hasattr(input, 'shape') and hasattr(placeholder, 'shape'):
num_dynamic = get_num_dynamic_axis(placeholder)
input_shape = input.shape[num_dynamic:]
placeholder_shape = placeholder.shape
for i, p in zip(input_shape, placeholder_shape):
if i != p and p != C.InferredDimension:
return False
return True
def __call__(self, inputs):
assert type(inputs) in {list, tuple}
feed_dict = {}
@@ -1576,6 +1651,15 @@ class Function(object):
value.dtype != np.float32 and
value.dtype != np.float64):
value = value.astype(np.float32)
# in current version cntk can't support input with variable
# length. Will support it in next release.
if not self._is_input_shape_compatible(value, tensor):
raise ValueError(
'CNTK backend: The placeholder has been resolved '
'to shape `%s`, but input shape is `%s`. Currently '
'CNTK can not take variable length inputs. Please '
'pass inputs that have a static shape.'
% (tensor.shape, value.shape))
feed_dict[tensor] = value
updated = []
@@ -1585,9 +1669,10 @@ class Function(object):
if argument in feed_dict:
input_dict[argument] = feed_dict[argument]
else:
raise ValueError('CNTK backend: argument %s is not found in inputs. '
'Please double check the model and inputs in '
'`train_function`.' % argument.name)
raise ValueError(
'CNTK backend: argument %s is not found in inputs. '
'Please double check the model and inputs in '
'`train_function`.' % argument.name)
result = self.trainer.train_minibatch(
input_dict, self.trainer_output)
@@ -1603,9 +1688,10 @@ class Function(object):
if argument in feed_dict:
input_dict[argument] = feed_dict[argument]
else:
raise ValueError('CNTK backend: metrics argument %s '
'is not found in inputs. Please double '
'check the model and inputs.' % argument.name)
raise ValueError(
'CNTK backend: metrics argument %s '
'is not found in inputs. Please double '
'check the model and inputs.' % argument.name)
output_values = self.metrics_func.eval(input_dict, as_numpy=False)
if isinstance(output_values, dict):
for o in self.metrics_outputs:
@@ -1623,9 +1709,10 @@ class Function(object):
if argument in feed_dict:
input_dict[argument] = feed_dict[argument]
else:
raise ValueError('CNTK backend: assign ops argument %s '
'is not found in inputs. Please double '
'check the model and inputs.' % argument.name)
raise ValueError(
'CNTK backend: assign ops argument %s '
'is not found in inputs. Please double '
'check the model and inputs.' % argument.name)
self.unrelated_updates.eval(input_dict, as_numpy=False)
return updated
+122 -30
Ver Arquivo
@@ -451,15 +451,15 @@ def shape(x):
>>> tf_session = K.get_session()
>>> val = np.array([[1, 2], [3, 4]])
>>> kvar = K.variable(value=val)
>>> input = keras.backend.placeholder(shape=(2, 4, 5))
>>> inputs = keras.backend.placeholder(shape=(2, 4, 5))
>>> K.shape(kvar)
<tf.Tensor 'Shape_8:0' shape=(2,) dtype=int32>
>>> K.shape(input)
>>> K.shape(inputs)
<tf.Tensor 'Shape_9:0' shape=(3,) dtype=int32>
# To get integer shape (Instead, you can use K.int_shape(x))
>>> K.shape(kvar).eval(session=tf_session)
array([2, 2], dtype=int32)
>>> K.shape(input).eval(session=tf_session)
>>> K.shape(inputs).eval(session=tf_session)
array([2, 4, 5], dtype=int32)
```
"""
@@ -478,8 +478,8 @@ def int_shape(x):
# Examples
```python
>>> from keras import backend as K
>>> input = K.placeholder(shape=(2, 4, 5))
>>> K.int_shape(input)
>>> inputs = K.placeholder(shape=(2, 4, 5))
>>> K.int_shape(inputs)
(2, 4, 5)
>>> val = np.array([[1, 2], [3, 4]])
>>> kvar = K.variable(value=val)
@@ -508,10 +508,10 @@ def ndim(x):
# Examples
```python
>>> from keras import backend as K
>>> input = K.placeholder(shape=(2, 4, 5))
>>> inputs = K.placeholder(shape=(2, 4, 5))
>>> val = np.array([[1, 2], [3, 4]])
>>> kvar = K.variable(value=val)
>>> K.ndim(input)
>>> K.ndim(inputs)
3
>>> K.ndim(kvar)
2
@@ -550,7 +550,7 @@ def dtype(x):
'float32_ref'
```
"""
return x.dtype.name
return x.dtype.base_dtype.name
def eval(x):
@@ -1089,10 +1089,10 @@ def transpose(x):
```
```python
>>> input = K.placeholder((2, 3))
>>> input
>>> inputs = K.placeholder((2, 3))
>>> inputs
<tf.Tensor 'Placeholder_11:0' shape=(2, 3) dtype=float32>
>>> input_transposed = K.transpose(input)
>>> input_transposed = K.transpose(inputs)
>>> input_transposed
<tf.Tensor 'transpose_4:0' shape=(3, 2) dtype=float32>
@@ -1153,7 +1153,7 @@ def max(x, axis=None, keepdims=False):
A tensor with maximum values of `x`.
"""
axis = _normalize_axis(axis, ndim(x))
return tf.reduce_max(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_max(x, axis=axis, keep_dims=keepdims)
def min(x, axis=None, keepdims=False):
@@ -1171,7 +1171,7 @@ def min(x, axis=None, keepdims=False):
A tensor with miminum values of `x`.
"""
axis = _normalize_axis(axis, ndim(x))
return tf.reduce_min(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_min(x, axis=axis, keep_dims=keepdims)
def sum(x, axis=None, keepdims=False):
@@ -1189,7 +1189,7 @@ def sum(x, axis=None, keepdims=False):
A tensor with sum of `x`.
"""
axis = _normalize_axis(axis, ndim(x))
return tf.reduce_sum(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_sum(x, axis=axis, keep_dims=keepdims)
def prod(x, axis=None, keepdims=False):
@@ -1207,7 +1207,7 @@ def prod(x, axis=None, keepdims=False):
A tensor with the product of elements of `x`.
"""
axis = _normalize_axis(axis, ndim(x))
return tf.reduce_prod(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_prod(x, axis=axis, keep_dims=keepdims)
def cumsum(x, axis=0):
@@ -1255,10 +1255,10 @@ def var(x, axis=None, keepdims=False):
axis = _normalize_axis(axis, ndim(x))
if x.dtype.base_dtype == tf.bool:
x = tf.cast(x, floatx())
m = tf.reduce_mean(x, reduction_indices=axis, keep_dims=True)
m = tf.reduce_mean(x, axis=axis, keep_dims=True)
devs_squared = tf.square(x - m)
return tf.reduce_mean(devs_squared,
reduction_indices=axis,
axis=axis,
keep_dims=keepdims)
@@ -1296,7 +1296,7 @@ def mean(x, axis=None, keepdims=False):
axis = _normalize_axis(axis, ndim(x))
if x.dtype.base_dtype == tf.bool:
x = tf.cast(x, floatx())
return tf.reduce_mean(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_mean(x, axis=axis, keep_dims=keepdims)
def any(x, axis=None, keepdims=False):
@@ -1312,7 +1312,7 @@ def any(x, axis=None, keepdims=False):
"""
axis = _normalize_axis(axis, ndim(x))
x = tf.cast(x, tf.bool)
return tf.reduce_any(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_any(x, axis=axis, keep_dims=keepdims)
def all(x, axis=None, keepdims=False):
@@ -1328,7 +1328,7 @@ def all(x, axis=None, keepdims=False):
"""
axis = _normalize_axis(axis, ndim(x))
x = tf.cast(x, tf.bool)
return tf.reduce_all(x, reduction_indices=axis, keep_dims=keepdims)
return tf.reduce_all(x, axis=axis, keep_dims=keepdims)
def argmax(x, axis=-1):
@@ -2327,12 +2327,12 @@ def rnn(step_function, inputs, initial_states,
# Arguments
step_function: RNN step function.
Parameters:
input: tensor with shape `(samples, ...)` (no time dimension),
inputs: tensor with shape `(samples, ...)` (no time dimension),
representing input for the batch of samples at a certain
time step.
states: list of tensors.
Returns:
output: tensor with shape `(samples, output_dim)`
outputs: tensor with shape `(samples, output_dim)`
(no time dimension).
new_states: list of tensors, same length and shapes
as 'states'. The first state in the list must be the
@@ -2722,14 +2722,14 @@ def softsign(x):
return tf.nn.softsign(x)
def categorical_crossentropy(output, target, from_logits=False):
def categorical_crossentropy(target, output, from_logits=False):
"""Categorical crossentropy between an output tensor and a target tensor.
# Arguments
target: A tensor of the same shape as `output`.
output: A tensor resulting from a softmax
(unless `from_logits` is True, in which
case `output` is expected to be the logits).
target: A tensor of the same shape as `output`.
from_logits: Boolean, whether `output` is the
result of a softmax, or is a tensor of logits.
@@ -2741,26 +2741,26 @@ def categorical_crossentropy(output, target, from_logits=False):
if not from_logits:
# scale preds so that the class probas of each sample sum to 1
output /= tf.reduce_sum(output,
reduction_indices=len(output.get_shape()) - 1,
axis=len(output.get_shape()) - 1,
keep_dims=True)
# manual computation of crossentropy
epsilon = _to_tensor(_EPSILON, output.dtype.base_dtype)
output = tf.clip_by_value(output, epsilon, 1. - epsilon)
return - tf.reduce_sum(target * tf.log(output),
reduction_indices=len(output.get_shape()) - 1)
axis=len(output.get_shape()) - 1)
else:
return tf.nn.softmax_cross_entropy_with_logits(labels=target,
logits=output)
def sparse_categorical_crossentropy(output, target, from_logits=False):
def sparse_categorical_crossentropy(target, output, from_logits=False):
"""Categorical crossentropy with integer targets.
# Arguments
target: An integer tensor.
output: A tensor resulting from a softmax
(unless `from_logits` is True, in which
case `output` is expected to be the logits).
target: An integer tensor.
from_logits: Boolean, whether `output` is the
result of a softmax, or is a tensor of logits.
@@ -2787,12 +2787,12 @@ def sparse_categorical_crossentropy(output, target, from_logits=False):
return res
def binary_crossentropy(output, target, from_logits=False):
def binary_crossentropy(target, output, from_logits=False):
"""Binary crossentropy between an output tensor and a target tensor.
# Arguments
output: A tensor.
target: A tensor with the same shape as `output`.
output: A tensor.
from_logits: Whether `output` is expected to be a logits tensor.
By default, we consider that `output`
encodes a probability distribution.
@@ -2911,6 +2911,26 @@ def in_top_k(predictions, targets, k):
# CONVOLUTIONS
def _preprocess_deconv3d_output_shape(x, shape, data_format):
"""Get the output_shape for the 3D 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[4], shape[1])
if shape[0] is None:
shape = (tf.shape(x)[0], ) + tuple(shape[1:])
shape = tf.stack(list(shape))
return shape
def _preprocess_deconv_output_shape(x, shape, data_format):
"""Get the output_shape for the deconvolution.
@@ -3211,6 +3231,41 @@ def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
return _postprocess_conv2d_output(x, data_format)
def depthwise_conv2d(x, depthwise_kernel, strides=(1, 1), padding='valid',
data_format=None, dilation_rate=(1, 1)):
"""2D convolution with separable filters.
# Arguments
x: input tensor
depthwise_kernel: convolution kernel for the depthwise convolution.
strides: strides tuple (length 2).
padding: string, `"same"` or `"valid"`.
data_format: string, `"channels_last"` or `"channels_first"`.
dilation_rate: tuple of integers,
dilation rates for the separable convolution.
# Returns
Output tensor.
# 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))
x = _preprocess_conv2d_input(x, data_format)
padding = _preprocess_padding(padding)
strides = (1,) + strides + (1,)
x = tf.nn.depthwise_conv2d(x, depthwise_kernel,
strides=strides,
padding=padding,
rate=dilation_rate)
return _postprocess_conv2d_output(x, data_format)
def conv3d(x, kernel, strides=(1, 1, 1), padding='valid',
data_format=None, dilation_rate=(1, 1, 1)):
"""3D convolution.
@@ -3251,6 +3306,43 @@ def conv3d(x, kernel, strides=(1, 1, 1), padding='valid',
return _postprocess_conv3d_output(x, data_format)
def conv3d_transpose(x, kernel, output_shape, strides=(1, 1, 1),
padding='valid', data_format=None):
"""3D deconvolution (i.e. transposed convolution).
# Arguments
x: input tensor.
kernel: kernel tensor.
output_shape: 1D int tensor for the output shape.
strides: strides tuple.
padding: string, "same" or "valid".
data_format: string, `"channels_last"` or `"channels_first"`.
Whether to use Theano or TensorFlow data format
for inputs/kernels/outputs.
# Returns
A tensor, result of transposed 3D convolution.
# 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))
if isinstance(output_shape, (tuple, list)):
output_shape = tf.stack(output_shape)
x = _preprocess_conv3d_input(x, data_format)
output_shape = _preprocess_deconv3d_output_shape(x, output_shape, data_format)
padding = _preprocess_padding(padding)
strides = (1,) + strides + (1,)
x = tf.nn.conv3d_transpose(x, kernel, output_shape, strides,
padding=padding)
return _postprocess_conv3d_output(x, data_format)
def pool2d(x, pool_size, strides=(1, 1),
padding='valid', data_format=None,
pool_mode='max'):
+102 -29
Ver Arquivo
@@ -1,7 +1,6 @@
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
@@ -446,10 +445,14 @@ def transpose(x):
def gather(reference, indices):
"""reference: a tensor.
indices: an int tensor of indices.
"""Retrieves the elements of indices `indices` in the tensor `reference`.
Return: a tensor of same type as reference.
# Arguments
reference: A tensor.
indices: An integer tensor of indices.
# Returns
A tensor of same type as `reference`.
"""
y = reference[indices]
if hasattr(reference, '_keras_shape') and hasattr(indices, '_keras_shape'):
@@ -930,7 +933,7 @@ def tile(x, n):
output_shape += (None,)
else:
output_shape += (i * j,)
elif type(n) is int:
elif isinstance(n, int):
output_shape = x._keras_shape[:-1]
if x._keras_shape[-1] is None:
output_shape += (None,)
@@ -1138,8 +1141,8 @@ def pattern_broadcast(x, broatcastable):
def get_value(x):
if not hasattr(x, 'get_value'):
raise TypeError('get_value() can only be called on a variable. '
'If you have an expression instead, use eval().')
raise TypeError('`get_value` can only be called on a variable. '
'If you have an expression instead, use `eval()`.')
return x.get_value()
@@ -1225,12 +1228,12 @@ def rnn(step_function, inputs, initial_states,
(at least 3D).
step_function:
Parameters:
input: tensor with shape (samples, ...) (no time dimension),
inputs: tensor with shape (samples, ...) (no time dimension),
representing input for the batch of samples at a certain
time step.
states: list of tensors.
Returns:
output: tensor with shape (samples, ...) (no time dimension),
outputs: tensor with shape (samples, ...) (no time dimension),
new_states: list of tensors, same length and shapes
as 'states'.
initial_states: tensor with shape (samples, ...) (no time dimension),
@@ -1311,14 +1314,14 @@ def rnn(step_function, inputs, initial_states,
if len(initial_states) > 0:
initial_states[0] = T.unbroadcast(initial_states[0], 0, 1)
def _step(input, mask, output_tm1, *states):
output, new_states = step_function(input, states)
def _step(inputs, mask, output_tm1, *states):
outputs, new_states = step_function(inputs, states)
# output previous output if masked.
output = T.switch(mask, output, output_tm1)
outputs = T.switch(mask, outputs, output_tm1)
return_states = []
for state, new_state in zip(states, new_states):
return_states.append(T.switch(mask, new_state, state))
return [output] + return_states
return [outputs] + return_states
results, _ = theano.scan(
_step,
@@ -1344,8 +1347,8 @@ def rnn(step_function, inputs, initial_states,
successive_states = []
states = initial_states
for i in indices:
output, states = step_function(inputs[i], states + constants)
successive_outputs.append(output)
outputs, states = step_function(inputs[i], states + constants)
successive_outputs.append(outputs)
successive_states.append(states)
outputs = T.stack(*successive_outputs)
states = []
@@ -1353,9 +1356,9 @@ def rnn(step_function, inputs, initial_states,
states.append(T.stack(*[states_at_step[i] for states_at_step in successive_states]))
else:
def _step(input, *states):
output, new_states = step_function(input, states)
return [output] + new_states
def _step(inputs, *states):
outputs, new_states = step_function(inputs, states)
return [outputs] + new_states
# Theano likes to make shape==1 dimensions in the initial states (outputs_info) broadcastable
if len(initial_states) > 0:
@@ -1386,7 +1389,18 @@ def rnn(step_function, inputs, initial_states,
def switch(condition, then_expression, else_expression):
"""condition: scalar tensor.
"""Switches between two operations depending on a scalar value.
Note that both `then_expression` and `else_expression`
should be symbolic tensors of the *same shape*.
# Arguments
condition: scalar tensor (`int` or `bool`).
then_expression: either a tensor, or a callable that returns a tensor.
else_expression: either a tensor, or a callable that returns a tensor.
# Returns
The selected tensor.
"""
if callable(then_expression):
then_expression = then_expression()
@@ -1487,7 +1501,7 @@ def softsign(x):
return T_softsign(x)
def categorical_crossentropy(output, target, from_logits=False):
def categorical_crossentropy(target, output, from_logits=False):
if from_logits:
output = T.nnet.softmax(output)
else:
@@ -1498,14 +1512,14 @@ def categorical_crossentropy(output, target, from_logits=False):
return T.nnet.categorical_crossentropy(output, target)
def sparse_categorical_crossentropy(output, target, from_logits=False):
def sparse_categorical_crossentropy(target, output, from_logits=False):
target = T.cast(T.flatten(target), 'int32')
target = T.extra_ops.to_one_hot(target, nb_class=output.shape[-1])
target = reshape(target, shape(output))
return categorical_crossentropy(output, target, from_logits)
def binary_crossentropy(output, target, from_logits=False):
def binary_crossentropy(target, output, from_logits=False):
if from_logits:
output = T.nnet.sigmoid(output)
# avoid numerical instability with _EPSILON clipping
@@ -1904,6 +1918,11 @@ def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
raise NotImplementedError
def depthwise_conv2d(x, depthwise_kernel, strides=(1, 1), padding='valid',
data_format=None, dilation_rate=(1, 1)):
raise NotImplementedError
def conv3d(x, kernel, strides=(1, 1, 1),
padding='valid', data_format=None,
dilation_rate=(1, 1, 1)):
@@ -1948,6 +1967,63 @@ def conv3d(x, kernel, strides=(1, 1, 1),
return conv_out
def conv3d_transpose(x, kernel, output_shape, strides=(1, 1, 1),
padding='valid', data_format=None):
"""3D deconvolution (transposed convolution).
# Arguments
kernel: kernel tensor.
output_shape: desired dimensions of output.
strides: strides tuple.
padding: string, "same" or "valid".
data_format: "channels_last" or "channels_first".
Whether to use Theano or TensorFlow data format
in inputs/kernels/outputs.
# Raises
ValueError: if using an even kernel size with padding 'same'.
"""
flip_filters = False
if data_format is None:
data_format = image_data_format()
if data_format not in {'channels_first', 'channels_last'}:
raise ValueError('Unknown data_format ' + data_format)
if data_format == 'channels_last':
output_shape = (output_shape[0],
output_shape[4],
output_shape[1],
output_shape[2],
output_shape[3])
if hasattr(kernel, '_keras_shape'):
kernel_shape = kernel._keras_shape
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 `Conv3DTranspose`, with padding mode `same`, '
'even kernel sizes are only supported with Tensorflow. '
'With Theano, set `kernel_size` to an odd number.')
kernel_shape = _preprocess_conv3d_filter_shape(kernel_shape, data_format)
x = _preprocess_conv3d_input(x, data_format)
kernel = _preprocess_conv3d_kernel(kernel, data_format)
th_padding = _preprocess_padding(padding)
op = T.nnet.abstract_conv.AbstractConv3d_gradInputs(imshp=None,
kshp=kernel_shape,
subsample=strides,
border_mode=th_padding,
filter_flip=not flip_filters)
conv_out = op(kernel, x, output_shape[2:])
conv_out = _postprocess_conv3d_output(conv_out, x, padding,
kernel_shape, strides, data_format)
return conv_out
def pool2d(x, pool_size, strides=(1, 1), padding='valid',
data_format=None, pool_mode='max'):
if data_format is None:
@@ -2278,9 +2354,8 @@ def foldl(fn, elems, initializer=None, name=None):
# We need to change the order of the arguments because theano accepts x as
# first parameter and accumulator as second
fn2 = lambda x, acc: fn(acc, x)
return theano.foldl(fn2, elems, initializer, name=name)[0]
return theano.foldl(lambda x, acc: fn(acc, x),
elems, initializer, name=name)[0]
def foldr(fn, elems, initializer=None, name=None):
@@ -2302,9 +2377,8 @@ def foldr(fn, elems, initializer=None, name=None):
# We need to change the order of the arguments because theano accepts x as
# first parameter and accumulator as second
fn2 = lambda x, acc: fn(acc, x)
return theano.foldr(fn2, elems, initializer, name=name)[0]
return theano.foldr(lambda x, acc: fn(acc, x),
elems, initializer, name=name)[0]
def local_conv1d(inputs, kernel, kernel_size, strides, data_format=None):
@@ -2372,5 +2446,4 @@ def local_conv2d(inputs, kernel, kernel_size, strides, output_shape, data_format
output = reshape(output,
(output_row, output_col, -1, filters))
output = permute_dimensions(output, (2, 0, 1, 3))
return output
+22 -18
Ver Arquivo
@@ -523,8 +523,6 @@ class RemoteMonitor(Callback):
path: String; path relative to `root` to which the events will be sent.
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'}`
"""
def __init__(self,
@@ -533,9 +531,7 @@ class RemoteMonitor(Callback):
field='data',
headers=None):
super(RemoteMonitor, self).__init__()
if headers is None:
headers = {'Accept': 'application/json',
'Content-Type': 'application/json'}
self.root = root
self.path = path
self.field = field
@@ -657,11 +653,12 @@ class TensorBoard(Callback):
for layer in self.model.layers:
for weight in layer.weights:
tf.summary.histogram(weight.name, weight)
mapped_weight_name = weight.name.replace(':', '_')
tf.summary.histogram(mapped_weight_name, weight)
if self.write_grads:
grads = model.optimizer.get_gradients(model.total_loss,
weight)
tf.summary.histogram('{}_grad'.format(weight.name), grads)
tf.summary.histogram('{}_grad'.format(mapped_weight_name), grads)
if self.write_images:
w_img = tf.squeeze(weight)
shape = K.int_shape(w_img)
@@ -694,7 +691,7 @@ class TensorBoard(Callback):
shape = K.int_shape(w_img)
assert len(shape) == 4 and shape[-1] in [1, 3, 4]
tf.summary.image(weight.name, w_img)
tf.summary.image(mapped_weight_name, w_img)
if hasattr(layer, 'output'):
tf.summary.histogram('{}_out'.format(layer.name),
@@ -876,8 +873,12 @@ class ReduceLROnPlateau(Callback):
logs['lr'] = K.get_value(self.model.optimizer.lr)
current = logs.get(self.monitor)
if current is None:
warnings.warn('Learning Rate Plateau Reducing requires %s available!' %
self.monitor, RuntimeWarning)
warnings.warn(
'Reduce LR on plateau conditioned on metric `%s` '
'which is not available. Available metrics are: %s' %
(self.monitor, ','.join(list(logs.keys()))), RuntimeWarning
)
else:
if self.in_cooldown():
self.cooldown_counter -= 1
@@ -975,7 +976,7 @@ class CSVLogger(Callback):
class LambdaCallback(Callback):
"""Callback for creating simple, custom callbacks on-the-fly.
r"""Callback for creating simple, custom callbacks on-the-fly.
This callback is constructed with anonymous functions that will be called
at the appropriate time. Note that the callbacks expects positional
@@ -1002,12 +1003,15 @@ class LambdaCallback(Callback):
batch_print_callback = LambdaCallback(
on_batch_begin=lambda batch,logs: print(batch))
# Plot the loss after every epoch.
import numpy as np
import matplotlib.pyplot as plt
plot_loss_callback = LambdaCallback(
on_epoch_end=lambda epoch, logs: plt.plot(np.arange(epoch),
logs['loss']))
# Stream the epoch loss to a file in JSON format. The file content
# is not well-formed JSON but rather has a JSON object per line.
import json
json_log = open('loss_log.json', mode='wt', buffering=1)
json_logging_callback = LambdaCallback(
on_epoch_end=lambda epoch, logs: json_log.write(
json.dumps({'epoch': epoch, 'loss': logs['loss']}) + '\n'),
on_train_end=lambda logs: json_log.close()
)
# Terminate some processes after having finished model training.
processes = ...
@@ -1017,7 +1021,7 @@ class LambdaCallback(Callback):
model.fit(...,
callbacks=[batch_print_callback,
plot_loss_callback,
json_logging_callback,
cleanup_callback])
```
"""
+3 -3
Ver Arquivo
@@ -27,7 +27,7 @@ class MaxNorm(Constraint):
has shape `(input_dim, output_dim)`,
set `axis` to `0` to constrain each weight vector
of length `(input_dim,)`.
In a `Convolution2D` layer with `data_format="channels_last"`,
In a `Conv2D` layer with `data_format="channels_last"`,
the weight tensor has shape
`(rows, cols, input_depth, output_depth)`,
set `axis` to `[0, 1, 2]`
@@ -71,7 +71,7 @@ class UnitNorm(Constraint):
has shape `(input_dim, output_dim)`,
set `axis` to `0` to constrain each weight vector
of length `(input_dim,)`.
In a `Convolution2D` layer with `data_format="channels_last"`,
In a `Conv2D` layer with `data_format="channels_last"`,
the weight tensor has shape
`(rows, cols, input_depth, output_depth)`,
set `axis` to `[0, 1, 2]`
@@ -112,7 +112,7 @@ class MinMaxNorm(Constraint):
has shape `(input_dim, output_dim)`,
set `axis` to `0` to constrain each weight vector
of length `(input_dim,)`.
In a `Convolution2D` layer with `dim_ordering="tf"`,
In a `Conv2D` layer with `data_format="channels_last"`,
the weight tensor has shape
`(rows, cols, input_depth, output_depth)`,
set `axis` to `[0, 1, 2]`
+1 -1
Ver Arquivo
@@ -19,7 +19,7 @@ def load_data(label_mode='fine'):
ValueError: in case of invalid `label_mode`.
"""
if label_mode not in ['fine', 'coarse']:
raise ValueError('label_mode must be one of "fine" "coarse".')
raise ValueError('`label_mode` must be one of `"fine"`, `"coarse"`.')
dirname = 'cifar-100-python'
origin = 'http://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz'
+1 -1
Ver Arquivo
@@ -17,7 +17,7 @@ def load_data(path='imdb.npz', num_words=None, skip_top=0,
num_words: max number of words to include. Words are ranked
by how often they occur (in the training set) and only
the most frequent words are kept
skip_top: skip the top N most frequently occuring words
skip_top: skip the top N most frequently occurring words
(which may not be informative).
maxlen: truncate sequences after this length.
seed: random seed for sample shuffling.
+1 -1
Ver Arquivo
@@ -18,7 +18,7 @@ def load_data(path='reuters.npz', num_words=None, skip_top=0,
num_words: max number of words to include. Words are ranked
by how often they occur (in the training set) and only
the most frequent words are kept
skip_top: skip the top N most frequently occuring words
skip_top: skip the top N most frequently occurring words
(which may not be informative).
maxlen: truncate sequences after this length.
test_split: Fraction of the dataset to be used as test data.
+46 -6
Ver Arquivo
@@ -744,7 +744,7 @@ class Layer(object):
str(mask))
# masking not explicitly supported: return None as mask
return None
# if masking is explictly supported, by default
# if masking is explicitly supported, by default
# carry over the input mask
return mask
@@ -1529,7 +1529,7 @@ class Container(Layer):
# every time the Container is called on a set on input tensors,
# we compute the output tensors,
# output masks and output shapes in one pass,
# then cache them here. When of of these output is queried later,
# then cache them here. When one of these output is queried later,
# we retrieve it from there instead of recomputing it.
self._output_mask_cache = {}
self._output_tensor_cache = {}
@@ -2637,10 +2637,25 @@ class Container(Layer):
"""
return yaml.dump(self._updated_config(), **kwargs)
def summary(self, line_length=None, positions=None):
print_layer_summary(self,
line_length=line_length,
positions=positions)
def summary(self, line_length=None, positions=None, print_fn=print):
"""Prints a string summary of the network.
# Arguments
line_length: Total length of printed lines
(e.g. set this to adapt the display to different
terminal window sizes).
positions: Relative or absolute positions of log elements
in each line. If not provided,
defaults to `[.33, .55, .67, 1.]`.
print_fn: Print function to use.
It will be called on each line of the summary.
You can set it to a custom function
in order to capture the string summary.
"""
return print_layer_summary(self,
line_length=line_length,
positions=positions,
print_fn=print_fn)
def get_source_inputs(tensor, layer=None, node_index=None):
@@ -2923,6 +2938,31 @@ def preprocess_weights_for_loading(layer, weights,
(2, 3, 1, 0))
weights = [kernel, recurrent_kernel, bias]
if layer.__class__.__name__ in ['Model', 'Sequential']:
new_weights = []
# trainable weights
for sublayer in layer.layers:
num_weights = len(sublayer.trainable_weights)
if num_weights > 0:
new_weights.extend(preprocess_weights_for_loading(
layer=sublayer,
weights=weights[:num_weights],
original_keras_version=original_keras_version,
original_backend=original_backend))
weights = weights[num_weights:]
# non-trainable weights
for sublayer in layer.layers:
num_weights = len([l for l in sublayer.weights if l not in sublayer.trainable_weights])
if num_weights > 0:
new_weights.extend(preprocess_weights_for_loading(
layer=sublayer,
weights=weights[:num_weights],
original_keras_version=original_keras_version,
original_backend=original_backend))
weights = weights[num_weights:]
weights = new_weights
conv_layers = ['Conv1D',
'Conv2D',
'Conv3D',
+127 -177
Ver Arquivo
@@ -4,12 +4,13 @@ from __future__ import absolute_import
import warnings
import copy
import time
import numpy as np
import multiprocessing
import threading
import six
from keras.utils import Sequence
from keras.utils import GeneratorEnqueuer
from keras.utils import OrderedEnqueuer
try:
import queue
except ImportError:
@@ -199,7 +200,7 @@ def _standardize_sample_weights(sample_weight, output_names):
'sample_weight')
def _check_array_lengths(inputs, targets, weights):
def _check_array_lengths(inputs, targets, weights=None):
"""Does user input validation for numpy arrays.
# Arguments
@@ -210,29 +211,34 @@ def _check_array_lengths(inputs, targets, weights):
# Raises
ValueError: in case of incorrectly formatted data.
"""
x_lengths = [x.shape[0] for x in inputs]
y_lengths = [y.shape[0] for y in targets]
w_lengths = [w.shape[0] for w in weights]
set_x = set(x_lengths)
def set_of_lengths(x):
# return a set with the variation between
# different shapes, with None => 0
if x is None:
return {0}
else:
return set([0 if y is None else y.shape[0] for y in x])
set_x = set_of_lengths(inputs)
set_y = set_of_lengths(targets)
set_w = set_of_lengths(weights)
if len(set_x) > 1:
raise ValueError('All input arrays (x) should have '
'the same number of samples. Got array shapes: ' +
str([x.shape for x in inputs]))
set_y = set(y_lengths)
if len(set_y) > 1:
raise ValueError('All target arrays (y) should have '
'the same number of samples. Got array shapes: ' +
str([y.shape for y in targets]))
set_w = set(w_lengths)
if len(set_w) > 1:
raise ValueError('All sample_weight arrays should have '
'the same number of samples. Got array shapes: ' +
str([w.shape for w in weights]))
if set_x and set_y and list(set_x)[0] != list(set_y)[0]:
raise ValueError('Input arrays should have '
'the same number of samples as target arrays. '
'Found ' + str(list(set_x)[0]) + ' input samples '
'and ' + str(list(set_y)[0]) + ' target samples.')
if len(set_w) > 1:
raise ValueError('All sample_weight arrays should have '
'the same number of samples. Got array shapes: ' +
str([w.shape for w in weights]))
if set_y and set_w and list(set_y)[0] != list(set_w)[0]:
raise ValueError('Sample_weight arrays should have '
'the same number of samples as target arrays. Got ' +
@@ -386,21 +392,25 @@ def _slice_arrays(arrays, start=None, stop=None):
# Returns
A slice of the array(s).
"""
if isinstance(arrays, list):
if arrays is None:
return [None]
elif isinstance(arrays, list):
if hasattr(start, '__len__'):
# hdf5 datasets only support list objects as indices
if hasattr(start, 'shape'):
start = start.tolist()
return [x[start] for x in arrays]
return [None if x is None else x[start] for x in arrays]
else:
return [x[start:stop] for x in arrays]
return [None if x is None else x[start:stop] for x in arrays]
else:
if hasattr(start, '__len__'):
if hasattr(start, 'shape'):
start = start.tolist()
return arrays[start]
else:
elif hasattr(start, '__getitem__'):
return arrays[start:stop]
else:
return [None]
def _weighted_masked_objective(fn):
@@ -443,13 +453,12 @@ def _weighted_masked_objective(fn):
# to the number of unmasked samples.
score_array /= K.mean(mask)
# reduce score_array to same ndim as weight array
ndim = K.ndim(score_array)
weight_ndim = K.ndim(weights)
score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim)))
# apply sample weighting
if weights is not None:
# reduce score_array to same ndim as weight array
ndim = K.ndim(score_array)
weight_ndim = K.ndim(weights)
score_array = K.mean(score_array, axis=list(range(weight_ndim, ndim)))
score_array *= weights
score_array /= K.mean(K.cast(K.not_equal(weights, 0), K.floatx()))
return K.mean(score_array)
@@ -562,7 +571,7 @@ def _standardize_weights(y, sample_weight=None, class_weight=None,
return sample_weight
elif isinstance(class_weight, dict):
if len(y.shape) > 2:
raise ValueError('class_weight not supported for '
raise ValueError('`class_weight` not supported for '
'3+ dimensional targets.')
if y.shape[1] > 1:
y_classes = y.argmax(axis=1)
@@ -579,101 +588,6 @@ def _standardize_weights(y, sample_weight=None, class_weight=None,
return np.ones((y.shape[0], y.shape[1]), dtype=K.floatx())
class GeneratorEnqueuer(object):
"""Builds a queue out of a data generator.
Used in `fit_generator`, `evaluate_generator`, `predict_generator`.
# Arguments
generator: a generator function which endlessly yields data
pickle_safe: use multiprocessing if True, otherwise threading
"""
def __init__(self, generator, pickle_safe=False):
self._generator = generator
self._pickle_safe = pickle_safe
self._threads = []
self._stop_event = None
self.queue = None
def start(self, workers=1, max_q_size=10, wait_time=0.05):
"""Kicks off threads which add data from the generator into the queue.
# Arguments
workers: number of worker threads
max_q_size: queue size (when full, threads could block on put())
wait_time: time to sleep in-between calls to put()
"""
def data_generator_task():
while not self._stop_event.is_set():
try:
if self._pickle_safe or self.queue.qsize() < max_q_size:
generator_output = next(self._generator)
self.queue.put(generator_output)
else:
time.sleep(wait_time)
except Exception:
self._stop_event.set()
raise
try:
if self._pickle_safe:
self.queue = multiprocessing.Queue(maxsize=max_q_size)
self._stop_event = multiprocessing.Event()
if hasattr(data_generator_task, 'lock'):
# We should replace the threading lock of the iterator
# with a process-safe lock.
data_generator_task.lock = multiprocessing.Lock()
else:
self.queue = queue.Queue()
self._stop_event = threading.Event()
for _ in range(workers):
if self._pickle_safe:
# Reset random seed else all children processes
# share the same seed
np.random.seed()
thread = multiprocessing.Process(target=data_generator_task)
thread.daemon = True
else:
thread = threading.Thread(target=data_generator_task)
self._threads.append(thread)
thread.start()
except:
self.stop()
raise
def is_running(self):
return self._stop_event is not None and not self._stop_event.is_set()
def stop(self, timeout=None):
"""Stop running threads and wait for them to exit, if necessary.
Should be called by the same thread which called start().
# Arguments
timeout: maximum time to wait on thread.join()
"""
if self.is_running():
self._stop_event.set()
for thread in self._threads:
if thread.is_alive():
if self._pickle_safe:
thread.terminate()
else:
thread.join(timeout)
if self._pickle_safe:
if self.queue is not None:
self.queue.close()
self._threads = []
self._stop_event = None
self.queue = None
class Model(Container):
"""The `Model` class adds training & evaluation routines to a `Container`.
"""
@@ -994,14 +908,8 @@ class Model(Container):
self.test_function = None
self.predict_function = None
# Collected trainable weights and sort them deterministically.
# Collected trainable weights, sorted in topological order.
trainable_weights = self.trainable_weights
# Sort weights by name.
if trainable_weights:
if K.backend() == 'theano':
trainable_weights.sort(key=lambda x: x.name if x.name else x.auto_name)
else:
trainable_weights.sort(key=lambda x: x.name)
self._collected_trainable_weights = trainable_weights
def _make_train_function(self):
@@ -1720,9 +1628,9 @@ class Model(Container):
validation_data=None,
validation_steps=None,
class_weight=None,
max_q_size=10,
max_queue_size=10,
workers=1,
pickle_safe=False,
use_multiprocessing=False,
initial_epoch=0):
"""Fits the model on data yielded batch-by-batch by a Python generator.
@@ -1730,8 +1638,14 @@ class Model(Container):
For instance, this allows you to do real-time data augmentation
on images on CPU in parallel to training your model on GPU.
The use of `keras.utils.Sequence` guarantees the ordering
and guarantees the single use of every input per epoch when
using `use_multiprocessing=True`.
# Arguments
generator: a generator.
generator: a generator or an instance of Sequence (keras.utils.Sequence)
object in order to avoid duplicate data
when using multiprocessing.
The output of the generator must be either
- a tuple (inputs, targets)
- a tuple (inputs, targets, sample_weights).
@@ -1756,10 +1670,10 @@ class Model(Container):
to yield from `generator` before stopping.
class_weight: dictionary mapping class indices to a weight
for the class.
max_q_size: maximum size for the generator queue
max_queue_size: maximum size for the generator queue
workers: maximum number of processes to spin up
when using process based threading
pickle_safe: if True, use process based threading.
use_multiprocessing: if True, use process based threading.
Note that because
this implementation relies on multiprocessing,
you should not pass
@@ -1804,7 +1718,8 @@ class Model(Container):
# python 2 has 'next', 3 has '__next__'
# avoid any explicit version checks
val_gen = (hasattr(validation_data, 'next') or
hasattr(validation_data, '__next__'))
hasattr(validation_data, '__next__') or
isinstance(validation_data, Sequence))
if val_gen and not validation_steps:
raise ValueError('When using a generator for validation data, '
'you must specify a value for '
@@ -1843,7 +1758,7 @@ class Model(Container):
elif len(validation_data) == 3:
val_x, val_y, val_sample_weight = validation_data
else:
raise ValueError('validation_data should be a tuple '
raise ValueError('`validation_data` should be a tuple '
'`(val_x, val_y, val_sample_weight)` '
'or `(val_x, val_y)`. Found: ' +
str(validation_data))
@@ -1854,11 +1769,25 @@ class Model(Container):
val_data += [0.]
for cbk in callbacks:
cbk.validation_data = val_data
is_sequence = isinstance(generator, Sequence)
if not is_sequence and use_multiprocessing and workers > 1:
warnings.warn(
UserWarning('Using a generator with `use_multiprocessing=True`'
' and multiple workers may duplicate your data.'
' Please consider using the`keras.utils.Sequence'
' class.'))
enqueuer = None
try:
enqueuer = GeneratorEnqueuer(generator, pickle_safe=pickle_safe)
enqueuer.start(max_q_size=max_q_size, workers=workers)
if is_sequence:
enqueuer = OrderedEnqueuer(generator,
use_multiprocessing=use_multiprocessing)
else:
enqueuer = GeneratorEnqueuer(generator,
use_multiprocessing=use_multiprocessing,
wait_time=wait_time)
enqueuer.start(workers=workers, max_queue_size=max_queue_size)
output_generator = enqueuer.get()
callback_model.stop_training = False
while epoch < epochs:
@@ -1866,16 +1795,10 @@ class Model(Container):
steps_done = 0
batch_index = 0
while steps_done < steps_per_epoch:
generator_output = None
while enqueuer.is_running():
if not enqueuer.queue.empty():
generator_output = enqueuer.queue.get()
break
else:
time.sleep(wait_time)
generator_output = next(output_generator)
if not hasattr(generator_output, '__len__'):
raise ValueError('output of generator should be '
raise ValueError('Output of generator should be '
'a tuple `(x, y, sample_weight)` '
'or `(x, y)`. Found: ' +
str(generator_output))
@@ -1885,7 +1808,7 @@ class Model(Container):
elif len(generator_output) == 3:
x, y, sample_weight = generator_output
else:
raise ValueError('output of generator should be '
raise ValueError('Output of generator should be '
'a tuple `(x, y, sample_weight)` '
'or `(x, y)`. Found: ' +
str(generator_output))
@@ -1923,9 +1846,9 @@ class Model(Container):
val_outs = self.evaluate_generator(
validation_data,
validation_steps,
max_q_size=max_q_size,
max_queue_size=max_queue_size,
workers=workers,
pickle_safe=pickle_safe)
use_multiprocessing=use_multiprocessing)
else:
# No need for try/except because
# data has already been validated.
@@ -1954,7 +1877,9 @@ class Model(Container):
@interfaces.legacy_generator_methods_support
def evaluate_generator(self, generator, steps,
max_q_size=10, workers=1, pickle_safe=False):
max_queue_size=10,
workers=1,
use_multiprocessing=False):
"""Evaluates the model on a data generator.
The generator should return the same kind of data
@@ -1963,12 +1888,15 @@ class Model(Container):
# Arguments
generator: Generator yielding tuples (inputs, targets)
or (inputs, targets, sample_weights)
or an instance of Sequence (keras.utils.Sequence)
object in order to avoid duplicate data
when using multiprocessing.
steps: Total number of steps (batches of samples)
to yield from `generator` before stopping.
max_q_size: maximum size for the generator queue
max_queue_size: maximum size for the generator queue
workers: maximum number of processes to spin up
when using process based threading
pickle_safe: if True, use process based threading.
use_multiprocessing: if True, use process based threading.
Note that because
this implementation relies on multiprocessing,
you should not pass
@@ -1992,23 +1920,30 @@ class Model(Container):
wait_time = 0.01
all_outs = []
batch_sizes = []
is_sequence = isinstance(generator, Sequence)
if not is_sequence and use_multiprocessing and workers > 1:
warnings.warn(
UserWarning('Using a generator with `use_multiprocessing=True`'
' and multiple workers may duplicate your data.'
' Please consider using the`keras.utils.Sequence'
' class.'))
enqueuer = None
try:
enqueuer = GeneratorEnqueuer(generator, pickle_safe=pickle_safe)
enqueuer.start(workers=workers, max_q_size=max_q_size)
if is_sequence:
enqueuer = OrderedEnqueuer(generator,
use_multiprocessing=use_multiprocessing)
else:
enqueuer = GeneratorEnqueuer(generator,
use_multiprocessing=use_multiprocessing,
wait_time=wait_time)
enqueuer.start(workers=workers, max_queue_size=max_queue_size)
output_generator = enqueuer.get()
while steps_done < steps:
generator_output = None
while enqueuer.is_running():
if not enqueuer.queue.empty():
generator_output = enqueuer.queue.get()
break
else:
time.sleep(wait_time)
generator_output = next(output_generator)
if not hasattr(generator_output, '__len__'):
raise ValueError('output of generator should be a tuple '
raise ValueError('Output of generator should be a tuple '
'(x, y, sample_weight) '
'or (x, y). Found: ' +
str(generator_output))
@@ -2018,7 +1953,7 @@ class Model(Container):
elif len(generator_output) == 3:
x, y, sample_weight = generator_output
else:
raise ValueError('output of generator should be a tuple '
raise ValueError('Output of generator should be a tuple '
'(x, y, sample_weight) '
'or (x, y). Found: ' +
str(generator_output))
@@ -2030,6 +1965,9 @@ class Model(Container):
batch_size = len(list(x.values())[0])
else:
batch_size = len(x)
if batch_size == 0:
raise ValueError('Received an empty batch. '
'Batches should at least contain one item.')
all_outs.append(outs)
steps_done += 1
@@ -2051,21 +1989,26 @@ class Model(Container):
@interfaces.legacy_generator_methods_support
def predict_generator(self, generator, steps,
max_q_size=10, workers=1,
pickle_safe=False, verbose=0):
max_queue_size=10,
workers=1,
use_multiprocessing=False,
verbose=0):
"""Generates predictions for the input samples from a data generator.
The generator should return the same kind of data as accepted by
`predict_on_batch`.
# Arguments
generator: Generator yielding batches of input samples.
generator: Generator yielding batches of input samples
or an instance of Sequence (keras.utils.Sequence)
object in order to avoid duplicate data
when using multiprocessing.
steps: Total number of steps (batches of samples)
to yield from `generator` before stopping.
max_q_size: Maximum size for the generator queue.
max_queue_size: Maximum size for the generator queue.
workers: Maximum number of processes to spin up
when using process based threading
pickle_safe: If `True`, use process based threading.
use_multiprocessing: If `True`, use process based threading.
Note that because
this implementation relies on multiprocessing,
you should not pass
@@ -2086,24 +2029,31 @@ class Model(Container):
steps_done = 0
wait_time = 0.01
all_outs = []
is_sequence = isinstance(generator, Sequence)
if not is_sequence and use_multiprocessing and workers > 1:
warnings.warn(
UserWarning('Using a generator with `use_multiprocessing=True`'
' and multiple workers may duplicate your data.'
' Please consider using the`keras.utils.Sequence'
' class.'))
enqueuer = None
try:
enqueuer = GeneratorEnqueuer(generator, pickle_safe=pickle_safe)
enqueuer.start(workers=workers, max_q_size=max_q_size)
if is_sequence:
enqueuer = OrderedEnqueuer(generator,
use_multiprocessing=use_multiprocessing)
else:
enqueuer = GeneratorEnqueuer(generator,
use_multiprocessing=use_multiprocessing,
wait_time=wait_time)
enqueuer.start(workers=workers, max_queue_size=max_queue_size)
output_generator = enqueuer.get()
if verbose == 1:
progbar = Progbar(target=steps)
while steps_done < steps:
generator_output = None
while enqueuer.is_running():
if not enqueuer.queue.empty():
generator_output = enqueuer.queue.get()
break
else:
time.sleep(wait_time)
generator_output = next(output_generator)
if isinstance(generator_output, tuple):
# Compatibility with the generators
# used for training.
@@ -2112,7 +2062,7 @@ class Model(Container):
elif len(generator_output) == 3:
x, _, _ = generator_output
else:
raise ValueError('output of generator should be '
raise ValueError('Output of generator should be '
'a tuple `(x, y, sample_weight)` '
'or `(x, y)`. Found: ' +
str(generator_output))
+234 -2
Ver Arquivo
@@ -476,7 +476,7 @@ class Conv3D(_Conv):
When using this layer as the first layer in a model,
provide the keyword argument `input_shape`
(tuple of integers, does not include the sample axis),
e.g. `input_shape=(128, 128, 128, 3)` for 128x128x128 volumes
e.g. `input_shape=(128, 128, 128, 1)` for 128x128x128 volumes
with a single channel,
in `data_format="channels_last"`.
@@ -484,7 +484,7 @@ class Conv3D(_Conv):
filters: Integer, the dimensionality of the output space
(i.e. the number output of filters in the convolution).
kernel_size: An integer or tuple/list of 3 integers, specifying the
width and height of the 3D convolution window.
depth, height and width of the 3D convolution window.
Can be a single integer to specify the same value for
all spatial dimensions.
strides: An integer or tuple/list of 3 integers,
@@ -806,6 +806,237 @@ class Conv2DTranspose(Conv2D):
return config
class Conv3DTranspose(Conv3D):
"""Transposed convolution layer (sometimes called Deconvolution).
The need for transposed convolutions generally arises
from the desire to use a transformation going in the opposite direction
of a normal convolution, i.e., from something that has the shape of the
output of some convolution to something that has the shape of its input
while maintaining a connectivity pattern that is compatible with
said convolution.
When using this layer as the first layer in a model,
provide the keyword argument `input_shape`
(tuple of integers, does not include the sample axis),
e.g. `input_shape=(128, 128, 128, 3)` for a 128x128x128 volume with 3 channels
if `data_format="channels_last"`.
# Arguments
filters: Integer, the dimensionality of the output space
(i.e. the number of output filters in the convolution).
kernel_size: An integer or tuple/list of 3 integers, specifying the
width and height of the 3D convolution window.
Can be a single integer to specify the same value for
all spatial dimensions.
strides: An integer or tuple/list of 3 integers,
specifying the strides of the convolution along the width and height.
Can be a single integer to specify the same value for
all spatial dimensions.
Specifying any stride value != 1 is incompatible with specifying
any `dilation_rate` value != 1.
padding: one of `"valid"` or `"same"` (case-insensitive).
data_format: A string,
one of `channels_last` (default) or `channels_first`.
The ordering of the dimensions in the inputs.
`channels_last` corresponds to inputs with shape
`(batch, depth, height, width, channels)` while `channels_first`
corresponds to inputs with shape
`(batch, channels, depth, height, width)`.
It defaults to the `image_data_format` value found in your
Keras config file at `~/.keras/keras.json`.
If you never set it, then it will be "channels_last".
dilation_rate: an integer or tuple/list of 3 integers, specifying
the dilation rate to use for dilated convolution.
Can be a single integer to specify the same value for
all spatial dimensions.
Currently, specifying any `dilation_rate` value != 1 is
incompatible with specifying any stride value != 1.
activation: Activation function to use
(see [activations](../activations.md)).
If you don't specify anything, no activation is applied
(ie. "linear" activation: `a(x) = x`).
use_bias: Boolean, whether the layer uses a bias vector.
kernel_initializer: Initializer for the `kernel` weights matrix
(see [initializers](../initializers.md)).
bias_initializer: Initializer for the bias vector
(see [initializers](../initializers.md)).
kernel_regularizer: Regularizer function applied to
the `kernel` weights matrix
(see [regularizer](../regularizers.md)).
bias_regularizer: Regularizer function applied to the bias vector
(see [regularizer](../regularizers.md)).
activity_regularizer: Regularizer function applied to
the output of the layer (its "activation").
(see [regularizer](../regularizers.md)).
kernel_constraint: Constraint function applied to the kernel matrix
(see [constraints](../constraints.md)).
bias_constraint: Constraint function applied to the bias vector
(see [constraints](../constraints.md)).
# Input shape
5D tensor with shape:
`(batch, channels, depth, rows, cols)` if data_format='channels_first'
or 5D tensor with shape:
`(batch, depth, rows, cols, channels)` if data_format='channels_last'.
# Output shape
5D tensor with shape:
`(batch, filters, new_depth, new_rows, new_cols)` if data_format='channels_first'
or 5D tensor with shape:
`(batch, new_depth, new_rows, new_cols, filters)` if data_format='channels_last'.
`depth` and `rows` and `cols` values might have changed due to padding.
# References
- [A guide to convolution arithmetic for deep learning](https://arxiv.org/abs/1603.07285v1)
- [Deconvolutional Networks](http://www.matthewzeiler.com/pubs/cvpr2010/cvpr2010.pdf)
"""
def __init__(self, filters,
kernel_size,
strides=(1, 1, 1),
padding='valid',
data_format=None,
activation=None,
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='zeros',
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs):
super(Conv3DTranspose, self).__init__(
filters,
kernel_size,
strides=strides,
padding=padding,
data_format=data_format,
activation=activation,
use_bias=use_bias,
kernel_initializer=kernel_initializer,
bias_initializer=bias_initializer,
kernel_regularizer=kernel_regularizer,
bias_regularizer=bias_regularizer,
activity_regularizer=activity_regularizer,
kernel_constraint=kernel_constraint,
bias_constraint=bias_constraint,
**kwargs)
self.input_spec = InputSpec(ndim=5)
def build(self, input_shape):
if len(input_shape) != 5:
raise ValueError('Inputs should have rank ' +
str(5) +
'; Received input shape:', str(input_shape))
if self.data_format == 'channels_first':
channel_axis = 1
else:
channel_axis = -1
if input_shape[channel_axis] is None:
raise ValueError('The channel dimension of the inputs '
'should be defined. Found `None`.')
input_dim = input_shape[channel_axis]
kernel_shape = self.kernel_size + (self.filters, input_dim)
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(shape=(self.filters,),
initializer=self.bias_initializer,
name='bias',
regularizer=self.bias_regularizer,
constraint=self.bias_constraint)
else:
self.bias = None
# Set input spec.
self.input_spec = InputSpec(ndim=5, axes={channel_axis: input_dim})
self.built = True
def call(self, inputs):
input_shape = K.shape(inputs)
batch_size = input_shape[0]
if self.data_format == 'channels_first':
d_axis, h_axis, w_axis = 2, 3, 4
else:
d_axis, h_axis, w_axis = 1, 2, 3
depth = input_shape[d_axis]
height = input_shape[h_axis]
width = input_shape[w_axis]
kernel_d, kernel_h, kernel_w = self.kernel_size
stride_d, stride_h, stride_w = self.strides
# Infer the dynamic output shape:
out_depth = conv_utils.deconv_length(depth,
stride_d, kernel_d,
self.padding)
out_height = conv_utils.deconv_length(height,
stride_h, kernel_h,
self.padding)
out_width = conv_utils.deconv_length(width,
stride_w, kernel_w,
self.padding)
if self.data_format == 'channels_first':
output_shape = (batch_size, self.filters, out_depth, out_height, out_width)
else:
output_shape = (batch_size, out_depth, out_height, out_width, self.filters)
outputs = K.conv3d_transpose(inputs,
self.kernel,
output_shape,
self.strides,
padding=self.padding,
data_format=self.data_format)
if self.bias:
outputs = K.bias_add(
outputs,
self.bias,
data_format=self.data_format)
if self.activation is not None:
return self.activation(outputs)
return outputs
def compute_output_shape(self, input_shape):
output_shape = list(input_shape)
if self.data_format == 'channels_first':
c_axis, d_axis, h_axis, w_axis = 1, 2, 3, 4
else:
c_axis, d_axis, h_axis, w_axis = 4, 1, 2, 3
kernel_d, kernel_h, kernel_w = self.kernel_size
stride_d, stride_h, stride_w = self.strides
output_shape[c_axis] = self.filters
output_shape[d_axis] = conv_utils.deconv_length(output_shape[d_axis],
stride_d,
kernel_d,
self.padding)
output_shape[h_axis] = conv_utils.deconv_length(output_shape[h_axis],
stride_h,
kernel_h,
self.padding)
output_shape[w_axis] = conv_utils.deconv_length(output_shape[w_axis],
stride_w,
kernel_w,
self.padding)
return tuple(output_shape)
def get_config(self):
config = super(Conv3DTranspose, self).get_config()
config.pop('dilation_rate')
return config
class SeparableConv2D(Conv2D):
"""Depthwise separable 2D convolution.
@@ -1891,6 +2122,7 @@ Convolution3D = Conv3D
SeparableConvolution2D = SeparableConv2D
Convolution2DTranspose = Conv2DTranspose
Deconvolution2D = Deconv2D = Conv2DTranspose
Deconvolution3D = Deconv3D = Conv3DTranspose
# Legacy aliases
AtrousConv1D = AtrousConvolution1D
+6 -6
Ver Arquivo
@@ -193,8 +193,8 @@ class SpatialDropout2D(Dropout):
if data_format is None:
data_format = K.image_data_format()
if data_format not in {'channels_last', 'channels_first'}:
raise ValueError('data_format must be in '
'{"channels_last", "channels_first"}')
raise ValueError('`data_format` must be in '
'{`"channels_last"`, `"channels_first"`}')
self.data_format = data_format
self.input_spec = InputSpec(ndim=4)
@@ -246,8 +246,8 @@ class SpatialDropout3D(Dropout):
if data_format is None:
data_format = K.image_data_format()
if data_format not in {'channels_last', 'channels_first'}:
raise ValueError('data_format must be in '
'{"channels_last", "channels_first"}')
raise ValueError('`data_format` must be in '
'{`"channels_last"`, `"channels_first"`}')
self.data_format = data_format
self.input_spec = InputSpec(ndim=5)
@@ -456,7 +456,7 @@ class Flatten(Layer):
```python
model = Sequential()
model.add(Convolution2D(64, 3, 3,
model.add(Conv2D(64, 3, 3,
border_mode='same',
input_shape=(3, 32, 32)))
# now: model.output_shape == (None, 64, 32, 32)
@@ -637,7 +637,7 @@ class Lambda(Layer):
else:
shape = self._output_shape(input_shape)
if not isinstance(shape, (list, tuple)):
raise ValueError('output_shape function must return a tuple')
raise ValueError('`output_shape` function must return a tuple.')
return tuple(shape)
def call(self, inputs, mask=None):
+2 -2
Ver Arquivo
@@ -75,7 +75,6 @@ class Embedding(Layer):
mask_zero=False,
input_length=None,
**kwargs):
kwargs['dtype'] = 'int32'
if 'input_shape' not in kwargs:
if input_length:
kwargs['input_shape'] = (input_length,)
@@ -98,7 +97,8 @@ class Embedding(Layer):
initializer=self.embeddings_initializer,
name='embeddings',
regularizer=self.embeddings_regularizer,
constraint=self.embeddings_constraint)
constraint=self.embeddings_constraint,
dtype=self.dtype)
self.built = True
def compute_mask(self, inputs, mask=None):
+1 -1
Ver Arquivo
@@ -137,7 +137,7 @@ class BatchNormalization(Layer):
def normalize_inference():
if needs_broadcasting:
# In this case we must explictly broadcast all parameters.
# In this case we must explicitly broadcast all parameters.
broadcast_moving_mean = K.reshape(self.moving_mean,
broadcast_shape)
broadcast_moving_variance = K.reshape(self.moving_variance,
+1 -1
Ver Arquivo
@@ -953,7 +953,7 @@ class LSTM(Recurrent):
the linear transformation of the recurrent state.
# References
- [Long short-term memory](http://deeplearning.cs.cmu.edu/pdfs/Hochreiter97_lstm.pdf) (original 1997 paper)
- [Long short-term memory](http://www.bioinf.jku.at/publications/older/2604.pdf) (original 1997 paper)
- [Learning to forget: Continual prediction with LSTM](http://www.mitpressjournals.org/doi/pdf/10.1162/089976600300015015)
- [Supervised sequence labeling with recurrent neural networks](http://www.cs.toronto.edu/~graves/preprint.pdf)
- [A Theoretically Grounded Application of Dropout in Recurrent Neural Networks](http://arxiv.org/abs/1512.05287)
+1 -2
Ver Arquivo
@@ -155,8 +155,7 @@ class TimeDistributed(Wrapper):
def call(self, inputs, training=None, mask=None):
kwargs = {}
func_args = inspect.getargspec(self.layer.call).args
if 'training' in func_args:
if has_arg(self.layer.call, 'training'):
kwargs['training'] = training
uses_learning_phase = False
+4 -3
Ver Arquivo
@@ -3,7 +3,6 @@
import six
import warnings
import functools
import inspect
import numpy as np
@@ -86,7 +85,7 @@ def generate_legacy_interface(allowed_positional_args=None,
warnings.warn('Update your `' + object_name +
'` call to the Keras 2 API: ' + signature, stacklevel=2)
return func(*args, **kwargs)
wrapper._legacy_support_signature = inspect.getargspec(func)
wrapper._original_function = func
return wrapper
return legacy_support
@@ -601,7 +600,9 @@ legacy_generator_methods_support = generate_legacy_method_interface(
('val_samples', 'steps'),
('nb_epoch', 'epochs'),
('nb_val_samples', 'validation_steps'),
('nb_worker', 'workers')],
('nb_worker', 'workers'),
('pickle_safe', 'use_multiprocessing'),
('max_q_size', 'max_queue_size')],
preprocessor=generator_methods_args_preprocessor)
+3 -3
Ver Arquivo
@@ -46,15 +46,15 @@ def logcosh(y_true, y_pred):
def categorical_crossentropy(y_true, y_pred):
return K.categorical_crossentropy(y_pred, y_true)
return K.categorical_crossentropy(y_true, y_pred)
def sparse_categorical_crossentropy(y_true, y_pred):
return K.sparse_categorical_crossentropy(y_pred, y_true)
return K.sparse_categorical_crossentropy(y_true, y_pred)
def binary_crossentropy(y_true, y_pred):
return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)
return K.mean(K.binary_crossentropy(y_true, y_pred), axis=-1)
def kullback_leibler_divergence(y_true, y_pred):
+28 -35
Ver Arquivo
@@ -207,32 +207,19 @@ def load_model(filepath, custom_objects=None, compile=True):
obj: object, dict, or list.
# Returns
The same structure, where occurences
The same structure, where occurrences
of a custom object name have been replaced
with the custom object.
"""
if isinstance(obj, list):
deserialized = []
for value in obj:
if value in custom_objects:
deserialized.append(custom_objects[value])
else:
deserialized.append(value)
deserialized.append(convert_custom_objects(value))
return deserialized
if isinstance(obj, dict):
deserialized = {}
for key, value in obj.items():
deserialized[key] = []
if isinstance(value, list):
for element in value:
if element in custom_objects:
deserialized[key].append(custom_objects[element])
else:
deserialized[key].append(element)
elif value in custom_objects:
deserialized[key] = custom_objects[value]
else:
deserialized[key] = value
deserialized[key] = convert_custom_objects(value)
return deserialized
if obj in custom_objects:
return custom_objects[obj]
@@ -288,7 +275,13 @@ def load_model(filepath, custom_objects=None, compile=True):
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)
try:
model.optimizer.set_weights(optimizer_weight_values)
except ValueError:
warnings.warn('Error in loading the saved optimizer '
'state. As a result, your model is '
'starting with a freshly initialized '
'optimizer.')
return model
@@ -1033,9 +1026,9 @@ class Sequential(Model):
validation_data=None,
validation_steps=None,
class_weight=None,
max_q_size=10,
max_queue_size=10,
workers=1,
pickle_safe=False,
use_multiprocessing=False,
initial_epoch=0):
"""Fits the model on data generated batch-by-batch by a Python generator.
@@ -1072,9 +1065,9 @@ class Sequential(Model):
validation dataset divided by the batch size.
class_weight: Dictionary mapping class indices to a weight
for the class.
max_q_size: Maximum size for the generator queue
max_queue_size: Maximum size for the generator queue
workers: Maximum number of processes to spin up
pickle_safe: Ff True, use process based threading.
use_multiprocessing: if True, use process based threading.
Note that because
this implementation relies on multiprocessing,
you should not pass
@@ -1118,15 +1111,15 @@ class Sequential(Model):
validation_data=validation_data,
validation_steps=validation_steps,
class_weight=class_weight,
max_q_size=max_q_size,
max_queue_size=max_queue_size,
workers=workers,
pickle_safe=pickle_safe,
use_multiprocessing=use_multiprocessing,
initial_epoch=initial_epoch)
@interfaces.legacy_generator_methods_support
def evaluate_generator(self, generator, steps,
max_q_size=10, workers=1,
pickle_safe=False):
max_queue_size=10, workers=1,
use_multiprocessing=False):
"""Evaluates the model on a data generator.
The generator should return the same kind of data
@@ -1137,9 +1130,9 @@ class Sequential(Model):
or (inputs, targets, sample_weights)
steps: Total number of steps (batches of samples)
to yield from `generator` before stopping.
max_q_size: maximum size for the generator queue
max_queue_size: maximum size for the generator queue
workers: maximum number of processes to spin up
pickle_safe: if True, use process based threading.
use_multiprocessing: if True, use process based threading.
Note that because this implementation
relies on multiprocessing, you should not pass
non picklable arguments to the generator
@@ -1159,14 +1152,14 @@ class Sequential(Model):
'before being used.')
return self.model.evaluate_generator(generator,
steps,
max_q_size=max_q_size,
max_queue_size=max_queue_size,
workers=workers,
pickle_safe=pickle_safe)
use_multiprocessing=use_multiprocessing)
@interfaces.legacy_generator_methods_support
def predict_generator(self, generator, steps,
max_q_size=10, workers=1,
pickle_safe=False, verbose=0):
max_queue_size=10, workers=1,
use_multiprocessing=False, verbose=0):
"""Generates predictions for the input samples from a data generator.
The generator should return the same kind of data as accepted by
@@ -1176,9 +1169,9 @@ class Sequential(Model):
generator: generator yielding batches of input samples.
steps: Total number of steps (batches of samples)
to yield from `generator` before stopping.
max_q_size: maximum size for the generator queue
max_queue_size: maximum size for the generator queue
workers: maximum number of processes to spin up
pickle_safe: if True, use process based threading.
use_multiprocessing: if True, use process based threading.
Note that because this implementation
relies on multiprocessing, you should not pass
non picklable arguments to the generator
@@ -1191,9 +1184,9 @@ class Sequential(Model):
if self.model is None:
self.build()
return self.model.predict_generator(generator, steps,
max_q_size=max_q_size,
max_queue_size=max_queue_size,
workers=workers,
pickle_safe=pickle_safe,
use_multiprocessing=use_multiprocessing,
verbose=verbose)
def get_config(self):
+3 -5
Ver Arquivo
@@ -219,8 +219,7 @@ class RMSprop(Optimizer):
def get_updates(self, params, constraints, loss):
grads = self.get_gradients(loss, params)
shapes = [K.get_variable_shape(p) for p in params]
accumulators = [K.zeros(shape) for shape in shapes]
accumulators = [K.zeros(K.get_variable_shape(p), dtype=K.dtype(p)) for p in params]
self.weights = accumulators
self.updates = []
@@ -413,9 +412,8 @@ class Adam(Optimizer):
lr_t = lr * (K.sqrt(1. - K.pow(self.beta_2, t)) /
(1. - K.pow(self.beta_1, t)))
shapes = [K.get_variable_shape(p) for p in params]
ms = [K.zeros(shape) for shape in shapes]
vs = [K.zeros(shape) for shape in shapes]
ms = [K.zeros(K.get_variable_shape(p), dtype=K.dtype(p)) for p in params]
vs = [K.zeros(K.get_variable_shape(p), dtype=K.dtype(p)) for p in params]
self.weights = [self.iterations] + ms + vs
for p, g, m, v in zip(params, grads, ms, vs):
+4 -4
Ver Arquivo
@@ -139,7 +139,7 @@ def random_zoom(x, zoom_range, row_axis=1, col_axis=2, channel_axis=0,
ValueError: if `zoom_range` isn't a tuple.
"""
if len(zoom_range) != 2:
raise ValueError('zoom_range should be a tuple or list of two floats. '
raise ValueError('`zoom_range` should be a tuple or list of two floats. '
'Received arg: ', zoom_range)
if zoom_range[0] == 1 and zoom_range[1] == 1:
@@ -421,8 +421,8 @@ class ImageDataGenerator(object):
self.preprocessing_function = preprocessing_function
if data_format not in {'channels_last', 'channels_first'}:
raise ValueError('data_format should be "channels_last" (channel after row and '
'column) or "channels_first" (channel before row and column). '
raise ValueError('`data_format` should be `"channels_last"` (channel after row and '
'column) or `"channels_first"` (channel before row and column). '
'Received arg: ', data_format)
self.data_format = data_format
if data_format == 'channels_first':
@@ -443,7 +443,7 @@ class ImageDataGenerator(object):
elif len(zoom_range) == 2:
self.zoom_range = [zoom_range[0], zoom_range[1]]
else:
raise ValueError('zoom_range should be a float or '
raise ValueError('`zoom_range` should be a float or '
'a tuple or list of two floats. '
'Received arg: ', zoom_range)
+2 -2
Ver Arquivo
@@ -104,7 +104,7 @@ def make_sampling_table(size, sampling_factor=1e-5):
is the probability that a word of rank i should be sampled.
"""
gamma = 0.577
rank = np.array(list(range(size)))
rank = np.arange(size)
rank[0] = 1
inv_fq = rank * (np.log(rank) + gamma) + 0.5 - 1. / (12. * rank)
f = sampling_factor * inv_fq
@@ -127,7 +127,7 @@ def skipgrams(sequence, vocabulary_size,
of word indices (integers). If using a `sampling_table`,
word indices are expected to match the rank
of the words in a reference dataset (e.g. 10 would encode
the 10-th most frequently occuring token).
the 10-th most frequently occurring token).
Note that index 0 is expected to be a non-word and will be skipped.
vocabulary_size: int. maximum possible word index + 1
window_size: int. actually half-window.
+52 -3
Ver Arquivo
@@ -8,11 +8,13 @@ from __future__ import division
import string
import sys
import warnings
from collections import OrderedDict
from hashlib import md5
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,):
maketrans = string.maketrans
@@ -45,11 +47,58 @@ def one_hot(text, n,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=' '):
"""One-hot encodes a text into a list of word indexes of size n.
This is a wrapper to the `hashing_trick` function using `hash` as the
hashing function, unicity of word to index mapping non-guaranteed.
"""
return hashing_trick(text, n,
hash_function=hash,
filters=filters,
lower=lower,
split=split)
def hashing_trick(text, n,
hash_function=None,
filters='!"#$%&()*+,-./:;<=>?@[\\]^_`{|}~\t\n',
lower=True,
split=' '):
"""Converts a text to a sequence of indexes in a fixed-size hashing space.
# Arguments
text: Input text (string).
n: Dimension of the hashing space.
hash_function: if `None` uses python `hash` function, can be 'md5' or
any function that takes in input a string and returns a int.
Note that `hash` is not a stable hashing function, so
it is not consistent across different runs, while 'md5'
is a stable hashing function.
filters: Sequence of characters to filter out.
lower: Whether to convert the input to lowercase.
split: Sentence split marker (string).
# Returns
A list of integer word indices (unicity non-guaranteed).
`0` is a reserved index that won't be assigned to any word.
Two or more words may be assigned to the same index, due to possible
collisions by the hashing function.
The [probability](https://en.wikipedia.org/wiki/Birthday_problem#Probability_table)
of a collision is in relation to the dimension of the hashing space and
the number of distinct objects.
"""
if hash_function is None:
hash_function = hash
elif hash_function == 'md5':
hash_function = lambda w: int(md5(w.encode()).hexdigest(), 16)
seq = text_to_word_sequence(text,
filters=filters,
lower=lower,
split=split)
return [(abs(hash(w)) % (n - 1) + 1) for w in seq]
return [(hash_function(w) % (n - 1) + 1) for w in seq]
class Tokenizer(object):
+3
Ver Arquivo
@@ -8,6 +8,9 @@ from . import conv_utils
# Globally-importable utils.
from .io_utils import HDF5Matrix
from .data_utils import get_file
from .data_utils import Sequence
from .data_utils import GeneratorEnqueuer
from .data_utils import OrderedEnqueuer
from .generic_utils import CustomObjectScope
from .generic_utils import custom_object_scope
from .generic_utils import get_custom_objects
+360 -8
Ver Arquivo
@@ -2,20 +2,32 @@
from __future__ import absolute_import
from __future__ import print_function
import tarfile
import zipfile
import os
import sys
import shutil
import hashlib
import multiprocessing
import os
import random
import shutil
import sys
import tarfile
import threading
import time
import zipfile
from abc import abstractmethod
from multiprocessing.pool import ThreadPool
import numpy as np
import six
from six.moves.urllib.request import urlopen
from six.moves.urllib.error import URLError
from six.moves.urllib.error import HTTPError
from six.moves.urllib.error import URLError
from six.moves.urllib.request import urlopen
try:
import queue
except ImportError:
import Queue as queue
from ..utils.generic_utils import Progbar
if sys.version_info[0] == 2:
def urlretrieve(url, filename, reporthook=None, data=None):
"""Replacement for `urlretrive` for Python 2.
@@ -34,6 +46,7 @@ if sys.version_info[0] == 2:
a block size in bytes, and the total size of the file.
data: `data` argument passed to `urlopen`.
"""
def chunk_read(response, chunk_size=8192, reporthook=None):
content_type = response.info().get('Content-Length')
total_size = -1
@@ -282,3 +295,342 @@ def validate_file(fpath, file_hash, algorithm='auto', chunk_size=65535):
return True
else:
return False
class Sequence(object):
"""Base object for fitting to a sequence of data, such as a dataset.
Every `Sequence` must implements the `__getitem__` and the `__len__` methods.
# Examples
```python
from skimage.io import imread
from skimage.transform import resize
import numpy as np
# Here, `x_set` is list of path to the images
# and `y_set` are the associated classes.
class CIFAR10Sequence(Sequence):
def __init__(self, x_set, y_set, batch_size):
self.X,self.y = x_set,y_set
self.batch_size = batch_size
def __len__(self):
return len(self.X) // self.batch_size
def __getitem__(self,idx):
batch_x = self.X[idx*self.batch_size:(idx+1)*self.batch_size]
batch_y = self.y[idx*self.batch_size:(idx+1)*self.batch_size]
return np.array([
resize(imread(file_name), (200,200))
for file_name in batch_x]), np.array(batch_y)
```
"""
@abstractmethod
def __getitem__(self, index):
"""Gets batch at position `index`.
# Arguments
index: position of the batch in the Sequence.
# Returns
A batch
"""
raise NotImplementedError
@abstractmethod
def __len__(self):
"""Number of batch in the Sequence.
# Returns
The number of batches in the Sequence.
"""
raise NotImplementedError
def get_index(ds, i):
"""Quick fix for Python2, otherwise, it cannot be pickled.
# Arguments
ds: a Sequence object
i: index
# Returns
The value at index `i`.
"""
return ds[i]
class SequenceEnqueuer(object):
"""Base class to enqueue inputs.
The task of an Enqueuer is to use parallelism to speed up preprocessing.
This is done with processes or threads.
# Examples
```python
enqueuer = SequenceEnqueuer(...)
enqueuer.start()
datas = enqueuer.get()
for data in datas:
# Use the inputs; training, evaluating, predicting.
# ... stop sometime.
enqueuer.close()
```
The `enqueuer.get()` should be an infinite stream of datas.
"""
@abstractmethod
def is_running(self):
raise NotImplementedError
@abstractmethod
def start(self, workers=1, max_queue_size=10):
"""Starts the handler's workers.
# Arguments
workers: number of worker threads
max_queue_size: queue size
(when full, threads could block on `put()`).
"""
raise NotImplementedError
@abstractmethod
def stop(self, timeout=None):
"""Stop running threads and wait for them to exit, if necessary.
Should be called by the same thread which called start().
# Arguments
timeout: maximum time to wait on thread.join()
"""
raise NotImplementedError
@abstractmethod
def get(self):
"""Creates a generator to extract data from the queue.
Skip the data if it is `None`.
# Returns
Generator yielding tuples `(inputs, targets)`
or `(inputs, targets, sample_weights)`.
"""
raise NotImplementedError
class OrderedEnqueuer(SequenceEnqueuer):
"""Builds a Enqueuer from a Sequence.
Used in `fit_generator`, `evaluate_generator`, `predict_generator`.
# Arguments
sequence: A `keras.utils.data_utils.Sequence` object.
use_multiprocessing: use multiprocessing if True, otherwise threading
scheduling: Sequential querying of datas if 'sequential', random otherwise.
"""
def __init__(self, sequence,
use_multiprocessing=False,
scheduling='sequential'):
self.sequence = sequence
self.use_multiprocessing = use_multiprocessing
self.scheduling = scheduling
self.workers = 0
self.executor = None
self.queue = None
self.run_thread = None
self.stop_signal = None
def is_running(self):
return self.stop_signal is not None and not self.stop_signal.is_set()
def start(self, workers=1, max_queue_size=10):
"""Start the handler's workers.
# Arguments
workers: number of worker threads
max_queue_size: queue size
(when full, workers could block on `put()`)
"""
if self.use_multiprocessing:
self.executor = multiprocessing.Pool(workers)
else:
self.executor = ThreadPool(workers)
self.queue = queue.Queue(max_queue_size)
self.stop_signal = threading.Event()
self.run_thread = threading.Thread(target=self._run)
self.run_thread.daemon = True
self.run_thread.start()
def _run(self):
"""Function to submit request to the executor and queue the `Future` objects."""
sequence = list(range(len(self.sequence)))
while True:
if self.scheduling is not 'sequential':
random.shuffle(sequence)
for i in sequence:
if self.stop_signal.is_set():
return
self.queue.put(
self.executor.apply_async(get_index,
(self.sequence, i)), block=True)
def get(self):
"""Creates a generator to extract data from the queue.
Skip the data if it is `None`.
# Returns
Generator yielding tuples (inputs, targets)
or (inputs, targets, sample_weights)
"""
try:
while self.is_running():
inputs = self.queue.get(block=True).get()
if inputs is not None:
yield inputs
except Exception as e:
self.stop()
raise StopIteration(e)
def stop(self, timeout=None):
"""Stops running threads and wait for them to exit, if necessary.
Should be called by the same thread which called `start()`.
# Arguments
timeout: maximum time to wait on `thread.join()`
"""
self.stop_signal.set()
with self.queue.mutex:
self.queue.queue.clear()
self.queue.unfinished_tasks = 0
self.queue.not_full.notify()
self.executor.close()
self.executor.join()
self.run_thread.join(timeout)
class GeneratorEnqueuer(SequenceEnqueuer):
"""Builds a queue out of a data generator.
Used in `fit_generator`, `evaluate_generator`, `predict_generator`.
# Arguments
generator: a generator function which endlessly yields data
use_multiprocessing: use multiprocessing if True, otherwise threading
wait_time: time to sleep in-between calls to `put()`
random_seed: Initial seed for workers,
will be incremented by one for each workers.
"""
def __init__(self, generator,
use_multiprocessing=False,
wait_time=0.05,
random_seed=None):
self.wait_time = wait_time
self._generator = generator
self._use_multiprocessing = use_multiprocessing
self._threads = []
self._stop_event = None
self.queue = None
self.random_seed = random_seed
def start(self, workers=1, max_queue_size=10):
"""Kicks off threads which add data from the generator into the queue.
# Arguments
workers: number of worker threads
max_queue_size: queue size
(when full, threads could block on `put()`)
"""
def data_generator_task():
while not self._stop_event.is_set():
try:
if self._use_multiprocessing or self.queue.qsize() < max_queue_size:
generator_output = next(self._generator)
self.queue.put(generator_output)
else:
time.sleep(self.wait_time)
except Exception:
self._stop_event.set()
raise
try:
if self._use_multiprocessing:
self.queue = multiprocessing.Queue(maxsize=max_queue_size)
self._stop_event = multiprocessing.Event()
else:
self.queue = queue.Queue()
self._stop_event = threading.Event()
for _ in range(workers):
if self._use_multiprocessing:
# Reset random seed else all children processes
# share the same seed
np.random.seed(self.random_seed)
thread = multiprocessing.Process(target=data_generator_task)
thread.daemon = True
if self.random_seed is not None:
self.random_seed += 1
else:
thread = threading.Thread(target=data_generator_task)
self._threads.append(thread)
thread.start()
except:
self.stop()
raise
def is_running(self):
return self._stop_event is not None and not self._stop_event.is_set()
def stop(self, timeout=None):
"""Stops running threads and wait for them to exit, if necessary.
Should be called by the same thread which called `start()`.
# Arguments
timeout: maximum time to wait on `thread.join()`.
"""
if self.is_running():
self._stop_event.set()
for thread in self._threads:
if thread.is_alive():
if self._use_multiprocessing:
thread.terminate()
else:
thread.join(timeout)
if self._use_multiprocessing:
if self.queue is not None:
self.queue.close()
self._threads = []
self._stop_event = None
self.queue = None
def get(self):
"""Creates a generator to extract data from the queue.
Skip the data if it is `None`.
# Returns
A generator
"""
while self.is_running():
if not self.queue.empty():
inputs = self.queue.get()
if inputs is not None:
yield inputs
else:
time.sleep(self.wait_time)
+32
Ver Arquivo
@@ -96,8 +96,40 @@ class HDF5Matrix(object):
@property
def shape(self):
"""Gets a numpy-style shape tuple giving the dataset dimensions.
# Returns
A numpy-style shape tuple.
"""
return (self.end - self.start,) + self.data.shape[1:]
@property
def dtype(self):
"""Gets the datatype of the dataset.
# Returns
A numpy dtype string.
"""
return self.data.dtype
@property
def ndim(self):
"""Gets the number of dimensions (rank) of the dataset.
# Returns
An integer denoting the number of dimensions (rank) of the dataset.
"""
return self.data.ndim
@property
def size(self):
"""Gets the total dataset size (number of elements).
# Returns
An integer denoting the number of elements in the dataset.
"""
return np.prod(self.shape)
def ask_to_proceed_with_overwrite(filepath):
"""Produces a prompt asking about overwriting a file.
+18 -12
Ver Arquivo
@@ -5,14 +5,20 @@ from .. import backend as K
import numpy as np
def print_summary(model, line_length=None, positions=None):
def print_summary(model, line_length=None, positions=None, print_fn=print):
"""Prints a summary of a model.
# Arguments
model: Keras model instance.
line_length: total length of printed lines
positions: relative or absolute positions of log elements in each line.
line_length: Total length of printed lines
(e.g. set this to adapt the display to different
terminal window sizes).
positions: Relative or absolute positions of log elements in each line.
If not provided, defaults to `[.33, .55, .67, 1.]`.
print_fn: Print function to use.
It will be called on each line of the summary.
You can set it to a custom function
in order to capture the string summary.
"""
if model.__class__.__name__ == 'Sequential':
sequential_like = True
@@ -51,11 +57,11 @@ def print_summary(model, line_length=None, positions=None):
line += str(fields[i])
line = line[:positions[i]]
line += ' ' * (positions[i] - len(line))
print(line)
print_fn(line)
print('_' * line_length)
print_fn('_' * line_length)
print_row(to_display, positions)
print('=' * line_length)
print_fn('=' * line_length)
def print_layer_summary(layer):
try:
@@ -108,19 +114,19 @@ def print_summary(model, line_length=None, positions=None):
else:
print_layer_summary_with_connections(layers[i])
if i == len(layers) - 1:
print('=' * line_length)
print_fn('=' * line_length)
else:
print('_' * line_length)
print_fn('_' * line_length)
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))
print('Non-trainable params: {:,}'.format(non_trainable_count))
print('_' * line_length)
print_fn('Total params: {:,}'.format(trainable_count + non_trainable_count))
print_fn('Trainable params: {:,}'.format(trainable_count))
print_fn('Non-trainable params: {:,}'.format(non_trainable_count))
print_fn('_' * line_length)
def convert_all_kernels_in_model(model):
@@ -1,5 +1,8 @@
import pytest
from keras.utils.test_utils import keras_test
from keras.utils.test_utils import layer_test
from keras.utils.generic_utils import CustomObjectScope
from keras.models import Sequential
from keras import applications
from keras import backend as K
@@ -166,5 +169,73 @@ def test_inceptionv3_pooling():
assert model.output_shape == (None, 2048)
@keras_test
@pytest.mark.skipif((K.backend() != 'tensorflow'),
reason="MobileNets are supported only on Tensorflow")
def test_mobilenet():
model = applications.MobileNet(weights=None)
assert model.output_shape == (None, 1000)
@keras_test
@pytest.mark.skipif((K.backend() != 'tensorflow'),
reason="MobileNets are supported only on Tensorflow")
def test_mobilenet_no_top():
model = applications.MobileNet(weights=None, include_top=False)
assert model.output_shape == (None, None, None, 1024)
@keras_test
@pytest.mark.skipif((K.backend() != 'tensorflow'),
reason="MobileNets are supported only on Tensorflow")
def test_mobilenet_pooling():
model = applications.MobileNet(weights=None, include_top=False, pooling='avg')
assert model.output_shape == (None, 1024)
@pytest.mark.skipif(K.backend() != 'tensorflow', reason='Requires TF backend')
@keras_test
def test_depthwise_conv_2d():
_convolution_paddings = ['valid', 'same']
num_samples = 2
stack_size = 3
num_row = 7
num_col = 6
with CustomObjectScope({'relu6': applications.mobilenet.relu6,
'DepthwiseConv2D': applications.mobilenet.DepthwiseConv2D}):
for padding in _convolution_paddings:
for strides in [(1, 1), (2, 2)]:
for multiplier in [1, 2]:
if padding == 'same' and strides != (1, 1):
continue
layer_test(applications.mobilenet.DepthwiseConv2D,
kwargs={'kernel_size': (3, 3),
'padding': padding,
'strides': strides,
'depth_multiplier': multiplier},
input_shape=(num_samples, num_row, num_col, stack_size))
layer_test(applications.mobilenet.DepthwiseConv2D,
kwargs={'kernel_size': 3,
'padding': padding,
'data_format': 'channels_first',
'activation': None,
'depthwise_regularizer': 'l2',
'bias_regularizer': 'l2',
'activity_regularizer': 'l2',
'depthwise_constraint': 'unit_norm',
'strides': strides,
'depth_multiplier': multiplier},
input_shape=(num_samples, stack_size, num_row, num_col))
# Test invalid use case
with pytest.raises(ValueError):
model = Sequential([applications.mobilenet.DepthwiseConv2D(kernel_size=3,
padding=padding,
batch_input_shape=(None, None, 5, None))])
if __name__ == '__main__':
pytest.main([__file__])
+8 -11
Ver Arquivo
@@ -131,11 +131,11 @@ def check_cross_entropy_with_valid_probability_distribution():
yth = KTH.variable(yval)
yc = KC.placeholder((4, 2))
ztf = KTF.eval(KTF.categorical_crossentropy(xtf, ytf, from_logits=True))
zth = KTH.eval(KTH.categorical_crossentropy(xth, yth, from_logits=True))
ztf = KTF.eval(KTF.categorical_crossentropy(ytf, xtf, from_logits=True))
zth = KTH.eval(KTH.categorical_crossentropy(yth, xth, from_logits=True))
func_cntk = KC.function([xc, yc],
[KC.categorical_crossentropy(xc, yc, from_logits=True), ])
[KC.categorical_crossentropy(yc, xc, from_logits=True)])
zc = func_cntk([xval, yval])
# Keras function return a list, take the first output
assert len(zc) == 1
@@ -839,7 +839,7 @@ class TestBackend(object):
np.log(np.sum(np.exp(x_np), axis=axis, keepdims=keepdims)),
rtol=1e-5)
@pytest.mark.parametrize('K', [KTH, KTF], ids=["KTH", "KTF"])
@pytest.mark.parametrize('K', [KTF], ids=["KTF"])
def test_logsumexp_optim(self, K):
'''
Check if optimization works.
@@ -886,7 +886,7 @@ class TestBackend(object):
check_two_tensor_operation('binary_crossentropy', (4, 2), (4, 2), BACKENDS, from_logits=True)
# cross_entropy call require the label is a valid probability distribution,
# otherwise it is garbage in garbage out...
# due to the algo difference, we can't guranteen CNTK has the same result on the garbage input.
# due to the algo difference, we can't guarantee CNTK has the same result on the garbage input.
# so create a seperate test case for valid lable input
check_two_tensor_operation('categorical_crossentropy', (4, 2), (4, 2), [KTH, KTF], from_logits=True)
check_cross_entropy_with_valid_probability_distribution()
@@ -1180,6 +1180,9 @@ class TestBackend(object):
cntk_check_single_tensor_operation('pool3d', (5, 9, 11, 5, 3), pool_size=(2, 3, 2),
strides=(1, 1, 1), pool_mode='avg')
check_single_tensor_operation('pool3d', (2, 6, 6, 6, 3), [KTH, KTF], pool_size=(3, 3, 3),
strides=(1, 1, 1), padding='same', pool_mode='avg')
def test_random_normal(self):
mean = 0.
std = 1.
@@ -1387,12 +1390,6 @@ class TestBackend(object):
ztf = KTF.eval(ztf)
assert zth.shape == ztf.shape
# TODO remove this if statement when Theano without
# T.nnet.bn.batch_normalization_train is deprecated
zth2, _, _ = KTH._old_normalize_batch_in_training(xth, None, None,
reduction_axes=[0, 1, 2, 3])
assert zth.shape == tuple(KTH.eval(zth2.shape))
def test_ctc(self):
# simplified version of TensorFlow's test
+130 -5
Ver Arquivo
@@ -1,17 +1,91 @@
import pytest
import numpy as np
from numpy.testing import assert_allclose
import sys
import scipy.sparse as sparse
from keras.layers import Dense, Dropout
from keras.engine.topology import Input
from keras.engine.training import Model, _check_loss_and_target_compatibility
from keras.engine.training import Model
from keras.engine.training import Model
from keras.engine.training import _check_loss_and_target_compatibility
from keras.engine.training import _weighted_masked_objective
from keras.engine.training import _check_array_lengths
from keras.engine.training import _slice_arrays
from keras.models import Sequential
from keras import backend as K
from keras.utils import Sequence
from keras.utils.test_utils import keras_test
from keras.callbacks import LambdaCallback
class RandomSequence(Sequence):
def __init__(self, batch_size):
self.batch_size = batch_size
def __len__(self):
return 12
def __getitem__(self, idx):
return [np.random.random((self.batch_size, 3)), np.random.random((self.batch_size, 3))], [
np.random.random((self.batch_size, 4)),
np.random.random((self.batch_size, 3))]
@keras_test
def test_check_array_lengths():
_check_array_lengths(None, None, None)
a_np = np.random.random((4, 3, 3))
_check_array_lengths(a_np, a_np, a_np)
_check_array_lengths([a_np, a_np], [a_np, a_np], [a_np, a_np])
_check_array_lengths([None], [None], [None])
b_np = np.random.random((3, 4))
with pytest.raises(ValueError):
_check_array_lengths(a_np, None, None)
with pytest.raises(ValueError):
_check_array_lengths(a_np, a_np, None)
with pytest.raises(ValueError):
_check_array_lengths([a_np], [None], None)
with pytest.raises(ValueError):
_check_array_lengths([a_np], [b_np], None)
with pytest.raises(ValueError):
_check_array_lengths([a_np], None, [b_np])
@keras_test
def test_slice_arrays():
input_a = np.random.random((10, 3))
_slice_arrays(None)
_slice_arrays(input_a, 0)
_slice_arrays(input_a, 0, 1)
_slice_arrays(input_a, stop=2)
input_a = [None, [1, 1], None, [1, 1]]
_slice_arrays(input_a, 0)
_slice_arrays(input_a, 0, 1)
_slice_arrays(input_a, stop=2)
input_a = [None]
_slice_arrays(input_a, 0)
_slice_arrays(input_a, 0, 1)
_slice_arrays(input_a, stop=2)
input_a = None
_slice_arrays(input_a, 0)
_slice_arrays(input_a, 0, 1)
_slice_arrays(input_a, stop=2)
@keras_test
def test_weighted_masked_objective():
a = Input(shape=(3,), name='input_a')
# weighted_masked_objective
def mask_dummy(y_true=None, y_pred=None, weight=None):
return K.placeholder(y_true.shape)
weighted_function = _weighted_masked_objective(K.categorical_crossentropy)
weighted_function(a, a, None)
@keras_test
def test_model_methods():
a = Input(shape=(3,), name='input_a')
@@ -80,7 +154,9 @@ def test_model_methods():
out = model.fit({'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np},
epochs=1, batch_size=4, validation_split=0.5,
validation_data=({'input_a': input_a_np, 'input_b': input_b_np}, {'dense_1': output_a_np, 'dropout': output_b_np}))
validation_data=(
{'input_a': input_a_np, 'input_b': input_b_np},
{'dense_1': output_a_np, 'dropout': output_b_np}))
# test_on_batch
out = model.test_on_batch([input_a_np, input_b_np],
@@ -174,6 +250,7 @@ def test_model_methods():
while True:
yield ([np.random.random((batch_sz, 3)), np.random.random((batch_sz, 3))],
[np.random.random((batch_sz, 4)), np.random.random((batch_sz, 3))])
out = model.fit_generator(gen_data(4), steps_per_epoch=3, epochs=5,
initial_epoch=2, callbacks=[tracker_cb])
assert trained_epochs == [2, 3, 4]
@@ -203,6 +280,13 @@ def test_model_methods():
out = model.evaluate([input_a_np, input_b_np], [output_a_np, output_b_np], batch_size=4)
out = model.predict([input_a_np, input_b_np], batch_size=4)
# empty batch
with pytest.raises(ValueError):
def gen_data():
while True:
yield (np.asarray([]), np.asarray([]))
out = model.evaluate_generator(gen_data(), steps=1)
# x is not a list of numpy arrays.
with pytest.raises(ValueError):
out = model.predict([None])
@@ -291,6 +375,47 @@ def test_model_methods():
[output_a_np, output_b_np],
sample_weight=sample_weight)
model.compile(optimizer, loss, metrics=[], loss_weights=loss_weights,
sample_weight_mode=None)
trained_epochs = []
out = model.fit_generator(generator=RandomSequence(3), steps_per_epoch=4, epochs=5,
initial_epoch=0, validation_data=RandomSequence(4),
validation_steps=3, callbacks=[tracker_cb])
assert trained_epochs == [0, 1, 2, 3, 4]
@pytest.mark.skipif(sys.version_info < (3,), reason='Cannot catch warnings in python 2')
@keras_test
def test_warnings():
a = Input(shape=(3,), name='input_a')
b = Input(shape=(3,), name='input_b')
a_2 = Dense(4, name='dense_1')(a)
dp = Dropout(0.5, name='dropout')
b_2 = dp(b)
model = Model([a, b], [a_2, b_2])
optimizer = 'rmsprop'
loss = 'mse'
loss_weights = [1., 0.5]
model.compile(optimizer, loss, metrics=[], loss_weights=loss_weights,
sample_weight_mode=None)
def gen_data(batch_sz):
while True:
yield ([np.random.random((batch_sz, 3)), np.random.random((batch_sz, 3))],
[np.random.random((batch_sz, 4)), np.random.random((batch_sz, 3))])
with pytest.warns(Warning) as w:
out = model.fit_generator(gen_data(4), steps_per_epoch=10, use_multiprocessing=True, workers=2)
warning_raised = any(['Sequence' in str(w_.message) for w_ in w])
assert warning_raised, 'No warning raised when using generator with processes.'
with pytest.warns(None) as w:
out = model.fit_generator(RandomSequence(3), steps_per_epoch=4, use_multiprocessing=True, workers=2)
assert all(['Sequence' not in str(w_.message) for w_ in w]), 'A warning was raised for Sequence.'
@pytest.mark.skipif(K.backend() != 'tensorflow', reason='sparse operations supported only by TF')
@keras_test
@@ -318,9 +443,9 @@ def test_trainable_argument():
assert_allclose(out, out_2)
# test with nesting
input = Input(shape=(3,))
output = model(input)
model = Model(input, output)
inputs = Input(shape=(3,))
outputs = model(inputs)
model = Model(inputs, outputs)
model.compile('rmsprop', 'mse')
out = model.predict(x)
model.train_on_batch(x, y)
+72 -27
Ver Arquivo
@@ -388,6 +388,51 @@ def test_convolution_3d():
stack_size))
@keras_test
def test_conv3d_transpose():
filters = 2
stack_size = 3
num_depth = 7
num_row = 5
num_col = 6
for padding in _convolution_paddings:
for strides in [(1, 1, 1), (2, 2, 2)]:
for data_format in ['channels_first', 'channels_last']:
if padding == 'same' and strides != (1, 1, 1):
continue
layer_test(convolutional.Conv3DTranspose,
kwargs={'filters': filters,
'kernel_size': 3,
'padding': padding,
'strides': strides,
'data_format': data_format},
input_shape=(None, num_depth, num_row, num_col, stack_size),
fixed_batch_size=True)
layer_test(convolutional.Conv3DTranspose,
kwargs={'filters': filters,
'kernel_size': 3,
'padding': padding,
'data_format': 'channels_first',
'activation': None,
'kernel_regularizer': 'l2',
'bias_regularizer': 'l2',
'activity_regularizer': 'l2',
'kernel_constraint': 'max_norm',
'bias_constraint': 'max_norm',
'strides': strides},
input_shape=(None, stack_size, num_depth, num_row, num_col),
fixed_batch_size=True)
# Test invalid use case
with pytest.raises(ValueError):
model = Sequential([convolutional.Conv3DTranspose(filters=filters,
kernel_size=3,
padding=padding,
batch_input_shape=(None, None, 5, None, None))])
@keras_test
def test_maxpooling_3d():
pool_size = (3, 3, 3)
@@ -428,29 +473,29 @@ def test_zero_padding_1d():
input_dim = 2
num_steps = 5
shape = (num_samples, num_steps, input_dim)
input = np.ones(shape)
inputs = np.ones(shape)
# basic test
layer_test(convolutional.ZeroPadding1D,
kwargs={'padding': 2},
input_shape=input.shape)
input_shape=inputs.shape)
layer_test(convolutional.ZeroPadding1D,
kwargs={'padding': (1, 2)},
input_shape=input.shape)
input_shape=inputs.shape)
# correctness test
layer = convolutional.ZeroPadding1D(padding=2)
layer.build(shape)
output = layer(K.variable(input))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
for offset in [0, 1, -1, -2]:
assert_allclose(np_output[:, offset, :], 0.)
assert_allclose(np_output[:, 2:-2, :], 1.)
layer = convolutional.ZeroPadding1D(padding=(1, 2))
layer.build(shape)
output = layer(K.variable(input))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
for left_offset in [0]:
assert_allclose(np_output[:, left_offset, :], 0.)
for right_offset in [-1, -2]:
@@ -481,8 +526,8 @@ def test_zero_padding_2d():
layer = convolutional.ZeroPadding2D(padding=(2, 2),
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
if data_format == 'channels_last':
for offset in [0, 1, -1, -2]:
assert_allclose(np_output[:, offset, :, :], 0.)
@@ -497,8 +542,8 @@ def test_zero_padding_2d():
layer = convolutional.ZeroPadding2D(padding=((1, 2), (3, 4)),
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
if data_format == 'channels_last':
for top_offset in [0]:
assert_allclose(np_output[:, top_offset, :, :], 0.)
@@ -545,8 +590,8 @@ def test_zero_padding_3d():
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)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
if data_format == 'channels_last':
for offset in [0, 1, -1, -2]:
assert_allclose(np_output[:, offset, :, :, :], 0.)
@@ -563,8 +608,8 @@ def test_zero_padding_3d():
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)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
if data_format == 'channels_last':
for dim1_offset in [0, -1, -2]:
assert_allclose(np_output[:, dim1_offset, :, :, :], 0.)
@@ -616,8 +661,8 @@ def test_upsampling_2d():
size=(length_row, length_col),
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
if data_format == 'channels_first':
assert np_output.shape[2] == length_row * input_num_row
assert np_output.shape[3] == length_col * input_num_col
@@ -667,8 +712,8 @@ def test_upsampling_3d():
size=(length_dim1, length_dim2, length_dim3),
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
if data_format == 'channels_first':
assert np_output.shape[2] == length_dim1 * input_len_dim1
assert np_output.shape[3] == length_dim2 * input_len_dim2
@@ -729,8 +774,8 @@ def test_cropping_2d():
layer = convolutional.Cropping2D(cropping=cropping,
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
# compare with numpy
if data_format == 'channels_first':
expected_out = inputs[:,
@@ -757,8 +802,8 @@ def test_cropping_2d():
layer = convolutional.Cropping2D(cropping=cropping,
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
# compare with input
assert_allclose(np_output, inputs)
@@ -794,8 +839,8 @@ def test_cropping_3d():
layer = convolutional.Cropping3D(cropping=cropping,
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
# compare with numpy
if data_format == 'channels_first':
expected_out = inputs[:,
@@ -824,8 +869,8 @@ def test_cropping_3d():
layer = convolutional.Cropping3D(cropping=cropping,
data_format=data_format)
layer.build(inputs.shape)
output = layer(K.variable(inputs))
np_output = K.eval(output)
outputs = layer(K.variable(inputs))
np_output = K.eval(outputs)
# compare with input
assert_allclose(np_output, inputs)
+10 -9
Ver Arquivo
@@ -93,11 +93,12 @@ def test_TimeDistributed():
reason='cntk does not support dropout yet')
def test_TimeDistributed_learning_phase():
# test layers that need learning_phase to be set
np.random.seed(1234)
x = Input(shape=(3, 2))
y = wrappers.TimeDistributed(core.Dropout(.999))(x, training=True)
model = Model(x, y)
y = model.predict(np.random.random((10, 3, 2)))
assert_allclose(0., y, atol=1e-2)
assert_allclose(np.mean(y), 0., atol=1e-1, rtol=1e-1)
@keras_test
@@ -157,18 +158,18 @@ def test_Bidirectional():
model.fit(x, y, epochs=1, batch_size=1)
# test with functional API
input = Input((timesteps, dim))
output = wrappers.Bidirectional(rnn(output_dim, dropout=dropout_rate,
recurrent_dropout=dropout_rate),
merge_mode=mode)(input)
model = Model(input, output)
inputs = Input((timesteps, dim))
outputs = wrappers.Bidirectional(rnn(output_dim, dropout=dropout_rate,
recurrent_dropout=dropout_rate),
merge_mode=mode)(inputs)
model = Model(inputs, outputs)
model.compile(loss='mse', optimizer='sgd')
model.fit(x, y, epochs=1, batch_size=1)
# Bidirectional and stateful
input = Input(batch_shape=(1, timesteps, dim))
output = wrappers.Bidirectional(rnn(output_dim, stateful=True), merge_mode=mode)(input)
model = Model(input, output)
inputs = Input(batch_shape=(1, timesteps, dim))
outputs = wrappers.Bidirectional(rnn(output_dim, stateful=True), merge_mode=mode)(inputs)
model = Model(inputs, outputs)
model.compile(loss='mse', optimizer='sgd')
model.fit(x, y, epochs=1, batch_size=1)
+4 -8
Ver Arquivo
@@ -807,18 +807,14 @@ def test_generator_methods_interface():
samples_per_epoch=1,
validation_data=val_generator(),
nb_val_samples=1,
nb_worker=1)
model.fit_generator(train_generator(),
10,
1,
nb_val_samples=1,
nb_worker=1)
nb_worker=1, pickle_safe=True, max_q_size=3)
model.evaluate_generator(generator=train_generator(),
val_samples=2,
nb_worker=1)
nb_worker=1, pickle_safe=False, max_q_size=3)
model.predict_generator(generator=pred_generator(),
val_samples=2,
nb_worker=1)
nb_worker=1, pickle_safe=False, max_q_size=3)
def test_spatialdropout1d_legacy_interface():
+6
Ver Arquivo
@@ -144,6 +144,12 @@ class TestImage:
assert(len(dir_iterator.classes) == count)
assert(sorted(dir_iterator.filenames) == sorted(filenames))
# Test invalid use cases
with pytest.raises(ValueError):
generator.flow_from_directory(str(tmpdir), color_mode='cmyk')
with pytest.raises(ValueError):
generator.flow_from_directory(str(tmpdir), class_mode='output')
def test_directory_iterator_class_mode_input(self, tmpdir):
tmpdir.join('class-1').mkdir()
+19 -2
Ver Arquivo
@@ -1,6 +1,7 @@
from keras.preprocessing.text import Tokenizer, one_hot
import pytest
import numpy as np
import pytest
from keras.preprocessing.text import Tokenizer, one_hot, hashing_trick
def test_one_hot():
@@ -11,6 +12,22 @@ def test_one_hot():
assert np.min(encoded) >= 0
def test_hashing_trick_hash():
text = 'The cat sat on the mat.'
encoded = hashing_trick(text, 5)
assert len(encoded) == 6
assert np.max(encoded) <= 4
assert np.min(encoded) >= 1
def test_hashing_trick_md5():
text = 'The cat sat on the mat.'
encoded = hashing_trick(text, 5, hash_function='md5')
assert len(encoded) == 6
assert np.max(encoded) <= 4
assert np.min(encoded) >= 1
def test_tokenizer():
texts = ['The cat sat on the mat.',
'The dog sat on the log.',
+3 -3
Ver Arquivo
@@ -98,7 +98,7 @@ def test_sequential_fit_generator():
model.fit_generator(data_generator(True), 5, epochs,
validation_data=data_generator(False),
validation_steps=3)
model.fit_generator(data_generator(True), 5, epochs, max_q_size=2)
model.fit_generator(data_generator(True), 5, epochs, max_queue_size=2)
model.evaluate(x_train, y_train)
@@ -133,8 +133,8 @@ def test_sequential(in_tmpdir):
loss = model.evaluate(x_test, y_test)
prediction = model.predict_generator(data_generator(x_test, y_test), 1, max_q_size=2, verbose=1)
gen_loss = model.evaluate_generator(data_generator(x_test, y_test, 50), 1, max_q_size=2)
prediction = model.predict_generator(data_generator(x_test, y_test), 1, max_queue_size=2, verbose=1)
gen_loss = model.evaluate_generator(data_generator(x_test, y_test, 50), 1, max_queue_size=2)
pred_loss = K.eval(K.mean(losses.get(model.loss)(K.variable(y_test), K.variable(prediction))))
assert(np.isclose(pred_loss, loss))
+165 -3
Ver Arquivo
@@ -1,14 +1,27 @@
"""Tests for functions in data_utils.py.
"""
import os
import pytest
import sys
import tarfile
import threading
import zipfile
from six.moves.urllib.request import pathname2url
from itertools import cycle
import numpy as np
import pytest
from six.moves.urllib.parse import urljoin
from six.moves.urllib.request import pathname2url
from keras.utils import Sequence
from keras.utils import GeneratorEnqueuer
from keras.utils import OrderedEnqueuer
from keras.utils.data_utils import _hash_file
from keras.utils.data_utils import get_file
from keras.utils.data_utils import validate_file
from keras.utils.data_utils import _hash_file
if sys.version_info < (3,):
def next(x):
return x.next()
@pytest.fixture
@@ -64,5 +77,154 @@ def test_data_utils(in_tmpdir):
os.remove('test.txt')
os.remove('test.zip')
"""Enqueuers Tests"""
class threadsafe_iter:
"""Takes an iterator/generator and makes it thread-safe by
serializing call to the `next` method of given iterator/generator.
"""
def __init__(self, it):
self.it = it
self.lock = threading.Lock()
def __iter__(self):
return self
def __next__(self):
return self.next()
def next(self):
with self.lock:
return next(self.it)
def threadsafe_generator(f):
"""A decorator that takes a generator function and makes it thread-safe.
"""
def g(*a, **kw):
return threadsafe_iter(f(*a, **kw))
return g
class TestSequence(Sequence):
def __init__(self, shape):
self.shape = shape
def __getitem__(self, item):
return np.ones(self.shape, dtype=np.uint8) * item
def __len__(self):
return 100
class FaultSequence(Sequence):
def __getitem__(self, item):
raise IndexError(item, 'is not present')
def __len__(self):
return 100
@threadsafe_generator
def create_generator_from_sequence_threads(ds):
for i in cycle(range(len(ds))):
yield ds[i]
def create_generator_from_sequence_pcs(ds):
for i in cycle(range(len(ds))):
yield ds[i]
def test_generator_enqueuer_threads():
enqueuer = GeneratorEnqueuer(create_generator_from_sequence_threads(
TestSequence([3, 200, 200, 3])), use_multiprocessing=False)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
acc = []
for i in range(100):
acc.append(int(next(gen_output)[0, 0, 0, 0]))
"""
Not comparing the order since it is not guarantee.
It may get ordered, but not a lot, one thread can take the GIL before he was supposed to.
"""
assert len(set(acc) - set(range(100))) == 0, "Output is not the same"
enqueuer.stop()
def test_generator_enqueuer_processes():
enqueuer = GeneratorEnqueuer(create_generator_from_sequence_pcs(
TestSequence([3, 200, 200, 3])), use_multiprocessing=True)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
acc = []
for i in range(100):
acc.append(int(next(gen_output)[0, 0, 0, 0]))
assert acc != list(range(100)), "Order was keep in GeneratorEnqueuer with processes"
enqueuer.stop()
def test_generator_enqueuer_fail_threads():
enqueuer = GeneratorEnqueuer(create_generator_from_sequence_threads(
FaultSequence()), use_multiprocessing=False)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
with pytest.raises(StopIteration):
next(gen_output)
def test_generator_enqueuer_fail_processes():
enqueuer = GeneratorEnqueuer(create_generator_from_sequence_pcs(
FaultSequence()), use_multiprocessing=True)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
with pytest.raises(StopIteration):
next(gen_output)
def test_ordered_enqueuer_threads():
enqueuer = OrderedEnqueuer(TestSequence([3, 200, 200, 3]), use_multiprocessing=False)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
acc = []
for i in range(100):
acc.append(next(gen_output)[0, 0, 0, 0])
assert acc == list(range(100)), "Order was not keep in GeneratorEnqueuer with threads"
enqueuer.stop()
def test_ordered_enqueuer_processes():
enqueuer = OrderedEnqueuer(TestSequence([3, 200, 200, 3]), use_multiprocessing=True)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
acc = []
for i in range(100):
acc.append(next(gen_output)[0, 0, 0, 0])
assert acc == list(range(100)), "Order was not keep in GeneratorEnqueuer with processes"
enqueuer.stop()
def test_ordered_enqueuer_fail_threads():
enqueuer = OrderedEnqueuer(FaultSequence(), use_multiprocessing=False)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
with pytest.raises(StopIteration):
next(gen_output)
def test_ordered_enqueuer_fail_processes():
enqueuer = OrderedEnqueuer(FaultSequence(), use_multiprocessing=True)
enqueuer.start(3, 10)
gen_output = enqueuer.get()
with pytest.raises(StopIteration):
next(gen_output)
if __name__ == '__main__':
pytest.main([__file__])
+4
Ver Arquivo
@@ -53,6 +53,10 @@ def test_io_utils(in_tmpdir):
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])
assert y_train.dtype == np.dtype('i'), 'HDF5Matrix dtype should match input array'
assert y_train.ndim == 2, 'HDF5Matrix ndim should match input array'
assert y_train.size == 150, 'HDF5Matrix ndim should match input array'
model = Sequential()
model.add(Dense(64, input_shape=(10,), activation='relu'))
model.add(Dense(1, activation='sigmoid'))
+15 -15
Ver Arquivo
@@ -78,11 +78,11 @@ def test_sequential_model_saving_2():
@keras_test
def test_functional_model_saving():
input = Input(shape=(3,))
x = Dense(2)(input)
output = Dense(3)(x)
inputs = Input(shape=(3,))
x = Dense(2)(inputs)
outputs = Dense(3)(x)
model = Model(input, output)
model = Model(inputs, outputs)
model.compile(loss=losses.MSE,
optimizer=optimizers.RMSprop(lr=0.0001),
metrics=[metrics.categorical_accuracy])
@@ -103,12 +103,12 @@ def test_functional_model_saving():
@keras_test
def test_saving_multiple_metrics_outputs():
input = Input(shape=(5,))
x = Dense(5)(input)
inputs = Input(shape=(5,))
x = Dense(5)(inputs)
output1 = Dense(1, name='output1')(x)
output2 = Dense(1, name='output2')(x)
model = Model(inputs=input, outputs=[output1, output2])
model = Model(inputs=inputs, outputs=[output1, output2])
metrics = {'output1': ['mse', 'binary_accuracy'],
'output2': ['mse', 'binary_accuracy']
@@ -270,11 +270,11 @@ def square_fn(x):
@keras_test
def test_saving_lambda_custom_objects():
input = Input(shape=(3,))
x = Lambda(lambda x: square_fn(x), output_shape=(3,))(input)
output = Dense(3)(x)
inputs = Input(shape=(3,))
x = Lambda(lambda x: square_fn(x), output_shape=(3,))(inputs)
outputs = Dense(3)(x)
model = Model(input, output)
model = Model(inputs, outputs)
model.compile(loss=losses.MSE,
optimizer=optimizers.RMSprop(lr=0.0001),
metrics=[metrics.categorical_accuracy])
@@ -297,10 +297,10 @@ def test_saving_lambda_custom_objects():
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)
inputs = Input(shape=(4, 2, 3))
outputs = Lambda(lambda image, mu, std: (image - mu) / std,
arguments={'mu': mean, 'std': std})(inputs)
model = Model(inputs, outputs)
model.compile(loss='mse', optimizer='sgd', metrics=['acc'])
_, fname = tempfile.mkstemp('.h5')
+33 -33
Ver Arquivo
@@ -49,16 +49,16 @@ def test_multiprocessing_training():
steps_per_epoch=5,
epochs=1,
verbose=1,
max_q_size=10,
max_queue_size=10,
workers=4,
pickle_safe=True)
use_multiprocessing=True)
model.fit_generator(custom_generator(),
steps_per_epoch=5,
epochs=1,
verbose=1,
max_q_size=10,
pickle_safe=False)
max_queue_size=10,
use_multiprocessing=False)
model.fit_generator(custom_generator(True),
steps_per_epoch=5,
@@ -131,16 +131,16 @@ def test_multiprocessing_training_fromfile(in_tmpdir):
steps_per_epoch=5,
epochs=1,
verbose=1,
max_q_size=10,
max_queue_size=10,
workers=2,
pickle_safe=True)
use_multiprocessing=True)
model.fit_generator(custom_generator(),
steps_per_epoch=5,
epochs=1,
verbose=1,
max_q_size=10,
pickle_safe=False)
max_queue_size=10,
use_multiprocessing=False)
os.remove('data.npz')
@@ -166,13 +166,13 @@ def test_multiprocessing_predicting():
model.compile(loss='mse', optimizer='adadelta')
model.predict_generator(custom_generator(),
steps=5,
max_q_size=10,
max_queue_size=10,
workers=2,
pickle_safe=True)
use_multiprocessing=True)
model.predict_generator(custom_generator(),
steps=5,
max_q_size=10,
pickle_safe=False)
max_queue_size=10,
use_multiprocessing=False)
@keras_test
@@ -199,13 +199,13 @@ def test_multiprocessing_evaluating():
model.evaluate_generator(custom_generator(),
steps=5,
max_q_size=10,
max_queue_size=10,
workers=2,
pickle_safe=True)
use_multiprocessing=True)
model.evaluate_generator(custom_generator(),
steps=5,
max_q_size=10,
pickle_safe=False)
max_queue_size=10,
use_multiprocessing=False)
@keras_test
@@ -226,16 +226,16 @@ def test_multiprocessing_fit_error():
samples = batch_size * (good_batches + 1)
with pytest.raises(ValueError):
with pytest.raises(StopIteration):
model.fit_generator(
custom_generator(), samples, 1,
workers=4, pickle_safe=True,
workers=4, use_multiprocessing=True,
)
with pytest.raises(ValueError):
with pytest.raises(StopIteration):
model.fit_generator(
custom_generator(), samples, 1,
pickle_safe=False,
use_multiprocessing=False,
)
@@ -255,45 +255,45 @@ def test_multiprocessing_evaluate_error():
model.add(Dense(1, input_shape=(2, )))
model.compile(loss='mse', optimizer='adadelta')
with pytest.raises(ValueError):
with pytest.raises(StopIteration):
model.evaluate_generator(
custom_generator(), good_batches + 1, 1,
workers=4, pickle_safe=True,
workers=4, use_multiprocessing=True,
)
with pytest.raises(ValueError):
with pytest.raises(StopIteration):
model.evaluate_generator(
custom_generator(), good_batches + 1, 1,
pickle_safe=False,
use_multiprocessing=False,
)
@keras_test
def test_multiprocessing_predict_error():
batch_size = 10
good_batches = 3
workers = 4
def custom_generator():
"""Raises an exception after a few good batches"""
for i in range(good_batches):
yield (np.random.randint(batch_size, 256, (50, 2)),
np.random.randint(batch_size, 2, 50))
yield (np.random.randint(1, 256, size=(2, 5)),
np.random.randint(1, 256, size=(2, 5)))
raise RuntimeError
model = Sequential()
model.add(Dense(1, input_shape=(2, )))
model.add(Dense(1, input_shape=(5,)))
model.compile(loss='mse', optimizer='adadelta')
with pytest.raises(ValueError):
with pytest.raises(StopIteration):
model.predict_generator(
custom_generator(), good_batches + 1, 1,
workers=4, pickle_safe=True,
custom_generator(), good_batches * workers + 1, 1,
workers=workers, use_multiprocessing=True,
)
with pytest.raises(ValueError):
with pytest.raises(StopIteration):
model.predict_generator(
custom_generator(), good_batches + 1, 1,
pickle_safe=False,
use_multiprocessing=False,
)