Coremltools: Get negative value through 'mb.floor'

Created on 20 Aug 2020  路  5Comments  路  Source: apple/coremltools

Hello! Thank you for updating coremltools!

馃悶Describe the bug

While converting my PyTorch model, I got Dimension mismatch error, and I found one parameter, which is then going to be output_size , somehow turn into negative value.
I'll show the exact point below. I tried logging as discussed in #818.
What is the problem?

=node=   %1497 = floor[](%1496)
<class 'coremltools.converters.mil.mil.var.Var'>
lnegth 1
input_value [128]
which_derived_from   %1496: (1,i8)*(Tensor) = const(val=[128], name="1496")

===Converting op 1497 : floor : shape = (1,) === 

=node=   %1498 = int[](%1497)
<class 'coremltools.converters.mil.mil.var.Var'>
lnegth 1
input_value [-128]
which_derived_from   %1497: (1,i8)*(Tensor) = floor(x=%1496, name="1497")

===Converting op 1498 : int : shape = (1,) === 

System environment (please complete the following information):

  • coremltools version == 4.0b3
  • torch == 1.5.0
  • torch vision == 0.6.0

Additional context

Thank you for your help in advance.

bug

Most helpful comment

@shiron8bit I am so sorry for the late reply.
I got those information by myinputs[i].val /myinputs[i].op respectively, where myinputs = _get_inputs(context, node).
(FYI, myinputs[i].val fails when myinputs[I] is NoneType object.)
You may know but there is a great discussion about logging at #818 .

All 5 comments

Just curious, does the bug go away if you change the data type from int8 to int32? I mean, the issue is with a
(1,i8)*(Tensor)
int8 tensor.

PS: Also note that PyTorch 1.6.0 doesn't like floor() on int8 or int32. Try

import torch
dummy_input = torch.tensor((126,127,-127,-128),dtype=torch.int8)
print ( torch.floor(dummy_input ))

which gives:
RuntimeError: floor_vml_cpu not implemented for 'Char'

or, RuntimeError: floor_vml_cpu not implemented for 'Int', with dtype=torch.int32

@leovinus2001 Thank you for your help!
You're right. Operating floor on int8 is strange. I should have noticed it.

As for my situation, the problem is found to be from the op to (coremltools/coremltools/converters/mil/frontend/torch/ops.py).
In my case, lin(inputs)==5 but the number deciding dtype is not from inputs[2] but inputs[1].
I suppose that because inputs[2] == False, dtype was set to 0, which means uint8, and this caused the problem.

So, I changed to op as below and it worked.

@register_torch_op
def to(context, node):
    # @non_blocking and @copy are unused
    inputs = _get_inputs(context, node)
    if len(inputs) == 6:
        _input = inputs[0]
        device = inputs[1]
        dtype = inputs[2].val
        # non_blocking = inputs[3]
        # copy = inputs[4]
        # memory_format = inputs[5] # usually None
    elif len(inputs) == 5:
        _input = inputs[0]
#============here=======================
        #dtype = inputs[2].val
        dtype = inputs[1].val  
#======================================
        # non_blocking = inputs[3]
        # copy = inputs[4]
    elif len(inputs) == 4:
        _input = inputs[0]
        dtype = inputs[1].val
        # non_blocking = inputs[2]
        # copy = inputs[3]
    elif len(inputs) == 3:
        # Since @non_blocking and @copy are unused, add back to context
        _input = inputs[0]
        # non_blocking = inputs[1]
        # copy = inputs[2]
        context.add(_input, torch_name=node.name)
        return
    else:
        raise ValueError(
            "Received invalid arguments for PyTorch conversion of op {}".format(node)
        )

    torch_dtype = NUM_TO_TORCH_DTYPE[dtype]
    if isinstance(_input, Var):
        _input = _input.val

    # numpy -> torch -> torch cast -> numpy
    # This path is needed to use the mapping of passed in dtypes to torch dtypes.
    casted_input = torch.tensor(_input).type(torch_dtype).numpy()
    const = mb.const(mode="immediate_value", val=casted_input, name=node.name)
    context.add(const)

Great to hear that you found a working solution. There were a few other reports of shape with negative dimensions, like #751 #739 where they see (1, 32, -128, -128), and we could wonder whether there is a coremltools root cause that could be fixed.

@mushipand Can i ask you how did you modify logging to output 'input_value' and 'which_derived_from'?

@shiron8bit I am so sorry for the late reply.
I got those information by myinputs[i].val /myinputs[i].op respectively, where myinputs = _get_inputs(context, node).
(FYI, myinputs[i].val fails when myinputs[I] is NoneType object.)
You may know but there is a great discussion about logging at #818 .

Was this page helpful?
0 / 5 - 0 ratings