Come calcolare l'impatto della memoria mini-batch durante l'allenamento dei modelli di apprendimento profondo?


17

Sto cercando di calcolare la quantità di memoria necessaria a una GPU per addestrare il mio modello sulla base di queste note di Andrej Karphaty: http://cs231n.github.io/convolutional-networks/#computational-considerations

La mia rete ha 532.752 attivazioni e 19.072.984 parametri (pesi e distorsioni). Questi sono tutti valori float a 32 bit, quindi ognuno richiede 4 byte in memoria.

La mia immagine di input è 180x50x1 (larghezza x altezza x profondità) = 9.000 float 32 valori. Non uso il potenziamento dell'immagine, quindi penso che la memoria miscellanea sia correlata solo alla dimensione del mini-batch. Sto usando una dimensione mini-batch di 128 immagini.

Sulla base della raccomandazione di Andrej, ottengo le seguenti dimensioni di memoria:

Attivazioni: 532.752 * 4 / (1024 ^ 2) = 2.03 MB

Parametri: 19.072.984 * 4 / (1024 ^ 2) * 3 = 218.27 MB

Varie: 128 * 9.000 * 4 / (1024 ^ 2) = 4.39 MB

Quindi la memoria totale per addestrare questa rete sarebbe di 224,69 MB .

Sto usando TensorFlow e penso che mi manchi qualcosa. Non ho ancora eseguito la formazione, ma sono abbastanza sicuro (sulla base delle esperienze passate) che la memoria in uso sarà molto più alta di quella che ho calcolato.

Se per ogni immagine nel mini-batch, TensorFlow mantiene i propri gradienti in modo da poterli normalizzare in un secondo momento per un singolo passo di aggiornamento di pesi / errori, allora penso che la memoria dovrebbe tener conto di altri 532.752 * 128 valori (gradienti per ogni immagine nel mini-batch). In tal caso, avrei bisogno di più 260,13 MB per addestrare questo modello con 128 immagini / mini-batch.

Potete aiutarmi a comprendere le considerazioni sulla memoria per la formazione del mio modello di apprendimento profondo? Le considerazioni di cui sopra sono giuste?


Vedi la mia (proposta) risposta alla tua domanda qui .
Adam Hendry,

Risposte:


5

Penso che tu sia sulla strada giusta.

Sì, sarà necessario memorizzare i derivati ​​delle attivazioni e dei parametri per la backpropagation.

Inoltre, la scelta dell'ottimizzazione può essere importante. Ti stai allenando con SGD, Adam o Adagrad? Questi avranno tutti requisiti di memoria diversi. Ad esempio, dovrai memorizzare la cache della dimensione del passo per un metodo basato sul momentum, anche se dovrebbe essere secondario rispetto alle altre considerazioni sulla memoria che menzioni.

Quindi, tutto sommato, sembra che tu abbia calcolato i requisiti di memoria per un passaggio in avanti. Andrej Karpathy afferma che il passaggio all'indietro potrebbe richiedere fino a 3 volte la memoria del passaggio in avanti, quindi questo potrebbe essere il motivo per cui vedi una tale differenza (scorri verso il basso fino a "Case Studies" sul sito Web per vedere un esempio di VGGNet).


5

@StatsSorceress TL; DR:

Sto attraversando questa attività per vedere se posso calcolare me stesso la memoria richiesta:

Attivazioni: 532.752 * 2 * 4 / (1024 ^ 2) = 4.06 MB

Parametri: 19.072.984 * 4 / (1024 ^ 2) * 3 = 218.27 MB

Varie: 128 * 9.000 * 4 / (1024 ^ 2) = 4.39 MB

Memoria totale: (4.06 * 128 ) + 218.27 + 4.39 = 742.34 MB

( Qualcuno per favore correggimi su questo se sbaglio. Cordiali saluti, hai già moltiplicato varie per 128, quindi è per questo che non ho moltiplicato per 128 sopra )


Vorrei indicarti questo articolo e il video corrispondente . Mi hanno aiutato a capire cosa sta succedendo molto meglio.

NOTA: la memoria richiesta per utilizzare una rete per le previsioni è molto inferiore a quella richiesta per la formazione per due motivi:

  • Durante la previsione, inviamo solo un'immagine in avanti attraverso la rete e non all'indietro (quindi non moltiplichiamo la memoria X 3; vedi sotto)
  • C'è una previsione per immagine (quindi non è necessario moltiplicare la memoria richiesta per un'immagine per una dimensione batch perché non utilizziamo i batch nella previsione).

Processo (memoria da addestrare)

  1. Calcola la memoria richiesta per allenarsi su un'immagine
  2. Moltiplica questo numero per il numero di immagini nel tuo batch

( RICORDA: il mini-batch dice che prendiamo un sottoinsieme dei nostri dati, calcoliamo i gradienti e gli errori per ogni immagine nel sottoinsieme, quindi li mediamo e facciamo un passo avanti nella direzione della media. Per convnet, pesi e distorsioni sono condivisi, ma il numero di attivazioni viene modificato in base al numero di immagini nel batch. ).

PASSAGGIO 1: Memoria per 1 immagine

Per addestrare un'immagine, è necessario riservare memoria per:

  • Parametri del modello:

    I pesi e le inclinazioni di ogni livello, i loro gradienti e le loro variabili di quantità di moto (se vengono utilizzati gli ottimizzatori Adam, Adagrad, RMSProp, ecc.)

    Per approssimare la memoria per questo, calcolare la memoria richiesta per memorizzare pesi e distorsioni e moltiplicarla per 3 (cioè "per 3" perché stiamo dicendo che la quantità di memoria necessaria per memorizzare pesi e distorsioni è (approssimativamente) uguale a quello necessario per i gradienti e per le variabili momentum)

    Equazioni:

    circonvoluzioni:

    pesi (n) = profondità (n) * (kernel_width * kernel_height) * profondità (n-1)

    bias (n) = profondità (n)

    Strati completamente collegati (densi):

    pesi (n) = uscite (n) * ingressi (n)

    bias (n) = output (n)

dove n è il livello corrente e n-1 è il livello precedente e le uscite sono il numero di uscite dal livello FC e gli ingressi sono il numero di ingressi al livello FC (se il livello precedente non è un livello completamente collegato, il numero di input è uguale alla dimensione di quello strato appiattito).

NOTA: la memoria per i soli pesi e distorsioni, più la memoria per le attivazioni per un'immagine (vedi sotto), è la quantità totale di memoria necessaria per le previsioni (escluso un sovraccarico di memoria per le convoluzioni e altre cose).

  • Attivazioni (questi sono "Blobs" nel Caffe):

(Sto usando termini vagamente qui, abbi pazienza con me)

Ogni convoluzione in un livello di convoluzione produce attivazioni " numero di pixel nell'immagine " (ovvero quando passi un'immagine attraverso una singola convoluzione, ottieni una singola mappa caratteristica costituita da attivazioni " m ", dove " m " è il numero di pixel dal tuo immagine / ingresso).

Per i livelli completamente collegati, il numero di attivazioni che produci è uguale alla dimensione del tuo output.

circonvoluzioni:

activations (n) = image_width * image_height * image_num_channels

Strati completamente collegati (densi):

attivazioni (n) = uscite (n)

Nota che il tuo input è in realtà solo un'immagine all'inizio della rete. Dopo le convoluzioni, si trasforma in qualcos'altro (mappe delle caratteristiche). Quindi sostituisci davvero "image_width", "image_height" e "image_num_channels" con "input_width", "input_height" e "layer_depth" per essere più precisi. (È solo più facile per me pensare a questo concetto in termini di immagini.)

Poiché dobbiamo anche memorizzare l'errore per le attivazioni su ciascun livello (utilizzato nel passaggio all'indietro), moltiplichiamo il numero di attivazioni per 2 per ottenere il numero totale di entità di cui abbiamo bisogno per fare spazio nel nostro spazio di archiviazione. Il numero di attivazioni aumenta con il numero di immagini nel batch, quindi moltiplica questo numero per la dimensione del batch.

PASSAGGIO 2: batch Memory to Train

Somma il numero di pesi e distorsioni (volte 3) e il numero di attivazioni (volte 2 volte la dimensione del lotto). Moltiplicalo per 4 e otterrai il numero di byte necessari per addestrare il batch. Puoi dividere per 1024 ^ 2 per ottenere la risposta in GB.


Perché dici "non usiamo i batch in previsione"? Se un utente deve fare previsioni su un gran numero di immagini, può avere senso usare i batch nelle previsioni.
user3731622,

1

In alternativa, penso che tu possa usare qualsiasi libreria di profiler per analizzare la memoria e l'utilizzo della CPU da parte del tuo programma. Esistono molte librerie Python che possono fornire un'istantanea della memoria e dell'utilizzo della CPU da parte di thread o processi particolari a intervalli di millisecondi.

È possibile eseguire la parte del programma che si desidera monitorare in un diverso processo secondario utilizzando popen e monitorare la memoria e l'utilizzo della CPU utilizzando il PID.

psutil trovo buono per tale lavoro. Sebbene ce ne siano molti altri.

Spero che questo possa aiutare.


3
Grazie per la risposta, @Anwar. Sto cercando un calcolo analitico piuttosto che un'osservazione empirica.
barbolo,
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.