Разработка AI для анализа дерматоскопических изображений
Дерматоскопия — оптическое исследование кожных образований с 10x увеличением и специальным освещением. AI-анализ дерматоскопических изображений решает задачу дифференциальной диагностики: меланома vs доброкачественное образование. Точность опытного дерматолога: 75–84%, AI-систем последнего поколения: 86–91% AUC.
HAM10000 Dataset и задача классификации
HAM10000 (Human Against Machine with 10000 training images) — стандартный бенчмарк. 10,015 дерматоскопических изображений, 7 классов:
HAM10000_CLASSES = {
0: 'akiec', # Actinic Keratoses (предраковые)
1: 'bcc', # Basal Cell Carcinoma (базально-клеточная)
2: 'bkl', # Benign Keratosis (доброкачественные кератозы)
3: 'df', # Dermatofibroma (дерматофибромы)
4: 'mel', # Melanoma (меланома) ← критически важный класс
5: 'nv', # Melanocytic Nevi (меланоцитарные невусы)
6: 'vasc' # Vascular Lesions (сосудистые)
}
import timm
import torch
import torch.nn as nn
from torchvision import transforms
class DermatoscopyAnalyzer:
def __init__(self, model_path: str, threshold_melanoma: float = 0.3):
# EfficientNetV2-L показывает лучший результат на HAM10000
backbone = timm.create_model('efficientnetv2_l', pretrained=False,
num_classes=0)
self.model = nn.Sequential(
backbone,
nn.Linear(backbone.num_features, 512),
nn.GELU(),
nn.Dropout(0.4),
nn.Linear(512, 7)
)
self.model.load_state_dict(torch.load(model_path))
self.model.eval()
# Порог для меланомы НИЖЕ стандартного 0.5
# Предпочитаем sensitivity над specificity
self.mel_threshold = threshold_melanoma
self.transform = transforms.Compose([
transforms.Resize((450, 450)),
transforms.CenterCrop(400),
transforms.ToTensor(),
transforms.Normalize([0.7630, 0.5456, 0.5700],
[0.1409, 0.1520, 0.1700]) # HAM10000 stats
])
@torch.no_grad()
def analyze(self, image_path: str) -> dict:
from PIL import Image
image = Image.open(image_path).convert('RGB')
tensor = self.transform(image).unsqueeze(0)
logits = self.model(tensor)
probs = torch.softmax(logits, dim=1).squeeze().numpy()
mel_prob = float(probs[4]) # индекс меланомы
return {
'class_probabilities': {
HAM10000_CLASSES[i]: float(probs[i]) for i in range(7)
},
'predicted_class': HAM10000_CLASSES[probs.argmax()],
'melanoma_probability': mel_prob,
'melanoma_alert': mel_prob > self.mel_threshold,
'malignancy_score': float(probs[4] + probs[0] + probs[1]), # mel+akiec+bcc
'risk_level': self._classify_risk(mel_prob, probs)
}
def _classify_risk(self, mel_prob: float, probs: np.ndarray) -> str:
malignant_score = probs[4] + probs[0] + probs[1]
if mel_prob > 0.5 or malignant_score > 0.6:
return 'HIGH'
elif mel_prob > 0.3 or malignant_score > 0.4:
return 'MEDIUM'
return 'LOW'
ABCD-правило в ML
Дерматологи используют ABCD-правило: Asymmetry, Border, Color, Dermoscopic structures. ML-модель можно обучить предсказывать эти признаки как промежуточные метки (multi-task learning) для explainability:
class ABCDAnalyzer(nn.Module):
def __init__(self):
super().__init__()
self.backbone = timm.create_model('efficientnetv2_m', num_classes=0)
feat_dim = self.backbone.num_features
self.asymmetry_head = nn.Linear(feat_dim, 1)
self.border_head = nn.Linear(feat_dim, 1)
self.color_head = nn.Linear(feat_dim, 5) # цветовые признаки
self.structures_head = nn.Linear(feat_dim, 10) # дерматоскопические структуры
self.diagnosis_head = nn.Linear(feat_dim, 7) # итоговый диагноз
def forward(self, x):
features = self.backbone(x)
return {
'asymmetry': torch.sigmoid(self.asymmetry_head(features)),
'border': torch.sigmoid(self.border_head(features)),
'colors': torch.sigmoid(self.color_head(features)),
'structures': torch.sigmoid(self.structures_head(features)),
'diagnosis': self.diagnosis_head(features)
}
Особенности дисбаланса классов
Меланома составляет только 10–12% датасета. Стратегии:
- Weighted sampling с весом обратно пропорциональным частоте класса
- Focal Loss с γ=2–5
- MixUp augmentation для underrepresented классов
- TTA (Test Time Augmentation): среднее 8–10 аугментированных версий
Metrics
| Метрика | EfficientNetV2-L | Dermatologist avg |
|---|---|---|
| AUC (mel vs all) | 0.93 | 0.87 |
| Sensitivity (mel) | 88% | 82% |
| Specificity (mel) | 84% | 86% |
| Accuracy (7 классов) | 89% | — |
| Задача | Срок |
|---|---|
| Классификатор на HAM10000 | 4–6 недель |
| Кастомная модель на корпоративных данных | 8–14 недель |
| ABCD + explainability + клиническая валидация | 16–28 недель |







