Вопрос или проблема
У меня очень уникальная задача многометочной многоклассовой классификации. У меня есть нейронная сеть, которая выдает 6 логитов. Количество классов, которые мы пытаемся предсказать, составляет 2^6, то есть я кодирую свой вывод в двоичном формате. Причина этого в том, что если я просто сделаю последний слой torch.nn.Linear
с 64 нейронами, моя модель становится слишком большой. Теперь я также работаю с очень несбалансированным набором данных, где некоторые метки встречаются чаще других. У меня есть вес torch.Tensor
размером 64, который я пытаюсь передать аргументу weight
функции torch.nn.functional.cross_entropy
, но получаю ошибку:
RuntimeError: cross_entropy: weight tensor should be defined either for all 6 classes or no classes but got weight tensor of shape: [64]
Как мне назначить вес для каждой из 2^6 перестановок вывода?
Ответ или решение
Для решения вашей задачи с многометочным, многоклассовым бинарным кодированием вывода нейронной сети, а также для работы с несимметричными данными, важно учитывать несколько ключевых моментов.
Проблема с использованием torch.nn.functional.cross_entropy
Вы упомянули о том, что ваша модель выводит 6 логитов, и вы хотите использовать зерновую (бинарную) кодировку для представления 64 (2^6) классов. Однако функция torch.nn.functional.cross_entropy
ожидает, что весовая тензор будет иметь тот же размер, что и количество классов в задаче классификации. Поскольку у вас 6 классов, функция ожидает веса в виде тензора размерности [6]
, а ваш тензор имеет размерность [64]
. Именно это и вызывает ошибку.
Как задать веса для 2^6 комбинаций
Для подхода, который вы хотите реализовать, необходимо преобразовать ваш выходной вектор и соответствующим образом скорректировать веса. Вот способы, которыми вы можете это сделать:
-
Аггрегация весов:
- Вместо индивидуального назначения веса для всех 64 комбинаций, вы можете сгруппировать данные по классам и рассчитать вес для каждого из 6 классов.
- При этом каждый класс будет иметь свой вес (для 0 и 1), который можете использовать в функции
cross_entropy
.
-
Модификация меток:
- Вы можете вычислить метки для каждой комбинации, используя одну из 6 переменных. Это означает, что каждый отдельный выходной элемент вашей сети будет соотноситься с определенным классом. Вы сможете затем динамически сопоставить ваши веса в зависимости от того, как часто классы встречаются в вашей обучающей выборке.
-
Пользовательская функция потерь:
- Если вы не можете адаптировать
cross_entropy
, вы можете реализовать свою собственную функцию потерь, которая будет учитывать ваши веса и правильно агрегировать их в зависимости от бинарного кодирования. - Этот подход более сложный, но обеспечит максимальную гибкость в настройках весов.
- Если вы не можете адаптировать
Пример реализации пользовательской функции потерь
Вот пример того, как вы можете начать писать пользовательскую функцию потерь:
import torch
def custom_loss(output, target, weights):
# Преобразование логитов в вероятности
probability = torch.softmax(output, dim=1)
# Вычисление потерь для каждого класса
loss = -torch.sum(target * torch.log(probability + 1e-10), dim=1)
# Применение весов к потерям
weighted_loss = loss * weights
return weighted_loss.mean()
Заключение
Проблема, которую вы описали, связана с несовпадением размерностей ваших классов и заданных весов в функции cross_entropy
. Определив правильные веса для каждого класса и адаптивно подходя к вашему выводу, вы сможете преодолеть текущие ограничения. Рассмотрите три предложенных подхода, чтобы гарантировать наилучшие результаты для вашей модели на несимметричных данных. Управляя весами с помощью пользовательской функции потерь, вы получите ровно такую гибкость, которую ищете.