blob: 5ac4fdaed9b6aa994b86c559309e878718205b48 [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
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100465 const PadStrideInfo deconv_info = node.deconvolution_info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100466
467 // Create and configure function (we assume that functions have been validated before creation)
468 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
469 std::unique_ptr<IFunction> func;
470
471 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
472 std::string(), mm,
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100473 input, weights, biases, output, deconv_info);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100474
475 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000476 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
477 << node.name()
478 << " Type: " << node.type()
479 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100480 << " Data Type: " << input->info()->data_type()
481 << " Input shape: " << input->info()->tensor_shape()
482 << " Weights shape: " << weights->info()->tensor_shape()
483 << " Output shape: " << output->info()->tensor_shape()
484 << std::endl);
485 return func;
486}
487
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100488/** Create a backend layer depth-wise convolution function
489 *
490 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
491 * @tparam TargetInfo Target-specific information
492 *
493 * @param[in] node Node to create the backend function for
494 *
495 * @return Backend depth-wise convolution layer function
496 */
497template <typename DepthwiseConvolutionLayerFunctions, typename TargetInfo>
498std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
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
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100508 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
509
510 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100511 {
512 biases->info()->set_data_type(DataType::S32);
513 }
514
Georgios Pinitas60e98252018-10-22 16:17:20 +0100515 const PadStrideInfo conv_info = node.convolution_info();
516 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
Georgios Pinitas05045c12018-12-07 18:31:47 +0000517 const unsigned int depth_multiplier = node.depth_multiplier();
Georgios Pinitas60e98252018-10-22 16:17:20 +0100518 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100519
520 // Create and configure function (we assume that functions have been validated before creation)
521 std::unique_ptr<IFunction> func;
522 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100523 if(dwc_algorithm == DepthwiseConvolutionMethod::Optimized3x3)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100524 {
Georgios Pinitas30271c72019-06-24 14:56:34 +0100525 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::OptimizedDepthwiseConvolutionLayer>(
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100526 std::string("DepthwiseConvolutionLayer3x3"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100527 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100528 }
529 else
530 {
531 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::GenericDepthwiseConvolutionLayer>(
532 std::string("DepthwiseConvolutionLayer"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100533 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100534 }
535
536 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100537 std::ostringstream qss;
538 if(is_quantized)
539 {
540 qss << " Input QuantInfo: " << input->info()->quantization_info()
541 << " Weights QuantInfo: " << weights->info()->quantization_info()
542 << " Output QuantInfo: " << output->info()->quantization_info();
543 }
Pablo Tello32521432018-11-15 14:43:10 +0000544 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
545 << node.name()
546 << " Type: " << func_name
547 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100548 << " Data Type: " << input->info()->data_type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100549 << " Input shape: " << input->info()->tensor_shape()
550 << " Weights shape: " << weights->info()->tensor_shape()
551 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000552 << " Depth multiplier: " << depth_multiplier
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000553 << qss.str()
Georgios Pinitas60e98252018-10-22 16:17:20 +0100554 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100555 << std::endl);
556 return func;
557}
558
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000559/** Create a backend detection output layer function
560 *
561 * @tparam DetectionOutputLayer Function Backend detection output function
562 * @tparam TargetInfo Target-specific information
563 *
564 * @param[in] node Node to create the backend function for
565 *
566 * @return Backend detection output layer function
567 */
568template <typename DetectionOutputLayerFunction, typename TargetInfo>
569std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
570{
571 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
572
573 // Extract IO and info
574 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
575 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
576 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
577 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
578 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
579
580 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
581 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
582 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
583 ARM_COMPUTE_ERROR_ON(output == nullptr);
584
585 // Create and configure function
586 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
587 func->configure(input0, input1, input2, output, detect_info);
588
589 // Log info
590 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
591 << node.name()
592 << " Type: " << node.type()
593 << " Target: " << TargetInfo::TargetType
594 << " Data Type: " << input0->info()->data_type()
595 << " Input0 shape: " << input0->info()->tensor_shape()
596 << " Input1 shape: " << input1->info()->tensor_shape()
597 << " Input2 shape: " << input2->info()->tensor_shape()
598 << " Output shape: " << output->info()->tensor_shape()
599 << " DetectionOutputLayer info: " << detect_info
600 << std::endl);
601
602 return std::move(func);
603}
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100604/** Create a backend element-wise operation layer function
605 *
606 * @tparam EltwiseFunctions Backend element-wise function
607 * @tparam TargetInfo Target-specific information
608 *
609 * @param[in] node Node to create the backend function for
610 *
611 * @return Backend element-wise operation layer function
612 */
613template <typename EltwiseFunctions, typename TargetInfo>
614std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
615{
616 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
617
618 // Extract IO and info
619 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
620 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
621 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
622 const EltwiseOperation eltwise_op = node.eltwise_operation();
623 const ConvertPolicy convert_policy = node.convert_policy();
624 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
625 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
626 ARM_COMPUTE_ERROR_ON(output == nullptr);
627
628 std::unique_ptr<IFunction> func = nullptr;
629 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100630 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100631 {
632 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
633 std::string("ArithmeticAddition"),
634 input1, input2, output, convert_policy);
635 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100636 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100637 {
638 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
639 std::string("ArithmeticSubtraction"),
640 input1, input2, output, convert_policy);
641 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100642 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100643 {
644 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
645 std::string("PixelWiseMultiplication"),
646 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
647 }
648 else
649 {
650 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
651 }
652
653 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000654 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
655 << node.name()
656 << " Type: " << node.type()
657 << " Target: " << TargetInfo::TargetType
658 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100659 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000660 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100661 << std::endl);
662
663 return func;
664}
665
666/** Create a backend flatten layer function
667 *
668 * @tparam FlattenLayerFunction Backend flatten function
669 * @tparam TargetInfo Target-specific information
670 *
671 * @param[in] node Node to create the backend function for
672 *
673 * @return Backend flatten layer function
674 */
675template <typename FlattenLayerFunction, typename TargetInfo>
676std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
677{
678 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
679
680 // Extract IO and info
681 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
682 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
683
Georgios Pinitase2220552018-07-20 13:23:44 +0100684 ARM_COMPUTE_ERROR_ON(input == nullptr);
685 ARM_COMPUTE_ERROR_ON(output == nullptr);
686
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100687 // Create and configure function
688 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
689 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100690
691 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000692 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
693 << node.name()
694 << " Type: " << node.type()
695 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100696 << " Data Type: " << input->info()->data_type()
697 << " Input shape: " << input->info()->tensor_shape()
698 << " Output shape: " << output->info()->tensor_shape()
699 << std::endl);
700
701 return std::move(func);
702}
703
704/** Create a backend fully connected layer function
705 *
706 * @tparam FullyConnectedLayerFunction Backend fully-connected function
707 * @tparam TargetInfo Target-specific information
708 *
709 * @param[in] node Node to create the backend function for
710 * @param[in] ctx Graph context
711 *
712 * @return Backend fully connected layer function
713 */
714template <typename FullyConnectedLayerFunction, typename TargetInfo>
715std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
716{
717 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
718
719 // Extract IO and info
720 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
721 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
722 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
723 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100724 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100725
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100726 ARM_COMPUTE_ERROR_ON(input == nullptr);
727 ARM_COMPUTE_ERROR_ON(weights == nullptr);
728 ARM_COMPUTE_ERROR_ON(output == nullptr);
729
Georgios Pinitase2220552018-07-20 13:23:44 +0100730 // Create and configure function
731 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
732 func->configure(input, weights, biases, output, fc_info);
733
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100734 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
735
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100736 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100737 std::ostringstream qss;
738 if(is_quantized)
739 {
740 qss << " Input QuantInfo: " << input->info()->quantization_info()
741 << " Weights QuantInfo: " << weights->info()->quantization_info()
742 << " Output QuantInfo: " << output->info()->quantization_info();
743 }
Pablo Tello32521432018-11-15 14:43:10 +0000744 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
745 << node.name()
746 << " Type: " << node.type()
747 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100748 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100749 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100750 << " Input shape: " << input->info()->tensor_shape()
751 << " Weights shape: " << weights->info()->tensor_shape()
752 << " Output shape: " << output->info()->tensor_shape()
753 << std::endl);
754
755 return std::move(func);
756}
757
Manuel Bottini5209be52019-02-13 16:34:56 +0000758/** Create a backend generate proposals layer function
759 *
760 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
761 * @tparam TargetInfo Target-specific information
762 *
763 * @param[in] node Node to create the backend function for
764 * @param[in] ctx Graph context
765 *
766 * @return Backend generate proposals layer function
767 */
768template <typename GenerateProposalsLayerFunction, typename TargetInfo>
769std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
770{
771 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
772
773 // Extract IO and info
774 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
775 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
776 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
777 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
778 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
779 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
780 const GenerateProposalsInfo info = node.info();
781
782 ARM_COMPUTE_ERROR_ON(scores == nullptr);
783 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
784 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
785 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
786 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
787
788 // Create and configure function
789 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
790 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
791
792 // Log info
793 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
794 << " Target " << TargetInfo::TargetType
795 << " Data Type: " << scores->info()->data_type()
796 << " Scores shape: " << scores->info()->tensor_shape()
797 << " Deltas shape: " << deltas->info()->tensor_shape()
798 << " Anchors shape: " << anchors->info()->tensor_shape()
799 << " Proposals shape: " << proposals->info()->tensor_shape()
800 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
801 << " Scores Out shape: " << scores_out->info()->tensor_shape()
802 << std::endl);
803
804 return std::move(func);
805}
806
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100807/** Create a backend normalization layer function
808 *
809 * @tparam NormalizationLayerFunction Backend normalization function
810 * @tparam TargetInfo Target-specific information
811 *
812 * @param[in] node Node to create the backend function for
813 * @param[in] ctx Graph context
814 *
815 * @return Backend normalization layer function
816 */
817template <typename NormalizationLayerFunction, typename TargetInfo>
818std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
819{
820 ARM_COMPUTE_UNUSED(ctx);
821
822 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
823
824 // Extract IO and info
825 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
826 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
827 const NormalizationLayerInfo norm_info = node.normalization_info();
828 ARM_COMPUTE_ERROR_ON(input == nullptr);
829 ARM_COMPUTE_ERROR_ON(output == nullptr);
830
831 // Create and configure function
832 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
833 func->configure(input, output, norm_info);
834
835 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000836 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
837 << node.name()
838 << " Type: " << node.type()
839 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100840 << " Data Type: " << input->info()->data_type()
841 << " Input shape: " << input->info()->tensor_shape()
842 << " Output shape: " << output->info()->tensor_shape()
843 << " Normalization info: " << norm_info.type()
844 << std::endl);
845
846 return std::move(func);
847}
848
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100849/** Create a backend normalize planar YUV layer function
850 *
851 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
852 * @tparam TargetInfo Target-specific information
853 *
854 * @param[in] node Node to create the backend function for
855 *
856 * @return Backend normalize plnar YUV layer function
857 */
858template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
859std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
860{
861 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
862
863 // Extract IO and info
864 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
865 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
866 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
867 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
868 ARM_COMPUTE_ERROR_ON(input == nullptr);
869 ARM_COMPUTE_ERROR_ON(mean == nullptr);
870 ARM_COMPUTE_ERROR_ON(std == nullptr);
871 ARM_COMPUTE_ERROR_ON(output == nullptr);
872
873 // Create and configure function
874 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
875 func->configure(input, output, mean, std);
876
877 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000878 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
879 << node.name()
880 << " Type: " << node.type()
881 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100882 << " Data Type: " << input->info()->data_type()
883 << " Shape: " << input->info()->tensor_shape()
884 << std::endl);
885
886 return std::move(func);
887}
888
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100889/** Create a backend pad layer function
890 *
891 * @tparam PadLayerFunction Backend pad function
892 * @tparam TargetInfo Target-specific information
893 *
894 * @param[in] node Node to create the backend function for
895 *
896 * @return Backend pad layer function
897 */
898template <typename PadLayerFunction, typename TargetInfo>
899std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
900{
901 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
902
903 // Extract IO and info
904 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
905 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
906 const PaddingList &padding = node.padding();
907 ARM_COMPUTE_ERROR_ON(input == nullptr);
908 ARM_COMPUTE_ERROR_ON(output == nullptr);
909
910 // Create and configure function
911 auto func = support::cpp14::make_unique<PadLayerFunction>();
912 func->configure(input, output, padding);
913
914 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000915 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
916 << node.name()
917 << " Type: " << node.type()
918 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100919 << " Data Type: " << input->info()->data_type()
920 << " Input shape: " << input->info()->tensor_shape()
921 << " Output shape: " << output->info()->tensor_shape()
922 << std::endl);
923
924 return std::move(func);
925}
926
Georgios Pinitas57c48242018-08-02 13:41:49 +0100927/** Create a backend permute layer function
928 *
929 * @tparam PermuteLayerFunction Backend permute function
930 * @tparam TargetInfo Target-specific information
931 *
932 * @param[in] node Node to create the backend function for
933 *
934 * @return Backend permute layer function
935 */
936template <typename PermuteLayerFunction, typename TargetInfo>
937std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
938{
939 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
940
941 // Extract IO and info
942 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
943 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
944 const PermutationVector &perm = node.permutation_vector();
945 ARM_COMPUTE_ERROR_ON(input == nullptr);
946 ARM_COMPUTE_ERROR_ON(output == nullptr);
947
948 // Create and configure function
949 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
950 func->configure(input, output, perm);
951
952 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000953 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
954 << node.name()
955 << " Type: " << node.type()
956 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +0100957 << " Data Type: " << input->info()->data_type()
958 << " Input shape: " << input->info()->tensor_shape()
959 << " Output shape: " << output->info()->tensor_shape()
960 << " Permutation vector: " << perm
961 << std::endl);
962
963 return std::move(func);
964}
965
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100966/** Create a backend pooling layer function
967 *
968 * @tparam PoolingLayerFunction Backend pooling function
969 * @tparam TargetInfo Target-specific information
970 *
971 * @param[in] node Node to create the backend function for
972 *
973 * @return Backend pooling layer function
974 */
975template <typename PoolingLayerFunction, typename TargetInfo>
976std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
977{
978 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
979
980 // Extract IO and info
981 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
982 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
983 const PoolingLayerInfo pool_info = node.pooling_info();
984 ARM_COMPUTE_ERROR_ON(input == nullptr);
985 ARM_COMPUTE_ERROR_ON(output == nullptr);
986
987 // Create and configure function
988 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
989 func->configure(input, output, pool_info);
990
991 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000992 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
993 << node.name()
994 << " Type: " << node.type()
995 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100996 << " Data Type: " << input->info()->data_type()
997 << " Input shape: " << input->info()->tensor_shape()
998 << " Output shape: " << output->info()->tensor_shape()
999 << " Pooling info: " << pool_info.pool_type()
1000 << std::endl);
1001
1002 return std::move(func);
1003}
1004
Pablo Tello32521432018-11-15 14:43:10 +00001005/** Create a backend priorbox layer function
1006 *
1007 * @tparam PriorBoxLayerFunction Backend priorbox function
1008 * @tparam TargetInfo Target-specific information
1009 *
1010 * @param[in] node Node to create the backend function for
1011 *
1012 * @return Backend priorbox layer function
1013 */
1014template <typename PriorBoxLayerFunction, typename TargetInfo>
1015std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1016{
1017 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1018
1019 // Extract IO and info
1020 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1021 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1022 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1023 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1024 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1025 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1026 ARM_COMPUTE_ERROR_ON(output == nullptr);
1027
1028 // Create and configure function
1029 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1030 func->configure(input0, input1, output, prior_info);
1031
1032 // Log info
1033 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1034 << node.name()
1035 << " Type: " << node.type()
1036 << " Target: " << TargetInfo::TargetType
1037 << " Data Type: " << input0->info()->data_type()
1038 << " Input0 shape: " << input0->info()->tensor_shape()
1039 << " Input1 shape: " << input1->info()->tensor_shape()
1040 << " Output shape: " << output->info()->tensor_shape()
1041 << " PriorBoxLayer info: " << prior_info
1042 << std::endl);
1043
1044 return std::move(func);
1045}
1046
Isabella Gottardi3db1ba92019-05-17 12:35:20 +01001047/** Create a backend quantization layer function
1048 *
1049 * @tparam QuantizationLayerFunction Backend quantization function
1050 * @tparam TargetInfo Target-specific information
1051 *
1052 * @param[in] node Node to create the backend function for
1053 *
1054 * @return Backend quantization layer function
1055 */
1056template <typename QuantizationLayerFunction, typename TargetInfo>
1057std::unique_ptr<IFunction> create_quantization_layer(QuantizationLayerNode &node)
1058{
1059 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1060
1061 // Extract IO and info
1062 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1063 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1064 ARM_COMPUTE_ERROR_ON(input == nullptr);
1065 ARM_COMPUTE_ERROR_ON(output == nullptr);
1066
1067 // Create and configure function
1068 auto func = support::cpp14::make_unique<QuantizationLayerFunction>();
1069 func->configure(input, output);
1070
1071 // Log info
1072 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1073 << node.name()
1074 << " Type: " << node.type()
1075 << " Target: " << TargetInfo::TargetType
1076 << " Data Type: " << input->info()->data_type()
1077 << " Input shape: " << input->info()->tensor_shape()
1078 << " Output shape: " << output->info()->tensor_shape()
1079 << std::endl);
1080
1081 return std::move(func);
1082}
1083
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001084/** Create a backend reorg layer function
1085 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001086 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001087 * @tparam TargetInfo Target-specific information
1088 *
1089 * @param[in] node Node to create the backend function for
1090 *
1091 * @return Backend reshape layer function
1092 */
1093template <typename ReorgLayerFunction, typename TargetInfo>
1094std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
1095{
1096 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1097
1098 // Extract IO and info
1099 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1100 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1101 ARM_COMPUTE_ERROR_ON(input == nullptr);
1102 ARM_COMPUTE_ERROR_ON(output == nullptr);
1103
1104 // Create and configure function
1105 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
1106 func->configure(input, output, node.stride());
1107
1108 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001109 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1110 << node.name()
1111 << " Type: " << node.type()
1112 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001113 << " Data Type: " << input->info()->data_type()
1114 << " Input shape: " << input->info()->tensor_shape()
1115 << " Output shape: " << output->info()->tensor_shape()
1116 << std::endl);
1117
1118 return std::move(func);
1119}
1120
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001121/** Create a backend reshape layer function
1122 *
1123 * @tparam ReshapeLayerFunction Backend reshape function
1124 * @tparam TargetInfo Target-specific information
1125 *
1126 * @param[in] node Node to create the backend function for
1127 *
1128 * @return Backend reshape layer function
1129 */
1130template <typename ReshapeLayerFunction, typename TargetInfo>
1131std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1132{
1133 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1134
1135 // Extract IO and info
1136 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1137 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1138 ARM_COMPUTE_ERROR_ON(input == nullptr);
1139 ARM_COMPUTE_ERROR_ON(output == nullptr);
1140
1141 // Create and configure function
1142 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1143 func->configure(input, output);
1144
1145 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001146 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1147 << node.name()
1148 << " Type: " << node.type()
1149 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001150 << " Data Type: " << input->info()->data_type()
1151 << " Input shape: " << input->info()->tensor_shape()
1152 << " Output shape: " << output->info()->tensor_shape()
1153 << std::endl);
1154
1155 return std::move(func);
1156}
1157
1158/** Create a backend resize layer function
1159 *
1160 * @tparam ResizeLayerFunction Backend resize function
1161 * @tparam TargetInfo Target-specific information
1162 *
1163 * @param[in] node Node to create the backend function for
1164 *
1165 * @return Backend resize layer function
1166 */
1167template <typename ResizeLayerFunction, typename TargetInfo>
1168std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1169{
1170 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1171
1172 // Extract IO and info
1173 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1174 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1175 ARM_COMPUTE_ERROR_ON(input == nullptr);
1176 ARM_COMPUTE_ERROR_ON(output == nullptr);
1177 const InterpolationPolicy policy = node.policy();
1178
1179 // Create and configure function
1180 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1181 func->configure(input, output, policy, BorderMode::CONSTANT);
1182
1183 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001184 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1185 << node.name()
1186 << " Type: " << node.type()
1187 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001188 << " Data Type: " << input->info()->data_type()
1189 << " Input shape: " << input->info()->tensor_shape()
1190 << " Output shape: " << output->info()->tensor_shape()
1191 << " Interpolation: " << policy
1192 << std::endl);
1193
1194 return std::move(func);
1195}
1196
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001197/** Create a backend ROI align layer function
1198 *
1199 * @tparam ROIAlignLayerFunction ROI Align function
1200 * @tparam TargetInfo Target-specific information
1201 *
1202 * @param[in] node Node to create the backend function for
1203 *
1204 * @return ROI Align layer function
1205 */
1206template <typename ROIAlignLayerFunction, typename TargetInfo>
1207std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1208{
1209 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1210
1211 // Extract IO and info
1212 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1213 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1214 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1215 ARM_COMPUTE_ERROR_ON(input == nullptr);
1216 ARM_COMPUTE_ERROR_ON(output == nullptr);
1217 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1218
1219 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1220
1221 // Create and configure function
1222 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1223
1224 func->configure(input, rois, output, pool_info);
1225
1226 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +00001227 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1228 << node.name()
1229 << " Type: " << node.type()
1230 << " Target: " << TargetInfo::TargetType
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001231 << " Data Type: " << input->info()->data_type()
1232 << " Input shape: " << input->info()->tensor_shape()
1233 << " Output shape: " << output->info()->tensor_shape()
1234 << " ROIs shape: " << rois->info()->tensor_shape()
1235 << " ROIPooling width: " << pool_info.pooled_width()
1236 << " ROIPooling height: " << pool_info.pooled_height()
1237 << std::endl);
1238
1239 return std::move(func);
1240}
1241
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001242/** Create a backend slice layer function
1243 *
1244 * @tparam SliceLayerFunction Backend slice function
1245 * @tparam TargetInfo Target-specific information
1246 *
1247 * @param[in] node Node to create the backend function for
1248 *
1249 * @return Backend slice layer function
1250 */
1251template <typename SliceLayerFunction, typename TargetInfo>
1252std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1253{
1254 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1255
1256 // Extract IO and info
1257 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1258 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1259 ARM_COMPUTE_ERROR_ON(input == nullptr);
1260 ARM_COMPUTE_ERROR_ON(output == nullptr);
1261
1262 // Create and configure function
1263 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1264 func->configure(input, output, node.starts(), node.ends());
1265
1266 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001267 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1268 << node.name()
1269 << " Type: " << node.type()
1270 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001271 << " Data Type: " << input->info()->data_type()
1272 << " Input shape: " << input->info()->tensor_shape()
1273 << " Output shape: " << output->info()->tensor_shape()
1274 << std::endl);
1275
1276 return std::move(func);
1277}
1278
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001279/** Create a backend softmax layer function
1280 *
1281 * @tparam SoftmaxLayerFunction Backend softmax function
1282 * @tparam TargetInfo Target-specific information
1283 *
1284 * @param[in] node Node to create the backend function for
1285 * @param[in] ctx Graph context
1286 *
1287 * @return Backend softmax layer function
1288 */
1289template <typename SoftmaxLayerFunction, typename TargetInfo>
1290std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1291{
1292 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1293
1294 // Extract IO and info
1295 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1296 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1297 const float beta = node.beta();
1298 ARM_COMPUTE_ERROR_ON(input == nullptr);
1299 ARM_COMPUTE_ERROR_ON(output == nullptr);
1300
1301 // Create and configure function
1302 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1303 func->configure(input, output, beta);
1304
1305 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001306 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1307 << node.name()
1308 << " Type: " << node.type()
1309 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001310 << " Data Type: " << input->info()->data_type()
1311 << " Input shape: " << input->info()->tensor_shape()
1312 << " Output shape: " << output->info()->tensor_shape()
1313 << std::endl);
1314
1315 return std::move(func);
1316}
Michele Di Giorgioec699752019-03-22 15:25:32 +00001317
1318/** Create a backend layer stack function
1319 *
1320 * @tparam StackLayerFunction Backend stack function
1321 * @tparam TargetInfo Target-specific information
1322 *
1323 * @param[in] node Node to create the backend function for
1324 *
1325 * @return Backend stack layer function
1326 */
1327template <typename StackLayerFunction, typename TargetInfo>
1328std::unique_ptr<arm_compute::IFunction> create_stack_layer(StackLayerNode &node)
1329{
1330 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Stack node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
1331 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
1332
1333 // Extract IO and info
1334 std::vector<typename TargetInfo::TensorType *> inputs;
1335 for(unsigned int i = 0; i < node.num_inputs(); ++i)
1336 {
1337 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
1338 }
1339 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1340 const int axis = node.axis();
1341
1342 // Create and configure function
1343 auto func = support::cpp14::make_unique<StackLayerFunction>();
1344 func->configure(inputs, axis, output);
1345
1346 // Log info
1347 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1348 << node.name()
1349 << " Type: " << node.type()
1350 << " Target: " << TargetInfo::TargetType
1351 << " Data Type: " << output->info()->data_type()
1352 << " Inputs shape: " << inputs[0]->info()->tensor_shape()
1353 << " Output shape: " << output->info()->tensor_shape()
1354 << " Num Inputs: " << inputs.size()
1355 << " Axis: " << axis
1356 << std::endl);
1357
1358 return std::move(func);
1359}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001360/** Create a backend Upsample layer function
1361 *
1362 * @tparam UpsampleLayerFunction Backend Upsample function
1363 * @tparam TargetInfo Target-specific information
1364 *
1365 * @param[in] node Node to create the backend function for
1366 * @param[in] ctx Graph context
1367 *
1368 * @return Backend Upsample layer function
1369 */
1370template <typename UpsampleLayerFunction, typename TargetInfo>
1371std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1372{
1373 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1374
1375 // Extract IO and info
1376 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1377 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1378 const Size2D info = node.info();
1379 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1380 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1381 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1382 ARM_COMPUTE_ERROR_ON(input == nullptr);
1383 ARM_COMPUTE_ERROR_ON(output == nullptr);
1384
1385 // Create and configure function
1386 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1387 func->configure(input, output, info, upsampling_policy);
1388
1389 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001390 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1391 << node.name()
1392 << " Type: " << node.type()
1393 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001394 << " Data Type: " << input->info()->data_type()
1395 << " Input shape: " << input->info()->tensor_shape()
1396 << " Output shape: " << output->info()->tensor_shape()
1397 << " Strides: " << info
1398 << " Upsampling policy: " << upsampling_policy
1399 << std::endl);
1400
1401 return std::move(func);
1402}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001403/** Create a backend YOLO layer function
1404 *
1405 * @tparam YoloLayerFunction Backend YOLO 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 YOLO layer function
1412 */
1413template <typename YOLOlayerFunction, typename TargetInfo>
1414std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &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 ActivationLayerInfo act_info = node.activation_info();
1422 const int32_t num_classes = node.num_classes();
1423 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1424 ARM_COMPUTE_ERROR_ON(input == nullptr);
1425 ARM_COMPUTE_ERROR_ON(output == nullptr);
1426
1427 // Create and configure function
1428 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1429 func->configure(input, output, act_info, num_classes);
1430
1431 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001432 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1433 << node.name()
1434 << " Type: " << node.type()
1435 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001436 << " Data Type: " << input->info()->data_type()
1437 << " Input shape: " << input->info()->tensor_shape()
1438 << " Output shape: " << output->info()->tensor_shape()
1439 << " Activation function: " << act_info.activation()
1440 << " Num classes: " << num_classes
1441 << std::endl);
1442
1443 return std::move(func);
1444}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001445} // namespace detail
1446} // namespace backends
1447} // namespace graph
1448} // namespace arm_compute
1449
1450#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */