From 586a9aac99312eb9cb304cbbd18cec46b9158e23 Mon Sep 17 00:00:00 2001 From: James Conroy Date: Fri, 20 Mar 2020 08:49:33 +0000 Subject: IVGCVSW-4549 Add front end for new QLSTM layer * Added new layer QLstm (Android R HAL 1.3) * Made necessary updates to APIs * Added unit tests * This layer is functionally equivalent to the original unquantized LSTM layer with some additonal quantization features added. Due to this, original LstmParams are used for this layer. Signed-off-by: James Conroy Change-Id: I5b7f2d2fb6e17e81573b41a31bc55f49ae79608f --- src/armnn/test/ConstTensorLayerVisitor.cpp | 793 ++++++++++++++++++++++++++++- src/armnn/test/ConstTensorLayerVisitor.hpp | 32 ++ src/armnn/test/InferOutputTests.cpp | 3 + src/armnn/test/InferOutputTests.hpp | 58 ++- 4 files changed, 868 insertions(+), 18 deletions(-) (limited to 'src/armnn/test') diff --git a/src/armnn/test/ConstTensorLayerVisitor.cpp b/src/armnn/test/ConstTensorLayerVisitor.cpp index ada665e4e9..7ef3dd2920 100644 --- a/src/armnn/test/ConstTensorLayerVisitor.cpp +++ b/src/armnn/test/ConstTensorLayerVisitor.cpp @@ -107,6 +107,104 @@ void TestLstmLayerVisitor::CheckInputParameters(const LstmInputParams& inputPara CheckConstTensorPtrs("CellBias", m_InputParams.m_CellBias, inputParams.m_CellBias); } +void TestQLstmLayerVisitor::CheckConstTensorPtrs(const std::string& name, + const ConstTensor* expected, + const ConstTensor* actual) +{ + if (expected == nullptr) + { + BOOST_CHECK_MESSAGE(actual == nullptr, name + " actual should have been a nullptr"); + } + else + { + BOOST_CHECK_MESSAGE(actual != nullptr, name + " actual should have been set"); + if (actual != nullptr) + { + CheckConstTensors(*expected, *actual); + } + } +} + +void TestQLstmLayerVisitor::CheckDescriptor(const QLstmDescriptor& descriptor) +{ + BOOST_CHECK(m_Descriptor.m_CellClip == descriptor.m_CellClip); + BOOST_CHECK(m_Descriptor.m_ProjectionClip == descriptor.m_ProjectionClip); + BOOST_CHECK(m_Descriptor.m_CifgEnabled == descriptor.m_CifgEnabled); + BOOST_CHECK(m_Descriptor.m_PeepholeEnabled == descriptor.m_PeepholeEnabled); + BOOST_CHECK(m_Descriptor.m_ProjectionEnabled == descriptor.m_ProjectionEnabled); +} + +void TestQLstmLayerVisitor::CheckInputParameters(const LstmInputParams& inputParams) +{ + CheckConstTensorPtrs("InputToInputWeights", + m_InputParams.m_InputToInputWeights, + inputParams.m_InputToInputWeights); + + CheckConstTensorPtrs("InputToForgetWeights", + m_InputParams.m_InputToForgetWeights, + inputParams.m_InputToForgetWeights); + + CheckConstTensorPtrs("InputToCellWeights", + m_InputParams.m_InputToCellWeights, + inputParams.m_InputToCellWeights); + + CheckConstTensorPtrs("InputToOutputWeights", + m_InputParams.m_InputToOutputWeights, + inputParams.m_InputToOutputWeights); + + CheckConstTensorPtrs("RecurrentToInputWeights", + m_InputParams.m_RecurrentToInputWeights, + inputParams.m_RecurrentToInputWeights); + + CheckConstTensorPtrs("RecurrentToForgetWeights", + m_InputParams.m_RecurrentToForgetWeights, + inputParams.m_RecurrentToForgetWeights); + + CheckConstTensorPtrs("RecurrentToCellWeights", + m_InputParams.m_RecurrentToCellWeights, + inputParams.m_RecurrentToCellWeights); + + CheckConstTensorPtrs("RecurrentToOutputWeights", + m_InputParams.m_RecurrentToOutputWeights, + inputParams.m_RecurrentToOutputWeights); + + CheckConstTensorPtrs("CellToInputWeights", + m_InputParams.m_CellToInputWeights, + inputParams.m_CellToInputWeights); + + CheckConstTensorPtrs("CellToForgetWeights", + m_InputParams.m_CellToForgetWeights, + inputParams.m_CellToForgetWeights); + + CheckConstTensorPtrs("CellToOutputWeights", + m_InputParams.m_CellToOutputWeights, + inputParams.m_CellToOutputWeights); + + CheckConstTensorPtrs("ProjectionWeights", m_InputParams.m_ProjectionWeights, inputParams.m_ProjectionWeights); + CheckConstTensorPtrs("ProjectionBias", m_InputParams.m_ProjectionBias, inputParams.m_ProjectionBias); + + CheckConstTensorPtrs("InputGateBias", m_InputParams.m_InputGateBias, inputParams.m_InputGateBias); + CheckConstTensorPtrs("ForgetGateBias", m_InputParams.m_ForgetGateBias, inputParams.m_ForgetGateBias); + CheckConstTensorPtrs("CellBias", m_InputParams.m_CellBias, inputParams.m_CellBias); + CheckConstTensorPtrs("OutputGateBias", m_InputParams.m_OutputGateBias, inputParams.m_OutputGateBias); + + CheckConstTensorPtrs("InputLayerNormWeights", + m_InputParams.m_InputLayerNormWeights, + inputParams.m_InputLayerNormWeights); + + CheckConstTensorPtrs("ForgetLayerNormWeights", + m_InputParams.m_ForgetLayerNormWeights, + inputParams.m_ForgetLayerNormWeights); + + CheckConstTensorPtrs("CellLayerNormWeights", + m_InputParams.m_CellLayerNormWeights, + inputParams.m_CellLayerNormWeights); + + CheckConstTensorPtrs("OutputLayerNormWeights", + m_InputParams.m_OutputLayerNormWeights, + inputParams.m_OutputLayerNormWeights); +} + void TestQuantizedLstmLayerVisitor::CheckConstTensorPtrs(const std::string& name, const ConstTensor* expected, const ConstTensor* actual) @@ -891,7 +989,7 @@ BOOST_AUTO_TEST_CASE(CheckNamedLstmLayerCifgDisabled) Network net; - IConnectableLayer *const layer = net.AddLstmLayer(descriptor, params, layerName); + IConnectableLayer* const layer = net.AddLstmLayer(descriptor, params, layerName); layer->Accept(visitor); } @@ -978,7 +1076,7 @@ BOOST_AUTO_TEST_CASE(CheckLstmLayerPeephole) Network net; - IConnectableLayer *const layer = net.AddLstmLayer(descriptor, params); + IConnectableLayer* const layer = net.AddLstmLayer(descriptor, params); layer->Accept(visitor); } @@ -1065,7 +1163,7 @@ BOOST_AUTO_TEST_CASE(CheckNamedLstmLayerPeephole) Network net; - IConnectableLayer *const layer = net.AddLstmLayer(descriptor, params, layerName); + IConnectableLayer* const layer = net.AddLstmLayer(descriptor, params, layerName); layer->Accept(visitor); } @@ -1152,7 +1250,7 @@ BOOST_AUTO_TEST_CASE(CheckLstmLayerProjection) Network net; - IConnectableLayer *const layer = net.AddLstmLayer(descriptor, params); + IConnectableLayer* const layer = net.AddLstmLayer(descriptor, params); layer->Accept(visitor); } @@ -1239,52 +1337,713 @@ BOOST_AUTO_TEST_CASE(CheckNamedLstmLayerProjection) Network net; - IConnectableLayer *const layer = net.AddLstmLayer(descriptor, params, layerName); + IConnectableLayer* const layer = net.AddLstmLayer(descriptor, params, layerName); layer->Accept(visitor); } -BOOST_AUTO_TEST_CASE(CheckQuantizedLstmLayer) +BOOST_AUTO_TEST_CASE(CheckQLstmLayerBasic) { - std::vector inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; - std::vector inputToInputWeightsDimensions = {1, 1, 3, 3}; - ConstTensor inputToInputWeights( - TensorInfo(4, inputToInputWeightsDimensions.data(), DataType::QAsymmU8), inputToInputWeightsData); + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = true; + // Basic params ONLY std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; ConstTensor inputToForgetWeights( - TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QAsymmU8), inputToForgetWeightsData); + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; ConstTensor inputToCellWeights( - TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QAsymmU8), inputToCellWeightsData); + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; ConstTensor inputToOutputWeights( - TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QAsymmU8), inputToOutputWeightsData); + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + + LstmInputParams params; + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + TestQLstmLayerVisitor visitor(descriptor, params); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params); + layer->Accept(visitor); +} + +BOOST_AUTO_TEST_CASE(CheckNamedQLstmLayerBasic) +{ + const char* layerName = "QLstmLayer"; + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = true; + + // Basic params ONLY + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + + LstmInputParams params; + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + TestQLstmLayerVisitor visitor(descriptor, params, layerName); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params, layerName); + layer->Accept(visitor); +} + +BOOST_AUTO_TEST_CASE(CheckQLstmLayerCifgDisabled) +{ + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = false; + + // Basic params + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + // CIFG disabled params + std::vector inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToInputWeights( + TensorInfo(4, inputToInputWeightsDimensions.data(), DataType::QSymmS8), inputToInputWeightsData); std::vector recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector recurrentToInputWeightsDimensions = {1, 1, 3, 3}; ConstTensor recurrentToInputWeights(TensorInfo( - 4, recurrentToInputWeightsDimensions.data(), DataType::QAsymmU8), recurrentToInputWeightsData); + 4, recurrentToInputWeightsDimensions.data(), DataType::QSymmS8), recurrentToInputWeightsData); + + std::vector inputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor inputGateBias( + TensorInfo(4, inputGateBiasDimensions.data(), DataType::Signed32), inputGateBiasData); + + LstmInputParams params; + + // Basic params + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + // CIFG disabled params + params.m_InputToInputWeights = &inputToInputWeights; + params.m_RecurrentToInputWeights = &recurrentToInputWeights; + params.m_InputGateBias = &inputGateBias; + + TestQLstmLayerVisitor visitor(descriptor, params); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params); + layer->Accept(visitor); +} + +BOOST_AUTO_TEST_CASE(CheckQLstmLayerCifgDisabledPeepholeEnabled) +{ + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = false; + descriptor.m_PeepholeEnabled = true; + + // Basic params + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; ConstTensor recurrentToForgetWeights(TensorInfo( - 4, recurrentToForgetWeightsDimensions.data(), DataType::QAsymmU8), recurrentToForgetWeightsData); + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; ConstTensor recurrentToCellWeights(TensorInfo( - 4, recurrentToCellWeightsDimensions.data(), DataType::QAsymmU8), recurrentToCellWeightsData); + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; ConstTensor recurrentToOutputWeights(TensorInfo( - 4, recurrentToOutputWeightsDimensions.data(), DataType::QAsymmU8), recurrentToOutputWeightsData); + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + + // CIFG disabled params + std::vector inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToInputWeights( + TensorInfo(4, inputToInputWeightsDimensions.data(), DataType::QSymmS8), inputToInputWeightsData); + + std::vector recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToInputWeights(TensorInfo( + 4, recurrentToInputWeightsDimensions.data(), DataType::QSymmS8), recurrentToInputWeightsData); + + std::vector inputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor inputGateBias( + TensorInfo(4, inputGateBiasDimensions.data(), DataType::Signed32), inputGateBiasData); + + // Peephole enabled, CIFG disabled params + std::vector cellToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor cellToInputWeights( + TensorInfo(4, cellToInputWeightsDimensions.data(), DataType::QSymmS16), cellToInputWeightsData); + + std::vector cellToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor cellToForgetWeights( + TensorInfo(4, cellToForgetWeightsDimensions.data(), DataType::QSymmS16), cellToForgetWeightsData); + + std::vector cellToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor cellToOutputWeights( + TensorInfo(4, cellToOutputWeightsDimensions.data(), DataType::QSymmS16), cellToOutputWeightsData); + + LstmInputParams params; + + // Basic params + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + // CIFG disabled params + params.m_InputToInputWeights = &inputToInputWeights; + params.m_RecurrentToInputWeights = &recurrentToInputWeights; + params.m_InputGateBias = &inputGateBias; + + // Peephole enabled, CIFG disabled params + params.m_CellToInputWeights = &cellToInputWeights; + params.m_CellToForgetWeights = &cellToForgetWeights; + params.m_CellToOutputWeights = &cellToOutputWeights; + + TestQLstmLayerVisitor visitor(descriptor, params); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params); + layer->Accept(visitor); +} + +BOOST_AUTO_TEST_CASE(CheckQLstmLayerCifgEnabledPeepholeEnabled) +{ + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = true; + descriptor.m_PeepholeEnabled = true; + + // Basic params + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + + // Peephole enabled and CIFG enabled params + std::vector cellToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor cellToForgetWeights( + TensorInfo(4, cellToForgetWeightsDimensions.data(), DataType::QSymmS16), cellToForgetWeightsData); + + std::vector cellToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor cellToOutputWeights( + TensorInfo(4, cellToOutputWeightsDimensions.data(), DataType::QSymmS16), cellToOutputWeightsData); + + LstmInputParams params; + + // Basic params + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + // Peephole enabled and CIFG enabled params + params.m_CellToForgetWeights = &cellToForgetWeights; + params.m_CellToOutputWeights = &cellToOutputWeights; + + TestQLstmLayerVisitor visitor(descriptor, params); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params); + layer->Accept(visitor); +} + +BOOST_AUTO_TEST_CASE(CheckQLstmLayerProjectionEnabled) +{ + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = true; + descriptor.m_ProjectionEnabled = true; + + // Basic params ONLY + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + + // Projection enabled params + std::vector projectionWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector projectionWeightsDimensions = {1, 1, 3, 3}; + ConstTensor projectionWeights(TensorInfo( + 4, projectionWeightsDimensions.data(), DataType::QSymmS8), projectionWeightsData); + + std::vector projectionBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector projectionBiasDimensions = {1, 1, 3, 3}; + ConstTensor projectionBias(TensorInfo( + 4, projectionBiasDimensions.data(), DataType::Signed32), projectionBiasData); + + LstmInputParams params; + + // Basic params + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + // Projection enabled params + params.m_ProjectionWeights = &projectionWeights; + params.m_ProjectionBias = &projectionBias; + + TestQLstmLayerVisitor visitor(descriptor, params); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params); + layer->Accept(visitor); +} + +BOOST_AUTO_TEST_CASE(CheckQLstmLayerCifgDisabledLayerNormEnabled) +{ + QLstmDescriptor descriptor; + descriptor.m_ProjectionClip = 0.5f; + descriptor.m_CellClip = 0.3f; + descriptor.m_CifgEnabled = false; + descriptor.m_LayerNormEnabled = true; + + // Basic params + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); + + std::vector forgetGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor forgetGateBias(TensorInfo( + 4, forgetGateBiasDimensions.data(), DataType::Signed32), forgetGateBiasData); + + std::vector cellBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellBiasDimensions = {1, 1, 3, 3}; + ConstTensor cellBias(TensorInfo( + 4, cellBiasDimensions.data(), DataType::Signed32), cellBiasData); + + std::vector outputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor outputGateBias(TensorInfo( + 4, outputGateBiasDimensions.data(), DataType::Signed32), outputGateBiasData); + + // CIFG disabled params + std::vector inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToInputWeights( + TensorInfo(4, inputToInputWeightsDimensions.data(), DataType::QSymmS8), inputToInputWeightsData); + + std::vector recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToInputWeights(TensorInfo( + 4, recurrentToInputWeightsDimensions.data(), DataType::QSymmS8), recurrentToInputWeightsData); + + std::vector inputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputGateBiasDimensions = {1, 1, 3, 3}; + ConstTensor inputGateBias( + TensorInfo(4, inputGateBiasDimensions.data(), DataType::Signed32), inputGateBiasData); + + // Layer Norm enabled, CIFG disabled params + std::vector inputLayerNormWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputLayerNormWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputLayerNormWeights( + TensorInfo(4, inputLayerNormWeightsDimensions.data(), DataType::QSymmS16), inputLayerNormWeightsData); + + std::vector forgetLayerNormWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector forgetLayerNormWeightsDimensions = {1, 1, 3, 3}; + ConstTensor forgetLayerNormWeights( + TensorInfo(4, forgetLayerNormWeightsDimensions.data(), DataType::QSymmS16), forgetLayerNormWeightsData); + + std::vector cellLayerNormWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector cellLayerNormWeightsDimensions = {1, 1, 3, 3}; + ConstTensor cellLayerNormWeights( + TensorInfo(4, cellLayerNormWeightsDimensions.data(), DataType::QSymmS16), cellLayerNormWeightsData); + + std::vector outputLayerNormWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector outputLayerNormWeightsDimensions = {1, 1, 3, 3}; + ConstTensor outputLayerNormWeights( + TensorInfo(4, outputLayerNormWeightsDimensions.data(), DataType::QSymmS16), outputLayerNormWeightsData); + + LstmInputParams params; + + // Basic params + params.m_InputToForgetWeights = &inputToForgetWeights; + params.m_InputToCellWeights = &inputToCellWeights; + params.m_InputToOutputWeights = &inputToOutputWeights; + params.m_RecurrentToForgetWeights = &recurrentToForgetWeights; + params.m_RecurrentToCellWeights = &recurrentToCellWeights; + params.m_RecurrentToOutputWeights = &recurrentToOutputWeights; + params.m_ForgetGateBias = &forgetGateBias; + params.m_CellBias = &cellBias; + params.m_OutputGateBias = &outputGateBias; + + // CIFG disabled params + params.m_InputToInputWeights = &inputToInputWeights; + params.m_RecurrentToInputWeights = &recurrentToInputWeights; + params.m_InputGateBias = &inputGateBias; + + // Layer Norm enabled, CIFG disabled params + params.m_InputLayerNormWeights = &inputLayerNormWeights; + params.m_ForgetLayerNormWeights = &forgetLayerNormWeights; + params.m_CellLayerNormWeights = &cellLayerNormWeights; + params.m_OutputLayerNormWeights = &outputLayerNormWeights; + + TestQLstmLayerVisitor visitor(descriptor, params); + + Network net; + + IConnectableLayer* const layer = net.AddQLstmLayer(descriptor, params); + layer->Accept(visitor); +} + + +BOOST_AUTO_TEST_CASE(CheckQuantizedLstmLayer) +{ + std::vector inputToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToInputWeights( + TensorInfo(4, inputToInputWeightsDimensions.data(), DataType::QSymmS8), inputToInputWeightsData); + + std::vector inputToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToForgetWeights( + TensorInfo(4, inputToForgetWeightsDimensions.data(), DataType::QSymmS8), inputToForgetWeightsData); + + std::vector inputToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToCellWeights( + TensorInfo(4, inputToCellWeightsDimensions.data(), DataType::QSymmS8), inputToCellWeightsData); + + std::vector inputToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector inputToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor inputToOutputWeights( + TensorInfo(4, inputToOutputWeightsDimensions.data(), DataType::QSymmS8), inputToOutputWeightsData); + + + std::vector recurrentToInputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToInputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToInputWeights(TensorInfo( + 4, recurrentToInputWeightsDimensions.data(), DataType::QSymmS8), recurrentToInputWeightsData); + + std::vector recurrentToForgetWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToForgetWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToForgetWeights(TensorInfo( + 4, recurrentToForgetWeightsDimensions.data(), DataType::QSymmS8), recurrentToForgetWeightsData); + + std::vector recurrentToCellWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToCellWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToCellWeights(TensorInfo( + 4, recurrentToCellWeightsDimensions.data(), DataType::QSymmS8), recurrentToCellWeightsData); + + std::vector recurrentToOutputWeightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; + std::vector recurrentToOutputWeightsDimensions = {1, 1, 3, 3}; + ConstTensor recurrentToOutputWeights(TensorInfo( + 4, recurrentToOutputWeightsDimensions.data(), DataType::QSymmS8), recurrentToOutputWeightsData); std::vector inputGateBiasData = {1, 2, 3, 4, 5, 6, 7, 8, 9}; diff --git a/src/armnn/test/ConstTensorLayerVisitor.hpp b/src/armnn/test/ConstTensorLayerVisitor.hpp index 203c5fd91b..e423e0f6e3 100644 --- a/src/armnn/test/ConstTensorLayerVisitor.hpp +++ b/src/armnn/test/ConstTensorLayerVisitor.hpp @@ -221,6 +221,38 @@ private: LstmInputParams m_InputParams; }; +class TestQLstmLayerVisitor : public TestLayerVisitor +{ +public: + explicit TestQLstmLayerVisitor(const QLstmDescriptor& descriptor, + const LstmInputParams& params, + const char* name = nullptr) + : TestLayerVisitor(name) + , m_Descriptor(descriptor) + , m_InputParams(params) + {} + + void VisitQLstmLayer(const IConnectableLayer* layer, + const QLstmDescriptor& descriptor, + const LstmInputParams& params, + const char* name = nullptr) + { + CheckLayerPointer(layer); + CheckLayerName(name); + CheckDescriptor(descriptor); + CheckInputParameters(params); + } + +protected: + void CheckDescriptor(const QLstmDescriptor& descriptor); + void CheckInputParameters(const LstmInputParams& inputParams); + void CheckConstTensorPtrs(const std::string& name, const ConstTensor* expected, const ConstTensor* actual); + +private: + QLstmDescriptor m_Descriptor; + LstmInputParams m_InputParams; +}; + class TestQuantizedLstmLayerVisitor : public TestLayerVisitor { diff --git a/src/armnn/test/InferOutputTests.cpp b/src/armnn/test/InferOutputTests.cpp index 3293cef0f7..015ab67079 100644 --- a/src/armnn/test/InferOutputTests.cpp +++ b/src/armnn/test/InferOutputTests.cpp @@ -46,6 +46,9 @@ ARMNN_SIMPLE_TEST_CASE(DepthwiseConvolution2dInferOutputShape, DepthwiseConvolut // TransposeConvolution2D ARMNN_SIMPLE_TEST_CASE(TransposeConvolution2dInferOutputShape, TransposeConvolution2dInferOutputShapeTest) +// QLstm +ARMNN_SIMPLE_TEST_CASE(QLstmInferOutputShape, QLstmInferOutputShapeTest) + // QuantizedLstm ARMNN_SIMPLE_TEST_CASE(QuantizedLstmInferOutputShape, QuantizedLstmInferOutputShapeTest) diff --git a/src/armnn/test/InferOutputTests.hpp b/src/armnn/test/InferOutputTests.hpp index b03449b568..70afbc9b3f 100644 --- a/src/armnn/test/InferOutputTests.hpp +++ b/src/armnn/test/InferOutputTests.hpp @@ -7,7 +7,6 @@ #include "TestUtils.hpp" - #include #include #include @@ -530,6 +529,63 @@ void DepthwiseConvolution2dInferOutputShapeTest() BOOST_CHECK(expectedOutputShape == depthwiseConvolution2dLayer->InferOutputShapes(shapes).at(0)); } +// QLstm +void QLstmInferOutputShapeImpl(const armnn::QLstmDescriptor descriptor, + const std::vector& inputShapes, + std::vector& outputShapes) +{ + armnn::Graph graph; + armnn::QLstmLayer* const qLstmLayer = graph.AddLayer(descriptor, "qLstm"); + outputShapes = qLstmLayer->InferOutputShapes(inputShapes); +} + +void QLstmInferOutputShapeTest() +{ + armnn::QLstmDescriptor descriptor; + descriptor.m_PeepholeEnabled = true; + descriptor.m_CifgEnabled = false; + descriptor.m_ProjectionEnabled = false; + + // Input shapes + const std::vector inputShape{ 2, 5 }; + const std::vector previousOutputInShape{ 2, 4 }; + const std::vector previousCellStateInShape{ 2, 4 }; + + armnn::TensorShape inputTensorShape(2, inputShape.data()); + armnn::TensorShape previousOutputInTensorShape(2, previousOutputInShape.data()); + armnn::TensorShape previousCellStateInTensorShape(2, previousCellStateInShape.data()); + + std::vector inShapes + { + inputTensorShape, + previousOutputInTensorShape, + previousCellStateInTensorShape + }; + + // Output shapes + const std::vector outputStateOutShape{ 2, 4 }; + const std::vector cellStateOutShape{ 2, 4 }; + const std::vector outputShape{ 2, 4 }; + armnn::TensorShape outputStateOutTensorShape(2, outputShape.data()); + armnn::TensorShape cellStateOutTensorShape(2, cellStateOutShape.data()); + armnn::TensorShape outputTensorShape(2, outputShape.data()); + + std::vector expectedOutShapes + { + outputStateOutTensorShape, + cellStateOutTensorShape, + outputTensorShape + }; + + std::vector actualOutShapes; + BOOST_CHECK_NO_THROW(QLstmInferOutputShapeImpl(descriptor, inShapes, actualOutShapes)); + + BOOST_CHECK(actualOutShapes.size() == 3); + BOOST_CHECK(expectedOutShapes[0] == actualOutShapes[0]); + BOOST_CHECK(expectedOutShapes[1] == actualOutShapes[1]); + BOOST_CHECK(expectedOutShapes[2] == actualOutShapes[2]); +} + // QuantizedLstm void QuantizedLstmInferOutputShapeImpl(const std::vector& inputShapes, std::vector& outputShapes) -- cgit v1.2.1