TensorFlow: Large-Scale Machine Learning on Heterogeneous Distributed Systems
计算图里的node,有0~N个输入,有0~N个输出。计算图里的edge,分为Tensor-edge和Special-edge;Tensor的大小和类型可以在计算图构建时指定或者自动推导出来;Special-edge是控制依赖,没有数据流动。
控制依赖可由用户指定步骤之间的顺序执行依赖关系;也可由tensorflow自动插入,控制并行度,从而控制峰值内存使用量。
模型的参数用Variable类型来表示,具有全局生命周期(内存反复使用不被释放);
Tensor使用引用计数,到0即可以释放内存;
单设备上执行:每个node维护依赖数,减至0则放入ready队列;
多设备上执行:有Cost Model:估计输入输出占用空间大小,估计操作执行时间长度;可能是按数据量进行粗略估计,也可能根据之前的实际计算测量值来估计;先跑模拟流程:对所有ready的<node,device>,估计其计算时间+通信时间,贪心的选一个最早结束的,调度上去;最后用模拟流程的<node,device>映射关系,去跑实际的graph; 用户也可以指定node的device,或者做范围限制;
跨device的边,被拆成Send和Receive节点;能合并的尽量合并,减少通信次数,减少内存占用次数;
整个流程是去中心化的,master只负责发送一个Run命令,剩下的同步在各个worker和各个device之间做;
故障恢复:所有Variable类型(即模型的参数)都和Save节点和Load节点相关联;每N次iteration就Save一次;恢复的时候一起来就Load一次;
“反向传播”graph,有可能用一些“前向传播”graph中的输入/中间结果;
只有“正向传播"graph,则中间结果可以用后马上释放内存;有了”反向传播“graph,早期的中间结果等到最后还要被用到,长期占用内存。解决方法:1. 用更精准的启发算法去推测graph执行顺序;2.用到的时候重新计算;3.GPU主存吃紧则可从GPU换出到CPU主存;
执行子图:用户可以指定任意边的输入值,用户可以指定要任意输出边做结果;系统根据graph的依赖关系,自动推断需要计算的最小子图;
用户可以手动指定node放到哪个device上执行,指定哪些node在同一个device上执行;
文件上的训练数据预取,和graph的计算,是通过Queue来并行化的;提到了训练数据shuffle(似乎也是小块内部进行shuffle);
优化
1. 相同表达式的合并,避免重复计算;
2. 调度优化,减少数据在GPU内存里存放的时长;精心安排数据的通信,减少网络竞争;对Receive操作加控制依赖边,防止其过早执行(过早执行,一来占内存,二来一上来就多处数据通信导致burst访问网络)
4. 用了很多成熟的库:BLAS, cuBLAS,cuda-convnet(不行了现在), cuDNN, Eigen(矩阵,矩阵分解等)
5. 半精度float有损压缩:特别是在跨机通信时有用;发送方把32位float的尾数部分截断16位就行;接收方把这16位补0恢复成32位;
正确性验证
1. ?
2. 先试验小模型;成功了再上大模型;
3. 先把learning-rate调成0,然后和竞品系统,跑同一份数据(用同样的模型参数?),看看结果是否一样;
4. 先debug单机版,最后再上多机分布式;适合发现race和非原子操作造成的bug;
5. 防御数值溢出:不同的库在处理Nan上是不同的;CNN对Nan非常敏感,所以要预先设防,避免后续事后分析;
6. 2个子网络在tensorflow和竞品上跑时(参数全一样),要判断误差是否在合理的数量级范围内;
上图是RNN的Model并行示意图;(Seide的Layer-by-Layer也是Model并行)
上图没看懂??