抓取网页生成电子书( AI社区搭建出所谓语言模型的前提是学习数据的原因)
优采云 发布时间: 2022-04-20 10:27抓取网页生成电子书(
AI社区搭建出所谓语言模型的前提是学习数据的原因)
由大数据文摘出品
合辑:非、倪妮、什锦甜、钱天培
人工智能未来的一个主要应用将是构建可以从数据中学习然后生成原创内容的网络。这个思想已经在自然语言处理(NLP)领域得到了充分的应用,这也是为什么AI社区可以构建所谓的语言模型:语言模型的前提是学习文章@中的句子结构> 段落,从而生成新的内容。
在这个文章@>我想尝试生成类似于非常流行的加拿大说唱歌手德雷克(又名#6god)风格的说唱歌词,一定很有趣。
另外,我也想分享一下通用的机器学习项目流水线,因为我发现很多同学想做一些小项目,但是不知道从哪里开始。
获取数据
首先,我们开始采集 Drake 的音乐库。为了节省时间,我写了一个爬虫来抓取网络上的歌词。
import urllib.request as urllib2
from bs4 import BeautifulSoup
import pandas as pd
import re
from unidecode import unidecode
quote_page = 'http://metrolyrics.com/{}-lyrics-drake.html'
filename = 'drake-songs.csv'
songs = pd.read_csv(filename)
for index, row in songs.iterrows():
page = urllib2.urlopen(quote_page.format(row['song']))
soup = BeautifulSoup(page, 'html.parser')
verses = soup.find_all('p', attrs={'class': 'verse'})
lyrics = ''
for verse in verses:
text = verse.text.strip()
text = re.sub(r"\[.*\]\n", "", unidecode(text))
if lyrics == '':
lyrics = lyrics + text.replace('\n', '|-|')
else:
lyrics = lyrics + '|-|' + text.replace('\n', '|-|')
songs.at[index, 'lyrics'] = lyrics
print('saving {}'.format(row['song']))
songs.head()
print('writing to .csv')
songs.to_csv(filename, sep=',', encoding='utf-8')
我使用了一个著名的 Python 包 BeautifulSoup 来抓取网页。我使用了 Justin Yek 的教程,一个很棒的人,在五分钟内学会了如何使用它。说明一下,在上面的代码中,我在循环中使用了歌曲的数据格式,因为我提前定义了我想要获取的歌曲。
教程:
所有歌词都存储在DataFrame中
运行爬虫后,我得到了一个csv文件,将歌词存储在一个合适的结构中,接下来就是对数据进行预处理并构建模型。
型号介绍
现在让我们看看模型是如何生成文本的。这部分理解很重要,因为这是真正的干货。我将从模型设计和生成歌词模型中的关键组件开始,然后我们可以直接进入实现阶段。
构建语言模型主要有两种方式:
1.字符级模型,
2.词级模型。
两者的主要区别在于模型的输入和输出。接下来,我将解释这两个模型是如何工作的。
字符级模型
在字符级模型中,输入是一个字符序列*敏*感*词*(seed),模型负责预测下一个字符,然后使用*敏*感*词*+new_char组合生成下一个字符,以此类推。请注意,由于我们应该保持每个输入的长度相同,我们实际上是在输入的每次迭代中删除一个字符。我们可以看一个简单直观的例子:
字符级模型生成单词的迭代过程
在每次迭代中,模型根据给定的*敏*感*词*字符预测下一个最有可能生成的字符,或者使用条件概率找到概率 P(new_char|seed) 的最大值,其中 new_char 是一个字母表。
在这个例子中,字符表是指所有英文字母和空格的集合。 (注意,字母表可以收录不同的字母,具体取决于您的需要,主要取决于您生成的语言类型)。
词法模型
词汇级别模型与字符级别模型非常相似,但它用于生成下一个单词而不是一个字符。这是一个简单的例子来说明这一点:
图3.词汇级模型生成的迭代过程
现在在这个模型中,我们期待以单词为单位的下一个单词,而不是字符。因此,我们要找到概率 P(new_word|seed) 的最大值,其中 new_word 是任意词。
这里需要注意的是,我们在比字符级别更大的范围内进行搜索。在字符集模型中,我们只需要从字符表中查找大约 30 个字符,但是每次迭代搜索在词汇表级别的范围远大于这个数字,所以每次迭代运行速度较慢,但是由于我们生成了一个整体单词而不是一个字符,所以也不错。
关于词汇级别模型的最后一点是,我们可以通过在数据集中搜索独特词汇来生成更多样化的词汇(此步骤通常在数据预处理阶段完成)。由于词汇量可以无限大,我们其实有很多算法来提高词汇生成的性能,比如词嵌入,不过我可以在这个问题上再写一个文章@>。
本文文章@>主要关注字符级模型,因为它更容易实现和理解,也更容易转化为复杂的词法级模型。
数据预处理
对于字符级模型,我们将进行如下数据预处理:
1.标记字符
对于字符级模型,输入应该基于字符而不是字符串。所以,我们先把每一行歌词变成一个字符的集合。
2。定义字符表
在上一步中,我们得到了歌词中所有可能的字符,现在我们需要找到所有唯一的字符。由于整个数据集不大(只有140首歌曲),为简单起见,我只保留所有英文字母和一些特殊符号(如空格),而忽略数字等信息(因为数据集很小,我宁愿让模型预测更少的字符)。
3.创建训练序列
这里我们将使用滑动窗口的概念。通过沿着句子拖动一个固定长度的窗口,我们将构建用于训练的数据序列。下图是滑动窗口操作的一个很好的例子:
图4.使用滑动窗口获取输入/输出
通过一次翻译一个字符,我们得到一个长度为 20 个字符的模型输入和一个长度为 1 个字符的模型输出。一次只转换一个网格的另一个好处是它极大地扩展了数据集的大小。
4.带注释的编码训练序列
最后,我们不想直接处理原创字符(虽然理论上每个字符都是一个数字,所以你也可以说 ASCII 已经为我们完成了每个字符的编码)。我们要做的就是用一个唯一的数字与每个字符一一对应,这一步就是所谓的标签编码。同时,我们要建立两个非常重要的映射:character-to-index(字符到索引)和index-to-character(索引到字符)。通过这两个映射,我们可以将字母表中的任意一个字符编码成对应的数字,同样的,我们也可以解码模型输出的数字索引,得到对应的字符。
5.数据集的one-hot编码
因为我们使用的是分类数据,也就是说所有的字符都可以归为某一类,所以我们会将字符编码成输入列的形式。
当我们完成以上五个步骤后,我们就基本完成了,接下来我们只需要构建和训练模型即可。如果您想深入了解更多细节,这里是五个步骤的代码供参考。
3.建立模型
我们将使用循环神经网络 (RNN),更具体地说是长短期记忆 (LSTM) 网络,根据先前呈现的字符集预测下一个字符。如果这两个概念听起来不熟悉,我还提供了相关概念的快速复习:
RNN 快速回顾
通常,您看到的网络是一个网格,从许多点汇聚到一个输出。如下图:
图5.神经网络图
这里的神经网络是单点输入和单点输出。它适用于输入不连续的情况,因为输入的顺序不影响输出。但是在我们的例子中,输入字符的顺序很重要,因为顺序决定了对应的单词。
RNN可以接收连续输入,将前一个节点的输出作为参数输入到下一个节点,从而解决输入顺序问题。
图6.简单的RNN*敏*感*词*
例如,基于序列 Tryna_keep_it_simple,提取的下一个字符应该是_。这正是我们希望我们的神经网络做的事情。神经网络的输入会是 T — > x, r -> x, n -> x... e-> x ,对应的输出字符是空格 y -> _ 。
LSTM 快速回顾
简单的 RNN 网络仍然存在一些问题,它不擅长将非常前端的单元格信息传递给后端单元格。例如,Tryna keep it simple 句子中的最后一个词 me 对我来说是一个挣扎,如果不回顾它之前出现的词(可能预测为 Baka、cat、potato 等),很难预测。
LSTM 可以很好地解决这个问题,它在每个单元格中存储了部分之前的事件信息(即之前的单词)。如下图:
图7. LSTM 图,取自 Andrew Ng 的深度学习课程
不仅传递了前一个单元格的输出a,而且收录前一个单元格的输入信息的c也作为下一个单元格的输入的一部分。这使 LSTM 能够更好地保留上下文信息,并且适用于语言建模预测。
编程建模
之前学过一点Keras,所以这次会用Keras作为框架来编程搭建模型。其实也可以选择自己搭建模型框架,不过这样会比较费时间。
# create sequential network, because we are passing activations
# down the network
model = Sequential()
# add LSTM layer
model.add(LSTM(128, input_shape=(maxlen, len(chars))))
# add Softmax layer to output one character
model.add(Dense(len(chars)))
model.add(Activation('softmax'))
# compile the model and pick the loss and optimizer
model.compile(loss='categorical_crossentropy', optimizer=RMSprop(lr=0.01))
# train the model
model.fit(x, y, batch_size=128, epochs=30)
从上图可以看出,我们构建了LSTM模型,使用了批处理,使用数据子集进行批量训练,而不是一次性输入所有数据,这样可以稍微提高训练速度。
4、生成歌词
训练完模型,我们来介绍下如何生成下一个字符。我们首先使用用户输入的简单字符串作为随机*敏*感*词*。接下来,我们使用*敏*感*词*作为网络的输入来预测下一个字符,并重复这个过程,直到我们生成一些新的歌词,类似于图 2 所示的歌词。
以下是生成歌词的一些示例。
注意:这些歌词均未经过审核,请在阅读时自行检查。
您可能会注意到某些生成的单词是无意义的,这是字符级模型的常见问题。这是因为输入序列经常在单词中间被截断,从而使神经网络模型能够学习并生成对其输入有意义但对我们来说看起来很奇怪的新单词。
这也是词法级模型可以解决的问题,但是对于仅用200行代码构建的模型,字符级模型达到的效果还是很可观的。
其他应用
此处演示的字符级模型的歌词预测功能可以扩展到其他更有用的应用程序。
例如,可以使用相同的原理来预测 iPhone 键盘上要输入的下一个单词。
图8.键盘输入预测下一个单词
想象一下,如果你构建一个高精度的 Python 语言模型,它不仅可以自动填写 关键词 或变量名,还可以填写大段代码,这将帮助程序员节省大量时间!
您可能还注意到文本中的代码不完整,并且缺少一些片段。请到我的 Github 了解更多详情并学习构建自己的项目模型。
Github 链接:
相关报道: