热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

转载|在TensorFlow和PaddleFluid中使用多块GPU卡进行训练

前四篇文章我们介绍了PaddleFluid和TensorFlow的设计原理基本使用概念,分别通过在两个平台上实现完全相同的模型完成图像分类,语言模型和序

前四篇文章我们介绍了 PaddleFluid 和 TensorFlow 的设计原理基本使用概念,分别通过在两个平台上实现完全相同的模型完成图像分类,语言模型和序列标注三个任务,了解我们的使用经验如何在两个平台之间迁移,以此来了解非序列模型和序列模型在两个平台之上设计和使用的差异。

转载|PaddleFluid和TensorFlow基本使用概念对比

转载|使用PaddleFluid和TensorFlow实现图像分类网络SE_ResNeXt

转载|使用PaddleFluid和TensorFlow训练RNN语言模型

转载|使用PaddleFluid和TensorFlow训练序列标注模型

到目前为止我们依然遗留了一个对在单机上使用深度学习框架来说最重要 的问题:如何利用 GPU, 也包括利用多个 GPU 进行训练。深度学习模型的训练往往非常耗时,在较大数据集上训练或是训练复杂模型往往会借助于 GPU 强大的并行计算能力。 如何能够让模型运行在单个/多个 GPU 上,充分利用多个 GPU 卡的计算能力,且无需关注框架在多设备、多卡通信实现上的细节是这一篇要解决的问题。 

这一篇我们以 RNN 语言模型为例。RNN 语言模型在 第三篇已经介绍过,这一篇我们维持原有的模型结构不变,在以下两处对第三节原有的例子进行改建: 

1. 为 PaddleFluid 和 TensorFlow 模型添加上多 GPU 卡运行的支持。 

2. 使用 TensorFlow 的 dataset API 为 TensorFlow 的 RNN 语言模型重写数据读取 部分,以提高 I/O 效率。 

请注意,这一篇我们主要关于 如何利用多 GPU 卡进行训练,请尽量在有多 块 GPU 卡的机器上运行本节示例。

如何使用代码

本篇文章配套有完整可运行的代码, 请随时从 github [1] 上获取最新代码。代码包括以下几个文件:

在执行训练任务前,请首先进入 data 文件夹,在终端执行下面的命令进行训练数据下载以及预处理。

sh download.sh

在终端运行以下命令便可以使用默认结构和默认参数运行 PaddleFluid 训练序列标注模型。

python train_fluid_model.py

在终端运行以下命令便可以使用默认结构和默认参数运行 TensorFlow 训练序列标注模型。

python train_tf_model.py数据并行与模型并行

这一篇我们仅考虑单机多设备情况,暂不考虑网络中的不同计算机。当我们单机上有多种计算设备(包括 CPU,多块不同的 GPU 卡),我们希望能够充分利用这些设备一起完成训练任务,常用的并行方式分为三种:  

模型并行( model parallelism ):不同设备(GPU/CPU 等)负责网络模型的不同部分 例如,神经网络模型的不同网络层被分配到不同的设备,或者同一层内部的不同参数被分配到不同设备。 

  • 每个设备都只有一部分 模型;不同设备之间会产生通信开销 ;

 

  • 神经网络的计算本身有一定的计算依赖,如果计算本身存在依赖无法并行进行,不同设备之间可能会产生等待。

数据并行( data parallelism ):不同的设备有同一个模型的多个副本,每个设备分配到不同的数据,然后将所有机器的计算结果按照某种方式合并。 

  • 每个计算设备都有一份完整的模型各自计算,指定某个设备作为 controller,将多个设备的计算结果进行合并;

 

  • 在神经网络中,通常需要合并的是多个设备计算的梯度,梯度合并后再进行 clipping,计算正则,计算更新量,更新参数等步骤;

     

  • 最大化计算效率的关键是尽可能降低串行避免计算设备的等待。 

混合并行(Hybrid parallelism):既有模型并行,又有数据并行。 

模型并行往往使用在模型大到单个计算设备已经无法存储整个模型(包括模型本身和计算过程中产生的中间结果)的场景,或是模型在计算上天然就存在多个 没有强计算依赖的部分,那么很自然的可以将这些没有计算依赖的部分放在不同设备上并行地进行计算。

然而,随着计算设备的不断增多,模型并行较难以一种通用的可扩展的方法达到接近线性加速的效果。一方面如何重叠(overlap)计算开销与跨设备通信开销依赖于对系统硬件丰富的知识和经验,另一方面神经网络计算的依赖性 会让模型的拆分随着设备的增加越发困难。

数据并行中每一个设备都维护了完整的模型,与模型并行相比往往会耗费更多的存储空间。但数据并行的优点是:通用性很好,适用于所有可能的神经网络模型结构。同样地,随着设备数目的增加通信代价也会越来越高,一般情况下在 2~8 卡时依然可以做到接近线性加速比。

需要注意的是,随着越来越多设备的加入,数据并行会导致 batch size 增大,一个 epoch 内参数更新次数减少,往往都需要对学习率,学习率 decay 进行再调参,否则可能会引起学习效果的下降。 

鉴于在使用中的通用性和有效性,这一篇中我们主要介绍更加通用的数据并行方法。非常笼统的,数据并行遵从一下的流程,其中一个 | 代表一个计算设备:

|           1. 将模型参数拷贝到不同的设备
|           2. 对输入数据均匀切分到不同的计算设备
||||        3. 多个设备并行进行前向计算
||||        4. 多个设备形象进行反向计算
|           5. 多个设备计算的梯度在主卡合并
|           6. 计算参数更新量,更新参数
|           to 1
PaddleFluid使用多GPU卡进行训练

在 PaddleFluid 中使用多个 GPU 卡以数据并行的方式训练需要引入 parallel_do 原语。顾名思义, parallel_do 会负责数据的切分,在多个设备上并行地执行一段相同的计算,最后合并计算结果。

与 ParallelDo 函数功能相近的函数还有 ParallelExecutor,大家也可以自行尝试一下。ParallelExecutor 的具体使用方式可以参考 API 文档:

http://www.paddlepaddle.org/docs/develop/api/fluid/en/executor.html

图 1 是 parallel_do 的原理示意图: 

▲ 图1. PaddleFluid中的Parallel do

下面我们来看看如何使用 parallel_do 让我们在第三篇中实现的 RNN LM 可在多个 GPU 上训练 ,下面是核心代码片段,完整代码请参考 rnnlm_fluid.py。

places = fluid.layers.get_places()
pd = fluid.layers.ParallelDo(places)with pd.do():word_ = pd.read_input(word)lbl_ = pd.read_input(lbl)prediction, cost = self.__network(word_, lbl_)pd.write_output(cost)pd.write_output(prediction)cost, prediction = pd()
avg_cost = fluid.layers.mean(x=cost)

调用 places = fluid.layers.get_places() 获取所有可用的计算设备 。可以通过设置 CUDA_VISIBLE_DEVICES 来控制可见 GPU 的数据。 

 pd = fluid.layers.ParallelDo(places) 指定将在 那些设备上并行地执行。 

 parallel_do 会构建一段 context,在其中定义要并行执行的计算,调用 pd.read_input 切分输入数据,在 parallel_do 的 context 之外调用 pd() 获取合并后的最终计算结果。

with pd.do():x_ = pd.read_input(x)  # 切分输入数据 xy_ = pd.read_input(y)  # 切分输入数据 y# 定义网络cost = network(x_, y_)pd.write_output(cost)
cost = pd()  # 获取合并后的计算结果
TensorFlow中使用多GPU卡进行训练

在 TensorFlow 中,通过调用 with tf.device() 创建一段 device context,在这段 context 中定义所需的计算,那么这 些计算将运行在指定的设备上。 

TensorFlow 中实现多卡数据并行有多种方法,常用的包括单机 ParameterServer 模式;Tower 模式 [2],甚至也 可以使用最新的 nccl [3] all reduce 系列 op 来实现梯度的聚合。这里我们以 Tower 模式为基础,介绍一种简单易用的多 GPU 上的数据并行方式。下面是核心代码片段,完整代码请参考 rnnlm_tensorflow.py。

def make_parallel(fn, num_gpus, **kwargs):in_splits = {}for k, v in kwargs.items():in_splits[k] = tf.split(v, num_gpus)out_split = []for i in range(num_gpus):with tf.device(tf.DeviceSpec(device_type="GPU", device_index=i)):with tf.variable_scope(tf.get_variable_scope(), reuse=tf.AUTO_REUSE):out_i = fn(**{k: v[i] for k, v in in_splits.items()})out_split.append(out_i)return tf.reduce_sum(tf.add_n(out_split)) / tf.to_float(self.batch_size)

 make_parallel 的第一个参数是一个函数,也就是我们自己定义的如何创建神经网络模型函数。第二个参数指定 GPU 卡数,数据将被平均地分配给这些 GPU。除此之外的参数将以 keyword argument 的形式传入,是神经网络的输入层 Tensor 。 

在定义神经网络模型时,需要创建 varaiable_scope ,同时指定 reuse=tf.AUTO_REUSE ,保证多个 GPU 卡上的可学习参数会是共享的。 

 make_parallel 中使用 tf.split op 对输入数据 Tensor 进行切分,使用 tf.add_n 合并多个 GPU 卡上的计算结果。

一些情况下同样可以使用 tf.concat 来合并多个卡的结算结果,这里因为使用了 dataset api 为dynamic rnn feed 数据,在定义计算图时 batch_size 和 max_sequence_length 均不确定,无法使用 tf.concat 。 

下面是对 make_parallel 的调用,从中可看到如何使用 make_parallel 方法。

self.cost = self.make_parallel(self.build_model,len(get_available_gpus()),curwd=curwd,nxtwd=nxtwd,seq_len=seq_len)

除了调用 make_parallel 之外,还有一处修改需要注意:在定义优化方法时,需要将colocate_gradients_with_ops 设置为 True,保证前向 Op 和反向 Op 被放置在相同的设备上进行计算。

optimizer.minimize(self.cost, colocate_gradients_with_ops=True)
总结

