Repa 2和3 API之间的主要区别是什么?

sac*_*eie 11 parallel-processing haskell image-processing repa data-parallel-haskell

更具体地说,我有以下看似无害的小修复3程序:

{-# 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
Run Code Online (Sandbox Code Playgroud)

花费这么多时间在我的2Ghz核心2双核笔记本电脑上处理640x420图像:

real    2m32.572s
user    4m57.324s
sys     0m1.870s
Run Code Online (Sandbox Code Playgroud)

我知道一些事情肯定是错的,因为我在使用Repa 2的更复杂的算法上获得了更好的性能.在那个API下,我发现的重大改进来自于在每次数组转换之前添加对'force'的调用(我理解)表示每次调用地图,卷积,遍历等).我无法弄清楚在维修3中做的类似事情 - 实际上我认为新的表现形式类型参数应该确保不存在关于何时需要强制数组的歧义?新的monadic接口如何适应这个方案?我已经阅读了Don S的精彩教程,但是在维修2和3 API之间存在一些关键差距,这些差距很少在网上讨论AFAIK.

更简单的说,是否有一种最小的影响方式来修复上述程序的效率?

小智 10

新的表示类型参数在需要时不会自动强制(这样做可能是一个很难的问题) - 您仍然需要手动强制执行.在Repa 3中,这是使用computeP函数完成的:

computeP
  :: (Monad m, Repr r2 e, Fill r1 r2 sh e)
  => Array r1 sh e -> m (Array r2 sh e)
Run Code Online (Sandbox Code Playgroud)

我个人真的不明白为什么它是monadic,因为你也可以使用Monad身份:

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
Run Code Online (Sandbox Code Playgroud)

所以,现在你的output函数可以用适当的强制重写:

output img = map cast . f . blur . f . blur . f . blur . f $ grey
  where ...
Run Code Online (Sandbox Code Playgroud)

f使用辅助函数的缩写u来辅助类型推断:

u :: Array U sh e -> Array U sh e
u = id
f = u . force
Run Code Online (Sandbox Code Playgroud)

随着这些变化,加速是非常显着的 - 这是可以预期的,因为没有中间强制每个输出像素最终评估比必要的更多(中间值不共享).

你原来的代码:

real    0m25.339s
user    1m35.354s
sys     0m1.760s
Run Code Online (Sandbox Code Playgroud)

强迫:

real    0m0.130s
user    0m0.320s
sys     0m0.028s
Run Code Online (Sandbox Code Playgroud)

使用600x400 png测试,输出文件完全相同.


Ben*_*ier 7

computeP是新的force.

在Repa 3中,您需要computeP使用force在Repair 2中使用过的任何地方.

来自repa-examples 的Laplace示例与您正在执行的操作类似.您还应该在函数中使用cmapplain而不是plain .将在下周初在我的主页上发表一篇文章解释原因.mapblur