Salut, je suis nouveau dans l'apprentissage automatique et j'ai une question sur la modification des seuils pour la fonction sigmoïde.

Je sais que la valeur de la fonction sigmoïde est dans la plage [0; 1], 0,5 est pris comme seuil, si h (thêta) <0,5 nous supposons que sa valeur est 0, si h (thêta)> = 0,5 alors c'est 1.

Les seuils ne sont utilisés que sur la couche de sortie du réseau et ce n'est que lors de la classification. Donc, si vous essayez de classer entre 3 classes, pouvez-vous donner des seuils différents pour chaque classe (0,2,0,4,0,4 - pour chaque classe)? Ou pouvez-vous spécifier un seuil différent dans l'ensemble, comme 0,8? Je ne sais pas comment définir cela dans le code ci-dessous. Toute orientation est appréciée.

# Hyper Parameters
input_size = 14
hidden_size = 40
hidden_size2 = 30
num_classes = 3
num_epochs = 600
batch_size = 34
learning_rate = 0.01


class Net(torch.nn.Module):
    def __init__(self, n_input, n_hidden, n_hidden2, n_output):
        super(Net, self).__init__()
        # define linear hidden layer output
        self.hidden = torch.nn.Linear(n_input, n_hidden)
        self.hidden2 = torch.nn.Linear(n_hidden, n_hidden2)
        # define linear output layer output
        self.out = torch.nn.Linear(n_hidden, n_output)

    def forward(self, x):
        """
            In the forward function we define the process of performing
            forward pass, that is to accept a Variable of input
            data, x, and return a Variable of output data, y_pred.
        """
        # get hidden layer input
        h_input1 = self.hidden(x)
        # define activation function for hidden layer
        h_output1 = torch.sigmoid(h_input1)

        # get hidden layer input
        h_input2 = self.hidden2(h_output1)
        # define activation function for hidden layer
        h_output2 = torch.sigmoid(h_input2)

        # get output layer output
        out = self.out(h_output2)

        return out


net = Net(input_size, hidden_size, hidden_size, num_classes)

criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(net.parameters(), lr=learning_rate)

all_losses = []

for epoch in range(num_epochs):
    total = 0
    correct = 0
    total_loss = 0
    for step, (batch_x, batch_y) in enumerate(train_loader):
        X = batch_x
        Y = batch_y.long()

    # Forward + Backward + Optimize
    optimizer.zero_grad()  # zero the gradient buffer
    outputs = net(X)
    loss = criterion(outputs, Y)
    all_losses.append(loss.item())
    loss.backward()
    optimizer.step()

    if epoch % 50 == 0:
        _, predicted = torch.max(outputs, 1)
        # calculate and print accuracy
        total = total + predicted.size(0)
        correct = correct + sum(predicted.data.numpy() == Y.data.numpy())
        total_loss = total_loss + loss
    if epoch % 50 == 0:
        print(
            "Epoch [%d/%d], Loss: %.4f, Accuracy: %.2f %%"
            % (epoch + 1, num_epochs, total_loss, 100 * correct / total)
        )

train_input = train_data.iloc[:, :input_size]
train_target = train_data.iloc[:, input_size]

inputs = torch.Tensor(train_input.values).float()
targets = torch.Tensor(train_target.values - 1).long()

outputs = net(inputs)
_, predicted = torch.max(outputs, 1)
0
KenjiChan1212 21 avril 2020 à 14:42

2 réponses

Meilleure réponse

Vous pouvez utiliser n'importe quel seuil que vous jugez approprié.

Les réseaux de neurones sont connus pour être souvent trop confiants (par exemple, en appliquant 0.95 à l'une des 50 classes), il peut donc être avantageux d'utiliser un seuil différent dans votre cas.

Votre entraînement est bon, mais vous devriez changer les prédictions (deux dernières lignes) et utiliser torch.nn.softmax comme ceci:

outputs = net(inputs) 
probabilities = torch.nn.functional.softmax(outputs, 1)

Comme mentionné dans une autre réponse, vous obtiendrez chaque ligne avec des probabilités totalisant 1 (auparavant, vous aviez des probabilités non normalisées a.k.a. logits).

Maintenant, utilisez simplement votre seuil souhaité sur ces probabilités:

predictions = probabilities > 0.8

Veuillez noter que vous ne pouvez obtenir que des zéros dans certains cas (par exemple, [0.2, 0.3, 0.5]).

Cela signifierait que le réseau de neurones n'est pas suffisamment confiant selon vos normes et entraînerait probablement une baisse du nombre de prédictions positives incorrectes (résumé, mais disons que vous prédisez si un patient n'a pas l'une des maladies 3 mutuellement exclusives. mieux vaut le dire seulement si vous êtes vraiment sûr).

Différents seuils pour chaque classe

Cela pourrait également être fait comme ceci:

thresholds = torch.tensor([0.1, 0.1, 0.8]).unsqueeze(0)
predictions = probabilities > thresholds

Commentaires finaux

Veuillez noter que dans le cas de softmax, une seule classe devrait être la réponse (comme indiqué dans une autre réponse) et cette approche (et la mention de sigmoïde) peut indiquer que vous recherchez la classification multi-étiquettes .

Si vous souhaitez entraîner votre réseau afin qu'il puisse prédire simultanément les classes, vous devez utiliser sigmoid et changer votre perte en torch.nn.BCEWithLogitsLoss.

1
Szymon Maszke 21 avril 2020 à 13:13

Dans une classification multi-classes, vous devez avoir une sortie pour chaque classe. Ensuite, vous pouvez utiliser la fonction softmax pour normaliser la sortie, ainsi la somme de tous est 1. La sortie avec la plus grande valeur est celle choisie comme classification.

-1
Diego Marin 21 avril 2020 à 11:48