Ricerca nel sito web

Come massimizzare l'utilizzo della GPU trovando la giusta dimensione del batch


Introduzione

Spesso, una delle domande più frequenti dei nuovi data scientist e ingegneri ML è se i loro processi di formazione sul deep learning funzionano in modo ottimale. In questa guida impareremo come diagnosticare e risolvere i problemi di prestazioni del deep learning indipendentemente dal fatto che stiamo lavorando su una o più macchine. Questo per aiutarci a capire come utilizzare in modo pratico ed efficace l'ampia varietà di GPU cloud disponibili.

Inizieremo comprendendo qual è l'utilizzo della GPU e finiremo discutendo la dimensione batch ottimale per il massimo utilizzo della GPU.

Nota: questa guida presuppone una conoscenza di base del sistema operativo Linux e del linguaggio di programmazione Python. Le ultime distribuzioni Linux vengono fornite con Ubuntu preinstallato, quindi possiamo procedere e installare pip e conda, poiché li useremo qui.

Prerequisiti

Per seguire questo articolo, avrai bisogno di esperienza con il codice Python e di una conoscenza principiante del Deep Learning. Opereremo partendo dal presupposto che tutti i lettori abbiano accesso a macchine sufficientemente potenti da poter eseguire il codice fornito.

Se non hai accesso a una GPU, ti suggeriamo di accedervi tramite il cloud. Esistono molti provider cloud che offrono GPU. I Droplet GPU DigitalOcean sono attualmente in disponibilità anticipata, scopri di più e iscriviti per interessarti ai Droplet GPU qui

Per istruzioni su come iniziare con il codice Python, ti consigliamo di provare questa guida per principianti per configurare il tuo sistema e prepararti a eseguire tutorial per principianti.

Cos'è l'utilizzo della GPU?

Nelle sessioni di formazione su machine e deep learning, l'utilizzo della GPU è l'aspetto più importante da osservare ed è disponibile tramite noti strumenti GPU integrati e di terze parti.

Possiamo definire l'utilizzo della GPU come la velocità con cui uno o più kernel GPU operano nell'ultimo secondo, che è parallela a una GPU utilizzata da un programma di deep learning. Potremmo anche dire questo

Come fai a sapere che hai bisogno di più calcolo della GPU?

Consideriamo qui uno scenario reale,

In una giornata tipo, un data scientist riceve due GPU che può utilizzare: queste “dovrebbero” essere risorse sufficienti. Nella maggior parte dei giorni, durante la fase di costruzione, non ci sono problemi a interagire con i cicli brevi della GPU e il flusso di lavoro è fluido. Quindi inizia la fase di training e all'improvviso il flusso di lavoro richiede ulteriore calcolo della GPU che non è immediatamente disponibile.

Ciò significa che saranno necessarie più risorse di calcolo per svolgere qualsiasi tipo di lavoro significativo. Poniamo particolare enfasi sulle seguenti attività in quanto impossibili quando tutta la RAM è allocata:

  • Esegui più esperimenti
  • Esegui l'addestramento multi-GPU per accelerare l'addestramento e sperimentare batch di dimensioni maggiori e ottenere una maggiore precisione del modello
  • Concentrarsi su un nuovo modello mentre il modello di training viene eseguito in modo indipendente

Vantaggi dell'utilizzo della GPU

In generale, questi aggiornamenti si trasformano in un doppio aumento dell'utilizzo dell'hardware e in un aumento del 100% della velocità di addestramento del modello.

  • L'utilizzo della GPU ci consentirà di gestire l'allocazione delle risorse in modo più efficiente e, in definitiva, di ridurre i tempi di inattività della GPU e aumentare l'utilizzo del cluster
  • Dal punto di vista di uno specialista del deep learning, consumare più potenza di calcolo della GPU darà spazio per eseguire più esperimenti che miglioreranno la nostra produttività e la qualità dei loro modelli
  • Inoltre, gli amministratori IT possono eseguire modelli di formazione distribuiti utilizzando più GPU, come le macchine multi-GPU NVlink offerte da DigitalOcean Droplets, che riducono i tempi di formazione

La dimensione batch ottimale per l'utilizzo della GPU

L'esperienza generale con la dimensione batch è sempre fonte di confusione perché non esiste un'unica dimensione batch "migliore" per un determinato set di dati e architettura del modello.  Se decidiamo di scegliere una dimensione batch più grande, si addestrerà più velocemente e consumerà più memoria, ma alla fine potrebbe mostrare una precisione inferiore. Innanzitutto, cerchiamo di capire cos'è una dimensione batch e perché ne hai bisogno.

Qual è la dimensione del lotto?

È importante specificare una dimensione batch quando si tratta di addestrare un modello come una rete neurale di deep learning. In parole povere, la dimensione del batch è il numero di campioni che verranno trasmessi contemporaneamente a una rete.

Dimensioni del lotto in un esempio

Diciamo che vogliamo addestrare la nostra rete a riconoscere diverse razze di gatti utilizzando 1000 foto di gatti. Supponiamo ora di aver scelto una dimensione batch pari a 10. Pertanto, significa che in un momento la rete riceverà 10 fotografie di gatti come gruppo o batch nel nostro caso.

Bene, ora abbiamo l'idea della dimensione del batch, ma qual è il punto? Potremmo semplicemente passare ciascun elemento di dati individualmente al nostro modello anziché inserire i dati in batch. Abbiamo spiegato perché ne abbiamo bisogno nella sezione seguente.

Perché utilizzare i batch?

Abbiamo menzionato in precedenza che una dimensione batch maggiore aiuterà un modello a completare rapidamente ogni epoca durante l'addestramento. Questo perché una macchina può essere in grado di produrre molto più di un singolo carattere alla volta a seconda delle risorse computazionali disponibili.

Tuttavia, anche se la nostra macchina è in grado di gestire lotti molto più grandi, l'output finale del modello potrebbe peggiorare quando impostiamo il nostro lotto più grande e alla fine potrebbe limitare il modello a generalizzare su nuovi dati.

Ora possiamo concordare sul fatto che la dimensione del batch è un altro iperparametro che dobbiamo valutare e modificare a seconda di come si comporta un particolare modello durante le sessioni di formazione. Sarà inoltre necessario esaminare questa impostazione per vedere quanto bene la nostra macchina utilizza la GPU quando si eseguono lotti di dimensioni diverse.

Ad esempio, se impostiamo la dimensione del batch su un valore piuttosto elevato, diciamo 100, è possibile che la nostra macchina non abbia una capacità di elaborazione sufficiente per elaborare tutte le 100 immagini contemporaneamente. Ciò indicherebbe che dobbiamo ridurre le dimensioni del nostro batch.

Ora che abbiamo capito un'idea generale di cosa sia una dimensione batch, vediamo come possiamo ottimizzare la giusta dimensione batch nel codice utilizzando PyTorch e Keras.

Trova la giusta dimensione del batch utilizzando PyTorch

In questa sezione esamineremo la ricerca della dimensione batch corretta su un modello Resnet18. Utilizzeremo il profiler PyTorch per misurare le prestazioni di training e l'utilizzo della GPU del modello Resnet18.

Per dimostrare un maggiore utilizzo di PyTorch su TensorBoard per monitorare le prestazioni del modello, utilizzeremo il profiler PyTorch in questo codice ma attiveremo opzioni extra.

Segui questa demo

Sul tuo computer basato su GPU cloud, utilizza wget per scaricare il notebook corrispondente. Quindi, esegui Jupyter Labs per aprire il notebook. Puoi farlo incollando quanto segue e aprendo il collegamento del notebook:

wget https://raw.githubusercontent.com/gradient-ai/batch-optimization-DL/refs/heads/main/notebook.ipynb
jupyter lab

Impostazione e preparazione dei dati e del modello

Digita il seguente comando per installare torch, torchvision e Profiler.

pip3 install torch torchvision torch-tb-profiler

Il seguente codice prenderà il nostro set di dati da CIFAR10 . Successivamente utilizzeremo l'apprendimento del trasferimento con il modello pre-addestrato resnet18 e addestreremo il modello.

#import all the necessary libraries 
import torch  
import torch.nn  
import torch.optim  
import torch.profiler  
import torch.utils.data  
import torchvision.datasets  
import torchvision.models  
import torchvision.transforms as T    
#prepare input data and transform it 
transform = T.Compose(  
    [T.Resize(224),  
     T.ToTensor(),  
     T.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])  
train_set = torchvision.datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)  use dataloader to launch each batch 
train_loader = torch.utils.data.DataLoader(train_set, batch_size=1, shuffle=True, num_workers=4)  Create a Resnet model, loss function, and optimizer objects. To run on GPU, move model and loss to a GPU device 
device = torch.device("cuda:0")  
model = torchvision.models.resnet18(pretrained=True).cuda(device) 
criterion = torch.nn.CrossEntropyLoss().cuda(device)  
optimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)  
model.train()    define the training step for each batch of input data 
def train(data):  
    inputs, labels = data[0].to(device=device), data[1].to(device=device)  
    outputs = model(inputs)  
    loss = criterion(outputs, labels)  
    optimizer.zero_grad()  
    loss.backward()  
    optimizer.step()

Abbiamo impostato con successo il nostro modello di base, ora abiliteremo le funzionalità opzionali nel profiler per registrare più informazioni durante il processo di formazione. Includiamo i seguenti parametri:

  • schedule: questo parametro richiede un singolo  step(int) e restituisce l'azione del profiler da eseguire in ogni fase.
  • profile_memory: viene utilizzato per allocare la memoria della GPU e impostarlo su true potrebbe costare tempo aggiuntivo.
  • with_stack - utilizzato per registrare le informazioni sulla fonte per tutte le tracce.

Ora che comprendiamo questi termini, possiamo tornare al codice:

with torch.profiler.profile(
        schedule=torch.profiler.schedule(wait=1, warmup=1, active=3, repeat=2),
        on_trace_ready=torch.profiler.tensorboard_trace_handler('./log/resnet18_batchsize1'),  
        record_shapes=True,
        profile_memory=True,
        with_stack=True
) as prof:
    for step, batch_data in enumerate(train_loader):
        if step >= (1 + 1 + 3) * 2:
            break
        train(batch_data)
        prof.step()  # Need call this at the end of each step to notify profiler of steps' boundary.

Trova la giusta dimensione del batch utilizzando Keras

In questo caso utilizzeremo un modello sequenziale arbitrario;

model = Sequential([
    Dense(units=16, input_shape=(1,), activation='relu'),
    Dense(units=32, activation='relu', kernel_regularizer=regularizers.l2(0.01)),
    Dense(units=2, activation='sigmoid')
])

Concentriamoci su dove chiamiamo model.fit(). Questa è la funzione con cui una rete neurale artificiale apprende e chiama per addestrare il nostro modello.

model.fit(

    x=scaled_train_samples,
    y=train_labels,
    validation_data=valid_set,
    batch_size=10,
    epochs=20,
    shuffle=True,
    verbose=2
    )

La funzione fit() qui sopra accetta un parametro chiamato batch_size. Qui è dove assegniamo un valore per la nostra variabile batch_size. In questo modello, abbiamo semplicemente impostato il valore su 10.  Pertanto, nell'addestramento di questo modello, passeremo 10 caratteri alla volta fino al completamento dell'intero ciclo. Successivamente, possiamo ricominciare il processo da capo per completare il ciclo successivo.

Cose importanti a cui prestare attenzione

Quando esegui l'addestramento multi-GPU, presta molta attenzione alle dimensioni del batch poiché potrebbe influire sulla velocità/memoria, sulla convergenza del tuo modello e, se non stiamo attenti, i pesi del nostro modello potrebbero essere danneggiati!

Velocità e memoria: senza dubbio, l'addestramento e la previsione vengono eseguiti più rapidamente con batch più grandi. I batch di piccole dimensioni comportano un sovraccarico maggiore a causa del sovraccarico associato al caricamento e allo scaricamento dei dati dalle GPU, ma alcuni studi indicano che l'addestramento con batch di piccole dimensioni produrrà punteggi di efficacia finale complessivi più elevati per tali modelli. D'altra parte, è necessaria RAM GPU aggiuntiva per lotti più grandi. Un batch di grandi dimensioni può causare problemi di memoria insufficiente poiché gli input per ogni livello vengono conservati in memoria, soprattutto durante l'addestramento quando sono necessari per la fase di propagazione all'indietro.

Convergenza: se addestri il tuo modello con la discesa del gradiente stocastico (SGD) o una delle sue varianti, dovresti essere consapevole che la dimensione del batch potrebbe avere un impatto sulla capacità di convergenza e generalizzazione della tua rete. In molti problemi di visione artificiale, le dimensioni dei batch in genere vanno da 32 a 512 istanze.

Corruzione delle GPU - Questo fastidioso dettaglio tecnico potrebbe avere effetti disastrosi. Quando si esegue l'addestramento multi-GPU, è fondamentale fornire dati a ciascuna GPU. È possibile che il batch finale della tua epoca includa meno dati del previsto (perché la dimensione del nostro set di dati non può essere divisa esattamente per la dimensione del nostro batch).

Di conseguenza, alcune GPU potrebbero non ricevere alcun dato durante la fase finale. Purtroppo, alcuni livelli Keras, in particolare il livello di normalizzazione batch, non sono in grado di gestirlo, il che fa sì che i valori NaN appaiano nei pesi (la media corrente e la varianza nel livello BN).

A peggiorare le cose, poiché il livello specifico utilizza la media/varianza del batch nelle stime, non si noterà il problema durante l'addestramento (quando la fase di apprendimento è 1). Tuttavia, la media/varianza corrente viene utilizzata durante le previsioni (fase di apprendimento impostata su 0), che nel nostro scenario può diventare nan portando a risultati inferiori alla media.

Pertanto, durante l'esecuzione dell'addestramento multi-GPU, dovremmo sempre assicurarci che la dimensione del batch sia fissa. Rifiutare i batch che non si adattano alle dimensioni predefinite o ripetere le voci nel batch fino a quando non lo raggiungono sono due approcci semplici per raggiungere questo obiettivo. Ultimo ma non meno importante, ricorda che in una configurazione multi-GPU, la dimensione del batch dovrebbe essere superiore al numero totale di GPU sul tuo sistema.

Conclusione

In questo articolo abbiamo visto come utilizzare vari strumenti per massimizzare l'utilizzo della GPU trovando la giusta dimensione del batch. Finché si imposta una dimensione batch rispettabile (16+) e si mantengono le stesse iterazioni ed epoche, la dimensione batch ha un impatto minimo sulle prestazioni. Tuttavia, il tempo di formazione sarà influenzato. Dovremmo selezionare la dimensione batch più piccola possibile per multi-GPU in modo che ciascuna GPU possa allenarsi con la sua piena capacità. 16 per GPU è un buon numero.

Articoli correlati: