随着深度学习的发展,当今的开源世界并不缺少成熟的深度学习框架,除Tensorflow和Torch两大阵营以外,Caffe、MXNet等框架也各自拥有大量的拥趸。这些框架虽然使用灵活,性能优异,然而在实际应用时仍然会遇到如下问题:
1. 数据存储于HDFS之上,且格式各异,与深度学习框架直接对接并不容易;
2. 用于训练模型的数据往往需要通过Spark进行清洗和特征转换,使得团队必须同时维护两套系统;
3. 计算资源通常为传统的CPU集群,基于Yarn这类框架进行调度。
面对上述问题,BigDL提出了自己的应对方案,可以简单概括为On Spark, for Cpus。
系统架构
分布式的深度学习训练通常有两种模式,即模型并行和数据并行(考虑到模型并行在实际应用中相对较少,这里仅仅讨论数据并行的情况)。在数据并行的模式中,每个数据partition会对应一个独立的模型,在该partition上,模型按照batch进行前向计算,得到梯度。各个模型计算得到的梯度汇总后按照设定的优化算法计算,得到新的模型参数,发送回模型进行下一轮迭代。
其中,参数更新的模式的不同对训练性能有较大影响,通常可以分为同步更新和异步更新。
同步更新:同步等待所有模型完成梯度计算后计算和更新参数。同步操作保证了参数更新的一致性,因而利于训练的收敛,缺点是各个partition计算速度往往各异,容易受限于最慢的节点;
异步更新:每个模型独立更新参数,这使得各个模型无需保证步调一致,加快了迭代速度,然而不利于收敛。
考虑到异步更新的实现需要借助于参数服务器,而Spark采用的仍然是继承自Hadoop的MapReduce原语,实现起来并不容易。因此,BigDL选择了更适合Spark应用的同步更新方式。在具体实现上,每轮迭代被划分成梯度计算和参数同步两个任务,按照以下方式依次运行。
1. 为模型生成一个和训练数据RDD具有同样partition数的模型RDD;
2. 在梯度计算过程中,两个RDD按照partition配对,根据当前的模型参数进行计算,得到梯度;
3. 计算得到的梯度在在参数同步任务中进行汇总,计算得到新的参数,回到第2步
值得一提的是,在梯度计算阶段,每个模型计算的得到的梯度会被分成n份,n对应于参数同步阶段的任务数。这使得新参数的计算可以并行,加快了迭代的速度。
网友评论