From 2a92925abb958a6c654e578a217950a213d7f8d0 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=EB=B0=95=EC=84=B8=ED=9D=AC/=EB=8F=99=EC=9E=91=EC=A0=9C?= =?utf8?q?=EC=96=B4Lab=28SR=29/Principal=20Engineer/=EC=82=BC=EC=84=B1?= =?utf8?q?=EC=A0=84=EC=9E=90?= Date: Mon, 10 Dec 2018 08:59:00 +0900 Subject: [PATCH] [enco] frontend/caffe: separate concat (#2567) This will move Concatenation layer handler to separate file Signed-off-by: SaeHie Park --- contrib/enco/frontend/caffe/src/Frontend.cpp | 100 --------------- .../frontend/caffe/src/GraphBuilderRegistry.cpp | 2 + .../enco/frontend/caffe/src/Op/Concatenation.cpp | 138 +++++++++++++++++++++ contrib/enco/frontend/caffe/src/Op/Concatenation.h | 35 ++++++ 4 files changed, 175 insertions(+), 100 deletions(-) create mode 100644 contrib/enco/frontend/caffe/src/Op/Concatenation.cpp create mode 100644 contrib/enco/frontend/caffe/src/Op/Concatenation.h diff --git a/contrib/enco/frontend/caffe/src/Frontend.cpp b/contrib/enco/frontend/caffe/src/Frontend.cpp index 9b53b3c..881e1d3 100644 --- a/contrib/enco/frontend/caffe/src/Frontend.cpp +++ b/contrib/enco/frontend/caffe/src/Frontend.cpp @@ -130,106 +130,6 @@ enco::Bundle Frontend::load(void) const graph_builder->build(layer, &opbuilder_context); } // TODO move type handlers to separate builder - else if (layer.type() == "Concat") - { - assert(layer.bottom().size() > 0); - assert(layer.top().size() == 1); - - // Assume default concat axis - // - Please refer to http://caffe.berkeleyvision.org/tutorial/layers/concat.html for details - // TODO Get concat axis from concat param - assert(!layer.has_concat_param()); - const uint32_t concat_axis = 1; - - // Construct a vector of input objects - std::vector input_objects; - - for (const auto &input_name : layer.bottom()) - { - const auto input_shape = as_feature_shape(shape_ctx.at(input_name)); - - auto input_bag = bag_ctx.at(input_name); - auto input_feature = module->entity()->object()->create(); - - input_feature->bag(input_bag); - input_feature->layout(coco::FeatureLayouts::BCHW::create(input_shape)); - - input_objects.emplace_back(input_feature); - } - - coco::FeatureObject *last_feature = input_objects.at(0); - - assert(last_feature != nullptr); - assert(last_feature->bag() != nullptr); - - // Update coco IR - // - // Given a sequence of input features %in[0] / %in[1] / ... / %in[N] - // the below code constructs a sequence of eval instructions - // - Load is omitted for simplicity - // - // %out[0] = eval(ConcatF(%in[0], %in[1])) - // %out[1] = eval(ConcatF(%out[0], %in[2])) - // ... - // %out[N - 1] = eval(ConcatF(%out[N - 2], %in[N])) - // - for (uint32_t n = 1; n < input_objects.size(); ++n) - { - auto const left_feature = last_feature; - auto const left_shape = left_feature->layout()->shape(); - - auto right_feature = input_objects.at(n); - auto right_shape = right_feature->layout()->shape(); - - // Batch is not supported, yet - assert(left_feature->layout()->batch() == 1); - assert(right_feature->layout()->batch() == 1); - - // Height and Width SHOULD BE IDENTICAL for depth concat - assert(left_shape.height() == right_shape.height()); - assert(left_shape.width() == right_shape.width()); - - const uint32_t C = left_shape.depth() + right_shape.depth(); - const uint32_t H = left_shape.height(); - const uint32_t W = left_shape.width(); - - const nncc::core::ADT::feature::Shape out_shape{C, H, W}; - - auto out_bag = module->entity()->bag()->create(num_elements(out_shape)); - auto out_feature = module->entity()->object()->create(); - - out_feature->bag(out_bag); - out_feature->layout(coco::FeatureLayouts::BCHW::create(out_shape)); - - auto left_load = op_builder(module).load(left_feature).pop(); - auto right_load = op_builder(module).load(right_feature).pop(); - - auto concat_f = module->entity()->op()->create(); - - concat_f->axis(coco::ConcatF::Axis::Depth); - concat_f->left(left_load); - concat_f->right(right_load); - - auto eval = instr_builder(module).eval(out_feature, concat_f); - - // Append the constructed Shuffle instruction - blk->instr()->append(eval); - - // Update 'last_feature' - last_feature = out_feature; - } - - assert(last_feature != nullptr); - assert(last_feature->bag() != nullptr); - - // Update bag and shape context - auto const out_name = layer.top(0); - auto const out_shape = as_tensor_shape(last_feature->layout()->shape()); - auto const out_bag = last_feature->bag(); - - bag_ctx[out_name] = out_bag; - shape_ctx[out_name] = out_shape; - } else if (layer.type() == "Eltwise") { using coco::FeatureLayouts::BCHW; diff --git a/contrib/enco/frontend/caffe/src/GraphBuilderRegistry.cpp b/contrib/enco/frontend/caffe/src/GraphBuilderRegistry.cpp index ccff739..5a0a96f 100644 --- a/contrib/enco/frontend/caffe/src/GraphBuilderRegistry.cpp +++ b/contrib/enco/frontend/caffe/src/GraphBuilderRegistry.cpp @@ -16,6 +16,7 @@ #include "GraphBuilderRegistry.h" +#include "Op/Concatenation.h" #include "Op/Convolution.h" #include "Op/Input.h" #include "Op/Pooling.h" @@ -31,6 +32,7 @@ namespace caffeimport GraphBuilderRegistry::GraphBuilderRegistry() { // TODO add GraphBuilder for each caffe layer. + _builder_map["Concat"] = make_unique(); _builder_map["Convolution"] = make_unique(); _builder_map["Input"] = make_unique(); _builder_map["Pooling"] = make_unique(); diff --git a/contrib/enco/frontend/caffe/src/Op/Concatenation.cpp b/contrib/enco/frontend/caffe/src/Op/Concatenation.cpp new file mode 100644 index 0000000..f05f590 --- /dev/null +++ b/contrib/enco/frontend/caffe/src/Op/Concatenation.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Concatenation.h" +#include "IRBuilder.h" + +#include + +#include + +#include + +using namespace nncc::core::ADT; +using namespace morph::caffe; + +namespace caffeimport +{ + +void ConcatBuilder::build(const ::caffe::LayerParameter &layer, GraphBuilderContext *context) const +{ + coco::Module *module = context->module(); + coco::Block *blk = context->block(); + std::map &shape_ctx = context->shape_ctx(); + std::map &bag_ctx = context->bag_ctx(); + + assert(layer.bottom().size() > 0); + assert(layer.top().size() == 1); + + // Assume default concat axis + // - Please refer to http://caffe.berkeleyvision.org/tutorial/layers/concat.html for details + // TODO Get concat axis from concat param + assert(!layer.has_concat_param()); + const uint32_t concat_axis = 1; + + // Construct a vector of input objects + std::vector input_objects; + + for (const auto &input_name : layer.bottom()) + { + const auto input_shape = as_feature_shape(shape_ctx.at(input_name)); + + auto input_bag = bag_ctx.at(input_name); + auto input_feature = module->entity()->object()->create(); + + input_feature->bag(input_bag); + input_feature->layout(coco::FeatureLayouts::BCHW::create(input_shape)); + + input_objects.emplace_back(input_feature); + } + + coco::FeatureObject *last_feature = input_objects.at(0); + + assert(last_feature != nullptr); + assert(last_feature->bag() != nullptr); + + // Update coco IR + // + // Given a sequence of input features %in[0] / %in[1] / ... / %in[N] + // the below code constructs a sequence of eval instructions + // - Load is omitted for simplicity + // + // %out[0] = eval(ConcatF(%in[0], %in[1])) + // %out[1] = eval(ConcatF(%out[0], %in[2])) + // ... + // %out[N - 1] = eval(ConcatF(%out[N - 2], %in[N])) + // + for (uint32_t n = 1; n < input_objects.size(); ++n) + { + auto const left_feature = last_feature; + auto const left_shape = left_feature->layout()->shape(); + + auto right_feature = input_objects.at(n); + auto right_shape = right_feature->layout()->shape(); + + // Batch is not supported, yet + assert(left_feature->layout()->batch() == 1); + assert(right_feature->layout()->batch() == 1); + + // Height and Width SHOULD BE IDENTICAL for depth concat + assert(left_shape.height() == right_shape.height()); + assert(left_shape.width() == right_shape.width()); + + const uint32_t C = left_shape.depth() + right_shape.depth(); + const uint32_t H = left_shape.height(); + const uint32_t W = left_shape.width(); + + const nncc::core::ADT::feature::Shape out_shape{C, H, W}; + + auto out_bag = module->entity()->bag()->create(num_elements(out_shape)); + auto out_feature = module->entity()->object()->create(); + + out_feature->bag(out_bag); + out_feature->layout(coco::FeatureLayouts::BCHW::create(out_shape)); + + auto left_load = op_builder(module).load(left_feature).pop(); + auto right_load = op_builder(module).load(right_feature).pop(); + + auto concat_f = module->entity()->op()->create(); + + concat_f->axis(coco::ConcatF::Axis::Depth); + concat_f->left(left_load); + concat_f->right(right_load); + + auto eval = instr_builder(module).eval(out_feature, concat_f); + + // Append the constructed Shuffle instruction + blk->instr()->append(eval); + + // Update 'last_feature' + last_feature = out_feature; + } + + assert(last_feature != nullptr); + assert(last_feature->bag() != nullptr); + + // Update bag and shape context + auto const out_name = layer.top(0); + auto const out_shape = as_tensor_shape(last_feature->layout()->shape()); + auto const out_bag = last_feature->bag(); + + bag_ctx[out_name] = out_bag; + shape_ctx[out_name] = out_shape; +} + +} // namespace caffeimport diff --git a/contrib/enco/frontend/caffe/src/Op/Concatenation.h b/contrib/enco/frontend/caffe/src/Op/Concatenation.h new file mode 100644 index 0000000..85e0400 --- /dev/null +++ b/contrib/enco/frontend/caffe/src/Op/Concatenation.h @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CONCAT_BUILDER_H__ +#define __CONCAT_BUILDER_H__ + +#include "GraphBuilder.h" + +#include "Context.h" + +namespace caffeimport +{ + +class ConcatBuilder final : public GraphBuilder +{ +public: + void build(const ::caffe::LayerParameter &layer, GraphBuilderContext *context) const override; +}; + +} // namespace caffeimport + +#endif // __CONCAT_BUILDER_H__ -- 2.7.4