File size: 1,879 Bytes
e2f3b24
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
"""
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()