File size: 4,328 Bytes
bdec3d7 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
# --------------------------------------------------------
# X-Decoder -- Generalized Decoding for Pixel, Image, and Language
# Copyright (c) 2022 Microsoft
# Licensed under The MIT License [see LICENSE for details]
# Modified by Xueyan Zou ([email protected])
# --------------------------------------------------------
import logging
import torch
from torchvision.ops import box_iou
from detectron2.structures import BoxMode
from detectron2.data import MetadataCatalog
from detectron2.utils.comm import all_gather, is_main_process, synchronize
from detectron2.evaluation.evaluator import DatasetEvaluator
class GroundingEvaluator(DatasetEvaluator):
"""
Evaluate grounding segmentation metrics.
"""
def __init__(
self,
dataset_name,
compute_box=False,
distributed=True,
):
self._logger = logging.getLogger(__name__)
self._dataset_name = dataset_name
self._distributed = distributed
self._cpu_device = torch.device("cpu")
self._compute_box = compute_box
meta = MetadataCatalog.get(dataset_name)
def reset(self):
self.cum_I = 0
self.cum_U = 0
self.mIoU = 0
self.eval_seg_iou_list = [.5, .6, .7, .8, .9]
self.seg_correct = torch.zeros(len(self.eval_seg_iou_list), device=self._cpu_device)
self.seg_total = 0
if self._compute_box:
self.mIoU_box = 0
self.seg_correct_box = torch.zeros(len(self.eval_seg_iou_list), device=self._cpu_device)
@staticmethod
def computeIoU(pred_seg, gd_seg):
I = (pred_seg & gd_seg)
U = (pred_seg | gd_seg)
return I, U
def process(self, inputs, outputs):
for input, output in zip(inputs, outputs):
pred = output['grounding_mask'].sigmoid() > 0.5
gt = input['groundings']['masks'].bool()
bsi = len(pred)
I, U = self.computeIoU(pred, gt)
self.cum_I += I.sum().cpu()
self.cum_U += U.sum().cpu()
IoU = I.reshape(bsi,-1).sum(-1)*1.0 / (U.reshape(bsi,-1).sum(-1) + 1e-6)
self.mIoU += IoU.sum().cpu()
if self._compute_box:
pred_box = BoxMode.convert(output['grounding_box'], BoxMode.XYWH_ABS, BoxMode.XYXY_ABS)
gt_box = BoxMode.convert(input['groundings']['boxes'], BoxMode.XYWH_ABS, BoxMode.XYXY_ABS).cpu()
IoU_box = box_iou(pred_box, gt_box).diagonal()
self.mIoU_box += IoU_box.sum()
for idx in range(len(self.eval_seg_iou_list)):
eval_seg_iou = self.eval_seg_iou_list[idx]
self.seg_correct[idx] += (IoU >= eval_seg_iou).sum().cpu()
if self._compute_box:
self.seg_correct_box[idx] += (IoU_box >= eval_seg_iou).sum().cpu()
self.seg_total += bsi
def evaluate(self):
if self._distributed:
synchronize()
self.cum_I = torch.stack(all_gather(self.cum_I)).sum()
self.cum_U = torch.stack(all_gather(self.cum_U)).sum()
self.mIoU = torch.stack(all_gather(self.mIoU)).sum()
self.seg_correct = torch.stack(all_gather(self.seg_correct)).sum(0)
self.seg_total = sum(all_gather(self.seg_total))
if self._compute_box:
self.mIoU_box = torch.stack(all_gather(self.mIoU_box)).sum()
self.seg_correct_box = torch.stack(all_gather(self.seg_correct_box)).sum(0)
if not is_main_process():
return
results = {}
for idx in range(len(self.eval_seg_iou_list)):
result_str = 'precision@{}'.format(self.eval_seg_iou_list[idx])
results[result_str] = (self.seg_correct[idx]*100 / self.seg_total).item()
results['cIoU'] = (self.cum_I*100./self.cum_U).item()
results['mIoU'] = (self.mIoU*100./self.seg_total).item()
if self._compute_box:
for idx in range(len(self.eval_seg_iou_list)):
result_str = 'precisionB@{}'.format(self.eval_seg_iou_list[idx])
results[result_str] = (self.seg_correct_box[idx]*100 / self.seg_total).item()
results['mBIoU'] = (self.mIoU_box*100./self.seg_total).item()
self._logger.info(results)
return {'grounding': results} |