用GPU进行TensorFlow计算加速
小编说:将深度学习应用到实际问题中,一个非常大的问题在于训练深度学习模型需要的计算量太大。为了加速训练过程,本文将介绍如何如何在TensorFlow中使用单个GPU进行计算加速,也将介绍生成TensorFlow会话(tf.Session)时的一些常用参数。通过这些参数可以使调试更加方便而且程序的可扩展性更好。本文选自《TensorFlow:实战Google深度学习框架(第2版)》。
TensorFlow程序可以通过tf.device函数来指定运行每一个操作的设备,这个设备可以是本地的CPU或者GPU,也可以是某一台远程的服务器。但在本文中只关心本地的设备。TensorFlow会给每一个可用的设备一个名称,tf.device函数可以通过设备的名称来指定执行运算的设备。比如CPU在TensorFlow中的名称为/cpu:0。在默认情况下,即使机器有多个CPU,TensorFlow也不会区分它们,所有的CPU都使用/cpu:0作为名称。而一台机器上不同GPU的名称是不同的,第n个GPU在TensorFlow中的名称为/gpu:n。比如第一个GPU的名称为/gpu:0,第二个GPU名称为/gpu:1,以此类推。
TensorFlow提供了一个快捷的方式来查看运行每一个运算的设备。在生成会话时,可以通过设置log_device_placement参数来打印运行每一个运算的设备。以下程序展示了如何使用log_device_placement这个参数。
import tensorflow as tfa = tf.constant([1.0, 2.0, 3.0], shape=[3], name='a')
b = tf.constant([1.0, 2.0, 3.0], shape=[3], name='b')
c = a + b
# 通过log_device_placement参数来输出运行每一个运算的设备。
sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
print sess.run(c)'''
在没有GPU的机器上运行以上代码可以得到类似以下的输出:
Device mapping: no known devices.add: (Add): /job:localhost/replica:0/task:0/cpu:0
b: (Const): /job:localhost/replica:0/task:0/cpu:0
a: (Const): /job:localhost/replica:0/task:0/cpu:0
[ 2. 4. 6.]
'''
在以上代码中,TensorFlow程序生成会话时加入了参数log_device_placement=True,所以程序会将运行每一个操作的设备输出到屏幕。于是除了可以看到最后的计算结果,还可以看到类似“add: /job:localhost/replica:0/task:0/cpu:0”这样的输出。这些输出显示了执行每一个运算的设备。比如加法操作add是通过CPU来运行的,因为它的设备名称中包含了/cpu:0。
在配置好GPU环境的TensorFlow中,如果操作没有明确地指定运行设备,那么TensorFlow会优先选择GPU。比如将以上代码在亚马逊(Amazon Web Services, AWS)的 g2.8xlarge实例上运行时,会得到类似以下的运行结果。
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GRID K520, pci bus id: 0000:00:03.0
/job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GRID K520, pci bus id: 0000:00:04.0
/job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: GRID K520, pci bus id: 0000:00:05.0
/job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: GRID K520, pci bus id: 0000:00:06.0add: (Add): /job:localhost/replica:0/task:0/gpu:0
b: (Const): /job:localhost/replica:0/task:0/gpu:0
a: (Const): /job:localhost/replica:0/task:0/gpu:0
[ 2. 4. 6.]
从以上输出可以看到在配置好GPU环境的TensorFlow中,TensorFlow会自动优先将运算放置在GPU上。不过,尽管g2.8xlarge实例有4个GPU,在默认情况下,TensorFlow只会将运算优先放到/gpu:0上。于是可以看见在以上程序中,所有的运算都被放在了/gpu:0上。如果需要将某些运算放到不同的GPU或者CPU上,就需要通过tf.device来手工指定。以下程序给出了一个通过tf.device手工指定运行设备的样例。
import tensorflow as tf# 通过tf.device将运算指定到特定的设备上。
with tf.device('/cpu:0'):a = tf.constant([1.0, 2.0, 3.0], shape=[3], name='a')b = tf.constant([1.0, 2.0, 3.0], shape=[3], name='b')with tf.device('/gpu:1'):c = a + bsess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
print sess.run(c)'''
在AWS g2.8xlarge实例上运行上述代码可以得到以下结果:
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GRID K520, pci bus id: 0000:00:03.0
/job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GRID K520, pci bus id: 0000:00:04.0
/job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: GRID K520, pci bus id: 0000:00:05.0
/job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: GRID K520, pci bus id: 0000:00:06.0add: (Add): /job:localhost/replica:0/task:0/gpu:1
b: (Const): /job:localhost/replica:0/task:0/cpu:0
a: (Const): /job:localhost/replica:0/task:0/cpu:0
[ 2. 4. 6.]
'''
在以上代码中可以看到生成常量a和b的操作被加载到了CPU上,而加法操作被放到了第二个GPU“/gpu:1”上。在TensorFlow中,不是所有的操作都可以被放在GPU上,如果强行将无法放在GPU上的操作指定到GPU上,那么程序将会报错。以下代码给出了一个报错的样例。
import tensorflow as tf# 在CPU上运行tf.Variable
a_cpu = tf.Variable(0, name="a_cpu")with tf.device('/gpu:0'):# 将tf.Variable强制放在GPU上。a_gpu = tf.Variable(0, name="a_gpu")sess = tf.Session(config=tf.ConfigProto(log_device_placement=True))
sess.run(tf.initialize_all_variables())'''
运行以上程序将会报出以下错误:
tensorflow.python.framework.errors.InvalidArgumentError: Cannot assign a device to node 'a_gpu': Could not satisfy explicit device specification '/device:GPU:0' because no supported kernel for GPU devices is available.
Colocation Debug Info:
Colocation group had the following types and devices:
Identity: CPU
Assign: CPU
Variable: CPU
[[Node: a_gpu = Variable[container="", dtype=DT_INT32, shape=[], shared_ name="", _device="/device:GPU:0"]()]]
'''
不同版本的TensorFlow对GPU的支持不一样,如果程序中全部使用强制指定设备的方式会降低程序的可移植性。在TensorFlow的kernel中定义了哪些操作可以跑在GPU上。比如可以在variable_ops.cc程序中找到以下定义。
# define REGISTER_GPU_KERNELS(type) \REGISTER_KERNEL_BUILDER( \Name("Variable").Device(DEVICE_GPU).TypeConstraint<type>("dtype"),\VariableOp); \…
TF_CALL_GPU_NUMBER_TYPES(REGISTER_GPU_KERNELS);
在这段定义中可以看到GPU只在部分数据类型上支持tf.Variable操作。如果在TensorFlow代码库中搜索调用这段代码的宏TF_CALL_GPU_NUMBER_TYPES,可以发现在GPU上,tf.Variable操作只支持实数型(float16、float32和double)的参数。而在报错的样例代码中给定的参数是整数型的,所以不支持在GPU上运行。为避免这个问题,TensorFlow在生成会话时可以指定allow_soft_placement参数。当allow_soft_placement参数设置为True时,如果运算无法由GPU执行,那么TensorFlow会自动将它放到CPU上执行。以下代码给出了一个使用allow_soft_placement参数的样例。
import tensorflow as tfa_cpu = tf.Variable(0, name="a_cpu")
with tf.device('/gpu:0'):a_gpu = tf.Variable(0, name="a_gpu")# 通过allow_soft_placement参数自动将无法放在GPU上的操作放回CPU上。
sess = tf.Session(config=tf.ConfigProto(allow_soft_placement=True, log_device_ placement=True))
sess.run(tf.initialize_all_variables())'''
运行上面这段程序可以得到以下结果:
Device mapping:
/job:localhost/replica:0/task:0/gpu:0 -> device: 0, name: GRID K520, pci bus id: 0000:00:03.0
/job:localhost/replica:0/task:0/gpu:1 -> device: 1, name: GRID K520, pci bus id: 0000:00:04.0
/job:localhost/replica:0/task:0/gpu:2 -> device: 2, name: GRID K520, pci bus id: 0000:00:05.0
/job:localhost/replica:0/task:0/gpu:3 -> device: 3, name: GRID K520, pci bus id: 0000:00:06.0
a_gpu: /job:localhost/replica:0/task:0/cpu:0
a_gpu/read: /job:localhost/replica:0/task:0/cpu:0
a_gpu/Assign: /job:localhost/replica:0/task:0/cpu:0
init/NoOp_1: /job:localhost/replica:0/task:0/gpu:0
a_cpu: /job:localhost/replica:0/task:0/cpu:0
a_cpu/read: /job:localhost/replica:0/task:0/cpu:0
a_cpu/Assign: /job:localhost/replica:0/task:0/cpu:0
init/NoOp: /job:localhost/replica:0/task:0/gpu:0
init: /job:localhost/replica:0/task:0/gpu:0
a_gpu/initial_value: /job:localhost/replica:0/task:0/gpu:0
a_cpu/initial_value: /job:localhost/replica:0/task:0/cpu:0从输出的日志中可以看到在生成变量a_gpu时,无法放到GPU上的运算被自动调整到了CPU上(比如a_gpu和a_gpu/read),而可以被GPU执行的命令(比如a_gpu/initial_value)依旧由GPU执行。
'''
虽然GPU可以加速TensorFlow的计算,但一般来说不会把所有的操作全部放在GPU上。一个比较好的实践是将计算密集型的运算放在GPU上,而把其他操作放到CPU上。GPU是机器中相对独立的资源,将计算放入或者转出GPU都需要额外的时间。而且GPU需要将计算时用到的数据从内存复制到GPU设备上,这也需要额外的时间。TensorFlow可以自动完成这些操作而不需要用户特别处理,但为了提高程序运行的速度,用户也需要尽量将相关的运算放在同一个设备上。
TensorFlow默认会占用设备上的所有GPU以及每个GPU的所有显存。如果在一个TensorFlow程序中只需要使用部分GPU,可以通过设置CUDA_VISIBLE_DEVICES环境变量来控制。以下样例介绍了如何在运行时设置这个环境变量。
# 只使用第二块GPU(GPU编号从0开始)。在demo_code.py中,机器上的第二块GPU的
# 名称变成/gpu:0,不过在运行时所有/gpu:0的运算将被放在第二块GPU上。
CUDA_VISIBLE_DEVICES=1 python demo_code.py
# 只使用第一块和第二块GPU。
CUDA_VISIBLE_DEVICES=0,1 python demo_code.py
TensorFlow也支持在程序中设置环境变量,以下代码展示了如何在程序中设置这些环境变量。
import os# 只使用第三块GPU。
os.environ["CUDA_VISIBLE_DEVICES"] = "2"
虽然TensorFlow默认会一次性占用一个GPU的所有显存,但是TensorFlow也支持动态分配GPU的显存,使得一块GPU上可以同时运行多个任务。下面给出了TensorFlow动态分配显存的方法。
config = tf.ConfigProto()# 让TensorFlow按需分配显存。config.gpu_options.allow_growth = True# 或者直接按固定的比例分配。以下代码会占用所有可使用GPU的40%显存。
# config.gpu_options.per_process_gpu_memory_fraction = 0.4
session = tf.Session(config=config, ...)
本文选自《TensorFlow:实战Google深度学习框架(第2版)》
用GPU进行TensorFlow计算加速相关推荐
- 深入浅出TensorFlow(七)TensorFlow计算加速
2017年2月16日,Google正式对外发布Google TensorFlow 1.0版本,并保证本次的发布版本API接口完全满足生产环境稳定性要求.这是TensorFlow的一个重要里程碑,标志着 ...
- 转 TensorFlow Object Detection API 多GPU 卡平行计算,加速模型训练速度教学
本篇记录如何使用多张GPU 显示卡,加速TensorFlow Object Detection API 模型训练的过程. 虽然TensorFlow Object Detection API 已经有支援 ...
- TensorFlow Object Detection API 多GPU 卡平行计算,加速模型训练速度教学
本篇记录如何使用多张GPU 显示卡,加速TensorFlow Object Detection API 模型训练的过程. 虽然TensorFlow Object Detection API 已经有支援 ...
- TensorFlow XLA加速编译器
TensorFlow XLA加速编译器 加速线性代数器(Accelerated linear algebra,XLA)是线性代数领域的专用编译器.根据 https://www.tensorflow.o ...
- 用NVIDIA Tensor Cores和TensorFlow 2加速医学图像分割
用NVIDIA Tensor Cores和TensorFlow 2加速医学图像分割 Accelerating Medical Image Segmentation with NVIDIA Tensor ...
- Win10安装GPU版tensorflow和keras
Win10安装GPU版tensorflow和keras 1.python安装 在此选用python3.7安装见详细教程https://blog.csdn.net/weixin_43545253/art ...
- 用Tensorflow计算距离矩阵
用Tensorflow计算距离矩阵 一般计算距离矩阵,都是用两层循环来做,这样效率太低.在样本维度上,距离矩阵的运算相互没有依赖关系,是可以做并行的.除了开多线程用CPU并行计算以外,还可以用GP ...
- 云知声 Atlas 超算平台: 基于 Fluid + Alluxio 的计算加速实践
Fluid 是云原生基金会 CNCF 下的云原生数据编排和加速项目,由南京大学.阿里云及 Alluxio 社区联合发起并开源.本文主要介绍云知声 Atlas 超算平台基于 Fluid + Alluxi ...
- FFmpeg在Intel GPU上的硬件加速与优化
英特尔提供了一套基于VA-API/Media SDK的硬件加速方案,通过在FFmpeg中集成Intel GPU的媒体硬件加速能力,为用户提供更多的收益.本文来自英特尔资深软件开发工程师赵军在LiveV ...
- 边缘计算加速视频直播场景:更清晰、流畅、实时
随着4G.5G网络技术的发展和智能手机的普及,网络直播逐渐成为了新媒体主要的传播方式,在社交娱乐.产品展示.政务公开.展会发布等领域被广泛使用. 面对全国不同城市.不同运营商的用户,如何保障视频直播清 ...
最新文章
- 图文并茂详解iptables 防火墙工作原理及知识点
- 【杂谈】2020年有三AI计算机视觉培养计划详解,该不该学怎么学CV的简单讨论...
- LeetCode 1550. 存在连续三个奇数的数组
- 游戏筑基开发之结构体定义动态数组及常见问题(C语言)
- Struts 2 之校验器
- 旧版sai笔刷_漂亮的sai笔刷大全(ps笔刷包) 简化中文版
- [BScroll warn]: Can not resolve the wrapper DOM.
- 2.4g和5g要不要合并_路由器2.4g和5g要不要合并?
- 程序员代码中的希腊字母表示
- 大佬给总结的单片机看门狗详解很有用
- Mac 上必备的常用软件,你值得拥有
- MySQL中Lob与JPA映射
- 2022东南大学网安916专硕上岸经验帖
- 新的篇章:来自鲍尔默和艾洛普的公开信
- Linux权限管理练习-->>神仙和妖怪
- 文件存储的实现-login登录案例2-sdcard
- MyBatis 集成MyBatisPlus
- 《Kubernetes与云原生应用》系列之Kubernetes的系统架构与设计理念
- python同花顺 财务_同花顺使用帮助之财务分析篇
- 解决java多继承问题
热门文章
- java day30【数据库连接池 、Spring JDBC : JDBC Template】
- 容器系列之虚拟化网络
- vue+element tree(树形控件)组件(1)
- ElasticStack系列之九 master、data 和 client 节点
- VBS基础篇 - 对象(5) - File对象
- 两本关于sharepoint 2010的书值得参考
- HP数组转JSON函数json_encode和JSON转数组json_decode函数的使用方法
- (转)增强学习(二)----- 马尔可夫决策过程MDP
- Center OS7网络设置
- 《疯狂Java讲义》(七)---- 方法