色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

TVM學習(八)pass總結

djelje ? 來源:djelje ? 作者:djelje ? 2022-08-02 09:43 ? 次閱讀

什么是pass?

Pass是TVM中基于relay IR進行的優化,目的是去除冗余算子,進行硬件友好的算子轉換,最終能夠提高硬件運行效率。由tensorflow深度學習框架生成的圖機構中,含有很多可以優化的算子,比如expand_dim,len等,其實在編譯階段完全可以優化掉,從而能夠減少硬件的計算,以及避免出現硬件不支持的算子。

TVM中在include/tvm/ir/transform.h中對pass進行了抽象,主要包括PassContext,PassInfo,Pass,以及Sequential。其中PassContext包含了pass執行依賴的一些參數,比如優化level,analysis report等。PassInfo是一個用于記錄pass信息的類,包括pass的opt-level,名稱等。和PassContext的區別是PassContext是pass執行所需要獲取的條件。Pass就是執行pass的主體,主要就是pass的函數。比如RemoveUnusedFunctions就是執行pass的一個主體函數,目的就是去除冗余算子。Sequential是一個container,裝載所有pass。

一些pass

01. RemoveUnusedFunctions

位于src/relay/backend/vm/removed_unused_funcs.cc中,顧名思義就是去除relay IR中的冗余函數。通過從main函數開始遍歷,如果一個函數體沒有引用其它函數,而同時又沒有被其它函數調用,即從relay圖上看是一個孤立算子,那么就從IRModule中刪除。

 void VisitExpr_(const FunctionNode* func_node) final {
    auto func = GetRef(func_node);
    if (visiting_.find(func) == visiting_.end()) {
      visiting_.insert(func);
      for (auto param : func_node->params) {
        ExprVisitor::VisitExpr(param);
      }
      ExprVisitor::VisitExpr(func_node-> body);
    }
  }

02. ToBasicBlockNormalForm

函數在文件src/relay/trnaforms/to_basic_block_normal_from.cc中。通過遍歷IRModule中的每個function,將每個function轉換為基本塊形式。轉換函數是ToBasicBlockNormalFormAux。這個函數包括兩個步驟:一是找到基本塊(basic block)的邊界,TVM中對邊界進行了一步抽象,判斷每個expr是否屬于同一個scope,如果scope相同那么就可以將這些表達式放在一個基本塊中;第二步根據每個表達式所屬的scope將表達式歸屬到一個基本塊中。

Expr ToBasicBlockNormalFormAux(const Expr& e) {
  // calculate all the dependency between nodes.
  support::Arena arena;
  DependencyGraph dg = DependencyGraph::Create(&arena, e);
  /* The scope of the whole expr is global.
   * The scope of any subexpr, is the lowest common ancestor of all incoming edge.
   * We also record the set of expressions whose scope is lifted.
   */
  std::pair scopes = CalcScope(dg);
  return Fill::ToBasicBlockNormalForm(e, dg, &scopes.first, &scopes.second);
}

DependencyGraph是一個表達式相互依賴的圖結構,通過遍歷圖中每個節點,找到每個節點的scope。CalcScope在文件src/relay/transforms/to_a_normal_from.cc中。這個函數中重點關注以下代碼:

…
        s = LCA(s, expr_scope.at(iit->value));
…
    if (n->new_scope) {
      auto child_scope = std::make_shared(s);
      expr_scope.insert({n, child_scope});
    } else {
      expr_scope.insert({n, s});
}

LCA是獲得當前節點的父節點的scope的LCA(least common ancestor),然后將這個scope作為這個節點的scope。了解基本塊原理的都知道,尋找基本塊首先要找到首指令的位置,然后一個首指令到下一個首指令之間的指令就屬于一個基本塊。而首指令就是那些具有條件和無條件跳轉的指令。在TVM中通過new_scope來標記這些節點,比如Ifnode,FunctionNode,LetNode在建立dependency圖的時候,這些節點就被標記為new_scope。這樣就建立了dependency節點到scope節點的對應map。同時scope節點也被建立起樹結構。

接下來就是建立Fill類,這個類中包含了dependency圖以及scope的信息,通過其函數ToBasicBlockNormalForm實現基本塊轉換。它的基本邏輯通過VisitExpr函數遍歷dependency節點,將具有相同scope的節點壓入到同一個let_list中。Let_list文檔中是這樣解釋的:

/*!
 * \file let_list.h
 * \brief LetList record let binding and insert let expression implicitly.
 *  using it, one can treat AST as value instead of expression,
 *  and pass them around freely without fear of AST explosion (or effect duplication).
 *  for example, if one write 'b = a + a; c = b + b; d = c + c', the AST will contain 8 'a'.
 *  if one instead write 'b = ll.Push(a + a); c = ll.Push(b + b); d = ll.Get(c + c);',
 *  the AST will contain 2 'a', as b and c are now variables.

Let_list使得抽象語法樹簡潔化,不會因為變量的復制導致樹的爆炸。具有相同的scope的expr被約束到相同的let_list中,用一個var來表達,這樣就將表達式轉化為var的形式。一個var也就對應了一個基本塊。

03. Legalize

Legalize是實現等價函數的轉換。主要代碼在src/relay/transforms/legalize.cc中。主函數是:

Expr Legalize(const Expr& expr, const std::string& legalize_map_attr_name) {
  auto rewriter = Legalizer(legalize_map_attr_name);
  return PostOrderRewrite(expr, &rewriter);
}

在legalize.cc文件中定義了一個繼承了ExprRewriter的類,在這個類中實現了對function的替換。我們追蹤一下調用的過程。PostOrderRewrite在文件src/relay/ir/expr_functor.cc中。首先建立一個PostOrderRewriter類,然后訪問每個節點。在訪問節點過程中調用了ExpandDataFlow函數,看一下這個函數的描述:

*
 * ExpandDataflow manually manages a stack and performs DFS to determine the processing
 * order of nodes in an input graph.
 *
 * If it finds a dataflow node (Call, Tuple, TupleGetItem), it checks if the arguments to that node
 * need to be processed via fcheck_visited. If so, the function pushes those arguments to the stack
 * and continues iteratively to process the top of the stack. When it finds a node that doesn't
 * match the dataflow types, or a node who's inputs have all been processed, it visits the current
 * leaf via fvisit_leaf.
 *
 * This function should be used internally to other classes to implement mixed-mode traversals. The
 * expectation is that fvisit_leaf will perform recursive analysis within mixed-mode traversal if it
 * hits a non-dataflow node.
 *
 * fcheck_visited and fvisit_leaf are templated to encourage compiler inlining.
 */

主要目的是有區別的去處理graph中的節點,如果fcheck_visited已經確定該節點處理過或者不需要處理,就跳過,通過fvisit_leaf繼續訪問下一個節點。而在VisitLeaf函數中就調用了legalizer類中的rewrite_函數實現了legalize功能。在Rewrite_中,通過映射表legalize_map_attr_name實現函數的等價轉換。

04. SimplifyInference

實現對batch normalization, layer normalization, instance normalization, group normalization, L2 normalization算子的分解,這樣做的目的是可以在之后的優化中,將這些算子融合到其它算子上,減少計算量。代碼在src/relay/transforms/simplify_inference.cc中。文件中定義了一個InferenceSimplifier類來處理這個問題。看一下這幾個normalization的公式:

1 BN:

pYYBAGGYIDKAMYXkAALAFPdMTWI678.png

2 LN:獲得均值和方差是基于同一層不同神經元的數據。歸一化公式相同。

3 GN: 將每個輸入樣本沿著通道進行分組,在每個組內進行歸一化。

4 IN:對每個通道的數據進行歸一化。

來看一下bacth normalization的處理代碼:

Expr BatchNormToInferUnpack(const Attrs attrs, Expr data, Expr gamma, Expr beta, Expr moving_mean,
                            Expr moving_var, Type tdata) {
  auto ttype = tdata.as();
  CHECK(ttype);
  const auto param = attrs.as< BatchNormAttrs>();
  Expr epsilon = MakeConstantScalar(ttype->dtype, static_cast(param->epsilon));
  Expr var_add_eps = Add(moving_var, epsilon);
  Expr sqrt_var = Sqrt(var_add_eps);
  Expr scale = Divide(MakeConstantScalar(ttype->dtype, 1.0f), sqrt_var);


  if (param->scale) {
    scale = Multiply(scale, gamma);
  }
  Expr neg_mean = Negative(moving_mean);
  Expr shift = Multiply(neg_mean, scale);
  if (param->center) {
    shift = Add(shift, beta);
  }


  auto ndim = ttype->shape.size();
  int axis = (param->axis <  0) ? param->axis + ndim : param->axis;
  scale = ExpandBiasToMatchAxis(scale, ndim, {axis});
  shift = ExpandBiasToMatchAxis(shift, ndim, {axis});


  Expr out = Multiply(data, scale);
  out = Add(out, shift);
  return out;
}

可以看到就是將batch norm算子分解成最基本的加減乘除算子。

05. EliminateCommonSubexpr

顧名思義,這個pass的目的是消除公共子表達式。公共子表達式類似這種:

a=b+c

d=b+c

兩個表達式具有相同的op,同時又有相同的args,而且args的順序也一樣。那么就可以用一個表達式替換。

這個pass的實現在文件src/relay/transforms/eliminate_common_subexpr.cc中。TVM定義了類CommonSubexprEliminator來處理。重載函數Rewrite_實現了對expr的遍歷和重寫操作。

 Expr Rewrite_(const CallNode* call, const Expr& post) final {
…
    if (new_call->args.size() == 0 || op == nullptr || op_stateful.get(GetRef< Op>(op), false)) {
      return new_expr;
    }
    if (fskip_ != nullptr && fskip_(new_expr)) {
      return new_expr;
    }


    auto it = expr_map_.find(new_call->op);
    if (it != expr_map_.end()) {
      for (const Expr& candidate_expr : it->second) {
        if (const CallNode* candidate = candidate_expr.as< CallNode>()) {
          bool is_equivalent = true;
          if (!attrs_equal(new_call->attrs, candidate->attrs)) {
            continue;
          }
          for (size_t i = 0; i <  new_call->args.size(); i++) {
            if (!new_call->args[i].same_as(candidate->args[i]) &&
                !IsEqualScalar(new_call->args[i], candidate->args[i])) {
              is_equivalent = false;
              break;
            }
          }
          if (!is_equivalent) continue;
          return GetRef(candidate);
        }
      }
    }
    expr_map_[new_call->op].push_back(new_expr);
    return new_expr;
  }

使用一個expr_map_映射記錄已經遍歷過的具有相同op的expr,之后每次遇到相同的op都會對已經記錄的expr進行匹配,匹配包括attrs以及args,如果二者都一樣的話,證明就是公共子表達式。

沒有看過的pass

以上是實現相對簡單的pass,TVM中還實現了其它很多pass,就沒有一一去讀代碼了。以后看需要再去讀吧。現在做一些羅列:

1 SimplifyExpr

簡化一些表達式,具體如何進行簡化需要讀代碼了。

2 CombineParallelConv2D

合并多分支并行的conv2d運算,理解是對多個batch的conv2d進行合并。

3 CombineParalleleDense

將多個batch的dense操作合并為一個batch_matmul操作。

4 CombineParallelBatchMatmul

對多個并行的batch_mamul再進行合并。

這幾個combine操作可能是針對GPU器件的一個多數據并行性的優化。

5 FoldConstant

典型的一個常量合并優化。

6 FoldScaleAxis

包含了ForwardFoldScaleAxis和backwardFoldScaleAxis,主要是將scale參數合并到conv/dense操作的權重參數中。

7 CanonicalizeCast

官方解釋是: Canonicalize cast expressions to make operator fusion more efficient。理解是對一些cast操作規范化,就是讓復雜的cast操作可以更簡潔。

8 CanonicalizeOps

規范化一些算子,比如bias_add能夠被表示為expand_dims和broadcast_add操作。

審核編輯 黃昊宇

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • 優化
    +關注

    關注

    0

    文章

    220

    瀏覽量

    23945
  • TVM
    TVM
    +關注

    關注

    0

    文章

    19

    瀏覽量

    3683
收藏 人收藏

    評論

    相關推薦

    TVM主要的編譯過程解析

    `  TVM主要的編譯過程如下圖:    Import:將tensorflow,onnx,pytorch等構建的深度學習模型導入,轉化成TVM的中間層表示IR。  Lower:將高層IR表示轉化成
    發表于 01-07 16:59

    TVM整體結構,TVM代碼的基本構成

    圖:    Frontend:這個就是將來自不同深度學習框架中的神經網絡轉化成TVM自己的IR表示。神經網絡模型的輸入是protoBuf文件,比如在tensorflow中就是pbtxt文件,這個文件中
    發表于 01-07 17:21

    TVM中將計算算符有哪幾種

    TVM中將計算算符分成四種
    發表于 01-26 06:34

    TVM的編譯流程

    TVM主要的編譯過程
    發表于 02-23 07:43

    SOPC Builder/Nios 學習經驗總結

    SOPC Builder/Nios 學習經驗總結
    發表于 07-22 15:32 ?0次下載
    SOPC Builder/Nios <b class='flag-5'>學習</b>經驗<b class='flag-5'>總結</b>

    FPGA學習總結[經典推薦]

    單片機(Microcontrollers)學習,FPGA學習總結[經典推薦],感興趣的小伙伴可以瞧一瞧。
    發表于 11-03 15:15 ?155次下載

    ARM寄存器學習總結

    ARM寄存器學習總結
    發表于 01-04 15:10 ?0次下載

    TVM用于移動端常見的ARM GPU,提高移動設備對深度學習的支持能力

    的壓力。 TVM是一個端到端的IR堆棧,它可以解決學習過程中的資源分配問題,從而輕松實現硬件優化。在這篇文章中,我們將展示如何用TVM/NNVM為ARM Mali GPU生成高效kernel
    的頭像 發表于 01-18 13:38 ?1.1w次閱讀

    什么是波場虛擬機TVM

    TVM與現有的開發生態系統無縫連接,并支持 DPoS。 TVM最初與 EVM 環境兼容,因此開發人員可以使用Solidity和其他語言在 Remix 環境中開發,調試和編譯智能合約,而不是學習
    發表于 05-15 09:46 ?3281次閱讀
    什么是波場虛擬機<b class='flag-5'>TVM</b>

    Linux的基礎學習筆記資料總結

    本文檔的主要內容詳細介紹的是Linux的基礎學習筆記資料總結包括了:一、 常用命令,二、 磁盤管理,三、 用戶管理,四、 文件權限,五、 目錄結構,六、 軟件安裝,七、 時間管理,、 啟動引導,九
    發表于 11-13 08:00 ?4次下載

    TVM的編譯流程是什么

    TVM主要的編譯過程如下圖:Import:將tensorflow,onnx,pytorch等構建的深度學習模型導入,轉化成TVM的中間層表示IR。Lower:將高層IR表示轉化成低階TIR表示。Codegen:內存分配和硬件可執
    的頭像 發表于 02-08 14:51 ?1734次閱讀
    <b class='flag-5'>TVM</b>的編譯流程是什么

    TVM學習(三)編譯流程

    TVM主要的編譯過程如下圖:Import:將tensorflow,onnx,pytorch等構建的深度學習模型導入,轉化成TVM的中間層表示IR。Lower:將高層IR表示轉化成低階TIR表示。Codegen:內存分配和硬件可執
    發表于 01-26 09:23 ?13次下載
    <b class='flag-5'>TVM</b><b class='flag-5'>學習</b>(三)編譯流程

    TVM學習(二):算符融合

    算符融合將多個計算單元揉進一個計算核中進行,減少了中間數據的搬移,節省了計算時間。TVM中將計算算符分成四種: 1 injective。一一映射函數,比如加法,點乘等。 2 reduction。輸入
    發表于 02-19 06:50 ?10次下載
    <b class='flag-5'>TVM</b><b class='flag-5'>學習</b>(二):算符融合

    FDTD學習總結.pdf

    FDTD學習總結.pdf
    發表于 01-17 11:28 ?0次下載

    使用TVM在android中進行Mobilenet SSD部署

    所謂TVM,按照正式說法:就是一種將深度學習工作負載部署到硬件的端到端IR(中間表示)堆棧。換一種說法,可以表述為一種把深度學習模型...
    發表于 02-07 12:07 ?0次下載
    使用<b class='flag-5'>TVM</b>在android中進行Mobilenet SSD部署
    主站蜘蛛池模板: 国产学生在线播放精品视频 | 后入式啪gif动态图 后入式狂顶免费视频 | 亚洲黄网站wwwwww | 97国产精品久久精品国产 | 曰韩一本道高清无码av | 杨幂视频1分11未删减在线观看 | 欧美特级特黄a大片免费 | 黄色一级毛片免费 | 啊轻点啊再深点视频免费 | 99在线免费观看 | 菠萝菠萝蜜免费播放高清 | 在线观看成人免费视频 | 国产精品久久久久久亚洲影视 | 亚洲中文热码在线视频 | 蜜桃久久久亚洲精品成人 | 国产三级级在线电影 | 男人网站在线观看 | 美国大臿蕉香蕉大视频 | 人善交XUANWEN200喷水 | 亚洲深夜在线 | 精品国产手机视频在在线 | 东京热百度影音 | 一级毛片两人添下面 | 女人高潮特级毛片 | 俄罗斯女人Z0ZOZO | 入禽太深视频免费视频 | 在线看片韩国免费人成视频 | 精品国产乱码久久久久乱码 | 人妻超级精品碰碰在线97视频 | yy8090理论三级在线看 | 91chinesevideo| 精品久久久久中文字幕日本 | 一道精品视频一区二区 | 在线不卡日本v二区 | 国产伦精品一区二区三区 | 国精产品一区一区三区有限 | 日本熟妇乱妇熟色A片蜜桃亚洲 | 色戒床震视频片段 | 变形金刚7免费观看完整 | 波多野结衣网站www 波多野结衣教师系列6 | 欧美日韩北条麻妃一区二区 |