自定义pass编写

TVM是一个框架,抽象了机器学习加速器的异质性。有时,用户可能需要自定义一些分析和IR转​​换,使TVM适应自己的专用硬件。本文可帮助用户在TVM中编写自定义pass。

先决条件

在阅读本文之前,假设读者已经熟悉以下主题:

  • 在TVM中编写算法并进行调度。否则,请参见示例教程,例如 如何在CPU上优化GEMM
  • HalideIR的基本结构。否则,请参阅HalideIR/src/ir/IR.h以了解定义了IR节点的哪些属性。
  • 访客设计模式。否则,请检查 Python AST模块以查看AST访问者的实现方式。
  • 如何将Schedule降低为IRModule类或LLVM模块。否则,请参考python/tvm/build_module.py以获得一些基础知识。

import tvm

from tvm import te

import numpy as np

首先编写一个非常简单的矢量加法,并使用默认调度对其进行构建。然后,使用定制的下降通道来直接操纵IR,而不是使用调度原语。

n = tvm.tir.const(128, "int32")

a = te.placeholder((n,), name="a")

b = te.placeholder((n,), name="b")

c = te.compute((n,), lambda i: a[i] + b[i], name="c")

sch = te.create_schedule(c.op)

ir = tvm.lower(sch, [a, b, c])

print(ir)

输出:

primfn(a_1: handle, b_1: handle, c_1: handle) -> ()

attr = {"global_symbol": "main", "tir.noalias": True}

buffers = {c: Buffer(c_2: Pointer(float32), float32, [128], []),

b: Buffer(b_2: Pointer(float32), float32, [128], []),

a: Buffer(a_2: Pointer(float32), float32, [128], [])}

buffer_map = {a_1: a, b_1: b, c_1: c} {

for (i: int32, 0, 128) {

c_2[i] = ((float32*)a_2[i] + (float32*)b_2[i])

}

}

写pass

本质上,“ IR转换遍历”是将语句映射到新语句的功能。因此,定义此向量化函数并逐步实现它。

TVM已经为用户提供了两类来分析和转换IR。

IR Vistor访客

可以用tvm.tir.stmt_functor.post_order_visit(stmt, func)funcfunc来从Halide IR收集信息。这是一个函数回调。在退出当前IR节点之前,即在后订单访问之前,将调用此函数。然后,利用side effects 副作用来存储IR访问的结果,返回值将被忽略。

必须使用一些数组来存储IR访问的结果。该值甚至是一个变量。这主要是由于Python-C运行时中的限制。每次递归都会刷新变量值,但会保留数组值。

loops = []

def find_width8(op):

""" Find all the 'tir.For' nodes whose extent can be divided by 8. """

if isinstance(op, tvm.tir.For):

if isinstance(op.extent, tvm.tir.IntImm):

if op.extent.value % 8 == 0:

loops.append(op)

IR转换

转换界面与访问者界面略有不同。访问者中仅存在一个后回调,但是转换访问者既支持前回调又支持后回调。如果要保留原始IR节点,只需返回None。如果要将当前节点更改为某个节点,请使用TVM IR maker界面进行构建并返回此值。

笔记

如果调用了预订功能并返回了非“无”的值,则将跳过 post-order 功能。

def vectorize8(op):

""" Split can vectorize the loops found in `find_width8`. """

if op in loops:

extent = op.extent.value

name = op.loop_var.name

lo, li = te.var(name + ".outer"), te.var(name + ".inner")

body = tvm.tir.stmt_functor.substitute(op.body, {op.loop_var: lo * 8 + li})

body = tvm.tir.For(li, 0, 8, tvm.tir.ForKind.VECTORIZED, body)

body = tvm.tir.For(lo, 0, extent // 8, tvm.tir.ForKind.SERIAL, body)

return body

return None

@tvm.tir.transform.prim_func_pass(opt_level=0)

def vectorize(f, mod, ctx):

global loops

tvm.tir.stmt_functor.post_order_visit(f.body, find_width8)

if not loops:

return sf

# The last list arugment indicates what kinds of nodes will be transformed.

# Thus, in this case only `For` nodes will call `vectorize8`

return f.with_body(tvm.tir.stmt_functor.ir_transform(f.body, None, vectorize8, ["tir.For"]))

降低胶水Glue to Lowering

到目前为止,已经完成了编写此IR转换通道的操作。接下来,需要将该pass粘贴到TVM的较低pass上。

在这种情况下,通过将元组列表作为参数提供给TVM标准降低passtir.add_lower_pass。“元组”表示降低的不同阶段。在TVM中,降级分为四个阶段,每个阶段完成后将调用用户自定义的阶段。

笔记

以下是每个阶段完成的基本转换:

  • · 阶段0生成原始IR和环路电平。
  • · 第1阶段将阵列存储平坦化。
  • · 阶段2转换循环,例如展开,向量化和线程绑定。
  • · 第三阶段进行一些清理工作。

因此,放置此转换过程的好地方就在阶段1之后。

with tvm.transform.PassContext(config={"tir.add_lower_pass": [(1, vectorize)]}):

print(tvm.lower(sch, [a, b, c]))

输出:

primfn(a_1: handle, b_1: handle, c_1: handle) -> ()

attr = {"global_symbol": "main", "tir.noalias": True}

buffers = {b: Buffer(b_2: Pointer(float32), float32, [128], []),

c: Buffer(c_2: Pointer(float32), float32, [128], []),

a: Buffer(a_2: Pointer(float32), float32, [128], [])}

buffer_map = {a_1: a, b_1: b, c_1: c} {

for (i.outer: int32, 0, 16) {

c_2[ramp((i.outer*8), 1, 8)] = ((float32x8*)a_2[ramp((i.outer*8), 1, 8)] + (float32x8*)b_2[ramp((i.outer*8), 1, 8)])

}

}

快速浏览

本文提供了编写自定义IR转换过程的快速视图:-tvm.tir.stmt_functor.post_order_visit用于收集每个IR节点上的信息。-tvm.tir.stmt_functor.ir_transform用于转换IR节点。-总结以上两个内容,编写一个IR转换功能。-用tvm.transform.PassContext将此功能用于TVM降准

自定义pass编写的更多相关文章

  1. nginx自定义模块编写-实时统计模块--转载

    原文:http://www.vimer.cn/2012/05/nginx%E8%87%AA%E5%AE%9A%E4%B9%89%E6%A8%A1%E5%9D%97%E7%BC%96%E5%86%99- ...

  2. nginx自定义模块编写-根据post参数路由到不同服务器

    nginx可以轻松实现根据不同的url 或者 get参数来转发到不同的服务器,然而当我们需要根据http包体来进行请求路由时,nginx默认的配置规则就捉襟见肘了,但是没关系,nginx提供了强大的自 ...

  3. Nginx自定义模块编写:根据post参数路由到不同服务器

    Nginx自定义模块编写:根据post参数路由到不同服务器 2014-05-05 15:27 blogread IT技术博客 字号:T | T Nginx可以轻松实现根据不同的url 或者 get参数 ...

  4. 学习 Linux,101: 自定义或编写简单脚本【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-lpic1-105-2/index.html 学习如何使用标准的 shell 语法.循环和控制结构,以及 ...

  5. Flutter实战视频-移动电商-44.详细页_首屏自定义Widget编写

    44.详细页_首屏自定义Widget编写 把详细页的图片.标题.编号和价格形成一个单独的widget去引用 详情页的顶部单独封装个插件 在pages下面新建detials_page的文件件并在里面新建 ...

  6. Excel VBA自定义函数编写(UDF, User-Defined Function)

    虽然知道Microsoft Office Excel可以支持用VB语言来进行复杂的编程和自定义函数的编写,但是一直以来都没有这个需求. 这次遇到的问题是要根据一列数组计算出一个值,但计算过程又比较复杂 ...

  7. java 编程基础:【注解】 提取注解信息,利用自定义注解编写测试类,注解绑定事件

    提取注解信息 使用注解修饰了类.方法.成员变量等成员之后,这些注解不会自己生效,必须由开发者提供相应工具来提取并处理注解信息.   Java使用java.lang.annotation.Annotat ...

  8. AngularJs 第一个自定义指令编写

    公司在做一个OA系统, 包括移动端(从微信企业号进入OA系统),电脑端. 电脑端还是用的传统的easyui做界面,asp.net mvc作为服务端.这个技术已经很成熟了配合权限框架很快就能开发出来.但 ...

  9. Flutter移动电商实战 --(44)详细页_首屏自定义Widget编写

    把详细页的图片.标题.编号和价格形成一个单独的widget去引用 详情页的顶部单独封装个插件 在pages下面新建detials_page的文件件并在里面新建页面details_top_area.da ...

随机推荐

  1. Vue2.0组件之间通信

    Vue中组件这个特性让不少前端er非常喜欢,我自己也是其中之一,它让前端的组件式开发更加合理和简单.笔者之前有写过一篇Vue2.0子父组件通信,这次我们就来聊一聊平级组件之间的通信. 首先我们先搭好开 ...

  2. 使用EasySYS搭建驱动开发基本框架

    提供EasySYS的下载地址:http://bbs.pediy.com/showthread.php?p=956643,看雪上有提供下载,自行百度. EasySYS你能够帮我们快速的搭建驱动的开发框架 ...

  3. IDA动态调试Android的DEX文件

    Android程序的dex文件的动态调试确实是个大问题,网上也有一些教程但是不是特别的详细,今天用到了IDA动态调试Android的DEX文件,特此记录一下. IDA 6.6新添加了对dex文件的调试 ...

  4. POJ3322滚箱子游戏(不错)

    题意:       讲的是一个游戏,就是在一个平面上滚动一个1*1*2的长方体的游戏,在本题里面的游戏规则是这样的: (1)      一开始给你箱子的状态,可能是横着也可能是竖着. (2)     ...

  5. Python爬虫之-动态网页数据抓取

    什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意 ...

  6. Python 图片转字符图

    pip install Image argparse pillow from PIL import Image import argparse #命令行输入参数处理 parser = argparse ...

  7. Win64 驱动内核编程-21.DKOM隐藏和保护进程

    DKOM隐藏和保护进程 主要就是操作链表,以及修改节点内容. DKOM 隐藏进程和保护进程的本质是操作 EPROCESS 结构体,不同的系统用的时候注意查下相关定义,确定下偏移,下面的数据是以win7 ...

  8. js--吐血总结最近遇到的变态表单校验---element+原生+jq+easyUI(前端职业生涯见过的最烦的校验)

    最近写了无数各种形式的表单,记录下奇奇怪怪的校验规则~ 一:首先是element自带的rules校验规则: element作为常用框架,自带rules属性简单易懂,官方文档一目了然,不再赘述,应付常用 ...

  9. JavaScript 中正则匹配时结果不一致的问题

    创建示例项目 考察如下场景,我们有个输入框组件,输入时同时进行校验. interface IInputProps { label: string; } function Input({ label } ...

  10. ThreadLocal引起的一次线上事故

    > 线上用户存储数据后查看提示无权限 前言 不知道什么时候年轻的我曾一度认为Java没啥难度,没有我实现不了的需求,没有我解不了的bug 直到我遇到至今难忘的一个bug . 线上用户存储数据后查 ...