1. 程式人生 > 程式設計 >Pytorch對Himmelblau函式的優化詳解

Pytorch對Himmelblau函式的優化詳解

Himmelblau函式如下:

Pytorch對Himmelblau函式的優化詳解

有四個全域性最小解,且值都為0,這個函式常用來檢驗優化演算法的表現如何:

Pytorch對Himmelblau函式的優化詳解

視覺化函式影象:

import numpy as np
from matplotlib import pyplot as plt
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 = np.arange(-6,6,0.1)
y = np.arange(-6,0.1)
X,Y = np.meshgrid(x,y)
Z = himmelblau([X,Y])
fig = plt.figure("himmeblau")
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()

結果:

Pytorch對Himmelblau函式的優化詳解

使用隨機梯度下降優化:

import torch
 
 def himmelblau(x):
 return (x[0] ** 2 + x[1] - 11) ** 2 + (x[0] + x[1] ** 2 - 7) ** 2
 
# 初始設定為0,0.
x = torch.tensor([0.,0.],requires_grad=True)
# 優化目標是找到使himmelblau函式值最小的座標x[0],x[1],
# 也就是x,y
# 這裡是定義Adam優化器,指明優化目標是x,學習率是1e-3
optimizer = torch.optim.Adam([x],lr=1e-3)
 
for step in range(20000):
 # 每次計算出當前的函式值
 pred = himmelblau(x)
 # 當網路參量進行反饋時,梯度是被積累的而不是被替換掉,這裡即每次將梯度設定為0
 optimizer.zero_grad()
 # 生成當前所在點函式值相關的梯度資訊,這裡即優化目標的梯度資訊
 pred.backward()
 # 使用梯度資訊更新優化目標的值,即更新x[0]和x[1]
 optimizer.step()
 # 每2000次輸出一下當前情況
 if step % 2000 == 0:
 print("step={},x={},f(x)={}".format(step,x.tolist(),pred.item()))

輸出結果:

step=0,x=[0.0009999999310821295,0.0009999999310821295],f(x)=170.0
step=2000,x=[2.3331806659698486,1.9540692567825317],f(x)=13.730920791625977
step=4000,x=[2.9820079803466797,2.0270984172821045],f(x)=0.014858869835734367
step=6000,x=[2.999983549118042,2.0000221729278564],f(x)=1.1074007488787174e-08
step=8000,x=[2.9999938011169434,2.0000083446502686],f(x)=1.5572823031106964e-09
step=10000,x=[2.999997854232788,2.000002861022949],f(x)=1.8189894035458565e-10
step=12000,x=[2.9999992847442627,2.0000009536743164],f(x)=1.6370904631912708e-11
step=14000,x=[2.999999761581421,2.000000238418579],f(x)=1.8189894035458565e-12
step=16000,x=[3.0,2.0],f(x)=0.0
step=18000,f(x)=0.0

從上面結果看,找到了一組最優解[3.0,此時極小值為0.0。如果修改Tensor變數x的初始化值,可能會找到其它的極小值,也就是說初始化值對於找到最優解很關鍵。

補充拓展:pytorch 搭建自己的神經網路和各種優化器

還是直接看程式碼吧!

import torch
import torchvision
import torchvision.transforms as transform
import torch.utils.data as Data
import matplotlib.pyplot as plt
from torch.utils.data import Dataset,DataLoader
import pandas as pd
import numpy as np
from torch.autograd import Variable
 
# data set
train=pd.read_csv('Thirdtest.csv')
#cut 0 col as label
train_label=train.iloc[:,[0]] #只讀取一列
#train_label=train.iloc[:,0:3]
#cut 1~16 col as data
train_data=train.iloc[:,1:]
#change to np
train_label_np=train_label.values
train_data_np=train_data.values
 
#change to tensor
train_label_ts=torch.from_numpy(train_label_np)
train_data_ts=torch.from_numpy(train_data_np)
 
train_label_ts=train_label_ts.type(torch.LongTensor)
train_data_ts=train_data_ts.type(torch.FloatTensor)
 
 
 
print(train_label_ts.shape)
print(type(train_label_ts))
 
train_dataset=Data.TensorDataset(train_data_ts,train_label_ts)
train_loader=DataLoader(dataset=train_dataset,batch_size=64,shuffle=True)
 
#make a network
 
import torch.nn.functional as F   # 激勵函式都在這
 
class Net(torch.nn.Module):   # 繼承 torch 的 Module
  def __init__(self ):
    super(Net,self).__init__()   # 繼承 __init__ 功能
    self.hidden1 = torch.nn.Linear(16,30)# 隱藏層線性輸出
    self.out = torch.nn.Linear(30,3)    # 輸出層線性輸出
 
  def forward(self,x):
    # 正向傳播輸入值,神經網路分析出輸出值
    x = F.relu(self.hidden1(x))   # 激勵函式(隱藏層的線性值)
    x = self.out(x)         # 輸出值,但是這個不是預測值,預測值還需要再另外計算
    return x
 
 
# net=Net()
# optimizer = torch.optim.SGD(net.parameters(),lr=0.0001,momentum=0.001)
# loss_func = torch.nn.CrossEntropyLoss() # the target label is NOT an one-hotted
 
# loss_list=[]
# for epoch in range(500):
#   for step,(b_x,b_y) in enumerate (train_loader):
#     b_x,b_y=Variable(b_x),Variable(b_y)
#     b_y=b_y.squeeze(1)
#     output=net(b_x)
#     loss=loss_func(output,b_y)
#     optimizer.zero_grad()
#     loss.backward()
#     optimizer.step()
#     if epoch%1==0:
#       loss_list.append(float(loss))
#     print( "Epoch: ",epoch,"Step ",step,"loss: ",float(loss))
 
 
# 為每個優化器建立一個 net
net_SGD     = Net()
net_Momentum  = Net()
net_RMSprop   = Net()
net_Adam    = Net()
nets = [net_SGD,net_Momentum,net_RMSprop,net_Adam]
 
#定義優化器
LR=0.0001
opt_SGD     = torch.optim.SGD(net_SGD.parameters(),lr=LR,momentum=0.001)
opt_Momentum  = torch.optim.SGD(net_Momentum.parameters(),momentum=0.8)
opt_RMSprop   = torch.optim.RMSprop(net_RMSprop.parameters(),alpha=0.9)
opt_Adam    = torch.optim.Adam(net_Adam.parameters(),betas=(0.9,0.99))
optimizers = [opt_SGD,opt_Momentum,opt_RMSprop,opt_Adam]
 
loss_func = torch.nn.CrossEntropyLoss()
losses_his = [[],[],[]]
 
for net,opt,l_his in zip(nets,optimizers,losses_his):
  for epoch in range(500):
    for step,b_y) in enumerate(train_loader):
      b_x,b_y = Variable(b_x),Variable(b_y)
      b_y = b_y.squeeze(1)# 資料必須得是一維非one-hot向量
    # 對每個優化器,優化屬於他的神經網路
 
      output = net(b_x)       # get output for every net
      loss = loss_func(output,b_y) # compute loss for every net
      opt.zero_grad()        # clear gradients for next train
      loss.backward()        # backpropagation,compute gradients
      opt.step()           # apply gradients
      if epoch%1==0:
        l_his.append(loss.data.numpy())   # loss recoder
        print("optimizers: ","Epoch: ",float(loss))
 
labels = ['SGD','Momentum','RMSprop','Adam']
for i,l_his in enumerate(losses_his):
  plt.plot(l_his,label=labels[i])
plt.legend(loc='best')
plt.xlabel('Steps')
plt.ylabel('Loss')
plt.xlim((0,1000))
plt.ylim((0,4))
plt.show()
 

 
#
# for epoch in range(5):
#   for step,b_y)
#     loss.backward()
#     optimizer.zero_grad()
#     optimizer.step()
#     print(loss)

以上這篇Pytorch對Himmelblau函式的優化詳解就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。