"""Evaluate the trained fusion model on Validation and Test sets.""" import joblib import numpy as np import torch from pathlib import Path from sklearn.metrics import accuracy_score, roc_auc_score, classification_report from torch.utils.data import DataLoader from torchvision import transforms import torchvision.transforms.functional as TF from train import DeepfakeFeatureFusion, ImageDataset def pad_to_min_size(img, size): w, h = img.size pad_w = max(0, size - w) pad_h = max(0, size - h) if pad_w or pad_h: left = pad_w // 2 right = pad_w - left top = pad_h // 2 bottom = pad_h - top img = TF.pad(img, [left, top, right, bottom], padding_mode='reflect') return img MODEL_INFO_PATH = Path('model_fusion_best.joblib_info.pkl') DATASET = Path('DeepfakeVsReal/Dataset') if not MODEL_INFO_PATH.exists(): raise FileNotFoundError(f'{MODEL_INFO_PATH} not found') model_info = joblib.load(str(MODEL_INFO_PATH)) state_path = model_info.get('state_dict_path') if state_path is None or not Path(state_path).exists(): raise FileNotFoundError(f'State dict not found: {state_path}') device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') model = DeepfakeFeatureFusion() model.load_state_dict(torch.load(state_path, map_location='cpu')) model.to(device) model.eval() print(f'Loaded fusion_improved model from {state_path}') transform = transforms.Compose([ transforms.Lambda(lambda img: pad_to_min_size(img, 224)), transforms.CenterCrop(224), transforms.ToTensor(), transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]) ]) def evaluate_split(split_name, split_root): if not split_root.exists(): print(f'No {split_name} folder found at {split_root}') return real_files = sorted([str(x) for x in (split_root / 'Real').rglob('*.jpg')] + [str(x) for x in (split_root / 'Real').rglob('*.png')]) fake_files = sorted([str(x) for x in (split_root / 'Fake').rglob('*.jpg')] + [str(x) for x in (split_root / 'Fake').rglob('*.png')]) files = real_files + fake_files labels = [0] * len(real_files) + [1] * len(fake_files) if not files: print(f'No {split_name} images found') return dataset = ImageDataset(files, labels, transform=transform) dataloader = DataLoader(dataset, batch_size=8, shuffle=False, num_workers=0) all_probs, all_labels = [], [] with torch.no_grad(): for inputs, lbls in dataloader: inputs = inputs.to(device) outputs = model(inputs) probs = torch.softmax(outputs, dim=1)[:, 1].cpu().numpy() all_probs.extend(probs.tolist()) all_labels.extend(lbls.tolist()) y_true = np.array(all_labels) y_prob = np.array(all_probs) y_pred = (y_prob >= 0.5).astype(int) print(f'\n{split_name} samples: {len(y_true)}') print(f'{split_name} accuracy: {accuracy_score(y_true, y_pred):.4f}') try: print(f'{split_name} ROC AUC: {roc_auc_score(y_true, y_prob):.4f}') except Exception: pass print(classification_report(y_true, y_pred)) evaluate_split('Validation', DATASET / 'Validation') evaluate_split('Test', DATASET / 'Test')