TensorFlow实现RNN循环神经网络

RNN(recurrent neural Network)循环神经网络

主要用于自然语言处理(nature language processing,NLP)

RNN主要用途是处理和预测序列数据

RNN广泛的用于 语音识别、语言模型、机器翻译

RNN的来源就是为了刻画一个序列当前的输出与之前的信息影响后面节点的输出

RNN 是包含循环的网络,允许信息的持久化

RNN会记忆之前的信息,并利用之前的信息影响后面节点的输出

RNN的隐藏层之间的节点是有相连的,隐藏层的输入不仅仅包括输入层的输出,还包括上一时刻隐藏层的输出。

RNN会对于每一个时刻的输入结合当前模型的状态给出一个输出

RNN理论上被看作同一个神经网络结构被无限复制的结果,目前RNN无法做到真正的无限循环,一般以循环体展开。

RNN图:

RNN最擅长的问题是与时间序列相关的

RNN对于一个序列数据,可以将序列上不同时刻的数据依次输入循环神经网络的输入层,而输出可以是对序列中下一个时刻的预测,也可以是对当前时刻信息的处理结果。

RNN 的关键点之一就是他们可以用来连接先前的信息到当前的任务上

展开后的RNN

循环体网络中的参数在不同的时刻也是共享的

RNN的状态是通过一个向量来表示,这个向量的维度也称为RNN隐藏层的大小

假如该向量为h,输入为x,激活函数为tanh,则有如图:

前向传播的计算过程:

理论上RNN可以支持任意长度的序列,但是如果序列太长会导致优化时实现梯度消失的问题,一般会设置最大长度,超长会对其截断。

代码实现简单的RNN:

import numpy as np 

# 定义RNN的参数。
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([[1.0], [2.0]])
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 ("output: ", final_output) 

LSTM(long short-term memory)长短时记忆网络:

LSTM解决了RNN不支持长期依赖的问题,使其大幅度提升记忆时长

RNN被成功应用的关键就是LSTM。

LSTM是一种拥有三个“门”结构的特殊网络结构。

粉色的圈代表 pointwise 的操作,诸如向量的和,而黄色的矩阵就是学习到的神经网络层。合在一起的线表示向量的连接,分开的线表示内容被复制,然后分发到不同的位置。

LSTM核心思想:

LSTM 的关键就是细胞状态,水平线在图上方贯穿运行。

细胞状态类似于传送带。直接在整个链上运行,只有一些少量的线性交互,信息在上面流传保持不变会很容易。

LSTM 有通过精心设计的称作为“门”的结构来去除或者增加信息到细胞状态的能力

“门”是一种让信息选择式通过的方法,包含一个sigmoid 神经网络层和一个 pointwise (按位做乘法)的操作。

之所以称之为“门”,因为使用Sigmoid 作为激活函数的层会输出 0 到 1 之间的数值,描述每个部分有多少信息量可以通过这个结构。

0 代表“不许任何量通过”,1 就指“允许任意量通过”!

LSTM的公式:

代码实现:

import tensorflow as tf 

# 定义一个LSTM结构
lstm = rnn_cell.BasicLSTMCell(lstm_hidden_size) 

# 将LSTM中的状态初始化为全0数组,每次使用一个batch的训练样本
state = lstm.zero_state(batch_size,tf.float32) 

# 定义损失函数
loss = 0.0 

# 规定一个最大序列长度
for i in range(num_steps):
  # 复用之前定义的变量
  if i > 0:
    tf.get_variable_scope().reuse_variables()
  # 将当前输入和前一时刻的状态传入定义的LSTM结构,得到输出和更新后的状态
  lstm_output, state = lstm(current_input,state) 

  # 将当前时刻的LSTM结构的输出传入一个全连接层得到最后的输出。
  final_output = fully_connectd(lstm_output) 

  # 计算当前时刻输出的损失
  loss += calc_loss(final_output,expected_output) 

双向循环神经网络

经典的循环神经网络中的状态传输是从前往后单向的,然而当前时刻的输出不仅和之前的状态有关系,也和之后的状态相关。

双向循环神经网络能解决状态单向传输的问题

双向循环神经网络是由两个循环神经网络反向上下叠加在一起组成两个循环神经网络的状态共同决定输出

也就是时间t时的输出不仅仅取决于过去的记忆,也同样取决于后面发生的事情。

深层(双向)循环神经网络

深层循环神经网络似于双向循环神经网络,只不过是每个时长内都有多层

深层循环神经网络有更强的学习能力

深层循环神经网络在每个时刻上将循环体结构复制多次,和卷积神经网络类似,每一层循环体中的参数是一致的,不同层的参数可以不同

TensorFlow中使用MultiRNNCell实现深层循环神经网络中每一个时刻的前向传播过程。剩下的步骤和RNN的构建步骤相同。

RNN中的dropout

通过dropout方法可以上卷积神经网络更加健壮,类似的用在RNN上也能取得同样的效果。

类似卷积神经网络,RNN只在最后的全连接层使用dropout。

RNN一般只在不同层循环体结构中使用dropout,不在同层循环体使用。

同一时刻t中,不同循环体之间会使用dropout

在TensorFlow中,使用DropoutWrapper类实现dropout功能。

通过input_keep_prob参数控制输入的dropout概率

通过output_keep_prob参数控制输出的dropout概率

TensorFlow样例实现RNN语言模型

代码:

import numpy as np
import tensorflow as tf
import reader 

DATA_PATH = "../datasets/PTB/data"
HIDDEN_SIZE = 200 # 隐藏层规模
NUM_LAYERS = 2 # 深层RNN中的LSTM结构的层数
VOCAB_SIZE = 10000 # 单词标识符个数 

LEARNING_RATE = 1.0 # 学习速率
TRAIN_BATCH_SIZE = 20 # 训练数据大小
TRAIN_NUM_STEP = 35 # 训练数据截断长度 

# 测试时不需要截断
EVAL_BATCH_SIZE = 1 # 测试数据大小
EVAL_NUM_STEP = 1 # 测试数据截断长度
NUM_EPOCH = 2 # 使用训练数据轮数
KEEP_PROB = 0.5 # 节点不被dropout
MAX_GRAD_NORM = 5 # 控制梯度膨胀参数 

# 定义一个类来描述模型结构。
class PTBModel (object):
  def __init__(self, is_training, batch_size, num_steps): 

    self.batch_size = batch_size
    self.num_steps = num_steps 

    # 定义输入层。
    self.input_data = tf.placeholder (tf.int32, [batch_size, num_steps])
    self.targets = tf.placeholder (tf.int32, [batch_size, num_steps]) 

    # 定义使用LSTM结构及训练时使用dropout。
    lstm_cell = tf.contrib.rnn.BasicLSTMCell (HIDDEN_SIZE)
    if is_training:
      lstm_cell = tf.contrib.rnn.DropoutWrapper (lstm_cell, output_keep_prob=KEEP_PROB)
    cell = tf.contrib.rnn.MultiRNNCell ([lstm_cell] * NUM_LAYERS) 

    # 初始化最初的状态。
    self.initial_state = cell.zero_state (batch_size, tf.float32)
    embedding = tf.get_variable ("embedding", [VOCAB_SIZE, HIDDEN_SIZE]) 

    # 将原本单词ID转为单词向量。
    inputs = tf.nn.embedding_lookup (embedding, self.input_data) 

    if is_training:
      inputs = tf.nn.dropout (inputs, KEEP_PROB) 

    # 定义输出列表。
    outputs = []
    state = self.initial_state
    with tf.variable_scope ("RNN"):
      for time_step in range (num_steps):
        if time_step > 0: tf.get_variable_scope ().reuse_variables ()
        cell_output, state = cell (inputs[:, time_step, :], state)
        outputs.append (cell_output)
    output = tf.reshape (tf.concat (outputs, 1), [-1, HIDDEN_SIZE])
    weight = tf.get_variable ("weight", [HIDDEN_SIZE, VOCAB_SIZE])
    bias = tf.get_variable ("bias", [VOCAB_SIZE])
    logits = tf.matmul (output, weight) + bias 

    # 定义交叉熵损失函数和平均损失。
    loss = tf.contrib.legacy_seq2seq.sequence_loss_by_example (
      [logits],
      [tf.reshape (self.targets, [-1])],
      [tf.ones ([batch_size * num_steps], dtype=tf.float32)])
    self.cost = tf.reduce_sum (loss) / batch_size
    self.final_state = state 

    # 只在训练模型时定义反向传播操作。
    if not is_training: return
    trainable_variables = tf.trainable_variables () 

    # 控制梯度大小,定义优化方法和训练步骤。
    grads, _ = tf.clip_by_global_norm (tf.gradients (self.cost, trainable_variables), MAX_GRAD_NORM)
    optimizer = tf.train.GradientDescentOptimizer (LEARNING_RATE)
    self.train_op = optimizer.apply_gradients (zip (grads, trainable_variables)) 

# 使用给定的模型model在数据data上运行train_op并返回在全部数据上的perplexity值
def run_epoch(session, model, data, train_op, output_log, epoch_size):
  total_costs = 0.0
  iters = 0
  state = session.run(model.initial_state) 

  # 训练一个epoch。
  for step in range(epoch_size):
    x, y = session.run(data)
    cost, state, _ = session.run([model.cost, model.final_state, train_op],
                    {model.input_data: x, model.targets: y, model.initial_state: state})
    total_costs += cost
    iters += model.num_steps 

    if output_log and step % 100 == 0:
      print("After %d steps, perplexity is %.3f" % (step, np.exp(total_costs / iters)))
  return np.exp(total_costs / iters) 

# 定义主函数并执行
def main():
  train_data, valid_data, test_data, _ = reader.ptb_raw_data(DATA_PATH) 

  # 计算一个epoch需要训练的次数
  train_data_len = len(train_data)
  train_batch_len = train_data_len // TRAIN_BATCH_SIZE
  train_epoch_size = (train_batch_len - 1) // TRAIN_NUM_STEP 

  valid_data_len = len(valid_data)
  valid_batch_len = valid_data_len // EVAL_BATCH_SIZE
  valid_epoch_size = (valid_batch_len - 1) // EVAL_NUM_STEP 

  test_data_len = len(test_data)
  test_batch_len = test_data_len // EVAL_BATCH_SIZE
  test_epoch_size = (test_batch_len - 1) // EVAL_NUM_STEP 

  initializer = tf.random_uniform_initializer(-0.05, 0.05)
  with tf.variable_scope("language_model", reuse=None, initializer=initializer):
    train_model = PTBModel(True, TRAIN_BATCH_SIZE, TRAIN_NUM_STEP) 

  with tf.variable_scope("language_model", reuse=True, initializer=initializer):
    eval_model = PTBModel(False, EVAL_BATCH_SIZE, EVAL_NUM_STEP) 

  # 训练模型。
  with tf.Session() as session:
    tf.global_variables_initializer().run() 

    train_queue = reader.ptb_producer(train_data, train_model.batch_size, train_model.num_steps)
    eval_queue = reader.ptb_producer(valid_data, eval_model.batch_size, eval_model.num_steps)
    test_queue = reader.ptb_producer(test_data, eval_model.batch_size, eval_model.num_steps) 

    coord = tf.train.Coordinator()
    threads = tf.train.start_queue_runners(sess=session, coord=coord) 

    for i in range(NUM_EPOCH):
      print("In iteration: %d" % (i + 1))
      run_epoch(session, train_model, train_queue, train_model.train_op, True, train_epoch_size) 

      valid_perplexity = run_epoch(session, eval_model, eval_queue, tf.no_op(), False, valid_epoch_size)
      print("Epoch: %d Validation Perplexity: %.3f" % (i + 1, valid_perplexity)) 

    test_perplexity = run_epoch(session, eval_model, test_queue, tf.no_op(), False, test_epoch_size)
    print("Test Perplexity: %.3f" % test_perplexity) 

    coord.request_stop()
    coord.join(threads) 

if __name__ == "__main__":
  main() 

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • TensorFlow实现RNN循环神经网络

    RNN(recurrent neural Network)循环神经网络 主要用于自然语言处理(nature language processing,NLP) RNN主要用途是处理和预测序列数据 RNN广泛的用于 语音识别.语言模型.机器翻译 RNN的来源就是为了刻画一个序列当前的输出与之前的信息影响后面节点的输出 RNN 是包含循环的网络,允许信息的持久化. RNN会记忆之前的信息,并利用之前的信息影响后面节点的输出. RNN的隐藏层之间的节点是有相连的,隐藏层的输入不仅仅包括输入层的输出,还包

  • python人工智能tensorflow构建循环神经网络RNN

    目录 学习前言 RNN简介 tensorflow中RNN的相关函数 tf.nn.rnn_cell.BasicLSTMCell tf.nn.dynamic_rnn 全部代码 学习前言 在前一段时间已经完成了卷积神经网络的复习,现在要对循环神经网络的结构进行更深层次的明确. RNN简介 RNN 是当前发展非常火热的神经网络中的一种,它擅长对序列数据进行处理. 什么是序列数据呢?举个例子. 现在假设有四个字,“我” “去” “吃” “饭”.我们可以对它们进行任意的排列组合. “我去吃饭”,表示的就是我

  • 基于循环神经网络(RNN)的古诗生成器

    基于循环神经网络(RNN)的古诗生成器,具体内容如下 之前在手机百度上看到有个"为你写诗"功能,能够随机生成古诗,当时感觉很酷炫= = 在学习了深度学习后,了解了一下原理,打算自己做个实现练练手,于是,就有了这个项目.文中如有瑕疵纰漏之处,还请路过的诸位大佬不吝赐教,万分感谢! 使用循环神经网络实现的古诗生成器,能够完成古体诗的自动生成.我简单地训练了一下,格式是对上了,至于意境么...emmm,呵呵 举一下模型测试结果例子: 1.生成古体诗 示例1: 树阴飞尽水三依,谩自为能厚景奇.

  • 基于循环神经网络(RNN)实现影评情感分类

    使用循环神经网络(RNN)实现影评情感分类 作为对循环神经网络的实践,我用循环神经网络做了个影评情感的分类,即判断影评的感情色彩是正面的,还是负面的. 选择使用RNN来做情感分类,主要是因为影评是一段文字,是序列的,而RNN对序列的支持比较好,能够"记忆"前文.虽然可以提取特征词向量,然后交给传统机器学习模型或全连接神经网络去做,也能取得很好的效果,但只从端对端的角度来看的话,RNN无疑是最合适的. 以下介绍实现过程. 一.数据预处理 本文中使用的训练数据集为https://www.c

  • python循环神经网络RNN函数tf.nn.dynamic_rnn使用

    目录 学习前言 tf.nn.dynamic_rnn的定义 tf.nn.dynamic_rnn的使用举例 单层实验 多层实验 学习前言 已经完成了RNN网络的构建,但是我们对于RNN网络还有许多疑问,特别是tf.nn.dynamic_rnn函数,其具体的应用方式我们并不熟悉,查询了一下资料,我心里的想法是这样的. tf.nn.dynamic_rnn的定义 tf.nn.dynamic_rnn( cell, inputs, sequence_length=None, initial_state=Non

  • Python使用循环神经网络解决文本分类问题的方法详解

    本文实例讲述了Python使用循环神经网络解决文本分类问题的方法.分享给大家供大家参考,具体如下: 1.概念 1.1.循环神经网络 循环神经网络(Recurrent Neural Network, RNN)是一类以序列数据为输入,在序列的演进方向进行递归且所有节点(循环单元)按链式连接的递归神经网络. 卷积网络的输入只有输入数据X,而循环神经网络除了输入数据X之外,每一步的输出会作为下一步的输入,如此循环,并且每一次采用相同的激活函数和参数.在每次循环中,x0乘以系数U得到s0,再经过系数W输入

  • Tensorflow实现AlexNet卷积神经网络及运算时间评测

    本文实例为大家分享了Tensorflow实现AlexNet卷积神经网络的具体实现代码,供大家参考,具体内容如下 之前已经介绍过了AlexNet的网络构建了,这次主要不是为了训练数据,而是为了对每个batch的前馈(Forward)和反馈(backward)的平均耗时进行计算.在设计网络的过程中,分类的结果很重要,但是运算速率也相当重要.尤其是在跟踪(Tracking)的任务中,如果使用的网络太深,那么也会导致实时性不好. from datetime import datetime import

  • Tensorflow与RNN、双向LSTM等的踩坑记录及解决

    1.tensorflow(不定长)文本序列读取与解析 tensorflow读取csv时需要指定各列的数据类型. 但是对于RNN这种接受序列输入的模型来说,一条序列的长度是不固定.这时如果使用csv存储序列数据,应当首先将特征序列拼接成一列. 例如两条数据序列,第一项是标签,之后是特征序列 [0, 1.1, 1.2, 2.3] 转换成 [0, '1.1_1.2_2.3'] [1, 1.0, 2.5, 1.6, 3.2, 4.5] 转换成 [1, '1.0_2.5_1.6_3.2_4.5'] 这样每

  • TensorFlow实现简单卷积神经网络

    本文使用的数据集是MNIST,主要使用两个卷积层加一个全连接层构建的卷积神经网络. 先载入MNIST数据集(手写数字识别集),并创建默认的Interactive Session(在没有指定回话对象的情况下运行变量) from tensorflow.examples.tutorials.mnist import input_data import tensorflow as tf mnist = input_data.read_data_sets("MNIST_data/", one_h

  • TensorFlow深度学习之卷积神经网络CNN

    一.卷积神经网络的概述 卷积神经网络(ConvolutionalNeural Network,CNN)最初是为解决图像识别等问题设计的,CNN现在的应用已经不限于图像和视频,也可用于时间序列信号,比如音频信号和文本数据等.CNN作为一个深度学习架构被提出的最初诉求是降低对图像数据预处理的要求,避免复杂的特征工程.在卷积神经网络中,第一个卷积层会直接接受图像像素级的输入,每一层卷积(滤波器)都会提取数据中最有效的特征,这种方法可以提取到图像中最基础的特征,而后再进行组合和抽象形成更高阶的特征,因此

随机推荐