1

私の目標は、Halide で信号に依存するガウス ノイズをモデル化できるようにすることです。私は現在Halideに移植しているOpenCVで構築されたモデルを持っています。問題は、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」の使用について話している人を見たことがありますが、残念ながらその機能に関するドキュメントは非常に軽いようで、必要なものを見つけることができません。

4

2 に答える 2

2

C++ コードにバインドするには、extern メカニズムのいずれかを使用する必要があります。HalideExtern_* は 2 つの中で簡単で、一度に 1 つずつ乱数を取得するための呼び出しを行うことができます。悲しいかな、test/correctness/c_function.cpp はこれの直接的な例です。これは役に立ちますが、より明確になる可能性があります。

効率的な理由から、一度に乱数のバッファーを要求したいと思うでしょう。これは、define_extern メカニズムを介して実行できます。C++ 関数は境界推論に参加する必要があるため、もう少し複雑です。これに対するテストは、正しさ/extern_producer.cpp です。

乱数を適切に分散するように変換するか、Halide で乱数生成アルゴリズムを実装することが、実際に高速な製品コードを実現するための正しい方法であると期待していますが、最初にこれを機能させるために必要な作業よりも多くの作業が必要になる可能性があります。 .

于 2016-10-14T00:03:15.920 に答える
1

また、Halide の RNG をガウスの二項近似と共に使用することもできます。

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

randomFloat のインスタンスをさらに追加して、真の正規分布にどんどん近づけていきます。

于 2016-10-14T01:04:39.810 に答える