Resize optimization for all architectures (#11956)

With this patch, it optimizes Resize when the input X is 4D int8/uint8 tensor
and the mode is linear by:

* Transforming NCHW Resize to NHWC variant
* Using the NHWC Resize kernel without floating-point computation

It improves DeepLab V3 with uint8 quantization by 19% on X64. It also improves
Resize of DeepLab V3 with int8 quantization by 15%~18% on X64.
This commit is contained in:
Yi-Hong Lyu 2022-06-29 09:19:19 -07:00 committed by GitHub
parent 4eb54ff9a5
commit c8cd36da01
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 2 additions and 14 deletions

View file

@ -1765,10 +1765,9 @@ static bool CanNodeSkipCostCheck(const OptimizerCtx& ctx, const api::NodeRef& no
// Inclusion of MaxPool is a hack because it has higher perf in the NHWC variant when supported.
return true;
}
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
if (node.IsOp("Resize")) {
// Resize is included because it has higher perf in the NHWC variant when
// the input X is 4D int8 tensor and the mode is linear on ARM
// the input X is 4D int8 tensor and the mode is linear
auto X_value_info = ctx.graph.GetValueInfo(node.Inputs()[0]);
auto X_shape = X_value_info->Shape();
auto X_dtype = X_value_info->DType();
@ -1778,9 +1777,6 @@ static bool CanNodeSkipCostCheck(const OptimizerCtx& ctx, const api::NodeRef& no
return true;
}
}
#else
(void)ctx;
#endif
return false;
}

View file

@ -1173,7 +1173,6 @@ Status Upsample<T>::BaseCompute(OpKernelContext* context,
output_height * output_width > 64 ? context->GetOperatorThreadPool() : nullptr);
} else {
if (use_extrapolation_) {
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
if (!is_2D &&
(Y->GetElementType() == ONNX_NAMESPACE::TensorProto_DataType_UINT8 ||
Y->GetElementType() == ONNX_NAMESPACE::TensorProto_DataType_INT8)) {
@ -1183,17 +1182,13 @@ Status Upsample<T>::BaseCompute(OpKernelContext* context,
alloc, get_original_coordinate_,
output_height * output_width * num_channels > 64 ? context->GetOperatorThreadPool() : nullptr);
} else {
#endif
NhwcUpsampleBilinear<T, true>(
batch_size, num_channels, input_height, input_width, output_height, output_width,
height_scale, width_scale, roi, extrapolation_value_, X->Data<T>(), Y->MutableData<T>(),
alloc, get_original_coordinate_,
output_height * output_width * num_channels > 64 ? context->GetOperatorThreadPool() : nullptr);
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
}
#endif
} else {
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
if (!is_2D &&
(Y->GetElementType() == ONNX_NAMESPACE::TensorProto_DataType_UINT8 ||
Y->GetElementType() == ONNX_NAMESPACE::TensorProto_DataType_INT8)) {
@ -1203,15 +1198,12 @@ Status Upsample<T>::BaseCompute(OpKernelContext* context,
alloc, get_original_coordinate_,
output_height * output_width * num_channels > 64 ? context->GetOperatorThreadPool() : nullptr);
} else {
#endif
NhwcUpsampleBilinear<T, false>(
batch_size, num_channels, input_height, input_width, output_height, output_width,
height_scale, width_scale, roi, extrapolation_value_, X->Data<T>(), Y->MutableData<T>(),
alloc, get_original_coordinate_,
output_height * output_width * num_channels > 64 ? context->GetOperatorThreadPool() : nullptr);
#if defined(_M_ARM64) || defined(__aarch64__) || defined(_M_ARM) || defined(__arm__)
}
#endif
}
}
return Status::OK();

View file

@ -255,7 +255,7 @@ void NhwcUpsampleBilinearInteger(const int32_t batch_size,
const T* const Xdata = XdataBase + n * (input_height * input_width) * num_channels;
T* const Ydata = YdataBase + n * (output_height * output_width) * num_channels;
concurrency::ThreadPool::TryParallelFor(
tp, output_height * output_width,
tp, static_cast<std::ptrdiff_t>(output_height) * output_width,
static_cast<double>(num_channels * 2),
[&](std::ptrdiff_t first, std::ptrdiff_t last) {
for (std::ptrdiff_t i = first; i < last; ++i) {