[IniSerializer] Add `serialize` to ini
authorJihoon Lee <jhoon.it.lee@samsung.com>
Mon, 12 Apr 2021 09:33:10 +0000 (18:33 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Thu, 6 May 2021 12:57:37 +0000 (21:57 +0900)
**Changes proposed in this PR:**
- implements ini interpreter::serialize
- add corresponding test (reference shoud be equal to
serialize->deserialized graph)
- Fix some const correctness

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

Signed-off-by: Jihoon Lee <jhoon.it.lee@samsung.com>
nntrainer/compiler/ini_interpreter.cpp
nntrainer/graph/network_graph.cpp
nntrainer/graph/network_graph.h
nntrainer/utils/ini_wrapper.cpp
nntrainer/utils/ini_wrapper.h
test/unittest/compiler/unittest_interpreter.cpp

index 0c9406a6d831d6afb0aaf1289b602492fa6abaef..2449805c2febbe2d3c0407c6cad5e1946c9854c1 100644 (file)
@@ -21,6 +21,7 @@
 #include <layer_factory.h>
 #include <nntrainer_error.h>
 #include <nntrainer_log.h>
+#include <node_exporter.h>
 #include <parse_util.h>
 #include <time_dist.h>
 #include <util_func.h>
@@ -275,12 +276,21 @@ void IniGraphInterpreter::serialize(
     IniSection s(layer->getName());
     s.setEntry("type", layer->getType());
 
-    /// @todo: implement export a property
-    std::cout << layer->getName() << std::endl;
+    Exporter e;
+    layer->export_to(e);
+
+    const auto key_val_pairs =
+      e.get_result<ExportMethods::METHOD_STRINGVECTOR>();
+
+    for (const auto &pair : key_val_pairs) {
+      s.setEntry(pair.first, pair.second);
+    }
+
+    sections.push_back(s);
   }
 
   auto ini = IniWrapper(out, sections);
-  ini.save_ini();
+  ini.save_ini(out);
 }
 
 std::shared_ptr<GraphRepresentation>
index 29fa8b63a679b042c44accc722c2c8cd20cb464c..c794961854029a55e901f05d939439b3d56641f6 100644 (file)
@@ -724,7 +724,7 @@ NetworkGraph::getUnsortedLayers(const std::string &input_layer,
   return ret;
 }
 
-std::vector<std::shared_ptr<Layer>> NetworkGraph::getLayers() {
+std::vector<std::shared_ptr<Layer>> NetworkGraph::getLayers() const {
   std::vector<std::shared_ptr<Layer>> ret;
   if (compiled) {
     std::transform(Sorted.begin(), Sorted.end(), std::back_inserter(ret),
index bf8cefda6731b58cb62bd0bf46b524b416f4abb9..fa020eb04e3c5a17a69964006bf8777186abb3e6 100644 (file)
@@ -151,7 +151,7 @@ public:
    * @note these layers will be in sorted order if the model is compiled,
    * otherwise the order is the order of addition of layers in the model.
    */
-  std::vector<std::shared_ptr<Layer>> getLayers();
+  std::vector<std::shared_ptr<Layer>> getLayers() const;
 
   /**
    * @brief     join passed graph into the existing graph model
index 519502bb6e383ae9a5834d1b2469dafec3f4d444..79075ac4133469e8c6498b7e096c4f4c6437e172 100644 (file)
@@ -113,8 +113,10 @@ void IniWrapper::updateSections(const Sections &sections_) {
   }
 }
 
-void IniWrapper::save_ini() {
-  std::ofstream out(getIniName().c_str(), std::ios_base::out);
+void IniWrapper::save_ini() { save_ini(getIniName()); }
+
+void IniWrapper::save_ini(const std::string &ini_name) {
+  std::ofstream out(ini_name.c_str(), std::ios_base::out);
   NNTR_THROW_IF(!out.good(), std::runtime_error) << "cannot open ini";
 
   for (auto &it : sections) {
index 2dda96d8ba5f58815a8c46bb18ab20ff02f01831..43ca4c5fd0b20d061acf1f5c5d0449812ef52149 100644 (file)
@@ -305,9 +305,16 @@ public:
   std::string getName() const { return name; }
 
   /**
-   * @brief save ini to a file
+   * @brief save ini to a file, (getIniName() is used to save)
    */
   void save_ini();
+
+  /**
+   * @brief save ini by ini_name
+   *
+   * @param ini_name ini name to svae
+   */
+  void save_ini(const std::string &ini_name);
   /**
    * @brief erase ini
    *
index 790434d3e920019a3c20a22485e7cbb943a83061..346b4129454fca2dea98c1e02cf2f2b6f424ebdc 100644 (file)
@@ -45,6 +45,41 @@ const std::string pathResolver(const std::string &path) {
 auto ini_interpreter =
   std::make_shared<nntrainer::IniGraphInterpreter>(ac, pathResolver);
 
+/**
+ * @brief prototypical version of checking graph is equal
+ *
+ * @param lhs compiled(later, finalized) graph to be compared
+ * @param rhs compiled(later, finalized) graph to be compared
+ * @return true graph is equal
+ * @return false graph is not equal
+ */
+static void graphEqual(const nntrainer::GraphRepresentation &lhs,
+                       const nntrainer::GraphRepresentation &rhs) {
+  auto layers = lhs.getLayers();
+  auto ref_layers = rhs.getLayers();
+  EXPECT_EQ(layers.size(), ref_layers.size());
+
+  auto is_node_equal = [](const nntrainer::Layer &l,
+                          const nntrainer::Layer &r) {
+    nntrainer::Exporter lhs_export;
+    nntrainer::Exporter rhs_export;
+
+    l.export_to(lhs_export);
+    r.export_to(rhs_export);
+
+    /*** fixme, there is one caveat that order matters in this form */
+    EXPECT_EQ(
+      lhs_export.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>(),
+      rhs_export.get_result<nntrainer::ExportMethods::METHOD_STRINGVECTOR>());
+  };
+
+  if (layers.size() == ref_layers.size()) {
+    for (unsigned int i = 0; i < layers.size(); ++i) {
+      is_node_equal(*layers[i], *ref_layers[i]);
+    }
+  }
+}
+
 /**
  * @brief nntrainer Interpreter Test setup
  *
@@ -90,24 +125,11 @@ TEST_P(nntrainerInterpreterTest, graphEqual) {
   status = g->compile(nntrainer::LossType::LOSS_NONE);
   EXPECT_EQ(status, ML_ERROR_NONE);
 
-  /// @todo: make a graph equal
+  /// @todo: make a proper graph equal
   /// 1. having same number of nodes
   /// 2. layer name is identical (this is too strict though)
   /// 3. attributes of layer is identical
-  // EXPECT_EQ(*graph, *interpreter->deserialize(file_path));
-
-  auto layers = g->getLayers();
-  auto ref_layers = reference->getLayers();
-  EXPECT_EQ(layers.size(), ref_layers.size());
-
-  if (layers.size() == ref_layers.size()) {
-    for (auto &layer : layers) {
-      std::shared_ptr<nntrainer::Layer> ref_layer;
-      EXPECT_NO_THROW(ref_layer = reference->getLayer(layer->getName()));
-
-      /// @todo: layer->getProperties() and do check on each properties
-    }
-  }
+  graphEqual(*g, *reference);
 }
 
 /**
@@ -123,13 +145,11 @@ TEST_P(nntrainerInterpreterTest, graphSerializeAfterDeserialize) {
   int status = g->compile(nntrainer::LossType::LOSS_NONE);
   EXPECT_EQ(status, ML_ERROR_NONE);
   interpreter->serialize(g, out_file_path);
+  auto new_g = interpreter->deserialize(out_file_path);
 
-  // auto new_g = interpreter->deserialize(out_file_path);
+  graphEqual(*g, *new_g);
 
-  /// @todo: enable this
-  /// check if graph is the same
-  // EXPECT_EQ(*g, *new_g);
-  // EXPECT_EQ(remove(out_file_path.c_str()), 0);
+  EXPECT_EQ(remove(out_file_path.c_str()), 0) << strerror(errno);
 }
 
 auto fc0 = LayerReprentation("fully_connected",