位生成器#
Generator 生成的随机值来源于 BitGenerator.BitGenerator 不直接提供随机数,仅包含用于设定种子,获取或设置状态,跳转或推进状态的方法,以及用于访问底层封装器的代码, 以供能高效访问所提供函数的代码使用,例如 numba .
受支持的位生成器#
包含的位生成器有:
PCG-64 - 默认值.一种可以按任意数量推进的快速生成器.请参阅
advance的文档.PCG-64 的周期为 \(2^{128}\) .有关此类 PRNG 的更多详细信息,请参阅 PCG author’s page .PCG-64 DXSM - PCG-64 的升级版本,在并行上下文中具有更好的统计特性.有关这些改进的更多信息,请参阅 使用 PCG64DXSM 升级 PCG64 .
MT19937 - 标准 Python 位生成器.添加了一个
MT19937.jumped函数,该函数返回一个新的生成器,其状态如同已进行了 \(2^{128}\) 次抽取.Philox - 一种基于计数器的生成器,能够推进任意数量的步数或生成独立的流.有关此类位生成器的更多详细信息,请参阅 Random123 页面.
SFC64 - 一种基于随机可逆映射的快速生成器.通常是四者中最快的生成器. 有关更多(少量)详细信息,请参阅 SFC author’s page .
|
通用 BitGenerator 的基类,它基于不同的算法提供随机位流. |
设定种子和熵#
BitGenerator 提供一个随机值流.为了生成可重现的流,BitGenerator 支持通过种子设置其初始状态.所有提供的 BitGenerator 都将采用任意大小的非负整数或此类整数列表作为种子.BitGenerator 需要获取这些输入并将其处理为 BitGenerator 的高质量内部状态.numpy 中的所有 BitGenerator 都将该任务委托给 SeedSequence ,后者使用哈希技术来确保即使是低质量的种子也能生成高质量的初始状态.
from numpy.random import PCG64
bg = PCG64(12345678903141592653589793)
SeedSequence 旨在方便实现最佳实践.我们建议随机程序默认使用来自操作系统的熵,以便每次运行都不同.该程序应打印或记录该熵.为了重现过去的值,该程序应允许用户通过某种机制(命令行参数很常见)提供该值,以便用户可以重新输入该熵以重现结果.除了与用户通信之外, SeedSequence 可以处理所有事情,这取决于您.
from numpy.random import PCG64, SeedSequence
# Get the user's seed somehow, maybe through `argparse`.
# If the user did not provide a seed, it should return `None`.
seed = get_user_seed()
ss = SeedSequence(seed)
print(f'seed = {ss.entropy}')
bg = PCG64(ss)
我们默认使用从操作系统收集的熵的 128 位整数.这是初始化我们在 numpy 中拥有的所有生成器的一个很好的熵量.我们不建议在一般用途中使用低于 32 位的小种子.仅使用一小组种子来实例化更大的状态空间意味着某些初始状态无法达到, 如果每个人都使用这样的值,这会造成一些偏差.
结果本身不会有什么问题;即使种子为 0,由于 SeedSequence 的处理,也是完全可以的. 如果您只需要一些固定值来进行单元测试或调试,请随意使用您喜欢的任何种子. 但是,如果您想从结果中进行推断或发布它们,从更大的种子集中抽取是一个很好的做法.
如果您需要“离线”生成一个好的种子,那么 SeedSequence().entropy 或使用标准库中的 secrets.randbits(128) 都是便捷的方法.
如果您需要并行运行几个随机模拟,最好的做法是为每个模拟构造一个随机生成器实例. 为了确保随机流具有不同的初始状态,您可以使用 SeedSequence 的 spawn 方法. 例如,这里我们构造一个包含 12 个实例的列表:
from numpy.random import PCG64, SeedSequence
# High quality initial entropy
entropy = 0x87351080e25cb0fad77a44a3be03b491
base_seq = SeedSequence(entropy)
child_seqs = base_seq.spawn(12) # a list of 12 SeedSequences
generators = [PCG64(seq) for seq in child_seqs]
如果您已经有一个初始的随机生成器实例,您可以使用 spawn 方法来缩短上面的代码:
from numpy.random import PCG64, SeedSequence
# High quality initial entropy
entropy = 0x87351080e25cb0fad77a44a3be03b491
base_bitgen = PCG64(entropy)
generators = base_bitgen.spawn(12)
另一种方法是使用 SeedSequence 可以用元素元组初始化的事实. 这里我们使用一个基本熵值和一个整数 worker_id
from numpy.random import PCG64, SeedSequence
# High quality initial entropy
entropy = 0x87351080e25cb0fad77a44a3be03b491
sequences = [SeedSequence((entropy, worker_id)) for worker_id in range(12)]
generators = [PCG64(seq) for seq in sequences]
请注意,后一种方法产生的序列将与通过 spawn 构造的序列不同.
|
SeedSequence 以可重现的方式混合熵源,从而为独立且很可能不重叠的 BitGenerator 设置初始状态. |