blob: 90ea81f21ad489bca6d3fb66c5b7af64fd949871 [file] [log] [blame]
Georgios Pinitasd8734b52017-12-22 15:27:52 +00001/*
2 * Copyright (c) 2018 ARM Limited.
3 *
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 */
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010024#include "arm_compute/graph/backends/CL/CLFunctionFactory.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000025
26#include "arm_compute/core/utils/misc/Cast.h"
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010027#include "arm_compute/graph/Graph.h"
28#include "arm_compute/graph/GraphContext.h"
29#include "arm_compute/graph/Logger.h"
30#include "arm_compute/graph/TypePrinter.h"
31#include "arm_compute/graph/Types.h"
32#include "arm_compute/graph/backends/Utils.h"
33#include "arm_compute/graph/nodes/Nodes.h"
Georgios Pinitasd8734b52017-12-22 15:27:52 +000034#include "arm_compute/runtime/CL/CLFunctions.h"
35
36#include "support/ToolchainSupport.h"
37
38using namespace arm_compute::utils::cast;
39
40namespace arm_compute
41{
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010042namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +000043{
44namespace backends
45{
46namespace
47{
48/** Returns backing tensor of a given tensor
49 *
50 * @param[in] tensor Tensor to extract the backing tensor from
51 *
52 * @return Backing tensor if present else nullptr
53 */
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010054arm_compute::ICLTensor *get_backing_tensor(arm_compute::graph::Tensor *tensor)
Georgios Pinitasd8734b52017-12-22 15:27:52 +000055{
56 arm_compute::ICLTensor *backing_tensor = nullptr;
57 if(tensor != nullptr)
58 {
Georgios Pinitasd9eb2752018-04-03 13:44:29 +010059 ARM_COMPUTE_ERROR_ON(tensor->desc().target != arm_compute::graph::Target::CL);
Georgios Pinitasd8734b52017-12-22 15:27:52 +000060 // Get backing tensor handle
61 ITensorHandle *tensor_handle = tensor->handle();
62 // Get backing tensor
63 backing_tensor = (tensor_handle != nullptr) ? polymorphic_cast<ICLTensor *>(&tensor_handle->tensor()) : nullptr;
64 }
65
66 return backing_tensor;
67}
68
69/** Create a backend activation layer function
70 *
71 * @param[in] node Node to create the backend function for
72 *
73 * @return Backend activation layer function
74 */
75std::unique_ptr<IFunction> create_activation_layer(ActivationLayerNode &node)
76{
77 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
78 "Creating CL ActivationLayerNode node with ID : " << node.id() << " and Name: " << node.name()
79 << std::endl);
80 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
81 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
82
83 // Extract IO and info
84 ICLTensor *input = get_backing_tensor(node.input(0));
85 ICLTensor *output = get_backing_tensor(node.output(0));
86 const ActivationLayerInfo act_info = node.activation_info();
87
88 // Create function
89 auto func = support::cpp14::make_unique<CLActivationLayer>();
90 func->configure(input, output, act_info);
91
92 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLActivationLayer"
93 << " Data Type: " << input->info()->data_type()
94 << " Shape: " << input->info()->tensor_shape()
95 << " Activation function: " << act_info.activation()
96 << " a: " << act_info.a()
97 << " b: " << act_info.b()
98 << " InPlace : " << is_in_place_operation(input, output)
99 << std::endl);
100
101 return std::move(func);
102}
103
104/** Create a backend batch normalization layer function
105 *
106 * @param[in] node Node to create the backend function for
107 *
108 * @return Backend batch normalization layer function
109 */
110std::unique_ptr<IFunction> create_batch_normalization_layer(BatchNormalizationLayerNode &node)
111{
112 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating CL BatchNormalization node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
113
114 // TODO (geopin01) : Var and mean are compulsory, switch function to accept nullptr as beta and/or gamma
115 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 5);
116 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
117
118 // Extract IO and info
119 ICLTensor *input = get_backing_tensor(node.input(0));
120 ICLTensor *mean = get_backing_tensor(node.input(1));
121 ICLTensor *var = get_backing_tensor(node.input(2));
122 ICLTensor *beta = get_backing_tensor(node.input(3));
123 ICLTensor *gamma = get_backing_tensor(node.input(4));
124 ICLTensor *output = get_backing_tensor(node.output(0));
125 const float epsilon = node.epsilon();
126 const ActivationLayerInfo fused_act = node.fused_activation();
127
128 // Create and configure function
129 auto func = support::cpp14::make_unique<CLBatchNormalizationLayer>();
130 func->configure(input, output, mean, var, beta, gamma, epsilon, fused_act);
131
132 // Log info
133 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLBatchNormalizationLayer"
134 << " Data Type: " << input->info()->data_type()
135 << " Shape: " << input->info()->tensor_shape()
136 << " Epsilon: " << epsilon << " "
137 << (fused_act.enabled() ? to_string(fused_act.activation()) : "")
138 << " InPlace : " << is_in_place_operation(input, output)
139 << std::endl);
140
141 return std::move(func);
142}
143
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100144/** Create a backend channel shuffle layer function
145 *
146 * @param[in] node Node to create the backend function for
147 *
148 * @return Backend channel shuffle layer function
149 */
150std::unique_ptr<IFunction> create_channel_shuffle_layer(ChannelShuffleLayerNode &node)
151{
152 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
153 "Creating CL Channel Shuffle node with ID : " << node.id() << " and Name: " << node.name()
154 << std::endl);
155 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
156 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
157
158 // Extract IO and info
159 ICLTensor *input = get_backing_tensor(node.input(0));
160 ICLTensor *output = get_backing_tensor(node.output(0));
161 const unsigned int num_groups = node.num_groups();
162
163 // Create function
164 auto func = support::cpp14::make_unique<CLChannelShuffleLayer>();
165 func->configure(input, output, num_groups);
166
167 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLChannelShuffleLayer"
168 << " Data Type: " << input->info()->data_type()
169 << " Shape: " << input->info()->tensor_shape()
170 << " Num groups: " << num_groups
171 << std::endl);
172
173 return std::move(func);
174}
175
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000176/** Create a backend convolution layer function
177 *
178 * @param[in] node Node to create the backend function for
179 *
180 * @return Backend convolution layer function
181 */
182std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
183{
184 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating CL ConvolutionLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
185 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 3);
186 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
187
188 // Extract IO and info
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100189 ICLTensor *input = get_backing_tensor(node.input(0));
190 ICLTensor *weights = get_backing_tensor(node.input(1));
191 ICLTensor *biases = get_backing_tensor(node.input(2));
192 ICLTensor *output = get_backing_tensor(node.output(0));
193
194 if(is_data_type_quantized_asymmetric(input->info()->data_type()))
195 {
196 biases->info()->set_data_type(DataType::S32);
197 }
198
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000199 const PadStrideInfo conv_info = node.convolution_info();
200 const ConvolutionMethod conv_algorithm = node.convolution_method();
Giorgio Arena59631a12018-05-02 13:59:04 +0100201 const bool fast_math = node.fast_math_hint() == FastMathHint::ENABLED;
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000202
203 // Create and configure function (we assume that functions have been validated before creation)
204 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, Target::CL);
205 std::unique_ptr<IFunction> func;
206 std::string func_name;
Gian Marco Iodiceed99f412018-03-21 17:45:31 +0000207
208 if(conv_algorithm == ConvolutionMethod::WINOGRAD)
209 {
Georgios Pinitas82b51482018-04-24 15:14:12 +0100210 std::tie(func, func_name) = create_named_memory_managed_function<CLWinogradConvolutionLayer>(
Giorgio Arena59631a12018-05-02 13:59:04 +0100211 std::string("CLWinogradConvolutionLayer"), mm, input, weights, biases, output, conv_info, ActivationLayerInfo(), fast_math);
Gian Marco Iodiceed99f412018-03-21 17:45:31 +0000212 }
213 else if(conv_algorithm == ConvolutionMethod::DIRECT)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000214 {
215 std::tie(func, func_name) = create_named_function<CLDirectConvolutionLayer>(
216 std::string("CLDirectConvolutionLayer"), input, weights, biases, output, conv_info);
217 }
218 else if(conv_algorithm == ConvolutionMethod::GEMM)
219 {
220 std::tie(func, func_name) = create_named_memory_managed_function<CLGEMMConvolutionLayer>(std::string("CLGEMMConvolutionLayer"), mm,
221 input, weights, biases, output, conv_info);
222 }
223 else
224 {
225 std::tie(func, func_name) = create_named_memory_managed_function<CLConvolutionLayer>(std::string("CLConvolutionLayer"), mm,
Giorgio Arena59631a12018-05-02 13:59:04 +0100226 input, weights, biases, output, conv_info, WeightsInfo(), Size2D(1U, 1U), ActivationLayerInfo(), fast_math);
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000227 }
228
229 // Log info
230 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
231 << " Data Type: " << input->info()->data_type()
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100232 << " Input QuantInfo: " << input->info()->quantization_info()
233 << " Weights QuantInfo: " << weights->info()->quantization_info()
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000234 << " Input shape: " << input->info()->tensor_shape()
235 << " Weights shape: " << weights->info()->tensor_shape()
236 << " Output shape: " << output->info()->tensor_shape()
237 << std::endl);
238 return func;
239}
240
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100241/** Create a backend deconvolution layer function
242 *
243 * @param[in] node Node to create the backend function for
244 *
245 * @return Backend deconvolution layer function
246 */
247std::unique_ptr<IFunction> create_deconvolution_layer(DeconvolutionLayerNode &node, GraphContext &ctx)
248{
249 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating CL DeconvolutionLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
250 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 3);
251 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
252
253 // Extract IO and info
254 ICLTensor *input = get_backing_tensor(node.input(0));
255 ICLTensor *weights = get_backing_tensor(node.input(1));
256 ICLTensor *biases = get_backing_tensor(node.input(2));
257 ICLTensor *output = get_backing_tensor(node.output(0));
258
259 const PadStrideInfo deconv_info = node.deconvolution_info();
260 const Size2D inner_border = node.inner_border();
261
262 // Create and configure function (we assume that functions have been validated before creation)
263 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, Target::CL);
264 std::unique_ptr<IFunction> func;
265 std::string func_name;
266
267 std::tie(func, func_name) = create_named_memory_managed_function<CLDeconvolutionLayer>(std::string("CLDeconvolutionLayer"), mm,
268 input, weights, biases, output,
269 deconv_info, inner_border.x(), inner_border.y());
270
271 // Log info
272 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
273 << " Data Type: " << input->info()->data_type()
274 << " Input shape: " << input->info()->tensor_shape()
275 << " Weights shape: " << weights->info()->tensor_shape()
276 << " Output shape: " << output->info()->tensor_shape()
277 << std::endl);
278 return func;
279}
280
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000281/** Create a backend layer depth concatenate function
282 *
283 * @param[in] node Node to create the backend function for
284 *
285 * @return Backend depth concatenate layer function
286 */
287std::unique_ptr<arm_compute::IFunction> create_depth_concatenate_layer(DepthConcatenateLayerNode &node)
288{
289 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating CL DepthConcatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
290 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
291
292 // Return nullptr if depth concatenate is switched off
293 if(!node.is_enabled())
294 {
295 return nullptr;
296 }
297
298 // Extract IO and info
299 std::vector<arm_compute::ICLTensor *> inputs;
300 for(unsigned int i = 0; i < node.num_inputs(); ++i)
301 {
302 inputs.push_back(get_backing_tensor(node.input(i)));
303 }
304 ICLTensor *output = get_backing_tensor(node.output(0));
305
306 // Create and configure function
307 auto func = support::cpp14::make_unique<CLDepthConcatenateLayer>();
308 func->configure(inputs, output);
309
310 // Log info
311 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLDepthConcatenateLayer"
312 << " Data Type: " << output->info()->data_type()
313 << " Shape: " << output->info()->tensor_shape()
314 << " Num Inputs: " << inputs.size()
315 << std::endl);
316
317 return std::move(func);
318}
319
320/** Create a backend layer depth-wise convolution function
321 *
322 * @param[in] node Node to create the backend function for
323 *
324 * @return Backend depth-wise convolution layer function
325 */
326std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
327{
328 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
329 "Creating CL DepthwiseConvolutionLayer node with ID : " << node.id() << " and Name: " << node.name()
330 << std::endl);
331 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 3);
332 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
333
334 // Extract IO and info
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100335 ICLTensor *input = get_backing_tensor(node.input(0));
336 ICLTensor *weights = get_backing_tensor(node.input(1));
337 ICLTensor *biases = get_backing_tensor(node.input(2));
338 ICLTensor *output = get_backing_tensor(node.output(0));
339
340 if(is_data_type_quantized_asymmetric(input->info()->data_type()))
341 {
342 biases->info()->set_data_type(DataType::S32);
343 }
344
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000345 const PadStrideInfo conv_info = node.convolution_info();
346 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
347
348 // Create and configure function (we assume that functions have been validated before creation)
349 std::unique_ptr<IFunction> func;
350 std::string func_name;
351 if(dwc_algorithm == DepthwiseConvolutionMethod::OPTIMIZED_3x3)
352 {
353 std::tie(func, func_name) = create_named_function<CLDepthwiseConvolutionLayer3x3>(
354 std::string("CLDepthwiseConvolutionLayer3x3"), input, weights, biases, output, conv_info);
355 }
356 else
357 {
358 std::tie(func, func_name) = create_named_function<CLDepthwiseConvolutionLayer>(
359 std::string("CLDepthwiseConvolutionLayer"), input, weights, biases, output, conv_info);
360 }
361
362 // Log info
363 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
364 << " Data Type: " << input->info()->data_type()
Giorgio Arenabb54e4e2018-04-05 17:20:34 +0100365 << " Input QuantInfo: " << input->info()->quantization_info()
366 << " Weights QuantInfo: " << weights->info()->quantization_info()
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000367 << " Input shape: " << input->info()->tensor_shape()
368 << " Weights shape: " << weights->info()->tensor_shape()
369 << " Output shape: " << output->info()->tensor_shape()
370 << std::endl);
371 return func;
372}
373
374/** Create a backend element-wise operation layer function
375 *
376 * @param[in] node Node to create the backend function for
377 *
378 * @return Backend element-wise operation layer function
379 */
380std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
381{
382 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
383 "Creating CL EltwiseLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
384 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 2);
385 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
386
387 // Extract IO and info
Isabella Gottardi88d5b222018-04-06 12:24:55 +0100388 ICLTensor *input1 = get_backing_tensor(node.input(0));
389 ICLTensor *input2 = get_backing_tensor(node.input(1));
390 ICLTensor *output = get_backing_tensor(node.output(0));
391 const EltwiseOperation eltwise_op = node.eltwise_operation();
392 const ConvertPolicy convert_policy = node.convert_policy();
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000393 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
394 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
395 ARM_COMPUTE_ERROR_ON(output == nullptr);
396
397 std::unique_ptr<IFunction> func = nullptr;
398 std::string func_name;
399 if(eltwise_op == EltwiseOperation::ADD)
400 {
401 std::tie(func, func_name) = create_named_function<CLArithmeticAddition>(std::string("CLArithmeticAddition"),
402 input1, input2, output,
Isabella Gottardi88d5b222018-04-06 12:24:55 +0100403 convert_policy);
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000404 }
405 else if(eltwise_op == EltwiseOperation::SUB)
406 {
407 std::tie(func, func_name) = create_named_function<CLArithmeticSubtraction>(
Isabella Gottardi88d5b222018-04-06 12:24:55 +0100408 std::string("CLArithmeticSubtraction"), input1, input2, output, convert_policy);
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000409 }
410 else if(eltwise_op == EltwiseOperation::MUL)
411 {
412 std::tie(func, func_name) = create_named_function<CLPixelWiseMultiplication>(
Isabella Gottardi88d5b222018-04-06 12:24:55 +0100413 std::string("CLPixelWiseMultiplication"), input1, input2, output, 1.f, convert_policy,
414 node.rounding_policy());
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000415 }
416 else
417 {
418 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
419 }
420
421 // Log info
422 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
423 << " Data Type: " << input1->info()->data_type()
424 << " Shape : " << input1->info()->tensor_shape()
425 << std::endl);
426
427 return func;
428}
429
430/** Create a backend flatten layer function
431 *
432 * @param[in] node Node to create the backend function for
433 *
434 * @return Backend flatten layer function
435 */
436std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
437{
438 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
439 "Creating CL FlattenLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
440 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
441 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
442
443 // Extract IO and info
444 ICLTensor *input = get_backing_tensor(node.input(0));
445 ICLTensor *output = get_backing_tensor(node.output(0));
446
447 // Create and configure function
448 auto func = support::cpp14::make_unique<CLFlattenLayer>();
449 func->configure(input, output);
450 ARM_COMPUTE_ERROR_ON(input == nullptr);
451 ARM_COMPUTE_ERROR_ON(output == nullptr);
452
453 // Log info
454 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLFlattenLayer"
455 << " Data Type: " << input->info()->data_type()
456 << " Input shape: " << input->info()->tensor_shape()
457 << " Output shape: " << output->info()->tensor_shape()
458 << std::endl);
459
460 return std::move(func);
461}
462
463/** Create a backend fully connected layer function
464 *
465 * @param[in] node Node to create the backend function for
466 *
467 * @return Backend fully connected layer function
468 */
469std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
470{
471 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
472 "Creating CL FullyConnectedLayer node with ID : " << node.id() << " and Name: " << node.name()
473 << std::endl);
474 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 3);
475 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
476
477 // Extract IO and info
478 ICLTensor *input = get_backing_tensor(node.input(0));
479 ICLTensor *weights = get_backing_tensor(node.input(1));
480 ICLTensor *biases = get_backing_tensor(node.input(2));
481 ICLTensor *output = get_backing_tensor(node.output(0));
482
483 // Create and configure function
484 auto func = support::cpp14::make_unique<CLFullyConnectedLayer>(get_memory_manager(ctx, Target::CL));
485 func->configure(input, weights, biases, output);
486 ARM_COMPUTE_ERROR_ON(input == nullptr);
487 ARM_COMPUTE_ERROR_ON(weights == nullptr);
488 ARM_COMPUTE_ERROR_ON(output == nullptr);
489
490 // Log info
491 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLFullyConnectedLayer"
492 << " Data Type: " << input->info()->data_type()
493 << " Input shape: " << input->info()->tensor_shape()
494 << " Weights shape: " << weights->info()->tensor_shape()
495 << " Biases Shape: " << biases->info()->tensor_shape()
496 << " Output shape: " << output->info()->tensor_shape()
497 << std::endl);
498
499 return std::move(func);
500}
501
502/** Create a backend normalization layer function
503 *
504 * @param[in] node Node to create the backend function for
505 *
506 * @return Backend normalization layer function
507 */
508std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node)
509{
510 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
511 "Creating CL NormalizationLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
512 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
513 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
514
515 // Extract IO and info
516 ICLTensor *input = get_backing_tensor(node.input(0));
517 ICLTensor *output = get_backing_tensor(node.output(0));
518 const NormalizationLayerInfo norm_info = node.normalization_info();
519 ARM_COMPUTE_ERROR_ON(input == nullptr);
520 ARM_COMPUTE_ERROR_ON(output == nullptr);
521
522 // Create and configure function
523 auto func = support::cpp14::make_unique<CLNormalizationLayer>();
524 func->configure(input, output, norm_info);
525
526 // Log info
527 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLNormalizationLayer"
528 << " Data Type: " << input->info()->data_type()
529 << " Input shape: " << input->info()->tensor_shape()
530 << " Output shape: " << output->info()->tensor_shape()
531 << " Normalization info: " << norm_info.type()
532 << std::endl);
533
534 return std::move(func);
535}
536
537/** Create a backend pooling layer function
538 *
539 * @param[in] node Node to create the backend function for
540 *
541 * @return Backend pooling layer function
542 */
543std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
544{
545 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
546 "Creating CL PoolingLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
547 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
548 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
549
550 // Extract IO and info
551 ICLTensor *input = get_backing_tensor(node.input(0));
552 ICLTensor *output = get_backing_tensor(node.output(0));
553 const PoolingLayerInfo pool_info = node.pooling_info();
554 ARM_COMPUTE_ERROR_ON(input == nullptr);
555 ARM_COMPUTE_ERROR_ON(output == nullptr);
556
557 // Create and configure function
558 auto func = support::cpp14::make_unique<CLPoolingLayer>();
559 func->configure(input, output, pool_info);
560
561 // Log info
562 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLPoolingLayer"
563 << " Data Type: " << input->info()->data_type()
564 << " Input shape: " << input->info()->tensor_shape()
565 << " Output shape: " << output->info()->tensor_shape()
566 << " Pooling info: " << pool_info.pool_type()
567 << std::endl);
568
569 return std::move(func);
570}
571
572/** Create a backend reshape layer function
573 *
574 * @param[in] node Node to create the backend function for
575 *
576 * @return Backend reshape layer function
577 */
578std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
579{
580 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
581 "Creating CL ReshapeLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
582 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
583 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
584
585 // Extract IO and info
586 ICLTensor *input = get_backing_tensor(node.input(0));
587 ICLTensor *output = get_backing_tensor(node.output(0));
588 ARM_COMPUTE_ERROR_ON(input == nullptr);
589 ARM_COMPUTE_ERROR_ON(output == nullptr);
590
591 // Create and configure function
592 auto func = support::cpp14::make_unique<CLReshapeLayer>();
593 func->configure(input, output);
594
595 // Log info
596 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLReshapeLayer"
597 << " Data Type: " << input->info()->data_type()
598 << " Input shape: " << input->info()->tensor_shape()
599 << " Output shape: " << output->info()->tensor_shape()
600 << std::endl);
601
602 return std::move(func);
603}
604
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100605/** Create a backend resize layer function
606 *
607 * @param[in] node Node to create the backend function for
608 *
609 * @return Backend resize layer function
610 */
611std::unique_ptr<IFunction> create_resize_layer(ResizeLayerNode &node)
612{
613 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
614 "Creating CL Resize node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
615 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
616 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
617
618 // Extract IO and info
619 ICLTensor *input = get_backing_tensor(node.input(0));
620 ICLTensor *output = get_backing_tensor(node.output(0));
621 ARM_COMPUTE_ERROR_ON(input == nullptr);
622 ARM_COMPUTE_ERROR_ON(output == nullptr);
623 const InterpolationPolicy policy = node.policy();
624
625 // Create and configure function
626 auto func = support::cpp14::make_unique<CLScale>();
627 func->configure(input, output, policy, BorderMode::CONSTANT);
628
629 // Log info
630 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLScale"
631 << " Data Type: " << input->info()->data_type()
632 << " Input shape: " << input->info()->tensor_shape()
633 << " Output shape: " << output->info()->tensor_shape()
634 << " Interpolation: " << policy
635 << std::endl);
636
637 return std::move(func);
638}
639
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000640/** Create a backend softmax layer function
641 *
642 * @param[in] node Node to create the backend function for
643 *
644 * @return Backend softmax layer function
645 */
646std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
647{
648 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
649 "Creating CL SoftmaxLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
650 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
651 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
652
653 // Extract IO and info
654 ICLTensor *input = get_backing_tensor(node.input(0));
655 ICLTensor *output = get_backing_tensor(node.output(0));
656 const float beta = node.beta();
657 ARM_COMPUTE_ERROR_ON(input == nullptr);
658 ARM_COMPUTE_ERROR_ON(output == nullptr);
659
660 // Create and configure function
661 auto func = support::cpp14::make_unique<CLSoftmaxLayer>(get_memory_manager(ctx, Target::CL));
662 func->configure(input, output, beta);
663
664 // Log info
665 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLSoftmaxLayer"
666 << " Data Type: " << input->info()->data_type()
667 << " Input shape: " << input->info()->tensor_shape()
668 << " Output shape: " << output->info()->tensor_shape()
669 << std::endl);
670
671 return std::move(func);
672}
673} // namespace
674
675std::unique_ptr<IFunction> CLFunctionFactory::create(INode *node, GraphContext &ctx)
676{
677 if(node == nullptr)
678 {
679 return nullptr;
680 }
681
682 NodeType type = node->type();
683 switch(type)
684 {
685 case NodeType::ActivationLayer:
686 return create_activation_layer(*polymorphic_downcast<ActivationLayerNode *>(node));
687 case NodeType::BatchNormalizationLayer:
688 return create_batch_normalization_layer(*polymorphic_downcast<BatchNormalizationLayerNode *>(node));
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100689 case NodeType::ChannelShuffleLayer:
690 return create_channel_shuffle_layer(*polymorphic_downcast<ChannelShuffleLayerNode *>(node));
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000691 case NodeType::ConvolutionLayer:
692 return create_convolution_layer(*polymorphic_downcast<ConvolutionLayerNode *>(node), ctx);
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100693 case NodeType::DeconvolutionLayer:
694 return create_deconvolution_layer(*polymorphic_downcast<DeconvolutionLayerNode *>(node), ctx);
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000695 case NodeType::DepthConcatenateLayer:
696 return create_depth_concatenate_layer(*polymorphic_downcast<DepthConcatenateLayerNode *>(node));
697 case NodeType::DepthwiseConvolutionLayer:
698 return create_depthwise_convolution_layer(*polymorphic_downcast<DepthwiseConvolutionLayerNode *>(node));
699 case NodeType::EltwiseLayer:
700 return create_eltwise_layer(*polymorphic_downcast<EltwiseLayerNode *>(node));
701 case NodeType::FlattenLayer:
702 return create_flatten_layer(*polymorphic_downcast<FlattenLayerNode *>(node));
703 case NodeType::FullyConnectedLayer:
704 return create_fully_connected_layer(*polymorphic_downcast<FullyConnectedLayerNode *>(node), ctx);
705 case NodeType::NormalizationLayer:
706 return create_normalization_layer(*polymorphic_downcast<NormalizationLayerNode *>(node));
707 case NodeType::PoolingLayer:
708 return create_pooling_layer(*polymorphic_downcast<PoolingLayerNode *>(node));
709 case NodeType::ReshapeLayer:
710 return create_reshape_layer(*polymorphic_downcast<ReshapeLayerNode *>(node));
Georgios Pinitas087eaf62018-05-16 15:52:35 +0100711 case NodeType::ResizeLayer:
712 return create_resize_layer(*polymorphic_downcast<ResizeLayerNode *>(node));
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000713 case NodeType::SoftmaxLayer:
714 return create_softmax_layer(*polymorphic_downcast<SoftmaxLayerNode *>(node), ctx);
715 default:
716 return nullptr;
717 }
718}
719} // namespace backends
Georgios Pinitasd9eb2752018-04-03 13:44:29 +0100720} // namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000721} // namespace arm_compute