blob: 4b9763682355f5dbcb2b8f65003ac5c912d85eb4 [file] [log] [blame]
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +01001//
Teresa Charlinacb3ec52023-04-03 19:57:00 +01002// Copyright © 2017,2022-2023 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);
Teresa Charlinee1497c2023-03-30 13:56:34 +0100114 weightsDesc.SetConstant(constantWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100115
116 armnn::TensorInfo biasesDesc({ outputChannels }, GetBiasTypeFromWeightsType(weightsDesc.GetDataType()).value());
117 biasesDesc.SetQuantizationScale(inputTensorInfo.GetQuantizationScale() * weightsDesc.GetQuantizationScale());
118 biasesDesc.SetQuantizationOffset(0);
Teresa Charlinee1497c2023-03-30 13:56:34 +0100119 biasesDesc.SetConstant(true);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100120
121 LayerTestResult<T, 2> result(outputTensorInfo);
122
Sadik Armagan483c8112021-06-01 09:24:52 +0100123 std::vector<T> input = ConvertToDataType<ArmnnType>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100124 {
125 -1.2f, 6.1f, -3.5f,
126 18.8f, -5.5f, 2.9f
127 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100128 inputTensorInfo);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100129
Sadik Armagan483c8112021-06-01 09:24:52 +0100130 std::vector<T> weights = ConvertToDataType<ArmnnType>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100131 {
132 -8.4f, 20.0f, -10.4f, -8, 16.4f, -11.8f,
133 23.4f, 10.4f, -14.0f, -3.8f, -11.8f, 11.4f
134 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100135 weightsDesc);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100136
Sadik Armagan483c8112021-06-01 09:24:52 +0100137 std::vector<int32_t> bias = {9250, 67500};
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100138
Matthew Sloyan81beae32021-07-13 19:46:11 +0100139 result = SimpleFullyConnectedTestImpl<T>(workloadFactory,
140 memoryManager,
141 tensorHandleFactory,
142 inputTensorInfo,
143 outputTensorInfo,
144 weightsDesc,
145 biasesDesc,
146 weights,
147 bias,
148 input,
149 biasEnabled,
150 true,
151 constantWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100152
153 if (biasEnabled)
154 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100155 result.m_ExpectedData = ConvertToDataType<ArmnnType>({80.f, 1460.f}, outputTensorInfo);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100156 }
157 else
158 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100159 result.m_ExpectedData = ConvertToDataType<ArmnnType>({-107.04f, 110.f}, outputTensorInfo);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100160 }
161
162 return result;
163}
164
165//
166// ArmNN variant of the AndroidNN fully_connected_float_large test.
167//
168// Tests the fully connected layer with large values, optionally transposing weights.
169// Note this is templated for consistency, but the nature of this tests makes it unlikely to be useful in Uint8 mode.
170//
171template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
172LayerTestResult<T, 2> FullyConnectedLargeTestCommon(
173 armnn::IWorkloadFactory& workloadFactory,
174 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100175 const armnn::ITensorHandleFactory& tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100176 bool transposeWeights,
Teresa Charlinacb3ec52023-04-03 19:57:00 +0100177 float qScale = 1.0f,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100178 int32_t qOffset = 0)
179{
180 unsigned int inputWidth = 1;
181 unsigned int inputHeight = 1;
182 unsigned int inputChannels = 5;
183 unsigned int inputNum = 1;
184
185 unsigned int outputChannels = 1;
186 unsigned int outputNum = 1;
187
Teresa Charlinee1497c2023-03-30 13:56:34 +0100188 bool isBiasEnabled = true;
189 bool isConstantWeights = true;
190
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100191 // Define the tensor descriptors.
192 armnn::TensorInfo inputTensorInfo;
193 armnn::TensorInfo outputTensorInfo;
194 armnn::TensorInfo weightsDesc;
195 armnn::TensorInfo biasesDesc;
196
197 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
198 unsigned int outputShape[] = { outputNum, outputChannels };
199 unsigned int weightsShape[] = { inputChannels, outputChannels };
200 if (transposeWeights)
201 {
202 std::swap(weightsShape[0], weightsShape[1]);
203 }
204
205 unsigned int biasShape[] = { outputChannels };
206
207 inputTensorInfo = armnn::TensorInfo(4, inputShape, ArmnnType);
208 outputTensorInfo = armnn::TensorInfo(2, outputShape, ArmnnType);
209 weightsDesc = armnn::TensorInfo(2, weightsShape, ArmnnType);
210 biasesDesc = armnn::TensorInfo(1, biasShape, ArmnnType);
Teresa Charlinee1497c2023-03-30 13:56:34 +0100211 weightsDesc.SetConstant(isConstantWeights);
212 biasesDesc.SetConstant(true);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100213
214 // Set quantization parameters if the requested type is a quantized type.
215 if(armnn::IsQuantizedType<T>())
216 {
217 inputTensorInfo.SetQuantizationScale(qScale);
218 inputTensorInfo.SetQuantizationOffset(qOffset);
219 outputTensorInfo.SetQuantizationScale(qScale);
220 outputTensorInfo.SetQuantizationOffset(qOffset);
221 }
222
223 LayerTestResult<T, 2> result(outputTensorInfo);
224
Sadik Armagan483c8112021-06-01 09:24:52 +0100225 std::vector<T> input = armnnUtils::QuantizedVector<T>(
226 {
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100227 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f,
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100228 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100229 qScale, qOffset);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100230
Sadik Armagan483c8112021-06-01 09:24:52 +0100231 std::vector<T> weights = armnnUtils::QuantizedVector<T>(
232 {
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100233 2.0f, 3.0f, 4.0f, 5.0f, 6.0f
Aron Virginas-Tar48623a02019-10-22 10:00:28 +0100234 },
Sadik Armagan483c8112021-06-01 09:24:52 +0100235 qScale, qOffset);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100236
237 std::vector<T> biasValues({900000.f});
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100238
239 result = SimpleFullyConnectedTestImpl<T>(
240 workloadFactory,
241 memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100242 tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100243 inputTensorInfo, outputTensorInfo,
244 weightsDesc, biasesDesc,
Sadik Armagan483c8112021-06-01 09:24:52 +0100245 weights, biasValues, input,
Teresa Charlinee1497c2023-03-30 13:56:34 +0100246 isBiasEnabled, transposeWeights, isConstantWeights
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100247 );
248
Sadik Armagan483c8112021-06-01 09:24:52 +0100249 result.m_ExpectedData = armnnUtils::QuantizedVector<T>({ 965432.0f }, qScale, qOffset);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100250
251 return result;
252}
253
254//
255// Explicit template specializations
256//
257
Derek Lambertif90c56d2020-01-10 17:14:08 +0000258template LayerTestResult<armnn::ResolveType<armnn::DataType::QAsymmU8>, 2>
259FullyConnectedTest<armnn::DataType::QAsymmU8>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100260 armnn::IWorkloadFactory& workloadFactory,
261 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100262 const armnn::ITensorHandleFactory& tensorHandleFactory,
Sadik Armaganf0a6dec2021-03-25 07:46:55 +0000263 bool biasEnabled,
264 bool constWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100265
Derek Lambertif90c56d2020-01-10 17:14:08 +0000266template LayerTestResult<armnn::ResolveType<armnn::DataType::QSymmS16>, 2>
267FullyConnectedTest<armnn::DataType::QSymmS16>(
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100268 armnn::IWorkloadFactory& workloadFactory,
269 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100270 const armnn::ITensorHandleFactory& tensorHandleFactory,
Sadik Armaganf0a6dec2021-03-25 07:46:55 +0000271 bool biasEnabled,
272 bool constWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100273
274//
275// Implementation functions
276//
277
278LayerTestResult<float, 2> FullyConnectedFloat32Test(
279 armnn::IWorkloadFactory& workloadFactory,
280 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100281 const armnn::ITensorHandleFactory& tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100282 bool biasEnabled,
283 bool transposeWeights)
284{
285 unsigned int inputWidth = 1;
286 unsigned int inputHeight = 1;
287 unsigned int inputChannels = 5;
288 unsigned int inputNum = 2;
289
290 unsigned int outputChannels = 3;
291 unsigned int outputNum = 2;
292
Teresa Charlinee1497c2023-03-30 13:56:34 +0100293 bool isConstantWeights = true;
294
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100295 // Define the tensor descriptors.
296 armnn::TensorInfo inputTensorInfo;
297 armnn::TensorInfo outputTensorInfo;
298 armnn::TensorInfo weightsDesc;
299 armnn::TensorInfo biasesDesc;
300
301 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
302 unsigned int outputShape[] = { outputNum, outputChannels };
303 unsigned int weightsShape[] = { inputChannels, outputChannels };
304
305 if (transposeWeights)
306 {
307 std::swap(weightsShape[0], weightsShape[1]);
308 }
309
310 unsigned int biasShape[] = { outputChannels };
311
312 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
313 outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32);
314 weightsDesc = armnn::TensorInfo(2, weightsShape, armnn::DataType::Float32);
315 biasesDesc = armnn::TensorInfo(1, biasShape, armnn::DataType::Float32);
Teresa Charlinee1497c2023-03-30 13:56:34 +0100316 weightsDesc.SetConstant(isConstantWeights);
317 biasesDesc.SetConstant(true);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100318
319 LayerTestResult<float, 2> result(outputTensorInfo);
320
Sadik Armagan483c8112021-06-01 09:24:52 +0100321 std::vector<float> input =
322 {
323 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
324 5.0f, 4.0f, 3.0f, 2.0f, 1.0f
325 };
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100326
Sadik Armagan483c8112021-06-01 09:24:52 +0100327 std::vector<float> weights =
328 {
329 .5f, 2.f, .5f,
330 .5f, 2.f, 1.f,
331 .5f, 2.f, 2.f,
332 .5f, 2.f, 3.f,
333 .5f, 2.f, 4.f
334 };
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100335
336 if (transposeWeights)
337 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100338 weights =
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100339 {
340 .5f, .5f, .5f, .5f, .5f,
341 2.f, 2.f, 2.f, 2.f, 2.f,
342 .5f, 1.f, 2.f, 3.f, 4.f
Sadik Armagan483c8112021-06-01 09:24:52 +0100343 };
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100344 }
345
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100346 std::vector<float> biasValues({0.f, 0.f, 0.f});
347 if (biasEnabled)
348 {
Sadik Armagan483c8112021-06-01 09:24:52 +0100349 biasValues = std::vector<float>({10.f, 20.f, 30.f});
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100350 }
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100351
352 result = SimpleFullyConnectedTestImpl<float>(
353 workloadFactory,
354 memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100355 tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100356 inputTensorInfo, outputTensorInfo,
357 weightsDesc, biasesDesc,
Sadik Armagan483c8112021-06-01 09:24:52 +0100358 weights, biasValues, input,
Teresa Charlinee1497c2023-03-30 13:56:34 +0100359 biasEnabled, transposeWeights, isConstantWeights
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100360 );
361
Sadik Armagan483c8112021-06-01 09:24:52 +0100362 std::vector<float> expectedOutput =
363 {
364 0.5f + 1.0f + 1.5f + 2.0f + 2.5f + biasValues[0],
365 2.0f + 4.0f + 6.0f + 8.0f + 10.f + biasValues[1],
366 0.5f + 2.0f + 6.0f + 12.f + 20.f + biasValues[2],
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100367
Sadik Armagan483c8112021-06-01 09:24:52 +0100368 2.5f + 2.0f + 1.5f + 1.0f + 0.5f + biasValues[0],
369 10.0f + 8.0f + 6.0f + 4.0f + 2.f + biasValues[1],
370 2.5f + 4.0f + 6.0f + 6.f + 4.f + biasValues[2]
371 };
372 result.m_ExpectedData = expectedOutput;
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100373
374 return result;
375}
376
377LayerTestResult<float, 2> FullyConnectedLargeTest(
378 armnn::IWorkloadFactory& workloadFactory,
379 const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager,
Finn Williams7faf9a82020-08-27 10:37:36 +0100380 const armnn::ITensorHandleFactory& tensorHandleFactory,
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100381 bool transposeWeights)
382{
Finn Williams7faf9a82020-08-27 10:37:36 +0100383 return FullyConnectedLargeTestCommon<armnn::DataType::Float32>(workloadFactory,
384 memoryManager,
385 tensorHandleFactory,
386 transposeWeights);
Aron Virginas-Tar00d306e2019-08-28 18:08:46 +0100387}