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

fix: error related to 'fma' call with different input types. Also simplify GlobalAvgPooling logic

parent d95abd33
No related branches found
No related tags found
No related merge requests found
......@@ -18,12 +18,11 @@
#include "aidge/backend/cpu/operator/OperatorImpl.hpp"
#include "aidge/operator/GlobalAveragePooling.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
// Operator implementation entry point for the backend
using GlobalAveragePoolingImpl_cpu = OperatorImpl_cpu<GlobalAveragePooling_Op,
void(const std::vector<DimSize_t> &, const void *, void *)>;
void(const std::shared_ptr<Tensor>&, void *)>;
// Implementation entry point registration to Operator
REGISTRAR(GlobalAveragePooling_Op, "cpu", Aidge::GlobalAveragePoolingImpl_cpu::create);
......
......@@ -12,92 +12,71 @@
#ifndef AIDGE_CPU_OPERATOR_GLOBALAVERAGEPOOLINGIMPL_KERNELS_H_
#define AIDGE_CPU_OPERATOR_GLOBALAVERAGEPOOLINGIMPL_KERNELS_H_
#include <cstddef>
#include <functional> // std::multiplies
#include <numeric> // std::accumulate
#include <cstddef> // std::size_t
#include <vector>
#include "aidge/backend/cpu/operator/GlobalAveragePoolingImpl.hpp"
#include "aidge/data/Data.hpp"
#include "aidge/utils/ErrorHandling.hpp"
#include "aidge/data/Tensor.hpp"
#include "aidge/utils/Registrar.hpp"
#include "aidge/utils/Types.h"
namespace Aidge {
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
stableMean(const T* vec, size_t size) {
T mean = 0;
for (size_t i = 0; i < size; ++i) {
mean = std::fma<T>(vec[i] - mean, 1.0f / (i + 1), mean);
}
return mean;
typename std::enable_if_t<std::is_floating_point<T>::value, T>
static stableMean(const T* vec, std::size_t size) {
T mean{0};
for (std::size_t i = 0; i < size; ++i) {
mean = std::fma(vec[i] - mean, static_cast<T>(1) / static_cast<T>(i + 1), mean);
}
return mean;
}
// Specialization for integers: perform the mean computation in float
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, double>::type
stableMean(const T* vec, size_t size) {
double mean = 0;
for (size_t i = 0; i < size; ++i) {
mean = std::fma<double>(vec[i] - mean, 1.0f / (i + 1), mean);
}
return mean;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
castFromFloat(T value) {
return value;
}
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, T>::type
castFromFloat(double value) {
return static_cast<T>(std::nearbyint(value));
typename std::enable_if_t<!std::is_floating_point<T>::value, double>
static stableMean(const T* vec, std::size_t size) {
double mean{0};
for (std::size_t i = 0; i < size; ++i) {
mean = std::fma<double>(static_cast<double>(vec[i]) - mean, 1.0 / static_cast<double>(i + 1), mean);
}
return mean;
}
template <class I, class O>
void GlobalAveragePoolingImpl_cpu_forward_kernel(
const std::vector<DimSize_t> &dims, const void *input_, void *output_) {
// error checking
AIDGE_ASSERT(dims.size() >= 3,"GlobalAveragePool needs at least a 3 dimensions "
"input, number of input dim : {}",
dims.size());
template <DataType DT_I, DataType DT_O = DT_I>
void GlobalAveragePoolingImpl_cpu_forward_kernel(const std::shared_ptr<Tensor>& inputTensor, void *output_) {
// computation
const I *input = static_cast<const I *>(input_);
O *output = static_cast<O *>(output_);
// computation
using I = cpptype_t<DT_I>;
using O = cpptype_t<DT_O>;
const I *input = static_cast<const I *>(inputTensor->getImpl()->rawPtr());
O *output = static_cast<O *>(output_);
const auto& dims = inputTensor->dims();
DimSize_t nb_elems = std::accumulate(dims.begin(), dims.end(), std::size_t(1),
std::multiplies<std::size_t>());
const DimSize_t strides_channels = inputTensor->strides()[1];
const DimSize_t in_batch_nb_elems{nb_elems / dims[0]};
const DimSize_t in_channel_nb_elems{in_batch_nb_elems / dims[1]};
const DimSize_t out_batch_nb_elems{dims[1]};
// parse channel by channel and fill each output with the average of the
// values in the channel
for (DimSize_t batch = 0; batch < dims[0]; ++batch) {
for (DimSize_t channel = 0; channel < dims[1]; ++channel) {
const I *filter_start = std::next(
input, (batch * in_batch_nb_elems) + (channel * in_channel_nb_elems));
output[batch * out_batch_nb_elems + channel] = castFromFloat<O>(stableMean<I>(filter_start, in_channel_nb_elems));
// parse channel by channel and fill each output with the average of the
// values in the channel
std::size_t input_idx = 0;
std::size_t output_idx = 0;
for (DimSize_t batch = 0; batch < dims[0]; ++batch) {
for (DimSize_t channel = 0; channel < dims[1]; ++channel) {
output[output_idx++] = static_cast<O>(stableMean<I>(input + input_idx, strides_channels));
input_idx += strides_channels;
}
}
}
}
// Kernels registration to implementation entry point
REGISTRAR(GlobalAveragePoolingImpl_cpu,
{DataType::Float32},
{ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<float, float>, nullptr});
{ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<DataType::Float32>, nullptr});
REGISTRAR(GlobalAveragePoolingImpl_cpu,
{DataType::Float64},
{ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<double, double>, nullptr});
{ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<DataType::Float64>, nullptr});
REGISTRAR(GlobalAveragePoolingImpl_cpu,
{DataType::Int32},
{ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<int32_t, int32_t>, nullptr});
{ProdConso::defaultModel, Aidge::GlobalAveragePoolingImpl_cpu_forward_kernel<DataType::Int32>, nullptr});
} // namespace Aidge
#endif /* AIDGE_CPU_OPERATOR_GLOBALAVERAGEPOOLINGIMPL_KERNELS_H_ */
......@@ -12,7 +12,6 @@
#ifndef AIDGE_CPU_OPERATOR_REDUCEMEANIMPL_H_
#define AIDGE_CPU_OPERATOR_REDUCEMEANIMPL_H_
#include <array>
#include <memory>
#include <tuple>
#include <vector>
......
......@@ -25,39 +25,39 @@
#include "aidge/utils/Registrar.hpp"
namespace Aidge {
template <typename T>
using Acc_T = typename std::conditional<std::is_floating_point<T>::value, T, double>::type;
using Acc_T = typename std::conditional_t<std::is_floating_point<T>::value, T, double>;
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
stableMean(const T* vec, size_t len, size_t stride) {
stableMean(const T* vec, std::size_t len, std::size_t stride) {
T mean = 0;
for (size_t i = 0; i < len; ++i) {
mean = std::fma<T>(vec[i * stride] - mean, 1.0f / (i + 1), mean);
for (std::size_t i = 0; i < len; ++i) {
mean = std::fma(vec[i * stride] - mean, static_cast<T>(1) / static_cast<T>(i + 1), mean);
}
return mean;
}
// Specialization for integers: perform the mean computation in float
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, double>::type
stableMean(const T* vec, size_t len, size_t stride) {
typename std::enable_if_t<!std::is_floating_point<T>::value, double>
stableMean(const T* vec, std::size_t len, std::size_t stride) {
double mean = 0;
for (size_t i = 0; i < len; ++i) {
mean = std::fma<double>(vec[i * stride] - mean, 1.0f / (i + 1), mean);
mean = std::fma<double>(static_cast<double>(vec[i * stride]) - mean, 1.0 / static_cast<double>(i + 1), mean);
}
return mean;
}
template <typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
typename std::enable_if_t<std::is_floating_point<T>::value, T>
castFromFloat(T value) {
return value;
}
template <typename T>
typename std::enable_if<!std::is_floating_point<T>::value, T>::type
typename std::enable_if_t<!std::is_floating_point<T>::value, T>
castFromFloat(double value) {
return static_cast<T>(std::nearbyint(value));
}
......
......@@ -30,13 +30,15 @@ void Aidge::GlobalAveragePoolingImpl_cpu::forward()
const GlobalAveragePooling_Op& op_ = static_cast<const GlobalAveragePooling_Op&>(mOp);
// Check if input is provided
AIDGE_ASSERT(op_.getInput(0), "missing input 0");
// error checking
AIDGE_ASSERT(op_.getInput(0)->nbDims() >= 3,"GlobalAveragePool needs at least a 3 dimensions "
"input. Got input dims {}", op_.getInput(0)->dims());
// Find the correct kernel type
const auto impl = Registrar<GlobalAveragePoolingImpl_cpu>::create(getBestMatch(getRequiredSpec()));
// Call kernel
impl.forward(op_.getInput(0)->dims(),
op_.getInput(0)->getImpl()->rawPtr(),
impl.forward(op_.getInput(0),
op_.getOutput(0)->getImpl()->rawPtr());
}
......
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