01 | ADMM算法加速的问题导入


    

这个问题的增广拉格朗日函数为:


迭代方程为:
将迭代公式展开为:

Karush-Kuhn-Tucker (KKT)条件是非线性规划(nonlinear programming)最佳解的必要条件。我们对ADMM算法进行收敛性分析。


假设存在  ,  是该问题最优解,即假设存在  ,  ,由迭代公式知当  时  ,当  时  。


当  和  等于0时候  ,  为最优解,将(  ,  )(   ),带入  和  得到:


02 | ADMM算法加速的加速步骤

显然   (Ⅰ)式的  收敛与0,但是原有的ADMM算法收敛速度只有  ,相较于梯度算法更慢,所以需要针对的收敛进行改进。

我们引入predictor-corrector步骤加速算法,加速步骤如下:


采用了predictor-corrector的admm算法:引入加速步骤后算法的收敛速度提升到了  。

03 | ADMM算法加速的实例讲解


为了便于与ADMM优化算法(附MATLAB代码)这篇推文中标准ADMM算法进行比较,我们采用相同的目标函数和约束条件:

  

我们可以构造出该目标函数的拉格朗日表达式:


使用matlab编程,目标函数:


function  fval  = compute_fval(x,y)
fval = (x-1)^2 + (y-2)^2;
end


由于目标函数是二次函数所以使用quadprog函数进行求解。

https://blog.csdn.net/jbb0523/article/details/50598641,关于quadprog函数我们可以参考这篇博客,我们需要求出H,F。


function [H,F] = getHession_F(fn)
% fn : function name
% H :hessian matrix
% F :一次项数系数
syms x y lambda rho; 
if strcmp(fn,'f1')
    f = (x-1)^2 + lambda*(2*x + 3*y -5) + rho/2*(2*x + 3*y -5)^2;
    H = hessian(f,x);
    F = (2*lambda + (rho*(12*y - 20))/2 - 2);
    fcol = collect(f,{'x'});%固定y,默认x为符号变量
    disp(fcol);
elseif strcmp(fn,'f2')
    f = (y-2)^2 + lambda*(2*x + 3*y -5) + rho/2*(2*x + 3*y -5)^2;
    H = hessian(f,y);
    F = (3*lambda + (rho*(12*x - 30))/2 - 4);
    fcol = collect(f,{'y'});%固定x,默认y为符号变量

    disp(fcol);
end
end


标准ADMM算法的函数如下:

function [x,y,iterNum,funval] = solve_admm(param)
 
x = param.x0;
y = param.y0;
lambda = param.lambda;
beta = param.beta;
rho = param.rho;
Hx = param.Hx;
Fx = param.Fx;
Hy = param.Hy;
Fy = param.Fy;
%%
xlb = 0;
xub = 3;
ylb = 1;
yub = 4;
maxIter = param.maxIter;
i = 1;
funval = zeros(maxIter-1,1);
iterNum = zeros(maxIter-1,1);
while 1
    if i == maxIter
        break;
    end
    % solve x
    Hxx = eval(Hx);
    Fxx = eval(Fx);
    x = quadprog(Hxx,Fxx,[],[],[],[],xlb,xub,[]);
    % solve y
    Hyy = eval(Hy);
    Fyy = eval(Fy);
    y=quadprog(Hyy,Fyy,[],[],[],[],ylb,yub,[]);
    % update lambda
    lambda = lambda + rho*(2*x + 3*y -5); % ascend
    funval(i) = compute_fval(x,y);
    iterNum(i) = i;
    i = i + 1;
end
end


ADMM算法加速的函数如下:

function [x,y,iterNum,funval] = fast_solve_admm(param)
x = param.x0;
y = param.y0;
lambda = param.lambda;
beta = param.beta;
alpha = param.alpha;
rho = param.rho;
Hx = param.Hx;
Fx = param.Fx;
Hy = param.Hy;
Fy = param.Fy;

xlb = 0;
xub = 3;
ylb = 1;
yub = 4;
maxIter = param.maxIter;
i = 1;
funval = zeros(maxIter-1,1);
iterNum = zeros(maxIter-1,1);
lambda_pre=0;
y_pre=0;
while 1
    if i == maxIter
        break;
    end
    % solve x
    Hxx = eval(Hx);
    Fxx = eval(Fx);
    x = quadprog(Hxx,Fxx,[],[],[],[],xlb,xub,[]);
    % solve y
    Hyy = eval(Hy);
    Fyy = eval(Fy);
    y_pre=y;
    y=quadprog(Hyy,Fyy,[],[],[],[],ylb,yub,[]);
    % update lambda
    lambda_pre=lambda;
    lambda = lambda + rho*(2*x + 3*y -5); % ascend
    funval(i) = compute_fval(x,y);
    iterNum(i) = i;
    i = i + 1;
    beta = alpha;
    alpha = (sqrt(1+4*alpha^2)+1)/2;
    y=y+((beta-1)/(alpha))*(y-y_pre);
    lambda = lambda+((beta-1)/(alpha))*(lambda-lambda_pre);
end
end

main函数

clear
clc
% x0,y0都是可行解
param.x0 = 1;
param.y0 = 1;
param.lambda = 1;
param.maxIter = 30;
param.beta = 1.1% a constant
param.alpha = 1
param.rho = 0.5;

[Hx,Fx] = getHession_F('f1');
[Hy,Fy] = getHession_F('f2');
 
param.Hx = Hx;
param.Fx = Fx;
param.Hy = Hy;
param.Fy = Fy;
 
%% 标准ADMM算法
[x,y,iterNum,funval] = solve_admm(param);
% 显示标准ADMM算法求得的最小值
disp(['[x,y]:' num2str(x) ',' num2str(y)]);

%% 加速ADMM
[x1,y1,iterNum1,funval1] = fast_solve_admm(param);
% 显示加速ADMM算法求得的最小值
disp(['[x1,y1]:' num2str(x1) ',' num2str(y1)]);

%% 画图,比较标准ADMM和加速ADMM算法的求解曲线
plot(iterNum,funval,'-b');
hold on
plot(iterNum1,funval1,'-r');
legend('ADMM','加速ADMM');


求解结果如下图所示:

ADMM优化算法加速(附MATLAB代码)_java