import os
import torch
import [Link] as nn
import [Link] as optim
from torchvision import datasets, transforms
from [Link] import DataLoader, random_split
import [Link] as plt
# Set your data path (make sure this matches where your dataset is in
Drive)
data_dir = '/content/database'
mean = [0.485, 0.456, 0.406]
std = [0.229, 0.224, 0.225]
batch_size = 16
num_epochs = 20
num_classes = 4 # Update if needed
device = [Link]('cuda' if [Link].is_available() else 'cpu')
print("Device:", device)
Device: cpu
class_counts = {}
for class_name in sorted([Link](data_dir)):
folder = [Link](data_dir, class_name)
if [Link](folder):
images = [f for f in [Link](folder)
if [Link]().endswith(('.jpg', '.jpeg', '.png'))]
class_counts[class_name] = len(images)
[Link](figsize=(8, 5))
[Link](class_counts.keys(), class_counts.values(), color='skyblue')
[Link]('Class')
[Link]('Number of Images')
[Link]('Dataset Distribution')
[Link](axis='y', linestyle='--', alpha=0.7)
plt.tight_layout()
[Link]()
import os, shutil
from torchvision import datasets, transforms
from [Link] import DataLoader, random_split
# ✅ Clean up .ipynb_checkpoints automatically
for root, dirs, files in [Link](data_dir):
if ".ipynb_checkpoints" in dirs:
[Link]([Link](root, ".ipynb_checkpoints"),
ignore_errors=True)
print("✅ Cleaned .ipynb_checkpoints folders")
# 🔹 Define transforms
train_transforms = [Link]([
[Link](224),
[Link](),
[Link](20),
[Link](degrees=0, shear=20),
[Link](brightness=0.2, contrast=0.2, saturation=0.2,
hue=0.1),
[Link](),
[Link](mean, std),
])
val_transforms = [Link]([
[Link]((224, 224)),
[Link](),
[Link](mean, std),
])
# 🔹 Load full dataset (with train transforms)
full_dataset = [Link](data_dir, transform=train_transforms)
# 🔹 Split into train & validation
train_size = int(0.8 * len(full_dataset))
val_size = len(full_dataset) - train_size
train_dataset, val_dataset = random_split(full_dataset, [train_size,
val_size])
# ✅ Apply val transforms correctly
# random_split returns Subset objects, so we need to "reset" transforms
val_dataset.[Link] = val_transforms
# 🔹 Dataloaders
train_loader = DataLoader(train_dataset, batch_size=batch_size,
shuffle=True, num_workers=2)
val_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False,
num_workers=2)
# 🔹 Print summary
print("Num train batches:", len(train_loader))
print("Num val batches:", len(val_loader))
✅ Cleaned .ipynb_checkpoints folders
Num train batches: 109
Num val batches: 28
from [Link] import efficientnet_v2_s,
EfficientNet_V2_S_Weights
model = efficientnet_v2_s(weights=EfficientNet_V2_S_Weights.DEFAULT)
[Link] = [Link](
[Link](p=0.3, inplace=True),
[Link]([Link][1].in_features, num_classes)
)
model = [Link](device)
criterion = [Link]()
optimizer = [Link]([Link](), lr=1e-4)
Downloading: "[Link]
[Link]" to /root/.cache/torch/hub/checkpoints/efficientnet_v2_s-
[Link]
100%|██████████| 82.7M/82.7M [00:00<00:00, 97.9MB/s]
train_losses, val_losses = [], []
train_accs, val_accs = [], []
for epoch in range(num_epochs):
[Link]()
running_loss, correct, total = 0.0, 0, 0
for batch_idx, (images, labels) in enumerate(train_loader):
images, labels = [Link](device), [Link](device)
optimizer.zero_grad()
outputs = model(images)
loss = criterion(outputs, labels)
[Link]()
[Link]()
running_loss += [Link]() * [Link](0)
_, predicted = [Link](1)
correct += [Link](labels).sum().item()
total += [Link](0)
if (batch_idx+1) % 10 == 0 or (batch_idx+1) == len(train_loader):
print(f"Epoch {epoch+1} [{batch_idx+1}/{len(train_loader)}] -
Batch Loss: {[Link]():.4f}")
train_loss = running_loss / total
train_acc = correct / total
train_losses.append(train_loss)
train_accs.append(train_acc)
# Validation
[Link]()
val_loss, val_correct, val_total = 0.0, 0, 0
with torch.no_grad():
for images, labels in val_loader:
images, labels = [Link](device), [Link](device)
outputs = model(images)
loss = criterion(outputs, labels)
val_loss += [Link]() * [Link](0)
_, predicted = [Link](1)
val_correct += [Link](labels).sum().item()
val_total += [Link](0)
val_loss = val_loss / val_total
val_acc = val_correct / val_total
val_losses.append(val_loss)
val_accs.append(val_acc)
print(f"Epoch {epoch+1}: Train Loss {train_loss:.4f}, Acc
{train_acc*100:.2f}%, "
f"Val Loss {val_loss:.4f}, Acc {val_acc*100:.2f}%")
print("✅ Training complete.")
Epoch 1 [10/106] - Batch Loss: 1.0758
Epoch 1 [20/106] - Batch Loss: 0.9236
Epoch 1 [30/106] - Batch Loss: 0.6181
Epoch 1 [40/106] - Batch Loss: 0.4881
Epoch 1 [50/106] - Batch Loss: 0.3331
Epoch 1 [60/106] - Batch Loss: 0.3191
Epoch 1 [70/106] - Batch Loss: 0.2822
Epoch 1 [80/106] - Batch Loss: 0.1582
Epoch 1 [90/106] - Batch Loss: 0.3430
Epoch 1 [100/106] - Batch Loss: 0.1673
Epoch 1 [106/106] - Batch Loss: 0.3308
Epoch 1: Train Loss 0.5283, Acc 80.61%, Val Loss 0.2381, Acc 92.18%
Epoch 2 [10/106] - Batch Loss: 0.1714
Epoch 2 [20/106] - Batch Loss: 0.2154
Epoch 2 [30/106] - Batch Loss: 0.1847
Epoch 2 [40/106] - Batch Loss: 0.1787
Epoch 2 [50/106] - Batch Loss: 0.1620
Epoch 2 [60/106] - Batch Loss: 0.2025
Epoch 2 [70/106] - Batch Loss: 0.2632
Epoch 2 [80/106] - Batch Loss: 0.2522
Epoch 2 [90/106] - Batch Loss: 0.0987
Epoch 2 [100/106] - Batch Loss: 0.1367
Epoch 2 [106/106] - Batch Loss: 0.1674
Epoch 2: Train Loss 0.1822, Acc 93.39%, Val Loss 0.2061, Acc 93.36%
Epoch 3 [10/106] - Batch Loss: 0.1124
Epoch 3 [20/106] - Batch Loss: 0.0727
Epoch 3 [30/106] - Batch Loss: 0.2946
Epoch 3 [40/106] - Batch Loss: 0.1693
Epoch 3 [50/106] - Batch Loss: 0.0663
Epoch 3 [60/106] - Batch Loss: 0.0161
Epoch 3 [70/106] - Batch Loss: 0.1229
Epoch 3 [80/106] - Batch Loss: 0.0429
Epoch 3 [90/106] - Batch Loss: 0.0208
Epoch 3 [100/106] - Batch Loss: 0.0148
Epoch 3 [106/106] - Batch Loss: 0.1050
Epoch 3: Train Loss 0.0877, Acc 97.21%, Val Loss 0.1928, Acc 93.60%
Epoch 4 [10/106] - Batch Loss: 0.0679
Epoch 4 [20/106] - Batch Loss: 0.1637
Epoch 4 [30/106] - Batch Loss: 0.1363
Epoch 4 [40/106] - Batch Loss: 0.0547
Epoch 4 [50/106] - Batch Loss: 0.0028
Epoch 4 [60/106] - Batch Loss: 0.0654
Epoch 4 [70/106] - Batch Loss: 0.0081
Epoch 4 [80/106] - Batch Loss: 0.0879
Epoch 4 [90/106] - Batch Loss: 0.0735
Epoch 4 [100/106] - Batch Loss: 0.0520
Epoch 4 [106/106] - Batch Loss: 0.0047
Epoch 4: Train Loss 0.0490, Acc 98.46%, Val Loss 0.2014, Acc 93.96%
Epoch 5 [10/106] - Batch Loss: 0.0057
Epoch 5 [20/106] - Batch Loss: 0.0086
Epoch 5 [30/106] - Batch Loss: 0.0326
Epoch 5 [40/106] - Batch Loss: 0.0162
Epoch 5 [50/106] - Batch Loss: 0.0298
Epoch 5 [60/106] - Batch Loss: 0.0089
Epoch 5 [70/106] - Batch Loss: 0.0565
Epoch 5 [80/106] - Batch Loss: 0.0191
Epoch 5 [90/106] - Batch Loss: 0.0924
Epoch 5 [100/106] - Batch Loss: 0.1392
Epoch 5 [106/106] - Batch Loss: 0.0821
Epoch 5: Train Loss 0.0402, Acc 98.75%, Val Loss 0.2887, Acc 91.23%
✅ Training complete.
model_save_path = '/content/efficientnet_v2.pth'
[Link](model.state_dict(), model_save_path)
print(f"Model saved as {model_save_path}")
Model saved as /content/efficientnet_v2.pth
import [Link] as plt
import seaborn as sns
import numpy as np
from [Link] import confusion_matrix, ConfusionMatrixDisplay
import torch
# -------------------------
# Plot Accuracy & Loss
# -------------------------
class_names = ["cataract", "diabitic retinopathy", "glaucoma", "normal"]
epochs = list(range(1, len(train_losses) + 1))
fig, ax1 = [Link](figsize=(10,6))
ax1.set_xlabel('Epoch')
ax1.set_ylabel('Accuracy (%)', color='blue')
[Link](epochs, [a*100 for a in train_accs], marker='o', linestyle='-',
color='b', label='Train Accuracy')
[Link](epochs, [a*100 for a in val_accs], marker='o', linestyle='-',
color='cyan', label='Validation Accuracy')
ax1.tick_params(axis='y', labelcolor='blue')
ax1.set_ylim(70, 100) # adjust range if needed
ax2 = [Link]()
ax2.set_ylabel('Loss', color='red')
[Link](epochs, train_losses, marker='x', linestyle='--', color='red',
label='Train Loss')
[Link](epochs, val_losses, marker='x', linestyle='--', color='orange',
label='Validation Loss')
ax2.tick_params(axis='y', labelcolor='red')
ax2.set_ylim(0, max(train_losses + val_losses) * 1.2)
lines_1, labels_1 = ax1.get_legend_handles_labels()
lines_2, labels_2 = ax2.get_legend_handles_labels()
[Link](lines_1 + lines_2, labels_1 + labels_2, loc='upper right')
[Link]('Training and Validation Accuracy & Loss over Epochs')
[Link](True, linestyle='--', alpha=0.5)
plt.tight_layout()
[Link]()
# -------------------------
# Confusion Matrix (using trained model)
# -------------------------
y_true, y_pred = [], []
[Link]()
with torch.no_grad():
for images, labels in val_loader: # <-- your validation DataLoader
images, labels = [Link](device), [Link](device)
outputs = model(images)
preds = [Link](dim=1)
y_pred.extend([Link]().numpy())
y_true.extend([Link]().numpy())
y_true = [Link](y_true)
y_pred = [Link](y_pred)
# Raw confusion matrix
cm = confusion_matrix(y_true, y_pred, labels=list(range(num_classes)))
disp = ConfusionMatrixDisplay(confusion_matrix=cm,
display_labels=class_names)
[Link](cmap="Blues", xticks_rotation=45)
[Link]("Confusion Matrix (Counts)")
[Link]()
# Normalized confusion matrix
[Link](figsize=(6,5))
cm_norm = [Link]('float') / [Link](axis=1)[:, [Link]]
[Link](cm_norm, annot=True, fmt=".2f", cmap="Blues",
xticklabels=class_names, yticklabels=class_names)
[Link]('True Label')
[Link]('Predicted Label')
[Link]('Normalized Confusion Matrix')
[Link]()
from [Link] import Dataset, DataLoader
from PIL import Image
import glob
import os
# ✅ Custom dataset for labeled test images (labels from filename)
class LabeledFlatDataset(Dataset):
def __init__(self, folder, transform=None):
[Link] = [Link]([Link](folder, "*")) # all images
[Link] = transform
# Define label mapping
self.label_map = {"cataract": 0, "diabetic": 1, "glaucoma": 2,
"normal": 3}
def __len__(self):
return len([Link])
def __getitem__(self, idx):
img_path = [Link][idx]
img = [Link](img_path).convert("RGB")
# 🔹 Extract label from filename
fname = [Link](img_path).lower()
label = None
for key, val in self.label_map.items():
if key in fname:
label = val
break
if label is None:
raise ValueError(f"Could not find label in filename: {fname}")
if [Link]:
img = [Link](img)
return img, label
# ✅ Path to test folder
test_dir = [Link](data_dir, "test")
# ✅ Create dataset & loader
test_dataset = LabeledFlatDataset(test_dir, transform=test_transforms)
test_loader = DataLoader(test_dataset, batch_size=batch_size,
shuffle=False, num_workers=2)
print("✅ Num test images:", len(test_dataset))
# ✅ Evaluate model
[Link]()
correct, total = 0, 0
with torch.no_grad():
for images, labels in test_loader:
images, labels = [Link](device), [Link](device)
outputs = model(images)
_, preds = [Link](1)
correct += [Link](labels).sum().item()
total += [Link](0)
test_acc = correct / total if total > 0 else 0
print(f"✅ Test accuracy: {test_acc*100:.2f}%")
✅ Num test images: 2561
✅ Test accuracy: 96.92%