利用信賴域算法求解無約束的非線性最小二乘問題~

在上一篇博客中,自己介紹了Levenberg_Marquardt的算法流程,特點以及在非線性最小二乘問題上的應用,信賴域算法也是自己曾經研究過的算法,並且在姿態估計上進行了應用,比較下來,得到的精度和Levenberg_Marquardt算法不相上下,但是收斂速度卻不如LM。本文介紹一下自己對信賴域算法的理解,與童鞋們分享一下。

相信做過機器學習的童鞋,一定使用過搜索算法,例如梯度下降法,牛頓法,擬牛頓法,BFGS算法,LM算法等,這些算法有一個共同的特點,它們的基本策略,也就是所謂的算法思想,都是“定方向,定步長”,不知道我這麼概括準確不準確,比如說經典到骨子裏的梯度下降,先選擇梯度相反方向作爲搜索方向,然後要麼一維搜索,要麼索性定個步長公式,沿着既定方向根據步長確定變量更新值,無一例外。然而,半路殺出了個程咬金,信賴域算法卻不是這樣乾的,人家採用的方法是“定區域,定極值”的方法,來達到同樣的目的。牛逼吧?我替你回答, 是的。這個毀三觀的行爲,造就了有趣的信賴域算法。

信賴域算法是在一個球形區域內進行搜索,具體說來,先定好一個球形區域,然後在這個球形區域的中心點進行二階泰勒近似(和LM是不是很像?LM是一階泰勒近似),如公式(1)所示,這個近似美其名曰“子問題”,由於二階泰勒近似其實就是一個二次規劃問題,可以直接求取極值,得到了子問題的最優解之後,下一步就要考察這個最優解(也就是參數變化量d)是否能夠使得“原問題”不斷的下降,這裏,引入了一個比較巧妙的度量方式,用於度量函數值實際下降量和預測下降量之間的比值,如公式(2)所示,如果這個比值大於一定的數值,說明參數變化量d是正確的,進一步,調整球形的半徑r,否則,就要摒棄這個d,減小半徑r,重新搜索。精髓一句話,每一步迭代都會轉化爲子問題來處理,不斷地更新參數,最終得到收斂解。

(1)

(2)

正如上一篇博客一樣,擔心大家聽不懂我在說什麼,我還是畫個算法流程圖,如下所示:



同樣也附上算法代碼,這裏我還是用信賴域算法,去解決任何一個非線性最小二乘問題,輸入變量的含義均已進行註釋。

下一篇博客,我會比較LM與信賴域算法之間對於同一問題的處理速度和算法精度,我覺得這兩個算法有必要好好的比較一下。

如果有bug或error,還請多多指教啊!小弟嗷嗷感激!!

%% 信賴域算法
function[x, iter] = Trust_Region(f, var, x0, r0, miu, yita, eps)
% 目標函數:                       f
% 自變量向量:                    var
% 初始點:                        x0
% 初始信賴域半徑:                r0
% 初始參數:                      miu
% 初始參數:                      yita
% 精度:                          eps
% 目標函數取最小值的自變量值:     x
% 迭代次數:                      iter
tol = 1;
r   = r0;
x   = x0;

% 迭代次數
iter = 1;

while tol > eps   
    jacf    = jacobian(f, var);             % 雅可比矩陣
    hessen  = jacobian(jacf, var);          % 赫森矩陣    
        
    % 計算目標函數值
    fx      = double(subs(f, var, x));
    
    % 計算雅克比矩陣值
    v       = subs(jacf, var, x);
    
    % 計算赫森矩陣值
    pv      = subs(hessen, var, x);
    
    tol     = double(norm(v));
    M_2     = double(pv);                   % 二次規劃 中的二次項矩陣    
    M_1     = double(transpose(v));         % 二次規劃 中的一次項矩陣
    lb      = -r * ones(length(var), 1);    % r爲信賴域半徑,自變量下界約束
    ub      = r * ones(length(var), 1);     % 自變量上界約束
    
    % 求解二次規劃
    [y, fy, EXITFLAG] = quadprog(M_2, M_1, [], [], [], [], lb, ub);
        
    % 重新計算目標函數值
    fx_n = double(subs(f, var, x + y));
    
    % 計算目標函數實際下降與預測下降之比
    p = (fx - fx_n) / (-fy);
        
    if p <= miu % 目標函數實際下降不明顯
        r = 0.5 * r;    
    else % 目標函數值下降明顯   
        x = x + y;    % 更新參數, 擴大信賴域半徑
        
        if p >= yita    % 如果 p > yita
            r = 2 * r;
        end
    end
        
    iter = iter + 1;
end
end


感慨一下,matlab具有強大的符號計算能力,實在是太方便了,總有人說matlab不能算是編程語言,我是超級不同意的,matlab是一門強大的編程語言好不好。尤其是在算法方面。



發佈了42 篇原創文章 · 獲贊 193 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章