Cervical Cancer Classification CNN

A CNN model for classifying cervical colposcopy images into 4 severity classes for cervical cancer screening.

Model Description

This model classifies cervical images into:

Class Label Description Clinical Action
0 Normal Healthy cervical tissue Routine screening in 3-5 years
1 LSIL Low-grade Squamous Intraepithelial Lesion Monitor, repeat test in 6-12 months
2 HSIL High-grade Squamous Intraepithelial Lesion Colposcopy, biopsy, treatment required
3 Cancer Invasive cervical cancer Immediate oncology referral

Model Architecture

Architecture Diagram

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    INPUT IMAGE                              β”‚
β”‚                   (3 Γ— 224 Γ— 298)                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CONV BLOCK 1                                               β”‚
β”‚  β”œβ”€β”€ Conv2d(3 β†’ 32, kernel=3Γ—3, padding=1)                  β”‚
β”‚  β”œβ”€β”€ BatchNorm2d(32)                                        β”‚
β”‚  β”œβ”€β”€ ReLU                                                   β”‚
β”‚  └── MaxPool2d(2Γ—2)                                         β”‚
β”‚  Output: 32 Γ— 112 Γ— 149                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CONV BLOCK 2                                               β”‚
β”‚  β”œβ”€β”€ Conv2d(32 β†’ 64, kernel=3Γ—3, padding=1)                 β”‚
β”‚  β”œβ”€β”€ BatchNorm2d(64)                                        β”‚
β”‚  β”œβ”€β”€ ReLU                                                   β”‚
β”‚  └── MaxPool2d(2Γ—2)                                         β”‚
β”‚  Output: 64 Γ— 56 Γ— 74                                       β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CONV BLOCK 3                                               β”‚
β”‚  β”œβ”€β”€ Conv2d(64 β†’ 128, kernel=3Γ—3, padding=1)                β”‚
β”‚  β”œβ”€β”€ BatchNorm2d(128)                                       β”‚
β”‚  β”œβ”€β”€ ReLU                                                   β”‚
β”‚  └── MaxPool2d(2Γ—2)                                         β”‚
β”‚  Output: 128 Γ— 28 Γ— 37                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CONV BLOCK 4                                               β”‚
β”‚  β”œβ”€β”€ Conv2d(128 β†’ 256, kernel=3Γ—3, padding=1)               β”‚
β”‚  β”œβ”€β”€ BatchNorm2d(256)                                       β”‚
β”‚  β”œβ”€β”€ ReLU                                                   β”‚
β”‚  └── MaxPool2d(2Γ—2)                                         β”‚
β”‚  Output: 256 Γ— 14 Γ— 18                                      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  GLOBAL AVERAGE POOLING                                     β”‚
β”‚  └── AdaptiveAvgPool2d(1Γ—1)                                 β”‚
β”‚  Output: 256 Γ— 1 Γ— 1 β†’ Flatten β†’ 256                        β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  FC BLOCK 1                                                 β”‚
β”‚  β”œβ”€β”€ Linear(256 β†’ 256)                                      β”‚
β”‚  β”œβ”€β”€ ReLU                                                   β”‚
β”‚  └── Dropout(0.5)                                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  FC BLOCK 2                                                 β”‚
β”‚  β”œβ”€β”€ Linear(256 β†’ 128)                                      β”‚
β”‚  β”œβ”€β”€ ReLU                                                   β”‚
β”‚  └── Dropout(0.5)                                           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β–Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CLASSIFIER                                                 β”‚
β”‚  └── Linear(128 β†’ 4)                                        β”‚
β”‚  Output: 4 class logits                                     β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                          β–Ό
              [Normal, LSIL, HSIL, Cancer]

Architecture Summary Table

Layer Type Input Shape Output Shape Parameters
conv_layers.0 Conv2d (3, 224, 298) (32, 224, 298) 896
conv_layers.1 BatchNorm2d (32, 224, 298) (32, 224, 298) 64
conv_layers.2 ReLU - - 0
conv_layers.3 MaxPool2d (32, 224, 298) (32, 112, 149) 0
conv_layers.4 Conv2d (32, 112, 149) (64, 112, 149) 18,496
conv_layers.5 BatchNorm2d (64, 112, 149) (64, 112, 149) 128
conv_layers.6 ReLU - - 0
conv_layers.7 MaxPool2d (64, 112, 149) (64, 56, 74) 0
conv_layers.8 Conv2d (64, 56, 74) (128, 56, 74) 73,856
conv_layers.9 BatchNorm2d (128, 56, 74) (128, 56, 74) 256
conv_layers.10 ReLU - - 0
conv_layers.11 MaxPool2d (128, 56, 74) (128, 28, 37) 0
conv_layers.12 Conv2d (128, 28, 37) (256, 28, 37) 295,168
conv_layers.13 BatchNorm2d (256, 28, 37) (256, 28, 37) 512
conv_layers.14 ReLU - - 0
conv_layers.15 MaxPool2d (256, 28, 37) (256, 14, 18) 0
avgpool AdaptiveAvgPool2d (256, 14, 18) (256, 1, 1) 0
fc_layers.0 Linear 256 256 65,792
fc_layers.1 ReLU - - 0
fc_layers.2 Dropout - - 0
fc_layers.3 Linear 256 128 32,896
fc_layers.4 ReLU - - 0
fc_layers.5 Dropout - - 0
classifier Linear 128 4 516
Total 488,580

PyTorch Model Code

import torch
import torch.nn as nn

class CervicalCancerCNN(nn.Module):
    def __init__(self):
        super().__init__()

        # Convolutional layers: [32, 64, 128, 256]
        self.conv_layers = nn.Sequential(
            # Block 1: 3 -> 32
            nn.Conv2d(3, 32, kernel_size=3, padding=1),
            nn.BatchNorm2d(32),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),

            # Block 2: 32 -> 64
            nn.Conv2d(32, 64, kernel_size=3, padding=1),
            nn.BatchNorm2d(64),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),

            # Block 3: 64 -> 128
            nn.Conv2d(64, 128, kernel_size=3, padding=1),
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),

            # Block 4: 128 -> 256
            nn.Conv2d(128, 256, kernel_size=3, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(2, 2),
        )

        self.avgpool = nn.AdaptiveAvgPool2d(1)

        # Fully connected layers: [256, 128] -> 4
        self.fc_layers = nn.Sequential(
            nn.Linear(256, 256),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
            nn.Linear(256, 128),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),
        )

        self.classifier = nn.Linear(128, 4)

    def forward(self, x):
        x = self.conv_layers(x)
        x = self.avgpool(x)
        x = x.view(x.size(0), -1)
        x = self.fc_layers(x)
        x = self.classifier(x)
        return x

Performance

Overall Metrics

Metric Value
Accuracy 59.52%
Macro F1 59.85%
Parameters 488,580

Per-Class Metrics

Class Precision Recall F1 Score Support
Normal 0.595 0.595 0.595 84
LSIL 0.521 0.583 0.551 84
HSIL 0.446 0.440 0.443 84
Cancer 0.853 0.762 0.805 84

Confusion Matrix

Predicted β†’     Normal    LSIL    HSIL   Cancer
Actual ↓
Normal            50        9       17       8
LSIL              24       49       11       0
HSIL               9       35       37       3
Cancer             1        1       18      64

Usage

Installation

pip install torch torchvision safetensors huggingface_hub

Loading the Model

import torch
from safetensors.torch import load_file
from huggingface_hub import hf_hub_download
import json

# Download model files
model_file = hf_hub_download("toderian/cerviguard_lesion", "model.safetensors")
config_file = hf_hub_download("toderian/cerviguard_lesion", "config.json")

# Load config
with open(config_file) as f:
    config = json.load(f)

# Define model (copy from above or download modeling_cervical.py)
model = CervicalCancerCNN()

# Load weights
state_dict = load_file(model_file)
model.load_state_dict(state_dict)
model.eval()

Inference

from PIL import Image
import torchvision.transforms as T

# Preprocessing
transform = T.Compose([
    T.Resize((224, 298)),
    T.ToTensor(),
    T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),
])

# Load and preprocess image
image = Image.open("cervical_image.jpg").convert("RGB")
input_tensor = transform(image).unsqueeze(0)

# Inference
with torch.no_grad():
    output = model(input_tensor)
    probabilities = torch.softmax(output, dim=1)
    prediction = output.argmax(dim=1).item()

classes = ["Normal", "LSIL", "HSIL", "Cancer"]
print(f"Prediction: {classes[prediction]}")
print(f"Confidence: {probabilities[0][prediction]:.2%}")

Training Details

Parameter Value
Learning Rate 1e-4
Batch Size 32
Optimizer Adam
Loss CrossEntropyLoss
Dropout 0.5
Epochs 34 (early stopping at 24)

Dataset

Split Samples Distribution
Train 3,003 Imbalanced [1540, 469, 854, 140]
Test 336 Balanced [84, 84, 84, 84]

Limitations

  • Trained on limited dataset (~3k samples)
  • HSIL class has lowest performance (F1=0.443)
  • Should not be used as sole diagnostic tool
  • Intended for research and screening assistance only

Medical Disclaimer

⚠️ This model is for research purposes only. It should not be used as a substitute for professional medical diagnosis. Always consult qualified healthcare professionals for cervical cancer screening and diagnosis.


Files in This Repository

File Description
model.safetensors Model weights (safetensors format)
pytorch_model.bin Model weights (legacy PyTorch format)
config.json Model configuration
preprocessor_config.json Image preprocessing settings
modeling_cervical.py Model class definition
example_inference.py Example inference script

Citation

@misc{cervical-cancer-cnn-2025,
  author = {Toderian},
  title = {Cervical Cancer Classification CNN},
  year = {2025},
  publisher = {Hugging Face},
  url = {https://huggingface.co/toderian/cerviguard_lesion}
}
Downloads last month
6
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support