timeseriesAI / tsai

Time series Timeseries Deep Learning Machine Learning Python Pytorch fastai | State-of-the-art Deep Learning library for Time Series and Sequences in Pytorch / fastai
https://timeseriesai.github.io/tsai/
Apache License 2.0
5.09k stars 635 forks source link

Horizon of > 1 throws TypeError: __init__() got an unexpected keyword argument 'custom_head' #400

Closed nurrebass1 closed 2 years ago

nurrebass1 commented 2 years ago

from tsai.all import * ts = get_forecasting_time_series("Sunspots").values X, y = SlidingWindow(60, horizon=3)(ts) splits = TimeSplitter(235)(y) batch_tfms = TSStandardize() fcst = TSForecaster(X, y, splits=splits, batch_tfms=batch_tfms, bs=512, arch=TST, metrics=mae, cbs=ShowGraph()) fcst.fit_one_cycle(50, 1e-3) fcst.export("models/fcst.pkl") # make sure you set the path to a folder that already exists

oguiza commented 2 years ago

Hi @nurrebass1, The issue in this case is that you are using TST (instead of TSTPlus). TST is a model based on the original model published by Zerveas (A Transformer-based Framework for Multivariate Time Series Representation Learning - https://arxiv.org/abs/2010.02803). It cannot handled multi-step targets. That's why I added models ending in Plus. They are based on the original ones, but add additional functionality. So if you run this code it'll work:

ts = get_forecasting_time_series("Sunspots").values
X, y = SlidingWindow(60, horizon=3)(ts)
splits = TimeSplitter(235)(y)
batch_tfms = TSStandardize()
fcst = TSForecaster(X, y, splits=splits, batch_tfms=batch_tfms, bs=512, arch=TSTPlus, metrics=mae, cbs=ShowGraph())
fcst.fit_one_cycle(50, 1e-3)
fcst.export("models/fcst.pkl")
nurrebass1 commented 2 years ago

Thank you very much @oguiza. That explains why using TST hasn't been working. I have second question: I am just wondering what the correct way to use Tsai to predict values for a given horizon and calculate MSE for each day in the given horizon trained on a LSTMPlus model. Does the following look right to you?

trainingWindowSize = 21
predictionWindowSize = 7

X, y = SlidingWindow(trainingWindowSize, horizon=predictionWindowSize)(data)
splits = TimeSplitter(235)(y) 
#splits = get_splits(y, valid_size=.2, stratify=True, random_state=23, shuffle=False)
batch_tfms = TSStandardize()
tfms  = [None, [TSForecasting()]]
dls = get_ts_dls(X, y, splits=splits, batch_tfms=batch_tfms, tfms = tfms, bs=512, arch=LSTMPlus, metrics=mse, cbs=ShowGraph())
#fcst = TSForecaster(X, y, splits=splits, batch_tfms=batch_tfms, bs=512, arch=LSTMPlus, metrics=mae, cbs=ShowGraph())

learn_LSTMPlus = ts_learner(dls, LSTMPlus, metrics=[mse], cbs=ShowGraph())
lr_LSTMPlus = learn_LSTMPlus.lr_find()

learn_LSTMPlus = ts_learner(dls, LSTMPlus, metrics=[mse], cbs=ShowGraph())
learn_LSTMPlus.fit_one_cycle(200, lr_LSTMPlus)

for i in range(predictionWindowSize):
    probas, _, preds_test_dataset = learn_LSTMPlus.get_X_preds(X)
mse_lstm_plus = skm.mean_squared_error(y, preds_test_dataset, squared=False)
oguiza commented 2 years ago

Hi @nurrebass1, I think your code is ok. The only thing I'd suggest is replacing:

for i in range(predictionWindowSize):
    probas, _, preds_test_dataset = learn_LSTMPlus.get_X_preds(X)
mse_lstm_plus = skm.mean_squared_error(y, preds_test_dataset, squared=False)

by something like this:

preds, targets, _ = learn_LSTMPlus.get_X_preds(X, y)
rmse_per_step = (((targets - preds)**2)**.5)
rmse_per_step

This would give you the rmse per sample and step. I believe this is what you are looking for.

saulofalcao commented 2 years ago

Hi @oguiza,

I'm having the same error message but using the MiniRocket when I try to get the horizon > 1. I tried to use the MiniRocketPlus but i got the same error. This is the code that I'm using (I'm novice at machine learning, so I'm not sure about where this error comes from):

window_length = 10
X, y = SlidingWindow(window_length,  get_x=[0,1,2,3,4], get_y=13, horizon=3)(df)

splits = get_splits(y, valid_size=.2, stratify=True, random_state=23, shuffle=False)

mrf = MiniRocketFeatures(X.shape[1], X.shape[2]).to(default_device())
X_train = X[splits[0]]

mrf.fit(torch.from_numpy(X_train).type(FloatTensor))

X_feat = get_minirocket_features(torch.from_numpy(X).type(torch.FloatTensor), mrf, chunksize=1024, to_np=True)
tfms = [None, TSForecasting()]
batch_tfms = TSStandardize(by_sample=True)
dls = get_ts_dls(X, y, splits=splits, tfms=tfms, batch_tfms=batch_tfms)
model = build_ts_model(MiniRocketPlus, dls=dls)
model.head

Error:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
/var/folders/f7/_hcm_8dd2qj4k2t9k9blkm2h0000gn/T/ipykernel_90233/1043730671.py in <module>
     13 batch_tfms = TSStandardize(by_sample=True)
     14 dls = get_ts_dls(X, y, splits=splits, tfms=tfms, batch_tfms=batch_tfms)
---> 15 model = build_ts_model(MiniRocketPlus, dls=dls)
     16 model.head

~/opt/anaconda3/lib/python3.9/site-packages/tsai/models/utils.py in build_ts_model(arch, c_in, c_out, seq_len, d, dls, device, verbose, pretrained, weights_path, exclude_head, cut, init, arch_config, **kwargs)
    134             if v in arch.__name__]):
    135         pv(f'arch: {arch.__name__}(c_in={c_in} c_out={c_out} seq_len={seq_len} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)
--> 136         model = arch(c_in, c_out, seq_len=seq_len, **arch_config, **kwargs).to(device=device)
    137     elif 'xresnet' in arch.__name__ and not '1d' in arch.__name__:
    138         pv(f'arch: {arch.__name__}(c_in={c_in} c_out={c_out} device={device}, arch_config={arch_config}, kwargs={kwargs})', verbose)

TypeError: __init__() got an unexpected keyword argument 'custom_head'

Thanks for your help!

nurrebass1 commented 2 years ago

@saulofalcao it can look like you are missing the arch parameter when using the get_ts_dls method. I think it is where you tell it which algorithm to use. Try that and see what happens.