tensorflow(七)——基于RNN、LSTM进行正弦函数sin预测

一、基础知识

RNN:存储了隐藏层的输出作为下一次的输入,网络具有时序信息

双向RNN:正向反向传递上一层的记忆,组合形成输出

从RNN到LSTM:RNN存在梯度消失,梯度爆炸的现象,所以对记忆体的存储更新做了修改,原来RNN是无限制更新记忆体的值,而LSTM对记忆体的存入,取出以及保存都通过门来限制。

梯度消失、梯度爆炸:是由反向传播链式求导法则中的连乘导致的,导数\权重初始化\网络深度\不恰当的非线性方法等因素一叠加,就会导致靠近输入层的地方发生梯度消失、梯度爆炸的问题

https://blog.csdn.net/raojunyang/article/details/79962665

https://blog.csdn.net/sinat_32502811/article/details/82716426

LSTM:有三个门,输入门、输出门、遗忘门,所用的激活函数多为sigmoid(输出在0到1之间,符合门的性质)

中间蓝色的c为记忆体,输入门控制输入响应f(Zi),可使输入无效;遗忘门控制记忆体c,可使之前的记忆无效,输出门控制记忆体的响应,可使输出无效。

二、应用场景

    文本自动生成(写诗、写歌词),客服机器人

文本自动生成机器人

参考理解链接:https://blog.csdn.net/irving_zhang/article/details/76664998

工程代码:https://github.com/jinfagang/tensorflow_poems

 

三、LSTM实例说明

本例来源及更多LSTM的简单示例及函数说明,详见:https://blog.csdn.net/xierhacker/article/details/78772560

本例取了一个sin函数的y点,利用前几个点来预测后一个点的值,几个点间具有时序的联系。建立的网络是两层LSTM。

有意思的是,从自己展开RNN代码来看,输入是按照序列一个个输入的,不是一下子全输进去((cell_output, state) = multi_lstm(X_p[:, timestep, :], state))。与全连接网络及cnn不同,lstm的输入是一个batch内一个个按照序列输入的(例如输入x1、h0得到h1)。

下图一展示了多次迭代中测试结果,下图二是进行50次迭代后的结果,50次后已能基本拟合。

网络有两个隐藏层,从输入到输出的大小为:

【(None,Time_steps,1),30,1,(None,1)】

 

    

import numpy as np
import tensorflow as tf
import tensorflow.contrib.rnn as rnn
import matplotlib.pyplot as plt

TIME_STEPS=10
BATCH_SIZE=128
HIDDEN_UNITS1=30
HIDDEN_UNITS=1
LEARNING_RATE=0.001
EPOCH=50

TRAIN_EXAMPLES=11000
TEST_EXAMPLES=1100

#------------------------------------Generate Data-----------------------------------------------#
#generate data
#数据的生成先利用linspace生成等分割点,再根据sin函数得到弦值,每个batch都是训练数据为前TIME_STEPS个数,标签为后一个数,也就是用前几个数预测后一个数据
#训练数据和测试数据的linespace分别取了[0,100],[100,110],这样就不同了
def generate(seq):
    X=[]
    y=[]
    for i in range(len(seq)-TIME_STEPS):
        X.append([seq[i:i+TIME_STEPS]])
        y.append([seq[i+TIME_STEPS]])
    return np.array(X,dtype=np.float32),np.array(y,dtype=np.float32)


seq_train=np.sin(np.linspace(start=0,stop=100,num=TRAIN_EXAMPLES,dtype=np.float32))
seq_test=np.sin(np.linspace(start=100,stop=110,num=TEST_EXAMPLES,dtype=np.float32))


X_train,y_train=generate(seq_train)
#print(X_train.shape,y_train.shape)
X_test,y_test=generate(seq_test)#X_test是前TIME_STEPS个数据,y_test是后一个数据

#reshape to (batch,time_steps,input_size)
X_train=np.reshape(X_train,newshape=(-1,TIME_STEPS,1))#这里的作用是增加最后一个维度
X_test=np.reshape(X_test,newshape=(-1,TIME_STEPS,1))

#draw y_test
plt.plot(range(1000),y_test[:1000,0],"r*")

#-----------------------------------------------------------------------------------------------------#


#--------------------------------------Define Graph---------------------------------------------------#
graph=tf.Graph()
with graph.as_default():

    #------------------------------------construct LSTM------------------------------------------#
    #place hoder
    X_p=tf.placeholder(dtype=tf.float32,shape=(None,TIME_STEPS,1),name="input_placeholder")
    y_p=tf.placeholder(dtype=tf.float32,shape=(None,1),name="pred_placeholder")

    #lstm instance
    lstm_cell1=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS1)#30
    lstm_cell=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS)#1

    multi_lstm=rnn.MultiRNNCell(cells=[lstm_cell1,lstm_cell])
    ## 初始状态,可以理解为初始记忆

    init_state = multi_lstm.zero_state(batch_size=BATCH_SIZE, dtype=tf.float32)

    # 使用dynamic rnn通过指定的RNN Cell来展开计算神经网络
    outputs, states = tf.nn.dynamic_rnn(cell=multi_lstm, inputs=X_p, initial_state=init_state, dtype=tf.float32)
    # print(outputs.shape)#(128,10,1)
    h = outputs[:, -1, :]


    # #自己展开RNN计算
    # outputs = list()                                    #用来接收存储每步的结果
    # state = init_state
    # with tf.variable_scope('RNN'):
    #     for timestep in range(TIME_STEPS):#TIME_STEPS为一个batch训练数据数量,这里的序列是一个个输入的
    #         if timestep > 0:
    #             tf.get_variable_scope().reuse_variables()#timestep=0首次输入,>0为后续输入
    #         # 这里的state保存了每一层 LSTM 的状态
    #         (cell_output, state) = multi_lstm(X_p[:, timestep, :], state)######网络输入输出
    #         outputs.append(cell_output)
    # h = outputs[-1]#取了最后的输出作为输出


    #---------------------------------define loss and optimizer----------------------------------#
    mse=tf.losses.mean_squared_error(labels=y_p,predictions=h)#均方误差
    #print(loss.shape)
    optimizer=tf.train.AdamOptimizer(LEARNING_RATE).minimize(loss=mse)

    init=tf.global_variables_initializer()


#-------------------------------------------Define Session---------------------------------------#
with tf.Session(graph=graph) as sess:
    sess.run(init)
    for epoch in range(1,EPOCH+1):#迭代次数
        results = np.zeros(shape=(TEST_EXAMPLES, 1))
        train_losses=[]
        test_losses=[]
        print("epoch:",epoch)
        for j in range(TRAIN_EXAMPLES//BATCH_SIZE):#训练数据是根据batch_size划分成了几块
            _,train_loss=sess.run(
                    fetches=(optimizer,mse),#这里通过运行optimizer进行train,测试时不进行优化就是测试了
                    feed_dict={
                            X_p:X_train[j*BATCH_SIZE:(j+1)*BATCH_SIZE],
                            y_p:y_train[j*BATCH_SIZE:(j+1)*BATCH_SIZE]
                        }
            )
            train_losses.append(train_loss)#train_losses记录了单次迭代中,每次batch的损失
        print("average training loss:", sum(train_losses) / len(train_losses))


        for j in range(TEST_EXAMPLES//BATCH_SIZE):#测试是在单次迭代后进行的,可以比较多次迭代后的效果
            result,test_loss=sess.run(
                    fetches=(h,mse),#有别于训练时运行fetches=(optimizer,mse)
                    feed_dict={
                            X_p:X_test[j*BATCH_SIZE:(j+1)*BATCH_SIZE],
                            y_p:y_test[j*BATCH_SIZE:(j+1)*BATCH_SIZE]
                        }
            )
            results[j*BATCH_SIZE:(j+1)*BATCH_SIZE]=result
            test_losses.append(test_loss)
        print("average test loss:", sum(test_losses) / len(test_losses))
    plt.plot(range(1000),results[:1000,0])#利用前1k个点作图 ,这句放到for循环里就可以看出优化过程了
    plt.show()

、RNN实例说明

    本部分基于第三部分的代码实现了基于RNN预测sin曲线,只需要将lstm核换成rnn核,即替换成以下的代码。肉眼未见测试结果图有何区别。

    #place hoder
    X_p=tf.placeholder(dtype=tf.float32,shape=(None,TIME_STEPS,1),name="input_placeholder")
    y_p=tf.placeholder(dtype=tf.float32,shape=(None,1),name="pred_placeholder")

    # #lstm instance
    # lstm_cell1=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS1)#30
    # lstm_cell=rnn.BasicLSTMCell(num_units=HIDDEN_UNITS)#1
    # multi_lstm=rnn.MultiRNNCell(cells=[lstm_cell1,lstm_cell])
    # #rnn instance
    cell1 = tf.nn.rnn_cell.BasicRNNCell(num_units=HIDDEN_UNITS1)
    cell2=tf.nn.rnn_cell.BasicRNNCell(num_units=HIDDEN_UNITS)
    multi_RNN = rnn.MultiRNNCell(cells=[cell1, cell2])
    
    init_state = multi_RNN.zero_state(batch_size=BATCH_SIZE, dtype=tf.float32)

    # 使用dynamic rnn通过指定的RNN Cell来展开计算神经网络
    outputs, states = tf.nn.dynamic_rnn(cell=multi_RNN, inputs=X_p, initial_state=init_state, dtype=tf.float32)
    # print(outputs.shape)#(128,10,1)
    h = outputs[:, -1, :]


五、机器翻译

    端到端建立源语言到目标语言的对应关系,使用序列到序列的模型,联合了两个循环神经网络:一个网络接收要源句子,一个输出成翻译的语句。即编解码过程,编码过程利用RNN的记忆功能,保留最后一个隐藏状态;解码器接收一个标识符作为一句话的开始,输入网络得到的输出作为第一个词,输入第一个词得到第二个词。。。编码器获得最后一个隐藏状态作为内容向量供解码器使用。

使用循环神经网络的原因:语句存在序列前后关系

使用序列到序列结构的原因:输入长度与输出长度可以不同;词与词见的前后关系可以颠倒;

参考网址:

https://blog.csdn.net/xierhacker/article/details/73384760

https://blog.csdn.net/xierhacker/article/details/78772560

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章