facebookresearch / facebookresearch/detectron2

Unable to convert model to torchscript

Open
#4,326 1 comment 0 reactions 0 assignees View on GitHub
Dominant language
Python
Stars
34.7k
Forks
7.9k
PR merge metrics
No merged PRs in 30d

Description

I am trying to export model with Faster R-CNN R 101 DC5 backbone into Torchscript. I utilised the R101 DC5.yaml file for configuration and built the model.

```
config_file = "COCO-Detection/faster_rcnn_R_101_DC5_3x.yaml"
cfg = get_cfg()
cfg.merge_from_file(model_zoo.get_config_file(config_file))
```

```
from detectron2.modeling import build_model
model = build_model(cfg).eval()
#model.eval()
checkpointer = DetectionCheckpointer(model)
checkpointer.load(cfg.MODEL.WEIGHTS)

import torch
model = torch.jit.script(model)
```

I get the following error :

```
---------------------------------------------------------------------------
NotSupportedError Traceback (most recent call last)
in
1 import torch
----> 2 model = torch.jit.script(model)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_script.py in script(obj, optimize, _frames_up, _rcb, example_inputs)
1256 obj = call_prepare_scriptable_func(obj)
1257 return torch.jit._recursive.create_script_module(
-> 1258 obj, torch.jit._recursive.infer_methods_to_compile
1259 )
1260

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_recursive.py in create_script_module(nn_module, stubs_fn, share_types, is_tracing)
449 if not is_tracing:
450 AttributeTypeIsSupportedChecker().check(nn_module)
--> 451 return create_script_module_impl(nn_module, concrete_type, stubs_fn)
452
453 def create_script_module_impl(nn_module, concrete_type, stubs_fn):

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_recursive.py in create_script_module_impl(nn_module, concrete_type, stubs_fn)
511
512 # Actually create the ScriptModule, initializing it with the function we just defined
--> 513 script_module = torch.jit.RecursiveScriptModule._construct(cpp_module, init_fn)
514
515 # Compile methods if necessary

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_script.py in _construct(cpp_module, init_fn)
585 """
586 script_module = RecursiveScriptModule(cpp_module)
--> 587 init_fn(script_module)
588
589 # Finalize the ScriptModule: replace the nn.Module state with our

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_recursive.py in init_fn(script_module)
489 else:
490 # always reuse the provided stubs_fn to infer the methods to compile
--> 491 scripted = create_script_module_impl(orig_value, sub_concrete_type, stubs_fn)
492
493 cpp_module.setattr(name, scripted)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_recursive.py in create_script_module_impl(nn_module, concrete_type, stubs_fn)
515 # Compile methods if necessary
516 if concrete_type not in concrete_type_store.methods_compiled:
--> 517 create_methods_and_properties_from_stubs(concrete_type, method_stubs, property_stubs)
518 # Create hooks after methods to ensure no name collisions between hooks and methods.
519 # If done before, hooks can overshadow methods that aren't exported.

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_recursive.py in create_methods_and_properties_from_stubs(concrete_type, method_stubs, property_stubs)
366 property_rcbs = [p.resolution_callback for p in property_stubs]
367
--> 368 concrete_type._create_methods_and_properties(property_defs, property_rcbs, method_defs, method_rcbs, method_defaults)
369
370 def create_hooks_from_stubs(concrete_type, hook_stubs, pre_hook_stubs):

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/annotations.py in try_ann_to_type(ann, loc)
338 if a is None:
339 inner.append(NoneType.get())
--> 340 maybe_type = try_ann_to_type(a, loc)
341 msg = "Unsupported annotation {} could not be resolved because {} could not be resolved."
342 assert maybe_type, msg.format(repr(ann), repr(maybe_type))

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/annotations.py in try_ann_to_type(ann, loc)
309 return TupleType([try_ann_to_type(a, loc) for a in ann.__args__])
310 if is_list(ann):
--> 311 elem_type = try_ann_to_type(ann.__args__[0], loc)
312 if elem_type:
313 return ListType(elem_type)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/annotations.py in try_ann_to_type(ann, loc)
381 return maybe_script_class
382 if torch._jit_internal.can_compile_class(ann):
--> 383 return torch.jit._script._recursive_compile_class(ann, loc)
384
385 # Maybe resolve a NamedTuple to a Tuple Type

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_script.py in _recursive_compile_class(obj, loc)
1431 error_stack = torch._C.CallStack(_qual_name, loc)
1432 rcb = _jit_internal.createResolutionCallbackForClassMethods(obj)
-> 1433 return _compile_and_register_class(obj, rcb, _qual_name)
1434
1435 CompilationUnit = torch._C.CompilationUnit

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/_recursive.py in _compile_and_register_class(obj, rcb, qualified_name)
40
41 if not script_class:
---> 42 ast = get_jit_class_def(obj, obj.__name__)
43 defaults = torch.jit.frontend.get_default_args_for_class(obj)
44 script_class = torch._C._jit_script_class_compile(qualified_name, ast, defaults, rcb)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/frontend.py in get_jit_class_def(cls, self_name)
199 name,
200 self_name=self_name,
--> 201 is_classmethod=is_classmethod(obj)) for (name, obj) in methods]
202
203 properties = get_class_properties(cls, self_name)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/frontend.py in (.0)
199 name,
200 self_name=self_name,
--> 201 is_classmethod=is_classmethod(obj)) for (name, obj) in methods]
202
203 properties = get_class_properties(cls, self_name)

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/frontend.py in get_jit_def(fn, def_name, self_name, is_classmethod)
262 pdt_arg_types = type_trace_db.get_args_types(qualname)
263
--> 264 return build_def(parsed_def.ctx, fn_def, type_line, def_name, self_name=self_name, pdt_arg_types=pdt_arg_types)
265
266 # TODO: more robust handling of recognizing ignore context manager

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/frontend.py in build_def(ctx, py_def, type_line, def_name, self_name, pdt_arg_types)
300 py_def.col_offset + len("def"))
301
--> 302 param_list = build_param_list(ctx, py_def.args, self_name, pdt_arg_types)
303 return_type = None
304 if getattr(py_def, 'returns', None) is not None:

~/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/torch/jit/frontend.py in build_param_list(ctx, py_args, self_name, pdt_arg_types)
324 expr = py_args.kwarg
325 ctx_range = ctx.make_range(expr.lineno, expr.col_offset - 1, expr.col_offset + len(expr.arg))
--> 326 raise NotSupportedError(ctx_range, _vararg_kwarg_err)
327 if py_args.vararg is not None:
328 expr = py_args.vararg

NotSupportedError: Compiled functions can't take variable number of arguments or use keyword-only arguments with defaults:
File "/home/ec2-user/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/detectron2/structures/instances.py", line 38
def __init__(self, image_size: Tuple[int, int], **kwargs: Any):
~~~~~~~ <--- HERE
"""
Args:
'__torch__.detectron2.structures.instances.Instances' is being compiled since it was called from 'RPN.forward'
File "/home/ec2-user/anaconda3/envs/pytorch_latest_p36/lib/python3.6/site-packages/detectron2/modeling/proposal_generator/rpn.py", line 431
def forward(
~~~~~~~~~~~~
self,
~~~~~
images: ImageList,
~~~~~~~~~~~~~~~~~~
features: Dict[str, torch.Tensor],
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gt_instances: Optional[List[Instances]] = None,
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
):
~~
"""
~~~
Args:
~~~~~
images (ImageList): input images of length `N`
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
features (dict[str, Tensor]): input data as a mapping from feature
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
map name to tensor. Axis 0 represents the number of images `N` in
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
the input data; axes 1-3 are channels, height, and width, which may
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
vary between feature maps (e.g., if a feature pyramid is used).
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gt_instances (list[Instances], optional): a length `N` list of `Instances`s.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Each `Instances` stores ground-truth instances for the corresponding image.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Returns:
~~~~~~~~
proposals: list[Instances]: contains fields "proposal_boxes", "objectness_logits"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
loss: dict[Tensor] or None
~~~~~~~~~~~~~~~~~~~~~~~~~~
"""
~~~
features = [features[f] for f in self.in_features]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
anchors = self.anchor_generator(features)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

pred_objectness_logits, pred_anchor_deltas = self.rpn_head(features)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Transpose the Hi*Wi*A dimension to the middle:
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pred_objectness_logits = [
~~~~~~~~~~~~~~~~~~~~~~~~~~
# (N, A, Hi, Wi) -> (N, Hi, Wi, A) -> (N, Hi*Wi*A)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
score.permute(0, 2, 3, 1).flatten(1)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for score in pred_objectness_logits
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
]
~
pred_anchor_deltas = [
~~~~~~~~~~~~~~~~~~~~~~
# (N, A*B, Hi, Wi) -> (N, A, B, Hi, Wi) -> (N, Hi, Wi, A, B) -> (N, Hi*Wi*A, B)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
x.view(x.shape[0], -1, self.anchor_generator.box_dim, x.shape[-2], x.shape[-1])
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.permute(0, 3, 4, 1, 2)
~~~~~~~~~~~~~~~~~~~~~~~
.flatten(1, -2)
~~~~~~~~~~~~~~~
for x in pred_anchor_deltas
~~~~~~~~~~~~~~~~~~~~~~~~~~~
]
~

if self.training:
~~~~~~~~~~~~~~~~~
assert gt_instances is not None, "RPN requires gt_instances in training!"
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gt_labels, gt_boxes = self.label_and_sample_anchors(anchors, gt_instances)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
losses = self.losses(
~~~~~~~~~~~~~~~~~~~~~
anchors, pred_objectness_logits, gt_labels, pred_anchor_deltas, gt_boxes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
)
~
else:
~~~~~
losses = {}
~~~~~~~~~~~
proposals = self.predict_proposals(
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
anchors, pred_objectness_logits, pred_anchor_deltas, images.image_sizes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
)
~
return proposals, losses
~~~~~~~~~~~~~~~~~~~~~~~~ <--- HERE
```

Kindly guide.

Contributor guide

Open the contributing guide

Research direction

Reproduce the failure with torch.jit.script(model) using the Faster R-CNN R101 DC5 configuration, then inspect detectron2/structures/instances.py and detectron2/modeling/proposal_generator/rpn.py, especially Instances.__init__ and RPN.forward. Done means the model exports to TorchScript without the reported NotSupportedError and its scripted inference remains usable.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, pytorch
Domain
computer-vision, machine-learning
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.