我就废话不多说了,大家还是直接看代码吧~
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
print (np.shape(X)) #(1920, 45, 20)
X = sequence.pad_sequences(X, maxlen = 100 , padding = 'post' )
print (np.shape(X)) #(1920, 100, 20)
model = Sequential()
model.add(Masking(mask_value = 0 ,input_shape = ( 100 , 20 )))
model.add(Dense( 13 ,activation = 'softmax' ))
model. compile (loss = 'categorical_crossentropy' ,
optimizer = 'adam' ,
metrics = [ 'accuracy' ])
# 用于保存验证集误差最小的参数,当验证集误差减少时,保存下来
history = LossHistory()
result = model.fit(X, Y, batch_size = 10 ,
nb_epoch = 500 , verbose = 1 , validation_data = (testX, testY),
callbacks = [checkpointer, history])
model.save( 'keras_rnn_epochend.hdf5' )
|
补充知识:RNN(LSTM)数据形式及Padding操作处理变长时序序列dynamic_rnn
Summary
RNN
样本一样,计算的状态值和输出结构一致,也即是说只要当前时刻的输入值也前一状态值一样,那么其当前状态值和当前输出结果一致,因为在当前这一轮训练中权重参数和偏置均未更新
RNN的最终状态值与最后一个时刻的输出值一致
输入数据要求格式为,shape=(batch_size, step_time_size, input_size),那么,state的shape=(batch_size, state_size);output的shape=(batch_size, step_time_size, state_size),并且最后一个有效输出(有效序列长度,不包括padding的部分)与状态值会一样
LSTM
LSTM与RNN基本一致,不同在于其状态有两个c_state和h_state,它们的shape一样,输出值output的最后一个有效输出与h_state一致
用变长RNN训练,要求其输入格式仍然要求为shape=(batch_size, step_time_size, input_size),但可指定每一个批次中各个样本的有效序列长度,这样在有效长度内其状态值和输出值原理不变,但超过有效长度的部分的状态值将不会发生改变,而输出值都将是shape=(state_size,)的零向量(注:RNN也是这个原理)
需要说明的是,不是因为无效序列长度部分全padding为0而引起输出全为0,状态不变,因为输出值和状态值得计算不仅依赖当前时刻的输入值,也依赖于上一时刻的状态值。其内部原理是利用一个mask matrix矩阵标记有效部分和无效部分,这样在无效部分就不用计算了,也就是说,这一部分不会造成反向传播时对参数的更新。当然,如果padding不是零,那么padding的这部分输出和状态同样与padding为零的结果是一样的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
'''
#样本数据为(batch_size,time_step_size, input_size[embedding_size])的形式,其中samples=4,timesteps=3,features=3,其中第二个、第四个样本是只有一个时间步长和二个时间步长的,这里自动补零
'''
import pandas as pd
import numpy as np
import tensorflow as tf
train_X = np.array([[[ 0 , 1 , 2 ], [ 9 , 8 , 7 ], [ 3 , 6 , 8 ]],
[[ 3 , 4 , 5 ], [ 0 , 10 , 110 ], [ 0 , 0 , 0 ]],
[[ 6 , 7 , 8 ], [ 6 , 5 , 4 ], [ 1 , 7 , 4 ]],
[[ 9 , 0 , 1 ], [ 3 , 7 , 4 ], [ 0 , 0 , 0 ]],
[[ 9 , 0 , 1 ], [ 3 , 3 , 4 ], [ 0 , 0 , 0 ]]
])
sequence_length = [ 3 , 1 , 3 , 2 , 2 ]
train_X.shape, train_X[:, 2 : 3 ,:].reshape( 5 , 3 )
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
tf.reset_default_graph()
x = tf.placeholder(tf.float32, shape = ( None , 3 , 3 )) # 输入数据只需能够迭代并符合要求shape即可,list也行,shape不指定表示没有shape约束,任意shape均可
rnn_cell = tf.nn.rnn_cell.BasicRNNCell(num_units = 6 ) # state_size[hidden_size]
lstm_cell = tf.nn.rnn_cell.BasicLSTMCell(num_units = 6 ) # state_size[hidden_size]
outputs1, state1 = tf.nn.dynamic_rnn(rnn_cell, x, dtype = tf.float32, sequence_length = sequence_length)
outputs2, state2 = tf.nn.dynamic_rnn(lstm_cell, x, dtype = tf.float32, sequence_length = sequence_length)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer()) # 初始化rnn_cell中参数变量
outputs1, state1 = sess.run((outputs1, state1), feed_dict = {x: train_X})
outputs2, state2 = sess.run([outputs2, state2], feed_dict = {x: train_X})
print (outputs1.shape, state1.shape) # (4, 3, 5)->(batch_size, time_step_size, state_size), (4, 5)->(batch_size, state_size)
print (outputs2.shape) # state2为LSTMStateTuple(c_state, h_state)
print ( "---------output1<rnn>state1-----------" )
print (outputs1) # 可以看出output1的最后一个时刻的输出即为state1, 即output1[:,-1,:]与state1相等
print (state1)
print (np. all (outputs1[:, - 1 ,:] = = state1))
print ( "---------output2<lstm>state2-----------" )
print (outputs2) # 可以看出output2的最后一个时刻的输出即为LSTMStateTuple中的h
print (state2)
print (np. all (outputs2[:, - 1 ,:] = = state2[ 1 ]))
|
再来怼怼dynamic_rnn中数据序列长度tricks
思路样例代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
from collections import Counter
import numpy as np
origin_data = np.array([[ 1 , 2 , 3 ],
[ 3 , 0 , 2 ],
[ 1 , 1 , 4 ],
[ 2 , 1 , 2 ],
[ 0 , 1 , 1 ],
[ 2 , 0 , 3 ]
])
# 按照指定列索引进行分组(看作RNN中一个样本序列),如下为按照第二列分组的结果
# [[[1, 2, 3], [0, 0, 0], [0, 0, 0]],
# [[3, 0, 2], [2, 0, 3], [0, 0, 0]],
# [[1, 1, 4], [2, 1, 2], [0, 1, 1]]]
# 第一步,将原始数据按照某列序列化使之成为一个序列数据
def groupby(a, col_index): # 未加入索引越界判断
max_len = max (Counter(a[:, col_index]).values())
for i in set (a[:, col_index]):
d[i] = []
for sample in a:
d[sample[col_index]].append( list (sample))
# for key in d:
# d[key].extend([[0]*a.shape[1] for _ in range(max_len-len(d[key]))])
return list (d.values()), [ len (_) for _ in d.values()]
samples, sizes = groupby(origin_data, 2 )
# 第二步,根据当前这一批次的中最大序列长度max(sizes)作为padding标准(不同批次的样本序列长度可以不一样,但同一批次要求一样(包括padding的部分)),当然也可以一次性将所有样本(不按照批量)按照最大序列长度padding也行,可能空间浪费
paddig_samples = np.zeros([ len (samples), max (sizes), 3 ])
for seq_index, seq in enumerate (samples):
paddig_samples[seq_index, : len (seq), :] = seq
paddig_samples
|
以上这篇keras在构建LSTM模型时对变长序列的处理操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持服务器之家。
原文链接:https://blog.csdn.net/xinfeng2005/article/details/68926800