# ---
# jupyter:
#   jupytext:
#     text_representation:
#       extension: .py
#       format_name: light
#       format_version: '1.5'
#       jupytext_version: 1.14.4
#   kernelspec:
#     display_name: Python 3
#     language: python
#     name: python3
# ---

# # Multivariate - single step

from numpy import *
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import *

# define input sequence. Example of defining multiple input and a dependent time series.
in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])

out_seq

# convert to [rows, columns] structure
in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))
# horizontally stack columns
dataset = hstack((in_seq1, in_seq2, out_seq))

dataset


# split a multivariate sequence into samples
def split_sequences(sequences, n_steps):
    X, y = list(), list()
    for i in range(len(sequences)):
        # find the end of this pattern
        end_ix = i + n_steps
        # check if we are beyond the dataset
        if end_ix > len(sequences):
            break
        # gather input and output parts of the pattern
        seq_x, seq_y = sequences[i:end_ix, :-1], sequences[end_ix-1, -1]
        X.append(seq_x)
        y.append(seq_y)
    return array(X), array(y)


# choose a number of time steps
n_steps = 3
# convert into input/output
X, y = split_sequences(dataset, n_steps) # X follows [samples, timesteps, features]
print(X.shape, y.shape)
# summarize the data
for i in range(len(X)):
    print(X[i], y[i])

# define model
n_features = 2
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(n_steps, n_features)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
model.summary()

# demonstrate prediction, Example of making an out-of-sample forecast
x_input = array([[80, 85], [90, 95], [100, 105]])
x_input = x_input.reshape((1, n_steps, n_features)) # (1 sample, 3 time steps, 2 features)
yhat = model.predict(x_input, verbose=0)
print(yhat)


# # Univariate Multi-step LSTM

# ## Vector Output Model

# split a univariate sequence into samples
def split_sequence(sequence, n_steps_in, n_steps_out):
    X, y = list(), list()
    for i in range(len(sequence)):
        # find the end of this pattern
        end_ix = i + n_steps_in
        out_end_ix = end_ix + n_steps_out
        # check if we are beyond the sequence
        if out_end_ix > len(sequence):
            break
        # gather input and output parts of the pattern
        seq_x, seq_y = sequence[i:end_ix], sequence[end_ix:out_end_ix]
        X.append(seq_x)
        y.append(seq_y)
    return array(X), array(y)
# define input sequence
raw_seq = [10, 20, 30, 40, 50, 60, 70, 80, 90]
# choose a number of time steps
n_steps_in, n_steps_out = 3, 2
# split into samples
X, y = split_sequence(raw_seq, n_steps_in, n_steps_out)
# summarize the data
for i in range(len(X)):
    print(X[i], y[i])

# reshape from [samples, timesteps] into [samples, timesteps, features]
n_features = 1
X = X.reshape((X.shape[0], X.shape[1], n_features))

# define model
model = Sequential()
model.add(LSTM(100, activation='relu', return_sequences=True, input_shape=(n_steps_in, n_features)))
model.add(LSTM(100, activation='relu'))
model.add(Dense(n_steps_out)) # 这里用于产生2个output，Vector Output，相当于multi-step ahead
model.compile(optimizer='adam', loss='mse')

# fit model
model.fit(X, y, epochs=50, verbose=0)
# demonstrate prediction
x_input = array([70, 80, 90])
x_input = x_input.reshape((1, n_steps_in, n_features))
yhat = model.predict(x_input, verbose=0)
print(yhat)

# ## Encoder-Decoder LSTM

# The model was designed for prediction problems where there are both input and output sequences, so-called sequence-to-sequence, or seq2seq problems, such as translating text from one language to another. This model can be used for multi-step time series forecasting. As its name suggests, the model is comprised of two sub-models: the encoder and the decoder.

# The encoder is a model responsible for reading and interpreting the input sequence. The output of the encoder is a fixed length vector that represents the model’s interpretation of the sequence. The encoder is traditionally a Vanilla LSTM model, although other encoder models can be used such as Stacked, Bidirectional, and CNN models.

model = Sequential()
# define encoder model
model.add(LSTM(100, activation='relu', input_shape=(n_steps_in, n_features)))

# The decoder uses the output of the encoder as an input. First, the **fixed-length output of the encoder is repeated**, once for each required time step in the output sequence.
#
# If the number of input and output time steps vary, then an Encoder-Decoder architecture can be used. The input time steps are mapped to a **fixed sized internal representation of the sequence**, then this vector is **used as input** to **producing each time step** in the **output sequence**.

# repeat encoding
model.add(RepeatVector(n_steps_out)) # RepeatVector将输入重复2次，即这里改变我们的步长（从1）变为n_steps_out == 2

# This sequence is then provided to an LSTM decoder model. The model must output a value for each value in the output time step, which can be interpreted by a single output model.

# define decoder model
# return_sequences=True since we need to output a value for each value 
# in the output time step
model.add(LSTM(100, activation='relu', return_sequences=True))

# We can use the same output layer or layers to make each one-step prediction in the output sequence. This can be achieved by wrapping the output part of the model in a TimeDistributed wrapper.
#
# TimeDistributed层在每个时间步上均操作了Dense，由上面几个图明显可以看出了增加了模型实现一对多和多对多的能力。如果你使用正常的Dense层，你最后只会得到一个结果。

# define model output
# The output layer predicts one observation per output time step 
# and is wrapped in a TimeDistributed wrapper layer in order to 
# use the same output layer multiple times for the required number of output time steps.
model.add(TimeDistributed(Dense(1)))  # TimeDistributed使每个步长（2）输出一个值

# all together
model = Sequential()
model.add(LSTM(100, activation='relu', input_shape=(n_steps_in, n_features)))
# RepeatVector将输入重复2次，即这里改变我们的步长（从1）变为n_steps_out=2。
# 这里相当于把第一个LSTM的输出（1个）复制成2个，再接入stack的第二个LSTM。
# 第一个LSTM的每个输出相当于是第二个LSTM的每个步长（总共2个步长）
model.add(RepeatVector(n_steps_out)) 
model.add(LSTM(100, activation='relu', return_sequences=True))
# 第二个LSTM输出时，依次用这2个步长产生两个预测值，即达到了multi-step ahead的目的
model.add(TimeDistributed(Dense(1))) # TimeDistributed使每个步长（2）用相同的input，输出一个值，即这里最后输出两个值
model.compile(optimizer='adam', loss='mse')
model.summary()

n_steps_in, n_features

# TimeDistributed和Dense的使用 [https://blog.csdn.net/ChaoFeiLi/article/details/89323078]
#
# 1、TimeDistributed和Dense的使用
#
# 下面代码是keras里面给出的解释：
#
#   \# as the first layer in a model
#   
#         model = Sequential()
#         model.add(TimeDistributed(Dense(8), input_shape=(10, 16)))
#   \# now model.output_shape == (None, 10, 8)
#
# 从上述代码中可以发现，TimeDistributed和Dense一起配合使用，主要应用于一对多，多对多的情况。
# input_shape = (10,16)，表示步长是10，每一步的维度为16，（即：每一个数据的属性长度为16））
#
# 首先使用TimeDistributed（Dense（8），input_shape = (10,16)）把每一步的维度为16变成8，不改变步长的大小
#
# 若该层的批输入形状为(50, 10, 16)，则这一层之后的输出为(50, 10, 8)，即每个sample都用于提供了输出。
#
# 2、RepeatVector的使用
#
# 这个是keras官网给出的解释
#
#         model = Sequential()
#         model.add(Dense(32, input_dim=32))
#         # now: model.output_shape == (None, 32)
#         # note: `None` is the batch dimension
#
#         model.add(RepeatVector(3))
#         # now: model.output_shape == (None, 3, 32)
#
#
# 解释：如果输入的形状为（None,32），经过添加RepeatVector(3)层之后，输出变为（None,3,32）,RepeatVector改变了我们的步长，不改变我们的每一步的维数（即：属性长度）
#

# [samples, timesteps, features]
X = X.reshape((X.shape[0], X.shape[1], n_features))

X.shape

# In the case of the Encoder-Decoder model, the output, or y part, of the training dataset must also have this shape. This is because the model will predict a given number of time steps with a given number of features for each input sample

# reshape output training data
y = y.reshape((y.shape[0], y.shape[1], n_features))

y.shape

y

# fit model
model.fit(X, y, epochs=100, verbose=0)
# demonstrate prediction
x_input = array([70, 80, 90])
x_input = x_input.reshape((1, n_steps_in, n_features))
yhat = model.predict(x_input, verbose=0)
print(yhat)


# # Multivariate Multi-step LSTM

# ## Vector Output Model

# split a multivariate sequence into samples
def split_sequences(sequences, n_steps_in, n_steps_out):
    X, y = list(), list()
    for i in range(len(sequences)):
        # find the end of this pattern
        end_ix = i + n_steps_in
        out_end_ix = end_ix + n_steps_out-1
        # check if we are beyond the dataset
        if out_end_ix > len(sequences):
            break
        # gather input and output parts of the pattern
        seq_x, seq_y = sequences[i:end_ix, :-1], sequences[end_ix-1:out_end_ix, -1]
        X.append(seq_x)
        y.append(seq_y)
    return array(X), array(y)


# Use three prior time steps of each of the two input time series to predict two time
# steps of the output time series.

# define input sequence
in_seq1 = array([10, 20, 30, 40, 50, 60, 70, 80, 90])
in_seq2 = array([15, 25, 35, 45, 55, 65, 75, 85, 95])
out_seq = array([in_seq1[i]+in_seq2[i] for i in range(len(in_seq1))])
# convert to [rows, columns] structure
in_seq1 = in_seq1.reshape((len(in_seq1), 1))
in_seq2 = in_seq2.reshape((len(in_seq2), 1))
out_seq = out_seq.reshape((len(out_seq), 1))
# horizontally stack columns
dataset = hstack((in_seq1, in_seq2, out_seq))
# choose a number of time steps
n_steps_in, n_steps_out = 3, 2
# covert into input/output
X, y = split_sequences(dataset, n_steps_in, n_steps_out)
print(X.shape, y.shape)
# the dataset knows the number of features, e.g. 2
n_features = X.shape[2]
# summarize the data
for i in range(len(X)):
    print(X[i], y[i])

# define model
model = Sequential()
model.add(LSTM(100, activation='relu', return_sequences=True, input_shape=(n_steps_in, n_features)))
model.add(LSTM(100, activation='relu'))
model.add(Dense(n_steps_out)) # output a vector for multi-step ahead
model.compile(optimizer='adam', loss='mse')
model.summary()

# fit model
model.fit(X, y, epochs=200, verbose=0)
# demonstrate prediction
x_input = array([[70, 75], [80, 85], [90, 95]])
x_input = x_input.reshape((1, n_steps_in, n_features))
yhat = model.predict(x_input, verbose=0)
print(yhat)

# ## Encoder-Decoder LSTM (略，跟univariate一样)













StarcoderdataJupyterScriptsDedupFiltered