blob: 94b385e81e75f4d89045812d3ccadb4a849e78fd [file] [log] [blame]
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001/*
Giuseppe Rossinibb365de2019-02-15 10:24:47 +00002 * Copyright (c) 2018-2019 ARM Limited.
Georgios Pinitasda2491f2018-06-01 17:49:09 +01003 *
4 * SPDX-License-Identifier: MIT
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to
8 * deal in the Software without restriction, including without limitation the
9 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10 * sell copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in all
14 * copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 * SOFTWARE.
23 */
24#ifndef __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__
25#define __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__
26
27#include "arm_compute/graph/Logger.h"
28#include "arm_compute/graph/Tensor.h"
29#include "arm_compute/graph/TypePrinter.h"
30#include "arm_compute/graph/Types.h"
Georgios Pinitas9e4824c2019-04-12 13:15:58 +010031#include "arm_compute/graph/Utils.h"
giuros01acce5042019-02-21 17:32:34 +000032#include "arm_compute/graph/backends/FusedConvolutionBatchNormalizationFunction.h"
Manuel Bottinibffb41e2019-06-20 16:00:27 +010033#include "arm_compute/graph/backends/FusedDepthwiseConvolutionBatchNormalizationFunction.h"
Georgios Pinitasda2491f2018-06-01 17:49:09 +010034#include "arm_compute/graph/backends/Utils.h"
35#include "arm_compute/graph/nodes/Nodes.h"
36
37#include "arm_compute/core/Error.h"
38#include "arm_compute/core/Helpers.h"
39#include "arm_compute/core/ITensorInfo.h"
40#include "arm_compute/core/utils/misc/Cast.h"
41
42namespace arm_compute
43{
44namespace graph
45{
46namespace backends
47{
48namespace detail
49{
50/** Returns backing tensor of a given tensor
51 *
52 * @tparam TargetInfo Target information
53 *
54 * @param[in] tensor Tensor to extract the backing tensor from
55 *
56 * @return Backing tensor if present else nullptr
57 */
58template <typename TargetInfo>
59typename TargetInfo::TensorType *get_backing_tensor(arm_compute::graph::Tensor *tensor)
60{
61 typename TargetInfo::TensorType *backing_tensor = nullptr;
62 if(tensor != nullptr)
63 {
64 ARM_COMPUTE_ERROR_ON(tensor->desc().target != TargetInfo::TargetType);
65 // Get backing tensor handle
66 ITensorHandle *tensor_handle = tensor->handle();
67 // Get backing tensor
68 backing_tensor = (tensor_handle != nullptr) ? arm_compute::utils::cast::polymorphic_cast<typename TargetInfo::TensorType *>(&tensor_handle->tensor()) : nullptr;
69 }
70
71 return backing_tensor;
72}
73
74template <typename TargetInfo>
75void validate_node(const INode &node, size_t num_expected_inputs, size_t num_expected_outputs)
76{
77 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating " << node.type()
Pablo Tello32521432018-11-15 14:43:10 +000078 << " Target: " << TargetInfo::TargetType
79 << " ID: " << node.id()
80 << node.name()
Georgios Pinitasda2491f2018-06-01 17:49:09 +010081 << std::endl);
82
83 ARM_COMPUTE_ERROR_ON(TargetInfo::TargetType != node.assigned_target());
84 ARM_COMPUTE_ERROR_ON(node.num_inputs() != num_expected_inputs);
85 ARM_COMPUTE_ERROR_ON(node.num_outputs() != num_expected_outputs);
Michalis Spyrou6bff1952019-10-02 17:22:11 +010086 ARM_COMPUTE_UNUSED(node, num_expected_inputs, num_expected_outputs);
Georgios Pinitasda2491f2018-06-01 17:49:09 +010087}
88
89/** Creates a backend activation layer function
90 *
91 * @tparam ActivationLayerFunction Backend activation function
92 * @tparam TargetInfo Target-specific information
93 *
94 * @param[in] node Node to create the backend function for
95 *
96 * @return Backend activation layer function
97 */
98template <typename ActivationLayerFunction, typename TargetInfo>
99std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
100{
101 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
102
103 // Extract IO and info
104 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
105 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
106 const ActivationLayerInfo act_info = node.activation_info();
107
108 // Create function
109 auto func = support::cpp14::make_unique<ActivationLayerFunction>();
110 func->configure(input, output, act_info);
111
Pablo Tello32521432018-11-15 14:43:10 +0000112 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
113 << node.name()
114 << " Type: " << node.type()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000115 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100116 << " Data Type: " << input->info()->data_type()
117 << " Shape: " << input->info()->tensor_shape()
118 << " Activation function: " << act_info.activation()
119 << " a: " << act_info.a()
120 << " b: " << act_info.b()
121 << " InPlace : " << is_in_place_operation(input, output)
122 << std::endl);
123
124 return std::move(func);
125}
126
127/** Create a backend batch normalization layer function
128 *
129 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
130 * @tparam TargetInfo Target-specific information
131 *
132 * @param[in] node Node to create the backend function for
133 *
134 * @return Backend batch normalization layer function
135 */
136template <typename BatchNormalizationLayerFunction, typename TargetInfo>
137std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
138{
139 validate_node<TargetInfo>(node, 5 /* expected inputs */, 1 /* expected outputs */);
140
141 // Extract IO and info
giuros01acce5042019-02-21 17:32:34 +0000142 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
143 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
144 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(2));
145 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(3));
146 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(4));
147
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100148 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
149 const float epsilon = node.epsilon();
150 const ActivationLayerInfo fused_act = node.fused_activation();
151
152 // Create and configure function
153 auto func = support::cpp14::make_unique<BatchNormalizationLayerFunction>();
154 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
155
156 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000157 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
158 << node.name()
159 << " Type: " << node.type()
160 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100161 << " Data Type: " << input->info()->data_type()
162 << " Shape: " << input->info()->tensor_shape()
163 << " Epsilon: " << epsilon << " "
164 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
Pablo Tello32521432018-11-15 14:43:10 +0000165 << " InPlace: " << is_in_place_operation(input, output)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100166 << std::endl);
167
168 return std::move(func);
169}
170
giuros01acce5042019-02-21 17:32:34 +0000171/** Create a backend batch normalization layer function
172 *
173 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
174 * @tparam TargetInfo Target-specific information
175 *
176 * @param[in] node Node to create the backend function for
177 *
178 * @return Backend batch normalization layer function
179 */
180template <typename FusedLayerTypes, typename TargetInfo>
181std::unique_ptr<IFunction> create_fused_convolution_batch_normalization_layer(FusedConvolutionBatchNormalizationNode &node)
182{
183 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
184
185 // Extract IO and info
186 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
187 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
188 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
189 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
190 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
191 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
192 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
193
194 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
195
196 const PadStrideInfo conv_info = node.convolution_info();
197 const unsigned int num_groups = node.num_groups();
198 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
199 const ActivationLayerInfo fused_act = node.fused_activation();
200 const float epsilon = node.epsilon();
201
giuros01acce5042019-02-21 17:32:34 +0000202 // Create and configure function
203 auto func = support::cpp14::make_unique<FusedConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>>();
204 func->configure(input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, num_groups, fast_math, fused_act);
205
206 // Log info
207 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
208 << node.name()
Manuel Bottinibffb41e2019-06-20 16:00:27 +0100209 << " Type: " << node.type()
210 << " Target: " << TargetInfo::TargetType
211 << " Data Type: " << input->info()->data_type()
212 << " Input shape: " << input->info()->tensor_shape()
213 << " Weights shape: " << weights->info()->tensor_shape()
214 << " Output shape: " << output->info()->tensor_shape()
215 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
216 << std::endl);
217 return std::move(func);
218}
219
220/** Create a backend fused depthwise convolution batch normalization layer function
221 *
222 * @tparam FusedLayerTypes Fused layer types
223 * @tparam TargetInfo Target-specific information
224 *
225 * @param[in] node Node to create the backend function for
226 *
227 * @return Backend fused depthwise convolution batch normalization layer function
228 */
229template <typename FusedLayerTypes, typename TargetInfo>
230std::unique_ptr<IFunction> create_fused_depthwise_convolution_batch_normalization_layer(FusedDepthwiseConvolutionBatchNormalizationNode &node)
231{
232 validate_node<TargetInfo>(node, 7 /* expected inputs */, 1 /* expected outputs */);
233
234 // Extract IO and info
235 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
236 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
237 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
238 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(3));
239 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(4));
240 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(5));
241 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(6));
242
243 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
244
245 const PadStrideInfo conv_info = node.convolution_info();
246 const unsigned int depth_multiplier = node.depth_multiplier();
247 const ActivationLayerInfo fused_act = node.fused_activation();
248 const float epsilon = node.epsilon();
249
250 // Create and configure function
251 auto func = support::cpp14::make_unique<FusedDepthwiseConvolutionBatchNormalizationFunction<TargetInfo, FusedLayerTypes>>();
252 func->configure(input, weights, biases, output, mean, var, beta, gamma, epsilon, conv_info, depth_multiplier, fused_act);
253
254 // Log info
255 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
256 << node.name()
257 << " Type: " << node.type()
giuros01acce5042019-02-21 17:32:34 +0000258 << " Target: " << TargetInfo::TargetType
259 << " Data Type: " << input->info()->data_type()
260 << " Input shape: " << input->info()->tensor_shape()
261 << " Weights shape: " << weights->info()->tensor_shape()
262 << " Output shape: " << output->info()->tensor_shape()
263 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
264 << std::endl);
265 return std::move(func);
266}
267
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100268/** Create a backend bounding box transform layer function
269 *
270 * @tparam BoundingBoxTransformLayerFunction Backend bounding box transform function
271 * @tparam TargetInfo Target-specific information
272 *
273 * @param[in] node Node to create the backend function for
274 *
275 * @return Backend bounding box transform layer function
276 */
277template <typename BoundingBoxTransformLayerFunction, typename TargetInfo>
278std::unique_ptr<IFunction> create_bounding_box_transform_layer(BoundingBoxTransformLayerNode &node)
279{
280 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
281
282 // Extract IO and info
283 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
284 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
285 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
286 const BoundingBoxTransformInfo bbox_info = node.info();
287
288 // Create and configure function
289 auto func = support::cpp14::make_unique<BoundingBoxTransformLayerFunction>();
290 func->configure(input, output, deltas, bbox_info);
291
292 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000293 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
294 << node.name()
295 << " Type: " << node.type()
296 << " Target: " << TargetInfo::TargetType
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100297 << " Data Type: " << input->info()->data_type()
298 << " Shape: " << input->info()->tensor_shape()
299 << " BoundingBox Info img W: " << bbox_info.img_width() << " "
300 << " BoundingBox Info img H: " << bbox_info.img_height() << " "
301 << std::endl);
302
303 return std::move(func);
304}
305
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100306/** Create a backend channel shuffle layer function
307 *
308 * @tparam ChannelShuffleLayerFunction Backend channel shuffle function
309 * @tparam TargetInfo Target-specific information
310 *
311 * @param[in] node Node to create the backend function for
312 *
313 * @return Backend channel shuffle layer function
314 */
315template <typename ChannelShuffleLayerFunction, typename TargetInfo>
316std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
317{
318 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
319
320 // Extract IO and info
321 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
322 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
323 const unsigned int num_groups = node.num_groups();
324
325 // Create function
326 auto func = support::cpp14::make_unique<ChannelShuffleLayerFunction>();
327 func->configure(input, output, num_groups);
328
Pablo Tello32521432018-11-15 14:43:10 +0000329 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
330 << node.name()
331 << " Type: " << node.type()
332 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100333 << " Data Type: " << input->info()->data_type()
334 << " Shape: " << input->info()->tensor_shape()
335 << " Num groups: " << num_groups
336 << std::endl);
337
338 return std::move(func);
339}
340
Georgios Pinitase2220552018-07-20 13:23:44 +0100341/** Create a backend layer concatenate function
342 *
343 * @tparam ConcatenateLayerFunction Backend concatenate function
344 * @tparam TargetInfo Target-specific information
345 *
346 * @param[in] node Node to create the backend function for
347 *
348 * @return Backend concatenate layer function
349 */
350template <typename ConcatenateLayerFunction, typename TargetInfo>
351std::unique_ptr<arm_compute::IFunction> create_concatenate_layer(ConcatenateLayerNode &node)
352{
353 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Concatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
354 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
355
356 // Return nullptr if depth concatenate is switched off
357 if(!node.is_enabled())
358 {
359 return nullptr;
360 }
361
362 // Extract IO and info
363 std::vector<typename TargetInfo::TensorType *> inputs;
364 for(unsigned int i = 0; i < node.num_inputs(); ++i)
365 {
366 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
367 }
368 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas9e4824c2019-04-12 13:15:58 +0100369 const DataLayout data_layout = node.output(0) != nullptr ? node.output(0)->desc().layout : DataLayout::UNKNOWN;
370 const size_t concat_axis = get_dimension_idx(data_layout, node.concatenation_axis());
Georgios Pinitase2220552018-07-20 13:23:44 +0100371
372 // Create and configure function
373 auto func = support::cpp14::make_unique<ConcatenateLayerFunction>();
374 func->configure(inputs, output, concat_axis);
375
376 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000377 const bool is_quantized = is_data_type_quantized_asymmetric(output->info()->data_type());
378 std::ostringstream qss;
379 if(is_quantized)
380 {
381 qss << " Output QuantInfo: " << output->info()->quantization_info();
382 }
Pablo Tello32521432018-11-15 14:43:10 +0000383 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
384 << node.name()
385 << " Type: " << node.type()
386 << " Target: " << TargetInfo::TargetType
Georgios Pinitase2220552018-07-20 13:23:44 +0100387 << " Data Type: " << output->info()->data_type()
388 << " Shape: " << output->info()->tensor_shape()
389 << " Num Inputs: " << inputs.size()
390 << " Axis: " << concat_axis
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000391 << qss.str()
Georgios Pinitase2220552018-07-20 13:23:44 +0100392 << std::endl);
393
394 return std::move(func);
395}
396
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100397/** Create a backend convolution layer function
398 *
399 * @tparam ConvolutionLayerFunctions Backend convolution functions
400 * @tparam TargetInfo Target-specific information
401 *
402 * @param[in] node Node to create the backend function for
403 * @param[in] ctx Graph context
404 *
405 * @return Backend convolution layer function
406 */
407template <typename ConvolutionLayerFunctions, typename TargetInfo>
408std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
409{
410 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
411
412 // Extract IO and info
413 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
414 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
415 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
416 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
417
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100418 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
419
420 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100421 {
422 biases->info()->set_data_type(DataType::S32);
423 }
424
Georgios Pinitas08346e92018-10-16 19:10:46 +0100425 const PadStrideInfo conv_info = node.convolution_info();
426 const unsigned int num_groups = node.num_groups();
427 const ConvolutionMethod conv_algorithm = node.convolution_method();
428 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
429 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100430
431 // Create and configure function (we assume that functions have been validated before creation)
432 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
433 std::unique_ptr<IFunction> func;
434 std::string func_name;
435
Georgios Pinitase2220552018-07-20 13:23:44 +0100436 if(conv_algorithm == ConvolutionMethod::Winograd)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100437 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100438 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "WinogradConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100439 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::WinogradConvolutionLayer>(
440 std::string("WinogradConvolutionLayer"), mm,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100441 input, weights, biases, output, conv_info, fused_act, fast_math);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100442 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100443 else if(conv_algorithm == ConvolutionMethod::Direct)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100444 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100445 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "DirectConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100446 std::tie(func, func_name) = create_named_function<typename ConvolutionLayerFunctions::DirectConvolutionLayer>(
447 std::string("DirectConvolutionLayer"),
Georgios Pinitas08346e92018-10-16 19:10:46 +0100448 input, weights, biases, output, conv_info, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100449 }
450 else if(conv_algorithm == ConvolutionMethod::GEMM)
451 {
452 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GEMMConvolutionLayer>(
453 std::string("GEMMConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100454 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100455 WeightsInfo(), Size2D(1U, 1U), fused_act, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100456 }
457 else
458 {
459 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GenericConvolutionLayer>(
460 std::string("GenericConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100461 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100462 WeightsInfo(), Size2D(1U, 1U), fused_act, fast_math, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100463 }
464
465 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100466 std::ostringstream qss;
467 if(is_quantized)
468 {
469 qss << " Input QuantInfo: " << input->info()->quantization_info()
470 << " Weights QuantInfo: " << weights->info()->quantization_info()
471 << " Output QuantInfo: " << output->info()->quantization_info();
472 }
Pablo Tello32521432018-11-15 14:43:10 +0000473 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
474 << node.name()
475 << " Type: " << func_name
476 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100477 << " Data Type: " << input->info()->data_type()
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100478 << " Groups: " << num_groups
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100479 << " Input shape: " << input->info()->tensor_shape()
480 << " Weights shape: " << weights->info()->tensor_shape()
481 << " Output shape: " << output->info()->tensor_shape()
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000482 << qss.str()
Georgios Pinitas08346e92018-10-16 19:10:46 +0100483 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100484 << std::endl);
485 return func;
486}
487
488/** Create a backend deconvolution layer function
489 *
490 * @tparam DeconvolutionLayerFunction Backend deconvolution function
491 * @tparam TargetInfo Target-specific information
492 *
493 * @param[in] node Node to create the backend function for
494 * @param[in] ctx Graph context
495 *
496 * @return Backend deconvolution layer function
497 */
498template <typename DeconvolutionLayerFunction, typename TargetInfo>
499std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
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
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100509 const PadStrideInfo deconv_info = node.deconvolution_info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100510
511 // Create and configure function (we assume that functions have been validated before creation)
512 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
513 std::unique_ptr<IFunction> func;
514
515 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
516 std::string(), mm,
Manuel Bottinic1b76fa2019-06-17 12:04:40 +0100517 input, weights, biases, output, deconv_info);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100518
519 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000520 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
521 << node.name()
522 << " Type: " << node.type()
523 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100524 << " Data Type: " << input->info()->data_type()
525 << " Input shape: " << input->info()->tensor_shape()
526 << " Weights shape: " << weights->info()->tensor_shape()
527 << " Output shape: " << output->info()->tensor_shape()
528 << std::endl);
529 return func;
530}
531
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100532/** Create a backend layer depth-wise convolution function
533 *
534 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
535 * @tparam TargetInfo Target-specific information
536 *
537 * @param[in] node Node to create the backend function for
538 *
539 * @return Backend depth-wise convolution layer function
540 */
541template <typename DepthwiseConvolutionLayerFunctions, typename TargetInfo>
542std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
543{
544 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
545
546 // Extract IO and info
547 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
548 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
549 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
550 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
551
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100552 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
553
554 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100555 {
556 biases->info()->set_data_type(DataType::S32);
557 }
558
Georgios Pinitas60e98252018-10-22 16:17:20 +0100559 const PadStrideInfo conv_info = node.convolution_info();
560 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
Georgios Pinitas05045c12018-12-07 18:31:47 +0000561 const unsigned int depth_multiplier = node.depth_multiplier();
Georgios Pinitas60e98252018-10-22 16:17:20 +0100562 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100563
564 // Create and configure function (we assume that functions have been validated before creation)
565 std::unique_ptr<IFunction> func;
566 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100567 if(dwc_algorithm == DepthwiseConvolutionMethod::Optimized3x3)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100568 {
Georgios Pinitas30271c72019-06-24 14:56:34 +0100569 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::OptimizedDepthwiseConvolutionLayer>(
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100570 std::string("DepthwiseConvolutionLayer3x3"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100571 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100572 }
573 else
574 {
575 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::GenericDepthwiseConvolutionLayer>(
576 std::string("DepthwiseConvolutionLayer"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100577 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100578 }
579
580 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100581 std::ostringstream qss;
582 if(is_quantized)
583 {
584 qss << " Input QuantInfo: " << input->info()->quantization_info()
585 << " Weights QuantInfo: " << weights->info()->quantization_info()
586 << " Output QuantInfo: " << output->info()->quantization_info();
587 }
Pablo Tello32521432018-11-15 14:43:10 +0000588 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
589 << node.name()
590 << " Type: " << func_name
591 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100592 << " Data Type: " << input->info()->data_type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100593 << " Input shape: " << input->info()->tensor_shape()
594 << " Weights shape: " << weights->info()->tensor_shape()
595 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000596 << " Depth multiplier: " << depth_multiplier
Isabella Gottardi0ae5de92019-03-14 10:32:11 +0000597 << qss.str()
Georgios Pinitas60e98252018-10-22 16:17:20 +0100598 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100599 << std::endl);
600 return func;
601}
602
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000603/** Create a backend detection output layer function
604 *
605 * @tparam DetectionOutputLayer Function Backend detection output function
606 * @tparam TargetInfo Target-specific information
607 *
608 * @param[in] node Node to create the backend function for
609 *
610 * @return Backend detection output layer function
611 */
612template <typename DetectionOutputLayerFunction, typename TargetInfo>
613std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
614{
615 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
616
617 // Extract IO and info
618 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
619 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
620 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
621 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
622 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
623
624 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
625 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
626 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
627 ARM_COMPUTE_ERROR_ON(output == nullptr);
628
629 // Create and configure function
630 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
631 func->configure(input0, input1, input2, output, detect_info);
632
633 // Log info
634 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
635 << node.name()
636 << " Type: " << node.type()
637 << " Target: " << TargetInfo::TargetType
638 << " Data Type: " << input0->info()->data_type()
639 << " Input0 shape: " << input0->info()->tensor_shape()
640 << " Input1 shape: " << input1->info()->tensor_shape()
641 << " Input2 shape: " << input2->info()->tensor_shape()
642 << " Output shape: " << output->info()->tensor_shape()
643 << " DetectionOutputLayer info: " << detect_info
644 << std::endl);
645
646 return std::move(func);
647}
Isabella Gottardia7acb3c2019-01-08 13:48:44 +0000648
649/** Create a backend detection post process layer function
650 *
651 * @tparam DetectionPostProcessLayerFunction Backend detection output function
652 * @tparam TargetInfo Target-specific information
653 *
654 * @param[in] node Node to create the backend function for
655 *
656 * @return Backend detection post process layer function
657 */
658template <typename DetectionPostProcessLayerFunction, typename TargetInfo>
659std::unique_ptr<IFunction> create_detection_post_process_layer(DetectionPostProcessLayerNode &node)
660{
661 validate_node<TargetInfo>(node, 3 /* expected inputs */, 4 /* expected outputs */);
662
663 // Extract IO and info
664 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
665 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
666 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
667 typename TargetInfo::TensorType *output0 = get_backing_tensor<TargetInfo>(node.output(0));
668 typename TargetInfo::TensorType *output1 = get_backing_tensor<TargetInfo>(node.output(1));
669 typename TargetInfo::TensorType *output2 = get_backing_tensor<TargetInfo>(node.output(2));
670 typename TargetInfo::TensorType *output3 = get_backing_tensor<TargetInfo>(node.output(3));
671 const DetectionPostProcessLayerInfo detect_info = node.detection_post_process_info();
672
673 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
674 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
675 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
676 ARM_COMPUTE_ERROR_ON(output0 == nullptr);
677 ARM_COMPUTE_ERROR_ON(output1 == nullptr);
678 ARM_COMPUTE_ERROR_ON(output2 == nullptr);
679 ARM_COMPUTE_ERROR_ON(output3 == nullptr);
680
681 // Create and configure function
682 auto func = support::cpp14::make_unique<DetectionPostProcessLayerFunction>();
683 func->configure(input0, input1, input2, output0, output1, output2, output3, detect_info);
684
685 // Log info
686 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
687 << node.name()
688 << " Type: " << node.type()
689 << " Target: " << TargetInfo::TargetType
690 << " Data Type: " << input0->info()->data_type()
691 << " Input0 shape: " << input0->info()->tensor_shape()
692 << " Input1 shape: " << input1->info()->tensor_shape()
693 << " Input2 shape: " << input2->info()->tensor_shape()
694 << " Output0 shape: " << output0->info()->tensor_shape()
695 << " Output1 shape: " << output1->info()->tensor_shape()
696 << " Output2 shape: " << output2->info()->tensor_shape()
697 << " Output3 shape: " << output3->info()->tensor_shape()
698 << " DetectionPostProcessLayer info: " << detect_info
699 << std::endl);
700
701 return std::move(func);
702}
703
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100704/** Create a backend element-wise operation layer function
705 *
706 * @tparam EltwiseFunctions Backend element-wise function
707 * @tparam TargetInfo Target-specific information
708 *
709 * @param[in] node Node to create the backend function for
710 *
711 * @return Backend element-wise operation layer function
712 */
713template <typename EltwiseFunctions, typename TargetInfo>
714std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
715{
716 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
717
718 // Extract IO and info
719 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
720 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
721 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
722 const EltwiseOperation eltwise_op = node.eltwise_operation();
723 const ConvertPolicy convert_policy = node.convert_policy();
724 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
725 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
726 ARM_COMPUTE_ERROR_ON(output == nullptr);
727
728 std::unique_ptr<IFunction> func = nullptr;
729 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100730 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100731 {
732 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
733 std::string("ArithmeticAddition"),
734 input1, input2, output, convert_policy);
735 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100736 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100737 {
738 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
739 std::string("ArithmeticSubtraction"),
740 input1, input2, output, convert_policy);
741 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100742 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100743 {
744 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
745 std::string("PixelWiseMultiplication"),
746 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
747 }
748 else
749 {
750 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
751 }
752
753 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000754 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
755 << node.name()
756 << " Type: " << node.type()
757 << " Target: " << TargetInfo::TargetType
758 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100759 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000760 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100761 << std::endl);
762
763 return func;
764}
765
766/** Create a backend flatten layer function
767 *
768 * @tparam FlattenLayerFunction Backend flatten function
769 * @tparam TargetInfo Target-specific information
770 *
771 * @param[in] node Node to create the backend function for
772 *
773 * @return Backend flatten layer function
774 */
775template <typename FlattenLayerFunction, typename TargetInfo>
776std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
777{
778 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
779
780 // Extract IO and info
781 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
782 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
783
Georgios Pinitase2220552018-07-20 13:23:44 +0100784 ARM_COMPUTE_ERROR_ON(input == nullptr);
785 ARM_COMPUTE_ERROR_ON(output == nullptr);
786
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100787 // Create and configure function
788 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
789 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100790
791 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000792 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
793 << node.name()
794 << " Type: " << node.type()
795 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100796 << " Data Type: " << input->info()->data_type()
797 << " Input shape: " << input->info()->tensor_shape()
798 << " Output shape: " << output->info()->tensor_shape()
799 << std::endl);
800
801 return std::move(func);
802}
803
804/** Create a backend fully connected layer function
805 *
806 * @tparam FullyConnectedLayerFunction Backend fully-connected function
807 * @tparam TargetInfo Target-specific information
808 *
809 * @param[in] node Node to create the backend function for
810 * @param[in] ctx Graph context
811 *
812 * @return Backend fully connected layer function
813 */
814template <typename FullyConnectedLayerFunction, typename TargetInfo>
815std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
816{
817 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
818
819 // Extract IO and info
820 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
821 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
822 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
823 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100824 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100825
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100826 ARM_COMPUTE_ERROR_ON(input == nullptr);
827 ARM_COMPUTE_ERROR_ON(weights == nullptr);
828 ARM_COMPUTE_ERROR_ON(output == nullptr);
829
Georgios Pinitase2220552018-07-20 13:23:44 +0100830 // Create and configure function
Michalis Spyrou1a569a32019-09-10 17:20:34 +0100831 auto wm = get_weights_manager(ctx, TargetInfo::TargetType);
832 auto mm = get_memory_manager(ctx, TargetInfo::TargetType);
833 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(mm, wm.get());
Georgios Pinitase2220552018-07-20 13:23:44 +0100834 func->configure(input, weights, biases, output, fc_info);
835
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100836 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
837
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100838 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100839 std::ostringstream qss;
840 if(is_quantized)
841 {
842 qss << " Input QuantInfo: " << input->info()->quantization_info()
843 << " Weights QuantInfo: " << weights->info()->quantization_info()
844 << " Output QuantInfo: " << output->info()->quantization_info();
845 }
Pablo Tello32521432018-11-15 14:43:10 +0000846 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
847 << node.name()
848 << " Type: " << node.type()
849 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100850 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100851 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100852 << " Input shape: " << input->info()->tensor_shape()
853 << " Weights shape: " << weights->info()->tensor_shape()
854 << " Output shape: " << output->info()->tensor_shape()
855 << std::endl);
856
857 return std::move(func);
858}
859
Manuel Bottini5209be52019-02-13 16:34:56 +0000860/** Create a backend generate proposals layer function
861 *
862 * @tparam GenerateProposalsLayerFunction Backend generate proposals function
863 * @tparam TargetInfo Target-specific information
864 *
865 * @param[in] node Node to create the backend function for
866 * @param[in] ctx Graph context
867 *
868 * @return Backend generate proposals layer function
869 */
870template <typename GenerateProposalsLayerFunction, typename TargetInfo>
871std::unique_ptr<IFunction> create_generate_proposals_layer(GenerateProposalsLayerNode &node, GraphContext &ctx)
872{
873 validate_node<TargetInfo>(node, 3 /* expected inputs */, 3 /* expected outputs */);
874
875 // Extract IO and info
876 typename TargetInfo::TensorType *scores = get_backing_tensor<TargetInfo>(node.input(0));
877 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
878 typename TargetInfo::TensorType *anchors = get_backing_tensor<TargetInfo>(node.input(2));
879 typename TargetInfo::TensorType *proposals = get_backing_tensor<TargetInfo>(node.output(0));
880 typename TargetInfo::TensorType *scores_out = get_backing_tensor<TargetInfo>(node.output(1));
881 typename TargetInfo::TensorType *num_valid_proposals = get_backing_tensor<TargetInfo>(node.output(2));
882 const GenerateProposalsInfo info = node.info();
883
884 ARM_COMPUTE_ERROR_ON(scores == nullptr);
885 ARM_COMPUTE_ERROR_ON(deltas == nullptr);
886 ARM_COMPUTE_ERROR_ON(anchors == nullptr);
887 ARM_COMPUTE_ERROR_ON(proposals == nullptr);
888 ARM_COMPUTE_ERROR_ON(scores_out == nullptr);
889
890 // Create and configure function
891 auto func = support::cpp14::make_unique<GenerateProposalsLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
892 func->configure(scores, deltas, anchors, proposals, scores_out, num_valid_proposals, info);
893
894 // Log info
895 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
896 << " Target " << TargetInfo::TargetType
897 << " Data Type: " << scores->info()->data_type()
898 << " Scores shape: " << scores->info()->tensor_shape()
899 << " Deltas shape: " << deltas->info()->tensor_shape()
900 << " Anchors shape: " << anchors->info()->tensor_shape()
901 << " Proposals shape: " << proposals->info()->tensor_shape()
902 << " Num valid proposals shape: " << num_valid_proposals->info()->tensor_shape()
903 << " Scores Out shape: " << scores_out->info()->tensor_shape()
904 << std::endl);
905
906 return std::move(func);
907}
908
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100909/** Create a backend normalization layer function
910 *
911 * @tparam NormalizationLayerFunction Backend normalization function
912 * @tparam TargetInfo Target-specific information
913 *
914 * @param[in] node Node to create the backend function for
915 * @param[in] ctx Graph context
916 *
917 * @return Backend normalization layer function
918 */
919template <typename NormalizationLayerFunction, typename TargetInfo>
920std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
921{
922 ARM_COMPUTE_UNUSED(ctx);
923
924 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
925
926 // Extract IO and info
927 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
928 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
929 const NormalizationLayerInfo norm_info = node.normalization_info();
930 ARM_COMPUTE_ERROR_ON(input == nullptr);
931 ARM_COMPUTE_ERROR_ON(output == nullptr);
932
933 // Create and configure function
934 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
935 func->configure(input, output, norm_info);
936
937 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000938 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
939 << node.name()
940 << " Type: " << node.type()
941 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100942 << " Data Type: " << input->info()->data_type()
943 << " Input shape: " << input->info()->tensor_shape()
944 << " Output shape: " << output->info()->tensor_shape()
945 << " Normalization info: " << norm_info.type()
946 << std::endl);
947
948 return std::move(func);
949}
950
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100951/** Create a backend normalize planar YUV layer function
952 *
953 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
954 * @tparam TargetInfo Target-specific information
955 *
956 * @param[in] node Node to create the backend function for
957 *
958 * @return Backend normalize plnar YUV layer function
959 */
960template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
961std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
962{
963 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
964
965 // Extract IO and info
966 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
967 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
968 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
969 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
970 ARM_COMPUTE_ERROR_ON(input == nullptr);
971 ARM_COMPUTE_ERROR_ON(mean == nullptr);
972 ARM_COMPUTE_ERROR_ON(std == nullptr);
973 ARM_COMPUTE_ERROR_ON(output == nullptr);
974
975 // Create and configure function
976 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
977 func->configure(input, output, mean, std);
978
979 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000980 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
981 << node.name()
982 << " Type: " << node.type()
983 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100984 << " Data Type: " << input->info()->data_type()
985 << " Shape: " << input->info()->tensor_shape()
986 << std::endl);
987
988 return std::move(func);
989}
990
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100991/** Create a backend pad layer function
992 *
993 * @tparam PadLayerFunction Backend pad function
994 * @tparam TargetInfo Target-specific information
995 *
996 * @param[in] node Node to create the backend function for
997 *
998 * @return Backend pad layer function
999 */
1000template <typename PadLayerFunction, typename TargetInfo>
1001std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
1002{
1003 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1004
1005 // Extract IO and info
1006 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1007 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1008 const PaddingList &padding = node.padding();
1009 ARM_COMPUTE_ERROR_ON(input == nullptr);
1010 ARM_COMPUTE_ERROR_ON(output == nullptr);
1011
1012 // Create and configure function
1013 auto func = support::cpp14::make_unique<PadLayerFunction>();
1014 func->configure(input, output, padding);
1015
1016 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001017 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1018 << node.name()
1019 << " Type: " << node.type()
1020 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +01001021 << " Data Type: " << input->info()->data_type()
1022 << " Input shape: " << input->info()->tensor_shape()
1023 << " Output shape: " << output->info()->tensor_shape()
1024 << std::endl);
1025
1026 return std::move(func);
1027}
1028
Georgios Pinitas57c48242018-08-02 13:41:49 +01001029/** Create a backend permute layer function
1030 *
1031 * @tparam PermuteLayerFunction Backend permute function
1032 * @tparam TargetInfo Target-specific information
1033 *
1034 * @param[in] node Node to create the backend function for
1035 *
1036 * @return Backend permute layer function
1037 */
1038template <typename PermuteLayerFunction, typename TargetInfo>
1039std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
1040{
1041 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1042
1043 // Extract IO and info
1044 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1045 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1046 const PermutationVector &perm = node.permutation_vector();
1047 ARM_COMPUTE_ERROR_ON(input == nullptr);
1048 ARM_COMPUTE_ERROR_ON(output == nullptr);
1049
1050 // Create and configure function
1051 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
1052 func->configure(input, output, perm);
1053
1054 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001055 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1056 << node.name()
1057 << " Type: " << node.type()
1058 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +01001059 << " Data Type: " << input->info()->data_type()
1060 << " Input shape: " << input->info()->tensor_shape()
1061 << " Output shape: " << output->info()->tensor_shape()
1062 << " Permutation vector: " << perm
1063 << std::endl);
1064
1065 return std::move(func);
1066}
1067
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001068/** Create a backend pooling layer function
1069 *
1070 * @tparam PoolingLayerFunction Backend pooling function
1071 * @tparam TargetInfo Target-specific information
1072 *
1073 * @param[in] node Node to create the backend function for
1074 *
1075 * @return Backend pooling layer function
1076 */
1077template <typename PoolingLayerFunction, typename TargetInfo>
1078std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
1079{
1080 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1081
1082 // Extract IO and info
1083 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1084 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1085 const PoolingLayerInfo pool_info = node.pooling_info();
1086 ARM_COMPUTE_ERROR_ON(input == nullptr);
1087 ARM_COMPUTE_ERROR_ON(output == nullptr);
1088
1089 // Create and configure function
1090 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
1091 func->configure(input, output, pool_info);
1092
1093 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001094 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1095 << node.name()
1096 << " Type: " << node.type()
1097 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001098 << " Data Type: " << input->info()->data_type()
1099 << " Input shape: " << input->info()->tensor_shape()
1100 << " Output shape: " << output->info()->tensor_shape()
1101 << " Pooling info: " << pool_info.pool_type()
1102 << std::endl);
1103
1104 return std::move(func);
1105}
1106
Pablo Tello32521432018-11-15 14:43:10 +00001107/** Create a backend priorbox layer function
1108 *
1109 * @tparam PriorBoxLayerFunction Backend priorbox function
1110 * @tparam TargetInfo Target-specific information
1111 *
1112 * @param[in] node Node to create the backend function for
1113 *
1114 * @return Backend priorbox layer function
1115 */
1116template <typename PriorBoxLayerFunction, typename TargetInfo>
1117std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
1118{
1119 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1120
1121 // Extract IO and info
1122 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
1123 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
1124 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1125 const PriorBoxLayerInfo prior_info = node.priorbox_info();
1126 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
1127 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
1128 ARM_COMPUTE_ERROR_ON(output == nullptr);
1129
1130 // Create and configure function
1131 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
1132 func->configure(input0, input1, output, prior_info);
1133
1134 // Log info
1135 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1136 << node.name()
1137 << " Type: " << node.type()
1138 << " Target: " << TargetInfo::TargetType
1139 << " Data Type: " << input0->info()->data_type()
1140 << " Input0 shape: " << input0->info()->tensor_shape()
1141 << " Input1 shape: " << input1->info()->tensor_shape()
1142 << " Output shape: " << output->info()->tensor_shape()
1143 << " PriorBoxLayer info: " << prior_info
1144 << std::endl);
1145
1146 return std::move(func);
1147}
1148
Isabella Gottardi3db1ba92019-05-17 12:35:20 +01001149/** Create a backend quantization layer function
1150 *
1151 * @tparam QuantizationLayerFunction Backend quantization function
1152 * @tparam TargetInfo Target-specific information
1153 *
1154 * @param[in] node Node to create the backend function for
1155 *
1156 * @return Backend quantization layer function
1157 */
1158template <typename QuantizationLayerFunction, typename TargetInfo>
1159std::unique_ptr<IFunction> create_quantization_layer(QuantizationLayerNode &node)
1160{
1161 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1162
1163 // Extract IO and info
1164 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1165 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1166 ARM_COMPUTE_ERROR_ON(input == nullptr);
1167 ARM_COMPUTE_ERROR_ON(output == nullptr);
1168
1169 // Create and configure function
1170 auto func = support::cpp14::make_unique<QuantizationLayerFunction>();
1171 func->configure(input, output);
1172
1173 // Log info
1174 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1175 << node.name()
1176 << " Type: " << node.type()
1177 << " Target: " << TargetInfo::TargetType
1178 << " Data Type: " << input->info()->data_type()
1179 << " Input shape: " << input->info()->tensor_shape()
1180 << " Output shape: " << output->info()->tensor_shape()
1181 << std::endl);
1182
1183 return std::move(func);
1184}
1185
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001186/** Create a backend reorg layer function
1187 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001188 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001189 * @tparam TargetInfo Target-specific information
1190 *
1191 * @param[in] node Node to create the backend function for
1192 *
1193 * @return Backend reshape layer function
1194 */
1195template <typename ReorgLayerFunction, typename TargetInfo>
1196std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
1197{
1198 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1199
1200 // Extract IO and info
1201 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1202 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1203 ARM_COMPUTE_ERROR_ON(input == nullptr);
1204 ARM_COMPUTE_ERROR_ON(output == nullptr);
1205
1206 // Create and configure function
1207 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
1208 func->configure(input, output, node.stride());
1209
1210 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001211 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1212 << node.name()
1213 << " Type: " << node.type()
1214 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +01001215 << " Data Type: " << input->info()->data_type()
1216 << " Input shape: " << input->info()->tensor_shape()
1217 << " Output shape: " << output->info()->tensor_shape()
1218 << std::endl);
1219
1220 return std::move(func);
1221}
1222
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001223/** Create a backend reshape layer function
1224 *
1225 * @tparam ReshapeLayerFunction Backend reshape function
1226 * @tparam TargetInfo Target-specific information
1227 *
1228 * @param[in] node Node to create the backend function for
1229 *
1230 * @return Backend reshape layer function
1231 */
1232template <typename ReshapeLayerFunction, typename TargetInfo>
1233std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
1234{
1235 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1236
1237 // Extract IO and info
1238 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1239 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1240 ARM_COMPUTE_ERROR_ON(input == nullptr);
1241 ARM_COMPUTE_ERROR_ON(output == nullptr);
1242
1243 // Create and configure function
1244 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
1245 func->configure(input, output);
1246
1247 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001248 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1249 << node.name()
1250 << " Type: " << node.type()
1251 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001252 << " Data Type: " << input->info()->data_type()
1253 << " Input shape: " << input->info()->tensor_shape()
1254 << " Output shape: " << output->info()->tensor_shape()
1255 << std::endl);
1256
1257 return std::move(func);
1258}
1259
1260/** Create a backend resize layer function
1261 *
1262 * @tparam ResizeLayerFunction Backend resize function
1263 * @tparam TargetInfo Target-specific information
1264 *
1265 * @param[in] node Node to create the backend function for
1266 *
1267 * @return Backend resize layer function
1268 */
1269template <typename ResizeLayerFunction, typename TargetInfo>
1270std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1271{
1272 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1273
1274 // Extract IO and info
1275 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1276 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1277 ARM_COMPUTE_ERROR_ON(input == nullptr);
1278 ARM_COMPUTE_ERROR_ON(output == nullptr);
1279 const InterpolationPolicy policy = node.policy();
1280
1281 // Create and configure function
1282 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1283 func->configure(input, output, policy, BorderMode::CONSTANT);
1284
1285 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001286 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1287 << node.name()
1288 << " Type: " << node.type()
1289 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001290 << " Data Type: " << input->info()->data_type()
1291 << " Input shape: " << input->info()->tensor_shape()
1292 << " Output shape: " << output->info()->tensor_shape()
1293 << " Interpolation: " << policy
1294 << std::endl);
1295
1296 return std::move(func);
1297}
1298
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001299/** Create a backend ROI align layer function
1300 *
1301 * @tparam ROIAlignLayerFunction ROI Align function
1302 * @tparam TargetInfo Target-specific information
1303 *
1304 * @param[in] node Node to create the backend function for
1305 *
1306 * @return ROI Align layer function
1307 */
1308template <typename ROIAlignLayerFunction, typename TargetInfo>
1309std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1310{
1311 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1312
1313 // Extract IO and info
1314 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1315 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1316 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1317 ARM_COMPUTE_ERROR_ON(input == nullptr);
1318 ARM_COMPUTE_ERROR_ON(output == nullptr);
1319 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1320
1321 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1322
1323 // Create and configure function
1324 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1325
1326 func->configure(input, rois, output, pool_info);
1327
1328 // Log info
Isabella Gottardi0ae5de92019-03-14 10:32:11 +00001329 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1330 << node.name()
1331 << " Type: " << node.type()
1332 << " Target: " << TargetInfo::TargetType
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001333 << " Data Type: " << input->info()->data_type()
1334 << " Input shape: " << input->info()->tensor_shape()
1335 << " Output shape: " << output->info()->tensor_shape()
1336 << " ROIs shape: " << rois->info()->tensor_shape()
1337 << " ROIPooling width: " << pool_info.pooled_width()
1338 << " ROIPooling height: " << pool_info.pooled_height()
1339 << std::endl);
1340
1341 return std::move(func);
1342}
1343
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001344/** Create a backend slice layer function
1345 *
1346 * @tparam SliceLayerFunction Backend slice function
1347 * @tparam TargetInfo Target-specific information
1348 *
1349 * @param[in] node Node to create the backend function for
1350 *
1351 * @return Backend slice layer function
1352 */
1353template <typename SliceLayerFunction, typename TargetInfo>
1354std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1355{
1356 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1357
1358 // Extract IO and info
1359 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1360 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1361 ARM_COMPUTE_ERROR_ON(input == nullptr);
1362 ARM_COMPUTE_ERROR_ON(output == nullptr);
1363
1364 // Create and configure function
1365 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1366 func->configure(input, output, node.starts(), node.ends());
1367
1368 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001369 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1370 << node.name()
1371 << " Type: " << node.type()
1372 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001373 << " Data Type: " << input->info()->data_type()
1374 << " Input shape: " << input->info()->tensor_shape()
1375 << " Output shape: " << output->info()->tensor_shape()
1376 << std::endl);
1377
1378 return std::move(func);
1379}
1380
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001381/** Create a backend softmax layer function
1382 *
1383 * @tparam SoftmaxLayerFunction Backend softmax function
1384 * @tparam TargetInfo Target-specific information
1385 *
1386 * @param[in] node Node to create the backend function for
1387 * @param[in] ctx Graph context
1388 *
1389 * @return Backend softmax layer function
1390 */
1391template <typename SoftmaxLayerFunction, typename TargetInfo>
1392std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1393{
1394 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1395
1396 // Extract IO and info
1397 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1398 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1399 const float beta = node.beta();
1400 ARM_COMPUTE_ERROR_ON(input == nullptr);
1401 ARM_COMPUTE_ERROR_ON(output == nullptr);
1402
1403 // Create and configure function
1404 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1405 func->configure(input, output, beta);
1406
1407 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001408 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1409 << node.name()
1410 << " Type: " << node.type()
1411 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001412 << " Data Type: " << input->info()->data_type()
1413 << " Input shape: " << input->info()->tensor_shape()
1414 << " Output shape: " << output->info()->tensor_shape()
1415 << std::endl);
1416
1417 return std::move(func);
1418}
Michele Di Giorgioec699752019-03-22 15:25:32 +00001419
1420/** Create a backend layer stack function
1421 *
1422 * @tparam StackLayerFunction Backend stack function
1423 * @tparam TargetInfo Target-specific information
1424 *
1425 * @param[in] node Node to create the backend function for
1426 *
1427 * @return Backend stack layer function
1428 */
1429template <typename StackLayerFunction, typename TargetInfo>
1430std::unique_ptr<arm_compute::IFunction> create_stack_layer(StackLayerNode &node)
1431{
1432 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Stack node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
1433 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
1434
1435 // Extract IO and info
1436 std::vector<typename TargetInfo::TensorType *> inputs;
1437 for(unsigned int i = 0; i < node.num_inputs(); ++i)
1438 {
1439 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
1440 }
1441 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1442 const int axis = node.axis();
1443
1444 // Create and configure function
1445 auto func = support::cpp14::make_unique<StackLayerFunction>();
1446 func->configure(inputs, axis, output);
1447
1448 // Log info
1449 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1450 << node.name()
1451 << " Type: " << node.type()
1452 << " Target: " << TargetInfo::TargetType
1453 << " Data Type: " << output->info()->data_type()
1454 << " Inputs shape: " << inputs[0]->info()->tensor_shape()
1455 << " Output shape: " << output->info()->tensor_shape()
1456 << " Num Inputs: " << inputs.size()
1457 << " Axis: " << axis
1458 << std::endl);
1459
1460 return std::move(func);
1461}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001462/** Create a backend Upsample layer function
1463 *
1464 * @tparam UpsampleLayerFunction Backend Upsample function
1465 * @tparam TargetInfo Target-specific information
1466 *
1467 * @param[in] node Node to create the backend function for
1468 * @param[in] ctx Graph context
1469 *
1470 * @return Backend Upsample layer function
1471 */
1472template <typename UpsampleLayerFunction, typename TargetInfo>
1473std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1474{
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001475 ARM_COMPUTE_UNUSED(ctx);
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001476 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1477
1478 // Extract IO and info
1479 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1480 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1481 const Size2D info = node.info();
1482 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1483 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1484 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1485 ARM_COMPUTE_ERROR_ON(input == nullptr);
1486 ARM_COMPUTE_ERROR_ON(output == nullptr);
1487
1488 // Create and configure function
1489 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1490 func->configure(input, output, info, upsampling_policy);
1491
1492 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001493 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1494 << node.name()
1495 << " Type: " << node.type()
1496 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001497 << " Data Type: " << input->info()->data_type()
1498 << " Input shape: " << input->info()->tensor_shape()
1499 << " Output shape: " << output->info()->tensor_shape()
1500 << " Strides: " << info
1501 << " Upsampling policy: " << upsampling_policy
1502 << std::endl);
1503
1504 return std::move(func);
1505}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001506/** Create a backend YOLO layer function
1507 *
1508 * @tparam YoloLayerFunction Backend YOLO function
1509 * @tparam TargetInfo Target-specific information
1510 *
1511 * @param[in] node Node to create the backend function for
1512 * @param[in] ctx Graph context
1513 *
1514 * @return Backend YOLO layer function
1515 */
1516template <typename YOLOlayerFunction, typename TargetInfo>
1517std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1518{
Michalis Spyrou6bff1952019-10-02 17:22:11 +01001519 ARM_COMPUTE_UNUSED(ctx);
Michalis Spyrou96f67692018-09-13 11:39:28 +01001520 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1521
1522 // Extract IO and info
1523 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1524 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1525 const ActivationLayerInfo act_info = node.activation_info();
1526 const int32_t num_classes = node.num_classes();
1527 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1528 ARM_COMPUTE_ERROR_ON(input == nullptr);
1529 ARM_COMPUTE_ERROR_ON(output == nullptr);
1530
1531 // Create and configure function
1532 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1533 func->configure(input, output, act_info, num_classes);
1534
1535 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001536 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1537 << node.name()
1538 << " Type: " << node.type()
1539 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001540 << " Data Type: " << input->info()->data_type()
1541 << " Input shape: " << input->info()->tensor_shape()
1542 << " Output shape: " << output->info()->tensor_shape()
1543 << " Activation function: " << act_info.activation()
1544 << " Num classes: " << num_classes
1545 << std::endl);
1546
1547 return std::move(func);
1548}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001549} // namespace detail
1550} // namespace backends
1551} // namespace graph
1552} // namespace arm_compute
1553
1554#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */