mirror of
https://github.com/saymrwulf/onnxruntime.git
synced 2026-07-29 20:14:01 +00:00
Fix issue that the generated context cache model inputs/outputs order is not guaranteed (#19195)
Fix issue that the generated context cache model inputs/outputs order is not guaranteed ### Description Currently, QNN EP generate the context cache model in Compile() method which only get access to the partitioned graph. And the inputs/outputs order for the partitioned graph is not guaranteed. And EP doesn't have the view of the input user model. Have to move the context cache model generation to a higher level in GraphPartitioner which has the view of the partitioned model. This is also a break down of PR for multi-partition support. https://github.com/microsoft/onnxruntime/pull/18865
This commit is contained in:
parent
a3ecb63267
commit
6e17571f2f
13 changed files with 210 additions and 26 deletions
|
|
@ -326,6 +326,15 @@ class IExecutionProvider {
|
|||
*/
|
||||
virtual std::vector<AllocatorPtr> CreatePreferredAllocators() { return std::vector<AllocatorPtr>(); };
|
||||
|
||||
/**
|
||||
* Get the array of pointers for EPContext nodes
|
||||
* EP needs to implement this if has the requirement to generate the context cache model. Otherwise leave it.
|
||||
* Default return an empty vector if not provided by the Execution Provider
|
||||
*/
|
||||
virtual const InlinedVector<const Node*> GetEpContextNodes() const {
|
||||
return InlinedVector<const Node*>();
|
||||
}
|
||||
|
||||
private:
|
||||
const std::string type_;
|
||||
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ static const char* const kOrtSessionOptionsOptimizedModelExternalInitializersFil
|
|||
static const char* const kOrtSessionOptionsOptimizedModelExternalInitializersMinSizeInBytes =
|
||||
"session.optimized_model_external_initializers_min_size_in_bytes";
|
||||
|
||||
// Enable EP context feature to dump the partitioned graph which include the EP context into Onnx file.
|
||||
// Enable EP context feature to dump the partitioned graph which includes the EP context into Onnx file.
|
||||
// The dumped Onnx model with EP context can be used for future inference to avoid the EP graph partitioning/compile overhead.
|
||||
// "0": disable. (default)
|
||||
// "1": enable.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
#include "core/graph/function_utils.h"
|
||||
#include "core/graph/graph_viewer.h"
|
||||
#include "core/graph/model.h"
|
||||
#include "core/session/onnxruntime_session_options_config_keys.h"
|
||||
|
||||
// uncomment this line to count non-CUDA ops in ONNX domain
|
||||
// #define COUNT_NON_CUDA_OPS
|
||||
|
|
@ -634,6 +635,100 @@ static Status InlineFunctionsAOTImpl(const ExecutionProviders& execution_provide
|
|||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status CreateEpContextModel(const ExecutionProviders& execution_providers,
|
||||
const Graph& graph,
|
||||
const std::string& ep_context_path,
|
||||
const logging::Logger& logger) {
|
||||
InlinedVector<const Node*> all_ep_context_nodes;
|
||||
for (const auto& ep : execution_providers) {
|
||||
const InlinedVector<const Node*> ep_context_nodes = ep->GetEpContextNodes();
|
||||
all_ep_context_nodes.insert(all_ep_context_nodes.begin(), ep_context_nodes.begin(), ep_context_nodes.end());
|
||||
}
|
||||
|
||||
auto get_ep_context_node = [&all_ep_context_nodes](const std::string& node_name) -> std::pair<bool, const Node*> {
|
||||
for (auto& node : all_ep_context_nodes) {
|
||||
if (node_name == node->Name()) {
|
||||
return std::make_pair(true, node);
|
||||
}
|
||||
}
|
||||
return std::make_pair(false, static_cast<const Node*>(nullptr));
|
||||
};
|
||||
|
||||
onnxruntime::PathString context_cache_path;
|
||||
PathString model_pathstring = graph.ModelPath().ToPathString();
|
||||
if (all_ep_context_nodes.size() > 0) {
|
||||
if (!ep_context_path.empty()) {
|
||||
context_cache_path = ToPathString(ep_context_path);
|
||||
} else if (!model_pathstring.empty()) {
|
||||
context_cache_path = model_pathstring + ToPathString("_ctx.onnx");
|
||||
}
|
||||
|
||||
{
|
||||
#ifdef _WIN32
|
||||
std::wifstream fs(context_cache_path);
|
||||
#else
|
||||
std::ifstream fs(context_cache_path);
|
||||
#endif
|
||||
ORT_RETURN_IF(fs.good(), "Failed to generate EP context model since the file exist already.");
|
||||
}
|
||||
|
||||
Model ep_context_model(graph.Name(), false, ModelMetaData(), PathString(), IOnnxRuntimeOpSchemaRegistryList(),
|
||||
graph.DomainToVersionMap(), {}, logger);
|
||||
auto& ep_graph = ep_context_model.MainGraph();
|
||||
ep_graph.SetDescription(graph.Description());
|
||||
|
||||
// Set inputs outputs explicitly to make sure the order is same as the user model.
|
||||
auto inputs = graph.GetInputs();
|
||||
auto outputs = graph.GetOutputs();
|
||||
|
||||
InlinedVector<const NodeArg*> ep_graph_inputs;
|
||||
ep_graph_inputs.reserve(inputs.size());
|
||||
for (auto& input : inputs) {
|
||||
auto input_arg = graph.GetNodeArg(input->Name());
|
||||
auto& ep_graph_input_arg = ep_graph.GetOrCreateNodeArg(input_arg->Name(), input_arg->TypeAsProto());
|
||||
ep_graph_inputs.push_back(&ep_graph_input_arg);
|
||||
}
|
||||
|
||||
InlinedVector<const NodeArg*> ep_graph_outputs;
|
||||
ep_graph_outputs.reserve(outputs.size());
|
||||
for (auto& output : outputs) {
|
||||
auto output_arg = graph.GetNodeArg(output->Name());
|
||||
auto& ep_graph_output_arg = ep_graph.GetOrCreateNodeArg(output_arg->Name(), output_arg->TypeAsProto());
|
||||
ep_graph_outputs.push_back(&ep_graph_output_arg);
|
||||
}
|
||||
|
||||
ep_graph.SetInputs(ep_graph_inputs);
|
||||
ep_graph.SetOutputs(ep_graph_outputs);
|
||||
|
||||
for (const auto& node : graph.Nodes()) {
|
||||
// the fused node and EPContext node has same node name
|
||||
auto ep_context_node = get_ep_context_node(node.Name());
|
||||
// Use EpContext node created by the EPs if name matched, otherwise use node from original model
|
||||
if (ep_context_node.first) {
|
||||
ep_graph.AddNode(*ep_context_node.second);
|
||||
} else {
|
||||
ep_graph.AddNode(node);
|
||||
}
|
||||
}
|
||||
|
||||
// handle initializers
|
||||
for (const auto& input : graph.GetInputsIncludingInitializers()) {
|
||||
const ONNX_NAMESPACE::TensorProto* initializer = nullptr;
|
||||
if (graph.GetInitializedTensor(input->Name(), initializer)) {
|
||||
// There initializer could have duplicates so make sure we only add once
|
||||
const ONNX_NAMESPACE::TensorProto* subgraph_initializer = nullptr;
|
||||
if (!ep_graph.GetInitializedTensor(input->Name(), subgraph_initializer)) {
|
||||
ep_graph.AddInitializedTensor(*initializer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ORT_RETURN_IF_ERROR(Model::Save(ep_context_model, context_cache_path));
|
||||
}
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
static Status PartitionOnnxFormatModel(const PartitionParams& partition_params, GraphPartitioner::Mode mode,
|
||||
const ExecutionProviders& execution_providers,
|
||||
KernelRegistryManager& kernel_registry_manager) {
|
||||
|
|
@ -840,6 +935,8 @@ Status GraphPartitioner::InlineFunctionsAOT(Model& model,
|
|||
|
||||
Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr,
|
||||
const layout_transformation::TransformLayoutFunction& transform_layout_function,
|
||||
const ConfigOptions& config_options,
|
||||
const logging::Logger& logger,
|
||||
Mode mode,
|
||||
const layout_transformation::DebugGraphFn& debug_graph_fn) const {
|
||||
// It is a greedy partitioning algorithm per provider preferences user provided when calling ONNX RUNTIME right now.
|
||||
|
|
@ -886,7 +983,15 @@ Status GraphPartitioner::Partition(Graph& graph, FuncManager& func_mgr,
|
|||
#if !defined(ORT_MINIMAL_BUILD)
|
||||
ORT_RETURN_IF_ERROR(PartitionOnnxFormatModel(partition_params, mode,
|
||||
providers_, kernel_registry_mgr_));
|
||||
|
||||
bool ep_context_enabled = config_options.GetConfigOrDefault(kOrtSessionOptionEpContextEnable, "0") == "1";
|
||||
std::string ep_context_path = config_options.GetConfigOrDefault(kOrtSessionOptionEpContextFilePath, "");
|
||||
if (ep_context_enabled) {
|
||||
ORT_RETURN_IF_ERROR(CreateEpContextModel(providers_, graph, ep_context_path, logger));
|
||||
}
|
||||
#else
|
||||
ORT_UNUSED_PARAMETER(config_options);
|
||||
ORT_UNUSED_PARAMETER(logger);
|
||||
return ORT_MAKE_STATUS(ONNXRUNTIME, FAIL, "ONNX models are not supported in this build.");
|
||||
#endif //! defined(ORT_MINIMAL_BUILD)
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ namespace onnxruntime {
|
|||
class ExecutionProviders;
|
||||
class KernelRegistryManager;
|
||||
class Model;
|
||||
struct ConfigOptions;
|
||||
|
||||
class GraphPartitioner {
|
||||
public:
|
||||
|
|
@ -31,6 +32,8 @@ class GraphPartitioner {
|
|||
// Run partitioning.
|
||||
Status Partition(Graph& graph, FuncManager& func_mgr,
|
||||
const layout_transformation::TransformLayoutFunction& transform_layout_function,
|
||||
const ConfigOptions& config_options,
|
||||
const logging::Logger& logger,
|
||||
Mode mode = Mode::kNormal,
|
||||
const layout_transformation::DebugGraphFn& debug_graph_fn = {}) const;
|
||||
|
||||
|
|
|
|||
|
|
@ -230,8 +230,7 @@ Status ValidateWithContextFile(const onnxruntime::PathString& context_cache_path
|
|||
return Status::OK();
|
||||
}
|
||||
|
||||
Status GenerateCtxCacheOnnxModel(const std::string model_name,
|
||||
const std::string model_description,
|
||||
Status GenerateCtxCacheOnnxModel(Model* model,
|
||||
unsigned char* buffer,
|
||||
uint64_t buffer_size,
|
||||
const std::string& sdk_build_version,
|
||||
|
|
@ -240,11 +239,7 @@ Status GenerateCtxCacheOnnxModel(const std::string model_name,
|
|||
const onnxruntime::PathString& context_cache_path,
|
||||
bool qnn_context_embed_mode,
|
||||
const logging::Logger& logger) {
|
||||
std::unordered_map<std::string, int> domain_to_version = {{kOnnxDomain, 11}, {kMSDomain, 1}};
|
||||
Model model(model_name, false, ModelMetaData(), PathString(), IOnnxRuntimeOpSchemaRegistryList(),
|
||||
domain_to_version, {}, logger);
|
||||
auto& graph = model.MainGraph();
|
||||
graph.SetDescription(model_description);
|
||||
auto& graph = model->MainGraph();
|
||||
|
||||
using namespace ONNX_NAMESPACE;
|
||||
int index = 0;
|
||||
|
|
@ -270,7 +265,7 @@ Status GenerateCtxCacheOnnxModel(const std::string model_name,
|
|||
nullptr,
|
||||
kMSDomain);
|
||||
|
||||
// Only dump the context buffer once since all QNN graph are in one single context
|
||||
// Only dump the context buffer once since all QNN graphs are in one single context
|
||||
if (0 == index) {
|
||||
if (qnn_context_embed_mode) {
|
||||
std::string cache_payload(buffer, buffer + buffer_size);
|
||||
|
|
@ -296,8 +291,6 @@ Status GenerateCtxCacheOnnxModel(const std::string model_name,
|
|||
ep_node.AddAttribute(SOURCE, kQnnExecutionProvider);
|
||||
++index;
|
||||
}
|
||||
ORT_RETURN_IF_ERROR(graph.Resolve());
|
||||
ORT_RETURN_IF_ERROR(Model::Save(model, context_cache_path));
|
||||
|
||||
return Status::OK();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,8 +73,7 @@ Status GetMetadataFromEpContextModel(const onnxruntime::PathString& ctx_onnx_mod
|
|||
std::string& cache_source,
|
||||
const logging::Logger& logger);
|
||||
|
||||
Status GenerateCtxCacheOnnxModel(const std::string model_name,
|
||||
const std::string model_description,
|
||||
Status GenerateCtxCacheOnnxModel(Model* model,
|
||||
unsigned char* buffer,
|
||||
uint64_t buffer_size,
|
||||
const std::string& sdk_build_version,
|
||||
|
|
|
|||
|
|
@ -613,8 +613,8 @@ Status QNNExecutionProvider::Compile(const std::vector<FusedNodeAndGraph>& fused
|
|||
ORT_RETURN_IF(fused_nodes_and_graphs.size() != 1, "Only support single partition for context cache feature.");
|
||||
uint64_t buffer_size(0);
|
||||
auto context_buffer = qnn_backend_manager_->GetContextBinaryBuffer(buffer_size);
|
||||
ORT_RETURN_IF_ERROR(qnn::GenerateCtxCacheOnnxModel(model_name,
|
||||
model_description,
|
||||
qnn_ep_context_model_ = std::make_unique<Model>("qnn_ep_context_model", false, logger);
|
||||
ORT_RETURN_IF_ERROR(qnn::GenerateCtxCacheOnnxModel(qnn_ep_context_model_.get(),
|
||||
context_buffer.get(),
|
||||
buffer_size,
|
||||
qnn_backend_manager_->GetSdkVersion(),
|
||||
|
|
@ -626,4 +626,16 @@ Status QNNExecutionProvider::Compile(const std::vector<FusedNodeAndGraph>& fused
|
|||
}
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
const InlinedVector<const Node*> QNNExecutionProvider::GetEpContextNodes() const {
|
||||
InlinedVector<const Node*> ep_context_nodes;
|
||||
if (qnn_ep_context_model_) {
|
||||
const auto& graph = qnn_ep_context_model_->MainGraph();
|
||||
for (const auto& node : graph.Nodes()) {
|
||||
ep_context_nodes.push_back(graph.GetNode(node.Index()));
|
||||
}
|
||||
}
|
||||
|
||||
return ep_context_nodes;
|
||||
}
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "core/providers/qnn/builder/qnn_backend_manager.h"
|
||||
#include "core/providers/qnn/builder/qnn_model.h"
|
||||
#include "core/providers/qnn/builder/qnn_graph_configs_helper.h"
|
||||
#include "core/graph/model.h"
|
||||
|
||||
namespace onnxruntime {
|
||||
|
||||
|
|
@ -35,6 +36,8 @@ class QNNExecutionProvider : public IExecutionProvider {
|
|||
|
||||
DataLayout GetPreferredLayout() const override;
|
||||
|
||||
const InlinedVector<const Node*> GetEpContextNodes() const override;
|
||||
|
||||
private:
|
||||
bool IsNodeSupported(qnn::QnnModelWrapper& qnn_model_wrapper, const NodeUnit& node_unit,
|
||||
std::unordered_map<const NodeUnit*, bool>& node_unit_supported_result,
|
||||
|
|
@ -66,6 +69,7 @@ class QNNExecutionProvider : public IExecutionProvider {
|
|||
bool disable_cpu_ep_fallback_ = false; // True if CPU EP fallback has been disabled for this session.
|
||||
bool qnn_context_embed_mode_ = true;
|
||||
int32_t vtcm_size_in_mb_ = 0;
|
||||
std::unique_ptr<onnxruntime::Model> qnn_ep_context_model_;
|
||||
};
|
||||
|
||||
} // namespace onnxruntime
|
||||
|
|
|
|||
|
|
@ -1164,6 +1164,7 @@ common::Status InferenceSession::TransformGraph(onnxruntime::Graph& graph, bool
|
|||
|
||||
// Do partitioning based on execution providers' capabilities.
|
||||
ORT_RETURN_IF_ERROR_SESSIONID_(partitioner.Partition(graph, session_state_->GetMutableFuncMgr(), transform_layout_fn,
|
||||
session_options_.config_options, *session_logger_,
|
||||
mode, debug_graph_fn));
|
||||
|
||||
// apply Level2 and higher transformers.
|
||||
|
|
@ -1458,7 +1459,9 @@ namespace {
|
|||
Status PartitionOrtFormatModel(onnxruntime::Graph& graph,
|
||||
const ExecutionProviders& providers,
|
||||
KernelRegistryManager& kernel_registry_manager,
|
||||
SessionState& session_state) {
|
||||
SessionState& session_state,
|
||||
const ConfigOptions& config_options,
|
||||
const logging::Logger& logger) {
|
||||
layout_transformation::TransformLayoutFunction transform_layout_fn = nullptr;
|
||||
|
||||
#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD)
|
||||
|
|
@ -1479,6 +1482,8 @@ Status PartitionOrtFormatModel(onnxruntime::Graph& graph,
|
|||
ORT_RETURN_IF_ERROR(partitioner.Partition(graph,
|
||||
session_state.GetMutableFuncMgr(),
|
||||
transform_layout_fn,
|
||||
config_options,
|
||||
logger,
|
||||
GraphPartitioner::Mode::kOrtFormatLoad));
|
||||
|
||||
return Status::OK();
|
||||
|
|
@ -1833,7 +1838,7 @@ common::Status InferenceSession::Initialize() {
|
|||
#endif // !defined(ORT_MINIMAL_BUILD)
|
||||
} else {
|
||||
ORT_RETURN_IF_ERROR_SESSIONID_(PartitionOrtFormatModel(graph, execution_providers_, kernel_registry_manager_,
|
||||
*session_state_));
|
||||
*session_state_, session_options_.config_options, *session_logger_));
|
||||
|
||||
#if !defined(ORT_MINIMAL_BUILD) || defined(ORT_EXTENDED_MINIMAL_BUILD)
|
||||
const auto& cpu_ep = *execution_providers_.Get(onnxruntime::kCpuExecutionProvider);
|
||||
|
|
|
|||
|
|
@ -171,13 +171,16 @@ TEST_P(SessionStateTestP, TestInitializerProcessing) {
|
|||
|
||||
GraphPartitioner partitioner(krm, execution_providers);
|
||||
ASSERT_STATUS_OK(
|
||||
partitioner.Partition(graph, session_state.GetMutableFuncMgr(),
|
||||
[](Graph& graph, bool& modified, const IExecutionProvider& execution_provider,
|
||||
const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status {
|
||||
AllocatorPtr cpu_allocator = std::make_shared<CPUAllocator>();
|
||||
return layout_transformation::TransformLayoutForEP(
|
||||
graph, modified, execution_provider, std::move(cpu_allocator), debug_graph_fn);
|
||||
}));
|
||||
partitioner.Partition(
|
||||
graph, session_state.GetMutableFuncMgr(),
|
||||
[](Graph& graph, bool& modified, const IExecutionProvider& execution_provider,
|
||||
const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status {
|
||||
AllocatorPtr cpu_allocator = std::make_shared<CPUAllocator>();
|
||||
return layout_transformation::TransformLayoutForEP(
|
||||
graph, modified, execution_provider, std::move(cpu_allocator), debug_graph_fn);
|
||||
},
|
||||
sess_options.config_options,
|
||||
DefaultLoggingManager().DefaultLogger()));
|
||||
|
||||
ASSERT_STATUS_OK(session_state.FinalizeSessionState(oss.str(), krm));
|
||||
|
||||
|
|
@ -257,7 +260,9 @@ TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) {
|
|||
const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status {
|
||||
return layout_transformation::TransformLayoutForEP(graph, modified, execution_provider,
|
||||
cpu_allocator, debug_graph_fn);
|
||||
}));
|
||||
},
|
||||
sess_options.config_options,
|
||||
DefaultLoggingManager().DefaultLogger()));
|
||||
|
||||
ASSERT_STATUS_OK(session_state.FinalizeSessionState(oss.str(), krm));
|
||||
|
||||
|
|
@ -314,7 +319,9 @@ TEST(SessionStateTest, TestInitializerMemoryAllocatedUsingNonArenaMemory) {
|
|||
const layout_transformation::DebugGraphFn& debug_graph_fn) -> Status {
|
||||
return layout_transformation::TransformLayoutForEP(
|
||||
graph, modified, execution_provider, cpu_allocator, debug_graph_fn);
|
||||
}));
|
||||
},
|
||||
sess_options.config_options,
|
||||
DefaultLoggingManager().DefaultLogger()));
|
||||
|
||||
// Finalize the session state
|
||||
ASSERT_STATUS_OK(session_state.FinalizeSessionState(oss.str(), krm));
|
||||
|
|
|
|||
|
|
@ -600,6 +600,51 @@ TEST_F(QnnHTPBackendTests, QnnContextBinaryGeneration2InputTypes) {
|
|||
|
||||
// Make sure the Qnn context cache binary file is generated
|
||||
EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str()));
|
||||
|
||||
// clean up
|
||||
ASSERT_EQ(std::remove(context_binary_file.c_str()), 0);
|
||||
}
|
||||
|
||||
// Generate context cache model from the ONNX models with 2 inputs.
|
||||
// The generated model should have same input order.
|
||||
// The input ONNX model is created in the way that the model inputs order
|
||||
// is different with the order in the graph (topological order).
|
||||
// It cause issue if the generated model doesn't set the inputs/outputs explicitly.
|
||||
TEST_F(QnnHTPBackendTests, QnnContextGeneration2InputsOrderIssue) {
|
||||
ProviderOptions provider_options;
|
||||
#if defined(_WIN32)
|
||||
provider_options["backend_path"] = "QnnHtp.dll";
|
||||
#else
|
||||
provider_options["backend_path"] = "libQnnHtp.so";
|
||||
#endif
|
||||
|
||||
// Add kMSDomain to cover contrib op like Gelu
|
||||
const std::unordered_map<std::string, int> domain_to_version = {{"", 13}, {kMSDomain, 1}};
|
||||
|
||||
auto& logging_manager = DefaultLoggingManager();
|
||||
logging_manager.SetDefaultLoggerSeverity(logging::Severity::kERROR);
|
||||
|
||||
const std::string context_binary_file = "./qnn_ctx_2_inputs_order_test_gen.onnx";
|
||||
Ort::SessionOptions so;
|
||||
so.AddConfigEntry(kOrtSessionOptionEpContextEnable, "1");
|
||||
so.AddConfigEntry(kOrtSessionOptionEpContextFilePath, context_binary_file.c_str());
|
||||
|
||||
so.AppendExecutionProvider("QNN", provider_options);
|
||||
|
||||
Ort::Session session(*ort_env, ORT_TSTR("testdata/qnn_ctx_2_inputs_order_test.onnx"), so);
|
||||
|
||||
// Make sure the Qnn context cache binary file is generated
|
||||
EXPECT_TRUE(std::filesystem::exists(context_binary_file.c_str()));
|
||||
|
||||
std::shared_ptr<Model> model;
|
||||
ASSERT_STATUS_OK(Model::Load(ToPathString(context_binary_file), model, nullptr, DefaultLoggingManager().DefaultLogger()));
|
||||
auto inputs = model->MainGraph().GetInputs();
|
||||
EXPECT_TRUE(inputs.size() == 2);
|
||||
EXPECT_TRUE(inputs[0]->Name() == "attention_mask");
|
||||
EXPECT_TRUE(inputs[1]->Name() == "Add_input_0");
|
||||
|
||||
// clean up
|
||||
ASSERT_EQ(std::remove(context_binary_file.c_str()), 0);
|
||||
}
|
||||
|
||||
// A repro of QC case 06838696, accuracy issue for Cast + Op (quantized)
|
||||
|
|
|
|||
|
|
@ -778,6 +778,8 @@ TEST_F(QnnHTPBackendTests, ContextBinaryCacheEmbedModeTest) {
|
|||
QDQTolerance(),
|
||||
logging::Severity::kERROR,
|
||||
context_binary_file);
|
||||
// Clean up
|
||||
ASSERT_EQ(std::remove(context_binary_file.c_str()), 0);
|
||||
}
|
||||
|
||||
// Run QDQ model on HTP 3 times
|
||||
|
|
|
|||
BIN
onnxruntime/test/testdata/qnn_ctx_2_inputs_order_test.onnx
vendored
Normal file
BIN
onnxruntime/test/testdata/qnn_ctx_2_inputs_order_test.onnx
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue