tensorflow源碼解析之framework-function


目錄

  1. 什么是function
  2. FunctionDef
  3. 函數相關類
  4. 關系圖
  5. 涉及的文件
  6. 迭代記錄

1. 什么是function

在講解function的概念之前,我們要先回顧下op。op是規定了輸入和輸出的操作聲明,在研究node的時候我們也看到,NodeDef是包含OpDef的,那么是不是op就只能是節點級別的操作呢?並非如此,操作是可以嵌套的,也就是說,操作A可能內部包含了操作B、C、D。從這個角度理解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進行集中管理的地方。它繼承自OpRegistryInterface,因此跟OpRegistry有相似之處。

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;
};

4. 關系圖

graph TB FunctionDefLibrary-.包含.->FunctionDef FunctionDefLibrary-.包含.->GradientDef FunctionDefHelper-.輔助構造.->FunctionDef FunctionCallFrame-.輔助調用.->FunctionDef OpRegistryInterface-->|派生|FunctionLibraryDefinition FunctionLibraryDefinition-.包含.->FunctionDef OpRegistryInterface-->|派生|OpRegistry FunctionLibraryRuntime-.包裹並管理.->FunctionLibraryDefinition

5. 涉及的文件

  • function

6. 迭代記錄

  • v1.0 2018-08-28 文檔創建
  • v2.0 2018-09-10 文檔重構

github地址


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM