Time series Forecasting

Time series Forecasting#

[24]:
import seaborn as sns
import numpy as np

data = sns.load_dataset("flights")
month_map = {month: i for i, month in enumerate(data["month"].cat.categories, start=1)}
data["month"] = data["month"].map(month_map)
data.head()
[24]:
year month passengers
0 1949 1 112
1 1949 2 118
2 1949 3 132
3 1949 4 129
4 1949 5 121
[86]:
import matplotlib.pyplot as plt

fig_size = plt.rcParams["figure.figsize"]
fig_size[0] = 15
fig_size[1] = 5
plt.rcParams["figure.figsize"] = fig_size

plt.title('Total passengers over time')
plt.ylabel('Total Passengers')
plt.xlabel('Time')
plt.grid(True)
plt.autoscale(axis='x',tight=True)
plt.plot(data['passengers'])
plt.show()
../_images/Applications_time_series_forecasting_2_0.png
[94]:
from sklearn.preprocessing import MinMaxScaler
import pandas as pd
import torch
from torch.utils.data import Dataset, DataLoader

SEQ_LENGTH = 3  # Size sequence
PREDICT_AHEAD = 1 # Forecast horizon
explanatory_variables = ['month', 'year']
target = "passengers"
scaler = MinMaxScaler()

# train-test split for time series
train_size = int(len(data) * 0.67)
test_size = len(data) - train_size
train, test = data[:train_size], data[train_size:]

train[explanatory_variables+[target]] = scaler.fit_transform(train[explanatory_variables+[target]])
test[explanatory_variables+[target]] = scaler.transform(test[explanatory_variables+[target]])

class TimeSeriesDataset(Dataset):
    def __init__(self, df, seq_length, predict_ahead):
        self.df = df
        self.seq_length = seq_length
        self.predict_ahead = predict_ahead

    def __len__(self):
        return len(self.df) - self.seq_length - self.predict_ahead

    def __getitem__(self, index):
        past_data = self.df.iloc[index : index + self.seq_length][explanatory_variables+[target]].values
        future_y = self.df.iloc[index + self.seq_length + self.predict_ahead][target]

        past_data[-self.predict_ahead:, 0] = 0  # Mask y(t-1 to t)

        return torch.tensor(past_data, dtype=torch.float32), torch.tensor(future_y, dtype=torch.float32)

    def denormalize(self, y):
        df = pd.DataFrame(index=self.df.index)
        df = df.iloc[self.seq_length + self.predict_ahead:]
        df['Pred'] = y*(scaler.data_max_[-1] - scaler.data_min_[0]) + scaler.data_min_[-1]
        return df

train_set = TimeSeriesDataset(train, SEQ_LENGTH, PREDICT_AHEAD)
test_set = TimeSeriesDataset(test, SEQ_LENGTH, PREDICT_AHEAD)

train_loader = DataLoader(train_set, batch_size=32, shuffle=False)
test_loader = DataLoader(test_set, batch_size=1, shuffle=False)


print(f"X: {train_set.__getitem__(0)[0].shape}, y: {test_set.__getitem__(0)[1]}")
X: torch.Size([3, 3]), y: 0.8122977614402771
/tmp/ipykernel_29773/950504395.py:17: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  train[explanatory_variables+[target]] = scaler.fit_transform(train[explanatory_variables+[target]])
/tmp/ipykernel_29773/950504395.py:18: SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html#returning-a-view-versus-a-copy
  test[explanatory_variables+[target]] = scaler.transform(test[explanatory_variables+[target]])
[95]:
import torch.nn as nn
import os

class TimeSeriesModel(nn.Module):
    def __init__(self, args, ts_shape):
        super().__init__()
        self.args = args
        self.input_shape = ts_shape

        # 1-dimensional DAG
        self.cell_1d = args['1D Dag']
        self.cell_1d.set(self.input_shape)

        self.flat_shape = (1, np.prod(self.cell_1d.output_shape))
        # Output layer
        self.output = args["Out"]
        args['Out'].set(self.flat_shape)

    def forward(self, X, h=None):
        out_1d = self.cell_1d(X)
        if isinstance(out_1d, tuple):
            out_1d, h = out_1d
        else:
            h = None
        flat = nn.Flatten(start_dim=1)(out_1d).unsqueeze(1)
        out = self.output(flat)
        if h is not None:
            return out.squeeze(-1).squeeze(-1), h
        else: return out.squeeze(-1).squeeze(-1)

    def set_prediction_to_save(self, name, df):
        self.prediction = {name: df}

    def save(self, path):
        if not os.path.exists(path):
            os.makedirs(path)
        full_path = os.path.join(path, "best_model.pth")
        torch.save(self.state_dict(), full_path)
        if hasattr(self, "prediction"):
            for k in self.prediction.keys():
                self.prediction[k].to_csv(os.path.join(path, f"best_model_{k}_outputs.csv"))
[96]:
from dragon.search_operators.base_neighborhoods import ArrayInterval, FloatInterval
from dragon.search_space.base_variables import ArrayVar, FloatVar
from dragon.search_space.bricks_variables import attention_1d, dag_var, identity_var, mlp_const_var, node_var, operations_var, recurrence_1d
from dragon.search_space.bricks_variables import mlp_var, conv_1d, pooling_1d, norm_1d, dropout

candidate_operations_1d = operations_var("2D Candidate operations", size=5,
                                            candidates=[identity_var("Unitary"), attention_1d("Attention"), mlp_var("MLP"), conv_1d("conv 1d", max_out=3, permute=False),
                                                        recurrence_1d("rnn_1d"), pooling_1d('Pooling'), norm_1d("Norm"), dropout('Dropout')])
dag_1d = dag_var("1D Dag", candidate_operations_1d)
out = node_var("Out", operation=mlp_const_var('Operation', 1), activation_function=nn.Identity())
lr = FloatVar("LR", lower=0.001, upper=0.1, neighbor=FloatInterval(0.01))

search_space = ArrayVar(dag_1d, out, lr, label="Search Space", neighbor=ArrayInterval())
labels = [e.label for e in search_space]
[97]:
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
def MSE(actual, pred):
    return np.mean((actual - pred) ** 2)


def MAPE(actual, pred):
    return np.mean(np.abs((actual - pred) / actual))


def RMSE(actual, pred):
    return np.sqrt(MSE(actual, pred))

def train_model(model, data_loader, lr, verbose=False):
    loss_fn = nn.MSELoss()
    optimizer = torch.optim.AdamW(model.parameters(), lr=lr)
    model.train()
    for ep in range(20):
        h = None
        ep_loss = 0
        for X,y in data_loader:
            X = X.to(device)
            y = y.to(device)
            optimizer.zero_grad()
            X, y = X.float(), y.float()
            pred = model(X, h)
            if isinstance(pred, tuple):
                pred, h = pred
                h = [hh.detach() for hh in h if hasattr(hh, "grad")]
            loss = loss_fn(pred,y)
            loss.backward()
            optimizer.step()
            ep_loss += loss
        if verbose:
            print(f"Train | Epoch: {ep}, loss = {ep_loss / len(data_loader)}")
    return model, h

def test_model(model, data_loader, h):
    loss_fn = nn.MSELoss()
    model.eval()
    test_loss = 0
    preds = []
    trues = []
    with torch.no_grad():
      for X, y in data_loader:
          X = X.to(device)
          y = y.to(device)
          X, y = X.float(), y.float()
          pred = model(X, h)
          if isinstance(pred, tuple):
              pred, h = pred
              h = [hh.detach() for hh in h if hasattr(hh, "grad")]
          loss = loss_fn(pred, y).item()
          test_loss += loss
          preds.append(pred.detach().numpy())
          trues.append(y.detach().numpy())
    loss = test_loss / len(data_loader)
    return loss, preds, trues


def loss_function(args, idx, verbose=False):
    args = dict(zip(labels, args))
    lr = args['LR']
    model = TimeSeriesModel(args, train_set.__getitem__(0)[0].shape).to(device)
    model, h = train_model(model, train_loader, verbose=verbose, lr=lr)
    loss, preds, trues = test_model(model, test_loader, h)
    preds = np.concatenate((np.asarray(preds[:-1]).reshape(-1,1), np.asarray(preds[-1]).reshape(-1,1)))
    trues = np.concatenate((np.asarray(trues[:-1]).reshape(-1,1), np.asarray(trues[-1]).reshape(-1,1)))
    preds = test_set.denormalize(preds)
    trues = test_set.denormalize(trues)
    mape = MAPE(trues, preds)
    rmse = RMSE(trues, preds)
    preds['Actual']=trues
    model.set_prediction_to_save("forecasts", preds)
    print(f"Idx: {idx}, on validation set: MAPE = {mape}, RMSE = {rmse}")
    return loss, model
[99]:
from dragon.search_algorithm.mutant_ucb import Mutant_UCB

search_algorithm = Mutant_UCB(search_space, save_dir="save/test_ts", T=100, N=5, K=20, E=0.01, evaluation=loss_function)
search_algorithm.run()
2025-02-07 13:47:37,631 | WARNING | Install mpi4py if you want to use the distributed version.
2025-02-07 13:47:37,633 | INFO | save/test_ts already exists. Deleting it.
2025-02-07 13:47:37,650 | INFO | The whole population has been created (size = 20), 20 have been randomy initialized.
Idx: 0, on validation set: MAPE = 0.25278031826019287, RMSE = 171.59567260742188
2025-02-07 13:47:38,707 | INFO | Best found! 0.17346756059619525 < inf
Idx: 1, on validation set: MAPE = 0.14085960388183594, RMSE = 87.64507293701172
2025-02-07 13:47:40,472 | INFO | Best found! 0.0452543810118765 < 0.17346756059619525
Idx: 2, on validation set: MAPE = 0.8092232346534729, RMSE = 441.6387939453125
Idx: 3, on validation set: MAPE = 0.7823165655136108, RMSE = 417.098876953125
Idx: 4, on validation set: MAPE = 0.39875057339668274, RMSE = 204.48941040039062
Idx: 5, on validation set: MAPE = 0.14847682416439056, RMSE = 115.73798370361328
Idx: 6, on validation set: MAPE = 0.13891682028770447, RMSE = 101.47113800048828
Idx: 7, on validation set: MAPE = 0.4745907485485077, RMSE = 268.2114562988281
Idx: 8, on validation set: MAPE = 12.157652854919434, RMSE = 6167.1279296875
Idx: 9, on validation set: MAPE = 0.403279572725296, RMSE = 207.37094116210938
Idx: 10, on validation set: MAPE = 0.4889073371887207, RMSE = 285.5888671875
Idx: 11, on validation set: MAPE = 0.69692462682724, RMSE = 412.52056884765625
Idx: 12, on validation set: MAPE = 0.17014995217323303, RMSE = 134.8133544921875
Idx: 13, on validation set: MAPE = 0.1305270791053772, RMSE = 88.1025619506836
Idx: 14, on validation set: MAPE = 0.13090716302394867, RMSE = 91.27886962890625
Idx: 15, on validation set: MAPE = 0.1183539405465126, RMSE = 94.23975372314453
Idx: 16, on validation set: MAPE = 0.13657067716121674, RMSE = 110.94203186035156
Idx: 17, on validation set: MAPE = 0.23222047090530396, RMSE = 162.815185546875
Idx: 18, on validation set: MAPE = 0.2873539328575134, RMSE = 190.031982421875
Idx: 19, on validation set: MAPE = 0.12392502278089523, RMSE = 76.68273162841797
2025-02-07 13:48:49,588 | INFO | Best found! 0.034641819290713596 < 0.0452543810118765
2025-02-07 13:48:49,593 | INFO | All models have been at least evaluated once, t = 20 < 100.
2025-02-07 13:48:49,593 | INFO | After initialisation, it remains 80 iterations.
2025-02-07 13:48:49,594 | INFO | With p = 0.2 = 1 / 5, training 19 instead
Idx: 19, on validation set: MAPE = 0.11574778705835342, RMSE = 92.8625717163086
2025-02-07 13:48:51,185 | INFO | With p = 0.2 = 1 / 5, training 1 instead
Idx: 1, on validation set: MAPE = 0.5122929215431213, RMSE = 296.73211669921875
2025-02-07 13:48:52,937 | INFO | With p = 0.2 = 1 / 5, training 13 instead
Idx: 13, on validation set: MAPE = 0.10445880889892578, RMSE = 80.71048736572266
2025-02-07 13:48:54,506 | INFO | With p = 0.2 = 1 / 5, training 14 instead
Idx: 14, on validation set: MAPE = 0.11222360283136368, RMSE = 82.90767669677734
2025-02-07 13:48:55,744 | INFO | With p = 0.2 = 1 / 5, training 15 instead
Idx: 15, on validation set: MAPE = 0.11740612983703613, RMSE = 91.13170623779297
2025-02-07 13:48:57,122 | INFO | With p = 0.2 = 1 / 5, training 6 instead
Idx: 6, on validation set: MAPE = 0.11892752349376678, RMSE = 87.65919494628906
2025-02-07 13:48:58,602 | INFO | With p = 0.4 = 2 / 5, training 13 instead
Idx: 13, on validation set: MAPE = 0.10612066090106964, RMSE = 88.17684173583984
2025-02-07 13:49:00,117 | INFO | With p = 0.4 = 2 / 5, training 19 instead
Idx: 19, on validation set: MAPE = 0.6006303429603577, RMSE = 330.9823913574219
2025-02-07 13:49:01,659 | INFO | With p = 0.2 = 1 / 5, training 16 instead
Idx: 16, on validation set: MAPE = 0.10128592699766159, RMSE = 81.72245025634766
2025-02-07 13:49:02,965 | INFO | With p = 0.4 = 2 / 5, training 14 instead
Idx: 14, on validation set: MAPE = 0.09792458266019821, RMSE = 74.09211730957031
2025-02-07 13:49:04,231 | INFO | Best found! 0.03234071052962794 < 0.034641819290713596
2025-02-07 13:49:04,234 | INFO | With p = 0.2 = 1 / 5, training 5 instead
Idx: 5, on validation set: MAPE = 0.18034058809280396, RMSE = 133.2898712158203
2025-02-07 13:49:05,355 | INFO | With p = 0.4 = 2 / 5, mutating 15 to 20
Idx: 20, on validation set: MAPE = 0.11646398901939392, RMSE = 100.49867248535156
2025-02-07 13:49:07,077 | INFO | With p = 0.2 = 1 / 5, mutating 20 to 21
Idx: 21, on validation set: MAPE = 0.12002182751893997, RMSE = 96.51895141601562
2025-02-07 13:49:08,797 | INFO | With p = 0.2 = 1 / 5, training 21 instead
Idx: 21, on validation set: MAPE = 0.10674992203712463, RMSE = 77.52178955078125
2025-02-07 13:49:10,579 | INFO | With p = 0.4 = 2 / 5, training 21 instead
Idx: 21, on validation set: MAPE = 0.10475777834653854, RMSE = 72.94390869140625
2025-02-07 13:49:12,218 | INFO | Best found! 0.03134610478435785 < 0.03234071052962794
2025-02-07 13:49:12,221 | INFO | With p = 0.4 = 2 / 5, mutating 6 to 22
Idx: 22, on validation set: MAPE = 0.10353737324476242, RMSE = 77.01615905761719
2025-02-07 13:49:13,723 | INFO | With p = 0.2 = 1 / 5, training 22 instead
Idx: 22, on validation set: MAPE = 0.09536831825971603, RMSE = 69.59992980957031
2025-02-07 13:49:15,345 | INFO | Best found! 0.02853797586882675 < 0.03134610478435785
2025-02-07 13:49:15,349 | INFO | With p = 0.4 = 2 / 5, mutating 22 to 23
Idx: 23, on validation set: MAPE = 0.13698846101760864, RMSE = 112.22069549560547
2025-02-07 13:49:16,752 | INFO | With p = 0.4 = 2 / 5, training 22 instead
Idx: 22, on validation set: MAPE = 0.09047950059175491, RMSE = 64.21504974365234
2025-02-07 13:49:18,378 | INFO | Best found! 0.024292889982763022 < 0.02853797586882675
2025-02-07 13:49:18,388 | INFO | With p = 0.2 = 1 / 5, training 23 instead
Idx: 23, on validation set: MAPE = 0.1122182086110115, RMSE = 88.15772247314453
2025-02-07 13:49:19,954 | INFO | With p = 0.6 = 3 / 5, training 22 instead
Idx: 22, on validation set: MAPE = 0.08819364756345749, RMSE = 61.659751892089844
2025-02-07 13:49:21,450 | INFO | Best found! 0.022397991680422405 < 0.024292889982763022
2025-02-07 13:49:21,455 | INFO | With p = 0.6 = 3 / 5, mutating 21 to 24
Idx: 24, on validation set: MAPE = 0.1258588433265686, RMSE = 73.9375
2025-02-07 13:49:23,439 | INFO | With p = 0.2 = 1 / 5, training 24 instead
Idx: 24, on validation set: MAPE = 0.09452932327985764, RMSE = 69.98967742919922
2025-02-07 13:49:25,437 | INFO | With p = 0.4 = 2 / 5, mutating 24 to 25
Idx: 25, on validation set: MAPE = 0.10315032303333282, RMSE = 67.85924530029297
2025-02-07 13:49:27,936 | INFO | With p = 0.2 = 1 / 5, training 25 instead
Idx: 25, on validation set: MAPE = 0.11185655742883682, RMSE = 71.13701629638672
2025-02-07 13:49:29,767 | INFO | With p = 0.4 = 2 / 5, mutating 25 to 26
Idx: 26, on validation set: MAPE = 0.11666081100702286, RMSE = 92.63421630859375
2025-02-07 13:49:31,265 | INFO | With p = 0.2 = 1 / 5, training 26 instead
Idx: 26, on validation set: MAPE = 0.11963345855474472, RMSE = 88.41085815429688
2025-02-07 13:49:32,525 | INFO | With p = 0.4 = 2 / 5, training 25 instead
Idx: 25, on validation set: MAPE = 0.11579463630914688, RMSE = 71.45938873291016
2025-02-07 13:49:34,132 | INFO | With p = 0.4 = 2 / 5, mutating 24 to 27
Idx: 27, on validation set: MAPE = 0.16406217217445374, RMSE = 126.80860137939453
2025-02-07 13:49:35,819 | INFO | With p = 0.4 = 2 / 5, mutating 26 to 28
Idx: 28, on validation set: MAPE = 0.11559046059846878, RMSE = 96.18035888671875
2025-02-07 13:49:37,178 | INFO | With p = 0.2 = 1 / 5, mutating 28 to 29
Idx: 29, on validation set: MAPE = 0.11902876198291779, RMSE = 88.86155700683594
2025-02-07 13:49:38,583 | INFO | With p = 0.2 = 1 / 5, training 29 instead
Idx: 29, on validation set: MAPE = 0.11736097931861877, RMSE = 91.23209381103516
2025-02-07 13:49:39,864 | INFO | With p = 0.4 = 2 / 5, training 29 instead
Idx: 29, on validation set: MAPE = 0.1194150373339653, RMSE = 88.5447998046875
2025-02-07 13:49:41,102 | INFO | With p = 0.6 = 3 / 5, training 25 instead
Idx: 25, on validation set: MAPE = 0.10577210783958435, RMSE = 68.99132537841797
2025-02-07 13:49:42,755 | INFO | With p = 0.4 = 2 / 5, mutating 24 to 30
Idx: 30, on validation set: MAPE = 0.10191940516233444, RMSE = 67.65409088134766
2025-02-07 13:49:44,437 | INFO | With p = 0.2 = 1 / 5, training 30 instead
Idx: 30, on validation set: MAPE = 0.11618217825889587, RMSE = 72.78789520263672
2025-02-07 13:49:46,247 | INFO | With p = 0.4 = 2 / 5, training 30 instead
Idx: 30, on validation set: MAPE = 0.11508996784687042, RMSE = 71.25272369384766
2025-02-07 13:49:47,840 | INFO | With p = 0.6 = 3 / 5, mutating 30 to 31
Idx: 31, on validation set: MAPE = 0.09083370119333267, RMSE = 69.9476318359375
2025-02-07 13:49:49,415 | INFO | With p = 0.2 = 1 / 5, training 31 instead
Idx: 31, on validation set: MAPE = 0.09752893447875977, RMSE = 67.94530487060547
2025-02-07 13:49:51,119 | INFO | With p = 0.4 = 2 / 5, training 31 instead
Idx: 31, on validation set: MAPE = 0.09218338131904602, RMSE = 72.2193832397461
2025-02-07 13:49:52,750 | INFO | With p = 0.6 = 3 / 5, training 31 instead
Idx: 31, on validation set: MAPE = 0.09772363305091858, RMSE = 67.41448211669922
2025-02-07 13:49:54,676 | INFO | With p = 0.8 = 4 / 5, training 31 instead
Idx: 31, on validation set: MAPE = 0.10580570250749588, RMSE = 67.8490219116211
2025-02-07 13:49:56,436 | INFO | With p = 0.6 = 3 / 5, training 30 instead
Idx: 30, on validation set: MAPE = 0.09115266799926758, RMSE = 70.34504699707031
2025-02-07 13:49:58,129 | INFO | With p = 0.8 = 4 / 5, mutating 22 to 32
Idx: 32, on validation set: MAPE = 0.08627993613481522, RMSE = 60.239261627197266
2025-02-07 13:49:59,541 | INFO | Best found! 0.021377891398680567 < 0.022397991680422405
2025-02-07 13:49:59,545 | INFO | With p = 0.2 = 1 / 5, training 32 instead
Idx: 32, on validation set: MAPE = 0.08562853932380676, RMSE = 59.051856994628906
2025-02-07 13:50:01,030 | INFO | Best found! 0.020543413724629807 < 0.021377891398680567
2025-02-07 13:50:01,033 | INFO | With p = 0.4 = 2 / 5, training 32 instead
Idx: 32, on validation set: MAPE = 0.08622968941926956, RMSE = 58.215091705322266
2025-02-07 13:50:02,422 | INFO | Best found! 0.019965347896541887 < 0.020543413724629807
2025-02-07 13:50:02,425 | INFO | With p = 0.6 = 3 / 5, training 32 instead
Idx: 32, on validation set: MAPE = 0.08825863152742386, RMSE = 57.72849655151367
2025-02-07 13:50:03,833 | INFO | Best found! 0.019632975156293305 < 0.019965347896541887
2025-02-07 13:50:03,838 | INFO | With p = 0.8 = 4 / 5, mutating 32 to 33
Idx: 33, on validation set: MAPE = 0.16718131303787231, RMSE = 131.91839599609375
2025-02-07 13:50:05,091 | INFO | With p = 0.8 = 4 / 5, training 32 instead
Idx: 32, on validation set: MAPE = 0.0928325355052948, RMSE = 58.10025405883789
2025-02-07 13:50:06,630 | INFO | With p = 1.0 = 5 / 5, mutating 32 to 34
Idx: 34, on validation set: MAPE = 0.08768563717603683, RMSE = 67.07479095458984
2025-02-07 13:50:08,282 | INFO | With p = 0.2 = 1 / 5, training 34 instead
Idx: 34, on validation set: MAPE = 0.10171080380678177, RMSE = 79.79564666748047
2025-02-07 13:50:09,730 | INFO | With p = 0.4 = 2 / 5, training 34 instead
Idx: 34, on validation set: MAPE = 0.09472493827342987, RMSE = 67.55670166015625
2025-02-07 13:50:11,246 | INFO | With p = 0.6 = 3 / 5, mutating 34 to 35
Idx: 35, on validation set: MAPE = 0.09291192889213562, RMSE = 66.5353012084961
2025-02-07 13:50:12,733 | INFO | With p = 0.2 = 1 / 5, training 35 instead
Idx: 35, on validation set: MAPE = 0.09348049014806747, RMSE = 68.2832260131836
2025-02-07 13:50:14,221 | INFO | With p = 0.4 = 2 / 5, training 35 instead
Idx: 35, on validation set: MAPE = 0.07845062762498856, RMSE = 56.833675384521484
2025-02-07 13:50:15,631 | INFO | Best found! 0.019029044557899253 < 0.019632975156293305
2025-02-07 13:50:15,635 | INFO | With p = 0.6 = 3 / 5, training 35 instead
Idx: 35, on validation set: MAPE = 0.08435732126235962, RMSE = 58.76644515991211
2025-02-07 13:50:17,052 | INFO | With p = 0.8 = 4 / 5, mutating 35 to 36
Idx: 36, on validation set: MAPE = 0.07325568795204163, RMSE = 50.333255767822266
2025-02-07 13:50:18,583 | INFO | Best found! 0.01492504175440052 < 0.019029044557899253
2025-02-07 13:50:18,587 | INFO | With p = 0.2 = 1 / 5, training 36 instead
Idx: 36, on validation set: MAPE = 0.07392118126153946, RMSE = 52.059139251708984
2025-02-07 13:50:20,137 | INFO | With p = 0.4 = 2 / 5, mutating 36 to 37
Idx: 37, on validation set: MAPE = 0.06664402782917023, RMSE = 47.97541427612305
2025-02-07 13:50:21,570 | INFO | Best found! 0.013559476533972966 < 0.01492504175440052
2025-02-07 13:50:21,574 | INFO | With p = 0.2 = 1 / 5, training 37 instead
Idx: 37, on validation set: MAPE = 0.05864858627319336, RMSE = 42.18466567993164
2025-02-07 13:50:23,083 | INFO | Best found! 0.010483702681982137 < 0.013559476533972966
2025-02-07 13:50:23,088 | INFO | With p = 0.4 = 2 / 5, training 37 instead
Idx: 37, on validation set: MAPE = 0.05765188857913017, RMSE = 41.282501220703125
2025-02-07 13:50:24,530 | INFO | Best found! 0.010040088404418218 < 0.010483702681982137
2025-02-07 13:50:24,534 | INFO | With p = 0.6 = 3 / 5, training 37 instead
Idx: 37, on validation set: MAPE = 0.05003468692302704, RMSE = 34.00397491455078
2025-02-07 13:50:26,005 | INFO | Best found! 0.006811846918543035 < 0.010040088404418218
2025-02-07 13:50:26,009 | INFO | With p = 0.4 = 2 / 5, mutating 36 to 38
Idx: 38, on validation set: MAPE = 0.08223886787891388, RMSE = 57.334014892578125
2025-02-07 13:50:27,696 | INFO | With p = 0.2 = 1 / 5, mutating 38 to 39
Idx: 39, on validation set: MAPE = 0.06400180608034134, RMSE = 47.055946350097656
2025-02-07 13:50:29,332 | INFO | With p = 0.2 = 1 / 5, training 39 instead
Idx: 39, on validation set: MAPE = 0.06279464066028595, RMSE = 44.33384704589844
2025-02-07 13:50:30,912 | INFO | With p = 0.4 = 2 / 5, training 39 instead
Idx: 39, on validation set: MAPE = 0.05884108692407608, RMSE = 42.20945358276367
2025-02-07 13:50:32,415 | INFO | With p = 0.2 = 1 / 5, training 38 instead
Idx: 38, on validation set: MAPE = 0.06877875328063965, RMSE = 49.80124282836914
2025-02-07 13:50:33,796 | INFO | With p = 0.6 = 3 / 5, training 39 instead
Idx: 39, on validation set: MAPE = 0.05325986072421074, RMSE = 36.90644073486328
2025-02-07 13:50:35,222 | INFO | With p = 0.4 = 2 / 5, mutating 38 to 40
Idx: 40, on validation set: MAPE = 0.064189113676548, RMSE = 45.805625915527344
2025-02-07 13:50:36,889 | INFO | With p = 0.2 = 1 / 5, training 40 instead
Idx: 40, on validation set: MAPE = 0.05684179067611694, RMSE = 38.86223220825195
2025-02-07 13:50:38,314 | INFO | With p = 0.4 = 2 / 5, training 40 instead
Idx: 40, on validation set: MAPE = 0.05338210240006447, RMSE = 37.53934097290039
2025-02-07 13:50:39,804 | INFO | With p = 0.6 = 3 / 5, training 40 instead
Idx: 40, on validation set: MAPE = 0.05127706751227379, RMSE = 35.88534927368164
2025-02-07 13:50:41,374 | INFO | With p = 0.8 = 4 / 5, training 40 instead
Idx: 40, on validation set: MAPE = 0.054205749183893204, RMSE = 35.92194747924805
2025-02-07 13:50:42,960 | INFO | With p = 0.8 = 4 / 5, mutating 37 to 41
Idx: 41, on validation set: MAPE = 0.050630927085876465, RMSE = 32.9295539855957
2025-02-07 13:50:44,570 | INFO | Best found! 0.006388180294550239 < 0.006811846918543035
2025-02-07 13:50:44,576 | INFO | With p = 0.2 = 1 / 5, training 41 instead
Idx: 41, on validation set: MAPE = 0.05351459980010986, RMSE = 33.1446418762207
2025-02-07 13:50:46,227 | INFO | With p = 0.4 = 2 / 5, mutating 41 to 42
Idx: 42, on validation set: MAPE = 0.05488821491599083, RMSE = 34.865421295166016
2025-02-07 13:50:47,713 | INFO | With p = 0.2 = 1 / 5, mutating 42 to 43
Idx: 43, on validation set: MAPE = 0.054597821086645126, RMSE = 35.39425277709961
2025-02-07 13:50:49,370 | INFO | With p = 0.2 = 1 / 5, training 43 instead
Idx: 43, on validation set: MAPE = 0.05455347150564194, RMSE = 36.06391143798828
2025-02-07 13:50:50,841 | INFO | With p = 0.2 = 1 / 5, training 42 instead
Idx: 42, on validation set: MAPE = 0.05818048492074013, RMSE = 36.88071823120117
2025-02-07 13:50:52,545 | INFO | With p = 0.4 = 2 / 5, training 43 instead
Idx: 43, on validation set: MAPE = 0.05734092369675636, RMSE = 38.490379333496094
2025-02-07 13:50:54,123 | INFO | Search algorithm is done. Min Loss = 0.006388180294550239
[100]:
import graphviz
from dragon.utils.plot_functions import draw_cell, load_archi, str_operations

def draw_graph(n_dag, m_dag, output_file, act="Identity()", name="Input"):
    G = graphviz.Digraph(output_file, format='pdf',
                            node_attr={'nodesep': '0.02', 'shape': 'box', 'rankstep': '0.02', 'fontsize': '20', "fontname": "sans-serif"})

    G, g_nodes = draw_cell(G, n_dag, m_dag, "#ffa600", [], name_input=name,
                            color_input="#ef5675")
    G.node(','.join(["MLP", "1", act]), style="rounded,filled", color="black", fillcolor="#ef5675", fontcolor="#ECECEC")
    G.edge(g_nodes[-1], ','.join(["MLP", "1", act]))
    return G

best_model = load_archi("save/test_ts/best_model/x.pkl")
labels = [e.label for e in search_space]
best_model = dict(zip(labels, best_model))
m_dag = best_model['1D Dag'].matrix
n_dag = str_operations(best_model["1D Dag"].operations)

graph = draw_graph(n_dag, m_dag, "save/test_ts/best_archi")
print(f'Model giving a loss of ', search_algorithm.min_loss)
graph
Model giving a loss of  0.006388180294550239
/home/b98181/Documents/CIFRE/Code/EvoDagsAutoDL/lib/dragon/utils/plot_functions.py:9: FutureWarning: You are using `torch.load` with `weights_only=False` (the current default value), which uses the default pickle module implicitly. It is possible to construct malicious pickle data which will execute arbitrary code during unpickling (See https://github.com/pytorch/pytorch/blob/main/SECURITY.md#untrusted-models for more details). In a future release, the default value for `weights_only` will be flipped to `True`. This limits the functions that could be executed during unpickling. Arbitrary objects will no longer be allowed to be loaded via this mode unless they are explicitly allowlisted by the user via `torch.serialization.add_safe_globals`. We recommend you start setting `weights_only=True` for any use case where you don't have full control of the loaded file. Please open an issue on GitHub for any issues related to this experimental feature.
  return lambda b: torch.load(io.BytesIO(b), map_location='cpu')
[100]:
../_images/Applications_time_series_forecasting_8_2.svg
[102]:
forecast = pd.read_csv("save/test_ts/best_model/best_model_forecasts_outputs.csv")
forecast[['Actual', 'Pred']].plot()
plt.legend()
plt.show()
../_images/Applications_time_series_forecasting_9_0.png