markdown在tvm.relay中使用外部库(代码片段)

author author     2022-12-13     639

关键词:

# 在TVM.Relay中使用外部库

这篇教程介绍怎么在Relay中使用cuDNN、cuBlas这样的外部库。

Relay在内部使用TVM生成特定目标的代码。例如,使用cuda作为后端,TVM为用户提供的网络生成所有层的cuda kernel代码。但是有时,将设备厂商提供的外部库合并到Relay中也很有用。幸运地,TVM提供一种透明地调用这些库的机制。对于Relay用户,我们需要做的只是设置适当的目标字符串。

在我们使用Relay的外部库之前,TVM需要使用我们想要使用的库来构建。例如,要使用cuDNN,需要启用cmake / config.cmake中的USE_CUDNN选项,并且必要时需要指定cuDNN include和library目录。

首先,导入Relay和TVM

```python
import tvm
import numpy as np
from tvm.contrib import graph_runtime as runtime
from tvm import relay
from tvm.relay import testing
```

## 创建一个简单的网络

构建一个包含卷积、批归一化、ReLU激活的简单网络

```python
out_channels = 16
batch_size = 1

#变量定义
data = relay.var("data",relay.TensorType((batch_size,3,224,224),"float32"))
weight = relay.var("weight")
bn_gamma = relay.var("bn_gamma")
bn_beta = relay.var("bn_beta")
bn_mmean = relay.var("bn_mean")
bn_mvar = relay.var("bn_var")

simple_net = relay.nn.conv2d(data=data, weight=weight, kernel_size=(3,3),channels=out_channels,padding=(1,1))
simple_net = relay.nn.batch_norm(simple_net, bn_gamma, bn_beta, bn_mmean, bn_mvar)[0]
simple_net = relay.nn.relu(simple_net)
simple_net = relay.Function(relay.ir_pass.free_vars(simple_net),simple_net)

data_shape = (batch_size, 3, 224, 224)
net, params = testing.create_workload(simple_net)
```

## 使用cuda后端构建和运行

像往常一样,我们使用cuda后端构建和运行网络。通过将日志记录级别设置为DEBUG,Relay graph编译的结果将作为伪代码转储。

```python
import logging
logging.basicConfig(level=logging.DEBUG)

#构建
target = "cuda"
graph, lib, params = relay.build_module.build(
    net, target, params=params)

ctx = tvm.context(target, 0)
data = np.random.uniform(-1, 1, size=data_shape).astype("float32")
#创建运行时
module = runtime.create(graph, lib, ctx)
#设置权重和输入数据
module.set_input(**params)
module.set_input("data",data)
#运行推理
module.run()
out_shape = (batch_size, out_channels, 224,224)
out = module.get_output(0,tvm.nd.empty(out_shape))
out_cuda = out.asnumpy()
```

生成的伪代码应如下所示。请注意bias add,batch_norm和ReLU激活如何融合到卷积内核中。 TVM从这个表示来生成单个融合内核。

```markdown
produce tensor
....

```

## 卷积层使用cuDNN实现

```python
net, params = testing.create_workload(simple_net)
#只需要修改target,其他代码与上面一样
target = "cuda -libs=cudnn" # use cudnn for convolution
graph, lib, params = relay.build_module.build(
        net, target, params=params)

ctx = tvm.context(target, 0)
data = np.random.uniform(-1, 1, size=data_shape).astype("float32")
module = runtime.create(graph, lib, ctx)
module.set_input(**params)
module.set_input("data", data)
module.run()
out_shape = (batch_size, out_channels, 224, 224)
out = module.get_output(0, tvm.nd.empty(out_shape))
out_cudnn = out.asnumpy()
```

注意,如果使用cuDNN,Relay不能将卷积与后面层融合。这是因为层融合发生在TVM IR(中间表示)的层面上。Relay对待外部库是当一个黑匣子,所以没有办法使用TVM IR去融合它们。

下面的伪代码表明cuDNN卷积+Bias Add+batch_norm+ ReLU变成了两个计算阶段,一个用于cuDNN调用,另一个用于其余操作。

