《Relay IR的基石:expr.h 中的表達式類型系統剖析》

TVM Relay源碼深度解讀

文章目錄

  • TVM Relay源碼深度解讀
  • 一 、從Constant看Relay表達式的設計哲學
    • 1. 類定義概述
    • 2. `ConstantNode` 詳解
      • 1. 核心成員
      • 2. 關鍵方法
      • 3. 類型系統注冊
    • 3. `Constant` 詳解
      • 1. 核心功能
  • 二. 核心內容概述
    • (1) Relay表達式基類
      • 1. RelayExprNode 和 RelayExpr 的區別與用法
      • 2. 主要區別
      • 3. 使用模式
        • 例子1:常量表達式
        • 例子2:變量表達式
        • 例子3:函數應用
      • 4. 實際使用建議
    • (2) 具體表達式類型
      • 1. 表達式類型 VarNode舉例子
        • 1. 核心設計理念
        • 2. 關鍵成員解析
          • (1) 核心字段
          • (2) 特殊方法
        • 3. 變量標識系統
          • (1) vid (Unique ID)
          • (2) name_hint 與 vid 的關系
        • 4. 類型系統整合
          • (1) 類型注解流程
          • (2) 類型推導規則
        • 5. 內存模型與跨語言交互
          • (1) C++ 層構造
          • (2) Python 綁定
          • **(3) 對象生命周期**
        • 6. 關鍵應用場景
          • (1) 函數參數定義
          • (2) 優化 Pass 中的變量處理
          • (3) 類型檢查
        • 7. 設計亮點總結
        • 8. 典型問題分析
    • (3) TVM_DECLARE_BASE_OBJECT_INFO 宏詳解
      • 1. 宏的參數
      • 2. 靜態斷言檢查(防止非法繼承)
      • 2. 運行時類型索引(RuntimeTypeIndex)
      • 3. 動態分配類型索引(_GetOrAllocRuntimeTypeIndex)
      • 通俗版解釋:TVM的類型身份證系統
        • 1. 為什么要辦身份證?
        • 2. 辦證過程(宏的作用)
        • 3. 特殊班級(FINAL版)
        • 4. 實際有什么用?
        • 舉個栗子🌰
        • 一句話總結
      • (4) 遍歷接口
        • 1. C++ 場景示例
          • (1) 模型序列化(保存為JSON)
          • (2) 優化Pass中的常量修改
          • (3) 調試打印
        • 2. Python 場景示例
          • (1) 直接屬性訪問
          • (2) 模型保存與加載
          • (3) 自定義屬性訪問器


一 、從Constant看Relay表達式的設計哲學

??在TVM的Relay IR中,即使是看似簡單的常量表達式relay.const(1),其背后也隱藏著整個類型系統的精妙設計。讓我們從include/tvm/relay/expr.h中的Constant類入手,逐步拆解…"

1. 類定義概述

類名繼承關系角色關鍵特性
ConstantNodepublic ExprNode常量表達式的實際數據存儲包含常量數據(NDArray)、類型信息,并實現屬性訪問、哈希和相等比較邏輯。
Constantpublic RelayExpr常量表達式的智能指針封裝提供用戶友好的構造函數和訪問方法,隱藏內存管理細節。

2. ConstantNode 詳解

class ConstantNode : public ExprNode {public:/*! \brief The data of the tensor */runtime::NDArray data;/*! \return The corresponding tensor type of the data */TensorType tensor_type() const;/*! \return Whether it is scalar(rank-0 tensor) */bool is_scalar() const { return data->ndim == 0; }void VisitAttrs(tvm::AttrVisitor* v) {v->Visit("data", &data);v->Visit("span", &span);v->Visit("mdata", &mdata);v->Visit("_checked_type_", &checked_type_);}bool SEqualReduce(const ConstantNode* other, SEqualReducer equal) const {return equal(data, other->data);}void SHashReduce(SHashReducer hash_reduce) const { hash_reduce(data); }static constexpr const char* _type_key = "relay.Constant";TVM_DECLARE_FINAL_OBJECT_INFO(ConstantNode, ExprNode);
};

1. 核心成員

  • data (runtime::NDArray)

    • 存儲常量張量的實際數據(如權重、偏置等),TVM 使用 NDArray 統一表示多維數組。
    • 示例:卷積層的權重矩陣會被存儲在這里。
  • tensor_type()

    • 根據 data 的維度(shape)和數據類型(dtype)自動生成對應的 TensorType
    • 用途:類型推斷時確定常量的類型。
  • is_scalar()

    • 判斷常量是否為標量(0維張量),如 data->ndim == 0

