了解TensorFlow中的操作注册和内核链接

Abh*_*bhi 7 c++ swig kernel registration tensorflow

我是TensorFlow的新手,现在正在研究定制的op开发.我已经阅读了官方教程,但我觉得很多事情都发生在幕后,我并不总是想把我的自定义操作放在user_ops目录中.

因此,我了一个例子word2vec

它使用自定义的"Skipgram"操作,其注册定义如下:
/word2vec_o​​ps.cc
,其内核实现位于:
/word2vec_kernels.cc

查看构建文件,我尝试构建单个目标

1)bazel build -c opt tensorflow/models/embedding:word2vec_ops
这会按预期生成一堆目标文件.

2)bazel build -c opt tensorflow/models/embedding:word2vec_kernels
同样的.

3) bazel build -c opt tensorflow/models/embedding:word2vec_kernels:gen_word2vec

最后一个版本使用自定义规则,即tf_op_gen_wrapper_py https://github.com/tensorflow/tensorflow/blob/master/tensorflow/tensorflow.bzl#L197-L231

有趣的是,这只取决于操作注册而不是内核本身.

毕竟,如果我py_binary使用自己构建自己

bazel build -c opt tensorflow/models/embedding:word2vec

它工作正常,但我没有看到内核c ++代码链接的位置和方式?

另外,我还想了解tf_op_gen_wrapper_py操作注册的幕后规则和整个编译/链接过程.

谢谢.

mrr*_*rry 20

增加一个新的操作TensorFlow的,主要有两个步骤:

  1. 注册"op",包括定义操作的接口,以及

  2. 注册一个或多个"内核",其中涉及定义操作的实现,可能使用针对不同数据类型或设备类型(如CPU或GPU)的专门实现.

这两个步骤都涉及编写C++代码.注册op使用REGISTER_OP(),注册内核使用REGISTER_KERNEL_BUILDER().这些宏创建静态初始化程序,这些初始化程序在加载包含它们的模块时运行.op和内核注册有两种主要的机制:

  1. 静态链接到核心TensorFlow库,并进行静态初始化.

  2. 使用该tf.load_op_library()函数在运行时动态链接.

在这种情况下"Skipgram",我们使用选项1(静态链接).在OPS被链接到核心TensorFlow图书馆在这里,和仁在链接这里.(请注意,这并不理想:word2vecops是在我们创建之前创建的tf.load_op_library(),因此没有动态链接它们的机制.)因此,当您第一次加载TensorFlow(in import tensorflow as tf)时,会注册操作和内核.如果它们是今天创建的,它们将被动态加载,这样它们只有在需要时才会被注册.(SyntaxNet代码有一个动态加载的例子.)

Bazel中的tf_op_gen_wrapper_py()规则获取了一个op -library依赖项列表,并为这些操作生成Python包装器.此规则仅依赖于op注册的原因是Python包装器完全由op的接口决定,该接口在op注册中定义.值得注意的是,Python接口不知道是否有特定类型或设备的专用内核.包装器生成器将op注册链接到一个简单的C++二进制文件,该二进制文件为每个注册的操作生成Python代码.请注意,如果使用tf.load_op_library(),则不需要自己调用包装器生成器,因为tf.load_op_library()它将在运行时生成必要的代码.

  • 我可能会补充一点,我在尝试将syntaxnet“自定义”操作链接到外部二进制文件时感到困惑,因为其中一个操作的syntaxnet中的BUILD目标缺少“alwayslink = 1”。我认为这是因为如果没有“alwayslink”,相关的“.o”文件就不会被链接(OpKernel 本身没有符号依赖),并且它不会注册。当“alwayslink = 1”存在时,“.o”将被链接并在加载二进制文件时静态注册 OpKernel。 (2认同)