Sobol 序列并行化的实践经验

随机数发生器并行化的常见策略

随机数发生器的并行化通常有四种策略(文献【2】):

  1. “随机化”种子
  2. 参数化随机数发生器
  3. 分块策略
  4. 蛙跳策略

“随机化”种子

“随机化”种子就是让每个线程上运行的发生器使用不同的种子,这种策略常见于伪随机数。不过,使用不同随机数种子的发生器所产生的随机数是否依然保持统计意义上的独立性,这一点是未知的。

参数化随机数发生器

某些随机数发生器可以采用不同的参数配置,例如最简单的线性同余发生器,让每个线程运行不同参数配置的发生器就可以实现并行化。不过,这种策略和“随机化”种子有相同的安全隐患,无法确保产生的随机数依然保持统计意义上的独立性。另外,即使保持了独立性,可用的参数配置组合可能数量十分有限,无法充分发挥硬件的并行优势。

分块策略

要确保产生的随机数保持统计意义上的独立性,最简单的办法就是使用一个发生器,在不同的线程上返回不同的数字。要做到这一点可以采用分块生成的策略,下面举个例子。

无论是伪随机还是拟随机,发生器产生的随机数的顺序是不变的。假设要在 4 个线程上并行发生 10000 个随机数,分块策略就是让第 1 个线程返回第 1~2500 个随机数;第 2 个线程返回第 2501~5000 个随机数;第 3 个线程返回第 5001~7500 个随机数;第 4 个线程返回第 7501~10000 个随机数。

分块策略要求发生器必须有一个“长距离跳转”的功能,而且要保证计算成本尽量低。

蛙跳策略

想要使用一个发生器在不同的线程上返回不同的数字,还可以采用“蛙跳”的策略,下面举个例子。

假设要在 4 个线程上并行发生 10000 个随机数,蛙跳策略就是让第 1 个线程返回第 \(4k\) 个随机数;第 2 个线程返回第 \(4k + 1\) 个随机数;第 3 个线程返回第 \(4k + 2\) 个随机数;第 4 个线程返回第 \(4k + 3\) 个随机数。

同分块策略相比,每个线程上产生的数字是间隔开的,跳转步长等于线程数。

因为要多次跳转,蛙跳策略要求发生器必须有一个“极低成本”的“短距离跳转”的功能。

Sobol 序列的原理和跳转功能

Sobol 序列的产生依赖于一组事先确定“方向数”——\(m\),以及“异或”运算。对于多维 Sobol 序列,每个维度有各自的方向数。

Sobol 序列的发生可以表示为非递归和递归两种形式:

  • 非递归形式:\(y_n = g_1 m_1 \oplus g_2 m_2 \oplus g_3 m_3 \oplus \cdots\)
  • 递归形式:\(y_n = y_{n-1} \oplus m_{f(n-1)}, y_0 = 0\)

其中 \(\oplus\) 表示异或运算;\(g_i\) 是 \(n\) 的 Gray 码的二进制表示,\(n\) 的 Gray 码等于 \(n \oplus (n/2)\),而 \(n \oplus (n/2) = \dots g_3 g_2 g_1\);\(f(n)\) 表示 \(n\) 的二进制编码中最右侧的 0 所在的位数。

若采用 32 位整数,\(x_n = 2^{-32} y_n\),\(x_n\) 就是服从单位均匀分布的 Sobol 序列。

非递归形式表明 Sobol 序列有低成本的长距离跳转功能,因为若采用 32 位整数,直接计算 \(y_n\) 至多进行 32 次异或计算。计算 Sobol 序列的程序通常都会提供一个 skipTo 函数,实现长距离跳转。

Sobol 序列并行化实践

随机数的并行化要求精准的操作线程,因此在最常见的“单机多核”情形下可以采用 OpenMP 框架。

分块策略

假设已经具备了单线程上的 Sobol 序列发生器 SobolRsg,可以构造一个复合对象 OmpSobolRsg,内部包含 \(N\) 个完全相同的 SobolRsg 对象。在集中调用之前,事先告知 OmpSobolRsg 未来要调用的次数 \(M\),将 \(N\) 个 SobolRsg 对象分别跳转到合适的位置,第 \(i\) 个 SobolRsg 对象将专门在第 \(i\) 个线程上调用。这样就实现了 Sobol 序列的并行发生。

