925
技術社區[雲棲]
如何使用最流行框架Tensorflow進行時間序列分析——第二篇
更多深度文章,請關注:https://yq.aliyun.com/cloud
看深度學習框架排名第一的TensorFlow如何進行時序預測——第一篇
時間序列分析是一種動態數據處理的統計方法。根據對係統進行觀測得到的時間序列數據,用曲線擬合的方法對係統進行客觀的描述。
如今,時間序列數據出現在金融,信號處理,語音識別和醫學等諸多領域。解決時間序列問題的標準方法通常需要手動提煉數據特征,然後才能將其輸入到機器學習算法中。這通常還要求開發設計人員掌握數據所屬學科領域的知識特征,以便在算法中加入特征過濾。例如,如果處理信號(即EEG信號的分類),則需要掌握的知識特征涉及各種頻帶的功率譜及Hjorth參數。對於認真鑽研本領域的程序猿來說,這簡直就是噩夢。
那麼是不是不掌握這些學科領域的知識特征,我們就沒有辦法進行模型設計了呢?
其實答案不然,在圖像分類領域也出現了類似的情況。但是,隨著深度學習的出現,卷積神經網絡(CNN)的性能已經可以勝過這種人工提取特征的方法。CNN不需要任何手動設置任何的圖像特征。在訓練過程中,隨著層次越來越深,CNN越來越複雜,進而它自己會學習得到許多“過濾器”,並在最終的分類器中使用它們。
在這篇博客文章中,我將討論使用深度學習的方法對時間序列數據進行分類,而無需手動設計特征。我在本文中將使用到的例子是UCI存儲庫中經典的人類活動識別(HAR)數據集。該數據集包含原始時間序列數據,以及具有561個預處理數據的工程特征。在博客中我會比較使用工程特征與深度學習這兩種方法(卷積和複現神經網絡),並表明深度學習可以超越前者的性能。
在本文中我將使用Tensorflow來實現和訓練博客中所用到的模型。在下麵的討論中,提供了代碼片段來解釋實現過程。有關完整的代碼,請參閱我的Github資源庫。
卷積神經網絡(CNN)
第一步是將數據投射到具有一定形狀的numpy數組中:(batch_size, seq_len, n_channels),其中batch_size是訓練期間批次中的示例數,seq_len是時間序列的長度(在我們的情況下n_channels為128),並且是進行測量的通道的數量。在本文的小例子中,有9個通道,每3個坐標軸包括3個不同的加速度測量。每次觀察有6類活動LAYING, STANDING, SITTING, WALKING_DOWNSTAIRS, WALKING_UPSTAIRS, WALKING。
首先,我們為輸入到計算圖的數據創建占位符:
graph = tf.Graph()
with graph.as_default():
inputs_ = tf.placeholder(tf.float32, [None, seq_len, n_channels],name = 'inputs')
labels_ = tf.placeholder(tf.float32, [None, n_classes], name = 'labels')
keep_prob_ = tf.placeholder(tf.float32, name = 'keep')
learning_rate_ = tf.placeholder(tf.float32, name = 'learning_rate')
inputs
輸入的張量饋送到計算圖,並將其數組第一個位置設置為None
,以便
允許可變的批量大小。labels_
是要預測的一個熱編碼的標簽,keep_prob
的作用
是在退出正則化中保持概率來防止過度擬合,並且learning_rate_
是Adam優化器中使用的學習率。
我們將通過使用移動序列的一維內核構造卷積層(與使用2d卷積的圖像不同)來構造卷積層,這些內核作為在訓練過程中的過濾器。像許多CNN架構一樣,層越深,過濾器數越多。每個卷積之後是匯集層,以此減少序列長度。下麵是可能可以使用的CNN架構的簡單圖片:
上麵描述的卷積層如下實現:
with graph.as_default():
# (batch, 128, 9) -> (batch, 32, 18)
conv1 = tf.layers.conv1d(inputs=inputs_, filters=18, kernel_size=2, strides=1,padding='same', activation = tf.nn.relu)
max_pool_1 = tf.layers.max_pooling1d(inputs=conv1, pool_size=4, strides=4, padding='same')
# (batch, 32, 18) -> (batch, 8, 36)
conv2 = tf.layers.conv1d(inputs=max_pool_1, filters=36, kernel_size=2, strides=1,padding='same', activation = tf.nn.relu)
max_pool_2 = tf.layers.max_pooling1d(inputs=conv2, pool_size=4, strides=4, padding='same')
# (batch, 8, 36) -> (batch, 2, 72)
conv3 = tf.layers.conv1d(inputs=max_pool_2, filters=72, kernel_size=2, strides=1,padding='same', activation = tf.nn.relu)
max_pool_3 = tf.layers.max_pooling1d(inputs=conv3, pool_size=4, strides=4, padding='same')
一旦達到最後一層,我們需要張量平坦化並將其輸送到具有正確數量的神經元的分類器中(上圖中的144個)。模型功能:
1. 計算softmax交叉熵,這是多類問題中使用的標準損失度量。
2. 從最大概率以及精度預測類標簽。
功能實現代碼如下:
with graph.as_default():
# Flatten and add dropout
flat = tf.reshape(max_pool_3, (-1, 2*72))
flat = tf.nn.dropout(flat, keep_prob=keep_prob_)
# Predictions
logits = tf.layers.dense(flat, n_classes)
# Cost function and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits,labels=labels_))
optimizer = tf.train.AdamOptimizer(learning_rate_).minimize(cost)
# Accuracy
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(labels_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32), name='accuracy')
其餘的實施部分涉及向圖表饋送批次的訓練數據並評估驗證集的性能。最後,對測試集進行評估。采用上述架構
batch_size=
600,learning_rate
=0.001(默認值),keep_prob=
0.5,500訓練次數,我們得到98%的測試精度。下麵的圖表顯示了訓練/驗證精度如何通過訓練次數演變:
長短期記憶網絡(LSTM)
LSTM在處理基於文本的數據方麵非常受歡迎,在情感分析,語言翻譯和文本生成方麵也相當成功。今天我們就用LSTM來解決我們今天的問題。
以下是可以在我們的問題中使用的示例架構:
為了將數據傳送到網絡中,我們需要將數組分成128個,每個的形狀我們定義為:(batch_size, n_channels)。然後,單層神經元將把這些輸入轉換成LSTM細胞,每一個都具有維度lstm_size。該參數的大小選擇要大於通道數。這是一種類似於在文本應用程序中嵌入圖層的方式。為了實現,占位符與上述相同。以下代碼段實現了LSTM層:
with graph.as_default():
# Construct the LSTM inputs and LSTM cells
lstm_in = tf.transpose(inputs_, [1,0,2]) # reshape into (seq_len, N, channels)
lstm_in = tf.reshape(lstm_in, [-1, n_channels]) # Now (seq_len*N, n_channels)
# To cells
lstm_in = tf.layers.dense(lstm_in, lstm_size, activation=None)
# Open up the tensor into a list of seq_len pieces
lstm_in = tf.split(lstm_in, seq_len, 0)
# Add LSTM layers
lstm = tf.contrib.rnn.BasicLSTMCell(lstm_size)
drop = tf.contrib.rnn.DropoutWrapper(lstm, output_keep_prob=keep_prob_)
cell = tf.contrib.rnn.MultiRNNCell([drop] * lstm_layers)
initial_state = cell.zero_state(batch_size, tf.float32)
上麵的代碼段中有一個重要的技術細節。我將陣列重新整形(batch_size, seq_len, n_channels)到(seq_len, batch_size, n_channels),這樣tf.split就可以在每個步驟中將數據(由第零個索引)正確地分割成數組列表。其餘的是LSTM實現的標準,包括構建層(包括正則化的退出),然後是定義初始狀態。
下一步是通過網絡實現前向傳遞和成本函數。一個重要的技術方麵利用梯度剪輯,因為它通過防止反向傳播期間的爆炸梯度來改善訓練。這是代碼:
with graph.as_default():
outputs, final_state = tf.contrib.rnn.static_rnn(cell, lstm_in, dtype=tf.float32,initial_state = initial_state)
# We only need the last output tensor to pass into a classifier
logits = tf.layers.dense(outputs[-1], n_classes, name='logits')
# Cost function and optimizer
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=labels_))
# Grad clipping
train_op = tf.train.AdamOptimizer(learning_rate_)
gradients = train_op.compute_gradients(cost)
capped_gradients = [(tf.clip_by_value(grad, -1., 1.), var) for grad,var in gradients]
optimizer = train_op.apply_gradients(capped_gradients)
# Accuracy
correct_pred = tf.equal(tf.argmax(logits, 1), tf.argmax(labels_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32), name='accuracy')
請注意,僅使用LSTM輸出頂部序列的最後一個成員,因為我們正在嚐試每個序列預測一個數字。其餘的類似CNN,我們隻需要將數據提供給圖表進行訓練。lstm_size=27
,lstm_layers=2
,batch_size=600
,learning_rate=0.0005
,和keep_prob=0.5
,我獲得95%的準確度的測試集。這比CNN的結果還差,但還是不錯的。這些超參數的更好選擇會改進的結果。
與工程特征進行比較
在此之前,我已經使用561個預先設計的特征測試了一些關於這個問題的機器學習方法。性能最好的模型之一是梯度提升樹(gradient booster)(樹形或線性),其結果是96%的精確度(您可以從這本筆記本中了解更多信息)。CNN架構優於梯度提升樹,但LSTM的性能相較於梯度提升樹(gradient booster)就稍差一些。
總結:
在這篇博客文章中,我已經說明了如何使用CNN和LSTM進行時間序列分類,並證明深層架構可以勝過預先設計的功能特征訓練的模型。除了達到更好的準確性外,深度學習模式還“培養”了自己的功能。這是非常可取的,因為人們不需要具有來自數據來源的領域專長,能夠訓練準確的模型。
我們在這篇文章中使用的序列相當小(128步)。人們可能會想,如果步驟數量很多,那麼今天我討論的這些架構的可訓練性是否還有?如果有?會發生什麼。我認為一種可能的架構將涉及LSTM和CNN的組合,其對於較大的序列(即> 1000,對於LSTM是有問題的)可以更好地工作。因為在這種情況下,具有匯集作用的幾個卷積就可以有效地減少前幾個層中的步數,並且得到的較短的序列可以被反饋送到LSTM層。這種結構的一個例子最近被用於從移動設備記錄的心房顫動檢測。如果你有興趣了解這種長序列的方法可以去研究它。
本文由北郵@愛可可-愛生活老師推薦,阿裏雲雲棲社區組織翻譯。
文章原標題《time-series-classification-with-tensorflow》,
作者:burakhimmetoglu 作者博客:https://burakhimmetoglu.com/
譯者:袁虎 審閱:主題曲
文章為簡譯,更為詳細的內容,請查看原文
最後更新:2017-08-31 10:33:13