diff --git a/include/aidge/operator/DepthToSpace.hpp b/include/aidge/operator/DepthToSpace.hpp
new file mode 100644
index 0000000000000000000000000000000000000000..05d2b2e07bb63c4889f09a072dad7630f18fc708
--- /dev/null
+++ b/include/aidge/operator/DepthToSpace.hpp
@@ -0,0 +1,111 @@
+/********************************************************************************
+ * 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_CORE_OPERATOR_DEPTHTOSPACE_H_
+#define AIDGE_CORE_OPERATOR_DEPTHTOSPACE_H_
+
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "aidge/graph/Node.hpp"
+#include "aidge/operator/OperatorTensor.hpp"
+#include "aidge/utils/Registrar.hpp"
+#include "aidge/utils/StaticAttributes.hpp"
+#include "aidge/utils/Types.h"
+
+namespace Aidge {
+class DepthToSpace_OpImpl : public OperatorImpl {
+public:
+    DepthToSpace_OpImpl(const Operator& op, const std::string& backend = ""): OperatorImpl(op, backend) {}
+    void forward() override;
+};
+
+enum class DepthToSpaceAttr { BlockSize, Mode };
+
+
+class DepthToSpace_Op : public OperatorTensor,
+                public Registrable<DepthToSpace_Op,
+                    std::string,
+                    std::shared_ptr<OperatorImpl>(const DepthToSpace_Op &)> {
+public:
+    static const std::string Type;
+    enum class Mode { DCR, CRD };
+
+private:
+    using Attributes_ = StaticAttributes<DepthToSpaceAttr, std::uint32_t, Mode>;
+    template <DepthToSpaceAttr e>
+    using attr = typename Attributes_::template attr<e>;
+    const std::shared_ptr<Attributes_> mAttributes;
+
+public:
+
+    DepthToSpace_Op() = delete;
+
+    DepthToSpace_Op(const std::uint32_t blockSize, const Mode mode = Mode::CRD)
+        : OperatorTensor(Type, {InputCategory::Data}, 1),
+          mAttributes(std::make_shared<Attributes_>(
+            attr<DepthToSpaceAttr::BlockSize>(blockSize),
+            attr<DepthToSpaceAttr::Mode>(mode))) {}
+
+    /**
+     * @brief Copy-constructor. Copy the operator attributes and its output tensor(s),
+     * but not its input tensors (the new operator has no input associated).
+     * @param op Operator to copy.
+     */
+    DepthToSpace_Op(const DepthToSpace_Op& op);
+
+    /**
+     * @brief Clone the operator using its copy-constructor.
+     * @see Operator::DepthToSpace_Op
+     */
+    std::shared_ptr<Operator> clone() const override {
+        return std::make_shared<DepthToSpace_Op>(*this);
+    }
+
+    // Data operator[](const char* inputName) override final {
+    //     std::shared_ptr<Tensor> in = (strcmp(inputName, "data")) ? mInputs[0] :
+    //         (strcmp(inputName, "weight") ? mInputs[1] :
+    //         (strcmp(inputName, "bias") ? mInputs[2] :
+    //         nullptr));
+    //     assert((in!=nullptr) && "No such parameter");
+    //     return *in;
+    // }
+
+
+    bool forwardDims(bool /*allowDataDependency*/ = false) override final;
+
+    void setBackend(const std::string &name, DeviceIdx_t device = 0) override final;
+
+    inline std::shared_ptr<Attributes> attributes() const override { return mAttributes; }
+    inline std::uint32_t& blockSize() const { return mAttributes->template getAttr<DepthToSpaceAttr::BlockSize>(); }
+    inline Mode& mode() const { return mAttributes->template getAttr<DepthToSpaceAttr::Mode>(); }
+
+    static const std::vector<std::string> getInputsName() {
+        return {"data_input"};
+    }
+    static const std::vector<std::string> getOutputsName() {
+        return {"data_output"};
+    }
+};
+
+std::shared_ptr<Node> DepthToSpace(const std::uint32_t blockSize,
+                                    const DepthToSpace_Op::Mode mode = DepthToSpace_Op::Mode::CRD,
+                                    const std::string& name = "");
+
+}  // namespace Aidge
+
+namespace {
+template <>
+const char *const EnumStrings<Aidge::DepthToSpaceAttr>::data[] = { "BlockSize", "Mode" };
+}
+
+#endif //AIDGE_CORE_OPERATOR_DEPTHTOSPACE_H_
diff --git a/src/operator/DepthToSpace.cpp b/src/operator/DepthToSpace.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..32db101fc2bc013f0a832d0f5455e5f69cdebc63
--- /dev/null
+++ b/src/operator/DepthToSpace.cpp
@@ -0,0 +1,90 @@
+/********************************************************************************
+ * 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/operator/DepthToSpace.hpp"
+
+#include <array>
+#include <cstddef>  // std::size_t
+#include <string>
+#include <vector>
+
+#include "aidge/data/Tensor.hpp"
+#include "aidge/utils/ErrorHandling.hpp"
+#include "aidge/utils/Types.h"
+
+void Aidge::DepthToSpace_OpImpl::forward() {
+    const DepthToSpace_Op& op = dynamic_cast<const DepthToSpace_Op&>(mOp);
+    // suppose an NCHW Tensor format
+
+    // Get input dimensions
+    const auto& dims = op.getInput(0)->dims<4>();
+    // Assert that c is divisible by blocksize squared
+    assert(dims[1] % (op.blockSize() * op.blockSize()) == 0 && "Number of channels must be divisible by blocksize squared");
+    // get final output dimension
+    const std::array<DimSize_t, 4> final_dims = op.getOutput(0)->dims<4>();
+
+    std::size_t b = dims[0];
+    std::size_t c = dims[1] / (static_cast<DimSize_t>(op.blockSize()) * static_cast<DimSize_t>(op.blockSize()));
+    std::size_t h = dims[2];
+    std::size_t w = dims[3];
+
+    // Copt input tensor to output
+    op.setOutput(0, op.getInput(0));
+
+    // Step 1: Resize
+    const std::vector<DimSize_t> resize_dims =
+        (op.mode() == DepthToSpace_Op::Mode::CRD) ?
+            std::vector<DimSize_t>({b, c, static_cast<DimSize_t>(op.blockSize()), static_cast<DimSize_t>(op.blockSize()), h, w}) :
+            std::vector<DimSize_t>({b, static_cast<DimSize_t>(op.blockSize()), static_cast<DimSize_t>(op.blockSize()), c, h, w});
+    op.getOutput(0)->resize(resize_dims);
+
+    // Step 2: Transpose
+    const std::vector<DimSize_t> transpose_order =
+        (op.mode() == DepthToSpace_Op::Mode::CRD) ?
+            std::vector<DimSize_t>({0, 1, 4, 2, 5, 3}) :
+            std::vector<DimSize_t>({0, 3, 4, 1, 5, 2});
+    op.getOutput(0)->copyTranspose(*(op.getOutput(0)), transpose_order);
+
+    // Step 3: Final resize
+    op.getOutput(0)->resize(final_dims);
+}
+
+const std::string Aidge::DepthToSpace_Op::Type = "DepthToSpace";
+
+
+bool Aidge::DepthToSpace_Op::forwardDims(bool /*allowDataDependency*/) {
+    if (inputsAssociated()) {
+        AIDGE_ASSERT(getInput(0)->nbDims() == 4, "{} Operator only accepts 4-D input Tensors.", DepthToSpace_Op::Type);
+
+        // Compute output dims
+        const std::array<DimSize_t, 4>& inDims = getInput(0)->dims<4>();
+        const std::vector<DimSize_t> outDims =
+                {inDims[0],
+                 inDims[1] / (static_cast<DimSize_t>(blockSize()) * static_cast<DimSize_t>(blockSize())),
+                 inDims[2] * static_cast<DimSize_t>(blockSize()),
+                 inDims[3] * static_cast<DimSize_t>(blockSize())};
+
+        mOutputs[0]->resize(outDims);
+        return true;
+    }
+
+    return false;
+}
+
+void Aidge::DepthToSpace_Op::setBackend(const std::string& name, Aidge::DeviceIdx_t device) {
+    if (Registrar<DepthToSpace_Op>::exists({name})) {
+        SET_IMPL_MACRO(DepthToSpace_Op, *this, name);
+    }
+    else {
+        mImpl = std::make_shared<DepthToSpace_OpImpl>(*this);
+    }
+    mOutputs[0]->setBackend(name, device);
+}