对近端梯度算法(Proximal Gradient Method)的理解

参考:
https://blog.csdn.net/jzwong/article/details/80361180
https://blog.csdn.net/lanyanchenxi/article/details/50448640#comments
前面说到对于不可微的凸函数我们可以利用次梯度算法对目标函数进行求解,但是这并不是唯一求解不可微的凸函数的算法。在参考其他博主写的博客基础上,结合自己的理解为近端梯度算法记下一个笔记。

算法求解的问题的形式

近端梯度算法求解问题的形式如下:
这里写图片描述
其中g(x)和h(x)是由F(x)分离出来的2项,特别的,g(x)是凸函数且可微,h(x)是凸函数但是在某些地方不可微也可以说成g(x)是平滑的,而h(x)是非平滑的函数。正如我们所知道的,传统的梯度下降算法只能解决可微函数的最小化问题。对于在某些地方不可微的凸函数h(x),我们需要其他的解决方法,近端梯度算法就是基于这样的问题提出来的。

proximity operator

在讲解近端梯度算法之前,必要提到proximity operator(投影算子)这个映射(proximal map)。对于凸函数h(x)【不可微】的proximity operator形式为:
这里写图片描述
投影算子其实只和不可微的凸函数有关
基于后面的公式推导的目的,我们在公式(2)中添加一个参数tk,即
这里写图片描述
公式(3)表示:对于给定的点x,找到其最优的点这里写图片描述使得这里写图片描述最小,这个解u是肯定存在的。也就是说,知道h(x)在x处不可微的时候,我们就去求一个点u不仅使得不可微函数h(x)的函数值足够小(最小化因素1),而且还接近原不可微点x(最小化因素2)。
当不可微函数h(x)具有不同的形式,投影算子也具有不同的形式。
这里写图片描述
这里写图片描述
对于上面的式子,用软阈值函数表示即为:soft(xi,λtk)。

近端梯度算法

近端梯度算法的递推式

那么对于要求解这里写图片描述(1)形式的问题,那么x的迭代递推公式为:这里写图片描述,使用(4)我们就可以求得公式(1)的解了。可是为什么递推公式(4)可以使用来求解问题(1)呢?下面给出证明,以使大家能够接受递推式(4)的合理性。

证明递推公式(4)

这里写图片描述
解释一下上面的证明,将公式(4)代入到公式(3)就得到第2步,然后将第3步的平方式展开就得到第4步,第4步红框部分与u无关视为常数,而第5步红框部分也可视为常数,所以将第4步红框部分去除并添加第5步红框部分就得到第5步的公式了,最后将第5步的最后3项近似视为g(u)在这里写图片描述的二阶泰勒展开
由上面的证明可以看出,h(x)函数不变,g(x) 变为在x 的二阶近似。

泰勒展开式

泰勒公式是将一个在x=x0处具有n阶导数的函数f(x)利用关于(x-x0)的n次多项式来逼近函数f(x)的方法。
若函数f(x)在包含x0的某个闭区间[a,b]上具有n阶导数,且在开区间(a,b)上具有(n+1)阶导数,则对闭区间[a,b]上任意一点x,成立下式:
这里写图片描述

近端梯度迭代

对于公式(4)我们将其改写为以下形式:
这里写图片描述
当Gt(x)=0时,则最小化g(x)。

求迭代步长

对于公式(5),我们可以使用2种方法来确定步长tk
(1)使用固定步长tk=1/L
(2)使用线性搜索(line search)确定tk
这里写图片描述
判断条件要求搜索步长不能太大。需要注意的是,我们通过可微分的g(x)来确定步长。
我们注意到红色横线标注的其实就是将要更新的xk,也就是说g(x)在这里写图片描述点的二阶泰勒近似要大于更新之后的g(xk)。这才是保证更新之后的函数值是小于原函数值的,保证走梯度下降的方向(函数值减小的方向)。不知理解可对。

求解L1范数的例子

将求解问题转为递推式

记soft thresholding operator(软阈值算子) 为:
这里写图片描述
现在我们有问题,形式为 这里写图片描述,其中g(x)是可微的凸函数。
按照前面的阐述,该问题求解即为:
这里写图片描述

一个实作

这里写图片描述
这里写图片描述
为了避免上面的展开混淆初学者,这里给出和上面对应的算法的主要步骤:
这里写图片描述

代码

需要注意的是,这里f(x) =1/2||Ax-b||2_{2}(可微凸函数),和我们前面所说的符号略有些差异。

扫描二维码关注公众号,回复: 3188391 查看本文章
function [x]=proximalGradient(A,b,gamma)
%%解决  1/2||AX-b||2_{2}+gamma*||X||1
%% A:m*n   X:n*1

tic;
MAX_ITER =400;
ABSTOL   = 1e-4;
RELTOL   = 1e-2;

f = @(u) 0.5*norm(A*u-b)^2;%%为了确定线搜索步长
lambda = 1;  % 步长
beta = 0.5;
[~,n]=size(A);
x = zeros(n,1);
xprev = x;
AtA = A'*A;
Atb = A'*b;
for k = 1:MAX_ITER
%     while 1
        grad_x = AtA*x - Atb;
        % gamma表示软阈值函数的阈值(非负值)
        % z是要更新的递推迭代式的xk
        z = soft_threshold(x - lambda*grad_x, lambda*gamma);%%迭代更新x
        %线性搜索步长(注释掉即为固定步长)
%         if f(z) <= f(x) + grad_x'*(z - x) + (1/(2*lambda))*(norm(z - x))^2
%             break;
%         end
%         lambda = beta*lambda;   %减小步长

    xprev = x;
    x = z;

    h.prox_optval(k) = objective(A, b, gamma, x, x);
    if k > 1 && abs(h.prox_optval(k) - h.prox_optval(k-1)) < ABSTOL
        break;
    end
end
% %=========================================
% % 得到目标函数的解x以及x所对应的函数近似值p_prox
% %=========================================
h.x_prox = x; % 得到的近端解x
h.p_prox = h.prox_optval(end); % 函数的近端近似值?
% %=========================================
% % 显示程序运行的相关信息
% %=========================================
h.prox_grad_toc = toc; % 计时程序运行时间
fprintf('Proximal gradient time elapsed: %.2f seconds.\n', h.prox_grad_toc);
h.prox_iter = length(h.prox_optval);
K = h.prox_iter;
h.prox_optval = padarray(h.prox_optval', K-h.prox_iter, h.p_prox, 'post');

plot( 1:K, h.prox_optval, 'r-');
xlim([0 75]);


end

function p = objective(A, b, gamma, x, z)
%目标函数的代码形式
  p = 0.5*(norm(A*x - b))^2 + gamma*norm(z,1);
end

function [X]=soft_threshold(b,lambda)
% 软阈值函数
  X=sign(b).*max(abs(b) - lambda,0);
end

猜你喜欢

转载自blog.csdn.net/Chaolei3/article/details/81320940