diff --git a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.cc b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.cc index f32e0aa438..a6039836ab 100644 --- a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.cc +++ b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.cc @@ -3,8 +3,10 @@ #include #include +#include #include "core/providers/common.h" +#include "core/providers/shared/utils/utils.h" #include "core/providers/nnapi/nnapi_builtin/nnapi_lib/nnapi_implementation.h" #include "helper.h" #include "model_builder.h" @@ -46,10 +48,13 @@ void ModelBuilder::AddInitializerToSkip(const std::string& tensor_name) { skipped_initializers_.insert(tensor_name); } +static std::unordered_map> GetAllQuantizedOpInputs(const GraphViewer& graph_viewer); + Status ModelBuilder::Prepare() { nnapi_model_ = std::unique_ptr(new Model()); RETURN_STATUS_ON_ERROR(nnapi_->ANeuralNetworksModel_create(&nnapi_model_->model_)); ORT_RETURN_IF_ERROR(GetTargetDevices()); + all_quantized_op_inputs_ = GetAllQuantizedOpInputs(graph_viewer_); PreprocessInitializers(); PreprocessActivations(); ORT_RETURN_IF_ERROR(RegisterInitializers()); @@ -143,7 +148,7 @@ void ModelBuilder::PreprocessActivations() { } // Help to get all quantized operators' input and the node(s) using the input -std::unordered_map> GetAllQuantizedOpInputs(const GraphViewer& graph_viewer) { +static std::unordered_map> GetAllQuantizedOpInputs(const GraphViewer& graph_viewer) { std::unordered_map> all_quantized_op_inputs; const auto& node_indices = graph_viewer.GetNodesInTopologicalOrder(); for (const auto& node_idx : node_indices) { @@ -175,6 +180,50 @@ std::unordered_map> GetAllQuantizedOpInputs(con return all_quantized_op_inputs; } +static Status GetInputDataType( + const InitializedTensorSet& initializers, + const std::unordered_map>& all_quantized_op_inputs, + const std::string& name, int32_t data_type, const Shape& shape, + OperandType& operand_type) { + Type type = Type::TENSOR_FLOAT32; + float scale = 0.0f; + int32_t zero_point = 0; + switch (data_type) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: + type = Type::TENSOR_FLOAT32; + break; + case ONNX_NAMESPACE::TensorProto_DataType_UINT8: + // For ONNX the quantized input/initializer does not carry scale and zero point info + // So we will need to search the operator using this input + // And dig out the scale and zero point as the input initializers to the operator + type = Type::TENSOR_QUANT8_ASYMM; + if (!Contains(all_quantized_op_inputs, name)) { + // We current do not support uint8 input if it is not a quantized input + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "The input/initializer of graph has unsupported quantized type, name: ", name, + " type: ", data_type); + } + + // TODO, verify the scale and zero point match if there are multiple op using same input + ORT_RETURN_IF_ERROR(GetQuantizedInputScaleAndZeroPoint( + initializers, *all_quantized_op_inputs.at(name)[0], name, scale, zero_point)); + break; + // case ONNX_NAMESPACE::TensorProto_DataType_INT8: + // We also do not consider ONNX_NAMESPACE::TensorProto_DataType_INT8 case here, since that can only + // be input 2 of Qlinear[Conv/MatMul], which has to be an initializer tensor and will be added + // separately by OpBuilder, so we do not treat it as an input/initializers here + default: + // TODO: support other type + return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, + "The input/initializer of graph doesn't have valid type, name: ", + name, " type: ", data_type); + break; + } + + operand_type = OperandType(type, shape, scale, zero_point); + return Status::OK(); +} + Status ModelBuilder::RegisterInitializers() { // First pass to get all the stats of the initializers const auto& initializer_tensors(GetInitializerTensors()); @@ -201,20 +250,10 @@ Status ModelBuilder::RegisterInitializers() { shape.push_back(1); } - Type type = Type::TENSOR_FLOAT32; - switch (tensor.data_type()) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: - type = Type::TENSOR_FLOAT32; - break; - default: - // TODO: support other type - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "The initializer of graph doesn't have valid type, name: ", - name, " type: ", tensor.data_type()); - break; - } - - OperandType operand_type(type, shape); + OperandType operand_type(Type::TENSOR_FLOAT32, shape); + ORT_RETURN_IF_ERROR( + GetInputDataType(GetInitializerTensors(), all_quantized_op_inputs_, + name, tensor.data_type(), shape, operand_type)); shaper_.AddShape(name, operand_type.dimensions); uint32_t index = 0; @@ -240,12 +279,26 @@ Status ModelBuilder::RegisterInitializers() { uint32_t index; size_t size, padded_size; std::tie(index, size, padded_size) = initializers[i++]; - const char* src = nullptr; - if (tensor.data_type() == ONNX_NAMESPACE::TensorProto_DataType_FLOAT) { - src = tensor.float_data().empty() - ? tensor.raw_data().data() - : reinterpret_cast(tensor.float_data().data()); - } // We should not get anything else here since we already checked in the 1st pass + const uint8_t* src = nullptr; + // uint8_t data need unpack, need a holder for free memory after copy + std::unique_ptr unpacked_tensor; + switch (tensor.data_type()) { + case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: + src = reinterpret_cast(GetTensorFloatData(tensor)); + break; + case ONNX_NAMESPACE::TensorProto_DataType_UINT8: + size_t tensor_byte_size; + ORT_RETURN_IF_ERROR( + onnxruntime::utils::UnpackInitializerData(tensor, graph_viewer_.ModelPath(), + unpacked_tensor, tensor_byte_size)); + ORT_RETURN_IF_NOT(size == tensor_byte_size, + "initializer tensor: ", tensor.name(), "'s size: ", tensor_byte_size, + " should match the calculated size: ", size); + src = unpacked_tensor.get(); + break; + // default: + // We should not get anything else here since we already checked in the 1st pass + } uint8_t* dest = nnapi_model_->mem_initializers_->GetDataPtr() + offset; memcpy(dest, src, size); @@ -257,7 +310,6 @@ Status ModelBuilder::RegisterInitializers() { } Status ModelBuilder::RegisterModelInputs() { - const auto all_quantized_op_inputs = GetAllQuantizedOpInputs(graph_viewer_); for (const auto* node_arg : graph_viewer_.GetInputs()) { const auto& input_name = node_arg->Name(); @@ -285,49 +337,17 @@ Status ModelBuilder::RegisterModelInputs() { shape.push_back(1); } - Type type = Type::TENSOR_FLOAT32; - float scale = 0.0f; - int32_t zero_point = 0; + OperandType operand_type(Type::TENSOR_FLOAT32, shape); const auto* type_proto = node_arg->TypeAsProto(); if (!type_proto || !type_proto->tensor_type().has_elem_type()) { return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "The input of graph doesn't have elem_type: ", input_name); } else { - switch (type_proto->tensor_type().elem_type()) { - case ONNX_NAMESPACE::TensorProto_DataType_FLOAT: - type = Type::TENSOR_FLOAT32; - break; - case ONNX_NAMESPACE::TensorProto_DataType_UINT8: { - // For ONNX the quantized input does not carry scale and zero point info - // So we will need to search the operator using this input - // And dig out the scale and zero point as the input initializers to the operator - type = Type::TENSOR_QUANT8_ASYMM; - if (!Contains(all_quantized_op_inputs, input_name)) { - // We current do not support uint8 input if it is not a quantized input - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "The input of graph has unsupported quantized type, name: ", input_name, - " type: ", type_proto->tensor_type().elem_type()); - } - - // TODO, verify the scale and zero point match if there are multiple op using same input - ORT_RETURN_IF_ERROR(GetQuantizedInputScaleAndZeroPoint( - *this, *all_quantized_op_inputs.at(input_name)[0], input_name, scale, zero_point)); - break; - } - // case NNX_NAMESPACE::TensorProto_DataType_INT8: - // We also do not consider ONNX_NAMESPACE::TensorProto_DataType_INT8 case here, since that can only - // be input 2 of Qlinear[Conv/MatMul], which has to be an initializer tensor, so we do not treat - // it as an input here - default: { - // TODO: support other type - return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, - "The input of graph has unsupported type, name: ", input_name, - " type: ", type_proto->tensor_type().elem_type()); - } - } + ORT_RETURN_IF_ERROR( + GetInputDataType(GetInitializerTensors(), all_quantized_op_inputs_, + input_name, type_proto->tensor_type().elem_type(), shape, operand_type)); } - OperandType operand_type(type, shape, scale, zero_point); shaper_.AddShape(input_name, operand_type.dimensions); uint32_t index = 0; diff --git a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.h b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.h index ee2ac944b6..cc03cdb979 100644 --- a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.h +++ b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/model_builder.h @@ -149,6 +149,10 @@ class ModelBuilder { std::vector input_index_vec_; std::vector output_index_vec_; + // Contains all quantized operators' input and the node(s) using the input + // In the form of {input_name, [node(s) using the input]} + std::unordered_map> all_quantized_op_inputs_; + std::unordered_set unique_names_; TargetDeviceOption target_device_option_{TargetDeviceOption::ALL_DEVICES}; diff --git a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.cc b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.cc index e18bb788ef..b4cff7e1c3 100644 --- a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.cc +++ b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.cc @@ -668,12 +668,7 @@ static void AddBinaryOpQuantizationScaleAndZeroPointToSkip(ModelBuilder& model_b model_builder.AddInitializerToSkip(input_defs[7]->Name()); // y_zero_point } -Status GetQuantizedInputScaleAndZeroPoint(const ModelBuilder& model_builder, - const Node& node, - const std::string& input_name, - float& scale, - int32_t& zero_point) ORT_MUST_USE_RESULT; -Status GetQuantizedInputScaleAndZeroPoint(const ModelBuilder& model_builder, +Status GetQuantizedInputScaleAndZeroPoint(const InitializedTensorSet& initializers, const Node& node, const std::string& input_name, float& scale, @@ -705,10 +700,10 @@ Status GetQuantizedInputScaleAndZeroPoint(const ModelBuilder& model_builder, return ORT_MAKE_STATUS(ONNXRUNTIME, INVALID_ARGUMENT, "Unsupported op: ", op_type); } - scale = GetQuantizationScale(model_builder.GetInitializerTensors(), node, scale_idx); + scale = GetQuantizationScale(initializers, node, scale_idx); zero_point = 0; - if (node.InputDefs().size() > 2) { - ORT_RETURN_IF_ERROR(GetQuantizationZeroPoint(model_builder.GetInitializerTensors(), node, zero_point_idx, zero_point)); + if (node.InputDefs().size() > zero_point_idx) { + ORT_RETURN_IF_ERROR(GetQuantizationZeroPoint(initializers, node, zero_point_idx, zero_point)); } return Status::OK(); diff --git a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.h b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.h index 27cfea02f4..55d1dfe627 100644 --- a/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.h +++ b/onnxruntime/core/providers/nnapi/nnapi_builtin/builders/op_builder.h @@ -30,7 +30,7 @@ Status TransposeNHWCToNCHW(ModelBuilder& model_builder, const std::string& input ORT_MUST_USE_RESULT; // Get the quantized input's scale and zero point for the given input -Status GetQuantizedInputScaleAndZeroPoint(const ModelBuilder& model_builder, +Status GetQuantizedInputScaleAndZeroPoint(const InitializedTensorSet& initializers, const Node& node, const std::string& input_name, float& scale, int32_t& zero_point) ORT_MUST_USE_RESULT; diff --git a/onnxruntime/test/contrib_ops/qlinear_binary_op_test.cc b/onnxruntime/test/contrib_ops/qlinear_binary_op_test.cc index 805abcb433..be79ecf027 100644 --- a/onnxruntime/test/contrib_ops/qlinear_binary_op_test.cc +++ b/onnxruntime/test/contrib_ops/qlinear_binary_op_test.cc @@ -41,6 +41,7 @@ void RunQLinearMathTestFromFloat( const std::vector& a, const std::vector& a_shape_origin, float A_scale, T A_zero_point, const std::vector& b, const std::vector& b_shape_origin, float B_scale, T B_zero_point, float C_scale, T C_zero_point, + bool input_b_is_initializer = false, bool all_initializer_scale_zero_point = false) { size_t number_dims = std::max(a_shape_origin.size(), b_shape_origin.size()); std::vector a_shape = PrefixingDims(a_shape_origin, number_dims); @@ -77,7 +78,7 @@ void RunQLinearMathTestFromFloat( for (size_t i = 0, sz = b.size(); i < sz; ++i) { b_quantized[i] = clampi(static_cast(std::nearbyintf(b[i] / B_scale)) + B_zero_point, qmin, qmax); } - test.template AddInput("B", b_shape_origin, b_quantized); + test.template AddInput("B", b_shape_origin, b_quantized, input_b_is_initializer); test.AddInput("B_scale", {}, {B_scale}, all_initializer_scale_zero_point); test.template AddInput("B_zero_point", {}, {B_zero_point}, all_initializer_scale_zero_point); @@ -148,11 +149,20 @@ TEST(QLinearBinaryOpTest, AddU8VectorVectorFull) { C_scale, C_zero_point); // NNAPI will require all the scales and zero points be initializers + // We also want to test the case input B is an initializer RunQLinearMathTestFromFloat("QLinearAdd", add_function, A, {63}, A_scale, A_zero_point, B, {63}, B_scale, B_zero_point, C_scale, C_zero_point, - true); + false /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); + + RunQLinearMathTestFromFloat("QLinearAdd", add_function, + A, {63}, A_scale, A_zero_point, + B, {63}, B_scale, B_zero_point, + C_scale, C_zero_point, + true /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); } TEST(QLinearBinaryOpTest, AddU8VectorVectorBroadcast) { @@ -174,11 +184,20 @@ TEST(QLinearBinaryOpTest, AddU8VectorVectorBroadcast) { C_scale, C_zero_point); // NNAPI will require all the scales and zero points be initializers + // We also want to test the case input B is an initializer RunQLinearMathTestFromFloat("QLinearAdd", add_function, A, {3, 3, 7}, A_scale, A_zero_point, B, {3, 1, 7}, B_scale, B_zero_point, C_scale, C_zero_point, - true); + false /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); + + RunQLinearMathTestFromFloat("QLinearAdd", add_function, + A, {3, 3, 7}, A_scale, A_zero_point, + B, {3, 1, 7}, B_scale, B_zero_point, + C_scale, C_zero_point, + true /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); } TEST(QLinearBinaryOpTest, AddU8ScalarVectorFull) { @@ -197,11 +216,20 @@ TEST(QLinearBinaryOpTest, AddU8ScalarVectorFull) { C_scale, C_zero_point); // NNAPI will require all the scales and zero points be initializers + // We also want to test the case input B is an initializer RunQLinearMathTestFromFloat("QLinearAdd", add_function, B, {1}, B_scale, B_zero_point, A, {63}, A_scale, A_zero_point, C_scale, C_zero_point, - true); + false /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); + + RunQLinearMathTestFromFloat("QLinearAdd", add_function, + B, {1}, B_scale, B_zero_point, + A, {63}, A_scale, A_zero_point, + C_scale, C_zero_point, + true /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); } TEST(QLinearBinaryOpTest, AddU8ScalarVectorBroadcast) { @@ -220,11 +248,20 @@ TEST(QLinearBinaryOpTest, AddU8ScalarVectorBroadcast) { C_scale, C_zero_point); // NNAPI will require all the scales and zero points be initializers + // We also want to test the case input B is an initializer RunQLinearMathTestFromFloat("QLinearAdd", add_function, B, {3, 1, 1}, B_scale, B_zero_point, A, {3, 7, 3}, A_scale, A_zero_point, C_scale, C_zero_point, - true); + false /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); + + RunQLinearMathTestFromFloat("QLinearAdd", add_function, + B, {3, 1, 1}, B_scale, B_zero_point, + A, {3, 7, 3}, A_scale, A_zero_point, + C_scale, C_zero_point, + true /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); } TEST(QLinearBinaryOpTest, AddU8VectorScalarFull) { @@ -243,11 +280,20 @@ TEST(QLinearBinaryOpTest, AddU8VectorScalarFull) { C_scale, C_zero_point); // NNAPI will require all the scales and zero points be initializers + // We also want to test the case input B is an initializer RunQLinearMathTestFromFloat("QLinearAdd", add_function, A, {63}, A_scale, A_zero_point, B, {1}, B_scale, B_zero_point, C_scale, C_zero_point, - true); + false /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); + + RunQLinearMathTestFromFloat("QLinearAdd", add_function, + A, {63}, A_scale, A_zero_point, + B, {1}, B_scale, B_zero_point, + C_scale, C_zero_point, + true /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); } TEST(QLinearBinaryOpTest, AddU8VectorScalarBroadcast) { @@ -266,11 +312,20 @@ TEST(QLinearBinaryOpTest, AddU8VectorScalarBroadcast) { C_scale, C_zero_point); // NNAPI will require all the scales and zero points be initializers + // We also want to test the case input B is an initializer RunQLinearMathTestFromFloat("QLinearAdd", add_function, A, {3, 7, 3}, A_scale, A_zero_point, B, {1, 1, 3}, B_scale, B_zero_point, C_scale, C_zero_point, - true); + false /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); + + RunQLinearMathTestFromFloat("QLinearAdd", add_function, + A, {3, 7, 3}, A_scale, A_zero_point, + B, {1, 1, 3}, B_scale, B_zero_point, + C_scale, C_zero_point, + true /* input_b_is_initializer */, + true /* all_initializer_scale_zero_point */); } TEST(QLinearBinaryOpTest, AddS8VectorVectorFull) { @@ -386,7 +441,7 @@ TEST(QLinearBinaryOpTest, MulU8VectorVectorFull) { uint8_t C_zero_point = 128; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {63}, A_scale, A_zero_point, B, {63}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {63}, A_scale, A_zero_point, B, {63}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulU8VectorVectorBroadcast) { @@ -394,73 +449,72 @@ TEST(QLinearBinaryOpTest, MulU8VectorVectorBroadcast) { float A_scale = 8.0f / 256.0f; uint8_t A_zero_point = 128; std::vector B = { - 4.00f, 0.25f, 0.00f, -0.25f, 0.50f, -0.25f, -0.00f, 0.25f, - -1.50f, -2.25f, 2.50f, 3.75f, -3.75f, -4.00f, 5.00f, 5.50f, - -0.50f, -1.25f, 0.75f, 0.00f, 2.25f - }; + 4.00f, 0.25f, 0.00f, -0.25f, 0.50f, -0.25f, -0.00f, 0.25f, + -1.50f, -2.25f, 2.50f, 3.75f, -3.75f, -4.00f, 5.00f, 5.50f, + -0.50f, -1.25f, 0.75f, 0.00f, 2.25f}; float B_scale = 8.0f / 256.0f; uint8_t B_zero_point = 128; float C_scale = 64.0f / 256.0f; uint8_t C_zero_point = 128; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {3, 3, 7}, A_scale, A_zero_point, B, {3, 1, 7}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {3, 3, 7}, A_scale, A_zero_point, B, {3, 1, 7}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulU8ScalarVectorFull) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; uint8_t A_zero_point = 128; - std::vector B = { 0.25f }; + std::vector B = {0.25f}; float B_scale = 8.0f / 256.0f; uint8_t B_zero_point = 96; float C_scale = 8.0f / 256.0f; uint8_t C_zero_point = 100; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - B, {1}, B_scale, B_zero_point, A, {63}, A_scale, A_zero_point, C_scale, C_zero_point); + B, {1}, B_scale, B_zero_point, A, {63}, A_scale, A_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulU8ScalarVectorBroadcast) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; uint8_t A_zero_point = 128; - std::vector B = { 0.25f, -0.25f, -0.00f }; + std::vector B = {0.25f, -0.25f, -0.00f}; float B_scale = 8.0f / 256.0f; uint8_t B_zero_point = 96; float C_scale = 8.0f / 256.0f; uint8_t C_zero_point = 100; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - B, {3, 1, 1}, B_scale, B_zero_point, A, {3, 7, 3}, A_scale, A_zero_point, C_scale, C_zero_point); + B, {3, 1, 1}, B_scale, B_zero_point, A, {3, 7, 3}, A_scale, A_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulU8VectorScalarFull) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; uint8_t A_zero_point = 128; - std::vector B = { 0.25f }; + std::vector B = {0.25f}; float B_scale = 8.0f / 256.0f; uint8_t B_zero_point = 96; float C_scale = 16.0f / 256.0f; uint8_t C_zero_point = 128; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {63}, A_scale, A_zero_point, B, {1}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {63}, A_scale, A_zero_point, B, {1}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulU8VectorScalarBroadcast) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; uint8_t A_zero_point = 128; - std::vector B = { 0.25f, -0.25f, -0.00f }; + std::vector B = {0.25f, -0.25f, -0.00f}; float B_scale = 8.0f / 256.0f; uint8_t B_zero_point = 96; float C_scale = 16.0f / 256.0f; uint8_t C_zero_point = 128; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {3, 7, 3}, A_scale, A_zero_point, B, {1, 1, 3}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {3, 7, 3}, A_scale, A_zero_point, B, {1, 1, 3}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulS8VectorVectorFull) { @@ -474,7 +528,7 @@ TEST(QLinearBinaryOpTest, MulS8VectorVectorFull) { int8_t C_zero_point = -16; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {63}, A_scale, A_zero_point, B, {63}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {63}, A_scale, A_zero_point, B, {63}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulS8VectorVectorBroadcast) { @@ -482,73 +536,72 @@ TEST(QLinearBinaryOpTest, MulS8VectorVectorBroadcast) { float A_scale = 8.0f / 256.0f; int8_t A_zero_point = 0; std::vector B = { - 4.00f, 0.25f, 0.00f, -0.25f, 0.50f, -0.25f, -0.00f, 0.25f, - -1.50f, -2.25f, 2.50f, 3.75f, -3.75f, -4.00f, 5.00f, 5.50f, - -0.50f, -1.25f, 0.75f, 1.25f, 2.25f - }; + 4.00f, 0.25f, 0.00f, -0.25f, 0.50f, -0.25f, -0.00f, 0.25f, + -1.50f, -2.25f, 2.50f, 3.75f, -3.75f, -4.00f, 5.00f, 5.50f, + -0.50f, -1.25f, 0.75f, 1.25f, 2.25f}; float B_scale = 8.0f / 256.0f; int8_t B_zero_point = 0; float C_scale = 16.0f / 256.0f; int8_t C_zero_point = -16; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {3, 3, 7}, A_scale, A_zero_point, B, {3, 1, 7}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {3, 3, 7}, A_scale, A_zero_point, B, {3, 1, 7}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulS8ScalarVectorFull) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; int8_t A_zero_point = 0; - std::vector B = { 0.25f }; + std::vector B = {0.25f}; float B_scale = 2.0f / 256.0f; int8_t B_zero_point = 16; float C_scale = 8.0f / 256.0f; int8_t C_zero_point = 10; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - B, {1}, B_scale, B_zero_point, A, {63}, A_scale, A_zero_point, C_scale, C_zero_point); + B, {1}, B_scale, B_zero_point, A, {63}, A_scale, A_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulS8ScalarVectorBroadcast) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; int8_t A_zero_point = 0; - std::vector B = { 0.25f, -0.25f, -0.00f }; + std::vector B = {0.25f, -0.25f, -0.00f}; float B_scale = 2.0f / 256.0f; int8_t B_zero_point = 16; float C_scale = 8.0f / 256.0f; int8_t C_zero_point = 10; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - B, {3, 1, 1}, B_scale, B_zero_point, A, {3, 7, 3}, A_scale, A_zero_point, C_scale, C_zero_point); + B, {3, 1, 1}, B_scale, B_zero_point, A, {3, 7, 3}, A_scale, A_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulS8VectorScalarFull) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; int8_t A_zero_point = 0; - std::vector B = { 0.25f }; + std::vector B = {0.25f}; float B_scale = 2.0f / 256.0f; int8_t B_zero_point = 16; float C_scale = 8.0f / 256.0f; int8_t C_zero_point = 10; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {63}, A_scale, A_zero_point, B, {1}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {63}, A_scale, A_zero_point, B, {1}, B_scale, B_zero_point, C_scale, C_zero_point); } TEST(QLinearBinaryOpTest, MulS8VectorScalarBroadcast) { const std::vector& A(A4Add); float A_scale = 8.0f / 256.0f; int8_t A_zero_point = 0; - std::vector B = { 0.25f, -0.25f, -0.00f }; + std::vector B = {0.25f, -0.25f, -0.00f}; float B_scale = 2.0f / 256.0f; int8_t B_zero_point = 16; float C_scale = 8.0f / 256.0f; int8_t C_zero_point = 10; RunQLinearMathTestFromFloat("QLinearMul", mul_function, - A, {3, 7, 3}, A_scale, A_zero_point, B, {1, 1, 3}, B_scale, B_zero_point, C_scale, C_zero_point); + A, {3, 7, 3}, A_scale, A_zero_point, B, {1, 1, 3}, B_scale, B_zero_point, C_scale, C_zero_point); } } // namespace test