pytorch擬合sin函式

啦啦無畏發表於2020-11-01

pytorch非線性迴歸調參分享

前期研究過程中獲得了一個非常奇怪的函式影像,打算用多層感知機(MLP)對函式影像進行建模模擬。前期相關研究中,MLP表現並不好,當時把這個方案已經放棄掉了。經過查閱相關的論文,發現原理上MLP能夠擬合任意函式。這段時間重新寫了一遍MLP網路,經過引數、增加訓練次數、GPU加速,現在能夠對函式較好擬合。現將程式碼分享一下。為方便展示,資料集改成了sin函式。

目標功能:對三個週期的sin(x)函式進行擬合
訓練效果:訓練效果展示

這個影像中,藍色為資料集,紅色為對其擬合的訓練結果。Loss表示兩個函式之間的均方根誤差。程式改編自

pyTorch非線性迴歸程式碼實現 作者ID胸毛飄蕩
在這裡插入圖片描述

import torch
import numpy as np
import matplotlib.pyplot as plt
import torch.nn as nn
from torch.autograd import Variable

x_tensor = torch.linspace(0, 6*np.pi, 10000)        #建立一個輸入資料集,[0-6*pi]
x_data = torch.unsqueeze(x_tensor, dim=1)           #增加維度,將x的形狀從[10000]變成二維[10000,1]
y_data = torch.sin(x_data)                          #待擬合的標籤值,此處可以新增部分噪聲
# plt.figure("檢視資料集是否正確")
# plt.scatter(x_data, y_data)
# plt.ion()
# plt.show()
# 定義超引數
D_in = 1                                            #輸入維度1
D_out = 1                                           #輸出維度1
H1 = 100                                            #中間隱藏層  100個神經元
train_step = 100000                                 #訓練次數10e5次
#定義新啟用函式swish(x) = x * sigmod(x),作為一個類
class Act_op(nn.Module):
    def __init__(self):
        super(Act_op, self).__init__()
    def forward(self, x):
        x = x * torch.sigmoid(x)
        return x
swish = Act_op()                                    #類的例項化
'''
對於下面的神經網路定義層的類,初始化輸入引數為D_in,H1,H2,D_out
H1代表第一個隱藏層的神經元個數
H2代表第二個隱藏層的神經元個數
目前程式中使用的神經網路只有H1一個隱藏層,除錯過程中曾經嘗試過增加隱藏層的個數
clamp(min=0)是relu啟用函式比較簡潔的表達方式
swish(x)方法表示 x*sigmod(x)這個啟用函式
'''
class TwolayerNet(torch.nn.Module):
    def __init__(self, D_in, H1, D_out):
        super(TwolayerNet, self).__init__()
        self.linear1 = torch.nn.Linear(D_in, H1)
        self.linear2 = torch.nn.Linear(H1, D_out)
    def forward(self, X):
        y_pred = self.linear2(swish(self.linear1(X)))
        return y_pred
net = TwolayerNet(D_in, H1, D_out)              #類的例項化
optimizer = torch.optim.Adam(net.parameters(), lr=0.0005)
loss_func = torch.nn.MSELoss()                      #優化器為adam,損失loss函式為MESloss
plt.figure("regression")                            #新建一張畫布,列印資料點和預測值
plt.ion()                                           #互動模式
if torch.cuda.is_available():                       #將模型搬移到GPU執行
    print("GPU1")
    net = net.cuda()
else:
    print("CPU")

for step in range(train_step):
    if torch.cuda.is_available():                   #將資料點搬移到GUP執行
        inputs = Variable(x_data).cuda()
        target = Variable(y_data).cuda()
    else:
        inputs = Variable(x_data)
        target = Variable(y_data)
    # 呼叫搭建好的神經網路模型,得到預測值
    prediction = net(inputs)
    # 用定義好的損失函式,得出預測值和真實值的loss
    loss = loss_func(prediction, target)
    # 每次都需要把梯度將為0
    optimizer.zero_grad()
    # 誤差反向傳遞
    loss.backward()
    # 呼叫優化器進行優化,將引數更新值施加到 net 的 parameters 上
    optimizer.step()
    if step % 100 == 0:
        # 清除當前座標軸
        plt.cla()
        plt.scatter(x_data.data.numpy(), y_data.data.numpy())
        # r- 是紅色 lw 是線寬
        plt.plot(x_data.data.numpy(), prediction.data.cpu().numpy(), 'r-', lw=5)
        '''
        給圖形新增標籤,0.5, 0 表示X軸和Y軸座標,
        'Loss=%.4f'%loss.data.numpy()表示標註的內容,
        .4f表示保留小數點後四位
        fontdict是設定字型大小和顏色
        '''
        plt.text(0.5, 0, 'Loss=%.4f'%loss.data.cpu().numpy(), fontdict={'size':20, 'color': 'red'})
        # 間隔多久再次進行繪圖
        plt.pause(0.1)
    if step % 1000 == 0:
        print(str(step/1000)+'   Loss=%.4f'%loss.data.cpu().numpy())

在這裡插入圖片描述
網路結構如上所示:輸入一個引數,輸出一個引數,中間有一個隱藏層,隱藏層有神經元100個。在測試程式過程中曾將嘗試將隱藏層的層數增加,但是較容易出現提前收斂的情況。

啟用函式並沒有使用常用的sigmod函式、tanh函式和relu函式,參考論文與網上經驗使用了新提出的swish函式。這個函式與relu函式類似,有下界但是無上界。比relu函式優越性在於它處處連續。函式影像如下所示在這裡插入圖片描述
在計算中使用了CUDA加速。訓練時間會快一點。假設裝置上沒有CUDA裝置,那也可以直接用CPU進行運算。

相關文章