赞
踩
最近又忍不住把RNN这一块儿的东西给过了一遍,感觉还是有一些收获!所以想着给记录下来,因为也看到有人给我提意见说:我写的关于算法的文章太多了,还是要好好搞学术研究,所以就想着最近多更几篇关于深度学习网络方面的文章。
关于RNN循环神经网络的具体概念我就不细讲了,稍微把概念给提下吧,然后会说说其变形模型,以及会给出两个demo讲述其在不同领域的应用,方便大家理解!
1. RNN循环神经网络介绍
上面这张图算是最最最经典的也是最一般的RNN网络结构了。
因为要讲解步骤,所以用这张图来表示步骤,上图其实是把RNN给展开成我们熟悉的全连接神经网络了,这样我们会比较熟悉。步骤如下:
基于上述步骤可实现一简单的RNN神经网络,核心流程如下demo所示:
- import numpy as np
- import os
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
-
- X = [1, 2]
- state = [0.0, 0.0]
- # 定义不同输入部分的权重
- w_cell_state = np.asarray([[0.1, 0.2], [0.3, 0.4]])
- w_cell_input = np.asarray([0.5, 0.6])
- b_cell = np.asarray([0.1, -0.1])
- # 定义输出层的权重
- w_output = np.asarray([[0.1], [0.2]])
- b_output = 0.1
- # 按照时间顺序执行循环神经网络的前向传播过程
- for i in range(len(X)):
- before_activation = np.dot(state, w_cell_state) + X[i]*w_cell_input+b_cell
- state = np.tanh(before_activation)
- # 计算当前时刻的最终输出
- final_output = np.dot(state, w_output) + b_output
- # 输出每一时刻的信息
- print("before_activation", before_activation)
- print("state", state)
- print("final_output", final_output)

只说这个最简单的网络,肯定是没有意思的!所以接下来我会分享一个用RNN来识别手写字体的demo。
2. RNN神经网络识别手写字体
- import tensorflow as tf
- from tensorflow.examples.tutorials.mnist import input_data
- from tensorflow.contrib import rnn
- import os
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
-
- # 载入数据
- mnist = input_data.read_data_sets("MNIST_data", one_hot=True)
-
- # 设置模型的参数
- # 对应输入图片的宽
- n_inputs = 28
- # 对应输入图片的行
- max_time = 28
- # 隐藏单元,实质上不是神经元,即LSTM单元
- lstm_size = 100
- # 图片总共有10个分类
- n_classes = 10
- # 每批次总共有50个样本
- batch_size = 50
- n_batch = mnist.train.num_examples//batch_size
-
- # 这里的None=50
- x = tf.placeholder(tf.float32, [None, 784])
- y = tf.placeholder(tf.float32, [None, 10])
-
- # 初始化权值
- weights = tf.Variable(tf.truncated_normal([lstm_size, n_classes], stddev=0.1))
- # 初始化偏置值
- biases = tf.Variable(tf.constant(0.1, shape=[n_classes]))
-
-
- # 定义RNN网络
- def RNN(X, weights, biases):
- inputs = tf.reshape(X, [-1, max_time, n_inputs])
- lstm_cell = rnn.BasicLSTMCell(lstm_size)
- # outputs维度为shape=(?, 28, 100);final_state维度为shape=(?, 100)
- outputs, final_state = tf.nn.dynamic_rnn(lstm_cell, inputs, dtype=tf.float32)
- print("shape(outputs)", outputs)
- print("shape(final_state)", final_state)
- # 如果使用Seq2Seq模型,则调用outputs;反之则使用final_state
- results = tf.nn.softmax(tf.matmul(final_state[1], weights)+biases)
- return results
-
-
- # 计算RNN的返回结果
- prediction = RNN(x, weights, biases)
- # 损失函数--交叉熵
- cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y, logits=prediction))
- # 使用AdamOptimizer进行优化
- train_op = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
- # 结果放在一个布尔型列表中
- crroect_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(prediction, 1))
- # 求准确率
- accuracy = tf.reduce_mean(tf.cast(crroect_prediction, tf.float32))
-
- # 开始训练模型
- with tf.Session() as sess:
- sess.run(tf.global_variables_initializer())
- for epoch in range(10):
- for batch in range(n_batch):
- batch_xs, batch_ys = mnist.train.next_batch(batch_size)
- sess.run(train_op, feed_dict={x: batch_xs, y:batch_ys})
- acc = sess.run(accuracy, feed_dict={x: mnist.test.images, y: mnist.test.labels})
- print("Iter "+str(epoch)+", Testing Accuracy="+str(acc))

这个demo里有处地方我需要强调一下:
- outputs, final_state = tf.nn.dynamic_rnn(lstm_cell, inputs, dtype=tf.float32)
- # 如果使用Seq2Seq模型,则调用outputs;反之则使用final_state
- results = tf.nn.softmax(tf.matmul(final_state[1], weights)+biases)
这里面outputs维度为shape=(?, 28, 100);final_state维度为shape=(?, 100),具体结构如下图所示:
在这个demo里我们是没用到output这个LSTM cell的,不是说它没用哈,而是在后面提到的Seq2Seq模型中会用到这个值。
3. RNN神经网络预测下一个字符
不知道大家发现没有,上面讲到的这个最基础的RNN模型中输入数据的“维度”与输出数据的“维度”是一一对应的,即Xt与Ot是相对应的。但是在实际应用中这种情形太少了,跟多的是N->M的关系,即输入数据的维度”与输出数据的“维度”是不同的。比如在机器翻译应用中,将一段汉语翻译成英文。汉语是:我英语不好,翻译成英文是:my English is poor 此处N=5,M=4明显是N与M不相等的情形,此时我们要怎么解决这个模型呢?
那问题就来了,此时我们要怎么解决这个模型呢?
为此得引入一种新的模型,这种结构又叫Encoder-Decoder模型,也可以称之为Seq2Seq模型。如下图所示:
还有一种做法是将c当做每一步的输入:
按照这个模型,我接下来将会给出能预测下一个字符的RNN模型
- import tensorflow as tf
- from tensorflow import contrib
- import numpy as np
- import os
- os.environ["TF_CPP_MIN_LOG_LEVEL"] = "2"
-
- sample = "这是一个基于tensorflow的RNN短句子练习"
- # 去重放入列表中
- idx2char = list(set(sample))
- print("idx2char", idx2char)
- # 转换为字典,其中把字母作键,索引作为值
- char2idx = {c: i for i, c in enumerate(idx2char)}
- # 在字典里取出对应值,因为在idx2char中原sample句子的顺序已经被打乱
- sample_idx = [char2idx[c] for c in sample]
- x_data = [sample_idx[:-1]]
- y_data = [sample_idx[1:]]
-
- # 设置该模型的一些参数
- 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])
- Y = tf.placeholder(tf.int32, [None, sequence_length])
- # 将input转化为one-hot类型数据输出,此时X的维度变为[None, sequence_length, num_classes]
- 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)
- print("outputs", tf.shape(outputs))
- weights = tf.ones([batch_size, sequence_length])
- # 此处包装了encoder和decoder
- 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())
- 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))

模型Run起来的结果如下:
可以看到:效果还是不错的!暂时就分享到这儿了,有想到更好的东西再来补充!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。