使用tensorflow seq2seq進行時間序列預測

來源:互聯網
上載者:User

時間序列預測可以根據短期預測,長期預測,以及具體情境選用不同的方法,如ARMA、ARIMA、神經網路預測、SVM預測、灰色預測、模糊預測、組合預測法等等。所謂沒有最好的模型,只有最適合的模型。至於哪一種模型能針對特定預測問題達到最高的精度,需要通過實驗來證明。本文通過產生的隨機數利用tensorflow的seq2seq模型進行單變數時間序列預測實驗,目的是理解seq2seq的模型基礎架構以及驗證模型在非線性資料上的表達能力。這裡暫時不考慮帶Attention機制的模型,具體可以參考Neural Machine Translation By Jointly Learning to Align and Translate。
最基礎的Seq2Seq模型包含了三個部分,即Encoder、Decoder以及串連兩者的中間狀態向量,Encoder通過學習輸入,將其編碼成一個固定大小的狀態向量S,繼而將S傳給Decoder,Decoder再通過對狀態向量S的學習來進行輸出。下圖是encoder與decoder均基於LSTM的模型。

首先我們匯入需要的包:

import tensorflow as tfimport numpy as np import randomimport mathfrom matplotlib import pyplot as pltimport osimport copy

1.資料準備
首先,我們產生一系列沒有噪音的樣本:

x = np.linspace(0, 30, 105)y = 2 * np.sin(x)l1, = plt.plot(x[:85], y[:85], 'y', label = 'training samples')l2, = plt.plot(x[85:], y[85:105], 'c--', label = 'test samples')plt.legend(handles = [l1, l2], loc = 'upper left')plt.show()


為了類比真實世界的資料,我們添加一些隨機噪音:

train_y = y.copy()noise_factor = 0.5train_y += np.random.randn(105) * noise_factorl1, = plt.plot(x[:85], train_y[:85], 'yo', label = 'training samples')plt.plot(x[:85], y[:85], 'y:')l2, = plt.plot(x[85:], train_y[85:], 'co', label = 'test samples')plt.plot(x[85:], y[85:], 'c:')plt.legend(handles = [l1, l2], loc = 'upper left')plt.show()


然後,我們設定輸入輸出的序列長度,並產生訓練樣本和測試樣本:

input_seq_len = 15output_seq_len = 20x = np.linspace(0, 30, 105)train_data_x = x[:85]def true_signal(x):    y = 2 * np.sin(x)    return ydef noise_func(x, noise_factor = 1):    return np.random.randn(len(x)) * noise_factordef generate_y_values(x):    return true_signal(x) + noise_func(x)def generate_train_samples(x = train_data_x, batch_size = 10, input_seq_len = input_seq_len, output_seq_len = output_seq_len):    total_start_points = len(x) - input_seq_len - output_seq_len    start_x_idx = np.random.choice(range(total_start_points), batch_size)    input_seq_x = [x[i:(i+input_seq_len)] for i in start_x_idx]    output_seq_x = [x[(i+input_seq_len):(i+input_seq_len+output_seq_len)] for i in start_x_idx]    input_seq_y = [generate_y_values(x) for x in input_seq_x]    output_seq_y = [generate_y_values(x) for x in output_seq_x]    #batch_x = np.array([[true_signal()]])    return np.array(input_seq_y), np.array(output_seq_y)
input_seq, output_seq = generate_train_samples(batch_size=10)

對含有噪音的資料進行可視化:

results = []for i in range(100):    temp = generate_y_values(x)    results.append(temp)results = np.array(results)for i in range(100):    l1, = plt.plot(results[i].reshape(105, -1), 'co', lw = 0.1, alpha = 0.05, label = 'noisy training data')l2, = plt.plot(true_signal(x), 'm', label = 'hidden true signal')plt.legend(handles = [l1, l2], loc = 'lower left')plt.show()

2.建立基本的RNN模型
2.1參數設定

## Parameterslearning_rate = 0.01lambda_l2_reg = 0.003  ## Network Parameters# length of input signalsinput_seq_len = 15 # length of output signalsoutput_seq_len = 20 # size of LSTM Cellhidden_dim = 64 # num of input signalsinput_dim = 1# num of output signalsoutput_dim = 1# num of stacked lstm layers num_stacked_layers = 2 # gradient clipping - to avoid gradient explodingGRADIENT_CLIPPING = 2.5 

2.2 模型架構
這裡的seq2seq模型基本與tensorflow在github中提供的模型一致。

def build_graph(feed_previous = False):    tf.reset_default_graph()    global_step = tf.Variable(                  initial_value=0,                  name="global_step",                  trainable=False,                  collections=[tf.GraphKeys.GLOBAL_STEP, tf.GraphKeys.GLOBAL_VARIABLES])    weights = {        'out': tf.get_variable('Weights_out', \                               shape = [hidden_dim, output_dim], \                               dtype = tf.float32, \                               initializer = tf.truncated_normal_initializer()),    }    biases = {        'out': tf.get_variable('Biases_out', \                               shape = [output_dim], \                               dtype = tf.float32, \                               initializer = tf.constant_initializer(0.)),    }    with tf.variable_scope('Seq2seq'):        # Encoder: inputs        enc_inp = [            tf.placeholder(tf.float32, shape=(None, input_dim), name="inp_{}".format(t))               for t in range(input_seq_len)        ]        # Decoder: target outputs        target_seq = [            tf.placeholder(tf.float32, shape=(None, output_dim), name="y".format(t))              for t in range(output_seq_len)        ]        # Give a "GO" token to the decoder.         # If dec_inp are fed into decoder as inputs, this is 'guided' training; otherwise only the         # first element will be fed as decoder input which is then 'un-guided'        dec_inp = [ tf.zeros_like(target_seq[0], dtype=tf.float32, name="GO") ] + target_seq[:-1]        with tf.variable_scope('LSTMCell'):             cells = []            for i in range(num_stacked_layers):                with tf.variable_scope('RNN_{}'.format(i)):                    cells.append(tf.contrib.rnn.LSTMCell(hidden_dim))            cell = tf.contrib.rnn.MultiRNNCell(cells)        def _rnn_decoder(decoder_inputs,                        initial_state,                        cell,                        loop_function=None,                        scope=None):          """RNN decoder for the sequence-to-sequence model.          Args:            decoder_inputs: A list of 2D Tensors [batch_size x input_size].            initial_state: 2D Tensor with shape [batch_size x cell.state_size].            cell: rnn_cell.RNNCell defining the cell function and size.            loop_function: If not None, this function will be applied to the i-th output              in order to generate the i+1-st input, and decoder_inputs will be ignored,              except for the first element ("GO" symbol). This can be used for decoding,              but also for training to emulate http://arxiv.org/abs/1506.03099.              Signature -- loop_function(prev, i) = next                * prev is a 2D Tensor of shape [batch_size x output_size],                * i is an integer, the step number (when advanced control is needed),                * next is a 2D Tensor of shape [batch_size x input_size].            scope: VariableScope for the created subgraph; defaults to "rnn_decoder".          Returns:            A tuple of the form (outputs, state), where:              outputs: A list of the same length as decoder_inputs of 2D Tensors with                shape [batch_size x output_size] containing generated outputs.              state: The state of each cell at the final time-step.                It is a 2D Tensor of shape [batch_size x cell.state_size].                (Note that in some cases, like basic RNN cell or GRU cell, outputs and                 states can be the same. They are different for LSTM cells though.)          """          with variable_scope.variable_scope(scope or "rnn_decoder"):            state = initial_state            outputs = []            prev = None            for i, inp in enumerate(decoder_inputs):              if loop_function is not None and prev is not None:                with variable_scope.variable_scope("loop_function", reuse=True):                  inp = loop_function(prev, i)              if i > 0:                variable_scope.get_variable_scope().reuse_variables()              output, state = cell(inp, state)              outputs.append(output)              if loop_function is not None:                prev = output          return outputs, state        def _basic_rnn_seq2seq(encoder_inputs,                              decoder_inputs,                              cell,                              feed_previous,                              dtype=dtypes.float32,                              scope=None):          """Basic RNN sequence-to-sequence model.          This model first runs an RNN to encode encoder_inputs into a state vector,          then runs decoder, initialized with the last encoder state, on decoder_inputs.          Encoder and decoder use the same RNN cell type, but don't share parameters.          Args:            encoder_inputs: A list of 2D Tensors [batch_size x input_size].            decoder_inputs: A list of 2D Tensors [batch_size x input_size].            feed_previous: Boolean; if True, only the first of decoder_inputs will be              used (the "GO" symbol), all other inputs will be generated by the previous               decoder output using _loop_function below. If False, decoder_inputs are used               as given (the standard decoder case).            dtype: The dtype of the initial state of the RNN cell (default: tf.float32).            scope: VariableScope for the created subgraph; default: "basic_rnn_seq2seq".          Returns:            A tuple of the form (outputs, state), where:              outputs: A list of the same length as decoder_inputs of 2D Tensors with                shape [batch_size x output_size] containing the generated outputs.              state: The state of each decoder cell in the final time-step.                It is a 2D Tensor of shape [batch_size x cell.state_size].          """          with variable_scope.variable_scope(scope or "basic_rnn_seq2seq"):            enc_cell = copy.deepcopy(cell)            _, enc_state = rnn.static_rnn(enc_cell, encoder_inputs, dtype=dtype)            if feed_previous:                return _rnn_decoder(decoder_inputs, enc_state, cell, _loop_function)            else:                return _rnn_decoder(decoder_inputs, enc_state, cell)        def _loop_function(prev, _):          '''Naive implementation of loop function for _rnn_decoder. Transform prev from           dimension [batch_size x hidden_dim] to [batch_size x output_dim], which will be          used as decoder input of next time step '''          return tf.matmul(prev, weights['out']) + biases['out']        dec_outputs, dec_memory = _basic_rnn_seq2seq(            enc_inp,             dec_inp,             cell,             feed_previous = feed_previous        )        reshaped_outputs = [tf.matmul(i, weights['out']) + biases['out'] for i in dec_outputs]    # Training loss and optimizer    with tf.variable_scope('Loss'):        # L2 loss        output_loss = 0        for _y, _Y in zip(reshaped_outputs, target_seq):            output_loss += tf.reduce_mean(tf.pow(_y - _Y, 2))        # L2 regularization for weights and biases        reg_loss = 0        for tf_var in tf.trainable_variables():            if 'Biases_' in tf_var.name or 'Weights_' in tf_var.name:                reg_loss += tf.reduce_mean(tf.nn.l2_loss(tf_var))        loss = output_loss + lambda_l2_reg * reg_loss    with tf.variable_scope('Optimizer'):        optimizer = tf.contrib.layers.optimize_loss(                loss=loss,                learning_rate=learning_rate,                global_step=global_step,                optimizer='Adam',                clip_gradients=GRADIENT_CLIPPING)    saver = tf.train.Saver    return dict(        enc_inp = enc_inp,         target_seq = target_seq,         train_op = optimizer,         loss=loss,        saver = saver,         reshaped_outputs = reshaped_outputs,        )

2.3模型訓練
在這裡設定了batch size為16,迭代次數為100。

total_iteractions = 100batch_size = 16KEEP_RATE = 0.5train_losses = []val_losses = []x = np.linspace(0, 30, 105)train_data_x = x[:85]rnn_model = build_graph(feed_previous=False)saver = tf.train.Saver()init = tf.global_variables_initializer()with tf.Session() as sess:    sess.run(init)    for i in range(total_iteractions):        batch_input, batch_output = generate_train_samples(batch_size=batch_size)        feed_dict = {rnn_model['enc_inp'][t]: batch_input[:,t].reshape(-1,input_dim) for t in range(input_seq_len)}        feed_dict.update({rnn_model['target_seq'][t]: batch_output[:,t].reshape(-1,output_dim) for t in range(output_seq_len)})        _, loss_t = sess.run([rnn_model['train_op'], rnn_model['loss']], feed_dict)        print(loss_t)    temp_saver = rnn_model['saver']()    save_path = temp_saver.save(sess, os.path.join('./', 'univariate_ts_model0'))print("Checkpoint saved at: ", save_path)

可見輸出的loss呈降低的趨勢:

57.305332.093452.93537.321537.12136.081224.072727.501627.862129.210425.280426.449324.891426.579924.987122.037324.207923.108424.799124.045225.478823.023722.950825.118127.694220.536721.289928.433621.994321.856826.513822.560221.146622.020325.046621.058823.058522.531126.107621.89720.69421.45921.108220.917621.814621.029922.360920.405721.078823.216224.853722.120220.745822.541121.442323.826623.352822.593420.263121.490719.601120.598323.436625.637723.413420.677318.80225.34122.93521.841322.159923.442224.042722.896322.33620.39722.016221.238920.533621.060522.886322.383922.105922.003220.50523.421626.962622.887521.953522.489820.173419.93619.721822.719120.206719.496424.020721.003922.3820.1875Checkpoint saved at:  ./univariate_ts_model0

3.預測
我們將模型用在測試集中進行預測

test_seq_input = true_signal(train_data_x[-15:])rnn_model = build_graph(feed_previous=True)init = tf.global_variables_initializer()with tf.Session() as sess:    sess.run(init)    saver = rnn_model['saver']().restore(sess, os.path.join('./', 'univariate_ts_model0'))    feed_dict = {rnn_model['enc_inp'][t]: test_seq_input[t].reshape(1,1) for t in range(input_seq_len)}    feed_dict.update({rnn_model['target_seq'][t]: np.zeros([1, output_dim]) for t in range(output_seq_len)})    final_preds = sess.run(rnn_model['reshaped_outputs'], feed_dict)    final_preds = np.concatenate(final_preds, axis = 1)

得到的預測效果如下:

l1, = plt.plot(range(85), true_signal(train_data_x[:85]), label = 'Training truth')l2, = plt.plot(range(85, 105), y[85:], 'yo', label = 'Test truth')l3, = plt.plot(range(85, 105), final_preds.reshape(-1), 'ro', label = 'Test predictions')plt.legend(handles = [l1, l2, l3], loc = 'lower left')plt.show()

references:
https://weiminwang.blog/2017/09/29/multivariate-time-series-forecast-using-seq2seq-in-tensorflow/
http://baijiahao.baidu.com/s?id=1571869641858839&wfr=spider&for=pc
https://blog.csdn.net/leadai/article/details/78809788
https://www.zhihu.com/question/21229371
https://blog.csdn.net/thriving_fcl/article/details/74853556

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.