LAYER_EMBEDDING, /** Embedding Layer type */
LAYER_RNN, /** RNN Layer type */
LAYER_LSTM, /** LSTM Layer type */
+ LAYER_SPLIT, /** Splite Layer type */
LAYER_TIME_DIST, /** Time Distributed Layer type */
LAYER_UNKNOWN = ML_TRAIN_LAYER_TYPE_UNKNOWN /** Unknown */
};
$(NNTRAINER_ROOT)/nntrainer/layers/lstm.cpp \
$(NNTRAINER_ROOT)/nntrainer/layers/time_dist.cpp \
$(NNTRAINER_ROOT)/nntrainer/layers/acti_func.cpp \
+ $(NNTRAINER_ROOT)/nntrainer/layers/split_layer.cpp \
$(NNTRAINER_ROOT)/nntrainer/layers/common_properties.cpp \
$(NNTRAINER_ROOT)/nntrainer/graph/network_graph.cpp \
$(NNTRAINER_ROOT)/nntrainer/graph/graph_core.cpp \
#include <preprocess_flip_layer.h>
#include <preprocess_translate_layer.h>
#include <rnn.h>
+#include <split_layer.h>
#include <time_dist.h>
#ifdef ENABLE_TFLITE_BACKBONE
#endif
ac.registerFactory(nntrainer::createLayer<EmbeddingLayer>,
EmbeddingLayer::type, LayerType::LAYER_EMBEDDING);
-
ac.registerFactory(nntrainer::createLayer<RNNLayer>, RNNLayer::type,
LayerType::LAYER_RNN);
-
ac.registerFactory(nntrainer::createLayer<LSTMLayer>, LSTMLayer::type,
LayerType::LAYER_LSTM);
-
ac.registerFactory(nntrainer::createLayer<TimeDistLayer>, TimeDistLayer::type,
LayerType::LAYER_TIME_DIST);
-
+ ac.registerFactory(nntrainer::createLayer<SplitLayer>, SplitLayer::type,
+ LayerType::LAYER_SPLIT);
ac.registerFactory(AppContext::unknownFactory<nntrainer::Layer>, "unknown",
LayerType::LAYER_UNKNOWN);
}
*/
void calcDerivative() override;
+ using Layer::setProperty;
+
/**
* @copydoc Layer::setProperty(const PropertyType type, const std::string
* &value)
#include <parse_util.h>
#include <pooling2d_layer.h>
#include <rnn.h>
+#include <split_layer.h>
#include <time_dist.h>
#ifdef ENABLE_TFLITE_BACKBONE
return EmbeddingLayer::type;
case LayerType::LAYER_TIME_DIST:
return TimeDistLayer::type;
+ case LayerType::LAYER_SPLIT:
+ return SplitLayer::type;
case LayerType::LAYER_UNKNOWN:
/** fallthrough intended */
default:
input_.reshape(input_reshape_helper);
for (unsigned int idx = 0; idx < getNumOutputs(); idx++) {
- Tensor &output_ = net_hidden[0]->getVariableRef();
+ Tensor &output_ = net_hidden[idx]->getVariableRef();
output_.reshape(output_reshape_helper);
for (unsigned int batch = 0; batch < input_.batch(); batch++) {
input_.getAddress(batch, 0, idx, 0), input_reshape_helper.width(),
{1, 1, 1, input_reshape_helper.width()});
Tensor dest_tensor = Tensor::Map(
- output_.getAddress(batch, 0, idx, 0), output_reshape_helper.width(),
+ output_.getAddress(batch, 0, 0, 0), output_reshape_helper.width(),
{1, 1, 1, output_reshape_helper.width()});
dest_tensor.copy(source_tensor);
}
input_.reshape(input_reshape_helper);
for (unsigned int idx = 0; idx < getNumOutputs(); idx++) {
- Tensor &output_ = net_hidden[0]->getGradientRef();
+ Tensor &output_ = net_hidden[idx]->getGradientRef();
output_.reshape(output_reshape_helper);
for (unsigned int batch = 0; batch < input_.batch(); batch++) {
input_reshape_helper.width(),
{1, 1, 1, input_reshape_helper.width()});
const Tensor source_tensor = Tensor::Map(
- output_.getAddress(batch, 0, idx, 0), output_reshape_helper.width(),
+ output_.getAddress(batch, 0, 0, 0), output_reshape_helper.width(),
{1, 1, 1, output_reshape_helper.width()});
dest_tensor.copy(source_tensor);
}
* @brief Constructor of Split Layer
*/
template <typename... Args>
- SplitLayer(unsigned int num_output_, unsigned int split_dim = 1,
- Args... args) :
+ SplitLayer(unsigned int split_dim = 1, Args... args) :
Layer(args...),
- split_dimension(split_dim) {
- setNumOutputs(num_output_);
- }
+ split_dimension(split_dim) {}
/**
* @brief Destructor of Split Layer
*/
void calcDerivative() override;
+ using Layer::setProperty;
+
/**
* @copydoc Layer::setProperty(const PropertyType type, const std::string
* &value)
#include <activation_layer.h>
#include <addition_layer.h>
#include <bn_layer.h>
+#include <concat_layer.h>
#include <conv2d_layer.h>
#include <embedding.h>
#include <fc_layer.h>
#include <preprocess_flip_layer.h>
#include <preprocess_translate_layer.h>
#include <rnn.h>
+#include <split_layer.h>
#include <tensor_dim.h>
#include <util_func.h>
}
/**
+ * @brief nntainer split Layer for test
+ */
+class nntrainer_SplitLayer
+ : public nntrainer_abstractLayer<nntrainer::SplitLayer> {
+
+protected:
+ typedef nntrainer_abstractLayer<nntrainer::SplitLayer> super;
+
+ virtual void prepareLayer() {
+ int status = setProperty("input_shape=9:8:7:6");
+ EXPECT_EQ(status, ML_ERROR_NONE);
+ }
+
+ nntrainer::Tensor result;
+};
+
+/**
+ * @brief Split Layer
+ */
+TEST_F(nntrainer_SplitLayer, init_01_p) {
+ nntrainer::TensorDim out_dim_expect;
+ layer.setBatch(9);
+
+ for (unsigned int idx = 1; idx < nntrainer::MAXDIM; idx++) {
+ std::stringstream ss;
+ ss << "split_dimension=" << idx;
+ EXPECT_EQ(ML_ERROR_NONE, layer.setProperty({ss.str()}));
+ ss.clear();
+ layer.initialize(manager);
+
+ auto in_dim = layer.getInputDimension();
+ auto out_dim = layer.getOutputDimension();
+
+ int val_at_split_dim = in_dim[0].getTensorDim(idx);
+ EXPECT_EQ(out_dim.size(), val_at_split_dim);
+
+ out_dim_expect = in_dim[0];
+ out_dim_expect.setTensorDim(idx, 1);
+
+ for (auto const &out_d : out_dim) {
+ EXPECT_EQ(out_dim_expect, out_d);
+ }
+ }
+}
+
+/**
+ * @brief Split Layer
+ */
+TEST_F(nntrainer_SplitLayer, init_02_n) {
+ nntrainer::TensorDim out_dim_expect;
+ layer.setBatch(9);
+ layer.setProperty({"split_dimension=0"});
+ EXPECT_EQ(ML_ERROR_INVALID_PARAMETER, layer.initialize(manager));
+}
+
+/**
+ * @brief Split Layer
+ */
+TEST_F(nntrainer_SplitLayer, init_03_n) {
+ nntrainer::TensorDim out_dim_expect;
+ layer.setBatch(9);
+ layer.setProperty({"split_dimension=5"});
+ EXPECT_EQ(ML_ERROR_INVALID_PARAMETER, layer.initialize(manager));
+ layer.setProperty({"split_dimension=8"});
+ EXPECT_EQ(ML_ERROR_INVALID_PARAMETER, layer.initialize(manager));
+}
+
+/**
+ * @brief Split + Concat Layer
+ */
+TEST_F(nntrainer_SplitLayer, forwarding_backwarding_01_p) {
+ nntrainer::ConcatLayer concat;
+ nntrainer::TensorDim out_dim_expect;
+ layer.setBatch(9);
+ concat.setBatch(9);
+
+ /// enable till nntrainer::MAXDIM once #1227 is resolved
+ for (unsigned int idx = 1; idx < 2; idx++) {
+ std::stringstream ss;
+ ss << "num_inputs=" << idx;
+ EXPECT_EQ(ML_ERROR_NONE, concat.setProperty({ss.str()}));
+ ss.str(std::string());
+
+ ss << "split_dimension=" << idx;
+ layer.setProperty({ss.str()});
+ EXPECT_EQ(ML_ERROR_NONE, layer.setProperty({ss.str()}));
+
+ auto in_dim = layer.getInputDimension();
+ auto out_dim = layer.getOutputDimension();
+ unsigned int val_at_split_dim = in_dim[0].getTensorDim(idx);
+ out_dim_expect = in_dim[0];
+ out_dim_expect.setTensorDim(idx, 1);
+
+ for (unsigned int ni = 0; ni < val_at_split_dim; ni++)
+ concat.setInputDimension(
+ std::vector<nntrainer::TensorDim>(val_at_split_dim, out_dim_expect));
+
+ nntrainer::Manager manager;
+ manager.setInferenceInOutMemoryOptimization(false);
+
+ layer.initialize(manager);
+ concat.initialize(manager);
+
+ layer.setInputBuffers(manager.trackLayerInputs(
+ layer.getType(), layer.getName(), layer.getInputDimension()));
+ layer.setOutputBuffers(manager.trackLayerOutputs(
+ layer.getType(), layer.getName(), layer.getOutputDimension()));
+ concat.setInputBuffers(layer.getOutputRef());
+ concat.setOutputBuffers(manager.trackLayerOutputs(
+ concat.getType(), concat.getName(), concat.getOutputDimension()));
+
+ manager.initializeTensors(true);
+ manager.allocateTensors();
+
+ nntrainer::Tensor input(in_dim[0]);
+ nntrainer::Tensor derivative(in_dim[0]);
+ input.setRandUniform();
+ derivative.setRandUniform();
+
+ auto split_outs = layer.forwarding_with_val({MAKE_SHARED_TENSOR(input)});
+ auto joined_inputs = concat.forwarding_with_val(split_outs);
+
+ EXPECT_EQ(input, *joined_inputs[0].get());
+
+ auto split_derv =
+ concat.backwarding_with_val({MAKE_SHARED_TENSOR(derivative)});
+ auto joined_deriv = layer.backwarding_with_val(split_derv);
+
+ EXPECT_EQ(*joined_deriv[0].get(), derivative);
+ }
+}
+
+/**
* @brief Main gtest
*/
int main(int argc, char **argv) {