推斷模式#
c10::InferenceMode 是一種新的 RAII 守護(guard),類似於 NoGradMode,適用於您確定操作不會與 autograd 互動的情況(例如模型訓練)。與 NoGradMode 相比,在此模式下執行的程式碼透過停用 autograd 相關的操作(如檢視跟蹤和版本計數器遞增)來獲得更好的效能。但是,在 c10::InferenceMode 中建立的張量在與 autograd 系統互動時也有更多限制。
InferenceMode 可以為給定的程式碼塊啟用。在 InferenceMode 內部,所有新分配的(非檢視)張量都會被標記為推斷張量。推斷張量
沒有版本計數器,因此如果您嘗試讀取它們的版本(例如,因為您儲存了此張量以用於反向傳播),將會引發錯誤。
在
InferenceMode外部是不可變的。因此,如果您嘗試:- 在 InferenceMode 外部修改其資料。- 在 InferenceMode 外部將其修改為requires_grad=True。將會引發錯誤。為了解決這個問題,您可以在 InferenceMode 外部建立一個克隆,以便在修改之前獲得一個常規張量。
當且僅當非檢視張量在 InferenceMode 內部分配時,它才是推斷張量。當且僅當檢視張量是推斷張量的檢視時,它才是推斷張量。
在 InferenceMode 塊內,我們提供了以下效能保證:
與
NoGradMode類似,所有操作都不會記錄grad_fn,即使它們的輸入具有requires_grad=True。這適用於推斷張量和常規張量。對推斷張量進行檢視操作不會進行檢視跟蹤。檢視和非檢視推斷張量是無法區分的。
對推斷張量進行原地(inplace)操作保證不會進行版本遞增。
有關 InferenceMode 的更多實現細節,請參閱 RFC-0011-InferenceMode。
從 AutoNonVariableTypeMode 遷移指南#
在 PyTorch 的生產推理工作負載中,我們觀察到 C++ 守護 AutoNonVariableTypeMode(現在是 AutoDispatchBelowADInplaceOrView)的使用激增,它會停用 autograd、檢視跟蹤和版本計數器遞增。不幸的是,當前這種用於推理工作負載的守護用法是不安全的:有可能使用 AutoNonVariableTypeMode 來繞過 PyTorch 的安全檢查,從而導致靜默錯誤的結果。例如,當為反向傳播儲存的張量隨後被修改時,PyTorch 會丟擲錯誤,但修改發生在 AutoNonVariableTypeMode 內部時,會靜默地繞過檢查,並向用戶返回錯誤的梯度。
噹噹前 AutoNonVariableTypeMode 的使用者考慮遷移時,以下步驟可能有助於您決定最佳替代方案:
嘗試在僅推理模式下執行工作負載的使用者(例如載入預訓練的 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
嘗試實現自定義核心並希望在
Autograddispatch keys 下重新分派的使用者應改用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};
}
自定義原地(inplace)和檢視(view)核心除了上述守護之外,還需要一些特殊處理,有關更多詳細資訊,請參閱 自定義核心教程。