π©Ί Breast Cancer Classification ANN
This is a PyTorch-based Deep Artificial Neural Network (ANN) trained on the Wisconsin Diagnostic Breast Cancer (WDBC) dataset to classify cell nuclei observations as either Malignant (M) or Benign (B).
Hyperparameters were systematically tuned using Optuna to maximize classification accuracy.
π Model Details
- Model Type: Multi-Layer Perceptron (MLP / ANN)
- Framework: PyTorch
- Optimization Framework: Optuna
- Task: Binary Tabular Classification (0: Benign, 1: Malignant)
- Input Dimension: 30 features
- Output Dimension: 1 (Logit / Sigmoid Probability)
βοΈ Hyperparameters (Optuna Best Trial)
The hyperparameter search space was optimized over 30 trials using Tree-structured Parzen Estimator (TPE):
- Hidden Layers: 2
- Neurons per Hidden Layer: 106
- Activation Function: ReLU
- Regularization:
- Batch Normalization (
nn.BatchNorm1d) per hidden layer - Dropout Rate:
0.4393
- Batch Normalization (
- Optimizer: Adam
- Learning Rate:
0.0031 - Loss Function: Binary Cross Entropy with Logits (
nn.BCEWithLogitsLoss) - Epochs: 60
π Dataset & Preprocessing
- Dataset: Breast Cancer Wisconsin (Diagnostic) Dataset
- Samples: 569 instances (455 Train / 114 Test)
- Feature Count: 30 real-valued numeric features computed from digitized images of fine needle aspirates (FNA) of breast masses.
- Preprocessing Pipeline:
- Removal of irrelevant metadata columns (
id,Unnamed: 32). - Target encoding via
LabelEncoder(M-> 1,B-> 0). - Feature standardization via
StandardScaler(zero mean and unit variance).
- Removal of irrelevant metadata columns (
π Evaluation & Results
Evaluated on unseen test set (20% split, 114 samples):
| Metric | Score |
|---|---|
| Best Test Accuracy | 100.00% (1.00) |
| Average Study Accuracy | ~96.5% |
π How to Use (Inference)
import torch
import torch.nn as nn
import pickle
import numpy as np
# 1. Define Model Architecture
class MyNN(nn.Module):
def __init__(self, input_dim=30, output_dim=1, num_hidden_layers=2, neuron_per_layer=106, dropout_rate=0.4393):
super().__init__()
layers = []
current_dim = input_dim
for _ in range(num_hidden_layers):
layers.append(nn.Linear(current_dim, neuron_per_layer))
layers.append(nn.BatchNorm1d(neuron_per_layer))
layers.append(nn.ReLU())
layers.append(nn.Dropout(dropout_rate))
current_dim = neuron_per_layer
layers.append(nn.Linear(current_dim, output_dim))
self.model = nn.Sequential(*layers)
def forward(self, x):
return self.model(x)
# 2. Load Scaler & Model Weights
with open("scaler.pkl", "rb") as f:
scaler = pickle.load(f)
model = MyNN()
model.load_state_dict(torch.load("best_model.pth", map_location=torch.device('cpu')))
model.eval()
# 3. Predict on raw 30 feature array
sample_features = np.random.rand(1, 30) # Replace with actual 30 feature values
scaled_features = scaler.transform(sample_features)
input_tensor = torch.tensor(scaled_features, dtype=torch.float32)
with torch.no_grad():
logits = model(input_tensor)
prob = torch.sigmoid(logits).item()
prediction = "Malignant" if prob >= 0.5 else "Benign"
print(f"Prediction: {prediction} (Probability: {prob:.4f})")
3. Predict on raw 30 feature array
sample_features = np.random.rand(1, 30) # Replace with actual 30 feature values scaled_features = scaler.transform(sample_features) input_tensor = torch.tensor(scaled_features, dtype=torch.float32)
with torch.no_grad(): logits = model(input_tensor) prob = torch.sigmoid(logits).item()
prediction = "Malignant" if prob >= 0.5 else "Benign" print(f"Prediction: {prediction} (Probability: {prob:.4f})")