7 · Les bibliothèques NVIDIA¶
Ce qu'il ne faut jamais réécrire. Ce chapitre est un catalogue raisonné : pour chaque bibliothèque, ce qu'elle fait, quand l'utiliser, et ses pièges.
7.1 Le principe¶
La règle de base
Avant d'écrire un noyau, vérifiez qu'il n'existe pas. Les bibliothèques NVIDIA représentent des années-personnes d'optimisation, sont réglées pour chaque architecture, et sont mises à jour à chaque génération.
Le corollaire : si votre opération est standard et que vous êtes 5× plus lent qu'une bibliothèque, ce n'est pas que votre code est mauvais — c'est que vous n'auriez pas dû l'écrire.
7.2 Algèbre linéaire¶
cuBLAS¶
L'implémentation BLAS de référence.
cublasHandle_t handle;
cublasCreate(&handle);
cublasGemmEx(handle, CUBLAS_OP_N, CUBLAS_OP_N,
m, n, k, &alpha,
A, CUDA_R_16BF, lda,
B, CUDA_R_16BF, ldb, &beta,
C, CUDA_R_32F, ldc,
CUBLAS_COMPUTE_32F, CUBLAS_GEMM_DEFAULT_TENSOR_OP);
Points d'attention :
cublasLtest l'API moderne, plus flexible : elle permet de choisir un algorithme, de fusionner un épilogue (biais, GELU, ReLU), et de gérer les formats FP8 avec échelle ;- cuBLAS est column-major par héritage Fortran. Avec des tenseurs row-major (PyTorch, NumPy), on utilise l'identité \((\mathbf{A}\mathbf{B})^\top = \mathbf{B}^\top\mathbf{A}^\top\) pour éviter une transposition ;
- CUDA 13.1 apporte 2 à 6× sur Blackwell en BF16, FP8 et formats à échelle par blocs, et ajoute le support de la GEMM groupée — décisif pour les MoE.
cuSOLVER, cuSPARSE¶
Factorisations (LU, QR, Cholesky), valeurs propres, systèmes linéaires denses (cuSOLVER) ou creux (cuSPARSE).
Point d'attention : les performances sur matrices creuses dépendent énormément du format de stockage (CSR, COO, BSR, ELL) et de la structure de la matrice. Un mauvais choix de format coûte un ordre de grandeur.
cuTENSOR¶
Contractions de tenseurs généralisées, permutations, réductions. Pertinent en chimie quantique, en physique et pour les réseaux de tenseurs.
7.3 Réseaux de neurones¶
cuDNN¶
Convolutions, normalisations, activations, pooling, RNN, et l'attention (fused multi-head attention).
Le mécanisme important : cuDNN dispose de plusieurs algorithmes par opération et choisit selon les dimensions. En PyTorch :
torch.backends.cudnn.benchmark = True # mesure et choisit au premier appel
À activer si vos formes sont stables. Sinon, chaque nouvelle forme déclenche une phase de mesure coûteuse.
cuDNN contre FlashAttention
Les deux implémentent l'attention. FlashAttention-4 mesure 1,3× plus rapide que cuDNN 9.13 sur B200 (1 605 TFLOPS contre ~1 235). L'écart n'est pas énorme, ce qui témoigne du niveau de cuDNN.
En pratique : essayez les deux, mesurez sur vos formes.
TensorRT et TensorRT-LLM¶
Compilateurs d'inférence. TensorRT prend un graphe (ONNX ou autre), fusionne, sélectionne les noyaux, quantifie, et produit un moteur optimisé.
TensorRT-LLM se spécialise sur les modèles de langage : paged attention, in-flight batching, quantification, décodage spéculatif.
Point notable pour la partie 8 : Ada-MK s'intègre à TensorRT-LLM sous forme de greffon, ce qui permet de combiner un moteur classique haut débit pour le prefill et un megakernel basse latence pour le décodage.
7.4 Primitives parallèles : CCCL¶
CCCL (CUDA Core Compute Libraries) regroupe trois bibliothèques historiquement séparées.
| Composant | Niveau | Contenu |
|---|---|---|
| Thrust | haut | algorithmes à la STL : sort, reduce, transform, scan |
| CUB | moyen | primitives par niveau : device, block, warp |
| libcu++ | bas | cuda::std::, cuda::atomic, cuda::barrier, cuda::pipeline |
// Thrust : simple
thrust::device_vector<float> v(n);
float s = thrust::reduce(v.begin(), v.end());
// CUB : contrôle du tampon temporaire, plus rapide
void* d_temp = nullptr; size_t temp_bytes = 0;
cub::DeviceReduce::Sum(d_temp, temp_bytes, d_in, d_out, n);
cudaMalloc(&d_temp, temp_bytes);
cub::DeviceReduce::Sum(d_temp, temp_bytes, d_in, d_out, n);
// CUB au niveau du bloc, dans votre propre noyau
using BlockReduce = cub::BlockReduce<float, 256>;
__shared__ typename BlockReduce::TempStorage stockage;
float somme = BlockReduce(stockage).Sum(ma_valeur);
Ce que CUB apporte
cub::DeviceRadixSort trie des milliards de clés à la bande passante
mémoire. cub::DeviceScan fait un scan au prix d'une copie grâce au
decoupled look-back. Ce sont des algorithmes non triviaux que personne ne
devrait réimplémenter.
CUDA 13.1 simplifie les APIs CUB en une seule phase (plus besoin du double appel pour dimensionner le tampon) et ajoute des réductions flottantes déterministes.
7.5 Transformées et signal¶
| Bibliothèque | Contenu |
|---|---|
| cuFFT | transformées de Fourier 1D à 3D, réelles et complexes |
| cuFFTDx | FFT à l'intérieur d'un noyau (device extension), fusionnable |
| NPP | primitives de traitement d'image (filtres, transformations, couleurs) |
| nvJPEG | décodage JPEG accéléré |
| CV-CUDA | opérations de vision par ordinateur pour les pipelines d'IA |
cuFFTDx mérite l'attention : il permet d'exécuter une FFT dans votre noyau, sans repasser par la mémoire globale. C'est la même logique de fusion que partout ailleurs, appliquée aux transformées.
7.6 Données et bases de données¶
RAPIDS est une suite d'analyse de données sur GPU :
| Composant | Équivalent CPU |
|---|---|
| cuDF | pandas |
| cuML | scikit-learn |
| cuGraph | NetworkX |
| cuSpatial | GeoPandas |
| cuVS | recherche vectorielle (index CAGRA, IVF-PQ) |
import cudf
df = cudf.read_parquet("gros_fichier.parquet")
resultat = df.groupby("cle").agg({"valeur": "sum"})
Accélérations typiques de 10 à 50× sur des jointures et agrégations de gros volumes, à condition que les données tiennent en VRAM — la contrainte dominante.
Depuis 2023, cudf.pandas permet d'accélérer du code pandas existant sans le
modifier, avec repli automatique sur le CPU.
7.7 Communication multi-GPU¶
NCCL¶
La bibliothèque de collectives : AllReduce, AllGather, ReduceScatter,
Broadcast, AllToAll. Elle détecte la topologie (NVLink, NVSwitch, PCIe,
InfiniBand) et choisit les algorithmes (anneau, arbre) en conséquence.
C'est ce qu'utilisent PyTorch DDP/FSDP, DeepSpeed et Megatron.
NVSHMEM¶
Un modèle PGAS (Partitioned Global Address Space) : chaque GPU expose une
mémoire dite symétrique que les autres peuvent lire et écrire par des
opérations unilatérales (put, get, atomiques), depuis l'intérieur d'un
noyau.
__global__ void noyau() {
// Écrire directement dans la mémoire d'un GPU distant, depuis le noyau
nvshmem_float_put(dest, source, nelems, pe_distant);
}
C'est ce qui rend possible le recouvrement calcul/communication à grain fin — et c'est la brique sur laquelle repose DeepEP, la bibliothèque de DeepSeek pour les MoE distribués. Notez toutefois que DeepEP V2 utilise par défaut un back-end NCCL (« Gin ») et ne dépend plus de NVSHMEM que pour des chemins hérités.
Mirage MPK utilise NVSHMEM pour la communication inter-GPU à l'intérieur de son megakernel.
7.8 Le tableau récapitulatif¶
| Besoin | Bibliothèque |
|---|---|
| GEMM | cuBLAS / cuBLASLt |
| GEMM avec épilogue custom | CUTLASS |
| GEMM groupée (MoE) | cuBLAS (13.1+) ou CUTLASS |
| Convolution | cuDNN |
| Attention | FlashAttention, FlashInfer, cuDNN |
| Tri, scan, réduction | CUB / Thrust |
| FFT | cuFFT, cuFFTDx |
| Algèbre creuse | cuSPARSE |
| Factorisations | cuSOLVER |
| Traitement d'image | NPP, CV-CUDA |
| DataFrames, ML classique | RAPIDS |
| Recherche vectorielle | cuVS |
| Collectives | NCCL |
| Communication dans le noyau | NVSHMEM |
| Inférence LLM | TensorRT-LLM, vLLM, SGLang |
| Atomiques, barrières, pipelines | libcu++ |
Résumé du chapitre¶
À retenir
- Ne réécrivez pas ce qui existe. Ces bibliothèques sont réglées par architecture et mises à jour à chaque génération.
- cuBLAS est column-major ; utilisez l'identité de transposition avec des tenseurs row-major. cuBLASLt permet l'épilogue fusionné et la GEMM groupée.
- CCCL = Thrust (haut) + CUB (moyen) + libcu++ (bas). CUB au niveau du bloc s'utilise dans vos propres noyaux.
torch.backends.cudnn.benchmark = Trueseulement si vos formes sont stables.- NCCL pour les collectives, NVSHMEM pour la communication émise depuis l'intérieur d'un noyau — la brique des megakernels multi-GPU.
- Écrivez un noyau quand votre opération est inhabituelle, pas quand elle est standard.
Vérifiez que vous avez compris¶
Pourquoi cuBLAS est-il column-major alors que tout le monde utilise du row-major ?
Héritage du BLAS Fortran des années 1970, dont cuBLAS reprend l'interface pour la compatibilité.
En pratique, on exploite l'identité :
Une matrice row-major \(M \times N\) est exactement une matrice column-major \(N \times M\) transposée. Il suffit donc d'échanger les opérandes et les dimensions dans l'appel, sans aucune copie. C'est ce que fait PyTorch en interne.
Votre pipeline RAPIDS est plus lent que pandas. Causes possibles ?
Quatre, par ordre de fréquence :
- Le volume est trop petit. En dessous de quelques centaines de mégaoctets, le transfert PCIe et le lancement des noyaux dominent.
- Les données font des allers-retours. Chaque
.to_pandas()ou.to_arrow()coûte un transfert PCIe complet. - L'opération est mal supportée et retombe silencieusement sur le CPU
(fréquent avec
cudf.pandas). - Les chaînes de caractères. Le traitement de chaînes de longueur variable est le point faible structurel du GPU : accès irréguliers, divergence, indirections.
Quand NVSHMEM plutôt que NCCL ?
NCCL quand la communication est une phase distincte du calcul :
un AllReduce après le backward, un AllGather avant une couche. C'est
optimisé, robuste, et l'API est simple.
NVSHMEM quand la communication doit être entrelacée avec le calcul à l'intérieur d'un noyau : envoyer les premiers résultats pendant que les suivants se calculent. Cela permet un recouvrement impossible avec des collectives à granularité de noyau.
C'est exactement l'usage des megakernels multi-GPU : MPK, qui atteint 1,1-1,4× sur 8 H100 contre SGLang/vLLM, s'appuie sur NVSHMEM pour « maximiser le recouvrement du calcul, du chargement de données et de la communication inter-GPU entre les couches ».
Chapitre suivant : 8 · AMD, HIP et ROCm