不用one-hot来表示输入x,是因为想要用word2vec
将每个单词得到vector,将每个vector拼接成一个sequence。[[w1],[w2],[w3]]
用RNN做文本生成
举个小小的例子,来看看LSTM是怎么玩的
我们这里不再用char级别,我们用word级别来做。
第一步,一样,先导入各种库
In [118]:
import os
import numpy as np
import nltk
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import Dropout
from keras.layers import LSTM
from keras.callbacks import ModelCheckpoint
from keras.utils import np_utils
from gensim.models.word2vec import Word2Vec
接下来,我们把文本读入
In [119]:
raw_text = ''
#读入一堆数据。上下文对照是根据句子跟句子之间。需要先分割好句子
for file in os.listdir("../input/"):
if file.endswith(".txt"):
raw_text += open("../input/"+file, errors='ignore').read() + '
'
# raw_text = open('../input/Winston_Churchil.txt').read()
raw_text = raw_text.lower()
sentensor = nltk.data.load('tokenizers/punkt/english.pickle') #分割句子,将原文变为句子的集合
sents = sentensor.tokenize(raw_text)
corpus = []
for sen in sents:
corpus.append(nltk.word_tokenize(sen)) #将句子变为单词的集合
print(len(corpus)) #corpus为二维小数组
print(corpus[:3])
输出结果:
好,w2v乱炖:
In [120]:
w2v_model = Word2Vec(corpus, size=128, window=5, min_count=5, workers=4) #单词的学习利用迁移学习,直接拿一个较好的word2vec模型
#虽然单词学习的模型用的其他语料,但是我们注重的是LSTM中对风格的学习,所以可以采用已经需练好的单词模型
In [121]:
w2v_model['office']
Out[121]:
接下来,其实我们还是以之前的方式来处理我们的training data,把源数据变成一个长长的x,好让LSTM学会predict下一个单词:
In [122]:
raw_input = [item for sublist in corpus for item in sublist] #将二维的corpus平坦化flatten成一个一维数组
len(raw_input)
Out[122]:
In [123]:
raw_input[12]
Out[123]:
In [124]:去掉不在vocabulary中的单词,将在的连接起来
text_stream = []
vocab = w2v_model.vocab
for word in raw_input:
if word in vocab:
text_stream.append(word)
len(text_stream)
Out[124]:
我们这里的文本预测就是,给了前面的单词以后,下一个单词是谁?
比如,hello from the other, 给出 side
构造训练测试集
我们需要把我们的raw text变成可以用来训练的x,y:
x 是前置字母们 y 是后一个字母
In [125]:
seq_length = 10
x = []
y = []
for i in range(0, len(text_stream) - seq_length):
given = text_stream[i:i + seq_length]
predict = text_stream[i + seq_length]
x.append(np.array([w2v_model[word] for word in given]))
y.append(w2v_model[predict])
我们可以看看我们做好的数据集的长相:
In [126]:
print(x[10])
print(y[10])
In [127]:
print(len(x))
print(len(y))
print(len(x[12]))
print(len(x[12][0]))
print(len(y[12]))
In [128]:
x = np.reshape(x, (-1, seq_length, 128))
y = np.reshape(y, (-1,128))
接下来我们做两件事:
-
我们已经有了一个input的数字表达(w2v),我们要把它变成LSTM需要的数组格式: [样本数,时间步伐,特征]
-
第二,对于output,我们直接用128维的输出(自己设定的单词向量的维度)
模型建造
LSTM模型构建
In [129]:
model = Sequential()
model.add(LSTM(256, dropout_W=0.2, dropout_U=0.2, input_shape=(seq_length, 128))) #增加Dropout
model.add(Dropout(0.2))
model.add(Dense(128, activation='sigmoid'))
model.compile(loss='mse', optimizer='adam')
跑模型
In [130]:
model.fit(x, y, nb_epoch=50, batch_size=4096)
Out[130]:
我们来写个测试程序,看看我们训练出来的LSTM的效果:
In [131]:
def predict_next(input_array):
x = np.reshape(input_array, (-1,seq_length,128))
y = model.predict(x)
return y
def string_to_index(raw_input):
raw_input = raw_input.lower()
input_stream = nltk.word_tokenize(raw_input)
res = []
for word in input_stream[(len(input_stream)-seq_length):]:
res.append(w2v_model[word])
return res
def y_to_word(y):
word = w2v_model.most_similar(positive=y, topn=1)
return word
好,写成一个大程序:
In [137]:
def generate_article(init, rounds=30):
in_string = init.lower()
for i in range(rounds):
n = y_to_word(predict_next(string_to_index(in_string)))
in_string += ' ' + n[0][0]
return in_string
In [138]:
init = 'Language Models allow us to measure how likely a sentence is, which is an important for Machine'
article = generate_article(init)
print(article)
In [ ]: