| 396 | |
| 397 | template <typename T> |
| 398 | SimpleTensor<T> conv2d_dft(const SimpleTensor<T> &src, const SimpleTensor<T> &w, const PadStrideInfo &conv_info) |
| 399 | { |
| 400 | // Pad input to full padding |
| 401 | const PaddingList padding_in = {{0, w.shape()[0] - 1}, {0, w.shape()[1] - 1}}; |
| 402 | auto padded_src = pad_layer(src, padding_in); |
| 403 | |
| 404 | // Flip weights |
| 405 | std::vector<uint32_t> axis_v = {0, 1}; |
| 406 | SimpleTensor<int32_t> axis{TensorShape(2U), DataType::S32}; |
| 407 | std::copy(axis_v.begin(), axis_v.begin() + axis.shape().x(), axis.data()); |
| 408 | auto flipped_w = reverse(w, axis, /* use_inverted_axis */ false); |
| 409 | |
| 410 | // Pad weights to have the same size as input |
| 411 | const PaddingList paddings_w = {{0, src.shape()[0] - 1}, {0, src.shape()[1] - 1}}; |
| 412 | auto padded_w = pad_layer(flipped_w, paddings_w); |
| 413 | |
| 414 | // Transform input and weights to frequency domain |
| 415 | auto Fsrc = rdft_2d(padded_src); |
| 416 | auto Fw = rdft_2d(padded_w); |
| 417 | |
| 418 | // Perform dot product |
| 419 | auto Fdst = complex_mul_and_reduce(Fsrc, Fw); |
| 420 | |
| 421 | // Transform output back to frequency domain |
| 422 | auto conv_res = ridft_2d(Fdst); |
| 423 | |
| 424 | // Slice output |
| 425 | const int start_left = w.shape().x() - conv_info.pad_left() - 1; |
| 426 | const int start_top = w.shape().y() - conv_info.pad_top() - 1; |
| 427 | const int end_right = conv_res.shape().x() - (w.shape().x() - conv_info.pad_right() - 1); |
| 428 | const int end_botton = conv_res.shape().y() - (w.shape().y() - conv_info.pad_bottom() - 1); |
| 429 | return slice(conv_res, Coordinates(start_left, start_top), Coordinates(end_right, end_botton)); |
| 430 | } |
| 431 | |
| 432 | // FP32 |
| 433 | template SimpleTensor<float> rdft_1d(const SimpleTensor<float> &src); |
no test coverage detected