From 2d63028a6fd1416b8081d53bcb59b3f4e02e0cb3 Mon Sep 17 00:00:00 2001 From: Jerome Hue <jerome.hue@cea.fr> Date: Fri, 28 Feb 2025 17:52:53 +0100 Subject: [PATCH] Add Heaviside backward surrogate and associated tests --- .../backend/cpu/operator/HeavisideImpl.hpp | 2 +- .../cpu/operator/HeavisideImpl_kernels.hpp | 5 ++-- src/operator/HeavisideImpl.cpp | 17 +++++------ unit_tests/operator/Test_HeavisideImpl.cpp | 28 ++++++++++++++++--- 4 files changed, 37 insertions(+), 15 deletions(-) diff --git a/include/aidge/backend/cpu/operator/HeavisideImpl.hpp b/include/aidge/backend/cpu/operator/HeavisideImpl.hpp index 7a3ba9ad..877fa2a9 100644 --- a/include/aidge/backend/cpu/operator/HeavisideImpl.hpp +++ b/include/aidge/backend/cpu/operator/HeavisideImpl.hpp @@ -23,7 +23,7 @@ namespace Aidge { using HeavisideImplCpu = OperatorImpl_cpu<Heaviside_Op, void(std::size_t, const void *, void *, const float), - void(const float, std::size_t, const void *, void *)>; + void(std::size_t, const void *, const void *, void *)>; // Implementation entry point registration for operator Heaviside REGISTRAR(Heaviside_Op, "cpu", HeavisideImplCpu::create); diff --git a/include/aidge/backend/cpu/operator/HeavisideImpl_kernels.hpp b/include/aidge/backend/cpu/operator/HeavisideImpl_kernels.hpp index 0bbbddee..7fc0eb0a 100644 --- a/include/aidge/backend/cpu/operator/HeavisideImpl_kernels.hpp +++ b/include/aidge/backend/cpu/operator/HeavisideImpl_kernels.hpp @@ -48,7 +48,8 @@ void HeavisideImplCpuBackwardKernel(std::size_t inputLength, for (size_t i = 0; i < inputLength; ++i) { // dx = dy * (1/PI) * (1 / (1 + (PI * x)^2)) - grad_input[i] = (1 / M_PI) * grad_output[i] * static_cast<O>(1.0 / (1.0 + output[i] * output[i])); + // grad_input[i] = (1 / M_PI) * grad_output[i] * static_cast<O>(1.0 / (1.0 + (output[i] * output[i]) * (M_PI * M_PI))); + grad_input[i] = grad_output[i] * static_cast<O>(1.0 / (1.0 + (output[i] * output[i]) * (M_PI * M_PI))); } } @@ -57,7 +58,7 @@ REGISTRAR(HeavisideImplCpu, {DataType::Float32}, {ProdConso::inPlaceModel, Aidge::HeavisideImplCpuForwardKernel<float, float>, - nullptr}); + Aidge::HeavisideImplCpuBackwardKernel<float,float,float>}); } // namespace Aidge #endif // AIDGE_CPU_OPERATOR_HEAVISIDEIMPL_KERNELS_H__H_ diff --git a/src/operator/HeavisideImpl.cpp b/src/operator/HeavisideImpl.cpp index 2ead2978..5bf77f87 100644 --- a/src/operator/HeavisideImpl.cpp +++ b/src/operator/HeavisideImpl.cpp @@ -34,21 +34,22 @@ template <> void Aidge::HeavisideImplCpu::forward() { template <> void Aidge::HeavisideImplCpu::backward() { - AIDGE_THROW_OR_ABORT(std::runtime_error, "Heaviside backward not implemented yet"); // TODO: The following lines are assuming that the surrogate gradient is Atan // remove that assumption by providing an attribute to Heaviside, // allowing to choose between different surrogate gradients. - // const Heavisde_Op& op_ = dynamic_cast<const Heavisie_Op &>(mOp); + const Heaviside_Op& op_ = dynamic_cast<const Heaviside_Op &>(mOp); + const auto impl = Registrar<HeavisideImplCpu>::create(getBestMatch(getRequiredSpec())); + auto gra_int0 = op_.getInput(0)->grad(); + auto gra_out0 = op_.getOutput(0)->grad(); - // ! backward of hs = forward of atan - //const auto impl = Registrar<HeavisideImplCpu>::create(getBestMatch(getRequiredSpec())); - // std::shared_ptr<Tensor> in0 = op_.getInput(0); - // std::shared_ptr<Tensor> out0 = op_.getOutput(0); - - //impl.forward() + std::shared_ptr<Tensor> in0 = op_.getInput(0); + std::shared_ptr<Tensor> out0 = op_.getOutput(0); + AIDGE_ASSERT(out0, "missing output #0 for current {} operator", op_.type()); + + impl.backward(gra_int0->size(), getCPUPtr(in0), getCPUPtr(gra_out0), getCPUPtr(gra_int0)); } diff --git a/unit_tests/operator/Test_HeavisideImpl.cpp b/unit_tests/operator/Test_HeavisideImpl.cpp index a0142513..515d6802 100644 --- a/unit_tests/operator/Test_HeavisideImpl.cpp +++ b/unit_tests/operator/Test_HeavisideImpl.cpp @@ -12,6 +12,7 @@ #include "aidge/backend/cpu/operator/HeavisideImpl_kernels.hpp" #include <aidge/operator/Memorize.hpp> +#include <aidge/utils/Types.h> #include <memory> #include <cstdlib> #include <random> @@ -100,10 +101,29 @@ TEST_CASE("[cpu/operator] Heaviside(forward)", "[Heaviside][CPU]") { } TEST_CASE("[cpu/operator] Heaviside(backward)", "[Heaviside][CPU]") { + auto hs = Heaviside(1.0f); + auto op = std::static_pointer_cast<OperatorTensor>(hs->getOperator()); + op->setDataType(DataType::Float32); + op->setBackend("cpu"); - auto add = Add(); - auto mem = Memorize(2); - auto hs = Heaviside(1); -} + auto input = Tensor(Array1D<float, 3>({1.0, -1.0, 1.0})); + input.setDataType(DataType::Float32); + input.setBackend("cpu"); + + auto grad = Tensor(Array1D<float, 3>({1.0, 1.0, 1.0})); + grad.setDataType(DataType::Float32); + grad.setBackend("cpu"); + + op->setInput(IOIndex_t(0), std::make_shared<Tensor>(input)); + op->forward(); + Log::info("Output : "); + op->getOutput(0)->print(); + + op->getOutput(0)->setGrad(std::make_shared<Tensor>(grad)); + op->backward(); + + Log::info("Gradient : "); + op->getInput(0)->grad()->print(); +} } -- GitLab