零基礎入門深度學習(5) - 循環神經網絡

往期回顧

在前面的文章系列文章中,我們介紹了全連接神經網絡和卷積神經網絡,以及它們的訓練和使用。他們都只能單獨的取處理一個個的輸入,前一個輸入和后一個輸入是完全沒有關系的。但是,某些任務需要能夠更好的處理序列的信息,即前面的輸入和后面的輸入是有關系的。比如,當我們在理解一句話意思時,孤立的理解這句話的每個詞是不夠的,我們需要處理這些詞連接起來的整個序列;當我們處理視頻的時候,我們也不能只單獨的去分析每一幀,而要分析這些幀連接起來的整個序列。這時,就需要用到深度學習領域中另一類非常重要神經網絡:循環神經網絡(Recurrent Neural Network)。RNN種類很多,也比較繞腦子。不過讀者不用擔心,本文將一如既往的對復雜的東西剝繭抽絲,幫助您理解RNNs以及它的訓練算法,并動手實現一個循環神經網絡。

語言模型

RNN是在自然語言處理領域中最先被用起來的,比如,RNN可以為語言模型來建模。那么,什么是語言模型呢?

我們可以和電腦玩一個游戲,我們寫出一個句子前面的一些詞,然后,讓電腦幫我們寫下接下來的一個詞。比如下面這句:

我昨天上學遲到了,老師批評了____。

我們給電腦展示了這句話前面這些詞,然后,讓電腦寫下接下來的一個詞。在這個例子中,接下來的這個詞最有可能是『我』,而不太可能是『小明』,甚至是『吃飯』。

語言模型就是這樣的東西:給定一個一句話前面的部分,預測接下來最有可能的一個詞是什么。

語言模型是對一種語言的特征進行建模,它有很多很多用處。比如在語音轉文本(STT)的應用中,聲學模型輸出的結果,往往是若干個可能的候選詞,這時候就需要語言模型來從這些候選詞中選擇一個最可能的。當然,它同樣也可以用在圖像到文本的識別中(OCR)。

使用RNN之前,語言模型主要是采用N-Gram。N可以是一個自然數,比如2或者3。它的含義是,假設一個詞出現的概率只與前面N個詞相關。我們以2-Gram為例。首先,對前面的一句話進行切詞:

我 昨天 上學 遲到 了 ,老師 批評 了 ____。

如果用2-Gram進行建模,那么電腦在預測的時候,只會看到前面的『了』,然后,電腦會在語料庫中,搜索『了』后面最可能的一個詞。不管最后電腦選的是不是『我』,我們都知道這個模型是不靠譜的,因為『了』前面說了那么一大堆實際上是沒有用到的。如果是3-Gram模型呢,會搜索『批評了』后面最可能的詞,感覺上比2-Gram靠譜了不少,但還是遠遠不夠的。因為這句話最關鍵的信息『我』,遠在9個詞之前!

現在讀者可能會想,可以提升繼續提升N的值呀,比如4-Gram、5-Gram.......。實際上,這個想法是沒有實用性的。因為我們想處理任意長度的句子,N設為多少都不合適;另外,模型的大小和N的關系是指數級的,4-Gram模型就會占用海量的存儲空間。

所以,該輪到RNN出場了,RNN理論上可以往前看(往后看)任意多個詞。

循環神經網絡是啥

循環神經網絡種類繁多,我們先從最簡單的基本循環神經網絡開始吧。

基本循環神經網絡

下圖是一個簡單的循環神經網絡如,它由輸入層、一個隱藏層和一個輸出層組成:

納尼?!相信第一次看到這個玩意的讀者內心和我一樣是崩潰的。因為循環神經網絡實在是太難畫出來了,網上所有大神們都不得不用了這種抽象藝術手法。不過,靜下心來仔細看看的話,其實也是很好理解的。如果把上面有W的那個帶箭頭的圈去掉,它就變成了最普通的全連接神經網絡。x是一個向量,它表示輸入層的值(這里面沒有畫出來表示神經元節點的圓圈);s是一個向量,它表示隱藏層的值(這里隱藏層面畫了一個節點,你也可以想象這一層其實是多個節點,節點數與向量s的維度相同);U是輸入層到隱藏層的權重矩陣(讀者可以回到第三篇文章零基礎入門深度學習(3) - 神經網絡和反向傳播算法,看看我們是怎樣用矩陣來表示全連接神經網絡的計算的);o也是一個向量,它表示輸出層的值;V是隱藏層到輸出層的權重矩陣。那么,現在我們來看看W是什么。循環神經網絡的隱藏層的值s不僅僅取決于當前這次的輸入x,還取決于上一次隱藏層的值s。權重矩陣?W就是隱藏層上一次的值作為這一次的輸入的權重。

如果我們把上面的圖展開,循環神經網絡也可以畫成下面這個樣子:

現在看上去就比較清楚了,這個網絡在t時刻接收到輸入之后,隱藏層的值是,輸出值是。關鍵一點是,的值不僅僅取決于,還取決于。我們可以用下面的公式來表示循環神經網絡的計算方法:

?

式式

?

式1是輸出層的計算公式,輸出層是一個全連接層,也就是它的每個節點都和隱藏層的每個節點相連。V是輸出層的權重矩陣,g是激活函數。式2是隱藏層的計算公式,它是循環層。U是輸入x的權重矩陣,W是上一次的值作為這一次的輸入的權重矩陣,f是激活函數。

從上面的公式我們可以看出,循環層和全連接層的區別就是循環層多了一個權重矩陣?W。

如果反復把式2帶入到式1,我們將得到:

?

?

從上面可以看出,循環神經網絡的輸出值,是受前面歷次輸入值、...影響的,這就是為什么循環神經網絡可以往前看任意多個輸入值的原因。

雙向循環神經網絡

對于語言模型來說,很多時候光看前面的詞是不夠的,比如下面這句話:

我的手機壞了,我打算____一部新手機。

可以想象,如果我們只看橫線前面的詞,手機壞了,那么我是打算修一修?換一部新的?還是大哭一場?這些都是無法確定的。但如果我們也看到了橫線后面的詞是『一部新手機』,那么,橫線上的詞填『買』的概率就大得多了。

在上一小節中的基本循環神經網絡是無法對此進行建模的,因此,我們需要雙向循環神經網絡,如下圖所示:

當遇到這種從未來穿越回來的場景時,難免處于懵逼的狀態。不過我們還是可以用屢試不爽的老辦法:先分析一個特殊場景,然后再總結一般規律。我們先考慮上圖中,的計算。

從上圖可以看出,雙向卷積神經網絡的隱藏層要保存兩個值,一個A參與正向計算,另一個值A'參與反向計算。最終的輸出值取決于。其計算方法為:

?

?

則分別計算:

?

?

現在,我們已經可以看出一般的規律:正向計算時,隱藏層的值有關;反向計算時,隱藏層的值有關;最終的輸出取決于正向和反向計算的加和。現在,我們仿照式1和式2,寫出雙向循環神經網絡的計算方法:

?

?

從上面三個公式我們可以看到,正向計算和反向計算不共享權重,也就是說U和U'、W和W'、V和V'都是不同的權重矩陣。

深度循環神經網絡

前面我們介紹的循環神經網絡只有一個隱藏層,我們當然也可以堆疊兩個以上的隱藏層,這樣就得到了深度循環神經網絡。如下圖所示:

我們把第i個隱藏層的值表示為,則深度循環神經網絡的計算方式可以表示為:

?

?

循環神經網絡的訓練

循環神經網絡的訓練算法:BPTT

BPTT算法是針對循環層的訓練算法,它的基本原理和BP算法是一樣的,也包含同樣的三個步驟:

  1. 前向計算每個神經元的輸出值;
  2. 反向計算每個神經元的誤差項值,它是誤差函數E對神經元j的加權輸入的偏導數;
  3. 計算每個權重的梯度。

最后再用隨機梯度下降算法更新權重。

循環層如下圖所示:

前向計算

使用前面的式2對循環層進行前向計算:

?

?

注意,上面的都是向量,用黑體字母表示;而U、V是矩陣,用大寫字母表示。向量的下標表示時刻,例如,表示在t時刻向量s的值。

我們假設輸入向量x的維度是m,輸出向量s的維度是n,則矩陣U的維度是,矩陣W的維度是。下面是上式展開成矩陣的樣子,看起來更直觀一些:

?

?

在這里我們用手寫體字母表示向量的一個元素,它的下標表示它是這個向量的第幾個元素,它的上標表示第幾個時刻。例如,表示向量s的第j個元素在t時刻的值。表示輸入層第i個神經元到循環層第j個神經元的權重。表示循環層第t-1時刻的第i個神經元到循環層第t個時刻的第j個神經元的權重。

誤差項的計算

BTPP算法將第l層t時刻的誤差項值沿兩個方向傳播,一個方向是其傳遞到上一層網絡,得到,這部分只和權重矩陣U有關;另一個是方向是將其沿時間線傳遞到初始時刻,得到,這部分只和權重矩陣W有關。

我們用向量表示神經元在t時刻的加權輸入,因為:

?

?

因此:

?

?

我們用a表示列向量,用表示行向量。上式的第一項是向量函數對向量求導,其結果為Jacobian矩陣:

?

?

同理,上式第二項也是一個Jacobian矩陣:

?

?

其中,diag[a]表示根據向量a創建一個對角矩陣,即

?

?

最后,將兩項合在一起,可得:

?

?

上式描述了將沿時間往前傳遞一個時刻的規律,有了這個規律,我們就可以求得任意時刻k的誤差項

?

?

式3就是將誤差項沿時間反向傳播的算法。

循環層將誤差項反向傳遞到上一層網絡,與普通的全連接層是完全一樣的,這在前面的文章零基礎入門深度學習(3) - 神經網絡和反向傳播算法中已經詳細講過了,在此僅簡要描述一下。

循環層的加權輸入與上一層的加權輸入關系如下:

?

?

上式中是第l層神經元的加權輸入(假設第l層是循環層);是第l-1層神經元的加權輸入;是第l-1層神經元的輸出;是第l-1層的激活函數。

?

?

所以,

?

?

式4就是將誤差項傳遞到上一層算法。

權重梯度的計算

現在,我們終于來到了BPTT算法的最后一步:計算每個權重的梯度。

首先,我們計算誤差函數E對權重矩陣W的梯度

上圖展示了我們到目前為止,在前兩步中已經計算得到的量,包括每個時刻t?循環層的輸出值,以及誤差項

回憶一下我們在文章零基礎入門深度學習(3) - 神經網絡和反向傳播算法介紹的全連接網絡的權重梯度計算算法:只要知道了任意一個時刻的誤差項,以及上一個時刻循環層的輸出值,就可以按照下面的公式求出權重矩陣在t時刻的梯度

?

?

在式5中,表示t時刻誤差項向量的第i個分量;表示t-1時刻循環層第i個神經元的輸出值。

我們下面可以簡單推導一下式5。

我們知道:

?

?

因為對W求導與無關,我們不再考慮。現在,我們考慮對權重項求導。通過觀察上式我們可以看到只與有關,所以:

?

?

按照上面的規律就可以生成式5里面的矩陣。

我們已經求得了權重矩陣W在t時刻的梯度,最終的梯度是各個時刻的梯度之和:

?

?

式6就是計算循環層權重矩陣W的梯度的公式。

----------數學公式超高能預警----------

前面已經介紹了的計算方法,看上去還是比較直觀的。然而,讀者也許會困惑,為什么最終的梯度是各個時刻的梯度之和呢?我們前面只是直接用了這個結論,實際上這里面是有道理的,只是這個數學推導比較繞腦子。感興趣的同學可以仔細閱讀接下來這一段,它用到了矩陣對矩陣求導、張量與向量相乘運算的一些法則。

我們還是從這個式子開始:

?

?

因為與W完全無關,我們把它看做常量。現在,考慮第一個式子加號右邊的部分,因為W和都是W的函數,因此我們要用到大學里面都學過的導數乘法運算:

?

?

因此,上面第一個式子寫成:

?

?

我們最終需要計算的是

?

?

我們先計算式7加號左邊的部分。是矩陣對矩陣求導,其結果是一個四維張量(tensor),如下所示:

?

?

接下來,我們知道,它是一個列向量。我們讓上面的四維張量與這個向量相乘,得到了一個三維張量,再左乘行向量,最終得到一個矩陣:

?

?

接下來,我們計算式7加號右邊的部分:

?

?

于是,我們得到了如下遞推公式:

?

?

這樣,我們就證明了:最終的梯度是各個時刻的梯度之和。

----------數學公式超高能預警解除----------

同權重矩陣W類似,我們可以得到權重矩陣U的計算方法。

?

?

式8是誤差函數在t時刻對權重矩陣U的梯度。和權重矩陣W一樣,最終的梯度也是各個時刻的梯度之和:

?

?

具體的證明這里就不再贅述了,感興趣的讀者可以練習推導一下。

RNN的梯度爆炸和消失問題

不幸的是,實踐中前面介紹的幾種RNNs并不能很好的處理較長的序列。一個主要的原因是,RNN在訓練中很容易發生梯度爆炸和梯度消失,這導致訓練時梯度不能在較長序列中一直傳遞下去,從而使RNN無法捕捉到長距離的影響。

為什么RNN會產生梯度爆炸和消失問題呢?我們接下來將詳細分析一下原因。我們根據式3可得:

?

?

上式的定義為矩陣的模的上界。因為上式是一個指數函數,如果t-k很大的話(也就是向前看很遠的時候),會導致對應的誤差項的值增長或縮小的非常快,這樣就會導致相應的梯度爆炸和梯度消失問題(取決于大于1還是小于1)。

通常來說,梯度爆炸更容易處理一些。因為梯度爆炸的時候,我們的程序會收到NaN錯誤。我們也可以設置一個梯度閾值,當梯度超過這個閾值的時候可以直接截取。

梯度消失更難檢測,而且也更難處理一些。總的來說,我們有三種方法應對梯度消失問題:

  1. 合理的初始化權重值。初始化權重,使每個神經元盡可能不要取極大或極小值,以躲開梯度消失的區域。
  2. 使用relu代替sigmoid和tanh作為激活函數。原理請參考上一篇文章零基礎入門深度學習(4) - 卷積神經網絡的激活函數一節。
  3. 使用其他結構的RNNs,比如長短時記憶網絡(LTSM)和Gated Recurrent Unit(GRU),這是最流行的做法。我們將在以后的文章中介紹這兩種網絡。

RNN的應用舉例——基于RNN的語言模型

現在,我們介紹一下基于RNN語言模型。我們首先把詞依次輸入到循環神經網絡中,每輸入一個詞,循環神經網絡就輸出截止到目前為止,下一個最可能的詞。例如,當我們依次輸入:

我 昨天 上學 遲到 了

神經網絡的輸出如下圖所示:

其中,s和e是兩個特殊的詞,分別表示一個序列的開始和結束。

向量化

我們知道,神經網絡的輸入和輸出都是向量,為了讓語言模型能夠被神經網絡處理,我們必須把詞表達為向量的形式,這樣神經網絡才能處理它。

神經網絡的輸入是詞,我們可以用下面的步驟對輸入進行向量化:

  1. 建立一個包含所有詞的詞典,每個詞在詞典里面有一個唯一的編號。
  2. 任意一個詞都可以用一個N維的one-hot向量來表示。其中,N是詞典中包含的詞的個數。假設一個詞在詞典中的編號是i,v是表示這個詞的向量,是向量的第j個元素,則:

?

?

上面這個公式的含義,可以用下面的圖來直觀的表示:

使用這種向量化方法,我們就得到了一個高維、稀疏的向量(稀疏是指絕大部分元素的值都是0)。處理這樣的向量會導致我們的神經網絡有很多的參數,帶來龐大的計算量。因此,往往會需要使用一些降維方法,將高維的稀疏向量轉變為低維的稠密向量。不過這個話題我們就不再這篇文章中討論了。

語言模型要求的輸出是下一個最可能的詞,我們可以讓循環神經網絡計算計算詞典中每個詞是下一個詞的概率,這樣,概率最大的詞就是下一個最可能的詞。因此,神經網絡的輸出向量也是一個N維向量,向量中的每個元素對應著詞典中相應的詞是下一個詞的概率。如下圖所示:

Softmax層

前面提到,語言模型是對下一個詞出現的概率進行建模。那么,怎樣讓神經網絡輸出概率呢?方法就是用softmax層作為神經網絡的輸出層。

我們先來看一下softmax函數的定義:

?

?

這個公式看起來可能很暈,我們舉一個例子。Softmax層如下圖所示:

從上圖我們可以看到,softmax layer的輸入是一個向量,輸出也是一個向量,兩個向量的維度是一樣的(在這個例子里面是4)。輸入向量x=[1 2 3 4]經過softmax層之后,經過上面的softmax函數計算,轉變為輸出向量y=[0.03 0.09 0.24 0.64]。計算過程為:

?

?

我們來看看輸出向量y的特征:

  1. 每一項為取值為0-1之間的正數;
  2. 所有項的總和是1。

我們不難發現,這些特征和概率的特征是一樣的,因此我們可以把它們看做是概率。對于語言模型來說,我們可以認為模型預測下一個詞是詞典中第一個詞的概率是0.03,是詞典中第二個詞的概率是0.09,以此類推。

語言模型的訓練

可以使用監督學習的方法對語言模型進行訓練,首先,需要準備訓練數據集。接下來,我們介紹怎樣把語料

我 昨天 上學 遲到 了

轉換成語言模型的訓練數據集。

首先,我們獲取輸入-標簽對:

輸入標簽
s
昨天
昨天上學
上學遲到
遲到
e

然后,使用前面介紹過的向量化方法,對輸入x和標簽y進行向量化。這里面有意思的是,對標簽y進行向量化,其結果也是一個one-hot向量。例如,我們對標簽『我』進行向量化,得到的向量中,只有第2019個元素的值是1,其他位置的元素的值都是0。它的含義就是下一個詞是『我』的概率是1,是其它詞的概率都是0。

最后,我們使用交叉熵誤差函數作為優化目標,對模型進行優化。

在實際工程中,我們可以使用大量的語料來對模型進行訓練,獲取訓練數據和訓練的方法都是相同的。

交叉熵誤差

一般來說,當神經網絡的輸出層是softmax層時,對應的誤差函數E通常選擇交叉熵誤差函數,其定義如下:

?

?

在上式中,N是訓練樣本的個數,向量是樣本的標記,向量是網絡的輸出。標記是一個one-hot向量,例如,如果網絡的輸出,那么,交叉熵誤差是(假設只有一個訓練樣本,即N=1):

?

?

我們當然可以選擇其他函數作為我們的誤差函數,比如最小平方誤差函數(MSE)。不過對概率進行建模時,選擇交叉熵誤差函數更make sense。具體原因,感興趣的讀者請閱讀參考文獻7。

RNN的實現

完整代碼請參考GitHub:?https://github.com/hanbt/learn_dl/blob/master/rnn.py?(python2.7)

為了加深我們對前面介紹的知識的理解,我們來動手實現一個RNN層。我們復用了上一篇文章零基礎入門深度學習(4) - 卷積神經網絡中的一些代碼,所以先把它們導入進來。

  1. import numpy as np
  2. from cnn import ReluActivator, IdentityActivator, element_wise_op

我們用RecurrentLayer類來實現一個循環層。下面的代碼是初始化一個循環層,可以在構造函數中設置卷積層的超參數。我們注意到,循環層有兩個權重數組,U和W。

  1. class RecurrentLayer(object):
  2. def __init__(self, input_width, state_width,
  3. activator, learning_rate):
  4. self.input_width = input_width
  5. self.state_width = state_width
  6. self.activator = activator
  7. self.learning_rate = learning_rate
  8. self.times = 0 # 當前時刻初始化為t0
  9. self.state_list = [] # 保存各個時刻的state
  10. self.state_list.append(np.zeros(
  11. (state_width, 1))) # 初始化s0
  12. self.U = np.random.uniform(-1e-4, 1e-4,
  13. (state_width, input_width)) # 初始化U
  14. self.W = np.random.uniform(-1e-4, 1e-4,
  15. (state_width, state_width)) # 初始化W

在forward方法中,實現循環層的前向計算,這部分比較簡單。

  1. def forward(self, input_array):
  2. '''
  3. 根據『式2』進行前向計算
  4. '''
  5. self.times += 1
  6. state = (np.dot(self.U, input_array) +
  7. np.dot(self.W, self.state_list[-1]))
  8. element_wise_op(state, self.activator.forward)
  9. self.state_list.append(state)