如何利用多个 GPU 卡进行训练对复杂模型或是大规模数据集上的训练任务往往是必然的选择。鉴于在使用中的有效性和通用性,这一节我们主要介绍了在 PaddleFluid 和 TensorFlow 上通过数据并行使用多个 GPU 卡最简单的方法。

这一篇所有可运行的例子都可以在 04_rnnlm_data_parallelism [4] 找到,更多实现细节请参考具体的代码。值得注意的是,不论是 PaddleFluid 还是 TensorFlow 都还有其他多种利用多计算设备提高训练并行度的方法。请大家随时关注官方的最新文档。

参考文献

[1]. 本文配套代码

https://github.com/JohnRabbbit/TF2Fluid/tree/master/04_rnnlm_data_parallelism

[2]. Tower模式 

https://github.com/tensorflow/models/blob/master/tutorials/image/cifar10/cifar10_multi_gpu_train.py

[3]. nccl

https://www.tensorflow.org/api_docs/python/tf/contrib/nccl

[4]. 04_rnnlm_data_parallelism

https://github.com/JohnRabbbit/TF2Fluid/tree/master/04_rnnlm_data_parallelism


推荐阅读
  • 本文由公众号【数智物语】(ID: decision_engine)发布,关注获取更多干货。文章探讨了从数据收集到清洗、建模及可视化的全过程,介绍了41款实用工具,旨在帮助数据科学家和分析师提升工作效率。 ... [详细]
  • 学习Linux下使用caffe进行模型训练(三)
    前言不管是训练过程中,查看网络学习的状态,还是训练结束后,使用模型去执行特定任务,都需要一个可被观察的输出呈现在研究者面前,最好是可视化的图形而非冰冷的数字。因此,本次讲的是通过c ... [详细]
  • 本文介绍了基于Java的在线办公工作流系统的毕业设计方案,涵盖了MyBatis框架的应用、源代码分析、调试与部署流程、数据库设计以及相关论文撰写指导。 ... [详细]
  • 本文详细探讨了编程中的命名空间与作用域概念,包括其定义、类型以及在不同上下文中的应用。 ... [详细]
  • 探索CNN的可视化技术
    神经网络的可视化在理论学习与实践应用中扮演着至关重要的角色。本文深入探讨了三种有效的CNN(卷积神经网络)可视化方法,旨在帮助读者更好地理解和优化模型。 ... [详细]
  • 利用Docker部署JupyterHub以支持Python协同开发
    本文介绍了如何通过Docker容器化技术安装和配置JupyterHub,以实现多用户的Python开发环境,特别适合团队协作场景。 ... [详细]
  • 本文详细介绍了Apache Spark 2.2.0版本中集群模式的基本概念和工作流程,包括如何通过集群管理器分配资源,以及Spark应用程序在集群中的运行机制。链接:http://spark.apache.org/docs/2.2.0/cluster-overview.html ... [详细]
  • 精选10款Python框架助力并行与分布式机器学习
    随着神经网络模型的不断深化和复杂化,训练这些模型变得愈发具有挑战性,不仅需要处理大量的权重,还必须克服内存限制等问题。本文将介绍10款优秀的Python框架,帮助开发者高效地实现分布式和并行化的深度学习模型训练。 ... [详细]
  • 新浪微博热搜暂停更新;即刻APP回归;Android 11 Beta版发布 | 科技新闻速递
    为您带来最新的科技资讯,涵盖社交媒体动态、软件更新及行业重大事件。CSDN携手您共同关注科技前沿。 ... [详细]
  • 机器学习(ML)三之多层感知机
    深度学习主要关注多层模型,现在以多层感知机(multilayerperceptron,MLP)为例,介绍多层神经网络的概念。隐藏层多层感知机在单层神经网络的基础上引入了一到多个隐藏 ... [详细]
  • Flutter 核心技术与混合开发模式深入解析
    本文深入探讨了 Flutter 的核心技术,特别是其混合开发模式,包括统一管理模式和三端分离模式,以及混合栈原理。通过对比不同模式的优缺点,帮助开发者选择最适合项目的混合开发策略。 ... [详细]
  • 本文介绍了如何使用 Google Colab 的免费 GPU 资源进行深度学习应用开发。Google Colab 是一个无需配置即可使用的云端 Jupyter 笔记本环境,支持多种深度学习框架,并且提供免费的 GPU 计算资源。 ... [详细]
  • 本文档涵盖了多个 Python 编程练习题,包括使用 while 和 for 循环处理数字序列、字符串操作以及简单的算法实现等。每道题目都提供了详细的代码示例,旨在帮助初学者加深对 Python 基础知识的理解。 ... [详细]
  • LeetCode 实战:寻找三数之和为零的组合
    给定一个包含 n 个整数的数组,判断该数组中是否存在三个元素 a、b、c,使得 a + b + c = 0。找出所有满足条件且不重复的三元组。 ... [详细]
  • 目录预备知识导包构建数据集神经网络结构训练测试精度可视化计算模型精度损失可视化输出网络结构信息训练神经网络定义参数载入数据载入神经网络结构、损失及优化训练及测试损失、精度可视化qu ... [详细]
author-avatar
不雅cf居
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有