使用TensorFlow训练WDL模型性能问题定位与调优

简介

TensorFlow是Google研发的第二代人工智能学习系统,能够处理多种深度学习算法模型,以功能强大和高可扩展性而著称。TensorFlow完全开源,所以很多公司都在使用,但是美团点评在使用分布式TensorFlow训练WDL模型时,发现训练速度很慢,难以满足业务需求。

经过对TensorFlow框架和Hadoop的分析定位,发现在数据输入、集群网络和计算内存分配等层面出现性能瓶颈。主要原因包括TensorFlow数据输入接口效率低、PS/Worker算子分配策略不佳以及Hadoop参数配置不合理。我们在调整对TensorFlow接口调用、并且优化系统配置后,WDL模型训练性能提高了10倍,分布式线性加速可达32个Worker,基本满足了美团点评广告和推荐等业务的需求。

术语

  • TensorFlow - Google发布的开源深度学习框架
  • OP - Operation缩写,TensorFlow算子
  • PS - Parameter Server 参数服务器
  • WDL - Wide & Deep Learning,Google发布的用于推荐场景的深度学习算法模型
  • AFO - AI Framework on YARN的简称 - 基于YARN开发的深度学习调度框架,支持TensorFlow,MXNet等深度学习框架

TensorFlow分布式架构简介

为了解决海量参数的模型计算和参数更新问题,TensorFlow支持分布式计算。和其他深度学习框架的做法类似,分布式TensorFlow也引入了参数服务器(Parameter Server,PS),用于保存和更新训练参数,而模型训练放在Worker节点完成。

TensorFlow分布式架构

TensorFlow支持图并行(in-graph)和数据并行(between-graph)模式,也支持同步更新和异步更新。因为in-graph只在一个节点输入并分发数据,严重影响并行训练速度,实际生产环境中一般使用between-graph。

同步更新时,需要一个Woker节点为Chief,来控制所有的Worker是否进入下一轮迭代,并且负责输出checkpoint。异步更新时所有Worker都是对等的,迭代过程不受同步barrier控制,训练过程更快。

AFO架构设计

TensorFlow只是一个计算框架,没有集群资源管理和调度的功能,分布式训练也欠缺集群容错方面的能力。为了解决这些问题,我们在YARN基础上自研了AFO框架解决这个问题。

AFO架构特点:

  • 高可扩展,PS、Worker都是任务(Task),角色可配置
  • 基于状态机的容错设计
  • 提供了日志服务和Tensorboard服务,方便用户定位问题和模型调试

AFO 架构

AFO模块说明:

  • Application Master:用来管理整个TensorFlow集群的资源申请,对任务进行状态监控
  • AFO Child:TensorFlow执行引擎,负责PS、Worker运行时管理和状态同步
  • History Server:管理TensorFlow训练生成的日志
  • AFO Client:用户客户端

WDL模型

在推荐系统、CTR预估场景中,训练的样本数据一般是查询、用户和上下文信息,系统返回一个排序好的候选列表。推荐系统面临的主要问题是,如何同时可以做到模型的记忆能力和泛化能力,WDL提出的思想是结合线性模型(Wide,用于记忆)和深度神经网络(Deep,用于泛化)。

以论文中用于Google Play Store推荐系统的WDL模型为例,该模型输入用户访问应用商店的日志,用户和设备的信息,给应用App打分,输出一个用户“感兴趣”App列表。

WDL 模型网络

其中,installed apps和impression apps这类特征具有稀疏性(在海量大小的App空间中,用户感兴趣的只有很少一部分),对应模型“宽的部分”,适合使用线性模型;在模型“深的部分”,稀疏特征由于维度太高不适合神经网络处理,需要embedding降维转成稠密特征,再和其他稠密特征串联起来,输入到一个3层ReLU的深度网络。最后Wide和Deep的预估结果加权输入给一个Logistic损失函数(例如Sigmoid)。

WDL模型中包含对稀疏特征的embedding计算,在TensorFlow中对应的接口是tf.embedding_lookup_sparse,但该接口所包含的OP无法使用GPU加速,只能在CPU上计算,因此TensorFlow在处理稀疏特征性能不佳。不仅如此,我们发现分布式TensorFlow在进行embedding计算时会引发大量的网络传输流量,严重影响训练性能。

性能瓶颈分析与调优

在使用TensorFlow训练WDL模型时,我们主要发现3个性能问题:

  1. 每轮训练时,输入数据环节耗时过多,超过60%的时间用于读取数据。
  2. 训练时产生的网络流量高,占用大量集群网络带宽资源,难以实现分布式性能线性加速。
  3. Hadoop的默认参数配置导致glibc malloc变慢,一个保护malloc内存池的内核自旋锁成为性能瓶颈。

TensorFlow输入数据瓶颈

TensorFlow支持以流水线(Pipeline)的方式输入训练数据。如下图所示,典型的输入数据流水线包含两个队列:Filename Queue对一组文件做shuffle,多个Reader线程从此队列中拿到文件名,读取训练数据,再经过Decode过程,将数据放入Example Queue,以备训练线程从中读取数据。Pipeline这种多线程、多队列的设计可以使训练线程和读数据线程并行。理想情况下,队列Example Queue总是充满数据的,训练线程完成一轮训练后可以立即读取下一批的数据。如果Example Queue总是处于“饥饿”状态,训练线程将不得不阻塞,等待Reader线程将Example Queue插入足够的数据。使用TensorFlow Timeline工具,可以直观地看到其中的OP调用过程。

TensorFlow输入数据流水线

使用Timeline,需要对tf.Session.run()增加如下几行代码:

with tf.Session as sess:ptions = tf.RunOptions(trace_level=tf.RunOptions.FULL_TRACE)run_metadata = tf.RunMetadata()_ = sess.run([train_op, global_step], options=run_options, run_metadata=run_metadata)if global_step > 1000 && global_step < 1010:from tensorflow.python.client import timelinefetched_timeline = timeline.Timeline(run_metadata.step_stats)chrome_trace = fetched_timeline.generate_chrome_trace_format()with open('/tmp/timeline_01.json', 'w') as f:f.write(chrome_trace)

这样训练到global step在1000轮左右时,会将该轮训练的Timeline信息保存到timeline_01.json文件中,在Chrome浏览器的地址栏中输入chrome://tracing,然后load该文件,可以看到图像化的Profiling结果。

业务模型的Timeline如图所示:

Timeline显示数据输入是性能瓶颈

可以看到QueueDequeueManyV2这个OP耗时最久,约占整体时延的60%以上。通过分析TensorFlow源码,我们判断有两方面的原因:

  • (1)Reader线程是Python线程,受制于Python的全局解释锁(GIL),Reader线程在训练时没有获得足够的调度执行;
  • (2)Reader默认的接口函数TFRecordReader.read函数每次只读入一条数据,如果Batch Size比较大,读入一个Batch的数据需要频繁调用该接口,系统开销很大;

针对第一个问题,解决办法是使用TensorFlow Dataset接口,该接口不再使用Python线程读数据,而是用C++线程实现,避免了Python GIL问题。 针对第二个问题,社区提供了批量读数据接口TFRecordReader.read_up_to,能够指定每次读数据的数量。我们设置每次读入1000条数据,使读数句接口被调用的频次从10000次降低到10次,每轮训练时延降低2-3倍。

优化数据输入使性能提升2-3倍

可以看到经过调优后,QueueDequeueManyV2耗时只有十几毫秒,每轮训练时延从原来的800多毫秒降低至不到300毫秒。

集群网络瓶颈

虽然使用了Mellanox的25G网卡,但是在WDL训练过程中,我们观察到Worker上的上行和下行网络流量抖动剧烈,幅度2-10Gbps,这是由于打满了PS网络带宽导致丢包。因为分布式训练参数都是保存和更新都是在PS上的,参数过多,加之模型网络较浅,计算很快,很容易形成多个Worker打一个PS的情况,导致PS的网络接口带宽被打满。

在推荐业务的WDL模型中,embedding张量的参数规模是千万级,TensorFlow的tf.embedding_lookup_sparse接口包含了几个OP,默认是分别摆放在PS和Worker上的。如图所示,颜色代表设备,embedding lookup需要在不同设备之前传输整个embedding变量,这意味着每轮Embedding的迭代更新需要将海量的参数在PS和Worker之间来回传输。

