Tensorflow 多 GPU 训练

2023-05-16

介绍

TensorFlow中的并行主要分为模型并行和数据并行。 模型并行需要根据不同模型设计不同的并行方式, 其主要原理是将模型中不同计算节点放在不同硬件资源上运算。 比较通用的且能简便地实现大规模并行的方式是数据并行, 其思路我们在第1章讲解过, 是同时使用多个硬件资源来计算不同batch的数据的梯度, 然后汇总梯度进行全局的参数更新。

数据并行又分为同步和异步,同步训练是指等所有GPU得到梯度后统一更新梯度,异步训练是每当有GPU得到梯度就更新网络权重。

这里使用数据并行的同步训练方法,大致如下:

  1. 先定义 batch 数,学习率衰减,优化方法等
  2. 分别为机器上所有的GPU定义模型,得到损失及梯度,使用reuse_variables,它们共享网络的参数值
  3. 保存所有GPU的梯度,得到平均值
  4. 根据定义的优化方法及平均梯度,优化模型

示例代码

import os.path
import re
import time
import numpy as np
import tensorflow as tf
import cifar10


batch_size = 128
max_steps = 1000000
num_gpus = 4


def tower_loss(scope):
    '''计算单个设备的所有损失
    
    参数:
        scope:设备的唯一编号
        
    返回值:
        批数据损失的tensor
    '''
    
    image, labels = cifar10.distorted_inputs()
    # 构建模型,获取logit
    logits = cifar10.inference(image)
    
    _ = cifar10.loss(logits, labels)
    # 搜集当前设备的损失
    losses = tf.get_collection('losses', scope)
    # 计算总损失
    total_loss = tf.add_n(losses, name='total_loss')
    
    return total_loss

def average_gradients(tower_grads):
    '''将搜集到的所有设备的梯度 tower_grads 取平均值后作为网络更新梯度
    
    参数: 
        tower_grads: shape 为 [[(grad0_gpu0,var0_gpu0),(grad1_gpu0,var1_gpu0),...],[...]]
        第一个维度为GPU各自的梯度
        第二个维度为GPU所有的变量梯度
        第三个维度是一个tuple,保存参数梯度grad0_gpu0,及参数值var0_gpu0
        
    返回值:
        所有GPU梯度的平均值及变量值,形状为输入参数的前2个维度
        
    操作:
        1、将梯度转置,方便获取所有GPU的同一个变量的同一个梯度
        2、将梯度拓展一个维度,加入list中
        3、合并列表取平均值
        4、获取变量var,与平均梯度一起返回
        
    '''
    average_grads = []
    for grad_and_vars in zip(*tower_grads):
        grads = []
        for g, _ in grad_and_vars:
            expanded_g = tf.expand_dims(g, 0)
            grads.append(expanded_g)
        
        grad = tf.concat(grads, 0)
        grad = tf.reduce_mean(grad, 0)
        
        v = grad_and_vars[0][1]
        grad_and_var = (grad, v)
        
        average_grads.append(grad_and_var)
        
        return average_grads


def train():
    '''训练函数
    
    步骤:
    1、先使用CPU进行一些简单的计算,比如global_step,学习率的衰减
    2、对每一个GPU,使用tower_loss计算自己的损失
    3、调用tf.get_variable_scope().reuse_variables(),使得所有GPU使用同样的参数
    4、计算平均损失,并更新
    
    疑问:
    1、网络是怎样在GPU之间复制的        tower_loss 函数已经创建网络并定义损失
    2、每个GPU怎样获取到自己的数据       tower_loss 函数里包含获取批次数据代码
    3、每个GPU怎样更新网络的权重        多个GPU共用一个Sess,因此使用一样的apply_gradients即可
    4、每个GPU怎样保持一样的权重        reuse_variables 函数使得GPU之间复用权重
    5、start_queue_runners 是做什么用的 准备好大量的数据增强后的样本
    '''
    
    # 全局训练步数
    with tf.Graph().as_default(), tf.device('/cpu:0'):
        global_step = tf.get_variable('global_step', [], 
                                      initializer=tf.constant_initializer(0),
                                      trainable=False)
        
        num_batches_per_epoch = cifar10.NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN / batch_size
        decay_step = int(num_batches_per_epoch * cifar10.NUM_EPOCHS_PER_DECAY)
        
        # 衰减学习率计算
        lr = tf.train.exponential_decay(cifar10.INITIAL_LEARNING_RATE,
                                        global_step,
                                        decay_step,
                                        cifar10.LEARNING_RATE_DECAY_FACTOR,
                                        staircase=True)
        
        opt = tf.train.GradientDescentOptimizer(lr)
        
        # 对每个GPU 使用tower_loss 构建模型,计算损失
        tower_grads = []
        for i in range(num_gpus):
            with tf.device('/gpu:%d' % i):
                with tf.name_scope('%s_%d' % (cifar10.TOWER_NAME, i)) as scope:
                    loss = tower_loss(scope)
                    # GPU共享参数
                    tf.get_variable_scope().reuse_variables() 
                    grads = opt.compute_gradients(loss)
                    tower_grads.append(grads)
            
        # 获取平均梯度并更新
        grads = average_gradients(tower_grads)
        apply_gradient_op = opt.apply_gradients(grads, global_step=global_step)
        
        # 初始化变量,创建Session
        saver = tf.train.Saver(tf.all_variables())
        init = tf.global_variables_initializer()
        sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True))
        sess.run(init)
        tf.train.start_queue_runners(sess=sess) # ?
        
        # 开始训练并保存数据
        for step in range(max_steps):
            start_time = time.time()
            
            _, loss_value = sess.run([apply_gradient_op, loss])
            duration = time.time() - start_time
            
            if step % 10 == 0:
                num_examples_per_step = batch_size * num_gpus
                examples_per_sec = num_examples_per_step / duration
                sec_per_batch = duration / num_gpus
                
                format_str = ('step %d, loss = %.2f (%.1f examples/sec; %.3f sec/batch)')
                print(format_str % (step, loss_value, examples_per_sec, sec_per_batch))
                
            if step % 1000 == 0 or (step + 1) == max_steps:
                saver.save(sess, './cifar10_train/model.ckpt', global_step=step)
                
cifar10.maybe_download_and_extract()
train()
步骤:
1、先使用CPU进行一些简单的计算,比如global_step,学习率的衰减
2、对每一个GPU,使用tower_loss计算自己的损失
3、调用tf.get_variable_scope().reuse_variables(),使得所有GPU使用同样的参数
4、计算平均损失,并更新

疑问:
1、网络是怎样在GPU之间复制的        tower_loss 函数已经创建网络并定义损失
2、每个GPU怎样获取到自己的数据       tower_loss 函数里包含获取批次数据代码
3、每个GPU怎样更新网络的权重        多个GPU共用一个Sess,因此使用一样的apply_gradients即可
4、每个GPU怎样保持一样的权重        reuse_variables 函数使得GPU之间复用权重
5、start_queue_runners 是做什么用的 准备好大量的数据增强后的样本

其他比如 cifar10.py 的代码参考这里https://github.com/yhlleo/tensorflow.cifar10

参考

《Tensorflow实战》 9.2 多GPU并行

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Tensorflow 多 GPU 训练 的相关文章

随机推荐

  • 使用CANAPE脚本script周期性发送报文

    1 新建一个drive 选择devices选项卡中的device configuration 选择device菜单 xff0c new一个新驱动CAN 名称可自定义 Next 配置通道 xff0c 导入DBC Next 选择CANAPE对应
  • 【图像处理】MATLAB:基本原理

    前言 兜兜转转 xff0c 越发意识到夯实基础的重要性 不积跬步无以至千里 xff0c 想要深入学习图像处理 xff0c 就得安下心来踏实学习 xff0c 掌握基本理论知识 xff0c 切不可再得过且过 吊儿郎当 谨记两个词 刻苦 创新 x
  • 【Kalman】卡尔曼滤波Matlab简单实现

    本节卡尔曼滤波Matlab实现是针对线性系统估计的 xff0c 仅为简单仿真 1 离散时间线性动态系统的状态方程 线性系统采用状态方程 观测方程及其初始条件来描述 线性离散时间系统的一般状态方程可描述为 其中 xff0c X k 是 k 时
  • 安装Airsim并在Airsim仿真环境下进行DDPG DQN强化学习算法无人机训练

    微软开源了基于虚幻4引擎的一款用于模拟无人机飞行的工具AirSim 用户可以用在虚幻引擎下模拟无人机的飞行并进行数据采集 非常适合做视觉算法的测试以及仿真环境的训练等等 xff0c 下面介绍如何快速使用次仿真环境完成project的运行和使
  • Android面试专题 (十一):显式Intent & 隐式Intent

    面试官 xff1a 来 xff0c 说一下Android中的显式Intent 和 隐式Intent吧 xff01 嗯 xff0c 乍一听觉得这么简单你让我说什么呢 xff1f 但是 xff0c 没办法 xff0c 面试往往面的就是基础不是嘛
  • Java设计模式 | 观察者模式解析与实战

    概述 观察者模式是一个使用率非常高的模式 xff0c 它最常用的地方是 GUI 系统 订阅 发布系统 这个模式的一个重要作用就是解耦 xff0c 将被观察者和观察者解耦 xff0c 使得它们之间的依赖性更小 xff0c 甚至做到毫无依赖 以
  • ISO 26262中的ASIL等级确定与分解

    ISO 26262中的ASIL等级确定与分解 1 引言 汽车上电子 电气系统 xff08 E E xff09 数量不断的增加 xff0c 一些高端豪华轿车上有多达70多个ECU xff08 Electronic Control Unit电子
  • 数字电路符号整理

    0 常见的数字电路符号 1 D触发器 这个就是D触发器的示意图 其中 xff0c clk为时钟 xff0c rst n为复位 xff0c d为输入 xff0c q为输出 这个功能非常简单 xff0c 复位有效的时候 xff0c 这个q的值你
  • 进程优先级详解(prio、static_prio、normal_prio、rt_priority)

    Linux 中采用了两种不同的优先级范围 xff0c 一种是 nice 值 xff0c 一种是实时优先级 在上一篇粗略的说了一下 nice 值和实时优先级 xff0c 仍有不少疑问 xff0c 本文来详细说明一下进程优先级 linux 内核
  • C++中struct和class

    在C 43 43 中我们可以看到struct和class的区别并不是很大 xff0c 两者之间有很大的相似性 那么为什么还要保留struct 这是因为C 43 43 是向下兼容的 xff0c 因此C 43 43 中保留了很多C的东西 一 首
  • Linux中的进程栈和线程栈

    转载自 xff1a Linux中的进程栈和线程栈 知乎 1 进程栈 进程栈是属于用户态栈 xff0c 和进程虚拟地址空间 Virtual Address Space 密切相关 那我们先了解下什么是虚拟地址空间 xff1a 在 32 位机器下
  • Linux内存管理(二):PTMalloc

    1 ptmalloc简介 2 内存管理数据结构 3 内存分配 4 内存回收 5 配置选项 6 注意事项 1 ptmalloc简介 Linux 中 malloc 的早期版本是由 Doug Lea 实现的 xff0c 它有一个重要问题就是在并行
  • P问题、NP问题、NP完全问题和NP难问题

    在讲P类问题之前先介绍两个个概念 xff1a 多项式 xff0c 时间复杂度 知道这两概念的可以自动跳过这部分 1 多项式 xff1a axn bxn 1 43 c 恩 就是长这个样子的 xff0c 叫x最高次为n的多项式 咳咳 xff0c
  • 电容基本知识

    旁路电容 xff0c 耦合电容 xff0c 电容不同类型的使用范围 在模拟和数字PCB设计中 xff0c 旁路或去耦电容 0 1uF 应尽量靠近器件 放置 供电电源去耦电容 10uF 应放置在电路板的电源线入口处 所有情 况下 xff0c
  • 最长递增子序列的三种算法

    转载自 xff1a http qiemengdao iteye com blog 1660229 最长递增子序列 问题 给定一个长度为N的数组 xff0c 找出一个最长的单调自增子序列 xff08 不一定连续 xff0c 但是顺序不能乱 x
  • 树莓派手动指定静态IP和DNS 终极解决大法

    在把玩树莓派的过程中 xff0c 往往需要手动给它设定一个静态的IP地址 xff0c 一来可以防范DHCP自动分配的IP来回变动 xff0c 导致远程SSH时常无法连接 xff1b 二来还可以提高树莓派的网络连接速度 对此菲菲君在网上查了很
  • Anroid面试专题(十二):图片大小的优化 及 三级缓存

    面试官 xff1a 你在项目中处理过图片吗 xff0c 说一下你是如何对它做优化的 xff0c 及三级缓存是什么 xff1f 我们可以这样一步一步来回答 xff1a 1 一张图的大小是怎么计算的 要回答这个问题 xff0c 我们要先从图片说
  • UART和RS232/RS485的关系是什么?

    串口通讯是电子工程师和嵌入式开发工程师面对的最基本问题 xff0c RS232则是其中最简单最常用的通讯方式 但是初学者往往搞不清有关的名词如UART和RS232或RS485之间是什么关系 xff0c 因为它们经常被放到语句中同等的位置使用
  • TensorBoard的使用

    介绍 使用 Tensorboard 是TF 的可视化工具 xff0c 它通过对Tensoflow程序运行过程中输出的日志文件进行可视化Tensorflow程序的运行状态 xff0c 如下所示 SCALARS 对标量数据进行汇总和记录 使用方
  • Tensorflow 多 GPU 训练

    介绍 TensorFlow中的并行主要分为模型并行和数据并行 模型并行需要根据不同模型设计不同的并行方式 xff0c 其主要原理是将模型中不同计算节点放在不同硬件资源上运算 比较通用的且能简便地实现大规模并行的方式是数据并行 xff0c 其