0.前言
解决非线性问题的方法:
最小二乘算法:https://www.mathworks.com/help/optim/ug/least-squares-model-fitting-algorithms.html
这里主要记录Levenberg-Marquardt算法学习笔记!
1.Levenberg-Marquardt算法介绍
基本原理:
计算当C最小时对应的函数参数。
- Levenberg-Marquardt(LM)是一种用于解决非线性最小二乘问题的算法,当通过最小化数据点与函数之间误差的平方和来拟合参数化函数到一组测量数据点时,就会出现最小二乘问题。
- Levenberg-Marquardt曲线拟合方法实际上是两种最小化方法的结合:梯度下降法( gradient
descent)和高斯-牛顿法(Gauss-Newton)。 - 在梯度下降法中,通过在最陡下降方向更新参数来减小误差的平方和。在高斯-牛顿法中,通过假设最小二乘函数是局部二次函数,并求出二次函数的最小值来减小误差的平方和。
- 评估指标——卡方误差chi-squared error criterion:
图片来源:https://msulaiman.org/onewebmedia/LM%20Method%20matlab%20codes%20and%20implementation.pdf
2.Levenberg-Marquardt算法实现-python
最小二乘实现方法:
python实现方法:https://mmas.github.io/least-squares-fitting-numpy-scipy
scipy.optimize.leastsq(func, x0, args=(), Dfun=None, full_output=0, col_deriv=0, ftol=1.49012e-08, xtol=1.49012e-08, gtol=0.0, maxfev=0, epsfcn=None, factor=100, diag=None)
from scipy.optimize import leastsq
def func(x):
return 2*(x-3)**2+1
leastsq(func, 0)
non-linear least squares fit:
def residual(p, x, y):
return y - f(x, *p)
p0 = [1., 8.]
popt, pcov = optimize.leastsq(residual, p0, args=(x, y))
print popt
yn = f(xn, *popt)
plt.plot(x, y, 'or')
plt.plot(xn, yn)
plt.show()
3.Levenberg-Marquardt算法实现-MATLAB
(1)LM算法原理:https://blog.csdn.net/waitingwinter/article/details/106142276
(2)LM算法实现:Matlab
(3)非线性拟合:MATLAB
rng('default');%将 rand、randi 和 randn 使用的随机数生成器的设置重置为其默认值。保证结果重复。
% 生成数据
len = 1000;
x = linspace(0.1, 300, len)';
y = 300*exp(-x/5) + 10;
% 添加噪声
y_noise = y + 20*randn(len, 1);
% 调用 lsqcurvefit
func = @(p, x) p(1)*exp(-x/p(2)) + p(3);
% 选择合适的初始值
p0 = [100, 2 1];
p = lsqcurvefit(func, p0, x, y_noise)
linespace函数:np.linspace(a,b,c)用于创建一个等差序列的向量,向量值是[a,b]之间均匀分布的c个实数。
拟合结果:
% 拟合结果
y_fit_lsq = func(p, x);
% 调用 nlinfit
pp = nlinfit(x, y_noise, func, p0)
nlinfit函数:beta = nlinfit(X,Y,modelfun,beta0)
使用 modelfun 指定的模型,返回一个向量,其中包含 Y 中的响应对 X 中的预测变量的非线性回归的估计系数。它使用迭代最小二乘估计来估计系数,初始值由 beta0 指定。
绘图:
figure;
plot(x, y_noise, '.', 'LineWidth', 2);
hold on
plot(x, y_fit_lsq, 'LineWidth', 2);
plot(x, y_fit_nlin, 'LineWidth', 2);
hold off
legend('原始数据', '拟合数据-lsqcurvefit', '拟合数据-nlinfit');
结果展示:
LM算法实现:
p1 = LSFittingExpFree(x, y_noise)
fit1 = func(p1, x);
plot(x, fit1, 'LineWidth', 2);
%%Levenberg_Marquardt LS Fitting
function result = LSFittingExpFree(x, y)
% Levenberg_Marquardt LS Fitting
% 按列排
x = x(:);
y = y(:);
M = length(x);
% Least Squares Minimization
rng('default');
% 初始值
a = sqrt(rand);
b = sqrt(rand);
c = sqrt(rand);
% 变量个数
nParam = 3;
% 残差
r = y - (a^2 * exp(-x / b^2) + c^2);
% 目标函数
f = r'*r;
% 正则化因子初值
lambda = 1;
% 迭代次数
it = 0;
% 更新标记
updateFlag = true;
% 最大迭代次数
maxIter = 100;
% 迭代计算
while it < maxIter
it = it + 1;
if updateFlag
Ja = 2 * a * exp(-x / b^2);
Jb = 2 * a^2 * x .* exp(-x / b^2) / b^3;
Jc = 2 * c * ones(M, 1);
J = [Ja, Jb, Jc];
g = -2 * J' * r;
H = 2 * (J'*J);
end
Hess = H + lambda * eye(nParam);
s = -Hess \ g;
a1 = a + s(1);
b1 = b + s(2);
c1 = c + s(3);
r1 = y - (a1^2 * exp(-x / b1^2) + c1^2);
f1 = r1'*r1;
fdr = (f - f1) / f;
if fdr > 0
a = a1;
b = b1;
c = c1;
f = f1;
r = r1;
lambda = 0.1 * lambda;
updateFlag = true;
else
lambda = 10 * lambda;
updateFlag = false;
end
if max(abs(s)) < 1e-6
disp(['达到收敛条件,迭代次数:' num2str(it)]);
break;
elseif it == maxIter
disp('达到最高迭代次数,可能不收敛;');
end
end
result = [a^2, b^2, c^2];
end
代码来源:https://zhuanlan.zhihu.com/p/388676905
完整代码:lsqcurvefit、LSFittingExpFree、nlinfit、lsqnonlin
% 保证结果可重复
rng('default');
% 生成数据
len = 1000;
x = linspace(0.1, 300, len)';
y = 300*exp(-x/5) + 10;
% 添加噪声
y_noise = y + 20*randn(len, 1);
% 调用 lsqcurvefit
func = @(p, x) p(1)*exp(-x/p(2)) + p(3);
%lsqnonlin
funl = @(p,x,y_noise) p(1)*exp(-x/p(2)) + p(3)- y_noise;
% 选择合适的初始值
p0 = [100, 2 1];
p = lsqcurvefit(func, p0, x, y_noise)
options.Algorithm = 'levenberg-marquardt';
% options = optimoptions(@lsqnonlin,'Algorithm','trust-region-reflective');
[p2,resnorm,residual] = lsqnonlin(funl,p0,[],[],options,x,y_noise)
% 拟合结果
y_fit_lsq = func(p, x);
% 调用 nlinfit
pp = nlinfit(x, y_noise, func, p0)
y_fit_nlin = func(pp, x);
p1 = LSFittingExpFree(x,y_noise)
fit1 = func(p1, x);
fit2 = funl(p2,x,y_noise);
figure;
plot(x, y_noise, '.', 'LineWidth', 2);
hold on
plot(x, y_fit_lsq, 'LineWidth', 2);
plot(x, fit1, 'LineWidth', 2);
plot(x, y_fit_nlin, 'LineWidth', 2);
plot(x, fit2+y_noise, 'LineWidth', 2);
hold off
legend('原始数据', '拟合数据-lsqcurvefit','拟合数据-LSFittingExpFree','拟合数据-nlinfit','拟合数据-lsqnonlin');
%%Levenberg_Marquardt LS Fitting
function result = LSFittingExpFree(x, y)
% Levenberg_Marquardt LS Fitting
% 按列排
x = x(:);
y = y(:);
M = length(x);
% Least Squares Minimization
rng('default');
% 初始值
a = sqrt(rand);
b = sqrt(rand);
c = sqrt(rand);
% 变量个数
nParam = 3;
% 残差
r = y - (a^2 * exp(-x / b^2) + c^2);
% 目标函数
f = r'*r;
% 正则化因子初值
lambda = 1;
% 迭代次数
it = 0;
% 更新标记
updateFlag = true;
% 最大迭代次数
maxIter = 100;
% 迭代计算
while it < maxIter
it = it + 1;
if updateFlag
Ja = 2 * a * exp(-x / b^2);
Jb = 2 * a^2 * x .* exp(-x / b^2) / b^3;
Jc = 2 * c * ones(M, 1);
J = [Ja, Jb, Jc];
g = -2 * J' * r;
H = 2 * (J'*J);
end
Hess = H + lambda * eye(nParam);
s = -Hess \ g;
a1 = a + s(1);
b1 = b + s(2);
c1 = c + s(3);
r1 = y - (a1^2 * exp(-x / b1^2) + c1^2);
f1 = r1'*r1;
fdr = (f - f1) / f;
if fdr > 0
a = a1;
b = b1;
c = c1;
f = f1;
r = r1;
lambda = 0.1 * lambda;
updateFlag = true;
else
lambda = 10 * lambda;
updateFlag = false;
end
if max(abs(s)) < 1e-6
disp(['达到收敛条件,迭代次数:' num2str(it)]);
break;
elseif it == maxIter
disp('达到最高迭代次数,可能不收敛;');
end
end
result = [a^2, b^2, c^2];
end
结果对比:
4.Levenberg-Marquardt模型评估
(1)模型评估方法:如lsqnonlin函数中,可以输出resnorm — Squared norm of the residual
或residual — Value of objective function at solution
。
(2)利用卡方检验Chi-Square Test方法来评估模型:
- 卡方检验,也称χ 2检验,是检验两个变量之间有没有关系。
- 卡方检验基本思想:以卡方分布为基础,计算观察值和期望值之间的偏离程度。
卡方检验、t检验和方差分析的区别:https://blog.csdn.net/symoriaty/article/details/100178446
(3)卡方检验(x2检验chi-square test)计算方法:
方法一:四格表资料的x2检验
检验的基本公式为:
A为实际数;T为理论数;
通过查x2值表求P值,判断两者相关性。
方法二:近似法
计算公式:
(4)误差分析(来自论文:The Levenberg-Marquardt method for nonlinear least squares
curve-fitting problems)
参考资料:
论文:The Levenberg-Marquardt method for nonlinear least squares curve-fitting problems
https://msulaiman.org/onewebmedia/LM%20Method%20matlab%20codes%20and%20implementation.pdf
PPT:Data Modeling and Least Squares Fitting 2
https://www.cs.princeton.edu/courses/archive/fall11/cos323/notes/cos323_f11_lecture08_lsq2
PPT:Numerical Optimization using the Levenberg-Marquardt Algorithm
https://mads.lanl.gov/presentations/Leif_LM_presentation_m.pdf
python实现方法-Least squares fitting with Numpy and Scipy:https://mmas.github.io/least-squares-fitting-numpy-scipy
非线性回归中的Levenberg-Marquardt算法理论和代码实现:https://zhuanlan.zhihu.com/p/349953779;代码:https://github.com/manfrezord/MediumArticles/blob/main/LM-Algorithm.ipynb