Strumenti di IA 101
Configurazione di un training, fine-tuning e inferenza di LLM con NVIDIA GPUs e CUDA
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.












