1 // 2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved. 3 // SPDX-License-Identifier: MIT 4 // 5 6 #include "DriverTestHelpers.hpp" 7 8 #include <log/log.h> 9 10 DOCTEST_TEST_SUITE("FullyConnectedTests") 11 { 12 using namespace android::hardware; 13 using namespace driverTestHelpers; 14 using namespace armnn_driver; 15 16 using HalPolicy = hal_1_0::HalPolicy; 17 18 // Add our own test here since we fail the fc tests which Google supplies (because of non-const weights) 19 DOCTEST_TEST_CASE("FullyConnected") 20 { 21 // this should ideally replicate fully_connected_float.model.cpp 22 // but that uses slightly weird dimensions which I don't think we need to support for now 23 24 auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); 25 HalPolicy::Model model = {}; 26 27 // add operands 28 int32_t actValue = 0; 29 float weightValue[] = {2, 4, 1}; 30 float biasValue[] = {4}; 31 32 AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 3}); 33 AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 3}, weightValue); 34 AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{1}, biasValue); 35 AddIntOperand<HalPolicy>(model, actValue); 36 AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 1}); 37 38 // make the fully connected operation 39 model.operations.resize(1); 40 model.operations[0].type = HalPolicy::OperationType::FULLY_CONNECTED; 41 model.operations[0].inputs = hidl_vec<uint32_t>{0, 1, 2, 3}; 42 model.operations[0].outputs = hidl_vec<uint32_t>{4}; 43 44 // make the prepared model 45 android::sp<V1_0::IPreparedModel> preparedModel = PrepareModel(model, *driver); 46 47 // construct the request 48 V1_0::DataLocation inloc = {}; 49 inloc.poolIndex = 0; 50 inloc.offset = 0; 51 inloc.length = 3 * sizeof(float); 52 RequestArgument input = {}; 53 input.location = inloc; 54 input.dimensions = hidl_vec<uint32_t>{}; 55 56 V1_0::DataLocation outloc = {}; 57 outloc.poolIndex = 1; 58 outloc.offset = 0; 59 outloc.length = 1 * sizeof(float); 60 RequestArgument output = {}; 61 output.location = outloc; 62 output.dimensions = hidl_vec<uint32_t>{}; 63 64 V1_0::Request request = {}; 65 request.inputs = hidl_vec<RequestArgument>{input}; 66 request.outputs = hidl_vec<RequestArgument>{output}; 67 68 // set the input data (matching source test) 69 float indata[] = {2, 32, 16}; 70 AddPoolAndSetData<float>(3, request, indata); 71 72 // add memory for the output 73 android::sp<IMemory> outMemory = AddPoolAndGetData<float>(1, request); 74 float* outdata = static_cast<float*>(static_cast<void*>(outMemory->getPointer())); 75 76 // run the execution 77 if (preparedModel.get() != nullptr) 78 { 79 Execute(preparedModel, request); 80 } 81 82 // check the result 83 DOCTEST_CHECK(outdata[0] == 152); 84 } 85 86 DOCTEST_TEST_CASE("TestFullyConnected4dInput") 87 { 88 auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); 89 90 V1_0::ErrorStatus error; 91 std::vector<bool> sup; 92 93 ArmnnDriver::getSupportedOperations_cb cb = [&](V1_0::ErrorStatus status, const std::vector<bool>& supported) __anon493742780102(V1_0::ErrorStatus status, const std::vector<bool>& supported) 94 { 95 error = status; 96 sup = supported; 97 }; 98 99 HalPolicy::Model model = {}; 100 101 // operands 102 int32_t actValue = 0; 103 float weightValue[] = {1, 0, 0, 0, 0, 0, 0, 0, 104 0, 1, 0, 0, 0, 0, 0, 0, 105 0, 0, 1, 0, 0, 0, 0, 0, 106 0, 0, 0, 1, 0, 0, 0, 0, 107 0, 0, 0, 0, 1, 0, 0, 0, 108 0, 0, 0, 0, 0, 1, 0, 0, 109 0, 0, 0, 0, 0, 0, 1, 0, 110 0, 0, 0, 0, 0, 0, 0, 1}; //identity 111 float biasValue[] = {0, 0, 0, 0, 0, 0, 0, 0}; 112 113 // fully connected operation 114 AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 1, 1, 8}); 115 AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{8, 8}, weightValue); 116 AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{8}, biasValue); 117 AddIntOperand<HalPolicy>(model, actValue); 118 AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 8}); 119 120 model.operations.resize(1); 121 122 model.operations[0].type = HalPolicy::OperationType::FULLY_CONNECTED; 123 model.operations[0].inputs = hidl_vec<uint32_t>{0,1,2,3}; 124 model.operations[0].outputs = hidl_vec<uint32_t>{4}; 125 126 // make the prepared model 127 android::sp<V1_0::IPreparedModel> preparedModel = PrepareModel(model, *driver); 128 129 // construct the request 130 V1_0::DataLocation inloc = {}; 131 inloc.poolIndex = 0; 132 inloc.offset = 0; 133 inloc.length = 8 * sizeof(float); 134 RequestArgument input = {}; 135 input.location = inloc; 136 input.dimensions = hidl_vec<uint32_t>{}; 137 138 V1_0::DataLocation outloc = {}; 139 outloc.poolIndex = 1; 140 outloc.offset = 0; 141 outloc.length = 8 * sizeof(float); 142 RequestArgument output = {}; 143 output.location = outloc; 144 output.dimensions = hidl_vec<uint32_t>{}; 145 146 V1_0::Request request = {}; 147 request.inputs = hidl_vec<RequestArgument>{input}; 148 request.outputs = hidl_vec<RequestArgument>{output}; 149 150 // set the input data 151 float indata[] = {1,2,3,4,5,6,7,8}; 152 AddPoolAndSetData(8, request, indata); 153 154 // add memory for the output 155 android::sp<IMemory> outMemory = AddPoolAndGetData<float>(8, request); 156 float* outdata = static_cast<float*>(static_cast<void*>(outMemory->getPointer())); 157 158 // run the execution 159 if (preparedModel != nullptr) 160 { 161 Execute(preparedModel, request); 162 } 163 164 // check the result 165 DOCTEST_CHECK(outdata[0] == 1); 166 DOCTEST_CHECK(outdata[1] == 2); 167 DOCTEST_CHECK(outdata[2] == 3); 168 DOCTEST_CHECK(outdata[3] == 4); 169 DOCTEST_CHECK(outdata[4] == 5); 170 DOCTEST_CHECK(outdata[5] == 6); 171 DOCTEST_CHECK(outdata[6] == 7); 172 DOCTEST_CHECK(outdata[7] == 8); 173 } 174 175 DOCTEST_TEST_CASE("TestFullyConnected4dInputReshape") 176 { 177 auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); 178 179 V1_0::ErrorStatus error; 180 std::vector<bool> sup; 181 182 ArmnnDriver::getSupportedOperations_cb cb = [&](V1_0::ErrorStatus status, const std::vector<bool>& supported) __anon493742780202(V1_0::ErrorStatus status, const std::vector<bool>& supported) 183 { 184 error = status; 185 sup = supported; 186 }; 187 188 HalPolicy::Model model = {}; 189 190 // operands 191 int32_t actValue = 0; 192 float weightValue[] = {1, 0, 0, 0, 0, 0, 0, 0, 193 0, 1, 0, 0, 0, 0, 0, 0, 194 0, 0, 1, 0, 0, 0, 0, 0, 195 0, 0, 0, 1, 0, 0, 0, 0, 196 0, 0, 0, 0, 1, 0, 0, 0, 197 0, 0, 0, 0, 0, 1, 0, 0, 198 0, 0, 0, 0, 0, 0, 1, 0, 199 0, 0, 0, 0, 0, 0, 0, 1}; //identity 200 float biasValue[] = {0, 0, 0, 0, 0, 0, 0, 0}; 201 202 // fully connected operation 203 AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 2, 2, 2}); 204 AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{8, 8}, weightValue); 205 AddTensorOperand<HalPolicy>(model, hidl_vec<uint32_t>{8}, biasValue); 206 AddIntOperand<HalPolicy>(model, actValue); 207 AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 8}); 208 209 model.operations.resize(1); 210 211 model.operations[0].type = HalPolicy::OperationType::FULLY_CONNECTED; 212 model.operations[0].inputs = hidl_vec<uint32_t>{0,1,2,3}; 213 model.operations[0].outputs = hidl_vec<uint32_t>{4}; 214 215 // make the prepared model 216 android::sp<V1_0::IPreparedModel> preparedModel = PrepareModel(model, *driver); 217 218 // construct the request 219 V1_0::DataLocation inloc = {}; 220 inloc.poolIndex = 0; 221 inloc.offset = 0; 222 inloc.length = 8 * sizeof(float); 223 RequestArgument input = {}; 224 input.location = inloc; 225 input.dimensions = hidl_vec<uint32_t>{}; 226 227 V1_0::DataLocation outloc = {}; 228 outloc.poolIndex = 1; 229 outloc.offset = 0; 230 outloc.length = 8 * sizeof(float); 231 RequestArgument output = {}; 232 output.location = outloc; 233 output.dimensions = hidl_vec<uint32_t>{}; 234 235 V1_0::Request request = {}; 236 request.inputs = hidl_vec<RequestArgument>{input}; 237 request.outputs = hidl_vec<RequestArgument>{output}; 238 239 // set the input data 240 float indata[] = {1,2,3,4,5,6,7,8}; 241 AddPoolAndSetData(8, request, indata); 242 243 // add memory for the output 244 android::sp<IMemory> outMemory = AddPoolAndGetData<float>(8, request); 245 float* outdata = static_cast<float*>(static_cast<void*>(outMemory->getPointer())); 246 247 // run the execution 248 if (preparedModel != nullptr) 249 { 250 Execute(preparedModel, request); 251 } 252 253 // check the result 254 DOCTEST_CHECK(outdata[0] == 1); 255 DOCTEST_CHECK(outdata[1] == 2); 256 DOCTEST_CHECK(outdata[2] == 3); 257 DOCTEST_CHECK(outdata[3] == 4); 258 DOCTEST_CHECK(outdata[4] == 5); 259 DOCTEST_CHECK(outdata[5] == 6); 260 DOCTEST_CHECK(outdata[6] == 7); 261 DOCTEST_CHECK(outdata[7] == 8); 262 } 263 264 DOCTEST_TEST_CASE("TestFullyConnectedWeightsAsInput") 265 { 266 auto driver = std::make_unique<ArmnnDriver>(DriverOptions(armnn::Compute::CpuRef)); 267 268 V1_0::ErrorStatus error; 269 std::vector<bool> sup; 270 271 ArmnnDriver::getSupportedOperations_cb cb = [&](V1_0::ErrorStatus status, const std::vector<bool>& supported) __anon493742780302(V1_0::ErrorStatus status, const std::vector<bool>& supported) 272 { 273 error = status; 274 sup = supported; 275 }; 276 277 HalPolicy::Model model = {}; 278 279 // operands 280 int32_t actValue = 0; 281 float weightValue[] = {1, 0, 0, 0, 0, 0, 0, 0, 282 0, 1, 0, 0, 0, 0, 0, 0, 283 0, 0, 1, 0, 0, 0, 0, 0, 284 0, 0, 0, 1, 0, 0, 0, 0, 285 0, 0, 0, 0, 1, 0, 0, 0, 286 0, 0, 0, 0, 0, 1, 0, 0, 287 0, 0, 0, 0, 0, 0, 1, 0, 288 0, 0, 0, 0, 0, 0, 0, 1}; //identity 289 float biasValue[] = {0, 0, 0, 0, 0, 0, 0, 0}; 290 291 // fully connected operation 292 AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 1, 1, 8}); 293 AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{8, 8}); 294 AddInputOperand<HalPolicy>(model, hidl_vec<uint32_t>{8}); 295 AddIntOperand<HalPolicy>(model, actValue); 296 AddOutputOperand<HalPolicy>(model, hidl_vec<uint32_t>{1, 8}); 297 298 model.operations.resize(1); 299 300 model.operations[0].type = HalPolicy::OperationType::FULLY_CONNECTED; 301 model.operations[0].inputs = hidl_vec<uint32_t>{0,1,2,3}; 302 model.operations[0].outputs = hidl_vec<uint32_t>{4}; 303 304 // make the prepared model 305 android::sp<V1_0::IPreparedModel> preparedModel = PrepareModel(model, *driver); 306 307 // construct the request for input 308 V1_0::DataLocation inloc = {}; 309 inloc.poolIndex = 0; 310 inloc.offset = 0; 311 inloc.length = 8 * sizeof(float); 312 RequestArgument input = {}; 313 input.location = inloc; 314 input.dimensions = hidl_vec<uint32_t>{1, 1, 1, 8}; 315 316 // construct the request for weights as input 317 V1_0::DataLocation wloc = {}; 318 wloc.poolIndex = 1; 319 wloc.offset = 0; 320 wloc.length = 64 * sizeof(float); 321 RequestArgument weights = {}; 322 weights.location = wloc; 323 weights.dimensions = hidl_vec<uint32_t>{8, 8}; 324 325 // construct the request for bias as input 326 V1_0::DataLocation bloc = {}; 327 bloc.poolIndex = 2; 328 bloc.offset = 0; 329 bloc.length = 8 * sizeof(float); 330 RequestArgument bias = {}; 331 bias.location = bloc; 332 bias.dimensions = hidl_vec<uint32_t>{8}; 333 334 V1_0::DataLocation outloc = {}; 335 outloc.poolIndex = 3; 336 outloc.offset = 0; 337 outloc.length = 8 * sizeof(float); 338 RequestArgument output = {}; 339 output.location = outloc; 340 output.dimensions = hidl_vec<uint32_t>{1, 8}; 341 342 V1_0::Request request = {}; 343 request.inputs = hidl_vec<RequestArgument>{input, weights, bias}; 344 request.outputs = hidl_vec<RequestArgument>{output}; 345 346 // set the input data 347 float indata[] = {1,2,3,4,5,6,7,8}; 348 AddPoolAndSetData(8, request, indata); 349 350 // set the weights data 351 AddPoolAndSetData(64, request, weightValue); 352 // set the bias data 353 AddPoolAndSetData(8, request, biasValue); 354 355 // add memory for the output 356 android::sp<IMemory> outMemory = AddPoolAndGetData<float>(8, request); 357 float* outdata = static_cast<float*>(static_cast<void*>(outMemory->getPointer())); 358 359 // run the execution 360 if (preparedModel != nullptr) 361 { 362 Execute(preparedModel, request); 363 } 364 365 // check the result 366 DOCTEST_CHECK(outdata[0] == 1); 367 DOCTEST_CHECK(outdata[1] == 2); 368 DOCTEST_CHECK(outdata[2] == 3); 369 DOCTEST_CHECK(outdata[3] == 4); 370 DOCTEST_CHECK(outdata[4] == 5); 371 DOCTEST_CHECK(outdata[5] == 6); 372 DOCTEST_CHECK(outdata[6] == 7); 373 DOCTEST_CHECK(outdata[7] == 8); 374 } 375 376 } 377