1. 牛顿法
牛顿法(英语:Newton's method)又称为牛顿-拉弗森方法(英语:Newton-Raphson method),它是一种在实数域和复数域上近似求解方程的方法。
牛顿法的基本思想是使用函数 的泰勒级数的前面几项来寻找方程
的根。
牛顿法主要应用在两个方面,1:求方程的根;2:最优化(求解最值问题)。
1.1 求方程的根
选择一个接近函数零点的
, 牛顿法对函数进行一阶泰勒展开:
由,得到迭代方式:
迭代后求得方程的根:
牛顿法有一个性质,就是能够保证二次收敛到方程的根。论述如下:
假设函数在开区间
是二阶可导的,并存在函数的根
.定义牛顿迭代法:
假设时,
收敛到
。若
,对于足够大的
,有:
于是,是二次收敛到
。
证明:
假设, 即
,根据泰勒展开公式,
其中,介于
和
之间。
由于
,所以有
由于函数连续可导,且
,只要
和
足够接近,则有
。两边除于
得到
根据牛顿迭代法的定义,可以得到下式:
所以有,
一般地,会收敛到
,由于
介于
和
之间,因此,
收敛到
,
收敛到
。对应足够大的
,有
证毕。
1.2 最优化(求取极值)
解决最优化问题的结构:
给定初始点,
- 确定搜索方向
,即依照一定规则构造
在
点处的下降方向为搜索方向;
- 确定步长因子
,使目标函数值有某种意义下降;
- 令
a) 若满足某种终止条件,则停止迭代,得到近似最优解,
b) 否则,重复以上步骤。

牛顿法解决最优化问题的基本思想是利用目标函数的二次Taylor展开,并将其极小化。
假设目标函数具有二阶连续偏导数,
为目标函数的极小点,对目标函数在第
次迭代值进行二阶泰勒展开:
其中,是
在
的一阶导数值,
是
的海森矩阵:
函数 有极值的必要条件是在极值点处一阶导数为0。特别的当
是正定矩阵时,函数
的极值为极小值。
对方程,根据上述牛顿迭代法可以求解,也可以二阶泰勒展开公式再进行求导:
其中,记,则有
迭代公式:
对于一元函数,上述迭代公式也可以写成:
1.3 牛顿法最优化的示例
import numpy as np
from sklearn import datasets
from sklearn.linear_model import LinearRegression
class Newton(object):
def __init__(self,epochs=50):
self.W = None
self.epochs = epochs
def get_loss(self, X, y, W,b):
"""
计算损失 0.5*sum(y_pred-y)^2
input: X(2 dim np.array):特征
y(1 dim np.array):标签
W(2 dim np.array):线性回归模型权重矩阵
output:损失函数值
"""
#print(np.dot(X,W))
loss = 0.5*np.sum((y - np.dot(X,W)-b)**2)
return loss
def first_derivative(self,X,y):
"""
计算一阶导数g = (y_pred - y)*x
input: X(2 dim np.array):特征
y(1 dim np.array):标签
W(2 dim np.array):线性回归模型权重矩阵
output:损失函数值
"""
y_pred = np.dot(X,self.W) + self.b
g = np.dot(X.T, np.array(y_pred - y))
g_b = np.mean(y_pred-y)
return g,g_b
def second_derivative(self,X,y):
"""
计算二阶导数 Hij = sum(X.T[i]*X.T[j])
input: X(2 dim np.array):特征
y(1 dim np.array):标签
output:损失函数值
"""
H = np.zeros(shape=(X.shape[1],X.shape[1]))
H = np.dot(X.T, X)
H_b = 1
return H, H_b
def fit(self, X, y):
"""
线性回归 y = WX + b拟合,牛顿法求解
input: X(2 dim np.array):特征
y(1 dim np.array):标签
output:拟合的线性回归
"""
np.random.seed(10)
self.W = np.random.normal(size=(X.shape[1]))
self.b = 0
for epoch in range(self.epochs):
g,g_b = self.first_derivative(X,y) # 一阶导数
H,H_b = self.second_derivative(X,y) # 二阶导数
self.W = self.W - np.dot(np.linalg.pinv(H),g)
self.b = self.b - 1/H_b*g_b
print("itration:{} ".format(epoch), "loss:{:.4f}".format(
self.get_loss(X, y , self.W,self.b)))
如果迭代次数epoch调大,两者的效果一样:
itration:495 loss:4.935776
itration:496 loss:4.935776
itration:497 loss:4.935776
itration:498 loss:4.935776
itration:499 loss:4.935776
predict_loss 3.20625981684797
3.2062598186600217