Repository: mlcommons/GaNDLF

Issue:
Hausdorff calculation is problematic
**Describe the bug**
Calculating `hausdorff` is giving problems for 2D images

**To Reproduce**
Steps to reproduce the behavior:
1. run `test_metrics_segmentation_rad_2d` from tests
2. See error

**Expected behavior**
It should work.

**Screenshots**
N.A.

**GaNDLF Version**
0.0.11-dev

**Desktop (please complete the following information):**
N.A.

**Additional context**
N.A.



Discussion:

Resolving patch:
diff --git a/GANDLF/metrics.py b/GANDLF/metrics.py
--- a/GANDLF/metrics.py
+++ b/GANDLF/metrics.py
@@ -82,7 +82,7 @@ def multi_class_dice(output, label, params):
     # print("Number of classes : ", params["model"]["num_classes"])
     for i in range(0, num_class):  # 0 is background
         # this check should only happen during validation
-        if num_class != params["model"]["ignore_label_validation"]:
+        if i != params["model"]["ignore_label_validation"]:
             total_dice += dice(output[:, i, ...], label[:, i, ...])
         # currentDiceLoss = 1 - currentDice # subtract from 1 because this is a loss
     total_dice /= num_class
@@ -227,10 +227,13 @@ def hd_generic(inp, target, params, percentile=95):
         one_hot(target, params["model"]["class_list"]).squeeze(-1).cpu().numpy()
     )
 
-    hd1 = __surface_distances(result_array, reference_array, params["subject_spacing"])
-    hd2 = __surface_distances(reference_array, result_array, params["subject_spacing"])
-    hd = numpy.percentile(numpy.hstack((hd1, hd2)), percentile)
-    return torch.tensor(hd)
+    hd = 0
+    for i in range(0, params["model"]["num_classes"]):
+        if i != params["model"]["ignore_label_validation"]:
+            hd1 = __surface_distances(result_array[:, i, ...].squeeze(0), reference_array[:, i, ...].squeeze(0))
+            hd2 = __surface_distances(reference_array[:,i,...].squeeze(0), result_array[:,i,...].squeeze(0), params["subject_spacing"])
+            hd += numpy.percentile(numpy.hstack((hd1, hd2)), percentile)
+    return torch.tensor(hd/params["model"]["num_classes"])
 
 
 def hd95(inp, target, params):
diff --git a/GANDLF/training_loop.py b/GANDLF/training_loop.py
--- a/GANDLF/training_loop.py
+++ b/GANDLF/training_loop.py
@@ -172,7 +172,7 @@ def train_network(model, train_dataloader, optimizer, params):
         label = label.to(params["device"])
 
         # ensure spacing is always present in params and is always subject-specific
-        if "subject_spacing" in subject:
+        if "spacing" in subject:
             params["subject_spacing"] = subject["spacing"]
         else:
             params["subject_spacing"] = None
@@ -358,6 +358,12 @@ def validate_network(
         if params["verbose"]:
             print("== Current subject:", subject["subject_id"], flush=True)
 
+        # ensure spacing is always present in params and is always subject-specific
+        if "spacing" in subject:
+            params["subject_spacing"] = subject["spacing"]
+        else:
+            params["subject_spacing"] = None
+            
         # constructing a new dict because torchio.GridSampler requires torchio.Subject, which requires torchio.Image to be present in initial dict, which the loader does not provide
         subject_dict = {}
         label_ground_truth = None


Test patch: