机器学习编译 -- 什么是机器学习编译
机器学习编译课程主要由华盛顿大学计算机系博士生 -- 陈天奇博士讲授,在读博期间,先后带领团队打造了模块化深度学习系统NNVM(2016年)和深度学习编译器TVM(2017年),共同组成了深度学习到各种硬件的完整优化工具链。
英文课程主页 https://mlc.ai/summer22/
中文课程主页 https://mlc.ai/summer22-zh/
中文论坛:https://github.com/mlc-ai/mlc-zh/discussions
英文论坛:https://github.com/mlc-ai/mlc-en/discussions
课程介绍
随着人工智能应用在我们的日常生活中变得越来越普遍,目前存在的挑战是如何在不同的生产环境中部署最新的人工智能模型。模型和部署环境的组合爆炸给训练和推理部署带来了巨大的挑战。此外,目前落地的模型也提出了更多的要求,例如减少软件依赖、全面的模型覆盖、利用新硬件进行加速、减少内存占用,以及更强的可扩展性。
这些模型训练和推理问题,涉及机器学习编程范式、基于学习的搜索算法、编译优化以及计算运行时。这些话题的组合生成了一个全新主题——机器学习编译,并且该方向正在不断持续发展。在本课程中,我们讲按照其中的关键元素,系统地研究这一新兴领域的关键要素。我们将学习一些核心的概念,用以表示机器学习程序、自动优化技术,以及在端到端机器学习部署中优化环境依赖、内存和性能的方法。
课程受众和背景要求
本课程针对在从事机器学习工作的广泛用户。实际应用中机器学习是一个广泛的课题,涉及包括机器学习科学家、机器学习工程师和硬件供应商等多个群体之间的协作。
该课程需要的数据科学和机器学习方面的背景知识:
-
熟悉 Python 语言和 Numpy 的使用;
-
一定的深度学习框架背景知识(例如 PyTorch, TensorFlow, JAX);
-
有系统层面的编程经验更佳(例如 C/CUDA)。
步入正题。。。
什么是机器学习编译
机器学习编译(Machine learning compilation,MLC)就是将机器学习模型从它的开发形态转换到部署形态并加以优化的过程。
开发形态(Development form)指的是在开发机器学习模型时使用的元素集合。一个典型的开发形态涉及使用通用的框架如Pytorch、TensorFlow或JAX等编写的模型描述,以及与之相关的权重。
部署形态(Deployment form ) 指的是机器学习应用程序运行所需要的元素集合。它通常涉及一组生成的代码,以支持机器学习模型的每一步,管理资源(如内存)的例程,以及应用开发环境的接口(如安卓应用的java API)。
机器编译的的两个目标
-
集成和依赖最小化(Integration and dependency minimization):在框架如pytorch等让不同的实现模块整合到一起,需要支持,整合、最小化相关依赖。
部署的过程通常涉及到整合--将必要的元素组装在一起用于部署应用程序。例如,如果我们想让一个安卓相机应用能够检测到猫,我们需要组装运行花卉分类模型的必要代码,但不一定需要其他与模型无关的部分(例如,我们不需要包括NLP应用的嵌入表查询代码)。组装和最小化必要的依赖关系的能力对于减少整体规模和增加应用程序可以部署的环境的可能数量相当重要。 -
充分利用硬件原生加速技术(Leveraging hardware native acceleration):个部署环境都有自己的一套原生加速技术,其中许多是专门为ML开发的。机器学习编译过程的一个目标是利用该硬件的原生加速技术。我们可以通过构建调用原生加速库的部署形式或生成利用原生指令(如TensorCore)的代码来实现。
其实就一个问题:在执行部署模式下,如何利用好硬件本身的加速特性。
总的来说,机器学习编译的目标就是对不同目标进行优化,以最小化内存使用或提高执行效率的方式转变模型执行。如嵌入式设备如何尽可能地减少内存的使用、如何让模型更快、如何进行多机多卡的部署等等。
机器学习编译关键元素
-
张量(Tensor):就是一个多维数组,神经网络模型的输入、输出和中间结果都是以张量的形式表示
-
张量函数(Tensor Functions): 神经网络的 "知识 "被编码在权重和输入张量和输出张量的计算序列中。我们称这些计算为张量函数。值得注意的是,一个张量函数不需要对应于神经网络计算的一个步骤。部分计算或整个端到端的计算也可以被看作是张量函数。
有多种方法来实现模型在特定环境下的执行,如上面的例子。值得注意的是,有两个区别:
- 第一点,linear操作与relu操作被合并成了一个linear_relu操作。
- 第二点,有了一个特定的linear_relu操作的具体实现
当然,在现实用例中,linear_relu会使用各种代码优化技术来实现。
MLC是一个左边的东西转换到右边的过程。在不同的环境中,这可能是手工完成,也可能由一些自动翻译工具完成,或者两者都有。
抽象和实现
我们可能注意到一件事,我们用几种不同的方式来表示一个张量函数,例如,linear_relu就表示成了图形中一个紧凑的方框,内部表示嵌套循环表示。
我们用抽象(abstraction)来表示同一个张量函数的表示。不同的抽象可以指定一些细节,而忽略其他的实现细节。例如linear_relu可以用不同 for loops来实现。
抽象 和 实现 也许是所有计算机系统中最重要的关键词。
抽象 规定了 “做什么”;实现 提供了 “怎么做”,这里没有具体的界限。
根据我们的看法,for循环本身可以被看作是一个抽象,因为它可以用python解释器来实现,也可以编译成本地汇编代码。