ПИТОРЧ MNIST пример не сходится - PullRequest
0 голосов
/ 21 февраля 2020

Я новичок в pytorch и пишу игрушечный пример выполнения классификации MNIST. Вот полный код моего примера:

import matplotlib
matplotlib.use("Agg")
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torch.utils.data import DataLoader

import torchvision.transforms as transforms
import torchvision.datasets as datasets

import matplotlib.pyplot as plt
import os
from os import system, listdir
from os.path import join, isfile, isdir, dirname

def img_transform(image):
    transform=transforms.Compose([
        # transforms.ToTensor(),
        transforms.Normalize((0.1307,), (0.3081,))])
    return transform(image)


def normalize_output(img):
    img = img - img.min()
    img = img / img.max()
    return img

def save_checkpoint(state, filename='checkpoint.pth.tar'):
    torch.save(state, filename)

class Net(nn.Module):
    """docstring for Net"""
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, 3, 1)
        self.conv2 = nn.Conv2d(32, 64, 3, 1)
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.max_pool2d(x, 2)
        x = torch.flatten(x, 1)
        x = self.fc1(x)
        x = F.relu(x)
        x = self.fc2(x)
        output = F.log_softmax(x, dim=1)
        return output

os.environ['CUDA_VISIBLE_DEVICES'] = '0'
data_images, data_labels = torch.load("./PATH/MNIST/processed/training.pt")
model = Net()
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-2)
epochs = 5
batch_size = 30
num_batch = int(data_images.shape[0] / batch_size)
for epoch in range(epochs):
    for batch_idx in range(num_batch):
        data = data_images[ batch_idx*batch_size : (batch_idx+1)*batch_size ].float()
        label = data_labels[ batch_idx*batch_size : (batch_idx+1)*batch_size ]
        data = img_transform(data)
        data = data.unsqueeze_(1)
        pred_score = model(data)
        loss = criterion(pred_score, label)
        loss.backward()
        optimizer.step()
        if batch_idx % 200 == 0:
            print('epoch', epoch, batch_idx, '/', num_batch, 'loss', loss.item())
            _, pred = pred_score.topk(1)
            pred = pred.t().squeeze()
            correct = pred.eq(label)
            num_correct = correct.sum(0).item()
            print('acc=', num_correct/batch_size)

dict_to_save = {
    'epoch': epochs,
    'state_dict': model.state_dict(),
    'optimizer' : optimizer.state_dict(),
    }
ckpt_file = 'a.pth.tar'
save_checkpoint(dict_to_save, ckpt_file)
print('save to ckpt_file', ckpt_file)
exit()

Код выполняется с набором данных MNIST, сохраненным в пути ./PATH/MNIST/processed/training.pt

Однако, процесс обучения не сходится, с обучением точность всегда ниже 0,2. Что не так с моей реализацией? Я пробовал разные скорости обучения и размер партии. Это не работает.

Есть ли какая-либо другая проблема в моем коде?

Спасибо вам всем за помощь !!!

Вот некоторые из журналов обучения

epoch 0 0 / 2000 loss 27.2023868560791
acc= 0.1
epoch 0 200 / 2000 loss 2.3346288204193115
acc= 0.13333333333333333
epoch 0 400 / 2000 loss 2.691042900085449
acc= 0.13333333333333333
epoch 0 600 / 2000 loss 2.6452369689941406
acc= 0.06666666666666667
epoch 0 800 / 2000 loss 2.7910964488983154
acc= 0.13333333333333333
epoch 0 1000 / 2000 loss 2.966330051422119
acc= 0.1
epoch 0 1200 / 2000 loss 3.111387014389038
acc= 0.06666666666666667
epoch 0 1400 / 2000 loss 3.1988155841827393
acc= 0.03333333333333333

1 Ответ

1 голос
/ 21 февраля 2020

Я вижу как минимум четыре проблемы, которые влияют на результаты, которые вы получаете:

1) Вам нужно обнулить градиент, например:

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

2) Вы кормление nn.CrossEntropyLoss() с F.softmax. Ожидает логиты. Удалите это:

output = F.log_softmax(x, dim=1)

3) Вы вычисляете потери и cc только для текущего пакета при его печати. Так что это не правильный результат. Чтобы решить эту проблему, вам нужно сохранить все потери / приросты и вычислить среднее значение перед печатью, например:

# During the loop
loss_value += loss.item()

# When printing:
print(loss_value/number_of_batch_losses_stored)

4) Это не большая проблема, но я бы сказал, что скорость обучения должна быть меньше, Например: 1e-3.

В качестве подсказки для улучшения вашего конвейера, лучше использовать DataLoader для загрузки ваших данных. Посмотрите на torch.utils.data, чтобы узнать, как это сделать. Загрузка пакетов неэффективна, как вы делаете, потому что вы не используете генераторы. Кроме того, MNIST уже доступен на torchvision.datasets.MNIST. Это сэкономит вам время, если вы загрузите данные оттуда.

Надеюсь, это поможет.

...