blob: 10f8c0c5c7c63d5162de9f147de97826d2e43faa [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);
86}
87
88/** Creates a backend activation layer function
89 *
90 * @tparam ActivationLayerFunction Backend activation function
91 * @tparam TargetInfo Target-specific information
92 *
93 * @param[in] node Node to create the backend function for
94 *
95 * @return Backend activation layer function
96 */
97template <typename ActivationLayerFunction, typename TargetInfo>
98std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
99{
100 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
101
102 // Extract IO and info
103 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
104 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
105 const ActivationLayerInfo act_info = node.activation_info();
106
107 // Create function
108 auto func = support::cpp14::make_unique<ActivationLayerFunction>();
109 func->configure(input, output, act_info);
110
Pablo Tello32521432018-11-15 14:43:10 +0000111 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
112 << node.name()
113 << " Type: " << node.type()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000114 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100115 << " Data Type: " << input->info()->data_type()
116 << " Shape: " << input->info()->tensor_shape()
117 << " Activation function: " << act_info.activation()
118 << " a: " << act_info.a()
119 << " b: " << act_info.b()
120 << " InPlace : " << is_in_place_operation(input, output)
121 << std::endl);
122
123 return std::move(func);
124}
125
126/** Create a backend batch normalization layer function
127 *
128 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
129 * @tparam TargetInfo Target-specific information
130 *
131 * @param[in] node Node to create the backend function for
132 *
133 * @return Backend batch normalization layer function
134 */
135template <typename BatchNormalizationLayerFunction, typename TargetInfo>
136std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
137{
138 validate_node<TargetInfo>(node, 5 /* expected inputs */, 1 /* expected outputs */);
139
140 // Extract IO and info
giuros01acce5042019-02-21 17:32:34 +0000141 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
142 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
143 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(2));
144 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(3));
145 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(4));
146
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100147 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
148 const float epsilon = node.epsilon();
149 const ActivationLayerInfo fused_act = node.fused_activation();
150
151 // Create and configure function
152 auto func = support::cpp14::make_unique<BatchNormalizationLayerFunction>();
153 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
154
155 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000156 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
157 << node.name()
158 << " Type: " << node.type()
159 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100160 << " Data Type: " << input->info()->data_type()
161 << " Shape: " << input->info()->tensor_shape()
162 << " Epsilon: " << epsilon << " "
163 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
Pablo Tello32521432018-11-15 14:43:10 +0000164 << " InPlace: " << is_in_place_operation(input, output)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100165 << std::endl);
166
167 return std::move(func);
168}
169
giuros01acce5042019-02-21 17:32:34 +0000170/** Create a backend batch normalization layer function
171 *
172 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
173 * @tparam TargetInfo Target-specific information
174 *
175 * @param[in] node Node to create the backend function for
176 *
177 * @return Backend batch normalization layer function
178 */
179template <typename FusedLayerTypes, typename TargetInfo>
180std::unique_ptr<IFunction> create_fused_convolution_batch_normalization_layer(FusedConvolutionBatchNormalizationNode &node)
181{
182 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
183
184 // Extract IO and info
185 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
186 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
187 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
188 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
189 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
190 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
191 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
192
193 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
194
195 const PadStrideInfo conv_info = node.convolution_info();
196 const unsigned int num_groups = node.num_groups();
197 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
198 const ActivationLayerInfo fused_act = node.fused_activation();
199 const float epsilon = node.epsilon();
200
giuros01acce5042019-02-21 17:32:34 +0000201 // Create and configure function
202 auto func = support::cpp14::make_unique<FusedConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>>();
203 func->configure(input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, num_groups, fast_math, fused_act);
204
205 // Log info
206 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
207 << node.name()
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100208 << " Type: " << node.type()
209 << " Target: " << TargetInfo::TargetType
210 << " Data Type: " << input->info()->data_type()
211 << " Input shape: " << input->info()->tensor_shape()
212 << " Weights shape: " << weights->info()->tensor_shape()
213 << " Output shape: " << output->info()->tensor_shape()
214 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
215 << std::endl);
216 return std::move(func);
217}
218
219/** Create a backend fused depthwise convolution batch normalization layer function
220 *
221 * @tparam FusedLayerTypes Fused layer types
222 * @tparam TargetInfo Target-specific information
223 *
224 * @param[in] node Node to create the backend function for
225 *
226 * @return Backend fused depthwise convolution batch normalization layer function
227 */
228template <typename FusedLayerTypes, typename TargetInfo>
229std::unique_ptr<IFunction> create_fused_depthwise_convolution_batch_normalization_layer(FusedDepthwiseConvolutionBatchNormalizationNode &node)
230{
231 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
232
233 // Extract IO and info
234 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
235 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
236 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
237 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
238 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
239 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
240 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
241
242 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
243
244 const PadStrideInfo conv_info = node.convolution_info();
245 const unsigned int depth_multiplier = node.depth_multiplier();
246 const ActivationLayerInfo fused_act = node.fused_activation();
247 const float epsilon = node.epsilon();
248
249 // Create and configure function
250 auto func = support::cpp14::make_unique<FusedDepthwiseConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>>();
251 func->configure(input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, depth_multiplier, fused_act);
252
253 // Log info
254 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
255 << node.name()
256 << " Type: " << node.type()
giuros01acce5042019-02-21 17:32:34 +0000257 << " Target: " << TargetInfo::TargetType
258 << " Data Type: " << input->info()->data_type()
259 << " Input shape: " << input->info()->tensor_shape()
260 << " Weights shape: " << weights->info()->tensor_shape()
261 << " Output shape: " << output->info()->tensor_shape()
262 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
263 << std::endl);
264 return std::move(func);
265}
266
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100267/** Create a backend bounding box transform layer function
268 *
269 * @tparam BoundingBoxTransformLayerFunction Backend bounding box transform function
270 * @tparam TargetInfo Target-specific information
271 *
272 * @param[in] node Node to create the backend function for
273 *
274 * @return Backend bounding box transform layer function
275 */
276template <typename BoundingBoxTransformLayerFunction, typename TargetInfo>
277std::unique_ptr<IFunction> create_bounding_box_transform_layer(BoundingBoxTransformLayerNode &node)
278{
279 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
280
281 // Extract IO and info
282 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
283 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
284 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
285 const BoundingBoxTransformInfo bbox_info = node.info();
286
287 // Create and configure function
288 auto func = support::cpp14::make_unique<BoundingBoxTransformLayerFunction>();
289 func->configure(input, output, deltas, bbox_info);
290
291 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000292 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
293 << node.name()
294 << " Type: " << node.type()
295 << " Target: " << TargetInfo::TargetType
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100296 << " Data Type: " << input->info()->data_type()
297 << " Shape: " << input->info()->tensor_shape()
298 << " BoundingBox Info img W: " << bbox_info.img_width() << " "
299 << " BoundingBox Info img H: " << bbox_info.img_height() << " "
300 << std::endl);
301
302 return std::move(func);
303}
304
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100305/** Create a backend channel shuffle layer function
306 *
307 * @tparam ChannelShuffleLayerFunction Backend channel shuffle function
308 * @tparam TargetInfo Target-specific information
309 *
310 * @param[in] node Node to create the backend function for
311 *
312 * @return Backend channel shuffle layer function
313 */
314template <typename ChannelShuffleLayerFunction, typename TargetInfo>
315std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
316{
317 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
318
319 // Extract IO and info
320 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
321 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
322 const unsigned int num_groups = node.num_groups();
323
324 // Create function
325 auto func = support::cpp14::make_unique<ChannelShuffleLayerFunction>();
326 func->configure(input, output, num_groups);
327
Pablo Tello32521432018-11-15 14:43:10 +0000328 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
329 << node.name()
330 << " Type: " << node.type()
331 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100332 << " Data Type: " << input->info()->data_type()
333 << " Shape: " << input->info()->tensor_shape()
334 << " Num groups: " << num_groups
335 << std::endl);
336
337 return std::move(func);
338}
339
Georgios Pinitase2220552018-07-20 13:23:44 +0100340/** Create a backend layer concatenate function
341 *
342 * @tparam ConcatenateLayerFunction Backend concatenate function
343 * @tparam TargetInfo Target-specific information
344 *
345 * @param[in] node Node to create the backend function for
346 *
347 * @return Backend concatenate layer function
348 */
349template <typename ConcatenateLayerFunction, typename TargetInfo>
350std::unique_ptr<arm_compute::IFunction> create_concatenate_layer(ConcatenateLayerNode &node)
351{
352 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Concatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
353 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
354
355 // Return nullptr if depth concatenate is switched off
356 if(!node.is_enabled())
357 {
358 return nullptr;
359 }
360
361 // Extract IO and info
362 std::vector<typename TargetInfo::TensorType *> inputs;
363 for(unsigned int i = 0; i < node.num_inputs(); ++i)
364 {
365 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
366 }
367 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100368 const DataLayout data_layout = node.output(0) != nullptr ? node.output(0)->desc().layout : DataLayout::UNKNOWN;
369 const size_t concat_axis = get_dimension_idx(data_layout, node.concatenation_axis());
Georgios Pinitase2220552018-07-20 13:23:44 +0100370
371 // Create and configure function
372 auto func = support::cpp14::make_unique<ConcatenateLayerFunction>();
373 func->configure(inputs, output, concat_axis);
374
375 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000376 const bool is_quantized = is_data_type_quantized_asymmetric(output->info()->data_type());
377 std::ostringstream qss;
378 if(is_quantized)
379 {
380 qss << " Output QuantInfo: " << output->info()->quantization_info();
381 }
Pablo Tello32521432018-11-15 14:43:10 +0000382 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
383 << node.name()
384 << " Type: " << node.type()
385 << " Target: " << TargetInfo::TargetType
Georgios Pinitase2220552018-07-20 13:23:44 +0100386 << " Data Type: " << output->info()->data_type()
387 << " Shape: " << output->info()->tensor_shape()
388 << " Num Inputs: " << inputs.size()
389 << " Axis: " << concat_axis
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000390 << qss.str()
Georgios Pinitase2220552018-07-20 13:23:44 +0100391 << std::endl);
392
393 return std::move(func);
394}
395
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100396/** Create a backend convolution layer function
397 *
398 * @tparam ConvolutionLayerFunctions Backend convolution functions
399 * @tparam TargetInfo Target-specific information
400 *
401 * @param[in] node Node to create the backend function for
402 * @param[in] ctx Graph context
403 *
404 * @return Backend convolution layer function
405 */
406template <typename ConvolutionLayerFunctions, typename TargetInfo>
407std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
408{
409 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
410
411 // Extract IO and info
412 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
413 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
414 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
415 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
416
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100417 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
418
419 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100420 {
421 biases->info()->set_data_type(DataType::S32);
422 }
423
Georgios Pinitas08346e92018-10-16 19:10:46 +0100424 const PadStrideInfo conv_info = node.convolution_info();
425 const unsigned int num_groups = node.num_groups();
426 const ConvolutionMethod conv_algorithm = node.convolution_method();
427 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
428 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100429
430 // Create and configure function (we assume that functions have been validated before creation)
431 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
432 std::unique_ptr<IFunction> func;
433 std::string func_name;
434
Georgios Pinitase2220552018-07-20 13:23:44 +0100435 if(conv_algorithm == ConvolutionMethod::Winograd)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100436 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100437 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "WinogradConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100438 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::WinogradConvolutionLayer>(
439 std::string("WinogradConvolutionLayer"), mm,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100440 input, weights, biases, output, conv_info, fused_act, fast_math);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100441 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100442 else if(conv_algorithm == ConvolutionMethod::Direct)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100443 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100444 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "DirectConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100445 std::tie(func, func_name) = create_named_function<typename ConvolutionLayerFunctions::DirectConvolutionLayer>(
446 std::string("DirectConvolutionLayer"),
Georgios Pinitas08346e92018-10-16 19:10:46 +0100447 input, weights, biases, output, conv_info, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100448 }
449 else if(conv_algorithm == ConvolutionMethod::GEMM)
450 {
451 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GEMMConvolutionLayer>(
452 std::string("GEMMConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100453 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100454 WeightsInfo(), Size2D(1U, 1U), fused_act, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100455 }
456 else
457 {
458 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GenericConvolutionLayer>(
459 std::string("GenericConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100460 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100461 WeightsInfo(), Size2D(1U, 1U), fused_act, fast_math, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100462 }
463
464 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100465 std::ostringstream qss;
466 if(is_quantized)
467 {
468 qss << " Input QuantInfo: " << input->info()->quantization_info()
469 << " Weights QuantInfo: " << weights->info()->quantization_info()
470 << " Output QuantInfo: " << output->info()->quantization_info();
471 }
Pablo Tello32521432018-11-15 14:43:10 +0000472 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
473 << node.name()
474 << " Type: " << func_name
475 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100476 << " Data Type: " << input->info()->data_type()
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100477 << " Groups: " << num_groups
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100478 << " Input shape: " << input->info()->tensor_shape()
479 << " Weights shape: " << weights->info()->tensor_shape()
480 << " Output shape: " << output->info()->tensor_shape()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000481 << qss.str()
Georgios Pinitas08346e92018-10-16 19:10:46 +0100482 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100483 << std::endl);
484 return func;
485}
486
487/** Create a backend deconvolution layer function
488 *
489 * @tparam DeconvolutionLayerFunction Backend deconvolution function
490 * @tparam TargetInfo Target-specific information
491 *
492 * @param[in] node Node to create the backend function for
493 * @param[in] ctx Graph context
494 *
495 * @return Backend deconvolution layer function
496 */
497template <typename DeconvolutionLayerFunction, typename TargetInfo>
498std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
499{
500 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
501
502 // Extract IO and info
503 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
504 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
505 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
506 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
507
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100508 const PadStrideInfo deconv_info = node.deconvolution_info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100509
510 // Create and configure function (we assume that functions have been validated before creation)
511 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
512 std::unique_ptr<IFunction> func;
513
514 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
515 std::string(), mm,
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100516 input, weights, biases, output, deconv_info);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100517
518 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000519 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
520 << node.name()
521 << " Type: " << node.type()
522 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100523 << " Data Type: " << input->info()->data_type()
524 << " Input shape: " << input->info()->tensor_shape()
525 << " Weights shape: " << weights->info()->tensor_shape()
526 << " Output shape: " << output->info()->tensor_shape()
527 << std::endl);
528 return func;
529}
530
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100531/** Create a backend layer depth-wise convolution function
532 *
533 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
534 * @tparam TargetInfo Target-specific information
535 *
536 * @param[in] node Node to create the backend function for
537 *
538 * @return Backend depth-wise convolution layer function
539 */
540template <typename DepthwiseConvolutionLayerFunctions, typename TargetInfo>
541std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
542{
543 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
544
545 // Extract IO and info
546 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
547 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
548 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
549 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
550
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100551 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
552
553 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100554 {
555 biases->info()->set_data_type(DataType::S32);
556 }
557
Georgios Pinitas60e98252018-10-22 16:17:20 +0100558 const PadStrideInfo conv_info = node.convolution_info();
559 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
Georgios Pinitas05045c12018-12-07 18:31:47 +0000560 const unsigned int depth_multiplier = node.depth_multiplier();
Georgios Pinitas60e98252018-10-22 16:17:20 +0100561 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100562
563 // Create and configure function (we assume that functions have been validated before creation)
564 std::unique_ptr<IFunction> func;
565 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100566 if(dwc_algorithm == DepthwiseConvolutionMethod::Optimized3x3)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100567 {
Georgios Pinitas30271c72019-06-24 14:56:34 +0100568 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::OptimizedDepthwiseConvolutionLayer>(
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100569 std::string("DepthwiseConvolutionLayer3x3"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100570 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100571 }
572 else
573 {
574 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::GenericDepthwiseConvolutionLayer>(
575 std::string("DepthwiseConvolutionLayer"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100576 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100577 }
578
579 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100580 std::ostringstream qss;
581 if(is_quantized)
582 {
583 qss << " Input QuantInfo: " << input->info()->quantization_info()
584 << " Weights QuantInfo: " << weights->info()->quantization_info()
585 << " Output QuantInfo: " << output->info()->quantization_info();
586 }
Pablo Tello32521432018-11-15 14:43:10 +0000587 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
588 << node.name()
589 << " Type: " << func_name
590 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100591 << " Data Type: " << input->info()->data_type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100592 << " Input shape: " << input->info()->tensor_shape()
593 << " Weights shape: " << weights->info()->tensor_shape()
594 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000595 << " Depth multiplier: " << depth_multiplier
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000596 << qss.str()
Georgios Pinitas60e98252018-10-22 16:17:20 +0100597 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100598 << std::endl);
599 return func;
600}
601
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000602/** Create a backend detection output layer function
603 *
604 * @tparam DetectionOutputLayer Function Backend detection output function
605 * @tparam TargetInfo Target-specific information
606 *
607 * @param[in] node Node to create the backend function for
608 *
609 * @return Backend detection output layer function
610 */
611template <typename DetectionOutputLayerFunction, typename TargetInfo>
612std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
613{
614 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
615
616 // Extract IO and info
617 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
618 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
619 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
620 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
621 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
622
623 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
624 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
625 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
626 ARM_COMPUTE_ERROR_ON(output == nullptr);
627
628 // Create and configure function
629 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
630 func->configure(input0, input1, input2, output, detect_info);
631
632 // Log info
633 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
634 << node.name()
635 << " Type: " << node.type()
636 << " Target: " << TargetInfo::TargetType
637 << " Data Type: " << input0->info()->data_type()
638 << " Input0 shape: " << input0->info()->tensor_shape()
639 << " Input1 shape: " << input1->info()->tensor_shape()
640 << " Input2 shape: " << input2->info()->tensor_shape()
641 << " Output shape: " << output->info()->tensor_shape()
642 << " DetectionOutputLayer info: " << detect_info
643 << std::endl);
644
645 return std::move(func);
646}
Isabella Gottardia7acb3c2019-01-08 13:48:44 +0000647
648/** Create a backend detection post process layer function
649 *
650 * @tparam DetectionPostProcessLayerFunction Backend detection output function
651 * @tparam TargetInfo Target-specific information
652 *
653 * @param[in] node Node to create the backend function for
654 *
655 * @return Backend detection post process layer function
656 */
657template <typename DetectionPostProcessLayerFunction, typename TargetInfo>
658std::unique_ptr<IFunction> create_detection_post_process_layer(DetectionPostProcessLayerNode &node)
659{
660 validate_node<TargetInfo>(node, 3 /* expected inputs */, 4 /* expected outputs */);
661
662 // Extract IO and info
663 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
664 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
665 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
666 typename TargetInfo::TensorType *output0 = get_backing_tensor<TargetInfo>(node.output(0));
667 typename TargetInfo::TensorType *output1 = get_backing_tensor<TargetInfo>(node.output(1));
668 typename TargetInfo::TensorType *output2 = get_backing_tensor<TargetInfo>(node.output(2));
669 typename TargetInfo::TensorType *output3 = get_backing_tensor<TargetInfo>(node.output(3));
670 const DetectionPostProcessLayerInfo detect_info = node.detection_post_process_info();
671
672 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
673 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
674 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
675 ARM_COMPUTE_ERROR_ON(output0 == nullptr);
676 ARM_COMPUTE_ERROR_ON(output1 == nullptr);
677 ARM_COMPUTE_ERROR_ON(output2 == nullptr);
678 ARM_COMPUTE_ERROR_ON(output3 == nullptr);
679
680 // Create and configure function
681 auto func = support::cpp14::make_unique<DetectionPostProcessLayerFunction>();
682 func->configure(input0, input1, input2, output0, output1, output2, output3, detect_info);
683
684 // Log info
685 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
686 << node.name()
687 << " Type: " << node.type()
688 << " Target: " << TargetInfo::TargetType
689 << " Data Type: " << input0->info()->data_type()
690 << " Input0 shape: " << input0->info()->tensor_shape()
691 << " Input1 shape: " << input1->info()->tensor_shape()
692 << " Input2 shape: " << input2->info()->tensor_shape()
693 << " Output0 shape: " << output0->info()->tensor_shape()
694 << " Output1 shape: " << output1->info()->tensor_shape()
695 << " Output2 shape: " << output2->info()->tensor_shape()
696 << " Output3 shape: " << output3->info()->tensor_shape()
697 << " DetectionPostProcessLayer info: " << detect_info
698 << std::endl);
699
700 return std::move(func);
701}
702
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100703/** Create a backend element-wise operation layer function
704 *
705 * @tparam EltwiseFunctions Backend element-wise function
706 * @tparam TargetInfo Target-specific information
707 *
708 * @param[in] node Node to create the backend function for
709 *
710 * @return Backend element-wise operation layer function
711 */
712template <typename EltwiseFunctions, typename TargetInfo>
713std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
714{
715 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
716
717 // Extract IO and info
718 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
719 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
720 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
721 const EltwiseOperation eltwise_op = node.eltwise_operation();
722 const ConvertPolicy convert_policy = node.convert_policy();
723 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
724 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
725 ARM_COMPUTE_ERROR_ON(output == nullptr);
726
727 std::unique_ptr<IFunction> func = nullptr;
728 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100729 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100730 {
731 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
732 std::string("ArithmeticAddition"),
733 input1, input2, output, convert_policy);
734 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100735 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100736 {
737 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
738 std::string("ArithmeticSubtraction"),
739 input1, input2, output, convert_policy);
740 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100741 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100742 {
743 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
744 std::string("PixelWiseMultiplication"),
745 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
746 }
747 else
748 {
749 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
750 }
751
752 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000753 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
754 << node.name()
755 << " Type: " << node.type()
756 << " Target: " << TargetInfo::TargetType
757 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100758 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000759 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100760 << std::endl);
761
762 return func;
763}
764
765/** Create a backend flatten layer function
766 *
767 * @tparam FlattenLayerFunction Backend flatten function
768 * @tparam TargetInfo Target-specific information
769 *
770 * @param[in] node Node to create the backend function for
771 *
772 * @return Backend flatten layer function
773 */
774template <typename FlattenLayerFunction, typename TargetInfo>
775std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
776{
777 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
778
779 // Extract IO and info
780 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
781 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
782
Georgios Pinitase2220552018-07-20 13:23:44 +0100783 ARM_COMPUTE_ERROR_ON(input == nullptr);
784 ARM_COMPUTE_ERROR_ON(output == nullptr);
785
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100786 // Create and configure function
787 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
788 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100789
790 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000791 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
792 << node.name()
793 << " Type: " << node.type()
794 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100795 << " Data Type: " << input->info()->data_type()
796 << " Input shape: " << input->info()->tensor_shape()
797 << " Output shape: " << output->info()->tensor_shape()
798 << std::endl);
799
800 return std::move(func);
801}
802
803/** Create a backend fully connected layer function
804 *
805 * @tparam FullyConnectedLayerFunction Backend fully-connected function
806 * @tparam TargetInfo Target-specific information
807 *
808 * @param[in] node Node to create the backend function for
809 * @param[in] ctx Graph context
810 *
811 * @return Backend fully connected layer function
812 */
813template <typename FullyConnectedLayerFunction, typename TargetInfo>
814std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
815{
816 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
817
818 // Extract IO and info
819 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
820 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
821 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
822 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100823 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100824
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100825 ARM_COMPUTE_ERROR_ON(input == nullptr);
826 ARM_COMPUTE_ERROR_ON(weights == nullptr);
827 ARM_COMPUTE_ERROR_ON(output == nullptr);
828
Georgios Pinitase2220552018-07-20 13:23:44 +0100829 // Create and configure function
Michalis Spyrou1a569a32019-09-10 17:20:34 +0100830 auto wm = get_weights_manager(ctx, TargetInfo::TargetType);
831 auto mm = get_memory_manager(ctx, TargetInfo::TargetType);
832 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(mm, wm.get());
Georgios Pinitase2220552018-07-20 13:23:44 +0100833 func->configure(input, weights, biases, output, fc_info);
834
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100835 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
836
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100837 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100838 std::ostringstream qss;
839 if(is_quantized)
840 {
841 qss << " Input QuantInfo: " << input->info()->quantization_info()
842 << " Weights QuantInfo: " << weights->info()->quantization_info()
843 << " Output QuantInfo: " << output->info()->quantization_info();
844 }
Pablo Tello32521432018-11-15 14:43:10 +0000845 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
846 << node.name()
847 << " Type: " << node.type()
848 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100849 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100850 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100851 << " Input shape: " << input->info()->tensor_shape()
852 << " Weights shape: " << weights->info()->tensor_shape()
853 << " Output shape: " << output->info()->tensor_shape()
854 << std::endl);
855
856 return std::move(func);
857}
858
Manuel Bottini5209be52019-02-13 16:34:56 +0000859/** Create a backend generate proposals layer function
860 *
861 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
862 * @tparam TargetInfo Target-specific information
863 *
864 * @param[in] node Node to create the backend function for
865 * @param[in] ctx Graph context
866 *
867 * @return Backend generate proposals layer function
868 */
869template <typename GenerateProposalsLayerFunction, typename TargetInfo>
870std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
871{
872 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
873
874 // Extract IO and info
875 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
876 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
877 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
878 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
879 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
880 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
881 const GenerateProposalsInfo info = node.info();
882
883 ARM_COMPUTE_ERROR_ON(scores == nullptr);
884 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
885 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
886 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
887 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
888
889 // Create and configure function
890 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
891 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
892
893 // Log info
894 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
895 << " Target " << TargetInfo::TargetType
896 << " Data Type: " << scores->info()->data_type()
897 << " Scores shape: " << scores->info()->tensor_shape()
898 << " Deltas shape: " << deltas->info()->tensor_shape()
899 << " Anchors shape: " << anchors->info()->tensor_shape()
900 << " Proposals shape: " << proposals->info()->tensor_shape()
901 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
902 << " Scores Out shape: " << scores_out->info()->tensor_shape()
903 << std::endl);
904
905 return std::move(func);
906}
907
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100908/** Create a backend normalization layer function
909 *
910 * @tparam NormalizationLayerFunction Backend normalization function
911 * @tparam TargetInfo Target-specific information
912 *
913 * @param[in] node Node to create the backend function for
914 * @param[in] ctx Graph context
915 *
916 * @return Backend normalization layer function
917 */
918template <typename NormalizationLayerFunction, typename TargetInfo>
919std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
920{
921 ARM_COMPUTE_UNUSED(ctx);
922
923 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
924
925 // Extract IO and info
926 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
927 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
928 const NormalizationLayerInfo norm_info = node.normalization_info();
929 ARM_COMPUTE_ERROR_ON(input == nullptr);
930 ARM_COMPUTE_ERROR_ON(output == nullptr);
931
932 // Create and configure function
933 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
934 func->configure(input, output, norm_info);
935
936 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000937 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
938 << node.name()
939 << " Type: " << node.type()
940 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100941 << " Data Type: " << input->info()->data_type()
942 << " Input shape: " << input->info()->tensor_shape()
943 << " Output shape: " << output->info()->tensor_shape()
944 << " Normalization info: " << norm_info.type()
945 << std::endl);
946
947 return std::move(func);
948}
949
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100950/** Create a backend normalize planar YUV layer function
951 *
952 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
953 * @tparam TargetInfo Target-specific information
954 *
955 * @param[in] node Node to create the backend function for
956 *
957 * @return Backend normalize plnar YUV layer function
958 */
959template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
960std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
961{
962 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
963
964 // Extract IO and info
965 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
966 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
967 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
968 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
969 ARM_COMPUTE_ERROR_ON(input == nullptr);
970 ARM_COMPUTE_ERROR_ON(mean == nullptr);
971 ARM_COMPUTE_ERROR_ON(std == nullptr);
972 ARM_COMPUTE_ERROR_ON(output == nullptr);
973
974 // Create and configure function
975 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
976 func->configure(input, output, mean, std);
977
978 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000979 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
980 << node.name()
981 << " Type: " << node.type()
982 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100983 << " Data Type: " << input->info()->data_type()
984 << " Shape: " << input->info()->tensor_shape()
985 << std::endl);
986
987 return std::move(func);
988}
989
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100990/** Create a backend pad layer function
991 *
992 * @tparam PadLayerFunction Backend pad function
993 * @tparam TargetInfo Target-specific information
994 *
995 * @param[in] node Node to create the backend function for
996 *
997 * @return Backend pad layer function
998 */
999template <typename PadLayerFunction, typename TargetInfo>
1000std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
1001{
1002 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1003
1004 // Extract IO and info
1005 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1006 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1007 const PaddingList &padding = node.padding();
1008 ARM_COMPUTE_ERROR_ON(input == nullptr);
1009 ARM_COMPUTE_ERROR_ON(output == nullptr);
1010
1011 // Create and configure function
1012 auto func = support::cpp14::make_unique<PadLayerFunction>();
1013 func->configure(input, output, padding);
1014
1015 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001016 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1017 << node.name()
1018 << " Type: " << node.type()
1019 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +01001020 << " Data Type: " << input->info()->data_type()
1021 << " Input shape: " << input->info()->tensor_shape()
1022 << " Output shape: " << output->info()->tensor_shape()
1023 << std::endl);
1024
1025 return std::move(func);
1026}
1027
Georgios Pinitas57c48242018-08-02 13:41:49 +01001028/** Create a backend permute layer function
1029 *
1030 * @tparam PermuteLayerFunction Backend permute function
1031 * @tparam TargetInfo Target-specific information
1032 *
1033 * @param[in] node Node to create the backend function for
1034 *
1035 * @return Backend permute layer function
1036 */
1037template <typename PermuteLayerFunction, typename TargetInfo>
1038std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
1039{
1040 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1041
1042 // Extract IO and info
1043 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1044 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1045 const PermutationVector &perm = node.permutation_vector();
1046 ARM_COMPUTE_ERROR_ON(input == nullptr);
1047 ARM_COMPUTE_ERROR_ON(output == nullptr);
1048
1049 // Create and configure function
1050 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
1051 func->configure(input, output, perm);
1052
1053 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001054 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1055 << node.name()
1056 << " Type: " << node.type()
1057 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +01001058 << " Data Type: " << input->info()->data_type()
1059 << " Input shape: " << input->info()->tensor_shape()
1060 << " Output shape: " << output->info()->tensor_shape()
1061 << " Permutation vector: " << perm
1062 << std::endl);
1063
1064 return std::move(func);
1065}
1066
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001067/** Create a backend pooling layer function
1068 *
1069 * @tparam PoolingLayerFunction Backend pooling function
1070 * @tparam TargetInfo Target-specific information
1071 *
1072 * @param[in] node Node to create the backend function for
1073 *
1074 * @return Backend pooling layer function
1075 */
1076template <typename PoolingLayerFunction, typename TargetInfo>
1077std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
1078{
1079 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1080
1081 // Extract IO and info
1082 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1083 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1084 const PoolingLayerInfo pool_info = node.pooling_info();
1085 ARM_COMPUTE_ERROR_ON(input == nullptr);
1086 ARM_COMPUTE_ERROR_ON(output == nullptr);
1087
1088 // Create and configure function
1089 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
1090 func->configure(input, output, pool_info);
1091
1092 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001093 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1094 << node.name()
1095 << " Type: " << node.type()
1096 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001097 << " Data Type: " << input->info()->data_type()
1098 << " Input shape: " << input->info()->tensor_shape()
1099 << " Output shape: " << output->info()->tensor_shape()
1100 << " Pooling info: " << pool_info.pool_type()
1101 << std::endl);
1102
1103 return std::move(func);
1104}
1105
Pablo Tello32521432018-11-15 14:43:10 +00001106/** Create a backend priorbox layer function
1107 *
1108 * @tparam PriorBoxLayerFunction Backend priorbox function
1109 * @tparam TargetInfo Target-specific information
1110 *
1111 * @param[in] node Node to create the backend function for
1112 *
1113 * @return Backend priorbox layer function
1114 */
1115template <typename PriorBoxLayerFunction, typename TargetInfo>
1116std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1117{
1118 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1119
1120 // Extract IO and info
1121 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1122 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1123 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1124 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1125 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1126 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1127 ARM_COMPUTE_ERROR_ON(output == nullptr);
1128
1129 // Create and configure function
1130 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1131 func->configure(input0, input1, output, prior_info);
1132
1133 // Log info
1134 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1135 << node.name()
1136 << " Type: " << node.type()
1137 << " Target: " << TargetInfo::TargetType
1138 << " Data Type: " << input0->info()->data_type()
1139 << " Input0 shape: " << input0->info()->tensor_shape()
1140 << " Input1 shape: " << input1->info()->tensor_shape()
1141 << " Output shape: " << output->info()->tensor_shape()
1142 << " PriorBoxLayer info: " << prior_info
1143 << std::endl);
1144
1145 return std::move(func);
1146}
1147
Isabella Gottardi3db1ba92019-05-17 12:35:20 +01001148/** Create a backend quantization layer function
1149 *
1150 * @tparam QuantizationLayerFunction Backend quantization function
1151 * @tparam TargetInfo Target-specific information
1152 *
1153 * @param[in] node Node to create the backend function for
1154 *
1155 * @return Backend quantization layer function
1156 */
1157template <typename QuantizationLayerFunction, typename TargetInfo>
1158std::unique_ptr<IFunction> create_quantization_layer(QuantizationLayerNode &node)
1159{
1160 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1161
1162 // Extract IO and info
1163 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1164 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1165 ARM_COMPUTE_ERROR_ON(input == nullptr);
1166 ARM_COMPUTE_ERROR_ON(output == nullptr);
1167
1168 // Create and configure function
1169 auto func = support::cpp14::make_unique<QuantizationLayerFunction>();
1170 func->configure(input, output);
1171
1172 // Log info
1173 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1174 << node.name()
1175 << " Type: " << node.type()
1176 << " Target: " << TargetInfo::TargetType
1177 << " Data Type: " << input->info()->data_type()
1178 << " Input shape: " << input->info()->tensor_shape()
1179 << " Output shape: " << output->info()->tensor_shape()
1180 << std::endl);
1181
1182 return std::move(func);
1183}
1184
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001185/** Create a backend reorg layer function
1186 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001187 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001188 * @tparam TargetInfo Target-specific information
1189 *
1190 * @param[in] node Node to create the backend function for
1191 *
1192 * @return Backend reshape layer function
1193 */
1194template <typename ReorgLayerFunction, typename TargetInfo>
1195std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
1196{
1197 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1198
1199 // Extract IO and info
1200 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1201 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1202 ARM_COMPUTE_ERROR_ON(input == nullptr);
1203 ARM_COMPUTE_ERROR_ON(output == nullptr);
1204
1205 // Create and configure function
1206 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
1207 func->configure(input, output, node.stride());
1208
1209 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001210 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1211 << node.name()
1212 << " Type: " << node.type()
1213 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001214 << " Data Type: " << input->info()->data_type()
1215 << " Input shape: " << input->info()->tensor_shape()
1216 << " Output shape: " << output->info()->tensor_shape()
1217 << std::endl);
1218
1219 return std::move(func);
1220}
1221
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001222/** Create a backend reshape layer function
1223 *
1224 * @tparam ReshapeLayerFunction Backend reshape function
1225 * @tparam TargetInfo Target-specific information
1226 *
1227 * @param[in] node Node to create the backend function for
1228 *
1229 * @return Backend reshape layer function
1230 */
1231template <typename ReshapeLayerFunction, typename TargetInfo>
1232std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1233{
1234 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1235
1236 // Extract IO and info
1237 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1238 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1239 ARM_COMPUTE_ERROR_ON(input == nullptr);
1240 ARM_COMPUTE_ERROR_ON(output == nullptr);
1241
1242 // Create and configure function
1243 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1244 func->configure(input, output);
1245
1246 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001247 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1248 << node.name()
1249 << " Type: " << node.type()
1250 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001251 << " Data Type: " << input->info()->data_type()
1252 << " Input shape: " << input->info()->tensor_shape()
1253 << " Output shape: " << output->info()->tensor_shape()
1254 << std::endl);
1255
1256 return std::move(func);
1257}
1258
1259/** Create a backend resize layer function
1260 *
1261 * @tparam ResizeLayerFunction Backend resize function
1262 * @tparam TargetInfo Target-specific information
1263 *
1264 * @param[in] node Node to create the backend function for
1265 *
1266 * @return Backend resize layer function
1267 */
1268template <typename ResizeLayerFunction, typename TargetInfo>
1269std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1270{
1271 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1272
1273 // Extract IO and info
1274 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1275 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1276 ARM_COMPUTE_ERROR_ON(input == nullptr);
1277 ARM_COMPUTE_ERROR_ON(output == nullptr);
1278 const InterpolationPolicy policy = node.policy();
1279
1280 // Create and configure function
1281 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1282 func->configure(input, output, policy, BorderMode::CONSTANT);
1283
1284 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001285 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1286 << node.name()
1287 << " Type: " << node.type()
1288 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001289 << " Data Type: " << input->info()->data_type()
1290 << " Input shape: " << input->info()->tensor_shape()
1291 << " Output shape: " << output->info()->tensor_shape()
1292 << " Interpolation: " << policy
1293 << std::endl);
1294
1295 return std::move(func);
1296}
1297
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001298/** Create a backend ROI align layer function
1299 *
1300 * @tparam ROIAlignLayerFunction ROI Align function
1301 * @tparam TargetInfo Target-specific information
1302 *
1303 * @param[in] node Node to create the backend function for
1304 *
1305 * @return ROI Align layer function
1306 */
1307template <typename ROIAlignLayerFunction, typename TargetInfo>
1308std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1309{
1310 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1311
1312 // Extract IO and info
1313 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1314 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1315 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1316 ARM_COMPUTE_ERROR_ON(input == nullptr);
1317 ARM_COMPUTE_ERROR_ON(output == nullptr);
1318 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1319
1320 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1321
1322 // Create and configure function
1323 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1324
1325 func->configure(input, rois, output, pool_info);
1326
1327 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +00001328 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1329 << node.name()
1330 << " Type: " << node.type()
1331 << " Target: " << TargetInfo::TargetType
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001332 << " Data Type: " << input->info()->data_type()
1333 << " Input shape: " << input->info()->tensor_shape()
1334 << " Output shape: " << output->info()->tensor_shape()
1335 << " ROIs shape: " << rois->info()->tensor_shape()
1336 << " ROIPooling width: " << pool_info.pooled_width()
1337 << " ROIPooling height: " << pool_info.pooled_height()
1338 << std::endl);
1339
1340 return std::move(func);
1341}
1342
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001343/** Create a backend slice layer function
1344 *
1345 * @tparam SliceLayerFunction Backend slice function
1346 * @tparam TargetInfo Target-specific information
1347 *
1348 * @param[in] node Node to create the backend function for
1349 *
1350 * @return Backend slice layer function
1351 */
1352template <typename SliceLayerFunction, typename TargetInfo>
1353std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1354{
1355 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1356
1357 // Extract IO and info
1358 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1359 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1360 ARM_COMPUTE_ERROR_ON(input == nullptr);
1361 ARM_COMPUTE_ERROR_ON(output == nullptr);
1362
1363 // Create and configure function
1364 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1365 func->configure(input, output, node.starts(), node.ends());
1366
1367 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001368 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1369 << node.name()
1370 << " Type: " << node.type()
1371 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001372 << " Data Type: " << input->info()->data_type()
1373 << " Input shape: " << input->info()->tensor_shape()
1374 << " Output shape: " << output->info()->tensor_shape()
1375 << std::endl);
1376
1377 return std::move(func);
1378}
1379
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001380/** Create a backend softmax layer function
1381 *
1382 * @tparam SoftmaxLayerFunction Backend softmax function
1383 * @tparam TargetInfo Target-specific information
1384 *
1385 * @param[in] node Node to create the backend function for
1386 * @param[in] ctx Graph context
1387 *
1388 * @return Backend softmax layer function
1389 */
1390template <typename SoftmaxLayerFunction, typename TargetInfo>
1391std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1392{
1393 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1394
1395 // Extract IO and info
1396 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1397 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1398 const float beta = node.beta();
1399 ARM_COMPUTE_ERROR_ON(input == nullptr);
1400 ARM_COMPUTE_ERROR_ON(output == nullptr);
1401
1402 // Create and configure function
1403 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1404 func->configure(input, output, beta);
1405
1406 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001407 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1408 << node.name()
1409 << " Type: " << node.type()
1410 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001411 << " Data Type: " << input->info()->data_type()
1412 << " Input shape: " << input->info()->tensor_shape()
1413 << " Output shape: " << output->info()->tensor_shape()
1414 << std::endl);
1415
1416 return std::move(func);
1417}
Michele Di Giorgioec699752019-03-22 15:25:32 +00001418
1419/** Create a backend layer stack function
1420 *
1421 * @tparam StackLayerFunction Backend stack function
1422 * @tparam TargetInfo Target-specific information
1423 *
1424 * @param[in] node Node to create the backend function for
1425 *
1426 * @return Backend stack layer function
1427 */
1428template <typename StackLayerFunction, typename TargetInfo>
1429std::unique_ptr<arm_compute::IFunction> create_stack_layer(StackLayerNode &node)
1430{
1431 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Stack node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
1432 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
1433
1434 // Extract IO and info
1435 std::vector<typename TargetInfo::TensorType *> inputs;
1436 for(unsigned int i = 0; i < node.num_inputs(); ++i)
1437 {
1438 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
1439 }
1440 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1441 const int axis = node.axis();
1442
1443 // Create and configure function
1444 auto func = support::cpp14::make_unique<StackLayerFunction>();
1445 func->configure(inputs, axis, output);
1446
1447 // Log info
1448 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1449 << node.name()
1450 << " Type: " << node.type()
1451 << " Target: " << TargetInfo::TargetType
1452 << " Data Type: " << output->info()->data_type()
1453 << " Inputs shape: " << inputs[0]->info()->tensor_shape()
1454 << " Output shape: " << output->info()->tensor_shape()
1455 << " Num Inputs: " << inputs.size()
1456 << " Axis: " << axis
1457 << std::endl);
1458
1459 return std::move(func);
1460}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001461/** Create a backend Upsample layer function
1462 *
1463 * @tparam UpsampleLayerFunction Backend Upsample function
1464 * @tparam TargetInfo Target-specific information
1465 *
1466 * @param[in] node Node to create the backend function for
1467 * @param[in] ctx Graph context
1468 *
1469 * @return Backend Upsample layer function
1470 */
1471template <typename UpsampleLayerFunction, typename TargetInfo>
1472std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1473{
1474 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1475
1476 // Extract IO and info
1477 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1478 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1479 const Size2D info = node.info();
1480 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1481 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1482 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1483 ARM_COMPUTE_ERROR_ON(input == nullptr);
1484 ARM_COMPUTE_ERROR_ON(output == nullptr);
1485
1486 // Create and configure function
1487 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1488 func->configure(input, output, info, upsampling_policy);
1489
1490 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001491 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1492 << node.name()
1493 << " Type: " << node.type()
1494 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001495 << " Data Type: " << input->info()->data_type()
1496 << " Input shape: " << input->info()->tensor_shape()
1497 << " Output shape: " << output->info()->tensor_shape()
1498 << " Strides: " << info
1499 << " Upsampling policy: " << upsampling_policy
1500 << std::endl);
1501
1502 return std::move(func);
1503}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001504/** Create a backend YOLO layer function
1505 *
1506 * @tparam YoloLayerFunction Backend YOLO function
1507 * @tparam TargetInfo Target-specific information
1508 *
1509 * @param[in] node Node to create the backend function for
1510 * @param[in] ctx Graph context
1511 *
1512 * @return Backend YOLO layer function
1513 */
1514template <typename YOLOlayerFunction, typename TargetInfo>
1515std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1516{
1517 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1518
1519 // Extract IO and info
1520 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1521 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1522 const ActivationLayerInfo act_info = node.activation_info();
1523 const int32_t num_classes = node.num_classes();
1524 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1525 ARM_COMPUTE_ERROR_ON(input == nullptr);
1526 ARM_COMPUTE_ERROR_ON(output == nullptr);
1527
1528 // Create and configure function
1529 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1530 func->configure(input, output, act_info, num_classes);
1531
1532 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001533 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1534 << node.name()
1535 << " Type: " << node.type()
1536 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001537 << " Data Type: " << input->info()->data_type()
1538 << " Input shape: " << input->info()->tensor_shape()
1539 << " Output shape: " << output->info()->tensor_shape()
1540 << " Activation function: " << act_info.activation()
1541 << " Num classes: " << num_classes
1542 << std::endl);
1543
1544 return std::move(func);
1545}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001546} // namespace detail
1547} // namespace backends
1548} // namespace graph
1549} // namespace arm_compute
1550
1551#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */