Читать книгу Praxiseinstieg Machine Learning mit Scikit-Learn, Keras und TensorFlow - Aurélien Géron - Страница 122
Stochastisches Gradientenverfahren
ОглавлениеDas Hauptproblem beim Batch-Gradientenverfahren ist, dass es bei jedem Schritt den gesamten Trainingsdatensatz zum Berechnen der Gradienten verwendet, wodurch es bei großen Trainingsdatensätzen sehr langsam wird. Das andere Extrem ist das stochastische Gradientenverfahren (SGD), das bei jedem Schritt nur einen Datenpunkt zufällig auswählt und nur für diesen Punkt die Gradienten berechnet. Natürlich wird dadurch der Algorithmus viel schneller, da in jeder Iteration nur sehr wenige Daten verändert werden müssen. Damit ist das Trainieren auf riesigen Datensätzen möglich, da pro Iteration nur ein Datenpunkt verändert werden muss (SGD lässt sich auch als Out-of-Core-Algorithmus implementieren, siehe Kapitel 1).
Andererseits ist dieser Algorithmus wegen seiner stochastischen (d.h. zufälligen) Arbeitsweise wesentlich unregelmäßiger als das Batch-Gradientenverfahren: Anstatt sanft zum Minimum hinabzugleiten, hüpft die Kostenfunktion auf und ab und sinkt nur im Mittel. Mit der Zeit landet sie sehr nah am Minimum, springt dort aber weiter umher und kommt nie zur Ruhe (siehe Abbildung 4-9). Sobald der Algorithmus anhält, werden die endgültigen Parameter also gut, aber nicht optimal sein.
Bei einer sehr unregelmäßigen Kostenfunktion (wie in Abbildung 4-6) kann dies dem Algorithmus helfen, aus lokalen Minima wieder herauszuspringen. Daher hat das stochastische Gradientenverfahren im Vergleich zum Batch-Gradientenverfahren eine höhere Chance, das globale Minimum zu finden.
Die Zufälligkeit ist also gut, um lokalen Minima zu entfliehen, aber schlecht, da der Algorithmus beim Minimum nie zur Ruhe kommt. Eine Lösung dieses Dilemmas ist, die Lernrate schrittweise zu verringern. Die Schritte sind zu Beginn groß (was zu schnellen Fortschritten führt und beim Verlassen lokaler Minima hilft) und werden dann immer kleiner, sodass der Algorithmus beim globalen Minimum zur Ruhe kommt. Diesen Prozess bezeichnet man als Simulated Annealing, inspiriert vom Ausglühen in der Metallurgie, bei dem geschmolzenes Metall langsam abkühlt. Die Funktion zum Festlegen der Lernrate bezeichnet man als Learning Schedule. Wenn die Lernrate zu schnell reduziert wird, bleiben Sie in einem lokalen Minimum stecken oder sogar auf halber Strecke zum Minimum. Wird die Lernrate zu langsam gesenkt, springen Sie sehr lange um das Minimum herum und erhalten eine suboptimale Lösung, wenn Sie das Trainieren zu früh anhalten.
Abbildung 4-9: Mit dem stochastischen Gradientenverfahren ist jeder Trainingsschritt viel schneller, aber auch viel zufälliger als beim Einsatz des Batch-Gradientenverfahren.
Im folgenden Codebeispiel ist das stochastische Gradientenverfahren mit einem einfachen Learning Schedule implementiert:
n_epochs = 50
t0, t1 = 5, 50 # Hyperparameter für den Learning Schedule
def learning_schedule(t):
return t0 / (t + t1)
theta = np.random.randn(2,1) # zufällige Initialisierung
for epoch in range(n_epochs):
for i in range(m):
random_index = np.random.randint(m)
xi = X_b[random_index:random_index+1]
yi = y[random_index:random_index+1]
gradients =2*xi.T.dot(xi.dot(theta) -yi)
eta = learning_schedule(epoch * m + i)
theta = theta - eta * gradients
Standardmäßig iterieren wir in Runden mit je m Iterationen; jede Runde nennt man Epoche. Der Code für das Batch-Gradientenverfahren hat den gesamten Trainingsdatensatz 1.000 Mal durchlaufen. Dieser Code durchläuft die Trainingsdaten nur 50 Mal und erzielt eine recht gute Lösung:
>>> theta
array([[4.21076011],
[2.74856079]])
Abbildung 4-10 zeigt die ersten 20 Schritte beim Trainieren (achten Sie darauf, wie unregelmäßig die Schritte sind).
Abbildung 4-10: Die ersten 20 Schritte des stochastischen Gradientenverfahrens
Da die Datenpunkte zufällig ausgewählt werden, werden manche Datenpunkte innerhalb einer Epoche mehrmals selektiert, andere dagegen gar nicht. Wenn Sie sichergehen möchten, dass jeder Datenpunkt in jeder Epoche abgearbeitet wird, können Sie die Trainingsdaten durchmischen (und sicherstellen, dass die Eingabemerkmale und die Labels zusammenbleiben) und dann Eintrag für Eintrag durchgehen. Anschließend mischen Sie die Daten erneut und so weiter. Allerdings konvergiert dieses Verfahren im Allgemeinen langsamer.
Beim Einsatz des stochastischen Gradientenverfahren müssen die Trainingsinstanzen unabhängig und gleichverteilt sein (Independent and Identically Distributed, IID), um sicherzustellen, dass die Parameter im Durchschnitt in Richtung des globalen Optimums gedrängt werden. Eine einfache Möglichkeit ist, die Instanzen während des Trainings zu durchmischen (zum Beispiel jede Instanz zufällig auszuwählen oder zu Beginn jeder Epoche den Trainingsdatensatz zu mischen). Vermischen Sie die Instanzen nicht – beispielsweise wenn sie anhand ihres Labels geordnet sind –, wird das stochastische Gradientenverfahren damit beginnen, erst für ein Label zu optimieren, dann für das nächste und so weiter. Dabei wird es aber nicht nahe an das globale Minimum gelangen. |
Um eine lineare Regression mit dem stochastischen Gradientenverfahren in Scikit-Learn durchzuführen, verwenden Sie die Klasse SGDRegressor, die den quadratischen Fehler als Kostenfunktion minimiert. Das folgende Codebeispiel führt 1.000 Epochen aus, oder es läuft, bis der Verlust während einer Epoche um weniger als 0,001 sinkt (max_iter=1000, tol=1e-3). Der Code beginnt mit einer Lernrate von 0,1 (eta0=0.1), verwendet den voreingestellten Learning Schedule (einen anderen als den oben vorgestellten) und keinerlei Regularisierung (penalty=None, Details dazu folgen in Kürze):
from sklearn.linear_model import SGDRegressor
sgd_reg = SGDRegressor(max_iter=1000, tol=1e-3, penalty=None, eta0=0.1)
sgd_reg.fit(X, y.ravel())
Die erzielte Lösung liegt erneut nah an der von der Normalengleichung gefundenen:
>>> sgd_reg.intercept_, sgd_reg.coef_
(array([ 4.16782089]), array([ 2.72603052]))