SemanticSegmentationModel
/
semantic-segmentation
/SemanticModel
/.ipynb_checkpoints
/evaluation_utils-checkpoint.py
import os | |
import cv2 | |
import torch | |
from tqdm import tqdm | |
from torch.utils.data import DataLoader | |
from segmentation_models_pytorch.base.modules import Activation | |
from SemanticModel.data_loader import SegmentationDataset | |
from SemanticModel.metrics import compute_mean_iou | |
from SemanticModel.image_preprocessing import get_validation_augmentations | |
def evaluate_model(model_config, data_path, image_size=None): | |
"""Evaluates model performance on a dataset.""" | |
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') | |
classes = ['background'] + model_config.classes if model_config.background_flag else model_config.classes | |
data_path = os.path.realpath(data_path) | |
image_subdir = os.path.join(data_path, 'Images') | |
mask_subdir = os.path.join(data_path, 'Masks') | |
if not all(os.path.exists(d) for d in [image_subdir, mask_subdir]): | |
raise Exception("Missing required subdirectories: 'Images' and 'Masks'") | |
if not image_size: | |
sample_image = cv2.imread(os.path.join(image_subdir, os.listdir(image_subdir)[0])) | |
height, width = sample_image.shape[:2] | |
image_size = max(height, width) | |
evaluation_dataset = SegmentationDataset( | |
data_path, | |
classes=classes, | |
augmentation=get_validation_augmentations( | |
im_width=image_size, | |
im_height=image_size, | |
fixed_size=False | |
), | |
preprocessing=model_config.preprocessing | |
) | |
evaluation_loader = DataLoader( | |
evaluation_dataset, | |
batch_size=1, | |
shuffle=False, | |
num_workers=2 | |
) | |
model = model_config.model.to(device) | |
model.eval() | |
requires_sigmoid = False | |
if model_config.n_classes == 1: | |
current_activation = _check_activation_function(model) | |
if current_activation != 'Sigmoid': | |
requires_sigmoid = True | |
predictions = [] | |
ground_truth = [] | |
print("Evaluating model performance...") | |
with torch.no_grad(): | |
for images, masks in tqdm(evaluation_loader): | |
images = images.to(device) | |
masks = masks.to(device) | |
outputs = model.forward(images) | |
if model_config.n_classes > 1: | |
predictions.extend([p.cpu().argmax(dim=0) for p in outputs]) | |
ground_truth.extend([gt.cpu().argmax(dim=0) for gt in masks]) | |
else: | |
if requires_sigmoid: | |
predictions.extend([ | |
(torch.sigmoid(p) > 0.5).float().squeeze().cpu() | |
for p in outputs | |
]) | |
else: | |
predictions.extend([ | |
(p > 0.5).float().squeeze().cpu() | |
for p in outputs | |
]) | |
ground_truth.extend([gt.cpu().squeeze() for gt in masks]) | |
metrics = compute_mean_iou( | |
predictions, | |
ground_truth, | |
num_labels=len(classes), | |
ignore_index=255 | |
) | |
print("\nEvaluation Results:") | |
print(f"Mean IoU: {metrics['mean_iou']:.3f}") | |
print("\nPer-class IoU:") | |
for idx, iou in enumerate(metrics['per_category_iou']): | |
print(f"{classes[idx]}: {iou:.3f}") | |
return metrics | |
def _check_activation_function(model): | |
"""Checks the activation function used in model's segmentation head.""" | |
from segmentation_models_pytorch.base.modules import Activation | |
activation_functions = [] | |
for _, module in model.segmentation_head.named_children(): | |
if isinstance(module, Activation): | |
activation_functions.append(type(module.activation).__name__) | |
return activation_functions[-1] if activation_functions else None |