开发者社区> lusing> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

Tensorflow快餐教程(10) - 循环神经网络

简介: 循环神经网络:LSTM和GRU
+关注继续查看

循环神经网络

上节介绍了在图像和语音领域里大放异彩引发革命的CNN。但是,还有一类问题是CNN所不擅长的。这类问题的特点是上下文相关序列,比如理解文字。这时需要一种带有记忆的结构,于是,深度学习中的另一法宝RNN横空出世了。

大家还记得第8节中我们讲的人工神经网络的第二次复兴吗?没错,第二次复兴的标志正是1984年加州理工学院的物理学家霍普菲尔德实现了他于两年前提出的一种循环神经网络模型。这种网络被称为Hopfield网络。当时因为硬件条件的限制,Hopfield网络并没有得到广泛应用。而两年扣BP网络被重新发明,全连接前馈神经网络成为主流。RNN正是在Hopfield网络的基础上发展起来的。

RNN_rolled

RNN的图片都取自:https://colah.github.io/posts/2015-08-Understanding-LSTMs/

从图中我们可以看到,一个典型的循环神经网络神经元的结构,是在输入$X_t$之外,A与自己也有一个连接。

我们将其展开的话可能看得更清楚一些:
RNN_unrolled

也就是前一次输出的结果是对下一次输出有影响。

LSTM

RNN中增加了对于之前状态的记忆项,不能直接使用之前BP网络的梯度下降的方法。但是基于该方法将循环项的输入都考虑进来,这个改进方法叫做BPTT算法(Back-Propagation Through Time)。

但是这种方法有个隐患,就是输入序列过长时会出现梯度消散问题(the vanishing gradient problem)。

于是一个改进算法LSTM(Long short-term memory)就增加了一个遗忘的机制。

LSTM的细节我们放到后面详细讲。我们先看看在Tensorflow中如何实现一个LSTM模型:

def RNN(x, weights, biases):
    x = tf.unstack(x, timesteps, 1)

    lstm_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0)

    outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32)

    return tf.matmul(outputs[-1], weights['out']) + biases['out']

第一步准备数据,第二步创建一个LSTMCell,第三步连成一个RNN网络,第四步矩阵乘输出。

下面我们还是以第1讲的例子来用LSTM来处理MNIST分类问题,第一时间有个可以运行的代码:

from __future__ import print_function

import tensorflow as tf
from tensorflow.contrib import rnn

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

# 训练参数
learning_rate = 0.001
training_steps = 10000
batch_size = 128
display_step = 200

# 网络参数
num_input = 28 # MNIST data input (img shape: 28*28)
timesteps = 28 # timesteps
num_hidden = 128 # hidden layer num of features
num_classes = 10 # MNIST total classes (0-9 digits)

X = tf.placeholder("float", [None, timesteps, num_input])
Y = tf.placeholder("float", [None, num_classes])

# 初始权值
weights = {
    'out': tf.Variable(tf.random_normal([num_hidden, num_classes]))
}
biases = {
    'out': tf.Variable(tf.random_normal([num_classes]))
}

def RNN(x, weights, biases):
    x = tf.unstack(x, timesteps, 1)

    lstm_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0)

    outputs, states = rnn.static_rnn(lstm_cell, x, dtype=tf.float32)

    return tf.matmul(outputs[-1], weights['out']) + biases['out']

logits = RNN(X, weights, biases)
prediction = tf.nn.softmax(logits)

# 定义损失和优化函数
loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=logits, labels=Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss_op)

