Discesa gradiente stocastica basata su operazioni vettoriali?


10

supponiamo che io voglia addestrare un algoritmo stocastico di regressione della discesa del gradiente usando un set di dati che ha N campioni. Poiché la dimensione del set di dati è fissa, riutilizzerò i dati T volte. Ad ogni iterazione o "epoca", utilizzo ogni campione di allenamento esattamente una volta dopo aver riordinato casualmente l'intero set di allenamento.

La mia implementazione si basa su Python e Numpy. Pertanto, l'utilizzo di operazioni vettoriali può ridurre notevolmente i tempi di calcolo. Venire con un'implementazione vettoriale della discesa del gradiente in lotti è abbastanza semplice. Tuttavia, nel caso della discesa gradiente stocastica non riesco a capire come evitare il ciclo esterno che scorre attraverso tutti i campioni in ogni epoca.

Qualcuno conosce un'implementazione vettoriale della discesa del gradiente stocastica?

EDIT : Mi è stato chiesto perché mi piacerebbe utilizzare la discesa gradiente online se la dimensione del mio set di dati è fissa.

Da [1], si può vedere che la discesa del gradiente online converge più lentamente della discesa del gradiente batch al minimo del costo empirico. Tuttavia, converge più rapidamente al minimo del costo previsto, che misura le prestazioni di generalizzazione. Mi piacerebbe testare l'impatto di questi risultati teorici sul mio problema particolare, attraverso la validazione incrociata. Senza un'implementazione vettoriale, il mio codice di discesa gradiente online è molto più lento di quello di discesa gradiente batch. Ciò aumenta notevolmente il tempo necessario per completare il processo di convalida incrociata.

EDIT : includo qui lo pseudocodice della mia implementazione on-line della discesa del gradiente, come richiesto da ffriend. Sto risolvendo un problema di regressione.

Method: on-line gradient descent (regression)
Input: X (nxp matrix; each line contains a training sample, represented as a length-p vector), Y (length-n vector; output of the training samples)
Output: A (length-p+1 vector of coefficients)

Initialize coefficients (assign value 0 to all coefficients)
Calculate outputs F
prev_error = inf
error = sum((F-Y)^2)/n
it = 0
while abs(error - prev_error)>ERROR_THRESHOLD and it<=MAX_ITERATIONS:
    Randomly shuffle training samples
    for each training sample i:
        Compute error for training sample i
        Update coefficients based on the error above
    prev_error = error
    Calculate outputs F
    error = sum((F-Y)^2)/n
    it = it + 1

[1] "Apprendimento online su larga scala", L. Bottou, Y. Le Cunn, NIPS 2003.


2
Suddividere il set di dati in mini-batch e adattare il modello a ciascun mini-batch in sequenza.
amico

Grazie amico. Tuttavia, questa non sarebbe una pura implementazione online.
Pablo Suau,

1
Qual è il motivo per utilizzare l'implementazione "pure online" se il set di dati è stato corretto? SGD dice solo che non è necessario iterare l'intero set di dati contemporaneamente, ma è possibile dividerlo in un numero arbitrario di pezzi (mini-batch) ed elaborarli uno per uno. Il mini-batch di dimensione 1 ha senso solo quando si dispone di una fonte di dati continua e possibilmente infinita (come ad esempio il feed di Twitter) e si desidera aggiornare il modello dopo ogni nuova osservazione. Ma questo è un caso molto raro e sicuramente non per set di dati fissi.
amico

Mi scuso per la mia risposta molto tardi. Per favore, controlla il testo che ho aggiunto alla domanda originale.
Pablo Suau,

1
Puoi mostrare la tua implementazione? Vedo incomprensioni, ma senza un esempio di codice sarà difficile spiegarlo.
amico

Risposte:


10

Prima di tutto, la parola "campione" viene normalmente utilizzata per descrivere un sottoinsieme di popolazione , quindi mi riferirò alla stessa cosa di "esempio".

L'implementazione SGD è lenta a causa di questa linea:

for each training example i:

Qui usi esplicitamente esattamente un esempio per ogni aggiornamento dei parametri del modello. Per definizione, la vettorializzazione è una tecnica per convertire le operazioni su un elemento in operazioni su un vettore di tali elementi. Pertanto, no, non è possibile elaborare gli esempi uno a uno e utilizzare comunque la vettorializzazione.

Tuttavia, è possibile approssimare SGD reale utilizzando mini-batch . Il mini-batch è un piccolo sottoinsieme del set di dati originale (diciamo, 100 esempi). Calcolate gli aggiornamenti di errori e parametri sulla base di mini-batch, ma continuate a iterare su molti di essi senza ottimizzazione globale, rendendo il processo stocastico. Quindi, per rendere la tua implementazione molto più veloce è sufficiente cambiare la riga precedente in:

batches = split dataset into mini-batches
for batch in batches: 

e calcola l'errore dal batch, non da un singolo esempio.

Anche se abbastanza ovvio, dovrei anche menzionare la vettorializzazione a livello di esempio. Cioè, invece di qualcosa del genere:

theta = np.array([...])  # parameter vector
x = np.array([...])      # example
y = 0                    # predicted response
for i in range(len(example)):
    y += x[i] * theta[i]
error = (true_y - y) ** 2  # true_y - true value of response

dovresti assolutamente fare qualcosa del genere:

error = (true_y - sum(np.dot(x, theta))) ** 2

che, ancora una volta, è facile generalizzare per i mini-lotti:

true_y = np.array([...])     # vector of response values
X = np.array([[...], [...]]) # mini-batch
errors = true_y - sum(np.dot(X, theta), 1)
error = sum(e ** 2 for e in errors)

1
Penso che questa sia la strada da percorrere. I mini-batch con una dimensione ben scelta possono effettivamente convergere più velocemente rispetto alla versione batch o online (il primo aggiorna i pesi solo una volta per intero set e il secondo non può essere vettorializzato, oltre a passaggi di aggiornamento del peso aggiuntivi più spesso)
Neil Slater

Grazie ad entrambi. Mi scuso per aver rifiutato ostinatamente i mini lotti prima, ma non ero sicuro delle implicazioni di questo metodo sul tasso di convergenza. Neil, la tua affermazione proviene dalla tua stessa esperienza o ci sono risultati pubblicati teorici / empirici?
Pablo Suau,

1
@PabloSuau Puoi controllare il corso di Machine Learning di Andrew Ng a Coursera, settimana 10, spiega perché la convergenza può essere più veloce sia di SGD che di GD in batch. Per essere più precisi: dovrebbe sempre essere veloce come SGD, ma a volte dovrebbe essere ancora più veloce in pratica.
gaboroso

1

Dai un'occhiata al metodo partial_fit del classificatore SGD di scikit . Hai il controllo su ciò che chiami con esso: puoi farlo "vero" apprendimento online passando un'istanza alla volta, oppure puoi raggruppare le istanze in mini-lotti se tutti i tuoi dati sono disponibili in un array. In tal caso, è possibile dividere l'array per fornire i minibatch.

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.