1
作者:Arm 工程部资深软件工程师 Kevin Mooney
OpenRNG 是一个开源随机数生成器 (RNG) 库,最初随 Arm Performance Libraries 24.04 一同发布。OpenRNG 旨在提升人工智能 (AI) 框架性能,有助于科学应用及金融软件的开发,因而广受欢迎。而在去年晚些时候,Arm 推出了 OpenRNG 的首个开源版本。
OpenRNG 可直接替代英特尔矢量统计库 (Vector Statistics Library, VSL) 的随机数生成组件,开发者从而能够更轻松地将应用移植到 Arm 平台。VSL 是 OneMKL 的一部分,专为 x86 架构处理器而设计。OpenRNG 有助于提升性能,例如与 Arm 平台上已有实现相比,OpenRNG 仅需很少的代码改动,就使 PyTorch 的 Dropout 层的性能提高了 44 倍。OpenRNG 的性能也较 C++ 标准库提高了 2.7 倍。
虽然起初的优化是针对基于 Arm 架构的系统,但我们的目标是将 OpenRNG 发展成为跨平台项目,因此我们欢迎针对任何架构的补丁。
英特尔按照知识共享许可协议向我们开放了这个接口。该许可协议使我们能够为基于 Arm 架构系统的用户实现这一功能,从而在不修改代码的情况下实现不同架构之间软件的可移植性。
源代码现已公开在 Arm 的 GitLab 上,可查阅 Arm Performance Libraries 参考指南获取相关信息。
随机数为什么实用?
随机数在各种应用中都非常重要,可用于模拟本质上不可预测的自然过程。例如,在物理学中,随机数常用于建立随机模型,模拟确定性模型无法解决的问题;在金融领域,随机数常用于模拟金融市场;在游戏中则常用于实现 AI。
物理过程和金融市场错综复杂,涉及很多输入,不可能进行完全的理解、建模和预测。而一些输入被视为随机变量,需要快速、可重复地生成;银行在计算风险敞口时,不应该因为重新运行相同的模型得到不同的随机数而发生变化。
为游戏开发 AI 时,行为动作应是不可预测的,因此要引入随机性。随机数生成的速度越快,同时生成的 AI 就越多。同样,多人游戏需要在多台设备上生成相同的随机数。不同玩家应该在同一个位置看到敌人,随机性很重要。
库里有什么?
OpenRNG 实现了多种生成器和分布方式。生成器算法可生成“看似随机”并具有某些统计特性的序列,我们将在下文进行讨论。分布方式会将序列映射到常见的概率分布概念,如高斯分布或二项分布。
OpenRNG 还提供复制和保存序列的工具,以及在不同线程间分发序列的工具。这些工具可实现高效的多线程处理和检查点等功能。
随机数生成器
OpenRNG 实现了三种类型的随机数生成器:伪随机数生成器、准随机数生成器、非确定性随机数生成器。
伪随机数生成器 (PRNG) 算法生成的数字序列在统计学上看似随机,但却能重复生成。PRNG 通常能通过很多随机性统计测试,但一旦知道当前序列中的位置,就能确定下一个数字;这就是我们说它看似随机的原因。OpenRNG 采用了多种类型的 PRNG,如线性同余生成器 (LCG)、多重递归生成器 (MRG)、梅森旋转算法(如 MT19937)和基于计数器的生成器(如 Philox)。
准随机数生成器 (QRNG) 的算法可生成低差异序列。该类工具无法通过随机性统计测试,但能生成在 n 维超立方体上均匀分布的 n 维向量,从而均匀地填充空间。OpenRNG 提供用于生成低差异序列的 SOBOL 生成器。
大多数现代硬件都配备了非确定性随机数生成器,也称真随机数生成器 (TRNG),OpenRNG 为这些生成器提供了一个接口,以便开发者访问。TRNG 可以提供高质量随机数,其序列来自于外部。TRNG 通常比 PRNG 速度慢,且序列不可再现。
我们尽力确保使用的生成器和初始化方式与 oneMKL 文档中定义的相同。这意味着,在可能的情况下,OpenRNG 和 oneMKL 之间的序列可以按位替换。
概率分布
除了实现 RNG 之外,OpenRNG 还提供了将随机序列转换为常见概率分布的便捷方法。OpenRNG 可以生成具有常见概率分布(离散和连续)的随机数。
连续分布是实数的概率分布,例如 0 和 1 之间的可表示小数。连续分布可以请求为单精度或双精度浮点数。OpenRNG 支持多种连续分布,包括均匀分布、高斯分布和指数分布。
离散分布是仅限于整数的概率分布。OpenRNG 采用了常见的离散分布,如均匀分布、泊松分布、二项分布和伯努利分布。
OpenRNG 分布生成的确切值可能与 oneMKL 的值略有不同,因为两个库之间各种操作的精度不同。
高效多线程
很多应用都需要生成长序列的随机数。多线程运行时,拥有不同的独立序列非常重要。OpenRNG 有两种不同的方法可供选择:跳过和跳跃。
跳过法让序列跳过一定数量的元素。此时效率至关重要,这种方法可以跳过很多元素,例如 2 的 32 次方的倍数,单独生成这些元素会产生大量不必要的开销。
跳跃法适用于线程交错消耗元素的情况。例如,在有 n 个线程的情况下,第 k 个线程从“全局”序列的第 k 个元素开始,则该线程序列中的第 i 个元素就是“全局”序列的第 (k + i*n) 个元素。
性能
C++ 标准库
C++ 标准库提供三种类型的生成器:线性同余生成器、梅森旋转算法生成器和带进位减法生成器。OpenRNG 未采用带进位减法生成器,而是采用了线性同余生成器和梅森旋转算法,只需稍加配置,我们就能比较 OpenRNG 和 C++ 标准库中的 MCG31 和 MT19937 实现情况。C++ 标准库和 OpenRNG 包含多种常见分布,我们选择了两种广泛使用的分布,即均匀分布和高斯分布(也称正态分布)。
下图展示了 AWS Graviton3 上使用 GCC 14 和 -O3 的基准数据。基准测试包括重复填充一个包含 5,000 个元素的缓冲区,并计算每个库在热点循环中花费的总时间的比例。我们对所选生成器和分布的所有组合重复执行了基准测试。
对于均匀分布,大部分运行时间都用于生成随机序列。组合使用 MCG31 生成器与均匀分布实现了更大地提速比,比率高达 2.73。
对于高斯分布,大部分运行时间都用于将随机序列转换为高斯分布。与 libstdc++ 相比,使用 MT19937 生成器的最大提速比为 1.88。
柱状图展示了 OpenRNG 相较于 C++ 标准库的性能优势。每个柱形的高度是使用两个库生成随机数所花时间的比率。大于 1 表示 OpenRNG 的速度更快。
PyTorch
下图显示了在 Arm 平台上使用 VSL RNG 进行 PyTorch 机器学习 (ML) 获得的优势。PyTorch 可以配置为在 Dropout 层使用 OpenRNG 的 VSL RNG,从伯努利分布中提取随机值。例如,当批次大小为 16,输入张量为 [16, 128, 3072] 时,与使用 PyTorch 中的默认 RNG 相比,顺序执行时性能提高了四倍。此外,当启用 VSL 接口时,PyTorch 会使用跳过法来并行生成随机值。如果不使用 VSL,随机值始终是按顺序生成的,没有并行。使用 16 个线程为输入张量 [16, 128, 3072] 实现并行处理可以进一步提高性能,在 Dropout 层中使用 OpenRNG 的速度比默认的速度快 44 倍左右。
柱状图展示了结合 OpenRNG 与 PyTorch 的性能优势。每个柱形的高度表示平均耗时。配置速度越快,高度越低。
欢迎提供补丁
我们很高兴能发布 OpenRNG 并涵盖了 VSL 的大部分功能,但仍有一些领域需进一步开发。目前某些功能还未实现。此外,目前所有的优化都专门针对基于 Arm 架构的系统。我们希望 OpenRNG 能成为一个跨平台项目,因此我们欢迎针对任何架构的新参考实现和性能优化补丁。如果你想提交自己的开发工作、报告错误、提交功能请求或其他任何事项,请在 GitLab 上提出问题并与我们联系。
Arm Performance Libraries 未来将继续包含 OpenRNG,并在 GitLab 中标记发布的代码。OpenRNG 仓库将保持开放,以供开发者使用。GitLab 上有贡献指南。我们已尽力确保 OpenRNG 采用 MIT 和 Apache-2.0 技术授权许可,让用户可以将源代码添加到自己的项目中,而不会受到繁琐的限制。
相关链接:
[1] Arm GitLab: https://gitlab.arm.com/libraries/openrng
[2] Arm Performance Libraries 参考指南:
https://developer.arm.com/documentation/101004/2404/Open-Random-Number-Generation--OpenRNG--Reference-Guide
[3] Arm GitLab 提问页面:
https://gitlab.arm.com/libraries/openrng/issues
[4] 贡献指南:
https://gitlab.arm.com/libraries/openrng/-/blob/main/CONTRIBUTING.md
* Arm 原创文章
全部0条评论
快来发表一下你的评论吧 !