blob: 785f6dc3b90d91f6be53fcfab67b8b9200f9168a [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"
Georgios Pinitasda2491f2018-06-01 17:49:09 +010033#include "arm_compute/graph/backends/Utils.h"
34#include "arm_compute/graph/nodes/Nodes.h"
35
36#include "arm_compute/core/Error.h"
37#include "arm_compute/core/Helpers.h"
38#include "arm_compute/core/ITensorInfo.h"
39#include "arm_compute/core/utils/misc/Cast.h"
40
41namespace arm_compute
42{
43namespace graph
44{
45namespace backends
46{
47namespace detail
48{
49/** Returns backing tensor of a given tensor
50 *
51 * @tparam TargetInfo Target information
52 *
53 * @param[in] tensor Tensor to extract the backing tensor from
54 *
55 * @return Backing tensor if present else nullptr
56 */
57template <typename TargetInfo>
58typename TargetInfo::TensorType *get_backing_tensor(arm_compute::graph::Tensor *tensor)
59{
60 typename TargetInfo::TensorType *backing_tensor = nullptr;
61 if(tensor != nullptr)
62 {
63 ARM_COMPUTE_ERROR_ON(tensor->desc().target != TargetInfo::TargetType);
64 // Get backing tensor handle
65 ITensorHandle *tensor_handle = tensor->handle();
66 // Get backing tensor
67 backing_tensor = (tensor_handle != nullptr) ? arm_compute::utils::cast::polymorphic_cast<typename TargetInfo::TensorType *>(&tensor_handle->tensor()) : nullptr;
68 }
69
70 return backing_tensor;
71}
72
73template <typename TargetInfo>
74void validate_node(const INode &node, size_t num_expected_inputs, size_t num_expected_outputs)
75{
76 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating " << node.type()
Pablo Tello32521432018-11-15 14:43:10 +000077 << " Target: " << TargetInfo::TargetType
78 << " ID: " << node.id()
79 << node.name()
Georgios Pinitasda2491f2018-06-01 17:49:09 +010080 << std::endl);
81
82 ARM_COMPUTE_ERROR_ON(TargetInfo::TargetType != node.assigned_target());
83 ARM_COMPUTE_ERROR_ON(node.num_inputs() != num_expected_inputs);
84 ARM_COMPUTE_ERROR_ON(node.num_outputs() != num_expected_outputs);
85}
86
87/** Creates a backend activation layer function
88 *
89 * @tparam ActivationLayerFunction Backend activation function
90 * @tparam TargetInfo Target-specific information
91 *
92 * @param[in] node Node to create the backend function for
93 *
94 * @return Backend activation layer function
95 */
96template <typename ActivationLayerFunction, typename TargetInfo>
97std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
98{
99 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
100
101 // Extract IO and info
102 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
103 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
104 const ActivationLayerInfo act_info = node.activation_info();
105
106 // Create function
107 auto func = support::cpp14::make_unique<ActivationLayerFunction>();
108 func->configure(input, output, act_info);
109
Pablo Tello32521432018-11-15 14:43:10 +0000110 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
111 << node.name()
112 << " Type: " << node.type()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000113 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100114 << " Data Type: " << input->info()->data_type()
115 << " Shape: " << input->info()->tensor_shape()
116 << " Activation function: " << act_info.activation()
117 << " a: " << act_info.a()
118 << " b: " << act_info.b()
119 << " InPlace : " << is_in_place_operation(input, output)
120 << std::endl);
121
122 return std::move(func);
123}
124
125/** Create a backend batch normalization layer function
126 *
127 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
128 * @tparam TargetInfo Target-specific information
129 *
130 * @param[in] node Node to create the backend function for
131 *
132 * @return Backend batch normalization layer function
133 */
134template <typename BatchNormalizationLayerFunction, typename TargetInfo>
135std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
136{
137 validate_node<TargetInfo>(node, 5 /* expected inputs */, 1 /* expected outputs */);
138
139 // Extract IO and info
giuros01acce5042019-02-21 17:32:34 +0000140 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
141 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
142 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(2));
143 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(3));
144 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(4));
145
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100146 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
147 const float epsilon = node.epsilon();
148 const ActivationLayerInfo fused_act = node.fused_activation();
149
150 // Create and configure function
151 auto func = support::cpp14::make_unique<BatchNormalizationLayerFunction>();
152 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
153
154 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000155 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
156 << node.name()
157 << " Type: " << node.type()
158 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100159 << " Data Type: " << input->info()->data_type()
160 << " Shape: " << input->info()->tensor_shape()
161 << " Epsilon: " << epsilon << " "
162 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
Pablo Tello32521432018-11-15 14:43:10 +0000163 << " InPlace: " << is_in_place_operation(input, output)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100164 << std::endl);
165
166 return std::move(func);
167}
168
giuros01acce5042019-02-21 17:32:34 +0000169/** Create a backend batch normalization layer function
170 *
171 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
172 * @tparam TargetInfo Target-specific information
173 *
174 * @param[in] node Node to create the backend function for
175 *
176 * @return Backend batch normalization layer function
177 */
178template <typename FusedLayerTypes, typename TargetInfo>
179std::unique_ptr<IFunction> create_fused_convolution_batch_normalization_layer(FusedConvolutionBatchNormalizationNode &node)
180{
181 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
182
183 // Extract IO and info
184 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
185 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
186 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
187 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
188 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
189 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
190 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
191
192 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
193
194 const PadStrideInfo conv_info = node.convolution_info();
195 const unsigned int num_groups = node.num_groups();
196 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
197 const ActivationLayerInfo fused_act = node.fused_activation();
198 const float epsilon = node.epsilon();
199
200 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
201 if(is_quantized && biases != nullptr)
202 {
203 biases->info()->set_data_type(DataType::S32);
204 }
205
206 // Create and configure function
207 auto func = support::cpp14::make_unique<FusedConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>>();
208 func->configure(input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, num_groups, fast_math, fused_act);
209
210 // Log info
211 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
212 << node.name()
213 << " Type: " << node.name()
214 << " Target: " << TargetInfo::TargetType
215 << " Data Type: " << input->info()->data_type()
216 << " Input shape: " << input->info()->tensor_shape()
217 << " Weights shape: " << weights->info()->tensor_shape()
218 << " Output shape: " << output->info()->tensor_shape()
219 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
220 << std::endl);
221 return std::move(func);
222}
223
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100224/** Create a backend bounding box transform layer function
225 *
226 * @tparam BoundingBoxTransformLayerFunction Backend bounding box transform function
227 * @tparam TargetInfo Target-specific information
228 *
229 * @param[in] node Node to create the backend function for
230 *
231 * @return Backend bounding box transform layer function
232 */
233template <typename BoundingBoxTransformLayerFunction, typename TargetInfo>
234std::unique_ptr<IFunction> create_bounding_box_transform_layer(BoundingBoxTransformLayerNode &node)
235{
236 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
237
238 // Extract IO and info
239 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
240 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
241 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
242 const BoundingBoxTransformInfo bbox_info = node.info();
243
244 // Create and configure function
245 auto func = support::cpp14::make_unique<BoundingBoxTransformLayerFunction>();
246 func->configure(input, output, deltas, bbox_info);
247
248 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000249 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
250 << node.name()
251 << " Type: " << node.type()
252 << " Target: " << TargetInfo::TargetType
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100253 << " Data Type: " << input->info()->data_type()
254 << " Shape: " << input->info()->tensor_shape()
255 << " BoundingBox Info img W: " << bbox_info.img_width() << " "
256 << " BoundingBox Info img H: " << bbox_info.img_height() << " "
257 << std::endl);
258
259 return std::move(func);
260}
261
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100262/** Create a backend channel shuffle layer function
263 *
264 * @tparam ChannelShuffleLayerFunction Backend channel shuffle function
265 * @tparam TargetInfo Target-specific information
266 *
267 * @param[in] node Node to create the backend function for
268 *
269 * @return Backend channel shuffle layer function
270 */
271template <typename ChannelShuffleLayerFunction, typename TargetInfo>
272std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
273{
274 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
275
276 // Extract IO and info
277 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
278 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
279 const unsigned int num_groups = node.num_groups();
280
281 // Create function
282 auto func = support::cpp14::make_unique<ChannelShuffleLayerFunction>();
283 func->configure(input, output, num_groups);
284
Pablo Tello32521432018-11-15 14:43:10 +0000285 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
286 << node.name()
287 << " Type: " << node.type()
288 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100289 << " Data Type: " << input->info()->data_type()
290 << " Shape: " << input->info()->tensor_shape()
291 << " Num groups: " << num_groups
292 << std::endl);
293
294 return std::move(func);
295}
296
Georgios Pinitase2220552018-07-20 13:23:44 +0100297/** Create a backend layer concatenate function
298 *
299 * @tparam ConcatenateLayerFunction Backend concatenate function
300 * @tparam TargetInfo Target-specific information
301 *
302 * @param[in] node Node to create the backend function for
303 *
304 * @return Backend concatenate layer function
305 */
306template <typename ConcatenateLayerFunction, typename TargetInfo>
307std::unique_ptr<arm_compute::IFunction> create_concatenate_layer(ConcatenateLayerNode &node)
308{
309 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Concatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
310 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
311
312 // Return nullptr if depth concatenate is switched off
313 if(!node.is_enabled())
314 {
315 return nullptr;
316 }
317
318 // Extract IO and info
319 std::vector<typename TargetInfo::TensorType *> inputs;
320 for(unsigned int i = 0; i < node.num_inputs(); ++i)
321 {
322 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
323 }
324 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100325 const DataLayout data_layout = node.output(0) != nullptr ? node.output(0)->desc().layout : DataLayout::UNKNOWN;
326 const size_t concat_axis = get_dimension_idx(data_layout, node.concatenation_axis());
Georgios Pinitase2220552018-07-20 13:23:44 +0100327
328 // Create and configure function
329 auto func = support::cpp14::make_unique<ConcatenateLayerFunction>();
330 func->configure(inputs, output, concat_axis);
331
332 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000333 const bool is_quantized = is_data_type_quantized_asymmetric(output->info()->data_type());
334 std::ostringstream qss;
335 if(is_quantized)
336 {
337 qss << " Output QuantInfo: " << output->info()->quantization_info();
338 }
Pablo Tello32521432018-11-15 14:43:10 +0000339 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
340 << node.name()
341 << " Type: " << node.type()
342 << " Target: " << TargetInfo::TargetType
Georgios Pinitase2220552018-07-20 13:23:44 +0100343 << " Data Type: " << output->info()->data_type()
344 << " Shape: " << output->info()->tensor_shape()
345 << " Num Inputs: " << inputs.size()
346 << " Axis: " << concat_axis
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000347 << qss.str()
Georgios Pinitase2220552018-07-20 13:23:44 +0100348 << std::endl);
349
350 return std::move(func);
351}
352
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100353/** Create a backend convolution layer function
354 *
355 * @tparam ConvolutionLayerFunctions Backend convolution functions
356 * @tparam TargetInfo Target-specific information
357 *
358 * @param[in] node Node to create the backend function for
359 * @param[in] ctx Graph context
360 *
361 * @return Backend convolution layer function
362 */
363template <typename ConvolutionLayerFunctions, typename TargetInfo>
364std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
365{
366 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
367
368 // Extract IO and info
369 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
370 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
371 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
372 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
373
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100374 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
375
376 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100377 {
378 biases->info()->set_data_type(DataType::S32);
379 }
380
Georgios Pinitas08346e92018-10-16 19:10:46 +0100381 const PadStrideInfo conv_info = node.convolution_info();
382 const unsigned int num_groups = node.num_groups();
383 const ConvolutionMethod conv_algorithm = node.convolution_method();
384 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
385 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100386
387 // Create and configure function (we assume that functions have been validated before creation)
388 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
389 std::unique_ptr<IFunction> func;
390 std::string func_name;
391
Georgios Pinitase2220552018-07-20 13:23:44 +0100392 if(conv_algorithm == ConvolutionMethod::Winograd)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100393 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100394 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "WinogradConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100395 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::WinogradConvolutionLayer>(
396 std::string("WinogradConvolutionLayer"), mm,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100397 input, weights, biases, output, conv_info, fused_act, fast_math);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100398 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100399 else if(conv_algorithm == ConvolutionMethod::Direct)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100400 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100401 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "DirectConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100402 std::tie(func, func_name) = create_named_function<typename ConvolutionLayerFunctions::DirectConvolutionLayer>(
403 std::string("DirectConvolutionLayer"),
Georgios Pinitas08346e92018-10-16 19:10:46 +0100404 input, weights, biases, output, conv_info, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100405 }
406 else if(conv_algorithm == ConvolutionMethod::GEMM)
407 {
408 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GEMMConvolutionLayer>(
409 std::string("GEMMConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100410 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100411 WeightsInfo(), Size2D(1U, 1U), fused_act, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100412 }
413 else
414 {
415 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GenericConvolutionLayer>(
416 std::string("GenericConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100417 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100418 WeightsInfo(), Size2D(1U, 1U), fused_act, fast_math, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100419 }
420
421 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100422 std::ostringstream qss;
423 if(is_quantized)
424 {
425 qss << " Input QuantInfo: " << input->info()->quantization_info()
426 << " Weights QuantInfo: " << weights->info()->quantization_info()
427 << " Output QuantInfo: " << output->info()->quantization_info();
428 }
Pablo Tello32521432018-11-15 14:43:10 +0000429 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
430 << node.name()
431 << " Type: " << func_name
432 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100433 << " Data Type: " << input->info()->data_type()
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100434 << " Groups: " << num_groups
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100435 << " Input shape: " << input->info()->tensor_shape()
436 << " Weights shape: " << weights->info()->tensor_shape()
437 << " Output shape: " << output->info()->tensor_shape()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000438 << qss.str()
Georgios Pinitas08346e92018-10-16 19:10:46 +0100439 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100440 << std::endl);
441 return func;
442}
443
444/** Create a backend deconvolution layer function
445 *
446 * @tparam DeconvolutionLayerFunction Backend deconvolution function
447 * @tparam TargetInfo Target-specific information
448 *
449 * @param[in] node Node to create the backend function for
450 * @param[in] ctx Graph context
451 *
452 * @return Backend deconvolution layer function
453 */
454template <typename DeconvolutionLayerFunction, typename TargetInfo>
455std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
456{
457 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
458
459 // Extract IO and info
460 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
461 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
462 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
463 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
464
465 const PadStrideInfo deconv_info = node.deconvolution_info();
466 const Size2D inner_border = node.inner_border();
467
468 // Create and configure function (we assume that functions have been validated before creation)
469 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
470 std::unique_ptr<IFunction> func;
471
472 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
473 std::string(), mm,
474 input, weights, biases, output, deconv_info, inner_border.x(), inner_border.y());
475
476 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000477 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
478 << node.name()
479 << " Type: " << node.type()
480 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100481 << " Data Type: " << input->info()->data_type()
482 << " Input shape: " << input->info()->tensor_shape()
483 << " Weights shape: " << weights->info()->tensor_shape()
484 << " Output shape: " << output->info()->tensor_shape()
485 << std::endl);
486 return func;
487}
488
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100489/** Create a backend layer depth-wise convolution function
490 *
491 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
492 * @tparam TargetInfo Target-specific information
493 *
494 * @param[in] node Node to create the backend function for
495 *
496 * @return Backend depth-wise convolution layer function
497 */
498template <typename DepthwiseConvolutionLayerFunctions, typename TargetInfo>
499std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
500{
501 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
502
503 // Extract IO and info
504 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
505 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
506 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
507 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
508
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100509 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
510
511 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100512 {
513 biases->info()->set_data_type(DataType::S32);
514 }
515
Georgios Pinitas60e98252018-10-22 16:17:20 +0100516 const PadStrideInfo conv_info = node.convolution_info();
517 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
Georgios Pinitas05045c12018-12-07 18:31:47 +0000518 const unsigned int depth_multiplier = node.depth_multiplier();
Georgios Pinitas60e98252018-10-22 16:17:20 +0100519 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100520
521 // Create and configure function (we assume that functions have been validated before creation)
522 std::unique_ptr<IFunction> func;
523 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100524 if(dwc_algorithm == DepthwiseConvolutionMethod::Optimized3x3)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100525 {
526 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::DepthwiseConvolutionLayer3x3>(
527 std::string("DepthwiseConvolutionLayer3x3"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100528 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100529 }
530 else
531 {
532 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::GenericDepthwiseConvolutionLayer>(
533 std::string("DepthwiseConvolutionLayer"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100534 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100535 }
536
537 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100538 std::ostringstream qss;
539 if(is_quantized)
540 {
541 qss << " Input QuantInfo: " << input->info()->quantization_info()
542 << " Weights QuantInfo: " << weights->info()->quantization_info()
543 << " Output QuantInfo: " << output->info()->quantization_info();
544 }
Pablo Tello32521432018-11-15 14:43:10 +0000545 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
546 << node.name()
547 << " Type: " << func_name
548 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100549 << " Data Type: " << input->info()->data_type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100550 << " Input shape: " << input->info()->tensor_shape()
551 << " Weights shape: " << weights->info()->tensor_shape()
552 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000553 << " Depth multiplier: " << depth_multiplier
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000554 << qss.str()
Georgios Pinitas60e98252018-10-22 16:17:20 +0100555 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100556 << std::endl);
557 return func;
558}
559
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000560/** Create a backend detection output layer function
561 *
562 * @tparam DetectionOutputLayer Function Backend detection output function
563 * @tparam TargetInfo Target-specific information
564 *
565 * @param[in] node Node to create the backend function for
566 *
567 * @return Backend detection output layer function
568 */
569template <typename DetectionOutputLayerFunction, typename TargetInfo>
570std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
571{
572 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
573
574 // Extract IO and info
575 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
576 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
577 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
578 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
579 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
580
581 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
582 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
583 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
584 ARM_COMPUTE_ERROR_ON(output == nullptr);
585
586 // Create and configure function
587 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
588 func->configure(input0, input1, input2, output, detect_info);
589
590 // Log info
591 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
592 << node.name()
593 << " Type: " << node.type()
594 << " Target: " << TargetInfo::TargetType
595 << " Data Type: " << input0->info()->data_type()
596 << " Input0 shape: " << input0->info()->tensor_shape()
597 << " Input1 shape: " << input1->info()->tensor_shape()
598 << " Input2 shape: " << input2->info()->tensor_shape()
599 << " Output shape: " << output->info()->tensor_shape()
600 << " DetectionOutputLayer info: " << detect_info
601 << std::endl);
602
603 return std::move(func);
604}
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100605/** Create a backend element-wise operation layer function
606 *
607 * @tparam EltwiseFunctions Backend element-wise function
608 * @tparam TargetInfo Target-specific information
609 *
610 * @param[in] node Node to create the backend function for
611 *
612 * @return Backend element-wise operation layer function
613 */
614template <typename EltwiseFunctions, typename TargetInfo>
615std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
616{
617 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
618
619 // Extract IO and info
620 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
621 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
622 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
623 const EltwiseOperation eltwise_op = node.eltwise_operation();
624 const ConvertPolicy convert_policy = node.convert_policy();
625 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
626 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
627 ARM_COMPUTE_ERROR_ON(output == nullptr);
628
629 std::unique_ptr<IFunction> func = nullptr;
630 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100631 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100632 {
633 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
634 std::string("ArithmeticAddition"),
635 input1, input2, output, convert_policy);
636 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100637 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100638 {
639 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
640 std::string("ArithmeticSubtraction"),
641 input1, input2, output, convert_policy);
642 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100643 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100644 {
645 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
646 std::string("PixelWiseMultiplication"),
647 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
648 }
649 else
650 {
651 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
652 }
653
654 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000655 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
656 << node.name()
657 << " Type: " << node.type()
658 << " Target: " << TargetInfo::TargetType
659 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100660 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000661 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100662 << std::endl);
663
664 return func;
665}
666
667/** Create a backend flatten layer function
668 *
669 * @tparam FlattenLayerFunction Backend flatten function
670 * @tparam TargetInfo Target-specific information
671 *
672 * @param[in] node Node to create the backend function for
673 *
674 * @return Backend flatten layer function
675 */
676template <typename FlattenLayerFunction, typename TargetInfo>
677std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
678{
679 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
680
681 // Extract IO and info
682 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
683 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
684
Georgios Pinitase2220552018-07-20 13:23:44 +0100685 ARM_COMPUTE_ERROR_ON(input == nullptr);
686 ARM_COMPUTE_ERROR_ON(output == nullptr);
687
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100688 // Create and configure function
689 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
690 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100691
692 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000693 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
694 << node.name()
695 << " Type: " << node.type()
696 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100697 << " Data Type: " << input->info()->data_type()
698 << " Input shape: " << input->info()->tensor_shape()
699 << " Output shape: " << output->info()->tensor_shape()
700 << std::endl);
701
702 return std::move(func);
703}
704
705/** Create a backend fully connected layer function
706 *
707 * @tparam FullyConnectedLayerFunction Backend fully-connected function
708 * @tparam TargetInfo Target-specific information
709 *
710 * @param[in] node Node to create the backend function for
711 * @param[in] ctx Graph context
712 *
713 * @return Backend fully connected layer function
714 */
715template <typename FullyConnectedLayerFunction, typename TargetInfo>
716std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
717{
718 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
719
720 // Extract IO and info
721 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
722 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
723 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
724 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100725 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100726
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100727 ARM_COMPUTE_ERROR_ON(input == nullptr);
728 ARM_COMPUTE_ERROR_ON(weights == nullptr);
729 ARM_COMPUTE_ERROR_ON(output == nullptr);
730
Georgios Pinitase2220552018-07-20 13:23:44 +0100731 // Create and configure function
732 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
733 func->configure(input, weights, biases, output, fc_info);
734
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100735 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
736
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100737 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100738 std::ostringstream qss;
739 if(is_quantized)
740 {
741 qss << " Input QuantInfo: " << input->info()->quantization_info()
742 << " Weights QuantInfo: " << weights->info()->quantization_info()
743 << " Output QuantInfo: " << output->info()->quantization_info();
744 }
Pablo Tello32521432018-11-15 14:43:10 +0000745 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
746 << node.name()
747 << " Type: " << node.type()
748 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100749 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100750 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100751 << " Input shape: " << input->info()->tensor_shape()
752 << " Weights shape: " << weights->info()->tensor_shape()
753 << " Output shape: " << output->info()->tensor_shape()
754 << std::endl);
755
756 return std::move(func);
757}
758
Manuel Bottini5209be52019-02-13 16:34:56 +0000759/** Create a backend generate proposals layer function
760 *
761 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
762 * @tparam TargetInfo Target-specific information
763 *
764 * @param[in] node Node to create the backend function for
765 * @param[in] ctx Graph context
766 *
767 * @return Backend generate proposals layer function
768 */
769template <typename GenerateProposalsLayerFunction, typename TargetInfo>
770std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
771{
772 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
773
774 // Extract IO and info
775 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
776 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
777 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
778 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
779 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
780 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
781 const GenerateProposalsInfo info = node.info();
782
783 ARM_COMPUTE_ERROR_ON(scores == nullptr);
784 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
785 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
786 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
787 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
788
789 // Create and configure function
790 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
791 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
792
793 // Log info
794 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
795 << " Target " << TargetInfo::TargetType
796 << " Data Type: " << scores->info()->data_type()
797 << " Scores shape: " << scores->info()->tensor_shape()
798 << " Deltas shape: " << deltas->info()->tensor_shape()
799 << " Anchors shape: " << anchors->info()->tensor_shape()
800 << " Proposals shape: " << proposals->info()->tensor_shape()
801 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
802 << " Scores Out shape: " << scores_out->info()->tensor_shape()
803 << std::endl);
804
805 return std::move(func);
806}
807
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100808/** Create a backend normalization layer function
809 *
810 * @tparam NormalizationLayerFunction Backend normalization function
811 * @tparam TargetInfo Target-specific information
812 *
813 * @param[in] node Node to create the backend function for
814 * @param[in] ctx Graph context
815 *
816 * @return Backend normalization layer function
817 */
818template <typename NormalizationLayerFunction, typename TargetInfo>
819std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
820{
821 ARM_COMPUTE_UNUSED(ctx);
822
823 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
824
825 // Extract IO and info
826 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
827 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
828 const NormalizationLayerInfo norm_info = node.normalization_info();
829 ARM_COMPUTE_ERROR_ON(input == nullptr);
830 ARM_COMPUTE_ERROR_ON(output == nullptr);
831
832 // Create and configure function
833 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
834 func->configure(input, output, norm_info);
835
836 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000837 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
838 << node.name()
839 << " Type: " << node.type()
840 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100841 << " Data Type: " << input->info()->data_type()
842 << " Input shape: " << input->info()->tensor_shape()
843 << " Output shape: " << output->info()->tensor_shape()
844 << " Normalization info: " << norm_info.type()
845 << std::endl);
846
847 return std::move(func);
848}
849
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100850/** Create a backend normalize planar YUV layer function
851 *
852 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
853 * @tparam TargetInfo Target-specific information
854 *
855 * @param[in] node Node to create the backend function for
856 *
857 * @return Backend normalize plnar YUV layer function
858 */
859template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
860std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
861{
862 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
863
864 // Extract IO and info
865 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
866 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
867 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
868 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
869 ARM_COMPUTE_ERROR_ON(input == nullptr);
870 ARM_COMPUTE_ERROR_ON(mean == nullptr);
871 ARM_COMPUTE_ERROR_ON(std == nullptr);
872 ARM_COMPUTE_ERROR_ON(output == nullptr);
873
874 // Create and configure function
875 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
876 func->configure(input, output, mean, std);
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
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100883 << " Data Type: " << input->info()->data_type()
884 << " Shape: " << input->info()->tensor_shape()
885 << std::endl);
886
887 return std::move(func);
888}
889
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100890/** Create a backend pad layer function
891 *
892 * @tparam PadLayerFunction Backend pad function
893 * @tparam TargetInfo Target-specific information
894 *
895 * @param[in] node Node to create the backend function for
896 *
897 * @return Backend pad layer function
898 */
899template <typename PadLayerFunction, typename TargetInfo>
900std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
901{
902 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
903
904 // Extract IO and info
905 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
906 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
907 const PaddingList &padding = node.padding();
908 ARM_COMPUTE_ERROR_ON(input == nullptr);
909 ARM_COMPUTE_ERROR_ON(output == nullptr);
910
911 // Create and configure function
912 auto func = support::cpp14::make_unique<PadLayerFunction>();
913 func->configure(input, output, padding);
914
915 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000916 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
917 << node.name()
918 << " Type: " << node.type()
919 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100920 << " Data Type: " << input->info()->data_type()
921 << " Input shape: " << input->info()->tensor_shape()
922 << " Output shape: " << output->info()->tensor_shape()
923 << std::endl);
924
925 return std::move(func);
926}
927
Georgios Pinitas57c48242018-08-02 13:41:49 +0100928/** Create a backend permute layer function
929 *
930 * @tparam PermuteLayerFunction Backend permute function
931 * @tparam TargetInfo Target-specific information
932 *
933 * @param[in] node Node to create the backend function for
934 *
935 * @return Backend permute layer function
936 */
937template <typename PermuteLayerFunction, typename TargetInfo>
938std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
939{
940 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
941
942 // Extract IO and info
943 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
944 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
945 const PermutationVector &perm = node.permutation_vector();
946 ARM_COMPUTE_ERROR_ON(input == nullptr);
947 ARM_COMPUTE_ERROR_ON(output == nullptr);
948
949 // Create and configure function
950 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
951 func->configure(input, output, perm);
952
953 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000954 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
955 << node.name()
956 << " Type: " << node.type()
957 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +0100958 << " Data Type: " << input->info()->data_type()
959 << " Input shape: " << input->info()->tensor_shape()
960 << " Output shape: " << output->info()->tensor_shape()
961 << " Permutation vector: " << perm
962 << std::endl);
963
964 return std::move(func);
965}
966
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100967/** Create a backend pooling layer function
968 *
969 * @tparam PoolingLayerFunction Backend pooling function
970 * @tparam TargetInfo Target-specific information
971 *
972 * @param[in] node Node to create the backend function for
973 *
974 * @return Backend pooling layer function
975 */
976template <typename PoolingLayerFunction, typename TargetInfo>
977std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
978{
979 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
980
981 // Extract IO and info
982 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
983 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
984 const PoolingLayerInfo pool_info = node.pooling_info();
985 ARM_COMPUTE_ERROR_ON(input == nullptr);
986 ARM_COMPUTE_ERROR_ON(output == nullptr);
987
988 // Create and configure function
989 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
990 func->configure(input, output, pool_info);
991
992 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000993 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
994 << node.name()
995 << " Type: " << node.type()
996 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100997 << " Data Type: " << input->info()->data_type()
998 << " Input shape: " << input->info()->tensor_shape()
999 << " Output shape: " << output->info()->tensor_shape()
1000 << " Pooling info: " << pool_info.pool_type()
1001 << std::endl);
1002
1003 return std::move(func);
1004}
1005
Pablo Tello32521432018-11-15 14:43:10 +00001006/** Create a backend priorbox layer function
1007 *
1008 * @tparam PriorBoxLayerFunction Backend priorbox function
1009 * @tparam TargetInfo Target-specific information
1010 *
1011 * @param[in] node Node to create the backend function for
1012 *
1013 * @return Backend priorbox layer function
1014 */
1015template <typename PriorBoxLayerFunction, typename TargetInfo>
1016std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1017{
1018 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1019
1020 // Extract IO and info
1021 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1022 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1023 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1024 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1025 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1026 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1027 ARM_COMPUTE_ERROR_ON(output == nullptr);
1028
1029 // Create and configure function
1030 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1031 func->configure(input0, input1, output, prior_info);
1032
1033 // Log info
1034 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1035 << node.name()
1036 << " Type: " << node.type()
1037 << " Target: " << TargetInfo::TargetType
1038 << " Data Type: " << input0->info()->data_type()
1039 << " Input0 shape: " << input0->info()->tensor_shape()
1040 << " Input1 shape: " << input1->info()->tensor_shape()
1041 << " Output shape: " << output->info()->tensor_shape()
1042 << " PriorBoxLayer info: " << prior_info
1043 << std::endl);
1044
1045 return std::move(func);
1046}
1047
Isabella Gottardi3db1ba92019-05-17 12:35:20 +01001048/** Create a backend quantization layer function
1049 *
1050 * @tparam QuantizationLayerFunction Backend quantization function
1051 * @tparam TargetInfo Target-specific information
1052 *
1053 * @param[in] node Node to create the backend function for
1054 *
1055 * @return Backend quantization layer function
1056 */
1057template <typename QuantizationLayerFunction, typename TargetInfo>
1058std::unique_ptr<IFunction> create_quantization_layer(QuantizationLayerNode &node)
1059{
1060 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1061
1062 // Extract IO and info
1063 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1064 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1065 ARM_COMPUTE_ERROR_ON(input == nullptr);
1066 ARM_COMPUTE_ERROR_ON(output == nullptr);
1067
1068 // Create and configure function
1069 auto func = support::cpp14::make_unique<QuantizationLayerFunction>();
1070 func->configure(input, output);
1071
1072 // Log info
1073 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1074 << node.name()
1075 << " Type: " << node.type()
1076 << " Target: " << TargetInfo::TargetType
1077 << " Data Type: " << input->info()->data_type()
1078 << " Input shape: " << input->info()->tensor_shape()
1079 << " Output shape: " << output->info()->tensor_shape()
1080 << std::endl);
1081
1082 return std::move(func);
1083}
1084
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001085/** Create a backend reorg layer function
1086 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001087 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001088 * @tparam TargetInfo Target-specific information
1089 *
1090 * @param[in] node Node to create the backend function for
1091 *
1092 * @return Backend reshape layer function
1093 */
1094template <typename ReorgLayerFunction, typename TargetInfo>
1095std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
1096{
1097 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1098
1099 // Extract IO and info
1100 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1101 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1102 ARM_COMPUTE_ERROR_ON(input == nullptr);
1103 ARM_COMPUTE_ERROR_ON(output == nullptr);
1104
1105 // Create and configure function
1106 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
1107 func->configure(input, output, node.stride());
1108
1109 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001110 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1111 << node.name()
1112 << " Type: " << node.type()
1113 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001114 << " Data Type: " << input->info()->data_type()
1115 << " Input shape: " << input->info()->tensor_shape()
1116 << " Output shape: " << output->info()->tensor_shape()
1117 << std::endl);
1118
1119 return std::move(func);
1120}
1121
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001122/** Create a backend reshape layer function
1123 *
1124 * @tparam ReshapeLayerFunction Backend reshape function
1125 * @tparam TargetInfo Target-specific information
1126 *
1127 * @param[in] node Node to create the backend function for
1128 *
1129 * @return Backend reshape layer function
1130 */
1131template <typename ReshapeLayerFunction, typename TargetInfo>
1132std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1133{
1134 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1135
1136 // Extract IO and info
1137 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1138 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1139 ARM_COMPUTE_ERROR_ON(input == nullptr);
1140 ARM_COMPUTE_ERROR_ON(output == nullptr);
1141
1142 // Create and configure function
1143 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1144 func->configure(input, output);
1145
1146 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001147 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1148 << node.name()
1149 << " Type: " << node.type()
1150 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001151 << " Data Type: " << input->info()->data_type()
1152 << " Input shape: " << input->info()->tensor_shape()
1153 << " Output shape: " << output->info()->tensor_shape()
1154 << std::endl);
1155
1156 return std::move(func);
1157}
1158
1159/** Create a backend resize layer function
1160 *
1161 * @tparam ResizeLayerFunction Backend resize function
1162 * @tparam TargetInfo Target-specific information
1163 *
1164 * @param[in] node Node to create the backend function for
1165 *
1166 * @return Backend resize layer function
1167 */
1168template <typename ResizeLayerFunction, typename TargetInfo>
1169std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1170{
1171 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1172
1173 // Extract IO and info
1174 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1175 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1176 ARM_COMPUTE_ERROR_ON(input == nullptr);
1177 ARM_COMPUTE_ERROR_ON(output == nullptr);
1178 const InterpolationPolicy policy = node.policy();
1179
1180 // Create and configure function
1181 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1182 func->configure(input, output, policy, BorderMode::CONSTANT);
1183
1184 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001185 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1186 << node.name()
1187 << " Type: " << node.type()
1188 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001189 << " Data Type: " << input->info()->data_type()
1190 << " Input shape: " << input->info()->tensor_shape()
1191 << " Output shape: " << output->info()->tensor_shape()
1192 << " Interpolation: " << policy
1193 << std::endl);
1194
1195 return std::move(func);
1196}
1197
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001198/** Create a backend ROI align layer function
1199 *
1200 * @tparam ROIAlignLayerFunction ROI Align function
1201 * @tparam TargetInfo Target-specific information
1202 *
1203 * @param[in] node Node to create the backend function for
1204 *
1205 * @return ROI Align layer function
1206 */
1207template <typename ROIAlignLayerFunction, typename TargetInfo>
1208std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1209{
1210 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1211
1212 // Extract IO and info
1213 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1214 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1215 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1216 ARM_COMPUTE_ERROR_ON(input == nullptr);
1217 ARM_COMPUTE_ERROR_ON(output == nullptr);
1218 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1219
1220 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1221
1222 // Create and configure function
1223 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1224
1225 func->configure(input, rois, output, pool_info);
1226
1227 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +00001228 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1229 << node.name()
1230 << " Type: " << node.type()
1231 << " Target: " << TargetInfo::TargetType
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001232 << " Data Type: " << input->info()->data_type()
1233 << " Input shape: " << input->info()->tensor_shape()
1234 << " Output shape: " << output->info()->tensor_shape()
1235 << " ROIs shape: " << rois->info()->tensor_shape()
1236 << " ROIPooling width: " << pool_info.pooled_width()
1237 << " ROIPooling height: " << pool_info.pooled_height()
1238 << std::endl);
1239
1240 return std::move(func);
1241}
1242
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001243/** Create a backend slice layer function
1244 *
1245 * @tparam SliceLayerFunction Backend slice function
1246 * @tparam TargetInfo Target-specific information
1247 *
1248 * @param[in] node Node to create the backend function for
1249 *
1250 * @return Backend slice layer function
1251 */
1252template <typename SliceLayerFunction, typename TargetInfo>
1253std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1254{
1255 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1256
1257 // Extract IO and info
1258 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1259 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1260 ARM_COMPUTE_ERROR_ON(input == nullptr);
1261 ARM_COMPUTE_ERROR_ON(output == nullptr);
1262
1263 // Create and configure function
1264 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1265 func->configure(input, output, node.starts(), node.ends());
1266
1267 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001268 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1269 << node.name()
1270 << " Type: " << node.type()
1271 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001272 << " Data Type: " << input->info()->data_type()
1273 << " Input shape: " << input->info()->tensor_shape()
1274 << " Output shape: " << output->info()->tensor_shape()
1275 << std::endl);
1276
1277 return std::move(func);
1278}
1279
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001280/** Create a backend softmax layer function
1281 *
1282 * @tparam SoftmaxLayerFunction Backend softmax function
1283 * @tparam TargetInfo Target-specific information
1284 *
1285 * @param[in] node Node to create the backend function for
1286 * @param[in] ctx Graph context
1287 *
1288 * @return Backend softmax layer function
1289 */
1290template <typename SoftmaxLayerFunction, typename TargetInfo>
1291std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1292{
1293 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1294
1295 // Extract IO and info
1296 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1297 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1298 const float beta = node.beta();
1299 ARM_COMPUTE_ERROR_ON(input == nullptr);
1300 ARM_COMPUTE_ERROR_ON(output == nullptr);
1301
1302 // Create and configure function
1303 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1304 func->configure(input, output, beta);
1305
1306 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001307 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1308 << node.name()
1309 << " Type: " << node.type()
1310 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001311 << " Data Type: " << input->info()->data_type()
1312 << " Input shape: " << input->info()->tensor_shape()
1313 << " Output shape: " << output->info()->tensor_shape()
1314 << std::endl);
1315
1316 return std::move(func);
1317}
Michele Di Giorgioec699752019-03-22 15:25:32 +00001318
1319/** Create a backend layer stack function
1320 *
1321 * @tparam StackLayerFunction Backend stack function
1322 * @tparam TargetInfo Target-specific information
1323 *
1324 * @param[in] node Node to create the backend function for
1325 *
1326 * @return Backend stack layer function
1327 */
1328template <typename StackLayerFunction, typename TargetInfo>
1329std::unique_ptr<arm_compute::IFunction> create_stack_layer(StackLayerNode &node)
1330{
1331 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Stack node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
1332 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
1333
1334 // Extract IO and info
1335 std::vector<typename TargetInfo::TensorType *> inputs;
1336 for(unsigned int i = 0; i < node.num_inputs(); ++i)
1337 {
1338 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
1339 }
1340 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1341 const int axis = node.axis();
1342
1343 // Create and configure function
1344 auto func = support::cpp14::make_unique<StackLayerFunction>();
1345 func->configure(inputs, axis, output);
1346
1347 // Log info
1348 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1349 << node.name()
1350 << " Type: " << node.type()
1351 << " Target: " << TargetInfo::TargetType
1352 << " Data Type: " << output->info()->data_type()
1353 << " Inputs shape: " << inputs[0]->info()->tensor_shape()
1354 << " Output shape: " << output->info()->tensor_shape()
1355 << " Num Inputs: " << inputs.size()
1356 << " Axis: " << axis
1357 << std::endl);
1358
1359 return std::move(func);
1360}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001361/** Create a backend Upsample layer function
1362 *
1363 * @tparam UpsampleLayerFunction Backend Upsample function
1364 * @tparam TargetInfo Target-specific information
1365 *
1366 * @param[in] node Node to create the backend function for
1367 * @param[in] ctx Graph context
1368 *
1369 * @return Backend Upsample layer function
1370 */
1371template <typename UpsampleLayerFunction, typename TargetInfo>
1372std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1373{
1374 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1375
1376 // Extract IO and info
1377 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1378 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1379 const Size2D info = node.info();
1380 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1381 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1382 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1383 ARM_COMPUTE_ERROR_ON(input == nullptr);
1384 ARM_COMPUTE_ERROR_ON(output == nullptr);
1385
1386 // Create and configure function
1387 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1388 func->configure(input, output, info, upsampling_policy);
1389
1390 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001391 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1392 << node.name()
1393 << " Type: " << node.type()
1394 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001395 << " Data Type: " << input->info()->data_type()
1396 << " Input shape: " << input->info()->tensor_shape()
1397 << " Output shape: " << output->info()->tensor_shape()
1398 << " Strides: " << info
1399 << " Upsampling policy: " << upsampling_policy
1400 << std::endl);
1401
1402 return std::move(func);
1403}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001404/** Create a backend YOLO layer function
1405 *
1406 * @tparam YoloLayerFunction Backend YOLO function
1407 * @tparam TargetInfo Target-specific information
1408 *
1409 * @param[in] node Node to create the backend function for
1410 * @param[in] ctx Graph context
1411 *
1412 * @return Backend YOLO layer function
1413 */
1414template <typename YOLOlayerFunction, typename TargetInfo>
1415std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1416{
1417 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1418
1419 // Extract IO and info
1420 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1421 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1422 const ActivationLayerInfo act_info = node.activation_info();
1423 const int32_t num_classes = node.num_classes();
1424 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
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<YOLOlayerFunction>();
1430 func->configure(input, output, act_info, num_classes);
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 Spyrou96f67692018-09-13 11:39:28 +01001437 << " Data Type: " << input->info()->data_type()
1438 << " Input shape: " << input->info()->tensor_shape()
1439 << " Output shape: " << output->info()->tensor_shape()
1440 << " Activation function: " << act_info.activation()
1441 << " Num classes: " << num_classes
1442 << std::endl);
1443
1444 return std::move(func);
1445}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001446} // namespace detail
1447} // namespace backends
1448} // namespace graph
1449} // namespace arm_compute
1450
1451#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */