TensorFlow 样式指南

本页中包含一些样式规定,TensorFlow 开发者和用户都应遵循这些规定,以提升其代码的可读性,减少错误数量,并提高一致性。

Python 样式

总体上遵循 PEP8 Python 样式指南,不过要使用 2 个空格。

Python 2 和 3 兼容性

  • 所有代码都需要与 Python 2 和 3 兼容。

  • 所有 Python 文件中都应包含下面这几行代码:

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
  • 使用 six 编写兼容代码(例如 six.moves.range)。

Bazel 编译规则

TensorFlow 使用编译系统并强制执行以下要求:

  • 所有编译文件都应包含以下标头:
# Description:
#   <...>

package(
    default_visibility = ["//visibility:private"],
)

licenses(["notice"])  # Apache 2.0

exports_files(["LICENSE"])
  • 所有编译文件的末尾都应包含:
filegroup(
    name = "all_files",
    srcs = glob(
        ["**/*"],
        exclude = [
            "**/METADATA",
            "**/OWNERS",
        ],
    ),
    visibility = ["//tensorflow:__subpackages__"],
)
  • 添加新的编译文件时,请将下面这行代码添加到 tensorflow/BUILD 文件的 all_opensource_files 目标中。
"//tensorflow/<directory>:all_files",
  • 对于所有 Python 编译目标(库和测试),请添加下面这行代码:
srcs_version = "PY2AND3",

Tensor

  • 处理批量内容的操作可以假定张量的第一个维度是批量维度。

Python 操作

Python 操作是一个函数,在收到输入张量和参数的情况下,可以创建图的一部分并返回输出张量。

  • 第一个参数应为张量,接下来是基本的 Python 参数。最后一个参数是 name,默认值为 None。如果操作需要将一些 Tensor 保存到图集中,请将带有图集名称的参数放在 name 参数之前并紧邻该参数。

  • 张量参数应为单个张量或一系列张量。例如,“张量或张量列表”太宽泛。请参阅 assert_proper_iterable

  • 将张量作为参数的操作应调用 convert_to_tensor,以便将非张量输入转换为张量(如果它们使用 C++ 操作的话)。请注意,在文档中,参数仍会被描述为特定 dtype 的 Tensor 对象。

  • 每个 Python 操作都应有一个如下所示的 name_scope。作为以下参数传达:name、操作的默认名称,以及输入张量的列表。

  • 操作应包含大量的 Python 注释,并包含参数和返回值声明,以说明每个值的类型和含义。在说明中,应指定可能的形状、dtype 或秩。 请参阅文档详细信息

  • 为了提高易用性,请在示例部分包括一个用法示例以及操作的输入/输出。

例如:

def my_op(tensor_in, other_tensor_in, my_param, other_param=0.5,
          output_collections=(), name=None):
  """My operation that adds two tensors with given coefficients.

  Args:
    tensor_in: `Tensor`, input tensor.
    other_tensor_in: `Tensor`, same shape as `tensor_in`, other input tensor.
    my_param: `float`, coefficient for `tensor_in`.
    other_param: `float`, coefficient for `other_tensor_in`.
    output_collections: `tuple` of `string`s, name of the collection to
                        collect result of this op.
    name: `string`, name of the operation.

  Returns:
    `Tensor` of same shape as `tensor_in`, sum of input values with coefficients.

  Example:
    >>> my_op([1., 2.], [3., 4.], my_param=0.5, other_param=0.6,
              output_collections=['MY_OPS'], name='add_t1t2')
    [2.3, 3.4]
  """
  with tf.name_scope(name, "my_op", [tensor_in, other_tensor_in]):
    tensor_in = tf.convert_to_tensor(tensor_in)
    other_tensor_in = tf.convert_to_tensor(other_tensor_in)
    result = my_param * tensor_in + other_param * other_tensor_in
    tf.add_to_collection(output_collections, result)
    return result

用法:

output = my_op(t1, t2, my_param=0.5, other_param=0.6,
               output_collections=['MY_OPS'], name='add_t1t2')

层是一种 Python 操作,结合了变量创建和/或一个或多个其他图形操作。遵循与常规 Python 操作相同的要求。

  • 如果一个层会创建一个或多个变量,则层函数也应按顺序采用以下参数:

    • initializers:可视需要允许为变量指定初始化器。
    • regularizers:可视需要允许为变量指定正则化器。
    • trainable:控制其变量是否可训练。
    • scope:用于放置变量的 VariableScope 对象。
    • reusebool 指示符,用于指示如果变量位于范围之内,是否应被重复使用。
  • 训练过程中行为方式不同的层应:

    • 采用 is_trainingbool 指示符,用于在执行期间有条件地选择不同的计算路径(例如使用 tf.cond)。

例如:

def conv2d(inputs,
           num_filters_out,
           kernel_size,
           stride=1,
           padding='SAME',
           activation_fn=tf.nn.relu,
           normalization_fn=add_bias,
           normalization_params=None,
           initializers=None,
           regularizers=None,
           trainable=True,
           scope=None,
           reuse=None):
  ... see implementation at tensorflow/contrib/layers/python/layers/layers.py ...