11

具体的には、次のような無害に見える小さなRepa3プログラムがあります。

{-# LANGUAGE QuasiQuotes #-}

import Prelude hiding (map, zipWith)
import System.Environment (getArgs)
import Data.Word (Word8)
import Data.Array.Repa
import Data.Array.Repa.IO.DevIL
import Data.Array.Repa.Stencil
import Data.Array.Repa.Stencil.Dim2

main = do
  [s] <- getArgs
  img <- runIL $ readImage s

  let out = output x where RGB x = img
  runIL . writeImage "out.bmp" . Grey =<< computeP out

output img = map cast . blur . blur $ blur grey
  where
    grey              = traverse img to2D luminance
    cast n            = floor n :: Word8
    to2D (Z:.i:.j:._) = Z:.i:.j

---------------------------------------------------------------

luminance f (Z:.i:.j)   = 0.21*r + 0.71*g + 0.07*b :: Float
  where
    (r,g,b) = rgb (fromIntegral . f) i j

blur = map (/ 9) . convolve kernel
  where
    kernel = [stencil2| 1 1 1
                        1 1 1
                        1 1 1 |]

convolve = mapStencil2 BoundClamp

rgb f i j = (r,g,b)
  where
    r = f $ Z:.i:.j:.0
    g = f $ Z:.i:.j:.1
    b = f $ Z:.i:.j:.2

2Ghzコア2デュオラップトップで640x420の画像を処理するには、これだけの時間がかかります。

real    2m32.572s
user    4m57.324s
sys     0m1.870s

Repa 2を使用して、はるかに複雑なアルゴリズムでパフォーマンスが大幅に向上したため、何かがかなり間違っているに違いないことを知っています。そのAPIの下で、すべての配列変換の前に「force」への呼び出しを追加することで、大きな改善が見られました(これは理解しています)マップ、畳み込​​み、トラバースなどへのすべての呼び出しを意味します)。Repa 3で行う類似のことを完全に理解することはできません。実際、新しいマニフェストタイプのパラメーターは、配列を強制する必要がある場合にあいまいさがないことを保証することになっていると思いましたか?そして、新しいモナディックインターフェイスはこのスキームにどのように適合しますか?Don Sによるすばらしいチュートリアルを読みましたが、Repa2と3のAPIの間には、オンラインAFAIKではほとんど議論されていないいくつかの重要なギャップがあります。

もっと簡単に言えば、上記のプログラムの効率を修正するための最小限の影響を与える方法はありますか?

4

2 に答える 2

10

新しい表現タイプのパラメーターは、必要なときに自動的に強制されません(これをうまく行うのはおそらく難しい問題です)。それでも手動で強制する必要があります。Repa 3では、これはcomputeP関数を使用して実行されます。

computeP
  :: (Monad m, Repr r2 e, Fill r1 r2 sh e)
  => Array r1 sh e -> m (Array r2 sh e)

モナドアイデンティティを使用することもできるので、私は個人的にそれがモナドである理由を本当に理解していません。

import Control.Monad.Identity (runIdentity)
force
  :: (Repr r2 e, Fill r1 r2 sh e)
  => Array r1 sh e -> Array r2 sh e
force = runIdentity . computeP

これで、output適切な強制で関数を書き直すことができます。

output img = map cast . f . blur . f . blur . f . blur . f $ grey
  where ...

型推論を支援fするヘルパー関数を使用した省略形:u

u :: Array U sh e -> Array U sh e
u = id
f = u . force

これらの変更により、スピードアップは非常に劇的になります。これは、中間の強制がないと、各出力ピクセルが必要以上に評価されるためです(中間値は共有されません)。

元のコード:

real    0m25.339s
user    1m35.354s
sys     0m1.760s

強制:

real    0m0.130s
user    0m0.320s
sys     0m0.028s

600x400 pngでテストしたところ、出力ファイルは同一でした。

于 2012-05-27T11:22:45.490 に答える
7

computeP新しいforceです。

Repa 3では、Repa2で使用したすべてのcomputeP場所で使用する必要がありますforce

repa-examplesのラプラスの例は、あなたがしていることと似ています。また、関数cmapでプレーンの代わりに使用する必要があります。来週初めに私のホームページにその理由を説明する論文があります。mapblur

于 2012-05-27T11:15:13.577 に答える