blob: 02bfe9dc229511127437b4a4da572ee6d3970b16 [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"
Georgios Pinitas9e4824c2019-04-12 13:15:58 +010031#include "arm_compute/graph/Utils.h"
giuros01acce5042019-02-21 17:32:34 +000032#include "arm_compute/graph/backends/FusedConvolutionBatchNormalizationFunction.h"
Manuel Bottinibffb41e2019-06-20 16:00:27 +010033#include "arm_compute/graph/backends/FusedDepthwiseConvolutionBatchNormalizationFunction.h"
Georgios Pinitasda2491f2018-06-01 17:49:09 +010034#include "arm_compute/graph/backends/Utils.h"
35#include "arm_compute/graph/nodes/Nodes.h"
36
37#include "arm_compute/core/Error.h"
38#include "arm_compute/core/Helpers.h"
39#include "arm_compute/core/ITensorInfo.h"
40#include "arm_compute/core/utils/misc/Cast.h"
41
42namespace arm_compute
43{
44namespace graph
45{
46namespace backends
47{
48namespace detail
49{
50/** Returns backing tensor of a given tensor
51 *
52 * @tparam TargetInfo Target information
53 *
54 * @param[in] tensor Tensor to extract the backing tensor from
55 *
56 * @return Backing tensor if present else nullptr
57 */
58template <typename TargetInfo>
59typename TargetInfo::TensorType *get_backing_tensor(arm_compute::graph::Tensor *tensor)
60{
61 typename TargetInfo::TensorType *backing_tensor = nullptr;
62 if(tensor != nullptr)
63 {
64 ARM_COMPUTE_ERROR_ON(tensor->desc().target != TargetInfo::TargetType);
65 // Get backing tensor handle
66 ITensorHandle *tensor_handle = tensor->handle();
67 // Get backing tensor
68 backing_tensor = (tensor_handle != nullptr) ? arm_compute::utils::cast::polymorphic_cast<typename TargetInfo::TensorType *>(&tensor_handle->tensor()) : nullptr;
69 }
70
71 return backing_tensor;
72}
73
74template <typename TargetInfo>
75void validate_node(const INode &node, size_t num_expected_inputs, size_t num_expected_outputs)
76{
77 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating " << node.type()
Pablo Tello32521432018-11-15 14:43:10 +000078 << " Target: " << TargetInfo::TargetType
79 << " ID: " << node.id()
80 << node.name()
Georgios Pinitasda2491f2018-06-01 17:49:09 +010081 << std::endl);
82
83 ARM_COMPUTE_ERROR_ON(TargetInfo::TargetType != node.assigned_target());
84 ARM_COMPUTE_ERROR_ON(node.num_inputs() != num_expected_inputs);
85 ARM_COMPUTE_ERROR_ON(node.num_outputs() != num_expected_outputs);
Michalis Spyrou6bff1952019-10-02 17:22:11 +010086 ARM_COMPUTE_UNUSED(node, num_expected_inputs, num_expected_outputs);
Georgios Pinitasda2491f2018-06-01 17:49:09 +010087}
88
89/** Creates a backend activation layer function
90 *
91 * @tparam ActivationLayerFunction Backend activation function
92 * @tparam TargetInfo Target-specific information
93 *
94 * @param[in] node Node to create the backend function for
95 *
96 * @return Backend activation layer function
97 */
98template <typename ActivationLayerFunction, typename TargetInfo>
99std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
100{
101 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
102
103 // Extract IO and info
104 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
105 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
106 const ActivationLayerInfo act_info = node.activation_info();
107
108 // Create function
109 auto func = support::cpp14::make_unique<ActivationLayerFunction>();
110 func->configure(input, output, act_info);
111
Pablo Tello32521432018-11-15 14:43:10 +0000112 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
113 << node.name()
114 << " Type: " << node.type()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000115 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100116 << " Data Type: " << input->info()->data_type()
117 << " Shape: " << input->info()->tensor_shape()
118 << " Activation function: " << act_info.activation()
119 << " a: " << act_info.a()
120 << " b: " << act_info.b()
121 << " InPlace : " << is_in_place_operation(input, output)
122 << std::endl);
123
124 return std::move(func);
125}
126
127/** Create a backend batch normalization layer function
128 *
129 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
130 * @tparam TargetInfo Target-specific information
131 *
132 * @param[in] node Node to create the backend function for
133 *
134 * @return Backend batch normalization layer function
135 */
136template <typename BatchNormalizationLayerFunction, typename TargetInfo>
137std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
138{
139 validate_node<TargetInfo>(node, 5 /* expected inputs */, 1 /* expected outputs */);
140
141 // Extract IO and info
giuros01acce5042019-02-21 17:32:34 +0000142 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
143 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
144 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(2));
145 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(3));
146 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(4));
147
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100148 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
149 const float epsilon = node.epsilon();
150 const ActivationLayerInfo fused_act = node.fused_activation();
151
152 // Create and configure function
153 auto func = support::cpp14::make_unique<BatchNormalizationLayerFunction>();
154 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
155
156 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000157 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
158 << node.name()
159 << " Type: " << node.type()
160 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100161 << " Data Type: " << input->info()->data_type()
162 << " Shape: " << input->info()->tensor_shape()
163 << " Epsilon: " << epsilon << " "
164 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
Pablo Tello32521432018-11-15 14:43:10 +0000165 << " InPlace: " << is_in_place_operation(input, output)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100166 << std::endl);
167
168 return std::move(func);
169}
170
giuros01acce5042019-02-21 17:32:34 +0000171/** Create a backend batch normalization layer function
172 *
173 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
174 * @tparam TargetInfo Target-specific information
175 *
176 * @param[in] node Node to create the backend function for
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000177 * @param[in] ctx Graph context
giuros01acce5042019-02-21 17:32:34 +0000178 *
179 * @return Backend batch normalization layer function
180 */
181template <typename FusedLayerTypes, typename TargetInfo>
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000182std::unique_ptr<IFunction> create_fused_convolution_batch_normalization_layer(FusedConvolutionBatchNormalizationNode &node, GraphContext &ctx)
giuros01acce5042019-02-21 17:32:34 +0000183{
184 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
185
186 // Extract IO and info
187 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
188 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
189 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
190 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
191 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
192 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
193 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
194
195 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
196
197 const PadStrideInfo conv_info = node.convolution_info();
198 const unsigned int num_groups = node.num_groups();
199 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
200 const ActivationLayerInfo fused_act = node.fused_activation();
201 const float epsilon = node.epsilon();
202
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000203 // Create and configure function (we assume that functions have been validated before creation)
204 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
205 std::unique_ptr<IFunction> func;
206 std::string func_name;
207
208 using FType = FusedConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>;
209
giuros01acce5042019-02-21 17:32:34 +0000210 // Create and configure function
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000211 std::tie(func, func_name) = create_named_memory_managed_function<FType>(
212 std::string("FusedConvolutionBatchNormalizationLayer"), mm, input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, num_groups, fast_math, fused_act);
giuros01acce5042019-02-21 17:32:34 +0000213
214 // Log info
215 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
216 << node.name()
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100217 << " Type: " << node.type()
218 << " Target: " << TargetInfo::TargetType
219 << " Data Type: " << input->info()->data_type()
220 << " Input shape: " << input->info()->tensor_shape()
221 << " Weights shape: " << weights->info()->tensor_shape()
222 << " Output shape: " << output->info()->tensor_shape()
223 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
224 << std::endl);
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000225 return func;
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100226}
227
228/** Create a backend fused depthwise convolution batch normalization layer function
229 *
230 * @tparam FusedLayerTypes Fused layer types
231 * @tparam TargetInfo Target-specific information
232 *
233 * @param[in] node Node to create the backend function for
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000234 * @param[in] ctx Graph context
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100235 *
236 * @return Backend fused depthwise convolution batch normalization layer function
237 */
238template <typename FusedLayerTypes, typename TargetInfo>
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000239std::unique_ptr<IFunction> create_fused_depthwise_convolution_batch_normalization_layer(FusedDepthwiseConvolutionBatchNormalizationNode &node, GraphContext &ctx)
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100240{
241 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
242
243 // Extract IO and info
244 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
245 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
246 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
247 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
248 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
249 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
250 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
251
252 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
253
254 const PadStrideInfo conv_info = node.convolution_info();
255 const unsigned int depth_multiplier = node.depth_multiplier();
256 const ActivationLayerInfo fused_act = node.fused_activation();
257 const float epsilon = node.epsilon();
258
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000259 // Create and configure function (we assume that functions have been validated before creation)
260 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
261 std::unique_ptr<IFunction> func;
262 std::string func_name;
263
264 using FType = FusedDepthwiseConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>;
265
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100266 // Create and configure function
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000267 std::tie(func, func_name) = create_named_memory_managed_function<FType>(
268 std::string("FusedDepthwiseConvolutionBatchNormalizationLayer"), mm, input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, depth_multiplier, fused_act);
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100269
270 // Log info
271 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
272 << node.name()
273 << " Type: " << node.type()
giuros01acce5042019-02-21 17:32:34 +0000274 << " Target: " << TargetInfo::TargetType
275 << " Data Type: " << input->info()->data_type()
276 << " Input shape: " << input->info()->tensor_shape()
277 << " Weights shape: " << weights->info()->tensor_shape()
278 << " Output shape: " << output->info()->tensor_shape()
279 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
280 << std::endl);
Gian Marco Iodice5dea19e2019-11-08 12:13:48 +0000281 return func;
giuros01acce5042019-02-21 17:32:34 +0000282}
283
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100284/** Create a backend bounding box transform layer function
285 *
286 * @tparam BoundingBoxTransformLayerFunction Backend bounding box transform function
287 * @tparam TargetInfo Target-specific information
288 *
289 * @param[in] node Node to create the backend function for
290 *
291 * @return Backend bounding box transform layer function
292 */
293template <typename BoundingBoxTransformLayerFunction, typename TargetInfo>
294std::unique_ptr<IFunction> create_bounding_box_transform_layer(BoundingBoxTransformLayerNode &node)
295{
296 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
297
298 // Extract IO and info
299 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
300 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
301 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
302 const BoundingBoxTransformInfo bbox_info = node.info();
303
304 // Create and configure function
305 auto func = support::cpp14::make_unique<BoundingBoxTransformLayerFunction>();
306 func->configure(input, output, deltas, bbox_info);
307
308 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000309 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
310 << node.name()
311 << " Type: " << node.type()
312 << " Target: " << TargetInfo::TargetType
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100313 << " Data Type: " << input->info()->data_type()
314 << " Shape: " << input->info()->tensor_shape()
315 << " BoundingBox Info img W: " << bbox_info.img_width() << " "
316 << " BoundingBox Info img H: " << bbox_info.img_height() << " "
317 << std::endl);
318
319 return std::move(func);
320}
321
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100322/** Create a backend channel shuffle layer function
323 *
324 * @tparam ChannelShuffleLayerFunction Backend channel shuffle function
325 * @tparam TargetInfo Target-specific information
326 *
327 * @param[in] node Node to create the backend function for
328 *
329 * @return Backend channel shuffle layer function
330 */
331template <typename ChannelShuffleLayerFunction, typename TargetInfo>
332std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
333{
334 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
335
336 // Extract IO and info
337 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
338 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
339 const unsigned int num_groups = node.num_groups();
340
341 // Create function
342 auto func = support::cpp14::make_unique<ChannelShuffleLayerFunction>();
343 func->configure(input, output, num_groups);
344
Pablo Tello32521432018-11-15 14:43:10 +0000345 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
346 << node.name()
347 << " Type: " << node.type()
348 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100349 << " Data Type: " << input->info()->data_type()
350 << " Shape: " << input->info()->tensor_shape()
351 << " Num groups: " << num_groups
352 << std::endl);
353
354 return std::move(func);
355}
356
Georgios Pinitase2220552018-07-20 13:23:44 +0100357/** Create a backend layer concatenate function
358 *
359 * @tparam ConcatenateLayerFunction Backend concatenate function
360 * @tparam TargetInfo Target-specific information
361 *
362 * @param[in] node Node to create the backend function for
363 *
364 * @return Backend concatenate layer function
365 */
366template <typename ConcatenateLayerFunction, typename TargetInfo>
367std::unique_ptr<arm_compute::IFunction> create_concatenate_layer(ConcatenateLayerNode &node)
368{
369 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Concatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
370 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
371
372 // Return nullptr if depth concatenate is switched off
373 if(!node.is_enabled())
374 {
375 return nullptr;
376 }
377
378 // Extract IO and info
379 std::vector<typename TargetInfo::TensorType *> inputs;
380 for(unsigned int i = 0; i < node.num_inputs(); ++i)
381 {
382 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
383 }
384 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100385 const DataLayout data_layout = node.output(0) != nullptr ? node.output(0)->desc().layout : DataLayout::UNKNOWN;
386 const size_t concat_axis = get_dimension_idx(data_layout, node.concatenation_axis());
Georgios Pinitase2220552018-07-20 13:23:44 +0100387
388 // Create and configure function
389 auto func = support::cpp14::make_unique<ConcatenateLayerFunction>();
390 func->configure(inputs, output, concat_axis);
391
392 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000393 const bool is_quantized = is_data_type_quantized_asymmetric(output->info()->data_type());
394 std::ostringstream qss;
395 if(is_quantized)
396 {
397 qss << " Output QuantInfo: " << output->info()->quantization_info();
398 }
Pablo Tello32521432018-11-15 14:43:10 +0000399 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
400 << node.name()
401 << " Type: " << node.type()
402 << " Target: " << TargetInfo::TargetType
Georgios Pinitase2220552018-07-20 13:23:44 +0100403 << " Data Type: " << output->info()->data_type()
404 << " Shape: " << output->info()->tensor_shape()
405 << " Num Inputs: " << inputs.size()
406 << " Axis: " << concat_axis
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000407 << qss.str()
Georgios Pinitase2220552018-07-20 13:23:44 +0100408 << std::endl);
409
410 return std::move(func);
411}
412
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100413/** Create a backend convolution layer function
414 *
415 * @tparam ConvolutionLayerFunctions Backend convolution functions
416 * @tparam TargetInfo Target-specific information
417 *
418 * @param[in] node Node to create the backend function for
419 * @param[in] ctx Graph context
420 *
421 * @return Backend convolution layer function
422 */
423template <typename ConvolutionLayerFunctions, typename TargetInfo>
424std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
425{
426 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
427
428 // Extract IO and info
429 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
430 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
431 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
432 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
433
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100434 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
435
436 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100437 {
438 biases->info()->set_data_type(DataType::S32);
439 }
440
Georgios Pinitas08346e92018-10-16 19:10:46 +0100441 const PadStrideInfo conv_info = node.convolution_info();
442 const unsigned int num_groups = node.num_groups();
443 const ConvolutionMethod conv_algorithm = node.convolution_method();
444 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
445 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100446
447 // Create and configure function (we assume that functions have been validated before creation)
448 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
449 std::unique_ptr<IFunction> func;
450 std::string func_name;
451
Georgios Pinitase2220552018-07-20 13:23:44 +0100452 if(conv_algorithm == ConvolutionMethod::Winograd)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100453 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100454 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "WinogradConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100455 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::WinogradConvolutionLayer>(
456 std::string("WinogradConvolutionLayer"), mm,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100457 input, weights, biases, output, conv_info, fused_act, fast_math);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100458 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100459 else if(conv_algorithm == ConvolutionMethod::Direct)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100460 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100461 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "DirectConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100462 std::tie(func, func_name) = create_named_function<typename ConvolutionLayerFunctions::DirectConvolutionLayer>(
463 std::string("DirectConvolutionLayer"),
Georgios Pinitas08346e92018-10-16 19:10:46 +0100464 input, weights, biases, output, conv_info, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100465 }
466 else if(conv_algorithm == ConvolutionMethod::GEMM)
467 {
468 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GEMMConvolutionLayer>(
469 std::string("GEMMConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100470 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100471 WeightsInfo(), Size2D(1U, 1U), fused_act, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100472 }
473 else
474 {
475 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GenericConvolutionLayer>(
476 std::string("GenericConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100477 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100478 WeightsInfo(), Size2D(1U, 1U), fused_act, fast_math, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100479 }
480
481 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100482 std::ostringstream qss;
483 if(is_quantized)
484 {
485 qss << " Input QuantInfo: " << input->info()->quantization_info()
486 << " Weights QuantInfo: " << weights->info()->quantization_info()
487 << " Output QuantInfo: " << output->info()->quantization_info();
488 }
Pablo Tello32521432018-11-15 14:43:10 +0000489 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
490 << node.name()
491 << " Type: " << func_name
492 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100493 << " Data Type: " << input->info()->data_type()
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100494 << " Groups: " << num_groups
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100495 << " Input shape: " << input->info()->tensor_shape()
496 << " Weights shape: " << weights->info()->tensor_shape()
497 << " Output shape: " << output->info()->tensor_shape()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000498 << qss.str()
Georgios Pinitas08346e92018-10-16 19:10:46 +0100499 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100500 << std::endl);
501 return func;
502}
503
504/** Create a backend deconvolution layer function
505 *
506 * @tparam DeconvolutionLayerFunction Backend deconvolution function
507 * @tparam TargetInfo Target-specific information
508 *
509 * @param[in] node Node to create the backend function for
510 * @param[in] ctx Graph context
511 *
512 * @return Backend deconvolution layer function
513 */
514template <typename DeconvolutionLayerFunction, typename TargetInfo>
515std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
516{
517 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
518
519 // Extract IO and info
520 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
521 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
522 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
523 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
524
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100525 const PadStrideInfo deconv_info = node.deconvolution_info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100526
527 // Create and configure function (we assume that functions have been validated before creation)
528 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
529 std::unique_ptr<IFunction> func;
530
531 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
532 std::string(), mm,
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100533 input, weights, biases, output, deconv_info);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100534
535 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000536 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
537 << node.name()
538 << " Type: " << node.type()
539 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100540 << " Data Type: " << input->info()->data_type()
541 << " Input shape: " << input->info()->tensor_shape()
542 << " Weights shape: " << weights->info()->tensor_shape()
543 << " Output shape: " << output->info()->tensor_shape()
544 << std::endl);
545 return func;
546}
547
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100548/** Create a backend layer depth-wise convolution function
549 *
550 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
551 * @tparam TargetInfo Target-specific information
552 *
553 * @param[in] node Node to create the backend function for
554 *
555 * @return Backend depth-wise convolution layer function
556 */
Manuel Bottini05069f02019-09-26 17:18:26 +0100557template <typename DepthwiseConvolutionLayer, typename TargetInfo>
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100558std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
559{
560 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
561
562 // Extract IO and info
563 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
564 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
565 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
566 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
567
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100568 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
569
570 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100571 {
572 biases->info()->set_data_type(DataType::S32);
573 }
574
Manuel Bottini05069f02019-09-26 17:18:26 +0100575 const PadStrideInfo conv_info = node.convolution_info();
576 const unsigned int depth_multiplier = node.depth_multiplier();
577 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100578
579 // Create and configure function (we assume that functions have been validated before creation)
580 std::unique_ptr<IFunction> func;
581 std::string func_name;
Manuel Bottini05069f02019-09-26 17:18:26 +0100582
583 std::tie(func, func_name) = create_named_function<DepthwiseConvolutionLayer>(
584 std::string("DepthwiseConvolutionLayer"),
585 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100586
587 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100588 std::ostringstream qss;
589 if(is_quantized)
590 {
591 qss << " Input QuantInfo: " << input->info()->quantization_info()
592 << " Weights QuantInfo: " << weights->info()->quantization_info()
593 << " Output QuantInfo: " << output->info()->quantization_info();
594 }
Pablo Tello32521432018-11-15 14:43:10 +0000595 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
596 << node.name()
597 << " Type: " << func_name
598 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100599 << " Data Type: " << input->info()->data_type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100600 << " Input shape: " << input->info()->tensor_shape()
601 << " Weights shape: " << weights->info()->tensor_shape()
602 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000603 << " Depth multiplier: " << depth_multiplier
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000604 << qss.str()
Georgios Pinitas60e98252018-10-22 16:17:20 +0100605 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100606 << std::endl);
607 return func;
608}
609
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000610/** Create a backend detection output layer function
611 *
612 * @tparam DetectionOutputLayer Function Backend detection output function
613 * @tparam TargetInfo Target-specific information
614 *
615 * @param[in] node Node to create the backend function for
616 *
617 * @return Backend detection output layer function
618 */
619template <typename DetectionOutputLayerFunction, typename TargetInfo>
620std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
621{
622 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
623
624 // Extract IO and info
625 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
626 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
627 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
628 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
629 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
630
631 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
632 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
633 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
634 ARM_COMPUTE_ERROR_ON(output == nullptr);
635
636 // Create and configure function
637 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
638 func->configure(input0, input1, input2, output, detect_info);
639
640 // Log info
641 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
642 << node.name()
643 << " Type: " << node.type()
644 << " Target: " << TargetInfo::TargetType
645 << " Data Type: " << input0->info()->data_type()
646 << " Input0 shape: " << input0->info()->tensor_shape()
647 << " Input1 shape: " << input1->info()->tensor_shape()
648 << " Input2 shape: " << input2->info()->tensor_shape()
649 << " Output shape: " << output->info()->tensor_shape()
650 << " DetectionOutputLayer info: " << detect_info
651 << std::endl);
652
653 return std::move(func);
654}
Isabella Gottardia7acb3c2019-01-08 13:48:44 +0000655
656/** Create a backend detection post process layer function
657 *
658 * @tparam DetectionPostProcessLayerFunction Backend detection output function
659 * @tparam TargetInfo Target-specific information
660 *
661 * @param[in] node Node to create the backend function for
662 *
663 * @return Backend detection post process layer function
664 */
665template <typename DetectionPostProcessLayerFunction, typename TargetInfo>
666std::unique_ptr<IFunction> create_detection_post_process_layer(DetectionPostProcessLayerNode &node)
667{
668 validate_node<TargetInfo>(node, 3 /* expected inputs */, 4 /* expected outputs */);
669
670 // Extract IO and info
671 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
672 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
673 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
674 typename TargetInfo::TensorType *output0 = get_backing_tensor<TargetInfo>(node.output(0));
675 typename TargetInfo::TensorType *output1 = get_backing_tensor<TargetInfo>(node.output(1));
676 typename TargetInfo::TensorType *output2 = get_backing_tensor<TargetInfo>(node.output(2));
677 typename TargetInfo::TensorType *output3 = get_backing_tensor<TargetInfo>(node.output(3));
678 const DetectionPostProcessLayerInfo detect_info = node.detection_post_process_info();
679
680 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
681 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
682 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
683 ARM_COMPUTE_ERROR_ON(output0 == nullptr);
684 ARM_COMPUTE_ERROR_ON(output1 == nullptr);
685 ARM_COMPUTE_ERROR_ON(output2 == nullptr);
686 ARM_COMPUTE_ERROR_ON(output3 == nullptr);
687
688 // Create and configure function
689 auto func = support::cpp14::make_unique<DetectionPostProcessLayerFunction>();
690 func->configure(input0, input1, input2, output0, output1, output2, output3, detect_info);
691
692 // Log info
693 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
694 << node.name()
695 << " Type: " << node.type()
696 << " Target: " << TargetInfo::TargetType
697 << " Data Type: " << input0->info()->data_type()
698 << " Input0 shape: " << input0->info()->tensor_shape()
699 << " Input1 shape: " << input1->info()->tensor_shape()
700 << " Input2 shape: " << input2->info()->tensor_shape()
701 << " Output0 shape: " << output0->info()->tensor_shape()
702 << " Output1 shape: " << output1->info()->tensor_shape()
703 << " Output2 shape: " << output2->info()->tensor_shape()
704 << " Output3 shape: " << output3->info()->tensor_shape()
705 << " DetectionPostProcessLayer info: " << detect_info
706 << std::endl);
707
708 return std::move(func);
709}
710
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100711/** Create a backend element-wise operation layer function
712 *
713 * @tparam EltwiseFunctions Backend element-wise function
714 * @tparam TargetInfo Target-specific information
715 *
716 * @param[in] node Node to create the backend function for
717 *
718 * @return Backend element-wise operation layer function
719 */
720template <typename EltwiseFunctions, typename TargetInfo>
721std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
722{
723 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
724
725 // Extract IO and info
726 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
727 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
728 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
729 const EltwiseOperation eltwise_op = node.eltwise_operation();
730 const ConvertPolicy convert_policy = node.convert_policy();
731 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
732 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
733 ARM_COMPUTE_ERROR_ON(output == nullptr);
734
735 std::unique_ptr<IFunction> func = nullptr;
736 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100737 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100738 {
739 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
740 std::string("ArithmeticAddition"),
741 input1, input2, output, convert_policy);
742 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100743 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100744 {
745 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
746 std::string("ArithmeticSubtraction"),
747 input1, input2, output, convert_policy);
748 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100749 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100750 {
751 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
752 std::string("PixelWiseMultiplication"),
753 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
754 }
755 else
756 {
757 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
758 }
759
760 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000761 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
762 << node.name()
763 << " Type: " << node.type()
764 << " Target: " << TargetInfo::TargetType
765 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100766 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000767 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100768 << std::endl);
769
770 return func;
771}
772
773/** Create a backend flatten layer function
774 *
775 * @tparam FlattenLayerFunction Backend flatten function
776 * @tparam TargetInfo Target-specific information
777 *
778 * @param[in] node Node to create the backend function for
779 *
780 * @return Backend flatten layer function
781 */
782template <typename FlattenLayerFunction, typename TargetInfo>
783std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
784{
785 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
786
787 // Extract IO and info
788 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
789 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
790
Georgios Pinitase2220552018-07-20 13:23:44 +0100791 ARM_COMPUTE_ERROR_ON(input == nullptr);
792 ARM_COMPUTE_ERROR_ON(output == nullptr);
793
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100794 // Create and configure function
795 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
796 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100797
798 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000799 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
800 << node.name()
801 << " Type: " << node.type()
802 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100803 << " Data Type: " << input->info()->data_type()
804 << " Input shape: " << input->info()->tensor_shape()
805 << " Output shape: " << output->info()->tensor_shape()
806 << std::endl);
807
808 return std::move(func);
809}
810
811/** Create a backend fully connected layer function
812 *
813 * @tparam FullyConnectedLayerFunction Backend fully-connected function
814 * @tparam TargetInfo Target-specific information
815 *
816 * @param[in] node Node to create the backend function for
817 * @param[in] ctx Graph context
818 *
819 * @return Backend fully connected layer function
820 */
821template <typename FullyConnectedLayerFunction, typename TargetInfo>
822std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
823{
824 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
825
826 // Extract IO and info
827 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
828 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
829 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
830 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100831 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100832
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100833 ARM_COMPUTE_ERROR_ON(input == nullptr);
834 ARM_COMPUTE_ERROR_ON(weights == nullptr);
835 ARM_COMPUTE_ERROR_ON(output == nullptr);
836
Georgios Pinitase2220552018-07-20 13:23:44 +0100837 // Create and configure function
Michalis Spyrou1a569a32019-09-10 17:20:34 +0100838 auto wm = get_weights_manager(ctx, TargetInfo::TargetType);
839 auto mm = get_memory_manager(ctx, TargetInfo::TargetType);
840 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(mm, wm.get());
Georgios Pinitase2220552018-07-20 13:23:44 +0100841 func->configure(input, weights, biases, output, fc_info);
842
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100843 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
844
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100845 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100846 std::ostringstream qss;
847 if(is_quantized)
848 {
849 qss << " Input QuantInfo: " << input->info()->quantization_info()
850 << " Weights QuantInfo: " << weights->info()->quantization_info()
851 << " Output QuantInfo: " << output->info()->quantization_info();
852 }
Pablo Tello32521432018-11-15 14:43:10 +0000853 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
854 << node.name()
855 << " Type: " << node.type()
856 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100857 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100858 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100859 << " Input shape: " << input->info()->tensor_shape()
860 << " Weights shape: " << weights->info()->tensor_shape()
861 << " Output shape: " << output->info()->tensor_shape()
862 << std::endl);
863
864 return std::move(func);
865}
866
Manuel Bottini5209be52019-02-13 16:34:56 +0000867/** Create a backend generate proposals layer function
868 *
869 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
870 * @tparam TargetInfo Target-specific information
871 *
872 * @param[in] node Node to create the backend function for
873 * @param[in] ctx Graph context
874 *
875 * @return Backend generate proposals layer function
876 */
877template <typename GenerateProposalsLayerFunction, typename TargetInfo>
878std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
879{
880 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
881
882 // Extract IO and info
883 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
884 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
885 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
886 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
887 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
888 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
889 const GenerateProposalsInfo info = node.info();
890
891 ARM_COMPUTE_ERROR_ON(scores == nullptr);
892 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
893 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
894 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
895 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
896
897 // Create and configure function
898 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
899 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
900
901 // Log info
902 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
903 << " Target " << TargetInfo::TargetType
904 << " Data Type: " << scores->info()->data_type()
905 << " Scores shape: " << scores->info()->tensor_shape()
906 << " Deltas shape: " << deltas->info()->tensor_shape()
907 << " Anchors shape: " << anchors->info()->tensor_shape()
908 << " Proposals shape: " << proposals->info()->tensor_shape()
909 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
910 << " Scores Out shape: " << scores_out->info()->tensor_shape()
911 << std::endl);
912
913 return std::move(func);
914}
915
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100916/** Create a backend normalization layer function
917 *
918 * @tparam NormalizationLayerFunction Backend normalization function
919 * @tparam TargetInfo Target-specific information
920 *
921 * @param[in] node Node to create the backend function for
922 * @param[in] ctx Graph context
923 *
924 * @return Backend normalization layer function
925 */
926template <typename NormalizationLayerFunction, typename TargetInfo>
927std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
928{
929 ARM_COMPUTE_UNUSED(ctx);
930
931 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
932
933 // Extract IO and info
934 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
935 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
936 const NormalizationLayerInfo norm_info = node.normalization_info();
937 ARM_COMPUTE_ERROR_ON(input == nullptr);
938 ARM_COMPUTE_ERROR_ON(output == nullptr);
939
940 // Create and configure function
941 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
942 func->configure(input, output, norm_info);
943
944 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000945 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
946 << node.name()
947 << " Type: " << node.type()
948 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100949 << " Data Type: " << input->info()->data_type()
950 << " Input shape: " << input->info()->tensor_shape()
951 << " Output shape: " << output->info()->tensor_shape()
952 << " Normalization info: " << norm_info.type()
953 << std::endl);
954
955 return std::move(func);
956}
957
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100958/** Create a backend normalize planar YUV layer function
959 *
960 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
961 * @tparam TargetInfo Target-specific information
962 *
963 * @param[in] node Node to create the backend function for
964 *
965 * @return Backend normalize plnar YUV layer function
966 */
967template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
968std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
969{
970 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
971
972 // Extract IO and info
973 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
974 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
975 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
976 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
977 ARM_COMPUTE_ERROR_ON(input == nullptr);
978 ARM_COMPUTE_ERROR_ON(mean == nullptr);
979 ARM_COMPUTE_ERROR_ON(std == nullptr);
980 ARM_COMPUTE_ERROR_ON(output == nullptr);
981
982 // Create and configure function
983 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
984 func->configure(input, output, mean, std);
985
986 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000987 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
988 << node.name()
989 << " Type: " << node.type()
990 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100991 << " Data Type: " << input->info()->data_type()
992 << " Shape: " << input->info()->tensor_shape()
993 << std::endl);
994
995 return std::move(func);
996}
997
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100998/** Create a backend pad layer function
999 *
1000 * @tparam PadLayerFunction Backend pad function
1001 * @tparam TargetInfo Target-specific information
1002 *
1003 * @param[in] node Node to create the backend function for
1004 *
1005 * @return Backend pad layer function
1006 */
1007template <typename PadLayerFunction, typename TargetInfo>
1008std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
1009{
1010 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1011
1012 // Extract IO and info
1013 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1014 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1015 const PaddingList &padding = node.padding();
1016 ARM_COMPUTE_ERROR_ON(input == nullptr);
1017 ARM_COMPUTE_ERROR_ON(output == nullptr);
1018
1019 // Create and configure function
1020 auto func = support::cpp14::make_unique<PadLayerFunction>();
1021 func->configure(input, output, padding);
1022
1023 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001024 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1025 << node.name()
1026 << " Type: " << node.type()
1027 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +01001028 << " Data Type: " << input->info()->data_type()
1029 << " Input shape: " << input->info()->tensor_shape()
1030 << " Output shape: " << output->info()->tensor_shape()
1031 << std::endl);
1032
1033 return std::move(func);
1034}
1035
Georgios Pinitas57c48242018-08-02 13:41:49 +01001036/** Create a backend permute layer function
1037 *
1038 * @tparam PermuteLayerFunction Backend permute function
1039 * @tparam TargetInfo Target-specific information
1040 *
1041 * @param[in] node Node to create the backend function for
1042 *
1043 * @return Backend permute layer function
1044 */
1045template <typename PermuteLayerFunction, typename TargetInfo>
1046std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
1047{
1048 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1049
1050 // Extract IO and info
1051 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1052 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1053 const PermutationVector &perm = node.permutation_vector();
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<PermuteLayerFunction>();
1059 func->configure(input, output, perm);
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
Georgios Pinitas57c48242018-08-02 13:41:49 +01001066 << " Data Type: " << input->info()->data_type()
1067 << " Input shape: " << input->info()->tensor_shape()
1068 << " Output shape: " << output->info()->tensor_shape()
1069 << " Permutation vector: " << perm
1070 << std::endl);
1071
1072 return std::move(func);
1073}
1074
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001075/** Create a backend pooling layer function
1076 *
1077 * @tparam PoolingLayerFunction Backend pooling function
1078 * @tparam TargetInfo Target-specific information
1079 *
1080 * @param[in] node Node to create the backend function for
1081 *
1082 * @return Backend pooling layer function
1083 */
1084template <typename PoolingLayerFunction, typename TargetInfo>
1085std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
1086{
1087 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1088
1089 // Extract IO and info
1090 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1091 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1092 const PoolingLayerInfo pool_info = node.pooling_info();
1093 ARM_COMPUTE_ERROR_ON(input == nullptr);
1094 ARM_COMPUTE_ERROR_ON(output == nullptr);
1095
1096 // Create and configure function
1097 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
1098 func->configure(input, output, pool_info);
1099
1100 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001101 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1102 << node.name()
1103 << " Type: " << node.type()
1104 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001105 << " Data Type: " << input->info()->data_type()
1106 << " Input shape: " << input->info()->tensor_shape()
1107 << " Output shape: " << output->info()->tensor_shape()
1108 << " Pooling info: " << pool_info.pool_type()
1109 << std::endl);
1110
1111 return std::move(func);
1112}
1113
Pablo Tello32521432018-11-15 14:43:10 +00001114/** Create a backend priorbox layer function
1115 *
1116 * @tparam PriorBoxLayerFunction Backend priorbox function
1117 * @tparam TargetInfo Target-specific information
1118 *
1119 * @param[in] node Node to create the backend function for
1120 *
1121 * @return Backend priorbox layer function
1122 */
1123template <typename PriorBoxLayerFunction, typename TargetInfo>
1124std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1125{
1126 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1127
1128 // Extract IO and info
1129 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1130 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1131 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1132 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1133 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1134 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1135 ARM_COMPUTE_ERROR_ON(output == nullptr);
1136
1137 // Create and configure function
1138 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1139 func->configure(input0, input1, output, prior_info);
1140
1141 // Log info
1142 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1143 << node.name()
1144 << " Type: " << node.type()
1145 << " Target: " << TargetInfo::TargetType
1146 << " Data Type: " << input0->info()->data_type()
1147 << " Input0 shape: " << input0->info()->tensor_shape()
1148 << " Input1 shape: " << input1->info()->tensor_shape()
1149 << " Output shape: " << output->info()->tensor_shape()
1150 << " PriorBoxLayer info: " << prior_info
1151 << std::endl);
1152
1153 return std::move(func);
1154}
1155
Isabella Gottardi3db1ba92019-05-17 12:35:20 +01001156/** Create a backend quantization layer function
1157 *
1158 * @tparam QuantizationLayerFunction Backend quantization function
1159 * @tparam TargetInfo Target-specific information
1160 *
1161 * @param[in] node Node to create the backend function for
1162 *
1163 * @return Backend quantization layer function
1164 */
1165template <typename QuantizationLayerFunction, typename TargetInfo>
1166std::unique_ptr<IFunction> create_quantization_layer(QuantizationLayerNode &node)
1167{
1168 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1169
1170 // Extract IO and info
1171 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1172 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1173 ARM_COMPUTE_ERROR_ON(input == nullptr);
1174 ARM_COMPUTE_ERROR_ON(output == nullptr);
1175
1176 // Create and configure function
1177 auto func = support::cpp14::make_unique<QuantizationLayerFunction>();
1178 func->configure(input, output);
1179
1180 // Log info
1181 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1182 << node.name()
1183 << " Type: " << node.type()
1184 << " Target: " << TargetInfo::TargetType
1185 << " Data Type: " << input->info()->data_type()
1186 << " Input shape: " << input->info()->tensor_shape()
1187 << " Output shape: " << output->info()->tensor_shape()
1188 << std::endl);
1189
1190 return std::move(func);
1191}
1192
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001193/** Create a backend reorg layer function
1194 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001195 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001196 * @tparam TargetInfo Target-specific information
1197 *
1198 * @param[in] node Node to create the backend function for
1199 *
1200 * @return Backend reshape layer function
1201 */
1202template <typename ReorgLayerFunction, typename TargetInfo>
1203std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &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<ReorgLayerFunction>();
1215 func->configure(input, output, node.stride());
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
Gian Marco Iodice23e24792018-09-07 15:32:14 +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 reshape layer function
1231 *
1232 * @tparam ReshapeLayerFunction Backend reshape function
1233 * @tparam TargetInfo Target-specific information
1234 *
1235 * @param[in] node Node to create the backend function for
1236 *
1237 * @return Backend reshape layer function
1238 */
1239template <typename ReshapeLayerFunction, typename TargetInfo>
1240std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1241{
1242 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1243
1244 // Extract IO and info
1245 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1246 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1247 ARM_COMPUTE_ERROR_ON(input == nullptr);
1248 ARM_COMPUTE_ERROR_ON(output == nullptr);
1249
1250 // Create and configure function
1251 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1252 func->configure(input, output);
1253
1254 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001255 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1256 << node.name()
1257 << " Type: " << node.type()
1258 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001259 << " Data Type: " << input->info()->data_type()
1260 << " Input shape: " << input->info()->tensor_shape()
1261 << " Output shape: " << output->info()->tensor_shape()
1262 << std::endl);
1263
1264 return std::move(func);
1265}
1266
1267/** Create a backend resize layer function
1268 *
1269 * @tparam ResizeLayerFunction Backend resize function
1270 * @tparam TargetInfo Target-specific information
1271 *
1272 * @param[in] node Node to create the backend function for
1273 *
1274 * @return Backend resize layer function
1275 */
1276template <typename ResizeLayerFunction, typename TargetInfo>
1277std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1278{
1279 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1280
1281 // Extract IO and info
1282 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1283 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1284 ARM_COMPUTE_ERROR_ON(input == nullptr);
1285 ARM_COMPUTE_ERROR_ON(output == nullptr);
1286 const InterpolationPolicy policy = node.policy();
1287
1288 // Create and configure function
1289 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1290 func->configure(input, output, policy, BorderMode::CONSTANT);
1291
1292 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001293 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1294 << node.name()
1295 << " Type: " << node.type()
1296 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001297 << " Data Type: " << input->info()->data_type()
1298 << " Input shape: " << input->info()->tensor_shape()
1299 << " Output shape: " << output->info()->tensor_shape()
1300 << " Interpolation: " << policy
1301 << std::endl);
1302
1303 return std::move(func);
1304}
1305
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001306/** Create a backend ROI align layer function
1307 *
1308 * @tparam ROIAlignLayerFunction ROI Align function
1309 * @tparam TargetInfo Target-specific information
1310 *
1311 * @param[in] node Node to create the backend function for
1312 *
1313 * @return ROI Align layer function
1314 */
1315template <typename ROIAlignLayerFunction, typename TargetInfo>
1316std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1317{
1318 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1319
1320 // Extract IO and info
1321 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1322 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1323 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1324 ARM_COMPUTE_ERROR_ON(input == nullptr);
1325 ARM_COMPUTE_ERROR_ON(output == nullptr);
1326 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1327
1328 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1329
1330 // Create and configure function
1331 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1332
1333 func->configure(input, rois, output, pool_info);
1334
1335 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +00001336 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1337 << node.name()
1338 << " Type: " << node.type()
1339 << " Target: " << TargetInfo::TargetType
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001340 << " Data Type: " << input->info()->data_type()
1341 << " Input shape: " << input->info()->tensor_shape()
1342 << " Output shape: " << output->info()->tensor_shape()
1343 << " ROIs shape: " << rois->info()->tensor_shape()
1344 << " ROIPooling width: " << pool_info.pooled_width()
1345 << " ROIPooling height: " << pool_info.pooled_height()
1346 << std::endl);
1347
1348 return std::move(func);
1349}
1350
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001351/** Create a backend slice layer function
1352 *
1353 * @tparam SliceLayerFunction Backend slice function
1354 * @tparam TargetInfo Target-specific information
1355 *
1356 * @param[in] node Node to create the backend function for
1357 *
1358 * @return Backend slice layer function
1359 */
1360template <typename SliceLayerFunction, typename TargetInfo>
1361std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1362{
1363 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1364
1365 // Extract IO and info
1366 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1367 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1368 ARM_COMPUTE_ERROR_ON(input == nullptr);
1369 ARM_COMPUTE_ERROR_ON(output == nullptr);
1370
1371 // Create and configure function
1372 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1373 func->configure(input, output, node.starts(), node.ends());
1374
1375 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001376 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1377 << node.name()
1378 << " Type: " << node.type()
1379 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001380 << " Data Type: " << input->info()->data_type()
1381 << " Input shape: " << input->info()->tensor_shape()
1382 << " Output shape: " << output->info()->tensor_shape()
1383 << std::endl);
1384
1385 return std::move(func);
1386}
1387
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001388/** Create a backend softmax layer function
1389 *
1390 * @tparam SoftmaxLayerFunction Backend softmax function
1391 * @tparam TargetInfo Target-specific information
1392 *
1393 * @param[in] node Node to create the backend function for
1394 * @param[in] ctx Graph context
1395 *
1396 * @return Backend softmax layer function
1397 */
1398template <typename SoftmaxLayerFunction, typename TargetInfo>
1399std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1400{
1401 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1402
1403 // Extract IO and info
1404 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1405 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1406 const float beta = node.beta();
1407 ARM_COMPUTE_ERROR_ON(input == nullptr);
1408 ARM_COMPUTE_ERROR_ON(output == nullptr);
1409
1410 // Create and configure function
1411 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1412 func->configure(input, output, beta);
1413
1414 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001415 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1416 << node.name()
1417 << " Type: " << node.type()
1418 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001419 << " Data Type: " << input->info()->data_type()
1420 << " Input shape: " << input->info()->tensor_shape()
1421 << " Output shape: " << output->info()->tensor_shape()
1422 << std::endl);
1423
1424 return std::move(func);
1425}
Michele Di Giorgioec699752019-03-22 15:25:32 +00001426
1427/** Create a backend layer stack function
1428 *
1429 * @tparam StackLayerFunction Backend stack function
1430 * @tparam TargetInfo Target-specific information
1431 *
1432 * @param[in] node Node to create the backend function for
1433 *
1434 * @return Backend stack layer function
1435 */
1436template <typename StackLayerFunction, typename TargetInfo>
1437std::unique_ptr<arm_compute::IFunction> create_stack_layer(StackLayerNode &node)
1438{
1439 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Stack node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
1440 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
1441
1442 // Extract IO and info
1443 std::vector<typename TargetInfo::TensorType *> inputs;
1444 for(unsigned int i = 0; i < node.num_inputs(); ++i)
1445 {
1446 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
1447 }
1448 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1449 const int axis = node.axis();
1450
1451 // Create and configure function
1452 auto func = support::cpp14::make_unique<StackLayerFunction>();
1453 func->configure(inputs, axis, output);
1454
1455 // Log info
1456 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1457 << node.name()
1458 << " Type: " << node.type()
1459 << " Target: " << TargetInfo::TargetType
1460 << " Data Type: " << output->info()->data_type()
1461 << " Inputs shape: " << inputs[0]->info()->tensor_shape()
1462 << " Output shape: " << output->info()->tensor_shape()
1463 << " Num Inputs: " << inputs.size()
1464 << " Axis: " << axis
1465 << std::endl);
1466
1467 return std::move(func);
1468}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001469/** Create a backend Upsample layer function
1470 *
1471 * @tparam UpsampleLayerFunction Backend Upsample function
1472 * @tparam TargetInfo Target-specific information
1473 *
1474 * @param[in] node Node to create the backend function for
1475 * @param[in] ctx Graph context
1476 *
1477 * @return Backend Upsample layer function
1478 */
1479template <typename UpsampleLayerFunction, typename TargetInfo>
1480std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1481{
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001482 ARM_COMPUTE_UNUSED(ctx);
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001483 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1484
1485 // Extract IO and info
1486 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1487 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1488 const Size2D info = node.info();
1489 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1490 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1491 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1492 ARM_COMPUTE_ERROR_ON(input == nullptr);
1493 ARM_COMPUTE_ERROR_ON(output == nullptr);
1494
1495 // Create and configure function
1496 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1497 func->configure(input, output, info, upsampling_policy);
1498
1499 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001500 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1501 << node.name()
1502 << " Type: " << node.type()
1503 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001504 << " Data Type: " << input->info()->data_type()
1505 << " Input shape: " << input->info()->tensor_shape()
1506 << " Output shape: " << output->info()->tensor_shape()
1507 << " Strides: " << info
1508 << " Upsampling policy: " << upsampling_policy
1509 << std::endl);
1510
1511 return std::move(func);
1512}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001513/** Create a backend YOLO layer function
1514 *
1515 * @tparam YoloLayerFunction Backend YOLO function
1516 * @tparam TargetInfo Target-specific information
1517 *
1518 * @param[in] node Node to create the backend function for
1519 * @param[in] ctx Graph context
1520 *
1521 * @return Backend YOLO layer function
1522 */
1523template <typename YOLOlayerFunction, typename TargetInfo>
1524std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1525{
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001526 ARM_COMPUTE_UNUSED(ctx);
Michalis Spyrou96f67692018-09-13 11:39:28 +01001527 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1528
1529 // Extract IO and info
1530 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1531 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1532 const ActivationLayerInfo act_info = node.activation_info();
1533 const int32_t num_classes = node.num_classes();
1534 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1535 ARM_COMPUTE_ERROR_ON(input == nullptr);
1536 ARM_COMPUTE_ERROR_ON(output == nullptr);
1537
1538 // Create and configure function
1539 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1540 func->configure(input, output, act_info, num_classes);
1541
1542 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001543 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1544 << node.name()
1545 << " Type: " << node.type()
1546 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001547 << " Data Type: " << input->info()->data_type()
1548 << " Input shape: " << input->info()->tensor_shape()
1549 << " Output shape: " << output->info()->tensor_shape()
1550 << " Activation function: " << act_info.activation()
1551 << " Num classes: " << num_classes
1552 << std::endl);
1553
1554 return std::move(func);
1555}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001556} // namespace detail
1557} // namespace backends
1558} // namespace graph
1559} // namespace arm_compute
1560
1561#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */