|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| import warnings
|
| import os
|
| from pathlib import Path
|
| import csv
|
| import json
|
| import torch
|
|
|
| import datasets.rayan_dataset as rayan_dataset
|
| from evaluation.utils.metrics import compute_metrics
|
|
|
| warnings.filterwarnings("ignore")
|
|
|
|
|
| class BaseEval:
|
| def __init__(self, cfg):
|
| self.cfg = cfg
|
| self.device = torch.device(
|
| "cuda:{}".format(cfg["device"]) if torch.cuda.is_available() else "cpu"
|
| )
|
|
|
| self.path = cfg["datasets"]["data_path"]
|
| self.dataset = cfg["datasets"]["dataset_name"]
|
| self.save_csv = cfg["testing"]["save_csv"]
|
| self.save_json = cfg["testing"]["save_json"]
|
| self.categories = cfg["datasets"]["class_name"]
|
| if isinstance(self.categories, str):
|
| if self.categories.lower() == "all":
|
| if self.dataset == "rayan_dataset":
|
| self.categories = self.get_available_class_names(self.path)
|
| else:
|
| self.categories = [self.categories]
|
| self.output_dir = cfg["testing"]["output_dir"]
|
| os.makedirs(self.output_dir, exist_ok=True)
|
| self.scores_dir = cfg["testing"]["output_scores_dir"]
|
| self.class_name_mapping_dir = cfg["testing"]["class_name_mapping_dir"]
|
|
|
| self.leaderboard_metric_weights = {
|
| "image_auroc": 1.2,
|
| "image_ap": 1.1,
|
| "image_f1": 1.1,
|
| "pixel_auroc": 1.0,
|
| "pixel_aupro": 1.4,
|
| "pixel_ap": 1.3,
|
| "pixel_f1": 1.3,
|
| }
|
|
|
| def get_available_class_names(self, root_data_path):
|
| all_items = os.listdir(root_data_path)
|
| folder_names = [
|
| item
|
| for item in all_items
|
| if os.path.isdir(os.path.join(root_data_path, item))
|
| ]
|
|
|
| return folder_names
|
|
|
| def load_datasets(self, category):
|
| dataset_classes = {
|
| "rayan_dataset": rayan_dataset.RayanDataset,
|
| }
|
|
|
| dataset_splits = {
|
| "rayan_dataset": rayan_dataset.DatasetSplit.TEST,
|
| }
|
|
|
| test_dataset = dataset_classes[self.dataset](
|
| source=self.path,
|
| split=dataset_splits[self.dataset],
|
| classname=category,
|
| )
|
| return test_dataset
|
|
|
| def get_category_metrics(self, category):
|
| print(f"Loading scores of '{category}'")
|
| gt_sp, pr_sp, gt_px, pr_px, _ = self.load_category_scores(category)
|
|
|
| print(f"Computing metrics for '{category}'")
|
| image_metric, pixel_metric = compute_metrics(gt_sp, pr_sp, gt_px, pr_px)
|
|
|
| return image_metric, pixel_metric
|
|
|
| def load_category_scores(self, category):
|
| raise NotImplementedError()
|
|
|
| def get_scores_path_for_image(self, image_path):
|
| """example image_path: './data/photovoltaic_module/test/good/037.png'"""
|
| path = Path(image_path)
|
|
|
| category, split, anomaly_type = path.parts[-4:-1]
|
| image_name = path.stem
|
|
|
| return os.path.join(
|
| self.scores_dir, category, split, anomaly_type, f"{image_name}_scores.json"
|
| )
|
|
|
| def calc_leaderboard_score(self, **metrics):
|
| weighted_sum = 0
|
| total_weight = 0
|
| for key, weight in self.leaderboard_metric_weights.items():
|
| metric = metrics.get(key)
|
| weighted_sum += metric * weight
|
| total_weight += weight
|
|
|
| if total_weight == 0:
|
| return 0
|
|
|
| return weighted_sum / total_weight
|
|
|
| def main(self):
|
| image_auroc_list = []
|
| image_f1_list = []
|
| image_ap_list = []
|
| pixel_auroc_list = []
|
| pixel_f1_list = []
|
| pixel_ap_list = []
|
| pixel_aupro_list = []
|
| leaderboard_score_list = []
|
| for category in self.categories:
|
| image_metric, pixel_metric = self.get_category_metrics(
|
| category=category,
|
| )
|
| image_auroc, image_f1, image_ap = image_metric
|
| pixel_auroc, pixel_f1, pixel_ap, pixel_aupro = pixel_metric
|
| leaderboard_score = self.calc_leaderboard_score(
|
| image_auroc=image_auroc,
|
| image_f1=image_f1,
|
| image_ap=image_ap,
|
| pixel_auroc=pixel_auroc,
|
| pixel_aupro=pixel_aupro,
|
| pixel_f1=pixel_f1,
|
| pixel_ap=pixel_ap,
|
| )
|
|
|
| image_auroc_list.append(image_auroc)
|
| image_f1_list.append(image_f1)
|
| image_ap_list.append(image_ap)
|
| pixel_auroc_list.append(pixel_auroc)
|
| pixel_f1_list.append(pixel_f1)
|
| pixel_ap_list.append(pixel_ap)
|
| pixel_aupro_list.append(pixel_aupro)
|
| leaderboard_score_list.append(leaderboard_score)
|
|
|
| print(category)
|
| print(
|
| "[image level] auroc:{}, f1:{}, ap:{}".format(
|
| image_auroc * 100,
|
| image_f1 * 100,
|
| image_ap * 100,
|
| )
|
| )
|
| print(
|
| "[pixel level] auroc:{}, f1:{}, ap:{}, aupro:{}".format(
|
| pixel_auroc * 100,
|
| pixel_f1 * 100,
|
| pixel_ap * 100,
|
| pixel_aupro * 100,
|
| )
|
| )
|
| print(
|
| "leaderboard score:{}".format(
|
| leaderboard_score * 100,
|
| )
|
| )
|
|
|
| image_auroc_mean = sum(image_auroc_list) / len(image_auroc_list)
|
| image_f1_mean = sum(image_f1_list) / len(image_f1_list)
|
| image_ap_mean = sum(image_ap_list) / len(image_ap_list)
|
| pixel_auroc_mean = sum(pixel_auroc_list) / len(pixel_auroc_list)
|
| pixel_f1_mean = sum(pixel_f1_list) / len(pixel_f1_list)
|
| pixel_ap_mean = sum(pixel_ap_list) / len(pixel_ap_list)
|
| pixel_aupro_mean = sum(pixel_aupro_list) / len(pixel_aupro_list)
|
| leaderboard_score_mean = sum(leaderboard_score_list) / len(
|
| leaderboard_score_list
|
| )
|
|
|
| print("mean")
|
| print(
|
| "[image level] auroc:{}, f1:{}, ap:{}".format(
|
| image_auroc_mean * 100, image_f1_mean * 100, image_ap_mean * 100
|
| )
|
| )
|
| print(
|
| "[pixel level] auroc:{}, f1:{}, ap:{}, aupro:{}".format(
|
| pixel_auroc_mean * 100,
|
| pixel_f1_mean * 100,
|
| pixel_ap_mean * 100,
|
| pixel_aupro_mean * 100,
|
| )
|
| )
|
| print(
|
| "leaderboard score:{}".format(
|
| leaderboard_score_mean * 100,
|
| )
|
| )
|
|
|
|
|
| if self.save_csv:
|
| with open(self.class_name_mapping_dir, "r") as f:
|
| class_name_mapping_dict = json.load(f)
|
| csv_data = [
|
| [
|
| "Category",
|
| "pixel_auroc",
|
| "pixel_f1",
|
| "pixel_ap",
|
| "pixel_aupro",
|
| "image_auroc",
|
| "image_f1",
|
| "image_ap",
|
| "leaderboard_score",
|
| ]
|
| ]
|
| for i, category in enumerate(self.categories):
|
| csv_data.append(
|
| [
|
| class_name_mapping_dict[category],
|
| pixel_auroc_list[i] * 100,
|
| pixel_f1_list[i] * 100,
|
| pixel_ap_list[i] * 100,
|
| pixel_aupro_list[i] * 100,
|
| image_auroc_list[i] * 100,
|
| image_f1_list[i] * 100,
|
| image_ap_list[i] * 100,
|
| leaderboard_score_list[i] * 100,
|
| ]
|
| )
|
| csv_data.append(
|
| [
|
| "mean",
|
| pixel_auroc_mean * 100,
|
| pixel_f1_mean * 100,
|
| pixel_ap_mean * 100,
|
| pixel_aupro_mean * 100,
|
| image_auroc_mean * 100,
|
| image_f1_mean * 100,
|
| image_ap_mean * 100,
|
| leaderboard_score_mean * 100,
|
| ]
|
| )
|
|
|
| csv_file_path = os.path.join(self.output_dir, "results.csv")
|
| with open(csv_file_path, mode="w", newline="") as file:
|
| writer = csv.writer(file)
|
| writer.writerows(csv_data)
|
|
|
|
|
| if self.save_json:
|
| json_data = []
|
| with open(self.class_name_mapping_dir, "r") as f:
|
| class_name_mapping_dict = json.load(f)
|
| for i, category in enumerate(self.categories):
|
| json_data.append(
|
| {
|
| "Category": class_name_mapping_dict[category],
|
| "pixel_auroc": pixel_auroc_list[i] * 100,
|
| "pixel_f1": pixel_f1_list[i] * 100,
|
| "pixel_ap": pixel_ap_list[i] * 100,
|
| "pixel_aupro": pixel_aupro_list[i] * 100,
|
| "image_auroc": image_auroc_list[i] * 100,
|
| "image_f1": image_f1_list[i] * 100,
|
| "image_ap": image_ap_list[i] * 100,
|
| "leaderboard_score": leaderboard_score_list[i] * 100,
|
| }
|
| )
|
| json_data.append(
|
| {
|
| "Category": "mean",
|
| "pixel_auroc": pixel_auroc_mean * 100,
|
| "pixel_f1": pixel_f1_mean * 100,
|
| "pixel_ap": pixel_ap_mean * 100,
|
| "pixel_aupro": pixel_aupro_mean * 100,
|
| "image_auroc": image_auroc_mean * 100,
|
| "image_f1": image_f1_mean * 100,
|
| "image_ap": image_ap_mean * 100,
|
| "leaderboard_score": leaderboard_score_mean * 100,
|
| }
|
| )
|
|
|
| json_file_path = os.path.join(self.output_dir, "results.json")
|
| with open(json_file_path, mode="w") as file:
|
| final_json = {
|
| "result": leaderboard_score_mean * 100,
|
| "metadata": json_data,
|
| }
|
| json.dump(final_json, file, indent=4)
|
|
|