Compute Library
 21.02
NEGEMMConv2d.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2020-2021 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
25 
30 
31 #include <set>
32 
33 namespace arm_compute
34 {
35 namespace
36 {
37 GEMMLowpOutputStageInfo calculate_output_stage_metadata(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *output, const ActivationLayerInfo &act)
38 {
39  // Since we need negative offsets for computing convolution, we need to change QuantizationInfo()
40  // Extract and negate input and weights offset
41  const QuantizationInfo iqinfo = input->quantization_info();
42  const QuantizationInfo wqinfo = weights->quantization_info();
43  const QuantizationInfo oqinfo = (output->total_size() == 0) ? iqinfo : output->quantization_info();
44  const UniformQuantizationInfo uoqinfo = oqinfo.uniform();
45  const DataType data_type = input->data_type();
46  // Merge activation with output stage
47  const std::set<ActivationLayerInfo::ActivationFunction> supported_acts = { ActivationLayerInfo::ActivationFunction::RELU,
50  };
51  PixelValue type_min{};
52  PixelValue type_max{};
53  std::tie(type_min, type_max) = get_min_max(data_type);
54  int32_t min_activation = type_min.get<int32_t>();
55  int32_t max_activation = type_max.get<int32_t>();
56  if(supported_acts.count(act.activation()) != 0)
57  {
58  std::tie(min_activation, max_activation) = get_quantized_activation_min_max(act, data_type, uoqinfo);
59  }
60  GEMMLowpOutputStageInfo os_info;
62  os_info.gemmlowp_offset = uoqinfo.offset;
63  os_info.gemmlowp_min_bound = min_activation;
64  os_info.gemmlowp_max_bound = max_activation;
65  os_info.is_quantized_per_channel = (weights->data_type() == DataType::QSYMM8_PER_CHANNEL);
66  quantization::calculate_quantized_multipliers(iqinfo, wqinfo, oqinfo, os_info);
67  return os_info;
68 }
69 AsmGemmInfo init_assembly_metadata(const Conv2dInfo &info, bool is_indirect)
70 {
71  AsmGemmInfo asm_info;
72  asm_info.method = is_indirect ? AsmConvMethod::Indirect : AsmConvMethod::Conv;
73  asm_info.ps_info = info.conv_info;
74  asm_info.activation_info = info.act_info;
75  asm_info.depth_output_gemm3d = true;
76  asm_info.reinterpret_input_as_3d = true;
77  asm_info.padding_top = info.conv_info.pad_top();
78  asm_info.padding_left = info.conv_info.pad_left();
79  asm_info.padding_value = 0.f;
80  asm_info.negated_offsets = false;
81  return asm_info;
82 }
83 } // namespace
84 
85 NEGEMMConv2d::NEGEMMConv2d(const std::shared_ptr<IMemoryManager> &memory_manager)
86  : _gemm_asm_func(std::make_unique<NEGEMMAssemblyDispatch>(memory_manager)), _activation_func(), _weights_permute_func(), _original_weights(nullptr), _permuted_weights(), _is_prepared(false),
87  _run_activation(false)
88 {
89 }
90 
91 NEGEMMConv2d::~NEGEMMConv2d() = default;
92 
93 void NEGEMMConv2d::configure(ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const Conv2dInfo &info)
94 {
95  ARM_COMPUTE_ERROR_ON_NULLPTR(input, weights, output);
97  weights->info(),
98  biases != nullptr ? biases->info() : nullptr,
99  output->info(),
100  info));
101  _original_weights = weights;
102  _weights_permute_func.configure(weights, &_permuted_weights, PermutationVector{ 3, 0, 1, 2 });
103 
104  // Configure assembly dispatch
105  AsmGemmInfo asm_info = init_assembly_metadata(info, false);
106  if(is_data_type_quantized(input->info()->data_type()))
107  {
108  asm_info.output_stage = calculate_output_stage_metadata(input->info(), weights->info(), output->info(), info.act_info);
109  }
110  _gemm_asm_func->configure(input, &_permuted_weights, biases, output, asm_info);
111 
112  // Configure activation
113  if(info.act_info.enabled() && !_gemm_asm_func->is_activation_supported(info.act_info))
114  {
115  _activation_func.configure(output, nullptr, info.act_info);
116  _run_activation = true;
117  }
118 }
119 Status NEGEMMConv2d::validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, const Conv2dInfo &info)
120 {
121  ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(input, weights, output);
125  ARM_COMPUTE_RETURN_ERROR_ON_MSG(info.num_groups > 1, "Grouping (num_groups != 1) is not supported on Neon");
126  ARM_COMPUTE_RETURN_ERROR_ON_MSG(input->data_layout() != DataLayout::NHWC, "Data layout supported is NHWC");
127  const DataType data_type = input->data_type();
128  const TensorShape i_shape = input->tensor_shape();
129  const TensorShape w_shape = weights->tensor_shape();
130  ARM_COMPUTE_RETURN_ERROR_ON(w_shape[0] != i_shape[0]);
132  // Validate biases
133  if(biases != nullptr)
134  {
135  if(is_data_type_quantized_asymmetric(data_type))
136  {
138  }
139  else if(data_type == DataType::BFLOAT16)
140  {
142  }
143  else
144  {
146  }
147  ARM_COMPUTE_RETURN_ERROR_ON(biases->dimension(0) != weights->dimension(3));
149  }
150 
151  AsmGemmInfo asm_info = init_assembly_metadata(info, false);
152  ARM_COMPUTE_RETURN_ON_ERROR(NEGEMMAssemblyDispatch::validate(input, weights, biases, output, asm_info));
153  return Status{};
154 }
156 {
157  prepare();
158 
159  _gemm_asm_func->run();
160  if(_run_activation)
161  {
162  _activation_func.run();
163  }
164 }
166 {
167  if(!_is_prepared)
168  {
169  _permuted_weights.allocator()->allocate();
170  _weights_permute_func.run();
171  _original_weights->mark_as_unused();
172  _is_prepared = true;
173  }
174 }
175 } // namespace arm_compute
bool is_data_type_quantized(DataType dt)
Check if a given data type is of quantized type.
Definition: Utils.h:1168
virtual size_t num_dimensions() const =0
The number of dimensions of the tensor (rank)
Shape of a tensor.
Definition: TensorShape.h:39
Quantize using a fixed point multiplication.
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_LAYOUT(...)
Definition: Validate.h:494
bool enabled() const
Check if initialised.
Definition: Types.h:1600
virtual size_t dimension(size_t index) const =0
Return the size of the requested dimension.
ActivationLayerInfo act_info
~NEGEMMConv2d()
Destructor.
#define ARM_COMPUTE_RETURN_ON_ERROR(status)
Checks if a status contains an error and returns it.
Definition: Error.h:204
virtual DataType data_type() const =0
Data type used for each element of the tensor.
1 channel, 1 F32 per channel
Store the tensor&#39;s metadata.
Definition: ITensorInfo.h:40
#define ARM_COMPUTE_ERROR_THROW_ON(status)
Definition: Error.h:455
Status class.
Definition: Error.h:52
#define ARM_COMPUTE_RETURN_ERROR_ON(cond)
If the condition is true, an error is returned.
Definition: Error.h:296
Interface for Neon tensor.
Definition: ITensor.h:36
Copyright (c) 2017-2021 Arm Limited.
1 channel, 1 F16 per channel
TensorAllocator * allocator()
Return a pointer to the tensor&#39;s allocator.
Definition: Tensor.cpp:48
#define ARM_COMPUTE_RETURN_ERROR_ON_NULLPTR(...)
Definition: Validate.h:163
void mark_as_unused() const
Marks a tensor as unused.
Definition: ITensor.cpp:168
1 channel, 1 S32 per channel
static Status validate(const ITensorInfo *input, const ITensorInfo *weights, const ITensorInfo *biases, const ITensorInfo *output, const Conv2dInfo &info)
Static function to check if given info will lead to a valid configuration of NEGEMMConv2d.
16-bit brain floating-point number
const DataType data_type
Definition: Im2Col.cpp:150
void run() override
Run the kernels contained in the function.
virtual const TensorShape & tensor_shape() const =0
Size for each dimension of the tensor.
std::pair< int32_t, int32_t > get_quantized_activation_min_max(ActivationLayerInfo act_info, DataType data_type, UniformQuantizationInfo oq_info)
Returns a pair of minimum and maximum values for a quantized activation.
Definition: Utils.cpp:483
Status calculate_quantized_multipliers(const QuantizationInfo &iq_info, const QuantizationInfo &wq_info, const QuantizationInfo &oq_info, GEMMLowpOutputStageInfo &stage_info)
Calculate quantized representation of per-channel multipliers.
quantized, asymmetric fixed-point 8-bit number unsigned
void allocate() override
Allocate size specified by TensorInfo of CPU memory.
virtual ITensorInfo * info() const =0
Interface to be implemented by the child class to return the tensor&#39;s metadata.
static Status validate(const ITensorInfo *a, const ITensorInfo *b, const ITensorInfo *c, const ITensorInfo *d, const AsmGemmInfo &info)
Indicates whether or not this function can be used to process the given parameters.
Descriptor used by the Convolution function.
void run() override
Run the kernels contained in the function.
bool is_data_type_quantized_asymmetric(DataType dt)
Check if a given data type is of asymmetric quantized type.
Definition: Utils.h:1190
GEMMLowpOutputStageInfo output_stage
Strides of an item in bytes.
Definition: Strides.h:37
quantized, symmetric per channel fixed-point 8-bit number
__constant DATA_TYPE16 type_min
Definition: minmaxloc.cl:46
void run() override
Run the kernels contained in the function.
Definition: NEPermute.cpp:67
ScaleKernelInfo info(interpolation_policy, default_border_mode, PixelValue(), sampling_policy, false)
NEGEMMConv2d(const std::shared_ptr< IMemoryManager > &memory_manager=nullptr)
Constructor.
#define ARM_COMPUTE_RETURN_ERROR_ON_MISMATCHING_DATA_TYPES(...)
Definition: Validate.h:545
Num samples, height, width, channels.
#define ARM_COMPUTE_RETURN_ERROR_ON_DATA_TYPE_CHANNEL_NOT_IN(t, c,...)
Definition: Validate.h:792
void configure(ITensor *input, ITensor *output, ActivationLayerInfo activation_info)
[NEActivationLayer snippet]
__constant DATA_TYPE16 type_max
Definition: minmaxloc.cl:47
#define ARM_COMPUTE_RETURN_ERROR_ON_MSG(cond, msg)
If the condition is true, an error is returned.
Definition: Error.h:244
#define ARM_COMPUTE_ERROR_ON_NULLPTR(...)
Definition: Validate.h:161
quantized, asymmetric fixed-point 8-bit number signed
void configure(const ITensor *input, ITensor *output, const PermutationVector &perm)
Configure the permute Neon kernel.
Definition: NEPermute.cpp:49
DataType
Available data types.
Definition: Types.h:77
std::tuple< PixelValue, PixelValue > get_min_max(DataType dt)
Compute the mininum and maximum values a data type can take.
Definition: Utils.h:564
void prepare() override
Prepare the function for executing.
void configure(ITensor *input, const ITensor *weights, const ITensor *biases, ITensor *output, const Conv2dInfo &info)
Set the input and output tensors.
virtual DataLayout data_layout() const =0
Get the data layout of the tensor.