aboutsummaryrefslogtreecommitdiff
path: root/arm_compute/core/NEON/kernels/winograd/winograd_layer.hpp
blob: a3b3db42dd99a07b0dc9988d08fa7117e46db86e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright (c) 2017 ARM Limited.
 *
 * SPDX-License-Identifier: MIT
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#pragma once

#include <utility>

#include "batched_blocked_gemm.hpp"
#include "winograd_gemm.hpp"

/** Example of how to construct an ACL-like interface.
 *
 * Use `get_weight_storage_size`, `get_input_storage_size` and
 * `get_output_storage_size` to allocate memory for the convolution engine.
 * Then create a `WinogradConvolutionLayer`.
 *
 * Initialise the weights using `weights_transform.run(...)`.
 *
 * For each inference:
 *   1. Transform the inputs to the Winograd domain using `input_transform.run(...)`
 *   2. Perform a number of GEMMs using `gemms.run(...)`
 *   3. Transform the output to the spatial domain using `output_transform.run(...)`
 */
template <int OutputTileRows, int OutputTileCols, int KernelRows, int KernelCols,
          typename TIn, typename TOut>
class WinogradConvolutionLayer
{
  private:
    const KernelShape _kernel_shape;
    const Tensor4DShape _input_shape;
    const PaddingType _padding;
    const Tensor4DShape _output_shape;
    const int _n_output_rows, _n_output_cols;
    const int _kernel_matrix_stride, _kernel_matrix_row_stride;
    const int _input_matrix_stride, _input_matrix_row_stride;
    const int _output_matrix_stride, _output_matrix_row_stride;
    const int _tile_rows, _tile_cols;
    const int _m, _k, _n;

  public:
    using WinogradBase = winograd::WinogradGEMM<OutputTileRows, OutputTileCols, KernelRows, KernelCols>;
    using WeightsTransform = typename WinogradBase::template WeightsTransform<TIn>;
    using InputTransform = typename WinogradBase::template InputTransform<TIn>;
    using WinogradConv = typename WinogradBase::template Convolution<TOut, TIn>;
    using MultiGEMM = winograd::BatchedBlockedGemm<WinogradConv::M_BLOCK, WinogradConv::N_BLOCK, TIn, TOut>;
    using OutputTransform = typename WinogradBase::template OutputTransform<TOut>;

    /* Public member variables. */
    WeightsTransform weights_transform;  /** Operator to transform weights to Winograd domain. */
    InputTransform input_transform;      /** Operator to transform input to Winograd domain. */
    MultiGEMM gemms;                     /** Operator to perform multiple GEMMs. */
    OutputTransform output_transform;    /** Operator to transform output from Winograd domain. */

    /** Determine how much memory (in units of TIn) to allocate for the
     * transformed weights.
     */
    static unsigned int get_weight_storage_size(
      const int n_output_channels,  /** Number of output feature maps. */
      const int n_input_channels    /** Number of input feature maps. */
    );

    /** Determine how much memory (in units of TIn) to allocate for the
     * transformed input.
     */
    static unsigned int get_input_storage_size(
      const int n_batches,     /** Number of batches in the input tensor. */
      const int n_channels,    /** Number of feature maps in the input tensor. */
      const int n_rows,        /** Number of rows in each feature map. */
      const int n_cols,        /** Number of columns in each feature map. */
      const bool same_padding  /** Use "SAME" padding, otherwise use "VALID". */
    );

    /** Determine how much memory (in units of TOut) to allocate for the
     * (Winograd domain) output.
     */
    static unsigned int get_output_storage_size(
      const int n_batches,          /** Number of batches in the output tensor. */
      const int n_rows,             /** Number of rows in each feature map of the input tensor. */
      const int n_cols,             /** Number of columns in each feature map of the input tensor. */
      const int n_output_channels,  /** Number of feature maps in the output tensor. */
      const bool same_padding       /** Use "SAME" padding, otherwise use "VALID". */
    );

    /** Get the shape (rows, cols) of a feature map of the output tensor. */
    static std::pair<int, int> get_output_feature_map_shape(
      const int n_input_rows,  /** Number of rows in the input feature map. */
      const int n_input_cols,  /** Number of columns in the input feature map. */
      const bool same_padding  /** Use "SAME" padding, otherwise use "VALID". */
    );

    /** Create a new Winograd convolution layer.
     */
    WinogradConvolutionLayer(
      const int n_batches,          /** Number of batches in the input and output tensors. */
      const int n_input_channels,   /** Number of feature maps in a batch of the input tensor. */
      const int n_input_rows,       /** Number of rows in a feature map of the input tensor. */
      const int n_input_cols,       /** Number of columns in a feature map of the input tensor. */
      const int n_output_channels,  /** Number of feature maps in the output tensor. */
      const bool same_padding,      /** Use "SAME" padding, otherwise use "VALID". */
      const TIn* const weights,     /** Pointer to weight tensor in spatial domain. Must be ordered as "Height x Rows x Input Feature Maps x Output Feature Maps. */
      TIn* const weights_storage,   /** Pointer to storage for weight tensor in the Winograd domain. Must be at least the size returned by `get_weight_storage_size`. */
      const TIn* const input,       /** Pointer to NHWC ordered input tensor, in the spatial domain. */
      TIn* const winograd_input,    /** Pointer to working space for the input tensor in the Winograd domain. Must be at least the size returned by `get_input_storage_size`. */
      TOut* const output,           /** Pointer to NHWC ordered output tensor, in the spatial domain. */
      TOut* const winograd_output   /** Pointer to working space for the output tensor in the Winograd domain. Must be at least the size returned by `get_output_storage_size`. */
    );
};