From 5f457f704022b08c5592481bf79d03adcf6450db Mon Sep 17 00:00:00 2001 From: Yong Tang <yong.tang.github@outlook.com> Date: Wed, 27 Jan 2021 20:25:08 +0000 Subject: [PATCH 1/2] Fix crash when invalid keepdims value is being passed to tf.math.reduce_prod This PR tries to address the issue raised in 46700 where tf.math.reduce_prod will crash if keepdims is being passed with a non-boolean value (e.g. numpy value) The issue was that keepdims is passed through pywrap which can not interprete numpy values, thus crashes. A way to detect the type mismatch before being passed to pywrap is to use `bool(keepdims)` to give python a chance to convert to bool (and throw out error when appropriate). This PR also fixes all reduce_ ops. This PR fixes 46700. Signed-off-by: Yong Tang <yong.tang.github@outlook.com> --- tensorflow/python/ops/math_ops.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/tensorflow/python/ops/math_ops.py b/tensorflow/python/ops/math_ops.py index cc0c4415fef..decad558e85 100644 --- a/tensorflow/python/ops/math_ops.py +++ b/tensorflow/python/ops/math_ops.py @@ -2016,7 +2016,7 @@ def reduce_sum_with_dims(input_tensor, keepdims=False, name=None, dims=None): - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops._sum(input_tensor, dims, keepdims, name=name)) @@ -2059,6 +2059,7 @@ def reduce_euclidean_norm(input_tensor, axis=None, keepdims=False, name=None): Returns: The reduced tensor, of the same dtype as the input_tensor. """ + keepdims = bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops.euclidean_norm( @@ -2331,7 +2332,7 @@ def reduce_mean(input_tensor, axis=None, keepdims=False, name=None): @end_compatibility """ - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops.mean( @@ -2491,7 +2492,7 @@ def reduce_prod(input_tensor, axis=None, keepdims=False, name=None): Equivalent to np.prod @end_compatibility """ - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops.prod( @@ -2678,7 +2679,7 @@ def reduce_min(input_tensor, axis=None, keepdims=False, name=None): Equivalent to np.min @end_compatibility """ - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops._min( @@ -2805,7 +2806,7 @@ def reduce_max_with_dims(input_tensor, keepdims=False, name=None, dims=None): - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops._max(input_tensor, dims, keepdims, name=name)) @@ -2909,7 +2910,7 @@ def reduce_all(input_tensor, axis=None, keepdims=False, name=None): Equivalent to np.all @end_compatibility """ - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops._all( @@ -3015,7 +3016,7 @@ def reduce_any(input_tensor, axis=None, keepdims=False, name=None): Equivalent to np.any @end_compatibility """ - keepdims = False if keepdims is None else keepdims + keepdims = False if keepdims is None else bool(keepdims) return _may_reduce_to_scalar( keepdims, axis, gen_math_ops._any( From b8a0b61cdbc48113dc813e395a58baaa7f2790cd Mon Sep 17 00:00:00 2001 From: Yong Tang <yong.tang.github@outlook.com> Date: Wed, 27 Jan 2021 20:29:07 +0000 Subject: [PATCH 2/2] Add test case for GitHub issue 46700. Signed-off-by: Yong Tang <yong.tang.github@outlook.com> --- .../python/kernel_tests/reduction_ops_test.py | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tensorflow/python/kernel_tests/reduction_ops_test.py b/tensorflow/python/kernel_tests/reduction_ops_test.py index 6a0f40108a8..3a58608443f 100644 --- a/tensorflow/python/kernel_tests/reduction_ops_test.py +++ b/tensorflow/python/kernel_tests/reduction_ops_test.py @@ -116,6 +116,25 @@ class ReductionUnknownShape(test.TestCase): self.assertEqual(y.shape, ()) +class ReductionInvalidKeepdims(test.TestCase): + + def testBasic(self): + # Test case for GitHub issue 46700. + for dtype, reductions in [(dtypes.float32, + (math_ops.reduce_sum, math_ops.reduce_mean, + math_ops.reduce_prod, math_ops.reduce_max, + math_ops.reduce_min, + math_ops.reduce_euclidean_norm)), + (dtypes.bool, (math_ops.reduce_all, + math_ops.reduce_any))]: + for reduction in reductions: + with self.assertRaisesRegex(ValueError, "The truth value"): + x = True if dtype == dtypes.bool else 1 + y = reduction( + input_tensor=x, keepdims=np.array([63600, 1], dtype=np.float16)) + self.evaluate(y) + + class BaseReductionTest(test.TestCase): def _tf_reduce(self, x, reduction_axes, keepdims):