1. 概述

分布式训练服务框架与集合通信库的组合构成了分布式训练的整体服务软件栈,在第3篇、第4篇文章里已经剖析完集合通信的相关内容,而本文会以Horovod为例介绍数据并行下分布式训练服务框架的基本原理以及进行架构解析。当前,在分布式训练里分布式训练服务框架需要解决以下几个核心问题 :

  • 计算与通信同步耦合问题:如果反向传播一产生一份梯度,就马上对其调用全局AllReduce,计算与通信同步耦合,容易造成死锁同时性能也会很不如意;
  • 计算时间与通信时间串行问题:神经网络是分层的,梯度计算的过程是数据加载,然后前向传播算出损失值,再反向传播算出梯度,而反向计算时梯度是从输出层往输入层方向一层一层产生的,在有些模型里,如果需要等所有的梯度都计算完毕才能触发全局AllReduce,那么对性能的影响也会很大;
  • 梯度生成的落后者问题:集群内每个计算节点的同一份梯度的产生不一定都是同一时刻的,如果梯度没有全部生成就发起对这个梯度的全局规约,否则容易造成训练出来的模型精度不达标或者不收敛的问题;
  • 梯度融合问题:如果每一份梯度都触发一次全局AllReduce,在梯度Tensor较多的神经网络训练里,整体的训练系统性能会变得极低;
  • 易用性问题:从TensorFlow,PyTorch迁移过来需要改的代码需要极少,从单卡训练迁移到多卡训练需要改动的代码也需要极少;
  • 可移植问题:支持多种多样的深度学习训练框架,比如 TensorFlow、PyTorch、MxNet等,也能支持多种多样的通信库,比如openMPI、NCCL、Gloo、CCL、RCCL等;
  • 可靠性问题:在集群训练的过程中网络时不可靠的、计算卡是会出故障的、服务器是会出故障的、系统软件也是会出Bug的,这些因素造成了分布式训练过程中还存在可靠性问题,如何解决这个问题也是一个难题。

软件是由人实现的,解析一个软件系统最难的地方在于从庞杂的代码里倒推出背后实现它的人的设计意图,为了更好的理解Horovod,本文会基于以上这几个分布式训练的核心问题,以Horovod为例介绍分布式训练服务框架的基本原理以及进行架构解析。

2. 基础知识

2.1 单卡训练

神经网络的训练,本质上就是Y=F(x)的迭代,通过反复输入X、输出Y,使得神经网络的参数变化与输入输出间的复杂关系拟合。在神经网络训练的过程中,通过输入数据利用梯度下降的方法进行迭代从而优化神经网络参数,并最终输出神经网络模型。而神经网络可以看作一种运算模型,其由大量的神经元(节点)相互联接构成,其由输入层、隐藏层以及输出层组合而成(如下图左侧所示)。神经元(neuron)是神经网络的基本计算单元,也被称作节点(node),它可以接受来自其他神经元或外部数据的输入,然后计算出一个输出(如下图右上角所示)。

单卡训练

如上图右下角所示,在单卡训练迭代中,基于并行梯度下降法,会有以下操作:

第一步,读取部分数据,并且将数据加载进训练卡的存储空间;

第二步,对模型进行前向传播计算,从输入层往输出层一层一层的进行计算,得到损失差LOSS;

第三步,对模型进行反向传播计算,从输出层往输入层一层一层的进行计算,得到梯度值,注意这一步会把每一层都计算出一个梯度张量(Gradient Tensor)出来;

第四步,将新的到的梯度与部分数据 作为新的输入,重新开始以上步骤的迭代。

在这一步里有一个很重要的与性能优化相关的信息是反向传播是每一层输出一个梯度张量,以及反向传播是从输出层往输入层一层一层的进行计算的,这一点信息可以用通信隐藏性能优化与梯度融合优化。

2.2 多卡训练

以数据并行随机梯度下降法( SGD )为例,多卡神经网络的训练过程如下图,与单卡训练相比,多卡训练多了梯度全局规约的过程:

多卡训练

第一步,通过Broadcast操作将第一个节点参数同步到集群内的所有的训练卡上,保证每个计算节点的初始参数是一致的,同时训练脚本在多个计算节点上运行,每个计算节点包含了整体的模型参数;

第二步,将数据样本切片分发到整个集群内的个计算节点(训练卡)上并且通过数据流水技术将数据样本加载进训练卡的高速内存空间内,作为输入X;

第三步,每个训练卡在其数据样本上运行前向传播,计算出损失差LOSSi;

第四步,对计算出的LOSSi进行反向传播,得到梯度GRADi,这一步也需要注意得是每一层都会计算出一个梯度,同时梯度是以输出的Tensor来表示的;

第五步,所有的训练卡计算出来的部分梯度,在主机内及主机之间通过集合通信进行全局归约(AllReduce)得到全局梯度;

第六步,最后再将这个全局梯度作为参数进行更新,再进行以上2-5步骤的迭代从而获得新的梯度。

以上2-6步骤就是多卡并行梯度下降的基本思想,即多个计算节点通过分片的数据样本进行梯度计算,得到分区梯度后,再通过全局梯度规约以及将这个聚合好的梯度作为新的参数进行更新,从而实现并行梯度下降。

3. 几个核心问题

在本章节里会解读本文概述里提到的分布式服务框架需要解决的几个与性能、易用性等相关的几个核心问题,并且以Horovod为例讲述Horovod是如何解决这个几个难题的。

3.1 计算与通信解耦

在神经网络的训练过程中,每一神经网络层都会计算出一个梯度,同时梯度是以输出Tensor来表示的,如果反向传播一计算出一个梯度就马上调用通信去做梯度规约,将计算与通信同步耦合,那么整体的性能的表现就会很差。比如一个ResNet-50 v3的梯度张量个数是153个,如果一计算出一个梯度就马上进行通信,假设计算梯度花了1ms,通信这个梯度花了 500ms,那么这个过程就是 501ms,总体上就需要501x153 = 76653ms,即近76.6s才能完成一次梯度迭代。而将计算与通信解耦,计算的归计算,通信的归通信,通过性能优化策略减少通信的次数,既能提升整体训练性能也能避免某些死锁问题,比如计算梯度grad i的时候花了很长时间,而通信线程一直在等待这个梯度,表现出来就是死锁现象。

Horovod采用计算与通信分离的设计思想,解耦了计算过程与通信过程,从而提升了整体训练的性能与可靠性。如下图的Horovod逻辑架构图所示,从图中可以看出Horovod解耦了计算与通信,其将框架层计算出来的梯度request信息push 到一个消息队列message_queue里,同时将梯度信息push到一个Tensor_table里,再通过控制层在后台起一个loop线程,周期性的从消息队列里读取梯度消息,在控制层集群的节点之间协商达成一致后,再进行消息分发触发训练行为。

Horovod逻辑架构

如上图可看出,Horovod从下到上分为7层:物理层、链路层、数据传输层、控制层、消息层、框架层以及用户层。框架层,控制层以及数据传输层体现了Horovod的核心设计理念,即:框架层,用户可以自定义Op,以插件的形式hack进框架;在控制层,worker节点与master节点之间协商达成触发训练行为的约定;在数据传输层,服务器内以及服务器之间采用集合通信库传输数据。

本质上Horovod的整体设计理念之一遵循的是生产者消费者模式,如下图所示:

生产者-消费者

在Horovod里每个计算节点都会有有两个核心线程:Execution thread 和 Background thread :

  • 生产者Execution Thread 是用来做梯度计算的,在TensorFlow、PyTorch之类的之类的训练框架计算出梯度Tensor后,将Tensor 信息push进tenor_table队列,同时将Tensor的request信息push进message_queue队列;
  • 消费者Background thread 是做集合通讯以及全局Allreduce的,后台线程会每隔一段时间轮询消息队列,拿到一批Tensor信息之后,会进行相应的操作。

3.2 通信隐藏

神经网络是分层的,在训练的过程中,先是数据加载,然后前向传播算出LOSS,再反向传播算出梯度,而反向计算时梯度是从输出层往输入层方向一层一层产生的,如果需要等所有的梯度都计算完毕才能触发全局AllReduce,对性能不是很友好。如下图所示,计算时间与通信时间是串行的,如果能将全局梯度规约的通信时间与计算时间想办法并行起来,将通信时间隐藏在计算时间之内,那么就能节约梯度的训练时间从而提升分布式训练系统整体的训练性能。

通信隐藏

如下图所示,将计算出来的梯度进行分桶触发异步Allreduce,一边反向传播计算梯度,一边做部分梯度的全局规约通信,从而达到将通信时间隐藏在计算时间内的效果。而Horovod为达成这一效果,Background thread 会每隔一段时间轮询梯度消息队列里的梯度信息,获取了可以过全局规约的梯度后,就进行全局规约操作,而这个时间其他的梯度还在计算过程中,通过调整轮询的时间间隔从而达到调整梯度分桶的效果。

通信隐藏

3.3 梯度协商

神经网络的每一层对应一个梯度Tensor,在分布式训练集群里每张训练卡对同一份梯度计算产生的时间是有差异的,当集群内每个计算节点的同一神经网络层的同一梯度都产生时,才能发起对这个梯度的全局AllReduce规约,否则容易造成丢梯度,训练出来模型精度不达标或者模型不收敛。比如在一个128卡的训练集群里,同一份梯度是对应同一个神经网络模型里的同一层神经网络的,只有每张训练卡上都计算出了同一层神经网络的梯度 才能对这一层神经网络的梯度进行全局规约,如下图所示:

梯度分层

Horovod设计了一种梯度状态协商机制,它将 计算节点Rank0 作为coordinator(master),其余的rank1-N节点进程为worker,由coordinator来协商确定同一份梯度是否在每个计算节点上都已经计算出来,只有在每个计算节点上都计算出来的同一梯度才可以进行全局规约操作。在Horovod里每个计算节点上都有一个message_queue以及tensor_table,而在coordinator节点上除此之外,还有一个message_table用于保存可以进行全局Allreduce的梯度请求次数信息。Horovod 控制面的ComputeResponseList 函数里实现了这一梯度的协商过程,在从message_queue获取了本节点生成的梯度信息后,coordinator会与其他节点协商这个梯度是否都计算出来,这一过程是阻塞进行的,这个协商过程如下图:

梯度状态协商

一个梯度是否能满足全局规约AllReduce的协商过程如下:

首先,集群内的每个计算节点进程都会往coordinator Rank0发送一个 tensor的请求request,表示说本节点这一层神经网络的梯度已经生成,比如tensor1,每个rank都会往rank0 发送一个本梯度tensor1已经计算出来的请求信息;

第二步,coordinator接收到节点的梯度协商请求后(包括本节点),会把收到的tensor请求次数进行累加,并将这个信息记录在message_table里,当这个梯度的请求信息达到集群内节点的个数时,比如在N个节点的集群,一个神经网络层的梯度tensor的通信请求出现了N次,那就表示在本集群里所有的计算节点都已经发出了对该梯度tensor的通信request,这就表明这个梯度tensor是符合全局规约要求的,就能进行集合通信全局规约,不符合要求的梯度tensor将继续留在message_table中,直到条件符合为止;

第三步,再接着coordinator会将满足全局allreduce规约条件的梯度Tensor通过response返回给其他节点,告诉其他节点这个梯度可以启动全局规约AllReduce。

经过这几步的协商达成梯度全局状态一致的目的,从而避免梯度丢失造成的模型精度不达标、不收敛或者进程死锁问题。

3.4 梯度融合

神经网络的每一层都能对应一个梯度,假设每生成一个梯度就进行一次全局规约时,100个梯度就需要进行100次全局通信100次全局规约,而通信对训练的性能有巨大的影响,这种情况表现出来的效果就是分布式训练集群的整体性能极差。通过梯度融合计算将多个梯度合成一个,从而减少全局规约的次数能大幅提高分布式训练的训练性能,如下图所示,将N个小梯度Tensor合成两个,能将全局通信的次数减少到2次,从而大幅提升训练性能,在Horovod里这个功能对TensorFusion特性。但这个特性也会与3.2通信隐藏特性相冲突,需要根据具体情况进行合理的调试优化。

tensorfusion

3.5 易用性

从TensorFlow,PyTorch等框架迁移到Horovod需要改的的代码极少,horovod接入方式比较简单,与原生训练框架对比,主要的区别在于:

1
2
3
4
5
6
7
8
9
10
11
12
13
1,初始化 Horovod,包括机器资源的分配:
horovod.init()

2,向每个进程分配XPU资源, 典型的设置是 1 个 XPU 一个进程,即设置 local rank:

config.gpu_options.visible_device_list = str(hvd.local_rank())

3,对原优化器进行包装,分布式优化器将梯度计算委托给原始优化器,使用allreduce或allgather对梯度求平均,然后应用这些平均梯度:

opt=hvd.DistributedOptimizer(opt)

4, 将初始化参数从rank 0广播给其他进程(rank表示进程序号),实现参数的初始化,确保所有节点的初始化参数保持一致:
hvd.BroadcastGlobalVariablesHook(0):

3.6 可移植

可移植问题,Horovod通过 OP和OpKernels的插件化机制支持多种多样的深度学习训练框架,比如 TensorFlow、PyTorch、MxNet等。基于的opKernels的可定制化机制,Horovod自定义了Op然后hack了数据链路层的通信协议,从而达到在多个深度学习框架之间可移植。

3.7 可靠性问题

在集群训练的过程中网络时不可靠的、计算卡是会出故障的、服务器是会出故障的的,这些因素造成了分布式训练过程中需要考虑训练集群的可靠性,Horovod结合集合通信库Gloo对外提供了弹性训练的特性,但可靠性不只是弹性训练就能完全解决的,它还有更多的系统级的问题需要解决,因此可靠性问题留着一个后续研究问题,不在本文阐述。

4. 优点缺点、改进点

选择一个框架也是辩证的,在获得它优点的同时也得接受它的缺点,Horovod的优点、缺点以及改进点描述如下:

4.1 Horovod优点

  • 简单易用、可移植,并且支持弹性训练提升了可靠性;
  • 不依赖于某个框架,其通过MPI机制独立建立了一套分布式训练服务系统;
  • 将计算与通信分离,完成了allreduce、allgather等集合通信工作,实现了规模可扩展;
  • 巧妙的通过间隔轮询的机制支持通信时间隐藏,并且完成了梯度协商从而保证训练出来的模型是可收敛、精度达标的;
  • 支持梯度融合,支持将小的tensor合并成一个大的tensor再进行通信传递,从而减小通信操作的额外开销;
  • 自带压缩算法,可以减少集合通信的数据量;

4.2 Horovod的缺点

  • 与GPU绑定,对新的训练加速设备的支持不够友好,缺乏设备插件化的机制,要添加一个新的训练加速设备比较困难;
  • 所有的代码都与CUDA绑定,所有的性能优化机制都是针对GPU的,对新的DSA架构的芯片基本忽视;
  • 弹性训练特性比较复杂,很难在生产上使用起来;
  • 的Message_queue,Tensor_table缺乏容错机制,如果丢失数据容易造成丢tensor,从而影响整体模型的收敛与精度;

4.3 Horovod的改进点

  • 简单易用的插件化支持新的训练芯片;
  • 即支持SIMT架构芯片的性能优化,也支持DSA架构的芯片性能优化;
  • 支持消息队列、张量表的容错,支持Rank 0 容错机制;

5. 思考题

  • 问题1,将通信时间隐藏在计算时间内能有助于提升训练系统的整体性能,但这一特性是针对SIMT芯片的架构的进行性能优化的,如果DSA芯片不能支持这一特性,那应该如何优化Horovod从而大幅提升整体的训练性能?(可以确定这一定是能做到的)
  • 问题2,梯度协商的过程中,每个梯度都需要协商一次,在梯度较多,网络规模较大的集群里,这一特性也会影响性能,如何进行优化才能有效提升Horovod性能?
  • 问题3,不同的模型对梯度融合有不同的要求,那么梯度融合需要融合到什么程度才能有效提升性能?

可以说明的是,这三个问题解决后还能继续提升Horovod在DSA架构芯片上的整体的分布式训练系统级性能。

6. 小结

本文介绍了分布式训练的基础知识以及剖析了分布式训练服务框架所面临的几个核心问题,以Horovod为例从计算与通信解耦、通信隐藏、梯度协商、梯度融合、易用性以及可移植这几个角度倒推了分布式训练服务框架背后的设计意图,从而帮助大家能更好的理解分布式训练服务框架。

日拱一卒,功不唐捐,分享是最好的学习,与其跟随不如创新,希望这个知识点对大家有用。另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

7. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

8. 参考资料

[1] https://www.changping.me
[2] https://horovod.ai
[3] https://www.cnblogs.com/rossiXYZ/p/14910959.html
[4] https://zhuanlan.zhihu.com/p/374575049

9. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

1. 概述

在深度学习的分布式训练里,Ring AllReduce拓扑算法奠定了数据并行训练的集合通信基础,但集合通信拓扑不只是仅有Ring Allreduce,经典的集合通信拓扑算法还有2D-Ring/Hierarchical Ring AllReduce,halving and doubling AllReduce,Butterfly AllReduce,2D-Torus AllReduce,2D-Mesh AllReduce,double binary tree等。拓扑算法很多,但也不是所有的拓扑算法都能满足实际的生产需求的,这需要具体问题具体分析、具体场景具体设计。

集合通信的难点在于需要在固定的网络互联结构的约束下进行高效的通信,集合通信拓扑算法与物理网络互联结构强相关,为了发挥网络通信的效率,也不是说就能随意发挥通信拓扑算法,更多的是在效率与成本、带宽与时延、客户要求与质量、创新与产品化等之间进行合理取舍。

充分发挥训练加速卡与网络的效率是通信拓扑算法的初衷,但除了设计高效的集合通信拓扑算法外,分布式训练中需要解决的通信难题还有:网络是异构的,网络带宽是有限的,主机内PCIE SWITCH是有亲和性的,网络是会出故障的,节点是有落后者效应的,设备成本是需要考虑的,数据中心是有部署约束的,用户是有多租户要求的等,这些属于产品化的范畴不在本文阐述。

2. 网络互联结构

分布式训练的集合通信拓扑算法与物理的网络互联结构强相关,而网络互联结构又多种多样,因此,本文需要先对网络互联结构进行约束,依据生产中常用的、既定的互联结构设计集合通信算法,网络互联结构描述如下:

2.1 服务内网络互联结构

以一台集成了8张训练加速卡的服务器为例,如下图:

服务器内互联结构

图片来源于《volta-architecture-whitepaper》,版权归原作者所有

这台服务器内的网络互联情况如下:

1)在这台服务器内,8张训练加速卡通过私有协议连接组成多个主机内的物理ring环,且可双工;

2)服务期内网络带宽 NVLINK>PCIE switch > QPI;

3)加速卡1、2、3、4之间两两全互联,加速卡5,、6、7、8之间两两全互联,2、5、3、8之间非全互联;

4)加速卡1、4与网卡NIC1 挂在同一个PCIE Switch上,具有亲和性,加速卡2、3与网卡NIC2挂在同一个PCIE Switch上,具有亲和性,而PCIE Switch之间也互联,因此 加速卡 1、2、3、4 与网卡NIC 1、NIC2具备亲和性,它们无需通过CPU的QPI线进行通信;

5)加速卡5、8与网卡NIC3 挂在同一个PCIE Switch上,具有亲和性,加速卡6、7与网卡NIC4挂在同一个PCIE Switch上,具有亲和性,而PCIE Switch之间也互联的,因此 加速卡 5、6、7、8 与网卡NIC 3、NIC4具备亲和性,它们也无需通过CPU的QPI线进行通信;

6)网卡可根据需要 选择 1张、2张、4张或8张,最多可以采用8张RDMA物理网卡;

2.2 服务器间网络互联结构

以一个训练加速卡集群为例,如下图是一个常用的CLOS互联架构方案:

整体网络拓扑结构

在这个集群内,其网络互联情况如下:

1)集群内每台服务器自带高速RDMA网卡,通过RDMA 交换机在主机间两两全互联;

2)交换机组成CLOS架构,分为Spine与Leaf交换机,当然也可以是更为高端的Spine、Leaf合一的高端交换机;

3)RDMA网卡与Leaf交换机互联,每台服务器的RDMA网卡数量根据成本与性能考虑,可以是1张、2张+每卡虚拟化4卡、4张+每卡虚拟化2卡或8张;

2.3 高速网卡及其虚拟化使用

RDMA网卡是双工的且可虚拟化,在这里每台服务器可根据成本、性能的考虑选用1张、2张、4张或8张,且在服务器内左右对称,如下图:

网卡配置

从成本与效率的角度考虑,每台服务器内的网卡可以是以下配置:

  • 1张物理RDMA网卡,不进行虚拟化,直接用双工通道,适合选用2D/Hierarchical Ring拓扑算法;
  • 2张物理RDMA网卡,可以每张虚拟化出4个虚拟网卡,2X4共8卡,适合选用2D-MESH、2D-Torus拓扑算法;
  • 4张物理RDMA网卡,可每张虚拟化出2个虚拟网卡,4X2共8卡,适合选用2D-MESH、2D-Torus拓扑算法;
  • 8张物理RDMA网卡,不需要虚拟化,直接采用双工通道,适合选用2D-MESH、2D-Torus拓扑算法;

在实际的分布式训练生产集群中,集合通信算法也可以结合RDMA网卡端口(包括虚拟化的)的具体个数进行设计,而拓扑算法的选择也是需要根据成本与效率的进行合理取舍的。

2.4 网络结构抽象

网络根据连接情况可分为ring结构、mesh结构、 torus 结构以及tree结构,基于以上的服务器内网络互联结构、服务器间网络互联结构以及网卡的具体情况,可以抽象出一个网络结构,即二维环面网络:Torus 网络,而Torus网络横向与纵向都可以看成ring结构,因此相应的拓扑算法基本上就是Ring-Based 集合通信拓扑算法。如下图:

Torus网络结构

TORUS网络是常见的大规模并行计算机的互连网络,在上图这个Torus网络里:

1)横向:主机内8卡通过私有连接协议,比如CXL/CCIX/NVLINK等组成一个或多个ring,如上图的黄色连接线,横向8卡组成二维Torus的横向维度;

2)纵向:主机间通过RDMA(RoCE/IB)网卡、交换机互联组成1到8个ring,如上图的红色连接线,纵向采用RDMA网卡组成二维Torus的纵向维度;

3)根据物理网卡数量、网卡虚拟化以及PCIe Switch亲和性的实际情况:

  • 每台服务器1张网卡可组成主机间一个ring,网卡与XPU0 挂载同一个PCIE switch上,依据最佳实践原则(比如性能、成本、客户要求等),适合选用2D/Hierarchical Ring拓扑算法;
  • 两张网卡可组成主机间两个ring或者经过虚拟化组成8个ring,根据PCIE SWITCH亲和性原则,一张网卡与XPU0挂在同一个pcie switch,另一张网卡与XPU4挂在同一个pcie switch,依据最佳实践原则(比如性能、成本、客户要求等),适合选用2D-MESH、2D-Torus拓扑算法;
  • 4张网卡、8张网卡以此类推,也是根据PCIE SWITCH亲和性原则进行连接,主机间RDMA物理网卡不够就虚拟化网口来凑,并且要服务器内的RDMA出口端口数左右平衡,依据最佳实践原则(比如性能、成本、客户要求等),也是适合选用2D-MESH、2D-Torus拓扑算法,这样才能发挥多张网卡以及XPU的算力优势。

4)更复杂的Torus网络组合关系还可以如下图,从横向只有 主机内的8卡纵向只有主机间的RDMA互联,扩展到 横向与纵向 主机内互联与主机间互联混合,但本文仅限于在横向8卡的二维Torus网络下进行拓扑算法选择与设计,因此不展开讲述。

Torus网络结构

3. 常用的通信拓扑算法

Torus 网络结构可以解读本文中的物理网络互联结构的一切,而Torus网络的横向与纵向都可以看成ring结构,因此,相应的集合通信拓扑算法都可以看成是Ring-Based 集合通信拓扑算法。

3.1 Ring AllReduce

在分布式训练中,Ring 是最基础的互联结构,在本文中Ring AllReduce的应用场景是在服务器内将8张加速卡组环通信进行分布式训练。每个XPU都是这个主机内互联环上的一个计算节点,每个节点都有一个前向和一个后向,它只会向它的前向接收数据,并向它的右向发送数据,如下图所示,8张XPU 通过主机内的私有互联网络组成一个环,当然因为这些通信网络是双工的,这8张XPU训练加速卡也可以看成是通过多个逻辑环互联起来的,同时缺点是,如果这个ring太大,Ring Allreduce的效率也会变得很低。

ring拓扑

Ring Allreduce 有两种组合实现策略:1)先Reduce后broadcast;2)先ScatterReduce后AllGather,这两个策略执行后都会让每个XPU节点得到一样的平均梯度,如下图所示:

allreduce

3.1.1 Reduce +broadcast

在Reduce + broadcast里,reduce先将8张卡的梯度reduce sum到master节点 XPU0 上,再通过broadcast将这个总的平均梯度复制给其他XPU,如下图:

ring reduce broadcast

Reduce + broadcast这种策略有几个比较大的缺点:1)8张卡的数据都reduce sum到一张卡,假设每张卡的梯度是100MB,8张卡就是800MB,这可能存在XPU 0计算很久,而其他7张卡空闲的情况存在,整体效率不高;2)XPU0 的网络带宽可能会成为瓶颈,8张卡的数据都只能通过XPU0的互联网络进行reduce和broadcast,在数据量比较大的场景 XPU0的带宽成为瓶颈;3)8张XPU不都是两两全互联的,因此,要把8张卡的数据一次Reduce或broadcast,这一点受限于网络互联条件做不到,那么就需要采用 ring或tree的策略进行reduce或broadcast,这样效率也不高。

3.1.2 ScatterReduce + AllGather

Ring AllReduce 的Ring ScatterReduce + Ring AllGather策略组合里,每个 XPU只会从前向接受数据,并发送数据给后向,其算法主要分为:

  • ScatterReduce:这一步会先scatter拆分数据块再进行reduce,并且在执行完毕后,每张XPU都会包括一个完整的经过融合的同维梯度;
  • AllGather:这一步会进行全局Gather同步,最后所有 XPU都会得到完整的大的整个梯度;

Ring ScatterReduce + Ring AllGather是效率比较高的 Ring AllReduce 组合策略,这个策略考虑到了XPU上的梯度可能很大的情况,比如一个梯度有400MB,在scatterreduce阶段就会先被拆分成 ring上XPU个数份,比如主机内XPU个数等于8,那么 这400MB 就会被 拆分成8份,每份50MB,从而减少了加速卡的计算量以及节约带宽。此外,scatterReduce通过将数据拆分成小块,同时并发进行scatterReduce,从而将通信时间隐藏在计算时间内进而提高Ring AllReduce的效率。

3.1.2.1 ScatterReduce

首先, ScatterReduce先将梯度拆分为N个更小的块,N等于ring里XPU个数,8张卡就拆分成8份,然后进行N-1次scatterreduce迭代。在第一轮迭代中XPU 0上的A0传递给XPU1上A1并相加,XPU1上的B1传递给XPU2上的B2并相加,XPU 2上的C2传递给XPU3上C3并相加,XPU3上的D3传递给XPU4上的D4并相加,以此类推,过程如下图左侧:

ring acatterreduce

接下来,XPU还会进行N-2次 ScatterReduce 迭代,在每次迭代过程中,XPU都会从前向接收一个小梯度块并累加到自己的梯度块中,并且也会向其后向发送一个小梯度块,每个XPU接收和发送的小梯度块在每次迭代中都是不同的,这样经过迭代,到最后,每个XPU将有一个完整的同维梯度,该块梯度中包含所有XPU中该块对应的所有梯度的总和,如上图右侧的累加和部分。

3.1.2.2 Allgather

在scatterReduce迭代完成之后,每个XPU都会得到一个同维度的完整的梯度累加值,将这些完整的累加值复制到其他的加速卡后,才算完成allReduce。Allgather的迭代次数与scatterReduce是相同的,也都需要进行N-1次(N是ring上的XPU卡数)迭代,但是不同于ScatterReduce的是allGather没有reduce的过程,只有数值的复制。这样迭代到最后,每个XPU都得到大的拆分前的梯度的完整累加值,如下图演示了这一过程,从第一次迭代开始,到最后AllGather拿到整体的结果。这里头的具体过程就不在这里描述了,可以查相关资料。

image-20220409203458896

Ring AllReduce 实现简单,在ring较少时,效率也较高,但是在ring比较大时需要的网络节点跳数变得比较大,通信时延增加,因此效率也会降低。比如,一个1000张XPU的 ring,这里头网络的跳数 是N-1= 1000-1 =999, 同时传输的过程中,传输效率还受效率最低、带宽最低的XPU的限制,这时网络上的时延会变得巨高,这个时候ring allreduce拓扑算法就变得不大适用这个场景,同时如果在异构网络里涉及网络的不同连接方式,Ring AllReduce也不大适合使用,因此就需要采用另外的更适合网络结构的更高效的集合通信拓扑算法来进行优化。

3.2 2D-Ring AllReduce

如果一台2.1里的服务器只配置了一张RDMA网卡,每台服务器通过RDMA交换机互联,这个集群的网络是异构的(如下图),那么Ring AllReduce拓扑算法就不适用了,这个时候,对于这个网络拓扑结构比较适合的是2D-Ring AllReduce也叫Hierarchical Ring AllReduce。

2D-RING 拓扑

经过抽象,可以将这个网络结构表达成如下的Torus结构:

横向:每台服务器8个XPU节点,每个XPU节点通过私有协议网络互联;

纵向:每台服务器通过一张RDMA网卡NIC 0 通过交换机互联,这个网卡NIC0 与XPU0 挂在同一个PCIE switch上,满足具备亲和性条件,XPU0上的梯度可以通过NIC 0 与其他服务器上的XPU进行全局规约。

2D-RING TOPO

2D-Ring AllReduce的过程如下图所示:

2D-RING allreduce

第1步,先进行主机内Ring AllReduce,也可以是 Ring Reduce或者根据主机内的互联情况选用的分层reduce方式,将8张卡上的梯度累加到Master节点 XPU0 上;

第2步,进行主机间XPU 0的 Ring AllReduce,将每台服务器的XPU0上的数据进行全局规约;

第3步,进行主机内Broadcast,将XPU0上的梯度复制到服务器内的其他XPU上

2D-Ring AllReduce能充分发挥异构网络的优势,将主机内、主机间的网络带宽充分利用起来。但是XPU的利用率也不是很高,比如在做主机间的Ring AllReduce,每台服务器内的其他7张XPU是处于空闲状态的。

再假设,如果每台服务器配置了 2张/4张/8张RDMA网卡,这个时候 2D-RING AllReduce又难以将网络的优势发挥出来,那么就需要选用 2D-Torus/2D-Mesh AllReduce拓扑算法。

3.3 2D-Torus AllReduce

考虑到服务器内PCIE SWITCH 的亲和性问题,2D-Torus至少需要配备2张 左右对称的RDMA网卡才能发挥这个拓扑算法的优势。在这个集群里主机内每张卡都通过私有的通信协议组成Ring,而主机间,可以通过RDMA网卡(包括虚拟化出来的)与RDMA交换机将XPU两两互联,这个网络也是异构的,如下图所示:

设备互联拓扑

经过抽象,可以将这个网络结构表达成如下的Torus结构:

  • 横向:每台服务器8个XPU节点,每个XPU节点通过私有协议网络互联;
  • 纵向:每台服务器通过至少2张RDMA网卡NIC 0 /NIC 1通过交换机互联,这个网卡NIC0 与XPU0、1、2、3 挂在同一个PCIE switch上,具备亲和性条件,XPU0、1、2、3上的梯度数据可以通过NIC 0 与其他服务器上的XPU进行交换。网卡NIC1 与XPU4、5、6、7 挂在同一个PCIE switch上,具备亲和性条件,XPU4、5、6、7上的梯度数据可以通过NIC 1 与其他服务器上的XPU进行交换;
  • 当然如果网卡是4个或者8个,也可以根据PCIE SWITCH的亲和性情况合理安排XPU与NIC的对应关系。

2D 拓扑

2D-Torus AllReduce的过程如下图所示:

2dtorus allreduce

第1步,横向,先进行主机内Ring ScatterReduce,将主机内8张卡上的梯度进行拆分与规约,这样经过迭代,到最后每个XPU将有一个完整的同维梯度,该块梯度包含所有XPU中该块所对应的所有梯度的总和(参考3.1.2.1 scatterReduce)

第2步,纵向,进行主机间N个(N等于服务器内XPU个数,这里是8个)纵向的 Ring AllReduce,将每台服务器的XPU0-XPU7上的数据进行集群内纵向全局规约;

第3步,横向,进行主机内AllGather,将XPUi(i=0-7)上的梯度复制到服务器内的其他XPU上;

2D-Torus AllReduce能充分挖掘XPU的效率以及发挥异构网络里多网卡的优势,将XPU以及主机内、主机间的网络带宽优势充分利用起来。此外,除了 2D-Torus AllReduce外,2D-Mesh AllReduce也能发挥类似效率。

3.4 2D-Mesh AllReduce

2D-Mesh AllReduce的主要思想也是分层,与2D-Torus AllReduce类似,都是水平和垂直两个方向,但是有点差异,如下图所示:

2D-MESH allreduce

不同于2D-Torus AllReduce的拓扑算法,2D-Mesh AllReduce 过程是:

第1步,横向,先进行主机内Ring AllReduce 将主机内的8张XPU的梯度都进行规约;

第2步,纵向,进行主机间N个(N等于主机内XPU个数,这里是8个)纵向的 Ring AllReduce;

经过这两步,完成了整体的梯度累加,2D-Mesh AllReduce 也能充分发挥XPU与多网卡异构网络的优势,将XPU与主机内、主机间的网络带宽优势充分利用起来。这里的2D-Mesh与Google论文上的有点差异,主要是吸取了其分层的思想而不是复制其一样的设计。理论上2D-Mesh AllReduce对比 2D-Torus AllReduce,主机间AllReduce用的是 主机内8卡的全局梯度,数据量会比ScatterReduce部分来的大点,因此效率也会相应降低一点。

4. 问题探讨

如下图所示,基于Torus网络的结构,组合Ring AllReduce,2D-Ring AllReduce, 2D-Mesh AllReduce,2D-Torus AllReduce还能构建 3D-Ring/Mesh/Torus AllReduce拓扑算法,但是这些拓扑算法的效率需要进行实践才能证实,也许在规模较大的集群里才能发挥出3D 拓扑算法的优势。

2D-Torus拓扑

关于 3D-Ring/Mesh/Torus AllReduce的拓扑算法,这里就不在阐述,可作为研究使用。

5. 小结

本文讲述了分布式训练里最常用的几个网络结构以及通信拓扑算法:

  • Ring AllReduce 的最佳组合是 ScatterReduce + AllGather;
  • 2D-Ring AllReduce = 主机内 ringAllReduce/Ring Reduce +主机间 RingAllReduce + 主机内Broadcast;
  • 2D-Torus AllReduce = 主机内 Ring ReduceScatter + 主机间N个Ring AllReduce + 主机内Ring AllGather;
  • 2D-Mesh AllReduce = 主机内Ring AllReduce + 主机间N个Ring AllReduce;

Ring AllReduce适合主机内互联Ring的情况使用,2D-Ring AllReduce适合一台服务器配置了一张网卡的异构网络场景,2D-Torus AllReduce与2D-Mesh AllReduce适合一台服务器配置了2/4/8张网卡的异构网络场景。

集合通信拓扑算法多种多样,但基于成本以及效率的取舍考虑,可生产适用的其实也不多,除了理论上的理解之外更重要的是自己编写代码去实践落地。除此之外,还需要解决网络带宽有限、网络容易出故障、落后者效应、部署约束、多租户等产品化的质量要求。日拱一卒,功不唐捐,分享是最好的学习,与其跟随不如创新,希望这个知识点对大家有用。另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

6. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

7. 参考资料

[1] https://www.changping.me

[2] 《volta-architecture-whitepaper》

[3] 2D-HRA: Two-Dimensional Hierarchical Ring-based All-reduce Algorithm in Large-Scale Distributed Machine Learning

[4] Massively Distributed SGD: ImageNet/ResNet-50 Training in a Flash

[5] https://zhuanlan.zhihu.com/p/79030485 , 腾讯机智团队分享–AllReduce算法的前世今生

[6] https://zhuanlan.zhihu.com/p/370548366, ring allreduce和tree allreduce的具体区别是什么?

[7] https://zhuanlan.zhihu.com/p/184942777 , 分布式深度学习初探

[8] https://arxiv.org/abs/1811.06992 , Image Classification at Supercomputer Scale

8. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

1. 概述

集合通信(Collective Communications)是一个进程组的所有进程都参与的全局通信操作,其最为基础的操作有 发送send、接收receive、复制copy、组内进程栅障同步Barrier以及节点间进程同步(signal +wait ),这几个最基本的操作经过组合构成了一组通信模板也叫通信原语,比如:1对多的广播broadcast、多对1的收集gather、多对多的收集all-gather、1对多的发散scatter、多对1的规约reduce、多对多的规约all-reduce、组合的规约与发散reduce-scatter、多对多的all-to-all等,集合通信的难点在于通信效率以及网络硬件连接拓扑结构的最佳适用。

2. 通信原语

