From 8f43d745b170aefca269a087fc045d8af3813c33 Mon Sep 17 00:00:00 2001 From: Pablo Tello Date: Wed, 27 Mar 2019 09:28:32 +0000 Subject: COMPMID-2063: New Winograd implementation Refactoring of winograd code reducing the size of the binaries about 8X. Change-Id: If8845bda324573e1a5cf436f354ac8603e88a92e Signed-off-by: Pablo Tello Reviewed-on: https://review.mlplatform.org/c/959 Comments-Addressed: Arm Jenkins Tested-by: Anthony Barbier Reviewed-by: Georgios Pinitas --- .../kernels/NEWinogradConvolutionLayerKernel.h | 183 ++++++++++++++------- 1 file changed, 123 insertions(+), 60 deletions(-) (limited to 'arm_compute/core/NEON/kernels/NEWinogradConvolutionLayerKernel.h') diff --git a/arm_compute/core/NEON/kernels/NEWinogradConvolutionLayerKernel.h b/arm_compute/core/NEON/kernels/NEWinogradConvolutionLayerKernel.h index 96580053dd..f6b189cb1c 100644 --- a/arm_compute/core/NEON/kernels/NEWinogradConvolutionLayerKernel.h +++ b/arm_compute/core/NEON/kernels/NEWinogradConvolutionLayerKernel.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 ARM Limited. + * Copyright (c) 2017-2019 ARM Limited. * * SPDX-License-Identifier: MIT * @@ -27,8 +27,7 @@ #include "arm_compute/core/NEON/INEKernel.h" #include "arm_compute/core/NEON/kernels/convolution/common/convolution.hpp" #include "arm_compute/core/NEON/kernels/convolution/common/tensor.hpp" -#include "arm_compute/core/NEON/kernels/convolution/winograd/batched_blocked_gemm.hpp" -#include "arm_compute/core/NEON/kernels/convolution/winograd/winograd_gemm.hpp" +#include "arm_compute/core/NEON/kernels/convolution/winograd/winograd_layer.hpp" namespace arm_compute { @@ -39,6 +38,17 @@ template class INEWinogradLayerTransformInputKernel : public INEKernel { public: + /** Get the working space required to perform the transformation. + * + * Note, the working space is only required when performing the + * transformation - hence it can be reused whenever the transformation is + * not running. + * + * @param num_threads The greatest number of threads that will be used to execute the transform. + * @return Size of working space required in bytes. + */ + virtual unsigned int get_working_space_size(unsigned int num_threads) const = 0; + /** Determine how much memory (in units of TIn) to allocate for the * transformed input. * @@ -72,9 +82,10 @@ public: * @param[in] padding Padding type. * @param[out] output Base of output matrices. * @param[in] matrix_stride Stride between output matrices. + * @param[in] workspace Tensor to be used as the working space during the computation. */ virtual void configure(const ITensor *input_nhwc, const int num_batches, const int num_rows, const int num_cols, const int num_channels, - const PaddingType padding, ITensor *output, const int matrix_stride) = 0; + const PaddingType padding, ITensor *output, const int matrix_stride, ITensor *workspace) = 0; /** Destructor */ virtual ~INEWinogradLayerTransformInputKernel() @@ -116,6 +127,18 @@ public: int num_cols, bool same_padding) const override; + /** Get the working space required to perform the transformation. + * + * Note, the working space is only required when performing the + * transformation - hence it can be reused whenever the transformation is + * not running. + * + * @param[in] num_threads The greatest number of threads that will be used to execute the transform. + * + * @return Size of working space required in bytes. + */ + unsigned int get_working_space_size(unsigned int num_threads) const override; + /** Gets the stride between matrices in the input worspace * * @param[in] kernel_shape The shape of the weights tensor. @@ -144,6 +167,7 @@ public: * @param[in] padding Padding type. * @param[out] output Base of output matrices. * @param[in] matrix_stride Stride between output matrices. + * @param[in] workspace Tensor to be used as the working space during the computation. */ void configure( const ITensor *input_nhwc, @@ -153,13 +177,14 @@ public: const int num_channels, const PaddingType padding, ITensor *output, - const int matrix_stride) override; + const int matrix_stride, + ITensor *workspace) override; // Inherited methods overridden: void run(const Window &window, const ThreadInfo &info) override; /** Winograd base kernel */ - using WinogradBase = winograd::WinogradGEMM; + using WinogradBase = winograd::WinogradGEMM; /** Winograd convolution kernel */ using WinogradConv = typename WinogradBase::template Convolution; @@ -174,15 +199,22 @@ public: static Status validate(const ITensorInfo *input, const ITensorInfo *output, const WinogradInfo &winograd_info); private: - using InputTransform = typename WinogradBase::template InputTransform; - const ITensor *_input_nhwc; - int _num_batches; /**< Number of batches in input tensor. */ - int _num_rows; /**< Number of rows in input tensor. */ - int _num_cols; /**< Number of columns in input tensor. */ - int _num_channels; /**< Number of channels in input tensor. */ - PaddingType _padding; /**< Padding type. */ - ITensor *_output; /**< Base of output matrices. */ - int _matrix_stride; /**< Stride between output matrices. */ + using InputTransform = typename WinogradBase::template InputTransform; + + std::unique_ptr _transform{ nullptr }; + const ITensor *_input_nhwc; + int _num_batches; /**< Number of batches in input tensor. */ + int _num_rows; /**< Number of rows in input tensor. */ + int _num_cols; /**< Number of columns in input tensor. */ + int _num_channels; /**< Number of channels in input tensor. */ + PaddingType _padding; /**< Padding type. */ + ITensor *_output; /**< Base of output matrices. */ + int _matrix_stride; /**< Stride between output matrices. */ + int _padding_top; /**< Padding to apply to the top of the image. */ + int _padding_left; /**< Padding to apply to the left of the image. */ + int _padding_right; /**< Padding to apply to the right of the image. */ + int _padding_bottom; /**< Padding to apply to the bottom of the image. */ + ITensor *_workspace; }; /** Interface for the NEON kernel to perform Winograd output transform. */ @@ -190,6 +222,18 @@ template class INEWinogradLayerTransformOutputKernel : public INEKernel { public: + /** Get the working space required to perform the transformation. + * + * Note, the working space is only required when performing the + * transformation - hence it can be reused whenever the transformation is + * not running. + * + * @param[in] num_threads The greatest number of threads that will be used to execute the transform. + * + * @return Size of working space required in bytes. + */ + virtual unsigned int get_working_space_size(unsigned int num_threads) const = 0; + /** Determine how much memory (in units of TOut) to allocate for the * (Winograd domain) output. * @@ -225,24 +269,26 @@ public: /** Configure the output transform kernel. * - * @param[in] biases Pointer to the biases tensor. - * @param[in] output_workingspace Pointer to working space for the output tensor in the Winograd domain. - * @param[in] matrix_stride Output matrix stride, can be computed with winograd::WinogradGEMM<2, 2, 3, 3>::Convolution::get_output_matrix_stride() - * @param[out] output_nhwc Pointer to a tensor in NHWC data layout ordered output tensor, in the spatial domain. - * @param[in] num_batches Number of batches in the input tensor. - * @param[in] num_rows Number of rows in output tensor. - * @param[in] num_cols Number of columns in output tensor. - * @param[in] num_channels Number of feature maps in the output tensor. + * @param[in] biases Pointer to the biases tensor. + * @param[in] transformed_output Pointer to working space for the output tensor in the Winograd domain. + * @param[in] matrix_stride Output matrix stride, can be computed with winograd::WinogradGEMM<2, 2, 3, 3>::Convolution::get_output_matrix_stride() + * @param[out] output_nhwc Pointer to a tensor in NHWC data layout ordered output tensor, in the spatial domain. + * @param[in] num_batches Number of batches in the input tensor. + * @param[in] num_rows Number of rows in output tensor. + * @param[in] num_cols Number of columns in output tensor. + * @param[in] num_channels Number of feature maps in the output tensor. + * @param[in] workspace Tensor to be used as the working space during the computation. */ virtual void configure( const ITensor *biases, - const ITensor *output_workingspace, + const ITensor *transformed_output, const int matrix_stride, ITensor *output_nhwc, const int num_batches, const int num_rows, const int num_cols, - const int num_channels) = 0; + const int num_channels, + ITensor *workspace) = 0; virtual ~INEWinogradLayerTransformOutputKernel() { @@ -305,54 +351,70 @@ public: */ Tensor4DShape get_output_shape(const KernelShape &kernel_shape, const Tensor4DShape &in_shape, const PaddingType padding) const override; + /** Get the working space required to perform the transformation. + * + * Note, the working space is only required when performing the + * transformation - hence it can be reused whenever the transformation is + * not running. + * + * @param[in] num_threads The greatest number of threads that will be used to execute the transform. + * + * @return Size of working space required in bytes. + */ + unsigned int get_working_space_size(unsigned int num_threads) const override; + /** Configure the output transform kernel. * - * @param[in] biases Pointer to the biases tensor. - * @param[in] output_workingspace Pointer to working space for the output tensor in the Winograd domain. - * @param[in] matrix_stride Output matrix stride, can be computed with winograd::WinogradGEMM<2, 2, 3, 3>::Convolution::get_output_matrix_stride() - * @param[out] output_nhwc Pointer to a tensor with NHWC data layout, in the spatial domain. - * @param[in] num_batches Number of batches in the input tensor. - * @param[in] num_rows Number of rows in output tensor. - * @param[in] num_cols Number of columns in output tensor. - * @param[in] num_channels Number of feature maps in the output tensor. + * @param[in] biases Pointer to the biases tensor. + * @param[in] transformed_output Pointer to working space for the output tensor in the Winograd domain. + * @param[in] matrix_stride Output matrix stride, can be computed with winograd::WinogradGEMM<2, 2, 3, 3>::Convolution::get_output_matrix_stride() + * @param[out] output_nhwc Pointer to a tensor with NHWC data layout, in the spatial domain. + * @param[in] num_batches Number of batches in the input tensor. + * @param[in] num_rows Number of rows in output tensor. + * @param[in] num_cols Number of columns in output tensor. + * @param[in] num_channels Number of feature maps in the output tensor. + * @param[in] workspace Tensor to be used as the working space during the computation. */ void configure( const ITensor *biases, - const ITensor *output_workingspace, + const ITensor *transformed_output, const int matrix_stride, ITensor *output_nhwc, const int num_batches, const int num_rows, const int num_cols, - const int num_channels) override; + const int num_channels, + ITensor *workspace) override; void run(const Window &window, const ThreadInfo &info) override; /** Static function to check if given info will lead to a valid configuration of @ref NEWinogradLayerTransformOutputKernel * - * @param[in] input Source tensor with shape [C, N, 16, batches] or [C, N, 36, batches]. Data types supported: F32. - * @param[in] bias Biases tensor. Shared biases supported. Biases are 1D tensor with dimensions [OFM]. It can be a nullptr. Data type supported: as @p input - * @param[out] output Destination tensor with shape [output_convolved_dims.width, output_convolved_dims.height, C, batches]. Data type supported: same as @p input - * @param[in] winograd_info Contains Winograd's information described in @ref WinogradInfo + * @param[in] input Source tensor info with shape [C, N, 16, batches] or [C, N, 36, batches]. Data types supported: F32. + * @param[in] bias Biases tensor info. Shared biases supported. Biases are 1D tensor with dimensions [OFM]. It can be a nullptr. Data type supported: as @p input + * @param[in] output Destination tensor info with shape [output_convolved_dims.width, output_convolved_dims.height, C, batches]. Data type supported: same as @p input + * @param[in] winograd_info Contains Winograd's information described in @ref WinogradInfo * * @return a status */ static Status validate(const ITensorInfo *input, const ITensorInfo *bias, const ITensorInfo *output, const WinogradInfo &winograd_info); private: - using WinogradBase = winograd::WinogradGEMM; + using WinogradBase = winograd::WinogradGEMM; using WinogradConv = typename WinogradBase::template Convolution; - using OutputTransform = typename WinogradBase::template OutputTransform; - - const ITensor *_biases; - const ITensor *_output_workspace; - int _matrix_stride; - int _matrix_row_stride; - ITensor *_output_nhwc; - int _num_batches; - int _num_rows; - int _num_cols; - int _num_channels; + using OutputTransform = typename WinogradBase::template OutputTransform; + + std::unique_ptr _transform{ nullptr }; + const ITensor *_biases; + const ITensor *_transformed_output; + ITensor *_workspace; + int _matrix_stride; + int _matrix_row_stride; + ITensor *_output_nhwc; + int _num_batches; + int _num_rows; + int _num_cols; + int _num_channels; }; /** Interface for the NEON kernel to perform Winograd weights transform. */ @@ -482,15 +544,16 @@ public: bool is_parallelisable() const override; private: - using WinogradBase = winograd::WinogradGEMM; + using WinogradBase = winograd::WinogradGEMM; using WinogradConv = typename WinogradBase::template Convolution; - using WeightsTransform = typename WinogradBase::template WeightsTransform; - - const ITensor *_weights_hwio; - ITensor *_output; - int _matrix_stride; - int _num_output_channels; - int _num_input_channels; + using WeightsTransform = typename WinogradBase::template WeightsTransform; + + std::unique_ptr _transform{ nullptr }; + const ITensor *_weights_hwio; + ITensor *_output; + int _matrix_stride; + int _num_output_channels; + int _num_input_channels; }; /** NEON kernel to perform Winograd. */ @@ -499,7 +562,7 @@ class NEWinogradLayerConfiguration { public: /** Winograd base kernel */ - using WinogradBase = winograd::WinogradGEMM; + using WinogradBase = winograd::WinogradGEMM; /** Winograd convolution kernel */ using WinogradConv = typename WinogradBase::template Convolution; -- cgit v1.2.1