循环神经网络RNN-写诗

数据下载

下载地址:https://pan.baidu.com/s/19fAqY0_ajkTiKfOBbpY_Sg

训练

数据预处理

import collections
import numpy as np
import tensorflow as tf


poetry_file = 'data/poetry.txt'

# 数据清洗,生成诗集
poetrys = []
with open(poetry_file, "r", encoding='utf-8') as f:
for line in f:
try:
line = line.strip(u'\n') #strip() 方法用于移除字符串头尾指定的字符
title, content = line.strip(u' ').split(u':')
content = content.replace(u' ', u'')
if u'_' in content or u'(' in content or u'(' in content or u'《' in content or u'[' in content:
continue
if len(content) < 5 or len(content) > 79:
continue
content = u'[' + content + u']'
poetrys.append(content)
except Exception as e:
pass
# print(poetrys[0])

# 按诗的字数排序
poetrys = sorted(poetrys, key=lambda lines: len(lines))
print('唐诗总数: ', len(poetrys))

# 统计每个字出现次数
all_words = []
for poetry in poetrys:
all_words += [word for word in poetry]
counter = collections.Counter(all_words) #Counter是一个无序的容器类型,以字典的键值对形式存储,其中元素作为key,其计数作为value。
count_pairs = sorted(counter.items(), key=lambda x: -x[1])
words, _ = zip(*count_pairs)

# 取前多少个常用字
words = words[:len(words)] + (' ',)
# 每个字映射为一个数字ID
word_num_map = dict(zip(words, range(len(words))))
# 把诗转换为向量形式.
trans_to_num = lambda word: word_num_map.get(word, len(words))
poetrys_vector = [list(map(trans_to_num, poetry)) for poetry in poetrys]


class DataSet(object):
def __init__(self, data_size):
self._data_size = data_size
self._epochs_completed = 0
self._index_in_epoch = 0
self._data_index = np.arange(data_size)

def next_batch(self, batch_size):
start = self._index_in_epoch
if start + batch_size > self._data_size:
np.random.shuffle(self._data_index)
self._epochs_completed = self._epochs_completed + 1
self._index_in_epoch = batch_size
full_batch_features, full_batch_labels = self.data_batch(0, batch_size)
return full_batch_features, full_batch_labels

else:
self._index_in_epoch += batch_size
end = self._index_in_epoch
full_batch_features, full_batch_labels = self.data_batch(start, end)
if self._index_in_epoch == self._data_size:
self._index_in_epoch = 0
self._epochs_completed = self._epochs_completed + 1
np.random.shuffle(self._data_index)
return full_batch_features, full_batch_labels

def data_batch(self, start, end):
batches = []
for i in range(start, end):
batches.append(poetrys_vector[self._data_index[i]])

length = max(map(len, batches))

xdata = np.full((end - start, length), word_num_map[' '], np.int32)
for row in range(end - start):
xdata[row, :len(batches[row])] = batches[row]
ydata = np.copy(xdata)
ydata[:, :-1] = xdata[:, 1:]
return xdata, ydata

构建RNN网络计算图

# 每次取64首诗进行训练
batch_size = 64
n_chunk = len(poetrys_vector) // batch_size

input_data = tf.placeholder(tf.int32, [batch_size, None])
output_targets = tf.placeholder(tf.int32, [batch_size, None])


# 定义RNN
def neural_network(model='lstm', rnn_size=128, num_layers=2):
global cell_fun
if model == 'rnn':
cell_fun = tf.nn.rnn_cell.BasicRNNCell
elif model == 'gru':
cell_fun = tf.nn.rnn_cell.GRUCell
elif model == 'lstm':
cell_fun = tf.nn.rnn_cell.BasicLSTMCell

cell = cell_fun(rnn_size, state_is_tuple=True)
cell = tf.nn.rnn_cell.MultiRNNCell([cell] * num_layers, state_is_tuple=True)

initial_state = cell.zero_state(batch_size, tf.float32)

with tf.variable_scope('rnnlm'):
softmax_w = tf.get_variable("softmax_w", [rnn_size, len(words)])
softmax_b = tf.get_variable("softmax_b", [len(words)])
with tf.device("/cpu:0"):
embedding = tf.get_variable("embedding", [len(words), rnn_size])
inputs = tf.nn.embedding_lookup(embedding, input_data)

outputs, last_state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state, scope='rnnlm')
output = tf.reshape(outputs, [-1, rnn_size])

logits = tf.matmul(output, softmax_w) + softmax_b
probs = tf.nn.softmax(logits)
return logits, last_state, probs, cell, initial_state

训练模型

def load_model(sess, saver, ckpt_path):
latest_ckpt = tf.train.latest_checkpoint(ckpt_path)
if latest_ckpt:
print('resume from', latest_ckpt)
saver.restore(sess, latest_ckpt)
return int(latest_ckpt[latest_ckpt.rindex('-') + 1:])
else:
print('building model from Training....')
sess.run(tf.global_variables_initializer())
return -1


# 训练
def train_neural_network():
logits, last_state, _, _, _ = neural_network()
targets = tf.reshape(output_targets, [-1])
loss = tf.contrib.legacy_seq2seq.sequence_loss_by_example([logits], [targets],
[tf.ones_like(targets, dtype=tf.float32)],
len(words))
##这个函数用于计算所有examples(假设一句话有n个单词,一个单词及单词所对应的label就是一个example,所有example就是一句话中所有单词)的加权交叉熵损失
cost = tf.reduce_mean(loss)
tf.summary.scalar('loss', tf.reshape(cost, []))##画损失图

learning_rate = tf.Variable(0.0, trainable=False)
tvars = tf.trainable_variables()##返回的是需要训练的变量列表
grads, _ = tf.clip_by_global_norm(tf.gradients(cost, tvars), 5)##tf.gradients:计算梯度;tf.clip_by_global_norm(t_list 是梯度张量, clip_norm 是截取的比率)让权重的更新限制在一个合适的范围

optimizer = tf.train.AdamOptimizer(learning_rate)
train_op = optimizer.apply_gradients(zip(grads, tvars))

Session_config = tf.ConfigProto(allow_soft_placement=True)
Session_config.gpu_options.allow_growth = True

trainds = DataSet(len(poetrys_vector))

with tf.Session(config=Session_config) as sess:
merged = tf.summary.merge_all()##tensorflow的可视化是使用summary和tensorboard合作完成的.###########tf.summary.merge_all: 将之前定义的所有summary op整合到一起
log_writer = tf.summary.FileWriter("logs", sess.graph)
sess.run(tf.initialize_all_variables())
saver = tf.train.Saver(tf.all_variables())
last_epoch = load_model(sess, saver, 'model/')
for epoch in range(last_epoch + 1, 1000):
sess.run(tf.assign(learning_rate, 0.002 * (0.97 ** epoch))) #tf.assign(A, new_number): 这个函数的功能主要是把A的值变为new_number
all_loss = 0.0
for batche in range(n_chunk):
x, y = trainds.next_batch(batch_size)
train_loss, _, _, merged_summary = sess.run([cost, last_state, train_op, merged],
feed_dict={input_data: x, output_targets: y})
all_loss = all_loss + train_loss
if batche % 50 == 1:
log_writer.add_summary(merged_summary, batche)
print("epoch:{} \n".format(epoch),
"batch:{} \n".format(batche),
"Learning_rate:{} \n".format(0.002 * (0.97 ** epoch)),
"train_loss:{} \n".format(train_loss))

print(epoch, ' Loss: ', all_loss * 1.0 / n_chunk)
saver.save(sess, 'model/poetry.module-%d' % epoch)
log_writer.close()

train_neural_network()

生成古诗

数据预处理

import collections
import numpy as np
import tensorflow as tf

poetry_file = 'data/poetry.txt'

# 诗集
poetrys = []
with open(poetry_file, "r", encoding='utf-8') as f:
for line in f:
try:
line = line.strip(u'\n')
title, content = line.strip(u' ').split(u':')
content = content.replace(u' ', u'')
if u'_' in content or u'(' in content or u'(' in content or u'《' in content or u'[' in content:
continue
if len(content) < 5 or len(content) > 79:
continue
content = u'[' + content + u']'
poetrys.append(content)
except Exception as e:
pass

# 按诗的字数排序
poetrys = sorted(poetrys, key=lambda line: len(line))
print('唐诗总数: ', len(poetrys))

# 统计每个字出现次数
all_words = []
for poetry in poetrys:
all_words += [word for word in poetry]
counter = collections.Counter(all_words)
count_pairs = sorted(counter.items(), key=lambda x: -x[1])
words, _ = zip(*count_pairs)

# 取前多少个常用字
words = words[:len(words)] + (' ',)
# 每个字映射为一个数字ID
word_num_map = dict(zip(words, range(len(words))))
# 把诗转换为向量形式
to_num = lambda word: word_num_map.get(word, len(words))
poetrys_vector = [list(map(to_num, poetry)) for poetry in poetrys]


# 每次取64首诗进行训练
batch_size = 1
n_chunk = len(poetrys_vector) // batch_size


# ---------------------------------------RNN--------------------------------------#

input_data = tf.placeholder(tf.int32, [batch_size, None])
output_targets = tf.placeholder(tf.int32, [batch_size, None])


# 定义RNN
def neural_network(model='lstm', rnn_size=128, num_layers=2):
global cell_fun
if model == 'rnn':
cell_fun = tf.nn.rnn_cell.BasicRNNCell
elif model == 'gru':
cell_fun = tf.nn.rnn_cell.GRUCell
elif model == 'lstm':
cell_fun = tf.nn.rnn_cell.BasicLSTMCell

cell = cell_fun(rnn_size, state_is_tuple=True)
cell = tf.nn.rnn_cell.MultiRNNCell([cell] * num_layers, state_is_tuple=True)

initial_state = cell.zero_state(batch_size, tf.float32)

with tf.variable_scope('rnnlm'):
softmax_w = tf.get_variable("softmax_w", [rnn_size, len(words)])
softmax_b = tf.get_variable("softmax_b", [len(words)])
with tf.device("/cpu:0"):
embedding = tf.get_variable("embedding", [len(words), rnn_size])
inputs = tf.nn.embedding_lookup(embedding, input_data)

outputs, last_state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state, scope='rnnlm')
output = tf.reshape(outputs, [-1, rnn_size])

logits = tf.matmul(output, softmax_w) + softmax_b
probs = tf.nn.softmax(logits)
return logits, last_state, probs, cell, initial_state

用训练完成的模型生成古诗

def gen_head_poetry(heads, type):
if type != 5 and type != 7:
print('The second para has to be 5 or 7!')
return

def to_word(weights):
t = np.cumsum(weights)#a = np.array([[1,2,3], [4,5,6]])### np.cumsum(a)###array([ 1, 3, 6, 10, 15, 21])####array([1,1+2=3,1+2+3=6,1+2+3+4=10,1+2+3+4+5=15,1+2+3+4+5+6=21])
s = np.sum(weights)
sample = int(np.searchsorted(t, np.random.rand(1) * s))##np.random.rand(3,2)##括号中为shape##np.searchsorted:寻找某个数应该插在数组的什么位置上,这个数组必须是按序排列的
return words[sample]

_, last_state, probs, cell, initial_state = neural_network()
Session_config = tf.ConfigProto(allow_soft_placement=True)
Session_config.gpu_options.allow_growth = True

with tf.Session(config=Session_config) as sess:
with tf.device('/gpu:1'):

sess.run(tf.initialize_all_variables())

saver = tf.train.Saver(tf.all_variables())
saver.restore(sess, 'model/poetry.module-99')
poem = ''
for head in heads:
flag = True
while flag:

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

x = np.array([list(map(word_num_map.get, u'['))])
[probs_, state_] = sess.run([probs, last_state], feed_dict={input_data: x, initial_state: state_})

sentence = head

x = np.zeros((1, 1))
x[0, 0] = word_num_map[sentence]
[probs_, state_] = sess.run([probs, last_state], feed_dict={input_data: x, initial_state: state_})
word = to_word(probs_)
sentence += word

while word != u'。':
x = np.zeros((1, 1))
x[0, 0] = word_num_map[word]
[probs_, state_] = sess.run([probs, last_state],
feed_dict={input_data: x, initial_state: state_})
word = to_word(probs_)
sentence += word

if len(sentence) == 2 + 2 * type:
sentence += u'\n'
poem += sentence
flag = False

return poem


def gen_poetry():
def to_word(weights):
t = np.cumsum(weights)
s = np.sum(weights)
sample = int(np.searchsorted(t, np.random.rand(1) * s))
return words[sample]

_, last_state, probs, cell, initial_state = neural_network()

with tf.Session() as sess:
sess.run(tf.initialize_all_variables())
saver = tf.train.Saver(tf.all_variables())
saver.restore(sess, 'model/poetry.module-99')
state_ = sess.run(cell.zero_state(1, tf.float32))
x = np.array([list(map(word_num_map.get, '['))])
[probs_, state_] = sess.run([probs, last_state], feed_dict={input_data: x, initial_state: state_})
word = to_word(probs_)
poem = ''
while word != '[':
poem += word
x = np.zeros((1, 1))
x[0, 0] = word_num_map[word]
[probs_, state_] = sess.run([probs, last_state], feed_dict={input_data: x, initial_state: state_})
word = to_word(probs_)
return poem


#print(gen_poetry())
print(gen_head_poetry(u'言叶之庭', 5))
------ 本文结束 🎉🎉 谢谢观看 ------
0%