2015-08-24 12 views
6

Ich verwende PyOpenCL, um Bilder in Python zu verarbeiten und ein 3D-Numpy-Array (x width x 4) an den Kernel zu senden. Ich habe Probleme beim Indexieren des 3D-Arrays innerhalb des Kernel-Codes. Zum jetzigen Zeitpunkt kann ich nur das gesamte Eingangsarray an den Ausgang kopieren. Der aktuelle Code sieht wie folgt aus, wo img ist das Bild mit img.shape = (320, 512, 4):PyOpenCL Indizierung von 3D-Arrays im Kernel-Code

__kernel void part1(__global float* img, __global float* results) 
{ 
    unsigned int x = get_global_id(0); 
    unsigned int y = get_global_id(1); 
    unsigned int z = get_global_id(2); 

    int index = x + 320*y + 320*512*z; 

    results[index] = img[index]; 
} 

Aber ich verstehe nicht ganz, wie diese Arbeit. Zum Beispiel, wie indexiere ich das Python-Äquivalent von img[1, 2, 3] in diesem Kernel? Und weiter, welcher Index sollte in results für das Speichern einiger Artikel verwendet werden, wenn ich möchte, dass es auf der Position results[1, 2, 3] im numpy Array ist, wenn ich die Ergebnisse zurück zu Python bekomme?

So führen diese ich diesen Python-Code verwenden:

import pyopencl as cl 
import numpy as np 

class OpenCL: 
def __init__(self): 
    self.ctx = cl.create_some_context() 
    self.queue = cl.CommandQueue(self.ctx) 

def loadProgram(self, filename): 
    f = open(filename, 'r') 
    fstr = "".join(f.readlines()) 
    self.program = cl.Program(self.ctx, fstr).build() 

def opencl_energy(self, img): 
    mf = cl.mem_flags 

    self.img = img.astype(np.float32) 

    self.img_buf = cl.Buffer(self.ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=self.img) 
    self.dest_buf = cl.Buffer(self.ctx, mf.WRITE_ONLY, self.img.nbytes) 

    self.program.part1(self.queue, self.img.shape, None, self.img_buf, self.dest_buf) 
    c = np.empty_like(self.img) 
    cl.enqueue_read_buffer(self.queue, self.dest_buf, c).wait() 
    return c 

example = OpenCL() 
example.loadProgram("get_energy.cl") 
image = np.random.rand(320, 512, 4) 
image = image.astype(np.float32) 
results = example.opencl_energy(image) 
print("All items are equal:", (results==image).all()) 
+0

Ich sah, dass pyopenCL direkt in der Lage sein sollte, CL Arrays wie es ist. Ich habe es jedoch nicht geschafft, dies einschließlich Indexierung zu tun. – Dschoni

+0

Ist diese Frage noch relevant? Ich könnte einige interessante Informationen hinzufügen, wenn Sie bereit sind, es zu versuchen. – jurij

+0

@jurij nicht mehr für mich. Aber wenn Sie wertvolle Einsichten haben, können Sie diese für andere freigeben, die das gleiche Problem haben könnten. – nikicc

Antwort

0

Obwohl diese Lösung nicht die opitimal ist, linearisiert ich das Array in Python und schickte es als 1D. Im Kernel-Code berechnete ich x, y und z aus dem linearen Index. Als ich nach Pyhon zurückkehrte, formte ich ihn wieder in seine ursprüngliche Form zurück.

+0

Ich denke in etwa: Funktioniert das wirklich mit einem Puffer? Oder muss ein Array dazu in der Lage sein? – Dschoni

0

Update: Der OpenCL docs Zustand (in 3.5), dass

"Memory objects are categorized into two types: buffer objects, and image objects. A buffer 
object stores a one-dimensional collection of elements whereas an image object is used to store a 
two- or three- dimensional texture, frame-buffer or image." 

so ein Puffer immer linear ist, oder linearisiert, wie Sie von meinem Beispiel unten sehen können.

import pyopencl as cl 
import numpy as np 


h_a = np.arange(27).reshape((3,3,3)).astype(np.float32) 

ctx = cl.create_some_context() 
queue = cl.CommandQueue(ctx) 

mf = cl.mem_flags 
d_a = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=h_a) 

prg = cl.Program(ctx, """ 
__kernel void p(__global const float *d_a) { 
    printf("Array element is %f ",d_a[10]); 
} 
""").build() 

prg.p(queue, (1,), None, d_a) 

Gibt mir

"Array element is 10" 

als Ausgabe. Also ist der Puffer tatsächlich das linearisierte Array. Dennoch funktioniert der naive [x, y, z] -Ansatz, der aus numpy bekannt ist, nicht so. Die Verwendung eines 2- oder 3-D-Bildes anstelle eines Puffers sollte dennoch funktionieren.

-1

Ich stieß auf das gleiche Problem. Auf https://lists.tiker.net/pipermail/pyopencl/2009-October/000134.html ist ein einfaches Beispiel, wie Sie 3D-Arrays mit PyOpenCL, die für mich arbeiteten, verwenden. Ich zitiere den Code hier für die zukünftige Referenz:

import pyopencl as cl 
import numpy 
import numpy.linalg as la 

sizeX=4 
sizeY=2 
sizeZ=5 
a = numpy.random.rand(sizeX,sizeY,sizeZ).astype(numpy.float32) 

ctx = cl.Context() 
queue = cl.CommandQueue(ctx) 

mf = cl.mem_flags 
a_buf = cl.Buffer(ctx, mf.READ_ONLY | mf.COPY_HOST_PTR, hostbuf=a) 
dest_buf = cl.Buffer(ctx, mf.WRITE_ONLY, a.nbytes) 

prg = cl.Program(ctx, """ 
    __kernel void sum(__global const float *a, __global float *b) 
    { 
     int x = get_global_id(0); 
     int y = get_global_id(1); 
     int z = get_global_id(2); 

     int idx = z * %d * %d + y * %d + x; 

     b[idx] = a[idx] * x + 3 * y + 5 * z; 
    } 
    """ % (sizeY, sizeX, sizeX)).build() 

prg.sum(queue, a.shape, a_buf, dest_buf) 
cl.enqueue_read_buffer(queue, dest_buf, a).wait() 
print a