Connect with us

Configurazione di un training, fine-tuning e inferenza di LLM con NVIDIA GPUs e CUDA

Strumenti di IA 101

Configurazione di un training, fine-tuning e inferenza di LLM con NVIDIA GPUs e CUDA

mm
Nvidia GPU in Ubuntu Basics of GPU Parallel Computing GPU Based LLM Training Machine

Il campo dell’intelligenza artificiale (AI) ha assistito a notevoli avanzamenti negli ultimi anni, e al centro di esso si trova la potente combinazione di unità di elaborazione grafica (GPUs) e piattaforma di calcolo parallelo.

Modelli come GPT, BERT, e più recentemente Llama, Mistral sono in grado di comprendere e generare testi simili a quelli umani con una fluidità e coerenza senza precedenti. Tuttavia, l’addestramento di questi modelli richiede grandi quantità di dati e risorse computazionali, rendendo le GPU e CUDA strumenti indispensabili in questo sforzo.

Questa guida completa ti guiderà attraverso il processo di configurazione di un’NVIDIA GPU su Ubuntu, coprendo l’installazione di componenti software essenziali come il driver NVIDIA, CUDA Toolkit, cuDNN, PyTorch e altro.

L’ascesa dei framework AI accelerati da CUDA

L’apprendimento profondo accelerato da GPU è stato alimentato dallo sviluppo di popolari framework AI che sfruttano CUDA per il calcolo efficiente. Framework come TensorFlow, PyTorch e MXNet hanno un supporto integrato per CUDA, consentendo un’integrazione senza soluzione di continuità dell’accelerazione GPU nelle pipeline di apprendimento profondo.

Secondo lo studio sulla prestazione dei prodotti di apprendimento profondo del data center NVIDIA, i modelli di apprendimento profondo accelerati da CUDA possono raggiungere prestazioni fino a 100 volte più veloci rispetto alle implementazioni basate su CPU.

La tecnologia Multi-Instance GPU (MIG) di NVIDIA, introdotta con l’architettura Ampere, consente a una singola GPU di essere suddivisa in più istanze sicure, ognuna con le proprie risorse dedicate. Questa funzione consente una condivisione efficiente delle risorse GPU tra più utenti o carichi di lavoro, massimizzando l’utilizzo e riducendo i costi complessivi.

Accelerazione dell’inferenza LLM con NVIDIA TensorRT

Mentre le GPU sono state strumentali nell’addestramento dei LLM, un’inferenza efficiente è altrettanto cruciale per il deploy di questi modelli in ambienti di produzione. NVIDIA TensorRT, un ottimizzatore e runtime di inferenza di apprendimento profondo ad alte prestazioni, svolge un ruolo vitale nell’accelerazione dell’inferenza LLM sulle GPU abilitate CUDA.

Secondo i benchmark di NVIDIA, TensorRT può fornire un’inferenza fino a 8 volte più veloce e un costo totale di proprietà 5 volte inferiore rispetto all’inferenza basata su CPU per grandi modelli linguistici come GPT-3.

L’impegno di NVIDIA per le iniziative open-source è stato una forza trainante dietro l’ampia adozione di CUDA nella comunità di ricerca AI. Progetti come cuDNN, cuBLAS e NCCL sono disponibili come librerie open-source, consentendo ai ricercatori e agli sviluppatori di sfruttare appieno il potenziale di CUDA per il loro apprendimento profondo.

Installazione

Quando si configura lo sviluppo AI, utilizzare i driver e le librerie più recenti non è sempre la scelta migliore. Ad esempio, mentre il driver NVIDIA più recente (545.xx) supporta CUDA 12.3, PyTorch e altre librerie potrebbero non supportare ancora questa versione. Pertanto, useremo driver versione 535.146.02 con CUDA 12.2 per assicurare la compatibilità.

Passaggi di installazione

1. Installazione del driver NVIDIA

Innanzitutto, identifica il modello della tua GPU. Per questa guida, useremo la GPU NVIDIA. Visita la pagina di download del driver NVIDIA, seleziona il driver appropriato per la tua GPU e nota la versione del driver.

Per verificare i pacchetti GPU precompilati su Ubuntu, esegui:


sudo ubuntu-drivers list --gpgpu

Riavvia il computer e verifica l’installazione:


nvidia-smi

2. Installazione di CUDA Toolkit

Il CUDA Toolkit fornisce l’ambiente di sviluppo per la creazione di applicazioni accelerate da GPU ad alte prestazioni.

