1. 程式人生 > 程式設計 >keras在構建LSTM模型時對變長序列的處理操作

keras在構建LSTM模型時對變長序列的處理操作

我就廢話不多說了,大家還是直接看程式碼吧~

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(LSTM(128,dropout_W=0.5,dropout_U=0.5))
model.add(Dense(13,activation='softmax'))
model.compile(loss='categorical_crossentropy',optimizer='adam',metrics=['accuracy'])

# 用於儲存驗證集誤差最小的引數,當驗證集誤差減少時,儲存下來
checkpointer = ModelCheckpoint(filepath="keras_rnn.hdf5",verbose=1,save_best_only=True,)
history = LossHistory()
result = model.fit(X,Y,batch_size=10,nb_epoch=500,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,state_size),並且最後一個有效輸出(有效序列長度,不包括padding的部分)與狀態值會一樣

LSTM

LSTM與RNN基本一致,不同在於其狀態有兩個c_state和h_state,它們的shape一樣,輸出值output的最後一個有效輸出與h_state一致

用變長RNN訓練,要求其輸入格式仍然要求為shape=(batch_size,input_size),但可指定每一個批次中各個樣本的有效序列長度,這樣在有效長度內其狀態值和輸出值原理不變,但超過有效長度的部分的狀態值將不會發生改變,而輸出值都將是shape=(state_size,)的零向量(注:RNN也是這個原理)

需要說明的是,不是因為無效序列長度部分全padding為0而引起輸出全為0,狀態不變,因為輸出值和狀態值得計算不僅依賴當前時刻的輸入值,也依賴於上一時刻的狀態值。其內部原理是利用一個mask matrix矩陣標記有效部分和無效部分,這樣在無效部分就不用計算了,也就是說,這一部分不會造成反向傳播時對引數的更新。當然,如果padding不是零,那麼padding的這部分輸出和狀態同樣與padding為零的結果是一樣的

'''
#樣本資料為(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]],[[6,7,8],[6,5,4],[1,4]],[[9,1],3,0]]
          ])
          
sequence_length = [3,2,2]

train_X.shape,train_X[:,2:3,:].reshape(5,3)
tf.reset_default_graph()

x = tf.placeholder(tf.float32,shape=(None,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,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,5)->(batch_size,time_step_size,(4,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[:,:] == state1))
  print("---------output2<lstm>state2-----------")
  print(outputs2) # 可以看出output2的最後一個時刻的輸出即為LSTMStateTuple中的h
  print(state2)
  print(np.all(outputs2[:,:] == state2[1]))

再來懟懟dynamic_rnn中資料序列長度tricks

keras在構建LSTM模型時對變長序列的處理操作

思路樣例程式碼

from collections import Counter
import numpy as np

origin_data = np.array([[1,3],[2,3]
            ])
# 按照指定列索引進行分組(看作RNN中一個樣本序列),如下為按照第二列分組的結果
# [[[1,0],# [[3,# [[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模型時對變長序列的處理操作就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。