为什么Pytorch一定要用第0块显卡
- 更新 (2020.11.23)
- 问题
- 原因
- 解决方法
更新 (2020.11.23)
Pytorch调用显卡的问题在1.0版本前比较明显,建议各位尽量使用1.0以后的版本。其次,对于超大模型的训练,有时会需要多显卡并行运算。
问题
在使用Pytorch进行训练的时候,有一个奇怪的问题是,无论怎么在代码里指定显卡,最终运行时始终会在第0块显卡上占用少量的内存。本来是个无伤大雅的问题,但是一旦0号显卡被自己或者别人占满了,就很抓狂?公用服务器的悲伤啊。
原因
查了一下在GitHub上有一个关于这个问题的讨论,Pytorch初始化问题,大概是pytorch在初始化的时候会默认在第0块显卡上进行,会占用一定的显存(在torch/cuda/init.py:110
中,拷贝了部分代码过来)。这就导致,在第0块显卡空闲内存不多时,程序会反复报Runtime Error的错,可以通过如下的方法来达到完全不使用第0块显卡的目的。
class device(object):
"""Context-manager that changes the selected device.
Arguments:
idx (int): device index to select. It's a no-op if this argument
is negative.
"""
def __init__(self, idx):
self.idx = idx
self.prev_idx = -1
def __enter__(self):
if self.idx is -1:
return
_lazy_init()
self.prev_idx = torch._C._cuda_getDevice()
if self.prev_idx != self.idx:
torch._C._cuda_setDevice(self.idx)
def __exit__(self, *args):
if self.prev_idx != self.idx:
torch._C._cuda_setDevice(self.prev_idx)
return False
解决方法
强制指定GPU的方法不少,但是不是每个都对pytorch有用,我在这里列出我知道的几个。
- 最好用的、绝对不会出错的device (适用于单卡调试,简单快捷,多卡训练的童靴使用方法2比较好)
一般使用device时大多数用来直接指定显卡号,但是pytorch那个尿性在你制定前就用了第0块进行初始化,所以保险的方法是使用with
语句,在with
块下再写pytorch的调用,亲测有效。
with torch.cuda.device(1):
pass
- 指令运行前设置环境变量 (适用于多卡训练)
在输入训练指令前加上CUDA_VISIBLE_DEVICES=1,2
,即设置环境变量,程序只“看得见”第1、2块显卡,自然就不需要在使用第0块显卡了。但是有一个问题是,在设置环境变量之后,第1、2块显卡在程序的眼里就变成了第0、1块显卡,在后续使用中需要注意序号的问题,不然会出现invalid device ordinal
的错误。使用成本最小,绝对不会出现cuda0在被禁用的情况下被调用的情况。
CUDA_VISIBLE_DEVICES=1,2 python train.py
- 别人的博客上说有用,但是我自己没实验成功的os指定法
用os指定理论上可以指定pytorch不走第0块GPU,但是我试了一下没成功,不知道是不是还要什么先决条件,有谁成功了欢迎评论指正。
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '1,2'
Pytorch可真是个小妖精