```c
// attr [y] storage_scope = "global"
allocate y[float32 * 802816]
produce y 
  // attr [0] extern_scope = 0
  tvm_call_packed("tvm.contrib.cudnn.conv2d.forward", 1, 0, 1, 1, 1, 1, 1, 1, 1, tvm_stack_make_array(placeholder, tvm_stack_make_shape(1, 3, 224, 224), 0, 4, 0.000000f, 0), tvm_stack_make_array(placeholder, tvm_stack_make_shape(16, 3, 3, 3), 0, 4, 0.000000f, 0), tvm_stack_make_array(y, tvm_stack_make_shape(1, 16, 224, 224), 0, 4, 0.000000f, 0))

produce tensor 
  // attr [iter_var(blockIdx.x, , blockIdx.x)] thread_extent = 256
  // attr [iter_var(threadIdx.x, , threadIdx.x)] thread_extent = 512
  for (ax0.ax1.fused.ax2.fused.ax3.fused.outer, 0, 7) 
    if (likely(((blockIdx.x*512) < ((802816 - (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072)) - threadIdx.x)))) 
      tensor[(((((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/802816)*802816) + (((((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/224) % 224)*224) + ((((blockIdx.x*64) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*32)) % 224))) + ((((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/50176) % 16)*50176))] = max(((y[(((((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/802816)*802816) + (((((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/224) % 224)*224) + ((((blockIdx.x*64) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*32)) % 224))) + ((((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/50176) % 16)*50176))]*placeholder[(((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/50176) % 16)]) + placeholder[(((((blockIdx.x*512) + threadIdx.x) + (ax0.ax1.fused.ax2.fused.ax3.fused.outer*131072))/50176) % 16)]), 0.000000f)
    
  

```

## 验证结果

```python
tvm.testing.assert_allclose(out_cuda, out_cudnn, rtol=1e-5)
```

## 结论

教程介绍了cuDNN在Relay的使用。我们也支持cuBLAS。如果启用了cuBLAS,它将在全连接层(relay.dense)中使用。要使用cuBLAS,请将目标字符串设置为“cuda -libs = cublas”。您可以将cuDNN和cuBLAS用于“cuda -libs = cudnn,cublas”。

对于ROCm后端,我们支持MIOpen和rocBLAS。可以使用目标“rocm -libs = miopen,rocblas”启用它们。

能够使用外部库是很好的,但我们需要记住一些注意事项。

首先,使用外部库可能会限制你对TVM和Relay的使用。例如,MIOpen目前仅支持NCHW布局和fp32数据类型,因此您无法在TVM中使用其他布局或数据类型。

其次,更重要的是,外部库限制了图形编译期间操作符融合的可能性,如上所示。TVM和Relay旨在通过联合操作员级别和图形级别优化,在各种硬件上实现最佳性能。为了实现这一目标,我们应该继续为TVM和Relay开发更好的优化操作,同时在必要时(优化操作没有外部库性能好的情况下)使用外部库也是一种好方法。

markdown包括xcode的外部库(代码片段)

查看详情

如何在 hive 上的 python UDF 中使用外部库?

】如何在hive上的pythonUDF中使用外部库?【英文标题】:HowtouseexternallibraryinpythonUDFonhive?【发布时间】:2017-07-2906:24:06【问题描述】:我想使用PythonUDF转换配置单元表(hdfs现场实例),为此我需要一个外部库“用户代理”。我不... 查看详情

如何在我的 java 应用程序中使用外部库

】如何在我的java应用程序中使用外部库【英文标题】:Howcaniuseexternallibrariesinmyjavaapplication【发布时间】:2019-11-1609:23:22【问题描述】:我正在尝试通过使用一些外部库e.gTesseract在Java中开发一个OCRapplication,但我不知道如何将Tess... 查看详情

markdown使用自签名证书在git存储库中禁用ssl验证(代码片段)

查看详情

在 Web 组件中使用外部 JS 库

】在Web组件中使用外部JS库【英文标题】:UsingexternalJSlibrariesinawebcomponent【发布时间】:2018-11-1419:38:35【问题描述】:我正在使用Polymer2开发一个Web组件,并希望使用第三方JavaScript库,该库并非专门为与Web组件一起使用而设计的... 查看详情

