倍增法

倍增法是一种用于求解凸优化问题的算法。假设我们有一个形如

\[\begin{split}\begin{array}{ll} \mbox{最小化} & f(x)\\ \mbox{约束} & Ax = b, \end{array}\end{split}\]

的问题,其中 \(f\) 是凸函数,\(x \in \mathbf{R}^n\) 是优化变量,\(A \in \mathbf{R}^{m \times n}\)\(b \in \mathbf{R}^m\) 是问题数据。

为了应用倍增法,我们首先构造增广Lagrangian函数

\[L_{\rho}(x,y) = f(x) + y^T(Ax - b) + (\rho/2)\|Ax-b\|^2_2.\]

与增广Lagrangian函数相关的对偶函数是 \(g_{\rho}(y) = \inf_x L_{\rho}(x,y)\)。对偶函数 \(g_{\rho}(y)\) 是凹函数,其最大值与原始问题的最优值相同。

我们使用梯度上升法来最大化对偶函数。梯度上升的每一步都可以归结为 \(x\)\(y\) 的更新

\[\begin{split}\begin{array}{lll} x^{k+1} & := & \mathop{\rm argmin}_{x}\left(f(x) + (y^k)^T(Ax - b) + (\rho/2)\left\|Ax-b\right\|^2_2 \right) \\ y^{k+1} & := & y^{k} + \rho(Ax^{k+1}-b) \end{array}\end{split}\]

下面的CVXPY脚本实现了乘子法并使用它来解决一个优化问题。

import cvxpy as cp
import numpy as np
np.random.seed(1)

# 初始化数据。
MAX_ITERS = 10
rho = 1.0
n = 20
m = 10
A = np.random.randn(m,n)
b = np.random.randn(m)

# 初始化问题。
x = cp.Variable(shape=n)
f = cp.norm(x, 1)

# 使用CVXPY求解。
cp.Problem(cp.Minimize(f), [A*x == b]).solve()
print("CVXPY得到的最优值: {}".format(f.value))

# 使用乘子法求解。
resid = A*x - b
y = cp.Parameter(shape=(m)); y.value = np.zeros(m)
aug_lagr = f + y.T*resid + (rho/2)*cp.sum_squares(resid)
for t in range(MAX_ITERS):
    cp.Problem(cp.Minimize(aug_lagr)).solve()
    y.value += rho*resid.value

print("乘子法得到的最优值: {}".format(f.value))
CVXPY得到的最优值: 5.5905035557463005
乘子法得到的最优值: 5.572761551213633