[PYTHON] [PyTorch Tutorial ⑥] Was ist torch.nn wirklich?

Einführung

Dies ist die sechste Ausgabe von PyTorch Official Tutorial nach Last time. Dieses Mal fahren wir mit Was ist torch.nn wirklich? fort.

What is torch.nn really?

Dieses Tutorial beschreibt torch.nn, torch.optim, Dataset und DataLoader. (Obwohl torch.nn und torch.optim das letzte Mal erklärt wurden, gibt es einige Überschneidungen, da verschiedene Personen Tutorials geschrieben haben.)

Der verwendete Datensatz ist der MNIST-Datensatz. Der MNIST-Datensatz ist ein Datensatz handgeschriebener numerischer Bilder von 0 bis 9. Zum besseren Verständnis erstellen Sie zuerst das Modell, ohne die oben genannten Pakete zu verwenden. Als nächstes fahren wir in der Reihenfolge torch.nn, torch.optim, Dataset, DataLoader fort und ersetzen den Code nacheinander.

  1. MNIST data setup

Laden Sie zunächst den MNIST-Datensatz herunter (handgeschriebener numerischer Bilddatensatz).

from pathlib import Path
import requests

DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"

PATH.mkdir(parents=True, exist_ok=True)

URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"

if not (PATH / FILENAME).exists():
        content = requests.get(URL + FILENAME).content
        (PATH / FILENAME).open("wb").write(content)

Dieser Datensatz ist ein Numpy-Array. Es wird im Pickle-Format gespeichert.

import pickle
import gzip

with gzip.open((PATH / FILENAME).as_posix(), "rb") as f:
        ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")

Ein Datenelement (x_train [0]) ist ein Bild mit einer Größe von 28 x 28, wird jedoch als eine Zeile mit 784 Spalten gespeichert. Um es mit pyplot.imshow anzuzeigen, müssen Sie es in 28x28 konvertieren.

from matplotlib import pyplot
import numpy as np

pyplot.imshow(x_train[0].reshape((28, 28)), cmap="gray")
print(x_train.shape)

out


(50000, 784)

ダウンロード.png

Von nun an werden wir PyTorch's Tensor verwenden. Konvertieren Sie von einem Numpy-Array in Tensor.

import torch

x_train, y_train, x_valid, y_valid = map(
    torch.tensor, (x_train, y_train, x_valid, y_valid)
)
n, c = x_train.shape
x_train, x_train.shape, y_train.min(), y_train.max()
print(x_train, y_train)
print(x_train.shape)
print(y_train.min(), y_train.max())

out


tensor([[0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        ...,
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.],
        [0., 0., 0.,  ..., 0., 0., 0.]]) tensor([5, 0, 4,  ..., 8, 4, 8])
torch.Size([50000, 784])
tensor(0) tensor(9)

Sie können sehen, dass die Anzahl der Trainingsdaten 50.000 (× 784) beträgt und die Lehrerdaten eine Zahl von 0 bis 9 sind.

  1. Neural net from scratch (no torch.nn)

Erstellen Sie zunächst nur mit Tensor ein neuronales Netzwerk, ohne torch.nn zu verwenden. Das zu erstellende Modell ist ein einfaches lineares Modell $ y = w \times x + b$ ist.

Initialisieren Sie das Gewicht $ w $ mit PyTorchs Zufallsmethode randn. randn ist ein standardisierter Zufallswert (0 Mittelwert, 1 Standardabweichung). Wir möchten den Farbverlauf bei der Initialisierung nicht berücksichtigen. Führen Sie daher nach der Initialisierung require_grad_ () aus und setzen Sie require_grad = True. Die Gewichtsinitialisierung verwendet die "Xavier-Initialisierung". (Es gibt, aber ich denke, dass die Berechnungsformel ein wenig anders ist) Die Vorspannung wird auf Null initialisiert.

import math

weights = torch.randn(784, 10) / math.sqrt(784)
weights.requires_grad_()
bias = torch.zeros(10, requires_grad=True)

Wir benötigen auch eine Aktivierungsfunktion, also erstellen Sie eine log_softmax-Funktion. PyTorch bietet eine Reihe von Verlust- und Aktivierungsfunktionen, aber Sie können auf diese Weise auch Ihre eigenen erstellen.

def log_softmax(x):
    return x - x.exp().sum(-1).log().unsqueeze(-1)

def model(xb):
    return log_softmax(xb @ weights + bias)

@ Stellt eine innere Produktoperation dar. Diese Funktion wird in Stapelgröße aufgerufen (diesmal 64 Bilder).

bs = 64  # batch size

xb = x_train[0:bs]  #Mini-Charge
preds = model(xb)  #Erwarten Sie mit Modell
preds[0], preds.shape
print(preds[0], preds.shape)

out


tensor([-2.8486, -2.2823, -2.2740, -2.7800, -2.1906, -1.3280, -2.4680, -2.2958,
        -2.8856, -2.8650], grad_fn=<SelectBackward>) torch.Size([64, 10])

Wenn Sie den vorhergesagten Wert preds ausgeben, können Sie sehen, dass Tensor eine Gradientenfunktion (grad_fn) enthält. Später werden wir diese Gradientenfunktion verwenden, um die Backpropagation zu berechnen. Implementieren Sie als Verlustfunktion die negative logarithmische Wahrscheinlichkeit der Lehrerdaten und den vorhergesagten Wert. Eine negative Log-Wahrscheinlichkeit wird üblicherweise als Kreuzentropiefehlerfunktion bezeichnet.

def nll(input, target):
    return -input[range(target.shape[0]), target].mean()

loss_func = nll

Berechnen Sie den Verlust mit dem vorhergesagten Wert und den Lehrerdaten und überprüfen Sie die Parameter nach dem Training.

yb = y_train[0:bs]
print(loss_func(preds, yb))

out


tensor(2.4101, grad_fn=<NegBackward>)

Es implementiert auch eine Bewertungsfunktion, die die Genauigkeit des Modells berechnet. Da out die Wahrscheinlichkeit handgeschriebener Zahlen von 0 bis 9 in einem Array enthält, ist der Maximalwert von argmax die wahrscheinlichste handgeschriebene Zahl. Die richtige Antwortrate wird berechnet, indem der übereinstimmende Durchschnitt aus dem Wert und den Lehrerdaten verwendet wird.

def accuracy(out, yb):
    preds = torch.argmax(out, dim=1)
    return (preds == yb).float().mean()
print(accuracy(preds, yb))

out


tensor(0.0781)

Jetzt sind Sie bereit zu lernen. Wiederholen Sie die folgenden Schritte, um zu lernen.

Nach dem Aktualisieren der Gewichte und der Vorspannung initialisiere ich den Verlauf mit grad.zero_ (). Dies liegt daran, dass bei der Berechnung des Verlaufs mit loss.backward () der bereits gespeicherte Wert hinzugefügt wird.

from IPython.core.debugger import set_trace

lr = 0.5  # learning rate
epochs = 2  # how many epochs to train for

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        #set_trace()
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        with torch.no_grad():
            weights -= weights.grad * lr
            bias -= bias.grad * lr
            weights.grad.zero_()
            bias.grad.zero_()

Sie können sehen, dass sich die Genauigkeit nach dem Lernen verbessert hat.

print(loss_func(model(xb), yb), accuracy(model(xb), yb))

out


tensor(0.0822, grad_fn=<NegBackward>) tensor(1.)

Vor dem Lernen betrug die korrekte Antwortrate 7%, nach dem Lernen jedoch 100%.

Jetzt haben Sie ein einfaches neuronales Netzwerk, das von Grund auf neu aufgebaut wurde. Das Netzwerk, das diesmal die Softmax-Funktion ohne die verborgene Schicht verwendet, wird als logistische Regression bezeichnet.

  1. Using torch.nn.functional

Von hier aus verwenden wir das nn-Paket von PyTorch, um unseren Code zu überarbeiten. Ersetzen wir im ersten Schritt die Aktivierungsfunktion und die Verlustfunktion. torch.nn.functional hat F.cross_entropy, das die Funktion log_softmax mit einer negativen Log-Wahrscheinlichkeit kombiniert. Ersetzen Sie die Verlustfunktion durch F.cross_entropy. Da F.cross_entropy die Funktion log_softmax enthält, können Sie auch die als Aktivierungsfunktion definierte def log_softmax (x) entfernen.

import torch.nn.functional as F

loss_func = F.cross_entropy

def model(xb):
    return xb @ weights + bias

Der vom Modell aufgerufene log_softmax wird nicht mehr benötigt. (In cross_entropy enthalten) Stellen Sie sicher, dass der Verlust und die Genauigkeit dieselben sind wie zuvor.

print(loss_func(model(xb), yb), accuracy(model(xb), yb))

out


tensor(0.0822, grad_fn=<NllLossBackward>) tensor(1.)
  1. Refactor using nn.Module

Als nächstes werden wir mit nn.Module und nn.Parameter umgestalten. nn.Module ist die Basisklasse für das neuronale Netzwerk von Pytorch. Implementieren Sie nn.Module als Unterklasse. Definieren Sie Gewichts- und Bias-Parameter in der von Ihnen erstellten Unterklasse. Beschreiben Sie auch den Vorgang des Verbindens von Eingabe zu Ausgabe in der Vorwärtsmethode. nn.Module enthält auch parameters (), das Modellparameter zurückgibt.

from torch import nn

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.weights = nn.Parameter(torch.randn(784, 10) / math.sqrt(784))
        self.bias = nn.Parameter(torch.zeros(10))

    def forward(self, xb):
        return xb @ self.weights + self.bias

Da wir Objekte anstelle von Funktionen verwenden, müssen wir zuerst das Modell instanziieren.

model = Mnist_Logistic()

Jetzt können Sie lernen, wie Sie es vor dem Refactoring getan haben. Das nn.Module-Objekt kann wie eine Funktion aufgerufen und verwendet werden.

print(loss_func(model(xb), yb))

out


tensor(2.3918, grad_fn=<NllLossBackward>)

In der bisherigen Implementierung wurden die Gewichts- und Bias-Aktualisierungen wie folgt berechnet und der Gradient manuell auf Null gesetzt.

  with torch.no_grad():
      weights -= weights.grad * lr
      bias -= bias.grad * lr
      weights.grad.zero_()
      bias.grad.zero_()

Gewichts- und Bias-Aktualisierungen können vereinfacht werden, indem sie durch die in nn.Module definierten Parameter () und zero_grad () ersetzt werden.

  #Kann nicht ausgeführt werden, da es sich um einen erklärenden Code handelt (ein Laufzeitfehler tritt auf).
  with torch.no_grad():
      for p in model.parameters(): p -= p.grad * lr
      model.zero_grad()

Definieren Sie die Lernschleife als Anpassungsfunktion, damit sie aufgerufen werden kann.

def fit():
    for epoch in range(epochs):
        for i in range((n - 1) // bs + 1):
            start_i = i * bs
            end_i = start_i + bs
            xb = x_train[start_i:end_i]
            yb = y_train[start_i:end_i]
            pred = model(xb)
            loss = loss_func(pred, yb)

            loss.backward()
            with torch.no_grad():
                for p in model.parameters():
                    p -= p.grad * lr
                model.zero_grad()

fit()

Lassen Sie uns erneut bestätigen, dass der Verlust reduziert ist.

print(loss_func(model(xb), yb))

out


tensor(0.0796, grad_fn=<NllLossBackward>)
  1. Refactor using nn.Linear

Ich habe zuerst Gewichte und Bias selbst definiert und auch die lineare Funktion $ w \ times x + b $ implementiert, aber lassen Sie uns sie durch nn.Linear (lineare Ebene) ersetzen.

class Mnist_Logistic(nn.Module):
    def __init__(self):
        super().__init__()
        self.lin = nn.Linear(784, 10)

    def forward(self, xb):

        return self.lin(xb)

Instanziieren Sie das Modell wie zuvor und berechnen Sie den Verlust.

model = Mnist_Logistic()
print(loss_func(model(xb), yb))

out


tensor(2.3661, grad_fn=<NllLossBackward>)

Lernen Sie, indem Sie eine funktionalisierte Passform aufrufen.

fit()
print(loss_func(model(xb), yb))

out


tensor(0.0813, grad_fn=<NllLossBackward>)

Der Verlustwert hat sich von 2,3661 auf 0,0813 geändert, was bestätigt, dass Lernen möglich ist.

  1. Refactor using optim

Überarbeiten Sie dann den Optimierungsalgorithmus. Das torch.optim-Paket von Pytorch verfügt über eine Vielzahl von Optimierungsalgorithmen. Außerdem aktualisiert jede Klasse in torch.optim die Parameter, indem sie die Schrittmethode ausführt, anstatt die Parameter manuell zu aktualisieren.

  with torch.no_grad():
      for p in model.parameters(): p -= p.grad * lr
      model.zero_grad()

Sie können den obigen Code wie folgt umschreiben.

  #Kann aufgrund von erklärendem Code nicht ausgeführt werden
  opt.step()
  opt.zero_grad()
from torch import optim

Die Funktionalisierung der Modell- und Optimierungsgenerierung vereinfacht den Code.

def get_model():
    model = Mnist_Logistic()
    return model, optim.SGD(model.parameters(), lr=lr)

model, opt = get_model()
print(loss_func(model(xb), yb))

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        start_i = i * bs
        end_i = start_i + bs
        xb = x_train[start_i:end_i]
        yb = y_train[start_i:end_i]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

out


tensor(2.3423, grad_fn=<NllLossBackward>)
tensor(0.0819, grad_fn=<NllLossBackward>)
  1. Refactor using Dataset

PyTorch hat eine abstrakte Dataset-Klasse. Der Datensatz erleichtert den Umgang mit Trainingsdaten (x_train) und Lehrerdaten (y_train) während des Trainings. Der Datensatz muss eine __len__ Funktion implementieren, die die Anzahl der Elemente zurückgibt, und eine __getitem__ Funktion, die Elemente durch Angabe eines Index zurückgibt. TensorDataset umschließt das Dataset in Tensor.

from torch.utils.data import TensorDataset

Erstellen Sie TensorDataset, indem Sie beim Erstellen x_train und y_train angeben.

train_ds = TensorDataset(x_train, y_train)

Bisher wurden die Trainingsdaten (x_train) und die Lehrerdaten (y_train) separat iterativ verarbeitet.

    xb = x_train[start_i:end_i]
    yb = y_train[start_i:end_i]

Sie können TensorDataset verwenden, um alle auf einmal zu verarbeiten.

    xb,yb = train_ds[i*bs : i*bs+bs]
model, opt = get_model()

for epoch in range(epochs):
    for i in range((n - 1) // bs + 1):
        xb, yb = train_ds[i * bs: i * bs + bs]
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

out


tensor(0.0803, grad_fn=<NllLossBackward>)
  1. Refactor using DataLoader

DataLoader kann verwendet werden, um das Schleifen mit Dataset zu vereinfachen. Erstellen Sie einen DataLoader basierend auf dem Datensatz.

from torch.utils.data import DataLoader

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs)

Im ersten Code haben wir die Startposition für jede Chargengröße angegeben und in Scheiben geschnitten.

for i in range((n-1)//bs + 1):
    xb,yb = train_ds[i*bs : i*bs+bs]
    pred = model(xb)

Der DataLoader vereinfacht die Schleife, da (xb, yb) automatisch nacheinander aus dem DataLoader geladen werden.

for xb,yb in train_dl:
    pred = model(xb)
model, opt = get_model()

for epoch in range(epochs):
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

print(loss_func(model(xb), yb))

out


tensor(0.0802, grad_fn=<NllLossBackward>)

Bisher haben wir nn.Module, nn.Parameter, Dataset und DataLoader verwendet. Ich konnte den Code präzise und einfach schreiben. Als nächstes fügen wir die grundlegenden Funktionen hinzu, die zum Erstellen eines effektiven Modells erforderlich sind.

  1. Add validation

Bis zu diesem Punkt wurde das Lernen nur mit Trainingsdaten fortgesetzt, aber beim tatsächlichen Lernen werden Validierungsdaten verwendet, um zu überprüfen, ob ein Übertraining stattgefunden hat und ob das Lernen fortgeschritten ist. Richten Sie den folgenden Validierungsdatensatz ein.

train_ds = TensorDataset(x_train, y_train)
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)

valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)

Verwenden Sie am Ende jeder Epoche Validierungsdaten, um den Verlust zu berechnen. Versetzen Sie model.train () vor dem Training in den Trainingsmodus und model.eval () vor der Validierung in den Evaluierungsmodus. Dies dient dazu, nn.Dropout usw. nur während des Trainings zu aktivieren.

model, opt = get_model()

for epoch in range(epochs):
    model.train()
    for xb, yb in train_dl:
        pred = model(xb)
        loss = loss_func(pred, yb)

        loss.backward()
        opt.step()
        opt.zero_grad()

    model.eval()
    with torch.no_grad():
        valid_loss = sum(loss_func(model(xb), yb) for xb, yb in valid_dl)

    print(epoch, valid_loss / len(valid_dl))

out


0 tensor(0.3679)
1 tensor(0.2997)
  1. Create fit() and get_data()

Erstellen Sie als Nächstes eine Funktion loss_batch, die sowohl Training als auch Validierung durchführen kann. Durch Übergeben des Optimierers an loss_batch wird die Backpropagation berechnet und die Parameter aktualisiert. Die Rückausbreitung wird nicht berechnet, indem der Optimierer während der Überprüfung nicht übergeben wird.

def loss_batch(model, loss_func, xb, yb, opt=None):
    loss = loss_func(model(xb), yb)

    if opt is not None:
        loss.backward()
        opt.step()
        opt.zero_grad()

    return loss.item(), len(xb)

Definieren Sie die Anpassungsfunktion. Die Anpassungsfunktion wiederholt das Training und die Validierung in jeder Epoche und zeigt den Verlust an.

import numpy as np

def fit(epochs, model, loss_func, opt, train_dl, valid_dl):
    for epoch in range(epochs):
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)

        model.eval()
        with torch.no_grad():
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)

        print(epoch, val_loss)

get_data gibt einen DataLoader für Trainings- und Validierungsdaten zurück.

def get_data(train_ds, valid_ds, bs):
    return (
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )

Jetzt können Sie den Prozess zum Abrufen des DataLoader und zum Durchführen des Trainings in drei Codezeilen schreiben.

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(epochs, model, loss_func, opt, train_dl, valid_dl)

out


0 0.45953697173595426
1 0.3061695278286934

Sie können verschiedene Modelle erstellen, indem Sie die drei Codezeilen umgestalten. Mal sehen, ob wir ein Faltungs-Neuronales Netzwerk (CNN) aufbauen können!

  1. Switch to CNN

Von hier aus werden wir ein neuronales Netzwerk mit drei Faltungsschichten aufbauen. Die bisher erstellten Funktionen unterliegen keinen Modellbeschränkungen, sodass Sie den CNN auf umschalten können, ohne Änderungen vorzunehmen.

Verwenden Sie die von Pytorch bereitgestellte Conv2d-Klasse als Faltungsschicht. Definieren Sie das CNN mit drei Faltungsschichten. Die Aktivierungsfunktion für jede Faltungsschicht ist ReLU. Fügen Sie abschließend eine durchschnittliche Pooling-Ebene hinzu. (Die Ansicht ist eine PyTorch-Version der Numpy-Variante.)

class Mnist_CNN(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1)
        self.conv2 = nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1)
        self.conv3 = nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1)

    def forward(self, xb):
        xb = xb.view(-1, 1, 28, 28)
        xb = F.relu(self.conv1(xb))
        xb = F.relu(self.conv2(xb))
        xb = F.relu(self.conv3(xb))
        xb = F.avg_pool2d(xb, 4)
        return xb.view(-1, xb.size(1))

lr = 0.1

Momentum ist eine Variation der probabilistischen Gradientenabstiegsmethode, die auch den zuletzt aktualisierten Wert berücksichtigt, was im Allgemeinen zu einem schnelleren Training führt.

model = Mnist_CNN()
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

out


0 0.7808464194297791
1 0.6988550303936004
  1. nn.Sequential

torch.nn hat eine weitere praktische Klasse, Sequential, mit der Sie Ihren Code vereinfachen können. Das sequentielle Objekt führt jedes darin enthaltene Modul nacheinander aus. Die Funktion ist, dass Sie das Netzwerk leicht beschreiben können.

Möglicherweise benötigen Sie eine benutzerdefinierte Ebene, um Sequential nutzen zu können. PyTorch verfügt nicht über eine Ebene, die die Dimensionen des Netzwerks (Ebene) transformiert. Daher müssen Sie eine eigene Ansichtsebene erstellen. Das folgende Lambda definiert die Eingabe- / Ausgabeschicht, die von Sequential verarbeitet wird.

class Lambda(nn.Module):
    def __init__(self, func):
        super().__init__()
        self.func = func

    def forward(self, x):
        return self.func(x)


def preprocess(x):
    return x.view(-1, 1, 28, 28)

Sequential erleichtert die Beschreibung Ihres Netzwerks wie folgt:

model = nn.Sequential(
    Lambda(preprocess),
    nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AvgPool2d(4),
    Lambda(lambda x: x.view(x.size(0), -1)),
)

opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

out


0 0.4288556560516357
1 0.2115058801174164
  1. Wrapping DataLoader

Das von mir erstellte CNN ist recht präzise, funktioniert jedoch aufgrund der folgenden Einschränkungen nur mit MNIST-Daten (handgeschriebene Zahlenbilder):

Entfernen Sie diese beiden Annahmen und lassen Sie das Modell mit jedem 2D-Einkanalbild (monochromatisches Bild) arbeiten. Löschen Sie zunächst die erste Lambda-Ebene und verschieben Sie die Datenvorverarbeitung in den Datenlader.

def preprocess(x, y):
    return x.view(-1, 1, 28, 28), y


class WrappedDataLoader:
    def __init__(self, dl, func):
        self.dl = dl
        self.func = func

    def __len__(self):
        return len(self.dl)

    def __iter__(self):
        batches = iter(self.dl)
        for b in batches:
            yield (self.func(*b))

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)

Ersetzen Sie dann nn.AvgPool2d durch nn.AdaptiveAvgPool2d. Auf diese Weise können Sie die Größe des gewünschten Ausgangstensors und nicht des Eingangstensors definieren. Infolgedessen arbeitet die durchschnittliche Poolebene mit Eingaben beliebiger Größe.

