mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-29 20:14:01 +00:00
[NNAPI QDQ] Add QDQTranspose op support (#10495)
* Squashed commit of the following: commit12380491a9Author: Guoyu Wang <wanggy@outlook.com> Date: Mon Feb 7 12:59:04 2022 -0800 Add qdq mul support commit9cadda7f2cMerge:7a328477610f5d0a091aAuthor: Guoyu Wang <wanggy@outlook.com> Date: Mon Feb 7 11:24:47 2022 -0800 Merge remote-tracking branch 'origin/master' into gwang-msft/qdq_mul commit7a32847761Author: Guoyu Wang <wanggy@outlook.com> Date: Mon Feb 7 00:41:30 2022 -0800 move test case to util commitc1a8f0d81eAuthor: Guoyu Wang <wanggy@outlook.com> Date: Fri Feb 4 13:04:26 2022 -0800 update input/output check commita6f0a0d504Author: Guoyu Wang <wanggy@outlook.com> Date: Thu Feb 3 18:37:21 2022 -0800 update quantized io check functions commit87f4d1dcfeMerge:7849f0710997b8f6f394Author: Guoyu Wang <wanggy@outlook.com> Date: Wed Feb 2 17:22:58 2022 -0800 Merge remote-tracking branch 'origin/master' into gwang-msft/qdq_mul commit7849f07109Author: Guoyu Wang <wanggy@outlook.com> Date: Wed Feb 2 17:22:55 2022 -0800 minor update commit7196cdf419Author: Guoyu Wang <wanggy@outlook.com> Date: Wed Feb 2 10:50:10 2022 -0800 init change commit84c00772a1Merge:a8c7dce22f7318361645Author: Guoyu Wang <wanggy@outlook.com> Date: Tue Feb 1 18:21:17 2022 -0800 Merge remote-tracking branch 'origin/master' into gwang-msft/qdq_mul commita8c7dce22fMerge:55e536c182ef7b4dc05cAuthor: Guoyu Wang <wanggy@outlook.com> Date: Tue Feb 1 13:51:04 2022 -0800 Merge remote-tracking branch 'origin/master' into gwang-msft/qdq_mul commit55e536c182Author: Guoyu Wang <wanggy@outlook.com> Date: Tue Feb 1 11:44:34 2022 -0800 address cr comments commitd460f5b776Author: Guoyu Wang <wanggy@outlook.com> Date: Tue Feb 1 00:33:54 2022 -0800 fix android UT failure commit52146cf06fAuthor: Guoyu Wang <wanggy@outlook.com> Date: Mon Jan 31 16:01:13 2022 -0800 fix build break commitec6d07df8bAuthor: Guoyu Wang <wanggy@outlook.com> Date: Mon Jan 31 15:41:52 2022 -0800 minor update to UT commit8ec8490b4fAuthor: Guoyu Wang <wanggy@outlook.com> Date: Mon Jan 31 15:01:30 2022 -0800 Add NNAPI support of QDQ Resize * Update qdq add/mul test case, fix build break * Address CR comments * Add QLinearMul support * remove unused params * Address CR comments * wip * save * minor fix * fix * fix build * address pr comments * fix wrong ut tests * address comments * minor update * fix addinitializersskip Co-authored-by: Guoyu Wang <wanggy@outlook.com> Co-authored-by: rachguo <rachguo@rachguos-Mini.attlocal.net>
This commit is contained in:
parent
318d31ea12
commit
5cfde7af29
7 changed files with 86 additions and 22 deletions
|
|
@ -78,9 +78,10 @@ QuantizedOpType GetQuantizedOpType(const NodeUnit& node_unit) {
|
|||
return QuantizedOpType::QDQAdd;
|
||||
else if (op_type == "Mul")
|
||||
return QuantizedOpType::QDQMul;
|
||||
else if (op_type == "Transpose")
|
||||
return QuantizedOpType::QDQTranspose;
|
||||
} else {
|
||||
// throw?
|
||||
// Do we want to throw here? seems got neglected last time
|
||||
}
|
||||
|
||||
return QuantizedOpType::Unknown;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ enum class QuantizedOpType : uint8_t {
|
|||
QDQAveragePool,
|
||||
QDQAdd,
|
||||
QDQMul,
|
||||
QDQTranspose,
|
||||
// TODO, add other QDQ NodeUnit types
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -788,12 +788,29 @@ Status ReluOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const N
|
|||
#pragma region op_transpose
|
||||
|
||||
class TransposeOpBuilder : public BaseOpBuilder {
|
||||
public:
|
||||
void AddInitializersToSkip(ModelBuilder& model_builder, const NodeUnit& node_unit) const override;
|
||||
|
||||
private:
|
||||
Status AddToModelBuilderImpl(ModelBuilder& model_builder, const NodeUnit& node_unit) const override;
|
||||
static bool IsQuantizedOp(const NodeUnit& node_unit) ORT_MUST_USE_RESULT; // TODO, see if we want to move this to BaseOpBuilder
|
||||
};
|
||||
|
||||
void TransposeOpBuilder::AddInitializersToSkip(ModelBuilder& model_builder, const NodeUnit& node_unit) const {
|
||||
if (!IsQuantizedOp(node_unit))
|
||||
return;
|
||||
|
||||
AddQuantizationScaleAndZeroPointToSkip(model_builder, *node_unit.Inputs()[0].quant_param); // x_scale, x_zp
|
||||
AddQuantizationScaleAndZeroPointToSkip(model_builder, *node_unit.Outputs()[0].quant_param); // y_scale, y_zp
|
||||
}
|
||||
|
||||
/* static */ bool TransposeOpBuilder::IsQuantizedOp(const NodeUnit& node_unit) {
|
||||
return GetQuantizedOpType(node_unit) == QuantizedOpType::QDQTranspose;
|
||||
}
|
||||
|
||||
Status TransposeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, const NodeUnit& node_unit) const {
|
||||
auto& shaper(model_builder.GetShaper());
|
||||
const auto& initializers(model_builder.GetInitializerTensors());
|
||||
|
||||
const auto& input = node_unit.Inputs()[0].node_arg.Name();
|
||||
const auto& output = node_unit.Outputs()[0].node_arg.Name();
|
||||
|
|
@ -816,6 +833,15 @@ Status TransposeOpBuilder::AddToModelBuilderImpl(ModelBuilder& model_builder, co
|
|||
perm[i] = axis_nchw_to_nhwc[perm[i]];
|
||||
}
|
||||
|
||||
// Check if the quantization scale and ZP are correct
|
||||
if (IsQuantizedOp(node_unit)) {
|
||||
float x_scale = 0.0f;
|
||||
int32_t x_zero_point = 0;
|
||||
ORT_RETURN_IF_ERROR(GetQuantizationScaleAndZeroPoint(
|
||||
initializers, node_unit.Inputs()[0], node_unit.ModelPath(), x_scale, x_zero_point));
|
||||
ORT_RETURN_IF_ERROR(IsValidInputQuantizedType(model_builder, input, x_scale, x_zero_point));
|
||||
}
|
||||
|
||||
std::string perm_name = model_builder.GetUniqueName(node_unit.Name() + input + "perm");
|
||||
|
||||
// It is possible this onnx transpose operator can be nchw->nhwc, but so far I don't see
|
||||
|
|
|
|||
|
|
@ -592,8 +592,14 @@ class TransposeOpSupportChecker : public BaseOpSupportChecker {
|
|||
bool HasSupportedInputOutputsImpl(
|
||||
const InitializedTensorSet& initializers, const NodeUnit& node_unit,
|
||||
const OpSupportCheckParams& params) const override;
|
||||
bool IsNodeUnitTypeSupported(const NodeUnit& /* node_unit */) const override { return true; }
|
||||
static bool IsQuantizedOp(const NodeUnit& node_unit) ORT_MUST_USE_RESULT; // TODO, see if we want to move this to BaseOpBuilder
|
||||
};
|
||||
|
||||
/* static */ bool TransposeOpSupportChecker::IsQuantizedOp(const NodeUnit& node_unit) {
|
||||
return GetQuantizedOpType(node_unit) == QuantizedOpType::QDQTranspose;
|
||||
}
|
||||
|
||||
bool TransposeOpSupportChecker::IsOpSupportedImpl(const InitializedTensorSet& /* initializers */, const NodeUnit& node_unit,
|
||||
const OpSupportCheckParams& /* params */) const {
|
||||
Shape input_shape;
|
||||
|
|
@ -611,8 +617,8 @@ bool TransposeOpSupportChecker::IsOpSupportedImpl(const InitializedTensorSet& /*
|
|||
}
|
||||
|
||||
bool TransposeOpSupportChecker::HasSupportedInputOutputsImpl(
|
||||
const InitializedTensorSet& /* initializers */, const NodeUnit& node_unit,
|
||||
const OpSupportCheckParams& /* params */) const {
|
||||
const InitializedTensorSet& initializers, const NodeUnit& node_unit,
|
||||
const OpSupportCheckParams& params) const {
|
||||
int32_t input_type;
|
||||
if (!GetType(node_unit.Inputs()[0].node_arg, input_type))
|
||||
return false;
|
||||
|
|
@ -625,6 +631,14 @@ bool TransposeOpSupportChecker::HasSupportedInputOutputsImpl(
|
|||
return false;
|
||||
}
|
||||
|
||||
if (IsQuantizedOp(node_unit)) {
|
||||
if (!IsQuantizedIOSupported(initializers, node_unit, {0}, params, IOKind::Input))
|
||||
return false;
|
||||
|
||||
if (!IsQuantizedIOSupported(initializers, node_unit, {0}, params, IOKind::Output))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -187,5 +187,30 @@ GetQDQTestCaseFn BuildBinaryOpTestCase(const std::vector<int64_t>& input_shape,
|
|||
output_arg);
|
||||
};
|
||||
}
|
||||
|
||||
template <typename InputType, typename OutputType>
|
||||
GetQDQTestCaseFn BuildQDQTransposeTestCase(
|
||||
const std::vector<int64_t>& input_shape,
|
||||
const std::vector<int64_t>& perms) {
|
||||
return [input_shape, perms](ModelTestBuilder& builder) {
|
||||
auto* input_arg = builder.MakeInput<InputType>(input_shape, -128, 127);
|
||||
auto* output_arg = builder.MakeOutput();
|
||||
|
||||
InputType dq_zp = std::numeric_limits<InputType>::max() / 2;
|
||||
OutputType q_zp = std::numeric_limits<OutputType>::max() / 2;
|
||||
|
||||
// add DQ
|
||||
auto* dq_output = builder.MakeIntermediate();
|
||||
builder.AddDequantizeLinearNode<InputType>(input_arg, .003f, dq_zp, dq_output);
|
||||
|
||||
// add Transpose
|
||||
auto* transpose_output = builder.MakeIntermediate();
|
||||
Node& transpose_node = builder.AddNode("Transpose", {dq_output}, {transpose_output});
|
||||
transpose_node.AddAttribute("perm", perms);
|
||||
|
||||
// add Q
|
||||
builder.AddQuantizeLinearNode<OutputType>(transpose_output, .003f, q_zp, output_arg);
|
||||
};
|
||||
}
|
||||
} // namespace test
|
||||
} // namespace onnxruntime
|
||||
|
|
@ -665,24 +665,7 @@ TEST(QDQTransformerTests, Gather) {
|
|||
}
|
||||
|
||||
TEST(QDQTransformerTests, Transpose) {
|
||||
auto test_case = [&](const std::vector<int64_t>& input1_shape, const std::vector<int64_t>& perms) {
|
||||
auto build_test_case = [&](ModelTestBuilder& builder) {
|
||||
auto* input1_arg = builder.MakeInput<int8_t>(input1_shape, -128, 127);
|
||||
auto* output_arg = builder.MakeOutput();
|
||||
|
||||
// add DQ
|
||||
auto* dq_output = builder.MakeIntermediate();
|
||||
builder.AddDequantizeLinearNode<int8_t>(input1_arg, .003f, 1, dq_output);
|
||||
|
||||
// add Transpose
|
||||
auto* transpose_output = builder.MakeIntermediate();
|
||||
Node& transpose_node = builder.AddNode("Transpose", {dq_output}, {transpose_output});
|
||||
transpose_node.AddAttribute("perm", perms);
|
||||
|
||||
// add Q
|
||||
builder.AddQuantizeLinearNode<int8_t>(transpose_output, .003f, 1, output_arg);
|
||||
};
|
||||
|
||||
auto test_case = [&](const std::vector<int64_t>& input_shape, const std::vector<int64_t>& perms) {
|
||||
auto check_graph = [&](InferenceSessionWrapper& session) {
|
||||
auto op_to_count = CountOpsInGraph(session.GetGraph());
|
||||
EXPECT_EQ(op_to_count["Transpose"], 1);
|
||||
|
|
@ -690,7 +673,10 @@ TEST(QDQTransformerTests, Transpose) {
|
|||
EXPECT_EQ(op_to_count["DequantizeLinear"], 0);
|
||||
};
|
||||
|
||||
TransformerTester(build_test_case, check_graph, TransformerLevel::Level1, TransformerLevel::Level2);
|
||||
TransformerTester(BuildQDQTransposeTestCase<int8_t, int8_t>(input_shape, perms),
|
||||
check_graph,
|
||||
TransformerLevel::Level1,
|
||||
TransformerLevel::Level2);
|
||||
};
|
||||
|
||||
test_case({2, 13, 12, 37}, {0, 3, 1, 2});
|
||||
|
|
|
|||
|
|
@ -359,6 +359,17 @@ TEST(NnapiExecutionProviderTest, TestQDQMul) {
|
|||
});
|
||||
}
|
||||
|
||||
TEST(NnapiExecutionProviderTest, TestQDQTranspose) {
|
||||
RunQDQModelTest(BuildQDQTransposeTestCase<uint8_t /* InputType */,
|
||||
uint8_t /* OutputType */>(
|
||||
{1, 3, 32, 32} /* input_shape */,
|
||||
{0, 3, 1, 2} /* perms */),
|
||||
"nnapi_qdq_test_graph_transpose",
|
||||
{
|
||||
true /* verify_entire_graph_use_ep */
|
||||
});
|
||||
}
|
||||
|
||||
#endif // !(ORT_MINIMAL_BUILD)
|
||||
|
||||
TEST(NnapiExecutionProviderTest, NNAPIFlagsTest) {
|
||||
|
|
|
|||
Loading…
Reference in a new issue