blob: f7519a73bc4362f38b10f9aa070bcf100d312c69 [file] [log] [blame]
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001//
Mike Kellyec67a0f2022-11-25 13:55:24 +00002// Copyright © 2017,2022 Arm Ltd and Contributors. All rights reserved.
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01003// SPDX-License-Identifier: MIT
4//
5
6#include "FullyConnectedTestImpl.hpp"
7
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01008
Colm Donelanc42a9872022-02-02 16:35:09 +00009#include <armnnUtils/QuantizeHelper.hpp>
Aron Virginas-Tar48623a02019-10-22 10:00:28 +010010
Colm Donelan0c479742021-12-10 12:43:54 +000011#include <armnn/backends/TensorHandle.hpp>
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010012
Sadik Armagana097d2a2021-11-24 15:47:28 +000013#include <DataTypeUtils.hpp>
14#include <armnnTestUtils/TensorCopyUtils.hpp>
Colm Donelan0c479742021-12-10 12:43:54 +000015#include <armnnTestUtils/WorkloadTestUtils.hpp>
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010016
Colm Donelanc42a9872022-02-02 16:35:09 +000017#include <armnnTestUtils/TensorHelpers.hpp>
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010018
19//
20// Implementation templates
21//
22
23template<typename T, typename B>
24LayerTestResult<T, 2> SimpleFullyConnectedTestImpl(
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000025 armnn::IWorkloadFactory& workloadFactory,
26 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
27 const armnn::ITensorHandleFactory& tensorHandleFactory,
28 armnn::TensorInfo inputTensorInfo,
29 armnn::TensorInfo outputTensorInfo,
30 armnn::TensorInfo weightsTensorInfo,
31 armnn::TensorInfo biasesTensorInfo,
Sadik Armagan483c8112021-06-01 09:24:52 +010032 std::vector<T>& weights,
33 std::vector<B>& bias,
34 std::vector<T>& input,
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000035 bool biasEnabled,
Matthew Sloyan81beae32021-07-13 19:46:11 +010036 bool transposeWeights,
37 bool constantWeights)
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000038{
39 std::unique_ptr<armnn::ITensorHandle> input0Handle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
40 std::unique_ptr<armnn::ITensorHandle> input1Handle = tensorHandleFactory.CreateTensorHandle(weightsTensorInfo);
41 std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
42
Sadik Armagan483c8112021-06-01 09:24:52 +010043 std::vector<T> actualOutput(outputTensorInfo.GetNumElements());
44
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000045 armnn::FullyConnectedQueueDescriptor data;
46 armnn::WorkloadInfo info;
47
48 AddInputToWorkload(data, info, inputTensorInfo, input0Handle.get());
49 AddInputToWorkload(data, info, weightsTensorInfo, input1Handle.get());
50 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
Matthew Sloyan81beae32021-07-13 19:46:11 +010051
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000052 data.m_Parameters.m_BiasEnabled = biasEnabled;
53 data.m_Parameters.m_TransposeWeightMatrix = transposeWeights;
Matthew Sloyan81beae32021-07-13 19:46:11 +010054 data.m_Parameters.m_ConstantWeights = constantWeights;
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000055
56 std::unique_ptr<armnn::ITensorHandle> input2Handle = nullptr;
57 if (biasEnabled)
58 {
59 input2Handle = tensorHandleFactory.CreateTensorHandle(biasesTensorInfo);
60 AddInputToWorkload(data, info, biasesTensorInfo, input2Handle.get());
61 }
62
Teresa Charlin611c7fb2022-01-07 09:47:29 +000063 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateWorkload(armnn::LayerType::FullyConnected,
64 data,
65 info);
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000066 LayerTestResult<T, 2> result(outputTensorInfo);
67
68 input0Handle->Allocate();
69 input1Handle->Allocate();
70 outputHandle->Allocate();
Sadik Armagan483c8112021-06-01 09:24:52 +010071 CopyDataToITensorHandle(input0Handle.get(), input.data());
72 CopyDataToITensorHandle(input1Handle.get(), weights.data());
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000073 if (biasEnabled)
74 {
75 input2Handle->Allocate();
Sadik Armagan483c8112021-06-01 09:24:52 +010076 CopyDataToITensorHandle(input2Handle.get(), bias.data());
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000077 }
78
79 ExecuteWorkload(*workload, memoryManager);
80
Sadik Armagan483c8112021-06-01 09:24:52 +010081 CopyDataFromITensorHandle(actualOutput.data(), outputHandle.get());
82 result.m_ActualData = actualOutput;
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000083
84 return result;
85}
86
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010087template<armnn::DataType ArmnnType, typename T>
88LayerTestResult<T, 2> FullyConnectedTest(
89 armnn::IWorkloadFactory& workloadFactory,
90 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +010091 const armnn::ITensorHandleFactory& tensorHandleFactory,
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000092 bool biasEnabled,
93 bool constantWeights)
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +010094{
95 constexpr static unsigned int inputWidth = 3u;
96 constexpr static unsigned int inputHeight = 2u;
97 constexpr static unsigned int inputChannels = 1u;
98
99 constexpr static unsigned int inputSize = inputWidth * inputHeight * inputChannels;
100
101 constexpr static unsigned int outputChannels = 2u;
102
103 armnn::TensorInfo inputTensorInfo({ 1, inputChannels, inputHeight, inputWidth }, ArmnnType);
104 inputTensorInfo.SetQuantizationScale(0.1f);
105 inputTensorInfo.SetQuantizationOffset(63);
106
107 armnn::TensorInfo outputTensorInfo({ 1, outputChannels }, ArmnnType);
108 outputTensorInfo.SetQuantizationScale(5.f);
109 outputTensorInfo.SetQuantizationOffset(biasEnabled ? -50 : 10);
110
111 armnn::TensorInfo weightsDesc({ outputChannels, inputSize }, ArmnnType);
112 weightsDesc.SetQuantizationScale(0.2f);
113 weightsDesc.SetQuantizationOffset(93);
114
115 armnn::TensorInfo biasesDesc({ outputChannels }, GetBiasTypeFromWeightsType(weightsDesc.GetDataType()).value());
116 biasesDesc.SetQuantizationScale(inputTensorInfo.GetQuantizationScale() * weightsDesc.GetQuantizationScale());
117 biasesDesc.SetQuantizationOffset(0);
118
119 LayerTestResult<T, 2> result(outputTensorInfo);
120
Sadik Armagan483c8112021-06-01 09:24:52 +0100121 std::vector<T> input = ConvertToDataType<ArmnnType>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100122 {
123 -1.2f, 6.1f, -3.5f,
124 18.8f, -5.5f, 2.9f
125 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100126 inputTensorInfo);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100127
Sadik Armagan483c8112021-06-01 09:24:52 +0100128 std::vector<T> weights = ConvertToDataType<ArmnnType>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100129 {
130 -8.4f, 20.0f, -10.4f, -8, 16.4f, -11.8f,
131 23.4f, 10.4f, -14.0f, -3.8f, -11.8f, 11.4f
132 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100133 weightsDesc);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100134
Sadik Armagan483c8112021-06-01 09:24:52 +0100135 std::vector<int32_t> bias = {9250, 67500};
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100136
Matthew Sloyan81beae32021-07-13 19:46:11 +0100137 result = SimpleFullyConnectedTestImpl<T>(workloadFactory,
138 memoryManager,
139 tensorHandleFactory,
140 inputTensorInfo,
141 outputTensorInfo,
142 weightsDesc,
143 biasesDesc,
144 weights,
145 bias,
146 input,
147 biasEnabled,
148 true,
149 constantWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100150
151 if (biasEnabled)
152 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100153 result.m_ExpectedData = ConvertToDataType<ArmnnType>({80.f, 1460.f}, outputTensorInfo);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100154 }
155 else
156 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100157 result.m_ExpectedData = ConvertToDataType<ArmnnType>({-107.04f, 110.f}, outputTensorInfo);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100158 }
159
160 return result;
161}
162
163//
164// ArmNN variant of the AndroidNN fully_connected_float_large test.
165//
166// Tests the fully connected layer with large values, optionally transposing weights.
167// Note this is templated for consistency, but the nature of this tests makes it unlikely to be useful in Uint8 mode.
168//
169template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
170LayerTestResult<T, 2> FullyConnectedLargeTestCommon(
171 armnn::IWorkloadFactory& workloadFactory,
172 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100173 const armnn::ITensorHandleFactory& tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100174 bool transposeWeights,
175 float qScale = 0.0f,
176 int32_t qOffset = 0)
177{
178 unsigned int inputWidth = 1;
179 unsigned int inputHeight = 1;
180 unsigned int inputChannels = 5;
181 unsigned int inputNum = 1;
182
183 unsigned int outputChannels = 1;
184 unsigned int outputNum = 1;
185
186 // Define the tensor descriptors.
187 armnn::TensorInfo inputTensorInfo;
188 armnn::TensorInfo outputTensorInfo;
189 armnn::TensorInfo weightsDesc;
190 armnn::TensorInfo biasesDesc;
191
192 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
193 unsigned int outputShape[] = { outputNum, outputChannels };
194 unsigned int weightsShape[] = { inputChannels, outputChannels };
195 if (transposeWeights)
196 {
197 std::swap(weightsShape[0], weightsShape[1]);
198 }
199
200 unsigned int biasShape[] = { outputChannels };
201
202 inputTensorInfo = armnn::TensorInfo(4, inputShape, ArmnnType);
203 outputTensorInfo = armnn::TensorInfo(2, outputShape, ArmnnType);
204 weightsDesc = armnn::TensorInfo(2, weightsShape, ArmnnType);
205 biasesDesc = armnn::TensorInfo(1, biasShape, ArmnnType);
206
207 // Set quantization parameters if the requested type is a quantized type.
208 if(armnn::IsQuantizedType<T>())
209 {
210 inputTensorInfo.SetQuantizationScale(qScale);
211 inputTensorInfo.SetQuantizationOffset(qOffset);
212 outputTensorInfo.SetQuantizationScale(qScale);
213 outputTensorInfo.SetQuantizationOffset(qOffset);
214 }
215
216 LayerTestResult<T, 2> result(outputTensorInfo);
217
Sadik Armagan483c8112021-06-01 09:24:52 +0100218 std::vector<T> input = armnnUtils::QuantizedVector<T>(
219 {
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100220 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100221 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100222 qScale, qOffset);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100223
Sadik Armagan483c8112021-06-01 09:24:52 +0100224 std::vector<T> weights = armnnUtils::QuantizedVector<T>(
225 {
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100226 2.0f, 3.0f, 4.0f, 5.0f, 6.0f
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100227 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100228 qScale, qOffset);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100229
230 std::vector<T> biasValues({900000.f});
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100231
232 result = SimpleFullyConnectedTestImpl<T>(
233 workloadFactory,
234 memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100235 tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100236 inputTensorInfo, outputTensorInfo,
237 weightsDesc, biasesDesc,
Sadik Armagan483c8112021-06-01 09:24:52 +0100238 weights, biasValues, input,
Matthew Sloyan81beae32021-07-13 19:46:11 +0100239 true, transposeWeights, true
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100240 );
241
Sadik Armagan483c8112021-06-01 09:24:52 +0100242 result.m_ExpectedData = armnnUtils::QuantizedVector<T>({ 965432.0f }, qScale, qOffset);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100243
244 return result;
245}
246
247//
248// Explicit template specializations
249//
250
Derek Lambertif90c56d2020-01-10 17:14:08 +0000251template LayerTestResult<armnn::ResolveType<armnn::DataType::QAsymmU8>, 2>
252FullyConnectedTest<armnn::DataType::QAsymmU8>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100253 armnn::IWorkloadFactory& workloadFactory,
254 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100255 const armnn::ITensorHandleFactory& tensorHandleFactory,
Sadik Armaganf0a6dec2021-03-25 07:46:55 +0000256 bool biasEnabled,
257 bool constWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100258
Derek Lambertif90c56d2020-01-10 17:14:08 +0000259template LayerTestResult<armnn::ResolveType<armnn::DataType::QSymmS16>, 2>
260FullyConnectedTest<armnn::DataType::QSymmS16>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100261 armnn::IWorkloadFactory& workloadFactory,
262 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100263 const armnn::ITensorHandleFactory& tensorHandleFactory,
Sadik Armaganf0a6dec2021-03-25 07:46:55 +0000264 bool biasEnabled,
265 bool constWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100266
267//
268// Implementation functions
269//
270
271LayerTestResult<float, 2> FullyConnectedFloat32Test(
272 armnn::IWorkloadFactory& workloadFactory,
273 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100274 const armnn::ITensorHandleFactory& tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100275 bool biasEnabled,
276 bool transposeWeights)
277{
278 unsigned int inputWidth = 1;
279 unsigned int inputHeight = 1;
280 unsigned int inputChannels = 5;
281 unsigned int inputNum = 2;
282
283 unsigned int outputChannels = 3;
284 unsigned int outputNum = 2;
285
286 // Define the tensor descriptors.
287 armnn::TensorInfo inputTensorInfo;
288 armnn::TensorInfo outputTensorInfo;
289 armnn::TensorInfo weightsDesc;
290 armnn::TensorInfo biasesDesc;
291
292 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
293 unsigned int outputShape[] = { outputNum, outputChannels };
294 unsigned int weightsShape[] = { inputChannels, outputChannels };
295
296 if (transposeWeights)
297 {
298 std::swap(weightsShape[0], weightsShape[1]);
299 }
300
301 unsigned int biasShape[] = { outputChannels };
302
303 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
304 outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32);
305 weightsDesc = armnn::TensorInfo(2, weightsShape, armnn::DataType::Float32);
306 biasesDesc = armnn::TensorInfo(1, biasShape, armnn::DataType::Float32);
307
308 LayerTestResult<float, 2> result(outputTensorInfo);
309
Sadik Armagan483c8112021-06-01 09:24:52 +0100310 std::vector<float> input =
311 {
312 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
313 5.0f, 4.0f, 3.0f, 2.0f, 1.0f
314 };
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100315
Sadik Armagan483c8112021-06-01 09:24:52 +0100316 std::vector<float> weights =
317 {
318 .5f, 2.f, .5f,
319 .5f, 2.f, 1.f,
320 .5f, 2.f, 2.f,
321 .5f, 2.f, 3.f,
322 .5f, 2.f, 4.f
323 };
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100324
325 if (transposeWeights)
326 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100327 weights =
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100328 {
329 .5f, .5f, .5f, .5f, .5f,
330 2.f, 2.f, 2.f, 2.f, 2.f,
331 .5f, 1.f, 2.f, 3.f, 4.f
Sadik Armagan483c8112021-06-01 09:24:52 +0100332 };
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100333 }
334
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100335 std::vector<float> biasValues({0.f, 0.f, 0.f});
336 if (biasEnabled)
337 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100338 biasValues = std::vector<float>({10.f, 20.f, 30.f});
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100339 }
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100340
341 result = SimpleFullyConnectedTestImpl<float>(
342 workloadFactory,
343 memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100344 tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100345 inputTensorInfo, outputTensorInfo,
346 weightsDesc, biasesDesc,
Sadik Armagan483c8112021-06-01 09:24:52 +0100347 weights, biasValues, input,
Matthew Sloyan81beae32021-07-13 19:46:11 +0100348 biasEnabled, transposeWeights, true
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100349 );
350
Sadik Armagan483c8112021-06-01 09:24:52 +0100351 std::vector<float> expectedOutput =
352 {
353 0.5f + 1.0f + 1.5f + 2.0f + 2.5f + biasValues[0],
354 2.0f + 4.0f + 6.0f + 8.0f + 10.f + biasValues[1],
355 0.5f + 2.0f + 6.0f + 12.f + 20.f + biasValues[2],
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100356
Sadik Armagan483c8112021-06-01 09:24:52 +0100357 2.5f + 2.0f + 1.5f + 1.0f + 0.5f + biasValues[0],
358 10.0f + 8.0f + 6.0f + 4.0f + 2.f + biasValues[1],
359 2.5f + 4.0f + 6.0f + 6.f + 4.f + biasValues[2]
360 };
361 result.m_ExpectedData = expectedOutput;
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100362
363 return result;
364}
365
366LayerTestResult<float, 2> FullyConnectedLargeTest(
367 armnn::IWorkloadFactory& workloadFactory,
368 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100369 const armnn::ITensorHandleFactory& tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100370 bool transposeWeights)
371{
Finn Williams7faf9a82020-08-27 10:37:36 +0100372 return FullyConnectedLargeTestCommon<armnn::DataType::Float32>(workloadFactory,
373 memoryManager,
374 tensorHandleFactory,
375 transposeWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100376}