炼数成金 门户 商业智能 TensorFlow 查看内容

用TensorFlow生成周杰伦歌词

2016-11-29 21:41| 发布者: 炼数成金_小数| 查看: 21792| 评论: 0
摘要: 拿中文举例来说,每个字与每个字并不是统计上独立的,比如说如果不爱就不要再伤害 长度为10的序列,如果我们知道如,下一个字有可能是果,如果知道前两个字如果,第三个字就是不的可能性大些,依次类推,如果知道前9 ...
tm 工具 框架 深度学习 商业智能
最近深度学习在机器视觉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,恕我直言,有以下三点比较膈应:

代码写的不够直观简洁
另外因为tensorflow的部分api有所变化
中英文之间有一些差异,看能否成功移植到处理中文上
于是打算基于以上两个项目,自己重写!

基本原理
拿中文举例来说,每个字与每个字并不是统计上独立的,比如说如果不爱就不要再伤害 长度为10的序列,如果我们知道如,下一个字有可能是果,如果知道前两个字如果,第三个字就是不的可能性大些,依次类推,如果知道前9个字如果不爱就不要再伤,那么最后一个就有可能是害字。用图直观的表示如下。
rnn
总的来说,这是一个seq2seq的模型,训练数据用的是周杰伦01年到11年所有歌的歌词,训练数据和代码我都放到github上,可以从这里下载

全部代码如下:

from tensorflow.python.ops import rnn_cell
from tensorflow.python.ops import seq2seq
from collections import namedtuple
import tensorflow as tf
import numpy as np
import sys
class HParam():
    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'
class DataGenerator():
    def __init__(self, datafiles, args):
        self.seq_length = args.seq_length
        self.batch_size = args.batch_size
        with open(datafiles, encoding='utf-8') as f:
            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 for i, w in enumerate(self.words)}
        self.id2char_dict = {i: w for i, w in enumerate(self.words)}
        
        # pointer position to generate current batch
        self._pointer = 0
        
    
    def char2id(self, c):
        return self.char2id_dict[c]
    def id2char(self, id):
        return self.id2char_dict[id]
    def next_batch(self):
        x_batches = []
        y_batches = []
        for i in range(self.batch_size):
            if self._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) for c in bx]
            by = [self.char2id(c) for c in by]
            x_batches.append(bx)
            y_batches.append(by)
        return x_batches, y_batches
    
        
class Model():
    """
    The core recurrent neural network model.
    """
    def __init__(self, args, data, infer=False):
        if infer:
            args.batch_size = 1
            args.seq_length = 1
        with tf.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])
        with tf.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)
            with tf.variable_scope('rnnlm'):
                w = tf.get_variable('softmax_w', [args.state_size, data.vocab_size])
                b = tf.get_variable('softmax_b', [data.vocab_size])
                with tf.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)
        with tf.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)
        with tf.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)
            for g in grads:
                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()
    
def sample(data, model, num=400):
    saver = tf.train.Saver()
    with tf.Session() as sess:
        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))
        for word in prime[:-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
        for i in range(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
        return lyrics
        
def main(infer):
    
    args = HParam()
    data = DataGenerator('JayLyrics.txt', args)
    model = Model(args, data, infer=infer)
    if infer:
        print(sample(data, model))
    else:
        with tf.Session() as sess:
            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
            for i in range(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)
                if i % 10 == 0:
                    writer.add_summary(summary, global_step=i)
                    print('Step:{}/{}, training_loss:{:4f}'.format(i, max_iter, train_loss))
                if i % 10000 == 0 or (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
    """
    if len(sys.argv) == 2:
        infer = int(sys.argv[-1])
        print('--Sampling--' if infer else '--Training--')
        main(infer)
    else:
        print(msg)
        sys.exit(1)
python3 gen_lyrics 0训练差不多10几分钟,然后运行python3 gen_lyrics.py 1生成的歌词如下:

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

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

欢迎加入本站公开兴趣群
商业智能与数据分析群
兴趣范围包括各种让数据产生价值的办法,实际应用案例分享与讨论,分析工具,ETL工具,数据仓库,数据挖掘工具,报表系统等全方位知识
QQ群:81035754

鲜花

握手

雷人

路过

鸡蛋

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

热门文章

      GMT+8, 2017-11-24 17:02 , Processed in 0.191695 second(s), 24 queries .