借助 OpenMP 框架,上述设计很容易实现,实现细节不赘述。

蛙跳策略

在蛙跳策略下,需要对 SobolRsg 对象稍加改造,以便实现从 \(y_{n}\) 直接到 \(y_{n+N}\) 的递归。和分块策略类似,需要构造一个复合对象 OmpSobolRsg,内部包含 \(N\) 个完全相同的 SobolRsg 对象。无需事先告知未来要调用的次数,只需初始化阶段将 \(N\) 个 SobolRsg 对象分别跳转,恰好错开一步。第 \(i\) 个 SobolRsg 对象将专门在第 \(i\) 个线程上调用。这样就实现了 Sobol 序列的并行发生。

借助 OpenMP 框架,上述设计也很容易实现,实现细节不赘述。

蛙跳策略的计算量分析

回想递归形式,在单线程情况下要生成 \(K\) 维的 Sobol 序列,需要进行 \(K\) 次整数间的异或计算,以及 \(K\) 次浮点数除法计算。蛙跳策略中的跳转则会触发若干次异或计算,当线程数量增多时,势必会增加计算量,削弱并行化的效果。

减少异或计算的技巧

依据递归形式,跳转 \(N\) 步的话有如下递归表达式:

\[y_n = y_{n-N} \oplus m_{f(n-N)} \oplus \cdots \oplus m_{f(n-2)} \oplus m_{f(n-1)}
\]

在原始情况下,跳转 \(N\) 步将发生 \(N\) 次异或计算。但根据 \(f(n)\) 的定义,\(m_{f(n-i)}\) 中可能有不少重合的数字。

与此同时,注意到异或计算的几个性质:

  • \(a \oplus b = b \oplus a\)
  • \(a \oplus (b \oplus c) = (a \oplus b) \oplus c\)
  • \(a \oplus a = 0\)
  • \(a \oplus 0 = a\)
  • \(0 \oplus 0 = 0\)

也就是说,偶数个 \(m\) 可以归并为 0,而 0 是可以忽略的。如果某个数字 \(m\) 出现了偶数次,可以直接忽略;如果某个数字 \(m\) 出现了奇数次,只保留一次就可以了。文献【1】中就举了这样的例子,跳转 \(2^p\) 步只需 2 次异或计算。

尽管如此,同分块策略相比蛙跳策略避免不了频繁跳转,也就避免不了多余的异或计算,这可能会导致并行 Monte Carlo 模拟的加速效率大打折扣。

分块策略不算缺点的缺点

和蛙跳策略相比,分块策略避免了反复跳转,但要求事先告知要调用的次数,这一点和随机数发生器通常的使用模式相背离。但是瑕不掩瑜,分块策略可以获得更好地加速比。笔者分别采用分块和蛙跳策略并行化了 QuantLib 的 Monte Carlo 定价框架,在 8 核 CPU 上,分块策略的加速比在 7 倍左右,而蛙跳策略的加速比在 5.4 倍左右。

图中可以看到,当线程数较少时,两种策略难分伯仲;但当线程数较多时,蛙跳策略的加速效率明显下降,这是频繁跳转造成的拖累。

参考文献

  • 【1】Parallelisation Techniques for Random Number Generators
  • 【2】Tina's Random Number Generator Library

Sobol 序列并行化的实践经验的更多相关文章

  1. CI Weekly #6 | 再谈 Docker / CI / CD 实践经验

    CI Weekly 围绕『 软件工程效率提升』 进行一系列技术内容分享,包括国内外持续集成.持续交付,持续部署.自动化测试. DevOps 等实践教程.工具与资源,以及一些工程师文化相关的程序员 Ti ...

  2. 根据实践经验,讲述些学习Java web能少走的弯路,内容摘自java web轻量级开发面试教程

    在和不少比较上进的初级程序员打交道的过程中,我们总结出了一些能帮到合格程序员尽快进阶的经验,从总体上来讲,多学.多实践不吃亏.本文来是从 java web轻量级开发面试教程从摘录的. 1  哪些知识点 ...

  3. 华为云对Kubernetes在Serverless Container产品落地中的实践经验

    华为云容器实例服务,它基于 Kubernetes 打造,对最终用户直接提供 K8S 的 API.正如前面所说,它最大的优点是用户可以围绕 K8S 直接定义运行应用. 这里值得一提是,我们采用了全物理机 ...

  4. 关于Flask使用Celery的实践经验分享

      最近大Boss反馈Celery经常出现问题,几经实践终于把问题解决了!于是乎有了这篇博客的诞生,算是一个实践经验的分享吧! 软件版本如下: Celery () Flask () RabbitMQ( ...

  5. 领域驱动设计(DDD)的实践经验分享之ORM的思考

    原文:领域驱动设计(DDD)的实践经验分享之ORM的思考 最近一直对DDD(Domain Driven Design)很感兴趣,于是去网上找了一些文章来看看,发现它确实是个好东西.于是我去买了两本关于 ...

  6. 领域驱动设计(DDD)的实践经验分享之持久化透明

    原文:领域驱动设计(DDD)的实践经验分享之持久化透明 前一篇文章中,我谈到了领域驱动设计中,关于ORM工具该如何使用的问题.谈了很多我心里的想法,大家也对我的观点做了一些回复,或多或少让我深深感觉到 ...

  7. 在单体应用的一些DDD实践经验

    阅读此文需要一定的DDD基础,如果你是第一次接触DDD读者,建议先去阅读一些DDD相关的书籍或者文章之后再来阅读本文. 背景 自从我在团队中推行DDD以来,我们团队经历了一系列的磨难--先是把核心项目 ...

  8. Java小白如何一步步学好Java,听听企业Java培训师的实践经验吧

    今天我准备给小主展示一篇Java培训老师的文章,希望能给Java小白一个学好Java的路径或者提示.以下就是原文: 从大学到现在,我使用Java已经将近20年,日常也带实习生,还在公司内部做train ...

  9. FreeWheel基于Go的实践经验漫谈——GC是大坑(关键业务场景不用),web框架尚未统一,和c++性能相比难说

    摘自:http://www.infoq.com/cn/news/2017/06/freewheel-experience-on-go Go语言是FreeWheel公司目前主要力推的一个方向,在其看来, ...

随机推荐

  1. 【流程】Flowable流程定义总结

    背景 近几年,互联网企业从消费互联网向产业互联网转型.在消费互联网时期,企业面对的时C端消费者,而产业互联网面对的是B端用户. 产业互联网涉及方方面面,企业信息化的建设就是B端用户的业务之一,在企业就 ...

  2. noip模拟18

    \(\color{white}{\mathbb{曲径通幽,星汉隐约,缥缈灯影,朦胧缺月,名之以:薄雾}}\) 放眼望去前十被我弃掉的 \(t2\) 基本都上85了-- 开考就以为 \(t2\) 是个大 ...

  3. Robot Framework(7)- DateTime 测试库常用的关键字列表

    如果你还想从头学起Robot Framework,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1770899.html 前言 所有关键字 ...

  4. window创建l2tp

    windows上创建一个L2TP的隧道连接 进入控制面板,打开"网络和共享中心",如下图,之后点击"设置新的连接或网络" 进入到"设置连接或网络&qu ...

  5. 全网唯一正常能用的centos7 安装mysql5.7.35 22 33 25

    CentOS7.4用yum安装并配置MySQL5.7   1.配置YUM源 下载MySQL源安装包 wget http://dev.mysql.com/get/mysql57-community-re ...

  6. Learning How to Learn 学习如何学习

    Introduction 这是 UCSD 开设在 Coursera 上的课程 Learning How to Learn 的课程笔记.这门课程主要基于神经科学和认知心理学的一些研究成果讲述高效学习的理 ...

  7. Python中with...as...的用法详解

    简介 with是从Python2.5引入的一个新的语法,它是一种上下文管理协议,目的在于从流程图中把 try,except 和finally 关键字和资源分配释放相关代码统统去掉,简化try-.exc ...

  8. 关于goto

    (下面一段来源<征服C指针>) 75: ReadLineStatus read_line(FILE *fp, char **line) 76: { 77: int ch; 78: Read ...

  9. 解决idea debugger Frames are not available

    现象:idea2017.3.7 sofaboot项目debugger报错 Frames are not available. 之前好用,不知道为啥突然不能debugger,run能正常运行代码.如下图 ...

  10. git pull 时remote: HTTP Basic: Access denied解决方案

    当qian windows用户密码过期更改了密码后,操作git pull 拉取远程仓库代码或git push时报错 如下:remote: HTTP Basic: Access denied  Auth ...