We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Shape of ONNX export dynamic batch
Thanks for your error report and we appreciate it a lot.

https://github.com/open-mmlab/mmdetection/blob/master/tools/deployment/pytorch2onnx.py#L71

This line should be 
```
    if dynamic_export:
        dynamic_axes = {
            input_name: {
                0: 'batch',
                2: 'height',
                3: 'width'
            },
            'dets': {
                0: 'batch',
                1: 'num_dets',
            },
            'labels': {
                0: 'batch',
                1: 'num_dets',
            },
        }
```

Based on the way the line below is implemented the dynamic axis should be `bs x c x h x w`. 
https://github.com/open-mmlab/mmdetection/blob/master/tools/deployment/pytorch2onnx.py#L139


I can create a quick PR for this if needed. 



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `tools/deployment/pytorch2onnx.py`
Content:
```
1 # Copyright (c) OpenMMLab. All rights reserved.
2 import argparse
3 import os.path as osp
4 import warnings
5 from functools import partial
6 
7 import numpy as np
8 import onnx
9 import torch
10 from mmcv import Config, DictAction
11 
12 from mmdet.core.export import build_model_from_cfg, preprocess_example_input
13 from mmdet.core.export.model_wrappers import ONNXRuntimeDetector
14 
15 
16 def pytorch2onnx(model,
17                  input_img,
18                  input_shape,
19                  normalize_cfg,
20                  opset_version=11,
21                  show=False,
22                  output_file='tmp.onnx',
23                  verify=False,
24                  test_img=None,
25                  do_simplify=False,
26                  dynamic_export=None,
27                  skip_postprocess=False):
28 
29     input_config = {
30         'input_shape': input_shape,
31         'input_path': input_img,
32         'normalize_cfg': normalize_cfg
33     }
34     # prepare input
35     one_img, one_meta = preprocess_example_input(input_config)
36     img_list, img_meta_list = [one_img], [[one_meta]]
37 
38     if skip_postprocess:
39         warnings.warn('Not all models support export onnx without post '
40                       'process, especially two stage detectors!')
41         model.forward = model.forward_dummy
42         torch.onnx.export(
43             model,
44             one_img,
45             output_file,
46             input_names=['input'],
47             export_params=True,
48             keep_initializers_as_inputs=True,
49             do_constant_folding=True,
50             verbose=show,
51             opset_version=opset_version)
52 
53         print(f'Successfully exported ONNX model without '
54               f'post process: {output_file}')
55         return
56 
57     # replace original forward function
58     origin_forward = model.forward
59     model.forward = partial(
60         model.forward,
61         img_metas=img_meta_list,
62         return_loss=False,
63         rescale=False)
64 
65     output_names = ['dets', 'labels']
66     if model.with_mask:
67         output_names.append('masks')
68     input_name = 'input'
69     dynamic_axes = None
70     if dynamic_export:
71         dynamic_axes = {
72             input_name: {
73                 0: 'batch',
74                 2: 'width',
75                 3: 'height'
76             },
77             'dets': {
78                 0: 'batch',
79                 1: 'num_dets',
80             },
81             'labels': {
82                 0: 'batch',
83                 1: 'num_dets',
84             },
85         }
86         if model.with_mask:
87             dynamic_axes['masks'] = {0: 'batch', 1: 'num_dets'}
88 
89     torch.onnx.export(
90         model,
91         img_list,
92         output_file,
93         input_names=[input_name],
94         output_names=output_names,
95         export_params=True,
96         keep_initializers_as_inputs=True,
97         do_constant_folding=True,
98         verbose=show,
99         opset_version=opset_version,
100         dynamic_axes=dynamic_axes)
101 
102     model.forward = origin_forward
103 
104     # get the custom op path
105     ort_custom_op_path = ''
106     try:
107         from mmcv.ops import get_onnxruntime_op_path
108         ort_custom_op_path = get_onnxruntime_op_path()
109     except (ImportError, ModuleNotFoundError):
110         warnings.warn('If input model has custom op from mmcv, \
111             you may have to build mmcv with ONNXRuntime from source.')
112 
113     if do_simplify:
114         import onnxsim
115 
116         from mmdet import digit_version
117 
118         min_required_version = '0.3.0'
119         assert digit_version(onnxsim.__version__) >= digit_version(
120             min_required_version
121         ), f'Requires to install onnx-simplify>={min_required_version}'
122 
123         input_dic = {'input': img_list[0].detach().cpu().numpy()}
124         onnxsim.simplify(
125             output_file, input_data=input_dic, custom_lib=ort_custom_op_path)
126     print(f'Successfully exported ONNX model: {output_file}')
127 
128     if verify:
129         # check by onnx
130         onnx_model = onnx.load(output_file)
131         onnx.checker.check_model(onnx_model)
132 
133         # wrap onnx model
134         onnx_model = ONNXRuntimeDetector(output_file, model.CLASSES, 0)
135         if dynamic_export:
136             # scale up to test dynamic shape
137             h, w = [int((_ * 1.5) // 32 * 32) for _ in input_shape[2:]]
138             h, w = min(1344, h), min(1344, w)
139             input_config['input_shape'] = (1, 3, h, w)
140 
141         if test_img is None:
142             input_config['input_path'] = input_img
143 
144         # prepare input once again
145         one_img, one_meta = preprocess_example_input(input_config)
146         img_list, img_meta_list = [one_img], [[one_meta]]
147 
148         # get pytorch output
149         with torch.no_grad():
150             pytorch_results = model(
151                 img_list,
152                 img_metas=img_meta_list,
153                 return_loss=False,
154                 rescale=True)[0]
155 
156         img_list = [_.cuda().contiguous() for _ in img_list]
157         if dynamic_export:
158             img_list = img_list + [_.flip(-1).contiguous() for _ in img_list]
159             img_meta_list = img_meta_list * 2
160         # get onnx output
161         onnx_results = onnx_model(
162             img_list, img_metas=img_meta_list, return_loss=False)[0]
163         # visualize predictions
164         score_thr = 0.3
165         if show:
166             out_file_ort, out_file_pt = None, None
167         else:
168             out_file_ort, out_file_pt = 'show-ort.png', 'show-pt.png'
169 
170         show_img = one_meta['show_img']
171         model.show_result(
172             show_img,
173             pytorch_results,
174             score_thr=score_thr,
175             show=True,
176             win_name='PyTorch',
177             out_file=out_file_pt)
178         onnx_model.show_result(
179             show_img,
180             onnx_results,
181             score_thr=score_thr,
182             show=True,
183             win_name='ONNXRuntime',
184             out_file=out_file_ort)
185 
186         # compare a part of result
187         if model.with_mask:
188             compare_pairs = list(zip(onnx_results, pytorch_results))
189         else:
190             compare_pairs = [(onnx_results, pytorch_results)]
191         err_msg = 'The numerical values are different between Pytorch' + \
192                   ' and ONNX, but it does not necessarily mean the' + \
193                   ' exported ONNX model is problematic.'
194         # check the numerical value
195         for onnx_res, pytorch_res in compare_pairs:
196             for o_res, p_res in zip(onnx_res, pytorch_res):
197                 np.testing.assert_allclose(
198                     o_res, p_res, rtol=1e-03, atol=1e-05, err_msg=err_msg)
199         print('The numerical values are the same between Pytorch and ONNX')
200 
201 
202 def parse_normalize_cfg(test_pipeline):
203     transforms = None
204     for pipeline in test_pipeline:
205         if 'transforms' in pipeline:
206             transforms = pipeline['transforms']
207             break
208     assert transforms is not None, 'Failed to find `transforms`'
209     norm_config_li = [_ for _ in transforms if _['type'] == 'Normalize']
210     assert len(norm_config_li) == 1, '`norm_config` should only have one'
211     norm_config = norm_config_li[0]
212     return norm_config
213 
214 
215 def parse_args():
216     parser = argparse.ArgumentParser(
217         description='Convert MMDetection models to ONNX')
218     parser.add_argument('config', help='test config file path')
219     parser.add_argument('checkpoint', help='checkpoint file')
220     parser.add_argument('--input-img', type=str, help='Images for input')
221     parser.add_argument(
222         '--show',
223         action='store_true',
224         help='Show onnx graph and detection outputs')
225     parser.add_argument('--output-file', type=str, default='tmp.onnx')
226     parser.add_argument('--opset-version', type=int, default=11)
227     parser.add_argument(
228         '--test-img', type=str, default=None, help='Images for test')
229     parser.add_argument(
230         '--dataset',
231         type=str,
232         default='coco',
233         help='Dataset name. This argument is deprecated and will be removed \
234         in future releases.')
235     parser.add_argument(
236         '--verify',
237         action='store_true',
238         help='verify the onnx model output against pytorch output')
239     parser.add_argument(
240         '--simplify',
241         action='store_true',
242         help='Whether to simplify onnx model.')
243     parser.add_argument(
244         '--shape',
245         type=int,
246         nargs='+',
247         default=[800, 1216],
248         help='input image size')
249     parser.add_argument(
250         '--mean',
251         type=float,
252         nargs='+',
253         default=[123.675, 116.28, 103.53],
254         help='mean value used for preprocess input data.This argument \
255         is deprecated and will be removed in future releases.')
256     parser.add_argument(
257         '--std',
258         type=float,
259         nargs='+',
260         default=[58.395, 57.12, 57.375],
261         help='variance value used for preprocess input data. '
262         'This argument is deprecated and will be removed in future releases.')
263     parser.add_argument(
264         '--cfg-options',
265         nargs='+',
266         action=DictAction,
267         help='Override some settings in the used config, the key-value pair '
268         'in xxx=yyy format will be merged into config file. If the value to '
269         'be overwritten is a list, it should be like key="[a,b]" or key=a,b '
270         'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" '
271         'Note that the quotation marks are necessary and that no white space '
272         'is allowed.')
273     parser.add_argument(
274         '--dynamic-export',
275         action='store_true',
276         help='Whether to export onnx with dynamic axis.')
277     parser.add_argument(
278         '--skip-postprocess',
279         action='store_true',
280         help='Whether to export model without post process. Experimental '
281         'option. We do not guarantee the correctness of the exported '
282         'model.')
283     args = parser.parse_args()
284     return args
285 
286 
287 if __name__ == '__main__':
288     args = parse_args()
289     warnings.warn('Arguments like `--mean`, `--std`, `--dataset` would be \
290         parsed directly from config file and are deprecated and \
291         will be removed in future releases.')
292 
293     assert args.opset_version == 11, 'MMDet only support opset 11 now'
294 
295     try:
296         from mmcv.onnx.symbolic import register_extra_symbolics
297     except ModuleNotFoundError:
298         raise NotImplementedError('please update mmcv to version>=v1.0.4')
299     register_extra_symbolics(args.opset_version)
300 
301     cfg = Config.fromfile(args.config)
302     if args.cfg_options is not None:
303         cfg.merge_from_dict(args.cfg_options)
304 
305     if args.shape is None:
306         img_scale = cfg.test_pipeline[1]['img_scale']
307         input_shape = (1, 3, img_scale[1], img_scale[0])
308     elif len(args.shape) == 1:
309         input_shape = (1, 3, args.shape[0], args.shape[0])
310     elif len(args.shape) == 2:
311         input_shape = (1, 3) + tuple(args.shape)
312     else:
313         raise ValueError('invalid input shape')
314 
315     # build the model and load checkpoint
316     model = build_model_from_cfg(args.config, args.checkpoint,
317                                  args.cfg_options)
318 
319     if not args.input_img:
320         args.input_img = osp.join(osp.dirname(__file__), '../../demo/demo.jpg')
321 
322     normalize_cfg = parse_normalize_cfg(cfg.test_pipeline)
323 
324     # convert model to onnx file
325     pytorch2onnx(
326         model,
327         args.input_img,
328         input_shape,
329         normalize_cfg,
330         opset_version=args.opset_version,
331         show=args.show,
332         output_file=args.output_file,
333         verify=args.verify,
334         test_img=args.test_img,
335         do_simplify=args.simplify,
336         dynamic_export=args.dynamic_export,
337         skip_postprocess=args.skip_postprocess)
338
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/tools/deployment/pytorch2onnx.py b/tools/deployment/pytorch2onnx.py
--- a/tools/deployment/pytorch2onnx.py
+++ b/tools/deployment/pytorch2onnx.py
@@ -71,8 +71,8 @@
         dynamic_axes = {
             input_name: {
                 0: 'batch',
-                2: 'width',
-                3: 'height'
+                2: 'height',
+                3: 'width'
             },
             'dets': {
                 0: 'batch',

{"golden_diff": "diff --git a/tools/deployment/pytorch2onnx.py b/tools/deployment/pytorch2onnx.py\n--- a/tools/deployment/pytorch2onnx.py\n+++ b/tools/deployment/pytorch2onnx.py\n@@ -71,8 +71,8 @@\n         dynamic_axes = {\n             input_name: {\n                 0: 'batch',\n-                2: 'width',\n-                3: 'height'\n+                2: 'height',\n+                3: 'width'\n             },\n             'dets': {\n                 0: 'batch',\n", "issue": "Shape of ONNX export dynamic batch\nThanks for your error report and we appreciate it a lot.\r\n\r\nhttps://github.com/open-mmlab/mmdetection/blob/master/tools/deployment/pytorch2onnx.py#L71\r\n\r\nThis line should be \r\n```\r\n    if dynamic_export:\r\n        dynamic_axes = {\r\n            input_name: {\r\n                0: 'batch',\r\n                2: 'height',\r\n                3: 'width'\r\n            },\r\n            'dets': {\r\n                0: 'batch',\r\n                1: 'num_dets',\r\n            },\r\n            'labels': {\r\n                0: 'batch',\r\n                1: 'num_dets',\r\n            },\r\n        }\r\n```\r\n\r\nBased on the way the line below is implemented the dynamic axis should be `bs x c x h x w`. \r\nhttps://github.com/open-mmlab/mmdetection/blob/master/tools/deployment/pytorch2onnx.py#L139\r\n\r\n\r\nI can create a quick PR for this if needed. \r\n\r\n\n", "before_files": [{"content": "# Copyright (c) OpenMMLab. All rights reserved.\nimport argparse\nimport os.path as osp\nimport warnings\nfrom functools import partial\n\nimport numpy as np\nimport onnx\nimport torch\nfrom mmcv import Config, DictAction\n\nfrom mmdet.core.export import build_model_from_cfg, preprocess_example_input\nfrom mmdet.core.export.model_wrappers import ONNXRuntimeDetector\n\n\ndef pytorch2onnx(model,\n                 input_img,\n                 input_shape,\n                 normalize_cfg,\n                 opset_version=11,\n                 show=False,\n                 output_file='tmp.onnx',\n                 verify=False,\n                 test_img=None,\n                 do_simplify=False,\n                 dynamic_export=None,\n                 skip_postprocess=False):\n\n    input_config = {\n        'input_shape': input_shape,\n        'input_path': input_img,\n        'normalize_cfg': normalize_cfg\n    }\n    # prepare input\n    one_img, one_meta = preprocess_example_input(input_config)\n    img_list, img_meta_list = [one_img], [[one_meta]]\n\n    if skip_postprocess:\n        warnings.warn('Not all models support export onnx without post '\n                      'process, especially two stage detectors!')\n        model.forward = model.forward_dummy\n        torch.onnx.export(\n            model,\n            one_img,\n            output_file,\n            input_names=['input'],\n            export_params=True,\n            keep_initializers_as_inputs=True,\n            do_constant_folding=True,\n            verbose=show,\n            opset_version=opset_version)\n\n        print(f'Successfully exported ONNX model without '\n              f'post process: {output_file}')\n        return\n\n    # replace original forward function\n    origin_forward = model.forward\n    model.forward = partial(\n        model.forward,\n        img_metas=img_meta_list,\n        return_loss=False,\n        rescale=False)\n\n    output_names = ['dets', 'labels']\n    if model.with_mask:\n        output_names.append('masks')\n    input_name = 'input'\n    dynamic_axes = None\n    if dynamic_export:\n        dynamic_axes = {\n            input_name: {\n                0: 'batch',\n                2: 'width',\n                3: 'height'\n            },\n            'dets': {\n                0: 'batch',\n                1: 'num_dets',\n            },\n            'labels': {\n                0: 'batch',\n                1: 'num_dets',\n            },\n        }\n        if model.with_mask:\n            dynamic_axes['masks'] = {0: 'batch', 1: 'num_dets'}\n\n    torch.onnx.export(\n        model,\n        img_list,\n        output_file,\n        input_names=[input_name],\n        output_names=output_names,\n        export_params=True,\n        keep_initializers_as_inputs=True,\n        do_constant_folding=True,\n        verbose=show,\n        opset_version=opset_version,\n        dynamic_axes=dynamic_axes)\n\n    model.forward = origin_forward\n\n    # get the custom op path\n    ort_custom_op_path = ''\n    try:\n        from mmcv.ops import get_onnxruntime_op_path\n        ort_custom_op_path = get_onnxruntime_op_path()\n    except (ImportError, ModuleNotFoundError):\n        warnings.warn('If input model has custom op from mmcv, \\\n            you may have to build mmcv with ONNXRuntime from source.')\n\n    if do_simplify:\n        import onnxsim\n\n        from mmdet import digit_version\n\n        min_required_version = '0.3.0'\n        assert digit_version(onnxsim.__version__) >= digit_version(\n            min_required_version\n        ), f'Requires to install onnx-simplify>={min_required_version}'\n\n        input_dic = {'input': img_list[0].detach().cpu().numpy()}\n        onnxsim.simplify(\n            output_file, input_data=input_dic, custom_lib=ort_custom_op_path)\n    print(f'Successfully exported ONNX model: {output_file}')\n\n    if verify:\n        # check by onnx\n        onnx_model = onnx.load(output_file)\n        onnx.checker.check_model(onnx_model)\n\n        # wrap onnx model\n        onnx_model = ONNXRuntimeDetector(output_file, model.CLASSES, 0)\n        if dynamic_export:\n            # scale up to test dynamic shape\n            h, w = [int((_ * 1.5) // 32 * 32) for _ in input_shape[2:]]\n            h, w = min(1344, h), min(1344, w)\n            input_config['input_shape'] = (1, 3, h, w)\n\n        if test_img is None:\n            input_config['input_path'] = input_img\n\n        # prepare input once again\n        one_img, one_meta = preprocess_example_input(input_config)\n        img_list, img_meta_list = [one_img], [[one_meta]]\n\n        # get pytorch output\n        with torch.no_grad():\n            pytorch_results = model(\n                img_list,\n                img_metas=img_meta_list,\n                return_loss=False,\n                rescale=True)[0]\n\n        img_list = [_.cuda().contiguous() for _ in img_list]\n        if dynamic_export:\n            img_list = img_list + [_.flip(-1).contiguous() for _ in img_list]\n            img_meta_list = img_meta_list * 2\n        # get onnx output\n        onnx_results = onnx_model(\n            img_list, img_metas=img_meta_list, return_loss=False)[0]\n        # visualize predictions\n        score_thr = 0.3\n        if show:\n            out_file_ort, out_file_pt = None, None\n        else:\n            out_file_ort, out_file_pt = 'show-ort.png', 'show-pt.png'\n\n        show_img = one_meta['show_img']\n        model.show_result(\n            show_img,\n            pytorch_results,\n            score_thr=score_thr,\n            show=True,\n            win_name='PyTorch',\n            out_file=out_file_pt)\n        onnx_model.show_result(\n            show_img,\n            onnx_results,\n            score_thr=score_thr,\n            show=True,\n            win_name='ONNXRuntime',\n            out_file=out_file_ort)\n\n        # compare a part of result\n        if model.with_mask:\n            compare_pairs = list(zip(onnx_results, pytorch_results))\n        else:\n            compare_pairs = [(onnx_results, pytorch_results)]\n        err_msg = 'The numerical values are different between Pytorch' + \\\n                  ' and ONNX, but it does not necessarily mean the' + \\\n                  ' exported ONNX model is problematic.'\n        # check the numerical value\n        for onnx_res, pytorch_res in compare_pairs:\n            for o_res, p_res in zip(onnx_res, pytorch_res):\n                np.testing.assert_allclose(\n                    o_res, p_res, rtol=1e-03, atol=1e-05, err_msg=err_msg)\n        print('The numerical values are the same between Pytorch and ONNX')\n\n\ndef parse_normalize_cfg(test_pipeline):\n    transforms = None\n    for pipeline in test_pipeline:\n        if 'transforms' in pipeline:\n            transforms = pipeline['transforms']\n            break\n    assert transforms is not None, 'Failed to find `transforms`'\n    norm_config_li = [_ for _ in transforms if _['type'] == 'Normalize']\n    assert len(norm_config_li) == 1, '`norm_config` should only have one'\n    norm_config = norm_config_li[0]\n    return norm_config\n\n\ndef parse_args():\n    parser = argparse.ArgumentParser(\n        description='Convert MMDetection models to ONNX')\n    parser.add_argument('config', help='test config file path')\n    parser.add_argument('checkpoint', help='checkpoint file')\n    parser.add_argument('--input-img', type=str, help='Images for input')\n    parser.add_argument(\n        '--show',\n        action='store_true',\n        help='Show onnx graph and detection outputs')\n    parser.add_argument('--output-file', type=str, default='tmp.onnx')\n    parser.add_argument('--opset-version', type=int, default=11)\n    parser.add_argument(\n        '--test-img', type=str, default=None, help='Images for test')\n    parser.add_argument(\n        '--dataset',\n        type=str,\n        default='coco',\n        help='Dataset name. This argument is deprecated and will be removed \\\n        in future releases.')\n    parser.add_argument(\n        '--verify',\n        action='store_true',\n        help='verify the onnx model output against pytorch output')\n    parser.add_argument(\n        '--simplify',\n        action='store_true',\n        help='Whether to simplify onnx model.')\n    parser.add_argument(\n        '--shape',\n        type=int,\n        nargs='+',\n        default=[800, 1216],\n        help='input image size')\n    parser.add_argument(\n        '--mean',\n        type=float,\n        nargs='+',\n        default=[123.675, 116.28, 103.53],\n        help='mean value used for preprocess input data.This argument \\\n        is deprecated and will be removed in future releases.')\n    parser.add_argument(\n        '--std',\n        type=float,\n        nargs='+',\n        default=[58.395, 57.12, 57.375],\n        help='variance value used for preprocess input data. '\n        'This argument is deprecated and will be removed in future releases.')\n    parser.add_argument(\n        '--cfg-options',\n        nargs='+',\n        action=DictAction,\n        help='Override some settings in the used config, the key-value pair '\n        'in xxx=yyy format will be merged into config file. If the value to '\n        'be overwritten is a list, it should be like key=\"[a,b]\" or key=a,b '\n        'It also allows nested list/tuple values, e.g. key=\"[(a,b),(c,d)]\" '\n        'Note that the quotation marks are necessary and that no white space '\n        'is allowed.')\n    parser.add_argument(\n        '--dynamic-export',\n        action='store_true',\n        help='Whether to export onnx with dynamic axis.')\n    parser.add_argument(\n        '--skip-postprocess',\n        action='store_true',\n        help='Whether to export model without post process. Experimental '\n        'option. We do not guarantee the correctness of the exported '\n        'model.')\n    args = parser.parse_args()\n    return args\n\n\nif __name__ == '__main__':\n    args = parse_args()\n    warnings.warn('Arguments like `--mean`, `--std`, `--dataset` would be \\\n        parsed directly from config file and are deprecated and \\\n        will be removed in future releases.')\n\n    assert args.opset_version == 11, 'MMDet only support opset 11 now'\n\n    try:\n        from mmcv.onnx.symbolic import register_extra_symbolics\n    except ModuleNotFoundError:\n        raise NotImplementedError('please update mmcv to version>=v1.0.4')\n    register_extra_symbolics(args.opset_version)\n\n    cfg = Config.fromfile(args.config)\n    if args.cfg_options is not None:\n        cfg.merge_from_dict(args.cfg_options)\n\n    if args.shape is None:\n        img_scale = cfg.test_pipeline[1]['img_scale']\n        input_shape = (1, 3, img_scale[1], img_scale[0])\n    elif len(args.shape) == 1:\n        input_shape = (1, 3, args.shape[0], args.shape[0])\n    elif len(args.shape) == 2:\n        input_shape = (1, 3) + tuple(args.shape)\n    else:\n        raise ValueError('invalid input shape')\n\n    # build the model and load checkpoint\n    model = build_model_from_cfg(args.config, args.checkpoint,\n                                 args.cfg_options)\n\n    if not args.input_img:\n        args.input_img = osp.join(osp.dirname(__file__), '../../demo/demo.jpg')\n\n    normalize_cfg = parse_normalize_cfg(cfg.test_pipeline)\n\n    # convert model to onnx file\n    pytorch2onnx(\n        model,\n        args.input_img,\n        input_shape,\n        normalize_cfg,\n        opset_version=args.opset_version,\n        show=args.show,\n        output_file=args.output_file,\n        verify=args.verify,\n        test_img=args.test_img,\n        do_simplify=args.simplify,\n        dynamic_export=args.dynamic_export,\n        skip_postprocess=args.skip_postprocess)\n", "path": "tools/deployment/pytorch2onnx.py"}], "after_files": [{"content": "# Copyright (c) OpenMMLab. All rights reserved.\nimport argparse\nimport os.path as osp\nimport warnings\nfrom functools import partial\n\nimport numpy as np\nimport onnx\nimport torch\nfrom mmcv import Config, DictAction\n\nfrom mmdet.core.export import build_model_from_cfg, preprocess_example_input\nfrom mmdet.core.export.model_wrappers import ONNXRuntimeDetector\n\n\ndef pytorch2onnx(model,\n                 input_img,\n                 input_shape,\n                 normalize_cfg,\n                 opset_version=11,\n                 show=False,\n                 output_file='tmp.onnx',\n                 verify=False,\n                 test_img=None,\n                 do_simplify=False,\n                 dynamic_export=None,\n                 skip_postprocess=False):\n\n    input_config = {\n        'input_shape': input_shape,\n        'input_path': input_img,\n        'normalize_cfg': normalize_cfg\n    }\n    # prepare input\n    one_img, one_meta = preprocess_example_input(input_config)\n    img_list, img_meta_list = [one_img], [[one_meta]]\n\n    if skip_postprocess:\n        warnings.warn('Not all models support export onnx without post '\n                      'process, especially two stage detectors!')\n        model.forward = model.forward_dummy\n        torch.onnx.export(\n            model,\n            one_img,\n            output_file,\n            input_names=['input'],\n            export_params=True,\n            keep_initializers_as_inputs=True,\n            do_constant_folding=True,\n            verbose=show,\n            opset_version=opset_version)\n\n        print(f'Successfully exported ONNX model without '\n              f'post process: {output_file}')\n        return\n\n    # replace original forward function\n    origin_forward = model.forward\n    model.forward = partial(\n        model.forward,\n        img_metas=img_meta_list,\n        return_loss=False,\n        rescale=False)\n\n    output_names = ['dets', 'labels']\n    if model.with_mask:\n        output_names.append('masks')\n    input_name = 'input'\n    dynamic_axes = None\n    if dynamic_export:\n        dynamic_axes = {\n            input_name: {\n                0: 'batch',\n                2: 'height',\n                3: 'width'\n            },\n            'dets': {\n                0: 'batch',\n                1: 'num_dets',\n            },\n            'labels': {\n                0: 'batch',\n                1: 'num_dets',\n            },\n        }\n        if model.with_mask:\n            dynamic_axes['masks'] = {0: 'batch', 1: 'num_dets'}\n\n    torch.onnx.export(\n        model,\n        img_list,\n        output_file,\n        input_names=[input_name],\n        output_names=output_names,\n        export_params=True,\n        keep_initializers_as_inputs=True,\n        do_constant_folding=True,\n        verbose=show,\n        opset_version=opset_version,\n        dynamic_axes=dynamic_axes)\n\n    model.forward = origin_forward\n\n    # get the custom op path\n    ort_custom_op_path = ''\n    try:\n        from mmcv.ops import get_onnxruntime_op_path\n        ort_custom_op_path = get_onnxruntime_op_path()\n    except (ImportError, ModuleNotFoundError):\n        warnings.warn('If input model has custom op from mmcv, \\\n            you may have to build mmcv with ONNXRuntime from source.')\n\n    if do_simplify:\n        import onnxsim\n\n        from mmdet import digit_version\n\n        min_required_version = '0.3.0'\n        assert digit_version(onnxsim.__version__) >= digit_version(\n            min_required_version\n        ), f'Requires to install onnx-simplify>={min_required_version}'\n\n        input_dic = {'input': img_list[0].detach().cpu().numpy()}\n        onnxsim.simplify(\n            output_file, input_data=input_dic, custom_lib=ort_custom_op_path)\n    print(f'Successfully exported ONNX model: {output_file}')\n\n    if verify:\n        # check by onnx\n        onnx_model = onnx.load(output_file)\n        onnx.checker.check_model(onnx_model)\n\n        # wrap onnx model\n        onnx_model = ONNXRuntimeDetector(output_file, model.CLASSES, 0)\n        if dynamic_export:\n            # scale up to test dynamic shape\n            h, w = [int((_ * 1.5) // 32 * 32) for _ in input_shape[2:]]\n            h, w = min(1344, h), min(1344, w)\n            input_config['input_shape'] = (1, 3, h, w)\n\n        if test_img is None:\n            input_config['input_path'] = input_img\n\n        # prepare input once again\n        one_img, one_meta = preprocess_example_input(input_config)\n        img_list, img_meta_list = [one_img], [[one_meta]]\n\n        # get pytorch output\n        with torch.no_grad():\n            pytorch_results = model(\n                img_list,\n                img_metas=img_meta_list,\n                return_loss=False,\n                rescale=True)[0]\n\n        img_list = [_.cuda().contiguous() for _ in img_list]\n        if dynamic_export:\n            img_list = img_list + [_.flip(-1).contiguous() for _ in img_list]\n            img_meta_list = img_meta_list * 2\n        # get onnx output\n        onnx_results = onnx_model(\n            img_list, img_metas=img_meta_list, return_loss=False)[0]\n        # visualize predictions\n        score_thr = 0.3\n        if show:\n            out_file_ort, out_file_pt = None, None\n        else:\n            out_file_ort, out_file_pt = 'show-ort.png', 'show-pt.png'\n\n        show_img = one_meta['show_img']\n        model.show_result(\n            show_img,\n            pytorch_results,\n            score_thr=score_thr,\n            show=True,\n            win_name='PyTorch',\n            out_file=out_file_pt)\n        onnx_model.show_result(\n            show_img,\n            onnx_results,\n            score_thr=score_thr,\n            show=True,\n            win_name='ONNXRuntime',\n            out_file=out_file_ort)\n\n        # compare a part of result\n        if model.with_mask:\n            compare_pairs = list(zip(onnx_results, pytorch_results))\n        else:\n            compare_pairs = [(onnx_results, pytorch_results)]\n        err_msg = 'The numerical values are different between Pytorch' + \\\n                  ' and ONNX, but it does not necessarily mean the' + \\\n                  ' exported ONNX model is problematic.'\n        # check the numerical value\n        for onnx_res, pytorch_res in compare_pairs:\n            for o_res, p_res in zip(onnx_res, pytorch_res):\n                np.testing.assert_allclose(\n                    o_res, p_res, rtol=1e-03, atol=1e-05, err_msg=err_msg)\n        print('The numerical values are the same between Pytorch and ONNX')\n\n\ndef parse_normalize_cfg(test_pipeline):\n    transforms = None\n    for pipeline in test_pipeline:\n        if 'transforms' in pipeline:\n            transforms = pipeline['transforms']\n            break\n    assert transforms is not None, 'Failed to find `transforms`'\n    norm_config_li = [_ for _ in transforms if _['type'] == 'Normalize']\n    assert len(norm_config_li) == 1, '`norm_config` should only have one'\n    norm_config = norm_config_li[0]\n    return norm_config\n\n\ndef parse_args():\n    parser = argparse.ArgumentParser(\n        description='Convert MMDetection models to ONNX')\n    parser.add_argument('config', help='test config file path')\n    parser.add_argument('checkpoint', help='checkpoint file')\n    parser.add_argument('--input-img', type=str, help='Images for input')\n    parser.add_argument(\n        '--show',\n        action='store_true',\n        help='Show onnx graph and detection outputs')\n    parser.add_argument('--output-file', type=str, default='tmp.onnx')\n    parser.add_argument('--opset-version', type=int, default=11)\n    parser.add_argument(\n        '--test-img', type=str, default=None, help='Images for test')\n    parser.add_argument(\n        '--dataset',\n        type=str,\n        default='coco',\n        help='Dataset name. This argument is deprecated and will be removed \\\n        in future releases.')\n    parser.add_argument(\n        '--verify',\n        action='store_true',\n        help='verify the onnx model output against pytorch output')\n    parser.add_argument(\n        '--simplify',\n        action='store_true',\n        help='Whether to simplify onnx model.')\n    parser.add_argument(\n        '--shape',\n        type=int,\n        nargs='+',\n        default=[800, 1216],\n        help='input image size')\n    parser.add_argument(\n        '--mean',\n        type=float,\n        nargs='+',\n        default=[123.675, 116.28, 103.53],\n        help='mean value used for preprocess input data.This argument \\\n        is deprecated and will be removed in future releases.')\n    parser.add_argument(\n        '--std',\n        type=float,\n        nargs='+',\n        default=[58.395, 57.12, 57.375],\n        help='variance value used for preprocess input data. '\n        'This argument is deprecated and will be removed in future releases.')\n    parser.add_argument(\n        '--cfg-options',\n        nargs='+',\n        action=DictAction,\n        help='Override some settings in the used config, the key-value pair '\n        'in xxx=yyy format will be merged into config file. If the value to '\n        'be overwritten is a list, it should be like key=\"[a,b]\" or key=a,b '\n        'It also allows nested list/tuple values, e.g. key=\"[(a,b),(c,d)]\" '\n        'Note that the quotation marks are necessary and that no white space '\n        'is allowed.')\n    parser.add_argument(\n        '--dynamic-export',\n        action='store_true',\n        help='Whether to export onnx with dynamic axis.')\n    parser.add_argument(\n        '--skip-postprocess',\n        action='store_true',\n        help='Whether to export model without post process. Experimental '\n        'option. We do not guarantee the correctness of the exported '\n        'model.')\n    args = parser.parse_args()\n    return args\n\n\nif __name__ == '__main__':\n    args = parse_args()\n    warnings.warn('Arguments like `--mean`, `--std`, `--dataset` would be \\\n        parsed directly from config file and are deprecated and \\\n        will be removed in future releases.')\n\n    assert args.opset_version == 11, 'MMDet only support opset 11 now'\n\n    try:\n        from mmcv.onnx.symbolic import register_extra_symbolics\n    except ModuleNotFoundError:\n        raise NotImplementedError('please update mmcv to version>=v1.0.4')\n    register_extra_symbolics(args.opset_version)\n\n    cfg = Config.fromfile(args.config)\n    if args.cfg_options is not None:\n        cfg.merge_from_dict(args.cfg_options)\n\n    if args.shape is None:\n        img_scale = cfg.test_pipeline[1]['img_scale']\n        input_shape = (1, 3, img_scale[1], img_scale[0])\n    elif len(args.shape) == 1:\n        input_shape = (1, 3, args.shape[0], args.shape[0])\n    elif len(args.shape) == 2:\n        input_shape = (1, 3) + tuple(args.shape)\n    else:\n        raise ValueError('invalid input shape')\n\n    # build the model and load checkpoint\n    model = build_model_from_cfg(args.config, args.checkpoint,\n                                 args.cfg_options)\n\n    if not args.input_img:\n        args.input_img = osp.join(osp.dirname(__file__), '../../demo/demo.jpg')\n\n    normalize_cfg = parse_normalize_cfg(cfg.test_pipeline)\n\n    # convert model to onnx file\n    pytorch2onnx(\n        model,\n        args.input_img,\n        input_shape,\n        normalize_cfg,\n        opset_version=args.opset_version,\n        show=args.show,\n        output_file=args.output_file,\n        verify=args.verify,\n        test_img=args.test_img,\n        do_simplify=args.simplify,\n        dynamic_export=args.dynamic_export,\n        skip_postprocess=args.skip_postprocess)\n", "path": "tools/deployment/pytorch2onnx.py"}]}