From 00f9eb9c589ad3c5ce5b4dde84763553c56ad0ee Mon Sep 17 00:00:00 2001 From: Alexandre Passos Date: Tue, 24 Jul 2018 09:35:59 -0700 Subject: Improvement resource variable documentation. Removes stale mentions of how to construct them from docstrings and adds a new section to the programmer's guide explaining resource handles and resource variable semantics. PiperOrigin-RevId: 205842012 --- tensorflow/contrib/eager/python/saver.py | 4 +-- .../base_api/api_def_ResourceScatterNdAdd.pbtxt | 2 +- tensorflow/python/eager/backprop.py | 8 ++--- tensorflow/python/eager/function.py | 27 +++++++------- tensorflow/python/ops/resource_variable_ops.py | 17 ++++----- tensorflow/python/ops/variables.py | 41 +++++++++------------- 6 files changed, 45 insertions(+), 54 deletions(-) diff --git a/tensorflow/contrib/eager/python/saver.py b/tensorflow/contrib/eager/python/saver.py index fdaca90fd1..d709308647 100644 --- a/tensorflow/contrib/eager/python/saver.py +++ b/tensorflow/contrib/eager/python/saver.py @@ -125,8 +125,8 @@ class Saver(object): Args: var_list: The list of variables that will be saved and restored. Either a - list of `tfe.Variable` objects, or a dictionary mapping names to - `tfe.Variable` objects. + list of `tf.Variable` objects, or a dictionary mapping names to + `tf.Variable` objects. Raises: RuntimeError: if invoked when eager execution has not been enabled. diff --git a/tensorflow/core/api_def/base_api/api_def_ResourceScatterNdAdd.pbtxt b/tensorflow/core/api_def/base_api/api_def_ResourceScatterNdAdd.pbtxt index 3b3a274df5..2b58969da2 100644 --- a/tensorflow/core/api_def/base_api/api_def_ResourceScatterNdAdd.pbtxt +++ b/tensorflow/core/api_def/base_api/api_def_ResourceScatterNdAdd.pbtxt @@ -51,7 +51,7 @@ 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 = tfe.Variable([1, 2, 3, 4, 5, 6, 7, 8]) + ref = tf.Variable([1, 2, 3, 4, 5, 6, 7, 8], use_resource=True) indices = tf.constant([[4], [3], [1] ,[7]]) updates = tf.constant([9, 10, 11, 12]) update = tf.scatter_nd_add(ref, indices, updates) diff --git a/tensorflow/python/eager/backprop.py b/tensorflow/python/eager/backprop.py index 9e0bbce4a1..da8b93dba8 100644 --- a/tensorflow/python/eager/backprop.py +++ b/tensorflow/python/eager/backprop.py @@ -643,10 +643,10 @@ class GradientTape(object): Operations are recorded if they are executed within this context manager and at least one of their inputs is being "watched". - Trainable variables (created by `tf.contrib.eager.Variable` or - @{tf.get_variable}, trainable=True is default in both cases) are automatically - watched. Tensors can be manually watched by invoking the `watch` method on - this context manager. + Trainable variables (created by `tf.Variable` or @{tf.get_variable}, + trainable=True is default in both cases) are automatically watched. Tensors + can be manually watched by invoking the `watch` method on this context + manager. For example, consider the function `y = x * x`. The gradient at `x = 3.0` can be computed as: diff --git a/tensorflow/python/eager/function.py b/tensorflow/python/eager/function.py index a6906f9efd..d283a85532 100644 --- a/tensorflow/python/eager/function.py +++ b/tensorflow/python/eager/function.py @@ -1077,7 +1077,7 @@ def defun(func=None, compiled=False): tf.enable_eager_execution() def fn(): - x = tf.contrib.eager.Variable(0.0) + x = tf.Variable(0.0) x.assign_add(1.0) return x.read_value() @@ -1094,19 +1094,18 @@ def defun(func=None, compiled=False): ``` Finally, because each input signature is bound to a unique graph, if your - Python function constructs `tf.contrib.eager.Variable` objects, then each - graph constructed for that Python function will reference a unique set of - variables. To circumvent this problem, we recommend against compiling Python - functions that create `tf.contrib.eager.Variable` objects. Instead, Python - functions should either lexically close over `tf.contrib.eager.Variable` - objects or accept them as arguments, preferably encapsulated in an - object-oriented container. If you must create variables inside your Python - function and you want each graph generated for it to reference the same set of - variables, add logic to your Python function that ensures that variables are - only created the first time it is called and are reused for every subsequent - invocation; note that this is precisely what @{tf.keras.layers.Layer} objects - do, so we recommend using them to represent variable-bearing computations - whenever possible. + Python function constructs `tf.Variable` objects, then each graph constructed + for that Python function will reference a unique set of variables. To + circumvent this problem, we recommend against compiling Python functions that + create `tf.Variable` objects. Instead, Python functions should either + lexically close over `tf.Variable` objects or accept them as arguments, + preferably encapsulated in an object-oriented container. If you must create + variables inside your Python function and you want each graph generated for it + to reference the same set of variables, add logic to your Python function that + ensures that variables are only created the first time it is called and are + reused for every subsequent invocation; note that this is precisely what + @{tf.keras.layers.Layer} objects do, so we recommend using them to represent + variable-bearing computations whenever possible. Args: func: function to be compiled. If `func` is None, returns a diff --git a/tensorflow/python/ops/resource_variable_ops.py b/tensorflow/python/ops/resource_variable_ops.py index db071e3974..8b259b6b6b 100644 --- a/tensorflow/python/ops/resource_variable_ops.py +++ b/tensorflow/python/ops/resource_variable_ops.py @@ -196,15 +196,16 @@ class ResourceVariable(variables.RefVariable): the variable are fixed. The value can be changed using one of the assign methods. - Just like any `Tensor`, variables created with `ResourceVariable()` can be - used as inputs for other Ops in the graph. Additionally, all the operators - overloaded for the `Tensor` class are carried over to variables, so you can - also add nodes to the graph by just doing arithmetic on variables. + Just like any `Tensor`, variables created with + `tf.Variable(use_resource=True)` can be used as inputs for other Ops in the + graph. Additionally, all the operators overloaded for the `Tensor` class are + carried over to variables, so you can also add nodes to the graph by just + doing arithmetic on variables. - Unlike tf.Variable, a tf.ResourceVariable has well-defined semantics. Each + Unlike ref-based variable, a ResourceVariable has well-defined semantics. Each usage of a ResourceVariable in a TensorFlow graph adds a read_value operation - to the graph. The Tensors returned by a read_value operation are guaranteed - to see all modifications to the value of the variable which happen in any + to the graph. The Tensors returned by a read_value operation are guaranteed to + see all modifications to the value of the variable which happen in any operation on which the read_value depends on (either directly, indirectly, or via a control dependency) and guaranteed to not see any modification to the value of the variable from operations that depend on the read_value operation. @@ -218,7 +219,7 @@ class ResourceVariable(variables.RefVariable): can cause tf.Variable and tf.ResourceVariable to behave differently: ```python - a = tf.ResourceVariable(1.0) + a = tf.Variable(1.0, use_resource=True) a.initializer.run() assign = a.assign(2.0) diff --git a/tensorflow/python/ops/variables.py b/tensorflow/python/ops/variables.py index d03d93beeb..fc00ce68ae 100644 --- a/tensorflow/python/ops/variables.py +++ b/tensorflow/python/ops/variables.py @@ -220,27 +220,31 @@ class Variable(six.with_metaclass(VariableMetaclass, various `Optimizer` classes use this collection as the default list of variables to optimize. - WARNING: tf.Variable objects have a non-intuitive memory model. A Variable is - represented internally as a mutable Tensor which can non-deterministically - alias other Tensors in a graph. The set of operations which consume a Variable - and can lead to aliasing is undetermined and can change across TensorFlow - versions. Avoid writing code which relies on the value of a Variable either - changing or not changing as other operations happen. For example, using - Variable objects or simple functions thereof as predicates in a `tf.cond` is - dangerous and error-prone: + WARNING: tf.Variable objects by default have a non-intuitive memory model. A + Variable is represented internally as a mutable Tensor which can + non-deterministically alias other Tensors in a graph. The set of operations + which consume a Variable and can lead to aliasing is undetermined and can + change across TensorFlow versions. Avoid writing code which relies on the + value of a Variable either changing or not changing as other operations + happen. For example, using Variable objects or simple functions thereof as + predicates in a `tf.cond` is dangerous and error-prone: ``` v = tf.Variable(True) tf.cond(v, lambda: v.assign(False), my_false_fn) # Note: this is broken. ``` - Here replacing tf.Variable with tf.contrib.eager.Variable will fix any - nondeterminism issues. + Here replacing adding `use_resource=True` when constructing the variable will + fix any nondeterminism issues: + ``` + v = tf.Variable(True, use_resource=True) + tf.cond(v, lambda: v.assign(False), my_false_fn) + ``` To use the replacement for variables which does not have these issues: - * Replace `tf.Variable` with `tf.contrib.eager.Variable`; + * Add `use_resource=True` when constructing `tf.Variable`; * Call `tf.get_variable_scope().set_use_resource(True)` inside a `tf.variable_scope` before the `tf.get_variable()` call. """ @@ -869,19 +873,7 @@ class RefVariable(Variable): ValueError: If the initial value is not specified, or does not have a shape and `validate_shape` is `True`. RuntimeError: If eager execution is enabled. - - @compatibility(eager) - `tf.Variable` is not compatible with eager execution. Use - `tfe.Variable` instead which is compatible with both eager execution - and graph construction. See [the TensorFlow Eager Execution - guide](https://github.com/tensorflow/tensorflow/tree/master/tensorflow/contrib/eager/python/g3doc/guide.md#variables-and-optimizers) - for details on how variables work in eager execution. - @end_compatibility """ - if context.executing_eagerly(): - raise RuntimeError( - "tf.Variable not supported when eager execution is enabled. " - "Please use tf.contrib.eager.Variable instead") self._in_graph_mode = True if variable_def: # If variable_def is provided, recreates the variable from its fields. @@ -992,8 +984,7 @@ class RefVariable(Variable): # Ensure that we weren't lifted into the eager context. if context.executing_eagerly(): raise RuntimeError( - "tf.Variable not supported when eager execution is enabled. " - "Please use tf.contrib.eager.Variable instead") + "RefVariable not supported when eager execution is enabled. ") with ops.name_scope(name, "Variable", [] if init_from_fn else [initial_value]) as name: -- cgit v1.2.3