0% found this document useful (0 votes)
15 views35 pages

Skin Disease Detection Using Transformers

This document outlines a Python script for training a deep learning model to classify skin diseases using a dataset of images. It includes data preprocessing, model training with early stopping, and evaluation metrics such as accuracy and confusion matrix visualization. The model is built using the DeiT architecture and leverages libraries like PyTorch and torchvision for implementation.

Uploaded by

shibilbasith4u
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
15 views35 pages

Skin Disease Detection Using Transformers

This document outlines a Python script for training a deep learning model to classify skin diseases using a dataset of images. It includes data preprocessing, model training with early stopping, and evaluation metrics such as accuracy and confusion matrix visualization. The model is built using the DeiT architecture and leverages libraries like PyTorch and torchvision for implementation.

Uploaded by

shibilbasith4u
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 35

# This Python 3 environment comes with many helpful analytics

libraries installed
# It is defined by the kaggle/python Docker image:
https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra


import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the read-only "../input/"


directory
# For example, running this (by clicking run or pressing Shift+Enter)
will list all files under the input directory

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
for filename in filenames:
print(os.path.join(dirname, filename))

# You can write up to 20GB to the current directory (/kaggle/working/)


that gets preserved as output when you create a version using "Save &
Run All"
# You can also write temporary files to /kaggle/temp/, but they won't
be saved outside of the current session

import os
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from tqdm import tqdm

from sklearn.model_selection import train_test_split


from sklearn.metrics import classification_report, confusion_matrix,
accuracy_score

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from torch.optim.lr_scheduler import CosineAnnealingLR

from torchvision import transforms


from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

# For DeiT model


import timm
# Set random seeds for reproducibility
SEED = 42
random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)
torch.cuda.manual_seed(SEED)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = True

# Set paths to dataset directories


Eczema_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/1. Eczema
1677'
Warts_Molluscum_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/10. Warts
Molluscum and other Viral Infections - 2103'
Atopic_Dermatitis_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/3. Atopic
Dermatitis - 1.25k'
Melanocytic_Nevi_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/5. Melanocytic
Nevi (NV) - 7970'
Psoriasis_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/7. Psoriasis
pictures Lichen Planus and related diseases - 2k'
Seborrheic_Keratoses_dir = r'/kaggle/input/skin-diseases-image-
dataset/IMG_CLASSES/8. Seborrheic Keratoses and other Benign Tumors -
1.8k'
Tinea_Ringworm_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/9. Tinea
Ringworm Candidiasis and other Fungal Infections - 1.7k'

# Class names corresponding to the directories


class_labels = [
'Eczema',
'Warts Molluscum and other Viral Infections',
'Atopic Dermatitis',
'Melanocytic Nevi',
'Psoriasis pictures Lichen Planus and related diseases',
'Seborrheic Keratoses and other Benign Tumors',
'Tinea Ringworm Candidiasis and other Fungal Infections'
]

# List of directories
directories = [Eczema_dir, Warts_Molluscum_dir, Atopic_Dermatitis_dir,
Melanocytic_Nevi_dir, Psoriasis_dir,
Seborrheic_Keratoses_dir,
Tinea_Ringworm_dir]
# Create dataframe with file paths and labels
filepaths, labels = [], []
for i, directory in enumerate(directories):
for filename in os.listdir(directory):
filepath = os.path.join(directory, filename)
filepaths.append(filepath)
labels.append(i) # Use numerical labels

skin_df = pd.DataFrame({'filepaths': filepaths, 'labels': labels})


print(f"Total images: {len(skin_df)}")
print(skin_df['labels'].value_counts())

# Split data into train, validation, and test sets


train_val_df, test_df = train_test_split(skin_df, test_size=0.15,
random_state=SEED, stratify=skin_df['labels'])
train_df, val_df = train_test_split(train_val_df, test_size=0.15,
random_state=SEED, stratify=train_val_df['labels'])
print(f"Training set: {len(train_df)} images")
print(f"Validation set: {len(val_df)} images")
print(f"Test set: {len(test_df)} images")

# Define image size and hyperparameters


IMG_SIZE = 224
NUM_CLASSES = len(class_labels)
BATCH_SIZE = 32
EPOCHS = 25

# Define transforms
train_transforms = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)),
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomVerticalFlip(p=0.2),
transforms.RandomRotation(30),
transforms.ColorJitter(brightness=0.2, contrast=0.2,
saturation=0.2, hue=0.1),
transforms.RandomAffine(degrees=0, translate=(0.1, 0.1),
scale=(0.9, 1.1)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229,
0.224, 0.225]),
transforms.RandomErasing(p=0.2)
])

val_test_transforms = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229,
0.224, 0.225])
])
# Create custom dataset class
class SkinDiseaseDataset(Dataset):
def __init__(self, dataframe, transform=None):
self.dataframe = dataframe
self.transform = transform

def __len__(self):
return len(self.dataframe)

def __getitem__(self, idx):


img_path = self.dataframe.iloc[idx]['filepaths']
label = self.dataframe.iloc[idx]['labels']
try:
image = Image.open(img_path).convert('RGB')
if self.transform:
image = self.transform(image)
return image, label
except Exception as e:
print(f"Error loading image {img_path}: {e}")
placeholder = torch.zeros((3, IMG_SIZE, IMG_SIZE))
return placeholder, label

# Create datasets
train_dataset = SkinDiseaseDataset(train_df,
transform=train_transforms)
val_dataset = SkinDiseaseDataset(val_df,
transform=val_test_transforms)
test_dataset = SkinDiseaseDataset(test_df,
transform=val_test_transforms)

# Create dataloaders
num_workers = 4
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE,
shuffle=True,
num_workers=num_workers, pin_memory=True,
persistent_workers=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE,
shuffle=False,
num_workers=num_workers, pin_memory=True,
persistent_workers=True)
test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE,
shuffle=False,
num_workers=num_workers, pin_memory=True)

# Set device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# Initialize the DeiT model from timm


# DeiT-Small (deit_small_patch16_224) is known for its efficiency on
smaller datasets.
model = timm.create_model("deit_small_patch16_224", pretrained=True,
num_classes=NUM_CLASSES)
model = model.to(device)

# Define loss function; label smoothing can help generalization.


criterion = nn.CrossEntropyLoss(label_smoothing=0.1)

# Define optimizer with differential learning rates:


# Lower LR for pretrained parameters and higher LR for the classifier
head.
optimizer = optim.AdamW([
{'params': model.patch_embed.parameters(), 'lr': 1e-5},
{'params': model.blocks.parameters(), 'lr': 1e-5},
{'params': model.norm.parameters(), 'lr': 1e-5},
{'params': model.head.parameters(), 'lr': 1e-4}
], weight_decay=0.01)

# Learning rate scheduler with cosine annealing


scheduler = CosineAnnealingLR(optimizer, T_max=10, eta_min=1e-6)

# Early stopping implementation


class EarlyStopping:
def __init__(self, patience=7, min_delta=0, verbose=True):
self.patience = patience
self.min_delta = min_delta
self.verbose = verbose
self.counter = 0
self.best_score = None
self.early_stop = False
self.val_loss_min = np.Inf

def __call__(self, val_loss, model, path):


score = -val_loss
if self.best_score is None:
self.best_score = score
self.save_checkpoint(val_loss, model, path)
elif score < self.best_score + self.min_delta:
self.counter += 1
if self.verbose:
print(f'EarlyStopping counter: {self.counter} out of
{self.patience}')
if self.counter >= self.patience:
self.early_stop = True
else:
self.best_score = score
self.save_checkpoint(val_loss, model, path)
self.counter = 0

def save_checkpoint(self, val_loss, model, path):


if self.verbose:
print(f'Validation loss decreased ({self.val_loss_min:.6f}
--> {val_loss:.6f}). Saving model...')
torch.save(model.state_dict(), path)
self.val_loss_min = val_loss

early_stopping = EarlyStopping(patience=8, verbose=True)

# Training function
def train_model(model, train_loader, val_loader, criterion, optimizer,
scheduler, num_epochs):
train_losses, val_losses = [], []
train_accs, val_accs = [], []
best_val_acc = 0.0
best_model_path = 'best_deit_skin_model.pth'

for epoch in range(num_epochs):


model.train()
running_loss, correct, total = 0.0, 0, 0
train_bar = tqdm(train_loader, desc=f'Epoch
{epoch+1}/{num_epochs} [Train]')
for inputs, labels in train_bar:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(),
max_norm=1.0)
optimizer.step()

running_loss += loss.item() * inputs.size(0)


_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
train_bar.set_postfix(loss=loss.item(),
acc=100.*correct/total)

epoch_train_loss = running_loss / len(train_loader.dataset)


epoch_train_acc = 100. * correct / total

# Validation phase
model.eval()
running_loss, correct, total = 0.0, 0, 0
with torch.no_grad():
val_bar = tqdm(val_loader, desc=f'Epoch
{epoch+1}/{num_epochs} [Val]')
for inputs, labels in val_bar:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
running_loss += loss.item() * inputs.size(0)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
val_bar.set_postfix(loss=loss.item(),
acc=100.*correct/total)

epoch_val_loss = running_loss / len(val_loader.dataset)


epoch_val_acc = 100. * correct / total

scheduler.step()

train_losses.append(epoch_train_loss)
val_losses.append(epoch_val_loss)
train_accs.append(epoch_train_acc)
val_accs.append(epoch_val_acc)

print(f'\nEpoch {epoch+1}/{num_epochs}:')
print(f'Train Loss: {epoch_train_loss:.4f}, Train Acc:
{epoch_train_acc:.2f}%')
print(f'Val Loss: {epoch_val_loss:.4f}, Val Acc:
{epoch_val_acc:.2f}%')
print(f'Learning rate: {scheduler.get_last_lr()[0]:.6f}')

if epoch_val_acc > best_val_acc:


print(f'New best model! Val Acc: {epoch_val_acc:.2f}%')
best_val_acc = epoch_val_acc
torch.save(model.state_dict(), best_model_path)

early_stopping(epoch_val_loss, model, best_model_path)


if early_stopping.early_stop:
print("Early stopping triggered")
break

model.load_state_dict(torch.load(best_model_path))
return model, train_losses, val_losses, train_accs, val_accs

print("Starting training with DeiT-Small...")


trained_model, train_losses, val_losses, train_accs, val_accs =
train_model(
model, train_loader, val_loader, criterion, optimizer, scheduler,
EPOCHS
)

# Plot training history


plt.figure(figsize=(15, 5))
plt.subplot(1, 2, 1)
plt.plot(train_losses, label='Train Loss')
plt.plot(val_losses, label='Val Loss')
plt.title('Loss')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(train_accs, label='Train Acc')
plt.plot(val_accs, label='Val Acc')
plt.title('Accuracy')
plt.legend()
plt.tight_layout()
plt.show()

# Evaluation on test set


def evaluate_model(model, test_loader):
model.eval()
all_preds, all_labels = [], []
with torch.no_grad():
for inputs, labels in tqdm(test_loader, desc="Evaluating"):
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
all_preds.extend(preds.cpu().numpy())
all_labels.extend(labels.cpu().numpy())

test_acc = accuracy_score(all_labels, all_preds) * 100


print(f"\nTest Accuracy: {test_acc:.2f}%")
print("\nClassification Report:")
print(classification_report(all_labels, all_preds,
target_names=class_labels))

cm = confusion_matrix(all_labels, all_preds)
plt.figure(figsize=(14, 10))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_labels, yticklabels=class_labels)
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('Confusion Matrix')
plt.tight_layout()
plt.show()

class_accuracy = cm.diagonal() / cm.sum(axis=1) * 100


for i, acc in enumerate(class_accuracy):
print(f"{class_labels[i]}: {acc:.2f}%")
return test_acc

test_accuracy = evaluate_model(trained_model, test_loader)

# Save the final model


torch.save({
'model_state_dict': trained_model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'test_accuracy': test_accuracy,
'class_labels': class_labels
}, 'deit_skin_disease_classifier.pth')
print("Model saved as 'deit_skin_disease_classifier.pth'")

# Function to visualize test predictions


def visualize_predictions(model, test_loader, class_labels,
num_images=10):
model.eval()
images, labels = next(iter(test_loader))
images, labels = images[:num_images].to(device),
labels[:num_images].to(device)
with torch.no_grad():
outputs = model(images)
_, preds = torch.max(outputs, 1)
probs = F.softmax(outputs, dim=1)

images_cpu = images.cpu()
mean = torch.tensor([0.485, 0.456, 0.406]).view(3, 1, 1)
std = torch.tensor([0.229, 0.224, 0.225]).view(3, 1, 1)
images_display = images_cpu * std + mean
images_display = torch.clamp(images_display, 0, 1)

plt.figure(figsize=(20, 20))
for i in range(num_images):
plt.subplot(5, 2, i+1)
plt.imshow(images_display[i].permute(1, 2, 0))
true_label = class_labels[labels[i]]
pred_label = class_labels[preds[i]]
confidence = probs[i, preds[i]] * 100
title_color = "green" if preds[i] == labels[i] else "red"
plt.title(f"True: {true_label}\nPred: {pred_label}\nConf:
{confidence:.1f}%",
color=title_color, fontsize=12)
plt.axis('off')
plt.tight_layout()
plt.show()

visualize_predictions(trained_model, test_loader, class_labels)

Total images: 18611


labels
3 7970
1 2103
4 2055
5 1847
6 1702
0 1677
2 1257
Name: count, dtype: int64
Training set: 13446 images
Validation set: 2373 images
Test set: 2792 images
Using device: cuda

{"model_id":"2167c72085894f90af8700ee09574af5","version_major":2,"vers
ion_minor":0}

Starting training with DeiT-Small...

Epoch 1/25 [Train]: 100%|██████████| 421/421 [02:15<00:00, 3.10it/s,


acc=63, loss=0.78]
Epoch 1/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.27it/s,
acc=71.8, loss=1.32]

Epoch 1/25:
Train Loss: 1.1584, Train Acc: 62.96%
Val Loss: 1.0298, Val Acc: 71.85%
Learning rate: 0.000010
New best model! Val Acc: 71.85%
Validation loss decreased (inf --> 1.029822). Saving model...

Epoch 2/25 [Train]: 100%|██████████| 421/421 [02:38<00:00, 2.65it/s,


acc=72.5, loss=1.09]
Epoch 2/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 6.94it/s,
acc=74.6, loss=1.42]

Epoch 2/25:
Train Loss: 0.9978, Train Acc: 72.54%
Val Loss: 0.9596, Val Acc: 74.63%
Learning rate: 0.000009
New best model! Val Acc: 74.63%
Validation loss decreased (1.029822 --> 0.959599). Saving model...

Epoch 3/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,


acc=76.5, loss=0.926]
Epoch 3/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.44it/s,
acc=77.3, loss=1.53]

