在上一篇博客中,自己介紹了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是一門強大的編程語言好不好。尤其是在算法方面。