太喜欢北极猴了,但他们好久没发新单了。长期缺乏精神食粮,一天晚上突然灵机一动,我可以自给自足!于是我写了一段简单的代码,用Keras和TensorFlow训练了一个文本生成模型,写了一首全新的ArcticMonkeys歌曲。不过条件有限,这东西比不上真正的北极猴的歌,不过安慰一下缺了好久的新歌的自己也无妨。本文将简单介绍这段代码,完整代码放在作者的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库包:importnumpyasnpfromtensorflow.keras.preprocessing.sequenceimportpad_sequencesfromtensorflowTM,simpenseport.outEkeras.,Bidirectionalfromtensorflow.keras.preprocessing.textimportTokenizerfromtensorflow.keras.modelsimportSequentialfromtensorflow.keras.optimizersimportAdamfromtensorflow.kerasimportregularizersimporttensorflow.keras.utilsasku接下来,导入数据:data=open('AM.txt').read()并在文本上安装分词器。分词器生成涵盖整个语料库的单词字典,本质上是键值对。键是单词,值是为该单词生成的标记。简而言之,分词器将句子字符串分解为单个单词,并为每个单词分配一个唯一的整数值。这一步很关键,为后续嵌入层数据的准备打下基础。得到单词索引的长度,就可以得到语料库中的单词总数。在此基础上加1,就可以引入外部词汇。对应代码如下:tokenizer=Tokenizer()data=open('AM.txt').read()tokenizer.fit_on_texts(corpus)total_words=len(tokenizer.word_index)+1然后,使用token列表创建导入顺序。说白了,导入序列就是一个python列表,文本语料的每一行通过tokenizer生成一个token列表。它是这样一行文字:通过这个过程,它会被转换成一串代表这些词的token。数据集的每一行都将这样处理。代码如下:input_sequences=[]forlineincorpus:token_list=tokenizer.texts_to_sequences([line])[0]foriinrange(1,len(token_list)):n_gram_sequence=token_list[:i+1]input_sequences.append(n_gram_sequence)可以看出导入序列其实就是把句子分解成词组,然后得到语料库中最长句子的长度。这一步很简单,只需要遍历所有句子,找到最长的句子即可。max_sequence_len=max([len(x)forxininput_sequences])现在填充所有序列,使它们的长度都相同。用零预填充序列,以便更容易提取标签值,只需抓住最后一个标记即可获取标签值。input_sequences=np.array(pad_sequences(input_sequences,maxlen=max_sequence_len,padding='pre'))填充后创建预测值和标签值,这样序列基本分解为x数组和y数组。这里用到的是python的slice属性。代码如下: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(长短期记忆网络)层图片来源:unsplashLSTM层的cellstate保存了整个上下文,从而保证了影响在下一个词汇上比相邻的词多。除了单层LSTM层外,还可以使用堆叠的多层LSTM。使用双向LSTM层,我们可以将原始数据从开始到结束再回到开始,将原始数据输入到学习算法中,这有助于神经网络更好地理解文本。双向LSTM还可以帮助神经网络更快地收敛。将返回序列标签设置为True,以便将序列信息传递到第二个LSTM层,而不是直接传递到最终状态。model.add(Bidirectional(LSTM(150,return_sequences=True)))接下来使用dense层进一步捕捉线性关系,将以上层的输出转化为词概率。softmax激活函数会将所有输入词概率从(-∞,∞)转换为(0,1)。model.add(Dense(total_words/2,activation='relu',kernel_regularizer=regularizers.l2(0.01)))model.add(Dense(total_words,activation='softmax'))由于这里做的是分类分类,所以将定律设置为分类交叉熵。至于优化器,这里使用了adam优化器。最后一步——Epochs最后,训练模型需要一点时间。数据集中数据不多,训练模型需要500个epoch左右。history=model.fit(predictors,label,epochs=100,verbose=1)预测的词越多,产生的乱码就越多,因为每个词都要预测,而且下一个和下一个词也是,那么下一个词总是比前一个词更不确定。让我们来看看网络预测的最终文本吧!seed_text="我很喜欢北极猴子,建立一个覆盖足够单词的语料库,可以在语料库上训练神经网络,通过预测下一个单词来帮助我们预测一些复杂的文本。有了机器学习,生产食物不再是难事,尝试使用此代码为您最喜欢的歌手写歌!
