浅谈Tensorflow2对GPU内存的分配策略
目录
- 一、问题源起
- 二、开发环境
- 三、Tensorflow针对GPU内存的分配策略
- 四、问题分析验证
- 五、GPU分配策略分析
- 六、扩展
一、问题源起 从以下的异常堆栈可以看到是BLAS程序集初始化失败,可以看到是执行MatMul的时候发生的异常,基本可以断定可能数据集太大导致memory不够用了。
2021-08-10 16:38:04.917501: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED2021-08-10 16:38:04.960048: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED2021-08-10 16:38:04.986898: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED2021-08-10 16:38:04.992366: E tensorflow/stream_executor/cuda/cuda_blas.cc:226] failed to create cublas handle: CUBLAS_STATUS_NOT_INITIALIZED2021-08-10 16:38:04.992389: W tensorflow/stream_executor/stream.cc:1455] attempting to perform BLAS operation using StreamExecutor without BLAS supportTraceback (most recent call last):File "/home/mango/PycharmProjects/DeepLearing/minist_conv.py", line 32, inmodel.fit(train_images, train_labels, epochs=5, batch_size=64)File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/keras/engine/training.py", line 1183, in fittmp_logs = self.train_function(iterator)File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/def_function.py", line 889, in __call__result = self._call(*args, **kwds)File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/def_function.py", line 950, in _callreturn self._stateless_fn(*args, **kwds)File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/function.py", line 3023, in __call__return graph_function._call_flat(File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/function.py", line 1960, in _call_flatreturn self._build_call_outputs(self._inference_function.call(File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/function.py", line 591, in calloutputs = execute.execute(File "/usr/local/lib/python3.9/dist-packages/tensorflow/python/eager/execute.py", line 59, in quick_executetensors = pywrap_tfe.TFE_Py_Execute(ctx._handle, device_name, op_name,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[[node sequential/dense/MatMul (defined at home/mango/PycharmProjects/DeepLearing/minist_conv.py:32) ]] [Op:__inference_train_function_993]Function call stack:train_function
二、开发环境
mango@mango-ubuntu:~$ /usr/local/cuda/bin/nvcc --versionnvcc: NVIDIA (R) Cuda compiler driverCopyright (c) 2005-2021 NVIDIA CorporationBuilt on Wed_Jul_14_19:41:19_PDT_2021Cuda~~ compilation tools, release 11.4, V11.4.100==Build cuda_11.4.r11.4/compiler.30188945_0mango@mango-ubuntu:~$ tail -n 10 /usr/include/cudnn_version.h#ifndef CUDNN_VERSION_H_#define CUDNN_VERSION_H_#define CUDNN_MAJOR 8#define CUDNN_MINOR 2#define CUDNN_PATCHLEVEL 2#define CUDNN_VERSION (CUDNN_MAJOR * 1000 + CUDNN_MINOR * 100 + CUDNN_PATCHLEVEL)#endif /* CUDNN_VERSION_H */mango@mango-ubuntu:~$ python3 --versionPython 3.9.5mango@mango-ubuntu:~$ nvidia-smiTue Aug 10 19:57:58 2021+-----------------------------------------------------------------------------+| NVIDIA-SMI 470.57.02Driver Version: 470.57.02CUDA Version: 11.4||-------------------------------+----------------------+----------------------+| GPUNamePersistence-M| Bus-IdDisp.A | Volatile Uncorr. ECC || FanTempPerfPwr:Usage/Cap|Memory-Usage | GPU-UtilCompute M. ||||MIG M. ||===============================+======================+======================||0NVIDIA GeForce ...Off| 00000000:01:00.0 Off |N/A || N/A54CP0N/A /N/A |329MiB /2002MiB |9%Default ||||N/A |+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+| Processes:||GPUGICIPIDTypeProcess nameGPU Memory ||IDIDUsage||=============================================================================||0N/AN/A1818G/usr/lib/xorg/Xorg186MiB ||0N/AN/A2002G/usr/bin/gnome-shell45MiB ||0N/AN/A3435G...AAAAAAAAA= --shared-files75MiB ||0N/AN/A6016Gpython313MiB |+-----------------------------------------------------------------------------+ mango@mango-ubuntu:~$ python3Python 3.9.5 (default, May 11 2021, 08:20:37) [GCC 10.3.0] on linuxType "help", "copyright", "credits" or "license" for more information.>>> import tensorflow as tf2021-08-10 18:33:05.917520: I tensorflow/stream_executor/platform/default/dso_loader.cc:53] Successfully opened dynamic library libcudart.so.11.0>>> tf.__version__'2.5.0'>>>
三、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的内存增长,在分配任何张量或执行任何操作之前,使用以下代码。
gpus = tf.config.list_physical_devices('GPU')if gpus:try:# Currently, memory growth needs to be the same across GPUsfor gpu in gpus:tf.config.experimental.set_memory_growth(gpu, True)logical_gpus = tf.config.list_logical_devices('GPU')print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")except RuntimeError as e:# Memory growth must be set before GPUs have been initializedprint(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)共享时,这是本地开发的常见做法。
gpus = tf.config.list_physical_devices('GPU')if gpus:# Restrict TensorFlow to only allocate 1GB of memory on the first GPUtry:tf.config.set_logical_device_configuration(gpus[0],[tf.config.LogicalDeviceConfiguration(memory_limit=1024)])logical_gpus = tf.config.list_logical_devices('GPU')print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")except RuntimeError as e:# Virtual devices must be set before GPUs have been initializedprint(e)
四、问题分析验证 通过上边对TensorFlow文档的分析,默认情况下会占用所有的GPU内存,但是TensorFlow提供了两种方式可以灵活的控制内存的分配策略;
我们可以直接设置GPU内存按需动态分配
import tensorflow as tfphysical_gpus = tf.config.list_physical_devices('GPU')tf.config.experimental.set_memory_growth(physical_gpus[0], True)
通过以下命令可以看到执行过程中GPU内存的占用最高为697M
mango@mango-ubuntu:~$ while true; do nvidia-smi; sleep 0.2; done; Tue Aug 10 20:30:58 2021+-----------------------------------------------------------------------------+| NVIDIA-SMI 470.57.02Driver Version: 470.57.02CUDA Version: 11.4||-------------------------------+----------------------+----------------------+| GPUNamePersistence-M| Bus-IdDisp.A | Volatile Uncorr. ECC || FanTempPerfPwr:Usage/Cap|Memory-Usage | GPU-UtilCompute M. ||||MIG M. ||===============================+======================+======================||0NVIDIA GeForce ...Off| 00000000:01:00.0 Off |N/A || N/A58CP0N/A /N/A |1026MiB /2002MiB |72%Default ||||N/A |+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+| Processes:||GPUGICIPIDTypeProcess nameGPU Memory ||IDIDUsage||=============================================================================||0N/AN/A1818G/usr/lib/xorg/Xorg186MiB ||0N/AN/A2002G/usr/bin/gnome-shell45MiB ||0N/AN/A3435G...AAAAAAAAA= --shared-files73MiB ||0N/AN/A6016Gpython313MiB ||0N/AN/A13829C/usr/bin/python3.9697MiB |+-----------------------------------------------------------------------------+
我们也可以限制最多使用1024M的GPU内存
import tensorflow as tfphysical_gpus = tf.config.list_physical_devices('GPU')tf.config.set_logical_device_configuration(physical_gpus[0], [tf.config.LogicalDeviceConfiguration(memory_limit=1024)])
同样通过命令可以看到执行过程中GPU内存的占用最高为1455M
mango@mango-ubuntu:~$ while true; do nvidia-smi; sleep 0.2; done; Tue Aug 10 20:31:24 2021+-----------------------------------------------------------------------------+| NVIDIA-SMI 470.57.02Driver Version: 470.57.02CUDA Version: 11.4||-------------------------------+----------------------+----------------------+| GPUNamePersistence-M| Bus-IdDisp.A | Volatile Uncorr. ECC || FanTempPerfPwr:Usage/Cap|Memory-Usage | GPU-UtilCompute M. ||||MIG M. ||===============================+======================+======================||0NVIDIA GeForce ...Off| 00000000:01:00.0 Off |N/A || N/A58CP0N/A /N/A |1784MiB /2002MiB |74%Default ||||N/A |+-------------------------------+----------------------+----------------------++-----------------------------------------------------------------------------+| Processes:||GPUGICIPIDTypeProcess nameGPU Memory ||IDIDUsage||=============================================================================||0N/AN/A1818G/usr/lib/xorg/Xorg186MiB ||0N/AN/A2002G/usr/bin/gnome-shell46MiB ||0N/AN/A3435G...AAAAAAAAA= --shared-files72MiB ||0N/AN/A6016Gpython313MiB ||0N/AN/A13570C/usr/bin/python3.91455MiB |+-----------------------------------------------------------------------------+
五、GPU分配策略分析 通过四中的测试结果可得
- 默认的分配策略会占用所有的内存,并且执行中不会进行释放,如果训练数据量比较打很容易内存不够用;
- 限制最大使用内存,测试占用内存比设置的大,这个可能跟训练中间使用的模型和操作的复杂程度有关系,需要根据具体的业务场景设置合适的值;但是要注意不能设置大了,否则还是会报错,但是设置小了只是执行的慢一些罢了;
- 设置内存按需分配可能是一个相对比较中庸的方案,感觉可能是一个更好的方案,不知道TensorFlow为什么没有设置为默认值,留作一个问题,后续有新的认知的话再补充;
六、扩展 单GPU模拟多GPU环境
当我们的本地开发环境只有一个GPU,但却需要编写多GPU的程序在工作站上进行训练任务时,TensorFlow为我们提供了一个方便的功能,可以让我们在本地开发环境中建立多个模拟GPU,从而让多GPU的程序调试变得更加方便。以下代码在实体GPU GPU:0 的基础上建立了两个显存均为2GB的虚拟GPU。
gpus = tf.config.list_physical_devices('GPU')if gpus:# Create 2 virtual GPUs with 1GB memory eachtry:tf.config.set_logical_device_configuration(gpus[0],[tf.config.LogicalDeviceConfiguration(memory_limit=1024),tf.config.LogicalDeviceConfiguration(memory_limit=1024)])logical_gpus = tf.config.list_logical_devices('GPU')print(len(gpus), "Physical GPU,", len(logical_gpus), "Logical GPUs")except RuntimeError as e:# Virtual devices must be set before GPUs have been initializedprint(e)
多GPU的数据并行
使用 tf.distribute.Strategy可以将模型拷贝到每个GPU上,然后将训练数据分批在不同的GPU上执行,达到数据并行。
tf.debugging.set_log_device_placement(True)gpus = tf.config.list_logical_devices('GPU')strategy = tf.distribute.MirroredStrategy(gpus)with strategy.scope():inputs = tf.keras.layers.Input(shape=(1,))predictions = tf.keras.layers.Dense(1)(inputs)model = tf.keras.models.Model(inputs=inputs, outputs=predictions)model.compile(loss='mse',optimizer=tf.keras.optimizers.SGD(learning_rate=0.2))
【浅谈Tensorflow2对GPU内存的分配策略】到此这篇关于浅谈Tensorflow2对GPU内存的分配策略的文章就介绍到这了,更多相关Tensorflow2 GPU内存分配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
推荐阅读
- 布丽吉特,人生绝对的赢家
- 进必趋|进必趋 退必迟,问起对 视勿移
- 对称加密和非对称加密的区别
- 对抗抑郁最好的方法
- 装聋作哑,关系融洽
- 社保代缴公司服务费包含哪些
- 数组常用方法一
- 幸福的婚姻不争对错!读《你要的是幸福还是对错》有感。
- 把一切献给现在
- 年轻人对未来迷茫时该怎么办()