问题描述
运行tensorflow的时候执行卷积出现下面的告警信息,困扰了我很长一段时间。
UnknownError: 2 root error(s) found.
(0) Unknown: Failed to get convolution algorithm. This is probably because cuDNN failed to initialize, so try looking to see if a warning log message was printed above.
[[{{node conv0/convolution}}]]
(1) Unknown: Failed to get convolution algorithm. This is probably because cuDNN failed to initialize, so try looking to see if a warning log message was printed above.
[[{{node conv0/convolution}}]]
百度结果中有多种解决方案,最坑的就是tensorflow和cuda的版本问题。翻过来覆过去安装多少遍,最后还是继续出现。
config = tf.ConfigProto(gpu_options=tf.GPUOptions(allow_growth=True))
config.gpu_options.per_process_gpu_memory_fraction = 0.99
with tf.Session(config=config) as sess:
这是一个有效的办法。但是这一次我使用的是keras, tensorflow只是后端,没办法设置session(我对keras不熟悉),于是这个问题又出现了。
仔细研究后,发现出现这个错误的根本原因在于:tensorflow默认攫取所有显存,据说这样可以有效避免内存碎片的产生。而当显存已经被图形界面等占用了一部分的时候,就会出现这样的错误。
~$ nvidia-smi
Mon Sep 28 20:07:12 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82 Driver Version: 440.82 CUDA Version: 10.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 1050 Off | 00000000:01:00.0 On | N/A |
| 45% 31C P8 N/A / 75W | 249MiB / 1992MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1225 G /usr/lib/xorg/Xorg 131MiB |
| 0 1632 G /usr/bin/gnome-shell 114MiB |
+-----------------------------------------------------------------------------+
这是运行tensorflow之前的显存情况,被图形界面占用了249M/1992M。
nvidia-smi
Mon Sep 28 20:20:59 2020
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 440.82 Driver Version: 440.82 CUDA Version: 10.2 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX 1050 Off | 00000000:01:00.0 On | N/A |
| 45% 32C P8 N/A / 75W | 1979MiB / 1992MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1225 G /usr/lib/xorg/Xorg 120MiB |
| 0 1632 G /usr/bin/gnome-shell 114MiB |
| 0 2547 G /usr/lib/firefox/firefox 1MiB |
| 0 2898 C ...e/zhangyl/anaconda3/envs/tf1/bin/python 1729MiB |
+-----------------------------------------------------------------------------+
这是出现错误之后的,python占用了1729M。
那么应该怎么避免这种情况呢?让我读原著,学原文,看tensorflow的文档是怎么说的。
限制GPU显存的增长
在缺省的情况下,tensorflow会把所有GPU(根据CUDA_VISIBLE_DEVICES)的几乎所有显存提供给进程。这样做是为了更有效的利用相对宝贵的GPU显存资源,因为可以减少内存的碎片。如果要限制tensorflow只使用特定的一组GPU,我们可以使用tf.config.experimental.set_visible_devices 方法。
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
# Restrict TensorFlow to only use the first GPU
try:
tf.config.experimental.set_visible_devices(gpus[0], 'GPU')
logical_gpus = tf.config.experimental.list_logical_devices('GPU')
print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPU")
except RuntimeError as e:
# Visible devices must be set before GPUs have been initialized
print(e)
有些情况下我们希望进程只使用一部分显存,或者只根据进程的需要增加显存需求。tensorflow提供了两个方法来解决这个问题。
第一个方法是打开显存增长开关,调用tf.config.experimental.set_memory_growth,这样进程只会使用需要用到的显存:它会先申请很少的显存,随着程序的运行需要更多的显存,我们才会想tensorflow进程提供更多的GPU显存区域。注意我们不会释放显存,因为那会导致显存碎片。要在制定的GPU上打开显存增长开关,需要在分配任何张量或运行任何计算前使用下面的代码。
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
try:
# Currently, memory growth needs to be the same across GPUs
for gpu in gpus:
tf.config.experimental.set_memory_growth(gpu, True)
logical_gpus = tf.config.experimental.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 initialized
打开这个开关的另一个方法是设置环境变量TF_FORCE_GPU_ALLOW_GROWTH为True。这个配置是对整个平台有效的。
第二个方法是设置虚拟GPU设备,使用tf.config.experimental.set_virtual_device_configuration,给在这个GPU上能使用的显存设一个上限。
gpus = tf.config.experimental.list_physical_devices('GPU')
if gpus:
# Restrict TensorFlow to only allocate 1GB of memory on the first GPU
try:
tf.config.experimental.set_virtual_device_configuration(
gpus[0],
[tf.config.experimental.VirtualDeviceConfiguration(memory_limit=1024)])
logical_gpus = tf.config.experimental.list_logical_devices('GPU')
print(len(gpus), "Physical GPUs,", len(logical_gpus), "Logical GPUs")
except RuntimeError as e:
注意:虚拟设备被初始化后就不能被修改了。
如果你真的想要限制tensorflow进程所能使用的显存,这就是个很有效的方法。这种需求对于开发者来说很常见,因为还用其它的应用,例如GUI工作站。
翻译的不好,大体就是这样了。讲得很清楚了。和tf.ConfigProto的定义非常类似,那应该就是上面内容的一个封装。我用上面的第二个方法有效解决了前面说的错误。