如何在 kscript (Kotlin) 中使用外部存储库?

】如何在kscript(Kotlin)中使用外部存储库?【英文标题】:Howtouseexternalrepositoryinkscript(Kotlin)?【发布时间】:2019-12-0619:26:50【问题描述】:什么是让kscript从外部maven存储库加载jdbc的正确方法?我的脚本开头有:#!/usr/bin/envkscript@file:... 查看详情

在 QtCreator 中链接/使用外部库

】在QtCreator中链接/使用外部库【英文标题】:Link/useexternallibraryinQtCreator【发布时间】:2015-07-1014:10:11【问题描述】:使用mingw的Msys工具,我已经成功地从source1.1.tar.gz构建了opus-codec。该构建生成了一些文件,其中包括libopus.a和li... 查看详情

在pyspark的pandas_udf中使用外部库

】在pyspark的pandas_udf中使用外部库【英文标题】:Useexternallibraryinpandas_udfinpyspark【发布时间】:2019-08-2908:43:21【问题描述】:可以在pandas_udf中使用像textdistance这样的外部库吗?我试过了,我得到了这个错误:ValueError:Thetruthvalueofa... 查看详情

markdown清理未使用的github存储库!在6(半)-自动步骤中删除所有未使用的存储库和忘记分叉!(代码片段)

查看详情

如何在 vuejs 中使用 jest 捕获外部库的元素?

】如何在vuejs中使用jest捕获外部库的元素?【英文标题】:Howtocatchtheelementofexternallibraryusingjestinvuejs?【发布时间】:2019-03-2710:13:28【问题描述】:我在我的VueJS项目中使用来自外部库ElementUI的下拉元素。我正在尝试使用Jest测试这... 查看详情

在 msys 中使用外部库 - minGW

】在msys中使用外部库-minGW【英文标题】:usingexternallibrarieswithmsys-minGW【发布时间】:2013-01-3022:25:49【问题描述】:我想编写和编译需要FLTK1.3.2GUI库的C++代码。我想将minGW与MSYS一起使用。我已经正确安装了minGW和MSYS,并且能够使... 查看详情

text使用inprojectrepository在项目中添加外部库(代码片段)

查看详情

在 Swift 4 Playground 中使用外部库

】在Swift4Playground中使用外部库【英文标题】:UsingexternallibrariesinSwift4playground【发布时间】:2017-08-3015:11:07【问题描述】:我一直在尝试学习Swift4,因此需要使用Xcode9Beta作为IDE。我想加载一个大型CSV数据文件来使用游乐场进行一... 查看详情

使用 Rcpp 在 R 包中添加外部库

】使用Rcpp在R包中添加外部库【英文标题】:AddinganexternallibraryinRpackageusingRcpp【发布时间】:2016-06-1016:32:24【问题描述】:我正在尝试开发一个R包,它使用SundialsC库来求解微分方程。为了不让用户安装库,我将库的源代码放在我... 查看详情

markdown(原始)angular2包括外部javascript库(代码片段)

查看详情

在 angular4 的 app.component.ts 文件中使用外部库变量

】在angular4的app.component.ts文件中使用外部库变量【英文标题】:Usingexternallibraryvariableinapp.component.tsfileinangular4【发布时间】:2018-11-2208:55:11【问题描述】:我想使用在app.component.ts文件的外部js库中声明的全局变量cwic。js库作为cwi... 查看详情

在 Qt 中使用外部库(libarchive) - 没有 .lib 文件

】在Qt中使用外部库(libarchive)-没有.lib文件【英文标题】:UsingExternalLibrary(libarchive)inQt-No.libfile【发布时间】:2011-12-0208:30:02【问题描述】:我已经按照构建说明在Linux和Windows上构建了libarchive。基本上我有一些.a文件和一个dll... 查看详情

在 Java webapp 中使用 Markdown 需要啥?

】在Javawebapp中使用Markdown需要啥?【英文标题】:WhatdoIneedtouseMarkdowninaJavawebapp?在Javawebapp中使用Markdown需要什么?【发布时间】:2011-03-2905:17:41【问题描述】:我正在考虑使用以下方法将Markdown添加到Java项目中:挂毯5春天Maven(... 查看详情