guochengqian / PointNeXt

[NeurIPS'22] PointNeXt: Revisiting PointNet++ with Improved Training and Scaling Strategies
https://guochengqian.github.io/PointNeXt/
MIT License
770 stars 111 forks source link

Using ignore_index in ConfusionMatrix return 0 IoU in Train and 100 IoU in Validation #138

Closed hpc100 closed 6 months ago

hpc100 commented 11 months ago

For some dataset, we have to use ignore_index parameter in ConfusionMatrix and Loss. In function train_one_epoch :

It seems that, in TRAIN mode IoU for ignore label is 0 and IoU in VAL mode is equal to 100, introducing a gap between TRAIN mIoU and VAL mIoU.

Example for S3DIS (if we introduce ignore_index = 0), we get this IoU :

Example for Semantic3D ( in this dataset ignore_index is set to 0) :

SimonBuusJensen commented 8 months ago

@hpc100 Did you find a solution for this? I am also currently looking into excluding the ignored class in the loss- and metric calculations. I might give an update, when I've looked into it.

Update:

I have the following 4 classe in my custom dataset: ['background', 'utility_pipes', 'main_pipe', 'ignore']

In order to make PointNeXt not include the ignore class (which has index 3 in my GT labels), I do the following two things:

  1. Modify the init method of ConfusionMatrix class (openpoints/utils/metrics.py): Original:

    def __init__(self, num_classes, ignore_index=None):
          self.value = 0
          self.num_classes = num_classes
          self.virtual_num_classes = num_classes + 1 if ignore_index is not None else num_classes
          self.ignore_index = ignore_index

    Change to:

    def __init__(self, num_classes, ignore_index=None):
          self.value = 0
          self.num_classes = num_classes - 1 if ignore_index is not None else num_classes
          self.virtual_num_classes = num_classes
          self.ignore_index = ignore_index
  2. Add an ignore_index attribute to default.yaml in the cfg file of my dataset (e.g. cfgs/[datasetname]/default.yaml):

    criterion_args:
    NAME: CrossEntropy
    label_smoothing: 0.2
    ignore_index: 3  # <---- Add id of the class that should be ignored
WeixiaoGao commented 6 months ago

Thank you both! I also updated the following code in "metrics.py" to avoid 100 mIoU on the validation dataset:

def get_mious(tp, union, count):
    # iou_per_cls = (tp + 1e-10) / (union + 1e-10) * 100
    # acc_per_cls = (tp + 1e-10) / (count + 1e-10) * 100

    iou_per_cls = torch.where(union + tp == 0, torch.tensor([0.0], device=tp.device), (tp + 1e-10) / (union + 1e-10)) * 100
    acc_per_cls = torch.where(count + tp == 0, torch.tensor([0.0], device=tp.device), (tp + 1e-10) / (count + 1e-10)) * 100
    over_all_acc = tp.sum() / count.sum() * 100

    miou = torch.mean(iou_per_cls)
    macc = torch.mean(acc_per_cls)  # class accuracy
    return miou.item(), macc.item(), over_all_acc.item(), iou_per_cls.cpu().numpy(), acc_per_cls.cpu().numpy()