牛顿法
- 牛顿法也是机器学习中用的比较多的一种优化算法。
1. 牛顿法的基本思想
-
基本牛顿法是一种是用导数的算法,它每一步的迭代方向都是沿着当前点函数值下降的方向。在现有的极小值估计值的附近对做二阶泰勒展开,进而找到极小点的下一个估计值,反复迭代直到函数的一阶导数小于某个接近0的阀值。
-
利用迭代点处的一阶导数(梯度)和二阶导数(Hessen矩阵)对目标函数进行二次函数近似,然后把二次模型的极小点作为新的迭代点,并不断重复这一过程,直至求得满足精度的近似极小值。
-
牛顿法的速度相当快,而且能高度逼近最优值,
2. 牛顿法的用途
- 牛顿法法主要是为了解决非线性优化问题,其收敛速度比梯度下降速度更快。其需要解决的问题可以描述为:对于目标函数f(x),在无约束条件的情况下求它的最小值。
2.1 求解方程的根
-
当方程没有求根公式,或者求根公式很复杂而导致求解困难时,怎么办呢?此时牛顿法就起作用了。
这里假设我们要求f(x) = 0的根。步骤如下: -
首先,选择一个接近函数f(x) = 0的 \(x_{0}\),计算相应的$ f(x_{0}) $ 和切线斜率$ f'(x_{0}) $。
-
然后计算穿过点$ (x_{0},f(x_{0}))并且斜率为f'(x_{0}) $ 的直线和x 轴的交点的坐标,也就是求如下方程的解(公式1):
$ x·f'({x_{0}}) + f(x_{0}) - x_{0}·f'(x_{0}) = 0$证明在文章后
-
我们将新求得的点的x 坐标命名为\(x_{1}\)。可以看到,\(x_{1}\)会比\(x_{0}\)更接近方程f(x) = 0的解。因此我们现在可以利用\(x_{1}\)开始下一轮迭代。我们对公式1进行变换,得到公式2:
$ x_{n+1} = x_{n} - \frac{f(x_{n})}{f'(x_{n})}$ -
通过公式2不断地迭代,就可以越来越接近 f(x) = 0的根。整个的过程可以由下图表示:

2.2 最优化问题——二阶牛顿法
在1.中我们求的是方程等于0的解。在实际的机器学习优化算法中,我们的目标是最小化目标函数的值:min(f(x))
根据数学知识,最小的值的一阶导数往往等于0,因此minf(x)可以转化为求f'(x) = 0。

3. 牛顿法 与 Hessian矩阵的关系

- 牛顿法 在多变量问题上仍然适用迭代求解,但Hessian矩阵的引入增加了复杂性,特别是当:
▪ Hessian 矩阵非正定(非凸)导致无法收敛;
▪ Hessian 矩阵维度过大带来巨大的计算量。
- 针对这个问题,在 牛顿法无法有效执行的情况下,提出了很多改进方法,比如 拟牛顿法(Quasi-Newton Methods)可以看作是牛顿法的近似。
4. 梯度下降法和牛顿法
-
梯度下降法:一阶收敛,可能为局部最优
-
牛顿法的优缺点总结:
-
优点:二阶收敛(因为当迭代到距离收敛值比较近的时候每次迭代都能使误差变为原来的平方),收敛速度快;
-
缺点:牛顿法是一种迭代算法,每一步都需要求解目标函数的Hessian矩阵的逆矩阵,计算比较复杂。
5. coding实现
from sympy import *
import matplotlib.pyplot as plt
x = symbols('x')
xl = 0 #区间下限
xu = 0.11 #区间上限
x0 = (xl+xu)/2 #迭代初始值
x_list = [x0]
i = 0
def f(x):
f = x**3 - 0.165*x**2 + 3.993*10**(-4)
return f
x_values = []
y_values = []
while True:
if diff(f(x),x).subs(x,x0) == 0:
print('极值点:',x0)
break
else:
x0 = x0 - f(x0)/diff(f(x),x).subs(x,x0)
x_list.append(x0)
if len(x_list) > 1:
i += 1
error = abs((x_list[-1] - x_list[-2]) / x_list[-1])
x_values.append(i)
y_values.append(error)
if error == 0:
print(f'迭代第{i}次后,误差等于0')
break
else:
pass
print(f'所求方程式的根为{x_list[-1]}')
#设置绘图风格
plt.style.use('ggplot')
#处理中文乱码
plt.rcParams['font.sans-serif'] = ['Microsoft YaHei']
#坐标轴负号的处理
plt.rcParams['axes.unicode_minus']=False
#横坐标是迭代次数
#纵坐标是误差值
plt.plot(x_values,
y_values,
color = 'steelblue', # 折线颜色
marker = 'o', # 折线图中添加圆点
markersize = 3, # 点的大小
)
# 修改x轴和y轴标签
plt.xlabel('迭代次数')
plt.ylabel('误差值')
# 显示图形
plt.show()

6. 公式1证明
6.1 直接推导
- 假设新方程为f(x) = kx + b,将斜率$ f'(x_{0}) 带入有:f(x) = f'(x_{0})x + b。$
\(由于过点(x_{0},f(x_{0}))\),
进一步带入可以得到:\(b =f(x_{0}) - f'(x_{0})x_{0}\)
因此对于新的方程有:$f(x) = f'(x_{0})x + f(x_{0}) - f'(x_{0})x_{0} $ - 令新方程等于0,即为:
$ x·f'({x_{0}}) + f(x_{0}) - x_{0}·f'(x_{0}) = 0$
6.2 泰勒证明
- 在上面,我们利用求解直线方程的方式,给出了公式1最为直接的推导方法。这里我们给出从泰勒展开推导的过程:
根据我们在$ x_{0} $处进行泰勒展开,如下:
$ f(x)=f(x_{0}) + f'(x_{0})(x-x_{0}) + \frac{f''(x_{0})}{2!}(x-x_{0})^{2} + … + \frac{f{n}(x_{0})}{n!}(x-x_{0}) + R_{n}(x)$
我们只保留一阶以及一阶之前的部分:
\(f(x) = f(x_{0}) + (x-x_{0})f'(x_{0})\)
令f(x) = 0,进一步通过移项整理可得下式,与公式2一致。
$ x = x_{0} - \frac{f(x_{0})}{f'(x_{0})}$
因此可以看到,迭代公式就是是泰勒一阶展开。
泰勒等式只是近似相等,所以求得的x并不能使f(x)=0完全成立
友链:

浙公网安备 33010602011771号