13
13
from coremltools .models .neural_network import NeuralNetworkBuilder #type: ignore
14
14
from coremltools .models import datatypes , MLModel #type: ignore
15
15
from coremltools .proto import FeatureTypes_pb2 as ft #type: ignore
16
+ from coremltools import _MINIMUM_CUSTOM_LAYER_SPEC_VERSION as IOS_11_2_SPEC_VERSION # iOS 11.2
17
+ from coremltools import _MINIMUM_CUSTOM_MODEL_SPEC_VERSION as IOS_12_SPEC_VERSION # iOS 12.0
18
+ from coremltools import _MINIMUM_NDARRAY_SPEC_VERSION as IOS_13_SPEC_VERSION # iOS 13.0
16
19
17
20
from typing import Tuple
18
21
34
37
35
38
DEBUG = False
36
39
40
+ class SupportedVersion ():
41
+ # Supported iOS Version
42
+ # New OS Version must be added at the end to maintain backward version index
43
+ supported_ios_version = ['11.2' , '12' , '13' ]
44
+ IOS_13_VERSION = supported_ios_version .index ('13' )
45
+ ND_ARRARY_SUPPORT = IOS_13_VERSION
46
+
47
+ @staticmethod
48
+ def ios_support_check (target_ios ):
49
+ return target_ios in SupportedVersion .supported_ios_version
50
+
51
+ @staticmethod
52
+ def is_nd_array_supported (target_ios ):
53
+ if not SupportedVersion .ios_support_check (target_ios ):
54
+ raise TypeError ('{} not supported. Please provide one of target iOS: {}' , target_ios , SupportedVersion .supported_ios_version )
55
+
56
+ target_ios_index = SupportedVersion .supported_ios_version .index (target_ios )
57
+ return SupportedVersion .ND_ARRARY_SUPPORT <= target_ios_index
58
+
59
+ @staticmethod
60
+ def get_supported_ios ():
61
+ return SupportedVersion .supported_ios_version
62
+
63
+ @staticmethod
64
+ def get_specification_version (target_ios ):
65
+ if not SupportedVersion .ios_support_check (target_ios ):
66
+ raise TypeError ('{} not supported. Please provide one of target iOS: {}' , target_ios , SupportedVersion .supported_ios_version )
67
+
68
+ if target_ios == '11.2' :
69
+ return IOS_11_2_SPEC_VERSION
70
+ elif target_ios == '12' :
71
+ return IOS_12_SPEC_VERSION
72
+ else :
73
+ return IOS_13_SPEC_VERSION
74
+
37
75
'''
38
76
inputs: list of tuples.
39
77
[Tuple]: [(name, type, shape)]
@@ -177,7 +215,7 @@ def _check_unsupported_ops(nodes, disable_coreml_rank5_mapping=False): # type: (
177
215
178
216
coreml_3_rerun_message = ''
179
217
if not disable_coreml_rank5_mapping :
180
- coreml_3_rerun_message = '\n Please try converting again with disable_coreml_rank5_mapping=True ' \
218
+ coreml_3_rerun_message = '\n Please try converting again with target_ios=13 ' \
181
219
' and coremltools 3.0 latest beta'
182
220
if len (unsupported_op_types ) > 0 :
183
221
raise NotImplementedError ("Unsupported ONNX ops of type: %s %s" % (
@@ -343,7 +381,7 @@ def convert(model, # type: Union[onnx.ModelProto, Text]
343
381
add_custom_layers = False , # type: bool
344
382
custom_conversion_functions = {}, #type: Dict[Text, Any]
345
383
onnx_coreml_input_shape_map = {}, # type: Dict[Text, List[int,...]]
346
- disable_coreml_rank5_mapping = False ):
384
+ target_ios = '12' ):
347
385
# type: (...) -> MLModel
348
386
"""
349
387
Convert ONNX model to CoreML.
@@ -384,13 +422,19 @@ def convert(model, # type: Union[onnx.ModelProto, Text]
384
422
how the shape of the input is mapped to CoreML. Convention used for CoreML shapes is
385
423
0: Sequence, 1: Batch, 2: channel, 3: height, 4: width.
386
424
For example, an input of rank 2 could be mapped as [3,4] (i.e. H,W) or [1,2] (i.e. B,C) etc.
387
- This is ignored if "disable_coreml_rank5_mapping" is set to True.
388
- disable_coreml_rank5_mapping: bool
389
- If True, then it disables the "RANK5_ARRAY_MAPPING" or enables the "EXACT_ARRAY_MAPPING"
390
- option in CoreML (https://github.com/apple/coremltools/blob/655b3be5cc0d42c3c4fa49f0f0e4a93a26b3e492/mlmodel/format/NeuralNetwork.proto#L67)
391
- Thus, no longer, onnx tensors are forced to map to rank 5 CoreML tensors.
392
- With this flag on, a rank r ONNX tensor, (1<=r<=5), will map to a rank r tensor in CoreML as well.
393
- This flag must be on to utilize any of the new layers added in CoreML 3 (i.e. specification version 4, iOS13)
425
+ This is ignored if "target_ios" is set to 13.
426
+ target_ios: str
427
+ Target Deployment iOS Version (default: '12')
428
+ Supported iOS version options: '11.2', '12', '13'
429
+ CoreML model produced by the converter will be compatible with the iOS version specified in this argument.
430
+ e.g. if target_ios = '12', the converter would only utilize CoreML features released till iOS12 (equivalently macOS 10.14, watchOS 5 etc).
431
+
432
+ iOS 11.2 (CoreML 0.8) does not support resize_bilinear, crop_resize layers
433
+ - (Supported features: https://github.com/apple/coremltools/releases/tag/v0.8)
434
+ iOS 12 (CoreML 2.0)
435
+ - (Supported features: https://github.com/apple/coremltools/releases/tag/v2.0)
436
+ iSO 13 (CoreML 3.0)
437
+ - (Supported features: https://github.com/apple/coremltools/releases/tag/3.0-beta6)
394
438
395
439
Returns
396
440
-------
@@ -405,13 +449,20 @@ def convert(model, # type: Union[onnx.ModelProto, Text]
405
449
"Model must be file path to .onnx file or onnx loaded model"
406
450
)
407
451
452
+ if not SupportedVersion .ios_support_check (target_ios ):
453
+ raise TypeError ('{} not supported. Please provide one of target iOS: {}' , target_ios , SupportedVersion .get_supported_ios ())
454
+
455
+
408
456
global USE_SHAPE_MAPPING
457
+ disable_coreml_rank5_mapping = False
458
+ if SupportedVersion .is_nd_array_supported (target_ios ):
459
+ disable_coreml_rank5_mapping = True
460
+
409
461
if disable_coreml_rank5_mapping :
410
462
USE_SHAPE_MAPPING = False
411
463
else :
412
464
USE_SHAPE_MAPPING = True
413
465
414
-
415
466
'''
416
467
First, apply a few optimizations to the ONNX graph,
417
468
in preparation for conversion to CoreML.
@@ -495,6 +546,9 @@ def __call__(self, graph):
495
546
496
547
builder = NeuralNetworkBuilder (input_features , output_features , mode = mode , disable_rank5_shape_mapping = disable_coreml_rank5_mapping )
497
548
549
+ # TODO: To be removed once, auto-downgrading of spec version is enabled
550
+ builder .spec .specificationVersion = SupportedVersion .get_specification_version (target_ios )
551
+
498
552
'''
499
553
Set CoreML input,output types (float, double, int) same as onnx types, if supported
500
554
'''
@@ -559,9 +613,7 @@ def __call__(self, graph):
559
613
ErrorHandling is a generic class, useful to store a variety of parameters during the conversion process
560
614
'''
561
615
err = ErrorHandling (add_custom_layers ,
562
- custom_conversion_functions ,
563
- disable_coreml_rank5_mapping = disable_coreml_rank5_mapping )
564
-
616
+ custom_conversion_functions )
565
617
566
618
for i , node in enumerate (graph .nodes ):
567
619
print ("%d/%d: Converting Node Type %s" % (i + 1 , len (graph .nodes ), node .op_type ))
@@ -658,6 +710,13 @@ def _add_informative_description(feature, raise_error=True):
658
710
if len (graph .optional_inputs ) > 0 or len (graph .optional_outputs ):
659
711
builder .add_optionals (graph .optional_inputs , graph .optional_outputs )
660
712
713
+ # Check for specification version and target ios compatibility
714
+ if target_ios == '11.2' and builder .spec .WhichOneof ('Type' ) == 'neuralNetwork' :
715
+ nn_spec = builder .spec .neuralNetwork
716
+ for layer in nn_spec .layers :
717
+ if layer .WhichOneof ('layer' ) == 'resizeBilinear' or layer .WhichOneof ('layer' ) == 'cropResize' :
718
+ raise TypeError ('{} not supported with target iOS 11.2 please provide higher target iOS' .format (layer .WhichOneof ('layer' )))
719
+
661
720
print ("Translation to CoreML spec completed. Now compiling the CoreML model." )
662
721
try :
663
722
if DEBUG :
0 commit comments