从TVM的官方Tutorial里面,介绍了如何新增自定义算子。(这是我翻译的)

之前的文章讲到了onnx 算子转换到Relay IR的过程

下面以Conv2d算子介绍,编译过程中 Relay IR是如何被调用的。

relay 算子调用

上面的get_relay_op实际上是查找所有 relay ir算子,其代码在python/tvm/relay/frontend/common.py中的get_relay_op。继续以conv卷积算子为例介绍。上文所述的转换算子中,有下面的语句

for candidate in (_op, _op.nn, _op.image, _op.vision, _op.contrib):
op = getattr(candidate, op_name, None)
if op is not None:
break

对于conv2d算子,在_op.nn中,找到conv2d实现。

def conv2d(
data,
weight,
strides=(1, 1),
padding=(0, 0),
dilation=(1, 1),
groups=1,
channels=None,
kernel_size=None,
data_layout="NCHW",
kernel_layout="OIHW",
out_layout="",
out_dtype="",
):
if isinstance(kernel_size, int):
kernel_size = (kernel_size, kernel_size)
if isinstance(strides, int):
strides = (strides, strides)
if isinstance(dilation, int):
dilation = (dilation, dilation)
padding = get_pad_tuple2d(padding)
return _make.conv2d( data, weight, strides, padding, dilation, groups, channels, kernel_size, data_layout, kernel_layout, out_layout, out_dtype,
)

这里的_make.conv2d是通过下面的PackFunc注册得到的

tvm._ffi._init_api("relay.op.nn._make", __name__)

src/relay/op/nn/convolution.cc找到conv2d的注册函数

TVM_REGISTER_GLOBAL("relay.op.nn._make.conv2d")
.set_body_typed([](Expr data, Expr weight, Array<IndexExpr> strides, Array<IndexExpr> padding,
Array<IndexExpr> dilation, int groups, IndexExpr channels,
Array<IndexExpr> kernel_size, String data_layout, String kernel_layout,
String out_layout, DataType out_dtype) {
return MakeConv<Conv2DAttrs>(data, weight, strides, padding, dilation, groups, channels,
kernel_size, data_layout, kernel_layout, out_layout, out_dtype,
"nn.conv2d");
});

MakeConv 是对所有卷积的模板,根据参数实例化相应的函数

template <typename T>
inline Expr MakeConv(Expr data, Expr weight, Array<IndexExpr> strides, Array<IndexExpr> padding,
Array<IndexExpr> dilation, int groups, IndexExpr channels,
Array<IndexExpr> kernel_size, std::string data_layout,
std::string kernel_layout, std::string out_layout, DataType out_dtype,
std::string op_name) {
auto attrs = make_object<T>();
attrs->strides = std::move(strides);
attrs->padding = std::move(padding);
attrs->dilation = std::move(dilation);
attrs->groups = groups;
attrs->channels = std::move(channels);
attrs->kernel_size = std::move(kernel_size);
attrs->data_layout = std::move(data_layout);
attrs->kernel_layout = std::move(kernel_layout);
attrs->out_layout = std::move(out_layout);
attrs->out_dtype = std::move(out_dtype);
const Op& op = Op::Get(op_name);
return Call(op, {data, weight}, Attrs(attrs), {});
}

这里通过Op::Get(op_name); 获取对应relay算子,在Op::Get函数中发现是通过查表得到。

// find operator by name
const Op& Op::Get(const String& name) {
const OpRegEntry* reg = OpRegistry::Global()->Get(name);
ICHECK(reg != nullptr) << "AttributeError: Operator " << name << " is not registered";
return reg->op();
}

注册是通过C++的RELAY_REGISTER_OP("nn.conv2d")宏注册到OpRegistry::Global()中。宏展开为

static __attribute__((unused))::tvm::OpRegEntry& __make_Op230 =
::tvm::OpRegEntry::RegisterOrGet("nn.conv2d").set_name()

注册过程:

RELAY_REGISTER_OP("nn.conv2d")
.describe(R"code(2D convolution layer (e.g. spatial convolution over images). This layer creates a convolution kernel that is convolved
with the layer input to produce a tensor of outputs. - **data**: This depends on the `layout` parameter. Input is 4D array of shape
(batch_size, in_channels, height, width) if `layout` is `NCHW`.
- **weight**: (channels, in_channels, kernel_size[0], kernel_size[1])
- **out**: This depends on the `layout` parameter. Output is 4D array of shape
(batch_size, channels, out_height, out_width) if `layout` is `NCHW`. )code" TVM_ADD_FILELINE)
.set_attrs_type<Conv2DAttrs>()
.set_num_inputs(2)
.add_argument("data", "Tensor", "The input tensor.")
.add_argument("weight", "Tensor", "The weight tensor.")
.set_support_level(2)
.add_type_rel("Conv2D", Conv2DRel<Conv2DAttrs>)
.set_attr<FInferCorrectLayout>("FInferCorrectLayout", ConvInferCorrectLayout<Conv2DAttrs>);

返回的是OpRegEntry,后续的set_name等,则是通过OpRegEntry的get接口(返回的是OpNode),构造对应的Relay op

