We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Confusion matrix error
While trying to generate the confusion matrix with this command:
```
python tools/analysis_tools/confusion_matrix.py ./work_dirs/perception-types--D06-01-2022--T09-23-45/perception-types.py results.pkl ./temp  --show
```
I ran into this error:
```
Traceback (most recent call last):
  File "tools/analysis_tools/confusion_matrix.py", line 261, in <module>
    main()
  File "tools/analysis_tools/confusion_matrix.py", line 257, in main
    show=args.show)
  File "tools/analysis_tools/confusion_matrix.py", line 210, in plot_confusion_matrix
    '{}%'.format(int(confusion_matrix[i, j])),
ValueError: cannot convert float NaN to integer
```
Would appreciate any help or suggestions! Thanks


--- 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/analysis_tools/confusion_matrix.py`
Content:
```
1 import argparse
2 import os
3 
4 import matplotlib.pyplot as plt
5 import mmcv
6 import numpy as np
7 from matplotlib.ticker import MultipleLocator
8 from mmcv import Config, DictAction
9 from mmcv.ops import nms
10 
11 from mmdet.core.evaluation.bbox_overlaps import bbox_overlaps
12 from mmdet.datasets import build_dataset
13 
14 
15 def parse_args():
16     parser = argparse.ArgumentParser(
17         description='Generate confusion matrix from detection results')
18     parser.add_argument('config', help='test config file path')
19     parser.add_argument(
20         'prediction_path', help='prediction path where test .pkl result')
21     parser.add_argument(
22         'save_dir', help='directory where confusion matrix will be saved')
23     parser.add_argument(
24         '--show', action='store_true', help='show confusion matrix')
25     parser.add_argument(
26         '--color-theme',
27         default='plasma',
28         help='theme of the matrix color map')
29     parser.add_argument(
30         '--score-thr',
31         type=float,
32         default=0.3,
33         help='score threshold to filter detection bboxes')
34     parser.add_argument(
35         '--tp-iou-thr',
36         type=float,
37         default=0.5,
38         help='IoU threshold to be considered as matched')
39     parser.add_argument(
40         '--nms-iou-thr',
41         type=float,
42         default=None,
43         help='nms IoU threshold, only applied when users want to change the'
44         'nms IoU threshold.')
45     parser.add_argument(
46         '--cfg-options',
47         nargs='+',
48         action=DictAction,
49         help='override some settings in the used config, the key-value pair '
50         'in xxx=yyy format will be merged into config file. If the value to '
51         'be overwritten is a list, it should be like key="[a,b]" or key=a,b '
52         'It also allows nested list/tuple values, e.g. key="[(a,b),(c,d)]" '
53         'Note that the quotation marks are necessary and that no white space '
54         'is allowed.')
55     args = parser.parse_args()
56     return args
57 
58 
59 def calculate_confusion_matrix(dataset,
60                                results,
61                                score_thr=0,
62                                nms_iou_thr=None,
63                                tp_iou_thr=0.5):
64     """Calculate the confusion matrix.
65 
66     Args:
67         dataset (Dataset): Test or val dataset.
68         results (list[ndarray]): A list of detection results in each image.
69         score_thr (float|optional): Score threshold to filter bboxes.
70             Default: 0.
71         nms_iou_thr (float|optional): nms IoU threshold, the detection results
72             have done nms in the detector, only applied when users want to
73             change the nms IoU threshold. Default: None.
74         tp_iou_thr (float|optional): IoU threshold to be considered as matched.
75             Default: 0.5.
76     """
77     num_classes = len(dataset.CLASSES)
78     confusion_matrix = np.zeros(shape=[num_classes + 1, num_classes + 1])
79     assert len(dataset) == len(results)
80     prog_bar = mmcv.ProgressBar(len(results))
81     for idx, per_img_res in enumerate(results):
82         if isinstance(per_img_res, tuple):
83             res_bboxes, _ = per_img_res
84         else:
85             res_bboxes = per_img_res
86         ann = dataset.get_ann_info(idx)
87         gt_bboxes = ann['bboxes']
88         labels = ann['labels']
89         analyze_per_img_dets(confusion_matrix, gt_bboxes, labels, res_bboxes,
90                              score_thr, tp_iou_thr, nms_iou_thr)
91         prog_bar.update()
92     return confusion_matrix
93 
94 
95 def analyze_per_img_dets(confusion_matrix,
96                          gt_bboxes,
97                          gt_labels,
98                          result,
99                          score_thr=0,
100                          tp_iou_thr=0.5,
101                          nms_iou_thr=None):
102     """Analyze detection results on each image.
103 
104     Args:
105         confusion_matrix (ndarray): The confusion matrix,
106             has shape (num_classes + 1, num_classes + 1).
107         gt_bboxes (ndarray): Ground truth bboxes, has shape (num_gt, 4).
108         gt_labels (ndarray): Ground truth labels, has shape (num_gt).
109         result (ndarray): Detection results, has shape
110             (num_classes, num_bboxes, 5).
111         score_thr (float): Score threshold to filter bboxes.
112             Default: 0.
113         tp_iou_thr (float): IoU threshold to be considered as matched.
114             Default: 0.5.
115         nms_iou_thr (float|optional): nms IoU threshold, the detection results
116             have done nms in the detector, only applied when users want to
117             change the nms IoU threshold. Default: None.
118     """
119     true_positives = np.zeros_like(gt_labels)
120     for det_label, det_bboxes in enumerate(result):
121         if nms_iou_thr:
122             det_bboxes, _ = nms(
123                 det_bboxes[:, :4],
124                 det_bboxes[:, -1],
125                 nms_iou_thr,
126                 score_threshold=score_thr)
127         ious = bbox_overlaps(det_bboxes[:, :4], gt_bboxes)
128         for i, det_bbox in enumerate(det_bboxes):
129             score = det_bbox[4]
130             det_match = 0
131             if score >= score_thr:
132                 for j, gt_label in enumerate(gt_labels):
133                     if ious[i, j] >= tp_iou_thr:
134                         det_match += 1
135                         if gt_label == det_label:
136                             true_positives[j] += 1  # TP
137                         confusion_matrix[gt_label, det_label] += 1
138                 if det_match == 0:  # BG FP
139                     confusion_matrix[-1, det_label] += 1
140     for num_tp, gt_label in zip(true_positives, gt_labels):
141         if num_tp == 0:  # FN
142             confusion_matrix[gt_label, -1] += 1
143 
144 
145 def plot_confusion_matrix(confusion_matrix,
146                           labels,
147                           save_dir=None,
148                           show=True,
149                           title='Normalized Confusion Matrix',
150                           color_theme='plasma'):
151     """Draw confusion matrix with matplotlib.
152 
153     Args:
154         confusion_matrix (ndarray): The confusion matrix.
155         labels (list[str]): List of class names.
156         save_dir (str|optional): If set, save the confusion matrix plot to the
157             given path. Default: None.
158         show (bool): Whether to show the plot. Default: True.
159         title (str): Title of the plot. Default: `Normalized Confusion Matrix`.
160         color_theme (str): Theme of the matrix color map. Default: `plasma`.
161     """
162     # normalize the confusion matrix
163     per_label_sums = confusion_matrix.sum(axis=1)[:, np.newaxis]
164     confusion_matrix = \
165         confusion_matrix.astype(np.float32) / per_label_sums * 100
166 
167     num_classes = len(labels)
168     fig, ax = plt.subplots(
169         figsize=(0.5 * num_classes, 0.5 * num_classes * 0.8), dpi=180)
170     cmap = plt.get_cmap(color_theme)
171     im = ax.imshow(confusion_matrix, cmap=cmap)
172     plt.colorbar(mappable=im, ax=ax)
173 
174     title_font = {'weight': 'bold', 'size': 12}
175     ax.set_title(title, fontdict=title_font)
176     label_font = {'size': 10}
177     plt.ylabel('Ground Truth Label', fontdict=label_font)
178     plt.xlabel('Prediction Label', fontdict=label_font)
179 
180     # draw locator
181     xmajor_locator = MultipleLocator(1)
182     xminor_locator = MultipleLocator(0.5)
183     ax.xaxis.set_major_locator(xmajor_locator)
184     ax.xaxis.set_minor_locator(xminor_locator)
185     ymajor_locator = MultipleLocator(1)
186     yminor_locator = MultipleLocator(0.5)
187     ax.yaxis.set_major_locator(ymajor_locator)
188     ax.yaxis.set_minor_locator(yminor_locator)
189 
190     # draw grid
191     ax.grid(True, which='minor', linestyle='-')
192 
193     # draw label
194     ax.set_xticks(np.arange(num_classes))
195     ax.set_yticks(np.arange(num_classes))
196     ax.set_xticklabels(labels)
197     ax.set_yticklabels(labels)
198 
199     ax.tick_params(
200         axis='x', bottom=False, top=True, labelbottom=False, labeltop=True)
201     plt.setp(
202         ax.get_xticklabels(), rotation=45, ha='left', rotation_mode='anchor')
203 
204     # draw confution matrix value
205     for i in range(num_classes):
206         for j in range(num_classes):
207             ax.text(
208                 j,
209                 i,
210                 '{}%'.format(int(confusion_matrix[i, j])),
211                 ha='center',
212                 va='center',
213                 color='w',
214                 size=7)
215 
216     ax.set_ylim(len(confusion_matrix) - 0.5, -0.5)  # matplotlib>3.1.1
217 
218     fig.tight_layout()
219     if save_dir is not None:
220         plt.savefig(
221             os.path.join(save_dir, 'confusion_matrix.png'), format='png')
222     if show:
223         plt.show()
224 
225 
226 def main():
227     args = parse_args()
228 
229     cfg = Config.fromfile(args.config)
230     if args.cfg_options is not None:
231         cfg.merge_from_dict(args.cfg_options)
232 
233     results = mmcv.load(args.prediction_path)
234     assert isinstance(results, list)
235     if isinstance(results[0], list):
236         pass
237     elif isinstance(results[0], tuple):
238         results = [result[0] for result in results]
239     else:
240         raise TypeError('invalid type of prediction results')
241 
242     if isinstance(cfg.data.test, dict):
243         cfg.data.test.test_mode = True
244     elif isinstance(cfg.data.test, list):
245         for ds_cfg in cfg.data.test:
246             ds_cfg.test_mode = True
247     dataset = build_dataset(cfg.data.test)
248 
249     confusion_matrix = calculate_confusion_matrix(dataset, results,
250                                                   args.score_thr,
251                                                   args.nms_iou_thr,
252                                                   args.tp_iou_thr)
253     plot_confusion_matrix(
254         confusion_matrix,
255         dataset.CLASSES + ('background', ),
256         save_dir=args.save_dir,
257         show=args.show)
258 
259 
260 if __name__ == '__main__':
261     main()
262
```
--- 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/analysis_tools/confusion_matrix.py b/tools/analysis_tools/confusion_matrix.py
--- a/tools/analysis_tools/confusion_matrix.py
+++ b/tools/analysis_tools/confusion_matrix.py
@@ -207,7 +207,10 @@
             ax.text(
                 j,
                 i,
-                '{}%'.format(int(confusion_matrix[i, j])),
+                '{}%'.format(
+                    int(confusion_matrix[
+                        i,
+                        j]) if not np.isnan(confusion_matrix[i, j]) else -1),
                 ha='center',
                 va='center',
                 color='w',

{"golden_diff": "diff --git a/tools/analysis_tools/confusion_matrix.py b/tools/analysis_tools/confusion_matrix.py\n--- a/tools/analysis_tools/confusion_matrix.py\n+++ b/tools/analysis_tools/confusion_matrix.py\n@@ -207,7 +207,10 @@\n             ax.text(\n                 j,\n                 i,\n-                '{}%'.format(int(confusion_matrix[i, j])),\n+                '{}%'.format(\n+                    int(confusion_matrix[\n+                        i,\n+                        j]) if not np.isnan(confusion_matrix[i, j]) else -1),\n                 ha='center',\n                 va='center',\n                 color='w',\n", "issue": "Confusion matrix error\nWhile trying to generate the confusion matrix with this command:\r\n```\r\npython tools/analysis_tools/confusion_matrix.py ./work_dirs/perception-types--D06-01-2022--T09-23-45/perception-types.py results.pkl ./temp  --show\r\n```\r\nI ran into this error:\r\n```\r\nTraceback (most recent call last):\r\n  File \"tools/analysis_tools/confusion_matrix.py\", line 261, in <module>\r\n    main()\r\n  File \"tools/analysis_tools/confusion_matrix.py\", line 257, in main\r\n    show=args.show)\r\n  File \"tools/analysis_tools/confusion_matrix.py\", line 210, in plot_confusion_matrix\r\n    '{}%'.format(int(confusion_matrix[i, j])),\r\nValueError: cannot convert float NaN to integer\r\n```\r\nWould appreciate any help or suggestions! Thanks\r\n\n", "before_files": [{"content": "import argparse\nimport os\n\nimport matplotlib.pyplot as plt\nimport mmcv\nimport numpy as np\nfrom matplotlib.ticker import MultipleLocator\nfrom mmcv import Config, DictAction\nfrom mmcv.ops import nms\n\nfrom mmdet.core.evaluation.bbox_overlaps import bbox_overlaps\nfrom mmdet.datasets import build_dataset\n\n\ndef parse_args():\n    parser = argparse.ArgumentParser(\n        description='Generate confusion matrix from detection results')\n    parser.add_argument('config', help='test config file path')\n    parser.add_argument(\n        'prediction_path', help='prediction path where test .pkl result')\n    parser.add_argument(\n        'save_dir', help='directory where confusion matrix will be saved')\n    parser.add_argument(\n        '--show', action='store_true', help='show confusion matrix')\n    parser.add_argument(\n        '--color-theme',\n        default='plasma',\n        help='theme of the matrix color map')\n    parser.add_argument(\n        '--score-thr',\n        type=float,\n        default=0.3,\n        help='score threshold to filter detection bboxes')\n    parser.add_argument(\n        '--tp-iou-thr',\n        type=float,\n        default=0.5,\n        help='IoU threshold to be considered as matched')\n    parser.add_argument(\n        '--nms-iou-thr',\n        type=float,\n        default=None,\n        help='nms IoU threshold, only applied when users want to change the'\n        'nms IoU threshold.')\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    args = parser.parse_args()\n    return args\n\n\ndef calculate_confusion_matrix(dataset,\n                               results,\n                               score_thr=0,\n                               nms_iou_thr=None,\n                               tp_iou_thr=0.5):\n    \"\"\"Calculate the confusion matrix.\n\n    Args:\n        dataset (Dataset): Test or val dataset.\n        results (list[ndarray]): A list of detection results in each image.\n        score_thr (float|optional): Score threshold to filter bboxes.\n            Default: 0.\n        nms_iou_thr (float|optional): nms IoU threshold, the detection results\n            have done nms in the detector, only applied when users want to\n            change the nms IoU threshold. Default: None.\n        tp_iou_thr (float|optional): IoU threshold to be considered as matched.\n            Default: 0.5.\n    \"\"\"\n    num_classes = len(dataset.CLASSES)\n    confusion_matrix = np.zeros(shape=[num_classes + 1, num_classes + 1])\n    assert len(dataset) == len(results)\n    prog_bar = mmcv.ProgressBar(len(results))\n    for idx, per_img_res in enumerate(results):\n        if isinstance(per_img_res, tuple):\n            res_bboxes, _ = per_img_res\n        else:\n            res_bboxes = per_img_res\n        ann = dataset.get_ann_info(idx)\n        gt_bboxes = ann['bboxes']\n        labels = ann['labels']\n        analyze_per_img_dets(confusion_matrix, gt_bboxes, labels, res_bboxes,\n                             score_thr, tp_iou_thr, nms_iou_thr)\n        prog_bar.update()\n    return confusion_matrix\n\n\ndef analyze_per_img_dets(confusion_matrix,\n                         gt_bboxes,\n                         gt_labels,\n                         result,\n                         score_thr=0,\n                         tp_iou_thr=0.5,\n                         nms_iou_thr=None):\n    \"\"\"Analyze detection results on each image.\n\n    Args:\n        confusion_matrix (ndarray): The confusion matrix,\n            has shape (num_classes + 1, num_classes + 1).\n        gt_bboxes (ndarray): Ground truth bboxes, has shape (num_gt, 4).\n        gt_labels (ndarray): Ground truth labels, has shape (num_gt).\n        result (ndarray): Detection results, has shape\n            (num_classes, num_bboxes, 5).\n        score_thr (float): Score threshold to filter bboxes.\n            Default: 0.\n        tp_iou_thr (float): IoU threshold to be considered as matched.\n            Default: 0.5.\n        nms_iou_thr (float|optional): nms IoU threshold, the detection results\n            have done nms in the detector, only applied when users want to\n            change the nms IoU threshold. Default: None.\n    \"\"\"\n    true_positives = np.zeros_like(gt_labels)\n    for det_label, det_bboxes in enumerate(result):\n        if nms_iou_thr:\n            det_bboxes, _ = nms(\n                det_bboxes[:, :4],\n                det_bboxes[:, -1],\n                nms_iou_thr,\n                score_threshold=score_thr)\n        ious = bbox_overlaps(det_bboxes[:, :4], gt_bboxes)\n        for i, det_bbox in enumerate(det_bboxes):\n            score = det_bbox[4]\n            det_match = 0\n            if score >= score_thr:\n                for j, gt_label in enumerate(gt_labels):\n                    if ious[i, j] >= tp_iou_thr:\n                        det_match += 1\n                        if gt_label == det_label:\n                            true_positives[j] += 1  # TP\n                        confusion_matrix[gt_label, det_label] += 1\n                if det_match == 0:  # BG FP\n                    confusion_matrix[-1, det_label] += 1\n    for num_tp, gt_label in zip(true_positives, gt_labels):\n        if num_tp == 0:  # FN\n            confusion_matrix[gt_label, -1] += 1\n\n\ndef plot_confusion_matrix(confusion_matrix,\n                          labels,\n                          save_dir=None,\n                          show=True,\n                          title='Normalized Confusion Matrix',\n                          color_theme='plasma'):\n    \"\"\"Draw confusion matrix with matplotlib.\n\n    Args:\n        confusion_matrix (ndarray): The confusion matrix.\n        labels (list[str]): List of class names.\n        save_dir (str|optional): If set, save the confusion matrix plot to the\n            given path. Default: None.\n        show (bool): Whether to show the plot. Default: True.\n        title (str): Title of the plot. Default: `Normalized Confusion Matrix`.\n        color_theme (str): Theme of the matrix color map. Default: `plasma`.\n    \"\"\"\n    # normalize the confusion matrix\n    per_label_sums = confusion_matrix.sum(axis=1)[:, np.newaxis]\n    confusion_matrix = \\\n        confusion_matrix.astype(np.float32) / per_label_sums * 100\n\n    num_classes = len(labels)\n    fig, ax = plt.subplots(\n        figsize=(0.5 * num_classes, 0.5 * num_classes * 0.8), dpi=180)\n    cmap = plt.get_cmap(color_theme)\n    im = ax.imshow(confusion_matrix, cmap=cmap)\n    plt.colorbar(mappable=im, ax=ax)\n\n    title_font = {'weight': 'bold', 'size': 12}\n    ax.set_title(title, fontdict=title_font)\n    label_font = {'size': 10}\n    plt.ylabel('Ground Truth Label', fontdict=label_font)\n    plt.xlabel('Prediction Label', fontdict=label_font)\n\n    # draw locator\n    xmajor_locator = MultipleLocator(1)\n    xminor_locator = MultipleLocator(0.5)\n    ax.xaxis.set_major_locator(xmajor_locator)\n    ax.xaxis.set_minor_locator(xminor_locator)\n    ymajor_locator = MultipleLocator(1)\n    yminor_locator = MultipleLocator(0.5)\n    ax.yaxis.set_major_locator(ymajor_locator)\n    ax.yaxis.set_minor_locator(yminor_locator)\n\n    # draw grid\n    ax.grid(True, which='minor', linestyle='-')\n\n    # draw label\n    ax.set_xticks(np.arange(num_classes))\n    ax.set_yticks(np.arange(num_classes))\n    ax.set_xticklabels(labels)\n    ax.set_yticklabels(labels)\n\n    ax.tick_params(\n        axis='x', bottom=False, top=True, labelbottom=False, labeltop=True)\n    plt.setp(\n        ax.get_xticklabels(), rotation=45, ha='left', rotation_mode='anchor')\n\n    # draw confution matrix value\n    for i in range(num_classes):\n        for j in range(num_classes):\n            ax.text(\n                j,\n                i,\n                '{}%'.format(int(confusion_matrix[i, j])),\n                ha='center',\n                va='center',\n                color='w',\n                size=7)\n\n    ax.set_ylim(len(confusion_matrix) - 0.5, -0.5)  # matplotlib>3.1.1\n\n    fig.tight_layout()\n    if save_dir is not None:\n        plt.savefig(\n            os.path.join(save_dir, 'confusion_matrix.png'), format='png')\n    if show:\n        plt.show()\n\n\ndef main():\n    args = parse_args()\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    results = mmcv.load(args.prediction_path)\n    assert isinstance(results, list)\n    if isinstance(results[0], list):\n        pass\n    elif isinstance(results[0], tuple):\n        results = [result[0] for result in results]\n    else:\n        raise TypeError('invalid type of prediction results')\n\n    if isinstance(cfg.data.test, dict):\n        cfg.data.test.test_mode = True\n    elif isinstance(cfg.data.test, list):\n        for ds_cfg in cfg.data.test:\n            ds_cfg.test_mode = True\n    dataset = build_dataset(cfg.data.test)\n\n    confusion_matrix = calculate_confusion_matrix(dataset, results,\n                                                  args.score_thr,\n                                                  args.nms_iou_thr,\n                                                  args.tp_iou_thr)\n    plot_confusion_matrix(\n        confusion_matrix,\n        dataset.CLASSES + ('background', ),\n        save_dir=args.save_dir,\n        show=args.show)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "tools/analysis_tools/confusion_matrix.py"}], "after_files": [{"content": "import argparse\nimport os\n\nimport matplotlib.pyplot as plt\nimport mmcv\nimport numpy as np\nfrom matplotlib.ticker import MultipleLocator\nfrom mmcv import Config, DictAction\nfrom mmcv.ops import nms\n\nfrom mmdet.core.evaluation.bbox_overlaps import bbox_overlaps\nfrom mmdet.datasets import build_dataset\n\n\ndef parse_args():\n    parser = argparse.ArgumentParser(\n        description='Generate confusion matrix from detection results')\n    parser.add_argument('config', help='test config file path')\n    parser.add_argument(\n        'prediction_path', help='prediction path where test .pkl result')\n    parser.add_argument(\n        'save_dir', help='directory where confusion matrix will be saved')\n    parser.add_argument(\n        '--show', action='store_true', help='show confusion matrix')\n    parser.add_argument(\n        '--color-theme',\n        default='plasma',\n        help='theme of the matrix color map')\n    parser.add_argument(\n        '--score-thr',\n        type=float,\n        default=0.3,\n        help='score threshold to filter detection bboxes')\n    parser.add_argument(\n        '--tp-iou-thr',\n        type=float,\n        default=0.5,\n        help='IoU threshold to be considered as matched')\n    parser.add_argument(\n        '--nms-iou-thr',\n        type=float,\n        default=None,\n        help='nms IoU threshold, only applied when users want to change the'\n        'nms IoU threshold.')\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    args = parser.parse_args()\n    return args\n\n\ndef calculate_confusion_matrix(dataset,\n                               results,\n                               score_thr=0,\n                               nms_iou_thr=None,\n                               tp_iou_thr=0.5):\n    \"\"\"Calculate the confusion matrix.\n\n    Args:\n        dataset (Dataset): Test or val dataset.\n        results (list[ndarray]): A list of detection results in each image.\n        score_thr (float|optional): Score threshold to filter bboxes.\n            Default: 0.\n        nms_iou_thr (float|optional): nms IoU threshold, the detection results\n            have done nms in the detector, only applied when users want to\n            change the nms IoU threshold. Default: None.\n        tp_iou_thr (float|optional): IoU threshold to be considered as matched.\n            Default: 0.5.\n    \"\"\"\n    num_classes = len(dataset.CLASSES)\n    confusion_matrix = np.zeros(shape=[num_classes + 1, num_classes + 1])\n    assert len(dataset) == len(results)\n    prog_bar = mmcv.ProgressBar(len(results))\n    for idx, per_img_res in enumerate(results):\n        if isinstance(per_img_res, tuple):\n            res_bboxes, _ = per_img_res\n        else:\n            res_bboxes = per_img_res\n        ann = dataset.get_ann_info(idx)\n        gt_bboxes = ann['bboxes']\n        labels = ann['labels']\n        analyze_per_img_dets(confusion_matrix, gt_bboxes, labels, res_bboxes,\n                             score_thr, tp_iou_thr, nms_iou_thr)\n        prog_bar.update()\n    return confusion_matrix\n\n\ndef analyze_per_img_dets(confusion_matrix,\n                         gt_bboxes,\n                         gt_labels,\n                         result,\n                         score_thr=0,\n                         tp_iou_thr=0.5,\n                         nms_iou_thr=None):\n    \"\"\"Analyze detection results on each image.\n\n    Args:\n        confusion_matrix (ndarray): The confusion matrix,\n            has shape (num_classes + 1, num_classes + 1).\n        gt_bboxes (ndarray): Ground truth bboxes, has shape (num_gt, 4).\n        gt_labels (ndarray): Ground truth labels, has shape (num_gt).\n        result (ndarray): Detection results, has shape\n            (num_classes, num_bboxes, 5).\n        score_thr (float): Score threshold to filter bboxes.\n            Default: 0.\n        tp_iou_thr (float): IoU threshold to be considered as matched.\n            Default: 0.5.\n        nms_iou_thr (float|optional): nms IoU threshold, the detection results\n            have done nms in the detector, only applied when users want to\n            change the nms IoU threshold. Default: None.\n    \"\"\"\n    true_positives = np.zeros_like(gt_labels)\n    for det_label, det_bboxes in enumerate(result):\n        if nms_iou_thr:\n            det_bboxes, _ = nms(\n                det_bboxes[:, :4],\n                det_bboxes[:, -1],\n                nms_iou_thr,\n                score_threshold=score_thr)\n        ious = bbox_overlaps(det_bboxes[:, :4], gt_bboxes)\n        for i, det_bbox in enumerate(det_bboxes):\n            score = det_bbox[4]\n            det_match = 0\n            if score >= score_thr:\n                for j, gt_label in enumerate(gt_labels):\n                    if ious[i, j] >= tp_iou_thr:\n                        det_match += 1\n                        if gt_label == det_label:\n                            true_positives[j] += 1  # TP\n                        confusion_matrix[gt_label, det_label] += 1\n                if det_match == 0:  # BG FP\n                    confusion_matrix[-1, det_label] += 1\n    for num_tp, gt_label in zip(true_positives, gt_labels):\n        if num_tp == 0:  # FN\n            confusion_matrix[gt_label, -1] += 1\n\n\ndef plot_confusion_matrix(confusion_matrix,\n                          labels,\n                          save_dir=None,\n                          show=True,\n                          title='Normalized Confusion Matrix',\n                          color_theme='plasma'):\n    \"\"\"Draw confusion matrix with matplotlib.\n\n    Args:\n        confusion_matrix (ndarray): The confusion matrix.\n        labels (list[str]): List of class names.\n        save_dir (str|optional): If set, save the confusion matrix plot to the\n            given path. Default: None.\n        show (bool): Whether to show the plot. Default: True.\n        title (str): Title of the plot. Default: `Normalized Confusion Matrix`.\n        color_theme (str): Theme of the matrix color map. Default: `plasma`.\n    \"\"\"\n    # normalize the confusion matrix\n    per_label_sums = confusion_matrix.sum(axis=1)[:, np.newaxis]\n    confusion_matrix = \\\n        confusion_matrix.astype(np.float32) / per_label_sums * 100\n\n    num_classes = len(labels)\n    fig, ax = plt.subplots(\n        figsize=(0.5 * num_classes, 0.5 * num_classes * 0.8), dpi=180)\n    cmap = plt.get_cmap(color_theme)\n    im = ax.imshow(confusion_matrix, cmap=cmap)\n    plt.colorbar(mappable=im, ax=ax)\n\n    title_font = {'weight': 'bold', 'size': 12}\n    ax.set_title(title, fontdict=title_font)\n    label_font = {'size': 10}\n    plt.ylabel('Ground Truth Label', fontdict=label_font)\n    plt.xlabel('Prediction Label', fontdict=label_font)\n\n    # draw locator\n    xmajor_locator = MultipleLocator(1)\n    xminor_locator = MultipleLocator(0.5)\n    ax.xaxis.set_major_locator(xmajor_locator)\n    ax.xaxis.set_minor_locator(xminor_locator)\n    ymajor_locator = MultipleLocator(1)\n    yminor_locator = MultipleLocator(0.5)\n    ax.yaxis.set_major_locator(ymajor_locator)\n    ax.yaxis.set_minor_locator(yminor_locator)\n\n    # draw grid\n    ax.grid(True, which='minor', linestyle='-')\n\n    # draw label\n    ax.set_xticks(np.arange(num_classes))\n    ax.set_yticks(np.arange(num_classes))\n    ax.set_xticklabels(labels)\n    ax.set_yticklabels(labels)\n\n    ax.tick_params(\n        axis='x', bottom=False, top=True, labelbottom=False, labeltop=True)\n    plt.setp(\n        ax.get_xticklabels(), rotation=45, ha='left', rotation_mode='anchor')\n\n    # draw confution matrix value\n    for i in range(num_classes):\n        for j in range(num_classes):\n            ax.text(\n                j,\n                i,\n                '{}%'.format(\n                    int(confusion_matrix[\n                        i,\n                        j]) if not np.isnan(confusion_matrix[i, j]) else -1),\n                ha='center',\n                va='center',\n                color='w',\n                size=7)\n\n    ax.set_ylim(len(confusion_matrix) - 0.5, -0.5)  # matplotlib>3.1.1\n\n    fig.tight_layout()\n    if save_dir is not None:\n        plt.savefig(\n            os.path.join(save_dir, 'confusion_matrix.png'), format='png')\n    if show:\n        plt.show()\n\n\ndef main():\n    args = parse_args()\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    results = mmcv.load(args.prediction_path)\n    assert isinstance(results, list)\n    if isinstance(results[0], list):\n        pass\n    elif isinstance(results[0], tuple):\n        results = [result[0] for result in results]\n    else:\n        raise TypeError('invalid type of prediction results')\n\n    if isinstance(cfg.data.test, dict):\n        cfg.data.test.test_mode = True\n    elif isinstance(cfg.data.test, list):\n        for ds_cfg in cfg.data.test:\n            ds_cfg.test_mode = True\n    dataset = build_dataset(cfg.data.test)\n\n    confusion_matrix = calculate_confusion_matrix(dataset, results,\n                                                  args.score_thr,\n                                                  args.nms_iou_thr,\n                                                  args.tp_iou_thr)\n    plot_confusion_matrix(\n        confusion_matrix,\n        dataset.CLASSES + ('background', ),\n        save_dir=args.save_dir,\n        show=args.show)\n\n\nif __name__ == '__main__':\n    main()\n", "path": "tools/analysis_tools/confusion_matrix.py"}]}