我有一些代码随机初始化了一些 numpy 数组:
rng = np.random.default_rng(seed=seed)
new_vectors = rng.uniform(-1.0, 1.0, target_shape).astype(np.float32) # [-1.0, 1.0)
new_vectors /= vector_size
一切运行良好,所有项目测试都通过。
不幸的是,uniform()
返回np.float64
,尽管下游步骤只需要np.float32
,并且在某些情况下,这个数组非常大(想想数百万个 400 维的词向量)。因此,临时 np.float64
返回值暂时使用所需 RAM 的 3 倍。
因此,我将上面的内容替换为定义上应该等效的内容:
rng = np.random.default_rng(seed=seed)
new_vectors = rng.random(target_shape, dtype=np.float32) # [0.0, 1.0)
new_vectors *= 2.0 # [0.0, 2.0)
new_vectors -= 1.0 # [-1.0, 1.0)
new_vectors /= vector_size
在此更改之后,所有密切相关的功能测试仍然通过,但依赖于如此初始化的向量的远下游计算的单个远程边缘测试已开始失败。并且以非常可靠的方式失败。这是一个随机测试,在顶部情况下可以通过较大的误差范围,但在底部情况下总是失败。所以:有些事情发生了变化,但以某种非常微妙的方式发生了变化。
在这两种情况下,new_vectors
的表面值似乎分布正确且相似。再说一遍,所有功能的“特写”测试仍然通过。
因此,我很想了解这 3 行更改可能带来哪些非直观变化的理论,这些变化可能会出现在下游。
(我仍在尝试找到一个最小的测试来检测任何不同之处。如果您喜欢深入研究受影响的项目,查看成功的确切特写测试和失败的边缘测试,并在 https://github.com/RaRe-Technologies/gensim/pull/2944#issuecomment-704512389 处提交有/没有微小变化的提交。但实际上,我只是希望 numpy 专家可能会认识到一些发生不直观的事情的微小角落案例,或者提供一些可测试的相同理论。)
有什么想法、建议的测试或可能的解决方案吗?
最佳答案
保持精度和节省内存的一种方法可能是创建大型目标数组,然后使用更高精度的 block 填充它。
例如:
def generate(shape, value, *, seed=None, step=10):
arr = np.empty(shape, dtype=np.float32)
rng = np.random.default_rng(seed=seed)
(d0, *dr) = shape
for i in range(0, d0, step):
j = min(d0, i + step)
arr[i:j,:] = rng.uniform(-1/value, 1/value, size=[j-i]+dr)
return arr
可以用作:
generate((100, 1024, 1024), 7, seed=13)
您可以调整这些 block 的大小(通过step
)以保持性能。
关于python - 这些替代的 numpy `uniform` 与 `random` 结构可能有何不同?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64234383/