程序如何在两个gpu卡上并行运行_深度学习分布式训练相关介绍 - Part 1 多GPU训练...

e07ee1e99ba66c217cd67ab9fded4ee6.png

本篇文章主要是对深度学习中运用多GPU进行训练的一些基本的知识点进行的一个梳理

文章中的内容都是经过认真地分析,并且尽量做到有所考证

抛砖引玉,希望可以给大家有更多的启发,并能有所收获

介绍

大多数时候,梯度下降算法的训练需要较大的Batch Size才能获得良好性能。而当我们选择比较大型的网络时候,由于GPU资源有限,我们往往要减少样本数据的Batch Size。

当GPU无法存储足够的训练样本时,我们该如何在更大的batch size上进行训练?

面对这个问题,事实上我们有几种工具、技巧可以选择,它们也是下文中将介绍的内容。

在这篇文章中,我们将探讨:

  • 多GPU训练和单GPU训练有什么区别
  • 如何最充分地使用多GPU机器
  • 如何进行多机多卡训练?

更多关于多机多卡的分布式训练的详细架构理解和实践请参考我的下一篇文章:

Zhang Bin:深度学习分布式训练相关介绍 - Part 2 详解分布式训练架构PS-Worker与Horovod​zhuanlan.zhihu.com
f6b2595689d275f8ee79be68e976b1bb.png

本文章介绍的内容在框架间是通用的,代码示例为:在不借助外部框架的情况下,将单GPU训练TensorFlow代码改为支持多GPU的训练代码

单GPU训练 vs 多GPU训练

单GPU训练 一般代码比较简单,并且能满足我们的基本需求,通常做法是设定变量CUDA_VISIBLE_DEVICES的值为某一块GPU来Mask我们机器上的GPU设备,虽然有时当我们忘了设定该变量时程序会自动占用所有的GPU资源,但如果没有相应的代码去分配掌控GPU资源的使用的话,程序还是只会利用到第一张卡的计算资源,其他的资源则仅是占用浪费状态。

多GPU训练 则可以从两个方面提升我们模型训练的上限:1. 超过单卡显存上限的模型大小, 2. 更大的Batch Size和更快训练速度。相应的,目前各大主流框架的多GPU训练一般存在两种模式:

  • 模型并行 :分布式系统中的不同GPU负责网络模型的不同部分,进而可以 构建超过单卡显存容量大小的模型 。比如,可以将神经网络的不同层分配到不同的GPU设备,或者将不同的参数变量分配到不同的GPU设备。
  • 数据并行 :不同的 GPU设备有同一模型的多个副本,将数据分片并分配到每个GPU上,然后将所有GPU的计算结果按照某种方式合并,进而可以增加训练数据的Batch Size

cc4b6e5d08f4edfa0627cd2edc2cd00f.png

此外,从主机的数量的角度来讲还存在 单机多卡多机多卡(分布式)的区别:

  • 单机多卡:只需运行一份代码,由该代码分配该台机器上GPU资源的使用
  • 多机多卡:每台机器上都需要运行一份代码,机器之间需要互相通信传递梯度,并且模型参数的更新也存在同步训练模式和异步训练模式的区别

多GPU机器的充分利用

这一节,将详细探讨一下多GPU的机器该如何利用。

对于多GPU训练,一般我们需要用数据并行的模式比较多,通过增大 Batch Size 并辅以较高的 Learning Rate 可以加快模型的收敛速度。

由于我们模型是通过若干步梯度反向传播来迭代收敛模型的参数,而每一步的梯度由一个Batch内样本数据的损失情况(Loss)得到,因此当 Batch Size 比较大时, 可以减少 Batch样本的分布和整体样本的分布偏差太大的风险,进而使得每一步的梯度更新方向更加准确。

比如,单卡训练 InceptionResNet 网络最大Batch Size为100, 学习率为0.001。采用4张卡去训练时,可以设置Batch Size为400, 学习率为 0.002。在代码中对每一个Batch 400 切分成 4*100,然后给到不同GPU卡上的模型上去训练。

下面主要介绍一下单机多卡训练的细节及部分Tensorflow代码:

  • 数据切片
  • 模型构建
  • 梯度反传

1. 数据分片

对于多GPU训练,我们首先要做的就是对训练数据进行分片,对于单机多卡模型,其数据的分片可以在代码的内部进行, 而对于多机多卡模型,多机之间没有必要进行数据切分方面的通信,建议的做法是先在本地做好数据的分配,然后再由不同的机器读取不同的数据。

Tensorflow 单机多卡的数据切片代码如下,其中 training_iterator 为采用tf.data.Dataset 构建的训练数据pipeline, num_tower 为当前机器上可见的(CUDA_VISIBLE_DEVICES)GPU数量。

tower 指模型的副本。

mnist_input, mnist_label = training_iterator.get_next()
tower_inputs = tf.split(mnist_input, num_towers)
tower_labels = tf.split(mnist_label, num_towers)

通过 tf.split 函数,将输入的数据按照GPU的数量平分。

2. 构建模型

有了分好的数据,下一步骤则是需要将模型放置在我们所有的GPU上,并将切片好的数据传入。

Tensorflow可以指定将不同的任务分配到不同的设备上, GPU支持大量并行计算, 因此可以将模型的运算、梯度的计算分配到GPU上来,而变量的存储、梯度的更新则可以由CPU来执行,如下图所示

be2dacd93e51384ad738aac591bf61ee.png

下面我们来看一下TensorFlow的相关代码

最外层的 for i in range(num_towers): 使我们需要构建模型 num_towers次。

下一层的 with tf.device(device_string % i): 代表着每次我们构建模型时,模型放置的设备名称, 如果为GPU机器device_string = '/gpu:%d' ,如果为CPU机器 device_string = '/cpu:%d'

再下一层 with (tf.variable_scope(("tower"), reuse=True if i > 0 else None)): 通过 scope 的reuse 使得我们再后续放置模型的时候,不同GPU之间的模型参数共享。

最后一层 with (slim.arg_scope([slim.model_variable, slim.variable], device="/cpu:0" if num_gpus != 1 else "/gpu:0")): 使得我们将构建模型中的变量放到CPU上来, 而运算则仍保留在该GPU上。

tower_gradients = []
tower_predictions = []
tower_label_losses = []
optimizer = tf.train.AdamOptimizer(learning_rate=1E-3)for i in range(num_towers):with tf.device(device_string % i):with (tf.variable_scope(("tower"), reuse=True if i > 0 else None)):with (slim.arg_scope([slim.model_variable, slim.variable],device="/cpu:0" if num_gpus != 1 else "/gpu:0")):x = tf.placeholder_with_default(tower_inputs[i], [None, 224,224,3], name="input")y_ = tf.placeholder_with_default(tower_labels[i], [None, 1001], name="label")# logits = tf.layers.dense(x, 10)logits = build_model(x)predictions = tf.nn.softmax(logits, name="predictions")loss = tf.losses.softmax_cross_entropy(onehot_labels=y_, logits=logits)grads = optimizer.compute_gradients(loss)tower_gradients.append(grads)tower_predictions.append(predictions)tower_label_losses.append(loss)

3. 梯度反传

上一步已经得到了各个tower上的梯度,下面则需要将这些梯度结合起来并进行反向传播以更新模型的参数。

梯度结合的代码可以参考下面的函数

def combine_gradients(tower_grads):"""Calculate the combined gradient for each shared variable across all towers.Note that this function provides a synchronization point across all towers.Args:tower_grads: List of lists of (gradient, variable) tuples. The outer listis over individual gradients. The inner list is over the gradientcalculation for each tower.Returns:List of pairs of (gradient, variable) where the gradient has been summedacross all towers."""filtered_grads = [[x for x in grad_list if x[0] is not None] for grad_list in tower_grads]final_grads = []for i in range(len(filtered_grads[0])):grads = [filtered_grads[t][i] for t in range(len(filtered_grads))]grad = tf.stack([x[0] for x in grads], 0)grad = tf.reduce_sum(grad, 0)final_grads.append((grad, filtered_grads[0][i][1],))return final_grads

通过 combine_gradients 来计算合并梯度,再通过 optimizer.apply_gradients 对得到的梯度进行反向传播

merged_gradients = combine_gradients(tower_gradients)
train_op = optimizer.apply_gradients(merged_gradients, global_step=global_step)

最后再通过 sess.run(train_op) 对执行。

多机多卡 分布式训练

多机多卡相比较于单机多卡,其使得模型训练的上限进一步突破。一般我们一台服务器只支持8张GPU卡,而采用分布式的多机多卡训练方式,可以将几十甚至几百台服务器调度起来一起训练一个模型。

但相比于单机多卡,多机多卡分布式训练方式的配置更复杂一些,不仅要保证多台机器之间是可以互相通信的,还需要配置不同机器之间的角色以及不同机器之间梯度传递。

d556517de8b3e9eb41d6cac3aaa80917.png
  • TensorFlow 原生 PS架构
    在Parameter server架构(PS架构)中,集群中的节点被分为两类:parameter server和worker。其中parameter server存放模型的参数,而worker负责计算参数的梯度。在每个迭代过程,worker从parameter sever中获得参数,然后将计算的梯度返回给parameter server,parameter server聚合从worker传回的梯度,然后更新参数,并将新的参数广播给worker。
  • Uber 开发的Horovod架构 - 支持 TensorFlow, Keras, PyTorch, and Apache MXNet
    Horovod 是一套面向 TensorFlow 的分布式训练框架,由 Uber 构建并开源,目前已经运行于 Uber 的 Michelangelo 机器学习即服务平台上。Horovod 能够简化并加速分布式深度学习项目的启动与运行。
    Horovod架构采用全新的梯度同步和权值同步算法,叫做 ring-allreduce。此种算法各个节点之间只与相邻的两个节点通信,并不需要参数服务器。因此,所有节点都参与计算也参与存储。

关于分布式训练的更多介绍,请参考我的下一篇文章

Zhang Bin:深度学习分布式训练相关介绍 - Part 2 详解分布式训练架构PS-Worker与Horovod​zhuanlan.zhihu.com
f6b2595689d275f8ee79be68e976b1bb.png

相关参考链接

TensorFlow - Multi GPU Computation

分布式tensorflow(一)

TensorFlow分布式全套(原理,部署,实例)

distributeTensorflowExample

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

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

相关文章

系统英伟达gpu驱动卸载_绕过CPU,英伟达让GPU直连存储设备

英伟达最近发布了一个新的GPUDirect Storage,暂且叫做GPU直连存储,让GPU直接连到NVMe存储设备上。这一方案用到了RDMA设备来把数据从闪存存储转移到GPU本地的内存里,无需经过CPU还有系统内存。如果这一举措顺利的话,英伟达就能摆脱…

嘲弄和存根–了解Mockito的测试双打

介绍 我遇到的一件事是使用模拟框架的团队假设他们在模拟。 他们并不知道Mocks只是Gerard Meszaros在xunitpatterns.com上归类的“测试双打”之一。 重要的是要意识到每种类型的测试双精度在测试中都扮演着不同的角色。 用与您需要学习不同模式或重构的方式相同,您…

【代码笔记】iOS-首页3张图片变化

一&#xff0c;效果图。 二&#xff0c;工程图。 三&#xff0c;代码。 RootViewController.h #import <UIKit/UIKit.h>interface RootViewController : UIViewController {NSTimer *timer;UIImageView *imageView1;UIImageView *imageView2;UIImageView *imageView3;UIV…

使用Eclipse在Amazon Ec2中部署Java Web应用程序的完整指南

嗨&#xff0c;读者们&#xff0c; 今天&#xff0c;我将向您展示如何使用Eclipse IDE在Amazon EC2中部署简单的Java Web应用程序。 在我们开始之前&#xff0c;我们需要一些必需的东西&#xff0c; Eclipse Java EE IDE –您可以从http://www.eclipse.org/downloads/下载&…

Spring 3和Java EE 6 –不公平和不完整的比较

这篇小文章的初稿标题为“ Spring&#xff06;Java EE –比较苹果和橙子”。 在撰写本文时&#xff0c;我了解到可以比较Spring Framework和Java EE&#xff0c;但这始终是不公平且不完整的工作。 Java for Enterprise和Spring Framework的发展紧密地联系在一起。 两者相互依存…

xml配置文件推荐方式

1.XML帮助类 /// <summary>/// Xml帮助类/// </summary>public class XmlHelper{/// <summary>/// 保存xml/// </summary>/// <typeparam name"T"></typeparam>/// <param name"path"></param>/// <p…

AFNetWorking https SSL认证

一般来讲如果app用了web service , 我们需要防止数据嗅探来保证数据安全.通常的做法是用ssl来连接以防止数据抓包和嗅探 其实这么做的话还是不够的 。 我们还需要防止中间人攻击&#xff08;不明白的自己去百度&#xff09;。攻击者通过伪造的ssl证书使app连接到了伪装的假冒的…

查看环境列表_Xfce 4.14桌面环境正式发布,想要图形界面又想节省内存?就它了...

1. Xfce 4.14桌面环境正式发布&#xff0c;它有什么新特性&#xff1f;本文主要讲解Xfce 4.14桌面环境正式发布&#xff0c;它有什么新特性。Xfce已经开发了4年多&#xff0c;但是这个周末终于看到了期待已久的Xfce 4.14的发布。Xfce 4.14是这个轻量级桌面环境的最新稳定版本&a…

卷积神经网络语音识别_用于物体识别的3D卷积神经网络

本文提出了一种基于CNN的3D物体识别方法&#xff0c;能够从3D图像表示中识别3D物体&#xff0c;并在比较了不同的体素时的准确性。已有文献中&#xff0c;3D CNN使用3D点云数据集或者RGBD图像来构建3D CNNs&#xff0c;但是CNN也可以用于直接识别物体体积表示的体素。本文中&am…

