Skip to content

Commit

Permalink
[ Subgraph ] Feat/ add subgraph_realizer
Browse files Browse the repository at this point in the history
- This commit adds subgraph_realizer.
- The subgraph_realizer supports to create multiple subgraphs with
  is_shared_subgraph property.

**Self-evaluation:**

Build test: [X]Passed [ ]Failed [ ]Skipped
Run test: [X]Passed [ ]Failed [ ]Skipped

Signed-off-by: Eunju Yang <[email protected]>
  • Loading branch information
EunjuYang committed Dec 27, 2024
1 parent ba7e166 commit 9a3c547
Show file tree
Hide file tree
Showing 5 changed files with 208 additions and 4 deletions.
7 changes: 4 additions & 3 deletions api/ccapi/include/model.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ enum class ModelType {
enum class ReferenceLayersType {
BACKBONE, /** backbone */
RECURRENT, /** recurrent */
SUBGRAPH, /** subgraph */
};

/**
Expand Down Expand Up @@ -308,16 +309,16 @@ class Model {
* @param[in] init_seq_len initial sequence length
* @param[in] from current working step index
* @param[in] to next working step index
* @param[in] output_hidden_state return last hidden state if true else return all hidden state
* @param[in] output_hidden_state return last hidden state if true else return
* all hidden state
* @retval list of output as float *
* @note The output memory must not be freed by the caller
*/
virtual std::vector<float *>
incremental_inference(unsigned int batch, const std::vector<float *> &input,
const std::vector<float *> &label,
unsigned int init_seq_len, unsigned int from,
unsigned int to,
bool output_hidden_state = false) = 0;
unsigned int to, bool output_hidden_state = false) = 0;

/**
* @brief Summarize the model
Expand Down
1 change: 1 addition & 0 deletions nntrainer/compiler/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ compiler_sources = [
'multiout_realizer.cpp',
'bn_realizer.cpp',
'loss_realizer.cpp',
'subgraph_realizer.cpp',
]

compiler_headers = [
Expand Down
82 changes: 82 additions & 0 deletions nntrainer/compiler/subgraph_realizer.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
// SPDX-License-Identifier: Apache-2.0
/**
* Copyright (C) 2024 Eunju Yang <[email protected]>
*
* @file subgraph_realizer.cpp
* @date 27 Dec 2024
* @brief NNTrainer subgraph realizer
* @see https://github.com/nnstreamer/nntrainer
* @author Eunju Yang <[email protected]>
* @bug No known bugs except for NYI items
*/

#include <base_properties.h>
#include <common_properties.h>

#include <layer_node.h>
#include <nntrainer_error.h>
#include <node_exporter.h>
#include <remap_realizer.h>
#include <subgraph_realizer.h>

#include <tuple>

namespace nntrainer {

SubgraphRealizer::SubgraphRealizer(const std::string scope,
const std::vector<std::string> &properties,
const std::vector<Connection> &input_conns) :
realizer_props(props::SubgraphIdx(), props::IsSharedSubgraph()),
input_conns(input_conns),
scope_name(scope),
subgraph_idx(0),
is_shared_subgraph(true) {

auto left = loadProperties(properties, realizer_props);
NNTR_THROW_IF(!left.empty(), std::invalid_argument)
<< "There is unparsed properties";

subgraph_idx = std::get<props::SubgraphIdx>(realizer_props).get();
is_shared_subgraph = std::get<props::IsSharedSubgraph>(realizer_props).get();
scope_full_name = scope + "/" + std::to_string(subgraph_idx);
}

SubgraphRealizer::~SubgraphRealizer() {}

/**
* @note
* subgraphrealize conducts the following two steps:
* 1. rename all the nodes in the subgraph
* to be unique by adding scope as its prefix
* 2. set shared_from property of each node
* in the subgraph to point to the original node
*/
GraphRepresentation
SubgraphRealizer::realize(const GraphRepresentation &reference) {

auto subgraph_realizer = [this](const GraphRepresentation &reference_) {
RemapRealizer rename_mapper([this](std::string &name) {
for (auto &i : input_conns) {
if (i.getName() == name) {
return;
}
}
std::string scoped_name = scope_full_name + "/" + name;
subgraph_node_names[scoped_name] = name;
name = scoped_name;
});

auto nodes = rename_mapper.realize(reference_);

if (is_shared_subgraph) {
for (auto &node : nodes)
node->setProperty({"shared_from=" + scope_name + "/0/" +
subgraph_node_names[node->getName()]});
}
return nodes;
};

return subgraph_realizer(reference);
}

} // namespace nntrainer
103 changes: 103 additions & 0 deletions nntrainer/compiler/subgraph_realizer.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
// SPDX-License-Identifier: Apache-2.0
/**
* Copyright (C) 2024 Eunju Yang <[email protected]>
*
* @file subgraph_realizer.h
* @date 27 Dec 2024
* @brief NNTrainer subgraph realizer
* @see https://github.com/nnstreamer/nntrainer
* @author Eunju Yang <[email protected]>
* @bug No known bugs except for NYI items
*/

#ifndef __SUBGRAPH_REALIZER_H__
#define __SUBGRAPH_REALIZER_H__

#include <realizer.h>

#include <string>
#include <tuple>
#include <unordered_map>
#include <utility>

#include <connection.h>

namespace nntrainer {

namespace props {
/**
* @brief Property subgraph_idx
*/
class SubgraphIdx final : public nntrainer::Property<unsigned int> {
public:
SubgraphIdx(const unsigned int &val = 0) :
nntrainer::Property<unsigned int>(val) {
set(val);
}
static constexpr const char *key = "subgraph_idx";
using prop_tag = uint_prop_tag;
};

/**
* @brief Property is_shared_subgraph
*/
class IsSharedSubgraph final : public nntrainer::Property<bool> {
public:
IsSharedSubgraph(bool val = true) : nntrainer::Property<bool>(val) {}
static constexpr const char *key = "is_shared_subgraph";
using prop_tag = bool_prop_tag;
};
} // namespace props

/**
* @brief SubGraph Realizer which adding some properties for subgraph
* construction.
* @param properties
* subgraph_idx = <int>
* is_shared_subgraph = <bool>
*/
class SubgraphRealizer : public GraphRealizer {
public:
/**
* @brief Construct a new Subgraph Realizer object
* @note
* SubGraphRealizer do the two tasks:
* 1. Update name of the every node in subgraph with scope/
* 2. The scope name can be varied according to its subgraph index, i.e.,
* scope/idx/name
* 3. If is_shared_subgraph is true, then the scope name will be shared among
* subgraphs.
* @param properties
* subgraph_idx = <int>
* is_shared_subgraph = <bool>
* @param input_conns input conns from outer side
*/
SubgraphRealizer(const std::string scope,
const std::vector<std::string> &properties,
const std::vector<Connection> &input_conns);

/**
* @brief Destroy the subgraph realizer object
*/
~SubgraphRealizer();

/**
* @brief realized graph
*/
GraphRepresentation realize(const GraphRepresentation &reference) override;

private:
std::tuple<props::SubgraphIdx, props::IsSharedSubgraph>
realizer_props; /**< subgraph properties */
std::vector<Connection> input_conns;
std::string scope_name; /**< scope name */
std::string scope_full_name;
std::unordered_map<std::string, std::string>
subgraph_node_names; /**< subgraph_name, original name */
unsigned int subgraph_idx;
bool is_shared_subgraph;
};

} /* namespace nntrainer */

#endif /* __SUBGRAPH_REALIZER_H__ */
19 changes: 18 additions & 1 deletion nntrainer/models/neuralnet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
#include <recurrent_realizer.h>
#include <remap_realizer.h>
#include <slice_realizer.h>
#include <subgraph_realizer.h>
#include <util_func.h>

#ifdef ENABLE_TFLITE_INTERPRETER
Expand Down Expand Up @@ -1459,7 +1460,23 @@ void NeuralNetwork::addWithReferenceLayers(
new RecurrentRealizer(type_properties, input_conns, end_conns));
}

if (!scope.empty()) {
/**
* @brief add SubGraphRealizer when type is SUBGRAPH
* subgraphrealizer updates the name of the node.
* Thus, remaprealizer should not be applied again.
* @note scope name should be set to apply subgraph realizer.
*/
if (type == ml::train::ReferenceLayersType::SUBGRAPH) {

// Applied only when `scope` is specified.
if (scope.empty()) {
ml_logd(
"The subgraph's scope name is not set. Subgraph setting is skipped.");
return;
}
realizers.emplace_back(
new SubgraphRealizer(scope, type_properties, input_conns));
} else if (!scope.empty()) {
realizers.emplace_back(
new RemapRealizer([&scope, &input_conns](std::string &name) {
for (auto &i : input_conns) {
Expand Down

0 comments on commit 9a3c547

Please sign in to comment.