c++ - 带有条件的 Arrayfire 错误

标签 c++ arrayfire

我正在尝试使 ArrayFire 中的数组饱和。我希望所有大于 0.75 的值饱和到 1.0,所有小于 0.25 的值饱和到 0.0。我正在使用以下表达式。

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

这是一个 af::array 类型。它可以工作一段时间,但一旦我得到一个没有值大于 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());
    }
}

最佳答案

您看到的错误是因为 open bug about zero length arrays (编辑:自 v3.4.0 起已修复)。这是一个普遍存在的问题,一段时间以来我们一直在努力解决。

这是针对您的案例的解决方法。您甚至不需要索引来实现您想要做的事情。

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

编辑:从 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 并且您试图替换它们,则算术将不起作用。在这种情况下,您可以回退到以下函数之一。

使用 select(使用额外的内存):

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;

请注意, bool 值 af::array 上的索引会在内部调用 af::where。所以这和下面的一样有效

arr(arr < some_val) = other_val;

还有一个额外的好处,即零大小的数组不会失败。

编辑:为后代添加了其他解决方法。

关于c++ - 带有条件的 Arrayfire 错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36263133/

相关文章:

c++ - 隐式与显式接口(interface)

c++ - std::back_inserter 在旧的 GCC 上需要 const_reference。为什么?

rust - 如何将 Arrayfire 数组转换为 Rust Vec?

c++ - 为新的 ArrayFire 版本调整 MatchedFilter 算法时出现问题

c++ - 在创建自己的数据结构时,我应该使用迭代器还是索引来提供从外部的访问?

c++ - 在 pragma pack 中包含 std map 会导致崩溃

c++ - ArrayFire中统一后端的使用

c++ - 从 C++ 中使用 curl 发送电子邮件

python - 英特尔 MKL fatal error : Cannot load libmkl_mc3. so 或 libmkl_def.so