From 4d0629718517739303dece2992ba4a6d3e9482d6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EB=B0=95=EC=A2=85=ED=98=84/=EB=8F=99=EC=9E=91=EC=A0=9C?= =?utf8?q?=EC=96=B4Lab=28SR=29/Staff=20Engineer/=EC=82=BC=EC=84=B1?= =?utf8?q?=EC=A0=84=EC=9E=90?= Date: Thu, 28 Jun 2018 19:16:16 +0900 Subject: [PATCH] Introduce 'nnop' library (#402) 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 --- contrib/nnop/CMakeLists.txt | 16 +++++++++ contrib/nnop/include/nnop/Conv2D.h | 66 ++++++++++++++++++++++++++++++++++++++ contrib/nnop/src/Conv2D.test.cpp | 33 +++++++++++++++++++ 3 files changed, 115 insertions(+) create mode 100644 contrib/nnop/CMakeLists.txt create mode 100644 contrib/nnop/include/nnop/Conv2D.h create mode 100644 contrib/nnop/src/Conv2D.test.cpp diff --git a/contrib/nnop/CMakeLists.txt b/contrib/nnop/CMakeLists.txt new file mode 100644 index 0000000..0939642 --- /dev/null +++ b/contrib/nnop/CMakeLists.txt @@ -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 index 0000000..4022a18 --- /dev/null +++ b/contrib/nnop/include/nnop/Conv2D.h @@ -0,0 +1,66 @@ +#ifndef __NNOP_CONV2D_H__ +#define __NNOP_CONV2D_H__ + +#include +#include +#include + +#include +#include + +#include +#include + +namespace nnop +{ + +template +void conv(const nncc::core::ADT::feature::Shape &out_shape, + nncc::core::ADT::feature::Accessor &out_data, + const nncc::core::ADT::feature::Shape &in_shape, + const nncc::core::ADT::feature::Reader &in_data, + const nncc::core::ADT::kernel::Shape &ker_shape, + const nncc::core::ADT::kernel::Reader &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(in_row), static_cast(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 index 0000000..b37aa62 --- /dev/null +++ b/contrib/nnop/src/Conv2D.test.cpp @@ -0,0 +1,33 @@ +#include "nnop/Conv2D.h" + +#include +#include + +#include +#include + +#include + +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(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(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(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); +} -- 2.7.4