摘要
为何用分布式
随着数据与模型参数量的越来越大,单机的内存(或显存)的增长速度并不能与之相匹配。由此,单节点进行深度学习训练已经无法满足要求。
绪论
背景+意义(其他框架简单的概括,使用的框架优点概括)、国内外现状、基本架构
基本架构
1.参数服务器架构+Spark 进行分布式集群资源管理+深度学习框架:Pytorch
- 单独Spark:
Mllib/Mlbase 等机器学习库发展缓慢,仅支持传统的机器学习相关算法
- 单独Pytorch:
Pytorch虽然具有分布式训练的接口,但是其编程需要配置节点集群,较为复杂,
没有集群资源管理功能,在分布式集群加入新的节点或者增加新的计算资源时,
程序需要重写;同时在迭代更新方面,并不能有效的降低网络中的通信开销,使得
分布式训练在扩展性与灵活性方面效果较差。
- Spark+Pytorch
通过将 Pytorch 与 Spark 结合起来,可以将分布式训练与底层资源
配置解耦,降低分布式训练编程的难度,为用户提供简单、明确、便捷的编程接口,
使用户可以更加方便的而进行分布式训练。
2.主要整合点
- 通过 Spark 将训练数据转化成 RDD 形式并分发在多个工作节点上进行分布式训练。
- 研究通过轻量级 Web 服务器框架 Flask,设计并建立参数服务器
- 梯度更新算法,ASGD、Hogwild异步更新算法(文章可以在此处创新,也可另辟蹊径)
urllib2 模块负责提供工作节点与参数服务器节点的网络通信功能。
pickle 负责将神经网络模型中的参数序列化与反序列化,以在网络上进行传输。
借鉴论文思想
神经网络模型梯度更新算法
- ASGD
- Hogwild
参数服务器
分布式深度学习系统分三种架构:数据流式,参数服务器和迭代式 Mapreduce(IMR) 1.工作原理
分布式集群节点从逻辑上被分为了工作节点(worker)与参数服务器节点(parameter worker)。工作节点负责本地的训练任务,每个工作节点维护一个本地模型,在本 地模型上进行训练任务。参数服务器维护全局模型,值得一提的是参数服务器可以 包含一个节点也可以包含一组节点,工作节点内部也可以包含多个节点,工作节点 上模型采用模型并行的方式进行训练。工作节点通过网络接口与参数服务器进行 交互通信,获取从参数服务器最新的模型参数,同时将本地训练的结果(模型或梯 度等)发送到参数服务器。工作节点内部之间计算隔离,无需相互通信,工作节点 仅需要与参数服务器节点进行交互,利用参数服务器维护全局模型参数,这样实现 了各工作节点可以分布式独立工作。
参数服务器架构下,工作节点对参数服务器节点的请求分为两种,push 和 pull。 pull 操作为请求从参数服务器上获取最新的全局模型参数,push 操作则是将本地 计算结果,一般为梯度或者模型参数,返回给参数服务器节点,参数服务器节点利 用来自各个工作节点上的信息更新全局模型。
需求分析与设计
- 神经网络建模、读取并处理数据集;
- 系统需为用户提供 Pytorch 原生的函数功能,包括 Convolution、Pooling函数、Normalization 函数、线性函数、Dropout 函数,以及相关的非线性激活函数;
- 系统需为用户提供分布式训练配置接口;
- 数据集转化;
- 异步更新算法进行创新;
- 损失函数接口
整体方法设计
- 用户通过调用系统提供的与原生 Pytorch 相同的网络接口编写待训练的神经网络模型,得到期望进行分布式训练的神经网络模型 Model P。
- 用户调用接口为所述 Model P 设置以下参数:
- 分布式训练相关参数:工作节点的数量,通信阈值与分布式更新算法
- 全局训练相关参数:包括期望精度值(用于控制训练过程何时终止)与参数服务器 Parameter Server的优化器Optimizer
- 工作节点训练相关参数,主要包括期望训练迭代轮数、batch size(训练批量尺寸)、损失函数以及工作节点 Worker 的优化器 Optimizer
-
系统内部将神经网络模型 Model P、分布式训练相关参数中的通信阈值以及工作节点相关训练参数发送到 N个工作节点,同时将 Model P、全局训练相关参数以及分布式训练相关参数中的分布式更新算法的设定传至参数服务器,同时将参数服务器上的 Model P 定义为全局神经网络模型 Model P_global,即分布式训练的目标模型。
-
系统将训练模型 Model P 的训练数据转化为 Spark 中的特色数据结构RDD。然后通过大数据并行计算框架 Spark 将转化为 RDD 后的训练数据等分成为N份,然后分发到 N个工作节点上。
-
各工作节点在获取相应的训练数据后,利用该数据以及工作节点训练相关参数训练本地模型 Model P_local,迭代的更新本地神经网络模型参数。各个节点在训练过程中记录自己的迭代轮数,在达到设定的通信阈值后,通过计算当前神经网络模型参数与上一轮发生通信时神经网络模型参数的差值,获取本地神经网络模型中参数的更新量,然后将更新量发送给参数服务器。
参数服务器根据相应的分布式更新算法,全局训练相关参数与工作节点传入的更新量训练全局模型 Model P_global,更新全局的网络参数,然后将更新后的参数下发给该工作节点,工作节点接收数据并更新本地模型
- 系统重复执行步骤 4,并周期性的将参数服务器上的全局模型保存备份,以便于故障恢复。在满足模型训练的终止条件后,将全局模型 Model P_global输出并保存,作为最终训练得到的模型。训练终止的条件:
- 第一种为,各个工作节点本地训练轮数达到设定的迭代次数;
- 第二种为,参数服务器上的全局模型的性能(准确度、损失函数值)达到阈值,即设定的期望值。
ASGD与Hogwild
同步方式下的更新算法比较适合分布式集群中节点性能较为平均、网络环境简单的情况,或者是单机多卡上的训练。若存在单个节点性能较低的情况,则在一轮迭代训练中,其他节点需要耗费大量的等待时间,形成木桶效应,造成效率低下。另外若有单个工作节点宕机的情况发生,则整个训练过程将会停止。
Hogwild!算法为 ASGD 算法的一个变体,本质上实现的是一种无锁的异步梯度下降算法,具体的 Hogwild!算法的流程如图 3-14 所示。Hogwild!算法在更新模型参数的时候,不需要获得对参数的写权限,可以根据梯度直接对参数更新,在这种情况下,是有可能出现来自某个节点梯度被另外一个节点的梯度覆盖掉的结果,这种情况可能会对训练造成一定的负面影响。
详细设计
架构 核心类Dpplee3
# sc SparkContext 对象 提供 Spark 上下文环境
# model Pytorch 模型对象 传入待训练的模型
# loss 损失函数名称 设置训练损失函数
# frequency Batch 或 Epoch 控制通信粒度
# frequency_num 整数 (默认为 1) 控制粒度下的通信频率
# mode ASGD 或 Hogwild 选择异步更新算法
# work_num 整数 设置工作节点的数量
# save_path url 地址 设置保存训练结果及备份的地址
class Dpplee3_model(object):
def __init__(self, sc, model, frequency, loss_function, mode, worker_num, frequency_num=1, save_path = None):
self.spark_context = sc
self.master_network = model
self.state_dict = model.state_dict()
self.network = model
self.frequency = frequency
self.mode = mode
# self.worker_optimizer = worker_optimizer
self.loss_function = loss_function
self.mode = mode
self.worker_num = worker_num
self.frequency_num = frequency_num #grain
self.lock = RWLock()
# torch.save(model, 'model.pkl')
# print('----model save------')
if save_path:
self.save_path = save_path