Как стать автором
Обновить

Нечеткое ассамблирование нейросетей для классификации на Python

Для ансамблирования нейросетей обычно используют простые методы, например, в задаче классификации, выбирают класс, за который проголосовало большинство моделей. Но что если рассматривать моделей, как экспертов, для которых мы можем оценить уровень точности? В этом посте я расскажу о своем подходе Fuzzy Vote, который использует нечеткую логику для объединения предсказаний моделей. Метод написан с помощью библиотеки fuzzyops, доступной через pypi. В библиотеке реализованы различные методы работы с нечеткими числами, поддерживаются вычисления на CUDA.

Идея метода

Каждая модель рассматривается как эксперт, который предсказывает вероятность принадлежности к классу и имеет определенную степень доверия. Эту информацию можно отразить через нечеткое число, в котором центр - это вероятность, ширина - неопределенность и высота - степень доверия.

Далее каждая модель "голосует" нечетким числом, числа агрегируются, и полученное число дефаззифицируется в одно значение. Полученное четкое число используется для классификации.

Генерация треугольного и гауссового нечеткого числа:

from fuzzyops.fuzzy_numbers import Domain, FuzzyNumber

def build_triangular(domain, centre, width, height):
    a, b, c = centre - width/2, centre, centre + width/2
    fn = domain.create_number("triangular", a, b, c)
    return fn * height

def build_gauss(domain, centre, sigma, height):
    fn = domain.create_number("gauss", sigma, centre)
    return fn * height

Агрегация одного примера:

def aggregate_sample(probs, accs, mf_type="gauss", scale_w=1.0, gamma=1.0, defuzz="cgrav"):
    domain = Domain((0.0, 1.0, 0.005), method="minimax")
    fnums = []

    for p, acc in zip(probs, accs):
        height = acc ** gamma
        width = max(0.02, (1.0 - acc) * scale_w)
        if mf_type == "tri":
            fnums.append(build_triangular(domain, p, width, height))
        else:
            sigma = width / 3.0
            fnums.append(build_gauss(domain, p, sigma, height))

    agg = sum(fnums[1:], start=fnums[0])
    return float(agg.defuzz(defuzz))

Агрегация всей выборки и оценка:

import numpy as np
from sklearn.metrics import roc_auc_score

def evaluate_fuzzy(probs_mat, y_true, acc_vec, **kwargs):
    scores = np.array([
        aggregate_sample(row, acc_vec, **kwargs)
        for row in probs_mat
    ])
    scores = (scores - scores.min()) / (scores.max() - scores.min() + 1e-12)
    return roc_auc_score(y_true, scores)

Как это сработало в задаче классификации пневмонии

Я обучил три модели (VGG19, ResNet50, DenseNet121) на датасете Chest X-Ray Pneumonia, взяв предобученные веса и переобучив классификатор на одну эпоху.

Результаты на валидационном и тестовом сете
Результаты на валидационном и тестовом сете

Метод Fuzzy-Vote дал лучшую точность, чем любая отдельная модель или простой majority vote метод. По ROC-AUC он не обошёл VGG19, но обошёл остальные методы, включая дискретный ансамбль. При этом метод не требует сложных архитектур или переобучения: он просто работает поверх уже полученных вероятностей.

Fuzzy-Vote — это простой, но гибкий способ агрегации предсказаний с учетом точности и уверенности каждой модели. Особенно полезен в случаях, когда:

  • модели сильно различаются по качеству

  • обычный majority vote даёт просадку

  • хочется объединить разные модели без дополнительного обучения

Но метод еще требует доработки, он не учитывает, например, confusion matrix каждой модели, чтобы учесть ошибки разного рода. Библиотека fuzzyops позволяет реализовать метод с минимумом кода и достаточно гибкой настройкой.

С полным кодом тренировки моделей и агрегирования можно ознакомиться по ссылке.

Теги:
+1
Комментарии0

Публикации

Работа

Data Scientist
69 вакансий

Ближайшие события