Skip to content

Commit b5ba7e1

Browse files
authored
7.0b1 release (#1874)
1 parent ef18cc0 commit b5ba7e1

File tree

269 files changed

+31412
-4057
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

269 files changed

+31412
-4057
lines changed

BUILDING.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Follow these steps:
1919
1. Fork and clone the GitHub [coremltools repository](https://github.com/apple/coremltools).
2020

2121
2. Run the [build.sh](scripts/build.sh) script to build `coremltools`.
22-
* By default this script uses Python 3.7, but you can include `--python=3.8` (or `3.9`, `3.10`) as a argument to change the Python version.
22+
* By default this script uses Python 3.7, but you can include `--python=3.8` (or `3.9`, `3.10`, `3.11`) as a argument to change the Python version.
2323
* The script creates a new `build` folder with the coremltools distribution, and a `dist` folder with Python wheel files.
2424

2525
3. Run the [test.sh](scripts/test.sh) script to test the build.
@@ -45,7 +45,7 @@ The following build targets help you configure the development environment. If y
4545
* `test_slow` | Run all non-fast tests.
4646
* `wheel` | Build wheels in release mode.
4747

48-
The script uses Python 3.7, but you can include `--python=3.8` (or `3.9`, `3.10`) as a argument to change the Python version.
48+
The script uses Python 3.7, but you can include `--python=3.8` (or `3.9`, `3.10`, `3.11`) as a argument to change the Python version.
4949

5050
## Resources
5151

CMakeLists.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,19 @@ else()
191191
message(STATUS "CoreML.framework and dependent frameworks not found. Skipping libcoremlpython build.")
192192
endif()
193193

194+
# Build kmeans-1d
195+
set(KMEANS_DIR "${PROJECT_SOURCE_DIR}/deps/kmeans1d")
196+
execute_process(
197+
COMMAND python3 setup.py build_ext --inplace
198+
WORKING_DIRECTORY ${KMEANS_DIR}
199+
)
200+
201+
# Copy kmeans-1d to Python deps folder
202+
execute_process(
203+
COMMAND cp -r kmeans1d ../../coremltools/_deps
204+
WORKING_DIRECTORY ${KMEANS_DIR}
205+
)
206+
194207
set(PYTHON_TAG "cp${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}")
195208
if(APPLE)
196209
execute_process(COMMAND uname -m OUTPUT_VARIABLE HARDWARE_NAME OUTPUT_STRIP_TRAILING_WHITESPACE)

LICENSE.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2020, Apple Inc. All rights reserved.
1+
Copyright © 2020-2023, Apple Inc. All rights reserved.
22

33
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
44

NOTICE.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
Copyright © 2020-2023, Apple Inc. All rights reserved.
2+
3+
This project contains content adapted from kmeans1d (https://github.com/dstein64/kmeans1d), the license for which follows:
4+
5+
MIT License
6+
7+
Copyright (c) 2019 Daniel Steinberg
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in all
17+
copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25+
SOFTWARE.

coremltools/__init__.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@
6060
# New versions for iOS 16.0
6161
_SPECIFICATION_VERSION_IOS_16 = 7
6262

63+
# New versions for iOS 17.0
64+
_SPECIFICATION_VERSION_IOS_17 = 8
65+
66+
6367
class ComputeUnit(_Enum):
6468
'''
6569
The set of processing-unit configurations the model can use to make predictions.
@@ -76,6 +80,7 @@ class ComputeUnit(_Enum):
7680
_SPECIFICATION_VERSION_IOS_14: "CoreML4",
7781
_SPECIFICATION_VERSION_IOS_15: "CoreML5",
7882
_SPECIFICATION_VERSION_IOS_16: "CoreML6",
83+
_SPECIFICATION_VERSION_IOS_17: "CoreML7",
7984
}
8085

8186
# Default specification version for each backend
@@ -84,7 +89,7 @@ class ComputeUnit(_Enum):
8489

8590

8691
# expose sub packages as directories
87-
from . import converters, models, proto
92+
from . import converters, models, optimize, proto
8893

8994
# expose unified converter in coremltools package level
9095
from .converters import ClassifierConfig

coremltools/_deps/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
kmeans1d/

coremltools/_deps/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,13 @@
1616

1717
from coremltools import _logger as logger
1818

19+
_HAS_KMEANS1D = True
20+
try:
21+
from . import kmeans1d as _kmeans1d
22+
except:
23+
_kmeans1d = None
24+
_HAS_KMEANS1D = False
25+
1926

2027
def _get_version(version):
2128
# matching 1.6.1, and 1.6.1rc, 1.6.1.dev
@@ -156,6 +163,14 @@ def __get_sklearn_version(version):
156163
MSG_TORCH_NOT_FOUND = "PyTorch not found."
157164

158165

166+
_HAS_TORCH_VISION = True
167+
try:
168+
import torchvision
169+
except:
170+
_HAS_TORCH_VISION = False
171+
MSG_TORCH_VISION_NOT_FOUND = "TorchVision not found."
172+
173+
159174
# ---------------------------------------------------------------------------------------
160175
try:
161176
import scipy

coremltools/converters/_converters_entry.py

Lines changed: 84 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import collections
77
import gc
88
import os
9-
from typing import Optional, Text, Union
9+
from typing import List, Optional, Text, Union
1010

1111
from coremltools import (
1212
_LOWEST_ALLOWED_SPECIFICATION_VERSION_FOR_MILPROGRAM,
@@ -23,8 +23,11 @@
2323
from coremltools.converters.mil.converter import mil_convert
2424
from coremltools.converters.mil.input_types import (
2525
ClassifierConfig,
26+
EnumeratedShapes,
2627
ImageType,
2728
InputType,
29+
RangeDim,
30+
Shape,
2831
TensorType,
2932
)
3033
from coremltools.converters.mil.mil import Program, types
@@ -395,7 +398,7 @@ def skip_real_div_ops(op):
395398
396399
pipeline = ct.PassPipeline()
397400
pipeline.remove_passes({"common::fuse_conv_batchnorm"})
398-
ct.convert(model, pass_pipeline=pipeline)
401+
mlmodel = ct.convert(model, pass_pipeline=pipeline)
399402
400403
* To avoid folding too-large ``const`` ops that lead to a large model, set pass option
401404
as shown in the following example:
@@ -404,7 +407,34 @@ def skip_real_div_ops(op):
404407
405408
pipeline = ct.PassPipeline()
406409
pipeline.set_options("common::const_elimination", {"skip_const_by_size": "1e6"})
407-
ct.convert(model, pass_pipeline=pipeline)
410+
mlmodel = ct.convert(model, pass_pipeline=pipeline)
411+
412+
We also provide a set of predefined pass pipelines that you can directly call.
413+
414+
* To avoid running all graph pass, you can use:
415+
416+
.. sourcecode:: python
417+
418+
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.EMPTY)
419+
420+
* To only run the cleanup graph passes, like constant_elimination, dead_code_elimination, etc.
421+
You can use:
422+
423+
.. sourcecode:: python
424+
425+
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.CLEANUP)
426+
427+
* To convert a source model with sparse weights to a sparse format Core ML model, you can use:
428+
429+
.. sourcecode:: python
430+
431+
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.DEFAULT_PRUNING)
432+
433+
* To convert a source model with palettized weights to a compressed format Core ML model, you can use:
434+
435+
.. sourcecode:: python
436+
437+
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.DEFAULT_PALETTIZATION)
408438
409439
Returns
410440
-------
@@ -463,9 +493,17 @@ def skip_real_div_ops(op):
463493
outputs_as_tensor_or_image_types,
464494
outputs)
465495
exact_target = _determine_target(convert_to, minimum_deployment_target)
466-
_validate_conversion_arguments(model, exact_source, inputs, outputs_as_tensor_or_image_types,
467-
classifier_config, compute_precision,
468-
exact_target, minimum_deployment_target)
496+
_validate_conversion_arguments(
497+
model,
498+
exact_source,
499+
exact_target,
500+
inputs,
501+
outputs_as_tensor_or_image_types,
502+
classifier_config,
503+
compute_precision,
504+
exact_target,
505+
minimum_deployment_target,
506+
)
469507

470508
if pass_pipeline is None:
471509
pass_pipeline = PassPipeline()
@@ -504,6 +542,12 @@ def skip_real_div_ops(op):
504542
main_pipeline=pass_pipeline,
505543
)
506544

545+
if exact_target == "mlprogram" and mlmodel._input_has_infinite_upper_bound():
546+
raise ValueError(
547+
"For mlprogram, inputs with infinite upper_bound is not allowed. Please set upper_bound"
548+
' to a positive value in "RangeDim()" for the "inputs" param in ct.convert().'
549+
)
550+
507551
if exact_target == 'milinternal':
508552
return mlmodel # Returns the MIL program
509553

@@ -539,7 +583,7 @@ def _need_fp16_cast_pass(
539583
raise ValueError(f"Invalid value of the argument 'compute_precision': {compute_precision}")
540584

541585

542-
def _set_default_specification_version(target):
586+
def _set_default_specification_version(target) -> Optional[AvailableTarget]:
543587
if target == "neuralnetwork":
544588
return _LOWEST_ALLOWED_SPECIFICATION_VERSION_FOR_NEURALNETWORK
545589
elif target == "mlprogram":
@@ -625,18 +669,20 @@ def _validate_outputs_argument(outputs):
625669
return output_names, outputs
626670

627671

628-
def _validate_conversion_arguments(model,
629-
exact_source,
630-
inputs,
631-
outputs,
632-
classifier_config,
633-
compute_precision,
634-
convert_to,
635-
minimum_deployment_target,
636-
):
672+
def _validate_conversion_arguments(
673+
model,
674+
exact_source,
675+
exact_target,
676+
inputs,
677+
outputs,
678+
classifier_config,
679+
compute_precision,
680+
convert_to,
681+
minimum_deployment_target,
682+
):
637683
"""
638684
Validate and process model, inputs, classifier_config based on
639-
`exact_source` (which cannot be `auto`)
685+
`exact_source` (which cannot be `auto`) and `exact_target`.
640686
"""
641687

642688
def raise_if_duplicated(input_list):
@@ -672,10 +718,10 @@ def _flatten_list(_inputs):
672718

673719
# get flattened inputs
674720
flat_inputs = _flatten_list(inputs)
675-
for t in flat_inputs:
676-
if not isinstance(t, InputType):
721+
for flat_input in flat_inputs:
722+
if not isinstance(flat_input, InputType):
677723
raise ValueError("inputs must be a list of type ct.TensorType or ct.ImageType")
678-
if t.dtype == types.fp16:
724+
if flat_input.dtype == types.fp16:
679725
if not (
680726
minimum_deployment_target is not None
681727
and minimum_deployment_target >= AvailableTarget.iOS16
@@ -685,6 +731,24 @@ def _flatten_list(_inputs):
685731
"target >= iOS16/macOS13/watchOS9/tvOS16"
686732
)
687733

734+
if exact_target == "mlprogram":
735+
err_msg_infinite_bound = (
736+
"For mlprogram, inputs with infinite upper_bound is not allowed. Please set upper_bound"
737+
' to a positive value in "RangeDim()" for the "inputs" param in ct.convert().'
738+
)
739+
if inputs is not None:
740+
for flat_input in _flatten_list(inputs):
741+
tensor_shapes: List[Optional[Shape]] = (
742+
flat_input.shape.shapes
743+
if isinstance(flat_input.shape, EnumeratedShapes)
744+
else [flat_input.shape]
745+
)
746+
for tensor_shape in tensor_shapes:
747+
if tensor_shape is not None:
748+
for shape in tensor_shape.shape:
749+
if isinstance(shape, RangeDim) and shape.upper_bound < 0:
750+
raise ValueError(err_msg_infinite_bound)
751+
688752
if outputs is not None:
689753
for t in outputs:
690754
if t.dtype == types.fp16:

coremltools/converters/mil/_deployment_compatibility.py

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,13 @@
55

66
from enum import IntEnum
77

8-
from coremltools import (_SPECIFICATION_VERSION_IOS_13,
9-
_SPECIFICATION_VERSION_IOS_14,
10-
_SPECIFICATION_VERSION_IOS_15,
11-
_SPECIFICATION_VERSION_IOS_16)
8+
from coremltools import (
9+
_SPECIFICATION_VERSION_IOS_13,
10+
_SPECIFICATION_VERSION_IOS_14,
11+
_SPECIFICATION_VERSION_IOS_15,
12+
_SPECIFICATION_VERSION_IOS_16,
13+
_SPECIFICATION_VERSION_IOS_17,
14+
)
1215

1316

1417
class AvailableTarget(IntEnum):
@@ -17,6 +20,7 @@ class AvailableTarget(IntEnum):
1720
iOS14 = _SPECIFICATION_VERSION_IOS_14
1821
iOS15 = _SPECIFICATION_VERSION_IOS_15
1922
iOS16 = _SPECIFICATION_VERSION_IOS_16
23+
iOS17 = _SPECIFICATION_VERSION_IOS_17
2024

2125
# macOS versions (aliases of iOS versions)
2226
macOS15 = _SPECIFICATION_VERSION_IOS_13
@@ -26,19 +30,22 @@ class AvailableTarget(IntEnum):
2630
macOS11 = _SPECIFICATION_VERSION_IOS_14
2731
macOS12 = _SPECIFICATION_VERSION_IOS_15
2832
macOS13 = _SPECIFICATION_VERSION_IOS_16
33+
macOS14 = _SPECIFICATION_VERSION_IOS_17
2934

3035
# watchOS versions (aliases of iOS versions)
3136
watchOS6 = _SPECIFICATION_VERSION_IOS_13
3237
watchOS7 = _SPECIFICATION_VERSION_IOS_14
3338
watchOS8 = _SPECIFICATION_VERSION_IOS_15
3439
watchOS9 = _SPECIFICATION_VERSION_IOS_16
40+
watchOS10 = _SPECIFICATION_VERSION_IOS_17
3541

3642
# tvOS versions (aliases of iOS versions)
3743
tvOS13 = _SPECIFICATION_VERSION_IOS_13
3844
tvOS14 = _SPECIFICATION_VERSION_IOS_14
3945
tvOS15 = _SPECIFICATION_VERSION_IOS_15
4046
tvOS16 = _SPECIFICATION_VERSION_IOS_16
41-
47+
tvOS17 = _SPECIFICATION_VERSION_IOS_17
48+
4249
# customized __str__
4350
def __str__(self):
4451
original_str = super().__str__()

0 commit comments

Comments
 (0)