使用Pytorch從零開始構建GRU

門控循環單元 (GRU) 是 LSTM 的更新版本。讓我們揭開這個網絡的面紗并探索這兩個兄弟姐妹之間的差異。

您聽說過 GRU 嗎?門控循環單元(GRU)是更流行的長短期記憶(LSTM)網絡的弟弟,也是循環神經網絡(RNN)的一種。就像它的兄弟一樣,GRU 能夠有效地保留順序數據中的長期依賴性。此外,它們還可以解決困擾普通 RNN 的“短期記憶”問題。

考慮到序列建模和預測中循環架構的遺留問題,GRU 有望因其卓越的速度而超越其前輩,同時實現相似的準確性和有效性。

在本文中,我們將介紹 GRU 背后的概念,并將 GRU 與 LSTM 的機制進行比較。我們還將探討這兩種 RNN 變體的性能差異。如果您不熟悉 RNN 或 LSTM,您可以查看我之前介紹這些主題的文章:

  • 使用Pytorch從零開始構建RNN
  • 使用Pytorch從零開始構建LSTM

什么是 GRU?

門控循環單元(GRU),顧名思義,是RNN 架構的一種變體,它使用門控機制來控制和管理神經網絡中單元之間的信息流。Cho 等人于 2014 年才引入 GRU 。可以被認為是一種相對較新的架構,特別是與Sepp Hochreiter 和 Jürgen Schmidhuber于 1997 年提出的廣泛采用的 LSTM 相比。
在這里插入圖片描述

GRU 的結構使其能夠自適應地捕獲大型數據序列的依賴性,而不會丟棄序列早期部分的信息。這是通過其門控單元實現的,類似于 LSTM 中的門控單元,它解決了傳統 RNN 的梯度消失/爆炸問題。這些門負責調節每個時間步要保留或丟棄的信息。我們將在本文后面深入探討這些門的工作原理以及它們如何克服上述問題的細節。
在這里插入圖片描述
除了其內部門控機制之外,GRU 的功能就像 RNN 一樣,其中順序輸入數據由 GRU 單元在每個時間步與內存一起消耗,或者稱為隱藏狀態。然后,隱藏狀態與序列中的下一個輸入數據一起重新輸入到 RNN 單元中。這個過程像繼電器系統一樣持續進行,產生所需的輸出。

GRU 的內部運作

GRU 保持長期依賴性或記憶的能力源于 GRU 單元內產生隱藏狀態的計算。雖然LSTM在單元之間傳遞兩種不同的狀態——單元狀態和隱藏狀態,分別承載長期和短期記憶,但 GRU 在時間步之間僅傳遞一種隱藏狀態。由于隱藏狀態和輸入數據所經歷的門控機制和計算,該隱藏狀態能夠同時保持長期和短期依賴性。
在這里插入圖片描述
GRU 單元僅包含兩個門:更新門和重置門。就像 LSTM 中的門一樣,GRU 中的這些門經過訓練可以有選擇地過濾掉任何不相關的信息,同時保留有用的信息。這些門本質上是包含0到1之間的值的向量,這些值將與輸入數據和/或隱藏狀態相乘。門向量中的0值表示輸入或隱藏狀態中的相應數據不重要,因此將返回零。另一方面,門向量中的值1意味著相應的數據很重要并將被使用。

在本文的其余部分中,我將交替使用術語“門”和“向量” ,因為它們指的是同一事物。

GRU單元的結構如下所示。
在這里插入圖片描述
雖然由于存在大量連接,該結構可能看起來相當復雜,但其背后的機制可以分為三個主要步驟。

重置門

第一步,我們將創建重置門。該門是使用前一時間步的隱藏狀態和當前時間步的輸入數據導出和計算的。

在這里插入圖片描述
從數學上講,這是通過將先前的隱藏狀態和當前輸入與其各自的權重相乘并在將總和傳遞給sigmoid函數之前將它們相加來實現的。sigmoid函數會將值轉換為介于0和1之間,從而允許門在后續步驟中在不太重要和更重要的信息之間進行過濾。
g a t e r e s e t = σ ( W i n p u t r e s e t ? x t + W h i d d e n r e s e t ? h t ? 1 ) gate_{reset} = \sigma(W_{input_{reset}} \cdot x_t + W_{hidden_{reset}} \cdot h_{t-1}) gatereset?=σ(Winputreset???xt?+Whiddenreset???ht?1?)
當整個網絡通過反向傳播進行訓練時,方程中的權重將被更新,使得向量將學會僅保留有用的特征。

先前的隱藏狀態將首先乘以可訓練權重,然后與重置向量進行逐元素乘法(哈達瑪乘積) 。 此操作將決定將先前時間步驟中的哪些信息與新輸入一起保留。同時,當前輸入還將乘以可訓練權重,然后與上面的重置向量和先前隱藏狀態的乘積相加。最后,將非線性激活tanh函數應用于最終結果,以獲得下面等式中的r 。
r = t a n h ( g a t e r e s e t ⊙ ( W h 1 ? h t ? 1 ) + W x 1 ? x t ) r = tanh(gate_{reset} \odot (W_{h_1} \cdot h_{t-1}) + W_{x_1} \cdot x_t) r=tanh(gatereset?(Wh1???ht?1?)+Wx1???xt?)

更新門

接下來,我們必須創建更新門。就像重置門一樣,門是使用先前的隱藏狀態和當前輸入數據來計算的。
在這里插入圖片描述
更新和重置門向量都是使用相同的公式創建的,但是,與輸入和隱藏狀態相乘的權重對于每個門來說是唯一的,這意味著每個門的最終向量是不同的。這使得大門能夠滿足其特定目的。
g a t e u p d a t e = σ ( W i n p u t u p d a t e ? x t + W h i d d e n u p d a t e ? h t ? 1 ) gate_{update} = \sigma(W_{input_{update}} \cdot x_t + W_{hidden_{update}} \cdot h_{t-1}) gateupdate?=σ(Winputupdate???xt?+Whiddenupdate???ht?1?)
然后,更新向量將與之前的隱藏狀態進行逐元素相乘,以獲得下面等式中的u ,該值將用于稍后計算我們的最終輸出。
u = g a t e u p d a t e ⊙ h t ? 1 u = gate_{update} \odot h_{t-1} u=gateupdate?ht?1?

稍后在獲得最終輸出時,更新向量還將用于另一個操作。這里更新門的目的是幫助模型確定存儲在先前隱藏狀態中的過去信息有多少需要保留以供將來使用。

組合輸出

在最后一步中,我們將重用更新門并獲取更新的隱藏狀態。
在這里插入圖片描述
這次,我們將采用同一更新向量(1 -更新 門)的逐元素逆版本,并與重置門的輸出r進行逐元素乘法。此操作的目的是讓更新門確定新信息的哪一部分應存儲在隱藏狀態中。

最后,上述操作的結果將與上一步更新門的輸出u相加。這將為我們提供新的和更新的隱藏狀態。
h t = r ⊙ ( 1 ? g a t e u p d a t e ) + u h_t = r \odot (1-gate_{update}) + u ht?=r(1?gateupdate?)+u

我們也可以通過將這個新的隱藏狀態傳遞給線性激活層來將其用作該時間步的輸出。

解決梯度消失/爆炸問題

我們已經看到了大門的運作。我們知道它們如何轉換我們的數據。現在讓我們回顧一下它們在管理網絡內存方面的整體作用,并討論它們如何解決梯度消失/爆炸問題。

正如我們在上面的機制中所看到的,重置門負責決定將先前隱藏狀態的哪些部分與當前輸入組合以提出新的隱藏狀態。

更新門負責確定要保留多少先前的隱藏狀態,以及將新提出的隱藏狀態(源自重置門)的哪一部分添加到最終隱藏狀態。當更新門首先與先前的隱藏狀態相乘時,網絡會選擇將先前隱藏狀態的哪些部分保留在內存中,同時丟棄其余部分。隨后,當它使用更新門的逆來從重置門過濾提議的新隱藏狀態時,它會修補信息的缺失部分。

這使得網絡能夠保留??長期的依賴關系。如果更新向量值接近 1,則更新門可以選擇保留隱藏狀態中的大部分先前記憶,而無需重新計算或更改整個隱藏狀態。

在訓練 RNN 時,反向傳播過程中會出現梯度消失/爆炸問題,特別是當 RNN 處理長序列或具有多層時。訓練期間計算的誤差梯度用于以正確的方向和正確的幅度更新網絡的權重。然而,這個梯度是用鏈式法則從網絡末端開始計算的。因此,在反向傳播過程中,梯度將連續進行矩陣乘法,并且對于長序列,梯度會呈指數收縮(消失)或爆炸(爆炸) 。梯度太小意味著模型無法有效更新其權重,而梯度太大會導致模型不穩定。

由于更新門的附加組件,LSTM 和 GRU 中的門有助于解決這個問題。傳統 RNN 總是在每個時間步替換隱藏狀態的全部內容,而 LSTM 和 GRU 保留大部分現有隱藏狀態,同時在其上添加新內容。這允許誤差梯度反向傳播,而不會由于加法運算而消失或爆炸太快。

雖然 LSTM 和 GRU 是解決上述問題最廣泛使用的方法,但梯度爆炸問題的另一種解決方案是梯度裁剪。Clipping 在梯度上設置了一個定義的閾值,這意味著即使在訓練過程中梯度增加超過預定義值,其值仍然會被限制在設定的閾值內。這樣,梯度的方向不受影響,僅梯度的大小發生變化。
在這里插入圖片描述

GRU 與 LSTM

我們已經掌握了 GRU 的機制。但它與它的老兄弟(也更流行)的 LSTM 相比如何呢?

兩者都是為了解決標準 RNN 面臨的梯度消失/爆炸問題而創建的,并且這兩種 RNN 變體都利用門控機制來控制網絡內長期和短期依賴關系的流動。

但它們有什么不同呢?

  1. 結構性差異
    雖然 GRU 和 LSTM 都包含門,但這兩種結構之間的主要區別在于門的數量及其具體作用。GRU 中的更新門的作用與LSTM 中的輸入門和遺忘門非常相似。然而,這兩者對添加到網絡的新內存內容的控制有所不同。
    在這里插入圖片描述
    在 LSTM 中,遺忘門決定保留先前單元狀態的哪一部分,而輸入門則決定要添加的新內存量。這兩個門是相互獨立的,這意味著通過輸入門 添加的新信息量完全獨立于通過遺忘門保留的信息量。
    對于GRU來說,更新門負責決定保留之前內存中的哪些信息,并 負責控制新內存的添加。這意味著 GRU 中先前內存的保留和向內存中添加新信息不是獨立的。
    如前所述,這些結構之間的另一個主要區別是 GRU 中缺少單元狀態。LSTM 將其長期依賴關系存儲在單元狀態中,并將短期記憶存儲在隱藏狀態中,而 GRU 將兩者存儲在單個隱藏狀態中。然而,就保留長期信息的有效性而言,兩種架構都已被證明可以有效地實現這一目標。

  2. 速度差異
    與 LSTM 相比,GRU 的訓練速度更快,因為訓練期間需要更新的權重和參數數量較少。這可以歸因于與 LSTM 的三個門相比,GRU 單元中的門數量較少(兩個門)。
    在本文后面的代碼演練中,我們將直接比較在完全相同的任務上訓練 LSTM 和 GRU 的速度。

  3. 性能評估
    模型的準確性,無論是通過誤差幅度還是正確分類的比例來衡量,通常是決定使用哪種類型的模型來完成任務時的主要??因素。GRU 和 LSTM 都是 RNNs 的變體,可以互換插入以獲得類似的結果。

項目:使用 GRU 和 LSTM 進行時間序列預測

我們已經了解了 GRU 背后的理論概念。現在是時候將所學知識付諸實踐了。

我們將在代碼中實現 GRU 模型。為了進一步進行 GRU-LSTM 比較,我們還將使用 LSTM 模型來完成相同的任務。我們將根據一些指標評估這兩個模型的性能。我們將使用的數據集是每小時能源消耗數據集,可以在Kaggle上找到。該數據集包含按小時記錄的美國不同地區的電力消耗數據,你可以訪問 GitHub 代碼庫。

該項目的目標是創建一個模型,可以根據歷史使用數據準確預測下一小時的能源使用情況。我們將使用 GRU 和 LSTM 模型來訓練一組歷史數據,并在未見過的測試集上評估這兩個模型。為此,我們將從特征選擇和數據預處理開始,然后定義、訓練并最終評估模型。

