FastAI Model to CoreML: RuntimeError: PyTorch convert function for op 'alias' not implemented

Hello - enjoying my time with FastAI, and working toward testing the FastAI image recognition model in iOS App. In order to efficiently run with ease in iOS, these models need to be converted to CoreML model. I have done this in the past with coremltools with Keras.

here is my code which produces the error

learn = torch.load("./models/fastai_learner.pt")
traced_land_model = torch.jit.trace(learn, x)
type(traced_land_model)
# torch.jit._trace.TopLevelTracedModule

import coremltools as ct
# Using image_input in the inputs parameter:
# Convert to Core ML using the Unified Conversion API.
model = ct.convert(
    traced_land_model,
    inputs=[ct.TensorType(shape=x.shape)]
 )
# here is stack trace
Converting Frontend ==> MIL Ops:   6%|â–Ś         | 14/246 [00:00<00:00, 2571.84 ops/s]
---------------------------------------------------------------------------
RuntimeError                              Traceback (most recent call last)
/tmp/ipykernel_65689/210732969.py in <module>
      6     #inputs=[ct.TensorType(shape=example_input.shape)]
      7     traced_land_model,
----> 8     inputs=[ct.TensorType(shape=x.shape)]
      9  )

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/_converters_entry.py in convert(model, source, inputs, outputs, classifier_config, minimum_deployment_target, convert_to, compute_precision, skip_model_load, compute_units, useCPUOnly, package_dir, debug)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/converter.py in mil_convert(model, convert_from, convert_to, compute_units, **kwargs)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/converter.py in _mil_convert(model, convert_from, convert_to, registry, modelClass, compute_units, **kwargs)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/converter.py in mil_convert_to_proto(model, convert_from, convert_to, converter_registry, **kwargs)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/converter.py in __call__(self, *args, **kwargs)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/load.py in load(model_spec, debug, **kwargs)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/load.py in _perform_torch_convert(converter, debug)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/load.py in _perform_torch_convert(converter, debug)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/converter.py in convert(self)

/anaconda/envs/fastai2/lib/python3.7/site-packages/coremltools/converters/mil/frontend/torch/ops.py in convert_nodes(context, graph)

RuntimeError: PyTorch convert function for op 'alias' not implemented.

In the coremltools docs, it should a workable way to convert, but doesn’t appear to be working with FastAI. PyTorch Conversion. Any insight appreciated.

Any chance you could show the full trace error it gives you?

@muellerzr - I just added the full trace to original post now. thank you

Doesn’t really help solve your problem, but my guess is the alias pytorch function needs to be lowered to torchscript for this to work. maybe open a pytorch bug. (I have the feeling apple would just punt it over to the pytorch guys)

I logged a bug like this a while back which feels pretty similar. when converting scripted model to coremltools, Unknown type bool encountered in graph lowering. This type is not supported in ONNX export. · Issue #1085 · apple/coremltools · GitHub

I encountered the same problem a few weeks ago. Turns out the problem was somehow triggered by the Flatten layer, which in my case was used after an AdaptiveConcatPool2d. Removing the TensorBase “cast” made it go away.

If this sounds familiar, read on for my solution.

Instead of modifying the fastai source, I patched my model replacing the layer with an alternative implementation.

First, I found where the Flatten layer was being used:

>>> model_to_export[0][-1]

Sequential(
  (0): AdaptiveConcatPool2d(
    (ap): AdaptiveAvgPool2d(output_size=1)
    (mp): AdaptiveMaxPool2d(output_size=1)
  )
  (1): Flatten(full=False)
  (2): BatchNorm1d(4096, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
... other unrelated layers
)

>>> model_to_export[0][-1][1]

Flatten(full=False)

Then I created a replacement Flatten. (I called it CopyFlatten because my initial intention was to copy the data, but the name doesn’t matter).

# This is a delightful way to create a subclass of `torch.nn.Module`
from fastai.layers import module

@module(full=False)
def CopyFlatten(self, x):
    "Flatten `x` to a single dimension, e.g. at end of a model. `full` for rank-1 tensor"
    return x.view(-1) if self.full else x.view(x.size(0), -1)

Then I replaced the layer inside the model:

model_to_export[0][-1][1] = CopyFlatten()

Please, let me know if this helps, and good luck!

1 Like

In my case the problem was also fastai’s Flatten, which appears when fastai does create_head.

My solution is to redefine create_head using torch’s native Flatten:

def create_head(nf, n_out, lin_ftrs=None, ps=0.5, pool=True, concat_pool=True, first_bn=True, bn_final=False,
                lin_first=False, y_range=None):
    "Model head that takes `nf` features, runs through `lin_ftrs`, and out `n_out` classes."
    print("Using torch.nn.Flatten")
    if pool and concat_pool: nf *= 2
    lin_ftrs = [nf, 512, n_out] if lin_ftrs is None else [nf] + lin_ftrs + [n_out]
    bns = [first_bn] + [True]*len(lin_ftrs[1:])
    ps = L(ps)
    if len(ps) == 1: ps = [ps[0]/2] * (len(lin_ftrs)-2) + ps
    actns = [nn.ReLU(inplace=True)] * (len(lin_ftrs)-2) + [None]
    layers = []
    if pool:
        pool = AdaptiveConcatPool2d() if concat_pool else nn.AdaptiveAvgPool2d(1)
        layers += [pool, torch.nn.Flatten()]
    if lin_first: layers.append(nn.Dropout(ps.pop(0)))
    for ni,no,bn,p,actn in zip(lin_ftrs[:-1], lin_ftrs[1:], bns, ps, actns):
        layers += LinBnDrop(ni, no, bn=bn, p=p, act=actn, lin_first=lin_first)
    if lin_first: layers.append(nn.Linear(lin_ftrs[-2], n_out))
    if bn_final: layers.append(nn.BatchNorm1d(lin_ftrs[-1], momentum=0.01))
    if y_range is not None: layers.append(SigmoidRange(*y_range))
    return nn.Sequential(*layers)

fastai.vision.learner.create_head = create_head