diff --git a/include/aidge/backend/cpu/data/Interpolation.hpp b/include/aidge/backend/cpu/data/Interpolation.hpp index 9745059e54b967ad102f4176e12a45132df736a0..5909f02a190f4e10cdeb878505fdfea1a17e2d75 100644 --- a/include/aidge/backend/cpu/data/Interpolation.hpp +++ b/include/aidge/backend/cpu/data/Interpolation.hpp @@ -96,7 +96,7 @@ class InterpolationCPU : public Interpolation { * - Split all points along each dimension depending of if their coords at * idx alongDim are above or under coordsToInterpolate until they are * 1-to-1. - * - Perform interpolation in 2 leftover points and return interpolated + * - Perform interpolation in 2 leftover points and return interpolated * point to parent call with a set of size 1. * - repeat until all dimensions have been interpolated. * @param[in]Â coordsToInterpolate: coordinates to interpolate diff --git a/include/aidge/backend/cpu/operator/ResizeImpl_kernels.hpp b/include/aidge/backend/cpu/operator/ResizeImpl_kernels.hpp index 94efc9cb03345963e29b78a252ef82797d59fcf5..6a22ff4ec9d7beaf05be3b479b43dd3ad69bc74b 100644 --- a/include/aidge/backend/cpu/operator/ResizeImpl_kernels.hpp +++ b/include/aidge/backend/cpu/operator/ResizeImpl_kernels.hpp @@ -28,6 +28,7 @@ #include "aidge/utils/Types.h" namespace Aidge { + template <typename IO> void ResizeImpl_cpu_forward_kernel( const void *input_, @@ -49,23 +50,52 @@ void ResizeImpl_cpu_forward_kernel( outputDims.cend(), 1, std::multiplies<DimSize_t>()); - std::vector<float> coordInApprox; + std::vector<float> coordInApprox(inputDims.size()); + std::vector<std::size_t> coordIn(inputDims.size()); std::vector<DimSize_t> coordOut; for (DimSize_t idxFlatOut = 0; idxFlatOut < outputLen; ++idxFlatOut) { - coordOut = Tensor::getCoord(outputDims, idxFlatOut); + coordOut = Tensor::toCoord(outputDims, idxFlatOut); coordInApprox = Interpolation::untransformCoordinates(coordOut, inputDims, outputDims, coordTransfoMode); - std::set<Interpolation::Point<IO>> neighbours = - InterpolationCPU::retrieveNeighbours(input, - inputDims, - coordInApprox, - paddingMode); - output[idxFlatOut] = InterpolationCPU::interpolate(coordInApprox, - neighbours, - interpMode); + if ((interpMode == Interpolation::Mode::Ceil) || (interpMode == Interpolation::Mode::Floor) || (interpMode == Interpolation::Mode::RoundPreferCeil) || (interpMode == Interpolation::Mode::RoundPreferFloor)) { + for (std::size_t i = 0; i < coordInApprox.size(); ++i) { + if (interpMode == Interpolation::Mode::Ceil) { + coordInApprox[i] = std::ceil(coordInApprox[i]); + } else if (interpMode == Interpolation::Mode::Floor) { + coordInApprox[i] = std::floor(coordInApprox[i]); + } else if (interpMode == Interpolation::Mode::RoundPreferCeil) { + coordInApprox[i] = std::floor(coordInApprox[i] + 0.5f); + } else { // (interpMode == Interpolation::Mode::RoundPreferFloor) + coordInApprox[i] = std::ceil(coordInApprox[i] - 0.5f); + } + } + if (Tensor::isInBounds<float>(inputDims, coordInApprox)) { + for (std::size_t i = 0; i < coordInApprox.size(); ++i) { + coordIn[i] = static_cast<std::size_t>(coordInApprox[i]); + } + } else { + if (paddingMode == PadBorderType::Edge) { + for (std::size_t i = 0; i < coordInApprox.size(); ++i) { + coordIn[i] = coordInApprox[i] < 0 ? 0 : (coordInApprox[i] >=inputDims[i] ? inputDims[i] - 1 : static_cast<std::size_t>(coordInApprox[i])); + } + } else { + AIDGE_THROW_OR_ABORT(std::runtime_error, "Padding mode not supported"); + } + } + output[idxFlatOut] = input[Tensor::toIndex(inputDims, coordIn)]; + } else { + std::set<Interpolation::Point<IO>> neighbours = + InterpolationCPU::retrieveNeighbours(input, + inputDims, + coordInApprox, + paddingMode); + output[idxFlatOut] = InterpolationCPU::interpolate(coordInApprox, + neighbours, + interpMode); + } } return; } @@ -74,7 +104,7 @@ REGISTRAR(ResizeImpl_cpu, {{{DataType::Int16}, {DataType::Float32}, {DataType::Float32}, - {DataType::Int64}}, + {DataType::UInt64}}, {DataType::Int16}}, {ProdConso::inPlaceModel, ResizeImpl_cpu_forward_kernel<int16_t>, @@ -83,7 +113,7 @@ REGISTRAR(ResizeImpl_cpu, {{{DataType::Int32}, {DataType::Float32}, {DataType::Float32}, - {DataType::Int64}}, + {DataType::UInt64}}, {DataType::Int32}}, {ProdConso::inPlaceModel, ResizeImpl_cpu_forward_kernel<int32_t>, @@ -93,7 +123,7 @@ REGISTRAR(ResizeImpl_cpu, {DataType::Float32}, {DataType::Float32}, {DataType::Int64}}, - {DataType::Int64}}, + {DataType::UInt64}}, {ProdConso::inPlaceModel, ResizeImpl_cpu_forward_kernel<int64_t>, nullptr}); @@ -102,7 +132,7 @@ REGISTRAR(ResizeImpl_cpu, {{{DataType::Float16}, {DataType::Float32}, {DataType::Float32}, - {DataType::Int64}}, + {DataType::UInt64}}, {DataType::Float16}}, {ProdConso::inPlaceModel, ResizeImpl_cpu_forward_kernel<half_float::half>, @@ -111,7 +141,7 @@ REGISTRAR(ResizeImpl_cpu, {{{DataType::Float32}, {DataType::Float32}, {DataType::Float32}, - {DataType::Int64}}, + {DataType::UInt64}}, {DataType::Float32}}, {ProdConso::inPlaceModel, ResizeImpl_cpu_forward_kernel<float>, @@ -120,7 +150,7 @@ REGISTRAR(ResizeImpl_cpu, {{{DataType::Float64}, {DataType::Float32}, {DataType::Float32}, - {DataType::Int64}}, + {DataType::UInt64}}, {DataType::Float64}}, {ProdConso::inPlaceModel, ResizeImpl_cpu_forward_kernel<double>, diff --git a/src/data/Interpolation.cpp b/src/data/Interpolation.cpp index c5a881bd8bfd4b51a3b9032d809bd158d089e6ed..40fa19155974735cc351b23cb6e68cb851fd11b5 100644 --- a/src/data/Interpolation.cpp +++ b/src/data/Interpolation.cpp @@ -1,3 +1,14 @@ +/******************************************************************************** + * Copyright (c) 2024 CEA-List + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * SPDX-License-Identifier: EPL-2.0 + * + ********************************************************************************/ + #include "aidge/backend/cpu/data/Interpolation.hpp" #include <aidge/utils/Log.hpp> @@ -212,26 +223,26 @@ T InterpolationCPU::nearest(const std::vector<float> &coordsToInterpolate, points.begin()->first); std::function<int64_t(const float &)> updateCoordinates; switch (nearestMode) { - case Interpolation::Mode::NearestCeil: { + case Interpolation::Mode::Ceil: { updateCoordinates = [](const float &coord) -> int64_t { return ceil(coord); }; break; } - case Interpolation::Mode::NearestFloor: { + case Interpolation::Mode::Floor: { updateCoordinates = [](const float &coord) -> int64_t { return floor(coord); }; break; } - case Interpolation::Mode::NearestRoundPreferFloor: { + case Interpolation::Mode::RoundPreferFloor: { updateCoordinates = [](const float &coord) -> int64_t { return (coord - floor(coord)) == 0.5 ? floor(coord) : std::round(coord); }; break; } - case Interpolation::Mode::NearestRoundPreferCeil: { + case Interpolation::Mode::RoundPreferCeil: { updateCoordinates = [](const float &coord) -> int64_t { return (coord - floor(coord)) == 0.5 ? ceil(coord) : std::round(coord); @@ -243,12 +254,12 @@ T InterpolationCPU::nearest(const std::vector<float> &coordsToInterpolate, std::runtime_error, "Invalid Interpolation mode for " "InterpolationCPU::interpolateNearest. Accepted modes are : " - "NearestCeil({}),NearestFloor({}),NearestRoundPreferCeil({}), " - "NearestRoundPreferFloor({}). Got {}.", - static_cast<int>(NearestCeil), - static_cast<int>(NearestFloor), - static_cast<int>(NearestRoundPreferCeil), - static_cast<int>(NearestRoundPreferFloor), + "Ceil({}),Floor({}),RoundPreferCeil({}), " + "RoundPreferFloor({}). Got {}.", + static_cast<int>(Ceil), + static_cast<int>(Floor), + static_cast<int>(RoundPreferCeil), + static_cast<int>(RoundPreferFloor), static_cast<int>(nearestMode)); } } @@ -292,10 +303,10 @@ T InterpolationCPU::interpolate(const std::vector<float> &coordsToInterpolate, return linear(coordsToInterpolate, points); break; } - case Interpolation::Mode::NearestCeil: - case Interpolation::Mode::NearestFloor: - case Interpolation::Mode::NearestRoundPreferFloor: - case Interpolation::Mode::NearestRoundPreferCeil: { + case Interpolation::Mode::Ceil: + case Interpolation::Mode::Floor: + case Interpolation::Mode::RoundPreferFloor: + case Interpolation::Mode::RoundPreferCeil: { result = InterpolationCPU::nearest(coordsToInterpolate, points, interpMode); break; diff --git a/unit_tests/data/Test_Interpolation.cpp b/unit_tests/data/Test_Interpolation.cpp index 9fb36cf285d5c4d674a582f365321f37dc007fc6..5c3b56f02ab17092a6ba238cc74e1bf75e203718 100644 --- a/unit_tests/data/Test_Interpolation.cpp +++ b/unit_tests/data/Test_Interpolation.cpp @@ -138,29 +138,29 @@ TEST_CASE("Interpolation", "[Interpolation][Data]") { {{3}, 4.0F}, {{4}, 5.0F}}; - SECTION("NearestFloor") { + SECTION("Floor") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestFloor) == 1); + Interpolation::Mode::Floor) == 1); } - SECTION("NearestCeil") { + SECTION("Ceil") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestCeil) == 2); + Interpolation::Mode::Ceil) == 2); } - SECTION("NearestRoundPreferFloor") { + SECTION("RoundPreferFloor") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestRoundPreferFloor) == 1); + Interpolation::Mode::RoundPreferFloor) == 1); } - SECTION("NearestRoundPreferCeil") { + SECTION("RoundPreferCeil") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestRoundPreferCeil) == 2); + Interpolation::Mode::RoundPreferCeil) == 2); } } SECTION("2D") { @@ -171,30 +171,30 @@ TEST_CASE("Interpolation", "[Interpolation][Data]") { {{2, 4}, 40.0}, {{3, 3}, 50.0}, {{3, 4}, 60.0}}; - SECTION("NearestFloor") { + SECTION("Floor") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestFloor) == 30.); + Interpolation::Mode::Floor) == 30.); } - SECTION("NearestCeil") { + SECTION("Ceil") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestCeil) == 60.); + Interpolation::Mode::Ceil) == 60.); } - SECTION("NearestRoundPreferFloor") { + SECTION("RoundPreferFloor") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestRoundPreferFloor) == + Interpolation::Mode::RoundPreferFloor) == 40.); } - SECTION("NearestRoundPreferCeil") { + SECTION("RoundPreferCeil") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestRoundPreferCeil) == 60.); + Interpolation::Mode::RoundPreferCeil) == 60.); } } SECTION("3D") { @@ -206,30 +206,30 @@ TEST_CASE("Interpolation", "[Interpolation][Data]") { {{2, 3, 3}, 40.0}, {{2, 3, 4}, 50.0}, {{3, 3, 4}, 60.0}}; - SECTION("NearestFloor") { + SECTION("Floor") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestFloor) == 10.); + Interpolation::Mode::Floor) == 10.); } - SECTION("NearestCeil") { + SECTION("Ceil") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestCeil) == 50.); + Interpolation::Mode::Ceil) == 50.); } - SECTION("NearestRoundPreferFloor") { + SECTION("RoundPreferFloor") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestRoundPreferFloor) == + Interpolation::Mode::RoundPreferFloor) == 30.); } - SECTION("NearestRoundPreferCeil") { + SECTION("RoundPreferCeil") { CHECK(InterpolationCPU::nearest( coordToInterpolate, pointsToInterpolate, - Interpolation::Mode::NearestRoundPreferCeil) == 30.); + Interpolation::Mode::RoundPreferCeil) == 30.); } } } diff --git a/unit_tests/operator/Test_ResizeImpl.cpp b/unit_tests/operator/Test_ResizeImpl.cpp index 161a50946d58f086fa6f4b6fcf7326a4c9c0a1cb..6b3520fc88d36660ff44403bd41a47cd7ed96256 100644 --- a/unit_tests/operator/Test_ResizeImpl.cpp +++ b/unit_tests/operator/Test_ResizeImpl.cpp @@ -26,84 +26,70 @@ namespace Aidge { -void setupTestResize(std::shared_ptr<Resize_Op> op, - Interpolation::Mode interpMode, - Interpolation::CoordinateTransformation coordTransfoMode, - PadBorderType paddingMode, - std::shared_ptr<Tensor> input, - std::shared_ptr<Tensor> roi, - std::shared_ptr<Tensor> scales, - std::shared_ptr<Tensor> sizes) { - - //////////////////////////////////// - // attributes - op->interpolationMode() = interpMode; - op->coordinateTransformationMode() = coordTransfoMode; - op->paddingMode() = paddingMode; - - //////////////////////////////////// - // op backend & inputs - op->setBackend("cpu"); +TEST_CASE("[cpu/operator] Resize(forward)", "[Resize][CPU]") { - input->setBackend("cpu"); - op->associateInput(0, input); + Log::setConsoleLevel(Log::Level::Debug); - if (scales != nullptr) { - scales->setBackend("cpu"); - op->associateInput(2, scales); - if (roi != nullptr) { - roi->setBackend("cpu"); - op->associateInput(1, roi); + SECTION("Nearest") { + SECTION("Ceil") { + std::shared_ptr<Tensor> input_tensor = std::make_shared<Tensor>(Array4D<std::int32_t, 1, 1, 2, 2>{{ + { + { + { 1, 2}, + { 3, 4} + } + } + }}); + Tensor expected_out_tensor = Tensor(Array4D<std::int32_t, 1, 1, 4, 4>{{ + { + { + { 1, 1, 1, 2}, + { 1, 1, 1, 2}, + { 1, 1, 1, 2}, + { 3, 3, 3, 4} + } + } + }}); + + std::vector<float> scales = {1.0f, 1.0f, 2.0f, 2.0f}; + auto resize_node = Resize(scales, {}, Interpolation::CoordinateTransformation::HalfPixel, Interpolation::Mode::Floor); + auto op = std::static_pointer_cast<Resize_Op>(resize_node->getOperator()); + op->associateInput(0, input_tensor); + + + op->setDataType(DataType::Int32); + op->setBackend("cpu"); + op->forwardDims(true); + op->forward(); + + op->getOutput(0)->print(); + expected_out_tensor.print(); + + CHECK(*(op->getOutput(0)) == expected_out_tensor); } - } else if (sizes != nullptr) { - sizes->setBackend("cpu"); - op->associateInput(3, sizes); - } else { - Log::warn("Test Resize Impl : Neither scales nor sizes provided. test " - "is excpected to crash."); } -} -TEST_CASE("[cpu/operator] Resize(forward)", "[Resize][CPU]") { - - Log::setConsoleLevel(Log::Level::Debug); + SECTION("1-sized input tensor (upscaling)") { + std::shared_ptr<Tensor> input_tensor = std::make_shared<Tensor>(Array4D<float, 1, 1, 1, 1>{{{{{0.417022}}}}}); - std::shared_ptr<Node> node = Resize(); - auto op = std::static_pointer_cast<Resize_Op>(node->getOperator()); + std::vector<std::size_t> sizes = {1, 1, 2, 2}; + auto resize_node = Resize({}, sizes, Interpolation::CoordinateTransformation::HalfPixel, Interpolation::Mode::Linear); + auto op = std::static_pointer_cast<Resize_Op>(resize_node->getOperator()); + op->associateInput(0, input_tensor); - std::shared_ptr<Tensor> input; - std::shared_ptr<Tensor> roi; - std::shared_ptr<Tensor> scales; - std::shared_ptr<Tensor> sizes; - std::shared_ptr<Tensor> expectedOutput; - SECTION("1-sized input tensor (upscaling)") { - setupTestResize( - op, - Interpolation::Linear, - Interpolation::CoordinateTransformation::HalfPixel, - PadBorderType::Edge, - std::make_shared<Tensor>( - Array4D<float, 1, 1, 1, 1>{{{{{0.417022}}}}}), - nullptr, - nullptr, - std::make_shared<Tensor>(Array1D<int64_t, 4>{1, 1, 2, 2})); op->setDataType(DataType::Float32); + op->setBackend("cpu"); op->forwardDims(true); op->forward(); - expectedOutput = std::make_shared<Tensor>(Array4D<float, 1, 1, 2, 2>{ + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(Array4D<float, 1, 1, 2, 2>{ {{{{0.417022, 0.417022}, {0.417022, 0.417022}}}}}); op->getOutput(0)->print(); CHECK(approxEq<float>(*op->getOutput(0), *expectedOutput) == true); } SECTION("Upscaling from 5x5 to 10x10 (linear)") { - setupTestResize( - op, - Interpolation::Linear, - Interpolation::Asymmetric, - PadBorderType::Edge, - std::make_shared<Tensor>( - Array4D<float, 1, 1, 5, 5>{{{{{7.20324516e-01, + std::shared_ptr<Tensor> input_tensor = std::make_shared<Tensor>( + Array4D<float, 1, 1, 5, 5>{{{{{7.20324516e-01, 1.14374816e-04, 3.02332580e-01, 1.46755889e-01, @@ -128,15 +114,18 @@ TEST_CASE("[cpu/operator] Resize(forward)", "[Resize][CPU]") { 6.92322612e-01, 8.76389146e-01, 8.94606650e-01}}}}} + ); + + std::vector<std::size_t> sizes = {1, 1, 10, 10}; + auto resize_node = Resize({}, sizes, Interpolation::CoordinateTransformation::Asymmetric, Interpolation::Mode::Linear); + auto op = std::static_pointer_cast<Resize_Op>(resize_node->getOperator()); + op->associateInput(0, input_tensor); - ), - nullptr, - nullptr, - std::make_shared<Tensor>(Array1D<int64_t, 4>{1, 1, 10, 10})); op->setDataType(DataType::Float32); + op->setBackend("cpu"); op->forwardDims(true); op->forward(); - expectedOutput = std::make_shared<Tensor>( + std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>( Array4D<float, 1, 1, 10, 10>{{{{{7.20324516e-01, 3.60219449e-01, 1.14374816e-04,