Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Generating and plotting confusion matrix #1301

Merged
merged 5 commits into from
Mar 3, 2022

Conversation

HJoonKwon
Copy link
Contributor

@HJoonKwon HJoonKwon commented Feb 17, 2022

Thank you for the great repository. I've been inspired a lot by you guys!
Here is the PR that adds a python file to generate/plot a normalized confusion matrix (n_classes x n_classes). The most part of the file is from mmdetection repo., and I changed it a bit in a way to be able to work on segmentation tasks. I tested it on my local computer with some prediction results formatted in .pkl. The plot looks like this!
confusion_matrix

If you get interested, I will add UT for this feature!

Motivation

There was neither a function to generate n_classes x n_classes confusion matrix nor to draw it. (related Issue: #1203). I thought it's always better to visualize everything, so I decided to make it.

Modification

I referred to mmdetection repo. as mentioned above.
First of all, I changed this function below

def calculate_confusion_matrix(dataset, results):

Referring to

def get_confusion_matrix(pred_label, label, num_classes, ignore_index):

in test_metrics.py, I calculated the confusion matrix based on the dataset(defined in the configuration file) and the results(loaded from pkl file). Other irrelevant variables were removed here as well.

def calculate_confusion_matrix(dataset, results):
    """Calculate the confusion matrix.

    Args:
        dataset (Dataset): Test or val dataset.
        results (list[ndarray]): A list of segmentation results in each image.
    """
    n = len(dataset.CLASSES)
    confusion_matrix = np.zeros(shape=[n, n])
    assert len(dataset) == len(results)
    prog_bar = mmcv.ProgressBar(len(results))
    for idx, per_img_res in enumerate(results):
        res_segm = per_img_res
        gt_segm = dataset.get_gt_seg_map_by_idx(idx)
        inds = n * gt_segm + res_segm
        inds = inds.flatten()
        mat = np.bincount(inds, minlength=n**2).reshape(n, n)
        confusion_matrix += mat
        prog_bar.update()
    return confusion_matrix

And finally, I changed the default color theme of the figure because 'plasma' makes high values look too shiny. So maybe the default can be 'winter' instead.

parser.add_argument(
        '--color-theme',
        default='winter',
        help='theme of the matrix color map')

Furthermore, I can add ignore_index thing as well, which isn't included here yet.

The confusion matrix figure would be saved then to save_dir which is given from the input arguments. This python file requires a prediction result file in .pkl format as it does in mmdetection repository.

BC-breaking (Optional)

No.

Use cases (Optional)

If this PR introduces a new feature, it is better to list some use cases here, and update the documentation.

Checklist

  • Pre-commit or other linting tools are used to fix the potential lint issues.
  • The modification is covered by complete unit tests. If not, please add more unit tests to ensure correctness.
  • The documentation has been modified accordingly, like docstring or example tutorials.

@MengzhangLI
Copy link
Contributor

Hi, thanks for your contribution!

We would review it asap.

@Junjun2016
Copy link
Collaborator

Hi @HJoonKwon
Nice feature, can add its usage to the doc.

@Junjun2016
Copy link
Collaborator

Also, add some examples with mmseg.

@HJoonKwon
Copy link
Contributor Author

@Junjun2016 Thank you! Should I add its usage and some examples to docs/en/useful_tools.md?

description='Generate confusion matrix from segmentation results')
parser.add_argument('config', help='test config file path')
parser.add_argument(
'prediction_path', help='prediction path where test .pkl result')
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently we do not generate .pkl result like MMDetection, neither do prediction result. ;(

Copy link
Contributor Author

@HJoonKwon HJoonKwon Feb 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh. I thought test.py generates either prediction result or eval result depending on args.eval argument. If .pkl format doesn't work, then I can make confusion_matrix.py take the numpy type of prediction result just from

        results = multi_gpu_test(
            model,
            data_loader,
            args.tmpdir,
            args.gpu_collect,
            False,
            pre_eval=args.eval is not None and not eval_on_format_results,
            format_only=args.format_only or eval_on_format_results,
            format_args=eval_kwargs)

instead and it would work the same.

Copy link
Contributor

@MengzhangLI MengzhangLI Feb 22, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, let me try to test whether .pkl could work, actually I never used pickle format before.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure! The result(numpy array) can be stored in any kind of format tho :)

