我看过很多针对特定案例问题的具体帖子,但没有基本的激励解释。此错误有什么作用:
RuntimeError: CUDA error: device-side assert triggered
意味 着?具体来说,正在触发的断言是什么,为什么断言在那里,我们如何逆向工作以调试问题?
按原样,此错误消息在诊断任何问题时几乎毫无用处,因为它似乎普遍说"某处接触 GPU 的某些代码"有问题。Cuda 的文档在这方面似乎也没有帮助,尽管我可能是错的。 https://docs.nvidia.com/cuda/cuda-gdb/index.html
当我将代码转移到 CPU 而不是 GPU 上工作时,我收到以下错误:
IndexError: index 128 is out of bounds for dimension 0 with size 128
因此,也许代码中可能存在错误,由于某种奇怪的原因,该错误显示为CUDA错误。
当在 CUDA 设备代码运行时检测到设备端错误时,将通过通常的 CUDA 运行时 API 错误报告机制报告该错误。 设备代码中通常检测到的错误类似于非法地址(例如,尝试取消引用无效指针),但另一种类型是设备端断言。每当设备代码中出现 C/C++assert()
并且断言条件为 false 时,就会生成这种类型的错误。
此类错误是由于特定内核而发生的。 CUDA 中的运行时错误检查必然是异步的,但可能至少有 3 种可能的方法可以开始调试它。
-
修改源代码,将异步内核启动有效转换为同步内核启动,并在每次内核启动后进行严格的错误检查。这将识别导致错误的特定内核。 此时,只需查看该内核代码中的各种断言就足够了,但您也可以使用下面的步骤 2 或 3。
-
使用
cuda-memcheck
运行代码。 这是一个类似于"设备代码的valgrind"的工具。 当您使用cuda-memcheck
运行代码时,它的运行速度往往会慢得多,但运行时错误报告将得到增强。 通常最好使用-lineinfo
编译代码。 在这种情况下,当触发设备端断言时,cuda-memcheck
将报告断言所在的源代码行号,以及断言本身和 false 的条件。 您可以在此处查看使用它的演练(尽管使用非法地址错误而不是assert()
,但assert()
的过程将是相似的。 -
也应该可以使用调试器。 如果您使用调试器,例如
cuda-gdb
(例如在 linux 上),则调试器将具有回溯跟踪报告,这些报告将指示断言在命中时是哪一行。
如果从 python 脚本启动 CUDA 代码,则可以使用cuda-memcheck
和调试器。
此时,您已经发现了断言是什么以及它在源代码中的位置。 为什么会在那里,不能笼统地回答。 这将取决于开发人员的意图,如果没有注释或其他明显,您将需要一些方法来以某种方式直觉。 "如何逆向工作"的问题也是一个通用的调试问题,而不是特定于 CUDA。 您可以在 CUDA 内核代码中使用printf
,也可以使用像cuda-gdb
这样的调试器来帮助解决这个问题(例如,在断言之前设置断点,并在断言即将命中时检查机器状态 - 例如变量)。
使用较新的GPU,您可能希望使用compute-sanitizer
而不是cuda-memcheck
。 它以类似的方式工作。
就我而言,导致此错误是因为我的损失函数只接收 [0, 1] 之间的值,并且我正在传递其他值。
因此,规范化我的损失函数输入,解决此问题:
saida_G -= saida_G.min(1, keepdim=True)[0]
saida_G /= saida_G.max(1, keepdim=True)[0]
阅读此内容:链接