说明

这是一个个人练习笔记,使用Python语言,Keras搭建神经网络
数据使用的是王力宏的歌词,包含91首歌,共2列属性:歌曲名(Title),歌词(Lyrics)(来源:网易云音乐)

导入各种包

import re
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from keras.layers import Dense, LSTM
from keras.utils import to_categorical
from keras.layers.embeddings import Embedding
from keras.preprocessing.text import Tokenizer
from keras.models import Sequential, load_model
from keras.preprocessing.sequence import pad_sequences%matplotlib inline

数据

这是关于王力宏的歌词excel文件,包含91首歌,共2列属性:歌曲名(Title),歌词(Lyrics)

Title Lyrics
0 Bridge of Faith 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 狼烟千里乱葬岗 乱世孤魂无人...
1 DO U Love Me 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如...
2 Dragon Dance 原来默罕默德就是杜明汉 杜杜杜杜~汉 额 这就叫做用丹田唱歌 他根本就不会用丹田唱歌 他...
3 FLOW 跟着我Flow 跟着我Flow 这么自由 这么自由 Yi Li A E Yi Li A O ...
4 appiness x 3 Loneliness x 3 happiness happiness happiness loneliness lonel...
file_path = '../input/wanglihong/wanglihong.xlsx'
songs = pd.read_excel(file_path)
print(songs.shape)
songs.head()
(91, 2)
Title Lyrics
0 Bridge of Faith 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 狼烟千里乱葬岗 乱世孤魂无人...
1 DO U Love Me 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如...
2 Dragon Dance 原来默罕默德就是杜明汉 杜杜杜杜~汉 额 这就叫做用丹田唱歌 他根本就不会用丹田唱歌 他...
3 FLOW 跟着我Flow 跟着我Flow 这么自由 这么自由 Yi Li A E Yi Li A O ...
4 Happiness x 3 Loneliness x 3 happiness happiness happiness loneliness lonel...

查看前五首歌的歌词内容

for i in range(5):print(i, '\n', songs['Lyrics'][i])
0 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 狼烟千里乱葬岗 乱世孤魂无人访 无言苍天笔墨寒 笔刀春秋以血偿 谈爱恨 不能潦草 战鼓敲啊敲 用信任 立下誓言我来熬 这缘分 像一道桥 旌旗飘啊飘 你想走 就请立马抽刀 爱一笔勾销 谈爱恨 不能潦草 红尘烧啊烧 以生死 无愧证明谁重要 这缘分 像一道桥 故事瞧一瞧 走天涯 你我卸下战袍 梦回长城谣 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 血肉筑城万箭穿 盔甲染血映月光 远方胡笳催断肠 狼嚎骤起震边关 谈爱恨 不能潦草 战鼓敲啊敲 用信任 立下誓言我来熬 这缘分 像一道桥 旌旗飘啊飘 你想走 就请立马抽刀 爱一笔勾销 谈爱恨 不能潦草 红尘烧啊烧 以生死 无愧证明谁重要 这缘分 像一道桥 故事瞧一瞧 走天涯 你我卸下战袍 梦回长城谣 这缘分 像一道桥 故事瞧一瞧 走天涯 你我卸下战袍 梦回长城谣
1 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如戏 你爱的人到底是不是我 是否真正的我 是另一个样子 如果你愿意 我卸下我的面具 给你我全部 全部的我都给你 你挑着担 我牵着马 迎来日出 送走晚霞 给我一个反应 喊喊我的名字 美猴王的魅力 推前浪的行着 还在努力找传说中的幸福 一句道白 让你听的清楚 Do U Love Me 说说 你爱我到什么程度 Do U Want Me 说说 你要我到什么地步 让我相信 你的动心 为什么我还是 无法觉得真心 DoDoDoDoDoDoDoDo DoDoDoDo Do U Love Me 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如戏 你爱的人到底是不是我 是否真正的我 是另一个样子 如果你愿意 我卸下我的面具 给你我全部 全部的我都给你 你挑着担 我牵着马 迎来日出 送走晚霞 给我一个反应 喊喊我的名字 美猴王的魅力 推前浪的行着 还在努力找传说中的幸福 一句道白 让你听的清楚 Do U Love Me 说说 你爱我到什么程度 Do U Love Me 说说 你要我到什么地步 让我相信 你的动心 为什么我还是 无法觉得真心 DoDoDoDoDoDoDoDo DoDoDoDo Do U Love Me? Do U Love Me 说说 你爱我到什么程度 Do U Want Me 说说 你要我到什么地步 让我相信 你的动心 为什么我还是 无法觉得真心 DoDoDoDoDoDoDoDo DoDoDoDo Do U Love Me
2 原来默罕默德就是杜明汉  杜杜杜杜~汉 额 这就叫做用丹田唱歌 他根本就不会用丹田唱歌  他根本就不会用丹田唱歌  根根本 根根跟本  根根本 根根本 根根根本  根根根本 他根本就不会用丹田唱歌 根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根本本 根本 不喜欢 根根本本 根本 不喜欢 根本就不会用丹田唱歌 根根本 根根根本 根本就不会用丹田唱歌 根根本 根根根本 我真没有想到啊 这明星效应 还真你拉灵 为什么还不回来 根根根本 不回来 为什么还不回来 根根根本 不回来 为什么还不回来 根根根本 为什么还不回来 阿德呀 阿德呀
3 跟着我Flow 跟着我Flow 这么自由 这么自由 Yi Li A E Yi Li A O 跟着我Flow 跟着我Flow…Flow…Flow I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 从头到脚趾头 没有理由有点儿奇怪 ABC Do re mi fa sol 节奏轻轻地甩 微妙地笑 酷酷的跳 这是新的style 不如你一起来加入 跟着我Flow  (我手指开始) 跟着我Flow  (我弹指开始) 这么自由       (那韵律开始 hey hey hey) 这么自由       (我们都开始 )  (我们都开始) 歌声多清切 灵感开始倾泻 的一种感觉    woo… 感觉多强烈 不需要详解 相同当中总有分别 两种风格的交接 Just Flow…(Just Flow) I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我Flow  (我手指开始) 跟着我Flow  (我弹指开始) 这么自由       (那韵律开始) 这么自由       (我们都开始) (我们都开始) I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go (我双脚开始go) 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 I think I'm gonna rock I think I'm gonna roll 一听到music start 我双脚开始go 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我Flow  (跟着我Flow) 跟着我Flow  (跟着我Flow) 这么自由       (这么自由 ) 这么自由       (这么自由) 跟着我Flow 跟着我Flow 这么自由 这么自由
4 happiness happiness happiness loneliness loneliness loneliness happiness happiness happiness loneliness loneliness loneliness just can't live just can't die 你似乎看见大楼阴影复活包围过来 自由到不自在期待的色彩都成了黑白 谁是你的朋友谁是你的真爱 究竟你想要证明些什么 woo yeah 你的一切脆弱我心里明白 我只想要立刻带你离开 you can get out get out get out of your nest you don't have to be the one you can get out get out get out of your nest you don't have to be the best happiness happiness happiness loneliness loneliness loneliness happiness happiness happiness loneliness loneliness loneliness just can't live just can't die 自由到不自在一切成了黑白 自由到不自在一切成了黑白 早晨的报纸晚上变成垃圾满街覆盖 一半已经昏迷努力的叫另一半醒来 你想发现什么想知道什么 没有人能够给你答案 woo yeah 你的一切脆弱我心里明白 我只想要立刻带你离开 you can get out get out get out of your nest you don't have to be the one you don't have to be the best you can get out get out get out of your nest happiness happiness happiness loneliness loneliness loneliness happiness happiness happiness loneliness loneliness loneliness just can't live just can't die 没有人能够给你答案你想发现什么

正则表达式

以第三首歌为例

英文,符号不要

song = re.sub(r"[a-zA-Z()''…?.,!!,-]+", '', songs['Lyrics'][3])
song
'跟着我 跟着我 这么自由 这么自由         跟着我 跟着我           一听到  我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 从头到脚趾头 没有理由有点儿奇怪       节奏轻轻地甩 微妙地笑 酷酷的跳 这是新的 不如你一起来加入 跟着我  我手指开始 跟着我  我弹指开始 这么自由       那韵律开始    这么自由       我们都开始   我们都开始 歌声多清切 灵感开始倾泻 的一种感觉     感觉多强烈 不需要详解 相同当中总有分别 两种风格的交接              一听到  我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我  我手指开始 跟着我  我弹指开始 这么自由       那韵律开始 这么自由       我们都开始 我们都开始           一听到  我双脚开始 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来           一听到  我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我  跟着我 跟着我  跟着我 这么自由       这么自由  这么自由       这么自由 跟着我 跟着我 这么自由 这么自由 '

空格太多,不要!只留一个空格

re.sub('\s{2,}', ' ', song)
'跟着我 跟着我 这么自由 这么自由 跟着我 跟着我 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 从头到脚趾头 没有理由有点儿奇怪 节奏轻轻地甩 微妙地笑 酷酷的跳 这是新的 不如你一起来加入 跟着我 我手指开始 跟着我 我弹指开始 这么自由 那韵律开始 这么自由 我们都开始 我们都开始 歌声多清切 灵感开始倾泻 的一种感觉 感觉多强烈 不需要详解 相同当中总有分别 两种风格的交接 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我 我手指开始 跟着我 我弹指开始 这么自由 那韵律开始 这么自由 我们都开始 我们都开始 一听到 我双脚开始 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 一听到 我双脚开始 当节奏开始转 是谁都能感受 那音符一起玩 我停不下来 我简直停不下来 跟着我 跟着我 跟着我 跟着我 这么自由 这么自由 这么自由 这么自由 跟着我 跟着我 这么自由 这么自由 '

很好,写成函数形式

def regex_func(text):text = re.sub(r"[a-zA-Z()''…?.,!!,-]+", '', text)text = re.sub('\s{2,}', ' ', text)return text

新建一个DataFrame

new_songs = pd.DataFrame(columns=songs.columns)
new_songs['Title'] = songs['Title']

将正则函数用于歌词,并且添加一个包含歌词长度的属性

length = []
for i in range(len(new_songs)):new_songs.loc[i]['Lyrics'] = regex_func(songs['Lyrics'][i])length.append(len(new_songs['Lyrics'][i]))
new_songs['Length'] = length
new_songs.head()
Title Lyrics Length
0 Bridge of Faith 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 狼烟千里乱葬岗 乱世孤魂无人... 396
1 DO U Love Me 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如... 490
2 Dragon Dance 原来默罕默德就是杜明汉 杜杜杜杜~汉 额 这就叫做用丹田唱歌 他根本就不会用丹田唱歌 他根本... 271
3 FLOW 跟着我 跟着我 这么自由 这么自由 跟着我 跟着我 一听到 我双脚开始 当节奏开始转 是谁都... 458
4 Happiness x 3 Loneliness x 3 你似乎看见大楼阴影复活包围过来 自由到不自在期待的色彩都成了黑白 谁是你的朋友谁是你的真爱... 200

现在拥有一个较干净的数据了,接下来可以搞 · 事 · 情了

输入输出1

取窗口长度为10,窗口步长为1,即输入字符串“秦时明月汉时关 万里”,然后输出“长”;输入“时明月汉时关 万里长”,然后输出“征”,不断地滑向下一个汉字,如此类推,这就是所谓的滑窗(Sliding Window),如下图:

输入 输出
秦时明月汉时关 万里
时明月汉时关 万里长
明月汉时关 万里长征
月汉时关 万里长征人
汉时关 万里长征人未

接下来将汉字转化为数值类型

序列化

n = len(new_songs) # 歌曲总数目
print('一共有{}首歌'.format(n))
一共有91首歌

将所有歌词合并成一个长长的字符串

texts = ''
for i in range(n):texts += new_songs['Lyrics'][i]
print('所有歌词的总长度:', len(texts))
所有歌词的总长度: 33575

使用Keras

使用Tokenizer()将文本转换为序列,即转为整数

tokenizer = Tokenizer()
tokenizer.fit_on_texts(texts)

每个字(当然不止汉字,可能还有其它奇奇怪怪的符号,以下统称汉字)对应的下标,返回字典形式——汉字:下标

tokenizer.word_index # 返回按字频降序排序的字典 {'的': 1, '我': 2, '你': 3, '不': 4, '是': 5, '一': 6, '爱': 7, ...}

每个字的出现频率频,返回字典形式——汉字:频率。以下简称:字频

tokenizer.word_counts # 返回 OrderedDict([('秦', 2),('时', 93),('明', 62),('月', 35),('汉', 4),('关', 17), ...])

查看字典的长度

print('字典的长度:', len(tokenizer.word_counts))
字典的长度: 1636

使用texts_to_sequences将汉字映射为整数序列

sequences = tokenizer.texts_to_sequences(texts)
print('"{}"{}'.format(texts[: 10], '分别被映射成了整数:'))
print(sequences[: 10])
"秦时明月汉时关 万里"分别被映射成了整数:
[[1062], [46], [87], [171], [805], [46], [341], [], [220], [31]]

然而我们所写的歌词并不需要使用字典里所有的汉字,有些字只出现一两次,所以考虑可以忽略掉

tokenizer()中提供了参数num_words,在使用时,取字频最多的前(num_words-1)个汉字,多余的为空集,但字典的长度还是和原来的一样

tokenizer = Tokenizer(num_words=num_words)
tokenizer.fit_on_texts(texts)
print('字典的长度:', len(tokenizer.word_index))
字典的长度: 1636
sequences = tokenizer.texts_to_sequences(texts)
print('"{}"{}'.format(texts[: 10], '分别被映射成了整数:'))
print(sequences[: 10])
"秦时明月汉时关 万里"分别被映射成了整数:
[[], [46], [87], [171], [], [46], [341], [], [220], [31]]

对比上面两个sequences的结果来看,第二个sequences里出现了更多的空列表,这就代表了num_words发挥了作用

Pad_sequences

pad_sequences(sequences, maxlen=None, padding='pre', truncating='pre', value=0.0)

  • sequences: 列表的列表,每一个元素是一个序列。
  • maxlen: 整数,所有序列的最大长度。
  • padding: 字符串,'pre' 或 'post' ,在序列的前端补齐还是在后端补齐。
  • truncating: 字符串,'pre' 或 'post' ,移除长度大于 maxlen 的序列的值,要么在序列前端截断,要么在后端。
  • value: 浮点数,表示用来补齐的值。

接着使用 pad_sequences 对空值进行填补

sequences = pad_sequences(sequences)
sequences[: 10]
array([[  0],[ 46],[ 87],[171],[  0],[ 46],[341],[  0],[220],[ 31]], dtype=int32)
print('最小索引:{},最大索引:{}'.format(sequences.min(), sequences.max()))
最小索引:0,最大索引:399

于是sequences里的索引对应了num_words=400,我们之后使用的汉字只有这400个字

新增列

这一列是将每首歌的歌词映射为整数序列后新的一列

star = 0
end = 0
new_songs['Sequences'] = ''
for i in range(n):end += new_songs['Length'][i]new_songs.loc[i, 'Sequences'] = sequences[star: end]star = end
new_songs.head()
Title Lyrics Length Sequences
0 Bridge of Faith 秦时明月汉时关 万里长征人未还 但使龙城飞将在 不教胡马度阴山 狼烟千里乱葬岗 乱世孤魂无人... 396 [0, 46, 87, 171, 0, 46, 341, 0, 220, 31, 212, ...
1 DO U Love Me 眼睛看我 看看我的眼睛 想问问你 问你一个问题 你你我我 还在演什么戏 戏如人生 还是人生如... 490 [49, 229, 39, 2, 0, 39, 39, 2, 1, 49, 229, 0, ...
2 Dragon Dance 原来默罕默德就是杜明汉 杜杜杜杜~汉 额 这就叫做用丹田唱歌 他根本就不会用丹田唱歌 他根本... 271 [263, 18, 389, 0, 389, 0, 14, 5, 0, 87, 0, 0, ...
3 FLOW 跟着我 跟着我 这么自由 这么自由 跟着我 跟着我 一听到 我双脚开始 当节奏开始转 是谁都... 458 [150, 33, 2, 0, 150, 33, 2, 0, 11, 13, 26, 139...
4 Happiness x 3 Loneliness x 3 你似乎看见大楼阴影复活包围过来 自由到不自在期待的色彩都成了黑白 谁是你的朋友谁是你的真爱... 200 [0, 3, 0, 359, 39, 57, 86, 0, 0, 360, 0, 348, ...

输入输出2

这时候拥有了数值型的数据,输入一个序列,输出下一个值:

输入 输出
[0, 46, 87, 171, 0, 46, 341, 0, 220, 31] [212]
[46, 87, 171, 0, 46, 341, 0, 220, 31, 212] [0]
[87, 171, 0, 46, 341, 0, 220, 31, 212, 0] [15]
[171, 0, 46, 341, 0, 220, 31, 212, 0, 15] [127]
[0, 46, 341, 0, 220, 31, 212, 0, 15, 127] [43]

接下来进行滑窗的处理

滑窗

由于每首歌之间的歌词是没有联系的,并不会从一首歌的歌词预测到另一首歌的歌词,所以不能直接使用整个texts来滑窗划分,而是分别对每首歌进行处理

以第一首歌为例

seq = new_songs['Sequences'][0]
seq[: 10]
[0, 46, 87, 171, 0, 46, 341, 0, 220, 31]

取滑窗的长度为10,也就是之后神经网络的输入序列的长度

max_len = 10 # 滑窗长度,也就是输入序列的长度
len_lrc = new_songs['Length'][0] # 每首歌歌词的长度
X = []
y = []
for i in range(len_lrc - (max_len+1)):X.append(seq[i: i + (max_len+1)])y.append(seq[i + (max_len+1)])

得到了第一首歌的 X,y

函数形式

# 这里是先将X,y合并成一个大矩阵,那么大矩阵的shape=(?, 11)
def build_matrix(sequence, max_len = 10):max_len += 1matrix = []length = len(sequence)for i in range(length - max_len):matrix.append(sequence[i: i + max_len])matrix = np.array(matrix)X = matrix[:, :-1]y = matrix[:, -1]return X, y

序列合并

# n = 91 歌曲数目
X, y = build_matrix(new_songs['Sequences'][0])
for i in range(1, n):sequence = new_songs['Sequences'][i]XX, yy = build_matrix(sequence)X = np.concatenate([X, XX])y = np.concatenate([y, yy])

得到了所有歌词的 X,y

X.shape, y.shape
((32574, 10), (32574,))

一共得到32574行的输入序列

输入输出3

将输入序列进行字向量化(此处为单个汉字,故称字向量,而使用更多的为词向量),输出进行One hot编码,例如(数值是瞎写的):

整数 One Hot 字向量
3 [0, 0, 0, 1, 0, 0] [0.32, 0.11]
6 [1, 0, 0, 0, 0, 0] [0.51, 0.62]
4 [0, 0, 1, 0, 0, 0] [0.26, 0.41]

模型

在Keras里面,使用嵌入层 Embedding 可以输入进行向量化

Embedding(input_dim, out_dim, input_length=None)

  • input_dim:大或等于0的整数,字典长度,即输入数据最大下标+1
  • out_dim:大于0的整数,代表全连接嵌入的维度
  • input_length:当输入序列的长度固定时,该值为其长度

现在可以举个例子,拿 X[: 1] 来做示范

print('X[: 1]是', X[: 1].shape, '矩阵')
print('它含有数值:', X[: 1])
X[: 1]是 (1, 10) 矩阵
它含有数值: [[  0  46  87 171   0  46 341   0 220  31]]

Embedding 层 input_dim 就是所使用汉字的数目 num_words,out_dim 就是我们需要让整数向量化后的长度,input_length 就是输入序列的长度,我们的 X.shape[1] = 10,就是10,例如我们这么写:

embedding = Sequential()
embedding.add(Embedding(num_words, 12, input_length=X.shape[1]))
WARNING:tensorflow:From /opt/conda/lib/python3.6/site-packages/tensorflow/python/framework/op_def_library.py:263: colocate_with (from tensorflow.python.framework.ops) is deprecated and will be removed in a future version.
Instructions for updating:
Colocations handled automatically by placer.

这样,输入的 X[: 1].shape = (1, 10) 就会变为 (1, 10, 12)

print(embedding.predict(X[: 1]))
print(embedding.predict(X[: 1]).shape)
[[[-9.2859752e-03 -1.9947542e-02  1.4158692e-02  2.5630761e-02-1.3254523e-02 -4.4673540e-02  2.0926904e-02 -2.1672739e-024.5357570e-03  7.1933120e-04  2.3986842e-02 -1.6472042e-02][ 3.5469163e-02 -4.4115938e-02 -3.4637891e-02 -2.7161956e-02-2.3825645e-02  2.0239640e-02  2.5555268e-03 -1.7135501e-02-3.0841781e-02  2.8748605e-02 -3.9590113e-03  6.0198195e-03][ 1.6848337e-02 -1.7353892e-02 -3.8705468e-02 -4.8205614e-023.5994854e-02 -1.7381988e-02  7.6504238e-03 -7.6918602e-03-1.4761232e-02  7.7899583e-03 -4.9694888e-03  3.0793250e-05][ 3.5687301e-02 -1.8727556e-03 -4.7537651e-02 -2.4941897e-02-2.4263645e-02 -1.2860574e-02  3.2451559e-02  2.3206424e-023.7631344e-02 -4.2071544e-02 -1.8674839e-02  3.9704118e-02][-9.2859752e-03 -1.9947542e-02  1.4158692e-02  2.5630761e-02-1.3254523e-02 -4.4673540e-02  2.0926904e-02 -2.1672739e-024.5357570e-03  7.1933120e-04  2.3986842e-02 -1.6472042e-02][ 3.5469163e-02 -4.4115938e-02 -3.4637891e-02 -2.7161956e-02-2.3825645e-02  2.0239640e-02  2.5555268e-03 -1.7135501e-02-3.0841781e-02  2.8748605e-02 -3.9590113e-03  6.0198195e-03][ 2.6380885e-02 -1.3970364e-02  4.0359497e-03  4.9115308e-03-1.5673112e-02  2.5444303e-02 -3.0493153e-02 -4.5944821e-023.2101501e-02 -2.2213591e-02 -2.4235893e-02 -2.3439897e-02][-9.2859752e-03 -1.9947542e-02  1.4158692e-02  2.5630761e-02-1.3254523e-02 -4.4673540e-02  2.0926904e-02 -2.1672739e-024.5357570e-03  7.1933120e-04  2.3986842e-02 -1.6472042e-02][-3.0420924e-02  4.8257243e-02 -7.5347200e-03  1.0823570e-022.1067370e-02  3.6987696e-02  3.3310857e-02 -7.7851191e-034.3326866e-02 -1.8127739e-02 -3.8963556e-02  7.5731166e-03][-5.6729540e-03  3.0662213e-02 -2.9343033e-02  3.2814298e-02-4.9867988e-02  4.5566510e-02  3.3448350e-02 -3.5617065e-024.3894444e-02 -3.1913005e-02 -3.4133270e-02 -3.0503750e-02]]]
(1, 10, 12)

从上面看来,即 0 -> [ 0.00410016 -0.04466455 -0.00399476 0.01623822 -0.04920522 -0.00889667 -0.01161783 -0.00897527 -0.01439846 -0.01946389 -0.02629197 0.04435097] 46 -> [-0.02194022 0.00509825 0.0128585 0.00029064 -0.00293522 0.00266709 0.00053818 -0.02969973 -0.03511238 0.02033797 0.02721104 0.0055184 ] ...

如此一来就可以马上开工了!

我们需要预测下一个汉字,那么输出层的节点数为num_words,即400个,使用softmax激活函数,然后获取最大输出值的下标,最后寻找字典中对应的汉字

损失函数使用categorical_crossentropy,优化函数使用adam

当使用 categorical_crossentropy 损失时,你的目标值应该是分类格式 (即,如果你有 10 个类,每个样本的目标值应该是一个 10 维的向量,这个向量除了表示类别的那个索引为 1,其他均为 0)。

model = Sequential()
model.add(Embedding(num_words, 128, input_length=X.shape[1]))
model.add(LSTM(64))
model.add(Dense(64, activation='relu'))
model.add(Dense(num_words, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')model.summary()
_________________________________________________________________
Layer (type)                 Output Shape              Param #
=================================================================
embedding_2 (Embedding)      (None, 10, 128)           51200
_________________________________________________________________
lstm_1 (LSTM)                (None, 64)                49408
_________________________________________________________________
dense_1 (Dense)              (None, 64)                4160
_________________________________________________________________
dense_2 (Dense)              (None, 400)               26000
=================================================================
Total params: 130,768
Trainable params: 130,768
Non-trainable params: 0
_________________________________________________________________

使用 to_categorical() 对 y 进行One hot编码

y = to_categorical(y, num_classes=num_words)

开始训练

需要等待一段较长的时间

model.fit(X, y, batch_size=256, epochs=500, verbose=0)
# model.save('lrc_model_0.h5')

可视化

loss = model.history.history['loss']plt.style.use('bmh')
plt.figure(figsize=(12, 8))
plt.plot(range(len(loss)), loss)
plt.title('LSTM')
plt.xlabel('Iterations')
plt.ylabel('Loss')
Text(0, 0.5, 'Loss')

预测

test_lrc = '当节奏开始转' # 输入歌词开头
test_sequence = tokenizer.texts_to_sequences(test_lrc) # 序列化
test_sequence = pad_sequences(test_sequence).reshape(1, -1)
test_sequence = pad_sequences(test_sequence, X.shape[1]) # 输入序列长度不足10,故使用pad_sequences将其补足
test_sequence
array([[  0,   0,   0,   0, 149, 374,   0,  38, 148, 131]], dtype=int32)
print('输出的最大下标为:', model.predict(test_sequence).argmax())
输出的最大下标为: 0

Tokenizer()中的字典是以1开始作为下标的,故我们将下标0看作是空格

try:print(tokenizer.index_word[0])
except:print('字典中没有')
字典中没有

我们需要让模型不断的输出,就要有一个不断输入的循环,将输出添加到原来的输入当中,于是就有了新的输入

test_lrc += ' ' # 下标为0,故添加一个空格
test_lrc
'当节奏开始转 '

新的汉字加进来后

test_sequence = tokenizer.texts_to_sequences(test_lrc)
test_sequence = pad_sequences(test_sequence).reshape(1, -1)
test_sequence = pad_sequences(test_sequence, X.shape[1])
test_sequence
array([[  0,   0,   0, 149, 374,   0,  38, 148, 131,   0]], dtype=int32)

函数形式

# 输入一个文本将其转化为序列
def input_sequence(text, max_len=10):sequence = tokenizer.texts_to_sequences(text) # 序列化sequence = pad_sequences(sequence).reshape(1, -1) # 填充0sequence = pad_sequences(sequence, maxlen=max_len) # 补足或截断return sequence
# 得到字典内的汉字
def next_word(y_pred):idx = np.argmax(y_pred) # 最大值的下标if idx == 0: # 下标为0时,字典内并不存在,故视为空格return ' 'else:return tokenizer.index_word[idx]

输出长度为200的歌词试试看

lrc = '当节奏开始转'
for i in range(200):X_sequence = input_sequence(lrc)y_pred = model.predict(X_sequence)word = next_word(y_pred)lrc += word
lrc = re.sub('\s+', ' ', lrc) # 只需要一个空格
print(lrc)
当节奏开始转 是否心里 这飞过 着边 着行满爱一变 心会感觉又会有前 喔 我的前吧 我只想要来 离的梦 你的高泪 却说以够 老远记向方真会忘掉 到不停此转生 一 依然明白 春人的春天的恋于离 力 那是唯一 这是十二个生 在乎我心爱不想用话 但看见你喜欢 头望 忘了一 大声 你在我心个欢的几次 带又后比任 好 断爱的 有言自头 有心 快出我用全部生的梦得痛 也不听见面 不如

然而我们并没有看懂他在讲什么

函数形式

def generating_lrc(lrc, length=200):for i in range(200):X_sequence = input_sequence(lrc)y_pred = model.predict(X_sequence)word = next_word(y_pred)lrc += wordlrc = re.sub('\s+', ' ', lrc) # 只需要一个空格return lrc
generating_lrc('大城小爱')
'大城小爱 关不尽不 来 我不切会说过任 忘了话冷 给我眼中 春 的已 的打 带 我用生命好听清楚 在 了 看 这一场爱情 失陪你拉英雄我到 把 伤情就能回到永远 永远眼愿中 然不思 我怎能 星 音乐 好 你陪都知道你是我手就是你我心愿就在这里 了春去现在 上了时候 们来 在每个 伤心犯我的心情留 人就会变成为今天 你们是神 着 全世界带 季 那 过 地 花'
generating_lrc('他根本就不会用丹田唱歌')
'他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本就不会用丹田唱歌 根根本 根根根本 根根根本 他根本'

参考资料

详情请移步github: 一个关于LSTM生成歌词的练习

  1. Generating Drake Rap Lyrics using Language Models and LSTMs(译文:使用Keras和LSTM生成说唱歌词)
  2. 序列预处理 - Keras中文文档
  3. 嵌入层 Embedding - Keras中文文档
  4. 损失函数 Losses - Keras中文文档
  5. 深度学习中Keras中的Embedding层的理解与使用

转载于:https://juejin.im/post/5ce4f2285188252dc142b79e

一个关于LSTM生成歌词的练习相关推荐

  1. python神经网络风格_[Deep-Learning-with-Python]使用LSTM生成尼采风格文章

    github地址repos LSTM生成文本 使用循环神经网络生成序列文本数据.循环神经网络可以用来生成音乐.图像作品.语音.对话系统对话等等. 如何生成序列数据? 深度学习中最常见的方法是训练一个网 ...

  2. 从零开始学keras之使用 LSTM 生成文本

    下面用 Keras 来实现这些想法.首先需要可用于学习语言模型的大量文本数据.我们可以使用任意足够大的一个或多个文本文件--维基百科.<指环王>等.本例将使用尼采的一些作品,他是 19 世 ...

  3. python词云去除词_Python生成歌词词云

    对于数据展示这一块有时候会用到词云,python中提供的wordcloud模块可以很灵活的完成 生成词云除了使用python提供的wordcloud模块以为还有在线的生成方式https://worda ...

  4. 使用LSTM生成文本

    使用LSTM生成文本 概述 如何生成序列数据 生成文本的采样策略 文本序列生成程序流程 准备并解析初始文本 将字符序列向量化 构建神经网络模型 训练语言模型并采样 用模型生成文本 概述 我们的感知模式 ...

  5. Tensorflow:基于LSTM生成藏头诗

    Tensorflow:基于LSTM生成藏头诗 最近在学习TensorFlow,学习到了RNN这一块,相关的资料不是很多,了解到使用RNN可以生成藏头诗之后,我就决定拿这个下手啦! 本文不介绍RNN以及 ...

  6. keras采用LSTM生成尼采风格文章

    LSTM生成文本 github地址 使用循环神经网络生成序列文本数据.循环神经网络可以用来生成音乐.图像作品.语音.对话系统对话等等. 如何生成序列数据? 深度学习中最常见的方法是训练一个网络模型(R ...

  7. Nikolai Yakovenko大佬:深度学习的下一个热点:生成对抗网络(GANs)将改变世界

    生成式对抗网络-简称GANs-将成为深度学习的下一个热点,它将改变我们认知世界的方式. 准确来讲,对抗式训练为指导人工智能完成复杂任务提供了一个全新的思路,某种意义上他们(人工智能)将学习如何成为一个 ...

  8. 深度学习的下一个热点:生成对抗网络(GANs)将改变世界

    本文作者 Nikolai Yakovenko 毕业于哥伦比亚大学,目前是 Google 的工程师,致力于构建人工智能系统,专注于语言处理.文本分类.解析与生成. 生成式对抗网络-简称GANs-将成为深 ...

  9. 实验三:实现一个大素数生成算法

    一.实验内容 掌进一步掌握大素数分解的一般原理和实现方法.能用间接方法实现大素数分解.用代码实现Solovay-Strassen素性测试法或Miller-Rabin素性测试法. 二.分实现一个大素数生 ...

最新文章

  1. Oracle TNS 不能启动
  2. loadrunner使用流程_LoadRunner关联函数
  3. Swift2.0语言教程之闭包
  4. 十分钟搭建和使用ELK日志分析系统
  5. matlab图像的腐蚀和膨胀_OpenCV图像处理系列八 --- 腐蚀与膨胀
  6. mnist数据集svm python_python支持向量机分类MNIST数据集
  7. vue3.0中使用Element-plus默认英文组件修改为中文
  8. 本地gradle使用
  9. 全国哀悼日 灰色CSS滤镜
  10. 硬件设计28之RS422、RS485
  11. 如何在SuperMap iDesktop制作卫星地图
  12. [转]应对新劳动法:华为万名员工“自愿”辞职[http://news.qq.com/a/20071030/001675.htm]
  13. 用word制作正规公文(转)
  14. python七段数码管绘制实验报告_Python绘制七段数码管实例代码
  15. iOS开发:设置App名称,设置App icon图标,设置App启动图
  16. vs2012创建的数据库中的表怎么都不能保存的
  17. UE4地形简单材质球制作,及地形变黑处理办法
  18. ery validator addMethod 方法的使用
  19. 这样的设计太妙了!K8S 神秘架构终于揭开面纱!
  20. IIS服务 与 NetWork Rat(网络老鼠)8.0 的 上线方法

热门文章

  1. python中tkinter较完整的鼠标样式cursor值
  2. C++17标准STL库并行策略在GCC编译器中的替代实现方法
  3. 解决Client.Timeout exceeded while awaiting headers报错
  4. Jenkins系列之——第二章 Jenkins中Maven和JDK配置
  5. windows下使用route添加路由
  6. 大促迷思:那个榨干我钱包的“猜你喜欢”是什么来头!?
  7. 60 Linux 常用 命令
  8. 武汉市企业研究开发中心备案
  9. OSChina 周五乱弹 ——下完雨朕的江山都湿了
  10. 计算机网络雨课堂练习11