[PYTHON] Einführung in das Schreiben von Cython [Notizen]

28.08.2017: Der im Kommentar erwähnte Teil wurde korrigiert.

Überblick

Kürzlich habe ich versucht, durch die Implementierung einer langsamen Verarbeitung in Python in C mit Cython zu beschleunigen. Daher werde ich diese zusammenfassen, damit ich zurückblicken kann, wenn ich vergesse, wie es geht. ** Es werden nur super rudimentäre und oberflächliche Dinge geschrieben **

Was ist Cython?

Cython erkennt, dass es so ist, als würde man eine in C geschriebene Funktion vermitteln, damit sie von Python aus aufgerufen werden kann. Mit anderen Worten, es ist ein Bild, das Sie jeden guten Punkt verwenden können, indem Sie den Teil für langsame Ausführung in C implementieren und den anderen Teil einfach in Python zeichnen.

Wie installiert man

windows Gehen Sie zu dieser Site und laden Sie die entsprechende Version herunter. (Wenn der Teil von cp ○○ Python 3.6 ist, wählen Sie den Teil aus, der 36 ist.) Geben Sie an der Eingabeaufforderung "pip install the path of the downloaded file" ein, um die Installation zu starten.

Wenn Sie danach einen Fehler wie "Fehler: vcvarsall.bat" kann nicht gefunden werden, rufen Sie die folgende Referenzseite auf [Einstellungen zur Verwendung einer anderen Version von VC ++] Es wurde gelöst, indem auf / build-python-package-on-windows / # VC-2) verwiesen wurde.

Referenzseite https://www.regentechlog.com/2014/04/13/build-python-package-on-windows/

Mac, Ubuntu usw.

Ich denke, Sie können es mit $ pip install cython installieren.

Dateien, die zum Umschließen von C benötigt werden

-. c-Datei: Eine Datei, die die Implementierung in C-Sprache beschreibt

Was diesmal zu machen

Um zu erkennen, dass es schneller ist, verwenden wir diesmal den folgenden Code mit double for loop.

python_code.py


# -*-encode: utf-8-*-
import time

if __name__ == "__main__":
    start_t = time.time()

    arr_a = [i for i in range(1000)]
    arr_b = [i for i in range(1000)]

    res = 0
    for elem_a in arr_a:
        for elem_b in arr_b:
            res = res + elem_a + elem_b
    print(res)

    all_time = time.time() - start_t
    print("Execution time:{0} [sec]".format(all_time))

Wir finden nur die Summe der Summen aller Kombinationen der Arrays "arr_a" und "arr_b". Wenn Sie dies tun,

out[1]


999000000
Execution time:0.24517321586608887 [sec]

Es wird.

Inhalt in C-Sprache geschrieben

Python scheint also eine lange Zeit für die Schleife zu brauchen

for elem_a in arr_a:
        for elem_b in arr_b:
            res = res + elem_a + elem_b

Dieser Teil ist in der Sprache C implementiert. Die Header-Datei und der Quellcode lauten wie folgt.

cython_c_code.h


#ifndef CYTHON_CODE
#define CYTHON_CODE
int c_algo(int*, int*, int, int);
#endif

cython_c_code.c


#include "cython_c_code.h"

int c_algo(int *arr_a, int *arr_b, int size_a, int size_b){
    int res = 0;
    for(int i=0; i < size_a; i++){
        for(int j=0; j < size_b; j++){
            res = res + arr_a[i]+arr_b[j];
        }
    }
    return res;
}

Wie schreibe ich eine Pyx-Datei

Schreiben Sie die obige C-Funktion c_algo () in .pyx, damit sie in Python aufgerufen werden kann.

cython_pyx_code.pyx


cimport numpy as np

cdef extern from "cython_c_code.h":
    int c_algo(int *arr_a, int *arr_b, int size_a, int size_b)

def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
    return c_algo(&arr_a[0], &arr_b[0], len(arr_a), len(arr_b))

Der hier angezeigte cimport ist eine Anweisung zum Lesen der Cython-Version der Header-Datei. Mit anderen Worten, indem Sie "python cimport numpy as np" schreiben, können Sie Typen wie "np.ndarray" deklarieren. Abgesehen davon, wenn Sie auch eine Numpy-Funktion benötigen, benötigen Sie auch "Numpy importieren".

Beschreiben Sie als Nächstes die zu verwendende Funktion aus der C-Header-Datei.

cdef extern vom Namen der Header-Datei:
Zu verwendende Funktion

Beschreiben Sie auf diese Weise.

Beschreiben Sie abschließend die Funktion, die von der Python-Seite aufgerufen werden soll. Es wird in def wie Python beschrieben, aber der Typ wird im Argumentteil angegeben. Der Typ beim Empfang eines Numpy-Arrays als Argument ist "np.ndarray [Elementtyp, ndim = Anzahl der Dimensionen]". Wenn ein Array-Zeiger an eine C-Funktion übergeben wird, kann er auch mit & array name [0] übergeben werden.

Wie schreibe ich setup.py

setup.py


from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
from Cython.Build import cythonize

import numpy as np

sourcefiles = ['cython_pyx_code.pyx','cython_c_code.c']

setup(
    cmdclass = {'build_ext': build_ext},
    ext_modules = [Extension("cython_code", sourcefiles, include_dirs=[np.get_include()])],
)

Importieren Sie die erforderliche Bibliothek und schreiben Sie Folgendes in das Argument "ext_modules" von "setup ()". [Erweiterung (" Name dieser Bibliothek ", [zu verwendende Quelldateien], include_dirs = [Header der zu verwendenden Bibliothek])] Da wir dieses Mal numpy verwenden, übergeben Sie np.get_include () an include_dirs.

kompilieren

Kompilieren Sie mit $ python setup.py build_ext -i. Wenn alles gut geht, haben Sie ein Build-Verzeichnis und einen "Bibliotheksnamen.so" (".pyd" für Windows). Sie können es wie eine normale Python-Bibliothek importieren und verwenden.

Versuchen Sie, mit Python zu laufen

cython_py_code.py


# -*-encode: utf-8-*-

import time
import numpy as np
import cython_code

if __name__ == "__main__":
    start_t = time.time()

    arr_a = [i for i in range(1000)]
    arr_b = [i for i in range(1000)]

    res = cython_code.cy_algo(np.array(arr_a), np.array(arr_b))
    print(res)

    all_time = time.time() - start_t
    print("Execution time:{0} [sec]".format(all_time))

out[2]


999000000
Execution time:0.0010039806365966797 [sec]

Die Geschwindigkeit hat sich um das 245-fache verbessert.

Apropos

Sie können den Code auch direkt in die .pyx-Datei schreiben, indem Sie den Typ angeben.

cy_only.pyx


cimport numpy as np

def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
    cdef int res
    cdef int elem_a
    cdef int elem_b

    res = 0
    for elem_a in arr_a:
        for elem_b in arr_b:
            res = res + elem_a +elem_b
    return res

Alle auf diese Weise verwendeten Variablen werden durch "cdef type name variable name" definiert. Beachten Sie, dass sich die Ausführungsgeschwindigkeit verlangsamt, wenn Sie zunächst vergessen, "elem_a" und "elem_b" zu definieren. Wenn Sie dies kompilieren und von Python aus aufrufen,

out[3]


999000000
Execution time:0.10053086280822754 [sec]

Es ist ungefähr doppelt so schnell, aber es scheint langsamer zu sein als das Schreiben in C, da es einfach ist, wie Python zu schreiben.

Da im Kommentar darauf hingewiesen wurde, habe ich den Code wie folgt geändert.

cy_only.pyx


cimport numpy as np

def cy_algo(np.ndarray[int, ndim=1] arr_a, np.ndarray[int, ndim=1] arr_b):
    cdef int res = 0
    cdef size_t len_a = len(arr_a)
    cdef size_t len_b = len(arr_b)

    for i in range(len_a):
        for j in range(len_b):
            res = res + arr_a[i] +arr_b[j]
    return res

Dann,

out[4]


999000000
Execution time:0.0019919872283935547 [sec]

Die Geschwindigkeit war nahe an der in C geschriebenen. Cython Es stellte sich heraus, dass selbst solides Schreiben schneller wäre, wenn es richtig geschrieben würde.

schließlich

Ich fange gerade an, Cython zu berühren, und ich verstehe nur die Einführungsstufe, also habe ich vielleicht etwas Passendes geschrieben. Ich würde es begrüßen, wenn Sie in diesem Fall darauf hinweisen könnten. Es scheint, dass die Geschwindigkeit weiter verbessert wird, indem unnötige Optionen in setup.py deaktiviert werden. Eine Liste finden Sie unter hier. Wenn Sie es etwas besser verstehen können, kann ich diesen Artikel umschreiben, um das Lesen zu erleichtern.

Recommended Posts

Einführung in das Schreiben von Cython [Notizen]
Einführung in das maschinelle Lernen Schreiben von Notizen
Einführung in MQTT (Einführung)
Einführung in Scrapy (1)
Einführung in Scrapy (3)
Erste Schritte mit Supervisor
Einführung in Tkinter 1: Einführung
Einführung in PyQt
Einführung in Scrapy (2)
[Linux] Einführung in Linux
Einführung in Scrapy (4)
Einführung in discord.py (2)
Eine Einführung in Cython, ohne tief zu gehen
Einführung in Cython ohne tief zu gehen -2-
Einführung in Lightning Pytorch
Erste Schritte mit Web Scraping
Einführung in nichtparametrische Felder
Einführung in EV3 / MicroPython
Einführung in die Python-Sprache
Einführung in die TensorFlow-Bilderkennung
Einführung in OpenCV (Python) - (2)
Einführung in PyQt4 Teil 1
Einführung in die Abhängigkeitsinjektion
Einführung in Private Chainer
Einführung in das maschinelle Lernen
AOJ Einführung in die Programmierung Thema Nr. 1, Thema Nr. 2, Thema Nr. 3, Thema Nr. 4
Einführung in das elektronische Papiermodul
Einführung in den Wörterbuch-Suchalgorithmus
[Lernmemorandum] Einführung in vim
Einführung in PyTorch (1) Automatische Differenzierung
opencv-python Einführung in die Bildverarbeitung
Einführung in Python Django (2) Win
Einführung in Private TensorFlow
Eine Einführung in das maschinelle Lernen
[Einführung in cx_Oracle] Übersicht über cx_Oracle
Eine super Einführung in Linux
AOJ Einführung in die Programmierung Thema Nr. 7, Thema Nr. 8
Python-Notizen, die Sie bald vergessen sollten
Cython kommt zu AtCoder !!
Einführung in die Anomalieerkennung 1 Grundlagen
Einführung in RDB mit sqlalchemy Ⅰ
[Einführung in Systre] Fibonacci Retracement ♬
Einführung in die nichtlineare Optimierung (I)
Einführung in die serielle Kommunikation [Python]
AOJ Einführung in die Programmierung Thema Nr. 5, Thema Nr. 6
Einführung in Deep Learning ~ Lernregeln ~
[Einführung in Python] <Liste> [Bearbeiten: 22.02.2020]
Einführung in Python (Python-Version APG4b)
Eine Einführung in die Python-Programmierung
[Einführung in cx_Oracle] (8.) Version cx_Oracle 8.0
Einführung in discord.py (3) Verwenden von Stimme
Einführung in die Bayes'sche Optimierung
Tiefe Stärkung des Lernens 1 Einführung in die Stärkung des Lernens
Super Einführung in das maschinelle Lernen
Einführung in Ansible Teil In'Inventory '
Serie: Einführung in den Inhalt von cx_Oracle
[Einführung] Verwendung von open3d