PyTorch 的即时执行模型的美妙之处在于可以实际调试程序。但是,有时 CUDA 执行的异步特性使调试变得困难。下面是调试程序的一个小技巧。
当使用 CUDA 操作运行 PyTorch 程序时,程序通常不会等到计算完成,而是继续向 GPU 投掷指令,直到它需要实际结果(例如,使用 .item() 或 .cpu() 或打印进行评估)。
虽然这种行为是PyTorch程序性能极快的关键,但有一个缺点:当cuda操作失败时,你的程序早就继续做其他事情了。通常的症状是,在触发错误的指令之后,在或多或少的随机位置出现非常非描述性错误。它通常如下所示:
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in ()
1 loss = torch.nn.functional.cross_entropy(activations, labels)
2 average = loss/4
----> 3 print(average.item())
RuntimeError: cuda runtime error (59) : device-side assert triggered at /home/tv/pytorch/pytorch/aten/src/THC/generic/THCStorage.cpp:36
这个报错很难理解,我们只能知道有些地方出错了。
下面是导致此输出的错误程序:
import torch
device = torch.device('cuda:0')
activations = torch.randn(4,3, device=device) # usually we get our activations in a more refined way...
labels = torch.arange(4, device=device)
loss = torch.nn.functional.cross_entropy(activations, labels)
average = loss/4
print(average.item())
其中一种调试方法是移动到 CPU执行。
但是,通常,我们使用库或有复杂的东西,这不是一个好的选项。那现在怎么办?如果我们能得到一个详细的追溯(traceback),我们应该能立即发现问题。
获得良好的追溯的方法:
1. 您可以把环境变量CUDA_LAUNCH_BLOCKING设置为 1 启动程序。
但你可以看到,我喜欢用Jupyter做我的很多工作,所以这没有那么容易。
2. 但是,这也可以解决:在程序的顶部,在导入所有包(特别是 import PyTorch)之前,插入
import os
os.environ['CUDA_LAUNCH_BLOCKING'] = "1"
在加入了上面这句话之后,我们对错误有了更好的追溯(traceback):
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
in ()
----> 1 loss = torch.nn.functional.cross_entropy(activations, labels)
2 average = loss/4
3 print(average.item())
/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in cross_entropy(input, target, weight, size_average, ignore_index, reduce)
1472 >>> loss.backward()
1473 """
-> 1474 return nll_loss(log_softmax(input, 1), target, weight, size_average, ignore_index, reduce)
1475
1476
/usr/local/lib/python3.6/dist-packages/torch/nn/functional.py in nll_loss(input, target, weight, size_average, ignore_index, reduce)
1362 .format(input.size(0), target.size(0)))
1363 if dim == 2:
-> 1364 return torch._C._nn.nll_loss(input, target, weight, size_average, ignore_index, reduce)
1365 elif dim == 4:
1366 return torch._C._nn.nll_loss2d(input, target, weight, size_average, ignore_index, reduce)
RuntimeError: cuda runtime error (59) : device-side assert triggered at /home/tv/pytorch/pytorch/aten/src/THCUNN/generic/ClassNLLCriterion.cu:116
很显然,是损失函数处报错。事实上,我们的输入的形状为:batch x 3
,所以我们只允许三个类别 (0, 1, 2), 但标签值取到了3!
这种方法的好处是,也适用于有一定复杂度的例子。
原文链接:Debugging CUDA device-side assert in PyTorch