With rebase, the var_grads representing inputs cannot be null tensors.
This patch provides a temporary fix for this issue. Proper fix for the
issue is added in #1544.
Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
if (lnode->requireLabel())
label_list.insert(label_list.end(), outputs.begin(), outputs.end());
- /**
- * @note must use existing properties like name/trainable of run_context to
- * create the new run_context
- */
lnode->configureRunContext(
// TODO: update weights spec for trainable based on layer trainable prop
tensor_manager->requestWeights(gnode, init_context.getWeightsSpec()),
* @brief Allocate and initialize the weight variable
*/
void initializeWeights() {
+ /**
+ * get the order of execution/usage order for the forwarding of the last
+ * layer and pass that as the max_exec_order ensuring that all weights with
+ * usage less than the max_exec_order are allocated.
+ *
+ * @note usage order of backwarding is not considered because weight has a
+ * separate memory pool for now. Later, if it shares pool with other
+ * tensors, then this must max of backward usage order.
+ */
tensor_manager->initializeWeights(
std::get<0>((*(cend() - 1))->getExecutionOrder()));
}
*/
void initializeTensors(bool training) {
if (!training)
+ /**
+ * get the order of execution/usage order for the forwarding of the last
+ * layer and pass that as the max_exec_order ensuring that all tensors
+ * with usage less than the max_exec_order are allocated.
+ */
tensor_manager->initializeTensors(
training, std::get<0>((*(cend() - 1))->getExecutionOrder()));
else
/** @todo update this to skip non-trainable layers */
+ /**
+ * get the order of execution/usage order for the backwarding of the first
+ * layer (as that will be the last layer to executed in the backwarding)
+ * and pass that as the max_exec_order ensuring that all tensors with
+ * usage less than the max_exec_order are allocated.
+ */
tensor_manager->initializeTensors(
training, std::get<1>((*(cbegin()))->getExecutionOrder()));
}
static void setLabels(const std::vector<Tensor> &data,
const std::vector<Var_Grad *> &label_list) {
- NNTR_THROW_IF(!data.empty() && data.size() != label_list.size(),
+ NNTR_THROW_IF(data.size() > 1 && data.size() != label_list.size(),
std::invalid_argument)
<< "label size does not match with the network requirements"
<< " label size: " << data.size()
<< " requirements size: " << label_list.size();
/// feed or clear label
- for (unsigned int idx = 0; idx < data.size(); idx++) {
+ for (unsigned int idx = 0; idx < label_list.size(); idx++) {
if (data.empty())
label_list[idx]->initializeGradient();
else if (data.size() == 1)
static void setLabels(sharedConstTensors &data,
const std::vector<Var_Grad *> &label_list) {
- NNTR_THROW_IF(data.size() > 1 && data.size() != label_list.size(),
- std::invalid_argument)
- << "label size does not match with the network requirements"
- << " label size: " << data.size()
- << " requirements size: " << label_list.size();
+ std::vector<Tensor> labels;
+ std::transform(data.begin(), data.end(), std::back_inserter(labels),
+ [](auto const &val) { return *val.get(); });
- /// feed or clear label
- for (unsigned int idx = 0; idx < label_list.size(); idx++) {
- if (data.empty())
- label_list[idx]->initializeGradient();
- else if (data.size() == 1)
- label_list[idx]->initializeGradient(*data[0]);
- else
- label_list[idx]->initializeGradient(*data[idx]);
- }
+ setLabels(labels, label_list);
}
static void setInputs(sharedConstTensors &data,
const std::vector<Var_Grad *> &input_list) {
- NNTR_THROW_IF(data.size() != input_list.size(), std::invalid_argument)
- << "input size does not match with the network requirements"
- << " input size: " << data.size()
- << " requirements size: " << input_list.size();
+ std::vector<Tensor> inputs;
+ std::transform(data.begin(), data.end(), std::back_inserter(inputs),
+ [](auto const &val) { return *val.get(); });
- /// feed or clear label
- for (unsigned int idx = 0; idx < data.size(); idx++) {
- input_list[idx]->initializeVariable(*data[idx]);
- }
+ setInputs(inputs, input_list);
}
/**
);
}
- inputs_v2.emplace_back(std::make_unique<Var_Grad>(var, grad));
+ /**
+ * TODO: This a temporary fix to handle external tensors due to rebase.
+ * This is properly fixed with #1544 using
+ * context.requestExternallyAllocatedTensor().
+ */
+ if (var && grad)
+ inputs_v2.emplace_back(std::make_unique<Var_Grad>(var, grad));
+ else
+ inputs_v2.emplace_back(std::make_unique<Var_Grad>(
+ dim, Tensor::Initializer::NONE, true, false,
+ node.getName() + std::string(":input") + std::to_string(idx)));
}
+ ret.reserve(inputs_dim.size());
std::transform(inputs_v2.begin() + current_size, inputs_v2.end(),
std::back_inserter(ret),
[](auto const &elem) { return elem.get(); });
void untrackLayerInOuts(const std::string &layer_name);
/**
- * @brief Initialize the inputs/outputs/derivatives/gradients for the layers
- * @param[in] training If true, initialize derivates/gradients, else, do not.
- * @note The memory allocation strategy varies based on the training. The
- * memory allocated for inference mode is not compatible with training, and
- * will require full allocation than reusing memory allocated with inference
- * mode.
+ * @brief Initialize the all the requested tensors
+ *
+ * @param[in] training If model will be training or not
+ * @param[in] max_exec_order The maximum order of execution to determine
+ * memory layout
+ *
+ * @note Any requested tensor which is not used inside the max_exec_order is
+ * not initialized and will not be allocated. The initialization uses a memory
+ * planner to plan the layout of all the tensors which are used at least once
+ * before the max_exec_order.
*/
void initializeTensors(bool training, unsigned int max_exec_order);