ValueError: Ops['identity_0', 'identity_0', 'identity_0', 'identity_0'] not found in block block0
In my Pytorch 1.9.1 test model on Python 3.8 with CoreMLTools 5.2.0 I try to convert a simple traced model that returns a tuple of tensors, but run into a ValueError of missing ops. Can someone please give me a hint, what's missing?
import torch
from torch import nn, Tensor
from typing import Optional, List, Any, Tuple
import coremltools as ct
class MyTupleModule9(nn.Module):
def __init__(self):
super().__init__()
def forward(self, x)->Tuple[Tensor, Tensor, Tensor, Tensor, Tensor]:
d: Tensor = torch.zeros(2, dtype=torch.float32)
result: Tuple[Tensor, Tensor, Tensor, Tensor, Tensor] = (d,d,d,d,d)
return result
if __name__ == '__main__':
t1 = MyTupleModule9()
x = torch.rand(2,2,1,1)
t = torch.jit.trace(t1, example_inputs=x)
result = t(x)
model = ct.convert(t, inputs=[ct.TensorType(shape=x.shape)], convert_to='mlprogram')
# ValueError: Ops['identity_0', 'identity_0', 'identity_0', 'identity_0'] not found in block block0
sys.exit(0)
Thanks for the minimal example. I can reproduce this issue. This looks an issue with an optimization pass to reduce the number of transpose operations.
Here is an even simpler reproduction code:
import torch
from torch import nn, Tensor
import coremltools as ct
class Net(nn.Module):
def forward(self, x):
d = torch.zeros(2, dtype=torch.float32)
return (d, d)
t1 = Net()
x = torch.rand(2,2,1,1)
t = torch.jit.trace(t1, example_inputs=x)
model = ct.convert(t, inputs=[ct.TensorType(shape=x.shape)], convert_to='mlprogram')
Here is the stacktrace:
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
~/Documents/coremltools/test.py in <module>
11 x = torch.rand(2,2,1,1)
12 t = torch.jit.trace(t1, example_inputs=x)
---> 13 model = ct.convert(t, inputs=[ct.TensorType(shape=x.shape)], convert_to='mlprogram')
~/Documents/coremltools/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)
361 compute_units=compute_units,
362 package_dir=package_dir,
--> 363 debug=debug,
364 )
365
~/Documents/coremltools/coremltools/converters/mil/converter.py in mil_convert(model, convert_from, convert_to, compute_units, **kwargs)
181 See `coremltools.converters.convert`
182 """
--> 183 return _mil_convert(model, convert_from, convert_to, ConverterRegistry, MLModel, compute_units, **kwargs)
184
185
~/Documents/coremltools/coremltools/converters/mil/converter.py in _mil_convert(model, convert_from, convert_to, registry, modelClass, compute_units, **kwargs)
213 convert_to,
214 registry,
--> 215 **kwargs
216 )
217
~/Documents/coremltools/coremltools/converters/mil/converter.py in mil_convert_to_proto(model, convert_from, convert_to, converter_registry, **kwargs)
279 passes = [p for p in kwargs.get("transforms", list()) if not isinstance(p, AbstractQuantizationPass)]
280
--> 281 apply_common_pass_pipeline(prog, passes)
282
283 if convert_to == 'milinternal':
~/Documents/coremltools/coremltools/converters/mil/mil/passes/apply_common_pass_pipeline.py in apply_common_pass_pipeline(prog, passes)
77 ]
78
---> 79 _apply(common_passes, name="Common")
80
81 for p in passes:
~/Documents/coremltools/coremltools/converters/mil/mil/passes/apply_common_pass_pipeline.py in _apply(passes, name)
28 _logging.info('Performing pass: "{}"'.format(p))
29 graph_pass = PASS_REGISTRY[p] if not isinstance(p, AbstractQuantizationPass) else p
---> 30 graph_pass(prog)
31 if isinstance(p, AbstractQuantizationPass) or not isinstance(PASS_REGISTRY[p], PassContainer):
32 prog.validate()
~/Documents/coremltools/coremltools/converters/mil/mil/passes/graph_pass.py in __call__(self, prog)
7
8 def __call__(self, prog):
----> 9 self.apply(prog)
10
11 def __str__(self):
~/Documents/coremltools/coremltools/converters/mil/mil/passes/reduce_transposes.py in apply(self, prog)
1253 def apply(self, prog):
1254 for f in prog.functions.values():
-> 1255 _reduce_transposes_block(f)
~/Documents/coremltools/coremltools/converters/mil/mil/passes/reduce_transposes.py in _reduce_transposes_block(block)
1245 opt_transposes = TransposeOptimization(block)
1246 opt_transposes.block_traversal()
-> 1247 opt_transposes.apply_transform()
1248
1249
~/Documents/coremltools/coremltools/converters/mil/mil/passes/reduce_transposes.py in apply_transform(self)
1212 self._remove_transpose_ops(transpose_op)
1213 self.block.set_outputs([sink_op.x for sink_op in self.output_sink_ops])
-> 1214 self.block.remove_ops(list(self.output_sink_ops))
1215
1216 if DEBUG:
~/Documents/coremltools/coremltools/converters/mil/mil/block.py in remove_ops(self, existing_ops)
673 not_found.append(op.name)
674 raise ValueError(
--> 675 "Ops {} not found in block {}".format(not_found, self.name)
676 )
677
ValueError: Ops ['identity_0'] not found in block block0
However the following network works fines:
class Net(nn.Module):
def forward(self, x):
d1 = torch.zeros(2, dtype=torch.float32)
d2 = torch.zeros(2, dtype=torch.float32)
return (d1, d2)
Any guidance on what to do here? Running into the same problem
As a temporary workaround, you could disable the problematic reduce_transposes optimization/pass. Delete or comment out, this line and this line.
A fix for this bug was included in our 6.1 release. With coremltools 6.1 the model now converts without error.