1# Copyright 2015 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Math Operations. 16 17Note: Functions taking `Tensor` arguments can also take anything accepted by 18`tf.convert_to_tensor`. 19 20Note: Elementwise binary operations in TensorFlow follow [numpy-style 21broadcasting](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html). 22 23TensorFlow provides a variety of math functions including: 24 25* Basic arithmetic operators and trigonometric functions. 26* Special math functions (like: `tf.math.igamma` and `tf.math.zeta`) 27* Complex number functions (like: `tf.math.imag` and `tf.math.angle`) 28* Reductions and scans (like: `tf.math.reduce_mean` and `tf.math.cumsum`) 29* Segment functions (like: `tf.math.segment_sum`) 30 31See: `tf.linalg` for matrix and tensor functions. 32 33<a id=Segmentation></a> 34 35## About Segmentation 36 37TensorFlow provides several operations that you can use to perform common 38math computations on tensor segments. 39Here a segmentation is a partitioning of a tensor along 40the first dimension, i.e. it defines a mapping from the first dimension onto 41`segment_ids`. The `segment_ids` tensor should be the size of 42the first dimension, `d0`, with consecutive IDs in the range `0` to `k`, 43where `k<d0`. 44In particular, a segmentation of a matrix tensor is a mapping of rows to 45segments. 46 47For example: 48 49```python 50c = tf.constant([[1,2,3,4], [-1,-2,-3,-4], [5,6,7,8]]) 51tf.math.segment_sum(c, tf.constant([0, 0, 1])) 52# ==> [[0 0 0 0] 53# [5 6 7 8]] 54``` 55 56The standard `segment_*` functions assert that the segment indices are sorted. 57If you have unsorted indices use the equivalent `unsorted_segment_` function. 58These functions take an additional argument `num_segments` so that the output 59tensor can be efficiently allocated. 60 61``` python 62c = tf.constant([[1,2,3,4], [-1,-2,-3,-4], [5,6,7,8]]) 63tf.math.unsorted_segment_sum(c, tf.constant([0, 1, 0]), num_segments=2) 64# ==> [[ 6, 8, 10, 12], 65# [-1, -2, -3, -4]] 66``` 67 68""" 69from __future__ import absolute_import 70from __future__ import division 71from __future__ import print_function 72 73import numbers 74import numpy as np 75import six 76from six.moves import builtins 77from six.moves import xrange # pylint: disable=redefined-builtin 78 79from tensorflow.python.eager import context 80from tensorflow.python.framework import constant_op 81from tensorflow.python.framework import dtypes 82from tensorflow.python.framework import graph_util 83from tensorflow.python.framework import ops 84from tensorflow.python.framework import sparse_tensor 85from tensorflow.python.framework import tensor_shape 86from tensorflow.python.framework import tensor_util 87from tensorflow.python.ops import array_ops 88from tensorflow.python.ops import gen_array_ops 89from tensorflow.python.ops import gen_bitwise_ops 90from tensorflow.python.ops import gen_data_flow_ops 91from tensorflow.python.ops import gen_math_ops 92from tensorflow.python.ops import gen_nn_ops 93from tensorflow.python.ops import gen_sparse_ops 94# go/tf-wildcard-import 95# pylint: disable=wildcard-import 96from tensorflow.python.ops.gen_math_ops import * 97# pylint: enable=wildcard-import 98from tensorflow.python.platform import tf_logging as logging 99from tensorflow.python.util import compat 100from tensorflow.python.util import deprecation 101from tensorflow.python.util import dispatch 102from tensorflow.python.util import nest 103from tensorflow.python.util import tf_decorator 104from tensorflow.python.util.compat import collections_abc 105from tensorflow.python.util.lazy_loader import LazyLoader 106from tensorflow.python.util.tf_export import tf_export 107 108 109np_dtypes = LazyLoader( 110 "np_dtypes", globals(), 111 "tensorflow.python.ops.numpy_ops.np_dtypes") 112 113 114# Aliases for some automatically-generated names. 115nextafter = gen_math_ops.next_after 116 117 118@tf_export("linspace", v1=["lin_space", "linspace"]) 119@dispatch.add_dispatch_support 120@deprecation.deprecated_endpoints("lin_space") 121def linspace_nd(start, stop, num, name=None, axis=0): 122 r"""Generates evenly-spaced values in an interval along a given axis. 123 124 A sequence of `num` evenly-spaced values are generated beginning at `start` 125 along a given `axis`. 126 If `num > 1`, the values in the sequence increase by 127 `(stop - start) / (num - 1)`, so that the last one is exactly `stop`. 128 If `num <= 0`, `ValueError` is raised. 129 130 Matches 131 [np.linspace](https://docs.scipy.org/doc/numpy/reference/generated/numpy.linspace.html)'s 132 behaviour 133 except when `num == 0`. 134 135 For example: 136 137 ``` 138 tf.linspace(10.0, 12.0, 3, name="linspace") => [ 10.0 11.0 12.0] 139 ``` 140 141 `Start` and `stop` can be tensors of arbitrary size: 142 143 >>> tf.linspace([0., 5.], [10., 40.], 5, axis=0) 144 <tf.Tensor: shape=(5, 2), dtype=float32, numpy= 145 array([[ 0. , 5. ], 146 [ 2.5 , 13.75], 147 [ 5. , 22.5 ], 148 [ 7.5 , 31.25], 149 [10. , 40. ]], dtype=float32)> 150 151 `Axis` is where the values will be generated (the dimension in the 152 returned tensor which corresponds to the axis will be equal to `num`) 153 154 >>> tf.linspace([0., 5.], [10., 40.], 5, axis=-1) 155 <tf.Tensor: shape=(2, 5), dtype=float32, numpy= 156 array([[ 0. , 2.5 , 5. , 7.5 , 10. ], 157 [ 5. , 13.75, 22.5 , 31.25, 40. ]], dtype=float32)> 158 159 160 161 Args: 162 start: A `Tensor`. Must be one of the following types: `bfloat16`, 163 `float32`, `float64`. N-D tensor. First entry in the range. 164 stop: A `Tensor`. Must have the same type and shape as `start`. N-D tensor. 165 Last entry in the range. 166 num: A `Tensor`. Must be one of the following types: `int32`, `int64`. 0-D 167 tensor. Number of values to generate. 168 name: A name for the operation (optional). 169 axis: Axis along which the operation is performed (used only when N-D 170 tensors are provided). 171 172 Returns: 173 A `Tensor`. Has the same type as `start`. 174 """ 175 176 with ops.name_scope(name, "linspace", [start, stop]): 177 start = ops.convert_to_tensor(start, name="start") 178 # stop must be convertible to the same dtype as start 179 stop = ops.convert_to_tensor(stop, name="stop", dtype=start.dtype) 180 num_int = array_ops.convert_to_int_tensor(num, name="num") 181 num = cast(num_int, dtype=start.dtype) 182 183 broadcast_shape = array_ops.broadcast_dynamic_shape( 184 array_ops.shape(start), array_ops.shape(stop)) 185 start = array_ops.broadcast_to(start, broadcast_shape) 186 stop = array_ops.broadcast_to(stop, broadcast_shape) 187 188 expanded_start = array_ops.expand_dims(start, axis=axis) 189 expanded_stop = array_ops.expand_dims(stop, axis=axis) 190 191 shape = array_ops.shape(expanded_start) 192 ndims = array_ops.shape(shape)[0] 193 194 axis = array_ops.where_v2(axis >= 0, axis, ndims + axis) 195 196 # The purpose is to avoid having negative values when repeating. 197 num_fill = gen_math_ops.maximum(num_int - 2, 0) 198 # To avoid having negative values in the range or zero division 199 # the result is sliced in the end so a correct result is returned for 200 # num == 1, and num == 0. 201 n_steps = gen_math_ops.maximum(num_int - 1, 1) 202 delta = (expanded_stop - expanded_start) / cast(n_steps, 203 expanded_stop.dtype) 204 # Re-cast tensors as delta. 205 expanded_start = cast(expanded_start, delta.dtype) 206 expanded_stop = cast(expanded_stop, delta.dtype) 207 # If num < 0, we will throw exception in the range 208 # otherwise use the same div for delta 209 range_end = array_ops.where_v2(num_int >= 0, n_steps, -1) 210 # Even though range supports an output dtype, its limited 211 # (e.g. doesn't support half at the moment). 212 desired_range = cast(range(1, range_end, dtype=dtypes.int64), delta.dtype) 213 mask = gen_math_ops.equal(axis, range(ndims)) 214 # desired_range_shape is [1. 1. 1. ... 1. num_fill 1. 1. ... 1.], where the 215 # index of num_fill is equal to axis. 216 desired_range_shape = array_ops.where_v2(mask, num_fill, 1) 217 desired_range = array_ops.reshape(desired_range, desired_range_shape) 218 219 res = expanded_start + delta * desired_range 220 221 # Add the start and endpoints to the result, and slice out the desired 222 # portion. 223 all_tensors = (expanded_start, res, expanded_stop) 224 concatenated = array_ops.concat(all_tensors, axis=axis) 225 begin = array_ops.zeros_like(shape) 226 size = array_ops.where_v2(mask, num_int, shape) 227 228 return array_ops.slice(concatenated, begin, size) 229 230 231linspace = linspace_nd 232 233arg_max = deprecation.deprecated(None, "Use `tf.math.argmax` instead")(arg_max) # pylint: disable=used-before-assignment 234arg_min = deprecation.deprecated(None, "Use `tf.math.argmin` instead")(arg_min) # pylint: disable=used-before-assignment 235tf_export(v1=["arg_max"])(dispatch.add_dispatch_support(arg_max)) 236tf_export(v1=["arg_min"])(dispatch.add_dispatch_support(arg_min)) 237 238 239# This is set by resource_variable_ops.py. It is included in this way since 240# there is a circular dependency between math_ops and resource_variable_ops 241_resource_variable_type = None 242 243 244def _set_doc(doc): 245 246 def _decorator(func): 247 func.__doc__ = doc 248 return func 249 250 return _decorator 251 252 253# pylint: disable=redefined-builtin 254@tf_export(v1=["math.argmax", "argmax"]) 255@dispatch.add_dispatch_support 256@deprecation.deprecated_args(None, "Use the `axis` argument instead", 257 "dimension") 258@_set_doc( 259 gen_math_ops.arg_max.__doc__.replace("dimensions", 260 "axes").replace("dimension", "axis")) 261def argmax(input, 262 axis=None, 263 name=None, 264 dimension=None, 265 output_type=dtypes.int64): 266 axis = deprecation.deprecated_argument_lookup("axis", axis, "dimension", 267 dimension) 268 return argmax_v2(input, axis, output_type, name) 269 270 271@tf_export("math.argmax", "argmax", v1=[]) 272@dispatch.add_dispatch_support 273def argmax_v2(input, axis=None, output_type=dtypes.int64, name=None): 274 """Returns the index with the largest value across axes of a tensor. 275 276 In case of identity returns the smallest index. 277 278 For example: 279 280 >>> A = tf.constant([2, 20, 30, 3, 6]) 281 >>> tf.math.argmax(A) # A[2] is maximum in tensor A 282 <tf.Tensor: shape=(), dtype=int64, numpy=2> 283 >>> B = tf.constant([[2, 20, 30, 3, 6], [3, 11, 16, 1, 8], 284 ... [14, 45, 23, 5, 27]]) 285 >>> tf.math.argmax(B, 0) 286 <tf.Tensor: shape=(5,), dtype=int64, numpy=array([2, 2, 0, 2, 2])> 287 >>> tf.math.argmax(B, 1) 288 <tf.Tensor: shape=(3,), dtype=int64, numpy=array([2, 2, 1])> 289 >>> C = tf.constant([0, 0, 0, 0]) 290 >>> tf.math.argmax(C) # Returns smallest index in case of ties 291 <tf.Tensor: shape=(), dtype=int64, numpy=0> 292 293 Args: 294 input: A `Tensor`. 295 axis: An integer, the axis to reduce across. Default to 0. 296 output_type: An optional output dtype (`tf.int32` or `tf.int64`). Defaults 297 to `tf.int64`. 298 name: An optional name for the operation. 299 300 Returns: 301 A `Tensor` of type `output_type`. 302 """ 303 if axis is None: 304 axis = 0 305 return gen_math_ops.arg_max(input, axis, name=name, output_type=output_type) 306 307 308@tf_export(v1=["math.argmin", "argmin"]) 309@dispatch.add_dispatch_support 310@deprecation.deprecated_args(None, "Use the `axis` argument instead", 311 "dimension") 312@_set_doc( 313 gen_math_ops.arg_min.__doc__.replace("dimensions", 314 "axes").replace("dimension", "axis")) 315def argmin(input, 316 axis=None, 317 name=None, 318 dimension=None, 319 output_type=dtypes.int64): 320 axis = deprecation.deprecated_argument_lookup("axis", axis, "dimension", 321 dimension) 322 return argmin_v2(input, axis, output_type, name) 323 324 325@tf_export("math.argmin", "argmin", v1=[]) 326@dispatch.add_dispatch_support 327def argmin_v2(input, axis=None, output_type=dtypes.int64, name=None): 328 """Returns the index with the smallest value across axes of a tensor. 329 330 Returns the smallest index in case of ties. 331 332 Args: 333 input: A `Tensor`. Must be one of the following types: `float32`, `float64`, 334 `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, `qint8`, 335 `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, `uint32`, 336 `uint64`. 337 axis: A `Tensor`. Must be one of the following types: `int32`, `int64`. 338 int32 or int64, must be in the range `-rank(input), rank(input))`. 339 Describes which axis of the input Tensor to reduce across. For vectors, 340 use axis = 0. 341 output_type: An optional `tf.DType` from: `tf.int32, tf.int64`. Defaults to 342 `tf.int64`. 343 name: A name for the operation (optional). 344 345 Returns: 346 A `Tensor` of type `output_type`. 347 348 Usage: 349 ```python 350 import tensorflow as tf 351 a = [1, 10, 26.9, 2.8, 166.32, 62.3] 352 b = tf.math.argmin(input = a) 353 c = tf.keras.backend.eval(b) 354 # c = 0 355 # here a[0] = 1 which is the smallest element of a across axis 0 356 ``` 357 """ 358 if axis is None: 359 axis = 0 360 return gen_math_ops.arg_min(input, axis, name=name, output_type=output_type) 361 362 363# pylint: enable=redefined-builtin 364 365 366# pylint: disable=anomalous-backslash-in-string,protected-access 367# pylint: disable=g-docstring-has-escape 368@tf_export("math.abs", "abs") 369@dispatch.add_dispatch_support 370def abs(x, name=None): # pylint: disable=redefined-builtin 371 r"""Computes the absolute value of a tensor. 372 373 Given a tensor of integer or floating-point values, this operation returns a 374 tensor of the same type, where each element contains the absolute value of the 375 corresponding element in the input. 376 377 Given a tensor `x` of complex numbers, this operation returns a tensor of type 378 `float32` or `float64` that is the absolute value of each element in `x`. For 379 a complex number \\(a + bj\\), its absolute value is computed as 380 \\(\sqrt{a^2 + b^2}\\). 381 382 For example: 383 384 >>> # real number 385 >>> x = tf.constant([-2.25, 3.25]) 386 >>> tf.abs(x) 387 <tf.Tensor: shape=(2,), dtype=float32, 388 numpy=array([2.25, 3.25], dtype=float32)> 389 390 >>> # complex number 391 >>> x = tf.constant([[-2.25 + 4.75j], [-3.25 + 5.75j]]) 392 >>> tf.abs(x) 393 <tf.Tensor: shape=(2, 1), dtype=float64, numpy= 394 array([[5.25594901], 395 [6.60492241]])> 396 397 Args: 398 x: A `Tensor` or `SparseTensor` of type `float16`, `float32`, `float64`, 399 `int32`, `int64`, `complex64` or `complex128`. 400 name: A name for the operation (optional). 401 402 Returns: 403 A `Tensor` or `SparseTensor` of the same size, type and sparsity as `x`, 404 with absolute values. Note, for `complex64` or `complex128` input, the 405 returned `Tensor` will be of type `float32` or `float64`, respectively. 406 """ 407 with ops.name_scope(name, "Abs", [x]) as name: 408 x = ops.convert_to_tensor(x, name="x") 409 if x.dtype.is_complex: 410 return gen_math_ops.complex_abs(x, Tout=x.dtype.real_dtype, name=name) 411 return gen_math_ops._abs(x, name=name) 412 413 414# pylint: enable=g-docstring-has-escape 415 416 417# pylint: disable=redefined-builtin 418def _bucketize(input, boundaries, name=None): 419 return gen_math_ops.bucketize(input=input, boundaries=boundaries, name=name) 420 421 422# pylint: enable=redefined-builtin 423 424 425class DivideDelegateWithName(object): 426 """Use Python2/Python3 division delegation to implement divide for tensors.""" 427 428 def __init__(self, x, name): 429 """Construct DivideDelegateWithName. 430 431 Args: 432 x: Tensor to use as left operand in operator overloads 433 name: The name that is preferred for the op created. 434 """ 435 self.x = x 436 self.name = name 437 438 def __truediv__(self, y): 439 return _truediv_python3(self.x, y, self.name) 440 441 def __floordiv__(self, y): 442 return floordiv(self.x, y, self.name) 443 444 def __div__(self, y): 445 return _div_python2(self.x, y, self.name) 446 447 448@tf_export("math.divide", "divide") 449@dispatch.add_dispatch_support 450def divide(x, y, name=None): 451 """Computes Python style division of `x` by `y`. 452 453 For example: 454 455 >>> x = tf.constant([16, 12, 11]) 456 >>> y = tf.constant([4, 6, 2]) 457 >>> tf.divide(x,y) 458 <tf.Tensor: shape=(3,), dtype=float64, 459 numpy=array([4. , 2. , 5.5])> 460 461 Args: 462 x: A `Tensor` 463 y: A `Tensor` 464 name: A name for the operation (optional). 465 466 Returns: 467 A `Tensor` with same shape as input 468 """ 469 470 if name is not None: 471 # Cannot use tensors operator overload, because it has no way to track 472 # override names. Use a dummy class to track the runtime division behavior 473 return DivideDelegateWithName(x, name) / y 474 else: 475 # We do conversion here to make sure at least x is a tensor. 476 if not tensor_util.is_tf_type(x): 477 dtype = y.dtype.base_dtype if tensor_util.is_tf_type(y) else None 478 x = ops.convert_to_tensor(x, dtype=dtype) 479 return x / y 480 481 482@tf_export("math.multiply", "multiply") 483@dispatch.add_dispatch_support 484def multiply(x, y, name=None): 485 """Returns an element-wise x * y. 486 487 For example: 488 489 >>> x = tf.constant(([1, 2, 3, 4])) 490 >>> tf.math.multiply(x, x) 491 <tf.Tensor: shape=(4,), dtype=..., numpy=array([ 1, 4, 9, 16], dtype=int32)> 492 493 Since `tf.math.multiply` will convert its arguments to `Tensor`s, you can also 494 pass in non-`Tensor` arguments: 495 496 >>> tf.math.multiply(7,6) 497 <tf.Tensor: shape=(), dtype=int32, numpy=42> 498 499 If `x.shape` is not the same as `y.shape`, they will be broadcast to a 500 compatible shape. (More about broadcasting 501 [here](https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html).) 502 503 For example: 504 505 >>> x = tf.ones([1, 2]); 506 >>> y = tf.ones([2, 1]); 507 >>> x * y # Taking advantage of operator overriding 508 <tf.Tensor: shape=(2, 2), dtype=float32, numpy= 509 array([[1., 1.], 510 [1., 1.]], dtype=float32)> 511 512 The reduction version of this elementwise operation is `tf.math.reduce_prod` 513 514 Args: 515 x: A Tensor. Must be one of the following types: `bfloat16`, 516 `half`, `float32`, `float64`, `uint8`, `int8`, `uint16`, 517 `int16`, `int32`, `int64`, `complex64`, `complex128`. 518 y: A `Tensor`. Must have the same type as `x`. 519 name: A name for the operation (optional). 520 521 Returns: 522 523 A `Tensor`. Has the same type as `x`. 524 525 Raises: 526 527 * InvalidArgumentError: When `x` and `y` have incompatible shapes or types. 528 """ 529 530 return gen_math_ops.mul(x, y, name) 531 532 533# TODO(aselle): put deprecation in after another round of global code changes 534@deprecation.deprecated( 535 "2016-12-30", 536 "`tf.mul(x, y)` is deprecated; use `tf.math.multiply(x, y)` or `x * y`") 537def _mul(x, y, name=None): 538 return gen_math_ops.mul(x, y, name) 539 540 541_mul.__doc__ = ( 542 gen_math_ops.mul.__doc__ + ("" if _mul.__doc__ is None else _mul.__doc__)) 543 544 545@tf_export("math.subtract", "subtract") 546@dispatch.add_dispatch_support 547def subtract(x, y, name=None): 548 return gen_math_ops.sub(x, y, name) 549 550 551subtract.__doc__ = gen_math_ops.sub.__doc__ 552 553 554# TODO(aselle): put deprecation in after another round of global code changes 555@deprecation.deprecated( 556 "2016-12-30", 557 "`tf.sub(x, y)` is deprecated, please use `tf.subtract(x, y)` or `x - y`") 558def _sub(x, y, name=None): 559 return gen_math_ops.sub(x, y, name) 560 561 562_sub.__doc__ = ( 563 gen_math_ops.sub.__doc__ + ("" if _sub.__doc__ is None else _sub.__doc__)) 564 565negative = gen_math_ops.neg 566 567 568# pylint: disable=g-docstring-has-escape 569@deprecation.deprecated( 570 "2016-12-30", 571 "`tf.neg(x)` is deprecated, please use `tf.negative(x)` or `-x`") 572def _neg(x, name=None): 573 """Computes numerical negative value element-wise. 574 575 I.e., \\(y = -x\\). 576 577 Args: 578 x: A `Tensor` or `SparseTensor`. Must be one of the following types: `half`, 579 `float32`, `float64`, `int32`, `int64`, `complex64`, `complex128`. 580 name: A name for the operation (optional). 581 582 Returns: 583 A `Tensor` or `SparseTensor`, respectively. Has the same type as `x`. 584 """ 585 return negative(x, name) 586 587 588# pylint: enable=g-docstring-has-escape 589 590 591@tf_export(v1=["math.scalar_mul", "scalar_mul"]) 592@dispatch.add_dispatch_support 593def scalar_mul(scalar, x, name=None): 594 """Multiplies a scalar times a `Tensor` or `IndexedSlices` object. 595 596 Intended for use in gradient code which might deal with `IndexedSlices` 597 objects, which are easy to multiply by a scalar but more expensive to 598 multiply with arbitrary tensors. 599 600 Args: 601 scalar: A 0-D scalar `Tensor`. Must have known shape. 602 x: A `Tensor` or `IndexedSlices` to be scaled. 603 name: A name for the operation (optional). 604 605 Returns: 606 `scalar * x` of the same type (`Tensor` or `IndexedSlices`) as `x`. 607 608 Raises: 609 ValueError: if scalar is not a 0-D `scalar`. 610 """ 611 scalar = ops.convert_to_tensor( 612 scalar, dtype=x.dtype.base_dtype, name="scalar") 613 shape = scalar.get_shape() 614 if shape.ndims == 0: 615 if isinstance(x, ops.IndexedSlices): 616 return ops.IndexedSlices( 617 gen_math_ops.mul(scalar, x.values, name), x.indices, x.dense_shape) 618 else: 619 return gen_math_ops.mul(scalar, x, name) 620 else: 621 raise ValueError("Only scalar multiply works, got shape %s" % shape) 622 623 624@tf_export("math.scalar_mul", "scalar_mul", v1=[]) 625@dispatch.add_dispatch_support 626@_set_doc(scalar_mul.__doc__) 627def scalar_mul_v2(scalar, x, name=None): 628 with ops.name_scope(name, "scalar_mul", [x]) as name: 629 return scalar_mul(scalar, x, name) 630 631 632@tf_export("math.pow", "pow") 633@dispatch.add_dispatch_support 634def pow(x, y, name=None): # pylint: disable=redefined-builtin 635 r"""Computes the power of one value to another. 636 637 Given a tensor `x` and a tensor `y`, this operation computes \\(x^y\\) for 638 corresponding elements in `x` and `y`. For example: 639 640 ```python 641 x = tf.constant([[2, 2], [3, 3]]) 642 y = tf.constant([[8, 16], [2, 3]]) 643 tf.pow(x, y) # [[256, 65536], [9, 27]] 644 ``` 645 646 Args: 647 x: A `Tensor` of type `float16`, `float32`, `float64`, `int32`, `int64`, 648 `complex64`, or `complex128`. 649 y: A `Tensor` of type `float16`, `float32`, `float64`, `int32`, `int64`, 650 `complex64`, or `complex128`. 651 name: A name for the operation (optional). 652 653 Returns: 654 A `Tensor`. 655 """ 656 with ops.name_scope(name, "Pow", [x]) as name: 657 return gen_math_ops._pow(x, y, name=name) 658 659 660# pylint: disable=redefined-builtin,redefined-outer-name 661@tf_export("dtypes.complex", "complex") 662@dispatch.add_dispatch_support 663def complex(real, imag, name=None): 664 r"""Converts two real numbers to a complex number. 665 666 Given a tensor `real` representing the real part of a complex number, and a 667 tensor `imag` representing the imaginary part of a complex number, this 668 operation returns complex numbers elementwise of the form \\(a + bj\\), where 669 *a* represents the `real` part and *b* represents the `imag` part. 670 671 The input tensors `real` and `imag` must have the same shape. 672 673 For example: 674 675 ```python 676 real = tf.constant([2.25, 3.25]) 677 imag = tf.constant([4.75, 5.75]) 678 tf.complex(real, imag) # [[2.25 + 4.75j], [3.25 + 5.75j]] 679 ``` 680 681 Args: 682 real: A `Tensor`. Must be one of the following types: `float32`, `float64`. 683 imag: A `Tensor`. Must have the same type as `real`. 684 name: A name for the operation (optional). 685 686 Returns: 687 A `Tensor` of type `complex64` or `complex128`. 688 689 Raises: 690 TypeError: Real and imag must be correct types 691 """ 692 real = ops.convert_to_tensor(real, name="real") 693 imag = ops.convert_to_tensor(imag, name="imag") 694 with ops.name_scope(name, "Complex", [real, imag]) as name: 695 input_types = (real.dtype, imag.dtype) 696 if input_types == (dtypes.float64, dtypes.float64): 697 Tout = dtypes.complex128 698 elif input_types == (dtypes.float32, dtypes.float32): 699 Tout = dtypes.complex64 700 else: 701 raise TypeError("real and imag have incorrect types: " 702 "{} {}".format(real.dtype.name, imag.dtype.name)) 703 return gen_math_ops._complex(real, imag, Tout=Tout, name=name) 704 705 706@tf_export("math.sign", "sign") 707@dispatch.add_dispatch_support 708def sign(x, name=None): 709 r"""Returns an element-wise indication of the sign of a number. 710 711 `y = sign(x) = -1 if x < 0; 0 if x == 0; 1 if x > 0`. 712 713 For complex numbers, `y = sign(x) = x / |x| if x != 0, otherwise y = 0`. 714 715 Example usage: 716 717 >>> # real number 718 >>> tf.math.sign([0., 2., -3.]) 719 <tf.Tensor: shape=(3,), dtype=float32, 720 numpy=array([ 0., 1., -1.], dtype=float32)> 721 722 >>> # complex number 723 >>> tf.math.sign([1 + 1j, 0 + 0j]) 724 <tf.Tensor: shape=(2,), dtype=complex128, 725 numpy=array([0.70710678+0.70710678j, 0. +0.j ])> 726 727 Args: 728 x: A Tensor. Must be one of the following types: bfloat16, half, float32, 729 float64, int32, int64, complex64, complex128. 730 name: A name for the operation (optional). 731 732 Returns: 733 A Tensor. Has the same type as x. 734 735 If x is a SparseTensor, returns SparseTensor(x.indices, 736 tf.math.sign(x.values, ...), x.dense_shape). 737 """ 738 x = ops.convert_to_tensor(x) 739 if x.dtype.is_complex: 740 return gen_math_ops.div_no_nan( 741 x, 742 cast( 743 gen_math_ops.complex_abs( 744 x, 745 Tout=dtypes.float32 746 if x.dtype == dtypes.complex64 else dtypes.float64), 747 dtype=x.dtype), 748 name=name) 749 return gen_math_ops.sign(x, name=name) 750 751 752@tf_export("math.real", v1=["math.real", "real"]) 753@dispatch.add_dispatch_support 754@deprecation.deprecated_endpoints("real") 755@dispatch.add_dispatch_support 756def real(input, name=None): 757 r"""Returns the real part of a complex (or real) tensor. 758 759 Given a tensor `input`, this operation returns a tensor of type `float` that 760 is the real part of each element in `input` considered as a complex number. 761 762 For example: 763 764 ```python 765 x = tf.constant([-2.25 + 4.75j, 3.25 + 5.75j]) 766 tf.math.real(x) # [-2.25, 3.25] 767 ``` 768 769 If `input` is already real, it is returned unchanged. 770 771 Args: 772 input: A `Tensor`. Must have numeric type. 773 name: A name for the operation (optional). 774 775 Returns: 776 A `Tensor` of type `float32` or `float64`. 777 """ 778 with ops.name_scope(name, "Real", [input]) as name: 779 input = ops.convert_to_tensor(input, name="input") 780 if input.dtype.is_complex: 781 real_dtype = input.dtype.real_dtype 782 return gen_math_ops.real(input, Tout=real_dtype, name=name) 783 else: 784 return input 785 786 787@tf_export("math.imag", v1=["math.imag", "imag"]) 788@dispatch.add_dispatch_support 789@deprecation.deprecated_endpoints("imag") 790@dispatch.add_dispatch_support 791def imag(input, name=None): 792 r"""Returns the imaginary part of a complex (or real) tensor. 793 794 Given a tensor `input`, this operation returns a tensor of type `float` that 795 is the imaginary part of each element in `input` considered as a complex 796 number. If `input` is real, a tensor of all zeros is returned. 797 798 For example: 799 800 ```python 801 x = tf.constant([-2.25 + 4.75j, 3.25 + 5.75j]) 802 tf.math.imag(x) # [4.75, 5.75] 803 ``` 804 805 Args: 806 input: A `Tensor`. Must be one of the following types: `float`, `double`, 807 `complex64`, `complex128`. 808 name: A name for the operation (optional). 809 810 Returns: 811 A `Tensor` of type `float32` or `float64`. 812 """ 813 with ops.name_scope(name, "Imag", [input]) as name: 814 input = ops.convert_to_tensor(input, name="input") 815 if input.dtype.is_complex: 816 return gen_math_ops.imag(input, Tout=input.dtype.real_dtype, name=name) 817 else: 818 return array_ops.zeros_like(input) 819 820 821@tf_export("math.angle", v1=["math.angle", "angle"]) 822@dispatch.add_dispatch_support 823@deprecation.deprecated_endpoints("angle") 824@dispatch.add_dispatch_support 825def angle(input, name=None): 826 r"""Returns the element-wise argument of a complex (or real) tensor. 827 828 Given a tensor `input`, this operation returns a tensor of type `float` that 829 is the argument of each element in `input` considered as a complex number. 830 831 The elements in `input` are considered to be complex numbers of the form 832 \\(a + bj\\), where *a* is the real part and *b* is the imaginary part. 833 If `input` is real then *b* is zero by definition. 834 835 The argument returned by this function is of the form \\(atan2(b, a)\\). 836 If `input` is real, a tensor of all zeros is returned. 837 838 For example: 839 840 ``` 841 input = tf.constant([-2.25 + 4.75j, 3.25 + 5.75j], dtype=tf.complex64) 842 tf.math.angle(input).numpy() 843 # ==> array([2.0131705, 1.056345 ], dtype=float32) 844 ``` 845 846 Args: 847 input: A `Tensor`. Must be one of the following types: `float`, `double`, 848 `complex64`, `complex128`. 849 name: A name for the operation (optional). 850 851 Returns: 852 A `Tensor` of type `float32` or `float64`. 853 """ 854 with ops.name_scope(name, "Angle", [input]) as name: 855 input = ops.convert_to_tensor(input, name="input") 856 if input.dtype.is_complex: 857 return gen_math_ops.angle(input, Tout=input.dtype.real_dtype, name=name) 858 else: 859 return array_ops.where(input < 0, np.pi * array_ops.ones_like(input), 860 array_ops.zeros_like(input)) 861 862 863# pylint: enable=redefined-outer-name,redefined-builtin 864 865 866@tf_export("math.round", "round") 867@dispatch.add_dispatch_support 868def round(x, name=None): # pylint: disable=redefined-builtin 869 """Rounds the values of a tensor to the nearest integer, element-wise. 870 871 Rounds half to even. Also known as bankers rounding. If you want to round 872 according to the current system rounding mode use tf::cint. 873 For example: 874 875 ```python 876 x = tf.constant([0.9, 2.5, 2.3, 1.5, -4.5]) 877 tf.round(x) # [ 1.0, 2.0, 2.0, 2.0, -4.0 ] 878 ``` 879 880 Args: 881 x: A `Tensor` of type `float16`, `float32`, `float64`, `int32`, or `int64`. 882 name: A name for the operation (optional). 883 884 Returns: 885 A `Tensor` of same shape and type as `x`. 886 """ 887 x = ops.convert_to_tensor(x, name="x") 888 if x.dtype.is_integer: 889 return x 890 else: 891 return gen_math_ops.round(x, name=name) 892 893 894@tf_export("cast", "dtypes.cast") 895@dispatch.add_dispatch_support 896def cast(x, dtype, name=None): 897 """Casts a tensor to a new type. 898 899 The operation casts `x` (in case of `Tensor`) or `x.values` 900 (in case of `SparseTensor` or `IndexedSlices`) to `dtype`. 901 902 For example: 903 904 >>> x = tf.constant([1.8, 2.2], dtype=tf.float32) 905 >>> tf.cast(x, tf.int32) 906 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([1, 2], dtype=int32)> 907 908 Notice `tf.cast` has an alias `tf.dtypes.cast`: 909 910 >>> x = tf.constant([1.8, 2.2], dtype=tf.float32) 911 >>> tf.dtypes.cast(x, tf.int32) 912 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([1, 2], dtype=int32)> 913 914 The operation supports data types (for `x` and `dtype`) of 915 `uint8`, `uint16`, `uint32`, `uint64`, `int8`, `int16`, `int32`, `int64`, 916 `float16`, `float32`, `float64`, `complex64`, `complex128`, `bfloat16`. 917 In case of casting from complex types (`complex64`, `complex128`) to real 918 types, only the real part of `x` is returned. In case of casting from real 919 types to complex types (`complex64`, `complex128`), the imaginary part of the 920 returned value is set to `0`. The handling of complex types here matches the 921 behavior of numpy. 922 923 Note casting nan and inf values to integral types has undefined behavior. 924 925 Args: 926 x: A `Tensor` or `SparseTensor` or `IndexedSlices` of numeric type. It could 927 be `uint8`, `uint16`, `uint32`, `uint64`, `int8`, `int16`, `int32`, 928 `int64`, `float16`, `float32`, `float64`, `complex64`, `complex128`, 929 `bfloat16`. 930 dtype: The destination type. The list of supported dtypes is the same as 931 `x`. 932 name: A name for the operation (optional). 933 934 Returns: 935 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` and 936 same type as `dtype`. 937 938 Raises: 939 TypeError: If `x` cannot be cast to the `dtype`. 940 """ 941 base_type = dtypes.as_dtype(dtype).base_dtype 942 if isinstance(x, 943 (ops.Tensor, _resource_variable_type)) and base_type == x.dtype: 944 return x 945 with ops.name_scope(name, "Cast", [x]) as name: 946 if isinstance(x, sparse_tensor.SparseTensor): 947 values_cast = cast(x.values, base_type, name=name) 948 x = sparse_tensor.SparseTensor(x.indices, values_cast, x.dense_shape) 949 elif isinstance(x, ops.IndexedSlices): 950 values_cast = cast(x.values, base_type, name=name) 951 x = ops.IndexedSlices(values_cast, x.indices, x.dense_shape) 952 else: 953 # TODO(josh11b): If x is not already a Tensor, we could return 954 # ops.convert_to_tensor(x, dtype=dtype, ...) here, but that 955 # allows some conversions that cast() can't do, e.g. casting numbers to 956 # strings. 957 x = ops.convert_to_tensor(x, name="x") 958 if x.dtype.base_dtype != base_type: 959 x = gen_math_ops.cast(x, base_type, name=name) 960 if x.dtype.is_complex and base_type.is_floating: 961 logging.warn("Casting complex to real discards imaginary part.") 962 return x 963 964 965@tf_export("dtypes.saturate_cast", "saturate_cast") 966@dispatch.add_dispatch_support 967def saturate_cast(value, dtype, name=None): 968 """Performs a safe saturating cast of `value` to `dtype`. 969 970 This function casts the input to `dtype` without applying any scaling. If 971 there is a danger that values would over or underflow in the cast, this op 972 applies the appropriate clamping before the cast. 973 974 Args: 975 value: A `Tensor`. 976 dtype: The desired output `DType`. 977 name: A name for the operation (optional). 978 979 Returns: 980 `value` safely cast to `dtype`. 981 """ 982 # When casting to a type with smaller representable range, clamp. 983 # Note that this covers casting to unsigned types as well. 984 with ops.name_scope(name, "saturate_cast", [value]) as name: 985 value = ops.convert_to_tensor(value, name="value") 986 dtype = dtypes.as_dtype(dtype).base_dtype 987 if value.dtype.min < dtype.min: 988 value = gen_math_ops.maximum( 989 value, 990 ops.convert_to_tensor(dtype.min, dtype=value.dtype, name="min")) 991 if value.dtype.max > dtype.max: 992 value = gen_math_ops.minimum( 993 value, 994 ops.convert_to_tensor(dtype.max, dtype=value.dtype, name="max")) 995 return cast(value, dtype, name=name) 996 997 998@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 999@tf_export(v1=["to_float"]) 1000@dispatch.add_dispatch_support 1001def to_float(x, name="ToFloat"): 1002 """Casts a tensor to type `float32`. 1003 1004 Args: 1005 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1006 name: A name for the operation (optional). 1007 1008 Returns: 1009 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1010 type `float32`. 1011 1012 Raises: 1013 TypeError: If `x` cannot be cast to the `float32`. 1014 """ 1015 return cast(x, dtypes.float32, name=name) 1016 1017 1018@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 1019@tf_export(v1=["to_double"]) 1020@dispatch.add_dispatch_support 1021def to_double(x, name="ToDouble"): 1022 """Casts a tensor to type `float64`. 1023 1024 Args: 1025 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1026 name: A name for the operation (optional). 1027 1028 Returns: 1029 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1030 type `float64`. 1031 1032 Raises: 1033 TypeError: If `x` cannot be cast to the `float64`. 1034 """ 1035 return cast(x, dtypes.float64, name=name) 1036 1037 1038@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 1039@tf_export(v1=["to_int32"]) 1040@dispatch.add_dispatch_support 1041def to_int32(x, name="ToInt32"): 1042 """Casts a tensor to type `int32`. 1043 1044 Args: 1045 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1046 name: A name for the operation (optional). 1047 1048 Returns: 1049 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1050 type `int32`. 1051 1052 Raises: 1053 TypeError: If `x` cannot be cast to the `int32`. 1054 """ 1055 return cast(x, dtypes.int32, name=name) 1056 1057 1058@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 1059@tf_export(v1=["to_int64"]) 1060@dispatch.add_dispatch_support 1061def to_int64(x, name="ToInt64"): 1062 """Casts a tensor to type `int64`. 1063 1064 Args: 1065 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1066 name: A name for the operation (optional). 1067 1068 Returns: 1069 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1070 type `int64`. 1071 1072 Raises: 1073 TypeError: If `x` cannot be cast to the `int64`. 1074 """ 1075 return cast(x, dtypes.int64, name=name) 1076 1077 1078@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 1079@tf_export(v1=["to_bfloat16"]) 1080@dispatch.add_dispatch_support 1081def to_bfloat16(x, name="ToBFloat16"): 1082 """Casts a tensor to type `bfloat16`. 1083 1084 Args: 1085 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1086 name: A name for the operation (optional). 1087 1088 Returns: 1089 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1090 type `bfloat16`. 1091 1092 Raises: 1093 TypeError: If `x` cannot be cast to the `bfloat16`. 1094 """ 1095 return cast(x, dtypes.bfloat16, name=name) 1096 1097 1098@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 1099@tf_export(v1=["to_complex64"]) 1100@dispatch.add_dispatch_support 1101def to_complex64(x, name="ToComplex64"): 1102 """Casts a tensor to type `complex64`. 1103 1104 Args: 1105 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1106 name: A name for the operation (optional). 1107 1108 Returns: 1109 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1110 type `complex64`. 1111 1112 Raises: 1113 TypeError: If `x` cannot be cast to the `complex64`. 1114 """ 1115 return cast(x, dtypes.complex64, name=name) 1116 1117 1118@deprecation.deprecated(date=None, instructions="Use `tf.cast` instead.") 1119@tf_export(v1=["to_complex128"]) 1120@dispatch.add_dispatch_support 1121def to_complex128(x, name="ToComplex128"): 1122 """Casts a tensor to type `complex128`. 1123 1124 Args: 1125 x: A `Tensor` or `SparseTensor` or `IndexedSlices`. 1126 name: A name for the operation (optional). 1127 1128 Returns: 1129 A `Tensor` or `SparseTensor` or `IndexedSlices` with same shape as `x` with 1130 type `complex128`. 1131 1132 Raises: 1133 TypeError: If `x` cannot be cast to the `complex128`. 1134 """ 1135 return cast(x, dtypes.complex128, name=name) 1136 1137 1138ops.Tensor._override_operator("__neg__", gen_math_ops.neg) 1139ops.Tensor._override_operator("__abs__", abs) 1140 1141 1142def _maybe_get_dtype(x): 1143 """Returns a numpy type if available from x. Skips if x is numpy.ndarray.""" 1144 # Don't put np.ndarray in this list, because np.result_type looks at the 1145 # value (not just dtype) of np.ndarray to decide the result type. 1146 if isinstance(x, numbers.Real): 1147 return x 1148 if isinstance(x, ops.Tensor): 1149 return x.dtype.as_numpy_dtype 1150 if isinstance(x, dtypes.DType): 1151 return x.as_numpy_dtype 1152 if isinstance(x, tensor_shape.TensorShape): 1153 return np.int32 1154 if isinstance(x, (list, tuple)): 1155 raise ValueError("Got sequence {}".format(x)) 1156 return x 1157 1158 1159def maybe_promote_tensors(*tensors, force_same_dtype=True): 1160 """Promote tensors if numpy style promotion is enabled.""" 1161 if not tensors: 1162 return tensors 1163 if not ops._numpy_style_type_promotion: 1164 if not force_same_dtype: 1165 return tensors 1166 promoted_tensors = [] 1167 promoted_tensors.append(tensors[0]) 1168 dtype = tensors[0].dtype.base_dtype 1169 for tensor in tensors[1:]: 1170 promoted_tensors.append( 1171 ops.convert_to_tensor(tensor, dtype, name="x")) 1172 return promoted_tensors 1173 result_type = np_dtypes._result_type( 1174 *[_maybe_get_dtype(x) for x in nest.flatten(tensors)]) 1175 def _promote_or_cast(x): 1176 if isinstance(x, ops.Tensor): 1177 x = cast(x, result_type) 1178 else: 1179 x = ops.convert_to_tensor(x, result_type) 1180 return x 1181 return [_promote_or_cast(x) for x in tensors] 1182 1183 1184def _OverrideBinaryOperatorHelper(func, op_name, clazz_object=ops.Tensor): 1185 """Register operators with different tensor and scalar versions. 1186 1187 If `clazz_object` is `SparseTensor`, assumes `func` takes `(sp_indices, 1188 sp_values, sp_shape, dense)` and outputs `(new_sp_values)`. 1189 1190 Args: 1191 func: the operator 1192 op_name: name of the operator being overridden 1193 clazz_object: class to override for. Either `Tensor` or `SparseTensor`. 1194 """ 1195 1196 def binary_op_wrapper(x, y): 1197 with ops.name_scope(None, op_name, [x, y]) as name: 1198 try: 1199 # force_same_dtype=False to preserve existing TF behavior 1200 # TODO(b/178860388): Figure out why binary_op_wrapper and 1201 # r_binary_op_wrapper use different force_same_dtype values. 1202 x, y = maybe_promote_tensors(x, y, force_same_dtype=False) 1203 return func(x, y, name=name) 1204 except (TypeError, ValueError) as e: 1205 # Even if dispatching the op failed, the RHS may be a tensor aware 1206 # object that can implement the operator with knowledge of itself 1207 # and the tensor. 1208 # If the RHS is not tensor aware we still want to raise the 1209 # original error from the LHS, because it may be more 1210 # informative. 1211 if hasattr(type(y), "__r%s__" % op_name): 1212 try: 1213 r_op = getattr(y, "__r%s__" % op_name) 1214 out = r_op(x) 1215 if out is NotImplemented: 1216 raise 1217 return out 1218 except (TypeError, ValueError): 1219 raise e 1220 else: 1221 raise 1222 1223 def binary_op_wrapper_sparse(sp_x, y): 1224 with ops.name_scope(None, op_name, [sp_x, y]) as name: 1225 y = ops.convert_to_tensor(y, dtype=sp_x.dtype.base_dtype, name="y") 1226 return sparse_tensor.SparseTensor( 1227 sp_x.indices, 1228 func(sp_x.indices, sp_x.values, sp_x.dense_shape, y, name=name), 1229 sp_x.dense_shape) 1230 1231 def r_binary_op_wrapper(y, x): 1232 with ops.name_scope(None, op_name, [x, y]) as name: 1233 # TODO(b/178860388): Figure out why binary_op_wrapper and 1234 # r_binary_op_wrapper use different force_same_dtype values. 1235 y, x = maybe_promote_tensors(y, x) 1236 return func(x, y, name=name) 1237 1238 # Propagate func.__doc__ to the wrappers 1239 try: 1240 doc = func.__doc__ 1241 except AttributeError: 1242 doc = None 1243 binary_op_wrapper.__doc__ = doc 1244 r_binary_op_wrapper.__doc__ = doc 1245 binary_op_wrapper_sparse.__doc__ = doc 1246 1247 if clazz_object is ops.Tensor: 1248 clazz_object._override_operator("__%s__" % op_name, binary_op_wrapper) 1249 del binary_op_wrapper 1250 clazz_object._override_operator("__r%s__" % op_name, r_binary_op_wrapper) 1251 del r_binary_op_wrapper 1252 else: 1253 clazz_object._override_operator("__%s__" % op_name, 1254 binary_op_wrapper_sparse) 1255 del binary_op_wrapper_sparse 1256 1257 1258# Conversion table for __truediv__. None entries mean no conversion required. 1259_TRUEDIV_TABLE = { 1260 dtypes.uint8: dtypes.float32, 1261 dtypes.int8: dtypes.float32, 1262 dtypes.uint16: dtypes.float32, 1263 dtypes.int16: dtypes.float32, 1264 dtypes.int32: dtypes.float64, 1265 dtypes.int64: dtypes.float64, 1266 dtypes.bfloat16: None, 1267 dtypes.float16: None, 1268 dtypes.float32: None, 1269 dtypes.float64: None, 1270 dtypes.complex64: None, 1271 dtypes.complex128: None, 1272} 1273 1274 1275# NOTE: the support of "sparse (true)div dense" is currently not baked in into 1276# "tf.(true_)div()". Until such an API decision is made, the supported usage is 1277# to explicitly use the "/" operator to invoke either truediv or div. 1278def _sparse_dense_truediv(sp_indices, sp_values, sp_shape, y, name=None): 1279 """Internal helper function for 'sp_t / dense_t'.""" 1280 with ops.name_scope(name, "truediv", 1281 [sp_indices, sp_values, sp_shape, y]) as name: 1282 sp_values = ops.convert_to_tensor(sp_values, name="sp_values") 1283 y = ops.convert_to_tensor(y, name="y") 1284 x_dtype = sp_values.dtype.base_dtype 1285 y_dtype = y.dtype.base_dtype 1286 if x_dtype != y_dtype: 1287 raise TypeError("x and y must have the same dtype, got %r != %r" % 1288 (x_dtype, y_dtype)) 1289 try: 1290 dtype = _TRUEDIV_TABLE[x_dtype] 1291 except KeyError: 1292 raise TypeError("Invalid dtype %r in __truediv__" % x_dtype) 1293 if dtype is not None: 1294 sp_values = cast(sp_values, dtype) 1295 y = cast(y, dtype) 1296 return gen_sparse_ops.sparse_dense_cwise_div( 1297 sp_indices, sp_values, sp_shape, y, name=name) 1298 1299 1300def _truediv_python3(x, y, name=None): 1301 with ops.name_scope(name, "truediv", [x, y]) as name: 1302 x = ops.convert_to_tensor(x, name="x") 1303 y = ops.convert_to_tensor(y, dtype_hint=x.dtype.base_dtype, name="y") 1304 x_dtype = x.dtype.base_dtype 1305 y_dtype = y.dtype.base_dtype 1306 if x_dtype != y_dtype: 1307 raise TypeError("x and y must have the same dtype, got %r != %r" % 1308 (x_dtype, y_dtype)) 1309 try: 1310 dtype = _TRUEDIV_TABLE[x_dtype] 1311 except KeyError: 1312 raise TypeError("Invalid dtype %r in __truediv__" % x_dtype) 1313 if dtype is not None: 1314 x = cast(x, dtype) 1315 y = cast(y, dtype) 1316 return gen_math_ops.real_div(x, y, name=name) 1317 1318 1319def _div_python2(x, y, name=None): 1320 """Divide two values using Python 2 semantics. 1321 1322 Used for Tensor.__div__. 1323 1324 Args: 1325 x: `Tensor` numerator of real numeric type. 1326 y: `Tensor` denominator of real numeric type. 1327 name: A name for the operation (optional). 1328 1329 Returns: 1330 `x / y` returns the quotient of x and y. 1331 """ 1332 1333 with ops.name_scope(name, "div", [x, y]) as name: 1334 x = ops.convert_to_tensor(x, name="x") 1335 y = ops.convert_to_tensor(y, name="y", dtype=x.dtype.base_dtype) 1336 x_dtype = x.dtype.base_dtype 1337 y_dtype = y.dtype.base_dtype 1338 if x_dtype != y_dtype: 1339 raise TypeError("x and y must have the same dtype, got %r != %r" % 1340 (x_dtype, y_dtype)) 1341 if x_dtype.is_floating or x_dtype.is_complex: 1342 return gen_math_ops.real_div(x, y, name=name) 1343 else: 1344 return gen_math_ops.floor_div(x, y, name=name) 1345 1346 1347@tf_export("math.truediv", "truediv") 1348@dispatch.add_dispatch_support 1349def truediv(x, y, name=None): 1350 """Divides x / y elementwise (using Python 3 division operator semantics). 1351 1352 NOTE: Prefer using the Tensor operator or tf.divide which obey Python 1353 division operator semantics. 1354 1355 This function forces Python 3 division operator semantics where all integer 1356 arguments are cast to floating types first. This op is generated by normal 1357 `x / y` division in Python 3 and in Python 2.7 with 1358 `from __future__ import division`. If you want integer division that rounds 1359 down, use `x // y` or `tf.math.floordiv`. 1360 1361 `x` and `y` must have the same numeric type. If the inputs are floating 1362 point, the output will have the same type. If the inputs are integral, the 1363 inputs are cast to `float32` for `int8` and `int16` and `float64` for `int32` 1364 and `int64` (matching the behavior of Numpy). 1365 1366 Args: 1367 x: `Tensor` numerator of numeric type. 1368 y: `Tensor` denominator of numeric type. 1369 name: A name for the operation (optional). 1370 1371 Returns: 1372 `x / y` evaluated in floating point. 1373 1374 Raises: 1375 TypeError: If `x` and `y` have different dtypes. 1376 """ 1377 return _truediv_python3(x, y, name) 1378 1379 1380@deprecation.deprecated( 1381 date=None, 1382 instructions="Deprecated in favor of operator or tf.math.divide.") 1383@tf_export(v1=["div"]) 1384@dispatch.add_dispatch_support 1385def div(x, y, name=None): 1386 """Divides x / y elementwise (using Python 2 division operator semantics). 1387 1388 NOTE: Prefer using the Tensor division operator or tf.divide which obey Python 1389 3 division operator semantics. 1390 1391 This function divides `x` and `y`, forcing Python 2 semantics. That is, if `x` 1392 and `y` are both integers then the result will be an integer. This is in 1393 contrast to Python 3, where division with `/` is always a float while division 1394 with `//` is always an integer. 1395 1396 Args: 1397 x: `Tensor` numerator of real numeric type. 1398 y: `Tensor` denominator of real numeric type. 1399 name: A name for the operation (optional). 1400 1401 Returns: 1402 `x / y` returns the quotient of x and y. 1403 """ 1404 return _div_python2(x, y, name) 1405 1406 1407@tf_export("math.divide_no_nan", v1=["math.divide_no_nan", "div_no_nan"]) 1408@dispatch.add_dispatch_support 1409@deprecation.deprecated_endpoints("div_no_nan") 1410@dispatch.add_dispatch_support 1411def div_no_nan(x, y, name=None): 1412 """Computes a safe divide which returns 0 if the y is zero. 1413 1414 Args: 1415 x: A `Tensor`. Must be one of the following types: `float32`, `float64`. 1416 y: A `Tensor` whose dtype is compatible with `x`. 1417 name: A name for the operation (optional). 1418 1419 Returns: 1420 The element-wise value of the x divided by y. 1421 """ 1422 1423 with ops.name_scope(name, "div_no_nan", [x, y]) as name: 1424 x = ops.convert_to_tensor(x, name="x") 1425 y = ops.convert_to_tensor(y, name="y", dtype=x.dtype.base_dtype) 1426 return gen_math_ops.div_no_nan(x, y, name=name) 1427 1428 1429@tf_export("math.multiply_no_nan") 1430@dispatch.add_dispatch_support 1431def multiply_no_nan(x, y, name=None): 1432 """Computes the product of x and y and returns 0 if the y is zero, even if x is NaN or infinite. 1433 1434 Args: 1435 x: A `Tensor`. Must be one of the following types: `float32`, `float64`. 1436 y: A `Tensor` whose dtype is compatible with `x`. 1437 name: A name for the operation (optional). 1438 1439 Returns: 1440 The element-wise value of the x times y. 1441 """ 1442 1443 with ops.name_scope(name, "multiply_no_nan", [x, y]) as name: 1444 x = ops.convert_to_tensor(x, name="x") 1445 y = ops.convert_to_tensor(y, name="y", dtype=x.dtype.base_dtype) 1446 x_dtype = x.dtype.base_dtype 1447 y_dtype = y.dtype.base_dtype 1448 if x_dtype != y_dtype: 1449 raise TypeError("x and y must have the same dtype, got %r != %r" % 1450 (x_dtype, y_dtype)) 1451 return gen_math_ops.mul_no_nan(x, y, name=name) 1452 1453 1454# TODO(aselle): This should be removed 1455mod = gen_math_ops.floor_mod 1456 1457 1458# TODO(aselle): Deprecate this once all internal functionality uses 1459# tf.truncatediv 1460@tf_export("math.floordiv", v1=["math.floordiv", "floordiv"]) 1461@dispatch.add_dispatch_support 1462@deprecation.deprecated_endpoints("floordiv") 1463def floordiv(x, y, name=None): 1464 """Divides `x / y` elementwise, rounding toward the most negative integer. 1465 1466 The same as `tf.compat.v1.div(x,y)` for integers, but uses 1467 `tf.floor(tf.compat.v1.div(x,y))` for 1468 floating point arguments so that the result is always an integer (though 1469 possibly an integer represented as floating point). This op is generated by 1470 `x // y` floor division in Python 3 and in Python 2.7 with 1471 `from __future__ import division`. 1472 1473 `x` and `y` must have the same type, and the result will have the same type 1474 as well. 1475 1476 Args: 1477 x: `Tensor` numerator of real numeric type. 1478 y: `Tensor` denominator of real numeric type. 1479 name: A name for the operation (optional). 1480 1481 Returns: 1482 `x / y` rounded down. 1483 1484 Raises: 1485 TypeError: If the inputs are complex. 1486 """ 1487 with ops.name_scope(name, "floordiv", [x, y]) as name: 1488 return gen_math_ops.floor_div(x, y, name=name) 1489 1490 1491realdiv = gen_math_ops.real_div 1492truncatediv = gen_math_ops.truncate_div 1493# TODO(aselle): Rename this to floordiv when we can. 1494floor_div = gen_math_ops.floor_div 1495truncatemod = gen_math_ops.truncate_mod 1496floormod = gen_math_ops.floor_mod 1497 1498 1499@tf_export("__operators__.add", v1=[]) 1500@dispatch.add_dispatch_support 1501def _add_dispatch(x, y, name=None): 1502 """The operation invoked by the `Tensor.__add__` operator. 1503 1504 Purpose in the API: 1505 1506 This method is exposed in TensorFlow's API so that library developers 1507 can register dispatching for `Tensor.__add__` to allow it to handle 1508 custom composite tensors & other custom objects. 1509 1510 The API symbol is not intended to be called by users directly and does 1511 appear in TensorFlow's generated documentation. 1512 1513 Args: 1514 x: The left-hand side of the `+` operator. 1515 y: The right-hand side of the `+` operator. 1516 name: an optional name for the operation. 1517 1518 Returns: 1519 The result of the elementwise `+` operation. 1520 """ 1521 if not isinstance(y, ops.Tensor) and not isinstance( 1522 y, sparse_tensor.SparseTensor): 1523 y = ops.convert_to_tensor(y, dtype_hint=x.dtype.base_dtype, name="y") 1524 if x.dtype == dtypes.string: 1525 return gen_math_ops.add(x, y, name=name) 1526 else: 1527 return gen_math_ops.add_v2(x, y, name=name) 1528 1529 1530def _mul_dispatch(x, y, name=None): 1531 """Dispatches cwise mul for "Dense*Dense" and "Dense*Sparse".""" 1532 if isinstance(y, sparse_tensor.SparseTensor): # Case: Dense * Sparse. 1533 new_vals = gen_sparse_ops.sparse_dense_cwise_mul(y.indices, y.values, 1534 y.dense_shape, x, name) 1535 return sparse_tensor.SparseTensor(y.indices, new_vals, y.dense_shape) 1536 else: 1537 return multiply(x, y, name=name) 1538 1539 1540# NOTE(aselle): When integer division is added for sparse_dense_cwise, 1541# div, truediv, and floordiv should be delegated appropriately for 1542# Python semantics, analogous to dense cwise tensor operations. 1543_OverrideBinaryOperatorHelper(gen_sparse_ops.sparse_dense_cwise_div, "div", 1544 sparse_tensor.SparseTensor) 1545_OverrideBinaryOperatorHelper(_sparse_dense_truediv, "truediv", 1546 sparse_tensor.SparseTensor) 1547_OverrideBinaryOperatorHelper(gen_sparse_ops.sparse_dense_cwise_mul, "mul", 1548 sparse_tensor.SparseTensor) 1549 1550_OverrideBinaryOperatorHelper(_add_dispatch, "add") 1551_OverrideBinaryOperatorHelper(subtract, "sub") 1552_OverrideBinaryOperatorHelper(_mul_dispatch, "mul") 1553_OverrideBinaryOperatorHelper(div, "div") 1554_OverrideBinaryOperatorHelper(truediv, "truediv") 1555_OverrideBinaryOperatorHelper(floordiv, "floordiv") 1556_OverrideBinaryOperatorHelper(gen_math_ops.floor_mod, "mod") 1557_OverrideBinaryOperatorHelper(pow, "pow") 1558 1559 1560@tf_export("math.logical_xor", v1=["math.logical_xor", "logical_xor"]) 1561@dispatch.add_dispatch_support 1562@deprecation.deprecated_endpoints("logical_xor") 1563def logical_xor(x, y, name="LogicalXor"): 1564 """Logical XOR function. 1565 1566 x ^ y = (x | y) & ~(x & y) 1567 1568 Requires that `x` and `y` have the same shape or have 1569 [broadcast-compatible](http://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) 1570 shapes. For example, `x` and `y` can be: 1571 1572 - Two single elements of type `bool` 1573 - One `tf.Tensor` of type `bool` and one single `bool`, where the result will 1574 be calculated by applying logical XOR with the single element to each 1575 element in the larger Tensor. 1576 - Two `tf.Tensor` objects of type `bool` of the same shape. In this case, 1577 the result will be the element-wise logical XOR of the two input tensors. 1578 1579 Usage: 1580 1581 >>> a = tf.constant([True]) 1582 >>> b = tf.constant([False]) 1583 >>> tf.math.logical_xor(a, b) 1584 <tf.Tensor: shape=(1,), dtype=bool, numpy=array([ True])> 1585 1586 >>> c = tf.constant([True]) 1587 >>> x = tf.constant([False, True, True, False]) 1588 >>> tf.math.logical_xor(c, x) 1589 <tf.Tensor: shape=(4,), dtype=bool, numpy=array([ True, False, False, True])> 1590 1591 >>> y = tf.constant([False, False, True, True]) 1592 >>> z = tf.constant([False, True, False, True]) 1593 >>> tf.math.logical_xor(y, z) 1594 <tf.Tensor: shape=(4,), dtype=bool, numpy=array([False, True, True, False])> 1595 1596 Args: 1597 x: A `tf.Tensor` type bool. 1598 y: A `tf.Tensor` of type bool. 1599 name: A name for the operation (optional). 1600 1601 Returns: 1602 A `tf.Tensor` of type bool with the same size as that of x or y. 1603 """ 1604 # TODO(alemi) Make this a cwise op if people end up relying on it. 1605 return gen_math_ops.logical_and( 1606 gen_math_ops.logical_or(x, y), 1607 gen_math_ops.logical_not(gen_math_ops.logical_and(x, y)), 1608 name=name) 1609 1610 1611def and_(x, y, name=None): 1612 if x.dtype == dtypes.bool: 1613 return gen_math_ops.logical_and(x, y, name) 1614 return gen_bitwise_ops.bitwise_and(x, y) 1615 1616 1617def or_(x, y, name=None): 1618 if x.dtype == dtypes.bool: 1619 return gen_math_ops.logical_or(x, y, name) 1620 return gen_bitwise_ops.bitwise_or(x, y) 1621 1622 1623def xor_(x, y, name=None): 1624 if x.dtype == dtypes.bool: 1625 return logical_xor(x, y, name) 1626 return gen_bitwise_ops.bitwise_xor(x, y) 1627 1628 1629def invert_(x, name=None): 1630 if x.dtype == dtypes.bool: 1631 return gen_math_ops.logical_not(x, name=name) 1632 return gen_bitwise_ops.invert(x, name=name) 1633 1634 1635_OverrideBinaryOperatorHelper(and_, "and") 1636_OverrideBinaryOperatorHelper(or_, "or") 1637_OverrideBinaryOperatorHelper(xor_, "xor") 1638ops.Tensor._override_operator("__invert__", invert_) 1639 1640 1641def _promote_dtypes_decorator(fn): 1642 def wrapper(x, y, *args, **kwargs): 1643 x, y = maybe_promote_tensors(x, y, force_same_dtype=False) 1644 return fn(x, y, *args, **kwargs) 1645 return tf_decorator.make_decorator(fn, wrapper) 1646 1647 1648ops.Tensor._override_operator("__lt__", _promote_dtypes_decorator( 1649 gen_math_ops.less)) 1650ops.Tensor._override_operator("__le__", _promote_dtypes_decorator( 1651 gen_math_ops.less_equal)) 1652ops.Tensor._override_operator("__gt__", _promote_dtypes_decorator( 1653 gen_math_ops.greater)) 1654ops.Tensor._override_operator("__ge__", _promote_dtypes_decorator( 1655 gen_math_ops.greater_equal)) 1656 1657 1658@tf_export("math.equal", "equal") 1659@dispatch.add_dispatch_support 1660def equal(x, y, name=None): 1661 """Returns the truth value of (x == y) element-wise. 1662 1663 Performs a [broadcast]( 1664 https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) with the 1665 arguments and then an element-wise equality comparison, returning a Tensor of 1666 boolean values. 1667 1668 For example: 1669 1670 >>> x = tf.constant([2, 4]) 1671 >>> y = tf.constant(2) 1672 >>> tf.math.equal(x, y) 1673 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])> 1674 1675 >>> x = tf.constant([2, 4]) 1676 >>> y = tf.constant([2, 4]) 1677 >>> tf.math.equal(x, y) 1678 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, True])> 1679 1680 Args: 1681 x: A `tf.Tensor` or `tf.sparse.SparseTensor` or `tf.IndexedSlices`. 1682 y: A `tf.Tensor` or `tf.sparse.SparseTensor` or `tf.IndexedSlices`. 1683 name: A name for the operation (optional). 1684 1685 Returns: 1686 A `tf.Tensor` of type bool with the same size as that of x or y. 1687 1688 Raises: 1689 `tf.errors.InvalidArgumentError`: If shapes of arguments are incompatible 1690 """ 1691 return gen_math_ops.equal(x, y, name=name) 1692 1693 1694@tf_export("math.not_equal", "not_equal") 1695@dispatch.add_dispatch_support 1696def not_equal(x, y, name=None): 1697 """Returns the truth value of (x != y) element-wise. 1698 1699 Performs a [broadcast]( 1700 https://docs.scipy.org/doc/numpy/user/basics.broadcasting.html) with the 1701 arguments and then an element-wise inequality comparison, returning a Tensor 1702 of boolean values. 1703 1704 For example: 1705 1706 >>> x = tf.constant([2, 4]) 1707 >>> y = tf.constant(2) 1708 >>> tf.math.not_equal(x, y) 1709 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([False, True])> 1710 1711 >>> x = tf.constant([2, 4]) 1712 >>> y = tf.constant([2, 4]) 1713 >>> tf.math.not_equal(x, y) 1714 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([False, False])> 1715 1716 Args: 1717 x: A `tf.Tensor` or `tf.sparse.SparseTensor` or `tf.IndexedSlices`. 1718 y: A `tf.Tensor` or `tf.sparse.SparseTensor` or `tf.IndexedSlices`. 1719 name: A name for the operation (optional). 1720 1721 Returns: 1722 A `tf.Tensor` of type bool with the same size as that of x or y. 1723 1724 Raises: 1725 `tf.errors.InvalidArgumentError`: If shapes of arguments are incompatible 1726 """ 1727 return gen_math_ops.not_equal(x, y, name=name) 1728 1729 1730@tf_export("__operators__.eq", v1=[]) 1731@dispatch.add_dispatch_support 1732def tensor_equals(self, other): 1733 """The operation invoked by the `Tensor.__eq__` operator. 1734 1735 Compares two tensors element-wise for equality if they are 1736 broadcast-compatible; or returns False if they are not broadcast-compatible. 1737 (Note that this behavior differs from `tf.math.equal`, which raises an 1738 exception if the two tensors are not broadcast-compatible.) 1739 1740 Purpose in the API: 1741 1742 This method is exposed in TensorFlow's API so that library developers 1743 can register dispatching for `Tensor.__eq__` to allow it to handle 1744 custom composite tensors & other custom objects. 1745 1746 The API symbol is not intended to be called by users directly and does 1747 appear in TensorFlow's generated documentation. 1748 1749 Args: 1750 self: The left-hand side of the `==` operator. 1751 other: The right-hand side of the `==` operator. 1752 1753 Returns: 1754 The result of the elementwise `==` operation, or `False` if the arguments 1755 are not broadcast-compatible. 1756 """ 1757 if other is None: 1758 return False 1759 g = getattr(self, "graph", None) 1760 if (ops.Tensor._USE_EQUALITY and ops.executing_eagerly_outside_functions() and 1761 (g is None or g.building_function)): 1762 self, other = maybe_promote_tensors(self, other) 1763 return gen_math_ops.equal(self, other, incompatible_shape_error=False) 1764 else: 1765 # In legacy graph mode, tensor equality is object equality 1766 return self is other 1767 1768 1769@tf_export("__operators__.ne", v1=[]) 1770@dispatch.add_dispatch_support 1771def tensor_not_equals(self, other): 1772 """The operation invoked by the `Tensor.__ne__` operator. 1773 1774 Compares two tensors element-wise for inequality if they are 1775 broadcast-compatible; or returns True if they are not broadcast-compatible. 1776 (Note that this behavior differs from `tf.math.not_equal`, which raises an 1777 exception if the two tensors are not broadcast-compatible.) 1778 1779 Purpose in the API: 1780 1781 This method is exposed in TensorFlow's API so that library developers 1782 can register dispatching for `Tensor.__ne__` to allow it to handle 1783 custom composite tensors & other custom objects. 1784 1785 The API symbol is not intended to be called by users directly and does 1786 appear in TensorFlow's generated documentation. 1787 1788 Args: 1789 self: The left-hand side of the `!=` operator. 1790 other: The right-hand side of the `!=` operator. 1791 1792 Returns: 1793 The result of the elementwise `!=` operation, or `True` if the arguments 1794 are not broadcast-compatible. 1795 """ 1796 if other is None: 1797 return True 1798 if ops.Tensor._USE_EQUALITY and ops.executing_eagerly_outside_functions(): 1799 self, other = maybe_promote_tensors(self, other) 1800 return gen_math_ops.not_equal(self, other, incompatible_shape_error=False) 1801 else: 1802 # In legacy graph mode, tensor equality is object equality 1803 return self is not other 1804 1805 1806ops.Tensor._override_operator("__eq__", tensor_equals) 1807ops.Tensor._override_operator("__ne__", tensor_not_equals) 1808 1809 1810@tf_export("range") 1811@dispatch.add_dispatch_support 1812def range(start, limit=None, delta=1, dtype=None, name="range"): # pylint: disable=redefined-builtin 1813 """Creates a sequence of numbers. 1814 1815 Creates a sequence of numbers that begins at `start` and extends by 1816 increments of `delta` up to but not including `limit`. 1817 1818 The dtype of the resulting tensor is inferred from the inputs unless 1819 it is provided explicitly. 1820 1821 Like the Python builtin `range`, `start` defaults to 0, so that 1822 `range(n) = range(0, n)`. 1823 1824 For example: 1825 1826 >>> start = 3 1827 >>> limit = 18 1828 >>> delta = 3 1829 >>> tf.range(start, limit, delta) 1830 <tf.Tensor: shape=(5,), dtype=int32, 1831 numpy=array([ 3, 6, 9, 12, 15], dtype=int32)> 1832 1833 >>> start = 3 1834 >>> limit = 1 1835 >>> delta = -0.5 1836 >>> tf.range(start, limit, delta) 1837 <tf.Tensor: shape=(4,), dtype=float32, 1838 numpy=array([3. , 2.5, 2. , 1.5], dtype=float32)> 1839 1840 >>> limit = 5 1841 >>> tf.range(limit) 1842 <tf.Tensor: shape=(5,), dtype=int32, 1843 numpy=array([0, 1, 2, 3, 4], dtype=int32)> 1844 1845 Args: 1846 start: A 0-D `Tensor` (scalar). Acts as first entry in the range if `limit` 1847 is not None; otherwise, acts as range limit and first entry defaults to 0. 1848 limit: A 0-D `Tensor` (scalar). Upper limit of sequence, exclusive. If None, 1849 defaults to the value of `start` while the first entry of the range 1850 defaults to 0. 1851 delta: A 0-D `Tensor` (scalar). Number that increments `start`. Defaults to 1852 1. 1853 dtype: The type of the elements of the resulting tensor. 1854 name: A name for the operation. Defaults to "range". 1855 1856 Returns: 1857 An 1-D `Tensor` of type `dtype`. 1858 1859 @compatibility(numpy) 1860 Equivalent to np.arange 1861 @end_compatibility 1862 """ 1863 if limit is None: 1864 start, limit = 0, start 1865 1866 with ops.name_scope(name, "Range", [start, limit, delta]) as name: 1867 if not isinstance(start, ops.Tensor): 1868 start = ops.convert_to_tensor(start, dtype=dtype, name="start") 1869 if not isinstance(limit, ops.Tensor): 1870 limit = ops.convert_to_tensor(limit, dtype=dtype, name="limit") 1871 if not isinstance(delta, ops.Tensor): 1872 delta = ops.convert_to_tensor(delta, dtype=dtype, name="delta") 1873 1874 # infer dtype if not explicitly provided 1875 if dtype is None: 1876 dtype_hierarchy = [ 1877 dtypes.int32, dtypes.int64, dtypes.float32, dtypes.float64 1878 ] 1879 assert all(arg.dtype in dtype_hierarchy for arg in [start, limit, delta]) 1880 inferred_dtype = max([arg.dtype for arg in [start, limit, delta]], 1881 key=dtype_hierarchy.index) 1882 else: 1883 inferred_dtype = dtype 1884 # Always try to perform a cast even when start/limit/delta are already 1885 # tensors. This will resolve the case where start/limit/delta's original's 1886 # dtype is different from provided dtype. 1887 start = cast(start, inferred_dtype) 1888 limit = cast(limit, inferred_dtype) 1889 delta = cast(delta, inferred_dtype) 1890 1891 return gen_math_ops._range(start, limit, delta, name=name) 1892 1893 1894def _range_tensor_conversion_function(value, dtype=None, name=None, 1895 as_ref=False): 1896 del as_ref 1897 return range(value.start, value.stop, value.step, dtype=dtype, name=name) 1898 1899 1900if not six.PY2: 1901 ops.register_tensor_conversion_function(builtins.range, 1902 _range_tensor_conversion_function) 1903 1904# Reduction operations 1905def _ReductionDims(x, axis): # pylint: disable=invalid-name 1906 """Returns range(0, rank(x)) if axis is None.""" 1907 if axis is not None: 1908 return axis 1909 else: 1910 x_rank = None 1911 if isinstance(x, ops.Tensor): 1912 x_rank = x.shape.rank 1913 elif (isinstance(x, sparse_tensor.SparseTensor) and 1914 x.dense_shape.shape.is_fully_defined()): 1915 x_rank = x.dense_shape.shape.dims[0].value # sparse.dense_shape is 1-D. 1916 # Fast path: avoid creating Rank and Range ops if ndims is known. 1917 if x_rank: 1918 return constant_op.constant(np.arange(x_rank, dtype=np.int32)) 1919 else: 1920 # Otherwise, we rely on Range and Rank to do the right thing at run-time. 1921 return range(0, array_ops.rank(x)) 1922 1923 1924def _has_fully_defined_shape(tensor): 1925 """Returns true if tensor has a fully defined shape.""" 1926 return isinstance(tensor, ops.EagerTensor) or tensor.shape.is_fully_defined() 1927 1928 1929def _may_reduce_to_scalar(keepdims, axis, output): 1930 """Set a reduction's output shape to be a scalar if we are certain.""" 1931 if not _has_fully_defined_shape(output) and (not keepdims) and ( 1932 axis is None): 1933 output.set_shape(()) 1934 return output 1935 1936 1937@tf_export(v1=["math.reduce_sum", "reduce_sum"]) 1938@dispatch.add_dispatch_support 1939@deprecation.deprecated_args(None, 1940 "keep_dims is deprecated, use keepdims instead", 1941 "keep_dims") 1942def reduce_sum_v1(input_tensor, 1943 axis=None, 1944 keepdims=None, 1945 name=None, 1946 reduction_indices=None, 1947 keep_dims=None): 1948 """Computes the sum of elements across dimensions of a tensor. 1949 1950 This is the reduction operation for the elementwise `tf.math.add` op. 1951 1952 Reduces `input_tensor` along the dimensions given in `axis`. 1953 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 1954 of the entries in `axis`, which must be unique. If `keepdims` is true, the 1955 reduced dimensions are retained with length 1. 1956 1957 If `axis` is None, all dimensions are reduced, and a 1958 tensor with a single element is returned. 1959 1960 For example: 1961 1962 >>> # x has a shape of (2, 3) (two rows and three columns): 1963 >>> x = tf.constant([[1, 1, 1], [1, 1, 1]]) 1964 >>> x.numpy() 1965 array([[1, 1, 1], 1966 [1, 1, 1]], dtype=int32) 1967 >>> # sum all the elements 1968 >>> # 1 + 1 + 1 + 1 + 1+ 1 = 6 1969 >>> tf.reduce_sum(x).numpy() 1970 6 1971 >>> # reduce along the first dimension 1972 >>> # the result is [1, 1, 1] + [1, 1, 1] = [2, 2, 2] 1973 >>> tf.reduce_sum(x, 0).numpy() 1974 array([2, 2, 2], dtype=int32) 1975 >>> # reduce along the second dimension 1976 >>> # the result is [1, 1] + [1, 1] + [1, 1] = [3, 3] 1977 >>> tf.reduce_sum(x, 1).numpy() 1978 array([3, 3], dtype=int32) 1979 >>> # keep the original dimensions 1980 >>> tf.reduce_sum(x, 1, keepdims=True).numpy() 1981 array([[3], 1982 [3]], dtype=int32) 1983 >>> # reduce along both dimensions 1984 >>> # the result is 1 + 1 + 1 + 1 + 1 + 1 = 6 1985 >>> # or, equivalently, reduce along rows, then reduce the resultant array 1986 >>> # [1, 1, 1] + [1, 1, 1] = [2, 2, 2] 1987 >>> # 2 + 2 + 2 = 6 1988 >>> tf.reduce_sum(x, [0, 1]).numpy() 1989 6 1990 1991 Args: 1992 input_tensor: The tensor to reduce. Should have numeric type. 1993 axis: The dimensions to reduce. If `None` (the default), reduces all 1994 dimensions. Must be in the range `[-rank(input_tensor), 1995 rank(input_tensor))`. 1996 keepdims: If true, retains reduced dimensions with length 1. 1997 name: A name for the operation (optional). 1998 reduction_indices: The old (deprecated) name for axis. 1999 keep_dims: Deprecated alias for `keepdims`. 2000 2001 Returns: 2002 The reduced tensor, of the same dtype as the input_tensor. 2003 2004 @compatibility(numpy) 2005 Equivalent to np.sum apart the fact that numpy upcast uint8 and int32 to 2006 int64 while tensorflow returns the same dtype as the input. 2007 @end_compatibility 2008 """ 2009 axis = deprecation.deprecated_argument_lookup("axis", axis, 2010 "reduction_indices", 2011 reduction_indices) 2012 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2013 "keep_dims", keep_dims) 2014 return reduce_sum(input_tensor, axis, keepdims, name) 2015 2016 2017@tf_export("math.reduce_sum", "reduce_sum", v1=[]) 2018@dispatch.add_dispatch_support 2019def reduce_sum(input_tensor, axis=None, keepdims=False, name=None): 2020 """Computes the sum of elements across dimensions of a tensor. 2021 2022 This is the reduction operation for the elementwise `tf.math.add` op. 2023 2024 Reduces `input_tensor` along the dimensions given in `axis`. 2025 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2026 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2027 reduced dimensions are retained with length 1. 2028 2029 If `axis` is None, all dimensions are reduced, and a 2030 tensor with a single element is returned. 2031 2032 For example: 2033 2034 >>> # x has a shape of (2, 3) (two rows and three columns): 2035 >>> x = tf.constant([[1, 1, 1], [1, 1, 1]]) 2036 >>> x.numpy() 2037 array([[1, 1, 1], 2038 [1, 1, 1]], dtype=int32) 2039 >>> # sum all the elements 2040 >>> # 1 + 1 + 1 + 1 + 1+ 1 = 6 2041 >>> tf.reduce_sum(x).numpy() 2042 6 2043 >>> # reduce along the first dimension 2044 >>> # the result is [1, 1, 1] + [1, 1, 1] = [2, 2, 2] 2045 >>> tf.reduce_sum(x, 0).numpy() 2046 array([2, 2, 2], dtype=int32) 2047 >>> # reduce along the second dimension 2048 >>> # the result is [1, 1] + [1, 1] + [1, 1] = [3, 3] 2049 >>> tf.reduce_sum(x, 1).numpy() 2050 array([3, 3], dtype=int32) 2051 >>> # keep the original dimensions 2052 >>> tf.reduce_sum(x, 1, keepdims=True).numpy() 2053 array([[3], 2054 [3]], dtype=int32) 2055 >>> # reduce along both dimensions 2056 >>> # the result is 1 + 1 + 1 + 1 + 1 + 1 = 6 2057 >>> # or, equivalently, reduce along rows, then reduce the resultant array 2058 >>> # [1, 1, 1] + [1, 1, 1] = [2, 2, 2] 2059 >>> # 2 + 2 + 2 = 6 2060 >>> tf.reduce_sum(x, [0, 1]).numpy() 2061 6 2062 2063 Args: 2064 input_tensor: The tensor to reduce. Should have numeric type. 2065 axis: The dimensions to reduce. If `None` (the default), reduces all 2066 dimensions. Must be in the range `[-rank(input_tensor), 2067 rank(input_tensor)]`. 2068 keepdims: If true, retains reduced dimensions with length 1. 2069 name: A name for the operation (optional). 2070 2071 Returns: 2072 The reduced tensor, of the same dtype as the input_tensor. 2073 2074 @compatibility(numpy) 2075 Equivalent to np.sum apart the fact that numpy upcast uint8 and int32 to 2076 int64 while tensorflow returns the same dtype as the input. 2077 @end_compatibility 2078 """ 2079 2080 return reduce_sum_with_dims(input_tensor, axis, keepdims, name, 2081 _ReductionDims(input_tensor, axis)) 2082 2083 2084def reduce_sum_with_dims(input_tensor, 2085 axis=None, 2086 keepdims=False, 2087 name=None, 2088 dims=None): 2089 keepdims = False if keepdims is None else bool(keepdims) 2090 return _may_reduce_to_scalar( 2091 keepdims, axis, 2092 gen_math_ops._sum(input_tensor, dims, keepdims, name=name)) 2093 2094 2095@tf_export("math.reduce_euclidean_norm") 2096@dispatch.add_dispatch_support 2097def reduce_euclidean_norm(input_tensor, axis=None, keepdims=False, name=None): 2098 """Computes the Euclidean norm of elements across dimensions of a tensor. 2099 2100 Reduces `input_tensor` along the dimensions given in `axis`. 2101 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2102 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2103 reduced dimensions are retained with length 1. 2104 2105 If `axis` is None, all dimensions are reduced, and a 2106 tensor with a single element is returned. 2107 2108 For example: 2109 2110 ```python 2111 x = tf.constant([[1, 2, 3], [1, 1, 1]]) # x.dtype is tf.int32 2112 tf.math.reduce_euclidean_norm(x) # returns 4 as dtype is tf.int32 2113 y = tf.constant([[1, 2, 3], [1, 1, 1]], dtype = tf.float32) 2114 tf.math.reduce_euclidean_norm(y) # returns 4.1231055 which is sqrt(17) 2115 tf.math.reduce_euclidean_norm(y, 0) # [sqrt(2), sqrt(5), sqrt(10)] 2116 tf.math.reduce_euclidean_norm(y, 1) # [sqrt(14), sqrt(3)] 2117 tf.math.reduce_euclidean_norm(y, 1, keepdims=True) # [[sqrt(14)], [sqrt(3)]] 2118 tf.math.reduce_euclidean_norm(y, [0, 1]) # sqrt(17) 2119 ``` 2120 2121 Args: 2122 input_tensor: The tensor to reduce. Should have numeric type. 2123 axis: The dimensions to reduce. If `None` (the default), reduces all 2124 dimensions. Must be in the range `[-rank(input_tensor), 2125 rank(input_tensor))`. 2126 keepdims: If true, retains reduced dimensions with length 1. 2127 name: A name for the operation (optional). 2128 2129 Returns: 2130 The reduced tensor, of the same dtype as the input_tensor. 2131 """ 2132 keepdims = bool(keepdims) 2133 return _may_reduce_to_scalar( 2134 keepdims, axis, 2135 gen_math_ops.euclidean_norm( 2136 input_tensor, _ReductionDims(input_tensor, axis), keepdims, 2137 name=name)) 2138 2139 2140@tf_export(v1=["math.count_nonzero", "count_nonzero"]) 2141@dispatch.add_dispatch_support 2142@deprecation.deprecated_args(None, 2143 "keep_dims is deprecated, use keepdims instead", 2144 "keep_dims") 2145@deprecation.deprecated_args( 2146 None, "reduction_indices is deprecated, use axis instead", 2147 "reduction_indices") 2148def count_nonzero(input_tensor=None, 2149 axis=None, 2150 keepdims=None, 2151 dtype=dtypes.int64, 2152 name=None, 2153 reduction_indices=None, 2154 keep_dims=None, 2155 input=None): # pylint: disable=redefined-builtin 2156 """Computes number of nonzero elements across dimensions of a tensor. 2157 2158 Reduces `input_tensor` along the dimensions given in `axis`. 2159 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2160 entry in `axis`. If `keepdims` is true, the reduced dimensions 2161 are retained with length 1. 2162 2163 If `axis` has no entries, all dimensions are reduced, and a 2164 tensor with a single element is returned. 2165 2166 **NOTE** Floating point comparison to zero is done by exact floating point 2167 equality check. Small values are **not** rounded to zero for purposes of 2168 the nonzero check. 2169 2170 For example: 2171 2172 ```python 2173 x = tf.constant([[0, 1, 0], [1, 1, 0]]) 2174 tf.math.count_nonzero(x) # 3 2175 tf.math.count_nonzero(x, 0) # [1, 2, 0] 2176 tf.math.count_nonzero(x, 1) # [1, 2] 2177 tf.math.count_nonzero(x, 1, keepdims=True) # [[1], [2]] 2178 tf.math.count_nonzero(x, [0, 1]) # 3 2179 ``` 2180 2181 **NOTE** Strings are compared against zero-length empty string `""`. Any 2182 string with a size greater than zero is already considered as nonzero. 2183 2184 For example: 2185 ```python 2186 x = tf.constant(["", "a", " ", "b", ""]) 2187 tf.math.count_nonzero(x) # 3, with "a", " ", and "b" as nonzero strings. 2188 ``` 2189 2190 Args: 2191 input_tensor: The tensor to reduce. Should be of numeric type, `bool`, or 2192 `string`. 2193 axis: The dimensions to reduce. If `None` (the default), reduces all 2194 dimensions. Must be in the range `[-rank(input_tensor), 2195 rank(input_tensor))`. 2196 keepdims: If true, retains reduced dimensions with length 1. 2197 dtype: The output dtype; defaults to `tf.int64`. 2198 name: A name for the operation (optional). 2199 reduction_indices: The old (deprecated) name for axis. 2200 keep_dims: Deprecated alias for `keepdims`. 2201 input: Overrides input_tensor. For compatibility. 2202 2203 Returns: 2204 The reduced tensor (number of nonzero values). 2205 """ 2206 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2207 "keep_dims", keep_dims) 2208 input_tensor = deprecation.deprecated_argument_lookup("input", input, 2209 "input_tensor", 2210 input_tensor) 2211 axis = deprecation.deprecated_argument_lookup("axis", axis, 2212 "reduction_indices", 2213 reduction_indices) 2214 2215 return count_nonzero_v2(input_tensor, axis, keepdims, dtype, name) 2216 2217 2218@tf_export("math.count_nonzero", v1=[]) 2219@dispatch.add_dispatch_support 2220def count_nonzero_v2( 2221 input, # pylint: disable=redefined-builtin 2222 axis=None, 2223 keepdims=None, 2224 dtype=dtypes.int64, 2225 name=None): 2226 """Computes number of nonzero elements across dimensions of a tensor. 2227 2228 Reduces `input` along the dimensions given in `axis`. 2229 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2230 entry in `axis`. If `keepdims` is true, the reduced dimensions 2231 are retained with length 1. 2232 2233 If `axis` has no entries, all dimensions are reduced, and a 2234 tensor with a single element is returned. 2235 2236 **NOTE** Floating point comparison to zero is done by exact floating point 2237 equality check. Small values are **not** rounded to zero for purposes of 2238 the nonzero check. 2239 2240 For example: 2241 2242 ```python 2243 x = tf.constant([[0, 1, 0], [1, 1, 0]]) 2244 tf.math.count_nonzero(x) # 3 2245 tf.math.count_nonzero(x, 0) # [1, 2, 0] 2246 tf.math.count_nonzero(x, 1) # [1, 2] 2247 tf.math.count_nonzero(x, 1, keepdims=True) # [[1], [2]] 2248 tf.math.count_nonzero(x, [0, 1]) # 3 2249 ``` 2250 2251 **NOTE** Strings are compared against zero-length empty string `""`. Any 2252 string with a size greater than zero is already considered as nonzero. 2253 2254 For example: 2255 ```python 2256 x = tf.constant(["", "a", " ", "b", ""]) 2257 tf.math.count_nonzero(x) # 3, with "a", " ", and "b" as nonzero strings. 2258 ``` 2259 2260 Args: 2261 input: The tensor to reduce. Should be of numeric type, `bool`, or `string`. 2262 axis: The dimensions to reduce. If `None` (the default), reduces all 2263 dimensions. Must be in the range `[-rank(input), rank(input))`. 2264 keepdims: If true, retains reduced dimensions with length 1. 2265 dtype: The output dtype; defaults to `tf.int64`. 2266 name: A name for the operation (optional). 2267 2268 Returns: 2269 The reduced tensor (number of nonzero values). 2270 """ 2271 if keepdims is None: 2272 keepdims = False 2273 with ops.name_scope(name, "count_nonzero", [input]): 2274 input = ops.convert_to_tensor(input, name="input") 2275 # A scalar of 'zero' is enough as `not_equal` will broadcast. 2276 zero = array_ops.zeros([], dtype=input.dtype) 2277 return cast( 2278 reduce_sum( 2279 # int64 reduction happens on GPU 2280 cast(gen_math_ops.not_equal(input, zero), dtypes.int64), 2281 axis=axis, 2282 keepdims=keepdims), 2283 dtype=dtype) 2284 2285 2286@tf_export(v1=["math.reduce_mean", "reduce_mean"]) 2287@dispatch.add_dispatch_support 2288def reduce_mean_v1(input_tensor, 2289 axis=None, 2290 keepdims=None, 2291 name=None, 2292 reduction_indices=None, 2293 keep_dims=None): 2294 """Computes the mean of elements across dimensions of a tensor. 2295 2296 Reduces `input_tensor` along the dimensions given in `axis` by computing the 2297 mean of elements across the dimensions in `axis`. 2298 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2299 the entries in `axis`, which must be unique. If `keepdims` is true, the 2300 reduced dimensions are retained with length 1. 2301 2302 If `axis` is None, all dimensions are reduced, and a tensor with a single 2303 element is returned. 2304 2305 For example: 2306 2307 >>> x = tf.constant([[1., 1.], [2., 2.]]) 2308 >>> tf.reduce_mean(x) 2309 <tf.Tensor: shape=(), dtype=float32, numpy=1.5> 2310 >>> tf.reduce_mean(x, 0) 2311 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1.5, 1.5], dtype=float32)> 2312 >>> tf.reduce_mean(x, 1) 2313 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)> 2314 2315 Args: 2316 input_tensor: The tensor to reduce. Should have numeric type. 2317 axis: The dimensions to reduce. If `None` (the default), reduces all 2318 dimensions. Must be in the range `[-rank(input_tensor), 2319 rank(input_tensor))`. 2320 keepdims: If true, retains reduced dimensions with length 1. 2321 name: A name for the operation (optional). 2322 reduction_indices: The old (deprecated) name for axis. 2323 keep_dims: Deprecated alias for `keepdims`. 2324 2325 Returns: 2326 The reduced tensor. 2327 2328 @compatibility(numpy) 2329 Equivalent to np.mean 2330 2331 Please note that `np.mean` has a `dtype` parameter that could be used to 2332 specify the output type. By default this is `dtype=float64`. On the other 2333 hand, `tf.reduce_mean` has an aggressive type inference from `input_tensor`, 2334 for example: 2335 2336 >>> x = tf.constant([1, 0, 1, 0]) 2337 >>> tf.reduce_mean(x) 2338 <tf.Tensor: shape=(), dtype=int32, numpy=0> 2339 >>> y = tf.constant([1., 0., 1., 0.]) 2340 >>> tf.reduce_mean(y) 2341 <tf.Tensor: shape=(), dtype=float32, numpy=0.5> 2342 2343 @end_compatibility 2344 """ 2345 axis = deprecation.deprecated_argument_lookup("axis", axis, 2346 "reduction_indices", 2347 reduction_indices) 2348 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2349 "keep_dims", keep_dims) 2350 return reduce_mean(input_tensor, axis, keepdims, name) 2351 2352 2353@tf_export("math.reduce_mean", "reduce_mean", v1=[]) 2354@dispatch.add_dispatch_support 2355def reduce_mean(input_tensor, axis=None, keepdims=False, name=None): 2356 """Computes the mean of elements across dimensions of a tensor. 2357 2358 Reduces `input_tensor` along the dimensions given in `axis` by computing the 2359 mean of elements across the dimensions in `axis`. 2360 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2361 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2362 reduced dimensions are retained with length 1. 2363 2364 If `axis` is None, all dimensions are reduced, and a tensor with a single 2365 element is returned. 2366 2367 For example: 2368 2369 >>> x = tf.constant([[1., 1.], [2., 2.]]) 2370 >>> tf.reduce_mean(x) 2371 <tf.Tensor: shape=(), dtype=float32, numpy=1.5> 2372 >>> tf.reduce_mean(x, 0) 2373 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1.5, 1.5], dtype=float32)> 2374 >>> tf.reduce_mean(x, 1) 2375 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 2.], dtype=float32)> 2376 2377 Args: 2378 input_tensor: The tensor to reduce. Should have numeric type. 2379 axis: The dimensions to reduce. If `None` (the default), reduces all 2380 dimensions. Must be in the range `[-rank(input_tensor), 2381 rank(input_tensor))`. 2382 keepdims: If true, retains reduced dimensions with length 1. 2383 name: A name for the operation (optional). 2384 2385 Returns: 2386 The reduced tensor. 2387 2388 @compatibility(numpy) 2389 Equivalent to np.mean 2390 2391 Please note that `np.mean` has a `dtype` parameter that could be used to 2392 specify the output type. By default this is `dtype=float64`. On the other 2393 hand, `tf.reduce_mean` has an aggressive type inference from `input_tensor`, 2394 for example: 2395 2396 >>> x = tf.constant([1, 0, 1, 0]) 2397 >>> tf.reduce_mean(x) 2398 <tf.Tensor: shape=(), dtype=int32, numpy=0> 2399 >>> y = tf.constant([1., 0., 1., 0.]) 2400 >>> tf.reduce_mean(y) 2401 <tf.Tensor: shape=(), dtype=float32, numpy=0.5> 2402 2403 @end_compatibility 2404 """ 2405 keepdims = False if keepdims is None else bool(keepdims) 2406 return _may_reduce_to_scalar( 2407 keepdims, axis, 2408 gen_math_ops.mean( 2409 input_tensor, _ReductionDims(input_tensor, axis), keepdims, 2410 name=name)) 2411 2412 2413@tf_export("math.reduce_variance") 2414@dispatch.add_dispatch_support 2415def reduce_variance(input_tensor, axis=None, keepdims=False, name=None): 2416 """Computes the variance of elements across dimensions of a tensor. 2417 2418 Reduces `input_tensor` along the dimensions given in `axis`. 2419 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2420 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2421 reduced dimensions are retained with length 1. 2422 2423 If `axis` is None, all dimensions are reduced, and a 2424 tensor with a single element is returned. 2425 2426 For example: 2427 2428 >>> x = tf.constant([[1., 2.], [3., 4.]]) 2429 >>> tf.math.reduce_variance(x) 2430 <tf.Tensor: shape=(), dtype=float32, numpy=1.25> 2431 >>> tf.math.reduce_variance(x, 0) 2432 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 1.], ...)> 2433 >>> tf.math.reduce_variance(x, 1) 2434 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([0.25, 0.25], ...)> 2435 2436 Args: 2437 input_tensor: The tensor to reduce. Should have real or complex type. 2438 axis: The dimensions to reduce. If `None` (the default), reduces all 2439 dimensions. Must be in the range `[-rank(input_tensor), 2440 rank(input_tensor))`. 2441 keepdims: If true, retains reduced dimensions with length 1. 2442 name: A name scope for the associated operations (optional). 2443 2444 Returns: 2445 The reduced tensor, of the same dtype as the input_tensor. Note, for 2446 `complex64` or `complex128` input, the returned `Tensor` will be of type 2447 `float32` or `float64`, respectively. 2448 2449 @compatibility(numpy) 2450 Equivalent to np.var 2451 2452 Please note `np.var` has a `dtype` parameter that could be used to specify the 2453 output type. By default this is `dtype=float64`. On the other hand, 2454 `tf.math.reduce_variance` has aggressive type inference from `input_tensor`. 2455 @end_compatibility 2456 """ 2457 name = name if name else "reduce_variance" 2458 with ops.name_scope(name): 2459 means = reduce_mean(input_tensor, axis=axis, keepdims=True) 2460 if means.dtype.is_integer: 2461 raise TypeError("Input must be either real or complex") 2462 diff = input_tensor - means 2463 if diff.dtype.is_complex: 2464 # For complex values we need to take the absolute value before squaring. 2465 # This is achieved by multiplying with the conjugate. 2466 real_dtype = diff.dtype.real_dtype 2467 squared_deviations = gen_math_ops.real( 2468 gen_math_ops.mul(gen_math_ops.conj(diff), diff), Tout=real_dtype) 2469 else: 2470 squared_deviations = gen_math_ops.square(diff) 2471 return reduce_mean(squared_deviations, axis=axis, keepdims=keepdims) 2472 2473 2474@tf_export("math.reduce_std") 2475@dispatch.add_dispatch_support 2476def reduce_std(input_tensor, axis=None, keepdims=False, name=None): 2477 """Computes the standard deviation of elements across dimensions of a tensor. 2478 2479 Reduces `input_tensor` along the dimensions given in `axis`. 2480 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2481 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2482 reduced dimensions are retained with length 1. 2483 2484 If `axis` is None, all dimensions are reduced, and a 2485 tensor with a single element is returned. 2486 2487 For example: 2488 2489 >>> x = tf.constant([[1., 2.], [3., 4.]]) 2490 >>> tf.math.reduce_std(x) 2491 <tf.Tensor: shape=(), dtype=float32, numpy=1.118034> 2492 >>> tf.math.reduce_std(x, 0) 2493 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([1., 1.], dtype=float32)> 2494 >>> tf.math.reduce_std(x, 1) 2495 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([0.5, 0.5], dtype=float32)> 2496 2497 Args: 2498 input_tensor: The tensor to reduce. Should have real or complex type. 2499 axis: The dimensions to reduce. If `None` (the default), reduces all 2500 dimensions. Must be in the range `[-rank(input_tensor), 2501 rank(input_tensor))`. 2502 keepdims: If true, retains reduced dimensions with length 1. 2503 name: A name scope for the associated operations (optional). 2504 2505 Returns: 2506 The reduced tensor, of the same dtype as the input_tensor. Note, for 2507 `complex64` or `complex128` input, the returned `Tensor` will be of type 2508 `float32` or `float64`, respectively. 2509 2510 @compatibility(numpy) 2511 Equivalent to np.std 2512 2513 Please note `np.std` has a `dtype` parameter that could be used to specify the 2514 output type. By default this is `dtype=float64`. On the other hand, 2515 `tf.math.reduce_std` has aggressive type inference from `input_tensor`. 2516 @end_compatibility 2517 """ 2518 name = name if name else "reduce_std" 2519 with ops.name_scope(name): 2520 variance = reduce_variance(input_tensor, axis=axis, keepdims=keepdims) 2521 return gen_math_ops.sqrt(variance) 2522 2523 2524@tf_export("math.reduce_prod", "reduce_prod", v1=[]) 2525@dispatch.add_dispatch_support 2526def reduce_prod(input_tensor, axis=None, keepdims=False, name=None): 2527 """Computes `tf.math.multiply` of elements across dimensions of a tensor. 2528 2529 This is the reduction operation for the elementwise `tf.math.multiply` op. 2530 2531 Reduces `input_tensor` along the dimensions given in `axis`. 2532 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2533 entry in `axis`. If `keepdims` is true, the reduced dimensions 2534 are retained with length 1. 2535 2536 If `axis` is None, all dimensions are reduced, and a 2537 tensor with a single element is returned. 2538 2539 For example: 2540 2541 >>> x = tf.constant([[1., 2.], [3., 4.]]) 2542 >>> tf.math.reduce_prod(x) 2543 <tf.Tensor: shape=(), dtype=float32, numpy=24.> 2544 >>> tf.math.reduce_prod(x, 0) 2545 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([3., 8.], dtype=float32)> 2546 >>> tf.math.reduce_prod(x, 1) 2547 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([2., 12.], 2548 dtype=float32)> 2549 2550 Args: 2551 input_tensor: The tensor to reduce. Should have numeric type. 2552 axis: The dimensions to reduce. If `None` (the default), reduces all 2553 dimensions. Must be in the range `[-rank(input_tensor), 2554 rank(input_tensor))`. 2555 keepdims: If true, retains reduced dimensions with length 1. 2556 name: A name for the operation (optional). 2557 2558 Returns: 2559 The reduced tensor. 2560 2561 @compatibility(numpy) 2562 Equivalent to np.prod 2563 @end_compatibility 2564 """ 2565 keepdims = False if keepdims is None else bool(keepdims) 2566 return _may_reduce_to_scalar( 2567 keepdims, axis, 2568 gen_math_ops.prod( 2569 input_tensor, _ReductionDims(input_tensor, axis), keepdims, 2570 name=name)) 2571 2572 2573@tf_export(v1=["math.reduce_prod", "reduce_prod"]) 2574@dispatch.add_dispatch_support 2575@deprecation.deprecated_args(None, 2576 "keep_dims is deprecated, use keepdims instead", 2577 "keep_dims") 2578def reduce_prod_v1(input_tensor, 2579 axis=None, 2580 keepdims=None, 2581 name=None, 2582 reduction_indices=None, 2583 keep_dims=None): 2584 """Computes `tf.math.multiply` of elements across dimensions of a tensor. 2585 2586 This is the reduction operation for the elementwise `tf.math.multiply` op. 2587 2588 Reduces `input_tensor` along the dimensions given in `axis`. 2589 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2590 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2591 reduced dimensions are retained with length 1. 2592 2593 If `axis` is None, all dimensions are reduced, and a 2594 tensor with a single element is returned. 2595 2596 For example: 2597 2598 >>> x = tf.constant([[1., 2.], [3., 4.]]) 2599 >>> tf.math.reduce_prod(x) 2600 <tf.Tensor: shape=(), dtype=float32, numpy=24.> 2601 >>> tf.math.reduce_prod(x, 0) 2602 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([3., 8.], dtype=float32)> 2603 >>> tf.math.reduce_prod(x, 1) 2604 <tf.Tensor: shape=(2,), dtype=float32, numpy=array([2., 12.], 2605 dtype=float32)> 2606 2607 Args: 2608 input_tensor: The tensor to reduce. Should have numeric type. 2609 axis: The dimensions to reduce. If `None` (the default), reduces all 2610 dimensions. Must be in the range `[-rank(input_tensor), 2611 rank(input_tensor))`. 2612 keepdims: If true, retains reduced dimensions with length 1. 2613 name: A name for the operation (optional). 2614 reduction_indices: The old (deprecated) name for axis. 2615 keep_dims: Deprecated alias for `keepdims`. 2616 2617 Returns: 2618 The reduced tensor. 2619 2620 @compatibility(numpy) 2621 Equivalent to np.prod 2622 @end_compatibility 2623 """ 2624 axis = deprecation.deprecated_argument_lookup("axis", axis, 2625 "reduction_indices", 2626 reduction_indices) 2627 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2628 "keep_dims", keep_dims) 2629 return reduce_prod(input_tensor, axis, keepdims, name) 2630 2631 2632@tf_export(v1=["math.reduce_min", "reduce_min"]) 2633@dispatch.add_dispatch_support 2634@deprecation.deprecated_args(None, 2635 "keep_dims is deprecated, use keepdims instead", 2636 "keep_dims") 2637def reduce_min_v1(input_tensor, 2638 axis=None, 2639 keepdims=None, 2640 name=None, 2641 reduction_indices=None, 2642 keep_dims=None): 2643 """Computes the `tf.math.minimum` of elements across dimensions of a tensor. 2644 2645 This is the reduction operation for the elementwise `tf.math.minimum` op. 2646 2647 Reduces `input_tensor` along the dimensions given in `axis`. 2648 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2649 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2650 reduced dimensions are retained with length 1. 2651 2652 If `axis` is None, all dimensions are reduced, and a 2653 tensor with a single element is returned. 2654 2655 Usage example: 2656 2657 >>> x = tf.constant([5, 1, 2, 4]) 2658 >>> tf.reduce_min(x) 2659 <tf.Tensor: shape=(), dtype=int32, numpy=1> 2660 >>> x = tf.constant([-5, -1, -2, -4]) 2661 >>> tf.reduce_min(x) 2662 <tf.Tensor: shape=(), dtype=int32, numpy=-5> 2663 >>> x = tf.constant([4, float('nan')]) 2664 >>> tf.reduce_min(x) 2665 <tf.Tensor: shape=(), dtype=float32, numpy=nan> 2666 >>> x = tf.constant([float('nan'), float('nan')]) 2667 >>> tf.reduce_min(x) 2668 <tf.Tensor: shape=(), dtype=float32, numpy=nan> 2669 >>> x = tf.constant([float('-inf'), float('inf')]) 2670 >>> tf.reduce_min(x) 2671 <tf.Tensor: shape=(), dtype=float32, numpy=-inf> 2672 2673 See the numpy docs for `np.amin` and `np.nanmin` behavior. 2674 2675 Args: 2676 input_tensor: The tensor to reduce. Should have real numeric type. 2677 axis: The dimensions to reduce. If `None` (the default), reduces all 2678 dimensions. Must be in the range `[-rank(input_tensor), 2679 rank(input_tensor))`. 2680 keepdims: If true, retains reduced dimensions with length 1. 2681 name: A name for the operation (optional). 2682 reduction_indices: The old (deprecated) name for axis. 2683 keep_dims: Deprecated alias for `keepdims`. 2684 2685 Returns: 2686 The reduced tensor. 2687 """ 2688 axis = deprecation.deprecated_argument_lookup("axis", axis, 2689 "reduction_indices", 2690 reduction_indices) 2691 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2692 "keep_dims", keep_dims) 2693 return reduce_min(input_tensor, axis, keepdims, name) 2694 2695 2696@tf_export("math.reduce_min", "reduce_min", v1=[]) 2697@dispatch.add_dispatch_support 2698def reduce_min(input_tensor, axis=None, keepdims=False, name=None): 2699 """Computes the `tf.math.minimum` of elements across dimensions of a tensor. 2700 2701 This is the reduction operation for the elementwise `tf.math.minimum` op. 2702 2703 Reduces `input_tensor` along the dimensions given in `axis`. 2704 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2705 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2706 reduced dimensions are retained with length 1. 2707 2708 If `axis` is None, all dimensions are reduced, and a 2709 tensor with a single element is returned. 2710 2711 For example: 2712 2713 >>> a = tf.constant([ 2714 ... [[1, 2], [3, 4]], 2715 ... [[1, 2], [3, 4]] 2716 ... ]) 2717 >>> tf.reduce_min(a) 2718 <tf.Tensor: shape=(), dtype=int32, numpy=1> 2719 2720 Choosing a specific axis returns minimum element in the given axis: 2721 2722 >>> b = tf.constant([[1, 2, 3], [4, 5, 6]]) 2723 >>> tf.reduce_min(b, axis=0) 2724 <tf.Tensor: shape=(3,), dtype=int32, numpy=array([1, 2, 3], dtype=int32)> 2725 >>> tf.reduce_min(b, axis=1) 2726 <tf.Tensor: shape=(2,), dtype=int32, numpy=array([1, 4], dtype=int32)> 2727 2728 Setting `keepdims` to `True` retains the dimension of `input_tensor`: 2729 2730 >>> tf.reduce_min(a, keepdims=True) 2731 <tf.Tensor: shape=(1, 1, 1), dtype=int32, numpy=array([[[1]]], dtype=int32)> 2732 >>> tf.math.reduce_min(a, axis=0, keepdims=True) 2733 <tf.Tensor: shape=(1, 2, 2), dtype=int32, numpy= 2734 array([[[1, 2], 2735 [3, 4]]], dtype=int32)> 2736 2737 Args: 2738 input_tensor: The tensor to reduce. Should have real numeric type. 2739 axis: The dimensions to reduce. If `None` (the default), reduces all 2740 dimensions. Must be in the range `[-rank(input_tensor), 2741 rank(input_tensor))`. 2742 keepdims: If true, retains reduced dimensions with length 1. 2743 name: A name for the operation (optional). 2744 2745 Returns: 2746 The reduced tensor. 2747 2748 @compatibility(numpy) 2749 Equivalent to np.min 2750 @end_compatibility 2751 """ 2752 keepdims = False if keepdims is None else bool(keepdims) 2753 return _may_reduce_to_scalar( 2754 keepdims, axis, 2755 gen_math_ops._min( 2756 input_tensor, _ReductionDims(input_tensor, axis), keepdims, 2757 name=name)) 2758 2759 2760@tf_export(v1=["math.reduce_max", "reduce_max"]) 2761@dispatch.add_dispatch_support 2762@deprecation.deprecated_args(None, 2763 "keep_dims is deprecated, use keepdims instead", 2764 "keep_dims") 2765def reduce_max_v1(input_tensor, 2766 axis=None, 2767 keepdims=None, 2768 name=None, 2769 reduction_indices=None, 2770 keep_dims=None): 2771 """Computes `tf.math.maximum` of elements across dimensions of a tensor. 2772 2773 This is the reduction operation for the elementwise `tf.math.maximum` op. 2774 2775 Reduces `input_tensor` along the dimensions given in `axis`. 2776 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2777 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2778 reduced dimensions are retained with length 1. 2779 2780 If `axis` is None, all dimensions are reduced, and a 2781 tensor with a single element is returned. 2782 2783 Usage example: 2784 2785 >>> x = tf.constant([5, 1, 2, 4]) 2786 >>> tf.reduce_max(x) 2787 <tf.Tensor: shape=(), dtype=int32, numpy=5> 2788 >>> x = tf.constant([-5, -1, -2, -4]) 2789 >>> tf.reduce_max(x) 2790 <tf.Tensor: shape=(), dtype=int32, numpy=-1> 2791 >>> x = tf.constant([4, float('nan')]) 2792 >>> tf.reduce_max(x) 2793 <tf.Tensor: shape=(), dtype=float32, numpy=nan> 2794 >>> x = tf.constant([float('nan'), float('nan')]) 2795 >>> tf.reduce_max(x) 2796 <tf.Tensor: shape=(), dtype=float32, numpy=nan> 2797 >>> x = tf.constant([float('-inf'), float('inf')]) 2798 >>> tf.reduce_max(x) 2799 <tf.Tensor: shape=(), dtype=float32, numpy=inf> 2800 2801 See the numpy docs for `np.amax` and `np.nanmax` behavior. 2802 2803 Args: 2804 input_tensor: The tensor to reduce. Should have real numeric type. 2805 axis: The dimensions to reduce. If `None` (the default), reduces all 2806 dimensions. Must be in the range `[-rank(input_tensor), 2807 rank(input_tensor))`. 2808 keepdims: If true, retains reduced dimensions with length 1. 2809 name: A name for the operation (optional). 2810 reduction_indices: The old (deprecated) name for axis. 2811 keep_dims: Deprecated alias for `keepdims`. 2812 2813 Returns: 2814 The reduced tensor. 2815 """ 2816 axis = deprecation.deprecated_argument_lookup("axis", axis, 2817 "reduction_indices", 2818 reduction_indices) 2819 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2820 "keep_dims", keep_dims) 2821 return reduce_max(input_tensor, axis, keepdims, name) 2822 2823 2824@tf_export("math.reduce_max", "reduce_max", v1=[]) 2825@dispatch.add_dispatch_support 2826def reduce_max(input_tensor, axis=None, keepdims=False, name=None): 2827 """Computes `tf.math.maximum` of elements across dimensions of a tensor. 2828 2829 This is the reduction operation for the elementwise `tf.math.maximum` op. 2830 2831 Reduces `input_tensor` along the dimensions given in `axis`. 2832 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2833 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2834 reduced dimensions are retained with length 1. 2835 2836 If `axis` is None, all dimensions are reduced, and a 2837 tensor with a single element is returned. 2838 2839 Usage example: 2840 2841 >>> x = tf.constant([5, 1, 2, 4]) 2842 >>> tf.reduce_max(x) 2843 <tf.Tensor: shape=(), dtype=int32, numpy=5> 2844 >>> x = tf.constant([-5, -1, -2, -4]) 2845 >>> tf.reduce_max(x) 2846 <tf.Tensor: shape=(), dtype=int32, numpy=-1> 2847 >>> x = tf.constant([4, float('nan')]) 2848 >>> tf.reduce_max(x) 2849 <tf.Tensor: shape=(), dtype=float32, numpy=nan> 2850 >>> x = tf.constant([float('nan'), float('nan')]) 2851 >>> tf.reduce_max(x) 2852 <tf.Tensor: shape=(), dtype=float32, numpy=nan> 2853 >>> x = tf.constant([float('-inf'), float('inf')]) 2854 >>> tf.reduce_max(x) 2855 <tf.Tensor: shape=(), dtype=float32, numpy=inf> 2856 2857 See the numpy docs for `np.amax` and `np.nanmax` behavior. 2858 2859 Args: 2860 input_tensor: The tensor to reduce. Should have real numeric type. 2861 axis: The dimensions to reduce. If `None` (the default), reduces all 2862 dimensions. Must be in the range `[-rank(input_tensor), 2863 rank(input_tensor))`. 2864 keepdims: If true, retains reduced dimensions with length 1. 2865 name: A name for the operation (optional). 2866 2867 Returns: 2868 The reduced tensor. 2869 """ 2870 return reduce_max_with_dims(input_tensor, axis, keepdims, name, 2871 _ReductionDims(input_tensor, axis)) 2872 2873 2874def reduce_max_with_dims(input_tensor, 2875 axis=None, 2876 keepdims=False, 2877 name=None, 2878 dims=None): 2879 keepdims = False if keepdims is None else bool(keepdims) 2880 return _may_reduce_to_scalar( 2881 keepdims, axis, 2882 gen_math_ops._max(input_tensor, dims, keepdims, name=name)) 2883 2884 2885@tf_export(v1=["math.reduce_all", "reduce_all"]) 2886@dispatch.add_dispatch_support 2887@deprecation.deprecated_args(None, 2888 "keep_dims is deprecated, use keepdims instead", 2889 "keep_dims") 2890def reduce_all_v1(input_tensor, 2891 axis=None, 2892 keepdims=None, 2893 name=None, 2894 reduction_indices=None, 2895 keep_dims=None): 2896 """Computes `tf.math.logical_and` of elements across dimensions of a tensor. 2897 2898 This is the reduction operation for the elementwise `tf.math.logical_and` op. 2899 2900 Reduces `input_tensor` along the dimensions given in `axis`. 2901 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2902 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2903 reduced dimensions are retained with length 1. 2904 2905 If `axis` is None, all dimensions are reduced, and a 2906 tensor with a single element is returned. 2907 2908 For example: 2909 2910 >>> x = tf.constant([[True, True], [False, False]]) 2911 >>> tf.math.reduce_all(x) 2912 <tf.Tensor: shape=(), dtype=bool, numpy=False> 2913 >>> tf.math.reduce_all(x, 0) 2914 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([False, False])> 2915 >>> tf.math.reduce_all(x, 1) 2916 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])> 2917 2918 Args: 2919 input_tensor: The boolean tensor to reduce. 2920 axis: The dimensions to reduce. If `None` (the default), reduces all 2921 dimensions. Must be in the range `[-rank(input_tensor), 2922 rank(input_tensor))`. 2923 keepdims: If true, retains reduced dimensions with length 1. 2924 name: A name for the operation (optional). 2925 reduction_indices: The old (deprecated) name for axis. 2926 keep_dims: Deprecated alias for `keepdims`. 2927 2928 Returns: 2929 The reduced tensor. 2930 2931 @compatibility(numpy) 2932 Equivalent to np.all 2933 @end_compatibility 2934 """ 2935 axis = deprecation.deprecated_argument_lookup("axis", axis, 2936 "reduction_indices", 2937 reduction_indices) 2938 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 2939 "keep_dims", keep_dims) 2940 return reduce_all(input_tensor, axis, keepdims, name) 2941 2942 2943@tf_export("math.reduce_all", "reduce_all", v1=[]) 2944@dispatch.add_dispatch_support 2945def reduce_all(input_tensor, axis=None, keepdims=False, name=None): 2946 """Computes `tf.math.logical_and` of elements across dimensions of a tensor. 2947 2948 This is the reduction operation for the elementwise `tf.math.logical_and` op. 2949 2950 Reduces `input_tensor` along the dimensions given in `axis`. 2951 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 2952 of the entries in `axis`, which must be unique. If `keepdims` is true, the 2953 reduced dimensions are retained with length 1. 2954 2955 If `axis` is None, all dimensions are reduced, and a 2956 tensor with a single element is returned. 2957 2958 For example: 2959 2960 >>> x = tf.constant([[True, True], [False, False]]) 2961 >>> tf.math.reduce_all(x) 2962 <tf.Tensor: shape=(), dtype=bool, numpy=False> 2963 >>> tf.math.reduce_all(x, 0) 2964 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([False, False])> 2965 >>> tf.math.reduce_all(x, 1) 2966 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])> 2967 2968 Args: 2969 input_tensor: The boolean tensor to reduce. 2970 axis: The dimensions to reduce. If `None` (the default), reduces all 2971 dimensions. Must be in the range `[-rank(input_tensor), 2972 rank(input_tensor))`. 2973 keepdims: If true, retains reduced dimensions with length 1. 2974 name: A name for the operation (optional). 2975 2976 Returns: 2977 The reduced tensor. 2978 2979 @compatibility(numpy) 2980 Equivalent to np.all 2981 @end_compatibility 2982 """ 2983 keepdims = False if keepdims is None else bool(keepdims) 2984 return _may_reduce_to_scalar( 2985 keepdims, axis, 2986 gen_math_ops._all( 2987 input_tensor, _ReductionDims(input_tensor, axis), keepdims, 2988 name=name)) 2989 2990 2991@tf_export(v1=["math.reduce_any", "reduce_any"]) 2992@dispatch.add_dispatch_support 2993@deprecation.deprecated_args(None, 2994 "keep_dims is deprecated, use keepdims instead", 2995 "keep_dims") 2996def reduce_any_v1(input_tensor, 2997 axis=None, 2998 keepdims=None, 2999 name=None, 3000 reduction_indices=None, 3001 keep_dims=None): 3002 """Computes `tf.math.logical_or` of elements across dimensions of a tensor. 3003 3004 This is the reduction operation for the elementwise `tf.math.logical_or` op. 3005 3006 Reduces `input_tensor` along the dimensions given in `axis`. 3007 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 3008 of the entries in `axis`, which must be unique. If `keepdims` is true, the 3009 reduced dimensions are retained with length 1. 3010 3011 If `axis` is None, all dimensions are reduced, and a 3012 tensor with a single element is returned. 3013 3014 For example: 3015 3016 >>> x = tf.constant([[True, True], [False, False]]) 3017 >>> tf.reduce_any(x) 3018 <tf.Tensor: shape=(), dtype=bool, numpy=True> 3019 >>> tf.reduce_any(x, 0) 3020 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, True])> 3021 >>> tf.reduce_any(x, 1) 3022 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])> 3023 3024 Args: 3025 input_tensor: The boolean tensor to reduce. 3026 axis: The dimensions to reduce. If `None` (the default), reduces all 3027 dimensions. Must be in the range `[-rank(input_tensor), 3028 rank(input_tensor))`. 3029 keepdims: If true, retains reduced dimensions with length 1. 3030 name: A name for the operation (optional). 3031 reduction_indices: The old (deprecated) name for axis. 3032 keep_dims: Deprecated alias for `keepdims`. 3033 3034 Returns: 3035 The reduced tensor. 3036 3037 @compatibility(numpy) 3038 Equivalent to np.any 3039 @end_compatibility 3040 """ 3041 axis = deprecation.deprecated_argument_lookup("axis", axis, 3042 "reduction_indices", 3043 reduction_indices) 3044 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 3045 "keep_dims", keep_dims) 3046 return reduce_any(input_tensor, axis, keepdims, name) 3047 3048 3049@tf_export("math.reduce_any", "reduce_any", v1=[]) 3050@dispatch.add_dispatch_support 3051def reduce_any(input_tensor, axis=None, keepdims=False, name=None): 3052 """Computes `tf.math.logical_or` of elements across dimensions of a tensor. 3053 3054 This is the reduction operation for the elementwise `tf.math.logical_or` op. 3055 3056 Reduces `input_tensor` along the dimensions given in `axis`. 3057 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 3058 of the entries in `axis`, which must be unique. If `keepdims` is true, the 3059 reduced dimensions are retained with length 1. 3060 3061 If `axis` is None, all dimensions are reduced, and a 3062 tensor with a single element is returned. 3063 3064 For example: 3065 3066 >>> x = tf.constant([[True, True], [False, False]]) 3067 >>> tf.reduce_any(x) 3068 <tf.Tensor: shape=(), dtype=bool, numpy=True> 3069 >>> tf.reduce_any(x, 0) 3070 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, True])> 3071 >>> tf.reduce_any(x, 1) 3072 <tf.Tensor: shape=(2,), dtype=bool, numpy=array([ True, False])> 3073 3074 Args: 3075 input_tensor: The boolean tensor to reduce. 3076 axis: The dimensions to reduce. If `None` (the default), reduces all 3077 dimensions. Must be in the range `[-rank(input_tensor), 3078 rank(input_tensor))`. 3079 keepdims: If true, retains reduced dimensions with length 1. 3080 name: A name for the operation (optional). 3081 3082 Returns: 3083 The reduced tensor. 3084 3085 @compatibility(numpy) 3086 Equivalent to np.any 3087 @end_compatibility 3088 """ 3089 keepdims = False if keepdims is None else bool(keepdims) 3090 return _may_reduce_to_scalar( 3091 keepdims, axis, 3092 gen_math_ops._any( 3093 input_tensor, _ReductionDims(input_tensor, axis), keepdims, 3094 name=name)) 3095 3096 3097@tf_export(v1=["math.reduce_logsumexp", "reduce_logsumexp"]) 3098@dispatch.add_dispatch_support 3099@deprecation.deprecated_args(None, 3100 "keep_dims is deprecated, use keepdims instead", 3101 "keep_dims") 3102def reduce_logsumexp_v1(input_tensor, 3103 axis=None, 3104 keepdims=None, 3105 name=None, 3106 reduction_indices=None, 3107 keep_dims=None): 3108 """Computes log(sum(exp(elements across dimensions of a tensor))). 3109 3110 Reduces `input_tensor` along the dimensions given in `axis`. 3111 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 3112 of the entries in `axis`, which must be unique. If `keepdims` is true, the 3113 reduced dimensions are retained with length 1. 3114 3115 If `axis` has no entries, all dimensions are reduced, and a 3116 tensor with a single element is returned. 3117 3118 This function is more numerically stable than log(sum(exp(input))). It avoids 3119 overflows caused by taking the exp of large inputs and underflows caused by 3120 taking the log of small inputs. 3121 3122 For example: 3123 3124 ```python 3125 x = tf.constant([[0., 0., 0.], [0., 0., 0.]]) 3126 tf.reduce_logsumexp(x) # log(6) 3127 tf.reduce_logsumexp(x, 0) # [log(2), log(2), log(2)] 3128 tf.reduce_logsumexp(x, 1) # [log(3), log(3)] 3129 tf.reduce_logsumexp(x, 1, keepdims=True) # [[log(3)], [log(3)]] 3130 tf.reduce_logsumexp(x, [0, 1]) # log(6) 3131 ``` 3132 3133 Args: 3134 input_tensor: The tensor to reduce. Should have numeric type. 3135 axis: The dimensions to reduce. If `None` (the default), reduces all 3136 dimensions. Must be in the range `[-rank(input_tensor), 3137 rank(input_tensor))`. 3138 keepdims: If true, retains reduced dimensions with length 1. 3139 name: A name for the operation (optional). 3140 reduction_indices: The old (deprecated) name for axis. 3141 keep_dims: Deprecated alias for `keepdims`. 3142 3143 Returns: 3144 The reduced tensor. 3145 """ 3146 axis = deprecation.deprecated_argument_lookup("axis", axis, 3147 "reduction_indices", 3148 reduction_indices) 3149 keepdims = deprecation.deprecated_argument_lookup("keepdims", keepdims, 3150 "keep_dims", keep_dims) 3151 return reduce_logsumexp(input_tensor, axis, keepdims, name) 3152 3153 3154@tf_export("math.reduce_logsumexp", "reduce_logsumexp", v1=[]) 3155@dispatch.add_dispatch_support 3156def reduce_logsumexp(input_tensor, axis=None, keepdims=False, name=None): 3157 """Computes log(sum(exp(elements across dimensions of a tensor))). 3158 3159 Reduces `input_tensor` along the dimensions given in `axis`. 3160 Unless `keepdims` is true, the rank of the tensor is reduced by 1 for each 3161 of the entries in `axis`, which must be unique. If `keepdims` is true, the 3162 reduced dimensions are retained with length 1. 3163 3164 If `axis` has no entries, all dimensions are reduced, and a 3165 tensor with a single element is returned. 3166 3167 This function is more numerically stable than log(sum(exp(input))). It avoids 3168 overflows caused by taking the exp of large inputs and underflows caused by 3169 taking the log of small inputs. 3170 3171 For example: 3172 3173 ```python 3174 x = tf.constant([[0., 0., 0.], [0., 0., 0.]]) 3175 tf.reduce_logsumexp(x) # log(6) 3176 tf.reduce_logsumexp(x, 0) # [log(2), log(2), log(2)] 3177 tf.reduce_logsumexp(x, 1) # [log(3), log(3)] 3178 tf.reduce_logsumexp(x, 1, keepdims=True) # [[log(3)], [log(3)]] 3179 tf.reduce_logsumexp(x, [0, 1]) # log(6) 3180 ``` 3181 3182 Args: 3183 input_tensor: The tensor to reduce. Should have numeric type. 3184 axis: The dimensions to reduce. If `None` (the default), reduces all 3185 dimensions. Must be in the range `[-rank(input_tensor), 3186 rank(input_tensor))`. 3187 keepdims: If true, retains reduced dimensions with length 1. 3188 name: A name for the operation (optional). 3189 3190 Returns: 3191 The reduced tensor. 3192 """ 3193 keepdims = False if keepdims is None else keepdims 3194 input_tensor = ops.convert_to_tensor(input_tensor) 3195 with ops.name_scope(name, "ReduceLogSumExp", [input_tensor]) as name: 3196 reduce_dim = _ReductionDims(input_tensor, axis) 3197 raw_max = reduce_max_with_dims( 3198 input_tensor, axis=axis, keepdims=True, dims=reduce_dim) 3199 my_max = array_ops.stop_gradient( 3200 gen_math_ops.select( 3201 gen_math_ops.is_finite(raw_max), raw_max, 3202 gen_array_ops.zeros_like(raw_max))) 3203 result = gen_math_ops.log( 3204 reduce_sum_with_dims( 3205 gen_math_ops.exp(gen_math_ops.sub(input_tensor, my_max)), 3206 axis=axis, 3207 keepdims=keepdims, 3208 dims=reduce_dim)) 3209 if not keepdims: 3210 my_max = array_ops.reshape(my_max, gen_array_ops.shape(result)) 3211 result = _add_dispatch(result, my_max, name=name) 3212 return _may_reduce_to_scalar(keepdims, axis, result) 3213 3214 3215@tf_export("linalg.trace", v1=["linalg.trace", "trace"]) 3216@dispatch.add_dispatch_support 3217@deprecation.deprecated_endpoints("trace") 3218@dispatch.add_dispatch_support 3219def trace(x, name=None): 3220 """Compute the trace of a tensor `x`. 3221 3222 `trace(x)` returns the sum along the main diagonal of each inner-most matrix 3223 in x. If x is of rank `k` with shape `[I, J, K, ..., L, M, N]`, then output 3224 is a tensor of rank `k-2` with dimensions `[I, J, K, ..., L]` where 3225 3226 `output[i, j, k, ..., l] = trace(x[i, j, k, ..., l, :, :])` 3227 3228 For example: 3229 3230 ```python 3231 x = tf.constant([[1, 2], [3, 4]]) 3232 tf.linalg.trace(x) # 5 3233 3234 x = tf.constant([[1, 2, 3], 3235 [4, 5, 6], 3236 [7, 8, 9]]) 3237 tf.linalg.trace(x) # 15 3238 3239 x = tf.constant([[[1, 2, 3], 3240 [4, 5, 6], 3241 [7, 8, 9]], 3242 [[-1, -2, -3], 3243 [-4, -5, -6], 3244 [-7, -8, -9]]]) 3245 tf.linalg.trace(x) # [15, -15] 3246 ``` 3247 3248 Args: 3249 x: tensor. 3250 name: A name for the operation (optional). 3251 3252 Returns: 3253 The trace of input tensor. 3254 """ 3255 with ops.name_scope(name, "Trace", [x]) as name: 3256 x = ops.convert_to_tensor(x, name="x") 3257 return reduce_sum(array_ops.matrix_diag_part(x), [-1], name=name) 3258 3259 3260@tf_export("linalg.matmul", "matmul") 3261@dispatch.add_dispatch_support 3262def matmul(a, 3263 b, 3264 transpose_a=False, 3265 transpose_b=False, 3266 adjoint_a=False, 3267 adjoint_b=False, 3268 a_is_sparse=False, 3269 b_is_sparse=False, 3270 name=None): 3271 """Multiplies matrix `a` by matrix `b`, producing `a` * `b`. 3272 3273 The inputs must, following any transpositions, be tensors of rank >= 2 3274 where the inner 2 dimensions specify valid matrix multiplication dimensions, 3275 and any further outer dimensions specify matching batch size. 3276 3277 Both matrices must be of the same type. The supported types are: 3278 `float16`, `float32`, `float64`, `int32`, `complex64`, `complex128`. 3279 3280 Either matrix can be transposed or adjointed (conjugated and transposed) on 3281 the fly by setting one of the corresponding flag to `True`. These are `False` 3282 by default. 3283 3284 If one or both of the matrices contain a lot of zeros, a more efficient 3285 multiplication algorithm can be used by setting the corresponding 3286 `a_is_sparse` or `b_is_sparse` flag to `True`. These are `False` by default. 3287 This optimization is only available for plain matrices (rank-2 tensors) with 3288 datatypes `bfloat16` or `float32`. 3289 3290 A simple 2-D tensor matrix multiplication: 3291 3292 >>> a = tf.constant([1, 2, 3, 4, 5, 6], shape=[2, 3]) 3293 >>> a # 2-D tensor 3294 <tf.Tensor: shape=(2, 3), dtype=int32, numpy= 3295 array([[1, 2, 3], 3296 [4, 5, 6]], dtype=int32)> 3297 >>> b = tf.constant([7, 8, 9, 10, 11, 12], shape=[3, 2]) 3298 >>> b # 2-D tensor 3299 <tf.Tensor: shape=(3, 2), dtype=int32, numpy= 3300 array([[ 7, 8], 3301 [ 9, 10], 3302 [11, 12]], dtype=int32)> 3303 >>> c = tf.matmul(a, b) 3304 >>> c # `a` * `b` 3305 <tf.Tensor: shape=(2, 2), dtype=int32, numpy= 3306 array([[ 58, 64], 3307 [139, 154]], dtype=int32)> 3308 3309 A batch matrix multiplication with batch shape [2]: 3310 3311 >>> a = tf.constant(np.arange(1, 13, dtype=np.int32), shape=[2, 2, 3]) 3312 >>> a # 3-D tensor 3313 <tf.Tensor: shape=(2, 2, 3), dtype=int32, numpy= 3314 array([[[ 1, 2, 3], 3315 [ 4, 5, 6]], 3316 [[ 7, 8, 9], 3317 [10, 11, 12]]], dtype=int32)> 3318 >>> b = tf.constant(np.arange(13, 25, dtype=np.int32), shape=[2, 3, 2]) 3319 >>> b # 3-D tensor 3320 <tf.Tensor: shape=(2, 3, 2), dtype=int32, numpy= 3321 array([[[13, 14], 3322 [15, 16], 3323 [17, 18]], 3324 [[19, 20], 3325 [21, 22], 3326 [23, 24]]], dtype=int32)> 3327 >>> c = tf.matmul(a, b) 3328 >>> c # `a` * `b` 3329 <tf.Tensor: shape=(2, 2, 2), dtype=int32, numpy= 3330 array([[[ 94, 100], 3331 [229, 244]], 3332 [[508, 532], 3333 [697, 730]]], dtype=int32)> 3334 3335 Since python >= 3.5 the @ operator is supported 3336 (see [PEP 465](https://www.python.org/dev/peps/pep-0465/)). In TensorFlow, 3337 it simply calls the `tf.matmul()` function, so the following lines are 3338 equivalent: 3339 3340 >>> d = a @ b @ [[10], [11]] 3341 >>> d = tf.matmul(tf.matmul(a, b), [[10], [11]]) 3342 3343 Args: 3344 a: `tf.Tensor` of type `float16`, `float32`, `float64`, `int32`, 3345 `complex64`, `complex128` and rank > 1. 3346 b: `tf.Tensor` with same type and rank as `a`. 3347 transpose_a: If `True`, `a` is transposed before multiplication. 3348 transpose_b: If `True`, `b` is transposed before multiplication. 3349 adjoint_a: If `True`, `a` is conjugated and transposed before 3350 multiplication. 3351 adjoint_b: If `True`, `b` is conjugated and transposed before 3352 multiplication. 3353 a_is_sparse: If `True`, `a` is treated as a sparse matrix. Notice, this 3354 **does not support `tf.sparse.SparseTensor`**, it just makes optimizations 3355 that assume most values in `a` are zero. 3356 See `tf.sparse.sparse_dense_matmul` 3357 for some support for `tf.sparse.SparseTensor` multiplication. 3358 b_is_sparse: If `True`, `b` is treated as a sparse matrix. Notice, this 3359 **does not support `tf.sparse.SparseTensor`**, it just makes optimizations 3360 that assume most values in `a` are zero. 3361 See `tf.sparse.sparse_dense_matmul` 3362 for some support for `tf.sparse.SparseTensor` multiplication. 3363 name: Name for the operation (optional). 3364 3365 Returns: 3366 A `tf.Tensor` of the same type as `a` and `b` where each inner-most matrix 3367 is the product of the corresponding matrices in `a` and `b`, e.g. if all 3368 transpose or adjoint attributes are `False`: 3369 3370 `output[..., i, j] = sum_k (a[..., i, k] * b[..., k, j])`, 3371 for all indices `i`, `j`. 3372 3373 Note: This is matrix product, not element-wise product. 3374 3375 3376 Raises: 3377 ValueError: If `transpose_a` and `adjoint_a`, or `transpose_b` and 3378 `adjoint_b` are both set to `True`. 3379 """ 3380 with ops.name_scope(name, "MatMul", [a, b]) as name: 3381 if transpose_a and adjoint_a: 3382 raise ValueError("Only one of transpose_a and adjoint_a can be True.") 3383 if transpose_b and adjoint_b: 3384 raise ValueError("Only one of transpose_b and adjoint_b can be True.") 3385 3386 if context.executing_eagerly(): 3387 if not isinstance(a, (ops.EagerTensor, _resource_variable_type)): 3388 a = ops.convert_to_tensor(a, name="a") 3389 if not isinstance(b, (ops.EagerTensor, _resource_variable_type)): 3390 b = ops.convert_to_tensor(b, dtype_hint=a.dtype.base_dtype, name="b") 3391 else: 3392 a = ops.convert_to_tensor(a, name="a") 3393 b = ops.convert_to_tensor(b, dtype_hint=a.dtype.base_dtype, name="b") 3394 3395 # TODO(apassos) remove _shape_tuple here when it is not needed. 3396 a_shape = a._shape_tuple() # pylint: disable=protected-access 3397 b_shape = b._shape_tuple() # pylint: disable=protected-access 3398 3399 output_may_have_non_empty_batch_shape = ( 3400 (a_shape is None or len(a_shape) > 2) or 3401 (b_shape is None or len(b_shape) > 2)) 3402 3403 if (not a_is_sparse and 3404 not b_is_sparse) and output_may_have_non_empty_batch_shape: 3405 # BatchMatmul does not support transpose, so we conjugate the matrix and 3406 # use adjoint instead. Conj() is a noop for real matrices. 3407 if transpose_a: 3408 a = conj(a) 3409 adjoint_a = True 3410 if transpose_b: 3411 b = conj(b) 3412 adjoint_b = True 3413 return gen_math_ops.batch_mat_mul_v2( 3414 a, b, adj_x=adjoint_a, adj_y=adjoint_b, name=name) 3415 3416 # Neither matmul nor sparse_matmul support adjoint, so we conjugate 3417 # the matrix and use transpose instead. Conj() is a noop for real 3418 # matrices. 3419 if adjoint_a: 3420 a = conj(a) 3421 transpose_a = True 3422 if adjoint_b: 3423 b = conj(b) 3424 transpose_b = True 3425 3426 use_sparse_matmul = False 3427 if a_is_sparse or b_is_sparse: 3428 sparse_matmul_types = [dtypes.bfloat16, dtypes.float32] 3429 use_sparse_matmul = ( 3430 a.dtype in sparse_matmul_types and b.dtype in sparse_matmul_types) 3431 if ((a.dtype == dtypes.bfloat16 or b.dtype == dtypes.bfloat16) and 3432 a.dtype != b.dtype): 3433 # matmul currently doesn't handle mixed-precision inputs. 3434 use_sparse_matmul = True 3435 if use_sparse_matmul: 3436 ret = sparse_matmul( 3437 a, 3438 b, 3439 transpose_a=transpose_a, 3440 transpose_b=transpose_b, 3441 a_is_sparse=a_is_sparse, 3442 b_is_sparse=b_is_sparse, 3443 name=name) 3444 # sparse_matmul always returns float32, even with 3445 # bfloat16 inputs. This prevents us from configuring bfloat16 training. 3446 # casting to bfloat16 also matches non-sparse matmul behavior better. 3447 if a.dtype == dtypes.bfloat16 and b.dtype == dtypes.bfloat16: 3448 ret = cast(ret, dtypes.bfloat16) 3449 return ret 3450 else: 3451 return gen_math_ops.mat_mul( 3452 a, b, transpose_a=transpose_a, transpose_b=transpose_b, name=name) 3453 3454 3455@tf_export("linalg.matvec") 3456@dispatch.add_dispatch_support 3457def matvec(a, 3458 b, 3459 transpose_a=False, 3460 adjoint_a=False, 3461 a_is_sparse=False, 3462 b_is_sparse=False, 3463 name=None): 3464 """Multiplies matrix `a` by vector `b`, producing `a` * `b`. 3465 3466 The matrix `a` must, following any transpositions, be a tensor of rank >= 2, 3467 with `shape(a)[-1] == shape(b)[-1]`, and `shape(a)[:-2]` able to broadcast 3468 with `shape(b)[:-1]`. 3469 3470 Both `a` and `b` must be of the same type. The supported types are: 3471 `float16`, `float32`, `float64`, `int32`, `complex64`, `complex128`. 3472 3473 Matrix `a` can be transposed or adjointed (conjugated and transposed) on 3474 the fly by setting one of the corresponding flag to `True`. These are `False` 3475 by default. 3476 3477 If one or both of the inputs contain a lot of zeros, a more efficient 3478 multiplication algorithm can be used by setting the corresponding 3479 `a_is_sparse` or `b_is_sparse` flag to `True`. These are `False` by default. 3480 This optimization is only available for plain matrices/vectors (rank-2/1 3481 tensors) with datatypes `bfloat16` or `float32`. 3482 3483 For example: 3484 3485 ```python 3486 # 2-D tensor `a` 3487 # [[1, 2, 3], 3488 # [4, 5, 6]] 3489 a = tf.constant([1, 2, 3, 4, 5, 6], shape=[2, 3]) 3490 3491 # 1-D tensor `b` 3492 # [7, 9, 11] 3493 b = tf.constant([7, 9, 11], shape=[3]) 3494 3495 # `a` * `b` 3496 # [ 58, 64] 3497 c = tf.linalg.matvec(a, b) 3498 3499 3500 # 3-D tensor `a` 3501 # [[[ 1, 2, 3], 3502 # [ 4, 5, 6]], 3503 # [[ 7, 8, 9], 3504 # [10, 11, 12]]] 3505 a = tf.constant(np.arange(1, 13, dtype=np.int32), 3506 shape=[2, 2, 3]) 3507 3508 # 2-D tensor `b` 3509 # [[13, 14, 15], 3510 # [16, 17, 18]] 3511 b = tf.constant(np.arange(13, 19, dtype=np.int32), 3512 shape=[2, 3]) 3513 3514 # `a` * `b` 3515 # [[ 86, 212], 3516 # [410, 563]] 3517 c = tf.linalg.matvec(a, b) 3518 ``` 3519 3520 Args: 3521 a: `Tensor` of type `float16`, `float32`, `float64`, `int32`, `complex64`, 3522 `complex128` and rank > 1. 3523 b: `Tensor` with same type as `a` and compatible dimensions. 3524 transpose_a: If `True`, `a` is transposed before multiplication. 3525 adjoint_a: If `True`, `a` is conjugated and transposed before 3526 multiplication. 3527 a_is_sparse: If `True`, `a` is treated as a sparse matrix. 3528 b_is_sparse: If `True`, `b` is treated as a sparse matrix. 3529 name: Name for the operation (optional). 3530 3531 Returns: 3532 A `Tensor` of the same type as `a` and `b` where each inner-most vector is 3533 the product of the corresponding matrices in `a` and vectors in `b`, e.g. if 3534 all transpose or adjoint attributes are `False`: 3535 3536 `output`[..., i] = sum_k (`a`[..., i, k] * `b`[..., k]), for all indices i. 3537 3538 Note: This is matrix-vector product, not element-wise product. 3539 3540 3541 Raises: 3542 ValueError: If transpose_a and adjoint_a are both set to True. 3543 """ 3544 with ops.name_scope(name, "MatVec", [a, b]) as name: 3545 output = matmul( 3546 a, 3547 array_ops.expand_dims(b, axis=-1), 3548 transpose_a=transpose_a, 3549 adjoint_a=adjoint_a, 3550 a_is_sparse=a_is_sparse, 3551 b_is_sparse=b_is_sparse) 3552 return array_ops.squeeze(output, axis=-1) 3553 3554 3555# TODO(b/178650720): Also support numpy-style type promotion in freestanding TF 3556# functions (e.g. tf.add). 3557def matmul_wrapper(a, b, name=None): # pylint: disable=missing-function-docstring 3558 if ops._numpy_style_type_promotion: 3559 return a._matmul(b) 3560 return matmul(a, b, name=name) 3561matmul_wrapper.__doc__ = matmul.__doc__ 3562_OverrideBinaryOperatorHelper(matmul_wrapper, "matmul") 3563 3564sparse_matmul = deprecation.deprecated(None, "Use `tf.linalg.matmul` instead")( 3565 gen_math_ops.sparse_mat_mul) 3566tf_export(v1=["sparse_matmul"])(sparse_matmul) 3567@dispatch.add_dispatch_support 3568 3569 3570@ops.RegisterStatistics("MatMul", "flops") 3571def _calc_mat_mul_flops(graph, node): 3572 """Calculates the compute resources needed for MatMul.""" 3573 transpose_a = node.attr["transpose_a"].b 3574 a_shape = graph_util.tensor_shape_from_node_def_name(graph, node.input[0]) 3575 a_shape.assert_is_fully_defined() 3576 if transpose_a: 3577 k = int(a_shape[0]) 3578 else: 3579 k = int(a_shape[1]) 3580 output_shape = graph_util.tensor_shape_from_node_def_name(graph, node.name) 3581 output_shape.assert_is_fully_defined() 3582 output_count = np.prod(output_shape.as_list()) 3583 return ops.OpStats("flops", (k * output_count * 2)) 3584 3585 3586@ops.RegisterStatistics("BatchMatMul", "flops") 3587@ops.RegisterStatistics("BatchMatMulV2", "flops") 3588def _calc_batch_mat_mul_flops(graph, node): 3589 """Calculates the compute resources needed for BatchMatMul.""" 3590 transpose_a = node.attr["transpose_a"].b 3591 a_shape = graph_util.tensor_shape_from_node_def_name(graph, node.input[0]) 3592 a_shape.assert_is_fully_defined() 3593 if transpose_a: 3594 k = int(a_shape[-2]) 3595 else: 3596 k = int(a_shape[-1]) 3597 output_shape = graph_util.tensor_shape_from_node_def_name(graph, node.name) 3598 output_shape.assert_is_fully_defined() 3599 output_count = np.prod(output_shape.as_list()) 3600 return ops.OpStats("flops", (k * output_count * 2)) 3601 3602 3603def _as_indexed_slices(x, optimize=True): 3604 """Convert 'x' to IndexedSlices. 3605 3606 Convert a dense Tensor to a block-sparse IndexedSlices. 3607 3608 Args: 3609 x: Either a Tensor object, or an IndexedSlices object. 3610 optimize: if true, attempt to optimize the conversion of 'x'. 3611 3612 Returns: 3613 An IndexedSlices object. 3614 3615 Raises: 3616 TypeError: If 'x' is not a Tensor or an IndexedSlices object. 3617 """ 3618 # TODO(touts): op_scope 3619 if not isinstance(x, (ops.Tensor, ops.IndexedSlices)): 3620 raise TypeError("Not a Tensor or IndexedSlices: %s" % type(x)) 3621 if isinstance(x, ops.IndexedSlices): 3622 return x 3623 x_shape = array_ops.shape_internal(x, optimize=optimize) 3624 return ops.IndexedSlices(x, range(0, x_shape[0]), x_shape) 3625 3626 3627def _as_indexed_slices_list(inputs, optimize=True): 3628 """Convert all elements of 'inputs' to IndexedSlices. 3629 3630 Additionally, homogenize the types of all the indices to 3631 either int32 or int64. 3632 3633 Args: 3634 inputs: List containing either Tensor or IndexedSlices objects. 3635 optimize: if true, attempt to optimize the conversion of each input. 3636 3637 Returns: 3638 A list of IndexedSlices objects. 3639 3640 Raises: 3641 TypeError: If 'inputs' is not a list or a tuple. 3642 """ 3643 if not isinstance(inputs, (list, tuple)): 3644 raise TypeError("Expected a list or tuple, not a %s" % type(inputs)) 3645 outputs = [_as_indexed_slices(i, optimize=optimize) for i in inputs] 3646 with_int32_index = [ 3647 o.indices for o in outputs if o.indices.dtype == dtypes.int32 3648 ] 3649 if not with_int32_index or len(with_int32_index) == len(outputs): 3650 return outputs 3651 casted_outputs = [] 3652 for o in outputs: 3653 if o.indices.dtype == dtypes.int32: 3654 casted_outputs.append( 3655 ops.IndexedSlices(o.values, cast(o.indices, dtypes.int64), 3656 o.dense_shape)) 3657 else: 3658 casted_outputs.append(o) 3659 return casted_outputs 3660 3661 3662@tf_export("math.add_n", "add_n") 3663@dispatch.add_dispatch_support 3664def add_n(inputs, name=None): 3665 """Adds all input tensors element-wise. 3666 3667 `tf.math.add_n` performs the same operation as `tf.math.accumulate_n`, but it 3668 waits for all of its inputs to be ready before beginning to sum. 3669 This buffering can result in higher memory consumption when inputs are ready 3670 at different times, since the minimum temporary storage required is 3671 proportional to the input size rather than the output size. 3672 3673 This op does not [broadcast]( 3674 https://docs.scipy.org/doc/numpy-1.13.0/user/basics.broadcasting.html) 3675 its inputs. If you need broadcasting, use `tf.math.add` (or the `+` operator) 3676 instead. 3677 3678 For example: 3679 3680 >>> a = tf.constant([[3, 5], [4, 8]]) 3681 >>> b = tf.constant([[1, 6], [2, 9]]) 3682 >>> tf.math.add_n([a, b, a]) 3683 <tf.Tensor: shape=(2, 2), dtype=int32, numpy= 3684 array([[ 7, 16], 3685 [10, 25]], dtype=int32)> 3686 3687 Args: 3688 inputs: A list of `tf.Tensor` or `tf.IndexedSlices` objects, each with the 3689 same shape and type. `tf.IndexedSlices` objects will be converted into 3690 dense tensors prior to adding. 3691 name: A name for the operation (optional). 3692 3693 Returns: 3694 A `tf.Tensor` of the same shape and type as the elements of `inputs`. 3695 3696 Raises: 3697 ValueError: If `inputs` don't all have same shape and dtype or the shape 3698 cannot be inferred. 3699 """ 3700 if not inputs or not isinstance(inputs, collections_abc.Iterable): 3701 raise ValueError("inputs must be an iterable of at least one " 3702 "Tensor/IndexedSlices with the same dtype and shape") 3703 inputs = ops.convert_n_to_tensor_or_indexed_slices(inputs) 3704 if not all(isinstance(x, (ops.Tensor, ops.IndexedSlices)) for x in inputs): 3705 raise ValueError("inputs must be an iterable of at least one " 3706 "Tensor/IndexedSlices with the same dtype and shape") 3707 3708 if len(inputs) == 1: 3709 if isinstance(inputs[0], ops.IndexedSlices): 3710 values = ops.convert_to_tensor(inputs[0]) 3711 else: 3712 values = inputs[0] 3713 if name: 3714 return array_ops.identity(values, name=name) 3715 return values 3716 return gen_math_ops.add_n(inputs, name=name) 3717 3718 3719@tf_export("math.accumulate_n", v1=["math.accumulate_n", "accumulate_n"]) 3720@dispatch.add_dispatch_support 3721@deprecation.deprecated_endpoints("accumulate_n") 3722def accumulate_n(inputs, shape=None, tensor_dtype=None, name=None): 3723 """Returns the element-wise sum of a list of tensors. 3724 3725 Optionally, pass `shape` and `tensor_dtype` for shape and type checking, 3726 otherwise, these are inferred. 3727 3728 `accumulate_n` performs the same operation as `tf.math.add_n`. 3729 3730 For example: 3731 3732 ```python 3733 a = tf.constant([[1, 2], [3, 4]]) 3734 b = tf.constant([[5, 0], [0, 6]]) 3735 tf.math.accumulate_n([a, b, a]) # [[7, 4], [6, 14]] 3736 3737 # Explicitly pass shape and type 3738 tf.math.accumulate_n([a, b, a], shape=[2, 2], tensor_dtype=tf.int32) 3739 # [[7, 4], 3740 # [6, 14]] 3741 ``` 3742 3743 Args: 3744 inputs: A list of `Tensor` objects, each with same shape and type. 3745 shape: Expected shape of elements of `inputs` (optional). Also controls the 3746 output shape of this op, which may affect type inference in other ops. A 3747 value of `None` means "infer the input shape from the shapes in `inputs`". 3748 tensor_dtype: Expected data type of `inputs` (optional). A value of `None` 3749 means "infer the input dtype from `inputs[0]`". 3750 name: A name for the operation (optional). 3751 3752 Returns: 3753 A `Tensor` of same shape and type as the elements of `inputs`. 3754 3755 Raises: 3756 ValueError: If `inputs` don't all have same shape and dtype or the shape 3757 cannot be inferred. 3758 """ 3759 3760 def _input_error(): 3761 return ValueError("inputs must be a list of at least one Tensor with the " 3762 "same dtype and shape") 3763 3764 if not inputs or not isinstance(inputs, (list, tuple)): 3765 raise _input_error() 3766 inputs = ops.convert_n_to_tensor_or_indexed_slices(inputs) 3767 if not all(isinstance(x, ops.Tensor) for x in inputs): 3768 raise _input_error() 3769 if not all(x.dtype == inputs[0].dtype for x in inputs): 3770 raise _input_error() 3771 if shape is not None: 3772 shape = tensor_shape.as_shape(shape) 3773 else: 3774 shape = tensor_shape.unknown_shape() 3775 for input_tensor in inputs: 3776 if isinstance(input_tensor, ops.Tensor): 3777 shape = shape.merge_with(input_tensor.get_shape()) 3778 3779 # tensor_dtype is for safety only; operator's output type computed in C++ 3780 if tensor_dtype is not None and tensor_dtype != inputs[0].dtype: 3781 raise TypeError("tensor_dtype is {}, but input is of type {}".format( 3782 tensor_dtype, inputs[0].dtype)) 3783 3784 if len(inputs) == 1 and name is None: 3785 return inputs[0] 3786 elif len(inputs) == 1 and name is not None: 3787 return array_ops.identity(inputs[0], name=name) 3788 return add_n(inputs, name=name) 3789 3790 3791@ops.RegisterGradient("AccumulateNV2") 3792def _accumulate_n_grad(op, grad): 3793 """Same as gradient for AddN. Copies the gradient to all inputs.""" 3794 # Not broadcasting. 3795 return [grad] * len(op.inputs) 3796 3797 3798@tf_export("math.sigmoid", "nn.sigmoid", "sigmoid") 3799@dispatch.add_dispatch_support 3800def sigmoid(x, name=None): 3801 r"""Computes sigmoid of `x` element-wise. 3802 3803 Formula for calculating $\mathrm{sigmoid}(x) = y = 1 / (1 + \exp(-x))$. 3804 3805 For $x \in (-\infty, \infty)$, $\mathrm{sigmoid}(x) \in (0, 1)$. 3806 3807 Example Usage: 3808 3809 If a positive number is large, then its sigmoid will approach to 1 since the 3810 formula will be `y = <large_num> / (1 + <large_num>)` 3811 3812 >>> x = tf.constant([0.0, 1.0, 50.0, 100.0]) 3813 >>> tf.math.sigmoid(x) 3814 <tf.Tensor: shape=(4,), dtype=float32, 3815 numpy=array([0.5 , 0.7310586, 1. , 1. ], dtype=float32)> 3816 3817 If a negative number is large, its sigmoid will approach to 0 since the 3818 formula will be `y = 1 / (1 + <large_num>)` 3819 3820 >>> x = tf.constant([-100.0, -50.0, -1.0, 0.0]) 3821 >>> tf.math.sigmoid(x) 3822 <tf.Tensor: shape=(4,), dtype=float32, numpy= 3823 array([0.0000000e+00, 1.9287499e-22, 2.6894143e-01, 0.5], 3824 dtype=float32)> 3825 3826 Args: 3827 x: A Tensor with type `float16`, `float32`, `float64`, `complex64`, or 3828 `complex128`. 3829 name: A name for the operation (optional). 3830 3831 Returns: 3832 A Tensor with the same type as `x`. 3833 3834 Usage Example: 3835 3836 >>> x = tf.constant([-128.0, 0.0, 128.0], dtype=tf.float32) 3837 >>> tf.sigmoid(x) 3838 <tf.Tensor: shape=(3,), dtype=float32, 3839 numpy=array([0. , 0.5, 1. ], dtype=float32)> 3840 3841 @compatibility(scipy) 3842 Equivalent to scipy.special.expit 3843 @end_compatibility 3844 """ 3845 with ops.name_scope(name, "Sigmoid", [x]) as name: 3846 x = ops.convert_to_tensor(x, name="x") 3847 return gen_math_ops.sigmoid(x, name=name) 3848 3849 3850@tf_export("math.log_sigmoid", v1=["math.log_sigmoid", "log_sigmoid"]) 3851@dispatch.add_dispatch_support 3852@deprecation.deprecated_endpoints("log_sigmoid") 3853def log_sigmoid(x, name=None): 3854 """Computes log sigmoid of `x` element-wise. 3855 3856 Specifically, `y = log(1 / (1 + exp(-x)))`. For numerical stability, 3857 we use `y = -tf.nn.softplus(-x)`. 3858 3859 Args: 3860 x: A Tensor with type `float32` or `float64`. 3861 name: A name for the operation (optional). 3862 3863 Returns: 3864 A Tensor with the same type as `x`. 3865 3866 Usage Example: 3867 3868 If a positive number is large, then its log_sigmoid will approach to 0 since 3869 the formula will be `y = log( <large_num> / (1 + <large_num>) )` which 3870 approximates to `log (1)` which is 0. 3871 3872 >>> x = tf.constant([0.0, 1.0, 50.0, 100.0]) 3873 >>> tf.math.log_sigmoid(x) 3874 <tf.Tensor: shape=(4,), dtype=float32, numpy= 3875 array([-6.9314718e-01, -3.1326169e-01, -1.9287499e-22, -0.0000000e+00], 3876 dtype=float32)> 3877 3878 If a negative number is large, its log_sigmoid will approach to the number 3879 itself since the formula will be `y = log( 1 / (1 + <large_num>) )` which is 3880 `log (1) - log ( (1 + <large_num>) )` which approximates to `- <large_num>` 3881 that is the number itself. 3882 3883 >>> x = tf.constant([-100.0, -50.0, -1.0, 0.0]) 3884 >>> tf.math.log_sigmoid(x) 3885 <tf.Tensor: shape=(4,), dtype=float32, numpy= 3886 array([-100. , -50. , -1.3132616, -0.6931472], 3887 dtype=float32)> 3888 """ 3889 with ops.name_scope(name, "LogSigmoid", [x]) as name: 3890 x = ops.convert_to_tensor(x, name="x") 3891 return gen_math_ops.neg(gen_nn_ops.softplus(-x), name=name) 3892 3893 3894@tf_export("math.cumsum", "cumsum") 3895@dispatch.add_dispatch_support 3896def cumsum(x, axis=0, exclusive=False, reverse=False, name=None): 3897 """Compute the cumulative sum of the tensor `x` along `axis`. 3898 3899 By default, this op performs an inclusive cumsum, which means that the first 3900 element of the input is identical to the first element of the output: 3901 For example: 3902 3903 >>> # tf.cumsum([a, b, c]) # [a, a + b, a + b + c] 3904 >>> x = tf.constant([2, 4, 6, 8]) 3905 >>> tf.cumsum(x) 3906 <tf.Tensor: shape=(4,), dtype=int32, 3907 numpy=array([ 2, 6, 12, 20], dtype=int32)> 3908 3909 >>> # using varying `axis` values 3910 >>> y = tf.constant([[2, 4, 6, 8], [1,3,5,7]]) 3911 >>> tf.cumsum(y, axis=0) 3912 <tf.Tensor: shape=(2, 4), dtype=int32, numpy= 3913 array([[ 2, 4, 6, 8], 3914 [ 3, 7, 11, 15]], dtype=int32)> 3915 >>> tf.cumsum(y, axis=1) 3916 <tf.Tensor: shape=(2, 4), dtype=int32, numpy= 3917 array([[ 2, 6, 12, 20], 3918 [ 1, 4, 9, 16]], dtype=int32)> 3919 3920 By setting the `exclusive` kwarg to `True`, an exclusive cumsum is performed 3921 instead: 3922 3923 >>> # tf.cumsum([a, b, c], exclusive=True) => [0, a, a + b] 3924 >>> x = tf.constant([2, 4, 6, 8]) 3925 >>> tf.cumsum(x, exclusive=True) 3926 <tf.Tensor: shape=(4,), dtype=int32, 3927 numpy=array([ 0, 2, 6, 12], dtype=int32)> 3928 3929 By setting the `reverse` kwarg to `True`, the cumsum is performed in the 3930 opposite direction: 3931 3932 >>> # tf.cumsum([a, b, c], reverse=True) # [a + b + c, b + c, c] 3933 >>> x = tf.constant([2, 4, 6, 8]) 3934 >>> tf.cumsum(x, reverse=True) 3935 <tf.Tensor: shape=(4,), dtype=int32, 3936 numpy=array([20, 18, 14, 8], dtype=int32)> 3937 3938 This is more efficient than using separate `tf.reverse` ops. 3939 The `reverse` and `exclusive` kwargs can also be combined: 3940 3941 >>> # tf.cumsum([a, b, c], exclusive=True, reverse=True) # [b + c, c, 0] 3942 >>> x = tf.constant([2, 4, 6, 8]) 3943 >>> tf.cumsum(x, exclusive=True, reverse=True) 3944 <tf.Tensor: shape=(4,), dtype=int32, 3945 numpy=array([18, 14, 8, 0], dtype=int32)> 3946 3947 Args: 3948 x: A `Tensor`. Must be one of the following types: `float32`, `float64`, 3949 `int64`, `int32`, `uint8`, `uint16`, `int16`, `int8`, `complex64`, 3950 `complex128`, `qint8`, `quint8`, `qint32`, `half`. 3951 axis: A `Tensor` of type `int32` (default: 0). Must be in the range 3952 `[-rank(x), rank(x))`. 3953 exclusive: If `True`, perform exclusive cumsum. 3954 reverse: A `bool` (default: False). 3955 name: A name for the operation (optional). 3956 3957 Returns: 3958 A `Tensor`. Has the same type as `x`. 3959 """ 3960 with ops.name_scope(name, "Cumsum", [x]) as name: 3961 x = ops.convert_to_tensor(x, name="x") 3962 return gen_math_ops.cumsum( 3963 x, axis, exclusive=exclusive, reverse=reverse, name=name) 3964 3965 3966@tf_export("math.cumprod", v1=["math.cumprod", "cumprod"]) 3967@dispatch.add_dispatch_support 3968@deprecation.deprecated_endpoints("cumprod") 3969def cumprod(x, axis=0, exclusive=False, reverse=False, name=None): 3970 """Compute the cumulative product of the tensor `x` along `axis`. 3971 3972 By default, this op performs an inclusive cumprod, which means that the 3973 first element of the input is identical to the first element of the output: 3974 3975 ```python 3976 tf.math.cumprod([a, b, c]) # [a, a * b, a * b * c] 3977 ``` 3978 3979 By setting the `exclusive` kwarg to `True`, an exclusive cumprod is 3980 performed 3981 instead: 3982 3983 ```python 3984 tf.math.cumprod([a, b, c], exclusive=True) # [1, a, a * b] 3985 ``` 3986 3987 By setting the `reverse` kwarg to `True`, the cumprod is performed in the 3988 opposite direction: 3989 3990 ```python 3991 tf.math.cumprod([a, b, c], reverse=True) # [a * b * c, b * c, c] 3992 ``` 3993 3994 This is more efficient than using separate `tf.reverse` ops. 3995 The `reverse` and `exclusive` kwargs can also be combined: 3996 3997 ```python 3998 tf.math.cumprod([a, b, c], exclusive=True, reverse=True) # [b * c, c, 1] 3999 ``` 4000 4001 Args: 4002 x: A `Tensor`. Must be one of the following types: `float32`, `float64`, 4003 `int64`, `int32`, `uint8`, `uint16`, `int16`, `int8`, `complex64`, 4004 `complex128`, `qint8`, `quint8`, `qint32`, `half`. 4005 axis: A `Tensor` of type `int32` (default: 0). Must be in the range 4006 `[-rank(x), rank(x))`. 4007 exclusive: If `True`, perform exclusive cumprod. 4008 reverse: A `bool` (default: False). 4009 name: A name for the operation (optional). 4010 4011 Returns: 4012 A `Tensor`. Has the same type as `x`. 4013 """ 4014 with ops.name_scope(name, "Cumprod", [x]) as name: 4015 x = ops.convert_to_tensor(x, name="x") 4016 return gen_math_ops.cumprod( 4017 x, axis, exclusive=exclusive, reverse=reverse, name=name) 4018 4019 4020@tf_export("math.cumulative_logsumexp", v1=["math.cumulative_logsumexp"]) 4021@dispatch.add_dispatch_support 4022def cumulative_logsumexp(x, axis=0, exclusive=False, reverse=False, name=None): 4023 """Compute the cumulative log-sum-exp of the tensor `x` along `axis`. 4024 4025 By default, this op performs an inclusive cumulative log-sum-exp, which means 4026 that the first element of the input is identical to the first element of 4027 the output. 4028 4029 This operation is significantly more numerically stable than the equivalent 4030 tensorflow operation `tf.math.log(tf.math.cumsum(tf.math.exp(x)))`, although 4031 computes the same result given infinite numerical precision. However, note 4032 that in some cases, it may be less stable than `tf.math.reduce_logsumexp` 4033 for a given element, as it applies the "log-sum-exp trick" in a different 4034 way. 4035 4036 More precisely, where `tf.math.reduce_logsumexp` uses the following trick: 4037 4038 ``` 4039 log(sum(exp(x))) == log(sum(exp(x - max(x)))) + max(x) 4040 ``` 4041 4042 it cannot be directly used here as there is no fast way of applying it 4043 to each prefix `x[:i]`. Instead, this function implements a prefix 4044 scan using pairwise log-add-exp, which is a commutative and associative 4045 (up to floating point precision) operator: 4046 4047 ``` 4048 log_add_exp(x, y) = log(exp(x) + exp(y)) 4049 = log(1 + exp(min(x, y) - max(x, y))) + max(x, y) 4050 ``` 4051 4052 However, reducing using the above operator leads to a different computation 4053 tree (logs are taken repeatedly instead of only at the end), and the maximum 4054 is only computed pairwise instead of over the entire prefix. In general, this 4055 leads to a different and slightly less precise computation. 4056 4057 Args: 4058 x: A `Tensor`. Must be one of the following types: `float16`, `float32`, 4059 `float64`. 4060 axis: A `Tensor` of type `int32` or `int64` (default: 0). Must be in the 4061 range `[-rank(x), rank(x))`. 4062 exclusive: If `True`, perform exclusive cumulative log-sum-exp. 4063 reverse: If `True`, performs the cumulative log-sum-exp in the reverse 4064 direction. 4065 name: A name for the operation (optional). 4066 4067 Returns: 4068 A `Tensor`. Has the same shape and type as `x`. 4069 """ 4070 with ops.name_scope(name, "CumulativeLogsumexp", [x]) as name: 4071 x = ops.convert_to_tensor(x, name="x") 4072 return gen_math_ops.cumulative_logsumexp( 4073 x, axis, exclusive=exclusive, reverse=reverse, name=name) 4074 4075 4076@tf_export("math.conj", v1=["math.conj", "conj"]) 4077@dispatch.add_dispatch_support 4078@deprecation.deprecated_endpoints("conj") 4079def conj(x, name=None): 4080 r"""Returns the complex conjugate of a complex number. 4081 4082 Given a tensor `x` of complex numbers, this operation returns a tensor of 4083 complex numbers that are the complex conjugate of each element in `x`. The 4084 complex numbers in `x` must be of the form \\(a + bj\\), where `a` is the 4085 real part and `b` is the imaginary part. 4086 4087 The complex conjugate returned by this operation is of the form \\(a - bj\\). 4088 4089 For example: 4090 4091 >>> x = tf.constant([-2.25 + 4.75j, 3.25 + 5.75j]) 4092 >>> tf.math.conj(x) 4093 <tf.Tensor: shape=(2,), dtype=complex128, 4094 numpy=array([-2.25-4.75j, 3.25-5.75j])> 4095 4096 If `x` is real, it is returned unchanged. 4097 4098 For example: 4099 4100 >>> x = tf.constant([-2.25, 3.25]) 4101 >>> tf.math.conj(x) 4102 <tf.Tensor: shape=(2,), dtype=float32, 4103 numpy=array([-2.25, 3.25], dtype=float32)> 4104 4105 Args: 4106 x: `Tensor` to conjugate. Must have numeric or variant type. 4107 name: A name for the operation (optional). 4108 4109 Returns: 4110 A `Tensor` that is the conjugate of `x` (with the same type). 4111 4112 Raises: 4113 TypeError: If `x` is not a numeric tensor. 4114 4115 @compatibility(numpy) 4116 Equivalent to numpy.conj. 4117 @end_compatibility 4118 """ 4119 if isinstance(x, ops.Tensor): 4120 dt = x.dtype 4121 if dt.is_floating or dt.is_integer: 4122 return x 4123 with ops.name_scope(name, "Conj", [x]) as name: 4124 x = ops.convert_to_tensor(x, name="x") 4125 if x.dtype.is_complex or x.dtype == dtypes.variant: 4126 return gen_math_ops.conj(x, name=name) 4127 elif x.dtype.is_floating or x.dtype.is_integer: 4128 return x 4129 else: 4130 raise TypeError("Expected numeric or variant tensor, got dtype %r" % 4131 x.dtype) 4132 4133 4134def reduced_shape(input_shape, axes): 4135 """Helper function for reduction ops. 4136 4137 Args: 4138 input_shape: 1-D Tensor, the shape of the Tensor being reduced. 4139 axes: 1-D Tensor, the reduction axes. 4140 4141 Returns: 4142 A 1-D Tensor, the output shape as if keepdims were set to True. 4143 """ 4144 # TODO(allenl): Refactor `reduced_shape` to take the tensor corresponding to 4145 # `input_shape` rather than `tf.shape` of it. Then we can check if the shape 4146 # is fully defined here, which may be faster executing eagerly than running 4147 # `tf.shape` and then fetching its constant value. 4148 constant_input_shape = tensor_util.constant_value(input_shape) 4149 if constant_input_shape is not None: 4150 constant_axes = tensor_util.constant_value(axes) 4151 if constant_axes is not None: 4152 constant_axes = np.array(constant_axes, dtype=np.int32) 4153 constant_input_shape = np.array(constant_input_shape, dtype=np.int32) 4154 constant_input_shape[constant_axes] = 1 4155 return constant_input_shape 4156 4157 # Example: 4158 # cast needed for SparseTensor reductions 4159 input_shape = cast(input_shape, dtypes.int32) # [2, 3, 5, 7] 4160 axes = cast(axes, dtypes.int32) # [1, 2] 4161 4162 input_rank = array_ops.size(input_shape) # 4 4163 axes = (axes + input_rank) % input_rank 4164 axes_shape = array_ops.shape(axes) # [2] 4165 return gen_data_flow_ops.dynamic_stitch( # [2, 1, 1, 7] 4166 [ 4167 range(input_rank), # [0, 1, 2, 3] 4168 axes 4169 ], # [1, 2] 4170 [ 4171 input_shape, # [2, 3, 5, 7] 4172 array_ops.fill(axes_shape, 1) 4173 ]) # [1, 1] 4174 4175 4176def _unsorted_segment_N(data, segment_ids, num_segments): 4177 """ Helper function for unsorted_segment_mean/_sqrtN. 4178 4179 Computes the number 4180 of segment entries with 0-entries set to 1 to allow division by N. 4181 """ 4182 num_segments = ops.convert_to_tensor(num_segments) 4183 # bincount doesn't support negative indices so we use unsorted_segment_sum 4184 segment_ids_shape = array_ops.shape_internal(segment_ids) 4185 ones_tensor = array_ops.ones(segment_ids_shape, dtype=data.dtype) 4186 n = gen_math_ops.unsorted_segment_sum(ones_tensor, segment_ids, num_segments) 4187 # add dimensions for all non-reduced axes 4188 broadcastable_shape = array_ops.concat( 4189 [num_segments[array_ops.newaxis], 4190 array_ops.ones([array_ops.rank(data) 4191 - array_ops.rank(segment_ids)], 4192 dtype=num_segments.dtype)], 4193 axis=0) 4194 n = array_ops.reshape(n, broadcastable_shape) 4195 return gen_math_ops.maximum(n, 1) 4196 4197 4198@tf_export( 4199 "math.unsorted_segment_mean", 4200 v1=["math.unsorted_segment_mean", "unsorted_segment_mean"]) 4201@dispatch.add_dispatch_support 4202@deprecation.deprecated_endpoints("unsorted_segment_mean") 4203@dispatch.add_dispatch_support 4204def unsorted_segment_mean(data, segment_ids, num_segments, name=None): 4205 r"""Computes the mean along segments of a tensor. 4206 4207 Read [the section on 4208 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4209 for an explanation of segments. 4210 4211 This operator is similar to the `tf.math.unsorted_segment_sum` operator. 4212 Instead of computing the sum over segments, it computes the mean of all 4213 entries belonging to a segment such that: 4214 4215 \\(output_i = 1/N_i \sum_{j...} data[j...]\\) where the sum is over tuples 4216 `j...` such that `segment_ids[j...] == i` with \\N_i\\ being the number of 4217 occurrences of id \\i\\. 4218 4219 If there is no entry for a given segment ID `i`, it outputs 0. 4220 4221 If the given segment ID `i` is negative, the value is dropped and will not 4222 be added to the sum of the segment. 4223 4224 Args: 4225 data: A `Tensor` with floating point or complex dtype. 4226 segment_ids: An integer tensor whose shape is a prefix of `data.shape`. 4227 num_segments: An integer scalar `Tensor`. The number of distinct segment 4228 IDs. 4229 name: A name for the operation (optional). 4230 4231 Returns: 4232 A `Tensor`. Has same shape as data, except for the first `segment_ids.rank` 4233 dimensions, which are replaced with a single dimension which has size 4234 `num_segments`. 4235 """ 4236 with ops.name_scope(name, "UnsortedSegmentMean"): 4237 data = ops.convert_to_tensor(data) 4238 segment_ids = ops.convert_to_tensor(segment_ids) 4239 N = _unsorted_segment_N(data, segment_ids, num_segments) 4240 summed = gen_math_ops.unsorted_segment_sum(data, segment_ids, num_segments) 4241 return summed / N 4242 4243 4244@tf_export( 4245 "math.unsorted_segment_sqrt_n", 4246 v1=["math.unsorted_segment_sqrt_n", "unsorted_segment_sqrt_n"]) 4247@dispatch.add_dispatch_support 4248@deprecation.deprecated_endpoints("unsorted_segment_sqrt_n") 4249@dispatch.add_dispatch_support 4250def unsorted_segment_sqrt_n(data, segment_ids, num_segments, name=None): 4251 r"""Computes the sum along segments of a tensor divided by the sqrt(N). 4252 4253 Read [the section on 4254 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4255 for an explanation of segments. 4256 4257 This operator is similar to the `tf.math.unsorted_segment_sum` operator. 4258 Additionally to computing the sum over segments, it divides the results by 4259 sqrt(N). 4260 4261 \\(output_i = 1/sqrt(N_i) \sum_{j...} data[j...]\\) where the sum is over 4262 tuples `j...` such that `segment_ids[j...] == i` with \\N_i\\ being the 4263 number of occurrences of id \\i\\. 4264 4265 If there is no entry for a given segment ID `i`, it outputs 0. 4266 4267 Note that this op only supports floating point and complex dtypes, 4268 due to tf.sqrt only supporting these types. 4269 4270 If the given segment ID `i` is negative, the value is dropped and will not 4271 be added to the sum of the segment. 4272 4273 Args: 4274 data: A `Tensor` with floating point or complex dtype. 4275 segment_ids: An integer tensor whose shape is a prefix of `data.shape`. 4276 num_segments: An integer scalar `Tensor`. The number of distinct segment 4277 IDs. 4278 name: A name for the operation (optional). 4279 4280 Returns: 4281 A `Tensor`. Has same shape as data, except for the first `segment_ids.rank` 4282 dimensions, which are replaced with a single dimension which has size 4283 `num_segments`. 4284 """ 4285 with ops.name_scope(name, "UnsortedSegmentSqrtN"): 4286 data = ops.convert_to_tensor(data) 4287 segment_ids = ops.convert_to_tensor(segment_ids) 4288 N = _unsorted_segment_N(data, segment_ids, num_segments) 4289 summed = gen_math_ops.unsorted_segment_sum(data, segment_ids, num_segments) 4290 return summed / gen_math_ops.sqrt(N) 4291 4292 4293@tf_export(v1=["sparse.segment_sum", "sparse_segment_sum"]) 4294@deprecation.deprecated_endpoints("sparse_segment_sum") 4295def sparse_segment_sum(data, 4296 indices, 4297 segment_ids, 4298 name=None, 4299 num_segments=None): 4300 r"""Computes the sum along sparse segments of a tensor. 4301 4302 Read [the section on 4303 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4304 for an explanation of segments. 4305 4306 Like `tf.math.segment_sum`, but `segment_ids` can have rank less than `data`'s 4307 first dimension, selecting a subset of dimension 0, specified by `indices`. 4308 `segment_ids` is allowed to have missing ids, in which case the output will 4309 be zeros at those indices. In those cases `num_segments` is used to determine 4310 the size of the output. 4311 4312 For example: 4313 4314 ```python 4315 c = tf.constant([[1,2,3,4], [-1,-2,-3,-4], [5,6,7,8]]) 4316 4317 # Select two rows, one segment. 4318 tf.sparse.segment_sum(c, tf.constant([0, 1]), tf.constant([0, 0])) 4319 # => [[0 0 0 0]] 4320 4321 # Select two rows, two segment. 4322 tf.sparse.segment_sum(c, tf.constant([0, 1]), tf.constant([0, 1])) 4323 # => [[ 1 2 3 4] 4324 # [-1 -2 -3 -4]] 4325 4326 # With missing segment ids. 4327 tf.sparse.segment_sum(c, tf.constant([0, 1]), tf.constant([0, 2]), 4328 num_segments=4) 4329 # => [[ 1 2 3 4] 4330 # [ 0 0 0 0] 4331 # [-1 -2 -3 -4] 4332 # [ 0 0 0 0]] 4333 4334 # Select all rows, two segments. 4335 tf.sparse.segment_sum(c, tf.constant([0, 1, 2]), tf.constant([0, 0, 1])) 4336 # => [[0 0 0 0] 4337 # [5 6 7 8]] 4338 4339 # Which is equivalent to: 4340 tf.math.segment_sum(c, tf.constant([0, 0, 1])) 4341 ``` 4342 4343 Args: 4344 data: A `Tensor` with data that will be assembled in the output. 4345 indices: A 1-D `Tensor` with indices into `data`. Has same rank as 4346 `segment_ids`. 4347 segment_ids: A 1-D `Tensor` with indices into the output `Tensor`. Values 4348 should be sorted and can be repeated. 4349 name: A name for the operation (optional). 4350 num_segments: An optional int32 scalar. Indicates the size of the output 4351 `Tensor`. 4352 4353 Returns: 4354 A `tensor` of the shape as data, except for dimension 0 which 4355 has size `k`, the number of segments specified via `num_segments` or 4356 inferred for the last element in `segments_ids`. 4357 """ 4358 if num_segments is not None: 4359 return gen_math_ops.sparse_segment_sum_with_num_segments( 4360 data=data, 4361 indices=indices, 4362 segment_ids=segment_ids, 4363 num_segments=num_segments, 4364 name=name) 4365 else: 4366 return gen_math_ops.sparse_segment_sum( 4367 data=data, indices=indices, segment_ids=segment_ids, name=name) 4368 4369 4370@tf_export("sparse.segment_sum", v1=[]) 4371def sparse_segment_sum_v2(data, 4372 indices, 4373 segment_ids, 4374 num_segments=None, 4375 name=None): 4376 r"""Computes the sum along sparse segments of a tensor. 4377 4378 Read [the section on 4379 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4380 for an explanation of segments. 4381 4382 Like `tf.math.segment_sum`, but `segment_ids` can have rank less than `data`'s 4383 first dimension, selecting a subset of dimension 0, specified by `indices`. 4384 `segment_ids` is allowed to have missing ids, in which case the output will 4385 be zeros at those indices. In those cases `num_segments` is used to determine 4386 the size of the output. 4387 4388 For example: 4389 4390 ```python 4391 c = tf.constant([[1,2,3,4], [-1,-2,-3,-4], [5,6,7,8]]) 4392 4393 # Select two rows, one segment. 4394 tf.sparse.segment_sum(c, tf.constant([0, 1]), tf.constant([0, 0])) 4395 # => [[0 0 0 0]] 4396 4397 # Select two rows, two segment. 4398 tf.sparse.segment_sum(c, tf.constant([0, 1]), tf.constant([0, 1])) 4399 # => [[ 1 2 3 4] 4400 # [-1 -2 -3 -4]] 4401 4402 # With missing segment ids. 4403 tf.sparse.segment_sum(c, tf.constant([0, 1]), tf.constant([0, 2]), 4404 num_segments=4) 4405 # => [[ 1 2 3 4] 4406 # [ 0 0 0 0] 4407 # [-1 -2 -3 -4] 4408 # [ 0 0 0 0]] 4409 4410 # Select all rows, two segments. 4411 tf.sparse.segment_sum(c, tf.constant([0, 1, 2]), tf.constant([0, 0, 1])) 4412 # => [[0 0 0 0] 4413 # [5 6 7 8]] 4414 4415 # Which is equivalent to: 4416 tf.math.segment_sum(c, tf.constant([0, 0, 1])) 4417 ``` 4418 4419 Args: 4420 data: A `Tensor` with data that will be assembled in the output. 4421 indices: A 1-D `Tensor` with indices into `data`. Has same rank as 4422 `segment_ids`. 4423 segment_ids: A 1-D `Tensor` with indices into the output `Tensor`. Values 4424 should be sorted and can be repeated. 4425 num_segments: An optional int32 scalar. Indicates the size of the output 4426 `Tensor`. 4427 name: A name for the operation (optional). 4428 4429 Returns: 4430 A `tensor` of the shape as data, except for dimension 0 which 4431 has size `k`, the number of segments specified via `num_segments` or 4432 inferred for the last element in `segments_ids`. 4433 """ 4434 return sparse_segment_sum( 4435 data, indices, segment_ids, name=name, num_segments=num_segments) 4436 4437 4438@tf_export(v1=["sparse.segment_mean", "sparse_segment_mean"]) 4439@deprecation.deprecated_endpoints("sparse_segment_mean") 4440def sparse_segment_mean(data, 4441 indices, 4442 segment_ids, 4443 name=None, 4444 num_segments=None): 4445 r"""Computes the mean along sparse segments of a tensor. 4446 4447 Read [the section on 4448 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4449 for an explanation of segments. 4450 4451 Like `tf.math.segment_mean`, but `segment_ids` can have rank less than 4452 `data`'s first dimension, selecting a subset of dimension 0, specified by 4453 `indices`. 4454 `segment_ids` is allowed to have missing ids, in which case the output will 4455 be zeros at those indices. In those cases `num_segments` is used to determine 4456 the size of the output. 4457 4458 Args: 4459 data: A `Tensor` with data that will be assembled in the output. 4460 indices: A 1-D `Tensor` with indices into `data`. Has same rank as 4461 `segment_ids`. 4462 segment_ids: A 1-D `Tensor` with indices into the output `Tensor`. Values 4463 should be sorted and can be repeated. 4464 name: A name for the operation (optional). 4465 num_segments: An optional int32 scalar. Indicates the size of the output 4466 `Tensor`. 4467 4468 Returns: 4469 A `tensor` of the shape as data, except for dimension 0 which 4470 has size `k`, the number of segments specified via `num_segments` or 4471 inferred for the last element in `segments_ids`. 4472 """ 4473 if num_segments is not None: 4474 return gen_math_ops.sparse_segment_mean_with_num_segments( 4475 data=data, 4476 indices=indices, 4477 segment_ids=segment_ids, 4478 num_segments=num_segments, 4479 name=name) 4480 else: 4481 return gen_math_ops.sparse_segment_mean( 4482 data=data, indices=indices, segment_ids=segment_ids, name=name) 4483 4484 4485@tf_export("sparse.segment_mean", v1=[]) 4486def sparse_segment_mean_v2(data, 4487 indices, 4488 segment_ids, 4489 num_segments=None, 4490 name=None): 4491 r"""Computes the mean along sparse segments of a tensor. 4492 4493 Read [the section on 4494 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4495 for an explanation of segments. 4496 4497 Like `tf.math.segment_mean`, but `segment_ids` can have rank less than 4498 `data`'s first dimension, selecting a subset of dimension 0, specified by 4499 `indices`. 4500 `segment_ids` is allowed to have missing ids, in which case the output will 4501 be zeros at those indices. In those cases `num_segments` is used to determine 4502 the size of the output. 4503 4504 Args: 4505 data: A `Tensor` with data that will be assembled in the output. 4506 indices: A 1-D `Tensor` with indices into `data`. Has same rank as 4507 `segment_ids`. 4508 segment_ids: A 1-D `Tensor` with indices into the output `Tensor`. Values 4509 should be sorted and can be repeated. 4510 num_segments: An optional int32 scalar. Indicates the size of the output 4511 `Tensor`. 4512 name: A name for the operation (optional). 4513 4514 Returns: 4515 A `tensor` of the shape as data, except for dimension 0 which 4516 has size `k`, the number of segments specified via `num_segments` or 4517 inferred for the last element in `segments_ids`. 4518 """ 4519 return sparse_segment_mean( 4520 data, indices, segment_ids, name=name, num_segments=num_segments) 4521 4522 4523@tf_export(v1=["sparse.segment_sqrt_n", "sparse_segment_sqrt_n"]) 4524@deprecation.deprecated_endpoints("sparse_segment_sqrt_n") 4525def sparse_segment_sqrt_n(data, 4526 indices, 4527 segment_ids, 4528 name=None, 4529 num_segments=None): 4530 r"""Computes the sum along sparse segments of a tensor divided by the sqrt(N). 4531 4532 `N` is the size of the segment being reduced. 4533 4534 Args: 4535 data: A `Tensor` with data that will be assembled in the output. 4536 indices: A 1-D `Tensor` with indices into `data`. Has same rank as 4537 `segment_ids`. 4538 segment_ids: A 1-D `Tensor` with indices into the output `Tensor`. Values 4539 should be sorted and can be repeated. 4540 name: A name for the operation (optional). 4541 num_segments: An optional int32 scalar. Indicates the size of the output 4542 `Tensor`. 4543 4544 Returns: 4545 A `tensor` of the shape as data, except for dimension 0 which 4546 has size `k`, the number of segments specified via `num_segments` or 4547 inferred for the last element in `segments_ids`. 4548 """ 4549 if num_segments is not None: 4550 return gen_math_ops.sparse_segment_sqrt_n_with_num_segments( 4551 data=data, 4552 indices=indices, 4553 segment_ids=segment_ids, 4554 num_segments=num_segments, 4555 name=name) 4556 else: 4557 return gen_math_ops.sparse_segment_sqrt_n( 4558 data=data, indices=indices, segment_ids=segment_ids, name=name) 4559 4560 4561@tf_export("sparse.segment_sqrt_n", v1=[]) 4562def sparse_segment_sqrt_n_v2(data, 4563 indices, 4564 segment_ids, 4565 num_segments=None, 4566 name=None): 4567 r"""Computes the sum along sparse segments of a tensor divided by the sqrt(N). 4568 4569 Read [the section on 4570 segmentation](https://www.tensorflow.org/versions/r2.0/api_docs/python/tf/math#about_segmentation) 4571 for an explanation of segments. 4572 4573 Like `tf.sparse.segment_mean`, but instead of dividing by the size of the 4574 segment, `N`, divide by `sqrt(N)` instead. 4575 4576 Args: 4577 data: A `Tensor` with data that will be assembled in the output. 4578 indices: A 1-D `Tensor` with indices into `data`. Has same rank as 4579 `segment_ids`. 4580 segment_ids: A 1-D `Tensor` with indices into the output `Tensor`. Values 4581 should be sorted and can be repeated. 4582 num_segments: An optional int32 scalar. Indicates the size of the output 4583 `Tensor`. 4584 name: A name for the operation (optional). 4585 4586 Returns: 4587 A `tensor` of the shape as data, except for dimension 0 which 4588 has size `k`, the number of segments specified via `num_segments` or 4589 inferred for the last element in `segments_ids`. 4590 """ 4591 return sparse_segment_sqrt_n( 4592 data, indices, segment_ids, name=name, num_segments=num_segments) 4593 4594 4595@tf_export("tensordot", "linalg.tensordot") 4596@dispatch.add_dispatch_support 4597def tensordot(a, b, axes, name=None): 4598 r"""Tensor contraction of a and b along specified axes and outer product. 4599 4600 Tensordot (also known as tensor contraction) sums the product of elements 4601 from `a` and `b` over the indices specified by `a_axes` and `b_axes`. 4602 The lists `a_axes` and `b_axes` specify those pairs of axes along which to 4603 contract the tensors. The axis `a_axes[i]` of `a` must have the same dimension 4604 as axis `b_axes[i]` of `b` for all `i` in `range(0, len(a_axes))`. The lists 4605 `a_axes` and `b_axes` must have identical length and consist of unique 4606 integers that specify valid axes for each of the tensors. Additionally 4607 outer product is supported by passing `axes=0`. 4608 4609 This operation corresponds to `numpy.tensordot(a, b, axes)`. 4610 4611 Example 1: When `a` and `b` are matrices (order 2), the case `axes = 1` 4612 is equivalent to matrix multiplication. 4613 4614 Example 2: When `a` and `b` are matrices (order 2), the case 4615 `axes = [[1], [0]]` is equivalent to matrix multiplication. 4616 4617 Example 3: When `a` and `b` are matrices (order 2), the case `axes=0` gives 4618 the outer product, a tensor of order 4. 4619 4620 Example 4: Suppose that \\(a_{ijk}\\) and \\(b_{lmn}\\) represent two 4621 tensors of order 3. Then, `contract(a, b, [[0], [2]])` is the order 4 tensor 4622 \\(c_{jklm}\\) whose entry 4623 corresponding to the indices \\((j,k,l,m)\\) is given by: 4624 4625 \\( c_{jklm} = \sum_i a_{ijk} b_{lmi} \\). 4626 4627 In general, `order(c) = order(a) + order(b) - 2*len(axes[0])`. 4628 4629 Args: 4630 a: `Tensor` of type `float32` or `float64`. 4631 b: `Tensor` with the same type as `a`. 4632 axes: Either a scalar `N`, or a list or an `int32` `Tensor` of shape [2, k]. 4633 If axes is a scalar, sum over the last N axes of a and the first N axes of 4634 b in order. If axes is a list or `Tensor` the first and second row contain 4635 the set of unique integers specifying axes along which the contraction is 4636 computed, for `a` and `b`, respectively. The number of axes for `a` and 4637 `b` must be equal. If `axes=0`, computes the outer product between `a` and 4638 `b`. 4639 name: A name for the operation (optional). 4640 4641 Returns: 4642 A `Tensor` with the same type as `a`. 4643 4644 Raises: 4645 ValueError: If the shapes of `a`, `b`, and `axes` are incompatible. 4646 IndexError: If the values in axes exceed the rank of the corresponding 4647 tensor. 4648 """ 4649 4650 def _tensordot_reshape(a, axes, flipped=False): 4651 """Helper method to perform transpose and reshape for contraction op. 4652 4653 This method is helpful in reducing `math_ops.tensordot` to `math_ops.matmul` 4654 using `array_ops.transpose` and `array_ops.reshape`. The method takes a 4655 tensor and performs the correct transpose and reshape operation for a given 4656 set of indices. It returns the reshaped tensor as well as a list of indices 4657 necessary to reshape the tensor again after matrix multiplication. 4658 4659 Args: 4660 a: `Tensor`. 4661 axes: List or `int32` `Tensor` of unique indices specifying valid axes of 4662 `a`. 4663 flipped: An optional `bool`. Defaults to `False`. If `True`, the method 4664 assumes that `a` is the second argument in the contraction operation. 4665 4666 Returns: 4667 A tuple `(reshaped_a, free_dims, free_dims_static)` where `reshaped_a` is 4668 the tensor `a` reshaped to allow contraction via `matmul`, `free_dims` is 4669 either a list of integers or an `int32` `Tensor`, depending on whether 4670 the shape of a is fully specified, and free_dims_static is either a list 4671 of integers and None values, or None, representing the inferred 4672 static shape of the free dimensions 4673 """ 4674 if a.get_shape().is_fully_defined() and isinstance(axes, (list, tuple)): 4675 shape_a = a.get_shape().as_list() 4676 axes = [i if i >= 0 else i + len(shape_a) for i in axes] 4677 free = [i for i in xrange(len(shape_a)) if i not in axes] 4678 free_dims = [shape_a[i] for i in free] 4679 prod_free = int(np.prod([shape_a[i] for i in free])) 4680 prod_axes = int(np.prod([shape_a[i] for i in axes])) 4681 perm = list(axes) + free if flipped else free + list(axes) 4682 new_shape = [prod_axes, prod_free] if flipped else [prod_free, prod_axes] 4683 if (perm != np.arange(len(shape_a))).any(): 4684 a_trans = array_ops.transpose(a, perm) 4685 else: 4686 a_trans = a 4687 if a_trans.get_shape().as_list() != new_shape: 4688 reshaped_a = array_ops.reshape(a_trans, new_shape) 4689 else: 4690 reshaped_a = a_trans 4691 return reshaped_a, free_dims, free_dims 4692 else: 4693 if a.get_shape().ndims is not None and isinstance(axes, (list, tuple)): 4694 shape_a = a.get_shape().as_list() 4695 axes = [i if i >= 0 else i + len(shape_a) for i in axes] 4696 free = [i for i in xrange(len(shape_a)) if i not in axes] 4697 axes_dims = [shape_a[i] for i in axes] 4698 free_dims = [shape_a[i] for i in free] 4699 free_dims_static = free_dims 4700 axes = ops.convert_to_tensor(axes, dtype=dtypes.int32, name="axes") 4701 free = ops.convert_to_tensor(free, dtype=dtypes.int32, name="free") 4702 shape_a = array_ops.shape(a) 4703 else: 4704 free_dims_static = None 4705 shape_a = array_ops.shape(a) 4706 rank_a = array_ops.rank(a) 4707 axes = ops.convert_to_tensor(axes, dtype=dtypes.int32, name="axes") 4708 axes = array_ops.where(axes >= 0, axes, axes + rank_a) 4709 free, _ = gen_array_ops.list_diff(range(rank_a), axes, dtypes.int32) 4710 free_dims = array_ops.gather(shape_a, free) 4711 axes_dims = array_ops.gather(shape_a, axes) 4712 prod_free_dims = reduce_prod(free_dims) 4713 prod_axes_dims = reduce_prod(axes_dims) 4714 if flipped: 4715 perm = array_ops.concat([axes, free], 0) 4716 new_shape = array_ops.stack([prod_axes_dims, prod_free_dims]) 4717 else: 4718 perm = array_ops.concat([free, axes], 0) 4719 new_shape = array_ops.stack([prod_free_dims, prod_axes_dims]) 4720 reshaped_a = array_ops.reshape(array_ops.transpose(a, perm), new_shape) 4721 return reshaped_a, free_dims, free_dims_static 4722 4723 def _tensordot_axes(a, axes): 4724 """Generates two sets of contraction axes for the two tensor arguments.""" 4725 a_shape = a.get_shape() 4726 if isinstance(axes, compat.integral_types): 4727 if axes < 0: 4728 raise ValueError("'axes' must be at least 0.") 4729 if a_shape.ndims is not None: 4730 if axes > a_shape.ndims: 4731 raise ValueError("'axes' must not be larger than the number of " 4732 "dimensions of tensor %s." % a) 4733 return (list(xrange(a_shape.ndims - axes, 4734 a_shape.ndims)), list(xrange(axes))) 4735 else: 4736 rank = array_ops.rank(a) 4737 return (range(rank - axes, rank, 4738 dtype=dtypes.int32), range(axes, dtype=dtypes.int32)) 4739 elif isinstance(axes, (list, tuple)): 4740 if len(axes) != 2: 4741 raise ValueError("'axes' must be an integer or have length 2.") 4742 a_axes = axes[0] 4743 b_axes = axes[1] 4744 if isinstance(a_axes, compat.integral_types) and \ 4745 isinstance(b_axes, compat.integral_types): 4746 a_axes = [a_axes] 4747 b_axes = [b_axes] 4748 if len(a_axes) != len(b_axes): 4749 raise ValueError( 4750 "Different number of contraction axes 'a' and 'b', %s != %s." % 4751 (len(a_axes), len(b_axes))) 4752 return a_axes, b_axes 4753 else: 4754 axes = ops.convert_to_tensor(axes, name="axes", dtype=dtypes.int32) 4755 return axes[0], axes[1] 4756 4757 with ops.name_scope(name, "Tensordot", [a, b, axes]) as name: 4758 a = ops.convert_to_tensor(a, name="a") 4759 b = ops.convert_to_tensor(b, name="b") 4760 a_axes, b_axes = _tensordot_axes(a, axes) 4761 a_reshape, a_free_dims, a_free_dims_static = _tensordot_reshape(a, a_axes) 4762 b_reshape, b_free_dims, b_free_dims_static = _tensordot_reshape( 4763 b, b_axes, True) 4764 ab_matmul = matmul(a_reshape, b_reshape) 4765 if isinstance(a_free_dims, list) and isinstance(b_free_dims, list): 4766 if (ab_matmul.get_shape().is_fully_defined() and 4767 ab_matmul.get_shape().as_list() == a_free_dims + b_free_dims): 4768 return ab_matmul 4769 else: 4770 return array_ops.reshape( 4771 ab_matmul, a_free_dims + b_free_dims, name=name) 4772 else: 4773 a_free_dims = ops.convert_to_tensor(a_free_dims, dtype=dtypes.int32) 4774 b_free_dims = ops.convert_to_tensor(b_free_dims, dtype=dtypes.int32) 4775 product = array_ops.reshape( 4776 ab_matmul, array_ops.concat([a_free_dims, b_free_dims], 0), name=name) 4777 if a_free_dims_static is not None and b_free_dims_static is not None: 4778 product.set_shape(a_free_dims_static + b_free_dims_static) 4779 return product 4780 4781 4782@tf_export("math.polyval") 4783@dispatch.add_dispatch_support 4784def polyval(coeffs, x, name=None): 4785 r"""Computes the elementwise value of a polynomial. 4786 4787 If `x` is a tensor and `coeffs` is a list n + 1 tensors, 4788 this function returns the value of the n-th order polynomial 4789 4790 `p(x) = coeffs[n-1] + coeffs[n-2] * x + ... + coeffs[0] * x**(n-1)` 4791 4792 evaluated using Horner's method, i.e. 4793 4794 ```python 4795 p(x) = coeffs[n-1] + x * (coeffs[n-2] + ... + x * (coeffs[1] + x * coeffs[0])) 4796 ``` 4797 4798 Usage Example: 4799 4800 >>> coefficients = [1.0, 2.5, -4.2] 4801 >>> x = 5.0 4802 >>> y = tf.math.polyval(coefficients, x) 4803 >>> y 4804 <tf.Tensor: shape=(), dtype=float32, numpy=33.3> 4805 4806 Usage Example: 4807 4808 >>> tf.math.polyval([2, 1, 0], 3) # evaluates 2 * (3**2) + 1 * (3**1) + 0 * (3**0) 4809 <tf.Tensor: shape=(), dtype=int32, numpy=21> 4810 4811 `tf.math.polyval` can also be used in polynomial regression. Taking 4812 advantage of this function can facilitate writing a polynomial equation 4813 as compared to explicitly writing it out, especially for higher degree 4814 polynomials. 4815 4816 >>> x = tf.constant(3) 4817 >>> theta1 = tf.Variable(2) 4818 >>> theta2 = tf.Variable(1) 4819 >>> theta3 = tf.Variable(0) 4820 >>> tf.math.polyval([theta1, theta2, theta3], x) 4821 <tf.Tensor: shape=(), dtype=int32, numpy=21> 4822 4823 Args: 4824 coeffs: A list of `Tensor` representing the coefficients of the polynomial. 4825 x: A `Tensor` representing the variable of the polynomial. 4826 name: A name for the operation (optional). 4827 4828 Returns: 4829 A `tensor` of the shape as the expression p(x) with usual broadcasting 4830 rules for element-wise addition and multiplication applied. 4831 4832 @compatibility(numpy) 4833 Equivalent to numpy.polyval. 4834 @end_compatibility 4835 """ 4836 if not isinstance(coeffs, list): 4837 raise ValueError("Argument coeffs must be list type " 4838 "found {}.".format(type(coeffs))) 4839 4840 with ops.name_scope(name, "polyval", nest.flatten(coeffs) + [x]) as name: 4841 x = ops.convert_to_tensor(x, name="x") 4842 if len(coeffs) < 1: 4843 return array_ops.zeros_like(x, name=name) 4844 coeffs = [ 4845 ops.convert_to_tensor(coeff, name=("coeff_%d" % index)) 4846 for index, coeff in enumerate(coeffs) 4847 ] 4848 p = coeffs[0] 4849 for c in coeffs[1:]: 4850 p = c + p * x 4851 return p 4852 4853 4854@tf_export("math.reciprocal_no_nan") 4855@dispatch.add_dispatch_support 4856def reciprocal_no_nan(x, name=None): 4857 """Performs a safe reciprocal operation, element wise. 4858 4859 If a particular element is zero, the reciprocal for that element is 4860 also set to zero. 4861 4862 For example: 4863 ```python 4864 x = tf.constant([2.0, 0.5, 0, 1], dtype=tf.float32) 4865 tf.math.reciprocal_no_nan(x) # [ 0.5, 2, 0.0, 1.0 ] 4866 ``` 4867 4868 Args: 4869 x: A `Tensor` of type `float16`, `float32`, `float64` `complex64` or 4870 `complex128`. 4871 name: A name for the operation (optional). 4872 4873 Returns: 4874 A `Tensor` of same shape and type as `x`. 4875 4876 Raises: 4877 TypeError: x must be of a valid dtype. 4878 4879 """ 4880 4881 with ops.name_scope(name, "reciprocal_no_nan", [x]) as scope: 4882 x = ops.convert_to_tensor(x, name="x") 4883 one = constant_op.constant(1, dtype=x.dtype.base_dtype, name="one") 4884 return gen_math_ops.div_no_nan(one, x, name=scope) 4885 4886 4887@tf_export("math.xlog1py") 4888@dispatch.add_dispatch_support 4889def xlog1py(x, y, name=None): 4890 r"""Compute x * log1p(y). 4891 4892 Given `x` and `y`, compute `x * log1p(y)`. This function safely returns 4893 zero when `x = 0`, no matter what the value of `y` is. 4894 4895 Example: 4896 4897 >>> tf.math.xlog1py(0., 1.) 4898 <tf.Tensor: shape=(), dtype=float32, numpy=0.> 4899 >>> tf.math.xlog1py(1., 1.) 4900 <tf.Tensor: shape=(), dtype=float32, numpy=0.6931472> 4901 >>> tf.math.xlog1py(2., 2.) 4902 <tf.Tensor: shape=(), dtype=float32, numpy=2.1972246> 4903 >>> tf.math.xlog1py(0., -1.) 4904 <tf.Tensor: shape=(), dtype=float32, numpy=0.> 4905 4906 Args: 4907 x: A `tf.Tensor` of type `bfloat16`, `half`, `float32`, `float64`, 4908 `complex64`, `complex128` 4909 y: A `tf.Tensor` of type `bfloat16`, `half`, `float32`, `float64`, 4910 `complex64`, `complex128` 4911 name: A name for the operation (optional). 4912 4913 Returns: 4914 `x * log1p(y)`. 4915 4916 @compatibility(scipy) 4917 Equivalent to scipy.special.xlog1py 4918 @end_compatibility 4919 """ 4920 with ops.name_scope(name, "xlog1py", [x]): 4921 return gen_math_ops.xlog1py(x, y) 4922 4923 4924@tf_export("math.erfinv") 4925@dispatch.add_dispatch_support 4926def erfinv(x, name=None): 4927 """Compute inverse error function. 4928 4929 Given `x`, compute the inverse error function of `x`. This function 4930 is the inverse of `tf.math.erf`. 4931 4932 Args: 4933 x: `Tensor` with type `float` or `double`. 4934 name: A name for the operation (optional). 4935 Returns: 4936 Inverse error function of `x`. 4937 """ 4938 with ops.name_scope(name, "erfinv", [x]): 4939 return gen_math_ops.erfinv(x) 4940 4941 4942@tf_export("math.ndtri") 4943@dispatch.add_dispatch_support 4944def ndtri(x, name=None): 4945 """Compute quantile of Standard Normal. 4946 4947 Args: 4948 x: `Tensor` with type `float` or `double`. 4949 name: A name for the operation (optional). 4950 Returns: 4951 Inverse error function of `x`. 4952 """ 4953 with ops.name_scope(name, "ndtri", [x]): 4954 return gen_math_ops.ndtri(x) 4955 4956 4957@tf_export("math.erfcinv") 4958@dispatch.add_dispatch_support 4959def erfcinv(x, name=None): 4960 """Computes the inverse of complementary error function. 4961 4962 Given `x`, compute the inverse complementary error function of `x`. 4963 This function is the inverse of `tf.math.erfc`, and is defined on 4964 `[0, 2]`. 4965 4966 >>> tf.math.erfcinv([0., 0.2, 1., 1.5, 2.]) 4967 <tf.Tensor: shape=(5,), dtype=float32, numpy= 4968 array([ inf, 0.9061935, -0. , -0.4769363, -inf], 4969 dtype=float32)> 4970 4971 Args: 4972 x: `Tensor` with type `float` or `double`. 4973 name: A name for the operation (optional). 4974 Returns: 4975 Inverse complementary error function of `x`. 4976 4977 @compatibility(numpy) 4978 Equivalent to scipy.special.erfcinv 4979 @end_compatibility 4980 """ 4981 with ops.name_scope(name, "erfcinv", [x]): 4982 x = ops.convert_to_tensor(x, name="start") 4983 return -ndtri(0.5 * x) * np.sqrt(0.5) 4984 4985 4986@tf_export("math.ceil", v1=["math.ceil", "ceil"]) 4987@dispatch.add_dispatch_support 4988@deprecation.deprecated_endpoints("ceil") 4989@dispatch.add_dispatch_support 4990def ceil(x, name=None): 4991 """Return the ceiling of the input, element-wise. 4992 4993 For example: 4994 4995 >>> tf.math.ceil([-1.7, -1.5, -0.2, 0.2, 1.5, 1.7, 2.0]) 4996 <tf.Tensor: shape=(7,), dtype=float32, 4997 numpy=array([-1., -1., -0., 1., 2., 2., 2.], dtype=float32)> 4998 4999 Args: 5000 x: A `tf.Tensor`. Must be one of the following types: `bfloat16`, `half`, 5001 `float32`, `float64`. `int32` 5002 name: A name for the operation (optional). 5003 5004 Returns: 5005 A `tf.Tensor`. Has the same type as `x`. 5006 5007 @compatibility(numpy) 5008 Equivalent to np.ceil 5009 @end_compatibility 5010 """ 5011 return gen_math_ops.ceil(x, name) 5012 5013 5014@tf_export("math.sqrt", "sqrt") 5015@dispatch.add_dispatch_support 5016def sqrt(x, name=None): # pylint: disable=redefined-builtin 5017 r"""Computes element-wise square root of the input tensor. 5018 5019 Note: This operation does not support integer types. 5020 5021 >>> x = tf.constant([[4.0], [16.0]]) 5022 >>> tf.sqrt(x) 5023 <tf.Tensor: shape=(2, 1), dtype=float32, numpy= 5024 array([[2.], 5025 [4.]], dtype=float32)> 5026 >>> y = tf.constant([[-4.0], [16.0]]) 5027 >>> tf.sqrt(y) 5028 <tf.Tensor: shape=(2, 1), dtype=float32, numpy= 5029 array([[nan], 5030 [ 4.]], dtype=float32)> 5031 >>> z = tf.constant([[-1.0], [16.0]], dtype=tf.complex128) 5032 >>> tf.sqrt(z) 5033 <tf.Tensor: shape=(2, 1), dtype=complex128, numpy= 5034 array([[0.0+1.j], 5035 [4.0+0.j]])> 5036 5037 Note: In order to support complex type, please provide an input tensor 5038 of `complex64` or `complex128`. 5039 5040 Args: 5041 x: A `tf.Tensor` of type `bfloat16`, `half`, `float32`, `float64`, 5042 `complex64`, `complex128` 5043 name: A name for the operation (optional). 5044 5045 Returns: 5046 A `tf.Tensor` of same size, type and sparsity as `x`. 5047 """ 5048 return gen_math_ops.sqrt(x, name) 5049 5050 5051# pylint: disable=g-docstring-has-escape 5052@tf_export("math.exp", "exp") 5053@dispatch.add_dispatch_support 5054def exp(x, name=None): 5055 r"""Computes exponential of x element-wise. \\(y = e^x\\). 5056 5057 This function computes the exponential of the input tensor element-wise. 5058 i.e. `math.exp(x)` or \\(e^x\\), where `x` is the input tensor. 5059 \\(e\\) denotes Euler's number and is approximately equal to 2.718281. 5060 Output is positive for any real input. 5061 5062 >>> x = tf.constant(2.0) 5063 >>> tf.math.exp(x) 5064 <tf.Tensor: shape=(), dtype=float32, numpy=7.389056> 5065 5066 >>> x = tf.constant([2.0, 8.0]) 5067 >>> tf.math.exp(x) 5068 <tf.Tensor: shape=(2,), dtype=float32, 5069 numpy=array([ 7.389056, 2980.958 ], dtype=float32)> 5070 5071 For complex numbers, the exponential value is calculated as 5072 $$ 5073 e^{x+iy} = {e^x} {e^{iy}} = {e^x} ({\cos (y) + i \sin (y)}) 5074 $$ 5075 5076 For `1+1j` the value would be computed as: 5077 $$ 5078 e^1 (\cos (1) + i \sin (1)) = 2.7182817 \times (0.5403023+0.84147096j) 5079 $$ 5080 5081 >>> x = tf.constant(1 + 1j) 5082 >>> tf.math.exp(x) 5083 <tf.Tensor: shape=(), dtype=complex128, 5084 numpy=(1.4686939399158851+2.2873552871788423j)> 5085 5086 Args: 5087 x: A `tf.Tensor`. Must be one of the following types: `bfloat16`, `half`, 5088 `float32`, `float64`, `complex64`, `complex128`. 5089 name: A name for the operation (optional). 5090 5091 Returns: 5092 A `tf.Tensor`. Has the same type as `x`. 5093 5094 @compatibility(numpy) 5095 Equivalent to np.exp 5096 @end_compatibility 5097 """ 5098 return gen_math_ops.exp(x, name) 5099 5100 5101# pylint: enable=g-docstring-has-escape 5102 5103 5104@tf_export("math.sobol_sample") 5105@dispatch.add_dispatch_support 5106def sobol_sample(dim, num_results, skip=0, dtype=dtypes.float32, name=None): 5107 """Generates points from the Sobol sequence. 5108 5109 Creates a Sobol sequence with `num_results` samples. Each sample has dimension 5110 `dim`. Skips the first `skip` samples. 5111 5112 Args: 5113 dim: Positive scalar `Tensor` representing each sample's dimension. 5114 num_results: Positive scalar `Tensor` of dtype int32. The number of Sobol 5115 points to return in the output. 5116 skip: (Optional) Positive scalar `Tensor` of dtype int32. The number of 5117 initial points of the Sobol sequence to skip. Default value is 0. 5118 dtype: (Optional) The `tf.Dtype` of the sample. One of: `tf.float32` or 5119 `tf.float64`. Defaults to `tf.float32`. 5120 name: (Optional) Python `str` name prefixed to ops created by this function. 5121 5122 Returns: 5123 `Tensor` of samples from Sobol sequence with `shape` [num_results, dim]. 5124 """ 5125 with ops.name_scope(name, "sobol", [dim, num_results, skip]): 5126 return gen_math_ops.sobol_sample(dim, num_results, skip, dtype=dtype) 5127 5128 5129@tf_export("math.rsqrt", v1=["math.rsqrt", "rsqrt"]) 5130@dispatch.add_dispatch_support 5131@deprecation.deprecated_endpoints("rsqrt") 5132@dispatch.add_dispatch_support 5133def rsqrt(x, name=None): 5134 """Computes reciprocal of square root of x element-wise. 5135 5136 For example: 5137 5138 >>> x = tf.constant([2., 0., -2.]) 5139 >>> tf.math.rsqrt(x) 5140 <tf.Tensor: shape=(3,), dtype=float32, 5141 numpy=array([0.707, inf, nan], dtype=float32)> 5142 5143 Args: 5144 x: A `tf.Tensor`. Must be one of the following types: `bfloat16`, `half`, 5145 `float32`, `float64`. 5146 name: A name for the operation (optional). 5147 5148 Returns: 5149 A `tf.Tensor`. Has the same type as `x`. 5150 """ 5151 return gen_math_ops.rsqrt(x, name) 5152 5153 5154@tf_export("math.acos", "acos") 5155@dispatch.add_dispatch_support 5156def acos(x, name=None): 5157 """Computes acos of x element-wise. 5158 5159 Provided an input tensor, the `tf.math.acos` operation 5160 returns the inverse cosine of each element of the tensor. 5161 If `y = tf.math.cos(x)` then, `x = tf.math.acos(y)`. 5162 5163 Input range is `[-1, 1]` and the output has a range of `[0, pi]`. 5164 5165 For example: 5166 5167 >>> x = tf.constant([1.0, -0.5, 3.4, 0.2, 0.0, -2], dtype = tf.float32) 5168 >>> tf.math.acos(x) 5169 <tf.Tensor: shape=(6,), dtype=float32, 5170 numpy= array([0. , 2.0943952, nan, 1.3694383, 1.5707964, nan], 5171 dtype=float32)> 5172 5173 Args: 5174 x: A `Tensor`. Must be one of the following types: `bfloat16`, `half`, 5175 `float32`, `float64`, `uint8`, `int8`, `int16`, `int32`, `int64`, 5176 `complex64`, `complex128`, `string`. 5177 name: A name for the operation (optional). 5178 5179 Returns: 5180 A `Tensor`. Has the same type as x. 5181 """ 5182 return gen_math_ops.acos(x, name) 5183 5184 5185@tf_export("math.floor", "floor") 5186@dispatch.add_dispatch_support 5187def floor(x, name=None): 5188 """Returns element-wise largest integer not greater than x. 5189 5190 Both input range is `(-inf, inf)` and the 5191 output range consists of all integer values. 5192 5193 For example: 5194 5195 >>> x = tf.constant([1.3324, -1.5, 5.555, -2.532, 0.99, float("inf")]) 5196 >>> tf.floor(x).numpy() 5197 array([ 1., -2., 5., -3., 0., inf], dtype=float32) 5198 5199 Args: 5200 x: A `Tensor`. Must be one of the following types: `bfloat16`, `half`, 5201 `float32`, `float64`. 5202 name: A name for the operation (optional). 5203 5204 Returns: 5205 A `Tensor`. Has the same type as x. 5206 """ 5207 return gen_math_ops.floor(x, name) 5208