python实现牛顿法_python实现牛顿法求解求解最小值(包括拟牛顿法)【最优化课程笔记】...

什么是牛顿法

在第9章中介绍了一维搜索的牛顿法,什么是一维搜索的牛顿法?

首先介绍一下一维搜索

一维搜索

一维搜索其实也很简单,在许多迭代下降算法中,具有一个共同的特点,就是得到点x(k)后,需要按照某种规则确定一个方向d(k),再从x(k)出发,沿着d(k)的方向上求目标函数的极小点。从而得到x(k+1),重复以上做法,知道求得问题的解。这就是一维搜索。上面提到的d可以称作为步长因子。

一维搜索的方法有很多,归纳起来可以大体分成两类。

试探法 : 这种方法需要按照某种方式找试探点,通过一系列试探点来确定极小点。

函数逼近法,或是插值法 : 用某种简单的曲线逼近本来的函数曲线,通过求逼近函数的极小点来估计目标函数的极小点。

里面的种种门道也是颇为复杂,这里就讲讲一维搜索的牛顿法,这是函数逼近法的一种。

一维搜索的牛顿法

牛顿法的基本思想是,在极小点附近用二阶Taylor多项式近似目标函数f(x),进而求出极小点的估计值。

假设,考虑问题

$$min f(x), x\in\Re.$$

$$\phi(x) = f(x^{(k)}) + f^{'}(x^{(k)})(x-x^{(k)}) + \frac{1}{2}f^{''}(x^{(k)})(x-x^{(k)})^2$$

又令

$$\phi^{'}(x) = f^{'}(x^{(k)}) + f^{''}(x^{(k)})(x-x^{(k)}) = 0$$

得到 $ phi(x) $ 的驻点,记作x(k+1),则

$$x^{(k+1)} = x^{(k)} - \frac{f^{'}(x^{(k)})}{f^{''}(x^{(k)})}$$

有了以上公式的推导,相信已经能够理解,下面为了加深对这个算法的印象,毕竟大家都是程序员,需要用伪代码才能说服对方。

牛顿法的计算步骤:

(1)给定初始点 x(0),允许误差 delta > 0 ,置k = 0

(2)若

$$ f^{'}(x^{(k)}) < delta $$

则迭代停止,,得到结果。

(3)计算点

$$x^{(k+1)} = x^{(k)} - \frac{f^{'}(x^{(k)})}{f^{''}(x^{(k)})}$$

置 k:=k+1,转步骤(2)

运用牛顿法是,初始点选择十分重要,如果初始点靠近极小点,则可能很快收敛,如果初始点远离极小点,迭代产生的点列可能不收敛于极小点。

牛顿法

一般来讲的牛顿法是使用导数的最优化方法,这里的牛顿法和一维搜索的牛顿法差别在于更新公式的不同,这里的迭代公式如下。

$$x^{(k)} = x^{(k)} - \nabla^{2}f(x^{(k)})^{-1} \nabla f(x^{(k)})$$

计算的步骤也是一样的。

其实误差delta可以设置是1-范式,也可以是2-范式。

coding time

"""

Newton法

Rosenbrock函数

函数 f(x)

梯度 g(x)

hessen 矩阵

"""

import numpy as np

import matplotlib.pyplot as plt

# 一阶导

def jacobian(x):

return np.array([2*x[0]+3,2*x[1]+4])

# 二阶导

def hessian(x):

return np.array([[2,0],[0,2]])

X1=np.arange(-1.5,1.5+0.05,0.05)

X2=np.arange(-3.5,2+0.05,0.05)

[x1,x2]=np.meshgrid(X1,X2)

f=x1**2+x2**2+3*x1+4*x2-26; # 给定的函数

plt.contour(x1,x2,f,20) # 画出函数的20条轮廓线

def newton(x0):

print('初始点为:')

print(x0,'\n')

W=np.zeros((2,10**3))

i = 1

imax = 1000

W[:,0] = x0

x = x0

delta = 1

while i0.1:

p = -np.dot(np.linalg.inv(hessian(x)),jacobian(x))

print(jacobian(x))

print(hessian(x))

x0 = x

x = x + p

W[:,i] = x

delta = sum((x-x0))

print('第'+str(i)+'次迭代结果:')

print(x,'\n')

i=i+1

W=W[:,0:i] # 记录迭代点

return W

x0 = np.array([1,1])

W=newton(x0)

plt.plot(W[0,:],W[1,:],'g*',W[0,:],W[1,:]) # 画出迭代点收敛的轨迹

plt.show()

代码注释的很清楚了,就不解释了,下面再提一句,如果更新时乘上了alpha值,就成了阻尼牛顿法。

"""

Newton法

Rosenbrock函数

函数 f(x)

梯度 g(x)

hessen 矩阵

"""

import numpy as np

import matplotlib.pyplot as plt

# 一阶导

def jacobian(x):

return np.array([2*x[0]+3,2*x[1]+4])

# 二阶导

def hessian(x):

return np.array([[2,0],[0,2]])

X1=np.arange(-1.5,1.5+0.05,0.05)

X2=np.arange(-3.5,2+0.05,0.05)

[x1,x2]=np.meshgrid(X1,X2)

f=x1**2+x2**2+3*x1+4*x2-26; # 给定的函数

plt.contour(x1,x2,f,20) # 画出函数的20条轮廓线

def newton(x0):

print('初始点为:')

print(x0,'\n')

W=np.zeros((2,10**3))

i = 1

imax = 1000

W[:,0] = x0

x = x0

delta = 1

alpha = 0.1

while i0.1:

p = -np.dot(np.linalg.inv(hessian(x)),jacobian(x))

print(jacobian(x))

print(hessian(x))

x0 = x

x = x + alpha*p

W[:,i] = x

delta = sum((x-x0))

print('第'+str(i)+'次迭代结果:')

print(x,'\n')

i=i+1

W=W[:,0:i] # 记录迭代点

return W

x0 = np.array([1,1])

W=newton(x0)

plt.plot(W[0,:],W[1,:],'g*',W[0,:],W[1,:]) # 画出迭代点收敛的轨迹

plt.show()

你可能感兴趣的:(python实现牛顿法)