天天看點

Stanford CS224n 第八講:RNN和語言模式

1. 傳統的語言模型

2. 循環神經網絡模型(RNN)

3. 訓練神經網絡面臨的問題和技巧

  • 梯度消失/爆炸出現的原因
  • 梯度消失/爆炸執行個體
  • 處理梯度消失/爆炸技巧

5. RNN應用于其他序列任務

\newline

\newline

本節課主要講了循環神經網絡,下面将上面幾個部分詳述:

1. 傳統的語言模型

語言模型是為了計算一個單詞序列出現的機率 P ( w 1 , w 2 , . . . , w T ) P(w_1,w_2,...,w_T) P(w1​,w2​,...,wT​),使最有可能出現的序列機率最大,例如在機器翻譯的問題中:

在翻譯"貓很小"時,單詞的語序問題中我們會使機率 P(the cat is small) > P(small the is cat);

在翻譯"放學後走回家"時,單詞的選擇問題中我們會使機率 P(walking home after school) > P(walking house after school)

目前我們很難為所有的語序計算機率,是以我們隻關注視窗下的前n個單詞來預測目前詞的機率。當然這是不正确但是必須的馬爾科夫假設:

P ( w 1 , . . . , w m ) = ∏ i = 1 m P ( w i ∣ w 1 , . . . w i − 1 ) ≈ ∏ i = 1 m P ( w i ∣ w i − ( n − 1 ) , . . . w i − 1 ) P(w_1,...,w_m)=\prod_{i=1}^m{P(w_i|w_1,...w_{i-1})}\approx\prod_{i=1}^m{P(w_i|w_{i-(n-1)},...w_{i-1})} P(w1​,...,wm​)=i=1∏m​P(wi​∣w1​,...wi−1​)≈i=1∏m​P(wi​∣wi−(n−1)​,...wi−1​)

通過語料中的先驗也就是通過計數的方式來計算一進制和二進制的條件機率公式如下:

n=1時,機率公式為: P ( w 2 ∣ w 1 ) = c o u n t ( w 1 , w 2 ) c o u n t ( w 1 ) P(w_2|w_1)={count(w_1,w_2)\over{count(w_1)}} P(w2​∣w1​)=count(w1​)count(w1​,w2​)​

n=2時,機率公式為: P ( w 3 ∣ w 1 , w 2 ) = c o u n t ( w 1 , w 2 , w 3 ) c o u n t ( w 1 , w 2 ) P(w_3|w_1,w_2)={count(w_1,w_2,w_3)\over{count(w_1,w_2)}} P(w3​∣w1​,w2​)=count(w1​,w2​)count(w1​,w2​,w3​)​

n=m時,機率公式為: P ( w m + 1 ∣ w 1 , . . . , w m ) = c o u n t ( w 1 , . . . , w m + 1 ) c o u n t ( w 1 , . . . , w m ) P(w_{m+1}|w_1,...,w_m)={count(w_1,...,w_{m+1})\over{count(w_1,...,w_m)}} P(wm+1​∣w1​,...,wm​)=count(w1​,...,wm​)count(w1​,...,wm+1​)​

其中count()為一個計數函數,它是負責計算對應詞序在語料中出現的頻數。由上面幾部分顯然,當n越大,馬爾科夫假設效果就越弱,計算出來的機率值也就越接近于真實值,當然n越大,我們的計算量也就越大(魚和熊掌不可兼得)。

2. 循環神經網絡模型(RNN)

目前對于語言模型,我們采用的是循環神經網絡,先通過模型圖來了解一下:

Stanford CS224n 第八講:RNN和語言模式

上圖的展開形式如下:

Stanford CS224n 第八講:RNN和語言模式

一般情況下我們以展開形式來了解RNN,但是實際上他們就是一個相同單元的展開,可以了解為每個單元的參數是共享的。

RNN的公式定義為:

給定一個詞向量清單: x 1 , . . . , x t − 1 , x t , x t + 1 . . . , x T x_1,...,x_{t-1},x_t,x_{t+1}...,x_T x1​,...,xt−1​,xt​,xt+1​...,xT​

h t = σ ( W h h h t − 1 + W h x x t ) h_t=\sigma(W^{hh}h_{t-1}+W^{hx}x_t) ht​=σ(Whhht−1​+Whxxt​)

y ^ = s o f t m a x ( W ( S ) h t ) \hat{y}=softmax(W^{(S)}h_t) y^​=softmax(W(S)ht​)

其中:

x t ∈ R d ∗ 1 x_t\in R^{d*1} xt​∈Rd∗1,是在t時刻輸入模型的 d x ∗ 1 d_x*1 dx​∗1次元的詞向量;

W h h ∈ R D h ∗ D h W^{hh}\in R^{D_h*D_h} Whh∈RDh​∗Dh​,是對輸入的上一層的隐向量 h t − 1 h_{t-1} ht−1​進行線性變換的權重矩陣;

W h x ∈ R D h ∗ d W^{hx}\in R^{D_h*d} Whx∈RDh​∗d,是對輸入的詞向量 x t x_t xt​進行線性變換的權重矩陣;

h t ∈ R D h ∗ 1 h_t\in R^{D_h*1} ht​∈RDh​∗1,是通過 σ \sigma σ()函數對輸入和上一層傳過來的隐向量之和記性非線性變換;

W ( S ) ∈ R ∣ V ∣ ∗ D h W^{(S)}\in R^{|V|*D_h} W(S)∈R∣V∣∗Dh​,是通過 W ( S ) W^{(S)} W(S)矩陣對 h t h_t ht​映射成|V|*1維的列向量,其中|V|表示待分類的類别數;

y ^ ∈ R ∣ V ∣ ∗ 1 \hat{y}\in R^{|V|*1} y^​∈R∣V∣∗1,通過softmax函數,将 W ( S ) h t W^{(S)}h_t W(S)ht​的結果轉換成各個類别的機率值。

還有一點需要注意的是,當剛開始的時候RNN沒有上一層傳入的隐向量,一般情況下,我們初始化一個全零的 h 0 h_0 h0​作為第一層傳入的隐向量。

我們現在的任務不是分類而是預測下一個單詞出現的機率值,是以我們需要拟合的就是

P ^ ( x t + 1 = v j ∣ x 1 , . . . , x t ) = y ^ t , j 其 中 v 表 示 語 料 庫 大 小 \hat{P}(x_{t+1}=v_j|x_1,...,x_t)=\hat{y}_{t,j} 其中v表示語料庫大小 P^(xt+1​=vj​∣x1​,...,xt​)=y^​t,j​其中v表示語料庫大小

是以在t時刻損失函數也采用交叉熵loss function,但是此時已經不是預測類别,而是預測單詞:

J t ( θ ) = − ∑ j = 1 ∣ V ∣ y t . j l o g y ^ t . j 其 中 ∣ V ∣ 表 示 語 料 庫 大 小 J^t(\theta)=-\sum^{|V|}_{j=1}y_{t.j}log\hat{y}_{t.j} 其中|V|表示語料庫大小 Jt(θ)=−j=1∑∣V∣​yt.j​logy^​t.j​其中∣V∣表示語料庫大小

由上式我們顯然可得到,整個序列的損失函數為:

J t ( θ ) = − 1 T ∑ t = 1 T ∑ j = 1 ∣ V ∣ y t . j l o g y ^ t . j 其 中 ∣ V ∣ 表 示 語 料 庫 大 小 J^t(\theta)=-{1\over T}\sum^{T}_{t=1}\sum^{|V|}_{j=1}y_{t.j}log\hat{y}_{t.j} 其中|V|表示語料庫大小 Jt(θ)=−T1​t=1∑T​j=1∑∣V∣​yt.j​logy^​t.j​其中∣V∣表示語料庫大小

3. 訓練神經網絡面臨的問題和技巧

RNN和普通的神經網絡的訓練過程有些許不同,對于普通的神經網絡,我們一般是自上而下的進行梯度計算,但是RNN特殊之處就在于,他的梯度有自上而下,自右向左兩個方向來源,如下圖:

Stanford CS224n 第八講:RNN和語言模式
  • 梯度消失/爆炸出現的原因

    梯度消失是什麼?為什麼會出現梯度消失?下面我們來看一下RNN的反向傳播過程。

    假設我們的RNN公式形式和上面定義保持一緻:

    h t = σ ( W h h h t − 1 + W h x x t ) h_t=\sigma(W^{hh}h_{t-1}+W^{hx}x_t) ht​=σ(Whhht−1​+Whxxt​)

    y t ^ = s o f t m a x ( W ( S ) h t ) \hat{y_t}=softmax(W^{(S)}h_t) yt​^​=softmax(W(S)ht​)

    對于RNN結構來說,由于我們在序列的每個位置都有損失,是以最終的損失函數為:

    J = ∑ t = 1 T J t J=\sum^T_{t=1}J^t J=∑t=1T​Jt

    其中 W ( S ) W^{(S)} W(S)的梯度計算是比較簡單的:

    ∂ J ∂ W ( S ) = ∑ t = 1 T ∂ J t ∂ W ( S ) = ∑ t = 1 T ∂ J t ∂ y ^ t ∂ y ^ t ∂ W ( S ) {{\partial J}\over{\partial W^{(S)}}}=\sum^T_{t=1}{\partial J^t \over \partial W^{(S)}}=\sum^T_{t=1}{\partial J^t \over \partial \hat y_t}{\partial \hat y_t \over \partial W^{(S)}} ∂W(S)∂J​=t=1∑T​∂W(S)∂Jt​=t=1∑T​∂y^​t​∂Jt​∂W(S)∂y^​t​​

    但是 W h h W^{hh} Whh和 W h x W^{hx} Whx的梯度計算就比較的複雜了。從RNN的模型可以看出,在反向傳播時,在t時刻的梯度損失由目前位置的輸出對應的梯度損失(從上到下)和t+1時的梯度損失(從右到左)兩部分共同決定。對于W在某一時刻t的梯度損失需要反向傳播一步步的計算。為了友善後面的重複利用,我們定義時刻t的隐藏狀态的梯度為 δ ( t ) \delta^{(t)} δ(t):

    δ ( t ) = ∂ J ∂ h t \delta^{(t)}={\partial J \over \partial h_t} δ(t)=∂ht​∂J​

    由此我們可以跟普通的神經網絡一樣,由 δ ( t + 1 ) \delta^{(t+1)} δ(t+1)推導出 δ ( t ) \delta^{(t)} δ(t):

    δ ( t ) = ∂ J ∂ y t ^ ∂ y t ^ ∂ h t + ∂ J ∂ h t + 1 ∂ h t + 1 ∂ h t = ∂ J ∂ y t ^ ∂ y t ^ ∂ h t + δ ( t + 1 ) ∂ h t + 1 ∂ h t \delta^{(t)}={\partial J \over \partial \hat {y_t}}{\partial \hat {y_t} \over \partial h_t}+{\partial J \over \partial h_{t+1}}{ \partial h_{t+1} \over \partial h_t}={\partial J \over \partial \hat {y_t}}{\partial \hat {y_t} \over \partial h_t}+{\delta^{(t+1)}}{ \partial h_{t+1} \over \partial h_t} δ(t)=∂yt​^​∂J​∂ht​∂yt​^​​+∂ht+1​∂J​∂ht​∂ht+1​​=∂yt​^​∂J​∂ht​∂yt​^​​+δ(t+1)∂ht​∂ht+1​​

    顯然上式中第一部分為從上到下傳播的梯度;第二部分為從右往左傳播的梯度。

為了友善運算書寫,我們假設 h t h_t ht​的激活函數 σ ( ) \sigma() σ()變為tanh()函數(PS:激活函數的一種,不影響求導思路,此處替換僅僅是為了友善運算),是以 W h h 和 W ( h x ) W^{hh}和W^(hx) Whh和W(hx)的求偏導過程如下:

∂ J ∂ W ( h h ) = ∑ t = 1 T ∂ J ∂ h t ∂ h t ∂ W ( h h ) = ∑ t = 1 T δ ( t ) ⨀ ( 1 ∈ R D h ∗ 1 − ( h t ) 2 ) h t − 1 T {\partial J\over \partial W^{(hh)}}=\sum^T_{t=1}{\partial J \over \partial h_t}{\partial h_t \over \partial W^{(hh)}}=\sum^T_{t=1}\delta^{(t)}\bigodot(1^{\in R^{D_h*1}}-(h_t)^2) h_{t-1}^T ∂W(hh)∂J​=t=1∑T​∂ht​∂J​∂W(hh)∂ht​​=t=1∑T​δ(t)⨀(1∈RDh​∗1−(ht​)2)ht−1T​

∂ J ∂ W ( h x ) = ∑ t = 1 T ∂ J ∂ h t ∂ h t ∂ W ( h x ) = ∑ t = 1 T δ ( t ) ⨀ ( 1 ∈ R D h ∗ 1 − ( h t ) 2 ) x t T {\partial J\over \partial W^{(hx)}}=\sum^T_{t=1}{\partial J \over \partial h_t}{\partial h_t \over \partial W^{(hx)}}=\sum^T_{t=1}\delta^{(t)}\bigodot(1^{\in R^{D_h*1}}-(h_t)^2) x_t^T ∂W(hx)∂J​=t=1∑T​∂ht​∂J​∂W(hx)∂ht​​=t=1∑T​δ(t)⨀(1∈RDh​∗1−(ht​)2)xtT​

上式中:

⨀ \bigodot ⨀為哈達瑪乘積,也就是矩陣對應元素相乘

δ ( t ) ∈ R D h ∗ 1 \delta^{(t)}\in R^{D_h*1} δ(t)∈RDh​∗1

h t ∈ R D h ∗ 1 h_t\in R^{D_h*1} ht​∈RDh​∗1

x t ∈ R d ∗ 1 x_t\in R^{d*1} xt​∈Rd∗1

激活函數tanh(x)求導有如下性質: f ( x ) = t a n h ( x ) f(x)=tanh(x) f(x)=tanh(x), f ’ ( x ) = 1 − ( f ( x ) ) 2 f^’(x)=1-(f(x))^2 f’(x)=1−(f(x))2

其實以上過程也跟第四講中的推倒過程類似,我是先通過求 W h h W^{hh} Whh矩陣中單一進制素的偏導數,然後拓展到矩陣求導,下面是對 W i j h h W^{hh}_{ij} Wijhh​的求導過程, W i j h x W^{hx}_{ij} Wijhx​類似,是以此處隻推導 W i j h h W^{hh}_{ij} Wijhh​:

∂ h t ∂ W i j h h = ( 1 − ( h t ( i ) ) 2 ) ∂ ( W h h h t − 1 + W h x x t ) ∂ W i j h h = ( 1 − ( h t ( i ) ) 2 ) ∂ ( ∑ m = 1 D h W i m h h h t − 1 ( m ) + W h x x t ) ∂ W i j h h = ( 1 − ( h t ( i ) ) 2 ) h t − 1 ( j ) {\partial h_t \over \partial W^{hh}_{ij}}=(1-(h^{(i)}_t)^2){\partial (W^{hh}h_{t-1}+W^{hx}x_t) \over \partial W^{hh}_{ij}}=(1-(h^{(i)}_t)^2){\partial (\sum ^{D_h}_{m=1}W^{hh}_{im}h^{(m)}_{t-1}+W^{hx}x_t) \over \partial W^{hh}_{ij}}=(1-(h^{(i)}_t)^2)h^{(j)}_{t-1} ∂Wijhh​∂ht​​=(1−(ht(i)​)2)∂Wijhh​∂(Whhht−1​+Whxxt​)​=(1−(ht(i)​)2)∂Wijhh​∂(∑m=1Dh​​Wimhh​ht−1(m)​+Whxxt​)​=(1−(ht(i)​)2)ht−1(j)​

由上式單個變量的偏導數我們就可以推導出他們的矩陣形式,以上推導過程如有錯誤,請不吝賜教。

從上面的推導過程中我們可以看到在對W求導的時候:

∂ J ∂ W ( h h ) = ∑ t = 1 T ∂ J t ∂ y t ^ ∂ y t ^ ∂ h t ∂ h t ∂ h k ∂ h k ∂ W ( h h ) {\partial J\over \partial W^{(hh)}}=\sum^T_{t=1}{\partial J_t \over \partial \hat {y_t}}{\partial \hat {y_t} \over \partial h_t}{\partial h_t \over \partial h_k}{\partial h_k \over \partial W^{(hh)}} ∂W(hh)∂J​=t=1∑T​∂yt​^​∂Jt​​∂ht​∂yt​^​​∂hk​∂ht​​∂W(hh)∂hk​​

其中上式中:

∂ h t ∂ h k = ∏ j = k + 1 t ∂ h j ∂ h j − 1 {\partial h_t \over \partial h_k}=\prod^t_{j=k+1}{\partial h_j \over \partial h_{j-1}} ∂hk​∂ht​​=j=k+1∏t​∂hj−1​∂hj​​

上式中每一個偏導數都是一個雅可比Jacobain行列式:

Stanford CS224n 第八講:RNN和語言模式

對于雅可比行列式,我們可以假設他的範數的上限為 β \beta β,則我們可以得到:

Stanford CS224n 第八講:RNN和語言模式

則W的梯度是一系列雅可比行列式範數的乘積:

Stanford CS224n 第八講:RNN和語言模式

由上式我們可知,當我們初始化時,行列式的範數大于1時,梯度就會出現變得無限大,這就是梯度爆炸;行列式範數小于1時,梯度就會變得無限小,這就是梯度消失。對于普通的神經網絡梯度消失會造成神經網絡前幾層的參數變化很小或者幾乎不更新。

  • 梯度消失出現的執行個體

    話不多說,先把代碼貼上(Git位址)再分析結果:

import numpy as np
import matplotlib.pyplot as plt

#sigmoid函數
def sigmoid(x):
    x=1/(1+np.exp(-x))
    return x
#sigmoid導函數
def sigmoid_grad(x):
    return x*(1-x)
#Relu激活函數
def relu(x):
    return np.maximum(0,x)

def three_layer_net(NONLINEARITY,X,y,model,step_size,reg):
    #參數初始化
    h=model['h']
    h2=model['h2']
    W1=model['W1']
    W2 = model['W2']
    W3 = model['W3']
    b1=model['b1']
    b2 = model['b2']
    b3 = model['b3']

    num_examples=X.shape[0]
    plot_array_1=[]
    plot_array_2=[]
    for i in range(50000):
        #前向傳播
        if NONLINEARITY=='RELU':
            hidden_layer=relu(np.dot(X,W1)+b1)
            hidden_layer2=relu(np.dot(hidden_layer,W2)+b2)
            scores=np.dot(hidden_layer2,W3)+b3
        elif NONLINEARITY == 'SIGM':
            hidden_layer = sigmoid(np.dot(X, W1) + b1)
            hidden_layer2 = sigmoid(np.dot(hidden_layer, W2) + b2)
            scores = np.dot(hidden_layer2, W3) + b3
        exp_scores=np.exp(scores)
        probs=exp_scores/np.sum(exp_scores,axis=1,keepdims=True)#softmax機率化得分[N*K]

        #計算損失
        correct_logprobs=-np.log(probs[range(num_examples),y])#整體的交叉熵損失
        data_loss=np.sum(correct_logprobs)/num_examples #平均交叉熵損失
        reg_loss=0.5*reg*np.sum(W1*W1)+0.5*reg*np.sum(W2*W2)+0.5*reg*np.sum(W3*W3)#正則化損失,W1*W1表示哈達瑪積
        loss=data_loss+reg_loss
        if i%1000==0:
            print("iteration %d: loss %f"%(i,loss))

        #計算scores的梯度
        dscores=probs
        dscores[range(num_examples),y]-=1 #此處為交叉熵損失函數的求導結果,詳細過程請看:https://blog.csdn.net/qian99/article/details/78046329
        dscores/=num_examples

        #反向傳播過程
        dW3=(hidden_layer2.T).dot(dscores)
        db3=np.sum(dscores,axis=0,keepdims=True)


        if NONLINEARITY == 'RELU':
            # 采用RELU激活函數的反向傳播過程
            dhidden2 = np.dot(dscores, W3.T)
            dhidden2[hidden_layer2 <= 0] = 0
            dW2 = np.dot(hidden_layer.T, dhidden2)
            plot_array_2.append(np.sum(np.abs(dW2)) / np.sum(np.abs(dW2.shape)))
            db2 = np.sum(dhidden2, axis=0)
            dhidden = np.dot(dhidden2, W2.T)
            dhidden[hidden_layer <= 0] = 0

        elif NONLINEARITY == 'SIGM':
            # 采用SIGM激活函數的反向傳播過程
            dhidden2 = dscores.dot(W3.T) * sigmoid_grad(hidden_layer2)
            dW2 = (hidden_layer.T).dot(dhidden2)
            plot_array_2.append(np.sum(np.abs(dW2)) / np.sum(np.abs(dW2.shape)))
            db2 = np.sum(dhidden2, axis=0)
            dhidden = dhidden2.dot(W2.T) * sigmoid_grad(hidden_layer)

        dW1 = np.dot(X.T, dhidden)
        plot_array_1.append(np.sum(np.abs(dW1)) / np.sum(np.abs(dW1.shape)))#第一層的平均梯度記錄下來
        db1 = np.sum(dhidden, axis=0)

        # 加入正則化得到的梯度
        dW3 += reg * W3
        dW2 += reg * W2
        dW1 += reg * W1

        # 記錄梯度
        grads = {}
        grads['W1'] = dW1
        grads['W2'] = dW2
        grads['W3'] = dW3
        grads['b1'] = db1
        grads['b2'] = db2
        grads['b3'] = db3

        # 更新梯度
        W1 += -step_size * dW1
        b1 += -step_size * db1
        W2 += -step_size * dW2
        b2 += -step_size * db2
        W3 += -step_size * dW3
        b3 += -step_size * db3
    # 評估模型的準确度
    if NONLINEARITY == 'RELU':
        hidden_layer = relu(np.dot(X, W1) + b1)
        hidden_layer2 = relu(np.dot(hidden_layer, W2) + b2)
    elif NONLINEARITY == 'SIGM':
        hidden_layer = sigmoid(np.dot(X, W1) + b1)
        hidden_layer2 = sigmoid(np.dot(hidden_layer, W2) + b2)
    scores = np.dot(hidden_layer2, W3) + b3
    predicted_class = np.argmax(scores, axis=1)
    print('training accuracy: %.2f' % (np.mean(predicted_class == y)))
    # 傳回梯度和參數
    return plot_array_1, plot_array_2, W1, W2, W3, b1, b2, b3
if __name__=='__main__':
    plt.rcParams['figure.figsize']=(10.0,8.0)#設定畫布的預設大小
    plt.rcParams['image.interpolation']='nearest'#設定插值的風格
    plt.rcParams['image.cmap']='gray'#設定畫布的顔色

    np.random.seed(0)#保證後面seed(0)生成的随機數相同
    N=100 #每一個類别的數量
    D=2 #次元
    K=3 #類别數
    h=50
    h2=50
    X=np.zeros((N*K,D))
    num_train_examples=X.shape[0]
    y=np.zeros(N*K,dtype='uint8')
    for j in range(K):
        ix=range(N*j,N*(j+1))
        r=np.linspace(0.0,1,N) # 半徑
        t=np.linspace(j*4,(j+1)*4,N)+np.random.randn(N)*0.2 # theta
        X[ix]=np.c_[r*np.sin(t),r*np.cos(t)]# 按行拼接兩個矩陣
        y[ix]=j
    fig=plt.figure()
    plt.scatter(X[:,0],X[:,1],c=y,s=40,cmap=plt.cm.Spectral)#畫點,c代表顔色,s代表點的大小
    plt.xlim([-1,1])#設定橫坐标的範圍大小
    plt.ylim([-1,1])#設定縱坐标的範圍大小
    plt.show()

    #初始化模型參數
    h = 50
    h2 = 50
    model={}
    model['h'] = h # hidden layer 1 大小
    model['h2']= h2# hidden layer 2 大小
    model['W1']= 0.1 * np.random.randn(D,h)
    model['b1'] = np.zeros((1,h))
    model['W2'] = 0.1 * np.random.randn(h,h2)
    model['b2']= np.zeros((1,h2))
    model['W3'] = 0.1 * np.random.randn(h2,K)
    model['b3'] = np.zeros((1,K))
    Activation_Function='RELU'#選擇激活函數  SIGM/RELU
    (plot_array_1, plot_array_2, W1, W2, W3, b1, b2, b3) = three_layer_net(Activation_Function, X, y, model,step_size=1e-1, reg=1e-3)

    #模型采用兩種激活函數時,分别畫出模型梯度的變化趨勢

    plt.plot(np.array(plot_array_1))
    plt.plot(np.array(plot_array_2))
    plt.title('Sum of magnitudes of gradients -- hidden layer neurons')
    plt.legend((Activation_Function+" first layer", Activation_Function+" second layer"))
    plt.show()
           

上述程式中先制造訓練資料,如下圖:

Stanford CS224n 第八講:RNN和語言模式

然後分别采用sigmoid和RELU函數當做激活函數來訓練模型,并記錄模型中各層梯度的變化,效果如下:

Stanford CS224n 第八講:RNN和語言模式

由上圖我們可以看出(PS:上圖中的第一層和第二層,是相對于神經網絡正向傳播時距離起點輸入的層數),反向傳播的過程中,距離反向傳播的起點越遠,梯度的變化值越小,如果神經網絡的層數很多,最終可能梯度就會消失,導緻前面層數的參數不更新,這就是梯度消失現象。

  • 處理梯度爆炸技巧

    處理梯度爆炸通常采用clip gradient算法,其僞代碼如下:

    Stanford CS224n 第八講:RNN和語言模式

    這個方法是Thomas Mikolov首先提出的,大體思想就是設定一個門檻值,當梯度大于這個門檻值的時候就截斷,這個方法聽上去很無腦,但是實際效果還不錯。

    但是這種方法沒法兒應用到梯度消失,因為當梯度很小的時候,說明某一些次元的特征權重要不變了,如果這時候設定一個最小值的門檻值,則會讓這些次元的特征權重繼續變化,是以得證:clip gradient不能應用到梯度消失。

  • 處理梯度消失技巧

處理梯度消失的方法大體就是

(1) 對W不采用随機初始化,初始化為機關矩陣;這樣初始效果就是上下文向量和詞向量具有相同權重,減少随機性。

(2)激活函數采用Relu函數,從Relu和Sigmoid函數的圖像我們可以知道,sigmoid的梯度在飽和區域非常平緩,接近于0,很容易造成梯度消失的問題;而Relu的梯度大多數情況下是常數。

Stanford CS224n 第八講:RNN和語言模式

5. RNN應用于其他序列任務

有了RNN,我們可以用它來做哪些任務呢?課程中講到,有NER(命名實體識别)、上下文中實體層次情感分析、觀點表達分類等 。

文中以RNN進行意見挖掘為例:

Stanford CS224n 第八講:RNN和語言模式

其中,意見挖掘任務就是将每個詞語歸類為:

DSE:直接主觀描述(明确表達觀點等)

ESE:間接主觀描述(間接地表達情感等)

具體的标注方法BIO标注,B表示實體的開始,I表示實體的延續,O表示other。

我們可以用簡單的RNN來完成上面任務:

Stanford CS224n 第八講:RNN和語言模式

其中x代表輸入tokens;y代表标簽BIO。

如果過我們考慮到RNN的單向性,而打标簽的過程可能依賴上下文,那麼我們可以采用雙向RNN:

Stanford CS224n 第八講:RNN和語言模式

當然為了實驗效果,也可以加深網絡:

Stanford CS224n 第八講:RNN和語言模式

最後的實驗結果(F1值)表明,神經網絡不是層數越大越好:

Stanford CS224n 第八講:RNN和語言模式

好了,這節課就寫到這兒吧。這次是我公式寫的最多的一次,繼續努力。。。

繼續閱讀