From 3ff7dcb1083c3f04032170b07ec2a092f27c069d Mon Sep 17 00:00:00 2001 From: ccsuzzh <1719571694@qq.com> Date: Mon, 1 Dec 2025 16:08:25 +0800 Subject: [PATCH] add transpose op for pnna delegate mode Co-authored-by:ccsu_zzh <1719571694@qq.com> --- .../src/litert/delegate/pnna/op/pnna_op.h | 4 +- .../litert/delegate/pnna/op/transpose_pnna.cc | 68 ++++ .../litert/delegate/pnna/op/transpose_pnna.h | 51 +++ .../src/litert/delegate/pnna/pnna_delegate.cc | 2 + .../src/litert/delegate/pnna/pnna_delegate.h | 3 +- .../src/litert/delegate/pnna/pnna_subgraph.h | 2 +- .../src/litert/delegate/pnna/pnna_utils.h | 2 +- .../test/ut/src/runtime/kernel/dsp/dsp_test.h | 10 + .../src/runtime/kernel/dsp/transpose_tests.cc | 290 ++++++++++++++++++ 9 files changed, 427 insertions(+), 5 deletions(-) create mode 100644 mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.cc create mode 100644 mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.h create mode 100644 mindspore-lite/test/ut/src/runtime/kernel/dsp/transpose_tests.cc diff --git a/mindspore-lite/src/litert/delegate/pnna/op/pnna_op.h b/mindspore-lite/src/litert/delegate/pnna/op/pnna_op.h index b553d4b2..dd6dee01 100644 --- a/mindspore-lite/src/litert/delegate/pnna/op/pnna_op.h +++ b/mindspore-lite/src/litert/delegate/pnna/op/pnna_op.h @@ -19,8 +19,8 @@ #include #include #include -#include "include/cxx_api/kernel.h" -#include "include/cxx_api/data_type.h" +#include "include/api/kernel.h" +#include "include/api/data_type.h" #include "include/errorcode.h" #include "src/common/log_adapter.h" #include "schema/ops_generated.h" diff --git a/mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.cc b/mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.cc new file mode 100644 index 00000000..6f66dc7a --- /dev/null +++ b/mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.cc @@ -0,0 +1,68 @@ +/** + * Copyright 2025 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include "src/litert/delegate/pnna/op/transpose_pnna.h" +#include "src/litert/delegate/pnna/pnna_utils.h" + +namespace mindspore { +namespace lite { +int PNNATranspose::InitParams() { + if (!perm_.empty()) { + return RET_OK; + } + if (in_tensors_.size() != kInputSize1) { + MS_LOG(ERROR) << "Transpose op expects " << kInputSize1 << " inputs, but got " << in_tensors_.size(); + return RET_ERROR; + } + auto perm_tensor = in_tensors_.at(1); + if (perm_tensor.Data() == nullptr) { + MS_LOG(ERROR) << "Transpose perm tensor data is nullptr"; + return RET_ERROR; + } + auto perm_num = perm_tensor.ElementNum(); + auto perm_data = reinterpret_cast(perm_tensor.Data().get()); + for (size_t i = 0; i < perm_num; i++) { + perm_.push_back(perm_data[i]); + } + return RET_OK; +} + +bool PNNATranspose::IsSupport() { + MS_CHECK_GE(in_tensors_.size(), kInputSize1, RET_NOT_SUPPORT); + auto perm_tensor = in_tensors_.at(1); + if (!perm_tensor.IsConst()) { + MS_LOG(WARNING) << "PNNA transpose must get fixed axis values."; + return false; + } + return true; +} + +int PNNATranspose::AddOpToPNNAModel(PNNASubGraph *graph) { + MS_CHECK_TRUE_RET(graph != nullptr, RET_ERROR); + + auto input_tensor = graph->GetMappedTensor(&in_tensors_[0]); + if (!input_tensor) { + input_tensor = graph->ConvertOperand(&in_tensors_[0]); + } + auto output_tensor = graph->ConvertOperand(&out_tensors_[0]); + auto transpose_op = + graph->graph()->CreateOperation(ConvertToPnnaPerm(perm_.data(), perm_.size())); + transpose_op->BindInputs({input_tensor}); + transpose_op->BindOutputs({output_tensor}); + return RET_OK; +} +} // namespace lite +} // namespace mindspore diff --git a/mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.h b/mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.h new file mode 100644 index 00000000..570e25dd --- /dev/null +++ b/mindspore-lite/src/litert/delegate/pnna/op/transpose_pnna.h @@ -0,0 +1,51 @@ +/** + * Copyright 2025 Huawei Technologies Co., Ltd + * + * 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. + */ +#ifndef MINDSPORE_LITE_SRC_LITERT_DELEGATE_PNNA_OP_TRANSPOSE_PNNA_H_ +#define MINDSPORE_LITE_SRC_LITERT_DELEGATE_PNNA_OP_TRANSPOSE_PNNA_H_ + +#include +#include +#include +#include "src/litert/delegate/pnna/op/pnna_op.h" + +namespace mindspore { +namespace lite { +class PNNATranspose : public PNNAOp { + public: + PNNATranspose(const std::string &name, std::vector perm, const std::vector &in_tensors, + const std::vector &out_tensors) + : PNNAOp(name, nullptr, in_tensors, out_tensors, schema::QuantType_QUANT_NONE) { + perm_ = std::move(perm); + type_ = schema::PrimitiveType_Transpose; + } + + PNNATranspose(const std::string &name, const schema::Primitive *primitive, + const std::vector &in_tensors, const std::vector &out_tensors, + schema::QuantType quant_type) + : PNNAOp(name, primitive, in_tensors, out_tensors, quant_type) {} + ~PNNATranspose() override {} + + bool IsSupport() override; + int InitParams() override; + int AddOpToPNNAModel(PNNASubGraph *graph) override; + std::vector GetPerm() { return perm_; } + + private: + std::vector perm_; +}; +} // namespace lite +} // namespace mindspore +#endif // MINDSPORE_LITE_SRC_LITERT_DELEGATE_PNNA_OP_TRANSPOSE_PNNA_H_ diff --git a/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.cc b/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.cc index ee47d6d5..f28326cb 100644 --- a/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.cc +++ b/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.cc @@ -25,6 +25,8 @@ namespace mindspore { namespace lite { Status PNNADelegate::Init() { ctx_ = pnna::Context::Create(); + op_func_lists_.clear(); + op_func_lists_ = {{schema::PrimitiveType_Transpose, GetPNNAOp}}; return mindspore::kSuccess; } diff --git a/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.h b/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.h index 1c25f6d9..06ba7654 100644 --- a/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.h +++ b/mindspore-lite/src/litert/delegate/pnna/pnna_delegate.h @@ -23,9 +23,10 @@ #include #include #include -#include "include/cxx_api/delegate.h" +#include "include/api/delegate.h" #include "src/litert/delegate/pnna/pnna_subgraph.h" #include "src/litert/delegate/pnna/op/pnna_op.h" +#include "src/litert/delegate/pnna/op/transpose_pnna.h" namespace mindspore { namespace lite { diff --git a/mindspore-lite/src/litert/delegate/pnna/pnna_subgraph.h b/mindspore-lite/src/litert/delegate/pnna/pnna_subgraph.h index ae6d8513..e1bda58d 100644 --- a/mindspore-lite/src/litert/delegate/pnna/pnna_subgraph.h +++ b/mindspore-lite/src/litert/delegate/pnna/pnna_subgraph.h @@ -22,7 +22,7 @@ #include #include #include -#include "include/cxx_api/kernel.h" +#include "include/api/kernel.h" #include "src/common/log_adapter.h" #include "src/litert/delegate/pnna/op/pnna_op.h" #include "src/litert/delegate/pnna/pnna_utils.h" diff --git a/mindspore-lite/src/litert/delegate/pnna/pnna_utils.h b/mindspore-lite/src/litert/delegate/pnna/pnna_utils.h index 29d3870a..ef62df7c 100644 --- a/mindspore-lite/src/litert/delegate/pnna/pnna_utils.h +++ b/mindspore-lite/src/litert/delegate/pnna/pnna_utils.h @@ -22,7 +22,7 @@ #include #include #include -#include "include/cxx_api/types.h" +#include "include/api/types.h" #include "pnna_core.h" // NOLINT(build/include_subdir) #define kNCHW_N 0 diff --git a/mindspore-lite/test/ut/src/runtime/kernel/dsp/dsp_test.h b/mindspore-lite/test/ut/src/runtime/kernel/dsp/dsp_test.h index 88419f42..0ee9e34d 100644 --- a/mindspore-lite/test/ut/src/runtime/kernel/dsp/dsp_test.h +++ b/mindspore-lite/test/ut/src/runtime/kernel/dsp/dsp_test.h @@ -19,11 +19,13 @@ #include #include +#include #include "schema/inner/model_generated.h" #include "src/litert/kernel_registry.h" #include "src/litert/kernel/dsp/dsp_subgraph.h" #include "common/common_test.h" #include "nnacl_c/arithmetic_parameter.h" +#include "nnacl_c/int8/quantize.h" namespace mindspore::lite::dsp::test { @@ -50,6 +52,14 @@ class DSPCommonTest : public CommonTest { dsp::DSPRuntimeInnerWrapper *dsp_runtime_wrapper_{nullptr}; std::shared_ptr allocator_; }; + +inline void QuantProcess(float *input, int len, float min, float max, float *scale, int *zero_point, int8_t *output) { + *scale = (max - min) / (std::numeric_limits::max() - std::numeric_limits::min()); + *zero_point = std::numeric_limits::max() - max / (*scale); + if (output) { + Quantize(input, len, *scale, *zero_point, output); + } +} } // namespace mindspore::lite::dsp::test #endif // MINDSPORE_LITE_TEST_UT_SRC_RUNTIME_KERNEL_DSP_DSP_TEST_H_ diff --git a/mindspore-lite/test/ut/src/runtime/kernel/dsp/transpose_tests.cc b/mindspore-lite/test/ut/src/runtime/kernel/dsp/transpose_tests.cc new file mode 100644 index 00000000..a15aca5e --- /dev/null +++ b/mindspore-lite/test/ut/src/runtime/kernel/dsp/transpose_tests.cc @@ -0,0 +1,290 @@ +/** + * Copyright 2025 Huawei Technologies Co., Ltd + * + * 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. + */ + +#include +#include +#include +#include "ut/src/runtime/kernel/dsp/dsp_test.h" +#include "include/api/context.h" +#include "include/api/data_type.h" +#include "include/api/model.h" +#include "nnacl_c/exp_parameter.h" +#include "schema/inner/model_generated.h" +#include "src/litert/kernel/dsp/dsp_subgraph.h" +#include "src/litert/kernel_registry.h" +#include "nnacl_c/int8/quantize.h" + +namespace mindspore::lite::dsp::test { +class TestDSP_Transpose : public DSPCommonTest {}; + +#ifdef SUPPORT_FT78 +TEST_F(TestDSP_Transpose, shape_1_3_2_3_float32_1_3_3_2) { + auto meta_graph = std::make_shared(); + meta_graph->name = "graph"; + + auto node = std::make_unique(); + node->inputIndex = {0, 1}; + node->outputIndex = {2}; + node->primitive = std::make_unique(); + node->primitive->value.type = schema::PrimitiveType_Transpose; + auto primitive = new schema::TransposeT; + node->primitive->value.value = primitive; + node->name = "Transpose"; + meta_graph->nodes.emplace_back(std::move(node)); + meta_graph->inputIndex = {0}; + meta_graph->outputIndex = {2}; + + auto input0 = std::make_unique(); + input0->nodeType = lite::NodeType_Parameter; + input0->dataType = TypeId::kNumberTypeFloat32; + input0->dims = {1, 3, 2, 3}; + input0->offset = -1; + meta_graph->allTensors.emplace_back(std::move(input0)); + + auto perm = std::make_unique(); + perm->nodeType = lite::NodeType_ValueNode; + perm->dataType = TypeId::kNumberTypeInt32; + perm->dims = {4}; + perm->offset = -1; + std::vector perm_data = {0, 3, 1, 2}; + perm->data.resize(sizeof(int32_t) * 4); + memcpy(perm->data.data(), perm_data.data(), 4 * sizeof(int32_t)); + meta_graph->allTensors.emplace_back(std::move(perm)); + + auto output = std::make_unique(); + output->nodeType = lite::NodeType_Parameter; + output->dataType = TypeId::kNumberTypeFloat32; + output->offset = -1; + meta_graph->allTensors.emplace_back(std::move(output)); + + flatbuffers::FlatBufferBuilder builder(1024); + auto offset = schema::MetaGraph::Pack(builder, meta_graph.get()); + builder.Finish(offset); + schema::FinishMetaGraphBuffer(builder, offset); + size_t size = builder.GetSize(); + const char *content = reinterpret_cast(builder.GetBufferPointer()); + + // create a context + auto context = std::make_shared(); + context->SetBuiltInDelegate(mindspore::DelegateMode::kPNNA); + auto &device_list = context->MutableDeviceInfo(); + std::shared_ptr device_info = std::make_shared(); + device_list.push_back(device_info); + + // build a model + auto model = std::make_shared(); + auto ret = model->Build(content, size, kMindIR_Lite, context); + ASSERT_EQ(kSuccess, ret.StatusCode()); + auto inputs = model->GetInputs(); + ASSERT_EQ(inputs.size(), 1); + auto inTensor = inputs.front(); + auto impl = inTensor.impl(); + ASSERT_NE(nullptr, impl); + float *in0_data = static_cast(inTensor.MutableData()); + std::vector input_data = {0.59885779, 0.62662862, 0.63011179, 0.82569427, 0.64772359, 0.42895413, + 0.30216458, 0.01351635, 0.32545444, 0.0360674, 0.33967769, 0.18092504, + 0.09479915, 0.52258112, 0.46735646, 0.95689111, 0.51619059, 0.82685718}; + std::vector expect = {0.59885776, 0.82569426, 0.30216458, 0.0360674, 0.09479915, 0.9568911, + 0.62662864, 0.6477236, 0.01351635, 0.3396777, 0.5225811, 0.5161906, + 0.6301118, 0.4289541, 0.32545444, 0.18092504, 0.46735647, 0.8268572}; + for (size_t i = 0; i < input_data.size(); ++i) in0_data[i] = input_data[i]; + std::vector outputs; + ret = model->Predict(inputs, &outputs); + ASSERT_EQ(kSuccess, ret.StatusCode()); + ASSERT_EQ(outputs.size(), 1); + auto *outData = reinterpret_cast(outputs.front().Data().get()); + ASSERT_EQ(0, CompareOutputData(outData, expect.data(), expect.size(), 1e-3f)); +} + +TEST_F(TestDSP_Transpose, shape_1_3_3_2_float32_1_3_2_3) { + auto meta_graph = std::make_shared(); + meta_graph->name = "graph"; + + auto node = std::make_unique(); + node->inputIndex = {0, 1}; + node->outputIndex = {2}; + node->primitive = std::make_unique(); + node->primitive->value.type = schema::PrimitiveType_Transpose; + auto primitive = new schema::TransposeT; + node->primitive->value.value = primitive; + node->name = "Transpose"; + meta_graph->nodes.emplace_back(std::move(node)); + meta_graph->inputIndex = {0}; + meta_graph->outputIndex = {2}; + + auto input0 = std::make_unique(); + input0->nodeType = lite::NodeType_Parameter; + input0->dataType = TypeId::kNumberTypeFloat32; + input0->dims = {1, 3, 3, 2}; + input0->offset = -1; + meta_graph->allTensors.emplace_back(std::move(input0)); + + auto perm = std::make_unique(); + perm->nodeType = lite::NodeType_ValueNode; + perm->dataType = TypeId::kNumberTypeInt32; + perm->dims = {4}; + perm->offset = -1; + std::vector perm_data = {0, 2, 3, 1}; + perm->data.resize(sizeof(int32_t) * 4); + memcpy(perm->data.data(), perm_data.data(), 4 * sizeof(int32_t)); + meta_graph->allTensors.emplace_back(std::move(perm)); + + auto output = std::make_unique(); + output->nodeType = lite::NodeType_Parameter; + output->dataType = TypeId::kNumberTypeFloat32; + output->offset = -1; + meta_graph->allTensors.emplace_back(std::move(output)); + + flatbuffers::FlatBufferBuilder builder(1024); + auto offset = schema::MetaGraph::Pack(builder, meta_graph.get()); + builder.Finish(offset); + schema::FinishMetaGraphBuffer(builder, offset); + size_t size = builder.GetSize(); + const char *content = reinterpret_cast(builder.GetBufferPointer()); + + // create a context + auto context = std::make_shared(); + context->SetBuiltInDelegate(mindspore::DelegateMode::kPNNA); + auto &device_list = context->MutableDeviceInfo(); + std::shared_ptr device_info = std::make_shared(); + device_list.push_back(device_info); + + // build a model + auto model = std::make_shared(); + auto ret = model->Build(content, size, kMindIR_Lite, context); + ASSERT_EQ(kSuccess, ret.StatusCode()); + auto inputs = model->GetInputs(); + ASSERT_EQ(inputs.size(), 1); + auto inTensor = inputs.front(); + auto impl = inTensor.impl(); + ASSERT_NE(nullptr, impl); + float *in0_data = static_cast(inTensor.MutableData()); + std::vector input_data = {0.59885779, 0.62662862, 0.63011179, 0.82569427, 0.64772359, 0.42895413, + 0.30216458, 0.01351635, 0.32545444, 0.0360674, 0.33967769, 0.18092504, + 0.09479915, 0.52258112, 0.46735646, 0.95689111, 0.51619059, 0.82685718}; + std::vector expect = {0.59885776, 0.30216458, 0.09479915, 0.62662864, 0.01351635, 0.5225811, + 0.6301118, 0.32545444, 0.46735647, 0.82569426, 0.0360674, 0.9568911, + 0.6477236, 0.3396777, 0.5161906, 0.42895412, 0.18092504, 0.8268572}; + for (size_t i = 0; i < input_data.size(); ++i) in0_data[i] = input_data[i]; + std::vector outputs; + ret = model->Predict(inputs, &outputs); + ASSERT_EQ(kSuccess, ret.StatusCode()); + ASSERT_EQ(outputs.size(), 1); + auto *outData = reinterpret_cast(outputs.front().Data().get()); + ASSERT_EQ(0, CompareOutputData(outData, expect.data(), expect.size(), 1e-3f)); +} + +TEST_F(TestDSP_Transpose, shape_1_3_2_3_int8_1_3_3_2) { + auto meta_graph = std::make_shared(); + meta_graph->name = "graph"; + + auto node = std::make_unique(); + node->inputIndex = {0, 1}; + node->outputIndex = {2}; + node->primitive = std::make_unique(); + node->primitive->value.type = schema::PrimitiveType_Transpose; + auto primitive = new schema::TransposeT; + node->primitive->value.value = primitive; + node->name = "Transpose"; + meta_graph->nodes.emplace_back(std::move(node)); + meta_graph->inputIndex = {0}; + meta_graph->outputIndex = {2}; + + int length = 3 * 3 * 2; + std::vector in0 = {0.59885779, 0.62662862, 0.63011179, 0.82569427, 0.64772359, 0.42895413, + 0.30216458, 0.01351635, 0.32545444, 0.0360674, 0.33967769, 0.18092504, + 0.09479915, 0.52258112, 0.46735646, 0.95689111, 0.51619059, 0.82685718}; + std::vector input0_data(length); + float in0_scale; + int in0_zp; + QuantProcess(in0.data(), length, 0, 1, &in0_scale, &in0_zp, input0_data.data()); + + std::vector expect = {0.59885776, 0.82569426, 0.30216458, 0.0360674, 0.09479915, 0.9568911, + 0.62662864, 0.6477236, 0.01351635, 0.3396777, 0.5225811, 0.5161906, + 0.6301118, 0.4289541, 0.32545444, 0.18092504, 0.46735647, 0.8268572}; + float out_scale; + int out_zp; + QuantProcess(expect.data(), length, 0, 1, &out_scale, &out_zp, nullptr); + + auto input_quant0 = std::make_unique(); + input_quant0->scale = in0_scale; + input_quant0->zeroPoint = in0_zp; + + auto out_quant = std::make_unique(); + out_quant->scale = out_scale; + out_quant->zeroPoint = out_zp; + + auto input0 = std::make_unique(); + input0->nodeType = lite::NodeType_Parameter; + input0->dataType = TypeId::kNumberTypeInt8; + input0->dims = {1, 3, 2, 3}; + input0->offset = -1; + input0->quantParams.emplace_back(std::move(input_quant0)); + meta_graph->allTensors.emplace_back(std::move(input0)); + + auto perm = std::make_unique(); + perm->nodeType = lite::NodeType_ValueNode; + perm->dataType = TypeId::kNumberTypeInt32; + perm->dims = {4}; + perm->offset = -1; + std::vector perm_data = {0, 3, 1, 2}; + perm->data.resize(sizeof(int32_t) * 4); + memcpy(perm->data.data(), perm_data.data(), 4 * sizeof(int32_t)); + meta_graph->allTensors.emplace_back(std::move(perm)); + + auto output = std::make_unique(); + output->nodeType = lite::NodeType_Parameter; + output->dataType = TypeId::kNumberTypeInt8; + output->offset = -1; + output->quantParams.emplace_back(std::move(out_quant)); + meta_graph->allTensors.emplace_back(std::move(output)); + + flatbuffers::FlatBufferBuilder builder(1024); + auto offset = schema::MetaGraph::Pack(builder, meta_graph.get()); + builder.Finish(offset); + schema::FinishMetaGraphBuffer(builder, offset); + size_t size = builder.GetSize(); + const char *content = reinterpret_cast(builder.GetBufferPointer()); + + // create a context + auto context = std::make_shared(); + context->SetBuiltInDelegate(mindspore::DelegateMode::kPNNA); + auto &device_list = context->MutableDeviceInfo(); + std::shared_ptr device_info = std::make_shared(); + device_list.push_back(device_info); + + // build a model + auto model = std::make_shared(); + auto ret = model->Build(content, size, kMindIR_Lite, context); + ASSERT_EQ(kSuccess, ret.StatusCode()); + auto inputs = model->GetInputs(); + ASSERT_EQ(inputs.size(), 1); + auto inTensor = inputs.front(); + auto impl = inTensor.impl(); + ASSERT_NE(nullptr, impl); + int8_t *in0_data = static_cast(inTensor.MutableData()); + for (size_t i = 0; i < inputs[0].ElementNum(); ++i) in0_data[i] = input0_data[i]; + std::vector outputs; + ret = model->Predict(inputs, &outputs); + ASSERT_EQ(kSuccess, ret.StatusCode()); + ASSERT_EQ(outputs.size(), 1); + std::vector out(length); + auto *outData = reinterpret_cast(outputs.front().Data().get()); + Dequantize(outData, length, out_scale, out_zp, out.data()); + ASSERT_EQ(0, CompareOutputData(out.data(), expect.data(), length, 1e-3)); +} +#endif +} // namespace mindspore::lite::dsp::test -- Gitee