nntrainer::Tensor in_tensor;
try {
in_tensor = nntrainer::Tensor(inbatch);
- mainNet.backwarding({MAKE_SHARED_TENSOR(in_tensor)}, {Q}, iter);
+ mainNet.forwarding({MAKE_SHARED_TENSOR(in_tensor)}, {Q});
+ mainNet.backwarding({Q}, iter);
} catch (...) {
std::cerr << "Error during backwarding the network" << std::endl;
return -1;
return out;
}
-void NetworkGraph::backwarding(sharedConstTensors output, int iteration) {
-
- /** First layer in Sorted must a INPUT layer */
- for (unsigned int i = Sorted.size() - 1; i > skip_non_trainable_layers + 1;
- i--) {
- LayerNode &layer_node = Sorted[i];
- if (istrequal(layer_node.layer->getType(), nntrainer::LossLayer::type)) {
- layer_node.layer->backwarding(output);
- } else {
- layer_node.layer->backwarding();
- }
- optimizer->apply_gradients(layer_node.layer->getWeightsRef(), iteration);
- }
-
- /** The last trainable layer need not calculate the derivatives */
- // Order is matter here. 1. calcGradient 2.Derivative & Gradient
- Sorted[skip_non_trainable_layers + 1].layer->calcGradient();
-#ifdef ENABLE_TEST
- Sorted[skip_non_trainable_layers + 1].layer->calcDerivative();
-#endif
- optimizer->apply_gradients(
- Sorted[skip_non_trainable_layers + 1].layer->getWeightsRef(), iteration);
-}
-
std::vector<TensorDim> NetworkGraph::getInputDimension() {
return Sorted[0].layer->getInputDimension();
}
sharedConstTensors forwarding(sharedConstTensors input);
/**
- * @brief backwarding network graph
- * @param[in] input data
- * @param[in] iteration
+ * @brief getter of ordered graph
+ * @retval ordered LayerNode list
*/
- void backwarding(sharedConstTensors input, int iteration);
+ const std::vector<LayerNode> &getSorted() { return Sorted; }
- void setOptimizer(std::shared_ptr<Optimizer> opt) { optimizer = opt; }
+ /**
+ * @brief get begin iterator for the backwarding
+ * @retval const reverse iterator marking the begin of backwarding
+ */
+ std::vector<LayerNode>::const_reverse_iterator getBackwardingBeginIter() {
+ return Sorted.crbegin();
+ }
/**
- * @brief getter of ordered graph
- * @retval ordered LayerNode list
+ * @brief get end iterator for the backwarding
+ * @retval const reverse iterator marking the end of backwarding
*/
- std::vector<LayerNode> getSorted() { return Sorted; }
+ std::vector<LayerNode>::const_reverse_iterator getBackwardingEndIter() {
+ return Sorted.crend() - skip_non_trainable_layers;
+ }
/**
* @brief getter of output dimension of graph
skip_non_trainable_layers; /**< denotes the number of non-trainable layers
at the start of the graph */
- std::shared_ptr<Optimizer> optimizer;
-
/**
* @brief Calculate the number of non-trainable layers at the start
*/
/**
* @brief Apply the gradient for the layer
* @param[in] iteration Iteration value for the Optimizer
+ * @note This function is no-op if optimizer is nullptr
*/
virtual void applyGradient(unsigned int iteration,
std::shared_ptr<Optimizer> optimizer) {
model_graph.topologicalSort();
+ auto &sorted = model_graph.getSorted();
+ if (sorted.empty() ||
+ !istrequal(sorted.back().layer->getType(), LossLayer::type)) {
+ ml_loge("last layer is not loss layer");
+ return ML_ERROR_INVALID_PARAMETER;
+ }
+
compiled = true;
return status;
manager.initialize();
- model_graph.setOptimizer(opt);
-
initialized = true;
return status;
}
* Call backwarding function of layer in reverse order
* No need to call at first Input Layer (No data to be updated)
*/
-void NeuralNetwork::backwarding(sharedConstTensors input,
- sharedConstTensors label, int iteration) {
-
- if (model_graph.Sorted.empty() ||
- !istrequal(model_graph.Sorted.back().layer->getType(), LossLayer::type)) {
- throw std::invalid_argument("last layer is not loss layer");
- }
-
- forwarding(input, label);
-
- sharedConstTensors output = label;
-
- model_graph.backwarding(output, iteration);
+void NeuralNetwork::backwarding(sharedConstTensors label, int iteration) {
+
+ /**
+ * @note -2 as backwarding for input layer is not supported and
+ * last layer backwarding is run out of this loop
+ */
+ auto iter_begin = model_graph.getBackwardingBeginIter();
+ auto iter_end = model_graph.getBackwardingEndIter();
+ for (auto iter = iter_begin; iter != iter_end - 2; iter++) {
+ auto layer = iter->layer;
+ if (istrequal(layer->getType(), nntrainer::LossLayer::type)) {
+ layer->backwarding(label);
+ } else {
+ layer->backwarding();
+ }
+ opt->apply_gradients(layer->getWeightsRef(), iteration);
+ }
+
+ auto last_layer = (iter_end - 2)->layer;
+ /**
+ * The last trainable layer need not calculate the derivatives
+ * Do not change this order:
+ * 1. calcGradient
+ * 2. calcDerivative
+ * 3. applyGradient
+ */
+ last_layer->calcGradient();
+#ifdef ENABLE_TEST
+ last_layer->calcDerivative();
+#endif
+ opt->apply_gradients(last_layer->getWeightsRef(), iteration);
}
float NeuralNetwork::getLoss() {
if (data_buffer->getDataFromBuffer(nntrainer::BufferType::BUF_TRAIN,
in->getData(), label->getData())) {
try {
- backwarding({in}, {label}, iter++);
+ forwarding({in}, {label});
+ backwarding({label}, iter++);
} catch (...) {
data_buffer->clear(nntrainer::BufferType::BUF_TRAIN);
ml_loge("Error: training error in #%d/%d.", epoch_idx, epochs);
* @param[in] label List of Label Tensors for the model
* @param[in] iteration Iteration Number for the optimizer
*/
- void backwarding(sharedConstTensors input, sharedConstTensors label,
- int iteration);
+ void backwarding(sharedConstTensors label, int iteration);
/**
* @brief save model and training parameters into file
*/
void addOptimizerVariable(const TensorDim &dim) {
opt_vars.emplace_back(dim);
+ // TODO: Move this out when an optimizer does not initialize with 0.
opt_vars.back().setZero();
}
for (int i = 0; i < batch; ++i)
output.setValue(i, 0, 0, 3, 1.0);
- NN.backwarding({MAKE_SHARED_TENSOR(input)}, {MAKE_SHARED_TENSOR(output)}, 1);
+ NN.forwarding({MAKE_SHARED_TENSOR(input)}, {MAKE_SHARED_TENSOR(output)});
+ NN.backwarding({MAKE_SHARED_TENSOR(output)}, 1);
}
static IniSection nw_base("model", "Type = NeuralNetwork | "
EXPECT_EQ(status, ML_ERROR_NONE);
EXPECT_NO_THROW(opt->addOptimizerVariable(layer.getWeightsRef()));
- // status = layer.setOptimizer(op);
- // EXPECT_EQ(status, ML_ERROR_NONE);
return status;
}
it->forward(iteration);
}
- nn.getNetworkGraph().backwarding(label, iteration);
+ nn.backwarding(label, iteration);
for (auto it = nodes.rbegin(); it != nodes.rend() - 1; it++)
it->backward(iteration);