https://github.com/GPflow/GPflow
Tip revision: 1342c286e4c704b0e718e15a6e1d4c194ce0c076 authored by Alexander G. de G. Matthews on 04 January 2018, 11:15:29 UTC
Merge pull request #607 from GPflow/awav/awav-backward-tensors
Merge pull request #607 from GPflow/awav/awav-backward-tensors
Tip revision: 1342c28
test_transforms.py
# Copyright 2016 the GPflow authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.from __future__ import print_function
import warnings
import tensorflow as tf
import numpy as np
from numpy.testing import assert_allclose, assert_equal
import gpflow
from gpflow.transforms import Chain, Identity
from gpflow.test_util import GPflowTestCase
from gpflow import settings
class TransformTests(GPflowTestCase):
def prepare(self):
x_np = np.random.randn(10).astype(settings.float_type)
transforms = []
for transform_class in gpflow.transforms.Transform.__subclasses__():
if transform_class == Chain:
continue # Chain transform cannot be tested on its own
if transform_class == gpflow.transforms.LowerTriangular:
transforms.append(transform_class(4))
elif transform_class == gpflow.transforms.DiagMatrix:
transforms.append(transform_class(5))
else:
transform = transform_class()
transforms.append(transform)
transforms.append(Chain(Identity(), transform))
transforms.append(Chain(transform, Identity()))
transforms.append(gpflow.transforms.Logistic(7.3, 19.4))
# test __call__() and chaining:
transforms.append(gpflow.transforms.positive(gpflow.transforms.Rescale(7.5)))
transforms.append(gpflow.transforms.Rescale(9.5)(gpflow.transforms.positive))
# test helper:
transforms.append(gpflow.transforms.positiveRescale(9.5))
return tf.convert_to_tensor(x_np), x_np, transforms
def test_tf_np_forward_backward(self):
"""
Make sure the np forward transforms are the same as the tensorflow ones
"""
with self.test_context() as session:
x, x_np, transforms = self.prepare()
for t in transforms:
y_tf = t.forward_tensor(x)
y_np = t.forward(x_np)
assert_allclose(session.run(y_tf), y_np)
def test_forward_backward(self):
with self.test_context() as session:
x, x_np, transforms = self.prepare()
x_expect = x_np.copy()
x_expect = x_expect.reshape(1, x_np.size)
for t in transforms:
y_np_res = t.forward(x_np)
y_tf = t.forward_tensor(x)
y_tf_res = session.run(y_tf)
assert_allclose(y_np_res, y_tf_res)
x_np_res = t.backward(y_np_res)
x_tf = t.backward_tensor(y_tf)
x_tf_res = session.run(x_tf)
assert_allclose(x_np_res, x_tf_res)
x_expect = x_np.reshape(x_np_res.shape)
assert_allclose(x_expect, x_np_res)
assert_allclose(x_expect, x_tf_res)
def test_logjac(self):
"""
We have hand-crafted the log-jacobians for speed. Check they're correct
wrt a tensorflow derived version
"""
with self.test_context() as session:
x, x_np, transforms = self.prepare()
# there is no jacobian: loop manually
def jacobian(f):
return tf.stack([tf.gradients(f(x)[i], x)[0] for i in range(10)])
tf_jacs = [tf.log(tf.matrix_determinant(jacobian(t.forward_tensor)))
for t in transforms
if not isinstance(t, (gpflow.transforms.LowerTriangular,
gpflow.transforms.DiagMatrix))]
hand_jacs = [t.log_jacobian_tensor(x)
for t in transforms
if not isinstance(t, (gpflow.transforms.LowerTriangular,
gpflow.transforms.DiagMatrix))]
for j1, j2 in zip(tf_jacs, hand_jacs):
j1_res = session.run(j1)
j2_res = session.run(j2)
assert_allclose(j1_res, j2_res)
def test_logistic_error_wrong_order(self):
with self.assertRaises(ValueError):
gpflow.transforms.Logistic(8.0, 4.7)
def test_logistic_error_bounds_equal(self):
with self.assertRaises(ValueError):
gpflow.transforms.Logistic(4.7, 4.7)
def test_bad_chain_argument(self):
t = gpflow.transforms.Logistic(1.0, 2.0)
with self.assertRaises(TypeError):
t(1.5) # this syntax chains transforms, is not equivalent to t.forward(x)
class TestChainIdentity(GPflowTestCase):
def prepare(self):
x_np = np.random.randn(10).astype(settings.float_type)
transforms = []
for transform in gpflow.transforms.Transform.__subclasses__():
if transform != Chain and transform != gpflow.transforms.LowerTriangular:
transforms.append(transform())
transforms.append(gpflow.transforms.Logistic(7.3, 19.4))
return tf.convert_to_tensor(x_np), x_np, transforms
def assertEqualElements(self, lst):
elem0 = lst[0]
for elemi in lst[1:]:
assert_equal(elem0, elemi)
def test_equivalence(self):
"""
Make sure chaining with identity doesn't lead to different values.
"""
with self.test_context() as session:
x, x_np, transforms = self.prepare()
for transform in transforms:
equiv_transforms = [transform,
Chain(transform, Identity()),
Chain(Identity(), transform)]
ys_np = [t.forward(x_np) for t in equiv_transforms]
self.assertEqualElements(ys_np)
y_np = ys_np[0]
xs_np = [t.backward(y_np) for t in equiv_transforms]
self.assertEqualElements(xs_np)
ys = [t.forward_tensor(x) for t in equiv_transforms]
ys_tf = [session.run(y) for y in ys]
self.assertEqualElements(ys_tf)
logjs = [t.log_jacobian_tensor(x) for t in equiv_transforms]
logjs_tf = [session.run(logj) for logj in logjs]
self.assertEqualElements(logjs_tf)
class TestOverflow(GPflowTestCase):
"""
Bug #302 identified an overflow in the standard positive transform. This is a regression test.
"""
def setUp(self):
self.t = gpflow.transforms.Log1pe()
def testOverflow(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
y = self.t.forward(np.array([-1000, -300, -10, 10, 300, 1000]))
self.assertEqual(len(w), 0)
self.assertFalse(np.any(np.isinf(y)))
self.assertFalse(np.any(np.isnan(y)))
def testDivByZero(self):
with warnings.catch_warnings(record=True) as w:
warnings.simplefilter('always')
y = self.t.backward(np.array([self.t._lower]))
self.assertTrue(len(w) == 0)
self.assertFalse(np.any(np.isinf(y)))
self.assertFalse(np.any(np.isnan(y)))
class TestMatrixTransforms(GPflowTestCase):
"""
Some extra tests for the matrix transformations.
"""
def test_LowerTriangular(self):
t = gpflow.transforms.LowerTriangular(1, 3)
t.forward(np.ones(3 * 6))
with self.assertRaises(ValueError):
t.forward(np.ones(3 * 7))
def test_DiagMatrix(self):
t = gpflow.transforms.DiagMatrix(3)
t.backward(np.eye(3))
t.backward(np.eye(3)[None, :, :])
t.backward(np.eye(3)[None, :, :] * np.array([1, 2])[:, None, None])
with self.assertRaises(ValueError):
t.backward(np.eye(4))
t.backward(np.eye(2)[None, :, :] * np.array([1, 2, 3])[:, None, None])
class TestDiagMatrixTransform(GPflowTestCase):
def setUp(self):
self.t1 = gpflow.transforms.DiagMatrix(dim=1)
self.t2 = gpflow.transforms.DiagMatrix(dim=3)
def test_forward_backward(self):
free_1d = np.random.randn(8)
fwd1d = self.t1.forward(free_1d)
assert_allclose(fwd1d.shape, np.array([len(free_1d), self.t1.dim, self.t1.dim]))
assert_allclose(free_1d, self.t1.backward(fwd1d))
size2d = 5
free_2d = np.random.randn(size2d, self.t2.dim).flatten()
fwd2d = self.t2.forward(free_2d)
assert_allclose(fwd2d.shape, np.array([size2d, self.t2.dim, self.t2.dim]))
assert_allclose(free_2d, self.t2.backward(fwd2d))
def test_tf_np_forward(self):
"""
Make sure the np forward transforms are the same as the tensorflow ones
"""
with self.test_context() as session:
free = np.random.randn(8, self.t2.dim)
x = tf.convert_to_tensor(free)
ys = session.run(self.t2.forward_tensor(x))
assert_allclose(ys, self.t2.forward(free))
free = np.random.randn(7, self.t1.dim)
x = tf.convert_to_tensor(free)
ys = session.run(self.t1.forward_tensor(x))
assert_allclose(ys, self.t1.forward(free))
if __name__ == "__main__":
tf.test.main()