@MengzhangLI MengzhangLI self-assigned this Feb 23, 2022
Comment on lines 385 to 386
### 1.Generate a prediction result in pkl format using `test.py`
```shell
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need a blank line

Suggested change
### 1.Generate a prediction result in pkl format using `test.py`
```shell
### 1.Generate a prediction result in pkl format using `test.py`
```shell

MD022/blanks-around-headings/blanks-around-headers: Headings should be surrounded by blank lines

```shell
python tools/test.py ${CONFIG_FILE} ${CHECKPOINT_FILE} [--out ${PATH_TO_RESULT_FILE}]
```
Note that the argument for ```--eval``` should be ```None``` so that the result file contains numpy type of prediction results. The usage for distribution test is just the same.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Note that the argument for ```--eval``` should be ```None``` so that the result file contains numpy type of prediction results. The usage for distribution test is just the same.
Note that the argument for ```--eval``` should be ```None``` so that the result file contains numpy type of prediction results. The usage for distribution test is just the same.

Need a blank line
MD031/blanks-around-fences: Fenced code blocks should be surrounded by blank lines

Comment on lines 391 to 392
Example:
```shell
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Example:
```shell
Example:
```shell

Comment on lines 399 to 400
### 2. Use ```confusion_matrix.py``` to generate and plot a confusion matrix
```shell
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### 2. Use ```confusion_matrix.py``` to generate and plot a confusion matrix
```shell
### 2. Use ```confusion_matrix.py``` to generate and plot a confusion matrix
```shell

python tools/test.py \
configs/fcn/fcn_r50-d8_512x1024_40k_cityscapes.py \
checkpoint/fcn_r50-d8_512x1024_40k_cityscapes_20200604_192608-efe53f0d.pth \
--out result/pred_result.pkl \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
--out result/pred_result.pkl \
--out result/pred_result.pkl

return args


def calculate_confusion_matrix(dataset, results):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a little concern that memory might be overloaded when loading all predicted results of a dataset

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would probably be predicted results from the test set that may be not that big(depending on applications tho). Do you have any suggestions? :)

Comment on lines 413 to 414
Example:
```shell
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Example:
```shell
Example:
```shell

if args.cfg_options is not None:
cfg.merge_from_dict(args.cfg_options)

results = mmcv.load(args.prediction_path)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From our experience, loading the result for a whole dataset always got stuck in segmentation task

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I add some lines to check memory allocated to the results and give a warning to users to reduce the size of the test set used for test.py? Or do you have any suggenstions? :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might we merge this pr and then fix bugs of load and dump seg predicted results? @Junjun2016

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did pull-rebase based on the most recent commit of master branch in case :)

Copy link
Collaborator

@MeowZheng MeowZheng Mar 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might fix format problem in docs/en/useful_tools.md, and we will merge this pr

@MeowZheng MeowZheng merged commit 369a2ee into open-mmlab:master Mar 3, 2022
@dirtycomputer
Copy link

python tools/confusion_matrix.py work_dirs/upernet_swin_tiny_patch4_window7_512x512_160k_CVC/upernet_swin_tiny_patch4_window7_512x512_160k_CVC.py work_dirs/upernet_swin_tiny_patch4_window7_512x512_160k_CVC/result.pkl work_dirs/upernet_swin_tiny_patch4_window7_512x512_160k_CVC/
Traceback (most recent call last):
File "tools/confusion_matrix.py", line 184, in
main()
File "tools/confusion_matrix.py", line 164, in main
raise TypeError('invalid type of prediction results')
TypeError: invalid type of prediction results

@HJoonKwon
Copy link
Contributor Author

@dirtycomputer Did you turn off the Eval argument when you created .pkl result? The result should be prediction results, not the evaluation metrics.

@dirtycomputer
Copy link

THANKS IT WORKS

@TWang1017
Copy link

tools/confusion_matrix.py does not work when reduce_zero_label=True, the class number in the prediction does not match that in the labels

ZhimingNJ pushed a commit to AetrexTechnology/mmsegmentation that referenced this pull request Jun 29, 2022
* generate and plot confusion matrix

* fix typo

* add usage and examples for confusion matrix

* deal with nan values(pick pr#7147 mmdet)

* fix md format
@mgsdqs
Copy link

mgsdqs commented Aug 12, 2022

tools/confusion_matrix.py在 reduce_zero_label=True 时不起作用,预测中的类号与标签中的类号不匹配

I want to know how to solve this problem ?

@shenxiangkei
Copy link

May I ask you how to removed the Eval parameter? Thanks

@HJoonKwon
Copy link
Contributor Author

May I ask you how to removed the Eval parameter? Thanks

Use --out argument instead of --eval. You can refer to here

@shenxiangkei
Copy link

shenxiangkei commented Apr 16, 2023 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants