blob: 1b448fefd2ca7bd379b8f97113eca99651aec50c [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
144/** Create a backend convolution layer function
145 *
146 * @param[in] node Node to create the backend function for
147 *
148 * @return Backend convolution layer function
149 */
150std::unique_ptr<IFunction> create_convolution_layer(ConvolutionLayerNode &node, GraphContext &ctx)
151{
152 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating CL ConvolutionLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
153 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 3);
154 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
155
156 // Extract IO and info
157 ICLTensor *input = get_backing_tensor(node.input(0));
158 ICLTensor *weights = get_backing_tensor(node.input(1));
159 ICLTensor *biases = get_backing_tensor(node.input(2));
160 ICLTensor *output = get_backing_tensor(node.output(0));
161 const PadStrideInfo conv_info = node.convolution_info();
162 const ConvolutionMethod conv_algorithm = node.convolution_method();
163
164 // Create and configure function (we assume that functions have been validated before creation)
165 std::shared_ptr<IMemoryManager> mm = get_memory_manager(ctx, Target::CL);
166 std::unique_ptr<IFunction> func;
167 std::string func_name;
Gian Marco Iodiceed99f412018-03-21 17:45:31 +0000168
169 if(conv_algorithm == ConvolutionMethod::WINOGRAD)
170 {
171 std::tie(func, func_name) = create_named_function<CLWinogradConvolutionLayer>(
172 std::string("CLWinogradConvolutionLayer"), input, weights, biases, output, conv_info);
173 }
174 else if(conv_algorithm == ConvolutionMethod::DIRECT)
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000175 {
176 std::tie(func, func_name) = create_named_function<CLDirectConvolutionLayer>(
177 std::string("CLDirectConvolutionLayer"), input, weights, biases, output, conv_info);
178 }
179 else if(conv_algorithm == ConvolutionMethod::GEMM)
180 {
181 std::tie(func, func_name) = create_named_memory_managed_function<CLGEMMConvolutionLayer>(std::string("CLGEMMConvolutionLayer"), mm,
182 input, weights, biases, output, conv_info);
183 }
184 else
185 {
186 std::tie(func, func_name) = create_named_memory_managed_function<CLConvolutionLayer>(std::string("CLConvolutionLayer"), mm,
187 input, weights, biases, output, conv_info);
188 }
189
190 // Log info
191 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
192 << " Data Type: " << input->info()->data_type()
193 << " Input shape: " << input->info()->tensor_shape()
194 << " Weights shape: " << weights->info()->tensor_shape()
195 << " Output shape: " << output->info()->tensor_shape()
196 << std::endl);
197 return func;
198}
199
200/** Create a backend layer depth concatenate function
201 *
202 * @param[in] node Node to create the backend function for
203 *
204 * @return Backend depth concatenate layer function
205 */
206std::unique_ptr<arm_compute::IFunction> create_depth_concatenate_layer(DepthConcatenateLayerNode &node)
207{
208 ARM_COMPUTE_LOG_GRAPH_VERBOSE("Creating CL DepthConcatenate node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
209 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
210
211 // Return nullptr if depth concatenate is switched off
212 if(!node.is_enabled())
213 {
214 return nullptr;
215 }
216
217 // Extract IO and info
218 std::vector<arm_compute::ICLTensor *> inputs;
219 for(unsigned int i = 0; i < node.num_inputs(); ++i)
220 {
221 inputs.push_back(get_backing_tensor(node.input(i)));
222 }
223 ICLTensor *output = get_backing_tensor(node.output(0));
224
225 // Create and configure function
226 auto func = support::cpp14::make_unique<CLDepthConcatenateLayer>();
227 func->configure(inputs, output);
228
229 // Log info
230 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLDepthConcatenateLayer"
231 << " Data Type: " << output->info()->data_type()
232 << " Shape: " << output->info()->tensor_shape()
233 << " Num Inputs: " << inputs.size()
234 << std::endl);
235
236 return std::move(func);
237}
238
239/** Create a backend layer depth-wise convolution function
240 *
241 * @param[in] node Node to create the backend function for
242 *
243 * @return Backend depth-wise convolution layer function
244 */
245std::unique_ptr<IFunction> create_depthwise_convolution_layer(DepthwiseConvolutionLayerNode &node)
246{
247 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
248 "Creating CL DepthwiseConvolutionLayer node with ID : " << node.id() << " and Name: " << node.name()
249 << 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 const PadStrideInfo conv_info = node.convolution_info();
259 const DepthwiseConvolutionMethod dwc_algorithm = node.depthwise_convolution_method();
260
261 // Create and configure function (we assume that functions have been validated before creation)
262 std::unique_ptr<IFunction> func;
263 std::string func_name;
264 if(dwc_algorithm == DepthwiseConvolutionMethod::OPTIMIZED_3x3)
265 {
266 std::tie(func, func_name) = create_named_function<CLDepthwiseConvolutionLayer3x3>(
267 std::string("CLDepthwiseConvolutionLayer3x3"), input, weights, biases, output, conv_info);
268 }
269 else
270 {
271 std::tie(func, func_name) = create_named_function<CLDepthwiseConvolutionLayer>(
272 std::string("CLDepthwiseConvolutionLayer"), input, weights, biases, output, conv_info);
273 }
274
275 // Log info
276 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
277 << " Data Type: " << input->info()->data_type()
278 << " Input shape: " << input->info()->tensor_shape()
279 << " Weights shape: " << weights->info()->tensor_shape()
280 << " Output shape: " << output->info()->tensor_shape()
281 << std::endl);
282 return func;
283}
284
285/** Create a backend element-wise operation layer function
286 *
287 * @param[in] node Node to create the backend function for
288 *
289 * @return Backend element-wise operation layer function
290 */
291std::unique_ptr<IFunction> create_eltwise_layer(EltwiseLayerNode &node)
292{
293 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
294 "Creating CL EltwiseLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
295 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 2);
296 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
297
298 // Extract IO and info
299 ICLTensor *input1 = get_backing_tensor(node.input(0));
300 ICLTensor *input2 = get_backing_tensor(node.input(1));
301 ICLTensor *output = get_backing_tensor(node.output(0));
302 const EltwiseOperation eltwise_op = node.eltwise_operation();
303 ARM_COMPUTE_ERROR_ON(input1 == nullptr);
304 ARM_COMPUTE_ERROR_ON(input2 == nullptr);
305 ARM_COMPUTE_ERROR_ON(output == nullptr);
306
307 std::unique_ptr<IFunction> func = nullptr;
308 std::string func_name;
309 if(eltwise_op == EltwiseOperation::ADD)
310 {
311 std::tie(func, func_name) = create_named_function<CLArithmeticAddition>(std::string("CLArithmeticAddition"),
312 input1, input2, output,
313 ConvertPolicy::SATURATE);
314 }
315 else if(eltwise_op == EltwiseOperation::SUB)
316 {
317 std::tie(func, func_name) = create_named_function<CLArithmeticSubtraction>(
318 std::string("CLArithmeticSubtraction"), input1, input2, output, ConvertPolicy::SATURATE);
319 }
320 else if(eltwise_op == EltwiseOperation::MUL)
321 {
322 std::tie(func, func_name) = create_named_function<CLPixelWiseMultiplication>(
323 std::string("CLPixelWiseMultiplication"), input1, input2, output, 1.f, ConvertPolicy::SATURATE,
324 RoundingPolicy::TO_NEAREST_EVEN);
325 }
326 else
327 {
328 ARM_COMPUTE_ERROR("Unsupported element-wise operation!");
329 }
330
331 // Log info
332 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated " << func_name
333 << " Data Type: " << input1->info()->data_type()
334 << " Shape : " << input1->info()->tensor_shape()
335 << std::endl);
336
337 return func;
338}
339
340/** Create a backend flatten layer function
341 *
342 * @param[in] node Node to create the backend function for
343 *
344 * @return Backend flatten layer function
345 */
346std::unique_ptr<IFunction> create_flatten_layer(FlattenLayerNode &node)
347{
348 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
349 "Creating CL FlattenLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
350 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
351 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
352
353 // Extract IO and info
354 ICLTensor *input = get_backing_tensor(node.input(0));
355 ICLTensor *output = get_backing_tensor(node.output(0));
356
357 // Create and configure function
358 auto func = support::cpp14::make_unique<CLFlattenLayer>();
359 func->configure(input, output);
360 ARM_COMPUTE_ERROR_ON(input == nullptr);
361 ARM_COMPUTE_ERROR_ON(output == nullptr);
362
363 // Log info
364 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLFlattenLayer"
365 << " Data Type: " << input->info()->data_type()
366 << " Input shape: " << input->info()->tensor_shape()
367 << " Output shape: " << output->info()->tensor_shape()
368 << std::endl);
369
370 return std::move(func);
371}
372
373/** Create a backend fully connected layer function
374 *
375 * @param[in] node Node to create the backend function for
376 *
377 * @return Backend fully connected layer function
378 */
379std::unique_ptr<IFunction> create_fully_connected_layer(FullyConnectedLayerNode &node, GraphContext &ctx)
380{
381 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
382 "Creating CL FullyConnectedLayer node with ID : " << node.id() << " and Name: " << node.name()
383 << std::endl);
384 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 3);
385 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
386
387 // Extract IO and info
388 ICLTensor *input = get_backing_tensor(node.input(0));
389 ICLTensor *weights = get_backing_tensor(node.input(1));
390 ICLTensor *biases = get_backing_tensor(node.input(2));
391 ICLTensor *output = get_backing_tensor(node.output(0));
392
393 // Create and configure function
394 auto func = support::cpp14::make_unique<CLFullyConnectedLayer>(get_memory_manager(ctx, Target::CL));
395 func->configure(input, weights, biases, output);
396 ARM_COMPUTE_ERROR_ON(input == nullptr);
397 ARM_COMPUTE_ERROR_ON(weights == nullptr);
398 ARM_COMPUTE_ERROR_ON(output == nullptr);
399
400 // Log info
401 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLFullyConnectedLayer"
402 << " Data Type: " << input->info()->data_type()
403 << " Input shape: " << input->info()->tensor_shape()
404 << " Weights shape: " << weights->info()->tensor_shape()
405 << " Biases Shape: " << biases->info()->tensor_shape()
406 << " Output shape: " << output->info()->tensor_shape()
407 << std::endl);
408
409 return std::move(func);
410}
411
412/** Create a backend normalization layer function
413 *
414 * @param[in] node Node to create the backend function for
415 *
416 * @return Backend normalization layer function
417 */
418std::unique_ptr<IFunction> create_normalization_layer(NormalizationLayerNode &node)
419{
420 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
421 "Creating CL NormalizationLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
422 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
423 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
424
425 // Extract IO and info
426 ICLTensor *input = get_backing_tensor(node.input(0));
427 ICLTensor *output = get_backing_tensor(node.output(0));
428 const NormalizationLayerInfo norm_info = node.normalization_info();
429 ARM_COMPUTE_ERROR_ON(input == nullptr);
430 ARM_COMPUTE_ERROR_ON(output == nullptr);
431
432 // Create and configure function
433 auto func = support::cpp14::make_unique<CLNormalizationLayer>();
434 func->configure(input, output, norm_info);
435
436 // Log info
437 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLNormalizationLayer"
438 << " Data Type: " << input->info()->data_type()
439 << " Input shape: " << input->info()->tensor_shape()
440 << " Output shape: " << output->info()->tensor_shape()
441 << " Normalization info: " << norm_info.type()
442 << std::endl);
443
444 return std::move(func);
445}
446
447/** Create a backend pooling layer function
448 *
449 * @param[in] node Node to create the backend function for
450 *
451 * @return Backend pooling layer function
452 */
453std::unique_ptr<IFunction> create_pooling_layer(PoolingLayerNode &node)
454{
455 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
456 "Creating CL PoolingLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
457 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
458 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
459
460 // Extract IO and info
461 ICLTensor *input = get_backing_tensor(node.input(0));
462 ICLTensor *output = get_backing_tensor(node.output(0));
463 const PoolingLayerInfo pool_info = node.pooling_info();
464 ARM_COMPUTE_ERROR_ON(input == nullptr);
465 ARM_COMPUTE_ERROR_ON(output == nullptr);
466
467 // Create and configure function
468 auto func = support::cpp14::make_unique<CLPoolingLayer>();
469 func->configure(input, output, pool_info);
470
471 // Log info
472 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLPoolingLayer"
473 << " Data Type: " << input->info()->data_type()
474 << " Input shape: " << input->info()->tensor_shape()
475 << " Output shape: " << output->info()->tensor_shape()
476 << " Pooling info: " << pool_info.pool_type()
477 << std::endl);
478
479 return std::move(func);
480}
481
482/** Create a backend reshape layer function
483 *
484 * @param[in] node Node to create the backend function for
485 *
486 * @return Backend reshape layer function
487 */
488std::unique_ptr<IFunction> create_reshape_layer(ReshapeLayerNode &node)
489{
490 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
491 "Creating CL ReshapeLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
492 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
493 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
494
495 // Extract IO and info
496 ICLTensor *input = get_backing_tensor(node.input(0));
497 ICLTensor *output = get_backing_tensor(node.output(0));
498 ARM_COMPUTE_ERROR_ON(input == nullptr);
499 ARM_COMPUTE_ERROR_ON(output == nullptr);
500
501 // Create and configure function
502 auto func = support::cpp14::make_unique<CLReshapeLayer>();
503 func->configure(input, output);
504
505 // Log info
506 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLReshapeLayer"
507 << " Data Type: " << input->info()->data_type()
508 << " Input shape: " << input->info()->tensor_shape()
509 << " Output shape: " << output->info()->tensor_shape()
510 << std::endl);
511
512 return std::move(func);
513}
514
515/** Create a backend softmax layer function
516 *
517 * @param[in] node Node to create the backend function for
518 *
519 * @return Backend softmax layer function
520 */
521std::unique_ptr<IFunction> create_softmax_layer(SoftmaxLayerNode &node, GraphContext &ctx)
522{
523 ARM_COMPUTE_LOG_GRAPH_VERBOSE(
524 "Creating CL SoftmaxLayer node with ID : " << node.id() << " and Name: " << node.name() << std::endl);
525 ARM_COMPUTE_ERROR_ON(node.num_inputs() != 1);
526 ARM_COMPUTE_ERROR_ON(node.num_outputs() != 1);
527
528 // Extract IO and info
529 ICLTensor *input = get_backing_tensor(node.input(0));
530 ICLTensor *output = get_backing_tensor(node.output(0));
531 const float beta = node.beta();
532 ARM_COMPUTE_ERROR_ON(input == nullptr);
533 ARM_COMPUTE_ERROR_ON(output == nullptr);
534
535 // Create and configure function
536 auto func = support::cpp14::make_unique<CLSoftmaxLayer>(get_memory_manager(ctx, Target::CL));
537 func->configure(input, output, beta);
538
539 // Log info
540 ARM_COMPUTE_LOG_GRAPH_INFO("Instantiated CLSoftmaxLayer"
541 << " Data Type: " << input->info()->data_type()
542 << " Input shape: " << input->info()->tensor_shape()
543 << " Output shape: " << output->info()->tensor_shape()
544 << std::endl);
545
546 return std::move(func);
547}
548} // namespace
549
550std::unique_ptr<IFunction> CLFunctionFactory::create(INode *node, GraphContext &ctx)
551{
552 if(node == nullptr)
553 {
554 return nullptr;
555 }
556
557 NodeType type = node->type();
558 switch(type)
559 {
560 case NodeType::ActivationLayer:
561 return create_activation_layer(*polymorphic_downcast<ActivationLayerNode *>(node));
562 case NodeType::BatchNormalizationLayer:
563 return create_batch_normalization_layer(*polymorphic_downcast<BatchNormalizationLayerNode *>(node));
564 case NodeType::ConvolutionLayer:
565 return create_convolution_layer(*polymorphic_downcast<ConvolutionLayerNode *>(node), ctx);
566 case NodeType::DepthConcatenateLayer:
567 return create_depth_concatenate_layer(*polymorphic_downcast<DepthConcatenateLayerNode *>(node));
568 case NodeType::DepthwiseConvolutionLayer:
569 return create_depthwise_convolution_layer(*polymorphic_downcast<DepthwiseConvolutionLayerNode *>(node));
570 case NodeType::EltwiseLayer:
571 return create_eltwise_layer(*polymorphic_downcast<EltwiseLayerNode *>(node));
572 case NodeType::FlattenLayer:
573 return create_flatten_layer(*polymorphic_downcast<FlattenLayerNode *>(node));
574 case NodeType::FullyConnectedLayer:
575 return create_fully_connected_layer(*polymorphic_downcast<FullyConnectedLayerNode *>(node), ctx);
576 case NodeType::NormalizationLayer:
577 return create_normalization_layer(*polymorphic_downcast<NormalizationLayerNode *>(node));
578 case NodeType::PoolingLayer:
579 return create_pooling_layer(*polymorphic_downcast<PoolingLayerNode *>(node));
580 case NodeType::ReshapeLayer:
581 return create_reshape_layer(*polymorphic_downcast<ReshapeLayerNode *>(node));
582 case NodeType::SoftmaxLayer:
583 return create_softmax_layer(*polymorphic_downcast<SoftmaxLayerNode *>(node), ctx);
584 default:
585 return nullptr;
586 }
587}
588} // namespace backends
Georgios Pinitasd9eb2752018-04-03 13:44:29 +0100589} // namespace graph
Georgios Pinitasd8734b52017-12-22 15:27:52 +0000590} // namespace arm_compute