tensorflow源码解析之framework-function

目录

  1. 核心概念
  2. FunctionDef
  3. function related classes

1. 核心概念

在讲解function的概念之前,我们要先回顾下op。op是规定了输入和输出的操作声明,在研究node的时候我们也看到,NodeDef是包含OpDef的,那么是不是op就只能是节点级别的操作呢?并非如此,操作是可以嵌套的,也就是说,操作A可能内部包含了操作BCD。从这个角度理解function就容易了,function其实就是一些大的op。函数的本质是给定输入,经过计算给出输出,这与op的定位相同。对于一些大op,我们可以定义函数与之对应,这些函数内部会包含OpDef,表示这个函数的签名(输入、输出),也会包含一系列NodeDef,用于表示函数内部的运行机制。

2. FunctionDef

有了上面的理解,我们先来看一下FunctionDef的结构:

message FunctionDef {
    OpDef signature = 1;
    map<string, AttrValue> attr = 5;//函数中的内部参数
    repeated NodeDef node_def = 3;
    map<string, string> ret = 4;//一个从signature中输出参数名称,到node_def的输出的映射
}
message GradientDef {
    string function_name = 1;//原函数名称
    string gradient_func = 2;//梯度函数名称
}
message FunctionDefLibrary {
    repeated FunctionDef function = 1;
    repeated GradientDef gradient = 2;
}

有以下几点需要说明:

  • 正如我们刚才所说的,node_def是一系列节点,这些节点组合在一起形成了函数内部的结构。OpDef中包含了输入输出的名称,在function中我们的输出是被包含在node_def中的,所以需要一个从OpDef中的输出名称到输出所在节点名称和端口号的映射,于是就有了ret。
  • TF支持梯度计算,是因为TF针对每个函数给出了它的梯度函数。梯度函数本身也是一个函数,有输入有输出,为了能将原函数和其梯度函数联系在一起,就有了GradientDef这个结构,这个结构中包含了原函数的名称,也包含了原函数所对应的梯度函数的名称。
  • TF的运行时包含了一个函数定义库,需要使用某个函数时,可以去库里找,因此这个函数定义库包含了多个普通函数,和梯度函数。

3. function related class

3.1 FunctionDefHelper

为了方便对FunctionDef的定义,设计了FunctionDefHelper类,利用它可以方便的定义函数,如下:

