一,2d函数优化器
2d函数优化器说白了就是一个特殊的含有两个变量的函数,这个函数有一个特点:
他的函数图像有四个局部极小值点,而且每个极小值点的值都为0,也就是说四个局部极小值点都是全局极小值点
这样,当你设计了一个梯度下降算法时,可以把它放到这个函数中跑一下,看看最终能不能掉到极小值点里面,掉进去的效率高不高,进而来评价这个算法的优越性。
二,二维函数优化的实战
该代码分为两个部分,第一个部分是利用matplotlib的子库 pyplot 绘制该二维优化函数的3d图像
1.利用pyplot绘制3d函数图像
①用python的形式把函数表达出来:
def himmelblau(x):#优化器函数用python的形式表现出来
return (x[0] ** 2 + x[1] - 11) ** 2 + (x[0] + x[1] ** 2 - 7) ** 2
②生成相应的x,y,z点
首先生成120个-6到6之间,间隔0.1的坐标值,然后利用np的meshgrid函数,但是这里的x和y只是数字,并不能代表他是坐标,因此不能被函数接受,因此还要用np的meshgrid函数来把这些数字生成相应的坐标X和Y,然后把这些坐标当作参数传递进写好的函数中,获得Z坐标
x = np.arange(-6,6,0.1)#从-6到6每个0.1生成一个数字,作为点的x坐标值
y = np.arange(-6,6,0.1)#同理作为y的坐标值
print('x,y range:',x.shape,y.shape)#由于有120个数字,所以x和y的shape都是[120]
X,Y = np.meshgrid(x,y)
#np.meshgrid(x,y)就是把x和y分别各个组成x*y个点(实际上不是x*y,是x有a个数字,y有b个数字,组成a*b个点)
#然后把这些点的x坐标和y坐标分别返回给X和Y
#比如x的shape是[120],y的shape是[120],他俩组成[120*120]个点,所以X和Y的维度就是[120,120]
print('X,Y maps:',X.shape,Y.shape)
Z = himmelblau([X,Y])
③把这些点传入plt的接口中,进行绘图
fig = plt.figure('himmelblau')#这个窗口的标题
ax = fig.add_subplot(111,projection = '3d')#两种使用方法,第一种是直接用fig,第二种就是这种ax = fig...,第一个参数一般都写111
#第二个参数代表是3d图
ax.plot_surface(X,Y,Z)#这是生成三维图像的函数,生成二维图像用ax.plot(X,Y),当然传的参数的shape与这里的X,Y就不相同了
#因为这里是为了绘制三维图像特意准备的点,shape为[120,120],不能直接用这里的XY绘制二维图像
ax.view_init(60,-30)#定义初始化的视角,也就是点进去第一眼在什么视角看,两个参数分别代表仰角和方位角
ax.set_xlabel('x')#x坐标的标题
ax.set_ylabel('y')#y坐标的标题
plt.show()#展示
可以说这套模板来画三维图像是通用的,如果想画其他函数的图像,只需要改himmelblau函数中的表达式即可
比如我想看z = x+y的图像,可以把himmelblau函数改成这样
def himmelblau(x):#优化器函数用python的形式表现出来
return x[0]+x[1]
2.梯度下降训练部分
x = torch.tensor([0.,0],requires_grad=True)#初值设置为0,0,设置成需要求梯度
optimzer = torch.optim.Adam([x],lr=1e-3)#自动进行梯度下降的迭代器,第一个参数传一个list,里面放权值,第二个参数传学习速率
for step in range(20000):#一共迭代两万步
pred = himmelblau(x)
#梯度下降三部曲
optimzer.zero_grad()#清零
pred.backward()#求导
optimzer.step()#下降
if step % 2000 == 0:#每隔两千步输出一下点所在的位置,看看最终有没有向全局最低点下降
print('step {}: x = {} , f(x) = {}'
.format(step,x.tolist(),pred.item()))
由此可见,初值的选择会影响训练的最终结果和运行效率,所以以后在训练模型的时候,一定要给所有的权值赋上初值
import numpy as np
from matplotlib import pyplot as plt#生成三维图像,是matplotlib的子库
import torch
def himmelblau(x):#优化器函数用python的形式表现出来
return (x[0] ** 2 + x[1] - 11) ** 2 + (x[0] + x[1] ** 2 - 7) ** 2
#return x[0]+x[1]
#下面是3D画图部分
'''
点的生成部分
'''
x = np.arange(-6,6,0.1)#从-6到6每个0.1生成一个数字,作为点的x坐标值
y = np.arange(-6,6,0.1)#同理作为y的坐标值
print('x,y range:',x.shape,y.shape)#由于有120个数字,所以x和y的shape都是[120]
X,Y = np.meshgrid(x,y)
#np.meshgrid(x,y)就是把x和y分别各个组成x*y个点(实际上不是x*y,是x有a个数字,y有b个数字,组成a*b个点)
#然后把这些点的x坐标和y坐标分别返回给X和Y
#比如x的shape是[120],y的shape是[120],他俩组成[120*120]个点,所以X和Y的维度就是[120,120]
print('X,Y maps:',X.shape,Y.shape)
Z = himmelblau([X,Y])
'''
图像绘制部分
'''
fig = plt.figure('himmelblau')#这个窗口的标题
ax = fig.add_subplot(111,projection = '3d')#两种使用方法,第一种是直接用fig,第二种就是这种ax = fig...,第一个参数一般都写111
#第二个参数代表是3d图
ax.plot_surface(X,Y,Z)#这是生成三维图像的函数,生成二维图像用ax.plot(X,Y),当然传的参数的shape与这里的X,Y就不相同了
#因为这里是为了绘制三维图像特意准备的点,shape为[120,120],不能直接用这里的XY绘制二维图像
ax.view_init(60,-30)#定义初始化的视角,也就是点进去第一眼在什么视角看,两个参数分别代表仰角和方位角
ax.set_xlabel('x')#x坐标的标题
ax.set_ylabel('y')#y坐标的标题
plt.show()
#下面是训练部分
x = torch.tensor([3.,-2],requires_grad=True)#初值设置为0,0,设置成需要求梯度
optimzer = torch.optim.Adam([x],lr=1e-3)#自动进行梯度下降的迭代器,第一个参数传一个list,里面放权值,第二个参数传学习速率
for step in range(20000):#一共迭代两万步
pred = himmelblau(x)
#梯度下降三部曲
optimzer.zero_grad()#清零
pred.backward()#求导
optimzer.step()#下降
if step % 2000 == 0:#每隔两千步输出一下点所在的位置,看看最终有没有向全局最低点下降
print('step {}: x = {} , f(x) = {}'
.format(step,x.tolist(),pred.item()))