blob: 125b7e62b12db23e2ffcf10d6f24a924a5d8595f [file] [log] [blame]
telsoa014fcda012018-03-09 14:13:49 +00001//
2// Copyright © 2017 Arm Ltd. All rights reserved.
David Beckecb56cd2018-09-05 12:52:57 +01003// SPDX-License-Identifier: MIT
telsoa014fcda012018-03-09 14:13:49 +00004//
5
6template<typename T, typename B>
7LayerTestResult<T, 2> SimpleFullyConnectedTestImpl(
8 armnn::IWorkloadFactory& workloadFactory,
9 armnn::TensorInfo inputTensorInfo,
10 armnn::TensorInfo outputTensorInfo,
11 armnn::TensorInfo weightsDesc,
12 armnn::TensorInfo biasesDesc,
surmeh013537c2c2018-05-18 16:31:43 +010013 boost::multi_array<T, 2>& weights,
14 boost::multi_array<B, 1>& bias,
15 boost::multi_array<T, 4>& input,
telsoa014fcda012018-03-09 14:13:49 +000016 bool biasEnabled,
17 bool transposeWeights)
18{
19 std::unique_ptr<armnn::ITensorHandle> inputHandle = workloadFactory.CreateTensorHandle(inputTensorInfo);
20 std::unique_ptr<armnn::ITensorHandle> outputHandle = workloadFactory.CreateTensorHandle(outputTensorInfo);
21
22 armnn::FullyConnectedQueueDescriptor data;
23 armnn::WorkloadInfo info;
24 armnn::ScopedCpuTensorHandle weightsTensor(weightsDesc);
25 armnn::ScopedCpuTensorHandle biasTensor(biasesDesc);
26
27 AllocateAndCopyDataToITensorHandle(&weightsTensor, &weights[0][0]);
28 AllocateAndCopyDataToITensorHandle(&biasTensor, &bias[0]);
29
30 AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
31 AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
32 data.m_Weight = &weightsTensor;
33 data.m_Bias = &biasTensor;
34 data.m_Parameters.m_BiasEnabled = biasEnabled;
35 data.m_Parameters.m_TransposeWeightMatrix = transposeWeights;
36
37 std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateFullyConnected(data, info);
38 LayerTestResult<T, 2> result(outputTensorInfo);
39
40 inputHandle->Allocate();
41 outputHandle->Allocate();
42 CopyDataToITensorHandle(inputHandle.get(), &input[0][0][0][0]);
43
surmeh013537c2c2018-05-18 16:31:43 +010044 workloadFactory.Finalize();
telsoa014fcda012018-03-09 14:13:49 +000045 workload->Execute();
46
47 CopyDataFromITensorHandle(&result.output[0][0], outputHandle.get());
48
49 return result;
50}
51
52LayerTestResult<float, 2> FullyConnectedFloat32Test(armnn::IWorkloadFactory& workloadFactory, bool biasEnabled,
53 bool transposeWeights)
54{
55 unsigned int inputWidth = 1;
56 unsigned int inputHeight = 1;
57 unsigned int inputChannels = 5;
58 unsigned int inputNum = 2;
59
60 unsigned int outputChannels = 3;
61 unsigned int outputNum = 2;
62
telsoa01c577f2c2018-08-31 09:22:23 +010063 // Define the tensor descriptors.
telsoa014fcda012018-03-09 14:13:49 +000064 armnn::TensorInfo inputTensorInfo;
65 armnn::TensorInfo outputTensorInfo;
66 armnn::TensorInfo weightsDesc;
67 armnn::TensorInfo biasesDesc;
68
69 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
70 unsigned int outputShape[] = { outputNum, outputChannels };
71 unsigned int weightsShape[] = { inputChannels, outputChannels };
72 if (transposeWeights)
73 {
74 std::swap(weightsShape[0], weightsShape[1]);
75 }
76 unsigned int biasShape[] = { outputChannels };
77
78 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
79 outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32);
80 weightsDesc = armnn::TensorInfo(2, weightsShape, armnn::DataType::Float32);
81 biasesDesc = armnn::TensorInfo(1, biasShape, armnn::DataType::Float32);
82
83 LayerTestResult<float, 2> result(outputTensorInfo);
84
85 boost::multi_array<float, 4> input = MakeTensor<float, 4>(inputTensorInfo, std::vector<float>(
86 {
87 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
88
89 5.0f, 4.0f, 3.0f, 2.0f, 1.0f
90 })
91 );
92
93 boost::multi_array<float, 2> weights = MakeTensor<float, 2>(weightsDesc, std::vector<float>(
94 {
95 .5f, 2.f, .5f,
96 .5f, 2.f, 1.f,
97 .5f, 2.f, 2.f,
98 .5f, 2.f, 3.f,
99 .5f, 2.f, 4.f
100 }));
101
102 if (transposeWeights)
103 {
104 weights = MakeTensor<float, 2>(weightsDesc, std::vector<float>(
105 {
106 .5f, .5f, .5f, .5f, .5f,
107 2.f, 2.f, 2.f, 2.f, 2.f,
108 .5f, 1.f, 2.f, 3.f, 4.f
109 }));
110 }
111
112
113 std::vector<float> biasValues({0.f, 0.f, 0.f});
114 if (biasEnabled)
115 {
116 biasValues = std::vector<float>({10.f, 20.f, 30.f});
117 }
118 boost::multi_array<float, 1> bias = MakeTensor<float, 1>(biasesDesc, biasValues);
119
120 result = SimpleFullyConnectedTestImpl<float>(
121 workloadFactory,
122 inputTensorInfo, outputTensorInfo,
123 weightsDesc, biasesDesc,
124 weights, bias, input,
125 biasEnabled, transposeWeights
126 );
127
128 result.outputExpected = MakeTensor<float, 2>(outputTensorInfo, std::vector<float>(
129 {
130 0.5f + 1.0f + 1.5f + 2.0f + 2.5f + biasValues[0],
131 2.0f + 4.0f + 6.0f + 8.0f + 10.f + biasValues[1],
132 0.5f + 2.0f + 6.0f + 12.f + 20.f + biasValues[2],
133
134 2.5f + 2.0f + 1.5f + 1.0f + 0.5f + biasValues[0],
135 10.0f + 8.0f + 6.0f + 4.0f + 2.f + biasValues[1],
136 2.5f + 4.0f + 6.0f + 6.f + 4.f + biasValues[2]
137 })
138 );
139
140 return result;
141}
142
143LayerTestResult<uint8_t, 2> FullyConnectedUint8Test(armnn::IWorkloadFactory& workloadFactory, bool biasEnabled)
144{
145 constexpr static unsigned int inputWidth = 3u;
146 constexpr static unsigned int inputHeight = 2u;
147 constexpr static unsigned int inputChannels = 1u;
148
149 constexpr static unsigned int inputSize = inputWidth * inputHeight * inputChannels;
150
151 constexpr static unsigned int outputChannels = 2u;
152
153 armnn::TensorInfo inputTensorInfo({ 1, inputChannels, inputHeight, inputWidth }, armnn::DataType::QuantisedAsymm8);
154 inputTensorInfo.SetQuantizationScale(0.1f);
155 inputTensorInfo.SetQuantizationOffset(63);
156
157 armnn::TensorInfo outputTensorInfo({ 1, outputChannels }, armnn::DataType::QuantisedAsymm8);
158 outputTensorInfo.SetQuantizationScale(5.f);
159 outputTensorInfo.SetQuantizationOffset(biasEnabled ? -50 : 10);
160
161 armnn::TensorInfo weightsDesc({ outputChannels, inputSize }, armnn::DataType::QuantisedAsymm8);
162 weightsDesc.SetQuantizationScale(0.2f);
163 weightsDesc.SetQuantizationOffset(93);
164
165 armnn::TensorInfo biasesDesc({ outputChannels }, armnn::DataType::Signed32);
166 biasesDesc.SetQuantizationScale(inputTensorInfo.GetQuantizationScale() * weightsDesc.GetQuantizationScale());
167 biasesDesc.SetQuantizationOffset(0);
168
169 LayerTestResult<uint8_t, 2> result(outputTensorInfo);
170
171 auto input = MakeTensor<uint8_t, 4>(inputTensorInfo, std::vector<uint8_t>{51, 124, 28,
172 251, 8, 92});
173
174 auto weights = MakeTensor<uint8_t, 2>(weightsDesc, std::vector<uint8_t>{51, 193, 42, 53, 175, 34,
175 210, 145, 23, 74, 34, 150});
176
177 // scale = 0.02
178 // offset = 0
179 auto bias = MakeTensor<int32_t, 1>(biasesDesc, std::vector<int32_t>{9250, 67500});
180
181 result = SimpleFullyConnectedTestImpl<uint8_t>(
182 workloadFactory,
183 inputTensorInfo, outputTensorInfo,
184 weightsDesc, biasesDesc,
185 weights, bias, input,
186 biasEnabled, true
187 );
188
telsoa01c577f2c2018-08-31 09:22:23 +0100189 // Manually calculated.
190 // Note one of these values has been clamped to 0.
telsoa014fcda012018-03-09 14:13:49 +0000191 if (biasEnabled)
192 {
193 result.outputExpected = MakeTensor<uint8_t, 2>(outputTensorInfo, std::vector<uint8_t>{0, 242});
194 }
195 else
196 {
197 result.outputExpected = MakeTensor<uint8_t, 2>(outputTensorInfo, std::vector<uint8_t>{0, 32});
198 }
199
200 return result;
201}
202
203
204
205//
206// ArmNN variant of the AndroidNN fully_connected_float_large test.
207//
208// Tests the fully connected layer with large values, optionally transposing weights.
209// Note this is templated for consistency, but the nature of this tests makes it unlikely to be useful in Uint8 mode.
210//
211template<typename T>
212LayerTestResult<T, 2> FullyConnectedLargeTestCommon(armnn::IWorkloadFactory& workloadFactory,
213 bool transposeWeights,
214 float qScale = 0.0f,
215 int32_t qOffset = 0)
216{
217 unsigned int inputWidth = 1;
218 unsigned int inputHeight = 1;
219 unsigned int inputChannels = 5;
220 unsigned int inputNum = 1;
221
222 unsigned int outputChannels = 1;
223 unsigned int outputNum = 1;
224
telsoa01c577f2c2018-08-31 09:22:23 +0100225 // Define the tensor descriptors.
telsoa014fcda012018-03-09 14:13:49 +0000226 armnn::TensorInfo inputTensorInfo;
227 armnn::TensorInfo outputTensorInfo;
228 armnn::TensorInfo weightsDesc;
229 armnn::TensorInfo biasesDesc;
230
231 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
232 unsigned int outputShape[] = { outputNum, outputChannels };
233 unsigned int weightsShape[] = { inputChannels, outputChannels };
234 if (transposeWeights)
235 {
236 std::swap(weightsShape[0], weightsShape[1]);
237 }
238
239 unsigned int biasShape[] = { outputChannels };
240
241 inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::GetDataType<T>());
242 outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::GetDataType<T>());
243 weightsDesc = armnn::TensorInfo(2, weightsShape, armnn::GetDataType<T>());
244 biasesDesc = armnn::TensorInfo(1, biasShape, armnn::GetDataType<T>());
245
246 // Set quantization parameters if the requested type is a quantized type.
247 if(armnn::IsQuantizedType<T>())
248 {
249 inputTensorInfo.SetQuantizationScale(qScale);
250 inputTensorInfo.SetQuantizationOffset(qOffset);
251 outputTensorInfo.SetQuantizationScale(qScale);
252 outputTensorInfo.SetQuantizationOffset(qOffset);
253 }
254
255 LayerTestResult<T, 2> result(outputTensorInfo);
256
257 boost::multi_array<T, 4> input = MakeTensor<T, 4>(inputTensorInfo,
258 QuantizedVector<T>(qScale, qOffset, {
259 1.0f, 10.0f, 100.0f, 1000.0f, 10000.0f,
260 })
261 );
262
263 boost::multi_array<T, 2> weights = MakeTensor<T, 2>(weightsDesc,
264 QuantizedVector<T>(qScale, qOffset, {
265 2.0f, 3.0f, 4.0f, 5.0f, 6.0f
266 })
267 );
268
269 std::vector<T> biasValues({900000.f});
270 boost::multi_array<T, 1> bias = MakeTensor<T, 1>(biasesDesc, biasValues);
271
272 result = SimpleFullyConnectedTestImpl<T>(
273 workloadFactory,
274 inputTensorInfo, outputTensorInfo,
275 weightsDesc, biasesDesc,
276 weights, bias, input,
277 true, transposeWeights
278 );
279
280 result.outputExpected = MakeTensor<T, 2>(outputTensorInfo,
281 QuantizedVector<T>(qScale, qOffset, {
282 965432.0f,
283 })
284 );
285
286 return result;
287}