chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
@@ -0,0 +1,586 @@
# Tests of TensorFlow math kernels written using the Python API.
load("//tensorflow:tensorflow.default.bzl", "cuda_py_strict_test", "tf_py_strict_test")
load(
"//tensorflow/tools/test:performance.bzl",
"cuda_py_benchmark_test",
)
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:license"],
licenses = ["notice"],
)
cuda_py_strict_test(
name = "aggregate_ops_test",
size = "small",
srcs = ["aggregate_ops_test.py"],
xla_tags = [
"no_cuda_asan", # times out
],
deps = [
"//tensorflow/core:protos_all_py",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:string_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "approx_topk_test",
srcs = ["approx_topk_test.py"],
tags = ["no_oss"],
xla_enable_strict_auto_jit = True,
xla_enabled = True,
deps = [
"//tensorflow/python/eager:backprop",
"//tensorflow/python/eager:def_function",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:dtypes",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:nn_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
"@absl_py//absl/testing:parameterized",
],
)
cuda_py_strict_test(
name = "argmax_op_test",
size = "small",
srcs = ["argmax_op_test.py"],
tags = [
"no_cuda_asan", # times out
],
xla_tags = [
"no_cuda_asan", # times out
],
deps = [
"//tensorflow/python/framework:dtypes",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
"@absl_py//absl/testing:parameterized",
],
)
cuda_py_strict_test(
name = "banded_triangular_solve_op_test",
size = "small",
srcs = ["banded_triangular_solve_op_test.py"],
deps = [
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:linalg_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "basic_gpu_test",
size = "small",
srcs = ["basic_gpu_test.py"],
grpc_enabled = True,
deps = [
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:random_seed",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:array_ops_gen",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:random_ops",
"//tensorflow/python/ops:variables",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "batch_matmul_op_test",
size = "medium",
srcs = ["batch_matmul_op_test.py"],
shard_count = 20,
tags = ["no_mac_arm64"],
deps = [
"//tensorflow/python:tf2",
"//tensorflow/python/client:session",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:variables",
"//tensorflow/python/platform:benchmark",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "bincount_op_test",
size = "small",
srcs = ["bincount_op_test.py"],
tags = ["no_windows_gpu"],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:bincount_ops",
"//tensorflow/python/ops:math_ops_gen",
"//tensorflow/python/ops:random_ops",
"//tensorflow/python/ops:sparse_ops",
"//tensorflow/python/ops/ragged:ragged_factory_ops",
"//tensorflow/python/ops/ragged:ragged_tensor",
"//tensorflow/python/platform:test",
"@absl_py//absl/testing:parameterized",
],
)
cuda_py_strict_test(
name = "bucketize_op_test",
size = "medium",
srcs = ["bucketize_op_test.py"],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
tf_py_strict_test(
name = "clip_ops_test",
size = "small",
srcs = ["clip_ops_test.py"],
tags = [
"no_gpu", # b/127001953
"no_windows",
],
deps = [
"//tensorflow/python/eager:backprop",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:indexed_slices",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:clip_ops",
"//tensorflow/python/ops:gradients_impl",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:math_ops_gen",
"//tensorflow/python/platform:client_testlib",
],
)
tf_py_strict_test(
name = "confusion_matrix_test",
size = "small",
srcs = ["confusion_matrix_test.py"],
deps = [
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:confusion_matrix",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:random_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "cross_grad_test",
size = "small",
srcs = ["cross_grad_test.py"],
deps = [
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
],
)
cuda_py_strict_test(
name = "cumulative_logsumexp_test",
size = "medium",
srcs = ["cumulative_logsumexp_test.py"],
deps = [
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/ops:map_fn",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "cwise_ops_test",
size = "medium",
srcs = ["cwise_ops_test.py"],
shard_count = 50,
tags = [
"no_cuda_asan", # b/179032113
],
deps = [
"//tensorflow/python/eager:context",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:sparse_tensor",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker",
"//tensorflow/python/ops:gradients_impl",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:nn_grad",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "cwise_ops_binary_test",
size = "medium",
srcs = ["cwise_ops_binary_test.py"],
shard_count = 50,
# b/140155647: Error just outside of tolerance
xla_enable_strict_auto_jit = False,
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:sparse_tensor",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:gradient_checker",
"//tensorflow/python/ops:gradients_impl",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:nn_grad",
"//tensorflow/python/ops:variables",
"//tensorflow/python/platform:client_testlib",
"//tensorflow/python/platform:tf_logging",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "cwise_ops_unary_test",
size = "medium",
srcs = ["cwise_ops_unary_test.py"],
shard_count = 10,
tags = [
"no_windows", # TODO(b/207048097): re-enable
],
# b/140155706: nans in result
xla_enable_strict_auto_jit = False,
deps = [
"//tensorflow/python/eager:backprop",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:sparse_tensor",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:gradient_checker",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:math_ops_gen",
"//tensorflow/python/ops:nn_grad",
"//tensorflow/python/ops:special_math_ops",
"//tensorflow/python/platform:client_testlib",
"//tensorflow/python/platform:tf_logging",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "division_future_test",
size = "medium",
srcs = ["division_future_test.py"],
tags = ["manual"],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "division_past_test",
size = "medium",
srcs = ["division_past_test.py"],
tags = [
"manual",
"no_windows",
],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "in_topk_op_test",
size = "small",
srcs = ["in_topk_op_test.py"],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/ops:nn_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "matmul_op_test",
size = "medium",
srcs = ["matmul_op_test.py"],
shard_count = 20,
tags = [
"no_mac_arm64",
],
deps = [
"//tensorflow/python:tf2",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_benchmark_test(
name = "reduce_benchmark_test",
srcs = ["reduce_benchmark_test.py"],
deps = [
"//tensorflow/core:protos_all_py",
"//tensorflow/python/client:session",
"//tensorflow/python/eager:backprop",
"//tensorflow/python/eager:context",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:ops",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradients_impl",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
],
)
cuda_py_strict_test(
name = "reduction_ops_test_big",
size = "medium",
srcs = ["reduction_ops_test_big.py"],
shard_count = 3,
tags = [
"manual",
"no_gpu",
"noguitar",
],
deps = [
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "reduction_ops_test",
size = "medium",
srcs = ["reduction_ops_test.py"],
shard_count = 6,
tags = [
"no_cuda_asan", # times out
"no_windows_gpu",
],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:variables",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
"@absl_py//absl/testing:parameterized",
],
)
cuda_py_strict_test(
name = "segment_reduction_ops_d9m_test",
size = "small",
srcs = ["segment_reduction_ops_d9m_test.py"],
tags = ["no_cuda_asan"], # b/195247538
xla_enable_strict_auto_jit = False,
deps = [
"//tensorflow/python/eager:backprop",
"//tensorflow/python/framework:config",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:dtypes",
"//tensorflow/python/framework:indexed_slices",
"//tensorflow/python/framework:ops",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:variables",
"//tensorflow/python/platform:client_testlib",
],
)
cuda_py_strict_test(
name = "segment_reduction_ops_test",
size = "medium",
srcs = ["segment_reduction_ops_test.py"],
shard_count = 10,
# TODO (b/173835746): the test fails with XLA.
xla_enable_strict_auto_jit = False,
deps = [
"//tensorflow/python/client:session",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:indexed_slices",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:gradient_checker",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/ops:gradients",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:variables",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
"@absl_py//absl/testing:parameterized",
],
)
tf_py_strict_test(
name = "sets_test",
size = "medium",
srcs = ["sets_test.py"],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:sparse_tensor",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/ops:set_ops_gen",
"//tensorflow/python/ops:sets",
"//tensorflow/python/ops:sparse_ops",
"//tensorflow/python/platform:test",
"//third_party/py/numpy",
"@absl_py//absl/testing:parameterized",
],
)
cuda_py_strict_test(
name = "tensordot_op_test",
size = "medium",
srcs = ["tensordot_op_test.py"],
shard_count = 20,
tags = [
"no_mac_arm64",
"no_rocm",
],
xla_enable_strict_auto_jit = False, # b/161856380
deps = [
"//tensorflow/python/eager:context",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:math_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "topk_op_test",
size = "medium",
srcs = ["topk_op_test.py"],
xla_tags = [
"no_cuda_asan", # times out
],
deps = [
"//tensorflow/python/client:session",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradients_impl",
"//tensorflow/python/ops:nn_grad",
"//tensorflow/python/ops:nn_ops",
"//tensorflow/python/ops:random_ops",
"//tensorflow/python/ops:resource_variable_ops",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "transpose_op_test",
size = "medium",
srcs = ["transpose_op_test.py"],
shard_count = 10,
tags = [
"no_gpu",
"no_oss",
"notap", # flaky timeout/segfault, b/136498892
"optonly", # times out
],
deps = [
"//tensorflow/python/eager:def_function",
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:tensor_spec",
"//tensorflow/python/ops:array_ops",
"//tensorflow/python/ops:gradient_checker_v2",
"//tensorflow/python/platform:client_testlib",
"//third_party/py/numpy",
],
)
cuda_py_strict_test(
name = "zero_division_test",
size = "medium",
srcs = ["zero_division_test.py"],
deps = [
"//tensorflow/python/framework:constant_op",
"//tensorflow/python/framework:errors",
"//tensorflow/python/framework:for_generated_wrappers",
"//tensorflow/python/framework:test_lib",
"//tensorflow/python/platform:client_testlib",
],
)
@@ -0,0 +1,143 @@
# 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 aggregate_ops."""
import numpy as np
from tensorflow.core.framework import tensor_pb2
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import tensor_shape
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import string_ops
from tensorflow.python.platform import test
class AddNTest(test.TestCase):
# AddN special-cases adding the first M inputs to make (N - M) divisible by 8,
# after which it adds the remaining (N - M) tensors 8 at a time in a loop.
# Test N in [1, 10] so we check each special-case from 1 to 9 and one
# iteration of the loop.
_MAX_N = 10
def _supported_types(self):
if test.is_gpu_available():
return [
dtypes.float16, dtypes.bfloat16, dtypes.float32, dtypes.float64,
dtypes.complex64, dtypes.complex128, dtypes.int64
]
return [
dtypes.int8,
dtypes.int16,
dtypes.int32,
dtypes.int64,
dtypes.bfloat16,
dtypes.float16,
dtypes.float32,
dtypes.float64,
dtypes.complex64,
dtypes.complex128,
]
def _buildData(self, shape, dtype):
data = np.random.randn(*shape).astype(dtype.as_numpy_dtype)
# For complex types, add an index-dependent imaginary component so we can
# tell we got the right value.
if dtype.is_complex:
return data + 10j * data
return data
def testAddN(self):
np.random.seed(12345)
with self.session():
for dtype in self._supported_types():
for count in range(1, self._MAX_N + 1):
data = [self._buildData((2, 2), dtype) for _ in range(count)]
actual = self.evaluate(math_ops.add_n(data))
expected = np.sum(np.vstack(
[np.expand_dims(d, 0) for d in data]), axis=0)
self.assertAllCloseAccordingToType(
expected,
actual,
float_rtol=5e-6,
float_atol=5e-6,
half_rtol=5e-3,
half_atol=5e-3,
)
@test_util.run_deprecated_v1
def testUnknownShapes(self):
np.random.seed(12345)
with self.session() as sess:
for dtype in self._supported_types():
data = self._buildData((2, 2), dtype)
for count in range(1, self._MAX_N + 1):
data_ph = array_ops.placeholder(dtype=dtype)
actual = sess.run(math_ops.add_n([data_ph] * count), {data_ph: data})
expected = np.sum(np.vstack([np.expand_dims(data, 0)] * count),
axis=0)
self.assertAllCloseAccordingToType(
expected,
actual,
half_rtol=5e-3,
half_atol=5e-3,
)
@test_util.run_deprecated_v1
def testVariant(self):
def create_constant_variant(value):
return constant_op.constant(
tensor_pb2.TensorProto(
dtype=dtypes.variant.as_datatype_enum,
tensor_shape=tensor_shape.TensorShape([]).as_proto(),
variant_val=[
tensor_pb2.VariantTensorDataProto(
# Match registration in variant_op_registry.cc
type_name=b"int",
metadata=np.array(value, dtype=np.int32).tobytes())
]))
# TODO(ebrevdo): Re-enable use_gpu=True once non-DMA Variant
# copying between CPU and GPU is supported.
with self.session(use_gpu=False):
num_tests = 127
values = list(range(100))
variant_consts = [create_constant_variant(x) for x in values]
sum_count_indices = np.random.randint(1, 29, size=num_tests)
sum_indices = [
np.random.randint(100, size=count) for count in sum_count_indices]
expected_sums = [np.sum(x) for x in sum_indices]
variant_sums = [math_ops.add_n([variant_consts[i] for i in x])
for x in sum_indices]
# We use as_string() to get the Variant DebugString for the
# variant_sums; we know its value so we can check via string equality
# here.
#
# Right now, non-numpy-compatible objects cannot be returned from a
# session.run call; similarly, objects that can't be converted to
# native numpy types cannot be passed to ops.convert_to_tensor.
variant_sums_string = string_ops.as_string(variant_sums)
self.assertAllEqual(
variant_sums_string,
["Variant<type: int value: {}>".format(s).encode("utf-8")
for s in expected_sums])
if __name__ == "__main__":
test.main()
@@ -0,0 +1,273 @@
# Copyright 2022 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 tf.math.approx_max_k and tf.math.approx_min_k."""
import itertools
from absl.testing import parameterized
import numpy as np
from tensorflow.python.eager import backprop
from tensorflow.python.eager.def_function import function
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import nn_ops
from tensorflow.python.platform import test
@test_util.run_all_in_graph_and_eager_modes
class ApproxTopkTest(test_util.TensorFlowTestCase, parameterized.TestCase):
def setUp(self):
test_util.TensorFlowTestCase.setUp(self)
self._rng = np.random.default_rng(42)
def compute_recall(self, result_neighbors, ground_truth_neighbors):
"""Computes the recall of an approximate nearest neighbor search.
Args:
result_neighbors: int32 numpy array of the shape [num_queries,
neighbors_per_query] where the values are the indices of the dataset.
ground_truth_neighbors: int32 numpy array of with shape [num_queries,
ground_truth_neighbors_per_query] where the values are the indices of
the dataset.
Returns:
The recall.
"""
self.assertLen(result_neighbors.shape, 2)
self.assertLen(ground_truth_neighbors.shape, 2)
self.assertEqual(result_neighbors.shape[0], ground_truth_neighbors.shape[0])
gt_sets = [set(np.asarray(x)) for x in ground_truth_neighbors]
def hits_per_q(q, nn_per_q):
return len(list(x for x in nn_per_q if x.item() in gt_sets[q]))
hits = sum(
hits_per_q(q, nn_per_q) for q, nn_per_q in enumerate(result_neighbors))
return hits / ground_truth_neighbors.size
@parameterized.parameters(
itertools.product(
[dtypes.bfloat16, dtypes.float16, dtypes.float32],
[1, 10], # k
[100, 500], # row_size
[1, 10, 128], # num_rows
[True, False], # aggregate_to_topk
))
def test_non_fused_max_k(self, dtype, k, row_size, num_rows,
aggregate_to_topk):
row = np.arange(row_size, dtype=np.float32)
db = np.stack(list(self._rng.permutation(row) for _ in range(num_rows)))
db_op = constant_op.constant(db, dtype=dtype)
# Must jit-compile to access the xla kernel.
@function(jit_compile=True)
def ann(db, k):
return nn_ops.approx_max_k(db, k, aggregate_to_topk=aggregate_to_topk)
_, idx = self.evaluate(ann(db_op, k))
gt = np.argsort(-db)[:, :k]
ann_recall = self.compute_recall(idx, gt)
self.assertGreaterEqual(ann_recall, 0.95)
@parameterized.parameters(
itertools.product(
[dtypes.bfloat16, dtypes.float16, dtypes.float32],
[1, 10], # k
[100, 500], # row_size
[1, 10, 128], # num_rows
[True, False], # aggregate_to_topk
))
def test_non_fused_min_k(self, dtype, k, row_size, num_rows,
aggregate_to_topk):
# Use the new rng api
row = np.arange(row_size, dtype=np.float32)
db = np.stack(list(self._rng.permutation(row) for _ in range(num_rows)))
db_op = constant_op.constant(db, dtype=dtype)
# Must jit-compile to access the xla kernel.
@function(jit_compile=True)
def ann(db, k=10):
return nn_ops.approx_min_k(db, k, aggregate_to_topk=aggregate_to_topk)
_, idx = self.evaluate(ann(db_op, k))
gt = np.argsort(db)[:, :k]
ann_recall = self.compute_recall(idx, gt)
self.assertGreaterEqual(ann_recall, 0.95)
@parameterized.parameters(
itertools.product(
[dtypes.float32], # Use float32 for numerical stability.
[1, 10], # k
[100, 500], # db_size
[1, 10, 128], # qy_size
[2, 32], # feature dim
))
# MIPS = Maximal Inner Product Search
def test_mips(self, dtype, k, db_size, qy_size, feature_dim):
qy = self._rng.random([qy_size, feature_dim])
db = self._rng.random([db_size, feature_dim])
qy_op = constant_op.constant(qy, dtype=dtype)
db_op = constant_op.constant(db, dtype=dtype)
# Must jit-compile to access the xla kernel.
@function(jit_compile=True)
def ann(qy, db, k):
scores = math_ops.matmul(qy, db, transpose_b=True)
return nn_ops.approx_max_k(scores, k)
_, idx = self.evaluate(ann(qy_op, db_op, k))
scores = self.evaluate(-math_ops.matmul(qy_op, db_op, transpose_b=True))
gt = np.argsort(scores)[:, :k]
ann_recall = self.compute_recall(idx, gt)
self.assertGreaterEqual(ann_recall, 0.95)
@parameterized.parameters(
itertools.product(
[dtypes.float32], # Use float32 for numerical stability.
[1, 10], # k
[100, 500], # db_size
[1, 10, 128], # qy_size
[2, 32], # feature dim
))
# L2ANN = Approximate Nearest Neighbor search in the L2 metric space
def test_l2ann(self, dtype, k, db_size, qy_size, feature_dim):
qy = self._rng.random([qy_size, feature_dim])
db = self._rng.random([db_size, feature_dim])
db_half_norm_sq = np.linalg.norm(db, axis=1)**2 / 2
qy_op = constant_op.constant(qy, dtype=dtype)
db_op = constant_op.constant(db, dtype=dtype)
db_half_norm_sq_op = constant_op.constant(db_half_norm_sq, dtype=dtype)
# Must jit-compile to access the xla kernel.
@function(jit_compile=True)
def ann(qy, db, db_half_norm_sq, k):
scores = db_half_norm_sq - math_ops.matmul(qy, db, transpose_b=True)
return nn_ops.approx_min_k(scores, k)
_, idx = self.evaluate(ann(qy_op, db_op, db_half_norm_sq_op, k))
scores = self.evaluate(db_half_norm_sq_op -
math_ops.matmul(qy_op, db_op, transpose_b=True))
gt = np.argsort(scores)[:, :k]
ann_recall = self.compute_recall(idx, gt)
self.assertGreaterEqual(ann_recall, 0.95)
def test_highdim(self):
db = self._rng.random([2, 10, 200, 3], dtype=np.float32)
k = 5
@function(jit_compile=True)
def ann(db, k):
return nn_ops.approx_min_k(db, k=k, reduction_dimension=2)
_, idx = self.evaluate(ann(db, k))
gt = np.argsort(db, axis=2)[:, :, :k, :]
flat_idx = np.reshape(np.transpose(idx, [0, 1, 3, 2]), [2 * 10 * 3, k])
flat_gt = np.reshape(np.transpose(gt, [0, 1, 3, 2]), [2 * 10 * 3, k])
ann_recall = self.compute_recall(flat_idx, flat_gt)
self.assertGreaterEqual(ann_recall, 0.95)
@parameterized.parameters(
itertools.product(
[dtypes.bfloat16, dtypes.float16, dtypes.float32],
[1, 10], # k
[100, 500], # row_size
[1, 10, 128], # num_rows
))
def test_gradients(self, dtype, k, row_size, num_rows):
row = np.arange(row_size, dtype=np.float32)
db = np.stack(list(self._rng.permutation(row) for _ in range(num_rows)))
db_op = constant_op.constant(db, dtype=dtype)
out_grads = self._rng.random([num_rows, k])
out_grads_op = constant_op.constant(out_grads, dtype=dtype)
# Must jit-compile to access the xla kernel.
@function(jit_compile=True)
def ann_with_grads(db, out_grads):
with backprop.GradientTape() as tape:
tape.watch(db)
val, idx = nn_ops.approx_max_k(db, k)
result_in_grads = tape.gradient(val, db, out_grads)
lifted_k_idx = array_ops.reshape(idx, [num_rows, k, 1])
iota_idx = array_ops.broadcast_to(
array_ops.reshape(math_ops.range(num_rows), [num_rows, 1, 1]),
[num_rows, k, 1])
lifted_idx = array_ops.concat([iota_idx, lifted_k_idx], axis=2)
k_idx_s = array_ops.reshape(lifted_idx, [num_rows * k, 2])
k_gra_s = array_ops.reshape(out_grads, [num_rows * k])
expected_in_grads = array_ops.scatter_nd(k_idx_s, k_gra_s,
[num_rows, row_size])
return [expected_in_grads, result_in_grads]
expected_in_grads, result_in_grads = self.evaluate(
ann_with_grads(db_op, out_grads_op))
self.assertAllClose(expected_in_grads, result_in_grads)
def test_invalid_input(self):
@function(jit_compile=True)
def fuzz_jit():
return nn_ops.approx_max_k(
[
183.39395141601562,
62.6842041015625,
83.8385238647461,
204.36642456054688,
],
4774,
reduction_dimension=0x8282828,
recall_target=135.9822179933652,
reduction_input_size_override=6154,
aggregate_to_topk=True,
)
with self.assertRaises((errors.InvalidArgumentError, ValueError)):
fuzz_jit()
def test_b272094281(self):
@function(jit_compile=True)
def fuzz_jit():
return nn_ops.approx_max_k(
[],
9223372036854775807,
reduction_dimension=-4294967297 + 0x41,
reduction_input_size_override=-9223372036854775807,
aggregate_to_topk=False,
)
with self.assertRaises((errors.InvalidArgumentError, ValueError)):
fuzz_jit()
@parameterized.parameters(
itertools.product(
[dtypes.float16, dtypes.bfloat16, dtypes.float32],
[1, 10], # k
[100, 500], # row_size
[1, 10, 128], # num_rows
)
)
def test_nonjit(self, dtype, k, row_size, num_rows):
# Support regular topk semantics.
row = np.arange(row_size, dtype=np.float32)
db = np.stack(list(self._rng.permutation(row) for _ in range(num_rows)))
db_tensor = constant_op.constant(db, dtype=dtype)
_, idx = self.evaluate(nn_ops.approx_max_k(db_tensor, k))
sorted_idx = np.sort(idx)
expected = np.sort(np.argsort(-db)[:, :k])
self.assertAllEqual(sorted_idx, expected)
if __name__ == '__main__':
test.main()
@@ -0,0 +1,143 @@
# Copyright 2015 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 tensorflow.ops.argmax_op."""
import functools
from absl.testing import parameterized
import numpy as np
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class ArgMaxTest(test.TestCase, parameterized.TestCase):
def _testArg(self,
method,
x,
axis,
expected_values,
use_gpu=False,
expected_err_re=None):
with self.session(use_gpu=use_gpu):
ans = method(x, axis=axis)
if expected_err_re is None:
tf_ans = self.evaluate(ans)
# Defaults to int64 output.
self.assertEqual(np.int64, tf_ans.dtype)
self.assertAllEqual(tf_ans, expected_values)
self.assertShapeEqual(expected_values, ans)
else:
with self.assertRaisesOpError(expected_err_re):
self.evaluate(ans)
def _testBothArg(self,
method,
x,
axis,
expected_values,
expected_err_re=None):
self._testArg(method, x, axis, expected_values, True, expected_err_re)
# Compilation time is too large with XLA/CPU autojit.
if not test_util.is_xla_enabled():
self._testArg(method, x, axis, expected_values, False, expected_err_re)
def _testBasic(self, dtype):
x = np.arange(200, dtype=np.float32).astype(dtype)
np.random.shuffle(x)
# Check that argmin and argmax match numpy along the primary axis
self._testBothArg(math_ops.argmax, x, 0, x.argmax())
self._testBothArg(math_ops.argmin, x, 0, x.argmin())
def _testTieBreaking(self, dtype):
x = np.zeros(200, dtype=dtype)
# Check that argmin and argmax match numpy along the primary axis for
# breaking ties.
self._testBothArg(math_ops.argmax, x, 0, x.argmax())
self._testBothArg(math_ops.argmin, x, 0, x.argmin())
# Check that argmin and argmax match numpy along axis=1 for
# breaking ties.
x = np.array([[0, 0, 1, 1], [1, 1, 0, 0], [0, 1, 0, 1]], dtype=dtype)
self._testBothArg(math_ops.argmax, x, 1, x.argmax(axis=1))
self._testBothArg(math_ops.argmin, x, 1, x.argmin(axis=1))
def _testDim(self, dtype):
shape = (3, 2, 4, 5, 6, 3, 7)
x = np.arange(
functools.reduce(lambda x, y: x * y, shape),
dtype=np.float32).astype(dtype)
np.random.shuffle(x)
x = x.reshape(shape)
# Check that argmin and argmax match numpy along all axes
for axis in range(-7, 7):
self._testBothArg(math_ops.argmax, x, axis, x.argmax(axis))
self._testBothArg(math_ops.argmin, x, axis, x.argmin(axis))
@parameterized.parameters(np.float16, np.float32, np.float64, np.int16,
np.int32, np.int64, np.bool_,
dtypes.bfloat16.as_numpy_dtype)
def testTypes(self, dtype):
self._testBasic(dtype,)
self._testTieBreaking(dtype)
self._testDim(dtype)
def testFloatInt32Output(self):
x = np.asarray(100 * np.random.randn(200), dtype=np.float32)
expected_values = x.argmax()
with self.session():
ans = math_ops.argmax(x, axis=0, output_type=dtypes.int32)
tf_ans = self.evaluate(ans)
self.assertEqual(np.int32, tf_ans.dtype)
# The values are equal when comparing int32 to int64 because
# the values don't have a range that exceeds 32-bit integers.
self.assertAllEqual(tf_ans, expected_values)
expected_values = x.argmin()
with self.session():
ans = math_ops.argmin(x, axis=0, output_type=dtypes.int32)
tf_ans = self.evaluate(ans)
self.assertEqual(np.int32, tf_ans.dtype)
self.assertAllEqual(tf_ans, expected_values)
def testEmpty(self):
with self.cached_session():
for op in math_ops.argmin, math_ops.argmax:
with self.assertRaisesOpError(
r"Reduction axis 0 is empty in shape \[0\]"):
op([], 0).eval()
@test_util.run_deprecated_v1
def testDefaultAxis(self):
with self.cached_session():
for op in math_ops.argmin, math_ops.argmax:
ans = op([1]).eval()
self.assertAllEqual(ans, 0)
@test_util.run_deprecated_v1
def testOutputEmpty(self):
with self.cached_session():
for op in math_ops.argmin, math_ops.argmax:
ret = op(array_ops.zeros(shape=[1, 0, 2]), axis=-1).eval()
self.assertEqual(ret.shape, (1, 0))
if __name__ == "__main__":
test.main()
@@ -0,0 +1,230 @@
# Copyright 2015 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 tensorflow.ops.math_ops.banded_triangular_solve."""
import numpy as np
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import linalg_ops
from tensorflow.python.platform import test
class BandedTriangularSolveOpTest(test.TestCase):
def _verifySolveAllWays(self, x, y, dtypes, batch_dims=None):
for lower in (False,):
for adjoint in (False, True):
for use_placeholder in True, False:
self._verifySolve(
x,
y,
lower=lower,
adjoint=adjoint,
batch_dims=batch_dims,
use_placeholder=use_placeholder,
dtypes=dtypes)
def _verifySolveAllWaysReal(self, x, y, batch_dims=None):
self._verifySolveAllWays(x, y, (np.float32, np.float64), batch_dims)
def _verifySolveAllWaysComplex(self, x, y, batch_dims=None):
self._verifySolveAllWays(x, y, (np.complex64, np.complex128), batch_dims)
def _verifySolve(self,
x,
y,
lower=True,
adjoint=False,
batch_dims=None,
use_placeholder=False,
dtypes=(np.float32, np.float64)):
for np_type in dtypes:
a = x.astype(np_type)
b = y.astype(np_type)
# Now we need to convert a to a dense triangular matrix.
def make_diags(diags, lower=True):
n = len(diags[0])
a = np.zeros(n * n, dtype=diags.dtype)
if lower:
for i, diag in enumerate(diags):
a[n * i:n * n:n + 1] = diag[i:]
else:
diags_flip = np.flip(diags, 0)
for i, diag in enumerate(diags_flip):
a[i:(n - i) * n:n + 1] = diag[:(n - i)]
return a.reshape(n, n)
# For numpy.solve we have to explicitly zero out the strictly
# upper or lower triangle.
if a.size > 0:
a_np = make_diags(a, lower=lower)
else:
a_np = a
if adjoint:
a_np = np.conj(np.transpose(a_np))
if batch_dims is not None:
a = np.tile(a, batch_dims + [1, 1])
a_np = np.tile(a_np, batch_dims + [1, 1])
b = np.tile(b, batch_dims + [1, 1])
with self.cached_session():
a_tf = a
b_tf = b
if use_placeholder:
a_tf = array_ops.placeholder_with_default(a_tf, shape=None)
b_tf = array_ops.placeholder_with_default(b_tf, shape=None)
tf_ans = linalg_ops.banded_triangular_solve(
a_tf, b_tf, lower=lower, adjoint=adjoint)
tf_val = self.evaluate(tf_ans)
np_ans = np.linalg.solve(a_np, b)
self.assertEqual(np_ans.shape, tf_val.shape)
self.assertAllClose(np_ans, tf_val)
@test_util.run_deprecated_v1
def testSolve(self):
# 1x1 matrix, single rhs.
matrix = np.array([[0.1]])
rhs0 = np.array([[1.]])
self._verifySolveAllWaysReal(matrix, rhs0)
# 2x2 matrix with 2 bands, single right-hand side.
# Corresponds to the lower triangular
# [[1., 0.], [3., 4.]]
# and upper triangular
# [[2., 1.], [0., 3.]]
matrix = np.array([[1., 4.], [2., 3.]])
rhs0 = np.array([[1.], [1.]])
self._verifySolveAllWaysReal(matrix, rhs0)
# 2x2 matrix with 2 bands, 3 right-hand sides.
rhs1 = np.array([[1., 0., 1.], [0., 1., 1.]])
self._verifySolveAllWaysReal(matrix, rhs1)
# 4 x 4 matrix with 2 bands, 3 right hand sides.
# Corresponds to the lower triangular
# [[1., 0., 0., 0.],
# [-1., 2., 0., 0.],
# [0., -2., 3., 0.],
# [0., 0., -3., 4.]]
# and upper triangular
# [[1., 1., 0., 0.],
# [0., -1., 2., 0.],
# [0., 0., -2., 3.],
# [0., 0., 0., -3.]]
matrix = np.array([[1., 2., 3., 4.], [1., -1., -2., -3.]])
rhs0 = np.array([[1., 0., 1.], [0., 1., 1.], [-1., 2., 1.], [0., -1., -1.]])
self._verifySolveAllWaysReal(matrix, rhs0)
def testSolveBandSizeSmaller(self):
rhs0 = np.random.randn(6, 4)
# 6 x 6 matrix with 2 bands. Ensure all non-zero entries.
matrix = 2. * np.random.uniform(size=[3, 6]) + 1.
self._verifySolveAllWaysReal(matrix, rhs0)
# 6 x 6 matrix with 3 bands. Ensure all non-zero entries.
matrix = 2. * np.random.uniform(size=[3, 6]) + 1.
self._verifySolveAllWaysReal(matrix, rhs0)
@test.disable_with_predicate(
pred=test.is_built_with_rocm,
skip_message="ROCm does not support BLAS operations for complex types")
@test_util.run_deprecated_v1
def testSolveComplex(self):
# 1x1 matrix, single rhs.
matrix = np.array([[0.1 + 1j * 0.1]])
rhs0 = np.array([[1. + 1j]])
self._verifySolveAllWaysComplex(matrix, rhs0)
# 2x2 matrix with 2 bands, single right-hand side.
# Corresponds to
# [[1. + 1j, 0.], [4 + 1j, 2 + 1j]]
matrix = np.array([[1., 2.], [3., 4.]]).astype(np.complex64)
matrix += 1j * matrix
rhs0 = np.array([[1.], [1.]]).astype(np.complex64)
rhs0 += 1j * rhs0
self._verifySolveAllWaysComplex(matrix, rhs0)
# 2x2 matrix with 2 bands, 3 right-hand sides.
rhs1 = np.array([[1., 0., 1.], [0., 1., 1.]]).astype(np.complex64)
rhs1 += 1j * rhs1
self._verifySolveAllWaysComplex(matrix, rhs1)
@test_util.run_deprecated_v1
def testSolveBatch(self):
matrix = np.array([[1., 2.], [3., 4.]])
rhs = np.array([[1., 0., 1.], [0., 1., 1.]])
# Batch of 2x3x2x2 matrices, 2x3x2x3 right-hand sides.
self._verifySolveAllWaysReal(matrix, rhs, batch_dims=[2, 3])
# Batch of 3x2x2x2 matrices, 3x2x2x3 right-hand sides.
self._verifySolveAllWaysReal(matrix, rhs, batch_dims=[3, 2])
matrix = np.array([[1., 2., 3., 4.], [-1., -2., -3., -4.],
[-1., 1., 2., 3.]])
rhs = np.array([[-1., 2.], [1., 1.], [0., 1.], [2., 3.]])
# Batch of 2x3x4x4 matrices with 3 bands, 2x3x4x2 right-hand sides.
self._verifySolveAllWaysReal(matrix, rhs, batch_dims=[2, 3])
# Batch of 3x2x4x4 matrices with 3 bands, 3x2x4x2 right-hand sides.
self._verifySolveAllWaysReal(matrix, rhs, batch_dims=[3, 2])
@test.disable_with_predicate(
pred=test.is_built_with_rocm,
skip_message="ROCm does not support BLAS operations for complex types")
@test_util.run_deprecated_v1
def testSolveBatchComplex(self):
matrix = np.array([[1., 2.], [3., 4.]]).astype(np.complex64)
matrix += 1j * matrix
rhs = np.array([[1., 0., 1.], [0., 1., 1.]]).astype(np.complex64)
rhs += 1j * rhs
# Batch of 2x3x2x2 matrices, 2x3x2x3 right-hand sides.
self._verifySolveAllWaysComplex(matrix, rhs, batch_dims=[2, 3])
# Batch of 3x2x2x2 matrices, 3x2x2x3 right-hand sides.
self._verifySolveAllWaysComplex(matrix, rhs, batch_dims=[3, 2])
@test_util.run_deprecated_v1
def testWrongDimensions(self):
# The matrix should have the same number of rows as the
# right-hand sides.
matrix = np.array([[1., 1.], [1., 1.]])
rhs = np.array([[1., 0.]])
with self.cached_session():
with self.assertRaises(ValueError):
self._verifySolve(matrix, rhs)
with self.assertRaises(ValueError):
self._verifySolve(matrix, rhs, batch_dims=[2, 3])
# Number of bands exceeds the dimension of the matrix.
matrix = np.ones((6, 4))
rhs = np.ones((4, 2))
with self.cached_session():
with self.assertRaises(ValueError):
self._verifySolve(matrix, rhs)
with self.assertRaises(ValueError):
self._verifySolve(matrix, rhs, batch_dims=[2, 3])
@test_util.run_deprecated_v1
@test_util.disable_xla("XLA cannot throw assertion errors during a kernel.")
def testNotInvertible(self):
# The input should be invertible.
# The matrix is singular because it has a zero on the diagonal.
# FIXME(rmlarsen): The GPU kernel does not check for singularity.
singular_matrix = np.array([[1., 0., -1.], [-1., 0., 1.], [0., -1., 1.]])
with self.cached_session():
with self.assertRaisesOpError("Input matrix is not invertible."):
self._verifySolve(singular_matrix, singular_matrix)
with self.assertRaisesOpError("Input matrix is not invertible."):
self._verifySolve(singular_matrix, singular_matrix, batch_dims=[2, 3])
if __name__ == "__main__":
test.main()
@@ -0,0 +1,246 @@
# Copyright 2016 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.
# ==============================================================================
"""Functional tests for basic component wise operations using a GPU device."""
import itertools
import threading
import numpy as np
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.framework import random_seed
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import random_ops
from tensorflow.python.ops import variables
from tensorflow.python.ops.gen_array_ops import broadcast_gradient_args
from tensorflow.python.platform import test
class GPUBinaryOpsTest(test.TestCase):
def _compareGPU(self, x, y, np_func, tf_func):
with self.cached_session():
inx = ops.convert_to_tensor(x)
iny = ops.convert_to_tensor(y)
out = tf_func(inx, iny)
tf_gpu = self.evaluate(out)
with self.cached_session(use_gpu=False):
inx = ops.convert_to_tensor(x)
iny = ops.convert_to_tensor(y)
out = tf_func(inx, iny)
tf_cpu = self.evaluate(out)
self.assertAllClose(tf_cpu, tf_gpu)
def testFloatBasic(self):
x = np.linspace(-5, 20, 15).reshape(1, 3, 5).astype(np.float32) # pylint: disable=too-many-function-args
y = np.linspace(20, -5, 15).reshape(1, 3, 5).astype(np.float32) # pylint: disable=too-many-function-args
self._compareGPU(x, y, np.add, math_ops.add)
self._compareGPU(x, y, np.subtract, math_ops.subtract)
self._compareGPU(x, y, np.multiply, math_ops.multiply)
self._compareGPU(x, y + 0.1, np.true_divide, math_ops.truediv)
self._compareGPU(x, y + 0.1, np.floor_divide, math_ops.floordiv)
self._compareGPU(x, y, np.power, math_ops.pow)
def testFloatWithBCast(self):
x = np.linspace(-5, 20, 15).reshape(3, 5).astype(np.float32)
y = np.linspace(20, -5, 30).reshape(2, 3, 5).astype(np.float32) # pylint: disable=too-many-function-args
self._compareGPU(x, y, np.add, math_ops.add)
self._compareGPU(x, y, np.subtract, math_ops.subtract)
self._compareGPU(x, y, np.multiply, math_ops.multiply)
self._compareGPU(x, y + 0.1, np.true_divide, math_ops.truediv)
def testDoubleBasic(self):
x = np.linspace(-5, 20, 15).reshape(1, 3, 5).astype(np.float64) # pylint: disable=too-many-function-args
y = np.linspace(20, -5, 15).reshape(1, 3, 5).astype(np.float64) # pylint: disable=too-many-function-args
self._compareGPU(x, y, np.add, math_ops.add)
self._compareGPU(x, y, np.subtract, math_ops.subtract)
self._compareGPU(x, y, np.multiply, math_ops.multiply)
self._compareGPU(x, y + 0.1, np.true_divide, math_ops.truediv)
def testDoubleWithBCast(self):
x = np.linspace(-5, 20, 15).reshape(3, 5).astype(np.float64)
y = np.linspace(20, -5, 30).reshape(2, 3, 5).astype(np.float64) # pylint: disable=too-many-function-args
self._compareGPU(x, y, np.add, math_ops.add)
self._compareGPU(x, y, np.subtract, math_ops.subtract)
self._compareGPU(x, y, np.multiply, math_ops.multiply)
self._compareGPU(x, y + 0.1, np.true_divide, math_ops.truediv)
class MathBuiltinUnaryTest(test.TestCase):
def _compare(self, x, np_func, tf_func, use_gpu):
np_out = np_func(x)
with self.cached_session(use_gpu=use_gpu) as sess:
inx = ops.convert_to_tensor(x)
ofunc = tf_func(inx)
tf_out = self.evaluate(ofunc)
self.assertAllClose(np_out, tf_out)
def _inv(self, x):
return 1.0 / x
def _rsqrt(self, x):
return self._inv(np.sqrt(x))
def _testDtype(self, dtype, use_gpu):
data = (np.arange(-3, 3) / 4.).reshape([1, 3, 2]).astype(dtype)
data_gt_1 = data + 2 # for x > 1
self._compare(data, np.abs, math_ops.abs, use_gpu)
self._compare(data, np.arccos, math_ops.acos, use_gpu)
self._compare(data, np.arcsin, math_ops.asin, use_gpu)
self._compare(data, np.arcsinh, math_ops.asinh, use_gpu)
self._compare(data_gt_1, np.arccosh, math_ops.acosh, use_gpu)
self._compare(data, np.arctan, math_ops.atan, use_gpu)
self._compare(data, np.ceil, math_ops.ceil, use_gpu)
self._compare(data, np.cos, math_ops.cos, use_gpu)
self._compare(data, np.cosh, math_ops.cosh, use_gpu)
self._compare(data, np.exp, math_ops.exp, use_gpu)
self._compare(data, np.floor, math_ops.floor, use_gpu)
self._compare(data, np.log, math_ops.log, use_gpu)
self._compare(data, np.log1p, math_ops.log1p, use_gpu)
self._compare(data, np.negative, math_ops.negative, use_gpu)
self._compare(data, self._rsqrt, math_ops.rsqrt, use_gpu)
self._compare(data, np.sin, math_ops.sin, use_gpu)
self._compare(data, np.sinh, math_ops.sinh, use_gpu)
self._compare(data, np.sqrt, math_ops.sqrt, use_gpu)
self._compare(data, np.square, math_ops.square, use_gpu)
self._compare(data, np.tan, math_ops.tan, use_gpu)
self._compare(data, np.tanh, math_ops.tanh, use_gpu)
self._compare(data, np.arctanh, math_ops.atanh, use_gpu)
def testTypes(self):
for dtype in [np.float32]:
self._testDtype(dtype, use_gpu=True)
def testFloorDivide(self):
x = (1 + np.linspace(0, 5, np.prod([1, 3, 2]))).astype(np.float32).reshape(
[1, 3, 2])
y = (1 + np.linspace(0, 5, np.prod([1, 3, 2]))).astype(np.float32).reshape(
[1, 3, 2])
np_out = np.floor_divide(x, y + 0.1)
with self.session():
inx = ops.convert_to_tensor(x)
iny = ops.convert_to_tensor(y + 0.1)
ofunc = inx / iny
out_func2 = math_ops.floor(ofunc)
tf_out = self.evaluate(out_func2)
self.assertAllClose(np_out, tf_out)
class BroadcastSimpleTest(test.TestCase):
def _GetGradientArgs(self, xs, ys):
return self.evaluate(broadcast_gradient_args(xs, ys))
def testBroadcast(self):
r0, r1 = self._GetGradientArgs([2, 3, 5], [1])
self.assertAllEqual(r0, [])
self.assertAllEqual(r1, [0, 1, 2])
_GRAD_TOL = {dtypes.float32: 1e-3}
def _compareGpu(self, x, y, np_func, tf_func):
np_ans = np_func(x, y)
with self.cached_session():
inx = ops.convert_to_tensor(x)
iny = ops.convert_to_tensor(y)
out = tf_func(inx, iny)
tf_gpu = self.evaluate(out)
self.assertAllClose(np_ans, tf_gpu)
self.assertShapeEqual(np_ans, out)
# TODO(zhifengc/ke): make gradient checker work on GPU.
def testGradient(self):
x1 = (1 + np.linspace(0, 5, np.prod([1, 3, 2]))).astype(np.float32).reshape(
[1, 3, 2])
x2 = (1 + np.linspace(0, 5, np.prod([1, 3, 2]))).astype(np.float32).reshape(
[1, 3, 2])
def div_x1(x1):
return math_ops.truediv(x1, x2) * math_ops.cast(1.1, dtype=x1.dtype)
def div_x2(x2):
return math_ops.truediv(x1, x2) * math_ops.cast(1.1, dtype=x2.dtype)
with self.cached_session():
err = gradient_checker_v2.max_error(*gradient_checker_v2.compute_gradient(
div_x1, [x1]))
self.assertLess(err, self._GRAD_TOL[dtypes.as_dtype(x1.dtype)])
err = gradient_checker_v2.max_error(*gradient_checker_v2.compute_gradient(
div_x2, [x2]))
self.assertLess(err, self._GRAD_TOL[dtypes.as_dtype(x2.dtype)])
self._compareGpu(x1, x2, np.true_divide, math_ops.truediv)
self._compareGpu(x1, x2 + 0.1, np.floor_divide, math_ops.floordiv)
class GpuMultiSessionMemoryTest(test_util.TensorFlowTestCase):
"""Tests concurrent sessions executing on the same GPU."""
def _run_session(self, session, results):
n_iterations = 500
with session as s:
data = variables.Variable(1.0)
with ops.device('/device:GPU:0'):
random_seed.set_random_seed(1)
matrix1 = variables.Variable(
random_ops.truncated_normal([1024, 1]), name='matrix1')
matrix2 = variables.Variable(
random_ops.truncated_normal([1, 1024]), name='matrix2')
x1 = math_ops.multiply(data, matrix1, name='x1')
x3 = math_ops.matmul(x1, math_ops.matmul(matrix2, matrix1))
x4 = math_ops.matmul(array_ops.transpose(x3), x3, name='x4')
s.run(variables.global_variables_initializer())
for _ in range(n_iterations):
value = s.run(x4)
results.add(value.flat[0])
if len(results) != 1:
break
@test_util.run_v1_only('b/126596827 needs graph mode in multiple threads')
def testConcurrentSessions(self):
n_threads = 4
threads = []
results = []
for _ in range(n_threads):
session = self.session(graph=ops.Graph(), use_gpu=True)
results.append(set())
args = (session, results[-1])
threads.append(threading.Thread(target=self._run_session, args=args))
for thread in threads:
thread.start()
for thread in threads:
thread.join()
flat_results = set(itertools.chain(*results))
self.assertEqual(1,
len(flat_results),
'Expected single value, got %r' % flat_results)
if __name__ == '__main__':
test.main()
@@ -0,0 +1,319 @@
# Copyright 2015 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 tensorflow.ops.tf.BatchMatMul."""
import numpy as np
from tensorflow.python import tf2
from tensorflow.python.client import session
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import variables
from tensorflow.python.platform import benchmark
from tensorflow.python.platform import test
def GetRandomNormalInput(shape, dtype):
# float16 has limited range so we reduce the variance of the scalars.
scale = 10.0 if dtype != np.float16 else 0.1
loc = -10.0 if dtype != np.float16 else 0.1
vals = np.array(np.random.normal(loc, scale, np.prod(shape)), dtype=dtype)
if dtype in (np.complex64, np.complex128):
imag = np.array(np.random.normal(loc, scale, np.prod(shape)), dtype=dtype)
vals += 1j * imag
return vals.reshape(shape)
class BatchMatmulOpTest(test.TestCase):
# Uses numpy to compute batch_matmul(x, y, adjoint_a, adjoint_b).
def _npBatchMatmul(self, x, y, adjoint_a, adjoint_b):
# output's shape depends on adj[0] and adj[1]
if adjoint_a:
x = np.conjugate(np.swapaxes(x, -1, -2))
if adjoint_b:
y = np.conjugate(np.swapaxes(y, -1, -2))
return np.matmul(x, y)
# Compares TensorFlow BatchMatmul with NumPy's matmul.
def _compare(self, x_in, y_in, adjoint_a, adjoint_b, static_shape):
x_t_shape = x_in.shape[:-2] + (x_in.shape[-1], x_in.shape[-2])
y_t_shape = y_in.shape[:-2] + (y_in.shape[-1], y_in.shape[-2])
x = x_in if not adjoint_a else x_in.reshape(x_t_shape)
y = y_in if not adjoint_b else y_in.reshape(y_t_shape)
is_floating = x.dtype != np.int32
# np.finfo doesn't support bfloat16. So, we manually compute the eps which
# defines the difference between 1.0 and the next smallest representable
# float larger than 1.0. For bfloat16, the difference is 1/128.
if x.dtype == dtypes.bfloat16.as_numpy_dtype:
epsilon = 0.0078125
elif is_floating:
epsilon = np.finfo(x.dtype).eps
tol = 100 * epsilon if is_floating else 0
with self.cached_session(use_gpu=is_floating) as sess:
if static_shape:
z0 = math_ops.matmul(x, y, adjoint_a=adjoint_a, adjoint_b=adjoint_b)
z0_val = self.evaluate(z0)
else:
x_ph = array_ops.placeholder(x.dtype)
y_ph = array_ops.placeholder(y.dtype)
z0 = math_ops.matmul(
x_ph, y_ph, adjoint_a=adjoint_a, adjoint_b=adjoint_b)
z0_val = sess.run(z0, feed_dict={x_ph: x, y_ph: y})
z1 = self._npBatchMatmul(x, y, adjoint_a, adjoint_b)
self.assertAllClose(z0_val, z1, rtol=tol, atol=tol)
def _testNonEmpty(self, dtype, adjoint_a, adjoint_b, use_static_shape):
def CompareNonEmpty(self, a_shape, b_shape):
self._compare(
GetRandomNormalInput(a_shape, dtype),
GetRandomNormalInput(b_shape, dtype),
adjoint_a,
adjoint_b,
static_shape=use_static_shape)
CompareNonEmpty(self, [1, 2, 3], [1, 3, 5])
CompareNonEmpty(self, [1, 2, 3], [1, 3, 1])
CompareNonEmpty(self, [1, 1, 3], [1, 3, 5])
CompareNonEmpty(self, [1, 2, 3], [1, 3, 5])
CompareNonEmpty(self, [7, 1, 3], [7, 3, 5])
CompareNonEmpty(self, [7, 2, 3], [7, 3, 1])
CompareNonEmpty(self, [7, 2, 3], [7, 3, 5])
CompareNonEmpty(self, [10, 64, 75], [10, 75, 30])
CompareNonEmpty(self, [5, 7, 2, 3], [5, 7, 3, 5])
def _testBroadcasting(self, dtype, adjoint_a, adjoint_b, use_static_shape):
def CompareNonEmpty(self, a_shape, b_shape):
self._compare(
GetRandomNormalInput(a_shape, dtype),
GetRandomNormalInput(b_shape, dtype),
adjoint_a,
adjoint_b,
static_shape=use_static_shape)
CompareNonEmpty(self, [2, 3], [1, 3, 5])
CompareNonEmpty(self, [1, 2, 3], [3, 5])
CompareNonEmpty(self, [5, 1, 2, 3], [1, 7, 3, 5])
CompareNonEmpty(self, [5, 2, 2, 3], [3, 5])
CompareNonEmpty(self, [2, 3], [5, 2, 3, 5])
CompareNonEmpty(self, [4, 5, 1, 2, 3], [1, 1, 3, 5])
CompareNonEmpty(self, [1, 2, 1, 4, 2, 1, 3, 4], [3, 2, 1, 1, 1, 2, 4, 2])
def _testEmpty(self, dtype, adjoint_a, adjoint_b, use_static_shape):
def CompareEmpty(self, a_shape, b_shape):
self._compare(
np.zeros(a_shape).astype(dtype),
np.zeros(b_shape).astype(dtype),
adjoint_a,
adjoint_b,
static_shape=use_static_shape)
CompareEmpty(self, [0, 3, 2], [0, 2, 4])
CompareEmpty(self, [3, 0, 2], [3, 2, 5])
CompareEmpty(self, [3, 3, 2], [3, 2, 0])
def _GetBatchMatmulOpTest(dtype, adjoint_a, adjoint_b, use_static_shape):
@test_util.run_without_tensor_float_32("Tests batch matmul")
def Test(self):
np.random.seed(42)
self._testNonEmpty(dtype, adjoint_a, adjoint_b, use_static_shape)
self._testEmpty(dtype, adjoint_a, adjoint_b, use_static_shape)
return Test
def _GetBatchMatmulOpBroadcastingTest(dtype, adjoint_a, adjoint_b,
use_static_shape):
@test_util.run_without_tensor_float_32("Tests batch matmul")
def Test(self):
np.random.seed(42)
self._testBroadcasting(dtype, adjoint_a, adjoint_b, use_static_shape)
return Test
class BatchMatmulGradientTest(test.TestCase):
# loss = sum(batch_matmul(x, y)). Verify dl/dx and dl/dy via the
# gradient checker.
def _checkGrad(self, x_in, y_in, adjoint_a, adjoint_b):
x_t_shape = x_in.shape[:-2] + (x_in.shape[-1], x_in.shape[-2])
y_t_shape = y_in.shape[:-2] + (y_in.shape[-1], y_in.shape[-2])
x = x_in if not adjoint_a else x_in.reshape(x_t_shape)
y = y_in if not adjoint_b else y_in.reshape(y_t_shape)
# np.finfo doesn't support bfloat16. So, we manually compute the eps which
# defines the difference between 1.0 and the next smallest representable
# float larger than 1.0. For bfloat16, the difference is 1/128.
if x.dtype == dtypes.bfloat16.as_numpy_dtype:
epsilon = 0.0078125
else:
epsilon = np.finfo(x.dtype).eps
# Since our gradient is linear, a larger delta decreases the error.
delta = 10 * epsilon**(1.0 / 3.0)
def Loss(x, y):
z = math_ops.matmul(x, y, adjoint_a, adjoint_b)
# To avoid the high error when reduce_sum over the bfloat16 values, we
# cast the results to float32.
if z.dtype == dtypes.bfloat16:
z = math_ops.cast(z, dtype=dtypes.float32)
return math_ops.reduce_sum(z)
with self.cached_session():
((x_jacob_t, y_jacob_t),
(x_jacob_n, y_jacob_n)) = gradient_checker_v2.compute_gradient(
Loss, [x, y], delta=delta)
tol = 10 * delta
self.assertAllClose(x_jacob_t, x_jacob_n, rtol=tol, atol=tol)
self.assertAllClose(y_jacob_t, y_jacob_n, rtol=tol, atol=tol)
# Tests gradients of a batched matmul of x, and y
def _compare(self, a_shape, b_shape, dtype, adjoint_a, adjoint_b):
np.random.seed(42)
x = GetRandomNormalInput(a_shape, dtype)
y = GetRandomNormalInput(b_shape, dtype)
self._checkGrad(x, y, adjoint_a, adjoint_b)
def _GetBatchMatmulGradientTest(dtype, adjoint_a, adjoint_b):
def Test(self):
def CheckGradients(self, a_shape, b_shape):
self._compare(a_shape, b_shape, dtype, adjoint_a, adjoint_b)
CheckGradients(self, [1, 2, 3], [1, 3, 5])
CheckGradients(self, [3, 4, 7], [3, 7, 10])
return Test
def _GetBatchMatmulGradientWithBroadcastingTest(dtype, adjoint_a, adjoint_b):
def Test(self):
def CheckGradients(self, a_shape, b_shape):
self._compare(a_shape, b_shape, dtype, adjoint_a, adjoint_b)
CheckGradients(self, [1, 5, 2, 3], [7, 1, 3, 2])
CheckGradients(self, [2, 3], [1, 3, 5])
CheckGradients(self, [2, 3], [5, 3, 5])
CheckGradients(self, [5, 2, 5], [5, 3])
CheckGradients(self, [5, 2, 2, 3], [3, 5])
CheckGradients(self, [4, 5, 1, 2, 3], [1, 1, 3, 5])
CheckGradients(self, [1, 2, 1, 4, 2, 1, 3, 4], [3, 2, 1, 1, 1, 2, 4, 2])
return Test
class BatchMatMulBenchmark(test.Benchmark):
# Batch sizes are 512.
shape_pairs = [
# Typical fully connected layer.
((4, 8, 4, 2, 1, 1024), (1024, 1024)),
((4, 1, 4, 1, 1, 1024), (1, 8, 1, 2, 1024, 1024)),
# Square matmul.
((4, 8, 4, 2, 512, 512), (512, 512)),
((4, 1, 4, 1, 512, 512), (1, 8, 1, 2, 512, 512)),
# Matrix-vector multiplies.
((4, 8, 4, 2, 10000, 200), (200, 1)),
((4, 1, 4, 1, 10000, 200), (1, 8, 1, 2, 200, 1)),
# Vector-matrix multiplies.
((4, 8, 4, 2, 1, 200), (200, 10000)),
((4, 1, 4, 1, 1, 200), (1, 8, 1, 2, 200, 10000)),
]
def benchmarkBatchMatMulBroadcast(self):
for (a_shape, b_shape) in self.shape_pairs:
with ops.Graph().as_default(), \
session.Session(config=benchmark.benchmark_config()) as sess, \
ops.device("/cpu:0"):
matrix_a = variables.Variable(
GetRandomNormalInput(a_shape, np.float32))
matrix_b = variables.Variable(
GetRandomNormalInput(b_shape, np.float32))
self.evaluate(variables.global_variables_initializer())
# Use batch matmul op's internal broadcasting.
self.run_op_benchmark(
sess,
math_ops.matmul(matrix_a, matrix_b),
min_iters=50,
name="batch_matmul_cpu_{}_{}".format(a_shape, b_shape))
# Manually broadcast the input matrices using the broadcast_to op.
broadcasted_batch_shape = array_ops.broadcast_static_shape(
matrix_a.shape[:-2], matrix_b.shape[:-2])
broadcasted_a_shape = broadcasted_batch_shape.concatenate(
matrix_a.shape[-2:])
broadcasted_b_shape = broadcasted_batch_shape.concatenate(
matrix_b.shape[-2:])
self.run_op_benchmark(
sess,
math_ops.matmul(
array_ops.broadcast_to(matrix_a, broadcasted_a_shape),
array_ops.broadcast_to(matrix_b, broadcasted_b_shape)),
min_iters=50,
name="batch_matmul_manual_broadcast_cpu_{}_{}".format(
a_shape, b_shape))
if __name__ == "__main__":
dtypes_to_test = [
np.float16, np.float32, np.float64, np.int32, np.complex64, np.complex128,
dtypes.bfloat16.as_numpy_dtype
]
for dtype_ in dtypes_to_test:
for adjoint_a_ in False, True:
for adjoint_b_ in False, True:
name = "%s_%s_%s" % (dtype_.__name__, adjoint_a_, adjoint_b_)
# TF2 does not support placeholders under eager so we skip it.
for use_static_shape_ in set([True, tf2.enabled()]):
setattr(
BatchMatmulOpTest,
"testBatchMatmulOp_" + name + "_{}".format(use_static_shape_),
test_util.xla_allow_fallback(
"TODO(b/134526360): XLA:CPU hasn't implemented int32 dot.")(
_GetBatchMatmulOpTest(dtype_, adjoint_a_, adjoint_b_,
use_static_shape_)))
# Broadcasting is supported only in v2.
setattr(
BatchMatmulOpTest, "testBatchMatmulBroadcasting_" + name +
("_%s" % use_static_shape_),
test_util.xla_allow_fallback(
"TODO(b/134526360): XLA:CPU hasn't implemented int32 dot.")(
_GetBatchMatmulOpBroadcastingTest(dtype_, adjoint_a_,
adjoint_b_,
use_static_shape_)))
if dtype_ == np.int32:
continue
setattr(BatchMatmulGradientTest, "testBatchMatmulGradient_" + name,
_GetBatchMatmulGradientTest(dtype_, adjoint_a_, adjoint_b_))
# Broadcasting is supported only in v2.
setattr(
BatchMatmulGradientTest,
"testBatchMatmulGradientWithBroadcasting_" + name,
_GetBatchMatmulGradientWithBroadcastingTest(dtype_, adjoint_a_,
adjoint_b_))
test.main()
@@ -0,0 +1,851 @@
# Copyright 2016 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 bincount_ops.bincount."""
from absl.testing import parameterized
import numpy as np
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors
from tensorflow.python.framework import errors_impl
from tensorflow.python.framework import ops
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import bincount_ops
from tensorflow.python.ops import gen_math_ops
from tensorflow.python.ops import random_ops
from tensorflow.python.ops import sparse_ops
from tensorflow.python.ops.ragged import ragged_factory_ops
from tensorflow.python.ops.ragged import ragged_tensor
from tensorflow.python.platform import googletest
class BincountTest(test_util.TensorFlowTestCase):
def test_empty(self):
with self.session():
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([], minlength=5)),
[0, 0, 0, 0, 0])
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([], minlength=1)), [0])
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([], minlength=0)), [])
self.assertEqual(
self.evaluate(
bincount_ops.bincount([], minlength=0, dtype=np.float32)).dtype,
np.float32)
self.assertEqual(
self.evaluate(
bincount_ops.bincount([], minlength=3, dtype=np.float64)).dtype,
np.float64)
self.assertAllEqual(
self.evaluate(
bincount_ops.bincount(
constant_op.constant([], shape=[0], dtype=np.int32),
minlength=5,
binary_output=True,
)
),
[0, 0, 0, 0, 0],
)
def test_values(self):
with self.session():
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([1, 1, 1, 2, 2, 3])),
[0, 3, 2, 1])
arr = [1, 1, 2, 1, 2, 3, 1, 2, 3, 4, 1, 2, 3, 4, 5]
self.assertAllEqual(
self.evaluate(bincount_ops.bincount(arr)), [0, 5, 4, 3, 2, 1])
arr += [0, 0, 0, 0, 0, 0]
self.assertAllEqual(
self.evaluate(bincount_ops.bincount(arr)), [6, 5, 4, 3, 2, 1])
self.assertAllEqual(self.evaluate(bincount_ops.bincount([])), [])
self.assertAllEqual(self.evaluate(bincount_ops.bincount([0, 0, 0])), [3])
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([5])), [0, 0, 0, 0, 0, 1])
self.assertAllEqual(
self.evaluate(bincount_ops.bincount(np.arange(10000))),
np.ones(10000))
def test_maxlength(self):
with self.session():
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([5], maxlength=3)), [0, 0, 0])
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([1], maxlength=3)), [0, 1])
self.assertAllEqual(
self.evaluate(bincount_ops.bincount([], maxlength=3)), [])
def test_random_with_weights(self):
num_samples = 10000
with self.session():
np.random.seed(42)
for dtype in [dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64]:
arr = np.random.randint(0, 1000, num_samples)
if dtype == dtypes.int32 or dtype == dtypes.int64:
weights = np.random.randint(-100, 100, num_samples)
else:
weights = np.random.random(num_samples)
self.assertAllClose(
self.evaluate(bincount_ops.bincount(arr, weights)),
np.bincount(arr, weights))
def test_random_without_weights(self):
num_samples = 10000
with self.session():
np.random.seed(42)
for dtype in [np.int32, np.float32]:
arr = np.random.randint(0, 1000, num_samples)
weights = np.ones(num_samples).astype(dtype)
self.assertAllClose(
self.evaluate(bincount_ops.bincount(arr, None)),
np.bincount(arr, weights))
@test_util.run_gpu_only
@test_util.disable_xla("Bincount is deterministic with XLA")
def test_bincount_determinism_error(self):
arr = np.random.randint(0, 1000, size=1000)
with test_util.deterministic_ops(), self.assertRaisesRegex(
errors_impl.UnimplementedError,
"Determinism is not yet supported in GPU implementation of "
"(Dense)?Bincount.",
):
self.evaluate(bincount_ops.bincount(arr, None, axis=None))
arr = np.random.randint(0, 1000, size=(100, 100))
with test_util.deterministic_ops(), self.assertRaisesRegex(
errors_impl.UnimplementedError,
"Determinism is not yet supported in GPU implementation of "
"(Dense)?Bincount."):
self.evaluate(bincount_ops.bincount(arr, None, axis=-1))
def test_zero_weights(self):
with self.session():
self.assertAllEqual(
self.evaluate(bincount_ops.bincount(np.arange(1000), np.zeros(1000))),
np.zeros(1000))
@test_util.disable_xla("This is not raised on XLA CPU")
def test_negative(self):
# unsorted_segment_sum will only report InvalidArgumentError on CPU
with self.cached_session(), ops.device("/CPU:0"):
with self.assertRaisesRegex(
(ValueError, errors.InvalidArgumentError), "must be non-negative"
):
self.evaluate(bincount_ops.bincount([1, 2, 3, -1, 6, 8]))
with self.assertRaisesRegex(
(ValueError, errors.InvalidArgumentError), "must be non-negative"
):
self.evaluate(
gen_math_ops.dense_bincount(
input=[[1, 1, 3], [0, -1, 2]], weights=[], size=4
)
)
@test_util.run_in_graph_and_eager_modes
def test_shape_function(self):
# size must be scalar.
with self.assertRaisesRegex(
(ValueError, errors.InvalidArgumentError),
"(?s)Shape must be rank 0 but is rank 1.*Bincount"):
gen_math_ops.bincount([1, 2, 3, 1, 6, 8], [1], [])
# size must be positive.
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"must be non-negative"):
gen_math_ops.bincount([1, 2, 3, 1, 6, 8], -5, [])
# if size is a constant then the shape is known.
v1 = gen_math_ops.bincount([1, 2, 3, 1, 6, 8], 5, [])
self.assertAllEqual(v1.get_shape().as_list(), [5])
# if size is a placeholder then the shape is unknown.
with ops.Graph().as_default():
s = array_ops.placeholder(dtype=dtypes.int32)
v2 = gen_math_ops.bincount([1, 2, 3, 1, 6, 8], s, [])
self.assertAllEqual(v2.get_shape().as_list(), [None])
@test_util.run_in_graph_and_eager_modes
def test_invalid_inputs(self):
binary_output = True
inp = random_ops.random_uniform(
shape=[10, 10],
minval=-10000,
maxval=10000,
dtype=dtypes.int32,
seed=-2460)
size = random_ops.random_uniform(
shape=[], minval=-10000, maxval=10000, dtype=dtypes.int32, seed=-10000)
weights = random_ops.random_uniform(
shape=[],
minval=-10000,
maxval=10000,
dtype=dtypes.float32,
seed=-10000)
with self.assertRaises(errors.InvalidArgumentError):
self.evaluate(
gen_math_ops.dense_bincount(
input=inp,
size=size,
weights=weights,
binary_output=binary_output))
class BincountOpTest(test_util.TensorFlowTestCase, parameterized.TestCase):
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_bincount_all_count(self, dtype):
np.random.seed(42)
size = 1000
inp = np.random.randint(0, size, (4096), dtype=dtype)
np_out = np.bincount(inp, minlength=size)
with test_util.use_gpu():
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.dense_bincount(input=inp, weights=[], size=size)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_bincount_all_count_with_weights(self, dtype):
np.random.seed(42)
size = 1000
inp = np.random.randint(0, size, (4096,), dtype=dtype)
np_weight = np.random.random((4096,))
np_out = np.bincount(inp, minlength=size, weights=np_weight)
with test_util.use_gpu():
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.dense_bincount(
input=inp, weights=np_weight, size=size)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_bincount_all_binary(self, dtype):
np.random.seed(42)
size = 10
inp = np.random.randint(0, size, (4096), dtype=dtype)
np_out = np.ones((size,))
with test_util.use_gpu():
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.dense_bincount(
input=inp, weights=[], size=size, binary_output=True)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_bincount_all_binary_with_weights(self, dtype):
np.random.seed(42)
size = 10
inp = np.random.randint(0, size, (4096,), dtype=dtype)
np_weight = np.random.random((4096,))
np_out = np.ones((size,))
with test_util.use_gpu():
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.dense_bincount(
input=inp, weights=np_weight, size=size, binary_output=True)))
def _test_bincount_col_count(self, num_rows, num_cols, size, dtype):
np.random.seed(42)
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_out = np.reshape(
np.concatenate(
[np.bincount(inp[j, :], minlength=size) for j in range(num_rows)],
axis=0), (num_rows, size))
with test_util.use_gpu():
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.dense_bincount(input=inp, weights=[], size=size)))
def _test_bincount_col_binary(self, num_rows, num_cols, size, dtype):
np.random.seed(42)
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_out = np.reshape(
np.concatenate([
np.where(np.bincount(inp[j, :], minlength=size) > 0, 1, 0)
for j in range(num_rows)
],
axis=0), (num_rows, size))
with test_util.use_gpu():
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.dense_bincount(
input=inp, weights=[], size=size, binary_output=True)))
def _test_bincount_col_count_with_weights(self, num_rows, num_cols, size,
dtype):
np.random.seed(42)
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_weight = np.random.random((num_rows, num_cols))
np_out = np.reshape(
np.concatenate([
np.bincount(inp[j, :], weights=np_weight[j, :], minlength=size)
for j in range(num_rows)
],
axis=0), (num_rows, size))
with test_util.use_gpu():
evaluated = self.evaluate(
gen_math_ops.dense_bincount(input=inp, weights=np_weight, size=size))
if np_out.dtype in (np.float32, np.float64):
self.assertAllClose(np_out, evaluated)
else:
self.assertAllEqual(np_out, evaluated)
def test_col_reduce_basic(self):
with test_util.use_gpu():
v = self.evaluate(
gen_math_ops.dense_bincount(
input=[[1, 2, 3], [0, 3, 2]], weights=[], size=4))
expected_out = [[0., 1., 1., 1.], [1., 0., 1., 1.]]
self.assertAllEqual(expected_out, v)
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_col_reduce_shared_memory(self, dtype):
# num_rows * num_bins less than half of max shared memory.
num_rows = 128
num_cols = 27
size = 10
self._test_bincount_col_count(num_rows, num_cols, size, dtype)
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_col_reduce_global_memory(self, dtype):
# num_rows * num_bins more than half of max shared memory.
num_rows = 128
num_cols = 27
size = 1024
self._test_bincount_col_count(num_rows, num_cols, size, dtype)
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_col_reduce_shared_memory_with_weights(self, dtype):
# num_rows * num_bins less than half of max shared memory.
num_rows = 128
num_cols = 27
size = 100
self._test_bincount_col_count_with_weights(num_rows, num_cols, size, dtype)
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_col_reduce_global_memory_with_weights(self, dtype):
# num_rows * num_bins more than half of max shared memory.
num_rows = 128
num_cols = 27
size = 1024
self._test_bincount_col_count_with_weights(num_rows, num_cols, size, dtype)
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_col_reduce_binary(self, dtype):
num_rows = 128
num_cols = 7
size = 10
self._test_bincount_col_binary(num_rows, num_cols, size, dtype)
def test_invalid_rank(self):
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"at most rank 2"):
with test_util.use_gpu():
self.evaluate(
gen_math_ops.dense_bincount(
input=[[[1, 2, 3], [0, 3, 2]]], weights=[], size=10))
@test_util.run_in_graph_and_eager_modes
def test_size_is_not_scalar(self): # b/206619828
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"Shape must be rank 0 but is rank 1"):
self.evaluate(
gen_math_ops.dense_bincount(
input=[0], size=[1, 1], weights=[3], binary_output=False))
class SparseBincountOpTest(test_util.TensorFlowTestCase,
parameterized.TestCase):
@parameterized.parameters([
{
"dtype": np.int32,
},
{
"dtype": np.int64,
},
])
def test_sparse_bincount_all_count(self, dtype):
np.random.seed(42)
num_rows = 4096
size = 1000
n_elems = 128
inp_indices = np.random.randint(0, num_rows, (n_elems, 1))
inp_vals = np.random.randint(0, size, (n_elems,), dtype=dtype)
np_out = np.bincount(inp_vals, minlength=size)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_indices,
values=inp_vals,
dense_shape=[num_rows],
size=size,
weights=[])))
@parameterized.parameters([
{
"dtype": np.int32,
},
{
"dtype": np.int64,
},
])
def test_sparse_bincount_all_count_with_weights(self, dtype):
np.random.seed(42)
num_rows = 4096
size = 1000
n_elems = 128
inp_indices = np.random.randint(0, num_rows, (n_elems, 1))
inp_vals = np.random.randint(0, size, (n_elems,), dtype=dtype)
inp_weight = np.random.random((n_elems,))
np_out = np.bincount(inp_vals, minlength=size, weights=inp_weight)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_indices,
values=inp_vals,
dense_shape=[num_rows],
size=size,
weights=inp_weight)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_sparse_bincount_all_binary(self, dtype):
np.random.seed(42)
num_rows = 128
size = 10
n_elems = 4096
inp_indices = np.random.randint(0, num_rows, (n_elems, 1))
inp_vals = np.random.randint(0, size, (n_elems,), dtype=dtype)
np_out = np.ones((size,))
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_indices,
values=inp_vals,
dense_shape=[num_rows],
size=size,
weights=[],
binary_output=True)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_sparse_bincount_all_binary_weights(self, dtype):
np.random.seed(42)
num_rows = 128
size = 10
n_elems = 4096
inp_indices = np.random.randint(0, num_rows, (n_elems, 1))
inp_vals = np.random.randint(0, size, (n_elems,), dtype=dtype)
inp_weight = np.random.random((n_elems,))
np_out = np.ones((size,))
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_indices,
values=inp_vals,
dense_shape=[num_rows],
size=size,
weights=inp_weight,
binary_output=True)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_sparse_bincount_col_reduce_count(self, dtype):
num_rows = 128
num_cols = 27
size = 100
np.random.seed(42)
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_out = np.reshape(
np.concatenate(
[np.bincount(inp[j, :], minlength=size) for j in range(num_rows)],
axis=0), (num_rows, size))
# from_dense will filter out 0s.
inp = inp + 1
# from_dense will cause OOM in GPU.
with ops.device("/CPU:0"):
inp_sparse = sparse_ops.from_dense(inp)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_sparse.indices,
values=inp_sparse.values - 1,
dense_shape=inp_sparse.dense_shape,
size=size,
weights=[])))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_sparse_bincount_col_reduce_binary(self, dtype):
num_rows = 128
num_cols = 27
size = 100
np.random.seed(42)
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_out = np.reshape(
np.concatenate([
np.where(np.bincount(inp[j, :], minlength=size) > 0, 1, 0)
for j in range(num_rows)
],
axis=0), (num_rows, size))
# from_dense will filter out 0s.
inp = inp + 1
# from_dense will cause OOM in GPU.
with ops.device("/CPU:0"):
inp_sparse = sparse_ops.from_dense(inp)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_sparse.indices,
values=inp_sparse.values - 1,
dense_shape=inp_sparse.dense_shape,
size=size,
weights=[],
binary_output=True)))
@parameterized.parameters([
{
"values": [0, 1, 2, 2],
"axis": 0,
"binary": False,
"expect": [1, 1, 2],
},
{
"values": [2, 1, 2, 2],
"axis": 0,
"binary": False,
"expect": [0, 1, 3],
},
{
"values": [0, 1, 2, 2],
"axis": 0,
"binary": True,
"expect": [1, 1, 1],
},
{
"values": [2, 1, 2, 2],
"axis": 0,
"binary": True,
"expect": [0, 1, 1],
},
{
"values": [0, 1, 2, 2],
"axis": -1,
"binary": False,
"expect": [[0, 0, 0], [1, 1, 0], [0, 0, 2], [0, 0, 0]],
},
{
"values": [2, 1, 2, 2],
"axis": -1,
"binary": False,
"expect": [[0, 0, 0], [0, 1, 1], [0, 0, 2], [0, 0, 0]],
},
{
"values": [0, 1, 2, 2],
"axis": -1,
"binary": True,
"expect": [[0, 0, 0], [1, 1, 0], [0, 0, 1], [0, 0, 0]],
},
{
"values": [2, 1, 2, 2],
"axis": -1,
"binary": True,
"expect": [[0, 0, 0], [0, 1, 1], [0, 0, 1], [0, 0, 0]],
},
])
def test_sparse_bincount_implicit_zeros(
self, values, axis, binary, expect
):
if axis == -1:
indices = [[1, 2], [1, 4], [2, 2], [2, 4]]
dense_shape = [4, 5]
else:
indices = [[7], [9], [12], [14]]
dense_shape = [20]
self.assertAllEqual(
expect,
self.evaluate(
gen_math_ops.sparse_bincount(
indices=indices,
values=values,
dense_shape=dense_shape,
size=3,
weights=[],
binary_output=binary)))
@test_util.run_in_graph_and_eager_modes
def test_size_is_not_scalar(self): # b/206619828
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"Shape must be rank 0 but is rank 1"):
self.evaluate(
gen_math_ops.sparse_bincount(
indices=[[0], [1]],
values=[0, 0],
dense_shape=[1, 1],
size=[1, 1],
weights=[0, 0],
binary_output=False))
def test_sparse_bincount_input_validation(self):
np.random.seed(42)
num_rows = 128
size = 1000
n_elems = 4096
inp_indices = np.random.randint(0, num_rows, (n_elems, 1))
inp_vals = np.random.randint(0, size, (n_elems,))
# Insert negative index.
inp_indices[10, 0] = -2
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"out of bounds"):
self.evaluate(
gen_math_ops.sparse_bincount(
indices=inp_indices,
values=inp_vals,
dense_shape=[num_rows],
size=size,
weights=[]))
class RaggedBincountOpTest(test_util.TensorFlowTestCase,
parameterized.TestCase):
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_ragged_bincount_count(self, dtype):
x = ragged_factory_ops.constant([[], [], [3, 0, 1], [], [5, 0, 4, 4]])
expected_output = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0,
0], [1, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 2, 1]]
self.assertAllEqual(
expected_output,
self.evaluate(
gen_math_ops.ragged_bincount(
splits=x.row_splits, values=x.values, weights=[], size=6)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_ragged_bincount_binary(self, dtype):
x = ragged_factory_ops.constant([[], [], [3, 0, 1], [], [5, 0, 4, 4]])
expected_output = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0,
0], [1, 1, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0], [1, 0, 0, 0, 1, 1]]
self.assertAllEqual(
expected_output,
self.evaluate(
gen_math_ops.ragged_bincount(
splits=x.row_splits,
values=x.values,
weights=[],
size=6,
binary_output=True)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_ragged_bincount_count_with_weights(self, dtype):
x = ragged_factory_ops.constant([[], [], [3, 0, 1], [], [5, 0, 4, 4]])
weights = ragged_factory_ops.constant([[], [], [.1, .2, .3], [],
[.2, .5, .6, .3]])
expected_output = [[0, 0, 0, 0, 0, 0], [0, 0, 0, 0, 0, 0],
[.2, .3, 0, .1, 0, 0], [0, 0, 0, 0, 0, 0],
[.5, 0, 0, 0, .9, .2]]
self.assertAllClose(
expected_output,
self.evaluate(
gen_math_ops.ragged_bincount(
splits=x.row_splits,
values=x.values,
weights=weights.values,
size=6)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_ragged_bincount_count_np(self, dtype):
np.random.seed(42)
num_rows = 128
num_cols = 27
size = 1000
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_out = np.reshape(
np.concatenate(
[np.bincount(inp[j, :], minlength=size) for j in range(num_rows)],
axis=0), (num_rows, size))
x = ragged_tensor.RaggedTensor.from_tensor(inp)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.ragged_bincount(
splits=x.row_splits, values=x.values, weights=[], size=size)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_ragged_bincount_count_np_with_weights(self, dtype):
np.random.seed(42)
num_rows = 128
num_cols = 27
size = 1000
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_weight = np.random.random((num_rows, num_cols))
np_out = np.reshape(
np.concatenate([
np.bincount(inp[j, :], weights=np_weight[j, :], minlength=size)
for j in range(num_rows)
],
axis=0), (num_rows, size))
x = ragged_tensor.RaggedTensor.from_tensor(inp)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.ragged_bincount(
splits=x.row_splits,
values=x.values,
weights=np_weight,
size=size)))
@parameterized.parameters([{
"dtype": np.int32,
}, {
"dtype": np.int64,
}])
def test_ragged_bincount_binary_np_with_weights(self, dtype):
np.random.seed(42)
num_rows = 128
num_cols = 27
size = 1000
inp = np.random.randint(0, size, (num_rows, num_cols), dtype=dtype)
np_out = np.reshape(
np.concatenate([
np.where(np.bincount(inp[j, :], minlength=size) > 0, 1, 0)
for j in range(num_rows)
],
axis=0), (num_rows, size))
x = ragged_tensor.RaggedTensor.from_tensor(inp)
self.assertAllEqual(
np_out,
self.evaluate(
gen_math_ops.ragged_bincount(
splits=x.row_splits,
values=x.values,
weights=[],
size=size,
binary_output=True)))
@test_util.run_in_graph_and_eager_modes
def test_size_is_not_scalar(self): # b/206619828
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"Shape must be rank 0 but is rank 1"):
self.evaluate(
gen_math_ops.ragged_bincount(
splits=[0, 0, 1],
values=[1],
size=[1, 1],
weights=[0, 0, 0],
binary_output=False,
name=None))
@test_util.run_in_graph_and_eager_modes
def test_splits_empty(self): # b/238450914
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
"Splits must be non-empty"):
self.evaluate(
gen_math_ops.ragged_bincount(
splits=[], # Invalid splits
values=[1],
size=1,
weights=[1],
binary_output=False,
name=None))
if __name__ == "__main__":
googletest.main()
@@ -0,0 +1,76 @@
# Copyright 2016 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 bucketize_op."""
import numpy as np
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors_impl
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class BucketizationOpTest(test.TestCase):
def testInt(self):
op = math_ops._bucketize(
constant_op.constant([-5, 0, 2, 3, 5, 8, 10, 11, 12]),
boundaries=[0, 3, 8, 11])
expected_out = [0, 1, 1, 2, 2, 3, 3, 4, 4]
with self.session():
self.assertAllEqual(expected_out, self.evaluate(op))
def testEmptyFloat(self):
op = math_ops._bucketize(
array_ops.zeros([0, 3], dtype=dtypes.float32), boundaries=[])
expected_out = np.zeros([0, 3], dtype=np.float32)
with self.session():
self.assertAllEqual(expected_out, self.evaluate(op))
def testFloat(self):
op = math_ops._bucketize(
constant_op.constant([-5., 0., 2., 3., 5., 8., 10., 11., 12.]),
boundaries=[0., 3., 8., 11.])
expected_out = [0, 1, 1, 2, 2, 3, 3, 4, 4]
with self.session():
self.assertAllEqual(expected_out, self.evaluate(op))
def test2DInput(self):
op = math_ops._bucketize(
constant_op.constant([[-5, 0, 2, 3, 5], [8, 10, 11, 12, 0]]),
boundaries=[0, 3, 8, 11])
expected_out = [[0, 1, 1, 2, 2], [3, 3, 4, 4, 1]]
with self.session():
self.assertAllEqual(expected_out, self.evaluate(op))
@test_util.run_deprecated_v1
def testInvalidBoundariesOrder(self):
op = math_ops._bucketize(
constant_op.constant([-5, 0]), boundaries=[0, 8, 3, 11])
with self.session():
with self.assertRaisesRegex(errors_impl.InvalidArgumentError,
"Expected sorted boundaries"):
self.evaluate(op)
def testBoundariesNotList(self):
with self.assertRaisesRegex(TypeError, "Expected list.*"):
math_ops._bucketize(constant_op.constant([-5, 0]), boundaries=0)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,621 @@
# Copyright 2015 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 tensorflow.ops.clip_ops."""
import numpy as np
from tensorflow.python.eager import backprop
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import indexed_slices as indexed_slices_lib
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import clip_ops
from tensorflow.python.ops import gen_math_ops
from tensorflow.python.ops import gradients_impl
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class ClipTest(test.TestCase):
# ClipByValue test
def testClipByValue(self):
with self.session():
x = constant_op.constant([-5.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3])
np_ans = [[-4.4, 2.0, 3.0], [4.0, 4.4, 4.4]]
clip_value = 4.4
ans = clip_ops.clip_by_value(x, -clip_value, clip_value)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
# [Tensor, Scalar, Scalar]
def testClipByValue0Type(self):
for dtype in [
dtypes.float16,
dtypes.float32,
dtypes.float64,
dtypes.bfloat16,
dtypes.int16,
dtypes.int32,
dtypes.int64,
dtypes.uint8,
]:
with self.cached_session():
x = constant_op.constant([1, 2, 3, 4, 5, 6], shape=[2, 3], dtype=dtype)
np_ans = [[2, 2, 3], [4, 4, 4]]
clip_value_min = 2
clip_value_max = 4
ans = clip_ops.clip_by_value(x, clip_value_min, clip_value_max)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
# [Tensor, Tensor, Scalar]
def testClipByValue1Type(self):
for dtype in [
dtypes.float16,
dtypes.float32,
dtypes.float64,
dtypes.bfloat16,
dtypes.int16,
dtypes.int32,
dtypes.int64,
dtypes.uint8,
]:
with self.cached_session():
x = constant_op.constant([1, 2, 3, 4, 5, 6], shape=[2, 3], dtype=dtype)
np_ans = [[2, 2, 3], [4, 4, 4]]
clip_value_min = constant_op.constant(
[2, 2, 2, 3, 3, 3], shape=[2, 3], dtype=dtype)
clip_value_max = 4
ans = clip_ops.clip_by_value(x, clip_value_min, clip_value_max)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
# [Tensor, Scalar, Tensor]
def testClipByValue2Type(self):
for dtype in [
dtypes.float16,
dtypes.float32,
dtypes.float64,
dtypes.bfloat16,
dtypes.int16,
dtypes.int32,
dtypes.int64,
dtypes.uint8,
]:
with self.cached_session():
x = constant_op.constant([1, 2, 3, 4, 5, 6], shape=[2, 3], dtype=dtype)
np_ans = [[4, 4, 4], [4, 5, 6]]
clip_value_min = 4
clip_value_max = constant_op.constant(
[6, 6, 6, 6, 6, 6], shape=[2, 3], dtype=dtype)
ans = clip_ops.clip_by_value(x, clip_value_min, clip_value_max)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
# [Tensor, Tensor, Tensor]
def testClipByValue3Type(self):
for dtype in [
dtypes.float16,
dtypes.float32,
dtypes.float64,
dtypes.bfloat16,
dtypes.int16,
dtypes.int32,
dtypes.int64,
dtypes.uint8,
]:
with self.cached_session():
x = constant_op.constant([1, 2, 3, 4, 5, 6], shape=[2, 3], dtype=dtype)
np_ans = [[2, 2, 3], [5, 5, 6]]
clip_value_min = constant_op.constant(
[2, 2, 2, 5, 5, 5], shape=[2, 3], dtype=dtype)
clip_value_max = constant_op.constant(
[5, 5, 5, 7, 7, 7], shape=[2, 3], dtype=dtype)
ans = clip_ops.clip_by_value(x, clip_value_min, clip_value_max)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByValueGradient(self):
def grad(x, y, z, clip_fn):
x = constant_op.constant(x, dtype=dtypes.float32)
y = constant_op.constant(y, dtype=dtypes.float32)
z = constant_op.constant(z, dtype=dtypes.float32)
with backprop.GradientTape() as tape:
tape.watch(x)
tape.watch(y)
tape.watch(z)
output = clip_fn(x, y, z)
return tape.gradient(output, [x, y, z])
for f in (clip_ops.clip_by_value, gen_math_ops._clip_by_value):
with self.subTest(f=f):
# Input: [Scalar, Scalar, Scalar]
xg, yg, zg = grad(0, -1, 1, clip_fn=f)
self.assertEqual(self.evaluate(xg), 1)
self.assertEqual(self.evaluate(yg), 0)
self.assertEqual(self.evaluate(zg), 0)
# Input: [Scalar, Scalar, Scalar]
xg, yg, zg = grad(2, -1, 1, clip_fn=f)
self.assertEqual(self.evaluate(xg), 0)
self.assertEqual(self.evaluate(yg), 0)
self.assertEqual(self.evaluate(zg), 1)
# Input: [Vector, Scalar, Scalar]
xg, yg, zg = grad([0, -2, 2, -2], -1, 1, clip_fn=f)
self.assertAllEqual(self.evaluate(xg), [1, 0, 0, 0])
self.assertEqual(self.evaluate(yg), 2)
self.assertEqual(self.evaluate(zg), 1)
# Input: [Vector, Vector, Scalar]
xg, yg, zg = grad([-1, -2, 0, 2], [-2, -1, -3, 0], 1, clip_fn=f)
self.assertAllEqual(self.evaluate(xg), [1, 0, 1, 0])
self.assertAllEqual(self.evaluate(yg), [0, 1, 0, 0])
self.assertEqual(self.evaluate(zg), 1)
# Input: [Vector, Vector, Vector]
xg, yg, zg = grad(
[-1, -2, 0, 2], [-2, -1, -3, 0], [1, 2, -1, 1], clip_fn=f
)
self.assertAllEqual(self.evaluate(xg), [1, 0, 0, 0])
self.assertAllEqual(self.evaluate(yg), [0, 1, 0, 0])
self.assertAllEqual(self.evaluate(zg), [0, 0, 1, 1])
# Only test the following with `clip_ops.clip_by_value`, as
# `gen_math_ops._clip_by_value` requires the min and max values to be
# scalar or the same shape as the input.
# Input: [Matrix, Vector, Matrix]
xg, yg, zg = grad([[-2, 3], [2, -1]], [-1, -2], [[1, 2], [3, 4]],
clip_fn=clip_ops.clip_by_value)
self.assertAllEqual(self.evaluate(xg), [[0, 0], [1, 1]])
self.assertAllEqual(self.evaluate(yg), [1, 0])
self.assertAllEqual(self.evaluate(zg), [[0, 1], [0, 0]])
def testClipByValueBadShape(self):
with self.session():
x = constant_op.constant([-5.0, 2.0, 3.0, 4.0, 5.0, 6.0], shape=[2, 3, 1])
# Use a nonsensical shape.
clip = constant_op.constant([1.0, 2.0])
with self.assertRaises(ValueError):
_ = clip_ops.clip_by_value(x, -clip, clip) # pylint: disable=invalid-unary-operand-type
with self.assertRaises(ValueError):
_ = clip_ops.clip_by_value(x, 1.0, clip)
def testClipByValueNonFinite(self):
# TODO(b/78016351): Enable test on GPU once the bug is fixed.
with self.cached_session():
x = constant_op.constant([float('NaN'), float('Inf'), -float('Inf')])
np_ans = [float('NaN'), 4.0, -4.0]
clip_value = 4.0
ans = clip_ops.clip_by_value(x, -clip_value, clip_value)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def _testClipIndexedSlicesByValue(self, values, indices, shape,
clip_value_min, clip_value_max, expected):
with self.session():
values = constant_op.constant(values)
indices = constant_op.constant(indices)
shape = constant_op.constant(shape)
# IndexedSlices mode
indexed_slices = indexed_slices_lib.IndexedSlices(values, indices, shape)
clipped = clip_ops.clip_by_value(indexed_slices, clip_value_min,
clip_value_max)
# clipped should be IndexedSlices
self.assertIsInstance(clipped, indexed_slices_lib.IndexedSlices)
self.assertAllClose(clipped.values, expected)
def testClipByValueWithIndexedSlicesClipped(self):
values = [[[-3.0, 0.0, 0.0], [4.0, 0.0, 0.0]],
[[0.0, 2.0, 0.0], [0.0, 0.0, -1.0]]]
indices = [2, 6]
shape = [10, 2, 3]
# [-2.0, 2.0]
self._testClipIndexedSlicesByValue(values, indices, shape, -2.0, 2.0,
[[[-2.0, 0.0, 0.0], [2.0, 0.0, 0.0]],
[[0.0, 2.0, 0.0], [0.0, 0.0, -1.0]]])
# [1.0, 2.0]
self._testClipIndexedSlicesByValue(values, indices, shape, 1.0, 2.0,
[[[1.0, 1.0, 1.0], [2.0, 1.0, 1.0]],
[[1.0, 2.0, 1.0], [1.0, 1.0, 1.0]]])
# [-2.0, -1.0]
self._testClipIndexedSlicesByValue(
values, indices, shape, -2.0, -1.0,
[[[-2.0, -1.0, -1.0], [-1.0, -1.0, -1.0]],
[[-1.0, -1.0, -1.0], [-1.0, -1.0, -1.0]]])
# ClipByNorm tests
def testClipByNormClipped(self):
# Norm clipping when clip_norm < 5
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
# Norm of x = sqrt(3^2 + 4^2) = 5
np_ans = [[-2.4, 0.0, 0.0], [3.2, 0.0, 0.0]]
clip_norm = 4.0
ans = clip_ops.clip_by_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
ans = clip_ops.clip_by_norm(x, clip_norm)
tf_ans_tensor = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
self.assertAllClose(np_ans, tf_ans_tensor)
@test_util.run_deprecated_v1
def testClipByNormGradientZeros(self):
with self.session():
x = array_ops.zeros([3])
b = clip_ops.clip_by_norm(x, 1.)
grad, = gradients_impl.gradients(b, x)
self.assertAllEqual(grad, [1., 1., 1.])
def testClipByNormBadShape(self):
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3, 1])
# Use a nonsensical shape.
clip = constant_op.constant([1.0, 2.0])
with self.assertRaises(ValueError):
_ = clip_ops.clip_by_norm(x, clip)
def testClipByNormNotClipped(self):
# No norm clipping when clip_norm >= 5
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
# Norm of x = sqrt(3^2 + 4^2) = 5
np_ans = [[-3.0, 0.0, 0.0], [4.0, 0.0, 0.0]]
clip_norm = 6.0
ans = clip_ops.clip_by_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByNormZero(self):
# No norm clipping when norm = 0
with self.session():
x = constant_op.constant([0.0, 0.0, 0.0, 0.0, 0.0, 0.0], shape=[2, 3])
# Norm = 0, no changes
np_ans = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
clip_norm = 6.0
ans = clip_ops.clip_by_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByNormClippedWithDim0(self):
# Norm clipping when clip_norm < 5
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 3.0], shape=[2, 3])
# Norm of x[:, 0] = sqrt(3^2 + 4^2) = 5, x[:, 2] = 3
np_ans = [[-2.4, 0.0, 0.0], [3.2, 0.0, 3.0]]
clip_norm = 4.0
ans = clip_ops.clip_by_norm(x, clip_norm, [0])
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByNormClippedWithDim1(self):
# Norm clipping when clip_norm < 5
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 3.0], shape=[2, 3])
# Norm of x[0, :] = 3, x[1, :] = sqrt(3^2 + 4^2) = 5
np_ans = [[-3.0, 0.0, 0.0], [3.2, 0.0, 2.4]]
clip_norm = 4.0
ans = clip_ops.clip_by_norm(x, clip_norm, [1])
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByNormNotClippedWithAxes(self):
# No norm clipping when clip_norm >= 5
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 3.0], shape=[2, 3])
# Norm of x[0, :] = 3, x[1, :] = sqrt(3^2 + 4^2) = 5
np_ans = [[-3.0, 0.0, 0.0], [4.0, 0.0, 3.0]]
clip_norm = 6.0
ans = clip_ops.clip_by_norm(x, clip_norm, [1])
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
# ClipByGlobalNorm tests
def testClipByGlobalNormClipped(self):
# Norm clipping when clip_norm < 5
with self.session():
x0 = constant_op.constant([-2.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
x1 = constant_op.constant([1.0, -2.0])
# Global norm of x0 and x1 = sqrt(1 + 4^2 + 2^2 + 2^2) = 5
clip_norm = 4.0
# Answers are the original tensors scaled by 4.0/5.0
np_ans_0 = [[-1.6, 0.0, 0.0], [3.2, 0.0, 0.0]]
np_ans_1 = [0.8, -1.6]
ans, norm = clip_ops.clip_by_global_norm((x0, x1), clip_norm)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[1])
tf_norm = self.evaluate(norm)
self.assertAllClose(tf_norm, 5.0)
self.assertAllClose(np_ans_0, tf_ans_1)
self.assertAllClose(np_ans_1, tf_ans_2)
def testClipByGlobalNormClippedTensor(self):
# Norm clipping when clip_norm < 5
with self.session():
x0 = constant_op.constant([-2.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
x1 = constant_op.constant([1.0, -2.0])
# Global norm of x0 and x1 = sqrt(1 + 4^2 + 2^2 + 2^2) = 5
clip_norm = constant_op.constant(4.0)
# Answers are the original tensors scaled by 4.0/5.0
np_ans_0 = [[-1.6, 0.0, 0.0], [3.2, 0.0, 0.0]]
np_ans_1 = [0.8, -1.6]
ans, norm = clip_ops.clip_by_global_norm((x0, x1), clip_norm)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[1])
tf_norm = self.evaluate(norm)
self.assertAllClose(tf_norm, 5.0)
self.assertAllClose(np_ans_0, tf_ans_1)
self.assertAllClose(np_ans_1, tf_ans_2)
def testClipByGlobalNormSupportsNone(self):
# Norm clipping when clip_norm < 5
with self.session():
x0 = constant_op.constant([-2.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
x1 = constant_op.constant([1.0, -2.0])
# Global norm of x0 and x1 = sqrt(1 + 4^2 + 2^2 + 2^2) = 5
clip_norm = 4.0
# Answers are the original tensors scaled by 4.0/5.0
np_ans_0 = [[-1.6, 0.0, 0.0], [3.2, 0.0, 0.0]]
np_ans_1 = [0.8, -1.6]
ans, norm = clip_ops.clip_by_global_norm((x0, None, x1, None), clip_norm)
self.assertTrue(ans[1] is None)
self.assertTrue(ans[3] is None)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[2])
tf_norm = self.evaluate(norm)
self.assertAllClose(tf_norm, 5.0)
self.assertAllClose(np_ans_0, tf_ans_1)
self.assertAllClose(np_ans_1, tf_ans_2)
@test_util.run_deprecated_v1
def testClipByGlobalNormWithIndexedSlicesClipped(self):
# Norm clipping when clip_norm < 5
with self.session():
x0 = constant_op.constant([-2.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
x1 = indexed_slices_lib.IndexedSlices(
constant_op.constant([1.0, -2.0]), constant_op.constant([3, 4]))
# Global norm of x0 and x1 = sqrt(1 + 4^2 + 2^2 + 2^2) = 5
clip_norm = 4.0
# Answers are the original tensors scaled by 4.0/5.0
np_ans_0 = [[-1.6, 0.0, 0.0], [3.2, 0.0, 0.0]]
np_ans_1 = [0.8, -1.6]
ans, norm = clip_ops.clip_by_global_norm([x0, x1], clip_norm)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[1].values)
tf_norm = self.evaluate(norm)
self.assertAllClose(tf_norm, 5.0)
self.assertAllClose(np_ans_0, tf_ans_1)
self.assertAllClose(np_ans_1, tf_ans_2)
def testClipByGlobalNormPreservesDenseShape(self):
dense_shape = (1,)
slices = indexed_slices_lib.IndexedSlices(
constant_op.constant([1.0]),
constant_op.constant([0]),
dense_shape=dense_shape)
ans, _ = clip_ops.clip_by_global_norm([slices], 1.0)
modified_slices = ans[0]
self.assertEqual(dense_shape, slices.dense_shape)
self.assertEqual(dense_shape, modified_slices.dense_shape)
def testClipByGlobalNormNotClipped(self):
# No norm clipping when clip_norm >= 5
with self.session():
x0 = constant_op.constant([-2.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
x1 = constant_op.constant([1.0, -2.0])
# Global norm of x0 and x1 = sqrt(1 + 4^2 + 2^2 + 2^2) = 5
np_ans_0 = [[-2.0, 0.0, 0.0], [4.0, 0.0, 0.0]]
np_ans_1 = [1.0, -2.0]
clip_norm = 6.0
ans, norm = clip_ops.clip_by_global_norm([x0, x1], clip_norm)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[1])
tf_norm = self.evaluate(norm)
self.assertAllClose(tf_norm, 5.0)
self.assertAllClose(np_ans_0, tf_ans_1)
self.assertAllClose(np_ans_1, tf_ans_2)
def testClipByGlobalNormZero(self):
# No norm clipping when norm = 0
with self.session():
x0 = constant_op.constant([0.0, 0.0, 0.0, 0.0, 0.0, 0.0], shape=[2, 3])
x1 = constant_op.constant([0.0, 0.0])
# Norm = 0, no changes
np_ans_0 = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
np_ans_1 = [0.0, 0.0]
clip_norm = 6.0
ans, norm = clip_ops.clip_by_global_norm([x0, x1], clip_norm)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[1])
tf_norm = self.evaluate(norm)
self.assertAllClose(tf_norm, 0.0)
self.assertAllClose(np_ans_0, tf_ans_1)
self.assertAllClose(np_ans_1, tf_ans_2)
def testClipByGlobalNormInf(self):
# Expect all NaNs when global norm is inf.
with self.session():
x0 = constant_op.constant([-2.0, 0.0, np.inf, 4.0, 0.0, 0.0],
shape=[2, 3])
x1 = constant_op.constant([1.0, -2.0])
clip_norm = 6.0
ans, norm = clip_ops.clip_by_global_norm([x0, x1], clip_norm)
tf_ans_1 = self.evaluate(ans[0])
tf_ans_2 = self.evaluate(ans[1])
tf_norm = self.evaluate(norm)
self.assertAllEqual(tf_norm, float('inf'))
self.assertAllEqual(tf_ans_1, np.full([2, 3], float('nan')))
self.assertAllEqual(tf_ans_2, np.full([2], float('nan')))
def testClipByAverageNormClipped(self):
# Norm clipping when average clip_norm < 0.83333333
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
# Average norm of x = sqrt(3^2 + 4^2) / 6 = 0.83333333
np_ans = [[-2.88, 0.0, 0.0], [3.84, 0.0, 0.0]]
clip_norm = 0.8
ans = clip_ops.clip_by_average_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByAverageNormClippedTensor(self):
# Norm clipping when average clip_norm < 0.83333333
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
# Average norm of x = sqrt(3^2 + 4^2) / 6 = 0.83333333
np_ans = [[-2.88, 0.0, 0.0], [3.84, 0.0, 0.0]]
clip_norm = constant_op.constant(0.8)
ans = clip_ops.clip_by_average_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByAverageNormNotClipped(self):
# No norm clipping when average clip_norm >= 0.83333333
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
# Average norm of x = sqrt(3^2 + 4^2) / 6 = 0.83333333
np_ans = [[-3.0, 0.0, 0.0], [4.0, 0.0, 0.0]]
clip_norm = 0.9
ans = clip_ops.clip_by_average_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByAverageNormZero(self):
# No norm clipping when average clip_norm = 0
with self.session():
x = constant_op.constant([0.0, 0.0, 0.0, 0.0, 0.0, 0.0], shape=[2, 3])
# Average norm = 0, no changes
np_ans = [[0.0, 0.0, 0.0], [0.0, 0.0, 0.0]]
clip_norm = 0.9
ans = clip_ops.clip_by_average_norm(x, clip_norm)
tf_ans = self.evaluate(ans)
self.assertAllClose(np_ans, tf_ans)
def testClipByAverageNormReplacedWithClipByNorm(self):
# Check clip_by_average_norm(t) is the same as
# clip_by_norm(t, clip_norm * tf.compat.v1.to_float(tf.size(t)))
with self.session():
x = constant_op.constant([-3.0, 0.0, 0.0, 4.0, 0.0, 0.0], shape=[2, 3])
# Average norm of x = sqrt(3^2 + 4^2) / 6 = 0.83333333
# expected answer [[-2.88, 0.0, 0.0], [3.84, 0.0, 0.0]]
clip_norm = constant_op.constant(0.8)
with_norm = clip_ops.clip_by_average_norm(x, clip_norm)
without_norm = clip_ops.clip_by_norm(
x, clip_norm * math_ops.cast(array_ops.size(x), dtypes.float32))
clip_by_average_norm_ans = self.evaluate(with_norm)
clip_by_norm_ans = self.evaluate(without_norm)
self.assertAllClose(clip_by_average_norm_ans, clip_by_norm_ans)
@test_util.run_deprecated_v1
def testClipByValueEmptyTensor(self):
# Test case for GitHub issue 19337
zero = array_ops.placeholder(dtype=dtypes.float32, shape=None)
x = clip_ops.clip_by_value(zero, zero, zero)
y = clip_ops.clip_by_value(zero, 1.0, 1.0)
z = clip_ops.clip_by_value(zero, zero, 1.0)
w = clip_ops.clip_by_value(zero, 1.0, zero)
with self.session() as sess:
sess.run([x, y, z, w], feed_dict={zero: np.zeros((7, 0))})
def testClipByValueInt64(self):
with self.session():
arr = np.array(
[
2230845440,
2516058112,
4239130624,
4126539776,
3265265664,
2870476800,
2238709760,
3696754688,
4192206848,
3995598848,
3856793600,
3214934016,
2412511232,
2746220544,
2485125120,
3115843584,
3763601408,
4092592128,
2752643072,
2457468928,
3747086336,
2615279616,
2977169408,
2200043520,
2187853824,
],
dtype=np.int64,
)
min_value, max_value = (np.int64(-2147483648), np.int64(2147483647))
clipped = clip_ops.clip_by_value(
math_ops.cast(arr, dtypes.int64), min_value, max_value
)
tf_ans = self.evaluate(clipped)
# All values should be clipped to max_value
np_ans = np.full(arr.shape, max_value, dtype=np.int64)
self.assertAllEqual(np_ans, tf_ans)
arr_neg = np.array([-5000000000, -2147483649], dtype=np.int64)
clipped_neg = clip_ops.clip_by_value(
math_ops.cast(arr_neg, dtypes.int64), min_value, max_value
)
tf_ans_neg = self.evaluate(clipped_neg)
np_ans_neg = np.array([-2147483648, -2147483648], dtype=np.int64)
self.assertAllEqual(np_ans_neg, tf_ans_neg)
if __name__ == '__main__':
test.main()
@@ -0,0 +1,474 @@
# Copyright 2016 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 confusion_matrix_ops."""
import numpy as np
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors_impl
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import confusion_matrix
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import random_ops
from tensorflow.python.platform import test
class ConfusionMatrixTest(test.TestCase):
@test_util.run_in_graph_and_eager_modes
def testExample(self):
"""This is a test of the example provided in pydoc."""
with self.cached_session():
self.assertAllEqual([
[0, 0, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 0, 0],
[0, 0, 0, 0, 1]
], self.evaluate(confusion_matrix.confusion_matrix(
labels=[1, 2, 4], predictions=[2, 2, 4])))
def _testConfMatrix(self, labels, predictions, truth, weights=None,
num_classes=None):
with self.cached_session():
dtype = predictions.dtype
ans = confusion_matrix.confusion_matrix(
labels, predictions, dtype=dtype, weights=weights,
num_classes=num_classes).eval()
self.assertAllClose(truth, ans, atol=1e-10)
self.assertEqual(ans.dtype, dtype)
def _testBasic(self, dtype):
labels = np.arange(5, dtype=dtype)
predictions = np.arange(5, dtype=dtype)
truth = np.asarray(
[[1, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 1, 0, 0],
[0, 0, 0, 1, 0],
[0, 0, 0, 0, 1]],
dtype=dtype)
self._testConfMatrix(labels=labels, predictions=predictions, truth=truth)
@test_util.run_deprecated_v1
def testInt32Basic(self):
self._testBasic(dtype=np.int32)
@test_util.run_deprecated_v1
def testInt64Basic(self):
self._testBasic(dtype=np.int64)
def _testConfMatrixOnTensors(self, tf_dtype, np_dtype):
with self.cached_session() as sess:
m_neg = array_ops.placeholder(dtype=dtypes.float32)
m_pos = array_ops.placeholder(dtype=dtypes.float32)
s = array_ops.placeholder(dtype=dtypes.float32)
neg = random_ops.random_normal(
[20], mean=m_neg, stddev=s, dtype=dtypes.float32)
pos = random_ops.random_normal(
[20], mean=m_pos, stddev=s, dtype=dtypes.float32)
data = array_ops.concat([neg, pos], 0)
data = math_ops.cast(math_ops.round(data), tf_dtype)
data = math_ops.minimum(math_ops.maximum(data, 0), 1)
lab = array_ops.concat(
[
array_ops.zeros(
[20], dtype=tf_dtype), array_ops.ones(
[20], dtype=tf_dtype)
],
0)
cm = confusion_matrix.confusion_matrix(
lab, data, dtype=tf_dtype, num_classes=2)
d, l, cm_out = sess.run([data, lab, cm], {m_neg: 0.0, m_pos: 1.0, s: 1.0})
truth = np.zeros([2, 2], dtype=np_dtype)
for i in range(len(d)):
truth[l[i], d[i]] += 1
self.assertEqual(cm_out.dtype, np_dtype)
self.assertAllClose(cm_out, truth, atol=1e-10)
@test_util.run_deprecated_v1
def testOnTensors_int32(self):
self._testConfMatrixOnTensors(dtypes.int32, np.int32)
@test_util.run_deprecated_v1
def testOnTensors_int64(self):
self._testConfMatrixOnTensors(dtypes.int64, np.int64)
def _testDifferentLabelsInPredictionAndTarget(self, dtype):
labels = np.asarray([4, 5, 6], dtype=dtype)
predictions = np.asarray([1, 2, 3], dtype=dtype)
truth = np.asarray(
[[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0],
[0, 0, 0, 1, 0, 0, 0]],
dtype=dtype)
self._testConfMatrix(labels=labels, predictions=predictions, truth=truth)
@test_util.run_deprecated_v1
def testInt32DifferentLabels(self, dtype=np.int32):
self._testDifferentLabelsInPredictionAndTarget(dtype)
@test_util.run_deprecated_v1
def testInt64DifferentLabels(self, dtype=np.int64):
self._testDifferentLabelsInPredictionAndTarget(dtype)
def _testMultipleLabels(self, dtype):
labels = np.asarray([1, 1, 2, 3, 5, 1, 3, 6, 3, 1], dtype=dtype)
predictions = np.asarray([1, 1, 2, 3, 5, 6, 1, 2, 3, 4], dtype=dtype)
truth = np.asarray(
[[0, 0, 0, 0, 0, 0, 0],
[0, 2, 0, 0, 1, 0, 1],
[0, 0, 1, 0, 0, 0, 0],
[0, 1, 0, 2, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 1, 0],
[0, 0, 1, 0, 0, 0, 0]],
dtype=dtype)
self._testConfMatrix(labels=labels, predictions=predictions, truth=truth)
@test_util.run_deprecated_v1
def testInt32MultipleLabels(self, dtype=np.int32):
self._testMultipleLabels(dtype)
@test_util.run_deprecated_v1
def testInt64MultipleLabels(self, dtype=np.int64):
self._testMultipleLabels(dtype)
@test_util.run_deprecated_v1
def testWeighted(self):
labels = np.arange(5, dtype=np.int32)
predictions = np.arange(5, dtype=np.int32)
weights = np.arange(5, dtype=np.int32)
truth = np.asarray(
[[0, 0, 0, 0, 0],
[0, 1, 0, 0, 0],
[0, 0, 2, 0, 0],
[0, 0, 0, 3, 0],
[0, 0, 0, 0, 4]],
dtype=np.int32)
self._testConfMatrix(
labels=labels, predictions=predictions, weights=weights, truth=truth)
@test_util.run_deprecated_v1
def testLabelsTooLarge(self):
labels = np.asarray([1, 1, 0, 3, 5], dtype=np.int32)
predictions = np.asarray([2, 1, 0, 2, 2], dtype=np.int32)
with self.assertRaisesWithPredicateMatch(errors_impl.InvalidArgumentError,
"`labels`.*out of bound"):
self._testConfMatrix(
labels=labels, predictions=predictions, num_classes=3, truth=None)
def testLabelsNegative(self):
labels = np.asarray([1, 1, 0, -1, -1], dtype=np.int32)
predictions = np.asarray([2, 1, 0, 2, 2], dtype=np.int32)
with self.assertRaisesOpError("`labels`.*negative values"):
self._testConfMatrix(
labels=labels, predictions=predictions, num_classes=3, truth=None)
@test_util.run_deprecated_v1
def testPredictionsTooLarge(self):
labels = np.asarray([1, 1, 0, 2, 2], dtype=np.int32)
predictions = np.asarray([2, 1, 0, 3, 5], dtype=np.int32)
with self.assertRaisesWithPredicateMatch(errors_impl.InvalidArgumentError,
"`predictions`.*out of bound"):
self._testConfMatrix(
labels=labels, predictions=predictions, num_classes=3, truth=None)
def testPredictionsNegative(self):
labels = np.asarray([1, 1, 0, 2, 2], dtype=np.int32)
predictions = np.asarray([2, 1, 0, -1, -1], dtype=np.int32)
with self.assertRaisesOpError("`predictions`.*negative values"):
self._testConfMatrix(
labels=labels, predictions=predictions, num_classes=3, truth=None)
@test_util.run_deprecated_v1
def testInputDifferentSize(self):
labels = np.asarray([1, 2])
predictions = np.asarray([1, 2, 3])
self.assertRaisesRegex(ValueError, "must be equal",
confusion_matrix.confusion_matrix, predictions,
labels)
def testOutputIsInt32(self):
labels = np.arange(2)
predictions = np.arange(2)
with self.cached_session():
cm = confusion_matrix.confusion_matrix(
labels, predictions, dtype=dtypes.int32)
tf_cm = self.evaluate(cm)
self.assertEqual(tf_cm.dtype, np.int32)
def testOutputIsInt64(self):
labels = np.arange(2)
predictions = np.arange(2)
with self.cached_session():
cm = confusion_matrix.confusion_matrix(
labels, predictions, dtype=dtypes.int64)
tf_cm = self.evaluate(cm)
self.assertEqual(tf_cm.dtype, np.int64)
class RemoveSqueezableDimensionsTest(test.TestCase):
@test_util.run_deprecated_v1
def testBothScalarShape(self):
label_values = 1.0
prediction_values = 0.0
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values))
labels_placeholder = array_ops.placeholder(dtype=dtypes.float32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.float32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder))
with self.cached_session():
self.assertAllEqual(label_values, self.evaluate(static_labels))
self.assertAllEqual(prediction_values, self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
prediction_values, dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testSameShape(self):
label_values = np.ones(shape=(2, 3, 1))
prediction_values = np.zeros_like(label_values)
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder))
with self.cached_session():
self.assertAllEqual(label_values, self.evaluate(static_labels))
self.assertAllEqual(prediction_values, self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
prediction_values, dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testSameShapeExpectedRankDiff0(self):
label_values = np.ones(shape=(2, 3, 1))
prediction_values = np.zeros_like(label_values)
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values, expected_rank_diff=0))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder, expected_rank_diff=0))
with self.cached_session():
self.assertAllEqual(label_values, self.evaluate(static_labels))
self.assertAllEqual(prediction_values, self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
prediction_values, dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testSqueezableLabels(self):
label_values = np.ones(shape=(2, 3, 1))
prediction_values = np.zeros(shape=(2, 3))
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder))
expected_label_values = np.reshape(label_values, (2, 3))
with self.cached_session():
self.assertAllEqual(expected_label_values, self.evaluate(static_labels))
self.assertAllEqual(prediction_values, self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
expected_label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
prediction_values, dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testSqueezableLabelsExpectedRankDiffPlus1(self):
label_values = np.ones(shape=(2, 3, 1))
prediction_values = np.zeros(shape=(2, 3, 5))
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values, expected_rank_diff=1))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder, expected_rank_diff=1))
expected_label_values = np.reshape(label_values, (2, 3))
with self.cached_session():
self.assertAllEqual(expected_label_values, self.evaluate(static_labels))
self.assertAllEqual(prediction_values, self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
expected_label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
prediction_values, dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testSqueezablePredictions(self):
label_values = np.ones(shape=(2, 3))
prediction_values = np.zeros(shape=(2, 3, 1))
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder))
expected_prediction_values = np.reshape(prediction_values, (2, 3))
with self.cached_session():
self.assertAllEqual(label_values, self.evaluate(static_labels))
self.assertAllEqual(expected_prediction_values,
self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
expected_prediction_values,
dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testSqueezablePredictionsExpectedRankDiffMinus1(self):
label_values = np.ones(shape=(2, 3, 5))
prediction_values = np.zeros(shape=(2, 3, 1))
static_labels, static_predictions = (
confusion_matrix.remove_squeezable_dimensions(
label_values, prediction_values, expected_rank_diff=-1))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(
labels_placeholder, predictions_placeholder, expected_rank_diff=-1))
expected_prediction_values = np.reshape(prediction_values, (2, 3))
with self.cached_session():
self.assertAllEqual(label_values, self.evaluate(static_labels))
self.assertAllEqual(expected_prediction_values,
self.evaluate(static_predictions))
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
label_values, dynamic_labels.eval(feed_dict=feed_dict))
self.assertAllEqual(
expected_prediction_values,
dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testUnsqueezableLabels(self):
label_values = np.ones(shape=(2, 3, 2))
prediction_values = np.zeros(shape=(2, 3))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
_, dynamic_predictions = (
confusion_matrix.remove_squeezable_dimensions(labels_placeholder,
predictions_placeholder))
with self.cached_session():
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
prediction_values, dynamic_predictions.eval(feed_dict=feed_dict))
@test_util.run_deprecated_v1
def testUnsqueezablePredictions(self):
label_values = np.ones(shape=(2, 3))
prediction_values = np.zeros(shape=(2, 3, 2))
labels_placeholder = array_ops.placeholder(dtype=dtypes.int32)
predictions_placeholder = array_ops.placeholder(dtype=dtypes.int32)
dynamic_labels, _ = (
confusion_matrix.remove_squeezable_dimensions(labels_placeholder,
predictions_placeholder))
with self.cached_session():
feed_dict = {
labels_placeholder: label_values,
predictions_placeholder: prediction_values
}
self.assertAllEqual(
label_values, dynamic_labels.eval(feed_dict=feed_dict))
if __name__ == "__main__":
test.main()
@@ -0,0 +1,43 @@
# Copyright 2015 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 tensorflow.ops.nn_ops.Cross."""
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class CrossOpTest(test.TestCase):
@test_util.run_deprecated_v1
def testGradientRandomValues(self):
with self.cached_session():
us = [2, 3]
u = array_ops.reshape(
[0.854, -0.616, 0.767, 0.725, -0.927, 0.159], shape=us)
v = array_ops.reshape(
[-0.522, 0.755, 0.407, -0.652, 0.241, 0.247], shape=us)
s = math_ops.cross(u, v)
jacob_u, jacob_v = gradient_checker.compute_gradient([u, v], [us, us], s,
us)
self.assertAllClose(jacob_u[0], jacob_u[1], rtol=1e-3, atol=1e-3)
self.assertAllClose(jacob_v[0], jacob_v[1], rtol=1e-3, atol=1e-3)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,133 @@
# Copyright 2016 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.
# ==============================================================================
"""Functional tests for cumulative_logsumexp op."""
import numpy as np
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.ops import map_fn
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class CumulativeLogsumexpTest(test.TestCase):
valid_dtypes = [
dtypes.float32,
dtypes.float64,
dtypes.float16,
dtypes.bfloat16,
]
def _computeLogSumExp(self, x, **kwargs):
result_naive = math_ops.cumsum(math_ops.exp(x), **kwargs)
result_fused = math_ops.exp(math_ops.cumulative_logsumexp(x, **kwargs))
return result_naive, result_fused
def _testLogSumExp(self, x, dtype=dtypes.float32, use_gpu=False, **kwargs):
with self.cached_session(use_gpu=use_gpu):
x = ops.convert_to_tensor(x, dtype=dtype)
result_naive, result_fused = self.evaluate(
self._computeLogSumExp(x, **kwargs))
tol = 2e-2 if dtype in [dtypes.float16, dtypes.bfloat16] else 1e-6
self.assertAllClose(result_naive, result_fused, rtol=tol, atol=tol)
def _testLogSumExpAllArgs(self, x, axis=0, use_gpu=False):
for dtype in self.valid_dtypes:
for reverse in (True, False):
for exclusive in (True, False):
self._testLogSumExp(
x, dtype=dtype, use_gpu=use_gpu,
reverse=reverse, exclusive=exclusive,
axis=axis)
def testMinusInfinity(self):
x = np.log([0., 0., 1., 1., 1., 1., 0., 0.])
self._testLogSumExpAllArgs(x, use_gpu=False)
self._testLogSumExpAllArgs(x, use_gpu=True)
def test1D(self):
x = np.arange(10) / 10.0 - 0.5
self._testLogSumExpAllArgs(x, use_gpu=False)
self._testLogSumExpAllArgs(x, use_gpu=True)
def test2D(self):
x = np.reshape(np.arange(20) / 20.0 - 0.5, (2, 10))
for axis in (-2, -1, 0, 1):
self._testLogSumExpAllArgs(x, axis=axis, use_gpu=False)
self._testLogSumExpAllArgs(x, axis=axis, use_gpu=True)
def _testGradient(self, x, use_gpu=False, **kwargs):
with self.cached_session(use_gpu=use_gpu):
x = ops.convert_to_tensor(x, dtype=dtypes.float64)
grad_naive_theoretical, _ = gradient_checker_v2.compute_gradient(
lambda y: math_ops.cumsum(math_ops.exp(y), **kwargs), [x])
grad_fused_theoretical, _ = gradient_checker_v2.compute_gradient(
lambda y: math_ops.exp(math_ops.cumulative_logsumexp(y, **kwargs)),
[x])
self.assertAllClose(grad_fused_theoretical, grad_naive_theoretical)
def testGradient(self):
for reverse in (True, False):
for exclusive in (True, False):
x = np.arange(10) / 10.0 - 0.5
self._testGradient(x, use_gpu=False,
reverse=reverse, exclusive=exclusive)
self._testGradient(x, use_gpu=True,
reverse=reverse, exclusive=exclusive)
def _logSumExpMap(self, x):
return map_fn.map_fn(
lambda i: math_ops.reduce_logsumexp(x[:i + 1]),
math_ops.range(array_ops.shape(x)[0]),
dtype=x.dtype)
def test1DLarge(self):
# This test ensures that the operation is correct even when the naive
# implementation would overflow.
x_np = np.arange(20) * 20.0
for use_gpu in (True, False):
with self.cached_session(use_gpu=use_gpu):
x_tf = ops.convert_to_tensor(x_np, dtype=dtypes.float32)
result_fused = self.evaluate(math_ops.cumulative_logsumexp(x_tf))
result_map = self.evaluate(self._logSumExpMap(x_tf))
self.assertAllClose(result_fused, result_map)
def testPlusInfinity(self):
x = [np.inf, np.inf, 1.0, np.inf]
for dtype in self.valid_dtypes:
for use_gpu in (True, False):
with self.cached_session(use_gpu=use_gpu):
x_tf = ops.convert_to_tensor(x, dtype=dtype)
result = self.evaluate(math_ops.cumulative_logsumexp(x_tf))
expected = np.array(
[np.inf, np.inf, np.inf, np.inf], dtype=x_tf.dtype.as_numpy_dtype
)
self.assertAllClose(result, expected)
if __name__ == '__main__':
test.main()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,685 @@
# Copyright 2018 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.
# ==============================================================================
"""Functional tests for unary coefficient-wise operations."""
import math
import numpy as np
from tensorflow.python.eager import backprop
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes as dtypes_lib
from tensorflow.python.framework import ops
from tensorflow.python.framework import sparse_tensor
from tensorflow.python.framework import test_util
from tensorflow.python.ops import gen_math_ops
from tensorflow.python.ops import gradient_checker
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import nn_grad # pylint: disable=unused-import
from tensorflow.python.ops import special_math_ops
from tensorflow.python.platform import test
from tensorflow.python.platform import tf_logging
_NEG = lambda x: -x
_ABS = abs
# TODO(zongheng): it'd be great to factor out this function and various random
# SparseTensor gen funcs.
def _sparsify(x, thresh=0.5, index_dtype=np.int64):
x[x < thresh] = 0
non_zero = np.where(x)
x_indices = np.vstack(non_zero).astype(index_dtype).T
x_values = x[non_zero]
x_shape = x.shape
return sparse_tensor.SparseTensor(
indices=x_indices, values=x_values, dense_shape=x_shape), x_values
def _default_tolerance(dtype):
"""Returns a sensible default tolerance for comparing results of a given type.
Args:
dtype: A datatype.
"""
if dtype == dtypes_lib.bfloat16.as_numpy_dtype:
return 5e-3
if dtype == np.float16:
return 5e-3
elif dtype in (np.float32, np.complex64):
return 1e-3
elif dtype in (np.float64, np.complex128):
return 1e-5
else:
return None # Fail fast for unexpected types
class UnaryOpTest(test.TestCase):
def _compareCpu(self, x, np_func, tf_func, grad_rtol=None, grad_atol=None):
if grad_rtol is None:
grad_rtol = _default_tolerance(x.dtype)
if grad_atol is None:
grad_atol = _default_tolerance(x.dtype)
np_ans = np_func(x)
with self.cached_session(use_gpu=False):
inx = ops.convert_to_tensor(x)
y = tf_func(inx)
tf_cpu = self.evaluate(y)
self.assertShapeEqual(np_ans, y)
if x.dtype == np.float16:
self.assertAllClose(np_ans, tf_cpu, rtol=1e-3, atol=1e-3)
elif x.dtype == dtypes_lib.bfloat16.as_numpy_dtype:
self.assertAllClose(np_ans, tf_cpu, rtol=1e-2, atol=1e-2)
else:
self.assertAllClose(np_ans, tf_cpu)
if x.dtype in (np.complex64, np.complex128) and tf_func == math_ops.sign:
return # Return early
if tf_func == math_ops.round:
return # Return early
if x.dtype in (np.float16, dtypes_lib.bfloat16.as_numpy_dtype):
s = list(np.shape(x))
jacob_t, _ = gradient_checker.compute_gradient(
inx, s, y, s, x_init_value=x)
xf = x.astype(np.float64)
inxf = ops.convert_to_tensor(xf)
yf = tf_func(inxf)
_, jacob_n = gradient_checker.compute_gradient(
inxf, s, yf, s, x_init_value=xf, delta=1e-2)
jacob_n = jacob_n.astype(x.dtype)
self.assertAllClose(jacob_t, jacob_n, rtol=grad_rtol, atol=grad_atol)
elif x.dtype in (np.float32, np.complex64):
s = list(np.shape(x))
jacob_t, jacob_n = gradient_checker.compute_gradient(
inx, s, y, s, x_init_value=x, delta=1e-3)
self.assertAllClose(jacob_t, jacob_n, rtol=grad_rtol, atol=grad_atol)
elif x.dtype in (np.float64, np.complex128):
s = list(np.shape(x))
jacob_t, jacob_n = gradient_checker.compute_gradient(
inx, s, y, s, x_init_value=x, delta=1e-5)
self.assertAllClose(jacob_t, jacob_n, rtol=grad_rtol, atol=grad_atol)
def _check(self, result_tensor, result_np, input_sp_t, tol):
self.assertTrue(isinstance(result_tensor, sparse_tensor.SparseTensor))
self.assertTrue(isinstance(input_sp_t, sparse_tensor.SparseTensor))
self.assertAllEqual(input_sp_t.indices, result_tensor.indices)
self.assertAllEqual(input_sp_t.dense_shape, result_tensor.dense_shape)
if tol is None:
self.assertAllClose(result_np, result_tensor.values)
else:
self.assertAllClose(result_np, result_tensor.values, rtol=tol, atol=tol)
def _compareSparseCpu(self, x, np_func, tf_func, tol):
x_sp, x_sp_vals = _sparsify(x)
res_np = np_func(x_sp_vals)
with test_util.force_cpu():
self._check(tf_func(x_sp), res_np, x_sp, tol)
def _compareGpu(self, x, np_func, tf_func):
np_ans = np_func(x)
with test_util.use_gpu():
result = tf_func(ops.convert_to_tensor(x))
tf_gpu = self.evaluate(result)
# Slightly increase the tolerance for float64 computations. This is
# desired for specifically lgamma but shouldn't be of concern for other
# functions.
self.assertAllCloseAccordingToType(np_ans, tf_gpu, atol=2e-6)
# TODO(zhifengc/ke): make gradient checker work on GPU.
def _compareSparseGpu(self, x, np_func, tf_func, tol):
x_sp, x_sp_vals = _sparsify(x)
res_np = np_func(x_sp_vals)
with test_util.use_gpu():
self._check(tf_func(x_sp), res_np, x_sp, tol)
def _compareBoth(self, x, np_func, tf_func, grad_tol=None):
self._compareCpu(x, np_func, tf_func, grad_rtol=grad_tol,
grad_atol=grad_tol)
self._compareGpu(x, np_func, tf_func)
def _compareBothSparse(self, x, np_func, tf_func, tol=None):
self._compareSparseCpu(x, np_func, tf_func, tol)
self._compareSparseGpu(x, np_func, tf_func, tol)
def _inv(self, x):
return 1.0 / x
def _rsqrt(self, x):
return self._inv(np.sqrt(x))
def _sigmoid(self, x):
return 1.0 / (1.0 + np.exp(-x))
def _log_sigmoid(self, x):
return np.log(self._sigmoid(x))
def _replace_domain_error_with_inf(self, fn):
def func(x):
try:
return fn(x)
except ValueError as e:
if "domain error" in str(e):
return np.inf * np.ones_like(x)
else:
raise e
return func
@test_util.run_deprecated_v1
def testFloatBasic(self):
x = np.arange(-3, 3).reshape(1, 3, 2).astype(np.float32)
w = x - x.min() + 1.02 # all greater than 1
y = (x + .5).astype(np.float32) # no zero
z = (x + 15.5).astype(np.float32) # all positive
k = np.arange(-0.90, 0.90, 0.25).astype(np.float32) # between -1 and 1
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(y, self._inv, math_ops.reciprocal)
self._compareBoth(x, np.square, math_ops.square)
self._compareBoth(z, np.sqrt, math_ops.sqrt)
self._compareBoth(z, self._rsqrt, math_ops.rsqrt)
self._compareBoth(x, np.exp, math_ops.exp)
self._compareBoth(x, np.expm1, math_ops.expm1)
self._compareBoth(z, np.log, math_ops.log)
self._compareBoth(z, np.log1p, math_ops.log1p)
self._compareBoth(x, np.sinh, math_ops.sinh)
self._compareBoth(x, np.cosh, math_ops.cosh)
self._compareBoth(x, np.tanh, math_ops.tanh)
self._compareBoth(x, np.arcsinh, math_ops.asinh)
self._compareBoth(w, np.arccosh, math_ops.acosh)
self._compareBoth(k, np.arctanh, math_ops.atanh)
self._compareBoth(x, self._sigmoid, math_ops.sigmoid)
self._compareBoth(x, self._log_sigmoid, math_ops.log_sigmoid)
self._compareBoth(y, np.sign, math_ops.sign)
self._compareBoth(x, np.sin, math_ops.sin)
self._compareBoth(x, np.cos, math_ops.cos)
self._compareBoth(k, np.arcsin, math_ops.asin)
self._compareBoth(k, np.arccos, math_ops.acos)
self._compareBoth(x, np.arctan, math_ops.atan)
self._compareBoth(x, np.tan, math_ops.tan)
self._compareBoth(
y, np.vectorize(self._replace_domain_error_with_inf(math.lgamma)),
math_ops.lgamma)
self._compareBoth(x, np.vectorize(math.erf), math_ops.erf)
self._compareBoth(x, np.vectorize(math.erfc), math_ops.erfc)
try:
from scipy import special # pylint: disable=g-import-not-at-top
self._compareBoth(x, special.i0e, special_math_ops.bessel_i0e)
self._compareBoth(x, special.i1e, special_math_ops.bessel_i1e)
except ImportError as e:
tf_logging.warn("Cannot test special functions: %s" % str(e))
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(z, np.sqrt, math_ops.sqrt, tol=1e-3)
self._compareBothSparse(x, np.tanh, math_ops.tanh)
self._compareBothSparse(y, np.sign, math_ops.sign)
self._compareBothSparse(x, np.vectorize(math.erf), math_ops.erf)
def testFloatErfinvNearOne(self):
# Regression test for GitHub issue #121629: eager float32 erfinv used to
# lose ~4 digits of precision for inputs close to +/-1 because it computed
# ndtri(0.5 * x + 0.5), and forming 0.5 * x + 0.5 in float32 destroys the
# distance of the argument from 1. Verify the float32 op now agrees with
# the float64 ground truth (and is symmetric) in that region.
x = np.array(
[0.9990000129, 0.9998999834, 0.9999899864, 0.9999989867, 0.9999998212],
dtype=np.float32,
)
x = np.concatenate([x, -x])
with self.cached_session():
expected = self.evaluate(
math_ops.erfinv(ops.convert_to_tensor(x.astype(np.float64)))
)
actual = self.evaluate(math_ops.erfinv(ops.convert_to_tensor(x)))
self.assertAllClose(expected, actual, rtol=1e-5, atol=1e-5)
def testFloatErfinvEdgeCases(self):
# erfinv is +/-inf at +/-1 and undefined (NaN) outside [-1, 1]. The float32
# path mirrors the XLA implementation here.
x = np.array([1.0, -1.0, 1.5, -2.0], dtype=np.float32)
with self.cached_session():
y = self.evaluate(math_ops.erfinv(ops.convert_to_tensor(x)))
self.assertEqual(np.inf, y[0])
self.assertEqual(-np.inf, y[1])
self.assertTrue(np.isnan(y[2]))
self.assertTrue(np.isnan(y[3]))
@test_util.run_deprecated_v1
def testFloatTanhEdge(self):
x = np.arange(40, 40 + 6).reshape(6).astype(np.float32)
self._compareBoth(x, np.tanh, math_ops.tanh)
x = np.arange(-40, -40 + 6).reshape(6).astype(np.float32)
self._compareBoth(x, np.tanh, math_ops.tanh)
@test_util.run_deprecated_v1
def testFloatEmpty(self):
x = np.empty((2, 0, 5), dtype=np.float32)
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(x, self._inv, math_ops.reciprocal)
self._compareBoth(x, np.square, math_ops.square)
self._compareBoth(x, np.sqrt, math_ops.sqrt)
self._compareBoth(x, self._rsqrt, math_ops.rsqrt)
self._compareBoth(x, np.exp, math_ops.exp)
self._compareBoth(x, np.expm1, math_ops.expm1)
self._compareBoth(x, np.log, math_ops.log)
self._compareBoth(x, np.log1p, math_ops.log1p)
self._compareBoth(x, np.sinh, math_ops.sinh)
self._compareBoth(x, np.arcsinh, math_ops.asinh)
self._compareBoth(x, np.cosh, math_ops.cosh)
self._compareBoth(x, np.arccosh, math_ops.acosh)
self._compareBoth(x, np.tanh, math_ops.tanh)
self._compareBoth(x, np.arctanh, math_ops.atanh)
self._compareBoth(x, self._sigmoid, math_ops.sigmoid)
self._compareBoth(x, np.sign, math_ops.sign)
self._compareBoth(x, np.sin, math_ops.sin)
self._compareBoth(x, np.cos, math_ops.cos)
# Can't use vectorize below, so just use some arbitrary function
self._compareBoth(x, np.sign, math_ops.lgamma)
self._compareBoth(x, np.sign, math_ops.erf)
self._compareBoth(x, np.sign, math_ops.erfc)
self._compareBoth(x, np.tan, math_ops.tan)
self._compareBoth(x, np.arcsin, math_ops.asin)
self._compareBoth(x, np.arccos, math_ops.acos)
self._compareBoth(x, np.arctan, math_ops.atan)
try:
from scipy import special # pylint: disable=g-import-not-at-top
self._compareBoth(x, special.i0e, special_math_ops.bessel_i0e)
self._compareBoth(x, special.i1e, special_math_ops.bessel_i1e)
except ImportError as e:
tf_logging.warn("Cannot test special functions: %s" % str(e))
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(x, np.sqrt, math_ops.sqrt, tol=1e-3)
self._compareBothSparse(x, np.tanh, math_ops.tanh)
self._compareBothSparse(x, np.sign, math_ops.sign)
self._compareBothSparse(x, np.sign, math_ops.erf)
@test_util.run_deprecated_v1
def testDoubleBasic(self):
x = np.arange(-3, 3).reshape(1, 3, 2).astype(np.float64)
w = x - x.min() + 1.02 # all greater than 1
y = (x + .5).astype(np.float64) # no zero
z = (x + 15.5).astype(np.float64) # all positive
k = np.arange(-0.90, 0.90,
0.35).reshape(1, 3, 2).astype(np.float64) # between -1 and 1
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(y, self._inv, math_ops.reciprocal)
self._compareBoth(x, np.square, math_ops.square)
self._compareBoth(z, np.sqrt, math_ops.sqrt)
self._compareBoth(z, self._rsqrt, math_ops.rsqrt)
self._compareBoth(x, np.exp, math_ops.exp)
self._compareBoth(x, np.expm1, math_ops.expm1)
self._compareBoth(z, np.log, math_ops.log)
self._compareBoth(z, np.log1p, math_ops.log1p)
self._compareBoth(x, np.sinh, math_ops.sinh)
self._compareBoth(x, np.cosh, math_ops.cosh)
self._compareBoth(x, np.tanh, math_ops.tanh)
self._compareBoth(x, np.arcsinh, math_ops.asinh)
self._compareBoth(w, np.arccosh, math_ops.acosh)
self._compareBoth(k, np.arctanh, math_ops.atanh)
self._compareBoth(x, self._sigmoid, math_ops.sigmoid)
self._compareBoth(y, np.sign, math_ops.sign)
self._compareBoth(x, np.sin, math_ops.sin)
self._compareBoth(x, np.cos, math_ops.cos)
self._compareBoth(
y, np.vectorize(self._replace_domain_error_with_inf(math.lgamma)),
math_ops.lgamma)
self._compareBoth(x, np.vectorize(math.erf), math_ops.erf)
self._compareBoth(x, np.vectorize(math.erfc), math_ops.erfc)
self._compareBoth(x, np.arctan, math_ops.atan)
self._compareBoth(k, np.arcsin, math_ops.asin)
self._compareBoth(k, np.arccos, math_ops.acos)
self._compareBoth(k, np.tan, math_ops.tan)
try:
from scipy import special # pylint: disable=g-import-not-at-top
self._compareBoth(x, special.i0e, special_math_ops.bessel_i0e)
self._compareBoth(x, special.i1e, special_math_ops.bessel_i1e)
except ImportError as e:
tf_logging.warn("Cannot test special functions: %s" % str(e))
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(z, np.sqrt, math_ops.sqrt, tol=1e-3)
self._compareBothSparse(x, np.tanh, math_ops.tanh)
self._compareBothSparse(y, np.sign, math_ops.sign)
self._compareBothSparse(x, np.vectorize(math.erf), math_ops.erf)
@test_util.run_deprecated_v1
def testHalfBasic(self):
x = np.arange(-3, 3).reshape(1, 3, 2).astype(np.float16)
w = x - x.min() + 1.1 # all greater than 1
y = (x + .5).astype(np.float16) # no zero
z = (x + 15.5).astype(np.float16) # all positive
k = np.arange(-0.90, 0.90, 0.05).astype(np.float16) # between -1 and 1
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(y, self._inv, math_ops.reciprocal)
self._compareBoth(x, np.square, math_ops.square)
self._compareBoth(z, np.sqrt, math_ops.sqrt)
self._compareBoth(z, self._rsqrt, math_ops.rsqrt)
self._compareBoth(x, np.exp, math_ops.exp)
self._compareBoth(x, np.expm1, math_ops.expm1)
self._compareBoth(z, np.log, math_ops.log)
self._compareBoth(z, np.log1p, math_ops.log1p)
self._compareBoth(x, np.sinh, math_ops.sinh)
self._compareBoth(x, np.cosh, math_ops.cosh)
self._compareBoth(x, np.tanh, math_ops.tanh)
self._compareBoth(x, self._sigmoid, math_ops.sigmoid)
self._compareBoth(y, np.sign, math_ops.sign)
self._compareBoth(x, np.sin, math_ops.sin)
self._compareBoth(x, np.cos, math_ops.cos)
self._compareBoth(x, np.tan, math_ops.tan)
self._compareBoth(k, np.arcsin, math_ops.asin)
self._compareBoth(k, np.arccos, math_ops.acos)
self._compareBoth(x, np.arctan, math_ops.atan)
self._compareBoth(x, np.arcsinh, math_ops.asinh)
# The derivative of acosh close to 1 is very large, and needs a high
# tolerance for small precision.
self._compareBoth(w, np.arccosh, math_ops.acosh, grad_tol=1e-3)
self._compareBoth(k, np.arctanh, math_ops.atanh)
self._compareBoth(
y, np.vectorize(self._replace_domain_error_with_inf(math.lgamma)),
math_ops.lgamma)
self._compareBoth(x, np.vectorize(math.erf), math_ops.erf)
self._compareBoth(x, np.vectorize(math.erfc), math_ops.erfc)
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(z, np.sqrt, math_ops.sqrt, tol=1e-3)
self._compareBothSparse(x, np.tanh, math_ops.tanh)
self._compareBothSparse(y, np.sign, math_ops.sign)
self._compareBothSparse(x, np.vectorize(math.erf), math_ops.erf, tol=1e-3)
@test_util.run_deprecated_v1
def testBFloat16Basic(self):
def compute_f32(np_func):
"""Decorator to compute Numpy function with float32 math."""
def f(x):
y = np_func(x.astype(np.float32))
return y.astype(x.dtype)
return f
bfloat16 = dtypes_lib.bfloat16.as_numpy_dtype
x = np.arange(-6, 6,
2).reshape(1, 3, 2).astype(bfloat16)
w = x - x.min() + 1.1 # all greater than 1
y = (x + .5).astype(bfloat16) # no zero
z = (x + 15.5).astype(bfloat16) # all positive
k = np.arange(-0.90, 0.90, 0.05).astype(bfloat16) # between -1 and 1
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(y, compute_f32(self._inv), math_ops.reciprocal)
self._compareCpu(x, np.round, math_ops.round)
self._compareCpu(x, np.exp, math_ops.exp)
self._compareCpu(x, np.expm1, math_ops.expm1)
self._compareCpu(z, compute_f32(np.log), math_ops.log)
self._compareCpu(z, compute_f32(np.log1p), math_ops.log1p)
self._compareBoth(y, np.sign, math_ops.sign)
self._compareCpu(z, self._rsqrt, math_ops.rsqrt)
self._compareCpu(x, np.square, math_ops.square)
self._compareBoth(x, compute_f32(np.sin), math_ops.sin)
self._compareBoth(x, compute_f32(np.cos), math_ops.cos)
self._compareBoth(x, compute_f32(np.tan), math_ops.tan)
self._compareBoth(x, compute_f32(np.sinh), math_ops.sinh)
self._compareBoth(x, compute_f32(np.cosh), math_ops.cosh)
self._compareBoth(x, compute_f32(np.tanh), math_ops.tanh)
self._compareBoth(k, compute_f32(np.arcsin), math_ops.asin)
self._compareBoth(k, compute_f32(np.arccos), math_ops.acos)
self._compareBoth(x, compute_f32(np.arctan), math_ops.atan)
self._compareBoth(x, compute_f32(np.arcsinh), math_ops.asinh)
self._compareBoth(w, compute_f32(np.arccosh), math_ops.acosh)
self._compareBoth(k, compute_f32(np.arctanh), math_ops.atanh,
grad_tol=1e-2)
self._compareBoth(x, compute_f32(np.vectorize(math.erf)), math_ops.erf)
self._compareBoth(x, compute_f32(np.vectorize(math.erfc)), math_ops.erfc)
self._compareBoth(x, compute_f32(np.square), math_ops.square)
def testInt8Basic(self):
x = np.arange(-6, 6, 2).reshape(1, 3, 2).astype(np.int8)
self._compareCpu(x, np.abs, math_ops.abs)
self._compareCpu(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(x, np.sign, math_ops.sign)
def testUInt8Basic(self):
x = np.arange(6).reshape(1, 3, 2).astype(np.uint8)
self._compareBoth(x, np.square, math_ops.square)
def testInt16Basic(self):
x = np.arange(-6, 6, 2).reshape(1, 3, 2).astype(np.int16)
self._compareCpu(x, np.abs, math_ops.abs)
self._compareCpu(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(x, np.sign, math_ops.sign)
def testUInt16Basic(self):
x = np.arange(6).reshape(1, 3, 2).astype(np.uint16)
self._compareBoth(x, np.square, math_ops.square)
def testInt32Basic(self):
x = np.arange(-6, 6, 2).reshape(1, 3, 2).astype(np.int32)
self._compareCpu(x, np.abs, math_ops.abs)
self._compareCpu(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(x, np.square, math_ops.square)
self._compareCpu(x, np.sign, math_ops.sign)
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(x, np.sign, math_ops.sign)
def testUInt32Basic(self):
x = np.arange(6).reshape(1, 3, 2).astype(np.uint32)
self._compareBoth(x, np.square, math_ops.square)
def testInt64Basic(self):
x = np.arange(-6 << 40, 6 << 40, 2 << 40).reshape(1, 3, 2).astype(np.int64)
self._compareCpu(x, np.abs, math_ops.abs)
self._compareCpu(x, np.abs, _ABS)
self._compareCpu(x, np.negative, math_ops.negative)
self._compareCpu(x, np.negative, _NEG)
self._compareCpu(x, np.sign, math_ops.sign)
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.sign, math_ops.sign)
def testInt64Square(self):
x = np.arange(-6 << 20, 6 << 20, 2 << 20).reshape(1, 3, 2).astype(np.int64)
self._compareCpu(x, np.square, math_ops.square)
self._compareBothSparse(x, np.square, math_ops.square)
def testUInt64Basic(self):
x = np.arange(6).reshape(1, 3, 2).astype(np.uint64)
self._compareBoth(x, np.square, math_ops.square)
@test_util.run_deprecated_v1
def testComplex64Basic(self):
x = (1 + 1j) * np.arange(-3, 3).reshape(1, 3, 2).astype(np.complex64)
y = x + (0.5 + 0.5j) # no zeros
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(y, self._inv, math_ops.reciprocal)
self._compareCpu(x, np.square, math_ops.square)
self._compareCpu(y, np.sqrt, math_ops.sqrt)
self._compareCpu(y, self._rsqrt, math_ops.rsqrt)
self._compareBoth(x, np.exp, math_ops.exp)
self._compareCpu(x, np.expm1, math_ops.expm1)
self._compareCpu(y, np.log, math_ops.log)
self._compareCpu(y, np.log1p, math_ops.log1p)
self._compareCpu(x, np.sinh, math_ops.sinh)
self._compareCpu(x, np.cosh, math_ops.cosh)
self._compareCpu(x, np.tanh, math_ops.tanh)
self._compareCpu(x, np.arcsin, math_ops.asin)
self._compareCpu(x, np.arctan, math_ops.atan)
# Complex64 versions of asinh() and acosh() in libstdc++ only have 6 digits
# of precision.
# Small gradient values + low precision --> High relative error
self._compareCpu(y, np.arcsinh, math_ops.asinh, grad_rtol=1e-2)
self._compareCpu(y, np.arccosh, math_ops.acosh, grad_rtol=1e-2)
self._compareCpu(y, np.arctanh, math_ops.atanh)
self._compareCpu(x, self._sigmoid, math_ops.sigmoid)
self._compareCpu(x, np.sin, math_ops.sin)
self._compareCpu(x, np.cos, math_ops.cos)
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(x, np.sqrt, math_ops.sqrt, 1e-3)
self._compareBothSparse(x, np.tanh, math_ops.tanh)
# Numpy uses an incorrect definition of sign; use the right one instead.
def complex_sign(x):
return x / np.abs(x)
self._compareBoth(y, complex_sign, math_ops.sign)
self._compareBothSparse(y, complex_sign, math_ops.sign)
@test_util.run_deprecated_v1
def testComplex128Basic(self):
x = (1 + 1j) * np.arange(-3, 3).reshape(1, 3, 2).astype(np.complex128)
y = x + (0.5 + 0.5j) # no zeros
self._compareBoth(x, np.abs, math_ops.abs)
self._compareBoth(x, np.abs, _ABS)
self._compareBoth(x, np.negative, math_ops.negative)
self._compareBoth(x, np.negative, _NEG)
self._compareBoth(y, self._inv, math_ops.reciprocal)
self._compareCpu(x, np.square, math_ops.square)
self._compareCpu(y, np.sqrt, math_ops.sqrt)
self._compareCpu(y, self._rsqrt, math_ops.rsqrt)
self._compareBoth(x, np.exp, math_ops.exp)
self._compareCpu(x, np.expm1, math_ops.expm1)
self._compareCpu(y, np.log, math_ops.log)
self._compareCpu(y, np.log1p, math_ops.log1p)
self._compareCpu(x, np.sinh, math_ops.sinh)
self._compareCpu(x, np.cosh, math_ops.cosh)
self._compareCpu(x, np.tanh, math_ops.tanh)
self._compareCpu(y, np.arcsinh, math_ops.asinh)
self._compareCpu(y, np.arccosh, math_ops.acosh)
self._compareCpu(y, np.arctanh, math_ops.atanh)
self._compareCpu(x, self._sigmoid, math_ops.sigmoid)
self._compareCpu(x, np.sin, math_ops.sin)
self._compareCpu(x, np.cos, math_ops.cos)
self._compareCpu(x, np.arcsin, math_ops.asin)
self._compareCpu(x, np.arctan, math_ops.atan)
self._compareBothSparse(x, np.abs, math_ops.abs)
self._compareBothSparse(x, np.negative, math_ops.negative)
self._compareBothSparse(x, np.square, math_ops.square)
self._compareBothSparse(x, np.sqrt, math_ops.sqrt, 1e-3)
self._compareBothSparse(x, np.tanh, math_ops.tanh)
# Numpy uses an incorrect definition of sign; use the right one instead.
def complex_sign(x):
return x / np.abs(x)
self._compareBoth(y, complex_sign, math_ops.sign)
self._compareBothSparse(y, complex_sign, math_ops.sign)
@test_util.run_deprecated_v1
def testGradGrad(self):
np.random.seed(7)
shape = (5,)
dtype_tols = [(np.float32, 5e-4), (np.float64, 1e-6), (np.complex64, 5e-4),
(np.complex128, 1e-6)]
op_range = [
(gen_math_ops.reciprocal_grad, [-2, 2]),
(gen_math_ops.rsqrt_grad, [0.1, 3]),
(gen_math_ops.sigmoid_grad, [-2, 2]),
(gen_math_ops.sqrt_grad, [0.1, 3]),
(gen_math_ops.tanh_grad, [-2, 2]),
]
def rand(dtype, real_range):
x = np.random.uniform(
real_range[0], real_range[1], size=shape[0]).astype(dtype)
if dtype in (np.complex64, np.complex128):
x += 1j * np.random.uniform(-2, 2, size=shape[0]).astype(dtype)
return x
for op, real_range in op_range:
with self.cached_session():
for dtype, tol in dtype_tols:
x = constant_op.constant(rand(dtype, real_range))
y = constant_op.constant(rand(dtype, real_range))
z = op(x, y)
grads = gradient_checker.compute_gradient(
[x, y], [shape, shape],
z,
shape,
x_init_value=[rand(dtype, real_range),
rand(dtype, real_range)])
if isinstance(grads, tuple):
grads = [grads]
for analytical, numerical in grads:
self.assertAllClose(analytical, numerical, rtol=tol, atol=tol)
@test_util.run_in_graph_and_eager_modes
def testComplexAbsGradGrad(self):
def f(x):
real = math_ops.cos(x)
imag = ops.convert_to_tensor(1.)
return math_ops.abs(math_ops.complex(real, imag))
def g(x):
with backprop.GradientTape() as t:
t.watch(x)
y = f(x)
return t.gradient(y, x)
err = gradient_checker_v2.max_error(
*gradient_checker_v2.compute_gradient(g, [ops.convert_to_tensor(2.0)]))
self.assertLess(err, 1e-3)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,69 @@
# Copyright 2015 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 division with division imported from __future__.
This file should be exactly the same as division_past_test.py except
for the __future__ division line.
"""
import numpy as np
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import ops
from tensorflow.python.platform import test
class DivisionTestCase(test.TestCase):
def testDivision(self):
"""Test all the different ways to divide."""
values = [1, 2, 7, 11]
functions = (lambda x: x), constant_op.constant
# TODO(irving): Test int8, int16 once we support casts for those.
dtypes = np.int32, np.int64, np.float32, np.float64
tensors = []
checks = []
def check(x, y):
x = ops.convert_to_tensor(x)
y = ops.convert_to_tensor(y)
tensors.append((x, y))
def f(x, y):
self.assertEqual(x.dtype, y.dtype)
self.assertAllClose(x, y)
checks.append(f)
with self.cached_session() as sess:
for dtype in dtypes:
for x in map(dtype, values):
for y in map(dtype, values):
for fx in functions:
for fy in functions:
tf_x = fx(x)
tf_y = fy(y)
div = x / y
tf_div = tf_x / tf_y
check(div, tf_div)
floordiv = x // y
tf_floordiv = tf_x // tf_y
check(floordiv, tf_floordiv)
# Do only one sess.run for speed
for f, (x, y) in zip(checks, self.evaluate(tensors)):
f(x, y)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,72 @@
# Copyright 2015 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 division with division imported from __future__.
This file should be exactly the same as division_future_test.py except
for the __future__ division line.
"""
# from __future__ import division # Intentionally skip this import
import numpy as np
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import ops
from tensorflow.python.platform import test
class DivisionTestCase(test.TestCase):
def testDivision(self):
"""Test all the different ways to divide."""
values = [1, 2, 7, 11]
functions = (lambda x: x), constant_op.constant
dtypes = np.int8, np.int16, np.int32, np.int64, np.float32, np.float64
tensors = []
checks = []
def check(x, y):
x = ops.convert_to_tensor(x)
y = ops.convert_to_tensor(y)
tensors.append((x, y))
def f(x, y):
self.assertEqual(x.dtype, y.dtype)
self.assertAllClose(x, y)
checks.append(f)
with self.cached_session() as sess:
for dtype in dtypes:
for x in map(dtype, values):
for y in map(dtype, values):
for fx in functions:
for fy in functions:
tf_x = fx(x)
tf_y = fy(y)
div = x / y
tf_div = tf_x / tf_y
# In NumPy 1.23, np.int16(x) / np.int16(y) now has np.float64
# type, which disagrees with TF.
if x.dtype not in (np.int8, np.int16):
check(div, tf_div)
floordiv = x // y
tf_floordiv = tf_x // tf_y
check(floordiv, tf_floordiv)
# Do only one sess.run for speed
for f, (x, y) in zip(checks, self.evaluate(tensors)):
f(x, y)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,78 @@
# Copyright 2015 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 PrecisionOp."""
import numpy as np
from tensorflow.python.framework import constant_op
from tensorflow.python.ops import nn_ops
from tensorflow.python.platform import test
class InTopKTest(test.TestCase):
def _validateInTopK(self, predictions, target, k, expected):
np_ans = np.array(expected, np.bool_)
with self.cached_session():
precision = nn_ops.in_top_k(predictions, target, k)
out = self.evaluate(precision)
self.assertAllClose(np_ans, out)
self.assertShapeEqual(np_ans, precision)
def testInTop1(self):
predictions = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.2, 0.3, 0.4]]
target = [3, 2]
self._validateInTopK(predictions, target, 1, [True, False])
def testInTop2(self):
predictions = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.2, 0.3, 0.4]]
target = [2, 2]
self._validateInTopK(predictions, target, 2, [False, True])
def testInTop2Tie(self):
# Class 2 and 3 tie for 2nd, so both are considered in top 2.
predictions = [[0.1, 0.3, 0.2, 0.2], [0.1, 0.3, 0.2, 0.2]]
target = [2, 3]
self._validateInTopK(predictions, target, 2, [True, True])
def testInTop2_int64Target(self):
predictions = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.2, 0.3, 0.4]]
target = np.asarray([0, 2]).astype(np.int64)
self._validateInTopK(predictions, target, 2, [False, True])
def testInTopNan(self):
predictions = [[0.1, float("nan"), 0.2, 0.4], [0.1, 0.2, 0.3, float("inf")]]
target = [1, 3]
self._validateInTopK(predictions, target, 2, [False, False])
def testBadTarget(self):
predictions = [[0.1, 0.3, 0.2, 0.2], [0.1, 0.3, 0.2, 0.2]]
target = [2, 4] # must return False for invalid target
self._validateInTopK(predictions, target, 2, [True, False])
def testEmpty(self):
predictions = np.empty([0, 5])
target = np.empty([0], np.int32)
self._validateInTopK(predictions, target, 2, [])
def testTensorK(self):
predictions = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.2, 0.3, 0.4]]
target = [0, 2]
k = constant_op.constant(3)
self._validateInTopK(predictions, target, k, [False, True])
if __name__ == "__main__":
test.main()
@@ -0,0 +1,380 @@
# Copyright 2015 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 tensorflow.ops.math_ops.matmul."""
import operator
import numpy as np
from tensorflow.python import tf2
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test as test_lib
# TODO(yangzihao): Currently matmul autotuning is disabled by default. Use
# os.environ["TF_MATMUL_AUTOTUNE_ENABLE"] = "1" to enable it.
@test_util.with_eager_op_as_function
class MatMulMixedType(test_lib.TestCase):
"""Simple test for tf.matmul where Tout is different from T."""
def testBatchMatMulV3OutputType(self):
# TODO(shivaniagrawal): uint8 is not supported for mixed matmul type in XLA.
for (a_dtype, b_dtype) in [(np.int8, np.int8), (np.uint8, np.uint8)]:
a = np.array([[1, 2], [3, 4]], dtype=a_dtype)
b = np.array([[1, 2], [3, 4]], dtype=b_dtype)
c = math_ops.batch_mat_mul_v3(a, b, adj_y=True, Tout=np.int32)
self.assertAllEqual((2, 2), c.shape)
self.assertAllEqual([[5, 11], [11, 25]], c)
def testBatchMatMulV3MixedPrec(self):
# TODO(shivaniagrawal): uint8 is not supported for mixed matmul type in XLA.
np_bf16 = dtypes.bfloat16.as_numpy_dtype
a = np.array([[1, 2], [3, 4]], dtype=np.int8)
b = np.array([[1, 2], [3, 4]], dtype=np_bf16)
c = math_ops.batch_mat_mul_v3(a, b, adj_y=True, Tout=np_bf16)
self.assertAllEqual((2, 2), c.shape)
self.assertAllEqual([[5, 11], [11, 25]], c)
@test_util.with_eager_op_as_function
class MatVecTest(test_lib.TestCase):
"""Simple test for matvec, which is sugar on top of matmul."""
def testTwoByTwoCase(self):
a = np.array([[1, 2], [3, 4]])
b = np.array([5, 6])
c = math_ops.matvec(a, b)
self.assertAllEqual((2,), c.shape)
self.assertAllEqual([5 + 2 * 6, 3 * 5 + 4 * 6], c)
def testEmpty(self):
full = np.array([[1., 2.], [3., 4.], [5., 6.]])
empty = np.empty([3, 0])
self.assertShapeEqual(
np.matmul(full.T, empty), math_ops.matmul(full, empty, adjoint_a=True))
self.assertShapeEqual(
np.matmul(empty.T, full), math_ops.matmul(empty, full, adjoint_a=True))
def _AddTest(test, op_name, testcase_name, fn):
test_name = "_".join(["test", op_name, testcase_name])
if hasattr(test, test_name):
raise RuntimeError("Test %s defined more than once" % test_name)
setattr(test, test_name, test_util.deprecated_graph_mode_only(fn))
def _GetTransposedMatrices(x, x_name, kwargs):
if kwargs["transpose_" + x_name] is True:
return x.T
elif kwargs["adjoint_" + x_name] is True:
return np.conj(x.T)
else:
return x
@test_util.with_eager_op_as_function
class MatMulTest(test_lib.TestCase):
pass # Filled in below
def _GetMatMulTest(a_np_, b_np_, use_static_shape_, **kwargs_):
@test_util.run_without_tensor_float_32("Tests matmul")
def Test(self):
np_val = np.matrix(a_np_) * np.matrix(b_np_)
use_gpu = True
if a_np_.dtype is np.float16 and (
not test_util.GpuSupportsHalfMatMulAndConv()):
use_gpu = False
print("Built without fp16 matmul support for Cuda, running test on CPU.")
# Transpose and possibly conjugate a_np_ and b_np_ according to the
# attributes such that tf.matmul(effective_a_np, effective_b_np, **kwargs)
# results in a valid matrix multiplication and produces the same result as
# np.matrix(a_np_) * np.matrix(b_np_)
effective_a_np = _GetTransposedMatrices(a_np_, "a", kwargs_)
effective_b_np = _GetTransposedMatrices(b_np_, "b", kwargs_)
with self.cached_session() as sess, test_util.device(use_gpu):
if use_static_shape_:
a = constant_op.constant(effective_a_np)
b = constant_op.constant(effective_b_np)
res = math_ops.matmul(a, b, **kwargs_)
tf_val = self.evaluate(res)
else:
a = array_ops.placeholder(a_np_.dtype)
b = array_ops.placeholder(b_np_.dtype)
res = math_ops.matmul(a, b, **kwargs_)
tf_val = sess.run(res, feed_dict={a: effective_a_np, b: effective_b_np})
self.assertAllCloseAccordingToType(
tf_val,
np_val,
float_rtol=3e-5,
float_atol=3e-5,
half_rtol=0.2,
half_atol=0.2)
return Test
@test_util.with_eager_op_as_function
class MatMulGradientTest(test_lib.TestCase):
pass # Will be filled in below.
def _GetMatMulGradientTest(a_np_, b_np_, use_static_shape_, **kwargs_):
@test_util.run_without_tensor_float_32("Tests matmul")
def Test(self):
if not use_static_shape_ or a_np_.dtype in (np.int32, np.int64, np.float16):
self.skipTest("Skipping infeasible gradient test.")
if (a_np_.dtype == dtypes.bfloat16.as_numpy_dtype and
not test_util.is_gpu_available()):
self.skipTest("The bfloat16 tests might fail on CPU")
# Transpose and possibly conjugate a_np_ and b_np_ according to the
# attributes such that tf.matmul(effective_a_np, effective_b_np, **kwargs)
# results in a valid matrix multiplication and produces the same result as
# np.matrix(a_np_) * np.matrix(b_np_)
effective_a_np = _GetTransposedMatrices(a_np_, "a", kwargs_)
effective_b_np = _GetTransposedMatrices(b_np_, "b", kwargs_)
# np.finfo doesn't support bfloat16. So, we manually compute the eps which
# defines the difference between 1.0 and the next smallest representable
# float larger than 1.0. For bfloat16, the difference is 1/128.
if a_np_.dtype == dtypes.bfloat16.as_numpy_dtype:
epsilon = 0.0078125
else:
epsilon = np.finfo(a_np_.dtype).eps
delta = epsilon**(1.0 / 3.0)
tol = 20 * delta
with self.session():
theoretical, numerical = gradient_checker_v2.compute_gradient(
lambda x: math_ops.matmul(x, effective_b_np, **kwargs_),
[effective_a_np],
delta=delta)
self.assertAllClose(theoretical, numerical, rtol=tol, atol=tol)
theoretical, numerical = gradient_checker_v2.compute_gradient(
lambda x: math_ops.matmul(effective_a_np, x, **kwargs_),
[effective_b_np],
delta=delta)
self.assertAllClose(theoretical, numerical, rtol=tol, atol=tol)
return Test
try:
# @ operator supported since python 3.5.
infix_matmul = operator.matmul
except AttributeError:
# For earlier versions of python, emulate regular behavior.
# Useful to build and test for 3.5+ on earlier versions.
def infix_matmul(x, y): # pylint: disable=invalid-name
try:
r = type(x).__matmul__(x, y)
except AttributeError:
r = NotImplemented
if r is NotImplemented and type(x) is not type(y):
try:
r = type(y).__rmatmul__(y, x)
except AttributeError:
r = NotImplemented
if r is NotImplemented:
raise TypeError("unsupported operand type(s) for @: '{}' and '{}'"
.format(type(x).__name__, type(y).__name__))
return r
@test_util.with_eager_op_as_function
class MatMulInfixOperatorTest(test_lib.TestCase):
def testMismatchedShape(self):
# The Python-level rank check now raises ValueError with a descriptive
# message before hitting the C++ kernel (which used to raise
# InvalidArgumentError). We accept both the old C++ patterns (for
# graph-mode / non-eager paths that bypass the Python guard) and the new
# ValueError message so the test stays green across all execution modes.
with self.assertRaisesRegex(
(ValueError, Exception),
(
r"(must be at least rank 2"
r"|In\[0\] and In\[1\] has different ndims"
r"|In\[0\] ndims must be >= 2"
r"|Shape must be rank 2 but is rank 1)"
),
):
infix_matmul(
ops.convert_to_tensor([10.0, 20.0, 30.0]),
ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0]]))
def testMismatchedShapeErrorMessage(self):
"""Verifies that the error message for rank < 2 inputs is descriptive."""
# --- `a` is rank-1 ---
with self.assertRaisesRegex(
ValueError,
r"Argument `a` passed to `tf.linalg.matmul` must be at least rank 2",
):
math_ops.matmul(
ops.convert_to_tensor([1.0, 2.0, 3.0]),
ops.convert_to_tensor([[4.0, 5.0], [6.0, 7.0], [8.0, 9.0]]),
)
# The message should show the actual shape and rank.
try:
math_ops.matmul(
ops.convert_to_tensor([1.0, 2.0]),
ops.convert_to_tensor([[3.0, 4.0], [5.0, 6.0]]),
)
except ValueError as e:
msg = str(e)
self.assertIn(
"(2,)", msg, "Error message should include the actual shape (2,)"
)
self.assertIn("rank 1", msg, "Error message should mention 'rank 1'")
# The message should suggest tf.expand_dims and tf.reshape for `a`.
try:
math_ops.matmul(
ops.convert_to_tensor([1.0, 2.0]),
ops.convert_to_tensor([[3.0, 4.0], [5.0, 6.0]]),
)
except ValueError as e:
msg = str(e)
self.assertIn(
"tf.expand_dims",
msg,
"Error should suggest tf.expand_dims as a remediation",
)
self.assertIn(
"tf.reshape", msg, "Error should suggest tf.reshape as a remediation"
)
# --- `b` is rank-1 ---
with self.assertRaisesRegex(
ValueError,
r"Argument `b` passed to `tf.linalg.matmul` must be at least rank 2",
):
math_ops.matmul(
ops.convert_to_tensor([[1.0, 2.0], [3.0, 4.0]]),
ops.convert_to_tensor([5.0, 6.0]),
)
# The message for `b` should also suggest tf.expand_dims, tf.reshape, and
# tf.linalg.matvec.
try:
math_ops.matmul(
ops.convert_to_tensor([[1.0, 2.0], [3.0, 4.0]]),
ops.convert_to_tensor([5.0, 6.0]),
)
except ValueError as e:
msg = str(e)
self.assertIn(
"tf.expand_dims", msg, "Error for `b` should suggest tf.expand_dims"
)
self.assertIn(
"tf.reshape", msg, "Error for `b` should suggest tf.reshape"
)
self.assertIn(
"tf.linalg.matvec",
msg,
"Error for `b` should suggest tf.linalg.matvec",
)
def testMismatchedDimensions(self):
with self.assertRaisesRegex(
Exception, r"(Matrix size-incompatible: In\[0\]: .* In\[1\]|"
r"Dimensions must be equal)"):
infix_matmul(
ops.convert_to_tensor([[10.0, 20.0, 30.0]]),
ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0]]))
@test_util.run_v1_only("Tensor.op is generally not applicable in TF 2")
def testInfixMatmulIsTfMatmul(self):
a = ops.convert_to_tensor([[10.0, 20.0, 30.0]])
b = ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0], [80.0, 90.0]])
c = infix_matmul(a, b)
self.assertEqual(c.op.type, "MatMul")
def testInfixMatmulDoesDotProduct(self):
a = ops.convert_to_tensor([[10.0, 20.0, 30.0]])
b = ops.convert_to_tensor([[40.0, 50.0], [60.0, 70.0], [80.0, 90.0]])
c = infix_matmul(a, b)
d = math_ops.matmul(a, b)
self.assertAllEqual(c, d)
if __name__ == "__main__":
sizes = [1, 3, 5]
trans_options = [[False, False], [True, False], [False, True]]
dtypes_to_test = [
np.int32, np.int64, np.float16, np.float32, np.float64, np.complex64,
np.complex128, dtypes.bfloat16.as_numpy_dtype
]
# TF2 does not support placeholders under eager so we skip it
for use_static_shape in set([True, tf2.enabled()]):
for dtype in dtypes_to_test:
for m in sizes:
for n in sizes:
for k in sizes:
# Construct compatible random matrices a_np of size [m, k] and b_np
# of size [k, n].
# Add seed value to make the tests for bfloat16 stable.
if dtype == dtypes.bfloat16.as_numpy_dtype:
np.random.seed(12)
a_np = np.random.normal(-5, 5, m * k).astype(dtype).reshape([m, k])
if dtype in (np.complex64, np.complex128):
a_np.imag = np.random.normal(-5, 5,
m * k).astype(dtype).reshape([m, k])
b_np = np.random.normal(-5, 5, k * n).astype(dtype).reshape([k, n])
if dtype in (np.complex64, np.complex128):
b_np.imag = np.random.normal(-5, 5,
k * n).astype(dtype).reshape([k, n])
for adjoint_a, transpose_a in trans_options:
for adjoint_b, transpose_b in trans_options:
name = "%s_%s_%s_%s_%s_%s_%s_%s_%s" % (
use_static_shape, dtype.__name__, m, n, k, adjoint_a,
transpose_a, adjoint_b, transpose_b)
_AddTest(MatMulTest, "MatMulTest", name,
_GetMatMulTest(
a_np,
b_np,
use_static_shape,
adjoint_a=adjoint_a,
transpose_a=transpose_a,
adjoint_b=adjoint_b,
transpose_b=transpose_b))
_AddTest(MatMulGradientTest, "MatMulGradientTest", name,
_GetMatMulGradientTest(
a_np,
b_np,
use_static_shape,
adjoint_a=adjoint_a,
transpose_a=transpose_a,
adjoint_b=adjoint_b,
transpose_b=transpose_b))
test_lib.main()
@@ -0,0 +1,102 @@
# Copyright 2015 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.
# ==============================================================================
"""Simple benchmarks for reductions and their gradients."""
import time
import numpy as np
from tensorflow.core.protobuf import config_pb2
from tensorflow.python.client import session
from tensorflow.python.eager import backprop
from tensorflow.python.eager import context
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import ops
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradients_impl
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class ReduceBenchmarks(test.Benchmark):
"""Benchmarks for reductions."""
def _run(self, func, num_iters):
# call func to maybe warm up the GPU
func()
start = time.time()
for _ in range(num_iters):
func()
end = time.time()
mean_us = (end - start) * 1e6 / num_iters
self.report_benchmark(
iters=num_iters,
wall_time=mean_us,
extras={"examples_per_sec": num_iters / (end - start)})
def benchmark_reduce_sum_grad_eager(self):
with context.eager_mode():
tensor = array_ops.zeros([100, 1000])
def fn():
backprop.gradients_function(math_ops.reduce_sum, [0])(tensor)
self._run(fn, 10000)
def benchmark_reduce_sum_grad_eager_cpu(self):
with context.eager_mode(), ops.device("/cpu:0"):
tensor = array_ops.zeros([100, 1000])
def fn():
backprop.gradients_function(math_ops.reduce_sum, [0])(tensor)
self._run(fn, 10000)
def benchmark_reduce_sum_grad_graph(self):
config = config_pb2.ConfigProto(
graph_options=config_pb2.GraphOptions(
optimizer_options=config_pb2.OptimizerOptions(
opt_level=config_pb2.OptimizerOptions.L0)))
with ops.Graph().as_default(), session.Session(config=config) as sess:
tensor = constant_op.constant(np.zeros([100, 1000], dtype=np.float32))
reduction = math_ops.reduce_sum(tensor)
grad, = gradients_impl.gradients(reduction, tensor)
def fn():
self.evaluate(grad.op)
self._run(fn, 10000)
def benchmark_reduce_sum_grad_graph_cpu(self):
config = config_pb2.ConfigProto(
graph_options=config_pb2.GraphOptions(
optimizer_options=config_pb2.OptimizerOptions(
opt_level=config_pb2.OptimizerOptions.L0)))
with ops.Graph().as_default(), session.Session(config=config) as sess:
with ops.device("/cpu:0"):
tensor = constant_op.constant(np.zeros([100, 1000], dtype=np.float32))
reduction = math_ops.reduce_sum(tensor)
grad, = gradients_impl.gradients(reduction, tensor)
def fn():
self.evaluate(grad.op)
self._run(fn, 10000)
if __name__ == "__main__":
test.main()
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,221 @@
# Copyright 2015 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.
# ==============================================================================
"""Functional tests for reduction ops."""
import numpy as np
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import ops
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test
class BaseReductionTest(test.TestCase):
def _tf_reduce(self, x, reduction_axes, keepdims):
raise NotImplementedError()
class BigReductionTest(BaseReductionTest):
"""Test reductions for sum and boolean all over a wide range of shapes."""
def _tf_reduce_max(self, x, reduction_axes, keepdims):
return math_ops.reduce_max(x, reduction_axes, keepdims)
def _tf_reduce_all(self, x, reduction_axes, keepdims):
return math_ops.reduce_all(x, reduction_axes, keepdims)
def _tf_reduce_mean(self, x, reduction_axes, keepdims):
return math_ops.reduce_mean(x, reduction_axes, keepdims)
def _tf_reduce_sum(self, x, reduction_axes, keepdims):
return math_ops.reduce_sum(x, reduction_axes, keepdims)
@test_util.run_deprecated_v1
def testFloat32Bfloat16Mean(self):
arrfp32 = np.random.normal(size=[4105, 4105]).astype(np.float32)
arrbf16 = arrfp32.astype(dtypes.bfloat16.as_numpy_dtype)
with self.session(graph=ops.Graph(), use_gpu=False) as sess:
arrfp32_placeholder = array_ops.placeholder(
dtype=np.float32, shape=(4105, 4105)
)
arrbf16_placeholder = array_ops.placeholder(
dtype=dtypes.bfloat16.as_numpy_dtype, shape=(4105, 4105)
)
tf_full_mean_fp32 = self._tf_reduce_mean(
arrfp32_placeholder, [0, 1], False
)
tf_full_mean_bf16 = self._tf_reduce_mean(
arrbf16_placeholder, [0, 1], False
)
tf_full_mean_bf16_cast = math_ops.cast(tf_full_mean_bf16, dtypes.float32)
tf_out_full_f, tf_out_full_b = sess.run(
[tf_full_mean_fp32, tf_full_mean_bf16_cast],
{arrfp32_placeholder: arrfp32, arrbf16_placeholder: arrbf16},
)
self.assertAllClose(tf_out_full_f, tf_out_full_b)
@test_util.run_deprecated_v1
def testFloat32Sum(self):
# make sure we test all possible kernel invocations
# logic is the same for all ops, test just float32 for brevity
arr_ = np.ones([4097, 4097], dtype=np.float32)
for size_x in [
1, 2, 3, 4, 16, 17, 32, 33, 64, 65, 128, 131, 256, 263, 1024, 1025,
4096, 4097
]:
for size_y in [
1, 2, 3, 4, 16, 17, 32, 33, 64, 65, 128, 131, 256, 263, 1024, 1025,
4096, 4097
]:
arr = arr_[0:size_x, 0:size_y]
col_sum = np.ones([size_y], dtype=np.float32) * size_x
row_sum = np.ones([size_x], dtype=np.float32) * size_y
full_sum = np.ones([], dtype=np.float32) * size_x * size_y
with self.session(graph=ops.Graph(), use_gpu=True) as sess:
arr_placeholder = array_ops.placeholder(dtype=np.float32,
shape=(size_x, size_y))
tf_row_sum = self._tf_reduce_sum(arr_placeholder, 1, False)
tf_col_sum = self._tf_reduce_sum(arr_placeholder, 0, False)
tf_full_sum = self._tf_reduce_sum(arr_placeholder, [0, 1], False)
tf_out_row, tf_out_col, tf_out_full = sess.run(
[tf_row_sum, tf_col_sum, tf_full_sum], {arr_placeholder: arr})
self.assertAllClose(col_sum, tf_out_col)
self.assertAllClose(row_sum, tf_out_row)
self.assertAllClose(full_sum, tf_out_full)
arr_ = np.ones([130, 130, 130], dtype=np.float32)
for size_x in range(1, 130, 13):
for size_y in range(1, 130, 13):
for size_z in range(1, 130, 13):
arr = arr_[0:size_x, 0:size_y, 0:size_z]
sum_y = np.ones([size_x, size_z], dtype=np.float32)
sum_xz = np.ones([size_y], dtype=np.float32)
with self.session(graph=ops.Graph(), use_gpu=True) as sess:
arr_placeholder = array_ops.placeholder(
dtype=np.float32, shape=(size_x, size_y, size_z))
tf_sum_xz = self._tf_reduce_mean(arr_placeholder, [0, 2], False)
tf_sum_y = self._tf_reduce_mean(arr_placeholder, 1, False)
tf_out_sum_xz, tf_out_sum_y = sess.run([tf_sum_xz, tf_sum_y],
{arr_placeholder: arr})
self.assertAllClose(sum_y, tf_out_sum_y)
self.assertAllClose(sum_xz, tf_out_sum_xz)
@test_util.run_deprecated_v1
def testFloat32Max(self):
# make sure we test all possible kernel invocations
# logic is the same for all ops, test just float32 for brevity
arr_ = np.random.uniform(
low=-3, high=-1, size=[4105, 4105]).astype(np.float32)
for size_x in [
1, 2, 3, 4, 16, 17, 32, 33, 64, 65, 128, 131, 256, 263, 1024, 1025,
4096, 4097
]:
for size_y in [
1, 2, 3, 4, 16, 17, 32, 33, 64, 65, 128, 131, 256, 263, 1024, 1025,
4096, 4097
]:
arr = arr_[0:size_x, 0:size_y]
col_max = np.max(arr, axis=0)
row_max = np.max(arr, axis=1)
full_max = np.max(col_max)
with self.session(graph=ops.Graph(), use_gpu=True) as sess:
arr_placeholder = array_ops.placeholder(dtype=np.float32,
shape=(size_x, size_y))
tf_row_max = self._tf_reduce_max(arr_placeholder, 1, False)
tf_col_max = self._tf_reduce_max(arr_placeholder, 0, False)
tf_full_max = self._tf_reduce_max(arr_placeholder, [0, 1], False)
tf_out_row, tf_out_col, tf_out_full = sess.run(
[tf_row_max, tf_col_max, tf_full_max], {arr_placeholder: arr})
self.assertAllClose(col_max, tf_out_col)
self.assertAllClose(row_max, tf_out_row)
self.assertAllClose(full_max, tf_out_full)
arr_ = np.random.uniform(
low=-3, high=-1, size=[130, 130, 130]).astype(np.float32)
for size_x in range(1, 130, 13):
for size_y in range(1, 130, 13):
for size_z in range(1, 130, 13):
arr = arr_[0:size_x, 0:size_y, 0:size_z]
sum_y = np.max(arr, axis=1)
sum_xz = np.max(arr, axis=(0, 2))
with self.session(graph=ops.Graph(), use_gpu=True) as sess:
arr_placeholder = array_ops.placeholder(
dtype=np.float32, shape=(size_x, size_y, size_z))
tf_sum_xz = self._tf_reduce_max(arr_placeholder, [0, 2], False)
tf_sum_y = self._tf_reduce_max(arr_placeholder, 1, False)
tf_out_sum_xz, tf_out_sum_y = sess.run(
[tf_sum_xz, tf_sum_y], {arr_placeholder: arr})
self.assertAllClose(sum_y, tf_out_sum_y)
self.assertAllClose(sum_xz, tf_out_sum_xz)
@test_util.run_deprecated_v1
def testBooleanAll(self):
# make sure we test all possible kernel invocations
# test operation where T(0) is not the identity
arr_ = np.ones([4097, 4097], dtype=np.bool_)
for size_x in [
1, 2, 3, 4, 16, 17, 32, 33, 64, 65, 128, 131, 256, 263, 1024, 1025,
4096, 4097
]:
for size_y in [
1, 2, 3, 4, 16, 17, 32, 33, 64, 65, 128, 131, 256, 263, 1024, 1025,
4096, 4097
]:
arr = arr_[0:size_x, 0:size_y]
col_sum = np.ones([size_y], dtype=np.bool_)
row_sum = np.ones([size_x], dtype=np.bool_)
full_sum = np.ones([1], dtype=np.bool_).reshape([])
with self.session(graph=ops.Graph(), use_gpu=True) as sess:
arr_placeholder = array_ops.placeholder(
dtype=np.bool_, shape=(size_x, size_y))
tf_row_sum = self._tf_reduce_all(arr_placeholder, 1, False)
tf_col_sum = self._tf_reduce_all(arr_placeholder, 0, False)
tf_full_sum = self._tf_reduce_all(arr_placeholder, [0, 1], False)
tf_out_row, tf_out_col, tf_out_full = sess.run(
[tf_row_sum, tf_col_sum, tf_full_sum], {arr_placeholder: arr})
self.assertAllClose(col_sum, tf_out_col)
self.assertAllClose(row_sum, tf_out_row)
self.assertAllClose(full_sum, tf_out_full)
arr_ = np.ones([130, 130, 130], dtype=np.bool_)
for size_x in range(1, 130, 13):
for size_y in range(1, 130, 13):
for size_z in range(1, 130, 13):
arr = arr_[0:size_x, 0:size_y, 0:size_z]
sum_y = np.ones([size_x, size_z], dtype=np.bool_)
sum_xz = np.ones([size_y], dtype=np.bool_)
with self.session(graph=ops.Graph(), use_gpu=True) as sess:
arr_placeholder = array_ops.placeholder(
dtype=np.bool_, shape=(size_x, size_y, size_z))
tf_sum_xz = self._tf_reduce_all(arr_placeholder, [0, 2], False)
tf_sum_y = self._tf_reduce_all(arr_placeholder, 1, False)
tf_out_sum_xz, tf_out_sum_y = sess.run(
[tf_sum_xz, tf_sum_y], {arr_placeholder: arr})
self.assertAllClose(sum_y, tf_out_sum_y)
self.assertAllClose(sum_xz, tf_out_sum_xz)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,139 @@
# Copyright 2021 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 deterministic functionality of segment reduction ops."""
from tensorflow.python.eager import backprop
from tensorflow.python.framework import config
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import indexed_slices
from tensorflow.python.framework import ops
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.ops import variables
from tensorflow.python.platform import test
class SegmentReductionDeterminismExceptionsTest(test.TestCase):
"""Test d9m-unimplemented exceptions from the segment reduction ops.
Test that tf.errors.UnimplementedError is thrown or not thrown, as
appropriate, by the GPU code-paths for segment reduction ops when
deterministic ops are enabled.
This test assumes that the base op test runs all the same test cases when
deterministic ops are not enabled and will therefore detect erroneous
exception throwing in those cases.
"""
def _input(self, data_type, segment_ids_type):
data = constant_op.constant([[1, 2, 3, 4], [5, 6, 7, 8]], dtype=data_type)
segment_ids = constant_op.constant([0, 1], dtype=segment_ids_type)
num_segments = 2
return data, segment_ids, num_segments
@test_util.run_cuda_only
def testSortedOps(self):
op_should_throw_for_float = {
math_ops.segment_max: False,
math_ops.segment_min: False,
math_ops.segment_prod: True,
math_ops.segment_sum: True,
}
for op, should_throw_for_float in op_should_throw_for_float.items():
for segment_ids_type in [dtypes.int32, dtypes.int64]:
for data_type in [dtypes.float16, dtypes.float32, dtypes.float64]:
with self.cached_session(force_gpu=True):
data, segment_ids, _ = self._input(data_type, segment_ids_type)
result = op(data, segment_ids)
self.evaluate(result)
_UNSORTED_ERROR_MESSAGE = ("Deterministic GPU implementation of unsorted " +
"segment reduction op not available.")
@test_util.run_cuda_only
@test_util.run_in_graph_and_eager_modes
def testUnsortedOps(self):
op_should_throw_for_float = {
math_ops.unsorted_segment_max: False,
math_ops.unsorted_segment_min: False,
math_ops.unsorted_segment_mean: True, # uses unsorted_segment_sum
math_ops.unsorted_segment_sqrt_n: True, # uses unsorted_segment_sum
math_ops.unsorted_segment_prod: True,
math_ops.unsorted_segment_sum: True,
}
with self.session(force_gpu=True):
for op, should_throw_for_float in op_should_throw_for_float.items():
for segment_ids_type in [dtypes.int32, dtypes.int64]:
for data_type in [
dtypes.float16, dtypes.float32, dtypes.float64, dtypes.int32
]:
if (op == math_ops.unsorted_segment_sqrt_n and
data_type == dtypes.int32): # sqrt_n doesn't support int32
continue
data, segment_ids, num_segments = self._input(
data_type, segment_ids_type)
result = op(data, segment_ids, num_segments)
self.evaluate(result)
@test_util.run_cuda_only
def testUnsortedOpsComplex(self):
for op in [
math_ops.unsorted_segment_sum,
]:
for data_type in [dtypes.complex64, dtypes.complex128]:
for segment_ids_type in [dtypes.int32, dtypes.int64]:
with self.cached_session(force_gpu=True):
data, segment_ids, num_segments = self._input(
data_type, segment_ids_type)
result = op(data, segment_ids, num_segments)
self.evaluate(result)
@test_util.run_cuda_only
@test_util.run_in_graph_and_eager_modes
def testConvertToTensor(self):
with self.session(force_gpu=True):
dtypes_to_test = [dtypes.float16, dtypes.float32, dtypes.float64]
if not test.is_built_with_rocm():
dtypes_to_test += [dtypes.complex64, dtypes.complex128]
for data_type in dtypes_to_test:
for segment_ids_type in [dtypes.int32, dtypes.int64]:
values, indices, _ = self._input(data_type, segment_ids_type)
sparse_value = indexed_slices.IndexedSlices(
values, indices, dense_shape=values.shape)
result = ops.convert_to_tensor(sparse_value)
self.evaluate(result)
@test_util.run_cuda_only
def testGatherBackprop(self):
dtypes_to_test = [dtypes.float16, dtypes.float32, dtypes.float64]
if not test.is_built_with_rocm():
dtypes_to_test += [dtypes.complex64, dtypes.complex128]
for data_type in dtypes_to_test:
for segment_ids_type in [dtypes.int32, dtypes.int64]:
with self.cached_session(force_gpu=True):
params, indices, _ = self._input(data_type, segment_ids_type)
params = variables.Variable(params)
with backprop.GradientTape() as tape:
tape.watch(params)
op_output = array_ops.gather(params, indices)
gradient = tape.gradient(op_output, params)
self.evaluate(params.assign(gradient))
if __name__ == "__main__":
config.enable_op_determinism()
test.main()
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,248 @@
# Copyright 2015 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 tensorflow.ops.math_ops.matmul."""
import numpy as np
from tensorflow.python.eager import context
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors_impl
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import math_ops
from tensorflow.python.platform import test as test_lib
_MAXDIM = 5
def _add_test(test, test_name, fn):
test_name = "_".join(["test", test_name])
if hasattr(test, test_name):
raise RuntimeError("Test %s defined more than once" % test_name)
setattr(test, test_name, fn)
class TensordotTest(test_lib.TestCase):
@test_util.run_in_graph_and_eager_modes(use_gpu=True)
def test_invalid_shape(self):
a = [[1, 2], [3, 4]]
b = [[1, 2], [3, 4], [5, 6]]
a_axes = [1]
b_axes = [0]
# Invalid static shapes.
with self.assertRaises((ValueError, errors_impl.InvalidArgumentError)):
math_ops.tensordot(a, b, (a_axes, b_axes))
# Invalid dynamic shapes.
if context.executing_eagerly():
return
with self.cached_session() as sess:
with self.assertRaisesOpError(
r"Matrix size-incompatible: In\[0\]: \[2,2\], In\[1\]: \[3,2\]"):
a_ph = array_ops.placeholder(dtypes.float32)
b_ph = array_ops.placeholder(dtypes.float32)
axes_ph = array_ops.placeholder(dtypes.int32)
output = math_ops.tensordot(a_ph, b_ph, axes_ph)
_ = sess.run(
[output], feed_dict={
a_ph: a,
b_ph: b,
axes_ph: (a_axes, b_axes)
})
@test_util.run_in_graph_and_eager_modes(use_gpu=True)
def test_invalid_axes(self):
a = [[1, 2], [3, 4]]
b = [[1, 2], [3, 4]]
# Invalid static axes.
for axes_value in -1, 3, [1], [[1]], [[1], [0, 1]]:
with self.assertRaises(ValueError):
math_ops.tensordot(a, b, axes_value)
with self.assertRaises(IndexError):
math_ops.tensordot(a, b, [[0], [7]])
if context.executing_eagerly():
return
# Invalid dynamic axes.
a_ph = array_ops.placeholder(dtypes.float32)
b_ph = array_ops.placeholder(dtypes.float32)
axes_ph = array_ops.placeholder(dtypes.int32)
output = math_ops.tensordot(a_ph, b_ph, axes_ph)
# Note: We don't support scalar Tensor values for axes.
for axes_value in 1, [1], [0, 1], [[1]], [[0, 1]], [[0], [7]]:
with self.cached_session() as sess:
with self.assertRaises(errors_impl.InvalidArgumentError):
_ = sess.run(
[output], feed_dict={
a_ph: a,
b_ph: b,
axes_ph: axes_value
})
# Test case for https://github.com/tensorflow/tensorflow/issues/11950
@test_util.run_in_graph_and_eager_modes(use_gpu=True)
def test_valid_axis(self):
for axes_value in [1, 2], [[1], [2]], [[], []], 0:
np_a = np.ones((3, 3))
np_b = np.array([2, 3, 1])[None, None]
np_ans = np.tensordot(np_a, np_b, axes_value)
tf_a = array_ops.ones((3, 3), dtype=dtypes.float32)
tf_b = constant_op.constant([2, 3, 1], dtype=dtypes.float32)[None, None]
tf_ans = math_ops.tensordot(tf_a, tf_b, axes_value)
self.assertAllEqual(tf_ans.shape, np_ans.shape)
self.assertAllEqual(self.evaluate(tf_ans), np_ans)
@test_util.run_v1_only("Shape inference test")
def test_partial_shape_inference(self):
for axes in ([1], [0]), 1:
a = array_ops.placeholder(dtypes.float32)
b = array_ops.placeholder(dtypes.float32)
output = math_ops.tensordot(a, b, axes)
self.assertEqual(output.get_shape().ndims, None)
a.set_shape([None, 2])
b.set_shape([2, 3])
output = math_ops.tensordot(a, b, axes)
output_shape = output.get_shape()
self.assertEqual(output_shape.ndims, 2)
output_shape = output_shape.as_list()
self.assertEqual(output_shape[0], None)
self.assertEqual(output_shape[1], 3)
a = array_ops.placeholder(dtypes.float32)
b = array_ops.placeholder(dtypes.float32)
a.set_shape([2, 2])
b.set_shape([2, None])
output = math_ops.tensordot(a, b, axes)
output_shape = output.get_shape()
self.assertEqual(output_shape.ndims, 2)
output_shape = output_shape.as_list()
self.assertEqual(output_shape[0], 2)
self.assertEqual(output_shape[1], None)
def _get_tensordot_tests(dtype_, rank_a_, rank_b_, num_dims_, dynamic_shape_):
# Select a random subset of size m from [0, 1, ..., n-1].
def _random_subset(m, n):
assert m <= n
return (np.random.permutation(n)[:m]).astype(np.int32)
def _generate_random_tensors_and_dims():
a_shape = np.random.random_integers(1, _MAXDIM, rank_a_)
b_shape = np.random.random_integers(1, _MAXDIM, rank_b_)
shared_shape = np.random.random_integers(1, _MAXDIM, num_dims_)
a_dims = _random_subset(num_dims_, rank_a_)
b_dims = _random_subset(num_dims_, rank_b_)
for i in range(num_dims_):
a_shape[a_dims[i]] = shared_shape[i]
b_shape[b_dims[i]] = shared_shape[i]
a = np.random.uniform(
low=-1.0, high=1.0,
size=np.prod(a_shape)).reshape(a_shape).astype(dtype_)
b = np.random.uniform(
low=-1.0, high=1.0,
size=np.prod(b_shape)).reshape(b_shape).astype(dtype_)
return a, b, a_dims, b_dims
@test_util.run_in_graph_and_eager_modes(use_gpu=True)
@test_util.run_without_tensor_float_32("Tests tensordot, which calls matmul")
def test_tensordot(self):
if dynamic_shape_ and context.executing_eagerly():
self.skipTest("Placeholders not support in eager mode")
num_trials = min(30, num_dims_ * num_dims_)
if dtype_ == np.float16:
tol = 0.05
elif dtype_ == np.float32 or dtype_ == np.complex64:
tol = 1e-5
else:
tol = 1e-12
for _ in range(num_trials):
a_np, b_np, a_dims_np, b_dims_np = _generate_random_tensors_and_dims()
np_ans = np.tensordot(a_np, b_np, axes=(a_dims_np, b_dims_np))
with self.cached_session() as sess:
if dynamic_shape_:
a = array_ops.placeholder(dtype_)
b = array_ops.placeholder(dtype_)
axes = array_ops.placeholder(dtypes.int32)
c = math_ops.tensordot(a, b, axes)
tf_ans = sess.run(
c, feed_dict={
a: a_np,
b: b_np,
axes: (a_dims_np, b_dims_np)
})
else:
tf_ans = math_ops.tensordot(a_np, b_np, (a_dims_np, b_dims_np))
self.assertAllClose(tf_ans, np_ans, rtol=tol, atol=tol)
self.assertAllEqual(tf_ans.shape, np_ans.shape)
@test_util.run_in_graph_and_eager_modes(use_gpu=True)
@test_util.run_without_tensor_float_32("Tests tensordot, which calls matmul")
def test_tensordot_scalar_axes(self):
if dynamic_shape_ and context.executing_eagerly():
self.skipTest("Placeholders not support in eager mode")
if num_dims_ < 1:
self.skipTest("Not a test")
if dtype_ == np.float16:
tol = 0.05
elif dtype_ == np.float32 or dtype_ == np.complex64:
tol = 1e-5
else:
tol = 1e-12
shape = [5] * num_dims_
a_np = np.random.uniform(
low=-1.0, high=1.0, size=np.prod(shape)).reshape(shape).astype(dtype_)
b_np = np.random.uniform(
low=-1.0, high=1.0, size=np.prod(shape)).reshape(shape).astype(dtype_)
all_axes = [0, 1]
if a_np.ndim > 2:
all_axes.append(a_np.ndim - 1)
for axes in all_axes:
np_ans = np.tensordot(a_np, b_np, axes=axes)
with self.cached_session() as sess:
if dynamic_shape_:
a = array_ops.placeholder(dtype_)
b = array_ops.placeholder(dtype_)
c = math_ops.tensordot(a, b, axes=axes)
tf_ans = sess.run(c, feed_dict={a: a_np, b: b_np})
else:
tf_ans = math_ops.tensordot(a_np, b_np, axes=axes)
self.assertAllClose(tf_ans, np_ans, rtol=tol, atol=tol)
self.assertAllEqual(tf_ans.shape, np_ans.shape)
return [test_tensordot, test_tensordot_scalar_axes]
if __name__ == "__main__":
dtypes_to_test = [
np.float16, np.float32, np.float64, np.complex64, np.complex128
]
for dtype in dtypes_to_test:
for rank_a in 1, 2, 4, 5:
for rank_b in 1, 2, 4, 5:
for num_dims in range(0, min(rank_a, rank_b) + 1):
# TF2 does not support placeholders under eager so we skip it
for dynamic_shape in set([False, True]):
for testcase in _get_tensordot_tests(dtype, rank_a, rank_b,
num_dims, dynamic_shape):
name = "%s_%s_%s_%s_%s_%s" % (testcase.__name__, dtype.__name__,
rank_a, rank_b, num_dims,
dynamic_shape)
_add_test(TensordotTest, name, testcase)
test_lib.main()
@@ -0,0 +1,282 @@
# Copyright 2015 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 TopK op."""
import itertools
import sys
import numpy as np
from tensorflow.python.client import session
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors
from tensorflow.python.framework import ops
from tensorflow.python.framework import test_util
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradients_impl
from tensorflow.python.ops import nn_ops
from tensorflow.python.ops import random_ops
from tensorflow.python.ops import resource_variable_ops
import tensorflow.python.ops.nn_grad # pylint: disable=unused-import
from tensorflow.python.platform import test
class TopKTest(test.TestCase):
def _validateTopK(
self,
inputs,
k,
expected_values,
expected_indices,
sorted=True,
index_type=dtypes.int32,
): # pylint: disable=redefined-builtin
np_expected_values = np.array(expected_values)
np_expected_indices = np.array(expected_indices)
with self.cached_session():
values_op, indices_op = nn_ops.top_k(
inputs, k, sorted=sorted, index_type=index_type
)
values, indices = self.evaluate([values_op, indices_op])
self.assertEqual(indices.dtype, index_type)
self.assertShapeEqual(np_expected_values, values_op)
self.assertShapeEqual(np_expected_indices, indices_op)
if sorted:
self.assertAllClose(np_expected_values, values)
# Do some special casing of equality of indices: if indices
# are not the same, but values are floating type, ensure that
# the values are within epsilon of each other.
if not np.issubdtype(np_expected_values.dtype, np.floating) and \
np_expected_values.dtype != dtypes.bfloat16.as_numpy_dtype:
# Values are not floating point type; check indices exactly
self.assertAllEqual(np_expected_indices, indices)
else:
# Values are floating point; indices may be swapped for
# values near each other.
indices_not_equal = np_expected_indices != indices
if np.any(indices_not_equal):
values_unsure = values[indices_not_equal]
expected_values_unsure = expected_values[indices_not_equal]
self.assertAllClose(expected_values_unsure, values_unsure)
else:
np_inputs = np.array(inputs)
# Check that the indices are valid.
for result_index, src_index in np.ndenumerate(indices):
value = values[result_index]
expected_value = np_inputs[result_index[0], src_index]
np.testing.assert_almost_equal(value, expected_value)
# Check that if two elements are equal, the lower-index element appears
# first.
shape = values.shape
for batch_index in range(shape[0]):
for index in range(shape[1] - 1):
if np.isclose(values[batch_index, index],
values[batch_index, index + 1]):
self.assertLess(indices[batch_index, index],
indices[batch_index, index + 1])
# Now check the results, ignoring order.
self.assertAllEqual(np.sort(np_expected_indices), np.sort(indices))
self.assertAllClose(np.sort(np_expected_values), np.sort(values))
def testTop1(self):
inputs = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.3, 0.3, 0.2]]
self._validateTopK(inputs, 1, [[0.4], [0.3]], [[3], [1]])
def testTop2(self):
inputs = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.3, 0.4, 0.2]]
self._validateTopK(inputs, 2, [[0.4, 0.3], [0.4, 0.3]], [[3, 1], [2, 1]])
def testOutputIndexType(self):
for index_type in [dtypes.int16, dtypes.int32, dtypes.int64]:
inputs = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.3, 0.4, 0.2]]
self._validateTopK(
inputs,
2,
[[0.4, 0.3], [0.4, 0.3]],
[[3, 1], [2, 1]],
index_type=index_type,
)
def testKType(self):
for ktype in [dtypes.int32, dtypes.int64, dtypes.int16]:
inputs = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.3, 0.4, 0.2]]
self._validateTopK(
inputs,
constant_op.constant(2, dtype=ktype),
[[0.4, 0.3], [0.4, 0.3]],
[[3, 1], [2, 1]],
)
def testTop3(self):
for k in range(3, 11, 2):
for dim in range(512, 12288, 512):
inputs = np.random.permutation(
np.linspace(0, 100, dim, dtype=np.float64))
indices = np.argsort(-inputs)[:k]
values = -np.sort(-inputs)[:k]
self._validateTopK(inputs, k, values, indices)
def testTop1AllNan(self):
inputs = [[np.nan, np.nan], [np.nan, np.nan]]
self._validateTopK(inputs, 1, [[np.nan], [np.nan]], [[0], [0]])
def _testLargeSort(self, dtype):
b = 10
n = 5000
inputs = np.random.permutation(
np.linspace(0, 100, b * n, dtype=dtype)).reshape(b, n)
indices = np.argsort(-inputs, axis=1)
values = -np.sort(-inputs, axis=1)
self._validateTopK(inputs, n, values, indices)
def testLargeSort(self):
self._testLargeSort(np.float32)
self._testLargeSort(np.float16)
self._testLargeSort(dtypes.bfloat16.as_numpy_dtype)
def _testLargeTopK(self, dtype):
b = 10
n = 5000
k = n - 1
inputs = np.random.permutation(
np.linspace(0, 100, b * n, dtype=dtype)).reshape(b, n)
indices = np.argsort(-inputs, axis=1)[:, :k]
values = -np.sort(-inputs, axis=1)[:, :k]
self._validateTopK(inputs, k, values, indices)
def testLargeTopK(self):
self._testLargeTopK(np.float32)
self._testLargeTopK(np.float16)
self._testLargeTopK(dtypes.bfloat16.as_numpy_dtype)
def _testMediumTopK(self, dtype):
b = 5
n = 500
k = 50
inputs = np.random.permutation(
np.linspace(0, 100, b * n, dtype=dtype)).reshape(b, n)
indices = np.argsort(-inputs, axis=1)[:, :k]
values = -np.sort(-inputs, axis=1)[:, :k]
self._validateTopK(inputs, k, values, indices)
def testMediumTopK(self):
self._testMediumTopK(np.float32)
self._testMediumTopK(np.float16)
self._testMediumTopK(dtypes.bfloat16.as_numpy_dtype)
def testStableSort(self):
b = 5
n = 500
for k in [1, 5, 50, 500]:
# Lots of repeated integers taking values in [0, 3]
inputs = np.random.permutation(
np.linspace(0, 3, b * n, dtype=np.int32)).reshape(b, n)
# Use mergesort, a stable sort, to get the indices.
indices = np.argsort(-inputs, axis=1, kind="mergesort")[:, :k]
values = -np.sort(-inputs, axis=1)[:, :k]
self._validateTopK(inputs, k, values, indices)
def testTopAll(self):
inputs = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.3, 0.3, 0.2]]
self._validateTopK(inputs, 4, [[0.4, 0.3, 0.2, 0.1], [0.3, 0.3, 0.2, 0.1]],
[[3, 1, 2, 0], [1, 2, 3, 0]])
def testTop3Unsorted(self):
inputs = [[0.1, 0.3, 0.2, 0.4], [0.1, 0.4, 0.3, 0.2]]
self._validateTopK(
inputs,
3, [[0.2, 0.3, 0.4], [0.2, 0.4, 0.3]], [[2, 1, 3], [3, 1, 2]],
sorted=False)
def testTop3Vector(self):
inputs = [3, 6, 15, 18, 6, 12, 1, 17, 3, 0, 4, 19, 1, 6]
self._validateTopK(inputs, 3, [19, 18, 17], [11, 3, 7])
def testTensorK(self):
inputs = [3, 6, 15, 18, 6, 12, 1, 17, 3, 0, 4, 19, 1, 6]
k = constant_op.constant(3)
self._validateTopK(inputs, k, [19, 18, 17], [11, 3, 7])
def testTop3ZeroRows(self):
inputs = np.zeros([0, 10], dtype=np.float32)
self._validateTopK(inputs, 3, np.zeros([0, 3], dtype=np.float32),
np.zeros([0, 3], dtype=np.int32))
def testKNegative(self):
with self.assertRaisesRegex(
(ValueError, errors.InvalidArgumentError),
"Need k >= 0, got -7|non-negative",
):
self.evaluate(nn_ops.top_k([[0.1, 0.2], [0.3, 0.4]], -7))
def testKTooLarge(self):
inputs = [[0.1, 0.2], [0.3, 0.4]]
with self.assertRaisesRegex(
(ValueError, errors.InvalidArgumentError),
r"must have last dimension >= k = 4|must have at least k",
):
self.evaluate(nn_ops.top_k(inputs, 4))
@test_util.run_deprecated_v1
def testTopKGradients(self):
with self.session() as sess:
inputs = array_ops.placeholder(dtypes.float32, shape=[2, 5])
values, _ = nn_ops.top_k(inputs, 3)
grad = sess.run(
gradients_impl.gradients(
values, inputs, grad_ys=[[[1., 2., 3.], [4., 5., 6.]]]),
feed_dict={inputs: [[2., -1., 1000., 3., 4.],
[1., 5., 2., 4., 3.]]})[0]
self.assertEqual(
grad.tolist(), [[0., 0., 1., 3., 2.], [0., 4., 0., 5., 6.]])
class TopKBenchmark(test.Benchmark):
def benchmarkTopK(self):
for (m, n, p, use_gpu) in itertools.product(
[128],
[10, 100, 1000, 10000, 100000],
[0.001, 0.01, 0.5, 0.99, 1.0],
[False, True]):
k = int(p * n)
if k == 0:
continue
name = "m_%d_n_%d_k_%g_use_gpu_%s" % (m, n, k, use_gpu)
device = "/%s:0" % ("gpu" if use_gpu else "cpu")
with ops.Graph().as_default():
with ops.device(device):
x = random_ops.random_uniform((m, n))
v = resource_variable_ops.ResourceVariable(x)
op = nn_ops.top_k(v, k)
with session.Session() as sess:
self.evaluate(v.initializer)
r = self.run_op_benchmark(sess, op, min_iters=100, name=name)
gb_processed_input = m * n / 1.0e9
throughput = gb_processed_input / r["wall_time"]
print("Benchmark: %s \t wall_time: %0.03g s \t "
"Throughput: %0.03g GB/s" % (name, r["wall_time"], throughput))
sys.stdout.flush()
if __name__ == "__main__":
test.main()
@@ -0,0 +1,557 @@
# Copyright 2015 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.
# ==============================================================================
"""Functional tests for Transpose op."""
import itertools
import numpy as np
from tensorflow.python.eager import def_function
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors
from tensorflow.python.framework import ops
from tensorflow.python.framework import tensor_shape
from tensorflow.python.framework import tensor_spec
from tensorflow.python.ops import array_ops
from tensorflow.python.ops import gradient_checker_v2
from tensorflow.python.platform import test
class TransposeTest(test.TestCase):
def _np_transpose(self, x, perm):
ret = np.copy(x)
ret = ret.transpose(perm)
return ret
def _compareCpu(self, x, p, conjugate=False):
if p is None:
rank = x.ndim
perm = (rank - 1) - np.arange(rank)
else:
perm = p
np_ans = self._np_transpose(x, perm)
if conjugate:
np_ans = np.conj(np_ans)
with self.cached_session(use_gpu=False):
inx = ops.convert_to_tensor(x)
y = array_ops.transpose(inx, p, conjugate=conjugate)
tf_ans = self.evaluate(y)
self.assertShapeEqual(np_ans, y)
self.assertAllEqual(np_ans, tf_ans)
jacob_t = None
# Gradient check on CPU.
if x.dtype in [np.float32, np.complex64]:
jacob_t, jacob_n = gradient_checker_v2.compute_gradient(
lambda x: array_ops.transpose(x, p, conjugate=conjugate), [inx])
self.assertAllClose(jacob_t, jacob_n, 1e-3, 1e-3)
elif x.dtype in [np.float64, np.complex128]:
jacob_t, jacob_n = gradient_checker_v2.compute_gradient(
lambda x: array_ops.transpose(x, p, conjugate=conjugate), [inx])
self.assertAllClose(jacob_t, jacob_n, 1e-6, 1e-6)
return tf_ans, jacob_t
def _compareGpu(self, x, p, conjugate=False):
if p is None:
rank = x.ndim
perm = (rank - 1) - np.arange(rank)
else:
perm = p
np_ans = self._np_transpose(x, perm)
if conjugate:
np_ans = np.conj(np_ans)
with self.cached_session():
inx = ops.convert_to_tensor(x)
y = array_ops.transpose(inx, p, conjugate=conjugate)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
jacob_t = None
# Gradient check on GPU.
if x.dtype == np.float32:
jacob_t, jacob_n = gradient_checker_v2.compute_gradient(
lambda x: array_ops.transpose(x, p, conjugate=conjugate), [inx])
self.assertAllClose(jacob_t, jacob_n, 1e-3, 1e-3)
elif x.dtype == np.float64:
jacob_t, jacob_n = gradient_checker_v2.compute_gradient(
lambda x: array_ops.transpose(x, p, conjugate=conjugate), [inx])
self.assertAllClose(jacob_t, jacob_n, 1e-6, 1e-6)
return tf_ans, jacob_t
def _compare(self, x, use_gpu=False):
n = np.ndim(x)
# generate all permutations of [0, 1, ... n-1] in random order.
all_perm = np.random.permutation(
[p for p in itertools.permutations(range(n))]).astype(np.int32)
cs = [False, True] if x.dtype in [np.complex64, np.complex128] else [False]
for c in cs:
for p in all_perm[:2]:
self._compareCpu(x, p, conjugate=c)
if use_gpu:
self._compareGpu(x, p, conjugate=c)
# Test with an empty permutation
for c in cs:
self._compareCpu(x, None, conjugate=c)
if use_gpu:
self._compareGpu(x, None, conjugate=c)
def _compare_cpu_gpu(self, x):
n = np.ndim(x)
# generate all permutation of [0, 1, ... n-1] in random order,
# choose the first two.
perms = itertools.permutations(range(n))
for _ in range(2):
p = np.random.permutation(next(perms)).astype(np.int32) if n > 1 else None
tf_a_cpu, tf_g_cpu = self._compareCpu(x, p)
tf_a_gpu, tf_g_gpu = self._compareGpu(x, p)
assert tf_g_cpu is not None
assert tf_g_gpu is not None
if x.dtype == np.float32:
self.assertAllClose(tf_a_cpu, tf_a_gpu, 1e-3, 1e-3)
self.assertAllClose(tf_g_cpu, tf_g_gpu, 1e-3, 1e-3)
elif x.dtype == np.float64:
self.assertAllClose(tf_a_cpu, tf_a_gpu, 1e-6, 1e-6)
self.assertAllClose(tf_g_cpu, tf_g_gpu, 1e-6, 1e-6)
def _testBoth(self, x):
self._compare(x, use_gpu=False)
self._compare(x, use_gpu=True)
def testRank1(self):
self._compareCpu(np.arange(0., 2), [0])
def test1D(self):
vector = np.arange(0, 2).reshape((1, 1, 1, 2, 1))
self._compare(vector, use_gpu=False)
self._compare(vector, use_gpu=True)
def test5DGPU(self):
# If no GPU available, skip the test
if not test.is_gpu_available(cuda_only=True):
return
large_shapes = [[4, 10, 10, 10, 3], [4, 10, 10, 10, 8], [4, 10, 10, 10, 13],
[4, 3, 10, 10, 10], [4, 8, 10, 10, 10], [4, 13, 10, 10,
10]] * 3
perms = [[0, 4, 1, 2, 3]] * 3 + [[0, 2, 3, 4, 1]] * 3 + [[
4, 1, 2, 3, 0
]] * 6 + [[1, 2, 3, 4, 0]] * 6
datatypes = [
np.int8, np.float16, np.float32, np.float64, np.complex128,
dtypes.bfloat16.as_numpy_dtype
]
for datatype in datatypes:
for input_shape, perm in zip(large_shapes, perms):
with self.subTest(
datatype=datatype, input_shape=input_shape, perm=perm):
total_size = np.prod(input_shape)
inp = np.arange(
1, total_size + 1, dtype=datatype).reshape(input_shape)
np_ans = self._np_transpose(inp, perm)
with self.cached_session():
inx = ops.convert_to_tensor(inp)
y = array_ops.transpose(inx, perm)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
def test4DGPU(self):
# If no GPU available, skip the test
if not test.is_gpu_available(cuda_only=True):
return
large_shapes = [[4, 10, 10, 3], [4, 10, 10, 8], [4, 10, 10, 13],
[4, 3, 10, 10], [4, 8, 10, 10], [4, 13, 10, 10]] * 3
perms = [[0, 3, 1, 2]] * 3 + [[0, 2, 3, 1]] * 3 + [[3, 1, 2, 0]] * 6 + [[
1, 2, 3, 0
]] * 3 + [[2, 3, 0, 1]] * 3
for input_shape, perm in zip(large_shapes, perms):
with self.subTest(input_shape=input_shape, perm=perm):
total_size = np.prod(input_shape)
inp = np.arange(
1, total_size + 1, dtype=np.float32).reshape(input_shape)
np_ans = self._np_transpose(inp, perm)
with self.cached_session():
inx = ops.convert_to_tensor(inp)
y = array_ops.transpose(inx, perm)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
# shapes related to Inception (taken from conv_ops_test.py)
inception_shapes = [[4, 5, 5, 124], [4, 8, 8, 38], [4, 8, 8, 38], [
4, 8, 8, 204
], [4, 8, 8, 44], [4, 8, 8, 204], [4, 8, 8, 204], [4, 8, 8, 204], [
4, 8, 8, 176
], [4, 8, 8, 176], [4, 8, 8, 176], [4, 8, 8, 176], [4, 17, 17, 19], [
4, 17, 17, 19
], [4, 17, 17, 124], [4, 17, 17, 12], [4, 17, 17, 124], [4, 17, 17, 22], [
4, 17, 17, 19
], [4, 17, 17, 19], [4, 17, 17, 121], [4, 17, 17, 121], [4, 17, 17, 22], [
4, 17, 17, 19
], [4, 17, 17, 19], [4, 17, 17, 115], [4, 17, 17, 115], [4, 17, 17, 19], [
4, 17, 17, 16
], [4, 17, 17, 115], [4, 17, 17, 102], [4, 17, 17, 12], [4, 17, 17, 102], [
4, 17, 17, 12
], [4, 17, 17, 102], [4, 17, 17, 12], [4, 17, 17, 76], [4, 17, 17, 12], [
4, 17, 17, 12
], [4, 17, 17, 76], [4, 17, 17, 76], [4, 35, 35, 9], [4, 35, 35, 28], [
4, 35, 35, 6
], [4, 35, 35, 28], [4, 35, 35, 25], [4, 35, 35, 4], [4, 35, 35, 25],
[4, 35, 35, 9], [4, 35, 35, 19], [4, 35, 35, 19],
[4, 35, 35, 19], [4, 73, 73, 6], [4, 73, 73,
6], [4, 147, 147, 2]]
for input_shape in inception_shapes:
with self.subTest(input_shape=input_shape):
perm = [0, 3, 1, 2]
total_size = np.prod(input_shape)
inp = np.arange(
1, total_size + 1, dtype=np.float32).reshape(input_shape)
np_ans = self._np_transpose(inp, perm)
with self.cached_session():
inx = ops.convert_to_tensor(inp)
y = array_ops.transpose(inx, perm)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
def test3DGPU(self):
# If no GPU available, skip the test
if not test.is_gpu_available(cuda_only=True):
return
datatypes = [np.int8, np.float16, np.float32, np.float64, np.complex128]
large_shapes = [[4, 1000, 3], [4, 1000, 8], [4, 1000, 13], [4, 3, 1000],
[4, 8, 1000], [4, 13, 1000]] * 3
perms = [[0, 2, 1]] * 6 + [[2, 1, 0]] * 6 + [[1, 2, 0]] * 3 + [[2, 0, 1]
] * 3
for datatype in datatypes:
for input_shape, perm in zip(large_shapes, perms):
with self.subTest(
datatype=datatype, input_shape=input_shape, perm=perm):
total_size = np.prod(input_shape)
inp = np.arange(
1, total_size + 1, dtype=datatype).reshape(input_shape)
np_ans = self._np_transpose(inp, perm)
with self.cached_session():
inx = ops.convert_to_tensor(inp)
y = array_ops.transpose(inx, perm)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
def testLargeSizeGPU(self):
# If no GPU available, skip the test
if not test.is_gpu_available(cuda_only=True):
return
large_shapes = [[1000000, 31, 3], [3, 1000000, 31], [3, 31, 1000000],
[10000, 310, 3], [3, 10000, 310], [3, 310, 10000],
[2, 1000, 1000], [1000, 2, 1000], [1000, 1000, 2]]
perms = [[0, 2, 1]] * 9
for input_shape, perm in zip(large_shapes, perms):
with self.subTest(input_shape=input_shape, perm=perm):
total_size = np.prod(input_shape)
inp = np.arange(
1, total_size + 1, dtype=np.float32).reshape(input_shape)
np_ans = self._np_transpose(inp, perm)
with self.cached_session():
inx = ops.convert_to_tensor(inp)
y = array_ops.transpose(inx, perm)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
def testRandomizedSmallDimLargeSizeGPU(self):
# If no GPU available, skip the test
if not test.is_gpu_available(cuda_only=True):
return
# Draw 10 random shapes with large dimension sizes.
# 40% prob to generate dim[0] size within [1, 2047]
# 40% prob to generate dim[0] size within [2048, 4095]
# 20% prob to generate dim[0] size within [4096, 100000]
# 50% prob to use dim[1] as the small dim (<16)
num_samples = 10
total_size = 500000
small_size_limit = 2048
large_size_limit = 95905
small_size_percentage = 0.4
medium_size_percentage = 0.4
large_size_percentage = 0.2
perms = [[0, 2, 1]] * num_samples
dim_zero_sizes = []
dim_zero_sizes += list(
np.random.randint(
small_size_limit, size=int(small_size_percentage * num_samples)) +
1)
dim_zero_sizes += list(
np.random.randint(
small_size_limit, size=int(medium_size_percentage * num_samples)) +
small_size_limit)
dim_zero_sizes += list(
np.random.randint(
large_size_limit, size=int(large_size_percentage * num_samples)) +
small_size_limit * 2)
input_shapes = []
small_dim_limit = 16
for dim_zero_size in dim_zero_sizes:
small_dim_size = np.random.randint(small_dim_limit - 1) + 1
large_dim_size = int(
total_size / dim_zero_size / small_dim_size) + small_dim_limit
input_shapes += ([[dim_zero_size, small_dim_size, large_dim_size]]
if np.random.randint(2) else
[[dim_zero_size, large_dim_size, small_dim_size]])
for input_shape, perm in zip(input_shapes, perms):
# generate input data with random ints from 0 to 9.
with self.subTest(input_shape=input_shape, perm=perm):
inp = np.random.randint(10, size=input_shape)
np_ans = self._np_transpose(inp, perm)
with self.cached_session():
inx = ops.convert_to_tensor(inp)
y = array_ops.transpose(inx, perm)
tf_ans = self.evaluate(y)
self.assertAllEqual(np_ans, tf_ans)
self.assertShapeEqual(np_ans, y)
self._ClearCachedSession()
def testNop(self):
self._compareCpu(np.arange(0, 6).reshape([3, 2]).astype(np.float32), [0, 1])
def testSimple(self):
self._compareCpu(
np.arange(0, 8).reshape([2, 4]).astype(np.float32),
np.array([1, 0]).astype(np.int32))
def testPermType(self):
for perm_dtype in [np.int64, np.int32]:
with self.subTest(perm_dtype=perm_dtype):
x = np.arange(0, 8).reshape([2, 4]).astype(np.float32)
p = np.array([1, 0]).astype(perm_dtype)
np_ans = np.copy(x).transpose(p)
with self.cached_session():
inx = ops.convert_to_tensor(x)
inp = constant_op.constant(p)
y = array_ops.transpose(inx, inp)
tf_ans = self.evaluate(y)
self.assertShapeEqual(np_ans, y)
self.assertAllEqual(np_ans, tf_ans)
def testHalf(self):
self._compare(np.arange(0, 21).reshape([3, 7]).astype(np.float16))
self._compare(np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.float16))
self._compare(
np.arange(0, 16).reshape([1, 2, 1, 2, 1, 2, 1, 2]).astype(np.float16))
def testBfloat16(self):
self._compare(
np.arange(0, 21).reshape([3, 7]).astype(dtypes.bfloat16.as_numpy_dtype))
self._compare(
np.arange(0, 210).reshape([2, 3, 5,
7]).astype(dtypes.bfloat16.as_numpy_dtype))
self._compare(
np.arange(0, 16).reshape([1, 2, 1, 2, 1, 2, 1,
2]).astype(dtypes.bfloat16.as_numpy_dtype))
def testFloat(self):
self._compare_cpu_gpu(np.arange(0, 21).reshape([3, 7]).astype(np.float32))
self._compare_cpu_gpu(
np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.float32))
self._compare_cpu_gpu(
np.arange(0, 16).reshape([1, 2, 1, 2, 1, 2, 1, 2]).astype(np.float32))
def testDouble(self):
self._compare_cpu_gpu(np.arange(0, 21).reshape([3, 7]).astype(np.float64))
self._compare_cpu_gpu(
np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.float64))
self._compare_cpu_gpu(
np.arange(0, 16).reshape([1, 2, 1, 2, 1, 2, 1, 2]).astype(np.float64))
def testComplex64(self):
self._testBoth(np.array(1 + 2j).astype(np.complex64))
self._testBoth((1 + 2j) * np.arange(0, 21).astype(np.complex64))
self._testBoth(
(1 + 2j) * np.arange(0, 21).reshape([3, 7]).astype(np.complex64))
self._testBoth(
(1 + 2j) * np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.complex64))
self._testBoth(
(1 + 2j) *
np.arange(0, 1260).reshape([2, 3, 5, 7, 2, 3]).astype(np.complex64))
def testComplex128(self):
self._testBoth(np.array(1 + 2j).astype(np.complex128))
self._testBoth((1 + 2j) * np.arange(0, 21).astype(np.complex128))
self._testBoth(
(1 + 2j) * np.arange(0, 21).reshape([3, 7]).astype(np.complex128))
self._testBoth(
(1 + 2j) *
np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.complex128))
self._testBoth(
(1 + 2j) *
np.arange(0, 1260).reshape([2, 3, 5, 7, 2, 3]).astype(np.complex128))
def testInt8(self):
self._testBoth(np.arange(0, 21).reshape([3, 7]).astype(np.int8))
self._testBoth(np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.int8))
self._testBoth(
np.arange(0, 1260).reshape([2, 3, 5, 7, 2, 3]).astype(np.int8))
def testInt16(self):
self._testBoth(np.arange(0, 21).reshape([3, 7]).astype(np.int16))
self._testBoth(np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.int16))
self._testBoth(
np.arange(0, 1260).reshape([2, 3, 5, 7, 2, 3]).astype(np.int16))
def testInt32(self):
self._testBoth(np.arange(0, 21).reshape([3, 7]).astype(np.int32))
self._testBoth(np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.int32))
self._testBoth(
np.arange(0, 1260).reshape([2, 3, 5, 7, 2, 3]).astype(np.int32))
def testInt64(self):
self._testBoth(np.arange(0, 21).reshape([3, 7]).astype(np.int64))
self._testBoth(np.arange(0, 210).reshape([2, 3, 5, 7]).astype(np.int64))
self._testBoth(
np.arange(0, 1260).reshape([2, 3, 5, 7, 2, 3]).astype(np.int64))
def testTranspose2DAuto(self):
x_np = [[1, 2, 3], [4, 5, 6]]
for use_gpu in [False, True]:
with self.subTest(use_gpu=use_gpu):
with self.cached_session(use_gpu=use_gpu):
x_tf = array_ops.transpose(x_np)
self.assertAllEqual(x_tf, [[1, 4], [2, 5], [3, 6]])
def testSingletonDims(self):
# A singleton dimension is a dimension i with shape[i] == 1. Such dimensions
# can be collapsed and expanded using reshape without changing the
# underlying data storage. If all non-singleton dimensions remain in
# ascending order, the shuffled singletons will be transposed by a reshape,
# saving a memory allocation & copy. Since this gets a special code-path in
# transpose_op.cc, we test that the codepath is exercised and the results
# are as expected; we do not test that we save the memory allocation and
# copy here.
for shape in [[2, 1, 2], [2, 1, 2, 1, 1, 2], [1, 2, 2, 1, 1, 1],
[1, 1, 1, 2, 2, 2], [2, 2, 1, 1, 1]]:
with self.subTest(shape=shape):
self._compare_cpu_gpu(
np.arange(np.prod(shape)).reshape(shape).astype(np.float32))
def testTransposeShapes(self):
self.assertEqual([],
array_ops.transpose(
constant_op.constant(1, dtype=dtypes.int32,
shape=[])).get_shape().dims)
self.assertEqual([100],
array_ops.transpose(
constant_op.constant(
1, dtype=dtypes.int32,
shape=[100])).get_shape().dims)
self.assertEqual([37, 100],
array_ops.transpose(
constant_op.constant(
1, dtype=dtypes.int32,
shape=[100, 37])).get_shape().dims)
self.assertEqual([100, 37],
array_ops.transpose(
constant_op.constant(
1, dtype=dtypes.int32, shape=[100, 37]),
[0, 1]).get_shape().dims)
self.assertEqual([15, 37, 100],
array_ops.transpose(
constant_op.constant(
1, dtype=dtypes.int32,
shape=[100, 37, 15])).get_shape().dims)
self.assertEqual([15, 100, 37],
array_ops.transpose(
constant_op.constant(
1, dtype=dtypes.int32, shape=[100, 37, 15]),
[2, 0, 1]).get_shape().dims)
def testTransposeDynamicShapes(self):
@def_function.function(input_signature=[
tensor_spec.TensorSpec(shape=None, dtype=dtypes.int32),
])
def transpose(x):
y = array_ops.transpose(x)
self.assertEqual(y.shape, tensor_shape.TensorShape(None))
return y
x = constant_op.constant([[1, 2, 3], [4, 5, 6]]) # Shape (2, 3)
expected_transpose = constant_op.constant([[1, 4], [2, 5],
[3, 6]]) # Shape (3, 2)
self.assertAllEqual(expected_transpose, transpose(x))
@def_function.function(input_signature=[
tensor_spec.TensorSpec(shape=None, dtype=dtypes.int32),
tensor_spec.TensorSpec(shape=None, dtype=dtypes.int32),
])
def transpose_with_perm(x, perm):
y = array_ops.transpose(x, perm)
self.assertEqual(y.shape, tensor_shape.TensorShape(None))
return y
self.assertAllEqual(x, transpose_with_perm(x, [0, 1]))
def testNullTensor(self):
with self.cached_session():
x = constant_op.constant([], dtype=dtypes.float32, shape=[1, 4, 0])
xt = array_ops.transpose(x, [0, 2, 1])
self.assertAllEqual(xt.shape, (1, 0, 4))
def testScalar(self):
with self.cached_session():
x = constant_op.constant(42, dtype=dtypes.float32, shape=[])
xt = array_ops.transpose(x)
self.assertAllEqual(xt, x)
def _testError(self, x, p, err):
with self.cached_session():
with self.assertRaisesOpError(err):
self.evaluate(array_ops.transpose(x, p))
def testError(self):
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
r"must be rank 1"):
array_ops.transpose(
np.arange(0., 30).reshape([2, 3, 5]), [[0, 1], [2, 3]])
with self.assertRaisesRegex((ValueError, errors.InvalidArgumentError),
r"3 is out of range"):
array_ops.transpose(np.arange(0., 30).reshape([2, 3, 5]), [0, 1, 3])
self._testError(
np.arange(0., 30).reshape([2, 3, 5]), [0, 1, 1], "2 is missing")
def testNegativePerm(self):
self.assertEqual(
[15, 100, 37],
array_ops.transpose(
constant_op.constant(1, dtype=dtypes.int32, shape=[100, 37, 15]),
[-1, -3, -2],
)
.get_shape()
.dims,
)
if __name__ == "__main__":
test.main()
@@ -0,0 +1,56 @@
# Copyright 2015 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 integer division by zero."""
from tensorflow.python.framework import constant_op
from tensorflow.python.framework import dtypes
from tensorflow.python.framework import errors
from tensorflow.python.framework import test_util
from tensorflow.python.platform import test
class ZeroDivisionTest(test.TestCase):
def testZeros(self):
with test_util.use_gpu():
for dtype in dtypes.uint8, dtypes.int16, dtypes.int32, dtypes.int64:
zero = constant_op.constant(0, dtype=dtype)
one = constant_op.constant(1, dtype=dtype)
bads = [lambda x, y: x // y]
if dtype in (dtypes.int32, dtypes.int64):
bads.append(lambda x, y: x % y)
for bad in bads:
try:
result = self.evaluate(bad(one, zero))
except (errors.OpError, errors.InvalidArgumentError) as e:
# Ideally, we'd get a nice exception. In theory, this should only
# happen on CPU, but 32 bit integer GPU division is actually on
# CPU due to a placer bug.
# TODO(irving): Make stricter once the placer bug is fixed.
self.assertIn('Integer division by zero', str(e))
else:
# On the GPU, integer division by zero produces all bits set.
# But apparently on some GPUs "all bits set" for 64 bit division
# means 32 bits set, so we allow 0xffffffff as well. This isn't
# very portable, so we may need to expand this list if other GPUs
# do different things.
#
# XLA constant folds integer division by zero to 1.
self.assertTrue(test.is_gpu_available())
self.assertIn(result, (-1, 1, 2, 0xff, 0xffffffff))
if __name__ == '__main__':
test.main()