本节介绍一个2D函数优化的实际例子
首先我们构建一个2D函数方程
该方程为Himmelblau方程,是科学家们专门用来检测一个优化器效果的方程。该方程所绘制出的图像如下:
由图可见,四个蓝色圆圈即为该方程的极小值点,其平面图像如上右图所示。
该方程虽有四个极小值点,但四个点所对应的值均为0。
四个极值点依次为:
我们使用深度学习法来测试是否能找到这四个极值点,便可知优化器的性能强弱。
首先在python上实现函数
代码语言:javascript复制import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
import numpy as np
from mpl_toolkits.mplot3d import Axes3D
def himmelblau(x):
return (x[0]**2 x[1]-11)**2 (x[0] x[1]**2 - 7)**2
# 这里的x[0]表示方程式上的x,x[1]表示方程式上的y
x = np.arange(-6, 6, 0.1)
y = np.arange(-6, 6, 0.1)
# 限定出x和y的范围,这里做出了[120, 120, 2]的矩阵
X, Y = np.meshgrid(x, y)
# meshgrid将两矩阵上的点一次传入
Z = himmelblau([X, Y])
fig = plt.figure('himmelblau')
ax = fig.gca(projection='3d')
ax.plot_surface(X, Y, Z)
ax.view_init(60, -30)
ax.set_xlabel('x')
ax.set_ylabel('y')
plt.show()
输出图像为
下面以梯度下降的算法来进行运算
因为这里是以优化预测值为目标,而不是前文所用的Error值。
先设定初始化的x值
代码语言:javascript复制# 先设定初始化x值
x = torch.tensor([0., 0.], requires_grad=True)
optimizer = torch.optim.Adam([x], lr=1e-3)
# 优化器对x进行优化,设定学习率为0.001
for step in range(20000):
pred = himmelblau(x)
optimizer.zero_grad()
# 梯度信息清零
pred.backward()
optimizer.step()
# 进行一次优化器优化
if step % 2000 == 0:
print('step{}: x={}, f(x)={}'.format(step, x.tolist(), pred.item()))
输出为
代码语言:javascript复制step0: x=[0.0009999999310821295, 0.0009999999310821295], f(x)=170.0
step2000: x=[2.3331806659698486, 1.9540692567825317], f(x)=13.730920791625977
step4000: x=[2.9820079803466797, 2.0270984172821045], f(x)=0.014858869835734367
step6000: x=[2.999983549118042, 2.0000221729278564], f(x)=1.1074007488787174e-08
step8000: x=[2.9999938011169434, 2.0000083446502686], f(x)=1.5572823031106964e-09
step10000: x=[2.999997854232788, 2.000002861022949], f(x)=1.8189894035458565e-10
step12000: x=[2.9999992847442627, 2.0000009536743164], f(x)=1.6370904631912708e-11
step14000: x=[2.999999761581421, 2.000000238418579], f(x)=1.8189894035458565e-12
step16000: x=[3.0, 2.0], f(x)=0.0
step18000: x=[3.0, 2.0], f(x)=0.0
由结果可见,运行到16000次后,找到极小值点
这里若改变初始值点,则会改变输出结果
将x设定为[4, 0]时
代码语言:javascript复制# 先设定初始化x值
x = torch.tensor([4., 0.], requires_grad=True)
optimizer = torch.optim.Adam([x], lr=1e-3)
# 优化器对x进行优化,设定学习率为0.001
for step in range(20000):
pred = himmelblau(x)
optimizer.zero_grad()
# 梯度信息清零
pred.backward()
optimizer.step()
# 进行一次优化器优化
if step % 2000 == 0:
print('step{}: x={}, f(x)={}'.format(step, x.tolist(), pred.item()))
改变了初始值点后,此时的输出为
代码语言:javascript复制step0: x=[3.999000072479248, -0.0009999999310821295], f(x)=34.0
step2000: x=[3.5741987228393555, -1.7641836404800415], f(x)=0.09904662519693375
step4000: x=[3.5844225883483887, -1.8481197357177734], f(x)=2.1100277081131935e-09
step6000: x=[3.5844264030456543, -1.8481241464614868], f(x)=2.41016095969826e-10
step8000: x=[3.58442759513855, -1.848125696182251], f(x)=2.9103830456733704e-11
step10000: x=[3.584428310394287, -1.8481262922286987], f(x)=9.094947017729282e-13
step12000: x=[3.584428310394287, -1.8481265306472778], f(x)=0.0
step14000: x=[3.584428310394287, -1.8481265306472778], f(x)=0.0
step16000: x=[3.584428310394287, -1.8481265306472778], f(x)=0.0
step18000: x=[3.584428310394287, -1.8481265306472778], f(x)=0.0
在12000次迭代后,找到极小值点。