Skip to content

Commit

Permalink
7.0b1 release (#1874)
Browse files Browse the repository at this point in the history
  • Loading branch information
TobyRoseman authored Jun 5, 2023
1 parent ef18cc0 commit b5ba7e1
Show file tree
Hide file tree
Showing 269 changed files with 31,412 additions and 4,057 deletions.
4 changes: 2 additions & 2 deletions BUILDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Follow these steps:
1. Fork and clone the GitHub [coremltools repository](https://github.com/apple/coremltools).

2. Run the [build.sh](scripts/build.sh) script to build `coremltools`.
* 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.
* 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.
* The script creates a new `build` folder with the coremltools distribution, and a `dist` folder with Python wheel files.

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

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.
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.

## Resources

Expand Down
13 changes: 13 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,19 @@ else()
message(STATUS "CoreML.framework and dependent frameworks not found. Skipping libcoremlpython build.")
endif()

# Build kmeans-1d
set(KMEANS_DIR "${PROJECT_SOURCE_DIR}/deps/kmeans1d")
execute_process(
COMMAND python3 setup.py build_ext --inplace
WORKING_DIRECTORY ${KMEANS_DIR}
)

# Copy kmeans-1d to Python deps folder
execute_process(
COMMAND cp -r kmeans1d ../../coremltools/_deps
WORKING_DIRECTORY ${KMEANS_DIR}
)

set(PYTHON_TAG "cp${PYTHON_VERSION_MAJOR}${PYTHON_VERSION_MINOR}")
if(APPLE)
execute_process(COMMAND uname -m OUTPUT_VARIABLE HARDWARE_NAME OUTPUT_STRIP_TRAILING_WHITESPACE)
Expand Down
2 changes: 1 addition & 1 deletion LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright (c) 2020, Apple Inc. All rights reserved.
Copyright © 2020-2023, Apple Inc. All rights reserved.

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

Expand Down
25 changes: 25 additions & 0 deletions NOTICE.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
Copyright © 2020-2023, Apple Inc. All rights reserved.

This project contains content adapted from kmeans1d (https://github.com/dstein64/kmeans1d), the license for which follows:

MIT License

Copyright (c) 2019 Daniel Steinberg

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
7 changes: 6 additions & 1 deletion coremltools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
# New versions for iOS 16.0
_SPECIFICATION_VERSION_IOS_16 = 7

# New versions for iOS 17.0
_SPECIFICATION_VERSION_IOS_17 = 8


class ComputeUnit(_Enum):
'''
The set of processing-unit configurations the model can use to make predictions.
Expand All @@ -76,6 +80,7 @@ class ComputeUnit(_Enum):
_SPECIFICATION_VERSION_IOS_14: "CoreML4",
_SPECIFICATION_VERSION_IOS_15: "CoreML5",
_SPECIFICATION_VERSION_IOS_16: "CoreML6",
_SPECIFICATION_VERSION_IOS_17: "CoreML7",
}

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


# expose sub packages as directories
from . import converters, models, proto
from . import converters, models, optimize, proto

# expose unified converter in coremltools package level
from .converters import ClassifierConfig
Expand Down
1 change: 1 addition & 0 deletions coremltools/_deps/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
kmeans1d/
15 changes: 15 additions & 0 deletions coremltools/_deps/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@

from coremltools import _logger as logger

_HAS_KMEANS1D = True
try:
from . import kmeans1d as _kmeans1d
except:
_kmeans1d = None
_HAS_KMEANS1D = False


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


_HAS_TORCH_VISION = True
try:
import torchvision
except:
_HAS_TORCH_VISION = False
MSG_TORCH_VISION_NOT_FOUND = "TorchVision not found."


# ---------------------------------------------------------------------------------------
try:
import scipy
Expand Down
104 changes: 84 additions & 20 deletions coremltools/converters/_converters_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import collections
import gc
import os
from typing import Optional, Text, Union
from typing import List, Optional, Text, Union

from coremltools import (
_LOWEST_ALLOWED_SPECIFICATION_VERSION_FOR_MILPROGRAM,
Expand All @@ -23,8 +23,11 @@
from coremltools.converters.mil.converter import mil_convert
from coremltools.converters.mil.input_types import (
ClassifierConfig,
EnumeratedShapes,
ImageType,
InputType,
RangeDim,
Shape,
TensorType,
)
from coremltools.converters.mil.mil import Program, types
Expand Down Expand Up @@ -395,7 +398,7 @@ def skip_real_div_ops(op):
pipeline = ct.PassPipeline()
pipeline.remove_passes({"common::fuse_conv_batchnorm"})
ct.convert(model, pass_pipeline=pipeline)
mlmodel = ct.convert(model, pass_pipeline=pipeline)
* To avoid folding too-large ``const`` ops that lead to a large model, set pass option
as shown in the following example:
Expand All @@ -404,7 +407,34 @@ def skip_real_div_ops(op):
pipeline = ct.PassPipeline()
pipeline.set_options("common::const_elimination", {"skip_const_by_size": "1e6"})
ct.convert(model, pass_pipeline=pipeline)
mlmodel = ct.convert(model, pass_pipeline=pipeline)
We also provide a set of predefined pass pipelines that you can directly call.
* To avoid running all graph pass, you can use:
.. sourcecode:: python
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.EMPTY)
* To only run the cleanup graph passes, like constant_elimination, dead_code_elimination, etc.
You can use:
.. sourcecode:: python
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.CLEANUP)
* To convert a source model with sparse weights to a sparse format Core ML model, you can use:
.. sourcecode:: python
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.DEFAULT_PRUNING)
* To convert a source model with palettized weights to a compressed format Core ML model, you can use:
.. sourcecode:: python
mlmodel = ct.convert(model, pass_pipeline=ct.PassPipeline.DEFAULT_PALETTIZATION)
Returns
-------
Expand Down Expand Up @@ -463,9 +493,17 @@ def skip_real_div_ops(op):
outputs_as_tensor_or_image_types,
outputs)
exact_target = _determine_target(convert_to, minimum_deployment_target)
_validate_conversion_arguments(model, exact_source, inputs, outputs_as_tensor_or_image_types,
classifier_config, compute_precision,
exact_target, minimum_deployment_target)
_validate_conversion_arguments(
model,
exact_source,
exact_target,
inputs,
outputs_as_tensor_or_image_types,
classifier_config,
compute_precision,
exact_target,
minimum_deployment_target,
)

if pass_pipeline is None:
pass_pipeline = PassPipeline()
Expand Down Expand Up @@ -504,6 +542,12 @@ def skip_real_div_ops(op):
main_pipeline=pass_pipeline,
)

if exact_target == "mlprogram" and mlmodel._input_has_infinite_upper_bound():
raise ValueError(
"For mlprogram, inputs with infinite upper_bound is not allowed. Please set upper_bound"
' to a positive value in "RangeDim()" for the "inputs" param in ct.convert().'
)

if exact_target == 'milinternal':
return mlmodel # Returns the MIL program

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


def _set_default_specification_version(target):
def _set_default_specification_version(target) -> Optional[AvailableTarget]:
if target == "neuralnetwork":
return _LOWEST_ALLOWED_SPECIFICATION_VERSION_FOR_NEURALNETWORK
elif target == "mlprogram":
Expand Down Expand Up @@ -625,18 +669,20 @@ def _validate_outputs_argument(outputs):
return output_names, outputs


def _validate_conversion_arguments(model,
exact_source,
inputs,
outputs,
classifier_config,
compute_precision,
convert_to,
minimum_deployment_target,
):
def _validate_conversion_arguments(
model,
exact_source,
exact_target,
inputs,
outputs,
classifier_config,
compute_precision,
convert_to,
minimum_deployment_target,
):
"""
Validate and process model, inputs, classifier_config based on
`exact_source` (which cannot be `auto`)
`exact_source` (which cannot be `auto`) and `exact_target`.
"""

def raise_if_duplicated(input_list):
Expand Down Expand Up @@ -672,10 +718,10 @@ def _flatten_list(_inputs):

# get flattened inputs
flat_inputs = _flatten_list(inputs)
for t in flat_inputs:
if not isinstance(t, InputType):
for flat_input in flat_inputs:
if not isinstance(flat_input, InputType):
raise ValueError("inputs must be a list of type ct.TensorType or ct.ImageType")
if t.dtype == types.fp16:
if flat_input.dtype == types.fp16:
if not (
minimum_deployment_target is not None
and minimum_deployment_target >= AvailableTarget.iOS16
Expand All @@ -685,6 +731,24 @@ def _flatten_list(_inputs):
"target >= iOS16/macOS13/watchOS9/tvOS16"
)

if exact_target == "mlprogram":
err_msg_infinite_bound = (
"For mlprogram, inputs with infinite upper_bound is not allowed. Please set upper_bound"
' to a positive value in "RangeDim()" for the "inputs" param in ct.convert().'
)
if inputs is not None:
for flat_input in _flatten_list(inputs):
tensor_shapes: List[Optional[Shape]] = (
flat_input.shape.shapes
if isinstance(flat_input.shape, EnumeratedShapes)
else [flat_input.shape]
)
for tensor_shape in tensor_shapes:
if tensor_shape is not None:
for shape in tensor_shape.shape:
if isinstance(shape, RangeDim) and shape.upper_bound < 0:
raise ValueError(err_msg_infinite_bound)

if outputs is not None:
for t in outputs:
if t.dtype == types.fp16:
Expand Down
17 changes: 12 additions & 5 deletions coremltools/converters/mil/_deployment_compatibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@

from enum import IntEnum

from coremltools import (_SPECIFICATION_VERSION_IOS_13,
_SPECIFICATION_VERSION_IOS_14,
_SPECIFICATION_VERSION_IOS_15,
_SPECIFICATION_VERSION_IOS_16)
from coremltools import (
_SPECIFICATION_VERSION_IOS_13,
_SPECIFICATION_VERSION_IOS_14,
_SPECIFICATION_VERSION_IOS_15,
_SPECIFICATION_VERSION_IOS_16,
_SPECIFICATION_VERSION_IOS_17,
)


class AvailableTarget(IntEnum):
Expand All @@ -17,6 +20,7 @@ class AvailableTarget(IntEnum):
iOS14 = _SPECIFICATION_VERSION_IOS_14
iOS15 = _SPECIFICATION_VERSION_IOS_15
iOS16 = _SPECIFICATION_VERSION_IOS_16
iOS17 = _SPECIFICATION_VERSION_IOS_17

# macOS versions (aliases of iOS versions)
macOS15 = _SPECIFICATION_VERSION_IOS_13
Expand All @@ -26,19 +30,22 @@ class AvailableTarget(IntEnum):
macOS11 = _SPECIFICATION_VERSION_IOS_14
macOS12 = _SPECIFICATION_VERSION_IOS_15
macOS13 = _SPECIFICATION_VERSION_IOS_16
macOS14 = _SPECIFICATION_VERSION_IOS_17

# watchOS versions (aliases of iOS versions)
watchOS6 = _SPECIFICATION_VERSION_IOS_13
watchOS7 = _SPECIFICATION_VERSION_IOS_14
watchOS8 = _SPECIFICATION_VERSION_IOS_15
watchOS9 = _SPECIFICATION_VERSION_IOS_16
watchOS10 = _SPECIFICATION_VERSION_IOS_17

# tvOS versions (aliases of iOS versions)
tvOS13 = _SPECIFICATION_VERSION_IOS_13
tvOS14 = _SPECIFICATION_VERSION_IOS_14
tvOS15 = _SPECIFICATION_VERSION_IOS_15
tvOS16 = _SPECIFICATION_VERSION_IOS_16

tvOS17 = _SPECIFICATION_VERSION_IOS_17

# customized __str__
def __str__(self):
original_str = super().__str__()
Expand Down
Loading

0 comments on commit b5ba7e1

Please sign in to comment.