Tutorial NVIDIA cuTile Python: kernel GPU tiled per vettori e matrici in Colab
NVIDIA cuTile Python è un’interfaccia di programmazione tile-based che permette di scrivere kernel CUDA direttamente in Python. In questo tutorial si parte dalla configurazione dell’ambiente Colab, si verificano GPU, driver, CUDA e installazione di cuTile, e poi si costruiscono tre esempi pratici: addizione vettoriale, addizione matriciale e moltiplicazione matriciale. Il tutto con un fallback PyTorch, così il notebook funziona anche se Colab non soddisfa i requisiti minimi di cuTile.
Installazione e diagnostica in Colab
Il primo passo è installare le dipendenze Python: torch, numpy, pandas, matplotlib e il pacchetto cuda-tile[tileiras] da PyPI. Dopo aver importato i moduli, si esegue una diagnostica del runtime: si controlla che PyTorch veda CUDA, si recupera il nome e la compute capability della GPU, e si parsa la versione del driver NVIDIA. Se il driver è almeno R580, CUDA è disponibile e l’import di cuda.tile funziona, cuTile è abilitato. Altrimenti, il notebook prosegue con PyTorch.
Nel tutorial, la variabile likely_runtime_ok decide se eseguire i kernel cuTile veri o usare il fallback. Le funzioni helper sincronizzano la GPU, misurano i tempi su più ripetizioni e verificano la correttezza con torch.testing.assert_close.
I kernel cuTile: vettori, matrici e matmul
Se cuda.tile è importabile, vengono definiti quattro kernel decorati con @ct.kernel:
- cutile_vec_add_direct_kernel: carica due tile vettoriali con
ct.load, li somma e li salva. Usact.bid(0)per ottenere l’indice del blocco. - cutile_vec_add_gather_kernel: invece di
ct.load, usact.gathercon offset calcolati dabid * TILE + arange. I due kernel sono funzionalmente identici per addizione vettoriale. - cutile_matrix_add_gather_kernel: per matrici 2D, usa due bid (riga e colonna), genera gli indici con broadcasting e applica gather/scatter.
- cutile_matmul_kernel: implementa la moltiplicazione matrice per matrice con accumulo tile per tile. Itera lungo la dimensione K, carica i tile di A e B (con padding zero per i bordi), li moltiplica con
ct.mmae accumula, poi converte il risultato nel dtype di output e lo salva.
I kernel sono avvolti in funzioni wrapper che, se l’ambiente è compatibile, lanciano il kernel su una griglia di blocchi calcolata dalle dimensioni degli input, altrimenti eseguono l’equivalente PyTorch.
L’approccio tile-based permette di scomporre operazioni su grandi tensori in blocchi piccoli e regolari, ottimizzando l’uso della memoria condivisa e il parallelismo delle GPU moderne.
