写点什么

美团深度学习系统的工程实践

  • 2020-02-27
  • 本文字数:4444 字

    阅读完需:约 15 分钟

美团深度学习系统的工程实践

背景

深度学习作为 AI 时代的核心技术,已经被应用于多个场景。在系统设计层面,由于其具有计算密集型的特性,所以与传统的机器学习算法在工程实践过程中存在诸多的不同。本文将介绍美团平台在应用深度学习技术的过程中,相关系统设计的一些经验。


本文将首先列举部分深度学习算法所需的计算量,然后再介绍为满足这些计算量,目前业界比较常见的一些解决方案。最后,我们将介绍美团平台在 NLU 和语音识别两个领域中,设计相关系统的经验。

深度学习的计算量

ModelInput SizeParam SizeFlops
AlexNet227 x 227233 MB727 MFLOPs
CaffeNet224 x 224233 MB724 MFLOPs
VGG-VD-16224 x 224528 MB16 GFLOPs
VGG-VD-19224 x 224548 MB20 GFLOPs
GoogleNet224 x 22451 MB2 GFLOPs
ResNet-34224 x 22483 MB4 GFLOPs
ResNet-152224 x 224230 MB11 GFLOPs
SENet224 x 224440 MB21 GFLOPs


数据来源


上表列举了,ImageNet 图像识别中常见算法的模型大小以及单张图片一次训练(One Pass)所需要的计算量。


自 2012 年,Hinton 的学生 Alex Krizhevsky 提出 AlexNet,一举摘下 ILSVRC 2012 的桂冠后,ILSVRC 比赛冠军的准确率越来越高。与此同时,其中使用到的深度学习算法也越来越复杂,所需要的计算量也越来越大。SENet 与 AlexNet 相比,计算量多了近 30 倍。我们知道,ImageNet 大概有 120 万张图片,以 SENet 为例,如果要完成 100 个 epoch 的完整训练,将需要 2.52 * 10^18 的计算量。如此庞大的计算量,已经远远超出传统的机器学习算法的范畴。更别说,Google 在论文《Revisiting Unreasonable Effectiveness of Data in Deep Learning Era》中提及的、比 ImageNet 大 300 倍的数据集。

物理计算性能

面对如此庞大的计算量,那么,我们业界当前常用的计算单元的计算力是多少呢?


  • CPU 物理核:一般浮点运算能力在 10^10 FLOPS 量级。一台 16 Cores 的服务器,大致上有 200 GFLOPS 的运算能力。实际运行,CPU 大概能用到 80%的性能,那就 160 GFLOPS 的运算能力。完成上述 SENet 运行,需要 182 天。

  • NVIDIA GPGPU: 目前的 V100,单精度浮点运算的峰值大概为 14 TFLOPS, 实际运行中,我们假设能用到 50%的峰值性能,那就是 7 TFLOPS,需要 4 天。


根据以上数据结果可以看出:在深度学习领域,GPU 训练数据集所需要耗费的时间,远远少于 CPU,这也是当前深度学习训练都是采用 GPU 的重要原因。

业界的解决方案

从前面的计算可知,即使使用 GPU 来计算,训练一次 ImageNet 也需要 4 天的时间。但对于算法工程师做实验、调参而言,这种耗时数天的等待是难以忍受的。为此,目前业界针对深度学习训练的加速,提出了各种各样的解决方案。

异构计算的并行方案

数据并行(Data Parallelism)


数据并行,即每个计算单元都保留一份完整的模型拷贝,分别训练不同的数据,经过一个 Iteration 或若干个 Iteration 后,把各个计算单元的模型做一次同步。这是最常见的深度学习训练方式,好处在于逻辑简单、代码实现方便。

模型并行(Model Parallelism)


模型并行,即各个计算单元存储同一层模型数据的不同部分,训练相同的数据。相对于数据并行,因为各个运算单元每训练完一层神经网络,就必须要同步一次,频繁的同步通信导致系统不能充分地利用硬件的运算能力,所以更为少见。但是在一些业务场景下,Softmax 层需要分类的类别可能会有很多,导致 Softmax 层太大,单个计算单元无法存储,这个时候,需要把模型切割成若干部分,存储在不同的运算单元。模型并行常见于 NLU、推荐、金融等领域。

