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.
Je vais le mentionner en premier.
―― 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.
.py
sans avoir à le créer dans des fichiers séparés.@ jit
.
―― Comme la gestion des types devient plus stricte, la partie qui fonctionnait avec "Nana" deviendra une erreur. En outre, il peut être nécessaire de trouver des moyens pour que numba effectue une inférence de type.
――Bien sûr, vous avez besoin de numba pour l'exécuter. Difficile d'installer numba dans certains environnements
――Cela semble facile dans l'environnement conda. Il existe de nombreux environnements dans lesquels vous pouvez entrer avec pip. L'Arch Linux que j'utilise est actuellement Python 3.8 et LLVM 9.0, qui ne sont pas tous deux pris en charge par numba pour le moment, j'ai donc abandonné la construction et utilisé l'environnement conda avec Docker.
――La compilation prend du temps, donc si vous la mettez dans les nuages sombres, elle aura l'effet inverse.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.
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.
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.
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.
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.
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.
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"
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.
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