符号说明
f
(
x
)
f(\textbf{x})
f(x)表示函数,某个
x
\textbf{x}
x向量对应的值是个常量。
x
\textbf{x}
x表示函数空间中在各个轴上的未知变量,表示为nx1的列向量。以(x,y,z)三维空间举例子,
x
\textbf{x}
x表示x,y两个轴上的变量,
f
(
x
)
f(\textbf{x})
f(x)代表在z轴上的映射,是一个常量。以后用
x
i
x_i
xi表示非
f
(
x
)
f(\textbf{x})
f(x)值所在的轴,y表示在
f
(
x
)
f(\textbf{x})
f(x)值所在的轴,比如三维空间中的点可表示成
(
x
1
,
x
2
,
y
)
(x_1,x_2,y)
(x1,x2,y)。
x
t
=
(
x
1
t
,
x
2
t
,
.
.
.
,
x
n
t
)
T
\textbf{x}_t=(x_{1}^{t},x_{2}^t,...,x_{n}^t)^T
xt=(x1t,x2t,...,xnt)T表示一个预估的nx1维向量,是确定的值。
▽
f
(
x
)
=
d
f
(
x
)
d
x
\triangledown{f(\textbf{x})}=\frac{df(\textbf{x})}{d\textbf{x}}
▽f(x)=dxdf(x)代表在
x
\textbf{x}
x方向上的导数,是一个列向量。
H
=
▽
2
f
(
x
)
=
▽
f
(
x
)
d
x
T
\textbf{H}=\triangledown{^2f(\textbf{x})}=\frac{\triangledown{f(\textbf{x})}}{d\textbf{x}^T}
H=▽2f(x)=dxT▽f(x)是一个nxn的矩阵,其中
H
i
j
=
∂
2
f
(
x
)
∂
x
i
∂
x
j
\textbf{H}_{ij}=\frac{\partial{^2f({\textbf{x})}}}{\partial{\textbf{x}}_i\partial{\textbf{x}}_j}
Hij=∂xi∂xj∂2f(x),也被称作海森矩阵(此处的i,j并不是指
x
\textbf{x}
x是一个nxn的矩阵,对于
x
\textbf{x}
x而言仅仅下标i与j之间不存在相关性而已,
x
\textbf{x}
x仍然是nx1的向量)。
牛顿法
在梯度下降法出现以前,常用的数值求解方法是牛顿法。
更严谨地讲,在求解之前需要证明牛顿法对该函数而言是收敛的,否则无法求出解,对于大多数应用而言,基本都是收敛的,而且由于本人精力有限,证明方式在此略过。
1.利用牛顿法求零点。
在二维平面中,牛顿法表示方法为
x
t
+
1
=
x
t
−
f
(
x
t
)
f
′
(
x
t
)
x_{t+1}=x_t-\frac{f(x_t)}{f^{'}(x_t)}
xt+1=xt−f′(xt)f(xt)
从迭代示意图中可以看出,迭代过程实际上是多个直线向零点方向前进,直到最后一个直线与曲线的零点重合为止。
那么在n+1维空间中,在点
x
t
\textbf{x}_t
xt上对
f
(
x
)
f(\textbf{x})
f(x)求梯度,满足以下等式
▽
f
(
x
t
)
T
(
x
t
+
1
−
x
t
)
+
f
(
x
t
)
=
0
(1)
\triangledown{f(\textbf{x}_t)}^T(\textbf{x}_{t+1}-\textbf{x}_t)+f(\textbf{x}_t)=0\tag{1}
▽f(xt)T(xt+1−xt)+f(xt)=0(1)
尝试绘制三维空间中迭代示意图
f
(
x
)
=
x
1
2
+
x
2
2
f(x)=x_1^2+x_2^2
f(x)=x12+x22,可能因为视图原因,不太好看,图中黄色部分为y=0所在平面,绿色部分为迭代平面,最终结果也是使迭代平面与二维曲面的零点重合。同样高维空间内是利用超平面进行迭代。
但是对于
f
(
x
)
=
x
1
2
+
x
2
2
−
8
f(x)=x_1^2+x_2^2-8
f(x)=x12+x22−8而言存在无数个零点,每一次迭代就会出现无数个解,这种求解方法显得有些乏力。
2.利用二阶可导的情况下利用牛顿法求极值
如果
f
(
x
)
f(\textbf{x})
f(x)二阶可导,那么求
f
(
x
)
f(\textbf{x})
f(x)的极值可以转化为求梯度
▽
f
(
x
)
\triangledown{f(\textbf{x})}
▽f(x),再对该梯度求零点的问题。
将
▽
f
(
x
)
\triangledown{f(\textbf{x})}
▽f(x)带入(1)得
▽
2
f
(
x
t
)
(
x
t
+
1
−
x
t
)
+
▽
f
(
x
t
)
=
0
\triangledown{^2f(\textbf{x}_t)}(\textbf{x}_{t+1}-\textbf{x}_t)+\triangledown{f(\textbf{x}_t)}=\textbf{0}
▽2f(xt)(xt+1−xt)+▽f(xt)=0
⇒
\Rightarrow
⇒
x
=
x
t
−
▽
2
f
(
x
t
)
−
1
▽
f
(
x
t
)
(2)
\textbf{x}=\textbf{x}_t-\triangledown{^2f(\textbf{x}_t)}^{-1}\triangledown{f(\textbf{x}_t)}\tag{2}
x=xt−▽2f(xt)−1▽f(xt)(2)
其中
▽
2
f
(
x
t
)
−
1
▽
f
(
x
t
)
\triangledown{^2f(\textbf{x}_t)}^{-1}\triangledown{f(\textbf{x}_t)}
▽2f(xt)−1▽f(xt)被称为迭代方向。
对于函数
f
(
x
)
=
x
1
2
+
x
2
2
f(x)=x_1^2+x_2^2
f(x)=x12+x22而言,仅仅需要迭代一次,即橙色与绿色平面确定的直线与y=0相交的位置为极值点所在位置。
但是有时会出现
H
\textbf{H}
H矩阵的逆不存在的情况,说明存在线性相关的二阶导数向量,那么n个平面之间不可能会相交到一条直线上,而且对
H
\textbf{H}
H求逆的运算太复杂,所以在求解过程中,常用的求解形式是
Hb
=
▽
f
(
x
)
\textbf{Hb}=\triangledown{f(x)}
Hb=▽f(x)
求出
b
\textbf{b}
b之后,利用公式
x
t
+
1
=
x
t
−
d
\textbf{x}_{t+1}=\textbf{x}_{t}-\textbf{d}
xt+1=xt−d迭代求解。
牛顿法在求解极值相较于其它梯度下降法而言,迭代次数少而且精度高,但是牛顿法的缺点是对函数求二阶导数而且还需要对矩阵求逆耗费很长时间,而且有些矩阵无法求逆,很多人对牛顿法做了了多次改进以提升运算效果,但在机器学习以及数值计算中常用的方法却是梯度下降法,梯度梯度下降法的递推式在形式上与牛顿法很相似,但是二者的计算思想以及推理方式却完全不同,具体的方法将在本人的另一篇博客中介绍。
绘制图像的python代码
第一幅图
import matplotlib.pyplot as plt
import numpy as np
x=np.arange(0,10,0.1)
y=x*x
plt.plot(x,y)
#第一次迭代
t1=np.array([10,3])
y1=16*t1-64
plt.plot(t1,y1,color='red')
#绘制虚线
plt.plot([8,8],[0,64],color='red',linestyle="--")
plt.plot([4,8],[0,0],color='red',linestyle="--")
#添加图例
plt.annotate(r'$step1:y=16x-64$',
xy=(8,64), xycoords='data',
xytext=(+30,+40), textcoords='offset points', fontsize=8,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.0"))
#第二次迭代
t1=np.array([6,1])
y1=8*t1-16
plt.plot(t1,y1,color='green')
#绘制虚线
plt.plot([4,4],[0,16],color='green',linestyle="--")
plt.plot([2,4],[0,0],color='green',linestyle="--")
#添加图例
plt.annotate(r'$step2:y=8x-16$',
xy=(4,16), xycoords='data',
xytext=(+30,+40), textcoords='offset points', fontsize=8,
arrowprops=dict(arrowstyle="->", connectionstyle="arc3,rad=.0"))
#坐标轴居中
ax = plt.subplot(111)
ax.spines['right'].set_color('none')
ax.spines['top'].set_color('none')
ax.xaxis.set_ticks_position('bottom')
ax.spines['bottom'].set_position(('data',0))
ax.yaxis.set_ticks_position('left')
ax.spines['left'].set_position(('data',0))
plt.show()
第二幅图
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
fig = figure()
ax = Axes3D(fig)
X = np.arange(-4, 4, 0.2)
Y = np.arange(-4, 4, 0.2)
X, Y = np.meshgrid(X, Y)
Z =X**2 + Y**2-8
ax.plot_surface(X, Y, Z)
Z=0*X+0*Y
ax.plot_surface(X,Y,Z)
z1=4*X+4*Y
ax.plot_surface(X,Y,z1)
show()
第三幅图
from pylab import *
from mpl_toolkits.mplot3d import Axes3D
fig = figure()
ax = Axes3D(fig)
X = np.arange(-4, 4, 0.2)
Y = np.arange(-4, 4, 0.2)
X, Y = np.meshgrid(X, Y)
Z =X**2 + Y**2
ax.plot_surface(X, Y, Z)
z1=2*X-1
z2=2*Y-1
ax.plot_surface(X,Y,z1)
ax.plot_surface(X,Y,z2)
show()