Skip to content
Snippets Groups Projects
Commit 659bae60 authored by Grégoire Kubler's avatar Grégoire Kubler
Browse files

feat : [ADD] Padding3D

parent 6db7b4c3
No related branches found
No related tags found
No related merge requests found
......@@ -54,9 +54,19 @@ using PadImpl2D_cpu = OperatorImpl_cpu<Pad_Op<2>,
const void *,
void *)>;
using Pad3D_Op = Pad_Op<3>;
using PadImpl3D_cpu = OperatorImpl_cpu<Pad_Op<3>,
void(const std::array<DimSize_t, 6>&,
const PadBorderType,
const double,
const std::array<DimSize_t, 5> &,
const void *,
void *)>;
// Implementation entry point registration to Operator
REGISTRAR(Pad1D_Op, "cpu", Aidge::PadImpl1D_cpu::create);
REGISTRAR(Pad2D_Op, "cpu", Aidge::PadImpl2D_cpu::create);
REGISTRAR(Pad3D_Op, "cpu", Aidge::PadImpl3D_cpu::create);
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_PADIMPL_H_ */
......@@ -12,16 +12,27 @@
#ifndef AIDGE_CPU_OPERATOR_PADIMPL_KERNELS_H_
#define AIDGE_CPU_OPERATOR_PADIMPL_KERNELS_H_
#include <algorithm> // std::max, std::min
#include <aidge/operator/Pad.hpp>
#include <aidge/utils/ErrorHandling.hpp>
#include <algorithm> // std::max, std::min
#include <array>
#include <cstddef> // std::size_t
#include <cstdint> // std::int32_t
#include <cmath>
#include <cstddef> // std::size_t
#include <cstdint> // std::int32_t
#include <fmt/base.h>
#include <stdexcept>
#include <type_traits>
#include "aidge/backend/cpu/operator/PadImpl.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
////////////////////////////////////////////////////////////////////////////////////////////////
// PAD 1D
////////////////////////////////////////////////////////////////////////////////////////////////
/**
* @brief Forward kernel for 1D Padding on CPU backend.
* @tparam I Input data type.
......@@ -187,6 +198,369 @@ REGISTRAR(PadImpl2D_cpu,
REGISTRAR(PadImpl2D_cpu,
{{DataType::Int32, DataFormat::NCHW}, {DataType::Int32, DataFormat::NCHW}},
{Pad_ProdConso_cpu::defaultModel, Aidge::PadImpl2D_cpu_forward_kernel<cpptype_t<DataType::Int32>, cpptype_t<DataType::Int32>>, nullptr});
} // namespace Aidge
////////////////////////////////////////////////////////////////////////////////////////////////
// PAD 3D
////////////////////////////////////////////////////////////////////////////////////////////////
template <typename I, typename O>
static inline void
pad3DForwardConstant(const std::array<DimSize_t, 6> &beginEndBorders,
const O borderValue,
const std::array<DimSize_t, 5> &iDims,
const std::array<DimSize_t, 4> &iStrides,
std::array<DimSize_t, 4> &iOffsets,
const I *input,
const std::array<DimSize_t, 3> &oDims,
const std::array<DimSize_t, 4> &oStrides,
std::array<DimSize_t, 4> &oOffsets,
O *output) {
for (DimSize_t oX = 0; oX < oDims[0]; ++oX) {
oOffsets[2] = oX * oStrides[2] + oOffsets[1];
const SignedDimSize_t iX = oX - beginEndBorders[0];
if (iX >= 0 && iX < static_cast<SignedDimSize_t>(iDims[2])) {
iOffsets[2] = iX * iStrides[2] + iOffsets[1];
} else {
std::fill(output + oOffsets[2],
output + oOffsets[2] + oStrides[2],
borderValue);
continue;
}
for (DimSize_t oY = 0; oY < oDims[1]; ++oY) {
oOffsets[3] = oY * oStrides[3] + oOffsets[2];
const SignedDimSize_t iY = oY - beginEndBorders[1];
if (iY >= 0 && iY < static_cast<SignedDimSize_t>(iDims[3])) {
iOffsets[3] = iY * iStrides[3] + iOffsets[2];
} else {
std::fill(output + oOffsets[3],
output + oOffsets[3] + oStrides[3],
borderValue);
continue;
}
for (DimSize_t oZ = 0; oZ < oDims[2]; ++oZ) {
const SignedDimSize_t iZ = oZ - beginEndBorders[2];
// if in bounds, takes corresponding value, otherwise takes
// default value
output[oOffsets[3] + oZ] =
(iZ >= 0 && iZ < static_cast<SignedDimSize_t>(iDims[4]))
? input[iOffsets[3] + iZ]
: borderValue;
}
}
}
}
/**
* @brief small inline fctn to generate the corresponding input coordinates of
* an output coord in edge padding along a given dimension.
* @param[in] beginBorder Padding at the beginning of given dimension.
* @param[in] iDim Size of given dimension
* @param[in] oCoord output coord along given dimension
*/
static inline DimSize_t padEdgeComputeInputCoord(const DimSize_t beginBorder,
const DimSize_t iDim,
const DimSize_t oCoord) {
return static_cast<DimSize_t>(std::max(
static_cast<SignedDimSize_t>(0),
std::min(static_cast<SignedDimSize_t>(iDim - 1),
static_cast<SignedDimSize_t>(oCoord - beginBorder))));
}
template <typename I, typename O>
static inline void
pad3DForwardEdge(const std::array<DimSize_t, 6> &beginEndBorders,
const std::array<DimSize_t, 5> &iDims,
const std::array<DimSize_t, 4> &iStrides,
std::array<DimSize_t, 4> &iOffsets,
const I *input,
const std::array<DimSize_t, 3> &oDims,
const std::array<DimSize_t, 4> &oStrides,
std::array<DimSize_t, 4> &oOffsets,
O *output) {
for (DimSize_t oX = 0; oX < oDims[0]; ++oX) {
oOffsets[2] = oX * oStrides[2] + oOffsets[1];
const DimSize_t iX =
padEdgeComputeInputCoord(beginEndBorders[0], iDims[2], oX);
iOffsets[2] = iX * iStrides[2] + iOffsets[1];
for (DimSize_t oY = 0; oY < oDims[1]; ++oY) {
oOffsets[3] = oY * oStrides[3] + oOffsets[2];
const DimSize_t iY =
padEdgeComputeInputCoord(beginEndBorders[1], iDims[3], oY);
iOffsets[3] = iY * iStrides[3] + iOffsets[2];
for (DimSize_t oZ = 0; oZ < oDims[2]; ++oZ) {
const DimSize_t iZ =
padEdgeComputeInputCoord(beginEndBorders[2], iDims[4], oZ);
output[oOffsets[3] + oZ] = input[iOffsets[3] + iZ];
}
}
}
}
/**
* @brief small inline fctn to generate the corresponding input coordinates of
* an output coord in reflect padding along a given dimension.
* @param[in] beginBorder Padding at the beginning of given dimension.
* @param[in] iDim Size of given dimension
* @param[in] oCoord output coord along given dimension
*/
static inline DimSize_t
padReflectComputeInputCoord(const DimSize_t beginBorder,
const DimSize_t iDim,
const DimSize_t oCoord) {
SignedDimSize_t iCoord =
std::abs(static_cast<SignedDimSize_t>(oCoord - beginBorder));
// Handle case where iCoord > iDim
// If so iCoord must be changed to (iDim - 1) - delta
// With delta = |iDim - 1 - icoord|
//
// Since iCoord > iDim - 1, |(iDim - 1) - iCoord| <=> iCoord - (iDim - 1)
// <=> iCoord + 1 - iDim
// Hence iDim - 1 - delta <=> iDim - 1 - (iCoord + 1 - iDim)
// <=> 2 * (iDim - 1) - iCoord
iCoord = (iCoord >= static_cast<SignedDimSize_t>(iDim))
? static_cast<SignedDimSize_t>(iDim + iDim - 2) - iCoord
// std::abs(static_cast<SignedDimSize_t>(iDim - 1) - iCoord)
: iCoord;
return iCoord;
}
template <typename I, typename O>
static inline void
pad3DForwardReflect(const std::array<DimSize_t, 6> &beginEndBorders,
const std::array<DimSize_t, 5> &iDims,
const std::array<DimSize_t, 4> &iStrides,
std::array<DimSize_t, 4> &iOffsets,
const I *input,
const std::array<DimSize_t, 3> &oDims,
const std::array<DimSize_t, 4> &oStrides,
std::array<DimSize_t, 4> &oOffsets,
O *output) {
for (DimSize_t oX = 0; oX < oDims[0]; ++oX) {
oOffsets[2] = oX * oStrides[2] + oOffsets[1];
DimSize_t iX =
padReflectComputeInputCoord(beginEndBorders[0], iDims[2], oX);
iOffsets[2] = iX * iStrides[2] + iOffsets[1];
for (DimSize_t oY = 0; oY < oDims[1]; ++oY) {
oOffsets[3] = oY * oStrides[3] + oOffsets[2];
DimSize_t iY =
padReflectComputeInputCoord(beginEndBorders[1], iDims[3], oY);
iOffsets[3] = iY * iStrides[3] + iOffsets[2];
for (DimSize_t oZ = 0; oZ < oDims[2]; ++oZ) {
DimSize_t iZ = padReflectComputeInputCoord(beginEndBorders[2],
iDims[4],
oZ);
output[oOffsets[3] + oZ] = input[iOffsets[3] + iZ];
}
}
}
}
/**
* @brief small inline fctn to generate the corresponding input coordinates of
* an output coord in wrap padding along a given dimension.
* @param[in] beginBorder Padding at the beginning of given dimension.
* @param[in] iDim Size of given dimension
* @param[in] oCoord output coord along given dimension
*/
static inline DimSize_t padWrapComputeInputCoord(const DimSize_t beginBorder,
const DimSize_t iDim,
const DimSize_t oCoord) {
return (iDim + oCoord - beginBorder) % iDim;
}
template <typename I, typename O>
static inline void
pad3DForwardWrap(const std::array<DimSize_t, 6> &beginEndBorders,
const std::array<DimSize_t, 5> &iDims,
const std::array<DimSize_t, 4> &iStrides,
std::array<DimSize_t, 4> &iOffsets,
const I *input,
const std::array<DimSize_t, 3> &oDims,
const std::array<DimSize_t, 4> &oStrides,
std::array<DimSize_t, 4> &oOffsets,
O *output) {
for (DimSize_t oX = 0; oX < oDims[0]; ++oX) {
oOffsets[2] = oX * oStrides[2] + oOffsets[1];
const DimSize_t iX =
padWrapComputeInputCoord(beginEndBorders[0], iDims[2], oX);
iOffsets[2] = iX * iStrides[2] + iOffsets[1];
for (DimSize_t oY = 0; oY < oDims[1]; ++oY) {
oOffsets[3] = oY * oStrides[3] + oOffsets[2];
const DimSize_t iY =
padWrapComputeInputCoord(beginEndBorders[1], iDims[3], oY);
iOffsets[3] = iY * iStrides[3] + iOffsets[2];
for (DimSize_t oZ = 0; oZ < oDims[2]; ++oZ) {
const DimSize_t iZ =
padWrapComputeInputCoord(beginEndBorders[2], iDims[4], oZ);
output[oOffsets[3] + oZ] = input[iOffsets[3] + iZ];
}
}
}
}
/**
* @brief Forward kernel for 2D Padding on CPU backend.
* @tparam I Input data type.
* @tparam O Output data type.
* @param attrs tuple of Parameters from the Operator
* @param iDims Array of input dimensions.
* @param input_ const input Tensor.
* @param output_ Output Tensor.
*/
template <class I, class O>
void PadImpl3D_cpu_forward_kernel(
const std::array<DimSize_t, 6> &beginEndBorders,
const PadBorderType borderType,
const double borderValue,
const std::array<DimSize_t, 5> &iDims,
const void *input_,
void *output_) {
const I *input = static_cast<const I *>(input_);
O *output = static_cast<O *>(output_);
// not taking in count batch & channel as they are identical to iDims
const std::array<DimSize_t, 3> oDims = {
iDims[2] + beginEndBorders[0] + beginEndBorders[3],
iDims[3] + beginEndBorders[1] + beginEndBorders[4],
iDims[4] + beginEndBorders[2] + beginEndBorders[5]};
const std::array<DimSize_t, 4> oStrides = {
iDims[1] * oDims[0] * oDims[1] * oDims[2],
oDims[0] * oDims[1] * oDims[2],
oDims[1] * oDims[2],
oDims[2],
};
const std::array<DimSize_t, 4> iStrides = {
iDims[1] * iDims[2] * iDims[3] * iDims[4],
iDims[2] * iDims[3] * iDims[4],
iDims[3] * iDims[4],
iDims[4],
};
std::array<DimSize_t, 4> oOffsets = {0, 0, 0, 0};
std::array<DimSize_t, 4> iOffsets = {0, 0, 0, 0};
for (std::size_t batch = 0; batch < iDims[0]; ++batch) {
oOffsets[0] = batch * oStrides[0];
iOffsets[0] = batch * iStrides[0];
for (std::size_t ch = 0; ch < iDims[1]; ++ch) {
iOffsets[1] = ch * iStrides[1] + iOffsets[0];
oOffsets[1] = ch * oStrides[1] + oOffsets[0];
switch (borderType) {
case PadBorderType::Constant: {
pad3DForwardConstant(beginEndBorders,
static_cast<O>(borderValue),
iDims,
iStrides,
iOffsets,
input,
oDims,
oStrides,
oOffsets,
output);
break;
}
case PadBorderType::Zero: {
pad3DForwardConstant(beginEndBorders,
static_cast<O>(0),
iDims,
iStrides,
iOffsets,
input,
oDims,
oStrides,
oOffsets,
output);
break;
}
case PadBorderType::Edge: {
pad3DForwardEdge(beginEndBorders,
iDims,
iStrides,
iOffsets,
input,
oDims,
oStrides,
oOffsets,
output);
break;
}
case PadBorderType::Reflect: {
pad3DForwardReflect(beginEndBorders,
iDims,
iStrides,
iOffsets,
input,
oDims,
oStrides,
oOffsets,
output);
break;
}
case PadBorderType::Wrap: {
pad3DForwardWrap(beginEndBorders,
iDims,
iStrides,
iOffsets,
input,
oDims,
oStrides,
oOffsets,
output);
break;
}
default: {
AIDGE_THROW_OR_ABORT(
std::runtime_error,
"Pad3D : unsupported padding method : {}.",
borderType);
}
}
}
}
}
// Kernels registration to implementation entry point
REGISTRAR(PadImpl3D_cpu,
{{DataType::Float32, DataFormat::NCHW},
{DataType::Float32, DataFormat::NCHW}},
{Pad_ProdConso_cpu::defaultModel,
Aidge::PadImpl3D_cpu_forward_kernel<cpptype_t<DataType::Float32>,
cpptype_t<DataType::Float32>>,
nullptr});
REGISTRAR(PadImpl3D_cpu,
{{DataType::Float64, DataFormat::NCHW},
{DataType::Float64, DataFormat::NCHW}},
{Pad_ProdConso_cpu::defaultModel,
Aidge::PadImpl3D_cpu_forward_kernel<cpptype_t<DataType::Float64>,
cpptype_t<DataType::Float64>>,
nullptr});
REGISTRAR(PadImpl3D_cpu,
{{DataType::Int32, DataFormat::NCHW},
{DataType::Int32, DataFormat::NCHW}},
{Pad_ProdConso_cpu::defaultModel,
Aidge::PadImpl3D_cpu_forward_kernel<cpptype_t<DataType::Int32>,
cpptype_t<DataType::Int32>>,
nullptr});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_PADIMPL_KERNELS_H_ */
......@@ -74,3 +74,26 @@ template <>
void Aidge::PadImpl2D_cpu::backward() {
AIDGE_THROW_OR_ABORT(std::runtime_error, "Backward not yet implemented for Pad_Op<2> on backend cpu");
}
template <>
void Aidge::PadImpl3D_cpu::forward() {
const auto& op_ = dynamic_cast<const Pad_Op<3>&>(mOp);
AIDGE_ASSERT(op_.getInput(0), "missing input #0 in Pad Operator.");
// Find the correct kernel type
const auto impl = Registrar<PadImpl3D_cpu>::create(getBestMatch(getRequiredSpec()));
// Call kernel
impl.forward(op_.beginEndBorders(),
op_.borderType(),
op_.borderValue(),
op_.getInput(0)->template dims<5>(),
getCPUPtr(mOp.getRawInput(0)),
getCPUPtr(mOp.getRawOutput(0)));
}
template <>
void Aidge::PadImpl3D_cpu::backward() {
AIDGE_THROW_OR_ABORT(std::runtime_error, "Backward not yet implemented for Pad_Op<2> on backend cpu");
}
This diff is collapsed.
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