AI for Dermatoscopy Image Analysis

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1 servicesAll 1566 services
AI for Dermatoscopy Image Analysis
Complex
~2-4 weeks
FAQ
AI Development Areas
AI Solution Development Stages
Latest works
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1161
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1041
  • image_logo-advance_0.png
    B2B Advance company logo design
    561
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    823
  • image_logo-aider_0.jpg
    AIDER company logo development
    762
  • image_crm_chasseurs_493_0.webp
    CRM development for Chasseurs
    848

Разработка 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 недель