梯度寻优
上接 凸优化基础
2.1 逐次逼近法
使用主元消去法求解线性方程组 \(Ax = b\) 相信大家都不陌生,但是对于 \(A\) 的阶数很大且零元素很多的大型稀疏矩阵方程组,使用主元消去法求解将会是一个很大的挑战。鉴于此,逐次逼近法 (或称为迭代法[1]) 提供了解决策略。
下面我们来看看迭代法的具体操作:
首先将 \(Ax=b\) 改写为 \(x = Bx + f\), 使用公式:
其中 \(k\) 为迭代次数 \((k=0, 1, 2, \cdots)\)。
若 \(\displaystyle\lim_{k \to \infty} x^k\) 存在 (记作 \(x^*\)),称此迭代法收敛。显然 \(x^*\) 就是方程组的解,否则称此迭代法发散。
2.1.1 研究数列的收敛性
引入误差向量:
我们可以得到
故而,要研究数列 \(\{x^k\}\) 的收敛性,只需要研究 \(\displaystyle\lim_{k \to \infty} \epsilon^k = 0\) 或 \(\displaystyle\lim_{k \to \infty} B^k = 0\) 满足的条件。
下面以 Numpy 的形式呈现迭代的过程与结果:
2.1.2 消元法
import numpy as np # 载入矩阵运算库
A = np.array([[8, -3, 2], [4, 11, -1], [6, 3, 12]])
b = np.array([[20], [33], [36]])
result = np.linalg.solve(A, b)
print('x\n',result)
x
[[3.]
[2.]
[1.]]
将 \(Ax = b\) 转换为:\(x^{k+1}=B x^k+f\)
B = np.array([[0.0, 3.0 / 8.0, -2.0 / 8.0],
[-4.0 / 11.0, 0.0, 1.0 / 11.0],
[-6.0 / 12.0, -3.0 / 12.0, 0.0]])
f = np.array([[20.0 / 8.0], [33.0 / 11.0], [36.0 / 12.0]])
m, n = B.shape
error = 1e-7 # 误差阈值
steps = 100 # 迭代次数
xk = np.zeros((m, 1)) # 初始化 xk = 0
errorlist = [] # 记录逐次逼近的误差列表
for k in range(steps):
xk_1 = xk # 上一次的 xk
xk = np.dot(B, xk) + f # 本次 xk
errorlist.append(np.linalg.norm(xk - xk_1)) # 计算并存储误差
if errorlist[-1] < error: # 判断误差是否小于阈值
print('终止迭代数:', k + 1) # 输出迭代次数
break
print(xk) # 输出计算结果
终止迭代数: 18
[[2.99999998]
[2.00000003]
[1.00000003]]
2.1.3 绘制误差收敛散点图
from matplotlib import pyplot as plt
def drawScatter(plt, mydata, size=20, color='blue', mrkr='o'):
m, n = mydata.shape
if m > n and m > 2:
plt.scatter(mydata.T[0], mydata.T[1], s=size, c=color, marker=mrkr)
else:
plt.scatter(mydata[0], mydata[1], s=size, c=color, marker=mrkr)
matpts = np.zeros((2, k + 1))
matpts[0] = np.linspace(1, k + 1, k + 1)
matpts[1] = np.array(errorlist)
drawScatter(plt, matpts)
plt.show()
如图, 可以看出误差收敛很快, 从第四次就开始接近最终结果, 后面的若干次迭代都是对结果的微调.
通过误差收敛与否判断解的存在性, 只要误差能够收敛, 方程组就会有解, 但若目标函数是非线性的, 为了更快的收敛, 我们需要找到收敛最快的方向 (梯度方向).
2.2 梯度下降
参考: 梯度下降法
假设目标函数是一个凸函数, 在最优化方法中被表示为:
假如 \(f(x)\) 在 \(x_0\) 处可微, 则 \(∇f(x_0)\) 便是 \(x_0\) 处的变化最快的方向.
为了求解 \(f(x)\) 的最小值, 可以选择任意初始点 \(x_0\), 从 \(x_0\) 出发沿着负梯度方向走, 可使得 \(f(x)\) 下降最快. 引入新的参数 \(\rho_k\) 被称为步长, 有
详细见 梯度相关代码