一、高等数学(梯度与牛顿法)
1.1梯度向量
- 梯度是一个向量(方向和模),表示某一函数在该点处的方向导数沿着该方向取得最大值
- 简单来说,函数在某点沿着梯度的方向变化最快,变化率最大(即为梯度的模)
1.2牛顿法
- 牛顿法是求解函数值为0时的自变量取值的方法。利用牛顿法求解目标函数的最小值其实是转化成求使目标函数的一阶导为0的参数值。这一转换的理论依据是,函数的极值点处的一阶导数0。
- 牛顿法迭代过程是在当前位置x0求该函数的切线,该切线和x轴的交点x1,作为新的x0,重复这个过程,直到交点和函数的零点重合。此时的参数值就是使得目标函数取得极值的参数值。其迭代过程如下:
1.3梯度下降法与牛顿法的比较
- 梯度下降法:通过梯度方向和步长,直接求解目标函数的最小值时的参数。越接近最优值时,步长应该不断减小,否则会在最优值附近来回震荡。
- 牛顿法:
通过求解目标函数的一阶导数为0时的参数,进而求出目标函数最小值时的参数。收敛速度很快。海森矩阵的逆在迭代过程中不断减小,可以起到逐步减小步长的效果。然而,缺点是海森矩阵的逆计算复杂,代价比较大,因此有了拟牛顿法。
二、作业(Rosenbrock函数)
第一问:不同的a,b取值对该表面形状的影响
import numpy as np
import matplotlib.pyplot as plt
from ipywidgets import * # 可以实现 jupyter notebook 笔记本的交互式控件操作
@interact(a=(-10, 10, 0.1), b=(-10, 10, 1))
def plot_3d(a=0, b=0):
plt.figure(figsize=(10, 10))
#生成x轴数据列表
x = np.arange(-100, 100, 0.1)
#生成y轴数据列表
y = np.arange(-100, 100, 0.1)
#网格化
X, Y = np.meshgrid(x, y)
Z = np.square(a - X) + b * np.square(Y - np.square(X))
ax = plt.subplot(1, 1, 1, projection='3d')
ax.plot_surface(X, Y, Z, cmap='rainbow')
ax.set_xlabel('x')
ax.set_ylabel('y')
ax.set_zlabel('z')
plt.title('Rosenbrock')
第二问:求解最小值及相应的最小解(采用梯度下降法)
import numpy as np
import time
# 设定随机种子
np.random.seed(2021)
# 定义题目所给函数
def func(x1, x2, a, b):
return (a - x1) ** 2 + b * (x2 - x1 ** 2) ** 2
# 定义梯度
def grad(x1, x2, a, b):
df1 = 2 * (x1 - a) + 4 * b * (x1 ** 2 - x2) * x1
df2 = 2 * b * (x2 - x1 ** 2)
return df1, df2
# 梯度下降法
def sgd(x1, x2, a, b, alpha, err, loops):
# 随机生成两个下标,从当前数据中取出初始值
idx = np.random.randint(0, len(x1), 1)
jdx = np.random.randint(0, len(x1[0]), 1)
x10, x20 = x1[idx, jdx], x2[idx, jdx]
# 计算初始的梯度
df1, df2 = grad(x10, x20, a, b)
# 开始迭代求最优值
num = 0
while num < loops:
if abs(df1) <= err and abs(df2) <= err:
print('已迭代到最优结果!\n', '迭代次数为:{}'.format(num))
break
x10 -= alpha * df1
x20 -= alpha * df2
df1, df2 = grad(x10, x20, a, b)
num += 1
if num == loops:
print('已经超出最大迭代次数!')
print('最终迭代完毕的结果为:{}'.format([x10, x20]))
if __name__ == '__main__':
# 生成变量
x_1 = np.linspace(-1.5, 1.5, 300) # 生成的是1维向量
x_2 = np.linspace(-1.5, 1.5, 300) # 同上
# 设定参数
a = 1
b = 100
alpha = 0.001 # 学习率
err = 0.0001 # 最小误差
loops = 100000 # 迭代次数
# 将两组一维向量进行扩展,行数是x2的数量,列数是x1的数量
X1, X2 = np.meshgrid(x_1, x_2)
# 此时X1的第ij个数与X2的第ij个数组成一对坐标
Fx = func(X1, X2, a, b) # 得到函数值
# 求最小值
start = time.time()
sgd(X1, X2, a, b, alpha, err, loops)
end = time.time()
print('优化时长为:{}s'.format(end - start))