首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >从ByteString创建Repa

从ByteString创建Repa
EN

Stack Overflow用户
提问于 2018-01-12 01:00:21
回答 1查看 101关注 0票数 2

最初,我有一个ByteString,然后我将其解压缩并转换为Int16s,这个过程的这部分时间相对较少。然后,我将Int16s的列表转换为带有以下行的Repa数组,

代码语言:javascript
复制
Repa.fromListUnboxed (Z :. bytesOfDataPerImage `div` 2) listOfInts

根据分析器,这一行占用了大约40%的CPU时间,这可能只是指示我正在执行的计算不值得使用Repa。当从ByteString到Repa数组时,是否有更有效的路径可选?

我已经尝试了Repa fromByteString函数,尽管

代码语言:javascript
复制
Array B DIM1 Word8 -> Array U DIM1 Int16

很慢。我首先将数组重组为Word8s的2d数组,然后折叠到Int16s中。也许Byte数组是正确的方法,而我的转换方法是错误的。

代码语言:javascript
复制
convertImageData :: Array B DIM1 Word8 -> Array U DIM1 Int16
convertImageData !arr = Repa.foldS convertWords 0 (Repa.map fromIntegral (splitArray arr))

splitArray :: Array B DIM1 Word8 -> Array U DIM2 Word8
splitArray !arr = computeUnboxedS $ reshape (Z :. ((size $ extent arr) `div` 2) :. 2) arr


convertWords :: Int16 -> Int16 -> Int16
convertWords !word1 !word2 = (word1 `shiftL` 8) .|. word2

对于某些上下文,此程序将根据用C/C++编写的相同程序进行基准测试。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-08-01 09:24:42

您最初转换为list并随后调用Repa.fromListUnboxed的方法非常缓慢,因为您所做的只是强制列表的元素,而不是顺序地将其加载到未装箱的数组中。这就是为什么转换到列表所需的时间非常少,因为它所做的只是创建了一组块,但是实际的计算是在将它加载到数组中时发生的。

您的第二种方法肯定更好,但仍然有不必要的步骤,例如。不需要reshape数组,只需将新大小传递给fromByteString函数。下面是一个略为改进的版本:

代码语言:javascript
复制
bytesToRepaOriginal :: Bytes.ByteString -> Repa.Array Repa.U Repa.DIM1 Int16
bytesToRepaOriginal bs =
  Repa.foldS
    convertWords
    0
    (Repa.map fromIntegral $
     Repa.fromByteString (Repa.Z Repa.:. (Bytes.length bs `div` 2) Repa.:. 2) bs)

由于某些原因,Repa中的fromByteString函数和B表示速度并不特别快,因此有一种更快的方法,即通过直接索引ByteString来构造数组

代码语言:javascript
复制
bytesToRepaP :: Monad m => Bytes.ByteString -> m (Repa.Array Repa.U Repa.DIM1 Int16)
bytesToRepaP bs =
  Repa.computeUnboxedP $
  Repa.fromFunction
    (Repa.Z Repa.:. (Bytes.length bs `div` 2))
    (\(Repa.Z Repa.:. i) ->
       let i' = i * 2
           f = Bytes.unsafeIndex bs
        in (fromIntegral (f i') `shiftL` 8) .|. fromIntegral (f (i' + 1)))

切换到使用Repa.computeUnboxedS的顺序计算将给您一个因素的x2慢下来,但由于我们正在尝试优化它,我们需要一直与并行计算。

我不想从一个非常好的Repa库中抢占所有的风头,我也想展示一下新的马西夫库是如何工作的:

代码语言:javascript
复制
import Data.Massiv.Array as Massiv

bytesToMassiv :: Bytes.ByteString -> Massiv.Array Massiv.U Massiv.Ix1 Int16
bytesToMassiv bs =
  Massiv.makeArrayR U Par (Bytes.length bs `div` 2)
    (\i ->
       let i' = i * 2
           f = Bytes.unsafeIndex bs
        in (fromIntegral (f i') `shiftL` 8) .|. fromIntegral (f (i' + 1)))

为了给出一些具体的数字,显示正在执行的优化,这里有一个简化的标准基准:

代码语言:javascript
复制
benchmarking fromByteString/Massiv Parallel
time                 1.114 ms   (1.079 ms .. 1.156 ms)

benchmarking fromByteString/Repa Parallel
time                 1.954 ms   (1.871 ms .. 2.040 ms)

benchmarking fromByteString/Repa Original
time                 15.80 ms   (15.67 ms .. 15.92 ms)
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/48218110

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档