以一台集成了4张训练加速卡的服务器为例,如下图,服务器内四张训练加速卡是全连接的,物理连接方式可以是私有物理互联协议,比如CXL、NVLINK,也可以是PCIe、InfiniBand、Ethernet等,本文将以此物理拓扑结构描述集合通信中常用的几组通信原语。

image-connect-topo

2.1 Broadcast

Broadcast属于1对多的通信原语,一个数据发送者,多个数据接收者,可以在集群内把一个节点自身的数据广播到其他节点上。如下图所示,圈圈表示集群中的训练加速卡节点,相同的颜色的小方块则代表相同的数据。当主节点 0 执行Broadcast时,数据即从主节点0被广播至其他节点。

image-20220404193446314

Broadcast是数据的1对多的同步,它将一张XPU卡上的数据同步到其他所有的XPU卡上,其应用场景有:

1)数据并行的参数初始化,确保每张卡上的初始参数是一致的;

2)allReduce里的 broadcast + reduce组合里的broadcast操作;

3)分布式训练parameter server 参数服务器结构里的 master节点 broadcast 数据到worker节点,再从worker节点reduce数据回master节点里的broadcast操作;

2.2 Scatter

同Broadcast一样,Scatter也是一个1对多的通信原语,也是一个数据发送者,多个数据接收者,可以在集群内把一个节点自身的数据发散到其他节点上。与Broadcast不同的是Broadcast把主节点0的数据发送给所有节点,而Scatter则是将数据的进行切片再分发给集群内所有的节点,如下图所示,不相同的颜色的小方块代表不相同的数据,主节点 0 将数据分为四份分发到了节点0-3。

image-20220404193446314

Scatter是数据的1对多的分发,它将一张XPU卡上的数据进行分片再分发到其他所有的XPU卡上,他的反向操作对应Gather,其应用场景有:

1)ReduceScatter组合里的 Scatter操作;

2)模型并行里初始化时将模型scatter到不同的XPU上;

2.3 Gather

Gather操作属于多对1的通信原语,具有多个数据发送者,一个数据接收者,可以在集群内把多个节点的数据收集到一个节点上,如下图所示,不相同的颜色的小方块代表不相同的数据。

image-20220404193952158

Gather是数据的多对1的收集,它将多张XPU卡上的数据收集到1张XPU卡上,他的反向操作对应Scatter,其应用场景有:

1)ReduceScatter组合里的 Scatter操作;

2.4 AllGather

AllGather属于多对多的通信原语,具有多个数据发送者,多个数据接收者,可以在集群内把多个节点的数据收集到一个主节点上(Gather),再把这个收集到的数据分发到其他节点上(broadcast),即收集集群内所有的数据到所有的节点上。

image-20220404194323067

AllGather是数据的多对多的同步全收集,它将多张XPU卡上的数据收集到多张XPU卡上,可以看做Gather + Broadcast的操作组合,它的反向操作对应ReduceScatter,其最应用场景有:

1) AllGather可应用于模型并行;

2)模型并行里前向计算里的参数全同步,需要用allgather把模型并行里将切分到不同的XPU上的参数全同步到一张XPU上才能进行前向计算。

2.5 Reduce

Reduce属于多对1的通信原语,具有多个数据发送者,一个数据接收者,可以在集群内把多个节点的数据规约运算到一个主节点上,常用的规约操作符有:求累加和SUM、求累乘积PROD、求最大值MAX、求最小值MIN、逻辑与 LAND、按位与BAND、逻辑或LOR、按位或BOR、逻辑异或LXOR、按位异或BOXR、求最大值和最小大的位置MAXLOC、求最小值和最小值的位置MINLOC等,这些规约运算也需要加速卡支持对应的算子才能生效。

Reuduce操作从集群内每个节点上获取一个输入数据,通过规约运算操作后,得到精简数据,如下图的SUM求累加和:节点0数值 5、节点1数值6、节点2数值7、节点3数值8,经过SUM运算后 累积和为 26,即得到更为精简的数值,在reduce原语里回会去调用 reduce SUM算子来完成这个求和累加。

image-20220404194633808

Reduce是数据的多对1的规约运算,它将所有张XPU卡上的数据规约(比如SUM求和)到1张XPU卡上,其应用场景有:

1)AllReduce里的 broadcast + reduce组合里的reduce操作;

2)ReduceScatter组合里的 reduce操作;

3)分布式训练parameter server 参数服务器结构里的 master节点 broadcast 数据到worker节点,再从worker节点reduce数据回master节点里的reduce操作;

2.6 ReduceScatter

ReduceScatter属于多对多的通信原语,具有多个数据发送者,多个数据接收者,其在集群内的所有节点上都按维度执行相同的Reduce规约运算,再将结果发散到集群内所有的节点上,Reduce-scatter等价于节点个数次的reduce规约运算操作,再后面执行节点个数的scatter次操作,其反向操作是AllGather。

如下图所示,先reduce操作 XPU 0-3的数据reduce为 A(A0+A1+A2+A3) + B(B0 + B1 +B2 + B3) + C(C0 + C1 + C2 + C3) + D(D0 + D1 + D2 + D3 ) 到一张XPU上,再进行分片scatter到集群内所有的XPU卡上。

image-20220404200227476

ReduceScatter是数据的多对多的reduce + scatter运算,它将所有的XPU卡上的数据先规约(比如SUM求和)到1张XPU卡上,再进行scatter,其应用场景有:

1)ReduceScatter即可应用于数据并行也可应用于模型并行;

2)数据并行allReduce里的 ReduceScatter+ Allgather组合里的ReduceScatter操作;

3)模型并行里在前向allgather后的反向计算里的ReduceScatter;

2.7 AllReduce

AllReduce属于多对多的通信原语,具有多个数据发送者,多个数据接收者,其在集群内的所有节点上都执行相同的Reduce操作,可以将集群内所有节点的数据规约运算得到的结果发送到所有的节点上。AllReduce操作可通过在主节点上执行Reduce + Broadcast或ReduceScatter + AllGather实现,如下图所示:先在主节点上执行reduce得到规约累加和26,再把这个累加和26 broadcast到其他的节点,这样整个集群内,每个节点的数值就都保持一致。

image-20220404195550358

AllReduce是数据的多对多的规约运算,它将所有的XPU卡上的数据规约(比如SUM求和)到集群内每张XPU卡上,其应用场景有:

1) AllReduce应用于数据并行;

2)数据并行各种通信拓扑结构比如Ring allReduce、Tree allReduce里的 allReduce操作;

2.8 All-To-All

All-To-All操作每一个节点的数据会scatter到集群内所有节点上,同时每一个节点也会Gather集群内所有节点的数据。ALLTOALL是对ALLGATHER的扩展,区别是ALLGATHER 操作中,不同节点向某一节点收集到的数据是相同的,而在ALLTOALL中,不同的节点向某一节点收集到的数据是不同的,如下图所示

image-20220404202332268

AllToAll是数据的多对多的转置,它将所有张XPU卡上的数据转置到所有的XPU卡上,其主要应用场景有:

1) AllToAll应用于模型并行;

2)模型并行里的矩阵转置;

3)数据并行到模型并行的矩阵转置;

2.9 Send 与 Receive

数据或参数在不同XPU之间的发送与接收。

2.10 Barrier

BARRIER同步操作会阻塞所有的调用者直到所有的组内成员都调用了它, 用于一个集合通信子中所有进程的同步,调用函数时进程将处于等待状态,直到通信子中所有进程 都调用了该函数后才继续执行。

2.11 Signal与Wait

Signal与Wait属于记录型信号量机制: wait(s),signal(s)可用于解决进程间的同步问题,在通信原语里从一个节点发送一个数据到另外一个节点时,会同时signal一个event值到对端,对端的wait操作接收到这个event时会返回一个确认给signal,这样保证在节点的进程间进行数据的同步操作。

3. 小结

在分布式训练过程中,深度学习训练框架不会去直接操作底层的通信网络,而是通过使用网络通信库来完成数据的集合通信,各家AI芯片加速卡厂家都会提供私有的网络通信库比如:xxx-AWARE OpenMPI或xCCL来完成这个底层通信硬件的屏蔽与抽象。在分布式训练集群里网络通信硬件连接样式多种多样,可以是Ethernet、InfiniBand 、RoCE v2/v1 等也可以是CXL、NVLINK等私有协议,这就要求在通信的后端层根据各个厂家的自己的SDK开发库接口,根据实际情况实现 各自的网络通信库,比如cuda-aware MPI、NCCL、NVSHMEM,以及根据实际的网络拓扑组合完成对应的最有效的网络拓扑算法。

本文讲述了分布式训练里的集合通信原语,这些原语是集合通信拓扑算法的基本组成单元,后续的文章里会讲述如何组合这些通信原语以完成合适的通信拓扑算法。日拱一卒,功不唐捐,分享是最好的学习,与其跟随不如创新,希望这个知识点对大家有用。另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

4. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

5. 参考资料

[1] https://www.changping.me

[2] http://scc.ustc.edu.cn/zlsc/cxyy/200910/MPICH

[3] 《用这拌元宵,一个字:香!| 分布式训练硬核技术——通讯原语》

[4] 《NCCL-Woolley》

[5] 《利用MegEngine分布式通信算子实现复杂的并行训练》

6. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

1. 前言

需要回答如何弥补开源项目与企业级商业产品之间的差距,首先需要回答两个基本问题:”什么是产品?“以及“如何将一个开源的软件项目产品化?”。一套科学技术分析方法的背后有一定有着深刻的理论基础和哲学背景。找到了这套技术分析的源头,才能从本质上把握这套技术,看清其全貌,明了其长处和短处,这样在具体应用中,才能得心应手,提高胜算,并不断的丰富和发展这套技术。基于此,本文提出了一套方法论,回答如何将开源软件项目产品化从而弥补开源项目与企业级商业产品之间的差距。

2. 什么是产品

依据公开的信息对产品的定义如下:

产品是指做为商品提供给市场,被人们使用和消费,并能满足人们某种需求的任何东西,包括有形的物品、无形的服务、组织、观念或它们的组合。

从产品的定义中我们可以看到以下几点:

  • 属性:有形的物品、无形的服务、组织、观念或它们的组合,因此产品自带有形或无形属性;

    • 有形属性:狭义上产品是被生产出的能满足人们需求的具有物理属性的有形的物品。在绝大多数人的认知里,对产品的理解是停留在这一层次的,产品具有看得见、摸得着的物理形态;
    • 无形属性:广义上产品是可以满足人们需求的任何东西,无形的服务、组织、观念或者它们的组合也是产品。广义上的产品定义对人的认知有更高的要求。服务是产品、企业是产品、团队是产品、认知是产品、本文是产品,这些东西的组合也是产品。万物皆产品,它目前不是产品,那只是没被产品化、或者不在对的时间与空间里;
  • 价值:产品首先是商品,其具有交易的价值,能提供给市场,供人们使用与消费,所有不能交易的东西不在产品的定义范围之内,因此这里可以推导出产品是具有价值的,没有价值的东西不属于产品的范畴;

  • 交易:产品是做为商品提供给市场,被人们使用和消费,因此具有交易的价值,能满足市场的某种需求;

因此基于以上的产品的公理化定义以及定理化推导得出产品的第一性原理定义:

1
产品 = 属性 + 价值 + 交易

从以上公式中可以认为产品是以属性为要素,以价值为连接,以交易为目的,属性又可分为有形属性与无形属性,二者之间有时候并不是割裂的,价值是能满足人们的某些需求,是物品与货币之间的连接关系,交易是产品生产的目的。

然而这些都是教科书式的 定义,对产品的认知到这一层次已经可以超越绝大部分人,但它也只是停留在”产品“层次,而不是“作品”,更不是“艺术品”。

在我看来 产品 还是具有灵魂的,产品是由人创造的,其自然会带有人的思想、人的创造、人的理念在里头,宗师与学徒画同样的一幅画,虽然东西都一样但是那个味道往往是不一样的。因此,要理解一款产品还需要理解其背后的人的设计理念,在此,我给产品注入人的灵魂,即“理念”,从而进一步扩展产品的第一性原理:

1
产品 = 属性 + 价值 + 交易 + 理念

开源软件是信息的载体,其表现形式是具有无形的信息属性,是作为计算机程序的形式而存在的,要将开源软件产品化就需要将开源软件的属性价值化、可交易化以及注入人的设计理念。

3. 开源软件产品化

3.1 价值与交付

如何将一个软件产品化回答的是“How” 的问题,在此之前还应该搞明白“Why”的问题,一个软件产品或者其特性为什么需要做也有一套方法论,这里我称之为 “产品交付之双轮驱动模型”(如下图):

价值与交付

在这个双轮驱动思维模型里有以下几个原则:

  • 以客户价值为前轮,前轮把握方向,解决的是需求探索、价值确定、特性探讨以及价值精炼的过程。首先是以客户价值为导向输入客户需求、但是这个需求还需要去伪存真、去粗纯精、过滤提炼,才能作为产品交付轮的输入,而不是只要是客户需求,不管是真需求还是假需求、也不管是有价值的、还是无价值的都全部输出到产品交付轮,无效的消耗产品交付资源;
  • 以产品交付为后轮,后轮提供驱动力,解决的是开发、测试、运维以及获取客户反馈,再根据这个客户反馈的结果作为开发的输入的过程。在产品交付轮中很重要的一环是“反馈“,其角色是作为客户与交付之间的桥梁,开发需要依据”客户反馈”作为输入,而不是自个闭门造车;
  • 客户价值又可分为主动式客户价值与被动式客户价值,获取客户需求的方式也需要合理取舍:

    • 主动式客户价值:有些客户”久病成医“,非常清楚自个痛点、难点、挑战点在哪里,也非常清楚自个需要什么样的解决方案可以药到病除,从而可以精确的输出自我的需求。这种客户对产品交付来说可遇而不可得,成本最低,需求最精确;
    • 被动式客户价值:这种情况下,光是在那里等待,从而期望客户能给出明确的需求作为输入,那是缘木求鱼、刻舟求剑,效率也非常低下。如同医院里的医生给病人看病一样,绝大多数客户其实只能知道表征,而不知道根因,因此就需要由产品交付轮以客户专家的角色提出解决方案,作为客户价值需求输入给客户,再看客户的使用效果得出反馈,再依据这个反馈调整解决方案。
  • 在双轮驱动模型里,二者谁都离不开谁,不是厚此薄彼的关系,而是二者互相协作从而推动产品往商业成功这个目标前进的关系;

  • 先有买家需求再有产品交付,而不是先有产品交付再找买家需求,需要明晰这个先后关系,为客户找出差异化需求才是产品交付的本质,寻求差异化、避免同质化,才是真正的以客户为中心。

因此,在将一个技术产品化之前,先花几分钟时间问问其价值在哪里,为什么需要做这个,这一点很重要,要能区分客户要的是能马上就能解决痛点的止痛片还是可有可无的无关紧要的维生素,从而以此进行任务排序,明晰产品交付与客户价值的双轮驱动关系,要能清楚的理解“以客户为中心”的价值理念以及让产品的获得“商业成功”的终极目标。

3.2 技术产品化

通常来讲开源软件的产品化可以从价值、交易以及理念这三个方面进行。价值:可服务化、无形化有形、价值竞争,交易:可度量化、个性标准化,以及融入人的设计理念:复杂简单化等。

3.2.1 可服务化

可服务化指的是从技术实现上支持可服务化,ToB产品常常是半产品半服务的,而且一般会签约服务质量保证协议SLA,因此除了团队需要有替客户解决问题的能力外,还需要从技术与流程上支持可服务化,其中包括:

  • 可运维性:易用的部署(步骤量化)、升级(AB测试、in-place、replace、rolling-back等)、数据迁移、自动化运维支持等。在一个产品的全生命周期里,开发也许只占20%不到的时间,而将近80%的时间都需要运维,因此需要拿出近4倍比的开发重视程度,重视可运维的设计与实现;
  • 可观测性:可观测性主要分为四大类: 监控、告警、日志、追踪;
  • 可操作性:支持远程接入、开放服务接口、后台管理UI、CLI、特性参数配置开关;
  • 健康管理:健康检查支持、健康报告支持、自动提交故障问题单支持;
  • 安全性:安全性是企业级产品必备,数据保护、密码安全、连接检查、LIB库授权协议等;
  • 多租户:多租户可以支持多团队、多部门小规模部署,进行业务隔离,也是非常重要的企业级特性;
  • 可视化:提供易用的用户UI、CLI;
  • 可支持:如何指定进行客户支持规则?如何升级成工程师团队介入提供服务定位问题或者排除问题?

当看到以上类目,脑海里就能闪现出需要怎么去实现这些以及用什么组件可以最佳实践的快速完成交付,而不是停留在概念的阶段,那才算对可服务化有了自己的理解。

3.2.2 无形化有形

无形化有形指的是将无形的软件硬件化或者云化,单单一个软件包是难以让用户买单的,需要把它硬件化,打包到服务器里以有形产品的形态销售出去,或者云化后以服务的无形形态销售出去。

3.2.3 价值竞争

价值竞争指的是“参与到客户的购买周期中,在每个阶段为客户创造价值”[3],从单纯的销售产品到提供整套生态化的解决方案。单纯的依靠销售产品往往已经难以给客户提供差异化的价值,并且也会面临低利润的同质化竞争,那么这个时候就需要更进一步的提供生态化的解决方案,针对行业需求做端到端的全生态化的解决方案。

生态化的解决方案化能给客户提供差异化的价值关系。比如,一份药品在药店里只能卖30块,而且只是一次销售无法挖掘后续价值。但是到了医院就不一样了,其依据客户的”恐惧“为刚需的基石,提供一整套的类生态化的医疗解决方案,从挂号预约、望闻问切、到各种仪器设备过一遍、再到开出药方、再依据客户的反应效果把这个过程再来几遍,因此在药店里30块钱的药,在医院里就能卖到 300块、3000块,获取十倍、百倍、千倍利润。当然这从道德上讲这是比较无耻的一种行为。

3.2.4 可度量化

可度量化指的是质量要可以量化,可预测的业务指标(比如AI训练里的精度、加速比、收敛时间、训练次数等)、性能、可靠性、可用性、可伸缩性、稳定性、容错性、可测试性等,这些很抽象的指标要能量化。在产品功能同质化的场景下,质量是最重要的差异化竞争力。

业务性能、可靠性、可用性、可伸缩性这几者之间页互相制约,质量与成本、时间也互相制约,同时在云化的场景下客户又有SLA要求,不满足SLA要求的服务,除了要赔钱,还严重影响商业信誉,因此质量指标之间也需要合理取舍。

3.2.5 个性标准化

个性标准化指的是将个性化的、“DIY”化的开源项目转成标准化的、可复制的、可量化的,同时依据资源的规格约束进行标准化,比如依据服务器规格、虚机规格,机架规格等进行标准化,例如AI服务器的配置就需要定义CPU、内存、磁盘、带宽以及训练卡的标准的规格,这样才能提供可预测的性能、可预测的加速比等质量指标,再比如云端场景下的服务监控,除了定义指标的名称之外,还需要定义监控指标的类型、故障码、输出的标记以及对应的处理措施等,所有的这些都要能标准化、可操作性化。

3.2.6 复杂简单化

复杂简单化指的是把复杂的体验简单化, 抽象及简化API、量化的安装步骤、高内聚低耦合的设计、易用的UI等,这里又涉及到产品设计哲学、人类的心理学等,也跟人的设计理念相关。

4. 小结

本文以方法论的形式解读了软件开发过程当中经常会遇到的两个问题:”什么是产品?如何将一个开源的软件产品化?“,从而解答了 “如何弥补开源项目与企业级商业产品之间的差距?”的问题,讲的是“无用”的知识。然而理论与实践是相互作用的,宏观角度知道方法论之后还需要从微观上进行实践,不然就如同知道很多道理却过不好这一生,知道很多原则却写不好代码一样一样的。

日拱一卒,功不唐捐,分享是最好的学习,与其跟随不如创新,希望这个知识点对大家有用,另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

5. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

6. 参考资料

[1] https://a16z.com/2019/10/04/commercializing-open-source/

[2] https://baike.baidu.com/item/%E4%BA%A7%E5%93%81/105875

[3] 《价值竞争:以客户为中心的销售转型》

7. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

1. 先有客户再有技术

技术不同于科学,科学是人类对自然的认知,它可以很前沿很理论也不用讲究工程价值,而技术更多指的是功能与工程得实现,更需要关注的是“利他”的常识。技术人员其比较关注的是技术架构、实现方式、技术价值以及开发成本,而比较容易忽略客户需求、使用场景以及产品价值与用户体验。忽略这些产品相关的内容而维技术论就容易犯错进而浪费有限的开发资源,在工程实现上维技术论常见的有四错:

  • 第一错:“我为用户想”,这是研发人员最容易犯的错,其已经有用户意识,但是却没有进一步与用户沟通,直接替用户做决定,也不清楚用户的使用场景,因此容易造成”所想“实际上并不是用户真正所想;
  • 第二错:追求有挑战的技术而非技术的实用价值,也非从合适的解决用户问题的角度出发,将技术上的自嗨当成客户需求,比如用户需要从A地到B地,简单一点给用户一辆自行车就可以解决的问题,而技术自嗨就容易非要先自行造个飞机,然后拼命的给用户推销这个好这个快,但是用户却不买单;
  • 第三错:维性价比论,总以为又便宜的又好的就是真的好,性价比是大杀器,但是很多情况下其实客户也讲ROI(投入产出比),比如双11秒杀活动,用户可以不计成本的采用最新进最前沿的技术,只要能扛得住双11的流量就可以不计成本,因为再大的成本,跟双11带来的收益对比都是毛毛雨;
  • 第四错:闭门造车,不实事求是,不与客户做探讨,不做调查就把想象的或还处于概念上的东西当成客户需求。

因此,研发人员不能维技术论,维技术论就不是一个合格的研发工程师,工程师还需要关注客户价值,在实现一个架构之前先确定这个是对客户有价值的,同时平衡好客户价值与技术前沿之间的取舍关系。

2. 什么是客户,又什么是客户价值

2.1 什么是客户

用英文单词表示,客户与用户其实是比较容易区别的,客户是 customers, 用户 是users,而中文二者都有个“户”字就比较容易混淆。To C产品客户可以是用户,但是To B产品, 客户却不是就等于就是用户。狭义的客户 = 买单的,广义上的客户 = 客户的客户 + 客户 + 客户的用户 + 利益链上的所有,用户也不就是一个角色或者某人,对to B产品来说,用户的本质是“需求“的集合。

2.2 什么是客户价值

“任何先进的技术、产品和解决方案,只有转化为客户的商业成功才能产生价值“ [1] ,客户价值就是对客户有用的东西,价值来源于价值的交换。技术的目的就是做对客户有用的东西,并且技术的进化方向是由市场所决定的。

以客户为中心,就是给客户创造价值,替解决用户难点、痛点、挑战点、为客户提供高质量低成本的产品,同时响应要及时。病根是需,药是求,拿出 “求” 解决 “需”,药到病除就是为客户创造价值[1]。

3. 如何做到以客户价值为中心?

认知上做到技术要先从客户价值开始,那么执行上应该如何拆分?使得认知具有可量化的执行性?这里从以下三个方面对“如何做到以客户价值为中心”这个问题进行拆解:

  • 价值探索 - 价值与交付双轮驱动思维模型,PMF-MVP思维模型
  • 价值确定 - 三三制需求分析思维模型
  • 价值输出 - 卡诺需求分级与分类思维模型

3.1 价值探索1 - 双轮驱动思维模型

双轮驱动思维模型

价值探索的方法论之一是双轮驱动思维模型,其原则为:

  • 以客户价值为前轮,前轮把握方向,解决的是需求探索、价值确定、特性探讨以及价值精炼的过程,需求输出需要去伪存真、去粗纯精、过滤提炼;
  • 产品交付为后轮,后轮提供驱动力,解决的是开发、测试、运维以及获取客户反馈;
  • 先有客户价值再有产品交付,客户价值又可分为主动式客户价值与被动式客户价值,获取客户需求的方式也需要合理取舍;
  • 在双轮驱动模型里,二者谁都离不开谁,不是厚此薄彼的关系,而是二者互相协作从而推动产品往商业成功这个目标前进的关系;

3.2 价值探索2 - PMF-MVP 开发模型

PMF-MVP

如上图所示,PMF(Product-Market Fit)是讲究产品与市场匹配,是产品需要与市场需求相匹配,而MVP (Minimal Viable Product)是 最小可用产品,MVP讲的是每个版本的迭代都是一个可用的产品而非功能的堆砌,PMF-MVP开发法,讲究快速给的输出可用的版本给到客户,再由客户进行使用获取客户的信息反馈,再进行版本迭代。

价值探索的方法论之二是PMF-MVP开发法,其原则为:

  • PMF-MVP 开发法可以帮助团队在早期快速确认客户的真实需求;从特性列表中确定产品(特性)的基本功能, 然后迅速开发MVP,再投放市场提前踩坑,收集用户反馈,然后再进行产品迭代,只有用户用起来,产品才有机会演化;
  • 做MVP的时候,不是验证产品好不好用,而是验证产品/特性是不是用户真的想要的,减少开发成本,“闭门造车”式的开发经常会遇到“再来一次”;
  • 跟目标用户产生互动和连接,每一步都收集用户的反馈,前期跟客户多交流,多沟通,“一元共创”与用户一起成长。

