-
Notifications
You must be signed in to change notification settings - Fork 302
Change eval_semantic_segmentation #217
Changes from 13 commits
3474058
8b92dc8
7430dab
ec2ac61
5f7a47f
9ce7523
e45a60b
babf7c9
ee4bd80
569e66f
f6c9288
35d6efb
41198b3
5db4c7e
916d298
c4ec9ec
e82eede
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
from chainercv.evaluations.eval_detection_voc import eval_detection_voc # NOQA | ||
from chainercv.evaluations.eval_pck import eval_pck # NOQA | ||
from chainercv.evaluations.eval_semantic_segmentation import eval_semantic_segmentation # NOQA | ||
from chainercv.evaluations.eval_semantic_segmentation_iou import calc_semantic_segmentation_confusion # NOQA | ||
from chainercv.evaluations.eval_semantic_segmentation_iou import calc_semantic_segmentation_iou # NOQA | ||
from chainercv.evaluations.eval_semantic_segmentation_iou import eval_semantic_segmentation_iou # NOQA |
This file was deleted.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
from __future__ import division | ||
|
||
import numpy as np | ||
import six | ||
|
||
|
||
def calc_semantic_segmentation_confusion(pred_labels, gt_labels): | ||
"""Collect a confusion matrix. | ||
|
||
The number of classes :math:`n\_class` is computed as the maximum | ||
class id among :obj:`pred_labels` and :obj:`gt_labels`. | ||
|
||
Args: | ||
pred_labels (iterable of numpy.ndarray): A collection of predicted | ||
labels. The shape of a label array | ||
is :math:`(H, W)`. :math:`H` and :math:`W` | ||
are height and width of the label. | ||
gt_labels (iterable of numpy.ndarray): A collection of ground | ||
truth label. The shape of a ground truth label array is | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
:math:`(H, W)`. The corresponding prediction label should | ||
have the same shape. | ||
A pixel with value :obj:`-1` will be ignored during evaluation. | ||
|
||
Returns: | ||
numpy.ndarray: | ||
A confusion matrix. Its shape is :math:`(n\_class, n\_class)`. | ||
The :math:`(i, j)` th element corresponds to the number of pixels | ||
that are labeled as class :math:`i` by the ground truth and | ||
class :math:`j` by the prediction. | ||
|
||
""" | ||
pred_labels = iter(pred_labels) | ||
gt_labels = iter(gt_labels) | ||
|
||
n_class = 0 | ||
confusion = np.zeros((n_class, n_class), dtype=np.int64) | ||
for pred_label, gt_label in six.moves.zip(pred_labels, gt_labels): | ||
if pred_label.ndim != 2 or gt_label.ndim != 2: | ||
raise ValueError('ndim of inputs should be two.') | ||
if pred_label.shape != gt_label.shape: | ||
raise ValueError('Shapes of inputs should be same.') | ||
pred_label = pred_label.flatten() | ||
gt_label = gt_label.flatten() | ||
|
||
# Dynamically expand the confusion matrix if necessary. | ||
lb_max = np.max((pred_label, gt_label)) | ||
if lb_max >= n_class: | ||
expanded_confusion = np.zeros | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is this line? |
||
expanded_confusion = np.zeros((lb_max + 1, lb_max + 1)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps it is better to use |
||
expanded_confusion[0:n_class, 0:n_class] = confusion | ||
|
||
n_class = lb_max + 1 | ||
confusion = expanded_confusion | ||
|
||
# Count statistics from valid pixels. | ||
mask = (gt_label >= 0) & (gt_label < n_class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
confusion += np.bincount( | ||
n_class * gt_label[mask].astype(int) + | ||
pred_label[mask], minlength=n_class**2).reshape(n_class, n_class) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we can expand the confusion matrix dynamically.
This expansion may affect performance. But I think it will be ignorable because neural networks are much slower. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That code seems simple enough. I will try it. |
||
|
||
for iter_ in (pred_labels, gt_labels): | ||
# This code assumes any iterator does not contain None as its items. | ||
if next(iter_, None) is not None: | ||
raise ValueError('Length of input iterables need to be same') | ||
return confusion | ||
|
||
|
||
def calc_semantic_segmentation_iou(confusion): | ||
"""Calculate Intersection over Union with a given confusion matrix. | ||
|
||
The definition of Intersection over Union (IoU) is as follows, | ||
where :math:`N_{ij}` is the number of pixels | ||
that are labeled as class :math:`i` by the ground truth and | ||
class :math:`j` by the prediction. | ||
|
||
* :math:`\\text{IoU of the i-th class} = \ | ||
\\frac{N_{ii}}{\\sum_{j=1}^k N_{ij} + \\sum_{j=1}^k N_{ji} - N_{ii}}` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Perhaps, we need denote the definition of |
||
|
||
Args: | ||
confusion (numpy.ndarray): A confusion matrix. Its shape is | ||
:math:`(n\_class, n\_class)`. | ||
The :math:`(i, j)` th element corresponds to the number of pixels | ||
that are labeled as class :math:`i` by the ground truth and | ||
class :math:`j` by the prediction. | ||
|
||
Returns: | ||
numpy.ndarray: | ||
An array of IoUs for the :math:`n\_class` classes. Its shape is | ||
:math:`(n\_class,)`. | ||
|
||
""" | ||
iou_denominator = (confusion.sum(axis=1) + confusion.sum(axis=0) | ||
- np.diag(confusion)) | ||
iou = np.diag(confusion) / iou_denominator | ||
return iou | ||
|
||
|
||
def eval_semantic_segmentation_iou(pred_labels, gt_labels): | ||
"""Evaluate Intersection over Union from labels. | ||
|
||
This function calculates Intersection over Union (IoU) | ||
for the task of semantic segmentation. | ||
|
||
The definition of IoU and a related metric, mean Intersection | ||
over Union (mIoU), are as follow, | ||
where :math:`N_{ij}` is the number of pixels | ||
that are labeled as class :math:`i` by the ground truth and | ||
class :math:`j` by the prediction. | ||
|
||
* :math:`\\text{IoU of the i-th class} = \ | ||
\\frac{N_{ii}}{\\sum_{j=1}^k N_{ij} + \\sum_{j=1}^k N_{ji} - N_{ii}}` | ||
* :math:`\\text{mIoU} = \\frac{1}{k} \ | ||
\\sum_{i=1}^k \ | ||
\\frac{N_{ii}}{\\sum_{j=1}^k N_{ij} + \\sum_{j=1}^k N_{ji} - N_{ii}}` | ||
|
||
mIoU can be computed by taking :obj:`numpy.nanmean` of the IoUs returned | ||
by this function. | ||
The more detailed descriptions of the above metric can be found in a | ||
review on semantic segmentation [#]_. | ||
|
||
The number of classes :math:`n\_class` is computed as the maximum | ||
class id among :obj:`pred_labels` and :obj:`gt_labels`. | ||
|
||
.. [#] Alberto Garcia-Garcia, Sergio Orts-Escolano, Sergiu Oprea, \ | ||
Victor Villena-Martinez, Jose Garcia-Rodriguez. \ | ||
`A Review on Deep Learning Techniques Applied to Semantic Segmentation \ | ||
<https://arxiv.org/abs/1704.06857>`_. arXiv 2017. | ||
|
||
Args: | ||
pred_labels (iterable of numpy.ndarray): A collection of predicted | ||
labels. The shape of a label array | ||
is :math:`(H, W)`. :math:`H` and :math:`W` | ||
are height and width of the label. | ||
For example, this is a list of labels | ||
:obj:`[label_0, label_1, ...]`, where | ||
:obj:`label_i.shape = (H_i, W_i)`. | ||
gt_labels (iterable of numpy.ndarray): A collection of ground | ||
truth labels. The shape of a ground truth label array is | ||
:math:`(H, W)`. The corresponding prediction label should | ||
have the same shape. | ||
A pixel with value :obj:`-1` will be ignored during evaluation. | ||
|
||
Returns: | ||
numpy.ndarray: | ||
An array of IoUs for the :math:`n\_class` classes. Its shape is | ||
:math:`(n\_class,)`. | ||
|
||
""" | ||
# Evaluation code is based on | ||
# https://github.com/shelhamer/fcn.berkeleyvision.org/blob/master/ | ||
# score.py#L37 | ||
confusion = calc_semantic_segmentation_confusion( | ||
pred_labels, gt_labels) | ||
iou = calc_semantic_segmentation_iou(confusion) | ||
return iou |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,15 @@ eval_pck | |
~~~~~~~~ | ||
.. autofunction:: eval_pck | ||
|
||
eval_semantic_segmentation | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
.. autofunction:: eval_semantic_segmentation | ||
|
||
eval_semantic_segmentation_iou | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
.. autofunction:: eval_semantic_segmentation_iou | ||
|
||
calc_semantic_segmentation_confusion | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not an alphabetical order. I guess you put these functions here because they are helper functions of |
||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
.. autofunction:: calc_semantic_segmentation_confusion | ||
|
||
calc_semantic_segmentation_iou | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
.. autofunction:: calc_semantic_segmentation_iou |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds
n_class = max(pred_labels, gt_labels)
.as
->from
? Perhaps, an equation liken_class = max(pred_labels, gt_labels) + 1
will be helpful.