model = nn.Sequential(
    nn.Conv2d(1, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 16, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.Conv2d(16, 10, kernel_size=3, stride=2, padding=1),
    nn.ReLU(),
    nn.AdaptiveAvgPool2d(1),
    Lambda(lambda x: x.view(x.size(0), -1)),
)

opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

Lass es uns versuchen.

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

out


0 0.3351769802570343
1 0.2583931807518005
  1. Using your GPU

Wenn Sie eine CUDA-fähige GPU zur Verfügung haben (die meisten Cloud-Anbieter kosten etwa 0,50 USD pro Stunde), können Sie Ihr Lernen beschleunigen. Stellen Sie zunächst sicher, dass Ihre GPU auf Pytorch ausgeführt wird.

print(torch.cuda.is_available())

out


True

Erstellen Sie als Nächstes ein Geräteobjekt. Das Geräteobjekt wird auf "cuda" gesetzt, wenn die GPU verfügbar ist, oder auf "cpu", wenn sie nicht verfügbar ist.

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

Fügen Sie die Vorverarbeitung hinzu, um den Stapel auf die GPU zu verschieben.

def preprocess(x, y):
    return x.view(-1, 1, 28, 28).to(dev), y.to(dev)

train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
train_dl = WrappedDataLoader(train_dl, preprocess)
valid_dl = WrappedDataLoader(valid_dl, preprocess)

Verschieben Sie das Modell schließlich auf die GPU.

model.to(dev)
opt = optim.SGD(model.parameters(), lr=lr, momentum=0.9)

Sie können sehen, dass sich die Verarbeitungsgeschwindigkeit erhöht hat.

fit(epochs, model, loss_func, opt, train_dl, valid_dl)

out


0 0.1938392831325531
1 0.18594802458286286

Als ich mich bei Google Colaboratory erkundigte, war der obige Vorgang, der für die CPU ungefähr 15 Sekunden dauerte, in ungefähr 5 Sekunden abgeschlossen.

15. Schlussgedanken (Zusammenfassung)

In diesem Tutorial haben Sie modellunabhängige Daten- und Trainingsprozesse erstellt. Es gibt viele Dinge, die wir hinzufügen möchten, wie z. B. Datenerweiterung, Optimierung von Hyperparametern, Überwachung des Trainings und Transferlernen. Diese Funktionen sind in der Fastai-Bibliothek verfügbar. Die Fastai-Bibliothek wurde unter Verwendung des gleichen Entwurfsansatzes entwickelt, der in diesem Tutorial gezeigt wird, und ist ein guter Schritt für alle, die maschinelles Lernen weiter lernen.

Für dieses Tutorial haben wir torch.nn, torch.optim, Dataset und DataLoader verwendet. Fassen wir zusammen, was wir bisher gesehen haben.

16. Schließlich

Das ist "Was ist Fackel.nn wirklich?" Es war ähnlich wie beim letzten Mal, aber ich konnte mein Verständnis von Pytorch und neuronalen Netzen vertiefen. Das nächste Mal möchte ich mit "Visualisieren von Modellen, Daten und Training mit Tensor Board" fortfahren.

Geschichte

2020/10/10 Erste Ausgabe veröffentlicht

Recommended Posts

[PyTorch Tutorial ⑥] Was ist torch.nn wirklich?
Was ist ein Namespace?
Was ist copy.copy ()
Was ist Django? .. ..
Was ist dotenv?
Was ist POSIX?
Was ist Linux?
Was ist SALOME?
Was ist Python?
Was ist Hyperopt?
Was ist Linux?
Was ist Pyvenv?
Was ist __call__?
Was ist Linux?
Was ist Python?
Was ist eine Distribution?
Was ist Piotroskis F-Score?
Was ist Raspberry Pi?
[Python] Was ist Pipeline ...
Was ist das Calmar-Verhältnis?
Was ist Hyperparameter-Tuning?
Was ist ein Hacker?
PyTorch DataLoader ist langsam
Wofür ist Linux?
Was ist Ensemble-Lernen?
[PyTorch Tutorial ③] NEURALE NETZWERKE
Was ist Pythons __init__.py?
Was ist ein Iterator?
Was ist UNIT-V Linux?
[Python] Was ist virtualenv?
Was ist maschinelles Lernen?
Was ist Mini Sam oder Mini Max?
Was ist eine logistische Regressionsanalyse?
[PyTorch Tutorial ④] AUSBILDUNG EINES KLASSIFIERERS
[PyTorch] Tutorial (japanische Version) ② ~ AUTOGRAD ~
Was ist ein Entscheidungsbaum?
Was ist ein Kontextwechsel?
Was ist Google Cloud Dataflow?
[DL] Was ist Gewichtsverlust?
Was ist ein Superuser?
Wettbewerbsprogrammierung ist was (Bonus)
[Python] * args ** Was ist kwrgs?
Was ist ein Systemaufruf?
[PyTorch] Tutorial (japanische Version) ① ~ Tensol ~
[Definition] Was ist ein Framework?
[PyTorch Tutorial ②] Autograd: Automatische Differenzierung
Tutorial zum neuronalen Netz von Pytorch (CNN) 1.3.1.
Was ist die Schnittstelle für ...
Was ist Project Euler 3-Beschleunigung?
Was ist eine Rückruffunktion?
Was ist die Rückruffunktion?
Was ist Ihr "Tanimoto-Koeffizient"?
Python-Grundkurs (1 Was ist Python?)