From 2444da36e0bfa242f83f34c38178bc5b5e572008 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: Tue, 3 Jul 2018 10:19:18 +0900 Subject: [PATCH] [core.ADT] Add kernel index enumerator (#415) This commit adds kernel index enumerator which is almost similar as that of tensor, but specialized for convolution kernel. Signed-off-by: Jonghyun Park --- .../include/nncc/core/ADT/kernel/IndexEnumerator.h | 54 +++++++++++++++++ libs/core/src/ADT/kernel/IndexEnumerator.cpp | 68 ++++++++++++++++++++++ libs/core/src/ADT/kernel/IndexEnumerator.test.cpp | 30 ++++++++++ 3 files changed, 152 insertions(+) create mode 100644 libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h create mode 100644 libs/core/src/ADT/kernel/IndexEnumerator.cpp create mode 100644 libs/core/src/ADT/kernel/IndexEnumerator.test.cpp diff --git a/libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h b/libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h new file mode 100644 index 0000000..d9a28c4 --- /dev/null +++ b/libs/core/include/nncc/core/ADT/kernel/IndexEnumerator.h @@ -0,0 +1,54 @@ +#ifndef __NNCC_CORE_ADT_KERNEL_INDEX_ENUMERATOR_H__ +#define __NNCC_CORE_ADT_KERNEL_INDEX_ENUMERATOR_H__ + +#include "nncc/core/ADT/kernel/Shape.h" + +namespace nncc +{ +namespace core +{ +namespace ADT +{ +namespace kernel +{ + +class IndexEnumerator +{ +public: + explicit IndexEnumerator(const Shape &shape); + +public: + IndexEnumerator(IndexEnumerator &&) = delete; + IndexEnumerator(const IndexEnumerator &) = delete; + +public: + bool valid(void) const; + +public: + uint32_t count(void) const; + uint32_t depth(void) const; + uint32_t height(void) const; + uint32_t width(void) const; + +public: + void advance(void); + +private: + // Store max and current offset for count/depth/height/width + // + // NOTE Here explicit array is used instead of kernel::Shape to make + // a room for improvement such as enumeration order (NHWC, NCHW) + // support + uint32_t _max[4]; + uint32_t _cur[4]; + +private: + uint32_t _cursor; +}; + +} // namespace kernel +} // namespace ADT +} // namespace core +} // namespace nncc + +#endif // __NNCC_CORE_ADT_KERNEL_INDEX_ENUMERATOR_H__ diff --git a/libs/core/src/ADT/kernel/IndexEnumerator.cpp b/libs/core/src/ADT/kernel/IndexEnumerator.cpp new file mode 100644 index 0000000..21ed7e3 --- /dev/null +++ b/libs/core/src/ADT/kernel/IndexEnumerator.cpp @@ -0,0 +1,68 @@ +#include "nncc/core/ADT/kernel/IndexEnumerator.h" + +#include +#include + +namespace nncc +{ +namespace core +{ +namespace ADT +{ +namespace kernel +{ + +IndexEnumerator::IndexEnumerator(const Shape &shape) : _cursor(0) +{ + _max[0] = shape.width(); + _max[1] = shape.height(); + _max[2] = shape.depth(); + _max[3] = shape.count(); + + std::fill(_cur, _cur + 4, 0); + + // NOTE Null dimension should NOT exist + assert(std::find(_max, _max + 4, 0) == (_max + 4)); +} + +bool IndexEnumerator::valid(void) const { return _cursor < 4; } + +uint32_t IndexEnumerator::count(void) const { return _cur[3]; } +uint32_t IndexEnumerator::depth(void) const { return _cur[2]; } +uint32_t IndexEnumerator::height(void) const { return _cur[1]; } +uint32_t IndexEnumerator::width(void) const { return _cur[0]; } + +void IndexEnumerator::advance(void) +{ + while (_cursor < 4) + { + if (_cur[_cursor] + 1 < _max[_cursor]) + { + break; + } + + ++_cursor; + } + + if (_cursor == 4) + { + return; + } + + // Increment index + _cur[_cursor] += 1; + + // Reset indices for lower dimensions + for (uint32_t head = 0; head < _cursor; ++head) + { + _cur[head] = 0; + } + + // Reset cursor + _cursor = 0; +} + +} // namespace kernel +} // namespace ADT +} // namespace core +} // namespace nncc diff --git a/libs/core/src/ADT/kernel/IndexEnumerator.test.cpp b/libs/core/src/ADT/kernel/IndexEnumerator.test.cpp new file mode 100644 index 0000000..4e55563 --- /dev/null +++ b/libs/core/src/ADT/kernel/IndexEnumerator.test.cpp @@ -0,0 +1,30 @@ +#include "nncc/core/ADT/kernel/IndexEnumerator.h" + +#include +#include + +#include + +using nncc::core::ADT::kernel::Shape; +using nncc::core::ADT::kernel::IndexEnumerator; + +TEST(ADT_KERNEL_INDEX_ENUMERATOR, iterate_full_range) +{ + const uint32_t N = 2; + const uint32_t C = 3; + const uint32_t H = 4; + const uint32_t W = 5; + + const Shape shape{N, C, H, W}; + + std::vector count; + count.resize(N * C * H * W, 0); + + for (IndexEnumerator e{shape}; e.valid(); e.advance()) + { + const uint32_t offset = ((e.count() * C + e.depth()) * H + e.height()) * W + e.width(); + count.at(offset) += 1; + } + + ASSERT_TRUE(std::all_of(count.begin(), count.end(), [](uint32_t n) { return n == 1; })); +} -- 2.7.4