1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #define LOG_TAG "Utils" 18 19 #include "Utils.h" 20 #include "NeuralNetworks.h" 21 #include "NeuralNetworksOEM.h" 22 23 #include <android-base/logging.h> 24 #include <android-base/properties.h> 25 #include <android-base/strings.h> 26 #include <sys/system_properties.h> 27 #include <unordered_map> 28 29 using ::android::hidl::allocator::V1_0::IAllocator; 30 31 namespace android { 32 namespace nn { 33 34 const char kVLogPropKey[] = "debug.nn.vlog"; 35 int vLogMask = ~0; 36 37 // Split the space separated list of tags from verbose log setting and build the 38 // logging mask from it. note that '1' and 'all' are special cases to enable all 39 // verbose logging. 40 // 41 // NN API verbose logging setting comes from system property debug.nn.vlog. 42 // Example: 43 // setprop debug.nn.vlog 1 : enable all logging tags. 44 // setprop debug.nn.vlog "model compilation" : only enable logging for MODEL and 45 // COMPILATION tags. 46 void initVLogMask() { 47 vLogMask = 0; 48 const std::string vLogSetting = android::base::GetProperty(kVLogPropKey, ""); 49 if (vLogSetting.empty()) { 50 return; 51 } 52 53 std::unordered_map<std::string, int> vLogFlags = { 54 {"1", -1}, 55 {"all", -1}, 56 {"model", MODEL}, 57 {"compilation", COMPILATION}, 58 {"execution", EXECUTION}, 59 {"cpuexe", CPUEXE}, 60 {"manager", MANAGER}, 61 {"driver", DRIVER}}; 62 63 std::vector<std::string> elements = android::base::Split(vLogSetting, " ,:"); 64 for (const auto& elem : elements) { 65 const auto& flag = vLogFlags.find(elem); 66 if (flag == vLogFlags.end()) { 67 LOG(ERROR) << "Unknown trace flag: " << elem; 68 continue; 69 } 70 71 if (flag->second == -1) { 72 // -1 is used for the special values "1" and "all" that enable all 73 // tracing. 74 vLogMask = ~0; 75 return; 76 } else { 77 vLogMask |= 1 << flag->second; 78 } 79 } 80 } 81 82 namespace { 83 84 template <typename EntryType, uint32_t entryCount, uint32_t entryCountOEM> 85 EntryType tableLookup(const EntryType (&table)[entryCount], 86 const EntryType (&tableOEM)[entryCountOEM], 87 uint32_t code) { 88 if (code < entryCount) { 89 return table[code]; 90 } else if (code >= kOEMCodeBase && (code - kOEMCodeBase) < entryCountOEM) { 91 return tableOEM[code - kOEMCodeBase]; 92 } else { 93 nnAssert(!"tableLookup: bad code"); 94 return EntryType(); 95 } 96 } 97 98 }; // anonymous namespace 99 100 #define COUNT(X) (sizeof(X) / sizeof(X[0])) 101 102 const char* kTypeNames[kNumberOfDataTypes] = { 103 "FLOAT32", "INT32", "UINT32", 104 "TENSOR_FLOAT32", "TENSOR_INT32", "TENSOR_QUANT8_ASYMM", 105 }; 106 107 static_assert(COUNT(kTypeNames) == kNumberOfDataTypes, "kTypeNames is incorrect"); 108 109 const char* kTypeNamesOEM[kNumberOfDataTypesOEM] = { 110 "OEM", "TENSOR_OEM_BYTE", 111 }; 112 113 static_assert(COUNT(kTypeNamesOEM) == kNumberOfDataTypesOEM, "kTypeNamesOEM is incorrect"); 114 115 const char* getOperandTypeName(OperandType type) { 116 uint32_t n = static_cast<uint32_t>(type); 117 return tableLookup(kTypeNames, kTypeNamesOEM, n); 118 } 119 120 // TODO Check if this useful 121 const char* kErrorNames[] = { 122 "NO_ERROR", "OUT_OF_MEMORY", "INCOMPLETE", "NULL", "BAD_DATA", 123 }; 124 125 const char* kOperationNames[kNumberOfOperationTypes] = { 126 "ADD", 127 "AVERAGE_POOL", 128 "CONCATENATION", 129 "CONV", 130 "DEPTHWISE_CONV", 131 "DEPTH_TO_SPACE", 132 "DEQUANTIZE", 133 "EMBEDDING_LOOKUP", 134 "FLOOR", 135 "FULLY_CONNECTED", 136 "HASHTABLE_LOOKUP", 137 "L2_NORMALIZATION", 138 "L2_POOL", 139 "LOCAL_RESPONSE_NORMALIZATION", 140 "LOGISTIC", 141 "LSH_PROJECTION", 142 "LSTM", 143 "MAX_POOL", 144 "MUL", 145 "RELU", 146 "RELU1", 147 "RELU6", 148 "RESHAPE", 149 "RESIZE_BILINEAR", 150 "RNN", 151 "SOFTMAX", 152 "SPACE_TO_DEPTH", 153 "SVDF", 154 "TANH", 155 "BATCH_TO_SPACE_ND", 156 "DIV", 157 "MEAN", 158 "PAD", 159 "SPACE_TO_BATCH_ND", 160 "SQUEEZE", 161 "STRIDED_SLICE", 162 "SUB", 163 "TRANSPOSE", 164 }; 165 166 static_assert(COUNT(kOperationNames) == kNumberOfOperationTypes, "kOperationNames is incorrect"); 167 168 const char* kOperationNamesOEM[kNumberOfOperationTypesOEM] = { 169 "OEM_OPERATION", 170 }; 171 172 static_assert(COUNT(kOperationNamesOEM) == kNumberOfOperationTypesOEM, 173 "kOperationNamesOEM is incorrect"); 174 175 const char* getOperationName(OperationType type) { 176 uint32_t n = static_cast<uint32_t>(type); 177 return tableLookup(kOperationNames, kOperationNamesOEM, n); 178 } 179 180 const uint32_t kSizeOfDataType[]{ 181 4, // ANEURALNETWORKS_FLOAT32 182 4, // ANEURALNETWORKS_INT32 183 4, // ANEURALNETWORKS_UINT32 184 4, // ANEURALNETWORKS_TENSOR_FLOAT32 185 4, // ANEURALNETWORKS_TENSOR_INT32 186 1 // ANEURALNETWORKS_TENSOR_SYMMETRICAL_QUANT8 187 }; 188 189 static_assert(COUNT(kSizeOfDataType) == kNumberOfDataTypes, "kSizeOfDataType is incorrect"); 190 191 const bool kScalarDataType[]{ 192 true, // ANEURALNETWORKS_FLOAT32 193 true, // ANEURALNETWORKS_INT32 194 true, // ANEURALNETWORKS_UINT32 195 false, // ANEURALNETWORKS_TENSOR_FLOAT32 196 false, // ANEURALNETWORKS_TENSOR_INT32 197 false, // ANEURALNETWORKS_TENSOR_SYMMETRICAL_QUANT8 198 }; 199 200 static_assert(COUNT(kScalarDataType) == kNumberOfDataTypes, "kScalarDataType is incorrect"); 201 202 const uint32_t kSizeOfDataTypeOEM[]{ 203 0, // ANEURALNETWORKS_OEM 204 1, // ANEURALNETWORKS_TENSOR_OEM_BYTE 205 }; 206 207 static_assert(COUNT(kSizeOfDataTypeOEM) == kNumberOfDataTypesOEM, 208 "kSizeOfDataTypeOEM is incorrect"); 209 210 const bool kScalarDataTypeOEM[]{ 211 true, // ANEURALNETWORKS_OEM 212 false, // ANEURALNETWORKS_TENSOR_OEM_BYTE 213 }; 214 215 static_assert(COUNT(kScalarDataTypeOEM) == kNumberOfDataTypesOEM, 216 "kScalarDataTypeOEM is incorrect"); 217 218 uint32_t sizeOfData(OperandType type, const std::vector<uint32_t>& dimensions) { 219 int n = static_cast<int>(type); 220 221 uint32_t size = tableLookup(kSizeOfDataType, kSizeOfDataTypeOEM, n); 222 223 if (tableLookup(kScalarDataType, kScalarDataTypeOEM, n) == true) { 224 return size; 225 } 226 227 for (auto d : dimensions) { 228 size *= d; 229 } 230 return size; 231 } 232 233 hidl_memory allocateSharedMemory(int64_t size) { 234 static const std::string type = "ashmem"; 235 static sp<IAllocator> allocator = IAllocator::getService(type); 236 237 hidl_memory memory; 238 239 // TODO: should we align memory size to nearest page? doesn't seem necessary... 240 allocator->allocate(size, [&](bool success, const hidl_memory& mem) { 241 if (!success) { 242 LOG(ERROR) << "unable to allocate " << size << " bytes of " << type; 243 } else { 244 memory = mem; 245 } 246 }); 247 248 return memory; 249 } 250 251 uint32_t alignBytesNeeded(uint32_t index, size_t length) { 252 uint32_t pattern; 253 if (length < 2) { 254 pattern = 0; // No alignment necessary 255 } else if (length < 4) { 256 pattern = 1; // Align on 2-byte boundary 257 } else { 258 pattern = 3; // Align on 4-byte boundary 259 } 260 uint32_t extra = (~(index - 1)) & pattern; 261 return extra; 262 } 263 264 void logModelToInfo(const V1_0::Model& model) { 265 LOG(INFO) << "V1_0::Model start"; 266 LOG(INFO) << "operands" << toString(model.operands); 267 LOG(INFO) << "operations" << toString(model.operations); 268 LOG(INFO) << "inputIndexes" << toString(model.inputIndexes); 269 LOG(INFO) << "outputIndexes" << toString(model.outputIndexes); 270 LOG(INFO) << "operandValues size" << model.operandValues.size(); 271 LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools)); 272 } 273 274 void logModelToInfo(const V1_1::Model& model) { 275 LOG(INFO) << "V1_1::Model start"; 276 LOG(INFO) << "operands" << toString(model.operands); 277 LOG(INFO) << "operations" << toString(model.operations); 278 LOG(INFO) << "inputIndexes" << toString(model.inputIndexes); 279 LOG(INFO) << "outputIndexes" << toString(model.outputIndexes); 280 LOG(INFO) << "operandValues size" << model.operandValues.size(); 281 LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools)); 282 } 283 284 // Validates the type. The used dimensions can be underspecified. 285 int validateOperandType(const ANeuralNetworksOperandType& type, const char* tag, 286 bool allowPartial) { 287 if (!allowPartial) { 288 for (uint32_t i = 0; i < type.dimensionCount; i++) { 289 if (type.dimensions[i] == 0) { 290 LOG(ERROR) << tag << " OperandType invalid dimensions[" << i 291 << "] = " << type.dimensions[i]; 292 return ANEURALNETWORKS_BAD_DATA; 293 } 294 } 295 } 296 if (!validCode(kNumberOfDataTypes, kNumberOfDataTypesOEM, type.type)) { 297 LOG(ERROR) << tag << " OperandType invalid type " << type.type; 298 return ANEURALNETWORKS_BAD_DATA; 299 } 300 if (type.type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) { 301 if (type.zeroPoint < 0 || type.zeroPoint > 255) { 302 LOG(ERROR) << tag << " OperandType invalid zeroPoint " << type.zeroPoint; 303 return ANEURALNETWORKS_BAD_DATA; 304 } 305 if (type.scale <= 0.f) { 306 LOG(ERROR) << tag << " OperandType invalid scale " << type.scale; 307 return ANEURALNETWORKS_BAD_DATA; 308 } 309 } 310 if (type.type == ANEURALNETWORKS_FLOAT32 || 311 type.type == ANEURALNETWORKS_INT32 || 312 type.type == ANEURALNETWORKS_UINT32 || 313 type.type == ANEURALNETWORKS_OEM_SCALAR) { 314 if (type.dimensionCount != 0 || type.dimensions != nullptr) { 315 LOG(ERROR) << tag << " Invalid dimensions for scalar type"; 316 return ANEURALNETWORKS_BAD_DATA; 317 } 318 } 319 320 return ANEURALNETWORKS_NO_ERROR; 321 } 322 323 int validateOperandList(uint32_t count, const uint32_t* list, uint32_t operandCount, 324 const char* tag) { 325 for (uint32_t i = 0; i < count; i++) { 326 if (list[i] >= operandCount) { 327 LOG(ERROR) << tag << " invalid operand index at " << i << " = " << list[i] 328 << ", operandCount " << operandCount; 329 return ANEURALNETWORKS_BAD_DATA; 330 } 331 } 332 return ANEURALNETWORKS_NO_ERROR; 333 } 334 335 int validateOperationOperandTypes(const std::vector<Operand>& operands, 336 uint32_t inOperandCount, const uint32_t* inOperandIndexes, 337 const std::vector<OperandType>& inExpectedTypes, 338 uint32_t outOperandCount, const uint32_t* outOperandIndexes, 339 const std::vector<OperandType>& outExpectedInTypes) { 340 if (inOperandCount > static_cast<uint32_t>(inExpectedTypes.size()) || 341 outOperandCount > static_cast<uint32_t>(outExpectedInTypes.size())) { 342 return ANEURALNETWORKS_BAD_DATA; 343 } 344 for (uint32_t i = 0; i < inOperandCount; i++) { 345 if (operands[inOperandIndexes[i]].type != inExpectedTypes[i]) { 346 LOG(ERROR) << "Invalid input tensor type " 347 << toString(operands[inOperandIndexes[i]].type) 348 << " for input " << i << ", expected " << toString(inExpectedTypes[i]); 349 return ANEURALNETWORKS_BAD_DATA; 350 } 351 } 352 for (uint32_t i = 0; i < outOperandCount; i++) { 353 if (operands[outOperandIndexes[i]].type != outExpectedInTypes[i]) { 354 LOG(ERROR) << "Invalid output tensor type " 355 << toString(operands[outOperandIndexes[i]].type) 356 << " for input " << i << ", expected " << toString(outExpectedInTypes[i]); 357 return ANEURALNETWORKS_BAD_DATA; 358 } 359 } 360 361 return ANEURALNETWORKS_NO_ERROR; 362 } 363 364 int validateOperation(ANeuralNetworksOperationType opType, 365 uint32_t inputCount, const uint32_t* inputIndexes, 366 uint32_t outputCount, const uint32_t* outputIndexes, 367 const std::vector<Operand>& operands) { 368 int n = validateOperandList(inputCount, inputIndexes, static_cast<uint32_t>(operands.size()), 369 "ANeuralNetworksModel_addOperation inputs"); 370 if (n != ANEURALNETWORKS_NO_ERROR) { 371 return n; 372 } 373 n = validateOperandList(outputCount, outputIndexes, static_cast<uint32_t>(operands.size()), 374 "ANeuralNetworksModel_addOperation outputs"); 375 if (n != ANEURALNETWORKS_NO_ERROR) { 376 return n; 377 } 378 379 auto logInvalidInOutNumber = [opType, inputCount, outputCount](int expIn, int expOut) { 380 LOG(ERROR) << "Invalid number of input operands (" 381 << inputCount << ", expected " << expIn << ") or output operands (" 382 << outputCount << ", expected " << expOut << ") for operation " 383 << kOperationNames[opType]; 384 }; 385 386 switch (opType) { 387 case ANEURALNETWORKS_OEM_OPERATION: { 388 return ANEURALNETWORKS_NO_ERROR; 389 } 390 case ANEURALNETWORKS_ADD: { 391 if (inputCount != 3 || outputCount != 1) { 392 logInvalidInOutNumber(3, 1); 393 return ANEURALNETWORKS_BAD_DATA; 394 } 395 auto inputType = operands[inputIndexes[0]].type; 396 std::vector<OperandType> inExpectedTypes; 397 std::vector<OperandType> outExpectedTypes; 398 if (inputType == OperandType::TENSOR_FLOAT32) { 399 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 400 OperandType::TENSOR_FLOAT32, 401 OperandType::INT32}; 402 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 403 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 404 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 405 OperandType::TENSOR_QUANT8_ASYMM, 406 OperandType::INT32}; 407 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 408 } else { 409 LOG(ERROR) << "Unsupported input tensor type for operation " 410 << kOperationNames[opType]; 411 return ANEURALNETWORKS_BAD_DATA; 412 } 413 return validateOperationOperandTypes(operands, 414 inputCount, inputIndexes, 415 inExpectedTypes, 416 outputCount, outputIndexes, 417 outExpectedTypes); 418 } 419 case ANEURALNETWORKS_MUL: { 420 if (inputCount != 3 || outputCount != 1) { 421 logInvalidInOutNumber(3, 1); 422 return ANEURALNETWORKS_BAD_DATA; 423 } 424 auto inputType = operands[inputIndexes[0]].type; 425 std::vector<OperandType> inExpectedTypes; 426 std::vector<OperandType> outExpectedTypes; 427 if (inputType == OperandType::TENSOR_FLOAT32) { 428 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 429 OperandType::TENSOR_FLOAT32, 430 OperandType::INT32}; 431 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 432 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 433 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 434 OperandType::TENSOR_QUANT8_ASYMM, 435 OperandType::INT32}; 436 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 437 } else { 438 LOG(ERROR) << "Unsupported input tensor type for operation " 439 << kOperationNames[opType]; 440 return ANEURALNETWORKS_BAD_DATA; 441 } 442 return validateOperationOperandTypes(operands, 443 inputCount, inputIndexes, 444 inExpectedTypes, 445 outputCount, outputIndexes, 446 outExpectedTypes); 447 } 448 case ANEURALNETWORKS_FLOOR: { 449 if (inputCount != 1 || outputCount != 1) { 450 logInvalidInOutNumber(1, 1); 451 return ANEURALNETWORKS_BAD_DATA; 452 } 453 auto inputType = operands[inputIndexes[0]].type; 454 std::vector<OperandType> inExpectedTypes; 455 std::vector<OperandType> outExpectedTypes; 456 if (inputType == OperandType::TENSOR_FLOAT32) { 457 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 458 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 459 } else { 460 LOG(ERROR) << "Unsupported input tensor type for operation " 461 << kOperationNames[opType]; 462 return ANEURALNETWORKS_BAD_DATA; 463 } 464 return validateOperationOperandTypes(operands, 465 inputCount, inputIndexes, 466 inExpectedTypes, 467 outputCount, outputIndexes, 468 outExpectedTypes); 469 } 470 case ANEURALNETWORKS_DEQUANTIZE: { 471 if (inputCount != 1 || outputCount != 1) { 472 logInvalidInOutNumber(1, 1); 473 return ANEURALNETWORKS_BAD_DATA; 474 } 475 auto inputType = operands[inputIndexes[0]].type; 476 std::vector<OperandType> inExpectedTypes; 477 std::vector<OperandType> outExpectedTypes; 478 if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 479 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 480 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 481 } else { 482 LOG(ERROR) << "Unsupported input tensor type for operation " 483 << kOperationNames[opType]; 484 return ANEURALNETWORKS_BAD_DATA; 485 } 486 return validateOperationOperandTypes(operands, 487 inputCount, inputIndexes, 488 inExpectedTypes, 489 outputCount, outputIndexes, 490 outExpectedTypes); 491 } 492 case ANEURALNETWORKS_DEPTHWISE_CONV_2D: { 493 if ((inputCount != 11 && inputCount != 8) || outputCount != 1) { 494 LOG(ERROR) << "Invalid number of input operands (" 495 << inputCount << ", expected 11 or 8) or output operands (" 496 << outputCount << ", expected 1) for operation " 497 << kOperationNames[opType]; 498 return ANEURALNETWORKS_BAD_DATA; 499 } 500 auto inputType = operands[inputIndexes[0]].type; 501 std::vector<OperandType> inExpectedTypes; 502 std::vector<OperandType> outExpectedTypes; 503 if (inputType == OperandType::TENSOR_FLOAT32) { 504 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 505 OperandType::TENSOR_FLOAT32, 506 OperandType::TENSOR_FLOAT32, 507 OperandType::INT32, 508 OperandType::INT32, 509 OperandType::INT32, 510 OperandType::INT32, 511 OperandType::INT32}; 512 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 513 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 514 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 515 OperandType::TENSOR_QUANT8_ASYMM, 516 OperandType::TENSOR_INT32, 517 OperandType::INT32, 518 OperandType::INT32, 519 OperandType::INT32, 520 OperandType::INT32, 521 OperandType::INT32}; 522 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 523 } else { 524 LOG(ERROR) << "Unsupported input tensor type for operation " 525 << kOperationNames[opType]; 526 return ANEURALNETWORKS_BAD_DATA; 527 } 528 529 if (inputCount == 11) { 530 std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32); 531 inExpectedTypes.insert(inExpectedTypes.end(), 532 explicitScalarTypes.begin(), 533 explicitScalarTypes.end()); 534 } 535 return validateOperationOperandTypes(operands, 536 inputCount, inputIndexes, 537 inExpectedTypes, 538 outputCount, outputIndexes, 539 outExpectedTypes); 540 } 541 case ANEURALNETWORKS_CONV_2D: { 542 if ((inputCount != 10 && inputCount != 7) || outputCount != 1) { 543 LOG(ERROR) << "Invalid number of input operands (" 544 << inputCount << ", expected 10 or 7) or output operands (" 545 << outputCount << ", expected 1) for operation " 546 << kOperationNames[opType]; 547 return ANEURALNETWORKS_BAD_DATA; 548 } 549 auto inputType = operands[inputIndexes[0]].type; 550 std::vector<OperandType> inExpectedTypes; 551 std::vector<OperandType> outExpectedTypes; 552 if (inputType == OperandType::TENSOR_FLOAT32) { 553 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 554 OperandType::TENSOR_FLOAT32, 555 OperandType::TENSOR_FLOAT32, 556 OperandType::INT32, 557 OperandType::INT32, 558 OperandType::INT32, 559 OperandType::INT32}; 560 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 561 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 562 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 563 OperandType::TENSOR_QUANT8_ASYMM, 564 OperandType::TENSOR_INT32, 565 OperandType::INT32, 566 OperandType::INT32, 567 OperandType::INT32, 568 OperandType::INT32}; 569 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 570 } else { 571 LOG(ERROR) << "Unsupported input tensor type for operation " 572 << kOperationNames[opType]; 573 return ANEURALNETWORKS_BAD_DATA; 574 } 575 576 if (inputCount == 10) { 577 std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32); 578 inExpectedTypes.insert(inExpectedTypes.end(), 579 explicitScalarTypes.begin(), 580 explicitScalarTypes.end()); 581 } 582 return validateOperationOperandTypes(operands, 583 inputCount, inputIndexes, 584 inExpectedTypes, 585 outputCount, outputIndexes, 586 outExpectedTypes); 587 } 588 case ANEURALNETWORKS_AVERAGE_POOL_2D: { 589 if ((inputCount != 10 && inputCount != 7) || outputCount != 1) { 590 LOG(ERROR) << "Invalid number of input operands (" 591 << inputCount << ", expected 10 or 7) or output operands (" 592 << outputCount << ", expected 1) for operation " 593 << kOperationNames[opType]; 594 return ANEURALNETWORKS_BAD_DATA; 595 } 596 auto inputType = operands[inputIndexes[0]].type; 597 std::vector<OperandType> inExpectedTypes; 598 std::vector<OperandType> outExpectedTypes; 599 if (inputType == OperandType::TENSOR_FLOAT32) { 600 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 601 OperandType::INT32, 602 OperandType::INT32, 603 OperandType::INT32, 604 OperandType::INT32, 605 OperandType::INT32, 606 OperandType::INT32}; 607 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 608 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 609 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 610 OperandType::INT32, 611 OperandType::INT32, 612 OperandType::INT32, 613 OperandType::INT32, 614 OperandType::INT32, 615 OperandType::INT32}; 616 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 617 } else { 618 LOG(ERROR) << "Unsupported input tensor type for operation " 619 << kOperationNames[opType]; 620 return ANEURALNETWORKS_BAD_DATA; 621 } 622 623 if (inputCount == 10) { 624 std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32); 625 inExpectedTypes.insert(inExpectedTypes.end(), 626 explicitScalarTypes.begin(), 627 explicitScalarTypes.end()); 628 } 629 return validateOperationOperandTypes(operands, 630 inputCount, inputIndexes, 631 inExpectedTypes, 632 outputCount, outputIndexes, 633 outExpectedTypes); 634 } 635 case ANEURALNETWORKS_L2_POOL_2D: { 636 if ((inputCount != 10 && inputCount != 7) || outputCount != 1) { 637 LOG(ERROR) << "Invalid number of input operands (" 638 << inputCount << ", expected 10 or 7) or output operands (" 639 << outputCount << ", expected 1) for operation " 640 << kOperationNames[opType]; 641 return ANEURALNETWORKS_BAD_DATA; 642 } 643 auto inputType = operands[inputIndexes[0]].type; 644 std::vector<OperandType> inExpectedTypes; 645 std::vector<OperandType> outExpectedTypes; 646 if (inputType == OperandType::TENSOR_FLOAT32) { 647 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 648 OperandType::INT32, 649 OperandType::INT32, 650 OperandType::INT32, 651 OperandType::INT32, 652 OperandType::INT32, 653 OperandType::INT32}; 654 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 655 } else { 656 LOG(ERROR) << "Unsupported input tensor type for operation " 657 << kOperationNames[opType]; 658 return ANEURALNETWORKS_BAD_DATA; 659 } 660 661 if (inputCount == 10) { 662 std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32); 663 inExpectedTypes.insert(inExpectedTypes.end(), 664 explicitScalarTypes.begin(), 665 explicitScalarTypes.end()); 666 } 667 return validateOperationOperandTypes(operands, 668 inputCount, inputIndexes, 669 inExpectedTypes, 670 outputCount, outputIndexes, 671 outExpectedTypes); 672 } 673 case ANEURALNETWORKS_MAX_POOL_2D: { 674 if ((inputCount != 10 && inputCount != 7) || outputCount != 1) { 675 LOG(ERROR) << "Invalid number of input operands (" 676 << inputCount << ", expected 10 or 7) or output operands (" 677 << outputCount << ", expected 1) for operation " 678 << kOperationNames[opType]; 679 return ANEURALNETWORKS_BAD_DATA; 680 } 681 auto inputType = operands[inputIndexes[0]].type; 682 std::vector<OperandType> inExpectedTypes; 683 std::vector<OperandType> outExpectedTypes; 684 if (inputType == OperandType::TENSOR_FLOAT32) { 685 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 686 OperandType::INT32, 687 OperandType::INT32, 688 OperandType::INT32, 689 OperandType::INT32, 690 OperandType::INT32, 691 OperandType::INT32}; 692 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 693 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 694 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 695 OperandType::INT32, 696 OperandType::INT32, 697 OperandType::INT32, 698 OperandType::INT32, 699 OperandType::INT32, 700 OperandType::INT32}; 701 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 702 } else { 703 LOG(ERROR) << "Unsupported input tensor type for operation " 704 << kOperationNames[opType]; 705 return ANEURALNETWORKS_BAD_DATA; 706 } 707 708 if (inputCount == 10) { 709 std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32); 710 inExpectedTypes.insert(inExpectedTypes.end(), 711 explicitScalarTypes.begin(), 712 explicitScalarTypes.end()); 713 } 714 return validateOperationOperandTypes(operands, 715 inputCount, inputIndexes, 716 inExpectedTypes, 717 outputCount, outputIndexes, 718 outExpectedTypes); 719 } 720 case ANEURALNETWORKS_RELU: { 721 if (inputCount != 1 || outputCount != 1) { 722 logInvalidInOutNumber(1, 1); 723 return ANEURALNETWORKS_BAD_DATA; 724 } 725 auto inputType = operands[inputIndexes[0]].type; 726 std::vector<OperandType> inExpectedTypes; 727 std::vector<OperandType> outExpectedTypes; 728 if (inputType == OperandType::TENSOR_FLOAT32) { 729 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 730 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 731 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 732 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 733 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 734 } else { 735 LOG(ERROR) << "Unsupported input tensor type for operation " 736 << kOperationNames[opType]; 737 return ANEURALNETWORKS_BAD_DATA; 738 } 739 return validateOperationOperandTypes(operands, 740 inputCount, inputIndexes, 741 inExpectedTypes, 742 outputCount, outputIndexes, 743 outExpectedTypes); 744 } 745 case ANEURALNETWORKS_RELU1: { 746 if (inputCount != 1 || outputCount != 1) { 747 logInvalidInOutNumber(1, 1); 748 return ANEURALNETWORKS_BAD_DATA; 749 } 750 auto inputType = operands[inputIndexes[0]].type; 751 std::vector<OperandType> inExpectedTypes; 752 std::vector<OperandType> outExpectedTypes; 753 if (inputType == OperandType::TENSOR_FLOAT32) { 754 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 755 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 756 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 757 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 758 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 759 } else { 760 LOG(ERROR) << "Unsupported input tensor type for operation " 761 << kOperationNames[opType]; 762 return ANEURALNETWORKS_BAD_DATA; 763 } 764 return validateOperationOperandTypes(operands, 765 inputCount, inputIndexes, 766 inExpectedTypes, 767 outputCount, outputIndexes, 768 outExpectedTypes); 769 } 770 case ANEURALNETWORKS_RELU6: { 771 if (inputCount != 1 || outputCount != 1) { 772 logInvalidInOutNumber(1, 1); 773 return ANEURALNETWORKS_BAD_DATA; 774 } 775 auto inputType = operands[inputIndexes[0]].type; 776 std::vector<OperandType> inExpectedTypes; 777 std::vector<OperandType> outExpectedTypes; 778 if (inputType == OperandType::TENSOR_FLOAT32) { 779 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 780 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 781 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 782 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 783 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 784 } else { 785 LOG(ERROR) << "Unsupported input tensor type for operation " 786 << kOperationNames[opType]; 787 return ANEURALNETWORKS_BAD_DATA; 788 } 789 return validateOperationOperandTypes(operands, 790 inputCount, inputIndexes, 791 inExpectedTypes, 792 outputCount, outputIndexes, 793 outExpectedTypes); 794 } 795 case ANEURALNETWORKS_TANH: { 796 if (inputCount != 1 || outputCount != 1) { 797 logInvalidInOutNumber(1, 1); 798 return ANEURALNETWORKS_BAD_DATA; 799 } 800 auto inputType = operands[inputIndexes[0]].type; 801 std::vector<OperandType> inExpectedTypes; 802 std::vector<OperandType> outExpectedTypes; 803 if (inputType == OperandType::TENSOR_FLOAT32) { 804 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 805 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 806 } else { 807 LOG(ERROR) << "Unsupported input tensor type for operation " 808 << kOperationNames[opType]; 809 return ANEURALNETWORKS_BAD_DATA; 810 } 811 return validateOperationOperandTypes(operands, 812 inputCount, inputIndexes, 813 inExpectedTypes, 814 outputCount, outputIndexes, 815 outExpectedTypes); 816 } 817 case ANEURALNETWORKS_LOGISTIC: { 818 if (inputCount != 1 || outputCount != 1) { 819 logInvalidInOutNumber(1, 1); 820 return ANEURALNETWORKS_BAD_DATA; 821 } 822 auto inputType = operands[inputIndexes[0]].type; 823 std::vector<OperandType> inExpectedTypes; 824 std::vector<OperandType> outExpectedTypes; 825 if (inputType == OperandType::TENSOR_FLOAT32) { 826 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 827 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 828 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 829 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 830 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 831 } else { 832 LOG(ERROR) << "Unsupported input tensor type for operation " 833 << kOperationNames[opType]; 834 return ANEURALNETWORKS_BAD_DATA; 835 } 836 return validateOperationOperandTypes(operands, 837 inputCount, inputIndexes, 838 inExpectedTypes, 839 outputCount, outputIndexes, 840 outExpectedTypes); 841 } 842 case ANEURALNETWORKS_SOFTMAX: { 843 if (inputCount != 2 || outputCount != 1) { 844 logInvalidInOutNumber(2, 1); 845 return ANEURALNETWORKS_BAD_DATA; 846 } 847 auto inputType = operands[inputIndexes[0]].type; 848 std::vector<OperandType> inExpectedTypes; 849 std::vector<OperandType> outExpectedTypes; 850 if (inputType == OperandType::TENSOR_FLOAT32) { 851 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 852 OperandType::FLOAT32}; 853 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 854 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 855 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 856 OperandType::FLOAT32}; 857 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 858 } else { 859 LOG(ERROR) << "Unsupported input tensor type for operation " 860 << kOperationNames[opType]; 861 return ANEURALNETWORKS_BAD_DATA; 862 } 863 return validateOperationOperandTypes(operands, 864 inputCount, inputIndexes, 865 inExpectedTypes, 866 outputCount, outputIndexes, 867 outExpectedTypes); 868 } 869 case ANEURALNETWORKS_FULLY_CONNECTED: { 870 if (inputCount != 4 || outputCount != 1) { 871 logInvalidInOutNumber(4, 1); 872 return ANEURALNETWORKS_BAD_DATA; 873 } 874 auto inputType = operands[inputIndexes[0]].type; 875 std::vector<OperandType> inExpectedTypes; 876 std::vector<OperandType> outExpectedTypes; 877 if (inputType == OperandType::TENSOR_FLOAT32) { 878 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 879 OperandType::TENSOR_FLOAT32, 880 OperandType::TENSOR_FLOAT32, 881 OperandType::INT32}; 882 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 883 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 884 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 885 OperandType::TENSOR_QUANT8_ASYMM, 886 OperandType::TENSOR_INT32, 887 OperandType::INT32}; 888 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 889 } else { 890 LOG(ERROR) << "Unsupported input tensor type for operation " 891 << kOperationNames[opType]; 892 return ANEURALNETWORKS_BAD_DATA; 893 } 894 return validateOperationOperandTypes(operands, 895 inputCount, inputIndexes, 896 inExpectedTypes, 897 outputCount, outputIndexes, 898 outExpectedTypes); 899 } 900 case ANEURALNETWORKS_CONCATENATION: { 901 if (inputCount < 2 || outputCount != 1) { 902 LOG(ERROR) << "Invalid number of input operands (" 903 << inputCount << ", expected at least 2) or output operands (" 904 << outputCount << ", expected 1) for operation " 905 << kOperationNames[opType]; 906 return ANEURALNETWORKS_BAD_DATA; 907 } 908 auto inputType = operands[inputIndexes[0]].type; 909 std::vector<OperandType> inExpectedTypes(inputCount, inputType); 910 std::vector<OperandType> outExpectedTypes = {inputType}; 911 // The last one is the activation function. 912 inExpectedTypes.back() = OperandType::INT32; 913 return validateOperationOperandTypes(operands, 914 inputCount, inputIndexes, 915 inExpectedTypes, 916 outputCount, outputIndexes, 917 outExpectedTypes); 918 } 919 case ANEURALNETWORKS_L2_NORMALIZATION: { 920 if (inputCount != 1 || outputCount != 1) { 921 logInvalidInOutNumber(1, 1); 922 return ANEURALNETWORKS_BAD_DATA; 923 } 924 auto inputType = operands[inputIndexes[0]].type; 925 std::vector<OperandType> inExpectedTypes; 926 std::vector<OperandType> outExpectedTypes; 927 if (inputType == OperandType::TENSOR_FLOAT32) { 928 inExpectedTypes = {OperandType::TENSOR_FLOAT32}; 929 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 930 } else { 931 LOG(ERROR) << "Unsupported input tensor type for operation " 932 << kOperationNames[opType]; 933 return ANEURALNETWORKS_BAD_DATA; 934 } 935 return validateOperationOperandTypes(operands, 936 inputCount, inputIndexes, 937 inExpectedTypes, 938 outputCount, outputIndexes, 939 outExpectedTypes); 940 } 941 case ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION: { 942 if (inputCount != 5 || outputCount != 1) { 943 logInvalidInOutNumber(5, 1); 944 return ANEURALNETWORKS_BAD_DATA; 945 } 946 auto inputType = operands[inputIndexes[0]].type; 947 std::vector<OperandType> inExpectedTypes; 948 std::vector<OperandType> outExpectedTypes; 949 if (inputType == OperandType::TENSOR_FLOAT32) { 950 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 951 OperandType::INT32, 952 OperandType::FLOAT32, 953 OperandType::FLOAT32, 954 OperandType::FLOAT32}; 955 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 956 } else { 957 LOG(ERROR) << "Unsupported input tensor type for operation " 958 << kOperationNames[opType]; 959 return ANEURALNETWORKS_BAD_DATA; 960 } 961 return validateOperationOperandTypes(operands, 962 inputCount, inputIndexes, 963 inExpectedTypes, 964 outputCount, outputIndexes, 965 outExpectedTypes); 966 } 967 case ANEURALNETWORKS_RESHAPE: { 968 if (inputCount != 2 || outputCount != 1) { 969 logInvalidInOutNumber(2, 1); 970 return ANEURALNETWORKS_BAD_DATA; 971 } 972 auto inputType = operands[inputIndexes[0]].type; 973 std::vector<OperandType> inExpectedTypes; 974 std::vector<OperandType> outExpectedTypes; 975 if (inputType == OperandType::TENSOR_FLOAT32) { 976 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 977 OperandType::TENSOR_INT32}; 978 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 979 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 980 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 981 OperandType::TENSOR_INT32}; 982 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 983 } else { 984 LOG(ERROR) << "Unsupported input tensor type for operation " 985 << kOperationNames[opType]; 986 return ANEURALNETWORKS_BAD_DATA; 987 } 988 return validateOperationOperandTypes(operands, 989 inputCount, inputIndexes, 990 inExpectedTypes, 991 outputCount, outputIndexes, 992 outExpectedTypes); 993 } 994 case ANEURALNETWORKS_RESIZE_BILINEAR: { 995 if (inputCount != 3 || outputCount != 1) { 996 logInvalidInOutNumber(3, 1); 997 return ANEURALNETWORKS_BAD_DATA; 998 } 999 auto inputType = operands[inputIndexes[0]].type; 1000 std::vector<OperandType> inExpectedTypes; 1001 std::vector<OperandType> outExpectedTypes; 1002 if (inputType == OperandType::TENSOR_FLOAT32) { 1003 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1004 OperandType::INT32, 1005 OperandType::INT32}; 1006 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1007 } else { 1008 LOG(ERROR) << "Unsupported input tensor type for operation " 1009 << kOperationNames[opType]; 1010 return ANEURALNETWORKS_BAD_DATA; 1011 } 1012 return validateOperationOperandTypes(operands, 1013 inputCount, inputIndexes, 1014 inExpectedTypes, 1015 outputCount, outputIndexes, 1016 outExpectedTypes); 1017 } 1018 case ANEURALNETWORKS_DEPTH_TO_SPACE: { 1019 if (inputCount != 2 || outputCount != 1) { 1020 logInvalidInOutNumber(2, 1); 1021 return ANEURALNETWORKS_BAD_DATA; 1022 } 1023 auto inputType = operands[inputIndexes[0]].type; 1024 std::vector<OperandType> inExpectedTypes; 1025 std::vector<OperandType> outExpectedTypes; 1026 if (inputType == OperandType::TENSOR_FLOAT32) { 1027 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1028 OperandType::INT32}; 1029 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1030 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1031 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1032 OperandType::INT32}; 1033 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1034 } else { 1035 LOG(ERROR) << "Unsupported input tensor type for operation " 1036 << kOperationNames[opType]; 1037 return ANEURALNETWORKS_BAD_DATA; 1038 } 1039 return validateOperationOperandTypes(operands, 1040 inputCount, inputIndexes, 1041 inExpectedTypes, 1042 outputCount, outputIndexes, 1043 outExpectedTypes); 1044 } 1045 case ANEURALNETWORKS_SPACE_TO_DEPTH: { 1046 if (inputCount != 2 || outputCount != 1) { 1047 logInvalidInOutNumber(2, 1); 1048 return ANEURALNETWORKS_BAD_DATA; 1049 } 1050 auto inputType = operands[inputIndexes[0]].type; 1051 std::vector<OperandType> inExpectedTypes; 1052 std::vector<OperandType> outExpectedTypes; 1053 if (inputType == OperandType::TENSOR_FLOAT32) { 1054 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1055 OperandType::INT32}; 1056 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1057 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1058 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1059 OperandType::INT32}; 1060 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1061 } else { 1062 LOG(ERROR) << "Unsupported input tensor type for operation " 1063 << kOperationNames[opType]; 1064 return ANEURALNETWORKS_BAD_DATA; 1065 } 1066 return validateOperationOperandTypes(operands, 1067 inputCount, inputIndexes, 1068 inExpectedTypes, 1069 outputCount, outputIndexes, 1070 outExpectedTypes); 1071 } 1072 case ANEURALNETWORKS_EMBEDDING_LOOKUP: { 1073 if (inputCount != 2 || outputCount != 1) { 1074 logInvalidInOutNumber(2, 1); 1075 return ANEURALNETWORKS_BAD_DATA; 1076 } 1077 auto inputType = operands[inputIndexes[1]].type; 1078 std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32, 1079 inputType}; 1080 std::vector<OperandType> outExpectedTypes = {inputType}; 1081 return validateOperationOperandTypes(operands, 1082 inputCount, inputIndexes, 1083 inExpectedTypes, 1084 outputCount, outputIndexes, 1085 outExpectedTypes); 1086 } 1087 case ANEURALNETWORKS_HASHTABLE_LOOKUP: { 1088 if (inputCount != 3 || outputCount != 2) { 1089 logInvalidInOutNumber(3, 2); 1090 return ANEURALNETWORKS_BAD_DATA; 1091 } 1092 auto inputType = operands[inputIndexes[2]].type; 1093 std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32, 1094 OperandType::TENSOR_INT32, 1095 inputType}; 1096 std::vector<OperandType> outExpectedTypes = {inputType, 1097 OperandType::TENSOR_QUANT8_ASYMM}; 1098 return validateOperationOperandTypes(operands, 1099 inputCount, inputIndexes, 1100 inExpectedTypes, 1101 outputCount, outputIndexes, 1102 outExpectedTypes); 1103 } 1104 case ANEURALNETWORKS_LSH_PROJECTION: { 1105 if (inputCount != 4 || outputCount != 1) { 1106 logInvalidInOutNumber(4, 1); 1107 return ANEURALNETWORKS_BAD_DATA; 1108 } 1109 auto inputType = operands[inputIndexes[1]].type; 1110 std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1111 inputType, 1112 OperandType::TENSOR_FLOAT32, 1113 OperandType::INT32}; 1114 std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_INT32}; 1115 return validateOperationOperandTypes(operands, 1116 inputCount, inputIndexes, 1117 inExpectedTypes, 1118 outputCount, outputIndexes, 1119 outExpectedTypes); 1120 } 1121 case ANEURALNETWORKS_LSTM: { 1122 if (inputCount != 23 || outputCount != 4) { 1123 logInvalidInOutNumber(23, 4); 1124 return ANEURALNETWORKS_BAD_DATA; 1125 } 1126 std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1127 OperandType::TENSOR_FLOAT32, 1128 OperandType::TENSOR_FLOAT32, 1129 OperandType::TENSOR_FLOAT32, 1130 OperandType::TENSOR_FLOAT32, 1131 OperandType::TENSOR_FLOAT32, 1132 OperandType::TENSOR_FLOAT32, 1133 OperandType::TENSOR_FLOAT32, 1134 OperandType::TENSOR_FLOAT32, 1135 OperandType::TENSOR_FLOAT32, 1136 OperandType::TENSOR_FLOAT32, 1137 OperandType::TENSOR_FLOAT32, 1138 OperandType::TENSOR_FLOAT32, 1139 OperandType::TENSOR_FLOAT32, 1140 OperandType::TENSOR_FLOAT32, 1141 OperandType::TENSOR_FLOAT32, 1142 OperandType::TENSOR_FLOAT32, 1143 OperandType::TENSOR_FLOAT32, 1144 OperandType::TENSOR_FLOAT32, 1145 OperandType::TENSOR_FLOAT32, 1146 OperandType::INT32, 1147 OperandType::FLOAT32, 1148 OperandType::FLOAT32}; 1149 std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_FLOAT32, 1150 OperandType::TENSOR_FLOAT32, 1151 OperandType::TENSOR_FLOAT32, 1152 OperandType::TENSOR_FLOAT32}; 1153 return validateOperationOperandTypes(operands, 1154 inputCount, inputIndexes, 1155 inExpectedTypes, 1156 outputCount, outputIndexes, 1157 outExpectedTypes); 1158 } 1159 case ANEURALNETWORKS_RNN: { 1160 if (inputCount != 6 || outputCount != 2) { 1161 logInvalidInOutNumber(6, 2); 1162 return ANEURALNETWORKS_BAD_DATA; 1163 } 1164 std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1165 OperandType::TENSOR_FLOAT32, 1166 OperandType::TENSOR_FLOAT32, 1167 OperandType::TENSOR_FLOAT32, 1168 OperandType::TENSOR_FLOAT32, 1169 OperandType::INT32}; 1170 std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_FLOAT32, 1171 OperandType::TENSOR_FLOAT32}; 1172 return validateOperationOperandTypes(operands, 1173 inputCount, inputIndexes, 1174 inExpectedTypes, 1175 outputCount, outputIndexes, 1176 outExpectedTypes); 1177 } 1178 case ANEURALNETWORKS_SVDF: { 1179 if (inputCount != 7 || outputCount != 2) { 1180 logInvalidInOutNumber(7, 2); 1181 return ANEURALNETWORKS_BAD_DATA; 1182 } 1183 std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1184 OperandType::TENSOR_FLOAT32, 1185 OperandType::TENSOR_FLOAT32, 1186 OperandType::TENSOR_FLOAT32, 1187 OperandType::TENSOR_FLOAT32, 1188 OperandType::INT32, 1189 OperandType::INT32}; 1190 std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_FLOAT32, 1191 OperandType::TENSOR_FLOAT32}; 1192 return validateOperationOperandTypes(operands, 1193 inputCount, inputIndexes, 1194 inExpectedTypes, 1195 outputCount, outputIndexes, 1196 outExpectedTypes); 1197 } 1198 case ANEURALNETWORKS_BATCH_TO_SPACE_ND: { 1199 if (inputCount != 2 || outputCount != 1) { 1200 logInvalidInOutNumber(2, 1); 1201 return ANEURALNETWORKS_BAD_DATA; 1202 } 1203 auto inputType = operands[inputIndexes[0]].type; 1204 std::vector<OperandType> inExpectedTypes; 1205 std::vector<OperandType> outExpectedTypes; 1206 if (inputType == OperandType::TENSOR_FLOAT32) { 1207 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1208 OperandType::TENSOR_INT32}; 1209 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1210 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1211 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1212 OperandType::TENSOR_INT32}; 1213 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1214 } else { 1215 LOG(ERROR) << "Unsupported input tensor type for operation " 1216 << kOperationNames[opType]; 1217 return ANEURALNETWORKS_BAD_DATA; 1218 } 1219 return validateOperationOperandTypes(operands, 1220 inputCount, inputIndexes, 1221 inExpectedTypes, 1222 outputCount, outputIndexes, 1223 outExpectedTypes); 1224 } 1225 case ANEURALNETWORKS_SPACE_TO_BATCH_ND: { 1226 if (inputCount != 3 || outputCount != 1) { 1227 logInvalidInOutNumber(3, 1); 1228 return ANEURALNETWORKS_BAD_DATA; 1229 } 1230 auto inputType = operands[inputIndexes[0]].type; 1231 std::vector<OperandType> inExpectedTypes; 1232 std::vector<OperandType> outExpectedTypes; 1233 if (inputType == OperandType::TENSOR_FLOAT32) { 1234 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1235 OperandType::TENSOR_INT32, 1236 OperandType::TENSOR_INT32}; 1237 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1238 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1239 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1240 OperandType::TENSOR_INT32, 1241 OperandType::TENSOR_INT32}; 1242 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1243 } else { 1244 LOG(ERROR) << "Unsupported input tensor type for operation " 1245 << kOperationNames[opType]; 1246 return ANEURALNETWORKS_BAD_DATA; 1247 } 1248 return validateOperationOperandTypes(operands, 1249 inputCount, inputIndexes, 1250 inExpectedTypes, 1251 outputCount, outputIndexes, 1252 outExpectedTypes); 1253 } 1254 case ANEURALNETWORKS_PAD: { 1255 if (inputCount != 2 || outputCount != 1) { 1256 logInvalidInOutNumber(2, 1); 1257 return ANEURALNETWORKS_BAD_DATA; 1258 } 1259 auto inputType = operands[inputIndexes[0]].type; 1260 std::vector<OperandType> inExpectedTypes; 1261 std::vector<OperandType> outExpectedTypes; 1262 if (inputType == OperandType::TENSOR_FLOAT32) { 1263 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1264 OperandType::TENSOR_INT32}; 1265 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1266 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1267 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1268 OperandType::TENSOR_INT32}; 1269 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1270 } else { 1271 LOG(ERROR) << "Unsupported input tensor type for operation " 1272 << kOperationNames[opType]; 1273 return ANEURALNETWORKS_BAD_DATA; 1274 } 1275 return validateOperationOperandTypes(operands, 1276 inputCount, inputIndexes, 1277 inExpectedTypes, 1278 outputCount, outputIndexes, 1279 outExpectedTypes); 1280 } 1281 case ANEURALNETWORKS_SQUEEZE: { 1282 if (inputCount != 2 || outputCount != 1) { 1283 logInvalidInOutNumber(2, 1); 1284 return ANEURALNETWORKS_BAD_DATA; 1285 } 1286 auto inputType = operands[inputIndexes[0]].type; 1287 std::vector<OperandType> inExpectedTypes; 1288 std::vector<OperandType> outExpectedTypes; 1289 if (inputType == OperandType::TENSOR_FLOAT32) { 1290 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1291 OperandType::TENSOR_INT32}; 1292 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1293 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1294 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1295 OperandType::TENSOR_INT32}; 1296 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1297 } else { 1298 LOG(ERROR) << "Unsupported input tensor type for operation " 1299 << kOperationNames[opType]; 1300 return ANEURALNETWORKS_BAD_DATA; 1301 } 1302 return validateOperationOperandTypes(operands, 1303 inputCount, inputIndexes, 1304 inExpectedTypes, 1305 outputCount, outputIndexes, 1306 outExpectedTypes); 1307 } 1308 case ANEURALNETWORKS_TRANSPOSE: { 1309 if (inputCount != 2 || outputCount != 1) { 1310 logInvalidInOutNumber(2, 1); 1311 return ANEURALNETWORKS_BAD_DATA; 1312 } 1313 auto inputType = operands[inputIndexes[0]].type; 1314 std::vector<OperandType> inExpectedTypes; 1315 std::vector<OperandType> outExpectedTypes; 1316 if (inputType == OperandType::TENSOR_FLOAT32) { 1317 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1318 OperandType::TENSOR_INT32}; 1319 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1320 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1321 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1322 OperandType::TENSOR_INT32}; 1323 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1324 } else { 1325 LOG(ERROR) << "Unsupported input tensor type for operation " 1326 << kOperationNames[opType]; 1327 return ANEURALNETWORKS_BAD_DATA; 1328 } 1329 return validateOperationOperandTypes(operands, 1330 inputCount, inputIndexes, 1331 inExpectedTypes, 1332 outputCount, outputIndexes, 1333 outExpectedTypes); 1334 } 1335 case ANEURALNETWORKS_STRIDED_SLICE: { 1336 if (inputCount != 7 || outputCount != 1) { 1337 logInvalidInOutNumber(7, 1); 1338 return ANEURALNETWORKS_BAD_DATA; 1339 } 1340 auto inputType = operands[inputIndexes[0]].type; 1341 std::vector<OperandType> inExpectedTypes; 1342 std::vector<OperandType> outExpectedTypes; 1343 if (inputType == OperandType::TENSOR_FLOAT32) { 1344 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1345 OperandType::TENSOR_INT32, 1346 OperandType::TENSOR_INT32, 1347 OperandType::TENSOR_INT32, 1348 OperandType::INT32, 1349 OperandType::INT32, 1350 OperandType::INT32}; 1351 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1352 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1353 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1354 OperandType::TENSOR_INT32, 1355 OperandType::TENSOR_INT32, 1356 OperandType::TENSOR_INT32, 1357 OperandType::INT32, 1358 OperandType::INT32, 1359 OperandType::INT32}; 1360 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1361 } else { 1362 LOG(ERROR) << "Unsupported input tensor type for operation " 1363 << kOperationNames[opType]; 1364 return ANEURALNETWORKS_BAD_DATA; 1365 } 1366 return validateOperationOperandTypes(operands, 1367 inputCount, inputIndexes, 1368 inExpectedTypes, 1369 outputCount, outputIndexes, 1370 outExpectedTypes); 1371 } 1372 case ANEURALNETWORKS_DIV: { 1373 if (inputCount != 3 || outputCount != 1) { 1374 logInvalidInOutNumber(3, 1); 1375 return ANEURALNETWORKS_BAD_DATA; 1376 } 1377 auto inputType = operands[inputIndexes[0]].type; 1378 std::vector<OperandType> inExpectedTypes; 1379 std::vector<OperandType> outExpectedTypes; 1380 if (inputType == OperandType::TENSOR_FLOAT32) { 1381 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1382 OperandType::TENSOR_FLOAT32, 1383 OperandType::INT32}; 1384 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1385 } else { 1386 LOG(ERROR) << "Unsupported input tensor type for operation " 1387 << kOperationNames[opType]; 1388 return ANEURALNETWORKS_BAD_DATA; 1389 } 1390 return validateOperationOperandTypes(operands, 1391 inputCount, inputIndexes, 1392 inExpectedTypes, 1393 outputCount, outputIndexes, 1394 outExpectedTypes); 1395 } 1396 case ANEURALNETWORKS_SUB: { 1397 if (inputCount != 3 || outputCount != 1) { 1398 logInvalidInOutNumber(3, 1); 1399 return ANEURALNETWORKS_BAD_DATA; 1400 } 1401 auto inputType = operands[inputIndexes[0]].type; 1402 std::vector<OperandType> inExpectedTypes; 1403 std::vector<OperandType> outExpectedTypes; 1404 if (inputType == OperandType::TENSOR_FLOAT32) { 1405 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1406 OperandType::TENSOR_FLOAT32, 1407 OperandType::INT32}; 1408 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1409 } else { 1410 LOG(ERROR) << "Unsupported input tensor type for operation " 1411 << kOperationNames[opType]; 1412 return ANEURALNETWORKS_BAD_DATA; 1413 } 1414 return validateOperationOperandTypes(operands, 1415 inputCount, inputIndexes, 1416 inExpectedTypes, 1417 outputCount, outputIndexes, 1418 outExpectedTypes); 1419 } 1420 case ANEURALNETWORKS_MEAN: { 1421 if (inputCount != 3 || outputCount != 1) { 1422 logInvalidInOutNumber(3, 1); 1423 return ANEURALNETWORKS_BAD_DATA; 1424 } 1425 auto inputType = operands[inputIndexes[0]].type; 1426 std::vector<OperandType> inExpectedTypes; 1427 std::vector<OperandType> outExpectedTypes; 1428 if (inputType == OperandType::TENSOR_FLOAT32) { 1429 inExpectedTypes = {OperandType::TENSOR_FLOAT32, 1430 OperandType::TENSOR_INT32, 1431 OperandType::INT32}; 1432 outExpectedTypes = {OperandType::TENSOR_FLOAT32}; 1433 } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) { 1434 inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM, 1435 OperandType::TENSOR_INT32, 1436 OperandType::INT32}; 1437 outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM}; 1438 } else { 1439 LOG(ERROR) << "Unsupported input tensor type for operation " 1440 << kOperationNames[opType]; 1441 return ANEURALNETWORKS_BAD_DATA; 1442 } 1443 return validateOperationOperandTypes(operands, 1444 inputCount, inputIndexes, 1445 inExpectedTypes, 1446 outputCount, outputIndexes, 1447 outExpectedTypes); 1448 } 1449 default: 1450 return ANEURALNETWORKS_BAD_DATA; 1451 } 1452 } 1453 1454 ErrorStatus convertResultCodeToErrorStatus(int resultCode) { 1455 switch (resultCode) { 1456 case ANEURALNETWORKS_NO_ERROR: 1457 return ErrorStatus::NONE; 1458 1459 case ANEURALNETWORKS_BAD_DATA: 1460 case ANEURALNETWORKS_UNEXPECTED_NULL: 1461 return ErrorStatus::INVALID_ARGUMENT; 1462 1463 default: 1464 LOG(ERROR) << "Unknown result code " << resultCode 1465 << " mapped to ErrorStatus::GENERAL_FAILURE"; 1466 case ANEURALNETWORKS_BAD_STATE: 1467 case ANEURALNETWORKS_INCOMPLETE: 1468 case ANEURALNETWORKS_OP_FAILED: 1469 case ANEURALNETWORKS_OUT_OF_MEMORY: 1470 case ANEURALNETWORKS_UNMAPPABLE: 1471 return ErrorStatus::GENERAL_FAILURE; 1472 } 1473 } 1474 1475 int convertErrorStatusToResultCode(ErrorStatus status) { 1476 switch (status) { 1477 case ErrorStatus::NONE: 1478 return ANEURALNETWORKS_NO_ERROR; 1479 1480 case ErrorStatus::INVALID_ARGUMENT: 1481 return ANEURALNETWORKS_BAD_DATA; 1482 1483 default: 1484 LOG(ERROR) << "Unknown ErrorStatus " << toString(status) 1485 << " mapped to ANEURALNETWORKS_OP_FAILED"; 1486 case ErrorStatus::DEVICE_UNAVAILABLE: 1487 case ErrorStatus::GENERAL_FAILURE: 1488 case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE: 1489 return ANEURALNETWORKS_OP_FAILED; 1490 } 1491 } 1492 1493 // Versioning 1494 1495 bool compliantWithV1_0(V1_0::OperationType) { 1496 return true; 1497 } 1498 1499 bool compliantWithV1_0(V1_1::OperationType operation) { 1500 switch (static_cast<V1_0::OperationType>(operation)) { 1501 case V1_0::OperationType::ADD: 1502 case V1_0::OperationType::AVERAGE_POOL_2D: 1503 case V1_0::OperationType::CONCATENATION: 1504 case V1_0::OperationType::CONV_2D: 1505 case V1_0::OperationType::DEPTHWISE_CONV_2D: 1506 case V1_0::OperationType::DEPTH_TO_SPACE: 1507 case V1_0::OperationType::DEQUANTIZE: 1508 case V1_0::OperationType::EMBEDDING_LOOKUP: 1509 case V1_0::OperationType::FLOOR: 1510 case V1_0::OperationType::FULLY_CONNECTED: 1511 case V1_0::OperationType::HASHTABLE_LOOKUP: 1512 case V1_0::OperationType::L2_NORMALIZATION: 1513 case V1_0::OperationType::L2_POOL_2D: 1514 case V1_0::OperationType::LOCAL_RESPONSE_NORMALIZATION: 1515 case V1_0::OperationType::LOGISTIC: 1516 case V1_0::OperationType::LSH_PROJECTION: 1517 case V1_0::OperationType::LSTM: 1518 case V1_0::OperationType::MAX_POOL_2D: 1519 case V1_0::OperationType::MUL: 1520 case V1_0::OperationType::RELU: 1521 case V1_0::OperationType::RELU1: 1522 case V1_0::OperationType::RELU6: 1523 case V1_0::OperationType::RESHAPE: 1524 case V1_0::OperationType::RESIZE_BILINEAR: 1525 case V1_0::OperationType::RNN: 1526 case V1_0::OperationType::SOFTMAX: 1527 case V1_0::OperationType::SPACE_TO_DEPTH: 1528 case V1_0::OperationType::SVDF: 1529 case V1_0::OperationType::TANH: 1530 case V1_0::OperationType::OEM_OPERATION: 1531 return true; 1532 default: 1533 return false; 1534 } 1535 } 1536 1537 bool compliantWithV1_1(V1_0::OperationType) { 1538 return true; 1539 } 1540 1541 bool compliantWithV1_1(V1_1::OperationType) { 1542 return true; 1543 } 1544 1545 bool compliantWithV1_0(V1_0::Capabilities) { 1546 return true; 1547 } 1548 1549 bool compliantWithV1_0(const V1_1::Capabilities& capabilities) { 1550 return capabilities.relaxedFloat32toFloat16Performance.execTime == 1551 capabilities.float32Performance.execTime 1552 && 1553 capabilities.relaxedFloat32toFloat16Performance.powerUsage == 1554 capabilities.float32Performance.powerUsage; 1555 } 1556 1557 bool compliantWithV1_1(const V1_0::Capabilities&) { 1558 return true; 1559 } 1560 1561 bool compliantWithV1_1(const V1_1::Capabilities&) { 1562 return true; 1563 } 1564 1565 bool compliantWithV1_0(const V1_0::Operation&) { 1566 return true; 1567 } 1568 1569 bool compliantWithV1_0(const V1_1::Operation& operation) { 1570 return compliantWithV1_0(operation.type); 1571 } 1572 1573 bool compliantWithV1_1(const V1_0::Operation&) { 1574 return true; 1575 } 1576 1577 bool compliantWithV1_1(const V1_1::Operation&) { 1578 return true; 1579 } 1580 1581 static bool compliantWithV1_0(const hidl_vec<V1_1::Operation>& operations) { 1582 return std::all_of(operations.begin(), operations.end(), 1583 [](const V1_1::Operation& operation) { 1584 return compliantWithV1_0(operation); 1585 }); 1586 } 1587 1588 bool compliantWithV1_0(const V1_0::Model&) { 1589 return true; 1590 } 1591 1592 bool compliantWithV1_0(const V1_1::Model& model) { 1593 // In addition to new enumeration values being introduced in V1_1::Model, a 1594 // new flag was introduced to indicate whether or not float32 data can be 1595 // calculated using float16 units. This 'relaxComputationFloat32toFloat16' 1596 // flag is not relevant in whether a V1_1::Model is compliant with a 1597 // V1_0::Model because all 1.0 drivers require strict calculation by default 1598 // in the P NN runtime. Even if fp16 calculations are allowed, they can 1599 // still be computed by a strict fp32 driver. 1600 return compliantWithV1_0(model.operations); 1601 } 1602 1603 bool compliantWithV1_1(const V1_0::Model&) { 1604 return true; 1605 } 1606 1607 bool compliantWithV1_1(const V1_1::Model&) { 1608 return true; 1609 } 1610 1611 V1_0::OperationType convertToV1_0(V1_0::OperationType type) { 1612 return type; 1613 } 1614 1615 V1_0::OperationType convertToV1_0(V1_1::OperationType type) { 1616 if (!compliantWithV1_0(type)) { 1617 LOG(ERROR) << "Upcasting non-compliant type " << toString(type) 1618 << " from V1_1::OperationType to V1_0::OperationType"; 1619 } 1620 return static_cast<V1_0::OperationType>(type); 1621 } 1622 1623 V1_1::OperationType convertToV1_1(V1_0::OperationType type) { 1624 return static_cast<V1_1::OperationType>(type); 1625 } 1626 1627 V1_1::OperationType convertToV1_1(V1_1::OperationType type) { 1628 return type; 1629 } 1630 1631 V1_0::Capabilities convertToV1_0(const V1_0::Capabilities& capabilities) { 1632 return capabilities; 1633 } 1634 1635 V1_0::Capabilities convertToV1_0(const V1_1::Capabilities& capabilities) { 1636 if (!compliantWithV1_0(capabilities)) { 1637 LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities) 1638 << " from V1_1::Capabilities to V1_0::Capabilities"; 1639 } 1640 return { .float32Performance = capabilities.float32Performance, 1641 .quantized8Performance = capabilities.quantized8Performance }; 1642 } 1643 1644 V1_1::Capabilities convertToV1_1(const V1_0::Capabilities& capabilities) { 1645 return { .float32Performance = capabilities.float32Performance, 1646 .quantized8Performance = capabilities.quantized8Performance, 1647 .relaxedFloat32toFloat16Performance = capabilities.float32Performance }; 1648 } 1649 1650 V1_1::Capabilities convertToV1_1(const V1_1::Capabilities& capabilities) { 1651 return capabilities; 1652 } 1653 1654 V1_0::Operation convertToV1_0(const V1_0::Operation& operation) { 1655 return operation; 1656 } 1657 1658 V1_0::Operation convertToV1_0(const V1_1::Operation& operation) { 1659 if (!compliantWithV1_0(operation)) { 1660 LOG(ERROR) << "Upcasting non-compliant operation " << toString(operation) 1661 << " from V1_1::Operation to V1_0::Operation"; 1662 } 1663 return {.type = convertToV1_0(operation.type), 1664 .inputs = operation.inputs, 1665 .outputs = operation.outputs}; 1666 } 1667 1668 V1_1::Operation convertToV1_1(const V1_0::Operation& operation) { 1669 return {.type = convertToV1_1(operation.type), 1670 .inputs = operation.inputs, 1671 .outputs = operation.outputs}; 1672 } 1673 1674 V1_1::Operation convertToV1_1(const V1_1::Operation& operation) { 1675 return operation; 1676 } 1677 1678 static hidl_vec<V1_0::Operation> convertToV1_0(const hidl_vec<V1_1::Operation>& operations) { 1679 hidl_vec<V1_0::Operation> result(operations.size()); 1680 std::transform(operations.begin(), operations.end(), result.begin(), 1681 [](const V1_1::Operation& operation) { return convertToV1_0(operation); }); 1682 return result; 1683 } 1684 1685 static hidl_vec<V1_1::Operation> convertToV1_1(const hidl_vec<V1_0::Operation>& operations) { 1686 hidl_vec<V1_1::Operation> result(operations.size()); 1687 std::transform(operations.begin(), operations.end(), result.begin(), 1688 [](const V1_0::Operation& operation) { return convertToV1_1(operation); }); 1689 return result; 1690 } 1691 1692 V1_0::Model convertToV1_0(const V1_0::Model& model) { 1693 return model; 1694 } 1695 1696 V1_0::Model convertToV1_0(const V1_1::Model& model) { 1697 if (!compliantWithV1_0(model)) { 1698 LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model)) 1699 << " from V1_1::Model to V1_0::Model"; 1700 } 1701 return {.operands = model.operands, 1702 .operations = convertToV1_0(model.operations), 1703 .inputIndexes = model.inputIndexes, 1704 .outputIndexes = model.outputIndexes, 1705 .operandValues = model.operandValues, 1706 .pools = model.pools}; 1707 } 1708 1709 V1_1::Model convertToV1_1(const V1_0::Model& model) { 1710 return {.operands = model.operands, 1711 .operations = convertToV1_1(model.operations), 1712 .inputIndexes = model.inputIndexes, 1713 .outputIndexes = model.outputIndexes, 1714 .operandValues = model.operandValues, 1715 .pools = model.pools, 1716 .relaxComputationFloat32toFloat16 = false}; 1717 } 1718 1719 V1_1::Model convertToV1_1(const V1_1::Model& model) { 1720 return model; 1721 } 1722 1723 #ifdef NN_DEBUGGABLE 1724 uint32_t getProp(const char* str, uint32_t defaultValue) { 1725 const std::string propStr = android::base::GetProperty(str, ""); 1726 if (propStr.size() > 0) { 1727 return std::stoi(propStr); 1728 } else { 1729 return defaultValue; 1730 } 1731 } 1732 #endif // NN_DEBUGGABLE 1733 1734 } // namespace nn 1735 } // namespace android 1736