QCon 演讲火热征集中,快来分享技术实践与洞见! 了解详情
写点什么

快手针对大型推荐模型的性能优化

  • 2023-03-27
    北京
  • 本文字数:3930 字

    阅读完需:约 13 分钟

快手针对大型推荐模型的性能优化

北京时间 2023 年 3 月 23 日 11:00,在英伟达 GTC 开发者大会上,来自快手的软件架构师梁潇分享了题为《针对大型推荐模型的性能优化》的演讲,介绍了快手如何通过平衡 CPU 和 GPU 的工作负载,实现大型推荐模型的性能优化。



在本文中,我将分享改进大模型推荐服务的一些经验——包括如何通过平衡 CPU 和 GPU 之间的工作负载,使得资源利用更加平衡,并提高系统吞吐。也希望能提供一些在日常工作中充分利用 GPU 算力的经验。

 

快手作为热门的短视频平台,日活用户就达到了 3.6 亿,日均时长为 129 分钟。为了提高用户体验,我们需要在个性化推荐领域做出非常多的努力。

 

与业界很多场景的推荐方案不同,我们的推荐服务主要面临两个挑战:

首先我们必须提供实时训练,以确保新近上传的视频可以在短时间内被推荐出来;

其次是模型的规模——个性化推荐需要大量特征进行准确预测,从而导致模型非常庞大。


例如,我们的精排模型使用了超过 1000 亿个特征,大约 1.9 万亿个稀疏参数。对于这样一个模型,常规的做法导致 80% 以上的时间都花在 CPU 计算上(包括特征抽取和 Embedding 处理),而只有 20% 的时间用于模型推理。这导致整个系统是一个高度内存密集型的系统。如果我们仅仅将模型推理部分移到 GPU 上,CPU 仍然会是整个系统的瓶颈,导致 GPU 的利用率受到限制。

 

为了解决这些问题,我们对这个系统做了很多改进:消除 CPU 瓶颈的最基本的想法是将 CPU 工作负载转移到远程服务器上。



有了这些远程服务器,我们可以很容易地通过调整两种服务器的实例个数来平衡系统,从而最大限度地减少对现有代码的修改。然而,在实际工作中,这种方法并不奏效。


首先,因为模型特征的数量很大,会导致这两种服务器之间的网络流量很高。

其次,为了处理网络数据包,GPU 服务器也会承担额外的内存访问开销,从而导致实际性能收益降低。我们对此做过评估,远程服务器的方案会对系统带来 20% 的额外开销,效果并不理想。

 

另外一种方案是通过平衡 CPU 和 GPU 的工作负载来优化整个系统——所有的工作都在同一台服务器上完成。这样做非常易于部署,并能同时充分利用 CPU 和 GPU 资源。这个方案的实现关键是:将部分负载转移到 GPU 上。为了做到这一点,我们首先要深度于优化 CPU 算法,并且提升模型在 GPU 上推理的效率。推理所需的时间越少,就意味着有更多的 GPU 算力可以用来承载从 CPU 上迁移的算法。此外,我们还尝试在 GPU 端缓存数据,从而减少对 DRAM 的访问量。



在实施这些优化之后,GPU 利用率从 20% 大幅提高到近 90%,整个系统的吞吐量提高了 10 倍以上。

 

大家可以先看一下系统的整体流程。



当服务接收到一个请求的时候,Feature Extractor 会向调度器请求 Data Slots。Data Slot 是 Data Context 的一部分,而一个 Data Context 可以理解为批任务(Batching)的数据存储单元,它被同时映射到 CPU 和 GPU 地址段上,因此调度器可以将 Context 中的数据在 CPU 和 GPU 之间自由迁移。调度器等这个 Data Context 填充完毕,就会将它发送到推理引擎。


与很多方案不同,在特征抽取开始之前,Data Context 就已经分配好了。虽然这会导致分配更多的内存(因为占用时间变长了),但是它让调度器对这个批任务有了更加充分的信息,可以选择更好的推理策略。特征抽取是在 CPU 或 GPU 上运行的算法,运行结果也可以直接保存在 GPU 内存中。在引擎部分,我们同时支持 TensorRT 和 Tensorflow。TensorRT 性能较好,但因为 Tensorflow 的兼容性更好,我们仍然需要它做一些对性能不太敏感的实验或验证。

 

在整个系统中,调度器(Scheduler)是最为关键的组件:因为我们需要对请求进行打包批处理(Batching),从而提高 GPU 的利用率。然而,在不同的时间段,每个请求中的候选视频个数并不均匀。调度器需要将请求定向到不同的 Batch,以确保尽可能将每个 Batch 填满。


为了提高性能,我们使用的是 Fixed-Size Model 进行推理(即输入 Tensor 的 bs 维度是固定的,不能改变),然后再通过调度器加载多个不同 Batch Size 的模型。例如,如果有 5 个请求,总计 200 个候选视频组成了 Batch,我们可以使用一个 bs = 256 的模型来推理。如果有 900 个候选视频,则会选择 bs = 1024 的模型。调度器负责维护不同 bs 的模型,并根据不同批次的大小选择合适的模型。


其次,调度器需要支持 dense 参数的实时更新,因此需要能够降低更新时对服务稳定性的影响(尤其是当有许多模型实例一起服务时,这种影响更加明显)。最后,调度器需要在内存密集型系统中考虑 NUMA 和 PCI-e 的亲和性。跨 NUMA 访问对系统延迟和吞吐的影响很大,调度器需要知道处理线程在哪个 CPU 上,并尽量把结果放在相应的 NUMA 节点上。根据测试,我们设计的调度器的吞吐量大约是 Tensorflow-Serving 的 2 倍。

 

TensorRT 的性能很好,但它对算子的支持能力有限,因此加载模型相对复杂。目前,官方并不提供从 Tensorflow 到 TensorRT 的解析器,我们实验后决定不从 ONNX 模型进行解析。最主要的原因是希望保留 Tensorflow 中的高语义运算符,这些运算符更易于编写 Kernel Funsion。



我们设计的模型加载器包含多个模块:首先是一个简单的 Parser,将 Tensorflow 模型文件解析成内存中的图结构(Graph),然后将图传递给 Graph Transformer,后者用来解决算子不兼容问题。假设某个算子不被 TensorRT 支持,Transformer 就会进行基于规则进行局部搜索,以确定是否能将某个包含这个算子的子图替换成另一个完全等价、且与 TensorRT 兼容的子图。Graph Fuser 用于算子融合,但对于实时更新的系统,有一些需要进行权重变换的融合并不容易实现。例如,右图所示的融合方式,需要将权重融合到一起。Weights Transformer 会记录这些融合步骤,并在参数更新期间按照这些步骤依次执行,从而保持训练侧不需要改变。经过这些步骤之后,Graph 就可以被 TensorRT 加载了。Builder 会负责将其转换成 TensorRT 的 Engine。

 

在针对 TensorRT 的性能调参中,我们总结了一些相关经验以供参考。或许在不同的项目里面,其他的参数配置性能更好,所以建议在做出决定前尝试每个参数。


首先,我们发现 Model Refit 对于实时更新权重更加友好。因为 Model Reload 非常耗时,从而导致更新期间的 P99 时延升高。即便使用了 TensorRT 8 中的 Timing Cache 机制,耗时仍然不可接受。然而,开启 Refit 会禁用掉一些 Point-wise Fusion,后续需要手工实现这些 Fusion。


其次,我们更加推荐使用 Explicit Batch,而不是 Implicit Batch。不仅因为 Explicit Batch 在设计图时更加灵活,还因为它的性能更好——如果模型图中的 shape 是固定的,TensorRT 可以优化得更好。缺点如前所提,如果使用 Explicit Batch 就需要调度器加载不同 Batch Size 的多个模型实例以适应不同 Batch。


此外,我们没有使用 Dynamic Shape,因为在项目实际测试中,Dynamic Shape 的性能比 Fixed Shape 低。使用如上设置后,TensorRT 在大部分场景下比 TensorFlow XLA 快 20%。

 

在 GPU 中缓存 Embedding 也是减少 CPU 负载和内存访问的有效方式。由于 Embedding 数量很大,我们使用远程服务器存储,本地使用了 Embedding Cache 的机制来降低网络访问量,这种方式还减少了远程调用过程中网络包解析带来的带宽影响。在我们的系统中,使用了 1GB 的缓存大小,就已经缓存了大约 60% 的 Hot Embedding。为了进一步减少 CPU 的工作量,我们将 Embedding 量化为 8bit,并且没有使用 LRU 的更新策略。



如下是一些测试结果:与完全没有缓存的版本相比,如果完全缓存在 CPU 内存中,可以节省 5% 的 CPU 利用率。这主要来自远程调用量的降低。如果将 Embedding Data 转移到 GPU 上,可以再节省 5% 的 CPU 利用率,以及 50% 的 H2D 带宽。如果将 Cache Index 也转移到 GPU 上,效果将更加明显。这项工作仍在进行着,从初步结果来看,与目前工业界解决方案相比,性能有 1.2 倍的改进。相关细节信息可以在我们的论文中查看。

 

将特征抽取算法转移到 GPU 上也可以改善系统性能。通常来讲,在 GPU 上实现特征抽取算法并不容易,因为这些算法有很多条件分支,难以并行化。然而,在我们的场景中,这件事情仍然很有意义:在特征抽取后,数据量会显著增加,导致 H2D 的同步时间变长。另外,访问 GPU 内存比访问 CPU 内存快很多,这对于内存密集型的系统有明显的收益。 此外,迁移后 CPU 的工作量降低可以进一步提高系统各个运算单元的平衡。



例如,对于 Sum-Pooling 算法,最初的 CPU 版本改写成 GPU 版本后,CPU 内存访问减少了近 1GB/s,耗时降低了 45%。如果对实现高性能的特征抽取算法有兴趣,可以参考 cuDF 和 Velox。

 

下图总结了各个性能优化方案的效果。



我们的主要任务是平衡 CPU 和 GPU 之间的工作负荷,因此需要迭代式地对 CPU 和 GPU 代码进行优化。比如,在进行 Kernel Fusion 之前,我们花了大量精力优化 CPU 端的算法,大幅降低了内存访问压力。否则,在 GPU 上优化的性能收益会因为 CPU 瓶颈被掩盖。在图中,可以看出 Scheduler 是其他优化的基础,之后我们通过减少 CPU 内存访问和 GPU 上 Kernel Fusion 的方式提升了整体的吞吐。当这些事情做完之后,CPU 仍然是系统的瓶颈。我们尝试通过在 GPU 上进行数据缓存和将特征抽取算法转移到 GPU 上来减少 CPU 的工作量。上述优化总计优化了系统整体吞吐约 10.5 倍。

 

以下为内容的总结。我们讨论了几种改善内存密集型系统吞吐量的方法。


首先,需要优化 CPU 算法,降低访存量;

其次,需要提高 GPU 推理效率,使 GPU 腾出算力承载更多算法;

再次,可以将 CPU 的算法迁移到 GPU 上,减轻 CPU 的工作压力;

最后,在 GPU 中缓存数据可以减少 H2D 的同步时间,并降低 DRAM 的访问量。


以上这些优化方法,可以使得整体系统更平衡,并帮助我们在成本可控的情况下,为用户提供更好的服务。

2023-03-27 17:287408

评论 2 条评论

发布
用户头像
1000亿个特征???
2024-10-11 10:46 · 上海
回复
1000亿特征维度还是特征个数???
2024-10-11 16:37 · 上海
回复
没有更多了
发现更多内容

出海蓝军先锋联想来酷,今夏再征"丝路"

Geek_116789

架构师训练营——第四周作业

jiangnanage

架构师训练营-第4周总结

坂田吴奇隆

极客大学架构师训练营

第四周学习总结

李白

第三周总结

李白

架构师训练营 - 系统架构

Pontus

极客大学架构师训练营

Mac开发环境 React Native0.60 环境 安卓环境Java变量 及~/.zshrc文件配置

蛋蛋

React

真棒! 20 张图揭开内存管理的迷雾,瞬间豁然开朗

小林coding

Linux 操作系统 计算机基础 内存管理

架构师训练营 No.4 周总结

连增申

信创舆情一线--数据安全法草案提请初审

统小信uos

大数据 安全

猿灯塔:关于Java面试,你应该准备这些知识点

猿灯塔

面试

消息队列(六)如何处理消费者故障导致的百万消息积压?

奈何花开

Java MQ 消息队列

架构师训练营第四周总结:互联网架构概要

hifly

高可用 高性能 极客大学架构师训练营 互联网架构

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

心在飞

极客大学架构师训练营

架构师训练营第 04周——总结

李伟

极客大学架构师训练营

时间管理的本质到底是什么?

非著名程序员

程序员 提升认知 时间管理

可读代码编写炸鸡四(上篇) - 来写注释

多选参数

代码质量 代码 代码注释

为什么大公司一定要使用DevOps?

张启华

架构师训练营第四周作业

Bruce Xiong

第三周作业

李白

可读代码编写炸鸡三 - 审美

多选参数

代码质量 代码 代码注释

印度下黑手!59款中国APP被禁用,微信微博QQ抖音等在列

程序员生活志

作业 - 第4周

Happy-Coming

JDBC拾遗

qihuajun

架构师训练营 第4周作业

坂田吴奇隆

极客大学架构师训练营

分布式计算DAG1-画猫

Hervor。

Python中进行None判断时,为什么用is而不是==

王坤祥

Python 编程 进阶 计算机基础

自己动手编译一个HEIF图片转jpeg工具(Mac平台)

GeorgeMR

HEIF HEIC jpeg 图片

一个大型互联网应用采用的技术方案和手段

李白

父亲节会员礼遇免费送,联想来酷重点发力"健康赛道"

Geek_116789

数据库周刊30丨数据安全法草案将亮相;2020数据库产业报告;云南电网上线达梦;达梦7误删Redo Log;Oracle存储过程性能瓶颈;易鲸捷实践案例……

墨天轮

MySQL 数据库 oracle mongodb 周刊

快手针对大型推荐模型的性能优化_语言 & 开发_快手技术_InfoQ精选文章