URL: https://linuxfr.org/news/numba-0-14 Title: Numba 0.14 Authors: Antoine Benoît Sibaud Date: 2014年09月17日T22:51:02+02:00 License: CC By-SA Tags: python, calcul_scientifique, llvm, numpy et cpython Score: 42 Numba, l'optimiseur Python spécialisé dans le calcul numérique, est sorti en version 0.14. Numba est un compilateur juste-à-temps (JIT) pour Python, basé sur LLVM, permettant d'optimiser du code de calcul numérique, notamment basé sur Numpy. Il est compatible avec CPython 2.6, 2.7, 3.3 et 3.4. Des paquets binaires sont disponibles via Anaconda, la distribution de paquets binaires dédiée au calcul scientifique maintenue par Continuum Analytics, l'entreprise qui développe Numba. ---- [Numba - site officiel](http://numba.pydata.org/) [Miniconda - pour un déploiement minimal d'Anaconda](http://conda.pydata.org/miniconda.html) [Numba 0.14 - notes de sortie](http://numba.pydata.org/numba-doc/0.14/releases.html) [Page GitHub de Numba (code source, bug tracker)](https://github.com/numba/numba/) ---- Qu'est-ce que Numba ? ===================== Numba est un compilateur juste à temps pour CPython spécialisé dans l'optimisation de code scientifique. ... CPython ? ------------- CPython est l'implémentation par défaut (ou "de référence", en langage politiquement correct) de Python. Les autres implémentations s'appellent PyPy, Jython, etc. ... Spécialisé ? ---------------- Numba ne prétend pas être capable d'optimiser tous les types de code Python, ni même toutes les constructions du langage (même si cela n'est pas exclu comme objectif à long terme). Numba est capable d'optimiser les calculs numériques et scientifiques impliquant des entiers, des flottants, des complexes ; il est capable de reconnaître certaines types de données bien connus, comme les tableaux Numpy. La liste des fonctionnalités optimisables grandit évidemment de version en version, par exemple la version 0.14 supporte désormais les types `numpy.datetime64` et `numpy.timedelta64`, qui permettent de faire des calculs sur des séries temporelles. ... Juste à temps ? ------------------- Numba fonctionne lors de l'exécution de votre code Python. Il suffit d'apposer le décorateur "`@numba.jit`" à une fonction pour la faire optimiser par Numba (certains aiment prier pour qu'il arrive à l'optimiser). Il n'y a pas de phase de compilation séparée, ni de ligne de commande à lancer. Plateformes supportées ====================== Numba utilise LLVM, ce qui permet une portabilité relativement aisée. Actuellement, les systèmes sous Linux, OS X et Windows sont supportés. Côté matériel, x86, x86-64 sont supportés et il y a également un backend CUDA (avec des limitations). Un exemple ========== Partons de notre ami l'ensemble de Mandelbrot. Pour cela, posons la fonction suivante dans un fichier nommé `mandel.py` : ```python import numpy def mandelbrot(width, height): x_min, x_max = -2.0, 1.0 y_min, y_max = -1.0, 1.0 arr = numpy.zeros((height, width), dtype=int) xs = numpy.linspace(x_min, x_max, num=width) ys = numpy.linspace(y_min, y_max, num=height) max_iters = 20 for idx_x, x in enumerate(xs): for idx_y, y in enumerate(ys): c = complex(x, y) z = 0.0j for i in range(max_iters): z = z * z + c if z.real * z.real + z.imag * z.imag>= 4: # Hors de l'ensemble break else: # Dans l'ensemble arr[idx_y, idx_x] = 1 return arr ``` Cette fonction renvoie un tableau d'entiers Numpy indiquant si un point fait partie de l'ensemble de Mandelbrot (1) ou non (0). Maintenant, lançons un Python depuis le même répertoire : ```python>>> import mandel>>> print(mandel.mandelbrot(20, 15)) [[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0] [0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0] [0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0] [0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]] ``` Ouf, ça ressemble :-) Maintenant compilons cette même fonction avec Numba : ```python>>> from numba import jit>>> opt = jit(mandel.mandelbrot)>>> print(opt(20, 15)) [[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0] [0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0] [0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0] [0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 0 0 0 0] [0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 1 1 1 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]] ``` Et lançons un benchmark d'une scientificité rigoureuse sur un tableau de 200x200 : ```python>>> import timeit>>> timeit.timeit("mandel.mandelbrot(200, 200)", setup="import mandel", number=1) 0.20483311700081686>>> timeit.timeit("opt(200, 200)", setup="from __main__ import opt", number=1) 0.003343598000355996 ``` Sur ce cas d'usage d'une grande importance, Numba est ainsi 60 fois plus rapide que l'interpréteur CPython ! Principe de fonctionnement ========================== Numba est un optimiseur fonction par fonction. Il part de la fonction que vous décorez avec `numba.jit` et lance une inférence de types pour essayer d'assigner un type précis à chaque variable et valeur intermédiaire dans la fonction. Pour cela, il utilise des règles dédiées à chaque opérateur, fonction standard, etc. Pour définir les types de départ du processus d'inférence, il y a en réalité deux possibilités : * Dans l'utilisation de base de `numba.jit`, l'utilisateur ne passe pas de paramètres : c'est alors lors de l'appel de la fonction décorée que les types des arguments sont utilisés pour lancer le processus d'inférence (la compilation est ici paresseuse). * Dans une utilisation avancée, l'utilisateur peut décrire explicitement les types à l'entrée de la fonction (cela lui permet, par exemple, de choisir des flottants simple précision plutôt que double précision) ; dans ce cas, la compilation a lieu immédiatement. L'inférence de type est l'étage fondamental qui permet ensuite de produire du code travaillant sur des types bas niveau, plutôt qu'au niveau du modèle objet de Python, qui est beaucoup plus difficile à optimiser. Bien entendu, la chaîne de traitement (_pipeline_) est constituée de multiples étages : 1. décodage du _bytecode_ CPython 1. construction d'un graphe de flot de contrôle (CFG) 1. génération d'une représentation intermédiaire (IR) spécifique à Numba 1. inférence de types, produisant une détermination du type de chaque variable manipulée par la fonction 1. génération de code LLVM correspondant à l'exécution de l'IR sur les types déterminés précédemment 1. appel à LLVM pour la génération du code machine, et encapsulation du tout dans un objet dédié (_wrapper_) qui lance le code machine quand il est appelé Grâce à LLVM, Numba n'a pas à se charger des optimisations bas niveau (propagation de constantes, vectorisation SIMD, etc.) et peut se concentrer sur les traitements spécifiques au langage Python. Pour une présentation plus détaillée, il convient de lire la documentation (en anglais) : [architecture de Numba](http://numba.pydata.org/numba-doc/dev/developer/architecture.html). Limitations =========== À l'heure actuelle, plutôt que de se lancer dans une liste interminable de limitations, il est plus raisonnable de lister ce qui est supporté. Types supportés --------------- * les scalaires numériques, que ce soit les types Python (`int`, `float`, `complex`...) ou NumPy (`numpy.complex64`, etc.) * les booléens * les dates et intervalles de temps NumPy (`numpy.datetime64` et `numpy.timedelta64`) -- mais pas les types standard `datetime.datetime` et `datetime.timedelta` * les tuples des types ci-dessus * les tableaux NumPy des types ci-dessus Constructions supportées ------------------------ Numba supporte la plupart des constructions syntaxiques du langage, sauf le traitement des exceptions (`try... except`, etc.), les gestionnaires de contexte (`with`), les générateurs (`yield`) et quelques autres détails. Fonctions supportées -------------------- Numba supporte une grande partie des opérateurs numériques, des fonctions standard (notamment le module `math`), et certaines fonctions de NumPy. Il est également capable d'optimiser les appels à des fonctions externes via [ctypes](https://docs.python.org/3/library/ctypes.html) ou [cffi](http://cffi.readthedocs.org/). Différences sémantiques ----------------------- Le caractère volontaire (_opt-in_) de la compilation permet à Numba de présenter des différences sémantiques par rapport au langage Python. Je ne les listerai pas ici, mais une différence évidente a trait aux entiers : les entiers de Python sont de largeur arbitraire, ceux de Numba sont de largeur fixe (déterminée à l'inférence de types, ou forcée par l'utilisateur). Un dépassement lors d'opérations mathématiques entraîne simplement une troncation. Notons qu'une grande partie de ces différences reflète en réalité le comportement de NumPy (dont les entiers sont aussi à largeur fixe, par exemple). Numba et l'écosystème Python ============================ Le fait que Numba fonctionne au-dessus de CPython lui permet de s'intégrer facilement à l'écosystème existant. Comme on l'aura compris, l'intégration avec NumPy est également une fonctionnalité de premier plan. D'une manière générale, la stratégie de Continuum (cf. ci-dessous) est de maximiser les possibilités d'interaction entre les multiples briques de calcul scientifique disponibles pour Python. Statut du projet ================ Numba est supporté par Continuum Analytics, qui paye à cet effet plusieurs développeurs (dont l'auteur de cette dépêche). Le développement est en partie financé par des clients et des fonds de recherche américains. Nous recevons également des contributions extérieures. Bien entendu, le projet est libre (licence de type MIT). Contribuer ========== Numba est un projet jeune auquel manquent de nombreuses fonctionnalités ; il y a donc beaucoup d'opportunités de contribution. Le processus est [détaillé dans la documentation](http://numba.pydata.org/numba-doc/dev/developer/contributing.html). Les compétences nécessaires dépendent de ce à quoi vous vous intéressez :-) La majeure partie du code de Numba est en Python ; il y a quelques parties en C, mais on les évite assez facilement. Nul besoin d'être en expert en NumPy ou en LLVM pour commencer (je ne les connaissais presque pas). Au débotté, voici quelques directions possibles de contribution, par ordre de difficulté : * améliorer la documentation * améliorer le retour utilisateur, qui est actuellement assez fruste (messages d'erreur, informations sur la fonction compilée) * corriger des bugs (!) * ajouter le support de nouvelles fonctions (de la bibliothèque standard ou de NumPy) * ajouter le support de nouveaux types * ajouter le support de nouvelles constructions (comme la gestion des exceptions ou les générateurs)

AltStyle によって変換されたページ (->オリジナル) /