$(NNTRAINER_ROOT)/nntrainer/dataset \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/utils \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/dataset \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/tensor \
$(NNTRAINER_ROOT)/nntrainer \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/utils \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/dataset \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/tensor \
$(NNTRAINER_ROOT)/nntrainer/dataset \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/tensor \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/tensor \
$(NNTRAINER_ROOT)/nntrainer/utils \
NNTRAINER_INCLUDES := $(NNTRAINER_ROOT)/nntrainer \
$(NNTRAINER_ROOT)/nntrainer/dataset \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/tensor \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/graph \
$(NNTRAINER_ROOT)/nntrainer/layers \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/optimizers \
$(NNTRAINER_ROOT)/nntrainer/tensor \
$(NNTRAINER_ROOT)/nntrainer/utils \
# node exporter and its dependencies
/usr/include/nntrainer/nntrainer_error.h
+/usr/include/nntrainer/connection.h
/usr/include/nntrainer/common_properties.h
/usr/include/nntrainer/base_properties.h
/usr/include/nntrainer/node_exporter.h
$(NNTRAINER_ROOT)/nntrainer/layers/reduce_mean_layer.cpp \
$(NNTRAINER_ROOT)/nntrainer/graph/network_graph.cpp \
$(NNTRAINER_ROOT)/nntrainer/graph/graph_core.cpp \
+ $(NNTRAINER_ROOT)/nntrainer/graph/connection.cpp \
$(NNTRAINER_ROOT)/nntrainer/optimizers/optimizer_context.cpp \
$(NNTRAINER_ROOT)/nntrainer/optimizers/optimizer_devel.cpp \
$(NNTRAINER_ROOT)/nntrainer/optimizers/optimizer_impl.cpp \
CCAPI_NNTRAINER_INCLUDES := $(NNTRAINER_ROOT)/nntrainer \
$(NNTRAINER_ROOT)/nntrainer/dataset \
+ $(NNTRAINER_ROOT)/nntrainer/compiler \
$(NNTRAINER_ROOT)/nntrainer/layers \
$(NNTRAINER_ROOT)/nntrainer/models \
$(NNTRAINER_ROOT)/nntrainer/tensor \
for (unsigned int i = 0, num_nodes = node->getNumInputConnections();
i < num_nodes; ++i) {
- props::InputConnection c(props::Connection(
- node->getInputConnectionName(i), node->getInputConnectionIndex(i)));
+ Connection c(node->getInputConnectionName(i),
+ node->getInputConnectionIndex(i));
auto uniq_name = to_string(c);
[[maybe_unused]] auto [iter, result] = freq_map.try_emplace(uniq_name, 0);
iter->second++;
multiout_nodes;
for (auto &[con_name, freq] : freq_map) {
- props::InputConnection con;
- from_string(con_name, con);
-
/// @note freq < 1 should never happen as the map entry is not created.
/// but if it happens multiout realizer is not interested in checking if it
/// is a dangled or actually an output. So there is no assurance done at
/// this point. Some other class must check if the given graph is formed in
/// a correct way.
+ Connection con(con_name);
if (freq <= 1) {
continue;
}
- std::string id = con.get().getName();
- auto idx = con.get().getIndex();
+ std::string id = con.getName();
+ auto idx = con.getIndex();
std::stringstream ss;
/// {connection_name}/generated_out_{index}
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file connection.cpp
+ * @date 23 Nov 2021
+ * @see https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ * @brief Connection class and related utility functions
+ */
+#include <connection.h>
+
+#include <common_properties.h>
+
+namespace {}
+
+namespace nntrainer {
+Connection::Connection(const std::string &layer_name, unsigned int idx) :
+ index(idx),
+ name(props::Name(layer_name).get()) {}
+
+Connection::Connection(const std::string &string_representation) {
+ auto &sr = string_representation;
+ auto pos = sr.find_first_of('(');
+ auto idx = 0u;
+ auto name_part = sr.substr(0, pos);
+
+ if (pos != std::string::npos) {
+ NNTR_THROW_IF(sr.back() != ')', std::invalid_argument)
+ << "failed to parse connection invalid format: " << sr;
+
+ auto idx_part = sr.substr(pos + 1, sr.length() - 1);
+ idx = str_converter<uint_prop_tag, unsigned>::from_string(idx_part);
+ }
+
+ index = idx;
+ name = props::Name(name_part);
+}
+
+Connection::Connection(const Connection &rhs) = default;
+Connection &Connection::operator=(const Connection &rhs) = default;
+Connection::Connection(Connection &&rhs) noexcept = default;
+Connection &Connection::operator=(Connection &&rhs) noexcept = default;
+
+bool Connection::operator==(const Connection &rhs) const noexcept {
+ return index == rhs.index and name == rhs.name;
+}
+
+std::string Connection::toString() const {
+ std::stringstream ss;
+ ss << getName() << '(' << getIndex() << ')';
+ return ss.str();
+}
+
+}; // namespace nntrainer
--- /dev/null
+// SPDX-License-Identifier: Apache-2.0
+/**
+ * Copyright (C) 2021 Jihoon Lee <jhoon.it.lee@samsung.com>
+ *
+ * @file connection.h
+ * @date 23 Nov 2020
+ * @see https://github.com/nnstreamer/nntrainer
+ * @author Jihoon Lee <jhoon.it.lee@samsung.com>
+ * @bug No known bugs except for NYI items
+ * @brief Connection class and related utility functions
+ */
+#ifndef __CONNECTION_H__
+#define __CONNECTION_H__
+
+#include <string>
+
+namespace nntrainer {
+/**
+ * @brief RAII class to define a connection
+ *
+ */
+class Connection {
+public:
+ /**
+ * @brief Construct a new Connection object
+ *
+ * @param layer_name layer identifier
+ */
+ Connection(const std::string &layer_name, unsigned int idx);
+
+ /**
+ * @brief Construct a new Connection object from string representation
+ * string representation is format of {layer_name, idx};
+ *
+ * @param string_representation string format of {layer_name}({idx})
+ */
+ explicit Connection(const std::string &string_representation);
+
+ /**
+ * @brief Construct a new Connection object
+ *
+ * @param rhs rhs to copy
+ */
+ Connection(const Connection &rhs);
+
+ /**
+ * @brief Copy assignment operator
+ *
+ * @param rhs rhs to copy
+ * @return Connection&
+ */
+ Connection &operator=(const Connection &rhs);
+
+ /**
+ * @brief Move Construct Connection object
+ *
+ * @param rhs rhs to move
+ */
+ Connection(Connection &&rhs) noexcept;
+
+ /**
+ * @brief Move assign a connection operator
+ *
+ * @param rhs rhs to move
+ * @return Connection&
+ */
+ Connection &operator=(Connection &&rhs) noexcept;
+
+ /**
+ * @brief string representation of connection
+ *
+ * @return std::string string format of {name}({idx})
+ */
+ std::string toString() const;
+
+ /**
+ * @brief Get the index
+ *
+ * @return unsigned index
+ */
+ const unsigned getIndex() const { return index; }
+
+ /**
+ * @brief Get the index
+ *
+ * @return unsigned index
+ */
+ unsigned &getIndex() { return index; }
+
+ /**
+ * @brief Get the Layer name object
+ *
+ * @return const Name& name of layer
+ */
+ const std::string &getName() const { return name; }
+
+ /**
+ * @brief Get the Layer name object
+ *
+ * @return Name& name of layer
+ */
+ std::string &getName() { return name; }
+
+ /**
+ *
+ * @brief operator==
+ *
+ * @param rhs right side to compare
+ * @return true if equal
+ * @return false if not equal
+ */
+ bool operator==(const Connection &rhs) const noexcept;
+
+private:
+ unsigned index;
+ std::string name;
+};
+
+} // namespace nntrainer
+
+#endif // __CONNECTION_H__
\ No newline at end of file
graph_sources = [
'network_graph.cpp',
- 'graph_core.cpp'
+ 'graph_core.cpp',
+ 'connection.cpp'
]
-graph_headers = []
+graph_headers = ['connection.h']
foreach s : graph_sources
nntrainer_sources += meson.current_source_dir() / s
InputConnection::InputConnection(const Connection &value) :
nntrainer::Property<Connection>(value) {} /**< default value if any */
-Connection::Connection(const std::string &layer_name, unsigned int idx) :
- index(idx),
- name(layer_name) {}
-
-Connection::Connection(const Connection &rhs) = default;
-Connection &Connection::operator=(const Connection &rhs) = default;
-Connection::Connection(Connection &&rhs) noexcept = default;
-Connection &Connection::operator=(Connection &&rhs) noexcept = default;
-
-bool Connection::operator==(const Connection &rhs) const noexcept {
- return index == rhs.index and name == rhs.name;
-};
-
Epsilon::Epsilon(float value) { set(value); }
bool Epsilon::isValid(const float &value) const { return value > 0.0f; }
} // namespace props
template <>
-std::string
-str_converter<props::connection_prop_tag, props::Connection>::to_string(
- const props::Connection &value) {
- std::stringstream ss;
- ss << value.getName().get() << '(' << value.getIndex() << ')';
- return ss.str();
+std::string str_converter<props::connection_prop_tag, Connection>::to_string(
+ const Connection &value) {
+ return value.toString();
}
template <>
-props::Connection
-str_converter<props::connection_prop_tag, props::Connection>::from_string(
+Connection str_converter<props::connection_prop_tag, Connection>::from_string(
const std::string &value) {
- auto pos = value.find_first_of('(');
- auto idx = 0u;
- auto name_part = value.substr(0, pos);
-
- if (pos != std::string::npos) {
- NNTR_THROW_IF(value.back() != ')', std::invalid_argument)
- << "failed to parse connection invalid format: " << value;
-
- auto idx_part = value.substr(pos + 1, value.length() - 1);
- idx = str_converter<uint_prop_tag, unsigned>::from_string(idx_part);
- }
-
- return props::Connection(name_part, idx);
+ return Connection(value);
}
} // namespace nntrainer
#include <string>
#include <base_properties.h>
+#include <connection.h>
#include <tensor.h>
#include <tensor_wrap_specs.h>
};
/**
- * @brief RAII class to define the connection
- *
- */
-class Connection {
-public:
- /**
- * @brief Construct a new Connection object
- *
- * @param layer_name layer identifier
- */
- Connection(const std::string &layer_name, unsigned int idx);
-
- /**
- * @brief Construct a new Connection object
- *
- * @param rhs rhs to copy
- */
- Connection(const Connection &rhs);
-
- /**
- * @brief Copy assignment operator
- *
- * @param rhs rhs to copy
- * @return Connection&
- */
- Connection &operator=(const Connection &rhs);
-
- /**
- * @brief Move Construct Connection object
- *
- * @param rhs rhs to move
- */
- Connection(Connection &&rhs) noexcept;
-
- /**
- * @brief Move assign a connection operator
- *
- * @param rhs rhs to move
- * @return Connection&
- */
- Connection &operator=(Connection &&rhs) noexcept;
-
- /**
- * @brief Get the index
- *
- * @return unsigned index
- */
- const unsigned getIndex() const { return index; }
-
- /**
- * @brief Get the index
- *
- * @return unsigned index
- */
- unsigned &getIndex() { return index; }
-
- /**
- * @brief Get the Layer name object
- *
- * @return const Name& name of layer
- */
- const Name &getName() const { return name; }
-
- /**
- * @brief Get the Layer name object
- *
- * @return Name& name of layer
- */
- Name &getName() { return name; }
-
- /**
- *
- * @brief operator==
- *
- * @param rhs right side to compare
- * @return true if equal
- * @return false if not equal
- */
- bool operator==(const Connection &rhs) const noexcept;
-
-private:
- unsigned index;
- Name name;
-};
-
-/**
* @brief Connection prop tag type
*
*/
#include <util_func.h>
namespace nntrainer {
+
+#ifdef PROFILE
static constexpr const char *FORWARD_SUFFIX = ":forward";
static constexpr const char *CALC_DERIV_SUFFIX = ":calcDeriv";
static constexpr const char *CALC_GRAD_SUFFIX = ":calcGrad";
+#endif
namespace props {
inplace(InPlace::NONE),
needs_calc_derivative(false),
needs_calc_gradient(false),
- output_layers(new std::vector<props::Connection>()),
+ output_layers(),
run_context(nullptr),
layer_node_props(
new PropsType(props::Name(), props::Distribute(), props::Trainable(), {},
};
print_vector(input_layers, " input_layers");
- /// @todo enable this
- // print_vector(l.output_layers, "output_layers");
+ // print_vector(l.output_layers, "output_layers");
return out;
}
}
unsigned int LayerNode::getNumOutputConnections() const {
- return output_layers->size();
+ return output_layers.size();
}
const std::vector<std::string> LayerNode::getInputLayers() const {
names.reserve(input_layers.size());
std::transform(input_layers.begin(), input_layers.end(),
std::back_inserter(names),
- [](const props::Connection &con) { return con.getName(); });
+ [](const Connection &con) { return con.getName(); });
return names;
}
const std::vector<std::string> LayerNode::getOutputLayers() const {
std::vector<std::string> names;
- names.reserve(output_layers->size());
- std::transform(output_layers->begin(), output_layers->end(),
- std::back_inserter(names),
- [](const props::Connection &con) { return con.getName(); });
+ names.reserve(output_layers.size());
+
+ for (auto &output_layer : output_layers) {
+ if (output_layer == nullptr) {
+ ml_logw("intermediate output is empty for layer: %s", getName().c_str());
+ continue;
+ }
+ names.push_back(output_layer->getName());
+ }
return names;
}
void LayerNode::addInputLayers(const std::string &in_layer) {
auto &input_layers =
std::get<std::vector<props::InputConnection>>(*layer_node_props);
- input_layers.emplace_back(props::Connection(in_layer, 0));
+ input_layers.emplace_back(Connection(in_layer, 0));
}
void LayerNode::addOutputLayers(const std::string &out_layer) {
- output_layers->emplace_back(out_layer, 0);
+ output_layers.emplace_back(new Connection(out_layer, 0));
}
void LayerNode::setInputLayers(const std::vector<std::string> &layers) {
input_layers.reserve(layers.size());
std::transform(layers.begin(), layers.end(), std::back_inserter(input_layers),
[](const std::string &id) {
- return props::Connection{id, 0};
+ return Connection{id, 0};
});
}
void LayerNode::setOutputLayers(const std::vector<std::string> &layers) {
- output_layers->clear();
- output_layers->reserve(layers.size());
- std::transform(layers.begin(), layers.end(),
- std::back_inserter(*output_layers), [](const std::string &id) {
- return props::Connection{id, 0};
- });
+ output_layers.clear();
+ output_layers.reserve(layers.size());
+ std::transform(
+ layers.begin(), layers.end(), std::back_inserter(output_layers),
+ [](const std::string &id) { return std::make_unique<Connection>(id); });
}
bool LayerNode::hasInputShapeProperty() const {
layer_node_props_realization = std::make_unique<RealizationPropsType>(
props::Flatten(), props::Activation());
- auto num_outputs = output_layers->size();
- if (output_layers->empty()) {
+ auto num_outputs = output_layers.size();
+ if (output_layers.empty()) {
num_outputs = 1;
}
remap_fn(name, idx);
}
- for (auto &output_layer : *output_layers) {
- auto &name = output_layer.getName();
- auto &idx = output_layer.getIndex();
+ for (auto &output_layer : output_layers) {
+ if (output_layer == nullptr) {
+ continue;
+ }
+
+ auto &name = output_layer->getName();
+ auto &idx = output_layer->getIndex();
remap_fn(name, idx);
}
}
namespace nntrainer {
class Layer;
-
+class Connection;
class Exporter;
enum class ExportMethods;
class InputShape;
class Activation;
class SharedFrom;
-class Connection;
class InputConnection;
class ClipGradByGlobalNorm;
} // namespace props
void setInputConnectionName(unsigned nth, const std::string &name);
/**
+ * @brief Set the Output Connection
+ * @note Each output must be identified only ONCE.
+ * @note when nth comes, getNumOutput() expends to nth + 1 as resize occurs.
+ * Please also notice none identified intermediate output (or mismatch between
+ * actual number of out tensors and output) is allowed but will produce
+ * warning, this implies that the output is not used else where.
+ * @throw std::invalid_argument when trying to identify output
+ * more then once
+ *
+ * @param nth nth output
+ * @param name name of the output bound connection
+ * @param index index of the output bound connection
+ */
+ void setOutputConnection(unsigned nth, const std::string &name,
+ unsigned index);
+
+ /**
* @brief Get the input connections for this node
*
* @return list of name of the nodes which form input connections
calcDerivative */
bool needs_calc_gradient; /**< cache if this layer needs to do calcGradient */
- std::unique_ptr<std::vector<props::Connection>>
+ std::vector<std::unique_ptr<Connection>>
output_layers; /**< output layer names */
std::unique_ptr<RunLayerContext>
%files devel
# node exporter and its dependencies
%{_includedir}/nntrainer/nntrainer_error.h
+%{_includedir}/nntrainer/connection.h
%{_includedir}/nntrainer/common_properties.h
%{_includedir}/nntrainer/base_properties.h
%{_includedir}/nntrainer/node_exporter.h
#include <gtest/gtest.h>
#include <common_properties.h>
+#include <connection.h>
#include <tensor_dim.h>
#include <array>
TEST(InputConnection, setPropertyValid_p) {
using namespace nntrainer::props;
{
- InputConnection expected(Connection("a", 0));
+ InputConnection expected(nntrainer::Connection("a", 0));
InputConnection actual;
nntrainer::from_string("A", actual);
}
{
- InputConnection expected(Connection("a", 2));
+ InputConnection expected(nntrainer::Connection("a", 2));
InputConnection actual;
nntrainer::from_string("a(2)", actual);