您當前的位置:首頁 > 書法

深度學習 - 時間序列分析例項(二)

作者:由 金戈老馬 發表于 書法時間:2021-12-09

上一篇介紹了基於LSTM模型預測24小時氣溫的基本過程,和實現程式碼。本篇就以下內容繼續探討:

如何緩解over-fitting(過擬合)?

如何評估模型預測能力?

其他常用模型

GRU模型

簡單RNN模型

雙向(Bidirectional)LSTM模型

多層LSTM模型

各個模型的預測能力比較

如何緩解over-fitting(過擬合)?

在上一篇的模型中,有73,345個需要訓練的模型引數,用於訓練的資料X_train僅有1000天的小時粒度的資料 [1000, 24, 14]。直觀上,如此小規模的資料要擬合如此多的自由引數,是很容易過擬合的。過擬合的模型泛化能力很差,也就是說,對於它沒有見過的資料輸入,預測結果將會很差。

針對神經網路模型,緩解過擬合的典型方法有:

資料正則化(規範化)

棄權(Dropout)

增加訓練樣本。比如:把1000天的資料增加10倍,到10000天

前兩種方法在上一篇的模型中都已經採用了。為了增強感性認識,現特意將引數 dropout = 0。2 改為 0,其他均不變,看看模型訓練的效果。程式碼如下:

model

<-

keras_model_sequential

()

%>%

layer_lstm

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

recurrent_dropout

=

0

#

enable

CUDNN

recurrent_activation

=

sigmoid

#

enable

CUDNN

return_sequences

=

TRUE

%>%

time_distributed

layer_dense

units

=

1

))

執行fit訓練之後,訓練過程如下圖左側所示,也就是dropout = 0時的情況。作為對比,下圖右側是上一篇(dropout = 0。2)的訓練過程。

肉眼可見地,右側的綠色validation loss(驗證損失)曲線相對更加平穩,大的趨勢是在減小;

相反,左側的綠色validation loss隨著訓練loss下降的過程中,上下波動,未有明顯的下降趨勢,說明模型的泛化能力並未隨著loss下降而增強,甚至在減弱。

具體dropout設為多大合適呢?手工調調,然後看結果吧!筆者通常設為0。2,或0。3。

深度學習 - 時間序列分析例項(二)

如何評估模型預測能力?

本例項是基於連續變數(氣溫)的預測,屬於迴歸(Regression)型別。

迴歸模型的評估方法,通常有:

MSE(均方誤差)

RMSE(均方根誤差)

殘差均值、殘差均方差

R-Square

MAE(平均絕對誤差)

視覺化方法:殘差圖、結果對照圖等。

由於MSE, RMSE的計算結果隨著樣本個數和樣本值的大小而變化,所以不好比較,在此省略。

上一篇結束於“結果對照圖”,下面計算殘差(= 預測值 – 實際值),如下:

rs

<-

matrix

rep

0

0

nrow

pred_test

*

ncol

pred_test

)),

nrow

=

nrow

pred_test

))

for

i

in

1

nrow

rs

)){

for

j

in

1

ncol

rs

)){

rs

i

j

<-

pred_test

i

j

*

col_stddevs

+

col_means

-

y_test_hour

i

j

1

*

col_stddevs

+

col_means

}

}

殘差值是二維矩陣rs[360, 24],其中24列對應的是預測24個小時中每一個小時的殘差。以第一列的前100個殘差值,畫點圖觀察一下分佈如下:

plot

rs

1

100

1

],

xlab

=

“時間點”

ylab

=

“殘差值”

abline

h

=

0

col

=

“grey”

深度學習 - 時間序列分析例項(二)

殘差在0附件波動,看起來是隨機分佈的。如果殘差不是隨機分佈的,並且,看起來存在某種規律性,那麼需要仔細分析資料並檢視模型。因為,模型並沒有將資料中的規律榨乾,以致於仍然存在某種規律遺留在殘差中。

另外,我們有理由猜測:預測的24個小時的結果中,每一個小時的殘差會有一些不同。因此,從統計的意義上,計算這24個小時的殘差均值,和殘差均方差,並繪圖顯示。

par

mfrow

=

c

1

2

))

plot

sapply

data

frame

rs

),

mean

),

xlab

=

“預測時間點”

ylab

=

“殘差均值”

plot

sapply

data

frame

rs

),

sd

),

xlab

=

“預測時間點”

ylab

=

“殘差均方差”

深度學習 - 時間序列分析例項(二)

從圖中可以看到,相鄰時間點的預測殘差存在相關性,筆者認為是合理的,因為,氣溫在相鄰時間點上本身就是相關的,比如:早上氣溫逐漸上升,黃昏時分氣溫逐漸下降。如果8時的預測結果比較差(殘差較大),那麼9時的預測也好不到哪裡去(殘差也會較大)。

為了方便模型比較,後續將計算MAE, R-Square值。為此,筆者寫了兩個函式用於計算MAE, R-Square值。

calc_mae

<-

function

residuals

){

return

round

mean

abs

residuals

)),

3

))

}

calc_r2

<-

function

residuals

actual

){

ssr

<-

sum

residuals

^

2

sst

<-

sum

(((

actual

-

mean

actual

))

*

col_stddevs

^

2

r2

<-

1

-

ssr

/

sst

return

round

r2

3

))

}

在上例中,計算MAE, R-Square如下:

calc_mae

rs

);

calc_r2

rs

y_test_hour

[,,

1

])

[1] 2。776

[1] 0。84

請注意,同一個模型在相同的訓練資料下,每次訓練的結果(模型引數)都會有差異的,因此,對同一批資料的預測、殘差,及MAE, R-Square的值都會不同。

我們將上述LSTM模型,重複執行100次,從模型定義、編譯、訓練、到結果預測,相應地得到每一次預測的殘差、MAE, R-Square的計算結果。改造後的程式碼如下:

model_lstm

<-

function

(){

model

<-

keras_model_sequential

()

%>%

layer_lstm

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

recurrent_activation

=

sigmoid

#

enable

CUDNN

return_sequences

=

TRUE

%>%

time_distributed

layer_dense

units

=

1

))

model

%>%

compile

loss

=

“logcosh”

optimizer

=

optimizer_rmsprop

(),

metrics

=

list

“mean_squared_error”

history

<-

model

%>%

fit

x

=

X_train

y

=

y_train_hour

validation_split

=

0

2

#

validation_data

=

list

X_valid

y_valid

),

batch_size

=

batch_size

epochs

=

30

callbacks

=

callbacks

return

model

}

num

<-

100

rs_lstm

<-

matrix

rep

0

0

num

*

4

),

nrow

=

num

for

i

in

1

num

){

pred_test

<-

model_lstm

()%>%

predict

X_test

batch_size

=

batch_size

%>%

。[,

1

rs_lstm

i

<-

calc_model_lstm_residuals

pred_test

}

rs_lstm包含100行記錄,下面的表格顯示前面10次的預測評估結果:

訓練/預測序號

殘差均值

殘差均方差

MAE

R-Square

1

0。176

3。51

2。733

0。843

2

-0。1

3。40

2。653

0。852

3

-0。49

3。44

2。724

0。846

4

0。137

3。49

2。717

0。845

5

-0。372

3。53

2。788

0。839

6

-0。119

3。50

2。743

0。843

7

-0。129

3。51

2。744

0。843

8

-0。245

3。43

2。690

0。849

9

-0。124

3。45

2。688

0。848

10

-0。103

3。48

2。709

0。845

基於這100次模型預測的殘差均值、殘差均方差、MAE、R-Square,繪製分佈圖如下。同時,疊加藍色正態分佈曲線,中間藍色線代表中值,兩側綠色豎線代表p = 0。05下的雙側置信區間。

深度學習 - 時間序列分析例項(二)

直方圖的密度不夠精細,而且看起來有點左偏,或右偏(綠色置信區間相對藍色中值線不對稱)。但是相對正態分佈曲線的擬合基本是一致的,“左偏”或“右偏”的一個重要因素是由於取樣資料量不夠(僅有100個測試結果)造成的。

注:連續執行100次LSTM模型的訓練和預測,在筆者的配置RTX4000的Ubuntu上運行了大約40分鐘。

基於上述結果,補充說明幾點如下:

殘差均值的中值是

-0.091

,基本上是在0附近。一個有效的模型,預測結果的殘差應該是均值為0的正態分佈,因此,此模型基本滿足。

殘差均方差、MAE、R-Square的均方差都很小,在很窄的區間(置信區間也比較窄)波動。這說明模型的每次執行結果是比較穩定的。

下面針對其他針對時間序列的常用深度學習模型,每一個都執行100次訓練和預測,並比較各個模型的預測評估指標。可以看出:只要模型是收斂的,每次訓練的模型,對資料的預測結果雖然有差異,但是差異一般都在可控範圍內。

其他用於時間序列預測的深度學習模型

LSTM作為典型的RNN (Recurrent Neural Network),被廣泛應用,此外,為了學習的目的,下面繼續探索其他幾個常用的、用於時間序列分析的深度學習模型,包括LSTM的擴充套件。

此外,常用的多層感知器模型MLP(Multilayer Perceptron)也可以用於時間序列分析,只是相對於上述模型,沒有任何優勢。這裡就不浪費版面了。

GRU模型

GRU是LSTM的變體。據說,可以有效緩解LSTM的梯度消失問題(vanish gradient problem)。由於GRU比LSTM少一個門(Gate),訓練的收斂時間會更快。

在保持各項引數與LSTM模型一樣的前提下,僅僅模型定義有一點不同(注意紅色GRU layer名稱),程式碼如下:

model_gru

<-

keras_model_sequential

()

%>%

layer_gru

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

return_sequences

=

TRUE

%>%

time_distributed

layer_dense

units

=

1

))

簡單(Simple)RNN模型

RNN的結構有很多,此處Simple RNN代表最簡單的RNN模型。類似於前面的模型定義,僅僅紅色Simple RNN layer名稱不同。

model_rnn

<-

keras_model_sequential

()

%>%

layer_simple_rnn

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

return_sequences

=

TRUE

%>%

time_distributed

layer_dense

units

=

1

))

雙向(Bidirectional)LSTM模型

Bidirectional LSTM相對於前面那個簡單的LSTM,通常能夠提供更優的表現,常用於自然語言處理(NLP)任務,有人稱它為自然語言處理的瑞士軍刀(曾經的)。

LSTM等RNN模型處理輸入資料的時候,是按照時間順序來處理的,與MLP, CNN等模型相比,充分利用時間順序的特性,因此是處理時序資料的更加合適的選擇。

Bidirectional LSTM在處理正向時序的同時,還處理了反向時序,所以,相當於包含了兩個LSTM網路模組,理論上能夠獲取單向LSTM可能忽略的特性。大多數實踐證明了Bidirectional LSTM的表現比單向LSTM更優。

Bidirectional LSTM的實現比較簡單,在第一個LSTM模型的基礎上簡單改造一下,在layer_lstm外面呼叫bidirectional即可。

model_lstm_bi

<-

keras_model_sequential

()

%>%

bidirectional

layer_lstm

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

recurrent_activation

=

sigmoid

#

enable

CUDNN

return_sequences

=

TRUE

%>%

time_distributed

layer_dense

units

=

1

))

在模型定義完了之後,如果立即呼叫summary(model_lstm_bi)函式會報錯,因為bidirectional需要完成構造之後才能給出模型摘要資訊,這是這個模型的不同之處。

其次,由於是雙向的LSTM,模型引數幾乎翻了一倍。

第三,模型預測效果相對前面的幾個模型,好了不少,尤其是在極大值、極小值處。將這個模型輸出的結果和第一個LSTM模型輸出的結果進行比較:

下圖中,黑線代表真實值,紅線/紅點代表LSTM模型預測的結果,藍線/藍點代表Bidirectional LSTM模型預測的結果。很明顯,藍線/藍點更加接近真實值。

左邊這張圖選擇從100-150(因為中間包含了極小值)預測序列中的第一個小時(每個輸入預測後續20小時);

右邊這張圖顯示第一個預測序列的全部24小時的結果。

深度學習 - 時間序列分析例項(二)

多層LSTM模型

前面所有的模型都是最小化模型的層級。下面試驗LSTM層之上再疊加一層網路,分兩種情況,看看預測效果如何。

第一種,兩層LSTM層。第二層LSTM輸出單元數也是128,方便和Bidirectional LSTM比較。

model_lstm2

<-

keras_model_sequential

()

%>%

layer_lstm

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

recurrent_activation

=

sigmoid

#

enable

CUDNN

return_sequences

=

TRUE

%>%

layer_lstm

units

=

128

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

recurrent_activation

=

sigmoid

#

enable

CUDNN

return_sequences

=

TRUE

%>%

time_distributed

layer_dense

units

=

1

))

第二種,在LSTM層之上疊加一層Dense(全連線層),每個時間節點輸出單元數為128,與LSTM + LSTM及Bidirectional LSTM引數設定一致,以便於比較效果。

model_lstm_dense

<-

keras_model_sequential

()

%>%

layer_lstm

units

=

128

input_shape

=

list

time_steps

14

),

dropout

=

0

2

recurrent_dropout

=

0

#

enable

CUDNN

recurrent_activation

=

sigmoid

#

enable

CUDNN

return_sequences

=

TRUE

%>%

layer_dense

units

=

128

%>%

time_distributed

layer_dense

units

=

1

))

模型預測能力比較

上述所有6種模型都是基於不同神經網路元件搭建的淺層(除了最後一層作為輸出層time_distributed(layer_dense(units = 1)),僅有一到兩層元件)深度學習模型。為了方便比較,第一層都是採用128個輸出神經元(每個時間點)。

因為每一次執行,同一個模型會給出略微不同的訓練結果(模型引數)和預測結果。為了更好地比較模型的預測能力,如同前面針對LSTM模型所作的,筆者針對每一個模型,都執行100次,計算每一個模型下各個引數的中值(殘差均值、殘差均方差、MAE、R-Square)。

如下表所示,除了模型的自由引數數量,各個引數顯示的是基於100次訓練和預測結果,計算的中值。

深度學習 - 時間序列分析例項(二)

Bidirectional LSTM相對其他模型而言算是鶴立雞群,MAE(越小越好)明顯小了很多,R-Square(越接近1越好)明顯大了很多。

為了方便比較,做了兩個箱型圖(Box plot),更好地比較MAE, R-Square在各個模型下的分佈情況:

Bidirectional LSTM無論是MAE,還是R-Square都是表現最好,一枝獨秀。

RNN相對所有其他模型而言效果最差,但是從肉眼可見的角度,除了Bidirectional LSTM, LSTM之外,和其他3個模型都存在箱形重疊,因此從統計的角度看,這種差別是不顯著的,所以不能說它和那3個模型在預測能力方面存在統計上的差別。

從箱型的寬度和尾部點數分佈來看,RNN, LSTM+Dense模型的穩定性稍差。

大概氣溫預測問題的複雜度相對較小,兩層LSTM模型相對於單層LSTM模型並未表現出優勢來。

深度學習 - 時間序列分析例項(二)

深度學習 - 時間序列分析例項(二)

下一步

本篇探討的都是簡單的、網路層數最小化的結構模型,模型的深度非常淺,除了最後輸出層(time_distributed(layer_dense(units = 1))),最多隻有一層,或兩層。當應用了NVIDIA GPU之後,每一論(epoch)的訓練時間都是秒殺(1秒以內),以致於都感受不到,不同模型在訓練時間上的差異。

下一篇繼續以LSTM作為基本元件,探討具有相對複雜結構的深度學習模型,並瞭解他們之間的差異和特性。

金戈老馬:深度學習 - 時間序列分析例項(一)

金戈老馬:深度學習 - 時間序列分析例項(三)

金戈老馬:時間序列分析 - 大資料競賽例項

我的專欄:

深度學習入門及實戰

汽車、出行大資料分析

標簽: 模型  LSTM  殘差  layer  dropout