Salta el contingut
 

Descens del gradient

Autor: Joan Puigcerver Ibáñez

Correu electrònic: j.puigcerveribanez@edu.gva.es

Llicència: CC BY-NC-SA 4.0

(Reconeixement - NoComercial - CompartirIgual) 🅭

Descens del gradient

L'algorisme del gradient descendent és un mètode iteratiu d'optimització que permet trobar el mínim d'una funció.

Aquest algorisme es basa en utilitzar la derivada de la funció de cost per trobar la direcció en la qual la funció de cost descendeix més ràpidament.

Aquest algorisme és molt útil ja que permet la utilització de diferents funcions de cost i diferents mètodes de regularització.

Funció de cost

La funció de cost és una funció que mesura la diferència entre els valors predits pel model i els valors reals de les dades.

Aquesta funció és la que l'algorisme del gradient descendent tracta d'optimitzar i minimitzar.

En el cas de problemes de regressió, trobem les següents funcions de cost:

Regulització

La regularització és un mètode que permet evitar el sobreajustament dels models de regressió.

Aquest mètode consisteix en afegir un terme a la funció de cost que penalitza els pesos del model, evitant que aprenguen massa els valors de les dades d'entrenament.

Els dos mètodes de regularització més comuns són:

  • l1: regularització L1 o Lasso.
  • l2: regularització L2 o Ridge.

SGDRegressor

La classe SGDRegressor de scikit-learn implementa l'algorisme del gradient descendent estocàstic (Stochastic Gradient Descent o SGD).

from sklearn.linear_model import SGDRegressor

model = SGDRegressor(loss='squared_loss', penalty='l2')

Aquest model té els següents hiperparàmetres:

  • loss: funció de cost a optimitzar (per defecte: squared_loss).
  • penalty: mètode de regularització (per defecte: l2).
  • alpha: terme de regularització (per defecte: 0.0001).
  • max_iter: nombre màxim d'iteracions (per defecte: 1000).
  • shuffle: barreja les dades a cada iteració (per defecte: True).

Documentació

Documentació oficial de SGDRegressor

Codi font

Aquest exemple utilitza el procés de Normalització de les dades mitjançant la classe StandardScaler, que encara no hem estudiat.

descens_gradient.py
#!/usr/bin/env python
import numpy as np
from sklearn.model_selection import train_test_split

def f(x):
    return 3*x + 100

np.random.seed(42)
n_samples = 50

X = np.random.uniform(-50, 50, n_samples)
Y = f(X) + np.random.randn(n_samples) * 10
X = X.reshape(-1, 1) # Convertim X en una matriu de 1 columna
Y[10] = 1000

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
X = scaler.fit_transform(X)
Y = scaler.fit_transform(Y.reshape(-1, 1)).ravel()

X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=0.2, random_state=42)
X_test, Y_test = zip(*sorted(zip(X_test, Y_test))) # Ordenem les dades de test per visualitzar-les correctament


from sklearn.linear_model import SGDRegressor

max_iter = 1000
models = {
    "huber_small_e": SGDRegressor(loss='huber', max_iter=max_iter, epsilon=0.1),
    "huber_large_e": SGDRegressor(loss='huber', max_iter=max_iter, epsilon=2.5),
    "epsilon_insensitive": SGDRegressor(loss='epsilon_insensitive', max_iter=max_iter, epsilon=0.1),
    "squared_error": SGDRegressor(loss='squared_error', max_iter=max_iter),
}
colors = ['red', 'green', 'cyan', 'magenta']

import matplotlib.pyplot as plt

plt.scatter(X_train, Y_train, color='blue')
plt.scatter(X_test, Y_test, color='orange')

for i, (title, model) in enumerate(models.items()):
    model.fit(X_train, Y_train)

    pred_Y = model.predict(X_test)

    from sklearn.metrics import root_mean_squared_error
    from sklearn.metrics import r2_score

    rmse = root_mean_squared_error(Y_test, pred_Y)
    r2 = r2_score(Y_test, pred_Y)
    print(f'RMSE {title}: {rmse:.2f}')
    print(f'R^2 {title}: {r2:.2f}')

    X_plot = [X.min(), X.max()]
    Y_plot = model.predict(np.array(X_plot).reshape(-1, 1))

    plt.plot(X_plot, Y_plot, color=colors[i], lw=2)

plt.legend(["train", "test"] + list(models.keys()))
plt.show()