1. 深度学习编译器概述:为什么需要深度学习编译器?
大家好,我是老张。做深度学习编译器这块也有些年头了。今天咱们聊聊最基础的问题——为什么我们需要深度学习编译器?
说实话,我刚入行那会儿也觉得奇怪。深度学习框架不是挺多的吗?PyTorch、TensorFlow,直接用不就行了?干嘛还要搞个编译器出来?
嗯,后来我在一个落地项目里被狠狠教育了一回。那次要在嵌入式设备上跑一个BERT模型,PyTorch导出的模型直接跑,推理延迟200多毫秒。客户要求50毫秒以内。我折腾了整整两周,各种算子优化、手工调优,最后勉强压到80毫秒。后来用TVM重新编译了一遍,你猜怎么着?直接干到45毫秒。
从那以后,我就明白了——深度学习编译器不是锦上添花,而是刚需。
1.1 为什么需要深度学习编译器?
说白了,深度学习编译器要解决的核心问题就一个:让模型在不同硬件上跑得又快又好。
你想想看,现在的深度学习模型越来越复杂。几年前还是几层的CNN,现在动不动就是上百层的Transformer。硬件平台更是五花八门——NVIDIA的GPU、AMD的GPU、华为的昇腾、寒武纪的NPU、各种ARM的CPU、甚至还有RISC-V的AI加速器。
每个硬件都有自己的"脾气":
- GPU喜欢并行计算,但不同架构的GPU对算子支持不一样
- NPU通常只支持有限的算子集合,需要把复杂算子拆解
- CPU上跑模型,内存带宽往往是瓶颈
我在一个项目里遇到过这种情况:同一个卷积算子,在NVIDIA V100上跑得飞快,换到华为昇腾310上就慢得像蜗牛。为什么?因为昇腾对某些卷积配置没有硬件加速,需要拆成多个小算子来执行。手工做这件事?累死你。
核心观点:深度学习编译器的本质,是把"写一次模型,到处都能高效运行"这个理想变成现实。
1.2 深度学习编译器与传统编译器的区别
很多人第一次接触深度学习编译器,会拿它和GCC、LLVM这些传统编译器做对比。我建议你换个角度想——它们解决的问题域完全不同。
传统编译器,比如GCC,输入的是C/C++代码,输出的是机器码。它的优化目标很明确:让程序跑得更快,或者让代码体积更小。优化手段也相对固定:常量折叠、循环展开、指令调度、寄存器分配等等。
但深度学习编译器呢?输入的是一个计算图,输出的是针对特定硬件的可执行代码。它的优化目标要复杂得多:
| 对比维度 | 传统编译器 | 深度学习编译器 |
|---|---|---|
| 输入 | 高级语言源码 | 计算图(DAG) |
| 输出 | 机器码/汇编 | 硬件可执行代码 |
| 优化目标 | 执行速度、代码体积 | 推理延迟、吞吐量、内存占用、功耗 |
| 优化粒度 | 指令级别 | 算子级别 + 图级别 + 指令级别 |
| 硬件适配 | 相对通用 | 高度定制化 |
| 典型代表 | GCC, LLVM, MSVC | TVM, XLA, Glow, nGraph |
你看,区别还是挺明显的。我个人的理解是:传统编译器做的是"翻译+优化",深度学习编译器做的是"理解+重构+优化"。
为什么会这样?因为深度学习模型的计算图有很强的语义信息。比如一个卷积算子,编译器知道它是在做特征提取,可以尝试各种等价变换——Winograd算法、FFT变换、Im2Col+GEMM等等。传统编译器面对的是通用代码,它不知道这段代码到底在干什么,所以不敢做太激进的变换。
一个小技巧:如果你之前做过传统编译器,转来做深度学习编译器,记得把思维从"指令优化"切换到"图优化"上来。我刚开始就犯过这个错,花了很多时间在底层指令优化上,结果发现图级别的融合和重排带来的收益更大。
1.3 深度学习编译器的核心价值
总结一下,深度学习编译器到底能给我们带来什么?
- 硬件抽象:你不需要为每个硬件平台手写算子。写一次模型,编译器帮你适配。
- 自动优化:算子融合、内存规划、并行调度,这些脏活累活编译器替你干了。
- 性能可移植:同一个模型在不同硬件上都能获得接近最优的性能。
- 降低开发成本:不用再养一个"算子优化团队"了。
我记得有一次跟一个做芯片的朋友聊天,他说他们公司之前每个新芯片出来,都要花三个月时间适配主流框架的算子。后来用了TVM,这个时间缩短到了两周。这就是深度学习编译器的价值。
注意:深度学习编译器不是万能的。对于某些极端场景(比如要在特定硬件上榨干每一分性能),手工优化的算子可能还是比编译器生成的代码快10%-20%。但编译器胜在通用性和开发效率。我的建议是:80%的场景用编译器,剩下20%的关键路径再手工调优。
1.4 知识体系总览
下面这张图是我自己整理的深度学习编译器知识体系,你可以把它当作整个课程的地图:
这张图展示了深度学习编译器的完整工作流程。从输入的计算图开始,经过前端、中端、后端三层优化,最终生成可执行代码。每一层都有自己独特的优化技术和中间表示(IR)。
后面的课程,我们会一层一层地深入进去。前端优化讲算子融合和形状推断,中端优化讲自动调度和内存规划,后端优化讲硬件特化和指令生成。每一层都有很多坑,我会把我在项目中踩过的坑都告诉你。
好了,这一章就到这里。记住一句话:深度学习编译器,本质上是在"计算图"和"硬件"之间搭一座自动化的桥。理解了这一点,后面的内容就好办了。
公众号:蓝海资料掘金营,微信deep3321