diff options
author | Viet Dang <vddang@google.com> | 2019-12-04 16:18:08 +0000 |
---|---|---|
committer | Viet Dang <vddang@google.com> | 2020-01-09 15:04:38 +0000 |
commit | f388cca00f9f6056f911a954843e9cd8adabef56 (patch) | |
tree | 806b1eab0320727f94ed53907bd48a40c033e5b6 /nn/runtime | |
parent | 2ff6fe9a732a56873eec9f2ac3fd45a43c145a4d (diff) | |
download | ml-f388cca00f9f6056f911a954843e9cd8adabef56.tar.gz |
Implements Quantized LSTM op for R.
Also adds support for TENSOR_QUANT8_ASYMM_SIGNED in Test Generator.
Bug: 144841609
Bug: 145916330
Test: NeuralNetworksTest_static
Change-Id: I14b0d284b1945833d532cbaa33c66e4d77afd8b7
Diffstat (limited to 'nn/runtime')
-rw-r--r-- | nn/runtime/NeuralNetworks.cpp | 1 | ||||
-rw-r--r-- | nn/runtime/include/NeuralNetworks.h | 131 | ||||
-rw-r--r-- | nn/runtime/test/TestValidateOperations.cpp | 120 | ||||
-rw-r--r-- | nn/runtime/test/generated/spec_V1_3/qlstm.example.cpp | 380 | ||||
-rw-r--r-- | nn/runtime/test/specs/V1_3/qlstm.mod.py | 178 |
5 files changed, 810 insertions, 0 deletions
diff --git a/nn/runtime/NeuralNetworks.cpp b/nn/runtime/NeuralNetworks.cpp index 3542c24b1..5ab55dbf7 100644 --- a/nn/runtime/NeuralNetworks.cpp +++ b/nn/runtime/NeuralNetworks.cpp @@ -188,6 +188,7 @@ static_assert(ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM == 92, "ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_LSTM has changed"); static_assert(ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN == 93, "ANEURALNETWORKS_UNIDIRECTIONAL_SEQUENCE_RNN has changed"); +static_assert(ANEURALNETWORKS_QUANTIZED_LSTM == 95, "ANEURALNETWORKS_QUANTIZED_LSTM has changed"); static_assert(ANEURALNETWORKS_OEM_OPERATION == 10000, "ANEURALNETWORKS_OEM_OPERATION has changed"); diff --git a/nn/runtime/include/NeuralNetworks.h b/nn/runtime/include/NeuralNetworks.h index 3bc646e2d..b2f72c47d 100644 --- a/nn/runtime/include/NeuralNetworks.h +++ b/nn/runtime/include/NeuralNetworks.h @@ -5084,6 +5084,137 @@ typedef enum { * Available since API level 29. */ ANEURALNETWORKS_RESIZE_NEAREST_NEIGHBOR = 94, + + /** + * Quantized version of {@link ANEURALNETWORKS_LSTM}. + * + * The input and the output use asymmetric quantized types, while the rest + * use symmetric ones. + * + * Inputs: + * * 0: The input to the LSTM cell. + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, inputSize] + * * 1: The input-to-input weights. Optional. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 2: The input-to-forget weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 3: The input-to-cell weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 4: The input-to-output weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, inputSize] + * * 5: The recurrent-to-input weights. Optional. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 6: The recurrent-to-forget weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 7: The recurrent-to-cell weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 8: The recurrent-to-output weights. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [numUnits, outputSize] + * * 9: The cell-to-input weights (for peephole). Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 10: The cell-to-forget weights (for peephole). Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 11: The cell-to-output weights (for peephole). Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 12: The input gate bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Optional. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 13: The forget gate bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 14: The cell bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 15: The output gate bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [numUnits] + * * 16: The projection weights. Optional. + * Type: {@link OperandType::TENSOR_QUANT8_SYMM} + * Shape: [outputSize, numUnits] + * * 17: The projection bias. Quantized with scale being the + * product of input and weights scales and zeroPoint equal to 0. + * Optional. + * Type: {@link OperandType::TENSOR_INT32} + * Shape: [outputSize] + * * 18: The output from the previous time step. + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, outputSize] + * * 19: The cell state from the previous time step. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [batchSize, numUnits] + * * 20: The input layer normalization weights. Used to rescale + * normalized inputs to activation at input gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 21: The forget layer normalization weights. Used to + * rescale normalized inputs to activation at forget gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 22: The cell layer normalization weights. Used to rescale + * normalized inputs to activation at cell gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 23: The output layer normalization weights. Used to + * rescale normalized inputs to activation at output gate. Optional. + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [numUnits] + * * 24: The cell clip. If provided the cell state is clipped + * by this value prior to the cell output activation. Optional. + * Type: {@link OperandType::FLOAT32}. + * * 25: The projection clip. If provided and projection is enabled, + * this is used for clipping the projected values. Optional. + * Type: {@link OperandType::FLOAT32}. + * * 26: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at input gate. + * Type: {@link OperandType::FLOAT32}. + * * 27: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at forget gate. + * Type: {@link OperandType::FLOAT32}. + * * 28: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at cell gate. + * Type: {@link OperandType::FLOAT32}. + * * 29: The scale of the intermediate result of matmul, + * i.e. input to layer normalization, at output gate. + * Type: {@link OperandType::FLOAT32}. + * * 30: The zero point of the hidden state, i.e. input to + * projection. + * Type: {@link OperandType::INT32}. + * * 31: The scale of the hidden state, i.e. input to + * projection. + * Type: {@link OperandType::FLOAT32}. + * + * Outputs: + * * 0: The output state (out). + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, outputSize] + * * 1: The cell state (out). + * Type: {@link OperandType::TENSOR_QUANT16_SYMM} + * Shape: [batchSize, numUnits] + * * 2: The output. This is effectively the same as the current + * "output state (out)" value. + * Type: {@link OperandType::TENSOR_QUANT8_ASYMM_SIGNED} + * Shape: [batchSize, outputSize] + * + * Available since API level 30. + */ + ANEURALNETWORKS_QUANTIZED_LSTM = 95, } OperationCode; /** diff --git a/nn/runtime/test/TestValidateOperations.cpp b/nn/runtime/test/TestValidateOperations.cpp index 0a259a2b4..0de593ef7 100644 --- a/nn/runtime/test/TestValidateOperations.cpp +++ b/nn/runtime/test/TestValidateOperations.cpp @@ -3520,4 +3520,124 @@ TEST(OperationValidationTest, RESIZE_NEAREST_NEIGHBOR_quant8_signed) { resizeNearestNeighborTest(ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED, ANEURALNETWORKS_FLOAT32); } +TEST(OperationValidationTest, QUANTIZED_LSTM) { + uint32_t oneDimensional[1] = {5}; + uint32_t twoDimensional[2] = {5, 5}; + + ANeuralNetworksOperandType quant8AsymSignedTensor2D = { + .type = ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED, + .dimensionCount = 2, + .dimensions = twoDimensional, + .scale = 0.0078125, + .zeroPoint = 0, + }; + ANeuralNetworksOperandType quant8SymTensor2D = { + .type = ANEURALNETWORKS_TENSOR_QUANT8_SYMM, + .dimensionCount = 2, + .dimensions = twoDimensional, + .scale = 0.0078125, + .zeroPoint = 0, + }; + ANeuralNetworksOperandType quant16SymTensor1D = { + .type = ANEURALNETWORKS_TENSOR_QUANT16_SYMM, + .dimensionCount = 1, + .dimensions = oneDimensional, + .scale = 1.0, + .zeroPoint = 0, + }; + ANeuralNetworksOperandType quant16SymTensor2D = { + .type = ANEURALNETWORKS_TENSOR_QUANT16_SYMM, + .dimensionCount = 2, + .dimensions = twoDimensional, + .scale = 1.0, + .zeroPoint = 0, + }; + ANeuralNetworksOperandType int32Tensor1D = { + .type = ANEURALNETWORKS_TENSOR_INT32, + .dimensionCount = 1, + .dimensions = oneDimensional, + .scale = 4.65661e-08, + .zeroPoint = 0, + }; + ANeuralNetworksOperandType int32Scalar = { + .type = ANEURALNETWORKS_INT32, + }; + ANeuralNetworksOperandType float32Scalar = { + .type = ANEURALNETWORKS_FLOAT32, + }; + + ANeuralNetworksOperandType input = quant8AsymSignedTensor2D; + ANeuralNetworksOperandType input_to_input_weights = quant8SymTensor2D; + ANeuralNetworksOperandType input_to_forget_weights = quant8SymTensor2D; + ANeuralNetworksOperandType input_to_cell_weights = quant8SymTensor2D; + ANeuralNetworksOperandType input_to_output_weights = quant8SymTensor2D; + ANeuralNetworksOperandType recurrent_to_input_weights = quant8SymTensor2D; + ANeuralNetworksOperandType recurrent_to_forget_weights = quant8SymTensor2D; + ANeuralNetworksOperandType recurrent_to_cell_weights = quant8SymTensor2D; + ANeuralNetworksOperandType recurrent_to_output_weights = quant8SymTensor2D; + ANeuralNetworksOperandType cell_to_input_weights = quant16SymTensor2D; + ANeuralNetworksOperandType cell_to_forget_weights = quant16SymTensor2D; + ANeuralNetworksOperandType cell_to_output_weights = quant16SymTensor2D; + ANeuralNetworksOperandType input_gate_bias = int32Tensor1D; + ANeuralNetworksOperandType forget_gate_bias = int32Tensor1D; + ANeuralNetworksOperandType cell_gate_bias = int32Tensor1D; + ANeuralNetworksOperandType output_gate_bias = int32Tensor1D; + ANeuralNetworksOperandType projection_weights = quant8SymTensor2D; + ANeuralNetworksOperandType projection_bias = int32Tensor1D; + ANeuralNetworksOperandType output_state_in = quant8AsymSignedTensor2D; + ANeuralNetworksOperandType cell_state_in = quant16SymTensor2D; + ANeuralNetworksOperandType input_layer_norm_weights = quant16SymTensor1D; + ANeuralNetworksOperandType forget_layer_norm_weights = quant16SymTensor1D; + ANeuralNetworksOperandType cell_layer_norm_weights = quant16SymTensor1D; + ANeuralNetworksOperandType output_layer_norm_weights = quant16SymTensor1D; + ANeuralNetworksOperandType cell_clip = float32Scalar; + ANeuralNetworksOperandType projection_clip = float32Scalar; + ANeuralNetworksOperandType input_intermediate_scale = float32Scalar; + ANeuralNetworksOperandType forget_intermediate_scale = float32Scalar; + ANeuralNetworksOperandType cell_intermediate_scale = float32Scalar; + ANeuralNetworksOperandType output_intermediate_scale = float32Scalar; + ANeuralNetworksOperandType hidden_state_zero_point = int32Scalar; + ANeuralNetworksOperandType hidden_state_scale = float32Scalar; + + ANeuralNetworksOperandType output_state_out = quant8AsymSignedTensor2D; + ANeuralNetworksOperandType cell_state_out = quant16SymTensor2D; + ANeuralNetworksOperandType output = quant8AsymSignedTensor2D; + + OperationTestBase test(ANEURALNETWORKS_QUANTIZED_LSTM, + {input, + input_to_input_weights, + input_to_forget_weights, + input_to_cell_weights, + input_to_output_weights, + recurrent_to_input_weights, + recurrent_to_forget_weights, + recurrent_to_cell_weights, + recurrent_to_output_weights, + cell_to_input_weights, + cell_to_forget_weights, + cell_to_output_weights, + input_gate_bias, + forget_gate_bias, + cell_gate_bias, + output_gate_bias, + projection_weights, + projection_bias, + output_state_in, + cell_state_in, + input_layer_norm_weights, + forget_layer_norm_weights, + cell_layer_norm_weights, + output_layer_norm_weights, + cell_clip, + projection_clip, + input_intermediate_scale, + forget_intermediate_scale, + cell_intermediate_scale, + output_intermediate_scale, + hidden_state_zero_point, + hidden_state_scale}, + {output_state_out, cell_state_out, output}); + test.testOpsValidations(); +} + } // end namespace diff --git a/nn/runtime/test/generated/spec_V1_3/qlstm.example.cpp b/nn/runtime/test/generated/spec_V1_3/qlstm.example.cpp new file mode 100644 index 000000000..e678fcd65 --- /dev/null +++ b/nn/runtime/test/generated/spec_V1_3/qlstm.example.cpp @@ -0,0 +1,380 @@ +// Generated from qlstm.mod.py +// DO NOT EDIT +// clang-format off +#include "TestHarness.h" +using namespace test_helper; + +namespace generated_tests::qlstm { + +const TestModel& get_test_model() { + static TestModel model = { + .expectFailure = false, + .expectedMultinomialDistributionTolerance = 0, + .inputIndexes = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23}, + .isRelaxed = false, + .minSupportedVersion = TestHalVersion::V1_3, + .operands = {{ + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({90, 102, 13, 26, 38, 102, 13, 26, 51, 64}), + .dimensions = {2, 5}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.0078125f, + .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({64, 77, 89, -102, -115, 13, 25, 38, -51, 64, -102, 89, -77, 64, -51, -64, -51, -38, -25, -13}), + .dimensions = {4, 5}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-77, -13, 38, 25, 115, -64, -25, -51, 38, -102, -51, 38, -64, -51, -77, 38, -51, -77, -64, -64}), + .dimensions = {4, 5}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-51, -38, -25, -13, -64, 64, -25, -38, -25, -77, 77, -13, -51, -38, -89, 89, -115, -64, 102, 77}), + .dimensions = {4, 5}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-102, -51, -25, -115, -13, -89, 38, -38, -102, -25, 77, -25, 51, -89, -38, -64, 13, 64, -77, -51}), + .dimensions = {4, 5}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-25, -38, 51, 13, -64, 115, -25, -38, -89, 6, -25, -77}), + .dimensions = {4, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-64, -38, -64, -25, 77, 51, 115, 38, -13, 25, 64, 25}), + .dimensions = {4, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-38, 25, 13, -38, 102, -10, -25, 38, 102, -77, -13, 25}), + .dimensions = {4, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({38, -13, 13, -25, -64, -89, -25, -77, -13, -51, -89, -25}), + .dimensions = {4, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00784314f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({0, 0, 0, 0}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 1.0f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({0, 0, 0, 0}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 1.0f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({0, 0, 0, 0}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 1.0f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int32_t>({644245, 3221226, 4724464, 8160438}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 4.65661e-08f, + .type = TestOperandType::TENSOR_INT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int32_t>({2147484, -6442451, -4294968, 2147484}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 4.65661e-08f, + .type = TestOperandType::TENSOR_INT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int32_t>({-1073742, 15461883, 5368709, 1717987}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 4.65661e-08f, + .type = TestOperandType::TENSOR_INT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int32_t>({1073742, -214748, 4294968, 2147484}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 4.65661e-08f, + .type = TestOperandType::TENSOR_INT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({-25, 51, 3, -51, 25, 127, 77, 20, 18, 51, -102, 51}), + .dimensions = {3,4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.00392157f, + .type = TestOperandType::TENSOR_QUANT8_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int32_t>({0, 0, 0}), + .dimensions = {3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::TENSOR_INT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({0, 0, 0, 0, 0, 0}), + .dimensions = {2, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 3.05176e-05f, + .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({0, 0, 0, 0, 0, 0, 0, 0}), + .dimensions = {2, 4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 3.05176e-05f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({3277, 6553, 9830, 16384}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 3.05182e-05f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({6553, 6553, 13107, 9830}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 3.05182e-05f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({22937, 6553, 9830, 26214}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 3.05182e-05f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({19660, 6553, 6553, 16384}), + .dimensions = {4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_INPUT, + .numberOfConsumers = 1, + .scale = 3.05182e-05f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.0f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.0f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.007059f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.007812f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.007059f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.007812f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int32_t>({0}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::INT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<float>({0.007f}), + .dimensions = {}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::CONSTANT_COPY, + .numberOfConsumers = 1, + .scale = 0.0f, + .type = TestOperandType::FLOAT32, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({127, 127, -108, -67, 127, 127}), + .dimensions = {2, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_OUTPUT, + .numberOfConsumers = 0, + .scale = 3.05176e-05f, + .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int16_t>({-14650, 8939, 5771, 6715, -11843, 7847, 1508, 12939}), + .dimensions = {2, 4}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_OUTPUT, + .numberOfConsumers = 0, + .scale = 3.05176e-05f, + .type = TestOperandType::TENSOR_QUANT16_SYMM, + .zeroPoint = 0 + }, { + .channelQuant = {}, + .data = TestBuffer::createFromVector<int8_t>({127, 127, -108, -67, 127, 127}), + .dimensions = {2, 3}, + .isIgnored = false, + .lifetime = TestOperandLifeTime::MODEL_OUTPUT, + .numberOfConsumers = 0, + .scale = 3.05176e-05f, + .type = TestOperandType::TENSOR_QUANT8_ASYMM_SIGNED, + .zeroPoint = 0 + }}, + .operations = {{ + .inputs = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31}, + .outputs = {32, 33, 34}, + .type = TestOperationType::QUANTIZED_LSTM + }}, + .outputIndexes = {32, 33, 34} + }; + return model; +} + +const auto dummy_test_model = TestModelManager::get().add("qlstm", get_test_model()); + +} // namespace generated_tests::qlstm + diff --git a/nn/runtime/test/specs/V1_3/qlstm.mod.py b/nn/runtime/test/specs/V1_3/qlstm.mod.py new file mode 100644 index 000000000..c00c61400 --- /dev/null +++ b/nn/runtime/test/specs/V1_3/qlstm.mod.py @@ -0,0 +1,178 @@ +# +# Copyright (C) 2019 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. +# + +# Test for QUANTIZED_LSTM op. +import copy + +model = Model() + +batch_size = 2 +input_size = 5 +num_units = 4 +output_size = 3 + +input = Input("input", + ("TENSOR_QUANT8_ASYMM_SIGNED", "{%d, %d}" % (batch_size, input_size), 0.0078125, 0)) + +input_to_input_weights = Input("input_to_input_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, input_size), 0.00784314, 0)) +input_to_forget_weights = Input("input_to_forget_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, input_size), 0.00784314, 0)) +input_to_cell_weights = Input("input_to_cell_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, input_size), 0.00784314, 0)) +input_to_output_weights = Input("input_to_output_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, input_size), 0.00784314, 0)) + +recurrent_to_input_weights = Input("recurrent_to_intput_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, output_size), + 0.00784314, 0)) +recurrent_to_forget_weights = Input("recurrent_to_forget_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, output_size), + 0.00784314, 0)) +recurrent_to_cell_weights = Input("recurrent_to_cell_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, output_size), + 0.00784314, 0)) +recurrent_to_output_weights = Input("recurrent_to_output_weights", + ("TENSOR_QUANT8_SYMM", "{%d, %d}" % (num_units, output_size), + 0.00784314, 0)) + +cell_to_input_weights = Input("cell_to_input_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % (num_units), 1.0, 0)) +cell_to_forget_weights = Input("cell_to_forget_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % (num_units), 1.0, 0)) +cell_to_output_weights = Input("cell_to_output_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % (num_units), 1.0, 0)) + +input_gate_bias = Input("input_gate_bias", + ("TENSOR_INT32", "{%d}" % (num_units), 4.65661e-08, 0)) +forget_gate_bias = Input("forget_gate_bias", + ("TENSOR_INT32", "{%d}" % (num_units), 4.65661e-08, 0)) +cell_gate_bias = Input("cell_gate_bias", + ("TENSOR_INT32", "{%d}" % (num_units), 4.65661e-08, 0)) +output_gate_bias = Input("output_gate_bias", + ("TENSOR_INT32", "{%d}" % (num_units), 4.65661e-08, 0)) + +projection_weights = Input("projection_weights", + ("TENSOR_QUANT8_SYMM", "{%d,%d}" % (output_size, num_units), 0.00392157, 0)) +projection_bias = Input("projection_bias", "TENSOR_INT32", "{%d}" % (output_size)) + +output_state_in = Input("output_state_in", + ("TENSOR_QUANT8_ASYMM_SIGNED", "{%d, %d}" % (batch_size, output_size), + 3.05176e-05, 0)) +cell_state_in = Input("cell_state_in", + ("TENSOR_QUANT16_SYMM", "{%d, %d}" % (batch_size, num_units), 3.05176e-05, 0)) + +input_layer_norm_weights = Input("input_layer_norm_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % num_units, 3.05182e-05, 0)) +forget_layer_norm_weights = Input("forget_layer_norm_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % num_units, 3.05182e-05, 0)) +cell_layer_norm_weights = Input("cell_layer_norm_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % num_units, 3.05182e-05, 0)) +output_layer_norm_weights = Input("output_layer_norm_weights", + ("TENSOR_QUANT16_SYMM", "{%d}" % num_units, 3.05182e-05, 0)) + +cell_clip = Float32Scalar("cell_clip", 0.) +projection_clip = Float32Scalar("projection_clip", 0.) + +input_intermediate_scale = Float32Scalar("input_intermediate_scale", 0.007059) +forget_intermediate_scale = Float32Scalar("forget_intermediate_scale", 0.007812) +cell_intermediate_scale = Float32Scalar("cell_intermediate_scale", 0.007059) +output_intermediate_scale = Float32Scalar("output_intermediate_scale", 0.007812) +hidden_state_zero_point = Int32Scalar("hidden_state_zero_point", 0) +hidden_state_scale = Float32Scalar("hidden_state_scale", 0.007) + +output_state_out = Output("output_state_out", + ("TENSOR_QUANT8_ASYMM_SIGNED", "{%d, %d}" % (batch_size, output_size), + 3.05176e-05, 0)) +cell_state_out = Output("cell_state_out", + ("TENSOR_QUANT16_SYMM", "{%d, %d}" % (batch_size, num_units), 3.05176e-05, 0)) +output = Output("output", + ("TENSOR_QUANT8_ASYMM_SIGNED", "{%d, %d}" % (batch_size, output_size), + 3.05176e-05, 0)) + +model = model.Operation( + "QUANTIZED_LSTM", input, input_to_input_weights, input_to_forget_weights, + input_to_cell_weights, input_to_output_weights, recurrent_to_input_weights, + recurrent_to_forget_weights, recurrent_to_cell_weights, + recurrent_to_output_weights, cell_to_input_weights, cell_to_forget_weights, + cell_to_output_weights, input_gate_bias, forget_gate_bias, cell_gate_bias, + output_gate_bias, projection_weights, projection_bias, output_state_in, + cell_state_in, input_layer_norm_weights, forget_layer_norm_weights, + cell_layer_norm_weights, output_layer_norm_weights, cell_clip, projection_clip, + input_intermediate_scale, forget_intermediate_scale, cell_intermediate_scale, + output_intermediate_scale, hidden_state_zero_point, hidden_state_scale).To([output_state_out, + cell_state_out, output]) + +# Example 1. Input in operand 0, +input0 = { + input_to_input_weights: [ + 64, 77, 89, -102, -115, 13, 25, 38, -51, 64, -102, 89, -77, 64, -51, -64, -51, -38, -25, -13 + ], + input_to_forget_weights: [ + -77, -13, 38, 25, 115, -64, -25, -51, 38, -102, -51, 38, -64, -51, -77, 38, -51, -77, -64, -64 + ], + input_to_cell_weights: [ + -51, -38, -25, -13, -64, 64, -25, -38, -25, -77, 77, -13, -51, -38, -89, 89, -115, -64, 102, 77 + ], + input_to_output_weights: [ + -102, -51, -25, -115, -13, -89, 38, -38, -102, -25, 77, -25, 51, -89, -38, -64, 13, 64, -77, -51 + ], + input_gate_bias: [644245, 3221226, 4724464, 8160438], + forget_gate_bias: [2147484, -6442451, -4294968, 2147484], + cell_gate_bias: [-1073742, 15461883, 5368709, 1717987], + output_gate_bias: [1073742, -214748, 4294968, 2147484], + recurrent_to_input_weights: [ + -25, -38, 51, 13, -64, 115, -25, -38, -89, 6, -25, -77 + ], + recurrent_to_forget_weights: [ + -64, -38, -64, -25, 77, 51, 115, 38, -13, 25, 64, 25 + ], + recurrent_to_cell_weights: [ + -38, 25, 13, -38, 102, -10, -25, 38, 102, -77, -13, 25 + ], + recurrent_to_output_weights: [ + 38, -13, 13, -25, -64, -89, -25, -77, -13, -51, -89, -25 + ], + projection_weights: [ + -25, 51, 3, -51, 25, 127, 77, 20, 18, 51, -102, 51 + ], + projection_bias: [ 0 for _ in range(output_size) ], + input_layer_norm_weights: [3277, 6553, 9830, 16384], + forget_layer_norm_weights: [6553, 6553, 13107, 9830], + cell_layer_norm_weights: [22937, 6553, 9830, 26214], + output_layer_norm_weights: [19660, 6553, 6553, 16384], +} + +test_input = [90, 102, 13, 26, 38, 102, 13, 26, 51, 64] + +golden_output = [ + 127, 127, -108, -67, 127, 127 +] + +output0 = { + output_state_out: golden_output, + cell_state_out: [-14650, 8939, 5771, 6715, -11843, 7847, 1508, 12939], + output: golden_output, +} + +input0[input] = test_input +input0[output_state_in] = [ 0 for _ in range(batch_size * output_size) ] +input0[cell_state_in] = [ 0 for _ in range(batch_size * num_units) ] +input0[cell_to_input_weights] = [0 for _ in range(num_units) ] +input0[cell_to_forget_weights] = [0 for _ in range(num_units) ] +input0[cell_to_output_weights] = [0 for _ in range(num_units) ] + +Example((input0, output0)) |