Epoch 3/25:
Train Loss: 0.9285, Train Acc: 76.45%
Val Loss: 0.9297, Val Acc: 77.29%
Learning rate: 0.000008
New best model! Val Acc: 77.29%
Validation loss decreased (0.959599 --> 0.929710). Saving model...

Epoch 4/25 [Train]: 100%|██████████| 421/421 [02:41<00:00, 2.61it/s,


acc=79.2, loss=0.956]
Epoch 4/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.26it/s,
acc=78.1, loss=1.39]

Epoch 4/25:
Train Loss: 0.8770, Train Acc: 79.21%
Val Loss: 0.8981, Val Acc: 78.09%
Learning rate: 0.000007
New best model! Val Acc: 78.09%
Validation loss decreased (0.929710 --> 0.898150). Saving model...

Epoch 5/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,


acc=81.2, loss=0.568]
Epoch 5/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.40it/s,
acc=79.7, loss=1.44]

Epoch 5/25:
Train Loss: 0.8433, Train Acc: 81.21%
Val Loss: 0.8846, Val Acc: 79.73%
Learning rate: 0.000005
New best model! Val Acc: 79.73%
Validation loss decreased (0.898150 --> 0.884619). Saving model...

Epoch 6/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,


acc=83.1, loss=0.545]
Epoch 6/25 [Val]: 100%|██████████| 75/75 [00:09<00:00, 7.54it/s,
acc=80, loss=1.28]

Epoch 6/25:
Train Loss: 0.8084, Train Acc: 83.07%
Val Loss: 0.8753, Val Acc: 80.03%
Learning rate: 0.000004
New best model! Val Acc: 80.03%
Validation loss decreased (0.884619 --> 0.875315). Saving model...

Epoch 7/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,


acc=84.5, loss=0.564]
Epoch 7/25 [Val]: 100%|██████████| 75/75 [00:09<00:00, 7.56it/s,
acc=80.2, loss=1.43]

Epoch 7/25:
Train Loss: 0.7830, Train Acc: 84.47%
Val Loss: 0.8654, Val Acc: 80.24%
Learning rate: 0.000003
New best model! Val Acc: 80.24%
Validation loss decreased (0.875315 --> 0.865395). Saving model...
Epoch 8/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.63it/s,
acc=85.5, loss=0.988]
Epoch 8/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.12it/s,
acc=80.9, loss=1.43]

Epoch 8/25:
Train Loss: 0.7629, Train Acc: 85.54%
Val Loss: 0.8615, Val Acc: 80.91%
Learning rate: 0.000002
New best model! Val Acc: 80.91%
Validation loss decreased (0.865395 --> 0.861548). Saving model...

Epoch 9/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.63it/s,


acc=86.5, loss=0.781]
Epoch 9/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 6.98it/s,
acc=81.4, loss=1.38]

Epoch 9/25:
Train Loss: 0.7460, Train Acc: 86.48%
Val Loss: 0.8501, Val Acc: 81.42%
Learning rate: 0.000001
New best model! Val Acc: 81.42%
Validation loss decreased (0.861548 --> 0.850144). Saving model...

Epoch 10/25 [Train]: 100%|██████████| 421/421 [02:41<00:00, 2.61it/s,


acc=86.8, loss=1.04]
Epoch 10/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.12it/s,
acc=81.8, loss=1.33]

Epoch 10/25:
Train Loss: 0.7394, Train Acc: 86.77%
Val Loss: 0.8483, Val Acc: 81.75%
Learning rate: 0.000001
New best model! Val Acc: 81.75%
Validation loss decreased (0.850144 --> 0.848337). Saving model...

Epoch 11/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.63it/s,


acc=87.1, loss=0.964]
Epoch 11/25 [Val]: 100%|██████████| 75/75 [00:09<00:00, 7.59it/s,
acc=81.8, loss=1.34]

Epoch 11/25:
Train Loss: 0.7318, Train Acc: 87.10%
Val Loss: 0.8461, Val Acc: 81.80%
Learning rate: 0.000001
New best model! Val Acc: 81.80%
Validation loss decreased (0.848337 --> 0.846072). Saving model...
Epoch 12/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.63it/s,
acc=87.4, loss=0.528]
Epoch 12/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.53it/s,
acc=81.5, loss=1.39]

Epoch 12/25:
Train Loss: 0.7276, Train Acc: 87.38%
Val Loss: 0.8438, Val Acc: 81.50%
Learning rate: 0.000002
Validation loss decreased (0.846072 --> 0.843824). Saving model...

Epoch 13/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.63it/s,


acc=86.9, loss=0.702]
Epoch 13/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 6.87it/s,
acc=82, loss=1.37]

Epoch 13/25:
Train Loss: 0.7273, Train Acc: 86.92%
Val Loss: 0.8407, Val Acc: 82.05%
Learning rate: 0.000003
New best model! Val Acc: 82.05%
Validation loss decreased (0.843824 --> 0.840723). Saving model...

Epoch 14/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.64it/s,


acc=87.3, loss=0.631]
Epoch 14/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.76it/s,
acc=82.2, loss=1.46]

Epoch 14/25:
Train Loss: 0.7229, Train Acc: 87.30%
Val Loss: 0.8413, Val Acc: 82.22%
Learning rate: 0.000004
New best model! Val Acc: 82.22%
EarlyStopping counter: 1 out of 8

Epoch 15/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.63it/s,


acc=87.9, loss=0.725]
Epoch 15/25 [Val]: 100%|██████████| 75/75 [00:09<00:00, 7.55it/s,
acc=81.7, loss=1.71]

Epoch 15/25:
Train Loss: 0.7169, Train Acc: 87.86%
Val Loss: 0.8452, Val Acc: 81.67%
Learning rate: 0.000006
EarlyStopping counter: 2 out of 8
Epoch 16/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.63it/s,
acc=88.4, loss=0.611]
Epoch 16/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.19it/s,
acc=82.4, loss=1.6]

Epoch 16/25:
Train Loss: 0.7036, Train Acc: 88.38%
Val Loss: 0.8389, Val Acc: 82.43%
Learning rate: 0.000007
New best model! Val Acc: 82.43%
Validation loss decreased (0.840723 --> 0.838917). Saving model...

Epoch 17/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.64it/s,


acc=88.9, loss=1.08]
Epoch 17/25 [Val]: 100%|██████████| 75/75 [00:09<00:00, 7.52it/s,
acc=82.8, loss=1.48]

Epoch 17/25:
Train Loss: 0.6980, Train Acc: 88.92%
Val Loss: 0.8315, Val Acc: 82.81%
Learning rate: 0.000008
New best model! Val Acc: 82.81%
Validation loss decreased (0.838917 --> 0.831526). Saving model...

Epoch 18/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.64it/s,


acc=89.4, loss=0.794]
Epoch 18/25 [Val]: 100%|██████████| 75/75 [00:09<00:00, 7.53it/s,
acc=82.7, loss=1.72]

Epoch 18/25:
Train Loss: 0.6882, Train Acc: 89.39%
Val Loss: 0.8377, Val Acc: 82.68%
Learning rate: 0.000009
EarlyStopping counter: 1 out of 8

Epoch 19/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.64it/s,


acc=90, loss=0.596]
Epoch 19/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.03it/s,
acc=83.1, loss=1.63]

Epoch 19/25:
Train Loss: 0.6723, Train Acc: 89.98%
Val Loss: 0.8220, Val Acc: 83.14%
Learning rate: 0.000010
New best model! Val Acc: 83.14%
Validation loss decreased (0.831526 --> 0.822037). Saving model...
Epoch 20/25 [Train]: 100%|██████████| 421/421 [02:39<00:00, 2.63it/s,
acc=90.7, loss=0.489]
Epoch 20/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 6.99it/s,
acc=83.7, loss=1.24]

Epoch 20/25:
Train Loss: 0.6603, Train Acc: 90.65%
Val Loss: 0.8140, Val Acc: 83.73%
Learning rate: 0.000010
New best model! Val Acc: 83.73%
Validation loss decreased (0.822037 --> 0.814007). Saving model...

Epoch 21/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,


acc=91.8, loss=0.598]
Epoch 21/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.10it/s,
acc=84, loss=1.78]

Epoch 21/25:
Train Loss: 0.6399, Train Acc: 91.83%
Val Loss: 0.8170, Val Acc: 83.99%
Learning rate: 0.000010
New best model! Val Acc: 83.99%
EarlyStopping counter: 1 out of 8

Epoch 22/25 [Train]: 100%|██████████| 421/421 [02:37<00:00, 2.67it/s,


acc=92.9, loss=0.489]
Epoch 22/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.51it/s,
acc=83.9, loss=1.54]

Epoch 22/25:
Train Loss: 0.6229, Train Acc: 92.86%
Val Loss: 0.8256, Val Acc: 83.94%
Learning rate: 0.000009
EarlyStopping counter: 2 out of 8

Epoch 23/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,


acc=93.5, loss=0.524]
Epoch 23/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.79it/s,
acc=83.8, loss=1.64]

Epoch 23/25:
Train Loss: 0.6058, Train Acc: 93.53%
Val Loss: 0.8290, Val Acc: 83.82%
Learning rate: 0.000008
EarlyStopping counter: 3 out of 8
Epoch 24/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.62it/s,
acc=94, loss=0.453]
Epoch 24/25 [Val]: 100%|██████████| 75/75 [00:11<00:00, 6.37it/s,
acc=84.1, loss=1.74]

