导读:
本文将以下三个方面开展介绍:
- DeepRec背景(咱们为什么要做DeepRec)
- DeepRec性能(设计动机和实现)
- DeepRec社区(最新公布的2206版本次要性能)
DeepRec背景介绍
咱们为什么须要稠密模型引擎?TensorFlow目前的社区版本是可能反对稠密场景的,然而在以下三个方面存在一些性能上的短板:
- 晋升模型成果的稠密训练性能;
- 晋升模型迭代效率的训练性能;
- 稠密模型的部署。
因而咱们提出了DeepRec,其功能定位在稠密场景做深度的优化。
DeepRec所做的工作次要在四大方面:稠密性能、训练性能、Serving、以及部署& ODL。
DeepRec在阿里巴巴外部的利用次要在举荐(猜你喜爱)、搜寻(主搜)、广告(直通车和定向)等几个外围场景。咱们也给云上的一些客户提供了局部稠密场景的解决办法,为其模型成果和迭代效率的晋升带来了很大帮忙。
DeepRec性能介绍
DeepRec的性能次要分为以下五大方面:稠密性能Embedding,训练框架(异步、同步),Runtime(Executor、PRMalloc),图优化(结构化模型,SmartStage),serving部署相干性能。
1. Embedding
Embedding局部将介绍以下5个子性能:
1.1 动静弹性特色(EV)
上图的右边是TensorFlow反对稠密性能的次要形式。用户首先定义固定的shape的Tensor,稠密的特色通过Hash+Mod的形式map到刚刚定义的Tensor上。这个逻辑上有4个问题:
- 稠密特色的抵触,Hash+Mod的形式容易引入特色抵触,这会导致无效特色的隐没,进而影响成果;
- 存储局部会导致内存的节约,有局部内存空间不会被应用到;
- 固定的shape,一旦Variable的shape固定了,将来无奈更改;
- 低效的IO,如果用户用这种形式定义Variable,必须通过全量的形式导出,如果Variable的维度很大,那么无论导出还是加载都是非常耗时的,但咱们在稠密的场景其实变动的局部是很少的。
在这种状况下,DeepRec定义的EmbeddingVariable设计的原理是:将动态的Variable转化为动静的相似HashTable的存储,每来一个key,新创建一个Embedding,这样就人造地解决了特色抵触的问题。通过这样的设计,当特色特地的多的时候,EmbeddingVariable无序的扩张,内存耗费也会变得很大,因而DeepRec引入了以下两个性能:特色准入和特色淘汰。它们都能无效的避免特色扩大到很大的维度。在搜寻和举荐这样的稠密场景,有些长尾特色被模型训练的次数非常少。因而特色准入能通过CounterFilter或者BloomFilter的形式对特色进入EmbeddingVariable设置一个门槛;在模型导出Checkpoint的时候也会有特色淘汰的性能,工夫上比拟老的特色也会被淘汰。这在阿里外部某个举荐业务AUC晋升5‰,在云上某举荐业务AUC晋升5‰,pvctr也有晋升4%。
1.2基于特征频率的动静弹性维度特色(FAE)
通常状况下同一个特色对应的EmbeddingVariable会被设置为同一个维度,如果EmbeddingVariable被设置一个较高的维度,低频的特色内容容易导致过拟合,并且会耗费大量的内存。相同的如果维度设置的过低,高频的特色内容则有可能因为表白的能力有余而影响模型的成果。FAE的性能则提供了对于同一个特色里,依据不同特色冷热来配置不同的维度。这样让模型主动进行训练时第一个是模型的成果能失去保障,第二个也能解决训练对资源的应用。这是对于FAE性能的出发点的介绍。这个性能的应用目前是让用户传入一个维度和统计的算法,FAE主动依据实现的算法来产生不同的EmbeddingVariable;前面DeepRec打算在零碎外部自适应的发现去调配特色的维度,从而进步用户的易用性。
1.3自适应EmbeddingVariable
这个性能和第二个性能有些相似,都是以定义高低频的关系作为出发点。当后面提到的EV特地大时,咱们会看到内存占用特地高。在Adaptive Embedding Variable中咱们用两个Variable来表白,如右图展现。咱们会定义其中一个Variable为动态的,低频的特色会尽可能映射到这个Variable上;另外一个则定义为动静弹性维度特色,用于高频局部的特色。Variable的外部反对低频和高频特色动静的转换,这样的长处是极大升高了系统对内存的应用。例如某个特色训练后第一维可能有靠近10亿,而重要的特色只有20%-30%,通过这种自适应的形式后,能够不须要那么大的维度,进而极大的升高了对内存的应用。咱们在理论利用发现对模型的精度影响是很小的。
1.4 Multi-Hash Variable
这个性能是为了解决特色抵触的问题。咱们原来是通过一个Hash+Mod的形式解决特色抵触,当初用两个或多个Hash+Mod去失去Embedding,并且随后对失去的Embedding做Reduction,这样的益处是能用更少的内存来解决特色抵触的问题。
1.5 Embedding多级混合存储
这一性能的出发点同样也是发现EV在特色个数多的时候,内存开销非常大,训练的时候worker占用的内存可能达到了几十上百G。咱们发现,特色实际上遵循典型的幂律散布。思考到这个特色点,咱们将热点特色放到CPU这样更贵重的资源,而绝对长尾低频的特色则放到绝对便宜的资源中。如右图,有DRAM、PMEM、SSD三种构造,PMEM是英特尔提供的速度介于DRAM和SSD之间,但容量很大。咱们目前反对DRAM-PMEM、DRAM-SSD、PMEM-SSD的混合,也在业务上获得了成果。云上有个业务 原来用200+多CPU分布式训练,当初应用多级存储后改成了单机GPU训练。
以上是对Embedding所有性能的介绍。咱们做这些性能的动机是因为TensorFlow的几个问题(次要是特色抵触),咱们解决的计划是动静弹性特色和Multi-Hash特色,针对动静弹性特色内存开销较大的问题,咱们又开发了特色准入和特色淘汰的性能;针对特色频次,咱们开发了3组性能:动静弹性维度和自适应动静弹性特色是从维度的方向解决的问题,多级混合存储则是从软硬件的方向解决的问题。
2. 训练框架
第二个要介绍的性能是训练框架,分为异步和同步两个方向来介绍。
2.1异步训练框架StarServer
在超大规模工作状况下,上千个worker,原生TensorFlow存在的问题是:线程调度非常低效,要害门路开销凸显,另外小包通信非常频繁,这些都成为了分布式通信的瓶颈。
StarServer在图的线程调度、内存的优化方面做得很好,将框架中Send/Recv批改为了Push/Pull语义,PS在执行的时候应用了lockless的办法,极大地提高了执行的效率。咱们比照原生框架有数倍的性能晋升,并且在外部3Kworker左右的数量能达到线性的扩大。
2.2同步训练框架HybridBackend,
这是咱们为同步训练开发的计划,它反对数据并行和模型并行混合分布式训练。数据读取通过数据并行来实现,模型并行能反对大参数量训练,最初应用数据并行做浓密计算。咱们针对不同EmbeddingLookup的特色,做了多路Lookup合并的优化,分组优化,还利用了GPU Direct RDMA的长处,基于网络拓扑的感知,设计整个同步的框架。
3. Runtime
第三个大方面的性能是Runtime,次要介绍PRMalloc和Executor优化。
3.1 PRMalloc
首先是内存调配,内存调配在TensorFlow和DeepRec中都是无处不在的,咱们首先在稠密训练中发现,大块内存调配造成了大量的minorpagefault,此外在多线程的调配中也存在并发调配的问题。咱们在DeepRec中针对稠密训练前向反向的特点,设计了针对深度学习的内存调配计划,称为PRMalloc。它进步了内存使用率和零碎的性能。在图中能够看到次要的一块是MemoryPlanner,它的作用是在模型训练的前k轮的minibatch先统计以后训练的特点,每次须要调配多少Tensor,将这些行为记录通过bin的buffer记录下来,并且做相应的优化。在k步后,咱们将其利用,从而极大缩小上述的问题。咱们在DeepRec的应用中发现,这能大大减少minorpagefault的呈现,缩小了内存的应用,训练速度也失去了1.6倍的减速。
3.2 Executor优化
TensorFlow原生的Executor的实现非常简略,首先对DAG做拓扑排序,随后将Node插入到执行队列中,通过Task利用Executor调度。这样的实现没有联合业务思考,ThreadPool默认应用了Eigen线程池,若线程负载不平均,会产生大量的线程间抢占Steal,带来极大开销。咱们在DeepRec中定义调度更平均,同时定义了要害门路使得在调度的时候有肯定的优先级程序,来执行Op。最终DeepRec也提供了多种包含基于Task,SimpleGraph的调度策略。
4. 图优化相干的性能
4.1结构化特色
这是从业务启发的一个性能。咱们发现在搜寻场景下,不论是训练还是推理,样本往往是1个user对应多个item,多个label的特点。原来的解决形式会视为多个样本,这样user的存储是冗余的,咱们为了节俭这部分开销,自定义了存储格局来做这部分优化。如果这些样本在一个minibatch中是同一个user,局部user网络和item网络会别离计算,最初在做相应的逻辑计算,这样能节俭计算开销。所以咱们别离从存储和计算端做了结构化的优化。
4.2 SmartStage
咱们看到稠密模型的训练通常包含样本的读取,EmbeddingLookup,还有MLP的网络计算。样本的读取和Embedding查找往往不是计算密集型的,并不能无效利用计算资源。原生框架提供的prefetch接口尽管能肯定水平上实现异步操作,然而咱们在EmbeddingLookup过程中设计局部简单的子图,这些不能通过TensorFlow的prefetch实现流水线。TensorFlow提供的流水线性能,理论应用中须要用户显示的指定stage边界,一方面会进步应用难度,另一方面因为stage的精度不够,无奈准确到op级别。对于High Level的API用户无奈手动插入,会导致很多步调并行化。下图是SmartStage的具体操作,它会将Op主动的归类到不同的Stage,使得并发的流水线能失去性能的晋升。咱们在ModelZoo里模型的测试成果最大减速比能达到1.1-1.3。
5. Serving
5.1模型增量导出及加载
一开始在介绍Embedding的时候其中一个重要的点是低效的IO,如果将后面提到动静弹性性能利用后,咱们人造能做增量的导出。只有在图中退出已经拜访的稠密ID,那么在增量导出的时候就能精确的导出这部分咱们须要的ID。咱们做这个性能有两个出发点:首先,模型训练时咱们原有的办法,在每个step导出全量的模型导出,在程序中断restore时候也是restore checkpoint,最差的时候可能损失两个checkpoint区间所有的后果,有了增量导出,咱们对于dense局部会全量导出,sparse局部是增量导出,这在理论场景10分钟的增量导出能很大水平节约restore带来的损失;另外,增量导出的场景是在线serving,如果每次都全量加载,那么对于稠密场景,模型非常大,每次加载都须要消耗很长时间,如果要做在线学习会很艰难,所以增量导出也会用到ODL场景。
5.2 ODL
最右边是样本解决,高低两局部是离线和在线的训练,左边是serving。这外面利用了很多PAI的组件来实现Pipeline的结构。
DeepRec 社区
社区方面,咱们在6月份公布了新版本2206,次要包含以下新性能:
发表回复