PyTorch:基於循環神經網絡利用sin預測cos

背景

之前在學習深度學習的時候,由於只是做一些圖像處理相關的東西,因此關注的重心都在CNN上;但是目前,RNN也逐漸在圖像處理上發揮了非常重要的作用,所以學習並瞭解一些RNN的基礎和原理也是非常重要。

本次,將利用sin函數值預測cos函數值,分別用RNNGRULSTM進行了測試。我也得到了一些結論,但是目前我對循環神經網絡理解還比較淺薄,所以可能也不一定對。

最後,本文的大部分代碼參考了以下鏈接的代碼;這個repo裏有很多非常有意思的代碼,非常感謝他的貢獻和分享。

https://github.com/MorvanZhou/PyTorch-Tutorial

代碼

代碼鏈接:https://github.com/Yannnnnnnnnnnn/learnPyTorch/blob/master/RNN_sin.ipynb

#讀取各個模塊
import torch
from torch import nn
from torch.autograd import Variable
import numpy as np
import matplotlib.pyplot as plt

 # 隨機數種子
torch.manual_seed(1)   

# 參數
TIME_STEP = 10      # 每個batch包含時間序列的長度,即包含數據的數量
INPUT_SIZE = 1       # 每個數據的特徵長度
LR = 0.02                  # 學習率 
HIDD_NUM  = 32      # 隱含特徵的數量

# 定義模型 RNN
class RNN(nn.Module):
    def __init__(self):
        super(RNN, self).__init__()

        self.rnn = nn.RNN(
            input_size=INPUT_SIZE,
            hidden_size=HIDD_NUM,     # rnn hidden unit
            num_layers=3,                      #  RNN層數
            batch_first=True,                   #  將batch數量放在最前. (batch, time_step, input_size)
        )

        self.fc3 = nn.Linear(HIDD_NUM, 1)

    def forward(self, x, h_state):
        # x (batch, time_step, input_size)
        # h_state (n_layers, batch, hidden_size)
        # r_out (batch, time_step, hidden_size)
        r_out, h_state = self.rnn(x, h_state)

        outs = []    # save all predictions
        for time_step in range(r_out.size(1)):    # calculate output for each time step
            out = self.fc3(r_out[:, time_step, :])
            outs.append(out)
        return torch.stack(outs, dim=1), h_state

# 定義模型
rnn = RNN()
# 定義優化器和損失函數
optimizer = torch.optim.Adam(rnn.parameters(), lr=LR) 
loss_func = nn.MSELoss()

# 定義隱藏狀態
h_state = None

# 畫圖
plt.figure(1, figsize=(12, 5))
plt.ion()           # continuously plot

# 訓練
for step in range(2400):
    # 生成訓練數據
    start, end = step * np.pi, (step+1)*np.pi   # time range
    steps = np.linspace(start, end, TIME_STEP, dtype=np.float32)
    x_np = np.sin(steps)    # float32 for converting torch FloatTensor
    y_np = np.cos(steps)

    # 數據轉換成Tensor
    x = Variable(torch.from_numpy(x_np[np.newaxis, :, np.newaxis]))    # shape (batch, time_step, input_size)
    y = Variable(torch.from_numpy(y_np[np.newaxis, :, np.newaxis]))

    # forward
    prediction, h_state = rnn(x, h_state)   # rnn output
    
    # 由於生成數據並沒有保存,所以並不用保存隱藏狀態
    h_state = Variable(h_state.data)
    
    # backward 
    loss = loss_func(prediction, y)         # cross entropy loss
    optimizer.zero_grad()                   # clear gradients for this training step
    loss.backward()                         # backpropagation, compute gradients
    optimizer.step()                        # apply gradients

    # 畫圖
    if step%100==0 or step%101==0:
        plt.plot(steps, y_np.flatten(), 'r-')
        plt.plot(steps, prediction.data.numpy().flatten(), 'b-')
        plt.draw(); plt.pause(0.05)



代碼擴展

上述代碼是利用的RNN,可以很容易的擴展成GRU和LSTM,其代碼分別入下:

  1. GRU
...
# 定義模型 RNN
class RNN(nn.Module):
    def __init__(self):
        super(RNN, self).__init__()

        self.rnn = nn.GRU(
            input_size=INPUT_SIZE,
            hidden_size=HIDD_NUM,     # rnn hidden unit
            num_layers=3,                      #  RNN層數
            batch_first=True,                   #  將batch數量放在最前. (batch, time_step, input_size)
        )
....
  1. LSTM
...
# 定義模型 RNN
class RNN(nn.Module):
    def __init__(self):
        super(RNN, self).__init__()

        self.rnn = nn.LSTM(
            input_size=INPUT_SIZE,
            hidden_size=HIDD_NUM,     # rnn hidden unit
            num_layers=3,                      #  RNN層數
            batch_first=True,                   #  將batch數量放在最前. (batch, time_step, input_size)
        )
....
    
    # 由於生成數據並沒有保存,所以並不用保存隱藏狀態
    h_state = (Variable(h_state[0].data),Variable(h_state[1].data))
    ...

這裏利用《Dive into DL Pytorch》的插圖,分別可視化一下RNN、GRU和LSTM,就可以很容易明白foward的返回值都是不一樣的,具體去看那本書吧。

RNN

RNN

GRU

在這裏插入圖片描述

LSTM

在這裏插入圖片描述


分析和結論

由於上述代碼可以直接跑通,所以我在此處只直接列出我遇到的一些現象,並做一下簡單的分析

  1. TIME_STEP=50,RNN網絡模型就不會收斂,而GRU和LSTM可以收斂;猜測原因可能是RNN僅能學習到比較短的信息,從而當TIME_STEP較大時,就不能學習到sin函數的精髓,而GRU和LSTM則引入了遺忘率和更新率保證了網絡能夠學習到更多的信息。
  2. 在GRU和LSTM模型下,可以通過提高HIDD_NUMnum_layber來保證模型的精度,這個相當於引入了更多的參數吧。
  3. 最後還有一個我也沒有想明白的事情,我本身想直接利用steps預測cos(steps),但是模型無論如何不收斂;現在我還不知道原因,等以後瞭解循環神經網絡了,再回來考慮這個問題。

總之,大家可以自行跑跑代碼,或者看看MorvanZhou的代碼和《Dive into DL Pytorch》,肯定會有所收穫。

發佈了151 篇原創文章 · 獲贊 160 · 訪問量 44萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章