blob: ed5b35c0d11f8cec74d7ec912d5729c445ef0377 [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}
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100647/** Create a backend element-wise operation layer function
648 *
649 * @tparam EltwiseFunctions Backend element-wise function
650 * @tparam TargetInfo Target-specific information
651 *
652 * @param[in] node Node to create the backend function for
653 *
654 * @return Backend element-wise operation layer function
655 */
656template <typename EltwiseFunctions, typename TargetInfo>
657std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
658{
659 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
660
661 // Extract IO and info
662 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
663 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
664 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
665 const EltwiseOperation eltwise_op = node.eltwise_operation();
666 const ConvertPolicy convert_policy = node.convert_policy();
667 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
668 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
669 ARM_COMPUTE_ERROR_ON(output == nullptr);
670
671 std::unique_ptr<IFunction> func = nullptr;
672 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100673 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100674 {
675 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
676 std::string("ArithmeticAddition"),
677 input1, input2, output, convert_policy);
678 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100679 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100680 {
681 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
682 std::string("ArithmeticSubtraction"),
683 input1, input2, output, convert_policy);
684 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100685 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100686 {
687 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
688 std::string("PixelWiseMultiplication"),
689 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
690 }
691 else
692 {
693 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
694 }
695
696 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000697 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
698 << node.name()
699 << " Type: " << node.type()
700 << " Target: " << TargetInfo::TargetType
701 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100702 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000703 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100704 << std::endl);
705
706 return func;
707}
708
709/** Create a backend flatten layer function
710 *
711 * @tparam FlattenLayerFunction Backend flatten function
712 * @tparam TargetInfo Target-specific information
713 *
714 * @param[in] node Node to create the backend function for
715 *
716 * @return Backend flatten layer function
717 */
718template <typename FlattenLayerFunction, typename TargetInfo>
719std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
720{
721 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
722
723 // Extract IO and info
724 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
725 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
726
Georgios Pinitase2220552018-07-20 13:23:44 +0100727 ARM_COMPUTE_ERROR_ON(input == nullptr);
728 ARM_COMPUTE_ERROR_ON(output == nullptr);
729
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100730 // Create and configure function
731 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
732 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100733
734 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000735 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
736 << node.name()
737 << " Type: " << node.type()
738 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100739 << " Data Type: " << input->info()->data_type()
740 << " Input shape: " << input->info()->tensor_shape()
741 << " Output shape: " << output->info()->tensor_shape()
742 << std::endl);
743
744 return std::move(func);
745}
746
747/** Create a backend fully connected layer function
748 *
749 * @tparam FullyConnectedLayerFunction Backend fully-connected function
750 * @tparam TargetInfo Target-specific information
751 *
752 * @param[in] node Node to create the backend function for
753 * @param[in] ctx Graph context
754 *
755 * @return Backend fully connected layer function
756 */
757template <typename FullyConnectedLayerFunction, typename TargetInfo>
758std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
759{
760 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
761
762 // Extract IO and info
763 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
764 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
765 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
766 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100767 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100768
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100769 ARM_COMPUTE_ERROR_ON(input == nullptr);
770 ARM_COMPUTE_ERROR_ON(weights == nullptr);
771 ARM_COMPUTE_ERROR_ON(output == nullptr);
772
Georgios Pinitase2220552018-07-20 13:23:44 +0100773 // Create and configure function
774 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
775 func->configure(input, weights, biases, output, fc_info);
776
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100777 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
778
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100779 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100780 std::ostringstream qss;
781 if(is_quantized)
782 {
783 qss << " Input QuantInfo: " << input->info()->quantization_info()
784 << " Weights QuantInfo: " << weights->info()->quantization_info()
785 << " Output QuantInfo: " << output->info()->quantization_info();
786 }
Pablo Tello32521432018-11-15 14:43:10 +0000787 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
788 << node.name()
789 << " Type: " << node.type()
790 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100791 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100792 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100793 << " Input shape: " << input->info()->tensor_shape()
794 << " Weights shape: " << weights->info()->tensor_shape()
795 << " Output shape: " << output->info()->tensor_shape()
796 << std::endl);
797
798 return std::move(func);
799}
800
Manuel Bottini5209be52019-02-13 16:34:56 +0000801/** Create a backend generate proposals layer function
802 *
803 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
804 * @tparam TargetInfo Target-specific information
805 *
806 * @param[in] node Node to create the backend function for
807 * @param[in] ctx Graph context
808 *
809 * @return Backend generate proposals layer function
810 */
811template <typename GenerateProposalsLayerFunction, typename TargetInfo>
812std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
813{
814 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
815
816 // Extract IO and info
817 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
818 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
819 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
820 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
821 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
822 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
823 const GenerateProposalsInfo info = node.info();
824
825 ARM_COMPUTE_ERROR_ON(scores == nullptr);
826 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
827 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
828 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
829 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
830
831 // Create and configure function
832 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
833 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
834
835 // Log info
836 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
837 << " Target " << TargetInfo::TargetType
838 << " Data Type: " << scores->info()->data_type()
839 << " Scores shape: " << scores->info()->tensor_shape()
840 << " Deltas shape: " << deltas->info()->tensor_shape()
841 << " Anchors shape: " << anchors->info()->tensor_shape()
842 << " Proposals shape: " << proposals->info()->tensor_shape()
843 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
844 << " Scores Out shape: " << scores_out->info()->tensor_shape()
845 << std::endl);
846
847 return std::move(func);
848}
849
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100850/** Create a backend normalization layer function
851 *
852 * @tparam NormalizationLayerFunction Backend normalization function
853 * @tparam TargetInfo Target-specific information
854 *
855 * @param[in] node Node to create the backend function for
856 * @param[in] ctx Graph context
857 *
858 * @return Backend normalization layer function
859 */
860template <typename NormalizationLayerFunction, typename TargetInfo>
861std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
862{
863 ARM_COMPUTE_UNUSED(ctx);
864
865 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
866
867 // Extract IO and info
868 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
869 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
870 const NormalizationLayerInfo norm_info = node.normalization_info();
871 ARM_COMPUTE_ERROR_ON(input == nullptr);
872 ARM_COMPUTE_ERROR_ON(output == nullptr);
873
874 // Create and configure function
875 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
876 func->configure(input, output, norm_info);
877
878 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000879 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
880 << node.name()
881 << " Type: " << node.type()
882 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100883 << " Data Type: " << input->info()->data_type()
884 << " Input shape: " << input->info()->tensor_shape()
885 << " Output shape: " << output->info()->tensor_shape()
886 << " Normalization info: " << norm_info.type()
887 << std::endl);
888
889 return std::move(func);
890}
891
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100892/** Create a backend normalize planar YUV layer function
893 *
894 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
895 * @tparam TargetInfo Target-specific information
896 *
897 * @param[in] node Node to create the backend function for
898 *
899 * @return Backend normalize plnar YUV layer function
900 */
901template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
902std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
903{
904 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
905
906 // Extract IO and info
907 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
908 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
909 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
910 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
911 ARM_COMPUTE_ERROR_ON(input == nullptr);
912 ARM_COMPUTE_ERROR_ON(mean == nullptr);
913 ARM_COMPUTE_ERROR_ON(std == nullptr);
914 ARM_COMPUTE_ERROR_ON(output == nullptr);
915
916 // Create and configure function
917 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
918 func->configure(input, output, mean, std);
919
920 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000921 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
922 << node.name()
923 << " Type: " << node.type()
924 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100925 << " Data Type: " << input->info()->data_type()
926 << " Shape: " << input->info()->tensor_shape()
927 << std::endl);
928
929 return std::move(func);
930}
931
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100932/** Create a backend pad layer function
933 *
934 * @tparam PadLayerFunction Backend pad function
935 * @tparam TargetInfo Target-specific information
936 *
937 * @param[in] node Node to create the backend function for
938 *
939 * @return Backend pad layer function
940 */
941template <typename PadLayerFunction, typename TargetInfo>
942std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
943{
944 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
945
946 // Extract IO and info
947 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
948 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
949 const PaddingList &padding = node.padding();
950 ARM_COMPUTE_ERROR_ON(input == nullptr);
951 ARM_COMPUTE_ERROR_ON(output == nullptr);
952
953 // Create and configure function
954 auto func = support::cpp14::make_unique<PadLayerFunction>();
955 func->configure(input, output, padding);
956
957 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000958 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
959 << node.name()
960 << " Type: " << node.type()
961 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100962 << " Data Type: " << input->info()->data_type()
963 << " Input shape: " << input->info()->tensor_shape()
964 << " Output shape: " << output->info()->tensor_shape()
965 << std::endl);
966
967 return std::move(func);
968}
969
Georgios Pinitas57c48242018-08-02 13:41:49 +0100970/** Create a backend permute layer function
971 *
972 * @tparam PermuteLayerFunction Backend permute function
973 * @tparam TargetInfo Target-specific information
974 *
975 * @param[in] node Node to create the backend function for
976 *
977 * @return Backend permute layer function
978 */
979template <typename PermuteLayerFunction, typename TargetInfo>
980std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
981{
982 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
983
984 // Extract IO and info
985 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
986 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
987 const PermutationVector &perm = node.permutation_vector();
988 ARM_COMPUTE_ERROR_ON(input == nullptr);
989 ARM_COMPUTE_ERROR_ON(output == nullptr);
990
991 // Create and configure function
992 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
993 func->configure(input, output, perm);
994
995 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000996 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
997 << node.name()
998 << " Type: " << node.type()
999 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +01001000 << " Data Type: " << input->info()->data_type()
1001 << " Input shape: " << input->info()->tensor_shape()
1002 << " Output shape: " << output->info()->tensor_shape()
1003 << " Permutation vector: " << perm
1004 << std::endl);
1005
1006 return std::move(func);
1007}
1008
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001009/** Create a backend pooling layer function
1010 *
1011 * @tparam PoolingLayerFunction Backend pooling function
1012 * @tparam TargetInfo Target-specific information
1013 *
1014 * @param[in] node Node to create the backend function for
1015 *
1016 * @return Backend pooling layer function
1017 */
1018template <typename PoolingLayerFunction, typename TargetInfo>
1019std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
1020{
1021 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1022
1023 // Extract IO and info
1024 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1025 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1026 const PoolingLayerInfo pool_info = node.pooling_info();
1027 ARM_COMPUTE_ERROR_ON(input == nullptr);
1028 ARM_COMPUTE_ERROR_ON(output == nullptr);
1029
1030 // Create and configure function
1031 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
1032 func->configure(input, output, pool_info);
1033
1034 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001035 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1036 << node.name()
1037 << " Type: " << node.type()
1038 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001039 << " Data Type: " << input->info()->data_type()
1040 << " Input shape: " << input->info()->tensor_shape()
1041 << " Output shape: " << output->info()->tensor_shape()
1042 << " Pooling info: " << pool_info.pool_type()
1043 << std::endl);
1044
1045 return std::move(func);
1046}
1047
Pablo Tello32521432018-11-15 14:43:10 +00001048/** Create a backend priorbox layer function
1049 *
1050 * @tparam PriorBoxLayerFunction Backend priorbox function
1051 * @tparam TargetInfo Target-specific information
1052 *
1053 * @param[in] node Node to create the backend function for
1054 *
1055 * @return Backend priorbox layer function
1056 */
1057template <typename PriorBoxLayerFunction, typename TargetInfo>
1058std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1059{
1060 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1061
1062 // Extract IO and info
1063 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1064 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1065 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1066 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1067 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1068 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1069 ARM_COMPUTE_ERROR_ON(output == nullptr);
1070
1071 // Create and configure function
1072 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1073 func->configure(input0, input1, output, prior_info);
1074
1075 // Log info
1076 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1077 << node.name()
1078 << " Type: " << node.type()
1079 << " Target: " << TargetInfo::TargetType
1080 << " Data Type: " << input0->info()->data_type()
1081 << " Input0 shape: " << input0->info()->tensor_shape()
1082 << " Input1 shape: " << input1->info()->tensor_shape()
1083 << " Output shape: " << output->info()->tensor_shape()
1084 << " PriorBoxLayer info: " << prior_info
1085 << std::endl);
1086
1087 return std::move(func);
1088}
1089
Isabella Gottardi3db1ba92019-05-17 12:35:20 +01001090/** Create a backend quantization layer function
1091 *
1092 * @tparam QuantizationLayerFunction Backend quantization function
1093 * @tparam TargetInfo Target-specific information
1094 *
1095 * @param[in] node Node to create the backend function for
1096 *
1097 * @return Backend quantization layer function
1098 */
1099template <typename QuantizationLayerFunction, typename TargetInfo>
1100std::unique_ptr<IFunction> create_quantization_layer(QuantizationLayerNode &node)
1101{
1102 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1103
1104 // Extract IO and info
1105 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1106 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1107 ARM_COMPUTE_ERROR_ON(input == nullptr);
1108 ARM_COMPUTE_ERROR_ON(output == nullptr);
1109
1110 // Create and configure function
1111 auto func = support::cpp14::make_unique<QuantizationLayerFunction>();
1112 func->configure(input, output);
1113
1114 // Log info
1115 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1116 << node.name()
1117 << " Type: " << node.type()
1118 << " Target: " << TargetInfo::TargetType
1119 << " Data Type: " << input->info()->data_type()
1120 << " Input shape: " << input->info()->tensor_shape()
1121 << " Output shape: " << output->info()->tensor_shape()
1122 << std::endl);
1123
1124 return std::move(func);
1125}
1126
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001127/** Create a backend reorg layer function
1128 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001129 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001130 * @tparam TargetInfo Target-specific information
1131 *
1132 * @param[in] node Node to create the backend function for
1133 *
1134 * @return Backend reshape layer function
1135 */
1136template <typename ReorgLayerFunction, typename TargetInfo>
1137std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
1138{
1139 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1140
1141 // Extract IO and info
1142 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1143 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1144 ARM_COMPUTE_ERROR_ON(input == nullptr);
1145 ARM_COMPUTE_ERROR_ON(output == nullptr);
1146
1147 // Create and configure function
1148 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
1149 func->configure(input, output, node.stride());
1150
1151 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001152 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1153 << node.name()
1154 << " Type: " << node.type()
1155 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001156 << " Data Type: " << input->info()->data_type()
1157 << " Input shape: " << input->info()->tensor_shape()
1158 << " Output shape: " << output->info()->tensor_shape()
1159 << std::endl);
1160
1161 return std::move(func);
1162}
1163
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001164/** Create a backend reshape layer function
1165 *
1166 * @tparam ReshapeLayerFunction Backend reshape function
1167 * @tparam TargetInfo Target-specific information
1168 *
1169 * @param[in] node Node to create the backend function for
1170 *
1171 * @return Backend reshape layer function
1172 */
1173template <typename ReshapeLayerFunction, typename TargetInfo>
1174std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1175{
1176 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1177
1178 // Extract IO and info
1179 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1180 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1181 ARM_COMPUTE_ERROR_ON(input == nullptr);
1182 ARM_COMPUTE_ERROR_ON(output == nullptr);
1183
1184 // Create and configure function
1185 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1186 func->configure(input, output);
1187
1188 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001189 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1190 << node.name()
1191 << " Type: " << node.type()
1192 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001193 << " Data Type: " << input->info()->data_type()
1194 << " Input shape: " << input->info()->tensor_shape()
1195 << " Output shape: " << output->info()->tensor_shape()
1196 << std::endl);
1197
1198 return std::move(func);
1199}
1200
1201/** Create a backend resize layer function
1202 *
1203 * @tparam ResizeLayerFunction Backend resize function
1204 * @tparam TargetInfo Target-specific information
1205 *
1206 * @param[in] node Node to create the backend function for
1207 *
1208 * @return Backend resize layer function
1209 */
1210template <typename ResizeLayerFunction, typename TargetInfo>
1211std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1212{
1213 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1214
1215 // Extract IO and info
1216 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1217 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1218 ARM_COMPUTE_ERROR_ON(input == nullptr);
1219 ARM_COMPUTE_ERROR_ON(output == nullptr);
1220 const InterpolationPolicy policy = node.policy();
1221
1222 // Create and configure function
1223 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1224 func->configure(input, output, policy, BorderMode::CONSTANT);
1225
1226 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001227 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1228 << node.name()
1229 << " Type: " << node.type()
1230 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001231 << " Data Type: " << input->info()->data_type()
1232 << " Input shape: " << input->info()->tensor_shape()
1233 << " Output shape: " << output->info()->tensor_shape()
1234 << " Interpolation: " << policy
1235 << std::endl);
1236
1237 return std::move(func);
1238}
1239
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001240/** Create a backend ROI align layer function
1241 *
1242 * @tparam ROIAlignLayerFunction ROI Align function
1243 * @tparam TargetInfo Target-specific information
1244 *
1245 * @param[in] node Node to create the backend function for
1246 *
1247 * @return ROI Align layer function
1248 */
1249template <typename ROIAlignLayerFunction, typename TargetInfo>
1250std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1251{
1252 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1253
1254 // Extract IO and info
1255 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1256 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1257 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1258 ARM_COMPUTE_ERROR_ON(input == nullptr);
1259 ARM_COMPUTE_ERROR_ON(output == nullptr);
1260 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1261
1262 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1263
1264 // Create and configure function
1265 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1266
1267 func->configure(input, rois, output, pool_info);
1268
1269 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +00001270 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1271 << node.name()
1272 << " Type: " << node.type()
1273 << " Target: " << TargetInfo::TargetType
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001274 << " Data Type: " << input->info()->data_type()
1275 << " Input shape: " << input->info()->tensor_shape()
1276 << " Output shape: " << output->info()->tensor_shape()
1277 << " ROIs shape: " << rois->info()->tensor_shape()
1278 << " ROIPooling width: " << pool_info.pooled_width()
1279 << " ROIPooling height: " << pool_info.pooled_height()
1280 << std::endl);
1281
1282 return std::move(func);
1283}
1284
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001285/** Create a backend slice layer function
1286 *
1287 * @tparam SliceLayerFunction Backend slice function
1288 * @tparam TargetInfo Target-specific information
1289 *
1290 * @param[in] node Node to create the backend function for
1291 *
1292 * @return Backend slice layer function
1293 */
1294template <typename SliceLayerFunction, typename TargetInfo>
1295std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1296{
1297 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1298
1299 // Extract IO and info
1300 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1301 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1302 ARM_COMPUTE_ERROR_ON(input == nullptr);
1303 ARM_COMPUTE_ERROR_ON(output == nullptr);
1304
1305 // Create and configure function
1306 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1307 func->configure(input, output, node.starts(), node.ends());
1308
1309 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001310 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1311 << node.name()
1312 << " Type: " << node.type()
1313 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001314 << " Data Type: " << input->info()->data_type()
1315 << " Input shape: " << input->info()->tensor_shape()
1316 << " Output shape: " << output->info()->tensor_shape()
1317 << std::endl);
1318
1319 return std::move(func);
1320}
1321
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001322/** Create a backend softmax layer function
1323 *
1324 * @tparam SoftmaxLayerFunction Backend softmax function
1325 * @tparam TargetInfo Target-specific information
1326 *
1327 * @param[in] node Node to create the backend function for
1328 * @param[in] ctx Graph context
1329 *
1330 * @return Backend softmax layer function
1331 */
1332template <typename SoftmaxLayerFunction, typename TargetInfo>
1333std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1334{
1335 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1336
1337 // Extract IO and info
1338 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1339 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1340 const float beta = node.beta();
1341 ARM_COMPUTE_ERROR_ON(input == nullptr);
1342 ARM_COMPUTE_ERROR_ON(output == nullptr);
1343
1344 // Create and configure function
1345 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1346 func->configure(input, output, beta);
1347
1348 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001349 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1350 << node.name()
1351 << " Type: " << node.type()
1352 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001353 << " Data Type: " << input->info()->data_type()
1354 << " Input shape: " << input->info()->tensor_shape()
1355 << " Output shape: " << output->info()->tensor_shape()
1356 << std::endl);
1357
1358 return std::move(func);
1359}
Michele Di Giorgioec699752019-03-22 15:25:32 +00001360
1361/** Create a backend layer stack function
1362 *
1363 * @tparam StackLayerFunction Backend stack function
1364 * @tparam TargetInfo Target-specific information
1365 *
1366 * @param[in] node Node to create the backend function for
1367 *
1368 * @return Backend stack layer function
1369 */
1370template <typename StackLayerFunction, typename TargetInfo>
1371std::unique_ptr<arm_compute::IFunction> create_stack_layer(StackLayerNode &node)
1372{
1373 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Stack node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
1374 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
1375
1376 // Extract IO and info
1377 std::vector<typename TargetInfo::TensorType *> inputs;
1378 for(unsigned int i = 0; i < node.num_inputs(); ++i)
1379 {
1380 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
1381 }
1382 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1383 const int axis = node.axis();
1384
1385 // Create and configure function
1386 auto func = support::cpp14::make_unique<StackLayerFunction>();
1387 func->configure(inputs, axis, output);
1388
1389 // Log info
1390 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1391 << node.name()
1392 << " Type: " << node.type()
1393 << " Target: " << TargetInfo::TargetType
1394 << " Data Type: " << output->info()->data_type()
1395 << " Inputs shape: " << inputs[0]->info()->tensor_shape()
1396 << " Output shape: " << output->info()->tensor_shape()
1397 << " Num Inputs: " << inputs.size()
1398 << " Axis: " << axis
1399 << std::endl);
1400
1401 return std::move(func);
1402}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001403/** Create a backend Upsample layer function
1404 *
1405 * @tparam UpsampleLayerFunction Backend Upsample function
1406 * @tparam TargetInfo Target-specific information
1407 *
1408 * @param[in] node Node to create the backend function for
1409 * @param[in] ctx Graph context
1410 *
1411 * @return Backend Upsample layer function
1412 */
1413template <typename UpsampleLayerFunction, typename TargetInfo>
1414std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1415{
1416 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1417
1418 // Extract IO and info
1419 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1420 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1421 const Size2D info = node.info();
1422 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1423 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1424 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1425 ARM_COMPUTE_ERROR_ON(input == nullptr);
1426 ARM_COMPUTE_ERROR_ON(output == nullptr);
1427
1428 // Create and configure function
1429 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1430 func->configure(input, output, info, upsampling_policy);
1431
1432 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001433 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1434 << node.name()
1435 << " Type: " << node.type()
1436 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001437 << " Data Type: " << input->info()->data_type()
1438 << " Input shape: " << input->info()->tensor_shape()
1439 << " Output shape: " << output->info()->tensor_shape()
1440 << " Strides: " << info
1441 << " Upsampling policy: " << upsampling_policy
1442 << std::endl);
1443
1444 return std::move(func);
1445}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001446/** Create a backend YOLO layer function
1447 *
1448 * @tparam YoloLayerFunction Backend YOLO function
1449 * @tparam TargetInfo Target-specific information
1450 *
1451 * @param[in] node Node to create the backend function for
1452 * @param[in] ctx Graph context
1453 *
1454 * @return Backend YOLO layer function
1455 */
1456template <typename YOLOlayerFunction, typename TargetInfo>
1457std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1458{
1459 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1460
1461 // Extract IO and info
1462 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1463 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1464 const ActivationLayerInfo act_info = node.activation_info();
1465 const int32_t num_classes = node.num_classes();
1466 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1467 ARM_COMPUTE_ERROR_ON(input == nullptr);
1468 ARM_COMPUTE_ERROR_ON(output == nullptr);
1469
1470 // Create and configure function
1471 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1472 func->configure(input, output, act_info, num_classes);
1473
1474 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001475 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1476 << node.name()
1477 << " Type: " << node.type()
1478 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001479 << " Data Type: " << input->info()->data_type()
1480 << " Input shape: " << input->info()->tensor_shape()
1481 << " Output shape: " << output->info()->tensor_shape()
1482 << " Activation function: " << act_info.activation()
1483 << " Num classes: " << num_classes
1484 << std::endl);
1485
1486 return std::move(func);
1487}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001488} // namespace detail
1489} // namespace backends
1490} // namespace graph
1491} // namespace arm_compute
1492
1493#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */