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 時間節約できました。