Accélérez grossièrement Python avec numba

Une bibliothèque appelée numba rend relativement facile l'accélération du code Python. J'espère que vous pourrez l'accélérer en écrivant simplement from numba import jit et en écrivant @ jit sur la ligne avant la fonction que vous souhaitez accélérer.

Le mécanisme semble être que numba récupère le code de la machine virtuelle Python, le compile dans LLVM IR et utilise LLVM pour en faire du code natif. Lors de la première exécution, le processus de compilation s'exécute, donc il sera un peu plus lent, mais s'il s'agit d'un processus lourd, numba peut être plus rapide même compte tenu du temps de compilation.

Avantages et inconvénients

Je vais le mentionner en premier.

avantage

―― Dans certains cas, vous pouvez facilement accélérer le code sans le modifier. ――Même s'il y a une modification de code, il s'agit souvent d'une modification mineure.

Désavantage

Exemple

Voici quelques exemples qui fonctionnent très bien. Je ne sais pas, mais il y a des fonctions très lentes.

import sys
sys.setrecursionlimit(100000)

def ack(m, n):
    if m == 0:
        return n + 1
    if n == 0:
        return ack(m - 1, 1)
    return ack(m - 1, ack(m, n - 1))

Je vais mesurer le temps pendant un moment.

import time
from contextlib import contextmanager

@contextmanager
def timer():
    t = time.perf_counter()
    yield None
    print('Elapsed:', time.perf_counter() - t)

with timer():
    print(ack(3, 10))

8189 Elapsed: 10.270420542001375

Cela a pris 10 secondes.

Augmenter le nombre prendra plus de temps, mais je ne le recommande pas car cela prend vraiment du temps. En particulier, si vous augmentez de 3 à 4, vous ne finirez probablement pas avant de mourir, donc je ne le recommande pas du tout. Cette fonction est [Fonction Ackerman](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%83%E3%82%AB%E3%83%BC%E3%83%9E Il est connu sous le nom de% E3% 83% B3% E9% 96% A2% E6% 95% B0).

Accélérons cela avec numba.

from numba import jit

@jit
def ack(m, n):
    if m == 0:
        return n + 1
    if n == 0:
        return ack(m - 1, 1)
    return ack(m - 1, ack(m, n - 1))

#Première fois
with timer():
    print(ack(3, 10))

#Deuxième fois
with timer():
    print(ack(3, 10))

#Troisième fois
with timer():
    print(ack(3, 10))

8189 Elapsed: 0.7036043469997821 8189 Elapsed: 0.4371343919992796 8189 Elapsed: 0.4372558859977289

Ce qui a pris 10 secondes est passé à 0,7 seconde pour la première fois et à 0,4 seconde pour la seconde fois et les suivantes. Si cela se produit simplement en ajoutant une ligne, c'est vraiment une bonne affaire.

Si ce n'est pas plus rapide que tu ne le penses

Le mode objet peut être utilisé.

numba a le mode No Python et le mode Object, et une fois compilé en mode No Python, s'il échoue, il est compilé en mode Object. (Cependant, cette spécification disparaîtra dans le futur, il semble que seul le mode No Python par défaut, le mode Object est optionnel)

Le premier gère tous les types directement, tandis que le second frappe les objets Python à partir de l'API Python C, et le premier est plus rapide. En outre, ce dernier peut ne pas être en mesure de réécrire efficacement la boucle en code natif, tandis que le premier rendra la boucle plus efficace. (boucle-jitting)

Pour forcer le mode No Python, écrivez @jit (nopython = True) ou @ njit, mais cela provoque souvent des erreurs comme" Je ne connais pas le type ".

Fondamentalement,

Vous pouvez clarifier le type par une telle méthode.

Relativement facile à prendre en charge le mode No Python

Etc. sont recommandés. Sachez que ce que Python est bon est fait avec Python, et ce que Python n'est pas bon est fait avec numba.

Essayez de paralléliser

Avec @ jit (parallel = True), vous pouvez utiliser prange au lieu de range dans la boucle for (nécessite from numba import prange).

Les boucles écrites avec prange sont parallélisées.

Cache de résultats compilé

Avec @ jit (cache = True), vous pouvez écrire le résultat de la compilation dans un fichier cache et éviter les problèmes de compilation à chaque fois.

Utilisez fastmath

Il peut être utilisé avec @jit (fastmath = True). Activez fastmath, qui se trouve également dans gcc et clang. C'est une optimisation légèrement dangereuse qui accélère les calculs de flottant.

Utilisez CUDA

Ce n'est pas très facile, mais vous pouvez utiliser CUDA pour le moment. Si vous avez déjà utilisé CUDA, vous le découvrirez avec le code ci-dessous.

Personnellement, je pensais que Cupy serait bien si c'était le cas.

import numpy as np
from numba import cuda

@cuda.jit
def add(a, b, n):
    idx = cuda.threadIdx.x + cuda.blockIdx.x * cuda.blockDim.x
    if idx < n:
        a[idx] += b[idx]

N = 1000000
a_host = np.array(np.ones(N))
b_host = np.array(np.ones(N))
a_dev = cuda.to_device(a_host)
b_dev = cuda.to_device(b_host)

n_thread = 64
n_block = N // n_thread + 1

add[n_block, n_thread](a_dev,b_dev,N)

a_dev.copy_to_host(a_host)

print(a_host) # Expect: [2, 2, ..., 2]

Si vous vous fâchez de ne pas avoir libNVVM, soit vous n'avez pas installé CUDA (vous pouvez l'installer avec conda install cudatoolkit, etc.) ou vous devez définir des variables d'environnement.

Exemple de configuration dans Google Colab etc.:

import os
os.environ['NUMBAPRO_LIBDEVICE'] = "/usr/local/cuda-10.0/nvvm/libdevice"
os.environ['NUMBAPRO_NVVM'] = "/usr/local/cuda-10.0/nvvm/lib64/libnvvm.so"

Résumé

Vous pouvez utiliser numba pour accélérer approximativement votre code Python. J'ai vu comment l'utiliser facilement.

Je suis heureux que vous puissiez l'utiliser comme référence.

Les références

Le Document officiel n'est pas très long et est très utile si vous ne lisez que là où vous en avez besoin. Conseils de performance est particulièrement utile.

Pour les paramètres de variable d'environnement lors de l'utilisation de CUDA https://colab.research.google.com/github/cbernet/maldives/blob/master/numba/numba_cuda.ipynb Je l'ai mentionné.

Recommended Posts

Accélérez grossièrement Python avec numba
Numba pour accélérer en Python
Mesurer la vitesse WiFi avec Python
Remarques sur l'accélération du code Python avec Numba
Comment accélérer les calculs Python
Accélérer la compilation C / C ++ avec ccache
N'écrivez pas Python si vous voulez l'accélérer avec Python
[Python] Arrondissez avec juste l'opérateur
J'ai installé et utilisé Numba avec Python3.5
FizzBuzz en Python3
Grattage avec Python
Grattage avec Python
Python avec Go
Twilio avec Python
Intégrer avec Python
Jouez avec 2016-Python
AES256 avec python
Testé avec Python
python commence par ()
avec syntaxe (Python)
Bingo avec python
Zundokokiyoshi avec python
Excel avec Python
Micro-ordinateur avec Python
Cast avec python
Vitesse explosive avec Python (bouteille)! Développement d'API Web
[Python] Faites de votre mieux pour accélérer SQL Alchemy
J'ai essayé d'accélérer le code Python, y compris l'instruction if avec Numba et Cython
Communication série avec Python
Zip, décompressez avec python
Django 1.11 a démarré avec Python3.6
Python avec eclipse + PyDev.
Communication de socket avec Python
Analyse de données avec python 2
Grattage en Python (préparation)
Essayez de gratter avec Python.
Apprendre Python avec ChemTHEATER 03
Recherche séquentielle avec Python
"Orienté objet" appris avec python
Manipuler yaml avec python
Résolvez AtCoder 167 avec python
Communication série avec python
[Python] Utiliser JSON avec Python
Apprendre Python avec ChemTHEATER 05-1
Apprenez Python avec ChemTHEATER
Exécutez prepDE.py avec python3
Python ~ Apprentissage rapide de la grammaire ~
1.1 Premiers pas avec Python
Collecter des tweets avec Python
Binarisation avec OpenCV / Python
3. 3. Programmation IA avec Python
Méthode Kernel avec Python
Vitesse de notation d'inclusion de liste en Python
Grattage avec Python + PhantomJS
Conduisez WebDriver avec python
[Python] Redirection avec CGIHTTPServer
Analyse vocale par python
Pensez à yaml avec python
Utiliser Kinesis avec Python