From: 박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 Date: Mon, 27 Aug 2018 09:36:07 +0000 (+0900) Subject: [enco] Introduce NormalizePass (#1192) X-Git-Tag: nncc_backup~2050 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=6a436a8fbd1d8d79831a518b0e8962e3c00cd627;p=platform%2Fcore%2Fml%2Fnnfw.git [enco] Introduce NormalizePass (#1192) This commit introduces NormalizePass which inserts data reordering (Shuffle) instructions to make each instruction/operation compatible with Android NN API. Signed-off-by: Jonghyun Park --- diff --git a/contrib/enco/core/src/Backend.cpp b/contrib/enco/core/src/Backend.cpp index 5baf763..02a7e8d 100644 --- a/contrib/enco/core/src/Backend.cpp +++ b/contrib/enco/core/src/Backend.cpp @@ -4,6 +4,7 @@ #include "CppCode.h" #include "Transforms/Duplicate.h" +#include "Transforms/Normalize.h" #include @@ -51,6 +52,10 @@ void Backend::compile(coco::Module *m, coco::Data *d) // that share the same bag as their underlying bag assert(!has_inout_bag(code.module())); + // Insert data ordering if necessary + NormalizePass normalize; + normalize.runOnCode(&code); + // TODO Run various transforms over enco::Code _os << CppCode{&code} << std::endl; diff --git a/contrib/enco/core/src/Transforms/Normalize.cpp b/contrib/enco/core/src/Transforms/Normalize.cpp new file mode 100644 index 0000000..889885b --- /dev/null +++ b/contrib/enco/core/src/Transforms/Normalize.cpp @@ -0,0 +1,215 @@ +#include "Normalize.h" + +#include "Normalize.h" + +#include +#include + +#include +#include + +namespace +{ +bool aligned(const coco::FeatureObject *o, const nncc::core::ADT::feature::Layout &l) +{ + const auto &shape = o->shape(); + + for (uint32_t row = 0; row < shape.height(); ++row) + { + for (uint32_t col = 0; col < shape.width(); ++col) + { + for (uint32_t ch = 0; ch < shape.depth(); ++ch) + { + if (o->at(ch, row, col).value() != l.offset(shape, ch, row, col)) + { + return false; + } + } + } + } + + return true; +} + +bool aligned(const coco::KernelObject *o, const nncc::core::ADT::kernel::Layout &l) +{ + const auto &shape = o->shape(); + + for (uint32_t nth = 0; nth < shape.count(); ++nth) + { + for (uint32_t row = 0; row < shape.height(); ++row) + { + for (uint32_t col = 0; col < shape.width(); ++col) + { + for (uint32_t ch = 0; ch < shape.depth(); ++ch) + { + if (o->at(nth, ch, row, col).value() != l.offset(shape, nth, ch, row, col)) + { + return false; + } + } + } + } + } + + return true; +} + +bool is_HWC_layout(const coco::FeatureObject *o) +{ + return aligned(o, nncc::core::ADT::feature::HWCLayout{}); +} + +class ShuffleGen : public coco::Instr::Mutator +{ +public: + ShuffleGen(coco::Module *m) : _module{m} + { + // DO NOTHING + } + +private: + coco::FeatureObject *clone(const coco::FeatureObject *oldobj) const; + coco::Shuffle *create(const coco::FeatureObject *from, const coco::FeatureObject *into) const; + +public: + void mutate(coco::UnitF *unit) override; + void mutate(coco::Shuffle *) override; + +private: + coco::Module *const _module; +}; + +coco::FeatureObject *ShuffleGen::clone(const coco::FeatureObject *oldobj) const +{ + auto oldbag = oldobj->bag(); + + auto newbag = _module->entity()->bag()->create(oldbag->size()); + auto newobj = _module->entity()->object()->create(oldobj->shape()); + + newobj->bag(newbag); + newobj->reorder(); + + return newobj; +} + +coco::Shuffle *ShuffleGen::create(const coco::FeatureObject *oldobj, + const coco::FeatureObject *newobj) const +{ + auto oldbag = oldobj->bag(); + auto newbag = newobj->bag(); + + const auto &shape = oldobj->shape(); + + std::map content; + + for (uint32_t ch = 0; ch < shape.depth(); ++ch) + { + for (uint32_t row = 0; row < shape.height(); ++row) + { + for (uint32_t col = 0; col < shape.width(); ++col) + { + content[newobj->at(ch, row, col)] = oldobj->at(ch, row, col); + } + } + } + + auto shuffle = _module->entity()->instr()->create(); + + shuffle->from(oldbag); + shuffle->into(newbag); + + for (uint32_t n = 0; n < newbag->size(); ++n) + { + shuffle->at(n) = content[coco::ElemID{n}]; + } + + return shuffle; +} + +void ShuffleGen::mutate(coco::UnitF *unit) +{ + auto m = unit->parent()->parent(); + +#if 0 + // Create a new bag B + // Create a new obj O + // Link O to B with HWC layout + // + // Shuffle elements from the exsiting bag to the newly allocated bag + // + // std::map m; + // for (uint32_t ch = 0; ...) + // for (uint32_t row = 0; ...) + // for (uint32_t col = 0; ...) + // m[new->at(ch, row, col)] = old->at(ch, row, col); + // + // auto shuffle = m->entity()->instr()->create(); + // + // shffule->in(old_bag); + // shuffle->out(new_bag); + // + // for (uint32_t n = 0; ... ) + // shuffle->at(ElemID{n}) = m[ElemID{n}]; +#endif + if (unit->op()->asConv2D()) + { + if (!is_HWC_layout(unit->ifm())) + { + auto oldobj = unit->ifm(); + auto newobj = clone(oldobj); + + auto shuffle = create(oldobj, newobj); + shuffle->insertBefore(unit); + + unit->ifm(newobj); + } + + if (!is_HWC_layout(unit->ofm())) + { + auto oldobj = unit->ofm(); + auto newobj = clone(oldobj); + + auto shuffle = create(newobj, oldobj); + shuffle->insertAfter(unit); + + unit->ofm(newobj); + } + + // Reorder Kernel as NHWC + auto ker_obj = unit->op()->asConv2D()->ker(); + auto ker_bag = ker_obj->bag(); + + assert(ker_bag != nullptr); + assert(ker_bag->object()->size() == 1); + assert((ker_bag->isInput() == false) && (ker_bag->isOutput() == false)); + ker_obj->reorder(); + } +} + +void ShuffleGen::mutate(coco::Shuffle *) +{ + // DO NOTHING +} + +} // namespace + +namespace enco +{ + +void NormalizePass::runOnModule(coco::Module *m) const +{ + ::ShuffleGen gen{m}; + + for (auto blk = m->block()->head(); blk; blk = blk->next()) + { + for (auto ins = blk->instr()->head(); ins; ins = ins->next()) + { + ins->accept(gen); + } + } +} + +void NormalizePass::runOnCode(enco::Code *code) const { runOnModule(code->module()); } + +} // namespace enco diff --git a/contrib/enco/core/src/Transforms/Normalize.h b/contrib/enco/core/src/Transforms/Normalize.h new file mode 100644 index 0000000..a785e6c --- /dev/null +++ b/contrib/enco/core/src/Transforms/Normalize.h @@ -0,0 +1,23 @@ +#ifndef __NORMALIZE_H__ +#define __NORMALIZE_H__ + +#include "Code.h" + +namespace enco +{ + +/** + * @brief Insert data reordering if necessary + */ +class NormalizePass +{ +private: + void runOnModule(coco::Module *m) const; + +public: + void runOnCode(enco::Code *) const; +}; + +} // namespace enco + +#endif // __NORMALIZE_H__