时间序列预测算法——DeepAR
DeepAR概述
DeepAR是亞馬遜提出的一種針對大量相關時間序列統一建模的預測算法,該算法采用了深度學習的技術,通過在大量時間序列上訓練自回歸遞歸網絡模型,可以從相關的時間序列中有效地學習全局模型,并且能夠學習復雜的模式,例如季節性、數據隨時間的不確定性增長,從而對各條時間序列進行預測。
DeepAR原理和實現過程
上圖左邊是模型的訓練過程,右邊是模型的預測過程。
原理
deepar目標是在給定歷史history_len時間長度的值及特征的情況下,預測未來future_len時間長度的值。
用zi,t表示第i條序列t時刻的值,xi,t表示第i條t時刻的特征,用表達式來表示就是:P(zi,t0:T∣zi,1:t0?1,Xi,1:T)P(z_{i,t_0:T}|z_{i,1:t_0-1},X_{i,1:T})P(zi,t0?:T?∣zi,1:t0??1?,Xi,1:T?),其中[zi,t0,zi,t0+1,...,zi,T]:=zi,t0:T[z_{i,t_0},z_{i,t_0{+1}},...,z_{i,T}] := z_{i,t_0:T}[zi,t0??,zi,t0?+1?,...,zi,T?]:=zi,t0?:T?,[zi,1,...zi,t0?2,zi,t0?1]:=zi,1:t0?1[z_{i,1},...z_{i,t_0{-2}},z_{i,t_0{-1}}] := z_{i,1:t_0-1}[zi,1?,...zi,t0??2?,zi,t0??1?]:=zi,1:t0??1?,[1,t0?1][1,t_0-1][1,t0??1]代表歷史區間,[t0,T][t_0,T][t0?,T]代表預測區間。
基于以上,論文設定模型分布由似然因子的乘積組成:
hi,th_{i,t}hi,t?由神經網絡獲得,即:hi,t=h(hi,t?1,zi,t?1,Xi,t,Θ)h_{i,t}=h(h_{i,t-1},z_{i,t-1},X_{i,t},Θ)hi,t?=h(hi,t?1?,zi,t?1?,Xi,t?,Θ);似然l(zi,t∣θ(hi,t,Θ))l(z_{i,t}|θ(h_{i,t},Θ))l(zi,t?∣θ(hi,t?,Θ))是一個fixed分布,其中的參數由神經網絡(lstm)的輸出hi,th_{i,t}hi,t?經過函數θ(hi,t,Θ)θ(h_{i,t},Θ)θ(hi,t?,Θ)的仿射獲得。
論文中提及了關于似然函數的選擇, Gaussian likelihood比較適合數值型數據;計數型的數據比較適合negative-binomial likelihood,另外還有Bernoulli likelihood,student_t等,亞馬遜在SageMaker中實現的deepar默認選擇的似然函數就是student_t。
最后關于模型loss的選擇,論文選用對數似然進行梯度優化訓練參數。
實現過程
訓練時,模型每一時刻的輸入包括前一時刻的真實值和當前時刻的特征x,x可以是當前時刻的時間特征;然后經過神經網絡的學習,對網絡返回的狀態hit進行函數仿射,返回當前時刻的預測概率分布。
預測時,每個時刻的輸入也包括兩部分:前一時刻的預測值和當前時刻的協變量x,即是一種遞歸式的預測方法;然后利用學習好的網絡,進行預測。
基于此,可以通過encode-decode的模式來實現DeepAR,其encode和decode的網絡部分可以使用lstm。假設時間序列的時間粒度是分鐘級別,可以利用RNN對l歷史encode_len分鐘長度的時間序列進行encode,返回的隱藏狀態輸入到decode,預測接下來decode_len分鐘長度的時間序列值。
下面是給出算法核心部分的代碼實現
訓練
首先定義一個lstm,encode和decode都是基于lstm。
def lstm_cell(layer_num,hidden_size,keep_prob):stacked_rnn = []for i in range(layer_num):lstm = tf.contrib.cudnn_rnn.CudnnCompatibleLSTMCell(hidden_size)drop = tf.nn.rnn_cell.DropoutWrapper(lstm, output_keep_prob=keep_prob)stacked_rnn.append(drop)lstm_multi = tf.contrib.rnn.MultiRNNCell(stacked_rnn)return lstm_multiencode
def encoder(encoder_input, encoder_seq_len, keep_prob):cells = lstm_cell(layer_num,hidden_size,keep_prob)with tf.variable_scope('encoder', reuse=tf.AUTO_REUSE):_, encoder_state = tf.nn.dynamic_rnn(cell=cells, inputs=encoder_input,sequence_length=encoder_seq_len,dtype=tf.float32)return encoder_statedecode
def decoder(decoder_input, decoder_seq_len, state_in, keep_prob):cells = lstm_cell(keep_prob)with tf.variable_scope('decoder', reuse=tf.AUTO_REUSE):decoder_outputs, decoder_state = tf.nn.dynamic_rnn(cell=cells,inputs=decoder_input,sequence_length=decoder_seq_len, initial_state=state_in)return decoder_outputs, decoder_stateloss
舉例使用高斯似然,對decode的輸出狀態進行仿射得到計算高斯似然的參數,從而計算loss進行梯度優化。
def create_gaussian_parameters(decoder_outputs, decoder_scale_factor, decoder_len,hidden_size):"""對decode的輸出進行仿射,得出計算高斯似然的參數。decoder_scale_factor:是歸一化因子"""batch_size = tf.shape(decoder_outputs)[0]with tf.variable_scope('gaussian_parameters', reuse=tf.AUTO_REUSE):W_mu = tf.get_variable(shape=[hidden_size, 1], dtype=tf.float32,name="W_mu")W_sigma = tf.get_variable(shape=[hidden_size, 1], dtype=tf.float32,name="W_sigma")b_mu = tf.get_variable(shape=[1], dtype=tf.float32, name="b_mu")b_sigma = tf.get_variable(shape=[1], dtype=tf.float32, name="b_sigma")W_mu_expand = tf.tile(tf.expand_dims(W_mu, 0), [batch_size, 1, 1])W_sigma_expand = tf.tile(tf.expand_dims(W_sigma, 0), [batch_size, 1, 1])b_mu_expand = tf.tile(tf.expand_dims(b_mu, 0), [batch_size, 1])b_sigma_expand = tf.tile(tf.expand_dims(b_sigma, 0), [batch_size, 1])mu = tf.reshape(tf.matmul(decoder_outputs, W_mu_expand), [batch_size, -1]) + b_mu_expandsigma = tf.log(1 + tf.math.exp(tf.reshape(tf.matmul(decoder_outputs, W_sigma_expand), [batch_size, -1]) + b_sigma_expand)) + 1e-6mu_scale = tf.math.multiply(mu, tf.reshape(decoder_scale_factor, [-1,decoder_len]))sigma_scale = tf.math.multiply(sigma, tf.reshape(decoder_scale_factor, [-1,decoder_len]))return mu_scale, sigma_scaledef gaussian_likelihood(y_true, mu, sigma):return tf.math.reduce_mean(0.5 * tf.math.log(tf.math.square(sigma)) + 0.5 * tf.math.divide(tf.math.square(y_true - mu),tf.math.square(sigma))) + 1e-6預測
encode
預測時候的encode和訓練時候一樣。
decode
def decoder_inference(encoder_state, decoder_x_input_scale, decoder_len,decoder_feature, decoder_scale_factor, keep_prob):"""推理的時候,需要將當前時刻的預測值傳遞給下一個時刻的輸入。訓練的時候,因為數據都已知,所以直接做一個shift的平移。"""mu_ta = tf.TensorArray(dtype=tf.float32, size=decoder_len)sigma_alpha_ta = tf.TensorArray(dtype=tf.float32, size=decoder_len)def cond_fn(time, prev_state, prev_output, decoder_scale_factor, mu_ta, sigma_alpha_ta):return time < decoder_lendef loop_fn(time, prev_state, prev_output, decoder_scale_factor, mu_ta, sigma_alpha_ta):batch_size = tf.shape(prev_output)[0]features = tf.slice(decoder_feature, [0, time, 0], [-1, 1, -1])next_input = tf.concat([prev_output, features], -1)decoder_seq_len = tf.ones([batch_size])decoder_outputs, decoder_state = decoder(next_input, decoder_seq_len, prev_state, keep_prob)mu, sigma_alpha = create_gaussian_parameters(decoder_outputs, decoder_scale_factor, 1)mu_ta = mu_ta.write(time, mu)sigma_alpha_ta = sigma_alpha_ta.write(time, sigma_alpha)sample_data = musample_data_scale = tf.math.divide(tf.reshape(sample_data, [batch_size, 1, 1]), decoder_scale_factor)return time + 1, decoder_state, sample_data_scale, decoder_scale_factor, mu_ta, sigma_alpha_taloop_init = [tf.constant(0, dtype=tf.int32),encoder_state,decoder_x_input_scale,decoder_scale_factor,mu_ta,sigma_alpha_ta]_, _, _, _, mu_output, sigma_alpha_output = tf.while_loop(cond_fn, loop_fn, loop_init)mu_result = tf.reshape(tf.transpose(mu_output.stack(), perm=[1, 0, 2]),[-1, decoder_len])sigma_alpha_result = tf.reshape(tf.transpose(sigma_alpha_output.stack(), perm=[1, 0, 2]),[-1, decoder_len])return mu_result, sigma_alpha_result算法的優缺點
優點
1.對實數和計數分別設計了不同的loss;
2.數據預處理方面使用歸一化的變換和預測使用weighted sampling。
缺點
1.沒有attention機制,對較長的時間序列可能會出現記憶丟失的問題,無法捕獲長周期、季節等信息。但在輸入部分可以加入attention機制,比如用同期的數據作為一個特征。
其他
1.預測多條時間序列時,論文中提到可以對每條時間序序列進行category的編碼,訓練時進行embedding的學習;
2.可以提取每條時間序列的時間特征,作為feature輸入到模型。
論文
論文連接
總結
以上是生活随笔為你收集整理的时间序列预测算法——DeepAR的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: EndNoteX7中conference
- 下一篇: java 判断数字二进制有几位_判断一个