-
Notifications
You must be signed in to change notification settings - Fork 689
[Executorch][Recipes][Coreml] Add coreml backend recipes #13121
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
Merged
abhinaykukkadapu
merged 1 commit into
pytorch:main
from
abhinaykukkadapu:coreml_backend_recipes
Aug 8, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
# Copyright © 2025 Apple Inc. All rights reserved. | ||
# | ||
# Please refer to the license found in the LICENSE file in the root directory of the source tree. | ||
|
||
|
||
from executorch.export import recipe_registry | ||
|
||
from .coreml_recipe_provider import CoreMLRecipeProvider | ||
from .coreml_recipe_types import CoreMLRecipeType | ||
|
||
# Auto-register CoreML backend recipe provider | ||
recipe_registry.register_backend_recipe_provider(CoreMLRecipeProvider()) | ||
|
||
__all__ = [ | ||
"CoreMLRecipeProvider", | ||
"CoreMLRecipeType", | ||
] |
132 changes: 132 additions & 0 deletions
132
backends/apple/coreml/recipes/coreml_recipe_provider.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
# Copyright © 2025 Apple Inc. All rights reserved. | ||
# | ||
# Please refer to the license found in the LICENSE file in the root directory of the source tree. | ||
|
||
|
||
from typing import Any, Optional, Sequence | ||
|
||
import coremltools as ct | ||
|
||
from executorch.backends.apple.coreml.compiler import CoreMLBackend | ||
from executorch.backends.apple.coreml.partition.coreml_partitioner import ( | ||
CoreMLPartitioner, | ||
) | ||
from executorch.backends.apple.coreml.recipes.coreml_recipe_types import ( | ||
COREML_BACKEND, | ||
CoreMLRecipeType, | ||
) | ||
|
||
from executorch.exir import EdgeCompileConfig | ||
from executorch.export import ( | ||
BackendRecipeProvider, | ||
ExportRecipe, | ||
LoweringRecipe, | ||
RecipeType, | ||
) | ||
|
||
|
||
class CoreMLRecipeProvider(BackendRecipeProvider): | ||
@property | ||
def backend_name(self) -> str: | ||
return COREML_BACKEND | ||
|
||
def get_supported_recipes(self) -> Sequence[RecipeType]: | ||
return list(CoreMLRecipeType) | ||
|
||
def create_recipe( | ||
self, recipe_type: RecipeType, **kwargs: Any | ||
) -> Optional[ExportRecipe]: | ||
"""Create CoreML recipe with precision and compute unit combinations""" | ||
|
||
if recipe_type not in self.get_supported_recipes(): | ||
return None | ||
|
||
if ct is None: | ||
raise ImportError( | ||
"coremltools is required for CoreML recipes. " | ||
"Install it with: pip install coremltools" | ||
) | ||
|
||
# Validate kwargs | ||
self._validate_recipe_kwargs(recipe_type, **kwargs) | ||
|
||
# Parse recipe type to get precision and compute unit | ||
precision = None | ||
if recipe_type == CoreMLRecipeType.FP32: | ||
precision = ct.precision.FLOAT32 | ||
elif recipe_type == CoreMLRecipeType.FP16: | ||
precision = ct.precision.FLOAT16 | ||
|
||
if precision is None: | ||
raise ValueError(f"Unknown precision for recipe: {recipe_type.value}") | ||
|
||
return self._build_recipe(recipe_type, precision, **kwargs) | ||
|
||
def _validate_recipe_kwargs(self, recipe_type: RecipeType, **kwargs: Any) -> None: | ||
if not kwargs: | ||
return | ||
expected_keys = {"minimum_deployment_target", "compute_unit"} | ||
unexpected = set(kwargs.keys()) - expected_keys | ||
if unexpected: | ||
raise ValueError( | ||
f"CoreML Recipes only accept 'minimum_deployment_target' or 'compute_unit' as parameter. " | ||
f"Unexpected parameters: {list(unexpected)}" | ||
) | ||
if "minimum_deployment_target" in kwargs: | ||
minimum_deployment_target = kwargs["minimum_deployment_target"] | ||
if not isinstance(minimum_deployment_target, ct.target): | ||
raise ValueError( | ||
f"Parameter 'minimum_deployment_target' must be an enum of type ct.target, got {type(minimum_deployment_target)}" | ||
) | ||
if "compute_unit" in kwargs: | ||
compute_unit = kwargs["compute_unit"] | ||
if not isinstance(compute_unit, ct.ComputeUnit): | ||
raise ValueError( | ||
f"Parameter 'compute_unit' must be an enum of type ct.ComputeUnit, got {type(compute_unit)}" | ||
) | ||
|
||
def _build_recipe( | ||
self, | ||
recipe_type: RecipeType, | ||
precision: ct.precision, | ||
**kwargs: Any, | ||
) -> ExportRecipe: | ||
lowering_recipe = self._get_coreml_lowering_recipe( | ||
compute_precision=precision, | ||
**kwargs, | ||
) | ||
|
||
return ExportRecipe( | ||
name=recipe_type.value, | ||
quantization_recipe=None, # TODO - add quantization recipe | ||
lowering_recipe=lowering_recipe, | ||
) | ||
|
||
def _get_coreml_lowering_recipe( | ||
self, | ||
compute_precision: ct.precision, | ||
**kwargs: Any, | ||
) -> LoweringRecipe: | ||
compile_specs = CoreMLBackend.generate_compile_specs( | ||
compute_precision=compute_precision, | ||
**kwargs, | ||
) | ||
|
||
minimum_deployment_target = kwargs.get("minimum_deployment_target", None) | ||
take_over_mutable_buffer = True | ||
if minimum_deployment_target and minimum_deployment_target < ct.target.iOS18: | ||
take_over_mutable_buffer = False | ||
|
||
partitioner = CoreMLPartitioner( | ||
compile_specs=compile_specs, | ||
take_over_mutable_buffer=take_over_mutable_buffer, | ||
) | ||
|
||
edge_compile_config = EdgeCompileConfig( | ||
_check_ir_validity=False, | ||
_skip_dim_order=False, | ||
) | ||
|
||
return LoweringRecipe( | ||
partitioners=[partitioner], edge_compile_config=edge_compile_config | ||
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Copyright © 2025 Apple Inc. All rights reserved. | ||
# | ||
# Please refer to the license found in the LICENSE file in the root directory of the source tree. | ||
|
||
|
||
from executorch.export import RecipeType | ||
|
||
|
||
COREML_BACKEND: str = "coreml" | ||
|
||
|
||
class CoreMLRecipeType(RecipeType): | ||
abhinaykukkadapu marked this conversation as resolved.
Show resolved
Hide resolved
|
||
"""CoreML-specific generic recipe types""" | ||
|
||
# FP32 generic recipe, defaults to values published by the CoreML backend and partitioner | ||
# Precision = FP32, Default compute_unit = All (can be overriden by kwargs) | ||
FP32 = "coreml_fp32" | ||
|
||
# FP16 generic recipe, defaults to values published by the CoreML backend and partitioner | ||
# Precision = FP32, Default compute_unit = All (can be overriden by kwargs) | ||
FP16 = "coreml_fp16" | ||
|
||
@classmethod | ||
def get_backend_name(cls) -> str: | ||
return COREML_BACKEND |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI: I have a PR updating CoreML docs that you might check out for quantization and available partitioner options: #13120
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@metascroy it might make sense for you to follow up on the recipes for quant
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, @abhinaykukkadapu are the quant recipes coming in a future PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@metascroy If you want to follow up, i can leave it upto you as you have more context on quantization, or i can take it up if you don't have bandwidth.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You can add the quantization recipe, I'm happy to review the quantize_ and PT2E recipes you add for CoreML
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@metascroy sure will add in a follow up diff, can we go ahead with these changes?