我正在尝试使用多处理数组类型在进程之间共享可写对象。我已经阅读了很多有关这样做的警告,但是由于物理内存的限制,我认为在我的应用程序中有必要这样做。
使用Array似乎会导致一些精度损失,但是我不太清楚。这是一个可重现的示例,该示例比较了通过多处理数组(带锁)直接对一系列随机数组求和的结果:
import numpy as np
from joblib import Parallel, delayed
from multiprocessing import Pool, Array
# Initialize multiprocessing Array and numpy view
n = 100
m = 100
num_reps = 100
arr = Array('d', n*m)
shared_result = np.ctypeslib.as_array(arr.get_obj()).reshape(n,m)
# Function to add random arrays to multiprocessing array
def adder(i,shared_res=shared_result,arr=arr):
tmp = np.random.rand(n,m)
with arr.get_lock():
shared_result[:,:] += tmp
return tmp
if __name__ == '__main__':
with Parallel(n_jobs=10) as parallel:
tst = parallel(delayed(adder)(k) for k in range(num_reps))
# Compare results from multiprocessing Array vs. explicit sum
print(np.mean(shared_result - sum(tst)))
这将产生:
9.73443547991e-17
我预计为0。这里是否存在一些精度问题?
更新:看来问题出在Parallel
上。如果不使用
tst = [adder(k) for k in range(num_reps)]
print(np.mean(np.abs(shared_result - sum(tst))))
如下面abarnert所建议的,您得到0。那么,在Parallel中进行酸洗会降低精度吗?
答案 0 :(得分:1)
原始数据的大小为0到1。您的误差约为1e-16。
这完全正常,因为64位浮点数大约有15个有效数字。因此,在进行幅度为0.5的计算时,可能会出现1e-16的误差。
关于使用进程间通信时为什么不会发生错误的原因,可能是因为您的本地CPU使用80位内部浮点格式(因为x87一直这样做),而在进程之间发送的浮点数却是将被限制为64位精度。
有一些特殊技术可以更精确地求和浮点数集。这是一个:https://en.wikipedia.org/wiki/Kahan_summation_algorithm