Medical AISelf-Supervised Learning

Self-Supervised Learning in Medical Imaging: From Pretext Tasks to Foundation Models

contrastive-learningvision-transformersmedical-imagingrepresentation-learningdeep-learning

#Introduction

Medical image analysis has been transformed by deep learning, yet a persistent bottleneck remains: the scarcity of expert annotations. Labeling medical images requires domain expertise (radiologists, pathologists), making large-scale annotation prohibitively expensive.

Self-Supervised Learning (SSL) offers a compelling solution by learning meaningful representations from unlabeled data — of which medical institutions have vast amounts.

#The Annotation Bottleneck

Consider the cost of annotation across modalities:

Modality Annotation Type Time per Image Expert Required
Chest X-ray Disease classification 2-5 min Radiologist
Histopathology Pixel-level segmentation 30-60 min Pathologist
Retinal OCT Layer segmentation 15-30 min Ophthalmologist
Dermoscopy Lesion boundary 5-10 min Dermatologist

SSL techniques learn from the inherent structure in images, dramatically reducing label requirements.

#Contrastive Learning for Medical Images

#SimCLR Framework

The core idea of contrastive learning is to learn representations where similar samples are close and dissimilar samples are far apart in the embedding space.

The NT-Xent (Normalized Temperature-scaled Cross-Entropy) loss for a positive pair (i,j)(i, j):

i,j=logexp(sim(zi,zj)/τ)k=12N1[ki]exp(sim(zi,zk)/τ)\ell_{i,j} = -\log \frac{\exp(\text{sim}(z_i, z_j) / \tau)}{\sum_{k=1}^{2N} \mathbf{1}_{[k \neq i]} \exp(\text{sim}(z_i, z_k) / \tau)}

where sim(u,v)=uvuv\text{sim}(u, v) = \frac{u^\top v}{\|u\| \|v\|} is the cosine similarity and τ\tau is the temperature parameter.

#Medical-Specific Augmentations

Standard augmentations (random crops, color jitter) may destroy diagnostic features in medical images. Domain-specific augmentations are crucial:

import torchvision.transforms as T
from typing import Tuple

class MedicalSSLAugmentation:
    """Augmentation pipeline for medical image SSL.
    
    Preserves diagnostic features while creating
    diverse positive pairs for contrastive learning.
    """
    
    def __init__(self, image_size: int = 224):
        self.transform = T.Compose([
            # Geometric transforms (mild)
            T.RandomResizedCrop(
                image_size, scale=(0.7, 1.0),
                ratio=(0.9, 1.1)  # Less aggressive than natural images
            ),
            T.RandomHorizontalFlip(p=0.5),
            T.RandomVerticalFlip(p=0.5),  # Valid for pathology
            T.RandomRotation(degrees=15),  # Mild rotation
            
            # Intensity transforms (critical for medical)
            T.RandomAdjustSharpness(
                sharpness_factor=2, p=0.3
            ),
            T.GaussianBlur(
                kernel_size=23, sigma=(0.1, 2.0)
            ),
            T.RandomAutocontrast(p=0.3),
            
            # Normalize to ImageNet stats (if using pretrained)
            T.ToTensor(),
            T.Normalize(
                mean=[0.485, 0.456, 0.406],
                std=[0.229, 0.224, 0.225]
            ),
        ])
    
    def __call__(self, x) -> Tuple:
        """Generate two augmented views."""
        return self.transform(x), self.transform(x)

Important: Color jitter should be used cautiously — stain variations in histopathology carry diagnostic information, while intensity changes in X-rays can obscure pathology.

#Vision Transformers Meet SSL

#DINO: Self-Distillation with No Labels

DINO (Caron et al., 2021) demonstrated that Vision Transformers (ViTs) trained with SSL produce features with remarkable semantic structure. The self-distillation objective:

LDINO=x{x1g,x2g}xVxxH(Pt(x),Ps(x))\mathcal{L}_{\text{DINO}} = - \sum_{x \in \{x_1^g, x_2^g\}} \sum_{\substack{x' \in V \\ x' \neq x}} H(P_t(x), P_s(x'))

where PtP_t and PsP_s are the teacher and student probability distributions:

Ps(x)(i)=exp(gθs(x)(i)/τs)kexp(gθs(x)(k)/τs)P_s(x)^{(i)} = \frac{\exp(g_{\theta_s}(x)^{(i)} / \tau_s)}{\sum_k \exp(g_{\theta_s}(x)^{(k)} / \tau_s)}

#Implementation for Medical ViT

import torch
import torch.nn as nn
import torch.nn.functional as F

class DINOHead(nn.Module):
    """Projection head for DINO self-distillation."""
    
    def __init__(self, in_dim: int, hidden_dim: int = 2048,
                 bottleneck_dim: int = 256, out_dim: int = 65536):
        super().__init__()
        self.mlp = nn.Sequential(
            nn.Linear(in_dim, hidden_dim),
            nn.GELU(),
            nn.Linear(hidden_dim, hidden_dim),
            nn.GELU(),
            nn.Linear(hidden_dim, bottleneck_dim),
        )
        self.last_layer = nn.utils.weight_norm(
            nn.Linear(bottleneck_dim, out_dim, bias=False)
        )
        self.last_layer.weight_g.data.fill_(1)
    
    def forward(self, x: torch.Tensor) -> torch.Tensor:
        x = self.mlp(x)
        x = F.normalize(x, dim=-1, p=2)
        x = self.last_layer(x)
        return x


class DINOLoss(nn.Module):
    """Cross-entropy loss for DINO self-distillation."""
    
    def __init__(self, out_dim: int, teacher_temp: float = 0.04,
                 student_temp: float = 0.1, center_momentum: float = 0.9):
        super().__init__()
        self.teacher_temp = teacher_temp
        self.student_temp = student_temp
        self.center_momentum = center_momentum
        self.register_buffer("center", torch.zeros(1, out_dim))
    
    def forward(self, student_output: torch.Tensor,
                teacher_output: torch.Tensor) -> torch.Tensor:
        student_probs = F.log_softmax(
            student_output / self.student_temp, dim=-1
        )
        teacher_probs = F.softmax(
            (teacher_output - self.center) / self.teacher_temp, 
            dim=-1
        ).detach()
        
        loss = -torch.sum(
            teacher_probs * student_probs, dim=-1
        ).mean()
        
        # Update center with EMA
        self.center = (
            self.center_momentum * self.center + 
            (1 - self.center_momentum) * teacher_output.mean(dim=0)
        )
        
        return loss

#Evaluation: Linear Probing Protocol

The standard evaluation for SSL representations is linear probing — training a linear classifier on frozen features:

Accuracylinear=maxW,b1Ni=1N1[Wfθ(xi)+b=yi]\text{Accuracy}_{\text{linear}} = \max_{W, b} \frac{1}{N} \sum_{i=1}^{N} \mathbf{1}[W \cdot f_\theta(x_i) + b = y_i]

Typical results on medical benchmarks:

Method CheXpert (AUC) PathMNIST (Acc) DermaMNIST (Acc)
Random Init 0.761 72.3% 71.5%
ImageNet Supervised 0.867 86.7% 78.2%
SimCLR (Medical) 0.854 88.1% 77.9%
DINO (Medical) 0.881 90.4% 80.1%

#Emerging Directions

#Foundation Models for Medical Imaging

Large-scale pre-trained models are emerging as foundation models for medical AI:

  1. BiomedCLIP — Vision-language alignment on PubMed figure-caption pairs
  2. PathDino — Self-supervised pathology-specific ViT
  3. CheXzero — Zero-shot chest X-ray interpretation

The training objective for vision-language models like BiomedCLIP combines:

LCLIP=12N[i=1Nlogesii/τjesij/τ+i=1Nlogesii/τjesji/τ]\mathcal{L}_{\text{CLIP}} = -\frac{1}{2N}\left[\sum_{i=1}^{N} \log \frac{e^{s_{ii}/\tau}}{\sum_j e^{s_{ij}/\tau}} + \sum_{i=1}^{N} \log \frac{e^{s_{ii}/\tau}}{\sum_j e^{s_{ji}/\tau}}\right]

where sij=fimage(xi)gtext(tj)s_{ij} = f_{\text{image}}(x_i)^\top g_{\text{text}}(t_j) is the similarity score.

#Conclusion

Self-supervised learning is rapidly closing the gap with supervised methods in medical imaging, and in some cases surpassing them — especially in low-data regimes. Key takeaways:

  • Domain-specific augmentations are critical for medical SSL
  • Vision Transformers with self-distillation (DINO) produce semantically rich features
  • Foundation models trained on paired image-text data enable zero-shot generalization
  • The path forward combines SSL pretraining with efficient fine-tuning (LoRA, adapters) for clinical deployment

Previous: Understanding Federated Learning. This post is part of a series on modern deep learning for healthcare.