| 240 | } |
| 241 | |
| 242 | NodeID GraphBuilder::add_convolution_node(Graph &g, |
| 243 | NodeParams params, |
| 244 | NodeIdxPair input, |
| 245 | Size2D kernel_spatial_extend, |
| 246 | unsigned int depth, |
| 247 | PadStrideInfo conv_info, |
| 248 | unsigned int num_groups, |
| 249 | ConvolutionMethod method, |
| 250 | FastMathHint fast_math_hint, |
| 251 | ITensorAccessorUPtr weights_accessor, |
| 252 | ITensorAccessorUPtr bias_accessor, |
| 253 | const QuantizationInfo &weights_quant_info, |
| 254 | const QuantizationInfo &out_quant_info) |
| 255 | { |
| 256 | check_nodeidx_pair(input, g); |
| 257 | ARM_COMPUTE_ERROR_ON(depth == 0); |
| 258 | ARM_COMPUTE_ERROR_ON((kernel_spatial_extend.width == 0) || (kernel_spatial_extend.height == 0)); |
| 259 | |
| 260 | bool has_bias = (bias_accessor != nullptr); |
| 261 | |
| 262 | // Get input tensor descriptor |
| 263 | const TensorDescriptor input_tensor_desc = get_tensor_descriptor(g, g.node(input.node_id)->outputs()[0]); |
| 264 | const DataLayout input_data_layout = input_tensor_desc.layout; |
| 265 | |
| 266 | // Create weights node |
| 267 | TensorDescriptor w_desc = input_tensor_desc; |
| 268 | w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::WIDTH), kernel_spatial_extend.width); |
| 269 | w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::HEIGHT), kernel_spatial_extend.height); |
| 270 | w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::CHANNEL), |
| 271 | get_dimension_size(input_tensor_desc, DataLayoutDimension::CHANNEL) / num_groups); |
| 272 | w_desc.shape.set(get_dimension_idx(input_data_layout, DataLayoutDimension::BATCHES), depth); |
| 273 | if (!weights_quant_info.empty()) |
| 274 | { |
| 275 | w_desc.quant_info = weights_quant_info; |
| 276 | } |
| 277 | |
| 278 | NodeID w_nid = add_const_node_with_name(g, params, "Weights", w_desc, std::move(weights_accessor)); |
| 279 | |
| 280 | // Create bias nodes |
| 281 | NodeID b_nid = EmptyNodeID; |
| 282 | if (has_bias) |
| 283 | { |
| 284 | TensorDescriptor b_desc = input_tensor_desc; |
| 285 | b_desc.shape = TensorShape(depth); |
| 286 | if (is_data_type_quantized_asymmetric(input_tensor_desc.data_type)) |
| 287 | { |
| 288 | b_desc.data_type = DataType::S32; |
| 289 | } |
| 290 | b_nid = add_const_node_with_name(g, params, "Bias", b_desc, std::move(bias_accessor)); |
| 291 | } |
| 292 | |
| 293 | // Create convolution node and connect |
| 294 | NodeID conv_nid = g.add_node<ConvolutionLayerNode>(conv_info, num_groups, method, fast_math_hint, out_quant_info); |
| 295 | g.add_connection(input.node_id, input.index, conv_nid, 0); |
| 296 | g.add_connection(w_nid, 0, conv_nid, 1); |
| 297 | if (has_bias) |
| 298 | { |
| 299 | g.add_connection(b_nid, 0, conv_nid, 2); |
nothing calls this directly
no test coverage detected