blob: af6b56852a7486caa86b4b4d41ced5e8e31c7e2b [file] [log] [blame]
Sadik Armaganf0a6dec2021-03-25 07:46:55 +00001//
2// Copyright © 2021 Arm Ltd and Contributors. All rights reserved.
3// SPDX-License-Identifier: MIT
4//
5#pragma once
6
7#include "CommonTestUtils.hpp"
8
9#include <ResolveType.hpp>
10
11#include <armnn/INetwork.hpp>
12
13#include <armnn/utility/NumericCast.hpp>
14
Sadik Armagan1625efc2021-06-10 18:24:34 +010015#include <doctest/doctest.h>
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000016
17#include <vector>
18
19namespace
20{
21
22armnn::INetworkPtr CreateFullyConnectedNetworkNonConstWeights(const armnn::TensorInfo& inputTensorInfo,
23 const armnn::TensorInfo& outputTensorInfo,
24 const armnn::TensorInfo& weightsTensorInfo,
25 armnn::FullyConnectedDescriptor descriptor)
26{
27 armnn::INetworkPtr network(armnn::INetwork::Create());
28
29 armnn::IConnectableLayer* inputLayer = network->AddInputLayer(0, "Input");
30 armnn::IConnectableLayer* weightsInputLayer = network->AddInputLayer(1, "Weights_Input");
Matthew Sloyan81beae32021-07-13 19:46:11 +010031 armnn::IConnectableLayer* fullyConnectedLayer = network->AddFullyConnectedLayer(descriptor, "Fully_Connected");
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000032 armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0, "Output");
33
34 Connect(inputLayer, fullyConnectedLayer, inputTensorInfo, 0, 0);
35 Connect(weightsInputLayer, fullyConnectedLayer, weightsTensorInfo, 0, 1);
36 Connect(fullyConnectedLayer, outputLayer, outputTensorInfo, 0, 0);
37
38 return network;
39}
40
Matthew Sloyan81beae32021-07-13 19:46:11 +010041armnn::INetworkPtr CreateFullyConnectedNetworkNonConstWeightsConstBias(const armnn::TensorInfo& inputTensorInfo,
42 const armnn::TensorInfo& outputTensorInfo,
43 const armnn::TensorInfo& weightsTensorInfo,
44 const armnn::TensorInfo& biasTensorInfo,
45 const armnn::ConstTensor& biasConstantTensor,
46 armnn::FullyConnectedDescriptor descriptor)
47{
48 armnn::INetworkPtr network(armnn::INetwork::Create());
49
50 armnn::IConnectableLayer* inputLayer = network->AddInputLayer(0, "Input");
51 armnn::IConnectableLayer* weightsInputLayer = network->AddInputLayer(1, "Weights_Input");
52 armnn::IConnectableLayer* biasLayer = network->AddConstantLayer(biasConstantTensor, "Weights");
53 armnn::IConnectableLayer* fullyConnectedLayer = network->AddFullyConnectedLayer(descriptor, "Fully_Connected");
54 armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0, "Output");
55
56 Connect(inputLayer, fullyConnectedLayer, inputTensorInfo, 0, 0);
57 Connect(weightsInputLayer, fullyConnectedLayer, weightsTensorInfo, 0, 1);
58 Connect(biasLayer, fullyConnectedLayer, biasTensorInfo, 0, 2);
59 Connect(fullyConnectedLayer, outputLayer, outputTensorInfo, 0, 0);
60
61 return network;
62}
63
64armnn::INetworkPtr CreateFullyConnectedNetworkConstWeightsNonConstBias(const armnn::TensorInfo& inputTensorInfo,
65 const armnn::TensorInfo& outputTensorInfo,
66 const armnn::TensorInfo& weightsTensorInfo,
67 const armnn::TensorInfo& biasTensorInfo,
68 const armnn::ConstTensor& weightsConstantTensor,
69 armnn::FullyConnectedDescriptor descriptor)
70{
71 armnn::INetworkPtr network(armnn::INetwork::Create());
72
73 armnn::IConnectableLayer* inputLayer = network->AddInputLayer(0, "Input");
74 armnn::IConnectableLayer* weightsLayer = network->AddConstantLayer(weightsConstantTensor, "Weights");
75 armnn::IConnectableLayer* biasLayer = network->AddInputLayer(2, "Bias_Input");
76 armnn::IConnectableLayer* fullyConnectedLayer = network->AddFullyConnectedLayer(descriptor, "Fully_Connected");
77 armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0, "Output");
78
79 Connect(inputLayer, fullyConnectedLayer, inputTensorInfo, 0, 0);
80 Connect(weightsLayer, fullyConnectedLayer, weightsTensorInfo, 0, 1);
81 Connect(biasLayer, fullyConnectedLayer, biasTensorInfo, 0, 2);
82 Connect(fullyConnectedLayer, outputLayer, outputTensorInfo, 0, 0);
83
84 return network;
85}
86
Sadik Armaganf0a6dec2021-03-25 07:46:55 +000087template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
88void FullyConnectedWithDynamicWeightsEndToEnd(const std::vector<armnn::BackendId>& backends)
89{
90 using namespace armnn;
91
92 armnn::TensorInfo inputTensorInfo({ 1, 1, 2, 3 }, ArmnnType);
93 inputTensorInfo.SetQuantizationScale(0.1f);
94 inputTensorInfo.SetQuantizationOffset(63);
95
96 armnn::TensorInfo outputTensorInfo({ 1, 2 }, ArmnnType);
97 outputTensorInfo.SetQuantizationScale(5.f);
98 outputTensorInfo.SetQuantizationOffset(10);
99
100 armnn::TensorInfo weightsTensorInfo({ 2, 6 }, ArmnnType);
101 weightsTensorInfo.SetQuantizationScale(0.2f);
102 weightsTensorInfo.SetQuantizationOffset(93);
103
104 FullyConnectedDescriptor descriptor;
105 descriptor.m_ConstantWeights = false;
106 descriptor.m_BiasEnabled = false;
107 descriptor.m_TransposeWeightMatrix = true;
108
109 std::vector<T> inputData {
110 -1.2f, 6.1f, -3.5f,
111 18.8f, -5.5f, 2.9f
112 };
113
114 std::vector<T> weightsData {
115 -8.4f, 20.0f, -10.4f, -8, 16.4f, -11.8f,
116 23.4f, 10.4f, -14.0f, -3.8f, -11.8f, 11.4f
117 };
118
119 std::vector<T> floatExpectedOutputData {
120 -107.04f, 110.f
121 };
122 std::vector<T> expectedOutputData = armnnUtils::QuantizedVector<T>(floatExpectedOutputData);
123
124 armnn::INetworkPtr network = CreateFullyConnectedNetworkNonConstWeights(inputTensorInfo,
125 outputTensorInfo,
126 weightsTensorInfo,
127 descriptor);
128
Sadik Armagan1625efc2021-06-10 18:24:34 +0100129 CHECK(network);
Sadik Armaganf0a6dec2021-03-25 07:46:55 +0000130
131 std::map<int, std::vector<T>> inputTensorData = {{ 0, inputData }, {1, weightsData}};
132 std::map<int, std::vector<T>> expectedOutputTensorData = {{ 0, expectedOutputData }};
133
134 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(network),
135 inputTensorData,
136 expectedOutputTensorData,
137 backends,
138 1.0f);
139}
Matthew Sloyan81beae32021-07-13 19:46:11 +0100140
141template<armnn::DataType ArmnnType, typename T = armnn::ResolveType<ArmnnType>>
142void FullyConnectedWithDynamicOrConstantInputsEndToEnd(const std::vector<armnn::BackendId>& backends,
143 const bool transposeWeights,
144 const bool constantWeightsOrBias)
145{
146 unsigned int inputWidth = 1;
147 unsigned int inputHeight = 1;
148 unsigned int inputChannels = 5;
149 unsigned int inputNum = 2;
150
151 unsigned int outputChannels = 3;
152 unsigned int outputNum = 2;
153
154 unsigned int inputShape[] = { inputNum, inputChannels, inputHeight, inputWidth };
155 unsigned int outputShape[] = { outputNum, outputChannels };
156 unsigned int weightsShape[] = { inputChannels, outputChannels };
157
158 if (transposeWeights)
159 {
160 std::swap(weightsShape[0], weightsShape[1]);
161 }
162
163 unsigned int biasShape[] = { outputChannels };
164
165 armnn::TensorInfo inputTensorInfo = armnn::TensorInfo(4, inputShape, armnn::DataType::Float32);
166 armnn::TensorInfo outputTensorInfo = armnn::TensorInfo(2, outputShape, armnn::DataType::Float32);
167 armnn::TensorInfo weightsDesc = armnn::TensorInfo(2, weightsShape, armnn::DataType::Float32);
168 armnn::TensorInfo biasesDesc = armnn::TensorInfo(1, biasShape, armnn::DataType::Float32);
169
170 std::vector<float> input =
171 {
172 1.0f, 2.0f, 3.0f, 4.0f, 5.0f,
173 5.0f, 4.0f, 3.0f, 2.0f, 1.0f
174 };
175
176 std::vector<float> weights =
177 {
178 .5f, 2.f, .5f,
179 .5f, 2.f, 1.f,
180 .5f, 2.f, 2.f,
181 .5f, 2.f, 3.f,
182 .5f, 2.f, 4.f
183 };
184
185 if (transposeWeights)
186 {
187 weights =
188 {
189 .5f, .5f, .5f, .5f, .5f,
190 2.f, 2.f, 2.f, 2.f, 2.f,
191 .5f, 1.f, 2.f, 3.f, 4.f
192 };
193 }
194
195 std::vector<float> biasValues = std::vector<float>({10.f, 20.f, 30.f});
196
197 std::vector<float> expectedOutput =
198 {
199 0.5f + 1.0f + 1.5f + 2.0f + 2.5f + biasValues[0],
200 2.0f + 4.0f + 6.0f + 8.0f + 10.f + biasValues[1],
201 0.5f + 2.0f + 6.0f + 12.f + 20.f + biasValues[2],
202
203 2.5f + 2.0f + 1.5f + 1.0f + 0.5f + biasValues[0],
204 10.0f + 8.0f + 6.0f + 4.0f + 2.f + biasValues[1],
205 2.5f + 4.0f + 6.0f + 6.f + 4.f + biasValues[2]
206 };
207
208 FullyConnectedDescriptor descriptor;
209 descriptor.m_BiasEnabled = true;
210 descriptor.m_TransposeWeightMatrix = transposeWeights;
211 descriptor.m_ConstantWeights = constantWeightsOrBias;
212
213 if (!constantWeightsOrBias)
214 {
215 // Tests non constant weights and constant bias.
216 ConstTensor biasConstantTensor(biasesDesc, biasValues.data());
217
218 armnn::INetworkPtr network = CreateFullyConnectedNetworkNonConstWeightsConstBias(inputTensorInfo,
219 outputTensorInfo,
220 weightsDesc,
221 biasesDesc,
222 biasConstantTensor,
223 descriptor);
224 CHECK(network);
225
226 std::map<int, std::vector<T>> inputTensorData = {{ 0, input }, {1, weights}};
227 std::map<int, std::vector<T>> expectedOutputTensorData = {{ 0, expectedOutput }};
228
229 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(network),
230 inputTensorData,
231 expectedOutputTensorData,
232 backends,
233 1.0f);
234 }
235 else
236 {
237 // Tests constant weights and non constant bias.
238 ConstTensor weightsConstantTensor(weightsDesc, weights.data());
239
240 armnn::INetworkPtr network = CreateFullyConnectedNetworkConstWeightsNonConstBias(inputTensorInfo,
241 outputTensorInfo,
242 weightsDesc,
243 biasesDesc,
244 weightsConstantTensor,
245 descriptor);
246 CHECK(network);
247
248 std::map<int, std::vector<T>> inputTensorData = {{ 0, input }, {2, biasValues}};
249 std::map<int, std::vector<T>> expectedOutputTensorData = {{ 0, expectedOutput }};
250
251 EndToEndLayerTestImpl<ArmnnType, ArmnnType>(move(network),
252 inputTensorData,
253 expectedOutputTensorData,
254 backends,
255 1.0f);
256 }
257}
258
Sadik Armaganf0a6dec2021-03-25 07:46:55 +0000259} // anonymous namespace