基於深度學習的時間序列分類[含程式碼]

格拉迪沃發表於2019-03-12

引言

目前,深度學習在計算機視覺和語音識別上有了非常廣泛的應用,但是在工業應用方面還沒有完善的體系,一方面缺乏資料集另一方缺乏優秀的頂級論文。在工業上的故障診斷領域,大多資料都來自於感測器的採集,如是西儲大學軸承資料,TE化工資料集等,都是典型的時間序列,因而絕大多數問題可以抽象成時間序列分類(TSC)問題。因此本人準備從時間序列分類出發,用典型的深度學習方法,如多層感知器,卷積神經網路,遞迴神經網路等去測試UCR資料集(共128個時間序列資料集)和自己模擬的時間序列,由此得到一些啟發和規律,再將這些知識遷移到工業上的故障診斷領域。為了方便大家閱讀和復現程式碼,本文就不再有過多的數學推到,多以程式碼和如何使用程式碼為主,用最直觀的方式去解釋一些實驗結果。

資料集

在時間序列的資料集中,最權威的就屬UCR Time Series,可以說是時間序列界的“Imagnet”,發文章必跑資料集,有一堆大牛在維護,並在2018年秋對其進行了意思大的更新。這個資料集很有意思,下載後解壓密碼要仔細讀其PPT然後在其參考論文中尋找,如果想懶省事的朋友可以直接從這裡下載。此資料集包含了128個時間序列資料集,下圖為前八個
UCR中前八個資料集
除了前人整理好的資料集資料集,我們在初期還可以自己設計一些簡單的,容易識別的資料集來進行入門以及演算法的初步篩選。不僅如此,為了探究模型結構的設計所考慮的因素或者驗證自己的猜想,都需要有針對性的設計一些時間序列。比如一些單變數時間序列如:
方波,正弦波,鋸齒波,等等,如下圖所示
各種典型的時間序列
一些簡單的多變數時間序列如下圖所示
在這裡插入圖片描述

實驗環境搭建

本文的實驗使用python語言,所用的開發模型為Tensorflow和帶有Tensorflow後端的Keras,所需的環境依賴如下:
1.tensorflow-gpu>=1.2.0
2.keras>=2.0.4
3.scipy
4.numpy
5.pandas
6.scikit-learn>=0.18.2
7.h5py
8.matplotlib
9.joblib>=0.12

儘管存在許多型別的DNN,但在此我們將重點關注用於TSC任務的三種主要DNN架構:多層感知器(MLP),卷積神經網路(CNN)和回聲狀態網路(ESN)。選擇這三種型別的架構,因為它們是被廣泛用於end to end深度學習TSC的模型。

實驗設計

龐大的高樓是由一塊塊磚瓦搭建成的,同樣的一個精妙的實驗也是由一個個最基本的實驗單元組成的。本文就如何使用一個資料集對設計好的神經網路進行訓練進行設計。
1.選擇你要進行訓練的資料集,弄明白樣本資訊以及分類狀況,本文以UCR資料集中的Adiac資料集為例進行實驗。
資料集信如下:
自動矽藻識別和分類(ADIAC)專案是一項關於根據影象自動識別矽藻(單細胞藻類)的試點研究。 該資料由該專案的博士生Andrei Jalba捐贈,該專案於21世紀初完成。 從閾值影象中提取輪廓。 據推測,時間序列是作為到參考點的距離而生成的。 資料很接近正弦。一個樣本如下圖所示:

在這裡插入圖片描述
訓練集樣本個數:390
測試集樣本個數:391
分類種類:39
時間序列長度:176

2.演算法選擇:
選擇全卷積網路(FNC),具體結構如圖所示:
在這裡插入圖片描述
3.評價網路

實驗程式碼

把實驗程式碼和資料集’Adiac’資料夾放到同一個目錄裡

#!/usr/bin/env 
# -*- coding: utf-8 -*-
"""
Created on Sun Oct 30 20:11:19 2016

@author: stephen
"""
 
from __future__ import print_function
 
from keras.models import Model
from keras.utils import np_utils
import numpy as np
import pandas as pd
import keras 
from keras.callbacks import ReduceLROnPlateau
      
def readucr(filename):
    data = np.loadtxt(filename, delimiter = ',')
    Y = data[:,0]
    X = data[:,1:]
    return X, Y
  
nb_epochs = 1000

flist  = ['Adiac']
for each in flist:
    fname = each
    x_train, y_train = readucr(fname+'/'+fname+'_TRAIN')
    x_test, y_test = readucr(fname+'/'+fname+'_TEST')
    nb_classes = len(np.unique(y_test))
    batch_size = min(x_train.shape[0]/10, 16)
    
    y_train = (y_train - y_train.min())/(y_train.max()-y_train.min())*(nb_classes-1)
    y_test = (y_test - y_test.min())/(y_test.max()-y_test.min())*(nb_classes-1)
    
    
    Y_train = np_utils.to_categorical(y_train, nb_classes)
    Y_test = np_utils.to_categorical(y_test, nb_classes)
    
    x_train_mean = x_train.mean()
    x_train_std = x_train.std()
    x_train = (x_train - x_train_mean)/(x_train_std)
     
    x_test = (x_test - x_train_mean)/(x_train_std)
    x_train = x_train.reshape(x_train.shape + (1,1,))
    x_test = x_test.reshape(x_test.shape + (1,1,))

    x = keras.layers.Input(x_train.shape[1:])
#    drop_out = Dropout(0.2)(x)
    conv1 = keras.layers.Conv2D(128, 8, 1, border_mode='same')(x)
    conv1 = keras.layers.normalization.BatchNormalization()(conv1)
    conv1 = keras.layers.Activation('relu')(conv1)
    
#    drop_out = Dropout(0.2)(conv1)
    conv2 = keras.layers.Conv2D(256, 5, 1, border_mode='same')(conv1)
    conv2 = keras.layers.normalization.BatchNormalization()(conv2)
    conv2 = keras.layers.Activation('relu')(conv2)
    
#    drop_out = Dropout(0.2)(conv2)
    conv3 = keras.layers.Conv2D(128, 3, 1, border_mode='same')(conv2)
    conv3 = keras.layers.normalization.BatchNormalization()(conv3)
    conv3 = keras.layers.Activation('relu')(conv3)
    
    full = keras.layers.pooling.GlobalAveragePooling2D()(conv3)    
    out = keras.layers.Dense(nb_classes, activation='softmax')(full)
    
    
    model = Model(input=x, output=out)
     
    optimizer = keras.optimizers.Adam()
    model.compile(loss='categorical_crossentropy',
                  optimizer=optimizer,
                  metrics=['accuracy'])
     
    reduce_lr = ReduceLROnPlateau(monitor = 'loss', factor=0.5,
                      patience=50, min_lr=0.0001) 
    hist = model.fit(x_train, Y_train, batch_size=batch_size, nb_epoch=nb_epochs,
              verbose=1, validation_data=(x_test, Y_test), callbacks = [reduce_lr])
    model.save('FCN_CBF_1500.h5')
acc = history.history['acc']
val_acc = history.history['val_acc']
loss = history.history['loss']
val_loss = history.history['val_loss']

epochs = range(len(acc))

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()

plt.figure()

plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()

plt.show()

實驗結果

如果出現下圖,那麼你的第一次實驗就完成了,完成了“helloworld”。那麼接下來就是一個不斷嘗試新的網路結構,探究其結構和資料特性關係的過程了
在這裡插入圖片描述
下面是視覺化結果
在這裡插入圖片描述

在這裡插入圖片描述

相關文章