在做推荐系统做分布式训练,面临的经典问题应该就是以下两个问题:
当然这两个问题可能在现有的大环境下已经被解决掉了,因为这是基础架构的一部分,大部分公司在做基建的时候就已经搞定了这些问题,所以说只从使用的角度来看,那其实不是个问题。
那么现在为什么还要提出这个问题?核心的点就是知其所以然,但是并不是完全的。如果涉及到ps调参其实是有必要了解ps的内部原理机制。
既然这篇文章是讲ps的,那么解决方案肯定是ps方案了。
ps全称是 parameter service(参数服务器),也可以理解为一个“数据库”(kv数据库),你给一个id,我给你返回 embedding ,那么可以理解key 就是id,value 就是embedding。当然不单单是存储数据,尤其是反向传播参数更新之类的都有。具体是怎么运作的可以继续往下看。
再稍微具体一点,基于Parameter Server的训练流程如下图所示:
[Worker] 训练时,每个worker先归纳一下当前batch需要涉及到哪些feature_id。
[Worker] 每个worker向整个ps server集群请求“当前batch涵盖的feature”的最新参数(e.g., 一阶权重或embedding)。即图中的Pull。
[Server] 因为每台ps server只拥有一部分feature的参数,所以尽管图中没有表现,但是中间会有一个路由机制,将worker的请求拆分、路由到合适的ps server上。
[Server] 收到“拉数据”请求的ps server,从本地存储中找到这些feature_id的最新参数,回复。
[Worker] 收到ps server发送回来的各feature的最新参数,worker就可以在当前batch的数据上进行前代+回代,得到这些feature上的梯度。
[Worker] Worker将计算好的梯度发往Server,即图中的Push。
[Server] 接到worker发来的梯度后,Server汇总聚合梯度,再用各种SGD的变体(e.g., FTRL、Adam、Adagrad等)更新本地参数。
这个标题其实算是标题党,现在成熟的ps架构肯定比这个更完善。ps-lite,故名思义是一个轻量版本,它会给出核心的骨架,有一点麻雀虽小五脏俱全的感觉,当然对我来说是有一个学习ps内部原理的机会。
在使用SGD进行训练的场景下:
server: 其实就是一个key/value数据库,
scheduler: 一个系统中只有一个scheduler节点,主要负责
PostOffice: 每个进程(无论scheduler/worker/server),有且只有一个“邮局”,是该进程的消息集散中心。它掌管着在它那里等消息的“顾客”的名单。 |
Van:每个邮局只有一辆“邮车”,负责收发信件的具体工作。派发信件时,Van通过PostOffice的名单,找到某个“顾客”,将信件交到他手上。 |
Customer:邮局的顾客,其实就是个中介。worker和server为了更好地专心业务工作,将“在邮局排队等消息”的工作外包给了“顾客”。Customer从Van手中接过信件后,转手就交给它的顾主,worker或server。
Worker:Customer的顾主,训练时主要负责处理样本、计算梯度等工作。
Server:Customer的顾主,训练时主要负责接收梯度,汇总梯度(同步模式下),更新权重等工作。
将上述的点用一张图来表示,大概如下图所示
附录: