我一直在尝试使用python的scipy.optimize
库来估计模型的参数但到目前为止还没有成功。我试图使用scipy.optimize.leastsq
使用levenberg-marquardt算法。不幸的是,即使我将初始参数设置为非常接近最佳拟合,它总是找不到我的模型函数的最小值。实际上,它总是返回初始猜测的参数。所以,我认为我做错了什么。我的模型是一个简单的圆,但为了使事情更简单,只有半径是实际参数,数据中圆的中心是已知的并且是硬编码的。数据是一个10x10像素的浮点图像,带有一个圆心,中心为5,5,半径为4.实际上,数据是使用我想要的模型生成的。因此,存在完美契合。这是我的代码:
import math
import numpy
import scipy.optimize
# ========================================================================
g_data_width = 10
g_data_height = 10
g_xo = 5.0
g_yo = 5.0
def evaluate_model01(x,y,r):
x2 = x*x
y2 = y*y
r2 = r*r
v = 0.0
if(x2 + y2 <= r2):
v = 20.0
return v
def model01(params,data_o):
data_r = numpy.zeros(g_data_height*g_data_width)
r = params[0]
for y in range(g_data_height):
for x in range(g_data_width):
xnew = x - g_xo
ynew = y - g_yo
data_r[y*g_data_width+x] = math.fabs(data_o[y,x]-evaluate_model01(xnew,ynew,r))
return data_r
# ========================================================================
g_data_o = numpy.array([[ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 20, 0, 0, 0, 0],
[ 0, 0, 0, 20, 20, 20, 20, 20, 0, 0],
[ 0, 0, 20, 20, 20, 20, 20, 20, 20, 0],
[ 0, 0, 20, 20, 20, 20, 20, 20, 20, 0],
[ 0, 20, 20, 20, 20, 20, 20, 20, 20, 20],
[ 0, 0, 20, 20, 20, 20, 20, 20, 20, 0],
[ 0, 0, 20, 20, 20, 20, 20, 20, 20, 0],
[ 0, 0, 0, 20, 20, 20, 20, 20, 0, 0],
[ 0, 0, 0, 0, 0, 20, 0, 0, 0, 0]],dtype=numpy.float32)
g_params = numpy.array([8.0])
print(scipy.optimize.leastsq(model01,g_params,args=(g_data_o),full_output=1))
# ========================================================================
我对数据进行了硬编码,以便删除任何数据依赖项,并允许代码在安装了scipy
的任何计算机上开箱即用。我不太明白的是model01
函数应该返回什么。根据文档,它应该返回一个数组。一阵什么?在我的代码中,我假设我必须为每个数据点返回一个残差数组。那是对的吗?我的数据是一个二维数组,因为它是一个图像但我的残差是一个平坦的2D残差数组。这可以吗?有人能告诉我究竟是做错了什么吗?有人可以修改和修复代码吗?如上所述,代码应该在安装了scipy
和numpy
的任何计算机上开箱即用。如果scipy.optimize.leastsq
无法实现我想要实现的目标,您能否使用levenberg-marquardt算法建议其他适合模型的库?
答案 0 :(得分:1)
我担心您无法使用leastsq
解决您的特定问题。 leastsq
是FORTRAN库minipack
的回绕,它调用MINPACK
的{{1}}和lmdif
算法。重要的是,它基于雅可比和最小二乘目标函数的Hessian。由于以下原因,您的目标函数没有平滑导数:
lmder
和
if(x2 + y2 <= r2):
v = 20.0
,因此math.fabs(......)
将始终返回初始启动参数。
您应该尝试使用一些不需要渐变/衍生的方法,例如Powell的方法leastsq
或Nelder-Mead fmin_powell
。
关于fmin
中发生了什么。它首先生成一个大小为model101()
{1}的1D数组,称为width*height
。然后迭代g_data
,计算每个元素的data_r
,并将该值放入1D数组g_data
。最后,它返回math.fabs(data_o[y,x]-evaluate_model01(xnew,ynew,r))
。
您的解释是正确的,data_r
会为您的2D数据返回展平的1D残差数组。