流式并行(Stream Parallelism)


流式并行,即每个计算单元都存储不同层的模型数据,训练相同的数据。如上图所示,GPU1 只负责第一层神经网络的计算,GPU2 只负责 2~5 层神经网络的计算,GPU3 只负责第 6 层的计算。流式并行的好处在于每个运算单元之间的通信和计算重叠(overlap),如果配置得当,可以非常充分地利用硬件资源。缺点在于,根据不同的模型,需要平衡好各个计算单元的计算量,如果配置不好,很容易形成“堰塞湖”。如上图所示,很有可能出现 GPU1 负责的运算量太少,而 GPU2 负责的运算量太多,导致 GPU1 和 GPU2 之间堵塞住大量的 Mini-batch,更常见于线上环境。

混合并行(Hybrid Parallelism)


混合并行,即上面提到的并行方式的混合。如对于一些图像识别任务来说,可能前几层使用数据并行,最后的 Softmax 层,使用模型并行。

异构计算的硬件解决方案

  • 单机单卡:一个主机内安装上一块 GPU 运算卡。常见于个人计算机。

  • 单机多卡:一个主机内安装上多块 GPU 运算卡。常见的有:1 机 4 卡,1 机 8 卡,甚至有 1 机 10 卡。一般公司都采取这种硬件方案。

  • 多机多卡:多台主机内安装多块 GPU 运算卡。常见于公司内部的计算集群,一般多机之间采取 Infiniband 来实现网络的快速通信。

  • 定制化:即类似于 Google 的 TPU 解决方案。常见于“巨无霸”公司内部。

异构计算的通信解决方案

根据上面的硬件解决方案,我们以 ResNet 为例:模型的大小为 230M,单张图片运算量为 11 GFLPOS,Mini-batch 假设为 128。可以计算出各个硬件模块在深度学习训练中的耗时比较:


  • GPU:对于 V100,假设有 6 TFLOPS,一次 Mini-batch 理论耗时:0.23s。

  • PCI-E:常见 PCI-E 3.0 * 16,速度为 10 GB/s,传输一个模型的理论耗时为:0.023s。

  • 网络:假设为 10 GB/s 的高速网络,传输一个模型的理论耗时:0.023s。

  • Disk:普通的磁盘,我们假设 200M/s 的读取速度,读取一次 Mini-batch 所需要的图片耗时:0.094s。


根据上面的数据结果,我们似乎可以得出一个结论:PCI-E 和网络的传输耗时,相对于 GPU 来说,整整少了一个数量级,所以网络通信同步的时间可以忽略不计。然而问题并没有那么简单,上面例子中的耗时只是单个模型的耗时,但是对于 8 卡的集群来说,如果使用数据并行,每次同步就需要传输 8 份模型,这就导致数据传输的时间和 GPU 的计算时间“旗鼓相当”。这样的话,GPU 就得每训练完一个 Mini-batch,都得等候很久的一段时间(采取同步更新),这会浪费很多计算资源。因此,网络通信也需要制定对应的解决方案。下面我们以 Nvidia NCCL 中单机多卡的通信解决方案为例介绍,而多机多卡的通信解决方案其实是类似的。



上图是单机 4 卡机器,在硬件上,两种不同的通信体系。左边为普通的 PCI-E 通信,即 4 个 GPU 之间组成一个环状。右边为 NVLink 通信,即两两之间相互连接。


常见的通信类型如下图所示



对于深度学习训练而言,关键的两种通信类型为:Broadcast 和 Reduce。Broadcast 用于 Master 分发最新的模型给各个 GPU。Reduce 用于各个 GPU 计算完 Mini-batch 后,把模型更新值汇总到 Master 上。以 Broadcast 为例,最简单的通信方式是 Master 往各个 GPU 上发送数据,这样的耗时就是 4 次模型传输的时间,通信时间就会太长,一种简单的优化方法如下图所示:



即把所需要传输的数据分成若干块,然后通过接力的方式逐个传递,每个 GPU 都把自己最新的一块数据发送到下一个 GPU 卡上。这种传输方式能充分利用硬件层面的通信结构,使得需要的耗时大幅缩减。与此类似的,Reduce 的通信优化也可以采取相同的方式进行提速。

美团的定制化深度学习系统

尽管目前在业界已经推出了很多著名的深度学习训练平台,通用的训练平台如 TensorFlow、MxNet 等等,还有领域专用的训练平台,如语音识别中的 Kaldi,但是我们经过调研后,决定内部自主开发一套深度学习系统,理由如下:


  • 通用的训练平台,缺乏了领域特色的功能。如语音识别中的特征提取模块和算法。

  • 通用的训练平台,通常是基于 Data-flow Graph,来对计算图中的每个 operator 进行建模,所以颗粒度很小,需要调度的单元多,导任务调度复杂。

  • 领域特色的训练平台,如 Kaldi,在神经网络训练的时候,性能不足。

  • 线上业务存在很多特殊性,如果使用 TensorFlow 之类作为训练平台,不太适合线上业务的情景。

NLU 线上系统

线上系统的业务特点

我们在设计 NLU 线上系统时,考虑了 NLU 业务的一些特性。发现其具备如下的一些特点:


  • 随着业务和技术的变化,算法流程也经常发生变化。

  • 算法流程是多个算法串联组成的,不单纯的只有深度学习算法。如分词等算法就不是 DL 算法。

  • 为了能够快速响应一些紧急问题,需要经常对模型进行热更新。

  • 更重要的是,我们希望构建一个能以“数据驱动”的自动迭代闭环。


业务多变


NLU 任务的算法流程是多层级的,并且业务经常发生变化。如下图所示:



即随着业务要求的变化,NLU 系统一开始的算法流程,只需要把一个 Query 分为两个类,但是到后面,极有可能会变成需要分为三个类别。


热更新


根据业务需求,或者为了紧急处理一些特殊问题,NLU 线上系统经常需要做出快速响应,热更新算法模型。如最近的热点词“skr”,几乎是一夜之间,突然火爆起来。如下图所示的微博,如果不能正确理解“skr”的正确语义,可能就不能准确理解这条微博想要表达的意思。



为了避免影响用户体验,我们可能会对 NLU 系统,马上进行热更新,把新模型紧急进行上线。


数据驱动的自动迭代闭环



对于线上系统而言,构建如上图所示的自动迭代闭环,能更好地利用业务数据来提升服务质量。

NLU 线上系统的核心设计

算法流程的抽象


为了适应线上系统串联、多变的算法流程,我们把线上系统的算法进行抽象,如下图所示:



即每一个算法,都依赖于若干个槽位(Slot)和资源(Resource),一旦槽位和资源就位,就会触发对应的算法执行。算法的执行先通过算法适配器,来适配槽位和资源中的数据,转换成算子的输入格式。然后算子执行算法本身,执行完算子后,再经过算法解析器。算法解析器主要用于解析算法执行的结果,触发对应的槽位。如根据算法的结果,触发 Top 3 的结果。


多个算法串联起来,就构建成如下结果:



热更新流程的设计



如上图所示,我们把算法的热更新流程设计如上。初试状态为左上角,即多个 Query 使用同一份模型数据。当遇到模型更新的请求后,系统将会 block 住新的 query(右上角状态)。然后更新模型完后,新的 query 使用新的模型,旧 query 依然使用旧模型(右下角状态)。最后,当使用旧模型的 query 结束后,把旧的模型从内存中删除(左下角),然后系统恢复到初始状态。

声学模型训练系统

因为 TensorFlow 等通用深度学习训练平台,缺乏了特征提取等业务相关的领域功能,而 Kaldi 的声学模型训练过程又太慢。所以美团开发了一个声学模型训练系统——Mimir,其具备如下特性:


  • 使用比 TensorFlow 更粗颗粒度的建模单元,使得任务调度、优化更简单方便易行。

  • 使用数据并行的并行方案,单机多卡可达到近线性加速。(采取同步更新策略下,4 卡加速比达到 3.8)

  • 移植了 Kaldi 的一些特有的训练算法。

  • 速度上为 Kaldi 的 6~7 倍。(800 个小时的训练数据,单机单卡的条件下,Kaldi 需要 6~7 天, Mimir 只需 20 个小时)

  • 业务上,移植了 Kaldi 的特征提取等领域的相关模块。

参考资料

作者简介

  • 剑鹏,美团点评算法专家。2017 年加入美团,目前作为语音识别团队的声学模型负责人,负责声学模型相关的算法和系统设计与开发。


2020-02-27 10:501425

评论

发布
暂无评论
发现更多内容

MySQL-技术专题-InnoDB存储引擎

码界西柚

Golang+Flutter实现聊天APP

Alber

IM Go 语言

并不想吹牛皮,但!为了把Github博客粉丝转移到公众号,我干了!

小傅哥

Java 小傅哥 博客 微信公众号

契约测试:解决微服务测试的问题

陈磊@Criss

Python中的单下划线和双下划线使用场景

wangkx

Python Python基础知识 Python基础

国内与国外区块链关键技术现状及差异

CECBC

区块链 应用技术

为什么修改hosts不立即生效?--浏览器DNS缓存机制分析

陈磊@Criss

记一次腾讯云(西安)后台开发面试经历

z小赵

面试 分布式 高并发

MySQL-技术专题-共享锁与排他锁

码界西柚

知道时间轮算法吗?在Netty和Kafka中如何应用的?为什么不用Timer、延时线程池?

yes

kafka Netty Timer ScheduledThreadPool 时间轮

LeetCode题解:88. 合并两个有序数组,双指针遍历+从前往后,JavaScript,详细注释

Lee Chen

大前端 LeetCode

鲲鹏一粤,智算万里

脑极体

如何隐藏你的数据库密码

Rayjun

安全 服务器

Go: Goroutine, 系统线程和CPU管理

陈思敏捷

mpg Go 语言

区块链一新基建 新动能 新发展大会将在南昌举办

CECBC

新基建 区块链技术

抽象类、接口、Trait

书旅

接口 面向对象 抽象 对象 Trait

源码分析 | Mybatis接口没有实现类为什么可以执行增删改查

小傅哥

Java 源码分析 小傅哥 mybatis

架构师训练营 - 第 7 周命题作业

红了哟

想要成功,你需要的是目标与动机,目标是你的助攻,动机是你的爱人。

叶小鍵

成功学 心理学 海蒂·格兰特·霍尔沃森

Github被攻击。我的GitPage博客也挂了,紧急修复之路,也教会你搭建 Jekyll 博客!

小傅哥

Java GitHub 小傅哥 博客

Dubbo2.7试用

心平气和

dubbo 灰度 hessian

Git命令可视化展示,代码管理再也不愁了,建议收藏!

诸葛小猿

git git merge git rebase git fetch git reset

架构师训练营 - 第十周作业

坂田吴奇隆

Flexible Box Layout 原理剖析

coolion

CSS 大前端

一文了解对称加密与非对称加密

我是程序员小贱

安全

MySQL 架构与历史

多选参数

MySQL 数据库 MySQL优化

用故事去理解「文件 I/O」

小林coding

操作系统 异步 文件系统 同步 非阻塞网络I/O

数据治理第一步,摆脱“手工作坊”

KAMI

大数据 数据治理 数据开发 数据平台

【DevOps】我们忽视了Daily Build(每日构建)吗?

Man

DevOps jenkins 每日构建

Git设置分支保护实现CodeReview卡点

陈磊@Criss

手把手教你从零开始使用python编写大型冒险类游戏01之游戏介绍

Geek_8dbdc1

美团深度学习系统的工程实践_文化 & 方法_美团技术团队_InfoQ精选文章