在价值探索之后就需要进行价值确定。

3.3 价值确定 – 三三制需求分析思维模型

公式: 需求 = 需(痛点、难点、挑战点、恐惧点) + 求 (产品、服务或解决方案), 需即痛点、难点、挑战点,求即解决方案、产品或服务,求到需即完成,这就是有客户价值。依据三三制需求分析思维模型我们可以进行价值确定,三三制需求分析思维模型是一个价值确定思维模型,其如下表:

类别 功能 质量 约束
“大”客户 业务目标: 商业成功,比如科技向善 业务质量: 多、快、好、省 业务约束: 时间、质量、成本,法律法规,信息安全,技术趋势,竞争对手,行业标准等
“大”用户 业务需求 运行时质量: 性能、可用性、可靠性,可伸缩性、可观测性、可运维性、易用性、兼容性、安全性等 使用时约束: 遗留系统,业务环境,用户能力,用户群特征等
“大”团队 功能需求: 基本功能P0 、增值功能P1、潜在功能P2 、可有可无功能P3 、有害无益功能P100 编程时质量: 可扩展,可读性,可测试性,可维护性,可移植性 编程时约束: 开发进度,资源预算、上级要求、开发团队能力、产品规划、运行环境

三三制需求分析思维模型进行价值确定之后即价值输出。

3.4 价值输出 – 卡诺需求分类与分级思维模型

KANO

这里采用KANO需求分类与分解思维模型进行价值输出,依据kano模型,需求可以分为:

  • 基本需求:必须有的最根本的需求,没这个根本就没法谈,会阻塞产品交付;
  • 增值需求:当提供此需求时用户满意度会提升;当不提供此需求时用户满意度会降低;
  • 竞争力需求:若不提供此需求,用户满意度不会降低;若提供此需求,用户满意度会有所的提升,属于亮点要素;
  • 可有可无需求:用户根本不在意的需求,对用户体验毫无影响;
  • 有害无益需求:提供后用户满意度反而下降;

卡诺模型将需求进行了分级与分类,进一步的区分了需求的价值。

4. 小结

本文首先确定了 “先有客户再有技术”的认知,再讲述了什么是客户,什么是客户价值,并且以思维模型的方式讲述了如何做到以客户价值为中心。日拱一卒,功不唐捐,分享是最好的学习,与其跟随不如创新,希望这个思维模型对大家有用。另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

5. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

6. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

7. 参考资料

[1] 《华为增长法》

产品开发的本质

根据第一性原理思维,可以得出产品开发的本质即:“高效、高质量地交付有用的价值”[1]。那么从这句话可以推导出四个需要解决的命题,即:

1
2
3
4
1,需要交付的价值是什么?
2,如何判断什么是有用的价值?
3,如何高效地交付?
4,如何高质量地交付?

此外,在软件产品开发过程中除了面临确定性复杂度之外还经常面临不确定性复杂度,不确定性的复杂度比确定性的复杂度更难解决,更容易引起焦虑,更容易带来团队熵增,也更容易造成软件开发交付的失败。因此,为了简单有效地解决这四个命题以及其所自带的复杂度问题,结合精益产品理论,本文提出一种从实战中总结出来的“极简产品开发法”。需要额外说明的是,本方法论还有两个约束条件:

  • 本方法论仅适用于以搞生产力为主而非以搞生产关系为主的企业、部门、团队或个人;

  • 本方法论仅适用于小团队或单兵作战能力很强的个体,比如10倍工程师;

极简精益产品开发法

为了简单有效地解决“需要交付的价值是什么?如何判断什么是有用的价值?如何高效地交付?如何高质量地交付?” 这四大命题以及软件开发所面临的确定与不确定复杂度,这里采用结构化的方法提出的极简产品开发思维模型,其涵盖五大原则与三大基石,即:

  • 五大原则:以终为始,架构先行,有拆有合,迭代更新,相关满意
  • 三大基石:领域能力,企业文化,组织到位

本极简产品开发法思维模型导图如下:

在极简产品开发法思维模型里,“领域能力、企业文化、组织到位”属于基石的范畴,三大基石不到位,则产品开发与交付的原则与行动无效。在五大原则里,“以终为始”是为了解决“判断需要交付的价值是什么?如何判断什么是有用的价值?”这两个问题,“架构先行,有拆有合,迭代更新,相关满意”是为了解决如何高效地交付,如何高质量地交付以及如何解决软件开发的确定性与不确定性复杂度。

五大原则

以终为始

“以终为始”是一种逆向思维,在软件开发里的应用指的是从最终的交付价值出发,反向推理交付过程,寻找软件开发的关键要素,获取反馈采取正确的策略,从而达成有用的价值交付。如下图所示,从未来的终局看现在,使用获取的未来信息强化现在的行为,赋予现在的行为以塑造未来的力量。

“以终为始”是确保正确地做事以及做的是正确的事的一种思维方式,在进行软件开发之前就进行了从交付结果开始的倒推分析,从交付结果得出开发的方向与方案。这里以“逆向工作法”以及“客户导向法” 为例说明软件开发过程中 “以终为始”思维的使用。

逆向工作法

逆向工作法是亚马逊所推崇的商业新哲学,因为产品最终的交付要“以客户为中心”,那就先从客户侧开始倒推开发,逆向工作法有助于一开始就把重心放在客户所真正关心的问题上,而不是一堆程序员坐在办公室内拍脑袋替客户做假想,进而避免一些无效的开发决策,使得确保推出的是有用、有价值、用户体验佳的产品。

拆解这个概念为具体的行动,亚马逊讲述了这个思维方式的应用步骤[4]:

1,先写一篇内部用的产品新闻稿,简单描述一下这个产品的特点与好处是什么,是为了解决什么痛点而产生,然后描述具体的问题,拿出一个新的解决方案,虚构一个用户的心声,设身处地为用户着想,然后发出来给内部同事,经过审核的也可以外发给公众;

2,写一个常见的FAQ问题文档,定义产品的用途以及考虑用户使用时会遇到的问题以及回答如何解决,FAQ需要包含外部客户会问的问题以及内部用户会问的问题;

3,定义客户体验,详细描述客户使用产品时会遇到的使用场景。比如用户界面是怎么样的,软件部署是怎么部署的,软件的技术架构图是怎么样的,先给客户一个能够呈现端到端体验的假象视图;

4,编写用户手册,用户手册是客户用来真正了解产品是什么以及如何使用它的,用户手册通常有三个部分:概念、操作方法和参考,它们之间告诉用户使用产品所需的所有知识。,

5,获取反馈,以上内容完成后,获取用户/客户反馈,然后在产品的生命周期中,不断迭代而演化产品的开发交付文档。

逆向工作法的目的是为了明白真正的用户/客户是谁,用户/客户的真实需求是什么,用户/客户的需要最先解决什么痛点等,而且以上步骤也只是一种应用方案,目的一致则无需拘泥于形式,只要思路和效果可以达到有效理解客户的目的即可。

客户导向法

客户导向法讲的是“先有客户再有产品与技术”,其理念上与逆向工作法类似,不同之处在于 逆向工作法是具体的行动,而客户导向法是认知上的提升。在这里,需要先定义什么是客户以及什么是客户价值:

  • 什么是客户?狭义的客户 = 买单的,广义上的客户 = 客户的客户 + 客户 + 客户的用户 + 所有相关方;
  • 什么是客户价值?客户价值就是对客户有用的东西,价值来源于价值的交换。技术的目的就是做对客户有用的东西,并且技术的进化方向是由市场所决定的。以客户为中心,就是给客户创造价值,替解决用户难点、痛点、挑战点、为客户提供高质量低成本的产品,同时响应要及时;

在产品开发上,软件开发人员常见的认知错误有:

  • “我为用户想”,这是研发人员最容易犯的错,其已经有用户意识,但是却没有进一步与用户沟通,直接替用户做决定,也不清楚用户的使用场景,因此容易造成”所想“实际上并不是用户真正所想;
  • 追求有挑战的技术而非技术的实用价值,也非从合适的解决用户问题的角度出发,将技术上的自嗨当成客户需求,比如用户需要从A地到B地,简单一点给用户一辆自行车就可以解决的问题,而技术自嗨就容易非要先自行造个飞机,然后拼命的给用户推销这个好这个快,但是用户却不买单;
  • 闭门造车,不实事求是,不与客户做探讨,不做调查就把想象的或还处于概念上的东西当成客户需求,带来的是低效、低质量的产品开发过程;

因此,开发产品需要先关注客户价值,在实现一个产品之前先确定这个是对客户有价值的,与客户/用户多沟通、一起共创,在“客户要的与我能提供的”二者之间保持理解一致,避免无效开发与交付。

架构先行

架构投影

柏拉图在《理想国》中构建了他的哲学王国—理念世界,其把世界分成两个:“现象世界与理念世界,柏拉图认为这两个世界的关系是原本和慕本的关系,理念世界是原本、模型,现象世界是理念世界的影子或慕本”。基于此设想,产品架构可以是产品在现象世界的原本,通过产品架构可以看到产品的最终形态。在开发(编码)产品之前可以先定义软件产品的架构,给出产品的画像,提供产品的总体概要架构设计文档(注意这里概要设计文档即可,无需详细设计文档),设计文档内定义产品的设计哲学、设计原则、技术架构图、设计提案、所需要实现的功能特性、交付目标以及风险管理、用户操作等,然后发给团队一起评审,利用团队的力量避免交付的技术路线风险,同时为下一阶段的工作分解做准备。

架构思维

狭义上的架构通常指的是架构的技能,其属于“术”的范畴,而广义的架构则是客户需求、市场趋势、架构理念、架构方法论、架构技能、架构用的工具以及架构的边界这几个方面的组合体,应用抽象思维,即“势、道、法、术、器、界”这六个字 ,简称架构思维六元组,具体可以参考《第15式 - 架构思维》。

势:时势

“势”是架构的方向。从宏观处着眼,“势”是产品架构设计的市场趋势、是客户需求趋势也是技术的应用趋势;从微观处着手,“势”是功能设计的价值与目的。架构设计需要从宏观处着眼微观处着手,看清客户的需求趋势、市场趋势以及技术趋势,功能设计需要分析清楚当前功能的价值与目的。

道:本质

“道”是架构的认知,是架构师的设计理念、设计意图,是产品架构的灵魂,这里我把它定义为产品架构的设计哲学。

法:方法论

”法“是方法论,是架构设计的方法论,是架构设计的套路,这里我把它定义为产品架构的设计原则

术:技能

术,技能,是架构技能,这里定义为设计提案,以及各种功能与特性实现的思路

器:工具

”器“是工具,是架构设计用的工具,”工欲善其事必先利其器“,

界:边界

”界“是边界,是架构的约束限制,是技术边界、也是技术约束与技术限制,也是架构的取舍因素之一,是架构能做什麽不能做什麽的解读,对市场来说它是技术壁垒,对产品来说它是法律法规、是功能约束,对团队来说它是资源约束、是自我能力约束。

有拆有合

有拆有合指的是工作分解结构法,基于“架构先行”这一步输出的概要设计进行工作分解,工作分解的结果可以直接影响了产品开发的效率与质量。

工作分解是个有拆有合的过程,一个大的工程任务往往是由很多的小个的任务组成的,如何将一个大任务拆解成合适的小任务,能将大任务拆解成什么样的小任务,能拆解到什么粒度,拆解是否准确,这是”拆“的过程。怎样对任务进行量化与质化,怎么将任务落地到具体的执行人员上,怎么进集成怎么验收,这是“合”。以下图的工作包分解表为例:

项目

1,首先前三行定义了项目的目标、原则以及投入,说明了项目的交付目标、交付进度、交付的原则以及约束、还有确定了人力资源的投入;

2,任务分解成了一级任务、二级任务以及工作包、工作包名称,关键特性可以是具体需要实现的功能,也包括项目文档、测试部署、相关采购等;

3,除这些在任务树上也可以体现的内容外,还增加了 工作进展、状态、评论、风险、阶段目标、执行的人员、复杂度以及依赖条件;

4,输出最终交付成果。

工作包分解表可以使得团队协作更加顺畅,将不确定的大任务包分解成一个个确定的最小可执行工作包,是的开发工作从不确定到确定,有利于保证软件产品开发的效率与质量。

迭代更新

产品根据环境改变而迭代,根据反馈结果而更新。迭代更新其目的为了逐步逼近所需的最终目标,而每一次迭代更新得到的结果都会作为下一次迭代更新的初始输入。在不确定性较大的软件产品开发过程中,将产品开发分为迭代0、 迭代1、迭代2…..最终迭代目标这几个阶段,每个阶段的输出都是一个最小可行产品,即 MVP(Minimum Viable Product)。

如下图“10人以内小团队你极简精益产品开发法”所示:

1,迭代0,先完成信息输入,依据“以终为始、架构先行、有拆有合”的步骤完成客户目标确认、价值确定、需求分析、初版概要设计、初版工作拆解;

2,迭代1,进行软件开发,输出MVP1,依据“以终为始、架构先行、有拆有合”的步骤刷新客户目标、交付价值、客户需求、概要设计、进行二次工作拆解;

3,迭代2,进行软件开发,输出MVP2,依据“以终为始、架构先行、有拆有合”的步骤刷新客户目标、交付价值、客户需求、概要设计、进行三次工作拆解;

以此类推,逐步迭代更新,过程根据变化微调控保证方向正确,直至抵达最终交付目标。

相关满意

相关满意指的是项目相关方满意,项目相关方是会影响项目或受项目所影响的组织、团队或人员。项目相关方的参与是项目成功的前提与保证,没有项目相关方,也就没有项目,忽略任何项目相关方都可能导致项目的失败。项目的开启、过程以及结果都需要能令项目相关方满意。

达成项目相关方满意需要从以下4个方面进行迭代推进以支持项目团队的工作:

1,识别相关方,相关方一般包括需要知晓情况的用户、客户、供应商、合作第三方,需要通知到的项目批准人、项目负责人,负责具体执行的项目开发团队:项目经理、产品经理、架构师、领域专家、各级工程师、测试、采购,以及其他的组织内外的项目支持职能部门;

2,管理预期,准确识别相关方的需求和期望;

3,提出方案,依据”以终为始、架构先行、有拆有合、迭代更新“法输出满足相关方需求和期望的提案;

4,迭代更新确保事态向最终目标的方向逐步推进;

项目相关方满意的核心就是在所有的相关方的预期中取得一个彼此都接受的解。

三大基石

领域能力

领域能力狭义上指的是个人或团队所具备的相应专业能力,广义上指完成整个软件开发交付所需要的技能,包括产品思维能力、项目管理能力、架构设计能力、编码能力、测试能力、维护能力以及质量保证能力。领域能力是软件开发原则与行动的最重要的基石之一。没有对应的交付能力就不要谈什么产品开发原则与交付,比如一个拧螺丝的团队你非要他们在限定的时间内打造一根火箭,必然无法达成。

企业文化

企业文化是极简产品开发法的基石之一,其涵盖了使命,目标,制度,边界,奖罚等,属于软件开发团队运作、开发原则与产品交付的最底层的基础设施。企业的使命讲的是企业与世界的关系,这跟企业员工离的较远,姑且不谈。而目标讲的是员工与企业的关系,每年制定的企业发展目标属于企业的战略范畴,体现了企业的战略方向以及资源投入的方向,团队目标与企业目标保持一致,个人目标与团队目标保持一致,这是最基本的团队运作准则,如果个人或团队年度目标不与企业目标对齐,那么个人或团队也拿不到资源得不到发展。而企业制度、边界与奖罚是团队运作的保障,奖什么罚什么更是最明显的企业文化导向,这里就不作举例说明了。

组织到位

组织到位的第一个意思是:”组织结构影响产品结构“,组织基因即产品基因,依据康威第一定律:

1
Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations. - Melvin Conway(1967)

翻译成中文即:”组织设计的产品/设计等价于这个组织的沟通结构“,通俗的来讲:产品结构必然是其组织内成员沟通结构的缩影,比如微服务。

组织到位的第二个意思是:人员到位,人事匹配。进行软件产品开发一方面需要配备相应的能力需求的人员,另一方面也需要讲究合适的人放在合适的岗位上,合适的岗位需要合适的人选,人选对了,事就成一半。

自组织、自平衡与强管控

软件产品的开发过程除了是一个业务管理过程也是一个团队/个人管理过程,“极简精益产品开发法”更多讲的是业务管理的过程,然而团队/个人管理的成功与否也可以决定产品开发的成败。软件开发过程是一个复杂的系统过程,而业务与团队也是一个复杂系统,需要以系统化的思维而非线性思维来看待。团队能否有效的自我组织、自我驱动直接影响软件开发的效率与质量。

基于此,这里提出团队/个人的三个组织形态:自组织、自平衡与强管控,如下面的组织形态变化图所示,组织的形态变化有自组织、自平衡、强管控这三个形态,自组织态会过度到自平衡态,如果没有外力的干预作用,自组织态与自平衡态都容易滚落到强管控态,强管控态势能最低也是最稳定的最终形态。

在一定的企业文化以及组织架构下,每一个管理决策和管理措施的输出背后,都有一种人性假设,道斯·麦格里格(Douglas McGregor)的X-Y理论(Theory X-Theory Y)概括了对人性的根本性理解:X理论-人性本恶,Y理论-人性本善。中国古代也有儒家人性论之争,最具有代表的就是孟子的“人性本善论”和荀子的“人性本恶论”。

人性本恶论认为员工需要被强力控制与安排,员工都讨厌工作、工作的驱动力只是为了保住饭碗、对于工作能躲就躲,因此有了强KPI管理法,271、361、末位淘汰、设定严格的规则制度等,如上图所示,其“具有低势能稳定性的形态,但不会带来创新和竞争力”[1];

人性本善论认为员工是能自我驱动的,愿意自我承担责任、积极向上、会自我以目标为驱动努力工作,因此有了OKR管理法、工作-生活平衡、对员工授权、人性激发、信任管理法等,如上图所示,其具有“高势能非稳定的状态,但确是激发创造力、提升效能的利器”[1];

软件开发是一个创造性的脑力劳动,其并不适合以人性本恶论为出发点强管控管理法,但是高效率、高创造性的自组织形态却具有不稳定性的特征,因此需要微管控使之一直处于自平衡态,既保持自组织的高效能、高创造力的特性,又规避了强管控管理法带来的无创新、无竞争力、低效率的弊端。以上三种形态在一个大的组织结构内可能同时存在。

本文将方法论局限在“10人以内小团队” 也是为了更容易达到团队的自组织或自平衡态,使之保持团队的勇于担当、自管理、高效率、高质量输出、高创造力形态。

小结

本文提出了一种 “小团队极简产品开发法”,用以解决软件开发的复杂度问题以及需要解决的四个命题,即:需要交付的价值是什么?如何判断什么是有用的价值?如何高效地交付?如何高质量地交付?详解了“以终为始,架构先行,有拆有合,迭代更新,相关满意”这五大原则以及“领域能力,企业文化,组织到位”这三大基石,此外还论述了“自组织、自平衡、强管控”这三种团队组织形态。其目的都是为了使得团队/个人目标与组织目标保持一致并且“高效、高质量地交付有用的价值”。此外,作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

参考资料

[1] 《精益产品开发:原则、方法与实施》 何勉著

[2] https://zhuanlan.zhihu.com/p/56556328

[3] https://www.cnblogs.com/yanglang/p/10270592.html

[4] https://www.allthingsdistributed.com/2006/11/working_backwards.html

[5] https://www.sohu.com/a/299920333_263553

1. 前言

在一个软件工程项目组里有四种角色特别重要,即:架构师、领域专家、产品经理以及项目经理,在一个比较大的项目里或者大公司大部门里,这四类角色一般分别对应四个人,然而在中小型项目里,特别是创业型公司或大公司里的小部门,这四类角色可能是四者合一的,即从团队当中选定一位有能力担当这四个角色的成员。如果这个成员原来就是架构师,那么对这位架构师的要求就是除了专业技能之外还应该具有项目管理能力。

根据定义项目是“为提供某项独特产品或服务所做的临时性努力”,其本身的特点是“变化”,因此,项目管理对架构师本身来说也是具有很大的挑战性的一项管理工作。项目管理具有入门容易、精通难的特性,大多数项目管理给工程师的感觉就是定计划、看进度、催活、做汇报,实际上这是没有领悟项目管理的精髓。

PMBOK定义项目管理为:“项目的管理者,在有限的资源约束下,运用系统的观点、方法和理论,对项目涉及的全部工作进行有效地管理。即从项目开始到项目结束的全过程进行启动、计划、执行、监控和验收,以实现项目的目标。”,即项目管理有其自身的“观点、方法与理论”,而在项目的落地过程中,所有节点的计划、执行、监控、风险管理以及验收等都依赖于工作分解结构(WBS: Work Breakdown Structure ),不同的行业对项目管理有不同的需求,进而有不同的工作分解结构方法,本文讲述的是与软件工程紧密相关的工作分解结构法。

2. 项目管理方法论

依据PMBOK理论定义以及软件工程实践,软件工程项目管理可以分为两大部分:一是5大流程,二是12大知识领域 ,如下:

2.1 项目管理五过程

项目管理五大过程包括项目的启动、计划、执行、监视和验收,如下图所示:

项目5过程

  • 启动阶段,首先需要确定项目的目标和项目的关键负责人、进行业务分析、需求分析以及组建团队,并且宣布项目正式立项;

  • 计划阶段,编写项目计划,把项目目标量化与质化,制定达到目标的里程碑,在这个阶段,还需要完成的是概要设计、目标分解、任务分派、风险评估等工作内容;

  • 执行阶段,按计划开展项目,进行详细设计、编写代码、调试自测,阶段性的实现目标,这一步是软件工程最核心的一个步骤;
  • 监控阶段,监控阶段与执行阶段是循环的关系,这一阶段需要准确识别偏差,判断影响项目进度因素,同时进行计划刷新与风险刷新以及任务刷新;
  • 验收阶段,按照项目要求,进行项目验收,包括版本发布、文档归档以及项目复盘。

不同于理论,在实践中,这5大过程是个计划、执行、检查、更新的循环过程,而不是一个线性过程。

2.2 项目管理12项

项目管理1.0版里涉及 范围、时间、成本以及质量,这四者是个平衡的过程。项目管理2.0里,又增加了 业务与组织,项目管理是为业务服务的,同时给组织保证结果。而在实践过程中容易发现软件工程项目管理其实涉及12大领域,即:业务、范围、进度、成本、质量、资源、风险、采购、相关方、沟通、测试以及综合管理,具体如下:

项目12项

  • 业务管理,其涉及业务分析、客户管理;
  • 范围管理,包括规划范围、需求分析、定义范围、工作分解、确认范围以及控制范围;
  • 进度管理,其包括:规划进度里程碑,定义任务,排列任务优先级,估算人力资源,估算所需时间,制定进度计划表以及控制进度;
  • 成本管理,包括规划成本管理,估算成本,制定预算以及控制成本;
  • 质量管理,包括规划质量指标,QA测试,质量保证以及控制质量;
  • 资源管理,这一部分与组织结构相关,是决定项目成败的关键要素,合适的项目需要合适的人选,其包括4个子过程:人力资源管理,组建团队,建设团队以及管理团队;
  • 沟通管理,包括3个子过程:规划沟通,管理沟通,控制沟通;
  • 风险管理,包括识别风险,风险分析,定量风险,提出应对以及控制风险;
  • 采购管理,包括4个子过程:规划采购,实施采购,控制采购,结束采购;
  • 相关方管理,相关方管理也是项目成败与否的一个非常关键的要素,包括4个过程:识别相关方,相关方参与,相关方满意度等;
  • 测试管理,项目管理往往容易忽略掉QA测试的作用,在代码编写好后需要提前安排QA介入,记住一点没有经过QA严格质量测试的软件包是不能输出给客户的;
  • 综合管理,综合管理的关键是综合平衡最优,平衡以上11项使之达到最优,包括制订章程,制定计划,指导与管理执行,监控项目,变更控制,结束项目。

不管是项目管理5大流程还是项目管理12项,其中有一个非常重要的工作即创建“工作分解结构”,工作分解结构是开展一切项目管理的依据与基础,可以说没有“工作分解结构”就没有项目管理。

2.3 工作分解结构

在工作过程中,人的认知是有差异的,比较资深的人员描述一个任务或问题时会比较的抽象,而初级工程师比较能理解的是具体的任务描述,为了团队具有较好的执行力,就需要把抽象的概念或描述分解成具体的可执行的行为或任务,这就需要一种合适的工具或方法来分解概念与工作。

工作分解结构法(WBS: Work Breakdown Structure,是一个“描述思路的规划和设计的工具”,是以项目结果为导向的工作过程的结构分解方法论,是将抽象的概念或任务分解成具体的行为的一种工具。将工作进行合理的分解是项目负责人的重要能力之一,缺乏项目分解能力的项目负责人容易造成项目失败,“工作分解”的好坏与否 也可以决定项目的成败与否。

项目

如上图所示,项目管理有两大基石:工作分解结构法与 企业文化+组织结构, WBS在PMBOK中给出的定义是:“WBS是针对可交付成果对项目要素进行的分组,它归纳和定义了项目的整个工作范围,每下降一层就代表对项目工作更详细地定义。”。这一定义说明WBS所分解的目标是工作包(Work Package),以可交付成果为导向的。企业文化与组织结构也是项目成功与否的基石,企业文化作保证,组织调整到位可以给项目提供坚强的基础资源与能力。

“工作分解结构法”的任务拆解是个有拆有合的过程。一个大的工程任务往往是由很多的小个的任务组成的,如何将一个大任务拆解成合适的小任务,能将大任务拆解成什么样的小任务,能拆解到什么粒度,拆解是否准确,这是”拆“的过程。怎样对任务进行量化与质化,怎么将任务落地到具体的执行人员上,怎么进集成怎么验收,这是“合”。任务拆解比较的考验工程人员的工程能力,任务拆解是否成功是工程进度与工程交付能否成功的关键要素。

3. 如何进行工作结构分解

3.1 任务树分解法

如下图所示,工作分解结构就是把项目可交付成果,比如总目标一级级的分解成较小的、更易于执行的组成部分的过程,建立工作分解结构的过程就是将项目进行显性化、结构化,将复杂的总目标分解成一级任务、二级任务,最后分解成最小可执行工作包的过程。

项目

工作分解结构可以按功能、组成、生命周期以及组织的形式进行分析,在软件工程项目中,通常以项目生命周期 + 功能以任务树的方式分解项目。如下图所示,

最终交付成果按生命周期分解成了 项目管理、业务、需求、设计与编码、集成以及交付这6项。然后设计与编码又按功能的形式分为一级任务特性:关键特性1、关键特性2、关键特性N,以此类推,直至分解成最小可执行工作包。

项目

工作分解结构法是面向结果为导向的分解,分解过程中也需要适可而止,比如初级工程师需要给他分解到很具体的最小可执行工作包这种层次,而比较资深的工程师可以给他分解到关键特性这一层次即可,当然前提是这个资深工程师有能力承担这一特性的分解与执行。

此外,任务树适合项目汇报使用,而工作包表格适合团队内部协作使用,其能提供更详细的细节,因此在任务树拆解后,下一步是进行工作表格分解。

3.2 工作表格分解法

对比于任务树,工作包表格可以在右侧增加更多的细节,这有利于团队协作,以下图的软件项目工作包表格为例:

项目

1,首先前三行定义了项目的目标、原则以及投入,说明了项目的交付目标、交付的原则以及约束、还有确定了人力资源的投入,;

2,任务分解成了一级任务、二级任务以及工作包、工作包名称;

3,除这些在任务树上也可以体现的内容外,还增加了 工作进展、状态、评论、风险、阶段目标、执行的人员、复杂度以及依赖条件;

4,输出最终交付成果。

工作包表格的这些细节可以使得团队协作更加顺畅,所以一般开发过程中选用工作包分解表作为项目跟进的任务进度表。

3.3 关键路径网络图分解法

除了任务树与工作包表格之外还有关键路径网络图分解法,在项目当中有些任务比较重要而复杂,有些任务相互独立、有些任务又有依赖关系,

如下图所示,S 表示Start,F表示Finish,SS 表示同时启动,FS表示先完成再启动。F11任务需要在F1任务启动后10天再启动,F23与F31任务可以同时并发进行,

而最终交付的目标需要 F2211 与 F3111 同时完成。

项目

关键路径网络图分解法明确了任务之间逻辑关系、先后关系、时间关系,有利于项目计划进度时间的评估与规划。

4. 工作分解结构法的理念与原则

以上内容讲的都是 工作分解结构法的 “术”的层次,其本身还有背后的理念 ,即“道”。工作分解结构法是“系统思维与分治思维”在软件工程项目中的应用。工作分解除了非常重要的专业技能,还需要遵循以下几个理念与原则:

1,滚动原则

如下图所示,项目的推进是一个 “分解、执行、检查、更新”滚动推进的过程,依据导弹思维,先保证大方向正确,开工,然后再在过程中调整小方向,直至最终精确的命中目标。项目管理也是一个逐步实现目标的过程,时间上近的获取的信息多、那么分解的层次与类目自然也就更细、更多、更准确,而时间上远的,因为信息不够完善,分解的层次与类目自然更少少,也没那么精确,在目标逐步达成后,可以进行刷新重新进行分解,完善工作包,直至最终达成目标。

项目

2,MECE原则

MECE即“相互独立,完全穷尽”,是应用系统思维从全局的角度分解任务,既不重复也不遗漏,纵向递进,横向遍历。

3,量化质化原则

分解出来的工作包需要能量化,需要可量化的完成时间、可量化的验收标准,不能量化的任务需要质化,即以满意度的方式验收。

4,以上统下原则

工作包分解的目标是可交付成果,每一个下级成果有且只有一个上级成果,每一个上级成果是其下级成果之和,不同的交付成果可以分解到不同的层级;

5,适可而止原则

工作包并不是分解的越细越好,而应当根据项目特性的难易程度进行分解,难的复杂度高的分解细点、适当增加分解的层级,而容易的复杂度低的可以减少分层。

6,人事匹配原则

需要考虑每一级任务到底需要什么样的领域专家或者工程人员,任务要能匹配工程人员的能力,工程人员能力要能匹配任务,考虑到执行力,还需要将任务分解到人人有事做,事事能完成的层次。

5. 小结

本文从宏观角度讲述了工作分解结构法的“术”与“道”,在宏观上理解了工作分解结构法,还需要微观上进行实践,才能做到“学以致用”。另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

6. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

7. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。

8. 参考资料

[1] 《极简项目管理》 郭致星著

1. 前言

不同于教科书里讲的深度学习的评价指标,这里主要讲述生产训练中常用的评价指标。通常在分布式训练中对训练的过程与结果会进行评价,比如选择一个评价指标:准确率,即表明模型求解给定问题的准确度。而本文提到的评价指标主要分为两大类,即训练结果评价与训练系统评价。

2. 训练指标

教科书里经常提到的深度学习的评价指标有准确率、精确率、召回率、F1值等,如下:

  • 准确率(Accuracy),所有的预测正确(正类负类)的占总的比重;

  • 精确率(Precision),查准率,即正确预测为正的占全部预测为正的比例;

  • 召回率(Recall),查全率,即正确预测为正的占全部实际为正的比例;

  • F1值(H-mean值),F1值为算数平均数除以几何平均数,且越大越好;

实际上这些指标在真正的生产过程中用的不多,在实际的分布式训练过程中,比较关心的训练评价指标有:

  • 加速比(speedup),即多卡训练下的单卡吞吐量平均指标除以单卡训练下的吞吐量平均指标,比如,大规模训练下的 ResNet-50 v1.5的单卡FPS指标是600,而单卡训练的FPS指标是800,那么加速比即 600/800 = 0.75,加速比体现的是训练集群的效率与可扩展性,越高的加速比表明训练集群的资源利用率越高,但是越高的加速比要求对训练集群的技术要求也越高。比如 一个 1000张卡的训练集群,要求 加速比 0.9以上,那么对于主机间的网络、主机内的网络、全栈软件、训练卡内部的硬件架构、集合通信拓扑算法、训练算法的优化等的要求都极高,这就涉及到整个分布式训练系统的问题,而不是单个点能彻底解决的;
  • 吞吐量,sequence/sec 或 FPS, 即每秒能处理的图片数或数据量;
  • 收敛时间(Time)与训练次数(epoch),生产过程中对训练所有的时间是有要求的,假设给定一个模型的训练次数(epoch)为100,如果要把这个100次都训练完需要 好几天,甚至好几个星期,那么可以认为生产不适用,基本上可以定义 训练一个模型到收敛需要 24小时以上,都可以看做是生产不适用,需要扩大训练集群的规模,使之训练时间控制在24小时之内;
  • 平均准确率(eval Accuracy),平均准确率是训练是否收敛的重要评判标准之一,比如定义一个 Resnet50 v1.5 的训练模型的准确率为 76%,如果训练结束的平均准确率能达到这个值就认为训练是收敛的;
  • 可收敛,训练的最终结果可以达到 平均准确率的要求,即认为可收敛,否者即任务训练失败;
  • 学习率(Learning rate)与损失率(Loss),学习率大模型训练学习速度快,但是易导致损失率爆炸, 学习率小模型训练学习速度慢,而且容易过拟合,收敛速度慢;
  • 曲线拟合(Curve Fitting),这是一个非常重要的评价手段,在XPU训练的场景下,通常先用一个已有的之前训练好模型为基础或先用GPU训练出一个基础模型,然后把XPU训练的结果指标跟GPU训练模型的指标进行比较,曲线拟合即认为XPU的训练结果达标,这也是调试XPU训练结果的一个重要手段。这里埋一个问题,按照曲线拟合的说法,假设有一个2000张XPU卡的集群,怎样评价这个集群训练的结果是正确的?以GPU训练的结果做比较,那么找一个这么大规模的GPU集群进行训练然后得到想要的模型做基础匹配也是不大现实的,那么需要采用什么技术方案才能解决这个问题?

以TensorBoard为例,说明模型的评价指标,在下面的命令行列输入一个baseline:/log_path_2:

1
# tensorboard --logdir=training_model:/log_path_1, baseline:/log_path_2

这个baseline 的模型已经确定是精度达标,生产可用的。然后 XPU训练的模型的 training_model:/log_path_1 与这个GPU训练处的baseline进行比,在tensorboard里可以表现如下图:

训练结果

在上图里,新的模型的eval_accuracy值与baseline的值最终是一样的,这说明训练结果是收敛且精度达标,eval_accuracy中间的线有点差异是由于按不同的训练次数进行tensorboard指标保存所造成。新模型的Loss线与Learning_rate 线也与基础线吻合,这说明XPU训练的模型质量可生产适用。eval_accuracy、Loss、Learning_rate是三个最重要的度量指标,只要这样三个指标达标,那么大概率即可判断这个在XPU下新训练的模型具备生产可用能力。

3. 系统指标

分布式训练系统其本身也是一个分布式系统,因此除了训练领域相关的度量指标,也有与分布式系统质量有关的一套度量指标,其中比较重要的几项内容如下:

  • 可用性(Availability),可用性指的是分布式训练系统长时间可对外提供服务的能力,通常采用小数点后的9的个数作为度量指标,按照这种约定“五个九”等于0.99999(或99.999%)的可用性,默认企业级达标的可用性为6个9。但是当前从时间维度来度量可用性已经没有太大的意义,因为设计得好的系统可以在系统出现故障得情况下也能保证对外提供得服务不中断,因此,当前更合适得可用性度量指标 是请求失败率;

  • 可靠性(Reliability),可靠性一般指系统在一定时间内、在一定条件下可以无故障地执行指定功能的能力或可能性, 也是采用小数点后的9的个数作为度量指标,通常5个9的可靠性就可以满足企业级达标;

  • 可伸缩性(Scalability),是指通过向系统添加资源来处理越来越多的工作并且维持高质量服务的能力,其受可用性以及可靠性的制约,集群规模越大出故障的概率越高从而降低可用性、可靠性,为了保证可用性以及可靠性达标,需要适配合理的可伸缩性指标;

  • 韧性(resilience),通常也叫容错性(fault-tolerant),也就是健壮和强壮的意思,指的是系统的对故障与异常的处理能力,比如在软件故障、硬件故障、认为故障这样的场景下,系统还能保持正常工作的能力,分布式训练系统的容错能力是一个非常重要的指标。

4. 小结

本文从实践的角度讲述了分布式训练的训练结果评价指标与系统评价指标,这些指标是度量一个分布式训练系统与训练的模型是否生产可用的重要参考。日拱一卒,功不唐捐,分享是最好的学习,与其跟随不如创新,希望这个知识点对大家有用。另作者能力与认知都有限,”我讲的,可能都是错的“,欢迎大家拍砖留念。

5. 作者简介

常平,中科大硕,某AI独角兽深度学习高级软件主管工程师、架构师,前EMC资深首席工程师,主要工作背景在深度学习、大数据、云计算、分布式中间件以及Linux内核领域。

6. 参考资料

[1] https://www.changping.me

7. 版权申明

本文的版权协议为 CC-BY-NC-ND license:https://creativecommons.org/licenses/by-nc-nd/3.0/deed.zh

在遵循署名、非商业使用(以获利为准)以及禁止演绎的前提下可以自由阅读、分享、转发、复制、分发等。