1. 程式人生 > >[NLP][Python]基於keras和LSTM的文字生成

[NLP][Python]基於keras和LSTM的文字生成

RNN and LSTM

學習如何使用RNN來預測和序列處理。
迴圈神經網路除了用於預測模型(做出預測)之外,他們還可以學習問題的序列,然後為問題域生成全新的合理序列。
初次嘗試將問題分解為三個子問題。
- 1.下載一個免費的文字語料庫,您可以使用它來訓練文字生成模型
- 2.如何將文字序列的問題構建成迴圈神經網路生成模型
- 3.如何開發一個LSTM來為給定的問題生成合理的文字序列

匯入資料

load ascii text and covert to lowercase
filename = "wonderland.txt"
raw_text = open(filename).read
() raw_text = raw_text.lower()`

插入說一下read(),readline(),readlines()三個函式的區別

  • read 一次性讀取所有檔案,將所有檔案放到一個字串變數裡
  • readline 每次講一行讀入記憶體,速度較慢(未比較)
  • readlines 讀取時將所有檔案一次性讀取,然後按行解析成列表,一般讀取時用這個

    匯入資料之後首先lower()一下,因為後面生成的時候我們沒有在意英文的首字母語法,這個有待改進。

資料預處理

chars = sorted(list(set(raw_text)))
char_to_int = dict((c, i) for
i, c in enumerate(chars)) int_to_char = dict((i, c) for i, c in enumerate(chars)) n_chars = len(raw_text) n_vocab = len(chars)
  • 首先獲取全部字元的set,然後做兩個dict方便後面向量化,一個char2int,一個int2char,這個之後每個字元對應一個整數。
  • 接著獲取全文字元數和set後的字元數,大約一個在15W一個在50左右。
  • 之後,做字元的向量化過程,因為字元是不能夠之間拉入LSTM中訓練的,我們預設序列長度為100,前100個數據沒有輸出,則有15W減去100個訓練資料,將他們用char2int轉換成向量形式。

首先,我們必須將輸入序列列表變換為LSTM網路預期的[樣本,時間步長,特徵]。接下來,我們需要將整數重新縮放到0到1的範圍,以使預設情況下使用Sigmoid啟用功能的LSTM網路更容易學習模式。
reshape()dataX為預期的張量形式,用utils中的to_categorical將labelY從類別向量(從0到nb_classes的整數向量)對映為二值類別矩陣

# prepare the dataset of input to output pairs encoded as integers
seq_length = 100
dataX = []
dataY = []
for i in range(0, n_chars - seq_length, 1):
    seq_in = raw_text[i:i + seq_length]
    seq_out = raw_text[i + seq_length]
    dataX.append([char_to_int[char] for char in seq_in])
    dataY.append(char_to_int[seq_out])
n_patterns = len(dataX)
print "Total Patterns: ", n_patterns

# reshape X to be [samples, time steps, features]
X = numpy.reshape(dataX, (n_patterns, seq_length, 1))

搭建網路

  • LSTM(input_shape=(100,1) ,output = 256)
  • DropOut(0.2)
  • Dense(256,vocabNum(大約在50))

編譯之後把最好的weight用該回調函式將在每個epoch後儲存模型到filepath。誤差用的交叉熵,adam優化方法。誤差大約在1.9-2.9之間

模型程式碼

model = Sequential()
model.add(LSTM(256, input_shape=(X.shape[1], X.shape[2])))
model.add(Dropout(0.2))
model.add(Dense(y.shape[1], activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
filepath="weights-improvement-{epoch:02d}-{loss:.4f}.hdf5"
checkpoint = ModelCheckpoint(filepath, monitor='loss', verbose=1, save_best_only=True, mode='min')
callbacks_list = [checkpoint]

model.fit(X, y, nb_epoch=20, batch_size=128, callbacks=callbacks_list)

生成預測文字
首先給一個種子序列作為輸入,可以random隨機給種子。然後把序列轉化為[樣本,時間步長,特徵]形式,這點非常重要!非常重要!非常重要!下面是生成程式碼:

# generate characters
for i in range(1000):
    x = numpy.reshape(pattern, (1, len(pattern), 1))
    x = x / float(n_vocab)
    prediction = model.predict(x, verbose=0)
    index = numpy.argmax(prediction)
    result = int_to_char[index]
    seq_in = [int_to_char[value] for value in pattern]
    sys.stdout.write(result)
    pattern.append(index)
    pattern = pattern[1:len(pattern)]
print "\nDone."

總結一下,LSTM的初次嘗試,一開始在網路輸入上摸不到頭腦,把序列問題當成了一般的分類做了處理,沒有考慮到張量的問題。每個資料都有固定的序列。估計程式還是要跑好久。下面說下問題:

  • 生成的文字學習不到語法
  • 有大量單詞沒有無效單詞
  • 有沒有可能做成中文文字生成
  • 時間效率太低