Skip to content
Snippets Groups Projects
Commit 2d7efcd3 authored by Maxence Naud's avatar Maxence Naud Committed by Olivier BICHLER
Browse files

Fix 'Nearest' interpolation mode and add a test

parent e7e7ac2a
No related branches found
No related tags found
2 merge requests!118v0.4.0,!104update Resize operator
Pipeline #60211 failed
This commit is part of merge request !104. Comments created here will be created in the context of that merge request.
......@@ -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
......
......@@ -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>,
......
/********************************************************************************
* 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;
......
......@@ -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.);
}
}
}
......
......@@ -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,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment