diff --git a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h index 0050e52d25..a64268f46e 100644 --- a/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h +++ b/neuralnetworks/1.1/vts/functional/VtsHalNeuralnetworks.h @@ -34,9 +34,11 @@ namespace hardware { namespace neuralnetworks { namespace V1_1 { -using V1_0::Request; using V1_0::DeviceStatus; using V1_0::ErrorStatus; +using V1_0::Operand; +using V1_0::OperandType; +using V1_0::Request; namespace vts { namespace functional { diff --git a/neuralnetworks/1.2/Android.bp b/neuralnetworks/1.2/Android.bp index e183a263fa..3c4ff8bfbe 100644 --- a/neuralnetworks/1.2/Android.bp +++ b/neuralnetworks/1.2/Android.bp @@ -17,6 +17,8 @@ hidl_interface { ], types: [ "Model", + "Operand", + "OperandType", "Operation", "OperationType", ], diff --git a/neuralnetworks/1.2/types.hal b/neuralnetworks/1.2/types.hal index bed1d5cad9..95e97c4b6b 100644 --- a/neuralnetworks/1.2/types.hal +++ b/neuralnetworks/1.2/types.hal @@ -16,10 +16,22 @@ package android.hardware.neuralnetworks@1.2; -import @1.0::Operand; +import @1.0::DataLocation; +import @1.0::OperandLifeTime; +import @1.0::OperandType; import @1.0::PerformanceInfo; import @1.1::OperationType; +enum OperandType : @1.0::OperandType { + /** + * An 8 bit boolean scalar value. + * + * Values of this operand type are either true or false. A zero value + * represents false; any other value represents true. + */ + BOOL = 6, +}; + /** * Operation types. * @@ -101,6 +113,101 @@ struct Operation { vec outputs; }; +/** + * Describes one operand of the model's graph. + */ +struct Operand { + /** + * Data type of the operand. + */ + OperandType type; + + /** + * Dimensions of the operand. + * + * For a scalar operand, dimensions.size() must be 0. + * + * For a tensor operand, dimensions.size() must be at least 1; + * however, any of the dimensions may be unspecified. + * + * A tensor operand with all dimensions specified has "fully + * specified" dimensions. Whenever possible (i.e., whenever the + * dimensions are known at model construction time), a tensor + * operand should have (but is not required to have) fully + * specified dimensions, in order to enable the best possible + * performance. + * + * If a tensor operand's dimensions are not fully specified, the + * dimensions of the operand are deduced from the operand + * dimensions and values of the operation for which that operand + * is an output. + * + * In the following situations, a tensor operand's dimensions must + * be fully specified: + * + * . The operand has lifetime CONSTANT_COPY or + * CONSTANT_REFERENCE. + * + * . The operand has lifetime MODEL_INPUT or MODEL_OUTPUT. Fully + * specified dimensions must either be present in the + * Operand or they must be provided in the corresponding + * RequestArgument. + * EXCEPTION: If the input or output is optional and omitted + * (by setting the hasNoValue field of the corresponding + * RequestArgument to true) then it need not have fully + * specified dimensions. + * + * A tensor operand with some number of unspecified dimensions is + * represented by setting each unspecified dimension to 0. + */ + vec dimensions; + + /** + * The number of times this operand appears as an operation input. + * + * (For example, if this operand appears once in one operation's + * input list, and three times in another operation's input list, + * then numberOfConsumers = 4.) + */ + uint32_t numberOfConsumers; + + /** + * Quantized scale of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM or + * TENSOR_INT32. + */ + float scale; + + /** + * Quantized zero-point offset of the operand. + * + * Only applicable if the operand is of type TENSOR_QUANT8_ASYMM. + */ + int32_t zeroPoint; + + /** + * How the operand is used. + */ + OperandLifeTime lifetime; + + /** + * Where to find the data for this operand. + * If the lifetime is TEMPORARY_VARIABLE, MODEL_INPUT, MODEL_OUTPUT, or + * NO_VALUE: + * - All the fields must be 0. + * If the lifetime is CONSTANT_COPY: + * - location.poolIndex is 0. + * - location.offset is the offset in bytes into Model.operandValues. + * - location.length is set. + * If the lifetime is CONSTANT_REFERENCE: + * - location.poolIndex is set. + * - location.offset is the offset in bytes into the specified pool. + * - location.length is set. + */ + DataLocation location; +}; + /** * A Neural Network Model. * diff --git a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp index 7ec6ff183e..5a8b8c59c0 100644 --- a/neuralnetworks/1.2/vts/functional/ValidateModel.cpp +++ b/neuralnetworks/1.2/vts/functional/ValidateModel.cpp @@ -26,9 +26,7 @@ namespace neuralnetworks { namespace V1_2 { using V1_0::IPreparedModel; -using V1_0::Operand; using V1_0::OperandLifeTime; -using V1_0::OperandType; using V1_1::ExecutionPreference; namespace vts { @@ -131,10 +129,10 @@ static uint32_t addOperand(Model* model, OperandLifeTime lifetime) { ///////////////////////// VALIDATE MODEL OPERAND TYPE ///////////////////////// static const int32_t invalidOperandTypes[] = { - static_cast(OperandType::FLOAT32) - 1, // lower bound fundamental - static_cast(OperandType::TENSOR_QUANT8_ASYMM) + 1, // upper bound fundamental - static_cast(OperandType::OEM) - 1, // lower bound OEM - static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM + static_cast(OperandType::FLOAT32) - 1, // lower bound fundamental + static_cast(OperandType::BOOL) + 1, // upper bound fundamental + static_cast(OperandType::OEM) - 1, // lower bound OEM + static_cast(OperandType::TENSOR_OEM_BYTE) + 1, // upper bound OEM }; static void mutateOperandTypeTest(const sp& device, const Model& model) { @@ -157,6 +155,7 @@ static uint32_t getInvalidRank(OperandType type) { case OperandType::FLOAT32: case OperandType::INT32: case OperandType::UINT32: + case OperandType::BOOL: return 1; case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_INT32: @@ -185,6 +184,7 @@ static float getInvalidScale(OperandType type) { case OperandType::FLOAT32: case OperandType::INT32: case OperandType::UINT32: + case OperandType::BOOL: case OperandType::TENSOR_FLOAT32: return 1.0f; case OperandType::TENSOR_INT32: @@ -214,6 +214,7 @@ static std::vector getInvalidZeroPoints(OperandType type) { case OperandType::FLOAT32: case OperandType::INT32: case OperandType::UINT32: + case OperandType::BOOL: case OperandType::TENSOR_FLOAT32: case OperandType::TENSOR_INT32: return {1}; @@ -253,6 +254,7 @@ static void mutateOperand(Operand* operand, OperandType type) { case OperandType::FLOAT32: case OperandType::INT32: case OperandType::UINT32: + case OperandType::BOOL: newOperand.dimensions = hidl_vec(); newOperand.scale = 0.0f; newOperand.zeroPoint = 0;