Συζήτηση
Γεια χαρά, Επισκέπτης
Όνομα χρήστη: Κωδικός: Να με θυμάσαι

ΘΕΜΑ: Cython + Numpy arrays

Cython + Numpy arrays 12 Χρόνια 10 Μήνες πριν #1518

  • pmav99
  • Το Άβαταρ του/της pmav99
  • Αποσυνδεμένος
  • Author
  • Δημοσιεύσεις: 684
  • Ληφθείσες Ευχαριστίες 111
Ο πιο εύχρηστος τρόπος για να επιταχύνουμε κώδικα Python μέσω του Cython είναι το λεγόμενο pure python mode. Το βασικότερο του πλεονέκτημα είναι ότι δεν κάνουμε καμιά αλλαγή στο αρχείο *.py

Η διαδικασία είναι η εξής:
  1. Γράφουμε κανονικά το πρόγραμμα μας σε python (tests, documentation κτλ)
  2. Γράφουμε ένα αρχείο με το ίδιο filename με το αρχείο *.py, με κατάληξη όμως *.pxd. Στο αρχείο αυτό γίνονται οι δηλώσεις των τύπων του μεταβλητών και των συναρτήσεων/κλάσεων του κυρίως προγράμματος.
  3. Γράφουμε ένα αρχείο setup.py το οποίο διαβάζοντας τα αρχεία *.py και *.pxd, παράγει το αντίστοιχο αρχείο *.c, και το κάνει compile παράγοντας ένα αρχείο *.so
  4. Κάνουμε import το αρχείο *.so και απολαμβάνουμε την ταχύτητα της C !!! Τα αρχεία *.so γίνονται import πριν από τα αρχεία *.pyc.
Προβλήματα μπορεί να συναντήσουμε στο βήμα 3. Εν ολίγοις πρέπει η εντολή `cython filename.py` να παράγει το αρχείο `filename.c` χωρίς προβλήματα και το αρχείο αυτό να γίνεται compile κανονικά (link τις βιβλιοθήκες κτλ). Αν βρείτε προβλήματα, ρωτήστε αλλά μη ξεχνάτε google is your friend.

Το άλλο σημείο που χρειάζεται προσοχή είναι οι τύποι των μεταβλητών που θα δηλώσουμε. Στο αρχείο pxd οι τύποι είναι οι τύποι της C ενώ θέλει προσοχή τα δεδομένα που δίνουμε στη συνάρτηση να είναι του τύπου που αυτή περιμένει (βοηθάει να κάνουμε δηλαδή και κανένα assert type(object) is ...)

ΠΑΡΑΔΕΙΓΜΑ

Γράφουμε μία συνάρτηση για τον υπολογισμό του εμβαδού μιας περιοχής που ορίζεται από σημεία (x, y). Χρησιμοποιούμε ΑΥΤΟΝ τον τύπο. (μάλλον μπορεί να γραφεί και πολύ καλύτερα χρησιμοποιώντας διάφορα κόλπα του numpy, αλλά για το παράδειγμα εδώ αρκεί αυτό).

Βήμα 1ο - Αρχείο area.py
from __future__ import division
 
def calc_area(x, y):
    """x, y must be numpy arrays!"""
    area = 0
    for i in range(-1, len(x) - 1):
        area += x[i] * y[i+1] - x[i+1] * y[i]
    return abs(area) / 2
Βήμα 2ο - Αρχείο area.pxd
cimport cython
cimport numpy
 
@cython.locals(area = double,
               i = int)
cpdef calc_area(numpy.ndarray[double, ndim=1] a,
                numpy.ndarray[double, ndim=1] b)
Βήμα 3ο - Αρχείο setup.py
import sys
 
# setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
import numpy
 
# make setup build extension modules in place
sys.argv.append("build_ext")
sys.argv.append("--inplace")
 
# for notes on compiler flags see:
# http://docs.python.org/install/index.html
setup(
    cmdclass = {"build_ext": build_ext},
    include_dirs = [numpy.get_include()],    # Find the numpy libraries
    ext_modules = [Extension("area",
                             ["area.py"],
                             extra_compile_args=["-O3"]),
                   ],
)
Δίνουμε στην κονσόλα `python2 setup.py` και θα πρέπει να γίνει το compilation χωρίς προβλήματα. Αν υπάρχουν προβλήματα θα βγει warning, να μη χρησιμοποιηθεί το αρχείο *.so που παράχθηκε.

Bήμα 4ο
(Αφού τεστάρουμε ότι όλα δουλευουν όπως πρέπει) Μετράμε τις διαφορές στην ταχύτητα πριν και μετά
python2 -m timeit -s "import numpy as np; x = np.array([1., 2., 3., 4., 4.], dtype = np.float); y = np.array([2., 3., 4., 4., 2.], dtype = np.float); from area import calc_area" "calc_area(x, y)"
Στο σύστημά μου,
Python : 100000 loops, best of 3: 19.9 usec per loop
Cython : 1000000 loops, best of 3: 2 usec per loop
Κερδίσαμε δηλαδή 10x στην εκτέλεση ενός απλού loop με 5 μόνο επαναλήψεις! Όσο μεγαλύτερο είναι το μήκος του πίνακα τόσο μεγαλύτερο είναι το κέρδος!
Τελευταία διόρθωση: 12 Χρόνια 10 Μήνες πριν από pmav99.
Πρέπει να είστε εγγεγραμμένο μέλος του Φόρουμ για να κάνετε μια δημοσίευση.
Συντονιστές: pmav99
Χρόνος δημιουργίας σελίδας: 0.378 δευτερόλεπτα

Μοιράσου το!

Powered by CoalaWeb

Λίστα Ταχυδρομείου