import torch import torch.nn as nn from torch.utils.data import DataLoader, Dataset from torchvision import transforms from PIL import Image import pandas as pd import io import ast import os from sklearn.metrics import confusion_matrix, classification_report import timm class EfficientNetB0Alpha(nn.Module): def __init__(self, num_classes=26): super().__init__() self.model = timm.create_model('efficientnet_b0', pretrained=True, in_chans=1, num_classes=num_classes) def forward(self, x): return self.model(x) class Dataset(Dataset): def __init__(self, csv_path, transform=None, image_col='image', label_col='label'): self.data = pd.read_csv(csv_path) self.transform = transform self.image_col = image_col self.label_col = label_col def __len__(self): return len(self.data) def __getitem__(self, idx): img_data = self.data.iloc[idx][self.image_col] label = self.data.iloc[idx][self.label_col] if isinstance(img_data, str): img_dict = ast.literal_eval(img_data) img_bytes = img_dict['bytes'] else: img_bytes = img_data['bytes'] img = Image.open(io.BytesIO(img_bytes)).convert('L') if self.transform: img = self.transform(img) return img, label def load_model(model_path, num_classes, device): if not os.path.exists(model_path): raise FileNotFoundError(f"Model file not found at {model_path}") model = EfficientNetB0Alpha(num_classes=num_classes) checkpoint = torch.load(model_path, map_location=device, weights_only=True) model.load_state_dict(checkpoint['model_state_dict']) model.to(device) model.eval() return model def evaluate(model, test_loader, device, class_names): model.eval() correct, total = 0, 0 all_preds, all_labels = [], [] with torch.no_grad(): for images, labels in test_loader: images, labels = images.to(device), labels.to(device) outputs = model(images) _, predicted = torch.max(outputs.data, 1) total += labels.size(0) correct += (predicted == labels).sum().item() all_preds.extend(predicted.cpu().numpy()) all_labels.extend(labels.cpu().numpy()) accuracy = 100 * correct / max(total, 1) print(f"Test Accuracy: {accuracy:.2f}%") print("\nClassification Report:") print(classification_report(all_labels, all_preds, target_names=class_names, digits=2)) cm = confusion_matrix(all_labels, all_preds) print("\nConfusion Matrix (True Labels: rows, Predicted Labels: columns):") print(pd.DataFrame(cm, index=class_names, columns=class_names)) return accuracy, cm def main(): device = torch.device("cuda" if torch.cuda.is_available() else "cpu") num_classes = 26 model_path = "saved_models/best_model.pth" test_csv = "dataset/test.csv" batch_size = 32 print("Device being used:", device) test_transform = transforms.Compose([ transforms.Grayscale(num_output_channels=1), transforms.Resize((224, 224)), transforms.ToTensor(), transforms.Normalize(mean=[0.5], std=[0.5]) ]) test_dataset = Dataset(test_csv, transform=test_transform) test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False, num_workers=4, pin_memory=True) class_names = [chr(65 + i) for i in range(26)] model = load_model(model_path, num_classes, device) evaluate(model, test_loader, device, class_names) if __name__ == "__main__": main()