Реализация функций потерь для задачи классификации в Python

Вот ссылка на мой Код блокнота Kaggle.

До сих пор меня поражало разнообразие опций, доступных для каждого гиперпараметра модели. Что такое функции потерь? Какую функцию активации использовать для последнего слоя? Как выбрать функцию потерь для бинарной и многоклассовой классификации? Я понимаю, что эти вопросы будут продолжать поступать, если я не буду четко понимать каждый вариант. Поэтому я создал этот пост как отправную точку, чтобы ответить на эти вопросы.

Давайте начнем с:

Что такое функции потерь?

Функции потерь (или Функции ошибок) используются для измерения ошибки между выходными данными прогноза и предоставленным целевым значением. Функция потерь будет определять производительность модели, сравнивая расстояние между выходными данными прогноза и целевыми значениями. Меньшие потери означают, что модель работает лучше, давая прогнозы, близкие к целевым значениям.

Определим функцию потерь (J), которая принимает следующие два параметра (рис. 1):

  • Прогнозируемый результат (y_pred)
  • Целевое значение (y_true)

Эта функция будет определять производительность вашей модели, сравнивая ее прогнозируемые выходные данные с фактическими целевыми значениями. Если отклонение между y_pred и y_true очень велико, значение потерь будет очень высоким.

Если отклонение небольшое или значения почти идентичны, будет выведено очень низкое значение потерь. Следовательно, правильная функция потерь необходима, если вы хотите правильно наказать модель во время обучения.

Функции потерь изменяются в зависимости от постановки задачи, которую пытается решить ваша модель. Целью обучения вашей модели является минимизация ошибки между целевым и прогнозируемым значением путем минимизации функции потерь.

Как выбрать функцию потерь для вашей задачи?

В зависимости от характера вашей задачи функции потерь классифицируются следующим образом:

1. Регрессионная потеря:

  • Среднеквадратическая ошибка или потеря L2
  • Средняя абсолютная ошибка или потеря L1
  • Хубер Лосс

2. Классификация потерь:

Двоичная классификация:

  • Потеря шарнира
  • Сигмовидная перекрестная потеря энтропии
  • Взвешенная перекрестная потеря энтропии

Многоклассовая классификация:

  • Перекрестная потеря энтропии Softmax
  • Разреженная перекрестная потеря энтропии
  • Потеря дивергенции Кульбака-Лейблера

Примечание. Сейчас я сосредоточусь на потере классификации.

Функции потерь для бинарной классификации:

Потеря шарнира: в основном он разработан для использования с моделями машины опорных векторов (SVM) в машинном обучении. Целевая переменная должна быть изменена, чтобы она находилась в наборе {-1,1}.

Квадратная потеря шарнира: функция потерь, используемая для задач бинарной классификации с максимальной маржой. Это сглаживает поверхность функции ошибок и упрощает работу с ней в числовом виде. Целевая переменная должна быть изменена, чтобы она находилась в наборе {-1,1}.

Используйте в сочетании с функцией активации tanh() на последнем уровне.

def HingeLoss(y_pred, y_true):
    """Average hinge loss (non-regularized)
    
    Parameters:
    ----------
    y_true: torch tensor of shape (n_samples,)
        True target, consisting of integers of two values. The positive lable must 
        be greater than the negative label
    
    y_predicted: torch tensor of shape (n_samples,)
        Prediction, as output by a decision function (floats)
        
    Returns:
    ----------
    list: tensor list of calculated loss
    mean: mean loss of the batch
        Hinge loss
    """
    list_ = torch.Tensor([max(0, 1 - x*y) for x,y in zip(y_pred, y_true)])
    return list_, torch.mean(list_)

Перекрестная энтропия/логистическая потеря (CE). Перекрестная энтропийная потеря также известна как функция логистических потерь. Это самая распространенная потеря для бинарной классификации (два класса 0 и 1). Мы хотим измерить расстояние от фактического класса до прогнозируемого значения, которое обычно представляет собой действительное число от 0 до 1. Мы должны использовать сигмоидальную функцию активации в качестве последнего слоя перед применением CE. Существует 2 типа КЭ:

  • Сигмовидная перекрестная потеря энтропии: преобразуйте значения x с помощью сигмоидальной функции перед применением перекрестной потери энтропии.

def BinaryCrossEntropy(y_pred, y_true):
    """Binary cross entropy loss
    
    Parameters:
    -----------
    y_true: tensor of shape (n_samples,)
        True target, consisting of integers of two values.
    y_pred: tensor of shape (n_samples,)
        Prediction, as output by a decision function (floats)
        
    Returns:
    -----------
    list_loss: tensor of shape (n_samples,)
        BCE loss list
    loss: float
        BCE loss
    """
    #y_pred = np.clip(y_pred, 1e-7, 1 - 1e-7) to avoid the extremes of the log function
    term_0 = y_true * torch.log(y_pred + 1e-7)
    term_1 = (1-y_true) * torch.log(1-y_pred + 1e-7)
    return -(term_0+term_1),-torch.mean(term_0+term_1, axis=0)

  • Взвешенная перекрестная потеря энтропии: взвешенная версия сигмовидной перекрестной потери энтропии. Здесь укажите вес положительной цели, чтобы контролировать выбросы для положительных прогнозов.

В Pytorch BCELoss и BCEWithLogitsLoss предназначены для двоичных меток.

# weigh 1 = 0.5
pos_weight_1 = torch.tensor([0.5])
criterion = torch.nn.BCEWithLogitsLoss(pos_weight=pos_weight_1, reduction='none')
bce_weight_loss_1 = criterion(pred[:200], target[:200]) #forward

# weight 2 = 0.75
pos_weight_2 = torch.tensor([0.75])
criterion = torch.nn.BCEWithLogitsLoss(pos_weight=pos_weight_2, reduction='none')
bce_weight_loss_2 = criterion(pred[:200], target[:200])
#bce_weight_loss.shape

Давайте соберем все бинарные функции потерь вместе!

Функции потерь для многоклассовой классификации:

Категорная кросс-энтропия

Вместо использования sigmoid в качестве активации последнего слоя мы используем softmax для категориальной кросс-энтропийной потери.

BCE_list_cat, loss = BinaryCrossEntropy(pred[:200].softmax(dim=0),target[:200])

Разреженная категориальная кросс-энтропия:

Эта потеря такая же, как и кросс-энтропийная потеря softmax, за исключением того, что целью является не распределение вероятностей, а показатель того, какая категория верна. Вместо разреженного целевого вектора со всеми нулями и одним значением единицы мы просто передаем индекс категории, которая является истинным значением, следующим образом:

m = nn.LogSoftmax(dim=0)

criterion = nn.NLLLoss(reduction='none')

x = torch.tensor(np.linspace(0,4,400).reshape(200,2), dtype=torch.float32) 
y = target[:200].long()#torch.ones(250, dtype=torch.long) # expect the target to be integer (Long)

sparse_loss = criterion(m(x), y)

Убыток от расхождения Кульбака-Лейблера

Чтобы избежать проблем с недостаточным значением при вычислении этого количества, эта потеря ожидает ввод аргумента в пространство журнала. Цель аргумента также может быть указана в пространстве журнала, если log_target= True.

kl_loss = torch.nn.KLDivLoss(reduction='none', log_target=True) #specify whether the target is the log space
# input should be a distribution in the log space
input_ = F.log_softmax(pred[:200], dim=0)
log_target = F.log_softmax(target[:200], dim=0)
output = kl_loss(input_, log_target)

Давайте визуализируем все функции потерь для многоклассовой классификации!

Заключение:

Подводя итог, я рассмотрел различные функции потерь, их использование и то, как выбрать подходящую функцию активации для каждой задачи классификации. В таблице ниже показано, где можно использовать каждую из этих функций:

Использованная литература:

СТАНЬТЕ ПИСАТЕЛЕМ на MLearning.ai