* @author Jihoon Lee <jhoon.it.lee@samsung.com>
* @bug No known bugs except for NYI items
*/
+#include <connection.h>
#include <input_realizer.h>
#include <layer_node.h>
#include <nntrainer_error.h>
#include <nntrainer_log.h>
#include <algorithm>
+#include <stdexcept>
#include <unordered_map>
namespace nntrainer {
-InputRealizer::InputRealizer(const std::vector<std::string> &start_layers,
- const std::vector<std::string> &input_layers) :
- start_layers(start_layers),
- input_layers(input_layers) {}
+InputRealizer::InputRealizer(const std::vector<Connection> &start_conns,
+ const std::vector<Connection> &input_conns) :
+ start_conns(start_conns),
+ input_conns(input_conns) {
+ NNTR_THROW_IF(start_conns.size() != input_conns.size(), std::invalid_argument)
+ << "start connection size is not same input_conns size";
+}
InputRealizer::~InputRealizer() {}
std::inserter(existing_nodes, existing_nodes.end()),
[](auto &node) { return std::pair(node->getName(), node.get()); });
- /// if start_layer is empty, it's not a hard error but likely to be wrong if
- /// there is two inputs
- ml_logw("trying to realize without start_layer specified, if there is more "
- "than two inputs, sort order make setting graph not determinated");
-
- auto get_next_input_ref = [input_ref_iter = input_layers.begin(),
- this]() mutable {
- NNTR_THROW_IF(input_ref_iter == input_layers.end(), std::invalid_argument)
- << "there is no more input layers";
- return input_ref_iter++;
- };
-
- for (auto &start_name : start_layers) {
- auto node = existing_nodes.at(start_name);
-
- auto num_input = node->getNumInputConnections();
+ for (unsigned i = 0u, sz = start_conns.size(); i < sz; ++i) {
+ const auto &sc = start_conns[i];
+ const auto &ic = input_conns[i];
+ auto node = existing_nodes.at(sc.getName());
- if (num_input == 0) {
- // case1. There is no input layers presented -> push single input
- node->setProperty({"input_layers=" + *get_next_input_ref()});
+ auto num_connection = node->getNumInputConnections();
+ if (num_connection == 0) {
+ NNTR_THROW_IF(sc.getIndex() != 0, std::invalid_argument)
+ << "start connection: " << sc.toString()
+ << " not defined and num connection of that node is empty, although "
+ "start connection of index zero is allowed";
+ node->setProperty({"input_layers=" + ic.toString()});
} else {
- /// case2. There is multiple input layers -> substitute orphaned node
- /// Orphaned node probably is being created from slicing or it is also a
- /// possible scenario that the graph in the first place is designed to
- /// have a orphaned node. In the latter case, the graph was non-compilable
- /// from the first time.
- for (auto i = 0u; i < num_input; ++i) {
- auto name = node->getInputConnectionName(i);
- if (!existing_nodes.count(name)) {
- node->setInputConnectionName(i, *get_next_input_ref());
- }
- }
+ NNTR_THROW_IF(sc.getIndex() >= num_connection, std::invalid_argument)
+ << "start connection: " << sc.toString()
+ << " not defined, num connection: " << num_connection;
+ node->setInputConnectionName(sc.getIndex(), ic.getName());
+ node->setInputConnectionIndex(sc.getIndex(), ic.getIndex());
}
}
#include <string>
#include <vector>
+#include <connection.h>
#include <realizer.h>
namespace nntrainer {
/**
* @brief Graph realizer class which remaps input from start -> input layers
- * @note This class find orphaned identifer in order from start_layers and
- * change the identifier to input_layers. If start_layers does not have any
- * input layers, push single input identifier, if start_layers have
- * input_layers, check if the given input layer exists starting from the first
- * input layers, if not exist, change to the given input layer in order. In case
- * of start_layer contains n input_layers to be replaced.
+ * @note This class overwrites input conns to the location of start conns.
+ * This requires each start location have the slot for input connection.
+ * @note When number of input connection == 0 for a start connection of index
+ * zero, this pushes input connection to the slot
*
*/
class InputRealizer final : public GraphRealizer {
/**
* @brief Construct a new Input Realizer object
*
- * @param start_layers start layers
- * @param input_layers input layers
+ * @param start_conns start layers
+ * @param input_conns input layers
*/
- InputRealizer(const std::vector<std::string> &start_layers,
- const std::vector<std::string> &input_layers);
+ InputRealizer(const std::vector<Connection> &start_conns,
+ const std::vector<Connection> &input_conns);
/**
* @brief Destroy the Graph Realizer object
GraphRepresentation realize(const GraphRepresentation &reference) override;
private:
- std::vector<std::string> start_layers;
- std::vector<std::string> input_layers;
+ std::vector<Connection> start_conns;
+ std::vector<Connection> input_conns;
};
} // namespace nntrainer
auto start_conns =
std::vector<Connection>(start_layers.begin(), start_layers.end());
-
+ auto input_conns =
+ std::vector<Connection>(input_layers.begin(), input_layers.end());
auto end_conns =
std::vector<Connection>(end_layers.begin(), end_layers.end());
realizers.emplace_back(new SliceRealizer(start_conns, end_conns));
if (!input_layers_.empty()) {
- realizers.emplace_back(new InputRealizer(start_layers_, input_layers_));
+ realizers.emplace_back(new InputRealizer(start_conns, input_conns));
}
if (type == ml::train::ReferenceLayersType::RECURRENT) {
realizeAndEqual(r, before, after);
}
-TEST(InputRealizer, remap_p) {
+TEST(InputRealizer, input_p) {
std::vector<LayerRepresentation> before = {
- {"fully_connected", {"name=fc1"}}, // no input_layers specified
- {"fully_connected",
- {"name=fc2", "input_layers=none1,fc1"}}, // single orphaned node
- {"fully_connected",
- {"name=fc3", "input_layers=none2,fc2,none3"}}, // multi orphaned node
+ {"fully_connected", {"name=fc1"}},
+ {"fully_connected", {"name=fc2", "input_layers=none1,fc1"}},
+ {"fully_connected", {"name=fc3", "input_layers=none2,fc2,none3"}},
};
std::vector<LayerRepresentation> after = {
- {"fully_connected",
- {"name=fc1", "input_layers=in1"}}, // no input_layers specified
- {"fully_connected",
- {"name=fc2", "input_layers=in2,fc1"}}, // single orphaned node
- {"fully_connected",
- {"name=fc3", "input_layers=in3,fc2,in4"}}, // multi orphaned node
+ {"fully_connected", {"name=fc1", "input_layers=in1(0)"}},
+ {"fully_connected", {"name=fc2", "input_layers=in2,fc1"}},
+ {"fully_connected", {"name=fc3", "input_layers=in3(3),fc2,in4"}},
};
- InputRealizer r({"fc1", "fc2", "fc3"}, {"in1", "in2", "in3", "in4"});
+ using C = Connection;
+ InputRealizer r(
+ {
+ C("fc1"),
+ C("fc2(0)"),
+ C("fc3(0)"),
+ C("fc3(2)"),
+ },
+ {
+ C("in1(0)"),
+ C("in2"),
+ C("in3(3)"),
+ C("in4"),
+ });
realizeAndEqual(r, before, after);
}
+TEST(InputRealizer, input_start_num_not_match_n) {
+ using C = Connection;
+ EXPECT_ANY_THROW(InputRealizer r(
+ {
+ C("fc1"),
+ },
+ {
+ C("in1(0)"),
+ C("in2"),
+ C("in3(3)"),
+ C("in4"),
+ }));
+}
+
+TEST(InputRealizer, start_empty_conn_not_defined_n) {
+ std::vector<LayerRepresentation> before = {
+ {"fully_connected", {"name=fc1"}},
+ {"fully_connected", {"name=fc2", "input_layers=none1,fc1"}},
+ {"fully_connected", {"name=fc3", "input_layers=none2,fc2,none3"}},
+ };
+
+ std::vector<LayerRepresentation> after = {
+ {"fully_connected", {"name=fc1", "input_layers=in1(0)"}},
+ {"fully_connected", {"name=fc2", "input_layers=in2,fc1"}},
+ {"fully_connected", {"name=fc3", "input_layers=in3(3),fc2,in4"}},
+ };
+
+ using C = Connection;
+ InputRealizer r(
+ {
+ C("fc1(2)"), /**< connection not defined, although fc1(0) is allowed */
+ C("fc2(0)"),
+ C("fc3(0)"),
+ C("fc3(2)"),
+ },
+ {
+ C("in1(0)"),
+ C("in2"),
+ C("in3(3)"),
+ C("in4"),
+ });
+ EXPECT_ANY_THROW(realizeAndEqual(r, before, after));
+}
+
+TEST(InputRealizer, intermediate_conn_not_defined_n) {
+ std::vector<LayerRepresentation> before = {
+ {"fully_connected", {"name=fc1"}},
+ {"fully_connected", {"name=fc2", "input_layers=none1,fc1"}},
+ {"fully_connected", {"name=fc3", "input_layers=none2,fc2,none3"}},
+ };
+
+ std::vector<LayerRepresentation> after = {
+ {"fully_connected", {"name=fc1", "input_layers=in1(0)"}},
+ {"fully_connected", {"name=fc2", "input_layers=in2,fc1"}},
+ {"fully_connected", {"name=fc3", "input_layers=in3(3),fc2,in4"}},
+ };
+
+ using C = Connection;
+ InputRealizer r(
+ {
+ C("fc1"),
+ C("fc2(4)"), /**< connection not defined */
+ C("fc3(0)"),
+ C("fc3(2)"),
+ },
+ {
+ C("in1(0)"),
+ C("in2"),
+ C("in3(3)"),
+ C("in4"),
+ });
+ EXPECT_ANY_THROW(realizeAndEqual(r, before, after));
+}
+
TEST(PreviousInputRealizer, previous_p) {
{ /// realization without identifying custom input
std::vector<LayerRepresentation> before = {