TVM系列---1.开始使用Tensor Expression

2023-11-19

Author: Tianqi Chen
https://docs.tvm.ai/tutorials/tensor_expr_get_started.html

Tensor Expression入门

这是TVM中Tensor表达语言的入门教程。TVM使用特定于域的张量表达式来进行有效的内核构造。

在本教程中,我们将演示使用张量表达式语言的基本工作流程。

from __future__ import absolute_import, print_function

import tvm
import numpy as np

# Global declarations of environment.

tgt_host="llvm"
# Change it to respective GPU if gpu is enabled Ex: cuda, opencl
tgt="cuda"

Vector Add Example

在本教程中,我们将使用向量添加示例来演示工作流程。

描述计算

作为第一步,我们需要描述我们的计算。TVM采用Tensor语义,每个中间结果表示为多维数组。用户需要描述生成Tensor的计算规则。

我们首先定义一个符号变量n来表示形状。然后我们定义两个占位符Tensor A和B,给定形状(n,)

然后我们用计算操作描述结果Tensor C. 计算函数采用张量的形状,以及描述张量的每个位置的计算规则的lambda函数。

在此阶段没有计算,因为我们只是声明应该如何进行计算。

n = tvm.var("n")
A = tvm.placeholder((n,), name='A')
B = tvm.placeholder((n,), name='B')
C = tvm.compute(A.shape, lambda i: A[i] + B[i], name="C")
print(type(C))

输出:

<class 'tvm.tensor.Tensor'>

计算图 Schedule the Computation

虽然上面的行描述了计算规则,但我们可以以多种方式计算C,因为C轴可以以数据并行方式计算。TVM要求用户提供的计算描述,我们称之为一个schedule。

schedule是一组计算转换,它转换程序中的计算循环。

在我们构造schedule之后,默认情况下,schedule以行主要顺序以串行方式计算C.

for (int i = 0; i < n; ++i) {
  C[i] = A[i] + B[i];
}
s = tvm.create_schedule(C.op)

我们使用split构造来分割C的第一个轴,这将原始迭代轴分成两次迭代的乘积。这相当于以下代码:

for (int bx = 0; bx < ceil(n / 64); ++bx) {
  for (int tx = 0; tx < 64; ++tx) {
    int i = bx * 64 + tx;
    if (i < n) {
      C[i] = A[i] + B[i];
    }
  }
}
bx, tx = s[C].split(C.op.axis[0], factor=64)

最后,我们将迭代轴bx和tx绑定到GPU计算网格中的线程。这些是GPU特定的构造,允许我们生成在GPU上运行的代码。

if tgt == "cuda" or tgt.startswith('opencl'):
  s[C].bind(bx, tvm.thread_axis("blockIdx.x"))
  s[C].bind(tx, tvm.thread_axis("threadIdx.x"))

Compilation

在完成指定Schedule后,我们可以将其编译为TVM函数。默认情况下,TVM编译成一个与类型无关的函数,可以从python端直接调用。

在下面的行中,我们使用tvm.build来创建一个函数。构建函数采用调度,函数的期望签名(包括输入和输出)以及我们要编译的目标语言。

编译fadd的结果是GPU设备功能(如果涉及GPU)以及调用GPU功能的主机包装器。fadd是生成的主机包装器函数,它包含对内部生成的设备函数的引用。

fadd = tvm.build(s, [A, B, C], tgt, target_host=tgt_host, name="myadd")

运行功能

编译的TVM函数公开了一个可以从任何语言调用的简洁C API。

我们在python中提供了一个最小的数组API,以帮助快速测试和原型设计。阵列API基于DLPack标准。

  • 我们首先创建一个GPU上下文。

  • 然后tvm.nd.array将数据复制到GPU。

  • fadd运行实际计算。

  • asnumpy()将GPU阵列复制回CPU,我们可以使用它来验证正确性

ctx = tvm.context(tgt, 0)

n = 1024
a = tvm.nd.array(np.random.uniform(size=n).astype(A.dtype), ctx)
b = tvm.nd.array(np.random.uniform(size=n).astype(B.dtype), ctx)
c = tvm.nd.array(np.zeros(n, dtype=C.dtype), ctx)
fadd(a, b, c)
tvm.testing.assert_allclose(c.asnumpy(), a.asnumpy() + b.asnumpy())

检查生成的代码

您可以在TVM中检查生成的代码。tvm.build的结果是一个TVM模块。fadd是包含主机包装器的主机模块,它还包含用于CUDA(GPU)功能的设备模块。

以下代码获取设备模块并打印内容代码。

if tgt == "cuda" or tgt.startswith('opencl'):
    dev_module = fadd.imported_modules[0]
    print("-----GPU code-----")
    print(dev_module.get_source())
else:
    print(fadd.get_source())

日期:

-----GPU code-----
extern "C" __global__ void myadd_kernel0( float* __restrict__ C,  float* __restrict__ A,  float* __restrict__ B, int n) {
  if ((((int)blockIdx.x) < (((n - 64) / 64) + 1)) && (((int)blockIdx.x) < (((n + 63) / 64) - 1))) {
    C[((((int)blockIdx.x) * 64) + ((int)threadIdx.x))] = (A[((((int)blockIdx.x) * 64) + ((int)threadIdx.x))] + B[((((int)blockIdx.x) * 64) + ((int)threadIdx.x))]);
  } else {
    if (((((int)blockIdx.x) * 64) + ((int)threadIdx.x)) < n) {
      if (((((int)blockIdx.x) * 64) + ((int)threadIdx.x)) < n) {
        C[((((int)blockIdx.x) * 64) + ((int)threadIdx.x))] = (A[((((int)blockIdx.x) * 64) + ((int)threadIdx.x))] + B[((((int)blockIdx.x) * 64) + ((int)threadIdx.x))]);
      }
    }
  }
}

注意

代码定制化

您可能已经注意到,A,B和C的声明都采用相同的形状参数,n。正如您将在打印的设备代码中找到的那样,TVM将利用此功能仅将单个形状参数传递给内核。这是一种专业化形式。

在主机端,TVM将自动生成检查参数中的约束的检查代码。因此,如果将具有不同形状的数组传递给fadd,则会引发错误。

我们可以做更多的专业化。例如,我们可以在计算声明中编写 n = tvm.convert(1024)而不是n = tvm.var(“n”)使生成的函数仅采用长度为1024的向量。

保存编译模块

除了运行时编译之外,我们还可以将已编译的模块保存到文件中,并在以后加载它们。我们称这个为提前编译。

以下代码首先执行以下步骤:

  • 它将已编译的主机模块保存到目标文件中。

  • 然后它将设备模块保存到ptx文件中。

  • cc.create_shared调用编译器(gcc)来创建共享库

from tvm.contrib import cc
from tvm.contrib import util

temp = util.tempdir()
fadd.save(temp.relpath("myadd.o"))
if tgt == "cuda":
    fadd.imported_modules[0].save(temp.relpath("myadd.ptx"))
if tgt.startswith('opencl'):
    fadd.imported_modules[0].save(temp.relpath("myadd.cl"))
cc.create_shared(temp.relpath("myadd.so"), [temp.relpath("myadd.o")])
print(temp.listdir())

输出:

['myadd.so', 'myadd.ptx', 'myadd.o', 'myadd.tvm_meta.json']
注意

模块存储格式

CPU(主机)模块直接保存为共享库(.so)。可以有多种自定义格式的设备代码。在我们的示例中,设备代码存储在ptx中,以及元数据json文件中。它们可以通过导入实现单独加载和链接。

加载编译模块

我们可以从文件系统加载已编译的模块并运行代码。以下代码分别加载主机和设备模块并将它们重新链接在一起。我们可以验证新加载的函数是否有效。

fadd1 = tvm.module.load(temp.relpath("myadd.so"))
if tgt == "cuda":
    fadd1_dev = tvm.module.load(temp.relpath("myadd.ptx"))
    fadd1.import_module(fadd1_dev)

if tgt.startswith('opencl'):
    fadd1_dev = tvm.module.load(temp.relpath("myadd.cl"))
    fadd1.import_module(fadd1_dev)

fadd1(a, b, c)
tvm.testing.assert_allclose(c.asnumpy(), a.asnumpy() + b.asnumpy())

将所有内容打包到一个库中

在上面的示例中,我们分别存储设备和主机代码。TVM还支持将所有内容导出为一个共享库。我们将设备模块打包成二进制blob,并将它们与主机代码链接在一起。目前,我们支持Metal,OpenCL和CUDA模块的包装。

fadd.export_library(temp.relpath("myadd_pack.so"))
fadd2 = tvm.module.load(temp.relpath("myadd_pack.so"))
fadd2(a, b, c)
tvm.testing.assert_allclose(c.asnumpy(), a.asnumpy() + b.asnumpy())

注意,运行时API和线程安全

