|
Um beim Gradientenverfahren zu vermeiden, dass es beim Einsatz des Lassos am Ende um das Optimum herumspringt, müssen Sie die Lernrate während des Trainings nach und nach reduzieren (es wird immer noch um das Optimum herumspringen, aber die Schritte werden immer kleiner werden, und das Ganze wird damit konvergieren). |
Die Lasso-Kostenfunktion ist bei θi = 0 (mit i = 1, 2, …, n) nicht differenzierbar, das Gradientenverfahren funktioniert trotzdem, wenn Sie einen Subgradientenvektor g verwenden, wenn irgendein θi = 0 beträgt.13 Formel 4-11 zeigt einen Subgradientenvektor, der sich für das Gradientenverfahren mit der Lasso-Kostenfunktion einsetzen lässt.
Formel 4-11: Subgradientenvektor für die Lasso-Regression
Hier folgt ein kleines Scikit-Learn-Beispiel für das Verwenden der Klasse Lasso.
>>> from sklearn.linear_model import Lasso
>>> lasso_reg = Lasso(alpha=0.1)
>>> lasso_reg.fit(X, y)
>>> lasso_reg.predict([[1.5]])
array([1.53788174])
Sie könnten stattdessen auch die Klasse SGDRegressor(penalty="l1")verwenden.
Elastic Net
Elastic Net liegt auf halber Strecke zwischen der Ridge-Regression und der Lasso-Regression. Der Regularisierungsterm ist eine Mischung aus den Regularisierungstermen von Ridge und Lasso, und Sie können das Mischverhältnis r bestimmen. Bei r = 0 ist Elastic Net äquivalent zur Ridge-Regression, und bei r = 1 entspricht es der Lasso-Regression (siehe Formel 4-12).
Formel 4-12: Kostenfunktion von Elastic Net
Wann sollten Sie also die einfache lineare Regression (also ohne jegliche Regularisierung), Ridge, Lasso oder Elastic Net verwenden? Ein wenig Regularisierung ist fast immer vorzuziehen, also sollten Sie die einfache lineare Regression vermeiden. Ridge ist ein guter Ausgangspunkt, aber wenn Sie vermuten, dass nur einige Merkmale wichtig sind, sollten Sie Lasso oder Elastic Net verwenden, da diese tendenziell die Gewichte nutzloser Merkmale auf null reduzieren. Im Allgemeinen ist Elastic Net gegenüber Lasso vorzuziehen, da sich Lasso sprunghaft verhalten kann, wenn die Anzahl der Merkmale größer als die Anzahl der Trainingsdatenpunkte ist oder wenn mehrere Merkmale stark miteinander korrelieren.
Hier folgt ein kurzes Anwendungsbeispiel für die Scikit-Learn-Klasse ElasticNet (l1_ratio entspricht dem Mischverhältnis r):
>>> from sklearn.linear_model import ElasticNet
>>> elastic_net = ElasticNet(alpha=0.1, l1_ratio=0.5)
>>> elastic_net.fit(X, y)
>>> elastic_net.predict([[1.5]])
array([1.54333232])
Early Stopping
Ein völlig anderes Verfahren zum Regularisieren iterativer Lernalgorithmen wie des Gradientenverfahrens ist es, das Training zu unterbrechen, sobald der Validierungsfehler ein Minimum erreicht. Dies bezeichnet man als Early Stopping. Abbildung 4-20 zeigt ein komplexes Modell (in diesem Fall ein höhergradiges polynomielles Regressionsmodell), das mit dem Batch-Gradientenverfahren trainiert wird. Von Epoche zu Epoche lernt der Algorithmus, und der Vorhersagefehler (RMSE) auf dem Trainingsdatensatz sinkt dabei ebenso wie der Vorhersagefehler auf dem Validierungsdatensatz. Nach einer Weile hört der Validierungsfehler aber auf zu sinken und steigt wieder an. Dies weist darauf hin, dass das Modell angefangen hat, die Trainingsdaten zu overfitten. Mit Early Stopping beenden Sie das Training, sobald der Validierungsfehler das Minimum erreicht. Diese Regularisierungstechnik ist derart einfach und effizient, dass Geoffrey Hinton sie ein »beautiful free lunch« genannt hat.
Abbildung 4-20: Regularisierung mit Early Stopping
Tipp: Beim stochastischen und beim Mini-Batch-Gradientenverfahren sind die Kurvenverläufe nicht ganz so glatt, und es ist manchmal schwierig zu erkennen, ob sie das Minimum erreicht haben oder nicht. Eine Möglichkeit ist, nur dann anzuhalten, wenn der Validierungsfehler eine Weile oberhalb des Minimums liegt (wenn Sie sich sicher sind, dass das Modell es nicht besser kann). Anschließend setzen Sie die Modellparameter wieder auf den Punkt zurück, an dem der Validierungsfehler minimal war.
Hier sehen Sie eine einfache Implementierung des Early Stopping:
from sklearn.base import clone
# Vorbereiten der Daten
poly_scaler = Pipeline([
("poly_features", PolynomialFeatures(degree=90, include_bias=False)),
("std_scaler", StandardScaler())
])
X_train_poly_scaled = poly_scaler.fit_transform(X_train)
X_val_poly_scaled = poly_scaler.transform(X_val)
sgd_reg = SGDRegressor(max_iter=1, tol=-np.infty, warm_start=True,
penalty=None, learning_rate="constant", eta0=0.0005)
minimum_val_error = float("inf")
best_epoch = None
best_model = None
for epoch in range(1000):
sgd_reg.fit(X_train_poly_scaled, y_train) # macht weiter, wo es aufgehört hat
y_val_predict = sgd_reg.predict(X_val_poly_scaled)
val_error = mean_squared_error(y_val, y_val_predict)
if val_error < minimum_val_error:
minimum_val_error = val_error
best_epoch = epoch
best_model = clone(sgd_reg)
Mit dem Aufruf der Methode fit() mit warm_start=True wird das Trainieren beim letzten Stand fortgesetzt, anstatt neu zu starten.
Logistische Regression
Wie in Kapitel 1 besprochen,