700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > RNN循环神经网络的直观理解:基于TensorFlow的简单RNN例子

RNN循环神经网络的直观理解:基于TensorFlow的简单RNN例子

时间:2019-05-21 00:20:20

相关推荐

RNN循环神经网络的直观理解:基于TensorFlow的简单RNN例子

RNN 直观理解

一个非常棒的RNN入门Anyone Can learn To Code LSTM-RNN in Python(Part 1: RNN)基于此文章,本文给出我自己的一些愚见基于此文章,给出其中代码的TensorFlow的实现版本。完整代码请看这里

RNN的结构

如果从网上搜索关于RNN的结构图,大概可以下面的结构图

第一次看到这样的图,我是懵逼的,这货怎么有两种形态? 先说结论:

左侧是RNN的原始结构, 右侧是RNN在时间上展开的结果RNN的结构,本质上和全连接网络相同

为什么可以根据时间维度展开,这主要是因为RNN的的输入是具有时间序列的。这一点是和全连接网络最大的不同,输入决定了RNN的结构

假设RNN的输入是一句话,这句话中有多个单词,那么RNN需要forward多次,如下图

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

就将RNN看成是全连接网络吧

将RNN看成是全连接网络就能很好的理解它。

将上面gif图中的隐层中的每一个神经元看成是LSTM单元,就得到了基于LSTM的RNNRNN的输入、输出都和全连接网络一模一样RNN只是一个需要做好多次forward的全连接网络

一个RNN的简单例子

基于TensorFlow,搭建一个RNN,教会神经网络进行二进制加法。参考Anyone Can learn To Code LSTM-RNN in Python(Part 1: RNN)

import tensorflow as tfimport numpy as np# 一个字典,隐射一个数字到其二进制的表示# 例如 int2binary[3] = [0,0,0,0,0,0,1,1]int2binary = {}# 最多8位二进制binary_dim = 8# 在8位情况下,最大数为2^8 = 256largest_number = pow(2,binary_dim)# 将[0,256)所有数表示成二进制binary = np.unpackbits(np.array([range(largest_number)],dtype=np.uint8).T,axis=1)# 建立字典for i in range(largest_number):int2binary[i] = binary[i]def binary_generation(numbers, reverse = False):'''返回numbers中所有数的二进制表达,例如 numbers = [3, 2, 1]返回 :[[0,0,0,0,0,0,1,1],[0,0,0,0,0,0,1,0],[0,0,0,0,0,0,0,1]'如果 reverse = True, 二进制表达式前后颠倒,这么做是为训练方便,因为训练的输入顺序是从低位开始的numbers : 一组数字reverse : 是否将其二进制表示进行前后翻转'''binary_x = np.array([ int2binary[num] for num in numbers], dtype=np.uint8)if reverse:binary_x = np.fliplr(binary_x)return binary_xdef batch_generation(batch_size, largest_number):'''生成batch_size大小的数据,用于训练或者验证batch_x 大小为[batch_size, biniary_dim, 2]batch_y 大小为[batch_size, biniray_dim]'''# 随机生成batch_size个数n1 = np.random.randint(0, largest_number//2, batch_size)n2 = np.random.randint(0, largest_number//2, batch_size)# 计算加法结果add = n1 + n2# int to binarybinary_n1 = binary_generation(n1, True)binary_n2 = binary_generation(n2, True)batch_y = binary_generation(add, True)# 堆叠,因为网络的输入是2个二进制batch_x = np.dstack((binary_n1, binary_n2))return batch_x, batch_y, n1, n2, adddef binary2int(binary_array):'''将一个二进制数组转为整数'''out = 0for index, x in enumerate(reversed(binary_array)):out += x*pow(2, index)return out

设置参数

batch_size = 64# LSTM的个数,就是隐层中神经元的数量lstm_size = 20# 隐层的层数lstm_layers =2

定义输入输出

# 输入,[None, binary_dim, 2], # None表示batch_size, binary_dim表示输入序列的长度,2表示每个时刻有两个输入x = tf.placeholder(tf.float32, [None, binary_dim, 2], name='input_x')# 输出y_ = tf.placeholder(tf.float32, [None, binary_dim], name='input_y')# dropout 参数keep_prob = tf.placeholder(tf.float32, name='keep_prob')

建立模型

# 搭建LSTM层(看成隐层)# 有lstm_size个单元lstm = tf.contrib.rnn.BasicLSTMCell(lstm_size)# dropoutdrop = tf.contrib.rnn.DropoutWrapper(lstm, output_keep_prob=keep_prob)# 一层不够,就多来几层def lstm_cell():return tf.contrib.rnn.BasicLSTMCell(lstm_size)cell = tf.contrib.rnn.MultiRNNCell([ lstm_cell() for _ in range(lstm_layers)])# 初始状态,可以理解为初始记忆initial_state = cell.zero_state(batch_size, tf.float32)# 进行forward,得到隐层的输出# outputs 大小为[batch_size, lstm_size*binary_dim]outputs, final_state = tf.nn.dynamic_rnn(cell, x, initial_state=initial_state)# 建立输出层weights = tf.Variable(tf.truncated_normal([lstm_size, 1], stddev=0.01))bias = tf.zeros([1])# [batch_size, lstm_size*binary_dim] ==> [batch_size*binary_dim, lstm_size]outputs = tf.reshape(outputs, [-1, lstm_size])# 得到输出, logits大小为[batch_size*binary_dim, 1]logits = tf.sigmoid(tf.matmul(outputs, weights))# [batch_size*binary_dim, 1] ==> [batch_size, binary_dim]predictions = tf.reshape(logits, [-1, binary_dim])

损失函数和优化方法

cost = tf.losses.mean_squared_error(y_, predictions)optimizer = tf.train.AdamOptimizer().minimize(cost)

12

训练

steps = 2000with tf.Session() as sess:tf.global_variables_initializer().run()iteration = 1for i in range(steps):# 获取训练数据input_x, input_y,_,_,_ = batch_generation(batch_size, largest_number)_, loss = sess.run([optimizer, cost], feed_dict={x:input_x, y_:input_y, keep_prob:0.5})if iteration % 1000 == 0:print('Iter:{}, Loss:{}'.format(iteration, loss)) iteration += 1# 训练结束,进行测试val_x, val_y, n1, n2, add = batch_generation(batch_size, largest_number)result = sess.run(predictions, feed_dict={x:val_x, y_:val_y, keep_prob:1.0})# 左右翻转二进制数组。因为输出的结果是低位在前,而正常的表达是高位在前,因此进行翻转result = np.fliplr(np.round(result))result = result.astype(np.int32)for b_x, b_p, a, b, add in zip(np.fliplr(val_x), result, n1, n2, add):print('{}:{}'.format(b_x[:,0], a))print('{}:{}'.format(b_x[:,1], b))print('{}:{}\n'.format(b_p, binary2int(b_p)))

Iter:1000, Loss:0.012912601232528687Iter:2000, Loss:0.000789149955380708[0 1 0 1 0 0 1 0]:82[0 0 1 1 1 1 0 0]:60[1 0 0 0 1 1 1 0]:142[0 1 1 1 1 1 0 0]:124[0 1 1 0 0 0 1 0]:98[1 1 0 1 1 1 1 0]:222[0 0 0 1 1 0 1 0]:26[0 0 0 0 0 1 0 1]:5[0 0 0 1 1 1 1 1]:31[0 0 0 1 0 0 1 1]:19[0 0 1 0 1 0 0 1]:41[0 0 1 1 1 1 0 0]:60[0 1 0 1 1 0 1 1]:91[0 1 0 0 0 0 0 0]:64[1 0 0 1 1 0 1 1]:155[0 1 0 1 0 1 0 0]:84[0 0 0 0 1 1 0 1]:13[0 1 1 0 0 0 0 1]:97[0 1 0 0 1 0 1 1]:75[0 0 1 0 0 0 0 1]:33[0 1 1 0 1 1 0 0]:108[0 0 1 1 0 1 0 0]:52[0 1 1 1 0 0 1 0]:114[1 0 1 0 0 1 1 0]:166[0 1 1 1 0 0 0 0]:112[0 0 1 0 1 1 0 1]:45[1 0 0 1 1 1 0 1]:157[0 0 1 1 0 1 0 1]:53[0 1 0 0 0 0 0 1]:65[0 1 1 1 0 1 1 0]:118[0 0 0 0 1 0 1 1]:11[0 1 1 0 0 1 0 1]:101[0 1 1 1 0 0 0 0]:112[0 0 0 0 1 1 0 0]:12[0 0 1 0 0 1 0 0]:36[0 0 1 1 0 0 0 0]:48[0 0 0 0 1 0 0 1]:9[0 1 1 0 0 0 0 1]:97[0 1 1 0 1 0 1 0]:106[0 0 0 1 1 1 1 0]:30[0 1 0 0 0 0 0 1]:65[0 1 0 1 1 1 1 1]:95[0 0 0 1 0 0 1 1]:19[0 1 0 0 0 0 0 1]:65[0 1 0 1 0 1 0 0]:84[0 1 1 0 1 1 0 0]:108[0 0 1 0 0 0 0 1]:33[1 0 0 0 1 1 0 1]:141[0 0 1 1 1 1 1 1]:63[0 0 1 0 0 0 0 1]:33[0 1 1 0 0 0 0 0]:96[0 0 0 1 0 1 1 1]:23[0 0 0 1 1 1 0 1]:29[0 0 1 1 0 1 0 0]:52[0 0 1 1 1 1 0 0]:60[0 1 0 0 1 0 0 1]:73[1 0 0 0 0 1 0 1]:133[0 1 0 0 1 1 0 0]:76[0 1 1 1 0 1 1 1]:119[1 1 0 0 0 0 1 1]:195[0 1 1 0 1 1 1 1]:111[0 0 0 1 1 0 0 1]:25[1 0 0 0 1 0 0 0]:136[0 0 1 1 0 0 0 1]:49[0 1 1 0 1 0 0 0]:104[1 0 0 1 1 0 0 1]:153[0 1 1 1 1 1 0 0]:124[0 1 1 0 1 0 1 1]:107[1 1 1 0 0 1 1 1]:231[0 0 1 1 1 0 1 1]:59[0 0 0 1 1 0 1 1]:27[0 1 0 1 0 1 1 0]:86[0 1 1 0 0 0 0 0]:96[0 0 0 1 1 1 0 1]:29[0 1 1 1 1 1 0 1]:125[0 0 1 1 1 0 1 0]:58[0 1 0 0 0 1 0 0]:68[0 1 1 1 1 1 1 0]:126[0 0 1 1 1 1 1 0]:62[0 1 1 0 0 1 1 1]:103[1 0 1 0 0 1 0 1]:165[0 1 1 1 1 0 0 0]:120[0 0 1 0 1 1 1 0]:46[1 0 1 0 0 1 1 0]:166[0 0 0 0 1 1 0 1]:13[0 0 1 1 0 0 0 0]:48[0 0 1 1 1 1 0 1]:61[0 0 1 0 0 1 0 0]:36[0 0 1 1 0 0 0 1]:49[0 1 0 1 0 1 0 1]:85..............[0 0 1 0 0 1 1 0]:38[0 1 0 0 1 1 0 1]:77[0 1 1 1 0 0 1 1]:115[0 1 0 1 1 1 1 0]:94[0 0 1 1 1 1 1 1]:63[1 0 0 1 1 1 0 1]:157[0 0 0 0 0 0 1 0]:2[0 1 0 1 0 0 0 0]:80[0 1 0 1 0 0 1 0]:82

总结

本文向大家介绍了RNN的结构,以及从全连接网络的角度出去,去理解RNN,得到结论有:

RNN的结构与全连接网络基本一致RNN具有时间展开的特点,这是由其输入决定的全连接网络对一个样本做一次forward,RNN对一个样本做多次forward

同时,基于TensorFlow给出一个简单的RNN网络,从实验结果看,该网络经过训练,以及能够正确进行二进制加法

原文:/weiwei9363/article/details/78902455

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。