embedding_lookup_sparse的OP拓扑图

有效降低网络流量的方法是尽量让参数更新在一个设备上完成,即

with tf.device(PS):do embedding computing

社区提供了一个接口方法正是按照这个思想实现的:embedding_lookup_sparse_with_distributed_aggregation接口,该接口可以将embedding计算的所使用的OP都放在变量所在的PS上,计算后转成稠密张量再传送到Worker上继续网络模型的计算。

从下图可以看到,embedding计算所涉及的OP都是在PS上,测试Worker的上行和下行网络流量也稳定在2-3Gpbs这一正常数值。

embedding_lookup_sparse_with_distributed_aggregation的OP拓扑图

PS上的UniqueOP性能瓶颈

在使用分布式TensorFlow 跑广告推荐的WDL算法时,发现一个奇怪的现象:WDL算法在AFO上的性能只有手动分布式的1/4。手动分布式是指:不依赖YARN调度,用命令行方式在集群上分别启动PS和Worker作业。

使用Perf诊断PS进程热点,发现PS多线程在竞争一个内核自旋锁,PS整体上有30%-50%的CPU时间耗在malloc的在内核的spin_lock上。

Perf诊断PS计算瓶颈

进一步查看PS进程栈,发现竞争内核自旋锁来自于malloc相关的系统调用。WDL的embedding_lookup_sparse会使用UniqueOp算子,TensorFlow支持OP多线程,UniqueOp计算时会开多线程,线程执行时会调用glibc的malloc申请内存。

经测试排查,发现Hadoop有一项默认的环境变量配置:

export MALLOC_ARENA_MAX="4"

该配置意思是限制进程所能使用的glibc内存池个数为4个。这意味着当进程开启多线程调用malloc时,最多从4个内存池中竞争申请,这限制了调用malloc的线程并行执行数量最多为4个。

翻查Hadoop社区相关讨论,当初增加这一配置的主要原因是:glibc的升级带来多线程ARENA的特性,可以提高malloc的并发性能,但同时也增加进程的虚拟内存(即top结果中的VIRT)。YARN管理进程树的虚拟内存和物理内存使用量,超过限制的进程树将被杀死。将MALLOC_ARENA_MAX的默认设置改为4之后,可以不至于VIRT增加很多,而且一般作业性能没有明显影响。

但这个默认配置对于WDL深度学习作业影响很大,我们去掉了这个环境配置,malloc并发性能极大提升。经过测试,WDL模型的平均训练时间性能减少至原来的1/4。

调优结果

注意:以下测试都去掉了Hadoop MALLOC_ARENA_MAX的默认配置

我们在AFO上针对业务的WDL模型做了性能调优前后的比对测试,测试环境参数如下:

模型:推荐广告模型WDL
OS:CentOS 7.1
CPU: Xeon E5 2.2G, 40 Cores
GPU:Nvidia P40
磁盘: Local Rotational Disk
网卡:Mellanox 25G(未使用RoCE)
TensorFlow版本:Release 1.4
CUDA/cuDNN: 8.0/5.1

分布式线性加速效果

可以看到调优后,训练性能提高2-3倍,性能可以达到32个GPU线性加速。这意味着如果使用同样的资源,业务训练时间会更快,或者说在一定的性能要求下,资源节省更多。如果考虑优化MALLOC_ARENA_MAX的因素,调优后的训练性能提升约为10倍左右。

总结

我们使用TensorFlow训练WDL模型发现一些系统上的性能瓶颈点,通过针对性的调优不仅可以大大加速训练过程,而且可以提高GPU、带宽等资源的利用率。在深入挖掘系统热点瓶颈的过程中,我们也加深了对业务算法模型、TensorFlow框架的理解,具有技术储备的意义,有助于我们后续进一步优化深度学习平台性能,更好地为业务提供工程技术支持。

作者简介

  • 郑坤,美团点评技术专家,2015年加入美团点评,负责深度学习平台、Docker平台的研发工作。

招聘

美团点评GPU计算团队,致力于打造公司一体化的深度学习基础设施平台,涉及到的技术包括:资源调度、高性能存储、高性能网络、深度学习框架等。目前平台还在建设中期,不论在系统底层、分布式架构、算法工程优化上都有很大的挑战!诚邀对这个领域感兴趣的同学加盟,不论是工程背景,还是算法背景我们都非常欢迎。有兴趣的同学可以发送简历到zhengkun@meituan.com。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/478730.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

