| 38 | { |
| 39 | template <typename T> |
| 40 | void im2col_nchw(const SimpleTensor<T> &src, |
| 41 | SimpleTensor<T> &dst, |
| 42 | const Size2D &kernel_dims, |
| 43 | const PadStrideInfo &conv_info, |
| 44 | bool has_bias, |
| 45 | unsigned int num_groups, |
| 46 | unsigned int channel_pad_right) |
| 47 | { |
| 48 | ARM_COMPUTE_UNUSED(channel_pad_right); |
| 49 | |
| 50 | ARM_COMPUTE_ERROR_ON(channel_pad_right > 0); |
| 51 | ARM_COMPUTE_ERROR_ON(src.data_layout() != DataLayout::NCHW); |
| 52 | |
| 53 | const int stride_x = conv_info.stride().first; |
| 54 | const int stride_y = conv_info.stride().second; |
| 55 | const int kernel_width = kernel_dims.width; |
| 56 | const int kernel_height = kernel_dims.height; |
| 57 | const int pad_x = conv_info.pad().first; |
| 58 | const int pad_y = conv_info.pad().second; |
| 59 | const int src_width = src.shape().x(); |
| 60 | const int src_height = src.shape().y(); |
| 61 | const int src_channels = src.shape().z(); |
| 62 | const int batches = src.shape().total_size_upper(3); |
| 63 | const int dst_height = dst.shape().y(); |
| 64 | const int pad_val = |
| 65 | is_data_type_quantized_asymmetric(src.data_type()) ? src.quantization_info().uniform().offset : 0; |
| 66 | int dst_idx = 0; |
| 67 | |
| 68 | // Compute width and height of the convolved tensors |
| 69 | std::pair<unsigned int, unsigned int> convolved_dims = |
| 70 | scaled_dimensions(src_width, src_height, kernel_dims.width, kernel_dims.height, conv_info); |
| 71 | |
| 72 | for (int b = 0; b < batches; ++b) |
| 73 | { |
| 74 | for (int g = 0; g < static_cast<int>(num_groups); ++g) |
| 75 | { |
| 76 | const int first_group_ch = g * (src_channels / num_groups); |
| 77 | const int last_group_ch = (g + 1) * (src_channels / num_groups); |
| 78 | |
| 79 | for (int yo = 0; yo < dst_height; ++yo) |
| 80 | { |
| 81 | // Compute input spatial coordinates |
| 82 | const int xi = (yo % convolved_dims.first) * stride_x; |
| 83 | const int yi = (yo / convolved_dims.first) * stride_y; |
| 84 | |
| 85 | for (int ci = first_group_ch; ci < last_group_ch; ++ci) |
| 86 | { |
| 87 | for (int yk = 0; yk < kernel_height; ++yk) |
| 88 | { |
| 89 | for (int xk = 0; xk < kernel_width; ++xk) |
| 90 | { |
| 91 | dst[dst_idx++] = tensor_elem_at(src, Coordinates(xi + xk - pad_x, yi + yk - pad_y, ci, b), |
| 92 | BorderMode::CONSTANT, static_cast<T>(pad_val)); |
| 93 | } |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | if (has_bias) |
no test coverage detected