如何在 Halide 中使用 C++ 随机函数?

How to use C++ random function in Halide?

我的目标是能够在 Halide 中模拟信号相关的高斯噪声。我有一个内置于 OpenCV 中的模型,我现在正在将其移植到 Halide。挑战在于 Halide 的随机数生成器不是正态分布的,因此我需要使用外部函数来生成噪声值。

实现尝试使用C++随机数生成器产生正态分布的噪声,Halide Func产生每个像素处噪声的信号相关标准差,然后将噪声添加到renoise中的像素。下面我展示了功能的布局。

// Note: This is an implementation of the noise model found in the paper below:
// "Noise measurement for raw-data of digital imaging sensors by 
// automatic segmentation of non-uniform targets"
float get_normal_dist_rand( float mean, float std_dev ) {
  std::default_random_engine generator;
  std::normal_distribution<float> distribution(mean,std_dev);
  float out = distribution(generator);
  return out;
}

Func make_get_std_dev( Func *in_func ) {
  Var x, y, c;
  float q = 0.0060;
  float p = 0.0500;
  // std_dev = q * sqrt(unnoised_pixel - p)
  Func get_std_dev("get_std_dev");
    get_std_dev(x,y,c) = q * sqrt( (*in_func)(x,y,c) - p );
  return get_std_dev;
}

Func make_renoise( Func *in_func, Func *std_dev ) {
  Var x, y, c;
  // Noise parameters
  // noised_pixel = unnoised_pixel + 
  //                  gaussian_rand( std_dev = q * sqrt(unnoised_pixel - p) )
  // q and p values do not vary between channels
  Func renoise("renoise");
    renoise(x,y,c) = (*in_func)(x,y,c) +  
                       get_normal_dist_rand(0,(*std_dev)(x,y,c));   
  return renoise;
}

这对我来说很有意义,但不幸的是,我在尝试编译时收到以下错误:

../common/pipe_stages.cpp: In function 'Halide::Func make_renoise(Halide::Func*, Halide::Func*)':
../common/pipe_stages.cpp:223:64: error: cannot convert 'std::enable_if<true, Halide::FuncRef>::type {aka Halide::FuncRef}' to 'float' for argument '2' to 'float get_normal_dist_rand(float, float)'
                        get_normal_dist_rand(0,(*std_dev)(x,y,c));  
                                                                ^

因此,似乎无法将 Func 的输出提供给 C++ 函数。我想这作为 Halide 的限制是有道理的,但我并没有真正看到实现信号相关正态分布噪声的替代方案。在 Halide 中还有其他使用外部 C++ 函数的方法吗?我看到有人在谈论使用 "extern",但不幸的是,关于该功能的文档似乎很少,我找不到我需要的东西。

您需要使用我们的一种外部机制来绑定到 C++ 代码。 HalideExtern_* 是两者中较简单的一个,可以让您一次调用一个随机数。 las test/correctness/c_function.cpp 是这方面的直接示例,它会有所帮助,但可能会更清楚。

出于效率原因,我希望您一次请求一个随机数缓冲区。这可以通过 define_extern 机制来完成。 C++ 函数必须参与边界推理,因此涉及更多。对此的测试是 correctness/extern_producer.cpp.

我希望将我们的随机数转换为适当分布或在 Halide 中实施随机数生成算法是获得真正快速生产代码的正确方法,但这可能比您想要做的工作更多让这个开始工作。

您还可以使用 Halide 的 RNG 以及对高斯分布的二项式近似:

Expr gaussian_random(Expr sigma) {
  return (random_float() + random_float() + random_float() - 1.5f) * 2 * sigma;
}

添加更多 randomFloat 实例以越来越接近真正的正态分布。