Introduce 'nnop' library (#402)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Thu, 28 Jun 2018 10:16:16 +0000 (19:16 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Thu, 28 Jun 2018 10:16:16 +0000 (19:16 +0900)
This commit introduce 'nnop' librarry which provides simple (naive)
implementation of NN operation (which can be used as a reference).

'nnop' currently contains 'conv2d' operation.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
contrib/nnop/CMakeLists.txt [new file with mode: 0644]
contrib/nnop/include/nnop/Conv2D.h [new file with mode: 0644]
contrib/nnop/src/Conv2D.test.cpp [new file with mode: 0644]

diff --git a/contrib/nnop/CMakeLists.txt b/contrib/nnop/CMakeLists.txt
new file mode 100644 (file)
index 0000000..0939642
--- /dev/null
@@ -0,0 +1,16 @@
+add_library(nnop INTERFACE)
+target_include_directories(nnop INTERFACE include)
+target_link_libraries(nnop INTERFACE nncc_core)
+
+nncc_find_package(GTest QUIET)
+
+if(NOT GTest_FOUND)
+  return()
+endif(NOT GTest_FOUND)
+
+file(GLOB_RECURSE TESTS "src/*.test.cpp")
+
+add_executable(nnop_test ${TESTS})
+target_link_libraries(nnop_test nnop)
+target_link_libraries(nnop_test gtest_main)
+add_test(nnop_test nnop_test)
diff --git a/contrib/nnop/include/nnop/Conv2D.h b/contrib/nnop/include/nnop/Conv2D.h
new file mode 100644 (file)
index 0000000..4022a18
--- /dev/null
@@ -0,0 +1,66 @@
+#ifndef __NNOP_CONV2D_H__
+#define __NNOP_CONV2D_H__
+
+#include <nncc/core/ADT/feature/Shape.h>
+#include <nncc/core/ADT/feature/Reader.h>
+#include <nncc/core/ADT/feature/Accessor.h>
+
+#include <nncc/core/ADT/kernel/Shape.h>
+#include <nncc/core/ADT/kernel/Reader.h>
+
+#include <nncc/core/ADT/PadInfo.h>
+#include <nncc/core/ADT/StrideInfo.h>
+
+namespace nnop
+{
+
+template<typename OutputDType, typename InputDType, typename KernelDType>
+void conv(const nncc::core::ADT::feature::Shape &out_shape,
+          nncc::core::ADT::feature::Accessor<OutputDType> &out_data,
+          const nncc::core::ADT::feature::Shape &in_shape,
+          const nncc::core::ADT::feature::Reader<InputDType> &in_data,
+          const nncc::core::ADT::kernel::Shape &ker_shape,
+          const nncc::core::ADT::kernel::Reader<KernelDType> &ker_data,
+          const nncc::core::ADT::PadInfo &pad_info, const nncc::core::ADT::StrideInfo &stride_info)
+{
+  for (uint32_t out_ch = 0; out_ch < out_shape.depth(); ++out_ch)
+  {
+    for (uint32_t out_row = 0; out_row < out_shape.height(); ++out_row)
+    {
+      for (uint32_t out_col = 0; out_col < out_shape.width(); ++out_col)
+      {
+        OutputDType out_value = 0;
+
+        for (uint32_t ker_ch = 0; ker_ch < ker_shape.depth(); ++ker_ch)
+        {
+          for (uint32_t ker_row = 0; ker_row < ker_shape.height(); ++ker_row)
+          {
+            for (uint32_t ker_col = 0; ker_col < ker_shape.width(); ++ker_col)
+            {
+              const uint32_t in_ch = ker_ch;
+              const int64_t in_row = stride_info.vertical() * out_row - pad_info.top() + ker_row;
+              const int64_t in_col = stride_info.horizontal() * out_col - pad_info.left() + ker_col;
+
+              const bool is_padding = (in_row < 0) || (in_row >= in_shape.height())
+                                    || (in_col < 0) || (in_col >= in_shape.width());
+
+              const auto in_value = (is_padding)
+                                  ? 0
+                                  : in_data.at(in_ch, static_cast<uint32_t>(in_row), static_cast<uint32_t>(in_col));
+
+              const auto ker_value = ker_data.at(out_ch, in_ch, ker_row, ker_col);
+
+              out_value += in_value * ker_value;
+            }
+          }
+        }
+
+        out_data.at(out_ch, out_row, out_col) = out_value;
+      }
+    }
+  }
+}
+
+} // namespace nnop
+
+#endif // __NNOP_CONV2D_H__
diff --git a/contrib/nnop/src/Conv2D.test.cpp b/contrib/nnop/src/Conv2D.test.cpp
new file mode 100644 (file)
index 0000000..b37aa62
--- /dev/null
@@ -0,0 +1,33 @@
+#include "nnop/Conv2D.h"
+
+#include <nncc/core/ADT/feature/Overlay.h>
+#include <nncc/core/ADT/feature/CHWLayout.h>
+
+#include <nncc/core/ADT/kernel/Overlay.h>
+#include <nncc/core/ADT/kernel/NCHWLayout.h>
+
+#include <gtest/gtest.h>
+
+using namespace nncc::core::ADT;
+
+TEST(CONV2D, conv_1)
+{
+  const feature::Shape ofm_shape{1, 1, 1};
+  int ofm_data[] = { 0 };
+  auto ofm_overlay = feature::make_overlay<int, feature::CHWLayout>(ofm_shape, ofm_data);
+
+  const feature::Shape ifm_shape{1, 3, 3};
+  int ifm_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+  auto ifm_overlay = feature::make_overlay<int, feature::CHWLayout>(ifm_shape, ifm_data);
+
+  const kernel::Shape ker_shape{1, 1, 3, 3};
+  int ker_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 };
+  auto ker_overlay = kernel::make_overlay<int, kernel::NCHWLayout>(ker_shape, ker_data);
+
+  const PadInfo pad{0, 0, 0, 0};
+  const StrideInfo stride{1, 1};
+
+  nnop::conv(ofm_shape, ofm_overlay, ifm_shape, ifm_overlay, ker_shape, ker_overlay, pad, stride);
+
+  EXPECT_EQ(ofm_data[0], 204);
+}