MENU

2D 函数梯度优化

January 3, 2020 • Read: 3366 • Deep Learning阅读设置

首先我们构建一个 2D 函数方程

$$ f(x,y)=(x^2+y-11)^2+(x+y^2-7)^2 $$

该方程为 Himmelblau 方程,是科学家们研究出来专门用于检测一个优化器效果的方程。该方程所绘制的图像如下
由图可见,四个蓝色圆圈即为该方程的极小值点,其平面上的图像如右图所示。该方程虽然有四个极小值点,但四个点对应的值均为 0

  • $f(3.0,2.0)=0.0$
  • $f(-2.805118,3.131312)=0.0$
  • $f(-3.779310,-3.283186)=0.0$
  • $f(3.584428,-1.848126)=0.0$
    我们可以通过测试优化器能否找到四个极小值点,来判断其优劣
  • import torch
  • import torch.nn.functional as F
  • import numpy as np
  • import matplotlib.pyplot as plt
  • from mpl_toolkits.mplot3d import Axes3D
  • def himmelblau(x, y):
  • return (x**2 + y - 11)**2 + (x + y**2 - 7)**2
  • x = np.arange(-6, 6, 0.1) # x轴的范围
  • y = np.arange(-6, 6, 0.1) # y轴的范围
  • X, Y = np.meshgrid(x, y)
  • 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()

输出图像为

关于 meshgrid() 函数,这篇博客解释的很好,如果不理解的可以看看

下面以梯度下降法为例子来试着找到 Himmelblau 方程的极小值。这里是以优化预测值 pred 为目标,而不是误差 Error

  • x = torch.tensor([0., 0.], requires_grad=True) # 设定初始值(0, 0)
  • optimizer = torch.optim.Adam([x], lr=1e-3)
  • # 优化器对x进行优化,设定学习率为0.001
  • for step in range(20000):
  • pred = himmelblau(x[0], x[1])
  • optimizer.zero_grad() # 梯度信息清零
  • pred.backward()
  • optimizer.step() # 进行一次优化器优化,根据梯度信息更新x[0]和x[1]
  • if step % 2000 == 0:
  • print("step{}: x={}, f(x) = {}".format(step, x.tolist(), pred.item()))

输出为

  • step0: x=[0.0009999999310821295, 0.0009999999310821295], f(x) = 170.0
  • step2000: x=[2.3331806659698486, 1.9540694952011108], f(x) = 13.730916023254395
  • 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 次后,找到极小值点。若改变初始值点,则可能会改变输出结果,比方说把初始值点由 (0,0) 改为 (4,0)

Archives Tip
QR Code for this page
Tipping QR Code