[layer] Move flatten property to layerNode
authorParichay Kapoor <pk.kapoor@samsung.com>
Tue, 18 May 2021 05:44:09 +0000 (14:44 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Tue, 8 Jun 2021 05:39:22 +0000 (14:39 +0900)
Move flatten property out to layerNode
also prepare for moving other properties out to layerNode

**Self evaluation:**
1. Build test: [x]Passed [ ]Failed [ ]Skipped
2. Run test: [x]Passed [ ]Failed [ ]Skipped

Signed-off-by: Parichay Kapoor <pk.kapoor@samsung.com>
api/ccapi/src/factory.cpp
nntrainer/compiler/ini_interpreter.cpp
nntrainer/graph/network_graph.cpp
nntrainer/layers/layer.cpp
nntrainer/layers/layer_internal.h
nntrainer/layers/layer_node.cpp
nntrainer/layers/layer_node.h
test/unittest/unittest_nntrainer_appcontext.cpp

index accfd982bc0a0b5d41204615d9cae80643eb0347..58b4ac62b08440dd082a207855c420841c6ad2fb 100644 (file)
@@ -40,11 +40,8 @@ std::unique_ptr<Layer> createLayer(const LayerType &type,
  */
 std::unique_ptr<Layer> createLayer(const std::string &type,
                                    const std::vector<std::string> &properties) {
-  auto &ac = nntrainer::AppContext::Global();
-  std::shared_ptr<nntrainer::Layer> nntr_layer =
-    ac.createObject<nntrainer::Layer>(type, properties);
   std::unique_ptr<nntrainer::LayerNode> layer =
-    std::make_unique<nntrainer::LayerNode>(nntr_layer);
+    nntrainer::createLayerNode(type, properties);
 
   return layer;
 }
@@ -63,12 +60,8 @@ createOptimizer(const OptimizerType &type,
 static std::unique_ptr<Layer>
 createLoss(nntrainer::LossType type,
            const std::vector<std::string> &properties) {
-  std::shared_ptr<nntrainer::Layer> nntr_layer = nntrainer::createLoss(type);
   std::unique_ptr<nntrainer::LayerNode> layer =
-    std::make_unique<nntrainer::LayerNode>(nntr_layer);
-
-  if (layer->setProperty(properties) != ML_ERROR_NONE)
-    throw std::invalid_argument("Set properties failed for layer");
+    nntrainer::createLayerNode(nntrainer::createLoss(type), properties);
 
   return layer;
 }
index 36ad2a4f1f26632029f14c4189c9addabbab450c..a62a35af9e277c5c7326ce63d8fef71904efca0d 100644 (file)
@@ -19,6 +19,7 @@
 #include <ini_wrapper.h>
 #include <layer.h>
 #include <layer_factory.h>
+#include <layer_node.h>
 #include <nntrainer_error.h>
 #include <nntrainer_log.h>
 #include <node_exporter.h>
@@ -132,10 +133,7 @@ section2layer<PlainLayer>(dictionary *ini, const std::string &sec_name,
     << FUNC_TAG << "section type is invalid for section name: " << sec_name;
 
   auto properties = section2properties(ini, sec_name);
-  std::shared_ptr<Layer> nntr_layer =
-    ac.createObject<Layer>(layer_type, properties);
-
-  auto layer = std::make_unique<LayerNode>(nntr_layer);
+  std::shared_ptr<Layer> nntr_layer = ac.createObject<Layer>(layer_type);
 
   if (nntr_layer->getDistribute()) {
     ml_logd("This %s layer is going to distributed", sec_name.c_str());
@@ -144,9 +142,11 @@ section2layer<PlainLayer>(dictionary *ini, const std::string &sec_name,
     std::dynamic_pointer_cast<TimeDistLayer>(dist_layer)
       ->setDistLayer(nntr_layer);
 
-    layer = std::make_unique<LayerNode>(dist_layer);
+    nntr_layer = dist_layer;
   }
 
+  auto layer = createLayerNode(nntr_layer, properties);
+
   return layer;
 }
 
@@ -175,9 +175,8 @@ section2layer<BackboneLayer>(dictionary *ini, const std::string &sec_name,
 
   auto properties = section2properties(ini, sec_name);
   properties.push_back("modelfile=" + backbone_file);
-  std::shared_ptr<Layer> nntr_layer = ac.createObject<Layer>(type, properties);
 
-  auto layer = std::make_unique<LayerNode>(nntr_layer);
+  auto layer = createLayerNode(type, properties);
 
   return layer;
 }
index 3c3d456de8a6928fb125cd79871728c82f9b0a0b..6fa9fe1919abf96e81b68002702f64e86df9beff 100644 (file)
@@ -460,7 +460,8 @@ int NetworkGraph::realizeGraph() {
   std::vector<std::shared_ptr<GraphNode>> node_list = graph.getNodes();
 
   for (unsigned int i = 0; i < num_nodes; ++i) {
-    Layer &l = *LNODE(node_list[i])->getObject();
+    auto const &lnode = LNODE(node_list[i]);
+    Layer &l = *lnode->getObject();
     ml_logd("layer name: %s", l.getName().c_str());
 
     /** If a layer does not has input nodes, then it must have input dimension
@@ -491,7 +492,7 @@ int NetworkGraph::realizeGraph() {
     }
 
     // Flatten in TimeDistLayer is not supported.
-    if (l.getFlatten() && l.getType() != TimeDistLayer::type) {
+    if (lnode->getFlatten() && l.getType() != TimeDistLayer::type) {
       status = realizeFlattenType(l);
       NN_RETURN_STATUS();
     }
index 9777dbdd9967fa8f53131488fbf469871480dd6d..ef508cf8cb422014b0270fe99f83dd0937d77cd4 100644 (file)
@@ -85,7 +85,6 @@ void Layer::copy(std::shared_ptr<Layer> l) {
   this->weight_regularizer = l->weight_regularizer;
   this->weight_regularizer_constant = l->weight_regularizer_constant;
   this->weight_initializer = l->weight_initializer;
-  this->flatten = l->flatten;
   this->trainable = l->trainable;
   this->distribute = l->distribute;
 }
@@ -228,12 +227,6 @@ void Layer::setProperty(const PropertyType type, const std::string &value) {
       setActivation((ActivationType)parseType(value, TOKEN_ACTI));
     }
     break;
-  case PropertyType::flatten:
-    if (!value.empty()) {
-      status = setBoolean(flatten, value);
-      throw_status(status);
-    }
-    break;
   case PropertyType::weight_regularizer:
     if (!value.empty()) {
       weight_regularizer =
@@ -338,7 +331,6 @@ void Layer::printPropertiesMeta(std::ostream &out) {
   printIfValid(
     out, PropertyType::activation,
     static_cast<std::underlying_type<ActivationType>::type>(activation_type));
-  printIfValid(out, PropertyType::flatten, flatten);
 }
 
 void Layer::printProperties(std::ostream &out) {
index 4070e9f41af27e3682e09ea5cdca94eda081a7a4..9133851083313ab716d0251b6b5b68236154cff2 100644 (file)
@@ -72,7 +72,6 @@ public:
     weight_regularizer_constant(weight_regularizer_constant_),
     weight_initializer(weight_initializer_),
     bias_initializer(bias_initializer_),
-    flatten(flatten_),
     trainable(trainable_),
     distribute(distribute_) {
     setNumInputs(1);
@@ -371,12 +370,6 @@ public:
    */
   virtual std::vector<Weight> getWeights() { return weights; }
 
-  /**
-   * @brief     get if the output of this layer must be flatten
-   * @retval    flatten value
-   */
-  virtual bool getFlatten() { return flatten; }
-
   /**
    * @brief     Set name of the layer
    */
@@ -668,17 +661,12 @@ protected:
    */
   WeightInitializer bias_initializer;
 
-  // TODO: remove this from here
-  /**
-   * @brief   Output of this layer should be flattened
-   */
-  bool flatten;
-
   /**
    * @brief     making this false will skip updating this layer variables
    */
   bool trainable;
 
+  // TODO: remove this from here
   /**
    * @brief     making this true will iterating along with time distribution
    */
@@ -745,12 +733,6 @@ private:
    */
   void setWeightInit(WeightInitializer wini) { weight_initializer = wini; }
 
-  /**
-   * @brief     get if the output of this layer must be flatten
-   * @retval    flatten value
-   */
-  void setFlatten(bool flatten) { this->flatten = flatten; }
-
   /**
    * @brief     Print layer related information. Do not override without clear
    * reason. It is recommended to override printShapeInfo, printPropertiesMeta,
index 1c820a1853901321ac698aa8884c07ebf237a86d..080dae668d163a4b91bcba5a3738d26522eeffda 100644 (file)
  * @brief  This is the layer node for network graph
  */
 
+#include <app_context.h>
 #include <layer_factory.h>
 #include <layer_node.h>
+#include <nntrainer_error.h>
+#include <nntrainer_log.h>
 
 namespace nntrainer {
 
 /**
  * @brief Layer factory creator with constructor
  */
-std::unique_ptr<LayerNode> createLayerNode(const std::string &type) {
-  return std::make_unique<LayerNode>(createLayer(type));
+std::unique_ptr<LayerNode>
+createLayerNode(const std::string &type,
+                const std::vector<std::string> &properties) {
+  auto &ac = nntrainer::AppContext::Global();
+  return createLayerNode(ac.createObject<nntrainer::Layer>(type), properties);
+}
+
+/**
+ * @brief Layer factory creator with constructor
+ */
+std::unique_ptr<LayerNode>
+createLayerNode(std::shared_ptr<nntrainer::Layer> layer,
+                const std::vector<std::string> &properties) {
+  auto lnode = std::make_unique<LayerNode>(layer);
+  if (lnode->setProperty(properties) != ML_ERROR_NONE)
+    throw std::invalid_argument("Error setting layer properties.");
+
+  return lnode;
+}
+
+int LayerNode::setProperty(std::vector<std::string> properties) {
+  int status = ML_ERROR_NONE;
+
+  try {
+    properties = loadProperties(properties, props);
+  } catch (std::invalid_argument &e) {
+    ml_loge("parsing property failed, reason: %s", e.what());
+    return ML_ERROR_INVALID_PARAMETER;
+  }
+
+  /// @todo: deprecate this in favor of loadProperties
+  std::vector<std::string> remainder;
+  for (unsigned int i = 0; i < properties.size(); ++i) {
+    std::string key;
+    std::string value;
+
+    status = getKeyValue(properties[i], key, value);
+    NN_RETURN_STATUS();
+
+    unsigned int type = parseLayerProperty(key);
+
+    if (value.empty()) {
+      ml_logd("value is empty for layer: %s, key: %s, value: %s",
+              getName().c_str(), key.c_str(), value.c_str());
+      return ML_ERROR_INVALID_PARAMETER;
+    }
+
+    try {
+      /// @note this calls derived setProperty if available
+      setProperty(static_cast<nntrainer::Layer::PropertyType>(type), value);
+    } catch (...) {
+      remainder.push_back(properties[i]);
+    }
+  }
+
+  status = layer->setProperty(remainder);
+  return status;
+}
+
+void LayerNode::setProperty(const nntrainer::Layer::PropertyType type,
+                            const std::string &value) {
+  int status = ML_ERROR_NONE;
+
+  switch (type) {
+  case nntrainer::Layer::PropertyType::flatten:
+    if (!value.empty()) {
+      status = setBoolean(flatten, value);
+      throw_status(status);
+    }
+    break;
+  default:
+    throw std::invalid_argument("Unknown property.");
+  }
 }
 
 std::ostream &operator<<(std::ostream &out, const LayerNode &l) {
index 6b854a17aeda6a0875f30e34538046edfbbeb22a..9bc7f9cd4405b08831321b56e38efd2a7d587634 100644 (file)
@@ -8,6 +8,8 @@
  * @author Parichay Kapoor <pk.kapoor@samsung.com>
  * @bug    No known bugs except for NYI items
  * @brief  This is the layer node for network graph
+ *
+ * @todo   Add printPreset support
  */
 
 #ifndef __LAYER_NODE_H__
@@ -71,9 +73,7 @@ public:
    * @details   This function accepts vector of properties in the format -
    *  { std::string property_name=property_val, ...}
    */
-  int setProperty(std::vector<std::string> properties) {
-    return layer->setProperty(properties);
-  }
+  int setProperty(std::vector<std::string> properties);
 
   /**
    * @brief     set name of layer
@@ -133,6 +133,16 @@ public:
    */
   bool getTrainable() noexcept { return layer->getTrainable(); }
 
+  /**
+   * Support interfaces for the properties intercepted from layer
+   */
+
+  /**
+   * @brief     get if the output of this layer must be flatten
+   * @retval    flatten value
+   */
+  bool getFlatten() { return flatten; }
+
 #ifdef PROFILE
   int event_key;
 #endif
@@ -153,12 +163,47 @@ private:
   bool flatten; /**< flatten the output of this node */
   ActivationType
     activation_type; /**< activation applied to the output of this node */
+  bool distribute;
+
+  /**
+   * These properties are set for the layer by the user but are intercepted
+   * and used in the node which forms the basic element of the graph.
+   */
+  std::tuple<> props; /**< properties for the layer node */
+
+  /**
+   * @brief setProperty by PropertyType
+   * @note By passing empty string, this can validate if @a type is valid
+   * @param[in] type property type to be passed
+   * @param[in] value value to be passed, if empty string is passed, do nothing
+   * but throws error when @a type is invalid
+   * @exception exception::not_supported     when property type is not valid for
+   * the particular layer
+   * @exception std::invalid_argument invalid argument
+   */
+  virtual void setProperty(const nntrainer::Layer::PropertyType type,
+                           const std::string &value = "");
 };
 
 /**
  * @brief LayerNode creator with constructor
+ *
+ * @params[in] type Type of the layer to be constructed
+ * @params[in] properties Properties of the layer
+ */
+std::unique_ptr<LayerNode>
+createLayerNode(const std::string &type,
+                const std::vector<std::string> &properties = {});
+
+/**
+ * @brief LayerNode creator with constructor
+ *
+ * @params[in] layer Already constructed layer
+ * @params[in] properties Properties of the layer
  */
-std::unique_ptr<LayerNode> createLayerNode(const std::string &type);
+std::unique_ptr<LayerNode>
+createLayerNode(std::shared_ptr<nntrainer::Layer> layer,
+                const std::vector<std::string> &properties = {});
 
 } // namespace nntrainer
 #endif // __LAYER_NODE_H__
index 9a9e7524cbf50ac19c43dfbd3f55bbed141030b6..250e829699603ba1e0fdc66ddc6f37b9c795877c 100644 (file)
 #include <app_context.h>
 #include <nntrainer_error.h>
 
+/**
+ * @brief   Directory for appcontext unittests
+ *
+ */
 class nntrainerAppContextDirectory : public ::testing::Test {
 
 protected:
@@ -89,6 +93,10 @@ TEST_F(nntrainerAppContextDirectory, notExisitingSetDirectory_n) {
                std::invalid_argument);
 }
 
+/**
+ * @brief   Custom Optimizer for unittests
+ *
+ */
 class CustomOptimizer : public nntrainer::Optimizer {
 public:
   /** Full custom optimizer example which overrides all functions */
@@ -112,6 +120,10 @@ public:
                      int iteration) override {}
 };
 
+/**
+ * @brief   Custom Optimizer for unittests
+ *
+ */
 class CustomOptimizer2 : public nntrainer::Optimizer {
 public:
   /** Minimal custom optimizer example which define only necessary functions */
@@ -127,7 +139,11 @@ public:
                      int iteration) override {}
 };
 
-/// @todo solidify the api signature
+/**
+ * @brief   Custom Layer for unittests
+ *
+ * @todo solidify the api signature
+ */
 class CustomLayer : public nntrainer::Layer {
 public:
   static const std::string type;
@@ -140,8 +156,6 @@ public:
 
   void setTrainable(bool train) override {}
 
-  bool getFlatten() override { return true; }
-
   std::string getName() noexcept override { return ""; }
 
   const std::string getType() const override { return CustomLayer::type; }