1. 摘要
Q 音探歌是 QQ 音乐孵化的一款全新 App, 主打高效, 准确的 "听歌识曲","扫描识别 MV" 功能, 这些服务的实现离不开深度学习能力. 把深度学习推断带到边缘设备( inference on the edge ), 可以减少计算时间, 改善用户体验, 但是也面临着种种挑战. 我们希望本文提供的观察, 见解和我们针对不同平台的设计原则能够帮助大家更好地设计和评估移动端的深度学习推断.
2. 介绍
2.1 深度学习的边缘化发展的机遇
越来越多的服务会使用到深度学习的能力, 例如给用户聚类, 识别动作与跟踪, 语音识别等等. 尽管所有的训练都还在专门的数据中心进行, 但是越来越多的人将深度学习推断, 过渡到边缘, 过渡到手机端执行. 虽然相比于训练计算, 推断计算所需的算力更低, 这为在能耗限制更严格的移动端进行推断提供了可行性. 但是, 在移动端执行边缘计算需要克服一些独特的挑战.
2.2 硬件多样性与软件多样性带来的挑战
尽管推理所需的算力小于训练所需, 但是移动端设备的碎片化限制了很多可能的方案. 图 1 显示了从 2016 年开始, 国内 Android 手机市场销量占比 85% 的设备的 CPU GFLOPS 性能分布. 该图显示了在 Android 设备上的巨大性能差异, 必须考虑这些性能差异, 才能在所有设备上高效, 实时的运行我们的服务. 如果我们谨慎的使用一个完全兼容低端设备的策略将不能充分发挥高端设备的计算能力. 同时, 也可以看到, 随着时间的流逝, 整体的算力是不断提升的. 为了使所有的模型都能高效的运行, 我们一直在研究和优化技术方案.
图 1: 国内的移动手机市场呈现出差异性很大的分布. 数据样本占整个市场份额的 85%以上, 并按相应的手机发布年份进行排序. 高低端手机性能可能相差一个数量级, 这增加了性能优化的设计难度.
2.3 对于移动芯片没有一致的优化方法
移动端设备性能差异巨大, 我们考虑对占比较大的移动端设备进行针对性优化, 以获取整体召回数据的提升, 为此, 我们调研了 Q 音探歌的部署情况. Q 音探歌的学习算法已经部署在上千种不同的机型中, 图 2 显示了不同机型的市场份额的累积分布函数(CDF). 数据描绘得很清楚: 没有 "典型" 的智能手机. 最常用的设备型号不到所有移动设备的 3%. 此外, 该分布显示出异常长的尾巴: 只有 7 种机型的市场份额超过 1%, 它们的联合覆盖率仅占市场的 10.6%.
图 2: 没有可优化的标准移动机型. 前 50 名最常见的机型仅占智能手机市场的 25.4%
在生产过程中, 智能手机硬件碎片化极为严重. 这种多样性来自 SoC 中多个组件的组合, 包括 CPU,GPU, 共享缓存, 内存控制器, 图像处理器, 数字信号处理器 (DSP) 甚至是专用的神经网络加速器( NPU). 每个移动芯片供应商都将其定制设计的组件与其他公司的组件进行混合和匹配. 硬件的碎片化在 Android 上尤为突出.
2.4 移动端 CPU 区别不大
CPU 的一般可用性和可编程性使其成为边缘计算的默认选项, 因此, 我们更关注 CPU 的结构差异. 在我们的数据集中, 绝大多数移动 CPU 使用 ARM Cortex-A53 和 Cortex-A7 内核, 图 3 显示了设计或发布智能手机 CPU 内核的年份细分. 目前, 用于移动设备的 72%的 CPU 内核是 6 年前设计的. Cortex A53 占整个移动处理器的 48%以上, 而 Cortex A7 则占移动处理器的 15%以上, 而较新的 CPU 分布更加多样化.
图 3: 最常用的移动处理器 Cortex A53 已有至少六年的历史. 在 2018 年, 只有四分之一的智能手机搭载了 2013 年或以后设计的 CPU 内核.
我们观察到移动端和服务器芯片出现了类似的多核趋势. 99.9%的 Android 设备具有多个内核, 而 98%的内核具有至少 4 个内核. 我们发现 Android 和 iOS 智能手机之间存在截然不同的设计策略 - iOS 设备倾向于使用更少, 功能更强大的内核, 而 Android 设备倾向于拥有更多的内核, 而这些内核通常功能不那么强大.
大约一半的 SoC 具有两个 CPU 集群: 一个高性能内核集群和另一个节能内核集群. 只有一小部分包含三个核心集群. 不同群集中的核心可能在微体系结构, 主频设置或缓存大小方面有所不同. 少数 SoC 甚至具有由相同内核组成的两个群集. 在几乎所有的 SoC 中, 同一集群中的内核都具有共享的缓存, 但是不同集群中的内核之间没有共享缓存级别. 缺少共享缓存会导致群集之间的同步成本很高. 因此, 我们可以通过一些手段, 例如线程数或者核心数来选择高性能 CPU 集群执行神经网络算法.
2.5 移动端的 CPU 和 GPU 的性能差别不大
高性能的 GPU 在深度学习的成功中发挥了重要作用. 移动 GPU 在边缘神经网络推断中扮演类似的角色似乎很自然. 但是, 由于移动 GPU 的性能限制, 碎片化问题以及可编程性限制, 目前大多数的的 Android 设备都在移动 CPU 上运行推断.
图 4 显示了 Android 上 CPU 和 GPU 之间的 GFLOPS 性能比. 在绝大多数设备中, GPU 的 GFLOPS 性能要超过 CPU 的 GFLOPS 性能. 90%的 GPU 性能是其 CPU 的两倍以上, 而有 15%的性能是其 CPU 的 10 倍. 这种性能分布不是历史产物, 而是市场细分的结果: 中端 SoC 通常具有比高端 SoC 慢 10%至 20%的 CPU. 针对不同细分市场的 GPU 的差距更大, 高中端 GPU 的性能差距是 5 到 10 倍. 实际使用时, 有限的内存传输带宽进一步限制了 GPU 性能. 与高性能离散 GPU 不同, 移动设备上没有专用的高带宽内存传输通道, 在移动端中, 移动 CPU 和 GPU 通常共享同一内存控制器, 争夺稀缺的内存带宽.
图 4: 移动 CPU 和 GPU 之间的 GFLOPS 性能差距较小. 在中端的 Android 设备中, GPU 的性能大约是其 CPU 性能的 5 倍. 有 15%的智能手机的 GPU 性能是其 CPU 的 10 倍.
2.6 可用的协处理器 DSP 和 NPU
DSP 是应用于特定场景的协处理器, 非常特定机器学习的推断计算. 我们探索 DSP 主要是为了降低功耗与提高运行效率(每瓦电能执行的运算次数). 然而, 由于缺乏可编程的手段, 在移动端运用 DSP 依然面临很大挑战, 尽管很多供应商都在添加矢量计算 DSP, 但要看到大量的市场份额可能还需要很多年.
大部分 DNN 算法的规律性使得 NPU 特别适于深度学习. 许多学术研究项目, 初创公司和大公司公司都在此领域提出了解决方案. 最著名的 NPU 是华为的 Kirin 970 SoC 中的 Cambricon 1A 和 Apple A12 Bionic SoC 中的神经引擎(Network Engine). 尽管目前 NPU 占比相对较少, 但我们可能正在达到一个转折点.
2.7 边缘推断的优化
边缘计算的优化主要包括模型框架的选择, 权重共享, 量化算法, 降低算法复杂度以及针对系统架构进行特定调整. 这些优化, 使得我们可以在移动端 CPU 上去执行深度学习推断, 考虑到深度学习模型的复杂度, 且大多数移动端 CPU 性能较低, 这已经是一项不小的壮举.
2.8 小结
首先, 目前几乎所有边缘计算都在 CPU 上运行, 并且大多数的移动 CPU 内核都是老旧且低端的. 在我们的数据集中, 绝大多数移动 CPU 使用 ARM Cortex-A53 和 Cortex-A7 内核. 在中等性能的 Android 设备中, GPU 的性能大约是 CPU 的 5 到 10 倍. 只有 15%的 Android 智能手机的 GPU 性能是其 CPU 的 10 倍以上.
其次, 系统多样性使将代码移植到协处理器 (例如 DSP) 变得困难. 我们发现采用对所有设备环境都起作用的常规优化更为有效. 当我们可以控制系统环境 (例如, Oculus VR 平台) 时, 或者处于多样性很少且成熟的系统中 (例如, iPhone) 时, 可以通过协处理器提高性能.
再次, 对于移动端设备来说切换到协处理器的主要原因是能耗更低和执行时间更稳定, 次要原因是计算速度更快.
最后, 移动设备的算力差异远比后台服务器大的多. 对于要求实时响应的面向用户的应用程序来说, 差异性带来了很大的挑战. 为了研究这些差异带来的影响, 针对性的进行优化, 需要进行现场性能建模.
总而言之, Q 音探歌采用了数据驱动的设计方法: 快速增长的设备差异性带来了很多性能, 准确率的挑战, 我们倾向于使用专注在边缘实现高效深度学习的平台化工具和基础架构来帮助我们实现深度学习服务. 同时, 机型的差异性使我们很难执行细粒度的特定于设备的优化, 在生产环境中进行机器学习的性能评估建模和现场研究十分重要.
3. 移动端协处理器编程研究
可编程性是使用移动端协处理器的主要障碍, 要想使用移动端 GPU 执行神经网络算法, Android 上编程的主要 API 是 OpenCL,OpenGL ES 和 Vulkan, 而 iOS 上主要是 Metal.
3.1 OpenCL
OpenCL 旨在使应用程序能够在可编程的协处理器上运行. 因此, OpenCL 不提供特定于图形的功能, 例如 3D 渲染. 专注于通用计算的好处是: OpenCL 的 API 支持对内存空间的管理, 高效的线程切换能力使之比面向图形的 API(如 OpenGL)更有计算效率. 但是, 尽管大多数 Android 设备附带了 OpenCL 驱动程序, 但 OpenCL 并未正式成为 Android 系统的一部分, 并且它未通过与 OpenGL ES 和 Vulkan 相同的单元测试. 根据 Facebook 在 2018 年统计的数据显示, 如图 5 所示, 相当一部分 Android 设备搭载了损坏的 OpenCL 驱动程序. 最糟糕的是有 1% 的设备在尝试加载 OpenCL 库时会发生崩溃. OpenCL 的库和驱动如此不稳定, 因此无法大规模使用.
图 5: OpenCL 在 Android 端的部署情况
3.2 OpenGL ES
事实证明, OpenGL ES 是一种可行的选择. OpenGL ES 是专用于移动和嵌入式系统的 OpenGL API 的精简版本. 作为图形 API, 最开始版本的 OpenGL ES 并不适合 GPGPU(General-purpose GPU 通用 GPU)编程. 但是, 最新版本的 API 提供了足够的功能来对神经网络计算进行编程. 不同的版本决定了我们可以使用移动 GPU 做什么, 目前市场上有多个版本的 OpenGL ES.
3.2.1 OpenGL ES 2.0
OpenGL ES 2.0 是移动端 OpenGL 的第一个版本. 使用 OpenGL ES 2.0, 可以通过 RTT(Render To Texture)技术实现神经网络运算符, 但是 API 的固有局限性限制了计算的存储空间. 所有计算都必须在片段着色器 (Fragment Shader) 内进行, 而一个片段着色器只能输出 16 位数据. 因此, 多通道卷积或矩阵乘法将需要多次读取相同的输入. 计算模式类似于在 CPU 上的进行矩阵点积乘法.
3.2.2 OpenGL ES 3.0
OpenGL ES 3.0(或更高版本)支持 93%的 Android 设备. 这是可用于神经网络实现的 OpenGL ES 的第一个版本. 与 2.0 类似, 所有计算都需要在片段着色器中实现, 但是 OpenGL ES 3.0 支持多种功能以提高效率. 例如, 片段着色器的每次调用可输入 128 位数据, 同时还使用统一缓冲区加载常量(例如权重).
3.2.3 OpenGL ES 3.1
OpenGL ES 3.1(或更高版本)支持 90%的 Android 设备. 它引入了计算着色器(Compute Shader), 这些着色器提供了 OpenCL 1.x 和早期版本的 CUDA 中可用的类似功能. 例如在 GPU 上启动内核以减少图形管线的开销, 工作组内的快速同步等等.
图 6 显示了目前市场占比较大的 Android 设备的 OpenGL ES 的覆盖情况.
图 6: OpenGL ES 在 Android 设备的覆盖情况
3.3Vulkan
Vulkan 是 OpenGL 和 OpenGL ES 的后继产品. 它提供与 OpenGL ES 3.1 类似的功能, 同时具有一些减少内存开销的新 API. 展望未来, Vulkan 是一个很有前途的 GPGPU API. 目前, 限制 Vulkan 的的主要原因是覆盖率, 虽然 google 从 Android 7 之后开始从软件层面支持了 Vulkan, 但是也必须要 GPU 也支持 Vulkan 才可以, 根据 Facebook2018 年的统计只有不到 36%的 Android 设备搭载了 Vulkan, 根据 google 的数据, 2019 年大约有 73% 的设备支持 Android 7 以上的版本(并不代表都可以运行 vulkan), 根据我们在优测平台的统计数据, 大约有 76% 的设备搭载了 vulkan, 覆盖情况如下图 7 所示.
图 7:Android 设备的 Vulkan 覆盖情况
3.4Metal
Metal 是 Apple 的 GPU 编程语言. iOS 设备上的移动 GPU 描绘出与 Android 截然不同的画面. 由于 Apple 的移动芯片组是垂直设计的, 因此操作系统可以更紧密地集成到 iPhone 中. 自 2013 年以来, 所有从 A7 开始的 Apple 移动处理器都支持 Metal.Metal 与 Vulkan 相似, 但具有更大的市场份额和更成熟的系统堆栈支持. 95%的 iOS 设备支持 Metal. 而且, GPU 和 CPU 之间的峰值性能差异达到 3-4 倍, 这使得配备 GPU 的 iOS 设备上的 Metal 成为实现高效神经网络推理的最佳选择.
3.5 一些开源框架的 GPU 编程方案对比
我们在表 1 里统计了市面上比较常见的几种开源框架的 GPU 编程策略. 可以看到在 iOS 上, 使用 Metal 是主流, 包括 Tensorflow-Lite 和 Pytorch Mobile 都使用了这种方案. 而 Android 端的选择则要复杂的多. 很多框架开始采用 vulkan 来实现神经网络算法, 也有一些框架选择去兼容比较复杂的情况, 例如像 Caffe2, 它甚至会针对 Nivida 的 CUDA 平台去做适配工作.
Android | iOS | |
---|---|---|
NCNN | vulkan | vulkan(需要额外引入三方库) |
MNN | vulkan,OpenGL ES,OpenCL | Metal |
MACE | OpenCL | OpenCL |
Tensorflow-Lite | OpenGL ES | Metal |
Paddle-Lite | vulkan | Metal |
Caffe2(Pytorch Mobile) | vulkan,OpenGL ES,OpenCL | Metal |
表 1: 几种常见开源框架的 GPU 编程方案对比
深度学习算法推断要在移动端落地, 需要着重衡量尺寸和性能的限制, 同时又要尽可能的提供给用户较好的体验(推断速度足够快).
More...
在接下来的章节里, 我们将会介绍 Q 音探歌对比各机器学习框架的过程, 机器学习服务落地的一般流程, 最后, 我们将总结整个过程中的一些经验, 结论. 敬请期待.
来源: http://www.tuicool.com/articles/f2Yn6nz