2 * Copyright (c) 2020 Samsung Electronics Co., Ltd. All Rights Reserved
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #include "KernelGenerator.h"
19 #include "ops/ConvolutionLayer.h"
20 #include "ops/FullyConnectedLayer.h"
22 #include <backend/Backend.h>
23 #include <backend/IConfig.h>
25 #include <util/Utils.h>
26 #include <util/logging.h>
27 #include <exec/DynamicShapeInferer.h>
38 KernelGenerator::KernelGenerator(
39 const ir::Operands &operands_ctx, const ir::Operations &operations_ctx,
40 const std::shared_ptr<TensorBuilder> &tensor_builder,
41 const std::shared_ptr<cpu_common::TensorRegistry> &tensor_reg,
42 const std::shared_ptr<backend::custom::IKernelBuilder> &kernel_builder,
43 const std::shared_ptr<ExternalContext> &external_context)
44 : _ctx(operands_ctx), _operations_ctx{operations_ctx}, _tensor_builder(tensor_builder),
45 _tensor_reg{tensor_reg}, _kernel_builder(kernel_builder),
46 _current_layout(ir::Layout::UNKNOWN), _external_context(external_context)
51 void KernelGenerator::visit(const ir::OpSequence &op_seq)
53 assert(!_return_fn_seq);
54 assert(_tensor_builder->dynamicTensorManager());
57 auto dyn_shape_inferer = std::make_shared<exec::DynamicShapeInferer>(_ctx, _tensor_reg);
59 _return_fn_seq = std::make_unique<exec::FunctionSequence>();
61 // Prepare to handle dynamic tensors later
62 auto dyn_ctx = std::make_shared<exec::FunctionSequence::DynamicTensorCtx>();
64 dyn_ctx->op_seq = &op_seq;
65 dyn_ctx->operations = &_operations_ctx;
66 dyn_ctx->dynamic_shape_inferer = std::move(dyn_shape_inferer);
67 dyn_ctx->dynamic_tensor_manager = _tensor_builder->dynamicTensorManager();
69 _return_fn_seq->dynamic_tensor_ctx(dyn_ctx);
72 _current_layout = op_seq.getLayout();
73 for (const auto &operation_idx : op_seq.operations())
75 const auto &node = _operations_ctx.at(operation_idx);
77 _return_fn_seq->append(releaseFunction());
79 for (const auto &ind : (node.getInputs() | ir::Remove::UNDEFINED) + node.getOutputs())
81 auto portable_tensor = _tensor_reg->getPortableTensor(ind);
84 assert(portable_tensor->layout() == ir::Layout::NHWC);
87 auto tensor = _tensor_reg->getNativeTensor(ind);
90 tensor->increase_ref();
96 void KernelGenerator::visit(const ir::operation::Conv2D &node)
98 using ir::operation::Conv2D;
100 const auto ofm_index{node.getOutputs().at(0)};
101 const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)};
102 const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)};
103 const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)};
105 auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
106 auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
107 auto ker_tensor = _tensor_reg->getPortableTensor(ker_index);
108 auto bias_tensor = _tensor_reg->getPortableTensor(bias_index);
110 const auto stride = node.param().stride;
111 const auto activation = node.param().activation;
112 const auto param_padding = node.param().padding;
113 const auto dilation = node.param().dilation;
114 auto fn = std::make_unique<ops::ConvolutionLayer>();
116 if (_ctx.at(ifm_index).info().isDynamic() || _ctx.at(ker_index).info().isDynamic())
118 fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, param_padding.param.left,
119 param_padding.param.right, param_padding.param.top, param_padding.param.bottom,
120 stride.horizontal, stride.vertical, dilation.width_factor, dilation.height_factor,
121 activation, ofm_tensor, _external_context);
123 _return_fn = std::move(fn);
126 const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_layout);
127 const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_layout);
128 // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
129 const auto &ker_shape = _ctx.at(ker_index).shape();
130 const auto ker_height = ker_shape.dim(1);
131 const auto ker_width = ker_shape.dim(2);
134 ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height,
135 dilation.width_factor, dilation.height_factor);
137 fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, padding.left,
138 padding.right, padding.top, padding.bottom, stride.horizontal, stride.vertical,
139 dilation.width_factor, dilation.height_factor, activation, ofm_tensor,
142 _return_fn = std::move(fn);
145 void KernelGenerator::visit(const ir::operation::FullyConnected &node)
147 using ir::operation::FullyConnected;
149 const auto output_index{node.getOutputs().at(0)};
150 const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)};
151 const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)};
152 const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)};
153 const auto activation = node.param().activation;
154 const auto weights_format = node.param().weights_format;
156 auto output_tensor = _tensor_reg->getPortableTensor(output_index);
157 auto input_tensor = _tensor_reg->getPortableTensor(input_index);
158 auto weight_tensor = _tensor_reg->getPortableTensor(weight_index);
159 auto bias_tensor = bias_index.undefined() ? nullptr : _tensor_reg->getPortableTensor(bias_index);
161 auto fn = std::make_unique<ops::FullyConnectedLayer>();
163 fn->configure(input_tensor, weight_tensor, bias_tensor, activation, weights_format, output_tensor,
166 _return_fn = std::move(fn);
170 } // namespace backend