GANDLF 0.1.4.dev20250609__py3-none-any.whl → 0.1.4.dev20250611__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of GANDLF might be problematic. Click here for more details.

@@ -10,7 +10,11 @@ import SimpleITK as sitk
10
10
  import numpy as np
11
11
 
12
12
  from GANDLF.config_manager import ConfigManager
13
- from GANDLF.utils import find_problem_type_from_parameters, one_hot
13
+ from GANDLF.utils import (
14
+ find_problem_type_from_parameters,
15
+ one_hot,
16
+ sanity_check_on_file_readers,
17
+ )
14
18
  from GANDLF.metrics import (
15
19
  overall_stats,
16
20
  structural_similarity_index,
@@ -176,6 +180,9 @@ def generate_metrics_dict(
176
180
  for _, row in tqdm(input_df.iterrows(), total=input_df.shape[0]):
177
181
  current_subject_id = row["SubjectID"]
178
182
  overall_stats_dict[current_subject_id] = {}
183
+ sanity_check_on_file_readers(
184
+ row["Target"], row["Prediction"], current_subject_id
185
+ )
179
186
  label_image = torchio.LabelMap(row["Target"])
180
187
  pred_image = torchio.LabelMap(row["Prediction"])
181
188
  label_tensor = label_image.data
@@ -264,20 +271,23 @@ def generate_metrics_dict(
264
271
  for _, row in tqdm(input_df.iterrows(), total=input_df.shape[0]):
265
272
  current_subject_id = row["SubjectID"]
266
273
  overall_stats_dict[current_subject_id] = {}
274
+ sanity_check_on_file_readers(
275
+ row["Target"], row["Prediction"], current_subject_id
276
+ )
267
277
  label_image = torchio.LabelMap(row["Target"])
268
278
  pred_image = torchio.LabelMap(row["Prediction"])
269
279
  label_tensor = label_image.data
270
280
  pred_tensor = pred_image.data
271
281
  spacing = label_image.spacing
272
- if label_tensor.data.shape[-1] == 1:
273
- spacing = spacing[0:2]
274
- # add dimension for batch
275
- parameters["subject_spacing"] = torch.Tensor(spacing).unsqueeze(0)
276
- label_array = label_tensor.unsqueeze(0).numpy()
277
- pred_array = pred_tensor.unsqueeze(0).numpy()
282
+ # if label_tensor.data.shape[-1] == 1:
283
+ # spacing = spacing[0:2]
284
+ # remove dimension to ensure 3D tensors
285
+ if label_tensor.data.ndim == 4:
286
+ label_array = label_tensor.squeeze(0).numpy().astype(int)
287
+ pred_array = pred_tensor.squeeze(0).numpy().astype(int)
278
288
 
279
289
  overall_stats_dict[current_subject_id] = generate_instance_segmentation(
280
- prediction=pred_array, target=label_array
290
+ prediction=pred_array, target=label_array, parameters=parameters
281
291
  )
282
292
 
283
293
  elif problem_type == "synthesis":
@@ -340,6 +350,9 @@ def generate_metrics_dict(
340
350
  for _, row in tqdm(input_df.iterrows(), total=input_df.shape[0]):
341
351
  current_subject_id = row["SubjectID"]
342
352
  overall_stats_dict[current_subject_id] = {}
353
+ sanity_check_on_file_readers(
354
+ row["Target"], row["Prediction"], current_subject_id
355
+ )
343
356
  target_image = __fix_2d_tensor(torchio.ScalarImage(row["Target"]).data)
344
357
  pred_image = __fix_2d_tensor(torchio.ScalarImage(row["Prediction"]).data)
345
358
  # if "Mask" is not in the row, we assume that the whole image is the mask
@@ -13,7 +13,10 @@ edge_case_handler: !EdgeCaseHandler
13
13
  !Metric IOU: !MetricZeroTPEdgeCaseHandling {empty_prediction_result: !EdgeCaseResult ZERO,
14
14
  empty_reference_result: !EdgeCaseResult ZERO, no_instances_result: !EdgeCaseResult NAN,
15
15
  normal: !EdgeCaseResult ZERO}
16
- !Metric ASSD: !MetricZeroTPEdgeCaseHandling {empty_prediction_result: !EdgeCaseResult INF,
16
+ !Metric NSD: !MetricZeroTPEdgeCaseHandling {empty_prediction_result: !EdgeCaseResult INF,
17
+ empty_reference_result: !EdgeCaseResult INF, no_instances_result: !EdgeCaseResult NAN,
18
+ normal: !EdgeCaseResult INF}
19
+ !Metric HD95: !MetricZeroTPEdgeCaseHandling {empty_prediction_result: !EdgeCaseResult INF,
17
20
  empty_reference_result: !EdgeCaseResult INF, no_instances_result: !EdgeCaseResult NAN,
18
21
  normal: !EdgeCaseResult INF}
19
22
  !Metric RVD: !MetricZeroTPEdgeCaseHandling {empty_prediction_result: !EdgeCaseResult NAN,
@@ -27,24 +30,27 @@ global_metrics: [!Metric DSC]
27
30
  instance_approximator: !ConnectedComponentsInstanceApproximator {cca_backend: null}
28
31
  instance_matcher: !NaiveThresholdMatching {allow_many_to_one: false, matching_metric: !Metric IOU,
29
32
  matching_threshold: 0.5}
30
- instance_metrics: [!Metric DSC, !Metric IOU, !Metric ASSD, !Metric RVD]
33
+ instance_metrics: [!Metric DSC, !Metric IOU, !Metric RVD, !Metric NSD, !Metric HD95]
31
34
  log_times: false
32
35
  save_group_times: false
33
36
  segmentation_class_groups: !SegmentationClassGroups
34
37
  groups:
35
- ed: !LabelGroup
38
+ snfh: !LabelGroup
36
39
  single_instance: false
37
40
  value_labels: [2]
38
41
  et: !LabelGroup
39
42
  single_instance: false
40
43
  value_labels: [3]
41
- net: !LabelGroup
44
+ netc: !LabelGroup
42
45
  single_instance: false
43
46
  value_labels: [1]
47
+ rc: !LabelGroup
48
+ single_instance: false
49
+ value_labels: [4]
44
50
  tc: !LabelMergeGroup
45
51
  single_instance: false
46
- value_labels: [1, 3]
52
+ value_labels: [1, 3, 4]
47
53
  wt: !LabelMergeGroup
48
54
  single_instance: false
49
- value_labels: [1, 2, 3]
55
+ value_labels: [1, 2, 3, 4]
50
56
  verbose: false
@@ -1,4 +1,5 @@
1
1
  from pathlib import Path
2
+ import tempfile
2
3
 
3
4
  import numpy as np
4
5
 
@@ -6,7 +7,10 @@ from panoptica import Panoptica_Evaluator
6
7
 
7
8
 
8
9
  def generate_instance_segmentation(
9
- prediction: np.ndarray, target: np.ndarray, panoptica_config_path: str = None
10
+ prediction: np.ndarray,
11
+ target: np.ndarray,
12
+ parameters: dict = None,
13
+ panoptica_config_path: str = None,
10
14
  ) -> dict:
11
15
  """
12
16
  Evaluate a single exam using Panoptica.
@@ -14,6 +18,7 @@ def generate_instance_segmentation(
14
18
  Args:
15
19
  prediction (np.ndarray): The input prediction containing objects.
16
20
  label_path (str): The path to the reference label.
21
+ target (np.ndarray): The input target containing objects.
17
22
  panoptica_config_path (str): The path to the Panoptica configuration file.
18
23
 
19
24
  Returns:
@@ -21,11 +26,21 @@ def generate_instance_segmentation(
21
26
  """
22
27
 
23
28
  cwd = Path(__file__).parent.absolute()
24
- panoptica_config_path = (
25
- cwd / "panoptica_config_brats.yaml"
26
- if panoptica_config_path is None
27
- else panoptica_config_path
28
- )
29
+ # the parameters dict takes precedence over the panoptica_config_path
30
+ panoptica_config = parameters.get("panoptica_config", None)
31
+ if panoptica_config is None:
32
+ panoptica_config_path = (
33
+ cwd / "panoptica_config_brats.yaml"
34
+ if panoptica_config_path is None
35
+ else panoptica_config_path
36
+ )
37
+ else:
38
+ # write the panoptica config to a file
39
+ panoptica_config_path = tempfile.NamedTemporaryFile(
40
+ mode="w", delete=False, suffix=".yaml"
41
+ ).name
42
+ with open(panoptica_config_path, "w") as f:
43
+ f.write(panoptica_config)
29
44
  evaluator = Panoptica_Evaluator.load_from_config(panoptica_config_path)
30
45
 
31
46
  # call evaluate
GANDLF/utils/__init__.py CHANGED
@@ -7,6 +7,7 @@ from .imaging import (
7
7
  resize_image,
8
8
  resample_image,
9
9
  perform_sanity_check_on_subject,
10
+ sanity_check_on_file_readers,
10
11
  write_training_patches,
11
12
  get_correct_padding_size,
12
13
  applyCustomColorMap,
GANDLF/utils/imaging.py CHANGED
@@ -123,6 +123,56 @@ def softer_sanity_check(
123
123
  return result
124
124
 
125
125
 
126
+ def sanity_check_on_file_readers(
127
+ file_reader_0: Union[str, sitk.ImageFileReader],
128
+ file_reader_1: Union[str, sitk.ImageFileReader],
129
+ subject_id: Optional[str] = "",
130
+ threshold: Optional[float] = 0.00001,
131
+ ) -> bool:
132
+ """
133
+ This function performs a sanity check on the file readers to ensure that the properties of the images are consistent.
134
+
135
+ Args:
136
+ file_reader_0 (Union[str, sitk.ImageFileReader]): The first file reader.
137
+ file_reader_1 (Union[str, sitk.ImageFileReader]): The second file reader.
138
+ threshold (Optional[float], optional): The threshold for comparison. Defaults to 0.00001.
139
+
140
+ Returns:
141
+ bool: True if the sanity check passes.
142
+ """
143
+
144
+ if isinstance(file_reader_0, str):
145
+ temp_file = file_reader_0
146
+ file_reader_0 = sitk.ImageFileReader()
147
+ file_reader_0.SetFileName(temp_file)
148
+ file_reader_0.ReadImageInformation()
149
+
150
+ if isinstance(file_reader_1, str):
151
+ temp_file = file_reader_1
152
+ file_reader_1 = sitk.ImageFileReader()
153
+ file_reader_1.SetFileName(temp_file)
154
+ file_reader_1.ReadImageInformation()
155
+ # this check needs to be absolute
156
+ assert file_reader_0.GetDimension() == file_reader_1.GetDimension(), (
157
+ "Dimensions for Subject '" + subject_id + "' are not consistent."
158
+ )
159
+
160
+ # other checks can be softer
161
+ assert softer_sanity_check(
162
+ file_reader_0.GetOrigin(), file_reader_1.GetOrigin(), threshold=threshold
163
+ ), ("Origin for Subject '" + subject_id + "' are not consistent.")
164
+
165
+ assert softer_sanity_check(
166
+ file_reader_0.GetDirection(), file_reader_1.GetDirection(), threshold=threshold
167
+ ), ("Orientation for Subject '" + subject_id + "' are not consistent.")
168
+
169
+ assert softer_sanity_check(
170
+ file_reader_0.GetSpacing(), file_reader_1.GetSpacing(), threshold=threshold
171
+ ), ("Spacing for Subject '" + subject_id + "' are not consistent.")
172
+
173
+ return True
174
+
175
+
126
176
  def perform_sanity_check_on_subject(subject: torchio.Subject, parameters: dict) -> bool:
127
177
  """
128
178
  This function performs a sanity check on the image modalities in input subject to ensure that they are consistent.
@@ -169,39 +219,11 @@ def perform_sanity_check_on_subject(subject: torchio.Subject, parameters: dict)
169
219
  else:
170
220
  file_reader_current = _get_itkimage_or_filereader(subject[str(key)])
171
221
 
172
- # this check needs to be absolute
173
- assert (
174
- file_reader_base.GetDimension()
175
- == file_reader_current.GetDimension()
176
- ), (
177
- "Dimensions for Subject '"
178
- + subject["subject_id"]
179
- + "' are not consistent."
180
- )
181
-
182
- # other checks can be softer
183
- assert softer_sanity_check(
184
- file_reader_base.GetOrigin(), file_reader_current.GetOrigin()
185
- ), (
186
- "Origin for Subject '"
187
- + subject["subject_id"]
188
- + "' are not consistent."
189
- )
190
-
191
- assert softer_sanity_check(
192
- file_reader_base.GetDirection(), file_reader_current.GetDirection()
193
- ), (
194
- "Orientation for Subject '"
195
- + subject["subject_id"]
196
- + "' are not consistent."
197
- )
198
-
199
- assert softer_sanity_check(
200
- file_reader_base.GetSpacing(), file_reader_current.GetSpacing()
201
- ), (
202
- "Spacing for Subject '"
203
- + subject["subject_id"]
204
- + "' are not consistent."
222
+ sanity_check_on_file_readers(
223
+ file_reader_base,
224
+ file_reader_current,
225
+ subject_id=subject["subject_id"],
226
+ threshold=parameters.get("sanity_check_threshold", 0.00001),
205
227
  )
206
228
 
207
229
  return True
GANDLF/version.py CHANGED
@@ -1 +1 @@
1
- __version__ = "0.1.4-dev20250609"
1
+ __version__ = "0.1.4-dev20250611"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: GANDLF
3
- Version: 0.1.4.dev20250609
3
+ Version: 0.1.4.dev20250611
4
4
  Summary: PyTorch-based framework that handles segmentation/regression/classification using various DL architectures for medical imaging.
5
5
  Author: MLCommons
6
6
  Author-email: gandlf@mlcommons.org
@@ -5,14 +5,14 @@ GANDLF/logger.py,sha256=oamQ1SOTTpAnC8vQ67o211Q6_bExGg_hAuqlHGlJfAI,2951
5
5
  GANDLF/logging_config.yaml,sha256=9XxRxAKtLn5ehT1khpR8wEiJGW64sx1lylAspM5KaWk,1337
6
6
  GANDLF/parseConfig.py,sha256=jO-ybIPxLw23OWDvFdTukbft0ZM8UOofGnoL2C5CEps,754
7
7
  GANDLF/training_manager.py,sha256=AZlf-fl7KAwZgyre8-0M5lAyma6NvtiGX6XT51AJdxU,11436
8
- GANDLF/version.py,sha256=6EFUxHuz3VK2LWZLY5x_Kd_z9--zoPRJAaUKr9ccvB0,34
8
+ GANDLF/version.py,sha256=IfZFHfeewJgD5R9DgFa2wSz2OhAyTh720DH2OZIIm64,34
9
9
  GANDLF/anonymize/__init__.py,sha256=Nxig-jM-a-aKlK09PNi1zhNulEpLTyjnsY_oGQKdjhQ,1953
10
10
  GANDLF/anonymize/convert_to_nifti.py,sha256=MOfSDncFGJGb-EQP9sFGn0yuKpX010Ioi2KNwttaex8,1339
11
11
  GANDLF/cli/__init__.py,sha256=F05eyL2HKyWkHczRZuPE_Z2Yg685P9ARYxTwz6njGeQ,784
12
12
  GANDLF/cli/config_generator.py,sha256=_j0aRV3puiIItJ1WOHRNVII_TkGJuH9ep6SuwPblcnc,4502
13
13
  GANDLF/cli/data_split_saver.py,sha256=72ygy9s3INt2NFAfSW4j9dxxmuuvfzfBTF0Hwh0nYBU,1720
14
14
  GANDLF/cli/deploy.py,sha256=7yPqRox6e5MB-VzHxmA4kt-W5dWwElxDm1mm019jN74,15155
15
- GANDLF/cli/generate_metrics.py,sha256=TxKJsDHtGBgKc-Fyx4F_tc_CMu5hSsO8xlc5Te86DGk,19973
15
+ GANDLF/cli/generate_metrics.py,sha256=ySQ5s0sGajXbr__HLOzsDtULhuZ3x7plqaC1Lz1oZto,20429
16
16
  GANDLF/cli/huggingface_hub_handler.py,sha256=vGQYwDiT3Y8yk_xLNkB8DgW1rYpEcwYp0TCdCO5oWTs,4631
17
17
  GANDLF/cli/main_run.py,sha256=gYNJQGvmwqBjj3ARRxj-y3R1PMOP4qTwcwFSRBbkh0k,4352
18
18
  GANDLF/cli/patch_extraction.py,sha256=30RpBfjpwE9GLRSSD7JRqwoHngESQL0eOt09n_5r18Q,3555
@@ -108,10 +108,10 @@ GANDLF/metrics/__init__.py,sha256=k8xcpujpUg22R33keOUNetzrLnGSHsEAmClkFeDHZxc,44
108
108
  GANDLF/metrics/classification.py,sha256=6rVZjXxHwfJFqw19UiRMYK3uF656QgfMwWDz-LOHUaw,4692
109
109
  GANDLF/metrics/generic.py,sha256=N-h9sDwuAsskK7AdZ2N0otcbFTmKxh9kdyi6MQkDO60,4983
110
110
  GANDLF/metrics/metric_calculators.py,sha256=c-NAl84yniTWjMKePBlf0TsCIJnYHODplt8HeEk9Uac,3610
111
- GANDLF/metrics/panoptica_config_brats.yaml,sha256=W2EBe-NRHNYc7vRZdxnAyKy0SgXQ21F3K3Nzb0EvwE0,2368
111
+ GANDLF/metrics/panoptica_config_brats.yaml,sha256=mTGSQuJoENuy84gZd2tHV0Dfl7GX5nIeE_46q5Vczx4,2685
112
112
  GANDLF/metrics/regression.py,sha256=Ca58jo9OL1GdjB2ZvQCcrKWz9F67iY5rcbnQxT-LpcU,4584
113
113
  GANDLF/metrics/segmentation.py,sha256=zqWEI6LuphFM0Nsm0sG2XeqAxpNJnoK1Z9q4FJt58c8,25645
114
- GANDLF/metrics/segmentation_panoptica.py,sha256=ExbobmLhlyKYRKE7zEhZmuHtu5fdIUDs-53K-u4AKX8,1026
114
+ GANDLF/metrics/segmentation_panoptica.py,sha256=aFGF3q_Fnf5vIWaJDMHcs2Az_fb23l2cvvifnCkgPO0,1611
115
115
  GANDLF/metrics/synthesis.py,sha256=IfYit-R0O5ZUfmsWfLD6BqcLjjoEiotx0lUdsXWlbao,6730
116
116
  GANDLF/models/MSDNet.py,sha256=mzBkw_kQigSDTxaR7tojhdI4ECIQ65i_qiCrNaZmBHI,3442
117
117
  GANDLF/models/__init__.py,sha256=3SwskWonRW1AduPe6CYQWucU8ZBkkfJUpEF34I0NWP0,4286
@@ -169,22 +169,22 @@ GANDLF/privacy/opacus/training_utils.py,sha256=ejXUIhLNjRzTebF-7uCYUluK7jyINDOpL
169
169
  GANDLF/schedulers/__init__.py,sha256=jMTea7kX7zawFrtjVDKHDLIfBgt7GD-G2z9_eKjI1_A,1320
170
170
  GANDLF/schedulers/wrap_monai.py,sha256=_kP3ArUIFK3x3u0nQV8Gi2oPruMIGGTSZxa4bSygGPs,400
171
171
  GANDLF/schedulers/wrap_torch.py,sha256=NuCAmYMKgYeFzO1PEiHfnFaHpzuQU0DsK5NOi-gVxOo,6746
172
- GANDLF/utils/__init__.py,sha256=QpNBl-fTrFUDyChAnaidPXdT-pY080pMG9kUTrlJ9OY,1691
172
+ GANDLF/utils/__init__.py,sha256=F74QIQ6dZL8cOIsZkU-VfDdcHewUW959GXRvDfphGCk,1725
173
173
  GANDLF/utils/data_splitter.py,sha256=IBVsLYo4y28G6LedbLPYWyiAUiaLxD4wWZD4EZC2D6I,10174
174
174
  GANDLF/utils/exceptions.py,sha256=SmEGzCbc5mXxjylmA9XE4PXZdmkkfOjrEh473cWTAvA,100
175
175
  GANDLF/utils/gandlf_logging.py,sha256=a1yV4244BGO5gp4OuAIKJUZgR21U1OPdovJ5nH1uUrs,2162
176
176
  GANDLF/utils/generic.py,sha256=NyJgaeCdryBlHMziPPLmWtIk450u042NWQgs_qh7knw,11744
177
177
  GANDLF/utils/handle_collisions.py,sha256=UFgfrddQqeipOdpKk0Mo-wwJ-TYTESNZyXzEyQeaLdI,3082
178
- GANDLF/utils/imaging.py,sha256=FZYtRXMHYUkL_7bzVtwsnrYyrYAm6Hvs5R-tFnEbYkY,15083
178
+ GANDLF/utils/imaging.py,sha256=_qCgvIXHZW_k_IUYLU95G5L5yoozxCRCYxo65TI-95U,15983
179
179
  GANDLF/utils/modelbase.py,sha256=MJ1ufJGQ-ZgfYWTg7o4f-Iz78d7SYiyxN7MT8bnNDaw,950
180
180
  GANDLF/utils/modelio.py,sha256=9koLUn3wCODtNOYA2abtxkqxfLgEG07Bhh-NYIrtWOc,8084
181
181
  GANDLF/utils/parameter_processing.py,sha256=DA7ZEsizWWLJZnCxBnDNh1NyA-bw5oirOvodiZZWbIk,5675
182
182
  GANDLF/utils/pred_target_processors.py,sha256=aatXJ6jdJaNAHa_tPzHfC1gOQrPYJLtg-cYeUFvkM_s,2701
183
183
  GANDLF/utils/tensor.py,sha256=AOwNTQfw9mnsomGwOF2Q_rdDS1WANlIatB0hhZN0gSg,21504
184
184
  GANDLF/utils/write_parse.py,sha256=HROxskhet-uIdUJmz16z_7p9r0mf8hWsqQFygwZ8ap0,9202
185
- gandlf-0.1.4.dev20250609.dist-info/licenses/LICENSE,sha256=GlZPAfA4eckod8IVayhBXkqCpESXf6cc9BGli_Jwims,11357
186
- gandlf-0.1.4.dev20250609.dist-info/METADATA,sha256=CmAfClLNUVdbXqogPnBI4TSWilLvYzPzS_fzMUhHOgY,9932
187
- gandlf-0.1.4.dev20250609.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
188
- gandlf-0.1.4.dev20250609.dist-info/entry_points.txt,sha256=agwocNI7Upi-sFDe1rMl71dGN8YhCBB7WJmtBHRF4jg,902
189
- gandlf-0.1.4.dev20250609.dist-info/top_level.txt,sha256=i5D9wEbQhl085_9Lx2m7x-9Zu6nlx1tjYYbuSihG09E,7
190
- gandlf-0.1.4.dev20250609.dist-info/RECORD,,
185
+ gandlf-0.1.4.dev20250611.dist-info/licenses/LICENSE,sha256=GlZPAfA4eckod8IVayhBXkqCpESXf6cc9BGli_Jwims,11357
186
+ gandlf-0.1.4.dev20250611.dist-info/METADATA,sha256=EKvbL6HRwo773sCkUvDapy-iUNoGoTfER_893QLLZgs,9932
187
+ gandlf-0.1.4.dev20250611.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
188
+ gandlf-0.1.4.dev20250611.dist-info/entry_points.txt,sha256=agwocNI7Upi-sFDe1rMl71dGN8YhCBB7WJmtBHRF4jg,902
189
+ gandlf-0.1.4.dev20250611.dist-info/top_level.txt,sha256=i5D9wEbQhl085_9Lx2m7x-9Zu6nlx1tjYYbuSihG09E,7
190
+ gandlf-0.1.4.dev20250611.dist-info/RECORD,,