Per un setup non LLM/deep learning, puoi utilizzare:


sudo apt install nvidia-cuda-toolkit

Tuttavia, per assicurare la compatibilità con BitsAndBytes, seguiremo questi passaggi:

[code language="BASH"]

git clone https://github.com/TimDettmers/bitsandbytes.git
cd bitsandbytes/
bash install_cuda.sh 122 ~/local 1

Verifica l’installazione:


~/local/cuda-12.2/bin/nvcc --version

Imposta le variabili d’ambiente:


export CUDA_HOME=/home/roguser/local/cuda-12.2/
export LD_LIBRARY_PATH=/home/roguser/local/cuda-12.2/lib64
export BNB_CUDA_VERSION=122
export CUDA_VERSION=122

3. Installazione di cuDNN

Scarica il pacchetto cuDNN dal sito web di NVIDIA Developer. Installalo con:


sudo apt install ./cudnn-local-repo-ubuntu2204-8.9.7.29_1.0-1_amd64.deb

Segui le istruzioni per aggiungere la chiave:


sudo cp /var/cudnn-local-repo-ubuntu2204-8.9.7.29/cudnn-local-08A7D361-keyring.gpg /usr/share/keyrings/

Installa le librerie cuDNN:


sudo apt update
sudo apt install libcudnn8 libcudnn8-dev libcudnn8-samples

4. Configurazione dell’ambiente virtuale Python

Ubuntu 22.04 viene con Python 3.10. Installa venv:


sudo apt-get install python3-pip
sudo apt install python3.10-venv

Crea e attiva l’ambiente virtuale:


cd
mkdir test-gpu
cd test-gpu
python3 -m venv venv
source venv/bin/activate

5. Installazione di BitsAndBytes da sorgente

Naviga nella directory BitsAndBytes e costruisci da sorgente:


cd ~/bitsandbytes
CUDA_HOME=/home/roguser/local/cuda-12.2/ \
LD_LIBRARY_PATH=/home/roguser/local/cuda-12.2/lib64 \
BNB_CUDA_VERSION=122 \
CUDA_VERSION=122 \
make cuda12x

CUDA_HOME=/home/roguser/local/cuda-12.2/ \
LD_LIBRARY_PATH=/home/roguser/local/cuda-12.2/lib64 \
BNB_CUDA_VERSION=122 \
CUDA_VERSION=122 \
python setup.py install

6. Installazione di PyTorch

Installa PyTorch con il seguente comando:


pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu121

7. Installazione di Hugging Face e Transformers

Installa le librerie transformers e accelerate:


pip install transformers
pip install accelerate

Il potere dell’elaborazione parallela

Alla base, le GPU sono processori paralleli progettati per gestire migliaia di thread contemporaneamente in modo efficiente. Questa architettura le rende adatte per le attività computazionalmente intensive coinvolte nell’addestramento di modelli di apprendimento profondo, compresi i LLM. La piattaforma CUDA, sviluppata da NVIDIA, fornisce un ambiente software che consente agli sviluppatori di sfruttare appieno le capacità di elaborazione parallela di queste GPU, consentendo loro di scrivere codice che possa sfruttare il parallelismo dell’hardware.
Accelerazione LLM Training con GPU e CUDA.

L’addestramento di grandi modelli linguistici è un’attività computazionalmente impegnativa che richiede l’elaborazione di grandi quantità di dati testuali e l’esecuzione di numerose operazioni matriciali. Le GPU, con le loro migliaia di core e alta larghezza di banda della memoria, sono ideali per queste attività. Sfruttando CUDA, gli sviluppatori possono ottimizzare il loro codice per sfruttare le capacità di elaborazione parallela delle GPU, riducendo significativamente il tempo necessario per l’addestramento dei LLM.

Ad esempio, l’addestramento di GPT-3, uno dei più grandi modelli linguistici fino ad oggi, è stato reso possibile attraverso l’uso di migliaia di GPU NVIDIA che eseguivano codice ottimizzato per CUDA. Ciò ha consentito al modello di essere addestrato su una quantità di dati senza precedenti, portando alle sue impressionanti prestazioni in compiti di linguaggio naturale.


import torch
import torch.nn as nn
import torch.optim as optim
from transformers import GPT2LMHeadModel, GPT2Tokenizer

# Carica modello e tokenizzatore pre-addestrati
model = GPT2LMHeadModel.from_pretrained('gpt2')
tokenizer = GPT2Tokenizer.from_pretrained('gpt2')

# Sposta il modello sulla GPU se disponibile
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = model.to(device)

# Definisci dati di addestramento e iperparametri
train_data = [...] # I tuoi dati di addestramento
batch_size = 32
num_epochs = 10
learning_rate = 5e-5

# Definisci funzione di perdita e ottimizzatore
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=learning_rate)

# Ciclo di addestramento
for epoch in range(num_epochs):
for i in range(0, len(train_data), batch_size):
# Prepara sequenze di input e target
inputs, targets = train_data[i:i+batch_size]
inputs = tokenizer(inputs, return_tensors="pt", padding=True)
inputs = inputs.to(device)
targets = targets.to(device)

# Passo in avanti
outputs = model(**inputs, labels=targets)
loss = outputs.loss

# Passo indietro e ottimizzazione
optimizer.zero_grad()
loss.backward()
optimizer.step()

print(f'Epoca {epoch+1}/{num_epochs}, Perdita: {loss.item()}')

In questo esempio, dimostriamo l’addestramento di un modello GPT-2 utilizzando PyTorch e GPU CUDA-abilitate. Il modello viene caricato sulla GPU (se disponibile) e il ciclo di addestramento sfrutta il parallelismo delle GPU per eseguire efficienti passi in avanti e indietro, accelerando il processo di addestramento.

Librerie accelerate da CUDA per apprendimento profondo

Oltre alla piattaforma CUDA stessa, NVIDIA e la comunità open-source hanno sviluppato una serie di librerie accelerate da CUDA che consentono l’implementazione efficiente di modelli di apprendimento profondo, compresi i LLM. Queste librerie forniscono implementazioni ottimizzate di operazioni comuni, come moltiplicazioni di matrici, convoluzioni e funzioni di attivazione, consentendo agli sviluppatori di concentrarsi sull’architettura del modello e sul processo di addestramento piuttosto che sull’ottimizzazione a basso livello.

Una di queste librerie è cuDNN (CUDA Deep Neural Network library), che fornisce implementazioni altamente ottimizzate di routine standard utilizzate nelle reti neurali profonde. Sfruttando cuDNN, gli sviluppatori possono accelerare significativamente l’addestramento e l’inferenza dei loro modelli, raggiungendo guadagni di prestazioni di diverse volte rispetto alle implementazioni basate su CPU.


import torch
import torch.nn as nn
import torch.nn.functional as F
from torch.cuda.amp import autocast

class ResidualBlock(nn.Module):
def __init__(self, in_channels, out_channels, stride=1):
super().__init__()
self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
self.bn1 = nn.BatchNorm2d(out_channels)
self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
self.bn2 = nn.BatchNorm2d(out_channels)
self.shortcut = nn.Sequential()
if stride != 1 or in_channels != out_channels:
self.shortcut = nn.Sequential(
nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
nn.BatchNorm2d(out_channels))

def forward(self, x):
with autocast():
out = F.relu(self.bn1(self.conv1(x)))
out = self.bn2(self.conv2(out))
out += self.shortcut(x)
out = F.relu(out)
return out

In questo esempio, definiamo un blocco residuale per una rete neurale convoluzionale (CNN) utilizzando PyTorch. Il gestore di contesto autocast di PyTorch è utilizzato per abilitare l’addestramento a precisione mista, che può fornire guadagni di prestazioni significativi su GPU CUDA-abilitate mantenendo un’alta accuratezza. La funzione F.relu è ottimizzata da cuDNN, garantendo un’esecuzione efficiente sulle GPU.

Addestramento multi-GPU e distribuito per scalabilità

Mentre i LLM e i modelli di apprendimento profondo continuano a crescere in termini di dimensioni e complessità, le esigenze computazionali per l’addestramento di questi modelli aumentano anch’esse. Per affrontare questa sfida, ricercatori e sviluppatori hanno iniziato a utilizzare tecniche di addestramento multi-GPU e distribuito, che consentono loro di sfruttare la potenza di calcolo combinata di più GPU su più macchine.

CUDA e librerie associate, come NCCL (NVIDIA Collective Communications Library), forniscono primitive di comunicazione efficienti che consentono la trasferimento e la sincronizzazione dei dati tra più GPU, abilitando l’addestramento distribuito su una scala senza precedenti.


import torch.distributed as dist

from torch.nn.parallel import DistributedDataParallel as DDP

# Inizializza l'addestramento distribuito
dist.init_process_group(backend='nccl', init_method='...')
local_rank = dist.get_rank()
torch.cuda.set_device(local_rank)

# Crea modello e spostalo sulla GPU
model = MyModel().cuda()

# Avvolgi il modello con DDP
model = DDP(model, device_ids=[local_rank])

# Ciclo di addestramento (distribuito)
for epoch in range(num_epochs):
for data in train_loader:
inputs, targets = data
inputs = inputs.cuda(non_blocking=True)
targets = targets.cuda(non_blocking=True)

outputs = model(inputs)
loss = criterion(outputs, targets)

optimizer.zero_grad()
loss.backward()
optimizer.step()

In questo esempio, dimostriamo l’addestramento distribuito utilizzando il modulo DistributedDataParallel (DDP) di PyTorch. Il modello è avvolto in DDP, che gestisce automaticamente la parallelizzazione dei dati, la sincronizzazione dei gradienti e la comunicazione tra più GPU utilizzando NCCL. Questo approccio consente un’efficiente scalabilità del processo di addestramento su più macchine, consentendo ai ricercatori e agli sviluppatori di addestrare modelli più grandi e complessi in un tempo ragionevole.

Distribuzione di modelli di apprendimento profondo con CUDA

Mentre le GPU e CUDA sono state utilizzate principalmente per l’addestramento di modelli di apprendimento profondo, sono anche cruciali per l’inferenza efficiente e la distribuzione. Man mano che i modelli di apprendimento profondo diventano più complessi e richiedono più risorse, l’accelerazione della GPU è essenziale per raggiungere prestazioni in tempo reale negli ambienti di produzione.

NVIDIA’s TensorRT è un ottimizzatore e runtime di inferenza di apprendimento profondo ad alte prestazioni che fornisce basse latenze e alte prestazioni di inferenza su GPU CUDA-abilitate. TensorRT può ottimizzare e accelerare modelli addestrati in framework come TensorFlow, PyTorch e MXNet, consentendo una distribuzione efficiente su varie piattaforme, dalle sistemi embedded ai data center.


import tensorrt as trt

# Carica modello pre-addestrato
model = load_model(...)

# Crea motore TensorRT
logger = trt.Logger(trt.Logger.INFO)
builder = trt.Builder(logger)
network = builder.create_network()
parser = trt.OnnxParser(network, logger)

# Analizza e ottimizza il modello
success = parser.parse_from_file(model_path)
engine = builder.build_cuda_engine(network)

# Esegui inferenza sulla GPU
context = engine.create_execution_context()
inputs, outputs, bindings, stream = allocate_buffers(engine)

# Imposta dati di input ed esegui inferenza
set_input_data(inputs, input_data)
context.execute_async_v2(bindings=bindings, stream_handle=stream.ptr)

# Elabora output
# ...

In questo esempio, dimostriamo l’uso di TensorRT per la distribuzione di un modello di apprendimento profondo pre-addestrato su una GPU CUDA-abilitata. Il modello viene analizzato e ottimizzato da TensorRT, che genera un motore di inferenza altamente ottimizzato adatto per il modello e l’hardware specifico. Questo motore può quindi essere utilizzato per eseguire un’inferenza efficiente sulla GPU, sfruttando CUDA per il calcolo accelerato.

Conclusione

La combinazione di GPU e CUDA è stata strumentale nel guidare gli avanzamenti nei grandi modelli linguistici, nella visione artificiale, nel riconoscimento vocale e in vari altri domini dell’apprendimento profondo. Sfruttando le capacità di elaborazione parallela delle GPU e le librerie ottimizzate fornite da CUDA, ricercatori e sviluppatori possono addestrare e distribuire modelli sempre più complessi con alta efficienza.

Man mano che il campo dell’AI continua a evolversi, l’importanza delle GPU e di CUDA crescerà. Con hardware e software sempre più potenti, possiamo aspettarci di vedere ulteriori avanzamenti nello sviluppo e nella distribuzione di sistemi AI, spingendo i confini di ciò che è possibile.

Ho trascorso gli ultimi cinque anni immergendomi nel fascinante mondo del Machine Learning e del Deep Learning. La mia passione e la mia esperienza mi hanno portato a contribuire a oltre 50 progetti di ingegneria del software diversi, con un focus particolare su AI/ML. La mia curiosità continua mi ha anche portato verso l'elaborazione del linguaggio naturale, un campo che sono ansioso di esplorare ulteriormente.