Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CoreML] Create EP by AppendExecutionProvider #22675

Open
wants to merge 21 commits into
base: main
Choose a base branch
from
Open

Conversation

wejoncy
Copy link
Contributor

@wejoncy wejoncy commented Oct 31, 2024

Description

Motivation and Context

@wejoncy wejoncy changed the title genenral appendEP for coreml [CoreML] Support to use general API to create EP Nov 1, 2024
@wejoncy wejoncy force-pushed the jicwen/coreml_aep branch 2 times, most recently from 96b7f1d to 530000a Compare November 4, 2024 09:30
@wejoncy wejoncy changed the title [CoreML] Support to use general API to create EP [CoreML] Create EP by AppendExecutionProvider Nov 4, 2024
js/react_native/ios/OnnxruntimeModule.mm Outdated Show resolved Hide resolved
coreml_version_(coreml::util::CoreMLVersion()) {
coreml_flags_ = options.count("coreml_flags") ? std::stoi(options.at("coreml_flags")) : 0;
Copy link
Contributor

@skottmckay skottmckay Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: would be good to define the option names as constants in a header

Can we also add options so the current flags don't need to be used? Some might fold together like the flags to choose device might be in an option called 'MLComputeUnits' and allow 'MLComputeUnitsCPUAndNeuralEngine|MLComputeUnitsCPUAndGPU|MLComputeUnitsCPUOnly|MLComputeUnitsAll' to be provided as a value. #Closed

Copy link
Contributor Author

@wejoncy wejoncy Nov 6, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

define the option names as constants in a header

seems not avaible for now. Other EPs used option names as well and we don't have onnxruntime_provider_options_config_keys.h.
Too much changes involved for this pattern.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can support both provider_options: "MLComputeUnits" and "coreml_flags". "coreml_flags" is compataible with the old API which is essential as the old API is used in many place.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can the option names be defined in include\onnxruntime\core\providers\coreml\coreml_provider_factory.h?

Optional for an external user to include that file with the new setup.

Option names are completely EP specific so I don't think we'd want an onnxruntime_provider_options_config_keys.h.

I wasn't suggesting getting rid of support for the existing coreml_flags. Just that a user should be forced to use coreml_flags for older settings, and an option key/value for newer ones. Ideally it's one (old style) or the other (new style).

@@ -439,7 +439,7 @@ select from 'TF8', 'TF16', 'UINT8', 'FLOAT', 'ITENSOR'. \n)");
}
}
// COREML_FLAG_CREATE_MLPROGRAM
Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_CoreML(session_options, coreml_flags));
session_options.AppendExecutionProvider("Coreml", {{"coreml_flags", std::to_string(coreml_flags)}});
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

May be better to convert this is just pass through option key/value pairs instead of setting flags (assuming we add options that cover the current flags). That way it doesn't need an update in the future.

We should have some shared parsing code though instead of so many different EPs parsing for a '|' to find the key and value. It's a little ridiculous that DNNL, CUDA, TensorRT, QNN, SNPE, DML, ACL and VitisAI are all repeating the same basic logic. Maybe ParseSessionConfigs in test/perftest/command_args_parser.cc can be used. Move it into a shared helper and call to create unordered_map<string, string> for the key/value pairs. The EP specific code can validate values using that map.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can commit the suggested changes from lintrunner.

onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/ort_test_session.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/strings_helper.cc Outdated Show resolved Hide resolved
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can commit the suggested changes from lintrunner.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can commit the suggested changes from lintrunner.

objectivec/ort_coreml_execution_provider.mm Outdated Show resolved Hide resolved
objectivec/test/ort_session_test.mm Outdated Show resolved Hide resolved
objectivec/test/ort_session_test.mm Outdated Show resolved Hide resolved
Comment on lines 47 to 50
static const char* const kCoremlProviderOption_MLModelFormat = "MLModelFormat";
static const char* const kCoremlProviderOption_MLAllowStaticInputShapes = "MLAllowStaticInputShapes";
static const char* const kCoremlProviderOption_MLEnableOnSubgraphs = "MLEnableOnSubgraphs";
static const char* const kCoremlProviderOption_MLModelCacheDir = "MLModelCacheDir";
Copy link
Contributor

@skottmckay skottmckay Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need the 'ML' prefix on these values? It makes sense to me for MLComputeUnits as that maps to a CoreML enum, but I'm not sure that any of the others do.

We should also provide clear documentation on what is valid/expected for each value even if it's simply copied from the flags doco.

A user might discover this file first so would also be good to mention that these values are intended to be used with Ort.::SessionOptions::AppendExecutionProvider (C++ API)/SessionOptionsAppendExecutionProvider (C API). #Closed

objectivec/ort_coreml_execution_provider.mm Outdated Show resolved Hide resolved
* @param error Optional error information set if an error occurs.
* @return Whether the provider was enabled successfully.
*/
- (BOOL)appendCoreMLExecutionProviderWithOptions_v2:(NSDictionary*)provider_options
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A user of appendCoreMLExecutionProviderWithOptions can easily look at the documentation for ORTCoreMLExecutionProviderOptions to know what is available. How should they discover the provider options that can be used here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch. All avaiable key-valus are listed in the comments.

@@ -12,9 +12,14 @@ namespace coreml {
class Model;
}

struct CoreMLOptions {
uint32_t coreml_flags = 0;
std::string cache_path;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: can we keep changes to add supporting a cache path in a separate PR?

Also wondering if this is going to grow better if we keep it separate from coreml_flags. It's a little hard to see what is supported with the current setup. If we define the full set of options in this struct, and we populate those from either the flags, or the provider options, it's clear what the full set of options is.

I'd suggest making CoreMLOptions a class and make it responsible for validation. Can have a ctor for flags and one for provider options. That way all the validation is done in one place and it's clear which class is responsible for validation.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, it's good to seperate cache path in another PR.

If we make different flag has its own variable to mark it. How can we capatiable it with current coreml_flags?
Besides, we can easily pass coreml_flags(uint32_t) to object-c. can we pass a class from c++ to obect-c directly?

onnxruntime/test/perftest/command_args_parser.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/command_args_parser.cc Outdated Show resolved Hide resolved
onnxruntime/test/perftest/command_args_parser.cc Outdated Show resolved Hide resolved
Comment on lines 28 to 37
// Error: must use a '|' to separate the key and value for session configuration entries.
return false;
}

std::string key(token_sv.substr(0, pos));
std::string value(token_sv.substr(pos + 1));

auto it = session_configs.find(key);
if (it != session_configs.end()) {
// Error: specified duplicate session configuration entry: {key}
Copy link
Contributor

@skottmckay skottmckay Nov 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we throw from here with the specific error info instead of duplicating the throw with the 'use | to separate values' message in multiple places, which may not be the actual cause of the failure? #Closed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good. I add another available_keys for early check.

onnxruntime/test/providers/coreml/dynamic_input_test.cc Outdated Show resolved Hide resolved
wejoncy and others added 3 commits November 21, 2024 16:28
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can commit the suggested changes from lintrunner.

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can commit the suggested changes from lintrunner.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants