Press "Enter" to skip to content

用于NLP的Python:使用Keras进行深度学习文本生成

原文链接: http://tecdat.cn/?p=8448

 

文本生成是NLP的最新应用程序之一。深度学习技术已用于各种文本生成任务,例如写作诗歌,生成电影脚本甚至创作音乐。但是,在本文中,我们将看到一个非常简单的文本生成示例,其中给定输入的单词字符串,我们将预测下一个单词。我们将使用莎士比亚着名小说《麦克白》的原始文本,并根据给定的一系列输入单词来预测下一个单词。

 

完成本文之后,您将能够使用所选的数据集执行文本生成。所以,让我们开始吧。

 

导入库和数据集

 

第一步是导入执行本文中的脚本所需的库以及数据集。以下代码导入所需的库:

 

importnumpyasnpfromkeras.modelsimportSequential, load_modelfromkeras.layersimportDense, Embedding, LSTM, Dropoutfromkeras.utilsimportto_categoricalfromrandomimportrandintimportre

 

下一步是下载数据集。我们将使用Python的NLTK库下载数据集。

 

importnltk nltk.download('gutenberg')fromnltk.corpusimportgutenbergasgut print(gut.fileids())

 

您应该看到以下输出:

 

['austen-emma.txt', 'austen-persuasion.txt', 'austen-sense.txt', 'bible-kjv.txt', 'blake-poems.txt', 'bryant-stories.txt', 'burgess-busterbrown.txt', 'carroll-alice.txt', 'chesterton-ball.txt', 'chesterton-brown.txt', 'chesterton-thursday.txt', 'edgeworth-parents.txt', 'melville-moby_dick.txt', 'milton-paradise.txt', 'shakespeare-caesar.txt', 'shakespeare-hamlet.txt', 'shakespeare-macbeth.txt', 'whitman-leaves.txt']

 

该文件 shakespeare-macbeth.txt
包含小说“ Macbeth”的原始文本。要从此文件读取文本,可以使用类中的 raw
方法 gutenberg

 

macbeth_text = nltk.corpus.gutenberg.raw('shakespeare-macbeth.txt')

 

让我们从数据集中打印出前500个字符:

 

print(macbeth_text[:500])

 

这是输出:

 

[The TragedieofMacbethbyWilliam Shakespeare1603] Actus Primus. Scoena Prima. ThunderandLightning. Enter three Witches.1.When shall we three meet againe? In Thunder, Lightning,orinRaine?2.When the Hurley-burley's done, When the Battaile's lost,andwonne3.That will be ere the setofSunne1.Where the place?2.Vpon the Heath3.There to meet with Macbeth1.I come, Gray-Malkin All. Padock calls anon: faireisfoule,andfouleisfaire, Houer through

 

您会看到文本包含许多特殊字符和数字。下一步是清理数据集。

 

数据预处理

 

要删除标点符号和特殊字符,我们将定义一个名为的函数 preprocess_text()

 

defpreprocess_text(sen):_# Remove punctuations and numbers_sentence = re.sub('[^a-zA-Z]',' ', sen)_# Single character removal_sentence = re.sub(r"\s+[a-zA-Z]\s+",' ', sentence)_# Removing multiple spaces_sentence = re.sub(r'\s+',' ', sentence)returnsentence.lower()

 

preprocess_text
函数接受文本字符串作为参数,并以小写形式返回干净的文本字符串。

 

现在让我们清理文本,然后再次打印前500个字符:

 

macbeth_text = preprocess_text(macbeth_text) macbeth_text[:500]

 

这是输出:

 

the tragedieofmacbethbywilliam shakespeare actus primus scoena prima thunderandlightning enter three witcheswhenshall we three meet againeinthunder lightningorinrainewhenthe hurley burley donewhenthe battaile lostandwonne that will be ere the setofsunne where the place vpon the heath there to meet with macbeth come gray malkin all padock calls anon faireisfouleandfouleisfaire houer through the foggeandfilthie ayre exeunt scena secunda alarum within enter king malcom

 

将单词转换为数字

 

深度学习模型基于统计算法。因此,为了使用深度学习模型,我们需要将单词转换为数字。

 

在本文中,我们将使用一种非常简单的方法,将单词转换为单个整数。在将单词转换为整数之前,我们需要将文本标记为单个单词。为此,可以使用模块中的 word_tokenize()
方法 nltk.tokenize

 

以下脚本标记我们数据集中的文本,然后打印数据集中的单词总数以及数据集中的唯一单词总数:

 

fromnltk.tokenizeimportword_tokenize macbeth_text_words = (word_tokenize(macbeth_text)) n_words = len(macbeth_text_words) unique_words = len(set(macbeth_text_words)) print('Total Words: %d'% n_words) print('Unique Words: %d'% unique_words)

 

输出这样:

 

TotalWords: 17250UniqueWords: 3436

 

我们的文字总共有17250个单词,其中3436个单词是唯一的。要将标记化的单词转换为数字,可以使用模块中的 Tokenizer
keras.preprocessing.text
。您需要调用该 fit_on_texts
方法并将其传递给单词列表。将创建一个字典,其中的键将代表单词,而整数将代表字典的相应值。

 

看下面的脚本:

 

fromkeras.preprocessing.textimportTokenizer tokenizer = Tokenizer(num_words=3437) tokenizer.fit_on_texts(macbeth_text_words)

 

要访问包含单词及其相应索引的字典, word_index
可以使用tokenizer对象的属性:

 

vocab_size = len(tokenizer.word_index) +1word_2_index = tokenizer.word_index

 

如果您检查字典的长度,它将包含3436个单词,这是我们数据集中唯一单词的总数。

 

现在让我们从 word_2_index
字典中打印第500个唯一单词及其整数值。

 

print(macbeth_text_words[500]) print(word_2_index[macbeth_text_words[500]])

 

这是输出:

 

comparisons1456

 

修改数据形状

 

LSTM接受3维格式的数据(样本数,时间步数,每个时间步的特征)。由于输出将是单个单词,因此输出的形状将是二维的(样本数,语料库中唯一词的数量)。

 

以下脚本修改了输入序列和相应输出的形状。

 

input_sequence = [] output_words = [] input_seq_length =100foriinrange(0, n_words - input_seq_length ,1): in_seq = macbeth_text_words[i:i + input_seq_length] out_seq = macbeth_text_words[i + input_seq_length] input_sequence.append([word_2_index[word]forwordinin_seq]) output_words.append(word_2_index[out_seq])

 

在上面的脚本中,我们声明两个空列表 input_sequence
output_words
。将 input_seq_length
被设置为100,这意味着我们的输入序列将包括100个字。接下来,我们执行一个循环,在第一次迭代中,将文本中前100个单词的整数值附加到 input_sequence
列表中。第101个单词将追加到 output_words
列表中。在第二次迭代过程中,从文本中的第二个单词开始到第101个单词结束的单词序列存储在 input_sequence
列表中,第102个单词存储在 output_words
数组中,依此类推。由于数据集中共有17250个单词(比单词总数少100个),因此将总共生成17150个输入序列。

 

现在让我们输出 input_sequence
列表中第一个序列的值:

 

print(input_sequence[0])

 

输出:

 

[1,869,4,40,60,1358,1359,408,1360,1361,409,265,2,870,31,190,291,76,36,30,190,327,128,8,265,870,83,8,1362,76,1,1363,1364,86,76,1,1365,354,2,871,5,34,14,168,1,292,4,649,77,1,220,41,1,872,53,3,327,12,40,52,1366,1367,25,1368,873,328,355,9,410,2,410,9,355,1369,356,1,1370,2,874,169,103,127,411,357,149,31,51,1371,329,107,12,358,412,875,1372,51,20,170,92,9]

 

让我们通过将序列中的整数除以最大整数值来归一化输入序列。以下脚本还将输出转换为二维格式。

 

X = np.reshape(input_sequence, (len(input_sequence), input_seq_length,1)) X = X / float(vocab_size) y = to_categorical(output_words)

 

以下脚本打印输入和相应输出的形状。

 

print("X shape:", X.shape) print("y shape:", y.shape)

 

输出:

 

Xshape: (17150, 100, 1)yshape: (17150, 3437)

 

训练模型

 

下一步是训练我们的模型。关于应使用多少层和神经元来训练模型,没有硬性规定。

 

我们将创建三个LSTM层,每个层具有800个神经元。最终将添加具有1个神经元的密集层,以预测下一个单词的索引,如下所示:

 

model = Sequential() model.add(LSTM(800, input_shape=(X.shape[1], X.shape[2]), return_sequences=True)) model.add(LSTM(800, return_sequences=True)) model.add(LSTM(800)) model.add(Dense(y.shape[1], activation='softmax')) model.summary() model.compile(loss='categorical_crossentropy', optimizer='adam')

 

由于输出单词可以是3436个唯一单词之一,因此我们的问题是多类分类问题,因此使用 categorical_crossentropy
损失函数。如果是二进制分类, binary_crossentropy
则使用该函数。一旦执行了上面的脚本,可以看到模型摘要:

 

Model: "sequential_1"**_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____**Layer (type) Output Shape Param # =================================================================lstm_1 (LSTM) (None, 100, 800) 2566400**_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____**lstm_2 (LSTM) (None, 100, 800) 5123200**_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____**lstm_3 (LSTM) (None, 800) 5123200**_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____****_____**dense_1 (Dense) (None, 3437) 2753037 =================================================================Total params: 15,565,837 Trainable params: 15,565,837 Non-trainable params: 0

 

要训练模型,我们可以简单地使用该 fit()
方法。

 

model.fit(X, y, batch_size=64, epochs=10, verbose=1)

 

做出预测

 

为了进行预测,我们将从 input_sequence
列表中随机选择一个序列,将其转换为3维形状,然后将其传递给 predict()
训练模型的方法。然后将索引值传递到 index_2_word
字典,在字典中将单词index用作键。该 index_2_word
字典将返回属于被作为重点字典传入的索引词。

 

以下脚本随机选择一个整数序列,然后输出相应的单词序列:

 

random_seq_index = np.random.randint(0, len(input_sequence)-1) random_seq = input_sequence[random_seq_index] index_2_word = dict(map(reversed, word_2_index.items())) word_sequence = [index_2_word[value]forvalueinrandom_seq] print(' '.join(word_sequence))

 

对于本文中的脚本,以下顺序是随机选择的:

 

amenwhenthey did say god blesse vs lady consider itnotso deepely mac but wherefore couldnotpronounce amen had most needofblessingandamen stuckinmy throat lady these deeds mustnotbe thought after these wayes so it will make vs mad macb me thought heard voyce cry sleepnomore macbeth does murther sleepe the innocent sleepe sleepe that knits vp the rauel sleeueofcare the deathofeach dayes life sore labors bath balmeofhurt mindes great natures second course chiefe nourisherinlife feast lady what doe you meane

 

接下来,我们将按照上述单词顺序输出接下来的100个单词:

 

foriinrange(100): int_sample = np.reshape(random_seq, (1, len(random_seq),1)) int_sample = int_sample / float(vocab_size) predicted_word_index = model.predict(int_sample, verbose=0) predicted_word_id = np.argmax(predicted_word_index) seq_in = [index_2_word[index]forindexinrandom_seq] word_sequence.append(index_2_word[ predicted_word_id]) random_seq.append(predicted_word_id) random_seq = random_seq[1:len(random_seq)]

 

word_sequence
现在,变量包含我们输入的单词序列以及接下来的100个预测单词。该 word_sequence
变量包含列表形式的单词序列。我们可以简单地将列表中的单词连接起来以获得最终的输出序列,如下所示:

 

final_output =""forwordinword_sequence: final_output = final_output +" "+ word print(final_output)

 

这是最终输出:

 

amenwhenthey did say god blesse vs lady consider itnotso deepely mac but wherefore couldnotpronounce amen had most needofblessingandamen stuckinmy throat lady these deeds mustnotbe thought after these wayes so it will make vs mad macb me thought heard voyce cry sleepnomore macbeth does murther sleepe the innocent sleepe sleepe that knits vp the rauel sleeueofcare the deathofeach dayes life sore labors bath balmeofhurt mindes great natures second course chiefe nourisherinlife feast lady what doe you meaneandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandandand

 

结论

 

在本文中,我们看到了如何通过Python的Keras库使用深度学习来创建文本生成模型。

Be First to Comment

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注