TVM基本调度原语

TVM调度原语官方DOC

#!/usr/bin/env python
# coding: utf-8

# 通常有几种方法来计算相同的结果,但是不同的方法会导致不同的局部性和性能。所以TVM要求用户提供如何执行称为Schedule的计算。
# Schedule是一组转换计算的集合,它转换程序中的计算循环。

# In[1]:


#兼容python2.x

from __future__ import print_function #在python2.x中也要像python3.x那样使用print()
from __future__ import absolute_import #在python2.x中使用绝对路径


# In[2]:



import tvm
from tvm import te
import numpy as np


# In[3]:


#声明两个var变量

n = te.var("n") #使用指定的名称和dtype创建一个新变量,dtype默认为‘int32’
m = te.var("m")


# In[4]:


#声明一个element-wise(相对位置相乘)乘法

A = te.placeholder((m, n), name="A") #构造一个空张量对象
B = te.placeholder((m, n), name="B")
C = te.compute((m, n), lambda i, j: A[i, j] * B[i, j], name="C") #声明运算

s = te.create_schedule([C.op]) #创建调度

print(tvm.lower(s, [A, B, C], simple_mode=True)) #lower将把计算从定义转换为实际的可调用函数


# # split

# In[5]:


A = te.placeholder((m,), name="A")
B = te.compute((m,), lambda i: A[i] * 2, name="B")

s = te.create_schedule(B.op)

xo, xi = s[B].split(B.op.axis[0], factor=32) #split用factor参数把一个指定的轴分解为两个轴

print(tvm.lower(s, [A, B], simple_mode=True))


# In[6]:


A = te.placeholder((m,), name="A")
B = te.compute((m,), lambda i:A[i], name='B')

s = te.create_schedule(B.op)

bx, tx = s[B].split(B.op.axis[0], nparts=32) #使用nparts与使用factor正好相反

print(tvm.lower(s, [A, B], simple_mode = True))


# # tile

# In[7]:


A = te.placeholder((m, n), name="A")
B = te.compute((m, n), lambda i, j:A[i, j], name="B")

s = te.create_schedule(B.op)

#使用tile,把数据进行平铺,例如这里的二维数据,相当于沿着两个轴,把数据切割成了一个一个小块
xo, yo, xi, yi = s[B].tile(B.op.axis[0], B.op.axis[1], x_factor=10, y_factor=5) 

print(tvm.lower(s, [A, B], simple_mode=True))


# # fuse

# In[8]:


A = te.placeholder((m, n), name="A")
B = te.compute((m, n), lambda i, j:A[i, j], name="B")

s = te.create_schedule(B.op)

xo, yo, xi, yi = s[B].tile(B.op.axis[0], B.op.axis[1], x_factor=10, y_factor=5)

fused = s[B].fuse(xi, yi) #把xi轴和yi轴融合成了一个轴

print(tvm.lower(s, [A, B], simple_mode=True))


# # reorder

# In[9]:


A = te.placeholder((m, n), name="A")
B = te.compute((m, n), lambda i, j: A[i, j], name="B")

s = te.create_schedule(B.op)

xo, yo, xi, yi = s[B].tile(B.op.axis[0], B.op.axis[1], x_factor=10, y_factor=5)

s[B].reorder(xi, yo, xo, yi) #将轴重新排序,即改变计算过程中的循环嵌套顺序

print(tvm.lower(s, [A, B], simple_mode=True))


# # bind&thread_axis

# In[10]:


A = te.placeholder((n,), name="A")
B = te.compute(A.shape, lambda i: A[i] * 2, name="B")

s = te.create_schedule(B.op)

bx, tx = s[B].split(B.op.axis[0], factor=64)

s[B].bind(bx, te.thread_axis("blockIdx.x")) #thread_axis:创建迭代变量来表示线程索引.bind:将指定的轴与线程绑定,通常用于gpu编程
s[B].bind(tx, te.thread_axis("threadIdx.x"))

print(tvm.lower(s,[A, B], simple_mode=True))


# # compute_at

# In[11]:


A = te.placeholder((m,), name="A")
B = te.compute((m,), lambda i: A[i] + 1, name="B")
C = te.compute((m,), lambda i: B[i] * 2, name="C")

s = te.create_schedule(C.op)

print(tvm.lower(s, [A, B, C], simple_mode=True)) #对于由多个运算符组成的调度,TVM默认情况下会在root分别计算张量.


# In[13]:


A = te.placeholder((m,), name="A")
B = te.compute((m,), lambda i: A[i] + 1, name="B")
C = te.compute((m,), lambda i: B[i] * 2, name="C")

s = te.create_schedule(C.op)

s[B].compute_at(s[C], C.op.axis[0]) #compute_at将B的计算挪到了C的计算的第一个轴里

print(tvm.lower(s, [A, B, C], simple_mode=True))


# # compute_inline

# In[16]:


A = te.placeholder((m,), name = "A")
B = te.compute((m,), lambda i: A[i] + 1, name = "B")
C = te.compute((m,), lambda i: B[i] * 2, name = "C")

s = te.create_schedule(C.op)

s[B].compute_inline() #compute_inline()将一个阶段标记为內联,然后计算体将被展开并插入到需要它的地方.

print(tvm.lower(s,[A, B, C], simple_mode=True))


# # copute_root

# In[18]:


A = te.placeholder((m,), name = "A")
B = te.compute((m,), lambda i: A[i] + 1)
C = te.compute((m,), lambda i: B[i] * 2)

s = te.create_schedule(C.op)

s[B].compute_at(s[C], C.op.axis[0])
s[B].compute_root() #将B的计算阶段挪回root

print(tvm.lower(s, [A, B, C], simple_mode = True))


# In[ ]:




上一篇:JAVA8 Map新方法:compute,computeIfAbsent,putIfAbsent与put的区别


下一篇:大舅开发-从小白到弃坑之路【openstack】-PRC调用