0% found this document useful (0 votes)
13 views37 pages

Breast Cancer Classification Using ADAM Vs Nirmal Optimizer With Pre-Trained Models

Uploaded by

teaching.masudur
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)
13 views37 pages

Breast Cancer Classification Using ADAM Vs Nirmal Optimizer With Pre-Trained Models

Uploaded by

teaching.masudur
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/ 37

Breast Cancer Classification using ADAM vs

Nirmal Optimizer with Pre-Trained Models

import numpy as np
import pandas as pd
import os

base_path =
"/kaggle/input/bus-uclm-breast-ultrasound-dataset/bus_uclm_separated/"
categories = ["benign","malign", "normal"]

image_paths = []
labels = []

for category in categories:


category_path = os.path.join(base_path, category)
for image_name in os.listdir(category_path):
image_path = os.path.join(category_path, image_name)
image_paths.append(image_path)
labels.append(category)

df = pd.DataFrame({
"image_path": image_paths,
"label": labels
})

df.head()

image_path label
0 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
1 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
2 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
3 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
4 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
df.tail()

image_path label
678 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
679 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
680 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
681 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
682 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal

df.shape

(683, 2)

df.columns

Index(['image_path', 'label'], dtype='object')

df.duplicated().sum()

df.isnull().sum()

image_path 0
label 0
dtype: int64

df.info()

<class 'pandas.core.frame.DataFrame'>
RangeIndex: 683 entries, 0 to 682
Data columns (total 2 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 image_path 683 non-null object
1 label 683 non-null object
dtypes: object(2)
memory usage: 10.8+ KB

df['label'].unique()

array(['benign', 'malign', 'normal'], dtype=object)

df['label'].value_counts()

label
normal 419
benign 174
malign 90
Name: count, dtype: int64

import seaborn as sns


import matplotlib.pyplot as plt
sns.set_style("whitegrid")

fig, ax = plt.subplots(figsize=(8, 6))


sns.countplot(data=df, x="label", palette="viridis", ax=ax)

ax.set_title("Distribution Types", fontsize=14, fontweight='bold')


ax.set_xlabel("Tumor Type", fontsize=12)
ax.set_ylabel("Count", fontsize=12)

for p in ax.patches:
ax.annotate(f'{int(p.get_height())}',
(p.get_x() + p.get_width() / 2., p.get_height()),
ha='center', va='bottom', fontsize=11, color='black',
xytext=(0, 5), textcoords='offset points')

plt.show()

label_counts = df["label"].value_counts()

fig, ax = plt.subplots(figsize=(8, 6))


colors = sns.color_palette("viridis", len(label_counts))

ax.pie(label_counts, labels=label_counts.index, autopct='%1.1f%%',


startangle=140, colors=colors, textprops={'fontsize': 12,
'weight': 'bold'},
wedgeprops={'edgecolor': 'black', 'linewidth': 1})

ax.set_title("Distribution Types - Pie Chart", fontsize=14,


fontweight='bold')

plt.show()
import cv2

num_images = 5

plt.figure(figsize=(15, 12))

for i, category in enumerate(categories):


category_images = df[df['label'] == category]
['image_path'].iloc[:num_images]

for j, img_path in enumerate(category_images):

img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

plt.subplot(len(categories), num_images, i * num_images + j +


1)
plt.imshow(img)
plt.axis('off')
plt.title(category)
plt.tight_layout()
plt.show()

from sklearn.utils import resample

max_count = df['label'].value_counts().max()

dfs = []
for category in df['label'].unique():
class_subset = df[df['label'] == category]
class_upsampled = resample(class_subset,
replace=True,
n_samples=max_count,
random_state=42)
dfs.append(class_upsampled)

df_balanced = pd.concat(dfs).sample(frac=1,
random_state=42).reset_index(drop=True)

df = df_balanced

df

image_path label
0 /kaggle/input/bus-uclm-breast-ultrasound-datas... malign
1 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
2 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
3 /kaggle/input/bus-uclm-breast-ultrasound-datas... benign
4 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
... ... ...
1252 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
1253 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
1254 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
1255 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal
1256 /kaggle/input/bus-uclm-breast-ultrasound-datas... normal

[1257 rows x 2 columns]

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

from sklearn.model_selection import train_test_split


from sklearn.metrics import confusion_matrix, classification_report

import tensorflow as tf
from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.applications import VGG16, InceptionV3,
DenseNet121, ResNet50
from tensorflow.keras.layers import Dense, GlobalAveragePooling2D
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'

train_df, test_df = train_test_split(df, test_size=0.2,


random_state=42, stratify=df['label'])

train_datagen = ImageDataGenerator(
rescale=1./255,
rotation_range=20,
width_shift_range=0.2,
height_shift_range=0.2,
shear_range=0.2,
zoom_range=0.2,
horizontal_flip=True,
fill_mode='nearest'
)
test_datagen = ImageDataGenerator(rescale=1./255)

train_generator = train_datagen.flow_from_dataframe(
train_df,
x_col='image_path',
y_col='label',
target_size=(224, 224),
batch_size=32,
class_mode='sparse'
)
test_generator = test_datagen.flow_from_dataframe(
test_df,
x_col='image_path',
y_col='label',
target_size=(224, 224),
batch_size=32,
class_mode='sparse',
shuffle=False
)

models = {
'VGG16': VGG16,
'InceptionV3': InceptionV3,
'DenseNet121': DenseNet121,
'ResNet50': ResNet50
}

results = {}
class_labels = ['benign', 'malignant', 'normal']

for model_name, model_func in models.items():


base_model = model_func(weights='imagenet', include_top=False,
input_shape=(224, 224, 3))
x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
predictions = Dense(3, activation='softmax')(x)
model = Model(inputs=base_model.input, outputs=predictions)

for layer in base_model.layers:


layer.trainable = False

model.compile(optimizer=Adam(learning_rate=0.001),
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])

history = model.fit(
train_generator,
epochs=5,
validation_data=test_generator
)

results[model_name] = {
'history': history.history,
'model': model
}

plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Validation
Accuracy')
plt.title(f'{model_name} Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Validation Loss')
plt.title(f'{model_name} Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.tight_layout()
plt.savefig(f'{model_name}_plots.png')
plt.close()

y_pred = np.argmax(model.predict(test_generator), axis=1)


y_true = test_generator.classes

cm = confusion_matrix(y_true, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_labels, yticklabels=class_labels)
plt.title(f'{model_name} Confusion Matrix')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.savefig(f'{model_name}_cm.png')
plt.close()

print(f"\nClassification Report for {model_name}:")


print(classification_report(y_true, y_pred,
target_names=class_labels))

comparison = pd.DataFrame(columns=['Model', 'Test Accuracy', 'Test


Loss'])
for model_name in results:
test_loss, test_accuracy = results[model_name]
['model'].evaluate(test_generator)
comparison = pd.concat([comparison, pd.DataFrame([{
'Model': model_name,
'Test Accuracy': test_accuracy,
'Test Loss': test_loss
}])], ignore_index=True)
plt.figure(figsize=(10, 6))
plt.subplot(1, 2, 1)
sns.barplot(x='Model', y='Test Accuracy', data=comparison)
plt.title('Model Comparison - Test Accuracy')
plt.xticks(rotation=45)

plt.subplot(1, 2, 2)
sns.barplot(x='Model', y='Test Loss', data=comparison)
plt.title('Model Comparison - Test Loss')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('model_comparison.png')
plt.close()

print("\nComparative Analysis:")
print(comparison)

Found 1005 validated image filenames belonging to 3 classes.


Found 252 validated image filenames belonging to 3 classes.

I0000 00:00:1754986841.448261 36 gpu_device.cc:2022] Created


device /job:localhost/replica:0/task:0/device:GPU:0 with 13942 MB
memory: -> device: 0, name: Tesla T4, pci bus id: 0000:00:04.0,
compute capability: 7.5
I0000 00:00:1754986841.448957 36 gpu_device.cc:2022] Created
device /job:localhost/replica:0/task:0/device:GPU:1 with 13942 MB
memory: -> device: 1, name: Tesla T4, pci bus id: 0000:00:05.0,
compute capability: 7.5

Downloading data from https://storage.googleapis.com/tensorflow/keras-


applications/vgg16/vgg16_weights_tf_dim_ordering_tf_kernels_notop.h5
58889256/58889256 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step

/usr/local/lib/python3.11/dist-packages/keras/src/trainers/
data_adapters/py_dataset_adapter.py:121: UserWarning: Your `PyDataset`
class should call `super().__init__(**kwargs)` in its constructor.
`**kwargs` can include `workers`, `use_multiprocessing`,
`max_queue_size`. Do not pass these arguments to `fit()`, as they will
be ignored.
self._warn_if_super_not_called()

Epoch 1/5

WARNING: All log messages before absl::InitializeLog() is called are


written to STDERR
I0000 00:00:1754986848.811511 125 service.cc:148] XLA service
0x7921e800d810 initialized for platform CUDA (this does not guarantee
that XLA will be used). Devices:
I0000 00:00:1754986848.812652 125 service.cc:156] StreamExecutor
device (0): Tesla T4, Compute Capability 7.5
I0000 00:00:1754986848.812677 125 service.cc:156] StreamExecutor
device (1): Tesla T4, Compute Capability 7.5
I0000 00:00:1754986849.204509 125 cuda_dnn.cc:529] Loaded cuDNN
version 90300

1/32 ━━━━━━━━━━━━━━━━━━━━ 7:23 14s/step - accuracy: 0.4375 - loss:


1.1566

I0000 00:00:1754986859.994613 125 device_compiler.h:188] Compiled


cluster using XLA! This line is logged at most once for the lifetime
of the process.

32/32 ━━━━━━━━━━━━━━━━━━━━ 63s 2s/step - accuracy: 0.3984 - loss:


1.1333 - val_accuracy: 0.5079 - val_loss: 0.9939
Epoch 2/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 32s 993ms/step - accuracy: 0.4301 - loss:
1.0726 - val_accuracy: 0.6310 - val_loss: 0.9474
Epoch 3/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 31s 981ms/step - accuracy: 0.5276 - loss:
0.9796 - val_accuracy: 0.5873 - val_loss: 0.9212
Epoch 4/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 31s 968ms/step - accuracy: 0.5340 - loss:
0.9685 - val_accuracy: 0.5079 - val_loss: 0.9292
Epoch 5/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 31s 980ms/step - accuracy: 0.5564 - loss:
0.9256 - val_accuracy: 0.6032 - val_loss: 0.8759
8/8 ━━━━━━━━━━━━━━━━━━━━ 6s 603ms/step

Classification Report for VGG16:


precision recall f1-score support

benign 0.71 0.56 0.63 84


malignant 0.90 0.31 0.46 84
normal 0.50 0.94 0.66 84

accuracy 0.60 252


macro avg 0.70 0.60 0.58 252
weighted avg 0.70 0.60 0.58 252

Downloading data from https://storage.googleapis.com/tensorflow/keras-


applications/inception_v3/
inception_v3_weights_tf_dim_ordering_tf_kernels_notop.h5
87910968/87910968 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Epoch 1/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 68s 2s/step - accuracy: 0.3882 - loss:
3.2720 - val_accuracy: 0.5754 - val_loss: 0.8500
Epoch 2/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 952ms/step - accuracy: 0.5454 - loss:
0.9566 - val_accuracy: 0.7183 - val_loss: 0.7440
Epoch 3/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 944ms/step - accuracy: 0.6265 - loss:
0.8549 - val_accuracy: 0.7302 - val_loss: 0.6799
Epoch 4/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 943ms/step - accuracy: 0.6192 - loss:
0.8501 - val_accuracy: 0.6944 - val_loss: 0.7001
Epoch 5/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 947ms/step - accuracy: 0.6489 - loss:
0.8002 - val_accuracy: 0.6071 - val_loss: 0.8121
8/8 ━━━━━━━━━━━━━━━━━━━━ 16s 1s/step

Classification Report for InceptionV3:


precision recall f1-score support

benign 0.64 0.71 0.67 84


malignant 0.54 0.88 0.67 84
normal 0.86 0.23 0.36 84

accuracy 0.61 252


macro avg 0.68 0.61 0.57 252
weighted avg 0.68 0.61 0.57 252

Downloading data from https://storage.googleapis.com/tensorflow/keras-


