blob: d0035d9a841ae42b7dc882776f0104297d3651fc [file] [log] [blame]
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001/*
Giuseppe Rossinibb365de2019-02-15 10:24:47 +00002 * Copyright (c) 2018-2019 ARM Limited.
Georgios Pinitasda2491f2018-06-01 17:49:09 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__
25#define __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__
26
27#include "arm_compute/graph/Logger.h"
28#include "arm_compute/graph/Tensor.h"
29#include "arm_compute/graph/TypePrinter.h"
30#include "arm_compute/graph/Types.h"
giuros01acce5042019-02-21 17:32:34 +000031#include "arm_compute/graph/backends/FusedConvolutionBatchNormalizationFunction.h"
Georgios Pinitasda2491f2018-06-01 17:49:09 +010032#include "arm_compute/graph/backends/Utils.h"
33#include "arm_compute/graph/nodes/Nodes.h"
34
35#include "arm_compute/core/Error.h"
36#include "arm_compute/core/Helpers.h"
37#include "arm_compute/core/ITensorInfo.h"
38#include "arm_compute/core/utils/misc/Cast.h"
39
40namespace arm_compute
41{
42namespace graph
43{
44namespace backends
45{
46namespace detail
47{
48/** Returns backing tensor of a given tensor
49 *
50 * @tparam TargetInfo Target information
51 *
52 * @param[in] tensor Tensor to extract the backing tensor from
53 *
54 * @return Backing tensor if present else nullptr
55 */
56template <typename TargetInfo>
57typename TargetInfo::TensorType *get_backing_tensor(arm_compute::graph::Tensor *tensor)
58{
59 typename TargetInfo::TensorType *backing_tensor = nullptr;
60 if(tensor != nullptr)
61 {
62 ARM_COMPUTE_ERROR_ON(tensor->desc().target != TargetInfo::TargetType);
63 // Get backing tensor handle
64 ITensorHandle *tensor_handle = tensor->handle();
65 // Get backing tensor
66 backing_tensor = (tensor_handle != nullptr) ? arm_compute::utils::cast::polymorphic_cast<typename TargetInfo::TensorType *>(&tensor_handle->tensor()) : nullptr;
67 }
68
69 return backing_tensor;
70}
71
72template <typename TargetInfo>
73void validate_node(const INode &node, size_t num_expected_inputs, size_t num_expected_outputs)
74{
75 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating " << node.type()
Pablo Tello32521432018-11-15 14:43:10 +000076 << " Target: " << TargetInfo::TargetType
77 << " ID: " << node.id()
78 << node.name()
Georgios Pinitasda2491f2018-06-01 17:49:09 +010079 << std::endl);
80
81 ARM_COMPUTE_ERROR_ON(TargetInfo::TargetType != node.assigned_target());
82 ARM_COMPUTE_ERROR_ON(node.num_inputs() != num_expected_inputs);
83 ARM_COMPUTE_ERROR_ON(node.num_outputs() != num_expected_outputs);
84}
85
86/** Creates a backend activation layer function
87 *
88 * @tparam ActivationLayerFunction Backend activation function
89 * @tparam TargetInfo Target-specific information
90 *
91 * @param[in] node Node to create the backend function for
92 *
93 * @return Backend activation layer function
94 */
95template <typename ActivationLayerFunction, typename TargetInfo>
96std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
97{
98 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
99
100 // Extract IO and info
101 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
102 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
103 const ActivationLayerInfo act_info = node.activation_info();
104
105 // Create function
106 auto func = support::cpp14::make_unique<ActivationLayerFunction>();
107 func->configure(input, output, act_info);
108
Pablo Tello32521432018-11-15 14:43:10 +0000109 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
110 << node.name()
111 << " Type: " << node.type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100112 << " Target " << TargetInfo::TargetType
113 << " Data Type: " << input->info()->data_type()
114 << " Shape: " << input->info()->tensor_shape()
115 << " Activation function: " << act_info.activation()
116 << " a: " << act_info.a()
117 << " b: " << act_info.b()
118 << " InPlace : " << is_in_place_operation(input, output)
119 << std::endl);
120
121 return std::move(func);
122}
123
124/** Create a backend batch normalization layer function
125 *
126 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
127 * @tparam TargetInfo Target-specific information
128 *
129 * @param[in] node Node to create the backend function for
130 *
131 * @return Backend batch normalization layer function
132 */
133template <typename BatchNormalizationLayerFunction, typename TargetInfo>
134std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
135{
136 validate_node<TargetInfo>(node, 5 /* expected inputs */, 1 /* expected outputs */);
137
138 // Extract IO and info
giuros01acce5042019-02-21 17:32:34 +0000139 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
140 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
141 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(2));
142 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(3));
143 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(4));
144
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100145 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
146 const float epsilon = node.epsilon();
147 const ActivationLayerInfo fused_act = node.fused_activation();
148
149 // Create and configure function
150 auto func = support::cpp14::make_unique<BatchNormalizationLayerFunction>();
151 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
152
153 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000154 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
155 << node.name()
156 << " Type: " << node.type()
157 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100158 << " Data Type: " << input->info()->data_type()
159 << " Shape: " << input->info()->tensor_shape()
160 << " Epsilon: " << epsilon << " "
161 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
Pablo Tello32521432018-11-15 14:43:10 +0000162 << " InPlace: " << is_in_place_operation(input, output)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100163 << std::endl);
164
165 return std::move(func);
166}
167
giuros01acce5042019-02-21 17:32:34 +0000168/** Create a backend batch normalization layer function
169 *
170 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
171 * @tparam TargetInfo Target-specific information
172 *
173 * @param[in] node Node to create the backend function for
174 *
175 * @return Backend batch normalization layer function
176 */
177template <typename FusedLayerTypes, typename TargetInfo>
178std::unique_ptr<IFunction> create_fused_convolution_batch_normalization_layer(FusedConvolutionBatchNormalizationNode &node)
179{
180 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
181
182 // Extract IO and info
183 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
184 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
185 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
186 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
187 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
188 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
189 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
190
191 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
192
193 const PadStrideInfo conv_info = node.convolution_info();
194 const unsigned int num_groups = node.num_groups();
195 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
196 const ActivationLayerInfo fused_act = node.fused_activation();
197 const float epsilon = node.epsilon();
198
199 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
200 if(is_quantized && biases != nullptr)
201 {
202 biases->info()->set_data_type(DataType::S32);
203 }
204
205 // Create and configure function
206 auto func = support::cpp14::make_unique<FusedConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>>();
207 func->configure(input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, num_groups, fast_math, fused_act);
208
209 // Log info
210 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
211 << node.name()
212 << " Type: " << node.name()
213 << " Target: " << TargetInfo::TargetType
214 << " Data Type: " << input->info()->data_type()
215 << " Input shape: " << input->info()->tensor_shape()
216 << " Weights shape: " << weights->info()->tensor_shape()
217 << " Output shape: " << output->info()->tensor_shape()
218 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
219 << std::endl);
220 return std::move(func);
221}
222
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100223/** Create a backend bounding box transform layer function
224 *
225 * @tparam BoundingBoxTransformLayerFunction Backend bounding box transform function
226 * @tparam TargetInfo Target-specific information
227 *
228 * @param[in] node Node to create the backend function for
229 *
230 * @return Backend bounding box transform layer function
231 */
232template <typename BoundingBoxTransformLayerFunction, typename TargetInfo>
233std::unique_ptr<IFunction> create_bounding_box_transform_layer(BoundingBoxTransformLayerNode &node)
234{
235 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
236
237 // Extract IO and info
238 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
239 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
240 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
241 const BoundingBoxTransformInfo bbox_info = node.info();
242
243 // Create and configure function
244 auto func = support::cpp14::make_unique<BoundingBoxTransformLayerFunction>();
245 func->configure(input, output, deltas, bbox_info);
246
247 // Log info
248 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
249 << " Target " << TargetInfo::TargetType
250 << " Data Type: " << input->info()->data_type()
251 << " Shape: " << input->info()->tensor_shape()
252 << " BoundingBox Info img W: " << bbox_info.img_width() << " "
253 << " BoundingBox Info img H: " << bbox_info.img_height() << " "
254 << std::endl);
255
256 return std::move(func);
257}
258
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100259/** Create a backend channel shuffle layer function
260 *
261 * @tparam ChannelShuffleLayerFunction Backend channel shuffle function
262 * @tparam TargetInfo Target-specific information
263 *
264 * @param[in] node Node to create the backend function for
265 *
266 * @return Backend channel shuffle layer function
267 */
268template <typename ChannelShuffleLayerFunction, typename TargetInfo>
269std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
270{
271 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
272
273 // Extract IO and info
274 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
275 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
276 const unsigned int num_groups = node.num_groups();
277
278 // Create function
279 auto func = support::cpp14::make_unique<ChannelShuffleLayerFunction>();
280 func->configure(input, output, num_groups);
281
Pablo Tello32521432018-11-15 14:43:10 +0000282 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
283 << node.name()
284 << " Type: " << node.type()
285 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100286 << " Data Type: " << input->info()->data_type()
287 << " Shape: " << input->info()->tensor_shape()
288 << " Num groups: " << num_groups
289 << std::endl);
290
291 return std::move(func);
292}
293
Georgios Pinitase2220552018-07-20 13:23:44 +0100294/** Create a backend layer concatenate function
295 *
296 * @tparam ConcatenateLayerFunction Backend concatenate function
297 * @tparam TargetInfo Target-specific information
298 *
299 * @param[in] node Node to create the backend function for
300 *
301 * @return Backend concatenate layer function
302 */
303template <typename ConcatenateLayerFunction, typename TargetInfo>
304std::unique_ptr<arm_compute::IFunction> create_concatenate_layer(ConcatenateLayerNode &node)
305{
306 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Concatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
307 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
308
309 // Return nullptr if depth concatenate is switched off
310 if(!node.is_enabled())
311 {
312 return nullptr;
313 }
314
315 // Extract IO and info
316 std::vector<typename TargetInfo::TensorType *> inputs;
317 for(unsigned int i = 0; i < node.num_inputs(); ++i)
318 {
319 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
320 }
321 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
322 const DataLayoutDimension concat_axis = node.concatenation_axis();
323
324 // Create and configure function
325 auto func = support::cpp14::make_unique<ConcatenateLayerFunction>();
326 func->configure(inputs, output, concat_axis);
327
328 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000329 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
330 << node.name()
331 << " Type: " << node.type()
332 << " Target: " << TargetInfo::TargetType
Georgios Pinitase2220552018-07-20 13:23:44 +0100333 << " Data Type: " << output->info()->data_type()
334 << " Shape: " << output->info()->tensor_shape()
335 << " Num Inputs: " << inputs.size()
336 << " Axis: " << concat_axis
337 << std::endl);
338
339 return std::move(func);
340}
341
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100342/** Create a backend convolution layer function
343 *
344 * @tparam ConvolutionLayerFunctions Backend convolution functions
345 * @tparam TargetInfo Target-specific information
346 *
347 * @param[in] node Node to create the backend function for
348 * @param[in] ctx Graph context
349 *
350 * @return Backend convolution layer function
351 */
352template <typename ConvolutionLayerFunctions, typename TargetInfo>
353std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
354{
355 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
356
357 // Extract IO and info
358 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
359 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
360 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
361 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
362
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100363 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
364
365 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100366 {
367 biases->info()->set_data_type(DataType::S32);
368 }
369
Georgios Pinitas08346e92018-10-16 19:10:46 +0100370 const PadStrideInfo conv_info = node.convolution_info();
371 const unsigned int num_groups = node.num_groups();
372 const ConvolutionMethod conv_algorithm = node.convolution_method();
373 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
374 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100375
376 // Create and configure function (we assume that functions have been validated before creation)
377 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
378 std::unique_ptr<IFunction> func;
379 std::string func_name;
380
Georgios Pinitase2220552018-07-20 13:23:44 +0100381 if(conv_algorithm == ConvolutionMethod::Winograd)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100382 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100383 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "WinogradConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100384 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::WinogradConvolutionLayer>(
385 std::string("WinogradConvolutionLayer"), mm,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100386 input, weights, biases, output, conv_info, fused_act, fast_math);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100387 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100388 else if(conv_algorithm == ConvolutionMethod::Direct)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100389 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100390 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "DirectConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100391 std::tie(func, func_name) = create_named_function<typename ConvolutionLayerFunctions::DirectConvolutionLayer>(
392 std::string("DirectConvolutionLayer"),
Georgios Pinitas08346e92018-10-16 19:10:46 +0100393 input, weights, biases, output, conv_info, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100394 }
395 else if(conv_algorithm == ConvolutionMethod::GEMM)
396 {
397 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GEMMConvolutionLayer>(
398 std::string("GEMMConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100399 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100400 WeightsInfo(), Size2D(1U, 1U), fused_act, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100401 }
402 else
403 {
404 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GenericConvolutionLayer>(
405 std::string("GenericConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100406 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100407 WeightsInfo(), Size2D(1U, 1U), fused_act, fast_math, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100408 }
409
410 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100411 std::ostringstream qss;
412 if(is_quantized)
413 {
414 qss << " Input QuantInfo: " << input->info()->quantization_info()
415 << " Weights QuantInfo: " << weights->info()->quantization_info()
416 << " Output QuantInfo: " << output->info()->quantization_info();
417 }
Pablo Tello32521432018-11-15 14:43:10 +0000418 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
419 << node.name()
420 << " Type: " << func_name
421 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100422 << " Data Type: " << input->info()->data_type()
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100423 << " Groups: " << num_groups
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100424 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100425 << " Input shape: " << input->info()->tensor_shape()
426 << " Weights shape: " << weights->info()->tensor_shape()
427 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas08346e92018-10-16 19:10:46 +0100428 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100429 << std::endl);
430 return func;
431}
432
433/** Create a backend deconvolution layer function
434 *
435 * @tparam DeconvolutionLayerFunction Backend deconvolution function
436 * @tparam TargetInfo Target-specific information
437 *
438 * @param[in] node Node to create the backend function for
439 * @param[in] ctx Graph context
440 *
441 * @return Backend deconvolution layer function
442 */
443template <typename DeconvolutionLayerFunction, typename TargetInfo>
444std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
445{
446 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
447
448 // Extract IO and info
449 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
450 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
451 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
452 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
453
454 const PadStrideInfo deconv_info = node.deconvolution_info();
455 const Size2D inner_border = node.inner_border();
456
457 // Create and configure function (we assume that functions have been validated before creation)
458 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
459 std::unique_ptr<IFunction> func;
460
461 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
462 std::string(), mm,
463 input, weights, biases, output, deconv_info, inner_border.x(), inner_border.y());
464
465 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000466 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
467 << node.name()
468 << " Type: " << node.type()
469 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100470 << " Data Type: " << input->info()->data_type()
471 << " Input shape: " << input->info()->tensor_shape()
472 << " Weights shape: " << weights->info()->tensor_shape()
473 << " Output shape: " << output->info()->tensor_shape()
474 << std::endl);
475 return func;
476}
477
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100478/** Create a backend layer depth-wise convolution function
479 *
480 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
481 * @tparam TargetInfo Target-specific information
482 *
483 * @param[in] node Node to create the backend function for
484 *
485 * @return Backend depth-wise convolution layer function
486 */
487template <typename DepthwiseConvolutionLayerFunctions, typename TargetInfo>
488std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
489{
490 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
491
492 // Extract IO and info
493 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
494 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
495 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
496 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
497
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100498 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
499
500 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100501 {
502 biases->info()->set_data_type(DataType::S32);
503 }
504
Georgios Pinitas60e98252018-10-22 16:17:20 +0100505 const PadStrideInfo conv_info = node.convolution_info();
506 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
Georgios Pinitas05045c12018-12-07 18:31:47 +0000507 const unsigned int depth_multiplier = node.depth_multiplier();
Georgios Pinitas60e98252018-10-22 16:17:20 +0100508 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100509
510 // Create and configure function (we assume that functions have been validated before creation)
511 std::unique_ptr<IFunction> func;
512 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100513 if(dwc_algorithm == DepthwiseConvolutionMethod::Optimized3x3)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100514 {
515 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::DepthwiseConvolutionLayer3x3>(
516 std::string("DepthwiseConvolutionLayer3x3"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100517 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100518 }
519 else
520 {
521 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::GenericDepthwiseConvolutionLayer>(
522 std::string("DepthwiseConvolutionLayer"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100523 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100524 }
525
526 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100527 std::ostringstream qss;
528 if(is_quantized)
529 {
530 qss << " Input QuantInfo: " << input->info()->quantization_info()
531 << " Weights QuantInfo: " << weights->info()->quantization_info()
532 << " Output QuantInfo: " << output->info()->quantization_info();
533 }
Pablo Tello32521432018-11-15 14:43:10 +0000534 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
535 << node.name()
536 << " Type: " << func_name
537 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100538 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100539 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100540 << " Input shape: " << input->info()->tensor_shape()
541 << " Weights shape: " << weights->info()->tensor_shape()
542 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000543 << " Depth multiplier: " << depth_multiplier
Georgios Pinitas60e98252018-10-22 16:17:20 +0100544 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100545 << std::endl);
546 return func;
547}
548
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000549/** Create a backend detection output layer function
550 *
551 * @tparam DetectionOutputLayer Function Backend detection output function
552 * @tparam TargetInfo Target-specific information
553 *
554 * @param[in] node Node to create the backend function for
555 *
556 * @return Backend detection output layer function
557 */
558template <typename DetectionOutputLayerFunction, typename TargetInfo>
559std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
560{
561 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
562
563 // Extract IO and info
564 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
565 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
566 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
567 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
568 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
569
570 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
571 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
572 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
573 ARM_COMPUTE_ERROR_ON(output == nullptr);
574
575 // Create and configure function
576 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
577 func->configure(input0, input1, input2, output, detect_info);
578
579 // Log info
580 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
581 << node.name()
582 << " Type: " << node.type()
583 << " Target: " << TargetInfo::TargetType
584 << " Data Type: " << input0->info()->data_type()
585 << " Input0 shape: " << input0->info()->tensor_shape()
586 << " Input1 shape: " << input1->info()->tensor_shape()
587 << " Input2 shape: " << input2->info()->tensor_shape()
588 << " Output shape: " << output->info()->tensor_shape()
589 << " DetectionOutputLayer info: " << detect_info
590 << std::endl);
591
592 return std::move(func);
593}
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100594/** Create a backend element-wise operation layer function
595 *
596 * @tparam EltwiseFunctions Backend element-wise function
597 * @tparam TargetInfo Target-specific information
598 *
599 * @param[in] node Node to create the backend function for
600 *
601 * @return Backend element-wise operation layer function
602 */
603template <typename EltwiseFunctions, typename TargetInfo>
604std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
605{
606 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
607
608 // Extract IO and info
609 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
610 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
611 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
612 const EltwiseOperation eltwise_op = node.eltwise_operation();
613 const ConvertPolicy convert_policy = node.convert_policy();
614 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
615 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
616 ARM_COMPUTE_ERROR_ON(output == nullptr);
617
618 std::unique_ptr<IFunction> func = nullptr;
619 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100620 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100621 {
622 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
623 std::string("ArithmeticAddition"),
624 input1, input2, output, convert_policy);
625 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100626 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100627 {
628 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
629 std::string("ArithmeticSubtraction"),
630 input1, input2, output, convert_policy);
631 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100632 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100633 {
634 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
635 std::string("PixelWiseMultiplication"),
636 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
637 }
638 else
639 {
640 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
641 }
642
643 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000644 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
645 << node.name()
646 << " Type: " << node.type()
647 << " Target: " << TargetInfo::TargetType
648 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100649 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000650 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100651 << std::endl);
652
653 return func;
654}
655
656/** Create a backend flatten layer function
657 *
658 * @tparam FlattenLayerFunction Backend flatten function
659 * @tparam TargetInfo Target-specific information
660 *
661 * @param[in] node Node to create the backend function for
662 *
663 * @return Backend flatten layer function
664 */
665template <typename FlattenLayerFunction, typename TargetInfo>
666std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
667{
668 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
669
670 // Extract IO and info
671 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
672 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
673
Georgios Pinitase2220552018-07-20 13:23:44 +0100674 ARM_COMPUTE_ERROR_ON(input == nullptr);
675 ARM_COMPUTE_ERROR_ON(output == nullptr);
676
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100677 // Create and configure function
678 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
679 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100680
681 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000682 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
683 << node.name()
684 << " Type: " << node.type()
685 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100686 << " Data Type: " << input->info()->data_type()
687 << " Input shape: " << input->info()->tensor_shape()
688 << " Output shape: " << output->info()->tensor_shape()
689 << std::endl);
690
691 return std::move(func);
692}
693
694/** Create a backend fully connected layer function
695 *
696 * @tparam FullyConnectedLayerFunction Backend fully-connected function
697 * @tparam TargetInfo Target-specific information
698 *
699 * @param[in] node Node to create the backend function for
700 * @param[in] ctx Graph context
701 *
702 * @return Backend fully connected layer function
703 */
704template <typename FullyConnectedLayerFunction, typename TargetInfo>
705std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
706{
707 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
708
709 // Extract IO and info
710 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
711 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
712 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
713 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100714 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100715
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100716 ARM_COMPUTE_ERROR_ON(input == nullptr);
717 ARM_COMPUTE_ERROR_ON(weights == nullptr);
718 ARM_COMPUTE_ERROR_ON(output == nullptr);
719
Georgios Pinitase2220552018-07-20 13:23:44 +0100720 // Create and configure function
721 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
722 func->configure(input, weights, biases, output, fc_info);
723
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100724 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
725
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100726 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100727 std::ostringstream qss;
728 if(is_quantized)
729 {
730 qss << " Input QuantInfo: " << input->info()->quantization_info()
731 << " Weights QuantInfo: " << weights->info()->quantization_info()
732 << " Output QuantInfo: " << output->info()->quantization_info();
733 }
Pablo Tello32521432018-11-15 14:43:10 +0000734 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
735 << node.name()
736 << " Type: " << node.type()
737 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100738 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100739 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100740 << " Input shape: " << input->info()->tensor_shape()
741 << " Weights shape: " << weights->info()->tensor_shape()
742 << " Output shape: " << output->info()->tensor_shape()
743 << std::endl);
744
745 return std::move(func);
746}
747
Manuel Bottini5209be52019-02-13 16:34:56 +0000748/** Create a backend generate proposals layer function
749 *
750 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
751 * @tparam TargetInfo Target-specific information
752 *
753 * @param[in] node Node to create the backend function for
754 * @param[in] ctx Graph context
755 *
756 * @return Backend generate proposals layer function
757 */
758template <typename GenerateProposalsLayerFunction, typename TargetInfo>
759std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
760{
761 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
762
763 // Extract IO and info
764 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
765 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
766 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
767 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
768 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
769 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
770 const GenerateProposalsInfo info = node.info();
771
772 ARM_COMPUTE_ERROR_ON(scores == nullptr);
773 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
774 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
775 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
776 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
777
778 // Create and configure function
779 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
780 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
781
782 // Log info
783 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
784 << " Target " << TargetInfo::TargetType
785 << " Data Type: " << scores->info()->data_type()
786 << " Scores shape: " << scores->info()->tensor_shape()
787 << " Deltas shape: " << deltas->info()->tensor_shape()
788 << " Anchors shape: " << anchors->info()->tensor_shape()
789 << " Proposals shape: " << proposals->info()->tensor_shape()
790 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
791 << " Scores Out shape: " << scores_out->info()->tensor_shape()
792 << std::endl);
793
794 return std::move(func);
795}
796
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100797/** Create a backend normalization layer function
798 *
799 * @tparam NormalizationLayerFunction Backend normalization function
800 * @tparam TargetInfo Target-specific information
801 *
802 * @param[in] node Node to create the backend function for
803 * @param[in] ctx Graph context
804 *
805 * @return Backend normalization layer function
806 */
807template <typename NormalizationLayerFunction, typename TargetInfo>
808std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
809{
810 ARM_COMPUTE_UNUSED(ctx);
811
812 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
813
814 // Extract IO and info
815 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
816 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
817 const NormalizationLayerInfo norm_info = node.normalization_info();
818 ARM_COMPUTE_ERROR_ON(input == nullptr);
819 ARM_COMPUTE_ERROR_ON(output == nullptr);
820
821 // Create and configure function
822 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
823 func->configure(input, output, norm_info);
824
825 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000826 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
827 << node.name()
828 << " Type: " << node.type()
829 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100830 << " Data Type: " << input->info()->data_type()
831 << " Input shape: " << input->info()->tensor_shape()
832 << " Output shape: " << output->info()->tensor_shape()
833 << " Normalization info: " << norm_info.type()
834 << std::endl);
835
836 return std::move(func);
837}
838
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100839/** Create a backend normalize planar YUV layer function
840 *
841 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
842 * @tparam TargetInfo Target-specific information
843 *
844 * @param[in] node Node to create the backend function for
845 *
846 * @return Backend normalize plnar YUV layer function
847 */
848template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
849std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
850{
851 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
852
853 // Extract IO and info
854 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
855 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
856 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
857 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
858 ARM_COMPUTE_ERROR_ON(input == nullptr);
859 ARM_COMPUTE_ERROR_ON(mean == nullptr);
860 ARM_COMPUTE_ERROR_ON(std == nullptr);
861 ARM_COMPUTE_ERROR_ON(output == nullptr);
862
863 // Create and configure function
864 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
865 func->configure(input, output, mean, std);
866
867 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000868 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
869 << node.name()
870 << " Type: " << node.type()
871 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100872 << " Data Type: " << input->info()->data_type()
873 << " Shape: " << input->info()->tensor_shape()
874 << std::endl);
875
876 return std::move(func);
877}
878
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100879/** Create a backend pad layer function
880 *
881 * @tparam PadLayerFunction Backend pad function
882 * @tparam TargetInfo Target-specific information
883 *
884 * @param[in] node Node to create the backend function for
885 *
886 * @return Backend pad layer function
887 */
888template <typename PadLayerFunction, typename TargetInfo>
889std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
890{
891 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
892
893 // Extract IO and info
894 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
895 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
896 const PaddingList &padding = node.padding();
897 ARM_COMPUTE_ERROR_ON(input == nullptr);
898 ARM_COMPUTE_ERROR_ON(output == nullptr);
899
900 // Create and configure function
901 auto func = support::cpp14::make_unique<PadLayerFunction>();
902 func->configure(input, output, padding);
903
904 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000905 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
906 << node.name()
907 << " Type: " << node.type()
908 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100909 << " Data Type: " << input->info()->data_type()
910 << " Input shape: " << input->info()->tensor_shape()
911 << " Output shape: " << output->info()->tensor_shape()
912 << std::endl);
913
914 return std::move(func);
915}
916
Georgios Pinitas57c48242018-08-02 13:41:49 +0100917/** Create a backend permute layer function
918 *
919 * @tparam PermuteLayerFunction Backend permute function
920 * @tparam TargetInfo Target-specific information
921 *
922 * @param[in] node Node to create the backend function for
923 *
924 * @return Backend permute layer function
925 */
926template <typename PermuteLayerFunction, typename TargetInfo>
927std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
928{
929 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
930
931 // Extract IO and info
932 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
933 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
934 const PermutationVector &perm = node.permutation_vector();
935 ARM_COMPUTE_ERROR_ON(input == nullptr);
936 ARM_COMPUTE_ERROR_ON(output == nullptr);
937
938 // Create and configure function
939 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
940 func->configure(input, output, perm);
941
942 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000943 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
944 << node.name()
945 << " Type: " << node.type()
946 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +0100947 << " Data Type: " << input->info()->data_type()
948 << " Input shape: " << input->info()->tensor_shape()
949 << " Output shape: " << output->info()->tensor_shape()
950 << " Permutation vector: " << perm
951 << std::endl);
952
953 return std::move(func);
954}
955
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100956/** Create a backend pooling layer function
957 *
958 * @tparam PoolingLayerFunction Backend pooling function
959 * @tparam TargetInfo Target-specific information
960 *
961 * @param[in] node Node to create the backend function for
962 *
963 * @return Backend pooling layer function
964 */
965template <typename PoolingLayerFunction, typename TargetInfo>
966std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
967{
968 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
969
970 // Extract IO and info
971 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
972 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
973 const PoolingLayerInfo pool_info = node.pooling_info();
974 ARM_COMPUTE_ERROR_ON(input == nullptr);
975 ARM_COMPUTE_ERROR_ON(output == nullptr);
976
977 // Create and configure function
978 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
979 func->configure(input, output, pool_info);
980
981 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000982 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
983 << node.name()
984 << " Type: " << node.type()
985 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100986 << " Data Type: " << input->info()->data_type()
987 << " Input shape: " << input->info()->tensor_shape()
988 << " Output shape: " << output->info()->tensor_shape()
989 << " Pooling info: " << pool_info.pool_type()
990 << std::endl);
991
992 return std::move(func);
993}
994
Pablo Tello32521432018-11-15 14:43:10 +0000995/** Create a backend priorbox layer function
996 *
997 * @tparam PriorBoxLayerFunction Backend priorbox function
998 * @tparam TargetInfo Target-specific information
999 *
1000 * @param[in] node Node to create the backend function for
1001 *
1002 * @return Backend priorbox layer function
1003 */
1004template <typename PriorBoxLayerFunction, typename TargetInfo>
1005std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1006{
1007 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1008
1009 // Extract IO and info
1010 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1011 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1012 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1013 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1014 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1015 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1016 ARM_COMPUTE_ERROR_ON(output == nullptr);
1017
1018 // Create and configure function
1019 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1020 func->configure(input0, input1, output, prior_info);
1021
1022 // Log info
1023 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1024 << node.name()
1025 << " Type: " << node.type()
1026 << " Target: " << TargetInfo::TargetType
1027 << " Data Type: " << input0->info()->data_type()
1028 << " Input0 shape: " << input0->info()->tensor_shape()
1029 << " Input1 shape: " << input1->info()->tensor_shape()
1030 << " Output shape: " << output->info()->tensor_shape()
1031 << " PriorBoxLayer info: " << prior_info
1032 << std::endl);
1033
1034 return std::move(func);
1035}
1036
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001037/** Create a backend reorg layer function
1038 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001039 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001040 * @tparam TargetInfo Target-specific information
1041 *
1042 * @param[in] node Node to create the backend function for
1043 *
1044 * @return Backend reshape layer function
1045 */
1046template <typename ReorgLayerFunction, typename TargetInfo>
1047std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
1048{
1049 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1050
1051 // Extract IO and info
1052 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1053 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1054 ARM_COMPUTE_ERROR_ON(input == nullptr);
1055 ARM_COMPUTE_ERROR_ON(output == nullptr);
1056
1057 // Create and configure function
1058 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
1059 func->configure(input, output, node.stride());
1060
1061 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001062 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1063 << node.name()
1064 << " Type: " << node.type()
1065 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001066 << " Data Type: " << input->info()->data_type()
1067 << " Input shape: " << input->info()->tensor_shape()
1068 << " Output shape: " << output->info()->tensor_shape()
1069 << std::endl);
1070
1071 return std::move(func);
1072}
1073
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001074/** Create a backend reshape layer function
1075 *
1076 * @tparam ReshapeLayerFunction Backend reshape function
1077 * @tparam TargetInfo Target-specific information
1078 *
1079 * @param[in] node Node to create the backend function for
1080 *
1081 * @return Backend reshape layer function
1082 */
1083template <typename ReshapeLayerFunction, typename TargetInfo>
1084std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1085{
1086 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1087
1088 // Extract IO and info
1089 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1090 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1091 ARM_COMPUTE_ERROR_ON(input == nullptr);
1092 ARM_COMPUTE_ERROR_ON(output == nullptr);
1093
1094 // Create and configure function
1095 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1096 func->configure(input, output);
1097
1098 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001099 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1100 << node.name()
1101 << " Type: " << node.type()
1102 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001103 << " Data Type: " << input->info()->data_type()
1104 << " Input shape: " << input->info()->tensor_shape()
1105 << " Output shape: " << output->info()->tensor_shape()
1106 << std::endl);
1107
1108 return std::move(func);
1109}
1110
1111/** Create a backend resize layer function
1112 *
1113 * @tparam ResizeLayerFunction Backend resize function
1114 * @tparam TargetInfo Target-specific information
1115 *
1116 * @param[in] node Node to create the backend function for
1117 *
1118 * @return Backend resize layer function
1119 */
1120template <typename ResizeLayerFunction, typename TargetInfo>
1121std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1122{
1123 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1124
1125 // Extract IO and info
1126 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1127 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1128 ARM_COMPUTE_ERROR_ON(input == nullptr);
1129 ARM_COMPUTE_ERROR_ON(output == nullptr);
1130 const InterpolationPolicy policy = node.policy();
1131
1132 // Create and configure function
1133 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1134 func->configure(input, output, policy, BorderMode::CONSTANT);
1135
1136 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001137 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1138 << node.name()
1139 << " Type: " << node.type()
1140 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001141 << " Data Type: " << input->info()->data_type()
1142 << " Input shape: " << input->info()->tensor_shape()
1143 << " Output shape: " << output->info()->tensor_shape()
1144 << " Interpolation: " << policy
1145 << std::endl);
1146
1147 return std::move(func);
1148}
1149
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001150/** Create a backend ROI align layer function
1151 *
1152 * @tparam ROIAlignLayerFunction ROI Align function
1153 * @tparam TargetInfo Target-specific information
1154 *
1155 * @param[in] node Node to create the backend function for
1156 *
1157 * @return ROI Align layer function
1158 */
1159template <typename ROIAlignLayerFunction, typename TargetInfo>
1160std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1161{
1162 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1163
1164 // Extract IO and info
1165 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1166 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1167 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1168 ARM_COMPUTE_ERROR_ON(input == nullptr);
1169 ARM_COMPUTE_ERROR_ON(output == nullptr);
1170 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1171
1172 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1173
1174 // Create and configure function
1175 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1176
1177 func->configure(input, rois, output, pool_info);
1178
1179 // Log info
1180 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
1181 << " Target " << TargetInfo::TargetType
1182 << " Data Type: " << input->info()->data_type()
1183 << " Input shape: " << input->info()->tensor_shape()
1184 << " Output shape: " << output->info()->tensor_shape()
1185 << " ROIs shape: " << rois->info()->tensor_shape()
1186 << " ROIPooling width: " << pool_info.pooled_width()
1187 << " ROIPooling height: " << pool_info.pooled_height()
1188 << std::endl);
1189
1190 return std::move(func);
1191}
1192
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001193/** Create a backend slice layer function
1194 *
1195 * @tparam SliceLayerFunction Backend slice function
1196 * @tparam TargetInfo Target-specific information
1197 *
1198 * @param[in] node Node to create the backend function for
1199 *
1200 * @return Backend slice layer function
1201 */
1202template <typename SliceLayerFunction, typename TargetInfo>
1203std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1204{
1205 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1206
1207 // Extract IO and info
1208 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1209 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1210 ARM_COMPUTE_ERROR_ON(input == nullptr);
1211 ARM_COMPUTE_ERROR_ON(output == nullptr);
1212
1213 // Create and configure function
1214 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1215 func->configure(input, output, node.starts(), node.ends());
1216
1217 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001218 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1219 << node.name()
1220 << " Type: " << node.type()
1221 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001222 << " Data Type: " << input->info()->data_type()
1223 << " Input shape: " << input->info()->tensor_shape()
1224 << " Output shape: " << output->info()->tensor_shape()
1225 << std::endl);
1226
1227 return std::move(func);
1228}
1229
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001230/** Create a backend softmax layer function
1231 *
1232 * @tparam SoftmaxLayerFunction Backend softmax function
1233 * @tparam TargetInfo Target-specific information
1234 *
1235 * @param[in] node Node to create the backend function for
1236 * @param[in] ctx Graph context
1237 *
1238 * @return Backend softmax layer function
1239 */
1240template <typename SoftmaxLayerFunction, typename TargetInfo>
1241std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1242{
1243 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1244
1245 // Extract IO and info
1246 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1247 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1248 const float beta = node.beta();
1249 ARM_COMPUTE_ERROR_ON(input == nullptr);
1250 ARM_COMPUTE_ERROR_ON(output == nullptr);
1251
1252 // Create and configure function
1253 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1254 func->configure(input, output, beta);
1255
1256 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001257 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1258 << node.name()
1259 << " Type: " << node.type()
1260 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001261 << " Data Type: " << input->info()->data_type()
1262 << " Input shape: " << input->info()->tensor_shape()
1263 << " Output shape: " << output->info()->tensor_shape()
1264 << std::endl);
1265
1266 return std::move(func);
1267}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001268/** Create a backend Upsample layer function
1269 *
1270 * @tparam UpsampleLayerFunction Backend Upsample function
1271 * @tparam TargetInfo Target-specific information
1272 *
1273 * @param[in] node Node to create the backend function for
1274 * @param[in] ctx Graph context
1275 *
1276 * @return Backend Upsample layer function
1277 */
1278template <typename UpsampleLayerFunction, typename TargetInfo>
1279std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1280{
1281 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1282
1283 // Extract IO and info
1284 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1285 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1286 const Size2D info = node.info();
1287 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1288 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1289 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1290 ARM_COMPUTE_ERROR_ON(input == nullptr);
1291 ARM_COMPUTE_ERROR_ON(output == nullptr);
1292
1293 // Create and configure function
1294 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1295 func->configure(input, output, info, upsampling_policy);
1296
1297 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001298 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1299 << node.name()
1300 << " Type: " << node.type()
1301 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001302 << " Data Type: " << input->info()->data_type()
1303 << " Input shape: " << input->info()->tensor_shape()
1304 << " Output shape: " << output->info()->tensor_shape()
1305 << " Strides: " << info
1306 << " Upsampling policy: " << upsampling_policy
1307 << std::endl);
1308
1309 return std::move(func);
1310}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001311/** Create a backend YOLO layer function
1312 *
1313 * @tparam YoloLayerFunction Backend YOLO function
1314 * @tparam TargetInfo Target-specific information
1315 *
1316 * @param[in] node Node to create the backend function for
1317 * @param[in] ctx Graph context
1318 *
1319 * @return Backend YOLO layer function
1320 */
1321template <typename YOLOlayerFunction, typename TargetInfo>
1322std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1323{
1324 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1325
1326 // Extract IO and info
1327 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1328 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1329 const ActivationLayerInfo act_info = node.activation_info();
1330 const int32_t num_classes = node.num_classes();
1331 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1332 ARM_COMPUTE_ERROR_ON(input == nullptr);
1333 ARM_COMPUTE_ERROR_ON(output == nullptr);
1334
1335 // Create and configure function
1336 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1337 func->configure(input, output, act_info, num_classes);
1338
1339 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001340 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1341 << node.name()
1342 << " Type: " << node.type()
1343 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001344 << " Data Type: " << input->info()->data_type()
1345 << " Input shape: " << input->info()->tensor_shape()
1346 << " Output shape: " << output->info()->tensor_shape()
1347 << " Activation function: " << act_info.activation()
1348 << " Num classes: " << num_classes
1349 << std::endl);
1350
1351 return std::move(func);
1352}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001353} // namespace detail
1354} // namespace backends
1355} // namespace graph
1356} // namespace arm_compute
1357
1358#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */