1 简介
Char-RNN,字符级循环神经网络,出自于Andrej Karpathy写的The Unreasonable Effectiveness of Recurrent Neural Networks。众所周知,RNN非常擅长处理序列问题。序列数据前后有很强的关联性,而RNN通过每个单元权重与偏置的共享以及循环计算(前面处理过的信息会被利用处理后续信息)来体现。Char-RNN模型是从字符的维度上,让机器生成文本,即通过已经观测到的字符出发,预测下一个字符出现的概率,也就是序列数据的推测。现在网上介绍的用深度学习写歌、写诗、写小说的大多都是基于这个方法。
在基本的RNN单元中,只有一个隐藏状态,对于长距离的记忆效果很差(序列开始的信息在后期保留很少),而且存在梯度消失的问题,因此诞生了许多变体,如LSTM、GRU等。本文介绍的Char-RNN就是选用LSTM作为基本模型。
2 Char RNN 原理
Char RNN 原理
上图展示了Char-RNN的原理。以要让模型学习写出“hello”为例,Char-RNN的输入输出层都是以字符为单位。输入“h”,应该输出“e”;输入“e”,则应该输出后续的“l”。输入层我们可以用只有一个元素为1的向量来编码不同的字符,例如,h被编码为“1000”、“e”被编码为“0100”,而“l”被编码为“0010”。使用RNN的学习目标是,可以让生成的下一个字符尽量与训练样本里的目标输出一致。在图一的例子中,根据前两个字符产生的状态和第三个输入“l”预测出的下一个字符的向量为<0.1, 0.5, 1.9, -1.1>,最大的一维是第三维,对应的字符则为“0010”,正好是“l”。这就是一个正确的预测。但从第一个“h”得到的输出向量是第四维最大,对应的并不是“e”,这样就产生代价。学习的过程就是不断降低这个代价。学习到的模型,对任何输入字符可以很好地不断预测下一个字符,如此一来就能生成句子或段落。
3 实践
下面是一个利用Char RNN实现写诗的应用,代码来自来自原先比较火的项目:https://github.com/jinfagang/tensorflow_poems,然后自己将其做成WEB应用,凑着学习了下如何使用tensorflow实现char rnn
def char_rnn(model,input_data,output_data,vocab_size,rnn_size=128,num_layers=2,batch_size=64, learning_rate=0.01): """ :param model: rnn单元的类型 rnn, lstm gru :param input_data: 输入数据 :param output_data: 输出数据 :param vocab_size: 词汇大小 :param rnn_size: :param num_layers: :param batch_size: :param learning_rate:学习率 :return: """ end_points = {} if model=='rnn': cell_fun=tf.contrib.rnn.BasicRNNCell elif model=='gru': cell_fun=tf.contrib.rnn.GRUCell elif model=='lstm': cell_fun=tf.contrib.rnn.BasicLSTMCell cell = cell_fun(rnn_size, state_is_tuple=True) cell = tf.contrib.rnn.MultiRNNCell([cell] * num_layers, state_is_tuple=True) if output_data is not None: initial_state = cell.zero_state(batch_size, tf.float32) else: initial_state = cell.zero_state(1, tf.float32) with tf.device("/cpu:0"): embedding=tf.get_variable('embedding',initializer=tf.random_uniform( [vocab_size+1,rnn_size],-1.0,1.0)) inputs=tf.nn.embedding_lookup(embedding,input_data) # [batch_size, ?, rnn_size] = [64, ?, 128] outputs, last_state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state) output = tf.reshape(outputs, [-1, rnn_size]) # logit计算 weights = tf.Variable(tf.truncated_normal([rnn_size, vocab_size + 1])) bias = tf.Variable(tf.zeros(shape=[vocab_size + 1])) logits = tf.nn.bias_add(tf.matmul(output, weights), bias=bias) # [?, vocab_size+1] if output_data is not None: # 独热编码 labels = tf.one_hot(tf.reshape(output_data, [-1]), depth=vocab_size + 1) # [?, vocab_size+1] loss = tf.nn.softmax_cross_entropy_with_logits(labels=labels, logits=logits) # [?, vocab_size+1] total_loss = tf.reduce_mean(loss) train_op = tf.train.AdamOptimizer(learning_rate).minimize(total_loss) end_points['initial_state'] = initial_state end_points['output'] = output end_points['train_op'] = train_op end_points['total_loss'] = total_loss end_points['loss'] = loss end_points['last_state'] = last_state else: prediction = tf.nn.softmax(logits) end_points['initial_state'] = initial_state end_points['last_state'] = last_state end_points['prediction'] = prediction return end_points
效果如下:
效果 1
效果 2
项目地址:https://github.com/yanqiangmiffy/char-rnn-writer/
4 参考资料
- yanqiangmiffy/char-rnn-writer: 基于Char RNN实现的“作家”应用,可以写诗也可以写小说,看起来还ok
- 【深度学习】文本生成 - Django's blog - 博客园
- 简单的Char RNN生成文本
- The Unreasonable Effectiveness of Recurrent Neural Networks
- Recurrent Neural Networks (RNN) – Part 1: Basic RNN / Char-RNN – The Neural Perspective
- Tensorflow下Char-RNN项目代码详解-学路网-学习路上 有我相伴
- hzy46/Char-RNN-TensorFlow: Multi-language Char RNN for TensorFlow >= 1.2.
- [译] RNN 循环神经网络系列 1:基本 RNN 与 CHAR-RNN-博客-云栖社区-阿里云
- 简单的Char RNN生成文本 - 简书