1

我正在尝试使用scipy.odr将测量数据点拟合到我的模型中。虽然在不指定 jacobian 的情况下进行拟合,但对于某些模型会产生不好的结果,但在仅使用某些模型指定我自己的 jacobian 时会出现分段错误。

#!/usr/bin/python2
from __future__ import print_function

import numpy as np
import scipy.odr as odr

tspace = np.linspace(0, 10, 100)

def fun(p, x):
    a, x0 = p
    r = a * (x - x0)**2
    return r

def param_jacobian(p, x, *args):
    a, x0 = p
    r = np.array([
        (x.T - x0)**2,
        -2*a*x0*(x.T - x0),
    ])
    return r

def value_jacobian(p, x, *args):
    a, x0 = p
    r = np.array([
        2*a*(x.T - x0),
    ])
    return r

correct = fun((0.5, 3), tspace)

p0 = (0.1, 1)

model = odr.Model(fun, fjacb=param_jacobian, fjacd=value_jacobian)
data = odr.Data(tspace, correct)

fitter = odr.ODR(data, model, beta0=p0)
fitter.set_job(0, 2)
fitter.run()
fitter.output.pprint()

此示例在 python 2.7、64 位、scipy 0.9.0 上因段错误而崩溃。fitter.set_job(0, 0)如果您通过调用or来切换自定义 jacobian 的使用,它可以工作(在fitter.set_job(0, 1)示例中拟合结果很好,但在其他示例中则不然)。

我的错误在哪里?完全是我的错吗?

更新:我又遇到了这个问题。我在 fit 脚本上运行了 gdb 和 valgrind。gdb 显示了一个 stacktrace into malloc_consolidate,它被模块的一些导入尝试深深调用syslog......对我来说似乎很奇怪,但我认为这无关紧要,因为 valgrind 显示以下两次之前,就在param_jacobian第一次被调用之后(这是在value_jacobian)。尝试获取结果时会发生段错误。我怀疑段错误是由于堆损坏,这可能是odrpack.so.

==32764== Source and destination overlap in memcpy(0x14239ee0, 0x14239ee0, 32)
==32764==    at 0x4A09306: memcpy@@GLIBC_2.14 (mc_replace_strmem.c:653)
==32764==    by 0x1B3663EB: fcn_callback (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32764==    by 0x1B3A1821: doddrv_ (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32764==    by 0x1B3A282A: dodcnt_ (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32764==    by 0x1B3A355A: dodrc_ (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32764==    by 0x1B36A452: odr (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32764==    by 0x3A41249382: PyObject_Call (abstract.c:2529)
==32764==    by 0x3A412DA8F6: PyEval_CallObjectWithKeywords (ceval.c:3967)
==32764==    by 0x3A412D89E9: builtin_apply (bltinmodule.c:195)
==32764==    by 0x3A412E03DA: PyEval_EvalFrameEx (ceval.c:4098)
==32764==    by 0x3A412E075D: PyEval_EvalFrameEx (ceval.c:4184)
==32764==    by 0x3A412E19A4: PyEval_EvalCodeEx (ceval.c:3330)

*_jacobian甚至在第二次调用函数之后:

==32100== Invalid read of size 8
==32100==    at 0x18189BFB: gen_output (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32100==    by 0x1818C4BA: odr (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32100==    by 0x3A41249382: PyObject_Call (abstract.c:2529)
==32100==    by 0x3A412DA8F6: PyEval_CallObjectWithKeywords (ceval.c:3967)
==32100==    by 0x3A412D89E9: builtin_apply (bltinmodule.c:195)
==32100==    by 0x3A412E03DA: PyEval_EvalFrameEx (ceval.c:4098)
==32100==    by 0x3A412E075D: PyEval_EvalFrameEx (ceval.c:4184)
==32100==    by 0x3A412E19A4: PyEval_EvalCodeEx (ceval.c:3330)
==32100==    by 0x3A412DFF02: PyEval_EvalFrameEx (ceval.c:4194)
==32100==    by 0x3A412E19A4: PyEval_EvalCodeEx (ceval.c:3330)
==32100==    by 0x3A412E1AD1: PyEval_EvalCode (ceval.c:689)
==32100==    by 0x3A412FBD5B: run_mod (pythonrun.c:1361)
==32100==  Address 0x10207b40 is 0 bytes inside a block of size 80 free'd
==32100==    at 0x4A0662E: free (vg_replace_malloc.c:366)
==32100==    by 0xC1050FF: ??? (in /usr/lib64/python2.7/site-packages/numpy/core/multiarray.so)
==32100==    by 0xC110199: ??? (in /usr/lib64/python2.7/site-packages/numpy/core/multiarray.so)
==32100==    by 0x18189A7E: gen_output (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32100==    by 0x1818C4BA: odr (in /usr/lib64/python2.7/site-packages/scipy/odr/__odrpack.so)
==32100==    by 0x3A41249382: PyObject_Call (abstract.c:2529)
==32100==    by 0x3A412DA8F6: PyEval_CallObjectWithKeywords (ceval.c:3967)
==32100==    by 0x3A412D89E9: builtin_apply (bltinmodule.c:195)
==32100==    by 0x3A412E03DA: PyEval_EvalFrameEx (ceval.c:4098)
==32100==    by 0x3A412E075D: PyEval_EvalFrameEx (ceval.c:4184)
==32100==    by 0x3A412E19A4: PyEval_EvalCodeEx (ceval.c:3330)
==32100==    by 0x3A412DFF02: PyEval_EvalFrameEx (ceval.c:4194)

Invalid read of size 8并且多次出现类似错误(来自同一函数内)。

我尝试在这个(大部分不相关LD_PRELOAD的)错误报告上发布小的 memcpy 替换,但这没有帮助。

4

0 回答 0