目前微博多模态内容理解服务支持了 40 多个业务集群,120 多个深度模型在线推理,峰值 QPS 2 万+,覆盖大多数主流框架和 NLP、CV 算法。本文将介绍微博多模态内容理解服务架构和 GPU 异构集群方案,主要包括分布式模型训练,Flink 实时流在线推理,GPU 性能对比,稳定性保障等相关内容。
背景介绍
1. 关于微博
微博现在大家都在用,但是可能用的比较少,尤其是近些年各种社交视频以及内容类的一些应用爆发,大家的空闲时间也不太够分配。不过目前微博定位来讲,它确实是一个国民级的应用。多数年轻人或者多数国人手机中都会有一个微博 APP 客户端,至少在吃瓜时,大家会去看一看。从独立设备数上来讲,微博依然在增长。从用户活跃度数据上来讲,现在月活是 5 亿,日活平均 2.2 亿。多模态内容理解每天的工作,是对微博博文中包含的视频、图片、文本以及语音相关的数据进行内容的理解。理解这些内容怎么用在微博整个生态体系里,怎么能为微博用户提供更好的效果、更好的内容。现在每天的微博的发博量接近 8000 万数据,带有话题的博文可能 730 万。这个数据也是我从艾瑞咨询上去找的一个公开数据。
2. 多模态内容理解—在微博的挑战
大数据:
基于这个背景,微博有现在数据量级之后,多模态内容理解会遇到什么样的问题?首先是数据量非常大,博文的数量在 7000 万到 8000 万之间,图片的数量在 4000 万到 5000 万之间。我们每天很多的模型都需要处理这些全量的图片,整个集群模型数大概有 100 多个模型,支持大概 40 多种业务集群。
异构化:
第二点异构化,业务模型本身的算法非常多,因为我们支持不同的业务方。每一位业务同学都有自己对业务的理解和技术兴趣点,所以他们会用各种各样新的数据、新的算法、新的框架来实现他们的业务诉求,都需我们要能够提供支持。所以我们对于主流的框架包括:TensorFlow、PyTorch、Caffe、Paddle Paddle 等,算法类型从图像算法到文本算法都支持。
标准化:
这种异构化就给我们带来另一个挑战,就是说我们怎么做到标准化?因为我们不可能对每一个模型都定制化,这样后期维护成本特别高,对稳定性也不利。我们的模型怎么支持这么大的数据量处理?我们内部的核心是基于 c++开发了一套 RPC 框架,把模型和核心架构做了分离。模型本身可以通过基于 python 去实现,通过一个我们自研 DAG 的 pipeline 框架做一个桥接,服务端引擎是基于 thriftRPC 实现。
平台化:
平台化是因为我们服务的数量非常多,有的服务对实时性有要求,比如说一条博文发布之后,可能要求几秒钟或者一分钟之内,必须在运营平台侧产生结果、或者部分下游业务会依赖这个结果,所以对实时性要求很高。对于实时性要求高的这些模型,同样对稳定性要求也高。不能说数据中断后,导致后续所有链路都不可用。
以上四点就是我们在平台化这边遇到的一些挑战。
3. 多模态内容理解—应用场景
我们的应用场景,主要有三类应用:分析类,检索类,描述类。
分析类模型用来分析视频、文本、图片是什么内容,能够提取哪些特征出来。
检索类就是说我们形成统一 embedding 的形式,做人脸检索、相似性检索或者物料去重。
描述类就是做图像描述、视频描述或者机器翻译这之类。
除了单个的模型以外(单纯的基于某一个算法对图片或对视频去识别它特征),我们对不同的模型之间会进行进一步的融合,就是多模态融合。从整个多模态内容理解模型角度来讲,是各模型之间相互串联、组合,以及模型内部算法的融合。这就是我们团队面临的一个现状。
多模态内容理解架构
刚才简单分享了我们的背景和应用场景,接下来跟大家分享下内容理解的架构。
1. 多模态内容理解工作流
这是我们的多模态内容理解工作流。我们现在整个平台支持从样本生成、模型构建、模型评估、模型注册、模型服务的应用链路。为什么内容理解需要有样本生成?训练跟 serving 之间是什么关系?我们的设备从规模上来讲已经非常大,而且历史比较悠久,整个系统是从 17 年开始构建,到现在有三年多时间。就现在来讲,这么大的规模和异构系统的场景还是比较少见,算是微博内部承接业务最多的机器学习中台团队。
做样本生成、做模型训练,也是为了加深对模型的理解,为用户在内容理解的工作流上提供一站式服务,不用来回拷贝模型、或者拷贝样本,可以通过样本的标注、小样本的学习,实现模型所需要的数据。我们这边也有自研的分布式训练框架。现在虽然对 CV 来讲,可能分布式的诉求不是特别大,但对 NLP 类的任务,语料库非常大,对于分布式的需求还是比较迫切的。我们在分布式的训练上,效果对比开源的系统是有一个 9 倍的效率比提升。
我们有完善的一套模型的注册、存储、管理的机制,以及一些模型分发、版本控制机制。对模型服务来讲,我们可以做到一键式模型自动化上线,配套资源管理、机器管理、模型运营、全链路监控等基础能力。
2. 多模态内容理解架构
这是我们的内容理解架构,从数据收集开始,数据收集可以用于在线推理,也可以用于离线模型训练。离线模型训练通过样本标注、样本处理,最终数据到样本库。模型训练的流程是直接从样本库里面去读取用户所选择的样本数据、样本格式,训练完之后,做完评估之后模型进入模型库。所以样本库和模型库是我们在线推理之前必须准备好的两份数据。
模型进入模型库之后,可以开始部署多模态推理服务。早期实时流我们是基于 Storm,现在我们的框架都逐步迁移到 Flink。Flink 可以比较好的处理数据的反压。经过多媒体推理服务,数据以特征的形式输出。特征是我们整个内容理解最终要做的事情,从数据的收集、标注、处理、训练到最终的线上的实时处理,最终目的就是为了拿到微博的相关特征。有特征之后,我们就可以对整个的微博建立物料库,可以用于进一步反馈到用户的终端做推荐、排序、审核、去重,从而形成整个链路的闭环。
3. 多模态内容理解优势
我们现在的优势是什么?可以分为以下 4 点:
稳定性方面,我们平均的稳定性可以达到三个九,特殊作业可以保障六个九。
低延迟,我们现在因为都是接实时流的处理,基本上整个的平均延时是在秒级实时调用的。特殊的情况,我们可以做一些进一步优化,可以在毫秒级拿到一个结果。
开发效率,把一些常见的流程模块化,通过统一的页面 UI,业务方自己就可以进行配置,实现想要的效果,让业务方自己把控模型训练、更新、迭代的节奏。
训练推理一体化,刚才我们讲为什么我们要做这样本做模型的训练,就是为了让用户不用来回的传输模型,减少他们的工作量,简化流程,提高效率。
GPU 异构集群
介绍完背景、多模态内容理解、架构应用场景、闭环的流程。下面讲一下 GPU 在我们业务场景下到底是怎么应用的。因为 GPU 用的比较早,在我们手头的 GPU 最老的有五年以上型号,也有比较新的英伟达 V100S。基本上每个时代的高性能计算的产品我这边都有,这也是给我们整个服务带来一定的挑战,就是怎么用好这些性能不一样的 GPU。
1. 异构硬件 GPU vs CPU 及技术挑战
关于 GPU 和 CPU 的不同,大家其实应该都有一定的了解,GPU 肯定就是要用来做加速的,但是在我们这个场景下来讲,因为非常复杂,不同的模型、不同的处理方式、不同的算法之间的组合,如果不同的模型部署在同一张卡上,他们对资源的利用方式抢占方式是不一样的。我们现在这边 100 多个模型彼此之间怎么做资源隔离?早期我们是手动的圈一批机器,手动打标签划分小集群来部署服务。这种方法存在扩容比较困难的问题。如果说流量上涨了,要扩容的话,这批机器所有服务都需要手工去扩容,非常不方便。或者说机器出现故障需要迁移,都需要手动去迁移。现在基于虚拟化系统化的技术(包括 cGPU 和 GPUManager)和 Kubernetes 做云原生的开发运维一体化,统一进行调度。资源分配会从 CPU、内存、磁盘、显存、算力、网络这六个维度来考虑。为什么会有磁盘和网络这两个维度?因为磁盘本身来讲,后面有一个案例也会讲到这个,多模态涉及到的视频有视频文件、视频 tar 包,以及图片,这些文件要处理的时候都需要通过网络下载到本地的磁盘上,在磁盘上进行处理。这样的话,就对网络提出了要求,网络吞吐量如果不够的话,那么同一时间并发就可能会受到的影响。那么磁盘也是这样的,如果说性能就处理速度跟不上,磁盘会被写满,然后机器被驱逐,最后服务挂掉。在我们整个的服务来讲都是需要考虑的。
2. 多模态内容理解与 GPU 相关到常见问题
以上是我们常见的一些问题,模型服务应该怎么去优化?QPS 不稳定不定怎么办?不稳定是什么原因?我们之前服务刚上线的时候跑得很好,然后因为更多的服务部署了,突然之间有的节点 QPS 不稳定了。从监控上看,服务整体错误率上升,进一步查询会定位到固定的或者是某几台机器上。
那么 GPU 利用率低是什么情况?GPU 成本很高,因为利用率低的机器可能是只占显存,但是算力很低。这样的话就是说应该是模型内部来讲,他把对于在 CPU 层面做了一些 IO 的这些操作,没有优化的好,可能都是一些串行的操作,导致数据在 GPU 层面运算的时间非常短,没有充分利用。那么多个模型共享 GPU 就一定可以提升 QPS 吗?不一定,多个模型共享 GPU 跟 QPS 不稳定,可以说是一个问题。多个模型都部署在同一个 GPU 卡上,他们之间会产生算力的竞争,比如说一个模型是 50%,但是部署两个是不是就百分之百的?不是这样的。如果说你对这两个模型他们的数据处理的结构是不一样的,甚至可能两个部署上去之后,它们的利用率会进一步下降。
按显存划分总量是不是合适呢?我们在服务部署时,只考虑显存,比如说一张 16G 显存 V100 卡,或者一张 16G 显存 T4 卡,一个模型占用了 4G 显存,是不是表示还可以继续部署 3 个一样的服务呢?只考虑个显存就会造成 QPS 不稳定。对我们来说,算力的考量应该是更重要的一个特征。
GPU 利用率已经百分之百了,或者是 90%,是不是已经满负荷运行?其实并不是,GPU 利用率本身并不表示它里边的所有的单元都参与运算,可以通过优化代码,提高单次数据吞吐量。做过训练的同学会比较了解,提升 batch size 会很好的提升 GPU 的利用率,因为它一次读进去的数据量很大,参与运算单元更多。
多种型号的 GPU 应该怎么合理分配?我们 GPU 是跨了很多年代,就是五年以上了,五年每年都会有新的 GPU 采购,老的型号也不能扔掉就不用了。所以这里面怎么再去使用?这个也是我们现在解决以及持续解决的一些问题。目前来说我们采用的方式这些 GPU 如果统一混合部署,实现来讲是没问题的,就是说你把所有的 GPU 当成一样的,但这样带来的问题就是说你在不同的 GPU 上,每个模型处理速度是不一样的。V100 和 M40 它们之间的差距就非常大,不同的卡之间显然也是不一样的。所以目前来讲我们还是说在测试的时候用什么样的模型去测,那么上线时实际相应的服务就给你匹配什么样的卡,这样的话能做到测试的性能和上线的性能基本上能够保持一致。
3. 异构 GPU 集群功能特性
K8S 资源调度:
我们现在一个 GPU 集群规模差不多 1000 张 GPU 卡。目前所有的 GPU 都是通过 Kubernetes 做资源的调度,通过 ResourceQuata 实现资源的管理。我们早期只是对 CPU 内存做资源限制,但是对显存和算力其实没有进行隔离,就导致了有一些特别的固定的问题。所以,我们也在逐步的优化。
模型加速:
第二点就是通过分布式训练框架对模型加速,通过在线推理引擎加速,对推理服务进行加速。最大限度的发挥单卡性能。
显存/算力隔离:
现在是通过 cGPU 和 GPUManager 来实现显存资源的任意切分。那么 cGPU 是阿里级的一个虚拟化的技术,只能在阿里云的机器上用,但是 GPUManager 是腾讯开源的一个工具,可以在任何机器上去用。他们的区别是什么?cGPU 支持的是显存,从 1 到 15 就是卡的大小,单位是 G。GPUManager 默认将显存切分为最小粒度是 256M,选择 1 默认申请 256M 显存。算力切分为 1~100,它们两个区别 cGPU 不用去关心在 K8S 文件上要加配置,不用去关心算力的分配情况。
服务/镜像管理:
把服务和镜像作为服务保障的重要手段,我们现在因为服务本身来讲会出现一些异常的情况,如何保障稳定性?如果把模型和依赖环境都分开处理,在节点需要扩容或者需要回滚的时候,时间是很长的。所以我们将模型和依赖统一作成镜像,把每一个稳定版本的模型和环境封装在一起,做到快速的回滚。一些自动更新的数据,也支持远程的挂载,通过对象存储支持数据定时更新。
灰度部署及自动扩缩容机制:
灰度的部署以及自动扩缩容,做过服务的同学应该是都是有经验的,因为你再怎么压测,它上线之前都要经过一定的灰度才能进一步的去保障服务的稳定。自动扩缩容是为了应对流量波峰低谷,每天不同时间段流量在波动。每个节假期或者热点事件来临,都需要对服务进行扩容。只是依赖监控,手动扩容总是很难及时跟上流量爆发,这必须依赖自动扩缩容机制。
全链路监控:
第六点就是全链路的监控。监控、压测、灰度这几个手段都是做在线服务必须经历的过程,也是每一个在线服务所必备的一些基础的设施。如果你没有一个就是日志的收集的工具,没有统一监控,没有平均耗时,没有 P99、P95,那么服务的稳定性很难保障。
4. GPU 性能优化之分布式训练加速
上图就是我们现在做过的一些训练、推理的一些性能方面的数据。从这个数据来看分布式训练这一块,绿色是现在所具备的训练的能力。右边效率比,我们在 P100、V100 在四机十六卡这种情况下,P100 可以 4.64 的效率比,V100 有一个 9.37 的效率比。
5. GPU 性能优化之在线推理
在线推理这一块,我们选择了比较主流的几种卡,进行了一些测试,这个数据跟我们从官网上看到的纯粹的算力的情况还是有一定区别的。比如说拿 T4 和 V100 来说,T4 和 V100 数据差距不到两倍。T4 官网给的算力单精度的算力的话是 8.1,V100 是 15.7。在实际测试结果来讲,V100 性能应该是更高一点。这个是为什么?这个应该是 V100 它的内存带宽 900GB,T4 是 320GB。而且 V100 本身的功耗更高是 300 瓦,P、T4 是 70 瓦。V100 能够维持一个长期的高速的运转,T4 如果长期它超负荷运转的话它自己去做一个主动的降频。
6. GPU 性能优化之模型推理加速
上图是一个在线推理加速的一个实验,我们基于模型文件本身做一个加速,从加速的结果上来看,有 20%~40%的提升,它不同的模型在表现上不太一样。刚才讲的这些就是除了在这种集群管理部署服务的稳定性,我们对模型训练、模型推理也做了很多的工作,其目的都是为了稳定服务整个内容理解的任务下,充分利用我们 GPU 集群、充分发挥 GPU 的算力。
7. GPU 全方位监控
上图是我们现在 GPU 的一个单节点监控,包括 GPU 使用率、显存读写时间,显存使用量以及 GPU 温度、功率,CPU 的情况、TCP 链接、进程、TCP 连接数,这里边为什么要有 TCP 连接数?就是对服务来讲,一个机器上会接很多的服务,然后会上游会记不同的数据流,那么有的服务可能会使用很多的长连接,或者说有的服务并发非常大,会导致我们出现连接被打满的情况,所以我们要对 TCP 连行监控。除了 GPU 的监控以外,我们对服务本身也是有监控的,服务的进程是否存在、结果的延迟是多少、总的 QPS 情况、单节点的 QPS 的情况等。有时候服务本身是在运行的,但是它的服务的波动是什么样子的?比如之前一台机器 QPS 是 100,一段时间之后就会下降,这种异常的监控我们都有。
总结来说,我们是基于微博生态,对微博的图像、视频、文本、语音这些数据,实现基于算法、基于模型的内容理解,最终结果写入到特征工程,从特征工程生成物料,最终又反馈到微博的客户端,让用户去消费。实现了从端上用户的生产到一系列的流程之后,又回到端上,让用户去消费的生态闭环。这就是关于 GPU 在微博内容理解的所有内容。
嘉宾介绍:
储芾坪
微博 | 机器学习模型服务负责人
本科毕业于北京师范大学,研究生毕业于中科院计算所,现在是微博机器学习模型服务负责人。
本文转载自:DataFunTalk(ID:dataFunTalk)
原文链接:GPU在微博多模态内容理解的应用
评论