docker镜像打包save,载入load,启动run

docker镜像打包save&#xff0c;载入load&#xff0c;启动run docker打包&#xff0c;针对的是镜像&#xff0c;而不是运行中的容器。 查看当前系统的镜像文件&#xff1a; docker images 首先&#xff0c;将当前运行中的&#xff0c;已经自定义修改之后的容器保存为新的镜像…

会议交流 - CNCC 技术论坛 | NLP中知识和数据怎么选?当然是全都要!——第四届中文信息技术发展战略研讨会...

本文转载自公众号&#xff1a;中国计算机学会 。本论坛将于CNCC2020期间&#xff0c;10月23日下午16:00-18:00&#xff0c;在北京新世纪日航饭店3层南京厅举行。本论坛将邀请多位来自国内著名高校和人工智能企业的知名自然语言处理专家介绍他们在知识图谱、知识获取、预训练模型…

从我开发过的Tensorflow、飞桨、无量框架看深度学习这几年

文 | Peter潘欣知乎和深度学习框架打交道已有多年时间。从Google的TensorFlow, 到百度的PaddlePaddle&#xff0c;再到现在腾讯的无量。很庆幸在AI技术爆发的这些年横跨中美几家公司&#xff0c;站在一个比较好的视角看着世界发生巨大的变化。在这些经历中&#xff0c;视角在不…

探索Glide对Gif图片资源的获取、解析过程

先预祝大家汤圆节快乐&#xff01;很久没写博客了。今天我们来探索一下Glide是如何支持Gif图片加载的。 本篇博客的目的 了解代码分析的基本思路与方法了解Glide是如何对Gif图片进行支持的 探索背景 为什么会有这么一个想法呢&#xff0c;一来一直对Glide是知其名而不知其所…

美团“猜你喜欢”深度学习排序模型实践

引言 推荐作为解决信息过载和挖掘用户潜在需求的技术手段&#xff0c;在美团点评这样业务丰富的生活服务电子商务平台&#xff0c;发挥着重要的作用。在美团App里&#xff0c;首页的“猜你喜欢”、运营区、酒店旅游推荐等重要的业务场景&#xff0c;都是推荐的用武之地。 目前&…

如何关闭docker容器里的进程

如何关闭docker容器里的进程 1、使用docker exec 容器名 ps -ef命令查看进程信息 示例&#xff1a; 创建名为"redis"的容器&#xff0c;并在容器内部和宿主机中查看容器中的进程信息&#xff1a; 2、然后进入该容器中&#xff0c;执行如下命令即可停掉进程&…

论文浅尝 | 一日看尽长安花--NLP可解释研究梳理

本文是对TACL2019《Analysis Methods in Neural Language Processing: A Survey》的翻译和整理。本文转载自知乎&#xff0c;文章链接&#xff1a;https://zhuanlan.zhihu.com/p/265815975导读NLP领域发展迅猛&#xff0c;其模型分析方法也正逐渐火热。为什么要研究NLP的可解释…

简明扼要的反射入门教程

反射 反射作为RTTI语言&#xff08;比如Java&#xff09;的基础之一被很多人所熟知&#xff0c;但是有些同学对反射本身还是懵懵懂懂的&#xff0c;不是很清楚它到底有什么用。今天这节课我们就对反射本身来一个通体的认知。 定义 反射所在的包为&#xff1a;java.lang.refl…

人在斯坦福,刚上CS224n

文 | Jazon大家好&#xff0c;我是Jazon&#xff0c;现在是Stanford计算机硕士项目的一只学生&#xff0c;非常荣幸加入小夕的大家庭&#xff01;请各路大神多多指教呀。2021年1月12日&#xff0c;又一季Stanford CS224n——自然语言处理开课了&#xff0c;我和很多MSCS同学一起…

美团外卖骑手背后的AI技术

背景 随着数字化时代的到来&#xff0c;外卖市场近年来发展非常迅猛。对外卖物流系统而言&#xff0c;配送效率和用户体验至关重要。而实际配送过程是由配送员&#xff08;骑手&#xff09;最终完成的&#xff0c;因此&#xff0c;想要真正提升配送效率&#xff0c;不但要在智能…

软件设计师:下午试题类型以及问题总结+软件设计师考试下午题统计分析(06到2019年)

‘’’ 首次更新下午试题 ‘’’ 下午考试时间为150分钟&#xff08;14:00–16:30&#xff09; 试题一到四为必答题&#xff0c;试题五和六为选答一个&#xff0c;每题15分&#xff0c;总共75分&#xff0c;每题大概3小问 第一题为结构化分析与设计&#xff0c;考查数据流…

LeetCode 494. 目标和(DFS+DP)

文章目录1. 题目2. 解题2.1 递归2.2 DP1. 题目 给定一个非负整数数组&#xff0c;a1, a2, …, an, 和一个目标数&#xff0c;S。现在你有两个符号 和 -。对于数组中的任意一个整数&#xff0c;你都可以从 或 -中选择一个符号添加在前面。 返回可以使最终数组和为目标数 S 的…

使用Kotlin开发Android应用初体验

使用Kotlin开发Android应用初体验 昨晚&#xff0c;最近一届的谷歌IO大会正式将Kotlin确定为了官方开发语言&#xff0c;作为一名Android开发鸟&#xff0c;怎么能不及时尝尝鲜呢? Kotlin的简要介绍 在开发之前&#xff0c;很多同学一定有很多疑问&#xff0c;Kotlin到底有…

论文浅尝 - ICML2020 | 基于子图推理的归纳式关系预测

论文笔记整理&#xff1a;陈名杨&#xff0c;浙江大学在读博士生&#xff0c;主要研究方向为知识图谱表示学习。论文来源&#xff1a;ICML 2020Introduction当前在知识图谱上&#xff08;KnowledgeGraph&#xff0c;KG&#xff09;进行关系预测的很多方法都依靠在对知识图谱中的…

CVPR 二十年,影响力最大的 10 篇论文!

文 | 二玖极市平台此前&#xff0c;极市盘点了图像分割在过去二十年中影响力最大的10篇论文&#xff0c;得到了许多开发者的支持。今天&#xff0c;我们将对计算机视觉领域三大顶会之一CVPR在近二十年来中产生的优秀论文进行一个全面的盘点与总结。CVPR是计算机视觉领域三大顶会…

DataMan-美团旅行数据质量监管平台实践

背景 数据&#xff0c;已经成为互联网企业非常依赖的新型重要资产。数据质量的好坏直接关系到信息的精准度&#xff0c;也影响到企业的生存和竞争力。Michael Hammer&#xff08;《Reengineering the Corporation》一书的作者&#xff09;曾说过&#xff0c;看起来不起眼的数据…

jupyter notebook切换到其他配置好的conda虚拟环境

1 手把手教你如何把jupyter notebook切换到其他配置好的conda虚拟环境 https://blog.csdn.net/weixin_41813895/article/details/84750990 2 Jupyter notebook切换Python环境 https://www.jianshu.com/p/8188c32a3a34

LeetCode 133. 克隆图(图的BFS/DFS)

1. 题目 给定无向连通图中一个节点的引用&#xff0c;返回该图的深拷贝&#xff08;克隆&#xff09;。图中的每个节点都包含它的值 val&#xff08;Int&#xff09; 和其邻居的列表&#xff08;list[Node]&#xff09;。 class Node { public:int val;vector<Node*> n…

七天搞定java接口自动化测试实战,一文搞定...

前言 无论是自动化测试还是自动化部署&#xff0c;撸码肯定少不了&#xff0c;所以下面的基于java语言的接口自动化测试&#xff0c;要想在业务上实现接口自动化&#xff0c;前提是要有一定的java基础。 如果没有java基础&#xff0c;也没关系。这里小编也为大家提供了一套jav…

Android自动化测试探索

前言 通常来说&#xff0c;我们开发完成产品之后&#xff0c;都是由测试组或者是我们自己点一点&#xff0c;基本上没有问题了就开始上线。但是&#xff0c;随着时间的堆叠&#xff0c;一款产品的功能也越来越多。这时&#xff0c;我们为了保证产品的质量&#xff0c;就需要在…