TVM的编译模块不依赖于TVM编译器。相反,它们仅依赖于最小运行时库。TVM运行时库包装设备驱动程序,并为编译的函数提供线程安全和设备无关的调用。
这意味着您可以从任何GPU上的任何线程调用已编译的TVM函数。

生成OpenCL代码

TVM为多个后端提供代码生成功能,我们还可以生成在CPU后端上运行的OpenCL代码或LLVM代码。

以下代码块生成OpenCL代码,在OpenCL设备上创建数组,并验证代码的正确性。

if tgt.startswith('opencl'):
    fadd_cl = tvm.build(s, [A, B, C], tgt, name="myadd")
    print("------opencl code------")
    print(fadd_cl.imported_modules[0].get_source())
    ctx = tvm.cl(0)
    n = 1024
    a = tvm.nd.array(np.random.uniform(size=n).astype(A.dtype), ctx)
    b = tvm.nd.array(np.random.uniform(size=n).astype(B.dtype), ctx)
    c = tvm.nd.array(np.zeros(n, dtype=C.dtype), ctx)
    fadd_cl(a, b, c)
    tvm.testing.assert_allclose(c.asnumpy(), a.asnumpy() + b.asnumpy())

Summary

本教程使用向量添加示例介绍TVM工作流程。一般工作流程是

  • 通过一系列操作描述您的计算。

  • 描述我们如何计算使用schedule原函数。

  • 编译到我们想要的目标函数。

  • (可选)保存稍后要加载的功能。

我们非常欢迎您查看其他示例和教程,以了解有关TVM中支持的操作,调度原语和其他功能的更多信息。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

TVM系列---1.开始使用Tensor Expression 的相关文章

  • linux(ubuntu20.04)安装tvm-0.9.0+llvm+cuda/cudnn(一步到胃版)

    我是在双系统中linux上安装的 xff0c 不是Ubuntu虚拟机 xff0c 虽然两者过程基本一样 xff0c 但是在双系统上会更方便 文章目录 零 xff1a 究极大招版一 xff1a 环境准备1 1 安装gcc cmake等必要的依
  • TVM Windows conda 安装

    TVM Windows 安装 简介 本篇博客主要目的是帮助大家在windows平台上安装好tvm xff0c 并且可以顺利使用 因为有项目需要使用tvm xff0c 同时自己需要用windows做一些测试 xff0c 因此想要在window
  • 【从零开始学深度学习编译器】五,TVM Relay以及Pass简介

    TVM Relay以及Pass简介 0x0 介绍0x2 Relay介绍0x2 1 使用Relay建立一个计算图0x2 2 Module xff1a 支持多个函数 xff08 Graphs xff09 0x2 3 Let Binding an
  • gitkraken免费版本6.5.1,Linux下载地址

    来源 https www kaisawind com 2020 03 04 2020 03 05 git gitkraken自6 5 3本地库开始收费 所以推荐下载旧版本下载地址 收费版本 version 6 5 3 url deb htt
  • 深度学习编译器系列视频摘要

    文章目录 0 前言 深度学习编译器 一 综述 深度学习编译器 二 Auto TVM 深度学习编译器 三 Auto Schedule 0 前言 在B站黄雍涛博士发了几个深度学习编译器的视频 感觉说得挺好 所以记录一下 深度学习编译器 一 综述
  • TVM 从入门到精通

    本文首发自 公众号 HyperAI超神经 内容一览 TVM 共有三种安装方法 从源码安装 使用 Docker 镜像安装和 NNPACK Contrib 安装 本文讲解如何通过 Docker 镜像 和 NNPACK Contrib 安装 关键
  • 编译 OneFlow 模型

    本篇文章译自英文文档 Compile OneFlow Models tvm 0 14 dev0 documentation 作者是 BBuf Xiaoyu Zhang GitHub 更多 TVM 中文文档可访问 Apache TVM 是一个
  • 编译 Keras 模型

    本篇文章译自英文文档 Compile Keras Models 作者是 Yuwei Hu 更多 TVM 中文文档可访问 TVM 中文站 本文介绍如何用 Relay 部署 Keras 模型 首先安装 Keras 和 TensorFlow 可通
  • 编译 MXNet 模型

    本篇文章译自英文文档 Compile MXNet Models 作者是 Joshua Z Zhang Kazutaka Morita 更多 TVM 中文文档可访问 TVM 中文站 本文将介绍如何用 Relay 部署 MXNet 模型 首先安
  • TVM User Tutorial -- Blitz Course to TensorIR

    Author Siyuan Feng TensorIR 是一种特定领域语言 用于深度学习项目 有两个广泛的用途 在各种硬件后端上实现转换和优化程序 自动张力化程序优化的抽象 import tvm from tvm ir module imp
  • AutoSchedule和AutoTVM

    简介 AutoTVM 用户自己手写一个模版 在模版里面自己定义一下tune的参数 例如tile size等 给定一个模版 在这个模版里面去搜索参数 使得可以达到一组最好的参数使得张量计算的结果最好 但是 它是一种基于模板的方法 因此仍然需要
  • 【TVM 学习资料】使用 Python 接口(AutoTVM)编译和优化模型

    本篇文章译自英文文档 Compiling and Optimizing a Model with the Python Interface AutoTVM 作者是 Chris Hoge 更多 TVM 中文文档可访问 TVM 中文站 TVMC
  • TVM 结构学习总结

    最近对深度学习编译器TVM学习了一下 了解各部分的功能 根据自己的理解进行总结 如有不正确请指正 话不多说上脑图 TVM为解决各种深度学习训练框架的模型部署到各种硬件而诞生 下图是TVM经典技术栈图 编译器层次抽象 编译器前端 接收C C
  • TVM(一):简介与安装

    简介 TVM是一个用于深度学习系统的编译器堆栈 它旨在缩小以生产力为中心的深度学习框架与以性能和效率为中心的硬件后端之间的差距 TVM与深度学习框架合作 为不同的后端提供端到端编译 换句话说 TVM就是一种将深度学习工作负载部署到硬件的端到
  • 【TVM 学习资料】用 Schedule 模板和 AutoTVM 优化算子

    本篇文章译自英文文档 Optimizing Operators with Schedule Templates and AutoTVM 作者是 Lianmin Zheng Chris Hoge 更多 TVM 中文文档 访问 TVM 中文站
  • 通过SSH -q -X来远程打开连接显示图形界面

    以下以qtcreator 为例 以Ubuntu 16 04 4 LTS为例 安装配置主要分为服务器端和客户端两个方面 一 服务器端配置 安装ssh服务 sudo apt get install openssh server apt get是
  • 【TVM 学习资料】使用 TVMC Python 入门:TVM 的高级 API

    本篇文章译自英文文档 Getting Starting using TVMC Python a high level API for TVM 作者是 Jocelyn Shiue 更多 TVM 中文文档可访问 TVM 中文站 本节将介绍针对
  • 深度学习编译中间件TVM之编译&安装

    参考文档 mxnet官方install手册 TVM 0 4 0官方安装指导手册 LLVM下载地址 Debian Ubuntu Linux下安装LLVM Clang编译器 开发环境介绍 操作系统版本 Ubuntu16 04 LTS 64 bi
  • TVM系列---1.开始使用Tensor Expression

    Author Tianqi Chen https docs tvm ai tutorials tensor expr get started html Tensor Expression入门 这是TVM中Tensor表达语言的入门教程 TV
  • Tegra 平板电脑上的 NDK 调试

    今天 我购买了用于本机开发的 Android 平板电脑 采用 Tegra 的 Acer Iconina Tab A500 Honeycomb 3 1 然后我从以下位置下载并安装了 Tegra Android Development Pack

随机推荐

  • 如何统计DataFrame中各列数据分类的各个不同数据出现的次数

    可以使用 value counts 函数来统计每个不同数据在数据列中出现的次数 例如 假设有一个名为 df 的 DataFrame 其中包含一列名为 col 要统计 col 列中各个不同数据的出现次数 可以使用以下代码 counts df
  • python 读写数据文件的6种常用方式

    本文主要介绍python读写数据文件的6种常用方式 1 python内置方法 with open r test xlsx as f a f read 一般 在应用上述上下文管理器后 可以用如下三种方式进行内置方法的读写操作 read 一次性
  • java实现区块链_用Java实现一个简单的区块链

    前面的文章 笔者花了不少的文字来介绍区块链的基础概念 以太坊的概念和开发 大家是否感觉区块链开发还是挺复杂的呢 但其实区块链技术本质就是一个分布式账本 在技术上本质就是一个链表 链表里面有一个个的区块 每个区块有自己的数字签名 涉及到加密技
  • Android Log-日志介绍

    一 基本介绍 Logcat是Android日常开发过程中的重要组成部分 Logcat上会显示系统消息 使用Log类添加到应用的消息 应用运行异常信息等 通过日志 我们可以实时监控应用运行状态 为应用调试提供重要参考 Log格式 一条标准的日
  • Appium抓取app数据

    主流APP数据抓取难点 1 请求参数加密 sign签名 使用sha1加上md5做辅助加密 2 请求body加密 整个请求体使用DES算法做加解密 3 代理检测反爬 抓包设置代理后 直接不再加载数据 4 私有CA证书反爬 由于公有的证书需要付
  • Scala中sorted、sortBy、sortWith区别

    1 sorted方法真正排序的逻辑是调用的java util Arrays sort 源码 def sorted B gt A implicit ord Ordering B Repr val len this length val b n
  • UG NX10.0软件安装教程

    软件下载 名称 UG NX 10 0 语言 简体中文 安装环境 Windows 下载链接 链接 https pan baidu com s 1SkskLU2CYLQznfGWM7O4HQ 提取码 ersv 安装中有问题请咨询管家微信 don
  • Android面试题最新整理,2022年最新版

    每年的9月和10月 是互联网大厂疯狂招人的时期 也是程序员们跳槽的黄金期 不知道你有没有幻想过这样一个场景 大厂的面试官说 恭喜你通过面试 明天来办理入职吧 今天 为大家整理了2022年Android大厂面试真题 刷企业历年真题 助你轻松搞
  • 大话西游手游有双系统服务器吗,大话西游手游有几个版本_大话西游手游官服和混服怎么区分_玩游戏网...

    大话西游 手游时间服点卡是互通的吗 点卡有两种 一种是大话西游手游内部的点卡 这种点数是在游戏里面购买道具或者计时用的 分为绑定点和交易点 这种是不能通用的 比如我在时间服有两个号 一个是绝代佳人区 另外一个是勿忘初心区 绝代佳人的点卡是不
  • 基于Matlab实现图像融合技术(附上多个仿真源码+数据)

    图像融合技术是一种将多幅图像融合为一幅图像的方法 使得这幅融合图像包含原始图像的所有信息 近年来 图像融合技术已经广泛应用于图像分割 变换和裁剪等领域 本文将介绍如何使用Matlab实现图像融合技术 实现步骤 首先 我们需要了解图像融合的基
  • linux下c语言实现tail -f功能---实时读取变化文件中的增量内容

    最近由于项目需要 需要对文件中实时新增的数据进行处理 结合tail f的逻辑 用c语言实现了这一功能 代码如下 cpp view plain copy include
  • jquery获取select值

  • ARM架构学习(二)——流水线

    本期主题 ARM流水线 往期地址 ARMv7架构学习 ARM流水线 1 流水线概念 2 指令的分解步骤 1 流水线概念 硬件资源总是有限的 有一个明显的方法能改善硬件资源的利用率 这就是pipeline 流水线 技术 其实就是在当前指令结束
  • std::nth_element bug引起的crash问题

    1 源码 auto less compare const MirroringGroup mg1 const MirroringGroup mg2 gt bool return mg1 usage lt mg2 usage std nth e
  • 腾讯云服务器配置选择方法

    腾讯云服务器配置如何选择 CPU内存 带宽和系统盘怎么选择合适 个人用户可以选择轻量应用服务器 企业用户可以选择云服务器CVM 2核2G3M带宽轻量服务器95元一年 2核4G5M服务器168元一年 企业用户可以选择标准型S5云服务器 可以一
  • idea 生成类图

    选中类 ctrl alt u或者ctrl alt shift u 生成类图
  • ArcGIS GraphicsLayer层的特殊要求

    如果你要使用GraphicsLayer这个绘图层 那么你需要注意自己的布局的模式不可以使用 layout absolute 如果你使用了这个布局 那么你的GraphicsLayer层可能会无法使用 比如下面的程序就是因为设置了 layout
  • java 最大公约数和最小公倍数

    题目 题目 输入两个正整数m和n 求其最大公约数和最小公倍数 比如 12和20的最大公约数是4 最小公倍数是60 说明 break关键字的使用 代码一 package l2 for 题目 输入两个正整数m和n 求其最大公约数和最小公倍数 比
  • Counter统计列表中元素出现次数

    使用Counter方法 统计元素在列表中出现的次数 from collections import Counter k labels 1 1 0 1 0 0 1 1 2 2 3 2 2 2 2 Counter返回的是字典 key为列表中元素
  • TVM系列---1.开始使用Tensor Expression

    Author Tianqi Chen https docs tvm ai tutorials tensor expr get started html Tensor Expression入门 这是TVM中Tensor表达语言的入门教程 TV