Comparar commits
216 Commits
| Autor | SHA1 | Data | |
|---|---|---|---|
| b2e3780e8c | |||
| 0b04ac3117 | |||
| 90d0eb9b88 | |||
| f2aa89f443 | |||
| 2a319c7255 | |||
| 4fb3f1b3f3 | |||
| 072d33599b | |||
| 56f3c85b87 | |||
| 8b42fff90e | |||
| 1dc5d43d32 | |||
| ee2d08ff79 | |||
| 305b3bed74 | |||
| 9f6acd960c | |||
| 672890b1c8 | |||
| c58bcc2c02 | |||
| 82318263a1 | |||
| d90e1db50b | |||
| 8af0264a77 | |||
| 8193287e08 | |||
| 13bd33e73f | |||
| b2e8d5ab7c | |||
| a375cb322f | |||
| d9c4d8a76a | |||
| 79edae58d5 | |||
| 6675776640 | |||
| 40685c3b2a | |||
| 25874ceab2 | |||
| 4b2093ef67 | |||
| 9bc2e60fd5 | |||
| 685ce7573d | |||
| f5ad1c5753 | |||
| cc92025fdc | |||
| f05cd95fad | |||
| 4325843ef0 | |||
| 607635d2ce | |||
| b8fddc862e | |||
| 0df0177437 | |||
| f90cbcd1e3 | |||
| 870d7f7f93 | |||
| 799bec66a2 | |||
| 2321fbbc1d | |||
| 48ae7217e4 | |||
| 6f54b233f1 | |||
| 1bf1055395 | |||
| 6417d90d5c | |||
| c939cebf0d | |||
| 7ae36d132a | |||
| c478409dad | |||
| 109441a708 | |||
| b267e8293d | |||
| 3a4c683d5c | |||
| d5649da5f8 | |||
| 9c28d21b4f | |||
| 9e58b8237b | |||
| b184c76205 | |||
| 065fb2a74c | |||
| a0a0d42630 | |||
| 756153899a | |||
| e02554412f | |||
| ca37e806b9 | |||
| fe0347dbf0 | |||
| 4984c5fc7c | |||
| f605769af9 | |||
| 534f6b7975 | |||
| ee8fd78383 | |||
| fbc4f37037 | |||
| f23f2ff2c9 | |||
| d0659327bd | |||
| 88b301f182 | |||
| d5e16807d2 | |||
| 79a2bcd05f | |||
| e582f9dcac | |||
| 4cefd6136b | |||
| 1cf04b7a10 | |||
| ad3db301f2 | |||
| e15eb40317 | |||
| 8459d0403c | |||
| 08014eea36 | |||
| c0b27108d0 | |||
| 40612facf3 | |||
| e418fc6937 | |||
| 045d442fcd | |||
| 2370f9f1db | |||
| 519d1e7420 | |||
| 82afc713d0 | |||
| a1e9a8addd | |||
| f59736a06c | |||
| d187059596 | |||
| 7d2f0b1ba8 | |||
| 6a6d939dea | |||
| 090b8b7f99 | |||
| e4dda27de1 | |||
| f2786d9d80 | |||
| c6daa24e3c | |||
| 2f4eed1f0f | |||
| acc5c45feb | |||
| 00c3335071 | |||
| 65e4c8e76e | |||
| d4f5dff8ee | |||
| 8d9cb782fb | |||
| 02ff1d4462 | |||
| 007d2c2e25 | |||
| 3bf7637986 | |||
| 33ff9dbce2 | |||
| f25e894558 | |||
| 52c1a7456f | |||
| b2392413fa | |||
| 1941eaabe0 | |||
| 3d5bf9753f | |||
| a4d191d4f9 | |||
| dad54ec211 | |||
| b525f5f4d7 | |||
| e8190a8d8d | |||
| 4e155139ca | |||
| 458edeed9a | |||
| 04d785f4bf | |||
| 28d9c0c511 | |||
| 91310971b9 | |||
| 5d2acf4897 | |||
| dc98019d49 | |||
| b008bb35cc | |||
| 46d5b197e0 | |||
| 2c510530b1 | |||
| ec6eda77ad | |||
| 4805e5856b | |||
| 55447cbb3d | |||
| 69d5139b8c | |||
| 89f1e05147 | |||
| bc779df8b7 | |||
| e3c260e7d3 | |||
| 0af7e004c7 | |||
| 447445388e | |||
| b2c66816d7 | |||
| b6f81c6cc3 | |||
| 98b289630a | |||
| d68c0bd795 | |||
| 5afda71f74 | |||
| 1b08a8d675 | |||
| b508ab64bd | |||
| 84f435e24b | |||
| 984ad34a61 | |||
| ad3231c29a | |||
| c3d20bbc53 | |||
| f9c03f183f | |||
| 046a3c8a28 | |||
| 05883934f1 | |||
| 97d2a73dd3 | |||
| 5367a44acb | |||
| 1deaf71388 | |||
| 99f564e972 | |||
| c725f8d354 | |||
| 257ace722c | |||
| 0cd9d46828 | |||
| cef9e28a6c | |||
| 6c42da2abf | |||
| a9fc2bed49 | |||
| 1855c49d1f | |||
| cce65ce34d | |||
| 70866c0154 | |||
| d06e3753b0 | |||
| cb4de1f859 | |||
| b6d23b2e2d | |||
| 6a8815de0c | |||
| e0179bad2f | |||
| 8778add0d6 | |||
| facc823612 | |||
| b91854ea9d | |||
| 05abe814ac | |||
| ea561ba6d8 | |||
| df84c69676 | |||
| 3726aba2ee | |||
| f6bcaffe4a | |||
| c689b52dd1 | |||
| 09d75a4347 | |||
| 59bd247603 | |||
| f221ef952f | |||
| d3c75e1d34 | |||
| 3aab55d29f | |||
| f9ef72c38a | |||
| 108159ed17 | |||
| defa1283c4 | |||
| 2788b60fe6 | |||
| 7e70e1768f | |||
| 896ba77061 | |||
| c034262b78 | |||
| b7edcf6eea | |||
| 23e1ad2df7 | |||
| 0a3939883a | |||
| 3c8f91ee3d | |||
| efa5b04797 | |||
| 2da66ed009 | |||
| 2ac6811362 | |||
| 74c51f213c | |||
| 4302d8060d | |||
| 576cf8978b | |||
| 3533912016 | |||
| cf9922ff1d | |||
| 4fa65fbb2f | |||
| f502ee2338 | |||
| 7a56925176 | |||
| 0a108b3fb2 | |||
| 381a108e6d | |||
| 726c9fc8a6 | |||
| 946ccd3228 | |||
| 8e1ebbfc11 | |||
| cc0e60c101 | |||
| ff3f00d845 | |||
| 40195c2fa2 | |||
| 7f7300b8cb | |||
| 1b158ff4ed | |||
| b686b85b52 | |||
| 8fa82ae5cb | |||
| 0d5289141e | |||
| 01d5e7bc47 | |||
| cfbaec60c7 | |||
| f3e7245910 |
+17
-14
@@ -1,19 +1,21 @@
|
||||
# Keras: Deep Learning library for Theano and TensorFlow
|
||||
# Keras: Deep Learning library for TensorFlow and Theano
|
||||
|
||||
[](https://travis-ci.org/fchollet/keras)
|
||||
[](https://badge.fury.io/py/keras)
|
||||
[](https://github.com/fchollet/keras/blob/master/LICENSE)
|
||||
[](https://gitter.im/Keras-io/Lobby)
|
||||
|
||||
|
||||
## You have just found Keras.
|
||||
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. *Being able to go from idea to result with the least possible delay is key to doing good research.*
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
|
||||
- allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- runs seamlessly on CPU and GPU.
|
||||
- Allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- Supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- Supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- Runs seamlessly on CPU and GPU.
|
||||
|
||||
Read the documentation at [Keras.io](http://keras.io).
|
||||
|
||||
@@ -114,32 +116,33 @@ Keras uses the following dependencies:
|
||||
- HDF5 and h5py (optional, required if you use model saving/loading functions)
|
||||
- Optional but recommended if you use CNNs: cuDNN.
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
*When using the TensorFlow backend:*
|
||||
|
||||
- TensorFlow
|
||||
- [See installation instructions](https://github.com/tensorflow/tensorflow#download-and-setup).
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
To install Keras, `cd` to the Keras folder and run the install command:
|
||||
```
|
||||
```sh
|
||||
sudo python setup.py install
|
||||
```
|
||||
|
||||
You can also install Keras from PyPI:
|
||||
```
|
||||
```sh
|
||||
sudo pip install keras
|
||||
```
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Switching from Theano to TensorFlow
|
||||
## Switching from TensorFlow to Theano
|
||||
|
||||
By default, Keras will use Theano as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
By default, Keras will use TensorFlow as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
FROM nvidia/cuda:7.5-cudnn5-devel
|
||||
|
||||
ENV CONDA_DIR /opt/conda
|
||||
ENV PATH $CONDA_DIR/bin:$PATH
|
||||
|
||||
RUN mkdir -p $CONDA_DIR && \
|
||||
echo export PATH=$CONDA_DIR/bin:'$PATH' > /etc/profile.d/conda.sh && \
|
||||
apt-get update && \
|
||||
apt-get install -y wget git libhdf5-dev g++ graphviz && \
|
||||
wget --quiet https://repo.continuum.io/miniconda/Miniconda3-3.9.1-Linux-x86_64.sh && \
|
||||
echo "6c6b44acdd0bc4229377ee10d52c8ac6160c336d9cdd669db7371aa9344e1ac3 *Miniconda3-3.9.1-Linux-x86_64.sh" | sha256sum -c - && \
|
||||
/bin/bash /Miniconda3-3.9.1-Linux-x86_64.sh -f -b -p $CONDA_DIR && \
|
||||
rm Miniconda3-3.9.1-Linux-x86_64.sh
|
||||
|
||||
ENV NB_USER keras
|
||||
ENV NB_UID 1000
|
||||
|
||||
RUN useradd -m -s /bin/bash -N -u $NB_UID $NB_USER && \
|
||||
mkdir -p $CONDA_DIR && \
|
||||
chown keras $CONDA_DIR -R && \
|
||||
mkdir -p /src && \
|
||||
chown keras /src
|
||||
|
||||
USER keras
|
||||
|
||||
# Python
|
||||
ARG python_version=3.5.1
|
||||
ARG tensorflow_version=0.9.0rc0-cp35-cp35m
|
||||
RUN conda install -y python=${python_version} && \
|
||||
pip install https://storage.googleapis.com/tensorflow/linux/gpu/tensorflow-${tensorflow_version}-linux_x86_64.whl && \
|
||||
pip install git+git://github.com/Theano/Theano.git && \
|
||||
pip install ipdb pytest pytest-cov python-coveralls coverage==3.7.1 pytest-xdist pep8 pytest-pep8 pydot_ng && \
|
||||
conda install Pillow scikit-learn notebook pandas matplotlib nose pyyaml six h5py && \
|
||||
pip install git+git://github.com/fchollet/keras.git && \
|
||||
conda clean -yt
|
||||
|
||||
ADD theanorc /home/keras/.theanorc
|
||||
|
||||
ENV PYTHONPATH='/src/:$PYTHONPATH'
|
||||
|
||||
WORKDIR /src
|
||||
|
||||
EXPOSE 8888
|
||||
|
||||
CMD jupyter notebook --port=8888 --ip=0.0.0.0
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
help:
|
||||
@cat Makefile
|
||||
|
||||
DATA?="${HOME}/Data"
|
||||
GPU?=0
|
||||
DOCKER_FILE=Dockerfile
|
||||
DOCKER=GPU=$(GPU) nvidia-docker
|
||||
BACKEND=tensorflow
|
||||
TEST=tests/
|
||||
SRC=$(shell dirname `pwd`)
|
||||
|
||||
build:
|
||||
docker build -t keras --build-arg python_version=3.5 -f $(DOCKER_FILE) .
|
||||
|
||||
bash: build
|
||||
$(DOCKER) run -it -v $(SRC):/src -v $(DATA):/data --env KERAS_BACKEND=$(BACKEND) keras bash
|
||||
|
||||
ipython: build
|
||||
$(DOCKER) run -it -v $(SRC):/src -v $(DATA):/data --env KERAS_BACKEND=$(BACKEND) keras ipython
|
||||
|
||||
notebook: build
|
||||
$(DOCKER) run -it -v $(SRC):/src -v $(DATA):/data --net=host --env KERAS_BACKEND=$(BACKEND) keras
|
||||
|
||||
test: build
|
||||
$(DOCKER) run -it -v $(SRC):/src -v $(DATA):/data --env KERAS_BACKEND=$(BACKEND) keras py.test $(TEST)
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Using Keras via Docker
|
||||
|
||||
This directory contains `Dockerfile` to make it easy to get up and running with
|
||||
Keras via [Docker](http://www.docker.com/).
|
||||
|
||||
## Installing Docker
|
||||
|
||||
General installation instructions are
|
||||
[on the Docker site](https://docs.docker.com/installation/), but we give some
|
||||
quick links here:
|
||||
|
||||
* [OSX](https://docs.docker.com/installation/mac/): [docker toolbox](https://www.docker.com/toolbox)
|
||||
* [ubuntu](https://docs.docker.com/installation/ubuntulinux/)
|
||||
|
||||
## Running the container
|
||||
|
||||
We are using `Makefile` to simplify docker commands within make commands.
|
||||
|
||||
Build the container and start a jupyter notebook
|
||||
|
||||
$ make notebook
|
||||
|
||||
Build the container and start an iPython shell
|
||||
|
||||
$ make ipython
|
||||
|
||||
Build the container and start a bash
|
||||
|
||||
$ make bash
|
||||
|
||||
For GPU support install NVidia drivers (ideally latest) and
|
||||
[nvidia-docker](https://github.com/NVIDIA/nvidia-docker). Run using
|
||||
|
||||
$ make notebook GPU=0 # or [ipython, bash]
|
||||
|
||||
Switch between Theano and TensorFlow
|
||||
|
||||
$ make notebook BACKEND=theano
|
||||
$ make notebook BACKEND=tensorflow
|
||||
|
||||
Mount a volume for external data sets
|
||||
|
||||
$ make DATA=~/mydata
|
||||
|
||||
Prints all make tasks
|
||||
|
||||
$ make help
|
||||
|
||||
You can change Theano parameters by editing `/docker/theanorc`.
|
||||
|
||||
|
||||
Note: If you would have a problem running nvidia-docker you may try the old way
|
||||
we have used. But it is not recommended. If you find a bug in the nvidia-docker report
|
||||
it there please and try using the nvidia-docker as described above.
|
||||
|
||||
$ export CUDA_SO=$(\ls /usr/lib/x86_64-linux-gnu/libcuda.* | xargs -I{} echo '-v {}:{}')
|
||||
$ export DEVICES=$(\ls /dev/nvidia* | xargs -I{} echo '--device {}:{}')
|
||||
$ docker run -it -p 8888:8888 $CUDA_SO $DEVICES gcr.io/tensorflow/tensorflow:latest-gpu
|
||||
@@ -0,0 +1,5 @@
|
||||
[global]
|
||||
floatX = float32
|
||||
optimizer=None
|
||||
device = gpu
|
||||
|
||||
+28
-8
@@ -65,6 +65,8 @@ if sys.version[0] == '2':
|
||||
sys.setdefaultencoding('utf8')
|
||||
|
||||
from keras.layers import convolutional
|
||||
from keras.layers import pooling
|
||||
from keras.layers import local
|
||||
from keras.layers import recurrent
|
||||
from keras.layers import core
|
||||
from keras.layers import noise
|
||||
@@ -88,6 +90,7 @@ EXCLUDE = {
|
||||
'Wrapper',
|
||||
'get_session',
|
||||
'set_session',
|
||||
'CallbackList',
|
||||
}
|
||||
|
||||
PAGES = [
|
||||
@@ -105,6 +108,7 @@ PAGES = [
|
||||
models.Sequential.predict_on_batch,
|
||||
models.Sequential.fit_generator,
|
||||
models.Sequential.evaluate_generator,
|
||||
models.Sequential.predict_generator,
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -119,6 +123,7 @@ PAGES = [
|
||||
models.Model.predict_on_batch,
|
||||
models.Model.fit_generator,
|
||||
models.Model.evaluate_generator,
|
||||
models.Model.predict_generator,
|
||||
models.Model.get_layer,
|
||||
]
|
||||
},
|
||||
@@ -128,6 +133,8 @@ PAGES = [
|
||||
core.Dense,
|
||||
core.Activation,
|
||||
core.Dropout,
|
||||
core.SpatialDropout2D,
|
||||
core.SpatialDropout3D,
|
||||
core.Flatten,
|
||||
core.Reshape,
|
||||
core.Permute,
|
||||
@@ -145,8 +152,11 @@ PAGES = [
|
||||
'page': 'layers/convolutional.md',
|
||||
'classes': [
|
||||
convolutional.Convolution1D,
|
||||
convolutional.AtrousConvolution1D,
|
||||
convolutional.Convolution2D,
|
||||
convolutional.AtrousConv2D,
|
||||
convolutional.AtrousConvolution2D,
|
||||
convolutional.SeparableConvolution2D,
|
||||
convolutional.Deconvolution2D,
|
||||
convolutional.Convolution3D,
|
||||
convolutional.UpSampling1D,
|
||||
convolutional.UpSampling2D,
|
||||
@@ -159,12 +169,23 @@ PAGES = [
|
||||
{
|
||||
'page': 'layers/pooling.md',
|
||||
'classes': [
|
||||
convolutional.MaxPooling1D,
|
||||
convolutional.MaxPooling2D,
|
||||
convolutional.MaxPooling3D,
|
||||
convolutional.AveragePooling1D,
|
||||
convolutional.AveragePooling2D,
|
||||
convolutional.AveragePooling3D,
|
||||
pooling.MaxPooling1D,
|
||||
pooling.MaxPooling2D,
|
||||
pooling.MaxPooling3D,
|
||||
pooling.AveragePooling1D,
|
||||
pooling.AveragePooling2D,
|
||||
pooling.AveragePooling3D,
|
||||
pooling.GlobalMaxPooling1D,
|
||||
pooling.GlobalAveragePooling1D,
|
||||
pooling.GlobalMaxPooling2D,
|
||||
pooling.GlobalAveragePooling2D,
|
||||
],
|
||||
},
|
||||
{
|
||||
'page': 'layers/local.md',
|
||||
'classes': [
|
||||
local.LocallyConnected1D,
|
||||
local.LocallyConnected2D,
|
||||
],
|
||||
},
|
||||
{
|
||||
@@ -201,7 +222,6 @@ PAGES = [
|
||||
'all_module_classes': [wrappers],
|
||||
},
|
||||
|
||||
|
||||
{
|
||||
'page': 'optimizers.md',
|
||||
'all_module_classes': [optimizers],
|
||||
|
||||
@@ -25,6 +25,7 @@ pages:
|
||||
- Core Layers: layers/core.md
|
||||
- Convolutional Layers: layers/convolutional.md
|
||||
- Pooling Layers: layers/pooling.md
|
||||
- Locally-connected Layers: layers/local.md
|
||||
- Recurrent Layers: layers/recurrent.md
|
||||
- Embedding Layers: layers/embeddings.md
|
||||
- Advanced Activations Layers: layers/advanced-activations.md
|
||||
@@ -41,6 +42,7 @@ pages:
|
||||
- Activations: activations.md
|
||||
- Callbacks: callbacks.md
|
||||
- Datasets: datasets.md
|
||||
- Applications: applications.md
|
||||
- Backend: backend.md
|
||||
- Initializations: initializations.md
|
||||
- Regularizers: regularizers.md
|
||||
|
||||
externo
+260
@@ -0,0 +1,260 @@
|
||||
# Applications
|
||||
|
||||
Keras Applications are deep learning models that are made available alongside pre-trained weights.
|
||||
These models can be used for prediction, feature extraction, and fine-tuning.
|
||||
|
||||
Weights are downloaded automatically when instantiating a model. They are stored at `~/.keras/models/`.
|
||||
|
||||
## Available models
|
||||
|
||||
Models for image classification with weights trained on ImageNet:
|
||||
|
||||
- [VGG16](#vgg16)
|
||||
- [VGG19](#vgg19)
|
||||
- [ResNet50](#resnet50)
|
||||
- [InceptionV3](#inceptionv3)
|
||||
|
||||
All of these architectures are compatible with both TensorFlow and Theano, and upon instantiation the models will be built according to the image dimension ordering set in your Keras configuration file at `~/.keras/keras.json`. For instance, if you have set `image_dim_ordering=tf`, then any model loaded from this repository will get built according to the TensorFlow dimension ordering convention, "Width-Height-Depth".
|
||||
|
||||
-----
|
||||
|
||||
## Examples
|
||||
|
||||
### Classify ImageNet classes with ResNet50
|
||||
|
||||
```python
|
||||
from keras.applications.resnet50 import ResNet50
|
||||
from keras.preprocessing import image
|
||||
from keras.applications.resnet50 import preprocess_input, decode_predictions
|
||||
|
||||
model = ResNet50(weights='imagenet')
|
||||
|
||||
img_path = 'elephant.jpg'
|
||||
img = image.load_img(img_path, target_size=(224, 224))
|
||||
x = image.img_to_array(img)
|
||||
x = np.expand_dims(x, axis=0)
|
||||
x = preprocess_input(x)
|
||||
|
||||
preds = model.predict(x)
|
||||
print('Predicted:', decode_predictions(preds))
|
||||
# print: [[u'n02504458', u'African_elephant']]
|
||||
```
|
||||
|
||||
### Extract features with VGG16
|
||||
|
||||
```python
|
||||
from keras.applications.vgg16 import VGG16
|
||||
from keras.preprocessing import image
|
||||
from keras.applications.vgg16 import preprocess_input
|
||||
|
||||
model = VGG16(weights='imagenet', include_top=False)
|
||||
|
||||
img_path = 'elephant.jpg'
|
||||
img = image.load_img(img_path, target_size=(224, 224))
|
||||
x = image.img_to_array(img)
|
||||
x = np.expand_dims(x, axis=0)
|
||||
x = preprocess_input(x)
|
||||
|
||||
features = model.predict(x)
|
||||
```
|
||||
|
||||
### Extract features from an arbitrary intermediate layer with VGG19
|
||||
|
||||
```python
|
||||
from keras.applications.vgg19 import VGG19
|
||||
from keras.preprocessing import image
|
||||
from keras.applications.vgg19 import preprocess_input
|
||||
from keras.models import Model
|
||||
|
||||
base_model = VGG19(weights='imagenet')
|
||||
model = Model(input=base_model.input, output=base_model.get_layer('block4_pool').output)
|
||||
|
||||
img_path = 'elephant.jpg'
|
||||
img = image.load_img(img_path, target_size=(224, 224))
|
||||
x = image.img_to_array(img)
|
||||
x = np.expand_dims(x, axis=0)
|
||||
x = preprocess_input(x)
|
||||
|
||||
block4_pool_features = model.predict(x)
|
||||
```
|
||||
|
||||
### Fine-tune InceptionV3 on a new set of classes
|
||||
|
||||
```python
|
||||
from keras.applications.inception_v3 import InceptionV3
|
||||
from keras.preprocessing import image
|
||||
from keras.models import Model
|
||||
from keras.layers import Dense, GlobalAveragePooling2D
|
||||
from keras import backend as K
|
||||
|
||||
# create the base pre-trained model
|
||||
base_model = InceptionV3(weights='imagenet', include_top=False)
|
||||
|
||||
# add a global spatial average pooling layer
|
||||
x = base_model.output
|
||||
x = GlobalAveragePooling2D()(x)
|
||||
# let's add a fully-connected layer
|
||||
x = Dense(1024, activation='relu')(x)
|
||||
# and a logistic layer -- let's say we have 200 classes
|
||||
predictions = Dense(200, activation='softmax')(x)
|
||||
|
||||
# this is the model we will train
|
||||
model = Model(input=base_model.input, output=predictions)
|
||||
|
||||
# first: train only the top layers (which were randomly initialized)
|
||||
# i.e. freeze all convolutional InceptionV3 layers
|
||||
for layer in base_model.layers:
|
||||
layer.trainable = False
|
||||
|
||||
# compile the model (should be done *after* setting layers to non-trainable)
|
||||
model.compile(optimizer='rmsprop', loss='categorical_crossentropy')
|
||||
|
||||
# train the model on the new data for a few epochs
|
||||
model.fit_generator(...)
|
||||
|
||||
# at this point, the top layers are well trained and we can start fine-tuning
|
||||
# convolutional layers from inception V3. We will freeze the bottom N layers
|
||||
# and train the remaining top layers.
|
||||
|
||||
# let's visualize layer names and layer indices to see how many layers
|
||||
# we should freeze:
|
||||
for i, layer in enumerate(base_model.layers):
|
||||
print(i, layer.name)
|
||||
|
||||
# we chose to train the top 2 inception blocks, i.e. we will freeze
|
||||
# the first 172 layers and unfreeze the rest:
|
||||
for layer in model.layers[:172]:
|
||||
layer.trainable = False
|
||||
for layer in model.layers[172:]:
|
||||
layer.trainable = True
|
||||
|
||||
# we need to recompile the model for these modifications to take effect
|
||||
# we use SGD with a low learning rate
|
||||
from keras.optimizers import SGD
|
||||
model.compile(optimizer=SGD(lr=0.0001, momentum=0.9), loss='categorical_crossentropy')
|
||||
|
||||
# we train our model again (this time fine-tuning the top 2 inception blocks
|
||||
# alongside the top Dense layers
|
||||
model.fit_generator(...)
|
||||
```
|
||||
|
||||
|
||||
### Build InceptionV3 over a custom input tensor
|
||||
|
||||
```python
|
||||
from keras.applications.inception_v3 import InceptionV3
|
||||
from keras.layers import Input
|
||||
|
||||
# this could also be the output a different Keras model or layer
|
||||
input_tensor = Input(shape=(224, 224, 3)) # this assumes K.image_dim_ordering() == 'tf'
|
||||
|
||||
model = InceptionV3(input_tensor=input_tensor, weights='imagenet', include_top=True)
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## VGG16
|
||||
|
||||
```python
|
||||
keras.applications.vgg16.VGG16(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
### References
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556): please cite this paper if you use the VGG models in your work.
|
||||
|
||||
### License
|
||||
|
||||
These weights are ported from the ones [released by VGG at Oxford](http://www.robots.ox.ac.uk/~vgg/research/very_deep/) under the [Creative Commons Attribution License](https://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
-----
|
||||
|
||||
## VGG19
|
||||
|
||||
|
||||
```python
|
||||
keras.applications.vgg19.VGG19(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
|
||||
### References
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)
|
||||
|
||||
### License
|
||||
|
||||
These weights are ported from the ones [released by VGG at Oxford](http://www.robots.ox.ac.uk/~vgg/research/very_deep/) under the [Creative Commons Attribution License](https://creativecommons.org/licenses/by/4.0/).
|
||||
|
||||
-----
|
||||
|
||||
## ResNet50
|
||||
|
||||
|
||||
```python
|
||||
keras.applications.resnet50.ResNet50(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
### References
|
||||
|
||||
- [Deep Residual Learning for Image Recognition](https://arxiv.org/abs/1512.03385)
|
||||
|
||||
### License
|
||||
|
||||
These weights are ported from the ones [released by Kaiming He](https://github.com/KaimingHe/deep-residual-networks) under the [MIT license](https://github.com/KaimingHe/deep-residual-networks/blob/master/LICENSE).
|
||||
|
||||
-----
|
||||
|
||||
## InceptionV3
|
||||
|
||||
|
||||
```python
|
||||
keras.applications.inception_v3.InceptionV3(include_top=True, weights='imagenet', input_tensor=None)
|
||||
```
|
||||
|
||||
### Arguments
|
||||
|
||||
- include_top: whether to include the 3 fully-connected layers at the top of the network.
|
||||
- weights: one of `None` (random initialization) or "imagenet" (pre-training on ImageNet).
|
||||
- input_tensor: optional Keras tensor (i.e. output of `layers.Input()`) to use as image input for the model.
|
||||
|
||||
### Returns
|
||||
|
||||
A Keras model instance.
|
||||
|
||||
### References
|
||||
|
||||
- [Rethinking the Inception Architecture for Computer Vision](http://arxiv.org/abs/1512.00567)
|
||||
|
||||
### License
|
||||
|
||||
These weights are trained by ourselves and are released under the MIT license.
|
||||
externo
+14
-6
@@ -4,10 +4,12 @@
|
||||
|
||||
Keras is a model-level library, providing high-level building blocks for developing deep learning models. It does not handle itself low-level operations such as tensor products, convolutions and so on. Instead, it relies on a specialized, well-optimized tensor manipulation library to do so, serving as the "backend engine" of Keras. Rather than picking one single tensor library and making the implementation of Keras tied to that library, Keras handles the problem in a modular way, and several different backend engines can be plugged seamlessly into Keras.
|
||||
|
||||
At this time, Keras has two backend implementations available: the **Theano** backend and the **TensorFlow** backend.
|
||||
At this time, Keras has two backend implementations available: the **TensorFlow** backend and the **Theano** backend.
|
||||
|
||||
- [Theano](http://deeplearning.net/software/theano/) is an open-source symbolic tensor manipulation framework developed by LISA/MILA Lab at Université de Montréal.
|
||||
- [TensorFlow](http://www.tensorflow.org/) is an open-source symbolic tensor manipulation framework developed by Google, Inc.
|
||||
- [Theano](http://deeplearning.net/software/theano/) is an open-source symbolic tensor manipulation framework developed by LISA/MILA Lab at Université de Montréal.
|
||||
|
||||
In the future, we are likely to add more backend options. If you are interested in developing a new backend, get in touch!
|
||||
|
||||
----
|
||||
|
||||
@@ -19,9 +21,16 @@ If you have run Keras at least once, you will find the Keras configuration file
|
||||
|
||||
If it isn't there, you can create it.
|
||||
|
||||
It probably looks like this:
|
||||
The default configuration file looks like this:
|
||||
|
||||
`{"epsilon": 1e-07, "floatx": "float32", "backend": "theano"}`
|
||||
```
|
||||
{
|
||||
"image_dim_ordering": "tf",
|
||||
"epsilon": 1e-07,
|
||||
"floatx": "float32",
|
||||
"backend": "tensorflow"
|
||||
}
|
||||
```
|
||||
|
||||
Simply change the field `backend` to either `"theano"` or `"tensorflow"`, and Keras will use the new configuration next time you run any Keras code.
|
||||
|
||||
@@ -29,9 +38,8 @@ You can also define the environment variable ``KERAS_BACKEND`` and this will
|
||||
override what is defined in your config file :
|
||||
|
||||
```bash
|
||||
KERAS_BACKEND=tensorflow python -c "from keras import backend; print backend._BACKEND"
|
||||
KERAS_BACKEND=tensorflow python -c "from keras import backend"
|
||||
Using TensorFlow backend.
|
||||
tensorflow
|
||||
```
|
||||
|
||||
----
|
||||
|
||||
externo
+18
-5
@@ -53,11 +53,14 @@ As a convention, "0" does not stand for a specific word, but instead is used to
|
||||
```python
|
||||
from keras.datasets import imdb
|
||||
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(path="imdb.pkl",
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(path="imdb_full.pkl",
|
||||
nb_words=None,
|
||||
skip_top=0,
|
||||
maxlen=None,
|
||||
test_split=0.1)
|
||||
seed=113,
|
||||
start_char=1,
|
||||
oov_char=2,
|
||||
index_from=3)
|
||||
```
|
||||
- __Return:__
|
||||
- 2 tuples:
|
||||
@@ -70,8 +73,12 @@ from keras.datasets import imdb
|
||||
- __nb_words__: integer or None. Top most frequent words to consider. Any less frequent word will appear as 0 in the sequence data.
|
||||
- __skip_top__: integer. Top most frequent words to ignore (they will appear as 0s in the sequence data).
|
||||
- __maxlen__: int. Maximum sequence length. Any longer sequence will be truncated.
|
||||
- __test_split__: float. Fraction of the dataset to be used as test data.
|
||||
- __seed__: int. Seed for reproducible data shuffling.
|
||||
- __start_char__: char. The start of a sequence will be marked with this character.
|
||||
Set to 1 because 0 is usually the padding character.
|
||||
- __oov_char__: char. words that were cut out because of the `nb_words`
|
||||
or `skip_top` limit will be replaced with this character.
|
||||
- __index_from__: int. Index actual words with this index and higher.
|
||||
|
||||
---
|
||||
|
||||
@@ -88,10 +95,16 @@ from keras.datasets import reuters
|
||||
nb_words=None,
|
||||
skip_top=0,
|
||||
maxlen=None,
|
||||
test_split=0.1)
|
||||
test_split=0.2,
|
||||
seed=113,
|
||||
start_char=1,
|
||||
oov_char=2,
|
||||
index_from=3)
|
||||
```
|
||||
|
||||
The specifications are the same as that of the IMDB dataset.
|
||||
The specifications are the same as that of the IMDB dataset, with the addition of:
|
||||
|
||||
- __test_split__: float. Fraction of the dataset to be used as test data.
|
||||
|
||||
This dataset also makes available the word index used for encoding the sequences:
|
||||
|
||||
|
||||
+69
-18
@@ -58,7 +58,31 @@ theano.config.floatX = 'float32'
|
||||
|
||||
*It is not recommended to use pickle or cPickle to save a Keras model.*
|
||||
|
||||
If you only need to save the architecture of a model, and not its weights, you can do:
|
||||
You can use `model.save(filepath)` to save a Keras model into a single HDF5 file which will contain:
|
||||
|
||||
- the architecture of the model, allowing to re-create the model
|
||||
- the weights of the model
|
||||
- the training configuration (loss, optimizer)
|
||||
- the state of the optimizer, allowing to resume training exactly where you left off.
|
||||
|
||||
You can then use `keras.models.load_model(filepath)` to reinstantiate your model.
|
||||
`load_model` will also take care of compiling the model using the saved training configuration
|
||||
(unless the model was never compiled in the first place).
|
||||
|
||||
Example:
|
||||
|
||||
```python
|
||||
from keras.models import load_model
|
||||
|
||||
model.save('my_model.h5') # creates a HDF5 file 'my_model.h5'
|
||||
del model # deletes the existing model
|
||||
|
||||
# returns a compiled model
|
||||
# identical to the previous one
|
||||
model = load_model('my_model.h5')
|
||||
```
|
||||
|
||||
If you only need to save the **architecture of a model**, and not its weights or its training configuration, you can do:
|
||||
|
||||
```python
|
||||
# save as JSON
|
||||
@@ -68,6 +92,8 @@ json_string = model.to_json()
|
||||
yaml_string = model.to_yaml()
|
||||
```
|
||||
|
||||
The generated JSON / YAML files are human-readable and can be manually edited if needed.
|
||||
|
||||
You can then build a fresh model from this data:
|
||||
|
||||
```python
|
||||
@@ -79,7 +105,7 @@ model = model_from_json(json_string)
|
||||
model = model_from_yaml(yaml_string)
|
||||
```
|
||||
|
||||
If you need to save the weights of a model, you can do so in HDF5 with the code below.
|
||||
If you need to save the **weights of a model**, you can do so in HDF5 with the code below.
|
||||
|
||||
Note that you will first need to install HDF5 and the Python library h5py, which do not come bundled with Keras.
|
||||
|
||||
@@ -87,26 +113,37 @@ Note that you will first need to install HDF5 and the Python library h5py, which
|
||||
model.save_weights('my_model_weights.h5')
|
||||
```
|
||||
|
||||
Assuming you have code for instantiating your model, you can then load the weights you saved into a model with the same architecture:
|
||||
Assuming you have code for instantiating your model, you can then load the weights you saved into a model with the *same* architecture:
|
||||
|
||||
```python
|
||||
model.load_weights('my_model_weights.h5')
|
||||
```
|
||||
|
||||
This leads us to a way to save and reconstruct models from only serialized data:
|
||||
```python
|
||||
json_string = model.to_json()
|
||||
open('my_model_architecture.json', 'w').write(json_string)
|
||||
model.save_weights('my_model_weights.h5')
|
||||
If you need to load weights into a *different* architecture (with some layers in common), for instance for fine-tuning or transfer-learning, you can load weights by *layer name*:
|
||||
|
||||
# elsewhere...
|
||||
model = model_from_json(open('my_model_architecture.json').read())
|
||||
model.load_weights('my_model_weights.h5')
|
||||
```python
|
||||
model.load_weights('my_model_weights.h5', by_name=True)
|
||||
```
|
||||
|
||||
Finally, before it can be used, the model shall be compiled.
|
||||
For example:
|
||||
|
||||
```python
|
||||
model.compile(optimizer='adagrad', loss='mse')
|
||||
"""
|
||||
Assume original model looks like this:
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="dense_1"))
|
||||
model.add(Dense(3, name="dense_2"))
|
||||
...
|
||||
model.save_weights(fname)
|
||||
"""
|
||||
|
||||
# new model
|
||||
model = Sequential()
|
||||
model.add(Dense(2, input_dim=3, name="dense_1")) # will be loaded
|
||||
model.add(Dense(10, name="new_dense")) # will not be loaded
|
||||
|
||||
# load weights from first model; will only affect the first layer, dense_1.
|
||||
model.load_weights(fname, by_name=True)
|
||||
```
|
||||
|
||||
---
|
||||
@@ -321,13 +358,27 @@ print(len(model.layers)) # "1"
|
||||
|
||||
Code and pre-trained weights are available for the following image classification models:
|
||||
|
||||
- [VGG-16](https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
|
||||
- [VGG-19](https://gist.github.com/baraldilorenzo/8d096f48a1be4a2d660d)
|
||||
- [AlexNet](https://github.com/heuritech/convnets-keras)
|
||||
- VGG16
|
||||
- VGG19
|
||||
- ResNet50
|
||||
- Inception v3
|
||||
|
||||
For an example of how to use such a pre-trained model for feature extraction or for fine-tuning, see [this blog post](http://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html).
|
||||
They can be imported from the module `keras.applications`:
|
||||
|
||||
The VGG-16 model is also the basis for several Keras example scripts:
|
||||
```python
|
||||
from keras.applications.vgg16 import VGG16
|
||||
from keras.applications.vgg19 import VGG19
|
||||
from keras.applications.resnet50 import ResNet50
|
||||
from keras.applications.inception_v3 import InceptionV3
|
||||
|
||||
model = VGG16(weights='imagenet', include_top=True)
|
||||
```
|
||||
|
||||
For a few simple usage examples, see [the documentation for the Applications module](/applications).
|
||||
|
||||
For a detailed example of how to use such a pre-trained model for feature extraction or for fine-tuning, see [this blog post](http://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html).
|
||||
|
||||
The VGG16 model is also the basis for several Keras example scripts:
|
||||
|
||||
- [Style transfer](https://github.com/fchollet/keras/blob/master/examples/neural_style_transfer.py)
|
||||
- [Feature visualization](https://github.com/fchollet/keras/blob/master/examples/conv_filter_visualization.py)
|
||||
|
||||
@@ -75,7 +75,7 @@ The model will also be supervised via two loss functions. Using the main loss fu
|
||||
|
||||
Here's what our model looks like:
|
||||
|
||||
<img src="http://s3.amazonaws.com/keras.io/img/multi-input-multi-output-graph.png" alt="multi-input-multi-output-graph" style="width: 400px;"/>
|
||||
<img src="https://s3.amazonaws.com/keras.io/img/multi-input-multi-output-graph.png" alt="multi-input-multi-output-graph" style="width: 400px;"/>
|
||||
|
||||
Let's implement it with the functional API.
|
||||
|
||||
@@ -310,7 +310,7 @@ from keras.layers import merge, Convolution2D, Input
|
||||
# input tensor for a 3-channel 256x256 image
|
||||
x = Input(shape=(3, 256, 256))
|
||||
# 3x3 conv with 3 output channels (same as input channels)
|
||||
y = Convolution2D(3, 3, 3, border_mode='same')
|
||||
y = Convolution2D(3, 3, 3, border_mode='same')(x)
|
||||
# this returns x + y.
|
||||
z = merge([x, y], mode='sum')
|
||||
```
|
||||
|
||||
@@ -86,7 +86,7 @@ final_model.add(merged)
|
||||
final_model.add(Dense(10, activation='softmax'))
|
||||
```
|
||||
|
||||
<img src="http://s3.amazonaws.com/keras.io/img/two_branches_sequential_model.png" alt="two branch Sequential" style="width: 400px;"/>
|
||||
<img src="https://s3.amazonaws.com/keras.io/img/two_branches_sequential_model.png" alt="two branch Sequential" style="width: 400px;"/>
|
||||
|
||||
Such a two-branch model can then be trained via e.g.:
|
||||
|
||||
@@ -107,7 +107,7 @@ The `Merge` layer supports a number of pre-defined modes:
|
||||
You can also pass a function as the `mode` argument, allowing for arbitrary transformations:
|
||||
|
||||
```python
|
||||
merged = Merge([left_branch, right_branch], mode=lambda x, y: x - y)
|
||||
merged = Merge([left_branch, right_branch], mode=lambda x: x[0] - x[1])
|
||||
```
|
||||
|
||||
Now you know enough to be able to define *almost* any model with Keras. For complex models that cannot be expressed via `Sequential` and `Merge`, you can use [the functional API](/getting-started/functional-api-guide).
|
||||
@@ -149,7 +149,7 @@ Keras models are trained on Numpy arrays of input data and labels. For training
|
||||
# for a single-input model with 2 classes (binary):
|
||||
|
||||
model = Sequential()
|
||||
model.add(Dense(1, input_dim=784, activation='softmax'))
|
||||
model.add(Dense(1, input_dim=784, activation='sigmoid'))
|
||||
model.compile(optimizer='rmsprop',
|
||||
loss='binary_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
@@ -418,7 +418,7 @@ The first two LSTMs return their full output sequences, but the last one only re
|
||||
the last step in its output sequence, thus dropping the temporal dimension
|
||||
(i.e. converting the input sequence into a single vector).
|
||||
|
||||
<img src="http://keras.io/img/regular_stacked_lstm.png" alt="stacked LSTM" style="width: 300px;"/>
|
||||
<img src="https://keras.io/img/regular_stacked_lstm.png" alt="stacked LSTM" style="width: 300px;"/>
|
||||
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
@@ -507,7 +507,7 @@ In this model, two input sequences are encoded into vectors by two separate LSTM
|
||||
|
||||
These two vectors are then concatenated, and a fully connected network is trained on top of the concatenated representations.
|
||||
|
||||
<img src="http://keras.io/img/dual_lstm.png" alt="Dual LSTM" style="width: 600px;"/>
|
||||
<img src="https://keras.io/img/dual_lstm.png" alt="Dual LSTM" style="width: 600px;"/>
|
||||
|
||||
```python
|
||||
from keras.models import Sequential
|
||||
|
||||
externo
+15
-14
@@ -2,14 +2,14 @@
|
||||
|
||||
## You have just found Keras.
|
||||
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. Being able to go from idea to result with the least possible delay is key to doing good research.
|
||||
Keras is a minimalist, highly modular neural networks library, written in Python and capable of running on top of either [TensorFlow](https://github.com/tensorflow/tensorflow) or [Theano](https://github.com/Theano/Theano). It was developed with a focus on enabling fast experimentation. *Being able to go from idea to result with the least possible delay is key to doing good research.*
|
||||
|
||||
Use Keras if you need a deep learning library that:
|
||||
|
||||
- allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- runs seamlessly on CPU and GPU.
|
||||
- Allows for easy and fast prototyping (through total modularity, minimalism, and extensibility).
|
||||
- Supports both convolutional networks and recurrent networks, as well as combinations of the two.
|
||||
- Supports arbitrary connectivity schemes (including multi-input and multi-output training).
|
||||
- Runs seamlessly on CPU and GPU.
|
||||
|
||||
Read the documentation at [Keras.io](http://keras.io).
|
||||
|
||||
@@ -33,7 +33,6 @@ 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 functional API](http://keras.io/getting-started/functional-api-guide).
|
||||
@@ -98,6 +97,7 @@ For a more in-depth tutorial about Keras, you can check out:
|
||||
|
||||
In the [examples folder](https://github.com/fchollet/keras/tree/master/examples) of the repository, you will find more advanced models: question-answering with memory networks, text generation with stacked LSTMs, etc.
|
||||
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
@@ -110,32 +110,33 @@ Keras uses the following dependencies:
|
||||
- HDF5 and h5py (optional, required if you use model saving/loading functions)
|
||||
- Optional but recommended if you use CNNs: cuDNN.
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
*When using the TensorFlow backend:*
|
||||
|
||||
- TensorFlow
|
||||
- [See installation instructions](https://github.com/tensorflow/tensorflow#download-and-setup).
|
||||
|
||||
*When using the Theano backend:*
|
||||
|
||||
- Theano
|
||||
- [See installation instructions](http://deeplearning.net/software/theano/install.html#install).
|
||||
|
||||
To install Keras, `cd` to the Keras folder and run the install command:
|
||||
```
|
||||
```sh
|
||||
sudo python setup.py install
|
||||
```
|
||||
|
||||
You can also install Keras from PyPI:
|
||||
```
|
||||
```sh
|
||||
sudo pip install keras
|
||||
```
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
## Switching from Theano to TensorFlow
|
||||
## Switching from TensorFlow to Theano
|
||||
|
||||
By default, Keras will use Theano as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
By default, Keras will use TensorFlow as its tensor manipulation library. [Follow these instructions](http://keras.io/backend/) to configure the Keras backend.
|
||||
|
||||
------------------
|
||||
|
||||
|
||||
+1
-1
@@ -30,4 +30,4 @@ yaml_string = model.to_yaml()
|
||||
model = model_from_yaml(yaml_string)
|
||||
```
|
||||
- `model.save_weights(filepath)`: saves the weights of the model as a HDF5 file.
|
||||
- `model.load_weights(filepath)`: loads the weights of the model from a HDF5 file (created by `save_weights`).
|
||||
- `model.load_weights(filepath, by_name=False)`: loads the weights of the model from a HDF5 file (created by `save_weights`). By default, the architecture is expected to be unchanged. To load weights into a different architecture (with some layers in common), use `by_name=True` to load only those layers with the same name.
|
||||
externo
+20
-1
@@ -9,7 +9,7 @@ model.add(Dense(64, init='uniform', input_dim=10))
|
||||
model.add(Activation('tanh'))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
sgd = SGD(lr=0.01, decay=1e-6, momentum=0.9, nesterov=True)
|
||||
model.compile(loss='mean_squared_error', optimizer=sgd)
|
||||
```
|
||||
|
||||
@@ -22,4 +22,23 @@ model.compile(loss='mean_squared_error', optimizer='sgd')
|
||||
|
||||
---
|
||||
|
||||
## Parameters common to all Keras optimizers
|
||||
|
||||
The parameters `clipnorm` and `clipvalue` can be used with all optimizers to control gradient clipping:
|
||||
|
||||
```python
|
||||
# all parameter gradients will be clipped to
|
||||
# a maximum norm of 1.
|
||||
sgd = SGD(lr=0.01, clipnorm=1.)
|
||||
```
|
||||
|
||||
```python
|
||||
# all parameter gradients will be clipped to
|
||||
# a maximum value of 0.5 and
|
||||
# a minimum value of -0.5.
|
||||
sgd = SGD(lr=0.01, clipvalue=0.5)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
{{autogenerated}}
|
||||
+4
-4
@@ -61,15 +61,15 @@ Generate batches of tensor image data with real-time data augmentation. The data
|
||||
- __X__: data.
|
||||
- __y__: labels.
|
||||
- __batch_size__: int (default: 32).
|
||||
- __shuffle__: boolean (defaut: False).
|
||||
- __shuffle__: boolean (defaut: True).
|
||||
- __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.
|
||||
- __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,
|
||||
- __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.
|
||||
@@ -88,7 +88,7 @@ Generate batches of tensor image data with real-time data augmentation. The data
|
||||
Example of using `.flow(X, y)`:
|
||||
|
||||
```python
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data(test_split=0.1)
|
||||
(X_train, y_train), (X_test, y_test) = cifar10.load_data()
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
# 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`.
|
||||
You can use `Sequential` Keras models (single-input only) as part of your Scikit-Learn workflow via the wrappers found at `keras.wrappers.scikit_learn.py`.
|
||||
|
||||
There are two wrappers available:
|
||||
|
||||
`keras.wrappers.sklearn.KerasClassifier(build_fn=None, **sk_params)`, which implements the sklearn classifier interface,
|
||||
`keras.wrappers.scikit_learn.KerasClassifier(build_fn=None, **sk_params)`, which implements the Scikit-Learn classifier interface,
|
||||
|
||||
`keras.wrappers.sklearn.KerasRegressor(build_fn=None, **sk_params)`, which implements the sklearn regressor interface.
|
||||
`keras.wrappers.scikit_learn.KerasRegressor(build_fn=None, **sk_params)`, which implements the Scikit-Learn regressor interface.
|
||||
|
||||
### Arguments
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ def vectorize_stories(data, word_idx, story_maxlen, query_maxlen):
|
||||
|
||||
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='https://s3.amazonaws.com/text-datasets/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'
|
||||
@@ -173,6 +173,7 @@ match = Sequential()
|
||||
match.add(Merge([input_encoder_m, question_encoder],
|
||||
mode='dot',
|
||||
dot_axes=[2, 2]))
|
||||
match.add(Activation('softmax'))
|
||||
# output: (samples, story_maxlen, query_maxlen)
|
||||
# embed the input into a single vector with size = story_maxlen:
|
||||
input_encoder_c = Sequential()
|
||||
|
||||
@@ -147,7 +147,7 @@ EPOCHS = 40
|
||||
print('RNN / Embed / Sent / Query = {}, {}, {}, {}'.format(RNN, EMBED_HIDDEN_SIZE, SENT_HIDDEN_SIZE, QUERY_HIDDEN_SIZE))
|
||||
|
||||
try:
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='http://www.thespermwhale.com/jaseweston/babi/tasks_1-20_v1-2.tar.gz')
|
||||
path = get_file('babi-tasks-v1-2.tar.gz', origin='https://s3.amazonaws.com/text-datasets/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'
|
||||
|
||||
@@ -43,7 +43,7 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
model = Sequential()
|
||||
|
||||
model.add(Convolution2D(32, 3, 3, border_mode='same',
|
||||
input_shape=(img_channels, img_rows, img_cols)))
|
||||
input_shape=X_train.shape[1:]))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(32, 3, 3))
|
||||
model.add(Activation('relu'))
|
||||
|
||||
@@ -3,32 +3,21 @@
|
||||
This script can run on CPU in a few minutes (with the TensorFlow backend).
|
||||
|
||||
Results example: http://i.imgur.com/4nj4KjN.jpg
|
||||
|
||||
Before running this script, download the weights for the VGG16 model at:
|
||||
https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
|
||||
(source: https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
|
||||
and make sure the variable `weights_path` in this script matches the location of the file.
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from scipy.misc import imsave
|
||||
import numpy as np
|
||||
import time
|
||||
import os
|
||||
import h5py
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.applications import vgg16
|
||||
from keras import backend as K
|
||||
|
||||
# dimensions of the generated pictures for each filter.
|
||||
img_width = 128
|
||||
img_height = 128
|
||||
|
||||
# path to the model weights file.
|
||||
weights_path = 'vgg16_weights.h5'
|
||||
|
||||
# the name of the layer we want to visualize (see model definition below)
|
||||
layer_name = 'conv5_1'
|
||||
# the name of the layer we want to visualize
|
||||
# (see model definition at keras/applications/vgg16.py)
|
||||
layer_name = 'block5_conv1'
|
||||
|
||||
# util function to convert a tensor into a valid image
|
||||
def deprocess_image(x):
|
||||
@@ -43,70 +32,22 @@ def deprocess_image(x):
|
||||
|
||||
# convert to RGB array
|
||||
x *= 255
|
||||
x = x.transpose((1, 2, 0))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.transpose((1, 2, 0))
|
||||
x = np.clip(x, 0, 255).astype('uint8')
|
||||
return x
|
||||
|
||||
# build the VGG16 network
|
||||
model = Sequential()
|
||||
model.add(ZeroPadding2D((1, 1), batch_input_shape=(1, 3, img_width, img_height)))
|
||||
first_layer = model.layers[-1]
|
||||
# this is a placeholder tensor that will contain our generated images
|
||||
input_img = first_layer.input
|
||||
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_2'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_2'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_3'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_3'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_3'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
# load the weights of the VGG16 networks
|
||||
# (trained on ImageNet, won the ILSVRC competition in 2014)
|
||||
# note: when there is a complete match between your model definition
|
||||
# and your weight savefile, you can simply call model.load_weights(filename)
|
||||
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
|
||||
f = h5py.File(weights_path)
|
||||
for k in range(f.attrs['nb_layers']):
|
||||
if k >= len(model.layers):
|
||||
# we don't look at the last (fully-connected) layers in the savefile
|
||||
break
|
||||
g = f['layer_{}'.format(k)]
|
||||
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
|
||||
model.layers[k].set_weights(weights)
|
||||
f.close()
|
||||
# build the VGG16 network with ImageNet weights
|
||||
model = vgg16.VGG16(weights='imagenet', include_top=False)
|
||||
print('Model loaded.')
|
||||
|
||||
model.summary()
|
||||
|
||||
# this is the placeholder for the input images
|
||||
input_img = model.input
|
||||
|
||||
# get the symbolic outputs of each "key" layer (we gave them unique names).
|
||||
layer_dict = dict([(layer.name, layer) for layer in model.layers])
|
||||
layer_dict = dict([(layer.name, layer) for layer in model.layers[1:]])
|
||||
|
||||
|
||||
def normalize(x):
|
||||
@@ -124,7 +65,10 @@ for filter_index in range(0, 200):
|
||||
# we build a loss function that maximizes the activation
|
||||
# of the nth filter of the layer considered
|
||||
layer_output = layer_dict[layer_name].output
|
||||
loss = K.mean(layer_output[:, filter_index, :, :])
|
||||
if K.image_dim_ordering() == 'th':
|
||||
loss = K.mean(layer_output[:, filter_index, :, :])
|
||||
else:
|
||||
loss = K.mean(layer_output[:, :, :, filter_index])
|
||||
|
||||
# we compute the gradient of the input picture wrt this loss
|
||||
grads = K.gradients(loss, input_img)[0]
|
||||
@@ -139,7 +83,11 @@ for filter_index in range(0, 200):
|
||||
step = 1.
|
||||
|
||||
# we start from a gray image with some random noise
|
||||
input_img_data = np.random.random((1, 3, img_width, img_height)) * 20 + 128.
|
||||
if K.image_dim_ordering() == 'th':
|
||||
input_img_data = np.random.random((1, 3, img_width, img_height))
|
||||
else:
|
||||
input_img_data = np.random.random((1, img_width, img_height, 3))
|
||||
input_img_data = (input_img_data - 0.5) * 20 + 128
|
||||
|
||||
# we run gradient ascent for 20 steps
|
||||
for i in range(20):
|
||||
|
||||
@@ -0,0 +1,470 @@
|
||||
'''This example uses a convolutional stack followed by a recurrent stack
|
||||
and a CTC logloss function to perform optical character recognition
|
||||
of generated text images. I have no evidence of whether it actually
|
||||
learns general shapes of text, or just is able to recognize all
|
||||
the different fonts thrown at it...the purpose is more to demonstrate CTC
|
||||
inside of Keras. Note that the font list may need to be updated
|
||||
for the particular OS in use.
|
||||
|
||||
This starts off with 4 letter words. After 10 or so epochs, CTC
|
||||
learns translational invariance, so longer words and groups of words
|
||||
with spaces are gradually fed in. This gradual increase in difficulty
|
||||
is handled using the TextImageGenerator class which is both a generator
|
||||
class for test/train data and a Keras callback class. Every 10 epochs
|
||||
the wordlist that the generator draws from increases in difficulty.
|
||||
|
||||
The table below shows normalized edit distance values. Theano uses
|
||||
a slightly different CTC implementation, so some Theano-specific
|
||||
hyperparameter tuning would be needed to get it to match Tensorflow.
|
||||
|
||||
Norm. ED
|
||||
Epoch | TF | TH
|
||||
------------------------
|
||||
10 0.072 0.272
|
||||
20 0.032 0.115
|
||||
30 0.024 0.098
|
||||
40 0.023 0.108
|
||||
|
||||
This requires cairo and editdistance packages:
|
||||
pip install cairocffi
|
||||
pip install editdistance
|
||||
|
||||
Due to the use of a dummy loss function, Theano requires the following flags:
|
||||
on_unused_input='ignore'
|
||||
|
||||
Created by Mike Henry
|
||||
https://github.com/mbhenry/
|
||||
'''
|
||||
|
||||
import os
|
||||
import itertools
|
||||
import re
|
||||
import datetime
|
||||
import cairocffi as cairo
|
||||
import editdistance
|
||||
import numpy as np
|
||||
from scipy import ndimage
|
||||
import pylab
|
||||
from keras import backend as K
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.layers import Input, Layer, Dense, Activation, Flatten
|
||||
from keras.layers import Reshape, Lambda, merge, Permute, TimeDistributed
|
||||
from keras.models import Model
|
||||
from keras.layers.recurrent import GRU
|
||||
from keras.optimizers import SGD
|
||||
from keras.utils import np_utils
|
||||
from keras.utils.data_utils import get_file
|
||||
from keras.preprocessing import image
|
||||
import keras.callbacks
|
||||
|
||||
OUTPUT_DIR = "image_ocr"
|
||||
|
||||
np.random.seed(55)
|
||||
|
||||
|
||||
# this creates larger "blotches" of noise which look
|
||||
# more realistic than just adding gaussian noise
|
||||
# assumes greyscale with pixels ranging from 0 to 1
|
||||
|
||||
def speckle(img):
|
||||
severity = np.random.uniform(0, 0.6)
|
||||
blur = ndimage.gaussian_filter(np.random.randn(*img.shape) * severity, 1)
|
||||
img_speck = (img + blur)
|
||||
img_speck[img_speck > 1] = 1
|
||||
img_speck[img_speck <= 0] = 0
|
||||
return img_speck
|
||||
|
||||
|
||||
# paints the string in a random location the bounding box
|
||||
# also uses a random font, a slight random rotation,
|
||||
# and a random amount of speckle noise
|
||||
|
||||
def paint_text(text, w, h):
|
||||
surface = cairo.ImageSurface(cairo.FORMAT_RGB24, w, h)
|
||||
with cairo.Context(surface) as context:
|
||||
context.set_source_rgb(1, 1, 1) # White
|
||||
context.paint()
|
||||
# this font list works in Centos 7
|
||||
fonts = ['Century Schoolbook', 'Courier', 'STIX', 'URW Chancery L', 'FreeMono']
|
||||
context.select_font_face(np.random.choice(fonts), cairo.FONT_SLANT_NORMAL,
|
||||
np.random.choice([cairo.FONT_WEIGHT_BOLD, cairo.FONT_WEIGHT_NORMAL]))
|
||||
context.set_font_size(40)
|
||||
box = context.text_extents(text)
|
||||
if box[2] > w or box[3] > h:
|
||||
raise IOError('Could not fit string into image. Max char count is too large for given image width.')
|
||||
|
||||
# teach the RNN translational invariance by
|
||||
# fitting text box randomly on canvas, with some room to rotate
|
||||
border_w_h = (10, 16)
|
||||
max_shift_x = w - box[2] - border_w_h[0]
|
||||
max_shift_y = h - box[3] - border_w_h[1]
|
||||
top_left_x = np.random.randint(0, int(max_shift_x))
|
||||
top_left_y = np.random.randint(0, int(max_shift_y))
|
||||
|
||||
context.move_to(top_left_x - int(box[0]), top_left_y - int(box[1]))
|
||||
context.set_source_rgb(0, 0, 0)
|
||||
context.show_text(text)
|
||||
|
||||
buf = surface.get_data()
|
||||
a = np.frombuffer(buf, np.uint8)
|
||||
a.shape = (h, w, 4)
|
||||
a = a[:, :, 0] # grab single channel
|
||||
a /= 255
|
||||
a = np.expand_dims(a, 0)
|
||||
a = speckle(a)
|
||||
a = image.random_rotation(a, 3 * (w - top_left_x) / w + 1)
|
||||
|
||||
return a
|
||||
|
||||
|
||||
def shuffle_mats_or_lists(matrix_list, stop_ind=None):
|
||||
ret = []
|
||||
assert all([len(i) == len(matrix_list[0]) for i in matrix_list])
|
||||
len_val = len(matrix_list[0])
|
||||
if stop_ind is None:
|
||||
stop_ind = len_val
|
||||
assert stop_ind <= len_val
|
||||
|
||||
a = range(stop_ind)
|
||||
np.random.shuffle(a)
|
||||
a += range(stop_ind, len_val)
|
||||
for mat in matrix_list:
|
||||
if isinstance(mat, np.ndarray):
|
||||
ret.append(mat[a])
|
||||
elif isinstance(mat, list):
|
||||
ret.append([mat[i] for i in a])
|
||||
else:
|
||||
raise TypeError('shuffle_mats_or_lists only supports '
|
||||
'numpy.array and list objects')
|
||||
return ret
|
||||
|
||||
|
||||
def text_to_labels(text, num_classes):
|
||||
ret = []
|
||||
for char in text:
|
||||
if char >= 'a' and char <= 'z':
|
||||
ret.append(ord(char) - ord('a'))
|
||||
elif char == ' ':
|
||||
ret.append(26)
|
||||
return ret
|
||||
|
||||
|
||||
# only a-z and space..probably not to difficult
|
||||
# to expand to uppercase and symbols
|
||||
|
||||
def is_valid_str(in_str):
|
||||
search = re.compile(r'[^a-z\ ]').search
|
||||
return not bool(search(in_str))
|
||||
|
||||
|
||||
# Uses generator functions to supply train/test with
|
||||
# data. Image renderings are text are created on the fly
|
||||
# each time with random perturbations
|
||||
|
||||
class TextImageGenerator(keras.callbacks.Callback):
|
||||
|
||||
def __init__(self, monogram_file, bigram_file, minibatch_size,
|
||||
img_w, img_h, downsample_width, val_split,
|
||||
absolute_max_string_len=16):
|
||||
|
||||
self.minibatch_size = minibatch_size
|
||||
self.img_w = img_w
|
||||
self.img_h = img_h
|
||||
self.monogram_file = monogram_file
|
||||
self.bigram_file = bigram_file
|
||||
self.downsample_width = downsample_width
|
||||
self.val_split = val_split
|
||||
self.blank_label = self.get_output_size() - 1
|
||||
self.absolute_max_string_len = absolute_max_string_len
|
||||
|
||||
def get_output_size(self):
|
||||
return 28
|
||||
|
||||
# num_words can be independent of the epoch size due to the use of generators
|
||||
# as max_string_len grows, num_words can grow
|
||||
def build_word_list(self, num_words, max_string_len=None, mono_fraction=0.5):
|
||||
assert max_string_len <= self.absolute_max_string_len
|
||||
assert num_words % self.minibatch_size == 0
|
||||
assert (self.val_split * num_words) % self.minibatch_size == 0
|
||||
self.num_words = num_words
|
||||
self.string_list = []
|
||||
self.max_string_len = max_string_len
|
||||
self.Y_data = np.ones([self.num_words, self.absolute_max_string_len]) * -1
|
||||
self.X_text = []
|
||||
self.Y_len = [0] * self.num_words
|
||||
|
||||
# monogram file is sorted by frequency in english speech
|
||||
with open(self.monogram_file, 'rt') as f:
|
||||
for line in f:
|
||||
if len(self.string_list) == int(self.num_words * mono_fraction):
|
||||
break
|
||||
word = line.rstrip()
|
||||
if max_string_len == -1 or max_string_len is None or len(word) <= max_string_len:
|
||||
self.string_list.append(word)
|
||||
|
||||
# bigram file contains common word pairings in english speech
|
||||
with open(self.bigram_file, 'rt') as f:
|
||||
lines = f.readlines()
|
||||
for line in lines:
|
||||
if len(self.string_list) == self.num_words:
|
||||
break
|
||||
columns = line.lower().split()
|
||||
word = columns[0] + ' ' + columns[1]
|
||||
if is_valid_str(word) and \
|
||||
(max_string_len == -1 or max_string_len is None or len(word) <= max_string_len):
|
||||
self.string_list.append(word)
|
||||
if len(self.string_list) != self.num_words:
|
||||
raise IOError('Could not pull enough words from supplied monogram and bigram files. ')
|
||||
|
||||
for i, word in enumerate(self.string_list):
|
||||
self.Y_len[i] = len(word)
|
||||
self.Y_data[i, 0:len(word)] = text_to_labels(word, self.get_output_size())
|
||||
self.X_text.append(word)
|
||||
self.Y_len = np.expand_dims(np.array(self.Y_len), 1)
|
||||
|
||||
self.cur_val_index = self.val_split
|
||||
self.cur_train_index = 0
|
||||
|
||||
# each time an image is requested from train/val/test, a new random
|
||||
# painting of the text is performed
|
||||
def get_batch(self, index, size, train):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_data = np.ones([size, 1, self.img_h, self.img_w])
|
||||
else:
|
||||
X_data = np.ones([size, self.img_h, self.img_w, 1])
|
||||
labels = np.ones([size, self.absolute_max_string_len])
|
||||
input_length = np.zeros([size, 1])
|
||||
label_length = np.zeros([size, 1])
|
||||
source_str = []
|
||||
|
||||
for i in range(0, size):
|
||||
# Mix in some blank inputs. This seems to be important for
|
||||
# achieving translational invariance
|
||||
if train and i > size - 4:
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_data[i, 0, :, :] = paint_text('', self.img_w, self.img_h)
|
||||
else:
|
||||
X_data[i, :, :, 0] = paint_text('', self.img_w, self.img_h)
|
||||
labels[i, 0] = self.blank_label
|
||||
input_length[i] = self.downsample_width
|
||||
label_length[i] = 1
|
||||
source_str.append('')
|
||||
else:
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_data[i, 0, :, :] = paint_text(self.X_text[index + i], self.img_w, self.img_h)
|
||||
else:
|
||||
X_data[i, :, :, 0] = paint_text(self.X_text[index + i], self.img_w, self.img_h)
|
||||
labels[i, :] = self.Y_data[index + i]
|
||||
input_length[i] = self.downsample_width
|
||||
label_length[i] = self.Y_len[index + i]
|
||||
source_str.append(self.X_text[index + i])
|
||||
|
||||
inputs = {'the_input': X_data,
|
||||
'the_labels': labels,
|
||||
'input_length': input_length,
|
||||
'label_length': label_length,
|
||||
'source_str': source_str # used for visualization only
|
||||
}
|
||||
outputs = {'ctc': np.zeros([size])} # dummy data for dummy loss function
|
||||
return (inputs, outputs)
|
||||
|
||||
def next_train(self):
|
||||
while 1:
|
||||
ret = self.get_batch(self.cur_train_index, self.minibatch_size, train=True)
|
||||
self.cur_train_index += self.minibatch_size
|
||||
if self.cur_train_index >= self.val_split:
|
||||
self.cur_train_index = self.cur_train_index % 32
|
||||
(self.X_text, self.Y_data, self.Y_len) = shuffle_mats_or_lists(
|
||||
[self.X_text, self.Y_data, self.Y_len], self.val_split)
|
||||
yield ret
|
||||
|
||||
def next_val(self):
|
||||
while 1:
|
||||
ret = self.get_batch(self.cur_val_index, self.minibatch_size, train=False)
|
||||
self.cur_val_index += self.minibatch_size
|
||||
if self.cur_val_index >= self.num_words:
|
||||
self.cur_val_index = self.val_split + self.cur_val_index % 32
|
||||
yield ret
|
||||
|
||||
def on_train_begin(self, logs={}):
|
||||
# translational invariance seems to be the hardest thing
|
||||
# for the RNN to learn, so start with <= 4 letter words.
|
||||
self.build_word_list(16000, 4, 1)
|
||||
|
||||
def on_epoch_begin(self, epoch, logs={}):
|
||||
# After 10 epochs, translational invariance should be learned
|
||||
# so start feeding longer words and eventually multiple words with spaces
|
||||
if epoch == 10:
|
||||
self.build_word_list(32000, 8, 1)
|
||||
if epoch == 20:
|
||||
self.build_word_list(32000, 8, 0.6)
|
||||
if epoch == 30:
|
||||
self.build_word_list(64000, 12, 0.5)
|
||||
|
||||
|
||||
# the actual loss calc occurs here despite it not being
|
||||
# an internal Keras loss function
|
||||
|
||||
def ctc_lambda_func(args):
|
||||
y_pred, labels, input_length, label_length = args
|
||||
# the 2 is critical here since the first couple outputs of the RNN
|
||||
# tend to be garbage:
|
||||
y_pred = y_pred[:, 2:, :]
|
||||
return K.ctc_batch_cost(labels, y_pred, input_length, label_length)
|
||||
|
||||
|
||||
# For a real OCR application, this should be beam search with a dictionary
|
||||
# and language model. For this example, best path is sufficient.
|
||||
|
||||
def decode_batch(test_func, word_batch):
|
||||
out = test_func([word_batch])[0]
|
||||
ret = []
|
||||
for j in range(out.shape[0]):
|
||||
out_best = list(np.argmax(out[j, 2:], 1))
|
||||
out_best = [k for k, g in itertools.groupby(out_best)]
|
||||
# 26 is space, 27 is CTC blank char
|
||||
outstr = ''
|
||||
for c in out_best:
|
||||
if c >= 0 and c < 26:
|
||||
outstr += chr(c + ord('a'))
|
||||
elif c == 26:
|
||||
outstr += ' '
|
||||
ret.append(outstr)
|
||||
return ret
|
||||
|
||||
|
||||
class VizCallback(keras.callbacks.Callback):
|
||||
|
||||
def __init__(self, test_func, text_img_gen, num_display_words=6):
|
||||
self.test_func = test_func
|
||||
self.output_dir = os.path.join(
|
||||
OUTPUT_DIR, datetime.datetime.now().strftime('%A, %d. %B %Y %I.%M%p'))
|
||||
self.text_img_gen = text_img_gen
|
||||
self.num_display_words = num_display_words
|
||||
os.makedirs(self.output_dir)
|
||||
|
||||
def show_edit_distance(self, num):
|
||||
num_left = num
|
||||
mean_norm_ed = 0.0
|
||||
mean_ed = 0.0
|
||||
while num_left > 0:
|
||||
word_batch = next(self.text_img_gen)[0]
|
||||
num_proc = min(word_batch['the_input'].shape[0], num_left)
|
||||
decoded_res = decode_batch(self.test_func, word_batch['the_input'][0:num_proc])
|
||||
for j in range(0, num_proc):
|
||||
edit_dist = editdistance.eval(decoded_res[j], word_batch['source_str'][j])
|
||||
mean_ed += float(edit_dist)
|
||||
mean_norm_ed += float(edit_dist) / len(word_batch['source_str'][j])
|
||||
num_left -= num_proc
|
||||
mean_norm_ed = mean_norm_ed / num
|
||||
mean_ed = mean_ed / num
|
||||
print('\nOut of %d samples: Mean edit distance: %.3f Mean normalized edit distance: %0.3f'
|
||||
% (num, mean_ed, mean_norm_ed))
|
||||
|
||||
def on_epoch_end(self, epoch, logs={}):
|
||||
self.model.save_weights(os.path.join(self.output_dir, 'weights%02d.h5' % epoch))
|
||||
self.show_edit_distance(256)
|
||||
word_batch = next(self.text_img_gen)[0]
|
||||
res = decode_batch(self.test_func, word_batch['the_input'][0:self.num_display_words])
|
||||
|
||||
for i in range(self.num_display_words):
|
||||
pylab.subplot(self.num_display_words, 1, i + 1)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
the_input = word_batch['the_input'][i, 0, :, :]
|
||||
else:
|
||||
the_input = word_batch['the_input'][i, :, :, 0]
|
||||
pylab.imshow(the_input, cmap='Greys_r')
|
||||
pylab.xlabel('Truth = \'%s\' Decoded = \'%s\'' % (word_batch['source_str'][i], res[i]))
|
||||
fig = pylab.gcf()
|
||||
fig.set_size_inches(10, 12)
|
||||
pylab.savefig(os.path.join(self.output_dir, 'e%02d.png' % epoch))
|
||||
pylab.close()
|
||||
|
||||
# Input Parameters
|
||||
img_h = 64
|
||||
img_w = 512
|
||||
nb_epoch = 50
|
||||
minibatch_size = 32
|
||||
words_per_epoch = 16000
|
||||
val_split = 0.2
|
||||
val_words = int(words_per_epoch * (val_split))
|
||||
|
||||
# Network parameters
|
||||
conv_num_filters = 16
|
||||
filter_size = 3
|
||||
pool_size_1 = 4
|
||||
pool_size_2 = 2
|
||||
time_dense_size = 32
|
||||
rnn_size = 512
|
||||
time_steps = img_w / (pool_size_1 * pool_size_2)
|
||||
|
||||
if K.image_dim_ordering() == 'th':
|
||||
input_shape = (1, img_h, img_w)
|
||||
else:
|
||||
input_shape = (img_h, img_w, 1)
|
||||
|
||||
fdir = os.path.dirname(get_file('wordlists.tgz',
|
||||
origin='http://www.isosemi.com/datasets/wordlists.tgz', untar=True))
|
||||
|
||||
img_gen = TextImageGenerator(monogram_file=os.path.join(fdir, 'wordlist_mono_clean.txt'),
|
||||
bigram_file=os.path.join(fdir, 'wordlist_bi_clean.txt'),
|
||||
minibatch_size=32,
|
||||
img_w=img_w,
|
||||
img_h=img_h,
|
||||
downsample_width=img_w / (pool_size_1 * pool_size_2) - 2,
|
||||
val_split=words_per_epoch - val_words)
|
||||
|
||||
act = 'relu'
|
||||
input_data = Input(name='the_input', shape=input_shape, dtype='float32')
|
||||
inner = Convolution2D(conv_num_filters, filter_size, filter_size, border_mode='same',
|
||||
activation=act, name='conv1')(input_data)
|
||||
inner = MaxPooling2D(pool_size=(pool_size_1, pool_size_1), name='max1')(inner)
|
||||
inner = Convolution2D(conv_num_filters, filter_size, filter_size, border_mode='same',
|
||||
activation=act, name='conv2')(inner)
|
||||
inner = MaxPooling2D(pool_size=(pool_size_2, pool_size_2), name='max2')(inner)
|
||||
|
||||
conv_to_rnn_dims = ((img_h / (pool_size_1 * pool_size_2)) * conv_num_filters, img_w / (pool_size_1 * pool_size_2))
|
||||
inner = Reshape(target_shape=conv_to_rnn_dims, name='reshape')(inner)
|
||||
inner = Permute(dims=(2, 1), name='permute')(inner)
|
||||
|
||||
# cuts down input size going into RNN:
|
||||
inner = TimeDistributed(Dense(time_dense_size, activation=act, name='dense1'))(inner)
|
||||
|
||||
# Two layers of bidirecitonal GRUs
|
||||
# GRU seems to work as well, if not better than LSTM:
|
||||
gru_1 = GRU(rnn_size, return_sequences=True, name='gru1')(inner)
|
||||
gru_1b = GRU(rnn_size, return_sequences=True, go_backwards=True, name='gru1_b')(inner)
|
||||
gru1_merged = merge([gru_1, gru_1b], mode='sum')
|
||||
gru_2 = GRU(rnn_size, return_sequences=True, name='gru2')(gru1_merged)
|
||||
gru_2b = GRU(rnn_size, return_sequences=True, go_backwards=True)(gru1_merged)
|
||||
|
||||
# transforms RNN output to character activations:
|
||||
inner = TimeDistributed(Dense(img_gen.get_output_size(), name='dense2'))(merge([gru_2, gru_2b], mode='concat'))
|
||||
y_pred = Activation('softmax', name='softmax')(inner)
|
||||
Model(input=[input_data], output=y_pred).summary()
|
||||
|
||||
labels = Input(name='the_labels', shape=[img_gen.absolute_max_string_len], dtype='float32')
|
||||
input_length = Input(name='input_length', shape=[1], dtype='int64')
|
||||
label_length = Input(name='label_length', shape=[1], dtype='int64')
|
||||
# Keras doesn't currently support loss funcs with extra parameters
|
||||
# so CTC loss is implemented in a lambda layer
|
||||
loss_out = Lambda(ctc_lambda_func, output_shape=(1,), name="ctc")([y_pred, labels, input_length, label_length])
|
||||
|
||||
lr = 0.03
|
||||
# clipnorm seems to speeds up convergence
|
||||
clipnorm = 5
|
||||
sgd = SGD(lr=lr, decay=3e-7, momentum=0.9, nesterov=True, clipnorm=clipnorm)
|
||||
|
||||
model = Model(input=[input_data, labels, input_length, label_length], output=[loss_out])
|
||||
|
||||
# the loss calc occurs elsewhere, so use a dummy lambda func for the loss
|
||||
model.compile(loss={'ctc': lambda y_true, y_pred: y_pred}, optimizer=sgd)
|
||||
|
||||
# captures output of softmax so we can decode the output during visualization
|
||||
test_func = K.function([input_data], [y_pred])
|
||||
|
||||
viz_cb = VizCallback(test_func, img_gen.next_val())
|
||||
|
||||
model.fit_generator(generator=img_gen.next_train(), samples_per_epoch=(words_per_epoch - val_words),
|
||||
nb_epoch=nb_epoch, validation_data=img_gen.next_val(), nb_val_samples=val_words,
|
||||
callbacks=[viz_cb, img_gen])
|
||||
@@ -9,8 +9,8 @@ import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Model
|
||||
from keras.layers import Dense, Dropout, Embedding, LSTM, Input, merge
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Embedding, LSTM, Input, Bidirectional
|
||||
from keras.datasets import imdb
|
||||
|
||||
|
||||
@@ -19,8 +19,7 @@ maxlen = 100 # cut texts after this number of words (among top max_features mos
|
||||
batch_size = 32
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features,
|
||||
test_split=0.2)
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
|
||||
@@ -32,24 +31,11 @@ print('X_test shape:', X_test.shape)
|
||||
y_train = np.array(y_train)
|
||||
y_test = np.array(y_test)
|
||||
|
||||
|
||||
# this is the placeholder tensor for the input sequences
|
||||
sequence = Input(shape=(maxlen,), dtype='int32')
|
||||
# this embedding layer will transform the sequences of integers
|
||||
# into vectors of size 128
|
||||
embedded = Embedding(max_features, 128, input_length=maxlen)(sequence)
|
||||
|
||||
# apply forwards LSTM
|
||||
forwards = LSTM(64)(embedded)
|
||||
# apply backwards LSTM
|
||||
backwards = LSTM(64, go_backwards=True)(embedded)
|
||||
|
||||
# concatenate the outputs of the 2 LSTMs
|
||||
merged = merge([forwards, backwards], mode='concat', concat_axis=-1)
|
||||
after_dp = Dropout(0.5)(merged)
|
||||
output = Dense(1, activation='sigmoid')(after_dp)
|
||||
|
||||
model = Model(input=sequence, output=output)
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, 128, input_length=maxlen))
|
||||
model.add(Bidirectional(LSTM(64)))
|
||||
model.add(Dropout(0.5))
|
||||
model.add(Dense(1, activation='sigmoid'))
|
||||
|
||||
# try using different optimizers and different optimizer configs
|
||||
model.compile('adam', 'binary_crossentropy', metrics=['accuracy'])
|
||||
|
||||
+9
-11
@@ -1,6 +1,6 @@
|
||||
'''This example demonstrates the use of Convolution1D for text classification.
|
||||
|
||||
Gets to 0.88 test accuracy after 2 epochs.
|
||||
Gets to 0.89 test accuracy after 2 epochs.
|
||||
90s/epoch on Intel i5 2.4Ghz CPU.
|
||||
10s/epoch on Tesla K40 GPU.
|
||||
|
||||
@@ -12,9 +12,9 @@ np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Activation, Lambda
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Embedding
|
||||
from keras.layers import Convolution1D
|
||||
from keras.layers import Convolution1D, MaxPooling1D
|
||||
from keras.datasets import imdb
|
||||
from keras import backend as K
|
||||
|
||||
@@ -30,8 +30,7 @@ hidden_dims = 250
|
||||
nb_epoch = 2
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features,
|
||||
test_split=0.2)
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
|
||||
@@ -58,13 +57,12 @@ model.add(Convolution1D(nb_filter=nb_filter,
|
||||
border_mode='valid',
|
||||
activation='relu',
|
||||
subsample_length=1))
|
||||
# we use max pooling:
|
||||
model.add(MaxPooling1D(pool_length=model.output_shape[1]))
|
||||
|
||||
# we use max over time pooling by defining a python function to use
|
||||
# in a Lambda layer
|
||||
def max_1d(X):
|
||||
return K.max(X, axis=1)
|
||||
|
||||
model.add(Lambda(max_1d, output_shape=(nb_filter,)))
|
||||
# We flatten the output of the conv layer,
|
||||
# so that we can add a vanilla dense layer:
|
||||
model.add(Flatten())
|
||||
|
||||
# We add a vanilla hidden layer:
|
||||
model.add(Dense(hidden_dims))
|
||||
|
||||
@@ -22,9 +22,9 @@ maxlen = 100
|
||||
embedding_size = 128
|
||||
|
||||
# Convolution
|
||||
filter_length = 3
|
||||
filter_length = 5
|
||||
nb_filter = 64
|
||||
pool_length = 2
|
||||
pool_length = 4
|
||||
|
||||
# LSTM
|
||||
lstm_output_size = 70
|
||||
@@ -40,7 +40,7 @@ Only 2 epochs are needed as the dataset is very small.
|
||||
'''
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features, test_split=0.2)
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
|
||||
|
||||
@@ -0,0 +1,139 @@
|
||||
'''This example demonstrates the use of fasttext for text classification
|
||||
|
||||
Based on Joulin et al's paper:
|
||||
|
||||
Bags of Tricks for Efficient Text Classification
|
||||
https://arxiv.org/abs/1607.01759
|
||||
|
||||
Results on IMDB datasets with uni and bi-gram embeddings:
|
||||
Uni-gram: 0.8813 test accuracy after 5 epochs. 15s/epoch on i7 cpu.
|
||||
Bi-gram : 0.9056 test accuracy after 5 epochs. 5s/epoch on GTX 1080 gpu.
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.preprocessing import sequence
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Flatten
|
||||
from keras.layers import Embedding
|
||||
from keras.layers import AveragePooling1D
|
||||
from keras.datasets import imdb
|
||||
|
||||
|
||||
def create_ngram_set(input_list, ngram_value=2):
|
||||
"""
|
||||
Extract a set of n-grams from a list of integers.
|
||||
|
||||
>>> create_ngram_set([1, 4, 9, 4, 1, 4], ngram_value=2)
|
||||
{(4, 9), (4, 1), (1, 4), (9, 4)}
|
||||
|
||||
>>> create_ngram_set([1, 4, 9, 4, 1, 4], ngram_value=3)
|
||||
[(1, 4, 9), (4, 9, 4), (9, 4, 1), (4, 1, 4)]
|
||||
"""
|
||||
return set(zip(*[input_list[i:] for i in range(ngram_value)]))
|
||||
|
||||
|
||||
def add_ngram(sequences, token_indice, ngram_range=2):
|
||||
"""
|
||||
Augment the input list of list (sequences) by appending n-grams values.
|
||||
|
||||
Example: adding bi-gram
|
||||
>>> sequences = [[1, 3, 4, 5], [1, 3, 7, 9, 2]]
|
||||
>>> token_indice = {(1, 3): 1337, (9, 2): 42, (4, 5): 2017}
|
||||
>>> add_ngram(sequences, token_indice, ngram_range=2)
|
||||
[[1, 3, 4, 5, 1337, 2017], [1, 3, 7, 9, 2, 1337, 42]]
|
||||
|
||||
Example: adding tri-gram
|
||||
>>> sequences = [[1, 3, 4, 5], [1, 3, 7, 9, 2]]
|
||||
>>> token_indice = {(1, 3): 1337, (9, 2): 42, (4, 5): 2017, (7, 9, 2): 2018}
|
||||
>>> add_ngram(sequences, token_indice, ngram_range=3)
|
||||
[[1, 3, 4, 5, 1337], [1, 3, 7, 9, 2, 1337, 2018]]
|
||||
"""
|
||||
new_sequences = []
|
||||
for input_list in sequences:
|
||||
new_list = input_list[:]
|
||||
for i in range(len(new_list)-ngram_range+1):
|
||||
for ngram_value in range(2, ngram_range+1):
|
||||
ngram = tuple(new_list[i:i+ngram_value])
|
||||
if ngram in token_indice:
|
||||
new_list.append(token_indice[ngram])
|
||||
new_sequences.append(new_list)
|
||||
|
||||
return new_sequences
|
||||
|
||||
# Set parameters:
|
||||
# ngram_range = 2 will add bi-grams features
|
||||
ngram_range = 1
|
||||
max_features = 20000
|
||||
maxlen = 400
|
||||
batch_size = 32
|
||||
embedding_dims = 50
|
||||
nb_epoch = 5
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
print('Average train sequence length: {}'.format(np.mean(list(map(len, X_train)), dtype=int)))
|
||||
print('Average test sequence length: {}'.format(np.mean(list(map(len, X_test)), dtype=int)))
|
||||
|
||||
if ngram_range > 1:
|
||||
print('Adding {}-gram features'.format(ngram_range))
|
||||
# Create set of unique n-gram from the training set.
|
||||
ngram_set = set()
|
||||
for input_list in X_train:
|
||||
for i in range(2, ngram_range+1):
|
||||
set_of_ngram = create_ngram_set(input_list, ngram_value=i)
|
||||
ngram_set.update(set_of_ngram)
|
||||
|
||||
# Dictionary mapping n-gram token to a unique integer.
|
||||
# Integer values are greater than max_features in order
|
||||
# to avoid collision with existing features.
|
||||
start_index = max_features + 1
|
||||
token_indice = {v: k+start_index for k, v in enumerate(ngram_set)}
|
||||
indice_token = {token_indice[k]: k for k in token_indice}
|
||||
|
||||
# max_features is the highest integer that could be found in the dataset.
|
||||
max_features = np.max(list(indice_token.keys())) + 1
|
||||
|
||||
# Augmenting X_train and X_test with n-grams features
|
||||
X_train = add_ngram(X_train, token_indice, ngram_range)
|
||||
X_test = add_ngram(X_test, token_indice, ngram_range)
|
||||
print('Average train sequence length: {}'.format(np.mean(list(map(len, X_train)), dtype=int)))
|
||||
print('Average test sequence length: {}'.format(np.mean(list(map(len, X_test)), dtype=int)))
|
||||
|
||||
print('Pad sequences (samples x time)')
|
||||
X_train = sequence.pad_sequences(X_train, maxlen=maxlen)
|
||||
X_test = sequence.pad_sequences(X_test, maxlen=maxlen)
|
||||
print('X_train shape:', X_train.shape)
|
||||
print('X_test shape:', X_test.shape)
|
||||
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
|
||||
# we start off with an efficient embedding layer which maps
|
||||
# our vocab indices into embedding_dims dimensions
|
||||
model.add(Embedding(max_features,
|
||||
embedding_dims,
|
||||
input_length=maxlen))
|
||||
|
||||
# we add a AveragePooling1D, which will average the embeddings
|
||||
# of all words in the document
|
||||
model.add(AveragePooling1D(pool_length=model.output_shape[1]))
|
||||
|
||||
# We flatten the output of the AveragePooling1D layer
|
||||
model.add(Flatten())
|
||||
|
||||
# We project onto a single unit output layer, and squash it with a sigmoid:
|
||||
model.add(Dense(1, activation='sigmoid'))
|
||||
|
||||
model.compile(loss='binary_crossentropy',
|
||||
optimizer='adam',
|
||||
metrics=['accuracy'])
|
||||
|
||||
model.fit(X_train, y_train,
|
||||
batch_size=batch_size,
|
||||
nb_epoch=nb_epoch,
|
||||
validation_data=(X_test, y_test))
|
||||
@@ -1,8 +1,6 @@
|
||||
'''Trains a LSTM on the IMDB sentiment classification task.
|
||||
|
||||
The dataset is actually too small for LSTM to be of any advantage
|
||||
compared to simpler, much faster methods such as TF-IDF+LogReg.
|
||||
|
||||
compared to simpler, much faster methods such as TF-IDF + LogReg.
|
||||
Notes:
|
||||
|
||||
- RNNs are tricky. Choice of batch size is important,
|
||||
@@ -28,8 +26,7 @@ maxlen = 80 # cut texts after this number of words (among top max_features most
|
||||
batch_size = 32
|
||||
|
||||
print('Loading data...')
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features,
|
||||
test_split=0.2)
|
||||
(X_train, y_train), (X_test, y_test) = imdb.load_data(nb_words=max_features)
|
||||
print(len(X_train), 'train sequences')
|
||||
print(len(X_test), 'test sequences')
|
||||
|
||||
@@ -41,7 +38,7 @@ print('X_test shape:', X_test.shape)
|
||||
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(Embedding(max_features, 128, input_length=maxlen, dropout=0.2))
|
||||
model.add(Embedding(max_features, 128, dropout=0.2))
|
||||
model.add(LSTM(128, dropout_W=0.2, dropout_U=0.2)) # try using a GRU instead, for fun
|
||||
model.add(Dense(1))
|
||||
model.add(Activation('sigmoid'))
|
||||
@@ -52,8 +49,6 @@ model.compile(loss='binary_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
|
||||
print('Train...')
|
||||
print(X_train.shape)
|
||||
print(y_train.shape)
|
||||
model.fit(X_train, y_train, batch_size=batch_size, nb_epoch=15,
|
||||
validation_data=(X_test, y_test))
|
||||
score, acc = model.evaluate(X_test, y_test,
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
'''This script demonstrates how to build the Inception v3 architecture
|
||||
using the Keras functional API.
|
||||
We are not actually training it here, for lack of appropriate data.
|
||||
|
||||
For more information about this architecture, see:
|
||||
|
||||
"Rethinking the Inception Architecture for Computer Vision"
|
||||
Christian Szegedy, Vincent Vanhoucke, Sergey Ioffe, Jonathon Shlens, Zbigniew Wojna
|
||||
http://arxiv.org/abs/1512.00567
|
||||
'''
|
||||
from keras.layers import Convolution2D, MaxPooling2D, AveragePooling2D
|
||||
from keras.layers import BatchNormalization, Flatten, Dense, Dropout
|
||||
from keras.layers import Input, merge
|
||||
from keras.models import Model
|
||||
from keras import regularizers
|
||||
|
||||
|
||||
# global constants
|
||||
NB_CLASS = 1000 # number of classes
|
||||
DIM_ORDERING = 'th' # 'th' (channels, width, height) or 'tf' (width, height, channels)
|
||||
WEIGHT_DECAY = 0. # L2 regularization factor
|
||||
USE_BN = False # whether to use batch normalization
|
||||
|
||||
|
||||
def conv2D_bn(x, nb_filter, nb_row, nb_col,
|
||||
border_mode='same', subsample=(1, 1),
|
||||
activation='relu', batch_norm=USE_BN,
|
||||
weight_decay=WEIGHT_DECAY, dim_ordering=DIM_ORDERING):
|
||||
'''Utility function to apply to a tensor a module conv + BN
|
||||
with optional weight decay (L2 weight regularization).
|
||||
'''
|
||||
if weight_decay:
|
||||
W_regularizer = regularizers.l2(weight_decay)
|
||||
b_regularizer = regularizers.l2(weight_decay)
|
||||
else:
|
||||
W_regularizer = None
|
||||
b_regularizer = None
|
||||
x = Convolution2D(nb_filter, nb_row, nb_col,
|
||||
subsample=subsample,
|
||||
activation=activation,
|
||||
border_mode=border_mode,
|
||||
W_regularizer=W_regularizer,
|
||||
b_regularizer=b_regularizer,
|
||||
dim_ordering=dim_ordering)(x)
|
||||
if batch_norm:
|
||||
x = BatchNormalization()(x)
|
||||
return x
|
||||
|
||||
# Define image input layer
|
||||
|
||||
if DIM_ORDERING == 'th':
|
||||
img_input = Input(shape=(3, 299, 299))
|
||||
CONCAT_AXIS = 1
|
||||
elif DIM_ORDERING == 'tf':
|
||||
img_input = Input(shape=(299, 299, 3))
|
||||
CONCAT_AXIS = 3
|
||||
else:
|
||||
raise Exception('Invalid dim ordering: ' + str(DIM_ORDERING))
|
||||
|
||||
# Entry module
|
||||
|
||||
x = conv2D_bn(img_input, 32, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
x = conv2D_bn(x, 32, 3, 3, border_mode='valid')
|
||||
x = conv2D_bn(x, 64, 3, 3)
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
|
||||
x = conv2D_bn(x, 80, 1, 1, border_mode='valid')
|
||||
x = conv2D_bn(x, 192, 3, 3, border_mode='valid')
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
|
||||
# mixed: 35 x 35 x 256
|
||||
|
||||
branch1x1 = conv2D_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2D_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2D_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 32, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed_1: 35 x 35 x 288
|
||||
|
||||
branch1x1 = conv2D_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2D_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2D_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 64, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed2: 35 x 35 x 288
|
||||
|
||||
branch1x1 = conv2D_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2D_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2D_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 64, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed3: 17 x 17 x 768
|
||||
|
||||
branch3x3 = conv2D_bn(x, 384, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 96, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = MaxPooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
x = merge([branch3x3, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed4: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 128, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 128, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 128, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 128, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed5: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed5: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed6: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed7: 17 x 17 x 768
|
||||
|
||||
branch1x1 = conv2D_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2D_bn(x, 192, 1, 1)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 1, 7)
|
||||
branch7x7 = conv2D_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2D_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2D_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# Auxiliary head
|
||||
|
||||
aux_logits = AveragePooling2D((5, 5), strides=(3, 3), dim_ordering=DIM_ORDERING)(x)
|
||||
aux_logits = conv2D_bn(aux_logits, 128, 1, 1)
|
||||
aux_logits = conv2D_bn(aux_logits, 728, 5, 5, border_mode='valid')
|
||||
aux_logits = Flatten()(aux_logits)
|
||||
aux_preds = Dense(NB_CLASS, activation='softmax')(aux_logits)
|
||||
|
||||
# mixed8: 8 x 8 x 1280
|
||||
|
||||
branch3x3 = conv2D_bn(x, 192, 1, 1)
|
||||
branch3x3 = conv2D_bn(branch3x3, 320, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch7x7x3 = conv2D_bn(x, 192, 1, 1)
|
||||
branch7x7x3 = conv2D_bn(branch7x7x3, 192, 1, 7)
|
||||
branch7x7x3 = conv2D_bn(branch7x7x3, 192, 7, 1)
|
||||
branch7x7x3 = conv2D_bn(branch7x7x3, 192, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(2, 2), dim_ordering=DIM_ORDERING)(x)
|
||||
x = merge([branch3x3, branch7x7x3, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed9: 8 x 8 x 2048
|
||||
|
||||
branch1x1 = conv2D_bn(x, 320, 1, 1)
|
||||
|
||||
branch3x3 = conv2D_bn(x, 384, 1, 1)
|
||||
branch3x3_1 = conv2D_bn(branch3x3, 384, 1, 3)
|
||||
branch3x3_2 = conv2D_bn(branch3x3, 384, 3, 1)
|
||||
branch3x3 = merge([branch3x3_1, branch3x3_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 448, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 384, 3, 3)
|
||||
branch3x3dbl_1 = conv2D_bn(branch3x3dbl, 384, 1, 3)
|
||||
branch3x3dbl_2 = conv2D_bn(branch3x3dbl, 384, 3, 1)
|
||||
branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# mixed10: 8 x 8 x 2048
|
||||
|
||||
branch1x1 = conv2D_bn(x, 320, 1, 1)
|
||||
|
||||
branch3x3 = conv2D_bn(x, 384, 1, 1)
|
||||
branch3x3_1 = conv2D_bn(branch3x3, 384, 1, 3)
|
||||
branch3x3_2 = conv2D_bn(branch3x3, 384, 3, 1)
|
||||
branch3x3 = merge([branch3x3_1, branch3x3_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch3x3dbl = conv2D_bn(x, 448, 1, 1)
|
||||
branch3x3dbl = conv2D_bn(branch3x3dbl, 384, 3, 3)
|
||||
branch3x3dbl_1 = conv2D_bn(branch3x3dbl, 384, 1, 3)
|
||||
branch3x3dbl_2 = conv2D_bn(branch3x3dbl, 384, 3, 1)
|
||||
branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same', dim_ordering=DIM_ORDERING)(x)
|
||||
branch_pool = conv2D_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool], mode='concat', concat_axis=CONCAT_AXIS)
|
||||
|
||||
# Final pooling and prediction
|
||||
|
||||
x = AveragePooling2D((8, 8), strides=(1, 1), dim_ordering=DIM_ORDERING)(x)
|
||||
x = Dropout(0.5)(x)
|
||||
x = Flatten()(x)
|
||||
preds = Dense(NB_CLASS, activation='softmax')(x)
|
||||
|
||||
# Define model
|
||||
|
||||
model = Model(input=img_input, output=[preds, aux_preds])
|
||||
model.compile('rmsprop', 'categorical_crossentropy')
|
||||
|
||||
# train via e.g. `model.fit(x_train, [y_train] * 2, batch_size=32, nb_epoch=100)`
|
||||
# Note that for a large dataset it would be preferable
|
||||
# to train using `fit_generator` (see Keras docs).
|
||||
@@ -14,6 +14,7 @@ from __future__ import print_function
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Dense, Activation, Dropout
|
||||
from keras.layers import LSTM
|
||||
from keras.optimizers import RMSprop
|
||||
from keras.utils.data_utils import get_file
|
||||
import numpy as np
|
||||
import random
|
||||
@@ -47,23 +48,25 @@ for i, sentence in enumerate(sentences):
|
||||
y[i, char_indices[next_chars[i]]] = 1
|
||||
|
||||
|
||||
# build the model: 2 stacked LSTM
|
||||
# build the model: a single LSTM
|
||||
print('Build model...')
|
||||
model = Sequential()
|
||||
model.add(LSTM(512, return_sequences=True, input_shape=(maxlen, len(chars))))
|
||||
model.add(LSTM(512, return_sequences=False))
|
||||
model.add(Dropout(0.2))
|
||||
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
|
||||
model.add(Dense(len(chars)))
|
||||
model.add(Activation('softmax'))
|
||||
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
optimizer = RMSprop(lr=0.01)
|
||||
model.compile(loss='categorical_crossentropy', optimizer=optimizer)
|
||||
|
||||
|
||||
def sample(a, temperature=1.0):
|
||||
def sample(preds, temperature=1.0):
|
||||
# helper function to sample an index from a probability array
|
||||
a = np.log(a) / temperature
|
||||
a = np.exp(a) / np.sum(np.exp(a))
|
||||
return np.argmax(np.random.multinomial(1, a, 1))
|
||||
preds = np.asarray(preds).astype('float64')
|
||||
preds = np.log(preds) / temperature
|
||||
exp_preds = np.exp(preds)
|
||||
preds = exp_preds / np.sum(exp_preds)
|
||||
probas = np.random.multinomial(1, preds, 1)
|
||||
return np.argmax(probas)
|
||||
|
||||
# train the model, output generated text after each iteration
|
||||
for iteration in range(1, 60):
|
||||
|
||||
+16
-8
@@ -14,6 +14,7 @@ from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
from keras import backend as K
|
||||
|
||||
batch_size = 128
|
||||
nb_classes = 10
|
||||
@@ -24,15 +25,22 @@ img_rows, img_cols = 28, 28
|
||||
# number of convolutional filters to use
|
||||
nb_filters = 32
|
||||
# size of pooling area for max pooling
|
||||
nb_pool = 2
|
||||
pool_size = (2, 2)
|
||||
# convolution kernel size
|
||||
nb_conv = 3
|
||||
kernel_size = (3, 3)
|
||||
|
||||
# the data, shuffled and split between train and test sets
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
|
||||
input_shape = (1, img_rows, img_cols)
|
||||
else:
|
||||
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)
|
||||
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)
|
||||
input_shape = (img_rows, img_cols, 1)
|
||||
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
@@ -47,13 +55,13 @@ Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
model = Sequential()
|
||||
|
||||
model.add(Convolution2D(nb_filters, nb_conv, nb_conv,
|
||||
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1],
|
||||
border_mode='valid',
|
||||
input_shape=(1, img_rows, img_cols)))
|
||||
input_shape=input_shape))
|
||||
model.add(Activation('relu'))
|
||||
model.add(Convolution2D(nb_filters, nb_conv, nb_conv))
|
||||
model.add(Convolution2D(nb_filters, kernel_size[0], kernel_size[1]))
|
||||
model.add(Activation('relu'))
|
||||
model.add(MaxPooling2D(pool_size=(nb_pool, nb_pool)))
|
||||
model.add(MaxPooling2D(pool_size=pool_size))
|
||||
model.add(Dropout(0.25))
|
||||
|
||||
model.add(Flatten())
|
||||
|
||||
@@ -0,0 +1,87 @@
|
||||
"""This is an example of using Hierarchical RNN (HRNN) to classify MNIST digits.
|
||||
|
||||
HRNNs can learn across multiple levels of temporal hiearchy over a complex sequence.
|
||||
Usually, the first recurrent layer of an HRNN encodes a sentence (e.g. of word vectors)
|
||||
into a sentence vector. The second recurrent layer then encodes a sequence of
|
||||
such vectors (encoded by the first layer) into a document vector. This
|
||||
document vector is considered to preserve both the word-level and
|
||||
sentence-level structure of the context.
|
||||
|
||||
# References
|
||||
- [A Hierarchical Neural Autoencoder for Paragraphs and Documents](https://web.stanford.edu/~jurafsky/pubs/P15-1107.pdf)
|
||||
Encodes paragraphs and documents with HRNN.
|
||||
Results have shown that HRNN outperforms standard
|
||||
RNNs and may play some role in more sophisticated generation tasks like
|
||||
summarization or question answering.
|
||||
- [Hierarchical recurrent neural network for skeleton based action recognition](http://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=7298714)
|
||||
Achieved state-of-the-art results on skeleton based action recognition with 3 levels
|
||||
of bidirectional HRNN combined with fully connected layers.
|
||||
|
||||
In the below MNIST example the first LSTM layer first encodes every
|
||||
column of pixels of shape (28, 1) to a column vector of shape (128,). The second LSTM
|
||||
layer encodes then these 28 column vectors of shape (28, 128) to a image vector
|
||||
representing the whole image. A final Dense layer is added for prediction.
|
||||
|
||||
After 5 epochs: train acc: 0.9858, val acc: 0.9864
|
||||
"""
|
||||
from __future__ import print_function
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Sequential, Model
|
||||
from keras.layers import Input, Dense, TimeDistributed
|
||||
from keras.layers import LSTM
|
||||
from keras.utils import np_utils
|
||||
|
||||
# Training parameters.
|
||||
batch_size = 32
|
||||
nb_classes = 10
|
||||
nb_epochs = 5
|
||||
|
||||
# Embedding dimensions.
|
||||
row_hidden = 128
|
||||
col_hidden = 128
|
||||
|
||||
# The data, shuffled and split between train and test sets.
|
||||
(X_train, y_train), (X_test, y_test) = mnist.load_data()
|
||||
|
||||
# Reshapes data to 4D for Hierarchical RNN.
|
||||
X_train = X_train.reshape(X_train.shape[0], 28, 28, 1)
|
||||
X_test = X_test.reshape(X_test.shape[0], 28, 28, 1)
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
print('X_train shape:', X_train.shape)
|
||||
print(X_train.shape[0], 'train samples')
|
||||
print(X_test.shape[0], 'test samples')
|
||||
|
||||
# Converts class vectors to binary class matrices.
|
||||
Y_train = np_utils.to_categorical(y_train, nb_classes)
|
||||
Y_test = np_utils.to_categorical(y_test, nb_classes)
|
||||
|
||||
row, col, pixel = X_train.shape[1:]
|
||||
|
||||
# 4D input.
|
||||
x = Input(shape=(row, col, pixel))
|
||||
|
||||
# Encodes a row of pixels using TimeDistributed Wrapper.
|
||||
encoded_rows = TimeDistributed(LSTM(output_dim=row_hidden))(x)
|
||||
|
||||
# Encodes columns of encoded rows.
|
||||
encoded_columns = LSTM(col_hidden)(encoded_rows)
|
||||
|
||||
# Final predictions and model.
|
||||
prediction = Dense(nb_classes, activation='softmax')(encoded_columns)
|
||||
model = Model(input=x, output=prediction)
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer='rmsprop',
|
||||
metrics=['accuracy'])
|
||||
|
||||
# Training.
|
||||
model.fit(X_train, Y_train, batch_size=batch_size, nb_epoch=nb_epochs,
|
||||
verbose=1, validation_data=(X_test, Y_test))
|
||||
|
||||
# Evaluation.
|
||||
scores = model.evaluate(X_test, Y_test, verbose=0)
|
||||
print('Test loss:', scores[0])
|
||||
print('Test accuracy:', scores[1])
|
||||
@@ -0,0 +1,384 @@
|
||||
'''This is an implementation of Net2Net experiment with MNIST in
|
||||
'Net2Net: Accelerating Learning via Knowledge Transfer'
|
||||
by Tianqi Chen, Ian Goodfellow, and Jonathon Shlens
|
||||
|
||||
arXiv:1511.05641v4 [cs.LG] 23 Apr 2016
|
||||
http://arxiv.org/abs/1511.05641
|
||||
|
||||
Notes
|
||||
- What:
|
||||
+ Net2Net is a group of methods to transfer knowledge from a teacher neural
|
||||
net to a student net,so that the student net can be trained faster than
|
||||
from scratch.
|
||||
+ The paper discussed two specific methods of Net2Net, i.e. Net2WiderNet
|
||||
and Net2DeeperNet.
|
||||
+ Net2WiderNet replaces a model with an equivalent wider model that has
|
||||
more units in each hidden layer.
|
||||
+ Net2DeeperNet replaces a model with an equivalent deeper model.
|
||||
+ Both are based on the idea of 'function-preserving transformations of
|
||||
neural nets'.
|
||||
- Why:
|
||||
+ Enable fast exploration of multiple neural nets in experimentation and
|
||||
design process,by creating a series of wider and deeper models with
|
||||
transferable knowledge.
|
||||
+ Enable 'lifelong learning system' by gradually adjusting model complexity
|
||||
to data availability,and reusing transferable knowledge.
|
||||
|
||||
Experiments
|
||||
- Teacher model: a basic CNN model trained on MNIST for 3 epochs.
|
||||
- Net2WiderNet exepriment:
|
||||
+ Student model has a wider Conv2D layer and a wider FC layer.
|
||||
+ Comparison of 'random-padding' vs 'net2wider' weight initialization.
|
||||
+ With both methods, student model should immediately perform as well as
|
||||
teacher model, but 'net2wider' is slightly better.
|
||||
- Net2DeeperNet experiment:
|
||||
+ Student model has an extra Conv2D layer and an extra FC layer.
|
||||
+ Comparison of 'random-init' vs 'net2deeper' weight initialization.
|
||||
+ Starting performance of 'net2deeper' is better than 'random-init'.
|
||||
- Hyper-parameters:
|
||||
+ SGD with momentum=0.9 is used for training teacher and student models.
|
||||
+ Learning rate adjustment: it's suggested to reduce learning rate
|
||||
to 1/10 for student model.
|
||||
+ Addition of noise in 'net2wider' is used to break weight symmetry
|
||||
and thus enable full capacity of student models. It is optional
|
||||
when a Dropout layer is used.
|
||||
|
||||
Results
|
||||
- Tested with 'Theano' backend and 'th' image_dim_ordering.
|
||||
- Running on GPU GeForce GTX 980M
|
||||
- Performance Comparisons - validation loss values during first 3 epochs:
|
||||
(1) teacher_model: 0.075 0.041 0.041
|
||||
(2) wider_random_pad: 0.036 0.034 0.032
|
||||
(3) wider_net2wider: 0.032 0.030 0.030
|
||||
(4) deeper_random_init: 0.061 0.043 0.041
|
||||
(5) deeper_net2deeper: 0.032 0.031 0.029
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Conv2D, MaxPooling2D, Dense, Flatten
|
||||
from keras.optimizers import SGD
|
||||
from keras.utils import np_utils
|
||||
from keras.datasets import mnist
|
||||
|
||||
input_shape = (1, 28, 28) # image shape
|
||||
nb_class = 10 # number of class
|
||||
|
||||
|
||||
# load and pre-process data
|
||||
def preprocess_input(x):
|
||||
return x.reshape((-1, ) + input_shape) / 255.
|
||||
|
||||
|
||||
def preprocess_output(y):
|
||||
return np_utils.to_categorical(y)
|
||||
|
||||
(train_x, train_y), (validation_x, validation_y) = mnist.load_data()
|
||||
train_x, validation_x = map(preprocess_input, [train_x, validation_x])
|
||||
train_y, validation_y = map(preprocess_output, [train_y, validation_y])
|
||||
print('Loading MNIST data...')
|
||||
print('train_x shape:', train_x.shape, 'train_y shape:', train_y.shape)
|
||||
print('validation_x shape:', validation_x.shape,
|
||||
'validation_y shape', validation_y.shape)
|
||||
|
||||
|
||||
# knowledge transfer algorithms
|
||||
def wider2net_conv2d(teacher_w1, teacher_b1, teacher_w2, new_width, init):
|
||||
'''Get initial weights for a wider conv2d layer with a bigger nb_filter,
|
||||
by 'random-padding' or 'net2wider'.
|
||||
|
||||
# Arguments
|
||||
teacher_w1: `weight` of conv2d layer to become wider,
|
||||
of shape (nb_filter1, nb_channel1, kh1, kw1)
|
||||
teacher_b1: `bias` of conv2d layer to become wider,
|
||||
of shape (nb_filter1, )
|
||||
teacher_w2: `weight` of next connected conv2d layer,
|
||||
of shape (nb_filter2, nb_channel2, kh2, kw2)
|
||||
new_width: new `nb_filter` for the wider conv2d layer
|
||||
init: initialization algorithm for new weights,
|
||||
either 'random-pad' or 'net2wider'
|
||||
'''
|
||||
assert teacher_w1.shape[0] == teacher_w2.shape[1], (
|
||||
'successive layers from teacher model should have compatible shapes')
|
||||
assert teacher_w1.shape[0] == teacher_b1.shape[0], (
|
||||
'weight and bias from same layer should have compatible shapes')
|
||||
assert new_width > teacher_w1.shape[0], (
|
||||
'new width (nb_filter) should be bigger than the existing one')
|
||||
|
||||
n = new_width - teacher_w1.shape[0]
|
||||
if init == 'random-pad':
|
||||
new_w1 = np.random.normal(0, 0.1, size=(n, ) + teacher_w1.shape[1:])
|
||||
new_b1 = np.ones(n) * 0.1
|
||||
new_w2 = np.random.normal(0, 0.1, size=(
|
||||
teacher_w2.shape[0], n) + teacher_w2.shape[2:])
|
||||
elif init == 'net2wider':
|
||||
index = np.random.randint(teacher_w1.shape[0], size=n)
|
||||
factors = np.bincount(index)[index] + 1.
|
||||
new_w1 = teacher_w1[index, :, :, :]
|
||||
new_b1 = teacher_b1[index]
|
||||
new_w2 = teacher_w2[:, index, :, :] / factors.reshape((1, -1, 1, 1))
|
||||
else:
|
||||
raise ValueError('Unsupported weight initializer: %s' % init)
|
||||
|
||||
student_w1 = np.concatenate((teacher_w1, new_w1), axis=0)
|
||||
if init == 'random-pad':
|
||||
student_w2 = np.concatenate((teacher_w2, new_w2), axis=1)
|
||||
elif init == 'net2wider':
|
||||
# add small noise to break symmetry, so that student model will have
|
||||
# full capacity later
|
||||
noise = np.random.normal(0, 5e-2 * new_w2.std(), size=new_w2.shape)
|
||||
student_w2 = np.concatenate((teacher_w2, new_w2 + noise), axis=1)
|
||||
student_w2[:, index, :, :] = new_w2
|
||||
student_b1 = np.concatenate((teacher_b1, new_b1), axis=0)
|
||||
|
||||
return student_w1, student_b1, student_w2
|
||||
|
||||
|
||||
def wider2net_fc(teacher_w1, teacher_b1, teacher_w2, new_width, init):
|
||||
'''Get initial weights for a wider fully connected (dense) layer
|
||||
with a bigger nout, by 'random-padding' or 'net2wider'.
|
||||
|
||||
# Arguments
|
||||
teacher_w1: `weight` of fc layer to become wider,
|
||||
of shape (nin1, nout1)
|
||||
teacher_b1: `bias` of fc layer to become wider,
|
||||
of shape (nout1, )
|
||||
teacher_w2: `weight` of next connected fc layer,
|
||||
of shape (nin2, nout2)
|
||||
new_width: new `nout` for the wider fc layer
|
||||
init: initialization algorithm for new weights,
|
||||
either 'random-pad' or 'net2wider'
|
||||
'''
|
||||
assert teacher_w1.shape[1] == teacher_w2.shape[0], (
|
||||
'successive layers from teacher model should have compatible shapes')
|
||||
assert teacher_w1.shape[1] == teacher_b1.shape[0], (
|
||||
'weight and bias from same layer should have compatible shapes')
|
||||
assert new_width > teacher_w1.shape[1], (
|
||||
'new width (nout) should be bigger than the existing one')
|
||||
|
||||
n = new_width - teacher_w1.shape[1]
|
||||
if init == 'random-pad':
|
||||
new_w1 = np.random.normal(0, 0.1, size=(teacher_w1.shape[0], n))
|
||||
new_b1 = np.ones(n) * 0.1
|
||||
new_w2 = np.random.normal(0, 0.1, size=(n, teacher_w2.shape[1]))
|
||||
elif init == 'net2wider':
|
||||
index = np.random.randint(teacher_w1.shape[1], size=n)
|
||||
factors = np.bincount(index)[index] + 1.
|
||||
new_w1 = teacher_w1[:, index]
|
||||
new_b1 = teacher_b1[index]
|
||||
new_w2 = teacher_w2[index, :] / factors[:, np.newaxis]
|
||||
else:
|
||||
raise ValueError('Unsupported weight initializer: %s' % init)
|
||||
|
||||
student_w1 = np.concatenate((teacher_w1, new_w1), axis=1)
|
||||
if init == 'random-pad':
|
||||
student_w2 = np.concatenate((teacher_w2, new_w2), axis=0)
|
||||
elif init == 'net2wider':
|
||||
# add small noise to break symmetry, so that student model will have
|
||||
# full capacity later
|
||||
noise = np.random.normal(0, 5e-2 * new_w2.std(), size=new_w2.shape)
|
||||
student_w2 = np.concatenate((teacher_w2, new_w2 + noise), axis=0)
|
||||
student_w2[index, :] = new_w2
|
||||
student_b1 = np.concatenate((teacher_b1, new_b1), axis=0)
|
||||
|
||||
return student_w1, student_b1, student_w2
|
||||
|
||||
|
||||
def deeper2net_conv2d(teacher_w):
|
||||
'''Get initial weights for a deeper conv2d layer by net2deeper'.
|
||||
|
||||
# Arguments
|
||||
teacher_w: `weight` of previous conv2d layer,
|
||||
of shape (nb_filter, nb_channel, kh, kw)
|
||||
'''
|
||||
nb_filter, nb_channel, kh, kw = teacher_w.shape
|
||||
student_w = np.zeros((nb_filter, nb_filter, kh, kw))
|
||||
for i in xrange(nb_filter):
|
||||
student_w[i, i, (kh - 1) / 2, (kw - 1) / 2] = 1.
|
||||
student_b = np.zeros(nb_filter)
|
||||
return student_w, student_b
|
||||
|
||||
|
||||
def copy_weights(teacher_model, student_model, layer_names):
|
||||
'''Copy weights from teacher_model to student_model,
|
||||
for layers with names listed in layer_names
|
||||
'''
|
||||
for name in layer_names:
|
||||
weights = teacher_model.get_layer(name=name).get_weights()
|
||||
student_model.get_layer(name=name).set_weights(weights)
|
||||
|
||||
|
||||
# methods to construct teacher_model and student_models
|
||||
def make_teacher_model(train_data, validation_data, nb_epoch=3):
|
||||
'''Train a simple CNN as teacher model.
|
||||
'''
|
||||
model = Sequential()
|
||||
model.add(Conv2D(64, 3, 3, input_shape=input_shape,
|
||||
border_mode='same', name='conv1'))
|
||||
model.add(MaxPooling2D(name='pool1'))
|
||||
model.add(Conv2D(64, 3, 3, border_mode='same', name='conv2'))
|
||||
model.add(MaxPooling2D(name='pool2'))
|
||||
model.add(Flatten(name='flatten'))
|
||||
model.add(Dense(64, activation='relu', name='fc1'))
|
||||
model.add(Dense(nb_class, activation='softmax', name='fc2'))
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer=SGD(lr=0.01, momentum=0.9),
|
||||
metrics=['accuracy'])
|
||||
|
||||
train_x, train_y = train_data
|
||||
history = model.fit(train_x, train_y, nb_epoch=nb_epoch,
|
||||
validation_data=validation_data)
|
||||
return model, history
|
||||
|
||||
|
||||
def make_wider_student_model(teacher_model, train_data,
|
||||
validation_data, init, nb_epoch=3):
|
||||
'''Train a wider student model based on teacher_model,
|
||||
with either 'random-pad' (baseline) or 'net2wider'
|
||||
'''
|
||||
new_conv1_width = 128
|
||||
new_fc1_width = 128
|
||||
|
||||
model = Sequential()
|
||||
# a wider conv1 compared to teacher_model
|
||||
model.add(Conv2D(new_conv1_width, 3, 3, input_shape=input_shape,
|
||||
border_mode='same', name='conv1'))
|
||||
model.add(MaxPooling2D(name='pool1'))
|
||||
model.add(Conv2D(64, 3, 3, border_mode='same', name='conv2'))
|
||||
model.add(MaxPooling2D(name='pool2'))
|
||||
model.add(Flatten(name='flatten'))
|
||||
# a wider fc1 compared to teacher model
|
||||
model.add(Dense(new_fc1_width, activation='relu', name='fc1'))
|
||||
model.add(Dense(nb_class, activation='softmax', name='fc2'))
|
||||
|
||||
# The weights for other layers need to be copied from teacher_model
|
||||
# to student_model, except for widened layers
|
||||
# and their immediate downstreams, which will be initialized separately.
|
||||
# For this example there are no other layers that need to be copied.
|
||||
|
||||
w_conv1, b_conv1 = teacher_model.get_layer('conv1').get_weights()
|
||||
w_conv2, b_conv2 = teacher_model.get_layer('conv2').get_weights()
|
||||
new_w_conv1, new_b_conv1, new_w_conv2 = wider2net_conv2d(
|
||||
w_conv1, b_conv1, w_conv2, new_conv1_width, init)
|
||||
model.get_layer('conv1').set_weights([new_w_conv1, new_b_conv1])
|
||||
model.get_layer('conv2').set_weights([new_w_conv2, b_conv2])
|
||||
|
||||
w_fc1, b_fc1 = teacher_model.get_layer('fc1').get_weights()
|
||||
w_fc2, b_fc2 = teacher_model.get_layer('fc2').get_weights()
|
||||
new_w_fc1, new_b_fc1, new_w_fc2 = wider2net_fc(
|
||||
w_fc1, b_fc1, w_fc2, new_fc1_width, init)
|
||||
model.get_layer('fc1').set_weights([new_w_fc1, new_b_fc1])
|
||||
model.get_layer('fc2').set_weights([new_w_fc2, b_fc2])
|
||||
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer=SGD(lr=0.001, momentum=0.9),
|
||||
metrics=['accuracy'])
|
||||
|
||||
train_x, train_y = train_data
|
||||
history = model.fit(train_x, train_y, nb_epoch=nb_epoch,
|
||||
validation_data=validation_data)
|
||||
return model, history
|
||||
|
||||
|
||||
def make_deeper_student_model(teacher_model, train_data,
|
||||
validation_data, init, nb_epoch=3):
|
||||
'''Train a deeper student model based on teacher_model,
|
||||
with either 'random-init' (baseline) or 'net2deeper'
|
||||
'''
|
||||
model = Sequential()
|
||||
model.add(Conv2D(64, 3, 3, input_shape=input_shape,
|
||||
border_mode='same', name='conv1'))
|
||||
model.add(MaxPooling2D(name='pool1'))
|
||||
model.add(Conv2D(64, 3, 3, border_mode='same', name='conv2'))
|
||||
# add another conv2d layer to make original conv2 deeper
|
||||
if init == 'net2deeper':
|
||||
prev_w, _ = model.get_layer('conv2').get_weights()
|
||||
new_weights = deeper2net_conv2d(prev_w)
|
||||
model.add(Conv2D(64, 3, 3, border_mode='same',
|
||||
name='conv2-deeper', weights=new_weights))
|
||||
elif init == 'random-init':
|
||||
model.add(Conv2D(64, 3, 3, border_mode='same', name='conv2-deeper'))
|
||||
else:
|
||||
raise ValueError('Unsupported weight initializer: %s' % init)
|
||||
model.add(MaxPooling2D(name='pool2'))
|
||||
model.add(Flatten(name='flatten'))
|
||||
model.add(Dense(64, activation='relu', name='fc1'))
|
||||
# add another fc layer to make original fc1 deeper
|
||||
if init == 'net2deeper':
|
||||
# net2deeper for fc layer with relu, is just an identity initializer
|
||||
model.add(Dense(64, init='identity',
|
||||
activation='relu', name='fc1-deeper'))
|
||||
elif init == 'random-init':
|
||||
model.add(Dense(64, activation='relu', name='fc1-deeper'))
|
||||
else:
|
||||
raise ValueError('Unsupported weight initializer: %s' % init)
|
||||
model.add(Dense(nb_class, activation='softmax', name='fc2'))
|
||||
|
||||
# copy weights for other layers
|
||||
copy_weights(teacher_model, model, layer_names=[
|
||||
'conv1', 'conv2', 'fc1', 'fc2'])
|
||||
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer=SGD(lr=0.001, momentum=0.9),
|
||||
metrics=['accuracy'])
|
||||
|
||||
train_x, train_y = train_data
|
||||
history = model.fit(train_x, train_y, nb_epoch=nb_epoch,
|
||||
validation_data=validation_data)
|
||||
return model, history
|
||||
|
||||
|
||||
# experiments setup
|
||||
def net2wider_experiment():
|
||||
'''Benchmark performances of
|
||||
(1) a teacher model,
|
||||
(2) a wider student model with `random_pad` initializer
|
||||
(3) a wider student model with `Net2WiderNet` initializer
|
||||
'''
|
||||
train_data = (train_x, train_y)
|
||||
validation_data = (validation_x, validation_y)
|
||||
print('\nExperiment of Net2WiderNet ...')
|
||||
print('\nbuilding teacher model ...')
|
||||
teacher_model, _ = make_teacher_model(train_data,
|
||||
validation_data,
|
||||
nb_epoch=3)
|
||||
|
||||
print('\nbuilding wider student model by random padding ...')
|
||||
make_wider_student_model(teacher_model, train_data,
|
||||
validation_data, 'random-pad',
|
||||
nb_epoch=3)
|
||||
print('\nbuilding wider student model by net2wider ...')
|
||||
make_wider_student_model(teacher_model, train_data,
|
||||
validation_data, 'net2wider',
|
||||
nb_epoch=3)
|
||||
|
||||
|
||||
def net2deeper_experiment():
|
||||
'''Benchmark performances of
|
||||
(1) a teacher model,
|
||||
(2) a deeper student model with `random_init` initializer
|
||||
(3) a deeper student model with `Net2DeeperNet` initializer
|
||||
'''
|
||||
train_data = (train_x, train_y)
|
||||
validation_data = (validation_x, validation_y)
|
||||
print('\nExperiment of Net2DeeperNet ...')
|
||||
print('\nbuilding teacher model ...')
|
||||
teacher_model, _ = make_teacher_model(train_data,
|
||||
validation_data,
|
||||
nb_epoch=3)
|
||||
|
||||
print('\nbuilding deeper student model by random init ...')
|
||||
make_deeper_student_model(teacher_model, train_data,
|
||||
validation_data, 'random-init',
|
||||
nb_epoch=3)
|
||||
print('\nbuilding deeper student model by net2deeper ...')
|
||||
make_deeper_student_model(teacher_model, train_data,
|
||||
validation_data, 'net2deeper',
|
||||
nb_epoch=3)
|
||||
|
||||
# run the experiments
|
||||
net2wider_experiment()
|
||||
net2deeper_experiment()
|
||||
@@ -0,0 +1,167 @@
|
||||
'''Trains a stacked what-where autoencoder built on residual blocks on the
|
||||
MNIST dataset. It exemplifies two influential methods that have been developed
|
||||
in the past few years.
|
||||
|
||||
The first is the idea of properly "unpooling." During any max pool, the
|
||||
exact location (the "where") of the maximal value in a pooled receptive field
|
||||
is lost, however it can be very useful in the overall reconstruction of an
|
||||
input image. Therefore, if the "where" is handed from the encoder
|
||||
to the corresponding decoder layer, features being decoded can be "placed" in
|
||||
the right location, allowing for reconstructions of much higher fidelity.
|
||||
|
||||
References:
|
||||
[1]
|
||||
"Visualizing and Understanding Convolutional Networks"
|
||||
Matthew D Zeiler, Rob Fergus
|
||||
https://arxiv.org/abs/1311.2901v3
|
||||
|
||||
[2]
|
||||
"Stacked What-Where Auto-encoders"
|
||||
Junbo Zhao, Michael Mathieu, Ross Goroshin, Yann LeCun
|
||||
https://arxiv.org/abs/1506.02351v8
|
||||
|
||||
The second idea exploited here is that of residual learning. Residual blocks
|
||||
ease the training process by allowing skip connections that give the network
|
||||
the ability to be as linear (or non-linear) as the data sees fit. This allows
|
||||
for much deep networks to be easily trained. The residual element seems to
|
||||
be advantageous in the context of this example as it allows a nice symmetry
|
||||
between the encoder and decoder. Normally, in the decoder, the final
|
||||
projection to the space where the image is reconstructed is linear, however
|
||||
this does not have to be the case for a residual block as the degree to which
|
||||
its output is linear or non-linear is determined by the data it is fed.
|
||||
However, in order to cap the reconstruction in this example, a hard softmax is
|
||||
applied as a bias because we know the MNIST digits are mapped to [0,1].
|
||||
|
||||
References:
|
||||
[3]
|
||||
"Deep Residual Learning for Image Recognition"
|
||||
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
|
||||
https://arxiv.org/abs/1512.03385v1
|
||||
|
||||
[4]
|
||||
"Identity Mappings in Deep Residual Networks"
|
||||
Kaiming He, Xiangyu Zhang, Shaoqing Ren, Jian Sun
|
||||
https://arxiv.org/abs/1603.05027v3
|
||||
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337) # for reproducibility
|
||||
|
||||
from keras.datasets import mnist
|
||||
from keras.models import Model
|
||||
from keras.layers import Activation, merge
|
||||
from keras.layers import UpSampling2D, Convolution2D, MaxPooling2D
|
||||
from keras.layers import Input, BatchNormalization
|
||||
import matplotlib.pyplot as plt
|
||||
import keras.backend as K
|
||||
|
||||
|
||||
def convresblock(x, nfeats=8, ksize=3, nskipped=2):
|
||||
''' The proposed residual block from [4]'''
|
||||
y0 = Convolution2D(nfeats, ksize, ksize, border_mode='same')(x)
|
||||
y = y0
|
||||
for i in range(nskipped):
|
||||
y = BatchNormalization(mode=0, axis=1)(y)
|
||||
y = Activation('relu')(y)
|
||||
y = Convolution2D(nfeats, ksize, ksize, border_mode='same')(y)
|
||||
return merge([y0, y], mode='sum')
|
||||
|
||||
|
||||
def getwhere(x):
|
||||
''' Calculate the "where" mask that contains switches indicating which
|
||||
index contained the max value when MaxPool2D was applied. Using the
|
||||
gradient of the sum is a nice trick to keep everything high level.'''
|
||||
y_prepool, y_postpool = x
|
||||
return K.gradients(K.sum(y_postpool), y_prepool)
|
||||
|
||||
# input image dimensions
|
||||
img_rows, img_cols = 28, 28
|
||||
|
||||
# the data, shuffled and split between train and test sets
|
||||
(X_train, _), (X_test, _) = mnist.load_data()
|
||||
|
||||
X_train = X_train.reshape(X_train.shape[0], 1, img_rows, img_cols)
|
||||
X_test = X_test.reshape(X_test.shape[0], 1, img_rows, img_cols)
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
X_test /= 255
|
||||
print('X_train shape:', X_train.shape)
|
||||
print(X_train.shape[0], 'train samples')
|
||||
print(X_test.shape[0], 'test samples')
|
||||
|
||||
# The size of the kernel used for the MaxPooling2D
|
||||
pool_size = 2
|
||||
# The total number of feature maps at each layer
|
||||
nfeats = [8, 16, 32, 64, 128]
|
||||
# The sizes of the pooling kernel at each layer
|
||||
pool_sizes = np.array([1, 1, 1, 1, 1]) * pool_size
|
||||
# The convolution kernel size
|
||||
ksize = 3
|
||||
# Number of epochs to train for
|
||||
nb_epoch = 5
|
||||
# Batch size during training
|
||||
batch_size = 128
|
||||
|
||||
if pool_size == 2:
|
||||
# if using a 5 layer net of pool_size = 2
|
||||
X_train = np.pad(X_train, [[0, 0], [0, 0], [2, 2], [2, 2]],
|
||||
mode='constant')
|
||||
X_test = np.pad(X_test, [[0, 0], [0, 0], [2, 2], [2, 2]], mode='constant')
|
||||
nlayers = 5
|
||||
elif pool_size == 3:
|
||||
# if using a 3 layer net of pool_size = 3
|
||||
X_train = X_train[:, :, :-1, :-1]
|
||||
X_test = X_test[:, :, :-1, :-1]
|
||||
nlayers = 3
|
||||
else:
|
||||
import sys
|
||||
sys.exit("Script supports pool_size of 2 and 3.")
|
||||
|
||||
# Shape of input to train on (note that model is fully convolutional however)
|
||||
input_shape = X_train.shape[1:]
|
||||
# The final list of the size of axis=1 for all layers, including input
|
||||
nfeats_all = [input_shape[0]] + nfeats
|
||||
|
||||
# First build the encoder, all the while keeping track of the "where" masks
|
||||
img_input = Input(shape=input_shape)
|
||||
|
||||
# We push the "where" masks to the following list
|
||||
wheres = [None] * nlayers
|
||||
y = img_input
|
||||
for i in range(nlayers):
|
||||
y_prepool = convresblock(y, nfeats=nfeats_all[i + 1], ksize=ksize)
|
||||
y = MaxPooling2D(pool_size=(pool_sizes[i], pool_sizes[i]))(y_prepool)
|
||||
wheres[i] = merge([y_prepool, y], mode=getwhere,
|
||||
output_shape=lambda x: x[0])
|
||||
|
||||
# Now build the decoder, and use the stored "where" masks to place the features
|
||||
for i in range(nlayers):
|
||||
ind = nlayers - 1 - i
|
||||
y = UpSampling2D(size=(pool_sizes[ind], pool_sizes[ind]))(y)
|
||||
y = merge([y, wheres[ind]], mode='mul')
|
||||
y = convresblock(y, nfeats=nfeats_all[ind], ksize=ksize)
|
||||
|
||||
# Use hard_simgoid to clip range of reconstruction
|
||||
y = Activation('hard_sigmoid')(y)
|
||||
|
||||
# Define the model and it's mean square error loss, and compile it with Adam
|
||||
model = Model(img_input, y)
|
||||
model.compile('adam', 'mse')
|
||||
|
||||
# Fit the model
|
||||
model.fit(X_train, X_train, validation_data=(X_test, X_test),
|
||||
batch_size=batch_size, nb_epoch=nb_epoch)
|
||||
|
||||
# Plot
|
||||
X_recon = model.predict(X_test[:25])
|
||||
X_plot = np.concatenate((X_test[:25], X_recon), axis=1)
|
||||
X_plot = X_plot.reshape((5, 10, input_shape[-2], input_shape[-1]))
|
||||
X_plot = np.vstack([np.hstack(x) for x in X_plot])
|
||||
plt.figure()
|
||||
plt.axis('off')
|
||||
plt.title('Test Samples: Originals/Reconstructions')
|
||||
plt.imshow(X_plot, interpolation='none', cmap='gray')
|
||||
plt.savefig('reconstructions.png')
|
||||
@@ -22,7 +22,7 @@ from keras.models import Sequential
|
||||
from keras.layers import Dense, Dropout, Activation, Flatten
|
||||
from keras.layers import Convolution2D, MaxPooling2D
|
||||
from keras.utils import np_utils
|
||||
|
||||
from keras import backend as K
|
||||
|
||||
now = datetime.datetime.now
|
||||
|
||||
@@ -35,14 +35,19 @@ img_rows, img_cols = 28, 28
|
||||
# number of convolutional filters to use
|
||||
nb_filters = 32
|
||||
# size of pooling area for max pooling
|
||||
nb_pool = 2
|
||||
pool_size = 2
|
||||
# convolution kernel size
|
||||
nb_conv = 3
|
||||
kernel_size = 3
|
||||
|
||||
if K.image_dim_ordering() == 'th':
|
||||
input_shape = (1, img_rows, img_cols)
|
||||
else:
|
||||
input_shape = (img_rows, img_cols, 1)
|
||||
|
||||
|
||||
def train_model(model, train, test, nb_classes):
|
||||
X_train = train[0].reshape(train[0].shape[0], 1, img_rows, img_cols)
|
||||
X_test = test[0].reshape(test[0].shape[0], 1, img_rows, img_cols)
|
||||
X_train = train[0].reshape((train[0].shape[0],) + input_shape)
|
||||
X_test = test[0].reshape((test[0].shape[0],) + input_shape)
|
||||
X_train = X_train.astype('float32')
|
||||
X_test = X_test.astype('float32')
|
||||
X_train /= 255
|
||||
@@ -86,13 +91,13 @@ y_test_gte5 = y_test[y_test >= 5] - 5
|
||||
|
||||
# define two groups of layers: feature (convolutions) and classification (dense)
|
||||
feature_layers = [
|
||||
Convolution2D(nb_filters, nb_conv, nb_conv,
|
||||
Convolution2D(nb_filters, kernel_size, kernel_size,
|
||||
border_mode='valid',
|
||||
input_shape=(1, img_rows, img_cols)),
|
||||
input_shape=input_shape),
|
||||
Activation('relu'),
|
||||
Convolution2D(nb_filters, nb_conv, nb_conv),
|
||||
Convolution2D(nb_filters, kernel_size, kernel_size),
|
||||
Activation('relu'),
|
||||
MaxPooling2D(pool_size=(nb_pool, nb_pool)),
|
||||
MaxPooling2D(pool_size=(pool_size, pool_size)),
|
||||
Dropout(0.25),
|
||||
Flatten(),
|
||||
]
|
||||
@@ -105,9 +110,7 @@ classification_layers = [
|
||||
]
|
||||
|
||||
# create complete model
|
||||
model = Sequential()
|
||||
for l in feature_layers + classification_layers:
|
||||
model.add(l)
|
||||
model = Sequential(feature_layers + classification_layers)
|
||||
|
||||
# train model for 5-digit classification [0..4]
|
||||
train_model(model,
|
||||
|
||||
@@ -0,0 +1,364 @@
|
||||
'''Neural doodle with Keras
|
||||
|
||||
Script Usage:
|
||||
# Arguments:
|
||||
```
|
||||
--nlabels: # of regions (colors) in mask images
|
||||
--style-image: image to learn style from
|
||||
--style-mask: semantic labels for style image
|
||||
--target-mask: semantic labels for target image (your doodle)
|
||||
--content-image: optional image to learn content from
|
||||
--target-image-prefix: path prefix for generated target images
|
||||
```
|
||||
|
||||
# Example 1: doodle using a style image, style mask
|
||||
and target mask.
|
||||
```
|
||||
python neural_doodle.py --nlabels 4 --style-image Monet/style.png \
|
||||
--style-mask Monet/style_mask.png --target-mask Monet/target_mask.png \
|
||||
--target-image-prefix generated/monet
|
||||
```
|
||||
|
||||
# Example 2: doodle using a style image, style mask,
|
||||
target mask and an optional content image.
|
||||
```
|
||||
python neural_doodle.py --nlabels 4 --style-image Renoir/style.png \
|
||||
--style-mask Renoir/style_mask.png --target-mask Renoir/target_mask.png \
|
||||
--content-image Renoir/creek.jpg \
|
||||
--target-image-prefix generated/renoir
|
||||
```
|
||||
|
||||
References:
|
||||
[Dmitry Ulyanov's blog on fast-neural-doodle](http://dmitryulyanov.github.io/feed-forward-neural-doodle/)
|
||||
[Torch code for fast-neural-doodle](https://github.com/DmitryUlyanov/fast-neural-doodle)
|
||||
[Torch code for online-neural-doodle](https://github.com/DmitryUlyanov/online-neural-doodle)
|
||||
[Paper Texture Networks: Feed-forward Synthesis of Textures and Stylized Images](http://arxiv.org/abs/1603.03417)
|
||||
[Discussion on parameter tuning](https://github.com/fchollet/keras/issues/3705)
|
||||
|
||||
Resources:
|
||||
Example images can be downloaded from
|
||||
https://github.com/DmitryUlyanov/fast-neural-doodle/tree/master/data
|
||||
'''
|
||||
from __future__ import print_function
|
||||
import time
|
||||
import argparse
|
||||
import numpy as np
|
||||
from scipy.optimize import fmin_l_bfgs_b
|
||||
from scipy.misc import imread, imsave
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import Input, Convolution2D, MaxPooling2D, AveragePooling2D
|
||||
from keras.models import Model
|
||||
from keras.preprocessing.image import load_img, img_to_array
|
||||
from keras.applications import vgg19
|
||||
|
||||
# Command line arguments
|
||||
parser = argparse.ArgumentParser(description='Keras neural doodle example')
|
||||
parser.add_argument('--nlabels', type=int,
|
||||
help='number of semantic labels'
|
||||
' (regions in differnet colors)'
|
||||
' in style_mask/target_mask')
|
||||
parser.add_argument('--style-image', type=str,
|
||||
help='path to image to learn style from')
|
||||
parser.add_argument('--style-mask', type=str,
|
||||
help='path to semantic mask of style image')
|
||||
parser.add_argument('--target-mask', type=str,
|
||||
help='path to semantic mask of target image')
|
||||
parser.add_argument('--content-image', type=str, default=None,
|
||||
help='path to optional content image')
|
||||
parser.add_argument('--target-image-prefix', type=str,
|
||||
help='path prefix for generated results')
|
||||
args = parser.parse_args()
|
||||
|
||||
style_img_path = args.style_image
|
||||
style_mask_path = args.style_mask
|
||||
target_mask_path = args.target_mask
|
||||
content_img_path = args.content_image
|
||||
target_img_prefix = args.target_image_prefix
|
||||
use_content_img = content_img_path is not None
|
||||
|
||||
nb_labels = args.nlabels
|
||||
nb_colors = 3 # RGB
|
||||
# determine image sizes based on target_mask
|
||||
ref_img = imread(target_mask_path)
|
||||
img_nrows, img_ncols = ref_img.shape[:2]
|
||||
|
||||
total_variation_weight = 50.
|
||||
style_weight = 1.
|
||||
content_weight = 0.1 if use_content_img else 0
|
||||
|
||||
content_feature_layers = ['block5_conv2']
|
||||
# To get better generation qualities, use more conv layers for style features
|
||||
style_feature_layers = ['block1_conv1', 'block2_conv1', 'block3_conv1',
|
||||
'block4_conv1', 'block5_conv1']
|
||||
|
||||
|
||||
# helper functions for reading/processing images
|
||||
def preprocess_image(image_path):
|
||||
img = load_img(image_path, target_size=(img_nrows, img_ncols))
|
||||
img = img_to_array(img)
|
||||
img = np.expand_dims(img, axis=0)
|
||||
img = vgg19.preprocess_input(img)
|
||||
return img
|
||||
|
||||
|
||||
def deprocess_image(x):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((3, img_nrows, img_ncols))
|
||||
x = x.transpose((1, 2, 0))
|
||||
else:
|
||||
x = x.reshape((img_nrows, img_ncols, 3))
|
||||
x = x[:, :, ::-1]
|
||||
x[:, :, 0] += 103.939
|
||||
x[:, :, 1] += 116.779
|
||||
x[:, :, 2] += 123.68
|
||||
x = np.clip(x, 0, 255).astype('uint8')
|
||||
return x
|
||||
|
||||
|
||||
def kmeans(xs, k):
|
||||
assert xs.ndim == 2
|
||||
try:
|
||||
from sklearn.cluster import k_means
|
||||
_, labels, _ = k_means(xs.astype("float64"), k)
|
||||
except ImportError:
|
||||
from scipy.cluster.vq import kmeans2
|
||||
_, labels = kmeans2(xs, k, missing='raise')
|
||||
return labels
|
||||
|
||||
|
||||
def load_mask_labels():
|
||||
'''Load both target and style masks.
|
||||
A mask image (nr x nc) with m labels/colors will be loaded
|
||||
as a 4D boolean tensor: (1, m, nr, nc) for 'th' or (1, nr, nc, m) for 'tf'
|
||||
'''
|
||||
target_mask_img = load_img(target_mask_path,
|
||||
target_size=(img_nrows, img_ncols))
|
||||
target_mask_img = img_to_array(target_mask_img)
|
||||
style_mask_img = load_img(style_mask_path,
|
||||
target_size=(img_nrows, img_ncols))
|
||||
style_mask_img = img_to_array(style_mask_img)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
mask_vecs = np.vstack([style_mask_img.reshape((3, -1)).T,
|
||||
target_mask_img.reshape((3, -1)).T])
|
||||
else:
|
||||
mask_vecs = np.vstack([style_mask_img.reshape((-1, 3)),
|
||||
target_mask_img.reshape((-1, 3))])
|
||||
|
||||
labels = kmeans(mask_vecs, nb_labels)
|
||||
style_mask_label = labels[:img_nrows *
|
||||
img_ncols].reshape((img_nrows, img_ncols))
|
||||
target_mask_label = labels[img_nrows *
|
||||
img_ncols:].reshape((img_nrows, img_ncols))
|
||||
|
||||
stack_axis = 0 if K.image_dim_ordering() == 'th' else -1
|
||||
style_mask = np.stack([style_mask_label == r for r in xrange(nb_labels)],
|
||||
axis=stack_axis)
|
||||
target_mask = np.stack([target_mask_label == r for r in xrange(nb_labels)],
|
||||
axis=stack_axis)
|
||||
|
||||
return (np.expand_dims(style_mask, axis=0),
|
||||
np.expand_dims(target_mask, axis=0))
|
||||
|
||||
# Create tensor variables for images
|
||||
if K.image_dim_ordering() == 'th':
|
||||
shape = (1, nb_colors, img_nrows, img_ncols)
|
||||
else:
|
||||
shape = (1, img_nrows, img_ncols, nb_colors)
|
||||
|
||||
style_image = K.variable(preprocess_image(style_img_path))
|
||||
target_image = K.placeholder(shape=shape)
|
||||
if use_content_img:
|
||||
content_image = K.variable(preprocess_image(content_img_path))
|
||||
else:
|
||||
content_image = K.zeros(shape=shape)
|
||||
|
||||
images = K.concatenate([style_image, target_image, content_image], axis=0)
|
||||
|
||||
# Create tensor variables for masks
|
||||
raw_style_mask, raw_target_mask = load_mask_labels()
|
||||
style_mask = K.variable(raw_style_mask.astype("float32"))
|
||||
target_mask = K.variable(raw_target_mask.astype("float32"))
|
||||
masks = K.concatenate([style_mask, target_mask], axis=0)
|
||||
|
||||
# index constants for images and tasks variables
|
||||
STYLE, TARGET, CONTENT = 0, 1, 2
|
||||
|
||||
# Build image model, mask model and use layer outputs as features
|
||||
# image model as VGG19
|
||||
image_model = vgg19.VGG19(include_top=False, input_tensor=images)
|
||||
|
||||
# mask model as a series of pooling
|
||||
mask_input = Input(tensor=masks, shape=(None, None, None), name="mask_input")
|
||||
x = mask_input
|
||||
for layer in image_model.layers[1:]:
|
||||
name = 'mask_%s' % layer.name
|
||||
if 'conv' in layer.name:
|
||||
x = AveragePooling2D((3, 3), strides=(
|
||||
1, 1), name=name, border_mode="same")(x)
|
||||
elif 'pool' in layer.name:
|
||||
x = AveragePooling2D((2, 2), name=name)(x)
|
||||
mask_model = Model(mask_input, x)
|
||||
|
||||
# Collect features from image_model and task_model
|
||||
image_features = {}
|
||||
mask_features = {}
|
||||
for img_layer, mask_layer in zip(image_model.layers, mask_model.layers):
|
||||
if 'conv' in img_layer.name:
|
||||
assert 'mask_' + img_layer.name == mask_layer.name
|
||||
layer_name = img_layer.name
|
||||
img_feat, mask_feat = img_layer.output, mask_layer.output
|
||||
image_features[layer_name] = img_feat
|
||||
mask_features[layer_name] = mask_feat
|
||||
|
||||
|
||||
# Define loss functions
|
||||
def gram_matrix(x):
|
||||
assert K.ndim(x) == 3
|
||||
features = K.batch_flatten(x)
|
||||
gram = K.dot(features, K.transpose(features))
|
||||
return gram
|
||||
|
||||
|
||||
def region_style_loss(style_image, target_image, style_mask, target_mask):
|
||||
'''Calculate style loss between style_image and target_image,
|
||||
for one common region specified by their (boolean) masks
|
||||
'''
|
||||
assert 3 == K.ndim(style_image) == K.ndim(target_image)
|
||||
assert 2 == K.ndim(style_mask) == K.ndim(target_mask)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
masked_style = style_image * style_mask
|
||||
masked_target = target_image * target_mask
|
||||
nb_channels = K.shape(style_image)[0]
|
||||
else:
|
||||
masked_style = K.permute_dimensions(
|
||||
style_image, (2, 0, 1)) * style_mask
|
||||
masked_target = K.permute_dimensions(
|
||||
target_image, (2, 0, 1)) * target_mask
|
||||
nb_channels = K.shape(style_image)[-1]
|
||||
s = gram_matrix(masked_style) / K.mean(style_mask) / nb_channels
|
||||
c = gram_matrix(masked_target) / K.mean(target_mask) / nb_channels
|
||||
return K.mean(K.square(s - c))
|
||||
|
||||
|
||||
def style_loss(style_image, target_image, style_masks, target_masks):
|
||||
'''Calculate style loss between style_image and target_image,
|
||||
in all regions.
|
||||
'''
|
||||
assert 3 == K.ndim(style_image) == K.ndim(target_image)
|
||||
assert 3 == K.ndim(style_masks) == K.ndim(target_masks)
|
||||
loss = K.variable(0)
|
||||
for i in xrange(nb_labels):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
style_mask = style_masks[i, :, :]
|
||||
target_mask = target_masks[i, :, :]
|
||||
else:
|
||||
style_mask = style_masks[:, :, i]
|
||||
target_mask = target_masks[:, :, i]
|
||||
loss += region_style_loss(style_image,
|
||||
target_image, style_mask, target_mask)
|
||||
return loss
|
||||
|
||||
|
||||
def content_loss(content_image, target_image):
|
||||
return K.sum(K.square(target_image - content_image))
|
||||
|
||||
|
||||
def total_variation_loss(x):
|
||||
assert 4 == K.ndim(x)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
a = K.square(x[:, :, :img_nrows - 1, :img_ncols - 1] -
|
||||
x[:, :, 1:, :img_ncols - 1])
|
||||
b = K.square(x[:, :, :img_nrows - 1, :img_ncols - 1] -
|
||||
x[:, :, :img_nrows - 1, 1:])
|
||||
else:
|
||||
a = K.square(x[:, :img_nrows - 1, :img_ncols - 1, :] -
|
||||
x[:, 1:, :img_ncols - 1, :])
|
||||
b = K.square(x[:, :img_nrows - 1, :img_ncols - 1, :] -
|
||||
x[:, :img_nrows - 1, 1:, :])
|
||||
return K.sum(K.pow(a + b, 1.25))
|
||||
|
||||
# Overall loss is the weighted sum of content_loss, style_loss and tv_loss
|
||||
# Each individual loss uses features from image/mask models.
|
||||
loss = K.variable(0)
|
||||
for layer in content_feature_layers:
|
||||
content_feat = image_features[layer][CONTENT, :, :, :]
|
||||
target_feat = image_features[layer][TARGET, :, :, :]
|
||||
loss += content_weight * content_loss(content_feat, target_feat)
|
||||
|
||||
for layer in style_feature_layers:
|
||||
style_feat = image_features[layer][STYLE, :, :, :]
|
||||
target_feat = image_features[layer][TARGET, :, :, :]
|
||||
style_masks = mask_features[layer][STYLE, :, :, :]
|
||||
target_masks = mask_features[layer][TARGET, :, :, :]
|
||||
sl = style_loss(style_feat, target_feat, style_masks, target_masks)
|
||||
loss += (style_weight / len(style_feature_layers)) * sl
|
||||
|
||||
loss += total_variation_weight * total_variation_loss(target_image)
|
||||
loss_grads = K.gradients(loss, target_image)
|
||||
|
||||
# Evaluator class for computing efficiency
|
||||
outputs = [loss]
|
||||
if type(loss_grads) in {list, tuple}:
|
||||
outputs += loss_grads
|
||||
else:
|
||||
outputs.append(loss_grads)
|
||||
|
||||
f_outputs = K.function([target_image], outputs)
|
||||
|
||||
|
||||
def eval_loss_and_grads(x):
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((1, 3, img_nrows, img_ncols))
|
||||
else:
|
||||
x = x.reshape((1, img_nrows, img_ncols, 3))
|
||||
outs = f_outputs([x])
|
||||
loss_value = outs[0]
|
||||
if len(outs[1:]) == 1:
|
||||
grad_values = outs[1].flatten().astype('float64')
|
||||
else:
|
||||
grad_values = np.array(outs[1:]).flatten().astype('float64')
|
||||
return loss_value, grad_values
|
||||
|
||||
|
||||
class Evaluator(object):
|
||||
|
||||
def __init__(self):
|
||||
self.loss_value = None
|
||||
self.grads_values = None
|
||||
|
||||
def loss(self, x):
|
||||
assert self.loss_value is None
|
||||
loss_value, grad_values = eval_loss_and_grads(x)
|
||||
self.loss_value = loss_value
|
||||
self.grad_values = grad_values
|
||||
return self.loss_value
|
||||
|
||||
def grads(self, x):
|
||||
assert self.loss_value is not None
|
||||
grad_values = np.copy(self.grad_values)
|
||||
self.loss_value = None
|
||||
self.grad_values = None
|
||||
return grad_values
|
||||
|
||||
evaluator = Evaluator()
|
||||
|
||||
# Generate images by iterative optimization
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = np.random.uniform(0, 255, (1, 3, img_nrows, img_ncols)) - 128.
|
||||
else:
|
||||
x = np.random.uniform(0, 255, (1, img_nrows, img_ncols, 3)) - 128.
|
||||
|
||||
for i in range(50):
|
||||
print('Start of iteration', i)
|
||||
start_time = time.time()
|
||||
x, min_val, info = fmin_l_bfgs_b(evaluator.loss, x.flatten(),
|
||||
fprime=evaluator.grads, maxfun=20)
|
||||
print('Current loss value:', min_val)
|
||||
# save current generated image
|
||||
img = deprocess_image(x.copy())
|
||||
fname = target_img_prefix + '_at_iteration_%d.png' % i
|
||||
imsave(fname, img)
|
||||
end_time = time.time()
|
||||
print('Image saved as', fname)
|
||||
print('Iteration %d completed in %ds' % (i, end_time - start_time))
|
||||
@@ -1,10 +1,5 @@
|
||||
'''Neural style transfer with Keras.
|
||||
|
||||
Before running this script, download the weights for the VGG16 model at:
|
||||
https://drive.google.com/file/d/0Bz7KyqmuGsilT0J5dmRCM0ROVHc/view?usp=sharing
|
||||
(source: https://gist.github.com/baraldilorenzo/07d7802847aaad0a35d3)
|
||||
and make sure the variable `weights_path` in this script matches the location of the file.
|
||||
|
||||
Run the script with:
|
||||
```
|
||||
python neural_style_transfer.py path_to_your_base_image.jpg path_to_your_reference.jpg prefix_for_results
|
||||
@@ -15,7 +10,6 @@ python neural_style_transfer.py img/tuebingen.jpg img/starry_night.jpg results/m
|
||||
```
|
||||
|
||||
It is preferable to run this script on GPU, for speed.
|
||||
If running on CPU, prefer the TensorFlow backend (much faster).
|
||||
|
||||
Example result: https://twitter.com/fchollet/status/686631033085677568
|
||||
|
||||
@@ -49,16 +43,14 @@ keeping the generated image close enough to the original one.
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
from scipy.misc import imread, imresize, imsave
|
||||
from keras.preprocessing.image import load_img, img_to_array
|
||||
from scipy.misc import imsave
|
||||
import numpy as np
|
||||
from scipy.optimize import fmin_l_bfgs_b
|
||||
import time
|
||||
import os
|
||||
import argparse
|
||||
import h5py
|
||||
|
||||
from keras.models import Sequential
|
||||
from keras.layers import Convolution2D, ZeroPadding2D, MaxPooling2D
|
||||
from keras.applications import vgg16
|
||||
from keras import backend as K
|
||||
|
||||
parser = argparse.ArgumentParser(description='Neural style transfer with Keras.')
|
||||
@@ -73,7 +65,6 @@ args = parser.parse_args()
|
||||
base_image_path = args.base_image_path
|
||||
style_reference_image_path = args.style_reference_image_path
|
||||
result_prefix = args.result_prefix
|
||||
weights_path = 'vgg16_weights.h5'
|
||||
|
||||
# these are the weights of the different loss components
|
||||
total_variation_weight = 1.
|
||||
@@ -81,20 +72,29 @@ style_weight = 1.
|
||||
content_weight = 0.025
|
||||
|
||||
# dimensions of the generated picture.
|
||||
img_width = 400
|
||||
img_height = 400
|
||||
assert img_height == img_width, 'Due to the use of the Gram matrix, width and height must match.'
|
||||
img_nrows = 400
|
||||
img_ncols = 400
|
||||
assert img_ncols == img_nrows, 'Due to the use of the Gram matrix, width and height must match.'
|
||||
|
||||
# util function to open, resize and format pictures into appropriate tensors
|
||||
def preprocess_image(image_path):
|
||||
img = imresize(imread(image_path), (img_width, img_height))
|
||||
img = img.transpose((2, 0, 1)).astype('float64')
|
||||
img = load_img(image_path, target_size=(img_nrows, img_ncols))
|
||||
img = img_to_array(img)
|
||||
img = np.expand_dims(img, axis=0)
|
||||
img = vgg16.preprocess_input(img)
|
||||
return img
|
||||
|
||||
# util function to convert a tensor into a valid image
|
||||
def deprocess_image(x):
|
||||
x = x.transpose((1, 2, 0))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((3, img_nrows, img_ncols))
|
||||
x = x.transpose((1, 2, 0))
|
||||
else:
|
||||
x = x.reshape((img_nrows, img_ncols, 3))
|
||||
x = x[:, :, ::-1]
|
||||
x[:, :, 0] += 103.939
|
||||
x[:, :, 1] += 116.779
|
||||
x[:, :, 2] += 123.68
|
||||
x = np.clip(x, 0, 255).astype('uint8')
|
||||
return x
|
||||
|
||||
@@ -103,7 +103,10 @@ base_image = K.variable(preprocess_image(base_image_path))
|
||||
style_reference_image = K.variable(preprocess_image(style_reference_image_path))
|
||||
|
||||
# this will contain our generated image
|
||||
combination_image = K.placeholder((1, 3, img_width, img_height))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
combination_image = K.placeholder((1, 3, img_nrows, img_ncols))
|
||||
else:
|
||||
combination_image = K.placeholder((1, img_nrows, img_ncols, 3))
|
||||
|
||||
# combine the 3 images into a single Keras tensor
|
||||
input_tensor = K.concatenate([base_image,
|
||||
@@ -111,60 +114,9 @@ input_tensor = K.concatenate([base_image,
|
||||
combination_image], axis=0)
|
||||
|
||||
# build the VGG16 network with our 3 images as input
|
||||
first_layer = ZeroPadding2D((1, 1))
|
||||
first_layer.set_input(input_tensor, shape=(3, 3, img_width, img_height))
|
||||
|
||||
model = Sequential()
|
||||
model.add(first_layer)
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu', name='conv1_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(64, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu', name='conv2_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(128, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu', name='conv3_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(256, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv4_2'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu', name='conv5_1'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu'))
|
||||
model.add(ZeroPadding2D((1, 1)))
|
||||
model.add(Convolution2D(512, 3, 3, activation='relu'))
|
||||
model.add(MaxPooling2D((2, 2), strides=(2, 2)))
|
||||
|
||||
# load the weights of the VGG16 networks
|
||||
# (trained on ImageNet, won the ILSVRC competition in 2014)
|
||||
# note: when there is a complete match between your model definition
|
||||
# and your weight savefile, you can simply call model.load_weights(filename)
|
||||
assert os.path.exists(weights_path), 'Model weights not found (see "weights_path" variable in script).'
|
||||
f = h5py.File(weights_path)
|
||||
for k in range(f.attrs['nb_layers']):
|
||||
if k >= len(model.layers):
|
||||
# we don't look at the last (fully-connected) layers in the savefile
|
||||
break
|
||||
g = f['layer_{}'.format(k)]
|
||||
weights = [g['param_{}'.format(p)] for p in range(g.attrs['nb_params'])]
|
||||
model.layers[k].set_weights(weights)
|
||||
f.close()
|
||||
# the model will be loaded with pre-trained ImageNet weights
|
||||
model = vgg16.VGG16(input_tensor=input_tensor,
|
||||
weights='imagenet', include_top=False)
|
||||
print('Model loaded.')
|
||||
|
||||
# get the symbolic outputs of each "key" layer (we gave them unique names).
|
||||
@@ -176,7 +128,10 @@ outputs_dict = dict([(layer.name, layer.output) for layer in model.layers])
|
||||
# the gram matrix of an image tensor (feature-wise outer product)
|
||||
def gram_matrix(x):
|
||||
assert K.ndim(x) == 3
|
||||
features = K.batch_flatten(x)
|
||||
if K.image_dim_ordering() == 'th':
|
||||
features = K.batch_flatten(x)
|
||||
else:
|
||||
features = K.batch_flatten(K.permute_dimensions(x, (2, 0, 1)))
|
||||
gram = K.dot(features, K.transpose(features))
|
||||
return gram
|
||||
|
||||
@@ -191,7 +146,7 @@ def style_loss(style, combination):
|
||||
S = gram_matrix(style)
|
||||
C = gram_matrix(combination)
|
||||
channels = 3
|
||||
size = img_width * img_height
|
||||
size = img_nrows * img_ncols
|
||||
return K.sum(K.square(S - C)) / (4. * (channels ** 2) * (size ** 2))
|
||||
|
||||
# an auxiliary loss function
|
||||
@@ -204,19 +159,25 @@ def content_loss(base, combination):
|
||||
# designed to keep the generated image locally coherent
|
||||
def total_variation_loss(x):
|
||||
assert K.ndim(x) == 4
|
||||
a = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, 1:, :img_height-1])
|
||||
b = K.square(x[:, :, :img_width-1, :img_height-1] - x[:, :, :img_width-1, 1:])
|
||||
if K.image_dim_ordering() == 'th':
|
||||
a = K.square(x[:, :, :img_nrows-1, :img_ncols-1] - x[:, :, 1:, :img_ncols-1])
|
||||
b = K.square(x[:, :, :img_nrows-1, :img_ncols-1] - x[:, :, :img_nrows-1, 1:])
|
||||
else:
|
||||
a = K.square(x[:, :img_nrows-1, :img_ncols-1, :] - x[:, 1:, :img_ncols-1, :])
|
||||
b = K.square(x[:, :img_nrows-1, :img_ncols-1, :] - x[:, :img_nrows-1, 1:, :])
|
||||
return K.sum(K.pow(a + b, 1.25))
|
||||
|
||||
# combine these loss functions into a single scalar
|
||||
loss = K.variable(0.)
|
||||
layer_features = outputs_dict['conv4_2']
|
||||
layer_features = outputs_dict['block4_conv2']
|
||||
base_image_features = layer_features[0, :, :, :]
|
||||
combination_features = layer_features[2, :, :, :]
|
||||
loss += content_weight * content_loss(base_image_features,
|
||||
combination_features)
|
||||
|
||||
feature_layers = ['conv1_1', 'conv2_1', 'conv3_1', 'conv4_1', 'conv5_1']
|
||||
feature_layers = ['block1_conv1', 'block2_conv1',
|
||||
'block3_conv1', 'block4_conv1',
|
||||
'block5_conv1']
|
||||
for layer_name in feature_layers:
|
||||
layer_features = outputs_dict[layer_name]
|
||||
style_reference_features = layer_features[1, :, :, :]
|
||||
@@ -235,8 +196,12 @@ else:
|
||||
outputs.append(grads)
|
||||
|
||||
f_outputs = K.function([combination_image], outputs)
|
||||
|
||||
def eval_loss_and_grads(x):
|
||||
x = x.reshape((1, 3, img_width, img_height))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = x.reshape((1, 3, img_nrows, img_ncols))
|
||||
else:
|
||||
x = x.reshape((1, img_nrows, img_ncols, 3))
|
||||
outs = f_outputs([x])
|
||||
loss_value = outs[0]
|
||||
if len(outs[1:]) == 1:
|
||||
@@ -274,7 +239,11 @@ evaluator = Evaluator()
|
||||
|
||||
# run scipy-based optimization (L-BFGS) over the pixels of the generated image
|
||||
# so as to minimize the neural style loss
|
||||
x = np.random.uniform(0, 255, (1, 3, img_width, img_height))
|
||||
if K.image_dim_ordering() == 'th':
|
||||
x = np.random.uniform(0, 255, (1, 3, img_nrows, img_ncols)) - 128.
|
||||
else:
|
||||
x = np.random.uniform(0, 255, (1, img_nrows, img_ncols, 3)) - 128.
|
||||
|
||||
for i in range(10):
|
||||
print('Start of iteration', i)
|
||||
start_time = time.time()
|
||||
@@ -282,7 +251,7 @@ for i in range(10):
|
||||
fprime=evaluator.grads, maxfun=20)
|
||||
print('Current loss value:', min_val)
|
||||
# save current generated image
|
||||
img = deprocess_image(x.reshape((3, img_width, img_height)))
|
||||
img = deprocess_image(x.copy())
|
||||
fname = result_prefix + '_at_iteration_%d.png' % i
|
||||
imsave(fname, img)
|
||||
end_time = time.time()
|
||||
|
||||
@@ -0,0 +1,144 @@
|
||||
'''This script loads pre-trained word embeddings (GloVe embeddings)
|
||||
into a frozen Keras Embedding layer, and uses it to
|
||||
train a text classification model on the 20 Newsgroup dataset
|
||||
(classication of newsgroup messages into 20 different categories).
|
||||
|
||||
GloVe embedding data can be found at:
|
||||
http://nlp.stanford.edu/data/glove.6B.zip
|
||||
(source page: http://nlp.stanford.edu/projects/glove/)
|
||||
|
||||
20 Newsgroup data can be found at:
|
||||
http://www.cs.cmu.edu/afs/cs.cmu.edu/project/theo-20/www/data/news20.html
|
||||
'''
|
||||
|
||||
from __future__ import print_function
|
||||
import os
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
|
||||
from keras.preprocessing.text import Tokenizer
|
||||
from keras.preprocessing.sequence import pad_sequences
|
||||
from keras.utils.np_utils import to_categorical
|
||||
from keras.layers import Dense, Input, Flatten
|
||||
from keras.layers import Conv1D, MaxPooling1D, Embedding
|
||||
from keras.models import Model
|
||||
import sys
|
||||
|
||||
BASE_DIR = ''
|
||||
GLOVE_DIR = BASE_DIR + '/glove.6B/'
|
||||
TEXT_DATA_DIR = BASE_DIR + '/20_newsgroup/'
|
||||
MAX_SEQUENCE_LENGTH = 1000
|
||||
MAX_NB_WORDS = 20000
|
||||
EMBEDDING_DIM = 100
|
||||
VALIDATION_SPLIT = 0.2
|
||||
|
||||
# first, build index mapping words in the embeddings set
|
||||
# to their embedding vector
|
||||
|
||||
print('Indexing word vectors.')
|
||||
|
||||
embeddings_index = {}
|
||||
f = open(os.path.join(GLOVE_DIR, 'glove.6B.100d.txt'))
|
||||
for line in f:
|
||||
values = line.split()
|
||||
word = values[0]
|
||||
coefs = np.asarray(values[1:], dtype='float32')
|
||||
embeddings_index[word] = coefs
|
||||
f.close()
|
||||
|
||||
print('Found %s word vectors.' % len(embeddings_index))
|
||||
|
||||
# second, prepare text samples and their labels
|
||||
print('Processing text dataset')
|
||||
|
||||
texts = [] # list of text samples
|
||||
labels_index = {} # dictionary mapping label name to numeric id
|
||||
labels = [] # list of label ids
|
||||
for name in sorted(os.listdir(TEXT_DATA_DIR)):
|
||||
path = os.path.join(TEXT_DATA_DIR, name)
|
||||
if os.path.isdir(path):
|
||||
label_id = len(labels_index)
|
||||
labels_index[name] = label_id
|
||||
for fname in sorted(os.listdir(path)):
|
||||
if fname.isdigit():
|
||||
fpath = os.path.join(path, fname)
|
||||
if sys.version_info < (3,):
|
||||
f = open(fpath)
|
||||
else:
|
||||
f = open(fpath, encoding='latin-1')
|
||||
texts.append(f.read())
|
||||
f.close()
|
||||
labels.append(label_id)
|
||||
|
||||
print('Found %s texts.' % len(texts))
|
||||
|
||||
# finally, vectorize the text samples into a 2D integer tensor
|
||||
tokenizer = Tokenizer(nb_words=MAX_NB_WORDS)
|
||||
tokenizer.fit_on_texts(texts)
|
||||
sequences = tokenizer.texts_to_sequences(texts)
|
||||
|
||||
word_index = tokenizer.word_index
|
||||
print('Found %s unique tokens.' % len(word_index))
|
||||
|
||||
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
|
||||
|
||||
labels = to_categorical(np.asarray(labels))
|
||||
print('Shape of data tensor:', data.shape)
|
||||
print('Shape of label tensor:', labels.shape)
|
||||
|
||||
# split the data into a training set and a validation set
|
||||
indices = np.arange(data.shape[0])
|
||||
np.random.shuffle(indices)
|
||||
data = data[indices]
|
||||
labels = labels[indices]
|
||||
nb_validation_samples = int(VALIDATION_SPLIT * data.shape[0])
|
||||
|
||||
x_train = data[:-nb_validation_samples]
|
||||
y_train = labels[:-nb_validation_samples]
|
||||
x_val = data[-nb_validation_samples:]
|
||||
y_val = labels[-nb_validation_samples:]
|
||||
|
||||
print('Preparing embedding matrix.')
|
||||
|
||||
# prepare embedding matrix
|
||||
nb_words = min(MAX_NB_WORDS, len(word_index))
|
||||
embedding_matrix = np.zeros((nb_words + 1, EMBEDDING_DIM))
|
||||
for word, i in word_index.items():
|
||||
if i > MAX_NB_WORDS:
|
||||
continue
|
||||
embedding_vector = embeddings_index.get(word)
|
||||
if embedding_vector is not None:
|
||||
# words not found in embedding index will be all-zeros.
|
||||
embedding_matrix[i] = embedding_vector
|
||||
|
||||
# load pre-trained word embeddings into an Embedding layer
|
||||
# note that we set trainable = False so as to keep the embeddings fixed
|
||||
embedding_layer = Embedding(nb_words + 1,
|
||||
EMBEDDING_DIM,
|
||||
weights=[embedding_matrix],
|
||||
input_length=MAX_SEQUENCE_LENGTH,
|
||||
trainable=False)
|
||||
|
||||
print('Training model.')
|
||||
|
||||
# train a 1D convnet with global maxpooling
|
||||
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
|
||||
embedded_sequences = embedding_layer(sequence_input)
|
||||
x = Conv1D(128, 5, activation='relu')(embedded_sequences)
|
||||
x = MaxPooling1D(5)(x)
|
||||
x = Conv1D(128, 5, activation='relu')(x)
|
||||
x = MaxPooling1D(5)(x)
|
||||
x = Conv1D(128, 5, activation='relu')(x)
|
||||
x = MaxPooling1D(35)(x)
|
||||
x = Flatten()(x)
|
||||
x = Dense(128, activation='relu')(x)
|
||||
preds = Dense(len(labels_index), activation='softmax')(x)
|
||||
|
||||
model = Model(sequence_input, preds)
|
||||
model.compile(loss='categorical_crossentropy',
|
||||
optimizer='rmsprop',
|
||||
metrics=['acc'])
|
||||
|
||||
# happy learning!
|
||||
model.fit(x_train, y_train, validation_data=(x_val, y_val),
|
||||
nb_epoch=2, batch_size=128)
|
||||
@@ -16,7 +16,7 @@ epochs = 25
|
||||
lahead = 1
|
||||
|
||||
|
||||
def gen_cosine_amp(amp=100, period=25, x0=0, xn=50000, step=1, k=0.0001):
|
||||
def gen_cosine_amp(amp=100, period=1000, x0=0, xn=50000, step=1, k=0.0001):
|
||||
"""Generates an absolute cosine time series with the amplitude
|
||||
exponentially decreasing
|
||||
|
||||
@@ -31,7 +31,7 @@ def gen_cosine_amp(amp=100, period=25, x0=0, xn=50000, step=1, k=0.0001):
|
||||
cos = np.zeros(((xn - x0) * step, 1, 1))
|
||||
for i in range(len(cos)):
|
||||
idx = x0 + i * step
|
||||
cos[i, 0, 0] = amp * np.cos(idx / (2 * np.pi * period))
|
||||
cos[i, 0, 0] = amp * np.cos(2 * np.pi * idx / period)
|
||||
cos[i, 0, 0] = cos[i, 0, 0] * np.exp(-k * idx)
|
||||
return cos
|
||||
|
||||
|
||||
@@ -11,27 +11,25 @@ from keras import backend as K
|
||||
from keras import objectives
|
||||
from keras.datasets import mnist
|
||||
|
||||
batch_size = 16
|
||||
batch_size = 100
|
||||
original_dim = 784
|
||||
latent_dim = 2
|
||||
intermediate_dim = 128
|
||||
epsilon_std = 0.01
|
||||
nb_epoch = 40
|
||||
intermediate_dim = 256
|
||||
nb_epoch = 50
|
||||
|
||||
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)
|
||||
z_log_var = 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
|
||||
z_mean, z_log_var = args
|
||||
epsilon = K.random_normal(shape=(batch_size, latent_dim), mean=0.)
|
||||
return z_mean + K.exp(z_log_var / 2) * 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])
|
||||
z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var])
|
||||
|
||||
# we instantiate these layers separately so as to reuse them later
|
||||
decoder_h = Dense(intermediate_dim, activation='relu')
|
||||
@@ -39,9 +37,10 @@ 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)
|
||||
xent_loss = original_dim * objectives.binary_crossentropy(x, x_decoded_mean)
|
||||
kl_loss = - 0.5 * K.sum(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
|
||||
return xent_loss + kl_loss
|
||||
|
||||
vae = Model(x, x_decoded_mean)
|
||||
@@ -87,7 +86,7 @@ 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
|
||||
z_sample = np.array([[xi, yi]])
|
||||
x_decoded = generator.predict(z_sample)
|
||||
digit = x_decoded[0].reshape(digit_size, digit_size)
|
||||
figure[i * digit_size: (i + 1) * digit_size,
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
'''This script demonstrates how to build a variational autoencoder with Keras and deconvolution layers.
|
||||
|
||||
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, Flatten, Reshape
|
||||
from keras.layers import Convolution2D, Deconvolution2D, MaxPooling2D
|
||||
from keras.models import Model
|
||||
from keras import backend as K
|
||||
from keras import objectives
|
||||
from keras.datasets import mnist
|
||||
|
||||
# input image dimensions
|
||||
img_rows, img_cols, img_chns = 28, 28, 1
|
||||
# number of convolutional filters to use
|
||||
nb_filters = 32
|
||||
# convolution kernel size
|
||||
nb_conv = 3
|
||||
|
||||
batch_size = 16
|
||||
original_dim = (img_chns, img_rows, img_cols)
|
||||
latent_dim = 2
|
||||
intermediate_dim = 128
|
||||
epsilon_std = 0.01
|
||||
nb_epoch = 5
|
||||
|
||||
|
||||
x = Input(batch_shape=(batch_size,) + original_dim)
|
||||
c = Convolution2D(nb_filters, nb_conv, nb_conv, border_mode='same', activation='relu')(x)
|
||||
f = Flatten()(c)
|
||||
h = Dense(intermediate_dim, activation='relu')(f)
|
||||
|
||||
z_mean = Dense(latent_dim)(h)
|
||||
z_log_var = Dense(latent_dim)(h)
|
||||
|
||||
|
||||
def sampling(args):
|
||||
z_mean, z_log_var = args
|
||||
epsilon = K.random_normal(shape=(batch_size, latent_dim),
|
||||
mean=0., std=epsilon_std)
|
||||
return z_mean + K.exp(z_log_var) * epsilon
|
||||
|
||||
# note that "output_shape" isn't necessary with the TensorFlow backend
|
||||
# so you could write `Lambda(sampling)([z_mean, z_log_var])`
|
||||
z = Lambda(sampling, output_shape=(latent_dim,))([z_mean, z_log_var])
|
||||
|
||||
# we instantiate these layers separately so as to reuse them later
|
||||
decoder_h = Dense(intermediate_dim, activation='relu')
|
||||
decoder_f = Dense(nb_filters*img_rows*img_cols, activation='relu')
|
||||
decoder_c = Reshape((nb_filters, img_rows, img_cols))
|
||||
decoder_mean = Deconvolution2D(img_chns, nb_conv, nb_conv,
|
||||
(batch_size, img_chns, img_rows, img_cols),
|
||||
border_mode='same')
|
||||
|
||||
h_decoded = decoder_h(z)
|
||||
f_decoded = decoder_f(h_decoded)
|
||||
c_decoded = decoder_c(f_decoded)
|
||||
x_decoded_mean = decoder_mean(c_decoded)
|
||||
|
||||
|
||||
def vae_loss(x, x_decoded_mean):
|
||||
# NOTE: binary_crossentropy expects a batch_size by dim for x and x_decoded_mean, so we MUST flatten these!
|
||||
x = K.flatten(x)
|
||||
x_decoded_mean = K.flatten(x_decoded_mean)
|
||||
xent_loss = objectives.binary_crossentropy(x, x_decoded_mean)
|
||||
kl_loss = - 0.5 * K.mean(1 + z_log_var - K.square(z_mean) - K.exp(z_log_var), axis=-1)
|
||||
return xent_loss + kl_loss
|
||||
|
||||
vae = Model(x, x_decoded_mean)
|
||||
vae.compile(optimizer='rmsprop', loss=vae_loss)
|
||||
vae.summary()
|
||||
|
||||
# train the VAE on MNIST digits
|
||||
(x_train, y_train), (x_test, y_test) = mnist.load_data()
|
||||
|
||||
x_train = x_train.astype('float32')[:, None, :, :] / 255.
|
||||
x_test = x_test.astype('float32')[:, None, :, :] / 255.
|
||||
|
||||
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)
|
||||
_f_decoded = decoder_f(_h_decoded)
|
||||
_c_decoded = decoder_c(_f_decoded)
|
||||
_x_decoded_mean = decoder_mean(_c_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]])
|
||||
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()
|
||||
+1
-1
@@ -15,4 +15,4 @@ from . import objectives
|
||||
from . import optimizers
|
||||
from . import regularizers
|
||||
|
||||
__version__ = '1.0.6'
|
||||
__version__ = '1.1.0'
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
from .vgg16 import VGG16
|
||||
from .vgg19 import VGG19
|
||||
from .resnet50 import ResNet50
|
||||
from .inception_v3 import InceptionV3
|
||||
@@ -0,0 +1,43 @@
|
||||
import numpy as np
|
||||
import json
|
||||
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
|
||||
CLASS_INDEX = None
|
||||
CLASS_INDEX_PATH = 'https://s3.amazonaws.com/deep-learning-models/image-models/imagenet_class_index.json'
|
||||
|
||||
|
||||
def preprocess_input(x, dim_ordering='default'):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
assert dim_ordering in {'tf', 'th'}
|
||||
|
||||
if dim_ordering == 'th':
|
||||
x[:, 0, :, :] -= 103.939
|
||||
x[:, 1, :, :] -= 116.779
|
||||
x[:, 2, :, :] -= 123.68
|
||||
# 'RGB'->'BGR'
|
||||
x = x[:, ::-1, :, :]
|
||||
else:
|
||||
x[:, :, :, 0] -= 103.939
|
||||
x[:, :, :, 1] -= 116.779
|
||||
x[:, :, :, 2] -= 123.68
|
||||
# 'RGB'->'BGR'
|
||||
x = x[:, :, :, ::-1]
|
||||
return x
|
||||
|
||||
|
||||
def decode_predictions(preds):
|
||||
global CLASS_INDEX
|
||||
assert len(preds.shape) == 2 and preds.shape[1] == 1000
|
||||
if CLASS_INDEX is None:
|
||||
fpath = get_file('imagenet_class_index.json',
|
||||
CLASS_INDEX_PATH,
|
||||
cache_subdir='models')
|
||||
CLASS_INDEX = json.load(open(fpath))
|
||||
indices = np.argmax(preds, axis=-1)
|
||||
results = []
|
||||
for i in indices:
|
||||
results.append(CLASS_INDEX[str(i)])
|
||||
return results
|
||||
@@ -0,0 +1,312 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''Inception V3 model for Keras.
|
||||
|
||||
Note that the ImageNet weights provided are from a model that had not fully converged.
|
||||
Inception v3 should be able to reach 6.9% top-5 error, but our model
|
||||
only gets to 7.8% (same as a fully-converged ResNet 50).
|
||||
For comparison, VGG16 only gets to 9.9%, quite a bit worse.
|
||||
|
||||
Also, do note that the input image format for this model is different than for
|
||||
other models (299x299 instead of 224x224), and that the input preprocessing function
|
||||
is also different.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Rethinking the Inception Architecture for Computer Vision](http://arxiv.org/abs/1512.00567)
|
||||
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..models import Model
|
||||
from ..layers import Flatten, Dense, Input, BatchNormalization, merge
|
||||
from ..layers import Convolution2D, MaxPooling2D, AveragePooling2D
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
from .imagenet_utils import decode_predictions
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def conv2d_bn(x, nb_filter, nb_row, nb_col,
|
||||
border_mode='same', subsample=(1, 1),
|
||||
name=None):
|
||||
'''Utility function to apply conv + BN.
|
||||
'''
|
||||
if name is not None:
|
||||
bn_name = name + '_bn'
|
||||
conv_name = name + '_conv'
|
||||
else:
|
||||
bn_name = None
|
||||
conv_name = None
|
||||
if K.image_dim_ordering() == 'th':
|
||||
bn_axis = 1
|
||||
else:
|
||||
bn_axis = 3
|
||||
x = Convolution2D(nb_filter, nb_row, nb_col,
|
||||
subsample=subsample,
|
||||
activation='relu',
|
||||
border_mode=border_mode,
|
||||
name=conv_name)(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name)(x)
|
||||
return x
|
||||
|
||||
|
||||
def InceptionV3(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the Inception v3 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
Note that the default input image size for this model is 299x299.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 299, 299)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (299, 299, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
if input_tensor is None:
|
||||
img_input = Input(shape=input_shape)
|
||||
else:
|
||||
if not K.is_keras_tensor(input_tensor):
|
||||
img_input = Input(tensor=input_tensor, shape=input_shape)
|
||||
else:
|
||||
img_input = input_tensor
|
||||
|
||||
if K.image_dim_ordering() == 'th':
|
||||
channel_axis = 1
|
||||
else:
|
||||
channel_axis = 3
|
||||
|
||||
x = conv2d_bn(img_input, 32, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
x = conv2d_bn(x, 32, 3, 3, border_mode='valid')
|
||||
x = conv2d_bn(x, 64, 3, 3)
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
x = conv2d_bn(x, 80, 1, 1, border_mode='valid')
|
||||
x = conv2d_bn(x, 192, 3, 3, border_mode='valid')
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
# mixed 0, 1, 2: 35 x 35 x 256
|
||||
for i in range(3):
|
||||
branch1x1 = conv2d_bn(x, 64, 1, 1)
|
||||
|
||||
branch5x5 = conv2d_bn(x, 48, 1, 1)
|
||||
branch5x5 = conv2d_bn(branch5x5, 64, 5, 5)
|
||||
|
||||
branch3x3dbl = conv2d_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3)
|
||||
|
||||
branch_pool = AveragePooling2D(
|
||||
(3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 32, 1, 1)
|
||||
x = merge([branch1x1, branch5x5, branch3x3dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed' + str(i))
|
||||
|
||||
# mixed 3: 17 x 17 x 768
|
||||
branch3x3 = conv2d_bn(x, 384, 3, 3, subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch3x3dbl = conv2d_bn(x, 64, 1, 1)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 96, 3, 3,
|
||||
subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
x = merge([branch3x3, branch3x3dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed3')
|
||||
|
||||
# mixed 4: 17 x 17 x 768
|
||||
branch1x1 = conv2d_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2d_bn(x, 128, 1, 1)
|
||||
branch7x7 = conv2d_bn(branch7x7, 128, 1, 7)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2d_bn(x, 128, 1, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 1, 7)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 128, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed4')
|
||||
|
||||
# mixed 5, 6: 17 x 17 x 768
|
||||
for i in range(2):
|
||||
branch1x1 = conv2d_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2d_bn(x, 160, 1, 1)
|
||||
branch7x7 = conv2d_bn(branch7x7, 160, 1, 7)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2d_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 1, 7)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 160, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D(
|
||||
(3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed' + str(5 + i))
|
||||
|
||||
# mixed 7: 17 x 17 x 768
|
||||
branch1x1 = conv2d_bn(x, 192, 1, 1)
|
||||
|
||||
branch7x7 = conv2d_bn(x, 192, 1, 1)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 1, 7)
|
||||
branch7x7 = conv2d_bn(branch7x7, 192, 7, 1)
|
||||
|
||||
branch7x7dbl = conv2d_bn(x, 160, 1, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 7, 1)
|
||||
branch7x7dbl = conv2d_bn(branch7x7dbl, 192, 1, 7)
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch7x7, branch7x7dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed7')
|
||||
|
||||
# mixed 8: 8 x 8 x 1280
|
||||
branch3x3 = conv2d_bn(x, 192, 1, 1)
|
||||
branch3x3 = conv2d_bn(branch3x3, 320, 3, 3,
|
||||
subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch7x7x3 = conv2d_bn(x, 192, 1, 1)
|
||||
branch7x7x3 = conv2d_bn(branch7x7x3, 192, 1, 7)
|
||||
branch7x7x3 = conv2d_bn(branch7x7x3, 192, 7, 1)
|
||||
branch7x7x3 = conv2d_bn(branch7x7x3, 192, 3, 3,
|
||||
subsample=(2, 2), border_mode='valid')
|
||||
|
||||
branch_pool = AveragePooling2D((3, 3), strides=(2, 2))(x)
|
||||
x = merge([branch3x3, branch7x7x3, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed8')
|
||||
|
||||
# mixed 9: 8 x 8 x 2048
|
||||
for i in range(2):
|
||||
branch1x1 = conv2d_bn(x, 320, 1, 1)
|
||||
|
||||
branch3x3 = conv2d_bn(x, 384, 1, 1)
|
||||
branch3x3_1 = conv2d_bn(branch3x3, 384, 1, 3)
|
||||
branch3x3_2 = conv2d_bn(branch3x3, 384, 3, 1)
|
||||
branch3x3 = merge([branch3x3_1, branch3x3_2],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed9_' + str(i))
|
||||
|
||||
branch3x3dbl = conv2d_bn(x, 448, 1, 1)
|
||||
branch3x3dbl = conv2d_bn(branch3x3dbl, 384, 3, 3)
|
||||
branch3x3dbl_1 = conv2d_bn(branch3x3dbl, 384, 1, 3)
|
||||
branch3x3dbl_2 = conv2d_bn(branch3x3dbl, 384, 3, 1)
|
||||
branch3x3dbl = merge([branch3x3dbl_1, branch3x3dbl_2],
|
||||
mode='concat', concat_axis=channel_axis)
|
||||
|
||||
branch_pool = AveragePooling2D(
|
||||
(3, 3), strides=(1, 1), border_mode='same')(x)
|
||||
branch_pool = conv2d_bn(branch_pool, 192, 1, 1)
|
||||
x = merge([branch1x1, branch3x3, branch3x3dbl, branch_pool],
|
||||
mode='concat', concat_axis=channel_axis,
|
||||
name='mixed' + str(9 + i))
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = AveragePooling2D((8, 8), strides=(8, 8), name='avg_pool')(x)
|
||||
x = Flatten(name='flatten')(x)
|
||||
x = Dense(1000, activation='softmax', name='predictions')(x)
|
||||
|
||||
# Create model
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('inception_v3_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='b3baf3070cc4bf476d43a2ea61b0ca5f')
|
||||
else:
|
||||
weights_path = get_file('inception_v3_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='79aaa90ab4372b4593ba3df64e142f05')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('inception_v3_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='fe114b3ff2ea4bf891e9353d1bbfb32f')
|
||||
else:
|
||||
weights_path = get_file('inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='2f3609166de1d967d1a481094754f691')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
|
||||
|
||||
def preprocess_input(x):
|
||||
x /= 255.
|
||||
x -= 0.5
|
||||
x *= 2.
|
||||
return x
|
||||
@@ -0,0 +1,235 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''ResNet50 model for Keras.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Deep Residual Learning for Image Recognition](https://arxiv.org/abs/1512.03385)
|
||||
|
||||
Adapted from code contributed by BigMoyan.
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..layers import merge, Input
|
||||
from ..layers import Dense, Activation, Flatten
|
||||
from ..layers import Convolution2D, MaxPooling2D, ZeroPadding2D, AveragePooling2D
|
||||
from ..layers import BatchNormalization
|
||||
from ..models import Model
|
||||
from .. import backend as K
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .imagenet_utils import decode_predictions, preprocess_input
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.2/resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def identity_block(input_tensor, kernel_size, filters, stage, block):
|
||||
'''The identity_block is the block that has no conv layer at shortcut
|
||||
|
||||
# Arguments
|
||||
input_tensor: input tensor
|
||||
kernel_size: defualt 3, the kernel size of middle conv layer at main path
|
||||
filters: list of integers, the nb_filters of 3 conv layer at main path
|
||||
stage: integer, current stage label, used for generating layer names
|
||||
block: 'a','b'..., current block label, used for generating layer names
|
||||
'''
|
||||
nb_filter1, nb_filter2, nb_filter3 = filters
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
conv_name_base = 'res' + str(stage) + block + '_branch'
|
||||
bn_name_base = 'bn' + str(stage) + block + '_branch'
|
||||
|
||||
x = Convolution2D(nb_filter1, 1, 1, name=conv_name_base + '2a')(input_tensor)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter2, kernel_size, kernel_size,
|
||||
border_mode='same', name=conv_name_base + '2b')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)
|
||||
|
||||
x = merge([x, input_tensor], mode='sum')
|
||||
x = Activation('relu')(x)
|
||||
return x
|
||||
|
||||
|
||||
def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)):
|
||||
'''conv_block is the block that has a conv layer at shortcut
|
||||
|
||||
# Arguments
|
||||
input_tensor: input tensor
|
||||
kernel_size: defualt 3, the kernel size of middle conv layer at main path
|
||||
filters: list of integers, the nb_filters of 3 conv layer at main path
|
||||
stage: integer, current stage label, used for generating layer names
|
||||
block: 'a','b'..., current block label, used for generating layer names
|
||||
|
||||
Note that from stage 3, the first conv layer at main path is with subsample=(2,2)
|
||||
And the shortcut should have subsample=(2,2) as well
|
||||
'''
|
||||
nb_filter1, nb_filter2, nb_filter3 = filters
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
conv_name_base = 'res' + str(stage) + block + '_branch'
|
||||
bn_name_base = 'bn' + str(stage) + block + '_branch'
|
||||
|
||||
x = Convolution2D(nb_filter1, 1, 1, subsample=strides,
|
||||
name=conv_name_base + '2a')(input_tensor)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2a')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter2, kernel_size, kernel_size, border_mode='same',
|
||||
name=conv_name_base + '2b')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2b')(x)
|
||||
x = Activation('relu')(x)
|
||||
|
||||
x = Convolution2D(nb_filter3, 1, 1, name=conv_name_base + '2c')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name=bn_name_base + '2c')(x)
|
||||
|
||||
shortcut = Convolution2D(nb_filter3, 1, 1, subsample=strides,
|
||||
name=conv_name_base + '1')(input_tensor)
|
||||
shortcut = BatchNormalization(axis=bn_axis, name=bn_name_base + '1')(shortcut)
|
||||
|
||||
x = merge([x, shortcut], mode='sum')
|
||||
x = Activation('relu')(x)
|
||||
return x
|
||||
|
||||
|
||||
def ResNet50(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the ResNet50 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. xput of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 224, 224)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (224, 224, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
if input_tensor is None:
|
||||
img_input = Input(shape=input_shape)
|
||||
else:
|
||||
if not K.is_keras_tensor(input_tensor):
|
||||
img_input = Input(tensor=input_tensor, shape=input_shape)
|
||||
else:
|
||||
img_input = input_tensor
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
bn_axis = 3
|
||||
else:
|
||||
bn_axis = 1
|
||||
|
||||
x = ZeroPadding2D((3, 3))(img_input)
|
||||
x = Convolution2D(64, 7, 7, subsample=(2, 2), name='conv1')(x)
|
||||
x = BatchNormalization(axis=bn_axis, name='bn_conv1')(x)
|
||||
x = Activation('relu')(x)
|
||||
x = MaxPooling2D((3, 3), strides=(2, 2))(x)
|
||||
|
||||
x = conv_block(x, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1))
|
||||
x = identity_block(x, 3, [64, 64, 256], stage=2, block='b')
|
||||
x = identity_block(x, 3, [64, 64, 256], stage=2, block='c')
|
||||
|
||||
x = conv_block(x, 3, [128, 128, 512], stage=3, block='a')
|
||||
x = identity_block(x, 3, [128, 128, 512], stage=3, block='b')
|
||||
x = identity_block(x, 3, [128, 128, 512], stage=3, block='c')
|
||||
x = identity_block(x, 3, [128, 128, 512], stage=3, block='d')
|
||||
|
||||
x = conv_block(x, 3, [256, 256, 1024], stage=4, block='a')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='b')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='c')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='d')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='e')
|
||||
x = identity_block(x, 3, [256, 256, 1024], stage=4, block='f')
|
||||
|
||||
x = conv_block(x, 3, [512, 512, 2048], stage=5, block='a')
|
||||
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='b')
|
||||
x = identity_block(x, 3, [512, 512, 2048], stage=5, block='c')
|
||||
|
||||
x = AveragePooling2D((7, 7), name='avg_pool')(x)
|
||||
|
||||
if include_top:
|
||||
x = Flatten()(x)
|
||||
x = Dense(1000, activation='softmax', name='fc1000')(x)
|
||||
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('resnet50_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='1c1f8f5b0c8ee28fe9d950625a230e1c')
|
||||
else:
|
||||
weights_path = get_file('resnet50_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='f64f049c92468c9affcd44b0976cdafe')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('resnet50_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models',
|
||||
md5_hash='a7b3fe01876f51b976af0dea6bc144eb')
|
||||
else:
|
||||
weights_path = get_file('resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models',
|
||||
md5_hash='a268eb855778b3df3c7506639542a6af')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
@@ -0,0 +1,149 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''VGG16 model for Keras.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)
|
||||
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..models import Model
|
||||
from ..layers import Flatten, Dense, Input
|
||||
from ..layers import Convolution2D, MaxPooling2D
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
from .imagenet_utils import decode_predictions, preprocess_input
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def VGG16(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the VGG16 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 224, 224)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (224, 224, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
if input_tensor is None:
|
||||
img_input = Input(shape=input_shape)
|
||||
else:
|
||||
if not K.is_keras_tensor(input_tensor):
|
||||
img_input = Input(tensor=input_tensor, shape=input_shape)
|
||||
else:
|
||||
img_input = input_tensor
|
||||
# Block 1
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv1')(img_input)
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
|
||||
|
||||
# Block 2
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv1')(x)
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
|
||||
|
||||
# Block 3
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv1')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv2')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv3')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
|
||||
|
||||
# Block 4
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv3')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
|
||||
|
||||
# Block 5
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv3')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = Flatten(name='flatten')(x)
|
||||
x = Dense(4096, activation='relu', name='fc1')(x)
|
||||
x = Dense(4096, activation='relu', name='fc2')(x)
|
||||
x = Dense(1000, activation='softmax', name='predictions')(x)
|
||||
|
||||
# Create model
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('vgg16_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg16_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('vgg16_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
@@ -0,0 +1,152 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''VGG19 model for Keras.
|
||||
|
||||
# Reference:
|
||||
|
||||
- [Very Deep Convolutional Networks for Large-Scale Image Recognition](https://arxiv.org/abs/1409.1556)
|
||||
|
||||
'''
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
|
||||
import warnings
|
||||
|
||||
from ..models import Model
|
||||
from ..layers import Flatten, Dense, Input
|
||||
from ..layers import Convolution2D, MaxPooling2D
|
||||
from ..utils.layer_utils import convert_all_kernels_in_model
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
from .imagenet_utils import decode_predictions, preprocess_input
|
||||
|
||||
|
||||
TH_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_th_dim_ordering_th_kernels.h5'
|
||||
TF_WEIGHTS_PATH = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels.h5'
|
||||
TH_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_th_dim_ordering_th_kernels_notop.h5'
|
||||
TF_WEIGHTS_PATH_NO_TOP = 'https://github.com/fchollet/deep-learning-models/releases/download/v0.1/vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5'
|
||||
|
||||
|
||||
def VGG19(include_top=True, weights='imagenet',
|
||||
input_tensor=None):
|
||||
'''Instantiate the VGG19 architecture,
|
||||
optionally loading weights pre-trained
|
||||
on ImageNet. Note that when using TensorFlow,
|
||||
for best performance you should set
|
||||
`image_dim_ordering="tf"` in your Keras config
|
||||
at ~/.keras/keras.json.
|
||||
|
||||
The model and the weights are compatible with both
|
||||
TensorFlow and Theano. The dimension ordering
|
||||
convention used by the model is the one
|
||||
specified in your Keras config file.
|
||||
|
||||
# Arguments
|
||||
include_top: whether to include the 3 fully-connected
|
||||
layers at the top of the network.
|
||||
weights: one of `None` (random initialization)
|
||||
or "imagenet" (pre-training on ImageNet).
|
||||
input_tensor: optional Keras tensor (i.e. output of `layers.Input()`)
|
||||
to use as image input for the model.
|
||||
|
||||
# Returns
|
||||
A Keras model instance.
|
||||
'''
|
||||
if weights not in {'imagenet', None}:
|
||||
raise ValueError('The `weights` argument should be either '
|
||||
'`None` (random initialization) or `imagenet` '
|
||||
'(pre-training on ImageNet).')
|
||||
# Determine proper input shape
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
input_shape = (3, 224, 224)
|
||||
else:
|
||||
input_shape = (3, None, None)
|
||||
else:
|
||||
if include_top:
|
||||
input_shape = (224, 224, 3)
|
||||
else:
|
||||
input_shape = (None, None, 3)
|
||||
|
||||
if input_tensor is None:
|
||||
img_input = Input(shape=input_shape)
|
||||
else:
|
||||
if not K.is_keras_tensor(input_tensor):
|
||||
img_input = Input(tensor=input_tensor, shape=input_shape)
|
||||
else:
|
||||
img_input = input_tensor
|
||||
# Block 1
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv1')(img_input)
|
||||
x = Convolution2D(64, 3, 3, activation='relu', border_mode='same', name='block1_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block1_pool')(x)
|
||||
|
||||
# Block 2
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv1')(x)
|
||||
x = Convolution2D(128, 3, 3, activation='relu', border_mode='same', name='block2_conv2')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block2_pool')(x)
|
||||
|
||||
# Block 3
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv1')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv2')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv3')(x)
|
||||
x = Convolution2D(256, 3, 3, activation='relu', border_mode='same', name='block3_conv4')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block3_pool')(x)
|
||||
|
||||
# Block 4
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv3')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block4_conv4')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block4_pool')(x)
|
||||
|
||||
# Block 5
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv1')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv2')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv3')(x)
|
||||
x = Convolution2D(512, 3, 3, activation='relu', border_mode='same', name='block5_conv4')(x)
|
||||
x = MaxPooling2D((2, 2), strides=(2, 2), name='block5_pool')(x)
|
||||
|
||||
if include_top:
|
||||
# Classification block
|
||||
x = Flatten(name='flatten')(x)
|
||||
x = Dense(4096, activation='relu', name='fc1')(x)
|
||||
x = Dense(4096, activation='relu', name='fc2')(x)
|
||||
x = Dense(1000, activation='softmax', name='predictions')(x)
|
||||
|
||||
# Create model
|
||||
model = Model(img_input, x)
|
||||
|
||||
# load weights
|
||||
if weights == 'imagenet':
|
||||
if K.image_dim_ordering() == 'th':
|
||||
if include_top:
|
||||
weights_path = get_file('vgg19_weights_th_dim_ordering_th_kernels.h5',
|
||||
TH_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg19_weights_th_dim_ordering_th_kernels_notop.h5',
|
||||
TH_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'tensorflow':
|
||||
warnings.warn('You are using the TensorFlow backend, yet you '
|
||||
'are using the Theano '
|
||||
'image dimension ordering convention '
|
||||
'(`image_dim_ordering="th"`). '
|
||||
'For best performance, set '
|
||||
'`image_dim_ordering="tf"` in '
|
||||
'your Keras config '
|
||||
'at ~/.keras/keras.json.')
|
||||
convert_all_kernels_in_model(model)
|
||||
else:
|
||||
if include_top:
|
||||
weights_path = get_file('vgg19_weights_tf_dim_ordering_tf_kernels.h5',
|
||||
TF_WEIGHTS_PATH,
|
||||
cache_subdir='models')
|
||||
else:
|
||||
weights_path = get_file('vgg19_weights_tf_dim_ordering_tf_kernels_notop.h5',
|
||||
TF_WEIGHTS_PATH_NO_TOP,
|
||||
cache_subdir='models')
|
||||
model.load_weights(weights_path)
|
||||
if K.backend() == 'theano':
|
||||
convert_all_kernels_in_model(model)
|
||||
return model
|
||||
@@ -11,6 +11,9 @@ from .common import get_uid
|
||||
from .common import cast_to_floatx
|
||||
from .common import image_dim_ordering
|
||||
from .common import set_image_dim_ordering
|
||||
from .common import is_keras_tensor
|
||||
from .common import legacy_weight_ordering
|
||||
from .common import set_legacy_weight_ordering
|
||||
|
||||
_keras_base_dir = os.path.expanduser('~')
|
||||
if not os.access(_keras_base_dir, os.W_OK):
|
||||
@@ -20,7 +23,7 @@ _keras_dir = os.path.join(_keras_base_dir, '.keras')
|
||||
if not os.path.exists(_keras_dir):
|
||||
os.makedirs(_keras_dir)
|
||||
|
||||
_BACKEND = 'theano'
|
||||
_BACKEND = 'tensorflow'
|
||||
_config_path = os.path.expanduser(os.path.join(_keras_dir, 'keras.json'))
|
||||
if os.path.exists(_config_path):
|
||||
_config = json.load(open(_config_path))
|
||||
@@ -39,12 +42,13 @@ if os.path.exists(_config_path):
|
||||
_BACKEND = _backend
|
||||
|
||||
# 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 not os.path.exists(_config_path):
|
||||
_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']
|
||||
@@ -60,3 +64,10 @@ elif _BACKEND == 'tensorflow':
|
||||
from .tensorflow_backend import *
|
||||
else:
|
||||
raise Exception('Unknown backend: ' + str(_BACKEND))
|
||||
|
||||
|
||||
def backend():
|
||||
'''Publicly accessible method
|
||||
for determining the current backend.
|
||||
'''
|
||||
return _BACKEND
|
||||
|
||||
@@ -6,7 +6,8 @@ from collections import defaultdict
|
||||
_FLOATX = 'float32'
|
||||
_EPSILON = 10e-8
|
||||
_UID_PREFIXES = defaultdict(int)
|
||||
_IMAGE_DIM_ORDERING = 'th'
|
||||
_IMAGE_DIM_ORDERING = 'tf'
|
||||
_LEGACY_WEIGHT_ORDERING = False
|
||||
|
||||
|
||||
def epsilon():
|
||||
@@ -64,3 +65,25 @@ def set_image_dim_ordering(dim_ordering):
|
||||
def get_uid(prefix=''):
|
||||
_UID_PREFIXES[prefix] += 1
|
||||
return _UID_PREFIXES[prefix]
|
||||
|
||||
|
||||
def reset_uids():
|
||||
global _UID_PREFIXES
|
||||
_UID_PREFIXES = defaultdict(int)
|
||||
|
||||
|
||||
def is_keras_tensor(x):
|
||||
if hasattr(x, '_keras_shape'):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def set_legacy_weight_ordering(value):
|
||||
global _LEGACY_WEIGHT_ORDERING
|
||||
assert value in {True, False}
|
||||
_LEGACY_WEIGHT_ORDERING = value
|
||||
|
||||
|
||||
def legacy_weight_ordering():
|
||||
return _LEGACY_WEIGHT_ORDERING
|
||||
|
||||
Diferenças do arquivo suprimidas por serem muito extensas
Carregar Diff
@@ -3,6 +3,11 @@ 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
|
||||
from theano.printing import Print
|
||||
try:
|
||||
import theano.sparse as th_sparse_module
|
||||
except ImportError:
|
||||
th_sparse_module = None
|
||||
try:
|
||||
from theano.tensor.nnet.nnet import softsign as T_softsign
|
||||
except ImportError:
|
||||
@@ -10,6 +15,7 @@ except ImportError:
|
||||
import inspect
|
||||
import numpy as np
|
||||
from .common import _FLOATX, _EPSILON, _IMAGE_DIM_ORDERING
|
||||
py_all = all
|
||||
|
||||
|
||||
# INTERNAL UTILS
|
||||
@@ -22,16 +28,45 @@ def learning_phase():
|
||||
return _LEARNING_PHASE
|
||||
|
||||
|
||||
def set_learning_phase(value):
|
||||
global _LEARNING_PHASE
|
||||
if value not in {0, 1}:
|
||||
raise ValueError('Expected learning phase to be '
|
||||
'0 or 1.')
|
||||
_LEARNING_PHASE = value
|
||||
|
||||
# VARIABLE MANIPULATION
|
||||
|
||||
|
||||
def _assert_sparse_module():
|
||||
if not th_sparse_module:
|
||||
raise ImportError("Failed to import theano.sparse\n"
|
||||
"You probably need to pip install nose-parameterized")
|
||||
|
||||
|
||||
def is_sparse(tensor):
|
||||
return th_sparse_module and isinstance(tensor.type, th_sparse_module.SparseType)
|
||||
|
||||
|
||||
def to_dense(tensor):
|
||||
if is_sparse(tensor):
|
||||
return th_sparse_module.dense_from_sparse(tensor)
|
||||
else:
|
||||
return tensor
|
||||
|
||||
|
||||
def variable(value, dtype=_FLOATX, name=None):
|
||||
'''Instantiate a tensor variable.
|
||||
'''
|
||||
value = np.asarray(value, dtype=dtype)
|
||||
return theano.shared(value=value, name=name, strict=False)
|
||||
if hasattr(value, 'tocoo'):
|
||||
_assert_sparse_module()
|
||||
return th_sparse_module.as_sparse_variable(value)
|
||||
else:
|
||||
value = np.asarray(value, dtype=dtype)
|
||||
return theano.shared(value=value, name=name, strict=False)
|
||||
|
||||
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
def placeholder(shape=None, ndim=None, dtype=_FLOATX, sparse=False, name=None):
|
||||
'''Instantiate an input data placeholder variable.
|
||||
'''
|
||||
if shape is None and ndim is None:
|
||||
@@ -42,7 +77,11 @@ def placeholder(shape=None, ndim=None, dtype=_FLOATX, name=None):
|
||||
shape = tuple([None for _ in range(ndim)])
|
||||
|
||||
broadcast = (False,) * ndim
|
||||
x = T.TensorType(dtype, broadcast)(name)
|
||||
if sparse:
|
||||
_assert_sparse_module()
|
||||
x = th_sparse_module.csr_matrix(name=name, dtype=dtype)
|
||||
else:
|
||||
x = T.TensorType(dtype, broadcast)(name)
|
||||
x._keras_shape = shape
|
||||
x._uses_learning_phase = False
|
||||
return x
|
||||
@@ -68,7 +107,7 @@ def dtype(x):
|
||||
def eval(x):
|
||||
'''Run a graph.
|
||||
'''
|
||||
return x.eval()
|
||||
return to_dense(x).eval()
|
||||
|
||||
|
||||
def zeros(shape, dtype=_FLOATX, name=None):
|
||||
@@ -97,6 +136,16 @@ def zeros_like(x):
|
||||
return T.zeros_like(x)
|
||||
|
||||
|
||||
def random_uniform_variable(shape, low, high, dtype=_FLOATX, name=None):
|
||||
return variable(np.random.uniform(low=low, high=high, size=shape),
|
||||
dtype=dtype, name=name)
|
||||
|
||||
|
||||
def random_normal_variable(shape, mean, scale, dtype=_FLOATX, name=None):
|
||||
return variable(np.random.normal(loc=0.0, scale=scale, size=shape),
|
||||
dtype=dtype, name=name)
|
||||
|
||||
|
||||
def count_params(x):
|
||||
'''Return number of scalars in a tensor.
|
||||
|
||||
@@ -109,6 +158,25 @@ def cast(x, dtype):
|
||||
return T.cast(x, dtype)
|
||||
|
||||
|
||||
# UPDATES OPS
|
||||
|
||||
|
||||
def update(x, new_x):
|
||||
return (x, new_x)
|
||||
|
||||
|
||||
def update_add(x, increment):
|
||||
return (x, x + increment)
|
||||
|
||||
|
||||
def update_sub(x, decrement):
|
||||
return (x, x - decrement)
|
||||
|
||||
|
||||
def moving_average_update(variable, value, momentum):
|
||||
return (variable, variable * momentum + value * (1. - momentum))
|
||||
|
||||
|
||||
# LINEAR ALGEBRA
|
||||
|
||||
'''
|
||||
@@ -118,28 +186,49 @@ Assumed overridden:
|
||||
|
||||
|
||||
def dot(x, y):
|
||||
return T.dot(x, y)
|
||||
if is_sparse(x):
|
||||
return th_sparse_module.basic.structured_dot(x, y)
|
||||
else:
|
||||
return T.dot(x, y)
|
||||
|
||||
|
||||
def batch_dot(x, y, axes=None):
|
||||
'''batchwise dot product
|
||||
'''Batchwise dot product.
|
||||
|
||||
batch_dot results in a tensor with less dimensions than the input.
|
||||
If the number of dimensions is reduced to 1, we use `expand_dims` to
|
||||
make sure that ndim is at least 2.
|
||||
|
||||
# Example
|
||||
Assume x = [[1, 2], [3, 4]] and y = [[5, 6], [7, 8]]
|
||||
batch_dot(x, y, axes=1) = [[17, 53]] which is the main diagonal
|
||||
of x.dot(y.T), although we never have to calculate the off-diagonal
|
||||
elements.
|
||||
|
||||
|
||||
# Arguments
|
||||
x, y: tensors with ndim >= 2
|
||||
axes: list (or single) int with target dimensions
|
||||
|
||||
# Returns
|
||||
Tensor with ndim >= 2
|
||||
A tensor with shape equal to the concatenation of x's shape
|
||||
(less the dimension that was summed over) and y's shape
|
||||
(less the batch dimension and the dimension that was summed over).
|
||||
If the final rank is 1, we reshape it to (batch_size, 1).
|
||||
|
||||
# Examples
|
||||
Assume x = [[1, 2], [3, 4]] and y = [[5, 6], [7, 8]]
|
||||
batch_dot(x, y, axes=1) = [[17, 53]] which is the main diagonal
|
||||
of x.dot(y.T), although we never have to calculate the off-diagonal
|
||||
elements.
|
||||
|
||||
Shape inference:
|
||||
Let x's shape be (100, 20) and y's shape be (100, 30, 20).
|
||||
If dot_axes is (1, 2), to find the output shape of resultant tensor,
|
||||
loop through each dimension in x's shape and y's shape:
|
||||
x.shape[0] : 100 : append to output shape
|
||||
x.shape[1] : 20 : do not append to output shape,
|
||||
dimension 1 of x has been summed over. (dot_axes[0] = 1)
|
||||
y.shape[0] : 100 : do not append to output shape,
|
||||
always ignore first dimension of y
|
||||
y.shape[1] : 30 : append to output shape
|
||||
y.shape[2] : 20 : do not append to output shape,
|
||||
dimension 2 of y has been summed over. (dot_axes[1] = 2)
|
||||
|
||||
output_shape = (100, 30)
|
||||
'''
|
||||
if type(axes) == int:
|
||||
axes = (axes, axes)
|
||||
@@ -270,6 +359,22 @@ def not_equal(x, y):
|
||||
return T.neq(x, y)
|
||||
|
||||
|
||||
def greater(x, y):
|
||||
return T.gt(x, y)
|
||||
|
||||
|
||||
def greater_equal(x, y):
|
||||
return T.ge(x, y)
|
||||
|
||||
|
||||
def lesser(x, y):
|
||||
return T.lt(x, y)
|
||||
|
||||
|
||||
def lesser_equal(x, y):
|
||||
return T.le(x, y)
|
||||
|
||||
|
||||
def maximum(x, y):
|
||||
return T.maximum(x, y)
|
||||
|
||||
@@ -290,7 +395,7 @@ def normalize_batch_in_training(x, gamma, beta,
|
||||
reduction_axes, epsilon=0.0001):
|
||||
'''Compute mean and std for batch then apply batch_normalization on batch.
|
||||
'''
|
||||
std = T.sqrt(x.var(reduction_axes) + epsilon)
|
||||
var = x.var(reduction_axes)
|
||||
mean = x.mean(reduction_axes)
|
||||
|
||||
target_shape = []
|
||||
@@ -302,26 +407,44 @@ def normalize_batch_in_training(x, gamma, beta,
|
||||
target_shape = T.stack(*target_shape)
|
||||
|
||||
broadcast_mean = T.reshape(mean, target_shape)
|
||||
broadcast_std = T.reshape(std, target_shape)
|
||||
broadcast_var = T.reshape(var, target_shape)
|
||||
broadcast_beta = T.reshape(beta, target_shape)
|
||||
broadcast_gamma = T.reshape(gamma, target_shape)
|
||||
normed = batch_normalization(x, broadcast_mean, broadcast_std,
|
||||
normed = batch_normalization(x, broadcast_mean, broadcast_var,
|
||||
broadcast_beta, broadcast_gamma,
|
||||
epsilon)
|
||||
return normed, mean, std
|
||||
return normed, mean, var
|
||||
|
||||
|
||||
def batch_normalization(x, mean, std, beta, gamma, epsilon=0.0001):
|
||||
'''Apply batch normalization on x given mean, std, beta and gamma.
|
||||
def batch_normalization(x, mean, var, beta, gamma, epsilon=0.0001):
|
||||
'''Apply batch normalization on x given mean, var, beta and gamma.
|
||||
'''
|
||||
normed = (x - mean) * (gamma * T.inv(std + epsilon)) + beta
|
||||
return normed
|
||||
ndim = x.ndim
|
||||
dev = theano.config.device
|
||||
use_cudnn = ndim < 5 and (dev.startswith('cuda') or dev.startswith('gpu'))
|
||||
if use_cudnn:
|
||||
try:
|
||||
return theano.sandbox.cuda.dnn.dnn_batch_normalization_test(x, gamma, beta, mean, var,
|
||||
'spatial', epsilon)
|
||||
except AttributeError:
|
||||
pass
|
||||
return T.nnet.bn.batch_normalization(x, gamma, beta, mean, sqrt(var + epsilon),
|
||||
mode='high_mem')
|
||||
|
||||
|
||||
# SHAPE OPERATIONS
|
||||
|
||||
def concatenate(tensors, axis=-1):
|
||||
return T.concatenate(tensors, axis=axis)
|
||||
if py_all([is_sparse(x) for x in tensors]):
|
||||
axis = axis % ndim(tensors[0])
|
||||
if axis == 0:
|
||||
return th_sparse_module.basic.vstack(tensors, format='csr')
|
||||
elif axis == 1:
|
||||
return th_sparse_module.basic.hstack(tensors, format='csr')
|
||||
else:
|
||||
raise Exception('Invalid concat axis for sparse matrix: ' + axis)
|
||||
else:
|
||||
return T.concatenate([to_dense(x) for x in tensors], axis=axis)
|
||||
|
||||
|
||||
def reshape(x, shape):
|
||||
@@ -430,11 +553,9 @@ def expand_dims(x, dim=-1):
|
||||
def squeeze(x, axis):
|
||||
'''Remove a 1-dimension from the tensor at index "axis".
|
||||
'''
|
||||
broadcastable = x.broadcastable[:axis] + x.broadcastable[axis+1:]
|
||||
x = T.patternbroadcast(x, [i == axis for i in range(x.type.ndim)])
|
||||
x = T.squeeze(x)
|
||||
x = T.patternbroadcast(x, broadcastable)
|
||||
return x
|
||||
shape = list(x.shape)
|
||||
shape.pop(axis)
|
||||
return T.reshape(x, tuple(shape))
|
||||
|
||||
|
||||
def temporal_padding(x, padding=1):
|
||||
@@ -452,7 +573,7 @@ def temporal_padding(x, padding=1):
|
||||
return T.set_subtensor(output[:, padding:x.shape[1] + padding, :], x)
|
||||
|
||||
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
def spatial_2d_padding(x, padding=(1, 1), dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
'''Pad the 2nd and 3rd dimensions of a 4D tensor
|
||||
with "padding[0]" and "padding[1]" (resp.) zeros left and right.
|
||||
'''
|
||||
@@ -483,7 +604,7 @@ def spatial_2d_padding(x, padding=(1, 1), dim_ordering='th'):
|
||||
return T.set_subtensor(output[indices], x)
|
||||
|
||||
|
||||
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering='th'):
|
||||
def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering=_IMAGE_DIM_ORDERING):
|
||||
'''Pad the 2nd, 3rd and 4th dimensions of a 5D tensor
|
||||
with "padding[0]", "padding[1]" and "padding[2]" (resp.) zeros left and right.
|
||||
'''
|
||||
@@ -521,6 +642,28 @@ def spatial_3d_padding(x, padding=(1, 1, 1), dim_ordering='th'):
|
||||
def pack(x):
|
||||
return T.stack(*x)
|
||||
|
||||
|
||||
def one_hot(indices, nb_classes):
|
||||
'''Input: nD integer tensor of shape (batch_size, dim1, dim2, ... dim(n-1))
|
||||
Output: (n + 1)D one hot representation of the input
|
||||
with shape (batch_size, dim1, dim2, ... dim(n-1), nb_classes)
|
||||
'''
|
||||
input_shape = tuple((indices.shape[i] for i in range(indices.ndim)))
|
||||
indices = T.flatten(indices)
|
||||
oh = T.extra_ops.to_one_hot(indices, nb_classes)
|
||||
oh = T.reshape(oh, input_shape + (nb_classes,))
|
||||
return oh
|
||||
|
||||
|
||||
def reverse(x, axes):
|
||||
'''Reverse a tensor along the the specified axes
|
||||
'''
|
||||
if type(axes) == int:
|
||||
axes = [axes]
|
||||
slices = [slice(None, None, -1) if i in axes else slice(None, None, None) for i in range(x.ndim)]
|
||||
return x[slices]
|
||||
|
||||
|
||||
# VALUE MANIPULATION
|
||||
|
||||
|
||||
@@ -547,6 +690,18 @@ def batch_set_value(tuples):
|
||||
x.set_value(np.asarray(value, dtype=x.dtype))
|
||||
|
||||
|
||||
def get_variable_shape(x):
|
||||
return x.get_value(borrow=True, return_internal_type=True).shape
|
||||
|
||||
|
||||
def print_tensor(x, message=''):
|
||||
'''Print the message and the tensor when evaluated and return the same
|
||||
tensor.
|
||||
'''
|
||||
p_op = Print(message)
|
||||
return p_op(x)
|
||||
|
||||
|
||||
# GRAPH MANIPULATION
|
||||
|
||||
class Function(object):
|
||||
@@ -554,7 +709,7 @@ class Function(object):
|
||||
def __init__(self, inputs, outputs, updates=[], **kwargs):
|
||||
self.function = theano.function(inputs, outputs, updates=updates,
|
||||
allow_input_downcast=True,
|
||||
on_unused_input='warn',
|
||||
on_unused_input='ignore',
|
||||
**kwargs)
|
||||
|
||||
def __call__(self, inputs):
|
||||
@@ -755,12 +910,20 @@ def switch(condition, then_expression, else_expression):
|
||||
|
||||
|
||||
def in_train_phase(x, alt):
|
||||
if _LEARNING_PHASE is 1:
|
||||
return x
|
||||
elif _LEARNING_PHASE is 0:
|
||||
return alt
|
||||
x = T.switch(_LEARNING_PHASE, x, alt)
|
||||
x._uses_learning_phase = True
|
||||
return x
|
||||
|
||||
|
||||
def in_test_phase(x, alt):
|
||||
if _LEARNING_PHASE is 1:
|
||||
return alt
|
||||
elif _LEARNING_PHASE is 0:
|
||||
return x
|
||||
x = T.switch(_LEARNING_PHASE, alt, x)
|
||||
x._uses_learning_phase = True
|
||||
return x
|
||||
@@ -829,14 +992,33 @@ def tanh(x):
|
||||
return T.tanh(x)
|
||||
|
||||
|
||||
def dropout(x, level, seed=None):
|
||||
def dropout(x, level, noise_shape=None, seed=None):
|
||||
'''Sets entries in `x` to zero at random,
|
||||
while scaling the entire tensor.
|
||||
|
||||
# Arguments
|
||||
x: tensor
|
||||
level: fraction of the entries in the tensor
|
||||
that will be set to 0.
|
||||
noise_shape: shape for randomly generated keep/drop flags,
|
||||
must be broadcastable to the shape of `x`
|
||||
seed: random seed to ensure determinism.
|
||||
'''
|
||||
if level < 0. or level >= 1:
|
||||
raise Exception('Dropout level must be in interval [0, 1[.')
|
||||
if seed is None:
|
||||
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)
|
||||
|
||||
if noise_shape is None:
|
||||
random_tensor = rng.binomial(x.shape, p=retain_prob, dtype=x.dtype)
|
||||
else:
|
||||
random_tensor = rng.binomial(noise_shape, p=retain_prob, dtype=x.dtype)
|
||||
random_tensor = T.patternbroadcast(random_tensor, [dim == 1 for dim in noise_shape])
|
||||
|
||||
x *= random_tensor
|
||||
x /= retain_prob
|
||||
return x
|
||||
|
||||
@@ -848,6 +1030,79 @@ def l2_normalize(x, axis):
|
||||
|
||||
# CONVOLUTIONS
|
||||
|
||||
def _preprocess_conv2d_input(x, dim_ordering):
|
||||
if dim_ordering == 'tf':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
x = x.dimshuffle((0, 3, 1, 2))
|
||||
return x
|
||||
|
||||
|
||||
def _preprocess_conv2d_kernel(kernel, dim_ordering):
|
||||
if dim_ordering == 'tf':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
kernel = kernel.dimshuffle((3, 2, 0, 1))
|
||||
return kernel
|
||||
|
||||
|
||||
def _preprocess_border_mode(border_mode):
|
||||
if border_mode == 'same':
|
||||
th_border_mode = 'half'
|
||||
elif border_mode == 'valid':
|
||||
th_border_mode = 'valid'
|
||||
else:
|
||||
raise Exception('Border mode not supported: ' + str(border_mode))
|
||||
return th_border_mode
|
||||
|
||||
|
||||
def _preprocess_image_shape(dim_ordering, image_shape):
|
||||
# Theano might not accept long type
|
||||
def int_or_none(value):
|
||||
try:
|
||||
return int(value)
|
||||
except TypeError:
|
||||
return None
|
||||
if dim_ordering == 'tf':
|
||||
if image_shape:
|
||||
image_shape = (image_shape[0], image_shape[3],
|
||||
image_shape[1], image_shape[2])
|
||||
if image_shape is not None:
|
||||
image_shape = tuple(int_or_none(v) for v in image_shape)
|
||||
return image_shape
|
||||
|
||||
|
||||
def _preprocess_filter_shape(dim_ordering, filter_shape):
|
||||
# Theano might not accept long type
|
||||
def int_or_none(value):
|
||||
try:
|
||||
return int(value)
|
||||
except TypeError:
|
||||
return None
|
||||
if dim_ordering == 'tf':
|
||||
if filter_shape:
|
||||
filter_shape = (filter_shape[3], filter_shape[2],
|
||||
filter_shape[0], filter_shape[1])
|
||||
if filter_shape is not None:
|
||||
filter_shape = tuple(int_or_none(v) for v in filter_shape)
|
||||
return filter_shape
|
||||
|
||||
|
||||
def _postprocess_conv2d_output(conv_out, x, border_mode, np_kernel, strides, dim_ordering):
|
||||
if border_mode == 'same':
|
||||
if np_kernel.shape[2] % 2 == 0:
|
||||
conv_out = conv_out[:, :, :(x.shape[2] + strides[0] - 1) // strides[0], :]
|
||||
if np_kernel.shape[3] % 2 == 0:
|
||||
conv_out = conv_out[:, :, :, :(x.shape[3] + strides[1] - 1) // strides[1]]
|
||||
if dim_ordering == 'tf':
|
||||
conv_out = conv_out.dimshuffle((0, 2, 3, 1))
|
||||
return conv_out
|
||||
|
||||
|
||||
def conv2d(x, kernel, strides=(1, 1), border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, image_shape=None,
|
||||
filter_shape=None, filter_dilation=(1, 1)):
|
||||
@@ -864,42 +1119,12 @@ def conv2d(x, kernel, strides=(1, 1), border_mode='valid',
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
if dim_ordering == 'tf':
|
||||
# TF uses the last dimension as channel dimension,
|
||||
# instead of the 2nd one.
|
||||
# TH input shape: (samples, input_depth, rows, cols)
|
||||
# TF input shape: (samples, rows, cols, input_depth)
|
||||
# TH kernel shape: (depth, input_depth, rows, cols)
|
||||
# TF kernel shape: (rows, cols, input_depth, depth)
|
||||
x = x.dimshuffle((0, 3, 1, 2))
|
||||
kernel = kernel.dimshuffle((3, 2, 0, 1))
|
||||
if image_shape:
|
||||
image_shape = (image_shape[0], image_shape[3],
|
||||
image_shape[1], image_shape[2])
|
||||
if filter_shape:
|
||||
filter_shape = (filter_shape[3], filter_shape[2],
|
||||
filter_shape[0], filter_shape[1])
|
||||
|
||||
if border_mode == 'same':
|
||||
th_border_mode = 'half'
|
||||
np_kernel = kernel.eval()
|
||||
elif border_mode == 'valid':
|
||||
th_border_mode = 'valid'
|
||||
else:
|
||||
raise Exception('Border mode not supported: ' + str(border_mode))
|
||||
|
||||
# Theano might not accept long type
|
||||
def int_or_none(value):
|
||||
try:
|
||||
return int(value)
|
||||
except TypeError:
|
||||
return None
|
||||
|
||||
if image_shape is not None:
|
||||
image_shape = tuple(int_or_none(v) for v in image_shape)
|
||||
|
||||
if filter_shape is not None:
|
||||
filter_shape = tuple(int_or_none(v) for v in filter_shape)
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
kernel = _preprocess_conv2d_kernel(kernel, dim_ordering)
|
||||
th_border_mode = _preprocess_border_mode(border_mode)
|
||||
np_kernel = kernel.eval()
|
||||
image_shape = _preprocess_image_shape(dim_ordering, image_shape)
|
||||
filter_shape = _preprocess_filter_shape(dim_ordering, filter_shape)
|
||||
|
||||
# TODO: remove the if statement when theano with no filter dilation is deprecated.
|
||||
if filter_dilation == (1, 1):
|
||||
@@ -916,14 +1141,8 @@ def conv2d(x, kernel, strides=(1, 1), border_mode='valid',
|
||||
filter_shape=filter_shape,
|
||||
filter_dilation=filter_dilation)
|
||||
|
||||
if border_mode == 'same':
|
||||
if np_kernel.shape[2] % 2 == 0:
|
||||
conv_out = conv_out[:, :, :(x.shape[2] + strides[0] - 1) // strides[0], :]
|
||||
if np_kernel.shape[3] % 2 == 0:
|
||||
conv_out = conv_out[:, :, :, :(x.shape[3] + strides[1] - 1) // strides[1]]
|
||||
|
||||
if dim_ordering == 'tf':
|
||||
conv_out = conv_out.dimshuffle((0, 2, 3, 1))
|
||||
conv_out = _postprocess_conv2d_output(conv_out, x, border_mode, np_kernel,
|
||||
strides, dim_ordering)
|
||||
return conv_out
|
||||
|
||||
|
||||
@@ -931,7 +1150,38 @@ def deconv2d(x, kernel, output_shape, strides=(1, 1),
|
||||
border_mode='valid',
|
||||
dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
image_shape=None, filter_shape=None):
|
||||
raise NotImplementedError
|
||||
'''2D deconvolution (transposed convolution).
|
||||
|
||||
# Arguments
|
||||
kernel: kernel tensor.
|
||||
output_shape: desired dimensions of output.
|
||||
strides: strides tuple.
|
||||
border_mode: string, "same" or "valid".
|
||||
dim_ordering: "tf" or "th".
|
||||
Whether to use Theano or TensorFlow dimension ordering
|
||||
in inputs/kernels/ouputs.
|
||||
'''
|
||||
flip_filters = False
|
||||
if dim_ordering not in {'th', 'tf'}:
|
||||
raise Exception('Unknown dim_ordering ' + str(dim_ordering))
|
||||
|
||||
x = _preprocess_conv2d_input(x, dim_ordering)
|
||||
kernel = _preprocess_conv2d_kernel(kernel, dim_ordering)
|
||||
kernel = kernel.dimshuffle((1, 0, 2, 3))
|
||||
th_border_mode = _preprocess_border_mode(border_mode)
|
||||
np_kernel = kernel.eval()
|
||||
filter_shape = _preprocess_filter_shape(dim_ordering, filter_shape)
|
||||
|
||||
op = T.nnet.abstract_conv.AbstractConv2d_gradInputs(imshp=output_shape,
|
||||
kshp=filter_shape,
|
||||
subsample=strides,
|
||||
border_mode=th_border_mode,
|
||||
filter_flip=not flip_filters)
|
||||
conv_out = op(kernel, x, output_shape[2:])
|
||||
|
||||
conv_out = _postprocess_conv2d_output(conv_out, x, border_mode, np_kernel,
|
||||
strides, dim_ordering)
|
||||
return conv_out
|
||||
|
||||
|
||||
def atrous_conv2d(x, kernel, rate=1,
|
||||
@@ -947,7 +1197,7 @@ def separable_conv2d(x, depthwise_kernel, pointwise_kernel, strides=(1, 1),
|
||||
|
||||
|
||||
def conv3d(x, kernel, strides=(1, 1, 1),
|
||||
border_mode='valid', dim_ordering='th',
|
||||
border_mode='valid', dim_ordering=_IMAGE_DIM_ORDERING,
|
||||
volume_shape=None, filter_shape=None):
|
||||
'''
|
||||
Run on cuDNN if available.
|
||||
@@ -1009,7 +1259,7 @@ def conv3d(x, kernel, strides=(1, 1, 1),
|
||||
|
||||
|
||||
def pool2d(x, pool_size, strides=(1, 1), border_mode='valid',
|
||||
dim_ordering='th', pool_mode='max'):
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, pool_mode='max'):
|
||||
if border_mode == 'same':
|
||||
w_pad = pool_size[0] - 2 if pool_size[0] % 2 == 1 else pool_size[0] - 1
|
||||
h_pad = pool_size[1] - 2 if pool_size[1] % 2 == 1 else pool_size[1] - 1
|
||||
@@ -1052,7 +1302,7 @@ def pool2d(x, pool_size, strides=(1, 1), border_mode='valid',
|
||||
|
||||
|
||||
def pool3d(x, pool_size, strides=(1, 1, 1), border_mode='valid',
|
||||
dim_ordering='th', pool_mode='max'):
|
||||
dim_ordering=_IMAGE_DIM_ORDERING, pool_mode='max'):
|
||||
if border_mode == 'same':
|
||||
# TODO: add implementation for border_mode="same"
|
||||
raise Exception('border_mode="same" not supported with Theano.')
|
||||
@@ -1131,3 +1381,105 @@ def random_binomial(shape, p=0.0, dtype=_FLOATX, seed=None):
|
||||
seed = np.random.randint(1, 10e6)
|
||||
rng = RandomStreams(seed=seed)
|
||||
return rng.binomial(shape, p=p, dtype=dtype)
|
||||
|
||||
# Theano implementation of CTC
|
||||
# Used with permission from Shawn Tan
|
||||
# https://github.com/shawntan/
|
||||
# Note that tensorflow's native CTC code is significantly
|
||||
# faster than this
|
||||
|
||||
def ctc_interleave_blanks(Y):
|
||||
Y_ = T.alloc(-1, Y.shape[0] * 2 + 1)
|
||||
Y_ = T.set_subtensor(Y_[T.arange(Y.shape[0]) * 2 + 1], Y)
|
||||
return Y_
|
||||
|
||||
def ctc_create_skip_idxs(Y):
|
||||
skip_idxs = T.arange((Y.shape[0] - 3) // 2) * 2 + 1
|
||||
non_repeats = T.neq(Y[skip_idxs], Y[skip_idxs + 2])
|
||||
return skip_idxs[non_repeats.nonzero()]
|
||||
|
||||
def ctc_update_log_p(skip_idxs, zeros, active, log_p_curr, log_p_prev):
|
||||
active_skip_idxs = skip_idxs[(skip_idxs < active).nonzero()]
|
||||
active_next = T.cast(T.minimum(
|
||||
T.maximum(
|
||||
active + 1,
|
||||
T.max(T.concatenate([active_skip_idxs, [-1]])) + 2 + 1
|
||||
), log_p_curr.shape[0]), 'int32')
|
||||
|
||||
common_factor = T.max(log_p_prev[:active])
|
||||
p_prev = T.exp(log_p_prev[:active] - common_factor)
|
||||
_p_prev = zeros[:active_next]
|
||||
# copy over
|
||||
_p_prev = T.set_subtensor(_p_prev[:active], p_prev)
|
||||
# previous transitions
|
||||
_p_prev = T.inc_subtensor(_p_prev[1:], _p_prev[:-1])
|
||||
# skip transitions
|
||||
_p_prev = T.inc_subtensor(_p_prev[active_skip_idxs + 2], p_prev[active_skip_idxs])
|
||||
updated_log_p_prev = T.log(_p_prev) + common_factor
|
||||
|
||||
log_p_next = T.set_subtensor(
|
||||
zeros[:active_next],
|
||||
log_p_curr[:active_next] + updated_log_p_prev
|
||||
)
|
||||
return active_next, log_p_next
|
||||
|
||||
def ctc_path_probs(predict, Y, alpha=1e-4):
|
||||
smoothed_predict = (1 - alpha) * predict[:, Y] + alpha * np.float32(1.) / Y.shape[0]
|
||||
L = T.log(smoothed_predict)
|
||||
zeros = T.zeros_like(L[0])
|
||||
base = T.set_subtensor(zeros[:1], np.float32(1))
|
||||
log_first = zeros
|
||||
|
||||
f_skip_idxs = ctc_create_skip_idxs(Y)
|
||||
b_skip_idxs = ctc_create_skip_idxs(Y[::-1]) # there should be a shortcut to calculating this
|
||||
|
||||
def step(log_f_curr, log_b_curr, f_active, log_f_prev, b_active, log_b_prev):
|
||||
f_active_next, log_f_next = ctc_update_log_p(f_skip_idxs, zeros, f_active, log_f_curr, log_f_prev)
|
||||
b_active_next, log_b_next = ctc_update_log_p(b_skip_idxs, zeros, b_active, log_b_curr, log_b_prev)
|
||||
return f_active_next, log_f_next, b_active_next, log_b_next
|
||||
|
||||
[f_active, log_f_probs, b_active, log_b_probs], _ = theano.scan(
|
||||
step, sequences=[L, L[::-1, ::-1]], outputs_info=[np.int32(1), log_first, np.int32(1), log_first])
|
||||
|
||||
idxs = T.arange(L.shape[1]).dimshuffle('x', 0)
|
||||
mask = (idxs < f_active.dimshuffle(0, 'x')) & (idxs < b_active.dimshuffle(0, 'x'))[::-1, ::-1]
|
||||
log_probs = log_f_probs + log_b_probs[::-1, ::-1] - L
|
||||
return log_probs, mask
|
||||
|
||||
def ctc_cost(predict, Y):
|
||||
log_probs, mask = ctc_path_probs(predict, ctc_interleave_blanks(Y))
|
||||
common_factor = T.max(log_probs)
|
||||
total_log_prob = T.log(T.sum(T.exp(log_probs - common_factor)[mask.nonzero()])) + common_factor
|
||||
return -total_log_prob
|
||||
|
||||
# batchifies original CTC code
|
||||
def ctc_batch_cost(y_true, y_pred, input_length, label_length):
|
||||
'''Runs CTC loss algorithm on each batch element.
|
||||
|
||||
# Arguments
|
||||
y_true: tensor (samples, max_string_length) containing the truth labels
|
||||
y_pred: tensor (samples, time_steps, num_categories) containing the prediction,
|
||||
or output of the softmax
|
||||
input_length: tensor (samples,1) containing the sequence length for
|
||||
each batch item in y_pred
|
||||
label_length: tensor (samples,1) containing the sequence length for
|
||||
each batch item in y_true
|
||||
|
||||
# Returns
|
||||
Tensor with shape (samples,1) containing the
|
||||
CTC loss of each element
|
||||
'''
|
||||
|
||||
def ctc_step(y_true_step, y_pred_step, input_length_step, label_length_step):
|
||||
y_pred_step = y_pred_step[0: input_length_step[0]]
|
||||
y_true_step = y_true_step[0:label_length_step[0]]
|
||||
return ctc_cost(y_pred_step, y_true_step)
|
||||
|
||||
ret, _ = theano.scan(
|
||||
fn = ctc_step,
|
||||
outputs_info=None,
|
||||
sequences=[y_true, y_pred, input_length, label_length]
|
||||
)
|
||||
|
||||
ret = ret.dimshuffle('x', 0)
|
||||
return ret
|
||||
|
||||
+53
-23
@@ -9,6 +9,7 @@ import warnings
|
||||
from collections import deque
|
||||
from .utils.generic_utils import Progbar
|
||||
from keras import backend as K
|
||||
from pkg_resources import parse_version
|
||||
|
||||
|
||||
class CallbackList(object):
|
||||
@@ -212,6 +213,7 @@ class History(Callback):
|
||||
for k, v in logs.items():
|
||||
self.history.setdefault(k, []).append(v)
|
||||
|
||||
|
||||
class ModelCheckpoint(Callback):
|
||||
'''Save the model after every epoch.
|
||||
|
||||
@@ -229,25 +231,29 @@ class ModelCheckpoint(Callback):
|
||||
verbose: verbosity mode, 0 or 1.
|
||||
save_best_only: if `save_best_only=True`,
|
||||
the latest best model according to
|
||||
the validation loss will not be overwritten.
|
||||
the quantity monitored will not be overwritten.
|
||||
mode: one of {auto, min, max}.
|
||||
If `save_best_only=True`, the decision
|
||||
to overwrite the current save file is made
|
||||
based on either the maximization or the
|
||||
minization of the monitored. For `val_acc`,
|
||||
minimization of the monitored quantity. For `val_acc`,
|
||||
this should be `max`, for `val_loss` this should
|
||||
be `min`, etc. In `auto` mode, the direction is
|
||||
automatically inferred from the name of the monitored quantity.
|
||||
save_weights_only: if True, then only the model's weights will be
|
||||
saved (`model.save_weights(filepath)`), else the full model
|
||||
is saved (`model.save(filepath)`).
|
||||
|
||||
'''
|
||||
def __init__(self, filepath, monitor='val_loss', verbose=0,
|
||||
save_best_only=False, mode='auto'):
|
||||
|
||||
save_best_only=False, save_weights_only=False,
|
||||
mode='auto'):
|
||||
super(ModelCheckpoint, self).__init__()
|
||||
self.monitor = monitor
|
||||
self.verbose = verbose
|
||||
self.filepath = filepath
|
||||
self.save_best_only = save_best_only
|
||||
self.save_weights_only = save_weights_only
|
||||
|
||||
if mode not in ['auto', 'min', 'max']:
|
||||
warnings.warn('ModelCheckpoint mode %s is unknown, '
|
||||
@@ -284,7 +290,10 @@ class ModelCheckpoint(Callback):
|
||||
% (epoch, self.monitor, self.best,
|
||||
current, filepath))
|
||||
self.best = current
|
||||
self.model.save_weights(filepath, overwrite=True)
|
||||
if self.save_weights_only:
|
||||
self.model.save_weights(filepath, overwrite=True)
|
||||
else:
|
||||
self.model.save(filepath, overwrite=True)
|
||||
else:
|
||||
if self.verbose > 0:
|
||||
print('Epoch %05d: %s did not improve' %
|
||||
@@ -292,7 +301,10 @@ class ModelCheckpoint(Callback):
|
||||
else:
|
||||
if self.verbose > 0:
|
||||
print('Epoch %05d: saving model to %s' % (epoch, filepath))
|
||||
self.model.save_weights(filepath, overwrite=True)
|
||||
if self.save_weights_only:
|
||||
self.model.save_weights(filepath, overwrite=True)
|
||||
else:
|
||||
self.model.save(filepath, overwrite=True)
|
||||
|
||||
|
||||
class EarlyStopping(Callback):
|
||||
@@ -303,11 +315,13 @@ class EarlyStopping(Callback):
|
||||
patience: number of epochs with no improvement
|
||||
after which training will be stopped.
|
||||
verbose: verbosity mode.
|
||||
mode: one of {auto, min, max}. In 'min' mode,
|
||||
mode: one of {auto, min, max}. In `min` mode,
|
||||
training will stop when the quantity
|
||||
monitored has stopped decreasing; in 'max'
|
||||
monitored has stopped decreasing; in `max`
|
||||
mode it will stop when the quantity
|
||||
monitored has stopped increasing.
|
||||
monitored has stopped increasing; in `auto`
|
||||
mode, the direction is automatically inferred
|
||||
from the name of the monitored quantity.
|
||||
'''
|
||||
def __init__(self, monitor='val_loss', patience=0, verbose=0, mode='auto'):
|
||||
super(EarlyStopping, self).__init__()
|
||||
@@ -319,7 +333,8 @@ class EarlyStopping(Callback):
|
||||
|
||||
if mode not in ['auto', 'min', 'max']:
|
||||
warnings.warn('EarlyStopping mode %s is unknown, '
|
||||
'fallback to auto mode.' % (self.mode), RuntimeWarning)
|
||||
'fallback to auto mode.' % (self.mode),
|
||||
RuntimeWarning)
|
||||
mode = 'auto'
|
||||
|
||||
if mode == 'min':
|
||||
@@ -361,8 +376,8 @@ class RemoteMonitor(Callback):
|
||||
# Arguments
|
||||
root: root url to which the events will be sent (at the end
|
||||
of every epoch). Events are sent to
|
||||
`root + '/publish/epoch/end/'` by default. Calls are
|
||||
HTTP POST, with a `data` argument which is a
|
||||
`root + '/publish/epoch/end/'` by default. Calls are
|
||||
HTTP POST, with a `data` argument which is a
|
||||
JSON-encoded dictionary of event data.
|
||||
'''
|
||||
|
||||
@@ -433,11 +448,12 @@ 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.
|
||||
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, write_graph=True):
|
||||
def __init__(self, log_dir='./logs', histogram_freq=0, write_graph=True, write_images=False):
|
||||
super(TensorBoard, self).__init__()
|
||||
if K._BACKEND != 'tensorflow':
|
||||
raise Exception('TensorBoard callback only works '
|
||||
@@ -446,6 +462,7 @@ class TensorBoard(Callback):
|
||||
self.histogram_freq = histogram_freq
|
||||
self.merged = None
|
||||
self.write_graph = write_graph
|
||||
self.write_images = write_images
|
||||
|
||||
def _set_model(self, model):
|
||||
import tensorflow as tf
|
||||
@@ -454,18 +471,31 @@ class TensorBoard(Callback):
|
||||
self.model = model
|
||||
self.sess = KTF.get_session()
|
||||
if self.histogram_freq and self.merged is None:
|
||||
layers = self.model.layers
|
||||
for layer in layers:
|
||||
if hasattr(layer, 'W'):
|
||||
tf.histogram_summary('{}_W'.format(layer), layer.W)
|
||||
if hasattr(layer, 'b'):
|
||||
tf.histogram_summary('{}_b'.format(layer), layer.b)
|
||||
for layer in self.model.layers:
|
||||
|
||||
for weight in layer.weights:
|
||||
tf.histogram_summary(weight.name, weight)
|
||||
|
||||
if self.write_images:
|
||||
w_img = tf.squeeze(weight)
|
||||
|
||||
shape = w_img.get_shape()
|
||||
if len(shape) > 1 and shape[0] > shape[1]:
|
||||
w_img = tf.transpose(w_img)
|
||||
|
||||
if len(shape) == 1:
|
||||
w_img = tf.expand_dims(w_img, 0)
|
||||
|
||||
w_img = tf.expand_dims(tf.expand_dims(w_img, 0), -1)
|
||||
|
||||
tf.image_summary(weight.name, w_img)
|
||||
|
||||
if hasattr(layer, 'output'):
|
||||
tf.histogram_summary('{}_out'.format(layer),
|
||||
tf.histogram_summary('{}_out'.format(layer.name),
|
||||
layer.output)
|
||||
self.merged = tf.merge_all_summaries()
|
||||
if self.write_graph:
|
||||
if tf.__version__ >= '0.8.0':
|
||||
if parse_version(tf.__version__) >= parse_version('0.8.0'):
|
||||
self.writer = tf.train.SummaryWriter(self.log_dir,
|
||||
self.sess.graph)
|
||||
else:
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from .cifar import load_batch
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
@@ -18,8 +19,8 @@ def load_data():
|
||||
for i in range(1, 6):
|
||||
fpath = os.path.join(path, 'data_batch_' + str(i))
|
||||
data, labels = load_batch(fpath)
|
||||
X_train[(i-1)*10000:i*10000, :, :, :] = data
|
||||
y_train[(i-1)*10000:i*10000] = labels
|
||||
X_train[(i - 1) * 10000: i * 10000, :, :, :] = data
|
||||
y_train[(i - 1) * 10000: i * 10000] = labels
|
||||
|
||||
fpath = os.path.join(path, 'test_batch')
|
||||
X_test, y_test = load_batch(fpath)
|
||||
@@ -27,4 +28,8 @@ def load_data():
|
||||
y_train = np.reshape(y_train, (len(y_train), 1))
|
||||
y_test = np.reshape(y_test, (len(y_test), 1))
|
||||
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
X_train = X_train.transpose(0, 2, 3, 1)
|
||||
X_test = X_test.transpose(0, 2, 3, 1)
|
||||
|
||||
return (X_train, y_train), (X_test, y_test)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from .cifar import load_batch
|
||||
from ..utils.data_utils import get_file
|
||||
from .. import backend as K
|
||||
import numpy as np
|
||||
import os
|
||||
|
||||
@@ -13,9 +14,6 @@ def load_data(label_mode='fine'):
|
||||
origin = "http://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz"
|
||||
path = get_file(dirname, origin=origin, untar=True)
|
||||
|
||||
nb_test_samples = 10000
|
||||
nb_train_samples = 50000
|
||||
|
||||
fpath = os.path.join(path, 'train')
|
||||
X_train, y_train = load_batch(fpath, label_key=label_mode+'_labels')
|
||||
|
||||
@@ -25,4 +23,8 @@ def load_data(label_mode='fine'):
|
||||
y_train = np.reshape(y_train, (len(y_train), 1))
|
||||
y_test = np.reshape(y_test, (len(y_test), 1))
|
||||
|
||||
if K.image_dim_ordering() == 'tf':
|
||||
X_train = X_train.transpose(0, 2, 3, 1)
|
||||
X_test = X_test.transpose(0, 2, 3, 1)
|
||||
|
||||
return (X_train, y_train), (X_test, y_test)
|
||||
|
||||
+58
-11
@@ -4,26 +4,58 @@ import gzip
|
||||
from ..utils.data_utils import get_file
|
||||
from six.moves import zip
|
||||
import numpy as np
|
||||
import sys
|
||||
|
||||
|
||||
def load_data(path="imdb.pkl", nb_words=None, skip_top=0,
|
||||
maxlen=None, test_split=0.2, seed=113,
|
||||
def load_data(path='imdb_full.pkl', nb_words=None, skip_top=0,
|
||||
maxlen=None, seed=113,
|
||||
start_char=1, oov_char=2, index_from=3):
|
||||
'''
|
||||
# Arguments
|
||||
path: where to store the data (in `/.keras/dataset`)
|
||||
nb_words: max number of words to include. Words are ranked
|
||||
by how often they occur (in the training set) and only
|
||||
the most frequent words are kept
|
||||
skip_top: skip the top N most frequently occuring words
|
||||
(which may not be informative).
|
||||
maxlen: truncate sequences after this length.
|
||||
seed: random seed for sample shuffling.
|
||||
start_char: The start of a sequence will be marked with this character.
|
||||
Set to 1 because 0 is usually the padding character.
|
||||
oov_char: words that were cut out because of the `nb_words`
|
||||
or `skip_top` limit will be replaced with this character.
|
||||
index_from: index actual words with this index and higher.
|
||||
|
||||
path = get_file(path, origin="https://s3.amazonaws.com/text-datasets/imdb.pkl")
|
||||
Note that the 'out of vocabulary' character is only used for
|
||||
words that were present in the training set but are not included
|
||||
because they're not making the `nb_words` cut here.
|
||||
Words that were not seen in the trining set but are in the test set
|
||||
have simply been skipped.
|
||||
'''
|
||||
path = get_file(path,
|
||||
origin='https://s3.amazonaws.com/text-datasets/imdb_full.pkl',
|
||||
md5_hash='d091312047c43cf9e4e38fef92437263')
|
||||
|
||||
if path.endswith(".gz"):
|
||||
if path.endswith('.gz'):
|
||||
f = gzip.open(path, 'rb')
|
||||
else:
|
||||
f = open(path, 'rb')
|
||||
|
||||
X, labels = cPickle.load(f)
|
||||
(x_train, labels_train), (x_test, labels_test) = cPickle.load(f)
|
||||
f.close()
|
||||
|
||||
np.random.seed(seed)
|
||||
np.random.shuffle(X)
|
||||
np.random.shuffle(x_train)
|
||||
np.random.seed(seed)
|
||||
np.random.shuffle(labels)
|
||||
np.random.shuffle(labels_train)
|
||||
|
||||
np.random.seed(seed * 2)
|
||||
np.random.shuffle(x_test)
|
||||
np.random.seed(seed * 2)
|
||||
np.random.shuffle(labels_test)
|
||||
|
||||
X = x_train + x_test
|
||||
labels = labels_train + labels_test
|
||||
|
||||
if start_char is not None:
|
||||
X = [[start_char] + [w + index_from for w in x] for x in X]
|
||||
@@ -60,10 +92,25 @@ def load_data(path="imdb.pkl", nb_words=None, skip_top=0,
|
||||
nX.append(nx)
|
||||
X = nX
|
||||
|
||||
X_train = np.array(X[:int(len(X) * (1 - test_split))])
|
||||
y_train = np.array(labels[:int(len(X) * (1 - test_split))])
|
||||
X_train = np.array(X[:len(x_train)])
|
||||
y_train = np.array(labels[:len(x_train)])
|
||||
|
||||
X_test = np.array(X[int(len(X) * (1 - test_split)):])
|
||||
y_test = np.array(labels[int(len(X) * (1 - test_split)):])
|
||||
X_test = np.array(X[len(x_train):])
|
||||
y_test = np.array(labels[len(x_train):])
|
||||
|
||||
return (X_train, y_train), (X_test, y_test)
|
||||
|
||||
|
||||
def get_word_index(path='imdb_word_index.pkl'):
|
||||
path = get_file(path,
|
||||
origin='https://s3.amazonaws.com/text-datasets/imdb_word_index.pkl',
|
||||
md5_hash='72d94b01291be4ff843198d3b0e1e4d7')
|
||||
f = open(path, 'rb')
|
||||
|
||||
if sys.version_info < (3,):
|
||||
data = cPickle.load(f)
|
||||
else:
|
||||
data = cPickle.load(f, encoding='latin1')
|
||||
|
||||
f.close()
|
||||
return data
|
||||
|
||||
@@ -7,11 +7,34 @@ import numpy as np
|
||||
import sys
|
||||
|
||||
|
||||
def load_data(path="reuters.pkl", nb_words=None, skip_top=0,
|
||||
def load_data(path='reuters.pkl', nb_words=None, skip_top=0,
|
||||
maxlen=None, test_split=0.2, seed=113,
|
||||
start_char=1, oov_char=2, index_from=3):
|
||||
'''
|
||||
# Arguments
|
||||
path: where to store the data (in `/.keras/dataset`)
|
||||
nb_words: max number of words to include. Words are ranked
|
||||
by how often they occur (in the training set) and only
|
||||
the most frequent words are kept
|
||||
skip_top: skip the top N most frequently occuring words
|
||||
(which may not be informative).
|
||||
maxlen: truncate sequences after this length.
|
||||
test_split: Fraction of the dataset to be used as test data.
|
||||
seed: random seed for sample shuffling.
|
||||
start_char: The start of a sequence will be marked with this character.
|
||||
Set to 1 because 0 is usually the padding character.
|
||||
oov_char: words that were cut out because of the `nb_words`
|
||||
or `skip_top` limit will be replaced with this character.
|
||||
index_from: index actual words with this index and higher.
|
||||
|
||||
path = get_file(path, origin="https://s3.amazonaws.com/text-datasets/reuters.pkl")
|
||||
Note that the 'out of vocabulary' character is only used for
|
||||
words that were present in the training set but are not included
|
||||
because they're not making the `nb_words` cut here.
|
||||
Words that were not seen in the trining set but are in the test set
|
||||
have simply been skipped.
|
||||
'''
|
||||
|
||||
path = get_file(path, origin='https://s3.amazonaws.com/text-datasets/reuters.pkl')
|
||||
f = open(path, 'rb')
|
||||
X, labels = cPickle.load(f)
|
||||
f.close()
|
||||
@@ -62,14 +85,14 @@ def load_data(path="reuters.pkl", nb_words=None, skip_top=0,
|
||||
return (X_train, y_train), (X_test, y_test)
|
||||
|
||||
|
||||
def get_word_index(path="reuters_word_index.pkl"):
|
||||
path = get_file(path, origin="https://s3.amazonaws.com/text-datasets/reuters_word_index.pkl")
|
||||
def get_word_index(path='reuters_word_index.pkl'):
|
||||
path = get_file(path, origin='https://s3.amazonaws.com/text-datasets/reuters_word_index.pkl')
|
||||
f = open(path, 'rb')
|
||||
|
||||
if sys.version_info < (3,):
|
||||
data = cPickle.load(f)
|
||||
else:
|
||||
data = cPickle.load(f, encoding="latin1")
|
||||
data = cPickle.load(f, encoding='latin1')
|
||||
|
||||
f.close()
|
||||
return data
|
||||
|
||||
+305
-108
@@ -5,14 +5,15 @@ from __future__ import division
|
||||
|
||||
import numpy as np
|
||||
|
||||
import sys
|
||||
import marshal
|
||||
import types as python_types
|
||||
import warnings
|
||||
import copy
|
||||
import os
|
||||
from six.moves import zip
|
||||
|
||||
from keras import backend as K
|
||||
from .. import backend as K
|
||||
from ..utils.io_utils import ask_to_proceed_with_overwrite
|
||||
from ..utils.generic_utils import func_dump, func_load
|
||||
|
||||
|
||||
def to_list(x):
|
||||
@@ -282,10 +283,14 @@ class Layer(object):
|
||||
|
||||
# these properties will be set upon call of self.build(),
|
||||
# which itself will be called upon self.add_inbound_node if necessary.
|
||||
self.trainable_weights = []
|
||||
self.non_trainable_weights = []
|
||||
self.regularizers = []
|
||||
self.constraints = {} # dict {tensor: constraint instance}
|
||||
if not hasattr(self, 'trainable_weights'):
|
||||
self.trainable_weights = []
|
||||
if not hasattr(self, 'non_trainable_weights'):
|
||||
self.non_trainable_weights = []
|
||||
if not hasattr(self, 'regularizers'):
|
||||
self.regularizers = []
|
||||
if not hasattr(self, 'constraints'):
|
||||
self.constraints = {} # dict {tensor: constraint instance}
|
||||
self.built = False
|
||||
|
||||
# these properties should be set by the user via keyword arguments.
|
||||
@@ -321,6 +326,30 @@ class Layer(object):
|
||||
if 'create_input_layer' in kwargs:
|
||||
self.create_input_layer(batch_input_shape, input_dtype)
|
||||
|
||||
@property
|
||||
def trainable_weights(self):
|
||||
trainable = getattr(self, 'trainable', True)
|
||||
if trainable:
|
||||
return self._trainable_weights
|
||||
else:
|
||||
return []
|
||||
|
||||
@trainable_weights.setter
|
||||
def trainable_weights(self, weights):
|
||||
self._trainable_weights = weights
|
||||
|
||||
@property
|
||||
def non_trainable_weights(self):
|
||||
trainable = getattr(self, 'trainable', True)
|
||||
if not trainable:
|
||||
return self._trainable_weights + self._non_trainable_weights
|
||||
else:
|
||||
return self._non_trainable_weights
|
||||
|
||||
@non_trainable_weights.setter
|
||||
def non_trainable_weights(self, weights):
|
||||
self._non_trainable_weights = weights
|
||||
|
||||
def create_input_layer(self, batch_input_shape,
|
||||
input_dtype=None, name=None):
|
||||
if not name:
|
||||
@@ -694,15 +723,15 @@ class Layer(object):
|
||||
' outbound layers. '
|
||||
'This will cause part of your model '
|
||||
'to be disconnected.')
|
||||
if not shape:
|
||||
if hasattr(K, 'int_shape'):
|
||||
shape = K.int_shape(input_tensor)
|
||||
else:
|
||||
raise Exception('`set_input` needs to know the shape '
|
||||
'of the `input_tensor` it receives, but '
|
||||
'Keras was not able to infer it automatically.'
|
||||
' Specify it via: '
|
||||
'`model.set_input(input_tensor, shape)`')
|
||||
if hasattr(K, 'int_shape'):
|
||||
# auto-infered shape takes priority
|
||||
shape = K.int_shape(input_tensor)
|
||||
elif not shape:
|
||||
raise Exception('`set_input` needs to know the shape '
|
||||
'of the `input_tensor` it receives, but '
|
||||
'Keras was not able to infer it automatically.'
|
||||
' Specify it via: '
|
||||
'`model.set_input(input_tensor, shape)`')
|
||||
# reset layer connections
|
||||
self.inbound_nodes = []
|
||||
self.outbound_nodes = []
|
||||
@@ -828,6 +857,10 @@ class Layer(object):
|
||||
'ill-defined for the layer. ' +
|
||||
'Use `get_output_shape_at(node_index)` instead.')
|
||||
|
||||
@property
|
||||
def weights(self):
|
||||
return self.trainable_weights + self.non_trainable_weights
|
||||
|
||||
def set_weights(self, weights):
|
||||
'''Sets the weights of the layer, from Numpy arrays.
|
||||
|
||||
@@ -838,12 +871,12 @@ class Layer(object):
|
||||
of the layer (i.e. it should match the
|
||||
output of `get_weights`).
|
||||
'''
|
||||
params = self.trainable_weights + self.non_trainable_weights
|
||||
params = self.weights
|
||||
if len(params) != len(weights):
|
||||
raise Exception('You called `set_weights(weights)` on layer "' + self.name +
|
||||
'" with a weight list of length ' + str(len(weights)) +
|
||||
', but the layer was expecting ' + str(len(params)) +
|
||||
' weights. Provided weights: ' + str(weights))
|
||||
' weights. Provided weights: ' + str(weights)[:50] + '...')
|
||||
if not params:
|
||||
return
|
||||
weight_value_tuples = []
|
||||
@@ -861,7 +894,7 @@ class Layer(object):
|
||||
'''Returns the current weights of the layer,
|
||||
as a list of numpy arrays.
|
||||
'''
|
||||
params = self.trainable_weights + self.non_trainable_weights
|
||||
params = self.weights
|
||||
return K.batch_get_value(params)
|
||||
|
||||
def get_config(self):
|
||||
@@ -914,12 +947,14 @@ class InputLayer(Layer):
|
||||
'''TODO: dosctring
|
||||
'''
|
||||
def __init__(self, input_shape=None, batch_input_shape=None,
|
||||
input_dtype=None, input_tensor=None, name=None):
|
||||
input_dtype=None, input_tensor=None, sparse=False, name=None):
|
||||
self.input_spec = None
|
||||
self.supports_masking = False
|
||||
self.uses_learning_phase = False
|
||||
self.trainable = False
|
||||
self.built = True
|
||||
self.trainable_weights = []
|
||||
self.non_trainable_weights = []
|
||||
|
||||
self.inbound_nodes = []
|
||||
self.outbound_nodes = []
|
||||
@@ -929,6 +964,8 @@ class InputLayer(Layer):
|
||||
self.regularizers = []
|
||||
self.constraints = {}
|
||||
|
||||
self.sparse = sparse
|
||||
|
||||
if not name:
|
||||
prefix = 'input'
|
||||
name = prefix + '_' + str(K.get_uid(prefix))
|
||||
@@ -939,11 +976,11 @@ class InputLayer(Layer):
|
||||
'batch_input_shape argument to '
|
||||
'InputLayer, not both at the same time.')
|
||||
if input_tensor is not None:
|
||||
if not input_shape and not batch_input_shape:
|
||||
# attempt automatic input shape inference
|
||||
try:
|
||||
batch_input_shape = K.int_shape(input_tensor)
|
||||
except:
|
||||
# attempt automatic input shape inference
|
||||
try:
|
||||
batch_input_shape = K.int_shape(input_tensor)
|
||||
except:
|
||||
if not input_shape and not batch_input_shape:
|
||||
raise ValueError('InputLayer was provided an input_tensor argument, '
|
||||
'but its input shape cannot be automatically inferred. '
|
||||
'You should pass an input_shape or batch_input_shape '
|
||||
@@ -969,6 +1006,7 @@ class InputLayer(Layer):
|
||||
if input_tensor is None:
|
||||
input_tensor = K.placeholder(shape=batch_input_shape,
|
||||
dtype=input_dtype,
|
||||
sparse=self.sparse,
|
||||
name=self.name)
|
||||
else:
|
||||
input_tensor._keras_shape = batch_input_shape
|
||||
@@ -990,12 +1028,13 @@ class InputLayer(Layer):
|
||||
def get_config(self):
|
||||
config = {'batch_input_shape': self.batch_input_shape,
|
||||
'input_dtype': self.input_dtype,
|
||||
'sparse': self.sparse,
|
||||
'name': self.name}
|
||||
return config
|
||||
|
||||
|
||||
def Input(shape=None, batch_shape=None,
|
||||
name=None, dtype=K.floatx(),
|
||||
name=None, dtype=K.floatx(), sparse=False,
|
||||
tensor=None):
|
||||
'''`Input()` is used to instantiate a Keras tensor.
|
||||
A Keras tensor is a tensor object from the underlying backend
|
||||
@@ -1028,6 +1067,7 @@ def Input(shape=None, batch_shape=None,
|
||||
It will be autogenerated if it isn't provided.
|
||||
dtype: The data type expected by the input, as a string
|
||||
(`float32`, `float64`, `int32`...)
|
||||
sparse: a boolean specifying whether this will be a sparse tensor
|
||||
|
||||
# Example usage
|
||||
|
||||
@@ -1043,9 +1083,11 @@ def Input(shape=None, batch_shape=None,
|
||||
' or a `batch_shape` argument. Note that ' +
|
||||
'`shape` does not include the batch '
|
||||
'dimension.')
|
||||
if shape and not batch_shape:
|
||||
batch_shape = (None,) + tuple(shape)
|
||||
input_layer = InputLayer(batch_input_shape=batch_shape,
|
||||
name=name, input_dtype=dtype,
|
||||
sparse=sparse,
|
||||
input_tensor=tensor)
|
||||
# return tensor including _keras_shape and _keras_history
|
||||
# note that in this case train_output and test_output are the same pointer.
|
||||
@@ -1084,7 +1126,7 @@ class Merge(Layer):
|
||||
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`.
|
||||
dot_axes: integer or tuple of integers, axes to use in mode `dot`.
|
||||
dot_axes: integer or tuple of integers, axes to use in mode `dot` or `cos`.
|
||||
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,
|
||||
@@ -1111,8 +1153,6 @@ class Merge(Layer):
|
||||
self.mode = mode
|
||||
self.concat_axis = concat_axis
|
||||
self.dot_axes = dot_axes
|
||||
if type(self.dot_axes) == int:
|
||||
self.dot_axes = [self.dot_axes, ] * 2
|
||||
self._output_shape = output_shape
|
||||
self.node_indices = node_indices
|
||||
self._output_mask = output_mask
|
||||
@@ -1188,18 +1228,18 @@ class Merge(Layer):
|
||||
n2 = len(shape2)
|
||||
if type(dot_axes) == int:
|
||||
if dot_axes < 0:
|
||||
dot_axes = [dot_axes % n1, dot_axes % n2]
|
||||
self.dot_axes = [dot_axes % n1, dot_axes % n2]
|
||||
else:
|
||||
dot_axes = [n1 - dot_axes, n2-dot_axes]
|
||||
if type(dot_axes) not in [list, tuple]:
|
||||
self.dot_axes = [dot_axes, ] * 2
|
||||
if type(self.dot_axes) not in [list, tuple]:
|
||||
raise Exception('Invalid type for dot_axes - should be a list.')
|
||||
if len(dot_axes) != 2:
|
||||
if len(self.dot_axes) != 2:
|
||||
raise Exception('Invalid format for dot_axes - should contain two elements.')
|
||||
if type(dot_axes[0]) is not int or type(dot_axes[1]) is not int:
|
||||
if type(self.dot_axes[0]) is not int or type(self.dot_axes[1]) is not int:
|
||||
raise Exception('Invalid format for dot_axes - list elements should be "int".')
|
||||
if shape1[dot_axes[0]] != shape2[dot_axes[1]]:
|
||||
if shape1[self.dot_axes[0]] != shape2[self.dot_axes[1]]:
|
||||
raise Exception('Dimension incompatibility using dot mode: ' +
|
||||
'%s != %s. ' % (shape1[dot_axes[0]], shape2[dot_axes[1]]) +
|
||||
'%s != %s. ' % (shape1[self.dot_axes[0]], shape2[self.dot_axes[1]]) +
|
||||
'Layer shapes: %s, %s' % (shape1, shape2))
|
||||
elif mode == 'concat':
|
||||
reduced_inputs_shapes = [list(shape) for shape in input_shapes]
|
||||
@@ -1336,15 +1376,13 @@ class Merge(Layer):
|
||||
elif self.mode in ['dot', 'cos']:
|
||||
shape1 = list(input_shapes[0])
|
||||
shape2 = list(input_shapes[1])
|
||||
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)
|
||||
if len(tensordot_output.shape) == 0:
|
||||
shape = (1,)
|
||||
else:
|
||||
shape = tensordot_output.shape
|
||||
return (shape1[0],) + shape
|
||||
shape1.pop(self.dot_axes[0])
|
||||
shape2.pop(self.dot_axes[1])
|
||||
shape2.pop(0)
|
||||
output_shape = shape1 + shape2
|
||||
if len(output_shape) == 1:
|
||||
output_shape += [1]
|
||||
return tuple(output_shape)
|
||||
|
||||
def compute_mask(self, inputs, mask=None):
|
||||
if mask is None or all([m is None for m in mask]):
|
||||
@@ -1356,9 +1394,19 @@ class Merge(Layer):
|
||||
masks = [K.expand_dims(m, 0) for m in mask if m is not None]
|
||||
return K.all(K.concatenate(masks, axis=0), axis=0, keepdims=False)
|
||||
elif self.mode == 'concat':
|
||||
masks = [K.ones_like(inputs[i][:-1]) if m is None else m for i, m in zip(inputs, mask)]
|
||||
expanded_dims = [K.expand_dims(m) for m in masks]
|
||||
concatenated = K.concatenate(expanded_dims, axis=self.concat_axis)
|
||||
# Make a list of masks while making sure the dimensionality of each mask
|
||||
# is the same as the corresponding input.
|
||||
masks = []
|
||||
for input_i, mask_i in zip(inputs, mask):
|
||||
if mask_i is None:
|
||||
# Input is unmasked. Append all 1s to masks, but cast it to uint8 first
|
||||
masks.append(K.cast(K.ones_like(input_i), 'uint8'))
|
||||
elif K.ndim(mask_i) < K.ndim(input_i):
|
||||
# Mask is smaller than the input, expand it
|
||||
masks.append(K.expand_dims(mask_i))
|
||||
else:
|
||||
masks.append(mask_i)
|
||||
concatenated = K.concatenate(masks, axis=self.concat_axis)
|
||||
return K.all(concatenated, axis=-1, keepdims=False)
|
||||
elif self.mode in ['cos', 'dot']:
|
||||
return None
|
||||
@@ -1372,13 +1420,8 @@ class Merge(Layer):
|
||||
raise Exception('Invalid merge mode: {}'.format(self.mode))
|
||||
|
||||
def get_config(self):
|
||||
py3 = sys.version_info[0] == 3
|
||||
|
||||
if isinstance(self.mode, python_types.LambdaType):
|
||||
if py3:
|
||||
mode = marshal.dumps(self.mode.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
mode = marshal.dumps(self.mode.func_code).decode('raw_unicode_escape')
|
||||
mode = func_dump(self.mode)
|
||||
mode_type = 'lambda'
|
||||
elif callable(self.mode):
|
||||
mode = self.mode.__name__
|
||||
@@ -1388,10 +1431,7 @@ class Merge(Layer):
|
||||
mode_type = 'raw'
|
||||
|
||||
if isinstance(self._output_shape, python_types.LambdaType):
|
||||
if py3:
|
||||
output_shape = marshal.dumps(self._output_shape.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
output_shape = marshal.dumps(self._output_shape.func_code).decode('raw_unicode_escape')
|
||||
output_shape = func_dump(self._output_shape)
|
||||
output_shape_type = 'lambda'
|
||||
elif callable(self._output_shape):
|
||||
output_shape = self._output_shape.__name__
|
||||
@@ -1414,8 +1454,7 @@ class Merge(Layer):
|
||||
if mode_type == 'function':
|
||||
mode = globals()[config['mode']]
|
||||
elif mode_type == 'lambda':
|
||||
mode = marshal.loads(config['mode'].encode('raw_unicode_escape'))
|
||||
mode = python_types.FunctionType(mode, globals())
|
||||
mode = func_load(config['mode'], globs=globals())
|
||||
else:
|
||||
mode = config['mode']
|
||||
|
||||
@@ -1423,8 +1462,7 @@ class Merge(Layer):
|
||||
if output_shape_type == 'function':
|
||||
output_shape = globals()[config['output_shape']]
|
||||
elif output_shape_type == 'lambda':
|
||||
output_shape = marshal.loads(config['output_shape'].encode('raw_unicode_escape'))
|
||||
output_shape = python_types.FunctionType(output_shape, globals())
|
||||
output_shape = func_load(config['output_shape'], globs=globals())
|
||||
else:
|
||||
output_shape = config['output_shape']
|
||||
|
||||
@@ -1452,7 +1490,7 @@ def merge(inputs, mode='sum', concat_axis=-1,
|
||||
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`.
|
||||
dot_axes: integer or tuple of integers, axes to use in mode `dot`.
|
||||
dot_axes: integer or tuple of integers, axes to use in mode `dot` or `cos`.
|
||||
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
|
||||
@@ -1544,6 +1582,9 @@ class Container(Layer):
|
||||
name = prefix + '_' + str(K.get_uid(prefix))
|
||||
self.name = name
|
||||
|
||||
# whether container weights are trainable
|
||||
self.trainable = True
|
||||
|
||||
# Container-specific properties
|
||||
if type(input) in {list, tuple}:
|
||||
self.inputs = list(input) # tensor or list of tensors
|
||||
@@ -1673,6 +1714,7 @@ class Container(Layer):
|
||||
container_nodes = set() # ids of all nodes relevant to the Container
|
||||
nodes_depths = {} # map {node: depth value}
|
||||
layers_depths = {} # map {layer: depth value}
|
||||
layer_indices = {} # map {layer: index in traversal}
|
||||
|
||||
def make_node_marker(node, depth):
|
||||
return str(id(node)) + '-' + str(depth)
|
||||
@@ -1716,6 +1758,8 @@ class Container(Layer):
|
||||
else:
|
||||
current_depth = max(depth, previously_seen_depth)
|
||||
layers_depths[layer] = current_depth
|
||||
if layer not in layer_indices:
|
||||
layer_indices[layer] = len(layer_indices)
|
||||
|
||||
# propagate to all previous tensors connected to this node
|
||||
for i in range(len(node.inbound_layers)):
|
||||
@@ -1756,8 +1800,12 @@ class Container(Layer):
|
||||
layers = []
|
||||
for depth in depth_keys:
|
||||
layers_for_depth = layers_by_depth[depth]
|
||||
# container.layers needs to have a deterministic order
|
||||
layers_for_depth.sort(key=lambda x: x.name)
|
||||
# container.layers needs to have a deterministic order:
|
||||
# here we order them by traversal order
|
||||
if K.legacy_weight_ordering():
|
||||
layers_for_depth.sort(key=lambda x: x.name)
|
||||
else:
|
||||
layers_for_depth.sort(key=lambda x: layer_indices[x])
|
||||
for layer in layers_for_depth:
|
||||
layers.append(layer)
|
||||
self.layers = layers
|
||||
@@ -1898,7 +1946,7 @@ class Container(Layer):
|
||||
cons = {}
|
||||
for layer in self.layers:
|
||||
for key, value in layer.constraints.items():
|
||||
if key in cons:
|
||||
if key in cons and cons[key] != value:
|
||||
raise Exception('Received multiple constraints '
|
||||
'for one weight tensor: ' + str(key))
|
||||
cons[key] = value
|
||||
@@ -1913,6 +1961,8 @@ class Container(Layer):
|
||||
|
||||
@property
|
||||
def trainable_weights(self):
|
||||
if not self.trainable:
|
||||
return []
|
||||
weights = []
|
||||
for layer in self.layers:
|
||||
weights += layer.trainable_weights
|
||||
@@ -1923,8 +1973,37 @@ class Container(Layer):
|
||||
weights = []
|
||||
for layer in self.layers:
|
||||
weights += layer.non_trainable_weights
|
||||
if not self.trainable:
|
||||
trainable_weights = []
|
||||
for layer in self.layers:
|
||||
trainable_weights += layer.trainable_weights
|
||||
return trainable_weights + weights
|
||||
return weights
|
||||
|
||||
def get_weights(self):
|
||||
'''Returns the weights of the model,
|
||||
as a flat list of Numpy arrays.
|
||||
'''
|
||||
weights = []
|
||||
for layer in self.layers:
|
||||
weights += layer.weights
|
||||
return K.batch_get_value(weights)
|
||||
|
||||
def set_weights(self, weights):
|
||||
'''Sets the weights of the model.
|
||||
The `weights` argument should be a list
|
||||
of Numpy arrays with shapes and types matching
|
||||
the output of `model.get_weights()`.
|
||||
'''
|
||||
tuples = []
|
||||
for layer in self.layers:
|
||||
nb_param = len(layer.weights)
|
||||
layer_weights = weights[:nb_param]
|
||||
for sw, w in zip(layer.weights, layer_weights):
|
||||
tuples.append((sw, w))
|
||||
weights = weights[nb_param:]
|
||||
K.batch_set_value(tuples)
|
||||
|
||||
@property
|
||||
def input_spec(self):
|
||||
specs = []
|
||||
@@ -2312,7 +2391,38 @@ class Container(Layer):
|
||||
output_tensors.append(layer_output_tensors[tensor_index])
|
||||
return cls(input=input_tensors, output=output_tensors, name=name)
|
||||
|
||||
def save_weights(self, filepath, overwrite=False):
|
||||
def save(self, filepath, overwrite=True):
|
||||
'''Save into a single HDF5 file:
|
||||
- the model architecture, allowing to re-instantiate the model
|
||||
- the model weights
|
||||
- the state of the optimizer, allowing to resume training
|
||||
exactly where you left off.
|
||||
|
||||
This allows you to save the entirety of the state of a model
|
||||
in a single file.
|
||||
|
||||
Saved models can be reinstantiated via `keras.models.load_model`.
|
||||
The model returned by `load_model`
|
||||
is a compiled model ready to be used (unless the saved model
|
||||
was never compiled in the first place).
|
||||
|
||||
# Example usage
|
||||
|
||||
```python
|
||||
from keras.models import load_model
|
||||
|
||||
model.save('my_model.h5') # creates a HDF5 file 'my_model.h5'
|
||||
del model # deletes the existing model
|
||||
|
||||
# returns a compiled model
|
||||
# identical to the previous one
|
||||
model = load_model('my_model.h5')
|
||||
```
|
||||
'''
|
||||
from ..models import save_model
|
||||
save_model(self, filepath, overwrite)
|
||||
|
||||
def save_weights(self, filepath, overwrite=True):
|
||||
'''Dumps all layer weights to a HDF5 file.
|
||||
|
||||
The weight file has:
|
||||
@@ -2325,33 +2435,28 @@ class Container(Layer):
|
||||
storing the weight value, named after the weight tensor
|
||||
'''
|
||||
import h5py
|
||||
import os.path
|
||||
# if file exists and should not be overwritten
|
||||
if not overwrite and os.path.isfile(filepath):
|
||||
import sys
|
||||
get_input = input
|
||||
if sys.version_info[:2] <= (2, 7):
|
||||
get_input = raw_input
|
||||
overwrite = get_input('[WARNING] %s already exists - overwrite? '
|
||||
'[y/n]' % (filepath))
|
||||
while overwrite not in ['y', 'n']:
|
||||
overwrite = get_input('Enter "y" (overwrite) or "n" (cancel).')
|
||||
if overwrite == 'n':
|
||||
proceed = ask_to_proceed_with_overwrite(filepath)
|
||||
if not proceed:
|
||||
return
|
||||
print('[TIP] Next time specify overwrite=True in save_weights!')
|
||||
f = h5py.File(filepath, 'w')
|
||||
self.save_weights_to_hdf5_group(f)
|
||||
f.flush()
|
||||
f.close()
|
||||
|
||||
def save_weights_to_hdf5_group(self, f):
|
||||
if hasattr(self, 'flattened_layers'):
|
||||
# support for legacy Sequential/Merge behavior
|
||||
flattened_layers = self.flattened_layers
|
||||
else:
|
||||
flattened_layers = self.layers
|
||||
|
||||
f = h5py.File(filepath, 'w')
|
||||
f.attrs['layer_names'] = [layer.name.encode('utf8') for layer in flattened_layers]
|
||||
|
||||
for layer in flattened_layers:
|
||||
g = f.create_group(layer.name)
|
||||
symbolic_weights = layer.trainable_weights + layer.non_trainable_weights
|
||||
symbolic_weights = layer.weights
|
||||
weight_values = K.batch_get_value(symbolic_weights)
|
||||
weight_names = []
|
||||
for i, (w, val) in enumerate(zip(symbolic_weights, weight_values)):
|
||||
@@ -2364,16 +2469,46 @@ class Container(Layer):
|
||||
for name, val in zip(weight_names, weight_values):
|
||||
param_dset = g.create_dataset(name, val.shape,
|
||||
dtype=val.dtype)
|
||||
param_dset[:] = val
|
||||
f.flush()
|
||||
f.close()
|
||||
if not val.shape:
|
||||
# scalar
|
||||
param_dset[()] = val
|
||||
else:
|
||||
param_dset[:] = val
|
||||
|
||||
def load_weights(self, filepath):
|
||||
def load_weights(self, filepath, by_name=False):
|
||||
'''Load all layer weights from a HDF5 save file.
|
||||
|
||||
If `by_name` is False (default) weights are loaded
|
||||
based on the network's topology, meaning the architecture
|
||||
should be the same as when the weights were saved.
|
||||
Note that layers that don't have weights are not taken
|
||||
into account in the topological ordering, so adding or
|
||||
removing layers is fine as long as they don't have weights.
|
||||
|
||||
If `by_name` is True, weights are loaded into layers
|
||||
only if they share the same name. This is useful
|
||||
for fine-tuning or transfer-learning models where
|
||||
some of the layers have changed.
|
||||
'''
|
||||
import h5py
|
||||
f = h5py.File(filepath, mode='r')
|
||||
if 'layer_names' not in f.attrs and 'model_weights' in f:
|
||||
f = f['model_weights']
|
||||
if by_name:
|
||||
self.load_weights_from_hdf5_group_by_name(f)
|
||||
else:
|
||||
self.load_weights_from_hdf5_group(f)
|
||||
|
||||
if hasattr(f, 'close'):
|
||||
f.close()
|
||||
|
||||
def load_weights_from_hdf5_group(self, f):
|
||||
'''Weight loading is based on layer order in a list
|
||||
(matching model.flattened_layers for Sequential models,
|
||||
and model.layers for Model class instances), not
|
||||
on layer names.
|
||||
Layers that have no weights are skipped.
|
||||
'''
|
||||
if hasattr(self, 'flattened_layers'):
|
||||
# support for legacy Sequential/Merge behavior
|
||||
flattened_layers = self.flattened_layers
|
||||
@@ -2387,7 +2522,7 @@ class Container(Layer):
|
||||
raise Exception('You are trying to load a weight file '
|
||||
'containing ' + str(nb_layers) +
|
||||
' layers into a model with ' +
|
||||
str(len(flattened_layers)) + '.')
|
||||
str(len(flattened_layers)) + ' layers.')
|
||||
|
||||
for k in range(nb_layers):
|
||||
g = f['layer_{}'.format(k)]
|
||||
@@ -2395,7 +2530,21 @@ class Container(Layer):
|
||||
flattened_layers[k].set_weights(weights)
|
||||
else:
|
||||
# new file format
|
||||
filtered_layers = []
|
||||
for layer in flattened_layers:
|
||||
weights = layer.weights
|
||||
if weights:
|
||||
filtered_layers.append(layer)
|
||||
flattened_layers = filtered_layers
|
||||
|
||||
layer_names = [n.decode('utf8') for n in f.attrs['layer_names']]
|
||||
filtered_layer_names = []
|
||||
for name in layer_names:
|
||||
g = f[name]
|
||||
weight_names = [n.decode('utf8') for n in g.attrs['weight_names']]
|
||||
if len(weight_names):
|
||||
filtered_layer_names.append(name)
|
||||
layer_names = filtered_layer_names
|
||||
if len(layer_names) != len(flattened_layers):
|
||||
raise Exception('You are trying to load a weight file '
|
||||
'containing ' + str(len(layer_names)) +
|
||||
@@ -2408,24 +2557,80 @@ class Container(Layer):
|
||||
for k, name in enumerate(layer_names):
|
||||
g = f[name]
|
||||
weight_names = [n.decode('utf8') for n in g.attrs['weight_names']]
|
||||
if len(weight_names):
|
||||
weight_values = [g[weight_name] for weight_name in weight_names]
|
||||
layer = flattened_layers[k]
|
||||
symbolic_weights = layer.trainable_weights + layer.non_trainable_weights
|
||||
weight_values = [g[weight_name] for weight_name in weight_names]
|
||||
layer = flattened_layers[k]
|
||||
symbolic_weights = layer.weights
|
||||
if len(weight_values) != len(symbolic_weights):
|
||||
raise Exception('Layer #' + str(k) +
|
||||
' (named "' + layer.name +
|
||||
'" in the current model) was found to '
|
||||
'correspond to layer ' + name +
|
||||
' in the save file. '
|
||||
'However the new layer ' + layer.name +
|
||||
' expects ' + str(len(symbolic_weights)) +
|
||||
' weights, but the saved weights have ' +
|
||||
str(len(weight_values)) +
|
||||
' elements.')
|
||||
if layer.__class__.__name__ == 'Convolution1D':
|
||||
# this is for backwards compatibility with
|
||||
# the old Conv1D weights format.
|
||||
w = weight_values[0]
|
||||
shape = w.shape
|
||||
if shape[:2] != (layer.filter_length, 1) or shape[3] != layer.nb_filter:
|
||||
# legacy shape: (self.nb_filter, input_dim, self.filter_length, 1)
|
||||
assert shape[0] == layer.nb_filter and shape[2:] == (layer.filter_length, 1)
|
||||
w = np.transpose(w, (2, 3, 1, 0))
|
||||
weight_values[0] = w
|
||||
weight_value_tuples += zip(symbolic_weights, weight_values)
|
||||
K.batch_set_value(weight_value_tuples)
|
||||
|
||||
def load_weights_from_hdf5_group_by_name(self, f):
|
||||
''' Name-based weight loading
|
||||
(instead of topological weight loading).
|
||||
Layers that have no matching name are skipped.
|
||||
'''
|
||||
if hasattr(self, 'flattened_layers'):
|
||||
# support for legacy Sequential/Merge behavior
|
||||
flattened_layers = self.flattened_layers
|
||||
else:
|
||||
flattened_layers = self.layers
|
||||
|
||||
if 'nb_layers' in f.attrs:
|
||||
raise Exception('The weight file you are trying to load is' +
|
||||
' in a legacy format that does not support' +
|
||||
' name-based weight loading.')
|
||||
else:
|
||||
# new file format
|
||||
layer_names = [n.decode('utf8') for n in f.attrs['layer_names']]
|
||||
|
||||
# Reverse index of layer name to list of layers with name.
|
||||
index = {}
|
||||
for layer in flattened_layers:
|
||||
if layer.name:
|
||||
index.setdefault(layer.name, []).append(layer)
|
||||
|
||||
# we batch weight value assignments in a single backend call
|
||||
# which provides a speedup in TensorFlow.
|
||||
weight_value_tuples = []
|
||||
for k, name in enumerate(layer_names):
|
||||
g = f[name]
|
||||
weight_names = [n.decode('utf8') for n in g.attrs['weight_names']]
|
||||
weight_values = [g[weight_name] for weight_name in weight_names]
|
||||
|
||||
for layer in index.get(name, []):
|
||||
symbolic_weights = layer.weights
|
||||
if len(weight_values) != len(symbolic_weights):
|
||||
raise Exception('Layer #' + str(k) +
|
||||
' (named "' + layer.name +
|
||||
'" in the current model) was found to '
|
||||
'correspond to layer ' + name +
|
||||
' in the save file. '
|
||||
'However the new layer ' + layer.name +
|
||||
' expects ' + str(len(symbolic_weights)) +
|
||||
' weights, but the saved weights have ' +
|
||||
str(len(weight_values)) +
|
||||
' elements.')
|
||||
weight_value_tuples += zip(symbolic_weights, weight_values)
|
||||
'") expects ' +
|
||||
str(len(symbolic_weights)) +
|
||||
' weight(s), but the saved weights' +
|
||||
' have ' + str(len(weight_values)) +
|
||||
' element(s).')
|
||||
# set values
|
||||
for i in range(len(weight_values)):
|
||||
weight_value_tuples.append((symbolic_weights[i], weight_values[i]))
|
||||
K.batch_set_value(weight_value_tuples)
|
||||
f.close()
|
||||
|
||||
def _updated_config(self):
|
||||
'''shared between different serialization methods'''
|
||||
@@ -2437,14 +2642,6 @@ class Container(Layer):
|
||||
'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):
|
||||
@@ -2464,7 +2661,7 @@ class Container(Layer):
|
||||
if type(obj).__name__ == type.__name__:
|
||||
return obj.__name__
|
||||
|
||||
raise TypeError('Not JSON Serializable')
|
||||
raise TypeError('Not JSON Serializable:', obj)
|
||||
|
||||
model_config = self._updated_config()
|
||||
return json.dumps(model_config, default=get_json_type, **kwargs)
|
||||
|
||||
+38
-39
@@ -418,15 +418,11 @@ def generator_queue(generator, max_q_size=10,
|
||||
_stop = threading.Event()
|
||||
|
||||
try:
|
||||
|
||||
def data_generator_task():
|
||||
while not _stop.is_set():
|
||||
try:
|
||||
if q.qsize() < max_q_size:
|
||||
try:
|
||||
generator_output = next(generator)
|
||||
except ValueError:
|
||||
continue
|
||||
if pickle_safe or q.qsize() < max_q_size:
|
||||
generator_output = next(generator)
|
||||
q.put(generator_output)
|
||||
else:
|
||||
time.sleep(wait_time)
|
||||
@@ -444,7 +440,6 @@ def generator_queue(generator, max_q_size=10,
|
||||
generator_threads.append(thread)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
except:
|
||||
_stop.set()
|
||||
if pickle_safe:
|
||||
@@ -610,8 +605,9 @@ class Model(Container):
|
||||
self.targets.append(K.placeholder(ndim=len(shape), name=name + '_target'))
|
||||
|
||||
# prepare metrics
|
||||
self.metrics = metrics
|
||||
self.metrics_names = ['loss']
|
||||
self.metrics = []
|
||||
self.metrics_tensors = []
|
||||
|
||||
# compute total loss
|
||||
total_loss = None
|
||||
@@ -625,7 +621,7 @@ class Model(Container):
|
||||
output_loss = weighted_loss(y_true, y_pred,
|
||||
sample_weight, mask)
|
||||
if len(self.outputs) > 1:
|
||||
self.metrics.append(output_loss)
|
||||
self.metrics_tensors.append(output_loss)
|
||||
self.metrics_names.append(self.output_names[i] + '_loss')
|
||||
if total_loss is None:
|
||||
total_loss = loss_weight * output_loss
|
||||
@@ -650,21 +646,21 @@ class Model(Container):
|
||||
output_shape = self.internal_output_shapes[i]
|
||||
if output_shape[-1] == 1 or self.loss_functions[i] == objectives.binary_crossentropy:
|
||||
# case: binary accuracy
|
||||
self.metrics.append(metrics_module.binary_accuracy(y_true, y_pred))
|
||||
self.metrics_tensors.append(metrics_module.binary_accuracy(y_true, y_pred))
|
||||
elif self.loss_functions[i] == objectives.sparse_categorical_crossentropy:
|
||||
# case: categorical accuracy with sparse targets
|
||||
self.metrics.append(
|
||||
self.metrics_tensors.append(
|
||||
metrics_module.sparse_categorical_accuracy(y_true, y_pred))
|
||||
else:
|
||||
# case: categorical accuracy with dense targets
|
||||
self.metrics.append(metrics_module.categorical_accuracy(y_true, y_pred))
|
||||
self.metrics_tensors.append(metrics_module.categorical_accuracy(y_true, y_pred))
|
||||
if len(self.output_names) == 1:
|
||||
self.metrics_names.append('acc')
|
||||
else:
|
||||
self.metrics_names.append(self.output_layers[i].name + '_acc')
|
||||
else:
|
||||
metric_fn = metrics_module.get(metric)
|
||||
self.metrics.append(metric_fn(y_true, y_pred))
|
||||
self.metrics_tensors.append(metric_fn(y_true, y_pred))
|
||||
if len(self.output_names) == 1:
|
||||
self.metrics_names.append(metric_fn.__name__)
|
||||
else:
|
||||
@@ -684,23 +680,25 @@ class Model(Container):
|
||||
self.test_function = None
|
||||
self.predict_function = None
|
||||
|
||||
self._collected_trainable_weights = collect_trainable_weights(self)
|
||||
|
||||
def _make_train_function(self):
|
||||
if not hasattr(self, 'train_function'):
|
||||
raise Exception('You must compile your model before using it.')
|
||||
if self.train_function is None:
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
inputs = self.inputs + self.targets + self.sample_weights + [K.learning_phase()]
|
||||
else:
|
||||
inputs = self.inputs + self.targets + self.sample_weights
|
||||
|
||||
# get trainable weights
|
||||
trainable_weights = collect_trainable_weights(self)
|
||||
training_updates = self.optimizer.get_updates(trainable_weights, self.constraints, self.total_loss)
|
||||
training_updates = self.optimizer.get_updates(self._collected_trainable_weights,
|
||||
self.constraints,
|
||||
self.total_loss)
|
||||
updates = self.updates + training_updates
|
||||
|
||||
# returns loss and metrics. Updates weights at each call.
|
||||
self.train_function = K.function(inputs,
|
||||
[self.total_loss] + self.metrics,
|
||||
[self.total_loss] + self.metrics_tensors,
|
||||
updates=updates,
|
||||
**self._function_kwargs)
|
||||
|
||||
@@ -708,14 +706,14 @@ class Model(Container):
|
||||
if not hasattr(self, 'test_function'):
|
||||
raise Exception('You must compile your model before using it.')
|
||||
if self.test_function is None:
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
inputs = self.inputs + self.targets + self.sample_weights + [K.learning_phase()]
|
||||
else:
|
||||
inputs = self.inputs + self.targets + self.sample_weights
|
||||
# return loss and metrics, no gradient updates.
|
||||
# Does update the network states.
|
||||
self.test_function = K.function(inputs,
|
||||
[self.total_loss] + self.metrics,
|
||||
[self.total_loss] + self.metrics_tensors,
|
||||
updates=self.state_updates,
|
||||
**self._function_kwargs)
|
||||
|
||||
@@ -723,7 +721,7 @@ class Model(Container):
|
||||
if not hasattr(self, 'predict_function'):
|
||||
self.predict_function = None
|
||||
if self.predict_function is None:
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
inputs = self.inputs + [K.learning_phase()]
|
||||
else:
|
||||
inputs = self.inputs
|
||||
@@ -767,9 +765,9 @@ class Model(Container):
|
||||
do_validation = True
|
||||
if verbose:
|
||||
print('Train on %d samples, validate on %d samples' %
|
||||
(len(ins[0]), len(val_ins[0])))
|
||||
(ins[0].shape[0], val_ins[0].shape[0]))
|
||||
|
||||
nb_train_sample = len(ins[0])
|
||||
nb_train_sample = ins[0].shape[0]
|
||||
index_array = np.arange(nb_train_sample)
|
||||
|
||||
self.history = cbks.History()
|
||||
@@ -863,7 +861,7 @@ class Model(Container):
|
||||
or list of arrays of predictions
|
||||
(if the model has multiple outputs).
|
||||
'''
|
||||
nb_sample = len(ins[0])
|
||||
nb_sample = ins[0].shape[0]
|
||||
outs = []
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=nb_sample)
|
||||
@@ -908,7 +906,7 @@ class Model(Container):
|
||||
and/or metrics). The attribute `model.metrics_names` will give you
|
||||
the display labels for the scalar outputs.
|
||||
'''
|
||||
nb_sample = len(ins[0])
|
||||
nb_sample = ins[0].shape[0]
|
||||
outs = []
|
||||
if verbose == 1:
|
||||
progbar = Progbar(target=nb_sample)
|
||||
@@ -1050,7 +1048,7 @@ class Model(Container):
|
||||
batch_size=batch_size)
|
||||
self._make_test_function()
|
||||
val_f = self.test_function
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
val_ins = val_x + val_y + val_sample_weights + [0.]
|
||||
else:
|
||||
val_ins = val_x + val_y + val_sample_weights
|
||||
@@ -1064,7 +1062,7 @@ class Model(Container):
|
||||
slice_X(sample_weights, 0, split_at), slice_X(sample_weights, split_at))
|
||||
self._make_test_function()
|
||||
val_f = self.test_function
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
val_ins = val_x + val_y + val_sample_weights + [0.]
|
||||
else:
|
||||
val_ins = val_x + val_y + val_sample_weights
|
||||
@@ -1074,7 +1072,7 @@ class Model(Container):
|
||||
val_ins = None
|
||||
|
||||
# prepare input arrays and training function
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
ins = x + y + sample_weights + [1.]
|
||||
else:
|
||||
ins = x + y + sample_weights
|
||||
@@ -1134,7 +1132,7 @@ class Model(Container):
|
||||
check_batch_dim=False,
|
||||
batch_size=batch_size)
|
||||
# prepare inputs, delegate logic to _test_loop
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
ins = x + y + sample_weights + [0.]
|
||||
else:
|
||||
ins = x + y + sample_weights
|
||||
@@ -1171,7 +1169,7 @@ class Model(Container):
|
||||
'Batch size: ' + str(batch_size) + '.')
|
||||
|
||||
# prepare inputs, delegate logic to _predict_loop
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
ins = x + [0.]
|
||||
else:
|
||||
ins = x
|
||||
@@ -1215,7 +1213,7 @@ class Model(Container):
|
||||
sample_weight=sample_weight,
|
||||
class_weight=class_weight,
|
||||
check_batch_dim=True)
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
ins = x + y + sample_weights + [1.]
|
||||
else:
|
||||
ins = x + y + sample_weights
|
||||
@@ -1253,7 +1251,7 @@ class Model(Container):
|
||||
x, y, sample_weights = self._standardize_user_data(x, y,
|
||||
sample_weight=sample_weight,
|
||||
check_batch_dim=True)
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
ins = x + y + sample_weights + [0.]
|
||||
else:
|
||||
ins = x + y + sample_weights
|
||||
@@ -1268,7 +1266,7 @@ class Model(Container):
|
||||
'''
|
||||
x = standardize_input_data(x, self.input_names,
|
||||
self.internal_input_shapes)
|
||||
if self.uses_learning_phase:
|
||||
if self.uses_learning_phase and type(K.learning_phase()) is not int:
|
||||
ins = x + [0.]
|
||||
else:
|
||||
ins = x
|
||||
@@ -1314,7 +1312,7 @@ class Model(Container):
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up when using process based threading
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
this implementation relies on multiprocessing, you should not pass
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
@@ -1430,11 +1428,11 @@ class Model(Container):
|
||||
# build batch logs
|
||||
batch_logs = {}
|
||||
if type(x) is list:
|
||||
batch_size = len(x[0])
|
||||
batch_size = x[0].shape[0]
|
||||
elif type(x) is dict:
|
||||
batch_size = len(list(x.values())[0])
|
||||
batch_size = list(x.values())[0].shape[0]
|
||||
else:
|
||||
batch_size = len(x)
|
||||
batch_size = x.shape[0]
|
||||
batch_logs['batch'] = batch_index
|
||||
batch_logs['size'] = batch_size
|
||||
callbacks.on_batch_begin(batch_index, batch_logs)
|
||||
@@ -1475,6 +1473,7 @@ class Model(Container):
|
||||
# no need for try/except because
|
||||
# data has already been validated
|
||||
val_outs = self.evaluate(val_x, val_y,
|
||||
batch_size=batch_size,
|
||||
sample_weight=val_sample_weights,
|
||||
verbose=0)
|
||||
if type(val_outs) is not list:
|
||||
@@ -1508,7 +1507,7 @@ class Model(Container):
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up when using process based threading
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
this implementation relies on multiprocessing, you should not pass
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
@@ -1593,7 +1592,7 @@ class Model(Container):
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up when using process based threading
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
this implementation relies on multiprocessing, you should not pass
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
|
||||
@@ -29,13 +29,11 @@ def get_fans(shape, dim_ordering='th'):
|
||||
|
||||
|
||||
def uniform(shape, scale=0.05, name=None):
|
||||
return K.variable(np.random.uniform(low=-scale, high=scale, size=shape),
|
||||
name=name)
|
||||
return K.random_uniform_variable(shape, -scale, scale, name=name)
|
||||
|
||||
|
||||
def normal(shape, scale=0.05, name=None):
|
||||
return K.variable(np.random.normal(loc=0.0, scale=scale, size=shape),
|
||||
name=name)
|
||||
return K.random_normal_variable(shape, 0.0, scale, name=name)
|
||||
|
||||
|
||||
def lecun_uniform(shape, name=None, dim_ordering='th'):
|
||||
|
||||
@@ -112,7 +112,7 @@ class ELU(Layer):
|
||||
return pos + self.alpha * (K.exp(neg) - 1.)
|
||||
|
||||
def get_config(self):
|
||||
config = {'alpha': self.alpha}
|
||||
config = {'alpha': float(self.alpha)}
|
||||
base_config = super(ELU, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -161,8 +161,8 @@ class ParametricSoftplus(Layer):
|
||||
return K.softplus(self.betas * x) * self.alphas
|
||||
|
||||
def get_config(self):
|
||||
config = {'alpha_init': self.alpha_init,
|
||||
'beta_init': self.beta_init}
|
||||
config = {'alpha_init': float(self.alpha_init),
|
||||
'beta_init': float(self.beta_init)}
|
||||
base_config = super(ParametricSoftplus, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -195,7 +195,7 @@ class ThresholdedReLU(Layer):
|
||||
return x * K.cast(x > self.theta, K.floatx())
|
||||
|
||||
def get_config(self):
|
||||
config = {'theta': self.theta}
|
||||
config = {'theta': float(self.theta)}
|
||||
base_config = super(ThresholdedReLU, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
+542
-40
@@ -4,7 +4,7 @@ from __future__ import absolute_import
|
||||
from .. import backend as K
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..engine import Layer, InputSpec
|
||||
from ..utils.np_utils import conv_output_length
|
||||
from ..utils.np_utils import conv_output_length, conv_input_length
|
||||
|
||||
# imports for backwards namespace compatibility
|
||||
from .pooling import AveragePooling1D, AveragePooling2D, AveragePooling3D
|
||||
@@ -113,7 +113,7 @@ class Convolution1D(Layer):
|
||||
|
||||
def build(self, input_shape):
|
||||
input_dim = input_shape[2]
|
||||
self.W_shape = (self.nb_filter, input_dim, self.filter_length, 1)
|
||||
self.W_shape = (self.filter_length, 1, input_dim, self.nb_filter)
|
||||
self.W = self.init(self.W_shape, name='{}_W'.format(self.name))
|
||||
if self.bias:
|
||||
self.b = K.zeros((self.nb_filter,), name='{}_b'.format(self.name))
|
||||
@@ -152,15 +152,13 @@ class Convolution1D(Layer):
|
||||
return (input_shape[0], length, self.nb_filter)
|
||||
|
||||
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))
|
||||
x = K.expand_dims(x, 2) # add a dummy dimension
|
||||
output = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='th')
|
||||
dim_ordering='tf')
|
||||
output = K.squeeze(output, 2) # remove the dummy dimension
|
||||
if self.bias:
|
||||
output += K.reshape(self.b, (1, self.nb_filter, 1, 1))
|
||||
output = K.squeeze(output, 3) # remove the dummy 3rd dimension
|
||||
output = K.permute_dimensions(output, (0, 2, 1))
|
||||
output += K.reshape(self.b, (1, 1, self.nb_filter))
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
@@ -183,6 +181,121 @@ class Convolution1D(Layer):
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class AtrousConvolution1D(Convolution1D):
|
||||
'''Atrous Convolution operator for filtering neighborhoods of one-dimensional inputs.
|
||||
A.k.a dilated convolution or convolution with holes.
|
||||
When using this layer as the first layer in a model,
|
||||
either provide the keyword argument `input_dim`
|
||||
(int, e.g. 128 for sequences of 128-dimensional vectors),
|
||||
or `input_shape` (tuples of integers, e.g. (10, 128) for sequences
|
||||
of 10 vectors of 128-dimensional vectors).
|
||||
|
||||
# Example
|
||||
|
||||
```python
|
||||
# apply an atrous convolution 1d with atrous rate 2 of length 3 to a sequence with 10 timesteps,
|
||||
# with 64 output filters
|
||||
model = Sequential()
|
||||
model.add(AtrousConvolution1D(64, 3, atrous_rate=2, border_mode='same', input_shape=(10, 32)))
|
||||
# now model.output_shape == (None, 10, 64)
|
||||
|
||||
# add a new atrous conv1d on top
|
||||
model.add(AtrousConvolution1D(32, 3, atrous_rate=2, border_mode='same'))
|
||||
# now model.output_shape == (None, 10, 32)
|
||||
```
|
||||
|
||||
# Arguments
|
||||
nb_filter: Number of convolution kernels to use
|
||||
(dimensionality of the output).
|
||||
filter_length: The extension (spatial or temporal) of each filter.
|
||||
init: name of initialization function for the weights of the layer
|
||||
(see [initializations](../initializations.md)),
|
||||
or alternatively, Theano function to use for weights initialization.
|
||||
This parameter is only relevant if you don't pass a `weights` argument.
|
||||
activation: name of activation function to use
|
||||
(see [activations](../activations.md)),
|
||||
or alternatively, elementwise Theano function.
|
||||
If you don't specify anything, no activation is applied
|
||||
(ie. "linear" activation: a(x) = x).
|
||||
weights: list of numpy arrays to set as initial weights.
|
||||
border_mode: 'valid' or 'same'.
|
||||
subsample_length: factor by which to subsample output.
|
||||
atrous_rate: Factor for kernel dilation. Also called filter_dilation
|
||||
elsewhere.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the main weights matrix.
|
||||
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
|
||||
applied to the bias.
|
||||
activity_regularizer: instance of [ActivityRegularizer](../regularizers.md),
|
||||
applied to the network output.
|
||||
W_constraint: instance of the [constraints](../constraints.md) module
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
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.
|
||||
input_length: Length of input sequences, when it is constant.
|
||||
This argument is required if you are going to connect
|
||||
`Flatten` then `Dense` layers upstream
|
||||
(without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, input_dim)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape: `(samples, new_steps, nb_filter)`.
|
||||
`steps` value might have changed due to padding.
|
||||
'''
|
||||
def __init__(self, nb_filter, filter_length,
|
||||
init='uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample_length=1, atrous_rate=1,
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for AtrousConv1D:', border_mode)
|
||||
|
||||
self.atrous_rate = int(atrous_rate)
|
||||
|
||||
super(AtrousConvolution1D, self).__init__(nb_filter, filter_length,
|
||||
init=init, activation=activation,
|
||||
weights=weights, border_mode=border_mode,
|
||||
subsample_length=subsample_length,
|
||||
W_regularizer=W_regularizer, b_regularizer=b_regularizer,
|
||||
activity_regularizer=activity_regularizer,
|
||||
W_constraint=W_constraint, b_constraint=b_constraint,
|
||||
bias=bias, **kwargs)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
length = conv_output_length(input_shape[1],
|
||||
self.filter_length,
|
||||
self.border_mode,
|
||||
self.subsample[0],
|
||||
dilation=self.atrous_rate)
|
||||
return (input_shape[0], length, self.nb_filter)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
x = K.expand_dims(x, 2) # add a dummy dimension
|
||||
output = K.conv2d(x, self.W, strides=self.subsample,
|
||||
border_mode=self.border_mode,
|
||||
dim_ordering='tf',
|
||||
filter_dilation=(self.atrous_rate, self.atrous_rate))
|
||||
output = K.squeeze(output, 2) # remove the dummy dimension
|
||||
if self.bias:
|
||||
output += K.reshape(self.b, (1, 1, self.nb_filter))
|
||||
output = self.activation(output)
|
||||
return output
|
||||
|
||||
def get_config(self):
|
||||
config = {'atrous_rate': self.atrous_rate}
|
||||
base_config = super(AtrousConvolution1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Convolution2D(Layer):
|
||||
'''Convolution operator for filtering windows of two-dimensional inputs.
|
||||
When using this layer as the first layer in a model,
|
||||
@@ -254,11 +367,12 @@ 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=K.image_dim_ordering(),
|
||||
border_mode='valid', subsample=(1, 1), dim_ordering='default',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution2D:', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
@@ -379,6 +493,165 @@ class Convolution2D(Layer):
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class Deconvolution2D(Convolution2D):
|
||||
'''Transposed convolution operator for filtering windows of two-dimensional inputs.
|
||||
The need for transposed convolutions generally arises from the desire
|
||||
to use a transformation going in the opposite direction of a normal convolution,
|
||||
i.e., from something that has the shape of the output of some convolution
|
||||
to something that has the shape of its input
|
||||
while maintaining a connectivity pattern that is compatible with said convolution. [1]
|
||||
|
||||
When using this layer as the first layer in a model,
|
||||
provide the keyword argument `input_shape`
|
||||
(tuple of integers, does not include the sample axis),
|
||||
e.g. `input_shape=(3, 128, 128)` for 128x128 RGB pictures.
|
||||
|
||||
# Examples
|
||||
|
||||
```python
|
||||
# apply a 3x3 transposed convolution with stride 1x1 and 3 output filters on a 12x12 image:
|
||||
model = Sequential()
|
||||
model.add(Deconvolution2D(3, 3, 3, output_shape=(None, 3, 14, 14), border_mode='valid', input_shape=(3, 12, 12)))
|
||||
# output_shape will be (None, 3, 14, 14)
|
||||
|
||||
# apply a 3x3 transposed convolution with stride 2x2 and 3 output filters on a 12x12 image:
|
||||
model = Sequential()
|
||||
model.add(Deconvolution2D(3, 3, 3, output_shape=(None, 3, 25, 25), subsample=(2, 2), border_mode='valid', input_shape=(3, 12, 12)))
|
||||
model.summary()
|
||||
# output_shape will be (None, 3, 25, 25)
|
||||
```
|
||||
|
||||
# Arguments
|
||||
nb_filter: Number of transposed convolution filters to use.
|
||||
nb_row: Number of rows in the transposed convolution kernel.
|
||||
nb_col: Number of columns in the transposed convolution kernel.
|
||||
output_shape: Output shape of the transposed convolution operation.
|
||||
tuple of integers (nb_samples, nb_filter, nb_output_rows, nb_output_cols)
|
||||
Formula for calculation of the output shape [1], [2]:
|
||||
o = s (i - 1) + a + k - 2p, \quad a \in \{0, \ldots, s - 1\}
|
||||
where:
|
||||
i - input size (rows or cols),
|
||||
k - kernel size (nb_filter),
|
||||
s - stride (subsample for rows or cols respectively),
|
||||
p - padding size,
|
||||
a - user-specified quantity used to distinguish between
|
||||
the s different possible output sizes.
|
||||
init: name of initialization function for the weights of the layer
|
||||
(see [initializations](../initializations.md)), or alternatively,
|
||||
Theano function to use for weights initialization.
|
||||
This parameter is only relevant if you don't pass
|
||||
a `weights` argument.
|
||||
activation: name of activation function to use
|
||||
(see [activations](../activations.md)),
|
||||
or alternatively, elementwise Theano/TensorFlow function.
|
||||
If you don't specify anything, no activation is applied
|
||||
(ie. "linear" activation: a(x) = x).
|
||||
weights: list of numpy arrays to set as initial weights.
|
||||
border_mode: 'valid' or 'same'.
|
||||
subsample: tuple of length 2. Factor by which to oversample output.
|
||||
Also called strides elsewhere.
|
||||
W_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the main weights matrix.
|
||||
b_regularizer: instance of [WeightRegularizer](../regularizers.md),
|
||||
applied to the bias.
|
||||
activity_regularizer: instance of [ActivityRegularizer](../regularizers.md),
|
||||
applied to the network output.
|
||||
W_constraint: instance of the [constraints](../constraints.md) module
|
||||
(eg. maxnorm, nonneg), applied to the main weights matrix.
|
||||
b_constraint: instance of the [constraints](../constraints.md) module,
|
||||
applied to the bias.
|
||||
dim_ordering: 'th' or 'tf'. In 'th' mode, the channels dimension
|
||||
(the depth) is at index 1, in 'tf' mode is it at index 3.
|
||||
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:
|
||||
`(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
4D tensor with shape:
|
||||
`(samples, nb_filter, new_rows, new_cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, new_rows, new_cols, nb_filter)` if dim_ordering='tf'.
|
||||
`rows` and `cols` values might have changed due to padding.
|
||||
|
||||
# References
|
||||
[1] [A guide to convolution arithmetic for deep learning](https://arxiv.org/abs/1603.07285 "arXiv:1603.07285v1 [stat.ML]")
|
||||
[2] [Transposed convolution arithmetic](http://deeplearning.net/software/theano_versions/dev/tutorial/conv_arithmetic.html#transposed-convolution-arithmetic)
|
||||
[3] [Deconvolutional Networks](http://www.matthewzeiler.com/pubs/cvpr2010/cvpr2010.pdf)
|
||||
'''
|
||||
def __init__(self, nb_filter, nb_row, nb_col, output_shape,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
dim_ordering='default',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Deconvolution2D:', border_mode)
|
||||
|
||||
self.output_shape_ = output_shape
|
||||
|
||||
super(Deconvolution2D, self).__init__(nb_filter, nb_row, nb_col,
|
||||
init=init, activation=activation,
|
||||
weights=weights, border_mode=border_mode,
|
||||
subsample=subsample, dim_ordering=dim_ordering,
|
||||
W_regularizer=W_regularizer, b_regularizer=b_regularizer,
|
||||
activity_regularizer=activity_regularizer,
|
||||
W_constraint=W_constraint, b_constraint=b_constraint,
|
||||
bias=bias, **kwargs)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
rows = input_shape[2]
|
||||
cols = input_shape[3]
|
||||
elif self.dim_ordering == 'tf':
|
||||
rows = input_shape[1]
|
||||
cols = input_shape[2]
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
rows = conv_input_length(rows, self.nb_row,
|
||||
self.border_mode, self.subsample[0])
|
||||
cols = conv_input_length(cols, self.nb_col,
|
||||
self.border_mode, self.subsample[1])
|
||||
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0], self.nb_filter, rows, cols)
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0], rows, cols, self.nb_filter)
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
output = K.deconv2d(x, self.W, self.output_shape_,
|
||||
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
|
||||
|
||||
def get_config(self):
|
||||
config = {'output_shape': self.output_shape}
|
||||
base_config = super(Deconvolution2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class AtrousConvolution2D(Convolution2D):
|
||||
'''Atrous Convolution operator for filtering windows of two-dimensional inputs.
|
||||
A.k.a dilated convolution or convolution with holes.
|
||||
@@ -453,10 +726,12 @@ class AtrousConvolution2D(Convolution2D):
|
||||
def __init__(self, nb_filter, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
atrous_rate=(1, 1), dim_ordering=K.image_dim_ordering(),
|
||||
atrous_rate=(1, 1), dim_ordering='default',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for AtrousConv2D:', border_mode)
|
||||
@@ -535,6 +810,11 @@ class SeparableConvolution2D(Layer):
|
||||
(tuple of integers, does not include the sample axis),
|
||||
e.g. `input_shape=(3, 128, 128)` for 128x128 RGB pictures.
|
||||
|
||||
# Theano warning
|
||||
|
||||
This layer is only available with the
|
||||
TensorFlow backend for the time being.
|
||||
|
||||
# Arguments
|
||||
nb_filter: Number of convolution filters to use.
|
||||
nb_row: Number of rows in the convolution kernel.
|
||||
@@ -555,8 +835,6 @@ class SeparableConvolution2D(Layer):
|
||||
Also called strides elsewhere.
|
||||
depth_multiplier: how many output channel to use per input channel
|
||||
for the depthwise convolution step.
|
||||
atrous_rate: tuple of length 2. Factor for kernel dilation.
|
||||
Also called filter_dilation elsewhere.
|
||||
depthwise_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the depthwise weights matrix.
|
||||
pointwise_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
@@ -595,7 +873,7 @@ class SeparableConvolution2D(Layer):
|
||||
def __init__(self, nb_filter, nb_row, nb_col,
|
||||
init='glorot_uniform', activation='linear', weights=None,
|
||||
border_mode='valid', subsample=(1, 1),
|
||||
depth_multiplier=1, dim_ordering=K.image_dim_ordering(),
|
||||
depth_multiplier=1, dim_ordering='default',
|
||||
depthwise_regularizer=None, pointwise_regularizer=None,
|
||||
b_regularizer=None, activity_regularizer=None,
|
||||
depthwise_constraint=None, pointwise_constraint=None,
|
||||
@@ -606,6 +884,9 @@ class SeparableConvolution2D(Layer):
|
||||
raise Exception('SeparableConv2D is only available '
|
||||
'with TensorFlow for the time being.')
|
||||
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for SeparableConv2D:', border_mode)
|
||||
|
||||
@@ -806,10 +1087,13 @@ 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=K.image_dim_ordering(),
|
||||
border_mode='valid', subsample=(1, 1, 1), dim_ordering='default',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
if border_mode not in {'valid', 'same'}:
|
||||
raise Exception('Invalid border mode for Convolution3D:', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
@@ -963,7 +1247,8 @@ class UpSampling1D(Layer):
|
||||
super(UpSampling1D, self).__init__(**kwargs)
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
return (input_shape[0], self.length * input_shape[1], input_shape[2])
|
||||
length = self.length * input_shape[1] if input_shape[1] is not None else None
|
||||
return (input_shape[0], length, input_shape[2])
|
||||
|
||||
def call(self, x, mask=None):
|
||||
output = K.repeat_elements(x, self.length, axis=1)
|
||||
@@ -1001,7 +1286,9 @@ class UpSampling2D(Layer):
|
||||
`(samples, upsampled_rows, upsampled_cols, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
def __init__(self, size=(2, 2), dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
def __init__(self, size=(2, 2), dim_ordering='default', **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.size = tuple(size)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
@@ -1010,14 +1297,18 @@ class UpSampling2D(Layer):
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
width = self.size[0] * input_shape[2] if input_shape[2] is not None else None
|
||||
height = self.size[1] * input_shape[3] if input_shape[3] is not None else None
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
self.size[0] * input_shape[2],
|
||||
self.size[1] * input_shape[3])
|
||||
width,
|
||||
height)
|
||||
elif self.dim_ordering == 'tf':
|
||||
width = self.size[0] * input_shape[1] if input_shape[1] is not None else None
|
||||
height = self.size[1] * input_shape[2] if input_shape[2] is not None else None
|
||||
return (input_shape[0],
|
||||
self.size[0] * input_shape[1],
|
||||
self.size[1] * input_shape[2],
|
||||
width,
|
||||
height,
|
||||
input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
@@ -1036,8 +1327,6 @@ class UpSampling3D(Layer):
|
||||
'''Repeat the first, second and third dimension of the data
|
||||
by size[0], size[1] and size[2] respectively.
|
||||
|
||||
Note: this layer will only work with Theano for the time being.
|
||||
|
||||
# Arguments
|
||||
size: tuple of 3 integers. The upsampling factors for dim1, dim2 and dim3.
|
||||
dim_ordering: 'th' or 'tf'.
|
||||
@@ -1060,10 +1349,9 @@ class UpSampling3D(Layer):
|
||||
`(samples, upsampled_dim1, upsampled_dim2, upsampled_dim3, channels)` if dim_ordering='tf'.
|
||||
'''
|
||||
|
||||
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.')
|
||||
def __init__(self, size=(2, 2, 2), dim_ordering='default', **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.size = tuple(size)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
@@ -1072,16 +1360,22 @@ class UpSampling3D(Layer):
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
dim1 = self.size[0] * input_shape[2] if input_shape[2] is not None else None
|
||||
dim2 = self.size[1] * input_shape[3] if input_shape[3] is not None else None
|
||||
dim3 = self.size[2] * input_shape[4] if input_shape[4] is not None else None
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
self.size[0] * input_shape[2],
|
||||
self.size[1] * input_shape[3],
|
||||
self.size[2] * input_shape[4])
|
||||
dim1,
|
||||
dim2,
|
||||
dim3)
|
||||
elif self.dim_ordering == 'tf':
|
||||
dim1 = self.size[0] * input_shape[1] if input_shape[1] is not None else None
|
||||
dim2 = self.size[1] * input_shape[2] if input_shape[2] is not None else None
|
||||
dim3 = self.size[2] * input_shape[3] if input_shape[3] is not None else None
|
||||
return (input_shape[0],
|
||||
self.size[0] * input_shape[1],
|
||||
self.size[1] * input_shape[2],
|
||||
self.size[2] * input_shape[3],
|
||||
dim1,
|
||||
dim2,
|
||||
dim3,
|
||||
input_shape[4])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
@@ -1154,8 +1448,10 @@ class ZeroPadding2D(Layer):
|
||||
(samples, depth, first_padded_axis, second_padded_axis)
|
||||
'''
|
||||
|
||||
def __init__(self, padding=(1, 1), dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
def __init__(self, padding=(1, 1), dim_ordering='default', **kwargs):
|
||||
super(ZeroPadding2D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.padding = tuple(padding)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
@@ -1192,8 +1488,6 @@ class ZeroPadding2D(Layer):
|
||||
class ZeroPadding3D(Layer):
|
||||
'''Zero-padding layer for 3D data (spatial or spatio-temporal).
|
||||
|
||||
Note: this layer will only work with Theano for the time being.
|
||||
|
||||
# Arguments
|
||||
padding: tuple of int (length 3)
|
||||
How many zeros to add at the beginning and end of
|
||||
@@ -1214,11 +1508,10 @@ class ZeroPadding3D(Layer):
|
||||
(samples, depth, first_padded_axis, second_padded_axis, third_axis_to_pad)
|
||||
'''
|
||||
|
||||
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.')
|
||||
def __init__(self, padding=(1, 1, 1), dim_ordering='default', **kwargs):
|
||||
super(ZeroPadding3D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.padding = tuple(padding)
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
@@ -1255,11 +1548,220 @@ class ZeroPadding3D(Layer):
|
||||
base_config = super(ZeroPadding3D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
class Cropping1D(Layer):
|
||||
'''Cropping layer for 1D input (e.g. temporal sequence).
|
||||
It crops along the time dimension (axis 1).
|
||||
|
||||
# Arguments
|
||||
cropping: tuple of int (length 2)
|
||||
How many units should be trimmed off at the beginning and end of
|
||||
the cropping dimension (axis 1).
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape (samples, axis_to_crop, features)
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape (samples, cropped_axis, features)
|
||||
'''
|
||||
|
||||
def __init__(self, cropping=(1, 1), **kwargs):
|
||||
super(Cropping1D, self).__init__(**kwargs)
|
||||
self.cropping = tuple(cropping)
|
||||
assert len(self.cropping) == 2, 'cropping must be a tuple length of 2'
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
length = input_shape[1] - self.cropping[0] - self.cropping[1] if input_shape[1] is not None else None
|
||||
return (input_shape[0],
|
||||
length,
|
||||
input_shape[2])
|
||||
|
||||
def call(self, x, mask=None):
|
||||
input_shape = self.input_spec[0].shape
|
||||
return x[:, self.cropping[0]:input_shape[1]-self.cropping[1], :]
|
||||
|
||||
def get_config(self):
|
||||
config = {'cropping': self.cropping}
|
||||
base_config = super(Cropping1D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
class Cropping2D(Layer):
|
||||
'''Cropping layer for 2D input (e.g. picture).
|
||||
It crops along spatial dimensions, i.e. width and height.
|
||||
|
||||
# Arguments
|
||||
cropping: tuple of tuple of int (length 2)
|
||||
How many units should be trimmed off at the beginning and end of
|
||||
the 2 cropping dimensions (width, height).
|
||||
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:
|
||||
(samples, depth, first_axis_to_crop, second_axis_to_crop)
|
||||
|
||||
# Output shape
|
||||
4D tensor with shape:
|
||||
(samples, depth, first_cropped_axis, second_cropped_axis)
|
||||
|
||||
# Examples
|
||||
|
||||
```python
|
||||
# Crop the input 2D images or feature maps
|
||||
model = Sequential()
|
||||
model.add(Cropping2D(cropping=((2, 2), (4, 4)), input_shape=(3, 28, 28)))
|
||||
# now model.output_shape == (None, 3, 24, 20)
|
||||
model.add(Convolution2D(64, 3, 3, border_mode='same))
|
||||
model.add(Cropping2D(cropping=((2, 2), (2, 2))))
|
||||
# now model.output_shape == (None, 64, 20, 16)
|
||||
|
||||
```
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, cropping=((0, 0), (0, 0)), dim_ordering='default', **kwargs):
|
||||
super(Cropping2D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.cropping = tuple(cropping)
|
||||
assert len(self.cropping) == 2, 'cropping must be a tuple length of 2'
|
||||
assert len(self.cropping[0]) == 2, 'cropping[0] must be a tuple length of 2'
|
||||
assert len(self.cropping[1]) == 2, 'cropping[1] must be a tuple length of 2'
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
self.input_spec = [InputSpec(ndim=4)]
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
input_shape[2] - self.cropping[0][0] - self.cropping[0][1],
|
||||
input_shape[3] - self.cropping[1][0] - self.cropping[1][1])
|
||||
elif self.dim_ordering == 'tf':
|
||||
return (input_shape[0],
|
||||
input_shape[1] - self.cropping[0][0] - self.cropping[0][1],
|
||||
input_shape[2] - self.cropping[1][0] - self.cropping[1][1],
|
||||
input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
input_shape = self.input_spec[0].shape
|
||||
if self.dim_ordering == 'th':
|
||||
return x[:,
|
||||
:,
|
||||
self.cropping[0][0]:input_shape[2]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[3]-self.cropping[1][1]]
|
||||
elif self.dim_ordering == 'tf':
|
||||
return x[:,
|
||||
self.cropping[0][0]:input_shape[1]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[2]-self.cropping[1][1],
|
||||
:]
|
||||
|
||||
def get_config(self):
|
||||
config = {'cropping': self.cropping}
|
||||
base_config = super(Cropping2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
class Cropping3D(Layer):
|
||||
'''Cropping layer for 2D input (e.g. picture).
|
||||
|
||||
# Arguments
|
||||
cropping: tuple of tuple of int (length 3)
|
||||
How many units should be trimmed off at the beginning and end of
|
||||
the 3 cropping dimensions (kernel_dim1, kernel_dim2, kernerl_dim3).
|
||||
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:
|
||||
(samples, depth, first_axis_to_crop, second_axis_to_crop, third_axis_to_crop)
|
||||
|
||||
# Output shape
|
||||
5D tensor with shape:
|
||||
(samples, depth, first_cropped_axis, second_cropped_axis, third_cropped_axis)
|
||||
|
||||
'''
|
||||
|
||||
def __init__(self, cropping=((1, 1), (1, 1), (1, 1)), dim_ordering='default', **kwargs):
|
||||
super(Cropping3D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.cropping = tuple(cropping)
|
||||
assert len(self.cropping) == 3, 'cropping must be a tuple length of 3'
|
||||
assert len(self.cropping[0]) == 2, 'cropping[0] must be a tuple length of 2'
|
||||
assert len(self.cropping[1]) == 2, 'cropping[1] must be a tuple length of 2'
|
||||
assert len(self.cropping[2]) == 2, 'cropping[2] must be a tuple length of 2'
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
self.input_spec = [InputSpec(ndim=5)]
|
||||
|
||||
def build(self, input_shape):
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'th':
|
||||
dim1 = input_shape[2] - self.cropping[0][0] - self.cropping[0][1] if input_shape[2] is not None else None
|
||||
dim2 = input_shape[3] - self.cropping[1][0] - self.cropping[1][1] if input_shape[3] is not None else None
|
||||
dim3 = input_shape[4] - self.cropping[2][0] - self.cropping[2][1] if input_shape[4] is not None else None
|
||||
return (input_shape[0],
|
||||
input_shape[1],
|
||||
dim1,
|
||||
dim2,
|
||||
dim3)
|
||||
elif self.dim_ordering == 'tf':
|
||||
dim1 = input_shape[1] - self.cropping[0][0] - self.cropping[0][1] if input_shape[1] is not None else None
|
||||
dim2 = input_shape[2] - self.cropping[1][0] - self.cropping[1][1] if input_shape[2] is not None else None
|
||||
dim3 = input_shape[3] - self.cropping[2][0] - self.cropping[2][1] if input_shape[3] is not None else None
|
||||
return (input_shape[0],
|
||||
dim1,
|
||||
dim2,
|
||||
dim3,
|
||||
input_shape[4])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
input_shape = self.input_spec[0].shape
|
||||
if self.dim_ordering == 'th':
|
||||
return x[:,
|
||||
:,
|
||||
self.cropping[0][0]:input_shape[2]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[3]-self.cropping[1][1],
|
||||
self.cropping[2][0]:input_shape[4]-self.cropping[2][1]]
|
||||
elif self.dim_ordering == 'tf':
|
||||
return x[:,
|
||||
self.cropping[0][0]:input_shape[1]-self.cropping[0][1],
|
||||
self.cropping[1][0]:input_shape[2]-self.cropping[1][1],
|
||||
self.cropping[2][0]:input_shape[3]-self.cropping[2][1],
|
||||
:]
|
||||
|
||||
def get_config(self):
|
||||
config = {'cropping': self.cropping}
|
||||
base_config = super(Cropping3D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
# Aliases
|
||||
|
||||
Conv1D = Convolution1D
|
||||
Conv2D = Convolution2D
|
||||
Conv3D = Convolution3D
|
||||
Deconv2D = Deconvolution2D
|
||||
AtrousConv1D = AtrousConvolution1D
|
||||
AtrousConv2D = AtrousConvolution2D
|
||||
SeparableConv2D = SeparableConvolution2D
|
||||
|
||||
+113
-22
@@ -7,14 +7,13 @@ import numpy as np
|
||||
import copy
|
||||
import inspect
|
||||
import types as python_types
|
||||
import marshal
|
||||
import sys
|
||||
import warnings
|
||||
|
||||
from .. import backend as K
|
||||
from .. import activations, initializations, regularizers, constraints
|
||||
from ..engine import InputSpec, Layer, Merge
|
||||
from ..regularizers import ActivityRegularizer
|
||||
from ..utils.generic_utils import func_dump, func_load
|
||||
|
||||
|
||||
class Masking(Layer):
|
||||
@@ -82,9 +81,13 @@ class Dropout(Layer):
|
||||
self.supports_masking = True
|
||||
super(Dropout, self).__init__(**kwargs)
|
||||
|
||||
def _get_noise_shape(self, x):
|
||||
return None
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if 0. < self.p < 1.:
|
||||
x = K.in_train_phase(K.dropout(x, level=self.p), x)
|
||||
noise_shape = self._get_noise_shape(x)
|
||||
x = K.in_train_phase(K.dropout(x, self.p, noise_shape), x)
|
||||
return x
|
||||
|
||||
def get_config(self):
|
||||
@@ -93,6 +96,101 @@ class Dropout(Layer):
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class SpatialDropout2D(Dropout):
|
||||
'''This version performs the same function as Dropout, however it drops
|
||||
entire 2D feature maps instead of individual elements. If adjacent pixels
|
||||
within feature maps are strongly correlated (as is normally the case in
|
||||
early convolution layers) then regular dropout will not regularize the
|
||||
activations and will otherwise just result in an effective learning rate
|
||||
decrease. In this case, SpatialDropout2D will help promote independence
|
||||
between feature maps and should be used instead.
|
||||
|
||||
# Arguments
|
||||
p: float between 0 and 1. Fraction of the input units to drop.
|
||||
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:
|
||||
`(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
Same as input
|
||||
|
||||
# References
|
||||
- [Efficient Object Localization Using Convolutional Networks](https://arxiv.org/pdf/1411.4280.pdf)
|
||||
'''
|
||||
def __init__(self, p, dim_ordering='default', **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
super(SpatialDropout2D, self).__init__(p, **kwargs)
|
||||
|
||||
def _get_noise_shape(self, x):
|
||||
input_shape = K.shape(x)
|
||||
if self.dim_ordering == 'th':
|
||||
noise_shape = (input_shape[0], input_shape[1], 1, 1)
|
||||
elif self.dim_ordering == 'tf':
|
||||
noise_shape = (input_shape[0], 1, 1, input_shape[3])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
return noise_shape
|
||||
|
||||
|
||||
class SpatialDropout3D(Dropout):
|
||||
'''This version performs the same function as Dropout, however it drops
|
||||
entire 3D feature maps instead of individual elements. If adjacent voxels
|
||||
within feature maps are strongly correlated (as is normally the case in
|
||||
early convolution layers) then regular dropout will not regularize the
|
||||
activations and will otherwise just result in an effective learning rate
|
||||
decrease. In this case, SpatialDropout3D will help promote independence
|
||||
between feature maps and should be used instead.
|
||||
|
||||
# Arguments
|
||||
p: float between 0 and 1. Fraction of the input units to drop.
|
||||
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:
|
||||
`(samples, channels, dim1, dim2, dim3)` if dim_ordering='th'
|
||||
or 5D tensor with shape:
|
||||
`(samples, dim1, dim2, dim3, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
Same as input
|
||||
|
||||
# References
|
||||
- [Efficient Object Localization Using Convolutional Networks](https://arxiv.org/pdf/1411.4280.pdf)
|
||||
'''
|
||||
def __init__(self, p, dim_ordering='default', **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
assert dim_ordering in {'tf', 'th'}, 'dim_ordering must be in {tf, th}'
|
||||
self.dim_ordering = dim_ordering
|
||||
super(SpatialDropout3D, self).__init__(p, **kwargs)
|
||||
|
||||
def _get_noise_shape(self, x):
|
||||
input_shape = K.shape(x)
|
||||
if self.dim_ordering == 'th':
|
||||
noise_shape = (input_shape[0], input_shape[1], 1, 1, 1)
|
||||
elif self.dim_ordering == 'tf':
|
||||
noise_shape = (input_shape[0], 1, 1, 1, input_shape[4])
|
||||
else:
|
||||
raise Exception('Invalid dim_ordering: ' + self.dim_ordering)
|
||||
return noise_shape
|
||||
|
||||
|
||||
class Activation(Layer):
|
||||
'''Applies an activation function to an output.
|
||||
|
||||
@@ -385,16 +483,16 @@ class Lambda(Layer):
|
||||
|
||||
# Arguments
|
||||
function: The function to be evaluated.
|
||||
Takes one argument: the output of previous layer
|
||||
Takes input tensor as first argument.
|
||||
output_shape: Expected output shape from function.
|
||||
Can be a tuple or function.
|
||||
If a tuple, it only specifies the first dimension onward;
|
||||
If a tuple, it only specifies the first dimension onward;
|
||||
sample dimension is assumed either the same as the input:
|
||||
`output_shape = (input_shape[0], ) + output_shape`
|
||||
or, the input is `None` and the sample dimension is also `None`:
|
||||
`output_shape = (None, ) + output_shape`
|
||||
If a function, it specifies the entire shape as a function of
|
||||
the input shape: `output_shape = f(input_shape)`
|
||||
If a function, it specifies the entire shape as a function of the
|
||||
input shape: `output_shape = f(input_shape)`
|
||||
arguments: optional dictionary of keyword arguments to be passed
|
||||
to the function.
|
||||
|
||||
@@ -439,7 +537,10 @@ class Lambda(Layer):
|
||||
# otherwise, we default to the input shape
|
||||
return input_shape
|
||||
elif type(self._output_shape) in {tuple, list}:
|
||||
nb_samples = input_shape[0] if input_shape else None
|
||||
if type(input_shape) is list:
|
||||
nb_samples = input_shape[0][0]
|
||||
else:
|
||||
nb_samples = input_shape[0] if input_shape else None
|
||||
return (nb_samples,) + tuple(self._output_shape)
|
||||
else:
|
||||
shape = self._output_shape(input_shape)
|
||||
@@ -455,23 +556,15 @@ class Lambda(Layer):
|
||||
return self.function(x, **arguments)
|
||||
|
||||
def get_config(self):
|
||||
py3 = sys.version_info[0] == 3
|
||||
|
||||
if isinstance(self.function, python_types.LambdaType):
|
||||
if py3:
|
||||
function = marshal.dumps(self.function.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
function = marshal.dumps(self.function.func_code).decode('raw_unicode_escape')
|
||||
function = func_dump(self.function)
|
||||
function_type = 'lambda'
|
||||
else:
|
||||
function = self.function.__name__
|
||||
function_type = 'function'
|
||||
|
||||
if isinstance(self._output_shape, python_types.LambdaType):
|
||||
if py3:
|
||||
output_shape = marshal.dumps(self._output_shape.__code__).decode('raw_unicode_escape')
|
||||
else:
|
||||
output_shape = marshal.dumps(self._output_shape.func_code).decode('raw_unicode_escape')
|
||||
output_shape = func_dump(self._output_shape)
|
||||
output_shape_type = 'lambda'
|
||||
elif callable(self._output_shape):
|
||||
output_shape = self._output_shape.__name__
|
||||
@@ -494,8 +587,7 @@ class Lambda(Layer):
|
||||
if function_type == 'function':
|
||||
function = globals()[config['function']]
|
||||
elif function_type == 'lambda':
|
||||
function = marshal.loads(config['function'].encode('raw_unicode_escape'))
|
||||
function = python_types.FunctionType(function, globals())
|
||||
function = func_load(config['function'], globs=globals())
|
||||
else:
|
||||
raise Exception('Unknown function type: ' + function_type)
|
||||
|
||||
@@ -503,8 +595,7 @@ class Lambda(Layer):
|
||||
if output_shape_type == 'function':
|
||||
output_shape = globals()[config['output_shape']]
|
||||
elif output_shape_type == 'lambda':
|
||||
output_shape = marshal.loads(config['output_shape'].encode('raw_unicode_escape'))
|
||||
output_shape = python_types.FunctionType(output_shape, globals())
|
||||
output_shape = func_load(config['output_shape'], globs=globals())
|
||||
else:
|
||||
output_shape = config['output_shape']
|
||||
|
||||
|
||||
@@ -125,6 +125,8 @@ class Embedding(Layer):
|
||||
return (input_shape[0], input_length, self.output_dim)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if K.dtype(x) != 'int32':
|
||||
x = K.cast(x, 'int32')
|
||||
if 0. < self.dropout < 1.:
|
||||
retain_p = 1. - self.dropout
|
||||
B = K.random_binomial((self.input_dim,), p=retain_p) * (1. / retain_p)
|
||||
|
||||
+26
-16
@@ -8,14 +8,17 @@ from ..utils.np_utils import conv_output_length
|
||||
|
||||
|
||||
class LocallyConnected1D(Layer):
|
||||
'''LocallyConnected1D layer works almost the same as Convolution1D layer,
|
||||
except that weights are unshared, that is, a different set of filters is
|
||||
applied at each different patch of the input. When using this layer as the
|
||||
first layer in a model, either provide the keyword argument `input_dim`
|
||||
'''The `LocallyConnected1D` layer works similarly to
|
||||
the `Convolution1D` layer, except that weights are unshared,
|
||||
that is, a different set of filters is applied at each different patch
|
||||
of the input.
|
||||
When using this layer as the first layer in a model,
|
||||
either provide the keyword argument `input_dim`
|
||||
(int, e.g. 128 for sequences of 128-dimensional vectors), or `input_shape`
|
||||
(tuple of integers, e.g. (10, 128) for sequences of 10 vectors of
|
||||
128-dimensional vectors). Also, you will need to fix shape of the previous
|
||||
layer, since the weights can only be defined with determined output shape.
|
||||
(tuple of integers, e.g. `input_shape=(10, 128)`
|
||||
for sequences of 10 vectors of 128-dimensional vectors).
|
||||
Also, note that this layer can only be used with
|
||||
a fully-specified input shape (`None` dimensions not allowed).
|
||||
|
||||
# Example
|
||||
```python
|
||||
@@ -28,6 +31,7 @@ class LocallyConnected1D(Layer):
|
||||
model.add(LocallyConnected1D(32, 3))
|
||||
# now model.output_shape == (None, 6, 32)
|
||||
```
|
||||
|
||||
# Arguments
|
||||
nb_filter: Dimensionality of the output.
|
||||
filter_length: The extension (spatial or temporal) of each filter.
|
||||
@@ -62,8 +66,10 @@ class LocallyConnected1D(Layer):
|
||||
This argument is required if you are going to connect
|
||||
`Flatten` then `Dense` layers upstream
|
||||
(without it, the shape of the dense outputs cannot be computed).
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, input_dim)`.
|
||||
|
||||
# Output shape
|
||||
3D tensor with shape: `(samples, new_steps, nb_filter)`.
|
||||
`steps` value might have changed due to padding.
|
||||
@@ -75,7 +81,7 @@ class LocallyConnected1D(Layer):
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, input_dim=None, input_length=None, **kwargs):
|
||||
if border_mode != 'valid':
|
||||
raise Exception('Invalid border mode for Convolution2D '
|
||||
raise Exception('Invalid border mode for LocallyConnected1D '
|
||||
'(only "valid" is supported):', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
self.filter_length = filter_length
|
||||
@@ -180,14 +186,16 @@ class LocallyConnected1D(Layer):
|
||||
|
||||
|
||||
class LocallyConnected2D(Layer):
|
||||
'''LocallyConnected2D layer works almost the same as Convolution2D layer,
|
||||
except that weights are unshared, that is, a different set of filters is
|
||||
applied at each different patch of the input. When using this layer as the
|
||||
'''The `LocallyConnected2D` layer works similarly
|
||||
to the `Convolution2D` layer, except that weights are unshared,
|
||||
that is, a different set of filters is applied at each
|
||||
different patch of the input.
|
||||
When using this layer as the
|
||||
first layer in a model, provide the keyword argument `input_shape` (tuple
|
||||
of integers, does not include the sample axis), e.g.
|
||||
`input_shape=(3, 128, 128)` for 128x128 RGB pictures. Also, you will need
|
||||
to fix shape of the previous layer, since the weights can only be defined
|
||||
with determined output shape.
|
||||
`input_shape=(3, 128, 128)` for 128x128 RGB pictures.
|
||||
Also, note that this layer can only be used with
|
||||
a fully-specified input shape (`None` dimensions not allowed).
|
||||
|
||||
# Examples
|
||||
```python
|
||||
@@ -251,12 +259,14 @@ class LocallyConnected2D(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=K.image_dim_ordering(),
|
||||
dim_ordering='default',
|
||||
W_regularizer=None, b_regularizer=None, activity_regularizer=None,
|
||||
W_constraint=None, b_constraint=None,
|
||||
bias=True, **kwargs):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
if border_mode != 'valid':
|
||||
raise Exception('Invalid border mode for Convolution2D '
|
||||
raise Exception('Invalid border mode for LocallyConnected2D '
|
||||
'(only "valid" is supported):', border_mode)
|
||||
self.nb_filter = nb_filter
|
||||
self.nb_row = nb_row
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
from ..engine import Layer
|
||||
from .. import backend as K
|
||||
import numpy as np
|
||||
|
||||
|
||||
class GaussianNoise(Layer):
|
||||
@@ -71,7 +72,7 @@ class GaussianDropout(Layer):
|
||||
def call(self, x, mask=None):
|
||||
if 0 < self.p < 1:
|
||||
noise_x = x * K.random_normal(shape=K.shape(x), mean=1.0,
|
||||
std=K.sqrt(self.p / (1.0 - self.p)))
|
||||
std=np.sqrt(self.p / (1.0 - self.p)))
|
||||
return K.in_train_phase(noise_x, x)
|
||||
return x
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
from ..engine import Layer, InputSpec
|
||||
from .. import initializations
|
||||
from .. import initializations, regularizers
|
||||
from .. import backend as K
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ class BatchNormalization(Layer):
|
||||
weights: Initialization weights.
|
||||
List of 2 Numpy arrays, with shapes:
|
||||
`[(input_shape,), (input_shape,)]`
|
||||
Note that the order of this list is [gamma, beta, mean, std]
|
||||
beta_init: name of initialization function for shift parameter
|
||||
(see [initializations](../initializations.md)), or alternatively,
|
||||
Theano/TensorFlow function to use for weights initialization.
|
||||
@@ -43,6 +44,10 @@ class BatchNormalization(Layer):
|
||||
[initializations](../initializations.md)), or alternatively,
|
||||
Theano/TensorFlow function to use for weights initialization.
|
||||
This parameter is only relevant if you don't pass a `weights` argument.
|
||||
gamma_regularizer: instance of [WeightRegularizer](../regularizers.md)
|
||||
(eg. L1 or L2 regularization), applied to the gamma vector.
|
||||
beta_regularizer: instance of [WeightRegularizer](../regularizers.md),
|
||||
applied to the beta vector.
|
||||
|
||||
# Input shape
|
||||
Arbitrary. Use the keyword argument `input_shape`
|
||||
@@ -55,8 +60,9 @@ class BatchNormalization(Layer):
|
||||
# References
|
||||
- [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):
|
||||
def __init__(self, epsilon=1e-5, mode=0, axis=-1, momentum=0.99,
|
||||
weights=None, beta_init='zero', gamma_init='one',
|
||||
gamma_regularizer=None, beta_regularizer=None, **kwargs):
|
||||
self.supports_masking = True
|
||||
self.beta_init = initializations.get(beta_init)
|
||||
self.gamma_init = initializations.get(gamma_init)
|
||||
@@ -64,6 +70,8 @@ class BatchNormalization(Layer):
|
||||
self.mode = mode
|
||||
self.axis = axis
|
||||
self.momentum = momentum
|
||||
self.gamma_regularizer = regularizers.get(gamma_regularizer)
|
||||
self.beta_regularizer = regularizers.get(beta_regularizer)
|
||||
self.initial_weights = weights
|
||||
if self.mode == 0:
|
||||
self.uses_learning_phase = True
|
||||
@@ -77,6 +85,15 @@ class BatchNormalization(Layer):
|
||||
self.beta = self.beta_init(shape, name='{}_beta'.format(self.name))
|
||||
self.trainable_weights = [self.gamma, self.beta]
|
||||
|
||||
self.regularizers = []
|
||||
if self.gamma_regularizer:
|
||||
self.gamma_regularizer.set_param(self.gamma)
|
||||
self.regularizers.append(self.gamma_regularizer)
|
||||
|
||||
if self.beta_regularizer:
|
||||
self.beta_regularizer.set_param(self.beta)
|
||||
self.regularizers.append(self.beta_regularizer)
|
||||
|
||||
self.running_mean = K.zeros(shape,
|
||||
name='{}_running_mean'.format(self.name))
|
||||
self.running_std = K.ones(shape,
|
||||
@@ -99,17 +116,10 @@ class BatchNormalization(Layer):
|
||||
broadcast_shape = [1] * len(input_shape)
|
||||
broadcast_shape[self.axis] = input_shape[self.axis]
|
||||
|
||||
# # case: train mode (uses stats of the current batch)
|
||||
# mean = K.mean(x, axis=reduction_axes)
|
||||
# brodcast_mean = K.reshape(mean, broadcast_shape)
|
||||
# std = K.mean(K.square(x - brodcast_mean) + self.epsilon, axis=reduction_axes)
|
||||
# std = K.sqrt(std)
|
||||
# brodcast_std = K.reshape(std, broadcast_shape)
|
||||
|
||||
if self.mode == 2:
|
||||
x_normed, mean, std = K.normalize_batch_in_training(x, self.gamma, self.beta, reduction_axes, epsilon=self.epsilon)
|
||||
mean_update = self.momentum * self.running_mean + (1 - self.momentum) * mean
|
||||
std_update = self.momentum * self.running_std + (1 - self.momentum) * std
|
||||
x_normed, mean, std = K.normalize_batch_in_training(
|
||||
x, self.gamma, self.beta, reduction_axes,
|
||||
epsilon=self.epsilon)
|
||||
else:
|
||||
# mode 0
|
||||
if self.called_with not in {None, x}:
|
||||
@@ -123,29 +133,28 @@ class BatchNormalization(Layer):
|
||||
'(see docs for a description of '
|
||||
'the behavior).')
|
||||
self.called_with = x
|
||||
x_normed, mean, std = K.normalize_batch_in_training(x, self.gamma, self.beta, reduction_axes, epsilon=self.epsilon)
|
||||
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, mean, std = K.normalize_batch_in_training(
|
||||
x, self.gamma, self.beta, reduction_axes,
|
||||
epsilon=self.epsilon)
|
||||
|
||||
if sorted(reduction_axes) == range(K.ndim(x))[:-1]:
|
||||
x_normed_running = K.batch_normalization(x, self.running_mean,
|
||||
self.running_std,
|
||||
self.beta,
|
||||
self.gamma,
|
||||
epsilon=self.epsilon)
|
||||
self.updates = [K.moving_average_update(self.running_mean, mean, self.momentum),
|
||||
K.moving_average_update(self.running_std, std, self.momentum)]
|
||||
|
||||
if K.backend() == 'tensorflow' and sorted(reduction_axes) == range(K.ndim(x))[:-1]:
|
||||
x_normed_running = K.batch_normalization(
|
||||
x, self.running_mean, self.running_std,
|
||||
self.beta, self.gamma,
|
||||
epsilon=self.epsilon)
|
||||
else:
|
||||
# need broadcasting
|
||||
broadcast_running_mean = K.reshape(self.running_mean, broadcast_shape)
|
||||
broadcast_running_std = K.reshape(self.running_std, broadcast_shape)
|
||||
broadcast_beta = K.reshape(self.beta, broadcast_shape)
|
||||
broadcast_gamma = K.reshape(self.gamma, broadcast_shape)
|
||||
x_normed_running = K.batch_normalization(x, broadcast_running_mean,
|
||||
broadcast_running_std,
|
||||
broadcast_beta,
|
||||
broadcast_gamma,
|
||||
epsilon=self.epsilon)
|
||||
x_normed_running = K.batch_normalization(
|
||||
x, broadcast_running_mean, broadcast_running_std,
|
||||
broadcast_beta, broadcast_gamma,
|
||||
epsilon=self.epsilon)
|
||||
|
||||
# pick the normalized form of x corresponding to the training phase
|
||||
x_normed = K.in_train_phase(x_normed, x_normed_running)
|
||||
@@ -162,6 +171,8 @@ class BatchNormalization(Layer):
|
||||
config = {"epsilon": self.epsilon,
|
||||
"mode": self.mode,
|
||||
"axis": self.axis,
|
||||
"gamma_regularizer": self.gamma_regularizer.get_config() if self.gamma_regularizer else None,
|
||||
"beta_regularizer": self.beta_regularizer.get_config() if self.beta_regularizer else None,
|
||||
"momentum": self.momentum}
|
||||
base_config = super(BatchNormalization, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
+135
-8
@@ -61,8 +61,9 @@ class MaxPooling1D(_Pooling1D):
|
||||
3D tensor with shape: `(samples, downsampled_steps, features)`.
|
||||
|
||||
# Arguments
|
||||
pool_length: factor by which to downscale. 2 will halve the input.
|
||||
stride: integer, or None. Stride value.
|
||||
pool_length: size of the region to which max pooling is applied
|
||||
stride: integer, or None. factor by which to downscale.
|
||||
2 will halve the input.
|
||||
If None, it will default to `pool_length`.
|
||||
border_mode: 'valid' or 'same'.
|
||||
Note: 'same' will only work with TensorFlow for the time being.
|
||||
@@ -114,8 +115,10 @@ class _Pooling2D(Layer):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
dim_ordering='default', **kwargs):
|
||||
super(_Pooling2D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.pool_size = tuple(pool_size)
|
||||
if strides is None:
|
||||
strides = self.pool_size
|
||||
@@ -199,7 +202,7 @@ class MaxPooling2D(_Pooling2D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
dim_ordering='default', **kwargs):
|
||||
super(MaxPooling2D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
@@ -241,7 +244,7 @@ class AveragePooling2D(_Pooling2D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
dim_ordering='default', **kwargs):
|
||||
super(AveragePooling2D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
@@ -257,8 +260,10 @@ class _Pooling3D(Layer):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
dim_ordering='default', **kwargs):
|
||||
super(_Pooling3D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.pool_size = tuple(pool_size)
|
||||
if strides is None:
|
||||
strides = self.pool_size
|
||||
@@ -344,7 +349,7 @@ class MaxPooling3D(_Pooling3D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
dim_ordering='default', **kwargs):
|
||||
super(MaxPooling3D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
@@ -384,7 +389,7 @@ class AveragePooling3D(_Pooling3D):
|
||||
'''
|
||||
|
||||
def __init__(self, pool_size=(2, 2, 2), strides=None, border_mode='valid',
|
||||
dim_ordering=K.image_dim_ordering(), **kwargs):
|
||||
dim_ordering='default', **kwargs):
|
||||
super(AveragePooling3D, self).__init__(pool_size, strides, border_mode,
|
||||
dim_ordering, **kwargs)
|
||||
|
||||
@@ -393,3 +398,125 @@ class AveragePooling3D(_Pooling3D):
|
||||
output = K.pool3d(inputs, pool_size, strides,
|
||||
border_mode, dim_ordering, pool_mode='avg')
|
||||
return output
|
||||
|
||||
|
||||
class _GlobalPooling1D(Layer):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(_GlobalPooling1D, self).__init__(**kwargs)
|
||||
self.input_spec = [InputSpec(ndim=3)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
return (input_shape[0], input_shape[2])
|
||||
|
||||
def call(self, x, mask=None):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class GlobalAveragePooling1D(_GlobalPooling1D):
|
||||
'''Global average pooling operation for temporal data.
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape: `(samples, features)`.
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
return K.mean(x, axis=1)
|
||||
|
||||
|
||||
class GlobalMaxPooling1D(_GlobalPooling1D):
|
||||
'''Global max pooling operation for temporal data.
|
||||
|
||||
# Input shape
|
||||
3D tensor with shape: `(samples, steps, features)`.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape: `(samples, features)`.
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
return K.max(x, axis=1)
|
||||
|
||||
|
||||
class _GlobalPooling2D(Layer):
|
||||
|
||||
def __init__(self, dim_ordering='default', **kwargs):
|
||||
super(_GlobalPooling2D, self).__init__(**kwargs)
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
print(dim_ordering)
|
||||
self.dim_ordering = dim_ordering
|
||||
self.input_spec = [InputSpec(ndim=4)]
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.dim_ordering == 'tf':
|
||||
return (input_shape[0], input_shape[3])
|
||||
else:
|
||||
return (input_shape[0], input_shape[1])
|
||||
|
||||
def call(self, x, mask=None):
|
||||
raise NotImplementedError
|
||||
|
||||
def get_config(self):
|
||||
config = {'dim_ordering': self.dim_ordering}
|
||||
base_config = super(_GlobalPooling2D, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
|
||||
class GlobalAveragePooling2D(_GlobalPooling2D):
|
||||
'''Global average pooling operation for spatial data.
|
||||
|
||||
# Arguments
|
||||
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:
|
||||
`(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape:
|
||||
`(nb_samples, channels)`
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if self.dim_ordering == 'tf':
|
||||
return K.mean(x, axis=[1, 2])
|
||||
else:
|
||||
return K.mean(x, axis=[2, 3])
|
||||
|
||||
|
||||
class GlobalMaxPooling2D(_GlobalPooling2D):
|
||||
'''Global max pooling operation for spatial data.
|
||||
|
||||
# Arguments
|
||||
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:
|
||||
`(samples, channels, rows, cols)` if dim_ordering='th'
|
||||
or 4D tensor with shape:
|
||||
`(samples, rows, cols, channels)` if dim_ordering='tf'.
|
||||
|
||||
# Output shape
|
||||
2D tensor with shape:
|
||||
`(nb_samples, channels)`
|
||||
'''
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if self.dim_ordering == 'tf':
|
||||
return K.max(x, axis=[1, 2])
|
||||
else:
|
||||
return K.max(x, axis=[2, 3])
|
||||
|
||||
+19
-37
@@ -12,13 +12,10 @@ def time_distributed_dense(x, w, b=None, dropout=None,
|
||||
'''Apply y.w + b for every temporal slice y of x.
|
||||
'''
|
||||
if not input_dim:
|
||||
# won't work with TensorFlow
|
||||
input_dim = K.shape(x)[2]
|
||||
if not timesteps:
|
||||
# won't work with TensorFlow
|
||||
timesteps = K.shape(x)[1]
|
||||
if not output_dim:
|
||||
# won't work with TensorFlow
|
||||
output_dim = K.shape(w)[1]
|
||||
|
||||
if dropout is not None and 0. < dropout < 1.:
|
||||
@@ -30,12 +27,15 @@ def time_distributed_dense(x, w, b=None, dropout=None,
|
||||
|
||||
# collapse time dimension and batch dimension together
|
||||
x = K.reshape(x, (-1, input_dim))
|
||||
|
||||
x = K.dot(x, w)
|
||||
if b:
|
||||
x = x + b
|
||||
# reshape to 3D tensor
|
||||
x = K.reshape(x, (-1, timesteps, output_dim))
|
||||
if K.backend() == 'tensorflow':
|
||||
x = K.reshape(x, K.pack([-1, timesteps, output_dim]))
|
||||
x.set_shape([None, None, output_dim])
|
||||
else:
|
||||
x = K.reshape(x, (-1, timesteps, output_dim))
|
||||
return x
|
||||
|
||||
|
||||
@@ -120,14 +120,10 @@ class Recurrent(Layer):
|
||||
use an [Embedding](embeddings.md) layer with the `mask_zero` parameter
|
||||
set to `True`.
|
||||
|
||||
# TensorFlow warning
|
||||
For the time being, when using the TensorFlow backend,
|
||||
the number of timesteps used must be specified in your model.
|
||||
Make sure to pass an `input_length` int argument to your
|
||||
recurrent layer (if it comes first in your model),
|
||||
or to pass a complete `input_shape` argument to the first layer
|
||||
in your model otherwise.
|
||||
|
||||
# Note on performance
|
||||
You are likely to see better performance with RNNs in Theano compared
|
||||
to TensorFlow. Additionally, when using TensorFlow, it is often
|
||||
preferable to set `unroll=True` for better performance.
|
||||
|
||||
# Note on using statefulness in RNNs
|
||||
You can set RNN layers to be 'stateful', which means that the states
|
||||
@@ -139,16 +135,15 @@ class Recurrent(Layer):
|
||||
To enable statefulness:
|
||||
- specify `stateful=True` in the layer constructor.
|
||||
- specify a fixed batch size for your model, by passing
|
||||
a `batch_input_shape=(...)` to the first layer in your model.
|
||||
if sequential model:
|
||||
a `batch_input_shape=(...)` to the first layer in your model.
|
||||
else for functional model with 1 or more Input layers:
|
||||
a `batch_shape=(...)` to all the first layers in your model.
|
||||
This is the expected shape of your inputs *including the batch size*.
|
||||
It should be a tuple of integers, e.g. `(32, 10, 100)`.
|
||||
|
||||
To reset the states of your model, call `.reset_states()` on either
|
||||
a specific layer, or on your entire model.
|
||||
|
||||
# Note on using dropout with TensorFlow
|
||||
When using the TensorFlow backend, specify a fixed batch size for your model
|
||||
following the notes on statefulness RNNs.
|
||||
'''
|
||||
def __init__(self, weights=None,
|
||||
return_sequences=False, go_backwards=False, stateful=False,
|
||||
@@ -204,19 +199,6 @@ class Recurrent(Layer):
|
||||
# note that the .build() method of subclasses MUST define
|
||||
# self.input_spec with a complete input shape.
|
||||
input_shape = self.input_spec[0].shape
|
||||
if K._BACKEND == 'tensorflow':
|
||||
if not input_shape[1]:
|
||||
raise Exception('When using TensorFlow, you should define '
|
||||
'explicitly the number of timesteps of '
|
||||
'your sequences.\n'
|
||||
'If your first layer is an Embedding, '
|
||||
'make sure to pass it an "input_length" '
|
||||
'argument. Otherwise, make sure '
|
||||
'the first layer has '
|
||||
'an "input_shape" or "batch_input_shape" '
|
||||
'argument, including the time axis. '
|
||||
'Found input shape at layer ' + self.name +
|
||||
': ' + str(input_shape))
|
||||
if self.stateful:
|
||||
initial_states = self.states
|
||||
else:
|
||||
@@ -372,7 +354,7 @@ class SimpleRNN(Recurrent):
|
||||
constants = []
|
||||
if 0 < self.dropout_U < 1:
|
||||
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
|
||||
ones = K.concatenate([ones] * self.output_dim, 1)
|
||||
ones = K.tile(ones, (1, self.output_dim))
|
||||
B_U = K.in_train_phase(K.dropout(ones, self.dropout_U), ones)
|
||||
constants.append(B_U)
|
||||
else:
|
||||
@@ -381,7 +363,7 @@ class SimpleRNN(Recurrent):
|
||||
input_shape = self.input_spec[0].shape
|
||||
input_dim = input_shape[-1]
|
||||
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
|
||||
ones = K.concatenate([ones] * input_dim, 1)
|
||||
ones = K.tile(ones, (1, input_dim))
|
||||
B_W = K.in_train_phase(K.dropout(ones, self.dropout_W), ones)
|
||||
constants.append(B_W)
|
||||
else:
|
||||
@@ -585,7 +567,7 @@ class GRU(Recurrent):
|
||||
constants = []
|
||||
if 0 < self.dropout_U < 1:
|
||||
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
|
||||
ones = K.concatenate([ones] * self.output_dim, 1)
|
||||
ones = K.tile(ones, (1, self.output_dim))
|
||||
B_U = [K.in_train_phase(K.dropout(ones, self.dropout_U), ones) for _ in range(3)]
|
||||
constants.append(B_U)
|
||||
else:
|
||||
@@ -595,7 +577,7 @@ class GRU(Recurrent):
|
||||
input_shape = self.input_spec[0].shape
|
||||
input_dim = input_shape[-1]
|
||||
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
|
||||
ones = K.concatenate([ones] * input_dim, 1)
|
||||
ones = K.tile(ones, (1, input_dim))
|
||||
B_W = [K.in_train_phase(K.dropout(ones, self.dropout_W), ones) for _ in range(3)]
|
||||
constants.append(B_W)
|
||||
else:
|
||||
@@ -825,7 +807,7 @@ class LSTM(Recurrent):
|
||||
constants = []
|
||||
if 0 < self.dropout_U < 1:
|
||||
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
|
||||
ones = K.concatenate([ones] * self.output_dim, 1)
|
||||
ones = K.tile(ones, (1, self.output_dim))
|
||||
B_U = [K.in_train_phase(K.dropout(ones, self.dropout_U), ones) for _ in range(4)]
|
||||
constants.append(B_U)
|
||||
else:
|
||||
@@ -835,7 +817,7 @@ class LSTM(Recurrent):
|
||||
input_shape = self.input_spec[0].shape
|
||||
input_dim = input_shape[-1]
|
||||
ones = K.ones_like(K.reshape(x[:, 0, 0], (-1, 1)))
|
||||
ones = K.concatenate([ones] * input_dim, 1)
|
||||
ones = K.tile(ones, (1, input_dim))
|
||||
B_W = [K.in_train_phase(K.dropout(ones, self.dropout_W), ones) for _ in range(4)]
|
||||
constants.append(B_W)
|
||||
else:
|
||||
|
||||
+139
-11
@@ -20,6 +20,13 @@ class Wrapper(Layer):
|
||||
self.regularizers = getattr(self.layer, 'regularizers', [])
|
||||
self.constraints = getattr(self.layer, 'constraints', {})
|
||||
|
||||
# properly attribute the current layer to
|
||||
# regularizers that need access to it
|
||||
# (e.g. ActivityRegularizer).
|
||||
for regularizer in self.regularizers:
|
||||
if hasattr(regularizer, 'set_layer'):
|
||||
regularizer.set_layer(self)
|
||||
|
||||
def get_weights(self):
|
||||
weights = self.layer.get_weights()
|
||||
return weights
|
||||
@@ -86,17 +93,6 @@ class TimeDistributed(Wrapper):
|
||||
def build(self, input_shape):
|
||||
assert len(input_shape) >= 3
|
||||
self.input_spec = [InputSpec(shape=input_shape)]
|
||||
if K._BACKEND == 'tensorflow':
|
||||
if not input_shape[1]:
|
||||
raise Exception('When using TensorFlow, you should define '
|
||||
'explicitly the number of timesteps of '
|
||||
'your sequences.\n'
|
||||
'If your first layer is an Embedding, '
|
||||
'make sure to pass it an "input_length" '
|
||||
'argument. Otherwise, make sure '
|
||||
'the first layer has '
|
||||
'an "input_shape" or "batch_input_shape" '
|
||||
'argument, including the time axis.')
|
||||
child_input_shape = (input_shape[0],) + input_shape[2:]
|
||||
if not self.layer.built:
|
||||
self.layer.build(child_input_shape)
|
||||
@@ -133,3 +129,135 @@ class TimeDistributed(Wrapper):
|
||||
output_shape = self.get_output_shape_for(input_shape)
|
||||
y = K.reshape(y, (-1, input_length) + output_shape[2:])
|
||||
return y
|
||||
|
||||
|
||||
class Bidirectional(Wrapper):
|
||||
''' Bidirectional wrapper for RNNs.
|
||||
|
||||
# Arguments:
|
||||
layer: `Recurrent` instance.
|
||||
merge_mode: Mode by which outputs of the
|
||||
forward and backward RNNs will be combined.
|
||||
One of {'sum', 'mul', 'concat', 'ave', None}.
|
||||
If None, the outputs will not be combined,
|
||||
they will be returned as a list.
|
||||
|
||||
# Examples:
|
||||
|
||||
```python
|
||||
model = Sequential()
|
||||
model.add(Bidirectional(LSTM(10, return_sequences=True), input_shape=(5, 10)))
|
||||
model.add(Bidirectional(LSTM(10)))
|
||||
model.add(Dense(5))
|
||||
model.add(Activation('softmax'))
|
||||
model.compile(loss='categorical_crossentropy', optimizer='rmsprop')
|
||||
```
|
||||
'''
|
||||
def __init__(self, layer, merge_mode='concat', weights=None, **kwargs):
|
||||
if merge_mode not in ['sum', 'mul', 'ave', 'concat', None]:
|
||||
raise ValueError('Invalid merge mode. '
|
||||
'Merge mode should be one of '
|
||||
'{"sum", "mul", "ave", "concat", None}')
|
||||
self.forward_layer = layer
|
||||
config = layer.get_config()
|
||||
config['go_backwards'] = not config['go_backwards']
|
||||
self.backward_layer = layer.__class__.from_config(config)
|
||||
self.forward_layer.name = 'forward_' + self.forward_layer.name
|
||||
self.backward_layer.name = 'backward_' + self.backward_layer.name
|
||||
self.merge_mode = merge_mode
|
||||
if weights:
|
||||
nw = len(weights)
|
||||
self.forward_layer.initial_weights = weights[:nw // 2]
|
||||
self.backward_layer.initial_weights = weights[nw // 2:]
|
||||
self.stateful = layer.stateful
|
||||
self.return_sequences = layer.return_sequences
|
||||
self.supports_masking = True
|
||||
super(Bidirectional, self).__init__(layer, **kwargs)
|
||||
|
||||
def get_weights(self):
|
||||
return self.forward_layer.get_weights() + self.backward_layer.get_weights()
|
||||
|
||||
def set_weights(self, weights):
|
||||
nw = len(weights)
|
||||
self.forward_layer.set_weights(weights[:nw // 2])
|
||||
self.backward_layer.set_weights(weights[nw // 2:])
|
||||
|
||||
def get_output_shape_for(self, input_shape):
|
||||
if self.merge_mode in ['sum', 'ave', 'mul']:
|
||||
return self.forward_layer.get_output_shape_for(input_shape)
|
||||
elif self.merge_mode == 'concat':
|
||||
shape = list(self.forward_layer.get_output_shape_for(input_shape))
|
||||
shape[-1] *= 2
|
||||
return tuple(shape)
|
||||
elif self.merge_mode is None:
|
||||
return [self.forward_layer.get_output_shape_for(input_shape)] * 2
|
||||
|
||||
def call(self, X, mask=None):
|
||||
Y = self.forward_layer.call(X, mask)
|
||||
Y_rev = self.backward_layer.call(X, mask)
|
||||
if self.return_sequences:
|
||||
Y_rev = K.reverse(Y_rev, 1)
|
||||
if self.merge_mode == 'concat':
|
||||
return K.concatenate([Y, Y_rev])
|
||||
elif self.merge_mode == 'sum':
|
||||
return Y + Y_rev
|
||||
elif self.merge_mode == 'ave':
|
||||
return (Y + Y_rev) / 2
|
||||
elif self.merge_mode == 'mul':
|
||||
return Y * Y_rev
|
||||
elif self.merge_mode is None:
|
||||
return [Y, Y_rev]
|
||||
|
||||
def reset_states(self):
|
||||
self.forward_layer.reset_states()
|
||||
self.backward_layer.reset_states()
|
||||
|
||||
def build(self, input_shape):
|
||||
self.forward_layer.build(input_shape)
|
||||
self.backward_layer.build(input_shape)
|
||||
|
||||
def compute_mask(self, input, mask):
|
||||
if self.return_sequences:
|
||||
if not self.merge_mode:
|
||||
return [mask, mask]
|
||||
else:
|
||||
return mask
|
||||
else:
|
||||
return None
|
||||
|
||||
@property
|
||||
def trainable_weights(self):
|
||||
if hasattr(self.forward_layer, 'trainable_weights'):
|
||||
return self.forward_layer.trainable_weights + self.backward_layer.trainable_weights
|
||||
return []
|
||||
|
||||
@property
|
||||
def non_trainable_weights(self):
|
||||
if hasattr(self.forward_layer, 'non_trainable_weights'):
|
||||
return self.forward_layer.non_trainable_weights + self.backward_layer.non_trainable_weights
|
||||
return []
|
||||
|
||||
@property
|
||||
def updates(self):
|
||||
if hasattr(self.forward_layer, 'updates'):
|
||||
return self.forward_layer.updates + self.backward_layer.updates
|
||||
return []
|
||||
|
||||
@property
|
||||
def regularizers(self):
|
||||
if hasattr(self.forward_layer, 'regularizers'):
|
||||
return self.forward_layer.regularizers + self.backward_layer.regularizers
|
||||
return []
|
||||
|
||||
@property
|
||||
def constraints(self):
|
||||
_constraints = {}
|
||||
if hasattr(self.forward_layer, 'constraints'):
|
||||
_constraints.update(self.forward_layer.constraints)
|
||||
_constraints.update(self.backward_layer.constraints)
|
||||
return _constraints
|
||||
|
||||
def get_config(self):
|
||||
config = {"merge_mode": self.merge_mode}
|
||||
base_config = super(Bidirectional, self).get_config()
|
||||
return dict(list(base_config.items()) + list(config.items()))
|
||||
|
||||
@@ -71,6 +71,26 @@ def cosine_proximity(y_true, y_pred):
|
||||
return -K.mean(y_true * y_pred)
|
||||
|
||||
|
||||
def matthews_correlation(y_true, y_pred):
|
||||
''' Matthews correlation coefficient
|
||||
'''
|
||||
y_pred_pos = K.round(K.clip(y_pred, 0, 1))
|
||||
y_pred_neg = 1 - y_pred_pos
|
||||
|
||||
y_pos = K.round(K.clip(y_true, 0, 1))
|
||||
y_neg = 1 - y_pos
|
||||
|
||||
tp = K.sum(y_pos * y_pred_pos)
|
||||
tn = K.sum(y_neg * y_pred_neg)
|
||||
|
||||
fp = K.sum(1 - y_neg * y_pred_pos)
|
||||
fn = K.sum(1 - y_pos * y_pred_neg)
|
||||
|
||||
numerator = (tp * tn - fp * fn)
|
||||
denominator = K.sqrt((tp + fp) * (tp + fn) * (tn + fp) * (tn + fn))
|
||||
|
||||
return numerator / (denominator + K.epsilon())
|
||||
|
||||
# aliases
|
||||
mse = MSE = mean_squared_error
|
||||
mae = MAE = mean_absolute_error
|
||||
|
||||
+195
-4
@@ -1,13 +1,174 @@
|
||||
from __future__ import print_function
|
||||
import warnings
|
||||
import copy
|
||||
import json
|
||||
import os
|
||||
import numpy as np
|
||||
|
||||
from . import backend as K
|
||||
from .utils.io_utils import ask_to_proceed_with_overwrite
|
||||
from .engine.training import Model
|
||||
from .engine.topology import get_source_inputs, Node
|
||||
from .optimizers import optimizer_from_config
|
||||
from .legacy.models import Graph
|
||||
|
||||
|
||||
def save_model(model, filepath, overwrite=True):
|
||||
|
||||
def get_json_type(obj):
|
||||
# if obj is a serializable Keras class instance
|
||||
# e.g. optimizer, layer
|
||||
if hasattr(obj, 'get_config'):
|
||||
return {'class_name': obj.__class__.__name__,
|
||||
'config': obj.get_config()}
|
||||
|
||||
# if obj is any numpy type
|
||||
if type(obj).__module__ == np.__name__:
|
||||
return obj.item()
|
||||
|
||||
# misc functions (e.g. loss function)
|
||||
if hasattr(obj, '__call__'):
|
||||
return obj.__name__
|
||||
|
||||
# if obj is a python 'type'
|
||||
if type(obj).__name__ == type.__name__:
|
||||
return obj.__name__
|
||||
|
||||
raise TypeError('Not JSON Serializable:', obj)
|
||||
|
||||
import h5py
|
||||
from keras import __version__ as keras_version
|
||||
|
||||
# if file exists and should not be overwritten
|
||||
if not overwrite and os.path.isfile(filepath):
|
||||
proceed = ask_to_proceed_with_overwrite(filepath)
|
||||
if not proceed:
|
||||
return
|
||||
|
||||
f = h5py.File(filepath, 'w')
|
||||
f.attrs['keras_version'] = str(keras_version).encode('utf8')
|
||||
f.attrs['model_config'] = json.dumps({
|
||||
'class_name': model.__class__.__name__,
|
||||
'config': model.get_config()
|
||||
}, default=get_json_type).encode('utf8')
|
||||
|
||||
model_weights_group = f.create_group('model_weights')
|
||||
model.save_weights_to_hdf5_group(model_weights_group)
|
||||
|
||||
if hasattr(model, 'optimizer'):
|
||||
f.attrs['training_config'] = json.dumps({
|
||||
'optimizer_config': {
|
||||
'class_name': model.optimizer.__class__.__name__,
|
||||
'config': model.optimizer.get_config()
|
||||
},
|
||||
'loss': model.loss,
|
||||
'metrics': model.metrics,
|
||||
'sample_weight_mode': model.sample_weight_mode,
|
||||
'loss_weights': model.loss_weights,
|
||||
}, default=get_json_type).encode('utf8')
|
||||
|
||||
# save optimizer weights
|
||||
symbolic_weights = getattr(model.optimizer, 'weights')
|
||||
if symbolic_weights:
|
||||
optimizer_weights_group = f.create_group('optimizer_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:
|
||||
name = str(w.name)
|
||||
else:
|
||||
name = 'param_' + str(i)
|
||||
weight_names.append(name.encode('utf8'))
|
||||
optimizer_weights_group.attrs['weight_names'] = weight_names
|
||||
for name, val in zip(weight_names, weight_values):
|
||||
param_dset = optimizer_weights_group.create_dataset(
|
||||
name,
|
||||
val.shape,
|
||||
dtype=val.dtype)
|
||||
if not val.shape:
|
||||
# scalar
|
||||
param_dset[()] = val
|
||||
else:
|
||||
param_dset[:] = val
|
||||
f.flush()
|
||||
f.close()
|
||||
|
||||
|
||||
def load_model(filepath, custom_objects={}):
|
||||
|
||||
def deserialize(obj):
|
||||
if type(obj) is list:
|
||||
deserialized = []
|
||||
for value in obj:
|
||||
if value in custom_objects:
|
||||
deserialized.append(custom_objects[value])
|
||||
else:
|
||||
deserialized.append(value)
|
||||
return deserialized
|
||||
if type(obj) is dict:
|
||||
deserialized = {}
|
||||
for key, value in obj.items():
|
||||
if value in custom_objects:
|
||||
deserialized[key] = custom_objects[value]
|
||||
else:
|
||||
deserialized[key] = value
|
||||
return deserialized
|
||||
if obj in custom_objects:
|
||||
return custom_objects[obj]
|
||||
return obj
|
||||
|
||||
import h5py
|
||||
f = h5py.File(filepath, mode='r')
|
||||
|
||||
# instantiate model
|
||||
model_config = f.attrs.get('model_config')
|
||||
if model_config is None:
|
||||
raise ValueError('No model found in config file.')
|
||||
model_config = json.loads(model_config.decode('utf-8'))
|
||||
model = model_from_config(model_config, custom_objects=custom_objects)
|
||||
|
||||
# set weights
|
||||
model.load_weights_from_hdf5_group(f['model_weights'])
|
||||
|
||||
# instantiate optimizer
|
||||
training_config = f.attrs.get('training_config')
|
||||
if training_config is None:
|
||||
warnings.warn('No training configuration found in save file: '
|
||||
'the model was *not* compiled. Compile it manually.')
|
||||
f.close()
|
||||
return model
|
||||
training_config = json.loads(training_config.decode('utf-8'))
|
||||
optimizer_config = training_config['optimizer_config']
|
||||
optimizer = optimizer_from_config(optimizer_config)
|
||||
|
||||
# recover loss functions and metrics
|
||||
loss = deserialize(training_config['loss'])
|
||||
metrics = deserialize(training_config['metrics'])
|
||||
sample_weight_mode = training_config['sample_weight_mode']
|
||||
loss_weights = training_config['loss_weights']
|
||||
|
||||
# compile model
|
||||
model.compile(optimizer=optimizer,
|
||||
loss=loss,
|
||||
metrics=metrics,
|
||||
loss_weights=loss_weights,
|
||||
sample_weight_mode=sample_weight_mode)
|
||||
|
||||
# set optimizer weights
|
||||
if 'optimizer_weights' in f:
|
||||
# build train function (to get weight updates)
|
||||
if model.__class__.__name__ == 'Sequential':
|
||||
model.model._make_train_function()
|
||||
else:
|
||||
model._make_train_function()
|
||||
optimizer_weights_group = f['optimizer_weights']
|
||||
optimizer_weight_names = [n.decode('utf8') for n in optimizer_weights_group.attrs['weight_names']]
|
||||
optimizer_weight_values = [optimizer_weights_group[n] for n in optimizer_weight_names]
|
||||
model.optimizer.set_weights(optimizer_weight_values)
|
||||
f.close()
|
||||
return model
|
||||
|
||||
|
||||
def model_from_config(config, custom_objects={}):
|
||||
from keras.utils.layer_utils import layer_from_config
|
||||
if isinstance(config, list):
|
||||
@@ -77,6 +238,7 @@ class Sequential(Model):
|
||||
self.model = None # internal Model instance
|
||||
self.inputs = [] # tensors
|
||||
self.outputs = [] # tensors (length 1)
|
||||
self.trainable = True
|
||||
|
||||
# model attributes
|
||||
self.inbound_nodes = []
|
||||
@@ -172,7 +334,27 @@ class Sequential(Model):
|
||||
else:
|
||||
self.layers[-1].outbound_nodes = []
|
||||
self.outputs = [self.layers[-1].output]
|
||||
# update self.inbound_nodes
|
||||
self.inbound_nodes[0].output_tensors = self.outputs
|
||||
self.inbound_nodes[0].output_shapes = [self.outputs[0]._keras_shape]
|
||||
self.built = False
|
||||
self._flattened_layers = None
|
||||
|
||||
def get_layer(self, name=None, index=None):
|
||||
'''Returns a layer based on either its name (unique)
|
||||
or its index in the graph. Indices are based on
|
||||
order of horizontal graph traversal (bottom-up).
|
||||
|
||||
# Arguments
|
||||
name: string, name of layer.
|
||||
index: integer, index of layer.
|
||||
|
||||
# Returns
|
||||
A layer instance.
|
||||
'''
|
||||
if not self.built:
|
||||
self.build()
|
||||
return self.model.get_layer(name, index)
|
||||
|
||||
def call(self, x, mask=None):
|
||||
if not self.built:
|
||||
@@ -257,13 +439,19 @@ class Sequential(Model):
|
||||
|
||||
@property
|
||||
def trainable_weights(self):
|
||||
if not self.trainable:
|
||||
return []
|
||||
# support for legacy behavior
|
||||
return self._gather_list_attr('trainable_weights')
|
||||
|
||||
@property
|
||||
def non_trainable_weights(self):
|
||||
# support for legacy behavior
|
||||
return self._gather_list_attr('non_trainable_weights')
|
||||
weights = self._gather_list_attr('non_trainable_weights')
|
||||
if not self.trainable:
|
||||
trainable_weights = self._gather_list_attr('trainable_weights')
|
||||
return trainable_weights + weights
|
||||
return weights
|
||||
|
||||
@property
|
||||
def updates(self):
|
||||
@@ -303,7 +491,7 @@ class Sequential(Model):
|
||||
'''
|
||||
# support for legacy behavior
|
||||
for layer in self.flattened_layers:
|
||||
nb_param = len(layer.get_weights())
|
||||
nb_param = len(layer.weights)
|
||||
layer.set_weights(weights[:nb_param])
|
||||
weights = weights[nb_param:]
|
||||
|
||||
@@ -359,6 +547,9 @@ class Sequential(Model):
|
||||
**kwargs)
|
||||
self.optimizer = self.model.optimizer
|
||||
self.loss = self.model.loss
|
||||
self.loss_weights = self.model.loss_weights
|
||||
self.metrics = self.model.metrics
|
||||
self.metrics_tensors = self.model.metrics_tensors
|
||||
self.metrics_names = self.model.metrics_names
|
||||
self.sample_weight_mode = self.model.sample_weight_mode
|
||||
|
||||
@@ -627,7 +818,7 @@ class Sequential(Model):
|
||||
max_q_size: maximum size for the generator queue
|
||||
nb_worker: maximum number of processes to spin up
|
||||
pickle_safe: if True, use process based threading. Note that because
|
||||
this implementation relies on multiprocessing, you should not pass non
|
||||
this implementation relies on multiprocessing, you should not pass
|
||||
non picklable arguments to the generator as they can't be passed
|
||||
easily to children processes.
|
||||
|
||||
@@ -686,7 +877,7 @@ class Sequential(Model):
|
||||
'''Evaluates the model on a data generator. The generator should
|
||||
return the same kind of data as accepted by `test_on_batch`.
|
||||
|
||||
Arguments:
|
||||
# Arguments
|
||||
generator:
|
||||
generator yielding tuples (inputs, targets)
|
||||
or (inputs, targets, sample_weights)
|
||||
|
||||
+140
-70
@@ -1,6 +1,5 @@
|
||||
from __future__ import absolute_import
|
||||
from . import backend as K
|
||||
import numpy as np
|
||||
from .utils.generic_utils import get_from_module
|
||||
from six.moves import zip
|
||||
|
||||
@@ -11,8 +10,24 @@ def clip_norm(g, c, n):
|
||||
return g
|
||||
|
||||
|
||||
def kl_divergence(p, p_hat):
|
||||
return p_hat - p + p * K.log(p / p_hat)
|
||||
def optimizer_from_config(config, custom_objects={}):
|
||||
all_classes = {
|
||||
'sgd': SGD,
|
||||
'rmsprop': RMSprop,
|
||||
'adagrad': Adagrad,
|
||||
'adadelta': Adadelta,
|
||||
'adam': Adam,
|
||||
'adamax': Adamax,
|
||||
'nadam': Nadam,
|
||||
}
|
||||
class_name = config['class_name']
|
||||
if class_name in custom_objects:
|
||||
cls = custom_objects[class_name]
|
||||
else:
|
||||
if class_name.lower() not in all_classes:
|
||||
raise ValueError('Optimizer class not found:', class_name)
|
||||
cls = all_classes[class_name.lower()]
|
||||
return cls.from_config(config['config'])
|
||||
|
||||
|
||||
class Optimizer(object):
|
||||
@@ -72,35 +87,35 @@ class Optimizer(object):
|
||||
output of `get_weights`).
|
||||
'''
|
||||
params = self.weights
|
||||
if len(params) != len(weights):
|
||||
raise Exception('Provided weight array does not match weights (' +
|
||||
str(len(params)) + ' optimizer params vs. ' +
|
||||
str(len(weights)) + ' provided weights)')
|
||||
for p, w in zip(params, weights):
|
||||
if K.get_value(p).shape != w.shape:
|
||||
weight_value_tuples = []
|
||||
param_values = K.batch_get_value(params)
|
||||
for pv, p, w in zip(param_values, params, weights):
|
||||
if pv.shape != w.shape:
|
||||
raise Exception('Optimizer weight shape ' +
|
||||
str(K.get_value(p).shape) +
|
||||
str(pv.shape) +
|
||||
' not compatible with '
|
||||
'provided weight shape ' + str(w.shape))
|
||||
K.set_value(p, w)
|
||||
weight_value_tuples.append((p, w))
|
||||
K.batch_set_value(weight_value_tuples)
|
||||
|
||||
def get_weights(self):
|
||||
'''Returns the current weights of the optimizer,
|
||||
as a list of numpy arrays.
|
||||
'''
|
||||
weights = []
|
||||
for p in self.weights:
|
||||
weights.append(K.get_value(p))
|
||||
return weights
|
||||
return K.batch_get_value(self.weights)
|
||||
|
||||
def get_config(self):
|
||||
config = {'name': self.__class__.__name__}
|
||||
config = {}
|
||||
if hasattr(self, 'clipnorm'):
|
||||
config['clipnorm'] = self.clipnorm
|
||||
if hasattr(self, 'clipvalue'):
|
||||
config['clipvalue'] = self.clipvalue
|
||||
return config
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, config):
|
||||
return cls(**config)
|
||||
|
||||
|
||||
class SGD(Optimizer):
|
||||
'''Stochastic gradient descent, with support for momentum,
|
||||
@@ -120,17 +135,24 @@ class SGD(Optimizer):
|
||||
self.lr = K.variable(lr)
|
||||
self.momentum = K.variable(momentum)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
lr = self.lr * (1. / (1. + self.decay * self.iterations))
|
||||
self.updates = [(self.iterations, self.iterations + 1.)]
|
||||
self.updates = []
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates .append(K.update_add(self.iterations, 1))
|
||||
|
||||
# momentum
|
||||
self.weights = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
for p, g, m in zip(params, grads, self.weights):
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
moments = [K.zeros(shape) for shape in shapes]
|
||||
self.weights = [self.iterations] + moments
|
||||
for p, g, m in zip(params, grads, moments):
|
||||
v = self.momentum * m - lr * g # velocity
|
||||
self.updates.append((m, v))
|
||||
self.updates.append(K.update(m, v))
|
||||
|
||||
if self.nesterov:
|
||||
new_p = p + self.momentum * v - lr * g
|
||||
@@ -141,7 +163,8 @@ class SGD(Optimizer):
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
|
||||
self.updates.append(K.update(p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
@@ -167,30 +190,41 @@ class RMSprop(Optimizer):
|
||||
lr: float >= 0. Learning rate.
|
||||
rho: float >= 0.
|
||||
epsilon: float >= 0. Fuzz factor.
|
||||
decay: float >= 0. Learning rate decay over each update.
|
||||
'''
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, **kwargs):
|
||||
def __init__(self, lr=0.001, rho=0.9, epsilon=1e-8, decay=0.,
|
||||
**kwargs):
|
||||
super(RMSprop, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
self.rho = K.variable(rho)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
self.iterations = K.variable(0.)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
# accumulators
|
||||
self.weights = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
accumulators = [K.zeros(shape) for shape in shapes]
|
||||
self.weights = accumulators
|
||||
self.updates = []
|
||||
|
||||
for p, g, a in zip(params, grads, self.weights):
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates.append(K.update_add(self.iterations, 1))
|
||||
|
||||
for p, g, a in zip(params, grads, accumulators):
|
||||
# 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)
|
||||
self.updates.append(K.update(a, new_a))
|
||||
new_p = p - lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
self.updates.append(K.update(p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
@@ -210,27 +244,39 @@ class Adagrad(Optimizer):
|
||||
# Arguments
|
||||
lr: float >= 0. Learning rate.
|
||||
epsilon: float >= 0.
|
||||
|
||||
# References
|
||||
- [Adaptive Subgradient Methods for Online Learning and Stochastic Optimization](http://www.jmlr.org/papers/volume12/duchi11a/duchi11a.pdf)
|
||||
'''
|
||||
def __init__(self, lr=0.01, epsilon=1e-8, **kwargs):
|
||||
def __init__(self, lr=0.01, epsilon=1e-8, decay=0., **kwargs):
|
||||
super(Adagrad, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
self.iterations = K.variable(0.)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
# accumulators
|
||||
self.weights = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
accumulators = [K.zeros(shape) for shape in shapes]
|
||||
self.weights = accumulators
|
||||
self.updates = []
|
||||
|
||||
for p, g, a in zip(params, grads, self.weights):
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates.append(K.update_add(self.iterations, 1))
|
||||
|
||||
for p, g, a in zip(params, grads, accumulators):
|
||||
new_a = a + K.square(g) # update accumulator
|
||||
self.updates.append((a, new_a))
|
||||
new_p = p - self.lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
self.updates.append(K.update(a, new_a))
|
||||
new_p = p - lr * g / (K.sqrt(new_a) + self.epsilon)
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
self.updates.append(K.update(p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
@@ -255,36 +301,46 @@ 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-8, **kwargs):
|
||||
def __init__(self, lr=1.0, rho=0.95, epsilon=1e-8, decay=0.,
|
||||
**kwargs):
|
||||
super(Adadelta, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.lr = K.variable(lr)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
self.iterations = K.variable(0.)
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
delta_accumulators = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
accumulators = [K.zeros(shape) for shape in shapes]
|
||||
delta_accumulators = [K.zeros(shape) for shape in shapes]
|
||||
self.weights = accumulators + delta_accumulators
|
||||
self.updates = []
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
self.updates.append(K.update_add(self.iterations, 1))
|
||||
|
||||
for p, g, a, d_a in zip(params, grads, accumulators, delta_accumulators):
|
||||
# update accumulator
|
||||
new_a = self.rho * a + (1. - self.rho) * K.square(g)
|
||||
self.updates.append((a, new_a))
|
||||
self.updates.append(K.update(a, new_a))
|
||||
|
||||
# use the new accumulator and the *old* delta_accumulator
|
||||
update = g * K.sqrt(d_a + self.epsilon) / K.sqrt(new_a + self.epsilon)
|
||||
|
||||
new_p = p - self.lr * update
|
||||
new_p = p - lr * update
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
self.updates.append(K.update(p, new_p))
|
||||
|
||||
# update delta_accumulator
|
||||
new_d_a = self.rho * d_a + (1 - self.rho) * K.square(update)
|
||||
self.updates.append((d_a, new_d_a))
|
||||
self.updates.append(K.update(d_a, new_d_a))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
@@ -309,39 +365,46 @@ class Adam(Optimizer):
|
||||
- [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, **kwargs):
|
||||
epsilon=1e-8, decay=0., **kwargs):
|
||||
super(Adam, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0)
|
||||
self.lr = K.variable(lr)
|
||||
self.beta_1 = K.variable(beta_1)
|
||||
self.beta_2 = K.variable(beta_2)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [(self.iterations, self.iterations + 1)]
|
||||
self.updates = [K.update_add(self.iterations, 1)]
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
|
||||
t = self.iterations + 1
|
||||
lr_t = self.lr * K.sqrt(1. - K.pow(self.beta_2, t)) / (1. - K.pow(self.beta_1, t))
|
||||
lr_t = lr * K.sqrt(1. - K.pow(self.beta_2, t)) / (1. - K.pow(self.beta_1, t))
|
||||
|
||||
ms = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
vs = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
self.weights = ms + vs
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
ms = [K.zeros(shape) for shape in shapes]
|
||||
vs = [K.zeros(shape) for shape in shapes]
|
||||
self.weights = [self.iterations] + ms + vs
|
||||
|
||||
for p, g, m, v in zip(params, grads, ms, vs):
|
||||
m_t = (self.beta_1 * m) + (1. - self.beta_1) * g
|
||||
v_t = (self.beta_2 * v) + (1. - self.beta_2) * K.square(g)
|
||||
p_t = p - lr_t * m_t / (K.sqrt(v_t) + self.epsilon)
|
||||
|
||||
self.updates.append((m, m_t))
|
||||
self.updates.append((v, v_t))
|
||||
self.updates.append(K.update(m, m_t))
|
||||
self.updates.append(K.update(v, v_t))
|
||||
|
||||
new_p = p_t
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
self.updates.append(K.update(p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
@@ -368,26 +431,33 @@ class Adamax(Optimizer):
|
||||
- [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, **kwargs):
|
||||
epsilon=1e-8, decay=0., **kwargs):
|
||||
super(Adamax, self).__init__(**kwargs)
|
||||
self.__dict__.update(locals())
|
||||
self.iterations = K.variable(0.)
|
||||
self.lr = K.variable(lr)
|
||||
self.beta_1 = K.variable(beta_1)
|
||||
self.beta_2 = K.variable(beta_2)
|
||||
self.decay = K.variable(decay)
|
||||
self.inital_decay = decay
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [(self.iterations, self.iterations + 1)]
|
||||
self.updates = [K.update_add(self.iterations, 1)]
|
||||
|
||||
lr = self.lr
|
||||
if self.inital_decay > 0:
|
||||
lr *= (1. / (1. + self.decay * self.iterations))
|
||||
|
||||
t = self.iterations + 1
|
||||
lr_t = self.lr / (1. - K.pow(self.beta_1, t))
|
||||
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
# zero init of 1st moment
|
||||
ms = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
ms = [K.zeros(shape) for shape in shapes]
|
||||
# zero init of exponentially weighted infinity norm
|
||||
us = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
self.weights = ms + us
|
||||
us = [K.zeros(shape) for shape in shapes]
|
||||
self.weights = [self.iterations] + ms + us
|
||||
|
||||
for p, g, m, u in zip(params, grads, ms, us):
|
||||
|
||||
@@ -395,15 +465,15 @@ class Adamax(Optimizer):
|
||||
u_t = K.maximum(self.beta_2 * u, K.abs(g))
|
||||
p_t = p - lr_t * m_t / (u_t + self.epsilon)
|
||||
|
||||
self.updates.append((m, m_t))
|
||||
self.updates.append((u, u_t))
|
||||
self.updates.append(K.update(m, m_t))
|
||||
self.updates.append(K.update(u, u_t))
|
||||
|
||||
new_p = p_t
|
||||
# apply constraints
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
self.updates.append(K.update(p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
@@ -430,9 +500,8 @@ class Nadam(Optimizer):
|
||||
epsilon: float >= 0. Fuzz factor.
|
||||
|
||||
# References
|
||||
[1] Nadam report - http://cs229.stanford.edu/proj2015/054_report.pdf
|
||||
[2] On the importance of initialization and momentum in deep learning -
|
||||
http://www.cs.toronto.edu/~fritz/absps/momentum.pdf
|
||||
- [Nadam report](http://cs229.stanford.edu/proj2015/054_report.pdf)
|
||||
- [On the importance of initialization and momentum in deep learning](http://www.cs.toronto.edu/~fritz/absps/momentum.pdf)
|
||||
'''
|
||||
def __init__(self, lr=0.002, beta_1=0.9, beta_2=0.999,
|
||||
epsilon=1e-8, schedule_decay=0.004, **kwargs):
|
||||
@@ -447,7 +516,7 @@ class Nadam(Optimizer):
|
||||
|
||||
def get_updates(self, params, constraints, loss):
|
||||
grads = self.get_gradients(loss, params)
|
||||
self.updates = [(self.iterations, self.iterations + 1)]
|
||||
self.updates = [K.update_add(self.iterations, 1)]
|
||||
|
||||
t = self.iterations + 1
|
||||
|
||||
@@ -458,10 +527,11 @@ class Nadam(Optimizer):
|
||||
m_schedule_next = self.m_schedule * momentum_cache_t * momentum_cache_t_1
|
||||
self.updates.append((self.m_schedule, m_schedule_new))
|
||||
|
||||
ms = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
vs = [K.variable(np.zeros(K.get_value(p).shape)) for p in params]
|
||||
shapes = [K.get_variable_shape(p) for p in params]
|
||||
ms = [K.zeros(shape) for shape in shapes]
|
||||
vs = [K.zeros(shape) for shape in shapes]
|
||||
|
||||
self.weights = ms + vs
|
||||
self.weights = [self.iterations] + ms + vs
|
||||
|
||||
for p, g, m, v in zip(params, grads, ms, vs):
|
||||
# the following equations given in [1]
|
||||
@@ -472,8 +542,8 @@ class Nadam(Optimizer):
|
||||
v_t_prime = v_t / (1. - K.pow(self.beta_2, t))
|
||||
m_t_bar = (1. - momentum_cache_t) * g_prime + momentum_cache_t_1 * m_t_prime
|
||||
|
||||
self.updates.append((m, m_t))
|
||||
self.updates.append((v, v_t))
|
||||
self.updates.append(K.update(m, m_t))
|
||||
self.updates.append(K.update(v, v_t))
|
||||
|
||||
p_t = p - self.lr * m_t_bar / (K.sqrt(v_t_prime) + self.epsilon)
|
||||
new_p = p_t
|
||||
@@ -482,7 +552,7 @@ class Nadam(Optimizer):
|
||||
if p in constraints:
|
||||
c = constraints[p]
|
||||
new_p = c(new_p)
|
||||
self.updates.append((p, new_p))
|
||||
self.updates.append(K.update(p, new_p))
|
||||
return self.updates
|
||||
|
||||
def get_config(self):
|
||||
|
||||
@@ -118,13 +118,17 @@ def flip_axis(x, axis):
|
||||
return x
|
||||
|
||||
|
||||
def array_to_img(x, dim_ordering=K.image_dim_ordering(), scale=True):
|
||||
def array_to_img(x, dim_ordering='default', scale=True):
|
||||
from PIL import Image
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
if dim_ordering == 'th':
|
||||
x = x.transpose(1, 2, 0)
|
||||
if scale:
|
||||
x += max(-np.min(x), 0)
|
||||
x /= np.max(x)
|
||||
x_max = np.max(x)
|
||||
if x_max != 0:
|
||||
x /= x_max
|
||||
x *= 255
|
||||
if x.shape[2] == 3:
|
||||
# RGB
|
||||
@@ -136,7 +140,9 @@ def array_to_img(x, dim_ordering=K.image_dim_ordering(), scale=True):
|
||||
raise Exception('Unsupported channel number: ', x.shape[2])
|
||||
|
||||
|
||||
def img_to_array(img, dim_ordering=K.image_dim_ordering()):
|
||||
def img_to_array(img, dim_ordering='default'):
|
||||
if dim_ordering == 'default':
|
||||
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)
|
||||
@@ -155,6 +161,14 @@ def img_to_array(img, dim_ordering=K.image_dim_ordering()):
|
||||
|
||||
|
||||
def load_img(path, grayscale=False, target_size=None):
|
||||
'''Load an image into PIL format.
|
||||
|
||||
# Arguments
|
||||
path: path to image file
|
||||
grayscale: boolean
|
||||
target_size: None (default to original size)
|
||||
or (img_height, img_width)
|
||||
'''
|
||||
from PIL import Image
|
||||
img = Image.open(path)
|
||||
if grayscale:
|
||||
@@ -162,7 +176,7 @@ def load_img(path, grayscale=False, target_size=None):
|
||||
else: # Ensure 3 channel even when loaded image is grayscale
|
||||
img = img.convert('RGB')
|
||||
if target_size:
|
||||
img = img.resize(target_size)
|
||||
img = img.resize((target_size[1], target_size[0]))
|
||||
return img
|
||||
|
||||
|
||||
@@ -222,7 +236,9 @@ class ImageDataGenerator(object):
|
||||
horizontal_flip=False,
|
||||
vertical_flip=False,
|
||||
rescale=None,
|
||||
dim_ordering=K.image_dim_ordering()):
|
||||
dim_ordering='default'):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.__dict__.update(locals())
|
||||
self.mean = None
|
||||
self.std = None
|
||||
@@ -446,12 +462,14 @@ class NumpyArrayIterator(Iterator):
|
||||
|
||||
def __init__(self, X, y, image_data_generator,
|
||||
batch_size=32, shuffle=False, seed=None,
|
||||
dim_ordering=K.image_dim_ordering(),
|
||||
dim_ordering='default',
|
||||
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))
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.X = X
|
||||
self.y = y
|
||||
self.image_data_generator = image_data_generator
|
||||
@@ -493,10 +511,12 @@ class DirectoryIterator(Iterator):
|
||||
|
||||
def __init__(self, directory, image_data_generator,
|
||||
target_size=(256, 256), color_mode='rgb',
|
||||
dim_ordering=K.image_dim_ordering,
|
||||
dim_ordering='default',
|
||||
classes=None, class_mode='categorical',
|
||||
batch_size=32, shuffle=True, seed=None,
|
||||
save_to_dir=None, save_prefix='', save_format='jpeg'):
|
||||
if dim_ordering == 'default':
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
self.directory = directory
|
||||
self.image_data_generator = image_data_generator
|
||||
self.target_size = tuple(target_size)
|
||||
|
||||
@@ -138,7 +138,7 @@ def skipgrams(sequence, vocabulary_size,
|
||||
continue
|
||||
couples.append([wi, wj])
|
||||
if categorical:
|
||||
labels.append([0,1])
|
||||
labels.append([0, 1])
|
||||
else:
|
||||
labels.append(1)
|
||||
|
||||
@@ -149,12 +149,12 @@ def skipgrams(sequence, vocabulary_size,
|
||||
|
||||
couples += [[words[i %len(words)], random.randint(1, vocabulary_size-1)] for i in range(nb_negative_samples)]
|
||||
if categorical:
|
||||
labels += [[1,0]]*nb_negative_samples
|
||||
labels += [[1, 0]]*nb_negative_samples
|
||||
else:
|
||||
labels += [0]*nb_negative_samples
|
||||
|
||||
if shuffle:
|
||||
seed = random.randint(0,10e6)
|
||||
seed = random.randint(0, 10e6)
|
||||
random.seed(seed)
|
||||
random.shuffle(couples)
|
||||
random.seed(seed)
|
||||
|
||||
@@ -99,6 +99,7 @@ class Tokenizer(object):
|
||||
wcounts = list(self.word_counts.items())
|
||||
wcounts.sort(key=lambda x: x[1], reverse=True)
|
||||
sorted_voc = [wc[0] for wc in wcounts]
|
||||
# note that index 0 is reserved, never assigned to an existing word
|
||||
self.word_index = dict(list(zip(sorted_voc, list(range(1, len(sorted_voc) + 1)))))
|
||||
|
||||
self.index_docs = {}
|
||||
|
||||
+32
-12
@@ -1,8 +1,10 @@
|
||||
from __future__ import absolute_import
|
||||
from . import backend as K
|
||||
from .utils.generic_utils import get_from_module
|
||||
|
||||
|
||||
class Regularizer(object):
|
||||
|
||||
def set_param(self, p):
|
||||
self.p = p
|
||||
|
||||
@@ -29,6 +31,9 @@ class EigenvalueRegularizer(Regularizer):
|
||||
self.uses_learning_phase = True
|
||||
|
||||
def set_param(self, p):
|
||||
if hasattr(self, 'p'):
|
||||
raise Exception('Regularizers cannot be reused. '
|
||||
'Instantiate one regularizer per layer.')
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
@@ -43,30 +48,37 @@ class EigenvalueRegularizer(Regularizer):
|
||||
|
||||
# power method for approximating the dominant eigenvector:
|
||||
o = K.ones([dim1, 1]) # initial values for the dominant eigenvector
|
||||
domin_eigenvect = K.dot(WW, o)
|
||||
main_eigenvect = K.dot(WW, o)
|
||||
for n in range(power - 1):
|
||||
domin_eigenvect = K.dot(WW, domin_eigenvect)
|
||||
main_eigenvect = K.dot(WW, main_eigenvect)
|
||||
|
||||
WWd = K.dot(WW, domin_eigenvect)
|
||||
WWd = K.dot(WW, main_eigenvect)
|
||||
|
||||
# the corresponding dominant eigenvalue:
|
||||
domin_eigenval = K.dot(K.transpose(WWd), domin_eigenvect) / K.dot(K.transpose(domin_eigenvect), domin_eigenvect)
|
||||
regularized_loss = loss + (domin_eigenval ** 0.5) * self.k # multiplied by the given regularization gain
|
||||
main_eigenval = (K.dot(K.transpose(WWd), main_eigenvect) /
|
||||
K.dot(K.transpose(main_eigenvect), main_eigenvect))
|
||||
# multiplied by the given regularization gain
|
||||
regularized_loss = loss + (main_eigenval ** 0.5) * self.k
|
||||
|
||||
return K.in_train_phase(regularized_loss[0, 0], loss)
|
||||
|
||||
|
||||
class WeightRegularizer(Regularizer):
|
||||
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
self.l1 = K.cast_to_floatx(l1)
|
||||
self.l2 = K.cast_to_floatx(l2)
|
||||
self.uses_learning_phase = True
|
||||
self.p = None
|
||||
|
||||
def set_param(self, p):
|
||||
if self.p is not None:
|
||||
raise Exception('Regularizers cannot be reused. '
|
||||
'Instantiate one regularizer per layer.')
|
||||
self.p = p
|
||||
|
||||
def __call__(self, loss):
|
||||
if not hasattr(self, 'p'):
|
||||
if self.p is None:
|
||||
raise Exception('Need to call `set_param` on '
|
||||
'WeightRegularizer instance '
|
||||
'before calling the instance. '
|
||||
@@ -75,8 +87,11 @@ class WeightRegularizer(Regularizer):
|
||||
'ActivityRegularizer '
|
||||
'(i.e. activity_regularizer="l2" instead '
|
||||
'of activity_regularizer="activity_l2".')
|
||||
regularized_loss = loss + K.sum(K.abs(self.p)) * self.l1
|
||||
regularized_loss += K.sum(K.square(self.p)) * self.l2
|
||||
regularized_loss = loss
|
||||
if self.l1:
|
||||
regularized_loss += K.sum(self.l1 * K.abs(self.p))
|
||||
if self.l2:
|
||||
regularized_loss += K.sum(self.l2 * K.square(self.p))
|
||||
return K.in_train_phase(regularized_loss, loss)
|
||||
|
||||
def get_config(self):
|
||||
@@ -86,24 +101,30 @@ class WeightRegularizer(Regularizer):
|
||||
|
||||
|
||||
class ActivityRegularizer(Regularizer):
|
||||
|
||||
def __init__(self, l1=0., l2=0.):
|
||||
self.l1 = K.cast_to_floatx(l1)
|
||||
self.l2 = K.cast_to_floatx(l2)
|
||||
self.uses_learning_phase = True
|
||||
self.layer = None
|
||||
|
||||
def set_layer(self, layer):
|
||||
if self.layer is not None:
|
||||
raise Exception('Regularizers cannot be reused')
|
||||
self.layer = layer
|
||||
|
||||
def __call__(self, loss):
|
||||
if not hasattr(self, 'layer'):
|
||||
if self.layer is None:
|
||||
raise Exception('Need to call `set_layer` on '
|
||||
'ActivityRegularizer instance '
|
||||
'before calling the instance.')
|
||||
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))
|
||||
if self.l1:
|
||||
regularized_loss += K.sum(self.l1 * K.abs(output))
|
||||
if self.l2:
|
||||
regularized_loss += K.sum(self.l2 * K.square(output))
|
||||
return K.in_train_phase(regularized_loss, loss)
|
||||
|
||||
def get_config(self):
|
||||
@@ -136,7 +157,6 @@ def activity_l1l2(l1=0.01, l2=0.01):
|
||||
return ActivityRegularizer(l1=l1, l2=l2)
|
||||
|
||||
|
||||
from .utils.generic_utils import get_from_module
|
||||
def get(identifier, kwargs=None):
|
||||
return get_from_module(identifier, globals(), 'regularizer',
|
||||
instantiate=True, kwargs=kwargs)
|
||||
|
||||
@@ -5,6 +5,7 @@ import tarfile
|
||||
import os
|
||||
import sys
|
||||
import shutil
|
||||
import hashlib
|
||||
from six.moves.urllib.request import urlopen
|
||||
from six.moves.urllib.error import URLError, HTTPError
|
||||
|
||||
@@ -21,9 +22,10 @@ if sys.version_info[0] == 2:
|
||||
count = 0
|
||||
while 1:
|
||||
chunk = response.read(chunk_size)
|
||||
if not chunk:
|
||||
break
|
||||
count += 1
|
||||
if not chunk:
|
||||
reporthook(count, total_size, total_size)
|
||||
break
|
||||
if reporthook:
|
||||
reporthook(count, chunk_size, total_size)
|
||||
yield chunk
|
||||
@@ -36,11 +38,12 @@ else:
|
||||
from six.moves.urllib.request import urlretrieve
|
||||
|
||||
|
||||
def get_file(fname, origin, untar=False):
|
||||
def get_file(fname, origin, untar=False,
|
||||
md5_hash=None, cache_subdir='datasets'):
|
||||
datadir_base = os.path.expanduser(os.path.join('~', '.keras'))
|
||||
if not os.access(datadir_base, os.W_OK):
|
||||
datadir_base = os.path.join('/tmp', '.keras')
|
||||
datadir = os.path.join(datadir_base, 'datasets')
|
||||
datadir = os.path.join(datadir_base, cache_subdir)
|
||||
if not os.path.exists(datadir):
|
||||
os.makedirs(datadir)
|
||||
|
||||
@@ -50,8 +53,19 @@ def get_file(fname, origin, untar=False):
|
||||
else:
|
||||
fpath = os.path.join(datadir, fname)
|
||||
|
||||
if not os.path.exists(fpath):
|
||||
print('Downloading data from', origin)
|
||||
download = False
|
||||
if os.path.exists(fpath):
|
||||
# file found; verify integrity if a hash was provided
|
||||
if md5_hash is not None:
|
||||
if not validate_file(fpath, md5_hash):
|
||||
print('A local file was found, but it seems to be '
|
||||
'incomplete or outdated.')
|
||||
download = True
|
||||
else:
|
||||
download = True
|
||||
|
||||
if download:
|
||||
print('Downloading data from', origin)
|
||||
global progbar
|
||||
progbar = None
|
||||
|
||||
@@ -60,7 +74,7 @@ def get_file(fname, origin, untar=False):
|
||||
if progbar is None:
|
||||
progbar = Progbar(total_size)
|
||||
else:
|
||||
progbar.update(count*block_size)
|
||||
progbar.update(count * block_size)
|
||||
|
||||
error_msg = 'URL fetch failure on {}: {} -- {}'
|
||||
try:
|
||||
@@ -93,3 +107,14 @@ def get_file(fname, origin, untar=False):
|
||||
return untar_fpath
|
||||
|
||||
return fpath
|
||||
|
||||
|
||||
def validate_file(fpath, md5_hash):
|
||||
hasher = hashlib.md5()
|
||||
with open(fpath, 'rb') as f:
|
||||
buf = f.read()
|
||||
hasher.update(buf)
|
||||
if str(hasher.hexdigest()) == str(md5_hash):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -3,6 +3,8 @@ import numpy as np
|
||||
import time
|
||||
import sys
|
||||
import six
|
||||
import marshal
|
||||
import types as python_types
|
||||
|
||||
|
||||
def get_from_module(identifier, module_params, module_name,
|
||||
@@ -33,6 +35,43 @@ def make_tuple(*args):
|
||||
return args
|
||||
|
||||
|
||||
def func_dump(func):
|
||||
'''Serialize user defined function.'''
|
||||
code = marshal.dumps(func.__code__).decode('raw_unicode_escape')
|
||||
defaults = func.__defaults__
|
||||
if func.__closure__:
|
||||
closure = tuple(c.cell_contents for c in func.__closure__)
|
||||
else:
|
||||
closure = None
|
||||
return code, defaults, closure
|
||||
|
||||
|
||||
def func_load(code, defaults=None, closure=None, globs=None):
|
||||
'''Deserialize user defined function.'''
|
||||
if isinstance(code, (tuple, list)): # unpack previous dump
|
||||
code, defaults, closure = code
|
||||
code = marshal.loads(code.encode('raw_unicode_escape'))
|
||||
if closure is not None:
|
||||
closure = func_reconstruct_closure(closure)
|
||||
if globs is None:
|
||||
globs = globals()
|
||||
return python_types.FunctionType(code, globs, name=code.co_name, argdefs=defaults, closure=closure)
|
||||
|
||||
|
||||
def func_reconstruct_closure(values):
|
||||
'''Deserialization helper that reconstructs a closure.'''
|
||||
nums = range(len(values))
|
||||
src = ["def func(arg):"]
|
||||
src += [" _%d = arg[%d]" % (n, n) for n in nums]
|
||||
src += [" return lambda:(%s)" % ','.join(["_%d" % n for n in nums]), ""]
|
||||
src = '\n'.join(src)
|
||||
try:
|
||||
exec(src)
|
||||
except:
|
||||
raise SyntaxError(src)
|
||||
return func(values).__closure__
|
||||
|
||||
|
||||
class Progbar(object):
|
||||
def __init__(self, target, width=30, verbose=1, interval=0.01):
|
||||
'''
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import absolute_import
|
||||
import h5py
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
|
||||
@@ -8,6 +9,8 @@ class HDF5Matrix():
|
||||
refs = defaultdict(int)
|
||||
|
||||
def __init__(self, datapath, dataset, start, end, normalizer=None):
|
||||
import h5py
|
||||
|
||||
if datapath not in list(self.refs.keys()):
|
||||
f = h5py.File(datapath)
|
||||
self.refs[datapath] = f
|
||||
@@ -29,7 +32,7 @@ class HDF5Matrix():
|
||||
raise IndexError
|
||||
elif isinstance(key, int):
|
||||
if key + self.start < self.end:
|
||||
idx = key+self.start
|
||||
idx = key + self.start
|
||||
else:
|
||||
raise IndexError
|
||||
elif isinstance(key, np.ndarray):
|
||||
@@ -49,7 +52,7 @@ class HDF5Matrix():
|
||||
|
||||
@property
|
||||
def shape(self):
|
||||
return tuple([self.end - self.start, self.data.shape[1]])
|
||||
return (self.end - self.start,) + self.data.shape[1:]
|
||||
|
||||
|
||||
def save_array(array, name):
|
||||
@@ -69,3 +72,17 @@ def load_array(name):
|
||||
a[:] = array[:]
|
||||
f.close()
|
||||
return a
|
||||
|
||||
|
||||
def ask_to_proceed_with_overwrite(filepath):
|
||||
get_input = input
|
||||
if sys.version_info[:2] <= (2, 7):
|
||||
get_input = raw_input
|
||||
overwrite = get_input('[WARNING] %s already exists - overwrite? '
|
||||
'[y/n]' % (filepath))
|
||||
while overwrite not in ['y', 'n']:
|
||||
overwrite = get_input('Enter "y" (overwrite) or "n" (cancel).')
|
||||
if overwrite == 'n':
|
||||
return False
|
||||
print('[TIP] Next time specify overwrite=True!')
|
||||
return True
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from __future__ import print_function
|
||||
|
||||
from .generic_utils import get_from_module
|
||||
from .np_utils import convert_kernel
|
||||
from ..layers import *
|
||||
from ..models import Model, Sequential, Graph
|
||||
from .. import backend as K
|
||||
@@ -97,3 +98,22 @@ def print_summary(layers, relevant_nodes=None, line_length=100, positions=[.33,
|
||||
|
||||
print('Total params: %s' % total_params)
|
||||
print('_' * line_length)
|
||||
|
||||
|
||||
def convert_all_kernels_in_model(model):
|
||||
# Note: SeparableConvolution not included
|
||||
# since only supported by TF.
|
||||
conv_classes = {
|
||||
'Convolution1D',
|
||||
'Convolution2D',
|
||||
'Convolution3D',
|
||||
'AtrousConvolution2D',
|
||||
'Deconvolution2D',
|
||||
}
|
||||
to_assign = []
|
||||
for layer in model.layers:
|
||||
if layer.__class__.__name__ in conv_classes:
|
||||
original_w = K.get_value(layer.W)
|
||||
converted_w = convert_kernel(original_w)
|
||||
to_assign.append((layer.W, converted_w))
|
||||
K.batch_set_value(to_assign)
|
||||
|
||||
@@ -120,3 +120,14 @@ def conv_output_length(input_length, filter_size, border_mode, stride, dilation=
|
||||
elif border_mode == 'valid':
|
||||
output_length = input_length - dilated_filter_size + 1
|
||||
return (output_length + stride - 1) // stride
|
||||
|
||||
|
||||
def conv_input_length(output_length, filter_size, border_mode, stride):
|
||||
if output_length is None:
|
||||
return None
|
||||
assert border_mode in {'same', 'valid'}
|
||||
if border_mode == 'same':
|
||||
pad = filter_size // 2
|
||||
elif border_mode == 'valid':
|
||||
pad = 0
|
||||
return (output_length - 1) * stride - 2 * pad + filter_size
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
import inspect
|
||||
import functools
|
||||
|
||||
from ..engine import Model, Input
|
||||
from ..models import Sequential, model_from_json
|
||||
@@ -35,7 +36,8 @@ def get_test_data(nb_train=1000, nb_test=500, input_shape=(10,),
|
||||
|
||||
|
||||
def layer_test(layer_cls, kwargs={}, input_shape=None, input_dtype=None,
|
||||
input_data=None, expected_output=None, expected_output_dtype=None):
|
||||
input_data=None, expected_output=None,
|
||||
expected_output_dtype=None, fixed_batch_size=False):
|
||||
'''Test routine for a layer with a single input tensor
|
||||
and single output tensor.
|
||||
'''
|
||||
@@ -63,7 +65,10 @@ def layer_test(layer_cls, kwargs={}, input_shape=None, input_dtype=None,
|
||||
layer = layer_cls(**kwargs)
|
||||
|
||||
# test in functional API
|
||||
x = Input(shape=input_shape[1:], dtype=input_dtype)
|
||||
if fixed_batch_size:
|
||||
x = Input(batch_shape=input_shape, dtype=input_dtype)
|
||||
else:
|
||||
x = Input(shape=input_shape[1:], dtype=input_dtype)
|
||||
y = layer(x)
|
||||
assert K.dtype(y) == expected_output_dtype
|
||||
|
||||
@@ -102,3 +107,15 @@ def layer_test(layer_cls, kwargs={}, input_shape=None, input_dtype=None,
|
||||
|
||||
# for further checks in the caller function
|
||||
return actual_output
|
||||
|
||||
|
||||
def keras_test(func):
|
||||
'''Clean up after tensorflow tests.
|
||||
'''
|
||||
@functools.wraps(func)
|
||||
def wrapper(*args, **kwargs):
|
||||
output = func(*args, **kwargs)
|
||||
if K._BACKEND == 'tensorflow':
|
||||
K.clear_session()
|
||||
return output
|
||||
return wrapper
|
||||
|
||||
@@ -78,7 +78,7 @@ class BaseWrapper(object):
|
||||
|
||||
for params_name in params:
|
||||
if params_name not in legal_params:
|
||||
assert False, '{} is not a legal parameter'.format(params_name)
|
||||
raise ValueError('{} is not a legal parameter'.format(params_name))
|
||||
|
||||
def get_params(self, deep=True):
|
||||
'''Get parameters for this estimator.
|
||||
@@ -234,6 +234,13 @@ class KerasClassifier(BaseWrapper):
|
||||
Mean accuracy of predictions on X wrt. y.
|
||||
'''
|
||||
kwargs = self.filter_sk_params(Sequential.evaluate, kwargs)
|
||||
|
||||
loss_name = self.model.loss
|
||||
if hasattr(loss_name, '__name__'):
|
||||
loss_name = loss_name.__name__
|
||||
if loss_name == 'categorical_crossentropy' and len(y.shape) != 2:
|
||||
y = to_categorical(y)
|
||||
|
||||
outputs = self.model.evaluate(X, y, **kwargs)
|
||||
if type(outputs) is not list:
|
||||
outputs = [outputs]
|
||||
@@ -263,7 +270,7 @@ class KerasRegressor(BaseWrapper):
|
||||
Predictions.
|
||||
'''
|
||||
kwargs = self.filter_sk_params(Sequential.predict, kwargs)
|
||||
return self.model.predict(X, **kwargs)
|
||||
return np.squeeze(self.model.predict(X, **kwargs))
|
||||
|
||||
def score(self, X, y, **kwargs):
|
||||
'''Returns the mean loss on the given test data and labels.
|
||||
|
||||
@@ -13,26 +13,20 @@ norecursedirs= build
|
||||
# E251 unexpected spaces around keyword / parameter equals
|
||||
# E225 missing whitespace around operator
|
||||
# E226 missing whitespace around arithmetic operator
|
||||
# W291 trailing whitespace
|
||||
# W293 blank line contains whitespace
|
||||
# E501 line too long (82 > 79 characters)
|
||||
# E402 module level import not at top of file - temporary measure to coninue adding ros python packaged in sys.path
|
||||
# E731 do not assign a lambda expression, use a def
|
||||
# E302 two blank lines between the functions
|
||||
# E231 missing whitespace after ,
|
||||
# E241 multiple spaces after ','
|
||||
# E261 at least two spaces before inline comment
|
||||
|
||||
|
||||
pep8ignore=* E251 \
|
||||
* E225 \
|
||||
* E226 \
|
||||
* W291 \
|
||||
* W293 \
|
||||
* E501 \
|
||||
* E402 \
|
||||
* E731 \
|
||||
* E302 \
|
||||
* E231 \
|
||||
* E241 \
|
||||
* E261
|
||||
|
||||
+3
-2
@@ -3,15 +3,16 @@ from setuptools import find_packages
|
||||
|
||||
|
||||
setup(name='Keras',
|
||||
version='1.0.6',
|
||||
version='1.1.0',
|
||||
description='Deep Learning for Python',
|
||||
author='Francois Chollet',
|
||||
author_email='francois.chollet@gmail.com',
|
||||
url='https://github.com/fchollet/keras',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.0.6',
|
||||
download_url='https://github.com/fchollet/keras/tarball/1.1.0',
|
||||
license='MIT',
|
||||
install_requires=['theano', 'pyyaml', 'six'],
|
||||
extras_require={
|
||||
'h5py': ['h5py'],
|
||||
'visualize': ['pydot-ng'],
|
||||
},
|
||||
packages=find_packages())
|
||||
|
||||
@@ -2,20 +2,21 @@ from __future__ import print_function
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from keras.utils.test_utils import get_test_data
|
||||
from keras.utils.test_utils import get_test_data, keras_test
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense, Flatten, Activation
|
||||
from keras.layers.convolutional import Convolution2D, MaxPooling2D
|
||||
from keras.utils.np_utils import to_categorical
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_image_classification():
|
||||
'''
|
||||
Classify random 16x16 color images into several classes using logistic regression
|
||||
with convolutional hidden layer.
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
input_shape = (3, 16, 16)
|
||||
input_shape = (16, 16, 3)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=200,
|
||||
input_shape=input_shape,
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
from __future__ import print_function
|
||||
import numpy as np
|
||||
np.random.seed(1337)
|
||||
import pytest
|
||||
import string
|
||||
|
||||
from keras.utils.test_utils import get_test_data
|
||||
from keras.utils.test_utils import get_test_data, keras_test
|
||||
from keras.utils.np_utils import to_categorical
|
||||
from keras.models import Sequential
|
||||
from keras.layers import TimeDistributedDense
|
||||
@@ -14,6 +15,7 @@ from keras.layers import LSTM
|
||||
from keras.layers import Embedding
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_temporal_classification():
|
||||
'''
|
||||
Classify temporal sequences of float numbers
|
||||
@@ -21,7 +23,6 @@ def test_temporal_classification():
|
||||
single layer of GRU units and softmax applied
|
||||
to the last activations of the units
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=500,
|
||||
input_shape=(3, 5),
|
||||
@@ -40,17 +41,17 @@ def test_temporal_classification():
|
||||
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.85)
|
||||
assert(history.history['val_acc'][-1] >= 0.8)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_temporal_regression():
|
||||
'''
|
||||
Predict float numbers (regression) based on sequences
|
||||
of float numbers of length 3 using a single layer of GRU units
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=200,
|
||||
nb_test=400,
|
||||
input_shape=(3, 5),
|
||||
output_shape=(2,),
|
||||
classification=False)
|
||||
@@ -60,9 +61,10 @@ def test_temporal_regression():
|
||||
model.compile(loss='hinge', optimizer='adam')
|
||||
history = model.fit(X_train, y_train, nb_epoch=5, batch_size=16,
|
||||
validation_data=(X_test, y_test), verbose=0)
|
||||
assert(history.history['val_loss'][-1] < 0.75)
|
||||
assert(history.history['val_loss'][-1] < 1.)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_sequence_to_sequence():
|
||||
'''
|
||||
Apply a same Dense layer for each element of time dimension of the input
|
||||
@@ -70,7 +72,6 @@ def test_sequence_to_sequence():
|
||||
This does not make use of the temporal structure of the sequence
|
||||
(see TimeDistributedDense for more details)
|
||||
'''
|
||||
np.random.seed(1337)
|
||||
(X_train, y_train), (X_test, y_test) = get_test_data(nb_train=500,
|
||||
nb_test=200,
|
||||
input_shape=(3, 5),
|
||||
@@ -86,13 +87,13 @@ def test_sequence_to_sequence():
|
||||
assert(history.history['val_loss'][-1] < 0.8)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_stacked_lstm_char_prediction():
|
||||
'''
|
||||
Learn alphabetical char sequence with stacked LSTM.
|
||||
Predict the whole alphabet based on the first two letters ('ab' -> 'ab...z')
|
||||
See non-toy example in examples/lstm_text_generation.py
|
||||
'''
|
||||
np.random.seed(1336)
|
||||
# generate alphabet: http://stackoverflow.com/questions/16060899/alphabet-range-python
|
||||
alphabet = string.ascii_lowercase
|
||||
number_of_chars = len(alphabet)
|
||||
@@ -135,6 +136,7 @@ def test_stacked_lstm_char_prediction():
|
||||
assert(generated == alphabet)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_masked_temporal():
|
||||
'''
|
||||
Confirm that even with masking on both inputs and outputs, cross-entropies are
|
||||
@@ -147,7 +149,6 @@ def test_masked_temporal():
|
||||
The ground-truth best cross-entropy loss should, then be -log(0.5) = 0.69
|
||||
|
||||
'''
|
||||
np.random.seed(55318)
|
||||
model = Sequential()
|
||||
model.add(Embedding(10, 20, mask_zero=True, input_length=20))
|
||||
model.add(TimeDistributedDense(10))
|
||||
@@ -182,5 +183,4 @@ def test_masked_temporal():
|
||||
assert(np.abs(history.history['val_loss'][-1] - ground_truth) < 0.06)
|
||||
|
||||
if __name__ == '__main__':
|
||||
# pytest.main([__file__])
|
||||
test_temporal_classification()
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -2,12 +2,13 @@ from __future__ import print_function
|
||||
import numpy as np
|
||||
import pytest
|
||||
|
||||
from keras.utils.test_utils import get_test_data
|
||||
from keras.utils.test_utils import get_test_data, keras_test
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Dense
|
||||
from keras.utils.np_utils import to_categorical
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_vector_classification():
|
||||
'''
|
||||
Classify random float vectors into 2 classes with logistic regression
|
||||
@@ -37,6 +38,7 @@ def test_vector_classification():
|
||||
assert(history.history['val_acc'][-1] > 0.8)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_vector_regression():
|
||||
'''
|
||||
Perform float data prediction (regression) using 2 layer MLP
|
||||
|
||||
@@ -2,6 +2,7 @@ import sys
|
||||
import pytest
|
||||
from numpy.testing import assert_allclose
|
||||
import numpy as np
|
||||
import scipy.sparse as sparse
|
||||
|
||||
from keras.backend import theano_backend as KTH
|
||||
from keras.backend import tensorflow_backend as KTF
|
||||
@@ -38,6 +39,7 @@ def check_two_tensor_operation(function_name, x_input_shape,
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
|
||||
def check_composed_tensor_operations(first_function_name, first_function_args,
|
||||
second_function_name, second_function_args,
|
||||
input_shape):
|
||||
@@ -59,6 +61,7 @@ def check_composed_tensor_operations(first_function_name, first_function_args,
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
|
||||
class TestBackend(object):
|
||||
|
||||
def test_linear_operations(self):
|
||||
@@ -68,6 +71,8 @@ class TestBackend(object):
|
||||
check_two_tensor_operation('batch_dot', (4, 2, 3), (4, 5, 3),
|
||||
axes=(2, 2))
|
||||
check_single_tensor_operation('transpose', (4, 2))
|
||||
check_single_tensor_operation('reverse', (4, 3, 2), axes=1)
|
||||
check_single_tensor_operation('reverse', (4, 3, 2), axes=(1, 2))
|
||||
|
||||
def test_shape_operations(self):
|
||||
# concatenate
|
||||
@@ -90,14 +95,15 @@ class TestBackend(object):
|
||||
check_single_tensor_operation('expand_dims', (4, 3), dim=-1)
|
||||
check_single_tensor_operation('expand_dims', (4, 3, 2), dim=1)
|
||||
check_single_tensor_operation('squeeze', (4, 3, 1), axis=2)
|
||||
check_composed_tensor_operations('reshape', {'shape':(4,3,1,1)},
|
||||
'squeeze', {'axis':2},
|
||||
check_single_tensor_operation('squeeze', (4, 1, 1), axis=1)
|
||||
check_composed_tensor_operations('reshape', {'shape': (4, 3, 1, 1)},
|
||||
'squeeze', {'axis': 2},
|
||||
(4, 3, 1, 1))
|
||||
|
||||
def test_repeat_elements(self):
|
||||
reps = 3
|
||||
for ndims in [1, 2, 3]:
|
||||
shape = np.arange(2, 2+ndims)
|
||||
shape = np.arange(2, 2 + ndims)
|
||||
arr = np.arange(np.prod(shape)).reshape(shape)
|
||||
arr_th = KTH.variable(arr)
|
||||
arr_tf = KTF.variable(arr)
|
||||
@@ -149,6 +155,17 @@ class TestBackend(object):
|
||||
# count_params
|
||||
assert KTH.count_params(xth) == KTF.count_params(xtf)
|
||||
|
||||
# print_tensor
|
||||
check_single_tensor_operation('print_tensor', ())
|
||||
check_single_tensor_operation('print_tensor', (2,))
|
||||
check_single_tensor_operation('print_tensor', (4, 3))
|
||||
check_single_tensor_operation('print_tensor', (1, 2, 3))
|
||||
|
||||
val = np.random.random((3, 2))
|
||||
xth = KTH.variable(val)
|
||||
xtf = KTF.variable(val)
|
||||
assert KTH.get_variable_shape(xth) == KTF.get_variable_shape(xtf)
|
||||
|
||||
def test_elementwise_operations(self):
|
||||
check_single_tensor_operation('max', (4, 2))
|
||||
check_single_tensor_operation('max', (4, 2), axis=1, keepdims=True)
|
||||
@@ -196,6 +213,11 @@ class TestBackend(object):
|
||||
|
||||
# two-tensor ops
|
||||
check_two_tensor_operation('equal', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('not_equal', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('greater', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('greater_equal', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('lesser', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('lesser_equal', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('maximum', (4, 2), (4, 2))
|
||||
check_two_tensor_operation('minimum', (4, 2), (4, 2))
|
||||
|
||||
@@ -276,6 +298,7 @@ class TestBackend(object):
|
||||
return output, [output]
|
||||
return step_function
|
||||
|
||||
# test default setup
|
||||
th_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTH)
|
||||
th_inputs = KTH.variable(input_val)
|
||||
th_initial_states = [KTH.variable(init_state_val)]
|
||||
@@ -321,6 +344,35 @@ class TestBackend(object):
|
||||
assert_allclose(th_outputs, unrolled_th_outputs, atol=1e-04)
|
||||
assert_allclose(th_state, unrolled_th_state, atol=1e-04)
|
||||
|
||||
# test go_backwards
|
||||
th_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTH)
|
||||
th_inputs = KTH.variable(input_val)
|
||||
th_initial_states = [KTH.variable(init_state_val)]
|
||||
last_output, outputs, new_states = KTH.rnn(th_rnn_step_fn, th_inputs,
|
||||
th_initial_states,
|
||||
go_backwards=True,
|
||||
mask=None)
|
||||
th_last_output = KTH.eval(last_output)
|
||||
th_outputs = KTH.eval(outputs)
|
||||
assert len(new_states) == 1
|
||||
th_state = KTH.eval(new_states[0])
|
||||
|
||||
tf_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTF)
|
||||
tf_inputs = KTF.variable(input_val)
|
||||
tf_initial_states = [KTF.variable(init_state_val)]
|
||||
last_output, outputs, new_states = KTF.rnn(tf_rnn_step_fn, tf_inputs,
|
||||
tf_initial_states,
|
||||
go_backwards=True,
|
||||
mask=None)
|
||||
tf_last_output = KTF.eval(last_output)
|
||||
tf_outputs = KTF.eval(outputs)
|
||||
assert len(new_states) == 1
|
||||
tf_state = KTF.eval(new_states[0])
|
||||
|
||||
assert_allclose(tf_last_output, th_last_output, atol=1e-04)
|
||||
assert_allclose(tf_outputs, th_outputs, atol=1e-04)
|
||||
assert_allclose(tf_state, th_state, atol=1e-04)
|
||||
|
||||
# test unroll with backwards = True
|
||||
bwd_last_output, bwd_outputs, bwd_new_states = KTH.rnn(
|
||||
th_rnn_step_fn, th_inputs,
|
||||
@@ -378,6 +430,50 @@ class TestBackend(object):
|
||||
assert_allclose(unrolled_masked_th_outputs, masked_th_outputs, atol=1e-04)
|
||||
assert_allclose(unrolled_masked_th_state, masked_th_state, atol=1e-04)
|
||||
|
||||
def test_rnn_no_states(self):
|
||||
# implement a simple RNN without states
|
||||
input_dim = 8
|
||||
output_dim = 4
|
||||
timesteps = 5
|
||||
|
||||
input_val = np.random.random((32, timesteps, input_dim))
|
||||
W_i_val = np.random.random((input_dim, output_dim))
|
||||
|
||||
def rnn_step_fn(input_dim, output_dim, K):
|
||||
W_i = K.variable(W_i_val)
|
||||
|
||||
def step_function(x, states):
|
||||
assert len(states) == 0
|
||||
output = K.dot(x, W_i)
|
||||
return output, []
|
||||
return step_function
|
||||
|
||||
# test default setup
|
||||
th_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTH)
|
||||
th_inputs = KTH.variable(input_val)
|
||||
th_initial_states = []
|
||||
last_output, outputs, new_states = KTH.rnn(th_rnn_step_fn, th_inputs,
|
||||
th_initial_states,
|
||||
go_backwards=False,
|
||||
mask=None)
|
||||
th_last_output = KTH.eval(last_output)
|
||||
th_outputs = KTH.eval(outputs)
|
||||
assert len(new_states) == 0
|
||||
|
||||
tf_rnn_step_fn = rnn_step_fn(input_dim, output_dim, KTF)
|
||||
tf_inputs = KTF.variable(input_val)
|
||||
tf_initial_states = []
|
||||
last_output, outputs, new_states = KTF.rnn(tf_rnn_step_fn, tf_inputs,
|
||||
tf_initial_states,
|
||||
go_backwards=False,
|
||||
mask=None)
|
||||
tf_last_output = KTF.eval(last_output)
|
||||
tf_outputs = KTF.eval(outputs)
|
||||
assert len(new_states) == 0
|
||||
|
||||
assert_allclose(tf_last_output, th_last_output, atol=1e-04)
|
||||
assert_allclose(tf_outputs, th_outputs, atol=1e-04)
|
||||
|
||||
def test_switch(self):
|
||||
val = np.random.random()
|
||||
xth = KTH.variable(val)
|
||||
@@ -435,8 +531,8 @@ class TestBackend(object):
|
||||
kernel_th = KTH.variable(convert_kernel(kernel_val))
|
||||
kernel_tf = KTF.variable(kernel_val)
|
||||
|
||||
zth = KTH.eval(KTH.conv2d(xth, kernel_th))
|
||||
ztf = KTF.eval(KTF.conv2d(xtf, kernel_tf))
|
||||
zth = KTH.eval(KTH.conv2d(xth, kernel_th, dim_ordering='th'))
|
||||
ztf = KTF.eval(KTF.conv2d(xtf, kernel_tf, dim_ordering='th'))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
@@ -479,8 +575,8 @@ class TestBackend(object):
|
||||
kernel_th = KTH.variable(convert_kernel(kernel_val))
|
||||
kernel_tf = KTF.variable(kernel_val)
|
||||
|
||||
zth = KTH.eval(KTH.conv3d(xth, kernel_th))
|
||||
ztf = KTF.eval(KTF.conv3d(xtf, kernel_tf))
|
||||
zth = KTH.eval(KTH.conv3d(xth, kernel_th, dim_ordering='th'))
|
||||
ztf = KTF.eval(KTF.conv3d(xtf, kernel_tf, dim_ordering='th'))
|
||||
|
||||
assert zth.shape == ztf.shape
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
@@ -506,23 +602,23 @@ class TestBackend(object):
|
||||
assert_allclose(zth, ztf, atol=1e-05)
|
||||
|
||||
def test_pool2d(self):
|
||||
check_single_tensor_operation('pool2d', (5, 3, 10, 12), pool_size=(2, 2),
|
||||
check_single_tensor_operation('pool2d', (5, 10, 12, 3), pool_size=(2, 2),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool2d', (5, 3, 9, 11), pool_size=(2, 2),
|
||||
check_single_tensor_operation('pool2d', (5, 9, 11, 3), pool_size=(2, 2),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool2d', (5, 3, 9, 11), pool_size=(2, 3),
|
||||
check_single_tensor_operation('pool2d', (5, 9, 11, 3), pool_size=(2, 3),
|
||||
strides=(1, 1), border_mode='valid')
|
||||
|
||||
def test_pool3d(self):
|
||||
check_single_tensor_operation('pool3d', (5, 3, 10, 12, 5), pool_size=(2, 2, 2),
|
||||
check_single_tensor_operation('pool3d', (5, 10, 12, 5, 3), pool_size=(2, 2, 2),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool3d', (5, 3, 9, 11, 5), pool_size=(2, 2, 2),
|
||||
check_single_tensor_operation('pool3d', (5, 9, 11, 5, 3), pool_size=(2, 2, 2),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
check_single_tensor_operation('pool3d', (5, 3, 9, 11, 5), pool_size=(2, 3, 2),
|
||||
check_single_tensor_operation('pool3d', (5, 9, 11, 5, 3), pool_size=(2, 3, 2),
|
||||
strides=(1, 1, 1), border_mode='valid')
|
||||
|
||||
def test_random_normal(self):
|
||||
@@ -567,6 +663,223 @@ class TestBackend(object):
|
||||
assert(np.max(rand) == 1)
|
||||
assert(np.min(rand) == 0)
|
||||
|
||||
def test_ctc(self):
|
||||
# simplified version of TensorFlow's test
|
||||
|
||||
label_lens = np.expand_dims(np.asarray([5, 4]), 1)
|
||||
input_lens = np.expand_dims(np.asarray([5, 5]), 1) # number of timesteps
|
||||
|
||||
# the Theano and Tensorflow CTC code use different methods to ensure
|
||||
# numerical stability. The Theano code subtracts out the max
|
||||
# before the final log, so the results are different but scale
|
||||
# identically and still train properly
|
||||
loss_log_probs_tf = [3.34211, 5.42262]
|
||||
loss_log_probs_th = [1.73308, 3.81351]
|
||||
|
||||
# dimensions are batch x time x categories
|
||||
labels = np.asarray([[0, 1, 2, 1, 0], [0, 1, 1, 0, -1]])
|
||||
inputs = np.asarray(
|
||||
[[[0.633766, 0.221185, 0.0917319, 0.0129757, 0.0142857, 0.0260553],
|
||||
[0.111121, 0.588392, 0.278779, 0.0055756, 0.00569609, 0.010436],
|
||||
[0.0357786, 0.633813, 0.321418, 0.00249248, 0.00272882, 0.0037688],
|
||||
[0.0663296, 0.643849, 0.280111, 0.00283995, 0.0035545, 0.00331533],
|
||||
[0.458235, 0.396634, 0.123377, 0.00648837, 0.00903441, 0.00623107]],
|
||||
[[0.30176, 0.28562, 0.0831517, 0.0862751, 0.0816851, 0.161508],
|
||||
[0.24082, 0.397533, 0.0557226, 0.0546814, 0.0557528, 0.19549],
|
||||
[0.230246, 0.450868, 0.0389607, 0.038309, 0.0391602, 0.202456],
|
||||
[0.280884, 0.429522, 0.0326593, 0.0339046, 0.0326856, 0.190345],
|
||||
[0.423286, 0.315517, 0.0338439, 0.0393744, 0.0339315, 0.154046]]],
|
||||
dtype=np.float32)
|
||||
|
||||
labels_tf = KTF.variable(labels, dtype="int32")
|
||||
inputs_tf = KTF.variable(inputs, dtype="float32")
|
||||
input_lens_tf = KTF.variable(input_lens, dtype="int32")
|
||||
label_lens_tf = KTF.variable(label_lens, dtype="int32")
|
||||
res = KTF.eval(KTF.ctc_batch_cost(labels_tf, inputs_tf, input_lens_tf, label_lens_tf))
|
||||
assert_allclose(res[:, 0], loss_log_probs_tf, atol=1e-05)
|
||||
|
||||
labels_th = KTH.variable(labels, dtype="int32")
|
||||
inputs_th = KTH.variable(inputs, dtype="float32")
|
||||
input_lens_th = KTH.variable(input_lens, dtype="int32")
|
||||
label_lens_th = KTH.variable(label_lens, dtype="int32")
|
||||
res = KTH.eval(KTH.ctc_batch_cost(labels_th, inputs_th, input_lens_th, label_lens_th))
|
||||
assert_allclose(res[0, :], loss_log_probs_th, atol=1e-05)
|
||||
|
||||
def test_ctc_decode_greedy(self):
|
||||
# Test adapted from tensorflow
|
||||
"""Test two batch entries - best path decoder."""
|
||||
max_time_steps = 6
|
||||
|
||||
seq_len_0 = 4
|
||||
input_prob_matrix_0 = np.asarray(
|
||||
[[1.0, 0.0, 0.0, 0.0], # t=0
|
||||
[0.0, 0.0, 0.4, 0.6], # t=1
|
||||
[0.0, 0.0, 0.4, 0.6], # t=2
|
||||
[0.0, 0.9, 0.1, 0.0], # t=3
|
||||
[0.0, 0.0, 0.0, 0.0], # t=4 (ignored)
|
||||
[0.0, 0.0, 0.0, 0.0]], # t=5 (ignored)
|
||||
dtype=np.float32)
|
||||
input_log_prob_matrix_0 = np.log(input_prob_matrix_0)
|
||||
|
||||
seq_len_1 = 5
|
||||
# dimensions are time x depth
|
||||
|
||||
input_prob_matrix_1 = np.asarray(
|
||||
[[0.1, 0.9, 0.0, 0.0], # t=0
|
||||
[0.0, 0.9, 0.1, 0.0], # t=1
|
||||
[0.0, 0.0, 0.1, 0.9], # t=2
|
||||
[0.0, 0.9, 0.1, 0.1], # t=3
|
||||
[0.9, 0.1, 0.0, 0.0], # t=4
|
||||
[0.0, 0.0, 0.0, 0.0]], # t=5 (ignored)
|
||||
dtype=np.float32)
|
||||
|
||||
# len max_time_steps array of batch_size x depth matrices
|
||||
inputs = [np.vstack([input_prob_matrix_0[t, :],
|
||||
input_prob_matrix_1[t, :]])
|
||||
for t in range(max_time_steps)]
|
||||
|
||||
# change tensorflow order to keras backend order
|
||||
inputs = KTF.variable(np.asarray(inputs).transpose((1, 0, 2)))
|
||||
# batch_size length vector of sequence_lengths
|
||||
input_length = KTF.variable(np.array([seq_len_0, seq_len_1], dtype=np.int32))
|
||||
|
||||
# batch_size length vector of negative log probabilities
|
||||
log_prob_truth = np.array([
|
||||
np.sum(-np.log([1.0, 0.6, 0.6, 0.9])),
|
||||
np.sum(-np.log([0.9, 0.9, 0.9, 0.9, 0.9]))
|
||||
], np.float32)[:, np.newaxis]
|
||||
|
||||
# keras output, unlike tensorflow, is a dense (not sparse) tensor
|
||||
decode_truth = np.array([[0, 1, -1], [1, 1, 0]])
|
||||
|
||||
decode_pred_tf, log_prob_pred_tf = KTF.ctc_decode(inputs,
|
||||
input_length,
|
||||
greedy=True)
|
||||
|
||||
assert len(decode_pred_tf) == 1
|
||||
|
||||
decode_pred = KTF.eval(decode_pred_tf[0])
|
||||
log_prob_pred = KTF.eval(log_prob_pred_tf)
|
||||
|
||||
assert np.alltrue(decode_truth == decode_pred)
|
||||
assert np.allclose(log_prob_truth, log_prob_pred)
|
||||
|
||||
def test_ctc_decode_beam_search(self):
|
||||
"""Test one batch, two beams - hibernating beam search."""
|
||||
|
||||
depth = 6
|
||||
|
||||
seq_len_0 = 5
|
||||
input_prob_matrix_0 = np.asarray(
|
||||
[[0.30999, 0.309938, 0.0679938, 0.0673362, 0.0708352, 0.173908],
|
||||
[0.215136, 0.439699, 0.0370931, 0.0393967, 0.0381581, 0.230517],
|
||||
[0.199959, 0.489485, 0.0233221, 0.0251417, 0.0233289, 0.238763],
|
||||
[0.279611, 0.452966, 0.0204795, 0.0209126, 0.0194803, 0.20655],
|
||||
[0.51286, 0.288951, 0.0243026, 0.0220788, 0.0219297, 0.129878],
|
||||
# Random entry added in at time=5
|
||||
[0.155251, 0.164444, 0.173517, 0.176138, 0.169979, 0.160671]],
|
||||
dtype=np.float32)
|
||||
|
||||
# len max_time_steps array of batch_size x depth matrices
|
||||
inputs = ([input_prob_matrix_0[t, :][np.newaxis, :]
|
||||
for t in range(seq_len_0)] + # Pad to max_time_steps = 8
|
||||
2 * [np.zeros((1, depth), dtype=np.float32)])
|
||||
|
||||
inputs = KTF.variable(np.asarray(inputs).transpose((1, 0, 2)))
|
||||
|
||||
# batch_size length vector of sequence_lengths
|
||||
input_length = KTF.variable(np.array([seq_len_0], dtype=np.int32))
|
||||
# batch_size length vector of negative log probabilities
|
||||
log_prob_truth = np.array([
|
||||
0.584855, # output beam 0
|
||||
0.389139 # output beam 1
|
||||
], np.float32)[np.newaxis, :]
|
||||
|
||||
decode_truth = [np.array([1, 0]), np.array([0, 1, 0])]
|
||||
|
||||
beam_width = 2
|
||||
top_paths = 2
|
||||
|
||||
decode_pred_tf, log_prob_pred_tf = KTF.ctc_decode(inputs,
|
||||
input_length,
|
||||
greedy=False,
|
||||
beam_width=beam_width,
|
||||
top_paths=top_paths)
|
||||
|
||||
assert len(decode_pred_tf) == top_paths
|
||||
|
||||
log_prob_pred = KTF.eval(log_prob_pred_tf)
|
||||
|
||||
for i in range(top_paths):
|
||||
assert np.alltrue(decode_truth[i] == KTF.eval(decode_pred_tf[i]))
|
||||
|
||||
assert np.allclose(log_prob_truth, log_prob_pred)
|
||||
|
||||
def test_one_hot(self):
|
||||
input_length = 10
|
||||
nb_classes = 20
|
||||
batch_size = 30
|
||||
indices = np.random.randint(0, nb_classes, size=(batch_size, input_length))
|
||||
oh = np.eye(nb_classes)[indices]
|
||||
for K in [KTH, KTF]:
|
||||
koh = K.eval(K.one_hot(K.variable(indices, dtype='int32'), nb_classes))
|
||||
assert np.all(koh == oh)
|
||||
|
||||
def test_sparse_dot(self):
|
||||
x_d = np.array([0, 7, 2, 3], dtype=np.float32)
|
||||
x_r = np.array([0, 2, 2, 3], dtype=np.int64)
|
||||
x_c = np.array([4, 3, 2, 3], dtype=np.int64)
|
||||
|
||||
x_sparse = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5))
|
||||
x_dense = x_sparse.toarray()
|
||||
|
||||
W = np.random.random((5, 4))
|
||||
|
||||
backends = [KTF]
|
||||
if KTH.th_sparse_module:
|
||||
# Theano has some dependency issues for sparse
|
||||
backends.append(KTH)
|
||||
|
||||
for K in backends:
|
||||
t_W = K.variable(W)
|
||||
k_s = K.eval(K.dot(K.variable(x_sparse), t_W))
|
||||
k_d = K.eval(K.dot(K.variable(x_dense), t_W))
|
||||
|
||||
assert k_s.shape == k_d.shape
|
||||
assert_allclose(k_s, k_d, atol=1e-05)
|
||||
|
||||
def test_sparse_concat(self):
|
||||
x_d = np.array([0, 7, 2, 3], dtype=np.float32)
|
||||
x_r = np.array([0, 2, 2, 3], dtype=np.int64)
|
||||
x_c = np.array([4, 3, 2, 3], dtype=np.int64)
|
||||
|
||||
x_sparse_1 = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5))
|
||||
|
||||
x_d = np.array([0, 7, 2, 3], dtype=np.float32)
|
||||
x_r = np.array([0, 2, 2, 3], dtype=np.int64)
|
||||
x_c = np.array([4, 3, 2, 3], dtype=np.int64)
|
||||
|
||||
x_sparse_2 = sparse.csr_matrix((x_d, (x_r, x_c)), shape=(4, 5))
|
||||
|
||||
x_dense_1 = x_sparse_1.toarray()
|
||||
x_dense_2 = x_sparse_2.toarray()
|
||||
|
||||
backends = [KTF]
|
||||
if KTH.th_sparse_module:
|
||||
# Theano has some dependency issues for sparse
|
||||
backends.append(KTH)
|
||||
|
||||
for K in backends:
|
||||
k_s = K.concatenate([K.variable(x_sparse_1), K.variable(x_sparse_2)])
|
||||
assert K.is_sparse(k_s)
|
||||
|
||||
k_s_d = K.eval(k_s)
|
||||
|
||||
k_d = K.eval(K.concatenate([K.variable(x_dense_1), K.variable(x_dense_2)]))
|
||||
|
||||
assert k_s_d.shape == k_d.shape
|
||||
assert_allclose(k_s_d, k_d, atol=1e-05)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -4,11 +4,56 @@ import numpy as np
|
||||
|
||||
from keras.layers import Dense, Dropout, InputLayer
|
||||
from keras.engine import merge, Input, get_source_inputs
|
||||
from keras.models import Model
|
||||
from keras.models import Model, Sequential
|
||||
from keras import backend as K
|
||||
from keras.models import model_from_json, model_from_yaml
|
||||
from keras.utils.test_utils import keras_test
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_trainable_weights():
|
||||
a = Input(shape=(2,))
|
||||
b = Dense(1)(a)
|
||||
model = Model(a, b)
|
||||
|
||||
weights = model.weights
|
||||
assert model.trainable_weights == weights
|
||||
assert model.non_trainable_weights == []
|
||||
|
||||
model.trainable = False
|
||||
assert model.trainable_weights == []
|
||||
assert model.non_trainable_weights == weights
|
||||
|
||||
model.trainable = True
|
||||
assert model.trainable_weights == weights
|
||||
assert model.non_trainable_weights == []
|
||||
|
||||
model.layers[1].trainable = False
|
||||
assert model.trainable_weights == []
|
||||
assert model.non_trainable_weights == weights
|
||||
|
||||
# sequential model
|
||||
model = Sequential()
|
||||
model.add(Dense(1, input_dim=2))
|
||||
weights = model.weights
|
||||
|
||||
assert model.trainable_weights == weights
|
||||
assert model.non_trainable_weights == []
|
||||
|
||||
model.trainable = False
|
||||
assert model.trainable_weights == []
|
||||
assert model.non_trainable_weights == weights
|
||||
|
||||
model.trainable = True
|
||||
assert model.trainable_weights == weights
|
||||
assert model.non_trainable_weights == []
|
||||
|
||||
model.layers[0].trainable = False
|
||||
assert model.trainable_weights == []
|
||||
assert model.non_trainable_weights == weights
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_learning_phase():
|
||||
a = Input(shape=(32,), name='input_a')
|
||||
b = Input(shape=(32,), name='input_b')
|
||||
@@ -50,6 +95,7 @@ def test_learning_phase():
|
||||
assert fn_outputs_no_dp[1].sum() != fn_outputs_dp[1].sum()
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_node_construction():
|
||||
####################################################
|
||||
# test basics
|
||||
@@ -128,6 +174,7 @@ def test_node_construction():
|
||||
assert dense.get_output_mask_at(1) is None
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_multi_input_layer():
|
||||
####################################################
|
||||
# test multi-input layer
|
||||
@@ -209,6 +256,7 @@ def test_multi_input_layer():
|
||||
assert [x.shape for x in fn_outputs] == [(10, 64), (10, 5)]
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_recursion():
|
||||
####################################################
|
||||
# test recursion
|
||||
@@ -400,98 +448,100 @@ def test_recursion():
|
||||
y = Dense(2)(x)
|
||||
|
||||
|
||||
def test_functional_guide():
|
||||
# MNIST
|
||||
from keras.layers import Input, Dense, LSTM
|
||||
from keras.models import Model
|
||||
from keras.utils import np_utils
|
||||
# @keras_test
|
||||
# def test_functional_guide():
|
||||
# # MNIST
|
||||
# from keras.layers import Input, Dense, LSTM
|
||||
# from keras.models import Model
|
||||
# from keras.utils import np_utils
|
||||
|
||||
# this returns a tensor
|
||||
inputs = Input(shape=(784,))
|
||||
# # this returns a tensor
|
||||
# inputs = Input(shape=(784,))
|
||||
|
||||
# a layer instance is callable on a tensor, and returns a tensor
|
||||
x = Dense(64, activation='relu')(inputs)
|
||||
x = Dense(64, activation='relu')(x)
|
||||
predictions = Dense(10, activation='softmax')(x)
|
||||
# # a layer instance is callable on a tensor, and returns a tensor
|
||||
# x = Dense(64, activation='relu')(inputs)
|
||||
# x = Dense(64, activation='relu')(x)
|
||||
# predictions = Dense(10, activation='softmax')(x)
|
||||
|
||||
# this creates a model that includes
|
||||
# the Input layer and three Dense layers
|
||||
model = Model(input=inputs, output=predictions)
|
||||
model.compile(optimizer='rmsprop',
|
||||
loss='categorical_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
# # this creates a model that includes
|
||||
# # the Input layer and three Dense layers
|
||||
# model = Model(input=inputs, output=predictions)
|
||||
# model.compile(optimizer='rmsprop',
|
||||
# loss='categorical_crossentropy',
|
||||
# metrics=['accuracy'])
|
||||
|
||||
# the data, shuffled and split between tran and test sets
|
||||
X_train = np.random.random((100, 784))
|
||||
Y_train = np.random.random((100, 10))
|
||||
# # the data, shuffled and split between tran and test sets
|
||||
# X_train = np.random.random((100, 784))
|
||||
# Y_train = np.random.random((100, 10))
|
||||
|
||||
model.fit(X_train, Y_train, nb_epoch=2, batch_size=128)
|
||||
# model.fit(X_train, Y_train, nb_epoch=2, batch_size=128)
|
||||
|
||||
assert model.inputs == [inputs]
|
||||
assert model.outputs == [predictions]
|
||||
assert model.input == inputs
|
||||
assert model.output == predictions
|
||||
assert model.input_shape == (None, 784)
|
||||
assert model.output_shape == (None, 10)
|
||||
# assert model.inputs == [inputs]
|
||||
# assert model.outputs == [predictions]
|
||||
# assert model.input == inputs
|
||||
# assert model.output == predictions
|
||||
# assert model.input_shape == (None, 784)
|
||||
# assert model.output_shape == (None, 10)
|
||||
|
||||
# try calling the sequential model
|
||||
inputs = Input(shape=(784,))
|
||||
new_outputs = model(inputs)
|
||||
new_model = Model(input=inputs, output=new_outputs)
|
||||
new_model.compile(optimizer='rmsprop',
|
||||
loss='categorical_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
# # try calling the sequential model
|
||||
# inputs = Input(shape=(784,))
|
||||
# new_outputs = model(inputs)
|
||||
# new_model = Model(input=inputs, output=new_outputs)
|
||||
# new_model.compile(optimizer='rmsprop',
|
||||
# loss='categorical_crossentropy',
|
||||
# metrics=['accuracy'])
|
||||
|
||||
##################################################
|
||||
# multi-io
|
||||
##################################################
|
||||
tweet_a = Input(shape=(4, 25))
|
||||
tweet_b = Input(shape=(4, 25))
|
||||
# this layer can take as input a matrix
|
||||
# and will return a vector of size 64
|
||||
shared_lstm = LSTM(64)
|
||||
# ##################################################
|
||||
# # multi-io
|
||||
# ##################################################
|
||||
# tweet_a = Input(shape=(4, 25))
|
||||
# tweet_b = Input(shape=(4, 25))
|
||||
# # this layer can take as input a matrix
|
||||
# # and will return a vector of size 64
|
||||
# shared_lstm = LSTM(64)
|
||||
|
||||
# when we reuse the same layer instance
|
||||
# multiple times, the weights of the layer
|
||||
# are also being reused
|
||||
# (it is effectively *the same* layer)
|
||||
encoded_a = shared_lstm(tweet_a)
|
||||
encoded_b = shared_lstm(tweet_b)
|
||||
# # when we reuse the same layer instance
|
||||
# # multiple times, the weights of the layer
|
||||
# # are also being reused
|
||||
# # (it is effectively *the same* layer)
|
||||
# encoded_a = shared_lstm(tweet_a)
|
||||
# encoded_b = shared_lstm(tweet_b)
|
||||
|
||||
# we can then concatenate the two vectors:
|
||||
merged_vector = merge([encoded_a, encoded_b],
|
||||
mode='concat', concat_axis=-1)
|
||||
# # we can then concatenate the two vectors:
|
||||
# merged_vector = merge([encoded_a, encoded_b],
|
||||
# mode='concat', concat_axis=-1)
|
||||
|
||||
# and add a logistic regression on top
|
||||
predictions = Dense(1, activation='sigmoid')(merged_vector)
|
||||
# # and add a logistic regression on top
|
||||
# predictions = Dense(1, activation='sigmoid')(merged_vector)
|
||||
|
||||
# we define a trainable model linking the
|
||||
# tweet inputs to the predictions
|
||||
model = Model(input=[tweet_a, tweet_b], output=predictions)
|
||||
# # we define a trainable model linking the
|
||||
# # tweet inputs to the predictions
|
||||
# model = Model(input=[tweet_a, tweet_b], output=predictions)
|
||||
|
||||
model.compile(optimizer='rmsprop',
|
||||
loss='binary_crossentropy',
|
||||
metrics=['accuracy'])
|
||||
data_a = np.random.random((1000, 4, 25))
|
||||
data_b = np.random.random((1000, 4, 25))
|
||||
labels = np.random.random((1000,))
|
||||
model.fit([data_a, data_b], labels, nb_epoch=1)
|
||||
# model.compile(optimizer='rmsprop',
|
||||
# loss='binary_crossentropy',
|
||||
# metrics=['accuracy'])
|
||||
# data_a = np.random.random((1000, 4, 25))
|
||||
# data_b = np.random.random((1000, 4, 25))
|
||||
# labels = np.random.random((1000,))
|
||||
# model.fit([data_a, data_b], labels, nb_epoch=1)
|
||||
|
||||
model.summary()
|
||||
assert model.inputs == [tweet_a, tweet_b]
|
||||
assert model.outputs == [predictions]
|
||||
assert model.input == [tweet_a, tweet_b]
|
||||
assert model.output == predictions
|
||||
# model.summary()
|
||||
# assert model.inputs == [tweet_a, tweet_b]
|
||||
# assert model.outputs == [predictions]
|
||||
# assert model.input == [tweet_a, tweet_b]
|
||||
# assert model.output == predictions
|
||||
|
||||
assert model.output == predictions
|
||||
assert model.input_shape == [(None, 4, 25), (None, 4, 25)]
|
||||
assert model.output_shape == (None, 1)
|
||||
# assert model.output == predictions
|
||||
# assert model.input_shape == [(None, 4, 25), (None, 4, 25)]
|
||||
# assert model.output_shape == (None, 1)
|
||||
|
||||
assert shared_lstm.get_output_at(0) == encoded_a
|
||||
assert shared_lstm.get_output_at(1) == encoded_b
|
||||
assert shared_lstm.input_shape == (None, 4, 25)
|
||||
# assert shared_lstm.get_output_at(0) == encoded_a
|
||||
# assert shared_lstm.get_output_at(1) == encoded_b
|
||||
# assert shared_lstm.input_shape == (None, 4, 25)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_sequential_regression():
|
||||
from keras.models import Sequential, Model
|
||||
from keras.layers import Merge, Embedding, BatchNormalization, LSTM, InputLayer, Input
|
||||
|
||||
@@ -7,8 +7,10 @@ from keras.engine.topology import merge, Input
|
||||
from keras.engine.training import Model
|
||||
from keras.models import Sequential, Graph
|
||||
from keras import backend as K
|
||||
from keras.utils.test_utils import keras_test
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_model_methods():
|
||||
a = Input(shape=(3,), name='input_a')
|
||||
b = Input(shape=(3,), name='input_b')
|
||||
@@ -167,6 +169,7 @@ def test_model_methods():
|
||||
out = model.predict([input_a_np, input_b_np], batch_size=4)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_trainable_argument():
|
||||
x = np.random.random((5, 3))
|
||||
y = np.random.random((5, 2))
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import pytest
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_leaky_relu():
|
||||
from keras.layers.advanced_activations import LeakyReLU
|
||||
for alpha in [0., .5, -1.]:
|
||||
@@ -9,12 +10,14 @@ def test_leaky_relu():
|
||||
input_shape=(2, 3, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_prelu():
|
||||
from keras.layers.advanced_activations import PReLU
|
||||
layer_test(PReLU, kwargs={},
|
||||
input_shape=(2, 3, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_elu():
|
||||
from keras.layers.advanced_activations import ELU
|
||||
for alpha in [0., .5, -1.]:
|
||||
@@ -22,6 +25,7 @@ def test_elu():
|
||||
input_shape=(2, 3, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_parametric_softplus():
|
||||
from keras.layers.advanced_activations import ParametricSoftplus
|
||||
for alpha in [0., .5, -1.]:
|
||||
@@ -31,12 +35,14 @@ def test_parametric_softplus():
|
||||
input_shape=(2, 3, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_thresholded_relu():
|
||||
from keras.layers.advanced_activations import ThresholdedReLU
|
||||
layer_test(ThresholdedReLU, kwargs={'theta': 0.5},
|
||||
input_shape=(2, 3, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_srelu():
|
||||
from keras.layers.advanced_activations import SReLU
|
||||
layer_test(SReLU, kwargs={},
|
||||
|
||||
@@ -2,22 +2,25 @@ import pytest
|
||||
import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
from keras.utils.np_utils import conv_input_length
|
||||
from keras import backend as K
|
||||
from keras.layers import convolutional
|
||||
from keras.layers import convolutional, pooling
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_convolution_1d():
|
||||
nb_samples = 2
|
||||
nb_steps = 8
|
||||
input_dim = 5
|
||||
input_dim = 2
|
||||
filter_length = 3
|
||||
nb_filter = 4
|
||||
nb_filter = 3
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample_length in [1]:
|
||||
for subsample_length in [1, 2]:
|
||||
if border_mode == 'same' and subsample_length != 1:
|
||||
continue
|
||||
|
||||
layer_test(convolutional.Convolution1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
@@ -36,6 +39,43 @@ def test_convolution_1d():
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_atrous_conv_1d():
|
||||
nb_samples = 2
|
||||
nb_steps = 8
|
||||
input_dim = 2
|
||||
filter_length = 3
|
||||
nb_filter = 3
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample_length in [1, 2]:
|
||||
for atrous_rate in [1, 2]:
|
||||
if border_mode == 'same' and subsample_length != 1:
|
||||
continue
|
||||
if subsample_length != 1 and atrous_rate != 1:
|
||||
continue
|
||||
|
||||
layer_test(convolutional.AtrousConv1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
'border_mode': border_mode,
|
||||
'subsample_length': subsample_length,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
layer_test(convolutional.AtrousConv1D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'filter_length': filter_length,
|
||||
'border_mode': border_mode,
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample_length': subsample_length,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_maxpooling_1d():
|
||||
for stride in [1, 2]:
|
||||
layer_test(convolutional.MaxPooling1D,
|
||||
@@ -44,6 +84,7 @@ def test_maxpooling_1d():
|
||||
input_shape=(3, 5, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_averagepooling_1d():
|
||||
for stride in [1, 2]:
|
||||
layer_test(convolutional.AveragePooling1D,
|
||||
@@ -52,10 +93,11 @@ def test_averagepooling_1d():
|
||||
input_shape=(3, 5, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_convolution_2d():
|
||||
nb_samples = 2
|
||||
nb_filter = 3
|
||||
stack_size = 4
|
||||
nb_filter = 2
|
||||
stack_size = 3
|
||||
nb_row = 10
|
||||
nb_col = 6
|
||||
|
||||
@@ -70,7 +112,7 @@ def test_convolution_2d():
|
||||
'nb_col': 3,
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(convolutional.Convolution2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -81,13 +123,55 @@ def test_convolution_2d():
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_deconvolution_2d():
|
||||
nb_samples = 2
|
||||
nb_filter = 2
|
||||
stack_size = 3
|
||||
nb_row = 10
|
||||
nb_col = 6
|
||||
|
||||
for border_mode in ['valid', 'same']:
|
||||
for subsample in [(1, 1), (2, 2)]:
|
||||
if border_mode == 'same' and subsample != (1, 1):
|
||||
continue
|
||||
|
||||
rows = conv_input_length(nb_row, 3, border_mode, subsample[0])
|
||||
cols = conv_input_length(nb_col, 3, border_mode, subsample[1])
|
||||
layer_test(convolutional.Deconvolution2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'output_shape': (nb_samples, nb_filter, rows, cols),
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'dim_ordering': 'th'},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col),
|
||||
fixed_batch_size=True)
|
||||
|
||||
layer_test(convolutional.Deconvolution2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
'nb_row': 3,
|
||||
'nb_col': 3,
|
||||
'output_shape': (nb_samples, nb_filter, rows, cols),
|
||||
'border_mode': border_mode,
|
||||
'dim_ordering': 'th',
|
||||
'W_regularizer': 'l2',
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col),
|
||||
fixed_batch_size=True)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_atrous_conv_2d():
|
||||
nb_samples = 2
|
||||
nb_filter = 3
|
||||
stack_size = 4
|
||||
nb_filter = 2
|
||||
stack_size = 3
|
||||
nb_row = 10
|
||||
nb_col = 6
|
||||
|
||||
@@ -106,7 +190,7 @@ def test_atrous_conv_2d():
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(convolutional.AtrousConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -118,14 +202,15 @@ def test_atrous_conv_2d():
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample,
|
||||
'atrous_rate': atrous_rate},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'tensorflow', reason="Requires TF backend")
|
||||
@keras_test
|
||||
def test_separable_conv_2d():
|
||||
nb_samples = 2
|
||||
nb_filter = 8
|
||||
stack_size = 4
|
||||
nb_filter = 6
|
||||
stack_size = 3
|
||||
nb_row = 10
|
||||
nb_col = 6
|
||||
|
||||
@@ -142,7 +227,7 @@ def test_separable_conv_2d():
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample,
|
||||
'depth_multiplier': multiplier},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
layer_test(convolutional.SeparableConv2D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -157,9 +242,34 @@ def test_separable_conv_2d():
|
||||
'depthwise_constraint': 'unitnorm',
|
||||
'subsample': subsample,
|
||||
'depth_multiplier': multiplier},
|
||||
input_shape=(nb_samples, stack_size, nb_row, nb_col))
|
||||
input_shape=(nb_samples, nb_row, nb_col, stack_size))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_globalpooling_1d():
|
||||
layer_test(pooling.GlobalMaxPooling1D,
|
||||
input_shape=(3, 4, 5))
|
||||
layer_test(pooling.GlobalAveragePooling1D,
|
||||
input_shape=(3, 4, 5))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_globalpooling_2d():
|
||||
layer_test(pooling.GlobalMaxPooling2D,
|
||||
kwargs={'dim_ordering': 'th'},
|
||||
input_shape=(3, 4, 5, 6))
|
||||
layer_test(pooling.GlobalMaxPooling2D,
|
||||
kwargs={'dim_ordering': 'tf'},
|
||||
input_shape=(3, 5, 6, 4))
|
||||
layer_test(pooling.GlobalAveragePooling2D,
|
||||
kwargs={'dim_ordering': 'th'},
|
||||
input_shape=(3, 4, 5, 6))
|
||||
layer_test(pooling.GlobalAveragePooling2D,
|
||||
kwargs={'dim_ordering': 'tf'},
|
||||
input_shape=(3, 5, 6, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_maxpooling_2d():
|
||||
pool_size = (3, 3)
|
||||
|
||||
@@ -168,9 +278,10 @@ def test_maxpooling_2d():
|
||||
kwargs={'strides': strides,
|
||||
'border_mode': 'valid',
|
||||
'pool_size': pool_size},
|
||||
input_shape=(3, 4, 11, 12))
|
||||
input_shape=(3, 11, 12, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_averagepooling_2d():
|
||||
pool_size = (3, 3)
|
||||
|
||||
@@ -181,13 +292,14 @@ def test_averagepooling_2d():
|
||||
kwargs={'strides': strides,
|
||||
'border_mode': border_mode,
|
||||
'pool_size': pool_size},
|
||||
input_shape=(3, 4, 11, 12))
|
||||
input_shape=(3, 11, 12, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_convolution_3d():
|
||||
nb_samples = 2
|
||||
nb_filter = 5
|
||||
stack_size = 4
|
||||
nb_filter = 2
|
||||
stack_size = 3
|
||||
kernel_dim1 = 2
|
||||
kernel_dim2 = 3
|
||||
kernel_dim3 = 1
|
||||
@@ -208,8 +320,9 @@ def test_convolution_3d():
|
||||
'kernel_dim3': kernel_dim3,
|
||||
'border_mode': border_mode,
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3))
|
||||
input_shape=(nb_samples,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3,
|
||||
stack_size))
|
||||
|
||||
layer_test(convolutional.Convolution3D,
|
||||
kwargs={'nb_filter': nb_filter,
|
||||
@@ -221,10 +334,12 @@ def test_convolution_3d():
|
||||
'b_regularizer': 'l2',
|
||||
'activity_regularizer': 'activity_l2',
|
||||
'subsample': subsample},
|
||||
input_shape=(nb_samples, stack_size,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3))
|
||||
input_shape=(nb_samples,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3,
|
||||
stack_size))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_maxpooling_3d():
|
||||
pool_size = (3, 3, 3)
|
||||
|
||||
@@ -236,6 +351,7 @@ def test_maxpooling_3d():
|
||||
input_shape=(3, 4, 11, 12, 10))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_averagepooling_3d():
|
||||
pool_size = (3, 3, 3)
|
||||
|
||||
@@ -247,13 +363,14 @@ def test_averagepooling_3d():
|
||||
input_shape=(3, 4, 11, 12, 10))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_zero_padding_2d():
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
stack_size = 2
|
||||
input_nb_row = 11
|
||||
input_nb_col = 12
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_nb_row, input_nb_col))
|
||||
input = np.ones((nb_samples, input_nb_row, input_nb_col, stack_size))
|
||||
|
||||
# basic test
|
||||
layer_test(convolutional.ZeroPadding2D,
|
||||
@@ -266,22 +383,22 @@ def test_zero_padding_2d():
|
||||
|
||||
out = K.eval(layer.output)
|
||||
for offset in [0, 1, -1, -2]:
|
||||
assert_allclose(out[:, offset, :, :], 0.)
|
||||
assert_allclose(out[:, :, offset, :], 0.)
|
||||
assert_allclose(out[:, :, :, offset], 0.)
|
||||
assert_allclose(out[:, :, 2:-2, 2:-2], 1.)
|
||||
assert_allclose(out[:, 2:-2, 2:-2, :], 1.)
|
||||
layer.get_config()
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_zero_padding_3d():
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
stack_size = 2
|
||||
input_len_dim1 = 10
|
||||
input_len_dim2 = 11
|
||||
input_len_dim3 = 12
|
||||
|
||||
input = np.ones((nb_samples, stack_size, input_len_dim1,
|
||||
input_len_dim2, input_len_dim3))
|
||||
input = np.ones((nb_samples,
|
||||
input_len_dim1, input_len_dim2, input_len_dim3,
|
||||
stack_size))
|
||||
|
||||
# basic test
|
||||
layer_test(convolutional.ZeroPadding3D,
|
||||
@@ -293,22 +410,24 @@ def test_zero_padding_3d():
|
||||
layer.set_input(K.variable(input), shape=input.shape)
|
||||
out = K.eval(layer.output)
|
||||
for offset in [0, 1, -1, -2]:
|
||||
assert_allclose(out[:, offset, :, :, :], 0.)
|
||||
assert_allclose(out[:, :, offset, :, :], 0.)
|
||||
assert_allclose(out[:, :, :, offset, :], 0.)
|
||||
assert_allclose(out[:, :, :, :, offset], 0.)
|
||||
assert_allclose(out[:, :, 2:-2, 2:-2, 2:-2], 1.)
|
||||
assert_allclose(out[:, 2:-2, 2:-2, 2:-2, :], 1.)
|
||||
layer.get_config()
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_upsampling_1d():
|
||||
layer_test(convolutional.UpSampling1D,
|
||||
kwargs={'length': 2},
|
||||
input_shape=(3, 5, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_upsampling_2d():
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
stack_size = 2
|
||||
input_nb_row = 11
|
||||
input_nb_col = 12
|
||||
|
||||
@@ -346,10 +465,9 @@ def test_upsampling_2d():
|
||||
assert_allclose(out, expected_out)
|
||||
|
||||
|
||||
@pytest.mark.skipif(K._BACKEND != 'theano', reason="Requires Theano backend")
|
||||
def test_upsampling_3d():
|
||||
nb_samples = 2
|
||||
stack_size = 7
|
||||
stack_size = 2
|
||||
input_len_dim1 = 10
|
||||
input_len_dim2 = 11
|
||||
input_len_dim3 = 12
|
||||
@@ -392,5 +510,93 @@ def test_upsampling_3d():
|
||||
assert_allclose(out, expected_out)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_cropping_1d():
|
||||
nb_samples = 2
|
||||
time_length = 10
|
||||
input_len_dim1 = 2
|
||||
input = np.random.rand(nb_samples, time_length, input_len_dim1)
|
||||
|
||||
layer_test(convolutional.Cropping1D,
|
||||
kwargs={'cropping': (2, 2)},
|
||||
input_shape=input.shape)
|
||||
|
||||
|
||||
def test_cropping_2d():
|
||||
nb_samples = 2
|
||||
stack_size = 2
|
||||
input_len_dim1 = 8
|
||||
input_len_dim2 = 8
|
||||
cropping = ((2, 2), (3, 3))
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
if dim_ordering == 'th':
|
||||
input = np.random.rand(nb_samples, stack_size, input_len_dim1, input_len_dim2)
|
||||
else:
|
||||
input = np.random.rand(nb_samples, input_len_dim1, input_len_dim2, stack_size)
|
||||
# basic test
|
||||
layer_test(convolutional.Cropping2D,
|
||||
kwargs={'cropping': cropping,
|
||||
'dim_ordering': dim_ordering},
|
||||
input_shape=input.shape)
|
||||
# correctness test
|
||||
layer = convolutional.Cropping2D(cropping=cropping, dim_ordering=dim_ordering)
|
||||
layer.set_input(K.variable(input), shape=input.shape)
|
||||
|
||||
out = K.eval(layer.output)
|
||||
# compare with numpy
|
||||
if dim_ordering == 'th':
|
||||
expected_out = input[:,
|
||||
:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1]]
|
||||
else:
|
||||
expected_out = input[:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
:]
|
||||
|
||||
assert_allclose(out, expected_out)
|
||||
|
||||
|
||||
def test_cropping_3d():
|
||||
nb_samples = 2
|
||||
stack_size = 2
|
||||
input_len_dim1 = 8
|
||||
input_len_dim2 = 8
|
||||
input_len_dim3 = 8
|
||||
cropping = ((2, 2), (3, 3), (2, 3))
|
||||
dim_ordering = K.image_dim_ordering()
|
||||
|
||||
if dim_ordering == 'th':
|
||||
input = np.random.rand(nb_samples, stack_size, input_len_dim1, input_len_dim2, input_len_dim3)
|
||||
else:
|
||||
input = np.random.rand(nb_samples, input_len_dim1, input_len_dim2, input_len_dim3, stack_size)
|
||||
# basic test
|
||||
layer_test(convolutional.Cropping3D,
|
||||
kwargs={'cropping': cropping,
|
||||
'dim_ordering': dim_ordering},
|
||||
input_shape=input.shape)
|
||||
# correctness test
|
||||
layer = convolutional.Cropping3D(cropping=cropping, dim_ordering=dim_ordering)
|
||||
layer.set_input(K.variable(input), shape=input.shape)
|
||||
|
||||
out = K.eval(layer.output)
|
||||
# compare with numpy
|
||||
if dim_ordering == 'th':
|
||||
expected_out = input[:,
|
||||
:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
cropping[2][0]:-cropping[2][1]]
|
||||
else:
|
||||
expected_out = input[:,
|
||||
cropping[0][0]:-cropping[0][1],
|
||||
cropping[1][0]:-cropping[1][1],
|
||||
cropping[2][0]:-cropping[2][1],
|
||||
:]
|
||||
|
||||
assert_allclose(out, expected_out)
|
||||
|
||||
if __name__ == '__main__':
|
||||
pytest.main([__file__])
|
||||
|
||||
@@ -3,15 +3,17 @@ import numpy as np
|
||||
|
||||
from keras import backend as K
|
||||
from keras.layers import core
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_masking():
|
||||
layer_test(core.Masking,
|
||||
kwargs={},
|
||||
input_shape=(3, 2, 3))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_merge():
|
||||
from keras.layers import Input, merge, Merge
|
||||
from keras.models import Model
|
||||
@@ -83,6 +85,7 @@ def test_merge():
|
||||
model.compile('rmsprop', 'mse')
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_merge_mask_2d():
|
||||
from keras.layers import Input, merge, Masking
|
||||
from keras.models import Model
|
||||
@@ -97,21 +100,28 @@ def test_merge_mask_2d():
|
||||
masked_a = Masking(mask_value=0)(input_a)
|
||||
masked_b = Masking(mask_value=0)(input_b)
|
||||
|
||||
# two different types of merging
|
||||
# three different types of merging
|
||||
merged_sum = merge([masked_a, masked_b], mode='sum')
|
||||
merged_concat = merge([masked_a, masked_b], mode='concat', concat_axis=1)
|
||||
merged_concat_mixed = merge([masked_a, input_b], mode='concat', concat_axis=1)
|
||||
|
||||
# test sum
|
||||
model_sum = Model([input_a, input_b], [merged_sum])
|
||||
model_sum.compile(loss='mse', optimizer='sgd')
|
||||
model_sum.fit([rand(2,3), rand(2,3)], [rand(2,3)], nb_epoch=1)
|
||||
model_sum.fit([rand(2, 3), rand(2, 3)], [rand(2, 3)], nb_epoch=1)
|
||||
|
||||
# test concatenation
|
||||
model_concat = Model([input_a, input_b], [merged_concat])
|
||||
model_concat.compile(loss='mse', optimizer='sgd')
|
||||
model_concat.fit([rand(2,3), rand(2,3)], [rand(2,6)], nb_epoch=1)
|
||||
model_concat.fit([rand(2, 3), rand(2, 3)], [rand(2, 6)], nb_epoch=1)
|
||||
|
||||
# test concatenation with masked and non-masked inputs
|
||||
model_concat = Model([input_a, input_b], [merged_concat_mixed])
|
||||
model_concat.compile(loss='mse', optimizer='sgd')
|
||||
model_concat.fit([rand(2, 3), rand(2, 3)], [rand(2, 6)], nb_epoch=1)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_merge_mask_3d():
|
||||
from keras.layers import Input, merge, Embedding, SimpleRNN
|
||||
from keras.models import Model
|
||||
@@ -134,15 +144,25 @@ def test_merge_mask_3d():
|
||||
merged_concat = merge([rnn_a, rnn_b], mode='concat', concat_axis=-1)
|
||||
model = Model([input_a, input_b], [merged_concat])
|
||||
model.compile(loss='mse', optimizer='sgd')
|
||||
model.fit([rand(2,3), rand(2,3)], [rand(2,3,6)])
|
||||
model.fit([rand(2, 3), rand(2, 3)], [rand(2, 3, 6)])
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_dropout():
|
||||
layer_test(core.Dropout,
|
||||
kwargs={'p': 0.5},
|
||||
input_shape=(3, 2))
|
||||
|
||||
layer_test(core.SpatialDropout2D,
|
||||
kwargs={'p': 0.5},
|
||||
input_shape=(2, 3, 4, 5))
|
||||
|
||||
layer_test(core.SpatialDropout3D,
|
||||
kwargs={'p': 0.5},
|
||||
input_shape=(2, 3, 4, 5, 6))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_activation():
|
||||
# with string argument
|
||||
layer_test(core.Activation,
|
||||
@@ -155,30 +175,35 @@ def test_activation():
|
||||
input_shape=(3, 2))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_reshape():
|
||||
layer_test(core.Reshape,
|
||||
kwargs={'target_shape': (8, 1)},
|
||||
input_shape=(3, 2, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_permute():
|
||||
layer_test(core.Permute,
|
||||
kwargs={'dims': (2, 1)},
|
||||
input_shape=(3, 2, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_flatten():
|
||||
layer_test(core.Flatten,
|
||||
kwargs={},
|
||||
input_shape=(3, 2, 4))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_repeat_vector():
|
||||
layer_test(core.RepeatVector,
|
||||
kwargs={'n': 3},
|
||||
input_shape=(3, 2))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_lambda():
|
||||
from keras.utils.layer_utils import layer_from_config
|
||||
Lambda = core.Lambda
|
||||
@@ -212,6 +237,7 @@ def test_lambda():
|
||||
ld = layer_from_config({'class_name': 'Lambda', 'config': config})
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_dense():
|
||||
from keras import regularizers
|
||||
from keras import constraints
|
||||
@@ -230,6 +256,7 @@ def test_dense():
|
||||
input_shape=(3, 2))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_activity_regularization():
|
||||
from keras.engine import Input, Model
|
||||
|
||||
@@ -250,6 +277,7 @@ def test_activity_regularization():
|
||||
model.compile('rmsprop', 'mse')
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_maxout_dense():
|
||||
from keras import regularizers
|
||||
from keras import constraints
|
||||
@@ -268,6 +296,7 @@ def test_maxout_dense():
|
||||
input_shape=(3, 2))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_highway():
|
||||
from keras import regularizers
|
||||
from keras import constraints
|
||||
@@ -285,6 +314,7 @@ def test_highway():
|
||||
input_shape=(3, 2))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_timedistributeddense():
|
||||
from keras import regularizers
|
||||
from keras import constraints
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import pytest
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
from keras.layers.embeddings import Embedding
|
||||
import keras.backend as K
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_embedding():
|
||||
layer_test(Embedding,
|
||||
kwargs={'output_dim': 4., 'input_dim': 10, 'input_length': 2},
|
||||
kwargs={'output_dim': 4, 'input_dim': 10, 'input_length': 2},
|
||||
input_shape=(3, 2),
|
||||
input_dtype='int32',
|
||||
expected_output_dtype=K.floatx())
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import pytest
|
||||
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
from keras.layers import local
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_locallyconnected_1d():
|
||||
nb_samples = 2
|
||||
nb_steps = 8
|
||||
@@ -33,6 +34,7 @@ def test_locallyconnected_1d():
|
||||
input_shape=(nb_samples, nb_steps, input_dim))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_locallyconnected_2d():
|
||||
nb_samples = 8
|
||||
nb_filter = 3
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
import pytest
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
from keras.layers import noise
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_GaussianNoise():
|
||||
layer_test(noise.GaussianNoise,
|
||||
kwargs={'sigma': 1.},
|
||||
input_shape=(3, 2, 3))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_GaussianDropout():
|
||||
layer_test(noise.GaussianDropout,
|
||||
kwargs={'p': 0.5},
|
||||
|
||||
@@ -3,37 +3,41 @@ import numpy as np
|
||||
from numpy.testing import assert_allclose
|
||||
|
||||
from keras.layers.core import Dense, Activation
|
||||
from keras.utils.test_utils import layer_test
|
||||
from keras.utils.test_utils import layer_test, keras_test
|
||||
from keras.layers import normalization
|
||||
from keras.models import Sequential, Graph
|
||||
from keras import backend as K
|
||||
|
||||
|
||||
input_1 = np.arange(10)
|
||||
input_2 = np.zeros(10)
|
||||
input_3 = np.ones((10))
|
||||
input_shapes = [np.ones((10, 10)), np.ones((10, 10, 10))]
|
||||
|
||||
|
||||
@keras_test
|
||||
def basic_batchnorm_test():
|
||||
from keras import regularizers
|
||||
layer_test(normalization.BatchNormalization,
|
||||
kwargs={'mode': 1},
|
||||
kwargs={'mode': 1,
|
||||
'gamma_regularizer': regularizers.l2(0.01),
|
||||
'beta_regularizer': regularizers.l2(0.01)},
|
||||
input_shape=(3, 4, 2))
|
||||
layer_test(normalization.BatchNormalization,
|
||||
kwargs={'mode': 0},
|
||||
input_shape=(3, 4, 2))
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_batchnorm_mode_0_or_2():
|
||||
for mode in [0, 2]:
|
||||
model = Sequential()
|
||||
norm_m0 = normalization.BatchNormalization(mode=mode, input_shape=(10,))
|
||||
norm_m0 = normalization.BatchNormalization(mode=mode, input_shape=(10,), momentum=0.8)
|
||||
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)
|
||||
model.fit(X, X, nb_epoch=4, verbose=0)
|
||||
out = model.predict(X)
|
||||
out -= K.eval(norm_m0.beta)
|
||||
out /= K.eval(norm_m0.gamma)
|
||||
@@ -42,15 +46,16 @@ def test_batchnorm_mode_0_or_2():
|
||||
assert_allclose(out.std(), 1.0, atol=1e-1)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_batchnorm_mode_0_convnet():
|
||||
model = Sequential()
|
||||
norm_m0 = normalization.BatchNormalization(mode=0, axis=1, input_shape=(3, 4, 4))
|
||||
norm_m0 = normalization.BatchNormalization(mode=0, axis=1, input_shape=(3, 4, 4), momentum=0.8)
|
||||
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, 3, 4, 4))
|
||||
model.fit(X, X, nb_epoch=5, verbose=0)
|
||||
model.fit(X, X, nb_epoch=4, verbose=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))
|
||||
@@ -59,6 +64,7 @@ def test_batchnorm_mode_0_convnet():
|
||||
assert_allclose(np.std(out, axis=(0, 2, 3)), 1.0, atol=1e-1)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_batchnorm_mode_1():
|
||||
norm_m1 = normalization.BatchNormalization(input_shape=(10,), mode=1)
|
||||
norm_m1.build(input_shape=(None, 10))
|
||||
|
||||
@@ -7,10 +7,11 @@ from keras.layers import recurrent, embeddings
|
||||
from keras.models import Sequential
|
||||
from keras.layers.core import Masking
|
||||
from keras import regularizers
|
||||
from keras.utils.test_utils import keras_test
|
||||
|
||||
from keras import backend as K
|
||||
|
||||
nb_samples, timesteps, embedding_dim, output_dim = 3, 5, 10, 5
|
||||
nb_samples, timesteps, embedding_dim, output_dim = 2, 5, 4, 3
|
||||
embedding_num = 12
|
||||
|
||||
|
||||
@@ -23,21 +24,30 @@ def _runner(layer_class):
|
||||
layer_test(layer_class,
|
||||
kwargs={'output_dim': output_dim,
|
||||
'return_sequences': True},
|
||||
input_shape=(3, 2, 3))
|
||||
input_shape=(nb_samples, timesteps, embedding_dim))
|
||||
|
||||
# check dynamic behavior
|
||||
layer = layer_class(output_dim, input_dim=embedding_dim)
|
||||
model = Sequential()
|
||||
model.add(layer)
|
||||
model.compile('sgd', 'mse')
|
||||
x = np.random.random((nb_samples, timesteps, embedding_dim))
|
||||
y = np.random.random((nb_samples, output_dim))
|
||||
model.train_on_batch(x, y)
|
||||
|
||||
# check dropout
|
||||
layer_test(layer_class,
|
||||
kwargs={'output_dim': output_dim,
|
||||
'dropout_U': 0.1,
|
||||
'dropout_W': 0.1},
|
||||
input_shape=(3, 2, 3))
|
||||
input_shape=(nb_samples, timesteps, embedding_dim))
|
||||
|
||||
# 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))
|
||||
input_shape=(nb_samples, timesteps, embedding_dim))
|
||||
|
||||
# check statefulness
|
||||
model = Sequential()
|
||||
@@ -82,7 +92,6 @@ def _runner(layer_class):
|
||||
left_padded_input = np.ones((nb_samples, timesteps))
|
||||
left_padded_input[0, :1] = 0
|
||||
left_padded_input[1, :2] = 0
|
||||
left_padded_input[2, :3] = 0
|
||||
out6 = model.predict(left_padded_input)
|
||||
|
||||
layer.reset_states()
|
||||
@@ -90,7 +99,6 @@ def _runner(layer_class):
|
||||
right_padded_input = np.ones((nb_samples, timesteps))
|
||||
right_padded_input[0, -1:] = 0
|
||||
right_padded_input[1, -2:] = 0
|
||||
right_padded_input[2, -3:] = 0
|
||||
out7 = model.predict(right_padded_input)
|
||||
|
||||
assert_allclose(out7, out6, atol=1e-5)
|
||||
@@ -107,18 +115,22 @@ def _runner(layer_class):
|
||||
K.eval(layer.output)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_SimpleRNN():
|
||||
_runner(recurrent.SimpleRNN)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_GRU():
|
||||
_runner(recurrent.GRU)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_LSTM():
|
||||
_runner(recurrent.LSTM)
|
||||
|
||||
|
||||
@keras_test
|
||||
def test_masking_layer():
|
||||
''' This test based on a previously failing issue here:
|
||||
https://github.com/fchollet/keras/issues/1567
|
||||
|
||||
Alguns arquivos não foram exibidos porque demasiados arquivos foram alterados neste diff Mostrar Mais
Referência em uma Nova Issue
Bloquear um usuário