blob: 548afd27c59d2f735d1b3e9a4e5430b4acfb6e5c [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"
31#include "arm_compute/graph/backends/Utils.h"
32#include "arm_compute/graph/nodes/Nodes.h"
33
34#include "arm_compute/core/Error.h"
35#include "arm_compute/core/Helpers.h"
36#include "arm_compute/core/ITensorInfo.h"
37#include "arm_compute/core/utils/misc/Cast.h"
38
39namespace arm_compute
40{
41namespace graph
42{
43namespace backends
44{
45namespace detail
46{
47/** Returns backing tensor of a given tensor
48 *
49 * @tparam TargetInfo Target information
50 *
51 * @param[in] tensor Tensor to extract the backing tensor from
52 *
53 * @return Backing tensor if present else nullptr
54 */
55template <typename TargetInfo>
56typename TargetInfo::TensorType *get_backing_tensor(arm_compute::graph::Tensor *tensor)
57{
58 typename TargetInfo::TensorType *backing_tensor = nullptr;
59 if(tensor != nullptr)
60 {
61 ARM_COMPUTE_ERROR_ON(tensor->desc().target != TargetInfo::TargetType);
62 // Get backing tensor handle
63 ITensorHandle *tensor_handle = tensor->handle();
64 // Get backing tensor
65 backing_tensor = (tensor_handle != nullptr) ? arm_compute::utils::cast::polymorphic_cast<typename TargetInfo::TensorType *>(&tensor_handle->tensor()) : nullptr;
66 }
67
68 return backing_tensor;
69}
70
71template <typename TargetInfo>
72void validate_node(const INode &node, size_t num_expected_inputs, size_t num_expected_outputs)
73{
74 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating " << node.type()
Pablo Tello32521432018-11-15 14:43:10 +000075 << " Target: " << TargetInfo::TargetType
76 << " ID: " << node.id()
77 << node.name()
Georgios Pinitasda2491f2018-06-01 17:49:09 +010078 << std::endl);
79
80 ARM_COMPUTE_ERROR_ON(TargetInfo::TargetType != node.assigned_target());
81 ARM_COMPUTE_ERROR_ON(node.num_inputs() != num_expected_inputs);
82 ARM_COMPUTE_ERROR_ON(node.num_outputs() != num_expected_outputs);
83}
84
85/** Creates a backend activation layer function
86 *
87 * @tparam ActivationLayerFunction Backend activation function
88 * @tparam TargetInfo Target-specific information
89 *
90 * @param[in] node Node to create the backend function for
91 *
92 * @return Backend activation layer function
93 */
94template <typename ActivationLayerFunction, typename TargetInfo>
95std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
96{
97 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
98
99 // Extract IO and info
100 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
101 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
102 const ActivationLayerInfo act_info = node.activation_info();
103
104 // Create function
105 auto func = support::cpp14::make_unique<ActivationLayerFunction>();
106 func->configure(input, output, act_info);
107
Pablo Tello32521432018-11-15 14:43:10 +0000108 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
109 << node.name()
110 << " Type: " << node.type()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100111 << " Target " << TargetInfo::TargetType
112 << " Data Type: " << input->info()->data_type()
113 << " Shape: " << input->info()->tensor_shape()
114 << " Activation function: " << act_info.activation()
115 << " a: " << act_info.a()
116 << " b: " << act_info.b()
117 << " InPlace : " << is_in_place_operation(input, output)
118 << std::endl);
119
120 return std::move(func);
121}
122
123/** Create a backend batch normalization layer function
124 *
125 * @tparam BatchNormalizationLayerFunction Backend batch normalization function
126 * @tparam TargetInfo Target-specific information
127 *
128 * @param[in] node Node to create the backend function for
129 *
130 * @return Backend batch normalization layer function
131 */
132template <typename BatchNormalizationLayerFunction, typename TargetInfo>
133std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
134{
135 validate_node<TargetInfo>(node, 5 /* expected inputs */, 1 /* expected outputs */);
136
137 // Extract IO and info
138 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
139 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
140 typename TargetInfo::TensorType *var = get_backing_tensor<TargetInfo>(node.input(2));
141 typename TargetInfo::TensorType *beta = get_backing_tensor<TargetInfo>(node.input(3));
142 typename TargetInfo::TensorType *gamma = get_backing_tensor<TargetInfo>(node.input(4));
143 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
144 const float epsilon = node.epsilon();
145 const ActivationLayerInfo fused_act = node.fused_activation();
146
147 // Create and configure function
148 auto func = support::cpp14::make_unique<BatchNormalizationLayerFunction>();
149 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
150
151 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000152 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
153 << node.name()
154 << " Type: " << node.type()
155 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100156 << " Data Type: " << input->info()->data_type()
157 << " Shape: " << input->info()->tensor_shape()
158 << " Epsilon: " << epsilon << " "
159 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
Pablo Tello32521432018-11-15 14:43:10 +0000160 << " InPlace: " << is_in_place_operation(input, output)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100161 << std::endl);
162
163 return std::move(func);
164}
165
Manuel Bottinid2048ce2018-10-23 17:00:42 +0100166/** Create a backend bounding box transform layer function
167 *
168 * @tparam BoundingBoxTransformLayerFunction Backend bounding box transform function
169 * @tparam TargetInfo Target-specific information
170 *
171 * @param[in] node Node to create the backend function for
172 *
173 * @return Backend bounding box transform layer function
174 */
175template <typename BoundingBoxTransformLayerFunction, typename TargetInfo>
176std::unique_ptr<IFunction> create_bounding_box_transform_layer(BoundingBoxTransformLayerNode &node)
177{
178 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
179
180 // Extract IO and info
181 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
182 typename TargetInfo::TensorType *deltas = get_backing_tensor<TargetInfo>(node.input(1));
183 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
184 const BoundingBoxTransformInfo bbox_info = node.info();
185
186 // Create and configure function
187 auto func = support::cpp14::make_unique<BoundingBoxTransformLayerFunction>();
188 func->configure(input, output, deltas, bbox_info);
189
190 // Log info
191 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << node.type()
192 << " Target " << TargetInfo::TargetType
193 << " Data Type: " << input->info()->data_type()
194 << " Shape: " << input->info()->tensor_shape()
195 << " BoundingBox Info img W: " << bbox_info.img_width() << " "
196 << " BoundingBox Info img H: " << bbox_info.img_height() << " "
197 << std::endl);
198
199 return std::move(func);
200}
201
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100202/** Create a backend channel shuffle layer function
203 *
204 * @tparam ChannelShuffleLayerFunction Backend channel shuffle function
205 * @tparam TargetInfo Target-specific information
206 *
207 * @param[in] node Node to create the backend function for
208 *
209 * @return Backend channel shuffle layer function
210 */
211template <typename ChannelShuffleLayerFunction, typename TargetInfo>
212std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
213{
214 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
215
216 // Extract IO and info
217 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
218 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
219 const unsigned int num_groups = node.num_groups();
220
221 // Create function
222 auto func = support::cpp14::make_unique<ChannelShuffleLayerFunction>();
223 func->configure(input, output, num_groups);
224
Pablo Tello32521432018-11-15 14:43:10 +0000225 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
226 << node.name()
227 << " Type: " << node.type()
228 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100229 << " Data Type: " << input->info()->data_type()
230 << " Shape: " << input->info()->tensor_shape()
231 << " Num groups: " << num_groups
232 << std::endl);
233
234 return std::move(func);
235}
236
Georgios Pinitase2220552018-07-20 13:23:44 +0100237/** Create a backend layer concatenate function
238 *
239 * @tparam ConcatenateLayerFunction Backend concatenate function
240 * @tparam TargetInfo Target-specific information
241 *
242 * @param[in] node Node to create the backend function for
243 *
244 * @return Backend concatenate layer function
245 */
246template <typename ConcatenateLayerFunction, typename TargetInfo>
247std::unique_ptr<arm_compute::IFunction> create_concatenate_layer(ConcatenateLayerNode &node)
248{
249 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating Concatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
250 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
251
252 // Return nullptr if depth concatenate is switched off
253 if(!node.is_enabled())
254 {
255 return nullptr;
256 }
257
258 // Extract IO and info
259 std::vector<typename TargetInfo::TensorType *> inputs;
260 for(unsigned int i = 0; i < node.num_inputs(); ++i)
261 {
262 inputs.push_back(get_backing_tensor<TargetInfo>(node.input(i)));
263 }
264 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
265 const DataLayoutDimension concat_axis = node.concatenation_axis();
266
267 // Create and configure function
268 auto func = support::cpp14::make_unique<ConcatenateLayerFunction>();
269 func->configure(inputs, output, concat_axis);
270
271 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000272 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
273 << node.name()
274 << " Type: " << node.type()
275 << " Target: " << TargetInfo::TargetType
Georgios Pinitase2220552018-07-20 13:23:44 +0100276 << " Data Type: " << output->info()->data_type()
277 << " Shape: " << output->info()->tensor_shape()
278 << " Num Inputs: " << inputs.size()
279 << " Axis: " << concat_axis
280 << std::endl);
281
282 return std::move(func);
283}
284
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100285/** Create a backend convolution layer function
286 *
287 * @tparam ConvolutionLayerFunctions Backend convolution functions
288 * @tparam TargetInfo Target-specific information
289 *
290 * @param[in] node Node to create the backend function for
291 * @param[in] ctx Graph context
292 *
293 * @return Backend convolution layer function
294 */
295template <typename ConvolutionLayerFunctions, typename TargetInfo>
296std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
297{
298 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
299
300 // Extract IO and info
301 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
302 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
303 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
304 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
305
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100306 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
307
308 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100309 {
310 biases->info()->set_data_type(DataType::S32);
311 }
312
Georgios Pinitas08346e92018-10-16 19:10:46 +0100313 const PadStrideInfo conv_info = node.convolution_info();
314 const unsigned int num_groups = node.num_groups();
315 const ConvolutionMethod conv_algorithm = node.convolution_method();
316 const bool fast_math = node.fast_math_hint() == FastMathHint::Enabled;
317 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100318
319 // Create and configure function (we assume that functions have been validated before creation)
320 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
321 std::unique_ptr<IFunction> func;
322 std::string func_name;
323
Georgios Pinitase2220552018-07-20 13:23:44 +0100324 if(conv_algorithm == ConvolutionMethod::Winograd)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100325 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100326 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "WinogradConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100327 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::WinogradConvolutionLayer>(
328 std::string("WinogradConvolutionLayer"), mm,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100329 input, weights, biases, output, conv_info, fused_act, fast_math);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100330 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100331 else if(conv_algorithm == ConvolutionMethod::Direct)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100332 {
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100333 ARM_COMPUTE_ERROR_ON_MSG(num_groups != 1, "DirectConvolutionLayer does not support grouping!");
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100334 std::tie(func, func_name) = create_named_function<typename ConvolutionLayerFunctions::DirectConvolutionLayer>(
335 std::string("DirectConvolutionLayer"),
Georgios Pinitas08346e92018-10-16 19:10:46 +0100336 input, weights, biases, output, conv_info, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100337 }
338 else if(conv_algorithm == ConvolutionMethod::GEMM)
339 {
340 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GEMMConvolutionLayer>(
341 std::string("GEMMConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100342 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100343 WeightsInfo(), Size2D(1U, 1U), fused_act, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100344 }
345 else
346 {
347 std::tie(func, func_name) = create_named_memory_managed_function<typename ConvolutionLayerFunctions::GenericConvolutionLayer>(
348 std::string("GenericConvolutionLayer"), mm,
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100349 input, weights, biases, output, conv_info,
Georgios Pinitas08346e92018-10-16 19:10:46 +0100350 WeightsInfo(), Size2D(1U, 1U), fused_act, fast_math, num_groups);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100351 }
352
353 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100354 std::ostringstream qss;
355 if(is_quantized)
356 {
357 qss << " Input QuantInfo: " << input->info()->quantization_info()
358 << " Weights QuantInfo: " << weights->info()->quantization_info()
359 << " Output QuantInfo: " << output->info()->quantization_info();
360 }
Pablo Tello32521432018-11-15 14:43:10 +0000361 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
362 << node.name()
363 << " Type: " << func_name
364 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100365 << " Data Type: " << input->info()->data_type()
Georgios Pinitas2a2db592018-08-15 12:14:46 +0100366 << " Groups: " << num_groups
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100367 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100368 << " Input shape: " << input->info()->tensor_shape()
369 << " Weights shape: " << weights->info()->tensor_shape()
370 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas08346e92018-10-16 19:10:46 +0100371 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100372 << std::endl);
373 return func;
374}
375
376/** Create a backend deconvolution layer function
377 *
378 * @tparam DeconvolutionLayerFunction Backend deconvolution function
379 * @tparam TargetInfo Target-specific information
380 *
381 * @param[in] node Node to create the backend function for
382 * @param[in] ctx Graph context
383 *
384 * @return Backend deconvolution layer function
385 */
386template <typename DeconvolutionLayerFunction, typename TargetInfo>
387std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
388{
389 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
390
391 // Extract IO and info
392 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
393 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
394 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
395 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
396
397 const PadStrideInfo deconv_info = node.deconvolution_info();
398 const Size2D inner_border = node.inner_border();
399
400 // Create and configure function (we assume that functions have been validated before creation)
401 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, TargetInfo::TargetType);
402 std::unique_ptr<IFunction> func;
403
404 std::tie(func, std::ignore) = create_named_memory_managed_function<DeconvolutionLayerFunction>(
405 std::string(), mm,
406 input, weights, biases, output, deconv_info, inner_border.x(), inner_border.y());
407
408 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000409 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
410 << node.name()
411 << " Type: " << node.type()
412 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100413 << " Data Type: " << input->info()->data_type()
414 << " Input shape: " << input->info()->tensor_shape()
415 << " Weights shape: " << weights->info()->tensor_shape()
416 << " Output shape: " << output->info()->tensor_shape()
417 << std::endl);
418 return func;
419}
420
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100421/** Create a backend layer depth-wise convolution function
422 *
423 * @tparam DepthwiseConvolutionLayerFunctions Backend depthwise convolution function
424 * @tparam TargetInfo Target-specific information
425 *
426 * @param[in] node Node to create the backend function for
427 *
428 * @return Backend depth-wise convolution layer function
429 */
430template <typename DepthwiseConvolutionLayerFunctions, typename TargetInfo>
431std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
432{
433 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
434
435 // Extract IO and info
436 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
437 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
438 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
439 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
440
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100441 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
442
443 if(is_quantized)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100444 {
445 biases->info()->set_data_type(DataType::S32);
446 }
447
Georgios Pinitas60e98252018-10-22 16:17:20 +0100448 const PadStrideInfo conv_info = node.convolution_info();
449 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
Georgios Pinitas05045c12018-12-07 18:31:47 +0000450 const unsigned int depth_multiplier = node.depth_multiplier();
Georgios Pinitas60e98252018-10-22 16:17:20 +0100451 const ActivationLayerInfo fused_act = node.fused_activation();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100452
453 // Create and configure function (we assume that functions have been validated before creation)
454 std::unique_ptr<IFunction> func;
455 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100456 if(dwc_algorithm == DepthwiseConvolutionMethod::Optimized3x3)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100457 {
458 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::DepthwiseConvolutionLayer3x3>(
459 std::string("DepthwiseConvolutionLayer3x3"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100460 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100461 }
462 else
463 {
464 std::tie(func, func_name) = create_named_function<typename DepthwiseConvolutionLayerFunctions::GenericDepthwiseConvolutionLayer>(
465 std::string("DepthwiseConvolutionLayer"),
Georgios Pinitas60e98252018-10-22 16:17:20 +0100466 input, weights, biases, output, conv_info, depth_multiplier, fused_act);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100467 }
468
469 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100470 std::ostringstream qss;
471 if(is_quantized)
472 {
473 qss << " Input QuantInfo: " << input->info()->quantization_info()
474 << " Weights QuantInfo: " << weights->info()->quantization_info()
475 << " Output QuantInfo: " << output->info()->quantization_info();
476 }
Pablo Tello32521432018-11-15 14:43:10 +0000477 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
478 << node.name()
479 << " Type: " << func_name
480 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100481 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100482 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100483 << " Input shape: " << input->info()->tensor_shape()
484 << " Weights shape: " << weights->info()->tensor_shape()
485 << " Output shape: " << output->info()->tensor_shape()
Georgios Pinitas05045c12018-12-07 18:31:47 +0000486 << " Depth multiplier: " << depth_multiplier
Georgios Pinitas60e98252018-10-22 16:17:20 +0100487 << (fused_act.enabled() ? " " + to_string(fused_act.activation()) : "")
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100488 << std::endl);
489 return func;
490}
491
Isabella Gottardi7234ed82018-11-27 08:51:10 +0000492/** Create a backend detection output layer function
493 *
494 * @tparam DetectionOutputLayer Function Backend detection output function
495 * @tparam TargetInfo Target-specific information
496 *
497 * @param[in] node Node to create the backend function for
498 *
499 * @return Backend detection output layer function
500 */
501template <typename DetectionOutputLayerFunction, typename TargetInfo>
502std::unique_ptr<IFunction> create_detection_output_layer(DetectionOutputLayerNode &node)
503{
504 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
505
506 // Extract IO and info
507 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
508 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
509 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(2));
510 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
511 const DetectionOutputLayerInfo detect_info = node.detection_output_info();
512
513 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
514 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
515 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
516 ARM_COMPUTE_ERROR_ON(output == nullptr);
517
518 // Create and configure function
519 auto func = support::cpp14::make_unique<DetectionOutputLayerFunction>();
520 func->configure(input0, input1, input2, output, detect_info);
521
522 // Log info
523 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
524 << node.name()
525 << " Type: " << node.type()
526 << " Target: " << TargetInfo::TargetType
527 << " Data Type: " << input0->info()->data_type()
528 << " Input0 shape: " << input0->info()->tensor_shape()
529 << " Input1 shape: " << input1->info()->tensor_shape()
530 << " Input2 shape: " << input2->info()->tensor_shape()
531 << " Output shape: " << output->info()->tensor_shape()
532 << " DetectionOutputLayer info: " << detect_info
533 << std::endl);
534
535 return std::move(func);
536}
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100537/** Create a backend element-wise operation layer function
538 *
539 * @tparam EltwiseFunctions Backend element-wise function
540 * @tparam TargetInfo Target-specific information
541 *
542 * @param[in] node Node to create the backend function for
543 *
544 * @return Backend element-wise operation layer function
545 */
546template <typename EltwiseFunctions, typename TargetInfo>
547std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
548{
549 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
550
551 // Extract IO and info
552 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(0));
553 typename TargetInfo::TensorType *input2 = get_backing_tensor<TargetInfo>(node.input(1));
554 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
555 const EltwiseOperation eltwise_op = node.eltwise_operation();
556 const ConvertPolicy convert_policy = node.convert_policy();
557 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
558 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
559 ARM_COMPUTE_ERROR_ON(output == nullptr);
560
561 std::unique_ptr<IFunction> func = nullptr;
562 std::string func_name;
Georgios Pinitase2220552018-07-20 13:23:44 +0100563 if(eltwise_op == EltwiseOperation::Add)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100564 {
565 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Addition>(
566 std::string("ArithmeticAddition"),
567 input1, input2, output, convert_policy);
568 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100569 else if(eltwise_op == EltwiseOperation::Sub)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100570 {
571 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Subtraction>(
572 std::string("ArithmeticSubtraction"),
573 input1, input2, output, convert_policy);
574 }
Georgios Pinitase2220552018-07-20 13:23:44 +0100575 else if(eltwise_op == EltwiseOperation::Mul)
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100576 {
577 std::tie(func, func_name) = create_named_function<typename EltwiseFunctions::Multiplication>(
578 std::string("PixelWiseMultiplication"),
579 input1, input2, output, 1.f, convert_policy, node.rounding_policy());
580 }
581 else
582 {
583 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
584 }
585
586 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000587 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
588 << node.name()
589 << " Type: " << node.type()
590 << " Target: " << TargetInfo::TargetType
591 << " Operation: " << func_name
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100592 << " Data Type: " << input1->info()->data_type()
Pablo Tello32521432018-11-15 14:43:10 +0000593 << " Shape: " << input1->info()->tensor_shape()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100594 << std::endl);
595
596 return func;
597}
598
599/** Create a backend flatten layer function
600 *
601 * @tparam FlattenLayerFunction Backend flatten function
602 * @tparam TargetInfo Target-specific information
603 *
604 * @param[in] node Node to create the backend function for
605 *
606 * @return Backend flatten layer function
607 */
608template <typename FlattenLayerFunction, typename TargetInfo>
609std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
610{
611 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
612
613 // Extract IO and info
614 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
615 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
616
Georgios Pinitase2220552018-07-20 13:23:44 +0100617 ARM_COMPUTE_ERROR_ON(input == nullptr);
618 ARM_COMPUTE_ERROR_ON(output == nullptr);
619
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100620 // Create and configure function
621 auto func = support::cpp14::make_unique<FlattenLayerFunction>();
622 func->configure(input, output);
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100623
624 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000625 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
626 << node.name()
627 << " Type: " << node.type()
628 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100629 << " Data Type: " << input->info()->data_type()
630 << " Input shape: " << input->info()->tensor_shape()
631 << " Output shape: " << output->info()->tensor_shape()
632 << std::endl);
633
634 return std::move(func);
635}
636
637/** Create a backend fully connected layer function
638 *
639 * @tparam FullyConnectedLayerFunction Backend fully-connected function
640 * @tparam TargetInfo Target-specific information
641 *
642 * @param[in] node Node to create the backend function for
643 * @param[in] ctx Graph context
644 *
645 * @return Backend fully connected layer function
646 */
647template <typename FullyConnectedLayerFunction, typename TargetInfo>
648std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
649{
650 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
651
652 // Extract IO and info
653 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
654 typename TargetInfo::TensorType *weights = get_backing_tensor<TargetInfo>(node.input(1));
655 typename TargetInfo::TensorType *biases = get_backing_tensor<TargetInfo>(node.input(2));
656 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
Georgios Pinitas7d66a8e2018-07-17 12:28:42 +0100657 const FullyConnectedLayerInfo fc_info = node.info();
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100658
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100659 ARM_COMPUTE_ERROR_ON(input == nullptr);
660 ARM_COMPUTE_ERROR_ON(weights == nullptr);
661 ARM_COMPUTE_ERROR_ON(output == nullptr);
662
Georgios Pinitase2220552018-07-20 13:23:44 +0100663 // Create and configure function
664 auto func = support::cpp14::make_unique<FullyConnectedLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
665 func->configure(input, weights, biases, output, fc_info);
666
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100667 const bool is_quantized = is_data_type_quantized_asymmetric(input->info()->data_type());
668
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100669 // Log info
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100670 std::ostringstream qss;
671 if(is_quantized)
672 {
673 qss << " Input QuantInfo: " << input->info()->quantization_info()
674 << " Weights QuantInfo: " << weights->info()->quantization_info()
675 << " Output QuantInfo: " << output->info()->quantization_info();
676 }
Pablo Tello32521432018-11-15 14:43:10 +0000677 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
678 << node.name()
679 << " Type: " << node.type()
680 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100681 << " Data Type: " << input->info()->data_type()
Georgios Pinitasfd7e8532018-09-07 10:51:27 +0100682 << qss.str()
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100683 << " Input shape: " << input->info()->tensor_shape()
684 << " Weights shape: " << weights->info()->tensor_shape()
685 << " Output shape: " << output->info()->tensor_shape()
686 << std::endl);
687
688 return std::move(func);
689}
690
691/** Create a backend normalization layer function
692 *
693 * @tparam NormalizationLayerFunction Backend normalization function
694 * @tparam TargetInfo Target-specific information
695 *
696 * @param[in] node Node to create the backend function for
697 * @param[in] ctx Graph context
698 *
699 * @return Backend normalization layer function
700 */
701template <typename NormalizationLayerFunction, typename TargetInfo>
702std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node, GraphContext &ctx)
703{
704 ARM_COMPUTE_UNUSED(ctx);
705
706 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
707
708 // Extract IO and info
709 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
710 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
711 const NormalizationLayerInfo norm_info = node.normalization_info();
712 ARM_COMPUTE_ERROR_ON(input == nullptr);
713 ARM_COMPUTE_ERROR_ON(output == nullptr);
714
715 // Create and configure function
716 auto func = support::cpp14::make_unique<NormalizationLayerFunction>();
717 func->configure(input, output, norm_info);
718
719 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000720 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
721 << node.name()
722 << " Type: " << node.type()
723 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100724 << " Data Type: " << input->info()->data_type()
725 << " Input shape: " << input->info()->tensor_shape()
726 << " Output shape: " << output->info()->tensor_shape()
727 << " Normalization info: " << norm_info.type()
728 << std::endl);
729
730 return std::move(func);
731}
732
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100733/** Create a backend normalize planar YUV layer function
734 *
735 * @tparam NormalizePlanarYUVLayerFunction Backend normalize planar YUV function
736 * @tparam TargetInfo Target-specific information
737 *
738 * @param[in] node Node to create the backend function for
739 *
740 * @return Backend normalize plnar YUV layer function
741 */
742template <typename NormalizePlanarYUVLayerFunction, typename TargetInfo>
743std::unique_ptr<IFunction> create_normalize_planar_yuv_layer(NormalizePlanarYUVLayerNode &node)
744{
745 validate_node<TargetInfo>(node, 3 /* expected inputs */, 1 /* expected outputs */);
746
747 // Extract IO and info
748 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
749 typename TargetInfo::TensorType *mean = get_backing_tensor<TargetInfo>(node.input(1));
750 typename TargetInfo::TensorType *std = get_backing_tensor<TargetInfo>(node.input(2));
751 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
752 ARM_COMPUTE_ERROR_ON(input == nullptr);
753 ARM_COMPUTE_ERROR_ON(mean == nullptr);
754 ARM_COMPUTE_ERROR_ON(std == nullptr);
755 ARM_COMPUTE_ERROR_ON(output == nullptr);
756
757 // Create and configure function
758 auto func = support::cpp14::make_unique<NormalizePlanarYUVLayerFunction>();
759 func->configure(input, output, mean, std);
760
761 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000762 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
763 << node.name()
764 << " Type: " << node.type()
765 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio555d1102018-09-12 13:51:59 +0100766 << " Data Type: " << input->info()->data_type()
767 << " Shape: " << input->info()->tensor_shape()
768 << std::endl);
769
770 return std::move(func);
771}
772
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100773/** Create a backend pad layer function
774 *
775 * @tparam PadLayerFunction Backend pad function
776 * @tparam TargetInfo Target-specific information
777 *
778 * @param[in] node Node to create the backend function for
779 *
780 * @return Backend pad layer function
781 */
782template <typename PadLayerFunction, typename TargetInfo>
783std::unique_ptr<IFunction> create_pad_layer(PadLayerNode &node)
784{
785 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
786
787 // Extract IO and info
788 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
789 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
790 const PaddingList &padding = node.padding();
791 ARM_COMPUTE_ERROR_ON(input == nullptr);
792 ARM_COMPUTE_ERROR_ON(output == nullptr);
793
794 // Create and configure function
795 auto func = support::cpp14::make_unique<PadLayerFunction>();
796 func->configure(input, output, padding);
797
798 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000799 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
800 << node.name()
801 << " Type: " << node.type()
802 << " Target: " << TargetInfo::TargetType
Michele Di Giorgio4bb17332018-09-26 13:56:51 +0100803 << " Data Type: " << input->info()->data_type()
804 << " Input shape: " << input->info()->tensor_shape()
805 << " Output shape: " << output->info()->tensor_shape()
806 << std::endl);
807
808 return std::move(func);
809}
810
Georgios Pinitas57c48242018-08-02 13:41:49 +0100811/** Create a backend permute layer function
812 *
813 * @tparam PermuteLayerFunction Backend permute function
814 * @tparam TargetInfo Target-specific information
815 *
816 * @param[in] node Node to create the backend function for
817 *
818 * @return Backend permute layer function
819 */
820template <typename PermuteLayerFunction, typename TargetInfo>
821std::unique_ptr<IFunction> create_permute_layer(PermuteLayerNode &node)
822{
823 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
824
825 // Extract IO and info
826 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
827 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
828 const PermutationVector &perm = node.permutation_vector();
829 ARM_COMPUTE_ERROR_ON(input == nullptr);
830 ARM_COMPUTE_ERROR_ON(output == nullptr);
831
832 // Create and configure function
833 auto func = support::cpp14::make_unique<PermuteLayerFunction>();
834 func->configure(input, output, perm);
835
836 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000837 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
838 << node.name()
839 << " Type: " << node.type()
840 << " Target: " << TargetInfo::TargetType
Georgios Pinitas57c48242018-08-02 13:41:49 +0100841 << " Data Type: " << input->info()->data_type()
842 << " Input shape: " << input->info()->tensor_shape()
843 << " Output shape: " << output->info()->tensor_shape()
844 << " Permutation vector: " << perm
845 << std::endl);
846
847 return std::move(func);
848}
849
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100850/** Create a backend pooling layer function
851 *
852 * @tparam PoolingLayerFunction Backend pooling function
853 * @tparam TargetInfo Target-specific information
854 *
855 * @param[in] node Node to create the backend function for
856 *
857 * @return Backend pooling layer function
858 */
859template <typename PoolingLayerFunction, typename TargetInfo>
860std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
861{
862 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
863
864 // Extract IO and info
865 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
866 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
867 const PoolingLayerInfo pool_info = node.pooling_info();
868 ARM_COMPUTE_ERROR_ON(input == nullptr);
869 ARM_COMPUTE_ERROR_ON(output == nullptr);
870
871 // Create and configure function
872 auto func = support::cpp14::make_unique<PoolingLayerFunction>();
873 func->configure(input, output, pool_info);
874
875 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000876 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
877 << node.name()
878 << " Type: " << node.type()
879 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100880 << " Data Type: " << input->info()->data_type()
881 << " Input shape: " << input->info()->tensor_shape()
882 << " Output shape: " << output->info()->tensor_shape()
883 << " Pooling info: " << pool_info.pool_type()
884 << std::endl);
885
886 return std::move(func);
887}
888
Pablo Tello32521432018-11-15 14:43:10 +0000889/** Create a backend priorbox layer function
890 *
891 * @tparam PriorBoxLayerFunction Backend priorbox function
892 * @tparam TargetInfo Target-specific information
893 *
894 * @param[in] node Node to create the backend function for
895 *
896 * @return Backend priorbox layer function
897 */
898template <typename PriorBoxLayerFunction, typename TargetInfo>
899std::unique_ptr<IFunction> create_priorbox_layer(PriorBoxLayerNode &node)
900{
901 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
902
903 // Extract IO and info
904 typename TargetInfo::TensorType *input0 = get_backing_tensor<TargetInfo>(node.input(0));
905 typename TargetInfo::TensorType *input1 = get_backing_tensor<TargetInfo>(node.input(1));
906 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
907 const PriorBoxLayerInfo prior_info = node.priorbox_info();
908 ARM_COMPUTE_ERROR_ON(input0 == nullptr);
909 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
910 ARM_COMPUTE_ERROR_ON(output == nullptr);
911
912 // Create and configure function
913 auto func = support::cpp14::make_unique<PriorBoxLayerFunction>();
914 func->configure(input0, input1, output, prior_info);
915
916 // Log info
917 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
918 << node.name()
919 << " Type: " << node.type()
920 << " Target: " << TargetInfo::TargetType
921 << " Data Type: " << input0->info()->data_type()
922 << " Input0 shape: " << input0->info()->tensor_shape()
923 << " Input1 shape: " << input1->info()->tensor_shape()
924 << " Output shape: " << output->info()->tensor_shape()
925 << " PriorBoxLayer info: " << prior_info
926 << std::endl);
927
928 return std::move(func);
929}
930
Gian Marco Iodice23e24792018-09-07 15:32:14 +0100931/** Create a backend reorg layer function
932 *
Michele Di Giorgioc30b6682018-09-12 17:44:08 +0100933 * @tparam ReorgLayerFunction Backend reorg function
Gian Marco Iodice23e24792018-09-07 15:32:14 +0100934 * @tparam TargetInfo Target-specific information
935 *
936 * @param[in] node Node to create the backend function for
937 *
938 * @return Backend reshape layer function
939 */
940template <typename ReorgLayerFunction, typename TargetInfo>
941std::unique_ptr<IFunction> create_reorg_layer(ReorgLayerNode &node)
942{
943 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
944
945 // Extract IO and info
946 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
947 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
948 ARM_COMPUTE_ERROR_ON(input == nullptr);
949 ARM_COMPUTE_ERROR_ON(output == nullptr);
950
951 // Create and configure function
952 auto func = support::cpp14::make_unique<ReorgLayerFunction>();
953 func->configure(input, output, node.stride());
954
955 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000956 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
957 << node.name()
958 << " Type: " << node.type()
959 << " Target: " << TargetInfo::TargetType
Gian Marco Iodice23e24792018-09-07 15:32:14 +0100960 << " Data Type: " << input->info()->data_type()
961 << " Input shape: " << input->info()->tensor_shape()
962 << " Output shape: " << output->info()->tensor_shape()
963 << std::endl);
964
965 return std::move(func);
966}
967
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100968/** Create a backend reshape layer function
969 *
970 * @tparam ReshapeLayerFunction Backend reshape function
971 * @tparam TargetInfo Target-specific information
972 *
973 * @param[in] node Node to create the backend function for
974 *
975 * @return Backend reshape layer function
976 */
977template <typename ReshapeLayerFunction, typename TargetInfo>
978std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
979{
980 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
981
982 // Extract IO and info
983 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
984 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
985 ARM_COMPUTE_ERROR_ON(input == nullptr);
986 ARM_COMPUTE_ERROR_ON(output == nullptr);
987
988 // Create and configure function
989 auto func = support::cpp14::make_unique<ReshapeLayerFunction>();
990 func->configure(input, output);
991
992 // Log info
Pablo Tello32521432018-11-15 14:43:10 +0000993 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
994 << node.name()
995 << " Type: " << node.type()
996 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +0100997 << " Data Type: " << input->info()->data_type()
998 << " Input shape: " << input->info()->tensor_shape()
999 << " Output shape: " << output->info()->tensor_shape()
1000 << std::endl);
1001
1002 return std::move(func);
1003}
1004
1005/** Create a backend resize layer function
1006 *
1007 * @tparam ResizeLayerFunction Backend resize function
1008 * @tparam TargetInfo Target-specific information
1009 *
1010 * @param[in] node Node to create the backend function for
1011 *
1012 * @return Backend resize layer function
1013 */
1014template <typename ResizeLayerFunction, typename TargetInfo>
1015std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
1016{
1017 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1018
1019 // Extract IO and info
1020 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1021 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1022 ARM_COMPUTE_ERROR_ON(input == nullptr);
1023 ARM_COMPUTE_ERROR_ON(output == nullptr);
1024 const InterpolationPolicy policy = node.policy();
1025
1026 // Create and configure function
1027 auto func = support::cpp14::make_unique<ResizeLayerFunction>();
1028 func->configure(input, output, policy, BorderMode::CONSTANT);
1029
1030 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001031 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1032 << node.name()
1033 << " Type: " << node.type()
1034 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001035 << " Data Type: " << input->info()->data_type()
1036 << " Input shape: " << input->info()->tensor_shape()
1037 << " Output shape: " << output->info()->tensor_shape()
1038 << " Interpolation: " << policy
1039 << std::endl);
1040
1041 return std::move(func);
1042}
1043
Manuel Bottini3f9d4d72018-10-19 14:04:42 +01001044/** Create a backend ROI align layer function
1045 *
1046 * @tparam ROIAlignLayerFunction ROI Align function
1047 * @tparam TargetInfo Target-specific information
1048 *
1049 * @param[in] node Node to create the backend function for
1050 *
1051 * @return ROI Align layer function
1052 */
1053template <typename ROIAlignLayerFunction, typename TargetInfo>
1054std::unique_ptr<IFunction> create_roi_align_layer(ROIAlignLayerNode &node)
1055{
1056 validate_node<TargetInfo>(node, 2 /* expected inputs */, 1 /* expected outputs */);
1057
1058 // Extract IO and info
1059 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1060 typename TargetInfo::TensorType *rois = get_backing_tensor<TargetInfo>(node.input(1));
1061 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1062 ARM_COMPUTE_ERROR_ON(input == nullptr);
1063 ARM_COMPUTE_ERROR_ON(output == nullptr);
1064 ARM_COMPUTE_ERROR_ON(rois == nullptr);
1065
1066 const ROIPoolingLayerInfo pool_info = node.pooling_info();
1067
1068 // Create and configure function
1069 auto func = support::cpp14::make_unique<ROIAlignLayerFunction>();
1070
1071 func->configure(input, rois, output, pool_info);
1072
1073 // Log info
1074 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << 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 << " ROIs shape: " << rois->info()->tensor_shape()
1080 << " ROIPooling width: " << pool_info.pooled_width()
1081 << " ROIPooling height: " << pool_info.pooled_height()
1082 << std::endl);
1083
1084 return std::move(func);
1085}
1086
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001087/** Create a backend slice layer function
1088 *
1089 * @tparam SliceLayerFunction Backend slice function
1090 * @tparam TargetInfo Target-specific information
1091 *
1092 * @param[in] node Node to create the backend function for
1093 *
1094 * @return Backend slice layer function
1095 */
1096template <typename SliceLayerFunction, typename TargetInfo>
1097std::unique_ptr<IFunction> create_slice_layer(SliceLayerNode &node)
1098{
1099 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1100
1101 // Extract IO and info
1102 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1103 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1104 ARM_COMPUTE_ERROR_ON(input == nullptr);
1105 ARM_COMPUTE_ERROR_ON(output == nullptr);
1106
1107 // Create and configure function
1108 auto func = support::cpp14::make_unique<SliceLayerFunction>();
1109 func->configure(input, output, node.starts(), node.ends());
1110
1111 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001112 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1113 << node.name()
1114 << " Type: " << node.type()
1115 << " Target: " << TargetInfo::TargetType
Michele Di Giorgioc30b6682018-09-12 17:44:08 +01001116 << " Data Type: " << input->info()->data_type()
1117 << " Input shape: " << input->info()->tensor_shape()
1118 << " Output shape: " << output->info()->tensor_shape()
1119 << std::endl);
1120
1121 return std::move(func);
1122}
1123
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001124/** Create a backend softmax layer function
1125 *
1126 * @tparam SoftmaxLayerFunction Backend softmax function
1127 * @tparam TargetInfo Target-specific information
1128 *
1129 * @param[in] node Node to create the backend function for
1130 * @param[in] ctx Graph context
1131 *
1132 * @return Backend softmax layer function
1133 */
1134template <typename SoftmaxLayerFunction, typename TargetInfo>
1135std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
1136{
1137 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1138
1139 // Extract IO and info
1140 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1141 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1142 const float beta = node.beta();
1143 ARM_COMPUTE_ERROR_ON(input == nullptr);
1144 ARM_COMPUTE_ERROR_ON(output == nullptr);
1145
1146 // Create and configure function
1147 auto func = support::cpp14::make_unique<SoftmaxLayerFunction>(get_memory_manager(ctx, TargetInfo::TargetType));
1148 func->configure(input, output, beta);
1149
1150 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001151 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1152 << node.name()
1153 << " Type: " << node.type()
1154 << " Target: " << TargetInfo::TargetType
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001155 << " Data Type: " << input->info()->data_type()
1156 << " Input shape: " << input->info()->tensor_shape()
1157 << " Output shape: " << output->info()->tensor_shape()
1158 << std::endl);
1159
1160 return std::move(func);
1161}
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001162/** Create a backend Upsample layer function
1163 *
1164 * @tparam UpsampleLayerFunction Backend Upsample function
1165 * @tparam TargetInfo Target-specific information
1166 *
1167 * @param[in] node Node to create the backend function for
1168 * @param[in] ctx Graph context
1169 *
1170 * @return Backend Upsample layer function
1171 */
1172template <typename UpsampleLayerFunction, typename TargetInfo>
1173std::unique_ptr<IFunction> create_upsample_layer(UpsampleLayerNode &node, GraphContext &ctx)
1174{
1175 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1176
1177 // Extract IO and info
1178 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1179 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1180 const Size2D info = node.info();
1181 const InterpolationPolicy upsampling_policy = node.upsampling_policy();
1182 ARM_COMPUTE_ERROR_ON(upsampling_policy != InterpolationPolicy::NEAREST_NEIGHBOR);
1183 ARM_COMPUTE_ERROR_ON(info.x() != 2 || info.y() != 2);
1184 ARM_COMPUTE_ERROR_ON(input == nullptr);
1185 ARM_COMPUTE_ERROR_ON(output == nullptr);
1186
1187 // Create and configure function
1188 auto func = support::cpp14::make_unique<UpsampleLayerFunction>();
1189 func->configure(input, output, info, upsampling_policy);
1190
1191 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001192 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1193 << node.name()
1194 << " Type: " << node.type()
1195 << " Target: " << TargetInfo::TargetType
Michalis Spyrou4e1c3f32018-09-20 17:14:03 +01001196 << " Data Type: " << input->info()->data_type()
1197 << " Input shape: " << input->info()->tensor_shape()
1198 << " Output shape: " << output->info()->tensor_shape()
1199 << " Strides: " << info
1200 << " Upsampling policy: " << upsampling_policy
1201 << std::endl);
1202
1203 return std::move(func);
1204}
Michalis Spyrou96f67692018-09-13 11:39:28 +01001205/** Create a backend YOLO layer function
1206 *
1207 * @tparam YoloLayerFunction Backend YOLO function
1208 * @tparam TargetInfo Target-specific information
1209 *
1210 * @param[in] node Node to create the backend function for
1211 * @param[in] ctx Graph context
1212 *
1213 * @return Backend YOLO layer function
1214 */
1215template <typename YOLOlayerFunction, typename TargetInfo>
1216std::unique_ptr<IFunction> create_yolo_layer(YOLOLayerNode &node, GraphContext &ctx)
1217{
1218 validate_node<TargetInfo>(node, 1 /* expected inputs */, 1 /* expected outputs */);
1219
1220 // Extract IO and info
1221 typename TargetInfo::TensorType *input = get_backing_tensor<TargetInfo>(node.input(0));
1222 typename TargetInfo::TensorType *output = get_backing_tensor<TargetInfo>(node.output(0));
1223 const ActivationLayerInfo act_info = node.activation_info();
1224 const int32_t num_classes = node.num_classes();
1225 ARM_COMPUTE_ERROR_ON(num_classes <= 0);
1226 ARM_COMPUTE_ERROR_ON(input == nullptr);
1227 ARM_COMPUTE_ERROR_ON(output == nullptr);
1228
1229 // Create and configure function
1230 auto func = support::cpp14::make_unique<YOLOlayerFunction>();
1231 func->configure(input, output, act_info, num_classes);
1232
1233 // Log info
Pablo Tello32521432018-11-15 14:43:10 +00001234 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated "
1235 << node.name()
1236 << " Type: " << node.type()
1237 << " Target: " << TargetInfo::TargetType
Michalis Spyrou96f67692018-09-13 11:39:28 +01001238 << " Data Type: " << input->info()->data_type()
1239 << " Input shape: " << input->info()->tensor_shape()
1240 << " Output shape: " << output->info()->tensor_shape()
1241 << " Activation function: " << act_info.activation()
1242 << " Num classes: " << num_classes
1243 << std::endl);
1244
1245 return std::move(func);
1246}
Georgios Pinitasda2491f2018-06-01 17:49:09 +01001247} // namespace detail
1248} // namespace backends
1249} // namespace graph
1250} // namespace arm_compute
1251
1252#endif /* __ARM_COMPUTE_GRAPH_BACKENDS_DETAIL_FUNCTION_HELPERS_H__ */