你好,游客 登录
背景:
阅读新闻

用TensorFlow生成周杰伦歌词

[日期:2016-11-29] 来源:极客头条  作者: [字体: ]

最近深度学习在机器视觉CV、自然语言处理NLP领域表现出强大的潜力,各种深度学习/机器学习框架也层出不穷。tensorflow是google于去年(2015.11)开源的深度学习框架,截止目前(2016-11-28)github上已经有38000+的star数,称之为最近最受欢迎的深度学习框架一点也不过分。

本着学习tensorflow和RNN的目的,前些天发现了 char-rnn 这个有趣的项目,具体就是基于字符预测下一个字符,比日说已知 hello 的前四个字母 hell ,那我们就可以据此预测下一个字符很可能是 o ,因为是字符char级别的,并没有单词或句子层次上的特征提取,相对而言比较简单易学。 

因为原作者的代码是基于torch写的,为了熟悉tensorflow,我就仔细地研究了一下具体代码,然后改写成基于tf的代码,github上也有基于tensorflow的 char-rnn-tensorflow ,恕我直言,有以下三点比较膈应: 

  1. 代码写的不够直观简洁
  2. 另外因为最新tensorflow的部分api有所变化
  3. 中英文之间有一些差异,看能否成功移植到处理中文上

于是打算基于以上两个项目,自己重写!

基本原理 

拿中文举例来说,每个字与每个字并不是统计上独立的,比如说 如果不爱就不要再伤害 长度为10的序列,如果我们知道  ,下一个字有可能是  ,如果知道前两个字 如果 ,第三个字就是  的可能性大些,依次类推,如果知道前9个字 如果不爱就不要再伤 ,那么最后一个就有可能是  字。用图直观的表示如下。 

总的来说,这是一个 seq2seq 的模型,训练数据用的是周杰伦01年到11年所有歌的歌词,训练数据和代码我都放到github上,可以从这里 下载

全部代码如下: 

fromtensorflow.python.opsimportrnn_cell
fromtensorflow.python.opsimportseq2seq
fromcollectionsimportnamedtuple
importtensorflowastf
importnumpyasnp
importsys


classHParam():
def__init__(self):
 self.batch_size = 32
 self.n_epoch = 50
 self.learning_rate = 0.01
 self.decay_steps = 1000
 self.decay_rate = 0.9
 self.grad_clip = 5

 self.state_size = 100
 self.num_layers = 3
 self.seq_length = 10
 self.log_dir = './logs'


classDataGenerator():
def__init__(self, datafiles, args):
 self.seq_length = args.seq_length
 self.batch_size = args.batch_size
withopen(datafiles, encoding='utf-8')asf:
 self.data = f.read()

 self.total_len = len(self.data) # total data length
 self.words = list(set(self.data))
 self.words.sort()
# vocabulary
 self.vocab_size = len(self.words) # vocabulary size
 print('Vocabulary Size: ', self.vocab_size)
 self.char2id_dict = {w: i fori, winenumerate(self.words)}
 self.id2char_dict = {i: w fori, winenumerate(self.words)}

# pointer position to generate current batch
 self._pointer = 0


defchar2id(self, c):
returnself.char2id_dict[c]


defid2char(self, id):
returnself.id2char_dict[id]


defnext_batch(self):
 x_batches = []
 y_batches = []
foriinrange(self.batch_size):
ifself._pointer + self.seq_length +1>= self.total_len:
 self._pointer = 0
 bx = self.data[self._pointer: self._pointer + self.seq_length]
 by = self.data[self._pointer + 1: self._pointer + self.seq_length +1]
 self._pointer += self.seq_length # update pointer position

# convert to ids
 bx = [self.char2id(c) forcinbx]
 by = [self.char2id(c) forcinby]
 x_batches.append(bx)
 y_batches.append(by)

returnx_batches, y_batches




classModel():
"""
 The core recurrent neural network model.
 """

def__init__(self, args, data, infer=False):
ifinfer:
 args.batch_size = 1
 args.seq_length = 1
withtf.name_scope('inputs'):
 self.input_data = tf.placeholder(tf.int32, [args.batch_size, args.seq_length])
 self.target_data = tf.placeholder(tf.int32, [args.batch_size, args.seq_length])

withtf.name_scope('model'):
 self.cell = rnn_cell.BasicLSTMCell(args.state_size)
 self.cell = rnn_cell.MultiRNNCell([self.cell] * args.num_layers)
 self.initial_state = self.cell.zero_state(args.batch_size, tf.float32)

withtf.variable_scope('rnnlm'):
 w = tf.get_variable('softmax_w', [args.state_size, data.vocab_size])
 b = tf.get_variable('softmax_b', [data.vocab_size])
withtf.device("/cpu:0"):
 embedding = tf.get_variable('embedding', [data.vocab_size, args.state_size])
 inputs = tf.nn.embedding_lookup(embedding, self.input_data)
 outputs, last_state = tf.nn.dynamic_rnn(self.cell, inputs, initial_state=self.initial_state)

withtf.name_scope('loss'):
 output = tf.reshape(outputs, [-1, args.state_size])

 self.logits = tf.matmul(output, w) + b
 self.probs = tf.nn.softmax(self.logits)
 self.last_state = last_state

 targets = tf.reshape(self.target_data, [-1])
 loss = seq2seq.sequence_loss_by_example([self.logits],
 [targets],
 [tf.ones_like(targets, dtype=tf.float32)])
 self.cost = tf.reduce_sum(loss)/args.batch_size 
 tf.scalar_summary('loss', self.cost)
withtf.name_scope('optimize'):
 self.lr = tf.placeholder(tf.float32, [])
 tf.scalar_summary('learning_rate', self.lr)

 optimizer = tf.train.AdamOptimizer(self.lr)
 tvars = tf.trainable_variables()
 grads = tf.gradients(self.cost, tvars)
forgingrads:
 tf.histogram_summary(g.name, g)
 grads, _ = tf.clip_by_global_norm(grads, args.grad_clip)

 self.train_op = optimizer.apply_gradients(zip(grads, tvars))
 self.merged_op = tf.merge_all_summaries()



defsample(data, model, num=400):
 saver = tf.train.Saver()
withtf.Session()assess:
 ckpt = tf.train.latest_checkpoint('./')
 print(ckpt)
 saver.restore(sess, ckpt)

# initial phrase to warm RNN
 prime = u'如果离开请不要伤害'

 state = sess.run(model.cell.zero_state(1, tf.float32))

forwordinprime[:-1]:
 x = np.zeros((1,1))
 x[0,0] = data.char2id(word)
 print(word, x[0,0])
 feed = {model.input_data: x, model.initial_state: state}
 state = sess.run(model.last_state, feed)

 word = prime[-1]
 lyrics = prime
foriinrange(num):
 x = np.zeros([1,1])
 x[0,0] = data.char2id(word)
 feed_dict={model.input_data: x, model.initial_state: state}
 probs, state = sess.run([model.probs, model.last_state], feed_dict)
 p = probs[0]
 word = data.id2char(np.argmax(p))
 lyrics += word
returnlyrics



defmain(infer):

 args = HParam()
 data = DataGenerator('JayLyrics.txt', args)
 model = Model(args, data, infer=infer)

ifinfer:
 print(sample(data, model))
else:
withtf.Session()assess:
 sess.run(tf.initialize_all_variables())
 saver = tf.train.Saver()
 writer = tf.train.SummaryWriter(args.log_dir, sess.graph)

 max_iter = args.n_epoch * (data.total_len // args.seq_length) // args.batch_size
foriinrange(max_iter):
 learning_rate = args.learning_rate * (args.decay_rate ** (i//args.decay_steps))
 x_batch, y_batch = data.next_batch()
 feed_dict={model.input_data: x_batch, model.target_data: y_batch, model.lr: learning_rate}
 train_loss, summary, _, _ = sess.run([model.cost, model.merged_op, model.last_state, model.train_op],
 feed_dict)

ifi %10==0:
 writer.add_summary(summary, global_step=i)
 print('Step:{}/{}, training_loss:{:4f}'.format(i, max_iter, train_loss))
ifi %10000==0or(i+1) == max_iter:
 saver.save(sess, 'lyrics_model', global_step=i)


if__name__ =='__main__':
 msg = """
 Usage:
 Training: 
 python3 gen_lyrics.py 0
 Sampling:
 python3 gen_lyrics.py 1
 """

iflen(sys.argv) ==2:
 infer = int(sys.argv[-1])
 print('--Sampling--'ifinferelse'--Training--')
 main(infer)
else:
 print(msg)
 sys.exit(1)

python3 gen_lyrics 0 训练差不多10几分钟,然后运行 python3 gen_lyrics.py 1 生成的歌词如下: 

如果离开请不要伤害
你的笑 我的笑容 我们的爱情
不要哭不到我
你不该的爱情
我的笑容 让我们 我的爱溢出就象雨踢
我的嘴角
而我们 半兽人 的里
我用第留 你说的爱我
倭~的 的平候
越着你的热情
我不要再微笑
我的笑容 让我们 我的解 我用爱什么 娘子依旧等待 你好你 听不该
彩虹的 爱酋的色里 不像连事的模 我跟一种味道
冷不留
语沉我们寻的画面
全美飘 你的笑容 拼命不是我要 我的世界
我用的意色
缺席你 我的解释请你务事
你的笑 我知道你
我不要
我不会经的爱我
我不能
我的声音
我不能有受
又多慢再我
我不能有蠢
我没要给我
你的声音
你的爱情 我不要
我的声音 我不不想要我
你不懂
脑袋瓜有一点秀容的四周叫是一瓢爱
篮地危名是太饱勾 
你说最善月 豆腐(豆腐)
二药开始来 园幕毛驴 Hia键 还不多
说你的泪 我喜欢的浪装
龙不开 扯去了 爱不需存
不要问不太你的声音
我用第一天 我用眼泪

不多说了,我要写歌词去了,争取当下一个方文山(逃)

收藏 推荐 打印 | 录入:admin | 阅读:
相关新闻      
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款