correct_pred = tf.equal(tf.argmax(prediction, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:

    sess.run(init)

    for step in range(1, training_steps+1):
        batch_x, batch_y = mnist.train.next_batch(batch_size)
        batch_x = batch_x.reshape((batch_size, timesteps, num_input))
        sess.run(train_op, feed_dict={X: batch_x, Y: batch_y})
        if step % display_step == 0 or step == 1:
            loss, acc = sess.run([loss_op, accuracy], feed_dict={X: batch_x,
                                                                 Y: batch_y})
            print("Step " + str(step) + ", Minibatch Loss= " + \
                  "{:.4f}".format(loss) + ", Training Accuracy= " + \
                  "{:.3f}".format(acc))

    print("Optimization Finished!")

    test_len = 128
    test_data = mnist.test.images[:test_len].reshape((-1, timesteps, num_input))
    test_label = mnist.test.labels[:test_len]
    print("Testing Accuracy:", \
        sess.run(accuracy, feed_dict={X: test_data, Y: test_label}))

门控循环单元GRU(Gated Recurrent Unit)

LSTM所使用的技术属于门控RNN(Gated RNN)技术。除了LSTM之外,还有一种应用广泛的门控RNN叫做GRU(Gated Recurrent Unit).

不同于1997年就发明的LSTM,GRU的技术比较新,提出在2014年。GRU与LSTM的不同在于,GRU同时可以控制『更新』门和『复位』门。
在Tensorflow中,使用tf.contrib.rnn.GRUCell来表示GRU单元。

到Tensorflow 1.8版本,一共支持5种单元,其中4种是LSTM单元,1种是GRU单元:

  • tf.contrib.rnn.BasicRNNCell
  • tf.contrib.rnn.BasicLSTMCell
  • tf.contrib.rnn.GRUCell
  • tf.contrib.rnn.LSTMCell
  • tf.contrib.rnn.LayerNormBasicLSTMCell

双向循环神经网络

从前面的LSTM的结构我们可以看到,它是有方向的。GRU是在LSTM基础上的改良,也是如此。就像一个链表一样。

那么,我们如果想同时支持两个方向该怎么办?这就是双向循环神经网络。

我们还是先看核心代码:

def BiRNN(x, weights, biases):
    x = tf.unstack(x, timesteps, 1)

    lstm_fw_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0)
    lstm_bw_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0)

    try:
        outputs, _, _ = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                              dtype=tf.float32)
    except Exception: 
        outputs = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                        dtype=tf.float32)

    return tf.matmul(outputs[-1], weights['out']) + biases['out']

别的没什么变化,就是前向和后向各需要一个单元,然后调用static_bidirectional_rnn来运行网络。

最后是双向RNN训练MNIST的完整代码:


from __future__ import print_function

import tensorflow as tf
from tensorflow.contrib import rnn
import numpy as np

from tensorflow.examples.tutorials.mnist import input_data
mnist = input_data.read_data_sets("/tmp/data/", one_hot=True)

learning_rate = 0.001
training_steps = 10000
batch_size = 128
display_step = 200

num_input = 28 # MNIST data input (img shape: 28*28)
timesteps = 28 # timesteps
num_hidden = 128 # hidden layer num of features
num_classes = 10 # MNIST total classes (0-9 digits)

X = tf.placeholder("float", [None, timesteps, num_input])
Y = tf.placeholder("float", [None, num_classes])

weights = {
     'out': tf.Variable(tf.random_normal([2*num_hidden, num_classes]))
}
biases = {
    'out': tf.Variable(tf.random_normal([num_classes]))
}

def BiRNN(x, weights, biases):

    x = tf.unstack(x, timesteps, 1)

    lstm_fw_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0)
    lstm_bw_cell = rnn.BasicLSTMCell(num_hidden, forget_bias=1.0)

    try:
        outputs, _, _ = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                              dtype=tf.float32)
    except Exception: # Old TensorFlow version only returns outputs not states
        outputs = rnn.static_bidirectional_rnn(lstm_fw_cell, lstm_bw_cell, x,
                                        dtype=tf.float32)

    return tf.matmul(outputs[-1], weights['out']) + biases['out']

logits = BiRNN(X, weights, biases)
prediction = tf.nn.softmax(logits)

loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(
    logits=logits, labels=Y))
optimizer = tf.train.GradientDescentOptimizer(learning_rate=learning_rate)
train_op = optimizer.minimize(loss_op)

correct_pred = tf.equal(tf.argmax(prediction, 1), tf.argmax(Y, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

init = tf.global_variables_initializer()

with tf.Session() as sess:

    sess.run(init)

    for step in range(1, training_steps+1):
        batch_x, batch_y = mnist.train.next_batch(batch_size)
        batch_x = batch_x.reshape((batch_size, timesteps, num_input))
        sess.run(train_op, feed_dict={X: batch_x, Y: batch_y})
        if step % display_step == 0 or step == 1:
            loss, acc = sess.run([loss_op, accuracy], feed_dict={X: batch_x,
                                                                 Y: batch_y})
            print("Step " + str(step) + ", Minibatch Loss= " + \
                  "{:.4f}".format(loss) + ", Training Accuracy= " + \
                  "{:.3f}".format(acc))

    print("Optimization Finished!")

    test_len = 128
    test_data = mnist.test.images[:test_len].reshape((-1, timesteps, num_input))
    test_label = mnist.test.labels[:test_len]
    print("Testing Accuracy:", \
        sess.run(accuracy, feed_dict={X: test_data, Y: test_label}))

小结

虽然已经讲了10节,但是前方还是有太多的未尽事业。但是我们不妨可以先复习一下之前的:
Tensorflow快餐教程(1) - 30行代码搞定手写识别:https://yq.aliyun.com/articles/582122
Tensorflow快餐教程(2) - 标量运算:https://yq.aliyun.com/articles/582490
Tensorflow快餐教程(3) - 向量:https://yq.aliyun.com/articles/584202
Tensorflow快餐教程(4) - 矩阵:https://yq.aliyun.com/articles/584526
Tensorflow快餐教程(5) - 范数:https://yq.aliyun.com/articles/584896
Tensorflow快餐教程(6) - 矩阵分解:https://yq.aliyun.com/articles/585599
Tensorflow快餐教程(7) - 梯度下降:https://yq.aliyun.com/articles/587350
Tensorflow快餐教程(8) - 深度学习简史:https://yq.aliyun.com/articles/588920
Tensorflow快餐教程(9) - 卷积:https://yq.aliyun.com/articles/590233

版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
深度学习实战:tensorflow训练循环神经网络让AI创作出模仿莎士比亚风格的作品
深度学习实战:tensorflow训练循环神经网络让AI创作出模仿莎士比亚风格的作品
0 0
《Scikit-Learn与TensorFlow机器学习实用指南》第14章 循环神经网络
第14章 循环神经网络 来源:ApacheCN《Sklearn 与 TensorFlow 机器学习实用指南》翻译项目 译者:@akonwang @alexcheen @飞龙 校对:@飞龙 击球手击出垒球,你会开始预测球的轨迹并立即开始奔跑。
1894 0
TensorFlow构建循环神经网络
前言 前面在《循环神经网络》文章中已经介绍了深度学习的循环神经网络模型及其原理,接下去这篇文章将尝试使用TensorFlow来实现一个循环神经网络,该例子能通过训练给定的语料生成模型并实现对字符的预测。
1202 0
金玉良缘易配而木石前盟难得|M1 Mac os(Apple Silicon)天生一对Python3开发环境搭建(集成深度学习框架Tensorflow/Pytorch)
笔者投入M1的怀抱已经有一段时间了,俗话说得好,但闻新人笑,不见旧人哭,Intel mac早已被束之高阁,而M1 mac已经不能用真香来形容了,简直就是“香透满堂金玉彩,扇遮半面桃花开!”,轻抚M1 mac那滑若柔荑的秒控键盘,别说996了,就是007,我们也能安之若素,也可以笑慰平生。好了,日常吹M1的环节结束,正所谓剑虽利,不厉不断,材虽美,不学不高。本次我们尝试在M1 Mac os 中搭建Python3的开发环境。
0 0
人工智能不过尔尔,基于Python3深度学习库Keras/TensorFlow打造属于自己的聊天机器人(ChatRobot)
聊天机器人(ChatRobot)的概念我们并不陌生,也许你曾经在百无聊赖之下和Siri打情骂俏过,亦或是闲暇之余与小爱同学谈笑风生,无论如何,我们都得承认,人工智能已经深入了我们的生活。目前市面上提供三方api的机器人不胜枚举:微软小冰、图灵机器人、腾讯闲聊、青云客机器人等等,只要我们想,就随时可以在app端或者web应用上进行接入。但是,这些应用的底层到底如何实现的?在没有网络接入的情况下,我们能不能像美剧[《西部世界》(Westworld)](https://movie.douban.com/subject/2338055/)里面描绘的那样,机器人只需要存储在本地的“心智球”就可以和人类沟
0 0
【深度学习框架TensorFlow】使用TensorFlow框架构建全连接的神经网络,实现手写数字识别
【深度学习框架TensorFlow】使用TensorFlow框架构建全连接的神经网络,实现手写数字识别
0 0
《TensorFlow深度学习应用实践》学习笔记1
《TensorFlow深度学习应用实践》学习笔记1
0 0
+关注
lusing
刘子瑛,阿里系统框架专家。工作十余年,一直对新编程语言、新开发方法、数学与算法相关和并发等相关领域保持浓厚的兴趣。乐于通过技术分享促进新技术。
文章
问答
文章排行榜
最热
最新
相关电子书
更多
深度学习框架实战-Tensorflow
立即下载
深度学习+大数据 TensorFlow on Yarn
立即下载
使用TensorFlow搭建智能开发系统自劢生成App UI代码
立即下载