Pas à pas sur la théorie, l'implémentation en python et l'analyse à l'aide de scikit-learn sur l'algorithme précédemment repris dans "Classification of Machine Learning" J'étudierai avec. Je l'écris pour un apprentissage personnel, alors j'aimerais que vous oubliez toute erreur.
Cette fois, je parlerai de la ** méthode de descente de gradient **, qui est une méthode pour optimiser les paramètres de la fonction de perte. C'est bien si une solution peut être trouvée mathématiquement, mais il y a peu de cas de ce genre dans le monde. Il existe différents gradients comme méthode de recherche de la valeur optimale, mais j'aimerais en résumer certains avec du code. Les sites auxquels j'ai fait référence comme d'habitude sont les suivants. Merci beaucoup.
D'après Wikipedia, quelle est la méthode du gradient?
La méthode du gradient est un terme général pour les algorithmes qui utilisent des informations sur le gradient d'une fonction pour rechercher une solution dans un problème d'optimisation.
Il est écrit. En régression simple, la fonction de perte $ E $ est la somme des carrés des résidus
Comme d'habitude, nous utilisons le diabète scikit-learn (données sur le diabète).
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn import datasets
diabetes = datasets.load_diabetes()
df = pd.DataFrame(diabetes.data, columns=diabetes.feature_names)
x = df['bmi'].values
y = diabetes.target
plt.scatter(x, y)
La pente et la section résolues mathématiquement sont respectivement
Inclinaison A: 949.43526038395
Section B: 152.1334841628967
était.
La descente de gradient la plus raide est l'idée de se déplacer progressivement dans la direction opposée du vecteur de gradient en un point de la fonction de perte. Soit la pente $$ nabla E
Pour la fonction de perte
\frac{\partial{E}}{\partial{A}}=\sum(-2x_iy_i+2Ax_i^2+2Bx_i)
\\
=-2\sum(Ax_i+B-y_i)x_i \\
\frac{\partial{E}}{\partial{B}}=\sum(-2x_iy_i+2Ax_i+2B)
\\
=-2\sum(Ax_i+B-y_i) \\
Sera. Décidez de la valeur initiale de manière appropriée, modifiez $ A $ et $ B $ dans la direction du gradient en utilisant la formule ci-dessus et arrêtez le calcul à un stade raisonnable.
Un examen plus approfondi est nécessaire sur la manière de déterminer la valeur initiale, la manière de déterminer la vitesse d'apprentissage et les conditions pour interrompre le calcul, mais le schéma est le suivant.
Création d'une classe SteepestGradientDescent qui réalise la méthode de descente la plus raide. J'ai essayé de faire correspondre la méthode à scikit-learn. Le taux d'apprentissage était approprié et il était coupé par le nombre de fois, et non lorsque l'erreur devenait suffisamment faible.
class SteepestGradientDescent:
def __init__(self, eta=0.001, n_iter=2000):
self.eta = eta
self.n_iter = n_iter
self.grad = np.zeros((2,))
self.loss = np.array([])
def fit(self, X, Y, w0):
self.w = w0
for _ in range(self.n_iter):
self.loss = np.append(self.loss, np.sum((Y-self.w[0]-self.w[1]*X)**2))
self.grad[0] = np.sum(-2*(Y-self.w[0]-self.w[1]*X))
self.grad[1] = np.sum(-2*X*(Y-self.w[0]-self.w[1]*X))
self.w -= self.eta * self.grad
def predict(self, x):
return (self.w[0] + self.w[1]*x)
@property
def coef_(self):
return self.w[1]
@property
def intercept_(self):
return self.w[0]
@property
def loss_(self):
return self.loss
Dans la méthode d'ajustement, le gradient est calculé pour toutes les données et le coefficient est mis à jour. La valeur de la fonction de perte a également été enregistrée en même temps afin que nous puissions voir comment l'apprentissage se déroulait.
Utilisons cette classe pour approximer les données sur le diabète et tracer le changement de perte sur un graphique.
w0 = np.array([1.,1.])
model = SteepestGradientDescent()
model.fit(x, y, w0)
print("A: ", model.coef_)
print("B: ", model.intercept_)
loss = model.loss
plt.plot(np.arange(len(loss)), np.log10(loss))
plt.show()
A: 932.1335010668406
B: 152.13348416289668
C'est maintenant avec la valeur mathématiquement résolue. Vous pouvez également voir comment la perte diminue.
La méthode de descente la plus raide a utilisé tous les échantillons pour calculer le gradient. La méthode de descente de gradient probabiliste utilise une ou plusieurs données mélangées pour mettre à jour les paramètres. La méthode d'utilisation de plusieurs méthodes est également appelée apprentissage par mini-lots.
La question est de savoir quoi faire de cette manière, mais la fonction de perte peut avoir plusieurs valeurs minimales en fonction de la forme. Rappelez-vous le terrain, mais les vallées que vous pouvez voir ne sont pas toujours les plus basses et vous pouvez trouver des vallées plus profondes au-delà des montagnes. Ce fond de vallée apparemment correct, mais non, s'appelle la ** solution locale **, et le fond de la vallée inférieure est appelé la ** solution globale **.
La méthode de descente la plus raide est facile de tomber dans une solution locale en sélectionnant la valeur initiale, mais la méthode de descente de gradient probabiliste resélectionne les données utilisées pour le calcul du gradient chaque fois que le paramètre est mis à jour, il est donc possible d'atteindre une solution globale sur une basse montagne. Semble être plus élevé.
De plus, il convient au traitement en temps réel car il n'est pas nécessaire de décider des données à utiliser.
J'ai créé la classe StochasticGradientDescent comme avant. Le contenu est presque le même que celui de la méthode de descente la plus raide, à l'exception de la partie mise à jour des paramètres. La taille du mini-lot peut maintenant être spécifiée combien utiliser pour toutes les données. Je me souviens du paramètre avec la perte la plus faible et j'essaye de le renvoyer.
class StochasticGradientDescent:
def __init__(self, eta=0.01, n_iter=2000, sample_rate=0.1):
self.eta = eta
self.n_iter = n_iter
self.sample_rate = sample_rate
self.grad = np.zeros((2,))
self.loss = np.array([])
def fit(self, X, Y, w0):
self.w = w0
self.min_w = w0
n_samples = int(np.ceil(len(X)*self.sample_rate))
min_loss = 10**18
for _ in range(self.n_iter):
loss = np.sum((Y-self.w[0]-self.w[1]*X)**2)
if min_loss>loss:
min_loss = loss
self.min_w = self.w
self.loss = np.append(self.loss, loss)
for i in range(n_samples):
index = np.random.randint(0, len(X))
batch_x = X[index]
batch_y = Y[index]
self.grad[0] = np.sum(-2*(batch_y-self.w[0]-self.w[1]*batch_x))
self.grad[1] = np.sum(-2*batch_x*(batch_y-self.w[0]-self.w[1]*batch_x))
self.w -= self.eta * self.grad
def predict(self, x):
return (self.w[0] + self.w[1]*x)
@property
def coef_(self):
return self.min_w[1]
@property
def intercept_(self):
return self.min_w[0]
@property
def loss_(self):
return self.loss
Faites-le et regardez également les changements dans les pertes.
w0 = np.array([1.,1.])
model = StochasticGradientDescent()
model.fit(x, y, w0)
print("A: ", model.coef_)
print("B: ", model.intercept_)
loss = model.loss
plt.plot(np.arange(len(loss)), np.log10(loss))
plt.show()
A: 925.5203159922469
B: 146.8724188770836
C'est un peu différent de la solution exacte, et on a l'impression que la perte devient sauvage. Je me suis demandé si la hauteur de la pointe serait inférieure si le taux d'apprentissage était abaissé, et s'il y avait une relation d'échantillonnage aléatoire ou si la corrélation de l'échantillon d'origine était faible, cela ne convergerait pas vers une solution exacte. Le réglage des paramètres ici est un problème.
En tant que méthode de descente de gradient, j'ai étudié la méthode de descente la plus raide et la méthode de descente de gradient de vitesse à acheter. Dans le monde du scikit-learn et du deep learning, il existe divers autres gradients, mais les bases sont les mêmes. En le regardant pas à pas de cette manière, il peut être plus facile d'imaginer le réglage des paramètres.
La prochaine fois, j'aimerais résumer le résumé de la régression, du surapprentissage et de la régularisation.
Recommended Posts