Skip to content

Commit

Permalink
added cntk to tested keras backends (#50)
Browse files Browse the repository at this point in the history
* added cntk to tested keras backends

* added travis_wait to cntk install

* sudo required

* added cntk compatibility to most of keras model and keras model tests

* assertions

* CNTK keras backend is not yet complete, removed from tests for now

"Currently not supported: Gradient as symbolic ops"
source: https://docs.microsoft.com/en-us/cognitive-toolkit/Using-CNTK-with-Keras

* added no-coverage annotation for cntk-specific code
  • Loading branch information
jonasrauber committed Jul 25, 2017
1 parent 2129bec commit 0e606a6
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 57 deletions.
13 changes: 12 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
sudo: false
sudo: required
dist: trusty
language: python
python:
Expand All @@ -25,8 +25,19 @@ before_install:
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then pip install http://download.pytorch.org/whl/cu75/torch-0.1.12.post2-cp27-none-linux_x86_64.whl; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then pip install http://download.pytorch.org/whl/cu75/torch-0.1.12.post2-cp35-cp35m-linux_x86_64.whl; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then pip install http://download.pytorch.org/whl/cu75/torch-0.1.12.post2-cp36-cp36m-linux_x86_64.whl; fi
- if [[ $TRAVIS_PYTHON_VERSION == 2.7 ]]; then travis_wait travis_retry pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.0-cp27-cp27mu-linux_x86_64.whl; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3.5 ]]; then travis_wait travis_retry pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.0-cp35-cp35m-linux_x86_64.whl; fi
- if [[ $TRAVIS_PYTHON_VERSION == 3.6 ]]; then travis_wait travis_retry pip install https://cntk.ai/PythonWheel/CPU-Only/cntk-2.0-cp36-cp36m-linux_x86_64.whl; fi
- travis_wait travis_retry pip install --upgrade keras
- travis_wait travis_retry pip install --upgrade mxnet==0.10.0

#install open mpi for cntk
- mkdir /tmp/mpi
- pushd /tmp/mpi
- wget http://cntk.ai/PythonWheel/ForKeras/depends/openmpi_1.10-3.zip
- unzip ./openmpi_1.10-3.zip
- sudo dpkg -i openmpi_1.10-3.deb
- popd
install:
- pip install -e .
script:
Expand Down
10 changes: 6 additions & 4 deletions foolbox/models/keras.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
from __future__ import absolute_import
import warnings
import numpy as np

from .base import DifferentiableModel
Expand Down Expand Up @@ -41,9 +40,6 @@ def __init__(

from keras import backend as K

if K.backend() != 'tensorflow': # pragma: no cover
warnings.warn('Your keras backend might not be supported.')

if predicts == 'probs':
predicts = 'probabilities'
assert predicts in ['probabilities', 'logits']
Expand Down Expand Up @@ -79,7 +75,13 @@ def __init__(
# theano always returns the gradient itself (and requires
# that loss is a single scalar tensor)
assert isinstance(grads, list)
assert len(grads) == 1
grad = grads[0]
elif K.backend() == 'cntk': # pragma: no cover
assert isinstance(grads, list)
assert len(grads) == 1
grad = grads[0]
grad = K.reshape(grad, (1,) + grad.shape)
else:
assert not isinstance(grads, list)
grad = grads
Expand Down
114 changes: 62 additions & 52 deletions foolbox/tests/test_models_keras.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import pytest
import warnings

import numpy as np
from keras.layers import GlobalAveragePooling2D
Expand All @@ -18,13 +19,15 @@ def test_keras_model(num_classes):
channels = num_classes

model = Sequential()
model.add(GlobalAveragePooling2D(
data_format='channels_last', input_shape=(5, 5, channels)))
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
model.add(GlobalAveragePooling2D(
data_format='channels_last', input_shape=(5, 5, channels)))

model = KerasModel(
model,
bounds=bounds,
predicts='logits')
model = KerasModel(
model,
bounds=bounds,
predicts='logits')

test_images = np.random.rand(2, 5, 5, channels).astype(np.float32)
test_label = 7
Expand Down Expand Up @@ -53,25 +56,27 @@ def test_keras_model_probs(num_classes):
bounds = (0, 255)
channels = num_classes

inputs = Input(shape=(5, 5, channels))
logits = GlobalAveragePooling2D(
data_format='channels_last')(inputs)
probs = Activation(softmax)(logits)
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
inputs = Input(shape=(5, 5, channels))
logits = GlobalAveragePooling2D(
data_format='channels_last')(inputs)
probs = Activation(softmax)(logits)

model1 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits')
model1 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits')

model2 = KerasModel(
Model(inputs=inputs, outputs=probs),
bounds=bounds,
predicts='probabilities')
model2 = KerasModel(
Model(inputs=inputs, outputs=probs),
bounds=bounds,
predicts='probabilities')

model3 = KerasModel(
Model(inputs=inputs, outputs=probs),
bounds=bounds,
predicts='probs')
model3 = KerasModel(
Model(inputs=inputs, outputs=probs),
bounds=bounds,
predicts='probs')

np.random.seed(22)
test_images = np.random.rand(2, 5, 5, channels).astype(np.float32)
Expand All @@ -98,28 +103,30 @@ def test_keras_model_preprocess():
bounds = (0, 255)
channels = num_classes

inputs = Input(shape=(5, 5, channels))
logits = GlobalAveragePooling2D(
data_format='channels_last')(inputs)
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
inputs = Input(shape=(5, 5, channels))
logits = GlobalAveragePooling2D(
data_format='channels_last')(inputs)

preprocessing = (np.arange(num_classes)[None, None],
np.random.uniform(size=(5, 5, channels)) + 1)
preprocessing = (np.arange(num_classes)[None, None],
np.random.uniform(size=(5, 5, channels)) + 1)

model1 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits')
model1 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits')

model2 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits',
preprocessing=preprocessing)
model2 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits',
preprocessing=preprocessing)

model3 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits')
model3 = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits')

np.random.seed(22)
test_images = np.random.rand(2, 5, 5, channels).astype(np.float32)
Expand Down Expand Up @@ -147,18 +154,20 @@ def test_keras_model_gradients():
bounds = (0, 255)
channels = num_classes

inputs = Input(shape=(5, 5, channels))
logits = GlobalAveragePooling2D(
data_format='channels_last')(inputs)
with warnings.catch_warnings():
warnings.filterwarnings("ignore", category=DeprecationWarning)
inputs = Input(shape=(5, 5, channels))
logits = GlobalAveragePooling2D(
data_format='channels_last')(inputs)

preprocessing = (np.arange(num_classes)[None, None],
np.random.uniform(size=(5, 5, channels)) + 1)
preprocessing = (np.arange(num_classes)[None, None],
np.random.uniform(size=(5, 5, channels)) + 1)

model = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits',
preprocessing=preprocessing)
model = KerasModel(
Model(inputs=inputs, outputs=logits),
bounds=bounds,
predicts='logits',
preprocessing=preprocessing)

eps = 1e-3

Expand All @@ -168,8 +177,9 @@ def test_keras_model_gradients():

_, g1 = model.predictions_and_gradient(test_image, test_label)

l1 = model._loss_fn([test_image[None] - eps / 2 * g1, [test_label]])[0]
l2 = model._loss_fn([test_image[None] + eps / 2 * g1, [test_label]])[0]
test_label_array = np.array([test_label])
l1 = model._loss_fn([test_image[None] - eps / 2 * g1, test_label_array])[0]
l2 = model._loss_fn([test_image[None] + eps / 2 * g1, test_label_array])[0]

assert 1e5 * (l2 - l1) > 1

Expand Down

0 comments on commit 0e606a6

Please sign in to comment.