haskell中的查找表加速

Posted

技术标签:

【中文标题】haskell中的查找表加速【英文标题】:Look-up table in haskell accelerate 【发布时间】:2015-11-05 19:00:23 【问题描述】:

我正在使用 Haskell 的加速库做一个有趣的项目。我有一个需要编写的函数,在纯 Haskell 中看起来像这样:

oddfac :: Int -> Int
oddfac n = product [1,3...n]

即类似于阶乘函数,但只乘以奇数。我想在加速后端执行这个功能,所以如果我理解正确,它需要变成Exp Int -> Exp Int类型。但是,出于性能原因,该库不允许在 Exp 中评估任意表达式。幸运的是,我只需要为小值评估这个函数,例如n

1) 有没有办法做到这一点,即定义一个硬编码数组,然后对其进行索引以在Exp a -> Exp b 类型的函数中检索适当的值?

2) 我是否以有效的方式处理事情?我对这个问题的看法有什么明显的缺陷吗?

更新

以下作品基于@ErikR 的回答和后续评论:

module Test where

import Data.Array.Accelerate as A
import Prelude as P

oddfac :: Exp Int -> Exp Int
oddfac n = (use $ A.fromList (Z :. 6) [1, 1, 3, 3, 15, 15]) A.! (index1 n)

alloddfac :: Acc (Vector Int)
alloddfac = A.map oddfac $ use $ A.fromList (Z :. 3) [1, 3, 5]

【问题讨论】:

你能在Exp Int上做模式匹配吗?然后你可以完全取消列表/索引。 否,这会导致运行时异常。即使它确实有效,我认为它会编译成高度分支的代码,这不是您在 Exp 计算中想要的,因为执行时间取决于输入。 【参考方案1】:

在我看来,您可以使用几种方法之一创建一个 Acc (Array DIM1 Int),然后使用 Accelerate 的 (!)index1 函数来索引数组。

请注意,Vector aArray DIM1 a 的别名。

以下是创建奇数阶乘(7 个元素)的Acc (Vector Int) 的方法:

oddfacts :: Acc (Vector Int)
-- analogous to: take 7 $ scanl (*) 1 [3,5..]
oddfacts = A.scanl (*) (constant (1::Int)) $ A.enumFromStepN (A.index1 (constant (7::Int))) (constant (3::Int)) (constant (2::Int))

这里是如何索引到它:

foo :: Exp Int -> Exp Int
foo n = oddfacts A.! (A.index1 n)

以及如何将它与条件一起使用:

bar :: Exp Int-> Exp Int
bar n = (n <=* (constant (7::Int))) ?
           ( oddfacts A.! (A.index1 n)
           , constant (0::Int)           -- return 0 if n > 7
           )

警告 - 我实际上并没有运行此代码,但它会进行类型检查。

accelerate-examples 包中的示例有很多使用数组生成函数(A.generate、A.scanl 等)和索引函数(A.index1、A.index2 等)的代码

【讨论】:

我认为这行不通,因为该库不允许程序员在 Exp 表达式中生成 Acc 计算。它将进行类型检查,但会导致运行时错误。我认为库编写者这样做的原因是为了防止嵌套数据并行表达式的执行,这将很难有效地运行,例如GPU。 hmmm... 你能像nofib 示例那样使用A.use $ A.fromList ... 对值进行硬编码吗?例如this code 看起来你遇到了同样的问题,因为 A.fromList 返回一个 Acc 数组,你不能将它嵌入到 Exp 计算中...... 你可以清楚地使用A.!在 Acc 计算中。例如参见pagerank example。请注意ranks ! ... 表达式是Exp Float。也许您想要做的更详细的示例会有所帮助,这样我们就可以实际尝试编写代码并运行它。【参考方案2】:

您可以从 Haskell 中“越过栅栏”进入Exp 任意数组,通过 (Shape sh, Elt e) =&gt; Lift Acc (Array sh e) 实例。因此,您可以在 Haskell 中创建查找表,然后只需 lift 它:

import Data.Array.Accelerate as A hiding (product)

oddfac :: Int -> Int
oddfac n = product [1,3..n]

oddfacs :: Vector Int
oddfacs = A.fromFunction (Z :. 7) (\(Z :. i) -> oddfac i)

lut :: Acc (Vector Int)
lut = A.lift oddfacs

其余的可以通过@ErikR 的答案,通过索引查找表lut 来实现。

【讨论】:

以上是关于haskell中的查找表加速的主要内容,如果未能解决你的问题,请参考以下文章

Haskell 中的大规模设计? [关闭]

Haskell 加速复制矩阵

Haskell Accelerate 中的 Exp a -> a

如何查找Haskell名称的包,版本和文档

编写一次并行数组 Haskell 表达式,在 CPU 和 GPU 上运行 repa 并加速

如何正确使用haskell中的长度函数?