最近小虎在cpu上试跑了detection任务的程序没什么问题,但是在gpu上运行时发生了关于cuda的一些报错,发现解决问题的精华就一句话:"不可在DataLoader或DataSet内将任何数据放到CUDA上,而是等到程序运行出DataLoader之后(也就是到了train里的时候)将数据放到CUDA上。"下面给出问题解决的例子和代码。
先看看小虎程序的报错,报错中说明了在对bounding box的左上角加长宽坐标形式转成左上右下对角点坐标形式时,CUDA初始化回发生错误。
File "/home/wei/lef/lef2/lib/model/detection/matcher/utils.py", line 173, in centreForm2CornerForm
boxes[..., :2] - (boxes[..., 2:] * 0.5),
RuntimeError: CUDA error: initialization error
CUDA kernel errors might be asynchronously reported at some other API call,so the stacktrace below might be incorrect.
For debugging consider passing CUDA_LAUNCH_BLOCKING=1.
查了一下类似的报错,有些问题可以通过将pin_memory设成False和num_workers设成1解决。但是很奇怪的是,我写代码参照的仓库并没有这种要求。然后就搜到了那句金句,在dataloader里面不能将tensor等数据放在cuda上面,也就是GPU device里面。依照我目前的经验来看,这种限制是因为dataloader数据都是临时的,读入一个batch的数据,清空,再读另一个batch,如果这个过程直接在gpu内存里处理,可能会很慢。
Codes(这里只给出我改动的部分):
原始,
DefaultAnchorsCtr = torch.tensor(DefaultAnchorsCtr, dtype=torch.float, device=self.Device)
改成,
DefaultAnchorsCtr = torch.tensor(DefaultAnchorsCtr, dtype=torch.float)
又因为dataloader和detection模型都用了anchor generator,所以可以在类里面写个主动把anchor放入cuda的function,在detection的模型中调用。
这个问题在用前面的方法解决了后就不会出现了。因为这是小虎程序的第一个报错,刚开始试了另一种办法。这个部分的报错有说是因为我在dataloader使用了pin_memory,所以不能重复在类里面的forward或者__call__里面声明新的tensor。所以我在类初始化的时候就生成anchor。
RuntimeError: Cannot re-initialize CUDA in forked subprocess. To use CUDA with multiprocessing, you must use the 'spawn' start method
RuntimeError: CUDA error: initialization error
Cannot re-initialize CUDA in forked subprocess on network.to(device) operation