In che modo la discesa gradiente stocastica può far risparmiare tempo rispetto alla discesa gradiente standard?


15

Discesa gradiente standard calcolerebbe il gradiente per l'intero set di dati di allenamento.

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

Per un numero predefinito di epoche, prima calcoliamo il vettore gradiente weights_grad della funzione di perdita per l'intero set di dati con i nostri parametri vettoriali.

La Discesa gradiente stocastica esegue invece un aggiornamento dei parametri per ciascun esempio di allenamento x (i) e l'etichetta 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

Si dice che SGD sia molto più veloce. Tuttavia, non capisco come possa essere molto più veloce se abbiamo ancora un ciclo su tutti i punti dati. Il calcolo del gradiente in GD è molto più lento del calcolo di GD per ciascun punto dati separatamente?

Il codice viene da qui .


1
Nel secondo caso, prenderebbe un piccolo batch per approssimare l'intero set di dati. Questo di solito funziona abbastanza bene. Quindi la parte confusa è probabilmente che sembra che il numero di epoche sia lo stesso in entrambi i casi, ma non avresti bisogno di tante epoche nel caso 2. Gli "iperparametri" sarebbero diversi per questi due metodi: GD nb_epochs! = SGD nb_epochs. Diciamo ai fini dell'argomento: GD nb_epochs = Esempi SGD * nb_epochs, in modo che il numero totale di loop sia lo stesso, ma il calcolo del gradiente è molto più veloce in SGD.
Nima Mousavi,

Questa risposta su CV è buona e correlata.
Zhubarb,

Risposte:


23

Risposta breve:

  • In molte impostazioni di big data (diciamo diversi milioni di punti dati), il calcolo del costo o del gradiente richiede molto tempo, perché dobbiamo sommare tutti i punti dati.
  • Noi non è necessario aver gradiente esatto per ridurre il costo in una data iterazione. Qualche approssimazione del gradiente funzionerebbe bene.
  • Gradiente stocastico decente (SGD) approssima il gradiente usando solo un punto dati. Pertanto, la valutazione del gradiente consente di risparmiare molto tempo rispetto alla somma di tutti i dati.
  • Con un numero "ragionevole" di iterazioni (questo numero potrebbe essere un paio di migliaia e molto meno del numero di punti dati, che possono essere milioni), il gradiente stocastico decente può ottenere una buona soluzione ragionevole.

Risposta lunga:

La mia notazione segue il corso Coursera di machine learning di Andrew NG. Se non si ha familiarità con esso, è possibile rivedere la serie di lezioni qui .

Supponiamo che la regressione sulla perdita al quadrato sia la funzione di costo

J(θ)=12mΣio=1m(hθ(X(io))-y(io))2

e il gradiente è

dJ(θ)dθ=1mΣio=1m(hθ(X(io))-y(io))X(io)

per il gradiente decente (GD), aggiorniamo il parametro di

θnew=θold-α1mΣio=1m(hθ(X(io))-y(io))X(io)

1/mX(io),y(io)

θnew=θold-α(hθ(X(io))-y(io))X(io)

Ecco perché stiamo risparmiando tempo:

Supponiamo di avere 1 miliardo di punti dati.

  • In GD, per aggiornare i parametri una volta, dobbiamo avere il gradiente (esatto). Ciò richiede di sommare questi 1 miliardo di punti dati per eseguire 1 aggiornamento.

  • In SGD, possiamo pensarlo come cercare di ottenere un gradiente approssimativo anziché esatto . L'approssimazione proviene da un punto dati (o da più punti dati chiamati mini batch). Pertanto, in SGD, possiamo aggiornare i parametri molto rapidamente. Inoltre, se "eseguiamo il ciclo" su tutti i dati (chiamati un'epoca), abbiamo effettivamente 1 miliardo di aggiornamenti.

Il trucco è che in SGD non è necessario avere 1 miliardo di iterazioni / aggiornamenti, ma molto meno iterazioni / aggiornamenti, diciamo 1 milione, e avrai un modello "abbastanza buono" da usare.


Sto scrivendo un codice per provare l'idea. Prima risolviamo il sistema lineare con equazione normale, quindi risolviamo con SGD. Quindi confrontiamo i risultati in termini di valori dei parametri e valori della funzione obiettivo finale. Per visualizzarlo in seguito, avremo 2 parametri per la messa a punto.

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)
}

I risultati:

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

124.1343123.0355 che sono molto vicini.

Ecco i valori della funzione di costo rispetto alle iterazioni, possiamo vedere che può effettivamente ridurre la perdita, il che illustra l'idea: possiamo usare un sottoinsieme di dati per approssimare il gradiente e ottenere risultati "abbastanza buoni".

inserisci qui la descrizione dell'immagine

inserisci qui la descrizione dell'immagine

Ora controlliamo gli sforzi computazionali tra due approcci. Nell'esperimento, abbiamo1000i punti dati, utilizzando SD, valutano il gradiente una volta che è necessario sommarli. MA in SGD,sq_loss_gr_approx funzione riassume solo 1 punto dati e, nel complesso, vediamo che l'algoritmo converge meno di300 iterazioni (nota, no 1000 iterazioni). Questo è il risparmio computazionale.


Ho pensato che l'argomento sulla "velocità" sia più su quante operazioni / iterazioni sono necessarie per convergere in un ottimale locale? (E anche quella discesa a gradiente stocastico tende a convergere verso una migliore optima.)
GeoMatt22

Per quanto ho capito, nel codice Python ho fornito che la variabile "dati" è la stessa. Il mini decodificatore gradiente batch - codice è diverso da SDG (ed esattamente lì usa solo una piccola parte dei dati). Inoltre, nella spiegazione fornita, sebbene ci sbarazziamo della somma in SDG, calcoliamo comunque l'aggiornamento per ciascun punto dati. Non riesco ancora a capire come l'aggiornamento di un parametro durante il ciclo su ciascun punto dati sia più veloce del semplice sommare tutti i punti dati contemporaneamente.
Alina,

@ GeoMatt22 Nel link che ho fornito si afferma: "D'altra parte, questo alla fine complica la convergenza al minimo esatto, poiché SGD continuerà a superare." Significa che non converge in optima migliore. O ho sbagliato?
Alina,

@Tonja Non sono un esperto, ma ad esempio questo documento altamente influente nel deep learning fornisce l'argomento "allenamento più rapido e affidabile" per la discesa stocastica a gradiente. Si noti che non utilizza la versione "grezza", ma utilizza varie stime di curvatura per impostare il tasso di apprendimento (dipendente dalle coordinate).
GeoMatt22,

1
@Tonja, sì. qualsiasi approssimazione "debole" del gradiente funzionerebbe. Puoi controllare "incremento gradiente", che è un'idea simile. D'altra parte, sto scrivendo un po 'di codice per demo l'idea. Lo posterò quando sarà pronto.
Haitao Du,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.