在backword方法中,實現BPTT算法。

  1. def backward(self, sensitivity_array,
  2. activator):
  3. '''
  4. 實現BPTT算法
  5. '''
  6. self.calc_delta(sensitivity_array, activator)
  7. self.calc_gradient()
  8. def calc_delta(self, sensitivity_array, activator):
  9. self.delta_list = [] # 用來保存各個時刻的誤差項
  10. for i in range(self.times):
  11. self.delta_list.append(np.zeros(
  12. (self.state_width, 1)))
  13. self.delta_list.append(sensitivity_array)
  14. # 迭代計算每個時刻的誤差項
  15. for k in range(self.times - 1, 0, -1):
  16. self.calc_delta_k(k, activator)
  17. def calc_delta_k(self, k, activator):
  18. '''
  19. 根據k+1時刻的delta計算k時刻的delta
  20. '''
  21. state = self.state_list[k+1].copy()
  22. element_wise_op(self.state_list[k+1],
  23. activator.backward)
  24. self.delta_list[k] = np.dot(
  25. np.dot(self.delta_list[k+1].T, self.W),
  26. np.diag(state[:,0])).T
  27. def calc_gradient(self):
  28. self.gradient_list = [] # 保存各個時刻的權重梯度
  29. for t in range(self.times + 1):
  30. self.gradient_list.append(np.zeros(
  31. (self.state_width, self.state_width)))
  32. for t in range(self.times, 0, -1):
  33. self.calc_gradient_t(t)
  34. # 實際的梯度是各個時刻梯度之和
  35. self.gradient = reduce(
  36. lambda a, b: a + b, self.gradient_list,
  37. self.gradient_list[0]) # [0]被初始化為0且沒有被修改過
  38. def calc_gradient_t(self, t):
  39. '''
  40. 計算每個時刻t權重的梯度
  41. '''
  42. gradient = np.dot(self.delta_list[t],
  43. self.state_list[t-1].T)
  44. self.gradient_list[t] = gradient

有意思的是,BPTT算法雖然數學推導的過程很麻煩,但是寫成代碼卻并不復雜。

在update方法中,實現梯度下降算法。

  1. def update(self):
  2. '''
  3. 按照梯度下降,更新權重
  4. '''
  5. self.W -= self.learning_rate * self.gradient

上面的代碼不包含權重U的更新。這部分實際上和全連接神經網絡是一樣的,留給感興趣的讀者自己來完成吧。

循環層是一個帶狀態的層,每次forword都會改變循環層的內部狀態,這給梯度檢查帶來了麻煩。因此,我們需要一個reset_state方法,來重置循環層的內部狀態。

  1. def reset_state(self):
  2. self.times = 0 # 當前時刻初始化為t0
  3. self.state_list = [] # 保存各個時刻的state
  4. self.state_list.append(np.zeros(
  5. (self.state_width, 1))) # 初始化s0

最后,是梯度檢查的代碼。

  1. def gradient_check():
  2. '''
  3. 梯度檢查
  4. '''
  5. # 設計一個誤差函數,取所有節點輸出項之和
  6. error_function = lambda o: o.sum()
  7. rl = RecurrentLayer(3, 2, IdentityActivator(), 1e-3)
  8. # 計算forward值
  9. x, d = data_set()
  10. rl.forward(x[0])
  11. rl.forward(x[1])
  12. # 求取sensitivity map
  13. sensitivity_array = np.ones(rl.state_list[-1].shape,
  14. dtype=np.float64)
  15. # 計算梯度
  16. rl.backward(sensitivity_array, IdentityActivator())
  17. # 檢查梯度
  18. epsilon = 10e-4
  19. for i in range(rl.W.shape[0]):
  20. for j in range(rl.W.shape[1]):
  21. rl.W[i,j] += epsilon
  22. rl.reset_state()
  23. rl.forward(x[0])
  24. rl.forward(x[1])
  25. err1 = error_function(rl.state_list[-1])
  26. rl.W[i,j] -= 2*epsilon
  27. rl.reset_state()
  28. rl.forward(x[0])
  29. rl.forward(x[1])
  30. err2 = error_function(rl.state_list[-1])
  31. expect_grad = (err1 - err2) / (2 * epsilon)
  32. rl.W[i,j] += epsilon
  33. print 'weights(%d,%d): expected - actural %f - %f' % (
  34. i, j, expect_grad, rl.gradient[i,j])

需要注意,每次計算error之前,都要調用reset_state方法重置循環層的內部狀態。下面是梯度檢查的結果,沒問題!

小節

至此,我們講完了基本的循環神經網絡、它的訓練算法:BPTT,以及在語言模型上的應用。RNN比較燒腦,相信拿下前幾篇文章的讀者們搞定這篇文章也不在話下吧!然而,循環神經網絡這個話題并沒有完結。我們在前面說到過,基本的循環神經網絡存在梯度爆炸和梯度消失問題,并不能真正的處理好長距離的依賴(雖然有一些技巧可以減輕這些問題)。事實上,真正得到廣泛的應用的是循環神經網絡的一個變體:長短時記憶網絡。它內部有一些特殊的結構,可以很好的處理長距離的依賴,我們將在下一篇文章中詳細的介紹它。現在,讓我們稍事休息,準備挑戰更為燒腦的長短時記憶網絡吧。

參考資料

  1. RECURRENT NEURAL NETWORKS TUTORIAL
  2. Understanding LSTM Networks
  3. The Unreasonable Effectiveness of Recurrent Neural Networks
  4. Attention and Augmented Recurrent Neural Networks
  5. On the difficulty of training recurrent neural networks, Bengio et al.
  6. Recurrent neural network based language model, Mikolov et al.
  7. Neural Network Classification, Categorical Data, Softmax Activation, and Cross Entropy Error, McCaffrey
  8. 轉載自:https://zybuluo.com/hanbingtao/note/541458

轉載于:https://www.cnblogs.com/tu6ge/p/9492338.html

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

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

相關文章

sql排名名次分頁mysql_mysql 實現排名及中文排序實例[分頁累加行號]

/*排名相同情況下,優先按姓名排序*/SELECT t.name, t.company_name, rownum:rownum1 as rankNum, t.ss from (SELECT u.name, sci.company_name, rownum:0,(u.check_numu.online_hours) as ss FROM v_user uLEFT JOIN sys_company_info sci ON u.companyId sci.com…

世上最簡單的mysql_史上最簡單安裝MySQL教程

1.安裝MySQL很多都推薦在MySQL官網進行安裝,我剛開始試的時候官網下載zip文件,打開完全找不到,踩坑了后面我發現了Windows簡易安裝,俗稱傻子都會安裝安裝好了就會看到一個這個文件安裝之前首先你的有沒有這個你就無法安裝,這個可以去這里進行下載安裝好了就可以安裝MySQL了因為…

linux下ftp配置文件詳解

# 匿名用戶配置 anonymous_enableYES # 是否允許匿名ftp,如否則選擇NO anon_upload_enableYES # 匿名用戶是否能上傳 anon_mkdir_write_enableYES # 匿名用戶是否能創建目錄 anon_other_write_enableYES # 修改文件名和刪除文件 # 本地用戶配置 …

Eclipse Maven 編譯錯誤 Dynamic Web Module 3.0 requires Java 1.6 or newer 解決方法

eclipse maven 項目報 Description Resource Path Location TypeDynamic Web Module 3.0 requires Java 1.6 or newer. bdp line 1 Maven Java EE Configuration ProblemDescription Resource Path Location Type One or more constraints have not been satisfied. bdp line 1…

帆軟按鈕控件變查詢_帆軟報表(多sheet)自定義分頁查詢

三、添加自定義按鈕以及JS事件1、打開‘模板Web屬性’2、選中‘填報頁面設置’,修改2)為‘為模板單獨設置‘,3)中是前面七個是添加的自定義按鈕;通過4)按鈕進行設置;5)操作是添加‘加載結束’事件;接下來詳細講述每個步…

使用Python-Flask框架開發Web網站系列課程(一)構建項目

版權聲明:如需轉載,請注明轉載地址。 https://blog.csdn.net/oJohnny123/article/details/81907475 前言 使用IDE:PyCharm 操作系統: Mac Python版本:3.6 我的郵箱:51263921qq.com 交流群: 372430835 請注意,既然要學習…

Mysql varchar 字節長度

1.我們經常 mysql創建 varchar(20) name這個 20長度 究竟是表示的字符數還是字節數?根編碼字符集又有沒有關系? 首先 mysql 5.X 以上的版本的 定義中 表示的字符長度,如上varchar(20)你既可以添加20個英文字符&#x…

網上訂餐python_來自美國網上訂餐網站的創新

美國網上訂餐網站的創新:小服務半徑產生大價值來源:站長網 作者:揚揚做為一個上班族,尤其是從事it行業的白領階層,整日對著電腦鍵盤敲敲打打,講究的是效率,而每天中午乃至晚上考慮吃些什么卻是讓人極其頭疼的事。去哪里…

PHP學習方向-進階2(三)

實踐篇 給定二維數組,根據某個字段排序如何判斷上傳文件類型,如:僅允許 jpg 上傳不使用臨時變量交換兩個變量的值 $a1; $b2; > $a2; $b1; strtoupper 在轉換中文時存在亂碼,你如何解決?php echo strtoupper(ab你好c…

Spring的@Autowired和@Resource

Autowired 當Spring發現Autowired注解時,將自動在代碼上下文中找到和其匹配(默認是類型匹配)的Bean,并自動注入到相應的地方去。 必須確保該類型在IOC容器中只有一個對象;否則報錯。 Resource1、Resource后面沒有任何內…

關于xml文件 xsi:schemaLocation

原文連接&#xff1a;https://www.jianshu.com/p/7f4cbcd9f09f ------------------------------------------------------相信很多人對xml 頭上一大堆得東西都是拿來主義&#xff0c;copy過來就行了&#xff0c;并不理解那是什么意思先來一段<?xml version"1.0" …

ES6部分特性小結

前言 踩著前人的肩膀&#xff0c;努力前行。參考了很多前人的文章。 1.變量聲明const和let es6之前聲明變量只能用var&#xff0c;var的特點是無論聲明在何處&#xff0c;都會被視為聲明在函數的最頂部(不在函數內即在全局作用域的最頂部) function test(){if(false){var name …

java 順序棧_Java實現順序棧

一、分析棧是限定僅在表的一端進行插入或刪除操作的線性表&#xff0c;對于棧來說&#xff0c;操作端稱為棧頂&#xff0c;另一端則稱為棧底&#xff0c;棧的修改是按照后進先出的原則進行的&#xff0c;因此又稱為后進先出的線性表。順序棧是指利用順序存儲結構實現的棧&#…

Spring IO platform

什么是Spring IO PlatformSpring IO Platform&#xff0c;簡單的可以認為是一個依賴維護平臺&#xff0c;該平臺將相關依賴匯聚到一起&#xff0c;針對每個依賴&#xff0c;都提供了一個版本號&#xff0c;這些版本對應的依賴都是經過測試的&#xff0c;可以保證一起正常使用。…

二十多歲不信,三十多歲卻深信不疑的道理

1.那些年偷的懶、荒廢的時間、敗壞的身體&#xff0c;都&#xff01;得&#xff01;還&#xff01; 年輕的時候心比天高&#xff0c;以為自己能干出一番大事業&#xff0c;后來慢慢意識到自己只是個普通人。 2.不和講道理。 3.原來被嗤之以鼻的門當戶對是有一定道理的。 4.以貌…

javascript === 和==的區別

原文鏈接&#xff1a;https://blog.csdn.net/seven_amber/article/details/62889290 -------------------------------------------------------------------- 用于比較 判斷 兩者相等 在比較的時候可以轉自動換數據類型用于嚴格比較 判斷兩者嚴格相等 嚴格比較…

authentication java_HTTP基本認證(Basic Authentication)的JAVA實例代碼

大家在登錄網站的時候&#xff0c;大部分時候是通過一個表單提交登錄信息。但是有時候瀏覽器會彈出一個登錄驗證的對話框&#xff0c;如下圖&#xff0c;這就是使用HTTP基本認證。下面來看看一看這個認證的工作過程:第一步:客戶端發送http request 給服務器,服務器驗證該用戶是…

Python數據分析入門(四)

前言上期給大家分享了關于豆瓣5500部電視劇的分析&#xff0c;那么這次我們就給吃貨們帶來一些福利&#xff0c;此次我們的主題為“尋找最好吃的火鍋”。進入主題之前&#xff0c;先給所有的吃貨們帶來一桌美味的火鍋&#xff0c;作為各位看官的前菜。數據采集此次我們采集的是…

微信開發者工具下載

https://developers.weixin.qq.com/miniprogram/dev/devtools/download.html

java continue goto_Java中goto和break、continue實現區別

goto 關鍵字很早就在程序設計語言中出現。事實上&#xff0c;goto 是匯編語言的程序控制結構的始祖&#xff1a;“若條件 A&#xff0c;則跳到這里&#xff1b;否則跳到那里”。若閱讀由幾乎所有編譯器生成的匯編代碼&#xff0c;就會發現程序控制里包含了許多跳轉。然而&#…