numpy - 浮点非确定性的原因?包括 NumPy?
问题描述
IEEE 浮点运算是确定性的,但请参阅如何使浮点计算成为确定性?对于整体浮点计算可能是不确定的一种方式:
...并行计算在执行浮点计算的顺序方面是不确定的,这可能导致跨运行的结果不精确。
两部分问题:
- 整体浮点计算怎么可能是不确定的,产生不完全相等的结果?
考虑一个单线程 Python 程序,该程序调用 NumPy、CVXOPT 和 SciPy 子例程(
scipy.optimize.fsolve()
例如 “<a href="https://scipy.github.io/old-wiki/pages/ParallelProgramming" rel="nofollow noreferrer">如果您的 numpy/scipy 是使用其中之一编译的,那么 dot() 将被计算并行(如果这更快),而无需您做任何事情。”</p>这些本机库是否曾经以引入非确定性结果的方式进行并行化?
假设:
- 相同的软件,相同的输入,在相同的硬件上。多次运行的输出应该相等。
- 如果可行,则非常希望测试进行代码重构后的输出是否相等。(是的,操作顺序的某些更改可能会使某些输出不相等。)
- 程序中的所有随机数都是伪随机数,在所有运行中以一致的方式从相同的种子中使用。
没有未初始化的值。Python 通常以这种方式是安全的,但会在
numpy.empty()
不初始化条目的情况下返回一个新数组。目前尚不清楚它在实践中的速度要快得多。所以要小心!@PaulPanzer 的测试表明它
numpy.empty()
确实返回了一个未初始化的数组,它可以轻松快速地回收最近的数组:import numpy as np np.arange(100); np.empty(100, int); np.empty(100, int) np.arange(100, 200.0); np.empty(100, float); np.empty(100, float)
为这些例程获得有用的时序测量是很棘手的!在一个
timeit
循环中,numpy.empty()
可以保持重新分配相同的一两个内存节点。时间与数组大小无关。为防止回收:from timeit import timeit timeit('l.append(numpy.empty(100000))', 'import numpy; l = []') timeit('l.append(numpy.zeros(100000))', 'import numpy; l = []')
但是将数组大小减小到原来
numpy.zeros(10000)
的 15 倍;将其减少到numpy.zeros(1000)
1.3 倍(在我的 MBP 上)。令人费解。
另请参阅: 哈希值在 Python 3 中被加盐,并且每个 dict 保留插入顺序。这可能会随着运行的不同而改变操作的顺序。[我在 Python 2.7.15 中解决这个问题。]
解决方案
我发现我遇到的大多数(不是全部)非确定性问题似乎在 OpenBLAS 0.3.5 的代码中得到了修复。
OpenBLAS 早期版本中的一堆线程问题已在 0.3.4 版本中修复,但该版本有一个 macOS 兼容性错误,该错误已在 0.3.5 版本的代码中修复。苹果的 Accelerate 框架版本 1.1 和英特尔的 MKL 也会出现这些错误mkl==2019.0
。
了解如何安装 OpenBLAS 并在其上编译 NumPy 和 SciPy。
也许我遇到的其余问题是由于链接到 Accelerate 的其他库引起的?
注意:我仍然愿意接受这个问题的更多答案。
推荐阅读
- c++ - 带有“无限”参数的 c++ 模板
- electron - 在 Cypress 中设置 Electron 的语言
- javascript - 如何在各个页面中具有相同 ID 的多个页面上使用 JavaScript 隐藏/显示链接(元素)?
- php - PHP:file_get_contents():SSL 操作失败,代码为 1
- java - 未使用改造从 IGDB Api 接收所有数据
- sql - SSRS - 具有不同价值的多个数据
- javascript - 停止提交按钮不发布并返回同一页面
- solr - 如何确定 solr 停止运行的原因?
- javascript - iframe 的 HTML/Javascript 错误,应该很容易
- python - Scrapy:如何获取页数?