页面树结构

2017-11-09 ApacheCN 开源组织,第二期邀请成员活动,一起走的更远 : http://www.apachecn.org/member/209.html


MachineLearning 优酷地址 : http://i.youku.com/apachecn

转至元数据结尾
转至元数据起始

背景

本文档旨在作为有意在其他编程语言中创建或开发 TensorFlow 功能的用户的指南。它描述了 TensorFlow 的功能和推荐的步骤,使其他编程语言可用。

PythonTensorFlow 支持的第一个客户端语言,目前支持最多的功能。越来越多的功能被转移到 TensorFlow 的核心(C ++ 中实现),并通过 C API 公开。客户端语言应该使用语言的外部函数接口(FFI来调用此 C API 来提供 TensorFlow 功能。

 

概观

以编程语言提供 TensorFlow 功能可以分为大类:

  • 运行预定义的图形:给定 GraphDef(或 MetaGraphDef)协议消息,能够创建一个会话,运行查询,并获得张量结果。这对于希望在预先训练的模型上运行推理的移动应用程序或服务器就足够了。
  • 图形构造:每个定义的 TensorFlow 操作至少有一个函数向图中添加一个操作。理想情况下,这些功能将自动生成,以便在修改 op 定义时保持同步。
  • 渐变(AKA自动区分):给定图形和输入和输出操作列表,向图中添加计算输出相对于输出的偏导数(梯度)的图形。允许自定义图形中特定操作的渐变功能。
  • 功能:定义可在主 GraphDef 中的多个位置调用的子图。定义 GraphDef 中包含的 FunctionDefLibrary 中的 FunctionDef
  • 控制流程:用用户指定的子图构造 “If” 和 “While” 。理想情况下,这些工作与渐变(见上文)。
  • 神经网络库:一些支持创建神经网络模型并进行训练的组件(可能在分布式环境中)。虽然以其他语言提供这种方法很方便,但目前还没有计划以 Python 以外的语言支持这一点。这些库通常是上述特征的包装器。

至少,语言绑定应该支持运行预定义的图形,但大多数应该也支持图形构造。TensorFlow Python API 提供了所有这些功能。

 

当前状态

新语言支持应该建立在 C API 之上。但是,如下表所示,C 并不是所有功能都可用。在 C API 中提供更多功能是一个持续的项目。

特征PythonC
运行预定义的图形tf.import_graph_def, tf.SessionTF_GraphImportGraphDef, TF_NewSession
具有生成 op 函数的图形结构是(C API 支持这样做的客户端语言)
渐变tf.gradients 
功能tf.python.framework.function.Defun 
控制流程tf.cond, tf.while_loop 
神经网络库tf.train,,,tf.nn tf.contrib.layers tf.contrib.slim 

推荐方法

运行预定义的图形

语言绑定有望定义以下类:

  • Graph:表示 TensorFlow 计算的图形。由操作组成(以操作的客户端语言表示),并对应于 C API 中的 TF_Graph 。主要用作创建新 Operation 对象和启动时的参数 Session。还支持遍历图形中的操作( TF_GraphNextOperation ),按名称查找操作( TF_GraphOperationByName ),并转换为 GraphDef 协议消息(C API 中的 TF_GraphToGraphDefTF_GraphImportGraphDef )。
  • Operation:表示图中的计算节点。对应于 C API 中的 TF_Operation
  • Output:表示图中操作的输出之一。有 DataType(最终形状)。可以作为输入参数传递给用于向图中添加操作的函数,或作为会话的 Run() 方法将该输出作为张量来获取。对应于 C API 中的 TF_Output
  • Session:表示客户端到 TensorFlow 运行时的特定实例。它的主要工作是构建一个 Graph 和一些选项,然后 Run() 对图表进行现场调用。对应于 C API 中的 TF_Session
  • Tensor:表示具有相同 DataType 元素的 N 维(矩形)数组。获取数据进出 SessionRun() 调用。对应于 C API 中的 TF_Tensor 
  • DataType:具有 TensorFlow 支持的所有可能的张量类型的枚举。对应于 C API 中的 TF_DataType ,在 Python API 中通常称为 dtype

图形构造

TensorFlow 有很多操作,列表不是静态的,所以我们建议生成函数来添加操作图,而不是用手单独编写它们(尽管用手写几个是一个很好的方法来弄清楚发生器应该是什么生成)。生成功能所需的 OpDef 信息包含在协议消息中。

有几种方法可以获得注册操作的 OpDefs 列表:

  • C API 中的 TF_GetAllOpList 检索所有注册的 OpDef 协议消息。这可以用于以客户端语言编写生成器。这要求客户端语言具有协议缓冲区支持,以便解释 OpDef 消息。
  • C ++ 函数 OpRegistry :: Global() - > GetRegisteredOps() 返回所有注册的 OpDefs 的相同列表(在 [tensorflow / core / framework / op.h] 中定义))。这可以用于在 C ++ 中编写生成器(特别适用于没有协议缓冲区支持的语言)。
  • 该列表的 ASCII 序列化版本通过自动化过程定期检入 [tensorflow / core / ops / ops.pbtxt]

 OpDef 规定如下:

  • CamelCaseop 的名称。对于生成的函数,遵循语言的约定。例如,如果语言使用 snake_case ,那么使用它而不是 CamelCase 作为 op 的函数名。
  • 输入和输出列表。这些类型可以通过引用属性来进行多态,如“ 添加操作”的 “输入和输出”部分 所述
  • 属性列表及其默认值(如果有)。请注意,其中一些将被推断(如果它们由输入确定),则某些将是可选的(如果它们具有默认值),并且某些将是必需的(无默认)。
  • 一般操作的文档以及输入,输出和非推断属性。
  • 运行时使用的其他一些字段,可以被代码生成器忽略。

OpDef 可以转换为使用 TF_OperationDescription C API (包装在语言的 FFI 中)将该 op 添加到图形的函数的文本:

  • TF_NewOperation() 开始创建 TF_OperationDescription *
  • 每次输入一次调用 TF_AddInput() TF_AddInputList() (取决于输入是否具有列表类型)。
  • 调用 TF_SetAttr *() 函数设置非推断属性。 如果不想覆盖默认值,可以跳过具有默认值的属性。
  • 必要时设置可选字段:
    • TF_SetDevice():强制操作到特定设备上。
    • TF_AddControlInput():在此操作开始运行之前添加另一个操作完成的要求
    • TF_SetAttrString("_kernel") 设置内核标签(很少使用)
    • TF_ColocateWith() 将一个操作与另一个操作对齐
  •  完成后调用 TF_FinishOperation() 。 这将操作添加到图形,之后它不能被修改。

现有的示例运行代码生成器作为构建过程的一部分(使用 Bazel genrule )。或者,代码生成器可以通过自动的 cron 进程运行,可能检查结果。这会产生生成的代码和检入存储库的 OpDef 之间的差异风险,但对于预期像 go getGocargo opsRust 那样预先生成代码的语言很有用 。在频谱的另一端,对于某些语言,代码可以从 [ tensorflow/core/ops/ops.pbtxt] 动态生成。

处理常数

如果用户可以为输入参数提供常量,调用代码将会更为简洁。生成的代码应将这些常量转换为添加到图形中的操作,并将其用作要被实例化的 op 的输入。

可选参数

如果语言允许功能的可选参数(如 Python 中的默认值的关键字参数),请使用它们作为可选属性,操作名称,设备,控制输入等。在某些语言中,可以使用动态范围(如“与 Python 中的”块“)。没有这些功能,库可能会采用“构建器模式”,就像 C ++ 版本的 TensorFlow API 一样。

名称范围

支持使用某种范围界定层次结构来命名图形操作是一个好主意,特别是考虑到 TensorBoard 依靠它以合理的方式显示大图。现有的 Python 和 C ++ API 采用不同的方法:在 Python 中,名称的“目录”部分(最后一个“/”)都来自于块。实际上,有一个线程本地堆栈,范围定义了名称层次结构。名称的最后一个组件是由用户显式提供(使用可选 name 关键字参数),或默认为要添加的操作的类型的名称。在 C ++ 中,名称的“目录”部分存储在显式 Scope 对象中。该 NewSubScope() 方法附加到该名称的该部分并返回一个新的 Scope 。 WithOpName() 名称的最后一个组件是使用该方法设置的,并且像 Python 一样默认为要添加的 op 类型的名称。Scope 明确传递对象以指定上下文的名称。

包装

将生成的函数保留为某些操作可能是有意义的,以便可以使用执行一些额外工作的包装器函数。这也提供了用于支持生成代码范围之外的功能的逃生舱。

包装器的一个用途是支持 SparseTensor 输入和输出。SparseTensor3 个密集张量的元组:索引,值和形状。值是向量大小 [n] ,形状是向量大小 [rank] ,索引是矩阵大小 [n,rank] 。有一些稀疏的操作使用这个三元组来表示单个稀疏张量。

使用包装的另一个原因是持有状态的操作。有几个这样的操作(例如一个变量)有几个伴随操作在该状态下操作。Python API 具有这些 op 的类,构造函数创建 op ,该类上的方法将对操作状态的图形添加操作。

其他注意事项

  • 有一个用于重命名 op 函数和参数的关键字列表,这些关键字与语言关键字(或其他会引起问题的符号,如库函数的名称或生成的代码中引用的变量)相冲突。
  • Const 操作添加到图形的功能通常是一个包装器,因为生成的函数通常将具有冗余的 DataType 输入。

梯度,功能和控制流程

此时,对 Python 以外的其他语言不支持渐变,功能和控制流操作( “if” “while” )。当 C API 提供必要的支持时,这将被更新。

 

  • 无标签