1、RNN--LSTM--GRU序列的tensorflow实现(单层)
这里只需要定义一个即可,其余的cell进行替换即:
BasicRNNCell是最基本的一种cell --(替换为)--> RNNCell、BasicLSTMCell、LSTMCell、GRUCell
tf.nn.dynamic_rnn(cell, inputs, sequence_length=None, initial_state=None,
dtype=None, parallel_iterations=None,swap_memory=False,time_major=False, scope=None)
参数:
--cell: RNNCell的一个实例
--inputs: RNN输入
--time_major == False(默认): 则是一个shape为[batch_size, max_time, input_size]的Tensor,或者这些元素的嵌套元组
time_major == True: 则是一个shape为[max_time, batch_size, input_size]的Tensor,或这些元素的嵌套元组
(time_major =True更有效,因为它避免了RNN计算开始和结束时的转置.但是,大多数TensorFlow数据都是batch-major,因此默认情况下,此函数接受输入并以batch-major形式发出输出)
--sequence_length: (可选)大小为[batch_size],数据的类型是int32/int64向量。
--initial_state: (可选)RNN的初始state(状态)。
返回值:一对(outputs, state)
--outputs: RNN输出Tensor
--如果time_major == False(默认),这将是shape为[batch_size, max_time, cell.output_size]的Tensor
--如果time_major == True,这将是shape为[max_time, batch_size, cell.output_size]的Tensor
--state: 最终的状态
--一般情况下state的形状为 [batch_size, cell.output_size ]
--如果cell是LSTMCells,则state将是包含每个单元格的LSTMStateTuple的元组,state的形状为[2,batch_size, cell.output_size]
import tensorflow as tf
import numpy as np
n_steps = 2 # 相当于一句话只有两个字
n_inputs = 3 # 每个字用一个 1*3 的一维向量表示
n_neurons = 5 # 也就是 hidden_size ,rnn个数为5 > 一句话长度2
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
# basic_cell = tf.contrib.rnn.BasicRNNCell(num_units=n_neurons)
basic_cell = tf.contrib.rnn.LSTMCell(num_units=n_neurons)
seq_length = tf.placeholder(tf.int32, [None])
outputs, states = tf.nn.dynamic_rnn(basic_cell, X, dtype=tf.float32,sequence_length=seq_length)
init = tf.global_variables_initializer()
X_batch = np.array([
# shape: 4*2*3
# 输入四句话 每句话两个字 每个字用1*3 的一维向量表示
[[0, 1, 2], [9, 8, 7]], # instance 1
[[1, 1, 1], [0, 0, 0]], # instance 2
[[6, 7, 8], [6, 5, 4]], # instance 3
[[9, 0, 1], [3, 2, 1]], # instance 4
])
seq_length_batch = np.array([2, 1, 2, 2]) # 规定每个样本的timestep的大小,如[3, 4, 5], [0, 0, 0]就只保留[3, 4, 5]的部分
with tf.Session() as sess:
init.run()
outputs_val, states_val = sess.run([outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})
# print("outputs_val.shape:", outputs_val.shape, "states_val.shape:", states_val.shape)
print("outputs_val:", outputs_val, "states_val:", states_val)
""" basic--rnn--cell
outputs_val:
[
[ [ 0.16252275 -0.21838261 0.5071136 -0.8777064 0.9440784 ]
[ 0.75742805 0.9998758 0.99818695 -0.9387361 0.9999933 ] ]
[ [ 0.07687274 0.5346504 0.45065388 -0.3090447 0.7222854 ]
[ 0. 0. 0. 0. 0. ] ]
[ [ 0.55537814 0.99757946 0.9980729 -0.997187 0.999999 ]
[ 0.6576928 0.9756552 0.9704857 -0.9092402 0.999601 ] ]
[ [ 0.9929467 0.9967808 0.9811955 0.999846 -0.8645005 ]
[ 0.28238386 0.96665514 0.96925664 -0.4429886 0.9281155 ] ]
]
states_val:
[[ 0.75742805 0.9998758 0.99818695 -0.9387361 0.9999933 ]
[ 0.07687274 0.5346504 0.45065388 -0.3090447 0.7222854 ]
[ 0.6576928 0.9756552 0.9704857 -0.9092402 0.999601 ]
[ 0.28238386 0.96665514 0.96925664 -0.4429886 0.9281155 ]]
"""
""" lstm--rnn
outputs_val:
[ [[-0.1515024 0.0414015 -0.02425683 0.05317516 -0.11273739]
[-0.7172007 0.04799957 -0.00251973 -0.00678627 -0.19663692]]
[[-0.15052094 -0.04909014 -0.06310479 -0.06192669 -0.02642662]
[ 0. 0. 0. 0. 0. ]]
[[-0.5171155 -0.01278513 -0.00652955 -0.04567356 -0.44855824]
[-0.77111876 -0.04901093 -0.02271985 -0.19334537 -0.20367831]]
[[-0.09574735 -0.10946438 -0.019915 -0.39390936 0.02905519]
[-0.29410264 -0.23854323 -0.14803335 -0.4029409 -0.01784849]]
]
states_val:
LSTMStateTuple(
c=array(
[[-0.9987148 , 0.06223609, -1.0173999 , -0.00715793, -0.20007385],
[-0.27164963, -0.09219637, -0.19096293, -0.10495596, -0.03995872],
[-1.2989509 , -0.06663355, -1.4104235 , -0.22700138, -0.21344885],
[-0.41951478, -0.40118104, -1.2497861 , -0.65628904, -0.02131107]],
dtype=float32),
h=array(
[[-0.7172007 , 0.04799957, -0.00251973, -0.00678627, -0.19663692],
[-0.15052094, -0.04909014, -0.06310479, -0.06192669, -0.02642662],
[-0.77111876, -0.04901093, -0.02271985, -0.19334537, -0.20367831],
[-0.29410264, -0.23854323, -0.14803335, -0.4029409 , -0.01784849]],
dtype=float32)
)
"""
说明:就 basic--rnn--cell进行说明
outputs是最后一层的输出,即 [batch_size,step,n_neurons] = [4,2,5]
states是每一层的最后一个step的输出,即三个结构为 [batch_size,n_neurons] = [4,5] 的tensor,继续观察数据,states中的最后一个array,正好是outputs的最后那个step的输出
分析:
tf.nn.dynamic_rnn()的time_major是默认的false,故输入X应该是一个[batch_size,step,input_size]=[4,2,3] 的tensor,注意我们这里调用的是BasicRNNCell,只有一层循环网络。
outputs是最后一层每个step的输出,它的结构是[batch_size,step,n_neurons]=[4,2,5]
states是每一层的最后那个step的输出,由于本例中,我们的循环网络只有一个隐藏层,所以它就代表这一层的最后那个step的输出,因此它和step的大小是没有关系的,我们的X有4个样本组成,隐层神经元个数为n_neurons是5,因此states的结构就是[batch_size,n_neurons]=[4,5] ,最后我们观察数据,states的每条数据正好就是outputs的最后一个step的输出。
2、RNN--LSTM--GRU序列的tensorflow多层实现(basic--rnn--cell 和 basic--lstm--cell)
import tensorflow as tf
import numpy as np
n_steps = 2 # 步长,句子的字数
n_inputs = 3 # 输入,每个字的向量维度
n_neurons = 5 # 每一层的神经元数
n_layers = 3 # 构建的rnn层数
X = tf.placeholder(tf.float32, [None, n_steps, n_inputs])
seq_length = tf.placeholder(tf.int32, [None])
# layers = [tf.contrib.rnn.BasicRNNCell(num_units=n_neurons, activation=tf.nn.relu) for layer in range(n_layers)]
layers = [tf.contrib.rnn.BasicLSTMCell(num_units=n_neurons, activation=tf.nn.relu) for layer in range(n_layers)]
# 建造多层cell列表
multi_layer_cell = tf.contrib.rnn.MultiRNNCell(layers)
outputs, states = tf.nn.dynamic_rnn(multi_layer_cell, X, dtype=tf.float32, sequence_length=seq_length)
init = tf.global_variables_initializer()
X_batch = np.array([
# step 0 step 1
[[0, 1, 2], [9, 8, 7]], # instance 1
[[3, 4, 5], [0, 0, 0]], # instance 2 (padded with zero vectors)
[[6, 7, 8], [6, 5, 4]], # instance 3
[[9, 0, 1], [3, 2, 1]], # instance 4
])
# 设置state输出的是第几步的值
seq_length_batch = np.array([2, 1, 2, 2])
with tf.Session() as sess:
init.run()
outputs_val, states_val = sess.run([outputs, states], feed_dict={X: X_batch, seq_length: seq_length_batch})
print("outputs_val.shape:", outputs, "states_val.shape:", states)
print("outputs_val:", outputs_val, "states_val:", states_val)
""" basic--rnn--cell
outputs_val:
[
[[0. 0. 0. 0.94110525 0.52952904]
[0. 1.2490433 0. 0.77188766 0.93011624]]
[[0. 0.2254023 0. 1.6372365 1.0218552 ]
[0. 0. 0. 0. 0. ]]
[[0. 0.52909493 0. 2.268035 1.3782274 ]
[0.5089346 1.392092 0.7507003 0. 1.2562542 ]]
[[0. 0.22220033 0. 0.16814911 0. ]
[0. 0.4996884 0. 0.6632186 0.375664 ]]
]
states_val:
(array([[2.9295716 , 3.2567546 , 5.9846582 , 0. , 0. ],
[0.20362723, 1.506877 , 3.6396174 , 0.86225355, 0. ],
[5.772155 , 3.4167778 , 7.1355224 , 0. , 0. ],
[0.27910823, 1.291137 , 1.3769454 , 0. , 0. ]],
dtype=float32),
array([[0. , 0.88036937, 0.8558484 , 2.0480504 , 0. ],
[1.177788 , 0.63505435, 0.7038198 , 2.1659842 , 0. ],
[0. , 0.7422787 , 0.9139857 , 1.0455277 , 0.37688923],
[0.24041918, 0.2875983 , 0.5586405 , 0.9000643 , 0. ]],
dtype=float32),
array([[0. , 1.2490433 , 0. , 0.77188766, 0.93011624],
[0. , 0.2254023 , 0. , 1.6372365 , 1.0218552 ],
[0.5089346 , 1.392092 , 0.7507003 , 0. , 1.2562542 ],
[0. , 0.4996884 , 0. , 0.6632186 , 0.375664 ]],
dtype=float32)
)
"""
""" lstm--cell
outputs_val:
[
[[0.0000000e+00 8.3128671e-04 3.1612897e-03 0.0000000e+00 3.4605121e-04]
[0.0000000e+00 9.1413833e-04 6.1877295e-03 0.0000000e+00 2.5316293e-04]]
[[0.0000000e+00 5.5302051e-04 1.2576625e-03 0.0000000e+00 1.6089274e-04]
[0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00 0.0000000e+00]]
[[0.0000000e+00 3.9677379e-05 5.1048800e-04 0.0000000e+00 0.0000000e+00]
[0.0000000e+00 2.8833621e-05 4.3160995e-03 0.0000000e+00 0.0000000e+00]]
[[0.0000000e+00 4.0190206e-03 0.0000000e+00 0.0000000e+00 0.0000000e+00]
[0.0000000e+00 2.8899033e-03 8.2549378e-03 0.0000000e+00 0.0000000e+00]]
]
states_val:
(LSTMStateTuple(
c=array(
[[0.0000000e+00, 2.7703049e-03, 1.7620984e+00, 7.7233900e-04, 2.2952499e+00],
[0.0000000e+00, 0.0000000e+00, 2.4333260e+00, 0.0000000e+00, 5.9484053e-01],
[0.0000000e+00, 0.0000000e+00, 3.9442434e+00, 8.4212096e-03, 2.1350546e+00],
[5.6616318e-01, 0.0000000e+00, 7.4903107e-01, 1.7679410e-01, 3.8056388e+00]], dtype=float32),
h=array(
[[0.0000000e+00, 2.4237809e-06, 5.5419179e-03, 3.2915897e-04, 4.1679955e-01],
[0.0000000e+00, 0.0000000e+00, 9.2825890e-02, 0.0000000e+00, 1.3505943e-01],
[0.0000000e+00, 0.0000000e+00, 1.1048420e-01, 3.3163740e-03, 6.4259231e-01],
[3.3395720e-01, 0.0000000e+00, 1.4191234e-01, 5.8281716e-02, 1.8665118e+00]], dtype=float32)),
LSTMStateTuple(
c=array(
[[0.08610132, 0.11147856, 0.01433742, 0.06254955, 0. ],
[0.03402846, 0.03710118, 0. , 0.02776909, 0. ],
[0.11612763, 0.17795445, 0. , 0.07696477, 0. ],
[0.46006948, 0.6286925 , 0.01662218, 0.2087687 , 0.06603457]], dtype=float32),
h=array(
[[0.04532592, 0.0596282 , 0.0077831 , 0.03033185, 0. ],
[0.01739167, 0.01900657, 0. , 0.01351981, 0. ],
[0.06294775, 0.09843437, 0. , 0.03604729, 0. ],
[0.27324262, 0.42447668, 0.01194939, 0.09189884, 0.03275691]], dtype=float32)),
LSTMStateTuple(
c=array(
[[0.0000000e+00, 1.8579917e-03, 1.2345124e-02, 0.0000000e+00, 5.0845230e-04],
[0.0000000e+00, 1.1119313e-03, 2.5110506e-03, 0.0000000e+00, 3.2198839e-04],
[0.0000000e+00, 5.9105962e-05, 8.6243059e-03, 0.0000000e+00, 0.0000000e+00],
[0.0000000e+00, 6.4492221e-03, 1.6449979e-02, 0.0000000e+00, 0.0000000e+00]], dtype=float32),
h=array(
[[0.0000000e+00, 9.1413833e-04, 6.1877295e-03, 0.0000000e+00, 2.5316293e-04],
[0.0000000e+00, 5.5302051e-04, 1.2576625e-03, 0.0000000e+00, 1.6089274e-04],
[0.0000000e+00, 2.8833621e-05, 4.3160995e-03, 0.0000000e+00, 0.0000000e+00],
[0.0000000e+00, 2.8899033e-03, 8.2549378e-03, 0.0000000e+00, 0.0000000e+00]], dtype=float32)))
"""
说明:rnn--basic--cell
outputs是最后一层的输出,即 [batch_size,step,n_neurons]=[4,2,5]
states是每一层的最后一个step的输出,即三个结构为 [batch_size,n_neurons]=[4,5]的tensor继续观察数据,states中的最后一个array,正好是outputs的最后那个step的输出。
说明:lstm--cell--basic
一个LSTM cell有两个状态Ct和ht ,而不是像一个RNN cell一样只有ht
在tensorflow中,将一个LSTM cell的Ct 和ht 合在一起,称为LSTMStateTuple。
因此我们的states包含三个LSTMStateTuple,每一个LSTMStateTuple表示每一层的最后一个step的输出,这个输出有两个信息,一个是ht 表示短期记忆信息,一个是Ct 表示长期记忆信息。维度都是[batch_size,n_neurons] = [4,5],states的最后一个LSTMStateTuple中的ht 就是outputs的最后一个step的输出。
3、总结以上代码流程
num_units这个参数的大小就是LSTM输出结果的维度。例如num_units=128, 那么LSTM网络最后输出就是一个128维的向量。我们换个角度举个例子,最后再用公式来说明。
假设在我们的训练数据中,每一个样本 x 是 28*28 维的一个矩阵,那么将这个样本的每一行当成一个输入,通过28个时间步骤展开LSTM,在每一个LSTM单元,我们输入一行维度为28的向量,如下图所示。
那么,对每一个LSTM单元,参数 num_units=128 的话,就是每一个单元的输出为 128*1 的向量,在展开的网络维度来看,如下图所示,对于每一个输入28维的向量,LSTM单元都把它映射到128维的维度, 在下一个LSTM单元时,LSTM会接收上一个128维的输出,和新的28维的输入,处理之后再映射成一个新的128维的向量输出,就这么一直处理下去,知道网络中最后一个LSTM单元,输出一个128维的向量。
从LSTM的公式的角度看是什么原理呢?我们先看一下LSTM的结构和公式:
参数num_units = 128
最后LSTM单元输出的h就是 128∗1的向量