3.6 KiB
TF Agents Style Guide
This page contains style decisions that both developers and users of TF Agents should follow to increase the readability of their code, reduce the number of errors, and promote consistency.
TensorFlow Style
Follow the TensorFlow style guide and documentation guide. Below are additional TensorFlow conventions not noted in those guides. (In the future, these noted conventions may be moved upstream.)
-
The name is TensorFlow, not Tensorflow.
-
Use
name_scopeat the beginning of every Python function.Justification: it’s easier to debug TF graphs when they align with Python code.
-
Run all Tensor args through
tf.convert_to_tensorimmediately after name_scope.Justification: not doing so can lead to surprising results when computing gradients. It can also lead to unnecessary graph ops as subsequent TF calls will keep creating a tensor from the same op.
-
Do not create new Tensors inside
@propertydecorated methods.Justification: property requests cannot pass a
name=argument to set a good name scope for these requests, making debugging harder. Furthermore, property requests should be lightweight and not perform too much computation. But creating tensors, or even performing Eager computation, is relatively expensive compared to just accessing an existing property of the class. -
Every module should define the constant
__all__in order to list all public members of the module.Justification:
__all__is an explicit enumeration of what's intended to be public. It also governs what's imported when usingfrom foo import *(although we cannot use star-import w/in Google, users can.) Use ticks for any Python objects, types, or code. E.g., write `Tensor` instead of Tensor. -
Do not use
tf.functionorcommon.functionin library code, only in binary examples.Justification: When end-users want to debug eager mode, interjecting
tf.functionbreaks their ability to do so. -
Use
utils.common.functioninstead oftf.function.Justification: The default behavior of
tf.functioncan be hard to debug (due to autograph, which we disable), and has serious performance issues with dynamically sized input arrays. -
Remove all calls to
tf.control_dependencies. Wraputils.common.function_in_tf1around functions that usetf.while_loop,tf.map_fn,tf.scan,tf.fold{l,r}, andtf.control_dependencies. This will ensure that the new TF2-style control flow and TensorFlow's new "autodeps" work consistently across the codebase. In TF2, all code is either Eager mode or wrapped in atf.function, and in both cases you get autodeps for free.Justification: Code that uses old-style control flow (TF1
tf.while_loopoutside oftf.function) and new-style control flow (TF2tf.while_loopand TF1tf.while_loopinsidetf.function) does not mix. We have moved most (all?) of TF Agents while loops to use the new-style control flow so we can have consistent behavior in TF1 and TF2. Furthermore, TF currently has some bugs where overzealoustf.control_dependencies, when combined withwhile_loop, creates invalid graphs with loops. Finally, autodeps will insert control deps as needed in the graph, avoiding overzealous control dependencies that cause a reduction in concurrency caused by the "shotgun" manualtf.control_dependenciesapproach.