四參數擬合算法之高斯牛頓法

介紹

 前面提到了牛頓法,那其實相當於求根的算法。跟一般最小二乘法的區別是,它並沒有顯示的最小二乘目標式子。
F(A,B,C,D,xi)=0F(A,B,C,D,x_i) = 0

 下面提到的高斯牛頓法,則要正式引入最小二乘法的目標式子。首先對牛頓法做一次更深入的展開。

牛頓法

 牛頓法在用於一元方程求根的時候,只需要做一階泰勒展開,這個時候,用到的是迭代點的導數信息找到下一個迭代點。在多維的情況下面,則用到了梯度信息。在求解的問題的時候,假如初始點選得不好,可能會遇到梯度消失的問題,最後會導致收斂失敗。但這好像是優化算法的一個通病,並非牛頓法的專利。言歸正傳,下面解釋一下牛頓法在四參數數據擬閤中應用。
對於給定的m組數據 (xi,yi)(x_i,y_i),
w=[A,B,C,D]Tf(w;xi)=D+AD1+(xi/C)Bri(w)=yif(w;xi) \\ w = [A,B,C,D]^T \\ f(w;x_i) = D+\frac{A-D}{1+(x_i/C)^B} \\ r_i(w) = y_i-f(w;x_i)
ri(w)Rr_i(w)\in \mathbb{R}稱爲剩餘值,或者叫殘差,偏差,是一個標量,r(w)Rm×1r(w)\in \mathbb{R}^{m\times 1}表示剩餘函數,是一個向量。ff爲待擬合的公式
求解的目標是使得殘差平方最小,如下
min F(w)=12r(w)Tr(w)=12i=1myif(w;xi)2 min \ F(w) =\frac{1}{2} r(w)^Tr(w) = \frac{1}{2} \sum_{i=1}^{m}||y_i-f(w;x_i) ||^2
牛頓法的第一步是求得F(w)F{'}(w),令F(w)=0F{'}(w) = 0,再對其做泰勒展開
F(w+Δw)F(w)+F(w)Δw=0Δw=(F(w))1F(w) F{'}(w+\Delta w) \approx F{'}(w)+F{''}(w)\Delta w=0 \\\Rightarrow \Delta w = -(F{''}(w))^{-1}F{'}(w)
總共需要對F做二次求導,這裏需要引入jacob矩陣
w 關於r的雅可比矩陣如下
J=[r1Ar1DrmArmD]=[r1(w)rm(w)] J=\begin{bmatrix} \frac{\partial r_1}{\partial A}&\cdots&\frac{\partial r_1}{\partial D}\\ \vdots&\ddots&\vdots\\ \frac{\partial r_m}{\partial A}&\cdots&\frac{\partial r_m}{\partial D} \end{bmatrix}=\begin{bmatrix} r^{'}_1(w)\\ \vdots \\ r^{'}_m(w) \end{bmatrix}

F的梯度信息g(w)
g(w)=F(w)=i=1mri(w)ri(w)=JTr(w) g(w) = F^{'}(w) =\sum_{i=1}^{m}r_i(w)r_i^{'}(w)=J^Tr(w)
ri(w)Rr_i(w)\in \mathbb{R}爲標量,ri(w)Rm×1r_i(w)^{'}\in \mathbb{R}^{m \times 1}爲偏導,或者說梯度,是一個向量,最後得到,g(w)Rm×1g(w)\in \mathbb{R}^{m \times 1}
F的海賽陣爲
G(w)=i=1m(ri(w)ri(w)T+ri(w)ri(w))=JTJ+S(w) G(w) = \sum_{i=1}^{m}(r_i^{'}(w)r_i^{'}(w)^T+r_i(w)r_i^{''}(w))=J^TJ+S(w)
Δw=(F(w))1F(w)=(JTJ+S(w))1JTr(w) \Delta w = -(F{''}(w))^{-1}F{'}(w)=-(J^TJ+S(w))^{-1}J^Tr(w)
S(w)Rn×nS(w)\in \mathbb{R}^{n \times n}通常運算量巨大,這部分常用兩種處理,一種是忽略,即小剩餘算法,另外一種是近似,大剩餘算法。
高斯牛頓法忽略了其高階項S(x),相當於目標式子的一階泰勒展開
Δw=(F(w))1F(w)=(JTJ)1JTr(w) \Delta w = -(F{''}(w))^{-1}F{'}(w)=-(J^TJ)^{-1}J^Tr(w)
這個做法其實等同於之前的牛頓法。當殘量r(w)r(w^*)比較小時,這種方法比較有效,反之,算法就比較難收斂。另外,從上公式裏面可以看到,Δw\Delta w的計算要求JJ爲列滿秩,否則求得的結果可能不穩定,導致算法難以收斂。 爲了克服這個問題,其中一個手段是改善矩陣JTJJ^TJ的變態程度。常用的處理就是在方程中加入擾動,也就是嶺迴歸做的事情。從另外一個角度來說,也是加入Δw\Delta w的2範式懲罰。爲什麼這麼做呢,因爲對於泰勒展開而言,無疑Δw\Delta w越大,展開式越不準確。由此,便得到了Levenberg-Marquardt算法。

Matlab Code

>> [A,B,C,D] =-10 36.9 1974.7 431.0

下面的代碼和之前代碼基本一致,只不過去掉了matlab 的symbolic運算,速度快的飛起

clear;
load census;
x1 = cdate ;
y1 = pop ;
lamda = 0.3;
%init a,b,c,d
d = max(y1)+1;
a = min(y1)-0.1;
y2 = log((y1-d)./(a-y1));
x2 = log(x1);
[curve2,gof2] = fit(x2,y2, 'poly1');
b = -curve2.p1;
c = exp(curve2.p2/b);
%newton
for k = 1:1:1000
    fy = [];
    JacobiMatrix = ones(length(x1),4);
    w=[a,b,c,d];
    [res,R,fit] = evaluateFit(y1,x1,w);
    if R>0.997
        return;
    end
    for i = 1:1:length(x1)
        fy(i,:) =  d+(a-d)/(1+(x1(i)/c)^b);
        JacobiMatrix(i,1) = calc_pA(x1(i),a,b,c,d);
        JacobiMatrix(i,2) = calc_pB(x1(i),a,b,c,d);
        JacobiMatrix(i,3) = calc_pC(x1(i),a,b,c,d);
        JacobiMatrix(i,4) = calc_pD(x1(i),a,b,c,d);
    end
    delta_w = inv((JacobiMatrix)'*(JacobiMatrix))*JacobiMatrix'*(y1-fy);
    %update a b c d
    a = a +lamda*delta_w(1);
    b = b+lamda*delta_w(2);
    c = c +lamda*delta_w(3);
    d= d +lamda*delta_w(4);
end

function [res,R2,fit] = evaluateFit(y,x,w)
fit = getFittingValue(x,w);
res =  norm(y-fit)/sqrt(length(fit));
yu =  mean(y);
R2 = 1 - norm(y-fit)^2/norm(y - yu)^2;
end
function fit = getFittingValue(x,w)
len = length(x);
fit = ones(len,1);
for i = 1:1:len
    fit(i)  = hypothesis(x(i),w);
end
end
function val  = hypothesis(x,w)
a = w(1);b= w(2);c= w(3);d= w(4);
val = d+(a-d)/(1+(x/c)^b);
end
function val = calc_pA(x,A,B,C,D)
val = 1/((x/C)^B + 1);
end
function val = calc_pB(x,A,B,C,D)
val = -(log(x/C)*(A - D)*(x/C)^B)/((x/C)^B + 1)^2;
end
function val = calc_pC(x,A,B,C,D)
val = (B*x*(A - D)*(x/C)^(B - 1))/(C^2*((x/C)^B + 1)^2);
end
function val = calc_pD(x,A,B,C,D)
val = 1 - 1/((x/C)^B + 1);
end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章