diff --git a/onnxruntime/core/providers/cpu/tensor/upsample.cc b/onnxruntime/core/providers/cpu/tensor/upsample.cc index 0a6f2241d5..d11eef247f 100644 --- a/onnxruntime/core/providers/cpu/tensor/upsample.cc +++ b/onnxruntime/core/providers/cpu/tensor/upsample.cc @@ -287,6 +287,8 @@ void UpsampleBilinear(int64_t batch_size, int64_t num_channels, int64_t input_height, int64_t input_width, + int64_t output_height, + int64_t output_width, float height_scale, float width_scale, const std::vector& roi, @@ -296,8 +298,6 @@ void UpsampleBilinear(int64_t batch_size, T* Ydata, AllocatorPtr& alloc, GetOriginalCoordinateFunc get_original_coordinate) { - auto output_width = static_cast(input_width * width_scale); - auto output_height = static_cast(input_height * height_scale); std::vector y_original; std::vector x_original; @@ -435,7 +435,7 @@ float CubicInterpolation1D(const T* Xdata, float result = 0; for (int i = 0, j = -1; i < static_cast(CubicModeGridLength); i++, j++) { auto orig_data = GetDataForCoordinate(Xdata, x + j, y, input_height, input_width); - result += coeff_array[i]/coeff_sum * orig_data; + result += coeff_array[i] / coeff_sum * orig_data; } cache[grid_start_pos] = result; @@ -448,6 +448,8 @@ void ResizeBiCubic( int64_t num_channels, int64_t input_height, int64_t input_width, + int64_t output_height, + int64_t output_width, float height_scale, float width_scale, float cubic_coeff_a, @@ -458,9 +460,6 @@ void ResizeBiCubic( const T* Xdata, T* Ydata, GetOriginalCoordinateFunc get_original_coordinate) { - auto output_width = static_cast(input_width * width_scale); - auto output_height = static_cast(input_height * height_scale); - std::vector y_original; std::vector x_original; std::unordered_map> cubic_coeffs; @@ -582,11 +581,17 @@ void ResizeBiCubic( } template -Status Upsample::BaseCompute(OpKernelContext* context, const std::vector& scales, const std::vector& roi) const { +Status Upsample::BaseCompute(OpKernelContext* context, + const std::vector& roi, + const std::vector& scales, + const std::vector& output_dims) const { const auto* X = context->Input(0); ORT_ENFORCE(X != nullptr); - const std::vector& dims = X->Shape().GetDims(); + ORT_ENFORCE(output_dims.size() == dims.size(), "Rank of input and output tensor should be same."); + + Tensor* Y = context->Output(0, output_dims); + if (dims.size() != scales.size()) return Status(ONNXRUNTIME, INVALID_ARGUMENT, is_resize ? "Resize: input tensor's dimension does not match the scales." @@ -597,14 +602,9 @@ Status Upsample::BaseCompute(OpKernelContext* context, const std::vector Y_dims; - Y_dims.reserve(dims.size()); - for (std::size_t i = 0; i < dims.size(); i++) { - int64_t dim_y = static_cast(scales[i] * dims[i]); - if (no_scale && dim_y != dims[i]) no_scale = false; - Y_dims.push_back(dim_y); + for (std::size_t i = 0, end = output_dims.size(); i < end; i++) { + if (no_scale && output_dims[i] != dims[i]) no_scale = false; } - Tensor* Y = context->Output(0, Y_dims); if (no_scale) { memcpy(Y->MutableDataRaw(), X->DataRaw(), Y->SizeInBytes()); @@ -632,10 +632,12 @@ Status Upsample::BaseCompute(OpKernelContext* context, const std::vectorGetTempSpaceAllocator(&alloc)); - UpsampleBilinear(batch_size, num_channels, input_height, input_width, + UpsampleBilinear(batch_size, num_channels, input_height, input_width, output_height, output_width, is_2D ? scales[0] : scales[2], is_2D ? scales[1] : scales[3], roi, use_extrapolation_, extrapolation_value_, X->template Data(), Y->template MutableData(), alloc, get_original_coordinate_); @@ -647,8 +649,10 @@ Status Upsample::BaseCompute(OpKernelContext* context, const std::vectortemplate Data(), Y->template MutableData(), get_original_coordinate_); @@ -664,36 +668,7 @@ Status Upsample::Compute(OpKernelContext* context) const { const auto* X = context->Input(0); ORT_ENFORCE(X != nullptr); - if (OpKernel::Node().InputDefs().size() == 1) { - std::vector roi_array(X->Shape().GetDims().size() * 2, 0.0f); - return BaseCompute(context, scales_, roi_array); - } - - // Both Roi and Scales are constant inputs - if (roi_cached_ && scales_cached_) { - return BaseCompute(context, scales_, roi_); - } - - // Get scales data - std::vector scales_array; - const std::vector* scales_ptr = scales_cached_ ? &scales_ : &scales_array; - - if (!scales_cached_) { - const auto* scales = context->Input(scales_input_idx_); - const auto* sizes = context->Input(sizes_input_idx_); - ORT_ENFORCE(scales != nullptr); - - // User must provide either the scales or sizes - if (scales->Shape().Size() == 0) { - ORT_ENFORCE(sizes != nullptr && sizes->Shape().Size() != 0, - "Either scales input or sizes input must be provided and the number of elements of scales or sizes should be the same as the rank of the input."); - - ParseScalesDataFromSizes(sizes, X->Shape().GetDims(), scales_array); - } else { - ORT_ENFORCE(sizes == nullptr); - ParseScalesData(scales, scales_array); - } - } + std::vector output_dims(X->Shape().GetDims().size()); // Get roi data // Initialize the roi array to all zeros as this will be the most common case @@ -714,6 +689,47 @@ Status Upsample::Compute(OpKernelContext* context) const { } } - return BaseCompute(context, *scales_ptr, *roi_ptr); + if (OpKernel::Node().InputDefs().size() == 1) { + // Compute output shape from scales and input dims + ComputeOutputShape(scales_, X->Shape().GetDims(), output_dims); + return BaseCompute(context, *roi_ptr, scales_, output_dims); + } + + const auto* scales = context->Input(scales_input_idx_); + const auto* sizes = context->Input(sizes_input_idx_); + ORT_ENFORCE(scales != nullptr); + + if (scales_cached_) { + ORT_ENFORCE(sizes == nullptr, "Only one of scales or sizes must be provided as input."); + + // Compute output shape from scales and input dims + ComputeOutputShape(scales_, X->Shape().GetDims(), output_dims); + return BaseCompute(context, *roi_ptr, scales_, output_dims); + } + + // Get scales data + std::vector scales_array(X->Shape().GetDims().size()); + + if (scales != nullptr && scales->Shape().Size() != 0) { + ORT_ENFORCE(sizes == nullptr, + "Only one of scales or sizes must be provided as input."); + ParseScalesData(scales, scales_array); + + // Compute output shape from scales and input dims + ComputeOutputShape(scales_array, X->Shape().GetDims(), output_dims); + } else { + ORT_ENFORCE(sizes != nullptr && sizes->Shape().Size() != 0, + "Either scales or sizes MUST be provided as input."); + + // When sizes input is available directly populate it into the output_dims array. + memcpy(output_dims.data(), sizes->template Data(), sizes->Shape().Size() * sizeof(int64_t)); + + ORT_ENFORCE(X->Shape().GetDims().size() == output_dims.size(), + "Resize: input tensor's rank does not match the output tensor's rank."); + + ParseScalesDataFromOutputSize(output_dims, X->Shape().GetDims(), scales_array); + } + + return BaseCompute(context, *roi_ptr, scales_array, output_dims); } } // namespace onnxruntime diff --git a/onnxruntime/core/providers/cpu/tensor/upsample.h b/onnxruntime/core/providers/cpu/tensor/upsample.h index 10f725cc7c..4beef0ffd6 100644 --- a/onnxruntime/core/providers/cpu/tensor/upsample.h +++ b/onnxruntime/core/providers/cpu/tensor/upsample.h @@ -216,7 +216,7 @@ class UpsampleBase { if (UpsampleMode::LINEAR == mode || UpsampleMode::CUBIC == mode) { ORT_ENFORCE(scales.size() == 2 || (scales.size() == 4 && scales[0] == 1 && scales[1] == 1), - "'Linear' mode only support 2-D inputs ('Bilinear') or 4-D inputs " + "'Linear' mode and 'Cubic' mode only support 2-D inputs ('Bilinear', 'Bicubic') or 4-D inputs " "with the corresponding outermost 2 scale values being 1 in the ", is_resize ? "Resize operator" : "Upsample operator"); } @@ -233,18 +233,6 @@ class UpsampleBase { ScalesValidation(scales, mode_); } - void ParseScalesDataFromSizes(const Tensor* sizes, const std::vector& dims, std::vector& scales) const { - const auto* sizes_data = sizes->template Data(); - int64_t scales_size = sizes->Shape().Size(); - if (scales.empty()) { - scales.resize(scales_size); - } - for (size_t i = 0, end = dims.size(); i < end; ++i) { - scales[i] = static_cast(sizes_data[i]) / static_cast(dims[i]); - } - ScalesValidation(scales, mode_); - } - void ParseRoiData(const Tensor* roi, std::vector& roi_array) const { int64_t roi_size = roi->Shape().Size(); if (roi_size > 0) { @@ -252,6 +240,23 @@ class UpsampleBase { memcpy(roi_array.data(), roi->template Data(), roi_size * sizeof(float)); } } + + void ParseScalesDataFromOutputSize(const std::vector& output_dims, + const std::vector& intput_dims, + std::vector& scales) const { + for (size_t i = 0, end = intput_dims.size(); i < end; ++i) { + scales[i] = static_cast(output_dims[i]) / static_cast(intput_dims[i]); + } + ScalesValidation(scales, mode_); + } + + void ComputeOutputShape(const std::vector& scales, + const std::vector& input_dims, + std::vector& output_dims) const { + for (std::size_t i = 0; i < input_dims.size(); i++) { + output_dims[i] = static_cast(scales[i] * input_dims[i]); + } + } }; template @@ -262,7 +267,8 @@ class Upsample : public UpsampleBase, public OpKernel { Status Compute(OpKernelContext* context) const override; - Status BaseCompute(OpKernelContext* context, const std::vector& scales, const std::vector& roi) const; + Status BaseCompute(OpKernelContext* context, const std::vector& roi, const std::vector& scales, + const std::vector& output_dims) const; }; } // namespace onnxruntime diff --git a/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc b/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc index c0ec4cd294..5076734106 100644 --- a/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc +++ b/onnxruntime/test/providers/cpu/tensor/resize_op_test.cc @@ -61,7 +61,7 @@ TEST(ResizeOpTest, ResizeOpLinearDownSampleTest_tf_crop_and_resize_with_extrapol 12.4f, 10.f, 10.0f, 10.0f, 10.0f, 10.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -83,7 +83,7 @@ TEST(ResizeOpTest, ResizeOpLineartDownSampleTest_4DBilinear) { std::vector Y = {2.66666651f, 4.3333331f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -106,7 +106,7 @@ TEST(ResizeOpTest, ResizeOpLineartDownSampleTest_4DBilinear_align_corners) { std::vector Y = {1.0f, 4.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -169,7 +169,7 @@ TEST(ResizeOpTest, ResizeOpLineartUpSampleTest_4DBilinear_asymmetric) { 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 11.0f, 11.0f, 11.0f, 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 11.0f, 11.0f, 11.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -194,7 +194,7 @@ TEST(ResizeOpTest, ResizeOpLineartUpSampleTest_2DBilinear_align_corners) { 3.0f, 3.4761906f, 3.952381f, 4.428571f, 4.904762f, 5.3809524f, 5.857143f, 6.33333f, 4.0f, 4.5714290f, 5.142857f, 5.714286f, 6.285714f, 6.8571430f, 7.428571f, 8.0f}; - test.AddOutput("Y", {(int64_t)(H * scales[0]), (int64_t)(W * scales[1])}, Y); + test.AddOutput("Y", {static_cast(H * scales[0]), static_cast(W * scales[1])}, Y); test.Run(); } @@ -243,7 +243,7 @@ TEST(ResizeOpTest, ResizeOpNearestDownSampleTest) { std::vector Y = {1.0f, 3.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -325,7 +325,7 @@ TEST(ResizeOpTest, ResizeOpNearestDownSampleTest_tf_crop_and_resize_with_extrapo 11.0f, 10.f, 10.0f, 10.0f, 10.0f, 10.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -348,7 +348,7 @@ TEST(ResizeOpTest, ResizeOpNearestUpSampleTest) { 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f, 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -411,7 +411,7 @@ TEST(ResizeOpTest, ResizeOpNearestUpSample_Floor_Align_Corners) { 9.0f, 9.0f, 9.0f, 10.0f, 10.0f, 11.0f, 11.0f, 12.0f, 13.0f, 13.0f, 13.0f, 14.0f, 14.0f, 15.0f, 15.0f, 16.0f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -437,7 +437,7 @@ TEST(ResizeOpTest, ResizeOpCubicDownSampleTest) { 6.71143f, 8.02148f, 9.32275f, 11.9165f, 13.2266f, 14.5278f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -467,7 +467,7 @@ TEST(ResizeOpTest, ResizeOpLineartDownSampleTest_exclude_outside) { 6.57363f, 7.875f, 9.21884f, 11.949f, 13.2503f, 14.5942f}; - test.AddOutput("Y", {(int64_t)(H * scales[0]), (int64_t)(W * scales[1])}, Y); + test.AddOutput("Y", {static_cast(H * scales[0]), static_cast(W * scales[1])}, Y); test.Run(); } @@ -494,7 +494,7 @@ TEST(ResizeOpTest, ResizeOpCubicDownSampleTest_coeff) { 6.57715f, 7.875f, 9.19824f, 11.8701f, 13.168f, 14.4912f,}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -521,7 +521,7 @@ TEST(ResizeOpTest, ResizeOpCubicDownSampleTest_with_roi) { 8.752f, 9.14275f, 9.496f, 9.76f, 10.1507f, 10.504f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -548,7 +548,7 @@ TEST(ResizeOpTest, ResizeOpCubicDownSampleTest_asymmetric) { 6.1875f, 7.48438f, 8.78125f, 11.375f, 12.6719f, 13.9688f}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -580,7 +580,7 @@ TEST(ResizeOpTest, ResizeOpCubicUpSampleTest) { 13.0f, 13.4063f, 14.0f, 14.5f, 15.0f, 15.5938f, 16.0f, 16.0938f, 13.375f, 13.7813f, 14.375f, 14.875f, 15.375f, 15.9688f, 16.375f, 16.4688f,}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); test.Run(); } @@ -661,7 +661,183 @@ TEST(ResizeOpTest, ResizeOpCubicUpSampleTest_tf_half_pixel_for_nn) { 13.6133f, 14.0898f, 14.7188f, 15.125f, 15.7539f, 16.2305f, 16.5273f, 16.457f, 13.332f, 13.8086f, 14.4375f, 14.8438f, 15.4727f, 15.9492f, 16.2461f, 16.1758f,}; - test.AddOutput("Y", {N, C, (int64_t)(H * scales[2]), (int64_t)(W * scales[3])}, Y); + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpLineartDownSampleTest_4DBilinear_Ver10) { + OpTester test("Resize", 10); + std::vector scales{1.0f, 1.0f, 0.6f, 0.6f}; + + test.AddAttribute("mode", "linear"); + + const int64_t N = 1, C = 1, H = 2, W = 4; + std::vector X = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f}; + + test.AddInput("X", {N, C, H, W}, X); + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.0f, 2.66666651f}; + + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpLineartDownSampleTest_2DBilinear_Ver10) { + OpTester test("Resize", 10); + std::vector scales{0.6f, 0.6f}; + + test.AddAttribute("mode", "linear"); + + const int64_t H = 2, W = 4; + std::vector X = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f}; + + test.AddInput("X", {H, W}, X); + test.AddInput("scales", {2}, scales); + + std::vector Y = {1.0f, 2.66666651f}; + + test.AddOutput("Y", {static_cast(H * scales[0]), static_cast(W * scales[1])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpLineartUpSampleTest_4DBilinear_Ver10) { + OpTester test("Resize", 10); + std::vector scales{1.0f, 1.0f, 2.0f, 4.0f}; + test.AddAttribute("mode", "linear"); + + const int64_t N = 2, C = 1, H = 2, W = 2; + std::vector X = {1.0f, 3.0f, + 4.0f, 8.0f, + + 6.0f, 2.0f, + 7.0f, 11.0f}; + + test.AddInput("X", {N, C, H, W}, X); + test.AddInput("scales", {4}, scales); + + std::vector Y = { + 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.0f, 3.0f, 3.0f, + 2.5f, 3.25f, 4.0f, 4.75f, 5.5f, 5.5f, 5.5f, 5.5f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 8.0f, 8.0f, 8.0f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 8.0f, 8.0f, 8.0f, + + 6.0f, 5.0f, 4.0f, 3.0f, 2.0f, 2.0f, 2.0f, 2.0f, + 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, 6.5f, + 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 11.0f, 11.0f, 11.0f, + 7.0f, 8.0f, 9.0f, 10.0f, 11.0f, 11.0f, 11.0f, 11.0f}; + + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpLineartUpSampleTest_2DBilinear_Ver10) { + OpTester test("Resize", 10); + std::vector scales{2.0f, 4.0f}; + test.AddAttribute("mode", "linear"); + + const int64_t H = 2, W = 2; + std::vector X = {1.0f, 3.0f, + 4.0f, 8.0f}; + + test.AddInput("X", {H, W}, X); + test.AddInput("scales", {2}, scales); + + std::vector Y = { + 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.0f, 3.0f, 3.0f, + 2.5f, 3.25f, 4.0f, 4.75f, 5.5f, 5.5f, 5.5f, 5.5f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 8.0f, 8.0f, 8.0f, + 4.0f, 5.0f, 6.0f, 7.0f, 8.0f, 8.0f, 8.0f, 8.0f}; + + test.AddOutput("Y", {static_cast(H * scales[0]), static_cast(W * scales[1])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpLineartScalesNoOpTest_Ver10) { + OpTester test("Resize", 10); + std::vector scales{1.0f, 1.0f, 1.0f, 1.0f}; + test.AddAttribute("mode", "linear"); + + const int64_t N = 2, C = 1, H = 2, W = 2; + std::vector X = {1.0f, 3.0f, + 4.0f, 8.0f, + + 6.0f, 2.0f, + 7.0f, 11.0f}; + + test.AddInput("X", {N, C, H, W}, X); + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.0f, 3.0f, + 4.0f, 8.0f, + + 6.0f, 2.0f, + 7.0f, 11.0f}; + + test.AddOutput("Y", {N, C, H, W}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpNearestDownSampleTest_Ver10) { + OpTester test("Resize", 10); + std::vector scales{1.0f, 1.0f, 0.6f, 0.6f}; + + test.AddAttribute("mode", "nearest"); + + const int64_t N = 1, C = 1, H = 2, W = 4; + std::vector X = { + 1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f}; + + test.AddInput("X", {N, C, H, W}, X); + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.0f, 3.0f}; + + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + +TEST(ResizeOpTest, ResizeOpNearestUpSampleTest_Ver10) { + OpTester test("Resize", 10); + std::vector scales{1.0f, 1.0f, 2.0f, 3.0f}; + + test.AddAttribute("mode", "nearest"); + + const int64_t N = 1, C = 1, H = 2, W = 2; + std::vector X = {1.0f, 2.0f, 3.0f, 4.0f}; + + test.AddInput("X", {N, C, H, W}, X); + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, + 1.0f, 1.0f, 1.0f, 2.0f, 2.0f, 2.0f, + 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f, + 3.0f, 3.0f, 3.0f, 4.0f, 4.0f, 4.0f}; + + test.AddOutput("Y", {N, C, static_cast(H * scales[2]), static_cast(W * scales[3])}, Y); + test.Run(); +} + +TEST(UpsampleOpTest, ResizeOpNearestNoScaleTest_Ver10) { + OpTester test("Resize", 10); + std::vector scales{1.0f, 1.0f, 1.0f, 1.0f}; + + test.AddAttribute("mode", "nearest"); + + const int64_t N = 1, C = 1, H = 2, W = 2; + std::vector X = {1.0f, 2.0f, 3.0f, 4.0f}; + + test.AddInput("X", {N, C, H, W}, X); + test.AddInput("scales", {4}, scales); + + std::vector Y = {1.0f, 2.0f, 3.0f, 4.0f}; + + test.AddOutput("Y", {N, C, H, W}, Y); test.Run(); }