[PYTHON] Keras-Liebhaber haben PyTorch ausprobiert

Einführung

Ich habe lange Zeit Deep Learning-Programme nur in Keras geschrieben, aber jetzt muss ich in PyTorch schreiben. Nach dem Studium habe ich versucht, etwas zu erstellen, das am Beispiel von MNIST funktioniert.

[Korrekturgeschichte] -Flatten () und Softmax () werden jetzt im Modell verwendet

Erstes Tutorial

Vorerst wird es zunächst ein Tutorial sein, daher habe ich von Anfang an mit PyTorch Tutorial begonnen.

Dies ist jedoch sehr schwer zu verstehen. Ich konnte "Autograd" nicht sinnlich erfassen und meine Motivation sank auf weniger als 10%.

Ich denke, es wäre besser gewesen, mit "Was ist torch.nn wirklich?" zu beginnen, als von vorne zu beginnen. ..

Backup

Ich hatte so ein Gefühl, also begann ich mit dem Tutorial und kaufte ein Buch. Nachdem ich verschiedene Dinge recherchiert hatte, wählte ich die folgenden zwei Bücher.

Ich werde dies sorgfältig lesen, während ich es kopiere.

Und MNIST

Es ist also zunächst MNIST, oder? Extrahieren Sie unter Bezugnahme auf PyTorch-Code nur die erforderlichen Teile und ändern Sie sie, damit Sie sie verstehen können ** Ich versuchte zu.

Umgebung

Zur Zeit mache ich es mit Windows 10 + Anaconda + CUDA.

import

import torch
import torch.nn as nn
import torch.optim as optim
from torch.optim.lr_scheduler import StepLR
from torchvision import datasets, transforms

from torchsummary import summary

Im Grunde ist es immer noch ein Beispiel, aber ich habe "Fackelzusammenfassung" zur Bestätigung hinzugefügt. Leider kann es nicht mit conda installiert werden, deshalb habe ich es mit pip installiert. Außerdem stimmte die Version von torchvision nicht überein und ich konnte sie nicht über die GUI installieren. (Installiert mit conda)

Parameter

seed = 1

epochs = 14
batch_size = 64
log_interval = 100

lr = 1.0
gamma = 0.7

In der Stichprobe war es ein Argument, aber ich habe nur die erforderlichen Variablen extrahiert und sie zu festen Werten gemacht. Der Wert ist die Standardnummer. (Ich habe nur log_interval geändert)

Modell-

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1)
        self.relu = nn.ReLU(inplace=True)
        self.maxpool = nn.MaxPool2d(kernel_size=2)
        self.dropout1 = nn.Dropout2d(0.25)
        self.dropout2 = nn.Dropout2d(0.5)
        self.flatten = nn.Flatten()
        self.fc1 = nn.Linear(9216, 128)
        self.fc2 = nn.Linear(128, 10)
        self.softmax = nn.Softmax(dim=1)

    def forward(self, x):
        x = self.conv1(x)
        x = self.relu(x)
        x = self.conv2(x)
        x = self.relu(x)
        x = self.maxpool(x)
        x = self.flatten(x)
        x = self.fc1(x)
        x = self.relu(x)
        x = self.dropout1(x)
        x = self.fc2(x)
        x = self.relu(x)
        x = self.dropout2(x)
        output = self.softmax(x)
        return output

Ich habe es so weit wie möglich zu einer internen Variablen mit \ _ \ _ init__ () gemacht. Der letzte ist Softmax ().

Ich habe auch darüber nachgedacht, das Modell mit der sequentiellen API zu schreiben, aber ich habe das Gefühl, dass ich darauf basierend damit herumspielen werde, also habe ich es als funktionale API belassen.

Lernen

def train(model, loss_fn, device, train_loader, optimizer, epoch):
    model.train()
    for batch_idx, (data, target) in enumerate(train_loader):
        data, target = data.to(device), target.to(device)
        optimizer.zero_grad()
        output = model(data)
        loss = loss_fn(output, target)
        loss.backward()
        optimizer.step()
        if batch_idx % 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()/len(data)))

Es ist im Grunde eine Probe. Die Verlustfunktion wird jetzt vom Anrufer festgelegt.

Ich mag den Mechanismus, die Epoche auf der Anruferseite zu drehen und den Stapel hier zu drehen, weil er leicht zu verstehen ist.

Auswertung

def test(model, loss_fn, device, test_loader):
    model.eval()
    test_loss = 0
    correct = 0
    with torch.no_grad():
        for data, target in test_loader:
            data, target = data.to(device), target.to(device)
            output = model(data)
            test_loss += loss_fn(output, target)  # sum up batch loss
            pred = output.argmax(dim=1, keepdim=True)  # get the index of the max log-probability
            correct += pred.eq(target.view_as(pred)).sum().item()

    test_loss /= len(test_loader.dataset)

    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
        test_loss, correct, len(test_loader.dataset),
        100. * correct / len(test_loader.dataset)))

Wieder entschied ich mich, die Verlustfunktion auf der Anruferseite anzugeben.

Es scheint, dass PyTorch nicht das Konzept der "Vorhersage" hat, daher denke ich, dass der Code hier hilfreich sein wird, wenn Sie später auf die Verwendung des trainierten Modells schließen. (Ich habe den Inferenzcode noch nicht geschrieben)

view_as () ist zu bequem und ich bin überrascht.

Hauptverarbeitung

torch.manual_seed(seed)

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

Betten Sie zunächst einen zufälligen Startwert ein und geben Sie die Ausführungsumgebung (CUDA) an.

transform=transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize((0.0,), (1.0,))
    ])
kwargs = {'batch_size': batch_size,
          'num_workers': 1,
          'pin_memory': True,
          'shuffle': True}

dataset1 = datasets.MNIST('../data', train=True, download=True, transform=transform)
dataset2 = datasets.MNIST('../data', train=False, transform=transform)
train_loader = torch.utils.data.DataLoader(dataset1,**kwargs)
test_loader = torch.utils.data.DataLoader(dataset2, **kwargs)

Laden Sie dann den MNIST-Datensatz. Beim Lesen ist der Durchschnitt 0 und die Standardabweichung 1. (Ich habe dies aus dem Beispiel geändert)

Bereiten Sie jetzt einen Datenlader vor. Dieser ist sehr praktisch. Ich hoffe, dass dieser Typ die Daten erweitern wird. (Noch nicht untersucht)

Ich bin auch froh, dass die Zielvariable nicht im One-Hot-Format vorliegen muss.

model = Net().to(device)
summary(model, (1,28,28))

loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adadelta(model.parameters(), lr=lr)
scheduler = StepLR(optimizer, step_size=1, gamma=gamma)

Ich habe ein Modell erstellt und dessen Inhalt angezeigt. Fackelzusammenfassung, ausgezeichnet. Wer Keras mag, ist ein Muss. Ich kann nicht erleichtert sein, wenn ich das nicht sehe. Dieses Mal wird es übrigens so angezeigt.

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1           [-1, 32, 26, 26]             320
              ReLU-2           [-1, 32, 26, 26]               0
            Conv2d-3           [-1, 64, 24, 24]          18,496
              ReLU-4           [-1, 64, 24, 24]               0
         MaxPool2d-5           [-1, 64, 12, 12]               0
           Flatten-6                 [-1, 9216]               0
            Linear-7                  [-1, 128]       1,179,776
              ReLU-8                  [-1, 128]               0
         Dropout2d-9                  [-1, 128]               0
           Linear-10                   [-1, 10]           1,290
             ReLU-11                   [-1, 10]               0
        Dropout2d-12                   [-1, 10]               0
          Softmax-13                   [-1, 10]               0
================================================================
Total params: 1,199,882
Trainable params: 1,199,882
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 1.04
Params size (MB): 4.58
Estimated Total Size (MB): 5.62
----------------------------------------------------------------

Ich bin mit dem vertrauten Display zufrieden. Übrigens ist zu beachten, dass die Reihenfolge der Anordnung unterschiedlich ist. Da es die ganze Zeit war (Charge, Höhe, Breite, Kanal), habe ich das Gefühl, dass etwas nicht stimmt (Charge, Kanal, Höhe, Breite).

Vergessen Sie nicht, die Verlustfunktion vorzubereiten. Ich verwende CrossEntropyLoss () für das Modell Softmax ().

Danach entscheiden Sie den Optimierungsalgorithmus und wie die Lernrate angepasst werden soll. Es wäre schön, einen Mechanismus zur Änderung der Lernrate einfach integrieren zu können.

for epoch in range(1, epochs + 1):
    train(model, loss_fn, device, train_loader, optimizer, epoch)
    test(model, loss_fn, device, test_loader)
    scheduler.step()

Ich werde mit der Epoche weiter lernen. Lernen → Auswertung → Anpassung der Lernrate Es ist sehr leicht zu verstehen.

Trainiertes Modell speichern / laden

torch.save(model.state_dict(), "mnist_cnn.pt")
model.load_state_dict(torch.load("mnist_cnn.pt"))

Als Bonus schrieb ich darüber, wie man das trainierte Modell speichert und lädt. Ich habe den Inhalt mit einem Binäreditor betrachtet, aber er war erfrischend.

Zusammenfassung

Ich bin noch nicht damit vertraut, aber ich hatte das Gefühl, dass es die folgenden Funktionen hat.

Ich werde härter lernen!

Recommended Posts

Keras-Liebhaber haben PyTorch ausprobiert
Ich habe versucht, Pytorchs Datensatz zu erklären
Ich habe versucht, DeepPose mit PyTorch zu implementieren
Ich habe versucht, DeepPose mit PyTorch PartⅡ zu implementieren
Ich habe versucht, CVAE mit PyTorch zu implementieren