我正在尝试使用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 替换,但这没有帮助。