From 150ef2e52af4e13e6e168181594b6a0db649e217 Mon Sep 17 00:00:00 2001 From: "jijoong.moon" Date: Fri, 20 Nov 2020 16:39:23 +0900 Subject: [PATCH] [ GRAPH ] Remove unused function and add doxygen note In neural network class, there is fucntions which should be moved to graph. In this PR, remove member functions which is not used any more and add doxygen comment in graph header. **Self evaluation:** 1. Build test: [X]Passed [ ]Failed [ ]Skipped 2. Run test: [X]Passed [ ]Failed [ ]Skipped Signed-off-by: jijoong.moon --- .../CIFAR_Classification/res/Classification.ini | 4 +- Applications/VGG/jni/main.cpp | 1 - api/capi/src/nntrainer.cpp | 5 +- api/ccapi/include/model.h | 5 + .../tensor_filter/tensor_filter_nntrainer.cc | 2 + nntrainer/graph/network_graph.cpp | 224 +++++++++------------ nntrainer/graph/network_graph.h | 120 +++++++++-- nntrainer/layers/flatten_layer.cpp | 10 +- nntrainer/layers/layer.cpp | 24 +-- nntrainer/layers/layer_internal.h | 14 +- nntrainer/models/model_loader.cpp | 5 + nntrainer/models/neuralnet.cpp | 162 +-------------- nntrainer/models/neuralnet.h | 61 ++---- test/unittest/unittest_nntrainer_layers.cpp | 2 +- test/unittest/unittest_nntrainer_models.cpp | 6 +- 15 files changed, 262 insertions(+), 383 deletions(-) diff --git a/Applications/TransferLearning/CIFAR_Classification/res/Classification.ini b/Applications/TransferLearning/CIFAR_Classification/res/Classification.ini index eab4fdc..dcfea8b 100644 --- a/Applications/TransferLearning/CIFAR_Classification/res/Classification.ini +++ b/Applications/TransferLearning/CIFAR_Classification/res/Classification.ini @@ -6,9 +6,9 @@ Decay_rate = 0.96 # for the decay_rate for the decayed learning rate Decay_steps = 1000 # decay step for the exponential decayed learning rate Epochs = 30000 # Epochs Optimizer = adam # Optimizer : sgd (stochastic gradien decent), -#adam(Adamtive Moment Estimation) + # adam(Adamtive Moment Estimation) Loss = cross # Loss function : mse (mean squared error) -#cross(cross entropy) + # cross(cross entropy) Save_Path = "model_cls.bin" # model path to save / read batch_size = 32 # batch size beta1 = 0.9 # beta 1 for adam diff --git a/Applications/VGG/jni/main.cpp b/Applications/VGG/jni/main.cpp index 0aa34b5..ca576e4 100644 --- a/Applications/VGG/jni/main.cpp +++ b/Applications/VGG/jni/main.cpp @@ -418,7 +418,6 @@ int main(int argc, char *argv[]) { try { NN.compile(); NN.initialize(); - NN.assignMem(); } catch (...) { std::cerr << "Error during init" << std::endl; return 0; diff --git a/api/capi/src/nntrainer.cpp b/api/capi/src/nntrainer.cpp index 0db7d17..86c2998 100644 --- a/api/capi/src/nntrainer.cpp +++ b/api/capi/src/nntrainer.cpp @@ -293,10 +293,7 @@ int ml_train_model_run(ml_train_model_h model, ...) { NN = nnmodel->network; } - returnable f = [&]() { return NN->assignMem(); }; - status = nntrainer_exception_boundary(f); - - f = [&]() { return NN->train(arg_list); }; + returnable f = [&]() { return NN->train(arg_list); }; status = nntrainer_exception_boundary(f); return status; diff --git a/api/ccapi/include/model.h b/api/ccapi/include/model.h index 1ba88b2..3155fe7 100644 --- a/api/ccapi/include/model.h +++ b/api/ccapi/include/model.h @@ -98,6 +98,11 @@ public: */ virtual int initialize() = 0; + /** + * @brief Compile Network. This should be called before initialize + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ virtual int compile() = 0; /** diff --git a/nnstreamer/tensor_filter/tensor_filter_nntrainer.cc b/nnstreamer/tensor_filter/tensor_filter_nntrainer.cc index 2941f45..73164bb 100644 --- a/nnstreamer/tensor_filter/tensor_filter_nntrainer.cc +++ b/nnstreamer/tensor_filter/tensor_filter_nntrainer.cc @@ -130,6 +130,8 @@ void NNTrainer::validateTensor(const GstTensorsInfo *tensorInfo, info_s.dims.push_back(tensorInfo->info[0].dimension[NUM_DIM - 1]); + // Here, we only compare channel, height, width. + // Just use batch from info variable, cause it will be updated if it differs. for (unsigned int i = 1; i < NUM_DIM; ++i) { if (tensorInfo->info[0].dimension[i - 1] != dim.getDim()[NUM_DIM - i]) throw std::invalid_argument("Tensor dimension doesn't match"); diff --git a/nntrainer/graph/network_graph.cpp b/nntrainer/graph/network_graph.cpp index 7ac7fe0..cfc3e4f 100644 --- a/nntrainer/graph/network_graph.cpp +++ b/nntrainer/graph/network_graph.cpp @@ -11,14 +11,34 @@ * */ +#include +#include +#include +#include +#include #include +#include #include #include #include +#include #include namespace nntrainer { +void NetworkGraph::updateNameInLayers( + std::vector> &layers, const std::string &cname, + const std::string &name) { + for (unsigned int i = 0; i < layers.size(); ++i) { + for (unsigned int j = 0; j < layers[i]->input_layers.size(); ++j) { + if (istrequal(layers[i]->input_layers[j], cname)) { + layers[i]->input_layers[j] = name; + return; + } + } + } +} + void NetworkGraph::addEdge(unsigned int ith, LayerNode node) { if (ith > num_node - 1) throw std::invalid_argument("Exceed total number of layer"); @@ -28,7 +48,9 @@ void NetworkGraph::addEdge(unsigned int ith, LayerNode node) { void NetworkGraph::addLayerNode(std::shared_ptr layer) { std::list l; - LayerNode *node = new LayerNode(); + std::unique_ptr node = std::make_unique(); + + ensureName(layer); node->layer = layer; node->index = num_node; @@ -38,7 +60,8 @@ void NetworkGraph::addLayerNode(std::shared_ptr layer) { num_node++; } -void NetworkGraph::topologicalSortUtil(unsigned int ith, bool visited[], +void NetworkGraph::topologicalSortUtil(unsigned int ith, + std::vector &visited, std::stack &Stack) { visited[ith] = true; @@ -77,10 +100,13 @@ LayerNode &NetworkGraph::getSortedLayerNode(unsigned int ith) { void NetworkGraph::topologicalSort() { std::stack Stack; + std::vector visited(num_node); + + std::fill(visited.begin(), visited.end(), false); - bool *visited = new bool[num_node]; - for (unsigned int i = 0; i < num_node; ++i) - visited[i] = false; + // TODO : After make node list of graph, we have to find root. (That means it + // should be the only one input for now.). Need to support multiple input and + // support search. for (unsigned int i = 0; i < num_node; ++i) { if (visited[i] == false) { @@ -88,22 +114,14 @@ void NetworkGraph::topologicalSort() { } } - delete[] visited; - while (Stack.empty() == false) { Sorted.push_back(Stack.top()); Stack.pop(); } - - for (unsigned int i = 0; i < Sorted.size(); ++i) { - std::cout << Sorted[i].layer->getName() << " "; - } - std::cout << std::endl; } void NetworkGraph::ensureName(std::shared_ptr layer, - const std::string &prefix = "", - bool force_rename = false) { + const std::string &prefix, bool force_rename) { std::string orig_name = layer->getName(); bool orig_name_empty = orig_name.empty(); if (!orig_name_empty && !force_rename && @@ -138,38 +156,37 @@ int NetworkGraph::realizeMultiInputType(Layer ¤t) { if (current.num_inputs == 1) return ML_ERROR_NONE; - if (current.num_inputs > 1) { - std::shared_ptr layer = nntrainer::createLayer("addition"); - ensureName(layer, current.getName()); - layer->num_inputs = current.num_inputs; - layer->input_dim.resize(layer->num_inputs); - layer->input_layers.clear(); - for (unsigned int i = 0; i < current.input_layers.size(); ++i) - layer->input_layers.push_back(current.input_layers[i]); - - current.num_inputs = 1; - current.input_layers.clear(); - current.input_layers.push_back(layer->getName()); - addLayerNode(layer); - } + std::shared_ptr layer = nntrainer::createLayer(AdditionLayer::type); + ensureName(layer, current.getName()); + layer->num_inputs = current.num_inputs; + layer->input_dim.resize(layer->num_inputs); + layer->input_layers.clear(); + for (unsigned int i = 0; i < current.input_layers.size(); ++i) + layer->input_layers.push_back(current.input_layers[i]); + + current.num_inputs = 1; + current.input_layers.clear(); + current.input_layers.push_back(layer->getName()); + addLayerNode(layer); + return status; } int NetworkGraph::realizeFlattenType( - Layer ¤t, std::vector> layers) { + Layer ¤t, std::vector> &layers) { if (num_node == 0) { ml_loge("layer is empty"); return ML_ERROR_INVALID_PARAMETER; } - if (current.getType() == "flatten") { + if (current.getType() == FlattenLayer::type) { ml_loge( "It is not allowed to realize flatten layer, possibly flatten layer is " "added right after flatten"); return ML_ERROR_INVALID_PARAMETER; } - std::shared_ptr layer = nntrainer::createLayer("flatten"); + std::shared_ptr layer = nntrainer::createLayer(FlattenLayer::type); ensureName(layer, current.getName()); @@ -179,19 +196,13 @@ int NetworkGraph::realizeFlattenType( addLayerNode(layer); - for (unsigned int i = 0; i < layers.size(); ++i) { - for (unsigned int j = 0; j < layers[i]->input_layers.size(); ++j) { - if (istrequal(layers[i]->input_layers[j], current.getName())) { - layers[i]->input_layers[j] = layer->getName(); - } - } - } - return ML_ERROR_NONE; } int NetworkGraph::realizeActivationType( - Layer ¤t, std::vector> layers) { + Layer ¤t, std::vector> &layers) { + int status = ML_ERROR_NONE; + ActivationType act = current.getActivationType(); if (act == ActivationType::ACT_NONE) { @@ -204,7 +215,7 @@ int NetworkGraph::realizeActivationType( return ML_ERROR_INVALID_PARAMETER; } - if (current.getType() == "activation") { + if (current.getType() == ActivationLayer::type) { ml_loge("It is not allowed to realize ativation layer, possibly layer is " "added right after activation"); return ML_ERROR_INVALID_PARAMETER; @@ -223,6 +234,9 @@ int NetworkGraph::realizeActivationType( layer->input_layers.clear(); layer->input_layers.push_back(current.getName()); + if (current.num_outputs != 1) + return ML_ERROR_INVALID_PARAMETER; + layer->num_outputs = current.num_outputs; layer->output_dim.resize(layer->num_outputs); layer->output_layers.clear(); @@ -235,15 +249,9 @@ int NetworkGraph::realizeActivationType( addLayerNode(layer); - for (unsigned int i = 0; i < layers.size(); ++i) { - for (unsigned int j = 0; j < layers[i]->input_layers.size(); ++j) { - if (istrequal(layers[i]->input_layers[j], current.getName())) { - layers[i]->input_layers[j] = layer->getName(); - } - } - } + updateNameInLayers(layers, current.getName(), layer->getName()); - return ML_ERROR_NONE; + return status; } int NetworkGraph::addLossLayer(const LossType loss_type) { @@ -280,7 +288,7 @@ int NetworkGraph::addLossLayer(const LossType loss_type) { std::string input_str = getLayerNode(num_node - 1).layer->getName(); - std::shared_ptr layer = nntrainer::createLayer("loss"); + std::shared_ptr layer = std::make_unique(); ensureName(layer); @@ -299,8 +307,7 @@ int NetworkGraph::addLossLayer(const LossType loss_type) { layer->output_layers.push_back("__exit__"); } - std::shared_ptr temp = std::dynamic_pointer_cast(layer); - status = temp->setLoss(updated_loss_type); + status = layer->setLoss(updated_loss_type); NN_RETURN_STATUS(); addLayerNode(layer); @@ -308,27 +315,27 @@ int NetworkGraph::addLossLayer(const LossType loss_type) { return ML_ERROR_NONE; } -void NetworkGraph::setOutputLayers(std::vector> layers) { +void NetworkGraph::setOutputLayers( + std::vector> &layers) { for (unsigned int idx = 0; idx < layers.size(); ++idx) { - unsigned int count = 0; - std::cout << layers[idx]->getName() << " : "; for (unsigned int i = 0; i < layers.size(); ++i) { if (istrequal(layers[i]->getName(), layers[idx]->getName())) continue; for (unsigned int j = 0; j < layers[i]->input_layers.size(); ++j) { if (istrequal(layers[i]->input_layers[j], layers[idx]->getName())) { + for (unsigned int k = 0; k < layers[idx]->output_layers.size(); ++k) { + if (!istrequal(layers[idx]->output_layers[k], layers[i]->getName())) + continue; + } layers[idx]->output_layers.push_back(layers[i]->getName()); - std::cout << layers[idx]->output_layers[count] << ", "; - count++; } } } - if (layers[idx]->num_outputs != count) { - layers[idx]->num_outputs = count; - layers[idx]->output_dim.resize(count); + if (layers[idx]->num_outputs != layers[idx]->output_layers.size()) { + layers[idx]->num_outputs = layers[idx]->output_layers.size(); + layers[idx]->output_dim.resize(layers[idx]->output_layers.size()); } - std::cout << std::endl; } if (layers.back()->num_outputs == 0) { @@ -336,46 +343,44 @@ void NetworkGraph::setOutputLayers(std::vector> layers) { layers.back()->output_dim.resize(1); layers.back()->output_layers.push_back("__exit__"); } + + for (auto idx = layers.begin(); idx < layers.end(); ++idx) { + if ((*idx)->output_layers.size() == 0) + throw std::invalid_argument("There is un-connected node"); + } } int NetworkGraph::realizeMultiOutputType( - Layer ¤t, std::vector> layers) { + Layer ¤t, std::vector> &layers) { int status = ML_ERROR_NONE; if (current.num_outputs == 1) return ML_ERROR_NONE; - if (current.num_outputs > 1) { - std::shared_ptr layer = nntrainer::createLayer("output"); - ensureName(layer, current.getName()); - - layer->num_inputs = 1; - layer->input_layers.clear(); - layer->input_layers.push_back(current.getName()); + std::shared_ptr layer = nntrainer::createLayer(OutputLayer::type); + ensureName(layer, current.getName()); - layer->num_outputs = current.num_outputs; - layer->output_layers.clear(); + layer->num_inputs = 1; + layer->input_layers.clear(); + layer->input_layers.push_back(current.getName()); - for (unsigned int i = 0; i < current.output_layers.size(); ++i) { - layer->output_layers.push_back(current.output_layers[i]); + layer->num_outputs = current.num_outputs; + layer->output_layers.clear(); - for (unsigned int j = 0; j < layers.size(); ++j) { - for (unsigned int k = 0; k < layers[j]->input_layers.size(); ++k) { - if (istrequal(layers[j]->input_layers[k], current.getName())) { - layers[j]->input_layers[k] = layer->getName(); - } - } - } - } + for (unsigned int i = 0; i < current.output_layers.size(); ++i) { + layer->output_layers.push_back(current.output_layers[i]); - current.num_outputs = 1; - current.output_layers.clear(); - current.output_layers.push_back(layer->getName()); - addLayerNode(layer); + updateNameInLayers(layers, current.getName(), layer->getName()); } + + current.num_outputs = 1; + current.output_layers.clear(); + current.output_layers.push_back(layer->getName()); + addLayerNode(layer); + return status; } -int NetworkGraph::setGraphNode(std::vector> layers, +int NetworkGraph::setGraphNode(std::vector> &layers, const LossType loss_type) { int status = ML_ERROR_NONE; @@ -397,19 +402,20 @@ int NetworkGraph::setGraphNode(std::vector> layers, l.input_layers.push_back("__data__"); } - if (l.getType() != "addition" && l.getType() != "concat") { + if (l.getType() != AdditionLayer::type && + l.getType() != ConcatLayer::type) { status = realizeMultiInputType(l); NN_RETURN_STATUS(); } addLayerNode(layers[i]); - if (l.getType() != "activation") { + if (l.getType() != ActivationLayer::type) { status = realizeActivationType(l, layers); NN_RETURN_STATUS(); } - if (l.getType() != "output") { + if (l.getType() != OutputLayer::type) { status = realizeMultiOutputType(l, layers); NN_RETURN_STATUS(); } @@ -420,7 +426,7 @@ int NetworkGraph::setGraphNode(std::vector> layers, } } - if (layers.back()->getType() != "loss") { + if (layers.back()->getType() != LossLayer::type) { status = addLossLayer(loss_type); NN_RETURN_STATUS(); } @@ -459,16 +465,6 @@ LayerNode &NetworkGraph::getLayerNode(const std::string &layer_name) { throw std::invalid_argument("Cannot find Layer"); } -LayerNode &NetworkGraph::getSortedLayerNode(const std::string &layer_name) { - - for (unsigned int i = 0; i < Sorted.size(); ++i) { - if (istrequal(Sorted[i].layer->getName(), layer_name)) - return Sorted[i]; - } - - throw std::invalid_argument("Cannot find Layer"); -} - int NetworkGraph::setEdge() { int status = ML_ERROR_NONE; @@ -484,33 +480,8 @@ int NetworkGraph::setEdge() { continue; unsigned int to_node_id = getLayerNode((*iter).layer->input_layers[j]).index; - std::cout << getLayerNode(to_node_id).layer->getName() << " : " - << (*iter).layer->getName() << " "; addEdge(to_node_id, (*iter)); } - std::cout << std::endl; - } - - for (unsigned int i = 0; i < adj.size(); ++i) { - - std::list::iterator iter; - std::cout << i << " : " << getLayerNode(i).layer->getName() << " (" - << getLayerNode(i).layer->num_inputs << " "; - for (unsigned int j = 0; j < getLayerNode(i).layer->input_layers.size(); - ++j) - std::cout << getLayerNode(i).layer->input_layers[j] << ", "; - - std::cout << " --> " << getLayerNode(i).layer->num_outputs << " "; - for (unsigned int j = 0; j < getLayerNode(i).layer->output_layers.size(); - ++j) - std::cout << getLayerNode(i).layer->output_layers[j] << ", "; - - std::cout << " )" << std::endl; - - for (iter = std::next(adj[i].begin()); iter != adj[i].end(); ++iter) { - std::cout << " " << (*iter).layer->getName(); - } - std::cout << std::endl; } return status; @@ -525,7 +496,8 @@ void NetworkGraph::setBatchSize(unsigned int batch_size) { sharedConstTensors NetworkGraph::forwarding(sharedConstTensors input) { for (unsigned int i = 0; i < Sorted.size() - 1; ++i) { LayerNode &layer_node = Sorted[i]; - if (istrequal(layer_node.layer->getType(), "input")) { + // TODO : Need to fix. Input Layer is not the only one which can take input. + if (istrequal(layer_node.layer->getType(), InputLayer::type)) { layer_node.layer->forwarding(input); } else { layer_node.layer->forwarding(); diff --git a/nntrainer/graph/network_graph.h b/nntrainer/graph/network_graph.h index 2fdf4fa..6bd7a49 100644 --- a/nntrainer/graph/network_graph.h +++ b/nntrainer/graph/network_graph.h @@ -78,56 +78,152 @@ public: void setNumNetBufferSize(); /** - * @brief getter of number of nodes - * @param[out] number of nodes + * @brief getter of LayerNode with index number + * @param[in] index + * @ret LayerNode */ LayerNode &getLayerNode(unsigned int ith); + /** + * @brief getter of Sorted LayerNode with index number + * @param[in] index + * @ret LayerNode + */ LayerNode &getSortedLayerNode(unsigned int ith); + /** + * @brief getter of LayerNode with layer name + * @param[in] layer name + * @retval LayerNode + */ LayerNode &getLayerNode(const std::string &layer_name); - LayerNode &getSortedLayerNode(const std::string &layer_name); - - void ensureName(std::shared_ptr layer, const std::string &prefix, - bool force_rename); + /** + * @brief Ensure that layer has a name + */ + void ensureName(std::shared_ptr layer, const std::string &prefix = "", + bool force_rename = false); - void setOutputLayers(std::vector> layers); + /** + * @brief set Multi Output Layer + * @param[in] list of layers generated model loader + */ + void setOutputLayers(std::vector> &layers); - int setGraphNode(std::vector> layers, + /** + * @brief Build Graph Nodes + * @param[in] list of layers generated by model loader + * @param[in] loss_type loss type + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ + int setGraphNode(std::vector> &layers, const LossType loss_type); + /** + * @brief check and add Multi Input Layer : addition or concat Layer + * @param[in] current layer + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int realizeMultiInputType(Layer ¤t); + /** + * @brief check and add Multi output Layer : output Layer + * @param[in] current layer + * @param[in] layers list of layers generated by model loader + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int realizeMultiOutputType(Layer ¤t, - std::vector> layers); + std::vector> &layers); + /** + * @brief Realize act type to layer and insert it to layers + * @param[in] current layer + * @param[in] layers list of layers generated by model loader + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int realizeActivationType(Layer ¤t, - std::vector> layers); + std::vector> &layers); + /** + * @brief Realize flatten type to layer and insert it to layers + * @param[in] current layer + * @param[in] layers list of layers generated by model loader + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int realizeFlattenType(Layer ¤t, - std::vector> layers); + std::vector> &layers); + /** + * @brief adding loss layer at last position + * @param[in] loss_type loss type + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int addLossLayer(const LossType loss_type); + /** + * @brief make connection between nodes + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int setEdge(); + /** + * @brief set batch size + * @param[in] batch size + */ void setBatchSize(unsigned int batch_size); + /** + * @brief forwarding network graph + * @param[in] input data + * @retval output tensors + */ sharedConstTensors forwarding(sharedConstTensors input); + /** + * @brief backwarding network graph + * @param[in] input data + * @param[in] iteration + */ void backwarding(sharedConstTensors input, int iteration); + /** + * @brief getter of ordered graph + * @retval ordered LayerNode list + */ std::vector getSorted() { return Sorted; } + /** + * @brief getter of output dimension of graph + * @retval output tensor dim list + */ std::vector getOutputDimension(); + /** + * @brief getter of input dimension of graph + * @retval input tensor dim list + */ std::vector getInputDimension(); private: - void topologicalSortUtil(unsigned int ith, bool visited[], + /** + * @brief topological sort + * @param[in] ith index of LayerNode + * @param[in] visited temp list + * @param[in] stack for Node list to visit. + */ + void topologicalSortUtil(unsigned int ith, std::vector &visited, std::stack &Stack); + void updateNameInLayers(std::vector> &layers, + const std::string &cname, const std::string &name); + unsigned int num_node; /**< Total Number of Graph Nodes */ std::vector> adj; /**< Graph Structure */ std::vector Sorted; /**< Ordered Graph Node List */ diff --git a/nntrainer/layers/flatten_layer.cpp b/nntrainer/layers/flatten_layer.cpp index be8d489..ef01070 100644 --- a/nntrainer/layers/flatten_layer.cpp +++ b/nntrainer/layers/flatten_layer.cpp @@ -42,13 +42,15 @@ int FlattenLayer::initialize() { } void FlattenLayer::forwarding(sharedConstTensors in) { - memcpy(net_hidden[0]->var.getData(), net_input[0]->var.getData(), - output_dim[0].getDataLen() * sizeof(float)); + Tensor temp = net_input[0]->var; + temp.reshape(net_hidden[0]->var.getDim()); + net_hidden[0]->var = temp; } void FlattenLayer::backwarding(int iteration, sharedConstTensors in) { - memcpy(net_input[0]->grad.getData(), net_hidden[0]->grad.getData(), - input_dim[0].getDataLen() * sizeof(float)); + Tensor temp = net_hidden[0]->grad; + temp.reshape(net_input[0]->grad.getDim()); + net_input[0]->grad = temp; } } /* namespace nntrainer */ diff --git a/nntrainer/layers/layer.cpp b/nntrainer/layers/layer.cpp index da2ae50..8a64671 100644 --- a/nntrainer/layers/layer.cpp +++ b/nntrainer/layers/layer.cpp @@ -61,7 +61,7 @@ void Layer::setBatch(unsigned int batch) { output_dim[idx].setTensorDim(0, batch); } -std::vector Layer::getHidden() { +std::vector Layer::getOutputs() { std::vector ret; for (unsigned int i = 0; i < num_outputs; ++i) { ret.push_back(net_hidden[i]->var); @@ -69,7 +69,7 @@ std::vector Layer::getHidden() { return ret; } -std::vector Layer::getGradient() { +std::vector Layer::getDerivatives() { std::vector ret; for (unsigned int i = 0; i < num_inputs; ++i) { ret.push_back(net_input[i]->grad); @@ -100,27 +100,16 @@ void Layer::copy(std::shared_ptr l) { this->num_outputs = l->num_outputs; } -sharedConstTensors Layer::forwarding_with_val(sharedConstTensors input, - sharedConstTensors in) { +sharedConstTensors Layer::forwarding_with_val(sharedConstTensors input) { for (unsigned int i = 0; i < num_inputs; ++i) { net_input[i]->var = *input[i]; } - if (num_outputs == 0) - throw("invalid number of outputs"); - if (num_outputs != net_hidden.size()) net_hidden.resize(num_outputs); - // for (unsigned int i = 0; i < num_outputs; ++i) { - // sharedNetBuffer h_buffer = std::make_unique(); - // h_buffer->var = Tensor(getOutputDimension()[i]); - // h_buffer->grad = Tensor(getOutputDimension()[i]); - // net_hidden[i] = h_buffer; - // } - - forwarding(in); + forwarding(); nntrainer::sharedConstTensors out; @@ -139,12 +128,11 @@ sharedConstTensors Layer::backwarding_with_val(int iteration, net_hidden[i]->grad = *deriv[i]; } - if (num_inputs == 0) - throw("invalid number of inputs"); - if (num_inputs != net_input.size()) net_input.resize(num_inputs); + // TODO Need to fix to use LossLayer::type instead of "loss". But cyclic + // includes! if (istrequal(getType(), "loss")) { backwarding(iteration, in); } else { diff --git a/nntrainer/layers/layer_internal.h b/nntrainer/layers/layer_internal.h index 47517f8..8692f92 100644 --- a/nntrainer/layers/layer_internal.h +++ b/nntrainer/layers/layer_internal.h @@ -113,8 +113,7 @@ public: */ virtual void forwarding(sharedConstTensors in = {}) = 0; - virtual sharedConstTensors forwarding_with_val(sharedConstTensors input, - sharedConstTensors in = {}); + virtual sharedConstTensors forwarding_with_val(sharedConstTensors input); /** * @brief Back Propagation of a layer @@ -311,10 +310,11 @@ public: output_dim.resize(num_outputs); } - std::vector getHidden(); + std::vector getOutputs(); - std::vector getGradient(); + std::vector getDerivatives(); +#ifdef ENABLE_TEST void resizeNetInput(unsigned int size) { net_input.resize(size); } void resizeNetOutput(unsigned int size) { net_hidden.resize(size); } @@ -333,6 +333,7 @@ public: throw std::invalid_argument("Error: exceed num_input size"); net_hidden[i] = n_buffer; } +#endif protected: /** @@ -488,11 +489,6 @@ private: std::vector output_layers; /** - * @brief Ensure that layer has a name - */ - void ensureName(); - - /** * @brief check if @a type is valid and print if prop is valid to @a out */ template diff --git a/nntrainer/models/model_loader.cpp b/nntrainer/models/model_loader.cpp index 5734038..ce3c9ec 100644 --- a/nntrainer/models/model_loader.cpp +++ b/nntrainer/models/model_loader.cpp @@ -273,6 +273,11 @@ int ModelLoader::loadBackboneConfigIni(dictionary *ini, } // set input dimension for the first layer in the graph + + /** TODO :the layers is not the actual model_graph. It is just the vector of + * layers generated by Model Loader. so graph[0] is still valid. Also we need + * to consider that the first layer of ini might be th first of layers. Need + * to change*/ std::string input_shape = iniparser_getstring(ini, (backbone_name + ":Input_Shape").c_str(), ""); if (!input_shape.empty()) { diff --git a/nntrainer/models/neuralnet.cpp b/nntrainer/models/neuralnet.cpp index f2f60d5..ace4888 100644 --- a/nntrainer/models/neuralnet.cpp +++ b/nntrainer/models/neuralnet.cpp @@ -63,54 +63,6 @@ int NeuralNetwork::loadFromConfig(std::string config) { return ML_ERROR_NONE; } -int NeuralNetwork::initLossLayer() { - int status = ML_ERROR_NONE; - LossType updated_loss_type = loss_type; - - if (layers.back()->getType() != LossLayer::type) { - ml_loge("Error: loss layer is not the last layer of the model."); - return ML_ERROR_INVALID_PARAMETER; - } - - NodeType layer = layers.back(); - std::shared_ptr loss_layer = - std::static_pointer_cast(layer); - - if (updated_loss_type == LossType::LOSS_ENTROPY) { - if (layers.size() < 2) { - ml_loge("Error: Cross Entropy need last layer to have softmax or sigmoid " - "activation."); - return ML_ERROR_NOT_SUPPORTED; - } - NodeType act_layer = *(layers.end() - 2); - - if (!istrequal(act_layer->getType(), ActivationLayer::type)) { - ml_loge("Error: Cross Entropy need last layer to have softmax or sigmoid " - "activation."); - return ML_ERROR_NOT_SUPPORTED; - } - - layers.erase(layers.begin() + layers.size() - 2); - - switch (act_layer->getActivationType()) { - case ActivationType::ACT_SIGMOID: - updated_loss_type = LossType::LOSS_ENTROPY_SIGMOID; - break; - case ActivationType::ACT_SOFTMAX: - updated_loss_type = LossType::LOSS_ENTROPY_SOFTMAX; - break; - default: - ml_loge("Error: Cross Entropy not supported without softmax or sigmoid."); - return ML_ERROR_NOT_SUPPORTED; - } - } - - status = loss_layer->setLoss(updated_loss_type); - NN_RETURN_STATUS(); - - return status; -} - int NeuralNetwork::setProperty(std::vector values) { int status = ML_ERROR_NONE; @@ -187,7 +139,7 @@ int NeuralNetwork::setTrainConfig(std::vector values) { int NeuralNetwork::compile() { int status = ML_ERROR_NONE; - status = isInitializable(); + status = isCompilable(); NN_RETURN_STATUS(); ml_logd("Compile model"); @@ -239,13 +191,8 @@ int NeuralNetwork::initialize() { } for (unsigned int i = 0; i < l.input_layers.size(); ++i) { - std::cout << " " << l.input_layers[i]; std::shared_ptr n_buffer = std::make_unique(); - // TODO : NetBuffer of layers are managed by graph - // model_graph.netBuffers.push_back(n_buffer); - - Layer &in_layer = - *model_graph.getSortedLayerNode(l.input_layers[i]).layer; + Layer &in_layer = *model_graph.getLayerNode(l.input_layers[i]).layer; unsigned int location = 0; for (unsigned int j = 0; j < in_layer.output_layers.size(); ++j) { @@ -259,18 +206,16 @@ int NeuralNetwork::initialize() { l.net_input[i] = n_buffer; - model_graph.getSortedLayerNode(l.input_layers[i]) + model_graph.getLayerNode(l.input_layers[i]) .layer->net_hidden[location] = n_buffer; } } else { for (unsigned int i = 0; i < l.input_layers.size(); ++i) { - std::cout << " " << l.input_layers[i]; std::shared_ptr n_buffer = std::make_unique(); l.net_input[i] = n_buffer; } } - std::cout << std::endl; status = l.initialize(); NN_RETURN_STATUS(); @@ -628,7 +573,7 @@ int NeuralNetwork::train_run() { return status; } -int NeuralNetwork::isInitializable() { +int NeuralNetwork::isCompilable() { if (layers.empty()) { ml_loge("Layer is empty"); return ML_ERROR_INVALID_PARAMETER; @@ -663,7 +608,7 @@ int NeuralNetwork::addLayer(NodeType layer) { } /** Ensure that the layer has a name and is unique */ - ensureName(layer); + model_graph.ensureName(layer); /** Validate the layer to be added */ status = layer->checkValidation(); @@ -699,7 +644,7 @@ int NeuralNetwork::extendGraph(GraphType graph, std::string prefix) { * and ensure it is unique in this new graph */ std::string org_name = prefix + layer->getName(); - ensureName(layer, prefix, true); + model_graph.ensureName(layer, prefix, true); sub_in_out.insert(std::make_pair(org_name, layer->getName())); for (unsigned int i = 0; i < layer->input_layers.size(); ++i) { @@ -771,37 +716,6 @@ int NeuralNetwork::setDataBuffer(std::shared_ptr data_buffer) { return ML_ERROR_NONE; } -void NeuralNetwork::ensureName(NodeType layer, const std::string &prefix, - bool force_rename) { - std::string orig_name = layer->getName(); - bool orig_name_empty = orig_name.empty(); - if (!orig_name_empty && !force_rename && - layer_names.end() == layer_names.find(orig_name)) - return; - - /** If just prefix with layer name makes it unique - directly set the name */ - if (!orig_name_empty) { - std::string direct_name = prefix + orig_name; - if (layer_names.find(direct_name) == layer_names.end()) { - layer->setName(direct_name); - return; - } - } - - std::set::iterator iter; - std::string name; - if (orig_name_empty) - orig_name = layer->getType(); - std::string direct_name = prefix + orig_name; - - do { - name = direct_name + std::to_string(def_name_count++); - iter = layer_names.find(name); - } while (iter != layer_names.end()); - - layer->setName(name); -} - int NeuralNetwork::getLayer(const char *name, std::shared_ptr *layer) { std::shared_ptr layer_; @@ -825,70 +739,6 @@ int NeuralNetwork::getLayer(const char *name, NodeType *layer) { return status; } -int NeuralNetwork::realizeActivationType(const ActivationType act) { - unsigned int position = layers.end() - layers.begin() - 1; - return realizeActivationType(act, position); -} - -int NeuralNetwork::realizeActivationType(const ActivationType act, - const unsigned int position) { - if (act == ActivationType::ACT_NONE) { - /// ActivationType::ACT_NONE does not need realization - return ML_ERROR_NONE; - } - - if (layers.empty()) { - ml_loge("layer is empty"); - return ML_ERROR_INVALID_PARAMETER; - } - - Layer ¤t = *layers[position]; - if (istrequal(current.getType(), ActivationLayer::type)) { - ml_loge("It is not allowed to realize ativation layer, possibly layer is " - "added right after activation"); - return ML_ERROR_INVALID_PARAMETER; - } - - if (act == ActivationType::ACT_UNKNOWN) { - ml_loge("cannot realize unknown activation type"); - return ML_ERROR_INVALID_PARAMETER; - } - - std::shared_ptr act_layer = - std::make_shared(); - ensureName(act_layer, current.getName()); - act_layer->setActivation(act); - - layers.insert(layers.begin() + position + 1, act_layer); - return ML_ERROR_NONE; -} - -int NeuralNetwork::realizeFlattenType(const unsigned int position) { - if (layers.empty()) { - return ML_ERROR_INVALID_PARAMETER; - } - - Layer ¤t = *layers[position]; - if (istrequal(current.getType(), FlattenLayer::type)) { - ml_loge( - "It is not allowed to realize flatten layer, possibly flatten layer is " - "added right after flatten"); - return ML_ERROR_INVALID_PARAMETER; - } - - std::shared_ptr flatten_layer = - std::make_shared(); - - ensureName(flatten_layer, current.getName()); - layers.insert(layers.begin() + position + 1, flatten_layer); - return ML_ERROR_NONE; -} - -int NeuralNetwork::realizeFlattenType() { - unsigned int position = layers.end() - layers.begin() - 1; - return realizeFlattenType(position); -} - /** * @brief Set loss type for the neural network. */ diff --git a/nntrainer/models/neuralnet.h b/nntrainer/models/neuralnet.h index a8c4ae8..71a4c9a 100644 --- a/nntrainer/models/neuralnet.h +++ b/nntrainer/models/neuralnet.h @@ -153,6 +153,12 @@ public: */ int initialize(); + /** + * @brief Assign Graph Memory. This should be called after initialize. + * @TODO Consider to move Network Graph Class + * @retval #ML_ERROR_NONE Successful. + * @retval #ML_ERROR_INVALID_PARAMETER invalid parameter. + */ int assignMem(); /** @@ -398,9 +404,11 @@ private: AppContext app_context; /** Configurations bound to current app */ - NetworkGraph model_graph; + NetworkGraph model_graph; /** Network Model Graph */ - std::map sub_in_out; + std::map + sub_in_out; /** This is map to identyfy input and output layer name of + subgraph */ /** * @brief print function for neuralnet @@ -413,11 +421,6 @@ private: Layer::PrintPreset layerPrintPreset = Layer::PrintPreset::PRINT_SUMMARY); /** - * @brief Sets up and initialize the loss layer - */ - int initLossLayer(); - - /** * @brief Set Loss * @param[in] l loss value */ @@ -431,47 +434,11 @@ private: int train_run(); /** - * @brief check neural network is ready to init. - * @retval #ML_ERROR_NONE neuralnetwork is ready to init - * @retval #ML_ERROR_INVALID_PARAMETER not ready to init. - */ - int isInitializable(); - - /** - * @brief Realize act type to layer and insert it to layers - * @param[in] ActivationType act Activation Type - * @param[in] int Position position to insert activation layer. - * @note layer is inserted at position - */ - int realizeActivationType(const ActivationType act, - const unsigned int position); - - /** - * @copydoc int realizeActivationType(ActivationType act, unsigned int - * &position); - * @note layer is inserted at the back of layers - */ - int realizeActivationType(const ActivationType act); - - /** - * @brief Realize flatten type to layer and insert it to layers - * @param[in] int Position position to insert the layer. - * @note layer is inserted at position - */ - int realizeFlattenType(const unsigned int position); - - /** - * @copydoc int realizeActivationType(ActivationType act, unsigned int - * &position); - * @note layer is inserted at the back of layers - */ - int realizeFlattenType(); - - /** - * @brief Ensure that layer has a name + * @brief check neural network is ready to compile. + * @retval #ML_ERROR_NONE neuralnetwork is ready to compile + * @retval #ML_ERROR_INVALID_PARAMETER not ready to compile. */ - void ensureName(NodeType layer, const std::string &prefix = "", - bool force_rename = false); + int isCompilable(); /** * @brief Swap function for the class diff --git a/test/unittest/unittest_nntrainer_layers.cpp b/test/unittest/unittest_nntrainer_layers.cpp index 3392d9d..9c121c3 100644 --- a/test/unittest/unittest_nntrainer_layers.cpp +++ b/test/unittest/unittest_nntrainer_layers.cpp @@ -603,7 +603,7 @@ protected: nntrainer::LossLayer::type)) { if (with_loss) { EXPECT_NO_THROW(layers.back()->backwarding(1, {label})); - back_out = MAKE_SHARED_TENSOR(layers.back()->getGradient()[0]); + back_out = MAKE_SHARED_TENSOR(layers.back()->getDerivatives()[0]); } else { back_out = def_derivative; } diff --git a/test/unittest/unittest_nntrainer_models.cpp b/test/unittest/unittest_nntrainer_models.cpp index 31bd9b4..68240e3 100644 --- a/test/unittest/unittest_nntrainer_models.cpp +++ b/test/unittest/unittest_nntrainer_models.cpp @@ -232,7 +232,7 @@ void NodeWatcher::forward(int iteration) { << iteration; std::string err_msg = ss.str(); - std::vector out = node.layer->getHidden(); + std::vector out = node.layer->getOutputs(); verify(out[0], expected_output, err_msg + " at output"); } @@ -258,11 +258,11 @@ void NodeWatcher::backward(int iteration, bool should_verify) { << iteration; std::string err_msg = ss.str(); - std::vector out = node.layer->getGradient(); + std::vector out = node.layer->getDerivatives(); if (should_verify) { - verify(out[0], expected_dx, err_msg); verifyGrad(err_msg); + verify(out[0], expected_dx, err_msg); verifyWeight(err_msg); } } -- 2.7.4