使用 TVM 将深度学习模型编译到 WebGL
现在 TVM 推出一个全新的 OpenGL/WebGL 后端!这篇博文将解释它是什么,以及您可以使用它实现什么。
OpenGL/WebGL 后端
TVM 已经针对许多后端,涵盖各种平台:CPU、GPU、移动设备等…… 这次我们添加了另一个后端:OpenGL/WebGL。
OpenGL/WebGL 使我们能够在没有安装 CUDA 的环境中使用 GPU。在目前看来,这是在浏览器内部使用 GPU 的唯一方法。
这个新的后端允许我们以 3 种不同的方式使用 OpenGL/WebGL
- 本地 OpenGL:我们可以将深度学习模型编译成 OpenGL,并直接在本地机器上运行它,完全使用 Python。
- WebGL 与 RPC:我们可以将深度学习模型编译成 WebGL,并通过 Emscripten 将其导出为共享库,包括 JavaScript 主机代码和 WebGL 设备代码。然后,我们可以通过 RPC 将该库部署到浏览器内部运行的 TVM JavaScript 运行时系统上。
- WebGL 与静态库:我们可以将深度学习模型编译成 WebGL,将其与 TVM JavaScript 运行时系统链接,并导出整个软件包。然后,我们可以在浏览器中的网页上运行该模型,而无需任何依赖项。详细流程如图 1 所示。
我们依赖 Emscripten 及其 fastcomp LLVM 后端来生成 javascript 后端。
图 1
请参阅此处,查看所有这三种方式的示例。
这与 X 有何不同?
在浏览器上运行神经网络并不是一个全新的事物。Andrej Karpathy 的 ConvNetJS 和 Google 的 DeepLearning.JS 就是这样的例子。
那么 TVM 与 WebGL 的独特之处是什么?最大的不同在于 TVM 中的算子内核是自动编译的,而不是手写的。如图 2 所示,TVM 利用统一的 AST 来定义内核,并将其编译为不同平台上的代码。
图 2
这意味着
- 要将您现有的模型部署到 WebGL,您不需要编写大量额外的代码。NNVM/TVM 模型定义对于所有目标都是相同的,因此您只需要将其编译为新的目标即可。
- 要添加新的算子内核,您只需要在 TVM 中定义一次,而不是为每个目标实现一次。您不需要知道如何编写 GLSL 代码来为 WebGL 添加新的算子内核!
基准测试
在这里,我们对一个典型的工作负载进行基准测试:使用 resnet18 进行图像分类。
我使用的是我的5 年旧的笔记本电脑,它配备了 8 核 Intel® Core™ i7-3610QM 和 GTX650M。
在这个基准测试中,我们从 Gluon 模型动物园下载了一个 resnet18 模型,并对一张猫的图像执行端到端分类。我们只测量模型执行时间(不包括模型/输入/参数加载),并且每个模型运行 100 次以获得平均值。结果如图 3 所示。
图 3
基准测试在 4 种不同的设置下运行
- CPU (LLVM):模型被编译成 LLVM IR 并进行 JIT 编译。因此,它完全在 CPU 上运行。
- OpenCL:模型被编译成 OpenCL。仍然有一些胶水代码被编译成 LLVM,它负责设置和启动 OpenCL 内核。然后我们在本地机器上运行它。
- OpenGL:与 OpenCL 相同,但编译为 OpenGL。
- WebGL:胶水代码被编译成 LLVM,并使用 Emscripten 的 Fastcomp LLVM 后端转换为 JavaScript。设备代码被编译成 WebGL。我们在 Firefox 中执行模型。
从上面的结果我们可以观察到,TVM OpenGL 后端具有与 OpenCL 相似的性能。更有趣的是,浏览器内部的 WebGL 版本并没有比桌面 OpenGL 慢很多。考虑到主机代码是 JavaScript,这非常令人惊讶。这可能是由于 Emscripten 生成了 asm.js,它在 Firefox 中实现了显著的优化。
这是朝着自动将深度学习模型编译到 Web 浏览器的第一步。随着我们将优化引入 TVM 堆栈,我们期望获得更多的性能改进。
给我看代码
- 查看这个完整的代码示例。
致谢
我们感谢 Emscripten 的开发者提供了 fastcomp 工具链,并在开发过程中提供了帮助。