Skip to content
Snippets Groups Projects
Commit f634dac0 authored by Maxence Naud's avatar Maxence Naud
Browse files

Merge branch 'feat_enhance_operator_resize_support' into 'dev'

update Resize operator

See merge request !104
parents 43268e1a 6a6d3f6a
No related branches found
No related tags found
2 merge requests!118v0.4.0,!104update Resize operator
Pipeline #60240 passed
...@@ -12,19 +12,14 @@ stages: ...@@ -12,19 +12,14 @@ stages:
- deploy - deploy
include: include:
- project: 'eclipse/aidge/gitlab_shared_files' - project: 'eclipse/aidge/gitlab_shared_files'
ref: 'main' ref: 'main'
file: file: # choose which jobs to run by including the corresponding files.
# choose which jobs to run by including the corresponding files.
- '.gitlab/ci/ubuntu_cpp.gitlab-ci.yml' - '.gitlab/ci/ubuntu_cpp.gitlab-ci.yml'
- '.gitlab/ci/ubuntu_python.gitlab-ci.yml' - '.gitlab/ci/ubuntu_python.gitlab-ci.yml'
- '.gitlab/ci/release/cibuildwheel_ubuntu.gitlab-ci.yml' - '.gitlab/ci/release/cibuildwheel_ubuntu.gitlab-ci.yml'
- '.gitlab/ci/windows_cpp.gitlab-ci.yml' - '.gitlab/ci/windows_cpp.gitlab-ci.yml'
- '.gitlab/ci/windows_python.gitlab-ci.yml'
- '.gitlab/ci/windows_python.gitlab-ci.yml' - '.gitlab/ci/release/cibuildwheel_windows.gitlab-ci.yml'
- '.gitlab/ci/release/cibuildwheel_windows.gitlab-ci.yml'
...@@ -22,6 +22,9 @@ execute_process( ...@@ -22,6 +22,9 @@ execute_process(
message(STATUS "Latest git commit: ${GIT_COMMIT_HASH}") message(STATUS "Latest git commit: ${GIT_COMMIT_HASH}")
add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}") add_definitions(-DGIT_COMMIT_HASH="${GIT_COMMIT_HASH}")
# helper for LSP users
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Note : project name is ${CMAKE_PROJECT_NAME} and python module name is also ${CMAKE_PROJECT_NAME} # Note : project name is ${CMAKE_PROJECT_NAME} and python module name is also ${CMAKE_PROJECT_NAME}
set(module_name _${CMAKE_PROJECT_NAME}) # target name set(module_name _${CMAKE_PROJECT_NAME}) # target name
set(pybind_module_name ${CMAKE_PROJECT_NAME}) # name of submodule for python bindings set(pybind_module_name ${CMAKE_PROJECT_NAME}) # name of submodule for python bindings
......
...@@ -40,6 +40,7 @@ ...@@ -40,6 +40,7 @@
#include "aidge/backend/cpu/operator/PowImpl.hpp" #include "aidge/backend/cpu/operator/PowImpl.hpp"
#include "aidge/backend/cpu/operator/ReduceMeanImpl.hpp" #include "aidge/backend/cpu/operator/ReduceMeanImpl.hpp"
#include "aidge/backend/cpu/operator/ReduceSumImpl.hpp" #include "aidge/backend/cpu/operator/ReduceSumImpl.hpp"
#include "aidge/backend/cpu/operator/ResizeImpl.hpp"
#include "aidge/backend/cpu/operator/ReLUImpl.hpp" #include "aidge/backend/cpu/operator/ReLUImpl.hpp"
#include "aidge/backend/cpu/operator/RoundImpl.hpp" #include "aidge/backend/cpu/operator/RoundImpl.hpp"
#include "aidge/backend/cpu/operator/ScalingImpl.hpp" #include "aidge/backend/cpu/operator/ScalingImpl.hpp"
......
/********************************************************************************
* 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
*
********************************************************************************/
#ifndef AIDGE_CPU_DATA_INTERPOLATION_H_
#define AIDGE_CPU_DATA_INTERPOLATION_H_
#include <vector>
#include <aidge/data/Interpolation.hpp>
#include <aidge/utils/Types.h>
namespace Aidge {
class InterpolationCPU : public Interpolation {
public:
/*
* @brief Interpolates values given via input in given mode.
*
* Values are contiguously arranged in a "square" shape around the point to
* interpolate. Depending on interpolation mode.
* The point that will be interpolated is located right in the
* middle of all points.
* Immediate neighbours :
* 1D interp : 2D interp :
* . . . . . .
* . . 1 2 . . . . . . . .
* . . 1 2 . .
* . . 3 4 . .
* . . . . . .
* . . . . . .
*
* 2 neighbours :
* 1D interp : 2D interp :
* . . . . . . . .
* . . . . . . . .
* . . 1 2 3 4 . . . . 1 2 3 4 . .
* . . 5 6 7 8 . .
* . . 9 10 11 12 . .
* . . 13 14 15 16 . .
* . . . . . . . .
* . . . . . . . .
*
* @param[in] originalCoords: coord of the point to interpolate in the
* original picture. These coords are generated with
* Interpolation::untransformCoords(coordsInInterpolatedTensor)
* @param[in] points : points to interpolate, arranged in a vector of a
* pairs ((point_coord), value) :
* [[[X1, X2, ..., XN], Xval], ...., [[A1, A2, ..., AN],Aval]].
* With :
* - N: the number of dimensions.
* - A: the number of points of the grid to interpolate.
* - All coordinates expressed in originalTensor frame.
* @param[in] interpMode: interpolation mode
* @return interpolated value
*/
template <typename T>
static T interpolate(const std::vector<float> &coordsToInterpolate,
const std::set<Point<T>> &points,
const Mode interpMode = Interpolation::Mode::Linear);
/**
* @brief performs linear interpolation on given points.
* @param[in] values: values to interpolate, since we only do an average of
* all values, their indexes isn't useful.
* @return interpolated value
*/
template <typename T>
static T linear(const std::vector<float> &originalCoords,
const std::set<Point<T>> &points);
/**
* @brief performs nearest interpolation on given points.
* @note it is a wrapper for linearRecurse() private method
* @param[in] coordsToInterpolate: coordinates to interpolate
* @param[in] points: points to interpolate
* @param[in] interpMode: interpolation method, must be a Nearest...
* otherwise function will throw an error.
* @return interpolated value
*/
template <typename T>
static T nearest(const std::vector<float> &coordsToInterpolate,
const std::set<Point<T>> &points,
const Interpolation::Mode nearestMode);
private:
/**
* @brief actual linear interpolation function.
* will :
* - 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
* point to parent call with a set of size 1.
* - repeat until all dimensions have been interpolated.
* @param[in] coordsToInterpolate: coordinates to interpolate
* @param[in] points: points to interpolate
* @param[in] alongDim: discriminant on along which dimension are being
* segregated.
* @return
*/
template <typename T>
static std::set<Interpolation::Point<T>>
linearRecurse(const std::vector<float> &coordsToInterpolate,
const std::set<Point<T>> &points,
const DimIdx_t alongDim = 0);
};
} // namespace Aidge
#endif // AIDGE_CPU_DATA_INTERPOLATION_H_
/********************************************************************************
* Copyright (c) 2023 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
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_RESIZEIMPL_H_
#define AIDGE_CPU_OPERATOR_RESIZEIMPL_H_
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/operator/Resize.hpp"
#include "aidge/utils/Registrar.hpp"
#include <aidge/data/Interpolation.hpp>
#include <aidge/operator/Pad.hpp>
#include <cstdint>
namespace Aidge {
// Operator implementation entry point for the backend
using ResizeImpl_cpu = OperatorImpl_cpu<
Resize_Op,
void(const void *, // input
const std::vector<DimSize_t> &, // INput dims
const std::vector<DimSize_t> &, // OUTput dims
const Interpolation::CoordinateTransformation, // coord transfo
const Interpolation::Mode, // interpolation mode
const PadBorderType, // padding mode
void *)>; // output
// Implementation entry point registration to Operator
REGISTRAR(Resize_Op, "cpu", Aidge::ResizeImpl_cpu::create);
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_RESIZEIMPL_H_ */
/********************************************************************************
* Copyright (c) 2023 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
*
********************************************************************************/
#ifndef AIDGE_CPU_OPERATOR_RESIZEIMPL_FORWARD_KERNEL_H_
#define AIDGE_CPU_OPERATOR_RESIZEIMPL_FORWARD_KERNEL_H_
#include "aidge/backend/cpu/operator/ResizeImpl.hpp"
#include <aidge/data/Data.hpp>
#include <aidge/data/half.hpp>
#include <aidge/operator/Pad.hpp>
#include <cmath>
#include <cstdint>
#include <numeric>
#include "aidge/backend/cpu/data/Interpolation.hpp"
#include "aidge/data/Interpolation.hpp"
#include "aidge/data/Tensor.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
template <typename IO>
void ResizeImpl_cpu_forward_kernel(
const void *input_,
const std::vector<DimSize_t> &inputDims,
const std::vector<DimSize_t> &outputDims,
const Interpolation::CoordinateTransformation coordTransfoMode,
const Interpolation::Mode interpMode,
const PadBorderType paddingMode,
// const double * /*roi*/,
// const float * /*scales*/,
// const int64_t * /*sizes*/,
void *output_) {
// Seting a data
const IO *input = static_cast<const IO *>(input_);
IO *output = static_cast<IO *>(output_);
const DimSize_t outputLen = std::accumulate(outputDims.cbegin(),
outputDims.cend(),
1,
std::multiplies<DimSize_t>());
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::toCoord(outputDims, idxFlatOut);
coordInApprox =
Interpolation::untransformCoordinates(coordOut,
inputDims,
outputDims,
coordTransfoMode);
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;
}
// Kernels registration to implementation entry point
REGISTRAR(ResizeImpl_cpu,
{{{DataType::Int16},
{DataType::Float32},
{DataType::Float32},
{DataType::UInt64}},
{DataType::Int16}},
{ProdConso::inPlaceModel,
ResizeImpl_cpu_forward_kernel<int16_t>,
nullptr});
REGISTRAR(ResizeImpl_cpu,
{{{DataType::Int32},
{DataType::Float32},
{DataType::Float32},
{DataType::UInt64}},
{DataType::Int32}},
{ProdConso::inPlaceModel,
ResizeImpl_cpu_forward_kernel<int32_t>,
nullptr});
REGISTRAR(ResizeImpl_cpu,
{{{DataType::Int64},
{DataType::Float32},
{DataType::Float32},
{DataType::Int64}},
{DataType::UInt64}},
{ProdConso::inPlaceModel,
ResizeImpl_cpu_forward_kernel<int64_t>,
nullptr});
REGISTRAR(ResizeImpl_cpu,
{{{DataType::Float16},
{DataType::Float32},
{DataType::Float32},
{DataType::UInt64}},
{DataType::Float16}},
{ProdConso::inPlaceModel,
ResizeImpl_cpu_forward_kernel<half_float::half>,
nullptr});
REGISTRAR(ResizeImpl_cpu,
{{{DataType::Float32},
{DataType::Float32},
{DataType::Float32},
{DataType::UInt64}},
{DataType::Float32}},
{ProdConso::inPlaceModel,
ResizeImpl_cpu_forward_kernel<float>,
nullptr});
REGISTRAR(ResizeImpl_cpu,
{{{DataType::Float64},
{DataType::Float32},
{DataType::Float32},
{DataType::UInt64}},
{DataType::Float64}},
{ProdConso::inPlaceModel,
ResizeImpl_cpu_forward_kernel<double>,
nullptr});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_RESIZEIMPL_FORWARD_KERNEL_H_ */
/********************************************************************************
* 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>
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <iterator>
#include <stdexcept>
#include <utility>
#include <vector>
#include <aidge/data/Interpolation.hpp>
#include <aidge/data/half.hpp>
#include <aidge/utils/ErrorHandling.hpp>
#include <aidge/utils/Types.h>
namespace Aidge {
template <typename T>
std::set<Interpolation::Point<T>>
InterpolationCPU::linearRecurse(const std::vector<float> &coordToInterpolate,
const std::set<Point<T>> &points,
const DimIdx_t alongDim) {
// all points have been discriminated properly along given dimension.
if (points.size() == 1) {
return points;
}
auto extractPtCoords = [](std::set<Point<T>> pts) -> std::set<Coords> {
std::set<Coords> result;
for (const auto &pt : pts) {
result.insert(pt.first);
}
return result;
};
///////////////////
// ERROR CHECKING
if (alongDim > coordToInterpolate.size() || points.size() == 0) {
// retrieving points coords as points values can be in half_float &
// this type is not fmt compatible
std::vector<Coords> pointsCoords;
for (const auto &point : points) {
pointsCoords.push_back(point.first);
}
AIDGE_ASSERT(
alongDim >= coordToInterpolate.size(),
"InterpolationCPU::linearInterpolationRecurse: alongDim value "
"exceeded exceeded number of dimensions of coordsTointerpolate. "
"Interpolation has failed. Input values : \n - "
"coordsToInterpolate {}\n - pointsToInterpolate {}\n - alongDim "
"{}",
coordToInterpolate,
pointsCoords,
alongDim);
AIDGE_ASSERT(
points.size() == 0,
"InterpolationCPU::linearInterpolationRecurse: entering recursive "
"function with 0 points. Interpolation has failed."
"Please file a bug report to aidge_backend_cpu repo: "
"https://gitlab.eclipse.org/eclipse/aidge/aidge_backend_cpu/-/"
"issues."
"\nInput values : \n - "
"coordsToInterpolate {}\n - pointsToInterpolate {}\n - alongDim "
"{}",
coordToInterpolate,
pointsCoords,
alongDim);
}
Log::debug("\nEntering linear recurse with {} points.", points.size());
Log::debug("Points : {}", extractPtCoords(points));
Log::debug("coordsToInterpolate : {}", coordToInterpolate);
Log::debug("alongDim : {}", alongDim);
///////////////////
// COMPUTATION
// split all points along each dimension
// depending on if their coords[alongDim] are above or under
// coords to interpolate values
std::set<Point<T>> lowerPoints;
std::set<Point<T>> upperPoints;
for (const auto &point : points) {
if (point.first[alongDim] <= coordToInterpolate[alongDim]) {
lowerPoints.insert(point);
} else {
upperPoints.insert(point);
}
}
Log::debug("alongDim : {}", alongDim);
Log::debug("lowerPoints : {}", extractPtCoords(lowerPoints));
Log::debug("upperPoints : {}", extractPtCoords(upperPoints));
// Here are 3 cases
// 1. upper/lowerPoints.size() == 0
// Coordinates to interpolate along current dimension are round.
// That would be equivalent to a linear interpolation with a
// ponderation of 1 for lowerPoints & 0 for upperPoints(or the
// opposite idk), hence we will only take lower/upperPoints values
// from there.
//
// Why this happens :
// If coordinates are round, the floor()/ceil() operations called
// in retrieveNeighbours to generate direct neighbours of floating
// coordinates returned the same value.
//
// 2. lower/upperPoints.size() == 1
// All dimensions have been discriminated, we can proceed to
// weighted interpolation
//
// 3. lower/upperPoints.size() > 1
// points have not been all discriminated and must be further split
// so we call linearRecurse()
switch (lowerPoints.size()) {
case 0: {
return linearRecurse(coordToInterpolate, upperPoints, alongDim + 1);
}
case 1: {
break;
}
default: {
lowerPoints =
linearRecurse(coordToInterpolate, lowerPoints, alongDim + 1);
break;
}
}
switch (upperPoints.size()) {
case 0: {
return linearRecurse(coordToInterpolate, lowerPoints, alongDim + 1);
}
case 1: {
break;
}
default: {
upperPoints =
linearRecurse(coordToInterpolate, upperPoints, alongDim + 1);
break;
}
}
// At this point lowerPoints & upperPoints are garanteed to be
// 1 sized arrays
AIDGE_ASSERT(lowerPoints.size() == 1,
"LowerPoints Size = {} != 1",
lowerPoints.size());
AIDGE_ASSERT(upperPoints.size() == 1,
"upperPoints Size = {} != 1",
upperPoints.size());
// ( point[dim] - Pl[dim] )
// t = ------------------------
// ( Pu[dim] - Pl[dim] )
float weight =
(coordToInterpolate[alongDim] - lowerPoints.begin()->first[alongDim]) /
(upperPoints.begin()->first[alongDim] -
lowerPoints.begin()->first[alongDim]);
Point<T> interpolatedPoint = std::make_pair(
lowerPoints.begin()->first,
static_cast<T>((1.F - weight) * lowerPoints.begin()->second +
weight * upperPoints.begin()->second));
// 0 is just a sanity check to ensure later that all dims have been
// interpolate
interpolatedPoint.first[alongDim] = 0;
Log::debug("successfully returned from alongDim : {}", alongDim);
return std::set<Point<T>>({interpolatedPoint});
}
template <typename T>
T InterpolationCPU::linear(const std::vector<float> &coordToInterpolate,
const std::set<Point<T>> &pointsToInterpolate) {
auto result = linearRecurse(coordToInterpolate, pointsToInterpolate, 0);
AIDGE_ASSERT(result.size() == 1,
"Result size is not 1 but {}",
result.size());
// if (!std::all_of(result.begin()->first.begin(),
// result.begin()->first.end(),
// [](DimSize_t coord) -> bool { return coord == 0; })) {
// std::vector<Coords> ptCoords;
// std::transform(pointsToInterpolate.begin(),
// pointsToInterpolate.end(),
// std::back_inserter(ptCoords),
// [](Point<T> pt) { return pt.first; });
// AIDGE_THROW_OR_ABORT(std::runtime_error,
// "Not all dimensions have been interpolated."
// "Input data :"
// "\n\t coord to interpolate : {}"
// "\n\t pointsToInterpolate : {}",
// // "\n\tAll non 0 values show dimensions
// // that were not interpolated : {}",
// coordToInterpolate,
// ptCoords //,
// // result.begin()->first
// );
// }
return result.begin()->second;
}
template <typename T>
T InterpolationCPU::nearest(const std::vector<float> &coordsToInterpolate,
const std::set<Point<T>> &points,
const Interpolation::Mode nearestMode) {
AIDGE_ASSERT(
coordsToInterpolate.size() == points.begin()->first.size(),
"Interpolation::nearest(): dimension mismatch : coordinate "
"to interpolate ({}) have not the same number of dimensions than "
"the points to interpolate({}).",
coordsToInterpolate,
points.begin()->first);
std::function<int64_t(const float &)> updateCoordinates;
switch (nearestMode) {
case Interpolation::Mode::Ceil: {
updateCoordinates = [](const float &coord) -> int64_t {
return ceil(coord);
};
break;
}
case Interpolation::Mode::Floor: {
updateCoordinates = [](const float &coord) -> int64_t {
return floor(coord);
};
break;
}
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::RoundPreferCeil: {
updateCoordinates = [](const float &coord) -> int64_t {
return (coord - floor(coord)) == 0.5 ? ceil(coord)
: std::round(coord);
};
break;
}
default: {
AIDGE_THROW_OR_ABORT(
std::runtime_error,
"Invalid Interpolation mode for "
"InterpolationCPU::interpolateNearest. Accepted modes are : "
"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));
}
}
Coords nearestCoords;
nearestCoords.reserve(coordsToInterpolate.size());
for (const auto &coord : coordsToInterpolate) {
nearestCoords.push_back(updateCoordinates(coord));
}
auto it = std::find_if(
points.begin(),
points.end(),
[nearestCoords](auto &point) { return nearestCoords == point.first; });
if (it != points.end()) {
return it->second;
} else {
Log::warn("Interpolate::nearest(): did not find a fitting point in "
"the neighbours whose coordinates were {}, returning 0. "
"Available neighbours are at following indexes: ",
coordsToInterpolate);
for (const auto &point : points) {
Log::warn("idx : [{}]\t\tvalue {}", point.first);
}
return static_cast<T>(0);
}
}
template <typename T>
T InterpolationCPU::interpolate(const std::vector<float> &coordsToInterpolate,
const std::set<Point<T>> &points,
const Mode interpMode) {
T result{0};
switch (interpMode) {
case Interpolation::Mode::Cubic: {
AIDGE_THROW_OR_ABORT(
std::runtime_error,
"Unsupported interpolation mode selected : Cubic.");
break;
}
case Interpolation::Mode::Linear: {
return linear(coordsToInterpolate, points);
break;
}
case Interpolation::Mode::Ceil:
case Interpolation::Mode::Floor:
case Interpolation::Mode::RoundPreferFloor:
case Interpolation::Mode::RoundPreferCeil: {
result =
InterpolationCPU::nearest(coordsToInterpolate, points, interpMode);
break;
}
default: {
AIDGE_THROW_OR_ABORT(std::runtime_error,
"InterpolationCPU::Interpolate({}): Unsupported "
"interpolation mode given as input.",
static_cast<int>(interpMode));
break;
}
}
return result;
}
//////////////////////////////////////////////////////////////////////////////////////////////////////
// TEMPLATE DECLARATION
//////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////
// INTERPOLATE
template int8_t InterpolationCPU::interpolate<int8_t>(
const std::vector<float> &originalCoords,
const std::set<Point<int8_t>> &points,
const Mode interpMode);
template int16_t InterpolationCPU::interpolate<int16_t>(
const std::vector<float> &originalCoords,
const std::set<Point<int16_t>> &points,
const Mode interpMode);
template int32_t InterpolationCPU::interpolate<int32_t>(
const std::vector<float> &originalCoords,
const std::set<Point<int32_t>> &points,
const Mode interpMode);
template int64_t InterpolationCPU::interpolate<int64_t>(
const std::vector<float> &originalCoords,
const std::set<Point<int64_t>> &points,
const Mode interpMode);
template half_float::half InterpolationCPU::interpolate<half_float::half>(
const std::vector<float> &originalCoords,
const std::set<Point<half_float::half>> &points,
const Mode interpMode);
template float InterpolationCPU::interpolate<float>(
const std::vector<float> &originalCoords,
const std::set<Point<float>> &points,
const Mode interpMode);
template double InterpolationCPU::interpolate<double>(
const std::vector<float> &originalCoords,
const std::set<Point<double>> &points,
const Mode interpMode);
////////////////////////////////////////////////////////////////////
// INTERPOLATE LINEAR (& its associated recursive function)
template int8_t
InterpolationCPU::linear(const std::vector<float> &coordsToInterpolate,
const std::set<Point<int8_t>> &points);
template std::set<Interpolation::Point<int8_t>>
InterpolationCPU::linearRecurse(const std::vector<float> &coordsToInterpolate,
const std::set<Point<int8_t>> &points,
DimIdx_t alongDim);
template int16_t
InterpolationCPU::linear(const std::vector<float> &coordsToInterpolate,
const std::set<Point<int16_t>> &points);
template std::set<Interpolation::Point<int16_t>>
InterpolationCPU::linearRecurse(const std::vector<float> &coordsToInterpolate,
const std::set<Point<int16_t>> &points,
DimIdx_t alongDim);
template int32_t
InterpolationCPU::linear(const std::vector<float> &coordsToInterpolate,
const std::set<Point<int32_t>> &points);
template std::set<Interpolation::Point<int32_t>>
InterpolationCPU::linearRecurse(const std::vector<float> &coordsToInterpolate,
const std::set<Point<int32_t>> &points,
DimIdx_t alongDim);
template half_float::half
InterpolationCPU::linear(const std::vector<float> &coordsToInterpolate,
const std::set<Point<half_float::half>> &points);
template std::set<Interpolation::Point<half_float::half>>
InterpolationCPU::linearRecurse(
const std::vector<float> &coordsToInterpolate,
const std::set<Point<half_float::half>> &points,
DimIdx_t alongDim);
template float
InterpolationCPU::linear(const std::vector<float> &coordsToInterpolate,
const std::set<Point<float>> &points);
template std::set<Interpolation::Point<float>>
InterpolationCPU::linearRecurse(const std::vector<float> &coordsToInterpolate,
const std::set<Point<float>> &points,
DimIdx_t alongDim);
template double
InterpolationCPU::linear(const std::vector<float> &coordsToInterpolate,
const std::set<Point<double>> &points);
template std::set<Interpolation::Point<double>>
InterpolationCPU::linearRecurse(const std::vector<float> &coordsToInterpolate,
const std::set<Point<double>> &points,
DimIdx_t alongDim);
//////////////////////////////////
// INTERPOLATE NEAREST
template int8_t
InterpolationCPU::nearest(const std::vector<float> &originalCoords,
const std::set<Point<int8_t>> &points,
const Interpolation::Mode nearestMode);
template int16_t
InterpolationCPU::nearest(const std::vector<float> &originalCoords,
const std::set<Point<int16_t>> &points,
const Interpolation::Mode nearestMode);
template int32_t
InterpolationCPU::nearest(const std::vector<float> &originalCoords,
const std::set<Point<int32_t>> &points,
const Interpolation::Mode nearestMode);
template half_float::half
InterpolationCPU::nearest(const std::vector<float> &originalCoords,
const std::set<Point<half_float::half>> &points,
const Interpolation::Mode nearestMode);
template float
InterpolationCPU::nearest(const std::vector<float> &originalCoords,
const std::set<Point<float>> &points,
const Interpolation::Mode nearestMode);
template double
InterpolationCPU::nearest(const std::vector<float> &originalCoords,
const std::set<Point<double>> &points,
const Interpolation::Mode nearestMode);
} // namespace Aidge
/********************************************************************************
* Copyright (c) 2023 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/operator/ResizeImpl.hpp"
#include "aidge/backend/cpu/operator/ResizeImpl_kernels.hpp"
#include "aidge/operator/Resize.hpp"
#include <cassert>
#include <cstdint>
#include <sys/stat.h>
#include "aidge/backend/OperatorImpl.hpp"
#include "aidge/utils/ErrorHandling.hpp"
namespace Aidge {
template <> void ResizeImpl_cpu::forward() {
auto &op = dynamic_cast<const Resize_Op &>(mOp);
/** @brief input #0 */
int8_t idxData = 0;
const bool input0DataPresent =
op.getInput(idxData) && !op.getInput(idxData)->undefined();
///////////////////////////////////////
// CHECKING NODE CONNECTIONS
AIDGE_ASSERT(input0DataPresent, "{}: missing data input #0", op.type());
///////////////////////////////////////
// CALL TO FORWARD
const auto impl =
Registrar<ResizeImpl_cpu>::create(getBestMatch(getRequiredSpec()));
impl.forward(op.getInput(idxData)->getImpl()->rawPtr(),
op.getInput(idxData)->dims(),
op.getOutput(0)->dims(),
op.coordinateTransformationMode(),
op.interpolationMode(),
op.paddingMode(),
op.getOutput(0)->getImpl()->rawPtr() // output pointer
);
}
template <> void Aidge::ResizeImpl_cpu::backward() {
AIDGE_THROW_OR_ABORT(
std::runtime_error,
"Backward not yet implemented for Slice_Op on backend cpu");
}
} // namespace Aidge
/********************************************************************************
* Copyright (c) 2023 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/data/Interpolation.hpp>
#include <aidge/data/Tensor.hpp>
#include <aidge/filler/Filler.hpp>
#include <aidge/utils/Types.h>
#include <catch2/catch_test_macros.hpp>
#include <limits>
#include "aidge/backend/cpu/data/Interpolation.hpp"
namespace Aidge {
TEST_CASE("Interpolation", "[Interpolation][Data]") {
SECTION("Linear") {
std::set<Interpolation::Point<int>> pointsToInterpolateInt;
std::set<Interpolation::Point<float>> pointsToInterpolateFloat;
SECTION("1D") {
pointsToInterpolateInt =
std::set<Interpolation::Point<int>>({{{0}, 10}, {{1}, 20}});
CHECK(abs(InterpolationCPU::linear({0.5}, pointsToInterpolateInt) -
15) <= std::numeric_limits<int>::epsilon());
pointsToInterpolateFloat = std::set<Interpolation::Point<float>>(
{{{0}, .0F}, {{1}, 0.2F}});
CHECK(fabs(InterpolationCPU::linear({0.3},
pointsToInterpolateFloat) -
.06F) <= 1e-5);
}
SECTION("2D") {
// example taken from
// https://en.wikipedia.org/wiki/Bilinear_interpolation
pointsToInterpolateFloat = {{{14, 20}, 91.F},
{{14, 21}, 162.F},
{{15, 20}, 210.F},
{{15, 21}, 95.F}};
CHECK(fabs(InterpolationCPU::linear<float>(
{14.5F, 20.2F},
pointsToInterpolateFloat) -
146.1) < 1e-5);
// pointsToInterpolateFloat = {{{0, 0}, .10F},
// {{0, 1}, .20F},
// {{1, 0}, .30F},
// {{1, 1}, .40F}};
// CHECK(abs(InterpolationCPU::linear<float>({1.5, 0.5},
// pointsToInterpolateInt)
// -
// 25) < std::numeric_limits<int>::epsilon());
// pointsToInterpolateFloat = std::vector({0.1F, 0.2F, 0.3F,
// 0.4F}); CHECK(InterpolationCPU::linear(pointsToInterpolateFloat)
// == .25f);
}
SECTION("3D") {
pointsToInterpolateFloat = {{{0, 0, 0}, .1F},
{{0, 0, 1}, .2F},
{{0, 1, 0}, .3F},
{{0, 1, 1}, .4F},
{{1, 0, 0}, .5F},
{{1, 0, 1}, .6F},
{{1, 1, 0}, .7F},
{{1, 1, 1}, .8F}};
CHECK(fabs(InterpolationCPU::linear({.5, .5, .5},
pointsToInterpolateFloat) -
.45f) < 1e-5);
}
SECTION("4D") {
SECTION("Casual") {
pointsToInterpolateFloat = {{{0, 0, 0, 0}, .1F},
{{0, 0, 0, 1}, .2F},
{{0, 0, 1, 0}, .3F},
{{0, 0, 1, 1}, .4F},
{{0, 1, 0, 0}, .5F},
{{0, 1, 0, 1}, .6F},
{{0, 1, 1, 0}, .7F},
{{0, 1, 1, 1}, .8F},
{{1, 0, 0, 0}, .9F},
{{1, 0, 0, 1}, 1.F},
{{1, 0, 1, 0}, 1.1F},
{{1, 0, 1, 1}, 1.2F},
{{1, 1, 0, 0}, 1.3F},
{{1, 1, 0, 1}, 1.4F},
{{1, 1, 1, 0}, 1.5F},
{{1, 1, 1, 1}, 1.6F}};
CHECK(fabs(InterpolationCPU::linear<float>(
{.5, .5, .5, .5},
pointsToInterpolateFloat) -
.85f) < 0.0001);
}
}
SECTION("Some of the coords to interpolate were round") {
// In this case retrieveNeighbours()
// only retrieved the neighbours against not round dimensions
auto tensor =
std::make_shared<Tensor>(std::vector<DimSize_t>({10, 10}));
tensor->setDataType(DataType::Float32);
tensor->setBackend("cpu");
Aidge::constantFiller(tensor, 1337.F);
std::set<Interpolation::Point<float>> expectedResult = {
{{0, 0, -1, -1}, 0.F},
{{0, 0, 0, -1}, 0.F},
{{0, 0, -1, 0}, 0.F},
{{0, 0, 0, 0}, 1337.F}};
pointsToInterpolateFloat = Interpolation::retrieveNeighbours(
reinterpret_cast<float *>(tensor->getImpl()->rawPtr()),
tensor->dims(),
std::vector<float>({0.F, 0.F, -0.25F, -0.25F}));
pointsToInterpolateFloat = {{{0, 0, -1, -1}, 1337.F},
{{0, 0, 0, -1}, 1337.F},
{{0, 0, -1, 0}, 1337.F},
{{0, 0, 0, 0}, 1337.F}};
}
}
SECTION("Nearest") {
std::set<Interpolation::Point<float>> pointsToInterpolate;
std::vector<float> coordToInterpolate;
SECTION("1D") {
coordToInterpolate = {0.5F};
pointsToInterpolate =
std::set<Interpolation::Point<float>>{{{0}, 1.0F},
{{1}, 2.0F},
{{2}, 3.0F},
{{3}, 4.0F},
{{4}, 5.0F}};
SECTION("Floor") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::Floor) == 1);
}
SECTION("Ceil") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::Ceil) == 2);
}
SECTION("RoundPreferFloor") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::RoundPreferFloor) == 1);
}
SECTION("RoundPreferCeil") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::RoundPreferCeil) == 2);
}
}
SECTION("2D") {
coordToInterpolate = {2.5F, 3.97F};
pointsToInterpolate = {{{0, 0}, 10.0},
{{1, 1}, 20.0},
{{2, 3}, 30.0},
{{2, 4}, 40.0},
{{3, 3}, 50.0},
{{3, 4}, 60.0}};
SECTION("Floor") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::Floor) == 30.);
}
SECTION("Ceil") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::Ceil) == 60.);
}
SECTION("RoundPreferFloor") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::RoundPreferFloor) ==
40.);
}
SECTION("RoundPreferCeil") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::RoundPreferCeil) == 60.);
}
}
SECTION("3D") {
coordToInterpolate = {1.9, 2.1, 3.6};
pointsToInterpolate = {{{0, 0, 0}, 5.0},
{{1, 2, 3}, 10.0},
{{2, 1, 4}, 20.0},
{{2, 2, 4}, 30.0},
{{2, 3, 3}, 40.0},
{{2, 3, 4}, 50.0},
{{3, 3, 4}, 60.0}};
SECTION("Floor") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::Floor) == 10.);
}
SECTION("Ceil") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::Ceil) == 50.);
}
SECTION("RoundPreferFloor") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::RoundPreferFloor) ==
30.);
}
SECTION("RoundPreferCeil") {
CHECK(InterpolationCPU::nearest(
coordToInterpolate,
pointsToInterpolate,
Interpolation::Mode::RoundPreferCeil) == 30.);
}
}
}
}
} // namespace Aidge
...@@ -25,7 +25,7 @@ ...@@ -25,7 +25,7 @@
namespace Aidge { namespace Aidge {
TEST_CASE("Test addition of Tensors","[TensorImpl][Add]") { TEST_CASE("Test addition of Tensors","[TensorImpl][Add][Data]") {
constexpr std::uint16_t NBTRIALS = 10; constexpr std::uint16_t NBTRIALS = 10;
// Create a random number generator // Create a random number generator
std::random_device rd; std::random_device rd;
......
/********************************************************************************
* Copyright (c) 2023 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 <cstdint>
#include <memory>
#include <aidge/data/Data.hpp>
#include <aidge/data/Interpolation.hpp>
#include <aidge/data/half.hpp>
#include <aidge/operator/Pad.hpp>
#include <aidge/utils/ArrayHelpers.hpp>
#include <catch2/catch_test_macros.hpp>
#include "aidge/data/Tensor.hpp"
#include "aidge/operator/OperatorTensor.hpp"
#include "aidge/operator/Resize.hpp"
#include "aidge/utils/TensorUtils.hpp"
namespace Aidge {
TEST_CASE("[cpu/operator] Resize(forward)", "[Resize][CPU]") {
Log::setConsoleLevel(Log::Level::Debug);
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);
}
}
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::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);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->forwardDims(true);
op->forward();
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)") {
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,
9.23385918e-02},
{1.86260208e-01,
3.45560730e-01,
3.96767467e-01,
5.38816750e-01,
4.19194520e-01},
{6.85219526e-01,
2.04452246e-01,
8.78117442e-01,
2.73875929e-02,
6.70467496e-01},
{4.17304814e-01,
5.58689833e-01,
1.40386939e-01,
1.98101491e-01,
8.00744593e-01},
{9.68261600e-01,
3.13424170e-01,
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);
op->setDataType(DataType::Float32);
op->setBackend("cpu");
op->forwardDims(true);
op->forward();
std::shared_ptr<Tensor> expectedOutput = std::make_shared<Tensor>(
Array4D<float, 1, 1, 10, 10>{{{{{7.20324516e-01,
3.60219449e-01,
1.14374816e-04,
1.51223481e-01,
3.02332580e-01,
2.24544227e-01,
1.46755889e-01,
1.19547240e-01,
9.23385918e-02,
9.23385918e-02},
{4.53292370e-01,
3.13064963e-01,
1.72837555e-01,
2.61193782e-01,
3.49550009e-01,
3.46168160e-01,
3.42786312e-01,
2.99276441e-01,
2.55766571e-01,
2.55766571e-01},
{1.86260208e-01,
2.65910476e-01,
3.45560730e-01,
3.71164083e-01,
3.96767467e-01,
4.67792094e-01,
5.38816750e-01,
4.79005635e-01,
4.19194520e-01,
4.19194520e-01},
{4.35739875e-01,
3.55373204e-01,
2.75006473e-01,
4.56224471e-01,
6.37442470e-01,
4.60272312e-01,
2.83102185e-01,
4.13966596e-01,
5.44831038e-01,
5.44831038e-01},
{6.85219526e-01,
4.44835901e-01,
2.04452246e-01,
5.41284859e-01,
8.78117442e-01,
4.52752531e-01,
2.73875929e-02,
3.48927557e-01,
6.70467496e-01,
6.70467496e-01},
{5.51262140e-01,
4.66416597e-01,
3.81571054e-01,
4.45411623e-01,
5.09252191e-01,
3.10998380e-01,
1.12744540e-01,
4.24175322e-01,
7.35606015e-01,
7.35606015e-01},
{4.17304814e-01,
4.87997323e-01,
5.58689833e-01,
3.49538386e-01,
1.40386939e-01,
1.69244215e-01,
1.98101491e-01,
4.99423027e-01,
8.00744593e-01,
8.00744593e-01},
{6.92783237e-01,
5.64420104e-01,
4.36057001e-01,
4.26205903e-01,
4.16354775e-01,
4.76800054e-01,
5.37245333e-01,
6.92460477e-01,
8.47675622e-01,
8.47675622e-01},
{9.68261600e-01,
6.40842915e-01,
3.13424170e-01,
5.02873421e-01,
6.92322612e-01,
7.84355879e-01,
8.76389146e-01,
8.85497928e-01,
8.94606650e-01,
8.94606650e-01},
{9.68261600e-01,
6.40842915e-01,
3.13424170e-01,
5.02873421e-01,
6.92322612e-01,
7.84355879e-01,
8.76389146e-01,
8.85497928e-01,
8.94606650e-01,
8.94606650e-01}}}}});
Log::notice("Expected result : dims = {}", expectedOutput->dims());
expectedOutput->print();
Log::notice("\nActual result: dims = {}", op->getOutput(0)->dims());
op->getOutput(0)->print();
CHECK(approxEq<float>(*op->getOutput(0),
*expectedOutput,
1e-5f,
1e-5f) == true);
}
}
} // namespace Aidge
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