web-dev-qa-db-fra.com

Fonction de perte personnalisée PyTorch

Comment mettre en œuvre une fonction de perte personnalisée? L'utilisation du code ci-dessous provoque une erreur:

import torch
import torch.nn as nn
import torchvision
import torchvision.transforms as transforms
import numpy as np
import matplotlib.pyplot as plt
import torch.utils.data as data_utils
import torch.nn as nn
import torch.nn.functional as F

num_epochs = 20

x1 = np.array([0,0])
x2 = np.array([0,1])
x3 = np.array([1,0])
x4 = np.array([1,1])

num_epochs = 200

class cus2(torch.nn.Module):

    def __init__(self):
        super(cus2,self).__init__()

    def forward(self, outputs, labels):
        # reshape labels to give a flat vector of length batch_size*seq_len
        labels = labels.view(-1)  

        # mask out 'PAD' tokens
        mask = (labels >= 0).float()

        # the number of tokens is the sum of elements in mask
        num_tokens = int(torch.sum(mask).data[0])

        # pick the values corresponding to labels and multiply by mask
        outputs = outputs[range(outputs.shape[0]), labels]*mask

        # cross entropy loss for all non 'PAD' tokens
        return -torch.sum(outputs)/num_tokens


x = torch.tensor([x1,x2,x3,x4]).float()

y = torch.tensor([0,1,1,0]).long()

train = data_utils.TensorDataset(x,y)
train_loader = data_utils.DataLoader(train , batch_size=2 , shuffle=True)

device = 'cpu'

input_size = 2
hidden_size = 100 
num_classes = 2

learning_rate = .0001

class NeuralNet(nn.Module) : 
    def __init__(self, input_size, hidden_size, num_classes) : 
        super(NeuralNet, self).__init__()
        self.fc1 = nn.Linear(input_size , hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size , num_classes)

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

for i in range(0 , 1) :

        model = NeuralNet(input_size, hidden_size, num_classes).to(device)

        criterion = nn.CrossEntropyLoss()
#         criterion = Regress_Loss()
#         criterion = cus2()
        optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

        total_step = len(train_loader)
        for Epoch in range(num_epochs) : 
            for i,(images , labels) in enumerate(train_loader) : 
                images = images.reshape(-1 , 2).to(device)
                labels = labels.to(device)

                outputs = model(images)
                loss = criterion(outputs , labels)

                optimizer.zero_grad()
                loss.backward()
                optimizer.step()
#                 print(loss)

        outputs = model(x)

        print(outputs.data.max(1)[1])

fait des prédictions parfaites sur les données d'entraînement:

tensor([0, 1, 1, 0])

Utiliser une fonction de perte personnalisée de https://cs230-stanford.github.io/pytorch-nlp.html#writing-a-custom-loss-function :

enter image description here

est implémenté dans le code ci-dessus comme cus2

Le code sans commentaire # criterion = cus2() pour utiliser cette fonction de perte renvoie:

tensor([0, 0, 0, 0])

Un avertissement est également renvoyé:

UserWarning: index non valide d'un tenseur de 0 dim. Ce sera une erreur dans PyTorch 0.5. Utilisez tensor.item () pour convertir un tenseur de 0 dim en un nombre Python

Je n'ai pas implémenté correctement la fonction de perte personnalisée?

7
blue-sky

Votre fonction de perte est correcte par programme, à l'exception de ce qui suit:

    # the number of tokens is the sum of elements in mask
    num_tokens = int(torch.sum(mask).data[0])

Lorsque vous faites torch.sum, Il renvoie un tenseur à 0 dimension et donc l'avertissement qu'il ne peut pas être indexé. Pour résoudre ce problème, faites int(torch.sum(mask).item()) comme suggéré ou int(torch.sum(mask)) fonctionnera également.

Maintenant, essayez-vous d'émuler la perte CE en utilisant la perte personnalisée? Si oui, il vous manque le log_softmax

Pour résoudre ce problème, ajoutez outputs = torch.nn.functional.log_softmax(outputs, dim=1) avant l'instruction 4. Notez que dans le cas du didacticiel que vous avez joint, log_softmax Est déjà effectué dans l'appel de transfert. Vous pouvez faire cela aussi.

De plus, j'ai remarqué que le taux d'apprentissage est lent et même avec une perte de CE, les résultats ne sont pas cohérents. Augmenter le taux d'apprentissage à 1e-3 fonctionne bien pour moi en cas de perte de coutume et de CE.

4
Umang Gupta