最近又忍不住把RNN这一块儿的东西给过了一遍,感觉还是有一些收获!所以想着给记录下来,因为也看到有人给我提意见说:我写的关于算法的文章太多了,还是要好好搞学术研究,所以就想着最近多更几篇关于深度学习网络方面的文章。

关于RNN循环神经网络的具体概念我就不细讲了,稍微把概念给提下吧,然后会说说其变形模型,以及会给出两个demo讲述其在不同领域的应用,方便大家理解!

1. RNN循环神经网络介绍

RNN循环神经网络 怎么实现 rnn循环神经网络实例_tensorflow

上面这张图算是最最最经典的也是最一般的RNN网络结构了。

RNN循环神经网络 怎么实现 rnn循环神经网络实例_RNN循环神经网络 怎么实现_02

 因为要讲解步骤,所以用这张图来表示步骤,上图其实是把RNN给展开成我们熟悉的全连接神经网络了,这样我们会比较熟悉。步骤如下:

RNN循环神经网络 怎么实现 rnn循环神经网络实例_RNN循环神经网络_03

基于上述步骤可实现一简单的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),具体结构如下图所示:

RNN循环神经网络 怎么实现 rnn循环神经网络实例_数据_04

在这个demo里我们是没用到output这个LSTM cell的,不是说它没用哈,而是在后面提到的Seq2Seq模型中会用到这个值。

3. RNN神经网络预测下一个字符

不知道大家发现没有,上面讲到的这个最基础的RNN模型中输入数据的“维度”与输出数据的“维度”是一一对应的,即Xt与Ot是相对应的。但是在实际应用中这种情形太少了,跟多的是N->M的关系,即输入数据的维度”与输出数据的“维度”是不同的。比如在机器翻译应用中,将一段汉语翻译成英文。汉语是:我英语不好,翻译成英文是:my English is poor 此处N=5,M=4明显是N与M不相等的情形,此时我们要怎么解决这个模型呢?

RNN循环神经网络 怎么实现 rnn循环神经网络实例_RNN循环神经网络_05

那问题就来了,此时我们要怎么解决这个模型呢?

为此得引入一种新的模型,这种结构又叫Encoder-Decoder模型,也可以称之为Seq2Seq模型。如下图所示:

RNN循环神经网络 怎么实现 rnn循环神经网络实例_RNN循环神经网络_06

 

还有一种做法是将c当做每一步的输入:

 

RNN循环神经网络 怎么实现 rnn循环神经网络实例_python_07

按照这个模型,我接下来将会给出能预测下一个字符的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起来的结果如下:

RNN循环神经网络 怎么实现 rnn循环神经网络实例_RNN循环神经网络 怎么实现_08

 

RNN循环神经网络 怎么实现 rnn循环神经网络实例_数据_09

可以看到:效果还是不错的!暂时就分享到这儿了,有想到更好的东西再来补充!