From 9c3cae8683e4b24932446b88d3ecbc02f9f9fa08 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Thu, 1 Aug 2019 16:01:48 +0100 Subject: IVGCVSW-3470 Add Quantized_LSTM tests * Added Layer and Create Workload tests for the new Quantized LSTM layer. * Tests to be enabled on NEON and CL in their respective patches. Signed-off-by: James Conroy Change-Id: I7e9e9768dd63010ab58367c45fffcff452377cfb --- src/backends/backendsCommon/test/LstmTestImpl.hpp | 191 +++++++++++++++++++++- 1 file changed, 190 insertions(+), 1 deletion(-) (limited to 'src/backends/backendsCommon/test/LstmTestImpl.hpp') diff --git a/src/backends/backendsCommon/test/LstmTestImpl.hpp b/src/backends/backendsCommon/test/LstmTestImpl.hpp index 2ed0a974fc..cd1f524879 100644 --- a/src/backends/backendsCommon/test/LstmTestImpl.hpp +++ b/src/backends/backendsCommon/test/LstmTestImpl.hpp @@ -128,7 +128,7 @@ void LstmUtilsVectorBatchVectorCwiseProductTestImpl( } // Lstm Layer tests: - +// *********************************** // template> LayerTestResult LstmNoCifgNoPeepholeNoProjectionTestImpl( @@ -1540,4 +1540,193 @@ LstmLayerNoCifgWithPeepholeWithProjectionWithLayerNormTestImpl(armnn::IWorkloadF return ret; +} + +// QuantizedLstm tests: + +LayerTestResult +QuantizedLstmTestImpl(armnn::IWorkloadFactory& workloadFactory, + const armnn::IBackendInternal::IMemoryManagerSharedPtr& memoryManager, + const boost::multi_array& input, + const boost::multi_array& outputExpected) +{ + + auto numBatches = boost::numeric_cast(input.shape()[0]); + auto inputSize = boost::numeric_cast(input.shape()[1]); + auto outputSize = boost::numeric_cast(outputExpected.shape()[1]); + + // Scale/Offset for input/output, cellState In/Out, weights, bias + float inputOutputScale = 0.0078125f; + int32_t inputOutputOffset = 128; + + float cellStateScale = 0.00048828125f; + int32_t cellStateOffset = 0; + + float weightsScale = 0.00408021f; + int32_t weightsOffset = 100; + + float biasScale = 3.1876640625e-05f; + int32_t biasOffset = 0; + + // Input/Output tensor info + armnn::TensorInfo inputInfo({numBatches , inputSize}, + armnn::DataType::QuantisedAsymm8, + inputOutputScale, + inputOutputOffset); + + armnn::TensorInfo cellStateInfo({numBatches , outputSize}, + armnn::DataType::QuantisedSymm16, + cellStateScale, + cellStateOffset); + + armnn::TensorInfo outputStateInfo({numBatches , outputSize}, + armnn::DataType::QuantisedAsymm8, + inputOutputScale, + inputOutputOffset); + + LayerTestResult ret(outputStateInfo); + + // Input0 + std::vector inputVector; + inputVector.assign(input.data(), input.data() + (numBatches * inputSize)); + auto inputTensor = MakeTensor(inputInfo, inputVector); + + // Input1 + std::vector cellStateInVector = {876, 1034, 955, -909, 761, 1029, 796, -1036}; // 13 + auto cellStateInTensor = MakeTensor(cellStateInfo, cellStateInVector); + + // Input2 + std::vector outputStateInVector = {136, 150, 140, 115, 135, 152, 138, 112}; // 14 + auto outputStateInTensor = MakeTensor(outputStateInfo, outputStateInVector); + + // Output0 + std::vector cellStateOutVector = {1485, 1177, 1373, -1023, 1019, 1355, 1097, -1235}; // 0 + auto cellStateOutTensor = MakeTensor(cellStateInfo, cellStateOutVector); + + // Output1 + std::vector outputVector; // 1 + outputVector.assign(outputExpected.data(), outputExpected.data() + (numBatches * outputSize)); + ret.outputExpected = MakeTensor(outputStateInfo, outputVector); + + // Create tensor handles + std::unique_ptr inputHandle = workloadFactory.CreateTensorHandle(inputInfo); + std::unique_ptr cellStateInHandle = + workloadFactory.CreateTensorHandle(cellStateInfo); + std::unique_ptr outputStateInHandle = + workloadFactory.CreateTensorHandle(outputStateInfo); + + std::unique_ptr cellStateOutHandle = + workloadFactory.CreateTensorHandle(cellStateInfo); + std::unique_ptr outputHandle = workloadFactory.CreateTensorHandle(outputStateInfo); + + armnn::QuantizedLstmQueueDescriptor data; + armnn::WorkloadInfo info; + + // Add inputs and outputs to workload + AddInputToWorkload(data, info, inputInfo, inputHandle.get()); + AddInputToWorkload(data, info, cellStateInfo, cellStateInHandle.get()); + AddInputToWorkload(data, info, outputStateInfo, outputStateInHandle.get()); + + AddOutputToWorkload(data, info, cellStateInfo, cellStateOutHandle.get()); + AddOutputToWorkload(data, info, outputStateInfo, outputHandle.get()); + + // Weights and bias tensor and quantization info + armnn::TensorInfo inputWeightsInfo({outputSize, inputSize}, + armnn::DataType::QuantisedAsymm8, + weightsScale, + weightsOffset); + + armnn::TensorInfo recurrentWeightsInfo({outputSize, outputSize}, + armnn::DataType::QuantisedAsymm8, + weightsScale, + weightsOffset); + + armnn::TensorInfo biasInfo({outputSize}, armnn::DataType::Signed32, biasScale, biasOffset); + + // Weights and bias tensor data + auto inputToInputWeights = MakeTensor(inputWeightsInfo, {146, 250, 235, 171, 10, 218, 171, 108}); + auto inputToForgetWeights = MakeTensor(inputWeightsInfo, {24, 50, 132, 179, 158, 110, 3, 169}); + auto inputToCellWeights = MakeTensor(inputWeightsInfo, {133, 34, 29, 49, 206, 109, 54, 183}); + auto inputToOutputWeights = MakeTensor(inputWeightsInfo, {195, 187, 11, 99, 109, 10, 218, 48}); + + auto recurrentToInputWeights = MakeTensor(recurrentWeightsInfo, + {254, 206, 77, 168, 71, 20, 215, 6, 223, 7, 118, 225, 59, 130, 174, 26}); + auto recurrentToForgetWeights = MakeTensor(recurrentWeightsInfo, + {137, 240, 103, 52, 68, 51, 237, 112, 0, 220, 89, 23, 69, 4, 207, 253}); + auto recurrentToCellWeights = MakeTensor(recurrentWeightsInfo, + {172, 60, 205, 65, 14, 0, 140, 168, 240, 223, 133, 56, 142, 64, 246, 216}); + auto recurrentToOutputWeights = MakeTensor(recurrentWeightsInfo, + {106, 214, 67, 23, 59, 158, 45, 3, 119, 132, 49, 205, 129, 218, 11, 98}); + + auto inputGateBias = MakeTensor(biasInfo, {-7876, 13488, -726, 32839}); + auto forgetGateBias = MakeTensor(biasInfo, {9206, -46884, -11693, -38724}); + auto cellBias = MakeTensor(biasInfo, {39481, 48624, 48976, -21419}); + auto outputGateBias = MakeTensor(biasInfo, {-58999, -17050, -41852, -40538}); + + // ScopedCpuTensorHandles + armnn::ScopedCpuTensorHandle inputToInputWeightsTensor(inputWeightsInfo); + armnn::ScopedCpuTensorHandle inputToForgetWeightsTensor(inputWeightsInfo); + armnn::ScopedCpuTensorHandle inputToCellWeightsTensor(inputWeightsInfo); + armnn::ScopedCpuTensorHandle inputToOutputWeightsTensor(inputWeightsInfo); + + armnn::ScopedCpuTensorHandle recurrentToInputWeightsTensor(recurrentWeightsInfo); + armnn::ScopedCpuTensorHandle recurrentToForgetWeightsTensor(recurrentWeightsInfo); + armnn::ScopedCpuTensorHandle recurrentToCellWeightsTensor(recurrentWeightsInfo); + armnn::ScopedCpuTensorHandle recurrentToOutputWeightsTensor(recurrentWeightsInfo); + + armnn::ScopedCpuTensorHandle inputGateBiasTensor(biasInfo); + armnn::ScopedCpuTensorHandle forgetGateBiasTensor(biasInfo); + armnn::ScopedCpuTensorHandle cellBiasTensor(biasInfo); + armnn::ScopedCpuTensorHandle outputGateBiasTensor(biasInfo); + + // Allocate and copy data + AllocateAndCopyDataToITensorHandle(&inputToInputWeightsTensor, &inputToInputWeights[0][0]); + AllocateAndCopyDataToITensorHandle(&inputToForgetWeightsTensor, &inputToForgetWeights[0][0]); + AllocateAndCopyDataToITensorHandle(&inputToCellWeightsTensor, &inputToCellWeights[0][0]); + AllocateAndCopyDataToITensorHandle(&inputToOutputWeightsTensor, &inputToOutputWeights[0][0]); + + AllocateAndCopyDataToITensorHandle(&recurrentToInputWeightsTensor, &recurrentToInputWeights[0][0]); + AllocateAndCopyDataToITensorHandle(&recurrentToForgetWeightsTensor, &recurrentToForgetWeights[0][0]); + AllocateAndCopyDataToITensorHandle(&recurrentToCellWeightsTensor, &recurrentToCellWeights[0][0]); + AllocateAndCopyDataToITensorHandle(&recurrentToOutputWeightsTensor, &recurrentToOutputWeights[0][0]); + + AllocateAndCopyDataToITensorHandle(&inputGateBiasTensor, &inputGateBias[0]); + AllocateAndCopyDataToITensorHandle(&forgetGateBiasTensor, &forgetGateBias[0]); + AllocateAndCopyDataToITensorHandle(&cellBiasTensor, &cellBias[0]); + AllocateAndCopyDataToITensorHandle(&outputGateBiasTensor, &outputGateBias[0]); + + // Setup queue descriptor + data.m_InputToInputWeights = &inputToInputWeightsTensor; + data.m_InputToForgetWeights = &inputToForgetWeightsTensor; + data.m_InputToCellWeights = &inputToCellWeightsTensor; + data.m_InputToOutputWeights = &inputToOutputWeightsTensor; + + data.m_RecurrentToInputWeights = &recurrentToInputWeightsTensor; + data.m_RecurrentToForgetWeights = &recurrentToForgetWeightsTensor; + data.m_RecurrentToCellWeights = &recurrentToCellWeightsTensor; + data.m_RecurrentToOutputWeights = &recurrentToOutputWeightsTensor; + + data.m_InputGateBias = &inputGateBiasTensor; + data.m_ForgetGateBias = &forgetGateBiasTensor; + data.m_CellBias = &cellBiasTensor; + data.m_OutputGateBias = &outputGateBiasTensor; + + // Create workload and allocate tensor handles + std::unique_ptr workload = workloadFactory.CreateQuantizedLstm(data, info); + inputHandle->Allocate(); + outputStateInHandle->Allocate(); + cellStateInHandle->Allocate(); + + cellStateOutHandle->Allocate(); + outputHandle->Allocate(); + + CopyDataToITensorHandle(inputHandle.get(), &inputTensor[0][0]); + CopyDataToITensorHandle(outputStateInHandle.get(), &outputStateInTensor[0][0]); + CopyDataToITensorHandle(cellStateInHandle.get(), &cellStateInTensor[0][0]); + + workload->Execute(); + + CopyDataFromITensorHandle(&ret.output[0][0], outputHandle.get()); + + return ret; } \ No newline at end of file -- cgit v1.2.1