0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

TVM中schedule介绍

电子设计 来源:电子设计 作者:电子设计 2022-02-08 17:36 次阅读

作者:安平博,Xilinx高级工程师;来源:AI加速微信公众号

Schedule是和硬件体系结构相关的一些列优化,Halide在其文章中对其做了以下定义:

1 When and where should be the value at each coordinate in each function be computed?

2 Where should they be stored?

3 How long are values cached and communicated across multiple consumers, and when are they independently recomputed by each?

第一条是描述了数据计算顺序对性能的影响,第二条是数据的存储位置对性能影响,最后一条是多线程处理过程中,不同线程数据应该如何进行交互。

参考文章:https://zhuanlan.zhihu.com/p/94846767,常用的shcedule有:

1 cache_read

将数据存储到片上缓存,减少访问数据时间。

2 cache_write

将结果写入片上缓存,然后再写入片外缓存。当然这里的片上和片外并不是绝对的概念,也可以理解为不同层次的存储结构。

3 set_scope

为数据指定存储位置,相比于cache_read和cache_write提供了更灵活的指定数据存储方式。本质上是相同的。

4 storage_align

在我看的文章中,storage_align是针对GPU shared memory的一个优化,目的是为了减少同一个bank的访问冲突。在GPU中shared memory被分割成多个bank,这些bank可以被独立线程同时访问。Storage_align就是为了将数据和bank大小匹配,减少bank conflict的发生。AI芯片中也有类似的问题,只有尽量减少bank冲突的发生,才能最大化并行计算。

5 compute_at

不懂CUDA,所以对文章中的代码不是很理解,但是从其解释看,对于多次循环的计算(或者多维计算),可以通过并行计算来降维。

6 compute_inline

将独立操作转化为内联函数,有点类似FPGA上的流水线计算。转化成内联函数从上层层面减少了stage。在FPGA中也有类似问题,可以将具有相同迭代的多条指令放在一起执行。

7 compute_root

Compute_at的反操作。

8 fuse

将多个循环iter融合为一个iter。

9 split

Fuse的反操作,将一次循环迭代拆分为多次。

10 reorder

调整循环计算迭代顺序。

11 tile

Tile也是将循环迭代进行拆分,拆分多次计算。是split+reorder。

12 unroll

将循环展开,增加并发执行。

13 vectorize

将循环迭代替换成ramp,可以通过SIMD指令实现数据批量计算,也就是单指令多数据计算。这在AI加速中会很常用,每条指令都是多数据计算的。

14 bind

CUDA中使用的优化方法,将iter绑定到不同线程,实现并发计算。

15 parallel

实现多设备并行.

16 pragma

可以在代码中人为添加编译注释,人为干预编译优化。HLS中就是通过这样的方式来实现c的硬件编程的。

17 prefetch

将数据计算和load后者store数据重叠起来,在FPGA中是很常见优化方法。

18 tensorize

将tensor作为一个整体匹配硬件的计算核心,比如一个卷积运算就可以实现在FPGA上的一个匹配。

文章https://zhuanlan.zhihu.com/p/166551011 是通过官网的一个例子来介绍schedule的。在这个例子中,首先利用te的节点表达式建立了计算函数,然后调用create_schedule来创建schedule实例,然后再调用lower函数实现schedule优化。代码如下:

# declare a matrix element-wise multiply A = te.placeholder((m, n), nam) B = te.placeholder((m, n), nam) C = te.compute((m, n), lambda i, j: A[i, j] * B[i, j], nam) s = te.create_schedule([C.op]) # lower will transform the computation from definition to the real # callable function. With argument `simple_mode=True`, it will # return you a readable C like statement, we use it here to print the # schedule result. print(tvm.lower(s, [A, B, C], simple_mode=True))

我这里依然延续上一章的内容,看代码中关于schedule的处理。

在上一章我们在codegen生成中,通过以下调用链转到了schedule的处理。Codegen -> VisitExpr(CallNode* op) -> relay.backend._CompileEngineLower -> LowerInternal。LowerInternal函数为:

o4YBAGAJhSOAPhF1AAF7w2uy4BE784.png

如果是外部定义的编译器,就只是建立cache_node节点和cache_func。如果是使用内部编译器,就会调用CreateSchedule建立schedule。接下来调用链为CreateSchedule -> ScheduleGetter.create -> te::create_schedule -> Schedule。create_schedule函数调用在文件re/schedule.h和te/schedule_lang.cc中。

create_schedule中主要有两件工作:

1 创建ReadGraph,获取post-dfs顺序的算符图。

2 初始化stage。

TVM中引入了stage的概念,一个op相当于一个stage,schedule优化是对stage的一个更改,可以增加,删减,更改其特性等。

pIYBAGAJhWKALtoXAAExsOmziHM113.png

通过createReadGraph可以遍历op图,返回op和其依赖的tensor列表。和遍历有关的主要函数为:

Op -> InputTensors -> PostOrderVisit -> IRApplyVisit,在IRApplyVisit中定义了VisitExpr和VisitStmt函数用于遍历节点。

pIYBAGAJhaOAPU1EAAOCUW3ZpIQ102.png

Stmt节点通常是节点中的主体实现,PrimExpr是TIR中节点的一个简单表达式。比如if节点:

o4YBAGAJheSAGUfwAAIKQRN_Atw687.png

ReadGraph创建完成后,通过PostDFSOrder来获取post-dfs列表,其函数具体实现在graph.cc中,

o4YBAGAJhiSARaKbAAKhr5FEruU905.png

通过不断迭代来进行深度优先搜索。

接下来是对stage进行初始化。

首先对postorder中的所有op初始化一个stage对象。我们看以下stage的定义:

Stage类中主要定义了set_scope, compute_at, compute_root, bind, split, fuse等几种优化算法。同时定义了StageNode,在StageNode中定义了和优化相关的变量,包括op,iter变量等。看一下stage初始化代码:

o4YBAGAJhmOAewapAAHNRZ9z5nY829.png

关键的几个变量lef_iter_vars,all_iter_vars,这些有什么作用还需要深入看优化函数的代码。我们看几个schedule函数,先看一个最简单的:compute_inline。代码只有一行:

(*this)->attach_type = kInline

对于标记了kInline的节点,在lower的时候会进行处理。应该会将其直接和调用的节点结合,合并两个op。

再看fuse函数,其代码为:

pIYBAGAJhqSAEGcxAAMXAmXWJb8660.png

IterVar表示计算中坐标轴,比如一个两级循环,每级循环就是一个axis。从代码中看出,fuse函数会对输入的所有axis进行合并,用fused变量替换合并后的axis。

这块代码比较抽象,先熟悉以下流程,之后再深入读一下。

审核编辑:何安

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • TVM
    TVM
    +关注

    关注

    0

    文章

    19

    浏览量

    3654
收藏 人收藏

    评论

    相关推荐

    电流传感器在电机应用介绍

    电流传感器在电机应用介绍
    的头像 发表于 10-31 17:17 254次阅读
    电流传感器在电机应用<b class='flag-5'>中</b>的<b class='flag-5'>介绍</b>

    RS-485:自动方向介绍及其在系统的作用

    电子发烧友网站提供《RS-485:自动方向介绍及其在系统的作用.pdf》资料免费下载
    发表于 09-12 10:35 0次下载
    RS-485:自动方向<b class='flag-5'>介绍</b>及其在系统<b class='flag-5'>中</b>的作用

    SemiDrive X9 AI 开发环境搭建

    SemiDrivex9AI开发环境搭建分开发机端,开发板端。主要的工具是SDNN,它是一个基于开源编译器框架TVM的端到端的AI编译器框架,Semidrive对TVM编译器框架做了适配,主要特性如下
    的头像 发表于 08-03 08:27 329次阅读
    SemiDrive X9 AI 开发环境搭建

    SDRAM的active命令介绍

    在向SDRAM 的任何行发出 READ或 WRITE 命令之前,必须先打开该行。这是通过 ACTIVE 命令完成的。ACTIVE 命令的目的是打开或者说激活(active)bank的一行并将数据从 DRAM 移动到bank的灵敏放大器。下图说明了 ACTIVE 命令的
    的头像 发表于 07-29 09:53 401次阅读
    SDRAM<b class='flag-5'>中</b>的active命令<b class='flag-5'>介绍</b>

    使用TVM量化部署模型报错NameError: name \'GenerateESPConstants\' is not defined如何解决?

    各位好,我在使用TVM部署模型时,遇到一下错误,请问如何解决?我进esp.py文件看,有如下两个函数是找不到定义的: GenerateESPConstants(), ExtractConstantsFromPartitionedFunction(),
    发表于 06-28 10:50

    电路的串联与并联介绍

    串联和并联是两种基本的连接方式,它们决定了电路组件之间的电流和电压分布。了解串联与并联的概念对于理解电路的工作原理和进行电路设计至关重要。 串联(Series) 在串联的连接方式,电路的总电阻
    的头像 发表于 05-02 16:28 3771次阅读

    在e² studio安装QE的流程介绍

    在e² studio安装QE的流程介绍
    的头像 发表于 04-04 08:05 469次阅读
    在e² studio<b class='flag-5'>中</b>安装QE的流程<b class='flag-5'>介绍</b>

    浅析SpinalHDLPipeline的复位定制

    之前有系列文章介绍了SpinalHDLPipeline的使用,最近在一个功能模块真实的使用了这个lib。
    的头像 发表于 03-17 17:31 998次阅读
    浅析SpinalHDL<b class='flag-5'>中</b>Pipeline<b class='flag-5'>中</b>的复位定制

    介绍智能照明系统在绿色建筑的应用与产品选型

    介绍智能照明系统在绿色建筑的应用与产品选型 张颖姣 安科瑞电气股份有限公司 上海嘉定201801 【摘要】:智能照明系统应用在智能建筑不仅能营造出舒适的生活、工作环境以及现代化的管理方式而且要
    的头像 发表于 02-26 09:25 466次阅读
    <b class='flag-5'>介绍</b>智能照明系统在绿色建筑<b class='flag-5'>中</b>的应用与产品选型

    RT-Thread程序在执行rt_schedule_remove_thread(to_thread);语句里面的打印时会进Hard_defaut的原因?

    ulog开启 log_LVL等级 LOG_LVL_DBG log_Out_LVL等级 LOG_LVL_DBG 程序在执行 rt_schedule_remove_thread(to_thread
    发表于 02-26 06:00

    AT89S51文资料介绍

    电子发烧友网站提供《AT89S51文资料介绍.pdf》资料免费下载
    发表于 02-20 09:24 7次下载

    Proteus元件库的电阻元件介绍

    在Proteus元件库,电阻元件被称为Resistor。电阻是一种常用的电子元件,用于限制电流流动的能力。它们通常用于各种电路,包括放大电路、滤波电路、稳压电路等等。在本文中,我们将对电阻
    的头像 发表于 01-24 10:11 9709次阅读

    AMBA总线APB slave设计介绍

    上篇文章给大家介绍了APB协议相关的知识点,本篇文章通过一个实际的APB slave的设计帮助大家巩固对APB的掌握。 APB slave设计Spec   其框图如上图所示,这里提一嘴,大家在做数字
    的头像 发表于 01-13 10:15 897次阅读
    AMBA总线<b class='flag-5'>中</b>APB slave设计<b class='flag-5'>介绍</b>

    电源设计电容的工作原理介绍

    电源设计,电容是一种非常重要的电子元件,它在电路起到滤波、耦合、储能等作用。本文将对电源设计电容的工作原理进行详细介绍。 电容是一种能够储存电荷的电子元件,其基本结构是由两个相互
    的头像 发表于 01-09 17:04 935次阅读
    电源设计<b class='flag-5'>中</b>电容的工作原理<b class='flag-5'>介绍</b>

    TVM编译器的整体架构和基本方法

    。但是这其中也去思考了一下基于FPGA加速器的编译器架构。在FPGA深度学习加速器,编译器除了需要自动化生成指令外,还要优化指令的结构,来最大化加速器性能。TVM是一个支持GPU、CPU、FPGA指令
    的头像 发表于 11-30 09:36 2317次阅读
    <b class='flag-5'>TVM</b>编译器的整体架构和基本方法