yolo26-face / scripts /coreml_patch.py
a-ml's picture
Add YOLO26 face-parsing models: PyTorch checkpoints, Core ML exports, training/export scripts, results and demo
e2f3b24 verified
Raw
History Blame Contribute Delete
1.88 kB
"""
Compatibility shim: coremltools 9.0 Torch frontend x numpy 2.x.
coremltools' `_cast` op handler folds a constant int/bool cast with
`mb.const(val=int(x.val))`. Under numpy >= 2.0, calling `int()`/`bool()` on a
length-1 (non 0-d) ndarray raises:
TypeError: only 0-dimensional arrays can be converted to Python scalars
YOLO26's attention block emits exactly such a cast, so conversion aborts at
`.../attn/...`. We re-register a `_cast` that coerces size-1 arrays via `.item()`
first. Behaviour is otherwise identical.
Import this module before calling `coremltools.convert(...)`.
"""
import numpy as np
from coremltools.converters.mil.frontend.torch import ops as _tops
from coremltools.converters.mil.frontend.torch.ops import _get_inputs
from coremltools.converters.mil.mil import Builder as mb
def _cast_numpy2_safe(context, node, dtype, dtype_name):
inputs = _get_inputs(context, node, expected=1)
x = inputs[0]
if not (len(x.shape) == 0 or np.all([d == 1 for d in x.shape])):
raise ValueError("input to cast must be either a scalar or a length 1 tensor")
if x.can_be_folded_to_const():
val = x.val
# numpy 2.x: int()/float()/bool() on a size-1, >0-d array raises. Coerce.
if hasattr(val, "item") and np.size(val) == 1:
val = val.item()
if not isinstance(x.val, dtype):
res = mb.const(val=dtype(val), name=node.name)
else:
res = x
elif len(x.shape) > 0:
x = mb.squeeze(x=x, name=node.name + "_item")
res = mb.cast(x=x, dtype=dtype_name, name=node.name)
else:
res = mb.cast(x=x, dtype=dtype_name, name=node.name)
context.add(res, node.name)
_applied = False
def apply():
global _applied
if not _applied:
_tops._cast = _cast_numpy2_safe
_applied = True
return _applied
# Apply on import.
apply()