程序如何在两个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,一经查实,立即删除!

相关文章

集成Spring和JavaServer Faces:改进的模板

随着2.0版的发布&#xff0c;Facelet模板成为JSF规范的核心部分。 使用<ui&#xff1a;composition>和<ui&#xff1a;decorate>标记&#xff0c;可以轻松构建复杂的页面&#xff0c;同时仍保持标记清晰。 模板在创建HTML表单时特别有用&#xff0c;但是不幸的是&a…

whmcs模板路径

whmcs网站根目录 比如你的域名是server.nongbin.vip&#xff0c;你需要cd /home/wwwroot/server.nongbin.vip&#xff0c;该目录下然后&#xff0c;cd template/ 给文件夹下就是你上传的模板文件夹转载于:https://www.cnblogs.com/nongbin/p/6412108.html

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

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

37、EnumSet详解

EnumSet类也是有顺序的&#xff0c;EnumSet按照枚举值在Enum类内定义的顺序决定集合元素的顺序 EnumSet在内部已位向量的形式存储&#xff0c;这种存储方式非常紧凑、搞笑&#xff0c;因此EnumSet占用内存很小&#xff0c;而且运行效率很好。 EnumSet集合不允许加入null元素 En…

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

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

numpy 辨异(三)—— hstack/column_stack,linalg.eig/linalg.eigh

1. np.hstack np.column_stack >>> np.hstack([np.array([1, 2, 3]), np.array([4, 5, 6])]) array([1, 2, 3, 4, 5, 6])>>> np.column_stack([np.array([1, 2, 3]), np.array([4, 5, 6])]) array([[1, 4],[2, 5],[3, 6]]) 当然对等地&#xff0c;也存在&…

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

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

acwing算法提高之动态规划--数位DP

目录 1 基础知识2 模板3 训练 1 基础知识 暂无。。。 2 模板 暂无。。。 3 训练 题目1&#xff1a;度的数量。 解题思路&#xff1a;分类讨论。 C代码如下&#xff0c; #include <iostream> #include <vector>using namespace std;const int N 35; int K,…

python 输入数字变成密码_如何在python中检查数字的“密码”

我建议使用sets和stdlib中的string包作为可接受字符的列表。在我还建议进行一点重构&#xff0c;以删除大量带有if / else分支的嵌套。在import stringupper set(list(string.uppercase))lower set(list(string.lowercase))numbers set(list(string.digits))while True:npw …

使用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/下载&…

jquery的load方法

load方法指定一个界面会显示在目标的标签内部 比如MVC的一个分部视图页面想要显示在某个标签里面&#xff0c;可以写成 $(标签ID).load&#xff08;分部视图名称,data&#xff09; 其中第二个参数可选&#xff0c;主要是一些需要传递到该页面的数据JSON格式组成&#xff0c;发送…

android 录音原始文件_音频采集:Android基于AudioRecord的实现

前言这篇文章简单介绍下移动端Android系统下利用AudioRecord进行音频采集方法。按照惯例开始前先提供一份源码 AudioRecordLib 。AudioRecord采集的核心实现在于 AudioRecordCore.java 这个文件。权限申请想要使用AudioRecord这个API&#xff0c;需要在AndroidManifest.xml的配…

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…

使用Log4jdbc记录JDBC操作

当我们开发任何应用程序&#xff0c;完成它或结束其任何模块时&#xff0c;我们都会开始优化过程。 大多数应用程序都包含数据库访问权限&#xff0c;并且如果您使用的是ORM &#xff0c;则可能会使用hibernate 。 优化休眠持久层&#xff0c;要求准备阅读&#xff0c;理解和评…

android BluetoothAdapter蓝牙BLE扫描总结

做室内定位的程序员应该都知道&#xff0c;在Android 5.0之后&#xff0c;google推出了蓝牙扫描新接口&#xff0c;我们在实测中发现出一些问题&#xff0c;现在给大家列出&#xff0c;以供参考&#xff1a; 1.android 4.3.1(Build.VERSION_CODES.JELLY_BEAN_MR2)增加的startLe…

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

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

段落排版--对齐(text-aliagn)

想为块状元素中的文本、图片设置居中样式吗&#xff1f;可以使用text-align样式代码&#xff0c;如下代码可实现文本居中显示。(那么什么是块状元素呢&#xff1f;后面会讲到呢~) h1{text-align:center; } <h1>了不起的盖茨比</h1> 同样可以设置居左&#xff1a; h…