From 314485e4f1756551c90005924877c0f39ddf50ed Mon Sep 17 00:00:00 2001 From: Parichay Kapoor Date: Mon, 12 Jul 2021 04:03:58 +0900 Subject: [PATCH] [layer] Update concat layer to V2 Update concat layer to V2 design. Signed-off-by: Parichay Kapoor --- nntrainer/layers/concat_layer.cpp | 94 +++++++++++++------------ nntrainer/layers/concat_layer.h | 40 +++++------ test/unittest/layers/meson.build | 1 + test/unittest/layers/unittest_layers_concat.cpp | 24 +++++++ 4 files changed, 91 insertions(+), 68 deletions(-) create mode 100644 test/unittest/layers/unittest_layers_concat.cpp diff --git a/nntrainer/layers/concat_layer.cpp b/nntrainer/layers/concat_layer.cpp index f065eed..14cc771 100644 --- a/nntrainer/layers/concat_layer.cpp +++ b/nntrainer/layers/concat_layer.cpp @@ -21,93 +21,99 @@ namespace nntrainer { -int ConcatLayer::initialize(Manager &manager) { - int status = ML_ERROR_NONE; - unsigned int channel = 0; +static constexpr size_t SINGLE_INOUT_IDX = 0; - if (getNumInputs() == 0) { - ml_loge("Error: number of inputs are not initialized"); - return ML_ERROR_INVALID_PARAMETER; - } +void ConcatLayer::finalize(InitLayerContext &context) { + unsigned int channel = 0; - const TensorDim &d = input_dim[0]; - channel += d.channel(); - for (unsigned int idx = 1; idx < getNumInputs(); ++idx) { - const TensorDim &dim = input_dim[idx]; + auto const &input_dims = context.getInputDimensions(); + const TensorDim &input_dim_0 = input_dims[SINGLE_INOUT_IDX]; + channel += input_dim_0.channel(); + for (unsigned int idx = 1; idx < context.getNumInputs(); ++idx) { + const TensorDim &dim = input_dims[idx]; - for (unsigned int i = 2; i < d.rank(); ++i) { - if (d[i] != dim[i]) + for (unsigned int i = 2; i < input_dim_0.rank(); ++i) { + if (input_dim_0[i] != dim[i]) throw std::runtime_error("Error: concat layer requires same " "shape from all input layers"); } - channel += input_dim[idx].channel(); + channel += dim.channel(); } - output_dim[0] = input_dim[0]; - output_dim[0].channel(channel); + TensorDim output_dim = input_dim_0; + output_dim.channel(channel); - return status; + context.setOutputDimensions({output_dim}); } -void ConcatLayer::forwarding(bool training) { - Tensor &hidden_ = net_hidden[0]->getVariableRef(); +void ConcatLayer::forwarding(RunLayerContext &context, bool training) { + Tensor &hidden_ = context.getOutput(SINGLE_INOUT_IDX); + const TensorDim &output_dim = hidden_.getDim(); #ifdef DEBUG + const TensorDim &input_dim = context.getInput(SINGLE_INOUT_IDX).getDim(); unsigned int channel = 0; - const TensorDim &d = net_input[0]->getDim(); - channel += d.channel(); - for (unsigned int idx = 1; idx < getNumInputs(); ++idx) { - const TensorDim &dim = net_input[idx]->getDim(); + channel += input_dim.channel(); + for (unsigned int idx = 1; idx < context.getNumInputs(); ++idx) { + const TensorDim &dim = context.getInput(idx).getDim(); - for (unsigned int i = 2; i < d.rank(); ++i) { - if (d[i] != dim[i]) + for (unsigned int i = 2; i < input_dim.rank(); ++i) { + if (input_dim[i] != dim[i]) throw std::runtime_error("Error: concat layer requires same " "shape from all input layers"); } - channel += input_dim[idx].channel(); + channel += dim.channel(); } - if (channel != output_dim[0].channel()) + if (channel != output_dim.channel()) throw std::runtime_error( "Error: Sum of channel of input layers is not same with output channel"); #endif - unsigned int f_size = output_dim[0].getFeatureLen(); + unsigned int f_size = output_dim.getFeatureLen(); /** * @todo avoid copy by creating input here as a shared_tensor of the output * here and then this layer can be in_place as well */ - for (unsigned int b = 0; b < input_dim[0].batch(); ++b) { + for (unsigned int b = 0; b < output_dim.batch(); ++b) { unsigned int position = 0; - for (unsigned int idx = 0; idx < getNumInputs(); ++idx) { - TensorDim in_dim = net_input[idx]->getDim(); - memcpy( - hidden_.getAddress(b * f_size + position), - net_input[idx]->getVariable().getAddress(b * in_dim.getFeatureLen()), - in_dim.getFeatureLen() * sizeof(float)); + for (unsigned int idx = 0; idx < context.getNumInputs(); ++idx) { + Tensor &input_ = context.getInput(idx); + TensorDim in_dim = input_.getDim(); + memcpy(hidden_.getAddress(b * f_size + position), + input_.getAddress(b * in_dim.getFeatureLen()), + in_dim.getFeatureLen() * sizeof(float)); position += in_dim.getFeatureLen(); } } } -void ConcatLayer::calcDerivative() { - TensorDim d = net_hidden[0]->getDim(); +void ConcatLayer::calcDerivative(RunLayerContext &context) { + Tensor &derivative_ = context.getIncomingDerivative(SINGLE_INOUT_IDX); + TensorDim d = derivative_.getDim(); unsigned int position = 0; - for (unsigned int idx = 0; idx < getNumInputs(); ++idx) { - TensorDim in_dim = input_dim[idx]; + for (unsigned int idx = 0; idx < context.getNumInputs(); ++idx) { + Tensor &ret_ = context.getOutgoingDerivative(idx); + TensorDim in_dim = ret_.getDim(); for (unsigned int b = 0; b < in_dim.batch(); ++b) { // TODO: replace with tensor::copy/fill - memcpy( - net_input[idx]->getGradient().getAddress(b * in_dim.getFeatureLen()), - net_hidden[0]->getGradient().getAddress(b * d.getFeatureLen() + - position), - in_dim.getFeatureLen() * sizeof(float)); + memcpy(ret_.getAddress(b * in_dim.getFeatureLen()), + derivative_.getAddress(b * d.getFeatureLen() + position), + in_dim.getFeatureLen() * sizeof(float)); } position += in_dim.getFeatureLen(); } } +void ConcatLayer::setProperty(const std::vector &values) { + if (!values.empty()) { + std::string msg = "[ConcatLayer] Unknown Layer Properties count " + + std::to_string(values.size()); + throw exception::not_supported(msg); + } +} + } /* namespace nntrainer */ diff --git a/nntrainer/layers/concat_layer.h b/nntrainer/layers/concat_layer.h index 2b554bc..67e6f9a 100644 --- a/nntrainer/layers/concat_layer.h +++ b/nntrainer/layers/concat_layer.h @@ -15,8 +15,7 @@ #define __CONCAT_LAYER_H__ #ifdef __cplusplus -#include -#include +#include namespace nntrainer { @@ -24,15 +23,12 @@ namespace nntrainer { * @class Concat Layer * @brief Concat Layer */ -class ConcatLayer : public LayerV1 { +class ConcatLayer : public Layer { public: /** * @brief Constructor of Concat Layer */ - template - ConcatLayer(unsigned int num_inputs_ = 1, Args... args) : LayerV1(args...) { - setNumInputs(num_inputs_); - } + ConcatLayer() : Layer() {} /** * @brief Destructor of Concat Layer @@ -52,39 +48,35 @@ public: ConcatLayer &operator=(ConcatLayer &&rhs) = default; /** - * @brief initialize layer - * @param[in] last last layer - * @retval #ML_ERROR_NONE Successful. - * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + * @copydoc Layer::finalize(InitLayerContext &context) */ - int initialize(Manager &manager) override; + void finalize(InitLayerContext &context) override; /** - * @brief Read Weight & Bias Data from file - * @param[in] file input stream file + * @copydoc Layer::forwarding(RunLayerContext &context, bool training) */ - void read(std::ifstream &file) override{}; + void forwarding(RunLayerContext &context, bool training) override; /** - * @brief Save Weight & Bias Data to file - * @param[in] file output stream file + * @copydoc Layer::calcDerivative(RunLayerContext &context) */ - void save(std::ofstream &file) override{}; + void calcDerivative(RunLayerContext &context) override; /** - * @copydoc Layer::forwarding(bool training) + * @copydoc Layer::getType() */ - void forwarding(bool training = true) override; + const std::string getType() const override { return ConcatLayer::type; }; /** - * @copydoc Layer::calcDerivative() + * @copydoc Layer::supportBackwarding() */ - void calcDerivative() override; + bool supportBackwarding() const { return true; } /** - * @copydoc Layer::getType() + * @copydoc Layer::setProperty(const PropertyType type, const std::string + * &value) */ - const std::string getType() const override { return ConcatLayer::type; }; + void setProperty(const std::vector &values) override; inline static const std::string type = "concat"; }; diff --git a/test/unittest/layers/meson.build b/test/unittest/layers/meson.build index 2c5a211..36df886 100644 --- a/test/unittest/layers/meson.build +++ b/test/unittest/layers/meson.build @@ -18,6 +18,7 @@ test_target = [ 'unittest_layers_preprocess.cpp', 'unittest_layers_split.cpp', 'unittest_layers_embedding.cpp', + 'unittest_layers_concat.cpp', ] exe = executable( diff --git a/test/unittest/layers/unittest_layers_concat.cpp b/test/unittest/layers/unittest_layers_concat.cpp new file mode 100644 index 0000000..6f7cfff --- /dev/null +++ b/test/unittest/layers/unittest_layers_concat.cpp @@ -0,0 +1,24 @@ +// SPDX-License-Identifier: Apache-2.0 +/** + * Copyright (C) 2021 Parichay Kapoor + * + * @file unittest_layers_concat.cpp + * @date 7 July 2021 + * @brief Concat Layer Test + * @see https://github.com/nnstreamer/nntrainer + * @author Parichay Kapoor + * @bug No known bugs except for NYI items + */ +#include + +#include + +#include +#include + +auto semantic_concat = + LayerSemanticsParamType(nntrainer::createLayer, + nntrainer::ConcatLayer::type, {}, {}, 0, false); + +INSTANTIATE_TEST_CASE_P(Concat, LayerSemantics, + ::testing::Values(semantic_concat)); -- 2.7.4