aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin May <kevin.may@arm.com>2019-03-14 11:56:32 +0000
committerÁron Virginás-Tar <aron.virginas-tar@arm.com>2019-03-15 10:56:29 +0000
commitf29a2c55af463141fac7c92042bfdb9f00ba4ccd (patch)
tree675816444109edc6af2268d407e6e61971485841
parent7bac1d7e8a7bf82d7c481cf05e31ae76f91725a6 (diff)
downloadandroid-nn-driver-f29a2c55af463141fac7c92042bfdb9f00ba4ccd.tar.gz
MLCE-91 LSTM doesn't support optional input
* Add fix for optional NO_VALUE operands in ConversionUtils.hpp * Remove fail message for optional NO_VALUE in ConversionUtils.hpp * Add to existing tests and test helper to cover optional NO_VALUE Signed-off-by: Kevin May <kevin.may@arm.com> Change-Id: Icf36af1fc00d3fb33cdd77ff6d6618cc4700d3fd
-rw-r--r--ConversionUtils.hpp19
-rw-r--r--test/DriverTestHelpers.hpp14
-rw-r--r--test/Lstm.cpp35
3 files changed, 53 insertions, 15 deletions
diff --git a/ConversionUtils.hpp b/ConversionUtils.hpp
index c86ad93c..ca1f0aea 100644
--- a/ConversionUtils.hpp
+++ b/ConversionUtils.hpp
@@ -488,13 +488,16 @@ ConstTensorPin ConvertOperandToConstTensorPin(const Operand& operand,
return ConstTensorPin();
}
- if (operand.lifetime != OperandLifeTime::CONSTANT_COPY && operand.lifetime != OperandLifeTime::CONSTANT_REFERENCE)
+ if (!optional &&
+ operand.lifetime != OperandLifeTime::CONSTANT_COPY &&
+ operand.lifetime != OperandLifeTime::CONSTANT_REFERENCE &&
+ operand.lifetime != OperandLifeTime::NO_VALUE)
{
Fail("%s: invalid operand lifetime: %s", __func__, toString(operand.lifetime).c_str());
return ConstTensorPin();
}
- const void* const valueStart = GetOperandValueReadOnlyAddress(operand, model, data);
+ const void* const valueStart = GetOperandValueReadOnlyAddress(operand, model, data, optional);
if (!valueStart)
{
if (optional)
@@ -539,7 +542,8 @@ ConstTensorPin ConvertOperationInputToConstTensorPin(const HalOperation& operati
}
template<typename HalModel>
-const void* GetOperandValueReadOnlyAddress(const Operand& operand, const HalModel& model, const ConversionData& data)
+const void* GetOperandValueReadOnlyAddress(const Operand& operand, const HalModel& model, const ConversionData& data,
+ bool optional = false)
{
const void* valueStart = nullptr;
@@ -557,6 +561,15 @@ const void* GetOperandValueReadOnlyAddress(const Operand& operand, const HalMode
valueStart = GetMemoryFromPool(operand.location, data.m_MemPools);
break;
}
+ case OperandLifeTime::NO_VALUE:
+ {
+ // An optional input tensor with no values is not an error so should not register as a fail
+ if (optional)
+ {
+ valueStart = nullptr;
+ break;
+ }
+ }
default:
{
// Unsupported/invalid (e.g. can't get value of an input to the model)
diff --git a/test/DriverTestHelpers.hpp b/test/DriverTestHelpers.hpp
index 4d91ae22..394720ed 100644
--- a/test/DriverTestHelpers.hpp
+++ b/test/DriverTestHelpers.hpp
@@ -112,7 +112,8 @@ template<typename HalModel, typename T>
void AddTensorOperand(HalModel& model,
const hidl_vec<uint32_t>& dimensions,
const T* values,
- OperandType operandType = OperandType::TENSOR_FLOAT32)
+ OperandType operandType = OperandType::TENSOR_FLOAT32,
+ OperandLifeTime operandLifeTime = OperandLifeTime::CONSTANT_COPY)
{
uint32_t totalElements = 1;
for (uint32_t dim : dimensions)
@@ -121,9 +122,13 @@ void AddTensorOperand(HalModel& model,
}
DataLocation location = {};
- location.offset = model.operandValues.size();
location.length = totalElements * sizeof(T);
+ if(operandLifeTime == OperandLifeTime::CONSTANT_COPY)
+ {
+ location.offset = model.operandValues.size();
+ }
+
Operand op = {};
op.type = operandType;
op.dimensions = dimensions;
@@ -143,9 +148,10 @@ template<typename HalModel, typename T>
void AddTensorOperand(HalModel& model,
const hidl_vec<uint32_t>& dimensions,
const std::vector<T>& values,
- OperandType operandType = OperandType::TENSOR_FLOAT32)
+ OperandType operandType = OperandType::TENSOR_FLOAT32,
+ OperandLifeTime operandLifeTime = OperandLifeTime::CONSTANT_COPY)
{
- AddTensorOperand<HalModel, T>(model, dimensions, values.data(), operandType);
+ AddTensorOperand<HalModel, T>(model, dimensions, values.data(), operandType, operandLifeTime);
}
template<typename HalModel>
diff --git a/test/Lstm.cpp b/test/Lstm.cpp
index ea0405c6..66f2cf02 100644
--- a/test/Lstm.cpp
+++ b/test/Lstm.cpp
@@ -56,6 +56,17 @@ bool TolerantCompareEqual(float a, float b, float tolerance = 0.00001f)
return rd < tolerance;
}
+// Helper function to create an OperandLifeTime::NO_VALUE for testing.
+// To be used on optional input operands that have no values - these are valid and should be tested.
+OperandLifeTime CreateNoValueLifeTime(const hidl_vec<uint32_t>& dimensions)
+{
+ // Only create a NO_VALUE for optional operands that have no elements
+ if (dimensions.size() == 0 || dimensions[0] == 0)
+ {
+ return OperandLifeTime::NO_VALUE;
+ }
+ return OperandLifeTime::CONSTANT_COPY;
+}
} // anonymous namespace
// Add our own tests here since we fail the lstm tests which Google supplies (because of non-const weights)
@@ -126,7 +137,8 @@ void LstmTestImpl(const hidl_vec<uint32_t>& inputDimensions,
// 01: The input-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
// [num_units, input_size], where “num_units” corresponds to the number of cell units.
- AddTensorOperand(model, inputToInputWeightsDimensions, inputToInputWeightsValue);
+ AddTensorOperand(model, inputToInputWeightsDimensions, inputToInputWeightsValue, OperandType::TENSOR_FLOAT32,
+ CreateNoValueLifeTime(inputToInputWeightsDimensions));
// 02: The input-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
// [num_units, input_size].
AddTensorOperand(model, inputToForgetWeightsDimensions, inputToForgetWeightsValue);
@@ -138,7 +150,8 @@ void LstmTestImpl(const hidl_vec<uint32_t>& inputDimensions,
// 05: The recurrent-to-input weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
// [num_units, output_size], where “output_size” corresponds to either the number of cell units (i.e.,
// “num_units”), or the second dimension of the “projection_weights”, if defined.
- AddTensorOperand(model, recurrentToInputWeightsDimensions, recurrentToInputWeightsValue);
+ AddTensorOperand(model, recurrentToInputWeightsDimensions, recurrentToInputWeightsValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(recurrentToInputWeightsDimensions));
// 06: The recurrent-to-forget weights: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
// [num_units, output_size].
AddTensorOperand(model, recurrentToForgetWeightsDimensions, recurrentToForgetWeightsValue);
@@ -149,13 +162,17 @@ void LstmTestImpl(const hidl_vec<uint32_t>& inputDimensions,
// [num_units, output_size].
AddTensorOperand(model, recurrentToOutputWeightsDimensions, recurrentToOutputWeightsValue);
// 09: The cell-to-input weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
- AddTensorOperand(model, cellToInputWeightsDimensions, cellToInputWeightsValue);
+ AddTensorOperand(model, cellToInputWeightsDimensions, cellToInputWeightsValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(cellToInputWeightsDimensions));
// 10: The cell-to-forget weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
- AddTensorOperand(model, cellToForgetWeightsDimensions, cellToForgetWeightsValue);
+ AddTensorOperand(model, cellToForgetWeightsDimensions, cellToForgetWeightsValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(cellToForgetWeightsDimensions));
// 11: The cell-to-output weights: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
- AddTensorOperand(model, cellToOutputWeightsDimensions, cellToOutputWeightsValue);
+ AddTensorOperand(model, cellToOutputWeightsDimensions, cellToOutputWeightsValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(cellToOutputWeightsDimensions));
// 12: The input gate bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
- AddTensorOperand(model, inputGateBiasDimensions, inputGateBiasValue);
+ AddTensorOperand(model, inputGateBiasDimensions, inputGateBiasValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(inputGateBiasDimensions));
// 13: The forget gate bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
AddTensorOperand(model, forgetGateBiasDimensions, forgetGateBiasValue);
// 14: The cell bias: A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [num_units].
@@ -164,9 +181,11 @@ void LstmTestImpl(const hidl_vec<uint32_t>& inputDimensions,
AddTensorOperand(model, outputGateBiasDimensions, outputGateBiasValue);
// 16: The projection weights: Optional. A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape
// [output_size, num_units].
- AddTensorOperand(model, projectionWeightsDimensions, projectionWeightsValue);
+ AddTensorOperand(model, projectionWeightsDimensions, projectionWeightsValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(projectionWeightsDimensions));
// 17: The projection bias: Optional. A 1-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [output_size].
- AddTensorOperand(model, projectionBiasDimensions, projectionBiasValue);
+ AddTensorOperand(model, projectionBiasDimensions, projectionBiasValue,
+ OperandType::TENSOR_FLOAT32, CreateNoValueLifeTime(projectionBiasDimensions));
// 18: The output state: A 2-D tensor of ANEURALNETWORKS_TENSOR_FLOAT32, of shape [batch_size, output_size].
AddInputOperand(model, outputStateInDimensions);