From 29d0cfa58b9ae40ca76bb189290d219665a1c2b2 Mon Sep 17 00:00:00 2001 From: Tamino Huxohl <thuxohl@techfak.uni-bielefeld.de> Date: Fri, 13 Jan 2023 09:45:48 +0100 Subject: [PATCH] write comments and improve measure computation --- mu_map/eval/measures.py | 103 +++++++++++++++++++++++++++++----------- 1 file changed, 76 insertions(+), 27 deletions(-) diff --git a/mu_map/eval/measures.py b/mu_map/eval/measures.py index 38bcb2f..ddacc24 100644 --- a/mu_map/eval/measures.py +++ b/mu_map/eval/measures.py @@ -1,17 +1,43 @@ import numpy as np +import pandas as pd +from mu_map.dataset.default import MuMapDataset +from mu_map.models.unet import UNet -def mse(prediction: np.array, target: np.array): + +def mse(prediction: np.array, target: np.array) -> float: + """ + Compute the mean squared error (MSE) between a prediction and + a target array. + + Parameters + ---------- + prediction: np.ndarray + target: np.ndarray + """ se = (prediction - target) ** 2 mse = se.sum() / se.size return mse -def nmae(prediction: np.array, target: np.array, vmax:float=None, vmin:float=None): - if vmax is None: - vmax = target.max() - if vmin is None: - vmin = target.min() +def nmae( + prediction: np.array, target: np.array, vmax: float = None, vmin: float = None +): + """ + Compute the normalized mean absolute error (NMAE) between a prediction + and a target array. + + Parameters + ---------- + prediction: np.ndarray + target: np.ndarray + vmax: float, optional + maximum value for normalization, defaults to the maximal value in the target + vmin: float, optional + minimum value for normalization, defaults to the minimal value in the target + """ + vmax = target.max() if vmax is None else vmax + vmin = target.min() if vmin is None else vmin ae = np.absolute(prediction - target) mae = ae.sum() / ae.size @@ -19,16 +45,51 @@ def nmae(prediction: np.array, target: np.array, vmax:float=None, vmin:float=Non return nmae +def compute_measures(dataset: MuMapDataset, model: UNet) -> pd.DataFrame: + """ + Compute measures (MSE, NMAE) for all images in a dataset. + + Parameters + ---------- + dataset: MuMapDataset + the dataset containing the reconstructions and mu maps for which the scores are computed + model: UNet + the UNet model which is used to predict mu maps from reconstructions + + Returns + ------- + pd.DataFrame + a dataframe containing containing the measures for each image in the dataset + """ + measures = {"NMAE": nmae, "MSE": mse} + values = pd.DataFrame(dict(map(lambda x: (x, []), measures.keys()))) + for i, (recon, mu_map) in enumerate(dataset): + _id = dataset.table.iloc[i]["id"] + print( + f"Process input {str(i):>{len(str(len(dataset)))}}/{len(dataset)}", end="\r" + ) + prediction = model(recon.unsqueeze(dim=0).to(device)) + + prediction = prediction.squeeze().cpu().numpy() + mu_map = mu_map.squeeze().cpu().numpy() + + row = dict( + map(lambda item: (item[0], [item[1](prediction, mu_map)]), measures.items()) + ) + row["id"] = _id + row = pd.DataFrame(row) + values = pd.concat((values, row), ignore_index=True) + print(f" " * 100, end="\r") + return values + + if __name__ == "__main__": import argparse - import pandas as pd import torch - from mu_map.dataset.default import MuMapDataset from mu_map.dataset.normalization import norm_by_str, norm_choices from mu_map.dataset.transform import SequenceTransform, PadCropTranform - from mu_map.models.unet import UNet parser = argparse.ArgumentParser( description="Compute, print and store measures for a given model", @@ -37,7 +98,7 @@ if __name__ == "__main__": parser.add_argument( "--device", type=str, - default="cpu", + default="cuda" if torch.cuda.is_available() else "cpu", choices=["cpu", "cuda"], help="the device on which the model is evaluated (cpu or cuda)", ) @@ -84,7 +145,7 @@ if __name__ == "__main__": torch.set_grad_enabled(False) device = torch.device(args.device) - model = UNet() + model = UNet(features=[32, 64, 128, 256, 512]) model.load_state_dict(torch.load(args.weights, map_location=device)) model = model.to(device).eval() @@ -101,28 +162,16 @@ if __name__ == "__main__": scatter_correction=args.scatter_corrected, ) - measures = {"NMAE": nmae, "MSE": mse} - values = pd.DataFrame(dict(map(lambda x: (x, []), measures.keys()))) - for i, (recon, mu_map) in enumerate(dataset): - print( - f"Process input {str(i):>{len(str(len(dataset)))}}/{len(dataset)}", end="\r" - ) - prediction = model(recon.unsqueeze(dim=0).to(device)) - - prediction = prediction.squeeze().cpu().numpy() - mu_map = mu_map.squeeze().cpu().numpy() - - row = pd.DataFrame(dict( - map(lambda item: (item[0], [item[1](prediction, mu_map)]), measures.items()) - )) - values = pd.concat((values, row), ignore_index=True) - print(f" " * 100, end="\r") + values = compute_measures(dataset, model) if args.out: values.to_csv(args.out, index=False) print("Scores:") for measure_name, measure_values in values.items(): + if measure_name == "id": + continue + mean = measure_values.mean() std = np.std(measure_values) print(f" - {measure_name:>6}: {mean:.6f}±{std:.6f}") -- GitLab