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.
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
Sicher, hinzugefügt das Bit, wo dieser Kernel in eine Schleife eingereiht wird, kann mehr bei Bedarf posten, einfach was sagen. – chrisvarnz