I. Preface
In a previous post PyTorch Build LSTM for Time Series Prediction (Load Prediction), we used LSTM to implement load prediction, but we simply used the load to predict the load, and we did not take advantage of some other environmental variables, such as temperature, humidity, and so on.
This post considers the implementation of multivariate time series forecasting by building LSTM with PyTorch.
Series of articles:
PyTorch builds LSTM for multivariate multistep time-series load prediction
PyTorch deep learning LSTM from input to Linear output
PyTorch builds LSTM for time series load forecasting
PyTorch builds bi-directional LSTM for time series load forecasting
II. Data processing
The dataset is the electrical load data for a certain area for a certain period of time, which includes information such as temperature and humidity in addition to the load.
In this paper, we predict the load at the next moment based on the load at the previous 24 moments and the environmental variables at that moment.
def load_data(file_name): global MAX, MIN df = pd.read_csv((()) + '/data/new_data/' + file_name, encoding='gbk') columns = ((), inplace=True) MAX = (df[columns[1]]) MIN = (df[columns[1]]) df[columns[1]] = (df[columns[1]] - MIN) / (MAX - MIN) return df class MyDataset(Dataset): def __init__(self, data): = data def __getitem__(self, item): return [item] def __len__(self): return len() def nn_seq(file_name, B): print('Processing data:') data = load_data(file_name) load = data[[1]] load = () data = () seq = [] for i in range(len(data) - 24): train_seq = [] train_label = [] for j in range(i, i + 24): x = [load[j]] for c in range(2, 8): (data[j][c]) train_seq.append(x) train_label.append(load[i + 24]) train_seq = (train_seq) train_label = (train_label).view(-1) ((train_seq, train_label)) # print(seq[:5]) Dtr = seq[0:int(len(seq) * 0.7)] Dte = seq[int(len(seq) * 0.7):len(seq)] train_len = int(len(Dtr) / B) * B test_len = int(len(Dte) / B) * B Dtr, Dte = Dtr[:train_len], Dte[:test_len] train = MyDataset(Dtr) test = MyDataset(Dte) Dtr = DataLoader(dataset=train, batch_size=B, shuffle=False, num_workers=0) Dte = DataLoader(dataset=test, batch_size=B, shuffle=False, num_workers=0) return Dtr, Dte
The above code used DataLoader to process the raw data and finally got the datasets Dtr and Dte with batch_size=B, Dtr is the training set and Dte is the test set.
Arbitrarily outputs a piece of data from the Dte:
[(tensor([[0.3513, 0.0000, 0.9091, 0.0000, 0.6667, 0.3023, 0.2439], [0.3333, 0.0000, 0.9091, 0.0435, 0.6667, 0.3023, 0.2439], [0.3396, 0.0000, 0.9091, 0.0870, 0.6667, 0.3023, 0.2439], [0.3427, 0.0000, 0.9091, 0.1304, 0.6667, 0.3023, 0.2439], [0.3838, 0.0000, 0.9091, 0.1739, 0.6667, 0.3023, 0.2439], [0.3700, 0.0000, 0.9091, 0.2174, 0.6667, 0.3023, 0.2439], [0.4288, 0.0000, 0.9091, 0.2609, 0.6667, 0.3023, 0.2439], [0.4474, 0.0000, 0.9091, 0.3043, 0.6667, 0.3023, 0.2439], [0.4406, 0.0000, 0.9091, 0.3478, 0.6667, 0.3023, 0.2439], [0.4657, 0.0000, 0.9091, 0.3913, 0.6667, 0.3023, 0.2439], [0.4540, 0.0000, 0.9091, 0.4348, 0.6667, 0.3023, 0.2439], [0.4939, 0.0000, 0.9091, 0.4783, 0.6667, 0.3023, 0.2439], [0.4328, 0.0000, 0.9091, 0.5217, 0.6667, 0.3023, 0.2439], [0.4238, 0.0000, 0.9091, 0.5652, 0.6667, 0.3023, 0.2439], [0.4779, 0.0000, 0.9091, 0.6087, 0.6667, 0.3023, 0.2439], [0.4591, 0.0000, 0.9091, 0.6522, 0.6667, 0.3023, 0.2439], [0.4651, 0.0000, 0.9091, 0.6957, 0.6667, 0.3023, 0.2439], [0.5102, 0.0000, 0.9091, 0.7391, 0.6667, 0.3023, 0.2439], [0.5067, 0.0000, 0.9091, 0.7826, 0.6667, 0.3023, 0.2439], [0.4635, 0.0000, 0.9091, 0.8261, 0.6667, 0.3023, 0.2439], [0.4224, 0.0000, 0.9091, 0.8696, 0.6667, 0.3023, 0.2439], [0.3796, 0.0000, 0.9091, 0.9130, 0.6667, 0.3023, 0.2439], [0.3292, 0.0000, 0.9091, 0.9565, 0.6667, 0.3023, 0.2439], [0.2940, 0.0000, 0.9091, 1.0000, 0.6667, 0.3023, 0.2439]]), tensor([0.3675]))]
Each row corresponds to a moment point load as well as an environment variable, at which point input_size=7.
III. LSTM model
A deeper understanding of the model in the input and output (from input to Linear output) of LSTM in PyTorch is used here:
class LSTM(): def __init__(self, input_size, hidden_size, num_layers, output_size, batch_size): super().__init__() self.input_size = input_size self.hidden_size = hidden_size self.num_layers = num_layers self.output_size = output_size self.num_directions = 1 self.batch_size = batch_size = (self.input_size, self.hidden_size, self.num_layers, batch_first=True) = (self.hidden_size, self.output_size) def forward(self, input_seq): h_0 = (self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device) c_0 = (self.num_directions * self.num_layers, self.batch_size, self.hidden_size).to(device) # print(input_seq.size()) seq_len = input_seq.shape[1] # input(batch_size, seq_len, input_size) input_seq = input_seq.view(self.batch_size, seq_len, self.input_size) # output(batch_size, seq_len, num_directions * hidden_size) output, _ = (input_seq, (h_0, c_0)) # print('=', ()) # print(self.batch_size * seq_len, self.hidden_size) output = ().view(self.batch_size * seq_len, self.hidden_size) # (5 * 30, 64) pred = (output) # pred() # print('pred=', ) pred = (self.batch_size, seq_len, -1) pred = pred[:, -1, :] return pred
IV. Training
def LSTM_train(name, b): Dtr, Dte = nn_seq(file_name=name, B=b) input_size, hidden_size, num_layers, output_size = 7, 64, 1, 1 model = LSTM(input_size, hidden_size, num_layers, output_size, batch_size=b).to(device) loss_function = ().to(device) optimizer = ((), lr=0.05) # Training epochs = 30 for i in range(epochs): cnt = 0 print('Current', i) for (seq, label) in Dtr: cnt += 1 seq = (device) label = (device) y_pred = model(seq) loss = loss_function(y_pred, label) optimizer.zero_grad() () () if cnt % 100 == 0: print('epoch', i, ':', cnt - 100, '~', cnt, ()) state = {'model': model.state_dict(), 'optimizer': optimizer.state_dict()} (state, LSTM_PATH)
V. Testing
def test(name, b): global MAX, MIN Dtr, Dte = nn_seq(file_name=name, B=b) pred = [] y = [] print('loading model...') input_size, hidden_size, num_layers, output_size = 7, 64, 1, 1 model = LSTM(input_size, hidden_size, num_layers, output_size, batch_size=b).to(device) model.load_state_dict((LSTM_PATH)['model']) () print('predicting...') for (seq, target) in Dte: target = list(chain.from_iterable(())) (target) seq = (device) with torch.no_grad(): y_pred = model(seq) y_pred = list(chain.from_iterable(y_pred.())) (y_pred) y, pred = ([y]), ([pred]) y = (MAX - MIN) * y + MIN pred = (MAX - MIN) * pred + MIN print('accuracy:', get_mape(y, pred)) # plot x = [i for i in range(1, 151)] x_smooth = ((x), (x), 900) y_smooth = make_interp_spline(x, [150:300])(x_smooth) (x_smooth, y_smooth, c='green', marker='*', ms=1, alpha=0.75, label='true') y_smooth = make_interp_spline(x, [150:300])(x_smooth) (x_smooth, y_smooth, c='red', marker='o', ms=1, alpha=0.75, label='pred') (axis='y') () ()
I just trained 30 rounds with a MAPE of 7.83%:
VI. Source code and data
The source code and data I put on GitHub.LSTM-Load-Forecasting
Above is the details of PyTorch build LSTM to realize multivariate temporal load prediction, more information about PyTorch LSTM multivariate temporal load prediction, please pay attention to my other related articles!