对于连续可微的
n
n
n元函数
f
(
x
)
f(\boldsymbol{x})
f(x),
x
=
(
x
1
⋮
x
i
⋮
x
n
)
∈
R
n
\boldsymbol{x}=\begin{pmatrix} x_1\\\vdots\\x_i\\\vdots\\x_n \end{pmatrix}\in\text{ℝ}^n
x=
x1⋮xi⋮xn
∈Rn,其梯度是由
f
(
x
)
f(\boldsymbol{x})
f(x)对
x
\boldsymbol{x}
x的各分量
x
i
x_i
xi的偏导数
∂
f
/
∂
x
i
\partial f/\partial x_i
∂f/∂xi(
i
=
1
,
2
⋯
,
n
i=1,2\cdots,n
i=1,2⋯,n)构成。事实上,偏导数
∂
f
/
∂
x
i
\partial f/\partial x_i
∂f/∂xi是将
f
(
x
)
f(\boldsymbol{x})
f(x)中的
x
i
x_i
xi视为唯一变量,其他均为常量的一元函数的导数。所以可利用中心差分(详见博文《最优化方法Python计算:一元函数导数的数值计算》)计算偏导数
∂
f
(
x
0
)
∂
x
i
≈
f
(
x
1
+
e
i
Δ
x
/
2
)
−
f
(
x
1
−
e
i
Δ
x
/
2
)
Δ
x
,
i
=
1
,
2
,
⋯
,
n
.
\frac{\partial f(\boldsymbol{x}_0)}{\partial x_i}\approx\frac{f(\boldsymbol{x}_1+\boldsymbol{e}_i\Delta x/2)-f(\boldsymbol{x}_1-\boldsymbol{e}_i\Delta x/2)}{\Delta x},i=1,2,\cdots,n.
∂xi∂f(x0)≈Δxf(x1+eiΔx/2)−f(x1−eiΔx/2),i=1,2,⋯,n.
其中,
e
i
=
(
0
⋮
1
⋮
0
)
i
\begin{array}{cc} \boldsymbol{e}_i=\begin{pmatrix} 0\\\vdots\\1\\\vdots\\0 \end{pmatrix}&i \end{array}
ei=
0⋮1⋮0
i
即第
i
i
i个分量为1其他分量均为0的向量,称为第
i
i
i个基本单位向量,
i
=
1
,
2
,
⋯
,
n
i=1,2,\cdots,n
i=1,2,⋯,n。利用上式,可定义如下计算
n
n
n元可微函数
f
(
x
)
f(\boldsymbol{x})
f(x)在点
x
1
\boldsymbol{x}_1
x1处梯度
∇
f
(
x
1
)
\nabla f(\boldsymbol{x}_1)
∇f(x1)的Python函数。
import numpy as np #导入numpy
def grad(f,x1): #f为函数f(x),x1为自变量值
dx=1e-7 #设置Δx=0.0000001
n=x1.size #x的维度
e=np.eye(n) #n个基本单位向量
g0=np.zeros(n) #梯度初始化为0向量
for i in range(n): #逐一计算偏导数
g0[i]=(f(x1+e[i]*dx/2)-f(x1-e[i]*dx/2))/dx
return g0
程序的第2~9行定义计算n元可微函数梯度的Python函数grad,参数f表示函数
f
(
x
)
f(\boldsymbol{x})
f(x),x1表示自变量(
n
n
n维向量)。第3行设置自变量增量
Δ
x
i
=
1
1
0
7
\Delta x_i=\frac{1}{10^7}
Δxi=1071为dx。第4行读取自变量所含分量个数n。第5行调用numpy的eye函数设置n个单位向量
e
1
,
e
2
,
⋯
,
e
n
\boldsymbol{e}_1,\boldsymbol{e}_2,\cdots,\boldsymbol{e}_n
e1,e2,⋯,en。第6行调用numpy的zeros函数将梯度g0初始化为0向量。第7~8行的for语句按前式逐一计算偏导数
∂
f
(
x
1
)
∂
x
i
\frac{\partial f(\boldsymbol{x}_1)}{\partial x_i}
∂xi∂f(x1),
i
=
1
,
2
,
⋯
,
n
i=1,2,\cdots,n
i=1,2,⋯,n。
相仿地,利用对广义导数的中心差分(详见博文《最优化方法Python计算:一元函数导数的数值计算》),可得二阶可微函数
f
(
x
)
f(\boldsymbol{x})
f(x)的二阶偏导数的计算公式
∂
2
f
(
x
1
)
∂
x
i
∂
x
j
≈
[
f
(
x
1
+
(
e
i
+
e
j
)
Δ
x
2
)
+
f
(
x
1
−
(
e
i
+
e
j
)
Δ
x
2
)
−
f
(
x
1
+
(
e
i
−
e
j
)
Δ
x
2
)
−
f
(
x
1
−
(
e
i
−
e
j
)
Δ
x
2
)
]
/
Δ
x
2
,
1
≤
i
,
j
≤
n
\frac{\partial^2f(\boldsymbol{x}_1)}{\partial x_i\partial x_j}\approx\left[ f\left(\boldsymbol{x}_1+(\boldsymbol{e}_i+\boldsymbol{e}_j)\frac{\Delta x}{2}\right)+f\left(\boldsymbol{x}_1-(\boldsymbol{e}_i+\boldsymbol{e}_j)\frac{\Delta x}{2}\right)\right.\\ \quad-\left.f\left(\boldsymbol{x}_1+(\boldsymbol{e}_i-\boldsymbol{e}_j)\frac{\Delta x}{2}\right)-f\left(\boldsymbol{x}_1-(\boldsymbol{e}_i-\boldsymbol{e}_j)\frac{\Delta x}{2}\right)\right]\big/\Delta x^2,1\leq i,j\leq n
∂xi∂xj∂2f(x1)≈[f(x1+(ei+ej)2Δx)+f(x1−(ei+ej)2Δx)−f(x1+(ei−ej)2Δx)−f(x1−(ei−ej)2Δx)]/Δx2,1≤i,j≤n
利用上式,定义计算
n
n
n元二阶可微函数
f
(
x
)
f(\boldsymbol{x})
f(x)在点
x
1
\boldsymbol{x}_1
x1处Hesse阵的Python函数如下
import numpy as np #导入numpy
def hess(f,x1): #f表示函数,x1表示自变量
dx=7.5e-8 #设置自变量增量Δx
n=x1.size #向量维数
e=np.eye(n) #基本单位向量
H0=np.zeros((n,n)) #Hesse阵初始化为0阵
for i in range(n): #逐一计算二阶偏导
for j in range(n):
H0[i,j]=(f(x1+(e[i]+e[j])*dx/2)+f(x1-(e[i]+e[j])*dx/2)-
f(x1+(e[i]-e[j])*dx/2)-f(x1-(e[i]-e[j])*dx/2))/dx**2
return H0
程序的第2~1行定义
n
n
n元二阶可微函数
f
(
x
)
f(\boldsymbol{x})
f(x)在点
x
1
\boldsymbol{x}_1
x1处Hesse矩阵
H
(
x
1
)
\boldsymbol{H}(\boldsymbol{x}_1)
H(x1)的计算函数hess。第3行设置自变量增量
Δ
x
=
7.5
⋅
1
0
−
8
\Delta x=7.5\cdot10^{-8}
Δx=7.5⋅10−8为dx。第4行读取作为自变量的
x
1
\boldsymbol{x}_1
x1的维数n。第5行调用numpy的eye函数设置n个单位向量
e
1
,
e
2
,
⋯
,
e
n
\boldsymbol{e}_1,\boldsymbol{e}_2,\cdots,\boldsymbol{e}_n
e1,e2,⋯,en。第6行调用numpy的zeros函数将Hesse阵H0初始化为0阵。第7~10行的两重for循环按上式逐一计算
f
(
x
)
f(\boldsymbol{x})
f(x)在
x
1
\boldsymbol{x}_1
x1的二阶偏导数
∂
2
f
(
x
1
)
∂
x
i
∂
x
j
\frac{\partial^2f(\boldsymbol{x}_1)}{\partial x_i\partial x_j}
∂xi∂xj∂2f(x1)并置于H[i,j]。
例1:计算函数
f
(
x
,
y
)
=
x
1
4
+
x
2
4
−
4
x
1
2
x
2
2
,
(
x
1
,
x
2
)
∈
R
2
f(x,y)=x_1^4+x_2^4-4x_1^2x_2^2,(x_1,x_2)\in\text{ℝ}^2
f(x,y)=x14+x24−4x12x22,(x1,x2)∈R2在
x
1
=
(
1
2
1
2
)
\boldsymbol{x}_1=\begin{pmatrix} \frac{1}{2}\\\frac{1}{2} \end{pmatrix}
x1=(2121)的梯度和Hesse矩阵。
解:下列代码调用上列程序定义的函数grad和hess计算
∇
f
(
x
1
)
\nabla f(\boldsymbol{x}_1)
∇f(x1)和
H
(
x
1
)
\boldsymbol{H}(\boldsymbol{x}_1)
H(x1)。
import numpy as np #导入numpy
from utility import grad,hess #导入grad,hess
f=lambda x:(x[0]**4)+(x[1]**4)-4*(x[0]**2)*(x[1]**2) #设置函数
x1=np.array([0.5,0.5]) #设置自变量x1
print(grad(f,x1)) #计算梯度
print(hess(f,x1)) #计算Hesse阵
利用代码内部的注释信息不难理解上述程序。运行程序,输出
[-0.5 -0.5]
[[ 1.00166788 -4.00667154]
[-4.00667154 1.00166788]]
输出的第1行,表示
f
(
x
)
f(\boldsymbol{x})
f(x)在
x
1
=
(
1
2
1
2
)
\boldsymbol{x}_1=\begin{pmatrix} \frac{1}{2}\\\frac{1}{2} \end{pmatrix}
x1=(2121)的梯度
∇
f
(
x
1
)
=
(
−
1
2
−
1
2
)
\nabla f(\boldsymbol{x}_1)=\begin{pmatrix} -\frac{1}{2}\\-\frac{1}{2} \end{pmatrix}
∇f(x1)=(−21−21)的近似,输出的第2~3行表示Hesse矩阵
H
(
x
1
)
=
(
1
−
4
−
4
1
)
\boldsymbol{H}(\boldsymbol{x}_1)=\begin{pmatrix} 1&-4\\ -4&1 \end{pmatrix}
H(x1)=(1−4−41)的近似。
写博不易,敬请支持:
如果阅读本文于您有所获,敬请点赞、评论、收藏,谢谢大家的支持!