【TVM模型编译】2. relay算子构造.md的更多相关文章

  1. TVM将深度学习模型编译为WebGL

    使用TVM将深度学习模型编译为WebGL TVM带有全新的OpenGL / WebGL后端! OpenGL / WebGL后端 TVM已经瞄准了涵盖各种平台的大量后端:CPU,GPU,移动设备等.这次 ...

  2. 【KAWAKO】TVM-tflite模型编译与优化

    目录 前言 准备模型 版本问题 精度问题 加载tflite模型 编译模型 在python上运行模型进行测试 加载输入数据 运行四连 优化(Autotune) 注: 前言 TVM的编译与优化主要有两种方 ...

  3. - 反编译 AndroidKiller 逆向 实践案例 MD

    目录 目录 反编译 AndroidKiller 逆向 实践案例 MD AndroidKiller 简介 插件升级 基本使用 实践案例 修改清单文件 打印 debug 级别的日志 方式一:直接代理 Lo ...

  4. TVM优化Deep Learning GPU算子

    TVM优化Deep Learning GPU算子 高效的深度学习算子是深度学习系统的核心.通常,这些算子很难优化,需要HPC专家付出巨大的努力. 端到端张量IR / DSL堆栈TVM使这一过程变得更加 ...

  5. MACE(2)-----模型编译

    作者:十岁的小男孩 QQ:929994365 无用 本文仅用于学习研究,非商业用途,欢迎大家指出错误一起学习,文章内容翻译自 MACE 官方手册,记录本人阅读与开发过程,力求不失原意,但推荐阅读原文. ...

  6. Win 10环境下6sV2.1模型编译心得

    最新版本6sV2.1模型是通过FORTRAN95编写的,2017年11月代码编写完成,2018年11月发布在模型官网上.通常我们在使用过程中都是调用模型的.exe可执行文件,而下载下来的是FORTRA ...

  7. opencv编译静态库时选择MD模式无效的原因

    在Cmake-gui上看到的明明是MD运行库依赖,生成MS项目时却变成了MT运行库依赖. 原因在于编译静态库时内部做了自动替换.

  8. TVM部署预定义模型

    TVM部署预定义模型 本文通过深度学习框架量化的模型加载到TVM中.预量化的模型导入是在TVM中提供的量化支持之一. 本文演示如何加载和运行由PyTorch,MXNet和TFLite量化的模型.加载后 ...

  9. 字节码 反编译 APKTool 重新打jar包 MD

    Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...

  10. keras channels_last、preprocess_input、全连接层Dense、SGD优化器、模型及编译

    channels_last 和 channels_first keras中 channels_last 和 channels_first 用来设定数据的维度顺序(image_data_format). ...

随机推荐

  1. opencv-python 4.9.2. 轮廓特征

    矩 图像的矩可帮助你计算某些特征,如对象的质心,对象的面积等特征.函数cv.moments()给出了计算的所有矩值的字典. 从这一刻起,你可以提取有用的数据,如面积,质心等.质心由关系给出, $$ C ...

  2. Git Commit Message 应该怎么写?

    原文链接: Git Commit Message 应该怎么写? 最近被同事吐槽了,说我代码提交说明写的太差.其实都不用他吐槽,我自己心里也非常清楚.毕竟很多时候犯懒,都是直接一个 -m "f ...

  3. 系统建模之UML状态图[转载]

    1 状态图的简介(Instrduction) 状态图(Statechart Diagram)主要用于描述一个对象在其生存期间的动态行为,表现为一个对象所经历的状态序列,引起状态转移的事件(Event) ...

  4. 1.springsecurity基于内存和数据库的认证

    1.总结: 昨天主要是使用security实现了基于内存的认证和基于数据库的认证(实际项目中使用): 在security的项目中,必须配置WebSecurityConfigurerAdaptor的实现 ...

  5. Semantic Kernel 入门系列:💾Native Function

    语义的归语义,语法的归语法. 基础定义 最基本的Native Function定义只需要在方法上添加 SKFunction 的特性即可. using Microsoft.SemanticKernel. ...

  6. day25:7个魔术方法&5个关于类的魔术属性

    目录 1.__del__(析构方法) 2.魔术方法:__str__ 3.魔术方法:__repr__ 4.魔术方法:__call__ 5.魔术方法:__bool__ 6.魔术方法:__add__& ...

  7. Buffer中的public void write(Buffer source, long byteCount)解析

    这个把source缓冲区中的数据写到当前缓冲区的方法是比较经典的: if (source == null) throw new IllegalArgumentException("sourc ...

  8. 升级:In-Place Upgrade升级MySQL5.6.26

    升级需谨慎,事前先备份 MySQL升级的实质是对数据字典的升级,数据字典有:sys.mysql.information_schema.performance_schema . MySQL升级的两种方式 ...

  9. Java构建树结构的公共方法

    一.前提 pId需要传入用来确认第一级的父节点,而且pId可以为null. 树实体类必须实现:TreeNode接口 MyTreeVo必须有这三个属性:id.pId.children 可以根据不同需求, ...

  10. django使用多个数据库实现

    一.说明: 在开发 Django 项目的时候,很多时候都是使用一个数据库,即 settings 中只有 default 数据库,但是有一些项目确实也需要使用多个数据库,这样的项目,在数据库配置和使用的 ...