FunctionDef my_func = FunctionDefHelper::Create(
  "my_func_name",
  {"x:T", "y:T"},//每个输入参数用一个字符串表示
  {“z:T"},//每个输出用一个字符串表示
  {"T: {float, double}"},//每个参数一条字符串
  {
      {{"o"},"Mul",{"x","y"},{{"T","$T"}}}
  },//每个节点对应一个元素
  {{"z", "o:z"}}//函数输出到节点输出的映射
);

这个类的实现比较简单,这里我们就不再赘述了。

3.2 FuncionCallFrame

在TF图中,如果要调用一个function,仅知道函数定义是不够的,我们还要为向函数中传递数据,以及从函数中返回数据,提供结构和功能上的支持。还记得OpKernel类的Compute函数吗?每个kernel的计算函数都使用了同样一个接口,依靠同一个接口实现了不同的运算,秘密就在于函数的输入参数OpKernelContext,它相当于Compute函数调用的上下文,让同样的接口,可以为完全不同的运算提供支持。这也就是FunctionCallFrame存在的意义,它本质上是一个数据中转站,把函数输入数据填入这个结构,在函数计算结束后再把输出数据填入,让函数调用者获取需要的数据。从某种意义上讲,它很像函数调用所在的栈帧,这也就是FunctionCallFrame这个名字的由来:

class FunctionCallFrame {
    //...
  private:
    DataTypeVector arg_types_;
    DataTypeVector ret_types_;
    gtl::InlinedVector<Tensor, 4> args_;
    struct Retval {
        bool has_val = false;
        Tensor val;
    };
    gtl::InlinedVector<Retval, 4> rets_;
}

可以看出,这个类的私有数据成员只有输入输出类型、输入输出数值这样四类,本质上就是函数调用的一个中转站。

3.3 FunctionLibraryDefinition

刚才我们在看函数相关proto的时候看到一个结构,FunctionDefLibrary,这两个类要区分清楚。Definition类本质上是一个注册器,提供了函数注册、查找等功能,而Library本质上是一个函数定义的集合,不具备查找功能。下面我们来看一下,类的结构:

class FunctionLibraryDefinition : public OpRegistryInterface {
  private:
    struct FunctionDefAndOpRegistration {
        FunctionDefAndOpRegistration(const FunctionDef& fdef_in);
        FunctionDef fdef;
        OpRegistrationData op_registration_data;
    };
    const OpRegistryInterface* const default_registry_;
    gtl::FlatMap<string, std::unique_ptr<FunctionDefAndOpRegistration>> function_defs_;
    gtl::FlatMap<string, string> func_grad_;
};

这个类给我们提供了一个方便对function进行集中管理的地方。

3.4 FunctionLibraryRuntime

顾名思义,是函数库的运行时类。为函数的执行提供了很多便利的接口。它单纯是包裹在FunctionLibraryDefinition这个类之上的,提供API支持,本身是没有任何数据成员的。我们简单看下它都提供了哪些API:

class FunctionLibraryRuntime {
  public:
    //...
    virtual Status Instantiate(const string& function_name, AttrSlice attrs, Handle* handle) = 0;//用参数实例化一个函数
    virtual const FunctionBody* GetFunctionBody(Handle h) = 0;//获取一个已经实例化了的函数的函数体
    virtual void Run(const Option& opts, Handle handle, gtl::ArraySlice<Tensor> args, std::vector<Tensor>* rets, DoneCallback done) = 0;//异步的调用一个使用handle标识的函数
    virtual Status CreateKernel(const NodeDef& ndef, OpKernel** kernel) = 0;//给定ndef,创造一个kernel
    virtual bool IsStateful(const string& function_name) = 0;//该函数是否是带有状态的
    virtual Device* device() = 0;//函数运行所在的设备
    virtual const FunctionLibraryDefinition* GetFunctionLibraryDefinition() const = 0;
    virtual Env* env() = 0;
};

原文地址:https://www.cnblogs.com/jicanghai/p/9551776.html

时间: 2024-11-01 11:36:35

tensorflow源码解析之framework-function的相关文章

tensorflow源码解析系列文章索引

文章索引 framework解析 resource allocator tensor op node kernel graph device function shape_inference common_runtime解析 device session graph_optimizer executor-1 executor-2 direct_session 后记 关于起源 阅读tensorflow源码时,为了敦促自己主动思考,把阅读的笔记整理成了博客,拿出来跟大家分享. 关于迭代 文章都是工作

Tensorflow源码解析1 -- 内核架构和源码结构

1 主流深度学习框架对比 当今的软件开发基本都是分层化和模块化的,应用层开发会基于框架层.比如开发Linux Driver会基于Linux kernel,开发Android app会基于Android Framework.深度学习也不例外,框架层为上层模型开发提供了强大的多语言接口.稳定的运行时.高效的算子,以及完备的通信层和设备层管理层.因此,各大公司早早的就开始了深度学习框架的研发,以便能占领市场.当前的框架有数十种之多,主流的如下(截止到2018年11月) 显然TensorFlow是独一无

tensorflow源码解析之common_runtime-executor-上

目录 核心概念 executor.h Executor NewLocalExecutor ExecutorBarrier executor.cc structs GraphView ExecutorImpl ExecutorState details 1. 核心概念 执行器是TF的核心中的核心了,前面做了这么多的准备工作,最后要在这里集大成了,想想还有点小激动.不过笔者在这里先打个预防针,执行器的概念多.结构复杂,想要透彻理解并不容易,为了保持文章的易读性,我们也是尽量对细枝末节做了舍弃,以求反

tensorflow源码解析之framework-allocator

目录 core/framework resource allocator 核心概念 给出的只是内存分配器的接口,没有给出具体实现. Allocator Allocator是一个内存分配器的接口类,它规定了一个内存分配器需要具有哪些API.具体看代码: class Allocator { public: virtual void* AllocateRaw(size_t alignment, size_t num_bytes) = 0; virtual void DeallocateRaw(void

tensorflow源码解析之common_runtime-device

目录 核心概念 device device_factory device_mgr device_set 1. 核心概念 在framework部分,我们介绍了DeviceAttributes和DeviceBase两个结构,这些其实是为了我们今天要介绍的Device类做准备的.感兴趣的读者可以去回顾下前面讲过的内容.Device类只是对DeviceBase类的继承,没有添加更多新的数据成员,但提供了Compute计算接口.DeviceSet是一个设备集合类,而DeviceMgr与DeviceSet的

tensorflow源码解析之common_runtime-graph_optimizer

目录 核心概念 graph_optimizer function optimization_registry 1. 核心概念 本篇主要讲图的优化迭代器.我们在构建原始图的时候,专注于达到目的,但不会去考虑图的执行效率.如果把图的设计过程比喻为高级语言的编写,那么图的优化过程就相当于,将高级语言编译为机器语言的过程中,为了能够加速进行的编译优化.比如,将相同的常数折叠,将Identity节点去除等等.本节主要用来讨论,跟图优化相关的类和函数. 2. graph_optimizer 进行图优化,需要

tensorflow源码解析之common_runtime-direct_session

目录 核心概念 direct_session direct_session.h direct_session.cc 1. 核心概念 读过之前文章的读者应该还记得,session是一个执行代理.我们把计算图和输入交给session,由它来调度执行器,执行计算产生结果.TF给我们提供了一个最简单的执行器direction_session.按照当前的理解,我们觉得direction_session的实现应该是非常简单而直接的,毕竟执行器的复杂结构我们在executor那篇已经见到了.但实际上,问题的难

tensorflow源码解析之framework-node

目录 核心概念 node_def 1. 核心概念 TF中的图由节点构成,每个节点包含了一个操作,表名这个节点的作用,比如,将两个输入矩阵相乘,输出结果.节点是自带图结构的,每个节点都包含了输入的来源,因此若干节点的集合就能无需其它信息的生成一张图.节点必须被放置在某一个设备上,为了减少跨设备传输数据,也为了提高计算效率,TF还专门开发了相应的节点放置算法. 2. node_def 我们先来看一下节点的定义: message NodeDef { string name = 1;//节点名称 str

tensorflow源码解析之common_runtime-executor-下

目录 核心概念 executor.h Executor NewLocalExecutor ExecutorBarrier executor.cc structs GraphView ExecutorImpl ExecutorState details 3.4 ExecutorState 在执行器的执行图计算的时候,需要一个结构来保存当前计算的即时信息,TF为此设计了类ExecutorState,它被用来保存每一个对ExecutorImpl::Run调用的状态信息.它会在一个节点已经准备好之后调度