快捷方式

推理模式

c10::InferenceMode 是一个新的 RAII 保护机制,类似于 NoGradMode,在您确定您的操作与自动梯度计算 (autograd) 没有交互时使用(例如模型训练)。与 NoGradMode 相比,在此模式下运行的代码通过禁用与 autograd 相关的操作(如视图跟踪和版本计数器递增)获得更好的性能。但是,在 c10::InferenceMode 内部创建的张量在与 autograd 系统交互时也有更多限制。

InferenceMode 可以为给定的代码块启用。在 InferenceMode 内部,所有新分配的(非视图)张量都被标记为推理张量。推理张量

  • 没有版本计数器,因此如果您尝试读取它们的版本(例如,因为您保存了此张量以进行反向传播),则会引发错误。

  • InferenceMode 外部是不可变的。因此,如果您尝试以下操作,则会引发错误:- 在 InferenceMode 外部修改其数据。- 在 InferenceMode 外部将其修改为 requires_grad=True。要解决此问题,您可以在 InferenceMode 外部进行克隆以获取普通张量,然后再进行修改。

当且仅当非视图张量是在 InferenceMode 内部分配时,它才是推理张量。当且仅当视图张量所引用的张量是推理张量时,它才是推理张量。

InferenceMode 代码块内部,我们做出以下性能保证

  • NoGradMode 类似,即使其输入具有 requires_grad=True,所有操作都不会记录 grad_fn。这适用于推理张量和普通张量。

  • 对推理张量的视图操作不执行视图跟踪。视图和非视图推理张量无法区分。

  • 对推理张量的就地操作保证不会导致版本递增。

有关 InferenceMode 的更多实现细节,请参阅 RFC-0011-InferenceMode

AutoNonVariableTypeMode 迁移指南

在用于推理工作负载的 PyTorch 生产使用中,我们已经看到 C++ 保护机制 AutoNonVariableTypeMode(现为 AutoDispatchBelowADInplaceOrView)的使用激增,它会禁用自动梯度计算、视图跟踪和版本计数器递增。不幸的是,目前将此保护机制用于推理工作负载的做法是不安全的:可以使用 AutoNonVariableTypeMode 来绕过 PyTorch 的安全检查,并导致静默错误的结果,例如,当为反向传播保存的张量随后被修改时,PyTorch 会引发错误,但在 AutoNonVariableTypeMode 内部发生的修改将静默绕过检查,并向用户返回错误的梯度。

当当前 AutoNonVariableTypeMode 用户考虑迁移时,以下步骤可能有助于您确定最佳替代方案

  1. 尝试仅以推理模式运行工作负载的用户(例如加载预训练的 JIT 模型并在 C++ 运行时中运行推理)应添加 c10::InferenceMode guard 来保护对张量的所有操作(包括模型加载)。请参阅下面的推理工作负载示例

c10::InferenceMode guard;
model.load_jit(saved_model);
auto inputs = preprocess_tensors(data);
auto out = model.forward(inputs);
auto outputs = postprocess_tensors(out);

注意 c10::InferenceMode 提供了 AutoNonVariableTypeMode 的直接替换,保留了 AutoNonVariableTypeMode 的性能特性。但它们也有一些差异,用户应额外注意

  • 这两个保护机制都会影响张量执行过程以跳过与推理无关的操作,但 InferenceMode 还会影响张量创建,而 AutoNonVariableTypeMode 则不会。换句话说,在 InferenceMode 内部创建的张量会被标记为推理张量,以便在退出 InferenceMode 后可以应用某些限制。

  • 可以嵌套启用/禁用 InferenceMode 状态,而 AutoNonVariableTypeMode 仅允许启用状态。

{
  InferenceMode guard(true);
  // InferenceMode is on
  {
    InferenceMode guard(false);
    // InferenceMode is off
  }
  // InferenceMode is on
}
// InferenceMode is off
  1. 尝试实现自定义内核并希望在 Autograd 分派键下重新分派的使用者应使用 AutoDispatchBelowADInplaceOrView。注意 AutoDispatchBelowADInplaceOrView 只是 AutoNonVariableTypeMode 的新名称,因为它更好地解释了保护机制的功能。我们正在弃用 AutoNonVariableTypeMode,它将在 1.10 版本中删除。有关示例,请参阅 pytorch/vision 中的自定义内核 ROIAlignFunction

class ROIAlignFunction : public torch::autograd::Function<ROIAlignFunction> {
 public:
  static torch::autograd::variable_list forward(
      torch::autograd::AutogradContext* ctx,
      const torch::autograd::Variable& input,
      const torch::autograd::Variable& rois,
      double spatial_scale,
      int64_t pooled_height,
      int64_t pooled_width,
      int64_t sampling_ratio,
      bool aligned) {
    ctx->saved_data["spatial_scale"] = spatial_scale;
    ctx->saved_data["pooled_height"] = pooled_height;
    ctx->saved_data["pooled_width"] = pooled_width;
    ctx->saved_data["sampling_ratio"] = sampling_ratio;
    ctx->saved_data["aligned"] = aligned;
    ctx->saved_data["input_shape"] = input.sizes();
    ctx->save_for_backward({rois});
    // Used to be at::AutoNonVariableTypeMode g;
    at::AutoDispatchBelowADInplaceOrView guard;
    auto result = roi_align(
        input, rois, spatial_scale, pooled_height,
        pooled_width, sampling_ratio, aligned);
    return {result};
  }

自定义的就地和视图内核需要一些特殊的处理,除了上述保护机制之外,请参阅 自定义内核教程 以获取更多详细信息。

文档

访问 PyTorch 的全面开发者文档

查看文档

教程

获取针对初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并获得问题的解答

查看资源