RNN循环神经网络的自我理解:基于Tensorflow的简单句子使用(通俗理解RNN)

解读tensorflow之rnn:

该开始接触RNN我们都会看到这样的张图:


 rnn_arch

 如上图可以看到每t-1时的forward的结果和t时的输入共同作为这一次forward的输入

所以RNN存在一定的弊端,就是如果输入足够的长,因为每一次forward都会带有之前数据的信息,就会使效果变差:

张三走了!天气也不错,我要去打篮球。”这句话的重点肯定在于天气不错所以我去打球,而不是因为张三走了,所以如果句子太长就会造成RNN在之后的训练中含有太多前面的冗余信息,使得效果变差。

为解决这类问题便有了LSTM,这里只做简单的RNN实现,便先不介绍。


RNN为什么有俩种形态? 先说结论:

  1. 左侧是RNN的原始结构, 右侧是RNN在时间上展开的图
  2. 我认为RNN本质上和全连接网络相同(全连接网络对一个样本做一次forward,RNN对一个样本做多次forward)

为什么可以根据时间维度展开,这主要是因为RNN的的输入是具有时间序列的。这一点是和全连接网络最大的不同,输入决定了RNN的结构 
假设RNN的输入是一句话,这句话中有多个单词,那么RNN需要forward多次,如下图 

 

  • 橙色部分是上一个时刻的隐层的值,可以直观的理解为“记忆”
  • 当前时刻的输出与当前时刻的输入还有记忆有关。
  • RNN对一个样本需要做多次forward,这一点与全连接网络不一样,全连接网络对一个样本只做一次forward。

 


 下面进行一个简单句子的RNN实现:(输入前一个字符预测它的后一个字符)

基于tensorflow的RNN实现中我们的难点只在与它参数的设置规则,深层次的处理不做研究。

1.首先做一个最基本的文本处理:

获取原字符串中含有字符的列表,循环遍历出列表内的值以及它的索引,构建新的字典(列表的值作为键,对应值的索引作为值),在字典里取出原句中包含所有字符的索引构成新的列表(由数字组成)。

看一张图: 这是一句 “hihello” 它进行rnn训练时某一时刻的流程图

 总体意思就是通过输入h预测i,i预测h,h预测e,以此类推,最后再次从头来过,通过这种不断循环更新这个字母后下面是哪一个字母出现的概率,来获得模型。

所以对于一句话来说:输入要去掉最后一个。输出要去掉第一个

sample = " 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) "
idx2char = list(set(sample)) # 去重放列表里

char2idx = {c: i for i, c in enumerate(idx2char)} # 转为字典  把字母作为键 它的索引作为值
sample_idx = [char2idx[c] for c in sample] # char to index 在字典里取出对应值
x_data = [sample_idx[:-1]] # 输入 去掉最后一个
y_data = [sample_idx[1:]]   #输出 去掉第一个
print(x_data)
print(y_data)

2.设置构建RNN所需要的参数

rnn_hidden_size是可以自己设定的,在下一篇

实验:构建cell时num_units的个数怎么影响输出

中展示。

dic_size = len(char2idx) #字典长度
rnn_hidden_size = len(char2idx)  # 单元个数 cell中神经元的个数
num_classes = len(char2idx) 
batch_size = 1 #    一个样本数据,一个批次
sequence_length = len(sample) - 1 #   序列的个数

3.定义占位符并且进行独热编码的转化

X = tf.placeholder(tf.int32, [None, sequence_length]) # X data
Y = tf.placeholder(tf.int32, [None, sequence_length]) # Y label
X_one_hot = tf.one_hot(X, num_classes) # one hot: 1 -> 0 1 0 0 0 0 0 0 0 0

4.构建RNN

state_is_tuple=True 必须写 它规定了状态信息的格式

initial_state = cell.zero_state(batch_size, tf.float32)为RNN的初始化状态,一般都这样定义

cell = tf.contrib.rnn.BasicLSTMCell(num_units=rnn_hidden_size, state_is_tuple=True)
initial_state = cell.zero_state(batch_size, tf.float32)

outputs, _states = tf.nn.dynamic_rnn(cell,  X_one_hot , initial_state=initial_state, dtype=tf.float32)

 5.加一层全连接,相当于加一层深度,使预测更准确

outputs = contrib.layers.fully_connected(inputs=outputs, num_outputs=num_classes, activation_fn=None)

6.定义损失、训练过程和结果的获取

weight为t时与t+1时之间的权重

最后的outputs是三维的 所以axis=2

weights = tf.ones([batch_size, sequence_length])

sequence_loss = tf.contrib.seq2seq.sequence_loss(logits=outputs, targets=Y,weights=weights)
loss = tf.reduce_mean(sequence_loss)
train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss)

prediction = tf.argmax(outputs, axis=2)

 7.进行训练的输入和打印结果

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    # print(sess.run(X_one_hot,feed_dict={X: x_data}))
    for i in range(3000):
        l, _ = sess.run([loss, train], feed_dict={X: x_data, Y: y_data})
        result = sess.run(prediction, feed_dict={X: x_data})
        # print char using dic
        result_str = [idx2char[c] for c in np.squeeze(result)]
        print(i, "loss:", l, "Prediction:", ''.join(result_str))
    print(len(result_str))

整体代码为:

import warnings
warnings.filterwarnings('ignore')
import tensorflow as tf
from tensorflow.contrib import rnn
from tensorflow import contrib
import numpy as np

sample = " 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) "
idx2char = list(set(sample)) # 去重放列表里

char2idx = {c: i for i, c in enumerate(idx2char)} # 转为字典  把字母作为键 它的索引作为值
sample_idx = [char2idx[c] for c in sample] #  在字典里取出对应值
x_data = [sample_idx[:-1]] # 输入 去掉最后一个
y_data = [sample_idx[1:]]   #输出 去掉第一个
print(x_data)
print(y_data)
# 一些参数
dic_size = len(char2idx) 
rnn_hidden_size = len(char2idx)  
num_classes = len(char2idx) 
batch_size = 1 
sequence_length = len(sample) - 1

X = tf.placeholder(tf.int32, [None, sequence_length]) # X data
Y = tf.placeholder(tf.int32, [None, sequence_length]) # Y label
X_one_hot = tf.one_hot(X, num_classes) 

cell = tf.contrib.rnn.BasicLSTMCell(num_units=rnn_hidden_size, state_is_tuple=True)
initial_state = cell.zero_state(batch_size, tf.float32)

outputs, _states = tf.nn.dynamic_rnn(cell,  X_one_hot , initial_state=initial_state, dtype=tf.float32)

outputs = contrib.layers.fully_connected(inputs=outputs, num_outputs=num_classes, activation_fn=None)

weights = tf.ones([batch_size, sequence_length])

sequence_loss = tf.contrib.seq2seq.sequence_loss(logits=outputs, targets=Y,weights=weights)
loss = tf.reduce_mean(sequence_loss)
train = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss)

prediction = tf.argmax(outputs, axis=2)


with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    # print(sess.run(X_one_hot,feed_dict={X: x_data}))
    for i in range(3000):
        l, _ = sess.run([loss, train], feed_dict={X: x_data, Y: y_data})
        result = sess.run(prediction, feed_dict={X: x_data})
        # print char using dic
        result_str = [idx2char[c] for c in np.squeeze(result)]
        print(i, "loss:", l, "Prediction:", ''.join(result_str))
    print(len(result_str))

输出结果为:

可以看到循环3000次训练的结果与原句子完全一致!!!

2991 loss: 0.101450786 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2992 loss: 0.10137266 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2993 loss: 0.1012946 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2994 loss: 0.10121668 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2995 loss: 0.10113874 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2996 loss: 0.101061 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2997 loss: 0.10098329 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2998 loss: 0.10090562 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 
2999 loss: 0.10082806 Prediction: 这是一个基于tensorflow的RNN短句子练习 (CSDN_qihao) 

 遗留问题:

构建cell时num_units的个数怎么影响输出???

解决方式点这里!!RNN:构建cell时num_units的个数怎么影响输出

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值