5

我有一门课,我想用 Numba 加快速度。该类通过简单地创建具有特定种子的 NumPy 的 RandomState 实例来为每个实例使用“随机数生成器”(因此我可以稍后复制我的工作)。当我使用 Numba 的 autojit 时,我得到一个奇怪的错误,它不会出现在“常规”Python 中。

幸运的是,这种行为非常容易复制。这是一个说明错误的简单示例:

from numpy.random import RandomState
from numba import autojit

# ------- This works in "regular Python" ------------

class SillyClass1(object):
    def __init__(self, seed):
        self.RNG = RandomState(seed)
    def draw_uniform(self):
        return self.RNG.uniform(0,1)

test1 = SillyClass1(123456)

test1.draw_uniform()

# Output:
# 0.12696983303810094


# The following code -- exactly the same as above, but with the @autojit 
# decorator, doesn't work, and throws an error which I am having a hard  
# time understanding how to fix:

@autojit
class SillyClass2(object):
    def __init__(self, seed):
        self.RNG = RandomState(seed)
    def draw_uniform(self):
        return self.RNG.uniform(0,1)

test2 = SillyClass2(123456)

test2.draw_uniform()

# Output:
#
# ValueError                                Traceback (most recent call last)
# <ipython-input-86-a18f95c11a1b> in <module>()
#      10 
#      11 
# ---> 12 test2 = SillyClass2(123456)
#      13 
#      14 test2.draw_uniform()
# 
# ...
# 
# ValueError: object of too small depth for desired array

我在 Ubuntu 13.10 上使用 Anaconda 发行版。

有什么想法吗?

编辑:我找到了一种解决方法,即简单地使用 Python 的标准“random.Random”而不是 NumPys 的“numpy.random.RandomState”

例子:

from random import Random 
@autojit
class SillyClass3(object):
    def __init__(self, seed):
        self.RNG = Random(seed)
    def draw_uniform(self):
        return self.RNG.uniform(0,1)

test3 = SillyClass3(123456)

test3.draw_uniform()

# Output:
# 0.8056271362589

这适用于我的直接应用程序(尽管其他问题立即出现,万岁)。

但是,此修复不适用于我知道我需要使用 numpy.random.RandomState 的未来算法。所以我的问题仍然存在——是否有人对在 Numba 中使用 numy.random.RandomState 的原始错误和/或解决方法有任何见解?

4

1 回答 1

1

一个迟到的答案,但问题是 Numba不支持Numpy 的RandomState对象(截至 2019 年 7 月)。它也不支持使用Python 标准库设置随机状态。

但是,鉴于np.random.seedNumba 支持这一点,您可以通过将seed参数传递给函数然后调用np.random.seed(seed)其中的方法,在 jitted 函数中使用 numpy 的 PRNG。从Numba 文档

Numba 支持来自 numpy.random 模块的顶级函数,但不允许您创建单独的 RandomState 实例。使用与标准随机模块相同的算法(因此适用相同的注释),但具有独立的内部状态:从一个生成器播种或绘制数字不会影响另一个。

代码示例

import random, numba, numpy

@numba.njit
def random_func(seed: int = 1234) -> str:
    seeded_prng = numpy.random.seed(seed)
    # Do random stuff
    random_computation = numpy.random.uniform(0, 1)
    return random_computation

# Example Invocation
seed = 1337
random_result = random_func(seed)
print(random_result)

哪个应该产生:

0.2620246750155817

如果您想为每个类实例设置不同的随机状态,则需要为每个类设置一个单独的线程,因为 PRNG 与实例化它们的线程相关联。幸运的是,Numba 会自动处理这个问题,前提是每个类发生在它自己的线程中:

从 0.28.0 版本开始,生成器是线程安全和 fork 安全的。每个线程和每个进程都会产生独立的随机数流。

最后,如果您的目标是 CUDA,有许多方法可以让您直接使用启用了 GPU 的 PRNG,这可能很方便。请参阅Numba 文档中的此页面。

于 2019-07-09T04:52:11.223 回答