1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383 |
- /*
- * Copyright (C) 2017 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #define LOG_TAG "Utils"
- #include "Utils.h"
- #include "NeuralNetworks.h"
- #include "NeuralNetworksOEM.h"
- #include "OperationResolver.h"
- #include "ValidateHal.h"
- #include <android-base/logging.h>
- #include <android-base/properties.h>
- #include <android-base/strings.h>
- #include <sys/system_properties.h>
- #include <algorithm>
- #include <unordered_map>
- using ::android::hidl::allocator::V1_0::IAllocator;
- namespace android {
- namespace nn {
- const char kVLogPropKey[] = "debug.nn.vlog";
- int vLogMask = ~0;
- // Split the space separated list of tags from verbose log setting and build the
- // logging mask from it. note that '1' and 'all' are special cases to enable all
- // verbose logging.
- //
- // NN API verbose logging setting comes from system property debug.nn.vlog.
- // Example:
- // setprop debug.nn.vlog 1 : enable all logging tags.
- // setprop debug.nn.vlog "model compilation" : only enable logging for MODEL and
- // COMPILATION tags.
- void initVLogMask() {
- vLogMask = 0;
- const std::string vLogSetting = android::base::GetProperty(kVLogPropKey, "");
- if (vLogSetting.empty()) {
- return;
- }
- std::unordered_map<std::string, int> vLogFlags = {
- {"1", -1},
- {"all", -1},
- {"model", MODEL},
- {"compilation", COMPILATION},
- {"execution", EXECUTION},
- {"cpuexe", CPUEXE},
- {"manager", MANAGER},
- {"driver", DRIVER}};
- std::vector<std::string> elements = android::base::Split(vLogSetting, " ,:");
- for (const auto& elem : elements) {
- const auto& flag = vLogFlags.find(elem);
- if (flag == vLogFlags.end()) {
- LOG(ERROR) << "Unknown trace flag: " << elem;
- continue;
- }
- if (flag->second == -1) {
- // -1 is used for the special values "1" and "all" that enable all
- // tracing.
- vLogMask = ~0;
- return;
- } else {
- vLogMask |= 1 << flag->second;
- }
- }
- }
- static bool isExtensionOperandType(int32_t type) {
- return static_cast<uint32_t>(type) > static_cast<uint32_t>(OperandTypeRange::BASE_MAX);
- }
- static bool isExtensionOperationType(ANeuralNetworksOperationType type) {
- return static_cast<uint32_t>(type) > static_cast<uint32_t>(OperationTypeRange::BASE_MAX);
- }
- bool isExtensionOperandType(OperandType type) {
- return isExtensionOperandType(static_cast<int32_t>(type));
- }
- bool isExtensionOperationType(OperationType type) {
- return isExtensionOperationType(static_cast<int32_t>(type));
- }
- namespace {
- template <typename EntryType, uint32_t entryCount, uint32_t entryCountOEM>
- EntryType tableLookup(const EntryType (&table)[entryCount],
- const EntryType (&tableOEM)[entryCountOEM],
- uint32_t code) {
- if (code < entryCount) {
- return table[code];
- } else if (code >= kOEMCodeBase && (code - kOEMCodeBase) < entryCountOEM) {
- return tableOEM[code - kOEMCodeBase];
- } else {
- nnAssert(!"tableLookup: bad code");
- return EntryType();
- }
- }
- class OperationValidationContext : public IOperationValidationContext {
- DISALLOW_IMPLICIT_CONSTRUCTORS(OperationValidationContext);
- public:
- OperationValidationContext(uint32_t inputCount, const uint32_t* inputIndexes,
- uint32_t outputCount, const uint32_t* outputIndexes,
- const Operand* operands, HalVersion halVersion)
- : inputCount(inputCount),
- inputIndexes(inputIndexes),
- outputCount(outputCount),
- outputIndexes(outputIndexes),
- operands(operands),
- halVersion(halVersion) {}
- HalVersion getHalVersion() const override;
- uint32_t getNumInputs() const override;
- OperandType getInputType(uint32_t index) const override;
- Shape getInputShape(uint32_t index) const override;
- const Operand::ExtraParams getInputExtraParams(uint32_t index) const override;
- uint32_t getNumOutputs() const override;
- OperandType getOutputType(uint32_t index) const override;
- Shape getOutputShape(uint32_t index) const override;
- private:
- const Operand* getInputOperand(uint32_t index) const;
- const Operand* getOutputOperand(uint32_t index) const;
- uint32_t inputCount;
- const uint32_t* inputIndexes;
- uint32_t outputCount;
- const uint32_t* outputIndexes;
- const Operand* operands;
- HalVersion halVersion;
- };
- HalVersion OperationValidationContext::getHalVersion() const {
- return halVersion;
- }
- const Operand* OperationValidationContext::getInputOperand(uint32_t index) const {
- CHECK(index < static_cast<uint32_t>(inputCount));
- return &operands[inputIndexes[index]];
- }
- const Operand* OperationValidationContext::getOutputOperand(uint32_t index) const {
- CHECK(index < static_cast<uint32_t>(outputCount));
- return &operands[outputIndexes[index]];
- }
- uint32_t OperationValidationContext::getNumInputs() const {
- return inputCount;
- }
- uint32_t OperationValidationContext::getNumOutputs() const {
- return outputCount;
- }
- OperandType OperationValidationContext::getInputType(uint32_t index) const {
- return getInputOperand(index)->type;
- }
- Shape OperationValidationContext::getInputShape(uint32_t index) const {
- const Operand* operand = getInputOperand(index);
- return {operand->type, operand->dimensions, operand->scale, operand->zeroPoint,
- operand->extraParams};
- }
- const Operand::ExtraParams OperationValidationContext::getInputExtraParams(uint32_t index) const {
- return getInputOperand(index)->extraParams;
- }
- OperandType OperationValidationContext::getOutputType(uint32_t index) const {
- return getOutputOperand(index)->type;
- }
- Shape OperationValidationContext::getOutputShape(uint32_t index) const {
- const Operand* operand = getOutputOperand(index);
- return {operand->type, operand->dimensions, operand->scale, operand->zeroPoint,
- operand->extraParams};
- }
- }; // anonymous namespace
- #define COUNT(X) (sizeof(X) / sizeof(X[0]))
- std::string getOperandTypeName(OperandType type) {
- return toString(type);
- }
- static std::string getOperationName(uint32_t code) {
- return getOperationName(static_cast<OperationType>(code));
- }
- std::string getOperationName(OperationType type) {
- return toString(type);
- }
- const uint32_t kSizeOfDataType[]{
- 4, // ANEURALNETWORKS_FLOAT32
- 4, // ANEURALNETWORKS_INT32
- 4, // ANEURALNETWORKS_UINT32
- 4, // ANEURALNETWORKS_TENSOR_FLOAT32
- 4, // ANEURALNETWORKS_TENSOR_INT32
- 1, // ANEURALNETWORKS_TENSOR_SYMMETRICAL_QUANT8
- 1, // ANEURALNETWORKS_BOOL
- 2, // ANEURALNETWORKS_TENSOR_QUANT16_SYMM
- 2, // ANEURALNETWORKS_TENSOR_FLOAT16
- 1, // ANEURALNETWORKS_TENSOR_BOOL8
- 2, // ANEURALNETWORKS_FLOAT16
- 1, // ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
- 2, // ANEURALNETWORKS_TENSOR_QUANT16_ASYMM
- 1, // ANEURALNETWORKS_TENSOR_QUANT8_SYMM
- };
- static_assert(COUNT(kSizeOfDataType) == kNumberOfDataTypes, "kSizeOfDataType is incorrect");
- const bool kScalarDataType[]{
- true, // ANEURALNETWORKS_FLOAT32
- true, // ANEURALNETWORKS_INT32
- true, // ANEURALNETWORKS_UINT32
- false, // ANEURALNETWORKS_TENSOR_FLOAT32
- false, // ANEURALNETWORKS_TENSOR_INT32
- false, // ANEURALNETWORKS_TENSOR_SYMMETRICAL_QUANT8
- true, // ANEURALNETWORKS_BOOL
- false, // ANEURALNETWORKS_TENSOR_QUANT16_SYMM
- false, // ANEURALNETWORKS_TENSOR_FLOAT16
- false, // ANEURALNETWORKS_TENSOR_BOOL8
- true, // ANEURALNETWORKS_FLOAT16
- false, // ANEURALNETWORKS_TENSOR_QUANT8_SYMM_PER_CHANNEL
- false, // ANEURALNETWORKS_TENSOR_QUANT16_ASYMM
- false, // ANEURALNETWORKS_TENSOR_QUANT8_SYMM
- };
- static_assert(COUNT(kScalarDataType) == kNumberOfDataTypes, "kScalarDataType is incorrect");
- const uint32_t kSizeOfDataTypeOEM[]{
- 0, // ANEURALNETWORKS_OEM
- 1, // ANEURALNETWORKS_TENSOR_OEM_BYTE
- };
- static_assert(COUNT(kSizeOfDataTypeOEM) == kNumberOfDataTypesOEM,
- "kSizeOfDataTypeOEM is incorrect");
- const bool kScalarDataTypeOEM[]{
- true, // ANEURALNETWORKS_OEM
- false, // ANEURALNETWORKS_TENSOR_OEM_BYTE
- };
- static_assert(COUNT(kScalarDataTypeOEM) == kNumberOfDataTypesOEM,
- "kScalarDataTypeOEM is incorrect");
- bool nonExtensionOperandTypeIsScalar(int type) {
- CHECK(!isExtensionOperandType(type)) << "Extension operand types are not supported";
- return tableLookup(kScalarDataType, kScalarDataTypeOEM, type);
- }
- uint32_t nonExtensionOperandSizeOfData(OperandType type, const std::vector<uint32_t>& dimensions) {
- CHECK(!isExtensionOperandType(type)) << "Size of extension operand data is unknown";
- int n = static_cast<int>(type);
- uint32_t size = tableLookup(kSizeOfDataType, kSizeOfDataTypeOEM, n);
- if (tableLookup(kScalarDataType, kScalarDataTypeOEM, n) == true) {
- return size;
- }
- if (dimensions.empty()) {
- return 0;
- }
- for (auto d : dimensions) {
- size *= d;
- }
- return size;
- }
- bool tensorHasUnspecifiedDimensions(int type, const uint32_t* dim, uint32_t dimCount) {
- if (!isExtensionOperandType(type)) {
- CHECK(!nonExtensionOperandTypeIsScalar(type))
- << "A scalar type can never have unspecified dimensions";
- }
- return dimCount == 0 || std::find(dim, dim + dimCount, 0) != (dim + dimCount);
- }
- bool tensorHasUnspecifiedDimensions(const ANeuralNetworksOperandType* type) {
- return tensorHasUnspecifiedDimensions(type->type, type->dimensions, type->dimensionCount);
- }
- bool tensorHasUnspecifiedDimensions(const Operand& operand) {
- return tensorHasUnspecifiedDimensions(static_cast<int>(operand.type), operand.dimensions.data(),
- operand.dimensions.size());
- }
- hidl_memory allocateSharedMemory(int64_t size) {
- static const std::string type = "ashmem";
- static sp<IAllocator> allocator = IAllocator::getService(type);
- hidl_memory memory;
- // TODO: should we align memory size to nearest page? doesn't seem necessary...
- allocator->allocate(size, [&](bool success, const hidl_memory& mem) {
- if (!success) {
- LOG(ERROR) << "unable to allocate " << size << " bytes of " << type;
- } else {
- memory = mem;
- }
- });
- return memory;
- }
- uint32_t alignBytesNeeded(uint32_t index, size_t length) {
- uint32_t pattern;
- if (length < 2) {
- pattern = 0; // No alignment necessary
- } else if (length < 4) {
- pattern = 1; // Align on 2-byte boundary
- } else {
- pattern = 3; // Align on 4-byte boundary
- }
- uint32_t extra = (~(index - 1)) & pattern;
- return extra;
- }
- void logModelToInfo(const V1_0::Model& model) {
- LOG(INFO) << "V1_0::Model start";
- LOG(INFO) << "operands" << toString(model.operands);
- LOG(INFO) << "operations" << toString(model.operations);
- LOG(INFO) << "inputIndexes" << toString(model.inputIndexes);
- LOG(INFO) << "outputIndexes" << toString(model.outputIndexes);
- LOG(INFO) << "operandValues size" << model.operandValues.size();
- LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
- }
- void logModelToInfo(const V1_1::Model& model) {
- LOG(INFO) << "V1_1::Model start";
- LOG(INFO) << "operands" << toString(model.operands);
- LOG(INFO) << "operations" << toString(model.operations);
- LOG(INFO) << "inputIndexes" << toString(model.inputIndexes);
- LOG(INFO) << "outputIndexes" << toString(model.outputIndexes);
- LOG(INFO) << "operandValues size" << model.operandValues.size();
- LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
- }
- bool validateOperandSymmPerChannelQuantParams(
- const Operand& halOperand, const ANeuralNetworksSymmPerChannelQuantParams& channelQuant,
- const char* tag) {
- if (halOperand.type != OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
- return false;
- }
- NN_RET_CHECK_LT(channelQuant.channelDim, halOperand.dimensions.size()) << tag;
- NN_RET_CHECK(channelQuant.scales != nullptr) << tag;
- NN_RET_CHECK_EQ(channelQuant.scaleCount, halOperand.dimensions[channelQuant.channelDim]) << tag;
- NN_RET_CHECK_NE(halOperand.dimensions[channelQuant.channelDim], 0u)
- << tag << " channel dimension " << channelQuant.channelDim << " is underspecified";
- for (uint32_t i = 0; i < halOperand.dimensions[channelQuant.channelDim]; i++) {
- NN_RET_CHECK_GT(channelQuant.scales[i], 0.0f) << tag << " invalid scaleArray[" << i << "]";
- }
- return true;
- }
- static bool validateScalarDimensions(const ANeuralNetworksOperandType& type, const char* tag) {
- NN_RET_CHECK_EQ(type.dimensionCount, 0u) << tag << " invalid dimensions for scalar type";
- NN_RET_CHECK(type.dimensions == nullptr) << tag << " invalid dimensions for scalar type";
- return true;
- }
- static bool validateQuant8AsymmParams(const ANeuralNetworksOperandType& type, const char* tag) {
- NN_RET_CHECK(0 <= type.zeroPoint && type.zeroPoint <= 255)
- << tag << " invalid zeroPoint: " << type.zeroPoint;
- NN_RET_CHECK_GT(type.scale, 0.f) << tag << " invalid scale";
- return true;
- }
- static bool validateQuant8SymmParams(const ANeuralNetworksOperandType& type, const char* tag) {
- NN_RET_CHECK_EQ(type.zeroPoint, 0) << tag << " invalid zeroPoint: " << type.zeroPoint;
- NN_RET_CHECK_GT(type.scale, 0.f) << tag << " invalid scale";
- return true;
- }
- static bool validateQuant16AsymmParams(const ANeuralNetworksOperandType& type, const char* tag) {
- NN_RET_CHECK(0 <= type.zeroPoint && type.zeroPoint <= 65535)
- << tag << " invalid zeroPoint: " << type.zeroPoint;
- NN_RET_CHECK_GT(type.scale, 0.f) << tag << " invalid scale";
- return true;
- }
- static bool validateQuantSymmParams(const ANeuralNetworksOperandType& type, const char* tag) {
- NN_RET_CHECK_EQ(type.zeroPoint, 0) << tag << " zeroPoint is not zero";
- NN_RET_CHECK_GT(type.scale, 0.f) << tag << " invalid scale";
- return true;
- }
- static bool validateNoQuantParams(const ANeuralNetworksOperandType& type, const char* tag) {
- NN_RET_CHECK_EQ(type.zeroPoint, 0) << tag << " zeroPoint is not zero";
- NN_RET_CHECK_EQ(type.scale, 0.f) << tag << " scale is not zero";
- return true;
- }
- static bool validateTensorDimensions(const ANeuralNetworksOperandType& type, const char* tag,
- bool allowPartial) {
- if (allowPartial) {
- return true;
- }
- NN_RET_CHECK_GT(type.dimensionCount, 0u) << tag << " invalid operand dimensions";
- for (uint32_t i = 0; i < type.dimensionCount; i++) {
- NN_RET_CHECK_NE(type.dimensions[i], 0u) << tag << " invalid operand dimensions";
- }
- return true;
- }
- static bool validateOperandTypeHelper(
- const ANeuralNetworksOperandType& type,
- const Extension::OperandTypeInformation* const extensionOperandTypeInfo, const char* tag,
- bool allowPartial) {
- NN_RET_CHECK_EQ(type.dimensionCount == 0, type.dimensions == nullptr);
- if (isExtensionOperandType(type.type)) {
- NN_RET_CHECK(extensionOperandTypeInfo != nullptr);
- if (extensionOperandTypeInfo->isTensor) {
- NN_RET_CHECK(validateTensorDimensions(type, tag, allowPartial));
- } else {
- NN_RET_CHECK(validateScalarDimensions(type, tag));
- }
- return validateNoQuantParams(type, tag);
- }
- NN_RET_CHECK(extensionOperandTypeInfo == nullptr);
- NN_RET_CHECK(validCode(kNumberOfDataTypes, kNumberOfDataTypesOEM, type.type))
- << tag << " invalid OperandType: " << type.type;
- bool isScalar = tableLookup(kScalarDataType, kScalarDataTypeOEM, type.type);
- if (isScalar) {
- NN_RET_CHECK(validateScalarDimensions(type, tag));
- if (type.type != ANEURALNETWORKS_OEM_SCALAR) { // Historically, we have allowed OEM types
- // to use quantization parameters.
- NN_RET_CHECK(validateNoQuantParams(type, tag));
- }
- } else {
- NN_RET_CHECK(validateTensorDimensions(type, tag, allowPartial));
- if (type.type == ANEURALNETWORKS_TENSOR_QUANT8_ASYMM) {
- NN_RET_CHECK(validateQuant8AsymmParams(type, tag));
- } else if (type.type == ANEURALNETWORKS_TENSOR_QUANT8_SYMM) {
- NN_RET_CHECK(validateQuant8SymmParams(type, tag));
- } else if (type.type == ANEURALNETWORKS_TENSOR_QUANT16_ASYMM) {
- NN_RET_CHECK(validateQuant16AsymmParams(type, tag));
- } else if (type.type == ANEURALNETWORKS_TENSOR_QUANT16_SYMM) {
- NN_RET_CHECK(validateQuantSymmParams(type, tag));
- } else if (type.type == ANEURALNETWORKS_TENSOR_INT32) {
- // TODO(b/119869082): TENSOR_INT32 should not use quantization parameters.
- } else if (type.type == ANEURALNETWORKS_TENSOR_OEM_BYTE) {
- // Historically, we have allowed OEM types to use quantization parameters.
- } else {
- NN_RET_CHECK(validateNoQuantParams(type, tag));
- }
- }
- return true;
- }
- int validateOperandType(const ANeuralNetworksOperandType& type,
- const Extension::OperandTypeInformation* const extensionOperandTypeInfo,
- const char* tag, bool allowPartial) {
- return validateOperandTypeHelper(type, extensionOperandTypeInfo, tag, allowPartial)
- ? ANEURALNETWORKS_NO_ERROR
- : ANEURALNETWORKS_BAD_DATA;
- }
- int validateOperandList(uint32_t count, const uint32_t* list, uint32_t operandCount,
- const char* tag) {
- for (uint32_t i = 0; i < count; i++) {
- if (list[i] >= operandCount) {
- LOG(ERROR) << tag << " invalid operand index at " << i << " = " << list[i]
- << ", operandCount " << operandCount;
- return ANEURALNETWORKS_BAD_DATA;
- }
- }
- return ANEURALNETWORKS_NO_ERROR;
- }
- int validateOperationOperandTypes(const std::vector<Operand>& operands,
- uint32_t inOperandCount, const uint32_t* inOperandIndexes,
- const std::vector<OperandType>& inExpectedTypes,
- uint32_t outOperandCount, const uint32_t* outOperandIndexes,
- const std::vector<OperandType>& outExpectedInTypes) {
- if (inOperandCount != static_cast<uint32_t>(inExpectedTypes.size()) ||
- outOperandCount != static_cast<uint32_t>(outExpectedInTypes.size())) {
- LOG(ERROR) << "Wrong operand count: expected " << inExpectedTypes.size() << " inputs and "
- << outExpectedInTypes.size() << " outputs,"
- << "got " << inOperandCount << " inputs and " << outOperandCount << " outputs";
- return ANEURALNETWORKS_BAD_DATA;
- }
- for (uint32_t i = 0; i < inOperandCount; i++) {
- if (operands[inOperandIndexes[i]].type != inExpectedTypes[i]) {
- LOG(ERROR) << "Invalid input tensor type "
- << toString(operands[inOperandIndexes[i]].type)
- << " for input " << i << ", expected " << toString(inExpectedTypes[i]);
- return ANEURALNETWORKS_BAD_DATA;
- }
- }
- for (uint32_t i = 0; i < outOperandCount; i++) {
- if (operands[outOperandIndexes[i]].type != outExpectedInTypes[i]) {
- LOG(ERROR) << "Invalid output tensor type "
- << toString(operands[outOperandIndexes[i]].type)
- << " for input " << i << ", expected " << toString(outExpectedInTypes[i]);
- return ANEURALNETWORKS_BAD_DATA;
- }
- }
- return ANEURALNETWORKS_NO_ERROR;
- }
- static int validateHalVersion(ANeuralNetworksOperationType opType, HalVersion halVersion,
- HalVersion minSupportedHalVersion) {
- if (halVersion < minSupportedHalVersion) {
- LOG(ERROR) << "The given inputs and outputs for operation " << getOperationName(opType)
- << " are only supported in " << toString(minSupportedHalVersion)
- << " and later (validating using " << toString(halVersion) << ")";
- return ANEURALNETWORKS_BAD_DATA;
- }
- return ANEURALNETWORKS_NO_ERROR;
- }
- int validateOperation(ANeuralNetworksOperationType opType, uint32_t inputCount,
- const uint32_t* inputIndexes, uint32_t outputCount,
- const uint32_t* outputIndexes, const std::vector<Operand>& operands,
- HalVersion halVersion) {
- NN_RETURN_IF_ERROR(validateOperandList(inputCount, inputIndexes,
- static_cast<uint32_t>(operands.size()),
- "ANeuralNetworksModel_addOperation inputs"));
- NN_RETURN_IF_ERROR(validateOperandList(outputCount, outputIndexes,
- static_cast<uint32_t>(operands.size()),
- "ANeuralNetworksModel_addOperation outputs"));
- if (isExtensionOperationType(opType)) {
- if (halVersion < HalVersion::V1_2) {
- LOG(ERROR)
- << "Extension operations are supported since HAL version 1.2, validating using "
- << toString(halVersion);
- return ANEURALNETWORKS_BAD_DATA;
- }
- // There is no other validation we can do for an extension operation.
- return ANEURALNETWORKS_NO_ERROR;
- }
- auto logInvalidInOutNumber = [opType, inputCount, outputCount](int expIn, int expOut) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected " << expIn
- << ") or output operands (" << outputCount << ", expected " << expOut
- << ") for operation " << getOperationName(opType);
- };
- switch (opType) {
- case ANEURALNETWORKS_OEM_OPERATION: {
- return ANEURALNETWORKS_NO_ERROR;
- }
- case ANEURALNETWORKS_FLOOR: {
- if (inputCount != 1 || outputCount != 1) {
- logInvalidInOutNumber(1, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_FLOAT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {OperandType::TENSOR_FLOAT16};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_DEPTHWISE_CONV_2D: {
- if ((inputCount != 14 && inputCount != 12 && inputCount != 11 && inputCount != 9 &&
- inputCount != 8) ||
- outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 14, 12, 11, 9 or 8) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- auto filterType = operands[inputIndexes[1]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_FLOAT32, OperandType::INT32,
- OperandType::INT32, OperandType::INT32,
- OperandType::INT32, OperandType::INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16, OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_FLOAT16, OperandType::INT32,
- OperandType::INT32, OperandType::INT32,
- OperandType::INT32, OperandType::INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- if (filterType != OperandType::TENSOR_QUANT8_ASYMM &&
- filterType != OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
- LOG(ERROR) << "Unsupported filter tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM,
- filterType,
- OperandType::TENSOR_INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- // NeuralNetworks.h specifies that ANEURALNETWORKS_DEPTHWISE_CONV_2D's output must
- // meet "outputScale > inputScale * filterScale" for the operand type
- // ANEURALNETWORKS_TENSOR_QUANT8_ASYMM before API level 29. For other
- // operand types (e.g., ANEURALNETWORKS_TENSOR_FLOAT32), this constraint
- // does not apply, so by default the constraint is met.
- bool meetsQuantizedScaleConstraintBeforeV1_2 = true;
- if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- const float inputScale = operands[inputIndexes[0]].scale;
- const float filterScale = operands[inputIndexes[1]].scale;
- const float outputScale = operands[outputIndexes[0]].scale;
- meetsQuantizedScaleConstraintBeforeV1_2 = (outputScale > inputScale * filterScale);
- }
- bool withExplicitPadding = false;
- bool withLayout = false;
- bool withDilation = false;
- if (inputCount >= 9) {
- if (operands[inputIndexes[8]].type == OperandType::INT32 && inputCount >= 11) {
- std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
- inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
- explicitScalarTypes.end());
- withExplicitPadding = true;
- }
- int inputOffset = withExplicitPadding ? 3 : 0;
- if (inputCount >= 9 + inputOffset) {
- inExpectedTypes.push_back(OperandType::BOOL);
- withLayout = true;
- }
- if (inputCount == 10 + inputOffset) {
- LOG(ERROR) << "Provided only one dilation factor value, two values are requred "
- "for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 11 + inputOffset) {
- inExpectedTypes.push_back(OperandType::INT32);
- inExpectedTypes.push_back(OperandType::INT32);
- withDilation = true;
- }
- }
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- filterType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL || withLayout ||
- withDilation || !meetsQuantizedScaleConstraintBeforeV1_2) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_LOCAL_RESPONSE_NORMALIZATION: {
- if ((inputCount != 6 && inputCount != 5) || outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 6 or 5) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32, OperandType::INT32, OperandType::FLOAT32,
- OperandType::FLOAT32, OperandType::FLOAT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16, OperandType::INT32, OperandType::FLOAT16,
- OperandType::FLOAT16, OperandType::FLOAT16,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 6) {
- inExpectedTypes.push_back(OperandType::INT32);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else if (operands[inputIndexes[0]].dimensions.size() != 4) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_RESHAPE: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {OperandType::TENSOR_FLOAT16, OperandType::TENSOR_INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32};
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_DEPTH_TO_SPACE: {
- if ((inputCount != 3 && inputCount != 2) || outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 3 or 2) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_FLOAT32,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {OperandType::TENSOR_FLOAT16, OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 3) {
- inExpectedTypes.push_back(OperandType::BOOL);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_SPACE_TO_DEPTH: {
- if ((inputCount != 3 && inputCount != 2) || outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 3 or 2) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_FLOAT32,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {OperandType::TENSOR_FLOAT16, OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 3) {
- inExpectedTypes.push_back(OperandType::BOOL);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_EMBEDDING_LOOKUP: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[1]].type;
- if (inputType != OperandType::TENSOR_FLOAT32 &&
- inputType != OperandType::TENSOR_INT32 &&
- inputType != OperandType::TENSOR_QUANT8_ASYMM) {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32,
- inputType};
- std::vector<OperandType> outExpectedTypes = {inputType};
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_HASHTABLE_LOOKUP: {
- if (inputCount != 3 || outputCount != 2) {
- logInvalidInOutNumber(3, 2);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[2]].type;
- if (inputType != OperandType::TENSOR_FLOAT32 &&
- inputType != OperandType::TENSOR_INT32 &&
- inputType != OperandType::TENSOR_QUANT8_ASYMM) {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> inExpectedTypes = {OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32,
- inputType};
- std::vector<OperandType> outExpectedTypes = {inputType,
- OperandType::TENSOR_QUANT8_ASYMM};
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_LSH_PROJECTION: {
- if (inputCount != 4 || outputCount != 1) {
- logInvalidInOutNumber(4, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[1]].type;
- if (inputType != OperandType::TENSOR_FLOAT16 &&
- inputType != OperandType::TENSOR_FLOAT32 &&
- inputType != OperandType::TENSOR_INT32 &&
- inputType != OperandType::TENSOR_QUANT8_ASYMM) {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto hashType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- if (hashType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16,
- inputType,
- OperandType::TENSOR_FLOAT16,
- OperandType::INT32,
- };
- } else if (hashType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32,
- inputType,
- OperandType::TENSOR_FLOAT32,
- OperandType::INT32,
- };
- } else {
- LOG(ERROR) << "Unsupported hash tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_INT32};
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_BIDIRECTIONAL_SEQUENCE_LSTM: {
- std::vector<OperandType> inExpectedTypes;
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> outExpectedTypes{inputType, inputType};
- std::vector<OperandType> outExpectedTypesMerged{inputType};
- if (inputType != OperandType::TENSOR_FLOAT32 &&
- inputType != OperandType::TENSOR_FLOAT16) {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {};
- for (int i = 0; i < 48; ++i) {
- inExpectedTypes.push_back(inputType);
- }
- inExpectedTypes.push_back(OperandType::INT32);
- inExpectedTypes.push_back(inputType == OperandType::TENSOR_FLOAT32
- ? OperandType::FLOAT32
- : OperandType::FLOAT16);
- inExpectedTypes.push_back(inputType == OperandType::TENSOR_FLOAT32
- ? OperandType::FLOAT32
- : OperandType::FLOAT16);
- inExpectedTypes.push_back(OperandType::BOOL);
- inExpectedTypes.push_back(OperandType::BOOL);
- for (int i = 0; i < 8; ++i) {
- inExpectedTypes.push_back(inputType);
- }
- if (inputCount != 61 || (outputCount != 1 && outputCount != 2)) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 61) or output operands (" << outputCount
- << ", expected 1 or 2) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto status = validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- if (status != ANEURALNETWORKS_NO_ERROR) {
- status = validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypesMerged);
- }
- return status;
- }
- case ANEURALNETWORKS_LSTM: {
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- auto inputType = operands[inputIndexes[0]].type;
- if (inputType != OperandType::TENSOR_FLOAT32 &&
- inputType != OperandType::TENSOR_FLOAT16) {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- inExpectedTypes = {inputType, inputType, inputType, inputType, inputType,
- inputType, inputType, inputType, inputType, inputType,
- inputType, inputType, inputType, inputType, inputType,
- inputType, inputType, inputType, inputType, inputType,
- OperandType::INT32};
- if (inputType == OperandType::TENSOR_FLOAT32) {
- inExpectedTypes.push_back(OperandType::FLOAT32);
- inExpectedTypes.push_back(OperandType::FLOAT32);
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes.push_back(OperandType::FLOAT16);
- inExpectedTypes.push_back(OperandType::FLOAT16);
- }
- outExpectedTypes = {inputType, inputType, inputType, inputType};
- if (inputCount == 23 && outputCount == 4) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- } else if (inputCount == 27 && outputCount == 4) {
- for (int i = 0; i < 4; ++i) {
- inExpectedTypes.push_back(inputType);
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 23 or 27) or output operands (" << outputCount
- << ", expected 4) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_QUANTIZED_16BIT_LSTM: {
- if (inputCount != 15 || outputCount != 2) {
- logInvalidInOutNumber(15, 2);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- std::vector<OperandType> inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_QUANT8_ASYMM, OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32, OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32, OperandType::TENSOR_QUANT16_SYMM,
- OperandType::TENSOR_QUANT8_ASYMM};
- std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_QUANT16_SYMM,
- OperandType::TENSOR_QUANT8_ASYMM};
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_RANDOM_MULTINOMIAL: {
- if (inputCount != 3 || outputCount != 1) {
- logInvalidInOutNumber(3, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- OperandType inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- inputType,
- OperandType::INT32,
- OperandType::TENSOR_INT32,
- };
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> outExpectedTypes = {OperandType::TENSOR_INT32};
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_RNN: {
- if (inputCount != 6 || outputCount != 2) {
- logInvalidInOutNumber(6, 2);
- return ANEURALNETWORKS_BAD_DATA;
- }
- OperandType inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_FLOAT32, OperandType::INT32,
- };
- outExpectedTypes = {
- OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_FLOAT32,
- };
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16, OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_FLOAT16, OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_FLOAT16, OperandType::INT32,
- };
- outExpectedTypes = {
- OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_FLOAT16,
- };
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_SVDF: {
- if (inputCount != 7 || outputCount != 2) {
- logInvalidInOutNumber(7, 2);
- return ANEURALNETWORKS_BAD_DATA;
- }
- OperandType inputType = operands[inputIndexes[0]].type;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_0));
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> inExpectedTypes = {
- inputType, inputType, inputType, inputType,
- inputType, OperandType::INT32, OperandType::INT32,
- };
- std::vector<OperandType> outExpectedTypes = {inputType, inputType};
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_BATCH_TO_SPACE_ND: {
- if ((inputCount != 3 && inputCount != 2) || outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 3 or 2) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 3) {
- inExpectedTypes.push_back(OperandType::BOOL);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_SPACE_TO_BATCH_ND: {
- if ((inputCount != 4 && inputCount != 3) || outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 4 or 3) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- if (operands[inputIndexes[0]].zeroPoint != 0) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- }
- inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 4) {
- inExpectedTypes.push_back(OperandType::BOOL);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_PAD: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- if (operands[inputIndexes[0]].zeroPoint == 0) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- } else {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- }
- inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_PAD_V2: {
- if (inputCount != 3 || outputCount != 1) {
- logInvalidInOutNumber(3, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32,
- OperandType::FLOAT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_INT32,
- OperandType::FLOAT16,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32,
- OperandType::INT32,
- }; // TODO(b/116699425): Make it UINT8.
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_CAST: {
- if (inputCount != 1 || outputCount != 1) {
- logInvalidInOutNumber(1, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- auto outputType = operands[outputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_INT32 ||
- inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {inputType};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> outExpectedTypes;
- if (outputType == OperandType::TENSOR_FLOAT16 ||
- outputType == OperandType::TENSOR_FLOAT32 ||
- outputType == OperandType::TENSOR_INT32 ||
- outputType == OperandType::TENSOR_QUANT8_ASYMM) {
- outExpectedTypes = {outputType};
- } else {
- LOG(ERROR) << "Unsupported output tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_SQUEEZE: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {OperandType::TENSOR_FLOAT16, OperandType::TENSOR_INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32};
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_STRIDED_SLICE: {
- if (inputCount != 7 || outputCount != 1) {
- logInvalidInOutNumber(7, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT32, OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32, OperandType::TENSOR_INT32,
- OperandType::INT32, OperandType::INT32,
- OperandType::INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {
- OperandType::TENSOR_FLOAT16, OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32, OperandType::TENSOR_INT32,
- OperandType::INT32, OperandType::INT32,
- OperandType::INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {
- OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32,
- OperandType::TENSOR_INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32,
- };
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_MEAN: {
- if (inputCount != 3 || outputCount != 1) {
- logInvalidInOutNumber(3, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_INT32,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- inExpectedTypes = {OperandType::TENSOR_FLOAT16, OperandType::TENSOR_INT32,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_1));
- inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
- OperandType::TENSOR_INT32,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return validateOperationOperandTypes(operands,
- inputCount, inputIndexes,
- inExpectedTypes,
- outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_ARGMAX:
- case ANEURALNETWORKS_ARGMIN: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_INT32 ||
- inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {inputType, OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_INT32};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_EXPAND_DIMS: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_INT32 ||
- inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {inputType, OperandType::INT32};
- outExpectedTypes = {inputType};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_SPLIT: {
- if (inputCount != 3) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount << ", expected 3)"
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- if (inputType != OperandType::TENSOR_FLOAT16 &&
- inputType != OperandType::TENSOR_FLOAT32 &&
- inputType != OperandType::TENSOR_INT32 &&
- inputType != OperandType::TENSOR_QUANT8_ASYMM) {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> inExpectedTypes = {inputType, OperandType::INT32,
- OperandType::INT32};
- std::vector<OperandType> outExpectedTypes(outputCount, inputType);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_MAXIMUM:
- case ANEURALNETWORKS_MINIMUM: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- OperandType inputType = operands[inputIndexes[0]].type;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_INT32 ||
- inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {inputType, inputType};
- outExpectedTypes = {inputType};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_GROUPED_CONV_2D: {
- if ((inputCount != 12 && inputCount != 9) || outputCount != 1) {
- LOG(ERROR) << "Invalid number of input operands (" << inputCount
- << ", expected 12 or 9) or output operands (" << outputCount
- << ", expected 1) for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- auto filterType = operands[inputIndexes[1]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT32) {
- inExpectedTypes = {OperandType::TENSOR_FLOAT32, OperandType::TENSOR_FLOAT32,
- OperandType::TENSOR_FLOAT32, OperandType::INT32,
- OperandType::INT32, OperandType::INT32,
- OperandType::INT32, OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT32};
- } else if (inputType == OperandType::TENSOR_FLOAT16) {
- inExpectedTypes = {OperandType::TENSOR_FLOAT16, OperandType::TENSOR_FLOAT16,
- OperandType::TENSOR_FLOAT16, OperandType::INT32,
- OperandType::INT32, OperandType::INT32,
- OperandType::INT32, OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_FLOAT16};
- } else if (inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- if (filterType != OperandType::TENSOR_QUANT8_ASYMM &&
- filterType != OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL) {
- LOG(ERROR) << "Unsupported filter tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (filterType == OperandType::TENSOR_QUANT8_SYMM_PER_CHANNEL &&
- operands[inputIndexes[1]].extraParams.channelQuant().channelDim != 0) {
- LOG(ERROR) << "Unsupported filter tensor channel dimension for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- inExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM,
- filterType,
- OperandType::TENSOR_INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32,
- OperandType::INT32};
- outExpectedTypes = {OperandType::TENSOR_QUANT8_ASYMM};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- if (inputCount == 12) {
- std::vector<OperandType> explicitScalarTypes(3, OperandType::INT32);
- inExpectedTypes.insert(inExpectedTypes.end(), explicitScalarTypes.begin(),
- explicitScalarTypes.end());
- }
- inExpectedTypes.push_back(OperandType::BOOL);
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_TILE: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_INT32 ||
- inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {inputType, OperandType::TENSOR_INT32};
- outExpectedTypes = {inputType};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_POW: {
- if (inputCount != 2 || outputCount != 1) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- auto inputType = operands[inputIndexes[0]].type;
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32) {
- inExpectedTypes = {inputType, inputType};
- outExpectedTypes = {inputType};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- case ANEURALNETWORKS_TOPK_V2: {
- if (inputCount != 2 || outputCount != 2) {
- logInvalidInOutNumber(2, 1);
- return ANEURALNETWORKS_BAD_DATA;
- }
- std::vector<OperandType> inExpectedTypes;
- std::vector<OperandType> outExpectedTypes;
- OperandType inputType = operands[inputIndexes[0]].type;
- if (inputType == OperandType::TENSOR_FLOAT16 ||
- inputType == OperandType::TENSOR_FLOAT32 ||
- inputType == OperandType::TENSOR_INT32 ||
- inputType == OperandType::TENSOR_QUANT8_ASYMM) {
- inExpectedTypes = {inputType, OperandType::INT32};
- outExpectedTypes = {inputType, OperandType::TENSOR_INT32};
- } else {
- LOG(ERROR) << "Unsupported input tensor type for operation "
- << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- NN_RETURN_IF_ERROR(validateHalVersion(opType, halVersion, HalVersion::V1_2));
- return validateOperationOperandTypes(operands, inputCount, inputIndexes,
- inExpectedTypes, outputCount, outputIndexes,
- outExpectedTypes);
- }
- default: {
- const OperationRegistration* operationRegistration =
- BuiltinOperationResolver::get()->findOperation(
- static_cast<OperationType>(opType));
- if (operationRegistration == nullptr) {
- if (0 <= opType && opType < kNumberOfOperationTypes) {
- LOG(ERROR) << getOperationName(opType) << " not registered";
- } else {
- LOG(ERROR) << "Operation type " << opType << " out of the range [0, "
- << kNumberOfOperationTypes << ")";
- }
- return ANEURALNETWORKS_UNEXPECTED_NULL;
- }
- if (operationRegistration->validate == nullptr) {
- LOG(ERROR) << "Incomplete operation registration: " << getOperationName(opType);
- return ANEURALNETWORKS_UNEXPECTED_NULL;
- }
- OperationValidationContext context(inputCount, inputIndexes, outputCount, outputIndexes,
- operands.data(), halVersion);
- if (!operationRegistration->validate(&context)) {
- LOG(ERROR) << "Validation failed for operation " << getOperationName(opType);
- return ANEURALNETWORKS_BAD_DATA;
- }
- return ANEURALNETWORKS_NO_ERROR;
- }
- }
- }
- ErrorStatus convertResultCodeToErrorStatus(int resultCode) {
- switch (resultCode) {
- case ANEURALNETWORKS_NO_ERROR:
- return ErrorStatus::NONE;
- case ANEURALNETWORKS_BAD_DATA:
- case ANEURALNETWORKS_UNEXPECTED_NULL:
- return ErrorStatus::INVALID_ARGUMENT;
- case ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE:
- return ErrorStatus::OUTPUT_INSUFFICIENT_SIZE;
- case ANEURALNETWORKS_UNAVAILABLE_DEVICE:
- return ErrorStatus::DEVICE_UNAVAILABLE;
- default:
- LOG(ERROR) << "Unknown result code " << resultCode
- << " mapped to ErrorStatus::GENERAL_FAILURE";
- return ErrorStatus::GENERAL_FAILURE;
- case ANEURALNETWORKS_BAD_STATE:
- case ANEURALNETWORKS_INCOMPLETE:
- case ANEURALNETWORKS_OP_FAILED:
- case ANEURALNETWORKS_OUT_OF_MEMORY:
- case ANEURALNETWORKS_UNMAPPABLE:
- return ErrorStatus::GENERAL_FAILURE;
- }
- }
- int convertErrorStatusToResultCode(ErrorStatus status) {
- switch (status) {
- case ErrorStatus::NONE:
- return ANEURALNETWORKS_NO_ERROR;
- case ErrorStatus::INVALID_ARGUMENT:
- return ANEURALNETWORKS_BAD_DATA;
- case ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
- return ANEURALNETWORKS_OUTPUT_INSUFFICIENT_SIZE;
- case ErrorStatus::DEVICE_UNAVAILABLE:
- return ANEURALNETWORKS_UNAVAILABLE_DEVICE;
- default:
- LOG(ERROR) << "Unknown ErrorStatus " << toString(status)
- << " mapped to ANEURALNETWORKS_OP_FAILED";
- return ANEURALNETWORKS_OP_FAILED;
- case ErrorStatus::GENERAL_FAILURE:
- return ANEURALNETWORKS_OP_FAILED;
- }
- }
- // V1_2::Capabilities::operandPerformance utilities.
- // The field V1_2::Capabilities::operandPerformance is a vector sorted by the
- // field V1_2::Capabilities::OperandPerformance::type.
- hidl_vec<Capabilities::OperandPerformance> nonExtensionOperandPerformance(PerformanceInfo perf) {
- using OpPerf = Capabilities::OperandPerformance;
- // Note: range presents enumerators in declaration order, not in numerical order.
- static constexpr ::android::hardware::hidl_enum_range<OperandType> kOperandTypeRange;
- hidl_vec<OpPerf> ret(kOperandTypeRange.end() - kOperandTypeRange.begin());
- std::transform(kOperandTypeRange.begin(), kOperandTypeRange.end(), ret.begin(),
- [perf](OperandType type) {
- return Capabilities::OperandPerformance{type, perf};
- });
- std::sort(ret.begin(), ret.end(),
- [](const OpPerf& a, const OpPerf& b) { return a.type < b.type; });
- return ret;
- }
- void update(hidl_vec<Capabilities::OperandPerformance>* operandPerformance, OperandType type,
- PerformanceInfo perf) {
- CHECK(operandPerformance != nullptr);
- const auto it = std::lower_bound(operandPerformance->begin(), operandPerformance->end(), type,
- [](const Capabilities::OperandPerformance& perf,
- OperandType type) { return perf.type < type; });
- CHECK(it != operandPerformance->end())
- << toString(type) << " not in " << toString(*operandPerformance);
- it->info = perf;
- }
- PerformanceInfo lookup(const hidl_vec<Capabilities::OperandPerformance>& operandPerformance,
- OperandType type) {
- const auto it = std::lower_bound(operandPerformance.begin(), operandPerformance.end(), type,
- [](const Capabilities::OperandPerformance& perf,
- OperandType type) { return perf.type < type; });
- if (it == operandPerformance.end()) {
- LOG(WARNING) << "No PerformanceInfo for " << toString(type);
- return {.execTime = FLT_MAX, .powerUsage = FLT_MAX};
- } else {
- return it->info;
- }
- }
- // Versioning
- // In Android P, most data types are treated as having the same performance as TENSOR_QUANT8_ASYMM.
- // This array must be in sorted order.
- static const OperandType kQuantized8PerformanceConsistentWithP[] = {
- OperandType::INT32, OperandType::UINT32, OperandType::TENSOR_INT32, OperandType::OEM,
- OperandType::TENSOR_OEM_BYTE};
- static bool isQuantized8PerformanceConsistentWithP(const V1_2::Capabilities& capabilities) {
- const PerformanceInfo quantized8Performance =
- lookup(capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM);
- return std::all_of(std::begin(kQuantized8PerformanceConsistentWithP),
- std::end(kQuantized8PerformanceConsistentWithP),
- [quantized8Performance, &capabilities](OperandType type) {
- return quantized8Performance ==
- lookup(capabilities.operandPerformance, type);
- });
- }
- static hidl_vec<V1_2::Capabilities::OperandPerformance> makeQuantized8PerformanceConsistentWithP(
- PerformanceInfo quantized8Performance) {
- hidl_vec<V1_2::Capabilities::OperandPerformance> ret(
- sizeof(kQuantized8PerformanceConsistentWithP) /
- sizeof(kQuantized8PerformanceConsistentWithP[0]));
- std::transform(
- std::begin(kQuantized8PerformanceConsistentWithP),
- std::end(kQuantized8PerformanceConsistentWithP), ret.begin(),
- [quantized8Performance](OperandType type) -> V1_2::Capabilities::OperandPerformance {
- return {type, quantized8Performance};
- });
- return ret;
- }
- bool compliantWithV1_0(const V1_0::Capabilities&) {
- return true;
- }
- bool compliantWithV1_0(const V1_1::Capabilities& capabilities) {
- return capabilities.relaxedFloat32toFloat16Performance == capabilities.float32Performance;
- }
- bool compliantWithV1_0(const V1_2::Capabilities& capabilities) {
- const PerformanceInfo perfTensorFloat32 =
- lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32);
- const PerformanceInfo perfFloat32 =
- lookup(capabilities.operandPerformance, OperandType::FLOAT32);
- if (perfTensorFloat32 != perfFloat32 ||
- perfTensorFloat32 != capabilities.relaxedFloat32toFloat16PerformanceTensor ||
- perfFloat32 != capabilities.relaxedFloat32toFloat16PerformanceScalar) {
- return false;
- }
- return isQuantized8PerformanceConsistentWithP(capabilities);
- }
- bool compliantWithV1_1(const V1_0::Capabilities&) {
- return true;
- }
- bool compliantWithV1_1(const V1_1::Capabilities&) {
- return true;
- }
- bool compliantWithV1_1(const V1_2::Capabilities& capabilities) {
- if ((capabilities.relaxedFloat32toFloat16PerformanceTensor !=
- capabilities.relaxedFloat32toFloat16PerformanceScalar) ||
- (lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32) !=
- lookup(capabilities.operandPerformance, OperandType::FLOAT32))) {
- return false;
- }
- return isQuantized8PerformanceConsistentWithP(capabilities);
- }
- bool compliantWithV1_2(const V1_0::Capabilities&) {
- return true;
- }
- bool compliantWithV1_2(const V1_1::Capabilities&) {
- return true;
- }
- bool compliantWithV1_2(const V1_0::Model&) {
- return true;
- }
- bool compliantWithV1_0(const V1_1::Model& model) {
- // In addition to new enumeration values being introduced in V1_1::Model, a
- // new flag was introduced to indicate whether or not float32 data can be
- // calculated using float16 units. This 'relaxComputationFloat32toFloat16'
- // flag is not relevant in whether a V1_1::Model is compliant with a
- // V1_0::Model because all 1.0 drivers require strict calculation by default
- // in the P NN runtime. Even if fp16 calculations are allowed, they can
- // still be computed by a strict fp32 driver.
- return std::all_of(
- model.operations.begin(), model.operations.end(), [&model](const V1_1::Operation& op) {
- int error = validateOperation(static_cast<int32_t>(op.type), op.inputs.size(),
- op.inputs.size() > 0 ? op.inputs.data() : nullptr,
- op.outputs.size(),
- op.outputs.size() > 0 ? op.outputs.data() : nullptr,
- convertToV1_2(model.operands), HalVersion::V1_0);
- return error == ANEURALNETWORKS_NO_ERROR;
- });
- }
- bool compliantWithV1_1(const V1_0::Model&) {
- return true;
- }
- bool compliantWithV1_1(const V1_1::Model&) {
- return true;
- }
- static V1_0::OperationType uncheckedConvertToV1_0(V1_1::OperationType type) {
- return static_cast<V1_0::OperationType>(type);
- }
- static V1_1::OperationType convertToV1_1(V1_0::OperationType type) {
- return static_cast<V1_1::OperationType>(type);
- }
- V1_0::Capabilities convertToV1_0(const V1_0::Capabilities& capabilities) {
- return capabilities;
- }
- V1_0::Capabilities convertToV1_0(const V1_1::Capabilities& capabilities) {
- if (!compliantWithV1_0(capabilities)) {
- LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
- << " from V1_1::Capabilities to V1_0::Capabilities";
- }
- return { .float32Performance = capabilities.float32Performance,
- .quantized8Performance = capabilities.quantized8Performance };
- }
- V1_0::Capabilities convertToV1_0(const V1_2::Capabilities& capabilities) {
- if (!compliantWithV1_0(capabilities)) {
- LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
- << " from V1_2::Capabilities to V1_0::Capabilities";
- }
- return {.float32Performance =
- lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32),
- .quantized8Performance =
- lookup(capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM)};
- }
- V1_1::Capabilities convertToV1_1(const V1_0::Capabilities& capabilities) {
- return { .float32Performance = capabilities.float32Performance,
- .quantized8Performance = capabilities.quantized8Performance,
- .relaxedFloat32toFloat16Performance = capabilities.float32Performance };
- }
- V1_1::Capabilities convertToV1_1(const V1_1::Capabilities& capabilities) {
- return capabilities;
- }
- V1_1::Capabilities convertToV1_1(const V1_2::Capabilities& capabilities) {
- if (!compliantWithV1_1(capabilities)) {
- LOG(ERROR) << "Upcasting non-compliant capabilities " << toString(capabilities)
- << " from V1_2::Capabilities to V1_1::Capabilities";
- }
- return {.float32Performance =
- lookup(capabilities.operandPerformance, OperandType::TENSOR_FLOAT32),
- .quantized8Performance =
- lookup(capabilities.operandPerformance, OperandType::TENSOR_QUANT8_ASYMM),
- .relaxedFloat32toFloat16Performance =
- capabilities.relaxedFloat32toFloat16PerformanceTensor};
- }
- V1_2::Capabilities convertToV1_2(const V1_0::Capabilities& capabilities) {
- V1_2::Capabilities ret = {
- .relaxedFloat32toFloat16PerformanceScalar = capabilities.float32Performance,
- .relaxedFloat32toFloat16PerformanceTensor = capabilities.float32Performance,
- .operandPerformance =
- makeQuantized8PerformanceConsistentWithP(capabilities.quantized8Performance)};
- auto& opPerf = ret.operandPerformance;
- opPerf.resize(opPerf.size() + 2);
- opPerf[opPerf.size() - 2] = {OperandType::TENSOR_FLOAT32, capabilities.float32Performance};
- opPerf[opPerf.size() - 1] = {OperandType::FLOAT32, capabilities.float32Performance};
- using OperandPerformance = V1_2::Capabilities::OperandPerformance;
- std::sort(opPerf.begin(), opPerf.end(),
- [](const OperandPerformance& a, const OperandPerformance& b) {
- return a.type < b.type;
- });
- return ret;
- }
- V1_2::Capabilities convertToV1_2(const V1_1::Capabilities& capabilities) {
- V1_2::Capabilities ret = {.relaxedFloat32toFloat16PerformanceScalar =
- capabilities.relaxedFloat32toFloat16Performance,
- .relaxedFloat32toFloat16PerformanceTensor =
- capabilities.relaxedFloat32toFloat16Performance,
- .operandPerformance = makeQuantized8PerformanceConsistentWithP(
- capabilities.quantized8Performance)};
- auto& opPerf = ret.operandPerformance;
- opPerf.resize(opPerf.size() + 2);
- opPerf[opPerf.size() - 2] = {OperandType::TENSOR_FLOAT32, capabilities.float32Performance};
- opPerf[opPerf.size() - 1] = {OperandType::FLOAT32, capabilities.float32Performance};
- using OperandPerformance = V1_2::Capabilities::OperandPerformance;
- std::sort(opPerf.begin(), opPerf.end(),
- [](const OperandPerformance& a, const OperandPerformance& b) {
- return a.type < b.type;
- });
- return ret;
- }
- V1_2::Capabilities convertToV1_2(const V1_2::Capabilities& capabilities) {
- return capabilities;
- }
- static V1_0::Operation uncheckedConvertToV1_0(const V1_1::Operation& operation) {
- return {.type = uncheckedConvertToV1_0(operation.type),
- .inputs = operation.inputs,
- .outputs = operation.outputs};
- }
- static V1_1::Operation convertToV1_1(const V1_0::Operation& operation) {
- return {.type = convertToV1_1(operation.type),
- .inputs = operation.inputs,
- .outputs = operation.outputs};
- }
- static hidl_vec<V1_0::Operation> uncheckedConvertToV1_0(
- const hidl_vec<V1_1::Operation>& operations) {
- hidl_vec<V1_0::Operation> result(operations.size());
- std::transform(
- operations.begin(), operations.end(), result.begin(),
- [](const V1_1::Operation& operation) { return uncheckedConvertToV1_0(operation); });
- return result;
- }
- static hidl_vec<V1_1::Operation> convertToV1_1(const hidl_vec<V1_0::Operation>& operations) {
- hidl_vec<V1_1::Operation> result(operations.size());
- std::transform(operations.begin(), operations.end(), result.begin(),
- [](const V1_0::Operation& operation) { return convertToV1_1(operation); });
- return result;
- }
- bool compliantWithV1_0(const V1_2::Operand& operand) {
- return validOperandType(static_cast<V1_0::OperandType>(operand.type)) &&
- (nonExtensionOperandTypeIsScalar(static_cast<int>(operand.type)) ||
- operand.dimensions.size() != 0);
- }
- V1_0::Model convertToV1_0(const V1_0::Model& model) {
- return model;
- }
- V1_0::Model convertToV1_0(const V1_1::Model& model) {
- if (!compliantWithV1_0(model)) {
- LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
- << " from V1_1::Model to V1_0::Model";
- }
- return {.operands = model.operands,
- .operations = uncheckedConvertToV1_0(model.operations),
- .inputIndexes = model.inputIndexes,
- .outputIndexes = model.outputIndexes,
- .operandValues = model.operandValues,
- .pools = model.pools};
- }
- V1_1::Model convertToV1_1(const V1_0::Model& model) {
- return {.operands = model.operands,
- .operations = convertToV1_1(model.operations),
- .inputIndexes = model.inputIndexes,
- .outputIndexes = model.outputIndexes,
- .operandValues = model.operandValues,
- .pools = model.pools,
- .relaxComputationFloat32toFloat16 = false};
- }
- V1_1::Model convertToV1_1(const V1_1::Model& model) {
- return model;
- }
- void logModelToInfo(const V1_2::Model& model) {
- LOG(INFO) << "V1_2::Model start";
- LOG(INFO) << "operands" << toString(model.operands);
- LOG(INFO) << "operations" << toString(model.operations);
- LOG(INFO) << "inputIndexes" << toString(model.inputIndexes);
- LOG(INFO) << "outputIndexes" << toString(model.outputIndexes);
- LOG(INFO) << "operandValues size" << model.operandValues.size();
- LOG(INFO) << "pools" << SHOW_IF_DEBUG(toString(model.pools));
- }
- static bool compliantWith(HalVersion version, const V1_2::Model& model,
- std::set<uint32_t>* noncompliantOperations) {
- if (version >= HalVersion::V1_2) return true;
- // A boolean vector indicating whether each pool is compliant with the target HAL version.
- std::vector<bool> isPoolCompliant(model.pools.size(), false);
- std::transform(model.pools.begin(), model.pools.end(), isPoolCompliant.begin(),
- [version](const hidl_memory& pool) { return validatePool(pool, version); });
- // A boolean vector indicating whether each operand is compliant with the target HAL version.
- std::vector<bool> isOperandCompliant(model.operands.size(), false);
- std::transform(model.operands.begin(), model.operands.end(), isOperandCompliant.begin(),
- [&isPoolCompliant](const V1_2::Operand& op) {
- // There is no V1_1::Operand -- both V1_0::Model and V1_1::Model use
- // V1_0::Operand.
- return compliantWithV1_0(op) &&
- !(op.lifetime == OperandLifeTime::CONSTANT_REFERENCE &&
- !isPoolCompliant[op.location.poolIndex]);
- });
- auto allOperandsCompliant = [&isOperandCompliant](const hidl_vec<uint32_t>& indices) {
- return std::all_of(
- indices.begin(), indices.end(),
- [&isOperandCompliant](const uint32_t ind) { return isOperandCompliant[ind]; });
- };
- auto localValidateOperation = [&model, version,
- &allOperandsCompliant](const V1_2::Operation& op) {
- if (!allOperandsCompliant(op.inputs) || !allOperandsCompliant(op.outputs)) return false;
- int error = validateOperation(
- static_cast<int32_t>(op.type), op.inputs.size(),
- op.inputs.size() > 0 ? op.inputs.data() : nullptr, op.outputs.size(),
- op.outputs.size() > 0 ? op.outputs.data() : nullptr, model.operands, version);
- return error == ANEURALNETWORKS_NO_ERROR;
- };
- if (noncompliantOperations) {
- CHECK(noncompliantOperations->empty());
- for (uint32_t idx = 0; idx < model.operations.size(); ++idx) {
- if (!localValidateOperation(model.operations[idx])) {
- noncompliantOperations->insert(idx);
- }
- }
- return noncompliantOperations->empty();
- } else {
- return std::all_of(model.operations.begin(), model.operations.end(),
- localValidateOperation);
- }
- }
- bool compliantWithV1_0(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations) {
- return compliantWith(HalVersion::V1_0, model, noncompliantOperations);
- }
- bool compliantWithV1_1(const V1_2::Model& model, std::set<uint32_t>* noncompliantOperations) {
- return compliantWith(HalVersion::V1_1, model, noncompliantOperations);
- }
- V1_0::OperationType uncheckedConvertToV1_0(V1_2::OperationType type) {
- return static_cast<V1_0::OperationType>(type);
- }
- V1_1::OperationType uncheckedConvertToV1_1(V1_2::OperationType type) {
- return static_cast<V1_1::OperationType>(type);
- }
- static V1_2::OperationType convertToV1_2(V1_0::OperationType type) {
- return static_cast<V1_2::OperationType>(type);
- }
- static V1_2::OperationType convertToV1_2(V1_1::OperationType type) {
- return static_cast<V1_2::OperationType>(type);
- }
- static V1_0::Operation uncheckedConvertToV1_0(const V1_2::Operation& operation) {
- return {.type = uncheckedConvertToV1_0(operation.type),
- .inputs = operation.inputs,
- .outputs = operation.outputs};
- }
- static V1_1::Operation uncheckedConvertToV1_1(const V1_2::Operation& operation) {
- return {.type = uncheckedConvertToV1_1(operation.type),
- .inputs = operation.inputs,
- .outputs = operation.outputs};
- }
- static V1_2::Operation convertToV1_2(const V1_0::Operation& operation) {
- return {.type = convertToV1_2(operation.type),
- .inputs = operation.inputs,
- .outputs = operation.outputs};
- }
- static V1_2::Operation convertToV1_2(const V1_1::Operation& operation) {
- return {.type = convertToV1_2(operation.type),
- .inputs = operation.inputs,
- .outputs = operation.outputs};
- }
- static hidl_vec<V1_0::Operation> uncheckedConvertToV1_0(
- const hidl_vec<V1_2::Operation>& operations) {
- hidl_vec<V1_0::Operation> result(operations.size());
- std::transform(
- operations.begin(), operations.end(), result.begin(),
- [](const V1_2::Operation& operation) { return uncheckedConvertToV1_0(operation); });
- return result;
- }
- static hidl_vec<V1_1::Operation> uncheckedConvertToV1_1(
- const hidl_vec<V1_2::Operation>& operations) {
- hidl_vec<V1_1::Operation> result(operations.size());
- std::transform(
- operations.begin(), operations.end(), result.begin(),
- [](const V1_2::Operation& operation) { return uncheckedConvertToV1_1(operation); });
- return result;
- }
- static hidl_vec<V1_2::Operation> convertToV1_2(const hidl_vec<V1_0::Operation>& operations) {
- hidl_vec<V1_2::Operation> result(operations.size());
- std::transform(operations.begin(), operations.end(), result.begin(),
- [](const V1_0::Operation& operation) { return convertToV1_2(operation); });
- return result;
- }
- static hidl_vec<V1_2::Operation> convertToV1_2(const hidl_vec<V1_1::Operation>& operations) {
- hidl_vec<V1_2::Operation> result(operations.size());
- std::transform(operations.begin(), operations.end(), result.begin(),
- [](const V1_1::Operation& operation) { return convertToV1_2(operation); });
- return result;
- }
- // We only need to convert from 1.0 and back since there wasn't any changes to
- // Operand in 1.1
- V1_2::OperandType convertToV1_2(const V1_0::OperandType& operandType) {
- return static_cast<V1_2::OperandType>(operandType);
- }
- static bool compliantWithV1_0(const V1_2::OperandType& operandType) {
- return validOperandType(static_cast<V1_0::OperandType>(operandType));
- }
- V1_0::OperandType convertToV1_0(const V1_2::OperandType& operandType) {
- if (!compliantWithV1_0(operandType)) {
- LOG(ERROR) << "Upcasting non-compliant operand type " << toString(operandType)
- << " from V1_2::Operand to V1_0::Operand";
- }
- return static_cast<V1_0::OperandType>(operandType);
- }
- // We only need to convert from 1.0 and back since there wasn't any changes to
- // Operand in 1.1
- V1_2::Operand convertToV1_2(const V1_0::Operand& operand) {
- return {.type = convertToV1_2(operand.type),
- .dimensions = operand.dimensions,
- .numberOfConsumers = operand.numberOfConsumers,
- .scale = operand.scale,
- .zeroPoint = operand.zeroPoint,
- .lifetime = operand.lifetime,
- .location = operand.location};
- }
- V1_2::Operand convertToV1_2(const V1_2::Operand& operand) {
- return operand;
- }
- V1_0::Operand convertToV1_0(const V1_2::Operand& operand) {
- return {.type = convertToV1_0(operand.type),
- .dimensions = operand.dimensions,
- .numberOfConsumers = operand.numberOfConsumers,
- .scale = operand.scale,
- .zeroPoint = operand.zeroPoint,
- .lifetime = operand.lifetime,
- .location = operand.location};
- }
- // We only need to convert from 1.0 and back since there wasn't any changes to
- // Operand in 1.1
- hidl_vec<V1_2::Operand> convertToV1_2(const hidl_vec<V1_0::Operand>& operands) {
- hidl_vec<V1_2::Operand> result(operands.size());
- std::transform(operands.begin(), operands.end(), result.begin(),
- [](const V1_0::Operand& operand) { return convertToV1_2(operand); });
- return result;
- }
- hidl_vec<V1_2::Operand> convertToV1_2(const hidl_vec<V1_2::Operand>& operands) {
- return operands;
- }
- hidl_vec<V1_0::Operand> convertToV1_0(const hidl_vec<V1_2::Operand>& operands) {
- hidl_vec<V1_0::Operand> result(operands.size());
- std::transform(operands.begin(), operands.end(), result.begin(),
- [](const V1_2::Operand& operand) { return convertToV1_0(operand); });
- return result;
- }
- V1_0::Model convertToV1_0(const V1_2::Model& model) {
- if (!compliantWithV1_0(model)) {
- LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
- << " from V1_2::Model to V1_0::Model";
- }
- return {.operands = convertToV1_0(model.operands),
- .operations = uncheckedConvertToV1_0(model.operations),
- .inputIndexes = model.inputIndexes,
- .outputIndexes = model.outputIndexes,
- .operandValues = model.operandValues,
- .pools = model.pools};
- }
- V1_1::Model convertToV1_1(const V1_2::Model& model) {
- if (!compliantWithV1_1(model)) {
- LOG(ERROR) << "Upcasting non-compliant model " << SHOW_IF_DEBUG(toString(model))
- << " from V1_2::Model to V1_1::Model";
- }
- return {.operands = convertToV1_0(model.operands), // Operands in 1.1 and 1.0 are identical.
- .operations = uncheckedConvertToV1_1(model.operations),
- .inputIndexes = model.inputIndexes,
- .outputIndexes = model.outputIndexes,
- .operandValues = model.operandValues,
- .pools = model.pools,
- .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16};
- }
- V1_2::Model convertToV1_2(const V1_0::Model& model) {
- return {.operands = convertToV1_2(model.operands),
- .operations = convertToV1_2(model.operations),
- .inputIndexes = model.inputIndexes,
- .outputIndexes = model.outputIndexes,
- .operandValues = model.operandValues,
- .pools = model.pools,
- .relaxComputationFloat32toFloat16 = false};
- }
- V1_2::Model convertToV1_2(const V1_1::Model& model) {
- return {.operands = convertToV1_2(model.operands),
- .operations = convertToV1_2(model.operations),
- .inputIndexes = model.inputIndexes,
- .outputIndexes = model.outputIndexes,
- .operandValues = model.operandValues,
- .pools = model.pools,
- .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16};
- }
- V1_2::Model convertToV1_2(const V1_2::Model& model) {
- return model;
- }
- #ifdef NN_DEBUGGABLE
- uint32_t getProp(const char* str, uint32_t defaultValue) {
- const std::string propStr = android::base::GetProperty(str, "");
- if (propStr.size() > 0) {
- return std::stoi(propStr);
- } else {
- return defaultValue;
- }
- }
- #endif // NN_DEBUGGABLE
- } // namespace nn
- } // namespace android
|