| # Copyright 2015 The TensorFlow Authors. All Rights Reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| # ============================================================================== |
| |
| """Variables. |
| |
| See the [Variables](https://www.tensorflow.org/guide/variables) guide. |
| """ |
| |
| from tensorflow.python.framework import ops |
| from tensorflow.python.framework import tensor_shape |
| from tensorflow.python.ops import array_ops |
| from tensorflow.python.ops import gen_math_ops |
| from tensorflow.python.ops import gen_resource_variable_ops |
| from tensorflow.python.ops import gen_state_ops |
| # go/tf-wildcard-import |
| # pylint: disable=wildcard-import |
| from tensorflow.python.ops.gen_state_ops import * |
| # pylint: enable=wildcard-import |
| from tensorflow.python.util import deprecation |
| from tensorflow.python.util.deprecation import deprecated |
| from tensorflow.python.util.tf_export import tf_export |
| |
| |
| # pylint: disable=protected-access,g-doc-return-or-yield,g-doc-args |
| def variable_op(shape, dtype, name="Variable", set_shape=True, container="", |
| shared_name=""): |
| """Deprecated. Used variable_op_v2 instead.""" |
| if not set_shape: |
| shape = tensor_shape.unknown_shape() |
| ret = gen_state_ops.variable(shape=shape, dtype=dtype, name=name, |
| container=container, shared_name=shared_name) |
| # TODO(mrry): Move this to where it is used, so we can get rid of this op |
| # wrapper? |
| if set_shape: |
| ret.set_shape(shape) |
| return ret |
| |
| |
| def variable_op_v2(shape, dtype, name="Variable", container="", shared_name=""): |
| """Create a variable Operation. |
| |
| See also variables.Variable. |
| |
| Args: |
| shape: The shape of the tensor managed by this variable |
| dtype: The underlying type of the tensor values. |
| name: optional name to use for the variable op. |
| container: An optional string. Defaults to "". |
| If non-empty, this variable is placed in the given container. |
| Otherwise, a default container is used. |
| shared_name: An optional string. Defaults to "". |
| If non-empty, this variable is named in the given bucket |
| with this shared_name. Otherwise, the node name is used instead. |
| |
| Returns: |
| A variable tensor. |
| """ |
| return gen_state_ops.variable_v2( |
| shape=shape, |
| dtype=dtype, |
| name=name, |
| container=container, |
| shared_name=shared_name) |
| |
| |
| def init_variable(v, init, name="init"): |
| """Initializes variable with "init". |
| |
| This op does the following: |
| if init is a Tensor, v = init |
| if callable(init): v = init(VariableShape(v), v.dtype) |
| |
| Args: |
| v: Variable to initialize |
| init: Tensor to assign to v, |
| Or an object convertible to Tensor e.g. nparray, |
| Or an Initializer that generates a tensor given the shape and type of v. |
| An "Initializer" is a callable that returns a tensor that "v" should be |
| set to. It will be called as init(shape, dtype). |
| name: Optional name for the op. |
| |
| Returns: |
| The operation that initializes v. |
| """ |
| with ops.name_scope(None, v.op.name + "/", [v, init]): |
| with ops.name_scope(name) as scope: |
| with ops.colocate_with(v): |
| if callable(init): |
| assert v.get_shape().is_fully_defined(), "Variable shape unknown." |
| # TODO(mrry): Convert to v.shape when the property and |
| # accessor are reconciled (and all initializers support |
| # tf.TensorShape objects). |
| value = init(v.get_shape().as_list(), v.dtype.base_dtype) |
| value = ops.convert_to_tensor(value, name="value") |
| return gen_state_ops.assign(v, value, name=scope) |
| else: |
| init = ops.convert_to_tensor(init, name="init") |
| return gen_state_ops.assign(v, init, name=scope) |
| |
| |
| def is_variable_initialized(ref, name=None): |
| """Checks whether a tensor has been initialized. |
| |
| Outputs boolean scalar indicating whether the tensor has been initialized. |
| |
| Args: |
| ref: A mutable `Tensor`. |
| Should be from a `Variable` node. May be uninitialized. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A `Tensor` of type `bool`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.is_variable_initialized(ref=ref, name=name) |
| # Handle resource variables. |
| return ref.is_initialized(name=name) |
| |
| |
| @tf_export(v1=["assign_sub"]) |
| def assign_sub(ref, value, use_locking=None, name=None): |
| """Update `ref` by subtracting `value` from it. |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| Unlike `tf.math.subtract`, this op does not broadcast. `ref` and `value` |
| must have the same shape. |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int64`, `int32`, `uint8`, `uint16`, `int16`, `int8`, |
| `complex64`, `complex128`, `qint8`, `quint8`, `qint32`, `half`. Should be |
| from a `Variable` node. |
| value: A `Tensor`. Must have the same shape and dtype as `ref`. The value to |
| be subtracted to the variable. |
| use_locking: An optional `bool`. Defaults to `False`. If True, the |
| subtraction will be protected by a lock; otherwise the behavior is |
| undefined, but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| Same as `ref`. Returned as a convenience for operations that want |
| to use the new value after the variable has been updated. |
| |
| @compatibility(TF2) |
| `tf.compat.v1.assign_sub` is mostly compatible with eager |
| execution and `tf.function`. |
| |
| To switch to the native TF2 style, one could use method 'assign_sub' of |
| `tf.Variable`: |
| |
| #### How to Map Arguments |
| |
| | TF1 Arg Name | TF2 Arg Name | Note | |
| | :-------------------- | :-------------- | :------------------------- | |
| | `ref` | `self` | In `assign_sub()` method | |
| | `value` | `value` | In `assign_sub()` method | |
| | `use_locking` | `use_locking` | In `assign_sub()` method | |
| | `name` | `name` | In `assign_sub()` method | |
| | - | `read_value` | Set to True to replicate | |
| : : : behavior (True is default) : |
| |
| |
| #### Before & After Usage Example |
| |
| Before: |
| |
| >>> with tf.Graph().as_default(): |
| ... with tf.compat.v1.Session() as sess: |
| ... a = tf.compat.v1.Variable(1, dtype=tf.int64) |
| ... sess.run(a.initializer) |
| ... update_op = tf.compat.v1.assign_sub(a, 1) |
| ... res_a = sess.run(update_op) |
| ... res_a |
| 0 |
| |
| After: |
| |
| >>> b = tf.Variable(1, dtype=tf.int64) |
| >>> res_b = b.assign_sub(1) |
| >>> res_b.numpy() |
| 0 |
| |
| @end_compatibility |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.assign_sub( |
| ref, value, use_locking=use_locking, name=name) |
| return ref.assign_sub(value) |
| |
| |
| @tf_export(v1=["assign_add"]) |
| def assign_add(ref, value, use_locking=None, name=None): |
| """Update `ref` by adding `value` to it. |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| Unlike `tf.math.add`, this op does not broadcast. `ref` and `value` must have |
| the same shape. |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int64`, `int32`, `uint8`, `uint16`, `int16`, `int8`, |
| `complex64`, `complex128`, `qint8`, `quint8`, `qint32`, `half`. Should be |
| from a `Variable` node. |
| value: A `Tensor`. Must have the same shape and dtype as `ref`. The value to |
| be added to the variable. |
| use_locking: An optional `bool`. Defaults to `False`. If True, the addition |
| will be protected by a lock; otherwise the behavior is undefined, but may |
| exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| Same as `ref`. Returned as a convenience for operations that want |
| to use the new value after the variable has been updated. |
| |
| @compatibility(TF2) |
| `tf.compat.v1.assign_add` is mostly compatible with eager |
| execution and `tf.function`. |
| |
| To switch to the native TF2 style, one could use method 'assign_add' of |
| `tf.Variable`: |
| |
| #### How to Map Arguments |
| |
| | TF1 Arg Name | TF2 Arg Name | Note | |
| | :-------------------- | :-------------- | :------------------------- | |
| | `ref` | `self` | In `assign_add()` method | |
| | `value` | `value` | In `assign_add()` method | |
| | `use_locking` | `use_locking` | In `assign_add()` method | |
| | `name` | `name` | In `assign_add()` method | |
| | - | `read_value` | Set to True to replicate | |
| : : : behavior (True is default) : |
| |
| |
| #### Before & After Usage Example |
| |
| Before: |
| |
| >>> with tf.Graph().as_default(): |
| ... with tf.compat.v1.Session() as sess: |
| ... a = tf.compat.v1.Variable(0, dtype=tf.int64) |
| ... sess.run(a.initializer) |
| ... update_op = tf.compat.v1.assign_add(a, 1) |
| ... res_a = sess.run(update_op) |
| ... res_a |
| 1 |
| |
| After: |
| |
| >>> b = tf.Variable(0, dtype=tf.int64) |
| >>> res_b = b.assign_add(1) |
| >>> res_b.numpy() |
| 1 |
| |
| @end_compatibility |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.assign_add( |
| ref, value, use_locking=use_locking, name=name) |
| return ref.assign_add(value) |
| |
| |
| @tf_export(v1=["assign"]) |
| def assign(ref, value, validate_shape=None, use_locking=None, name=None): |
| """Update `ref` by assigning `value` to it. |
| |
| This operation outputs a Tensor that holds the new value of `ref` after |
| the value has been assigned. This makes it easier to chain operations that |
| need to use the reset value. |
| |
| Args: |
| ref: A mutable `Tensor`. Should be from a `Variable` node. May be |
| uninitialized. |
| value: A `Tensor`. Must have the same shape and dtype as `ref`. The value to |
| be assigned to the variable. |
| validate_shape: An optional `bool`. Defaults to `True`. If true, the |
| operation will validate that the shape of 'value' matches the shape of the |
| Tensor being assigned to. If false, 'ref' will take on the shape of |
| 'value'. |
| use_locking: An optional `bool`. Defaults to `True`. If True, the assignment |
| will be protected by a lock; otherwise the behavior is undefined, but may |
| exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A `Tensor` that will hold the new value of `ref` after |
| the assignment has completed. |
| |
| @compatibility(TF2) |
| `tf.compat.v1.assign` is mostly compatible with eager |
| execution and `tf.function`. However, argument 'validate_shape' will be |
| ignored. To avoid shape validation, set 'shape' to tf.TensorShape(None) when |
| constructing the variable: |
| |
| >>> import tensorflow as tf |
| >>> a = tf.Variable([1], shape=tf.TensorShape(None)) |
| >>> tf.compat.v1.assign(a, [2,3]) |
| |
| To switch to the native TF2 style, one could use method 'assign' of |
| `tf.Variable`: |
| |
| #### How to Map Arguments |
| |
| | TF1 Arg Name | TF2 Arg Name | Note | |
| | :-------------------- | :-------------- | :------------------------- | |
| | `ref` | `self` | In `assign()` method | |
| | `value` | `value` | In `assign()` method | |
| | `validate_shape` | Not supported | Specify `shape` in the | |
| : : : constructor to replicate : |
| : : : behavior : |
| | `use_locking` | `use_locking` | In `assign()` method | |
| | `name` | `name` | In `assign()` method | |
| | - | `read_value` | Set to True to replicate | |
| : : : behavior (True is default) : |
| @end_compatibility |
| |
| |
| #### Before & After Usage Example |
| |
| Before: |
| |
| >>> with tf.Graph().as_default(): |
| ... with tf.compat.v1.Session() as sess: |
| ... a = tf.compat.v1.Variable(0, dtype=tf.int64) |
| ... sess.run(a.initializer) |
| ... update_op = tf.compat.v1.assign(a, 2) |
| ... res_a = sess.run(update_op) |
| ... res_a |
| 2 |
| |
| After: |
| |
| >>> b = tf.Variable(0, dtype=tf.int64) |
| >>> res_b = b.assign(2) |
| >>> res_b.numpy() |
| 2 |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.assign( |
| ref, value, use_locking=use_locking, name=name, |
| validate_shape=validate_shape) |
| return ref.assign(value, name=name) |
| |
| |
| @tf_export(v1=["count_up_to"]) |
| @deprecated(None, "Prefer Dataset.range instead.") |
| def count_up_to(ref, limit, name=None): |
| r"""Increments 'ref' until it reaches 'limit'. |
| |
| Args: |
| ref: A Variable. Must be one of the following types: `int32`, `int64`. |
| Should be from a scalar `Variable` node. |
| limit: An `int`. |
| If incrementing ref would bring it above limit, instead generates an |
| 'OutOfRange' error. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A `Tensor`. Has the same type as `ref`. |
| A copy of the input before increment. If nothing else modifies the |
| input, the values produced will all be distinct. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.count_up_to(ref, limit=limit, name=name) |
| return gen_state_ops.resource_count_up_to( |
| ref.handle, limit, T=ref.dtype, name=name) |
| |
| |
| @tf_export(v1=["scatter_update"]) |
| def scatter_update(ref, indices, updates, use_locking=True, name=None): |
| # pylint: disable=line-too-long |
| r"""Applies sparse updates to a variable reference. |
| |
| This operation computes |
| |
| ```python |
| # Scalar indices |
| ref[indices, ...] = updates[...] |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] = updates[i, ...] |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] = updates[i, ..., j, ...] |
| ``` |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| |
| If values in `ref` is to be updated more than once, because there are |
| duplicate entries in `indices`, the order at which the updates happen |
| for each value is undefined. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]`. |
| |
| <div style="width:70%; margin:auto; margin-bottom:10px; margin-top:20px;"> |
| <img style="width:100%" src="https://www.tensorflow.org/images/ScatterUpdate.png" alt> |
| </div> |
| |
| Args: |
| ref: A `Variable`. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. |
| A tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. |
| A tensor of updated values to store in `ref`. |
| use_locking: An optional `bool`. Defaults to `True`. |
| If True, the assignment will be protected by a lock; |
| otherwise the behavior is undefined, but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| Same as `ref`. Returned as a convenience for operations that want |
| to use the updated values after the update is done. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_update(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_update( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_nd_update"]) |
| def scatter_nd_update(ref, indices, updates, use_locking=True, name=None): |
| r"""Applies sparse `updates` to individual values or slices in a Variable. |
| |
| `ref` is a `Tensor` with rank `P` and `indices` is a `Tensor` of rank `Q`. |
| |
| `indices` must be integer tensor, containing indices into `ref`. |
| It must be shape `[d_0, ..., d_{Q-2}, K]` where `0 < K <= P`. |
| |
| The innermost dimension of `indices` (with length `K`) corresponds to |
| indices into elements (if `K = P`) or slices (if `K < P`) along the `K`th |
| dimension of `ref`. |
| |
| `updates` is `Tensor` of rank `Q-1+P-K` with shape: |
| |
| ``` |
| [d_0, ..., d_{Q-2}, ref.shape[K], ..., ref.shape[P-1]]. |
| ``` |
| |
| For example, say we want to update 4 scattered elements to a rank-1 tensor to |
| 8 elements. In Python, that update would look like this: |
| |
| ```python |
| ref = tf.Variable([1, 2, 3, 4, 5, 6, 7, 8]) |
| indices = tf.constant([[4], [3], [1] ,[7]]) |
| updates = tf.constant([9, 10, 11, 12]) |
| update = tf.compat.v1.scatter_nd_update(ref, indices, updates) |
| with tf.compat.v1.Session() as sess: |
| print sess.run(update) |
| ``` |
| |
| The resulting update to ref would look like this: |
| |
| [1, 11, 3, 10, 9, 6, 7, 12] |
| |
| See `tf.scatter_nd` for more details about how to make updates to |
| slices. |
| |
| Args: |
| ref: A Variable. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. |
| A tensor of indices into ref. |
| updates: A `Tensor`. Must have the same type as `ref`. |
| A Tensor. Must have the same type as ref. A tensor of updated |
| values to add to ref. |
| use_locking: An optional `bool`. Defaults to `True`. |
| An optional bool. Defaults to True. If True, the assignment will |
| be protected by a lock; otherwise the behavior is undefined, |
| but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| The value of the variable after the update. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_nd_update( |
| ref, indices, updates, use_locking, name) |
| return ref._lazy_read(gen_state_ops.resource_scatter_nd_update( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_add"]) |
| def scatter_add(ref, indices, updates, use_locking=False, name=None): |
| # pylint: disable=line-too-long |
| r"""Adds sparse updates to the variable referenced by `resource`. |
| |
| This operation computes |
| |
| ```python |
| # Scalar indices |
| ref[indices, ...] += updates[...] |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] += updates[i, ...] |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] += updates[i, ..., j, ...] |
| ``` |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the updated value. |
| Duplicate entries are handled correctly: if multiple `indices` reference |
| the same location, their contributions add. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]`. |
| |
| <div style="width:70%; margin:auto; margin-bottom:10px; margin-top:20px;"> |
| <img style="width:100%" src='https://www.tensorflow.org/images/ScatterAdd.png' alt> |
| </div> |
| |
| Args: |
| ref: A `Variable`. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. |
| A tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. |
| A tensor of updated values to store in `ref`. |
| use_locking: An optional `bool`. Defaults to `False`. |
| If True, the assignment will be protected by a lock; |
| otherwise the behavior is undefined, but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| Same as `ref`. Returned as a convenience for operations that want |
| to use the updated values after the update is done. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_add(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_add( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_nd_add"]) |
| def scatter_nd_add(ref, indices, updates, use_locking=False, name=None): |
| r"""Applies sparse addition to individual values or slices in a Variable. |
| |
| `ref` is a `Tensor` with rank `P` and `indices` is a `Tensor` of rank `Q`. |
| |
| `indices` must be integer tensor, containing indices into `ref`. |
| It must be shape `[d_0, ..., d_{Q-2}, K]` where `0 < K <= P`. |
| |
| The innermost dimension of `indices` (with length `K`) corresponds to |
| indices into elements (if `K = P`) or slices (if `K < P`) along the `K`th |
| dimension of `ref`. |
| |
| `updates` is `Tensor` of rank `Q-1+P-K` with shape: |
| |
| ``` |
| [d_0, ..., d_{Q-2}, ref.shape[K], ..., ref.shape[P-1]] |
| ``` |
| |
| For example, say we want to add 4 scattered elements to a rank-1 tensor to |
| 8 elements. In Python, that addition would look like this: |
| |
| ```python |
| ref = tf.Variable([1, 2, 3, 4, 5, 6, 7, 8]) |
| indices = tf.constant([[4], [3], [1], [7]]) |
| updates = tf.constant([9, 10, 11, 12]) |
| add = tf.compat.v1.scatter_nd_add(ref, indices, updates) |
| with tf.compat.v1.Session() as sess: |
| print sess.run(add) |
| ``` |
| |
| The resulting update to ref would look like this: |
| |
| [1, 13, 3, 14, 14, 6, 7, 20] |
| |
| See `tf.scatter_nd` for more details about how to make updates to |
| slices. |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, |
| `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, |
| `uint32`, `uint64`. A mutable Tensor. Should be from a Variable node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. |
| A tensor of indices into ref. |
| updates: A `Tensor`. Must have the same type as `ref`. |
| A tensor of updated values to add to ref. |
| use_locking: An optional `bool`. Defaults to `False`. |
| If True, the assignment will be protected by a lock; |
| otherwise the behavior is undefined, but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_nd_add( |
| ref, indices, updates, use_locking, name) |
| return ref._lazy_read(gen_state_ops.resource_scatter_nd_add( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_sub"]) |
| def scatter_sub(ref, indices, updates, use_locking=False, name=None): |
| r"""Subtracts sparse updates to a variable reference. |
| |
| ```python |
| # Scalar indices |
| ref[indices, ...] -= updates[...] |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] -= updates[i, ...] |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] -= updates[i, ..., j, ...] |
| ``` |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| |
| Duplicate entries are handled correctly: if multiple `indices` reference |
| the same location, their (negated) contributions add. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]` or |
| `updates.shape = []`. |
| |
| <div style="width:70%; margin:auto; margin-bottom:10px; margin-top:20px;"> |
| <img style="width:100%" |
| src="https://www.tensorflow.org/images/ScatterSub.png" alt> |
| </div> |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, |
| `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, |
| `uint32`, `uint64`. Should be from a `Variable` node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. |
| A tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. |
| A tensor of updated values to subtract from `ref`. |
| use_locking: An optional `bool`. Defaults to `False`. |
| If True, the subtraction will be protected by a lock; |
| otherwise the behavior is undefined, but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_sub(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_sub( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_nd_sub"]) |
| def scatter_nd_sub(ref, indices, updates, use_locking=False, name=None): |
| r"""Applies sparse subtraction to individual values or slices in a Variable. |
| |
| `ref` is a `Tensor` with rank `P` and `indices` is a `Tensor` of rank `Q`. |
| |
| `indices` must be integer tensor, containing indices into `ref`. |
| It must be shape `[d_0, ..., d_{Q-2}, K]` where `0 < K <= P`. |
| |
| The innermost dimension of `indices` (with length `K`) corresponds to |
| indices into elements (if `K = P`) or slices (if `K < P`) along the `K`th |
| dimension of `ref`. |
| |
| `updates` is `Tensor` of rank `Q-1+P-K` with shape: |
| |
| ``` |
| [d_0, ..., d_{Q-2}, ref.shape[K], ..., ref.shape[P-1]] |
| ``` |
| |
| For example, say we want to subtract 4 scattered elements from a rank-1 tensor |
| with 8 elements. In Python, that update would look like this: |
| |
| ```python |
| ref = tf.Variable([1, 2, 3, 4, 5, 6, 7, 8]) |
| indices = tf.constant([[4], [3], [1] ,[7]]) |
| updates = tf.constant([9, 10, 11, 12]) |
| op = tf.compat.v1.scatter_nd_sub(ref, indices, updates) |
| with tf.compat.v1.Session() as sess: |
| print sess.run(op) |
| ``` |
| |
| The resulting update to ref would look like this: |
| |
| [1, -9, 3, -6, -6, 6, 7, -4] |
| |
| See `tf.scatter_nd` for more details about how to make updates to |
| slices. |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, |
| `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, |
| `uint32`, `uint64`. A mutable Tensor. Should be from a Variable node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. |
| A tensor of indices into ref. |
| updates: A `Tensor`. Must have the same type as `ref`. |
| A tensor of updated values to add to ref. |
| use_locking: An optional `bool`. Defaults to `False`. |
| An optional bool. Defaults to True. If True, the assignment will |
| be protected by a lock; otherwise the behavior is undefined, |
| but may exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_nd_sub( |
| ref, indices, updates, use_locking, name) |
| return ref._lazy_read(gen_state_ops.resource_scatter_nd_sub( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_mul"]) |
| def scatter_mul(ref, indices, updates, use_locking=False, name=None): |
| # pylint: disable=line-too-long |
| r"""Multiplies sparse updates into a variable reference. |
| |
| This operation computes |
| |
| ```python |
| # Scalar indices |
| ref[indices, ...] *= updates[...] |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] *= updates[i, ...] |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] *= updates[i, ..., j, ...] |
| ``` |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| |
| Duplicate entries are handled correctly: if multiple `indices` reference |
| the same location, their contributions multiply. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]` or `updates.shape = |
| []`. |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, |
| `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, |
| `uint32`, `uint64`. Should be from a `Variable` node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. A |
| tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. A tensor of updated |
| values to multiply to `ref`. |
| use_locking: An optional `bool`. Defaults to `False`. If True, the operation |
| will be protected by a lock; otherwise the behavior is undefined, but may |
| exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_mul(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_mul( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_div"]) |
| def scatter_div(ref, indices, updates, use_locking=False, name=None): |
| # pylint: disable=line-too-long |
| r"""Divides a variable reference by sparse updates. |
| |
| This operation computes |
| |
| ```python |
| # Scalar indices |
| ref[indices, ...] /= updates[...] |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] /= updates[i, ...] |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] /= updates[i, ..., j, ...] |
| ``` |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| |
| Duplicate entries are handled correctly: if multiple `indices` reference |
| the same location, their contributions divide. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]` or `updates.shape = |
| []`. |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `float32`, |
| `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, |
| `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, |
| `uint32`, `uint64`. Should be from a `Variable` node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. A |
| tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. A tensor of values |
| that `ref` is divided by. |
| use_locking: An optional `bool`. Defaults to `False`. If True, the operation |
| will be protected by a lock; otherwise the behavior is undefined, but may |
| exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_div(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_div( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_max"]) |
| def scatter_max(ref, indices, updates, use_locking=False, name=None): |
| # pylint: disable=line-too-long |
| r"""Reduces sparse updates into a variable reference using the `max` operation. |
| |
| This operation computes |
| |
| # Scalar indices |
| ref[indices, ...] = max(ref[indices, ...], updates[...]) |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] = max(ref[indices[i], ...], updates[i, ...]) |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] = max(ref[indices[i, ..., j], ...], |
| updates[i, ..., j, ...]) |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| |
| Duplicate entries are handled correctly: if multiple `indices` reference |
| the same location, their contributions combine. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]` or `updates.shape = |
| []`. |
| |
| <div style="width:70%; margin:auto; margin-bottom:10px; margin-top:20px;"> |
| <img style="width:100%" src="https://www.tensorflow.org/images/ScatterAdd.png" |
| alt> |
| </div> |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `half`, |
| `bfloat16`, `float32`, `float64`, `int32`, `int64`. Should be from a |
| `Variable` node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. A |
| tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. A tensor of updated |
| values to reduce into `ref`. |
| use_locking: An optional `bool`. Defaults to `False`. If True, the update |
| will be protected by a lock; otherwise the behavior is undefined, but may |
| exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_max(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_max( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["scatter_min"]) |
| def scatter_min(ref, indices, updates, use_locking=False, name=None): |
| # pylint: disable=line-too-long |
| r"""Reduces sparse updates into a variable reference using the `min` operation. |
| |
| This operation computes |
| |
| # Scalar indices |
| ref[indices, ...] = min(ref[indices, ...], updates[...]) |
| |
| # Vector indices (for each i) |
| ref[indices[i], ...] = min(ref[indices[i], ...], updates[i, ...]) |
| |
| # High rank indices (for each i, ..., j) |
| ref[indices[i, ..., j], ...] = min(ref[indices[i, ..., j], ...], |
| updates[i, ..., j, ...]) |
| |
| This operation outputs `ref` after the update is done. |
| This makes it easier to chain operations that need to use the reset value. |
| |
| Duplicate entries are handled correctly: if multiple `indices` reference |
| the same location, their contributions combine. |
| |
| Requires `updates.shape = indices.shape + ref.shape[1:]` or `updates.shape = |
| []`. |
| |
| <div style="width:70%; margin:auto; margin-bottom:10px; margin-top:20px;"> |
| <img style="width:100%" src="https://www.tensorflow.org/images/ScatterAdd.png" |
| alt> |
| </div> |
| |
| Args: |
| ref: A mutable `Tensor`. Must be one of the following types: `half`, |
| `bfloat16`, `float32`, `float64`, `int32`, `int64`. Should be from a |
| `Variable` node. |
| indices: A `Tensor`. Must be one of the following types: `int32`, `int64`. A |
| tensor of indices into the first dimension of `ref`. |
| updates: A `Tensor`. Must have the same type as `ref`. A tensor of updated |
| values to reduce into `ref`. |
| use_locking: An optional `bool`. Defaults to `False`. If True, the update |
| will be protected by a lock; otherwise the behavior is undefined, but may |
| exhibit less contention. |
| name: A name for the operation (optional). |
| |
| Returns: |
| A mutable `Tensor`. Has the same type as `ref`. |
| """ |
| if ref.dtype._is_ref_dtype: |
| return gen_state_ops.scatter_min(ref, indices, updates, |
| use_locking=use_locking, name=name) |
| return ref._lazy_read(gen_resource_variable_ops.resource_scatter_min( # pylint: disable=protected-access |
| ref.handle, indices, ops.convert_to_tensor(updates, ref.dtype), |
| name=name)) |
| |
| |
| @tf_export(v1=["batch_scatter_update"]) |
| @deprecation.deprecated( |
| "2018-11-29", "Use the batch_scatter_update method of Variable instead.") |
| def batch_scatter_update(ref, indices, updates, use_locking=True, name=None): |
| """Generalization of `tf.compat.v1.scatter_update` to axis different than 0. |
| |
| Analogous to `batch_gather`. This assumes that `ref`, `indices` and `updates` |
| have a series of leading dimensions that are the same for all of them, and the |
| updates are performed on the last dimension of indices. In other words, the |
| dimensions should be the following: |
| |
| `num_prefix_dims = indices.ndims - 1` |
| `batch_dim = num_prefix_dims + 1` |
| `updates.shape = indices.shape + var.shape[batch_dim:]` |
| |
| where |
| |
| `updates.shape[:num_prefix_dims]` |
| `== indices.shape[:num_prefix_dims]` |
| `== var.shape[:num_prefix_dims]` |
| |
| And the operation performed can be expressed as: |
| |
| `var[i_1, ..., i_n, indices[i_1, ..., i_n, j]] = updates[i_1, ..., i_n, j]` |
| |
| When indices is a 1D tensor, this operation is equivalent to |
| `tf.compat.v1.scatter_update`. |
| |
| To avoid this operation there would be 2 alternatives: |
| 1) Reshaping the variable by merging the first `ndims` dimensions. However, |
| this is not possible because `tf.reshape` returns a Tensor, which we |
| cannot use `tf.compat.v1.scatter_update` on. |
| 2) Looping over the first `ndims` of the variable and using |
| `tf.compat.v1.scatter_update` on the subtensors that result of slicing the |
| first |
| dimension. This is a valid option for `ndims = 1`, but less efficient than |
| this implementation. |
| |
| See also `tf.compat.v1.scatter_update` and `tf.compat.v1.scatter_nd_update`. |
| |
| Args: |
| ref: `Variable` to scatter onto. |
| indices: Tensor containing indices as described above. |
| updates: Tensor of updates to apply to `ref`. |
| use_locking: Boolean indicating whether to lock the writing operation. |
| name: Optional scope name string. |
| |
| Returns: |
| Ref to `variable` after it has been modified. |
| |
| Raises: |
| ValueError: If the initial `ndims` of `ref`, `indices`, and `updates` are |
| not the same. |
| """ |
| with ops.name_scope(name): |
| indices = ops.convert_to_tensor(indices, name="indices") |
| indices_shape = array_ops.shape(indices) |
| indices_dimensions = indices.get_shape().ndims |
| |
| if indices_dimensions is None: |
| raise ValueError("batch_gather does not allow indices with unknown " |
| "shape.") |
| |
| nd_indices = array_ops.expand_dims(indices, axis=-1) |
| nd_indices_list = [] |
| |
| # Scatter ND requires indices to have an additional dimension, in which the |
| # coordinates of the updated things are specified. For this to be adapted to |
| # the scatter_update with several leading dimensions, we simply make use of |
| # a tf.range for all the leading dimensions followed by concat of all the |
| # coordinates we created with the original indices. |
| |
| # For example if indices.shape = [2, 3, 4], we should generate the following |
| # indices for tf.compat.v1.scatter_nd_update: |
| # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]] |
| # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]] |
| # nd_indices[:, :, 2] = indices |
| for dimension in range(indices_dimensions - 1): |
| # In this loop we generate the following for the example (one for each |
| # iteration). |
| # nd_indices[:, :, 0] = [[0, 0, 0], [1, 1, 1]] |
| # nd_indices[:, :, 1] = [[0, 1, 2], [0, 1, 2]] |
| # This is done at every iteration with a tf.range over the size of the |
| # i-th dimension and using broadcasting over the desired shape. |
| dimension_size = indices_shape[dimension] |
| shape_to_broadcast = [1] * (indices_dimensions + 1) |
| shape_to_broadcast[dimension] = dimension_size |
| dimension_range = array_ops.reshape( |
| gen_math_ops._range(0, dimension_size, 1), shape_to_broadcast) |
| if dimension_range.dtype.base_dtype != nd_indices.dtype: |
| dimension_range = gen_math_ops.cast(dimension_range, nd_indices.dtype) |
| nd_indices_list.append( |
| dimension_range * array_ops.ones_like(nd_indices)) |
| # Add the original indices at the end, as described above, and concat. |
| nd_indices_list.append(nd_indices) |
| final_indices = array_ops.concat(nd_indices_list, axis=-1) |
| return scatter_nd_update( |
| ref, final_indices, updates, use_locking=use_locking) |