Compute Library
 21.11
GraphBuilder.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2021 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  */
25 
30 
32 
33 namespace arm_compute
34 {
35 namespace graph
36 {
37 namespace
38 {
39 inline void check_nodeidx_pair(const NodeIdxPair &pair, const Graph &g)
40 {
41  ARM_COMPUTE_UNUSED(pair);
43  ARM_COMPUTE_ERROR_ON((pair.node_id >= g.nodes().size()) || (g.node((pair).node_id) == nullptr) || (pair.index >= g.node(pair.node_id)->num_outputs()));
44 }
45 
46 Status set_node_params(Graph &g, NodeID nid, NodeParams &params)
47 {
48  INode *node = g.node(nid);
50 
51  node->set_common_node_parameters(params);
52 
53  return Status{};
54 }
55 
56 Status set_accessor_on_node(Graph &g, NodeID nid, bool is_output, size_t idx, ITensorAccessorUPtr accessor)
57 {
58  INode *node = g.node(nid);
60 
61  Tensor *tensor = is_output ? node->output(idx) : node->input(idx);
63 
64  tensor->set_accessor(std::move(accessor));
65 
66  return Status{};
67 }
68 
69 NodeID add_const_node_with_name(Graph &g, NodeParams params, const std::string &name, const TensorDescriptor &desc, ITensorAccessorUPtr accessor)
70 {
71  params.name = params.name.empty() ? "" : params.name + name;
72  auto nid = GraphBuilder::add_const_node(g, params, desc, std::move(accessor));
73  set_node_params(g, nid, params);
74  return nid;
75 }
76 
77 template <typename NT, typename... Args>
78 NodeID create_simple_single_input_output_node(Graph &g, NodeParams &params, NodeIdxPair input, Args &&... args)
79 {
80  check_nodeidx_pair(input, g);
81 
82  NodeID nid = g.add_node<NT>(std::forward<Args>(args)...);
83  g.add_connection(input.node_id, input.index, nid, 0);
84  set_node_params(g, nid, params);
85 
86  return nid;
87 }
88 
89 template <typename NT, typename... Args>
90 NodeID create_simple_multiple_input_single_output_node(Graph &g, NodeParams &params, const std::vector<NodeIdxPair> &inputs, Args &&... args)
91 {
92  ARM_COMPUTE_ERROR_ON(inputs.size() == 0);
93 
94  NodeID nid = g.add_node<NT>(std::forward<Args>(args)...);
95 
96  unsigned int i = 0;
97  for(const auto &input : inputs)
98  {
99  check_nodeidx_pair(input, g);
100  g.add_connection(input.node_id, input.index, nid, i++);
101  }
102  set_node_params(g, nid, params);
103 
104  return nid;
105 }
106 } // namespace
107 
109 {
110  auto nid = g.add_node<ConstNode>(desc);
111  set_node_params(g, nid, params);
112  set_accessor_on_node(g, nid, true, 0, std::move(accessor));
113  return nid;
114 }
115 
117 {
118  auto nid = g.add_node<InputNode>(desc);
119  set_node_params(g, nid, params);
120  set_accessor_on_node(g, nid, true, 0, std::move(accessor));
121  return nid;
122 }
123 
125 {
126  check_nodeidx_pair(input, g);
127 
128  NodeID nid = g.add_node<OutputNode>();
129  g.add_connection(input.node_id, input.index, nid, 0);
130  set_node_params(g, nid, params);
131  set_accessor_on_node(g, nid, false, 0, std::move(accessor));
132 
133  return nid;
134 }
135 
137  const QuantizationInfo &out_quant_info)
138 {
139  return create_simple_single_input_output_node<ActivationLayerNode>(g, params, input, act_info, out_quant_info);
140 }
141 
143  DataType out_data_type, const QuantizationInfo &out_quant_info)
144 {
145  return create_simple_single_input_output_node<ArgMinMaxLayerNode>(g, params, input, op, axis, out_data_type, out_quant_info);
146 }
147 
149  ITensorAccessorUPtr mean_accessor, ITensorAccessorUPtr var_accessor,
150  ITensorAccessorUPtr beta_accessor, ITensorAccessorUPtr gamma_accessor)
151 {
152  check_nodeidx_pair(input, g);
153 
154  bool has_beta = (beta_accessor != nullptr);
155  bool has_gamma = (gamma_accessor != nullptr);
156 
157  // Get input tensor descriptor
158  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
159 
160  // Calculate Common Descriptor
161  TensorDescriptor common_desc = input_tensor_desc;
162  common_desc.shape = TensorShape(get_dimension_size(input_tensor_desc, DataLayoutDimension::CHANNEL));
163 
164  // Create mean and var nodes
165  auto mean_nid = add_const_node_with_name(g, params, "Mean", common_desc, std::move(mean_accessor));
166  auto var_nid = add_const_node_with_name(g, params, "Variance", common_desc, std::move(var_accessor));
167 
168  // Create beta node
169  NodeID beta_nid = EmptyNodeID;
170  if(has_beta)
171  {
172  beta_nid = add_const_node_with_name(g, params, "Beta", common_desc, std::move(beta_accessor));
173  }
174 
175  // Create gamma node
176  NodeID gamma_nid = EmptyNodeID;
177  if(has_gamma)
178  {
179  gamma_nid = add_const_node_with_name(g, params, "Gamma", common_desc, std::move(gamma_accessor));
180  }
181 
182  // Create batch normalization node and add connections
183  NodeID batch_norm_nid = g.add_node<BatchNormalizationLayerNode>(epsilon);
184  g.add_connection(input.node_id, input.index, batch_norm_nid, 0);
185  g.add_connection(mean_nid, 0, batch_norm_nid, 1);
186  g.add_connection(var_nid, 0, batch_norm_nid, 2);
187  if(has_beta)
188  {
189  g.add_connection(beta_nid, 0, batch_norm_nid, 3);
190  }
191  if(has_gamma)
192  {
193  g.add_connection(gamma_nid, 0, batch_norm_nid, 4);
194  }
195  set_node_params(g, batch_norm_nid, params);
196 
197  return batch_norm_nid;
198 }
199 
201 {
202  check_nodeidx_pair(input, g);
203  check_nodeidx_pair(deltas, g);
204 
206 
207  g.add_connection(input.node_id, input.index, nid, 0);
208  g.add_connection(deltas.node_id, deltas.index, nid, 1);
209 
210  set_node_params(g, nid, params);
211  return nid;
212 }
213 
215 {
216  return create_simple_single_input_output_node<ChannelShuffleLayerNode>(g, params, input, num_groups);
217 }
218 
220  Size2D kernel_spatial_extend, unsigned int depth, PadStrideInfo conv_info,
221  unsigned int num_groups, ConvolutionMethod method, FastMathHint fast_math_hint,
222  ITensorAccessorUPtr weights_accessor, ITensorAccessorUPtr bias_accessor,
223  const QuantizationInfo &weights_quant_info,
224  const QuantizationInfo &out_quant_info)
225 {
226  check_nodeidx_pair(input, g);
227  ARM_COMPUTE_ERROR_ON(depth == 0);
228  ARM_COMPUTE_ERROR_ON((kernel_spatial_extend.width == 0) || (kernel_spatial_extend.height == 0));
229 
230  bool has_bias = (bias_accessor != nullptr);
231 
232  // Get input tensor descriptor
233  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
234  const DataLayout input_data_layout = input_tensor_desc.layout;
235 
236  // Create weights node
237  TensorDescriptor w_desc = input_tensor_desc;
238  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::WIDTH), kernel_spatial_extend.width);
239  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::HEIGHT), kernel_spatial_extend.height);
240  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::CHANNEL),
241  get_dimension_size(input_tensor_desc, DataLayoutDimension::CHANNEL) / num_groups);
242  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::BATCHES), depth);
243  if(!weights_quant_info.empty())
244  {
245  w_desc.quant_info = weights_quant_info;
246  }
247 
248  NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor));
249 
250  // Create bias nodes
251  NodeID b_nid = EmptyNodeID;
252  if(has_bias)
253  {
254  TensorDescriptor b_desc = input_tensor_desc;
255  b_desc.shape = TensorShape(depth);
256  if(is_data_type_quantized_asymmetric(input_tensor_desc.data_type))
257  {
258  b_desc.data_type = DataType::S32;
259  }
260  b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor));
261  }
262 
263  // Create convolution node and connect
264  NodeID conv_nid = g.add_node<ConvolutionLayerNode>(conv_info, num_groups, method, fast_math_hint, out_quant_info);
265  g.add_connection(input.node_id, input.index, conv_nid, 0);
266  g.add_connection(w_nid, 0, conv_nid, 1);
267  if(has_bias)
268  {
269  g.add_connection(b_nid, 0, conv_nid, 2);
270  }
271  set_node_params(g, conv_nid, params);
272 
273  return conv_nid;
274 }
275 
277  Size2D kernel_spatial_extend, unsigned int depth, PadStrideInfo deconv_info,
278  ITensorAccessorUPtr weights_accessor,
279  ITensorAccessorUPtr bias_accessor)
280 {
281  check_nodeidx_pair(input, g);
282  ARM_COMPUTE_ERROR_ON(depth == 0);
283  ARM_COMPUTE_ERROR_ON((kernel_spatial_extend.width == 0) || (kernel_spatial_extend.height == 0));
284 
285  bool has_bias = (bias_accessor != nullptr);
286 
287  // Get input tensor descriptor
288  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
289  const DataLayout input_data_layout = input_tensor_desc.layout;
290 
291  // Create weights node
292  TensorDescriptor w_desc = input_tensor_desc;
293  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::WIDTH), kernel_spatial_extend.width);
294  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::HEIGHT), kernel_spatial_extend.height);
295  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::CHANNEL),
297  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::BATCHES), depth);
298 
299  NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor));
300 
301  // Create bias nodes
302  NodeID b_nid = EmptyNodeID;
303  if(has_bias)
304  {
305  TensorDescriptor b_desc = input_tensor_desc;
306  b_desc.shape = TensorShape(depth);
307  if(is_data_type_quantized_asymmetric(input_tensor_desc.data_type))
308  {
309  b_desc.data_type = DataType::S32;
310  }
311  b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor));
312  }
313 
314  // Create convolution node and connect
316  g.add_connection(input.node_id, input.index, deconv_nid, 0);
317  g.add_connection(w_nid, 0, deconv_nid, 1);
318  if(has_bias)
319  {
320  g.add_connection(b_nid, 0, deconv_nid, 2);
321  }
322  set_node_params(g, deconv_nid, params);
323 
324  return deconv_nid;
325 }
326 
327 NodeID GraphBuilder::add_concatenate_node(Graph &g, NodeParams params, const std::vector<NodeIdxPair> &inputs, const descriptors::ConcatLayerDescriptor &concat_descriptor)
328 {
329  return create_simple_multiple_input_single_output_node<ConcatenateLayerNode>(g, params, inputs, inputs.size(), concat_descriptor);
330 }
331 
333  PadStrideInfo conv_info, int depth_multiplier, DepthwiseConvolutionMethod method,
334  ITensorAccessorUPtr weights_accessor, ITensorAccessorUPtr bias_accessor, const QuantizationInfo &quant_info, const QuantizationInfo &out_quant_info)
335 {
336  check_nodeidx_pair(input, g);
337  ARM_COMPUTE_ERROR_ON((kernel_spatial_extend.width == 0) || (kernel_spatial_extend.height == 0));
338 
339  bool has_bias = (bias_accessor != nullptr);
340 
341  // Get input tensor descriptor
342  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
343  const DataLayout input_data_layout = input_tensor_desc.layout;
344 
345  // Create weights node
346  TensorDescriptor w_desc = input_tensor_desc;
347  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::WIDTH), kernel_spatial_extend.width);
348  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::HEIGHT), kernel_spatial_extend.height);
349  w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::CHANNEL),
350  get_dimension_size(input_tensor_desc, DataLayoutDimension::CHANNEL) * depth_multiplier);
351  if(!quant_info.empty())
352  {
353  w_desc.quant_info = quant_info;
354  }
355 
356  NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor));
357 
358  // Create bias nodes
359  NodeID b_nid = EmptyNodeID;
360  if(has_bias)
361  {
362  TensorDescriptor b_desc = input_tensor_desc;
363  b_desc.shape = TensorShape(get_dimension_size(input_tensor_desc, DataLayoutDimension::CHANNEL) * depth_multiplier);
364 
366  {
367  b_desc.data_type = DataType::S32;
368  }
369 
370  b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor));
371  }
372 
373  // Create convolution node and connect
374  NodeID conv_nid = g.add_node<DepthwiseConvolutionLayerNode>(conv_info, depth_multiplier, method, out_quant_info);
375  g.add_connection(input.node_id, input.index, conv_nid, 0);
376  g.add_connection(w_nid, 0, conv_nid, 1);
377  if(has_bias)
378  {
379  g.add_connection(b_nid, 0, conv_nid, 2);
380  }
381  set_node_params(g, conv_nid, params);
382 
383  return conv_nid;
384 }
385 
387 {
388  return create_simple_single_input_output_node<DepthToSpaceLayerNode>(g, params, input, block_shape);
389 }
390 
392 {
393  return create_simple_single_input_output_node<DequantizationLayerNode>(g, params, input);
394 }
395 
397 {
398  check_nodeidx_pair(input_loc, g);
399  check_nodeidx_pair(input_conf, g);
400  check_nodeidx_pair(input_priorbox, g);
401 
402  // Create detection_output node and connect
403  NodeID detect_nid = g.add_node<DetectionOutputLayerNode>(detect_info);
404  g.add_connection(input_loc.node_id, input_loc.index, detect_nid, 0);
405  g.add_connection(input_conf.node_id, input_conf.index, detect_nid, 1);
406  g.add_connection(input_priorbox.node_id, input_priorbox.index, detect_nid, 2);
407 
408  set_node_params(g, detect_nid, params);
409 
410  return detect_nid;
411 }
412 
413 NodeID GraphBuilder::add_detection_post_process_node(Graph &g, NodeParams params, NodeIdxPair input_box_encoding, NodeIdxPair input_class_prediction, const DetectionPostProcessLayerInfo &detect_info,
414  ITensorAccessorUPtr anchors_accessor, const QuantizationInfo &anchor_quant_info)
415 {
416  check_nodeidx_pair(input_box_encoding, g);
417  check_nodeidx_pair(input_class_prediction, g);
418 
419  // Get input tensor descriptor
420  const TensorDescriptor input_box_encoding_tensor_desc = get_tensor_descriptor(g, g.node(input_box_encoding.node_id)->outputs()[0]);
421 
422  // Calculate anchor descriptor
423  TensorDescriptor anchor_desc = input_box_encoding_tensor_desc;
424  if(!anchor_quant_info.empty())
425  {
426  anchor_desc.quant_info = anchor_quant_info;
427  }
428 
429  // Create anchors nodes
430  auto anchors_nid = add_const_node_with_name(g, params, "Anchors", anchor_desc, std::move(anchors_accessor));
431 
432  // Create detection_output node and connect
433  NodeID detect_nid = g.add_node<DetectionPostProcessLayerNode>(detect_info);
434  g.add_connection(input_box_encoding.node_id, input_box_encoding.index, detect_nid, 0);
435  g.add_connection(input_class_prediction.node_id, input_class_prediction.index, detect_nid, 1);
436  g.add_connection(anchors_nid, 0, detect_nid, 2);
437 
438  set_node_params(g, detect_nid, params);
439 
440  return detect_nid;
441 }
442 
444 {
445  return create_simple_single_input_output_node<DummyNode>(g, params, input, shape);
446 }
447 
449 {
450  check_nodeidx_pair(input0, g);
451  check_nodeidx_pair(input1, g);
452 
454 
455  g.add_connection(input0.node_id, input0.index, nid, 0);
456  g.add_connection(input1.node_id, input1.index, nid, 1);
457 
458  set_node_params(g, nid, params);
459 
460  return nid;
461 }
462 
464 {
465  return create_simple_single_input_output_node<FlattenLayerNode>(g, params, input);
466 }
467 
469  NodeID weights_nid, NodeID bias_nid,
470  const FullyConnectedLayerInfo fc_info, const QuantizationInfo &out_quant_info, FastMathHint fast_math_hint)
471 {
472  check_nodeidx_pair(input, g);
473  ARM_COMPUTE_ERROR_ON(num_outputs == 0);
474  ARM_COMPUTE_ERROR_ON(weights_nid == EmptyNodeID);
475 
476  const bool has_bias = (bias_nid != EmptyNodeID);
477 
478  // Get input tensor descriptor
479  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
480 
481  // Create fully connected node and connect
482  NodeID fc_nid = g.add_node<FullyConnectedLayerNode>(num_outputs, out_quant_info, fc_info, fast_math_hint);
483  g.add_connection(input.node_id, input.index, fc_nid, 0);
484  g.add_connection(weights_nid, 0, fc_nid, 1);
485  if(has_bias)
486  {
487  g.add_connection(bias_nid, 0, fc_nid, 2);
488  }
489 
490  set_node_params(g, fc_nid, params);
491 
492  return fc_nid;
493 }
494 
496  ITensorAccessorUPtr weights_accessor, ITensorAccessorUPtr bias_accessor,
497  const FullyConnectedLayerInfo fc_info,
498  const QuantizationInfo &weights_quant_info, const QuantizationInfo &out_quant_info, FastMathHint fast_math_hint)
499 {
500  check_nodeidx_pair(input, g);
501  ARM_COMPUTE_ERROR_ON(num_outputs == 0);
502 
503  bool has_bias = (bias_accessor != nullptr);
504 
505  // Get input tensor descriptor
506  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
507 
508  // Create weights node
509  TensorDescriptor w_desc = FullyConnectedLayerNode::compute_weights_descriptor(input_tensor_desc, num_outputs, fc_info, weights_quant_info);
510  NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor));
511 
512  // Create bias nodes
513  NodeID b_nid = EmptyNodeID;
514  if(has_bias)
515  {
516  TensorDescriptor b_desc = input_tensor_desc;
517  b_desc.shape = TensorShape(num_outputs);
518  if(is_data_type_quantized_asymmetric(input_tensor_desc.data_type))
519  {
520  b_desc.data_type = DataType::S32;
521  }
522  b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor));
523  }
524 
525  // Create fully connected node and connect
526  NodeID fc_nid = g.add_node<FullyConnectedLayerNode>(num_outputs, out_quant_info, fc_info, fast_math_hint);
527  g.add_connection(input.node_id, input.index, fc_nid, 0);
528  g.add_connection(w_nid, 0, fc_nid, 1);
529  if(has_bias)
530  {
531  g.add_connection(b_nid, 0, fc_nid, 2);
532  }
533 
534  set_node_params(g, fc_nid, params);
535 
536  return fc_nid;
537 }
538 
540 {
541  check_nodeidx_pair(scores, g);
542  check_nodeidx_pair(deltas, g);
543  check_nodeidx_pair(anchors, g);
544 
546 
547  g.add_connection(scores.node_id, scores.index, nid, 0);
548  g.add_connection(deltas.node_id, deltas.index, nid, 1);
549  g.add_connection(anchors.node_id, anchors.index, nid, 2);
550 
551  set_node_params(g, nid, params);
552  return nid;
553 }
554 
556 {
557  return create_simple_single_input_output_node<L2NormalizeLayerNode>(g, params, input, axis, epsilon);
558 }
559 
561 {
562  return create_simple_single_input_output_node<NormalizationLayerNode>(g, params, input, norm_info);
563 }
564 
566  ITensorAccessorUPtr mean_accessor, ITensorAccessorUPtr std_accessor)
567 {
568  check_nodeidx_pair(input, g);
569 
570  // Get input tensor descriptor
571  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
572 
573  // Calculate Common Descriptor
574  TensorDescriptor common_desc = input_tensor_desc;
575  common_desc.shape = TensorShape(get_dimension_size(input_tensor_desc, DataLayoutDimension::CHANNEL));
576 
577  // Create mean and std nodes
578  auto mean_nid = add_const_node_with_name(g, params, "Mean", common_desc, std::move(mean_accessor));
579  auto std_nid = add_const_node_with_name(g, params, "Std", common_desc, std::move(std_accessor));
580 
581  // Create normalize planar YUV node and add connections
582  NodeID norm_planar_yuv_nid = g.add_node<NormalizePlanarYUVLayerNode>();
583  g.add_connection(input.node_id, input.index, norm_planar_yuv_nid, 0);
584  g.add_connection(mean_nid, 0, norm_planar_yuv_nid, 1);
585  g.add_connection(std_nid, 0, norm_planar_yuv_nid, 2);
586  set_node_params(g, norm_planar_yuv_nid, params);
587 
588  return norm_planar_yuv_nid;
589 }
590 
592 {
593  return create_simple_single_input_output_node<PadLayerNode>(g, params, input, paddings, pad_value);
594 }
595 
597 {
598  return create_simple_single_input_output_node<PermuteLayerNode>(g, params, input, perm, layout);
599 }
600 
602 {
603  check_nodeidx_pair(input, g);
604  check_nodeidx_pair(alpha, g);
605 
606  NodeID prelu_nid = g.add_node<PReluLayerNode>();
607  g.add_connection(input.node_id, input.index, prelu_nid, 0);
608  g.add_connection(alpha.node_id, alpha.index, prelu_nid, 1);
609 
610  set_node_params(g, prelu_nid, params);
611 
612  return prelu_nid;
613 }
614 
616 {
617  return create_simple_single_input_output_node<PoolingLayerNode>(g, params, input, pool_info);
618 }
619 
620 NodeID GraphBuilder::add_print_node(Graph &g, NodeParams params, NodeIdxPair input, std::ostream &stream, const IOFormatInfo &format_info, const std::function<ITensor *(ITensor *)> transform)
621 {
622  return create_simple_single_input_output_node<PrintLayerNode>(g, params, input, stream, format_info, transform);
623 }
624 
626 {
627  check_nodeidx_pair(input0, g);
628  check_nodeidx_pair(input1, g);
629 
630  // Create priorbox node and connect
631  NodeID prior_nid = g.add_node<PriorBoxLayerNode>(prior_info);
632  g.add_connection(input0.node_id, input0.index, prior_nid, 0);
633  g.add_connection(input1.node_id, input1.index, prior_nid, 1);
634 
635  set_node_params(g, prior_nid, params);
636 
637  return prior_nid;
638 }
639 
641 {
642  return create_simple_single_input_output_node<QuantizationLayerNode>(g, params, input, out_quant_info);
643 }
644 
646 {
647  return create_simple_single_input_output_node<ReductionLayerNode>(g, params, input, op, axis, keep_dims);
648 }
649 
651 {
652  return create_simple_single_input_output_node<ReorgLayerNode>(g, params, input, stride);
653 }
654 
656 {
657  return create_simple_single_input_output_node<ReshapeLayerNode>(g, params, input, shape);
658 }
659 
661  float width_scale, float height_scale)
662 {
663  return create_simple_single_input_output_node<ResizeLayerNode>(g, params, input, policy, width_scale, height_scale);
664 }
665 
667 {
668  check_nodeidx_pair(input, g);
669  check_nodeidx_pair(rois, g);
670 
671  NodeID nid = g.add_node<ROIAlignLayerNode>(pool_info);
672 
673  g.add_connection(input.node_id, input.index, nid, 0);
674  g.add_connection(rois.node_id, rois.index, nid, 1);
675 
676  set_node_params(g, nid, params);
677  return nid;
678 }
679 
681 {
682  check_nodeidx_pair(input, g);
683 
684  // Get input tensor descriptor
685  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
686  const DataLayout input_data_layout = input_tensor_desc.layout;
687 
688  // Create mul node
689  TensorDescriptor mul_desc = input_tensor_desc;
690  const size_t C = input_tensor_desc.shape[get_dimension_idx(input_data_layout, DataLayoutDimension::CHANNEL)];
691  mul_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::WIDTH), 1);
692  mul_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::HEIGHT), 1);
693  mul_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::CHANNEL), C);
694  NodeID mul_const_nid = add_const_node_with_name(g, params, "Mul", mul_desc, std::move(mul_accessor));
695  NodeIdxPair mul_const_nidxp = { mul_const_nid, 0 };
696 
697  // Create add node
698  TensorDescriptor add_desc = mul_desc;
699  NodeID add_const_nid = add_const_node_with_name(g, params, "Add", add_desc, std::move(add_accessor));
700  NodeIdxPair add_const_nidxp = { add_const_nid, 0 };
701 
702  // Create node and connect
703  NodeID mul_node = GraphBuilder::add_elementwise_node(g, params, input, mul_const_nidxp, EltwiseOperation::Mul);
704  NodeIdxPair mulnode_nidxp = { mul_node, 0 };
705  NodeID add_node = GraphBuilder::add_elementwise_node(g, params, mulnode_nidxp, add_const_nidxp, EltwiseOperation::Add);
706 
707  return add_node;
708 }
709 
711 {
712  return create_simple_single_input_output_node<SoftmaxLayerNode>(g, params, input, beta);
713 }
714 
716 {
717  return create_simple_single_input_output_node<SliceLayerNode>(g, params, input, starts, ends);
718 }
719 
720 NodeID GraphBuilder::add_split_node(Graph &g, NodeParams params, NodeIdxPair input, unsigned int num_splits, unsigned int axis)
721 {
722  return create_simple_single_input_output_node<SplitLayerNode>(g, params, input, num_splits, axis);
723 }
724 
726 {
727  return create_simple_single_input_output_node<StridedSliceLayerNode>(g, params, input, starts, ends, strides, info);
728 }
729 
730 NodeID GraphBuilder::add_stack_node(Graph &g, NodeParams params, const std::vector<NodeIdxPair> &inputs, int axis)
731 {
732  return create_simple_multiple_input_single_output_node<StackLayerNode>(g, params, inputs, inputs.size(), axis);
733 }
734 
736 {
737  check_nodeidx_pair(input, g);
738 
739  // Get input tensor descriptor
740  const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]);
741  const bool is_nhwc = input_tensor_desc.layout == DataLayout::NHWC;
742 
743  // Box format: [Objectness:1][Box:4][Classes:N]
744 
745  // Activate objectness and front part of the box
746  const Coordinates box_start(0, 0, 0);
747  const Coordinates box_end = is_nhwc ? Coordinates(3, -1, -1) : Coordinates(-1, -1, 3);
748  NodeID box = g.add_node<SliceLayerNode>(box_start, box_end);
749  NodeID act_box = g.add_node<ActivationLayerNode>(act_info);
750  set_node_params(g, box, params);
751  set_node_params(g, act_box, params);
752  g.add_connection(input.node_id, input.index, box, 0);
753  g.add_connection(box, 0, act_box, 0);
754 
755  // Immutable part
756  const Coordinates imm_start = is_nhwc ? Coordinates(3, 0, 0) : Coordinates(0, 0, 3);
757  const Coordinates imm_end = is_nhwc ? Coordinates(5, -1, -1) : Coordinates(-1, -1, 5);
758  NodeID imm = g.add_node<SliceLayerNode>(imm_start, imm_end);
759  set_node_params(g, imm, params);
760  g.add_connection(input.node_id, input.index, imm, 0);
761 
762  // Activation classes and end part of box
763  const Coordinates cls_start = is_nhwc ? Coordinates(5, 0, 0) : Coordinates(0, 0, 5);
764  const Coordinates cls_end = Coordinates(-1, -1, -1);
765  NodeID cls = g.add_node<SliceLayerNode>(cls_start, cls_end);
766  NodeID cls_act = g.add_node<ActivationLayerNode>(act_info);
767  set_node_params(g, cls, params);
768  set_node_params(g, cls_act, params);
769  g.add_connection(input.node_id, input.index, cls, 0);
770  g.add_connection(cls, 0, cls_act, 0);
771 
773  set_node_params(g, concat, params);
774  g.add_connection(act_box, 0, concat, 0);
775  g.add_connection(imm, 0, concat, 1);
776  g.add_connection(cls_act, 0, concat, 2);
777 
778  return concat;
779 }
780 } // namespace graph
781 } // namespace arm_compute
static NodeID add_reduction_operation_node(Graph &g, NodeParams params, NodeIdxPair input, ReductionOperation op, int axis, bool keep_dims=true)
Adds a reduction sum layer node to the graph.
TensorDescriptor get_tensor_descriptor(const Graph &g, TensorID tid)
Returns the tensor descriptor of a given tensor.
Definition: Utils.h:50
Common node parameters.
Definition: Types.h:269
Class describing the value of a pixel for any image format.
Definition: PixelValue.h:34
NodeID node_id
Node ID.
Definition: Types.h:264
static NodeID add_split_node(Graph &g, NodeParams params, NodeIdxPair input, unsigned int num_splits, unsigned int axis=0)
Adds a split node to the graph.
InterpolationPolicy
Interpolation method.
Definition: Types.h:398
static NodeID add_quantization_node(Graph &g, NodeParams params, NodeIdxPair input, const QuantizationInfo &out_quant_info)
Adds a quantization layer node to the graph.
static NodeID add_batch_normalization_node(Graph &g, NodeParams params, NodeIdxPair input, float epsilon, ITensorAccessorUPtr mean_accessor=nullptr, ITensorAccessorUPtr var_accessor=nullptr, ITensorAccessorUPtr beta_accessor=nullptr, ITensorAccessorUPtr gamma_accessor=nullptr)
Adds a batch normalization layer node to the graph.
Generate Proposals Information class.
Definition: Types.h:1311
Shape of a tensor.
Definition: TensorShape.h:39
EltwiseOperation
Supported Element-wise operations.
Definition: Types.h:109
static NodeID add_input_node(Graph &g, NodeParams params, const TensorDescriptor &desc, ITensorAccessorUPtr accessor=nullptr)
Adds an input layer node to the graph.
size_t get_dimension_size(const TensorDescriptor &descriptor, const DataLayoutDimension data_layout_dimension)
Get size of a tensor&#39;s given dimension depending on its layout.
Definition: Utils.cpp:142
std::vector< PaddingInfo > PaddingList
List of padding information.
Definition: Types.h:440
ReductionOperation
Available reduction operations.
Definition: Types.h:463
static NodeID add_prelu_node(Graph &g, NodeParams params, NodeIdxPair input, NodeIdxPair alpha)
Adds a prelu layer node to the graph.
NodeID add_node(Ts &&... args)
Adds a node to the graph.
Definition: Graph.h:235
static NodeID add_resize_node(Graph &g, NodeParams params, NodeIdxPair input, InterpolationPolicy policy, float width_scale, float height_scale)
Adds a resize layer node to the graph.
static NodeID add_activation_node(Graph &g, NodeParams params, NodeIdxPair input, ActivationLayerInfo act_info, const QuantizationInfo &out_quant_info=QuantizationInfo())
Adds an activation layer node to the graph.
static NodeID add_normalization_node(Graph &g, NodeParams params, NodeIdxPair input, NormalizationLayerInfo norm_info)
Adds a normalization layer node to the graph.
static NodeID add_permute_node(Graph &g, NodeParams params, NodeIdxPair input, PermutationVector perm, DataLayout layout=DataLayout::UNKNOWN)
Adds a permute layer node to the graph.
Normalization Layer Information class.
Definition: Types.h:1610
static NodeID add_yolo_node(Graph &g, NodeParams params, NodeIdxPair input, ActivationLayerInfo act_info)
Adds a yolo layer to the graph.
#define ARM_COMPUTE_ERROR_ON(cond)
If the condition is true then an error message is printed and an exception thrown.
Definition: Error.h:466
Fully connected layer info.
Definition: Types.h:1572
std::unique_ptr< ITensorAccessor > ITensorAccessorUPtr
static NodeID add_fully_connected_layer(Graph &g, NodeParams params, NodeIdxPair input, unsigned int num_outputs, NodeID weights_nid, NodeID bias_nid=EmptyNodeID, const FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo(), const QuantizationInfo &out_quant_info=QuantizationInfo(), FastMathHint fast_math_hint=FastMathHint::Disabled)
Adds a fully connected layer node to the graph.
static NodeID add_bounding_box_transform_node(Graph &g, NodeParams params, NodeIdxPair input, NodeIdxPair deltas, BoundingBoxTransformInfo info)
Adds a bounding box transform layer node to the graph.
static NodeID add_reshape_node(Graph &g, NodeParams params, NodeIdxPair input, TensorShape shape)
Adds a reshape layer node to the graph.
#define ARM_COMPUTE_RETURN_ERROR_ON(cond)
If the condition is true, an error is returned.
Definition: Error.h:296
Activation Layer Information class.
Definition: Types.h:1509
static NodeID add_priorbox_node(Graph &g, NodeParams params, NodeIdxPair input0, NodeIdxPair input1, const PriorBoxLayerInfo &prior_info)
Adds a priorbox layer node to the graph.
Interface for CPU tensor.
Definition: ITensor.h:36
static NodeID add_concatenate_node(Graph &g, NodeParams params, const std::vector< NodeIdxPair > &inputs, const descriptors::ConcatLayerDescriptor &concat_descriptor)
Adds a depth concatenate node to the graph.
static NodeID add_generate_proposals_node(Graph &g, NodeParams params, NodeIdxPair scores, NodeIdxPair deltas, NodeIdxPair anchors, GenerateProposalsInfo info)
Adds a generate proposals layer node to the graph.
static NodeID add_slice_node(Graph &g, NodeParams params, NodeIdxPair input, Coordinates &starts, Coordinates &ends)
Adds a slice node to the graph.
static NodeID add_deconvolution_node(Graph &g, NodeParams params, NodeIdxPair input, Size2D kernel_spatial_extend, unsigned int depth, PadStrideInfo deconv_info, ITensorAccessorUPtr weights_accessor=nullptr, ITensorAccessorUPtr bias_accessor=nullptr)
Adds a deconvolution layer node to the graph.
static NodeID add_convolution_node(Graph &g, NodeParams params, NodeIdxPair input, Size2D kernel_spatial_extend, unsigned int depth, PadStrideInfo conv_info, unsigned int num_groups=1, ConvolutionMethod method=ConvolutionMethod::Default, FastMathHint fast_math_hint=FastMathHint::Disabled, ITensorAccessorUPtr weights_accessor=nullptr, ITensorAccessorUPtr bias_accessor=nullptr, const QuantizationInfo &weights_quant_info=QuantizationInfo(), const QuantizationInfo &out_quant_info=QuantizationInfo())
Adds a convolution layer node to the graph.
static NodeID add_depth_to_space_node(Graph &g, NodeParams params, NodeIdxPair input, int32_t block_shape)
Adds an depth to space layer node to the graph.
Copyright (c) 2017-2021 Arm Limited.
size_t height
Height of the image region or rectangle.
Definition: Size2D.h:91
static NodeID add_detection_output_node(Graph &g, NodeParams params, NodeIdxPair input_loc, NodeIdxPair input_conf, NodeIdxPair input_priorbox, const DetectionOutputLayerInfo &detect_info)
Adds a detection output layer node to the graph.
static NodeID add_pad_node(Graph &g, NodeParams params, NodeIdxPair input, const PaddingList &paddings, PixelValue pad_value=PixelValue())
Adds a pad layer node to the graph.
1 channel, 1 S32 per channel
Quantization information.
QuantizationInfo quant_info
Quantization info.
static NodeID add_print_node(Graph &g, NodeParams params, NodeIdxPair input, std::ostream &stream, const IOFormatInfo &format_info=IOFormatInfo(), const std::function< ITensor *(ITensor *)> transform=nullptr)
Adds a print layer node to the graph.
static NodeID add_stack_node(Graph &g, NodeParams params, const std::vector< NodeIdxPair > &inputs, int axis)
Adds a stack layer node to the graph.
#define ARM_COMPUTE_UNUSED(...)
To avoid unused variables warnings.
Definition: Error.h:152
static NodeID add_elementwise_node(Graph &g, NodeParams params, NodeIdxPair input0, NodeIdxPair input1, EltwiseOperation operation)
Adds an element-wise layer node to the graph.
IO formatting information class.
Definition: Types.h:2216
static NodeID add_reorg_node(Graph &g, NodeParams params, NodeIdxPair input, int stride)
Adds a reorg layer node to the graph.
const unsigned int num_groups
Definition: Im2Col.cpp:153
DepthwiseConvolutionMethod
Supported Depthwise Convolution layer methods.
Definition: Types.h:135
Coordinates of an item.
Definition: Coordinates.h:37
Pooling Layer Information struct.
Definition: Types.h:1173
Output Layer node.
Definition: OutputNode.h:34
static NodeID add_roi_align_node(Graph &g, NodeParams params, NodeIdxPair input, NodeIdxPair rois, ROIPoolingLayerInfo pool_info)
Adds a ROI align layer node to the graph.
PriorBox layer info.
Definition: Types.h:798
static NodeID add_l2_normalize_node(Graph &g, NodeParams params, NodeIdxPair input, int axis, float epsilon)
Adds a L2 Normalize layer node to the graph.
Padding and stride information class.
Definition: Types.h:656
const std::vector< TensorID > & outputs() const
Returns outputs of the node.
Definition: INode.cpp:123
const char * name
EdgeID add_connection(NodeID source, size_t source_idx, NodeID sink, size_t sink_idx)
Adds a connection between two nodes.
Definition: Graph.cpp:69
Bounding Box Transform information class.
Definition: Types.h:1442
static NodeID add_dummy_node(Graph &g, NodeParams params, NodeIdxPair input, TensorShape shape)
Adds a Dummy node to the graph.
static NodeID add_dequantization_node(Graph &g, NodeParams params, NodeIdxPair input)
Adds a dequantization node to the graph.
static NodeID add_normalize_planar_yuv_node(Graph &g, NodeParams params, NodeIdxPair input, ITensorAccessorUPtr mean_accessor=nullptr, ITensorAccessorUPtr std_accessor=nullptr)
Adds a normalize planar YUV layer node to the graph.
NodeID-index struct.
Definition: Types.h:262
FastMathHint
Enable or disable fast math for Convolution layer.
Definition: Types.h:143
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1003
Input Layer node.
Definition: InputNode.h:34
static NodeID add_channel_shuffle_node(Graph &g, NodeParams params, NodeIdxPair input, unsigned int num_groups)
Adds an channel shuffle layer node to the graph.
Strides of an item in bytes.
Definition: Strides.h:37
Graph class.
Definition: Graph.h:53
Detection Output layer info.
Definition: Types.h:935
DetectionPostProcess Layer node.
static NodeID add_detection_post_process_node(Graph &g, NodeParams params, NodeIdxPair input_box_encoding, NodeIdxPair input_class_prediction, const DetectionPostProcessLayerInfo &detect_info, ITensorAccessorUPtr anchors_accessor=nullptr, const QuantizationInfo &anchor_quant_info=QuantizationInfo())
Adds a detection post process layer node to the graph.
unsigned int NodeID
Definition: Types.h:69
ScaleKernelInfo info(interpolation_policy, default_border_mode, PixelValue(), sampling_policy, false)
static NodeID add_softmax_node(Graph &g, NodeParams params, NodeIdxPair input, float beta=1.f)
Adds a softmax node to the graph.
bool empty() const
Indicates whether this QuantizationInfo has valid settings or not.
size_t width
Width of the image region or rectangle.
Definition: Size2D.h:90
ROI Pooling Layer Information class.
Definition: Types.h:1268
constexpr NodeID EmptyNodeID
Constant EdgeID specifying an equivalent of null edge.
Definition: Types.h:76
const INode * node(NodeID id) const
Get node object given its id.
Definition: Graph.cpp:204
Class for specifying the size of an image or rectangle.
Definition: Size2D.h:34
static NodeID add_scale_layer(Graph &g, const NodeParams &params, NodeIdxPair input, ITensorAccessorUPtr mul_accessor=nullptr, ITensorAccessorUPtr add_accessor=nullptr)
Adds a scale layer node to the graph This layer computes a product of the input with a scale (read fr...
Num samples, height, width, channels.
ConvolutionMethod
Supported Convolution layer methods.
Definition: Types.h:126
Detection Output layer info.
Definition: Types.h:1054
JoinDataset< T, U > concat(T &&dataset1, U &&dataset2)
Helper function to create a JoinDataset.
Definition: JoinDataset.h:160
static TensorDescriptor compute_weights_descriptor(const TensorDescriptor &input_descriptor, unsigned int num_outputs, FullyConnectedLayerInfo fc_info=FullyConnectedLayerInfo(), const QuantizationInfo &weights_quant_info=QuantizationInfo())
Computes weights descriptor.
static NodeID add_const_node(Graph &g, NodeParams params, const TensorDescriptor &desc, ITensorAccessorUPtr accessor=nullptr)
Adds a Const node to the graph.
static NodeID add_flatten_node(Graph &g, NodeParams params, NodeIdxPair input)
Adds a flatten layer node to the graph.
static NodeID add_pooling_node(Graph &g, NodeParams params, NodeIdxPair input, PoolingLayerInfo pool_info)
Adds a pooling layer node to the graph.
DataType
Available data types.
Definition: Types.h:79
static NodeID add_strided_slice_node(Graph &g, NodeParams params, NodeIdxPair input, Coordinates &starts, Coordinates &ends, BiStrides &strides, StridedSliceLayerInfo info)
Adds a strided slice node to the graph.
DataLayout
[DataLayout enum definition]
Definition: Types.h:113
TensorShape & set(size_t dimension, size_t value, bool apply_dim_correction=true, bool increase_dim_unit=true)
Accessor to set the value of one of the dimensions.
Definition: TensorShape.h:79
size_t get_dimension_idx(DataLayout data_layout, const DataLayoutDimension data_layout_dimension)
Get index of a tensor&#39;s given dimension depending on its layout.
Definition: Utils.cpp:148
static NodeID add_arg_min_max_node(Graph &g, NodeParams params, NodeIdxPair input, ReductionOperation op, unsigned int axis, DataType out_data_type=DataType::UNKNOWN, const QuantizationInfo &out_quant_info=QuantizationInfo())
Adds an activation layer node to the graph.
static NodeID add_output_node(Graph &g, NodeParams params, NodeIdxPair input, ITensorAccessorUPtr accessor=nullptr)
Adds an output layer node to the graph.
static NodeID add_depthwise_convolution_node(Graph &g, NodeParams params, NodeIdxPair input, Size2D kernel_spatial_extend, PadStrideInfo conv_info, int depth_multiplier=1, DepthwiseConvolutionMethod method=DepthwiseConvolutionMethod::Default, ITensorAccessorUPtr weights_accessor=nullptr, ITensorAccessorUPtr bias_accessor=nullptr, const QuantizationInfo &quant_info=QuantizationInfo(), const QuantizationInfo &out_quant_info=QuantizationInfo())
Adds a depth-wise convolution layer node to the graph.