Cython Performance mangelhaft

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
felue
User
Beiträge: 6
Registriert: Donnerstag 21. August 2008, 13:26

Hallo,

um eine Implementierung eines Partikelfilters schneller zu machen, habe ich auf cython zurückgegriffen. Die erreichten Geschwindigkeitssteigerungen bleiben jedoch weit hinter dem zurück, was ich in den Tutorials gelesen habe (maximal Faktor 4). Hier kommt der Cython code für die beiden Funktionen:

Code: Alles auswählen

import cython
import numpy
cimport numpy

import math
import random


# http://docs.cython.org/src/tutorial/numpy.html

DTYPE = numpy.float64
ctypedef numpy.float64_t DTYPE_t		# whyever... a compile-time type with _t suffix is necessary. (See link above)

#~ DTYPE2 = numpy.long
#~ ctypedef numpy.long_t DTYPE2_t

@cython.boundscheck(False) # turn of bounds-checking for entire function
def reCalcEinenSensorCython(unsigned int no_particles, int x, int y, numpy.ndarray[DTYPE_t, ndim=2] particleNumpy, numpy.ndarray[long, ndim=2] XBlackToWhite, numpy.ndarray[long, ndim=2] XWhiteToBlack, numpy.ndarray[long, ndim=2] YBlackToWhite, numpy.ndarray[long, ndim=2] YWhiteToBlack):
	
	cdef numpy.ndarray[int, ndim=1] l	# changed arrays in Schachbrett to numpy arrays
	cdef numpy.ndarray[int, ndim=2] vektorKleiner
	cdef numpy.ndarray[int, ndim=2] vektorGroesser
	cdef numpy.ndarray[int, ndim=2] vektor
	cdef numpy.ndarray[int, ndim=1] vektorMitte
	cdef numpy.ndarray[int, ndim=2] vektorKleinereDist
	
	for l in XBlackToWhite:
		particleNumpy[0:no_particles,14] = particleNumpy[0:no_particles,x]-l[0]
		vektorKleiner = numpy.array(numpy.nonzero(particleNumpy[0:no_particles,y]<l[1]))
		vektorGroesser = numpy.array(numpy.nonzero(particleNumpy[0:no_particles,y]>l[2]))
		vektor = numpy.array(numpy.nonzero(particleNumpy[0:no_particles,y]>=l[1]))
		vektorMitte = numpy.array(numpy.nonzero(particleNumpy[vektor,y]<=l[2])[1])
		particleNumpy[vektorMitte,13] = 0
		particleNumpy[vektorKleiner,13] = particleNumpy[vektorKleiner,y] - l[1]
		particleNumpy[vektorGroesser,13] = particleNumpy[vektorGroesser,y] - l[2]
		particleNumpy[0:no_particles,14] = (particleNumpy[0:no_particles,13]*particleNumpy[0:no_particles,13]+particleNumpy[0:no_particles,14]*particleNumpy[0:no_particles,14])**0.5
		vektorKleinereDist = numpy.array(numpy.nonzero(particleNumpy[0:no_particles,3]>particleNumpy[0:no_particles,14]))
		particleNumpy[vektorKleinereDist,3] = particleNumpy[vektorKleinereDist,14]
	return particleNumpy, vektorKleinereDist



@cython.boundscheck(False) # turn of bounds-checking for entire function
def sensorPart4Cython(unsigned int no_particles, numpy.ndarray[DTYPE_t, ndim=2] particleNumpy, unsigned int particlefilterStepcount):
		
		cdef float start = 0.0
		cdef int b
		cdef int a
		cdef int pos
		cdef int deltapos
		cdef float pGewichtung
		cdef int c
		cdef list rangeList = range(no_particles)		# can I somehow define this as list of integers???
		
		for b in rangeList:
			a = b - 1
			particleNumpy[a,13] = start
			start = start + particleNumpy[a,4]
			particleNumpy[a,14] = start
		
		neueParticel = numpy.array([numpy.random.normal(800, 50, no_particles), numpy.random.normal(300, 100, no_particles), numpy.random.normal(math.pi, math.pi/16, no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles), range(no_particles)], float)
		neueParticel = neueParticel.transpose()
		c = 0
		for b in rangeList:
			a = b - 1
			pos = int(no_particles/2)
			deltapos = int(no_particles/2)
			pGewichtung = random.random() * start

			while not(particleNumpy[pos,13] <= pGewichtung and pGewichtung<=particleNumpy[pos,14]):
				particlefilterStepcount = particlefilterStepcount + 1
				if deltapos!=1:
					deltapos = int(deltapos / 2)
					if deltapos<1:
						deltapos=1
				if particleNumpy[pos,13]>=pGewichtung:
					pos = pos-deltapos
				else:
					pos = pos+deltapos
			#x, y, phi, Distanz, Gewichtung, xSensor, ySensor, xtemp, ytemp, calcTemp
			neueParticel[c,0] = particleNumpy[pos,0] + random.gauss(0,1)
			neueParticel[c,1] = particleNumpy[pos,1] + random.gauss(0,1)
			neueParticel[c,2] = particleNumpy[pos,2] + random.gauss(0,math.pi/32)
			c = c + 1
		
		return neueParticel, particlefilterStepcount
Einerseits zwei allgemeine Fragen:

- wie kann ich mir die Version meiner Cython Installation ausgeben lassen?
- wie kann ich eine List mit integer Einträgen als cdef definieren (Siehe auch Kommentar im Code)?

und schließlich bin ich für Eure allgemeinen Hinweise dankbar, die mir den Code schneller machen!

Vielen Dank schon jetzt.

BG
Felix
Zuletzt geändert von Anonymous am Mittwoch 21. September 2011, 12:13, insgesamt 1-mal geändert.
Grund: Quelltext in Python-Code-Tags gesetzt.
Benutzeravatar
darktrym
User
Beiträge: 784
Registriert: Freitag 24. April 2009, 09:26

Das sieht mir so aus, dass mehr als nur eine Stelle in deinem Code redundant ist.
„gcc finds bugs in Linux, NetBSD finds bugs in gcc.“[Michael Dexter, Systems 2008]
Bitbucket, Github
deets

Du benutzt ja schon viel Numpy - damit ist der Geschwindigkeitzuwachs beschraenkt wuerde ich vermuten, denn solange die Numpy-Calls nicht irgendwie direkt in C umgesetzt werden. Laut

http://wiki.cython.org/tutorials/numpy

ist bei der Verwendung von Cython und Numpy jetzt nicht unbedingt der Hammer an Geschwindigkeitszuwachs zu erwarten.
Benutzeravatar
snafu
User
Beiträge: 6731
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Vielleicht mal PyPy probieren? Ansonsten ist ein häufiger Fehler wohl, dass Python-Schleifen mit Numpy-Aufrufen verwendet werden, anstatt dass direkt die passende Numpy-Funktion verwendet wird, die eine Schleife in Python unnötig macht. Das bringt wohl zum Teil beträchtliche Performance-Zuwächse. Frag mich aber nicht nach Details. Bin kein Numpy-Kenner.
Antworten