Ensemble deep learning model combining ResNet-50, EfficientNet-B3, and MobileNetV2 for dermatological image classification, achieving 96.33% accuracy on skin lesion detection.
Published at ICoICI-2024 (IEEE)
Skin lesion classification is a domain where the failure modes are asymmetric in a way that matters: missing a melanoma is not the same kind of error as flagging a benign mole. Individual CNN architectures each have characteristic blind spots, and a single model's confidence tells you nothing about whether you're in one of them.
I combined three pre-trained networks chosen for genuinely different architectural strengths rather than for variety's sake. ResNet-50 contributes deep feature extraction via residual connections that avoid gradient degradation. EfficientNet-B3 brings compound scaling tuned for accuracy per unit of compute. MobileNetV2 adds depthwise separable convolutions, the deployment-friendly member of the group.
All three were fine-tuned on dermoscopic images from ImageNet weights, then combined through weighted voting where each model's prediction confidence feeds the final classification. The weights are learned parameters passed through a softmax, not fixed constants, so the ensemble tunes its own trust in each member.
96.33% accuracy across melanoma, basal cell carcinoma, and benign categories, higher than any individual model in the ensemble. The complementary architectures cover each other on the edge cases where a single model gets confidently wrong.
Published at ICoICI-2024 (IEEE) and designed as a clinician decision-support tool for early malignancy detection, not as an autonomous diagnostic.
Ensembles only pay off when the members fail differently. Three variations of the same architecture would have averaged their errors instead of covering them. The diversity was the whole mechanism.
class SkinCancerEnsemble(nn.Module):
"""Weighted ensemble of ResNet-50, EfficientNet-B3, MobileNetV2."""
def __init__(self, num_classes: int):
super().__init__()
self.resnet = models.resnet50(pretrained=True)
self.effnet = models.efficientnet_b3(pretrained=True)
self.mobilenet = models.mobilenet_v2(pretrained=True)
# Replace classification heads
self.resnet.fc = nn.Linear(2048, num_classes)
self.effnet.classifier[1] = nn.Linear(1536, num_classes)
self.mobilenet.classifier[1] = nn.Linear(1280, num_classes)
# Learned ensemble weights
self.weights = nn.Parameter(torch.ones(3) / 3)
def forward(self, x):
w = F.softmax(self.weights, dim=0)
preds = (w[0] * self.resnet(x) +
w[1] * self.effnet(x) +
w[2] * self.mobilenet(x))
return preds