Trainieren von Modellen mit PyTorch
PyTorch ist ein gängiges Machine Learning-Framework zum Trainieren von Deep Learning-Modellen. In Azure Databricks ist PyTorch in ML-Clustern bereits vorinstalliert.
Hinweis
Die Codeausschnitte in dieser Lerneinheit sind Beispiele, um wichtige Punkte zu verdeutlichen. Später in diesem Modul haben Sie die Möglichkeit, Code für ein vollständiges, praktisches Beispiel auszuführen.
Definieren eines PyTorch-Netzes
In PyTorch basieren Modelle auf einem von Ihnen definierten Netz. Das Netz besteht aus mehreren Schichten mit jeweils angegebenen Ein- und Ausgaben. Darüber hinaus wird eine Weitergabefunktion definiert, die Funktionen auf die einzelnen Schichten anwendet, während die Daten das Netz durchlaufen.
Im folgenden Beispielcode wird ein Netz definiert.
import torch
import torch.nn as nn
import torch.nn.functional as F
class MyNet(nn.Module):
def __init__(self):
super(MyNet, self).__init__()
self.layer1 = nn.Linear(4, 5)
self.layer2 = nn.Linear(5, 5)
self.layer3 = nn.Linear(5, 3)
def forward(self, x):
layer1_output = torch.relu(self.layer1(x))
layer2_output = torch.relu(self.layer2(layer1_output))
y = self.layer3(layer2_output)
return y
Obwohl der Code auf den ersten Blick komplex erscheinen mag, definiert diese Klasse ein relativ einfaches Netz aus drei Schichten:
- Eine Eingabeschicht, die vier Eingabewerte akzeptiert und fünf Ausgabewerte für die nächste Schicht generiert.
- Eine Schicht, die fünf Eingaben akzeptiert und fünf Ausgaben generiert.
- Eine letzte Ausgabeschicht, die fünf Eingaben akzeptiert und drei Ausgaben generiert.
Die Weitergabefunktion wendet die Schichten auf die Eingabedaten (x) an, übergibt die Ausgabe von jeder Schicht an die nächste und gibt schließlich die Ausgabe der letzten Schicht zurück (die den Vektor für die Bezeichnungsvorhersage y enthält). Eine ReLU-Aktivierungsfunktion (Rectified Linear Unit) wird auf die Ausgaben der Schichten 1 und 2 angewendet, um die Ausgabewerte auf positive Zahlen zu beschränken.
Hinweis
Abhängig vom Typ des verwendeten Verlustkriteriums können Sie eine Aktivierungsfunktion wie z. B. log_softmax auf den Rückgabewert anwenden, um den Bereich von 0 bis 1 zu erzwingen. Einige Verlustkriterien (z. B. CrossEntropyLoss, das häufig für mehrklassige Klassifizierungsmodelle verwendet wird) wenden jedoch automatisch eine geeignete Funktion an.
Wenn Sie ein Trainingsmodell erstellen möchten, müssen Sie lediglich eine Instanz der Netzklasse erstellen:
myModel = MyNet()
Aufbereiten von Daten für die Modellierung
PyTorch-Schichten arbeiten mit Daten, die als Tensoren formatiert sind. Dabei handelt es sich um matrixähnliche Strukturen. Es gibt verschiedene Funktionen zum Konvertieren anderer gängiger Datenformate in Tensoren. Sie können einen Datenlader von PyTorch definieren, um Datentensoren für das Training oder Rückschlüsse in ein Modell zu lesen.
Wie bei den meisten überwachten Machine Learning-Methoden sollten Sie separate Datasets für das Training und die Überprüfung definieren. Durch diese Trennung können Sie überprüfen, ob das Modell auch dann genaue Vorhersagen generiert, wenn es Daten erhält, mit denen es nicht trainiert wurde.
Der folgende Code definiert zwei Datenlader: einen für das Training, den anderen zum Testen. Bei den Quelldaten für die beiden Datenlader in diesem Beispiel wird angenommen, dass es sich jeweils um ein NumPy-Array von Attributwerten und den entsprechenden Bezeichnungswerten handelt.
# Create a dataset and loader for the training data and labels
train_x = torch.Tensor(x_train).float()
train_y = torch.Tensor(y_train).long()
train_ds = td.TensorDataset(train_x,train_y)
train_loader = td.DataLoader(train_ds, batch_size=20,
shuffle=False, num_workers=1)
# Create a dataset and loader for the test data and labels
test_x = torch.Tensor(x_test).float()
test_y = torch.Tensor(y_test).long()
test_ds = td.TensorDataset(test_x,test_y)
test_loader = td.DataLoader(test_ds, batch_size=20,
shuffle=False, num_workers=1)
Die Lader in diesem Beispiel teilen die Daten in 30er-Batches auf, die während des Trainings oder Rückschlusses an die Weitergabefunktion übergeben werden.
Auswählen eines Verlustkriteriums und eines Optimiereralgorithmus
Das Modell wird trainiert, indem die Trainingsdaten in das Netz eingespeist werden, der Verlust (die aggregierte Differenz zwischen vorhergesagten und tatsächlichen Werten) gemessen und das Netz durch Anpassen der Gewichtungs- und Bias-Werte optimiert wird, um den Verlust zu minimieren. Die spezifischen Details zur Berechnung und Minimierung des Verlusts werden durch das von Ihnen ausgewählte Verlustkriterium und den Optimiereralgorithmus bestimmt.
Verlustkriterien
PyTorch unterstützt eine Vielzahl von Funktionen für Verlustkriterien, einschließlich:
- cross_entropy: Eine Funktion, die die aggregierte Differenz zwischen vorhergesagten und tatsächlichen Werten für mehrere Variablen misst (wird häufig zum Messen des Verlusts bei Klassenwahrscheinlichkeiten in mehrklassigen Klassifizierungsmodellen verwendet).
- binary_cross_entropy: Eine Funktion, die die Differenz zwischen vorhergesagten und tatsächlichen Wahrscheinlichkeiten misst (wird häufig zum Messen des Verlusts bei Klassenwahrscheinlichkeiten in binären Klassifizierungsmodellen verwendet).
- mse_loss: Eine Funktion, die den Verlust der mittleren Fehlerquadratsumme für vorhergesagte und tatsächliche numerische Werte misst (wird in der Regel für Regressionen verwendet).
Wenn Sie das Verlustkriterium angeben möchten, das zum Trainieren Ihres Modells verwendet werden soll, erstellen Sie eine Instanz der entsprechenden Funktion:
import torch.nn as nn
loss_criteria = nn.CrossEntropyLoss
Tipp
Weitere Informationen zu den in PyTorch verfügbaren Verlustkriterien finden Sie in der PyTorch-Dokumentation unter Loss functions (Verlustfunktionen).
Optimiereralgorithmen
Nachdem der Verlust berechnet wurde, wird mithilfe eines Optimierers bestimmt, wie die Gewichtungs- und Bias-Werte angepasst werden müssen, um den Verlust zu minimieren. Optimierer sind spezifische Implementierungen eines Gradientenabstiegsverfahrens zur Minimierung einer Funktion. Zu den in PyTorch verfügbaren Optimierern gehören (unter anderem):
- Adadelta: Ein Optimierer, der auf dem Algorithmus der adaptiven Lernraten (Adaptive Learning Rate) basiert.
- Adam: Ein rechenleistungseffizienter Optimierer, der auf dem Adam-Algorithmus basiert.
- SGD: Ein Optimierer, der auf dem Algorithmus des stochastischen Gradientenabstiegs (Stochastic Gradient Descent) basiert.
Wenn Sie einen dieser Algorithmen zum Trainieren eines Modells verwenden möchten, müssen Sie eine Instanz des Optimierers erstellen und alle erforderlichen Parameter festlegen. Die spezifischen Parameter variieren je nach ausgewähltem Optimierer, doch bei den meisten müssen Sie eine Lernrate angeben, die den Umfang der bei jeder Optimierung vorgenommenen Anpassungen steuert.
Der folgende Code erstellt eine Instanz des Adam-Optimierers.
import torch.optim as opt
learning_rate = 0.001
optimizer = opt.Adam(model.parameters(), lr=learning_rate)
Tipp
Weitere Informationen zu den in PyTorch verfügbaren Optimierern finden Sie in der PyTorch-Dokumentation und Algorithms (Algorithmen).
Erstellen von Trainings- und Testfunktionen
Nachdem Sie ein Netz definiert und Daten dafür vorbereitet haben, können Sie die Daten zum Trainieren und Testen eines Modells verwenden. Hierzu übergeben Sie die Trainingsdaten an das Netz, berechnen den Verlust, optimieren die Gewichtungs- und Bias-Werte des Netzes und überprüfen die Leistung des Netzes mit den Testdaten. In der Regel wird eine Funktion definiert, die Daten für das Training des Modells mithilfe der Trainingsdaten an das Netz übergibt, sowie eine separate Funktion, um das Modell mit den Testdaten zu testen.
Erstellen einer Trainingsfunktion
Das folgende Beispiel zeigt eine Funktion zum Trainieren eines Modells.
def train(model, data_loader, optimizer):
# Use GPU if available, otherwise CPU
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
# Set the model to training mode (to enable backpropagation)
model.train()
train_loss = 0
# Feed the batches of data forward through the network
for batch, tensor in enumerate(data_loader):
data, target = tensor # Specify features and labels in a tensor
optimizer.zero_grad() # Reset optimizer state
out = model(data) # Pass the data through the network
loss = loss_criteria(out, target) # Calculate the loss
train_loss += loss.item() # Keep a running total of loss for each batch
# backpropagate adjustments to weights/bias
loss.backward()
optimizer.step()
#Return average loss for all batches
avg_loss = train_loss / (batch+1)
print('Training set: Average loss: {:.6f}'.format(avg_loss))
return avg_loss
Das folgende Beispiel zeigt eine Funktion zum Testen des Modells.
def test(model, data_loader):
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
# Switch the model to evaluation mode (so we don't backpropagate)
model.eval()
test_loss = 0
correct = 0
# Pass the data through with no gradient computation
with torch.no_grad():
batch_count = 0
for batch, tensor in enumerate(data_loader):
batch_count += 1
data, target = tensor
# Get the predictions
out = model(data)
# calculate the loss
test_loss += loss_criteria(out, target).item()
# Calculate the accuracy
_, predicted = torch.max(out.data, 1)
correct += torch.sum(target==predicted).item()
# Calculate the average loss and total accuracy for all batches
avg_loss = test_loss/batch_count
print('Validation set: Average loss: {:.6f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
avg_loss, correct, len(data_loader.dataset),
100. * correct / len(data_loader.dataset)))
return avg_loss
Epochenübergreifendes Trainieren des Modells
Zum Trainieren eines Deep Learning-Modells wird die Trainingsfunktion in der Regel mehrmals ausgeführt. Dabei wird jeder Durchgang als Epoche bezeichnet. Das Ziel besteht darin, den aus den Trainingsdaten berechneten Verlust der einzelnen Epochen zu reduzieren. Mithilfe der Testfunktion können Sie überprüfen, ob sich der Verlust aus den Testdaten (mit denen das Modell nicht trainiert wurde) entsprechend dem Trainingsverlust verringert. In anderen Worten darf das Modelltraining kein Modell erzeugen, dass an die Trainingsdaten überangepasst ist.
Tipp
Sie müssen die Testfunktion nicht für jede Epoche ausführen. Es genügt eine Ausführung für jede zweite Epoche oder ganz am Ende. Das Testen des Modells während des Trainings kann jedoch hilfreich sein, um herauszufinden, nach wie vielen Epochen die Überanpassung des Modells beginnt.
Der folgende Code trainiert ein Modell über fünfzig Epochen.
epochs = 50
for epoch in range(1, epochs + 1):
# print the epoch number
print('Epoch: {}'.format(epoch))
# Feed training data into the model to optimize the weights
train_loss = train(model, train_loader, optimizer)
print(train_loss)
# Feed the test data into the model to check its performance
test_loss = test(model, test_loader)
print(test_loss)
Speichern des Status des trainierten Modells
Nachdem Sie ein Modell erfolgreich trainiert haben, können Sie dessen Gewichtungs- und Bias-Werte wie folgt speichern:
model_file = '/dbfs/my_model.pkl'
torch.save(model.state_dict(), model_file)
Wenn Sie das Modell zu einem späteren Zeitpunkt laden und verwenden möchten, erstellen Sie eine Instanz der Netzklasse, auf der das Modell basiert, und laden Sie die gespeicherten Gewichtungs- und Bias-Werte.
model = myNet()
model.load_state_dict(torch.load(model_file))