vb6 怎么把一个数组的 0 值 去掉_机器学习带你横扫乐坛,你就是下一个方文山...

a3d8dd0385125f24f4968ecd0b5771d4.png
全文共3369字,预计学习时长9分钟

b3dce18acf33010dde3c53090dc5a762.png
图源:unsplash

我太爱北极猴子乐队了,但他们已经很久没有发行新单曲了。久久欠缺精神食粮的我某天晚上突然灵机一动,我可以自给自足呀!于是我写了个简单的代码,用Keras和TensorFlow训练了一个文本生成模型,写出一首全新的北极猴子的歌。

不过条件有限,这玩意儿无法跟真正的北极猴子的歌曲相提并论,但安慰一下长期缺新歌的自己还是可以的。

本文将简单介绍这个代码,完整的代码放在笔者的GitHub上:https://github.com/Rajwrita/Sequence-Models-for-Literature/blob/master/NLP-AM2.0.ipynb。

首先,你得建立一个几乎将全部北极猴子的歌曲包括在内的数据集(https://github.com/Rajwrita/Sequence-Models-for-Literature/blob/master/AM.txt),之后如果继续执行此代码,请尝试使用自己的数据集生成文本。

导入

首先要为深度学习模型导入通用的数据帧操作库以及TensorFlow和Keras库包:

import numpy as np
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout,Bidirectional
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.models import Sequential
from tensorflow.keras.optimizers import Adam
from tensorflow.keras import regularizers
import tensorflow.keras.utils as ku

接着,导入数据:

data = open('AM.txt').read()

再给文本装上一个分词器(tokenizer)。分词器可以生成覆盖整个语料库的单词词典,实质上就是键值对。键是单词,而值则是为该单词生成的标记。简言之,分词器将成句的字符串分解为独立的单词,然后赋予每个单词一个唯一整数值。这一步很关键,为后续嵌入层数据的准备打下基础。

获取单词索引的长度,可以得出语料库里单词的总量。在此基础上加1,就可以引入外部词汇。相应的代码如下:

tokenizer = Tokenizer()data = open('AM.txt').read()
tokenizer.fit_on_texts(corpus)
total_words = len(tokenizer.word_index) + 1

再然后,使用token列表创建导入序列。导入序列说白了就是一个python列表,文本语料库的每一行都通过分词器生成一个token列表。是像这样的一行文本:

92cfa5ff39c23cdc511bbf03b26307f4.png

通过这道程序,就会将其转化为代表这些单词的一串token。数据集的每一行都会这样处理。其代码如下:

input_sequences = []
for line in corpus:
   token_list =tokenizer.texts_to_sequences([line])[0]
   for i in range(1, len(token_list)):
      n_gram_sequence = token_list[:i+1]
      input_sequences.append(n_gram_sequence)

可以看出,导入序列只是被分解为短语的句子,紧接着要获取语料库中最长句子的长度。这一步很简单,只需要将所有句子遍历循环并找出最长那句即可。

max_sequence_len = max([len(x) for x in input_sequences])

现在填充所有序列使它们全部一样长。用零预填充序列,这样更容易提取到标签值,只要抓取最后一个标记就可以得到标签值了。

input_sequences = np.array(pad_sequences(input_sequences,maxlen=max_sequence_len, padding='pre'))

填充之后,创建预测值和标签值,这样序列基本上就被分解为x数组和y数组了。这里用到的是python的切片属性。代码如下:

predictors, label = input_sequences[:,:-1],input_sequences[:,-1]

现在,数据已经分为x数组和y数组,可以开始创建神经网络,对给定词组进行分类预测了。

从嵌入层开始

嵌入层是任何一种理解单词的深度学习模型不可或缺的一层,其实际作用是通过赋予同样含义词汇以同样数值,将较高维空间的向量投影到较低维空间,这样就可以直接对向量进行数学运算了。

在一行文本中,它处理了所有词汇并且赋予其在神经网络中的含义。第一个参数处理的是单词,第二个参数则是绘制单词矢量的维数,最后一个参数是输入维度的尺寸,其实就是最长序列的长度减1。减掉1是因为前面为了得到标签值,我们将每个序列的最后一个词砍掉了,所以得到的序列比最大序列长度要小1。

model.add(Embedding(total_words, 100, input_length=max_sequence_len-1))

添加LSTM(长短期记忆网络)层

8a95f43efbd0b732f51c678919478716.png
图源:unsplash

LSTM层的细胞状态保存了整个上下文语境,从而保证了对下一个词汇产生影响的不止有相邻词汇。

除了单层的LSTM层,还可以使用堆叠多层的LSTM。使用双向LSTM层,我们可以从头到尾再从尾到头将原始数据导入学习算法中,这有助于神经网络更好地理解文本。双向LSTM还可以帮助神经网络更快收敛。

将返还序列标注设为True,这样就能将序列信息传递到第二层LSTM层,而不是直接到最终状态。

model.add(Bidirectional(LSTM(150, return_sequences = True)))

接下来,运用密集层进一步捕获线性关系,以上各层的输出将转化为单词概率。softmax激活函数会将所有输入单词概率从(-∞,∞ ) 转化为(0,1)。

model.add(Dense(total_words/2, activation='relu', kernel_regularizer=regularizers.l2(0.01)))model.add(Dense(total_words,activation='softmax'))

由于这里做的是categorical分类,所以要将定律设为分类交叉熵。至于优化器,这里选用adam优化器。

最后一步——Epochs

最后要花一点时间训练模型,数据集的数据不多,大概要训练模型500个epoch左右。

history = model.fit(predictors, label, epochs=100, verbose=1)

要预测的单词越多,产生的乱码也会越多,因为每一个单词都要预测,其下一个和下下个单词也是,那么下一个单词永远比上一个有更多不确定性。来看看网络最后预测出来的文本!

seed_text = "I really like the Arctic Monkeys and

ddaa8b6dbe31171b98113fcbf3ebce88.png

建立覆盖足够单词的语料库,神经网络就可以在语料库上训练,并通过预测下一个单词,帮助我们预测一些复杂文本。

有了机器学习,产粮不再是难事,试试用这个代码为你的心水歌手写一首歌吧!

ae9ee9eb4d8a34554cd2b4435f7623b3.png

留言点赞关注

我们一起分享AI学习与发展的干货

编译组:黄壹格、吴子珺

相关链接:https://medium.com/@rajwrita/using-text-generation-to-get-the-lyrics-for-the-next-arctic-monkey-song-f7c93a882c6f

如转载,请私信小芯,遵守转载规范