"vscode:/vscode.git/clone" did not exist on "5ed1c2f28b9c22713e7cf51390f4a69419b8ce93"
test_rcnn_export_example.py 4.62 KB
Newer Older
1
2
3
4
5
6
7
8
9
#!/usr/bin/env python3
# Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved

import os
import unittest

import torch
from d2go.runner.default_runner import GeneralizedRCNNRunner
from d2go.tools.exporter import main
Hang Zhang's avatar
Hang Zhang committed
10
from d2go.utils.testing.data_loader_helper import create_local_dataset
11
12
from d2go.utils.testing.rcnn_helper import get_quick_test_config_opts
from mobile_cv.common.misc.file_utils import make_temp_directory
13
from mobile_cv.common.misc.oss_utils import is_oss
14
15


16
def maskrcnn_export_caffe2_vs_torchvision_opset_format_example(self):
17
    with make_temp_directory("export_demo") as tmp_dir:
Hang Zhang's avatar
Hang Zhang committed
18
19
20
21
22
23
24
25
        # use a fake dataset for ci
        dataset_name = create_local_dataset(tmp_dir, 5, 224, 224)
        config_list = [
            "DATASETS.TRAIN",
            (dataset_name,),
            "DATASETS.TEST",
            (dataset_name,),
        ]
26
27
28
29
30
        # START_WIKI_EXAMPLE_TAG
        runner = GeneralizedRCNNRunner()
        cfg = runner.get_default_cfg()
        cfg.merge_from_file("detectron2go://mask_rcnn_fbnetv3a_dsmask_C4.yaml")
        cfg.merge_from_list(get_quick_test_config_opts())
Hang Zhang's avatar
Hang Zhang committed
31
        cfg.merge_from_list(config_list)
32
33

        # equivalent to running:
Yanghan Wang's avatar
Yanghan Wang committed
34
        #   exporter.par --runner GeneralizedRCNNRunner --config-file config.yaml --predictor-types torchscript tourchscript@c2_ops --output-dir tmp_dir
35
        _ = main(
Hang Zhang's avatar
Hang Zhang committed
36
37
38
            cfg,
            tmp_dir,
            runner,
Yanghan Wang's avatar
Yanghan Wang committed
39
            predictor_types=["torchscript@c2_ops", "torchscript"],
40
41
42
        )

        # the path can be fetched from the return of main, here just use hard-coded values
Yanghan Wang's avatar
Yanghan Wang committed
43
44
45
46
47
48
        torchvision_ops_model = torch.jit.load(
            os.path.join(tmp_dir, "torchscript", "model.jit")
        )
        caffe2_ops_model = torch.jit.load(
            os.path.join(tmp_dir, "torchscript@c2_ops", "model.jit")
        )
49

Yanghan Wang's avatar
Yanghan Wang committed
50
        # Running inference using torchvision-style format
51
        image = torch.zeros(1, 64, 96)  # chw 3D tensor
52
53
54
        # The exported model can run on both cpu/gpu
        device = "cuda:0" if torch.cuda.is_available() else "cpu"
        torchvision_ops_model = torchvision_ops_model.to(device)
Yanghan Wang's avatar
Yanghan Wang committed
55
56
57
        torchvision_style_outputs = torchvision_ops_model(
            image
        )  # suppose N instances are detected
58
59
60
61
62
        # NOTE: the output are flattened tensors of the real output (which is a dict), they're
        # ordered by the key in dict, which is deterministic for the given model, but it might
        # be difficult to figure out just from model.jit file. The predictor_info.json from
        # the same directory contains the `outputs_schema`, which indicate how the final output
        # is constructed from flattened tensors.
63
64
65
66
67
68
69
70
71
72
73
74
75
76
        (
            pred_boxes,  # torch.Size([N, 4])
            pred_classes,  # torch.Size([N])
            pred_masks,  # torch.Size([N, 1, Hmask, Wmask])
            scores,  # torch.Size([N])
            image_sizes,  # torch.Size([2])
        ) = torchvision_style_outputs
        self.assertTrue(
            all(
                x.device == torch.device(device) for x in torchvision_style_outputs[:4]
            ),
            torchvision_style_outputs,
        )
        torch.testing.assert_close(image_sizes, torch.tensor([64, 96]))
77

Yanghan Wang's avatar
Yanghan Wang committed
78
        # Running inference using caffe2-style format
79
80
        data = torch.zeros(1, 1, 64, 96)
        im_info = torch.tensor([[64, 96, 1.0]])
Yanghan Wang's avatar
Yanghan Wang committed
81
        caffe2_style_outputs = caffe2_ops_model([data, im_info])
82
83
        # NOTE: the output order is determined in the order of creating the tensor during
        # forward function, it's also follow the order of original Caffe2 model.
Yanghan Wang's avatar
Yanghan Wang committed
84
85
86
87
        roi_bbox_nms = caffe2_style_outputs[0]  # torch.Size([N, 4])
        roi_score_nms = caffe2_style_outputs[1]  # torch.Size([N])
        roi_class_nms = caffe2_style_outputs[2]  # torch.Size([N])
        mask_fcn_probs = caffe2_style_outputs[3]  # torch.Size([N, Cmask, Hmask, Wmask])
88

Yanghan Wang's avatar
Yanghan Wang committed
89
        # relations between torchvision-style outputs and caffe2-style outputs
90
91
92
93
94
95
96
97
        torch.testing.assert_close(pred_boxes, roi_bbox_nms, check_device=False)
        torch.testing.assert_close(
            pred_classes, roi_class_nms.to(torch.int64), check_device=False
        )
        torch.testing.assert_close(
            pred_masks,
            mask_fcn_probs[:, roi_class_nms.to(torch.int64), :, :],
            check_device=False,
98
        )
99
        torch.testing.assert_close(scores, roi_score_nms, check_device=False)
100
101
102
103
        # END_WIKI_EXAMPLE_TAG


class TestOptimizer(unittest.TestCase):
104
    @unittest.skipIf(is_oss(), "Caffe2 is not available for OSS")
Yanghan Wang's avatar
Yanghan Wang committed
105
    def test_maskrcnn_export_caffe2_vs_torchvision_opset_format_example(self):
106
        maskrcnn_export_caffe2_vs_torchvision_opset_format_example(self)