为您的项目提供 GPU · 无 KYC 的加密货币支付 如何租用
简体中文
打开控制台
实用指南 / KERNODECK

出现 CUDA 错误:应该检查哪个操作?

保留第一次失败,确定相关的 batch,并将应用缩减到触发该失败的那个操作。在 CUDA 上,异步执行可能导致错误在原因发生之后更晚才浮现。随后再检查索引、形状、类型和设备,然后再去修改环境。此方法针对的是已经启动的应用;它不能替代最初对 GPU 可用性的检查。

2 分钟阅读 · 开发者指南

保留第一次失败及其上下文

本指南从一次成功的启动之后开始:PyTorch 能看到设备,但你的应用在某个 batch 或运算符上失败。如果连一个很小的计算都无法运行,就回到最初的诊断。否则,请保留第一个错误、迭代编号以及最后完成的步骤。第一次失败之后接连出现的消息,描述的可能是它的后果,而不是多个彼此独立的原因。

记录代码版本、Python 和 PyTorch 版本、后端、数值类型以及输入形状。对于数据,优先使用内部标识符和维度,而不是完整复制内容。找出问题批次与其他批次的差异:长度、缺失的目标、最后一个不完整的批次、数据增强或很少使用的分支。该档案让你无需重跑整个训练即可复现该案例。

在异步执行下定位出错的启动

在 CUDA 上,操作会被排队,可能在 Python 函数返回后才完成。因此,在拷贝到 CPU 或读取标量时抛出的错误,可能来自之前的计算。PyTorch 文档解释了这种异步执行。堆栈跟踪所指的行是一个需要检查的观测点,并不总是根本原因。

若要在 NVIDIA/CUDA 上进行简短的复现,请单独使用 CUDA_LAUNCH_BLOCKING=1 进行启动。该选项使调用同步,能让错误更接近其源头。它用于诊断,而非计时。你也可以在主要步骤之间临时插入同步,以缩小可疑区间。之后请移除这些插桩:它们会改变常规的调度顺序。

以下命令仅作教学用途,并未实际执行。它假定使用 POSIX 终端且存在 train.py 脚本。该赋值仅对本次启动生效;请根据你的 shell 调整语法。不要将这个 NVIDIA 变量推广到 ROCm 技术栈。

建议的诊断启动,未执行
CUDA_LAUNCH_BLOCKING=1 python train.py

读懂一类错误,不要急于下结论

报错信息缩小了搜索范围,但它不能替代可复现的案例。域外索引、张量位于错误设备以及无法完成的分配,各自需要不同的检查。请保持对无效数据、算子契约和二进制环境之间的区分。同时更改批次、精度和库会抹掉这种区分。

在设备上执行断言后,不要尝试在同一进程中继续相同的训练。NVIDIA 指出 cudaErrorAssert 会使现有分配失效,必须结束并重启进程。在 notebook 中,这意味着在修正后的复现之前重启内核。不过,重启既不能修正错误的目标,也不能修正无效的索引。

左右滚动表格即可查看所有列。
诊断线索,不在报错信息与原因之间建立自动关联
观察到的线索首要检查应避免的结论
device-side assert索引、目标与算子条件GPU 一定有故障
显存不足形状、张量生命周期、进程内存任何 CUDA 错误都是 VRAM 不足
算子或内核不可用版本、扩展、后端与 dtype盲目重装所有东西
设备不一致模型和每个输入的放置位置在不了解来源的情况下添加拷贝

实例演示:四分类问题中出现了类别 4

设想一个教学用的分类器,其输出有四列。它的类别索引为 0 到 3。一个包含数值 4 的标注文件可能表明采用了 1 到 4 的编码,或存在一个意料之外的第五个类别。仅仅增大输出尺寸会掩盖一项约束,却无法解决标注含义的问题。

下面提出的检查在将目标转移到 CPU 之前进行。它并未实际执行。它演示了 CrossEntropyLoss 对 long 类型类别索引的契约,并明确选择了 ignore_index=-100。它不涵盖由概率分布构成的目标。在此场景中,[0, 2, 4] 应被拒绝;该预期结果是由规则推导得出的,并非作为实测结果呈现。

