Aivaro
  • Оглавление
  • Вопросы
  • Практика
  • Вики
  • Материалы сообщества
  • Тесты
  • Поиск
✈Telegram @ai_varo
RUEN中文
…
Оглавление/Вопросы/#915

Что такое Multilabel Classification (в отличие от Multiclass)? Какую функцию потерь использовать для multilabel?

Краткий тезис

Multilabel classification — задача, где каждый объект может одновременно принадлежать нескольким классам (меткам), в отличие от multiclass, где объект относится ровно к одному из N взаимоисключающих классов. Для multilabel стандартная функция потерь — Binary Cross Entropy (BCE), применяемая независимо к каждой метке, а не Categorical Cross Entropy, которая используется для multiclass. Порог принятия решений в multilabel часто требует калибровки, отличной от стандартного 0.5.

2. Multilabel: несколько бинарных меток

Multilabel classification — задача, где каждый образец может иметь произвольное количество меток из фиксированного набора (вплоть до всех или ни одной). Метки не являются взаимоисключающими.

Ключевые характеристики:

  • Выходной слой: sigmoid (независимо для каждой метки, вероятность от 0 до 1)
  • Функция потерь: Binary Cross Entropy (BCE), суммированная по всем меткам
  • Примеры: тегирование изображений (кошка, собака, улица — одновременно), категоризация текста по жанрам, определение симптомов в медицинской диагностике
  • Предсказание: пороговое решение (обычно 0.5) для каждой метки независимо

Математическая формулировка: Для M меток модель выводит вектор вероятностей p = [p₁, p₂, ..., pₘ], где каждая pⱼ ∈ [0,1] независима. Истинные метки — бинарный вектор y (0 или 1 для каждой метки). Функция потерь:

L = -Σⱼ [yⱼ * log(pⱼ) + (1 - yⱼ) * log(1 - pⱼ)]

Пример в NLP: Классификация отзыва на продукт — один отзыв может одновременно содержать метки «качество», «цена», «доставка» и «обслуживание».

Ключевое отличие от multiclass:

ХарактеристикаMulticlassMultilabel
Количество классов на объектРовно 10, 1 или несколько
ВзаимоисключениеДаНет
Функция активацииSoftmaxSigmoid (поэлементно)
Функция потерьCCEBCE
Метод предсказанияArgmaxПорог (threshold)

3. Функции потерь: Binary Cross Entropy (BCE) vs Categorical Cross Entropy

Binary Cross Entropy (BCE) для multilabel

BCE рассматривает каждую метку как независимую бинарную задачу. Это корректно, так как метки не конкурируют друг с другом.

Формула (для одной метки j):

BCEⱼ = -[yⱼ * log(σ(zⱼ)) + (1 - yⱼ) * log(1 - σ(zⱼ))]

где σ(zⱼ) — сигмоида от логита zⱼ.

Реализация в PyTorch:

import torch.nn as nn

# Вариант 1: BCEWithLogitsLoss (численно стабильнее)
criterion = nn.BCEWithLogitsLoss()
loss = criterion(logits, targets)  # logits: [batch, num_labels], targets: [batch, num_labels]

# Вариант 2: Sigmoid + BCELoss
criterion = nn.BCELoss()
probs = torch.sigmoid(logits)
loss = criterion(probs, targets)

Реализация в TensorFlow/Keras:

import tensorflow as tf

# Для multilabel
model.compile(optimizer='adam',
              loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
              metrics=['accuracy'])

Categorical Cross Entropy (CCE) для multiclass

CCE предполагает, что только один класс может быть истинным. Если применить CCE к multilabel, модель будет штрафовать за одновременное предсказание нескольких меток, что некорректно.

Формула:

CCE = -Σᵢ yᵢ * log(pᵢ)

где pᵢ — softmax-вероятность класса i.

Почему CCE не подходит для multilabel:

  • Softmax нормализует выходы так, что сумма вероятностей = 1, создавая ложную конкуренцию между метками
  • Если истинных меток несколько, CCE будет пытаться «выбрать» одну, игнорируя остальные
  • Градиенты будут распределяться неверно, ухудшая обучение

Альтернативы BCE для multilabel

  1. Focal Loss — модификация BCE для работы с дисбалансом классов:

    FL = -α * (1 - p)ᵞ * log(p)  для положительных меток
    

    где γ ≥ 0 фокусирует обучение на сложных примерах.

  2. Asymmetric Loss (ASL) — адаптация Focal Loss для multilabel с разными весами для положительных и отрицательных меток.

  3. Ranking-based losses (например, ListNet) — оптимизируют ранжирование меток, а не пороговую классификацию.


4. Порог принятия решений (0.5 vs оптимальный)

Стандартный порог 0.5

По умолчанию для multilabel используется порог 0.5: если sigmoid-вероятность ≥ 0.5, метка считается положительной. Однако это не всегда оптимально.

Проблемы порога 0.5:

  • Дисбаланс классов: если метка встречается редко (например, 5% объектов), порог 0.5 может давать слишком много ложных срабатываний
  • Разная стоимость ошибок: false positive и false negative могут иметь разную цену
  • Калибровка модели: вероятности могут быть смещены (overconfident или underconfident)

Поиск оптимального порога

Оптимальный порог подбирается индивидуально для каждой метки или глобально на валидационной выборке.

Методы поиска порога:

  1. По метрике F1 — максимизация F1-score на валидации:

    from sklearn.metrics import f1_score
    import numpy as np
    
    def find_optimal_threshold(y_true, y_pred_probs):
        best_threshold = 0.5
        best_f1 = 0
        for threshold in np.arange(0.1, 0.9, 0.05):
            y_pred = (y_pred_probs >= threshold).astype(int)
            f1 = f1_score(y_true, y_pred, average='micro')
            if f1 > best_f1:
                best_f1 = f1
                best_threshold = threshold
        return best_threshold, best_f1
    
  2. По метрике Jaccard index (IoU) — для задач, где важна точность совпадения наборов меток.

  3. Per-label thresholds — отдельный порог для каждой метки:

    thresholds = {}
    for label in range(num_labels):
        best_th, _ = find_optimal_threshold(y_true[:, label], y_pred_probs[:, label])
        thresholds[label] = best_th
    
  4. Threshold-moving с ROC-кривой — выбор точки на ROC-кривой, ближайшей к (0,1) или максимизирующей метрику.

Практические рекомендации

  • Начинайте с порога 0.5, но обязательно калибруйте на валидации
  • Для редких меток (менее 10% объектов) порог часто нужно снижать до 0.3-0.4
  • Используйте Precision-Recall curve вместо ROC при сильном дисбалансе
  • Рассмотрите label smoothing для улучшения калибровки вероятностей

5. Пет-проект для закрепления

Задача: Разработать классификатор тегов для новостных статей, где одна статья может иметь несколько тегов (например, «технологии», «бизнес», «наука»).

Инструменты:

  • Python, PyTorch или TensorFlow
  • Hugging Face Transformers (BERT или RuBERT)
  • scikit-learn для метрик и поиска порога
  • Датасет: LC-QuAD 2.0 или любой multilabel-датасет (например, Reuters-21578)

Шаги:

  1. Загрузите multilabel-датасет (например, Reuters с 90 категориями)
  2. Предобработайте тексты: токенизация, паддинг до фиксированной длины
  3. Загрузите предобученный BERT (bert-base-uncased) и замените head на линейный слой с num_labels нейронами
  4. Обучите модель с BCEWithLogitsLoss, используя AdamW
  5. На валидации подберите оптимальный порог (по F1-micro)
  6. Сравните метрики при пороге 0.5 и оптимальном пороге
  7. Визуализируйте confusion matrix для 5 самых частых меток

Ожидаемый результат:

  • Модель с F1-micro > 0.85 на тестовой выборке
  • График зависимости F1 от порога
  • Вывод: оптимальный порог отличается от 0.5 (обычно ниже для редких меток)

Связь с другими вопросами

ВопросТема
914Что такое Multiclass Classification и как работает softmax?
916Как работает Hierarchical Classification для иерархических меток?

Навигация

  • Предыдущий: 914
  • Следующий: 916
  • Индекс: 00. Индекс разборов