Добавьте точность обучения и тестирования в простую нейронную сеть в PyTorch - PullRequest
5 голосов
/ 11 февраля 2020

Я знаю, что это примитивный вопрос, но что я должен добавить в свой код, чтобы он выводил точность обучения нейронной сети в дополнение к потере, я проверил уроки PyTorch, и они показывают, как добавить точность обучения / тестирования в классификация изображений, но я не знаю, как это сделать в моем простом решении XOR NN, ниже приведен код:

# Step 1: importing our dependencies
import torch
from torch.autograd import Variable
import numpy as np

# Our data
x = Variable(torch.Tensor([[0, 0, 1], [0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], 
                           [1, 1, 1], [0, 0, 0]]))
y = Variable(torch.Tensor([[0], [1], [1], [1], [1], [0], [0]]))

# Step 2: building our class model             
class NeuralNetwork(torch.nn.Module):
def __init__(self):
    super(NeuralNetwork, self).__init__()
    self.linear_ij = torch.nn.Linear(3, 4)
    self.linear_jk = torch.nn.Linear(4, 1)

def forward(self, x):
    matmul = self.linear_ij(x)
    activation = torch.sigmoid(matmul)
    matmul = self.linear_jk(activation)
    prediction = torch.sigmoid(matmul)
    return prediction

# Our model
model = NeuralNetwork()

# Constructing the loss function and the optimization algorithm
criterion = torch.nn.BCELoss(reduction='mean')
optimizer = torch.optim.SGD(model.parameters(), lr=1)

# Step 3: the training process
for epoch in range(10000):

    prediction = model(x)
    loss = criterion(prediction, y)

    if epoch % 1000 == 0 or epoch == 10000 - 1:
        print("epoch ", epoch, ",", "loss: ", loss.item())

    # Backpropagation process
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

, и это то, что он дает в качестве вывода:

epoch  0 , loss:  0.6983293294906616
epoch  1000 , loss:  0.015215665102005005
epoch  2000 , loss:  0.0048239342868328094
epoch  3000 , loss:  0.00280318153090775
epoch  4000 , loss:  0.001963752554729581
epoch  5000 , loss:  0.0015071843517944217
epoch  6000 , loss:  0.0012211233843117952
epoch  7000 , loss:  0.0010254186345264316
epoch  8000 , loss:  0.000883264874573797
epoch  9000 , loss:  0.0007753585232421756
epoch  9999 , loss:  0.0006908221403136849

Что касается тестирования:

# Testing our model
model.eval()

x_test = Variable(torch.Tensor([[1, 1, 0], [0, 0, 1], [0, 1, 1]]))
y_test = Variable(torch.Tensor([[0], [0], [1]]))
y_pred = model(x_test)
print(model(x_test))   

с выводом:

tensor([[0.0026],
        [0.0011],
        [0.9991]], grad_fn=<SigmoidBackward>)

1 Ответ

3 голосов
/ 11 февраля 2020

Чтобы добавить точность, вам нужна только одна строка, а именно:

print("Accuracy: ", ((prediction > 0.5) == y).float().mean().item())

При использовании sigmoid все, что больше 0.5, считается положительным, а что-либо ниже отрицательного. (prediction > 0.5) создает tensor типа bool, и вы проверяете, какие из них равны y. float() необходим, поскольку вы не можете вычислить mean из bool тензоров. item() не требуется, но возвращает python значение из одного значения tensor, и IMO выглядит чище.

Вы можете сделать то же самое для test, следовательно, это будет:

model.eval()

x_test = Variable(torch.Tensor([[1, 1, 0], [0, 0, 1], [0, 1, 1]]))
y_test = Variable(torch.Tensor([[0], [0], [1]]))
with torch.no_grad():
    y_pred = model(x_test)
    print("Accuracy: ", ((y_pred > 0.5) == y_test).float().mean().item())

Обратите внимание torch.no_grad(). Этот менеджер контекста отключает autograph, когда вы находитесь в пределах его видимости. Поскольку вы просто передаете входные данные через свою нейронную сеть, а не обучаете ее с использованием градиентов, нет необходимости использовать автограф как часть уравнения.

Работа с логитами

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

def forward(self, x):
    matmul = self.linear_ij(x)
    activation = torch.sigmoid(matmul)
    # Notice no sigmoid
    return self.linear_jk(activation)

Это выдает logits (скажем, ненормализованная вероятность в диапазоне от [-inf, inf]), указывающее, насколько уверена ваша нейронная сеть в положительном (+inf) или отрицательном классе .

Вы должны соответствующим образом изменить функцию потерь, например, torch.nn.BCEWithLogitsLoss (mean - сокращение по умолчанию, здесь нет необходимости делать это явно):

criterion = torch.nn.BCEWithLogitsLoss()

Наконец, точность изменяется немного так же. Теперь все, что больше 0, считается положительным, поэтому вы должны сделать это:

print("Accuracy: ", ((prediction > 0) == y).float().mean().item())

Если вам нужна вероятность, вы все равно можете использовать torch.sigmoid на выходе, но вам это может даже не понадобиться (так как в данном случае это выглядит так) 1055 *

x = torch.Tensor(
    [[0, 0, 1], [0, 1, 1], [1, 0, 1], [0, 1, 0], [1, 0, 0], [1, 1, 1], [0, 0, 0]]
)
y = torch.Tensor([[0], [1], [1], [1], [1], [0], [0]])

РЕДАКТИРОВАТЬ2:

Он должен быть размещен ниже (или выше) вашей печати с потерями, например:

for epoch in range(10000):

    prediction = model(x)
    loss = criterion(prediction, y)

    if epoch % 1000 == 0 or epoch == 10000 - 1:
        # Here is fine
        print("Accuracy: ", ((prediction > 0.5) == y).float().mean().item())
        print("epoch ", epoch, ",", "loss: ", loss.item())

    # Backpropagation process
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
...