многозначная сеть классификации pytorch не обучается

#python #pytorch

#python #pytorch

Вопрос:

Я пытаюсь использовать простой пример классификации с несколькими метками, но сеть, похоже, не обучается правильно, поскольку потери остаются неизменными.

Я использовал multilabel_soft_margin_loss, как предполагают документы pytorch, но больше нечего продолжать .. не могу найти подходящих примеров в документах.

Может кто-нибудь заглянуть в это и указать, что с этим не так? Полностью рабочий пример ниже (также вопрос о предсказании ниже)

Полностью рабочий пример кода

 from __future__ import print_function
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
from sklearn.datasets import make_multilabel_classification
from torch.utils.data import TensorDataset, DataLoader
from sklearn.model_selection import train_test_split
import xgboost as xgb
from sklearn.metrics import accuracy_score
num_classes = 3
X, y = make_multilabel_classification(n_samples=1000,n_classes=num_classes)
X_tensor, y_tensor = torch.tensor(X), torch.tensor(y)
print("X Shape :{}".format(X_tensor.shape))
print("y Shape :{}".format(y_tensor.shape))


class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.fc1 = nn.Linear(X.shape[1], 300)
        self.fc2 = nn.Linear(300, 10)
        self.fc3 = nn.Linear(10, num_classes)

    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x
    

device = torch.device("cpu") 
lr = 1
batch_size = 128
gamma = 0.9
epochs = 100
args = {'log_interval': 10, 'dry_run':False}
kwargs = {'batch_size': batch_size}
kwargs.update({'num_workers': 1,
               'pin_memory': True,
               'shuffle': True},
                 )

model = Net().to(device)
optimizer = optim.Adam(model.parameters(), lr=lr, weight_decay=0.1)    
scheduler = StepLR(optimizer, step_size=1, gamma=gamma)

# data loader
my_dataset = TensorDataset(X_tensor,y_tensor) # create tensor dataset 

train_dataset, test_dataset, = train_test_split(
    my_dataset, test_size=0.2, random_state=42)

train_loader = DataLoader(train_dataset,**kwargs) 
test_loader = DataLoader(test_dataset,**kwargs) 

## Train step ##
for epoch in range(1, epochs   1):
    model.train() # set model to train
    
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data.float())
        loss = F.multilabel_soft_margin_loss(output,target)
        loss.backward()
        optimizer.step()
        if batch_idx % args['log_interval'] == 0:
            print('Train Epoch: {} [{}/{} ({:.0f}%)]tLoss: {:.6f}'.format(
                epoch, batch_idx * len(data), len(train_loader.dataset),
                100. * batch_idx / len(train_loader), loss.item()))
            if args['dry_run']:
                break
    
    scheduler.step()
  

Прогресс потери обучения

 Train Epoch: 1 [0/800 (0%)] Loss: 0.694400
Train Epoch: 2 [0/800 (0%)] Loss: 0.697095
Train Epoch: 3 [0/800 (0%)] Loss: 0.705593
Train Epoch: 4 [0/800 (0%)] Loss: 0.651981
Train Epoch: 5 [0/800 (0%)] Loss: 0.704895
Train Epoch: 6 [0/800 (0%)] Loss: 0.650302
Train Epoch: 7 [0/800 (0%)] Loss: 0.658809
Train Epoch: 8 [0/800 (0%)] Loss: 0.904834
Train Epoch: 9 [0/800 (0%)] Loss: 0.655516
Train Epoch: 10 [0/800 (0%)]    Loss: 0.662808
Train Epoch: 11 [0/800 (0%)]    Loss: 0.664752
Train Epoch: 12 [0/800 (0%)]    Loss: 0.656390
Train Epoch: 13 [0/800 (0%)]    Loss: 0.664982
Train Epoch: 14 [0/800 (0%)]    Loss: 0.664430
Train Epoch: 15 [0/800 (0%)]    Loss: 0.664603 # stagnates
  

Кроме того, как я мог бы получить прогнозы для этого? Это уже не то же самое, что использовать argmax в качестве проблемы с несколькими метками, верно? (Пример вывода сети ниже)
Вывод

 tensor([[ 0.2711,  0.1754, -0.3354],
    [ 0.2711,  0.1754, -0.3354],
    [ 0.2711,  0.1754, -0.3354],
    [ 0.2711,  0.1754, -0.3354],
    [ 0.2711,  0.1754, -0.3354],
    [ 0.2711,  0.1754, -0.3354],
    [ 0.2711,  0.1754, -0.3354]]
  

Спасибо!

Ответ №1:

Кроме того, как я мог бы получить прогнозы для этого?

Если это задача с несколькими метками, и вы выводите логиты (как и вы), тогда просто сделайте:

 output = model(data.float())
labels = output > 0
  

укажите, что с этим не так?

Это сложно и самоуверенно, что я бы сделал, чтобы:

  • проверьте свои данные. Ответ вашей нейронной сети одинаков для каждого ввода (учитывая, что ваш пример вывода реален). Возможно, вы передаете один и тот же образец (хотя это маловероятно, поскольку это sklearn созданные данные)
  • начните с простого; нет планировщика LR, нет снижения веса, только простая нейронная сеть и оптимизатор ( Adam может остаться). Используйте уменьшение веса если ваша модель переобучена, это явно не так.
  • исправьте скорость обучения; это один из самых важных гиперпараметров. 1 вероятно, слишком велико, начните с чего-то вроде 3e-4 или 1e-3 .
  • попробуйте переоборудовать (потерять ~0.0 ) небольшое количество выборок (скажем 32 , выборок). Если вы не можете, ваша нейронная сеть, вероятно, не обладает достаточной пропускной способностью или в вашем коде есть ошибка (не заметил ее с первого взгляда, помимо того, что я упомянул выше). Вы должны вручную проверить правильность входных и выходных форм и возвращаемых значений (кажется, для каждого образца сеть возвращает одни и те же логиты?).
  • если вы уверены, что ошибки нет, увеличьте пропускную способность сети. Добавьте новый скрытый слой или два (есть только один) и переобучите один пакет. Если это возможно, используйте больше данных

Я использовал multilabel_soft_margin_loss, как предлагают документы pytorch,

Это то же самое, что и использование torch.nn.BCEWithLogitsLoss , которое, я думаю, является более распространенным, но это дополнение.

Комментарии:

1. Спасибо за подробный ответ! Я подозреваю, что это как-то связано с тем, как я настроил потерю? Я не уверен, правильно ли она распространяется назад..

2. @Wboy Он распространяется правильно, возможные причины вашей потери указаны выше

3. Вы правы, попытка статического LR 0,001 сработала. это действительно странно, хотя почему такой низкий статический LR будет работать ..?

4. Это довольно стандартная скорость обучения, 1 обычно она слишком высока, и параметры, вероятно, постоянно выходят за пределы минимума.

5. Хм, у меня был довольно значительный спад LR, хотя это должно было сработать. Ну что ж, спасибо!