在Python中重新生成随机向量

4

我想生成和再生一个随机正态向量的矩阵。

我希望通过生成100x3大小的随机正态矩阵,并具有均值为0和标准差为1的随机正态数,实现以下目标:

seed1 = '123'
seed2 = 'asd'
randMatrixrows = 100
randMatrixcols = 3
mu = 0
sd = 1

normRand1 = rekina_normRandomGenerator( seed1, randMatrixrows, randMatrixcols, mu, sd ) #normRand1 is of size 100x3
normRand2 = rekina_normRandomGenerator( seed2, randMatrixrows, randMatrixcols, mu, sd )
normRand3 = rekina_normRandomGenerator( seed1, randMatrixrows, randMatrixcols, mu, sd )
normRand4 = rekina_normRandomGenerator( seed2, randMatrixrows, randMatrixcols, mu, sd )

err1 = normRand1 - normRand3
err2 = normRand2 - normRand4

err1和err2的每个元素都应该为0。

我尝试阅读过,但由于对Python还很陌生,对实现完全感到困惑。我期望看到一个简单的实现来展示如何使用CBRNG。


我对reikna不是很了解,但每次生成随机内容时,它不都会不同吗?为什么需要将err1和err3设置为0? - Sagar Waghmode
@Sagar 在编程中,伪随机数生成器通过种子控制所谓的“随机”数字,这些数字是完全确定性的。拥有可重复的“随机”数字在测试等方面非常有用。 - Ilja Everilä
谢谢@Ilja,我会仔细阅读的。 - Sagar Waghmode
1个回答

3
您的初始假设是需要使用 reikna.cbrng.CBRNG,这是正确的。它似乎提供了多种基于计数器的 RNG 的伪随机源分布,这可能会让人感到困惑。它还提供了快捷方式,用于创建具有给定分布的随机数生成器。请注意,文本中保留了 HTML 标签。
from reikna.core import Type
from reikna.cbrng import CBRNG
from reikna.cluda import any_api
import numpy as np

# Get any supported API for this system, or an exception    
_api = any_api()
# The global CLUDA Thread, wrapping context, shared by all
# reikna_norm_rng's
_thr = _api.Thread.create()


def reikna_norm_rng(seed, rows, cols, mean, std,
                    dtype=np.float32,
                    generators_dim=1):
    """
    A do-all generator function for creating a new Computation
    returning a stream of pseudorandom number arrays.
    """
    # The Type of the output array
    randoms_arr = Type(dtype, (rows, cols))
    # Shortcut for creating a Sampler for normally distributed
    # random numbers
    rng = CBRNG.normal_bm(randoms_arr=randoms_arr,
                          generators_dim=generators_dim,
                          sampler_kwds=dict(mean=mean, std=std),
                          # Reikna expects a positive integer. This is a 
                          # quick and *dirty* solution.
                          seed=abs(hash(seed)))
    compiled_comp = rng.compile(_thr)
    # RNG "state"
    counters = _thr.to_device(rng.create_counters())
    # Output array
    randoms = _thr.empty_like(compiled_comp.parameter.randoms)

    while True:
        compiled_comp(counters, randoms)
        yield randoms.get()

要看到它的效果,请添加:

if __name__ == '__main__':
    seed1 = '123'
    seed2 = 'asd'
    rows, cols = 100, 3
    mu, sd = 0, 1

    # This will create a new RNG, take 1 result and throw the RNG away
    r1 = next(reikna_norm_rng(seed1, rows, cols, mu, sd))
    r2 = next(reikna_norm_rng(seed2, rows, cols, mu, sd))
    r3 = next(reikna_norm_rng(seed1, rows, cols, mu, sd))
    r4 = next(reikna_norm_rng(seed2, rows, cols, mu, sd))

    err1 = r1 - r3
    err2 = r2 - r4

    print("all(err1 == 0):", np.all(err1 == 0))
    print("all(err2 == 0):", np.all(err2 == 0))

我也希望确保使用两个不同的种子生成的随机数没有相关性。 这取决于实现的质量。以下是使用种子0和1绘制出的2组数字的情况:
rng1 = reikna_norm_rng(0, 100, 10000, 0, 1)
rng2 = reikna_norm_rng(1, 100, 10000, 0, 1)
A = next(rng1)
B = next(rng2)
A_r = A.ravel()
B_r = B.ravel()
for i in range(0, A_r.size, 1000):
    plot(A_r[i:i+1000], B_r[i:i+1000], 'b.')

绘制(A, B)

免责声明

这是我第一次使用reikna。上述代码可能无法及时释放资源和/或泄漏像筛子一样。它使用全局Thread,这在较大的应用程序中可能不是您想要的。

附言

np.random.seed(seed)
np.random.normal(0, 1, (100, 3))

还可以生成形状为 (100, 3) 的正态分布随机数数组,尽管它不使用GPU。


以上代码可能无法及时释放资源和/或泄漏得像筛子一样。它使用了一个全局线程,这在较大的应用程序中可能不是您想要的。 - Zanam
一般来说,我相信Python对象在被垃圾回收时会释放资源等,但这个GPU的东西对我来说有点陌生,所以我不太确定是否应该手动释放这些缓冲区。可能不需要。 - Ilja Everilä
在一个更大的应用程序中,您可能会重构 reikna_norm_rng,使其接受应用程序提供的线程实例而不是模块作用域全局变量。这样可以更容易地进行测试,并且通常会更加模块化。 - Ilja Everilä
@Zanam 关于 seed=abs(hash(seed)) 的注释:numpy 1.11 已经改变了种子处理方式,不再默默地将给定的种子模除 2**32,而是会引发异常(我刚刚遇到了这个问题)。因此,如果不是非常关键的话,要么将种子更改为从给定种子生成适当的 32 位种子,要么自己执行 seed=abs(hash(seed)) % 2**32。Reikna 使用 numpy 的 PRNG 来创建 CBRNG 的密钥。 - Ilja Everilä

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接