然后修正数据准备中的映射,并检查它与类别名称之间的双射关系。在不确定所有来源是否采用同一约定之前,不要到处减 1。将出错案例添加到一个随项目一起保留的小型验证集中。

针对类别索引的教学用 CPU 防护
import torch

classes = 4
ignore_index = -100
target = torch.tensor([0, 2, 4], dtype=torch.long)
if target.ndim != 1 or target.dtype != torch.long:
    raise ValueError("Cibles : vecteur d’indices attendu")
valid = target[target != ignore_index]
if valid.numel() == 0:
    raise ValueError("Aucune cible exploitable dans ce batch")
if bool(((valid < 0) | (valid >= classes)).any()):
    raise ValueError("Indice de classe hors domaine")

在不删除触发条件的前提下缩小程序

首先用相同的变换重放单个输入或单个批次。移除远程跟踪、结果写入以及与故障无关的分支。保留疑似出错的 dtype、形状和算子。如果错误依赖某个特定的长度或内存布局,随意取一个小张量可能无法再复现它。

每次只比较一处修改:关闭可选扩展、参考算子、常规精度,或在 CPU 上存在时用 CPU 执行同一运算。CPU 上成功只是线索,并不等于 CUDA 验证通过。对于自定义函数,还要记录关于 strides、连续性和大小的假设。寻找一个修复前失败、修复后成功的示例,并用输出检查来验证,而不只是没有抛出异常。

在初始范围内验证修复正确性

可接受的修复必须通过最小用例、相邻用例以及原始流程中具有代表性的一部分。尤其要重放最后一个批次、一个短输入、一个长输入以及映射的边界值。确认被拒绝的元素可被识别,且处理的输入数量仍符合预期。静默忽略异常可能把一次可见的崩溃变成不完整的结果。

关闭诊断模式,从全新进程重新开始,并用正常配置确认行为。保留故障原因、所应用的修改以及非回归检查。如果你此前中断了训练,请从错误发生前经过验证的一致检查点重新开始;仅凭故障期间写入的文件并不足以保证其可恢复。

知道何时寻求更有针对性的分析

如果同一个最小用例在输入有效时仍失败,请准备一份精确的请求:运算、形状、类型、后端、版本以及第一条相关信息。移除个人标识符和不必要的路径。二进制扩展可能需要自己的兼容性矩阵;PyTorch 的一般支持并不会自动验证该扩展。

在 ROCm 上,PyTorch 仍保留 torch.cuda 接口和 cuda 设备名称。请检查 torch.version.hip 以在应用 NVIDIA 流程之前识别这套技术栈。信息、工具和诊断选项可能有所不同。本文所述任何检查都不能证明准备好的环境与 Kernodeck 的某个方案兼容;请在选择 GPU 之前用这些标准来明确你的需求。

您的疑问

CUDA_LAUNCH_BLOCKING=1 能修复 CUDA 错误吗?

不能。它让 CUDA 调用同步,以帮助定位出错的运算。请在简短的复现用例上使用它,然后修复根本原因,并在测量正常性能之前将其移除。

device-side assert 之后我还能继续使用 notebook 吗?

在重放修复后的用例之前请重启内核。设备端断言可能使上下文不可用,并使分配失效。重启可恢复上下文,但不会修正错误的索引或数据。

如果同样的计算在 CPU 上能通过,是否说明 GPU 有故障?

不能。这个结果区分了两条执行路径。dtype、扩展、内核或数据约束都可能解释这种差异。请先在实际涉及的 GPU 技术栈上复现一个最小运算,再下结论。

NVIDIA 的流程在 ROCm 上完全相同吗?

不完全相同。用于 ROCm 的 PyTorch 也使用 torch.cuda,但工具和某些诊断变量有所不同。请用 torch.version.hip 识别 HIP,并查阅对应实际后端的文档。