1 /* 2 * Copyright (c) 2017-2022 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 */ 24 #include "arm_compute/core/Helpers.h" 25 #include "arm_compute/core/TensorShape.h" 26 #include "arm_compute/core/Types.h" 27 #include "arm_compute/core/utils/misc/ShapeCalculator.h" 28 #include "tests/AssetsLibrary.h" 29 #include "tests/Globals.h" 30 #include "tests/IAccessor.h" 31 #include "tests/framework/Asserts.h" 32 #include "tests/framework/Fixture.h" 33 #include "tests/validation/Helpers.h" 34 #include "tests/validation/fixtures/ConvolutionLayerFixture.h" 35 #include "tests/validation/reference/ConvolutionLayer.h" 36 #include "tests/validation/reference/Permute.h" 37 38 #include <random> 39 40 namespace arm_compute 41 { 42 namespace test 43 { 44 namespace validation 45 { 46 using namespace arm_compute::misc::shape_calculator; 47 48 template <typename TensorType, typename AccessorType, typename FunctionType, typename T> 49 class DirectConvolutionValidationGenericFixture : public framework::Fixture 50 { 51 public: 52 using TBias = typename std::conditional < std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value, int32_t, T >::type; 53 54 template <typename...> 55 void setup(TensorShape input_shape, int stride_x, int stride_y, int pad_x, int pad_y, unsigned int kernel_size, unsigned int num_kernels, 56 DataType data_type, QuantizationInfo quantization_info, ActivationLayerInfo act_info, DataLayout data_layout, bool mixed_layout = false) 57 { 58 _quantization_info = quantization_info; 59 _data_type = data_type; 60 _mixed_layout = mixed_layout; 61 62 TensorShape weights_shape(kernel_size, kernel_size, input_shape.z(), num_kernels); 63 const TensorShape bias_shape(num_kernels); 64 const PadStrideInfo info(stride_x, stride_y, pad_x, pad_y, DimensionRoundingType::FLOOR); 65 const DataType bias_data_type = is_data_type_quantized_asymmetric(data_type) ? DataType::S32 : data_type; 66 67 TensorInfo input_info = TensorInfo(input_shape, 1, data_type); 68 TensorInfo weights_info = TensorInfo(weights_shape, 1, data_type); 69 70 const TensorShape output_shape = compute_deep_convolution_shape(input_info, weights_info, info); 71 72 _target = compute_target(input_shape, weights_shape, bias_shape, output_shape, info, data_type, bias_data_type, quantization_info, act_info, data_layout); 73 _reference = compute_reference(input_shape, weights_shape, bias_shape, output_shape, info, data_type, bias_data_type, quantization_info, act_info); 74 } 75 76 template <typename...> setup(TensorShape input_shape,TensorShape weights_shape,TensorShape bias_shape,TensorShape output_shape,PadStrideInfo info,Size2D dilation,DataType data_type,QuantizationInfo quantization_info,ActivationLayerInfo act_info,DataLayout data_layout)77 void setup(TensorShape input_shape, TensorShape weights_shape, TensorShape bias_shape, TensorShape output_shape, PadStrideInfo info, Size2D dilation, 78 DataType data_type, QuantizationInfo quantization_info, ActivationLayerInfo act_info, DataLayout data_layout) 79 { 80 ARM_COMPUTE_ERROR_ON(data_layout == DataLayout::UNKNOWN); 81 ARM_COMPUTE_UNUSED(dilation); 82 83 _quantization_info = quantization_info; 84 _data_type = data_type; 85 86 const DataType bias_data_type = is_data_type_quantized_asymmetric(data_type) ? DataType::S32 : data_type; 87 88 _target = compute_target(input_shape, weights_shape, bias_shape, output_shape, info, data_type, bias_data_type, quantization_info, act_info, data_layout); 89 _reference = compute_reference(input_shape, weights_shape, bias_shape, output_shape, info, data_type, bias_data_type, quantization_info, act_info); 90 } 91 92 protected: mix_layout(FunctionType & layer,TensorType & src,TensorType & dst)93 void mix_layout(FunctionType &layer, TensorType &src, TensorType &dst) 94 { 95 DataLayout data_layout = src.info()->data_layout(); 96 // Test Multi DataLayout graph cases, when the data layout changes after configure 97 src.info()->set_data_layout(data_layout == DataLayout::NCHW ? DataLayout::NHWC : DataLayout::NCHW); 98 dst.info()->set_data_layout(data_layout == DataLayout::NCHW ? DataLayout::NHWC : DataLayout::NCHW); 99 100 // Compute Convolution function 101 layer.run(); 102 103 // Reinstating original data layout for the test suite to properly check the values 104 src.info()->set_data_layout(data_layout); 105 dst.info()->set_data_layout(data_layout); 106 } 107 108 template <typename U> fill(U && tensor,int i)109 void fill(U &&tensor, int i) 110 { 111 switch(tensor.data_type()) 112 { 113 case DataType::QASYMM8: 114 { 115 std::uniform_int_distribution<uint32_t> distribution(0, 50); 116 library->fill(tensor, distribution, i); 117 break; 118 } 119 case DataType::QASYMM8_SIGNED: 120 { 121 // Use small input range to avoid all the test results being saturated at the end. 122 std::uniform_int_distribution<int32_t> distribution(-25, 25); 123 library->fill(tensor, distribution, i); 124 break; 125 } 126 case DataType::F16: 127 { 128 arm_compute::utils::uniform_real_distribution_16bit<half> distribution{ -1.0f, 1.0f }; 129 library->fill(tensor, distribution, i); 130 break; 131 } 132 case DataType::F32: 133 { 134 std::uniform_real_distribution<float> distribution(-1.0f, 1.0f); 135 library->fill(tensor, distribution, i); 136 break; 137 } 138 case DataType::S32: 139 { 140 std::uniform_int_distribution<int32_t> distribution(-5, 5); 141 library->fill(tensor, distribution, i); 142 break; 143 } 144 default: 145 library->fill_tensor_uniform(tensor, i); 146 } 147 } 148 compute_target(TensorShape input_shape,TensorShape weights_shape,const TensorShape & bias_shape,TensorShape output_shape,const PadStrideInfo & info,DataType data_type,DataType bias_data_type,QuantizationInfo quantization_info,ActivationLayerInfo act_info,const DataLayout & data_layout)149 TensorType compute_target(TensorShape input_shape, TensorShape weights_shape, const TensorShape &bias_shape, TensorShape output_shape, const PadStrideInfo &info, 150 DataType data_type, DataType bias_data_type, QuantizationInfo quantization_info, ActivationLayerInfo act_info, const DataLayout &data_layout) 151 { 152 if(data_layout == DataLayout::NHWC) 153 { 154 permute(input_shape, PermutationVector(2U, 0U, 1U)); 155 permute(weights_shape, PermutationVector(2U, 0U, 1U)); 156 permute(output_shape, PermutationVector(2U, 0U, 1U)); 157 } 158 159 // Create tensors 160 TensorType src = create_tensor<TensorType>(input_shape, data_type, 1, quantization_info, data_layout); 161 TensorType weights = create_tensor<TensorType>(weights_shape, data_type, 1, quantization_info, data_layout); 162 TensorType bias = create_tensor<TensorType>(bias_shape, bias_data_type, 1, quantization_info); 163 TensorType dst = create_tensor<TensorType>(output_shape, data_type, 1, quantization_info, data_layout); 164 165 add_padding_x({ &src, &bias, &dst }, data_layout); 166 add_padding_x({ &weights }, data_layout, input_shape[0] % 4 == 0); // Don't add left padding if cl image will be used 167 168 // Create and configure function 169 FunctionType conv; 170 conv.configure(&src, &weights, &bias, &dst, info, act_info); 171 172 ARM_COMPUTE_ASSERT(src.info()->is_resizable()); 173 ARM_COMPUTE_ASSERT(weights.info()->is_resizable()); 174 ARM_COMPUTE_ASSERT(bias.info()->is_resizable()); 175 ARM_COMPUTE_ASSERT(dst.info()->is_resizable()); 176 177 // Allocate tensors 178 src.allocator()->allocate(); 179 weights.allocator()->allocate(); 180 bias.allocator()->allocate(); 181 dst.allocator()->allocate(); 182 183 ARM_COMPUTE_ASSERT(!src.info()->is_resizable()); 184 ARM_COMPUTE_ASSERT(!weights.info()->is_resizable()); 185 ARM_COMPUTE_ASSERT(!bias.info()->is_resizable()); 186 ARM_COMPUTE_ASSERT(!dst.info()->is_resizable()); 187 188 // Fill tensors 189 fill(AccessorType(src), 0); 190 fill(AccessorType(weights), 1); 191 fill(AccessorType(bias), 2); 192 193 if(_mixed_layout) 194 { 195 mix_layout(conv, src, dst); 196 } 197 else 198 { 199 // Compute Convolution function 200 conv.run(); 201 } 202 203 return dst; 204 } 205 compute_reference(const TensorShape & input_shape,const TensorShape & weights_shape,const TensorShape & bias_shape,const TensorShape & output_shape,const PadStrideInfo & info,DataType data_type,DataType bias_data_type,QuantizationInfo quantization_info,ActivationLayerInfo act_info)206 SimpleTensor<T> compute_reference(const TensorShape &input_shape, const TensorShape &weights_shape, const TensorShape &bias_shape, const TensorShape &output_shape, const PadStrideInfo &info, 207 DataType data_type, DataType bias_data_type, QuantizationInfo quantization_info, ActivationLayerInfo act_info) 208 { 209 // Create reference 210 SimpleTensor<T> src{ input_shape, data_type, 1, quantization_info }; 211 SimpleTensor<T> weights{ weights_shape, data_type, 1, quantization_info }; 212 SimpleTensor<TBias> bias{ bias_shape, bias_data_type, 1, quantization_info }; 213 214 // Fill reference 215 fill(src, 0); 216 fill(weights, 1); 217 fill(bias, 2); 218 219 SimpleTensor<T> dst = reference::convolution_layer<T>(src, weights, bias, output_shape, info); 220 return (act_info.enabled()) ? reference::activation_layer<T>(dst, act_info) : dst; 221 } 222 TensorType _target{}; 223 SimpleTensor<T> _reference{}; 224 QuantizationInfo _quantization_info{}; 225 DataType _data_type{}; 226 bool _mixed_layout{ false }; 227 }; 228 229 template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool mixed_layout = false> 230 class DirectConvolutionValidationFixture : public DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T> 231 { 232 public: 233 template <typename...> setup(TensorShape input_shape,int stride_x,int stride_y,int pad_x,int pad_y,unsigned int kernel_size,unsigned int num_kernels,DataType data_type,ActivationLayerInfo act_info,DataLayout data_layout)234 void setup(TensorShape input_shape, int stride_x, int stride_y, int pad_x, int pad_y, unsigned int kernel_size, unsigned int num_kernels, DataType data_type, ActivationLayerInfo act_info, 235 DataLayout data_layout) 236 { 237 DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup(input_shape, stride_x, stride_y, pad_x, pad_y, kernel_size, num_kernels, data_type, QuantizationInfo(), 238 act_info, data_layout, mixed_layout); 239 } 240 }; 241 242 template <typename TensorType, typename AccessorType, typename FunctionType, typename T, bool mixed_layout = false> 243 class DirectConvolutionValidationQuantizedFixture : public DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T> 244 { 245 public: 246 template <typename...> setup(TensorShape input_shape,int stride_x,int stride_y,int pad_x,int pad_y,unsigned int kernel_size,unsigned int num_kernels,DataType data_type,QuantizationInfo quantization_info,ActivationLayerInfo act_info,DataLayout data_layout)247 void setup(TensorShape input_shape, int stride_x, int stride_y, int pad_x, int pad_y, unsigned int kernel_size, unsigned int num_kernels, DataType data_type, QuantizationInfo quantization_info, 248 ActivationLayerInfo act_info, DataLayout data_layout) 249 { 250 DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup(input_shape, stride_x, stride_y, pad_x, pad_y, kernel_size, num_kernels, data_type, quantization_info, 251 act_info, data_layout, mixed_layout); 252 } 253 }; 254 255 template <typename TensorType, typename AccessorType, typename FunctionType, typename T> 256 class DirectConvolutionValidationWithTensorShapesQuantizedFixture : public DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T> 257 { 258 public: 259 template <typename...> setup(TensorShape input_shape,TensorShape weights_shape,TensorShape bias_shape,TensorShape output_shape,PadStrideInfo info,Size2D dilation,DataType data_type,QuantizationInfo quantization_info,ActivationLayerInfo act_info,DataLayout data_layout)260 void setup(TensorShape input_shape, TensorShape weights_shape, TensorShape bias_shape, TensorShape output_shape, PadStrideInfo info, Size2D dilation, 261 DataType data_type, QuantizationInfo quantization_info, ActivationLayerInfo act_info, DataLayout data_layout) 262 { 263 DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup(input_shape, weights_shape, bias_shape, output_shape, info, dilation, data_type, quantization_info, 264 act_info, data_layout); 265 } 266 }; 267 268 template <typename TensorType, typename AccessorType, typename FunctionType, typename T> 269 class DirectConvolutionValidationWithTensorShapesFixture : public DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T> 270 { 271 public: 272 template <typename...> setup(TensorShape input_shape,TensorShape weights_shape,TensorShape bias_shape,TensorShape output_shape,PadStrideInfo info,Size2D dilation,DataType data_type,ActivationLayerInfo act_info)273 void setup(TensorShape input_shape, TensorShape weights_shape, TensorShape bias_shape, TensorShape output_shape, PadStrideInfo info, Size2D dilation, 274 DataType data_type, ActivationLayerInfo act_info) 275 { 276 DirectConvolutionValidationGenericFixture<TensorType, AccessorType, FunctionType, T>::setup(input_shape, weights_shape, bias_shape, output_shape, info, dilation, data_type, QuantizationInfo(), 277 act_info, DataLayout::NCHW); 278 } 279 }; 280 281 } // namespace validation 282 } // namespace test 283 } // namespace arm_compute 284