2016-06-28 12 views
3

Ich habe in meiner Studienarbeit eine einfache Suche nach nächsten Nachbarn implementiert. Tatsache ist, dass die grundlegende numpy Implementierung gut funktioniert, aber nur den '@jit' Dekorator hinzufügend (kompilierend in Numba), die Ausgaben sind differents (es kopiert einige Nachbarn am Ende aus irgendeinem unbekannten Grund ...)Unterschiede in den Ausgaben von numba

Hier ist der grundlegende Algorithmus:

import numpy as np 
from numba import jit 

@jit(nopython=True) 
def knn(p, points, k): 
    '''Find the k nearest neighbors (brute force) of the point p 
    in the list points (each row is a point)''' 

    n = p.size # Lenght of the points 
    M = points.shape[0] # Number of points 
    neighbors = np.zeros((k,n)) 
    distances = 1e6*np.ones(k) 

    for i in xrange(M): 
     d = 0 
     pt = points[i, :] # Point to compare 
     for r in xrange(n): # For each coordinate 
      aux = p[r] - pt[r] 
      d += aux * aux 
     if d < distances[k-1]: # We find a new neighbor 
      pos = k-1 
      while pos>0 and d<distances[pos-1]: # Find the position 
       pos -= 1 
      pt = points[i, :] 
      # Insert neighbor and distance: 
      neighbors[pos+1:, :] = neighbors[pos:-1, :] 
      neighbors[pos, :] = pt 
      distances[pos+1:] = distances[pos:-1] 
      distances[pos] = d 

    return neighbors, distances 

Zum Testen:

p = np.random.rand(10) 
points = np.random.rand(250, 10) 
k = 5 
neighbors = knn(p, points, k) 

OHNE @jit Dekorateur, eine die richtige Antwort bekommt:

In [1]: distances 
Out[1]: array([ 0.3933974 , 0.44754336, 0.54548715, 0.55619749, 0.5657846 ]) 

Aber die Numba Compilation gibt seltsame Ausgänge:

Out[2]: distances 
Out[2]: array([ 0.3933974 , 0.44754336, 0.54548715, 0.54548715, 0.54548715]) 

Jemand helfen kann? Ich weiß nicht, warum es passiert ...

Vielen Dank.

+0

Sie können in der scipy interessiert sein [KDTree] (http://docs.scipy.org/doc/scipy/ Referenz/generierte/scipy.spatial.cKDTree.html) Implementierung. – Daniel

+0

@Ophion Danke für den Tipp. Ich habe mit der KDTree-Implementierung von sklearn gespielt (ich nehme an, sie sind ähnlich) und sie sind gut für die Vorverarbeitung der Daten für zukünftige multiple Abfragepunkte. In meiner Arbeit muss ich die Nachbarn finden, die ständig die Punkteliste ändern (in Sachen Bildverarbeitung), und diese Art von Implementierungen wird zu langsam. Und es scheint, dass die KDTree-Implementierung nicht besser ist als Brute-Force, wenn die Raumdimension groß ist (beispielsweise größer als 25). –

Antwort

1

Ich glaube, das Problem ist, dass Numba das Schreiben einer Scheibe in eine andere anders behandelt, wenn diese Scheiben sich überlappen, als wenn ohne. Ich kenne die Interna von numpy nicht, aber vielleicht gibt es eine besondere Logik, um mit flüchtigen Speicheroperationen wie dieser umzugehen, die es in Numba nicht gibt. Ändern Sie die folgenden Zeilen und die Ergebnisse mit dem JIT-Dekorateur werden im Einklang mit der Ebene Python-Version:

neighbors[pos+1:, :] = neighbors[pos:-1, :].copy() 
... 
distances[pos+1:] = distances[pos:-1].copy() 
+0

Danke @JoshAdel! Das funktioniert für mich. Ich habe vorher verifiziert, dass dieses überlappende Stück in Numpy keine Probleme verursacht, aber aus irgendwelchen Gründen übersetzt Numba es in einen anderen Algorithmus ... In allen Fällen ist es schlecht, dass nur einige der Nachbarn dupliziert werden, aber nicht die anderen ... Danke nochmal! PD: Ich bin ein Fan von Python, aber solche Dinge lassen mich ernsthaft darüber nachdenken, Julia zu lernen ... –

+0

@ MarioGonzález Ich würde Sie ermutigen, Ihr Beispiel als ein Problem auf dem Numba GitHub Issue Tracker zu veröffentlichen. Das Entwicklerteam ist normalerweise sehr reaktiv und möchte über Bugs oder unerwartetes Verhalten informiert werden. – JoshAdel

+0

Danke @JoshAdel für den Rat. Es wurde [hier] gepostet (https://github.com/numba/numba/issues/1960). –