用于组合分析的 GPGPU/FPGA 编程

计算科学 并行计算 数据分析 可能性 组合学
2021-12-01 07:54:35

最近,我对执行 21(二十一点)游戏的组合分析感兴趣,并尝试使用我的 AMD APU 尝试通过芯片上的 4 个内核对程序进行线程化。生成正确的策略和期望已被证明是成功的,并且只需几秒钟(大约 12 秒)即可计算出任何给定规则和套牌组合的最佳策略。然而,在计算其他套牌组合时,计算所有套牌状态需要 12.63 年……对于单个套牌。因此,另一种方法是通过蒙特卡洛方法模拟随机甲板子集的选择限制。这会奏效!但是,每次分析 12 秒是一个巨大的瓶颈!随机选择 10E6 个子集大约需要 139 天。即使使用线程,我当前的 CPU 也不可行。

关于我如何分析策略图表的入门:

1.) 我首先通过为玩家获取一组 n_cards 并列举所有可能的庄家手牌来计算对站立的总体期望是什么。我将每个特定经销商总数的结果与玩家手牌的当前手牌总数进行比较。

2.) 然后我通过选择玩家手组 {23} 并为 x:2->A 找到匹配的手组来计算击球期望,这样我们就可以计算击球到 {232}、{233} 的加权期望, {234},...,{23A}。我们首先计算所有硬 21,然后计算硬 20……直到所有硬 12;然后通过计算击中所有软 21 到软 13 来做同样的事情;然后计算所有硬 11 到硬 5;最后,我们计算击中所有对子牌({22}、{33}、...、{TT}、{AA}。)

3.) 加倍与击中相同,只是我们只抽一张牌并代表任何 2_card 玩家手牌。我们将抽牌的期望返回给特定的 3_card 手,并将期望乘以抽牌概率的 2 倍。

4.) 对于拆分,我们将执行步骤 1.) 到 3.),我们将重复 1->3 最多 11 次。为什么?我们通过删除我们要拆分的排名来计算拆分到新手的期望。(例如:我们想要拆分 {22}。我们将计算给定甲板子集的站立、击球、加倍,减去我们要拆分的排名之一。如果我们最初将 {22} 拆分为 {4 4 的甲板子集4 4 4 4 4 4 16 4: 2-A} 或 {3 1 4 3 4 4 3 1 14 3: 2-A},我们的新子集将是 {3 4 4 4 4 4 4 4 16 4: 2- A} 或 {2 1 4 3 4 4 3 1 14 3: 2-A}。)

5.) 在所有这一切之后,我们应该针对每个玩家手牌的每个可能决策的计算期望得到最优策略。

现在,我一直在研究是否有更快的方法来分析使用 GPGPU 或 FPGA/ASIC 的策略。我首先将 GPU 编程视为一种可能的途径,但是,我不确定它是否可行,因为有 3072 个独特的玩家手部状态,这意味着将有 3072 个独特的数据结构来计算站立、击球、加倍和分裂。

尽管如此,我希望有一种方法可以执行某种形式的同时处理,其中每个期望的状态会根据规则和/或套牌状态的变化而变化。也就是说,与其对 rules/deck_state 的每次变化重新计算每个期望值,不如对每个数据点的输出有一定的依赖性。例如:我们有名为 A、B 和 C 的三个数据点。我们还有状态数据 {1 2 3}。对于每个数据点,我们拥有一个状态方程:

A = 数据[0]

B = A + 数据[1]

C = B +数据[2]

在串行处理下,我们将首先评估 A 为 1,B 为 2 加 A,C 为 3 加 B。如果我们将数据更改为 {2 2 3},则 A 为 2,B 为 4,C将是 7。在串行处理下,对于每个数据点,每个数据点需要几个周期。FPGA下有没有一种方法可以瞬间改变状态?也就是说,如果我们改变任何一个数据点,A、B、C 会在数据改变后同时改变?

如果不是,FPGA/GPGPU 处理对想要在近乎瞬间准确快速地计算大量浮点数据的程序员有什么好处?基本上,有没有一种方法可以快速计算出比 12 秒长的多线程 CPU 处理更快的二十一点游戏的最佳策略?

1个回答

我正在写一个关于将 CPU 上运行的程序移植到 GPU 或 FPGA 的一般答案。

GPU 程序(比如 CUDA)和 CPU 程序都是用 C、C++ 等高级语言编写的。因此,将 CPU 程序移植到 GPGPU 上的等效程序要容易得多。您提出的算法似乎适合移植到 GPU。它是计算密集型的、重复的。付出一些努力,您将能够实现良好的加速。

OpenCL、OneAPI (Intel) 等框架的主要目标是将 CPU 程序移植到 GPU 或 FPGA 等加速器的过程自动化。但它们仍然没有得到广泛的认可。跨问题域的自动化仍然不够好。以我个人的经验,从头开始编写 GPU 程序要容易得多。对于可以用 C 编程的人来说,这不是很困难。

FPGA 是完全不同的游戏。就像您在示例中提到的使用三个数据点的逻辑一样,可以使用两个加法器在 FPGA 中轻松实现。得到的电路是一个组合电路,因此使用适当的加法器(如提前进位),可以在现代 FPGA 上在一纳秒内执行计算。

但这需要学习诸如verilog或VHDL之类的HDL语言。这将需要很多努力。

另一种选择是等待一些框架(如 OneAPI 或 OpenCL)得到足够的改进,以便它们能够从高级语言(如 C 语言)程序生成等效的 FPGA HDL 代码。

就个人而言,我相信这不会很快发生。