【tvm解析】 Operator Strategy 机制
本文地址:https://www.cnblogs.com/wanger-sjtu/p/15082871.html
Relay Operator Strategy是建立Relay IR与TOPI算子库的桥梁,通过Relay Operator Strategy,每个Relay IR至少与一个compute和一个schedule注册关联起来。至少一个原因在于,一个算子在不同后端设备上有不同的实现,而且一个算子可能有多种计算算法,适应不同场景。
在增加relay IR 的教程里面注册算子的compute、schedule中,就是通过OpStrategy关联算子的compute与schedule
@override_native_generic_func("cumsum_strategy")
def cumsum_strategy(attrs, inputs, out_type, target):
"""cumsum generic strategy"""
strategy = _op.OpStrategy()
strategy.add_implementation(
wrap_compute_scanop(topi.cumsum), #上面写的compute
wrap_topi_schedule(topi.generic.schedule_extern),
name="cumsum.generic",
)
return strategy
Operator Strategy Design
OpStrategy的核心为OpImplementation,包含了一组compute及对应的schedule,不同实现的名字,选择优先级(参见下文的选择策略)。
OpStrategy中包含一系列的OpSpecialization,每个OpSpecialization包含一组SpecializedCondition(参考include/tvm/te/schedule.h). 如果SpecializedCondition为空(null),表示是一个通用的实现,反之则是对于特定情形优化的。SpecializedCondition包含了这一算子的多个TE实现,以及实现被调用的条件。
最后一点,对给定的workload,一个strategy 函数或者FTVMStrategy,决定了使用哪个compute和schedule,因此这部分需要与relay算子对应起来。
FTVMStrategy 实现位置在include/tvm/target/generic_func.h,是一个通用函数,对于给定硬件平台可以重写。函数签名是
OpStrategy(const Attrs& attrs, const Array<Tensor>& inputs, const Type& out_type, const Target& target)
对给定算子属性信息、输入、输出类型以及平台设备,这个函数返回相应的OpStrategy.
手写一个 Strategy 函数
tvm 推荐在python侧来写Strategy 函数,在python侧提供了OpStrategy类,其中包含一个add_implementation方法。
@tvm._ffi.register_object("relay.OpStrategy")
class OpStrategy(Object):
"""Operator strategy"""
def __init__(self):
self.__init_handle_by_constructor__(_make.OpStrategy)
def add_implementation(self, compute, schedule, name="default", plevel=10):
_OpStrategyAddImplementation(self, compute, schedule, name, plevel)
后面以topk的算子为例,介绍了如何手写 Strategy 函数
# 通用的
# add to python/tvm/relay/op/strategy/generic.py
@override_native_generic_func("topk_strategy")
def topk_strategy(attrs, inputs, out_type, target):
strategy = _op.OpStrategy()
strategy.add_implementation(
wrap_compute_topk(topi.topk),
wrap_topi_schedule(topi.generic.schedule_topk),
name="topk.generic")
return strategy
# 针对GPU CUDA的
# add to each target file in python/tvm/relay/op/strategy, e.g., x86.py, cuda.py, etc.
@topk_strategy.register(["cuda", "gpu"])
def topk_strategy_cuda(attrs, inputs, out_type, target):
strategy = _op.OpStrategy()
strategy.add_implementation(
wrap_compute_my_new_op(topi.cuda.topk),
wrap_topi_schedule(topi.cuda.schedule_topk),
name="topk.cuda")
return strategy
为了满足Strategy 函数对于函数签名的要求(see FTVMCompute and FTVMSchedule in include/tvm/relay/op_attr_types.h),这里对topk的compute和schedule做了一层封装。由于算子属性不同,通常需要算子开发者自己写这部分的封装函数。
上面的例子比较简单,对于一个设备平台只有一个实现,但对一些其他的复杂算子来说,需要针对不同的算法来写相应的schedule,以卷积算子为例,可以直接写滑窗来计算,也可以使用winograd算法计算。这种情况下有多个implementation:
strategy.add_implementation(
wrap_compute_conv2d(topi.cuda.conv2d_nchw),
wrap_topi_schedule(topi.cuda.schedule_conv2d_nchw),
name="conv2d_nchw.cuda",
plevel=10)
if winograd_condition:
strategy.add_implementation(
wrap_compute_conv2d(topi.cuda.conv2d_nchw_winograd),
wrap_topi_schedule(topi.cuda.schedule_conv2d_nchw_winograd),
name="conv2d_nchw_winograd.cuda",
plevel=15)
可以看到这两个是优先级不同,在满足winograd算法的情况下,会优先选择winograd算法。这样也可以新增条件,新增implentation。
同样也可以对不同shape设置不同的优先级策略。下面的例子就是在m > 16时,有额外的计算策略:
def dense_strategy(attrs, inputs, out_type, target):
m = inputs[0].shape[0]
strategy = _op.OpStrategy()
strategy.add_implementation(
wrap_compute_dense(dense_compute1),
wrap_topi_schedule(dense_schedule1),
name="dense_common")
with tvm.te.SpecializedCondition(m > 16):
strategy.add_implementation(
wrap_compute_dense(dense_compute2),
wrap_topi_schedule(dense_schedule2),
name="dense_for_large_m",
plevel=15)
return strategy
将算子 Strategy 绑定到算子
定义了算子strategy函数以后,需要跟算子绑定在一起。
register_strategy("topk", strategy.topk_strategy)
然而,对于一个算子来说,写它的strategy函数是比较困难的,对简单算子来说,这里提供了两种方案。
第一个:算子是单射的、广播、reduce操作时候,可以通过 register_injective_schedule, register_broadcast_schedule、 register_reduce_schedule,这就避免自己手写schedule了。不过这种方式对于任意后端设备都是通用的。
register_broadcast_schedule("add")
第二种:对于没有明确pattern的算子,可以用register_schedule实现对任意后端的注册。
# 通用兜底的
# add to python/tvm/relay/op/strategy/generic.py
@generic_func
def schedule_pool(attrs, outs, target):
with target:
return topi.generic.schedule_pool(outs, attrs.layout)
# 如果特定target的,需要在对应的文件下增加
# add to each target file in python/tvm/relay/op/strategy, e.g., x86.py, cuda.py, etc.
@schedule_pool.register("cpu")
def schedule_pool_cpu(attrs, outs, target):
...
register_schedule("nn.max_pool2d", strategy.schedule_pool)
Operator Strategy 选择
一个算子有多个Strategy的时候,选择策略是什么呢?
对于静态shape:首先会根据搜索时候的tune log选择最佳实现,如果tune log中没有或者已有auto TVM模板中有特定的实现,则会根据优先级选择对应的实现。如果多个实现具有相同优先级,选哪个就不确定了。
动态shape场景,则会选择高优先级的情况。
【tvm解析】 Operator Strategy 机制的更多相关文章
- 解析Android消息处理机制:Handler/Thread/Looper & MessageQueue
解析Android消息处理机制 ——Handler/Thread/Looper & MessageQueue Keywords: Android Message HandlerThread L ...
- [转载]ECMall模板解析语法与机制
ECMall模板解析语法与机制 2011-05-22 在ECMall模板中,用"{"开头,以"}"结尾就构成一个标签单元,"{"紧接着的单词 ...
- 转 : 深入解析Java锁机制
深入解析Java锁机制 https://mp.weixin.qq.com/s?__biz=MzU0OTE4MzYzMw%3D%3D&mid=2247485524&idx=1&s ...
- 两道面试题,带你解析Java类加载机制
文章首发于[博客园-陈树义],点击跳转到原文<两道面试题,带你解析Java类加载机制> 在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Gr ...
- 【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)
本文转自 https://www.cnblogs.com/chanshuyi/p/the_java_class_load_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Ja ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- 【转】彻底解析Android缓存机制——LruCache
彻底解析Android缓存机制——LruCache 关于Android的三级缓存,其中主要的就是内存缓存和硬盘缓存.这两种缓存机制的实现都应用到了LruCache算法,今天我们就从使用到源码解析,来彻 ...
- Flink 源码解析 —— 深度解析 Flink 序列化机制
Flink 序列化机制 https://t.zsxq.com/JaQfeMf 博客 1.Flink 从0到1学习 -- Apache Flink 介绍 2.Flink 从0到1学习 -- Mac 上搭 ...
- Netty源码解析 -- 事件循环机制实现原理
本文主要分享Netty中事件循环机制的实现. 源码分析基于Netty 4.1 EventLoop 前面分享服务端和客户端启动过程的文章中说过,Netty通过事件循环机制(EventLoop)处理IO事 ...
- WEB请求过程(http解析,浏览器缓存机制,域名解析,cdn分发)
概述 发起一个http请求的过程就是建立一个socket通信的过程. 我们可以模仿浏览器发起http请求,譬如用httpclient工具包,curl命令等方式. curl "http://w ...
随机推荐
- 阿里巴巴为什么这样强制从List中删除元素
还是先举个例子,你侄女对天文知识感兴趣,然后你就用程序写了太阳系九大星系(水星.金星.地球.火星.木星.土星.天王星.海王星.冥王星)的运行轨迹图,然后拿给侄女看.然后她说错了错了,你的知识太旧了,多 ...
- 把一个列表拆成N个子列表的四种方法
编程的方法往往不止一种,比如怎么把一个Python种的列表拆成N个子列表,我们可以很容易找到N种方法,也许这就是编程的魅力所在. 一.列表表达式法 这种方法最为简洁,不过可读性差一些 这个方法中,即使 ...
- [操作系统/Linux]磁盘分区
0 基本概念1: 盘片/盘面/磁头/扇区/磁道/柱面 本小节摘自: 硬盘基本知识(磁头.磁道.扇区.柱面) - 博客园 一张磁盘并不是拿过来直接用,需要先分区. 磁盘本身有很多sector(扇区).c ...
- AutoGPT目前只是成功学大师GPT版
一大波韭菜被收割了 最近很多人在交流对于AutoGPT的震惊和激动.AutoGPT是一个开源的应用程序,展示了GPT-4语言模型的能力.这个程序由GPT-4驱动,自主地开发和管理业务,以增加净值.它是 ...
- 【深度学习】【图像分类网络】(二)VisionTransformer
Transformer简介 上下文的this值, 作为自己的this值 1. 所以 call() / apply() / bind() 方法对于箭头函数来说只是传入参数 ...
- Vue闪烁的问题
问题: 当我们打开Vue页面的时候,如果弱网环境,会出现一个闪烁的效果 原因: Vue还来不及处理的模板 解决: 使用 v-cloak 来解决Vue这个打开页面的闪烁的问题 原理: 利用 v-cloa ...
- 实例讲解Playwright(一)
实例讲解Playwright(一) 网址 说明 https://playwright.dev/ 官网首页 https://playwright.dev/python/docs/intro Python ...
- Spring源码系列:核心概念解析
前言 本文旨在为读者解析Spring源码中的关键类,以便读者在深入阅读源码时,能够了解关键类的作用和用途.在阅读Spring源码时,经常会遇到一些不熟悉的概念,了解关键类的作用可以帮助读者更好地理解这 ...
- 笔记:C++学习之旅---引用
笔记:C++学习之旅---引用 什么是引用? 引用就是别名,引用并非对象,相反的,他只是为一个已经存在的对象所起的另外一个名字. /*引用就是别名*/ #include <iostream> ...