In [ ]:
# -*- coding: utf-8 -*-
########################################################################################################
####################第一步:准备样本####################################################################
##########################################################################################################


#######1、定义基本工具函数################################################################################
###引入头文件,然后定义相关函数########################################################################
import numpy as np
import tensorflow as tf
from tensorflow.contrib import rnn
import random
import time
from collections import Counter
start_time = time.time()
def elapsed(sec):
    if sec<60:
        return str(sec) + " sec"
    elif sec<(60*60):
        return str(sec/60) + " min"
    else:
        return str(sec/(60*60)) + " hr"


# 目标日志路径
tf.reset_default_graph()
training_file = 'wordstest.txt'


#处理多个中文文件
def readalltxt(txt_files):
    labels = []
    for txt_file in txt_files:
        
        target = get_ch_lable(txt_file)  #从文件里获取文本
        labels.append(target)  
    return labels
    
#处理汉字
def get_ch_lable(txt_file):  
    labels= ""
    with open(txt_file, 'rb') as f:
        for label in f: 
            #labels =label.decode('utf-8')
            labels =labels+label.decode('gb2312')
           
    return  labels
    

#优先转文件里的字符到向量
def get_ch_lable_v(txt_file,word_num_map,txt_label=None):#将文本数组转换成向量
      
    words_size = len(word_num_map)   
    to_num = lambda word: word_num_map.get(word, words_size) 
    if txt_file!= None:
        txt_label = get_ch_lable(txt_file)

    labels_vector = list(map(to_num, txt_label)) 
    return labels_vector  


####2 、样本预处理#########################################################################################
##########读取整体样本
training_data =get_ch_lable(training_file)

print("Loaded training data...")

print(len(training_data))
counter = Counter(training_data)  
words = sorted(counter)
words_size= len(words)
word_num_map = dict(zip(words, range(words_size))) 
print(word_num_map)

print('字表大小:', words_size)   
#将文本数组转换为向量
wordlabel = get_ch_lable_v(training_file,word_num_map)
print (wordlabel)




############################################################################################################
########第二步:构建模型####################################################################################
###############################################################################################################


###############1、参数设置################################################################################################
#学习率为0.001,迭代10000次,每1000次输出一次中间状态。每次输入4个字,来预测第5个字。
learning_rate = 0.001
training_iters = 10000    
display_step = 1000      
n_input = 4

#网络模型使用了3层的lstm,第一层为256个cell,第二层和第三层都是512个cell.
n_hidden1 = 256
n_hidden2 = 512
n_hidden3 = 512
# 定义占位符
x = tf.placeholder("float", [None, n_input,1])    #输入4个连续的汉字
wordy = tf.placeholder("float", [None, words_size]) #代表一个字,


######2、定义网络结构####################################################################################


#将x形状变换并按照时间序列裁分
x1 = tf.reshape(x, [-1, n_input])
x2 = tf.split(x1,n_input,1)

# 3层LSTM,每层有n_hidden个units
rnn_cell = rnn.MultiRNNCell([rnn.LSTMCell(n_hidden1),rnn.LSTMCell(n_hidden2),rnn.LSTMCell(n_hidden3)])

# 通过RNN得到输出,
outputs, states = rnn.static_rnn(rnn_cell, x2, dtype=tf.float32)
print (outputs)
# 通过全连接输出指定维度
pred = tf.contrib.layers.fully_connected(outputs[-1],words_size,activation_fn = None)

# 3、定义优化器
####tf.nn.softmax_cross_entropy_with_logits:计算交叉熵;tf.reduce_mean:计算均值
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=pred, labels=wordy))
####创建了一个优化函数AdamOptimizer,并基于一定的学习速率进行梯度训练。minimize():按照loss的最小值方向更新参数
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(loss)

# 模型评估
correct_pred = tf.equal(tf.argmax(pred,1), tf.argmax(wordy,1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))


##########4、训练模型########################################################################################################
##在训练过程中同样添加保存检查点功能。在session中每次随机取一个偏移量,然后取后面4个文字向量当作输入,
#第5个文字向量当成标签来计算loss
############################################################################################################


savedir = "A:/Users/yhh/Desktop/RNN实例/"
saver = tf.train.Saver(max_to_keep=1) # 生成saver

# 启动session
with tf.Session() as session:
    session.run(tf.global_variables_initializer())
    step = 0
    offset = random.randint(0,n_input+1)
    end_offset = n_input + 1
    acc_total = 0
    loss_total = 0
    
    kpt = tf.train.latest_checkpoint(savedir)
    print("kpt:",kpt)
    startepo= 0
    if kpt!=None:
        saver.restore(session, kpt) 
        ind = kpt.find("-")
        startepo = int(kpt[ind+1:])
        print(startepo)
        step = startepo

    while step < training_iters:

        # 随机取一个位置偏移
        if offset > (len(training_data)-end_offset):
            offset = random.randint(0, n_input+1)
       
        inwords = [ [wordlabel[ i]] for i in range(offset, offset+n_input) ]#按照指定的位置偏移获取后面的4个文字向量当作输入

        inwords = np.reshape(np.array(inwords), [-1, n_input, 1])

        out_onehot= np.zeros([words_size], dtype=float)
        out_onehot[wordlabel[offset+n_input]] = 1.0
        out_onehot = np.reshape(out_onehot,[1,-1])#所有的字都变成onehot

        _, acc, lossval, onehot_pred = session.run([optimizer, accuracy, loss, pred],feed_dict={x: inwords, wordy: out_onehot})
        loss_total += lossval
        acc_total += acc
        if (step+1) % display_step == 0:
            print("Iter= " + str(step+1) + ", Average Loss= " + \
                  "{:.6f}".format(loss_total/display_step) + ", Average Accuracy= " + \
                  "{:.2f}%".format(100*acc_total/display_step))
            acc_total = 0
            loss_total = 0
            in2 = [words [wordlabel[i]] for i in range(offset, offset + n_input)]
            out2 = words [wordlabel[offset + n_input]]
            out_pred=words[int(tf.argmax(onehot_pred, 1).eval())]
            print("%s - [%s] vs [%s]" % (in2,out2,out_pred))            
            saver.save(session, savedir+"./rnnwordtest.cpkt", global_step=step)
        step += 1
        offset += (n_input+1)#中间隔了一个,作为预测
        
    print("Finished!")
    saver.save(session, savedir+"./rnnwordtest.cpkt", global_step=step)
    print("Elapsed time: ", elapsed(time.time() - start_time))

    
    ##########5、运行模型生成句子##################################################################################################
#####启用一个循环,等待输入文字,当收到输入文本后,通过eval计算onehot_pred节点,并进行文字的转义,得到预测文字。
####接下来将预测文字在循环输入模型中,预测下一个文字。代码中设置循环32次,输出32个字。
###########################################################################################################


    while True:
        prompt = "请输入%s个字: " % n_input
        sentence = input(prompt)
        inputword = sentence.strip()
        
        if len(inputword) != n_input:
            print("您输入的字符长度为:",len(inputword),"请输入4个字")
            continue
        try:
            inputword = get_ch_lable_v(None,word_num_map,inputword)
           
            for i in range(32):
                keys = np.reshape(np.array(inputword), [-1, n_input, 1])
                onehot_pred = session.run(pred, feed_dict={x: keys})
                onehot_pred_index = int(tf.argmax(onehot_pred, 1).eval())
                sentence = "%s%s" % (sentence,words[onehot_pred_index])
                inputword = inputword[1:]
                inputword.append(onehot_pred_index)
            print(sentence)
        except:
            print("该字我还没学会")


Loaded training data...
97
{'、': 0, '。': 1, '一': 2, '不': 3, '世': 4, '中': 5, '为': 6, '了': 7, '以': 8, '们': 9, '会': 10, '信': 11, '光': 12, '再': 13, '凡': 14, '前': 15, '力': 16, '只': 17, '在': 18, '地': 19, '坚': 20, '头': 21, '守': 22, '尘': 23, '就': 24, '己': 25, '平': 26, '心': 27, '念': 28, '悬': 29, '想': 30, '懈': 31, '我': 32, '所': 33, '扰': 34, '持': 35, '挂': 36, '方': 37, '普': 38, '气': 39, '注': 40, '活': 41, '淀': 42, '灌': 43, '灯': 44, '理': 45, '琐': 46, '生': 47, '的': 48, '着': 49, '神': 50, '种': 51, '积': 52, '立': 53, '站': 54, '粹': 55, '精': 56, '纷': 57, '自': 58, '蕴': 59, '藉': 60, '行': 61, '要': 62, '走': 63, '远': 64, '通': 65, '都': 66, '默': 67, ',': 68}
字表大小: 69
[18, 23, 4, 48, 57, 34, 5, 68, 17, 62, 27, 21, 29, 36, 49, 64, 37, 48, 44, 12, 68, 32, 9, 24, 10, 20, 35, 3, 31, 19, 63, 68, 45, 30, 6, 32, 9, 43, 40, 7, 56, 50, 48, 59, 60, 1, 33, 8, 68, 47, 41, 13, 26, 14, 0, 13, 38, 65, 0, 13, 46, 55, 68, 32, 9, 66, 62, 20, 35, 2, 51, 11, 28, 68, 67, 22, 2, 51, 56, 50, 68, 6, 58, 25, 52, 42, 54, 53, 48, 11, 27, 68, 15, 61, 48, 39, 16]
WARNING:tensorflow:From <ipython-input-1-2c6582665411>:112: LSTMCell.__init__ (from tensorflow.python.ops.rnn_cell_impl) is deprecated and will be removed in a future version.
Instructions for updating:
This class is equivalent as tf.keras.layers.LSTMCell, and will be replaced by that in Tensorflow 2.0.
WARNING:tensorflow:From <ipython-input-1-2c6582665411>:112: MultiRNNCell.__init__ (from tensorflow.python.ops.rnn_cell_impl) is deprecated and will be removed in a future version.
Instructions for updating:
This class is equivalent as tf.keras.layers.StackedRNNCells, and will be replaced by that in Tensorflow 2.0.
WARNING:tensorflow:From <ipython-input-1-2c6582665411>:115: static_rnn (from tensorflow.python.ops.rnn) is deprecated and will be removed in a future version.
Instructions for updating:
Please use `keras.layers.RNN(cell, unroll=True)`, which is equivalent to this API
WARNING:tensorflow:From A:\annaconda3\envs\python3\lib\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.
[<tf.Tensor 'rnn/rnn/multi_rnn_cell/cell_2/lstm_cell/mul_2:0' shape=(?, 512) dtype=float32>, <tf.Tensor 'rnn/rnn/multi_rnn_cell/cell_2/lstm_cell/mul_5:0' shape=(?, 512) dtype=float32>, <tf.Tensor 'rnn/rnn/multi_rnn_cell/cell_2/lstm_cell/mul_8:0' shape=(?, 512) dtype=float32>, <tf.Tensor 'rnn/rnn/multi_rnn_cell/cell_2/lstm_cell/mul_11:0' shape=(?, 512) dtype=float32>]
WARNING:tensorflow:From <ipython-input-1-2c6582665411>:122: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.
Instructions for updating:

Future major versions of TensorFlow will allow gradients to flow
into the labels input on backprop by default.

See `tf.nn.softmax_cross_entropy_with_logits_v2`.

kpt: A:/Users/yhh/Desktop/RNN实例/./rnnwordtest.cpkt-10000
WARNING:tensorflow:From A:\annaconda3\envs\python3\lib\site-packages\tensorflow\python\training\saver.py:1266: checkpoint_exists (from tensorflow.python.training.checkpoint_management) is deprecated and will be removed in a future version.
Instructions for updating:
Use standard file APIs to check for files with this prefix.
INFO:tensorflow:Restoring parameters from A:/Users/yhh/Desktop/RNN实例/./rnnwordtest.cpkt-10000
10000
Finished!
Elapsed time:  2.736156463623047 sec
请输入4个字: 我们就会
我们就会坚持不懈地走,理力为我们灌注了精神的再平,默守一种精扰,灯站立光
请输入4个字: 咦咦咦一
咦咦咦一所以,生活再平凡、再普通、再琐粹,力心以种纷扰持为我纷前,的气力
请输入4个字: 咦咦咦咦
咦咦咦咦为所以,注活再平,默守一种精扰,灯站立光,我头就挂不懈地走,理力
请输入4个字: 黄垚黄垚
黄垚黄垚为所以,注活再平,默守一种精扰,灯站立光,我头就挂不懈地走,理力
请输入4个字: 1111
1111为所以,注活再平,默守一种精扰,灯站立光,我头就挂不懈地走,理力
请输入4个字: ****
****为所以,注活再平,默守一种精扰,灯站立光,我头就挂不懈地走,理力

In [ ]:


In [ ]: