Comparar commits
95 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| 97e31b6090 | |||
| 62053e68e2 | |||
| 489c07e748 | |||
| 604ea8d68a | |||
| fd3cfb196b | |||
| b71f6ba864 | |||
| dfc128b89a | |||
| 34b8b57c2f | |||
| 3bba409d9e | |||
| 7869cdccec | |||
| 0e18e345b0 | |||
| e5b99c7512 | |||
| 7d4c85018a | |||
| edbec2dbc9 | |||
| 973ece9809 | |||
| 90f441a6a0 | |||
| 5a71090476 | |||
| 76cae0ec44 | |||
| 273f0dda9d | |||
| 882b5a1d89 | |||
| 8c84ad1a86 | |||
| 80bfec7253 | |||
| 91b930298b | |||
| 9c56b91548 | |||
| 7b5bab83f4 | |||
| c5e2116ead | |||
| d9db73a791 | |||
| 01ece4ef7b | |||
| 601f3e7cdb | |||
| a9ca2c547f | |||
| 594cbed03b | |||
| 3938a905a1 | |||
| 88d523e01b | |||
| 0419fe67fc | |||
| 33ddeb5cbe | |||
| 1f5d5b391b | |||
| 198c515208 | |||
| 5156673e17 | |||
| 1529c9c438 | |||
| 32b10a8832 | |||
| 24501d4361 | |||
| bf0c08e24a | |||
| 34d8cce6bc | |||
| f0bfc24adc | |||
| 2f8acfe4bf | |||
| e2fb8b2786 | |||
| ebbc4d9fb8 | |||
| 8fc5b90e9a | |||
| 8a717f5b6c | |||
| aa91994166 | |||
| 2091347a71 | |||
| e0ed174f2c | |||
| 8c2a573ebf | |||
| d7ff7cde92 | |||
| 15d0b0ea08 | |||
| 3695bc2db5 | |||
| a08995a90d | |||
| aea00258e7 | |||
| b581eb3f27 | |||
| 610ccba9f5 | |||
| d5ae6f32dd | |||
| 5308033936 | |||
| e2abb5ef2c | |||
| 1b11b4eeb6 | |||
| 39357b3045 | |||
| ed7a5a1418 | |||
| ae682a71f9 | |||
| 8327b37a0b | |||
| 973b5570aa | |||
| 7cb41fc5cc | |||
| 595d67ad7d | |||
| bb626c120e | |||
| ba8fefa8ec | |||
| 4b24f6d7b1 | |||
| 1c460e1e08 | |||
| 7b4e157356 | |||
| 5749f1b971 | |||
| 3c57aff85b | |||
| 18504bcc86 | |||
| d8864bfe48 | |||
| 078b20169b | |||
| 5f7e78df65 | |||
| fc470db7ab | |||
| f576f37801 | |||
| b74118a766 | |||
| 1c7a0248b9 | |||
| 36a829c20d | |||
| 33af75aa39 | |||
| 844420425e | |||
| da57a530f9 | |||
| 1f17013949 | |||
| f18899cb36 | |||
| 877f946e24 | |||
| a981a8c42c | |||
| ed365e94fd |
+1
-1
@@ -51,7 +51,7 @@ model = Sequential()
|
||||
Stacking layers is as easy as `.add()`:
|
||||
|
||||
```python
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.layers import Dense, Activation
|
||||
|
||||
model.add(Dense(output_dim=64, input_dim=100))
|
||||
model.add(Activation("relu"))
|
||||
|
||||
+2
-100
@@ -82,6 +82,7 @@ from keras import constraints
|
||||
from keras import activations
|
||||
from keras import regularizers
|
||||
|
||||
|
||||
EXCLUDE = {
|
||||
'Optimizer',
|
||||
'Wrapper',
|
||||
@@ -334,6 +335,7 @@ def process_function_docstring(docstring):
|
||||
print('Cleaning up existing sources directory.')
|
||||
if os.path.exists('sources'):
|
||||
shutil.rmtree('sources')
|
||||
|
||||
print('Populating sources directory with templates.')
|
||||
for subdir, dirs, fnames in os.walk('templates'):
|
||||
for fname in fnames:
|
||||
@@ -418,103 +420,3 @@ for page_data in PAGES:
|
||||
if not os.path.exists(subdir):
|
||||
os.makedirs(subdir)
|
||||
open(path, 'w').write(mkdown)
|
||||
|
||||
|
||||
# covered_so_far = set()
|
||||
# for module, module_name in MODULES:
|
||||
# class_pages = []
|
||||
# for name in dir(module):
|
||||
# if name in SKIP:
|
||||
# continue
|
||||
# if name[0] == '_':
|
||||
# continue
|
||||
# module_member = getattr(module, name)
|
||||
# if module_member in covered_so_far:
|
||||
# continue
|
||||
# if inspect.isclass(module_member):
|
||||
# cls = module_member
|
||||
# if cls.__module__ == module_name:
|
||||
|
||||
# try:
|
||||
# class_signature = get_function_signature(cls.__init__)
|
||||
# class_signature = class_signature.replace('__init__', cls.__name__)
|
||||
# except:
|
||||
# # in case the class inherits from object and does not
|
||||
# # define __init__
|
||||
# class_signature = module_name + '.' + cls.__name__ + '()'
|
||||
|
||||
# functions = []
|
||||
# functions_not_defined_here = []
|
||||
# for name in dir(cls):
|
||||
# if name in SKIP:
|
||||
# continue
|
||||
# if name[0] == '_':
|
||||
# continue
|
||||
# cls_member = getattr(cls, name)
|
||||
# if inspect.isfunction(cls_member):
|
||||
# function = cls_member
|
||||
# signature = inspect.getargspec(function)
|
||||
# defaults = signature.defaults
|
||||
# args = signature.args[1:]
|
||||
# if defaults:
|
||||
# kwargs = zip(args[-len(defaults):], defaults)
|
||||
# args = args[:-len(defaults)]
|
||||
# else:
|
||||
# kwargs = []
|
||||
|
||||
# defined_by = get_earliest_class_that_defined_member(function.__name__, cls)
|
||||
# if cls == defined_by:
|
||||
# functions.append(function)
|
||||
# else:
|
||||
# functions_not_defined_here.append((function, defined_by))
|
||||
|
||||
# blocks = []
|
||||
# blocks.append('<span style="float:right;">' + class_to_source_link(cls) + '</span>')
|
||||
# blocks.append('# ' + cls.__name__ + '\n')
|
||||
# blocks.append(code_snippet(class_signature))
|
||||
# docstring = cls.__doc__
|
||||
# if docstring:
|
||||
# blocks.append(process_class_docstring(docstring))
|
||||
|
||||
# if cls.__name__ in INCLUDE_functionS_FOR:
|
||||
# if functions or functions_not_defined_here:
|
||||
# blocks.append('### functions\n')
|
||||
# for function in functions:
|
||||
# signature = get_function_signature(function)
|
||||
# signature = signature.replace(module_name + '.', '')
|
||||
# blocks.append(code_snippet(signature))
|
||||
# docstring = function.__doc__
|
||||
# if docstring:
|
||||
# blocks.append(process_function_docstring(docstring))
|
||||
# for function, defined_by in functions_not_defined_here:
|
||||
# signature = get_function_signature(function)
|
||||
# function_module_name = function.__module__
|
||||
# signature = signature.replace(function_module_name + '.', '')
|
||||
# link = '[' + defined_by.__name__ + '](' + class_to_docs_link(defined_by) + ')'
|
||||
# blocks.append(code_snippet(signature))
|
||||
# blocks.append('Defined by ' + link + '.\n')
|
||||
|
||||
# mkdown = '\n'.join(blocks)
|
||||
# class_pages.append((id(cls), mkdown))
|
||||
# covered_so_far.add(module_member)
|
||||
|
||||
# class_pages.sort(key=lambda x: x[0])
|
||||
# class_pages = [x[1] for x in class_pages]
|
||||
# module_page = '\n----\n\n'.join(class_pages)
|
||||
|
||||
# # save module page.
|
||||
# # Either insert content into existing page,
|
||||
# # or create page otherwise
|
||||
# path = 'sources/' + module_name.replace('.', '/')[6:] + '.md'
|
||||
# if os.path.exists(path):
|
||||
# template = open(path).read()
|
||||
# assert '{{autogenerated}}' in template, ('Template found for ' + path +
|
||||
# ' but missing {{autogenerated}} tag.')
|
||||
# module_page = template.replace('{{autogenerated}}', module_page)
|
||||
# print('...inserting autogenerated content into template:', path)
|
||||
# else:
|
||||
# print('...creating new page with autogenerated content:', path)
|
||||
# subdir = os.path.dirname(path)
|
||||
# if not os.path.exists(subdir):
|
||||
# os.makedirs(subdir)
|
||||
# open(path, 'w').write(module_page)
|
||||
|
||||
externo
+1
@@ -30,6 +30,7 @@ model.add(Activation(tanh))
|
||||
|
||||
- __softmax__: Softmax applied across inputs last dimension. Expects shape either `(nb_samples, nb_timesteps, nb_dims)` or `(nb_samples, nb_dims)`.
|
||||
- __softplus__
|
||||
- __softsign__
|
||||
- __relu__
|
||||
- __tanh__
|
||||
- __sigmoid__
|
||||
|
||||
+57
-9
@@ -10,6 +10,7 @@
|
||||
- [How is the validation split computed?](#how-is-the-validation-split-computed)
|
||||
- [Is the data shuffled during training?](#is-the-data-shuffled-during-training)
|
||||
- [How can I record the training / validation loss / accuracy at each epoch?](#how-can-i-record-the-training-validation-loss-accuracy-at-each-epoch)
|
||||
- [How can I "freeze" layers?](#how-can-i-freeze-keras-layers)
|
||||
- [How can I use stateful RNNs?](#how-can-i-use-stateful-rnns)
|
||||
|
||||
---
|
||||
@@ -20,12 +21,11 @@ Please cite Keras in your publications if it helps your research. Here is an exa
|
||||
|
||||
```
|
||||
@misc{chollet2015keras,
|
||||
author = {Chollet, François},
|
||||
title = {Keras},
|
||||
year = {2015},
|
||||
publisher = {GitHub},
|
||||
journal = {GitHub repository},
|
||||
howpublished = {\url{https://github.com/fchollet/keras}}
|
||||
title={Keras},
|
||||
author={Chollet, Fran\c{c}ois},
|
||||
year={2015},
|
||||
publisher={GitHub},
|
||||
howpublished={\url{https://github.com/fchollet/keras}},
|
||||
}
|
||||
```
|
||||
|
||||
@@ -139,14 +139,28 @@ to pass the learning phase flag to your function:
|
||||
get_3rd_layer_output = K.function([model.layers[0].input, K.learning_phase()],
|
||||
[model.layers[3].output])
|
||||
|
||||
# output in train mode = 0
|
||||
# output in test mode = 0
|
||||
layer_output = get_3rd_layer_output([X, 0])[0]
|
||||
|
||||
# output in test mode = 1
|
||||
# output in train mode = 1
|
||||
layer_output = get_3rd_layer_output([X, 1])[0]
|
||||
```
|
||||
|
||||
Another more flexible way of getting output from intermediate layers is to use the [functional API](/getting-started/functional-api-guide).
|
||||
Another more flexible way of getting output from intermediate layers is to use the [functional API](/getting-started/functional-api-guide). For example, if you have created an autoencoder for MNIST:
|
||||
|
||||
```python
|
||||
inputs = Input(shape=(784,))
|
||||
encoded = Dense(32, activation='relu')(inputs)
|
||||
decoded = Dense(784)(encoded)
|
||||
model = Model(input=inputs, output=decoded)
|
||||
```
|
||||
|
||||
After compiling and training the model, you can get the output of the data from the encoder like this:
|
||||
|
||||
```python
|
||||
encoder = Model(input=inputs, output=encoded)
|
||||
X_encoded = encoder.predict(X)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -201,6 +215,40 @@ print(hist.history)
|
||||
|
||||
---
|
||||
|
||||
### How can I "freeze" Keras layers?
|
||||
|
||||
To "freeze" a layer means to exclude it from training, i.e. its weights will never be updated. This is useful in the context of fine-tuning a model, or using fixed embeddings for a text input.
|
||||
|
||||
You can pass a `trainable` argument (boolean) to a layer constructor to set a layer to be non-trainable:
|
||||
|
||||
```python
|
||||
frozen_layer = Dense(32, trainable=False)
|
||||
```
|
||||
|
||||
Additionally, you can set the `trainable` property of a layer to `True` or `False` after instantiation. For this to take effect, you will need to call `compile()` on your model after modifying the `trainable` property. Here's an example:
|
||||
|
||||
```python
|
||||
x = Input(shape=(32,))
|
||||
layer = Dense(32)
|
||||
layer.trainable = False
|
||||
y = layer(x)
|
||||
|
||||
frozen_model = Model(x, y)
|
||||
# in the model below, the weights of `layer` will not be updated during training
|
||||
frozen_model.compile(optimizer='rmsprop', loss='mse')
|
||||
|
||||
layer.trainable = True
|
||||
trainable_model = Model(x, y)
|
||||
# with this model the weights of the layer will be updated during training
|
||||
# (which will also affect the above model since it uses the same layer instance)
|
||||
trainable_model.compile(optimizer='rmsprop', loss='mse')
|
||||
|
||||
frozen_model.fit(data, labels) # this does NOT update the weights of `layer`
|
||||
trainable_model.fit(data, labels) # this updates the weights of `layer`
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### How can I use stateful RNNs?
|
||||
|
||||
Making a RNN stateful means that the states for the samples of each batch will be reused as initial states for the samples in the next batch.
|
||||
|
||||
@@ -309,8 +309,8 @@ from keras.layers import merge, Convolution2D, Input
|
||||
|
||||
# input tensor for a 3-channel 256x256 image
|
||||
x = Input(shape=(3, 256, 256))
|
||||
# 3x3 conv with 16 output channels
|
||||
y = Convolution2D(16, 3, 3, border_mode='same')
|
||||
# 3x3 conv with 3 output channels (same as input channels)
|
||||
y = Convolution2D(3, 3, 3, border_mode='same')
|
||||
# this returns x + y.
|
||||
z = merge([x, y], mode='sum')
|
||||
```
|
||||
|
||||
@@ -6,6 +6,7 @@ You can create a `Sequential` model by passing a list of layer instances to the
|
||||
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Activation
|
||||
|
||||
model = Sequential([
|
||||
Dense(32, input_dim=784),
|
||||
|
||||
externo
+2
-2
@@ -36,7 +36,7 @@ Keras is compatible with: __Python 2.7-3.5__.
|
||||
|
||||
## Getting started: 30 seconds to Keras
|
||||
|
||||
The core data structure of Keras is a __model__, a way to organize layers. The main type of model is the [`Sequential`](http://keras.io/getting-started/sequential-model-guide) model, a linear stack of layers. For more complex architectures, you should use the [Keras function API](http://keras.io/getting-started/functional-api-guide).
|
||||
The core data structure of Keras is a __model__, a way to organize layers. The main type of model is the [`Sequential`](http://keras.io/getting-started/sequential-model-guide) model, a linear stack of layers. For more complex architectures, you should use the [Keras functional API](http://keras.io/getting-started/functional-api-guide).
|
||||
|
||||
Here's the `Sequential` model:
|
||||
|
||||
@@ -49,7 +49,7 @@ model = Sequential()
|
||||
Stacking layers is as easy as `.add()`:
|
||||
|
||||
```python
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.layers import Dense, Activation
|
||||
|
||||
model.add(Dense(output_dim=64, input_dim=100))
|
||||
model.add(Activation("relu"))
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# Writing your own Keras layers
|
||||
|
||||
For simple, stateless custom operations, you are probably better off using `layers.core.Lambda` layers. But for any custom operation that has trainable weights, you should implement your own layer.
|
||||
|
||||
Here is the skeleton of a Keras layer. There are only three methods you need to implement:
|
||||
|
||||
- `build(input_shape)`: this is where you will define your weights. Trainable weights should be added to the list `self.trainable_weights`. Other attributes of note are: `self.non_trainable_weights` (list) and `self.updates` (list of update tuples (tensor, new_tensor)). For an example of how to use `non_trainable_weights` and `updates`, see the code for the `BatchNormalization` layer.
|
||||
- `call(x)`: this is where the layer's logic lives. Unless you want you want your layer to support masking, you only have to care about the first argument passed to `call`: the input tensor.
|
||||
- `get_output_shape_for(input_shape)`: in case your layer modifies the shape of its input, you should specify here the shape transformation logic. This allows Keras to do automatic shape inference.
|
||||
|
||||
```python
|
||||
from keras import backend as K
|
||||
from keras.engine.topology import Layer
|
||||
import numpy as np
|
||||
|
||||
class MyLayer(Layer):
|
||||
def __init__(self, output_dim, **kwargs):
|
||||
self.output_dim = output_dim
|
||||
super(MyLayer, self).__init__(**kwargs)
|
||||
|
||||
def build(self, input_shape):
|
||||
input_dim = input_shape[1]
|
||||
initial_weight_value = np.random.random((input_dim, output_dim))
|
||||
self.W = K.variable(initial_weight_value)
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
def call(self, x, mask=None):
|
||||
return K.dot(x, self.W)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
return (input_shape[0], self.output_dim)
|
||||
```
|
||||
|
||||
The existing Keras layers provide ample examples of how to implement almost anything. Never hesitate to read the source code!
|
||||
externo
+3
-2
@@ -27,5 +27,6 @@ For a few examples of such functions, check out the [objectives source](https://
|
||||
- __binary_crossentropy__: Also known as logloss.
|
||||
- __categorical_crossentropy__: Also known as multiclass logloss. __Note__: using this objective requires that your labels are binary arrays of shape `(nb_samples, nb_classes)`.
|
||||
- __sparse_categorical_crossentropy__: As above but accepts sparse labels. __Note__: this objective still requires that your labels have the same number of dimensions as your outputs; you may need to add a length-1 dimension to the shape of your labels, e.g with `np.expand_dims(y, -1)`.
|
||||
- __poisson__: mean of `(predictions - targets * log(predictions))`
|
||||
- __cosine_proximity__: the opposite (negative) of the mean cosine proximity between predictions and targets.
|
||||
- __kullback_leibler_divergence__ / __kld__: Information gain from a predicted probability distribution Q to a true probability distribution P. Gives a measure of difference between both distributions.
|
||||
- __poisson__: Mean of `(predictions - targets * log(predictions))`
|
||||
- __cosine_proximity__: The opposite (negative) of the mean cosine proximity between predictions and targets.
|
||||
|
||||
+74
-11
@@ -2,18 +2,23 @@
|
||||
## ImageDataGenerator
|
||||
|
||||
```python
|
||||
keras.preprocessing.image.ImageDataGenerator(featurewise_center=True,
|
||||
keras.preprocessing.image.ImageDataGenerator(featurewise_center=False,
|
||||
samplewise_center=False,
|
||||
featurewise_std_normalization=True,
|
||||
featurewise_std_normalization=False,
|
||||
samplewise_std_normalization=False,
|
||||
zca_whitening=False,
|
||||
rotation_range=0.,
|
||||
width_shift_range=0.,
|
||||
height_shift_range=0.,
|
||||
shear_range=0.,
|
||||
zoom_range=0.,
|
||||
channel_shift_range=0.,
|
||||
fill_mode='nearest',
|
||||
cval=0.,
|
||||
horizontal_flip=False,
|
||||
vertical_flip=False,
|
||||
dim_ordering='th')
|
||||
rescale=None,
|
||||
dim_ordering=K.image_dim_ordering())
|
||||
```
|
||||
|
||||
Generate batches of tensor image data with real-time data augmentation. The data will be looped over (in batches) indefinitely.
|
||||
@@ -30,31 +35,58 @@ Generate batches of tensor image data with real-time data augmentation. The data
|
||||
- __shear_range__: Float. Shear Intensity (Shear angle in counter-clockwise direction as radians)
|
||||
- __zoom_range__: Float or [lower, upper]. Range for random zoom. If a float, `[lower, upper] = [1-zoom_range, 1+zoom_range]`.
|
||||
- __channel_shift_range__: Float. Range for random channel shifts.
|
||||
- __fill_mode__: One of {"constant", "nearest", "reflect" or "wrap"}.
|
||||
- __cval__: Float or Int. Value used for points outside the boundaries when `fill_mode` is "constant".
|
||||
- __fill_mode__: One of {"constant", "nearest", "reflect" or "wrap"}. Points outside the boundaries of the input are filled according to the given mode.
|
||||
- __cval__: Float or Int. Value used for points outside the boundaries when `fill_mode = "constant"`.
|
||||
- __horizontal_flip__: Boolean. Randomly flip inputs horizontally.
|
||||
- __vertical_flip__: Boolean. Randomly flip inputs vertically.
|
||||
- __rescale__: rescaling factor. Defaults to None. If None or 0, no rescaling is applied,
|
||||
otherwise we multiply the data by the value provided (before applying
|
||||
any other transformation).
|
||||
- __dim_ordering__: One of {"th", "tf"}.
|
||||
"tf" mode means that the images should have shape `(samples, width, height, channels)`,
|
||||
"th" mode means that the images should have shape `(samples, channels, width, height)`.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
- __Methods__:
|
||||
- __fit(X)__: Required if featurewise_center or featurewise_std_normalization or zca_whitening. Compute necessary quantities on some sample data.
|
||||
- __fit(X)__: Compute the internal data stats related to the data-dependent transformations, based on an array of sample data.
|
||||
Only required if featurewise_center or featurewise_std_normalization or zca_whitening.
|
||||
- __Arguments__:
|
||||
- __X__: sample data.
|
||||
- __augment__: Boolean (default: False). Whether to fit on randomly augmented samples.
|
||||
- __rounds__: int (default: 1). If augment, how many augmentation passes over the data to use.
|
||||
- __flow(X, y)__:
|
||||
- __flow(X, y)__: Takes numpy data & label arrays, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
|
||||
- __Arguments__:
|
||||
- __X__: data.
|
||||
- __y__: labels.
|
||||
- __batch_size__: int (default: 32).
|
||||
- __shuffle__: boolean (defaut: False).
|
||||
- __save_to_dir__: None or str. This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
|
||||
- __save_prefix__: str. Prefix to use for filenames of saved pictures.
|
||||
- __save_format__: one of "png", jpeg".
|
||||
- __save_to_dir__: None or str (default: None). This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
|
||||
- __save_prefix__: str (default: `''`). Prefix to use for filenames of saved pictures (only relevant if `save_to_dir` is set).
|
||||
- __save_format__: one of "png", jpeg" (only relevant if `save_to_dir` is set). Default: "jpeg".
|
||||
- ___yields__: Tuples of `(x, y)` where `x` is a numpy array of image data and `y` is a numpy array of corresponding labels.
|
||||
The generator loops indefinitely.
|
||||
- __flow_from_directory(directory)__: Takes the path to a directory, and generates batches of augmented/normalized data. Yields batches indefinitely, in an infinite loop.
|
||||
- __Arguments__:
|
||||
- __directory: path to the target directory. It should contain one subdirectory per class,
|
||||
and the subdirectories should contain PNG or JPG images. See [this script](https://gist.github.com/fchollet/0830affa1f7f19fd47b06d4cf89ed44d) for more details.
|
||||
- __target_size__: tuple of integers, default: `(256, 256)`. The dimensions to which all images found will be resized.
|
||||
- __color_mode__: one of "grayscale", "rbg". Default: "rgb". Whether the images will be converted to have 1 or 3 color channels.
|
||||
- __classes__: optional list of class subdirectories (e.g. `['dogs', 'cats']`). Default: None. If not provided, the list of classes will be automatically infered (and the order of the classes, which will map to the label indices, will be alphanumeral).
|
||||
- __class_mode__: one of "categorical", "binary", "sparse" or None. Default: "categorical". Determines the type of label arrays that are returned: "categorical" will be 2D one-hot encoded labels, "binary" will be 1D binary labels, "sparse" will be 1D integer labels. If None, no labels are returned (the generator will only yield batches of image data, which is useful to use `model.predict_generator()`, `model.evaluate_generator()`, etc.).
|
||||
- __batch_size__: size of the batches of data (default: 32).
|
||||
- __shuffle__: whether to shuffle the data (default: True)
|
||||
- __seed__: optional random seed for shuffling.
|
||||
- __save_to_dir__: None or str (default: None). This allows you to optimally specify a directory to which to save the augmented pictures being generated (useful for visualizing what you are doing).
|
||||
- __save_prefix__: str. Prefix to use for filenames of saved pictures (only relevant if `save_to_dir` is set).
|
||||
- __save_format__: one of "png", jpeg" (only relevant if `save_to_dir` is set). Default: "jpeg".
|
||||
|
||||
|
||||
- __Examples__:
|
||||
|
||||
Example of using `.flow(X, y)`:
|
||||
|
||||
- __Example__:
|
||||
```python
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data(test_split=0.1)
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
@@ -88,3 +120,34 @@ for e in range(nb_epoch):
|
||||
# the generator loops indefinitely
|
||||
break
|
||||
```
|
||||
|
||||
Example of using `.flow_from_directory(directory)`:
|
||||
|
||||
```python
|
||||
train_datagen = ImageDataGenerator(
|
||||
rescale=1./255,
|
||||
shear_range=0.2,
|
||||
zoom_range=0.2,
|
||||
horizontal_flip=True)
|
||||
|
||||
test_datagen = ImageDataGenerator(rescale=1./255)
|
||||
|
||||
train_generator = train_datagen.flow_from_directory(
|
||||
'data/train',
|
||||
target_size=(150, 150),
|
||||
batch_size=32,
|
||||
class_mode='binary')
|
||||
|
||||
validation_generator = test_datagen.flow_from_directory(
|
||||
'data/validation',
|
||||
target_size=(150, 150),
|
||||
batch_size=32,
|
||||
class_mode='binary')
|
||||
|
||||
model.fit_generator(
|
||||
train_generator,
|
||||
samples_per_epoch=2000,
|
||||
nb_epoch=50,
|
||||
validation_data=validation_generator,
|
||||
nb_val_samples=800)
|
||||
```
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
# Wrappers for the Sciki-Learn API
|
||||
# Wrappers for the Scikit-Learn API
|
||||
|
||||
You can use `Sequential` Keras models (single-input only) as part of your Scikit-Learn workflow via the wrappers found at `keras.wrappers.sklearn.py`.
|
||||
|
||||
@@ -42,4 +42,4 @@ fitting (predicting) parameters are selected in the following order:
|
||||
When using scikit-learn's `grid_search` API, legal tunable parameters are
|
||||
those you could pass to `sk_params`, including fitting parameters.
|
||||
In other words, you could use `grid_search` to search for the best
|
||||
`batch_size` or `nb_epoch` as well as the model parameters.
|
||||
`batch_size` or `nb_epoch` as well as the model parameters.
|
||||
|
||||
@@ -29,8 +29,7 @@ Five digits inverted:
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.engine.training import slice_X
|
||||
from keras.layers.core import Activation, TimeDistributedDense, RepeatVector
|
||||
from keras.layers import recurrent
|
||||
from keras.layers import Activation, TimeDistributed, Dense, RepeatVector, recurrent
|
||||
import numpy as np
|
||||
from six.moves import range
|
||||
|
||||
@@ -140,7 +139,7 @@ for _ in range(LAYERS):
|
||||
model.add(RNN(HIDDEN_SIZE, return_sequences=True))
|
||||
|
||||
# For each of step of the output sequence, decide which character should be chosen
|
||||
model.add(TimeDistributedDense(len(chars)))
|
||||
model.add(TimeDistributed(Dense(len(chars))))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
|
||||
@@ -12,7 +12,7 @@ backend (`K`), our code can run both on TensorFlow and Theano.
|
||||
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Layer, Activation
|
||||
from keras.layers import Dense, Dropout, Layer, Activation
|
||||
from keras.datasets import mnist
|
||||
from keras import backend as K
|
||||
from keras.utils import np_utils
|
||||
|
||||
@@ -16,8 +16,8 @@ Time per epoch: 3s on CPU (core i7).
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.core import Activation, Dense, Merge, Permute, Dropout
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers import Activation, Dense, Merge, Permute, Dropout
|
||||
from keras.layers import LSTM
|
||||
from keras.utils.data_utils import get_file
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
from functools import reduce
|
||||
@@ -94,8 +94,13 @@ def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
|
||||
pad_sequences(Xq, maxlen=query_maxlen), np.array(Y))
|
||||
|
||||
|
||||
path = get_file('babi-tasks-v1-2.tar.gz',
|
||||
origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
except:
|
||||
print('Error downloading dataset, please download it manually:\n'
|
||||
'$ wget http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz\n'
|
||||
'$ mv tasks_1-20_v1-2.tar.gz ~/.keras/datasets/babi-tasks-v1-2.tar.gz')
|
||||
raise
|
||||
tar = tarfile.open(path)
|
||||
|
||||
challenges = {
|
||||
|
||||
@@ -66,7 +66,7 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.utils.data_utils import get_file
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.core import Dense, Merge, Dropout, RepeatVector
|
||||
from keras.layers import Dense, Merge, Dropout, RepeatVector
|
||||
from keras.layers import recurrent
|
||||
from keras.models import Sequential
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
@@ -146,7 +146,13 @@ BATCH_SIZE = 32
|
||||
EPOCHS = 40
|
||||
print('RNN / Embed / Sent / Query = {}, {}, {}, {}'.format(RNN, EMBED_HIDDEN_SIZE, SENT_HIDDEN_SIZE, QUERY_HIDDEN_SIZE))
|
||||
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
except:
|
||||
print('Error downloading dataset, please download it manually:\n'
|
||||
'$ wget http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz\n'
|
||||
'$ mv tasks_1-20_v1-2.tar.gz ~/.keras/datasets/babi-tasks-v1-2.tar.gz')
|
||||
raise
|
||||
tar = tarfile.open(path)
|
||||
# Default QA1 with 1000 samples
|
||||
# challenge = 'tasks_1-20_v1-2/en/qa1_single-supporting-fact_{}.txt'
|
||||
|
||||
@@ -15,8 +15,8 @@ from __future__ import print_function
|
||||
from keras.datasets import cifar10
|
||||
from keras.preprocessing.image import ImageDataGenerator
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.optimizers import SGD
|
||||
from keras.utils import np_utils
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ import h5py
|
||||
import os
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.convolutional import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras import backend as K
|
||||
|
||||
parser = argparse.ArgumentParser(description='Deep Dreams with Keras.')
|
||||
|
||||
@@ -12,9 +12,9 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Lambda
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.convolutional import Convolution1D
|
||||
from keras.layers import Dense, Dropout, Activation, Lambda
|
||||
from keras.layers import Embedding
|
||||
from keras.layers import Convolution1D
|
||||
from keras.datasets import imdb
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
@@ -9,10 +9,10 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, GRU, SimpleRNN
|
||||
from keras.layers.convolutional import Convolution1D, MaxPooling1D
|
||||
from keras.layers import Dense, Dropout, Activation
|
||||
from keras.layers import Embedding
|
||||
from keras.layers import LSTM, GRU, SimpleRNN
|
||||
from keras.layers import Convolution1D, MaxPooling1D
|
||||
from keras.datasets import imdb
|
||||
|
||||
|
||||
|
||||
@@ -19,9 +19,8 @@ np.random.seed(1337) # for reproducibility
|
||||
from keras.preprocessing import sequence
|
||||
from keras.utils import np_utils
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.embeddings import Embedding
|
||||
from keras.layers.recurrent import LSTM, SimpleRNN, GRU
|
||||
from keras.layers import Dense, Dropout, Activation, Embedding
|
||||
from keras.layers import LSTM, SimpleRNN, GRU
|
||||
from keras.datasets import imdb
|
||||
|
||||
max_features = 20000
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
'''Compare LSTM implementations on the IMDB sentiment classification task.
|
||||
|
||||
consume_less='cpu' preprocesses input to the LSTM which typically results in
|
||||
faster computations at the expense of increased peak memory usage as the
|
||||
preprocessed input must be kept in memory.
|
||||
|
||||
consume_less='mem' does away with the preprocessing, meaning that it might take
|
||||
a little longer, but should require less peak memory.
|
||||
|
||||
consume_less='gpu' concatenates the input, output and forget gate's weights
|
||||
into one, large matrix, resulting in faster computation time as the GPU can
|
||||
utilize more cores, at the expense of reduced regularization because the same
|
||||
dropout is shared across the gates.
|
||||
|
||||
Note that the relative performance of the different `consume_less` modes
|
||||
can vary depending on your device, your model and the size of your data.
|
||||
'''
|
||||
|
||||
import time
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Embedding, Dense, LSTM
|
||||
from keras.datasets import imdb
|
||||
|
||||
max_features = 20000
|
||||
max_length = 80
|
||||
embedding_dim = 256
|
||||
batch_size = 128
|
||||
epochs = 10
|
||||
modes = ['cpu', 'mem', 'gpu']
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
X_train = sequence.pad_sequences(X_train, max_length)
|
||||
X_test = sequence.pad_sequences(X_test, max_length)
|
||||
|
||||
# Compile and train different models while meauring performance.
|
||||
results = []
|
||||
for mode in modes:
|
||||
print('Testing mode: consume_less="{}"'.format(mode))
|
||||
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, embedding_dim, input_length=max_length, dropout=0.2))
|
||||
model.add(LSTM(embedding_dim, dropout_W=0.2, dropout_U=0.2, consume_less=mode))
|
||||
model.add(Dense(1, activation='sigmoid'))
|
||||
model.compile(loss='binary_crossentropy',
|
||||
optimizer='adam',
|
||||
metrics=['accuracy'])
|
||||
|
||||
start_time = time.time()
|
||||
history = model.fit(X_train, y_train,
|
||||
batch_size=batch_size,
|
||||
nb_epoch=epochs,
|
||||
validation_data=(X_test, y_test))
|
||||
average_time_per_epoch = (time.time() - start_time) / epochs
|
||||
|
||||
results.append((history, average_time_per_epoch))
|
||||
|
||||
# Compare models' accuracy, loss and elapsed time per epoch.
|
||||
plt.style.use('ggplot')
|
||||
ax1 = plt.subplot2grid((2, 2), (0, 0))
|
||||
ax1.set_title('Accuracy')
|
||||
ax1.set_ylabel('Validation Accuracy')
|
||||
ax1.set_xlabel('Epochs')
|
||||
ax2 = plt.subplot2grid((2, 2), (1, 0))
|
||||
ax2.set_title('Loss')
|
||||
ax2.set_ylabel('Validation Loss')
|
||||
ax2.set_xlabel('Epochs')
|
||||
ax3 = plt.subplot2grid((2, 2), (0, 1), rowspan=2)
|
||||
ax3.set_title('Time')
|
||||
ax3.set_ylabel('Seconds')
|
||||
for mode, result in zip(modes, results):
|
||||
ax1.plot(result[0].epoch, result[0].history['val_acc'], label=mode)
|
||||
ax2.plot(result[0].epoch, result[0].history['val_loss'], label=mode)
|
||||
ax1.legend()
|
||||
ax2.legend()
|
||||
ax3.bar(np.arange(len(results)), [x[1] for x in results],
|
||||
tick_label=modes, align='center')
|
||||
plt.tight_layout()
|
||||
plt.show()
|
||||
@@ -12,8 +12,8 @@ has at least ~100k characters. ~1M is better.
|
||||
|
||||
from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation, Dropout
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers import Dense, Activation, Dropout
|
||||
from keras.layers import LSTM
|
||||
from keras.utils.data_utils import get_file
|
||||
import numpy as np
|
||||
import random
|
||||
|
||||
@@ -11,8 +11,8 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
batch_size = 128
|
||||
|
||||
@@ -3,7 +3,7 @@ with pixel-by-pixel sequential MNIST in
|
||||
"A Simple Way to Initialize Recurrent Networks of Rectified Linear Units"
|
||||
by Quoc V. Le, Navdeep Jaitly, Geoffrey E. Hinton
|
||||
|
||||
arXiv:1504.00941v2 [cs.NE] 7 Apr 201
|
||||
arXiv:1504.00941v2 [cs.NE] 7 Apr 2015
|
||||
http://arxiv.org/pdf/1504.00941v2.pdf
|
||||
|
||||
Optimizer is replaced with RMSprop which yields more stable and steady
|
||||
@@ -17,9 +17,9 @@ from __future__ import print_function
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.layers import Dense, Activation
|
||||
from keras.layers import SimpleRNN
|
||||
from keras.initializations import normal, identity
|
||||
from keras.layers.recurrent import SimpleRNN
|
||||
from keras.optimizers import RMSprop
|
||||
from keras.utils import np_utils
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ def euclidean_distance(vects):
|
||||
|
||||
def eucl_dist_output_shape(shapes):
|
||||
shape1, shape2 = shapes
|
||||
return shape1
|
||||
return (shape1[0], 1)
|
||||
|
||||
|
||||
def contrastive_loss(y_true, y_pred):
|
||||
|
||||
@@ -9,8 +9,8 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
from keras.wrappers.scikit_learn import KerasClassifier
|
||||
from sklearn.grid_search import GridSearchCV
|
||||
|
||||
@@ -19,8 +19,8 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
|
||||
|
||||
@@ -58,7 +58,7 @@ import argparse
|
||||
import h5py
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers.convolutional import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras import backend as K
|
||||
|
||||
parser = argparse.ArgumentParser(description='Neural style transfer with Keras.')
|
||||
|
||||
@@ -8,8 +8,7 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import reuters
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Dropout, Activation
|
||||
from keras.layers.normalization import BatchNormalization
|
||||
from keras.layers import Dense, Dropout, Activation
|
||||
from keras.utils import np_utils
|
||||
from keras.preprocessing.text import Tokenizer
|
||||
|
||||
|
||||
@@ -5,8 +5,7 @@ from __future__ import print_function
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense
|
||||
from keras.layers.recurrent import LSTM
|
||||
from keras.layers import Dense, LSTM
|
||||
|
||||
|
||||
# since we are using stateful rnn tsteps can be set to 1
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
'''This script demonstrates how to build a variational autoencoder with Keras.
|
||||
|
||||
Reference: "Auto-Encoding Variational Bayes" https://arxiv.org/abs/1312.6114
|
||||
'''
|
||||
import numpy as np
|
||||
import matplotlib.pyplot as plt
|
||||
|
||||
from keras.layers import Input, Dense, Lambda
|
||||
from keras.models import Model
|
||||
from keras import backend as K
|
||||
from keras import objectives
|
||||
from keras.datasets import mnist
|
||||
|
||||
batch_size = 16
|
||||
original_dim = 784
|
||||
latent_dim = 2
|
||||
intermediate_dim = 128
|
||||
epsilon_std = 0.01
|
||||
nb_epoch = 40
|
||||
|
||||
x = Input(batch_shape=(batch_size, original_dim))
|
||||
h = Dense(intermediate_dim, activation='relu')(x)
|
||||
z_mean = Dense(latent_dim)(h)
|
||||
z_log_std = Dense(latent_dim)(h)
|
||||
|
||||
def sampling(args):
|
||||
z_mean, z_log_std = args
|
||||
epsilon = K.random_normal(shape=(batch_size, latent_dim),
|
||||
mean=0., std=epsilon_std)
|
||||
return z_mean + K.exp(z_log_std) * epsilon
|
||||
|
||||
# note that "output_shape" isn't necessary with the TensorFlow backend
|
||||
# so you could write `Lambda(sampling)([z_mean, z_log_std])`
|
||||
z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_std])
|
||||
|
||||
# we instantiate these layers separately so as to reuse them later
|
||||
decoder_h = Dense(intermediate_dim, activation='relu')
|
||||
decoder_mean = Dense(original_dim, activation='sigmoid')
|
||||
h_decoded = decoder_h(z)
|
||||
x_decoded_mean = decoder_mean(h_decoded)
|
||||
|
||||
def vae_loss(x, x_decoded_mean):
|
||||
xent_loss = objectives.binary_crossentropy(x, x_decoded_mean)
|
||||
kl_loss = - 0.5 * K.mean(1 + z_log_std - K.square(z_mean) - K.exp(z_log_std), axis=-1)
|
||||
return xent_loss + kl_loss
|
||||
|
||||
vae = Model(x, x_decoded_mean)
|
||||
vae.compile(optimizer='rmsprop', loss=vae_loss)
|
||||
|
||||
# train the VAE on MNIST digits
|
||||
(x_train, y_train), (x_test, y_test) = mnist.load_data()
|
||||
|
||||
x_train = x_train.astype('float32') / 255.
|
||||
x_test = x_test.astype('float32') / 255.
|
||||
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
|
||||
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
|
||||
|
||||
vae.fit(x_train, x_train,
|
||||
shuffle=True,
|
||||
nb_epoch=nb_epoch,
|
||||
batch_size=batch_size,
|
||||
validation_data=(x_test, x_test))
|
||||
|
||||
# build a model to project inputs on the latent space
|
||||
encoder = Model(x, z_mean)
|
||||
|
||||
# display a 2D plot of the digit classes in the latent space
|
||||
x_test_encoded = encoder.predict(x_test, batch_size=batch_size)
|
||||
plt.figure(figsize=(6, 6))
|
||||
plt.scatter(x_test_encoded[:, 0], x_test_encoded[:, 1], c=y_test)
|
||||
plt.colorbar()
|
||||
plt.show()
|
||||
|
||||
# build a digit generator that can sample from the learned distribution
|
||||
decoder_input = Input(shape=(latent_dim,))
|
||||
_h_decoded = decoder_h(decoder_input)
|
||||
_x_decoded_mean = decoder_mean(_h_decoded)
|
||||
generator = Model(decoder_input, _x_decoded_mean)
|
||||
|
||||
# display a 2D manifold of the digits
|
||||
n = 15 # figure with 15x15 digits
|
||||
digit_size = 28
|
||||
figure = np.zeros((digit_size * n, digit_size * n))
|
||||
# we will sample n points within [-15, 15] standard deviations
|
||||
grid_x = np.linspace(-15, 15, n)
|
||||
grid_y = np.linspace(-15, 15, n)
|
||||
|
||||
for i, yi in enumerate(grid_x):
|
||||
for j, xi in enumerate(grid_y):
|
||||
z_sample = np.array([[xi, yi]]) * epsilon_std
|
||||
x_decoded = generator.predict(z_sample)
|
||||
digit = x_decoded[0].reshape(digit_size, digit_size)
|
||||
figure[i * digit_size: (i + 1) * digit_size,
|
||||
j * digit_size: (j + 1) * digit_size] = digit
|
||||
|
||||
plt.figure(figsize=(10, 10))
|
||||
plt.imshow(figure)
|
||||
plt.show()
|
||||
+2
-1
@@ -1,5 +1,4 @@
|
||||
from __future__ import absolute_import
|
||||
__version__ = '1.0.2'
|
||||
from . import backend
|
||||
from . import datasets
|
||||
from . import engine
|
||||
@@ -15,3 +14,5 @@ from . import models
|
||||
from . import objectives
|
||||
from . import optimizers
|
||||
from . import regularizers
|
||||
|
||||
__version__ = '1.0.4'
|
||||
|
||||
@@ -19,6 +19,10 @@ def softplus(x):
|
||||
return K.softplus(x)
|
||||
|
||||
|
||||
def softsign(x):
|
||||
return K.softsign(x)
|
||||
|
||||
|
||||
def relu(x, alpha=0., max_value=None):
|
||||
return K.relu(x, alpha=alpha, max_value=max_value)
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@ from .common import set_epsilon
|
||||
from .common import set_floatx
|
||||
from .common import get_uid
|
||||
from .common import cast_to_floatx
|
||||
from .common import image_dim_ordering
|
||||
from .common import set_image_dim_ordering
|
||||
|
||||
_keras_base_dir = os.path.expanduser('~')
|
||||
if not os.access(_keras_base_dir, os.W_OK):
|
||||
@@ -28,24 +30,27 @@ if os.path.exists(_config_path):
|
||||
assert type(_epsilon) == float
|
||||
_backend = _config.get('backend', _BACKEND)
|
||||
assert _backend in {'theano', 'tensorflow'}
|
||||
_image_dim_ordering = _config.get('image_dim_ordering', image_dim_ordering())
|
||||
assert _image_dim_ordering in {'tf', 'th'}
|
||||
|
||||
set_floatx(_floatx)
|
||||
set_epsilon(_epsilon)
|
||||
_BACKEND = _backend
|
||||
else:
|
||||
# save config file, for easy edition
|
||||
_config = {'floatx': floatx(),
|
||||
'epsilon': epsilon(),
|
||||
'backend': _BACKEND}
|
||||
with open(_config_path, 'w') as f:
|
||||
# add new line in order for bash 'cat' display the content correctly
|
||||
f.write(json.dumps(_config) + '\n')
|
||||
|
||||
# save config file
|
||||
_config = {'floatx': floatx(),
|
||||
'epsilon': epsilon(),
|
||||
'backend': _BACKEND,
|
||||
'image_dim_ordering': image_dim_ordering()}
|
||||
with open(_config_path, 'w') as f:
|
||||
f.write(json.dumps(_config, indent=4))
|
||||
|
||||
if 'KERAS_BACKEND' in os.environ:
|
||||
_backend = os.environ['KERAS_BACKEND']
|
||||
assert _backend in {'theano', 'tensorflow'}
|
||||
_BACKEND = _backend
|
||||
|
||||
# import backend
|
||||
if _BACKEND == 'theano':
|
||||
sys.stderr.write('Using Theano backend.\n')
|
||||
from .theano_backend import *
|
||||
|
||||
@@ -4,13 +4,20 @@ import numpy as np
|
||||
_FLOATX = 'float32'
|
||||
_EPSILON = 10e-8
|
||||
_UID_PREFIXES = {}
|
||||
_IMAGE_DIM_ORDERING = 'th'
|
||||
|
||||
|
||||
def epsilon():
|
||||
'''Returns the value of the fuzz
|
||||
factor used in numeric expressions.
|
||||
'''
|
||||
return _EPSILON
|
||||
|
||||
|
||||
def set_epsilon(e):
|
||||
'''Sets the value of the fuzz
|
||||
factor used in numeric expressions.
|
||||
'''
|
||||
global _EPSILON
|
||||
_EPSILON = e
|
||||
|
||||
@@ -26,8 +33,7 @@ def set_floatx(floatx):
|
||||
global _FLOATX
|
||||
if floatx not in {'float16', 'float32', 'float64'}:
|
||||
raise Exception('Unknown floatx type: ' + str(floatx))
|
||||
floatx = str(floatx)
|
||||
_FLOATX = floatx
|
||||
_FLOATX = str(floatx)
|
||||
|
||||
|
||||
def cast_to_floatx(x):
|
||||
@@ -36,6 +42,23 @@ def cast_to_floatx(x):
|
||||
return np.asarray(x, dtype=_FLOATX)
|
||||
|
||||
|
||||
def image_dim_ordering():
|
||||
'''Returns the image dimension ordering
|
||||
convention ('th' or 'tf').
|
||||
'''
|
||||
return _IMAGE_DIM_ORDERING
|
||||
|
||||
|
||||
def set_image_dim_ordering(dim_ordering):
|
||||
'''Sets the value of the image dimension
|
||||
ordering convention ('th' or 'tf').
|
||||
'''
|
||||
global _IMAGE_DIM_ORDERING
|
||||
if dim_ordering not in {'tf', 'th'}:
|
||||
raise Exception('Unknown dim_ordering:', dim_ordering)
|
||||
_IMAGE_DIM_ORDERING = str(dim_ordering)
|
||||
|
||||
|
||||
def get_uid(prefix=''):
|
||||
if prefix not in _UID_PREFIXES:
|
||||
_UID_PREFIXES[prefix] = 1
|
||||
|
||||
@@ -499,15 +499,21 @@ def resize_images(X, height_factor, width_factor, dim_ordering):
|
||||
positive integers.
|
||||
'''
|
||||
if dim_ordering == 'th':
|
||||
original_shape = int_shape(X)
|
||||
new_shape = tf.shape(X)[2:]
|
||||
new_shape *= tf.constant(np.array([height_factor, width_factor]).astype('int32'))
|
||||
X = permute_dimensions(X, [0, 2, 3, 1])
|
||||
X = tf.image.resize_nearest_neighbor(X, new_shape)
|
||||
return permute_dimensions(X, [0, 3, 1, 2])
|
||||
X = permute_dimensions(X, [0, 3, 1, 2])
|
||||
X.set_shape((None, None, original_shape[2] * height_factor, original_shape[3] * width_factor))
|
||||
return X
|
||||
elif dim_ordering == 'tf':
|
||||
original_shape = int_shape(X)
|
||||
new_shape = tf.shape(X)[1:3]
|
||||
new_shape *= tf.constant(np.array([height_factor, width_factor]).astype('int32'))
|
||||
return tf.image.resize_nearest_neighbor(X, new_shape)
|
||||
X = tf.image.resize_nearest_neighbor(X, new_shape)
|
||||
X.set_shape((None, original_shape[1] * height_factor, original_shape[2] * width_factor, None))
|
||||
return X
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + dim_ordering)
|
||||
|
||||
@@ -539,6 +545,8 @@ def repeat(x, n):
|
||||
|
||||
|
||||
def tile(x, n):
|
||||
if not hasattr(n, 'shape') and not hasattr(n, '__len__'):
|
||||
n = [n]
|
||||
return tf.tile(x, n)
|
||||
|
||||
|
||||
@@ -602,6 +610,16 @@ def get_value(x):
|
||||
return x.eval(session=get_session())
|
||||
|
||||
|
||||
def batch_get_value(xs):
|
||||
'''Returns the value of more than one tensor variable,
|
||||
as a list of Numpy arrays.
|
||||
'''
|
||||
if xs:
|
||||
return get_session().run(xs)
|
||||
else:
|
||||
return []
|
||||
|
||||
|
||||
def set_value(x, value):
|
||||
'''Sets the value of a tensor variable,
|
||||
from a Numpy array.
|
||||
@@ -852,6 +870,10 @@ def softplus(x):
|
||||
return tf.nn.softplus(x)
|
||||
|
||||
|
||||
def softsign(x):
|
||||
return tf.nn.softsign(x)
|
||||
|
||||
|
||||
def categorical_crossentropy(output, target, from_logits=False):
|
||||
'''Categorical crossentropy between an output tensor
|
||||
and a target tensor, where the target is a tensor of the same
|
||||
|
||||
@@ -3,6 +3,10 @@ from theano import tensor as T
|
||||
from theano.sandbox.rng_mrg import MRG_RandomStreams as RandomStreams
|
||||
from theano.tensor.signal import pool
|
||||
from theano.tensor.nnet import conv3d2d
|
||||
try:
|
||||
from theano.tensor.nnet.nnet import softsign as T_softsign
|
||||
except ImportError:
|
||||
from theano.sandbox.softsign import softsign as T_softsign
|
||||
import inspect
|
||||
import numpy as np
|
||||
from .common import _FLOATX, _EPSILON
|
||||
@@ -483,6 +487,13 @@ def get_value(x):
|
||||
return x.get_value()
|
||||
|
||||
|
||||
def batch_get_value(xs):
|
||||
'''Returns the value of more than one tensor variable,
|
||||
as a list of Numpy arrays.
|
||||
'''
|
||||
return [get_value(x) for x in xs]
|
||||
|
||||
|
||||
def set_value(x, value):
|
||||
x.set_value(np.asarray(value, dtype=x.dtype))
|
||||
|
||||
@@ -725,6 +736,10 @@ def softplus(x):
|
||||
return T.nnet.softplus(x)
|
||||
|
||||
|
||||
def softsign(x):
|
||||
return T_softsign(x)
|
||||
|
||||
|
||||
def categorical_crossentropy(output, target, from_logits=False):
|
||||
if from_logits:
|
||||
output = T.nnet.softmax(output)
|
||||
@@ -767,7 +782,7 @@ def dropout(x, level, seed=None):
|
||||
if level < 0. or level >= 1:
|
||||
raise Exception('Dropout level must be in interval [0, 1[.')
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
retain_prob = 1. - level
|
||||
x *= rng.binomial(x.shape, p=retain_prob, dtype=x.dtype)
|
||||
@@ -1012,20 +1027,20 @@ def pool3d(x, pool_size, strides=(1, 1, 1), border_mode='valid',
|
||||
|
||||
def random_normal(shape, mean=0.0, std=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.normal(size=shape, avg=mean, std=std, dtype=dtype)
|
||||
|
||||
|
||||
def random_uniform(shape, low=0.0, high=1.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.uniform(shape, low=low, high=high, dtype=dtype)
|
||||
|
||||
|
||||
def random_binomial(shape, p=0.0, dtype=_FLOATX, seed=None):
|
||||
if seed is None:
|
||||
seed = np.random.randint(10e6)
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.binomial(shape, p=p, dtype=dtype)
|
||||
|
||||
+15
-4
@@ -192,7 +192,7 @@ class ProgbarLogger(Callback):
|
||||
if k in logs:
|
||||
self.log_values.append((k, logs[k]))
|
||||
if self.verbose:
|
||||
self.progbar.update(self.seen, self.log_values)
|
||||
self.progbar.update(self.seen, self.log_values, force=True)
|
||||
|
||||
|
||||
class History(Callback):
|
||||
@@ -430,8 +430,11 @@ class TensorBoard(Callback):
|
||||
histogram_freq: frequency (in epochs) at which to compute activation
|
||||
histograms for the layers of the model. If set to 0,
|
||||
histograms won't be computed.
|
||||
write_graph: whether to visualize the graph in tensorboard. The log file can
|
||||
become quite large when write_graph is set to True.
|
||||
'''
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0):
|
||||
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0, write_graph=True):
|
||||
super(Callback, self).__init__()
|
||||
if K._BACKEND != 'tensorflow':
|
||||
raise Exception('TensorBoard callback only works '
|
||||
@@ -439,6 +442,7 @@ class TensorBoard(Callback):
|
||||
self.log_dir = log_dir
|
||||
self.histogram_freq = histogram_freq
|
||||
self.merged = None
|
||||
self.write_graph = write_graph
|
||||
|
||||
def _set_model(self, model):
|
||||
import tensorflow as tf
|
||||
@@ -457,8 +461,15 @@ class TensorBoard(Callback):
|
||||
tf.histogram_summary('{}_out'.format(layer),
|
||||
layer.output)
|
||||
self.merged = tf.merge_all_summaries()
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph_def)
|
||||
if self.write_graph:
|
||||
if tf.__version__ >= '0.8.0':
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph)
|
||||
else:
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph_def)
|
||||
else:
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir)
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
import tensorflow as tf
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
from __future__ import absolute_import
|
||||
import sys
|
||||
from six.moves import cPickle
|
||||
from six.moves import range
|
||||
|
||||
|
||||
def load_batch(fpath, label_key='labels'):
|
||||
|
||||
+85
-55
@@ -847,10 +847,11 @@ class Layer(object):
|
||||
if not params:
|
||||
return
|
||||
weight_value_tuples = []
|
||||
for p, w in zip(params, weights):
|
||||
if K.get_value(p).shape != w.shape:
|
||||
param_values = K.batch_get_value(params)
|
||||
for pv, p, w in zip(param_values, params, weights):
|
||||
if pv.shape != w.shape:
|
||||
raise Exception('Layer weight shape ' +
|
||||
str(K.get_value(p).shape) +
|
||||
str(pv.shape) +
|
||||
' not compatible with '
|
||||
'provided weight shape ' + str(w.shape))
|
||||
weight_value_tuples.append((p, w))
|
||||
@@ -861,10 +862,7 @@ class Layer(object):
|
||||
as a list of numpy arrays.
|
||||
'''
|
||||
params = self.trainable_weights + self.non_trainable_weights
|
||||
weights = []
|
||||
for p in params:
|
||||
weights.append(K.get_value(p))
|
||||
return weights
|
||||
return K.batch_get_value(params)
|
||||
|
||||
def get_config(self):
|
||||
'''Returns a Python dictionary (serializable)
|
||||
@@ -1017,9 +1015,9 @@ def Input(shape=None, batch_shape=None,
|
||||
```
|
||||
'''
|
||||
if not batch_shape:
|
||||
assert shape, ('Please provide to Input either an `input_shape`' +
|
||||
' or `batch_input_shape` argument. Note that ' +
|
||||
'`input_shape` does not include the batch '
|
||||
assert shape, ('Please provide to Input either a `shape`' +
|
||||
' or a `batch_shape` argument. Note that ' +
|
||||
'`shape` does not include the batch '
|
||||
'dimension.')
|
||||
batch_shape = (None,) + tuple(shape)
|
||||
input_layer = InputLayer(batch_input_shape=batch_shape,
|
||||
@@ -1062,10 +1060,14 @@ class Merge(Layer):
|
||||
and return a single tensor.
|
||||
concat_axis: integer, axis to use in mode `concat`.
|
||||
dot_axes: integer or tuple of integers, axes to use in mode `dot`.
|
||||
output_shape: shape tuple (tuple of integers), or lambda/function
|
||||
to compute output_shape (only if merge mode is a lambda/function).
|
||||
If the latter case, it should take as input a list of shape tuples
|
||||
(1:1 mapping to input tensors) and return a single shape tuple.
|
||||
output_shape: either a shape tuple (tuple of integers), or a lambda/function
|
||||
to compute `output_shape` (only if merge mode is a lambda/function).
|
||||
If the argument is a tuple,
|
||||
it should be expected output shape, *not* including the batch size
|
||||
(same convention as the `input_shape` argument in layers).
|
||||
If the argument is callable, it should take as input a list of shape tuples
|
||||
(1:1 mapping to input tensors) and return a single shape tuple, including the
|
||||
batch size (same convention as the `get_output_shape_for` method of layers).
|
||||
node_indices: optional list of integers containing
|
||||
the output node index for each input layer
|
||||
(in case some input layers have multiple output nodes).
|
||||
@@ -1112,7 +1114,6 @@ class Merge(Layer):
|
||||
node_indices = [0 for _ in range(len(layers))]
|
||||
self._arguments_validation(layers, mode,
|
||||
concat_axis, dot_axes,
|
||||
output_shape,
|
||||
node_indices, tensor_indices)
|
||||
self.built = True
|
||||
self.add_inbound_node(layers, node_indices, tensor_indices)
|
||||
@@ -1120,7 +1121,7 @@ class Merge(Layer):
|
||||
self.built = False
|
||||
|
||||
def _arguments_validation(self, layers, mode, concat_axis, dot_axes,
|
||||
output_shape, node_indices, tensor_indices):
|
||||
node_indices, tensor_indices):
|
||||
'''Validates user-passed arguments and raises exceptions
|
||||
as appropriate.
|
||||
'''
|
||||
@@ -1222,6 +1223,7 @@ class Merge(Layer):
|
||||
l2 = inputs[1]
|
||||
denominator = K.sqrt(K.batch_dot(l1, l1, self.dot_axes) *
|
||||
K.batch_dot(l2, l2, self.dot_axes))
|
||||
denominator = K.maximum(denominator, K.epsilon())
|
||||
output = K.batch_dot(l1, l2, self.dot_axes) / denominator
|
||||
output = K.expand_dims(output, 1)
|
||||
return output
|
||||
@@ -1260,13 +1262,12 @@ class Merge(Layer):
|
||||
tensor_indices.append(tensor_index)
|
||||
self._arguments_validation(layers, self.mode,
|
||||
self.concat_axis, self.dot_axes,
|
||||
self._output_shape,
|
||||
node_indices, tensor_indices)
|
||||
self.built = True
|
||||
self.add_inbound_node(layers, node_indices, tensor_indices)
|
||||
|
||||
outputs = self.inbound_nodes[-1].output_tensors
|
||||
return outputs[0] # merge only returns a single tensor
|
||||
return outputs[0] # merge only returns a single tensor
|
||||
else:
|
||||
return self.call(inputs, mask)
|
||||
|
||||
@@ -1278,7 +1279,7 @@ class Merge(Layer):
|
||||
output_shape = self._output_shape(input_shape)
|
||||
return output_shape
|
||||
elif self._output_shape is not None:
|
||||
return self._output_shape
|
||||
return (input_shape[0],) + tuple(self._output_shape)
|
||||
else:
|
||||
# TODO: consider shape auto-inference with TF
|
||||
raise Exception('The Merge layer ' + self.name +
|
||||
@@ -1300,12 +1301,10 @@ class Merge(Layer):
|
||||
break
|
||||
output_shape[self.concat_axis] += shape[self.concat_axis]
|
||||
return tuple(output_shape)
|
||||
elif self.mode == 'join':
|
||||
return None
|
||||
elif self.mode == 'dot':
|
||||
shape1 = list(input_shapes[0])
|
||||
shape2 = list(input_shapes[1])
|
||||
dot_axes = [a-1 for a in self.dot_axes]
|
||||
dot_axes = [a - 1 for a in self.dot_axes]
|
||||
tensordot_output = np.tensordot(np.zeros(tuple(shape1[1:])),
|
||||
np.zeros(tuple(shape2[1:])),
|
||||
axes=dot_axes)
|
||||
@@ -1330,9 +1329,9 @@ class Merge(Layer):
|
||||
|
||||
if isinstance(self.mode, python_types.LambdaType):
|
||||
if py3:
|
||||
mode = marshal.dumps(self.mode.__code__)
|
||||
mode = marshal.dumps(self.mode.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
mode = marshal.dumps(self.mode.func_code)
|
||||
mode = marshal.dumps(self.mode.func_code).decode('raw_unicode_escape')
|
||||
mode_type = 'lambda'
|
||||
elif callable(self.mode):
|
||||
mode = self.mode.__name__
|
||||
@@ -1368,7 +1367,7 @@ class Merge(Layer):
|
||||
if mode_type == 'function':
|
||||
mode = globals()[config['mode']]
|
||||
elif mode_type == 'lambda':
|
||||
mode = marshal.loads(config['mode'])
|
||||
mode = marshal.loads(config['mode'].encode('raw_unicode_escape'))
|
||||
mode = python_types.FunctionType(mode, globals())
|
||||
else:
|
||||
mode = config['mode']
|
||||
@@ -1402,7 +1401,7 @@ def merge(inputs, mode='sum', concat_axis=-1,
|
||||
|
||||
# Arguments
|
||||
mode: string or lambda/function. If string, must be one
|
||||
of: 'sum', 'mul', 'concat', 'ave', 'join', 'cos', 'dot'.
|
||||
of: 'sum', 'mul', 'concat', 'ave', 'cos', 'dot'.
|
||||
If lambda/function, it should take as input a list of tensors
|
||||
and return a single tensor.
|
||||
concat_axis: integer, axis to use in mode `concat`.
|
||||
@@ -1570,12 +1569,28 @@ class Container(Layer):
|
||||
raise Exception('Output tensors to a ' + cls_name + ' must be '
|
||||
'Keras tensors. Found: ' + str(x))
|
||||
# build self.output_layers:
|
||||
masks = []
|
||||
for x in self.outputs:
|
||||
layer, node_index, tensor_index = x._keras_history
|
||||
self.output_layers.append(layer)
|
||||
self.output_layers_node_indices.append(node_index)
|
||||
self.output_layers_tensor_indices.append(tensor_index)
|
||||
# build self.output_layers:
|
||||
|
||||
# also fill in the output mask cache
|
||||
node = layer.inbound_nodes[node_index]
|
||||
mask = node.output_masks[tensor_index]
|
||||
masks.append(mask)
|
||||
|
||||
# output mask cache
|
||||
mask_cache_key = ','.join([str(id(x)) for x in self.inputs])
|
||||
mask_cache_key += '_' + ','.join([str(id(x)) for x in masks])
|
||||
if len(masks) == 1:
|
||||
mask = masks[0]
|
||||
else:
|
||||
mask = masks
|
||||
self._output_mask_cache[mask_cache_key] = mask
|
||||
|
||||
# build self.input_layers:
|
||||
for x in self.inputs:
|
||||
layer, node_index, tensor_index = x._keras_history
|
||||
# it's supposed to be an input layer, so only one node
|
||||
@@ -1603,7 +1618,7 @@ class Container(Layer):
|
||||
nodes_depths = {} # map {node: depth value}
|
||||
layers_depths = {} # map {layer: depth value}
|
||||
|
||||
def make_node_key(node, depth):
|
||||
def make_node_marker(node, depth):
|
||||
return str(id(node)) + '-' + str(depth)
|
||||
|
||||
def build_map_of_graph(tensor, seen_nodes=set(), depth=0,
|
||||
@@ -1627,7 +1642,7 @@ class Container(Layer):
|
||||
node = layer.inbound_nodes[node_index]
|
||||
|
||||
# prevent cycles
|
||||
seen_nodes.add(make_node_key(node, depth))
|
||||
seen_nodes.add(make_node_marker(node, depth))
|
||||
|
||||
node_key = layer.name + '_ib-' + str(node_index)
|
||||
# update container_nodes
|
||||
@@ -1639,11 +1654,12 @@ class Container(Layer):
|
||||
else:
|
||||
nodes_depths[node] = max(depth, node_depth)
|
||||
# update layers_depths
|
||||
layer_depth = layers_depths.get(layer)
|
||||
if layer_depth is None:
|
||||
layers_depths[layer] = depth
|
||||
previously_seen_depth = layers_depths.get(layer)
|
||||
if previously_seen_depth is None:
|
||||
current_depth = depth
|
||||
else:
|
||||
layers_depths[layer] = max(depth, layer_depth)
|
||||
current_depth = max(depth, previously_seen_depth)
|
||||
layers_depths[layer] = current_depth
|
||||
|
||||
# propagate to all previous tensors connected to this node
|
||||
for i in range(len(node.inbound_layers)):
|
||||
@@ -1652,9 +1668,10 @@ class Container(Layer):
|
||||
node_index = node.node_indices[i]
|
||||
tensor_index = node.tensor_indices[i]
|
||||
next_node = layer.inbound_nodes[node_index]
|
||||
node_key = make_node_key(next_node, depth + 1)
|
||||
if node_key not in seen_nodes:
|
||||
build_map_of_graph(x, seen_nodes, depth + 1,
|
||||
# use node_marker to prevent cycles
|
||||
node_marker = make_node_marker(next_node, current_depth + 1)
|
||||
if node_marker not in seen_nodes:
|
||||
build_map_of_graph(x, seen_nodes, current_depth + 1,
|
||||
layer, node_index, tensor_index)
|
||||
|
||||
for x in self.outputs:
|
||||
@@ -2109,8 +2126,6 @@ class Container(Layer):
|
||||
return output_tensors, output_masks, output_shapes
|
||||
|
||||
def get_config(self):
|
||||
'''TODO: add keras version information
|
||||
'''
|
||||
config = {
|
||||
'name': self.name,
|
||||
}
|
||||
@@ -2191,9 +2206,9 @@ class Container(Layer):
|
||||
# the graph reconstruction process
|
||||
created_layers = {}
|
||||
|
||||
# iterate over saved layers, instantiate them,
|
||||
# then call them on appropriate inputs to create graph nodes
|
||||
for layer_data in config['layers']:
|
||||
def process_layer(layer_data):
|
||||
# iterate over saved layers, instantiate them,
|
||||
# then call them on appropriate inputs to create graph nodes
|
||||
layer_name = layer_data['name']
|
||||
|
||||
# instantiate layer
|
||||
@@ -2218,6 +2233,10 @@ class Container(Layer):
|
||||
layer(input_tensors[0])
|
||||
else:
|
||||
layer(input_tensors)
|
||||
|
||||
for layer_data in config['layers']:
|
||||
process_layer(layer_data)
|
||||
|
||||
name = config.get('name')
|
||||
input_tensors = []
|
||||
output_tensors = []
|
||||
@@ -2275,7 +2294,7 @@ class Container(Layer):
|
||||
for layer in flattened_layers:
|
||||
g = f.create_group(layer.name)
|
||||
symbolic_weights = layer.trainable_weights + layer.non_trainable_weights
|
||||
weight_values = layer.get_weights()
|
||||
weight_values = K.batch_get_value(symbolic_weights)
|
||||
weight_names = []
|
||||
for i, (w, val) in enumerate(zip(symbolic_weights, weight_values)):
|
||||
if hasattr(w, 'name') and w.name:
|
||||
@@ -2350,6 +2369,26 @@ class Container(Layer):
|
||||
K.batch_set_value(weight_value_tuples)
|
||||
f.close()
|
||||
|
||||
def _updated_config(self):
|
||||
'''shared between different serialization methods'''
|
||||
from keras import __version__ as keras_version
|
||||
|
||||
config = self.get_config()
|
||||
model_config = {
|
||||
'class_name': self.__class__.__name__,
|
||||
'config': config,
|
||||
'keras_version': keras_version
|
||||
}
|
||||
|
||||
if hasattr(self, 'optimizer'):
|
||||
model_config['optimizer'] = self.optimizer.get_config()
|
||||
model_config['loss'] = getattr(self.loss, '__name__', self.loss)
|
||||
model_config['sample_weight_mode'] = self.sample_weight_mode
|
||||
|
||||
if hasattr(self, 'loss_weights'):
|
||||
model_config['loss_weights'] = self.loss_weights
|
||||
return model_config
|
||||
|
||||
def to_json(self, **kwargs):
|
||||
'''Returns a JSON string containing the network configuration.
|
||||
|
||||
@@ -2369,11 +2408,7 @@ class Container(Layer):
|
||||
|
||||
raise TypeError('Not JSON Serializable')
|
||||
|
||||
config = self.get_config()
|
||||
model_config = {
|
||||
'class_name': self.__class__.__name__,
|
||||
'config': config,
|
||||
}
|
||||
model_config = self._updated_config()
|
||||
return json.dumps(model_config, default=get_json_type, **kwargs)
|
||||
|
||||
def to_yaml(self, **kwargs):
|
||||
@@ -2387,14 +2422,9 @@ class Container(Layer):
|
||||
functions / classes.
|
||||
'''
|
||||
import yaml
|
||||
config = self.get_config()
|
||||
model_config = {
|
||||
'class_name': self.__class__.__name__,
|
||||
'config': config,
|
||||
}
|
||||
return yaml.dump(model_config, **kwargs)
|
||||
return yaml.dump(self._updated_config(), **kwargs)
|
||||
|
||||
def summary(self):
|
||||
def summary(self, line_length=100, positions=[.33, .55, .67, 1.]):
|
||||
from keras.utils.layer_utils import print_summary
|
||||
|
||||
if hasattr(self, 'flattened_layers'):
|
||||
@@ -2403,7 +2433,7 @@ class Container(Layer):
|
||||
else:
|
||||
flattened_layers = self.layers
|
||||
|
||||
print_summary(flattened_layers, getattr(self, 'container_nodes', None))
|
||||
print_summary(flattened_layers, getattr(self, 'container_nodes', None), line_length=line_length, positions=positions)
|
||||
|
||||
|
||||
def get_source_inputs(tensor, layer=None, node_index=None):
|
||||
|
||||
+20
-13
@@ -84,9 +84,6 @@ def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
|
||||
# check shapes compatibility
|
||||
if shapes:
|
||||
for i in range(len(names)):
|
||||
if not i and not check_batch_dim:
|
||||
# skip the first axis
|
||||
continue
|
||||
array = arrays[i]
|
||||
if len(array.shape) != len(shapes[i]):
|
||||
raise Exception('Error when checking ' + exception_prefix +
|
||||
@@ -94,7 +91,10 @@ def standardize_input_data(data, names, shapes=None, check_batch_dim=True,
|
||||
' to have ' + str(len(shapes[i])) +
|
||||
' dimensions, but got array with shape ' +
|
||||
str(array.shape))
|
||||
for dim, ref_dim in zip(array.shape, shapes[i]):
|
||||
for j, (dim, ref_dim) in enumerate(zip(array.shape, shapes[i])):
|
||||
if not j and not check_batch_dim:
|
||||
# skip the first axis
|
||||
continue
|
||||
if ref_dim:
|
||||
if ref_dim != dim:
|
||||
raise Exception('Error when checking ' + exception_prefix +
|
||||
@@ -452,6 +452,7 @@ class Model(Container):
|
||||
self.optimizer = optimizers.get(optimizer)
|
||||
self.sample_weight_mode = sample_weight_mode
|
||||
self.loss = loss
|
||||
self.loss_weights = loss_weights
|
||||
|
||||
# prepare loss weights
|
||||
if loss_weights is None:
|
||||
@@ -571,6 +572,10 @@ class Model(Container):
|
||||
name = self.output_names[i]
|
||||
self.targets.append(K.placeholder(ndim=len(shape), name=name + '_target'))
|
||||
|
||||
# prepare metrics
|
||||
self.metrics_names = ['loss']
|
||||
self.metrics = []
|
||||
|
||||
# compute total loss
|
||||
total_loss = None
|
||||
for i in range(len(self.outputs)):
|
||||
@@ -580,19 +585,20 @@ class Model(Container):
|
||||
sample_weight = sample_weights[i]
|
||||
mask = masks[i]
|
||||
loss_weight = loss_weights_list[i]
|
||||
output_loss = loss_weight * weighted_loss(y_true, y_pred,
|
||||
sample_weight, mask)
|
||||
output_loss = weighted_loss(y_true, y_pred,
|
||||
sample_weight, mask)
|
||||
if len(self.outputs) > 1:
|
||||
self.metrics.append(output_loss)
|
||||
self.metrics_names.append(self.output_names[i] + '_loss')
|
||||
if total_loss is None:
|
||||
total_loss = output_loss
|
||||
total_loss = loss_weight * output_loss
|
||||
else:
|
||||
total_loss += output_loss
|
||||
total_loss += loss_weight * output_loss
|
||||
|
||||
# add regularization penalties to the loss
|
||||
for r in self.regularizers:
|
||||
total_loss = r(total_loss)
|
||||
|
||||
# prepare metrics
|
||||
self.metrics_names = ['loss']
|
||||
self.metrics = []
|
||||
# list of same size as output_names.
|
||||
# contains tuples (metrics for output, names of metrics)
|
||||
nested_metrics = collect_metrics(metrics, self.output_names)
|
||||
@@ -681,7 +687,7 @@ class Model(Container):
|
||||
|
||||
def _make_predict_function(self):
|
||||
if not hasattr(self, 'predict_function'):
|
||||
raise Exception('You must compile your model before using it.')
|
||||
self.predict_function = None
|
||||
if self.predict_function is None:
|
||||
if self.uses_learning_phase:
|
||||
inputs = self.inputs + [K.learning_phase()]
|
||||
@@ -689,10 +695,11 @@ class Model(Container):
|
||||
inputs = self.inputs
|
||||
# returns network outputs. Does not update weights.
|
||||
# Does update the network states.
|
||||
kwargs = getattr(self, '_function_kwargs', {})
|
||||
self.predict_function = K.function(inputs,
|
||||
self.outputs,
|
||||
updates=self.state_updates,
|
||||
**self._function_kwargs)
|
||||
**kwargs)
|
||||
|
||||
def _fit_loop(self, f, ins, out_labels=[], batch_size=32,
|
||||
nb_epoch=100, verbose=1, callbacks=[],
|
||||
|
||||
@@ -12,11 +12,13 @@ def get_fans(shape, dim_ordering='th'):
|
||||
# TH kernel shape: (depth, input_depth, ...)
|
||||
# TF kernel shape: (..., input_depth, depth)
|
||||
if dim_ordering == 'th':
|
||||
fan_in = np.prod(shape[1:])
|
||||
fan_out = shape[0]
|
||||
receptive_field_size = np.prod(shape[2:])
|
||||
fan_in = shape[1] * receptive_field_size
|
||||
fan_out = shape[0] * receptive_field_size
|
||||
elif dim_ordering == 'tf':
|
||||
fan_in = np.prod(shape[:-1])
|
||||
fan_out = shape[-1]
|
||||
receptive_field_size = np.prod(shape[:2])
|
||||
fan_in = shape[-2] * receptive_field_size
|
||||
fan_out = shape[-1] * receptive_field_size
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + dim_ordering)
|
||||
else:
|
||||
|
||||
+127
-70
@@ -65,6 +65,7 @@ class Convolution1D(Layer):
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
input_dim: Number of channels/dimensions in the input.
|
||||
Either this argument or the keyword argument `input_shape`must be
|
||||
provided when using this layer as the first layer in a model.
|
||||
@@ -85,7 +86,7 @@ class Convolution1D(Layer):
|
||||
border_mode='valid', subsample_length=1,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None, **kwargs):
|
||||
bias=True, input_dim=None, input_length=None, **kwargs):
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution1D:', border_mode)
|
||||
@@ -106,6 +107,7 @@ class Convolution1D(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
self.initial_weights = weights
|
||||
self.input_dim = input_dim
|
||||
@@ -118,15 +120,18 @@ class Convolution1D(Layer):
|
||||
input_dim = input_shape[2]
|
||||
self.W_shape = (self.nb_filter, input_dim, self.filter_length, 1)
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
self.regularizers = []
|
||||
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -137,7 +142,7 @@ class Convolution1D(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -154,11 +159,11 @@ class Convolution1D(Layer):
|
||||
def call(self, x, mask=None):
|
||||
x = K.expand_dims(x, -1) # add a dimension of the right
|
||||
x = K.permute_dimensions(x, (0, 2, 1, 3))
|
||||
conv_out = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='th')
|
||||
|
||||
output = conv_out + K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
output = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='th')
|
||||
if self.bias:
|
||||
output += K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
output = self.activation(output)
|
||||
output = K.squeeze(output, 3) # remove the dummy 3rd dimension
|
||||
output = K.permute_dimensions(output, (0, 2, 1))
|
||||
@@ -176,6 +181,7 @@ class Convolution1D(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim,
|
||||
'input_length': self.input_length}
|
||||
base_config = super(Convolution1D, self).get_config()
|
||||
@@ -232,6 +238,10 @@ class Convolution2D(Layer):
|
||||
applied to the bias.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
@@ -248,9 +258,10 @@ class Convolution2D(Layer):
|
||||
'''
|
||||
def __init__(self, nb_filter, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1), dim_ordering='th',
|
||||
border_mode='valid', subsample=(1, 1), dim_ordering=K.image_dim_ordering(),
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution2D:', border_mode)
|
||||
@@ -272,6 +283,7 @@ class Convolution2D(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.input_spec = [InputSpec(ndim=4)]
|
||||
self.initial_weights = weights
|
||||
super(Convolution2D, self).__init__(**kwargs)
|
||||
@@ -286,15 +298,18 @@ class Convolution2D(Layer):
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
self.regularizers = []
|
||||
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -305,7 +320,7 @@ class Convolution2D(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -335,16 +350,17 @@ class Convolution2D(Layer):
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
conv_out = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
filter_shape=self.W_shape)
|
||||
if self.dim_ordering == 'th':
|
||||
output = conv_out + K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
elif self.dim_ordering == 'tf':
|
||||
output = conv_out + K.reshape(self.b, (1, 1, 1, self.nb_filter))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
output = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
filter_shape=self.W_shape)
|
||||
if self.bias:
|
||||
if self.dim_ordering == 'th':
|
||||
output += K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
elif self.dim_ordering == 'tf':
|
||||
output += K.reshape(self.b, (1, 1, 1, self.nb_filter))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
@@ -361,7 +377,8 @@ class Convolution2D(Layer):
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None}
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias}
|
||||
base_config = super(Convolution2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -407,6 +424,10 @@ class Convolution3D(Layer):
|
||||
applied to the bias.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 4.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
|
||||
# Input shape
|
||||
5D tensor with shape:
|
||||
@@ -424,9 +445,10 @@ class Convolution3D(Layer):
|
||||
|
||||
def __init__(self, nb_filter, kernel_dim1, kernel_dim2, kernel_dim3,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1, 1), dim_ordering='th',
|
||||
border_mode='valid', subsample=(1, 1, 1), dim_ordering=K.image_dim_ordering(),
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception(self.__class__.__name__ +
|
||||
' is currently only working with Theano backend.')
|
||||
@@ -451,6 +473,7 @@ class Convolution3D(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.input_spec = [InputSpec(ndim=5)]
|
||||
self.initial_weights = weights
|
||||
super(Convolution3D, self).__init__(**kwargs)
|
||||
@@ -471,15 +494,18 @@ class Convolution3D(Layer):
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -490,7 +516,7 @@ class Convolution3D(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -525,36 +551,37 @@ class Convolution3D(Layer):
|
||||
|
||||
def call(self, x, mask=None):
|
||||
input_shape = self.input_spec[0].shape
|
||||
conv_out = K.conv3d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
volume_shape=input_shape,
|
||||
filter_shape=self.W_shape)
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
output = conv_out + K.reshape(self.b, (1, self.nb_filter, 1, 1, 1))
|
||||
elif self.dim_ordering == 'tf':
|
||||
output = conv_out + K.reshape(self.b, (1, 1, 1, 1, self.nb_filter))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
output = K.conv3d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
volume_shape=input_shape,
|
||||
filter_shape=self.W_shape)
|
||||
if self.bias:
|
||||
if self.dim_ordering == 'th':
|
||||
output += K.reshape(self.b, (1, self.nb_filter, 1, 1, 1))
|
||||
elif self.dim_ordering == 'tf':
|
||||
output += K.reshape(self.b, (1, 1, 1, 1, self.nb_filter))
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {"nb_filter": self.nb_filter,
|
||||
"kernel_dim1": self.kernel_dim1,
|
||||
"kernel_dim2": self.kernel_dim2,
|
||||
"kernel_dim3": self.kernel_dim3,
|
||||
"dim_ordering": self.dim_ordering,
|
||||
"init": self.init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"border_mode": self.border_mode,
|
||||
"subsample": self.subsample,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"activity_regularizer": self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
"W_constraint": self.W_constraint.get_config() if self.W_constraint else None,
|
||||
"b_constraint": self.b_constraint.get_config() if self.b_constraint else None}
|
||||
config = {'nb_filter': self.nb_filter,
|
||||
'kernel_dim1': self.kernel_dim1,
|
||||
'kernel_dim2': self.kernel_dim2,
|
||||
'kernel_dim3': self.kernel_dim3,
|
||||
'dim_ordering': self.dim_ordering,
|
||||
'init': self.init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'border_mode': self.border_mode,
|
||||
'subsample': self.subsample,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias}
|
||||
base_config = super(Convolution3D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -665,7 +692,7 @@ class _Pooling2D(Layer):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(_Pooling2D, self).__init__(**kwargs)
|
||||
self.pool_size = tuple(pool_size)
|
||||
if strides is None:
|
||||
@@ -731,6 +758,9 @@ class MaxPooling2D(_Pooling2D):
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
@@ -746,7 +776,7 @@ class MaxPooling2D(_Pooling2D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(MaxPooling2D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
@@ -769,6 +799,9 @@ class AveragePooling2D(_Pooling2D):
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
@@ -784,7 +817,7 @@ class AveragePooling2D(_Pooling2D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(AveragePooling2D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
@@ -800,7 +833,7 @@ class _Pooling3D(Layer):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(_Pooling3D, self).__init__(**kwargs)
|
||||
self.pool_size = tuple(pool_size)
|
||||
if strides is None:
|
||||
@@ -871,6 +904,9 @@ class MaxPooling3D(_Pooling3D):
|
||||
border_mode: 'valid' or 'same'.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 4.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
5D tensor with shape:
|
||||
@@ -886,7 +922,7 @@ class MaxPooling3D(_Pooling3D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception(self.__class__.__name__ +
|
||||
' is currently only working with Theano backend.')
|
||||
@@ -913,6 +949,9 @@ class AveragePooling3D(_Pooling3D):
|
||||
border_mode: 'valid' or 'same'.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 4.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
5D tensor with shape:
|
||||
@@ -928,7 +967,7 @@ class AveragePooling3D(_Pooling3D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering='th', **kwargs):
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception(self.__class__.__name__ +
|
||||
' is currently only working with Theano backend.')
|
||||
@@ -982,6 +1021,9 @@ class UpSampling2D(Layer):
|
||||
dim_ordering: 'th' or 'tf'.
|
||||
In 'th' mode, the channels dimension (the depth)
|
||||
is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
@@ -996,7 +1038,7 @@ class UpSampling2D(Layer):
|
||||
`(samples, upsampled_rows, upsampled_cols, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, size=(2, 2), dim_ordering='th', **kwargs):
|
||||
def __init__(self, size=(2, 2), dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
self.size = tuple(size)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
@@ -1038,6 +1080,9 @@ class UpSampling3D(Layer):
|
||||
dim_ordering: 'th' or 'tf'.
|
||||
In 'th' mode, the channels dimension (the depth)
|
||||
is at index 1, in 'tf' mode is it at index 4.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
5D tensor with shape:
|
||||
@@ -1052,7 +1097,7 @@ class UpSampling3D(Layer):
|
||||
`(samples, upsampled_dim1, upsampled_dim2, upsampled_dim3, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, size=(2, 2, 2), dim_ordering='th', **kwargs):
|
||||
def __init__(self, size=(2, 2, 2), dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception(self.__class__.__name__ +
|
||||
' is currently only working with Theano backend.')
|
||||
@@ -1130,6 +1175,12 @@ class ZeroPadding2D(Layer):
|
||||
padding: tuple of int (length 2)
|
||||
How many zeros to add at the beginning and end of
|
||||
the 2 padding dimensions (axis 3 and 4).
|
||||
dim_ordering: 'th' or 'tf'.
|
||||
In 'th' mode, the channels dimension (the depth)
|
||||
is at index 1, in 'tf' mode is it at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
4D tensor with shape:
|
||||
@@ -1140,7 +1191,7 @@ class ZeroPadding2D(Layer):
|
||||
(samples, depth, first_padded_axis, second_padded_axis)
|
||||
'''
|
||||
|
||||
def __init__(self, padding=(1, 1), dim_ordering='th', **kwargs):
|
||||
def __init__(self, padding=(1, 1), dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
super(ZeroPadding2D, self).__init__(**kwargs)
|
||||
self.padding = tuple(padding)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
@@ -1184,6 +1235,12 @@ class ZeroPadding3D(Layer):
|
||||
padding: tuple of int (length 3)
|
||||
How many zeros to add at the beginning and end of
|
||||
the 3 padding dimensions (axis 3, 4 and 5).
|
||||
dim_ordering: 'th' or 'tf'.
|
||||
In 'th' mode, the channels dimension (the depth)
|
||||
is at index 1, in 'tf' mode is it at index 4.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
|
||||
# Input shape
|
||||
5D tensor with shape:
|
||||
@@ -1194,7 +1251,7 @@ class ZeroPadding3D(Layer):
|
||||
(samples, depth, first_padded_axis, second_padded_axis, third_axis_to_pad)
|
||||
'''
|
||||
|
||||
def __init__(self, padding=(1, 1, 1), dim_ordering='th', **kwargs):
|
||||
def __init__(self, padding=(1, 1, 1), dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
if K._BACKEND != 'theano':
|
||||
raise Exception(self.__class__.__name__ +
|
||||
' is currently only working with Theano backend.')
|
||||
|
||||
+65
-41
@@ -550,12 +550,10 @@ class Dense(Layer):
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
input_dim: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
bias: boolean
|
||||
Default True;
|
||||
Setting it to False will remove the bias (b) from all calculations.
|
||||
|
||||
# Input shape
|
||||
2D tensor with shape: `(nb_samples, input_dim)`.
|
||||
@@ -565,7 +563,8 @@ class Dense(Layer):
|
||||
'''
|
||||
def __init__(self, output_dim, init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, bias=True, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, **kwargs):
|
||||
self.init = initializations.get(init)
|
||||
self.activation = activations.get(activation)
|
||||
self.output_dim = output_dim
|
||||
@@ -606,7 +605,7 @@ class Dense(Layer):
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer and self.bias:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -617,7 +616,7 @@ class Dense(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint and self.bias:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -643,8 +642,8 @@ class Dense(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'input_dim': self.input_dim,
|
||||
'bias': self.bias}
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim}
|
||||
base_config = super(Dense, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -670,10 +669,10 @@ class ActivityRegularization(Layer):
|
||||
self.l1 = l1
|
||||
self.l2 = l2
|
||||
|
||||
super(ActivityRegularization, self).__init__(**kwargs)
|
||||
activity_regularizer = ActivityRegularizer(l1=l1, l2=l2)
|
||||
activity_regularizer.set_layer(self)
|
||||
self.regularizers = [activity_regularizer]
|
||||
super(ActivityRegularization, self).__init__(**kwargs)
|
||||
|
||||
def get_config(self):
|
||||
config = {'l1': self.l1,
|
||||
@@ -703,11 +702,6 @@ class MaxoutDense(Layer):
|
||||
or alternatively, Theano function to use for weights
|
||||
initialization. This parameter is only relevant
|
||||
if you don't pass a `weights` argument.
|
||||
activation: name of activation function to use
|
||||
(see [activations](../activations.md)),
|
||||
or alternatively, elementwise Theano function.
|
||||
If you don't specify anything, no activation is applied
|
||||
(ie. "linear" activation: a(x) = x).
|
||||
weights: list of numpy arrays to set as initial weights.
|
||||
The list should have 2 elements, of shape `(input_dim, output_dim)`
|
||||
and (output_dim,) for weights and biases respectively.
|
||||
@@ -721,6 +715,7 @@ class MaxoutDense(Layer):
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
input_dim: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
@@ -737,7 +732,8 @@ class MaxoutDense(Layer):
|
||||
def __init__(self, output_dim, nb_feature=4,
|
||||
init='glorot_uniform', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, **kwargs):
|
||||
self.output_dim = output_dim
|
||||
self.nb_feature = nb_feature
|
||||
self.init = initializations.get(init)
|
||||
@@ -749,6 +745,7 @@ class MaxoutDense(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.initial_weights = weights
|
||||
self.input_spec = [InputSpec(ndim=2)]
|
||||
|
||||
@@ -764,17 +761,19 @@ class MaxoutDense(Layer):
|
||||
|
||||
self.W = self.init((self.nb_feature, input_dim, self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.nb_feature, self.output_dim),
|
||||
name='{}_b'.format(self.name))
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_feature, self.output_dim),
|
||||
name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
else:
|
||||
self.trainable_weights = [self.W]
|
||||
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -785,7 +784,7 @@ class MaxoutDense(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -798,7 +797,10 @@ class MaxoutDense(Layer):
|
||||
|
||||
def call(self, x, mask=None):
|
||||
# no activation, this layer is only linear.
|
||||
output = K.max(K.dot(x, self.W) + self.b, axis=1)
|
||||
output = K.dot(x, self.W)
|
||||
if self.bias:
|
||||
output += self.b
|
||||
output = K.max(output, axis=1)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
@@ -810,6 +812,7 @@ class MaxoutDense(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim}
|
||||
base_config = super(MaxoutDense, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
@@ -844,6 +847,7 @@ class Highway(Layer):
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
input_dim: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
@@ -860,7 +864,8 @@ class Highway(Layer):
|
||||
def __init__(self, init='glorot_uniform', transform_bias=-2,
|
||||
activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None, input_dim=None, **kwargs):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, **kwargs):
|
||||
self.init = initializations.get(init)
|
||||
self.transform_bias = transform_bias
|
||||
self.activation = activations.get(activation)
|
||||
@@ -872,6 +877,7 @@ class Highway(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.initial_weights = weights
|
||||
self.input_spec = [InputSpec(ndim=2)]
|
||||
|
||||
@@ -890,19 +896,21 @@ class Highway(Layer):
|
||||
self.W_carry = self.init((input_dim, input_dim),
|
||||
name='{}_W_carry'.format(self.name))
|
||||
|
||||
self.b = K.zeros((input_dim,), name='{}_b'.format(self.name))
|
||||
# initialize with a vector of values `transform_bias`
|
||||
self.b_carry = K.variable(np.ones((input_dim,)) * self.transform_bias,
|
||||
name='{}_b_carry'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W, self.b, self.W_carry, self.b_carry]
|
||||
if self.bias:
|
||||
self.b = K.zeros((input_dim,), name='{}_b'.format(self.name))
|
||||
# initialize with a vector of values `transform_bias`
|
||||
self.b_carry = K.variable(np.ones((input_dim,)) * self.transform_bias,
|
||||
name='{}_b_carry'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b, self.W_carry, self.b_carry]
|
||||
else:
|
||||
self.trainable_weights = [self.W, self.W_carry]
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -913,7 +921,7 @@ class Highway(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -921,8 +929,14 @@ class Highway(Layer):
|
||||
del self.initial_weights
|
||||
|
||||
def call(self, x, mask=None):
|
||||
transform_weight = activations.sigmoid(K.dot(x, self.W_carry) + self.b_carry)
|
||||
act = self.activation(K.dot(x, self.W) + self.b)
|
||||
y = K.dot(x, self.W_carry)
|
||||
if self.bias:
|
||||
y += self.b_carry
|
||||
transform_weight = activations.sigmoid(y)
|
||||
y = K.dot(x, self.W)
|
||||
if self.bias:
|
||||
y += self.b
|
||||
act = self.activation(y)
|
||||
act *= transform_weight
|
||||
output = act + (1 - transform_weight) * x
|
||||
return output
|
||||
@@ -936,6 +950,7 @@ class Highway(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim}
|
||||
base_config = super(Highway, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
@@ -952,8 +967,10 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape `(nb_sample, time_dimension, input_dim)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape `(nb_sample, time_dimension, output_dim)`.
|
||||
|
||||
# Arguments
|
||||
output_dim: int > 0.
|
||||
init: name of initialization function for the weights of the layer
|
||||
@@ -979,16 +996,19 @@ class TimeDistributedDense(Layer):
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
bias: whether to include a bias (i.e. make the layer affine rather than linear).
|
||||
input_dim: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
input_length: length of inputs sequences
|
||||
(integer, or None for variable-length sequences).
|
||||
'''
|
||||
|
||||
def __init__(self, output_dim,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
input_dim=None, input_length=None, **kwargs):
|
||||
bias=True, input_dim=None, input_length=None, **kwargs):
|
||||
warnings.warn('TimeDistributedDense is deprecated, '
|
||||
'please use TimeDistributed(Dense(...)) instead.')
|
||||
self.output_dim = output_dim
|
||||
@@ -1002,6 +1022,7 @@ class TimeDistributedDense(Layer):
|
||||
self.W_constraint = constraints.get(W_constraint)
|
||||
self.b_constraint = constraints.get(b_constraint)
|
||||
|
||||
self.bias = bias
|
||||
self.initial_weights = weights
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
self.supports_masking = True
|
||||
@@ -1019,17 +1040,17 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
self.W = self.init((input_dim, self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.b = K.zeros((self.output_dim,),
|
||||
name='{}_b'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.output_dim,),
|
||||
name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.b]
|
||||
self.regularizers = []
|
||||
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
|
||||
if self.b_regularizer:
|
||||
if self.bias and self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
@@ -1040,7 +1061,7 @@ class TimeDistributedDense(Layer):
|
||||
self.constraints = {}
|
||||
if self.W_constraint:
|
||||
self.constraints[self.W] = self.W_constraint
|
||||
if self.b_constraint:
|
||||
if self.bias and self.b_constraint:
|
||||
self.constraints[self.b] = self.b_constraint
|
||||
|
||||
if self.initial_weights is not None:
|
||||
@@ -1070,7 +1091,9 @@ class TimeDistributedDense(Layer):
|
||||
|
||||
# Squash samples and timesteps into a single axis
|
||||
x = K.reshape(x, (-1, input_shape[-1])) # (samples * timesteps, input_dim)
|
||||
y = K.dot(x, self.W) + self.b # (samples * timesteps, output_dim)
|
||||
y = K.dot(x, self.W) # (samples * timesteps, output_dim)
|
||||
if self.bias:
|
||||
y += self.b
|
||||
# We have to reshape Y to (samples, timesteps, output_dim)
|
||||
y = K.reshape(y, (-1, input_length, self.output_dim)) # (samples, timesteps, output_dim)
|
||||
y = self.activation(y)
|
||||
@@ -1085,6 +1108,7 @@ class TimeDistributedDense(Layer):
|
||||
'activity_regularizer': self.activity_regularizer.get_config() if self.activity_regularizer else None,
|
||||
'W_constraint': self.W_constraint.get_config() if self.W_constraint else None,
|
||||
'b_constraint': self.b_constraint.get_config() if self.b_constraint else None,
|
||||
'bias': self.bias,
|
||||
'input_dim': self.input_dim,
|
||||
'input_length': self.input_length}
|
||||
base_config = super(TimeDistributedDense, self).get_config()
|
||||
|
||||
@@ -17,7 +17,7 @@ class Embedding(Layer):
|
||||
model = Sequential()
|
||||
model.add(Embedding(1000, 64, input_length=10))
|
||||
# the model will take as input an integer matrix of size (batch, input_length).
|
||||
# the largest integer (i.e. word index) in the input should be no larger than 1000 (vocabulary size).
|
||||
# the largest integer (i.e. word index) in the input should be no larger than 999 (vocabulary size).
|
||||
# now model.output_shape == (None, 10, 64), where None is the batch dimension.
|
||||
|
||||
input_array = np.random.randint(1000, size=(32, 10))
|
||||
@@ -28,7 +28,7 @@ class Embedding(Layer):
|
||||
```
|
||||
|
||||
# Arguments
|
||||
input_dim: int >= 0. Size of the vocabulary, ie.
|
||||
input_dim: int > 0. Size of the vocabulary, ie.
|
||||
1 + maximum integer index occurring in the input data.
|
||||
output_dim: int >= 0. Dimension of the dense embedding.
|
||||
init: name of initialization function for the weights
|
||||
@@ -46,6 +46,8 @@ class Embedding(Layer):
|
||||
This is useful for [recurrent layers](recurrent.md) which may take
|
||||
variable length input. If this is `True` then all subsequent layers
|
||||
in the model need to support masking or an exception will be raised.
|
||||
If mask_zero is set to True, as a consequence, index 0 cannot be
|
||||
used in the vocabulary (input_dim should equal |vocabulary| + 2).
|
||||
input_length: Length of input sequences, when it is constant.
|
||||
This argument is required if you are going to connect
|
||||
`Flatten` then `Dense` layers upstream
|
||||
|
||||
@@ -19,7 +19,13 @@ class BatchNormalization(Layer):
|
||||
using Theano conventions (samples, channels, rows, cols)
|
||||
then you should set `axis` to `1` to normalize along
|
||||
the channels axis.
|
||||
During training we use per-batch statistics to normalize
|
||||
the data, and during testing we use running averages
|
||||
computed during the training phase.
|
||||
- 1: sample-wise normalization. This mode assumes a 2D input.
|
||||
- 2: feature-wise normalization, like mode 0, but
|
||||
using per-batch statistics to normalize the data during both
|
||||
testing and training.
|
||||
axis: integer, axis along which to normalize in mode 0. For instance,
|
||||
if your input tensor has shape (samples, channels, rows, cols),
|
||||
set axis to 1 to normalize per feature map (channels axis).
|
||||
@@ -47,7 +53,7 @@ class BatchNormalization(Layer):
|
||||
Same shape as input.
|
||||
|
||||
# References
|
||||
- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](http://arxiv.org/pdf/1502.03167v3.pdf)
|
||||
- [Batch Normalization: Accelerating Deep Network Training by Reducing Internal Covariate Shift](http://jmlr.org/proceedings/papers/v37/ioffe15.html)
|
||||
'''
|
||||
def __init__(self, epsilon=1e-6, mode=0, axis=-1, momentum=0.9,
|
||||
weights=None, beta_init='zero', gamma_init='one', **kwargs):
|
||||
@@ -58,7 +64,8 @@ class BatchNormalization(Layer):
|
||||
self.axis = axis
|
||||
self.momentum = momentum
|
||||
self.initial_weights = weights
|
||||
self.uses_learning_phase = True
|
||||
if self.mode == 0:
|
||||
self.uses_learning_phase = True
|
||||
super(BatchNormalization, self).__init__(**kwargs)
|
||||
|
||||
def build(self, input_shape):
|
||||
@@ -78,9 +85,12 @@ class BatchNormalization(Layer):
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
self.built = True
|
||||
self.called_with = None
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if self.mode == 0:
|
||||
if self.mode == 0 or self.mode == 2:
|
||||
assert self.built, 'Layer must be built before being called'
|
||||
input_shape = self.input_spec[0].shape
|
||||
|
||||
reduction_axes = list(range(len(input_shape)))
|
||||
@@ -94,20 +104,37 @@ class BatchNormalization(Layer):
|
||||
std = K.mean(K.square(x - brodcast_mean) + self.epsilon, axis=reduction_axes)
|
||||
std = K.sqrt(std)
|
||||
brodcast_std = K.reshape(std, broadcast_shape)
|
||||
mean_update = self.momentum * self.running_mean + (1-self.momentum) * mean
|
||||
std_update = self.momentum * self.running_std + (1-self.momentum) * std
|
||||
self.updates = [(self.running_mean, mean_update),
|
||||
(self.running_std, std_update)]
|
||||
x_normed = (x - brodcast_mean) / (brodcast_std + self.epsilon)
|
||||
mean_update = self.momentum * self.running_mean + (1 - self.momentum) * mean
|
||||
std_update = self.momentum * self.running_std + (1 - self.momentum) * std
|
||||
|
||||
# case: test mode (uses running averages)
|
||||
brodcast_running_mean = K.reshape(self.running_mean, broadcast_shape)
|
||||
brodcast_running_std = K.reshape(self.running_std, broadcast_shape)
|
||||
x_normed_running = ((x - brodcast_running_mean) / (brodcast_running_std + self.epsilon))
|
||||
if self.mode == 2:
|
||||
x_normed = (x - brodcast_mean) / (brodcast_std + self.epsilon)
|
||||
out = K.reshape(self.gamma, broadcast_shape) * x_normed + K.reshape(self.beta, broadcast_shape)
|
||||
else:
|
||||
# mode 0
|
||||
if self.called_with not in {None, x}:
|
||||
raise Exception('You are attempting to share a '
|
||||
'same `BatchNormalization` layer across '
|
||||
'different data flows. '
|
||||
'This is not possible. '
|
||||
'You should use `mode=2` in '
|
||||
'`BatchNormalization`, which has '
|
||||
'a similar behavior but is shareable '
|
||||
'(see docs for a description of '
|
||||
'the behavior).')
|
||||
self.called_with = x
|
||||
self.updates = [(self.running_mean, mean_update),
|
||||
(self.running_std, std_update)]
|
||||
x_normed = (x - brodcast_mean) / (brodcast_std + self.epsilon)
|
||||
|
||||
# pick the normalized form of x corresponding to the training phase
|
||||
x_normed = K.in_train_phase(x_normed, x_normed_running)
|
||||
out = K.reshape(self.gamma, broadcast_shape) * x_normed + K.reshape(self.beta, broadcast_shape)
|
||||
# case: test mode (uses running averages)
|
||||
brodcast_running_mean = K.reshape(self.running_mean, broadcast_shape)
|
||||
brodcast_running_std = K.reshape(self.running_std, broadcast_shape)
|
||||
x_normed_running = ((x - brodcast_running_mean) / (brodcast_running_std + self.epsilon))
|
||||
|
||||
# pick the normalized form of x corresponding to the training phase
|
||||
x_normed = K.in_train_phase(x_normed, x_normed_running)
|
||||
out = K.reshape(self.gamma, broadcast_shape) * x_normed + K.reshape(self.beta, broadcast_shape)
|
||||
|
||||
elif self.mode == 1:
|
||||
# sample-wise normalization
|
||||
|
||||
+196
-137
@@ -81,12 +81,18 @@ class Recurrent(Layer):
|
||||
is always unrolled, so this argument does not do anything.
|
||||
Unrolling can speed-up a RNN, although it tends to be more memory-intensive.
|
||||
Unrolling is only suitable for short sequences.
|
||||
consume_less: one of "cpu", "mem". If set to "cpu", the RNN will use
|
||||
consume_less: one of "cpu", "mem", or "gpu" (LSTM/GRU only).
|
||||
If set to "cpu", the RNN will use
|
||||
an implementation that uses fewer, larger matrix products,
|
||||
thus running faster (at least on CPU) but consuming more memory.
|
||||
thus running faster on CPU but consuming more memory.
|
||||
If set to "mem", the RNN will use more matrix products,
|
||||
but smaller ones, thus running slower (may actually be faster on GPU)
|
||||
while consuming less memory.
|
||||
If set to "gpu" (LSTM/GRU only), the RNN will combine the input gate,
|
||||
the forget gate and the output gate into a single matrix,
|
||||
enabling more time-efficient parallelization on the GPU. Note: RNN
|
||||
dropout must be shared for all gates, resulting in a slightly
|
||||
reduced regularization.
|
||||
input_dim: dimensionality of the input (integer).
|
||||
This argument (or alternatively, the keyword argument `input_shape`)
|
||||
is required when using this layer as the first layer in a model.
|
||||
@@ -383,15 +389,15 @@ class SimpleRNN(Recurrent):
|
||||
return constants
|
||||
|
||||
def get_config(self):
|
||||
config = {"output_dim": self.output_dim,
|
||||
"init": self.init.__name__,
|
||||
"inner_init": self.inner_init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"dropout_W": self.dropout_W,
|
||||
"dropout_U": self.dropout_U}
|
||||
config = {'output_dim': self.output_dim,
|
||||
'init': self.init.__name__,
|
||||
'inner_init': self.inner_init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'U_regularizer': self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'dropout_W': self.dropout_W,
|
||||
'dropout_U': self.dropout_U}
|
||||
base_config = super(SimpleRNN, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -444,53 +450,66 @@ class GRU(Recurrent):
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
input_dim = input_shape[2]
|
||||
self.input_dim = input_dim
|
||||
self.input_dim = input_shape[2]
|
||||
|
||||
self.W_z = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_z'.format(self.name))
|
||||
self.U_z = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_z'.format(self.name))
|
||||
self.b_z = K.zeros((self.output_dim,), name='{}_b_z'.format(self.name))
|
||||
|
||||
self.W_r = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_r'.format(self.name))
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_r'.format(self.name))
|
||||
self.b_r = K.zeros((self.output_dim,), name='{}_b_r'.format(self.name))
|
||||
|
||||
self.W_h = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_h'.format(self.name))
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_h'.format(self.name))
|
||||
self.b_h = K.zeros((self.output_dim,), name='{}_b_h'.format(self.name))
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(K.concatenate([self.W_z,
|
||||
self.W_r,
|
||||
self.W_h]))
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.U_regularizer:
|
||||
self.U_regularizer.set_param(K.concatenate([self.U_z,
|
||||
self.U_r,
|
||||
self.U_h]))
|
||||
self.regularizers.append(self.U_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(K.concatenate([self.b_z,
|
||||
self.b_r,
|
||||
self.b_h]))
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.trainable_weights = [self.W_z, self.U_z, self.b_z,
|
||||
self.W_r, self.U_r, self.b_r,
|
||||
self.W_h, self.U_h, self.b_h]
|
||||
if self.stateful:
|
||||
self.reset_states()
|
||||
else:
|
||||
# initial states: all-zero tensor of shape (output_dim)
|
||||
self.states = [None]
|
||||
|
||||
if self.consume_less == 'gpu':
|
||||
|
||||
self.W = self.init((self.input_dim, 3 * self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.U = self.inner_init((self.output_dim, 3 * self.output_dim),
|
||||
name='{}_U'.format(self.name))
|
||||
|
||||
self.b = K.variable(np.hstack((np.zeros(self.output_dim),
|
||||
np.zeros(self.output_dim),
|
||||
np.zeros(self.output_dim))),
|
||||
name='{}_b'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W, self.U, self.b]
|
||||
else:
|
||||
|
||||
self.W_z = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_z'.format(self.name))
|
||||
self.U_z = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_z'.format(self.name))
|
||||
self.b_z = K.zeros((self.output_dim,), name='{}_b_z'.format(self.name))
|
||||
|
||||
self.W_r = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_r'.format(self.name))
|
||||
self.U_r = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_r'.format(self.name))
|
||||
self.b_r = K.zeros((self.output_dim,), name='{}_b_r'.format(self.name))
|
||||
|
||||
self.W_h = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_h'.format(self.name))
|
||||
self.U_h = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_h'.format(self.name))
|
||||
self.b_h = K.zeros((self.output_dim,), name='{}_b_h'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W_z, self.U_z, self.b_z,
|
||||
self.W_r, self.U_r, self.b_r,
|
||||
self.W_h, self.U_h, self.b_h]
|
||||
|
||||
self.W = K.concatenate([self.W_z, self.W_r, self.W_h])
|
||||
self.U = K.concatenate([self.U_z, self.U_r, self.U_h])
|
||||
self.b = K.concatenate([self.b_z, self.b_r, self.b_h])
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.U_regularizer:
|
||||
self.U_regularizer.set_param(self.U)
|
||||
self.regularizers.append(self.U_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
@@ -528,19 +547,37 @@ class GRU(Recurrent):
|
||||
B_U = states[1] # dropout matrices for recurrent units
|
||||
B_W = states[2]
|
||||
|
||||
if self.consume_less == 'cpu':
|
||||
x_z = x[:, :self.output_dim]
|
||||
x_r = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_h = x[:, 2 * self.output_dim:]
|
||||
if self.consume_less == 'gpu':
|
||||
|
||||
matrix_x = K.dot(x * B_W[0], self.W) + self.b
|
||||
matrix_inner = K.dot(h_tm1 * B_U[0], self.U[:, :2 * self.output_dim])
|
||||
|
||||
x_z = matrix_x[:, :self.output_dim]
|
||||
x_r = matrix_x[:, self.output_dim: 2 * self.output_dim]
|
||||
inner_z = matrix_inner[:, :self.output_dim]
|
||||
inner_r = matrix_inner[:, self.output_dim: 2 * self.output_dim]
|
||||
|
||||
z = self.inner_activation(x_z + inner_z)
|
||||
r = self.inner_activation(x_r + inner_r)
|
||||
|
||||
x_h = matrix_x[:, 2 * self.output_dim:]
|
||||
inner_h = K.dot(r * h_tm1 * B_U[0], self.U[:, 2 * self.output_dim:])
|
||||
hh = self.activation(x_h + inner_h)
|
||||
else:
|
||||
x_z = K.dot(x * B_W[0], self.W_z) + self.b_z
|
||||
x_r = K.dot(x * B_W[1], self.W_r) + self.b_r
|
||||
x_h = K.dot(x * B_W[2], self.W_h) + self.b_h
|
||||
if self.consume_less == 'cpu':
|
||||
x_z = x[:, :self.output_dim]
|
||||
x_r = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_h = x[:, 2 * self.output_dim:]
|
||||
elif self.consume_less == 'mem':
|
||||
x_z = K.dot(x * B_W[0], self.W_z) + self.b_z
|
||||
x_r = K.dot(x * B_W[1], self.W_r) + self.b_r
|
||||
x_h = K.dot(x * B_W[2], self.W_h) + self.b_h
|
||||
else:
|
||||
raise Exception('Unknown `consume_less` mode.')
|
||||
z = self.inner_activation(x_z + K.dot(h_tm1 * B_U[0], self.U_z))
|
||||
r = self.inner_activation(x_r + K.dot(h_tm1 * B_U[1], self.U_r))
|
||||
|
||||
z = self.inner_activation(x_z + K.dot(h_tm1 * B_U[0], self.U_z))
|
||||
r = self.inner_activation(x_r + K.dot(h_tm1 * B_U[1], self.U_r))
|
||||
|
||||
hh = self.activation(x_h + K.dot(r * h_tm1 * B_U[2], self.U_h))
|
||||
hh = self.activation(x_h + K.dot(r * h_tm1 * B_U[2], self.U_h))
|
||||
h = z * h_tm1 + (1 - z) * hh
|
||||
return h, [h]
|
||||
|
||||
@@ -566,16 +603,16 @@ class GRU(Recurrent):
|
||||
return constants
|
||||
|
||||
def get_config(self):
|
||||
config = {"output_dim": self.output_dim,
|
||||
"init": self.init.__name__,
|
||||
"inner_init": self.inner_init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"inner_activation": self.inner_activation.__name__,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"dropout_W": self.dropout_W,
|
||||
"dropout_U": self.dropout_U}
|
||||
config = {'output_dim': self.output_dim,
|
||||
'init': self.init.__name__,
|
||||
'inner_init': self.inner_init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'inner_activation': self.inner_activation.__name__,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'U_regularizer': self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'dropout_W': self.dropout_W,
|
||||
'dropout_U': self.dropout_U}
|
||||
base_config = super(GRU, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -637,8 +674,7 @@ class LSTM(Recurrent):
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
input_dim = input_shape[2]
|
||||
self.input_dim = input_dim
|
||||
self.input_dim = input_shape[2]
|
||||
|
||||
if self.stateful:
|
||||
self.reset_states()
|
||||
@@ -646,56 +682,64 @@ class LSTM(Recurrent):
|
||||
# initial states: 2 all-zero tensors of shape (output_dim)
|
||||
self.states = [None, None]
|
||||
|
||||
self.W_i = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_i'.format(self.name))
|
||||
self.U_i = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_i'.format(self.name))
|
||||
self.b_i = K.zeros((self.output_dim,), name='{}_b_i'.format(self.name))
|
||||
if self.consume_less == 'gpu':
|
||||
self.W = self.init((self.input_dim, 4 * self.output_dim),
|
||||
name='{}_W'.format(self.name))
|
||||
self.U = self.inner_init((self.output_dim, 4 * self.output_dim),
|
||||
name='{}_U'.format(self.name))
|
||||
|
||||
self.W_f = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_f'.format(self.name))
|
||||
self.U_f = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_f'.format(self.name))
|
||||
self.b_f = self.forget_bias_init((self.output_dim,),
|
||||
name='{}_b_f'.format(self.name))
|
||||
self.b = K.variable(np.hstack((np.zeros(self.output_dim),
|
||||
K.get_value(self.forget_bias_init(self.output_dim)),
|
||||
np.zeros(self.output_dim),
|
||||
np.zeros(self.output_dim))),
|
||||
name='{}_b'.format(self.name))
|
||||
self.trainable_weights = [self.W, self.U, self.b]
|
||||
else:
|
||||
self.W_i = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_i'.format(self.name))
|
||||
self.U_i = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_i'.format(self.name))
|
||||
self.b_i = K.zeros((self.output_dim,), name='{}_b_i'.format(self.name))
|
||||
|
||||
self.W_c = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_c'.format(self.name))
|
||||
self.U_c = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_c'.format(self.name))
|
||||
self.b_c = K.zeros((self.output_dim,), name='{}_b_c'.format(self.name))
|
||||
self.W_f = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_f'.format(self.name))
|
||||
self.U_f = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_f'.format(self.name))
|
||||
self.b_f = self.forget_bias_init((self.output_dim,),
|
||||
name='{}_b_f'.format(self.name))
|
||||
|
||||
self.W_o = self.init((input_dim, self.output_dim),
|
||||
name='{}_W_o'.format(self.name))
|
||||
self.U_o = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_o'.format(self.name))
|
||||
self.b_o = K.zeros((self.output_dim,), name='{}_b_o'.format(self.name))
|
||||
self.W_c = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_c'.format(self.name))
|
||||
self.U_c = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_c'.format(self.name))
|
||||
self.b_c = K.zeros((self.output_dim,), name='{}_b_c'.format(self.name))
|
||||
|
||||
self.W_o = self.init((self.input_dim, self.output_dim),
|
||||
name='{}_W_o'.format(self.name))
|
||||
self.U_o = self.inner_init((self.output_dim, self.output_dim),
|
||||
name='{}_U_o'.format(self.name))
|
||||
self.b_o = K.zeros((self.output_dim,), name='{}_b_o'.format(self.name))
|
||||
|
||||
self.trainable_weights = [self.W_i, self.U_i, self.b_i,
|
||||
self.W_c, self.U_c, self.b_c,
|
||||
self.W_f, self.U_f, self.b_f,
|
||||
self.W_o, self.U_o, self.b_o]
|
||||
|
||||
self.W = K.concatenate([self.W_i, self.W_f, self.W_c, self.W_o])
|
||||
self.U = K.concatenate([self.U_i, self.U_f, self.U_c, self.U_o])
|
||||
self.b = K.concatenate([self.b_i, self.b_f, self.b_c, self.b_o])
|
||||
|
||||
self.regularizers = []
|
||||
if self.W_regularizer:
|
||||
self.W_regularizer.set_param(K.concatenate([self.W_i,
|
||||
self.W_f,
|
||||
self.W_c,
|
||||
self.W_o]))
|
||||
self.W_regularizer.set_param(self.W)
|
||||
self.regularizers.append(self.W_regularizer)
|
||||
if self.U_regularizer:
|
||||
self.U_regularizer.set_param(K.concatenate([self.U_i,
|
||||
self.U_f,
|
||||
self.U_c,
|
||||
self.U_o]))
|
||||
self.U_regularizer.set_param(self.U)
|
||||
self.regularizers.append(self.U_regularizer)
|
||||
if self.b_regularizer:
|
||||
self.b_regularizer.set_param(K.concatenate([self.b_i,
|
||||
self.b_f,
|
||||
self.b_c,
|
||||
self.b_o]))
|
||||
self.b_regularizer.set_param(self.b)
|
||||
self.regularizers.append(self.b_regularizer)
|
||||
|
||||
self.trainable_weights = [self.W_i, self.U_i, self.b_i,
|
||||
self.W_c, self.U_c, self.b_c,
|
||||
self.W_f, self.U_f, self.b_f,
|
||||
self.W_o, self.U_o, self.b_o]
|
||||
|
||||
if self.initial_weights is not None:
|
||||
self.set_weights(self.initial_weights)
|
||||
del self.initial_weights
|
||||
@@ -743,21 +787,36 @@ class LSTM(Recurrent):
|
||||
B_U = states[2]
|
||||
B_W = states[3]
|
||||
|
||||
if self.consume_less == 'cpu':
|
||||
x_i = x[:, :self.output_dim]
|
||||
x_f = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_c = x[:, 2 * self.output_dim: 3 * self.output_dim]
|
||||
x_o = x[:, 3 * self.output_dim:]
|
||||
else:
|
||||
x_i = K.dot(x * B_W[0], self.W_i) + self.b_i
|
||||
x_f = K.dot(x * B_W[1], self.W_f) + self.b_f
|
||||
x_c = K.dot(x * B_W[2], self.W_c) + self.b_c
|
||||
x_o = K.dot(x * B_W[3], self.W_o) + self.b_o
|
||||
if self.consume_less == 'gpu':
|
||||
z = K.dot(x * B_W[0], self.W) + K.dot(h_tm1 * B_U[0], self.U) + self.b
|
||||
|
||||
i = self.inner_activation(x_i + K.dot(h_tm1 * B_U[0], self.U_i))
|
||||
f = self.inner_activation(x_f + K.dot(h_tm1 * B_U[1], self.U_f))
|
||||
c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * B_U[2], self.U_c))
|
||||
o = self.inner_activation(x_o + K.dot(h_tm1 * B_U[3], self.U_o))
|
||||
z0 = z[:, :self.output_dim]
|
||||
z1 = z[:, self.output_dim: 2 * self.output_dim]
|
||||
z2 = z[:, 2 * self.output_dim: 3 * self.output_dim]
|
||||
z3 = z[:, 3 * self.output_dim:]
|
||||
|
||||
i = self.inner_activation(z0)
|
||||
f = self.inner_activation(z1)
|
||||
c = f * c_tm1 + i * self.activation(z2)
|
||||
o = self.inner_activation(z3)
|
||||
else:
|
||||
if self.consume_less == 'cpu':
|
||||
x_i = x[:, :self.output_dim]
|
||||
x_f = x[:, self.output_dim: 2 * self.output_dim]
|
||||
x_c = x[:, 2 * self.output_dim: 3 * self.output_dim]
|
||||
x_o = x[:, 3 * self.output_dim:]
|
||||
elif self.consume_less == 'mem':
|
||||
x_i = K.dot(x * B_W[0], self.W_i) + self.b_i
|
||||
x_f = K.dot(x * B_W[1], self.W_f) + self.b_f
|
||||
x_c = K.dot(x * B_W[2], self.W_c) + self.b_c
|
||||
x_o = K.dot(x * B_W[3], self.W_o) + self.b_o
|
||||
else:
|
||||
raise Exception('Unknown `consume_less` mode.')
|
||||
|
||||
i = self.inner_activation(x_i + K.dot(h_tm1 * B_U[0], self.U_i))
|
||||
f = self.inner_activation(x_f + K.dot(h_tm1 * B_U[1], self.U_f))
|
||||
c = f * c_tm1 + i * self.activation(x_c + K.dot(h_tm1 * B_U[2], self.U_c))
|
||||
o = self.inner_activation(x_o + K.dot(h_tm1 * B_U[3], self.U_o))
|
||||
|
||||
h = o * self.activation(c)
|
||||
return h, [h, c]
|
||||
@@ -784,16 +843,16 @@ class LSTM(Recurrent):
|
||||
return constants
|
||||
|
||||
def get_config(self):
|
||||
config = {"output_dim": self.output_dim,
|
||||
"init": self.init.__name__,
|
||||
"inner_init": self.inner_init.__name__,
|
||||
"forget_bias_init": self.forget_bias_init.__name__,
|
||||
"activation": self.activation.__name__,
|
||||
"inner_activation": self.inner_activation.__name__,
|
||||
"W_regularizer": self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
"U_regularizer": self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
"b_regularizer": self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
"dropout_W": self.dropout_W,
|
||||
"dropout_U": self.dropout_U}
|
||||
config = {'output_dim': self.output_dim,
|
||||
'init': self.init.__name__,
|
||||
'inner_init': self.inner_init.__name__,
|
||||
'forget_bias_init': self.forget_bias_init.__name__,
|
||||
'activation': self.activation.__name__,
|
||||
'inner_activation': self.inner_activation.__name__,
|
||||
'W_regularizer': self.W_regularizer.get_config() if self.W_regularizer else None,
|
||||
'U_regularizer': self.U_regularizer.get_config() if self.U_regularizer else None,
|
||||
'b_regularizer': self.b_regularizer.get_config() if self.b_regularizer else None,
|
||||
'dropout_W': self.dropout_W,
|
||||
'dropout_U': self.dropout_U}
|
||||
base_config = super(LSTM, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -473,6 +473,8 @@ class Graph(Model):
|
||||
x = self._get_x(data)
|
||||
output_list = super(Graph, self).predict(x, batch_size=batch_size,
|
||||
verbose=verbose)
|
||||
if not isinstance(output_list, list):
|
||||
output_list = [output_list]
|
||||
return dict(zip(self._graph_outputs, output_list))
|
||||
|
||||
def train_on_batch(self, data,
|
||||
@@ -528,6 +530,8 @@ class Graph(Model):
|
||||
|
||||
def predict_on_batch(self, data):
|
||||
output_list = super(Graph, self).predict_on_batch(data)
|
||||
if not isinstance(output_list, list):
|
||||
output_list = [output_list]
|
||||
return dict(zip(self._graph_outputs, output_list))
|
||||
|
||||
def fit_generator(self, generator, samples_per_epoch, nb_epoch,
|
||||
|
||||
+27
-10
@@ -10,6 +10,9 @@ from .legacy.models import Graph
|
||||
|
||||
def model_from_config(config, custom_objects={}):
|
||||
from keras.utils.layer_utils import layer_from_config
|
||||
if isinstance(config, list):
|
||||
raise Exception('`model_fom_config` expects a dictionary, not a list. '
|
||||
'Maybe you meant to use `Sequential.from_config(config)`?')
|
||||
return layer_from_config(config, custom_objects=custom_objects)
|
||||
|
||||
|
||||
@@ -452,12 +455,14 @@ class Sequential(Model):
|
||||
A Numpy array of predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
self.build()
|
||||
return self.model.predict(x, batch_size=batch_size, verbose=verbose)
|
||||
|
||||
def predict_on_batch(self, x):
|
||||
'''Returns predictions for a single batch of samples.
|
||||
'''
|
||||
if self.model is None:
|
||||
self.build()
|
||||
return self.model.predict_on_batch(x)
|
||||
|
||||
def train_on_batch(self, x, y, class_weight=None,
|
||||
@@ -478,6 +483,8 @@ class Sequential(Model):
|
||||
The attribute `model.metrics_names` will give you
|
||||
the display labels for the scalar outputs.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
if 'accuracy' in kwargs:
|
||||
kwargs.pop('accuracy')
|
||||
warnings.warn('The "accuracy" argument is deprecated, '
|
||||
@@ -508,6 +515,8 @@ class Sequential(Model):
|
||||
The attribute `model.metrics_names` will give you
|
||||
the display labels for the scalar outputs.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
if 'accuracy' in kwargs:
|
||||
kwargs.pop('accuracy')
|
||||
warnings.warn('The "accuracy" argument is deprecated, '
|
||||
@@ -534,8 +543,6 @@ class Sequential(Model):
|
||||
# Returns
|
||||
A Numpy array of probability predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
preds = self.predict(x, batch_size, verbose)
|
||||
if preds.min() < 0. or preds.max() > 1.:
|
||||
warnings.warn('Network returning invalid probability values. '
|
||||
@@ -557,8 +564,6 @@ class Sequential(Model):
|
||||
# Returns
|
||||
A numpy array of class predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
proba = self.predict(x, batch_size=batch_size, verbose=verbose)
|
||||
if proba.shape[-1] > 1:
|
||||
return proba.argmax(axis=-1)
|
||||
@@ -697,13 +702,13 @@ class Sequential(Model):
|
||||
A Numpy array of predictions.
|
||||
'''
|
||||
if self.model is None:
|
||||
raise Exception('The model needs to be compiled before being used.')
|
||||
self.build()
|
||||
return self.model.predict_generator(generator, val_samples,
|
||||
max_q_size=max_q_size)
|
||||
|
||||
def get_config(self):
|
||||
'''Returns the model configuration
|
||||
as a Python dictionary.
|
||||
as a Python list.
|
||||
'''
|
||||
config = []
|
||||
if self.layers[0].__class__.__name__ == 'Merge':
|
||||
@@ -725,7 +730,7 @@ class Sequential(Model):
|
||||
return copy.deepcopy(config)
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config):
|
||||
def from_config(cls, config, layer_cache={}):
|
||||
'''Supports legacy formats
|
||||
'''
|
||||
from keras.utils.layer_utils import layer_from_config
|
||||
@@ -744,8 +749,20 @@ class Sequential(Model):
|
||||
return new_config
|
||||
return conf
|
||||
|
||||
# the model we will return
|
||||
model = cls()
|
||||
|
||||
def get_or_create_layer(layer_data):
|
||||
if layer_data['class_name'] == 'Sequential':
|
||||
return Sequential.from_config(layer_data['config'],
|
||||
layer_cache=layer_cache)
|
||||
name = layer_data['config'].get('name')
|
||||
if name in layer_cache:
|
||||
return layer_cache[name]
|
||||
layer = layer_from_config(layer_data)
|
||||
layer_cache[name] = layer
|
||||
return layer
|
||||
|
||||
first_layer = config[0]
|
||||
first_layer = normalize_legacy_config(first_layer)
|
||||
if first_layer['class_name'] == 'Merge':
|
||||
@@ -758,11 +775,11 @@ class Sequential(Model):
|
||||
merge = Merge.from_config(first_layer_config)
|
||||
model.add(merge)
|
||||
else:
|
||||
layer = layer_from_config(first_layer)
|
||||
layer = get_or_create_layer(first_layer)
|
||||
model.add(layer)
|
||||
|
||||
for conf in config[1:]:
|
||||
conf = normalize_legacy_config(conf)
|
||||
layer = layer_from_config(conf)
|
||||
layer = get_or_create_layer(conf)
|
||||
model.add(layer)
|
||||
return model
|
||||
|
||||
@@ -48,6 +48,12 @@ def binary_crossentropy(y_true, y_pred):
|
||||
return K.mean(K.binary_crossentropy(y_pred, y_true), axis=-1)
|
||||
|
||||
|
||||
def kullback_leibler_divergence(y_true, y_pred):
|
||||
y_true = K.clip(y_true, K.epsilon(), 1)
|
||||
y_pred = K.clip(y_pred, K.epsilon(), 1)
|
||||
return K.sum(y_true * K.log(y_true / y_pred), axis=-1)
|
||||
|
||||
|
||||
def poisson(y_true, y_pred):
|
||||
return K.mean(y_pred - y_true * K.log(y_pred + K.epsilon()), axis=-1)
|
||||
|
||||
@@ -63,6 +69,7 @@ mse = MSE = mean_squared_error
|
||||
mae = MAE = mean_absolute_error
|
||||
mape = MAPE = mean_absolute_percentage_error
|
||||
msle = MSLE = mean_squared_logarithmic_error
|
||||
kld = KLD = kullback_leibler_divergence
|
||||
cosine = cosine_proximity
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
|
||||
+54
-38
@@ -29,6 +29,11 @@ class Optimizer(object):
|
||||
when their absolute value exceeds this value.
|
||||
'''
|
||||
def __init__(self, **kwargs):
|
||||
allowed_kwargs = {'clipnorm', 'clipvalue'}
|
||||
for k in kwargs:
|
||||
if k not in allowed_kwargs:
|
||||
raise Exception('Unexpected keyword argument '
|
||||
'passed to optimizer: ' + str(k))
|
||||
self.__dict__.update(kwargs)
|
||||
self.updates = []
|
||||
self.weights = []
|
||||
@@ -89,7 +94,12 @@ class Optimizer(object):
|
||||
return weights
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__}
|
||||
config = {'name': self.__class__.__name__}
|
||||
if hasattr(self, 'clipnorm'):
|
||||
config['clipnorm'] = self.clipnorm
|
||||
if hasattr(self, 'clipvalue'):
|
||||
config['clipvalue'] = self.clipvalue
|
||||
return config
|
||||
|
||||
|
||||
class SGD(Optimizer):
|
||||
@@ -102,8 +112,8 @@ class SGD(Optimizer):
|
||||
decay: float >= 0. Learning rate decay over each update.
|
||||
nesterov: boolean. Whether to apply Nesterov momentum.
|
||||
'''
|
||||
def __init__(self, lr=0.01, momentum=0., decay=0., nesterov=False,
|
||||
*args, **kwargs):
|
||||
def __init__(self, lr=0.01, momentum=0., decay=0.,
|
||||
nesterov=False, **kwargs):
|
||||
super(SGD, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
@@ -135,11 +145,12 @@ class SGD(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"momentum": float(K.get_value(self.momentum)),
|
||||
"decay": float(K.get_value(self.decay)),
|
||||
"nesterov": self.nesterov}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'momentum': float(K.get_value(self.momentum)),
|
||||
'decay': float(K.get_value(self.decay)),
|
||||
'nesterov': self.nesterov}
|
||||
base_config = super(SGD, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class RMSprop(Optimizer):
|
||||
@@ -157,7 +168,7 @@ class RMSprop(Optimizer):
|
||||
rho: float >= 0.
|
||||
epsilon: float >= 0. Fuzz factor.
|
||||
'''
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-6, *args, **kwargs):
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, **kwargs):
|
||||
super(RMSprop, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
@@ -173,7 +184,7 @@ class RMSprop(Optimizer):
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1. - self.rho) * K.square(g)
|
||||
self.updates.append((a, new_a))
|
||||
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
@@ -183,10 +194,11 @@ class RMSprop(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"rho": float(K.get_value(self.rho)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'rho': float(K.get_value(self.rho)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(RMSprop, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adagrad(Optimizer):
|
||||
@@ -199,7 +211,7 @@ class Adagrad(Optimizer):
|
||||
lr: float >= 0. Learning rate.
|
||||
epsilon: float >= 0.
|
||||
'''
|
||||
def __init__(self, lr=0.01, epsilon=1e-6, *args, **kwargs):
|
||||
def __init__(self, lr=0.01, epsilon=1e-8, **kwargs):
|
||||
super(Adagrad, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
@@ -213,7 +225,7 @@ class Adagrad(Optimizer):
|
||||
for p, g, a in zip(params, grads, self.weights):
|
||||
new_a = a + K.square(g) # update accumulator
|
||||
self.updates.append((a, new_a))
|
||||
new_p = p - self.lr * g / K.sqrt(new_a + self.epsilon)
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
@@ -222,9 +234,10 @@ class Adagrad(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adagrad, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adadelta(Optimizer):
|
||||
@@ -242,7 +255,7 @@ class Adadelta(Optimizer):
|
||||
# References
|
||||
- [Adadelta - an adaptive learning rate method](http://arxiv.org/abs/1212.5701)
|
||||
'''
|
||||
def __init__(self, lr=1.0, rho=0.95, epsilon=1e-6, *args, **kwargs):
|
||||
def __init__(self, lr=1.0, rho=0.95, epsilon=1e-8, **kwargs):
|
||||
super(Adadelta, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
@@ -275,10 +288,11 @@ class Adadelta(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"rho": self.rho,
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'rho': self.rho,
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adadelta, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adam(Optimizer):
|
||||
@@ -294,8 +308,8 @@ class Adam(Optimizer):
|
||||
# References
|
||||
- [Adam - A Method for Stochastic Optimization](http://arxiv.org/abs/1412.6980v8)
|
||||
'''
|
||||
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-8,
|
||||
*args, **kwargs):
|
||||
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999,
|
||||
epsilon=1e-8, **kwargs):
|
||||
super(Adam, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0)
|
||||
@@ -331,11 +345,12 @@ class Adam(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"beta_1": float(K.get_value(self.beta_1)),
|
||||
"beta_2": float(K.get_value(self.beta_2)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'beta_1': float(K.get_value(self.beta_1)),
|
||||
'beta_2': float(K.get_value(self.beta_2)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adam, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Adamax(Optimizer):
|
||||
@@ -352,8 +367,8 @@ class Adamax(Optimizer):
|
||||
# References
|
||||
- [Adam - A Method for Stochastic Optimization](http://arxiv.org/abs/1412.6980v8)
|
||||
'''
|
||||
def __init__(self, lr=0.002, beta_1=0.9, beta_2=0.999, epsilon=1e-8,
|
||||
*args, **kwargs):
|
||||
def __init__(self, lr=0.002, beta_1=0.9, beta_2=0.999,
|
||||
epsilon=1e-8, **kwargs):
|
||||
super(Adamax, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
@@ -392,11 +407,12 @@ class Adamax(Optimizer):
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
return {"name": self.__class__.__name__,
|
||||
"lr": float(K.get_value(self.lr)),
|
||||
"beta_1": float(K.get_value(self.beta_1)),
|
||||
"beta_2": float(K.get_value(self.beta_2)),
|
||||
"epsilon": self.epsilon}
|
||||
config = {'lr': float(K.get_value(self.lr)),
|
||||
'beta_1': float(K.get_value(self.beta_1)),
|
||||
'beta_2': float(K.get_value(self.beta_2)),
|
||||
'epsilon': self.epsilon}
|
||||
base_config = super(Adamax, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
# aliases
|
||||
|
||||
+245
-83
@@ -1,8 +1,9 @@
|
||||
'''Fairly basic set of tools for realtime data augmentation on image data.
|
||||
'''Fairly basic set of tools for real-time data augmentation on image data.
|
||||
Can easily be extended to include new transformations,
|
||||
new preprocessing methods, etc...
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import re
|
||||
@@ -12,6 +13,8 @@ from six.moves import range
|
||||
import os
|
||||
import threading
|
||||
|
||||
from .. import backend as K
|
||||
|
||||
|
||||
def random_rotation(x, rg, row_index=1, col_index=2, channel_index=0,
|
||||
fill_mode='nearest', cval=0.):
|
||||
@@ -115,7 +118,7 @@ def flip_axis(x, axis):
|
||||
return x
|
||||
|
||||
|
||||
def array_to_img(x, dim_ordering='th', scale=True):
|
||||
def array_to_img(x, dim_ordering=K.image_dim_ordering(), scale=True):
|
||||
from PIL import Image
|
||||
if dim_ordering == 'th':
|
||||
x = x.transpose(1, 2, 0)
|
||||
@@ -133,8 +136,7 @@ def array_to_img(x, dim_ordering='th', scale=True):
|
||||
raise Exception('Unsupported channel number: ', x.shape[2])
|
||||
|
||||
|
||||
# only used by tests/keras/preprocessing/test_image.py to convert PIL.Image to numpy array
|
||||
def img_to_array(img, dim_ordering='th'):
|
||||
def img_to_array(img, dim_ordering=K.image_dim_ordering()):
|
||||
if dim_ordering not in ['th', 'tf']:
|
||||
raise Exception('Unknown dim_ordering: ', dim_ordering)
|
||||
# image has dim_ordering (height, width, channel)
|
||||
@@ -152,13 +154,15 @@ def img_to_array(img, dim_ordering='th'):
|
||||
return x
|
||||
|
||||
|
||||
def load_img(path, grayscale=False):
|
||||
def load_img(path, grayscale=False, target_size=None):
|
||||
from PIL import Image
|
||||
img = Image.open(path)
|
||||
if grayscale:
|
||||
img = img.convert('L')
|
||||
else: # Ensure 3 channel even when loaded image is grayscale
|
||||
img = img.convert('RGB')
|
||||
if target_size:
|
||||
img = img.resize(target_size)
|
||||
return img
|
||||
|
||||
|
||||
@@ -192,8 +196,14 @@ class ImageDataGenerator(object):
|
||||
'constant'. Default is 0.
|
||||
horizontal_flip: whether to randomly flip images horizontally.
|
||||
vertical_flip: whether to randomly flip images vertically.
|
||||
rescale: rescaling factor. If None or 0, no rescaling is applied,
|
||||
otherwise we multiply the data by the value provided (before applying
|
||||
any other transformation).
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode it is at index 3.
|
||||
It defaults to the `image_dim_ordering` value found in your
|
||||
Keras config file at `~/.keras/keras.json`.
|
||||
If you never set it, then it will be "th".
|
||||
'''
|
||||
def __init__(self,
|
||||
featurewise_center=False,
|
||||
@@ -211,23 +221,24 @@ class ImageDataGenerator(object):
|
||||
cval=0.,
|
||||
horizontal_flip=False,
|
||||
vertical_flip=False,
|
||||
dim_ordering='th'):
|
||||
rescale=None,
|
||||
dim_ordering=K.image_dim_ordering()):
|
||||
self.__dict__.update(locals())
|
||||
self.mean = None
|
||||
self.std = None
|
||||
self.principal_components = None
|
||||
self.lock = threading.Lock()
|
||||
self.rescale = rescale
|
||||
|
||||
if dim_ordering not in {'tf', 'th'}:
|
||||
raise Exception('dim_ordering should be "tf" (channel after row and '
|
||||
'column) or "th" (channel before row and column). '
|
||||
'Received arg: ', dim_ordering)
|
||||
self.dim_ordering = dim_ordering
|
||||
if dim_ordering == "th":
|
||||
if dim_ordering == 'th':
|
||||
self.channel_index = 1
|
||||
self.row_index = 2
|
||||
self.col_index = 3
|
||||
if dim_ordering == "tf":
|
||||
if dim_ordering == 'tf':
|
||||
self.channel_index = 3
|
||||
self.row_index = 1
|
||||
self.col_index = 2
|
||||
@@ -241,79 +252,30 @@ class ImageDataGenerator(object):
|
||||
'a tuple or list of two floats. '
|
||||
'Received arg: ', zoom_range)
|
||||
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen = 0
|
||||
|
||||
def reset(self):
|
||||
self.batch_index = 0
|
||||
|
||||
def _flow_index(self, N, batch_size=32, shuffle=False, seed=None):
|
||||
while 1:
|
||||
index_array = np.arange(N)
|
||||
if self.batch_index == 0:
|
||||
if shuffle:
|
||||
if seed is not None:
|
||||
np.random.seed(seed + self.total_batches_seen)
|
||||
index_array = np.random.permutation(N)
|
||||
|
||||
current_index = (self.batch_index * batch_size) % N
|
||||
if N >= current_index + batch_size:
|
||||
current_batch_size = batch_size
|
||||
self.batch_index += 1
|
||||
else:
|
||||
current_batch_size = N - current_index
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen += 1
|
||||
yield (index_array[current_index: current_index + current_batch_size],
|
||||
current_index, current_batch_size)
|
||||
|
||||
def flow(self, X, y, batch_size=32, shuffle=False, seed=None,
|
||||
def flow(self, X, y=None, batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
assert len(X) == len(y)
|
||||
self.X = X
|
||||
self.y = y
|
||||
self.save_to_dir = save_to_dir
|
||||
self.save_prefix = save_prefix
|
||||
self.save_format = save_format
|
||||
self.reset()
|
||||
self.flow_generator = self._flow_index(X.shape[0], batch_size,
|
||||
shuffle, seed)
|
||||
return self
|
||||
return NumpyArrayIterator(
|
||||
X, y, self,
|
||||
batch_size=batch_size, shuffle=shuffle, seed=seed,
|
||||
dim_ordering=self.dim_ordering,
|
||||
save_to_dir=save_to_dir, save_prefix=save_prefix, save_format=save_format)
|
||||
|
||||
def __iter__(self):
|
||||
# needed if we want to do something like:
|
||||
# for x, y in data_gen.flow(...):
|
||||
return self
|
||||
|
||||
def next(self):
|
||||
# for python 2.x.
|
||||
# Keeps under lock only the mechanism which advances
|
||||
# the indexing of each batch
|
||||
# see # http://anandology.com/blog/using-iterators-and-generators/
|
||||
with self.lock:
|
||||
index_array, current_index, current_batch_size = next(self.flow_generator)
|
||||
# The transformation of images is not under thread lock so it can be done in parallel
|
||||
bX = np.zeros(tuple([current_batch_size] + list(self.X.shape)[1:]))
|
||||
for i, j in enumerate(index_array):
|
||||
x = self.X[j]
|
||||
x = self.random_transform(x.astype('float32'))
|
||||
x = self.standardize(x)
|
||||
bX[i] = x
|
||||
if self.save_to_dir:
|
||||
for i in range(current_batch_size):
|
||||
img = array_to_img(bX[i], self.dim_ordering, scale=True)
|
||||
fname = '{prefix}_{index}.{format}'.format(prefix=self.save_prefix,
|
||||
index=current_index + i,
|
||||
format=self.save_format)
|
||||
img.save(os.path.join(self.save_to_dir, fname))
|
||||
bY = self.y[index_array]
|
||||
return bX, bY
|
||||
|
||||
def __next__(self):
|
||||
# for python 3.x.
|
||||
return self.next()
|
||||
def flow_from_directory(self, directory,
|
||||
target_size=(256, 256), color_mode='rgb',
|
||||
classes=None, class_mode='categorical',
|
||||
batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
return DirectoryIterator(
|
||||
directory, self,
|
||||
target_size=target_size, color_mode=color_mode,
|
||||
classes=classes, class_mode=class_mode,
|
||||
dim_ordering=self.dim_ordering,
|
||||
batch_size=batch_size, shuffle=shuffle, seed=seed,
|
||||
save_to_dir=save_to_dir, save_prefix=save_prefix, save_format=save_format)
|
||||
|
||||
def standardize(self, x):
|
||||
if self.rescale:
|
||||
x *= self.rescale
|
||||
# x is a single image, so it doesn't have image number at index 0
|
||||
img_channel_index = self.channel_index - 1
|
||||
if self.samplewise_center:
|
||||
@@ -435,9 +397,209 @@ class ImageDataGenerator(object):
|
||||
self.principal_components = np.dot(np.dot(U, np.diag(1. / np.sqrt(S + 10e-7))), U.T)
|
||||
|
||||
|
||||
class GraphImageDataGenerator(ImageDataGenerator):
|
||||
'''Example of how to build a generator for a Graph model
|
||||
'''
|
||||
class Iterator(object):
|
||||
|
||||
def __init__(self, N, batch_size, shuffle, seed):
|
||||
self.N = N
|
||||
self.batch_size = batch_size
|
||||
self.shuffle = shuffle
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen = 0
|
||||
self.lock = threading.Lock()
|
||||
self.index_generator = self._flow_index(N, batch_size, shuffle, seed)
|
||||
|
||||
def reset(self):
|
||||
self.batch_index = 0
|
||||
|
||||
def _flow_index(self, N, batch_size=32, shuffle=False, seed=None):
|
||||
# ensure self.batch_index is 0
|
||||
self.reset()
|
||||
while 1:
|
||||
if self.batch_index == 0:
|
||||
index_array = np.arange(N)
|
||||
if shuffle:
|
||||
if seed is not None:
|
||||
np.random.seed(seed + self.total_batches_seen)
|
||||
index_array = np.random.permutation(N)
|
||||
|
||||
current_index = (self.batch_index * batch_size) % N
|
||||
if N >= current_index + batch_size:
|
||||
current_batch_size = batch_size
|
||||
self.batch_index += 1
|
||||
else:
|
||||
current_batch_size = N - current_index
|
||||
self.batch_index = 0
|
||||
self.total_batches_seen += 1
|
||||
yield (index_array[current_index: current_index + current_batch_size],
|
||||
current_index, current_batch_size)
|
||||
|
||||
def __iter__(self):
|
||||
# needed if we want to do something like:
|
||||
# for x, y in data_gen.flow(...):
|
||||
return self
|
||||
|
||||
def __next__(self, *args, **kwargs):
|
||||
return self.next(*args, **kwargs)
|
||||
|
||||
|
||||
class NumpyArrayIterator(Iterator):
|
||||
|
||||
def __init__(self, X, y, image_data_generator,
|
||||
batch_size=32, shuffle=False, seed=None,
|
||||
dim_ordering=K.image_dim_ordering(),
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
if y is not None and len(X) != len(y):
|
||||
raise Exception('X (images tensor) and y (labels) '
|
||||
'should have the same length. '
|
||||
'Found: X.shape = %s, y.shape = %s' % (np.asarray(X).shape, np.asarray(y).shape))
|
||||
self.X = X
|
||||
self.y = y
|
||||
self.image_data_generator = image_data_generator
|
||||
self.dim_ordering = dim_ordering
|
||||
self.save_to_dir = save_to_dir
|
||||
self.save_prefix = save_prefix
|
||||
self.save_format = save_format
|
||||
super(NumpyArrayIterator, self).__init__(X.shape[0], batch_size, shuffle, seed)
|
||||
|
||||
def next(self):
|
||||
bX, bY = super(GraphImageDataGenerator, self).next()
|
||||
return {'input': bX, 'output': bY}
|
||||
# for python 2.x.
|
||||
# Keeps under lock only the mechanism which advances
|
||||
# the indexing of each batch
|
||||
# see http://anandology.com/blog/using-iterators-and-generators/
|
||||
with self.lock:
|
||||
index_array, current_index, current_batch_size = next(self.index_generator)
|
||||
# The transformation of images is not under thread lock so it can be done in parallel
|
||||
batch_x = np.zeros(tuple([current_batch_size] + list(self.X.shape)[1:]))
|
||||
for i, j in enumerate(index_array):
|
||||
x = self.X[j]
|
||||
x = self.image_data_generator.random_transform(x.astype('float32'))
|
||||
x = self.image_data_generator.standardize(x)
|
||||
batch_x[i] = x
|
||||
if self.save_to_dir:
|
||||
for i in range(current_batch_size):
|
||||
img = array_to_img(batch_x[i], self.dim_ordering, scale=True)
|
||||
fname = '{prefix}_{index}_{hash}.{format}'.format(prefix=self.save_prefix,
|
||||
index=current_index + i,
|
||||
hash=np.random.randint(1e4),
|
||||
format=self.save_format)
|
||||
img.save(os.path.join(self.save_to_dir, fname))
|
||||
if self.y is None:
|
||||
return batch_x
|
||||
batch_y = self.y[index_array]
|
||||
return batch_x, batch_y
|
||||
|
||||
|
||||
class DirectoryIterator(Iterator):
|
||||
|
||||
def __init__(self, directory, image_data_generator,
|
||||
target_size=(256, 256), color_mode='rgb',
|
||||
dim_ordering=K.image_dim_ordering,
|
||||
classes=None, class_mode='categorical',
|
||||
batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
self.directory = directory
|
||||
self.image_data_generator = image_data_generator
|
||||
self.target_size = tuple(target_size)
|
||||
if color_mode not in {'rgb', 'grayscale'}:
|
||||
raise ValueError('Invalid color mode:', color_mode,
|
||||
'; expected "rgb" or "grayscale".')
|
||||
self.color_mode = color_mode
|
||||
self.dim_ordering = dim_ordering
|
||||
if self.color_mode == 'rgb':
|
||||
if self.dim_ordering == 'tf':
|
||||
self.image_shape = self.target_size + (3,)
|
||||
else:
|
||||
self.image_shape = (3,) + self.target_size
|
||||
else:
|
||||
if self.dim_ordering == 'tf':
|
||||
self.image_shape = self.target_size + (1,)
|
||||
else:
|
||||
self.image_shape = (1,) + self.target_size
|
||||
self.classes = classes
|
||||
if class_mode not in {'categorical', 'binary', 'sparse', None}:
|
||||
raise ValueError('Invalid class_mode:', class_mode,
|
||||
'; expected one of "categorical", '
|
||||
'"binary", "sparse", or None.')
|
||||
self.class_mode = class_mode
|
||||
self.save_to_dir = save_to_dir
|
||||
self.save_prefix = save_prefix
|
||||
self.save_format = save_format
|
||||
|
||||
white_list_formats = {'png', 'jpg', 'jpeg', 'bmp'}
|
||||
|
||||
# first, count the number of samples and classes
|
||||
self.nb_sample = 0
|
||||
|
||||
if not classes:
|
||||
classes = []
|
||||
for subdir in os.listdir(directory):
|
||||
if os.path.isdir(os.path.join(directory, subdir)):
|
||||
classes.append(subdir)
|
||||
self.nb_class = len(classes)
|
||||
self.class_indices = dict(zip(classes, range(len(classes))))
|
||||
|
||||
for subdir in classes:
|
||||
subpath = os.path.join(directory, subdir)
|
||||
for fname in os.listdir(subpath):
|
||||
is_valid = False
|
||||
for extension in white_list_formats:
|
||||
if fname.endswith('.' + extension):
|
||||
is_valid = True
|
||||
break
|
||||
if is_valid:
|
||||
self.nb_sample += 1
|
||||
print('Found %d images belonging to %d classes.' % (self.nb_sample, self.nb_class))
|
||||
|
||||
# second, build an index of the images in the different class subfolders
|
||||
self.filenames = []
|
||||
self.classes = np.zeros((self.nb_sample,), dtype='int32')
|
||||
i = 0
|
||||
for subdir in classes:
|
||||
subpath = os.path.join(directory, subdir)
|
||||
for fname in os.listdir(subpath):
|
||||
is_valid = False
|
||||
for extension in white_list_formats:
|
||||
if fname.endswith('.' + extension):
|
||||
is_valid = True
|
||||
break
|
||||
if is_valid:
|
||||
self.classes[i] = self.class_indices[subdir]
|
||||
self.filenames.append(os.path.join(subdir, fname))
|
||||
i += 1
|
||||
super(DirectoryIterator, self).__init__(self.nb_sample, batch_size, shuffle, seed)
|
||||
|
||||
def next(self):
|
||||
with self.lock:
|
||||
index_array, current_index, current_batch_size = next(self.index_generator)
|
||||
# The transformation of images is not under thread lock so it can be done in parallel
|
||||
batch_x = np.zeros((current_batch_size,) + self.image_shape)
|
||||
grayscale = self.color_mode == 'grayscale'
|
||||
# build batch of image data
|
||||
for i, j in enumerate(index_array):
|
||||
fname = self.filenames[j]
|
||||
img = load_img(os.path.join(self.directory, fname), grayscale=grayscale, target_size=self.target_size)
|
||||
x = img_to_array(img, dim_ordering=self.dim_ordering)
|
||||
x = self.image_data_generator.random_transform(x)
|
||||
x = self.image_data_generator.standardize(x)
|
||||
batch_x[i] = x
|
||||
# optionally save augmented images to disk for debugging purposes
|
||||
if self.save_to_dir:
|
||||
for i in range(current_batch_size):
|
||||
img = array_to_img(batch_x[i], self.dim_ordering, scale=True)
|
||||
fname = '{prefix}_{index}_{hash}.{format}'.format(prefix=self.save_prefix,
|
||||
index=current_index + i,
|
||||
hash=np.random.randint(1e4),
|
||||
format=self.save_format)
|
||||
img.save(os.path.join(self.save_to_dir, fname))
|
||||
# build batch of labels
|
||||
if self.class_mode == 'sparse':
|
||||
batch_y = self.classes[index_array]
|
||||
elif self.class_mode == 'binary':
|
||||
batch_y = self.classes[index_array].astype('float32')
|
||||
elif self.class_mode == 'categorical':
|
||||
batch_y = np.zeros((len(batch_x), self.nb_class), dtype='float32')
|
||||
for i, label in enumerate(self.classes[index_array]):
|
||||
batch_y[i, label] = 1.
|
||||
else:
|
||||
return batch_x
|
||||
return batch_x, batch_y
|
||||
|
||||
@@ -41,8 +41,8 @@ class WeightRegularizer(Regularizer):
|
||||
|
||||
def get_config(self):
|
||||
return {'name': self.__class__.__name__,
|
||||
'l1': self.l1,
|
||||
'l2': self.l2}
|
||||
'l1': float(self.l1),
|
||||
'l2': float(self.l2)}
|
||||
|
||||
|
||||
class ActivityRegularizer(Regularizer):
|
||||
@@ -59,15 +59,17 @@ class ActivityRegularizer(Regularizer):
|
||||
raise Exception('Need to call `set_layer` on '
|
||||
'ActivityRegularizer instance '
|
||||
'before calling the instance.')
|
||||
output = self.layer.output
|
||||
regularized_loss = loss + self.l1 * K.sum(K.mean(K.abs(output), axis=0))
|
||||
regularized_loss += self.l2 * K.sum(K.mean(K.square(output), axis=0))
|
||||
regularized_loss = loss
|
||||
for i in range(len(self.layer.inbound_nodes)):
|
||||
output = self.layer.get_output_at(i)
|
||||
regularized_loss += self.l1 * K.sum(K.mean(K.abs(output), axis=0))
|
||||
regularized_loss += self.l2 * K.sum(K.mean(K.square(output), axis=0))
|
||||
return K.in_train_phase(regularized_loss, loss)
|
||||
|
||||
def get_config(self):
|
||||
return {'name': self.__class__.__name__,
|
||||
'l1': self.l1,
|
||||
'l2': self.l2}
|
||||
'l1': float(self.l1),
|
||||
'l2': float(self.l2)}
|
||||
|
||||
|
||||
def l1(l=0.01):
|
||||
|
||||
@@ -34,24 +34,28 @@ def make_tuple(*args):
|
||||
|
||||
|
||||
class Progbar(object):
|
||||
def __init__(self, target, width=30, verbose=1):
|
||||
def __init__(self, target, width=30, verbose=1, interval=0.01):
|
||||
'''
|
||||
@param target: total number of steps expected
|
||||
@param interval: minimum visual progress update interval (in seconds)
|
||||
'''
|
||||
self.width = width
|
||||
self.target = target
|
||||
self.sum_values = {}
|
||||
self.unique_values = []
|
||||
self.start = time.time()
|
||||
self.last_update = 0
|
||||
self.interval = interval
|
||||
self.total_width = 0
|
||||
self.seen_so_far = 0
|
||||
self.verbose = verbose
|
||||
|
||||
def update(self, current, values=[]):
|
||||
def update(self, current, values=[], force=False):
|
||||
'''
|
||||
@param current: index of current step
|
||||
@param values: list of tuples (name, value_for_last_step).
|
||||
The progress bar will display averages for these values.
|
||||
@param force: force visual progress update
|
||||
'''
|
||||
for k, v in values:
|
||||
if k not in self.sum_values:
|
||||
@@ -64,6 +68,9 @@ class Progbar(object):
|
||||
|
||||
now = time.time()
|
||||
if self.verbose == 1:
|
||||
if not force and (now - self.last_update) < self.interval:
|
||||
return
|
||||
|
||||
prev_total_width = self.total_width
|
||||
sys.stdout.write("\b" * prev_total_width)
|
||||
sys.stdout.write("\r")
|
||||
@@ -127,6 +134,8 @@ class Progbar(object):
|
||||
info += ' %.4e' % avg
|
||||
sys.stdout.write(info + "\n")
|
||||
|
||||
self.last_update = now
|
||||
|
||||
def add(self, n, values=[]):
|
||||
self.update(self.seen_so_far + n, values)
|
||||
|
||||
|
||||
@@ -35,9 +35,11 @@ def layer_from_config(config, custom_objects={}):
|
||||
return layer_class.from_config(config['config'])
|
||||
|
||||
|
||||
def print_summary(layers, relevant_nodes=None):
|
||||
line_length = 100 # total length of printed lines
|
||||
positions = [35, 55, 67, 100] # absolute positions of log elements in each line
|
||||
def print_summary(layers, relevant_nodes=None, line_length=100, positions=[.33, .55, .67, 1.]):
|
||||
# line_length: total length of printed lines
|
||||
# positions: relative or absolute positions of log elements in each line
|
||||
if positions[-1] <= 1:
|
||||
positions = [int(line_length * p) for p in positions]
|
||||
# header names for the different log elements
|
||||
to_display = ['Layer (type)', 'Output Shape', 'Param #', 'Connected to']
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ if not pydot.find_graphviz():
|
||||
' and graphviz for `pydotprint` to work.')
|
||||
|
||||
|
||||
def model_to_dot(model, show_shapes=False):
|
||||
def model_to_dot(model, show_shapes=False, show_layer_names=True):
|
||||
dot = pydot.Dot()
|
||||
dot.set('rankdir', 'TB')
|
||||
dot.set('concentrate', True)
|
||||
@@ -24,7 +24,10 @@ def model_to_dot(model, show_shapes=False):
|
||||
# first, populate the nodes of the graph
|
||||
for layer in layers:
|
||||
layer_id = str(id(layer))
|
||||
label = str(layer.name) + ' (' + layer.__class__.__name__ + ')'
|
||||
if show_layer_names:
|
||||
label = str(layer.name) + ' (' + layer.__class__.__name__ + ')'
|
||||
else:
|
||||
label = layer.__class__.__name__
|
||||
|
||||
if show_shapes:
|
||||
# Build the label that will actually contain a table with the
|
||||
@@ -59,6 +62,6 @@ def model_to_dot(model, show_shapes=False):
|
||||
return dot
|
||||
|
||||
|
||||
def plot(model, to_file='model.png', show_shapes=False):
|
||||
dot = model_to_dot(model, show_shapes)
|
||||
def plot(model, to_file='model.png', show_shapes=False, show_layer_names=True):
|
||||
dot = model_to_dot(model, show_shapes, show_layer_names)
|
||||
dot.write_png(to_file)
|
||||
|
||||
@@ -2,7 +2,6 @@ from __future__ import absolute_import
|
||||
import copy
|
||||
import inspect
|
||||
import types
|
||||
import numpy as np
|
||||
|
||||
from ..utils.np_utils import to_categorical
|
||||
from ..models import Sequential
|
||||
|
||||
+2
-2
@@ -3,12 +3,12 @@ from setuptools import find_packages
|
||||
|
||||
|
||||
setup(name='Keras',
|
||||
version='1.0.2',
|
||||
version='1.0.4',
|
||||
description='Deep Learning for Python',
|
||||
author='Francois Chollet',
|
||||
author_email='francois.chollet@gmail.com',
|
||||
url='https://github.com/fchollet/keras',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.0.2',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.0.4',
|
||||
license='MIT',
|
||||
install_requires=['theano', 'pyyaml', 'six'],
|
||||
extras_require={
|
||||
|
||||
@@ -23,7 +23,7 @@ def test_temporal_classification():
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=200,
|
||||
nb_test=500,
|
||||
input_shape=(3, 5),
|
||||
classification=True,
|
||||
nb_class=2)
|
||||
@@ -35,12 +35,12 @@ def test_temporal_classification():
|
||||
input_shape=(X_train.shape[1], X_train.shape[2]),
|
||||
activation='softmax'))
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer='adadelta',
|
||||
optimizer='adagrad',
|
||||
metrics=['accuracy'])
|
||||
history = model.fit(X_train, y_train, nb_epoch=5, batch_size=16,
|
||||
history = model.fit(X_train, y_train, nb_epoch=20, batch_size=32,
|
||||
validation_data=(X_test, y_test),
|
||||
verbose=0)
|
||||
assert(history.history['val_acc'][-1] > 0.9)
|
||||
assert(history.history['val_acc'][-1] >= 0.85)
|
||||
|
||||
|
||||
def test_temporal_regression():
|
||||
@@ -182,4 +182,5 @@ def test_masked_temporal():
|
||||
assert(np.abs(history.history['val_loss'][-1] - ground_truth) < 0.06)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
# pytest.main([__file__])
|
||||
test_temporal_classification()
|
||||
|
||||
@@ -91,6 +91,17 @@ class TestBackend(object):
|
||||
assert_allclose(np_rep, th_rep, atol=1e-05)
|
||||
assert_allclose(np_rep, tf_rep, atol=1e-05)
|
||||
|
||||
def test_tile(self):
|
||||
shape = (3, 4)
|
||||
arr = np.arange(np.prod(shape)).reshape(shape)
|
||||
arr_th = KTH.variable(arr)
|
||||
arr_tf = KTF.variable(arr)
|
||||
|
||||
n = (2, 1)
|
||||
th_rep = KTH.eval(KTH.tile(arr_th, n))
|
||||
tf_rep = KTF.eval(KTF.tile(arr_tf, n))
|
||||
assert_allclose(tf_rep, th_rep, atol=1e-05)
|
||||
|
||||
def test_value_manipulation(self):
|
||||
val = np.random.random((4, 2))
|
||||
xth = KTH.variable(val)
|
||||
|
||||
@@ -515,8 +515,6 @@ def test_sequential_regression():
|
||||
name='embed_1'))
|
||||
branch_1.add(LSTM(32, name='lstm_1'))
|
||||
|
||||
branch_1.add(BatchNormalization())
|
||||
|
||||
branch_2 = Sequential(name='branch_2')
|
||||
branch_2.add(Dense(32, input_shape=(8,), name='dense_2'))
|
||||
|
||||
|
||||
@@ -117,10 +117,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
|
||||
# this should also work
|
||||
model.compile(optimizer, loss, metrics={'dense_1': 'acc'},
|
||||
@@ -128,10 +128,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
|
||||
# and this as well
|
||||
model.compile(optimizer, loss, metrics={'dense_1': ['acc']},
|
||||
@@ -139,10 +139,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 2
|
||||
assert len(out) == 4
|
||||
|
||||
# test with a custom metric function
|
||||
mse = lambda y_true, y_pred: K.mean(K.pow(y_true - y_pred, 2))
|
||||
@@ -151,10 +151,10 @@ def test_model_methods():
|
||||
|
||||
out = model.train_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
out = model.test_on_batch([input_a_np, input_b_np],
|
||||
[output_a_np, output_b_np])
|
||||
assert len(out) == 3
|
||||
assert len(out) == 5
|
||||
|
||||
input_a_np = np.random.random((10, 3))
|
||||
input_b_np = np.random.random((10, 3))
|
||||
|
||||
@@ -24,22 +24,22 @@ def basic_batchnorm_test():
|
||||
input_shape=(3, 4, 2))
|
||||
|
||||
|
||||
def test_batchnorm_mode_0():
|
||||
model = Sequential()
|
||||
norm_m0 = normalization.BatchNormalization(mode=0, input_shape=(10,))
|
||||
model.add(norm_m0)
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
def test_batchnorm_mode_0_or_2():
|
||||
for mode in [0, 2]:
|
||||
model = Sequential()
|
||||
norm_m0 = normalization.BatchNormalization(mode=mode, input_shape=(10,))
|
||||
model.add(norm_m0)
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 10))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
out = norm_m0.call(K.variable(X))
|
||||
out -= norm_m0.beta
|
||||
out /= norm_m0.gamma
|
||||
np_out = K.function([K.learning_phase()], [out])([1.])[0]
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 10))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
out = model.predict(X)
|
||||
out -= K.eval(norm_m0.beta)
|
||||
out /= K.eval(norm_m0.gamma)
|
||||
|
||||
assert_allclose(np_out.mean(), 0.0, atol=1e-1)
|
||||
assert_allclose(np_out.std(), 1.0, atol=1e-1)
|
||||
assert_allclose(out.mean(), 0.0, atol=1e-1)
|
||||
assert_allclose(out.std(), 1.0, atol=1e-1)
|
||||
|
||||
|
||||
def test_batchnorm_mode_0_convnet():
|
||||
@@ -51,13 +51,12 @@ def test_batchnorm_mode_0_convnet():
|
||||
# centered on 5.0, variance 10.0
|
||||
X = np.random.normal(loc=5.0, scale=10.0, size=(1000, 3, 4, 4))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
out = norm_m0.call(K.variable(X))
|
||||
out -= K.reshape(norm_m0.beta, (1, 3, 1, 1))
|
||||
out /= K.reshape(norm_m0.gamma, (1, 3, 1, 1))
|
||||
np_out = K.function([K.learning_phase()], [out])([1.])[0]
|
||||
out = model.predict(X)
|
||||
out -= np.reshape(K.eval(norm_m0.beta), (1, 3, 1, 1))
|
||||
out /= np.reshape(K.eval(norm_m0.gamma), (1, 3, 1, 1))
|
||||
|
||||
assert_allclose(np.mean(np_out, axis=(0, 2, 3)), 0.0, atol=1e-1)
|
||||
assert_allclose(np.std(np_out, axis=(0, 2, 3)), 1.0, atol=1e-1)
|
||||
assert_allclose(np.mean(out, axis=(0, 2, 3)), 0.0, atol=1e-1)
|
||||
assert_allclose(np.std(out, axis=(0, 2, 3)), 1.0, atol=1e-1)
|
||||
|
||||
|
||||
def test_batchnorm_mode_1():
|
||||
|
||||
@@ -32,6 +32,13 @@ def _runner(layer_class):
|
||||
'dropout_W': 0.1},
|
||||
input_shape=(3, 2, 3))
|
||||
|
||||
# check implementation modes
|
||||
for mode in ['cpu', 'mem', 'gpu']:
|
||||
layer_test(layer_class,
|
||||
kwargs={'output_dim': output_dim,
|
||||
'consume_less': mode},
|
||||
input_shape=(3, 2, 3))
|
||||
|
||||
# check statefulness
|
||||
model = Sequential()
|
||||
model.add(embeddings.Embedding(embedding_num, embedding_dim,
|
||||
|
||||
@@ -56,6 +56,22 @@ def test_softplus():
|
||||
assert_allclose(result, expected, rtol=1e-05)
|
||||
|
||||
|
||||
def test_softsign():
|
||||
'''
|
||||
Test using a reference softsign implementation
|
||||
'''
|
||||
def softsign(x):
|
||||
return np.divide(x, np.ones_like(x) + np.absolute(x))
|
||||
|
||||
x = K.placeholder(ndim=2)
|
||||
f = K.function([x], [activations.softsign(x)])
|
||||
test_values = get_standard_values()
|
||||
|
||||
result = f([test_values])[0]
|
||||
expected = softsign(test_values)
|
||||
assert_allclose(result, expected, rtol=1e-05)
|
||||
|
||||
|
||||
def test_sigmoid():
|
||||
'''
|
||||
Test using a numerically stable reference sigmoid implementation
|
||||
|
||||
@@ -4,8 +4,14 @@ import numpy as np
|
||||
from keras import initializations
|
||||
from keras import backend as K
|
||||
|
||||
SHAPE = (100, 100)
|
||||
# 2D tensor test fixture
|
||||
FC_SHAPE = (100, 100)
|
||||
|
||||
# 4D convolution in th order. This shape has the same effective shape as FC_SHAPE
|
||||
CONV_SHAPE = (25, 25, 2, 2)
|
||||
|
||||
# The equivalent shape of both test fixtures
|
||||
SHAPE = (100, 100)
|
||||
|
||||
def _runner(init, shape, target_mean=None, target_std=None,
|
||||
target_max=None, target_min=None):
|
||||
@@ -22,62 +28,78 @@ def _runner(init, shape, target_mean=None, target_std=None,
|
||||
assert abs(output.min() - target_min) < lim
|
||||
|
||||
|
||||
def test_uniform():
|
||||
_runner(initializations.uniform, SHAPE, target_mean=0.,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_uniform(tensor_shape):
|
||||
_runner(initializations.uniform, tensor_shape, target_mean=0.,
|
||||
target_max=0.05, target_min=-0.05)
|
||||
|
||||
|
||||
def test_normal():
|
||||
_runner(initializations.normal, SHAPE, target_mean=0., target_std=0.05)
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_normal(tensor_shape):
|
||||
_runner(initializations.normal, tensor_shape, target_mean=0., target_std=0.05)
|
||||
|
||||
|
||||
def test_lecun_uniform():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_lecun_uniform(tensor_shape):
|
||||
scale = np.sqrt(3. / SHAPE[0])
|
||||
_runner(initializations.lecun_uniform, SHAPE,
|
||||
_runner(initializations.lecun_uniform, tensor_shape,
|
||||
target_mean=0., target_max=scale, target_min=-scale)
|
||||
|
||||
|
||||
def test_glorot_uniform():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_glorot_uniform(tensor_shape):
|
||||
scale = np.sqrt(6. / (SHAPE[0] + SHAPE[1]))
|
||||
_runner(initializations.glorot_uniform, SHAPE, target_mean=0.,
|
||||
_runner(initializations.glorot_uniform, tensor_shape, target_mean=0.,
|
||||
target_max=scale, target_min=-scale)
|
||||
|
||||
|
||||
def test_glorot_normal():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_glorot_normal(tensor_shape):
|
||||
scale = np.sqrt(2. / (SHAPE[0] + SHAPE[1]))
|
||||
_runner(initializations.glorot_normal, SHAPE,
|
||||
_runner(initializations.glorot_normal, tensor_shape,
|
||||
target_mean=0., target_std=scale)
|
||||
|
||||
|
||||
def test_he_uniform():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_he_uniform(tensor_shape):
|
||||
scale = np.sqrt(6. / SHAPE[0])
|
||||
_runner(initializations.he_uniform, SHAPE, target_mean=0.,
|
||||
_runner(initializations.he_uniform, tensor_shape, target_mean=0.,
|
||||
target_max=scale, target_min=-scale)
|
||||
|
||||
|
||||
def test_he_normal():
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_he_normal(tensor_shape):
|
||||
scale = np.sqrt(2. / SHAPE[0])
|
||||
_runner(initializations.he_normal, SHAPE,
|
||||
_runner(initializations.he_normal, tensor_shape,
|
||||
target_mean=0., target_std=scale)
|
||||
|
||||
|
||||
def test_orthogonal():
|
||||
_runner(initializations.orthogonal, SHAPE,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_orthogonal(tensor_shape):
|
||||
_runner(initializations.orthogonal, tensor_shape,
|
||||
target_mean=0.)
|
||||
|
||||
|
||||
def test_identity():
|
||||
_runner(initializations.identity, SHAPE,
|
||||
target_mean=1./SHAPE[0], target_max=1.)
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_identity(tensor_shape):
|
||||
if len(tensor_shape) > 2:
|
||||
with pytest.raises(Exception):
|
||||
_runner(initializations.identity, tensor_shape,
|
||||
target_mean=1./SHAPE[0], target_max=1.)
|
||||
else:
|
||||
_runner(initializations.identity, tensor_shape,
|
||||
target_mean=1./SHAPE[0], target_max=1.)
|
||||
|
||||
|
||||
def test_zero():
|
||||
_runner(initializations.zero, SHAPE,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_zero(tensor_shape):
|
||||
_runner(initializations.zero, tensor_shape,
|
||||
target_mean=0., target_max=0.)
|
||||
|
||||
|
||||
def test_one():
|
||||
_runner(initializations.one, SHAPE,
|
||||
@pytest.mark.parametrize('tensor_shape', [FC_SHAPE, CONV_SHAPE], ids=['FC', 'CONV'])
|
||||
def test_one(tensor_shape):
|
||||
_runner(initializations.one, tensor_shape,
|
||||
target_mean=1., target_max=1.)
|
||||
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ allobj = [objectives.mean_squared_error,
|
||||
objectives.squared_hinge,
|
||||
objectives.hinge, objectives.categorical_crossentropy,
|
||||
objectives.binary_crossentropy,
|
||||
objectives.kullback_leibler_divergence,
|
||||
objectives.poisson,
|
||||
objectives.cosine_proximity]
|
||||
|
||||
|
||||
Referência em uma Nova Issue
Bloquear um usuário