Eine Bibliothek namens numba macht es relativ einfach, Python-Code zu beschleunigen. Hoffentlich können Sie es beschleunigen, indem Sie einfach "from numba import jit" und "@ jit" in die Zeile vor der Funktion schreiben, die Sie beschleunigen möchten.
Der Mechanismus scheint zu sein, dass numba den Code der virtuellen Python-Maschine erhält, ihn in LLVM IR kompiliert und LLVM verwendet, um ihn zu nativem Code zu machen. Bei der ersten Ausführung wird der Kompilierungsprozess ausgeführt, sodass er etwas langsamer ist. Wenn es sich jedoch um einen schweren Prozess handelt, kann numba auch unter Berücksichtigung der Kompilierungszeit schneller sein.
Ich werde es zuerst erwähnen.
――In einigen Fällen können Sie problemlos beschleunigen, ohne den Code selbst zu ändern. ――Selbst eine Codeänderung vorliegt, handelt es sich häufig um eine geringfügige Änderung.
.py
-Datei verwenden, ohne es mühsam in separate Dateien erstellen zu müssen.Hier sind einige Beispiele, die sehr gut funktionieren. Ich weiß es nicht, aber es gibt einige sehr langsame Funktionen.
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))
Ich werde die Zeit für einen Moment messen.
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
Es dauerte 10 Sekunden.
Das Erhöhen der Anzahl wird länger dauern, aber ich empfehle es nicht, weil es wirklich Zeit braucht. Insbesondere wenn Sie 3 auf 4 erhöhen, werden Sie wahrscheinlich nicht fertig sein, bis Sie sterben, also empfehle ich es überhaupt nicht. Diese Funktion ist [Ackerman-Funktion](https://ja.wikipedia.org/wiki/%E3%82%A2%E3%83%83%E3%82%AB%E3%83%BC%E3%83%9E Es ist bekannt als% E3% 83% B3% E9% 96% A2% E6% 95% B0).
Lassen Sie uns dies mit numba beschleunigen.
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))
#Erstes Mal
with timer():
print(ack(3, 10))
#Zweites Mal
with timer():
print(ack(3, 10))
#Drittes Mal
with timer():
print(ack(3, 10))
8189 Elapsed: 0.7036043469997821 8189 Elapsed: 0.4371343919992796 8189 Elapsed: 0.4372558859977289
Was 10 Sekunden dauerte, ist zum ersten Mal auf 0,7 Sekunden und zum zweiten und nachfolgenden Mal auf 0,4 Sekunden geschrumpft. Wenn dies nur durch Hinzufügen einer Zeile geschieht, ist dies wirklich ein gutes Geschäft.
Der Objektmodus kann verwendet werden.
numba hat den No Python-Modus und den Object-Modus. Wenn es einmal im No Python-Modus kompiliert wurde und fehlschlägt, wird es im Object-Modus kompiliert. (Diese Spezifikation wird jedoch in Zukunft verschwinden. Es scheint, dass standardmäßig nur kein Python-Modus verfügbar ist. Der Objektmodus ist optional.)
Ersteres behandelt alle Typen direkt, während letzteres Python-Objekte über die Python C-API trifft und ersteres schneller ist. Darüber hinaus kann Letzteres die Schleife möglicherweise nicht effizient in nativen Code umschreiben, während Ersteres die Schleife effizienter macht. (Loop-Jitting)
Um den No Python-Modus zu erzwingen, schreiben Sie "@jit (nopython = True)" oder "@ njit". Dies führt jedoch häufig zu Fehlern wie "Ich kenne den Typ nicht".
Grundsätzlich,
Sie können den Typ mit einer solchen Methode klären.
--Schneiden Sie nur den schweren Berechnungsteil für eine andere Funktion aus und lassen Sie ihn numba entsprechen ――Selbst wenn Sie das Teil ausschneiden, das den Typ durcheinander bringt oder es dem Objekt zuweist, sollten Sie darüber nachdenken, es zu löschen. --numba Überlegen Sie, wie Sie dies mit numba in Form einer Vor- oder Nachbearbeitung des entsprechenden Teils vermeiden können
Usw. werden empfohlen. Seien Sie sich bewusst, dass das, was Python kann, mit Python gemacht wird und was Python nicht kann, mit numba.
Mit "@ jit (parallel = True)" können Sie "prange" anstelle von "range" in der for-Schleife verwenden (erfordert "from numba import prange").
Mit prange
geschriebene Schleifen werden parallelisiert.
Mit @ jit (cache = True)
können Sie das Kompilierungsergebnis in eine Cache-Datei schreiben und die Probleme beim Kompilieren jedes Mal vermeiden.
fastmath
Es kann mit @jit (fastmath = True)
verwendet werden.
Aktivieren Sie Fastmath, das auch in gcc und clang enthalten ist. Es ist eine etwas gefährliche Optimierung, die Float-Berechnungen beschleunigt.
Es ist nicht sehr einfach, aber Sie können CUDA vorerst verwenden. Wenn Sie CUDA bereits verwendet haben, erfahren Sie dies anhand des folgenden Codes.
Persönlich dachte ich, dass Cupy in Ordnung wäre, wenn dies der Fall wäre.
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]
Wenn Sie wütend werden, dass Sie nicht "libNVVM" haben, haben Sie entweder CUDA nicht installiert (Sie können es mit "conda install cudatoolkit" usw. installieren) oder Sie müssen Umgebungsvariablen festlegen.
Beispiel in Google Colab usw .:
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"
Sie können numba verwenden, um Ihren Python-Code grob zu beschleunigen. Ich habe gesehen, wie man es leicht benutzt.
Ich bin froh, wenn Sie es als Referenz verwenden können.
Das offizielle Dokument ist nicht sehr lang und sehr hilfreich, wenn Sie nur dort lesen, wo Sie es benötigen. Leistungstipps ist besonders nützlich.
Für Umgebungsvariableneinstellungen bei Verwendung von CUDA https://colab.research.google.com/github/cbernet/maldives/blob/master/numba/numba_cuda.ipynb Ich bezog mich auf.
Recommended Posts