[分布式训练] 单机多卡的正确打开方式:Horovod

[分布式训练] 单机多卡的正确打开方式:Horovod

转自:https://fyubang.com/2019/07/26/distributed-training4/

讲完了单机多卡的分布式训练的理论、TensorFlow和PyTorch分别的实现后,今天瓦砾讲一个强大的第三方插件:Horovod。

Horovod是Uber开源的跨平台的分布式训练工具,名字来自于俄国传统民间舞蹈,舞者手牵手围成一个圈跳舞,与Horovod设备之间的通信模式很像,有以下几个特点:

  1. 兼容TensorFlow、Keras和PyTorch机器学习框架。
  2. 使用Ring-AllReduce算法,对比Parameter Server算法,有着无需等待,负载均衡的优点。
  3. 实现简单,五分钟包教包会。(划重点)

Uber官方在git上给了很详细的例子: https://github.com/horovod/horovod/tree/master/examples,所以这里只简单讲一下大概的使用方法:

TensorFlow

以TF的Custom Training Loop API为例:

import tensorflow as tf
import horovod.tensorflow as hvd# 1. 初始化horovod
hvd.init()
# 2. 给当前进程分配对应的gpu,local_rank()返回的是当前是第几个进程
config = tf.ConfigProto()
config.gpu_options.visible_device_list = str(hvd.local_rank())
# 3. Scale学习率,封装优化器
opt = tf.train.AdagradOptimizer(0.01 * hvd.size())
opt = hvd.DistributedOptimizer(opt)
# 4. 定义初始化的时候广播参数的hook,这个是为了在一开始的时候同步各个gpu之间的参数
hooks = [hvd.BroadcastGlobalVariablesHook(0)]
# 搭建model,定义loss
loss = ...
train_op = opt.minimize(loss)
# 5. 只保存一份ckpt就行
checkpoint_dir = '/tmp/train_logs' if hvd.rank() == 0 else None
# 7. 用MonitoredTrainingSession实现初始化,读写ckpt
with tf.train.MonitoredTrainingSession(checkpoint_dir=checkpoint_dir,config=config,hooks=hooks) as mon_sess:while not mon_sess.should_stop():# Perform synchronous training.mon_sess.run(train_op)

具体的代码看tensorflow_mnist.py:https://github.com/horovod/horovod/blob/master/examples/tensorflow_mnist.py

单机双卡训练输入以下命令:

CUDA_VISIBLE_DEVICES=6,7 horovodrun -np 2 -H localhost:2 python tensorflow_mnist.py

这里 -np指的是进程的数量。

执行之后可以看到如下的结果,因为多线程,每个step都打印了两遍。

[1,0]<stderr>:INFO:tensorflow:loss = 0.13126025, step = 300 (0.191 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.01396352, step = 310 (0.177 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.063738815, step = 310 (0.182 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.044452004, step = 320 (0.215 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.028987963, step = 320 (0.212 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.09094897, step = 330 (0.206 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.11366991, step = 330 (0.210 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.08559138, step = 340 (0.200 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.037002128, step = 340 (0.201 sec)
[1,0]<stderr>:INFO:tensorflow:loss = 0.15422738, step = 350 (0.181 sec)
[1,1]<stderr>:INFO:tensorflow:loss = 0.06424393, step = 350 (0.179 sec)

PyTorch

Torch下也是类似的套路,但是由于PyTorch本身单机多卡训练已经够简单了,API也稳定,所以笔者一般做的时候就是直接用Torch自己的DPDDP了。

import torch
import horovod.torch as hvd# 1. 初始化horovod
hvd.init()
# 2. 给当前进程分配对应的gpu,local_rank()返回的是当前是第几个进程
torch.cuda.set_device(hvd.local_rank())
# Define dataset...
train_dataset = ...
# 3. 用DistributedSampler给各个worker分数据
train_sampler = torch.utils.data.distributed.DistributedSampler(train_dataset, num_replicas=hvd.size(), rank=hvd.rank())
train_loader = torch.utils.data.DataLoader(train_dataset, batch_size=..., sampler=train_sampler)
# Build model...
model = ...
model.cuda()
# 4. 封装优化器
optimizer = optim.SGD(model.parameters())
optimizer = hvd.DistributedOptimizer(optimizer, named_parameters=model.named_parameters())
# 5. 初始化的时候广播参数,这个是为了在一开始的时候同步各个gpu之间的参数
hvd.broadcast_parameters(model.state_dict(), root_rank=0)
# 训练
for epoch in range(100):for batch_idx, (data, target) in enumerate(train_loader):optimizer.zero_grad()output = model(data)loss = F.nll_loss(output, target)loss.backward()optimizer.step()if batch_idx % args.log_interval == 0:print('Train Epoch: {} [{}/{}]\tLoss: {}'.format(epoch, batch_idx * len(data), len(train_sampler), loss.item()))

速度

瓦砾还没有来得及做一个全面的Horovod、tf.distribute和 Torch的单机多卡训练速度的横向对比,不过大家可以参考这两篇:

  1. Horovod: fast and easy distributed deep learning in TensorFlow
  2. Goodbye Horovod, Hello CollectiveAllReduce

总体而言,用了All-Reduce算法的API,速度应该都差不多,如果你是土豪,拥有NVLINK(卡间通信极快)的话,那忘了我说的这几篇“废话”吧朋友。Orz。

总结

终于结束了单机多卡系列的最后一章,由于博客本身的限制,给的例子整体还是比较简单,以入门为主,大家具体使用的时候肯定还是会遇到一些坑,这里瓦砾把踩过的一些坑和解决办法列举在这,以避免大家以后重复踩坑:

  • tf.contrib.distributed.MirroredStrategy 需要optimizer支持merge_call(bert实现的optimizer是直接修改apply_gradient的,所以会报错),这个时候就需要正确地修改optimizer里的_apply_dense、_apply_sparse(参考Issue 23986 和 JayYip)。或者用horovod,就可以避免这个问题。
  • Effective batch size,不同的多卡工具对输入的batch size的操作不一样,要确定最后进模型的effective batch size才有意义。一般来说,多进程的batch size指的是每张卡的batch size。
  • Learning rate scale,学习率要根据effective batch size调整。
  • All-Reduce由于是多进程的,数据流各自独立,为了防止同一个step多gpu的batch重叠,最好的的办法是在每个进程里根据local_rank设置shard的数据,保证各个gpu采样的数据不重叠。
  • 为了使用horovod,新建docker container时,要加—privileged,否则会疯狂报warning,虽然没影响,但是看着难受。
  • Pytorch的DP多卡要注意最后一个batch的batch size不能小于gpu的数量,否则会报错,最保险的做法是drop_last,扔掉最后的batch。
  • 并不是所有情况下All-Reduce都比PS好,比如当卡间通信用的是NVLink的时候,在gpu数量不多的情况下,数据传输的时间不是瓶颈,All-Reduce的提升就几乎没有了。
  • DP和DDP有一个区别在于BatchNorm。
  • DDP封装model后不能再改动model。
  • 待补充。。。

Reference

  1. Horovod的官方给的一些例子。
  2. Uber:如何用Horovod实现bert的单机多卡训练
  3. Goodbye Horovod, Hello CollectiveAllReduce
  4. Horovod: fast and easy distributed deep learning in TensorFlow

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/532701.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【c语言数据结构笔记】1.2 数据结构

1.2数据结构 数据元素并独立 结构实体关系 形式定义&#xff08;D&#xff0c;S&#xff09; 其中D是数据元素的有限集&#xff0c;S是D上关系的有限集 eg&#xff1a;12位数&#xff1a;132423451233 分成三组四位数 次序关系<a1,a2><a2,a3> 遵守次序关系 eg&…

使用Apex进行混合精度训练

使用Apex进行混合精度训练 转自&#xff1a;https://fyubang.com/2019/08/26/fp16/ 你想获得双倍训练速度的快感吗&#xff1f; 你想让你的显存空间瞬间翻倍吗&#xff1f; 如果我告诉你只需要三行代码即可实现&#xff0c;你信不&#xff1f; 在这篇博客里&#xff0c;瓦砾…

【数据结构1.3笔记】研究内容

1.3研究内容 数据结构&#xff08;D&#xff0c;S&#xff09; {逻辑结构&#xff1a; {物理结构&#xff08;存储结构&#xff09; {数据的运算 1.逻辑结构 1 集合&#xff1a;集合&#xff0c;没有逻辑关系 2 线性结构 “一对一” 3树形结构 层次关系 4图形结构 练习&…

Linux下的LD_PRELOAD环境变量与库打桩

Linux下的LD_PRELOAD环境变量与库打桩 LD_PRELOAD是Linux系统的一个环境变量&#xff0c;它可以影响程序的运行时的链接&#xff08;Runtime linker&#xff09;&#xff0c;它允许你定义在程序运行前优先加载的动态链接库&#xff0c;一方面&#xff0c;我们可以以此功能来使…

2019年蓝桥杯第一题

第一题 标题&#xff1a;组队&#xff08;本题总分&#xff1a;5 分&#xff09; 作为篮球队教练&#xff0c;你需要从以下名单中选出 1 号位至 5 号位各一名球员&#xff0c; 组成球队的首发阵容。 每位球员担任 1 号位至 5 号位时的评分如下表所示。请你计算首发阵容 1 号位…

深度学习编译:MLIR初步

深度学习编译MLIR初步 深度模型的推理引擎 目前深度模型的推理引擎按照实现方式大体分为两类&#xff1a;解释型推理引擎和编译型推理引擎。 解释型推理引擎 一般包含模型解析器&#xff0c;模型解释器&#xff0c;模型优化器。 模型解析器负责读取和解析模型文件&#xff…

深入浅出LLVM

深入浅出LLVM 转自&#xff1a;https://www.jianshu.com/p/1367dad95445 什么是LLVM&#xff1f; LLVM项目是模块化、可重用的编译器以及工具链技术的集合。 美国计算机协会 (ACM) 将其2012 年软件系统奖项颁给了LLVM&#xff0c;之前曾经获得此奖项的软件和技术包括:Java、A…

蓝桥杯真题训练 2019.2题

2019第二题 标题&#xff1a;年号字串&#xff08;本题总分&#xff1a;5 分&#xff09; 小明用字母 A 对应数字 1&#xff0c;B 对应 2&#xff0c;以此类推&#xff0c;用 Z 对应 26。对于 27 以上的数字&#xff0c;小明用两位或更长位的字符串来对应&#xff0c;例如 AA…

一分钟系列:什么是虚拟内存?

一分钟系列&#xff1a;什么是虚拟内存&#xff1f; 转自&#xff1a;https://mp.weixin.qq.com/s/opMgZrXV-lfgOWrNUMKweg 注&#xff1a;一分钟系列的篇幅都不长&#xff0c;适合吃饭蹲坑、地铁公交上食用&#xff5e; 内存对于用户来说就是一个字节数组&#xff0c;我们可…

蓝桥杯真题训练 2019.3题

标题&#xff1a;数列求值 &#xff08;本题总分&#xff1a;10 分&#xff09;### 给定数列 1, 1, 1, 3, 5, 9, 17, …&#xff0c;从第 4 项开始&#xff0c;每项都是前 3 项的和。求 第 20190324 项的最后 4 位数字。 【答案提交】 这是一道结果填空的题&#xff0c;你只需…

11-Kafka

1 Kafka Kafka是一个分布式流式数据平台&#xff0c;它具有三个关键特性 Message System: Pub-Sub消息系统Availability & Reliability&#xff1a;以容错及持久化的方式存储数据记录流Scalable & Real time 1.1 Kafka架构体系 Kafka系统中存在5个关键组件 Producer…

虚拟内存精粹

虚拟内存精粹 标题&#xff1a;虚拟内存精粹 作者&#xff1a;潘建锋 原文&#xff1a;HTTPS://strikefreedom.top/memory-management–virtual-memory 导言 虚拟内存是当今计算机系统中最重要的抽象概念之一&#xff0c;它的提出是为了更加有效地管理内存并且降低内存出错的概…

蓝桥杯真题训练 2019.4题

标题&#xff1a; 数的分解&#xff08;本题总分&#xff1a;10 分&#xff09; 【问题描述】 把 2019 分解成 3 个各不相同的正整数之和&#xff0c;并且要求每个正整数都不包 含数字 2 和 4&#xff0c;一共有多少种不同的分解方法&#xff1f; 注意交换 3 个整数的顺序被视…

深度学习自动编译和优化技术调研

深度学习自动编译和优化技术调研 转自&#xff1a;https://moqi.com.cn/blog/deeplearning/ 作者&#xff1a;墨奇科技全栈开发 在墨奇科技&#xff0c;我们需要将一些包含深度神经网络&#xff08;DNN&#xff09;的 AI 算法移植到边缘端的设备&#xff0c; 这些设备往往使用 …

三元组数据处理系统

include<stdio.h> include<stdlib.h> define OK 1 define ERROR 0 define OVERFLOW -2 typedef int Status; typedef float ElemType; typedef ElemType *Triplet; // 声明Triplet为ElemType指针类型 //三元组的初始化 Status initTriplet(Triplet &T, E…

Copy-On-Write COW机制

Copy-On-Write COW机制 转自&#xff1a;https://zhuanlan.zhihu.com/p/48147304 作者&#xff1a;Java3y 前言 只有光头才能变强 在读《Redis设计与实现》关于哈希表扩容的时候&#xff0c;发现这么一段话&#xff1a; 执行BGSAVE命令或者BGREWRITEAOF命令的过程中&#xff0c…

实验报告:抽象数据类型的表现和实现

实验报告&#xff1a;抽象数据类型的表现和实现 实验内容 基本要求&#xff1a; 设计实现抽象数据类型“三元组”&#xff0c;要求动态分配内存。每个三元组由任意三个实数的序列构成&#xff0c;基本操作包括&#xff1a;创建一个三元组&#xff0c;取三元组的任意一个分量&…

关于x86、x86_64/x64、amd64和arm64/aarch64

关于x86、x86_64/x64、amd64和arm64/aarch64 转自&#xff1a;https://www.jianshu.com/p/2753c45af9bf 为什么叫x86和x86_64和AMD64? 为什么大家叫x86为32位系统&#xff1f; 为什么软件版本会注明 for amd64版本&#xff0c;不是intel64呢&#xff1f; x86是指intel的开…

实验报告: 线性表的基本操作及应用

实验报告&#xff1a; 线性表的基本操作及应用 实验内容 基本要求&#xff1a; &#xff08;1&#xff09;实现单链表的创建&#xff1b;&#xff08;2&#xff09;实现单链表的插入&#xff1b;&#xff08;3&#xff09;实现单链表的删除 &#xff08;4&#xff09;实现单链…

TVM:源码编译安装

TVM&#xff1a;Linux源码编译安装 笔者环境&#xff1a; OS&#xff1a;Ubuntu 18.04 CMake&#xff1a;3.10.2 gcc&#xff1a;7.5.0 cuda&#xff1a;11.1 编译安装过程总览 本文将简介 tvm 的编译安装过程&#xff0c;包含两个步骤&#xff1a; 通过C代码构建共享库设置相…