[Props] Add dimension property
authorJihoon Lee <jhoon.it.lee@samsung.com>
Mon, 3 May 2021 06:10:51 +0000 (15:10 +0900)
committerJijoong Moon <jijoong.moon@samsung.com>
Fri, 14 May 2021 03:45:34 +0000 (12:45 +0900)
This patch add dimension property

**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/utils/base_properties.cpp
nntrainer/utils/base_properties.h
test/unittest/unittest_properties.cpp

index 64435410da6e7c8a1563dec47588971c27dd8d9e..4cdedb24be96b8baddd27d0ae1da5796204b09eb 100644 (file)
@@ -11,7 +11,9 @@
  */
 #include <base_properties.h>
 
+#include <sstream>
 #include <string>
+#include <vector>
 
 namespace nntrainer {
 
@@ -48,4 +50,38 @@ unsigned int str_converter<uint_prop_tag, unsigned int>::from_string(
   const std::string &value) {
   return std::stoul(value);
 }
+
+template <>
+std::string str_converter<dimension_prop_tag, TensorDim>::to_string(
+  const TensorDim &dimension) {
+  std::stringstream ss;
+  ss << dimension.batch() << ':' << dimension.channel() << ':'
+     << dimension.height() << ':' << dimension.width();
+  return ss.str();
+}
+
+template <>
+TensorDim str_converter<dimension_prop_tag, TensorDim>::from_string(
+  const std::string &value) {
+  std::vector<std::string> tokens;
+  std::string token;
+  std::istringstream iss(value);
+
+  while (std::getline(iss, token, ':')) {
+    tokens.push_back(token);
+  }
+
+  NNTR_THROW_IF(tokens.size() > MAXDIM, std::invalid_argument)
+    << "More than 4 axes is not supported, target string: " << value;
+
+  TensorDim target;
+
+  int cur_axis = 3;
+  for (auto iter = tokens.rbegin(); iter != tokens.rend(); iter++) {
+    target.setTensorDim(cur_axis--, std::stoul(*iter));
+  }
+
+  return target;
+}
+
 } // namespace nntrainer
index 6ec21ef17ec760e0c8801f45e76ed0d824324bbd..69cfdf7228d0f3a7048da07d00d4bc22165371ab 100644 (file)
@@ -11,6 +11,7 @@
  */
 #include <nntrainer_error.h>
 #include <string>
+#include <tensor_dim.h>
 
 #ifndef __BASE_PROPERTIES_H__
 #define __BASE_PROPERTIES_H__
index a3202522cb1e3a03e9a44b1a829c506cef862d7c..4e0ddc9e44f203ad54d851f1ee7835f307e27848 100644 (file)
@@ -54,6 +54,22 @@ public:
     return nntrainer::endswith(v, "good");
   }
 };
+
+/**
+ * @brief DimensionOfBanana property for example, this has to have batch size of
+ * 1
+ *
+ */
+class DimensionOfBanana : public nntrainer::Property<nntrainer::TensorDim> {
+public:
+  static constexpr const char *key = "banana_size";
+  using prop_tag = nntrainer::dimension_prop_tag;
+
+  bool isValid(const nntrainer::TensorDim &dim) const override {
+    std::cerr << dim;
+    return dim.batch() == 1;
+  }
+};
 } // namespace
 
 TEST(BasicProperty, tagCast) {
@@ -111,6 +127,27 @@ TEST(BasicProperty, valid_p) {
     EXPECT_EQ(nntrainer::to_string(q), "this is good");
   }
 
+  { /** set -> get / to_string, dimension*/
+    DimensionOfBanana q;
+    q.set({1, 2, 3, 4});
+    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
+    EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
+  }
+
+  { /**< from_string -> get / to_string, dimension */
+    DimensionOfBanana q;
+    nntrainer::from_string("1:2:3:4", q);
+    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 2, 3, 4));
+    EXPECT_EQ(nntrainer::to_string(q), "1:2:3:4");
+  }
+
+  { /**< from_string -> get / to_string, dimension */
+    DimensionOfBanana q;
+    nntrainer::from_string("3:4", q);
+    EXPECT_EQ(q.get(), nntrainer::TensorDim(1, 1, 3, 4));
+    EXPECT_EQ(nntrainer::to_string(q), "1:1:3:4");
+  }
+
   { /**< exporter test */
     auto props = std::make_tuple(NumBanana(), QualityOfBanana());
 
@@ -139,12 +176,13 @@ TEST(BasicProperty, valid_p) {
   }
 
   { /**< load from layer */
-    auto props = std::make_tuple(NumBanana(), QualityOfBanana());
+    auto props =
+      std::make_tuple(NumBanana(), QualityOfBanana(), DimensionOfBanana());
 
-    auto v =
-      nntrainer::loadProperties({"num_banana=2", "quality_banana=thisisgood",
-                                 "num_banana=42", "not_used=key"},
-                                props);
+    auto v = nntrainer::loadProperties(
+      {"num_banana=2", "quality_banana=thisisgood", "num_banana=42",
+       "banana_size=2:2:3", "not_used=key"},
+      props);
 
     EXPECT_EQ(v, std::vector<std::string>{"not_used=key"});
     EXPECT_EQ(std::get<0>(props).get(), 42);
@@ -162,6 +200,11 @@ TEST(BasicProperty, setNotValid_02_n) {
   EXPECT_THROW(q.set("invalid_str"), std::invalid_argument);
 }
 
+TEST(BasicProperty, setNotValid_03_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(d.set({3, 3, 2, 4}), std::invalid_argument);
+}
+
 TEST(BasicProperty, fromStringNotValid_01_n) {
   NumBanana b;
   EXPECT_THROW(nntrainer::from_string("not integer", b), std::invalid_argument);
@@ -177,6 +220,26 @@ TEST(BasicProperty, fromStringNotValid_03_n) {
   EXPECT_THROW(nntrainer::from_string("invalid_str", q), std::invalid_argument);
 }
 
+TEST(BasicProperty, fromStringNotValid_04_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string("1:1:2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_05_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string("2:2:3:5", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_06_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string("", d), std::invalid_argument);
+}
+
+TEST(BasicProperty, fromStringNotValid_07_n) {
+  DimensionOfBanana d;
+  EXPECT_THROW(nntrainer::from_string(":2:3:5", d), std::invalid_argument);
+}
+
 TEST(Exporter, invalidMethods_n) {
   auto props = std::make_tuple(NumBanana(), QualityOfBanana());