一、问题源起

从以下的异常堆栈可以看到是BLAS程序集初始化失败,可以看到是执行MatMul的时候发生的异常,基本可以断定可能数据集太大导致memory不够用了。

  1. 2021-08-10 16:38:04.917501: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED
  2. 2021-08-10 16:38:04.960048: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED
  3. 2021-08-10 16:38:04.986898: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED
  4. 2021-08-10 16:38:04.992366: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED
  5. 2021-08-10 16:38:04.992389: W tensorflow/stream_executor/stream.cc:1455] attempting to perform BLAS operation using StreamExecutor without BLAS support
  6. Traceback (most recent call last):
  7. File "/home/mango/PycharmProjects/DeepLearing/minist_conv.py", line 32, in <module>
  8. model.fit(train_images, train_labels, epochs=5, batch_size=64)
  9. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/keras/engine/training.py", line 1183, in fit
  10. tmp_logs = self.train_function(iterator)
  11. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/def_function.py", line 889, in __call__
  12. result = self._call(*args, **kwds)
  13. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/def_function.py", line 950, in _call
  14. return self._stateless_fn(*args, **kwds)
  15. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/function.py", line 3023, in __call__
  16. return graph_function._call_flat(
  17. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/function.py", line 1960, in _call_flat
  18. return self._build_call_outputs(self._inference_function.call(
  19. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/function.py", line 591, in call
  20. outputs = execute.execute(
  21. File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/execute.py", line 59, in quick_execute
  22. tensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,
  23. tensorflow.python.framework.errors_impl.InternalError: Blas xGEMM launch failed : a.shape=[1,64,576], b.shape=[1,576,64], m=64, n=64, k=576
  24. [[node sequential/dense/MatMul (defined at home/mango/PycharmProjects/DeepLearing/minist_conv.py:32) ]] [Op:__inference_train_function_993]
  25. Function call stack:
  26. train_function

二、开发环境

  1. mango@mango-ubuntu:~$ /usr/local/cuda/bin/nvcc --version
  2. nvcc: NVIDIA (R) Cuda compiler driver
  3. Copyright (c) 2005-2021 NVIDIA Corporation
  4. Built on Wed_Jul_14_19:41:19_PDT_2021
  5. Cuda~~ compilation tools, release 11.4, V11.4.100==
  6. Build cuda_11.4.r11.4/compiler.30188945_0
  7. mango@mango-ubuntu:~$ tail -n 10 /usr/include/cudnn_version.h
  8. #ifndef CUDNN_VERSION_H_
  9. #define CUDNN_VERSION_H_
  10. #define CUDNN_MAJOR 8
  11. #define CUDNN_MINOR 2
  12. #define CUDNN_PATCHLEVEL 2
  13. #define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)
  14. #endif /* CUDNN_VERSION_H */
  15. mango@mango-ubuntu:~$ python3 --version
  16. Python 3.9.5
  17. mango@mango-ubuntu:~$ nvidia-smi
  18. Tue Aug 10 19:57:58 2021
  19. +-----------------------------------------------------------------------------+
  20. | NVIDIA-SMI 470.57.02 Driver Version: 470.57.02 CUDA Version: 11.4 |
  21. |-------------------------------+----------------------+----------------------+
  22. | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
  23. | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
  24. | | | MIG M. |
  25. |===============================+======================+======================|
  26. | 0 NVIDIA GeForce ... Off | 00000000:01:00.0 Off | N/A |
  27. | N/A 54C P0 N/A / N/A | 329MiB / 2002MiB | 9% Default |
  28. | | | N/A |
  29. +-------------------------------+----------------------+----------------------+
  30. +-----------------------------------------------------------------------------+
  31. | Processes: |
  32. | GPU GI CI PID Type Process name GPU Memory |
  33. | ID ID Usage |
  34. |=============================================================================|
  35. | 0 N/A N/A 1818 G /usr/lib/xorg/Xorg 186MiB |
  36. | 0 N/A N/A 2002 G /usr/bin/gnome-shell 45MiB |
  37. | 0 N/A N/A 3435 G ...AAAAAAAAA= --shared-files 75MiB |
  38. | 0 N/A N/A 6016 G python3 13MiB |
  39. +-----------------------------------------------------------------------------+
  40. mango@mango-ubuntu:~$ python3
  41. Python 3.9.5 (default, May 11 2021, 08:20:37)
  42. [GCC 10.3.0] on linux
  43. Type "help", "copyright", "credits" or "license" for more information.
  44. >>> import tensorflow as tf
  45. 2021-08-10 18:33:05.917520: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0
  46. >>> tf.__version__
  47. '2.5.0'
  48. >>>

三、Tensorflow针对GPU内存的分配策略

By default, TensorFlow maps nearly all of the GPU memory of all GPUs (subject to CUDA_VISIBLE_DEVICES) visible to the process. This is done to more efficiently use the relatively precious GPU memory resources on the devices by reducing memory fragmentation.

默认情况下,为了通过减少内存碎片更有效地利用设备上相对宝贵的GPU内存资源,TensorFlow进程会使用所有可见的GPU。

In some cases it is desirable for the process to only allocate a subset of the available memory, or to only grow the memory usage as is needed by the process. TensorFlow provides two methods to control this.

在某些情况下,进程只分配可用内存的一个子集,或者只根据进程的需要增加内存使用量。TensorFlow提供了两种方法来控制这种情况。

The first option is to turn on memory growth by calling tf.config.experimental.set_memory_growth, which attempts to allocate only as much GPU memory as needed for the runtime allocations: it starts out allocating very little memory, and as the program gets run and more GPU memory is needed, the GPU memory region is extended for the TensorFlow process. Memory is not released since it can lead to memory fragmentation. To turn on memory growth for a specific GPU, use the following code prior to allocating any tensors or executing any ops.

第一种选择是通过调用tf.config.experimental.set_memory_growth来打开内存增长,它尝试只分配运行时所需的GPU内存:它开始分配很少的内存,当程序运行时需要更多的GPU内存时,GPU内存区域会进一步扩展增大。内存不会被释放,因为这会导致内存碎片。为了打开特定GPU的内存增长,在分配任何张量或执行任何操作之前,使用以下代码。

  1. gpus = tf.config.list_physical_devices('GPU')
  2. if gpus:
  3. try:
  4. # Currently, memory growth needs to be the same across GPUs
  5. for gpu in gpus:
  6. tf.config.experimental.set_memory_growth(gpu, True)
  7. logical_gpus = tf.config.list_logical_devices('GPU')
  8. print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
  9. except RuntimeError as e:
  10. # Memory growth must be set before GPUs have been initialized
  11. print(e)

Another way to enable this option is to set the environmental variable TF_FORCE_GPU_ALLOW_GROWTH to true. This configuration is platform specific.

启用该选项的另一种方法是将环境变量TF_FORCE_GPU_ALLOW_GROWTH设置为true。此配置是特定于平台的。

The second method is to configure a virtual GPU device with tf.config.experimental.set_virtual_device_configuration and set a hard limit on the total memory to allocate on the GPU.

This is useful if you want to truly bound the amount of GPU memory available to the TensorFlow process. This is common practice for local development when the GPU is shared with other applications such as a workstation GUI.

第二种方法是使用tf.config.experimental.set_virtual_device_configuration配置虚拟GPU设备,并设置GPU上可分配的总内存的硬限制。

如果你想真正将GPU内存的数量绑定到TensorFlow进程中,这是非常有用的。当GPU与其他应用程序(如工作站GUI)共享时,这是本地开发的常见做法。

  1. gpus = tf.config.list_physical_devices('GPU')
  2. if gpus:
  3. # Restrict TensorFlow to only allocate 1GB of memory on the first GPU
  4. try:
  5. tf.config.set_logical_device_configuration(
  6. gpus[0],
  7. [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
  8. logical_gpus = tf.config.list_logical_devices('GPU')
  9. print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
  10. except RuntimeError as e:
  11. # Virtual devices must be set before GPUs have been initialized
  12. print(e)

四、问题分析验证

通过上边对TensorFlow文档的分析,默认情况下会占用所有的GPU内存,但是TensorFlow提供了两种方式可以灵活的控制内存的分配策略;

我们可以直接设置GPU内存按需动态分配

  1. import tensorflow as tf
  2. physical_gpus = tf.config.list_physical_devices('GPU')
  3. tf.config.experimental.set_memory_growth(physical_gpus[0], True)

通过以下命令可以看到执行过程中GPU内存的占用最高为697M

  1. mango@mango-ubuntu:~$ while true; do nvidia-smi; sleep 0.2; done;
  2. Tue Aug 10 20:30:58 2021
  3. +-----------------------------------------------------------------------------+
  4. | NVIDIA-SMI 470.57.02 Driver Version: 470.57.02 CUDA Version: 11.4 |
  5. |-------------------------------+----------------------+----------------------+
  6. | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
  7. | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
  8. | | | MIG M. |
  9. |===============================+======================+======================|
  10. | 0 NVIDIA GeForce ... Off | 00000000:01:00.0 Off | N/A |
  11. | N/A 58C P0 N/A / N/A | 1026MiB / 2002MiB | 72% Default |
  12. | | | N/A |
  13. +-------------------------------+----------------------+----------------------+
  14. +-----------------------------------------------------------------------------+
  15. | Processes: |
  16. | GPU GI CI PID Type Process name GPU Memory |
  17. | ID ID Usage |
  18. |=============================================================================|
  19. | 0 N/A N/A 1818 G /usr/lib/xorg/Xorg 186MiB |
  20. | 0 N/A N/A 2002 G /usr/bin/gnome-shell 45MiB |
  21. | 0 N/A N/A 3435 G ...AAAAAAAAA= --shared-files 73MiB |
  22. | 0 N/A N/A 6016 G python3 13MiB |
  23. | 0 N/A N/A 13829 C /usr/bin/python3.9 697MiB |
  24. +-----------------------------------------------------------------------------+

我们也可以限制最多使用1024M的GPU内存

  1. import tensorflow as tf
  2. physical_gpus = tf.config.list_physical_devices('GPU')
  3. tf.config.set_logical_device_configuration(physical_gpus[0], [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])

同样通过命令可以看到执行过程中GPU内存的占用最高为1455M

  1. mango@mango-ubuntu:~$ while true; do nvidia-smi; sleep 0.2; done;
  2. Tue Aug 10 20:31:24 2021
  3. +-----------------------------------------------------------------------------+
  4. | NVIDIA-SMI 470.57.02 Driver Version: 470.57.02 CUDA Version: 11.4 |
  5. |-------------------------------+----------------------+----------------------+
  6. | GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
  7. | Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
  8. | | | MIG M. |
  9. |===============================+======================+======================|
  10. | 0 NVIDIA GeForce ... Off | 00000000:01:00.0 Off | N/A |
  11. | N/A 58C P0 N/A / N/A | 1784MiB / 2002MiB | 74% Default |
  12. | | | N/A |
  13. +-------------------------------+----------------------+----------------------+
  14. +-----------------------------------------------------------------------------+
  15. | Processes: |
  16. | GPU GI CI PID Type Process name GPU Memory |
  17. | ID ID Usage |
  18. |=============================================================================|
  19. | 0 N/A N/A 1818 G /usr/lib/xorg/Xorg 186MiB |
  20. | 0 N/A N/A 2002 G /usr/bin/gnome-shell 46MiB |
  21. | 0 N/A N/A 3435 G ...AAAAAAAAA= --shared-files 72MiB |
  22. | 0 N/A N/A 6016 G python3 13MiB |
  23. | 0 N/A N/A 13570 C /usr/bin/python3.9 1455MiB |
  24. +-----------------------------------------------------------------------------+

五、GPU分配策略分析

通过四中的测试结果可得

  1. 默认的分配策略会占用所有的内存,并且执行中不会进行释放,如果训练数据量比较打很容易内存不够用;
  2. 限制最大使用内存,测试占用内存比设置的大,这个可能跟训练中间使用的模型和操作的复杂程度有关系,需要根据具体的业务场景设置合适的值;但是要注意不能设置大了,否则还是会报错,但是设置小了只是执行的慢一些罢了;
  3. 设置内存按需分配可能是一个相对比较中庸的方案,感觉可能是一个更好的方案,不知道TensorFlow为什么没有设置为默认值,留作一个问题,后续有新的认知的话再补充;

六、扩展

单GPU模拟多GPU环境

当我们的本地开发环境只有一个GPU,但却需要编写多GPU的程序在工作站上进行训练任务时,TensorFlow为我们提供了一个方便的功能,可以让我们在本地开发环境中建立多个模拟GPU,从而让多GPU的程序调试变得更加方便。以下代码在实体GPU GPU:0 的基础上建立了两个显存均为2GB的虚拟GPU。

  1. gpus = tf.config.list_physical_devices('GPU')
  2. if gpus:
  3. # Create 2 virtual GPUs with 1GB memory each
  4. try:
  5. tf.config.set_logical_device_configuration(
  6. gpus[0],
  7. [tf.config.LogicalDeviceConfiguration(memory_limit=1024),
  8. tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
  9. logical_gpus = tf.config.list_logical_devices('GPU')
  10. print(len(gpus), "Physical GPU,", len(logical_gpus), "Logical GPUs")
  11. except RuntimeError as e:
  12. # Virtual devices must be set before GPUs have been initialized
  13. print(e)

多GPU的数据并行

使用 tf.distribute.Strategy可以将模型拷贝到每个GPU上,然后将训练数据分批在不同的GPU上执行,达到数据并行。

  1. tf.debugging.set_log_device_placement(True)
  2. gpus = tf.config.list_logical_devices('GPU')
  3. strategy = tf.distribute.MirroredStrategy(gpus)
  4. with strategy.scope():
  5. inputs = tf.keras.layers.Input(shape=(1,))
  6. predictions = tf.keras.layers.Dense(1)(inputs)
  7. model = tf.keras.models.Model(inputs=inputs, outputs=predictions)
  8. model.compile(loss='mse',
  9. optimizer=tf.keras.optimizers.SGD(learning_rate=0.2))

Tensorflow2对GPU内存的分配策略的更多相关文章

  1. 深入理解JVM(4)——对象内存的分配策略

    一.Java所承担的自动内存管理主要是针对对象内存的分配和回收. 二.在Java虚拟机的五块内存空间中,程序计数器.Java虚拟机栈.本地方法栈内存的分配和回收都具有确定性,一般在编译阶段就能确定需要 ...

  2. java内存的分配策略

    1.概述 本文是<深入理解java虚拟机>(周志明著)3.6节的笔记整理,文章结构也与书上相同,讲述的是几条最普遍的内存分配策略. 2.对象优先在Eden分配 ** 大多数情况下,对象在新 ...

  3. JVM内存分配策略

    在 JVM内存垃圾回收方法 中,我们已经详细讨论了内存回收,但是,我们程序中生成的对象是如何进行分配的呢?以下所述针对的是HotSpot虚拟机. 1.Java堆结构 以HotSpot为例,如下图: H ...

  4. java中内存分配策略及堆和栈的比较

    Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...

  5. Memcache 内存分配策略和性能(使用)状态检查

    前言: 一直在使用Memcache,但是对其内部的问题,如它内存是怎么样被使用的,使用一段时间后想看看一些状态怎么样?一直都不清楚,查了又忘记,现在整理出该篇文章,方便自己查阅.本文不涉及安装.操作. ...

  6. 深入理解java虚拟机(2)------垃圾收集器和内存分配策略

    GC可谓是java相较于C++语言,最大的不同点之一. 1.GC回收什么? 上一篇讲了内存的分布. 其中程序计数器栈,虚拟机栈,本地方法栈 3个区域随着线程而生,随着线程而死.这些栈的内存,可以理解为 ...

  7. 【转载】Ogre的内存分配策略

    原文:Ogre的内存分配策略 读这个之前,强烈建议看一下Alexandrescu的modern c++的第一章关于policy技术的解释.应该是这哥们发明的,这里只是使用. 首先列出涉及到的头文件:( ...

  8. GC之一--GC 的算法分析、垃圾收集器、内存分配策略介绍

    一.概述 垃圾收集 Garbage Collection 通常被称为“GC”,它诞生于1960年 MIT 的 Lisp 语言,经过半个多世纪,目前已经十分成熟了. jvm 中,程序计数器.虚拟机栈.本 ...

  9. JVM学习总结四——内存分配策略

    之前几篇我们介绍了jvm的内存模型以及垃圾回收机制,而本篇我们将介绍几个JVM中对象在分配内存是应该遵循的策略.毕竟,想要去优化程序,不仅要考虑垃圾回收的过程,还要从对象内存分配的角度减少gc的代价. ...

随机推荐

  1. 渗透测试工具Burpsuite操作教程

    Burpsuite简介 Burp Suite 是一款专业的Web和移动应用程序渗透测试工具,是用于攻击web 应用程序的集成平台,包含了许多工具.Burp Suite为这些工具设计了许多接口,以加快攻 ...

  2. 4、git和gitlab的配置(1)

    4.0.服务器说明: 服务器名称 ip地址 controller-node1 172.16.1.90 4.1.git介绍: 1.git分布式图: 2.git区域: 3.四种状态: 上面的操作在工作目录 ...

  3. 13.7Cloneable接口

    要点提示:Cloneable接口给出了一个可克隆对象.

  4. CentOS 8 按tab键不能自动补全问题解决方案

    CentOS中按tab键不能自动补全问题解决办法 检查一下系统有没有安装bash-completion包 [root@Sonarqube ~]# rpm -lq bash-completion yum ...

  5. 前端 | Vue 路由返回恢复页面状态

    需求场景:首页搜索内容,点击跳转至详情页,页面后退返回主页,保留搜索结果. 方案:路由参数:路由守卫 需求描述 在使用 Vue 开发前端的时候遇到一个场景:在首页进行一些数据搜索,点击搜索结果进入详情 ...

  6. 跨域解决之JSONP和CORS的详细介绍

    JSONP跨域和CORS跨域 什么是跨域? 跨域:指的是浏览器不能执行其它网站的脚本,它是由浏览器的同源策略造成的,是浏览器的安全限制! 同源策略 同源策略:域名.协议.端口均相同. 浏览器执行Jav ...

  7. Leetcode No.27 Remove Element(c++实现)

    1. 题目 1.1 英文题目 Given an integer array nums and an integer val, remove all occurrences of val in nums ...

  8. 记两道最近做的pwn题(ciscn_2019)

    这两题为什么要记录呢,一个是我发现网上很多教程没写清楚(也可能是我太菜了),二是细节点很多,不同的大佬方式不太一样,有很多细节需要注意 ciscn_2019_es_2 这题是栈迁移的题,先上exp 1 ...

  9. mongodb oplog详解和格式分析

    1. 基本概念 oplog使用固定大小集合记录了数据库中所有修改操作的操作日志(新增.修改和删除,无查询),mongodb收到修改请求后,先在主节点(Primary)执行请求,再把操作日志保存到opl ...

  10. Leetcode春季打卡第四天:994. 腐烂的橘子

    Leetcode春季打卡第四天:994. 腐烂的橘子 Leetcode春季打卡第四天:994. 腐烂的橘子 思路 思路是采用广度优先搜索,一层一层遍历. 首先先扫描矩阵,将坏橘子放进队列,记录正常橘子 ...