Epoch 24/25:
Train Loss: 0.5942, Train Acc: 93.98%
Val Loss: 0.8192, Val Acc: 84.07%
Learning rate: 0.000007
New best model! Val Acc: 84.07%
EarlyStopping counter: 4 out of 8

Epoch 25/25 [Train]: 100%|██████████| 421/421 [02:40<00:00, 2.63it/s,


acc=95.3, loss=0.481]
Epoch 25/25 [Val]: 100%|██████████| 75/75 [00:10<00:00, 7.16it/s,
acc=84.7, loss=1.83]
<ipython-input-1-6043d5d80d21>:268: FutureWarning: You are using
`torch.load` with `weights_only=False` (the current default value),
which uses the default pickle module implicitly. It is possible to
construct malicious pickle data which will execute arbitrary code
during unpickling (See
https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-
models for more details). In a future release, the default value for
`weights_only` will be flipped to `True`. This limits the functions
that could be executed during unpickling. Arbitrary objects will no
longer be allowed to be loaded via this mode unless they are
explicitly allowlisted by the user via
`torch.serialization.add_safe_globals`. We recommend you start setting
`weights_only=True` for any use case where you don't have full control
of the loaded file. Please open an issue on GitHub for any issues
related to this experimental feature.
model.load_state_dict(torch.load(best_model_path))

Epoch 25/25:
Train Loss: 0.5767, Train Acc: 95.28%
Val Loss: 0.8198, Val Acc: 84.75%
Learning rate: 0.000006
New best model! Val Acc: 84.75%
EarlyStopping counter: 5 out of 8
Evaluating: 100%|██████████| 88/88 [00:14<00:00, 5.96it/s]

Test Accuracy: 84.31%

Classification Report:
precision
recall f1-score support

Eczema 0.75
0.64 0.69 252
Warts Molluscum and other Viral Infections 0.68
0.83 0.75 315
Atopic Dermatitis 0.64
0.66 0.65 189
Melanocytic Nevi 0.99
1.00 1.00 1196
Psoriasis pictures Lichen Planus and related diseases 0.69
0.70 0.70 308
Seborrheic Keratoses and other Benign Tumors 0.90
0.71 0.79 277
Tinea Ringworm Candidiasis and other Fungal Infections 0.76
0.78 0.77 255

accuracy
0.84 2792
macro avg 0.77
0.76 0.76 2792
weighted avg 0.85
0.84 0.84 2792
Eczema: 64.29%
Warts Molluscum and other Viral Infections: 83.17%
Atopic Dermatitis: 66.14%
Melanocytic Nevi: 99.75%
Psoriasis pictures Lichen Planus and related diseases: 69.81%
Seborrheic Keratoses and other Benign Tumors: 71.12%
Tinea Ringworm Candidiasis and other Fungal Infections: 78.43%
Model saved as 'deit_skin_disease_classifier.pth'
import os
import random
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from tqdm import tqdm

from sklearn.model_selection import train_test_split


from sklearn.metrics import classification_report, confusion_matrix,
accuracy_score

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader
from torch.optim.lr_scheduler import CosineAnnealingLR

from torchvision import transforms


from PIL import Image, ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True

# For ViT model


import timm

# Set random seeds for reproducibility


SEED = 42
random.seed(SEED)
np.random.seed(SEED)
torch.manual_seed(SEED)
torch.cuda.manual_seed(SEED)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = True

# Set paths to dataset directories


Eczema_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/1. Eczema
1677'
Warts_Molluscum_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/10. Warts
Molluscum and other Viral Infections - 2103'
Atopic_Dermatitis_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/3. Atopic
Dermatitis - 1.25k'
Melanocytic_Nevi_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/5. Melanocytic
Nevi (NV) - 7970'
Psoriasis_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/7. Psoriasis
pictures Lichen Planus and related diseases - 2k'
Seborrheic_Keratoses_dir = r'/kaggle/input/skin-diseases-image-
dataset/IMG_CLASSES/8. Seborrheic Keratoses and other Benign Tumors -
1.8k'
Tinea_Ringworm_dir =
r'/kaggle/input/skin-diseases-image-dataset/IMG_CLASSES/9. Tinea
Ringworm Candidiasis and other Fungal Infections - 1.7k'

# Class names corresponding to the directories


class_labels = [
'Eczema',
'Warts Molluscum and other Viral Infections',
'Atopic Dermatitis',
'Melanocytic Nevi',
'Psoriasis pictures Lichen Planus and related diseases',
'Seborrheic Keratoses and other Benign Tumors',
'Tinea Ringworm Candidiasis and other Fungal Infections'
]

# List of directories
directories = [Eczema_dir, Warts_Molluscum_dir, Atopic_Dermatitis_dir,
Melanocytic_Nevi_dir, Psoriasis_dir,
Seborrheic_Keratoses_dir,
Tinea_Ringworm_dir]

# Create dataframe with file paths and labels


filepaths, labels = [], []
for i, directory in enumerate(directories):
for filename in os.listdir(directory):
filepath = os.path.join(directory, filename)
filepaths.append(filepath)
labels.append(i) # Use numerical labels

skin_df = pd.DataFrame({'filepaths': filepaths, 'labels': labels})


print(f"Total images: {len(skin_df)}")
print(skin_df['labels'].value_counts())

# Split data into train, validation, and test sets


train_val_df, test_df = train_test_split(skin_df, test_size=0.15,
random_state=SEED, stratify=skin_df['labels'])
train_df, val_df = train_test_split(train_val_df, test_size=0.15,
random_state=SEED, stratify=train_val_df['labels'])
print(f"Training set: {len(train_df)} images")
print(f"Validation set: {len(val_df)} images")
print(f"Test set: {len(test_df)} images")

# Define image size and hyperparameters


IMG_SIZE = 224
NUM_CLASSES = len(class_labels)
BATCH_SIZE = 32
EPOCHS = 25

# Define transforms
train_transforms = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)),
transforms.RandomHorizontalFlip(p=0.5),
transforms.RandomVerticalFlip(p=0.2),
transforms.RandomRotation(30),
transforms.ColorJitter(brightness=0.2, contrast=0.2,
saturation=0.2, hue=0.1),
transforms.RandomAffine(degrees=0, translate=(0.1, 0.1),
scale=(0.9, 1.1)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229,
0.224, 0.225]),
transforms.RandomErasing(p=0.2)
])

val_test_transforms = transforms.Compose([
transforms.Resize((IMG_SIZE, IMG_SIZE)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229,
0.224, 0.225])
])

# Create custom dataset class


class SkinDiseaseDataset(Dataset):
def __init__(self, dataframe, transform=None):
self.dataframe = dataframe
self.transform = transform

def __len__(self):
return len(self.dataframe)

def __getitem__(self, idx):


img_path = self.dataframe.iloc[idx]['filepaths']
label = self.dataframe.iloc[idx]['labels']
try:
image = Image.open(img_path).convert('RGB')
if self.transform:
image = self.transform(image)
return image, label
except Exception as e:
print(f"Error loading image {img_path}: {e}")
placeholder = torch.zeros((3, IMG_SIZE, IMG_SIZE))
return placeholder, label

# Create datasets
train_dataset = SkinDiseaseDataset(train_df,
transform=train_transforms)
val_dataset = SkinDiseaseDataset(val_df,
transform=val_test_transforms)
test_dataset = SkinDiseaseDataset(test_df,
transform=val_test_transforms)

# Create dataloaders
num_workers = 4
train_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE,
shuffle=True,
num_workers=num_workers, pin_memory=True,
persistent_workers=True)
val_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE,
shuffle=False,
num_workers=num_workers, pin_memory=True,
persistent_workers=True)
test_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE,
shuffle=False,
num_workers=num_workers, pin_memory=True)

# Set device
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# Initialize the Vision Transformer (ViT) model from timm


# Here we use vit_base_patch16_224, which has proven widely effective.
model = timm.create_model("vit_base_patch16_224", pretrained=True,
num_classes=NUM_CLASSES)
model = model.to(device)

# Define loss function with label smoothing


criterion = nn.CrossEntropyLoss(label_smoothing=0.1)

# Define optimizer.
# Note: Optionally you can adjust differential learning rates for
transformer layers if needed.
optimizer = optim.AdamW(model.parameters(), lr=1e-4,
weight_decay=0.01)

# Learning rate scheduler with cosine annealing


scheduler = CosineAnnealingLR(optimizer, T_max=10, eta_min=1e-6)

# Early stopping implementation


class EarlyStopping:
def __init__(self, patience=7, min_delta=0, verbose=True):
self.patience = patience
self.min_delta = min_delta
self.verbose = verbose
self.counter = 0
self.best_score = None
self.early_stop = False
self.val_loss_min = np.Inf

def __call__(self, val_loss, model, path):


score = -val_loss
if self.best_score is None:
self.best_score = score
self.save_checkpoint(val_loss, model, path)
elif score < self.best_score + self.min_delta:
self.counter += 1
if self.verbose:
print(f'EarlyStopping counter: {self.counter} out of
{self.patience}')
if self.counter >= self.patience:
self.early_stop = True
else:
self.best_score = score
self.save_checkpoint(val_loss, model, path)
self.counter = 0

def save_checkpoint(self, val_loss, model, path):


if self.verbose:
print(f'Validation loss decreased ({self.val_loss_min:.6f}
--> {val_loss:.6f}). Saving model...')
torch.save(model.state_dict(), path)
self.val_loss_min = val_loss

early_stopping = EarlyStopping(patience=8, verbose=True)

# Training function
def train_model(model, train_loader, val_loader, criterion, optimizer,
scheduler, num_epochs):
train_losses, val_losses = [], []
train_accs, val_accs = [], []
best_val_acc = 0.0
best_model_path = 'best_vit_skin_model.pth'

for epoch in range(num_epochs):


model.train()
running_loss, correct, total = 0.0, 0, 0
train_bar = tqdm(train_loader, desc=f'Epoch
{epoch+1}/{num_epochs} [Train]')
for inputs, labels in train_bar:
inputs, labels = inputs.to(device), labels.to(device)
optimizer.zero_grad()
outputs = model(inputs)
loss = criterion(outputs, labels)
loss.backward()
torch.nn.utils.clip_grad_norm_(model.parameters(),
max_norm=1.0)
optimizer.step()
running_loss += loss.item() * inputs.size(0)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
train_bar.set_postfix(loss=loss.item(),
acc=100.*correct/total)

epoch_train_loss = running_loss / len(train_loader.dataset)


epoch_train_acc = 100. * correct / total

# Validation phase
model.eval()
running_loss, correct, total = 0.0, 0, 0
with torch.no_grad():
val_bar = tqdm(val_loader, desc=f'Epoch
{epoch+1}/{num_epochs} [Val]')
for inputs, labels in val_bar:
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
loss = criterion(outputs, labels)
running_loss += loss.item() * inputs.size(0)
_, predicted = outputs.max(1)
total += labels.size(0)
correct += predicted.eq(labels).sum().item()
val_bar.set_postfix(loss=loss.item(),
acc=100.*correct/total)

epoch_val_loss = running_loss / len(val_loader.dataset)


epoch_val_acc = 100. * correct / total

scheduler.step()
train_losses.append(epoch_train_loss)
val_losses.append(epoch_val_loss)
train_accs.append(epoch_train_acc)
val_accs.append(epoch_val_acc)

print(f'\nEpoch {epoch+1}/{num_epochs}:')
print(f'Train Loss: {epoch_train_loss:.4f}, Train Acc:
{epoch_train_acc:.2f}%')
print(f'Val Loss: {epoch_val_loss:.4f}, Val Acc:
{epoch_val_acc:.2f}%')
print(f'Learning rate: {scheduler.get_last_lr()[0]:.6f}')

if epoch_val_acc > best_val_acc:


print(f'New best model! Val Acc: {epoch_val_acc:.2f}%')
best_val_acc = epoch_val_acc
torch.save(model.state_dict(), best_model_path)

early_stopping(epoch_val_loss, model, best_model_path)


if early_stopping.early_stop:
print("Early stopping triggered")
break

model.load_state_dict(torch.load(best_model_path))
return model, train_losses, val_losses, train_accs, val_accs

print("Starting training with ViT Base...")


trained_model, train_losses, val_losses, train_accs, val_accs =
train_model(
model, train_loader, val_loader, criterion, optimizer, scheduler,
EPOCHS
)

# Plot training history


plt.figure(figsize=(15, 5))
plt.subplot(1, 2, 1)
plt.plot(train_losses, label='Train Loss')
plt.plot(val_losses, label='Val Loss')
plt.title('Loss')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(train_accs, label='Train Acc')
plt.plot(val_accs, label='Val Acc')
plt.title('Accuracy')
plt.legend()
plt.tight_layout()
plt.show()

# Evaluation on test set


def evaluate_model(model, test_loader):
model.eval()
all_preds, all_labels = [], []
with torch.no_grad():
for inputs, labels in tqdm(test_loader, desc="Evaluating"):
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
_, preds = torch.max(outputs, 1)
all_preds.extend(preds.cpu().numpy())
all_labels.extend(labels.cpu().numpy())

test_acc = accuracy_score(all_labels, all_preds) * 100


print(f"\nTest Accuracy: {test_acc:.2f}%")
print("\nClassification Report:")
print(classification_report(all_labels, all_preds,
target_names=class_labels))

cm = confusion_matrix(all_labels, all_preds)
plt.figure(figsize=(14, 10))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_labels, yticklabels=class_labels)
plt.xlabel('Predicted')
plt.ylabel('True')
plt.title('Confusion Matrix')
plt.tight_layout()
plt.show()

class_accuracy = cm.diagonal() / cm.sum(axis=1) * 100


for i, acc in enumerate(class_accuracy):
print(f"{class_labels[i]}: {acc:.2f}%")
return test_acc

test_accuracy = evaluate_model(trained_model, test_loader)

# Save the final model


torch.save({
'model_state_dict': trained_model.state_dict(),
'optimizer_state_dict': optimizer.state_dict(),
'test_accuracy': test_accuracy,
'class_labels': class_labels
}, 'vit_skin_disease_classifier.pth')
print("Model saved as 'vit_skin_disease_classifier.pth'")

# Function to visualize test predictions


def visualize_predictions(model, test_loader, class_labels,
num_images=10):
model.eval()
images, labels = next(iter(test_loader))
images, labels = images[:num_images].to(device),
labels[:num_images].to(device)
with torch.no_grad():
outputs = model(images)
_, preds = torch.max(outputs, 1)
probs = F.softmax(outputs, dim=1)

images_cpu = images.cpu()
mean = torch.tensor([0.485, 0.456, 0.406]).view(3, 1, 1)
std = torch.tensor([0.229, 0.224, 0.225]).view(3, 1, 1)
images_display = images_cpu * std + mean
images_display = torch.clamp(images_display, 0, 1)

plt.figure(figsize=(20, 20))
for i in range(num_images):
plt.subplot(5, 2, i+1)
plt.imshow(images_display[i].permute(1, 2, 0))
true_label = class_labels[labels[i]]
pred_label = class_labels[preds[i]]
confidence = probs[i, preds[i]] * 100
title_color = "green" if preds[i] == labels[i] else "red"
plt.title(f"True: {true_label}\nPred: {pred_label}\nConf:
{confidence:.1f}%",
color=title_color, fontsize=12)
plt.axis('off')
plt.tight_layout()
plt.show()

visualize_predictions(trained_model, test_loader, class_labels)

Total images: 18611


labels
3 7970
1 2103
4 2055
5 1847
6 1702
0 1677
2 1257
Name: count, dtype: int64
Training set: 13446 images
Validation set: 2373 images
Test set: 2792 images
Using device: cuda

{"model_id":"b39a8a16e43f4e4089fd491258aa2fb3","version_major":2,"vers
ion_minor":0}

Starting training with ViT Base...

Epoch 1/25 [Train]: 100%|██████████| 421/421 [07:06<00:00, 1.01s/it,


acc=62.9, loss=0.964]
Epoch 1/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.93it/s,
acc=63.5, loss=1.28]

Epoch 1/25:
Train Loss: 1.1789, Train Acc: 62.90%
Val Loss: 1.1543, Val Acc: 63.51%
Learning rate: 0.000098
New best model! Val Acc: 63.51%
Validation loss decreased (inf --> 1.154347). Saving model...

Epoch 2/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=68.7, loss=0.911]
Epoch 2/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.98it/s,
acc=71.8, loss=1.22]

Epoch 2/25:
Train Loss: 1.0619, Train Acc: 68.71%
Val Loss: 1.0125, Val Acc: 71.85%
Learning rate: 0.000091
New best model! Val Acc: 71.85%
Validation loss decreased (1.154347 --> 1.012527). Saving model...

Epoch 3/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.01s/it,


acc=73, loss=0.525]
Epoch 3/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=74.5, loss=1.65]

Epoch 3/25:
Train Loss: 0.9868, Train Acc: 73.02%
Val Loss: 0.9710, Val Acc: 74.55%
Learning rate: 0.000080
New best model! Val Acc: 74.55%
Validation loss decreased (1.012527 --> 0.970966). Saving model...

Epoch 4/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.01s/it,


acc=77.4, loss=1.04]
Epoch 4/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=78.4, loss=1.56]

Epoch 4/25:
Train Loss: 0.9065, Train Acc: 77.42%
Val Loss: 0.9046, Val Acc: 78.38%
Learning rate: 0.000066
New best model! Val Acc: 78.38%
Validation loss decreased (0.970966 --> 0.904570). Saving model...

Epoch 5/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=81, loss=1]
Epoch 5/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=79.5, loss=1.34]

Epoch 5/25:
Train Loss: 0.8360, Train Acc: 81.00%
Val Loss: 0.8912, Val Acc: 79.48%
Learning rate: 0.000051
New best model! Val Acc: 79.48%
Validation loss decreased (0.904570 --> 0.891229). Saving model...

Epoch 6/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=85.4, loss=0.734]
Epoch 6/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.96it/s,
acc=81.6, loss=1.38]

Epoch 6/25:
Train Loss: 0.7546, Train Acc: 85.39%
Val Loss: 0.8336, Val Acc: 81.63%
Learning rate: 0.000035
New best model! Val Acc: 81.63%
Validation loss decreased (0.891229 --> 0.833577). Saving model...

Epoch 7/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=89.6, loss=0.769]
Epoch 7/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=83.6, loss=1.61]

Epoch 7/25:
Train Loss: 0.6717, Train Acc: 89.63%
Val Loss: 0.8331, Val Acc: 83.57%
Learning rate: 0.000021
New best model! Val Acc: 83.57%
Validation loss decreased (0.833577 --> 0.833127). Saving model...

Epoch 8/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=92.8, loss=0.997]
Epoch 8/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.96it/s,
acc=85.1, loss=1.77]

Epoch 8/25:
Train Loss: 0.6061, Train Acc: 92.81%
Val Loss: 0.8093, Val Acc: 85.12%
Learning rate: 0.000010
New best model! Val Acc: 85.12%
Validation loss decreased (0.833127 --> 0.809258). Saving model...

Epoch 9/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.01s/it,


acc=95.2, loss=0.456]
Epoch 9/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.98it/s,
acc=85, loss=1.52]

Epoch 9/25:
Train Loss: 0.5584, Train Acc: 95.23%
Val Loss: 0.8282, Val Acc: 85.04%
Learning rate: 0.000003
EarlyStopping counter: 1 out of 8

Epoch 10/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=96.3, loss=0.454]
Epoch 10/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=85.2, loss=1.76]

Epoch 10/25:
Train Loss: 0.5340, Train Acc: 96.31%
Val Loss: 0.8276, Val Acc: 85.21%
Learning rate: 0.000001
New best model! Val Acc: 85.21%
EarlyStopping counter: 2 out of 8

Epoch 11/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=96.9, loss=0.462]
Epoch 11/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.98it/s,
acc=85.8, loss=1.84]

Epoch 11/25:
Train Loss: 0.5208, Train Acc: 96.88%
Val Loss: 0.8307, Val Acc: 85.76%
Learning rate: 0.000003
New best model! Val Acc: 85.76%
EarlyStopping counter: 3 out of 8

Epoch 12/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=96.7, loss=0.653]
Epoch 12/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.96it/s,
acc=85.2, loss=1.9]

Epoch 12/25:
Train Loss: 0.5234, Train Acc: 96.67%
Val Loss: 0.8347, Val Acc: 85.21%
Learning rate: 0.000010
EarlyStopping counter: 4 out of 8

Epoch 13/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=96.6, loss=0.455]
Epoch 13/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=85.6, loss=1.62]

Epoch 13/25:
Train Loss: 0.5251, Train Acc: 96.59%
Val Loss: 0.8276, Val Acc: 85.63%
Learning rate: 0.000021
EarlyStopping counter: 5 out of 8

Epoch 14/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=96.1, loss=0.462]
Epoch 14/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=85.3, loss=1.22]

Epoch 14/25:
Train Loss: 0.5366, Train Acc: 96.05%
Val Loss: 0.8540, Val Acc: 85.25%
Learning rate: 0.000035
EarlyStopping counter: 6 out of 8

Epoch 15/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=94.6, loss=0.525]
Epoch 15/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.96it/s,
acc=84, loss=1.75]

Epoch 15/25:
Train Loss: 0.5663, Train Acc: 94.65%
Val Loss: 0.8607, Val Acc: 83.99%
Learning rate: 0.000051
EarlyStopping counter: 7 out of 8

Epoch 16/25 [Train]: 100%|██████████| 421/421 [07:07<00:00, 1.02s/it,


acc=93.3, loss=0.45]
Epoch 16/25 [Val]: 100%|██████████| 75/75 [00:25<00:00, 2.97it/s,
acc=83.2, loss=1.89]
<ipython-input-1-0bd50b2ec5eb>:262: FutureWarning: You are using
`torch.load` with `weights_only=False` (the current default value),
which uses the default pickle module implicitly. It is possible to
construct malicious pickle data which will execute arbitrary code
during unpickling (See
https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-
models for more details). In a future release, the default value for
`weights_only` will be flipped to `True`. This limits the functions
that could be executed during unpickling. Arbitrary objects will no
longer be allowed to be loaded via this mode unless they are
explicitly allowlisted by the user via
`torch.serialization.add_safe_globals`. We recommend you start setting
`weights_only=True` for any use case where you don't have full control
of the loaded file. Please open an issue on GitHub for any issues
related to this experimental feature.
model.load_state_dict(torch.load(best_model_path))

Epoch 16/25:
Train Loss: 0.5916, Train Acc: 93.33%
Val Loss: 0.8797, Val Acc: 83.23%
Learning rate: 0.000066
EarlyStopping counter: 8 out of 8
Early stopping triggered
Evaluating: 100%|██████████| 88/88 [00:30<00:00, 2.92it/s]

Test Accuracy: 85.53%

Classification Report:
precision
recall f1-score support

Eczema 0.76
0.72 0.74 252
Warts Molluscum and other Viral Infections 0.77
0.80 0.78 315
Atopic Dermatitis 0.66
0.68 0.67 189
Melanocytic Nevi 0.99
1.00 0.99 1196
Psoriasis pictures Lichen Planus and related diseases 0.71
0.71 0.71 308
Seborrheic Keratoses and other Benign Tumors 0.84
0.79 0.81 277
Tinea Ringworm Candidiasis and other Fungal Infections 0.76
0.76 0.76 255

accuracy
0.86 2792
macro avg 0.78
0.78 0.78 2792
weighted avg 0.85
0.86 0.85 2792
Eczema: 71.83%
Warts Molluscum and other Viral Infections: 79.68%
Atopic Dermatitis: 67.72%
Melanocytic Nevi: 100.00%
Psoriasis pictures Lichen Planus and related diseases: 71.43%
Seborrheic Keratoses and other Benign Tumors: 78.70%
Tinea Ringworm Candidiasis and other Fungal Infections: 76.08%
Model saved as 'vit_skin_disease_classifier.pth'

You might also like