2012-04-03 18 views
2

JOCLを使用して、JavaでOpenCLでバックプロップ学習を行うフィードフォワードマルチレイヤパーセプトロンの実装に問題があります。このOpenCLカーネルがエラーの原因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; 
    } 

基本的には、このカーネルをネットワークの各レイヤーに対して実行します。最初の層には "入力"がないので、ループは実行されません。しかし、第1層は入力ノード層であるため、入力パターンから関連する値を追加します。これは正常に実行され、この時点で値を読み取ることができます。

ただし、入力があり、最初のレイヤーからのすべてのノードを持つSECONDレイヤーを実行しようとすると、clFinish()を呼び出すとCL_INVALID_COMMAND_QUEUEというエラーが返されます。ときには、このエラーはドライバーのクラッシュと回復と結びついています。私はTDRのタイムアウトに問題がある可能性があることを(例えばhereのように)読んだことがあります。

私はclSetKernelArg()を呼び出して何か愚かなことをチェックするつもりですが、誰でもコード内の何かを明らかに見つけることができますか? forループが含まれているため、2番目のレイヤーにエラーが導入されているように見えます。必要な場合はすべてのパラメータを明確にすることができますが、最初の投稿では少し過剰なようです。

また、私はこのコードは、おそらくどこでも有能なプログラマーへの侮辱であってもよいが、炎に無料で感じることが十分に承知している:P

EDIT:ホストコード:

//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 pastebinに完全なコードをアップロードしました。

+0

共有するホストコードの一部がありますか?私はそれがニューロンの第1の層のために動くなら、カーネル自体に問題があるとは思わない。また、clFinish()の代わりにclWaitForEvents()を試してみましたか? – mfa

+0

確かに、このカーネルがループ内でエンキューされている場所にビットを追加し、必要に応じてさらにポストして、何を言うことができます。 – chrisvarnz

答えて

2

解決済み。 [0]ですべてのインデックスをバッファーではなく直線カーネルパラメーターにすることで、エラーを修正しました。明らかに、ハードウェアは、一度にバッファのある特定の要素にアクセスするたくさんのものが好きではない。

1

私はループの上に何があるのか​​分かりません。このループ以外のキューを使用しますか?以下は試してみたいことです。

//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

私はイベントで行くことがありましたが、それは私のトラブルを引き起こしましたので、通話をブロックしてclFinish()して、別の場所に移動して、それがどう運賃かを見ていきます。また、私は[pastebinned](http://pastebin.com/xGNBn4Gp)全体のファイルを、GPUTrain関数は重要なものです(それは少しモノリシックです)。入力いただきありがとうございます! – chrisvarnz

+0

ようこそ。私はあなたがjava + oclを使用していることを認識していませんでした。私はポインタのものがまだ動作することを願っています。私はチャンスを得るときにコードをもう一度見ていきます。 – mfa

+0

clEnqueueNDRangeKernel()呼び出しの直後にclWaitForEvents()を呼び出すと、2回目のパスでCL_OUT_OF_RESOURCESでブレークします。これは、おそらくカーネルが壊れているという同じ問題の症状でなければなりません。 PS。ええ、私はトップに言及しました:Pこの実装では、配列を使用して周りのポインタのものは、配列は本質的にネイティブポインタであるロングを含んでいます。 – chrisvarnz

関連する問題