#获得请求来源ip_以太网数据包TCP、IP、ICMP、UDP、ARP协议头结构详解

以太网首部目地MAC地址(8字节)源MAC地址(8字节)类型(2字节)1、IP头的结构版本(4位)头长度(4位)服务类型(8位)封包总长度(16位)封包标识(16位)标志(3位)片断偏移地址(13位)存活时间(8位)协议(8位)校验和(16位)来源IP地址(32位)目的IP地址(32位)选项(可选)填充(可选)数据(1)字节和…

c# ef报错_C# EF调用MySql出现“未将对象引用设置到对象的实例”错误解决方案

C# EF调用MySql出现“未将对象引用设置到对象的实例”错误解决方案---修改步骤---1.打开Nuget管理包&#xff0c;把Mysql.Data替换为6.10.0以下任意版本。这里选择的是6.8.82.修改完毕后&#xff0c;继续把Mysql.Data.Entity也修改为对应版本6.8.8。3.安装完成后可以看到App.Co…

ServletRequest startAsync()的有用性有限

前段时间我遇到了Servlet 3.0中AsyncContext.start&#xff08;…&#xff09;的目的是什么&#xff1f; 题。 引用上述方法的Javadoc &#xff1a; 使容器调度线程&#xff08;可能从托管线程池中&#xff09;运行指定的Runnable 。 提醒大家&#xff0c; AsyncContext是Servl…

mysql所支持的比较运算符_mysql比较运算符有哪些?Mysql比较运算符详解

比较运算符可用于比较数字和字符串。今天发一篇Mysql比较运算符详解&#xff0c;希望对初学者有所帮助&#xff0c;虽然现在流行NoSQL&#xff0c;但是MYSQL还是很有用的&#xff0c;数字作为浮点值进行比较&#xff0c;字符串以不区为例进行比较&#xff0c;运算符用于比较表达…

Http Invoker的Spring Remoting支持

Spring HTTP Invoker是Java到Java远程处理的重要解决方案。 该技术使用标准的Java序列化机制通过HTTP公开服务&#xff0c;并且可以被视为替代解决方案&#xff0c;而不是Hessian和Burlap中的自定义序列化。 而且&#xff0c;它仅由Spring提供&#xff0c;因此客户端和服务器应…

学习后缀自动机想法

小序&#xff1a;学习后缀自动机是要有耐心的&#xff0c;clj的论文自己看真心酸爽&#xff01;&#xff08;还是自己太弱&#xff0c;ls&#xff0c;oyzx好劲啊&#xff0c;狂膜不止&#xff09; 刚刚在写博客之前又看了篇论文&#xff0c;终于看懂了&#xff0c;好开心 正文&…

mysql 分组top_MySQL:如何查询出每个分组中的 top n 条记录?

问题描述需求&#xff1a;查询出每月 order_amount(订单金额) 排行前3的记录。例如对于2019-02&#xff0c;查询结果中就应该是这3条&#xff1a;解决方法MySQL 5.7 和 MySQL 8.0 有不同的处理方法。1. MySQL 5.7我们先写一个查询语句。根据 order_date 中的年、月&#xff0c;…

利用jenkins的api来完成相关工作流程的自动化

[本文出自天外归云的博客园] 背景 1. 实际工作中涉及到安卓客户端方面的测试&#xff0c;外推或运营部门经常会有很多的渠道&#xff0c;而每个渠道都对应着一个app的下载包&#xff0c;这些渠道都记录在安卓项目下的一个渠道列表文件中。外推或运营部门经常会有新的渠道产生&a…

拥有成本分析:Oracle WebLogic Server与JBoss

Crimson Consulting Group 撰写的非常有趣的白皮书 &#xff0c;比较了Weblogic和JBoss之间的拥有成本 。 尽管JBoss是免费的&#xff0c;但该白皮书却严肃地宣称&#xff0c;从长远来看&#xff0c;Weblogic更便宜。 尽管此研究是由Oracle赞助的&#xff0c;但它看起来非常严肃…

mysql limit 分页 0_Mysql分页之limit用法与limit优化

Mysql limit分页语句用法与Oracle和MS SqlServer相比&#xff0c;mysql的分页方法简单的让人想哭。--语法&#xff1a;SELECT * FROM table LIMIT [offset,] rows | rows OFFSET offset--举例&#xff1a;select * from table limit 5; --返回前5行select * from table limit 0…

linux每天一小步---sed命令详解

1 命令功能 sed是一个相当强大的文件处理编辑工具&#xff0c;sed用来替换&#xff0c;删除&#xff0c;更新文件中的内容。sed以文本行为单位进行处理&#xff0c;一次处理一行内容。首先sed吧当前处理的行存储在临时的缓冲区中&#xff08;称为模式空间pattern space&#xf…