ONE - On-device Neural Engine
Loading...
Searching...
No Matches
Concatenation.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018 Samsung Electronics Co., Ltd. All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Concatenation.h"
18#include "IRBuilder.h"
19
21
22#include <morph/caffe.h>
23
24#include <cassert>
25
26using namespace nncc::core::ADT;
27using namespace morph::caffe;
28
29namespace caffeimport
30{
31
32void ConcatBuilder::build(const ::caffe::LayerParameter &layer, GraphBuilderContext *context) const
33{
34 coco::Module *module = context->module();
35 coco::Block *blk = context->block();
36 std::map<std::string, tensor::Shape> &shape_ctx = context->shape_ctx();
37 std::map<std::string, coco::Bag *> &bag_ctx = context->bag_ctx();
38
39 assert(layer.bottom().size() > 0);
40 assert(layer.top().size() == 1);
41
42 // Assume default concat axis
43 // - Please refer to http://caffe.berkeleyvision.org/tutorial/layers/concat.html for details
44 // TODO Get concat axis from concat param
45 assert(!layer.has_concat_param());
46 const uint32_t concat_axis = 1;
47
48 // Construct a vector of input objects
49 std::vector<coco::FeatureObject *> input_objects;
50
51 for (const auto &input_name : layer.bottom())
52 {
53 const auto input_shape = as_feature_shape(shape_ctx.at(input_name));
54
55 auto input_bag = bag_ctx.at(input_name);
56 auto input_feature = module->entity()->object()->create<coco::FeatureObject>();
57
58 input_feature->bag(input_bag);
59 input_feature->layout(coco::FeatureLayouts::BCHW::create(input_shape));
60
61 input_objects.emplace_back(input_feature);
62 }
63
64 coco::FeatureObject *last_feature = input_objects.at(0);
65
66 assert(last_feature != nullptr);
67 assert(last_feature->bag() != nullptr);
68
69 // Update coco IR
70 //
71 // Given a sequence of input features %in[0] / %in[1] / ... / %in[N]
72 // the below code constructs a sequence of eval instructions
73 // - Load is omitted for simplicity
74 //
75 // %out[0] = eval(ConcatF(%in[0], %in[1]))
76 // %out[1] = eval(ConcatF(%out[0], %in[2]))
77 // ...
78 // %out[N - 1] = eval(ConcatF(%out[N - 2], %in[N]))
79 //
80 for (uint32_t n = 1; n < input_objects.size(); ++n)
81 {
82 auto const left_feature = last_feature;
83 auto const left_shape = left_feature->layout()->shape();
84
85 auto right_feature = input_objects.at(n);
86 auto right_shape = right_feature->layout()->shape();
87
88 // Batch is not supported, yet
89 assert(left_feature->layout()->batch() == 1);
90 assert(right_feature->layout()->batch() == 1);
91
92 // Height and Width SHOULD BE IDENTICAL for depth concat
93 assert(left_shape.height() == right_shape.height());
94 assert(left_shape.width() == right_shape.width());
95
96 const uint32_t C = left_shape.depth() + right_shape.depth();
97 const uint32_t H = left_shape.height();
98 const uint32_t W = left_shape.width();
99
100 const nncc::core::ADT::feature::Shape out_shape{C, H, W};
101
102 auto out_bag = module->entity()->bag()->create(num_elements(out_shape));
103 auto out_feature = module->entity()->object()->create<coco::FeatureObject>();
104
105 out_feature->bag(out_bag);
106 out_feature->layout(coco::FeatureLayouts::BCHW::create(out_shape));
107
108 auto left_load = op_builder(module).load(left_feature).pop();
109 auto right_load = op_builder(module).load(right_feature).pop();
110
111 auto concat_f = module->entity()->op()->create<coco::ConcatF>();
112
113 concat_f->axis(coco::ConcatF::Axis::Depth);
114 concat_f->left(left_load);
115 concat_f->right(right_load);
116
117 auto eval = instr_builder(module).eval(out_feature, concat_f);
118
119 // Append the constructed Shuffle instruction
120 blk->instr()->append(eval);
121
122 // Update 'last_feature'
123 last_feature = out_feature;
124 }
125
126 assert(last_feature != nullptr);
127 assert(last_feature->bag() != nullptr);
128
129 // Update bag and shape context
130 auto const out_name = layer.top(0);
131 auto const out_shape = as_tensor_shape(last_feature->layout()->shape());
132 auto const out_bag = last_feature->bag();
133
134 bag_ctx[out_name] = out_bag;
135 shape_ctx[out_name] = out_shape;
136}
137
138} // namespace caffeimport
OpBuilder op_builder(coco::Module *m)
Definition IRBuilder.h:144
InstrBuilder instr_builder(coco::Module *m)
Definition IRBuilder.h:174
coco::Eval * eval(coco::Object *out, coco::Op *op) const
Create "Eval" instruction with a given "Object" and "Op".
Definition IRBuilder.h:162
OpBuilder & load(coco::Object *obj)
Create "Load" op and push it onto the internal stack.
Definition IRBuilder.h:70
coco::Op * pop(void)
Pop op from the internal stack.
Definition IRBuilder.h:116
void build(const ::caffe::LayerParameter &layer, GraphBuilderContext *context) const override
ShapeContext & shape_ctx()
Definition Context.h:97
A unit of (grouped) instructions.
Definition Block.h:40
static std::unique_ptr< BCHW > create(const nncc::core::ADT::feature::Shape &shape)
FeatureMap values (used in CNN)
const FeatureLayout * layout(void) const
Top-level element of coco IR which represents a neural network.
Definition Module.h:34
coco::Bag * bag(void) const
Definition Object.h:74
tensor::Shape as_tensor_shape(const ::caffe::BlobShape &blob_shape)
Definition Convert.cpp:24
nncc::core::ADT::feature::Shape as_feature_shape(const nncc::core::ADT::tensor::Shape &)
Definition caffe.cpp:54
virtual const FeatureShape & shape(void) const =0