Levenberg Marquardt实施问题

32次浏览(最近30天)
罗伯特。”class=
罗伯特。 2019年12月21日
回答: 艾哈迈德FAKHRI2020年12月1日
编辑:你能至少建议我在哪里找到实现LM算法的特定matlab函数吗?
你好,
出于个人研究的原因,我试图从头开始实现深度学习工具箱中的训练算法。使用一阶算法,如标准反向传播梯度下降,一切进展顺利。我的自定义代码收敛到完全相同的权重/偏差比matlab的一个,它也快了两倍。我认为更高的速度是由于matlab需要做更多的if/else指令,而我的代码只适用于具有tanh激活的一层网络。
但我对Levenberg Marquardt有问题。我写了3个函数:
  1. Jacobian_LM
  2. UpdatesThroughHessianAndGradient
  3. Levenberg_Marquardt_Backpropagation
第一个只是通过标准反向传播算法计算网络WRT权重和偏差的“每个示例”雅可比矩阵。这意味着它输出矩阵,其中每一列都是相对于单个输入/输出对的梯度。
第二步是将雅可比矩阵扁平化为一个长向量并计算黑森矩阵 H 还有渐变 D 用于LM更新规则:
然后,它将这些更新重新塑造并分割成具有正确大小和形状的网络的特定权重和偏差矩阵。
最后,第三个是LM循环的实现,在每次迭代中更新标准matlab网络对象的权重和偏差(具有一个隐藏层和tanh激活),直到通过mu的增加/减少模式实现性能改进。
这里是你需要尝试我的算法的函数:
函数[Net] = Levenberg_Marquardt_Backpropagation(Net,x,y,mu, mu_incree_rate, mu_reduce_rate,max_mu,iterations)
这个函数的摘要在这里
详细的解释在这里
%网络权重\偏差存储
IW = Net.IW{1,1};
b = Net.b{1,1};
LW = Net.LW{2,1};
Lb = Net.b{2,1};
%%%%%%%%%%%%%%%%%
I = 1:迭代
Mu <= max_mu && Mu > 1e-20
% PREV-PERFORMANCE计算
Pred = LW*tansig(IW*x + Ib) + Lb;
pre_perf = mean((y-Pred).^2);
%%%%%%%%%%%%%%%%%%%%%%%%
%以前的权重\偏差存储
pre_iw = IW;
pre_ib = Ib;
Prev_LW = LW;
Prev_Lb = Lb;
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%计算梯度\黑森
[IWJ,IbJ,LWJ,LbJ] = Jacobian_LM(IW,LW,Ib,Lb,x,y);
[IWUpdate, ibuupdate,LWUpdate, lbuupdate] = UpdatesThroughHessianAndGradient(IWJ,IbJ,LWJ,LbJ,Pred,y,mu);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%的权重\偏见更新
= IW + IWUpdate;
Ib = Ib + iupdate;
LW = LW + LWUpdate';
Lb = Lb + lbuupdate;
%%%%%%%%%%%
%性能计算
Pred = LW*tansig(IW*x + Ib) + Lb;
Perf = mean((y-Pred).^2);
%%%%%%%%%%%%%%%%%%%%%%%%
%性能检查
如果(Perf >= pre_perf)
IW = pre_iw;
Ib = Prev_Ib;
LW = Prev_LW;
Lb = Prev_Lb;
Mu = Mu * mu_incree_rate;
其他的
μ=μ* mu_decrease_rate;
打破
结束
%%%%%%%%%%%%%%%%%%
结束
结束
%最终净更新
网{1,1} = Iw;
网Lw {2,1} = Lw;
网b{1,1} = b;
网b{2,1} = Lb;
%%%%%%%%%%%
结束
函数[IWUpdate, ibuupdate,LWUpdate, lbuupdate] = UpdatesThroughHessianAndGradient(IWJ,IbJ,LWJ,LbJ,Pred,y,mu)
这个函数的摘要在这里
详细的解释在这里
1 = size(IWJ,1);
s2 = size(IWJ,2);
3 = size(IbJ,1);
4 = size(LWJ,1);
5 = size(LbJ,1);
6 = size(IWJ,3);
Jac = nan(s1*s2 + s3 + s4 + s5,s6);
Jac(1:s1*s2,:) = align = align (1,s1*s2, 1);
Jac(s1*s2+1:s1*s2+s3,:) = IbJ;
Jac(s1*s2+s3+1:s1*s2+s3+s4,:) = LWJ;
Jac(s1*s2+s3+s4+1:s1*s2+s3+s4+s5,:) = LbJ;
H = (Jac*Jac')/ 6;
D =平均;*(Pred - y),2);
Update_Tot = -pinv (H +μ*眼(大小(H, 1))、min (H (:)) / 1000) * D;
IWUpdate = transform (Update_Tot(1:s1*s2),s1,s2);
(s1*s2+1:s1*s2+s3);
LWUpdate = Update_Tot(s1*s2+s3+1:s1*s2+s3+s4);
LbUpdate = (s1*s2+s3+s4+1:s1*s2+s3+s4+s5);
结束
函数[IWJ,IbJ,LWJ,LbJ] = Jacobian_LM(IW,LW,Ib,Lb,x,y)% #好< INUSL >
这个函数的摘要在这里
详细的解释在这里
%传球前进
*x + b;
aI = tansig(zI);
%zL = LW*aI + Lb;
%aL = zL;
%%%%%%%%%%%%%%
%反向传播
deltaLW = ones(1,size(y,2));
deltaLW = (1 - aI.^2).*LW'.*deltaLW;
%%%%%%%%%%%%%%%%
%计算雅可比矩阵
IWJ = nan(size(deltaw,1),size(x,1),size(x,2));
I = 1:size(x,2)
IWJ(:,:,i) = deltaw (:,i).*x(:,i)';
结束
IbJ = deltaw;
LWJ = aI.*deltaLW;
LbJ = deltaLW;
%%%%%%%%%%%%%%%%%%%%%
结束
这里有一个脚本,你可以复制/粘贴来测试代码(当然,如果你的工作目录中有上面的文件):
rng (0)
清晰的
格式
警告(“关闭”
定义一个简单的问题
X = rand(2,1000)*10;
X = X -5;
Y = x(1,:)。^2 + x(2,:) ^2;
X = X /10;
%%%%%%%%%%%%%%%%%%%%%%%%
%定义训练参数
disp (”“
disp (”“
Initial_Mu = 0.001;
Incr_Rate = 10;
Decr_Rate = 0.1;
Max_Mu = 1e10;
epoch = 1000;
Hidden_Neurons = 20;
disp ([“Initial_Mu:”num2str (Initial_Mu)]);
disp ([“Incr_Rate:”num2str (Incr_Rate)]);
disp ([“Decr_Rate:”num2str (Decr_Rate)]);
disp ([“Hidden_Neurons:”num2str (Hidden_Neurons)]);
%%%%%%%%%%%%%%%%%%%%%%%%%%%
定义并初始化网络
net = feedforwardnet(Hidden_Neurons);
net.trainParam.epochs = epoch;
net.trainParam。mu_dec= Decr_Rate;
net.trainParam。mu_inc= Incr_Rate;
net.trainParam.mu = Initial_Mu;
net.trainParam。μ_max = Max_Mu;
% net.trainParam。showWindow = false;
net.inputs{1}。processFcns = {};
net.outputs{1,2}。processFcns = {};
net.trainParam。Min_grad = 1e-25;
net.trainParam。Max_fail = 50;
net.divideParam.trainRatio = 1;
net.divideParam.valRatio = 0;
net.divideParam.testRatio = 0;
Net = configure(Net,x,y);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%使用matlab的trainlm进行初始化的网络训练
disp (”“
disp (”“
netMATLAB = net;
抽搐
netMATLAB = train(netMATLAB,x,y);
disp (“Matlab时间:
toc
disp (”“
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%使用相同的初始化网络进行自定义训练
netCUSTOM = net;
抽搐
[netCUSTOM] = Levenberg_Marquardt_Backpropagation(netCUSTOM,x,y,Initial_Mu,Incr_Rate,Decr_Rate,Max_Mu,Epochs);
disp (定制时间:“
toc
disp (”“
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%比较结果
Pred_Matlab = netMATLAB(x);
Pred_Custom = netCUSTOM(x);
disp (“Matlab和自定义输出的绝对差异”);
disp(mean(abs(Pred_Matlab - Pred_Custom)));
disp (“Matlab梅。”
disp(mean(abs(Pred_Matlab - y)))
disp (“自定义美”
disp(mean(abs(Pred_Custom - y)))
%%%%%%%%%%%%%%%%
这个脚本比较了执行时间和收敛性。
当您运行上面的脚本时,您会得到如下结果。
下面是一些不同设置的例子:
对于3个神经元,这两种算法(trainlm和我自定义的LM)收敛到相似(但不相同)的网络:
Initial_Mu: 0.001
Incr_Rate: 10
Decr_Rate: 0.1
Hidden_Neurons: 3
Matlab时间:
运行时间是0.793722秒。
自定义时间:
运行时间是1.711315秒。
绝对Matlab和自定义输出之间的差异
7.440071774738044 e-07
Matlab
6.179026991132736
自定义
6.179027091263226
对于5个神经元,结果是非常不同的。由于某种原因,我的算法收敛到一个更好的网络:
Initial_Mu: 0.001
Incr_Rate: 10
Decr_Rate: 0.1
Hidden_Neurons: 5
Matlab时间:
运行时间是0.883287秒。
自定义时间:
运行时间为1.980380秒。
绝对Matlab和自定义输出之间的差异
0.007647618697004
Matlab
0.013716265278847
自定义
0.006069555043366
10个神经元的网络几乎是一样的:
Initial_Mu: 0.001
Incr_Rate: 10
Decr_Rate: 0.1
Hidden_Neurons: 10
Matlab时间:
运行时间是1.011172秒。
自定义时间:
运行时间为2.766820秒。
绝对Matlab和自定义输出之间的差异
1.992397943695323 e-08
Matlab
0.030143779923111
自定义
0.030143774946144
对于50个神经元,结果仍然非常相似:
Initial_Mu: 0.001
Incr_Rate: 10
Decr_Rate: 0.1
Hidden_Neurons: 50
Matlab时间:
运行时间是2.985799秒。
自定义时间:
运行时间是7.052290秒。
绝对Matlab和自定义输出之间的差异
8.268088436125254 e-13
Matlab
2.147009752994717 e-04
自定义
2.147009753220598 e-04
对于100个神经元,同样,结果很接近:
Initial_Mu: 0.001
Incr_Rate: 10
Decr_Rate: 0.1
Hidden_Neurons: 100
Matlab时间:
运行时间是8.071735秒。
自定义时间:
运行时间为17.729801秒。
绝对Matlab和自定义输出之间的差异
3.318731955914700 e-13
Matlab
6.768720617779367 e-05
自定义
6.768720614557056 e-05
最后,对于200个神经元,有一个显著的区别:
Initial_Mu: 0.001
Incr_Rate: 10
Decr_Rate: 0.1
Hidden_Neurons: 200
Matlab时间:
运行时间是23.504194秒。
自定义时间:
运行时间是49.679209秒。
绝对Matlab和自定义输出之间的差异
1.711683279275178 e-07
Matlab
2.712217358494099 e-04
自定义
2.712337472282703 e-04
但是,如果通过将增减率设置为1来强制mu为常数,则即使有200个神经元,结果也会变得接近:
Initial_Mu: 0.001
Incr_Rate: 1
Decr_Rate: 1
Hidden_Neurons: 200
Matlab时间:
运行时间是16.398573秒。
自定义时间:
运行时间是24.675034秒。
绝对Matlab和自定义输出之间的差异
7.406640634144424 e-12
Matlab
0.020155109646983
自定义
0.020155109647200
观察和问题:
  1. 我的算法比trainlm慢多了。它大约慢了2倍。在我的代码中有一些明显的瓶颈?
  2. 看起来trainlm和我的算法在实现上有些不同。它们绝对不一样。相似但不相同。
  3. 我的第一个猜测是,matlab使用了一些聪明的方法来反转黑森矩阵。我只是使用了“inv”功能,并禁用了所有的警告。如何matlab反演黑森矩阵到底?它是否使用彭罗斯伪逆和一些智能公差设置?
  4. 考虑到对于常数mu,两个算法产生非常相似的输出,我的第二个猜测是差异在于mu更新模式,可能我使用了稍微不同的方式来更新mu参数。在每次迭代中,我只是使用while循环不断更新mu,直到实现性能改进。如何准确matlab更新参数mu通过迭代?
  5. matlab是否使用一些隐式最小的mu来限制像max_mu参数这样的mu更新?
我为这篇文章的长度道歉,并提前感谢你

接受的答案

马特·J”class=
马特·J 2019年12月23日
编辑:马特·J 2019年12月23日
我的第一个猜测是,matlab使用了一些聪明的方法来反转黑森矩阵。我只是使用了“inv”功能,并禁用了所有的警告。如何matlab反演黑森矩阵到底?
它可能根本不能反转黑森。完全矩阵反演是求解一组线性方程的一种非常低效的方法。更有可能的是,它使用mldivide()或linsolve()。比较:
> > N = 6000;一个=兰德(N);b =兰德(N, 1);
> >抽搐;一个\ b;toc
运行时间是2.510903秒。
> >抽搐;发票(一)* b;toc
运行时间是10.053053秒。
编辑:
在每次迭代中,我都使用while循环不断减小mu,直到实现性能改进。如何准确matlab更新参数mu通过迭代?
我认为你不希望为了更好的下降而减小mu。这会使反转变得越来越奇异。你想要增加。这种机制 trainlm 这在 trainlm文档 ,特别是
自适应值 μ 增加了 mu_inc 直到上述更改导致性能值降低。然后对网络和 μ 减小了 mu_dec
13个评论
罗伯特。”class=
罗伯特。 2019年12月24日
辉煌!你的想法很有效,现在我们离火车的表现很近了。
我明天会做更多的检查,并告诉你最新的情况。
现在,谢谢你,圣诞快乐!

登录评论。

更多答案(2)

马特·J”class=
马特·J 2019年12月23日
编辑:马特·J 2019年12月23日
我想知道您是否也考虑过使用Levenberg-Marquardt的实现 lsqnonlin。 通过使用 SpecifyObjectiveGradient 选项,您仍然可以从自定义的雅可比矩阵计算中获益,但也避免了重新实现/调试负责迭代更新的算法框架的工作。
1评论
罗伯特。”class=
罗伯特。 2019年12月23日
不,我没有。这是个好主意,谢谢。
这将是我的下一个尝试,如果我不设法改善我的代码。
在这一点上,我很清楚,我的算法和trainlm做同样的事情。这两个算法的输出是相同的,直到10个有效数字或更多。我只是想知道为什么我的效率不高。我近了! !

登录评论。


艾哈迈德FAKHRI”class=
艾哈迈德FAKHRI 2020年12月1日
Hi@ 马特·J
我有一个关于Levenberg-Marquardt推导的问题。我不明白在下图中,G(fi(m) ^2)的梯度步骤的元素是如何变成2fi(m)*G(fi(m)j的。你能帮我一下吗?谢谢

社区寻宝

在MATLAB Central中寻找宝藏,并了解社区如何帮助您!

开始狩猎!