2016-03-28 8 views
2

ArrayFireで配列を飽和しようとしています。私は、0.75より大きいすべての値を1.0に飽和させ、0.25未満を0.0に飽和させたい。私は次の式を使用しています。Arrayfireの条件付きエラー

a(a > 0.75) = 1.0; 
a(a < 0.25) = 0.0; 

これはaf ::配列型です。それはしばらくの間動作しますが、0.75より大きい値がない配列を取得するとすぐに、次の例外が発生します。

terminate called after throwing an instance of 'af::exception' 
    what(): ArrayFire Exception (Invalid input size:203): 
In function verifyDims 
In file src/api/c/data.cpp:36 
Invalid dimension for argument 1 
Expected: ndims >= 1 

In function af::array af::constant(T, const af::dim4&, af::dtype) [with T = double; af::dtype = af_dtype] 
In file src/api/cpp/data.cpp:28 

私がaf::print("", a > 0.75);と呼ぶと、クラッシュする前に次の出力が得られます。

[10 1 1 1] 
     0 
     0 
     0 
     0 
     0 
     0 
     0 
     0 
     0 
     0 

は、それが何らかの形でこの配列は、(非が0.75以上であるので、それがあるべき)すべてゼロであることを見て、その後、次元がゼロであると言っていますか?それは私が間違ってやっていることか、コードのバグですか?

次のコードはそれを修正するようですが、この解決策はいくらか非効率です。

af::array bellow = a[levels - 1] < 0.25f; 
af::array above = a[levels - 1] > 0.75f; 

if(af::anyTrue<bool>(above)) 
    a[levels - 1](above) = 0.75f; 

if(af::anyTrue<bool>(bellow)) 
    a[levels - 1](bellow) = 0.25f; 

機能全体を見たいと思う人のために、私はグラデーションをニューラルネットワークでうまくやっています。 aは実際にはaf :: array型の配列です。私は質問を簡素化するためにそれを残しました。

void train(const float* in, const float* expected_out, float learning_rate) 
{ 
    std::unique_ptr<af::array[]> a(new af::array[levels]), 
      z(new af::array[levels]), d(new af::array[levels]); 

    af::array in_array(inputs, in); 
    af::array y(dims[levels - 1], expected_out); 

    z[0] = af::matmul(weights[0], in_array) + biases[0]; 
    a[0] = sigma(z[0]); 


    for(size_t i = 1; i < levels; i++) 
    { 
     z[i] = af::matmul(weights[i], a[i - 1]) + biases[i]; 
     a[i] = sigma(z[i]); 
    } 


    a[levels - 1](a[levels - 1] < 0.25f) = 0.0f; 
    a[levels - 1](a[levels - 1] > 0.75f) = 1.0f; 

    d[levels - 1] = (y - a[levels - 1]) * sigma_prime(z[levels - 1]); 
    for(size_t i = levels - 1; i-- > 0;) 
     d[i] = af::matmul(weights[i + 1].T(), d[i + 1]) * sigma_prime(z[i]); 

    for(size_t i = 0; i < levels; i++) 
    { 
     biases[i] += learning_rate * d[i]; 
     weights[i] += learning_rate * af::matmul(d[i], (i ? a[i - 1] : in_array).T()); 
    } 
} 
+0

エラーの原因となるコードを追加してください。 – hyde

+0

私はそれをコードの最初の部分でした。 – chasep255

+0

'a(a> 0.75)= 1.0; a(a <0.25)= 0.0; ' – chasep255

答えて

4

あなたが見ているエラーは、このopen bug about zero length arraysである(EDIT:v3.4.0で修正)。これは私たちがしばらくの間正しく修正しようとしている普及した問題です。

あなたの場合の回避策は次のとおりです。あなたは何をしようとしているのかを達成するためにインデックスを作成する必要はありません。

a[levels - 1] = af::min(0.75, af::max(0.25, a[levels - 1])); 

EDIT: 3.4の時点で、あなたはarrayfireで同じ機能を実現するために次の操作を行うことができます。

a[levels - 1] = af::clamp(a[levels - 1], 0.25, 0.75); 

この方法は、はるかに速く、あなたのケースのためのインデックス作成を超えています。言っ


、あなたはインデックスを交換するaf::minaf::maxを使用しないことがあります。そのような場合は、回避策として次のようなことを行うことができます。

af::array cond = arr < some_val; 
arr = arr * (1 - cond) + cond * other_val; 

これはインデックス作成よりも速くなければなりません。しかし、配列にNANがあり、その配列を置き換えようとすると、算術演算は機能しません。その場合は、次のいずれかの機能に戻ります。選択は、(追加のメモリ使用)を使用して

arr = af::select(af::isNaN(arr), arr, other_val)); 

置き換える使用(場所に置き換えると、追加のメモリが使用されません):

af::replace(arr, af::isNaN(arr) other_val)); 

しかし、いくつかのベンチマークはselectreplaceができることを私たちに示しました。特定のケースではインデックス作成よりも遅くなります(これを修正しようとしています)。アルゴリズムでは、select/replaceが遅い場合、次の回避策を使用してインデックスを作成することができます。

af::array idx = af::where(af::isNaN(arr)); 
if (idx.elements()) arr(idx) = replace_val; 

注内部af::whereを呼び出しaf::arrayブール上のインデックス。これは、次のように効率的です。

arr(arr < some_val) = other_val; 

ゼロサイズの配列では失敗しないという利点があります。

EDIT:後書きに追加の回避策を追加しました。