使用语言模型和LSTM生成歌词

未来人工智能应用程序的主要是构建能够从一些数据集学习并生成原始内容的网络。这个想法已被应用于自然语言处理(NLP),这就是AI社区如何开发一种称为语言模型的东西。

语言模型的前提是要学习如何在某些文本中构建句子并生成原始内容的网络。

在本文中,想尝试使用饶舌作为一个有趣的项目,看看是否可以重新制作流行的加拿大说唱歌手Drake的歌词。

同时,也想分享一个通用的机器学习项目管道,因为如果你不知道从哪里开始,那么构建你自己的东西往往是非常困难的。

1.获取数据

这一切都始于寻找所有Drake歌曲的数据集,基于时间的问题,所以这里构建了一个快速脚本,把名为metrolyrics.com的流行网站的网页挖出来。

这儿用了一个众所周知的Python包抓取出页面,这是在大约5分钟内从Justin Yek的精彩教程中摘录的。作为一个说明,实际上预先定义了想要获得的歌曲,实际上是预先定义了想要获取的歌曲,这就是为什么您可能会注意到在上面的代码中遍历歌曲dataframe。

DataFrame存储所有歌曲的歌词

在运行scraper之后,将所有歌词都格式化为.csv文件,并准备开始预处理数据并构建模型。

关于模型

现在,我们将谈论文本生成的模型,这是真正的原料部分。我将首先讨论模型设计和一些使抒情生成成为可能的重要元素,然后我们将着手实施它。

建立语言模型主要有两种方法:(1)字符级模型和(2)字级模型。

每个模型的主要区别来自您的输入和输出,我将详细讨论它们各自如何在这里工作。

字符级模型

在字符级模型的情况下,您的输入是一系列字符seed,您的模型负责预测下一个字符new_char。然后把seed + new_char一起使用来产生下一个字符等等。请注意,由于您的网络输入必须始终具有相同的形状,因此我们实际上将在此过程的每次迭代中丢失一个字符。这是一个简单的可视化图片:

图2用字符级语言模型生成字的迭代过程

在每一次迭代中,模型基本上都是预测给定字符的下一个最可能的字符是什么,或者使用条件概率,这可以描述为找到最大值P(new_char|seed),new_char字母表中的任何字符在哪里。在我们的例子中,字母表是一组所有英文字母和一个空格字符(注意,您的字母表可以非常不同,并且可以包含您想要的任何字符,这取决于您正在构建的模型。

字级模型

字级模型几乎与字符一样,但它会生成下一个字,而不是下一个字符。这里有一个简单的例子:

图3用字符级语言模型生成词的迭代过程

现在,在这个模型中,我们正在向前看一个单位,但这次我们的单位是一个单词,而不是一个字符。所以,我们正在寻找P(new_word|seed),其中,new_word词汇中的词语。

请注意,现在我们正在搜索比以前更大的集合。使用字母表时,我们搜索了大约30个项目,现在我们在每次迭代中都搜索更多项目,因此单词级别算法在每次迭代中都比较慢,但由于我们生成的是整个单词而不是单个字符,因此它其实并没有那么糟糕。作为我们的字符级模型的最后一个注记,我们可以有一个非常多样化的词汇表,我们通常通过从数据集中找到独特的单词(通常在数据预处理阶段完成)来开发它。由于词汇表可以变得无限大,因此有许多技术可以提高算法的效率,例如词嵌入,这是为了以后的文章。

出于本文的目的,将重点介绍字符级模型,因为它的实现更简单,并且对字符级模型的理解可以稍后轻松转移到更复杂的字级模型。

2.数据预处理

对于字符级模型,我们将不得不按照以下方式预处理数据:

标记数据集 - 当我们将输入馈送到模型中时,我们不想只用字符串进行输入,我们想要用字符来代替,因为这是一个字符级模型。所以我们将把所有歌词分成一个字符列表。

定义字母表- 现在,我们知道可能出现在歌词中的每一种字符(来自之前的标记化步骤),我们希望找到所有的独特字符。为了简单起见,整个数据集并没有那么大(只使用了140首歌曲),这里将坚持使用英文字母和一些特殊字符(比如空格),并且会忽略所有数字和其他东西(由于数据集很小,宁愿让模型预测更少的字符)。

创建训练序列 - 我们将使用滑动窗口的概念,并通过在句子上滑动固定大小的窗口来创建一组训练示例。这是一个很好的可视化方式:

图4输入/输出生成的数据集上的滑动窗口

通过一次移动一个字符,我们可以生成长度为20个字符的输入和一个输出字符。此外,作为奖励,由于我们一次只移动一个角色,实际上我们正在显著扩大数据集的大小。

4.标签编码训练序列 -最后,因为我们不希望模型使用原始字符(尽管理论上可能是这样,因为字符在技术上只是一个数字,所以你几乎可以说ASCII编码了所有字符为了我们)。我们将把一个唯一的整数与我们字母表中的每个字符关联起来,这可能是您听说过的标签编码。这也是时候我们创建了两个非常重要的映射character-to-index和index-to-character。通过这两种映射,我们可以将任何字符编码为唯一的整数,并将模型的输出从索引解码为其原始字符。

5.单热编码数据集 - 由于我们正在处理分类数据,所有字符都属于某种类别,所以我们将不得不编码输入列。下面是关于单热编码实际上由Rakshith Vasudev写的一个很好的描述。

一旦我们完成了这五个步骤,我们已经完成了很多工作,现在我们所要做的就是构建模型并进行训练。如果您想深入了解细节,以下是前五个步骤的代码。

3.建立模型

为了使用一组以前的字符来预测下一个字符,我们将要使用递归神经网络(RNN)或专门的长期短期记忆网络(LSTM)。如果你对这两个概念都不熟悉,我建议你阅读它们。RNNs通过Pranoy拉达克里希和LSMTs通过Eugine康。如果你只是需要一个复习或感觉勇敢,这里是快速破败:

RNN

通常情况下,您会看到网络看起来像网络,并从多个节点汇聚到单个输出。像这样的东西:

图5神经网络的图像

这里我们有一个输入点和一个输出点。这对于输入不连续的输入非常有用,输入顺序不会影响输出。但在我们的例子中,字符顺序实际上非常重要,因为字符的具体顺序是创建独特单词的顺序。

RNN通过创建一个接受连续输入的网络来解决这个问题,并且使用前一个节点的激活作为下一个节点的参数。

图6简单RNN的概述

记住我们的一个序列的情况,Tryna_keep_it_simple我们提取后面的下一个字符应该是_。这正是我们希望我们的网络所做的。我们要输入每个字符进入的字符序列,T — > s, r -> x, n -> x... e-> x网络预测输出y -> _,这是我们的下一个字符。

LSTM

简单的RNN对他们来说有一个问题,他们不擅长将信息从非常早的细胞传递到后面的细胞。例如,如果您正在查看Tryna keep it simple is a struggle for me预测最后一个单词me(可能是字面上任何人或任何类似于:猫,土豆)的句子,如果您无法回顾并查看之前出现的其他单词,则非常困难。

LSTM通过给每个单元添加一点内存来解决这个问题,该单元存储了一些关于之前发生的事情的信息(以前出现过的单词),这就是为什么LSTM看起来像这样:

图7 LSTM可视化,取自Andrew Ng的深度学习专门化

除了传递a激活之外,还传递了c包含之前节点中发生的事件的信息。这就是为什么LSTM更好地保留上下文,并且通常可以为语言建模等目的做出更好的预测。

实际建设

这里用Keras作为构建网络的框架,但事实上,这可以通过手工完成,唯一的区别是它需要更长的时间。

正如您所看到的,我们正在使用LSTM模型,并且我们也在使用批处理,这意味着我们一次性对数据子集进行训练,而不是一次性加快训练过程。

4.生成歌词

在我们的网络训练完成之后,我们将如何寻找下一个角色。我们将得到一些随机种子,这将是一个由用户输入的简单字符串。然后我们将使用种子作为网络的输入来预测下一个字符,我们将重复这个过程,直到我们产生了一串新的行,类似于上面显示的图2。

以下是生成的歌词的一些例子

注意:歌词没有被审查,所以请自行判断

您可能已经注意到,单词有时是没有意义的,这是字符级模型的一个非常常见的问题,这是由于输入数据通常在单词中间切片,这会使网络学习并生成奇怪的新单词。

这是用字级模型解决的问题,但对于少于200行的代码,字符级模型仍然非常令人印象深刻。

其他应用

在这个字符级网络中描述的想法可以扩展到比歌词生成更有用的许多其他应用程序。

例如,这与iPhone键盘上的下一个!单词建议的工作方式是相同的。

键盘下一个单词预测

想象一下,如果您构建了足够准确的Python语言模型,则不仅可以自动完成关键字或变量名称,还可以自动完成大量代码,从而为程序员节省大量时间。

您可能已经注意到代码有缺失的部分,这是github的地址:

https://github.com/keras-team/keras/blob/master/examples/lstm_text_generation.py

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180410G1LQL300?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券