1

ruby-fann への入力を作成しており、パフォーマンス上の理由から narray で可能な限り多くの操作を行っています。通常、フロートの 2D 200x200 配列を操作しており、何千回も処理を繰り返す必要があります。

NArray だけを使用すると、許容できるパフォーマンスが得られます。ただし、私が見る限り、NArray に一括処理を実行させることができない場合に、実行したいいくつかの操作を実行しました。つまり、Ruby のループ コントロールを使用して個々の NArray エントリを操作することになります。これは、私のコードのパフォーマンスに即座に悪影響を及ぼします。どのような回避策やアプローチが利用できるのか疑問に思いました。NArray を fork して自分の仕事にいくつかの機能を追加することはできますが、そうしたくはありません。私が必要とする機能は、そのライブラリに入るほど一般的ではないため、私にはうまくいきません。

何らかの形で NArray を直接使用するネイティブ拡張を作成することを検討するかもしれません-それを行う方法についてのポインタは歓迎されます.ネイティブに拡張された宝石を別の宝石から参照する方法がわかりません.

また、Ruby 部分を高速化するため、または NArray 機能や関連ライブラリを利用するために、コードをどのように構造化するかについての洞察やフィードバックをいただければ幸いです。

私の 2 つの遅いコードは非常に似ているため、1 つの質問を投稿します。

1) float の行列を範囲に制限する

私が現在行っていること(簡略化):

  # In reality, nn_input contains real-world data, and I want to 
  # re-normalise it, clipping high values to a maximum of 1.0
  nn_input = NArray.float(200,200).random
  nn_input *= 1.1 
  # The test for "anything needs clipping" is fast, the 200x200 loop is somewhat slower!
  if (nn_input.gt 1.0).sum > 0
    (0...200).each do |x|
      (0...200).each do |y|
        nn_input[x, y] = 1.0 if nn_input[x, y] > 1.0
      end
    end
  end

2) 平均値に基づいて大きな行列を小さな行列にダウンサンプリングします (「画像のサイズ変更」と考えてください)。

私が現在行っていること(簡略化):

  # In reality, nn_input contains real-world data, and I want to 
  # downsize it, re-sampling a 200x200 array to a 20x20 one
  large_input = NArray.float(200,200).random
  small_output = NArray.float(20,20) 

 (0...20).each do |x|
   (0...20).each do |y|
     small_output[x, y] = large_input[x*10..x*10+9,y*10..y*10+9].mean
   end
 end

2 番目の例ではNArray のmeanメソッドを使用していますが、1 番目の例ほど問題はありません。各項目に対して小さな Ruby ループを 40000 回実行することになります (つまり、データ セット全体で 2 億回以上!)。


masa16 からの返信に続いて、速度の違いを示す非常に簡単な irb ベンチマークを次に示します。

irb
1.9.3-p327 :001 > require 'narray'
 => true
1.9.3-p327 :002 > t0 = Time.now; 250.times { nn_input = NArray.float(200,200).random() * 1.1; (0...200).each {|x| (0...200).each { |y| nn_input[x,y]=1.0 if nn_input[x,y]> 1.0 }} }; Time.now - t0
 => 9.329647
1.9.3-p327 :003 > t0 = Time.now; 250.times { nn_input = NArray.float(200,200).random() * 1.1; nn_input[nn_input.gt 1.0] = 1.0; }; Time.now - t0
 => 0.764973

つまり、10 倍高速な小さなコード セグメントの場合、通常は 250 回ではなく 50,000 回実行しているため、以前は 3 時間から 4 時間かかっていた実行時間を 30 分から 1 時間節約できました。

4

2 に答える 2

1

1) nn_input[nn_input.gt 1.0] = 1.0

2) small_output = large_input.reshape(10,20,10,20).mean(0,2)

于 2013-03-18T15:24:11.657 に答える
0

コードをベンチマークして、ボトルネックがあるかどうかを確認しましたか?
マルチコア環境を利用するために計算を並列化する方法はありますか? その場合、優れた JVM マルチスレッド サポートを活用するために JRuby の使用を検討しましたか?

これらは、頭のてっぺんから思いつくことができるもののいくつかです。単純に、これを解決する別の方法を見つける必要があるほど多くのデータを扱っている可能性があります。

于 2013-03-18T14:51:10.600 に答える