2012-04-03 5 views
2

Ich habe ein Problem mit der Implementierung eines Feed-Forward MultiLayer Perceptron, mit Back-Prop-Lernen in OpenCL in Java, mit JOCL. Hier ist der Kernel-Code für die Berechnungsphase:Was ist mit diesem OpenCL-Kernel verursacht den Fehler CL_INVALID_COMMAND_QUEUE

#pragma OPENCL EXTENSION cl_khr_fp64 : enable 
    __kernel void Neuron(__global const double *inputPatterns, 
          __global double *weights, 
          __global const int *numInputs, 
          __global const int *activation, 
          __global const double *bias, 
          __global const int *usingBias, 
          __global double *values, 
          __global const int *maxNumFloats, 
          __global const int *patternIndex, 
          __global const int *inputPatternSize, 
          __global const int *indexOffset, 
          __global const int *isInputNeuron, 
          __global const int *inputs) 
    { 
     int gid = get_global_id(0); 
     double sum = 0.0; 
     for(int i = 0; i < numInputs[gid+indexOffset[0]]; i++) 
     { 
      sum += values[inputs[(gid+indexOffset[0]) * maxNumFloats[0] + i]] * 
        weights[(gid+indexOffset[0]) * maxNumFloats[0] + i]; 
     } 
     if(usingBias[gid+indexOffset[0]]) 
      sum += bias[gid+indexOffset[0]]; 
     if(isInputNeuron[gid+indexOffset[0]]) 
      sum += inputPatterns[gid+indexOffset[0]+(patternIndex[0] * inputPatternSize[0])]; 
     if(activation[gid+indexOffset[0]] == 1) 
      sum = 1.0/(1.0 + exp(-sum)); 
     values[gid + indexOffset[0]] = sum; 
    } 

Grundsätzlich führe ich diesen Kernel für jede Schicht im Netzwerk. Für die erste Schicht gibt es keine "Eingänge", so dass die Schleife nicht ausgeführt wird. Da die erste Schicht jedoch eine Eingangsknotenschicht ist, fügt sie den relevanten Wert aus dem Eingangsmuster hinzu. Dies funktioniert gut, und ich kann die Werte an diesem Punkt zurücklesen.

Wenn ich versuche, die zweite Schicht (die jedoch Eingänge hat, jeden Knoten von der ersten Schicht) zu führen, gibt ein Aufruf von clFinish() den Fehler CL_INVALID_COMMAND_QUEUE zurück. Manchmal ist dieser Fehler mit einem Absturz und einer Wiederherstellung des Treibers verbunden. Ich habe gelesen (here zum Beispiel), dass dies ein Problem mit TDR Timeouts sein könnte, und habe versucht, das Limit zu erhöhen, aber unsicher, ob dies einen Unterschied macht.

Ich gehe durch die Aufrufe von clSetKernelArg() nach etwas Dummes zu suchen, aber kann irgendjemand etwas offensichtlich off im Code finden? Es scheint, dass der Fehler in der zweiten Schicht aufgrund der Einbeziehung der for-Schleife eingeführt wird ... Ich kann jeden der Parameter klären, wenn es benötigt wird, aber es schien ein bisschen übertrieben für einen ersten Post.

Auch ich bin dieser Code voll bewusst wird wahrscheinlich überall ein Affront gegen die zuständigen Programmierer sein, aber Flamme frei fühlen: P

EDIT: Host-Code:

//Calc 
    for(int k = 0; k < GPUTickList.length; k++) 
    { 
     clFlush(clCommandQueue); 
     clFinish(clCommandQueue); 
     //If input nodes 
     if(k == 0) 
      //Set index offset to 0 
      GPUMapIndexOffset.asIntBuffer().put(0, 0); 
     else 
      //Update index offset 
      GPUMapIndexOffset.asIntBuffer().put(0, 
       GPUMapIndexOffset.asIntBuffer().get(0) + GPUTickList[k-1]); 
     //Write index offset to GPU buffer 
     ret = clEnqueueWriteBuffer(clCommandQueue, memObjects[12], CL_TRUE, 0, 
       Sizeof.cl_int, Pointer.to(GPUMapIndexOffset.position(0)), 0, null, null);    
     //Set work size (width of layer) 
     global_work_size[0] = GPUTickList[k]; 
     ret = clEnqueueNDRangeKernel(clCommandQueue, kernel_iterate, 1, 
      global_work_offset, global_work_size, local_work_size, 
      0, null, null); 
    } 

EDIT 2: I habe den vollständigen Code auf pastebin hochgeladen.

+0

Haben Sie einen Teil Ihres Host-Codes für die Freigabe? Ich bezweifle, dass es ein Problem mit dem Kernel selbst gibt, wenn es für die erste Neuronenschicht läuft. Haben Sie auch clWaitForEvents() anstelle von clFinish() ausprobiert? – mfa

+0

Sicher, hinzugefügt das Bit, wo dieser Kernel in eine Schleife eingereiht wird, kann mehr bei Bedarf posten, einfach was sagen. – chrisvarnz

Antwort

2

Gelöst. Der Fehler wurde behoben, indem alles, was mit [0] indexiert wurde, statt eines Puffers einen geraden Kernel-Parameter enthielt. Offensichtlich mag es die Hardware nicht, wenn viele Dinge gleichzeitig auf ein bestimmtes Element eines Puffers zugreifen.

1

Ich bin mir nicht sicher, was Sie über der Schleife haben .. verwenden Sie die Warteschlange anders als in dieser Schleife? Unten können Sie etwas ausprobieren.

//flush + finish if you need to before the loop, otherwise remove these lines 
clFlush(clCommandQueue); 
clFinish(clCommandQueue); 

cl_event latestEvent; 
//Calc 
for(int k = 0; k < GPUTickList.length; k++) 
{ 
    //If input nodes 
    if(k == 0) 
     //Set index offset to 0 
     GPUMapIndexOffset.asIntBuffer().put(0, 0); 
    else 
     //Update index offset 
     GPUMapIndexOffset.asIntBuffer().put(0, 
      GPUMapIndexOffset.asIntBuffer().get(0) + GPUTickList[k-1]); 
    //Write index offset to GPU buffer 
    ret = clEnqueueWriteBuffer(clCommandQueue, memObjects[12], CL_TRUE, 0, 
      Sizeof.cl_int, Pointer.to(GPUMapIndexOffset.position(0)), 0, null, null);    
    //Set work size (width of layer) 
    global_work_size[0] = GPUTickList[k]; 
    ret = clEnqueueNDRangeKernel(clCommandQueue, kernel_iterate, 1, 
     global_work_offset, global_work_size, local_work_size, 
     0, null, &latestEvent); 
    clWaitForEvents(1, &latestEvent); 
} 
+0

Ich habe mich mit Ereignissen beschäftigt, aber es verursachte mir Probleme, also blockierte ich die Anrufe und clFinish(), ich gebe es jetzt noch einmal und sehe, wie es geht. Außerdem habe ich [pastebinned] (http://pastebin.com/xGNBn4Gp) die ganze Datei, die GPUTrain-Funktion ist die wichtige (es ist ein bisschen monolithisch). Danke für die Eingabe! – chrisvarnz

+0

Gern geschehen. Ich wusste nicht, dass du Java + OCL benutzt. Ich hoffe, dass das Pointer-Zeug immer noch funktioniert. Ich werde den Code noch einmal anschauen, wenn ich eine Chance bekomme. – mfa

+0

Der Aufruf von clWaitForEvents(), der unmittelbar auf den Aufruf von clEnqueueNDRangeKernel() folgt, bricht beim zweiten Durchlauf mit CL_OUT_OF_RESOURCES ab. Dies muss ein Symptom für das gleiche Problem sein, wahrscheinlich dass der Kernel bricht. PS. Ja, ich habe das oben erwähnt: P Das Pointer-Zeug, das Sie mit Arrays in dieser Implementierung umgehen, die Arrays enthalten im Wesentlichen Longs, die die nativen Zeiger sind. – chrisvarnz