diff --git a/include/aidge/backend/cpu/operator/LnImpl.hpp b/include/aidge/backend/cpu/operator/LnImpl.hpp
new file mode 100755
index 0000000000000000000000000000000000000000..faa03855a4f881f2a644ebc4023871b7acd6275c
--- /dev/null
+++ b/include/aidge/backend/cpu/operator/LnImpl.hpp
@@ -0,0 +1,54 @@
+/********************************************************************************
+ * 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_LNIMPL_H_
+#define AIDGE_CPU_OPERATOR_LNIMPL_H_
+
+#include "aidge/backend/OperatorImpl.hpp"
+#include "aidge/operator/Ln.hpp"
+#include "aidge/utils/Registrar.hpp"
+#include "aidge/utils/Types.h"
+#include "aidge/backend/cpu/data/GetCPUPtr.h"
+#include <memory>
+#include <vector>
+
+namespace Aidge {
+// class Ln_Op;
+
+// compute kernel registry for forward and backward
+class LnImplForward_cpu
+    : public Registrable<LnImplForward_cpu, std::tuple<DataType, DataType>, void(const std::size_t, const void*, void*)> {
+};
+class LnImplBackward_cpu
+    : public Registrable<LnImplBackward_cpu, std::tuple<DataType, DataType, DataType>, void(const std::size_t, const void*, const void*, void*)> {
+};
+
+class LnImpl_cpu : public OperatorImpl {
+public:
+    LnImpl_cpu(const Ln_Op& op) : OperatorImpl(op, "cpu") {}
+
+    static std::unique_ptr<LnImpl_cpu> create(const Ln_Op& op) {
+        return std::make_unique<LnImpl_cpu>(op);
+    }
+
+    Elts_t getNbRequiredProtected(const IOIndex_t inputIdx) const override final;
+	
+    void forward() override final;
+
+    void backward() override final;
+};
+
+namespace {
+static Registrar<Ln_Op> registrarLnImpl_cpu("cpu", Aidge::LnImpl_cpu::create);
+}
+}  // namespace Aidge
+
+#endif /* AIDGE_CPU_OPERATOR_LNIMPL_H_ */
diff --git a/include/aidge/backend/cpu/operator/LnImpl_backward_kernels.hpp b/include/aidge/backend/cpu/operator/LnImpl_backward_kernels.hpp
new file mode 100755
index 0000000000000000000000000000000000000000..70e34cf3cc2bc9aacde01eea4bef797d81d27f26
--- /dev/null
+++ b/include/aidge/backend/cpu/operator/LnImpl_backward_kernels.hpp
@@ -0,0 +1,45 @@
+/********************************************************************************
+ * 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_LNIMPL_BACKWARD_KERNEL_H_
+#define AIDGE_CPU_OPERATOR_LNIMPL_BACKWARD_KERNEL_H_
+
+#include <cstddef>  // std::size_t
+
+#include "aidge/backend/cpu/operator/LnImpl.hpp"
+#include "aidge/utils/Registrar.hpp"
+
+namespace Aidge {
+template <class I, class GI, class GO>
+void LnImpl_cpu_backward_kernel(const std::size_t inputLenght,
+                                const void* input_, const void* grad_output_,
+	                        void* grad_input_) {
+									 
+    const I* input = static_cast<const I*>(input_);
+    const GO* grad_output = static_cast<const GO*>(grad_output_);
+    GI* grad_input = static_cast<GI*>(grad_input_);
+	
+    for (std::size_t i = 0; i < inputLenght; ++i) {
+        grad_input[i] = grad_output[i] / input[i];
+    }
+}
+
+namespace {
+static Registrar<LnImplBackward_cpu> registrarLnImplBackward_cpu_Float32(
+    {DataType::Float32, DataType::Float32, DataType::Float32},
+    Aidge::LnImpl_cpu_backward_kernel<float, float, float>);	
+static Registrar<LnImplBackward_cpu> registrarLnImplBackward_cpu_Float64(
+    {DataType::Float64, DataType::Float64, DataType::Float64},
+    Aidge::LnImpl_cpu_backward_kernel<double, double, double>);
+}  // namespace
+}  // namespace Aidge
+
+#endif /* AIDGE_CPU_OPERATOR_LNIMPL_BACKWARD_KERNEL_H_ */
diff --git a/include/aidge/backend/cpu/operator/LnImpl_forward_kernels.hpp b/include/aidge/backend/cpu/operator/LnImpl_forward_kernels.hpp
new file mode 100755
index 0000000000000000000000000000000000000000..c7681730cd0557bf51137cb02147b234de43a3f9
--- /dev/null
+++ b/include/aidge/backend/cpu/operator/LnImpl_forward_kernels.hpp
@@ -0,0 +1,42 @@
+/********************************************************************************
+ * 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_LNIMPL_FORWARD_KERNEL_H_
+#define AIDGE_CPU_OPERATOR_LNIMPL_FORWARD_KERNEL_H_
+
+#include "aidge/utils/Registrar.hpp"
+
+#include "aidge/backend/cpu/operator/LnImpl.hpp"
+
+namespace Aidge {
+template <class I, class O>
+void LnImpl_cpu_forward_kernel(std::size_t inputLenght,
+                               const void* input_,
+                               void* output_) {
+
+    const I* input = static_cast<const I*>(input_);
+    O* output = static_cast<O*>(output_);
+
+//#pragma omp parallel for if (inputLenght > 1024)
+    for (std::size_t i = 0; i < inputLenght; ++i) {
+        output[i] = std::log(input[i]);
+    }
+}
+
+namespace {
+static Registrar<LnImplForward_cpu> registrarLnImplForward_cpu_Float32(
+        {DataType::Float32, DataType::Float32}, Aidge::LnImpl_cpu_forward_kernel<float, float>);
+static Registrar<LnImplForward_cpu> registrarLnImplForward_cpu_Float64(
+        {DataType::Float64, DataType::Float64}, Aidge::LnImpl_cpu_forward_kernel<double, double>);
+}  // namespace
+}  // namespace Aidge
+
+#endif /* AIDGE_CPU_OPERATOR_LNIMPL_FORWARD_KERNEL_H_ */
diff --git a/src/operator/LnImpl.cpp b/src/operator/LnImpl.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..12885a944be46a977463e900af4047319bb1c8b2
--- /dev/null
+++ b/src/operator/LnImpl.cpp
@@ -0,0 +1,65 @@
+/********************************************************************************
+ * 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 <cassert>
+#include <chrono>  // std::chrono::milliseconds
+#include <numeric> // std::accumulate
+#include <thread>  // std::this_thread::sleep_for
+#include <vector>
+
+#include "aidge/operator/Ln.hpp"
+#include "aidge/utils/Types.h"
+#include "aidge/backend/cpu/data/GetCPUPtr.h"
+
+#include "aidge/backend/cpu/operator/LnImpl.hpp"
+#include "aidge/backend/cpu/operator/LnImpl_forward_kernels.hpp"
+#include "aidge/backend/cpu/operator/LnImpl_backward_kernels.hpp"
+
+Aidge::Elts_t Aidge::LnImpl_cpu::getNbRequiredProtected(const Aidge::IOIndex_t /*inputIdx*/) const {
+    // this implementation can be in-place
+    return Elts_t::DataElts(0);
+}
+
+void Aidge::LnImpl_cpu::forward() {
+    const Ln_Op& op_ = static_cast<const Ln_Op&>(mOp);
+	std::shared_ptr<Tensor> in0 = op_.getInput(0);
+    std::shared_ptr<Tensor> out0 = op_.getOutput(0);
+    AIDGE_ASSERT(in0, "missing input #0");
+
+    // Find the correct kernel type
+    auto kernelFunc = Registrar<LnImplForward_cpu>::create({
+        in0->dataType(),
+	    out0->dataType()});
+
+    // Call kernel
+    kernelFunc(in0->size(),
+        getCPUPtr(mOp.getRawInput(0)),
+        getCPUPtr(mOp.getRawOutput(0)));
+}
+
+void Aidge::LnImpl_cpu::backward() {
+    const Ln_Op& op_ = dynamic_cast<const Ln_Op&>(mOp);
+	std::shared_ptr<Tensor> in0  = op_.getInput(0);
+    std::shared_ptr<Tensor> out0  = op_.getOutput(0);
+    std::shared_ptr<Tensor> gra_int0 = op_.getInput(0)->grad();
+    std::shared_ptr<Tensor> gra_out0 = op_.getOutput(0)->grad();
+    AIDGE_ASSERT(out0, "missing output #0 for current {} operator", op_.type());
+
+    // Find the correct kernel type
+    auto kernelFunc = Registrar<LnImplBackward_cpu>::create({
+        in0->dataType(),
+	    gra_int0->dataType(),
+        gra_out0->dataType()        
+    });
+
+    // Call kernel
+    kernelFunc(gra_int0->size(), getCPUPtr(in0), getCPUPtr(gra_out0), getCPUPtr(gra_int0));
+}