简体   繁体   English

确定性python脚本以非确定性方式运行

[英]Deterministic python script behaves in non-deterministic way

I have a script which uses no randomisation that gives me different answers when I run it. 我有一个不使用随机化的脚本,当我运行它时会给出不同的答案。 I expect the answer to be the same, every time I run the script. 每次运行脚本时,我都希望答案是一样的。 The problem appears to only happen for certain (ill-conditioned) input data. 问题似乎只发生在某些(病态的)输入数据上。

The snippet comes from an algorithm to compute a specific type of controller for a linear system, and it mostly consists of doing linear algebra (matrix inversions, Riccati equation, eigenvalues). 该片段来自为线性系统计算特定类型控制器的算法,它主要由线性代数(矩阵求逆,Riccati方程,特征值)组成。

Obviously, this is a major worry for me, as I now cannot trust my code to give me the right results. 显然,这对我来说是一个主要的担忧,因为我现在不能相信我的代码能给我正确的结果。 I know the result can be wrong for poorly conditioned data, but I expect consistently wrong. 我知道结果对条件差的数据来说可能是错误的,但我一直都错了。 Why is the answer not always the same on my Windows machine? 为什么我的Windows机器上的答案并不总是一样的? Why do the Linux & Windows machine not give the same results? 为什么Linux和Windows机器没有给出相同的结果?

I'm using Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win 32 , with Numpy version 1.8.2 and Scipy 0.14.0. Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win 32使用Python 2.7.9 (default, Dec 10 2014, 12:24:55) [MSC v.1500 32 bit (Intel)] on win 32 ,Numpy版本1.8.2和Scipy 0.14.0。 (Windows 8, 64bit). (Windows 8,64位)。

The code is below. 代码如下。 I've also tried running the code on two Linux machines, and there the script always gives the same answer (but the machines gave differing answers). 我也尝试在两台Linux机器上运行代码,脚本总是给出相同的答案(但机器给出了不同的答案)。 One was running Python 2.7.8, with Numpy 1.8.2 and Scipy 0.14.0. 一个是运行Python 2.7.8,Numpy 1.8.2和Scipy 0.14.0。 The second was running Python 2.7.3 with Numpy 1.6.1 and Scipy 0.12.0. 第二个是使用Numpy 1.6.1和Scipy 0.12.0运行Python 2.7.3。

I solve the Riccati equation three times, and then print the answers. 我三次解决Riccati方程,然后打印答案。 I expect the same answer every time, instead I get the sequence '1.75305103767e-09; 我每次都期待相同的答案,而不是我得到序列'1.75305103767e-09; 3.25501787302e-07; 3.25501787302e-07; 3.25501787302e-07'. 3.25501787302e-07' 。

    import numpy as np
    import scipy.linalg

    matrix = np.matrix

    A = matrix([[  0.00000000e+00,   2.96156260e+01,   0.00000000e+00,
                        -1.00000000e+00],
                    [ -2.96156260e+01,  -6.77626358e-21,   1.00000000e+00,
                        -2.11758237e-22],
                    [  0.00000000e+00,   0.00000000e+00,   2.06196064e+00,
                         5.59422224e+01],
                    [  0.00000000e+00,   0.00000000e+00,   2.12407340e+01,
                        -2.06195974e+00]])
    B = matrix([[     0.        ,      0.        ,      0.        ],
                    [     0.        ,      0.        ,      0.        ],
                    [  -342.35401351, -14204.86532216,     31.22469724],
                    [  1390.44997337,    342.33745324,   -126.81720597]])
    Q = matrix([[ 5.00000001,  0.        ,  0.        ,  0.        ],
                    [ 0.        ,  5.00000001,  0.        ,  0.        ],
                    [ 0.        ,  0.        ,  0.        ,  0.        ],
                    [ 0.        ,  0.        ,  0.        ,  0.        ]])
    R = matrix([[ -3.75632852e+04,  -0.00000000e+00,   0.00000000e+00],
                    [ -0.00000000e+00,  -3.75632852e+04,   0.00000000e+00],
                    [  0.00000000e+00,   0.00000000e+00,   4.00000000e+00]])

    counter = 0
    while counter < 3:
            counter +=1

            X = scipy.linalg.solve_continuous_are(A, B, Q, R)
            print(-3449.15531628 - X[0,0])

My numpy config is as below print np.show_config() 我的numpy配置如下所示print np.show_config()

lapack_opt_info:
    libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md', 'mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md']
    library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32']
    define_macros = [('SCIPY_MKL_H', None)]
    include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include']
blas_opt_info:
    libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md']
    library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32']
    define_macros = [('SCIPY_MKL_H', None)]
    include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include']
openblas_info:
  NOT AVAILABLE
lapack_mkl_info:
    libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md', 'mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md']
    library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32']
    define_macros = [('SCIPY_MKL_H', None)]
    include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include']
blas_mkl_info:
    libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md']
    library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32']
    define_macros = [('SCIPY_MKL_H', None)]
    include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include']
mkl_info:
    libraries = ['mkl_blas95', 'mkl_lapack95', 'mkl_intel_c', 'mkl_intel_thread', 'mkl_core', 'libiomp5md']
    library_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/lib/ia32', 'C:/Program Files (x86)/Intel/Composer XE 2013 SP1/compiler/lib/ia32']
    define_macros = [('SCIPY_MKL_H', None)]
    include_dirs = ['c:/Program Files (x86)/Intel/Composer XE 2013 SP1/mkl/include']
None

(edits to trim the question down) (编辑以减少问题)

In general, linalg libraries on Windows give different answers on different runs at machine precision level. 通常,Windows上的linalg库在机器精度级别的不同运行中给出不同的答案。 I never heard of an explanation why this happens only or mainly on Windows. 我从来没有听说过为什么这种情况只发生在Windows上或主要发生在Windows上。

If your matrix is ill conditioned, then the inv will be largely numerical noise. 如果你的矩阵生病,那么inv将主要是数字噪声。 On Windows the noise is not always the same in consecutive runs, on other operating systems the noise might be always the same but can differ depending on the details of the linear algebra library, on threading options, cache usage and so on. 在Windows上,连续运行时噪声并不总是相同,在其他操作系统上,噪声可能总是相同但可能会有所不同,具体取决于线性代数库的细节,线程选项,缓存使用情况等。

I've seen on and posted to the scipy mailing list several examples for this on Windows, I was using mostly the official 32 bit binaries with ATLAS BLAS/LAPACK. 我已经看到并在scipy邮件列表上发布了几个关于Windows的例子,我主要使用官方32位二进制文​​件和ATLAS BLAS / LAPACK。

The only solution is to make the outcome of your calculation not depend so much on floating point precision issues and numerical noise, for example regularize the matrix inverse, use generalized inverse, pinv, reparameterize or similar. 唯一的解决方案是使计算的结果不依赖于浮点精度问题和数值噪声,例如将矩阵求逆,使用广义逆,pinv,重新参数化或类似。

As pv noted in the comments to user333700's answer , the previous formulation of the Riccati solvers were, though being theoretically correct, not numerically stable. 正如pv针对user333700的回答中所指出的那样,Riccati求解器的先前公式虽然在理论上是正确的,但在数值上并不稳定。 This issue is fixed on the development version of SciPy and the solvers support generalized Riccati equations too. 此问题已在SciPy的开发版本上修复,求解器也支持广义Riccati方程。

The Riccati solvers are updated and resulting solvers will be available from version 0.19 and onwards. Riccati解算器已更新,结果解算器将从0.19及更高版本开始提供。 You can check the development branch docs here . 您可以在此处查看开发分支文档

If, using the given example in the question I replace the last loop with 如果,使用问题中的给定示例,我将最后一个循环替换为

for _ in range(5):
    x = scipy.linalg.solve_continuous_are(A, B, Q, R)
    Res = x@a + a.T@x + q - x@b@ np.linalg.solve(r,b.T)@ x
    print(Res)

I get (windows 10, py3.5.2) 我得到了(windows 10,py3.5.2)

[[  2.32314924e-05  -2.55086270e-05  -7.66709854e-06  -9.01878229e-06]
 [ -2.62447211e-05   2.61182140e-05   8.27328768e-06   1.00345896e-05]
 [ -7.92257197e-06   8.57094892e-06   2.50908488e-06   3.05714639e-06]
 [ -9.51046241e-06   9.80847472e-06   3.13103374e-06   3.60747799e-06]]
[[  2.32314924e-05  -2.55086270e-05  -7.66709854e-06  -9.01878229e-06]
 [ -2.62447211e-05   2.61182140e-05   8.27328768e-06   1.00345896e-05]
 [ -7.92257197e-06   8.57094892e-06   2.50908488e-06   3.05714639e-06]
 [ -9.51046241e-06   9.80847472e-06   3.13103374e-06   3.60747799e-06]]
[[  2.32314924e-05  -2.55086270e-05  -7.66709854e-06  -9.01878229e-06]
 [ -2.62447211e-05   2.61182140e-05   8.27328768e-06   1.00345896e-05]
 [ -7.92257197e-06   8.57094892e-06   2.50908488e-06   3.05714639e-06]
 [ -9.51046241e-06   9.80847472e-06   3.13103374e-06   3.60747799e-06]]
[[  2.32314924e-05  -2.55086270e-05  -7.66709854e-06  -9.01878229e-06]
 [ -2.62447211e-05   2.61182140e-05   8.27328768e-06   1.00345896e-05]
 [ -7.92257197e-06   8.57094892e-06   2.50908488e-06   3.05714639e-06]
 [ -9.51046241e-06   9.80847472e-06   3.13103374e-06   3.60747799e-06]]
[[  2.32314924e-05  -2.55086270e-05  -7.66709854e-06  -9.01878229e-06]
 [ -2.62447211e-05   2.61182140e-05   8.27328768e-06   1.00345896e-05]
 [ -7.92257197e-06   8.57094892e-06   2.50908488e-06   3.05714639e-06]
 [ -9.51046241e-06   9.80847472e-06   3.13103374e-06   3.60747799e-06]]

For reference, the solution returned is 作为参考,返回的解决方案是

array([[-3449.15531305,  4097.1707738 ,  1142.52971904,  1566.51333847],
       [ 4097.1707738 , -4863.70533241, -1356.66524959, -1860.15980716],
       [ 1142.52971904, -1356.66524959,  -378.32586814,  -518.71965102],
       [ 1566.51333847, -1860.15980716,  -518.71965102,  -711.21062988]])

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM