当前位置: 代码迷 >> 综合 >> TensorFlow 16——ch12-RNN 和 LSTM 的实现方式
  详细解决方案

TensorFlow 16——ch12-RNN 和 LSTM 的实现方式

热度:116   发布时间:2023-09-26 21:24:23.0

TensorFlow 15——ch12-RNN、LSTM基本结构

目录

      • RNNCell
      • RNN 基本单元
      • LSMT 基本单元
      • MultiRNNCell
      • BasicRNNCell 的 call
      • BasicLSTMCell 的 call
      • 展开时间维度

RNNCell

RNNCell 是 Tensorflow 中的 RNN 基本单元,是一个抽象类,没有办法实体化,要用的是两个子类,一个是 BasicRNNCell ,一个是 BasicLSTMCell

RNNCell 有一个 call 函数,是 RNN 的单步计算,调用:

(output, next_state) = call(input, state)

初始输入为 x1,初始的隐藏层为 h0,例如:

(output1, h1) = cell.call(x1, h0) # 得到h1
(output2, h2) = cell.call(x2, h1) # 得到h2

RNNCell 的类属性 :

  • state_size 规定了隐藏层的大小
  • output_size 规定了输出向量的大小

RNN 基本单元

import tensorflow as tf
rnn_cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128)
print(rnn_cell.state_size)

TensorFlow 16——ch12-RNN 和 LSTM 的实现方式

LSMT 基本单元

import tensorflow as tf
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=128)
print(lstm_cell.state_size)

TensorFlow 16——ch12-RNN 和 LSTM 的实现方式

可以看到 BasicLSTMCell 的 state_size 由 ch 两部分组成。

所以一般使用 BasicLSTMCell 的时候,分开这两部分:

import tensorflow as tf
import numpy as np
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units=128)
inputs = tf.placeholder(np.float32, shape=(32, 100))
h0 = lstm_cell.zero_state(32, np.float32)
output, h1 = lstm_cell.call(inputs, h0)
print(h1.h)
print(h1.c)

TensorFlow 16——ch12-RNN 和 LSTM 的实现方式

MultiRNNCell

单层 RNN 的能力有限,所以需要多层的 RNN,也就是第一层的输出 h 作为第二层的输入。

可以使用tf.nn.rnn_cell.MultiRNNCell 函数对 RNN 进行堆叠。测试代码如下:

# 返回一个BasicLSTMCell
def get_a_cell():return tf.nn.rnn_cell.BasicLSTMCell(128)# 创建3层的RNN,state_size=(128,128,128),表示3个隐层大小都为128
cell = tf.nn.rnn_cell.MultiRNNCell([get_a_cell() for _ in range(3)])inputs = tf.placeholder(np.float32, shape=(32, 100))
h0 = cell.zero_state(32, np.float32)
output, h1 = cell.call(inputs, h0)
print(h1)

打印结果(换行是我加的):

TensorFlow 16——ch12-RNN 和 LSTM 的实现方式

LSTMStateTuple(
c=<tf.Tensor 'cell_0/cell_0/basic_lstm_cell/add_1:0' shape=(32, 128) dtype=float32>, 
h=<tf.Tensor 'cell_0/cell_0/basic_lstm_cell/mul_2:0' shape=(32, 128) dtype=float32>
), 
LSTMStateTuple(
c=<tf.Tensor 'cell_1/cell_1/basic_lstm_cell/add_1:0' shape=(32, 128) dtype=float32>, 
h=<tf.Tensor 'cell_1/cell_1/basic_lstm_cell/mul_2:0' shape=(32, 128) dtype=float32>
), 
LSTMStateTuple(
c=<tf.Tensor 'cell_2/cell_2/basic_lstm_cell/add_1:0' shape=(32, 128) dtype=float32>, 
h=<tf.Tensor 'cell_2/cell_2/basic_lstm_cell/mul_2:0' shape=(32, 128) dtype=float32>
)

BasicRNNCell 的 call

BasicRNNCell 的 call 的 return :

def call(self, inputs, state):if self._linear is None:self._linear = _Linear([inputs, state], self._num_units, True)output = self._activation(self._linear([inputs, state]))return output, output

可以看出在 BasicRNNCell 中 output(输出) 和隐状态是一样的,因此需要额外对输出定义新的变换,才能得到图中真正的输出 y 。

而隐状态就是函数中的 output(函数),所以 BasicRNNCell 中 state_size 永远等于 output_size 。

BasicLSTMCell 的 call

BasicLSTMCell 的 call 的 return :

if self._state_is_tuple:new_state = LSTMStateTuple(new_c, new_h)
else:new_state = array_ops.concat([new_c, new_h], 1)
return new_h, new_state

其中 _state_is_tuple 是一直等于 Ture 的,所以返回的隐状态是 LSTMStateTuple(new_c, new_h) ,而output是 new_h

因此如果处理的是分类问题,还需要对 output 添加单独的 Softmax 层才能得到最后的分类概率输出。

展开时间维度

对单个的 RNNCell ,如果序列长,则需要调用n次call,所以 Tensorflow 提供了一个函数 tf.nn.dynamic_rnn,这个函数相当于就调用了n次call。

def dynamic_rnn(cell, inputs, sequence_length=None, initial_state=None, dtype=None, parallel_iterations=None, swap_memory=False, time_major=False, scope=None):

输入的 inputs 数据格式:

inputs: shape = (batch_size, time_steps, input_size)

  • batch_size:batch的大小
  • time_steps:长度,也就是 time_steps 次call
  • input_size:表示输入数据单个序列单个时间维度上固有的长度