错误处理指南

TVM 包含结构化的错误类,用于指示特定类型的错误。请尽可能引发特定错误类型,以便用户可以编写代码来处理必要的特定错误类别。您可以直接在 Python 中引发特定的错误对象。在其他语言(如 C++)中,您只需在错误消息中添加 <ErrorType>: 前缀(见下文)。

注意

请参考 tvm.error 以获取错误列表。

在 C++ 中引发特定错误

您可以将 <ErrorType>: 前缀添加到您的错误消息中,以引发相应类型的错误。请注意,您不必添加新类型,如果没有在消息中添加错误类型前缀,则默认会引发 tvm.error.TVMError。此机制适用于 LOG(FATAL)ICHECK 宏。以下代码给出了如何执行此操作的示例。

// src/api_test.cc
void ErrorTest(int x, int y) {
  ICHECK_EQ(x, y) << "ValueError: expect x and y to be equal."
  if (x == 1) {
    LOG(FATAL) << "InternalError: cannot reach here";
  }
}

上面的函数作为 PackedFunc 注册到 Python 前端,名称为 tvm._api_internal._ErrorTest。以下是如果我们调用注册函数会发生的情况

>>> import tvm
>>> tvm.testing.ErrorTest(0, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/tvm/python/tvm/_ffi/_ctypes/function.py", line 190, in __call__
    raise get_last_ffi_error()
ValueError: Traceback (most recent call last):
  [bt] (3) /path/to/tvm/build/libtvm.so(TVMFuncCall+0x48) [0x7fab500b8ca8]
  [bt] (2) /path/to/tvm/build/libtvm.so(+0x1c4126) [0x7fab4f7f5126]
  [bt] (1) /path/to/tvm/build/libtvm.so(+0x1ba2f8) [0x7fab4f7eb2f8]
  [bt] (0) /path/to/tvm/build/libtvm.so(+0x177d12) [0x7fab4f7a8d12]
  File "/path/to/tvm/src/api/api_test.cc", line 80
ValueError: Check failed: x == y (0 vs. 1) : expect x and y to be equal.
>>>
>>> tvm.testing.ErrorTest(1, 1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/path/to/tvm/python/tvm/_ffi/_ctypes/function.py", line 190, in __call__
    raise get_last_ffi_error()
tvm.error.InternalError: Traceback (most recent call last):
  [bt] (3) /path/to/tvm/build/libtvm.so(TVMFuncCall+0x48) [0x7fab500b8ca8]
  [bt] (2) /path/to/tvm/build/libtvm.so(+0x1c4126) [0x7fab4f7f5126]
  [bt] (1) /path/to/tvm/build/libtvm.so(+0x1ba35c) [0x7fab4f7eb35c]
  [bt] (0) /path/to/tvm/build/libtvm.so(+0x177d12) [0x7fab4f7a8d12]
  File "/path/to/tvm/src/api/api_test.cc", line 83
InternalError: cannot reach here
TVM hint: You hit an internal error. Please open a thread on https://discuss.tvm.ai/ to report it.

正如您在上面的示例中看到的,TVM 的 ffi 系统将 Python 和 C++ 的堆栈跟踪组合成单个消息,并自动生成相应的错误类。

如何选择错误类型

您可以浏览下面列出的错误类型,尝试使用常识,并参考现有代码中的选择。我们尝试保持合理数量的错误类型。如果您认为需要添加新的错误类型,请执行以下步骤

  • 发送 RFC 提案,其中包含当前代码库中的描述和用例示例。

  • 将新的错误类型添加到 tvm.error,并提供清晰的文档。

  • 更新此文件中的列表以包含新的错误类型。

  • 更改代码以使用新的错误类型。

我们还建议在创建简短错误消息时减少抽象。这样代码更具可读性,并且也为在必要时制作特定的错误消息开辟了道路。

def preferred():
    # Very clear about what is being raised and what is the error message.
    raise OpNotImplemented("Operator relu is not implemented in the MXNet frontend")

def _op_not_implemented(op_name):
    return OpNotImplemented("Operator {} is not implemented.").format(op_name)

def not_preferred():
    # Introduces another level of indirection.
    raise _op_not_implemented("relu")

如果我们需要引入一个包装函数来构造多行错误消息,请将包装器放在同一文件中,以便其他开发人员可以轻松查找实现。