Reading Time: 11 minutes

Points à retenir clés

  • Cupy est le bon choix lorsque vous souhaitez un remplacement de NumPy ou Scipy qui accélère les opérations de la baie avec un minimum de modifications de code. Il est optimisé pour les mathématiques en masse, les FFT et les opérations par élément.
  • Numba fonctionne mieux lorsque le goulot d’étranglement est constitué de boucles Python ou de fonctions numériques personnalisées. Son compilateur JIT transforme le python lent en code de vitesse quasi-c, et @cuda.jit vous permet d’écrire des noyaux CUDA qui s’exécutent directement sur le GPU.
  • CUDF est conçu pour les opérations de trame de données accélérées par GPU. Si votre flux de travail dépend de la fusion, du filtrage ou de l’agrégation de grands ensembles de données, CUDF vous donne une API de type Pandas qui s’exécute sur du matériel GPU.
  • Le choix ne s’exclut pas mutuellement. Les workflows Fast Scientific Python combinent souvent les trois : CUPY pour les maths Array, Numba pour les noyaux personnalisés et CUDF pour la lutte de données.

L’accélération des GPU n’est plus une préoccupation de niche pour les chercheurs en informatique à haute performance. Il est devenu pratique pour les simulations scientifiques basées sur Python, les pipelines d’analyse de données et les flux de travail d’apprentissage automatique à grande échelle.

La question n’est plus de savoir s’il faut utiliser l’accélération GPU. La question la plus utile est de savoir quelle bibliothèque GPU Python correspond à votre charge de travail.

Ce guide compare trois principales bibliothèques Python accélérées par GPU : CUPY, NUMBA et CUDF. Il explique leurs architectures, leurs caractéristiques de performance et leurs cas d’utilisation idéaux. Que vous exécutiez des simulations PDE, que vous traitiez des jeux de données expérimentaux ou que vous soyez des modèles de formation sur des clusters GPU, cette comparaison peut vous aider à choisir le bon outil pour chaque étape de votre flux de travail.

Pourquoi l’accélération du GPU est importante en Python scientifique

Avant de comparer les trois bibliothèques, il est utile de comprendre le changement que l’accélération du GPU apporte aux flux de travail Python.

Un CPU typique a un petit nombre de cœurs puissants. Les postes de travail modernes ou les nœuds HPC peuvent avoir plusieurs cœurs ou plusieurs dizaines de cœurs. Les GPU ont des milliers de cœurs plus simples optimisés pour des charges de travail massivement parallèles.

Lorsque le code Python peut être exprimé sous la forme d’opérations sur de grands tableaux ou des ensembles de données, les GPU peuvent fournir des accélérations majeures. Les avantages les plus importants apparaissent généralement dans les opérations matricielles, les FFT, les opérations élémentaires et les grandes charges de travail parallèles.

Le défi est que l’accélération du GPU ajoute de la complexité. Vous devez gérer la mémoire à travers la RAM CPU et la VRAM du GPU, réduire les transferts de données inutiles et tenir compte des contraintes matérielles.

CUPY, NUMBA et CUDF abordent chacun différemment cette complexité.

Cupy : le drop-in numpy pour les baies de GPU

Cupy est une bibliothèque open-source qui implémente un sous-ensemble d’API Nvidia et Scipy sur les plateformes NVIDIA CUDA et AMD ROCM. Sa valeur fondamentale est la simplicité. Vous pouvez souvent accélérer le code Numpy existant en remplaçant import numpy as np par import cupy as cp.

Comment fonctionne Cupie

Les tableaux CUPY, ou cupy.ndarray, sont stockés dans la mémoire GPU. Les tableaux NumPy vivent dans la RAM système. La plupart des opérations Numpy ont des équivalents CUPY qui s’exécutent sur le GPU.

import cupy as cp

# NumPy-style code with CuPy
a = cp.random.rand(1000, 1000)  # GPU memory
b = cp.random.rand(1000, 1000)
c = cp.dot(a, b)  # Matrix multiplication on GPU

Cupy est soutenu par des bibliothèques CUDA telles que Cublas, Cufft, Cusparse, Cusolver et Curand. Il utilise également des noyaux optimisés de bas niveau pour fournir de solides performances pour les charges de travail de calcul scientifique courants.

Points forts

  • Remplacement sans rendez-vous. CUPY nécessite souvent des changements de code minimes pour les bases de code lourdes.
  • Couverture API étendue. Il met en œuvre de nombreuses API Numpy et Scipy utilisées par les projets scientifiques Python.
  • Prise en charge du ROCM. Cupy peut fonctionner sur les plates-formes GPU AMD prises en charge ainsi que sur les plates-formes NVIDIA CUDA.
  • Prise en charge multi-GPU. cupyx.distributed fournit des primitives de communication collectives et pairs.
  • Fusion du noyau. Cupy peut combiner plusieurs opérations dans un seul noyau GPU pour réduire le trafic de mémoire.

Les faiblesses

  • Frais de transfert de données. Le déplacement des données entre la mémoire CPU et la mémoire GPU peut dominer le temps d’exécution si les transferts sont fréquents.
  • Moins de flexibilité pour les noyaux personnalisés. Cupy est le plus fort avec des opérations de baies prédéfinies, tandis que les noyaux hautement personnalisés peuvent nécessiter des travaux supplémentaires.
  • Contraintes de mémoire GPU. Les grands maillages 3D peuvent dépasser la mémoire du GPU lorsque les champs de solution, les coefficients et les tableaux temporaires sont stockés ensemble.

Quand choisir Cupy

Utilisez Cupy lorsque vous avez déjà un code NumPy-Heavy et que vous souhaitez une refactorisation minimale.

Les scénarios typiques incluent :

  • Opérations matricielles, algèbre linéaire et FFT.
  • Opérations de tableaux par élément sur de grands tableaux contigus.
  • Bases de code déjà structurées autour des API NumPy ou Scipy.

NUMBA : compilation JIT pour les noyaux et boucles personnalisés

NUMBA est un compilateur JIT open source qui traduit les fonctions Python en code machine optimisé lors de l’exécution à l’aide de LLVM. Contrairement à Cupy, qui se concentre sur les opérations de tableau, Numba accélère les boucles Python, les fonctions arithmétiques et numériques en les compilant dans un code machine efficace.

Comment fonctionne Numba

NUMBA utilise des décorateurs pour marquer les fonctions pour la compilation.

from numba import njit, prange
import numpy as np

@njit(parallel=True)
def compute_source_terms(phi_values, source_coeff, result):
    """Compute source terms in parallel across all cells."""
    for i in prange(phi_values.shape[0]):
        result[i] = source_coeff[i] * phi_values[i]**2
    return result

Pour l’exécution du GPU, NUMBA fournit @cuda.jit pour écrire des noyaux CUDA explicites.

from numba import cuda

@cuda.jit
def flux_kernel(phi, velocity, flux, nx, ny):
    """CUDA kernel computing fluxes in parallel."""
    i, j = cuda.grid(2)
    if i < nx and j < ny:
        idx = i * ny + j
        flux[idx] = velocity[idx] * phi[idx]

Points forts

  • Flexibilité maximale. @cuda.jit vous permet d’écrire des noyaux CUDA explicites avec un contrôle sur la mémoire et le parallélisme.
  • Fonctionne avec le flux de contrôle Python. NUMBA peut compiler des boucles JIT avec une logique conditionnelle.
  • Mode double CPU et GPU. Le code peut fonctionner sur CPU via @njit ou sur GPU via @cuda.jit.
  • De bonnes performances pour les charges de travail personnalisées. NUMBA peut approcher les performances CUDA écrites à la main lorsque le mouvement des données est minimisé.
  • Fonctionne avec les tableaux CUPY. Numba peut lancer des noyaux qui fonctionnent directement sur les données CUPY.

Les faiblesses

  • Courbe d’apprentissage plus raide. L’écriture de noyaux CUDA nécessite de comprendre la configuration de la grille, les dimensions de bloc, les déformations et la disposition de la mémoire.
  • Compilation JIT surcharge. La première exécution comprend le temps de compilation, qui peut aller de secondes à plus pour des fonctions complexes.
  • Divergence des branches. Les GPU exécutent des threads dans les déformations. La logique conditionnelle peut faire attendre certains threads pendant que d’autres s’exécutent.

Quand choisir Numba

Utilisez NUMBA lorsque le goulot d’étranglement est des boucles Python, des fonctions numériques personnalisées ou un parallélisme GPU fin.

Les scénarios typiques incluent :

  • Code de boucle lourd avec une logique conditionnelle complexe.
  • Algorithmes personnalisés qui ne correspondent pas proprement aux opérations de baies existantes.
  • Rechercher le code où le réglage des performances compte plus que la facilité d’utilisation.
  • Mise à l’échelle multi-GPU où le contrôle explicite sur l’affectation des appareils est important.

CUDF : Opérations DataFrame accélérées par GPU

CUDF est une bibliothèque Python GPU DataFrame construite sur le format de mémoire colonnaire Apache Arrow. Il fournit une API de type Pandas pour la manipulation des données accélérées par GPU, ce qui la rend familière aux ingénieurs de données et aux scientifiques des données.

Comment fonctionne CUDF

CUDF fait partie de l’écosystème NVIDIA Rapids et fournit une interface DataFrame pour les flux de travail accélérés par GPU.

import cudf

# GPU-accelerated DataFrame operations
df = cudf.DataFrame({'a': [1, 2, 3], 'b': ['x', 'y', 'z']})
result = df.groupby('a').sum()  # Runs on GPU

CUDF fournit également cudf.pandas, qui peut accélérer le code Pandas sur le GPU pour les opérations prises en charge et retomber sur Pandas lorsqu’une opération n’est pas prise en charge.

Points forts

  • API familière. L’interface de type pandas réduit la courbe d’apprentissage pour les scientifiques des données.
  • Format de mémoire colonnaire. L’architecture basée sur les flèches est optimisée pour les charges de travail analytiques.
  • Opérations lourdes de données. Les opérations de fusion, de filtrage, d’agrégation et de jointure peuvent être accélérées sur le GPU.
  • Intégration rapide. CUDF travaille avec d’autres bibliothèques Rapids telles que CuGragraph et CuSQL.
  • repli automatique. cudf.pandas peut retomber sur les pandas du CPU lorsque la prise en charge du GPU n’est pas disponible pour une opération spécifique.

Les faiblesses

  • portée étroite. CUDF se concentre sur les opérations DataFrame et n’est pas conçu pour les maths ou les noyaux personnalisés.
  • Dépendance des rapides. Cela nécessite la pile Rapids, qui peut être grande à installer.
  • contraintes matérielles. Les limites de mémoire GPU s’appliquent, en particulier pour les grandes jointures, les fusions et les ensembles de données larges.

Quand choisir CUDF

Utilisez CUDF lorsque votre flux de travail dépend des opérations de données lourdes.

Les scénarios typiques incluent :

  • Fusionner, filtrer ou regrouper de grands ensembles de données.
  • Créer des pipelines de données où l’accélération du GPU des opérations de trame de données est importante.
  • Transition de Pandas sans réécriture de la logique de traitement des données.
  • Analyse exploratoire des données à grande échelle.

Comparaison : CUPY VS NUMBA VS CUDF

Le tableau suivant résume les trois bibliothèques à travers les dimensions clés.

Dimensions cupide numba cudf
Cas d’utilisation principal Opérations de tableau en tant que remplacement de NumPy ou Scipy Kernels personnalisés et accélération de la boucle Opérations DataFrame en remplacement de Pandas
Style API Compatible avec Numpy et Scipy Décorateurs Python tels que @njit et @cuda.jit API DataFrame de type Pandas
Courbe d’apprentissage Faible si vous connaissez Numpy Moyenne parce que les concepts CUDA comptent Faible si vous connaissez les pandas
Modèle de mémoire GPU Tableaux GPU explicites Noyaux CUDA explicites Format de flèche en colonne
Prise en charge multi-GPU Oui, via cupyx.distributed et NCCL Oui, via des noyaux multi-GPU explicites Oui, grâce à l’écosystème Rapids
Portabilité CPU/GPU Non, principalement orienté GPU Oui, le code peut cibler le CPU ou le GPU Non, principalement orienté GPU
Support matériel NVIDIA CUDA et AMD ROCM NVIDIA CUDA et CPU Nvidia Cuda
Technologies clés Cublas, Cufft, Cusparse Compilateur JIT LLVM Flèche Apache et NCCL
le mieux pour Matrix Math, FFT et opérations par élément Algorithmes personnalisés et parallélisme de boucle Data Wrangling, jointures et agrégations

Comment combiner les trois flux de travail en un

Les workflows scientifiques les plus efficaces n’ont pas besoin de choisir une seule bibliothèque. Ils peuvent utiliser les trois de manière stratégique.

Un pipeline de recherche typique peut combiner CUPY, NUMBA et CUDF comme ceci :

  1. Ingestion et prétraitement des données avec CUDF. Chargez des ensembles de données expérimentales, nettoyez les données et effectuez des agrégations et des jointures initiaux.
  2. Simulation ou analyse avec CUPY. Déplacez les données prétraitées vers des tableaux GPU et exécutez des opérations matricielles, des FFT ou des calculs statistiques.
  3. Exécution du noyau personnalisée avec Numba. Si l’algorithme a des goulots d’étranglement lourds en boucle ou une logique personnalisée, compilez les sections JIT avec @cuda.jit.
  4. Agrégation de résultats avec CUDF. Recueillir les résultats dans les trames de données pour des rapports, une visualisation ou une analyse plus approfondie.

Cette approche hybride utilise chaque bibliothèque là où elle est la plus forte. Par exemple, vous pouvez utiliser CUPY pour la plupart des opérations de tableau, ajouter des noyaux Numba pour les boucles serrées que CuPy n’optimise pas bien et utiliser CUDF pour l’agrégation des résultats.

Des pièges courants et comment les éviter

1. Goulots d’étranglement de transfert de données

Le plus gros problème de performances du Python accéléré par le GPU est souvent le mouvement inutile des données entre le processeur et la mémoire du GPU. Chaque transfert sur PCIe est beaucoup plus lent que les opérations GPU internes.

Corrigez cela en profilant le code pour identifier les sections lourdes de transfert. Opérations par lots afin que les données se déplacent une fois vers le GPU, de nombreux calculs s’y déroulent et seuls les résultats finaux reviennent.

2. Épuisement de mémoire GPU

Les grandes simulations 3D peuvent dépasser rapidement la mémoire du GPU. Un maillage avec de nombreuses cellules peut avoir besoin de mémoire pour les champs de solution, les coefficients, les tableaux temporaires et les diagnostics.

Corrigez cela en utilisant float32 au lieu de float64 lorsque le compromis de précision est acceptable. Le profil avant et après le changement pour confirmer qu’une précision réduite ne compromet pas les résultats.

3. Divergence des branches dans les noyaux personnalisés

Les GPU exécutent des threads dans les déformations. Lorsque les threads divergent en raison de la logique conditionnelle, certains threads peuvent caler tandis que d’autres s’exécutent.

Corrigez cela en concevant des algorithmes qui minimisent la ramification. Dans la mesure du possible, restructurez les boucles pour éviter la logique conditionnelle à l’intérieur de sections parallèles étroites.

4. Sur-optimisation

L’accélération du GPU n’est pas toujours bénéfique. De petits problèmes, des opérations liées à la mémoire et des structures de données complexes peuvent effacer les avantages du parallélisme GPU.

Corrigez cela en profilant d’abord. Accélérer uniquement les opérations où les benchmarks affichent une accélération significative. Parfois, un simple remplacement de Cupy donne suffisamment de gain sans ajouter plus de complexité.

Quand choisir l’outil

Choisissez Cupy si :

  • Votre code est déjà NumPy ou Scipy Heavy.
  • Vous voulez une refactorisation minimale.
  • Votre goulot d’étranglement est constitué d’opérations de tableau telles que Matrix Math, FFT ou calculs par élément.
  • Vous avez besoin d’un support pour les plateformes NVIDIA et AMD GPU.

Choisissez Numba si :

  • Votre goulot d’étranglement est Python Loops ou des fonctions personnalisées.
  • Vous avez besoin d’un contrôle précis du parallélisme GPU.
  • Vous implémentez de nouveaux algorithmes à partir de zéro.
  • Vous avez besoin d’un code qui peut fonctionner à la fois sur le processeur et sur le GPU.

Choisissez CUDF si :

  • Votre charge de travail implique des dataframes, des fusions, des jointures ou des agrégations.
  • Vous quittez les pandas et vous souhaitez éviter de réécrire tout le pipeline.
  • Vous effectuez une exploration de données à grande échelle.
  • Vous avez besoin d’une distorsion de données accélérées par GPU.

Choisissez les trois si :

  • Vous êtes en train de construire un pipeline de recherche complet avec des phases d’ingestion, de simulation et d’analyse des données.
  • Vous souhaitez combiner des performances solides avec des API familières.
  • Votre flux de travail s’étend sur les mathématiques du tableau, les noyaux personnalisés et les opérations DataFrame.

Conclusion : Associez l’outil à la charge de travail

Il n’y a pas de meilleure bibliothèque Python accélérée par GPU. Cupy, Numba et CUDF résolvent différents problèmes.

  • Cupy est l’outil de style numpy pour accélérer les opérations de tableau avec un minimum de modifications de code.
  • Numba est le compilateur JIT flexible pour transformer des boucles lentes en noyaux hautes performances.
  • CUDF est la bibliothèque DataFrame qui apporte des opérations de style Pandas au matériel GPU.

Les flux de travail scientifiques les plus efficaces combinent stratégiquement les trois. Utilisez chaque outil là où il excelle. Comprendre les compromis entre la facilité d’utilisation, les performances, la flexibilité et les contraintes matérielles vous aide à créer des flux de travail rapides et maintenables.

Avant de démarrer l’accélération du GPU, profilez le code pour identifier les goulots d’étranglement réels. Ce n’est qu’alors que les gains de performances justifieront la complexité de la programmation compatible GPU.

Lectures complémentaires

Guides connexes

FAQ

À quel point Cupy est-il plus rapide que NumPy ?

CUPY peut accélérer considérablement les opérations de la baie en fonction de la taille et de la complexité de l’opération. Les gains les plus importants apparaissent généralement dans les opérations à forte intensité de calcul telles que la multiplication matricielle et les FFT. Le gain peut être plus petit pour les opérations liées à la mémoire.

Cupie peut-il courir sur les GPU AMD ?

Oui. CUPY prend en charge AMD ROCM sur du matériel compatible, permettant à CUPY de s’exécuter sur les plates-formes NVIDIA et GPU AMD prises en charge.

Numba est-il plus rapide que CUPY pour les calculs personnalisés ?

Cela dépend de la charge de travail. CUPY est souvent plus rapide pour les opérations de baies en bloc avec des noyaux optimisés. NUMBA peut être plus fort pour les boucles personnalisées, la logique conditionnelle ou les algorithmes qui ne correspondent pas parfaitement aux opérations de tableau existantes.

Quelle est la différence entre CUPY et CUDA ?

CUDA est le cadre de programmation de niveau inférieur. Cupy est une bibliothèque Python de haut niveau qui enveloppe la fonctionnalité GPU via une API compatible avec NumPy. Cupy donne une accélération GPU sans vous demander d’écrire directement des noyaux CUDA.

Quand dois-je utiliser CUDF au lieu de Pandas ?

Utilisez CUDF lorsque les opérations DataFrame sont un goulot d’étranglement et que le matériel GPU est disponible. Il est utile pour les grandes fusions, jointures, filtres et agrégations. Si l’ensemble de données est petit ou si le code n’a pas besoin d’accélération, Pandas peut être plus simple.

Prochaines étapes

Si vous envisagez une accélération GPU pour les flux de travail Scientific Python, suivez cette séquence :

  1. profil d’abord. Identifiez les opérations qui sont réellement lentes avant d’optimiser.
  2. Commencez petit. Essayez le modèle de remplacement sans rendez-vous de Cupy sur une seule section NumPy-Heavy.
  3. Benchmark. Comparez les temps d’exécution du CPU et du GPU avec des ensembles de données réalistes.
  4. Combinez les bibliothèques. Utilisez Cupy pour Array Math, Numba pour les noyaux personnalisés et CUDF pour les données.

Pour les équipes qui créent un logiciel de recherche avec des flux de travail Python accélérés par GPU, l’investissement dans la programmation compatible GPU peut réduire le temps de simulation, accélérer le traitement des données et prendre en charge des problèmes plus importants que les flux de travail uniquement.

Références