Press "Enter" to skip to content

超越容器化,爱奇艺深度学习云平台的实践及优化

写在前面

 

深度学习技术在图像处理上取得了巨大成功,替代了许多传统的图像处理算法。爱奇艺视频业务线对深度学习训练任务的计算需求飞速增长。这些训练任务通常使用 GPU 进行大量密集的计算。GPU 不同于 CPU 的独占使用方式,使得让传统基于时间片的共享方法失效。GPU 高昂的价格带来的成本压力,对使用效率提出了更高的要求。如何把 GPU 资源更好的更快的更灵活的提供给业务使用,降低深度学习的使用门槛,成为计算团队的一个难题。为了解决这个难题,我们开始对深度学习云平台构建的漫长旅途。

 

一个云计算平台主要解决三大类问题:计算、存储和网络。在计算方面,爱奇艺大量使用虚拟化计算和容器云计算。相比于虚拟化技术,容器更加简单便捷,不需要额外的硬件支持,近乎无损的提供 GPU 计算能力,可以快速的提供不同软件环境,启动时间短,成为首选的 GPU 计算承载方式。

 

训练任务场景

 

 

 

我们的第一次尝试从训练任务容器化开始。一个典型的训练任务和普通数据处理任务类似:训练程序设置参数,从数据源读取数据,使用框架提供的 API 进行计算,输出保存点和最终模型,同时也会输出日志和一些事件信息。

 

训练任务容器化 demo 很快就完成了,我们拿着 demo 去和算法同事沟通:

 

A:“首先需要把训练框架和代码做成一个 Docker 镜像,然后登录到我们容器云平台,启动容器……”

 

B:“什幺是 Docker/ 容器?可以直接跑训练任务吗?”算法同事问。

 

A:“我们两个星期后要上线,什幺时候可以给训练任务服务?”

 

B:”有没有一个方案可以让算法用户在不了解容器的情况下使用训练服务?最好两个星期内做出来!“

 

PS: 这个时候发现我们忽略了最终用户的基础情况:算法工程师专注与算法,关心平台的易用性和实际训练时间。通常没有兴趣了解容器、存储等基础服务,对计算性能几乎没有概念。

 

Runonce 训练服务

 

 

两个星期后,我们开始测试了 Runonce 训练服务。Runonce 的最初设计目的是,让用户像使用虚拟机一样使用容器。Runonce 底层设施是基于 mesos 容器云环境。计算资源已容器方式的提供,所有容器使用统一镜像。为了保存用户数据,容器使用了 Ceph RBD 网络块存储设备作为 RootFS。容器启动点是一个 sshd 服务,作为用户的登录入口。我们提供了特殊的文件注入工具帮助用户管理 ssh key。

 

Runonce 训练服务功能简单,开发量小,短时间完成上线。Runonce 服务的用户体验没有发生根本新的变化,可以很快上手。但是,缺点也很明显。用户对软件环境完全控制,常常出现错误修改系统文件引发的问题。这些问题很难跟踪和调查,带来很高的运维开销。用户是在使用 shell 来交互操作资源,通常会进行大量代码修改和调试,实际使用 GPU 时间不多,最终体现是整体 GPU 利用率较低。由于块存储设备不能进行共享,RUNONCE 不支持数据集共享,也不能支持并行多任务训练,更加不支持分布式训练。

 

因为 Runonce 服务存在无法修复的缺陷,我们决定开发一个新的训练平台。通过大量观察用户使用 Runonce 服务行为,我们总结出典型使用步骤:数据集上传,编写训练代码,执行训练任务,获取训练结果。这些步骤后面的核心是数据,而支持数据读取的存储方案是最关键的方案。

 

储存选择

 

 

如果需要进行数据共享,那幺网络存储是最好的选择。在对网络存储选择过程中,我们关注下面这些设计和指标:健壮性,伸缩性,吞吐量,并发,延迟。由于多数训练框架都支持文件系统接口,所以提供文件接口是存储的必须功能。综合各个因素后,Jarvis 使用的首选存储平台是 Ceph 对象存储(RWG)。Ceph 对象存储有很好的并发性能,可以很容易的进行水平扩展,但对象储存提供的接口是基于 HTTP 的 S3 接口,需要进行文件 API 的封装。

 

Jarvis 存储

 

 

Jarvis 在 S3 上采用 fuse 文件系统,用于支持文件读写。S3 fuse 对读操作很友好,但是在写功能上有很多限制,例如:不支持随机写,任何文件修改都需要重新上传整个文件。Jarvis 使用本地文件作为缓存,然后定期同步到 Ceph 对象存储。因为同步会造成大量重复写操作,Jarvis 对写操作做了划分,一类是写日志这样的小文件操作,一类是模型同步等的大文件操作。小文件使用较短的同步周期,大文件使用较长的同步周期。

 

Jarvis 运行环境

 

在 Jarvis 上,训练任务容器使用的是定制的镜像,软件环境是精确定义。镜像启动脚本将训练数据通过 S3 fuse 接入到容器内部,然后拉取 gitlab 代码,执行用户训练任务,同时将输出数据同步到对象存储上。这里我们做一个小小的优化,软件环境划分为基础镜像和运行时脚本镜像。在基础镜像上,注入运行时脚本镜像内容。每次修改运行脚本,可以不必更新基础镜像,大大加快了开发效率。

 

但是 Jarvis 很大程度的改变了用户使用方法,用户普遍反应使用更不方便。我们在调试和状态查询上下了很大的功夫,提供了实时日志展现网页,同时还提供 Tensorboard 这样的图形化状态查看的功能。Tensorboard 功能强大,但是内存消耗也比较大。于是,我们开发了轻量化指标收集器,将指标直接投递到数据后台,由数据后台界面来进行展现。

 

在 Jarvis 平台运行一段时间之后,我们没有观察到 GPU 利用率显着提升。这样结果让我们很惊讶。我们发现,GPU 利用率低的主要原因是,大多数任务没有对优化数据读取。这个问题在网络存储环境下会更加突出。

 

存储优化

 

 

网络存储有以下这些特点:

 

高吞吐:读写速度很高

 

高并发:可以支持很高的并发读写

 

高延迟:发去请求到拿到第一个字节的时间相对较长

 

掉队现象:某些请求可能会过很长时间才返回

 

在网络存储环境下,我们需要增加处理数据读取和处理的并发数,尽量避免使用小文件,放宽读取数据顺序的限制。

 

如果训练数据文件都是比较小的图片,应该合并若干小文件为一个 tfrecord 的大文件,降低请求次数。目前,tensorflow 在并发数据读取处理支持做好,建议阅读 Data Input Pipeline Performance。

 

申请容器时,用户应该注意 CPU 资源的数量。如果 CPU 申请较少,数据处理速度慢,GPU 处于等待数据空闲状态。

 

同时,还应该做好数据的预处理。我们遇到一个案例,使用纯文本的输入数据,大量 CPU 时间花费在字符串到数字转换上。在将文本数据处理成二级制数据之后,训练任务几乎跑满了 GPU 计算能力。

 

深度学习技术发展迅速,大量变革正在发生。很多端到端的平台正在开发,例如 Kubeflow,OpenPAI。这些平台都想把深度学习做成完整的闭环功能,让算法工程师专注于数据和算法。要实现这样的功能,我们还有很长的路要走。

 

本文转载自“爱奇艺技术产品团队”公众号。

 

作者简介:周海维,QCon 讲师,爱奇艺机器学习平台架构师。有 12 年软件开发经验,从底层操作系统到上层应用都有涉及,熟悉系统软件的性能分析与调优。加入爱奇艺后,从事智能路由器程序设计和开发。转到云平台部门后,专注容器云和高性能计算,负责机器学习平台 Jarvis 开发。希望通过 Jarvis 平台降低机器学习使用门槛,普通用户也可以方便使用先进机器学习算法。

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注