1075 lines
34 KiB
Python
1075 lines
34 KiB
Python
# Copyright 2017 The TensorFlow Authors. All Rights Reserved.
|
|
#
|
|
# 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.
|
|
# ==============================================================================
|
|
"""Tests for XLA JIT compiler."""
|
|
|
|
import unittest
|
|
|
|
import numpy as np
|
|
import six
|
|
|
|
from tensorflow.compiler.tests import xla_test
|
|
from tensorflow.python.framework import dtypes
|
|
from tensorflow.python.ops import array_ops
|
|
from tensorflow.python.ops import array_ops_stack # pylint: disable=g-direct-tensorflow-import
|
|
from tensorflow.python.ops import bitwise_ops
|
|
from tensorflow.python.ops import gen_functional_ops
|
|
from tensorflow.python.ops import gen_nn_ops
|
|
from tensorflow.python.ops import math_ops
|
|
from tensorflow.python.ops import nn_ops
|
|
from tensorflow.python.platform import googletest
|
|
|
|
|
|
def nhwc_to_format(x, data_format):
|
|
"""Converts a numpy array from NHWC format to `data_format`."""
|
|
rank = len(x.shape)
|
|
if data_format == "NCHW":
|
|
return np.transpose(x, [0, rank - 1] + list(range(1, rank - 1)))
|
|
elif data_format == "NHWC":
|
|
return x
|
|
else:
|
|
raise ValueError("Unknown format {}".format(data_format))
|
|
|
|
|
|
class UnaryOpsTest(xla_test.XLATestCase):
|
|
"""Test cases for unary operators."""
|
|
|
|
def _assertOpOutputMatchesExpected(
|
|
self, op, inp, expected, equality_test=None, rtol=1e-3, atol=1e-5
|
|
):
|
|
"""Verifies that 'op' produces 'expected' when fed input 'inp' .
|
|
|
|
Args:
|
|
op: operator to test
|
|
inp: numpy input array to use as input to 'op'.
|
|
expected: numpy array representing the expected output of 'op'.
|
|
equality_test: either None, or a function that tests two numpy arrays for
|
|
equality. If None, self.assertAllClose is used.
|
|
rtol: relative tolerance for equality test.
|
|
atol: absolute tolerance for equality test.
|
|
"""
|
|
with self.session() as session:
|
|
with self.test_scope():
|
|
pinp = array_ops.placeholder(
|
|
dtypes.as_dtype(inp.dtype), inp.shape, name="a"
|
|
)
|
|
output = op(pinp)
|
|
result = session.run(output, {pinp: inp})
|
|
if equality_test is None:
|
|
self.assertEqual(output.dtype, expected.dtype)
|
|
self.assertAllCloseAccordingToType(
|
|
expected, result, rtol=rtol, atol=atol, bfloat16_rtol=0.03
|
|
)
|
|
else:
|
|
equality_test(result, expected, rtol=rtol, atol=atol)
|
|
|
|
def ListsAreClose(self, result, expected, rtol, atol):
|
|
"""Tests closeness of two lists of floats."""
|
|
self.assertEqual(len(result), len(expected))
|
|
for i in range(len(result)):
|
|
self.assertAllClose(result[i], expected[i], rtol, atol)
|
|
|
|
def AssertCloseAndSorted(self, result, expected, rtol, atol):
|
|
"""Tests that result and expected are both close and sorted."""
|
|
self.assertAllClose(result, expected, rtol, atol)
|
|
self.assertAllEqual(np.sort(result), result)
|
|
|
|
def AssertAllEqual(self, result, expected, rtol, atol):
|
|
"""Tests that result and expected are exactly equal."""
|
|
self.assertAllEqual(result, expected)
|
|
|
|
def testAllTypeOps(self):
|
|
for dtype in self.numeric_types - {np.int8, np.uint8}:
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.diag,
|
|
np.array([1, 2, 3, 4], dtype=dtype),
|
|
np.array(
|
|
[[1, 0, 0, 0], [0, 2, 0, 0], [0, 0, 3, 0], [0, 0, 0, 4]],
|
|
dtype=dtype,
|
|
),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.diag_part,
|
|
np.arange(36).reshape([2, 3, 2, 3]).astype(dtype),
|
|
np.array([[0, 7, 14], [21, 28, 35]], dtype=dtype),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.diag,
|
|
np.array([[1, 2], [3, 4]], dtype=dtype),
|
|
np.array(
|
|
[
|
|
[[[1, 0], [0, 0]], [[0, 2], [0, 0]]],
|
|
[[[0, 0], [3, 0]], [[0, 0], [0, 4]]],
|
|
],
|
|
dtype=dtype,
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.identity,
|
|
np.array([[-1, 1]], dtype=dtype),
|
|
expected=np.array([[-1, 1]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.prevent_gradient,
|
|
np.array([[-1, 1]], dtype=dtype),
|
|
expected=np.array([[-1, 1]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.squeeze,
|
|
np.array([[[[[]]]]], dtype=dtype),
|
|
expected=np.array([], dtype=dtype),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.squeeze,
|
|
np.array([[[1], [2]]], dtype=dtype),
|
|
expected=np.array([1, 2], dtype=dtype),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.squeeze,
|
|
np.array([[[1]], [[2]]], dtype=dtype),
|
|
expected=np.array([1, 2], dtype=dtype),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.squeeze,
|
|
np.array([[[1, 2], [3, 4]]], dtype=dtype),
|
|
expected=np.array([[1, 2], [3, 4]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.stop_gradient,
|
|
np.array([[-1, 1]], dtype=dtype),
|
|
expected=np.array([[-1, 1]], dtype=dtype),
|
|
)
|
|
|
|
def testLog(self):
|
|
for dtype in self.float_types - {dtypes.bfloat16.as_numpy_dtype}:
|
|
tol = 1e-4 if dtype == np.float32 else 1e-9
|
|
# pylint: disable=invalid-unary-operand-type
|
|
x = np.linspace(-np.e, np.e, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.log, x, expected=np.log(x), atol=tol, rtol=tol
|
|
)
|
|
|
|
x = np.linspace(0.0, np.e * 1e-30, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.log, x, expected=np.log(x), atol=tol, rtol=tol
|
|
)
|
|
|
|
x = np.linspace(0.0, np.pi * 1e30, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.log, x, expected=np.log(x), atol=tol, rtol=tol
|
|
)
|
|
|
|
def testSin(self):
|
|
for dtype in self.float_types - {dtypes.bfloat16.as_numpy_dtype}:
|
|
tol = 1e-6 if dtype == np.float32 else 1e-12
|
|
|
|
x = np.linspace(-4 * np.e, 4 * np.e, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sin, x, expected=np.sin(x), rtol=tol, atol=tol
|
|
)
|
|
|
|
x = np.linspace(0.0, np.e * 1e-30, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sin, x, expected=np.sin(x), rtol=tol, atol=tol
|
|
)
|
|
|
|
if dtype == np.float64:
|
|
x = np.linspace(0.0, np.e * 1e8, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sin, x, expected=np.sin(x), rtol=tol, atol=1e-5
|
|
)
|
|
|
|
def testCos(self):
|
|
for dtype in self.float_types - {dtypes.bfloat16.as_numpy_dtype}:
|
|
tol = 1e-6 if dtype == np.float32 else 1e-12
|
|
|
|
x = np.linspace(-4 * np.e, 4 * np.e, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.cos, x, expected=np.cos(x), rtol=tol, atol=tol
|
|
)
|
|
|
|
x = np.linspace(0.0, np.e * 1e-30, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.cos, x, expected=np.cos(x), rtol=tol, atol=tol
|
|
)
|
|
|
|
if dtype == np.float64:
|
|
x = np.linspace(0.0, np.e * 1e8, num=1000, dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.cos, x, expected=np.cos(x), rtol=tol, atol=1e-5
|
|
)
|
|
|
|
def testSigmoidNumericalStability(self):
|
|
for dtype in self.float_types:
|
|
if dtype != np.float16:
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: math_ops.sigmoid(x) / math_ops.log1p(math_ops.exp(x)),
|
|
np.array([-40, 40], dtype=dtype),
|
|
expected=np.array([1.0, 0.025], dtype=dtype),
|
|
)
|
|
|
|
def testQuantizeAndDequantize(self):
|
|
for dtype in self.float_types:
|
|
|
|
def quantize_and_dequantize_v2(x):
|
|
return array_ops.quantize_and_dequantize(
|
|
x, -127, 127, signed_input=True, num_bits=8
|
|
)
|
|
|
|
def quantize_and_dequantize_v3(x):
|
|
return array_ops.quantize_and_dequantize_v3(
|
|
x, -127, 127, num_bits=8, signed_input=True, range_given=False
|
|
)
|
|
|
|
def quantize_and_dequantize_v4(x):
|
|
return array_ops.quantize_and_dequantize_v2(
|
|
x, -127, 127, signed_input=True, num_bits=8
|
|
)
|
|
|
|
test_fns = (
|
|
quantize_and_dequantize_v2,
|
|
quantize_and_dequantize_v3,
|
|
quantize_and_dequantize_v4,
|
|
)
|
|
for test_fn in test_fns:
|
|
self._assertOpOutputMatchesExpected(
|
|
test_fn,
|
|
np.array([-1, -0.5, 0, 0.3], dtype=dtype),
|
|
expected=np.array([-1.0, -0.5, 0.0, 0.296875], dtype=dtype),
|
|
)
|
|
|
|
def quantize_and_dequantize_v2_round_half_up(x):
|
|
return array_ops.quantize_and_dequantize(
|
|
x,
|
|
-1.0,
|
|
1.0,
|
|
signed_input=True,
|
|
num_bits=8,
|
|
range_given=True,
|
|
round_mode="HALF_UP",
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
quantize_and_dequantize_v2_round_half_up,
|
|
np.array([-0.8, -0.4, 0, 0.3, 0.8, -2, 33], dtype=dtype),
|
|
expected=np.array(
|
|
[
|
|
-102.0 / 127,
|
|
-51.0 / 127,
|
|
0,
|
|
38.0 / 127,
|
|
102.0 / 127,
|
|
-128.0 / 127,
|
|
1,
|
|
],
|
|
dtype=dtype,
|
|
),
|
|
)
|
|
|
|
def quantize_and_dequantize_v2_round_half_to_even(x):
|
|
return array_ops.quantize_and_dequantize(
|
|
x,
|
|
-1.0,
|
|
1.0,
|
|
signed_input=True,
|
|
num_bits=8,
|
|
range_given=True,
|
|
round_mode="HALF_TO_EVEN",
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
quantize_and_dequantize_v2_round_half_to_even,
|
|
np.array([-0.8, -0.4, 0, 0.3, 0.8, -2, 33], dtype=dtype),
|
|
expected=np.array(
|
|
[
|
|
-102.0 / 127,
|
|
-51.0 / 127,
|
|
0,
|
|
38.0 / 127,
|
|
102.0 / 127,
|
|
-128.0 / 127,
|
|
1,
|
|
],
|
|
dtype=dtype,
|
|
),
|
|
)
|
|
|
|
def testComplexOps(self):
|
|
for dtype in self.complex_types:
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.acosh,
|
|
np.array([0.1, 0.2j, 0.3 - 0.1j, 0.4 + 0.5j], dtype=dtype),
|
|
expected=np.arccosh(
|
|
np.array([0.1, 0.2j, 0.3 - 0.1j, 0.4 + 0.5j], dtype=dtype)
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.asinh,
|
|
np.array([0.1, 0.2j, 0.3 - 0.1j, 0.4 + 0.5j], dtype=dtype),
|
|
expected=np.arcsinh(
|
|
np.array([0.1, 0.2j, 0.3 - 0.1j, 0.4 + 0.5j], dtype=dtype)
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.atanh,
|
|
np.array([0.1, 0.2j, 0.3 - 0.1j, 0.4 + 0.5j], dtype=dtype),
|
|
expected=np.arctanh(
|
|
np.array([0.1, 0.2j, 0.3 - 0.1j, 0.4 + 0.5j], dtype=dtype)
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.cosh,
|
|
np.array([1j, 2 - 3j, 3, 4 + 2j], dtype=dtype),
|
|
expected=np.cosh(np.array([1j, 2 - 3j, 3, 4 + 2j], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sinh,
|
|
np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype),
|
|
expected=np.sinh(np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.exp,
|
|
np.array([[-1 + 2j, 3j, 2 - 3j]], dtype=dtype),
|
|
expected=np.exp(np.array([[-1 + 2j, 3j, 2 - 3j]], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.expm1,
|
|
np.array([[-1 + 2j, 3j, 2 - 3j]], dtype=dtype),
|
|
expected=np.expm1(np.array([[-1 + 2j, 3j, 2 - 3j]], dtype=dtype)),
|
|
rtol=1e-6,
|
|
atol=1e-6,
|
|
)
|
|
|
|
# For real part close to zero, or imaginary part close to a multiple of
|
|
# pi.
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.expm1,
|
|
np.array(
|
|
[[
|
|
1e-11 + 1j,
|
|
-1e-11 - 1j,
|
|
1.0 + 1e-11j,
|
|
-1.0 - 1e-11j,
|
|
1e-13j + 1e-13j,
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
expected=np.expm1(
|
|
np.array(
|
|
[[
|
|
1e-11 + 1j,
|
|
-1e-11 - 1j,
|
|
1.0 + 1e-11j,
|
|
-1.0 - 1e-11j,
|
|
1e-13j + 1e-13j,
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
dtype=dtype,
|
|
),
|
|
rtol=1e-09,
|
|
atol=1e-20,
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.reciprocal,
|
|
np.array([[1, 2j, 2 + 3j]], dtype=dtype),
|
|
expected=1.0 / np.array([[1, 2j, 2 + 3j]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.log,
|
|
np.array([[5j, 3 - 2j]], dtype=dtype),
|
|
expected=np.log(np.array([[5j, 3 - 2j]], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sin,
|
|
np.array([[5j, 3 - 2j]], dtype=dtype),
|
|
expected=np.sin(np.array([[5j, 3 - 2j]], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.cos,
|
|
np.array([[5j, 3 - 2j]], dtype=dtype),
|
|
expected=np.cos(np.array([[5j, 3 - 2j]], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.log1p,
|
|
np.array([[1e-14, 1e-15j, 0.6 - 0.3j]], dtype=dtype),
|
|
expected=np.log1p(
|
|
np.array([[1e-14, 1e-15j, 0.6 - 0.3j]], dtype=dtype)
|
|
),
|
|
rtol=1e-4,
|
|
atol=1e-6,
|
|
)
|
|
|
|
val = np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.rsqrt, val, expected=1 / np.sqrt(val)
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sigmoid, val, expected=1 / (1 + np.exp(-val))
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sqrt, val, expected=np.sqrt(val)
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.tanh,
|
|
np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype),
|
|
expected=np.tanh(np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.tan,
|
|
np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype),
|
|
expected=np.tan(np.array([1, 2j, 2 - 3j, 4 + 5j], dtype=dtype)),
|
|
)
|
|
|
|
ctypes = {np.complex64: np.float32, np.complex128: np.float64}
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.abs,
|
|
np.array([[3 - 4j, -1j, np.inf]], dtype=dtype),
|
|
expected=np.array([[5, 1, np.inf]], dtype=ctypes[dtype]),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.negative,
|
|
np.array([[-1 + 2j, -3j]], dtype=dtype),
|
|
expected=np.array([[1 - 2j, 3j]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.square,
|
|
np.array([[-2 - 3j, 3 + 4j, 5j]], dtype=dtype),
|
|
expected=np.array([[-2 - 3j, 3 + 4j, 5j]], dtype=dtype) ** 2,
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.zeros_like,
|
|
np.array([[4j, 3 - 2j], [2, -1j]], dtype=dtype),
|
|
expected=np.array([[0, 0], [0, 0]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.ones_like,
|
|
np.array([[-4j, 3 + 2j], [2, -1j]], dtype=dtype),
|
|
expected=np.array([[1, 1], [1, 1]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.angle,
|
|
np.array([1 + 3j, -4 + 7j, 2.7, -3j], dtype=dtype),
|
|
expected=np.angle(np.array([1 + 3j, -4 + 7j, 2.7, -3j], dtype=dtype)),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.conj,
|
|
np.array([1 + 3j, -4 + 7j, 2.7, -3j], dtype=dtype),
|
|
expected=np.array([1 - 3j, -4 - 7j, 2.7, 3j], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.imag,
|
|
np.array([1 + 3j, -4 + 7j, 2.7, -3j], dtype=dtype),
|
|
expected=np.array([3, 7, 0, -3], dtype=ctypes[dtype]),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.real,
|
|
np.array([1 + 3j, -4 + 7j, 2.7, -3j], dtype=dtype),
|
|
expected=np.array([1, -4, 2.7, 0], dtype=ctypes[dtype]),
|
|
)
|
|
|
|
def testIntOps(self):
|
|
for dtype in self.int_types - self.unsigned_int_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
bitwise_ops.invert,
|
|
np.array([0, -1, 1, 16, 42], dtype=dtype),
|
|
expected=np.array([-1, 0, -2, -17, -43], dtype=dtype),
|
|
)
|
|
|
|
# Test population_count for array inputs.
|
|
raw_inputs = [
|
|
0,
|
|
1,
|
|
-1,
|
|
3,
|
|
-3,
|
|
5,
|
|
-5,
|
|
14,
|
|
-14,
|
|
127,
|
|
128,
|
|
255,
|
|
256,
|
|
65535,
|
|
65536,
|
|
2**31 - 1,
|
|
2**31,
|
|
2**32 - 1,
|
|
2**32,
|
|
-(2**32) + 1,
|
|
-(2**32),
|
|
-(2**63) + 1,
|
|
2**63 - 1,
|
|
]
|
|
# Only choose inputs which fit in the int dtype.
|
|
raw_inputs = list(
|
|
filter(
|
|
lambda x: np.iinfo(dtype).min <= x <= np.iinfo(dtype).max,
|
|
raw_inputs,
|
|
)
|
|
)
|
|
inputs = np.array(raw_inputs, dtype=dtype)
|
|
|
|
def count_bits(x):
|
|
return sum(bin(z).count("1") for z in six.iterbytes(x.tobytes()))
|
|
|
|
truth = [count_bits(x) for x in inputs]
|
|
self._assertOpOutputMatchesExpected(
|
|
bitwise_ops.population_count,
|
|
inputs,
|
|
expected=np.array(truth, dtype=np.uint8),
|
|
equality_test=self.AssertAllEqual,
|
|
)
|
|
|
|
# Test population_count for scalar inputs.
|
|
for raw_inp in raw_inputs:
|
|
inp = dtype(raw_inp)
|
|
truth = count_bits(inp)
|
|
self._assertOpOutputMatchesExpected(
|
|
bitwise_ops.population_count,
|
|
inp,
|
|
expected=np.uint8(truth),
|
|
equality_test=self.AssertAllEqual,
|
|
)
|
|
|
|
def testNumericOps(self):
|
|
for dtype in self.numeric_types - {np.int8, np.uint8}:
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.abs,
|
|
np.array([[2, -1]], dtype=dtype),
|
|
expected=np.array([[2, 1]], dtype=np.real(dtype(0)).dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.negative,
|
|
np.array([[-1, 1]], dtype=dtype),
|
|
expected=np.array([[1, -1]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.square,
|
|
np.array([[-2, 3]], dtype=dtype),
|
|
expected=np.array([[4, 9]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.zeros_like,
|
|
np.array([[4, 3], [2, 1]], dtype=dtype),
|
|
expected=np.array([[0, 0], [0, 0]], dtype=dtype),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.ones_like,
|
|
np.array([[4, 3], [2, 1]], dtype=dtype),
|
|
expected=np.array([[1, 1], [1, 1]], dtype=dtype),
|
|
)
|
|
|
|
# TODO(phawkins): these tests fail unless fastmath optimizations
|
|
# are disabled. Use more robust IsInf/IsNaN detection and enable these
|
|
# tests.
|
|
@unittest.skip("test case fails in fast-math mode")
|
|
def testIsInfAndIsNan(self):
|
|
for dtype in self.float_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.is_inf,
|
|
np.array(
|
|
[[-np.inf, -2, -1, 0, 0.5, 1, 2, np.inf, np.nan]], dtype=dtype
|
|
),
|
|
expected=np.array([[1, 0, 0, 0, 0, 0, 0, 1, 0]], dtype=np.bool_),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.is_nan,
|
|
np.array(
|
|
[[-np.inf, -2, -1, 0, 0.5, 1, 2, np.inf, np.nan]], dtype=dtype
|
|
),
|
|
expected=np.array([[0, 0, 0, 0, 0, 0, 0, 0, 1]], dtype=np.bool_),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.sign,
|
|
np.array([[np.nan]], dtype=dtype),
|
|
expected=np.array([[0.0]], dtype=dtype),
|
|
)
|
|
|
|
def testLogicalOps(self):
|
|
self._assertOpOutputMatchesExpected(
|
|
math_ops.logical_not,
|
|
np.array([[True, False], [False, True]], dtype=np.bool_),
|
|
expected=np.array([[False, True], [True, False]], dtype=np.bool_),
|
|
)
|
|
|
|
def testBiasAddGrad(self):
|
|
self._assertOpOutputMatchesExpected(
|
|
gen_nn_ops.bias_add_grad,
|
|
np.array([[1.0, 2.0], [3.0, 4.0]], dtype=np.float32),
|
|
expected=np.array([4.0, 6.0], dtype=np.float32),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: gen_nn_ops.bias_add_grad(x, data_format="NCHW"),
|
|
np.array(
|
|
[[[1.0, 2.0], [3.0, 4.0]], [[5.0, 6.0], [7.0, 8.0]]],
|
|
dtype=np.float32,
|
|
),
|
|
expected=np.array([14.0, 22.0], dtype=np.float32),
|
|
)
|
|
|
|
def testBitcast(self):
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.int32),
|
|
np.array([1, 0x3F800000], np.int32),
|
|
expected=np.array([1, 0x3F800000], np.int32),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.float32),
|
|
np.array([1, 0x3F800000], np.int32),
|
|
expected=np.array([1e-45, 1.0], np.float32),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.int32),
|
|
np.array([1e-45, 1.0], np.float32),
|
|
expected=np.array([1, 0x3F800000], np.int32),
|
|
)
|
|
if np.int64 in self.numeric_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.int64),
|
|
np.array([1, 0x100000003F800000], np.uint64),
|
|
expected=np.array([1, 0x100000003F800000], np.int64),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.uint64),
|
|
np.array([1, 0x100000003F800000], np.int64),
|
|
expected=np.array([1, 0x100000003F800000], np.uint64),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.float64),
|
|
np.array(
|
|
[0, 0x3FF0000000000000, 0xC3AF161421C8E000, 0x4032000000000007],
|
|
np.uint64,
|
|
),
|
|
expected=np.array(
|
|
[0, 1.0, -1.12e18, 18.000000000000024869], np.float64
|
|
),
|
|
atol=0,
|
|
)
|
|
|
|
def testBitcastInt8ToFloat(self):
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.float32),
|
|
np.array([[1, 0, 0, 0], [0xD0, 0x0F, 0x49, 0x40]]).astype(np.int8),
|
|
expected=np.array([1e-45, 3.14159], np.float32),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops.bitcast(x, dtypes.np.int8),
|
|
np.array([1e-45, 3.14159], np.float32),
|
|
expected=np.array([[1, 0, 0, 0], [0xD0, 0x0F, 0x49, 0x40]]).astype(
|
|
np.int8
|
|
),
|
|
)
|
|
|
|
def testInvertPermutation(self):
|
|
for np_dtype in [np.int32, np.int64]:
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops.invert_permutation,
|
|
np.array([1, 2, 0], np_dtype),
|
|
expected=np.array([2, 0, 1], dtype=np_dtype),
|
|
)
|
|
|
|
def testInvertPermutationTwiceIsNoop(self):
|
|
|
|
def invert_twice(x):
|
|
return array_ops.invert_permutation(array_ops.invert_permutation(x))
|
|
|
|
for np_dtype in [np.int32, np.int64]:
|
|
self._assertOpOutputMatchesExpected(
|
|
invert_twice,
|
|
np.array([1, 2, 0], np_dtype),
|
|
expected=np.array([1, 2, 0], dtype=np_dtype),
|
|
)
|
|
|
|
def testRank(self):
|
|
rank_op = lambda x: array_ops.rank_internal(x, optimize=False)
|
|
for dtype in self.numeric_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
rank_op, dtype(7), expected=np.int32(0)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
rank_op, np.array([[], []], dtype=dtype), expected=np.int32(2)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
rank_op, np.array([0, 1], dtype=dtype), expected=np.int32(1)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
rank_op, np.array([[0, 1]], dtype=dtype), expected=np.int32(2)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
rank_op, np.array([[0], [1], [4]], dtype=dtype), expected=np.int32(2)
|
|
)
|
|
|
|
def testShape(self):
|
|
shape_op = lambda x: array_ops.shape_internal(x, optimize=False)
|
|
for dtype in self.numeric_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
shape_op, dtype(7), expected=np.array([], dtype=np.int32)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
shape_op,
|
|
np.array([[], []], dtype=dtype),
|
|
expected=np.array([2, 0], dtype=np.int32),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
shape_op,
|
|
np.array([0, 1], dtype=dtype),
|
|
expected=np.array([2], dtype=np.int32),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
shape_op,
|
|
np.array([[0, 1]], dtype=dtype),
|
|
expected=np.array([1, 2], dtype=np.int32),
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
shape_op,
|
|
np.array([[0], [1], [4]], dtype=dtype),
|
|
expected=np.array([3, 1], dtype=np.int32),
|
|
)
|
|
|
|
def testSize(self):
|
|
size_op = lambda x: array_ops.size_internal(x, optimize=False)
|
|
for dtype in self.numeric_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
size_op, dtype(7), expected=np.int32(1)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
size_op, np.array([[], []], dtype=dtype), expected=np.int32(0)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
size_op, np.array([0, 1], dtype=dtype), expected=np.int32(2)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
size_op, np.array([[0, 1]], dtype=dtype), expected=np.int32(2)
|
|
)
|
|
self._assertOpOutputMatchesExpected(
|
|
size_op, np.array([[0], [1], [4]], dtype=dtype), expected=np.int32(3)
|
|
)
|
|
|
|
def testSizeWithInt64OutType(self):
|
|
|
|
def size_op(x):
|
|
return array_ops.size_internal(x, optimize=False, out_type=np.int64)
|
|
|
|
for dtype in self.numeric_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
size_op, np.array([[0], [1], [4]], dtype=dtype), expected=np.int64(3)
|
|
)
|
|
|
|
def testUnpack(self):
|
|
self._assertOpOutputMatchesExpected(
|
|
array_ops_stack.unstack,
|
|
np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32),
|
|
expected=[
|
|
np.array([1.0, 2.0], dtype=np.float32),
|
|
np.array([3.0, 4.0], dtype=np.float32),
|
|
np.array([5.0, 6.0], dtype=np.float32),
|
|
],
|
|
equality_test=self.ListsAreClose,
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
lambda x: array_ops_stack.unstack(x, axis=1),
|
|
np.array([[1.0, 2.0], [3.0, 4.0], [5.0, 6.0]], dtype=np.float32),
|
|
expected=[
|
|
np.array([1.0, 3.0, 5.0], dtype=np.float32),
|
|
np.array([2.0, 4.0, 6.0], dtype=np.float32),
|
|
],
|
|
equality_test=self.ListsAreClose,
|
|
)
|
|
|
|
def testDepthToSpace(self):
|
|
|
|
def make_op(data_format):
|
|
|
|
def op(x):
|
|
return array_ops.depth_to_space(
|
|
x, block_size=2, data_format=data_format
|
|
)
|
|
|
|
return op
|
|
|
|
for dtype in self.numeric_types:
|
|
for data_format in ["NCHW", "NHWC"]:
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op(data_format),
|
|
nhwc_to_format(
|
|
np.array([[[[1, 2, 3, 4]]]], dtype=dtype), data_format
|
|
),
|
|
expected=nhwc_to_format(
|
|
np.array([[[[1], [2]], [[3], [4]]]], dtype=dtype), data_format
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op(data_format),
|
|
nhwc_to_format(
|
|
np.array(
|
|
[[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]]]], dtype=dtype
|
|
),
|
|
data_format,
|
|
),
|
|
expected=nhwc_to_format(
|
|
np.array(
|
|
[[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]],
|
|
dtype=dtype,
|
|
),
|
|
data_format,
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op(data_format),
|
|
nhwc_to_format(
|
|
np.array(
|
|
[[
|
|
[[1, 2, 3, 4], [5, 6, 7, 8]],
|
|
[[9, 10, 11, 12], [13, 14, 15, 16]],
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
data_format,
|
|
),
|
|
expected=nhwc_to_format(
|
|
np.array(
|
|
[[
|
|
[[1], [2], [5], [6]],
|
|
[[3], [4], [7], [8]],
|
|
[[9], [10], [13], [14]],
|
|
[[11], [12], [15], [16]],
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
data_format,
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op("NCHW_VECT_C"),
|
|
np.arange(32, dtype=dtype).reshape((1, 8, 1, 1, 4)),
|
|
expected=np.array(
|
|
[[
|
|
[
|
|
[[0, 1, 2, 3], [8, 9, 10, 11]],
|
|
[[16, 17, 18, 19], [24, 25, 26, 27]],
|
|
],
|
|
[
|
|
[[4, 5, 6, 7], [12, 13, 14, 15]],
|
|
[[20, 21, 22, 23], [28, 29, 30, 31]],
|
|
],
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
)
|
|
|
|
def testSpaceToDepth(self):
|
|
|
|
def make_op(data_format):
|
|
|
|
def op(x):
|
|
return array_ops.space_to_depth(
|
|
x, block_size=2, data_format=data_format
|
|
)
|
|
|
|
return op
|
|
|
|
for dtype in self.numeric_types:
|
|
for data_format in ["NCHW", "NHWC"]:
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op(data_format),
|
|
nhwc_to_format(
|
|
np.array([[[[1], [2]], [[3], [4]]]], dtype=dtype), data_format
|
|
),
|
|
expected=nhwc_to_format(
|
|
np.array([[[[1, 2, 3, 4]]]], dtype=dtype), data_format
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op(data_format),
|
|
nhwc_to_format(
|
|
np.array(
|
|
[[[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]],
|
|
dtype=dtype,
|
|
),
|
|
data_format,
|
|
),
|
|
expected=nhwc_to_format(
|
|
np.array(
|
|
[[[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]]]], dtype=dtype
|
|
),
|
|
data_format,
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op(data_format),
|
|
nhwc_to_format(
|
|
np.array(
|
|
[[
|
|
[[1], [2], [5], [6]],
|
|
[[3], [4], [7], [8]],
|
|
[[9], [10], [13], [14]],
|
|
[[11], [12], [15], [16]],
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
data_format,
|
|
),
|
|
expected=nhwc_to_format(
|
|
np.array(
|
|
[[
|
|
[[1, 2, 3, 4], [5, 6, 7, 8]],
|
|
[[9, 10, 11, 12], [13, 14, 15, 16]],
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
data_format,
|
|
),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
make_op("NCHW_VECT_C"),
|
|
np.arange(32, dtype=dtype).reshape((1, 2, 2, 2, 4)),
|
|
expected=np.array(
|
|
[[
|
|
[[[0, 1, 2, 3]]],
|
|
[[[16, 17, 18, 19]]],
|
|
[[[4, 5, 6, 7]]],
|
|
[[[20, 21, 22, 23]]],
|
|
[[[8, 9, 10, 11]]],
|
|
[[[24, 25, 26, 27]]],
|
|
[[[12, 13, 14, 15]]],
|
|
[[[28, 29, 30, 31]]],
|
|
]],
|
|
dtype=dtype,
|
|
),
|
|
)
|
|
|
|
def _assertSoftplusMatchesExpected(
|
|
self, features, dtype, equality_test=None, rtol=1e-6, atol=9.1e-6
|
|
):
|
|
features = np.array(features, dtype=dtype)
|
|
zero = np.asarray(0).astype(dtype)
|
|
expected = np.logaddexp(zero, features).astype(dtype)
|
|
self._assertOpOutputMatchesExpected(
|
|
nn_ops.softplus,
|
|
features,
|
|
expected=expected,
|
|
equality_test=equality_test,
|
|
rtol=rtol,
|
|
atol=atol,
|
|
)
|
|
|
|
def testSoftplus(self):
|
|
for dtype in self.float_types & {dtypes.float32, dtypes.float64}:
|
|
self._assertSoftplusMatchesExpected([[-2, 0, 8]], dtype)
|
|
self._assertSoftplusMatchesExpected(
|
|
[[-9, 7, -5, 3, -1], [1, -3, 5, -7, 9]], dtype
|
|
)
|
|
if dtype == dtypes.bfloat16.as_numpy_dtype:
|
|
log_eps = np.log(np.finfo(np.float32).eps)
|
|
else:
|
|
log_eps = np.log(np.finfo(dtype).eps)
|
|
one = dtype(1)
|
|
ten = dtype(10)
|
|
self._assertSoftplusMatchesExpected(
|
|
[
|
|
log_eps,
|
|
log_eps - one,
|
|
log_eps + one,
|
|
log_eps - ten,
|
|
log_eps + ten,
|
|
-log_eps,
|
|
-log_eps - one,
|
|
-log_eps + one,
|
|
-log_eps - ten,
|
|
-log_eps + ten,
|
|
],
|
|
dtype,
|
|
)
|
|
|
|
self._assertSoftplusMatchesExpected(
|
|
[0.69302183, 0.69324386],
|
|
dtype,
|
|
equality_test=self.AssertCloseAndSorted,
|
|
rtol=9e-5,
|
|
atol=9e-5,
|
|
)
|
|
|
|
def testToBool(self):
|
|
for dtype in self.numeric_types - self.complex_types:
|
|
self._assertOpOutputMatchesExpected(
|
|
gen_functional_ops.to_bool,
|
|
np.array(5, dtype=dtype),
|
|
expected=np.array(True),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
gen_functional_ops.to_bool,
|
|
np.array(0, dtype=dtype),
|
|
expected=np.array(False),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
gen_functional_ops.to_bool,
|
|
np.array([], dtype=dtype),
|
|
expected=np.array(False),
|
|
)
|
|
|
|
self._assertOpOutputMatchesExpected(
|
|
gen_functional_ops.to_bool,
|
|
np.array([1, 2, 3], dtype=dtype),
|
|
expected=np.array(True),
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
googletest.main()
|