1. 程式人生 > >PyTorch基礎入門七:PyTorch搭建迴圈神經網路(RNN)

PyTorch基礎入門七:PyTorch搭建迴圈神經網路(RNN)

1)任務介紹

今天,我們通過PyTorch搭建一個用於處理序列的RNN。

當我們以sin值作為輸入,其對應的cos作為輸出的時候,你會發現,即使輸入值sin相同,其輸出結果也可以是不同的,這樣的話,以前學過的FC, CNN就難以處理,因為你的輸出結果不僅僅依賴於輸出,而且還依賴於之前的程式結果。所以說,RNN在這裡就派上了用場。

2)程式碼實現

上程式碼之前,還是先了解一下RNN的引數吧:

torch.nn.RNN()

引數 含義
input_size 輸入 x 的特徵數量
hidden_size 隱狀態 h 中的特徵數量
num_layers RNN 的層數
nonlinearity 指定非線性函式使用 [‘tanh’|’relu’]. 預設: ‘tanh’
bias 如果是 False , 那麼 RNN 層就不會使用偏置權重 b_ih 和 b_hh, 預設: True
batch_first 如果 True, 那麼輸入 Tensor 的 shape 應該是 (batch, seq, feature),並且輸出也是一樣
dropout  如果值非零, 那麼除了最後一層外, 其它層的輸出都會套上一個 dropout 層
bidirectional 如果 True , 將會變成一個雙向 RNN, 預設為 False

首先,我們定義出RNN模型

import torch
from torch import nn


class Rnn(nn.Module):
    def __init__(self, INPUT_SIZE):
        super(Rnn, self).__init__()

        self.rnn = nn.RNN(
            input_size=INPUT_SIZE,
            hidden_size=32,
            num_layers=1,
            batch_first=True
        )

        self.out = nn.Linear(32, 1)

    def forward(self, x, h_state):
        r_out, h_state = self.rnn(x, h_state)

        outs = []
        for time in range(r_out.size(1)):
            outs.append(self.out(r_out[:, time, :]))
        return torch.stack(outs, dim=1), h_state

選擇模型進行訓練:

import numpy as np
import matplotlib.pyplot as plt
import torch
from torch import nn
import rnn

# 定義一些超引數
TIME_STEP = 10
INPUT_SIZE = 1
LR = 0.02

# # 創造一些資料
# steps = np.linspace(0, np.pi*2, 100, dtype=np.float)
# x_np = np.sin(steps)
# y_np = np.cos(steps)
# #
# # “看”資料
# plt.plot(steps, y_np, 'r-', label='target(cos)')
# plt.plot(steps, x_np, 'b-', label='input(sin)')
# plt.legend(loc='best')
# plt.show()

# 選擇模型
model = rnn.Rnn(INPUT_SIZE)
print(model)

# 定義優化器和損失函式
loss_func = nn.MSELoss()
optimizer = torch.optim.Adam(model.parameters(), lr=LR)

h_state = None # 第一次的時候,暫存為0

for step in range(300):
    start, end = step * np.pi, (step+1)*np.pi

    steps = np.linspace(start, end, TIME_STEP, dtype=np.float32)
    x_np = np.sin(steps)
    y_np = np.cos(steps)

    x = torch.from_numpy(x_np[np.newaxis, :, np.newaxis])
    y = torch.from_numpy(y_np[np.newaxis, :, np.newaxis])

    prediction, h_state = model(x, h_state)
    h_state = h_state.data

    loss = loss_func(prediction, y)
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()

然後,畫圖看看最後擬合的結果

plt.plot(steps, y_np.flatten(), 'r-')
plt.plot(steps, prediction.data.numpy().flatten(), 'b-')
plt.show()

其擬合效果如下圖:

可以看到,真實的結果和擬合的效果已經十分接近了。

3)結語

神經網路學到RNN的時候,才慢慢感覺到神經網路的真正強大之處。因為RNN引入了”時間“這個特徵,我們的訓練結果不再受限於輸入,而是取決於”隨著時間的輸入序列“。正是由於這樣的原因,它可以廣泛的應用到自然語言處理,語言識別,甚至是AI作曲中來。

RNN確實相比於其他的神經網路顯得更為複雜和抽象,但是學到這裡的時候是非常興奮的,今天的博文只是借鑑了別人的程式碼,簡單地展示了一些RNN在處理序列上的優勢,關於RNN的一些擴充套件,是可以深入研究的,這將是一件非常有趣的事情。