| 357 | } |
| 358 | |
| 359 | void CpuWinogradConv2d::run(ITensorPack &tensors) |
| 360 | { |
| 361 | ARM_COMPUTE_TRACE_EVENT(ARM_COMPUTE_PROF_CAT_CPU, ARM_COMPUTE_PROF_LVL_CPU, "CpuWinogradConv2d::run"); |
| 362 | prepare(tensors); |
| 363 | auto src = tensors.get_const_tensor(ACL_SRC_0); |
| 364 | auto biases = tensors.get_const_tensor(ACL_SRC_2); |
| 365 | auto output = tensors.get_tensor(ACL_DST); |
| 366 | Window win; |
| 367 | |
| 368 | const uint32_t nthreads = NEScheduler::get().num_threads(); |
| 369 | |
| 370 | // The Winograd transform implementation does fine-grain threading inside the transforms. Just pass thread_id and nthreads. |
| 371 | win.set(Window::DimX, Window::Dimension(0, nthreads, 1)); |
| 372 | |
| 373 | // Wrap the winograd-domain tensorInfos created in configuration in tensors and allocate the required memory. |
| 374 | CpuAuxTensorHandler input_nhwc(offset_int_vec(PermutedInput), _input_nhwc, tensors, true); |
| 375 | CpuAuxTensorHandler winograd_input_transformed(offset_int_vec(TransformedInput), _winograd_transformed_input, |
| 376 | tensors, true); |
| 377 | CpuAuxTensorHandler input_workspace(offset_int_vec(WorkspaceIO), _input_workspace, tensors, true); |
| 378 | const bool is_nchw = _data_layout == DataLayout::NCHW; |
| 379 | if (is_nchw) |
| 380 | { |
| 381 | //Bring channels to the front as Winograd code expects the tensor to be in the format NHWC |
| 382 | ITensorPack pack{{ACL_SRC, src}, {ACL_DST, input_nhwc.get()}}; |
| 383 | _permute_input->run(pack); |
| 384 | } |
| 385 | |
| 386 | CpuAuxTensorHandler winograd_output_transformed(offset_int_vec(TransformedOutput), _winograd_transformed_output, |
| 387 | tensors, true); |
| 388 | CpuAuxTensorHandler output_workspace(offset_int_vec(WorkspaceIO), _output_workspace, tensors, true); |
| 389 | CpuAuxTensorHandler output_nhwc(offset_int_vec(PermutedOutput), _output_nhwc, tensors, true); |
| 390 | |
| 391 | ITensorPack transform_input_pack{{ACL_SRC, is_nchw ? input_nhwc.get() : src}, |
| 392 | {ACL_DST, winograd_input_transformed.get()}, |
| 393 | {ACL_INT, input_workspace.get()}}; |
| 394 | NEScheduler::get().schedule_op(_transform_input_kernel.get(), Window::DimX, win, transform_input_pack); |
| 395 | |
| 396 | CpuAuxTensorHandler winograd_weights_transformed(offset_int_vec(TransformedWeights), _winograd_transformed_weights, |
| 397 | tensors, true); |
| 398 | |
| 399 | // Run 16 GEMMs in multiple threads, each kernel runs one or more GEMMs |
| 400 | ITensorPack gemm_pack = tensors; |
| 401 | gemm_pack.add_const_tensor(ACL_SRC, winograd_input_transformed.get()); |
| 402 | gemm_pack.add_const_tensor(ACL_SRC_1, winograd_weights_transformed.get()); |
| 403 | gemm_pack.add_const_tensor(ACL_BIAS, nullptr); |
| 404 | gemm_pack.add_tensor(ACL_DST, winograd_output_transformed.get()); |
| 405 | _gemm_function->run(gemm_pack); |
| 406 | |
| 407 | // Output transform |
| 408 | ITensorPack transform_output_pack{{ACL_SRC_0, winograd_output_transformed.get()}, |
| 409 | {ACL_DST, is_nchw ? output_nhwc.get() : output}, |
| 410 | {ACL_SRC_1, biases}, |
| 411 | {ACL_INT, output_workspace.get()}}; |
| 412 | NEScheduler::get().schedule_op(_transform_output_kernel.get(), Window::DimX, win, transform_output_pack); |
| 413 | if (is_nchw) |
| 414 | { |
| 415 | // Reorder the convoluted output to ACL's ordering NCHW |
| 416 | ITensorPack pack{{ACL_SRC, output_nhwc.get()}, {ACL_DST, output}}; |
no test coverage detected