2. 關鍵方法

  • VisitAttrs

    • 實現屬性的序列化/反序列化,支持以下字段:
      v->Visit("data", &data);          // 張量數據
      v->Visit("span", &span);         // 源碼位置信息
      v->Visit("mdata", &mdata);       // 元數據(如調試信息)
      v->Visit("_checked_type_", &checked_type_);  // 類型檢查后的類型
      
  • SEqualReduceSHashReduce

    • 結構化相等比較:比較兩個 ConstantNodedata 是否相同(用于優化中的常量折疊)。
    • 哈希計算:基于 data 生成哈希值(用于快速查找重復常量)。

3. 類型系統注冊

TVM_DECLARE_FINAL_OBJECT_INFO(ConstantNode, ExprNode);
  • _type_key = "relay.Constant":唯一標識常量節點類型。
  • FINAL:禁止繼承,確保常量節點的行為不可被修改。

3. Constant 詳解

class Constant : public Expr {public:/*!* \brief The constructor* \param data The data of the constant tensor.* \param span The source span of the expression.*/TVM_DLL explicit Constant(runtime::NDArray data, Span span = Span(), MetaData mdata = MetaData());TVM_DEFINE_OBJECT_REF_METHODS(Constant, RelayExpr, ConstantNode);
};

1. 核心功能

  • 構造函數

    explicit Constant(runtime::NDArray data, Span span = Span(), MetaData mdata = MetaData());
    
    • 接收 NDArray 數據,構造一個常量表達式。
    • 示例
      # Python 前端等價代碼
      data = np.array([1, 2, 3], dtype="float32")
      const_expr = relay.Constant(tvm.nd.array(data))
      
  • 智能指針方法

    TVM_DEFINE_OBJECT_REF_METHODS(Constant, RelayExpr, ConstantNode);
    

    展開后提供:

    • operator->():直接訪問 ConstantNode 成員(如 const_expr->data)。
    • get():獲取底層 ConstantNode 指針。
    • 自動內存管理(通過 ObjectRef 的引用計數)。

二. 核心內容概述

??在TVM源碼中,include/tvm/relay/expr.hRelay IR(中間表示)的核心頭文件,定義了所有Relay表達式的基礎數據結構和類型系統。它是實現TVM高層計算圖表示的關鍵組成部分。以下是該文件的詳細解析:
相關重要文件

文件路徑關聯內容
include/tvm/relay/type.h類型系統(TensorType等)
include/tvm/relay/op.h運算符定義
include/tvm/relay/adt.h代數數據類型支持
src/relay/ir/expr.cc表達式方法的實現

include/tvm/relay/expr.h文件主要包含:

  • (1) Relay表達式基類RelayExpr/RelayExprNode
  • (2) 所有具體表達式類型的聲明(如變量、常量、函數調用等)
  • (3) 表達式類型的遍歷和轉換接口
  • (4) 類型系統和屬性訪問的支持

(1) Relay表達式基類

class RelayExprNode : public BaseExprNode { /*...*/ };
class RelayExpr : public BaseExpr { /*...*/ };
  • 角色:所有Relay表達式的公共基類
  • 功能
    • 提供類型系統支持(通過checked_type_字段)
    • 實現屬性訪問(VisitAttrs
    • 支持結構化相等比較(SEqualReduce

1. RelayExprNode 和 RelayExpr 的區別與用法

??RelayExprNode 是 Relay 表達式的實際實現類,是一個 C++ 類,包含了表達式的所有數據和功能實現。它是所有 Relay 表達式類型的基類。
??RelayExpr 是一個智能指針(relay::Expr),它指向 RelayExprNode 或其子類的實例。它提供了對 RelayExprNode 的安全訪問和管理。

2. 主要區別

特性RelayExprNodeRelayExpr
類型C++ 類智能指針(std::shared_ptr 的封裝)
生命周期管理需要手動管理自動管理
使用方式通常不直接使用,作為實現細節用戶主要交互的接口
繼承關系作為基類定義表達式結構作為訪問接口

3. 使用模式

在 TVM 中,通常的模式是:

  1. 定義一個繼承自 RelayExprNode 的具體表達式節點類
  2. 使用 RelayExpr 作為這些節點的引用
例子1:常量表達式
// 創建一個常量表達式
auto const_node = relay::ConstantNode::make(tvm::runtime::NDArray::Zeros(...));
RelayExpr const_expr = const_node;// 通常更簡潔的寫法
RelayExpr const_expr = relay::Constant(tvm::runtime::NDArray::Zeros(...));
例子2:變量表達式
// 創建一個變量表達式
auto var_node = relay::VarNode::make("x", relay::Type());
RelayExpr var_expr = var_node;// 或者更簡潔地
RelayExpr var_expr = relay::Var("x", relay::Type());
例子3:函數應用
// 創建函數應用表達式
RelayExpr func = ...; // 某個函數
RelayExpr arg = ...;  // 某個參數
auto call_node = relay::CallNode::make(func, {arg});
RelayExpr call_expr = call_node;// 或者
RelayExpr call_expr = relay::Call(func, {arg});

4. 實際使用建議

  1. 用戶代碼:在大多數情況下,你應該使用 RelayExpr 而不是直接操作 RelayExprNode

  2. 擴展 Relay:如果你想定義新的表達式類型,需要繼承 RelayExprNode 并實現相應接口。

  3. 類型轉換:可以使用 as<T> 方法將 RelayExpr 向下轉換為特定類型的節點指針:

RelayExpr expr = ...;
if (const auto* call = expr.as<CallNode>()) {// 現在可以訪問 CallNode 的特定成員call->op;call->args;
}
  1. 創建新表達式:TVM 提供了輔助函數來創建表達式,通常以節點類型名去掉 “Node” 命名(如 relay::Var() 創建 VarNodeRelayExpr)。

這種分離設計使得 Relay IR 既靈活又安全,同時保持了良好的性能特性

(2) 具體表達式類型

表達式類型說明關鍵成員/方法
VarNode變量(輸入/中間結果)String name_hint, Type type_annotation, Id vid
ConstantNode常量張量(如模型權重)runtime::NDArray data, tensor_type(), is_scalar()
CallNode函數/運算符調用Expr op, Array<Expr> args, Attrs attrs, Array<Type> type_args
LetNodeLet綁定(實現變量作用域)Var var, Expr value, Expr body
TupleNode元組結構(多返回值)Array<Expr> fields
TupleGetItemNode從元組中獲取元素Expr tuple, int index
IfNode條件表達式Expr cond, Expr true_branch, Expr false_branch
OpNode基本運算符(如add/concat)通過Op::Get("op_name")獲取
FunctionNode函數定義(在function.h中聲明,但屬于表達式)Array<Var> params, Expr body, Type ret_type, Array<TypeVar> type_params
RefCreateNode創建可變引用(用于狀態更新)Expr value
RefReadNode讀取引用值Expr ref
RefWriteNode更新引用值Expr ref, Expr value
ConstructorNode代數數據類型(ADT)的構造器(在adt.h中聲明)String tag, Array<Type> inputs
MatchNode模式匹配(ADT處理)Expr data, Array<Clause> clauses
TempExprNode臨時表達式(用于優化過程中的中間表示)通常作為優化Pass的中間載體
GlobalVarNode全局函數引用(跨模塊調用)String name_hint
SeqExprNode順序執行多個表達式(類似語句塊)Array<Binding> bindings, Expr body

1. 表達式類型 VarNode舉例子

include/tvm/relay/expr.h

class Var;
/*! \brief Container for Var */
class VarNode : public ExprNode {public:/*!* \brief The unique identifier of the Var.** vid will be preserved for the same Var during type inference* and other rewritings, while the VarNode might be recreated* to attach additional information.* This property can be used to keep track of parameter Var* information across passes.*/Id vid;/*!* \brief type annotaion of the variable.* This field records user provided type annotation of the Var.* This field is optional and can be None.*/Type type_annotation;/*! \return The name hint of the variable */const String& name_hint() const { return vid->name_hint; }void VisitAttrs(tvm::AttrVisitor* v) {v->Visit("vid", &vid);v->Visit("type_annotation", &type_annotation);v->Visit("span", &span);v->Visit("mdata", &mdata);v->Visit("_checked_type_", &checked_type_);}bool SEqualReduce(const VarNode* other, SEqualReducer equal) const {return equal(type_annotation, other->type_annotation) && equal.FreeVarEqualImpl(this, other);}void SHashReduce(SHashReducer hash_reduce) const {hash_reduce(type_annotation);hash_reduce.FreeVarHashImpl(this);}static constexpr const char* _type_key = "relay.Var";TVM_DECLARE_FINAL_OBJECT_INFO(VarNode, ExprNode);
};class Var : public Expr {public:/*!* \brief The constructor* \param name_hint The name hint of a variable.* \param type_annotation The type annotation of a variable.* \param span The source span of the expression.*/TVM_DLL Var(String name_hint, Type type_annotation, Span span = Span(), MetaData mdata = MetaData()): Var(Id(name_hint), type_annotation, span, mdata) {}/*!* \brief The constructor* \param vid The unique id of a variable.* \param type_annotation The type annotation of a variable.* \param span The source span of the expression.*/TVM_DLL Var(Id vid, Type type_annotation, Span span = Span(), MetaData mdata = MetaData());TVM_DEFINE_OBJECT_REF_METHODS(Var, RelayExpr, VarNode);
};
1. 核心設計理念

VarNodeVar 共同實現了 Relay IR 的變量系統,采用 TVM 標準的 Object-ObjectRef 設計模式

  • VarNode:存儲實際數據的節點類(繼承自 ExprNode
  • Var:管理 VarNode智能指針包裝類(繼承自 Expr

2. 關鍵成員解析
(1) 核心字段
成員類型作用
vidId唯一標識符,跨 Pass 保持不變(即使節點被重建)
type_annotationType用戶顯式指定的類型注解(可空)
name_hint()String通過 vid->name_hint 獲取的可讀名稱(非唯一)
spanSpan源碼位置信息(用于錯誤定位)
mdataMetaData擴展元數據
(2) 特殊方法
方法功能
SEqualReduce結構化相等比較(用于優化 Pass 的重復檢測)
SHashReduce哈希計算(支持快速查找)
VisitAttrs屬性序列化/反序列化

3. 變量標識系統
(1) vid (Unique ID)
class IdNode : public Object {public:String name_hint;// ... 其他元數據
};
  • 核心特性
    • 通過 Id(name_hint) 構造,但系統會保證其唯一性
    • 即使優化 Pass 重建變量節點,vid 保持不變
    • 用于跨 Pass 跟蹤參數變量(如梯度更新時識別同一參數)
(2) name_hint 與 vid 的關系
x = relay.var("input", shape=(1,3))  # 實際創建:# vid = Id("input_0x7f") (自動去重)# name_hint = "input" (用戶友好)

4. 類型系統整合
(1) 類型注解流程
graph TDA[用戶構造] -->|relay.var(..., dtype="float32")| B(type_annotation)B --> C[類型檢查]C -->|更新| D(_checked_type_)
(2) 類型推導規則
  • type_annotation 存在:必須與實際使用類型兼容
  • 若為空:從上下文推斷類型

5. 內存模型與跨語言交互
(1) C++ 層構造
// 方式1:通過 name_hint
Var x("data", TensorType({1,3}, DataType::Float(32)));// 方式2:直接指定 Id
Var x(Id("data_0x7f"), TensorType({1,3}, DataType::Float(32)));
(2) Python 綁定
# Python 前端接口
x = relay.var(name="input",shape=(1,3),dtype="float32",span=SourceSpan(...)
)
(3) 對象生命周期
sequenceDiagramPython->>C++: relay.var() 創建請求C++->>Heap: 分配 VarNodeC++->>Python: 返回 Var(ObjectRef)Python->>C++: 析構時觸發引用計數-1

6. 關鍵應用場景
(1) 函數參數定義
def build_linear():x = relay.var("x", shape=(1,3))w = relay.var("w", shape=(3,2))b = relay.var("b", shape=(2,))y = relay.add(relay.matmul(x, w), b)return relay.Function([x, w, b], y)
(2) 優化 Pass 中的變量處理
// 在 ConstantFolding 中識別變量引用
if (const VarNode* var = expr.as<VarNode>()) {if (var_map.count(var->vid)) {// 替換為已知常量}
}
(3) 類型檢查
// 檢查變量類型是否匹配
bool CheckType(const VarNode* var, const Type& expected) {return var->checked_type().as<TensorType>()->dtype == expected;
}

7. 設計亮點總結
  1. 穩定性vid 保證變量在優化過程中的持久標識
  2. 靈活性type_annotation 支持顯式/隱式類型指定
  3. 安全性TVM_DECLARE_FINAL_OBJECT_INFO 防止錯誤繼承
  4. 可調試性spanname_hint 增強錯誤可讀性
  5. 性能SEqualReduce/SHashReduce 優化圖操作效率

8. 典型問題分析

Q: 為什么需要同時存在 vidname_hint
A: 分工不同:

  • name_hint:面向用戶,提供可讀性(允許重復)
  • vid:面向系統,保證唯一性和跨Pass一致性

Q: 何時會重建 VarNode
A: 典型場景:

  • 類型推斷后附加 _checked_type_
  • 優化 Pass 中克隆表達式時保留原 vid 但新建節點

(3) TVM_DECLARE_BASE_OBJECT_INFO 宏詳解

??這個宏是 TVM 類型系統的核心,用于在 C++ 中動態注冊和管理對象的類型信息。它的核心作用是: 為每個類自動生成類型注冊代碼,使其能被 TVM 運行時識別和操作


1. 宏的參數

#define TVM_DECLARE_BASE_OBJECT_INFO(TypeName, ParentType)
  • TypeName:當前類名(如 ConstantNode
  • ParentType:父類名(如 ExprNode

2. 靜態斷言檢查(防止非法繼承)

static_assert(!ParentType::_type_final, "ParentObj marked as final");
  • 作用:如果父類被標記為 final(通過 _type_final),則禁止子類繼承。

2. 運行時類型索引(RuntimeTypeIndex)

static uint32_t RuntimeTypeIndex() {// 檢查子類槽位配置是否合法static_assert(TypeName::_type_child_slots == 0 || ParentType::_type_child_slots == 0 ||TypeName::_type_child_slots < ParentType::_type_child_slots,"子類槽位數不能超過父類限制");// 如果已預分配類型ID,直接返回if (TypeName::_type_index != ::tvm::runtime::TypeIndex::kDynamic) {return TypeName::_type_index;}// 否則動態分配return _GetOrAllocRuntimeTypeIndex();
}
  • 功能:返回類的唯一類型 ID(uint32_t)。
  • 優化:優先使用預分配的 _type_index(性能更高),否則動態分配。

3. 動態分配類型索引(_GetOrAllocRuntimeTypeIndex)

static uint32_t _GetOrAllocRuntimeTypeIndex() {static uint32_t tidx = Object::GetOrAllocRuntimeTypeIndex(TypeName::_type_key,         // 類型名稱字符串(如 "relay.Constant")TypeName::_type_index,       // 預分配的類型IDParentType::RuntimeTypeIndex(), // 父類類型IDTypeName::_type_child_slots, // 為子類預留的槽位數TypeName::_type_child_slots_can_overflow // 是否允許超額);return tidx;
}
  • 作用:向 TVM 運行時注冊類型,并分配唯一 ID。
  • 關鍵參數
    • _type_child_slots:限制子類數量(防止類型爆炸)。
    • _type_child_slots_can_overflow:為 true 時允許突破限制。

通俗版解釋:TVM的類型身份證系統

你可以把TVM的類型系統想象成一個學校的學生管理系統,而TVM_DECLARE_BASE_OBJECT_INFO就是給學生(類)辦身份證的機器:


1. 為什么要辦身份證?
  • 每個學生(類)需要唯一學號(類型ID)
  • 需要知道他的班主任是誰(父類)
  • 防止有人冒充轉校生(非法繼承)
2. 辦證過程(宏的作用)
// 給"小明同學"辦證,班主任是"李老師"
TVM_DECLARE_BASE_OBJECT_INFO(小明, 李老師)

這個宏會自動做三件事:

  1. 檢查家世清白

    static_assert(!李老師::是final班, "班主任明確不收新學生!");
    
    • 如果班主任聲明"我們班不接收轉學生",就報錯
  2. 分配學號

    • 優先用預留的VIP學號(_type_index
    • 沒有就現場搖號(_GetOrAllocRuntimeTypeIndex
  3. 登記親屬關系

    學號 = 教務處.登記(姓名:"小明",班主任:李老師.學號,可帶小弟人數:3  // _type_child_slots
    );
    
3. 特殊班級(FINAL版)
TVM_DECLARE_FINAL_OBJECT_INFO(學霸班, 實驗班)
  • 相當于在班級門口掛**“禁止轉入”**牌子
  • 其他班同學想轉學過來會直接報錯
4. 實際有什么用?
  • 查身份證快obj->IsInstance<小明>() 比查戶口本快
  • 安全轉班obj.as<小明>() 能安全轉換類型
  • 防止冒名頂替:禁止隨便認爹(錯誤繼承)

舉個栗子🌰
# Python前端定義一個"漢堡店"類
@register_relay_node("food.HamburgerShop")
class HamburgerShopNode(ExprNode):_type_key = "food.HamburgerShop"_type_child_slots = 2  # 允許開2家分店

C++層通過這個宏:

  1. 給漢堡店分配類型ID(比如9527)
  2. 記錄它的父類是ExprNode
  3. 允許最多2個子類(比如CheeseBurgerShopChickenBurgerShop

一句話總結

這個宏就是TVM給類發身份證+建家族檔案的工具,讓系統能:

  • ? 快速識別"你是誰"(類型檢查)
  • ? 知道"你爸是誰"(繼承關系)
  • ? 防止"亂認親戚"(非法繼承)

(4) 遍歷接口

  void VisitAttrs(tvm::AttrVisitor* v) {v->Visit("data", &data);v->Visit("span", &span);v->Visit("mdata", &mdata);v->Visit("_checked_type_", &checked_type_);}

??VisitAttrs 是 TVM 中用于統一序列化、反序列化和屬性訪問的核心接口。以下是 ConstantNode 使用該函數的具體示例,涵蓋 C++ 和 Python 場景:


1. C++ 場景示例
(1) 模型序列化(保存為JSON)
// 創建常量節點
runtime::NDArray arr = runtime::NDArray::Empty({2, 2}, DLDataType{kDLFloat, 32, 1}, DLContext{kDLCPU, 0});
ConstantNode* const_node = new ConstantNode();
const_node->data = arr;// 序列化為JSON
JSONAttrVisitor visitor;
const_node->VisitAttrs(&visitor);  // 觸發以下調用:// visitor.Visit("data", &data)// visitor.Visit("span", &span)...
std::string json = visitor.GetJSON();

輸出JSON片段

{"type_key": "relay.Constant","data": {"b64": "AABAA...", "dtype": "float32", "shape": [2, 2]},"span": null,"_checked_type_": "TensorType([2,2], float32)"
}
(2) 優化Pass中的常量修改
class ConstantMutator : public AttrMutator {public:void VisitAttrs(AttrVisitor* v) override {if (v->IsMutator()) {  // 檢查是否為修改模式runtime::NDArray new_data = ...; // 生成新數據v->Visit("data", &new_data);    // 修改data字段}}
};// 調用示例:
ConstantMutator mutator;
const_node->VisitAttrs(&mutator);  // 修改常量數據
(3) 調試打印
class DebugPrinter : public AttrVisitor {public:void Visit(const char* key, runtime::NDArray* data) override {std::cout << key << ": shape=" << data.Shape();}
};DebugPrinter printer;
const_node->VisitAttrs(&printer);  // 輸出:data: shape=[2,2]

2. Python 場景示例
(1) 直接屬性訪問
import tvm
from tvm import relay# 創建常量
data = tvm.nd.array(np.zeros((2,2), dtype="float32"))
const = relay.Constant(data)# Python屬性訪問(背后調用VisitAttrs)
print(const.data)      # 訪問NDArray → 觸發Visit("data", &data)
print(const.span)      # 訪問源碼位置 → Visit("span", &span)

輸出

<tvm.nd.NDArray shape=(2, 2), dtype=float32>
None  # 未設置span時的默認值
(2) 模型保存與加載
# 保存模型(觸發序列化)
mod = tvm.IRModule.from_expr(const)
mod.save("const.json")  # 內部調用VisitAttrs# 加載模型(觸發反序列化)
loaded_mod = tvm.ir.load_json("const.json")
loaded_const = loaded_mod["main"].body
assert isinstance(loaded_const, relay.Constant)
(3) 自定義屬性訪問器
class MyVisitor(tvm.ir.AttrVisitor):def visit(self, name, value):print(f"Attribute {name} has type {type(value)}")visitor = MyVisitor()
const.visit_attrs(visitor)  # 顯式調用VisitAttrs

輸出

Attribute data has type <class 'tvm.runtime.ndarray.NDArray'>
Attribute span has type <class 'tvm.ir.Span'>
...

class Constant;
/*!* \brief Constant tensor type.*/
class ConstantNode : public ExprNode {public:/*! \brief The data of the tensor */runtime::NDArray data;/*! \return The corresponding tensor type of the data */TensorType tensor_type() const;/*! \return Whether it is scalar(rank-0 tensor) */bool is_scalar() const { return data->ndim == 0; }void VisitAttrs(tvm::AttrVisitor* v) {v->Visit("data", &data);v->Visit("span", &span);v->Visit("mdata", &mdata);v->Visit("_checked_type_", &checked_type_);}bool SEqualReduce(const ConstantNode* other, SEqualReducer equal) const {return equal(data, other->data);}void SHashReduce(SHashReducer hash_reduce) const { hash_reduce(data); }static constexpr const char* _type_key = "relay.Constant";TVM_DECLARE_FINAL_OBJECT_INFO(ConstantNode, ExprNode);
};class Constant : public Expr {public:/*!* \brief The constructor* \param data The data of the constant tensor.* \param span The source span of the expression.*/TVM_DLL explicit Constant(runtime::NDArray data, Span span = Span(), MetaData mdata = MetaData());TVM_DEFINE_OBJECT_REF_METHODS(Constant, RelayExpr, ConstantNode);
};

以下是關于 ConstantNodeConstant 類的詳細解釋與概括,結合它們在 TVM Relay IR 中的作用和實現設計:



本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/77780.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/77780.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/77780.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

自動駕駛地圖數據傳輸協議ADASIS v2

ADASIS&#xff08;Advanced Driver Assistance Systems Interface Specification&#xff09;直譯過來就是 ADAS 接口規格&#xff0c;它要負責的東西其實很簡單&#xff0c;就是為自動駕駛車輛提供前方道路交通相關的數據&#xff0c;這些數據被抽象成一個標準化的概念&#…

Flutter 狀態管理 Riverpod

Android Studio版本 Flutter SDK 版本 將依賴項添加到您的應用 flutter pub add flutter_riverpod flutter pub add riverpod_annotation flutter pub add dev:riverpod_generator flutter pub add dev:build_runner flutter pub add dev:custom_lint flutter pub add dev:riv…

【EasyPan】MySQL主鍵與索引核心作用解析

【EasyPan】項目常見問題解答&#xff08;自用&持續更新中…&#xff09;匯總版 MySQL主鍵與索引核心作用解析 一、主鍵&#xff08;PRIMARY KEY&#xff09;核心作用 1. 數據唯一標識 -- 創建表時定義主鍵 CREATE TABLE users (id INT AUTO_INCREMENT PRIMARY KEY,use…

IcePlayer音樂播放器項目分析及學習指南

IcePlayer音樂播放器項目分析及學習指南 項目概述 IcePlayer是一個基于Qt5框架開發的音樂播放器應用程序&#xff0c;使用Visual Studio 2013作為開發環境。該項目實現了音樂播放、歌詞顯示、專輯圖片獲取等功能&#xff0c;展現了桌面應用程序開發的核心技術和設計思想。 技…

vscode 打開新頁簽

目錄 vscode 打開新頁簽 完整settings.json內容&#xff1a; vscode 打開新頁簽 .vscode目錄中 新建settings.json 在 settings.json 文件中&#xff0c;添加或修改以下行&#xff1a; json "workbench.editor.enablePreview": false 這將禁用預覽模式&#xff0…

C語言高頻面試題——常量指針與指針常量區別

1. 常量指針&#xff08;Pointer to Constant&#xff09; 定義&#xff1a; 常量指針是指向一個常量數據的指針&#xff0c;即指針指向的內容不能通過該指針被修改。 語法&#xff1a; const int* ptr;或者&#xff1a; int const* ptr;解釋&#xff1a; const修飾的是指…

c++基礎·列表初始化

目錄 一、列表初始化的核心優勢 二、基礎數據類型與數組初始化 1. 基礎類型初始化 2. 數組初始化 三、類與結構體初始化 1. 構造函數匹配規則 2. 注意事項 四、標準容器初始化 五、聚合類型&#xff08;Aggregate Types&#xff09;初始化 1. 聚合類型定義 2. 初始化…

數據分析與產品、運營、市場之間如何有效對齊

數據分析的重要性在于它能夠將海量的原始信息轉化為可操作的洞察。以產品開發為例,通過用戶行為數據的分析,產品經理可以清晰了解哪些功能被頻繁使用,哪些設計導致用戶流失,從而優化迭代方向。運營團隊則依靠數據分析來監控供應鏈效率、預測需求波動,甚至通過實時數據調整…

[C]基礎11.深入理解指針(3)

博客主頁&#xff1a;向不悔本篇專欄&#xff1a;[C]您的支持&#xff0c;是我的創作動力。 文章目錄 0、總結1、字符指針變量2、數組指針變量2.1 數組指針變量是什么&#xff1f;2.2 數組指針變量怎么初始化&#xff1f; 3、二維數組傳參的本質4、函數指針變量4.1 函數指針變量…

【漏洞復現】CVE-2024-38856(ApacheOfbiz RCE)

【漏洞復現】CVE-2024-38856&#xff08;ApacheOfbiz RCE&#xff09; 1. 漏洞描述 Apache OFBiz 是一個開源的企業資源規劃&#xff08;ERP&#xff09;系統。它提供了一套企業應用程序&#xff0c;用于集成和自動化企業的許多業務流程。 這個漏洞是由于對 CVE-2023-51467 的…

C++入門小館: 深入string類(二)

嘿&#xff0c;各位技術潮人&#xff01;好久不見甚是想念。生活就像一場奇妙冒險&#xff0c;而編程就是那把超酷的萬能鑰匙。此刻&#xff0c;陽光灑在鍵盤上&#xff0c;靈感在指尖跳躍&#xff0c;讓我們拋開一切束縛&#xff0c;給平淡日子加點料&#xff0c;注入滿滿的pa…

【nginx】服務的信號控制

目錄 1. 說明2. 常用信號及作用3. 信號控制的具體操作3.1 獲取 Nginx 主進程 PID3.2 發送信號 4. 應用場景4.1 重新加載配置文件4.2 日志切割 5. 平滑升級 Nginx6. 注意事項 1. 說明 1.Nginx 的信號控制是其管理服務的重要機制&#xff0c;通過向主進程發送特定信號&#xff0…

Ubuntu下展銳刷機工具spd_dump使用說明

spd_dump使用說明 源碼地址&#xff1a;https://github.com/ilyakurdyukov/spreadtrum_flash 編譯環境準備&#xff1a; sudo apt update sudo apt install git sudo apt install build-essential sudo apt install libusb-1.0-0-devIf you create /etc/udev/rules.d/80-spd…

鴻蒙NEXT開發LRUCache緩存工具類(單例模式)(ArkTs)

import { util } from kit.ArkTS;/*** LRUCache緩存工具類&#xff08;單例模式&#xff09;* author 鴻蒙布道師* since 2025/04/21*/ export class LRUCacheUtil {private static instance: LRUCacheUtil;private lruCache: util.LRUCache<string, any>;/*** 私有構造函…

筆記:react中 父組件怎么獲取子組件中的屬性或方法

在子組件中我們可以使用下面兩個方法去暴露你所要放行的屬性或方法&#x1f447; 1.useImperativeHandle 2.orwardRef 搭配使用例子 import React, { useState, forwardRef, useImperativeHandle } from "react"function Son(props, ref) {const [data] useStat…

《潯川代碼編輯器v2.0內測(完整)報告》

一、測試概述 潯川代碼編輯器v2.0經過為期五周的封閉內測&#xff0c;累計提交了186份測試報告。本次內測主要針對v2.0新增的多語言支持、AI輔助編碼、性能優化等核心功能進行全面驗證。 二、測試環境 - 硬件配置&#xff1a;i7-12700H/16GB RAM/512GB SSD - 操作系統&#xf…

ubuntu18.04安裝QT問題匯總

1、Could not determine which ”make“ command to run. Check the ”make“ step in the build configuration.” sudo apt-get install clang sudo apt-get install build-essential sudo apt-get install libqt4-dev 2、fatal error: sqlite3.h: No such …

基于單片機的BMS熱管理功能設計

標題:基于單片機的BMS熱管理功能設計 內容:1.摘要 摘要&#xff1a;在電動汽車和儲能系統中&#xff0c;電池管理系統&#xff08;BMS&#xff09;的熱管理功能至關重要&#xff0c;它直接影響電池的性能、壽命和安全性。本文的目的是設計一種基于單片機的BMS熱管理功能。采用…

CSS基礎-即學即用 -- 筆記1

目錄 前言CSS 基礎1. 層疊樣式表來源理解優先級源碼順序經驗法則繼承inherit 關鍵字initial 關鍵字 2. 相對單位em 和 rem響應式面板視口的相對單位使用vw定義字號使用calc()定義字號自定義屬性&#xff08;即CSS變量&#xff09; 3. 盒模型調整盒模型 前言 只需一分鐘就能學會…

Linux中服務器時間同步

簡單介紹 在 redhat 8 之前&#xff0c;時間同步服務是使用 NTP&#xff08;網絡時間協議&#xff09;來實現的&#xff0c;在 redhat 8 及之 后使用是 NTP 的實現工具 chrony 來實現時間同步。 在 redhat 8 及之后&#xff0c;默認情況下已經安裝好 chrony 軟件并已經開機啟…