并行与分布式系统中的并行随机采样:拒绝采样(Rejection Sampling)的并行化算法
题目描述
在统计学、机器学习和科学计算中,拒绝采样 是一种从复杂概率分布中生成随机样本的基本方法。其核心思想是:假设我们希望从目标分布 \(p(x)\) 中采样,但 \(p(x)\) 难以直接采样,而存在一个易于采样的参考分布(或称提议分布) \(q(x)\),满足 \(p(x) \leq M \cdot q(x)\) 对所有 \(x\) 成立,其中 \(M\) 是一个常数。传统的拒绝采样算法串行执行,每次迭代独立生成候选样本并决定接受与否,因此天然适合并行化。然而,并行化时需解决两个关键问题:
- 负载均衡:由于接受候选样本是随机事件,各处理单元(进程/线程)可能产生不同数量的有效样本。
- 样本顺序:在需要保持样本顺序(如用于马尔可夫链蒙特卡洛中的后续处理)时,并行生成样本的顺序需妥善处理。
本题要求设计一个并行拒绝采样算法,实现在分布式内存环境下高效生成大量独立样本,并确保结果的正确性与负载均衡。
解题过程循序渐进讲解
步骤1:回顾串行拒绝采样算法原理
串行拒绝采样的步骤如下:
- 选择一个易于采样的提议分布 \(q(x)\) 和常数 \(M\),使得 \(p(x) \leq M \cdot q(x)\) 对所有 \(x\) 成立。
- 重复以下过程直至获得足够样本:
a. 从 \(q(x)\) 中抽取候选样本 \(x\)。
b. 从均匀分布 \(U(0,1)\) 中生成随机数 \(u\)。
c. 若 \(u \leq \frac{p(x)}{M \cdot q(x)}\),则接受 \(x\) 作为一个有效样本;否则拒绝。
这个算法接受概率为 \(1/M\),因此较小的 \(M\) 可提高效率,但必须满足覆盖条件。
并行化挑战:步骤2的每次迭代独立,可并行执行。但接受候选样本是随机事件,各处理器产生的有效样本数不均衡。此外,在分布式环境下,需收集各处理器样本并合并。
步骤2:设计基础并行框架(主从模型)
一个简单并行方案是采用主从模型:
- 主进程:负责任务分配、结果收集与全局样本计数。
- 从进程:每个从进程独立执行串行拒绝采样,直到本地生成了指定数量的样本。
但此方案存在明显问题:各从进程完成时间可能差异巨大(因为每个进程需等待本地生成足够样本,而生成速度受随机接受事件影响)。改进思路是让主进程动态分配“生成候选样本”的任务,而非固定样本数。
步骤3:任务划分与动态负载均衡
为平衡负载,将采样任务划分为“生成候选样本”的小批量任务。每个任务包含:
- 生成 \(B\) 个候选样本(\(B\) 为批量大小)。
- 对每个候选执行接受/拒绝判断。
- 返回该批次中接受的样本。
算法流程:
- 主进程维护一个全局样本计数 \(G\),初始为0,目标为 \(N\)。
- 主进程向空闲从进程发送“生成一批样本”的请求。
- 从进程收到请求后:
a. 生成 \(B\) 个独立候选样本(从 \(q(x)\) 采样)。
b. 对每个候选生成均匀随机数 \(u\),判断是否接受。
c. 将本批次接受的所有样本发送回主进程。 - 主进程收到一批样本后:
a. 将样本存入全局缓冲区,更新 \(G\)。
b. 若 \(G < N\),继续向该从进程发送新请求;否则发送终止信号。
此方法确保了各从进程持续工作直到全局样本数足够,有效平衡负载。
步骤4:随机数生成与可重复性
并行随机数生成需确保各进程的随机数序列独立且不重叠,避免样本相关性。常用方法:
- 每个进程用不同的随机数种子(例如,进程ID为种子偏移)。
- 采用可跳跃的随机数生成器(如跳步的线性同余生成器)。
为可重复性,种子和随机数生成器参数需全局一致。
步骤5:处理样本顺序要求
如果应用要求保持样本的全局顺序(例如,样本用于构建时间序列),则需为每个接受的样本分配一个全局唯一且递增的序号。实现方法:
- 主进程维护一个全局计数器 \(C\),初始为0。
- 当主进程收到一批样本时,按接收顺序依次为样本分配序号 \(C, C+1, \dots\),并更新 \(C\)。
- 由于网络延迟,样本到达顺序可能不同于生成顺序,但主进程分配的序号即确定了最终顺序。
步骤6:优化通信与批量大小
批量大小 \(B\) 影响性能:
- 过小的 \(B\) 导致频繁通信,增加延迟。
- 过大的 \(B\) 可能导致负载不均衡(某些进程完成大批量任务时,其他进程可能已空闲)。
自适应批量大小策略:主进程根据历史完成时间动态调整 \(B\),例如,若样本接受率较低,则增大 \(B\) 以减少通信次数。
步骤7:分布式版本(无中心主进程)
为消除主进程瓶颈,可采用完全分布式设计:
- 每个进程独立生成候选样本,判断接受/拒绝,并将接受的样本存储在本地缓冲区。
- 当本地缓冲区满时,进程与随机选择的其他进程交换样本,以均衡各进程持有样本数。
- 最终,所有进程同步,汇总样本数,若不足则继续迭代。
该方法适合大规模分布式环境,但实现复杂,需注意缓冲区管理和进程间通信协议。
步骤8:算法伪代码(主从模型)
以下是主从模型的伪代码,包含动态任务分配与样本排序:
主进程:
Initialize: global_count = 0, next_id = 0
For each slave process p:
Send (REQUEST, batch_size) to p
While global_count < N:
Receive (ACCEPTED_SAMPLES, samples) from any slave p
For each sample in samples:
Assign sample_id = next_id
next_id += 1
Store sample with sample_id
global_count += len(samples)
If global_count < N:
Send (REQUEST, batch_size) to p
Else:
Send (TERMINATE) to p
Wait for all slaves to terminate
从进程:
Loop:
Receive message from master
If message is TERMINATE: break
Let B = batch_size from message
accepted_samples = empty list
For i = 1 to B:
x = sample from q(x)
u = uniform(0,1)
if u <= p(x) / (M * q(x)):
accepted_samples.append(x)
Send (ACCEPTED_SAMPLES, accepted_samples) to master
步骤9:性能考虑与扩展
- 通信开销:批量大小 \(B\) 应使通信时间远小于计算时间。
- 容错:若在长时运行中进程可能失败,需加入超时重发机制。
- 混合并行:每个从进程可使用多线程进一步并行化候选样本生成与判断。
总结
并行拒绝采样的核心是将独立的采样任务动态分配给各处理器,并通过批量任务和动态负载均衡来应对接受率随机性带来的负载不均。在需要样本顺序的场景,由主进程统一分配序号即可。该算法可显著加速从复杂分布中采样,适用于蒙特卡洛模拟、贝叶斯推断等大规模科学计算。