applications/densenet/
densenet121_weights_tf_dim_ordering_tf_kernels_notop.h5
29084464/29084464 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step
Epoch 1/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 94s 2s/step - accuracy: 0.3885 - loss:
2.0804 - val_accuracy: 0.4127 - val_loss: 1.0410
Epoch 2/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 954ms/step - accuracy: 0.5077 - loss:
0.9440 - val_accuracy: 0.4286 - val_loss: 0.9836
Epoch 3/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 31s 956ms/step - accuracy: 0.6385 - loss:
0.8013 - val_accuracy: 0.6429 - val_loss: 0.8065
Epoch 4/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 951ms/step - accuracy: 0.6378 - loss:
0.7991 - val_accuracy: 0.6190 - val_loss: 0.8532
Epoch 5/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 31s 964ms/step - accuracy: 0.6642 - loss:
0.7501 - val_accuracy: 0.6667 - val_loss: 0.7633
8/8 ━━━━━━━━━━━━━━━━━━━━ 26s 2s/step

Classification Report for DenseNet121:


precision recall f1-score support

benign 0.62 0.81 0.70 84


malignant 0.70 0.87 0.77 84
normal 0.71 0.32 0.44 84

accuracy 0.67 252


macro avg 0.68 0.67 0.64 252
weighted avg 0.68 0.67 0.64 252

Downloading data from https://storage.googleapis.com/tensorflow/keras-


applications/resnet/
resnet50_weights_tf_dim_ordering_tf_kernels_notop.h5
94765736/94765736 ━━━━━━━━━━━━━━━━━━━━ 1s 0us/step
Epoch 1/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 56s 1s/step - accuracy: 0.3453 - loss:
1.4782 - val_accuracy: 0.3333 - val_loss: 1.2729
Epoch 2/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 950ms/step - accuracy: 0.3390 - loss:
1.2229 - val_accuracy: 0.3333 - val_loss: 1.1594
Epoch 3/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 952ms/step - accuracy: 0.3267 - loss:
1.1328 - val_accuracy: 0.3571 - val_loss: 1.1035
Epoch 4/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 31s 970ms/step - accuracy: 0.3647 - loss:
1.1157 - val_accuracy: 0.3452 - val_loss: 1.0987
Epoch 5/5
32/32 ━━━━━━━━━━━━━━━━━━━━ 30s 951ms/step - accuracy: 0.3236 - loss:
1.1379 - val_accuracy: 0.4087 - val_loss: 1.0919
8/8 ━━━━━━━━━━━━━━━━━━━━ 13s 1s/step

Classification Report for ResNet50:


precision recall f1-score support

benign 1.00 0.05 0.09 84


malignant 0.45 0.33 0.38 84
normal 0.38 0.85 0.53 84

accuracy 0.41 252


macro avg 0.61 0.41 0.33 252
weighted avg 0.61 0.41 0.33 252

8/8 ━━━━━━━━━━━━━━━━━━━━ 5s 565ms/step - accuracy: 0.5720 - loss:


0.8996

/tmp/ipykernel_36/2745638562.py:133: FutureWarning: The behavior of


DataFrame concatenation with empty or all-NA entries is deprecated. In
a future version, this will no longer exclude empty or all-NA columns
when determining the result dtypes. To retain the old behavior,
exclude the relevant entries before the concat operation.
comparison = pd.concat([comparison, pd.DataFrame([{

8/8 ━━━━━━━━━━━━━━━━━━━━ 4s 534ms/step - accuracy: 0.6372 - loss:


0.7824
8/8 ━━━━━━━━━━━━━━━━━━━━ 4s 533ms/step - accuracy: 0.6979 - loss:
0.7522
8/8 ━━━━━━━━━━━━━━━━━━━━ 4s 539ms/step - accuracy: 0.3914 - loss:
1.0914

Comparative Analysis:
Model Test Accuracy Test Loss
0 VGG16 0.603175 0.875864
1 InceptionV3 0.607143 0.812130
2 DenseNet121 0.666667 0.763266
3 ResNet50 0.408730 1.091896

import os
import matplotlib.pyplot as plt
import matplotlib.image as mpimg

directory_path = '/kaggle/working/'

image_files = [f for f in os.listdir(directory_path) if


f.lower().endswith(('.png', '.jpg', '.jpeg', '.bmp', '.gif'))]

for image_file in image_files:


img_path = os.path.join(directory_path, image_file)
img = mpimg.imread(img_path)
plt.figure(figsize=(10, 10))
plt.imshow(img)
plt.title(image_file)
plt.axis('off')
plt.show()
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
import seaborn as sns
import torch
import torch.nn as nn
import torch.optim as Optimizer
from torch.utils.data import Dataset, DataLoader
from torchvision import models, transforms
from torchvision.models import VGG16_Weights, Inception_V3_Weights,
DenseNet121_Weights, ResNet50_Weights
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix, classification_report
from PIL import Image

torch.manual_seed(42)

class NIRMAL(Optimizer.Optimizer):
def __init__(self, params, lr=1e-3, momentum=0.9, beta=0.999,
eps=1e-8,
knight_scale=0.01, camel_scale=1.5, horse_scale=0.5,
w_wazir=0.3, w_elephant=0.25, w_knight=0.1,
w_camel=0.2,
w_horse=0.15, weight_decay=0):
defaults = dict(
lr=lr, momentum=momentum, beta=beta, eps=eps,
knight_scale=knight_scale, camel_scale=camel_scale,
horse_scale=horse_scale,
w_wazir=w_wazir, w_elephant=w_elephant, w_knight=w_knight,
w_camel=w_camel, w_horse=w_horse,
weight_decay=weight_decay
)
super(NIRMAL, self).__init__(params, defaults)

def __setstate__(self, state):


super(NIRMAL, self).__setstate__(state)

def step(self, closure=None):


loss = None
if closure is not None:
loss = closure()

for group in self.param_groups:


lr = group['lr']
momentum = group['momentum']
beta = group['beta']
eps = group['eps']
knight_scale = group['knight_scale']
camel_scale = group['camel_scale']
horse_scale = group['horse_scale']
w_wazir = group['w_wazir']
w_elephant = group['w_elephant']
w_knight = group['w_knight']
w_camel = group['w_camel']
w_horse = group['w_horse']
weight_decay = group['weight_decay']

for p in group['params']:
if p.grad is None:
continue
grad = p.grad.data

if weight_decay != 0:
grad = grad.add(p.data, alpha=weight_decay)

state = self.state[p]

if len(state) == 0:
state['step'] = 0
state['m'] = torch.zeros_like(p.data)
state['v'] = torch.zeros_like(p.data)

m, v = state['m'], state['v']
state['step'] += 1

delta_wazir = -lr * grad


m.mul_(momentum).add_(grad, alpha=1 - momentum)
delta_elephant = -lr * m
delta_knight = lr * knight_scale *
torch.randn_like(p.data)
v.mul_(beta).addcmul_(grad, grad, value=1 - beta)
delta_camel = -lr * camel_scale * m / (torch.sqrt(v) +
eps)
delta_horse = -lr * horse_scale * torch.tanh(m)

delta_total = (w_wazir * delta_wazir + w_elephant *


delta_elephant +
w_knight * delta_knight + w_camel *
delta_camel +
w_horse * delta_horse)

p.data.add_(delta_total)

return loss

class CustomImageDataset(Dataset):
def __init__(self, dataframe, transform=None):
self.dataframe = dataframe
self.transform = transform
self.label_map = {'benign': 0, 'malign': 1, 'normal': 2}

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

def __getitem__(self, idx):


img_path = self.dataframe.iloc[idx]['image_path']
label = self.label_map[self.dataframe.iloc[idx]['label']]
image = Image.open(img_path).convert('RGB')
if self.transform:
image = self.transform(image)

return image, label

train_transforms = transforms.Compose([
transforms.Resize((299, 299)),
transforms.RandomRotation(20),
transforms.RandomHorizontalFlip(),
transforms.RandomAffine(degrees=0, translate=(0.2, 0.2),
shear=0.2, scale=(0.8, 1.2)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229,
0.224, 0.225])
])

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

train_df, test_df = train_test_split(df, test_size=0.2,


random_state=42, stratify=df['label'])

train_dataset = CustomImageDataset(train_df,
transform=train_transforms)
test_dataset = CustomImageDataset(test_df, transform=test_transforms)

train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)


test_loader = DataLoader(test_dataset, batch_size=16, shuffle=False)

models_dict = {
'VGG16': lambda:
models.vgg16(weights=VGG16_Weights.IMAGENET1K_V1),
'InceptionV3': lambda:
models.inception_v3(weights=Inception_V3_Weights.IMAGENET1K_V1),
'DenseNet121': lambda:
models.densenet121(weights=DenseNet121_Weights.IMAGENET1K_V1),
'ResNet50': lambda:
models.resnet50(weights=ResNet50_Weights.IMAGENET1K_V1)
}

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')


results = {}
class_labels = ['benign', 'malign', 'normal']

for model_name, model_func in models_dict.items():


torch.cuda.empty_cache()
model = model_func()

for param in model.parameters():


param.requires_grad = False

in_features_map = {
'VGG16': 512 * 7 * 7,
'InceptionV3': 2048,
'DenseNet121': 1024,
'ResNet50': 2048
}

class CustomModel(nn.Module):
def __init__(self, base_model, model_name, in_features):
super(CustomModel, self).__init__()
self.base_model = base_model
self.model_name = model_name

self.pool = nn.AdaptiveAvgPool2d((1, 1))


self.flatten = nn.Flatten()
self.classifier = nn.Sequential(
nn.Linear(in_features, 1024),
nn.ReLU(),
nn.Linear(1024, 3)
)

if model_name == 'VGG16':
self.features = base_model.features
self.avgpool = base_model.avgpool
elif model_name == 'InceptionV3':
self.features_early = nn.Sequential(
base_model.Conv2d_1a_3x3,
base_model.Conv2d_2a_3x3,
base_model.Conv2d_2b_3x3,
base_model.maxpool1,
base_model.Conv2d_3b_1x1,
base_model.Conv2d_4a_3x3,
base_model.maxpool2,
base_model.Mixed_5b,
base_model.Mixed_5c,
base_model.Mixed_5d,
base_model.Mixed_6a,
base_model.Mixed_6b,
base_model.Mixed_6c,
base_model.Mixed_6d,
base_model.Mixed_6e
)
self.features_late = nn.Sequential(
base_model.Mixed_7a,
base_model.Mixed_7b,
base_model.Mixed_7c
)
self.aux_logits = base_model.aux_logits
self.AuxLogits = base_model.AuxLogits if
base_model.aux_logits else None
elif model_name == 'DenseNet121':
self.features = base_model.features
elif model_name == 'ResNet50':
self.features = nn.Sequential(
base_model.conv1,
base_model.bn1,
base_model.relu,
base_model.maxpool,
base_model.layer1,
base_model.layer2,
base_model.layer3,
base_model.layer4
)

def forward(self, x):


if self.model_name == 'InceptionV3' and self.training and
self.aux_logits:
x_early = self.features_early(x)
aux = self.AuxLogits(x_early) if self.AuxLogits else
None
x = self.features_late(x_early)
x = self.pool(x)
x = self.flatten(x)
x = self.classifier(x)
return x, aux
else:
if self.model_name == 'InceptionV3':
x = self.features_early(x)
x = self.features_late(x)
else:
x = self.features(x)
if self.model_name == 'VGG16':
x = self.avgpool(x)
x = self.flatten(x)
else:
x = self.pool(x)
x = self.flatten(x)
x = self.classifier(x)
return x

model = CustomModel(model, model_name,


in_features_map[model_name]).to(device)
criterion = nn.CrossEntropyLoss()
optimizer = NIRMAL(model.parameters(), lr=0.001)

num_epochs = 5
accumulation_steps = 2
history = {'accuracy': [], 'val_accuracy': [], 'loss': [],
'val_loss': []}

for epoch in range(num_epochs):


model.train()
running_loss = 0.0
correct = 0
total = 0
optimizer.zero_grad()

for i, (images, labels) in enumerate(train_loader):


images, labels = images.to(device), labels.to(device)

if model_name == 'InceptionV3' and model.training:


outputs, aux_outputs = model(images)
loss1 = criterion(outputs, labels)
loss2 = criterion(aux_outputs, labels)
loss = loss1 + 0.4 * loss2
else:
outputs = model(images)
loss = criterion(outputs, labels)

loss = loss / accumulation_steps


loss.backward()

if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()

running_loss += loss.item() * accumulation_steps


_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()

if (i + 1) % accumulation_steps != 0:
optimizer.step()
optimizer.zero_grad()

train_accuracy = correct / total


train_loss = running_loss / len(train_loader)
history['accuracy'].append(train_accuracy)
history['loss'].append(train_loss)
model.eval()
val_loss = 0.0
correct = 0
total = 0
y_true = []
y_pred = []

with torch.no_grad():
for images, labels in test_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
val_loss += loss.item()

_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
y_true.extend(labels.cpu().numpy())
y_pred.extend(predicted.cpu().numpy())

val_accuracy = correct / total


val_loss = val_loss / len(test_loader)
history['val_accuracy'].append(val_accuracy)
history['val_loss'].append(val_loss)

print(f'{model_name} Epoch {epoch+1}/{num_epochs}, '


f'Train Loss: {train_loss:.4f}, Train Acc:
{train_accuracy:.4f}, '
f'Val Loss: {val_loss:.4f}, Val Acc:
{val_accuracy:.4f}')

results[model_name] = {
'history': history,
'model': model
}

plt.figure(figsize=(12, 4))
plt.subplot(1, 2, 1)
plt.plot(history['accuracy'], label='Train Accuracy')
plt.plot(history['val_accuracy'], label='Validation Accuracy')
plt.title(f'{model_name} Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()

plt.subplot(1, 2, 2)
plt.plot(history['loss'], label='Train Loss')
plt.plot(history['val_loss'], label='Validation Loss')
plt.title(f'{model_name} Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.tight_layout()
plt.savefig(f'{model_name}_plots.png')
plt.close()

cm = confusion_matrix(y_true, y_pred)
plt.figure(figsize=(8, 6))
sns.heatmap(cm, annot=True, fmt='d', cmap='Blues',
xticklabels=class_labels, yticklabels=class_labels)
plt.title(f'{model_name} Confusion Matrix')
plt.ylabel('True Label')
plt.xlabel('Predicted Label')
plt.savefig(f'{model_name}_cm.png')
plt.close()

print(f"\nClassification Report for {model_name}:")


print(classification_report(y_true, y_pred,
target_names=class_labels))

comparison = pd.DataFrame(columns=['Model', 'Test Accuracy', 'Test


Loss'])

for model_name in results:


model = results[model_name]['model']
model.eval()
test_loss = 0.0
correct = 0
total = 0

with torch.no_grad():
for images, labels in test_loader:
images, labels = images.to(device), labels.to(device)
outputs = model(images)
loss = criterion(outputs, labels)
test_loss += loss.item()
_, predicted = torch.max(outputs, 1)
total += labels.size(0)
correct += (predicted == labels).sum().item()

test_accuracy = correct / total


test_loss = test_loss / len(test_loader)
comparison = pd.concat([comparison, pd.DataFrame([{
'Model': model_name,
'Test Accuracy': test_accuracy,
'Test Loss': test_loss
}])], ignore_index=True)

plt.figure(figsize=(10, 6))
plt.subplot(1, 2, 1)
sns.barplot(x='Model', y='Test Accuracy', data=comparison)
plt.title('Model Comparison - Test Accuracy')
plt.xticks(rotation=45)

plt.subplot(1, 2, 2)
sns.barplot(x='Model', y='Test Loss', data=comparison)
plt.title('Model Comparison - Test Loss')
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('model_comparison.png')
plt.close()

print("\nComparative Analysis:")
print(comparison)

VGG16 Epoch 1/5, Train Loss: 1.5353, Train Acc: 0.4149, Val Loss:
1.0731, Val Acc: 0.4365
VGG16 Epoch 2/5, Train Loss: 0.8810, Train Acc: 0.5900, Val Loss:
0.8278, Val Acc: 0.6389
VGG16 Epoch 3/5, Train Loss: 0.7623, Train Acc: 0.6488, Val Loss:
0.6811, Val Acc: 0.7183
VGG16 Epoch 4/5, Train Loss: 0.7022, Train Acc: 0.6856, Val Loss:
0.6444, Val Acc: 0.7698
VGG16 Epoch 5/5, Train Loss: 0.6684, Train Acc: 0.7055, Val Loss:
0.7735, Val Acc: 0.6944

Classification Report for VGG16:


precision recall f1-score support

benign 0.62 0.86 0.72 84


malign 0.88 0.45 0.60 84
normal 0.71 0.77 0.74 84

accuracy 0.69 252


macro avg 0.74 0.69 0.68 252
weighted avg 0.74 0.69 0.68 252

InceptionV3 Epoch 1/5, Train Loss: 4.4167, Train Acc: 0.4418, Val
Loss: 1.0132, Val Acc: 0.4802
InceptionV3 Epoch 2/5, Train Loss: 4.2478, Train Acc: 0.5502, Val
Loss: 0.9279, Val Acc: 0.5278
InceptionV3 Epoch 3/5, Train Loss: 4.2041, Train Acc: 0.5552, Val
Loss: 0.9020, Val Acc: 0.5794
InceptionV3 Epoch 4/5, Train Loss: 4.1284, Train Acc: 0.6328, Val
Loss: 0.9020, Val Acc: 0.5675
InceptionV3 Epoch 5/5, Train Loss: 4.0647, Train Acc: 0.6637, Val
Loss: 0.8349, Val Acc: 0.6190

Classification Report for InceptionV3:


precision recall f1-score support

benign 0.63 0.67 0.65 84


malign 0.70 0.50 0.58 84
normal 0.56 0.69 0.62 84

accuracy 0.62 252


macro avg 0.63 0.62 0.62 252
weighted avg 0.63 0.62 0.62 252

DenseNet121 Epoch 1/5, Train Loss: 0.9417, Train Acc: 0.5393, Val
Loss: 0.7709, Val Acc: 0.6468
DenseNet121 Epoch 2/5, Train Loss: 0.7352, Train Acc: 0.6866, Val
Loss: 0.8149, Val Acc: 0.6310
DenseNet121 Epoch 3/5, Train Loss: 0.6786, Train Acc: 0.7104, Val
Loss: 0.6596, Val Acc: 0.7024
DenseNet121 Epoch 4/5, Train Loss: 0.6485, Train Acc: 0.7174, Val
Loss: 0.6234, Val Acc: 0.7024
DenseNet121 Epoch 5/5, Train Loss: 0.5944, Train Acc: 0.7303, Val
Loss: 0.6410, Val Acc: 0.7143

Classification Report for DenseNet121:


precision recall f1-score support

benign 0.64 0.83 0.72 84


malign 0.84 0.57 0.68 84
normal 0.73 0.74 0.73 84

accuracy 0.71 252


macro avg 0.74 0.71 0.71 252
weighted avg 0.74 0.71 0.71 252

ResNet50 Epoch 1/5, Train Loss: 1.3323, Train Acc: 0.3234, Val Loss:
1.0902, Val Acc: 0.3333
ResNet50 Epoch 2/5, Train Loss: 1.0695, Train Acc: 0.4458, Val Loss:
1.0512, Val Acc: 0.5556
ResNet50 Epoch 3/5, Train Loss: 1.0456, Train Acc: 0.4667, Val Loss:
1.0583, Val Acc: 0.4762
ResNet50 Epoch 4/5, Train Loss: 0.9955, Train Acc: 0.5035, Val Loss:
1.0576, Val Acc: 0.4484
ResNet50 Epoch 5/5, Train Loss: 0.9355, Train Acc: 0.5522, Val Loss:
0.9699, Val Acc: 0.5278

Classification Report for ResNet50:


precision recall f1-score support

benign 0.52 0.75 0.61 84


malign 0.53 0.71 0.61 84
normal 0.59 0.12 0.20 84
accuracy 0.53 252
macro avg 0.55 0.53 0.47 252
weighted avg 0.55 0.53 0.47 252

/tmp/ipykernel_36/2409283139.py:371: FutureWarning: The behavior of


DataFrame concatenation with empty or all-NA entries is deprecated. In
a future version, this will no longer exclude empty or all-NA columns
when determining the result dtypes. To retain the old behavior,
exclude the relevant entries before the concat operation.
comparison = pd.concat([comparison, pd.DataFrame([{

Comparative Analysis:
Model Test Accuracy Test Loss
0 VGG16 0.694444 0.773453
1 InceptionV3 0.619048 0.834861
2 DenseNet121 0.714286 0.640971
3 ResNet50 0.527778 0.969906

for image_file in image_files:


img_path = os.path.join(directory_path, image_file)
img = mpimg.imread(img_path)
plt.figure(figsize=(10, 10))
plt.imshow(img)
plt.title(image_file)
plt.axis('off')
plt.show()

You might also like