淺談RNN、LSTM + Kreas實現及應用


本文主要針對RNN與LSTM的結構及其原理進行詳細的介紹,了解什么是RNN,RNN的1對N、N對1的結構,什么是LSTM,以及LSTM中的三門(input、ouput、forget),后續將利用深度學習框架Kreas,結合案例對LSTM進行進一步的介紹。

一、RNN的原理

  RNN(Recurrent Neural Networks),即全稱循環神經網絡,它是一種對序列型的數據進行建模的深度模型。如圖1.1所示。

 

圖1.1

 

  1、其中為序列數據。即神經網絡的輸入,例如nlp中,X1可以看作第一個單詞、X2可以看作是第二個單詞,依次類推。語音處理中,可以將是每幀的聲音信號。時間序列中,例如,某生活用品的銷量數據。

  2、U、W、V是參數矩陣,b、c是偏置項,f是激活函數,通常采用”熱擼”、tanh函數作為激活函數,用softmax將輸出轉換成各個類別的概率。

  3、上圖為經典的RNN結構,其運算過程可以表示為:

 

式中:表示神經網絡的輸出;表示前一個時間點的狀態;

  4、考慮到輸入與輸出的關系,序列問題具有以下分類:

       一對多的RNN結構:序列輸出,用於圖像字幕,如圖1.2所示。

 

圖1.2

  多對一的RNN結構:序列輸入,用於情感分類,如圖1.3所示。

 

 

圖1.3

  多對多:序列輸入和輸出,用於機器翻譯

  同步多對多:同步序列輸入和輸出,用於視頻分類

二、LSTM的原理

  上面第一部分簡單介紹了RNN的幾種結構,接下來,介紹一下RNN的改進版:LSTM。LSTM(long short-term memory,長短時記憶網絡),它的出現解決了很難處理的“長程依賴”問題,即無法學到序列中蘊含的間隔時間較長的規律RNN每一層的隱狀態都由前一層的隱狀態經過變換和激活函數得到,反向傳播求導時最終得到的導數會包含每一步梯度的連乘,將會引起梯度的消失或者梯度的爆炸。LSTM在隱狀態使用了加法替代了每一步的迭代變換,這樣便可以避免梯度消失的問題,從而使得網絡學到長程的規律。

RNN可用圖1.4表示

 

 

圖1.4

 

  同理,LSTM的結構圖1.5所示

 

圖1.5

  其中圖1.5中的符號,長方形表示對輸入的數據做變換或激活函數;圓形表示逐點,逐點運算是指兩個形狀完全相同的矩形的對應位置進行相加、相乘或者其他的一些運算;箭頭則表示向量會在那里進行運算。注意: 通過concat操作,才進入Sigmoid或tanh函數。

  RNN與LSTM有所不同,LSTM的隱狀態有兩部分,一部分是ht ,另一部分則是在各個步驟之間傳遞的主要信息,綠色的水平線可看作“主干道”,如圖1.6所示。通過加法,可以無障礙的在這條主干道上傳遞,因此較遠的梯度也可以在長程上傳播,這便是LSTM的核心思想

 

圖1.6

  但是,不是每一步的信息都是完全使用前一步的,而是在 的基礎之上“遺忘”掉一些內容,或“記住”一些內容。

  1、  遺忘門,我們首先談一談遺忘門,每個單元都有一個“遺忘門”,用來控制遺忘掉 的那些部分,其結構如圖1.7所示。其中σ是sigmoid激活函數,它的輸出在0~1之間,遺忘門輸出的 相同形狀的矩陣,該矩陣將會和逐點相乘,決定遺忘掉那部分內容。經過激活函數的輸出,f取值接近0的維度上的信息就會被“忘記”,而f取值接近1的維度上的信息就會被保留。

 

圖1.7

  2、 輸入層,如圖1.8,在循環神經網絡“忘記”了部分之前的狀態后,它還需要從當前的輸入補充最新的記憶,這個過程就是“輸入門”完成的。輸入門的輸入同樣是兩項,分別是:。它的輸出項,一項是 同樣經過Sigmoid函數運算得到,其值都是在0~1之間,還有一項。最終要“記住”的內容是點相乘,如圖1.9。

 

 

圖1.8

 

圖1.9

3、  輸出門,輸出門用於計算另一個隱狀態的值,真正的輸出(如類別)需要通過做進一步運算得到。輸出門的結構如圖1.20所示,同樣根據計算,中每一個數值在0~1之間,通過得到。

 

圖1.20

最終總結:LSTM中每一步的輸入是,隱狀態是,最終的輸出必須要經過進一步變換得到。

 

'''
1、讀取IMDb數據集
2、建立token字典
3、使用token將“影評文字”轉換成“數字列表”
4、截長補短讓所有“數字列表”的長度都為100
5、建立嵌入層將“數字列表”轉換為“向量列表”
'''

from keras.preprocessing import sequence #用於將截長補短,讓所有“數字列表”長度為100
from keras.preprocessing.text import Tokenizer  #用於建立字典
# Using TensorFlow backend
from keras.models import Sequential
from keras.layers.core import Dense,Dropout,Activation,Flatten
from keras.layers.embeddings import Embedding
from keras.layers.recurrent import LSTM
from matplotlib import pyplot as plt

import os
import re
import pandas as pd
def rm_tags(text):
    re_tag = re.compile(r',<[^>]+>')
    return re_tag.sub('',text)
def read_files(filename):
    path = "D:/pycharm_program/keras_file/aclImdb/"
    filelist = []
    positive_path = path+filename+"/pos/"
    print(os.listdir(positive_path))
    for f in os.listdir(positive_path):
        filelist += [positive_path+f]

    negative_path = path+filename+"/neg/"
    print(os.listdir(negative_path))
    for f in os.listdir(negative_path):
        filelist += [negative_path+f]

    all_labels = [1] * 12500 + [0] * 12500
    all_texts = []
    for fi in filelist:
        with open(fi,encoding='utf8') as file_input:
            all_texts += [rm_tags("".join(file_input.readlines()))]
    print(len(filelist))
    return all_labels,all_texts
# read_files("train")
# read_files("test")
pd.set_option('display.max_columns',10000)

y_train_labels,y_train_text = read_files("train")
print(y_train_text[0])
y_test_labels,y_test_text = read_files("test")

#建立token,將數據集中,按照每個英文單詞在所有影評中出現的次數進行排序,排序的前3800名的英文單詞會列入字典中
token = Tokenizer(num_words=4000)
token.fit_on_texts(y_train_text)
print(token.document_count)#查看讀取了多少篇文章

#將“評論文字”轉換為“數字列表”
y_train_text_seq = token.texts_to_sequences(y_train_text)
y_test_text_seq = token.texts_to_sequences(y_test_text)

#截長補短,保留數字列表后380個數字,不夠添加成380個數字
y_train = sequence.pad_sequences(y_train_text_seq,maxlen=300)
y_test = sequence.pad_sequences(y_test_text_seq,maxlen=300)

def creat_model():
    #建立一個線性堆疊模型,后續只需要將各個神經網絡層加入模型即可
    model = Sequential()
    #嵌入層,只能作為第一層
    model.add(Embedding(output_dim=32,
                        input_dim=4000,
                        input_length=300))
    #Dropout層
    model.add(Dropout(0.2))
    #LSTM層
    model.add(LSTM(32))
    #隱藏層
    model.add(Dense(units=256,activation='relu'))  #全連接層
    # Dropout層
    model.add(Dropout(0.2))
    # 輸出層
    model.add(Dense(units = 1,activation="sigmoid"))
    #查看模型摘要
    print(model.summary())
    return model
model = creat_model()

#訓練模型之前,對訓練模型進行設置
model.compile(loss='binary_crossentropy',#categorical_crossentropy
              optimizer = 'adam',
              metrics = ['accuracy'])

train_history = model.fit(y_train,y_train_labels,batch_size=100,epochs=10,verbose=2,validation_split=0.2)
#verbose = 2:顯示訓練過程
#validation_split=0.2 划分數據集

#評估模型的准確率
scores = model.evaluate(y_test,y_test_labels,verbose=1)

def save_model():
    #將模型保存成JSON文件
    model_json = model.to_json()
    with open('model.increment.json','w') as f:
        f.write(model_json)

    model.save_weights('model.increment.json.h5')

    #從JSON文件中加載模型
    with open('model.increment.json','r') as f:
        model_json = f.read()

    from keras.models import model_from_json
    new_model = model_from_json(model_json)
    new_model.load_weights('model.increment.json.h5')
    new_model.compile(loss='binary_crossentropy',
                  optimizer = 'adam',
                  metrics = ['accuracy'])
    #編譯模型
    new_model.fit(y_train,y_train_labels,batch_size=100,epochs=10,verbose=2,validation_split=0.2)

    #評估模型的准確率
    scores = model.evaluate(y_test,y_test_labels,verbose=1)
# save_model()

def predict_review(input_text):  #預測一段text
    input_seq = token.texts_to_sequences(input_text)
    pad_input_seq = sequence.pad_sequences(input_seq,maxlen=300)
    predict_result = model.predict_classes(pad_input_seq)
#acc的歷史
plt.plot(train_history.history['acc'])
plt.plot(train_history.history['val_acc'])
plt.title("model accuracy")
plt.ylabel('accuracy')
plt.xlabel('epoch')
plt.legend(['train','validation'],loc = 'upper left')
plt.show()

#loss的歷史
plt.plot(train_history.history['loss'])
plt.plot(train_history.history['val_loss'])
plt.title("model loss")
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train','validation'],loc = 'upper left')
plt.show()

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM