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/DepthwiseConvolutionLayer.h"
21 #include "ops/FullyConnectedLayer.h"
23 #include <backend/Backend.h>
24 #include <backend/IConfig.h>
26 #include <util/Utils.h>
27 #include <util/logging.h>
28 #include <exec/DynamicShapeInferer.h>
39 KernelGenerator::KernelGenerator(
40 const ir::Graph &graph, const std::shared_ptr<TensorBuilder> &tensor_builder,
41 const std::shared_ptr<basic::TensorRegistry> &tensor_reg,
42 const std::shared_ptr<backend::custom::IKernelBuilder> &kernel_builder,
43 const std::shared_ptr<ExternalContext> &external_context)
44 : basic::KernelGeneratorBase{graph},
45 _ctx(graph.operands()), _operations_ctx{graph.operations()}, _current_layout{graph.layout()},
46 _tensor_builder(tensor_builder), _tensor_reg{tensor_reg}, _kernel_builder(kernel_builder),
47 _external_context(external_context)
52 std::unique_ptr<exec::FunctionSequence> KernelGenerator::generate(ir::OperationIndex ind)
54 auto ret = std::make_unique<exec::FunctionSequence>();
56 assert(_tensor_builder->dynamicTensorManager());
59 // Prepare to handle dynamic tensors later
60 auto dyn_ctx = std::make_shared<exec::FunctionSequence::DynamicTensorCtx>();
62 dyn_ctx->op = &_operations_ctx.at(ind);
63 dyn_ctx->dynamic_shape_inferer = std::make_shared<exec::DynamicShapeInferer>(_ctx, _tensor_reg);
65 ret->dynamic_tensor_ctx(dyn_ctx);
67 auto &op = _graph.operations().at(ind);
69 assert(_return_fn); // _return_fn must have been generated
70 ret->append(std::move(_return_fn));
72 for (auto ind : (op.getInputs() | ir::Remove::UNDEFINED) + op.getOutputs())
74 auto portable_tensor = _tensor_reg->getPortableTensor(ind);
77 assert(portable_tensor->layout() == ir::Layout::NHWC);
80 auto tensor = _tensor_reg->getNativeTensor(ind);
83 tensor->increase_ref();
89 void KernelGenerator::visit(const ir::operation::Conv2D &node)
91 using ir::operation::Conv2D;
93 const auto ofm_index{node.getOutputs().at(0)};
94 const auto ifm_index{node.getInputs().at(Conv2D::Input::INPUT)};
95 const auto ker_index{node.getInputs().at(Conv2D::Input::KERNEL)};
96 const auto bias_index{node.getInputs().at(Conv2D::Input::BIAS)};
98 auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
99 auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
100 auto ker_tensor = _tensor_reg->getPortableTensor(ker_index);
101 auto bias_tensor = _tensor_reg->getPortableTensor(bias_index);
103 const auto stride = node.param().stride;
104 const auto activation = node.param().activation;
105 const auto param_padding = node.param().padding;
106 const auto dilation = node.param().dilation;
107 auto fn = std::make_unique<ops::ConvolutionLayer>(_external_context);
109 const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_layout);
110 const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_layout);
111 // Kernel format is [depth_out, kernel_height, kernel_width, depth_in].
112 const auto &ker_shape = _ctx.at(ker_index).shape();
113 const auto ker_height = ker_shape.dim(1);
114 const auto ker_width = ker_shape.dim(2);
117 ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width, ker_height,
118 dilation.width_factor, dilation.height_factor);
120 fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, padding.left,
121 padding.right, padding.top, padding.bottom, stride.horizontal, stride.vertical,
122 dilation.width_factor, dilation.height_factor, activation, ofm_tensor);
124 _return_fn = std::move(fn);
127 void KernelGenerator::visit(const ir::operation::DepthwiseConv2D &node)
129 using ir::operation::DepthwiseConv2D;
131 const auto ofm_index{node.getOutputs().at(0)};
132 const auto ifm_index{node.getInputs().at(DepthwiseConv2D::Input::INPUT)};
133 const auto ker_index{node.getInputs().at(DepthwiseConv2D::Input::KERNEL)};
134 const auto bias_index{node.getInputs().at(DepthwiseConv2D::Input::BIAS)};
136 const auto stride = node.param().stride;
137 const auto ifm_shape = _ctx.at(ifm_index).shape().asFeature(_current_layout);
138 const auto ofm_shape = _ctx.at(ofm_index).shape().asFeature(_current_layout);
139 // Kernel format is [1, kernel_height, kernel_width, depth_out].
140 const auto &ker_shape = _ctx.at(ker_index).shape();
141 const auto ker_height = ker_shape.dim(1);
142 const auto ker_width = ker_shape.dim(2);
143 const auto dilation_width = node.param().dilation.width_factor;
144 const auto dilation_height = node.param().dilation.height_factor;
145 const auto param_padding = node.param().padding;
146 const auto padding = ir::calculatePadding(param_padding, ifm_shape, ofm_shape, stride, ker_width,
147 ker_height, dilation_width, dilation_height);
148 const auto multiplier = node.param().multiplier;
149 const auto activation = node.param().activation;
151 auto ofm_tensor = _tensor_reg->getPortableTensor(ofm_index);
152 auto ifm_tensor = _tensor_reg->getPortableTensor(ifm_index);
153 auto ker_tensor = _tensor_reg->getPortableTensor(ker_index);
154 auto bias_tensor = _tensor_reg->getPortableTensor(bias_index);
156 auto fn = std::make_unique<ops::DepthwiseConvolutionLayer>(_external_context);
158 fn->configure(ifm_tensor, ker_tensor, bias_tensor, param_padding.type, padding.left,
159 padding.right, padding.top, padding.bottom, stride.horizontal, stride.vertical,
160 multiplier, dilation_width, dilation_height, activation, ofm_tensor);
162 _return_fn = std::move(fn);
165 void KernelGenerator::visit(const ir::operation::FullyConnected &node)
167 using ir::operation::FullyConnected;
169 const auto output_index{node.getOutputs().at(0)};
170 const auto input_index{node.getInputs().at(FullyConnected::Input::INPUT)};
171 const auto weight_index{node.getInputs().at(FullyConnected::Input::WEIGHT)};
172 const auto bias_index{node.getInputs().at(FullyConnected::Input::BIAS)};
173 const auto activation = node.param().activation;
175 auto output_tensor = _tensor_reg->getPortableTensor(output_index);
176 auto input_tensor = _tensor_reg->getPortableTensor(input_index);
177 auto weight_tensor = _tensor_reg->getPortableTensor(weight_index);
178 auto bias_tensor = bias_index.undefined() ? nullptr : _tensor_reg->getPortableTensor(bias_index);
180 auto fn = std::make_unique<ops::FullyConnectedLayer>(_external_context);
182 fn->configure(input_tensor, weight_tensor, bias_tensor, activation, output_tensor);
184 _return_fn = std::move(fn);
187 } // namespace xnnpack
188 } // namespace backend