Comment la descente de gradient stochastique pourrait-elle gagner du temps par rapport à la descente de gradient standard?

15

La descente de gradient standard calculerait le gradient pour l'ensemble des données d'apprentissage.

for i in range(nb_epochs):
  params_grad = evaluate_gradient(loss_function, data, params)
  params = params - learning_rate * params_grad

Pour un nombre prédéfini d'époques, nous calculons d'abord le vecteur de gradient weights_grad de la fonction de perte pour l'ensemble de données par rapport à nos paramètres de vecteur de paramètres.

La descente de gradient stochastique, en revanche, effectue une mise à jour des paramètres pour chaque exemple d'apprentissage x (i) et étiquette y (i).

for i in range(nb_epochs):
  np.random.shuffle(data)
  for example in data:
    params_grad = evaluate_gradient(loss_function, example, params)
    params = params - learning_rate * params_grad

SGD serait beaucoup plus rapide. Cependant, je ne comprends pas comment cela peut être beaucoup plus rapide si nous avons encore une boucle sur tous les points de données. Le calcul du gradient dans GD est-il beaucoup plus lent que le calcul de GD pour chaque point de données séparément?

Le code vient d' ici .

Alina
la source
1
Dans le second cas, vous prendriez un petit lot pour approximer l'ensemble de données entier. Cela fonctionne généralement assez bien. Donc, la partie déroutante est probablement qu'il semble que le nombre d'époques soit le même dans les deux cas, mais vous n'auriez pas besoin d'autant d'époques dans le cas 2. Les "hyperparamètres" seraient différents pour ces deux méthodes: GD nb_epochs! = SGD nb_epochs. Disons aux fins de l'argument: GD nb_epochs = exemples SGD * nb_epochs, de sorte que le nombre total de boucles est le même, mais le calcul du gradient est beaucoup plus rapide dans SGD.
Nima Mousavi
Cette réponse sur CV est bonne et connexe.
Zhubarb

Réponses:

23

Réponse courte:

  • Dans de nombreux paramètres de Big Data (disons plusieurs millions de points de données), le calcul du coût ou du gradient prend très longtemps, car nous devons additionner tous les points de données.
  • Nous n'avons PAS besoin d'avoir un gradient exact pour réduire le coût dans une itération donnée. Une approximation du gradient fonctionnerait bien.
  • Le gradient stochastique décent (SGD) se rapproche du gradient en utilisant un seul point de données. Ainsi, l'évaluation du gradient permet de gagner beaucoup de temps par rapport à la somme de toutes les données.
  • Avec un nombre "raisonnable" d'itérations (ce nombre pourrait être de quelques milliers, et bien inférieur au nombre de points de données, qui peuvent être des millions), le gradient stochastique décent peut obtenir une bonne solution raisonnable.

Longue réponse:

Ma notation suit le cours Coursera d'apprentissage automatique d'Andrew NG. Si vous ne le connaissez pas, vous pouvez consulter la série de conférences ici .

Supposons une régression sur la perte au carré, la fonction de coût est

J(θ)=12mje=1m(hθ(X(je))-y(je))2

et le gradient est

J(θ)θ=1mje=1m(hθ(X(je))-y(je))X(je)

pour un gradient décent (GD), nous mettons à jour le paramètre en

θnew=θol-α1mje=1m(hθ(X(je))-y(je))X(je)

1/mX(je),y(je)

θnew=θol-α(hθ(X(je))-y(je))X(je)

Voici pourquoi nous gagnons du temps:

Supposons que nous ayons 1 milliard de points de données.

  • Dans GD, afin de mettre à jour les paramètres une fois, nous devons avoir le gradient (exact). Cela nécessite de résumer ces 1 milliard de points de données pour effectuer 1 mise à jour.

  • Dans SGD, nous pouvons penser qu'il essaie d'obtenir un gradient approximatif au lieu d'un gradient exact . L'approximation provient d'un point de données (ou de plusieurs points de données appelés mini-lots). Par conséquent, dans SGD, nous pouvons mettre à jour les paramètres très rapidement. De plus, si nous "bouclons" sur toutes les données (appelées une époque), nous avons en fait 1 milliard de mises à jour.

L'astuce est que, dans SGD, vous n'avez pas besoin d'avoir 1 milliard d'itérations / mises à jour, mais beaucoup moins d'itérations / mises à jour, disons 1 million, et vous aurez un modèle "assez bon" à utiliser.


J'écris un code pour démo l'idée. Nous résolvons d'abord le système linéaire par une équation normale, puis le résolvons avec SGD. Ensuite, nous comparons les résultats en termes de valeurs de paramètres et de valeurs de fonctions objectives finales. Afin de le visualiser plus tard, nous aurons 2 paramètres à régler.

set.seed(0);n_data=1e3;n_feature=2;
A=matrix(runif(n_data*n_feature),ncol=n_feature)
b=runif(n_data)
res1=solve(t(A) %*% A, t(A) %*% b)

sq_loss<-function(A,b,x){
  e=A %*% x -b
  v=crossprod(e)
  return(v[1])
}

sq_loss_gr_approx<-function(A,b,x){
  # note, in GD, we need to sum over all data
  # here i is just one random index sample
  i=sample(1:n_data, 1)
  gr=2*(crossprod(A[i,],x)-b[i])*A[i,]
  return(gr)
}

x=runif(n_feature)
alpha=0.01
N_iter=300
loss=rep(0,N_iter)

for (i in 1:N_iter){
  x=x-alpha*sq_loss_gr_approx(A,b,x)
  loss[i]=sq_loss(A,b,x)
}

Les resultats:

as.vector(res1)
[1] 0.4368427 0.3991028
x
[1] 0.3580121 0.4782659

124.1343123.0355

Voici les valeurs de la fonction de coût sur les itérations, nous pouvons voir qu'elle peut effectivement réduire la perte, ce qui illustre l'idée: nous pouvons utiliser un sous-ensemble de données pour approximer le gradient et obtenir des résultats "assez bons".

entrez la description de l'image ici

entrez la description de l'image ici

1000sq_loss_gr_approx3001000

Haitao Du
la source
Je pensais que l'argument sur la «vitesse» concernait davantage le nombre d'opérations / itérations nécessaires pour converger vers un optimum local? (Et aussi cette descente de gradient stochastique a tendance à converger vers de meilleurs optima.)
GeoMatt22
Pour autant que je sache, dans le code python, j'ai fourni la variable "data" est la même. Le mini-gradient décent par lots - le code est différent de SDG (et exactement là, il n'utilise qu'une petite fraction des données). De plus, dans l'explication que vous avez fournie, bien que nous nous débarrassions de la somme dans SDG, nous calculons toujours la mise à jour pour chaque point de données. Je ne comprends toujours pas comment la mise à jour d'un paramètre tout en bouclant sur chaque point de données est plus rapide que de simplement prendre une somme sur tous les points de données à la fois.
Alina
@ GeoMatt22 Dans le lien que j'ai fourni, il est indiqué: "D'un autre côté, cela complique finalement la convergence au minimum exact, car SGD continuera de dépasser." Cela signifie qu'il ne converge pas vers de meilleurs optima. Ou est-ce que je me suis trompé?
Alina
@Tonja Je ne suis pas un expert, mais par exemple, cet article très influent sur l'apprentissage en profondeur donne l'argument "une formation plus rapide et plus fiable" pour la descente de gradient stochastique. Notez qu'il n'utilise pas la version "brute", mais utilise diverses estimations de courbure pour définir le taux d'apprentissage (dépendant des coordonnées).
GeoMatt22
1
@Tonja, oui. toute approximation "faible" du gradient fonctionnerait. Vous pouvez cocher la case "gradient boosting", qui est une idée similaire. D'un autre côté, j'écris du code pour démo l'idée. Je le posterai quand il sera prêt.
Haitao Du