這將是我們項目的流程。
在這里插入圖片描述
我們將使用 PyTorch 庫以及數據分析中使用的其他常見 Python 庫來實現這兩種類型的模型。

import os
import timeimport numpy as np
import pandas as pd
import matplotlib.pyplot as pltimport torch
import torch.nn as nn
from torch.utils.data import TensorDataset, DataLoaderfrom tqdm import tqdm_notebook
from sklearn.preprocessing import MinMaxScaler# Define data root directory
data_dir = "./data/"
# Visualise how our data looks
pd.read_csv(data_dir + 'AEP_hourly.csv').head()

在這里插入圖片描述
我們總共有12 個 .csv文件,其中包含上述格式的每小時能源趨勢數據(未使用“est_hourly.paruqet”和“pjm_hourly_est.csv” )。在下一步中,我們將按以下順序讀取這些文件并預處理這些數據:

  • 獲取每個單獨時間步的時間數據并對它們進行概括
    • 一天中的某個小時,即 0 - 23
    • 一周中的某一天,即。1 - 7
    • 月份,即 1 - 12
    • 一年中的某一天,即 1 - 365
  • 將數據縮放到 0 到 1 之間的值
    • 當特征具有相對相似的規模和/或接近正態分布時,算法往往會表現更好或收斂得更快
    • 縮放保留了原始分布的形狀并且不會降低異常值的重要性
  • 將數據分組為序列,用作模型的輸入并存儲其相應的標簽
    • 序列長度或回顧周期是模型用于進行預測的歷史數據點的數量
    • 標簽將是輸入序列中最后一個數據點之后的下一個數據點
  • 將輸入和標簽拆分為訓練集和測試集
# The scaler objects will be stored in this dictionary so that our output test data from the model can be re-scaled during evaluation
label_scalers = {}train_x = []
test_x = {}
test_y = {}for file in tqdm_notebook(os.listdir(data_dir)): # Skipping the files we're not usingif file[-4:] != ".csv" or file == "pjm_hourly_est.csv":continue# Store csv file in a Pandas DataFramedf = pd.read_csv('{}/{}'.format(data_dir, file), parse_dates=[0])# Processing the time data into suitable input formatsdf['hour'] = df.apply(lambda x: x['Datetime'].hour,axis=1)df['dayofweek'] = df.apply(lambda x: x['Datetime'].dayofweek,axis=1)df['month'] = df.apply(lambda x: x['Datetime'].month,axis=1)df['dayofyear'] = df.apply(lambda x: x['Datetime'].dayofyear,axis=1)df = df.sort_values("Datetime").drop("Datetime",axis=1)# Scaling the input datasc = MinMaxScaler()label_sc = MinMaxScaler()data = sc.fit_transform(df.values)# Obtaining the Scale for the labels(usage data) so that output can be re-scaled to actual value during evaluationlabel_sc.fit(df.iloc[:,0].values.reshape(-1,1))label_scalers[file] = label_sc# Define lookback period and split inputs/labelslookback = 90inputs = np.zeros((len(data)-lookback,lookback,df.shape[1]))labels = np.zeros(len(data)-lookback)for i in range(lookback, len(data)):inputs[i-lookback] = data[i-lookback:i]labels[i-lookback] = data[i,0]inputs = inputs.reshape(-1,lookback,df.shape[1])labels = labels.reshape(-1,1)# Split data into train/test portions and combining all data from different files into a single arraytest_portion = int(0.1*len(inputs))if len(train_x) == 0:train_x = inputs[:-test_portion]train_y = labels[:-test_portion]else:train_x = np.concatenate((train_x,inputs[:-test_portion]))train_y = np.concatenate((train_y,labels[:-test_portion]))test_x[file] = (inputs[-test_portion:])test_y[file] = (labels[-test_portion:])

我們總共有 980,185 個訓練數據序列。

為了提高訓練速度,我們可以批量處理數據,這樣模型就不需要頻繁更新權重。Torch Dataset和DataLoader類對于將數據拆分為批次并對其進行混洗非常有用。

batch_size = 1024
train_data = TensorDataset(torch.from_numpy(train_x), torch.from_numpy(train_y))
train_loader = DataLoader(train_data, shuffle=True, batch_size=batch_size, drop_last=True)

我們還可以檢查是否有 GPU 來加快訓練時間。如果您使用帶有 GPU 的 FloydHub 來運行此代碼,訓練時間將顯著減少。

# torch.cuda.is_available() checks and returns a Boolean True if a GPU is available, else it'll return False
is_cuda = torch.cuda.is_available()# If we have a GPU available, we'll set our device to GPU. We'll use this device variable later in our code.
if is_cuda:device = torch.device("cuda")
else:device = torch.device("cpu")

接下來,我們將定義 GRU 和 LSTM 模型的結構。兩種模型具有相同的結構,唯一的區別是循環層(GRU/LSTM)和隱藏狀態的初始化。LSTM 的隱藏狀態是包含單元狀態和隱藏狀態 的元組,而 GRU 僅具有單個隱藏狀態。

class GRUNet(nn.Module):def __init__(self, input_dim, hidden_dim, output_dim, n_layers, drop_prob=0.2):super(GRUNet, self).__init__()self.hidden_dim = hidden_dimself.n_layers = n_layersself.gru = nn.GRU(input_dim, hidden_dim, n_layers, batch_first=True, dropout=drop_prob)self.fc = nn.Linear(hidden_dim, output_dim)self.relu = nn.ReLU()def forward(self, x, h):out, h = self.gru(x, h)out = self.fc(self.relu(out[:,-1]))return out, hdef init_hidden(self, batch_size):weight = next(self.parameters()).datahidden = weight.new(self.n_layers, batch_size, self.hidden_dim).zero_().to(device)return hiddenclass LSTMNet(nn.Module):def __init__(self, input_dim, hidden_dim, output_dim, n_layers, drop_prob=0.2):super(LSTMNet, self).__init__()self.hidden_dim = hidden_dimself.n_layers = n_layersself.lstm = nn.LSTM(input_dim, hidden_dim, n_layers, batch_first=True, dropout=drop_prob)self.fc = nn.Linear(hidden_dim, output_dim)self.relu = nn.ReLU()def forward(self, x, h):out, h = self.lstm(x, h)out = self.fc(self.relu(out[:,-1]))return out, hdef init_hidden(self, batch_size):weight = next(self.parameters()).datahidden = (weight.new(self.n_layers, batch_size, self.hidden_dim).zero_().to(device),weight.new(self.n_layers, batch_size, self.hidden_dim).zero_().to(device))return hidden

訓練過程在下面的函數中定義,以便我們可以為兩個模型重現它。兩個模型在隱藏狀態和層中將具有相同數量的維度,在相同數量的epoch和學習率上進行訓練,并在完全相同的數據集上進行訓練和測試。

為了比較兩個模型的性能,我們將跟蹤模型訓練所需的時間,并最終比較兩個模型在測試集上的最終準確性。對于我們的準確性測量,我們將使用對稱平均絕對百分比誤差(sMAPE)來評估模型。sMAPE是預測值和實際值之間的絕對差值除以預測值和實際值的平均值的總和,從而給出衡量誤差量的百分比。這是sMAPE的公式:
$$

$$

def train(train_loader, learn_rate, hidden_dim=256, EPOCHS=5, model_type="GRU"):# Setting common hyperparametersinput_dim = next(iter(train_loader))[0].shape[2]output_dim = 1n_layers = 2# Instantiating the modelsif model_type == "GRU":model = GRUNet(input_dim, hidden_dim, output_dim, n_layers)else:model = LSTMNet(input_dim, hidden_dim, output_dim, n_layers)model.to(device)# Defining loss function and optimizercriterion = nn.MSELoss()optimizer = torch.optim.Adam(model.parameters(), lr=learn_rate)model.train()print("Starting Training of {} model".format(model_type))epoch_times = []# Start training loopfor epoch in range(1,EPOCHS+1):start_time = time.clock()h = model.init_hidden(batch_size)avg_loss = 0.counter = 0for x, label in train_loader:counter += 1if model_type == "GRU":h = h.dataelse:h = tuple([e.data for e in h])model.zero_grad()out, h = model(x.to(device).float(), h)loss = criterion(out, label.to(device).float())loss.backward()optimizer.step()avg_loss += loss.item()if counter%200 == 0:print("Epoch {}......Step: {}/{}....... Average Loss for Epoch: {}".format(epoch, counter, len(train_loader), avg_loss/counter))current_time = time.clock()print("Epoch {}/{} Done, Total Loss: {}".format(epoch, EPOCHS, avg_loss/len(train_loader)))print("Total Time Elapsed: {} seconds".format(str(current_time-start_time)))epoch_times.append(current_time-start_time)print("Total Training Time: {} seconds".format(str(sum(epoch_times))))return modeldef evaluate(model, test_x, test_y, label_scalers):model.eval()outputs = []targets = []start_time = time.clock()for i in test_x.keys():inp = torch.from_numpy(np.array(test_x[i]))labs = torch.from_numpy(np.array(test_y[i]))h = model.init_hidden(inp.shape[0])out, h = model(inp.to(device).float(), h)outputs.append(label_scalers[i].inverse_transform(out.cpu().detach().numpy()).reshape(-1))targets.append(label_scalers[i].inverse_transform(labs.numpy()).reshape(-1))print("Evaluation Time: {}".format(str(time.clock()-start_time)))sMAPE = 0for i in range(len(outputs)):sMAPE += np.mean(abs(outputs[i]-targets[i])/(targets[i]+outputs[i])/2)/len(outputs)print("sMAPE: {}%".format(sMAPE*100))return outputs, targets, sMAPE
lr = 0.001
gru_model = train(train_loader, lr, model_type="GRU")
Lstm_model = train(train_loader, lr, model_type="LSTM")
[Out]: Starting Training of GRU modelEpoch 1......Step: 200/957....... Average Loss for Epoch: 0.0070570480596506965Epoch 1......Step: 400/957....... Average Loss for Epoch: 0.0039001358837413135Epoch 1......Step: 600/957....... Average Loss for Epoch: 0.0027501484048358784Epoch 1......Step: 800/957....... Average Loss for Epoch: 0.0021489552696584723Epoch 1/5 Done, Total Loss: 0.0018450273993545988Time Elapsed for Epoch: 78.02232400000003 seconds...Total Training Time: 390.52727700000037 secondsStarting Training of LSTM modelEpoch 1......Step: 200/957....... Average Loss for Epoch: 0.013630141295143403...Total Training Time: 462.73371699999984 seconds

從兩個模型的訓練時間可以看出,我們的弟弟妹妹在速度方面絕對擊敗了哥哥。GRU 模型在這個維度上是明顯的贏家;它比 LSTM 模型快 72 秒完成了 5 個訓練周期。

繼續測量兩個模型的準確性,我們現在將使用評估()函數和測試數據集。

gru_outputs, targets, gru_sMAPE = evaluate(gru_model, test_x, test_y, label_scalers)
[Out]: Evaluation Time: 1.982479000000012sMAPE: 0.28081167222194775%
lstm_outputs, targets, lstm_sMAPE = evaluate(lstm_model, test_x, test_y, label_scalers)
[Out]: Evaluation Time: 2.602886000000126sMAPE: 0.27014616762377464%

有趣,對吧?雖然 LSTM 模型的誤差可能較小,并且在性能準確度方面略微領先于 GRU 模型,但差異并不顯著,因此尚無定論。

比較這兩個模型的其他測試同樣沒有得出明顯的勝利者,無法確定哪個是更好的整體架構。

最后,讓我們對預測輸出與實際消耗數據的隨機集進行一些可視化。

plt.figure(figsize=(14,10))
plt.subplot(2,2,1)
plt.plot(gru_outputs[0][-100:], "-o", color="g", label="Predicted")
plt.plot(targets[0][-100:], color="b", label="Actual")
plt.ylabel('Energy Consumption (MW)')
plt.legend()plt.subplot(2,2,2)
plt.plot(gru_outputs[8][-50:], "-o", color="g", label="Predicted")
plt.plot(targets[8][-50:], color="b", label="Actual")
plt.ylabel('Energy Consumption (MW)')
plt.legend()plt.subplot(2,2,3)
plt.plot(gru_outputs[4][:50], "-o", color="g", label="Predicted")
plt.plot(targets[4][:50], color="b", label="Actual")
plt.ylabel('Energy Consumption (MW)')
plt.legend()plt.subplot(2,2,4)
plt.plot(lstm_outputs[6][:100], "-o", color="g", label="Predicted")
plt.plot(targets[6][:100], color="b", label="Actual")
plt.ylabel('Energy Consumption (MW)')
plt.legend()
plt.show()

在這里插入圖片描述
看起來這些模型在預測能源消耗趨勢方面基本上是成功的。雖然他們可能仍然會犯一些錯誤,例如延遲預測消耗下降,但預測非常接近測試集上的實際線。這是由于能源消耗數據的性質以及模型可以解釋的模式和周期性變化這一事實造成的。更困難的時間序列預測問題,例如股票價格預測或銷量預測,可能具有很大程度上隨機的數據或沒有可預測的模式,在這種情況下,準確性肯定會較低。

超越 GRU

正如我在LSTM 文章中提到的,多年來,RNN 及其變體在各種 NLP 任務中已被取代,不再是NLP 標準架構。預訓練的Transformer 模型(例如 Google 的 BERT、OpenAI 的 GPT和最近推出的 XLNet)已經產生了最先進的基準和結果,并將下游任務的遷移學習引入到 NLP。

至此,GRU 的所有事情就暫時結束了。這篇文章完成了我涵蓋 RNN 基礎知識的系列文章;未來,我們將探索更先進的概念,例如注意力機制、Transformers 和 NLP 中最先進的技術。

本博客譯自 Gabriel Loye的博文。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/165987.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/165987.shtml
英文地址,請注明出處:http://en.pswp.cn/news/165987.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

極智AI | LLM大模型部署框架之OpenLLM

歡迎關注我的公眾號 [極智視界],獲取我的更多經驗分享 大家好,我是極智視界,本文來介紹一下 LLM大模型部署框架之OpenLLM。 邀您加入我的知識星球「極智視界」,星球內有超多好玩的項目實戰源碼下載,鏈接:https://t.zsxq.com/0aiNxERDq 由于 LLM 大模型在模型結構、模型規…

圖像評價之計算PSNR、SSIM、MSE、LPIPS和NIQE評價指標

文章目錄 鏈接說明代碼峰值信噪比結構相似性均方誤差學習感知圖像塊相似性自然圖像質量評估器 鏈接 GitHub 倉庫 如果代碼對你的研究有所幫助,請為該倉庫點上小星星。 說明 PSNR、SSIM、MSE和LPIPS是有監督指標,計算時必須是兩對圖像參與;…

安索夫矩陣(ANSOFF)

👉安索夫矩陣是策略管理之父安索夫博士于1957年提出的營銷策略模型,該模型以“產品”和“市場”作為兩大基本面,提出了4種不同組合下的營銷策略,是營銷分析中應用最廣泛的工具之一。其主要邏輯是通過選擇4種不同的成長性策略來實現…

C++11的線程

線程的創建 用std::thread創建線程非常簡單&#xff0c;只需要提供線程函數或者線程對象即可&#xff0c;并可以同時指定線程函數的參數。下面是創建線程的示例&#xff1a; #include <thread> #include <iostream> using namespace std;void func() {cout <<…

C# 獲取圖像、字體等對象大小的數據結構SizeF

如果你想要獲取字符串 "你好嗎" 的字節數組長度或者字符數&#xff0c; 使用如下代碼&#xff1a; string s "你好嗎"; //字節數組長度 int byteCount System.Text.Encoding.UTF8.GetBytes(s).Length; //字符數 int charCount s.Length; 如果你想獲取…

大話設計模式C++實現

大話設計模式&#xff0c;講得非常好&#xff0c;但是作者是用C#寫的&#xff0c;為了方便C程序員&#xff0c;使用C寫了大話設計模式的代碼 詳情見Github&#xff1a;https://github.com/liubamboo/BigTalkDesignPattern

新蘋果手機如何導入舊手機數據?解決方案來了,記得收藏!

為了保持其競爭優勢&#xff0c;蘋果公司不斷推出新的產品和服務&#xff0c;因此蘋果手機的更新換代速度是比較快的。正巧最近剛出了iPhone15&#xff0c;相信很多小伙伴已經換上了期待已久的新手機。 更換新手機后&#xff0c;大家都會面臨一個問題&#xff1a;新蘋果手機如…

java 手機商城免費搭建+電商源碼+小程序+三級分銷+SAAS云平臺

【SAAS云平臺】打造全行業全渠道全場景的SaaS產品&#xff0c;為店鋪經營場景提供一體化解決方案&#xff1b;門店經營區域化、網店經營一體化&#xff0c;本地化、全方位、一站式服務&#xff0c;為多門店提供統一運營解決方案&#xff1b;提供豐富多樣的營銷玩法覆蓋所有經營…

Windows DOS 常用命令

文章目錄 1 概述1.1 官方文檔1.2 常用 2 分類2.1 目錄2.2 文件2.3 網絡2.4 系統 1 概述 1.1 官方文檔 Windows 命令官方文檔&#xff1a;https://learn.microsoft.com/zh-cn/windows-server/administration/windows-commands/windows-commands 1.2 常用 win r # 打開運…

如何預防數據泄露?六步策略幫您打造企業信息安全壁壘

大家好&#xff01;我是恒小馳&#xff0c;今天我想和大家聊聊一個非常重要的話題——如何預防數據泄露。在這個數字化的時代&#xff0c;數據已經成為了我們生活中不可或缺的一部分。然而&#xff0c;隨著數據的價值日益凸顯&#xff0c;數據泄露的風險也隨之增加。企業應該如…

MacBook使用指南

一、安裝及卸載Windows系統 1、卸載Windows系統 步驟① 點擊下側任務欄中的“啟動臺”&#xff0c;進入程序塢&#xff0c;點擊"其他",選擇“啟動轉換助理” 步驟② 點擊“繼續”&#xff0c;接著點擊“恢復”&#xff0c;即可卸載Windows系統 2、安裝Windows系統 …

Shell編程里if的參數從-a到-z詳解

Shell編程里if的參數從-a到-z詳解

智能醫療越發周到!新的機器人系統評估中風后的活動能力

原創 | 文 BFT機器人 中風是在醫療界上最難的解決的病例之一&#xff0c;全球每年有超過1500萬人中風&#xff0c;四分之三的中風患者的手臂和手部會出現損傷、虛弱和癱瘓。 許多中風患者日常生活是依靠他們強壯的手臂來完成的&#xff0c;從拿一些小東西到梳頭&#xff0c;即…

phpstudy和IDEA 配置php debug

1.安裝xdebug 擴展&#xff0c;phpinfo() 查看 2.配置php.ini zend_extensionD:/phpstudy_pro/Extensions/php/php7.4.3nts/ext/php_xdebug.dll xdebug.collect_params1 xdebug.collect_return1 xdebug.auto_traceOn xdebug.trace_output_dirD:/phpstudy_pro/Extensions/php_l…

c語言新龜兔賽跑

以下是一個使用C語言編寫的新的龜兔賽跑游戲&#xff1a; #include <stdio.h>#include <stdlib.h>#include <time.h>int main() { int distance, turtle_speed, rabbit_speed, turtle_time, rabbit_time, rabbit_lead; srand(time(NULL)); // 隨機數種…

Whatweb簡單使用

目錄 簡介 安裝 debian/ubtuntu redhat/centos 特性 使用 常用參數如下&#xff1a; whatweb -v whatweb --version whatweb -i 1.txt whatweb -v www.baidu.com 掃描等級 whatweb -a 4 www.baidu.com 掃描網段 whatweb --no-errors -t 255 192.168.71.0/24 導出…

http與https有什么區別,https攻擊要如何防護

我們在瀏覽網站時&#xff0c;在網址的前面經常會看到http// 或者https//的顯示。同樣是http&#xff0c;加了s與不加s是有什么區別&#xff0c;加了s又有哪些用處。 http&#xff0c;中文叫做超文本傳輸協議。它是一種用于分布式、協作式和超媒體信息系統的應用層協議。是基于…

在vscode中添加代碼提示

添加配置 run->add_configuration 添加頭文件路徑 在c_cpp_properties.json中添加頭文件路徑 效果

時間敏感網絡TSN的車載設計實踐: 802.1Qbv協議

▎概述 IEEE 802.1Qbv[1]是TSN系列協議中備受關注的技術之一&#xff0c;如圖1所示&#xff0c;它定義了一種時間感知整形器&#xff08;Time Aware Shaper&#xff0c;TAS&#xff09;&#xff0c;支持Qbv協議的交換機可以按照配置好的門控列表來打開/關閉交換機出口隊列&…