Breast Cancer Classification Using ADAM Vs Nirmal Optimizer With Pre-Trained Models
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 = []
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
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()
df['label'].value_counts()
label
normal 419
benign 174
malign 90
Name: count, dtype: int64
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()
plt.show()
import cv2
num_images = 5
plt.figure(figsize=(15, 12))
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
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
import pandas as pd
import numpy as np
import os
import matplotlib.pyplot as plt
import seaborn as sns
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_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']
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()
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()
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)
/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
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/'
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)
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
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)
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_dataset = CustomImageDataset(train_df,
transform=train_transforms)
test_dataset = CustomImageDataset(test_df, transform=test_transforms)
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)
}
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
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
)
num_epochs = 5
accumulation_steps = 2
history = {'accuracy': [], 'val_accuracy': [], 'loss': [],
'val_loss': []}
if (i + 1) % accumulation_steps == 0:
optimizer.step()
optimizer.zero_grad()
if (i + 1) % accumulation_steps != 0:
optimizer.step()
optimizer.zero_grad()
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())
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()
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()
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
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
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
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
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