dsipts 1.1.5__py3-none-any.whl → 1.1.7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -800,6 +800,7 @@ class TimeSeries():
800
800
  callbacks=[checkpoint_callback,mc],
801
801
  auto_lr_find=auto_lr_find,
802
802
  accelerator=accelerator,
803
+ log_every_n_steps=5,
803
804
  devices=devices,
804
805
  strategy=strategy,
805
806
  enable_progress_bar=False,
@@ -813,6 +814,7 @@ class TimeSeries():
813
814
  callbacks=[checkpoint_callback,mc],
814
815
  strategy='auto',
815
816
  devices=devices,
817
+ log_every_n_steps=5,
816
818
  enable_progress_bar=False,
817
819
  precision=precision,
818
820
  gradient_clip_val=gradient_clip_val,
@@ -231,28 +231,11 @@ class DilatedConv(Base):
231
231
  activation(),
232
232
  nn.Linear(hidden_RNN//4,1)))
233
233
 
234
+ self.return_additional_loss = True
234
235
 
235
236
 
236
237
 
237
238
 
238
- def training_step(self, batch, batch_idx):
239
- """
240
- pythotrch lightening stuff
241
-
242
- :meta private:
243
- """
244
- y_hat,score = self(batch)
245
- return self.compute_loss(batch,y_hat)#+torch.abs(score-self.glu_percentage)*loss/5.0 ##TODO investigating
246
-
247
- def validation_step(self, batch, batch_idx):
248
- """
249
- pythotrch lightening stuff
250
-
251
- :meta private:
252
- """
253
- y_hat,score = self(batch)
254
- return self.compute_loss(batch,y_hat)#+torch.abs(score-self.glu_percentage)*loss/5.0 ##TODO investigating
255
-
256
239
  def forward(self, batch):
257
240
  """It is mandatory to implement this method
258
241
 
@@ -332,11 +315,11 @@ class DilatedConv(Base):
332
315
  res = res.reshape(B,self.future_steps,-1,self.mul)
333
316
  if self.remove_last:
334
317
  res+=x_start.unsqueeze(1)
335
-
318
+
336
319
 
337
320
  return res, score
338
321
 
339
322
  def inference(self, batch:dict)->torch.tensor:
340
-
323
+
341
324
  res, score = self(batch)
342
325
  return res
dsipts/models/base.py CHANGED
@@ -154,7 +154,7 @@ class Base(pl.LightningModule):
154
154
  assert self.out_channels==1, "Classification require only one channel"
155
155
 
156
156
  self.future_steps = future_steps
157
-
157
+ self.return_additional_loss = False
158
158
  beauty_string(self.description,'info',True)
159
159
  @abstractmethod
160
160
  def forward(self, batch:dict)-> torch.tensor:
@@ -247,14 +247,22 @@ class Base(pl.LightningModule):
247
247
  opt = self.optimizers()
248
248
  def closure():
249
249
  opt.zero_grad()
250
- y_hat = self(batch)
251
- loss = self.compute_loss(batch,y_hat)
250
+ if self.return_additional_loss:
251
+ y_hat,score = self(batch)
252
+ loss = self.compute_loss(batch,y_hat) + score
253
+ else:
254
+ y_hat = self(batch)
255
+ loss = self.compute_loss(batch,y_hat)
252
256
  self.manual_backward(loss)
253
257
  return loss
254
258
 
255
259
  opt.step(closure)
256
- y_hat = self(batch)
257
- loss = self.compute_loss(batch,y_hat)
260
+ if self.return_additional_loss:
261
+ y_hat,score = self(batch)
262
+ loss = self.compute_loss(batch,y_hat)+score
263
+ else:
264
+ y_hat = self(batch)
265
+ loss = self.compute_loss(batch,y_hat)
258
266
 
259
267
  #opt.first_step(zero_grad=True)
260
268
 
@@ -269,8 +277,14 @@ class Base(pl.LightningModule):
269
277
 
270
278
  #self.trainer.fit_loop.epoch_loop.manual_optimization.optim_step_progress.increment("optimizer")
271
279
  else:
272
- y_hat = self(batch)
273
- loss = self.compute_loss(batch,y_hat)
280
+ if self.return_additional_loss:
281
+ y_hat,score = self(batch)
282
+ loss = self.compute_loss(batch,y_hat)+score
283
+ else:
284
+ y_hat = self(batch)
285
+ loss = self.compute_loss(batch,y_hat)
286
+
287
+ self.train_epoch_metrics.append(loss.item())
274
288
  return loss
275
289
 
276
290
 
@@ -280,7 +294,11 @@ class Base(pl.LightningModule):
280
294
 
281
295
  :meta private:
282
296
  """
283
- y_hat = self(batch)
297
+ if self.return_additional_loss:
298
+ y_hat,score = self(batch)
299
+ else:
300
+ y_hat = self(batch)
301
+ score = 0
284
302
  if batch_idx==0:
285
303
  if self.use_quantiles:
286
304
  idx = 1
@@ -301,7 +319,7 @@ class Base(pl.LightningModule):
301
319
  self.logger.experiment.track(Image(fig), name='cm_training_end')
302
320
  #self.log(f"example_{i}", np.stack([real, pred]).T,sync_dist=True)
303
321
 
304
- return self.compute_loss(batch,y_hat)
322
+ return self.compute_loss(batch,y_hat)+score
305
323
 
306
324
 
307
325
  def validation_epoch_end(self, outs):
@@ -310,8 +328,12 @@ class Base(pl.LightningModule):
310
328
 
311
329
  :meta private:
312
330
  """
313
-
314
- loss = torch.stack(outs).mean()
331
+ if len(outs)==0:
332
+ loss = 10000
333
+ beauty_string(f'THIS IS A BUG, It should be polulated','info',self.verbose)
334
+ else:
335
+ loss = torch.stack(outs).mean()
336
+
315
337
  self.log("val_loss", loss.item(),sync_dist=True)
316
338
  beauty_string(f'Epoch: {self.count_epoch} train error: {self.train_loss_epoch:.4f} validation loss: {loss.item():.4f}','info',self.verbose)
317
339
 
dsipts/models/base_v2.py CHANGED
@@ -157,7 +157,7 @@ class Base(pl.LightningModule):
157
157
 
158
158
 
159
159
  self.future_steps = future_steps
160
-
160
+ self.return_additional_loss = False
161
161
  beauty_string(self.description,'info',True)
162
162
  @abstractmethod
163
163
  def forward(self, batch:dict)-> torch.tensor:
@@ -250,14 +250,22 @@ class Base(pl.LightningModule):
250
250
  opt = self.optimizers()
251
251
  def closure():
252
252
  opt.zero_grad()
253
- y_hat = self(batch)
254
- loss = self.compute_loss(batch,y_hat)
253
+ if self.return_additional_loss:
254
+ y_hat,score = self(batch)
255
+ loss = self.compute_loss(batch,y_hat) + score
256
+ else:
257
+ y_hat = self(batch)
258
+ loss = self.compute_loss(batch,y_hat)
255
259
  self.manual_backward(loss)
256
260
  return loss
257
261
 
258
262
  opt.step(closure)
259
- y_hat = self(batch)
260
- loss = self.compute_loss(batch,y_hat)
263
+ if self.return_additional_loss:
264
+ y_hat,score = self(batch)
265
+ loss = self.compute_loss(batch,y_hat)+score
266
+ else:
267
+ y_hat = self(batch)
268
+ loss = self.compute_loss(batch,y_hat)
261
269
 
262
270
  #opt.first_step(zero_grad=True)
263
271
 
@@ -272,8 +280,12 @@ class Base(pl.LightningModule):
272
280
 
273
281
  #self.trainer.fit_loop.epoch_loop.manual_optimization.optim_step_progress.increment("optimizer")
274
282
  else:
275
- y_hat = self(batch)
276
- loss = self.compute_loss(batch,y_hat)
283
+ if self.return_additional_loss:
284
+ y_hat,score = self(batch)
285
+ loss = self.compute_loss(batch,y_hat)+score
286
+ else:
287
+ y_hat = self(batch)
288
+ loss = self.compute_loss(batch,y_hat)
277
289
 
278
290
  self.train_epoch_metrics.append(loss.item())
279
291
  return loss
@@ -285,7 +297,12 @@ class Base(pl.LightningModule):
285
297
 
286
298
  :meta private:
287
299
  """
288
- y_hat = self(batch)
300
+
301
+ if self.return_additional_loss:
302
+ y_hat,score = self(batch)
303
+ else:
304
+ y_hat = self(batch)
305
+ score = 0
289
306
  if batch_idx==0:
290
307
  if self.use_quantiles:
291
308
  idx = 1
@@ -305,7 +322,7 @@ class Base(pl.LightningModule):
305
322
  ax.set_title(f'Channel {i} first element first batch validation {int(100*self.count_epoch/self.trainer.max_epochs)}%')
306
323
  self.logger.experiment.track(Image(fig), name='cm_training_end')
307
324
  #self.log(f"example_{i}", np.stack([real, pred]).T,sync_dist=True)
308
- self.validation_epoch_metrics.append(self.compute_loss(batch,y_hat))
325
+ self.validation_epoch_metrics.append(self.compute_loss(batch,y_hat)+score)
309
326
  return
310
327
 
311
328
 
@@ -315,7 +332,12 @@ class Base(pl.LightningModule):
315
332
 
316
333
  :meta private:
317
334
  """
318
- avg = torch.stack(self.validation_epoch_metrics).mean()
335
+
336
+ if len(self.validation_epoch_metrics)==0:
337
+ avg = 10000
338
+ beauty_string(f'THIS IS A BUG, It should be polulated','info',self.verbose)
339
+ else:
340
+ avg = torch.stack(self.validation_epoch_metrics).mean()
319
341
  self.validation_epoch_metrics = []
320
342
  self.log("val_loss", avg,sync_dist=True)
321
343
  beauty_string(f'Epoch: {self.count_epoch} train error: {self.train_loss_epoch:.4f} validation loss: {avg:.4f}','info',self.verbose)
@@ -327,7 +349,11 @@ class Base(pl.LightningModule):
327
349
 
328
350
  :meta private:
329
351
  """
330
- avg = np.stack(self.train_epoch_metrics).mean()
352
+ if len(self.train_epoch_metrics)==0:
353
+ avg = 0
354
+ beauty_string(f'THIS IS A BUG, It should be polulated','info',self.verbose)
355
+ else:
356
+ avg = np.stack(self.train_epoch_metrics).mean()
331
357
  self.log("train_loss", avg,sync_dist=True)
332
358
  self.count_epoch+=1
333
359
  self.train_epoch_metrics = []
@@ -0,0 +1,438 @@
1
+ Metadata-Version: 2.4
2
+ Name: dsipts
3
+ Version: 1.1.7
4
+ Summary: Unified library for timeseries modelling
5
+ Author-email: Andrea Gobbi <agobbi@fbk.eu>
6
+ Project-URL: Homepage, https://github.com/DSIP-FBK/DSIPTS
7
+ Project-URL: Docs, https://dsip-fbk.github.io/DSIPTS/
8
+ Requires-Python: ==3.11.13
9
+ Description-Content-Type: text/markdown
10
+ Requires-Dist: aim==3.20.1
11
+ Requires-Dist: beautifulsoup4==4.12.0
12
+ Requires-Dist: einops>=0.8.1
13
+ Requires-Dist: html-table-parser-python3==0.3.1
14
+ Requires-Dist: html5lib>=1.1
15
+ Requires-Dist: hydra-core>=1.3.2
16
+ Requires-Dist: hydra-joblib-launcher>=1.2.0
17
+ Requires-Dist: hydra-optuna-sweeper>=1.2.0
18
+ Requires-Dist: hydra-submitit-launcher>=1.2.0
19
+ Requires-Dist: ipykernel>=6.30.1
20
+ Requires-Dist: lightning>=2.5.4
21
+ Requires-Dist: matplotlib>=3.10.6
22
+ Requires-Dist: nbformat>=5.10.4
23
+ Requires-Dist: numba>=0.61.2
24
+ Requires-Dist: numpy<2.0.0
25
+ Requires-Dist: pandas>=2.3.2
26
+ Requires-Dist: plotly>=6.3.0
27
+ Requires-Dist: scikit-learn>=1.7.1
28
+ Requires-Dist: sphinx>=8.2.3
29
+ Requires-Dist: sphinx-mdinclude>=0.6.2
30
+ Requires-Dist: sphinx-pdj-theme>=0.7.3
31
+ Requires-Dist: transformers>=4.56.0
32
+
33
+
34
+
35
+ # DSIPTS: unified library for timeseries modelling
36
+ > [!CAUTION]
37
+ The documentation, README and notebook are somehow outdated, some architectures are under review, please be patient. Moreover, there will some frequent changes due to refactoring or documentation update. Wait the version 1.2.0 for more stable library (in terms of structure and documentation) or even 2.0.0 for the tests, assertions and other standard stuff.
38
+
39
+ This library allows to:
40
+
41
+ - load timeseries in a convenient format
42
+ - create tool timeseries with controlled categorical features
43
+ - load public timeseries
44
+ - train a predictive model using different PyTorch architectures
45
+ - define more complex structures using Modifiers (e.g. combining unsupervised learning + deep learning)
46
+
47
+ ## Disclamer
48
+ The original repository is located [here](https://gitlab.fbk.eu/dsip/dsip_dlresearch/timeseries) but there is a push mirror in gitlab and you can find it [here](https://github.com/DSIP-FBK/DSIPTS/). Depending on the evolution of the library we will decide if keep both or move definitively to github.
49
+
50
+
51
+ ## Background
52
+
53
+ Let $X(t)$ be a multivariate timeseries, e.g. $\forall t, X(t)\in \mathbf{R}^k$ for some $k$. The vector space $\mathbf{R}^k$ can be partitioned into two disjoint sets: the categorical features $\mathcal{C}\subset \mathbf{N}^c$ and continuous features $\mathcal{W}\subset \mathbf{R}^{k-c}$. We assume that $\mathcal{C}$ is known for each $t$. Let $\mathcal{F}\subset\mathbf{R}^{f}$ be the set of known variables for each $t$, $\mathcal{P}\subset\mathbf{R}^{p}$ be the set of variables known until time $t$, and $\mathcal{T}\subset\mathcal{P}\subset\mathbf{R}^{s}$ the target variables. Let also define $\tau\in N$ as the number of lag for wich we want a forecast, then the aim of a predictive model is to find a function $F:\mathbf{R}^k\rightarrow\mathbf{R}^{s \times \tau}$ such as:
54
+
55
+ $$
56
+ F(\mathcal{C}(t-K,\ldots,t+\tau),\mathcal{F}(t-K,\ldots,t+\tau),\mathcal{P}(t-K,\ldots,t),\mathcal{T}(t-K,\ldots,t) ) = \mathcal{T}(t+1,\ldots,t+\tau)
57
+ $$
58
+
59
+ for some K representing the maximum past context.
60
+
61
+ In the library we adopt some convention that must be used when developing a new model:
62
+ ```
63
+ y : the target variable(s)
64
+ x_num_past: the numerical past variables
65
+ x_num_future: the numerical future variables
66
+ x_cat_past: the categorical past variables
67
+ x_cat_future: the categorical future variables
68
+ idx_target: index containing the y variables in the past dataset. Can be used during the training for train a differential model
69
+ ```
70
+ by default, during the dataset construction, the target variable will be added to the `x_num_past` list. Moreover the set of categorical variable can be different in the past and the future but we choose to distinguish the two parts during the forward loop for seek of generability.
71
+
72
+ During the forward process, the batch is a dictionary with some of the key showed above, remember that not all keys are always present (check it please) and build a model according. The shape of such tensor are in the form $[B,L,C]$ where $B$ indicates the batch size, $L$ the length and $C$ the number of channels.
73
+
74
+ The output of a new model must be $[B,L,C,1]$ in case of single prediction or $[B,L,C,3]$ in case you are using quantile loss.
75
+
76
+
77
+ Try to reuse some of the common keywords while building your model. After the initialization of the model you can use whatever variable you want but during the initialization please use the following conventions.
78
+ This first block maybe is common between several architectures:
79
+
80
+ ---
81
+
82
+ - **past_steps** = int. THIS IS CRUCIAL and self explanatory
83
+ - **future_steps** = int. THIS IS CRUCIAL and self explanatory
84
+ - **past_channels** = len(ts.num_var). THIS IS CRUCIAL and self explanatory
85
+ - **future_channels** = len(ts.future_variables). THIS IS CRUCIAL and self explanatory
86
+ - **out_channels** = len(ts.target_variables). THIS IS CRUCIAL and self explanatory
87
+ - **embs_past** = [ts.dataset[c].nunique() for c in ts.cat_past_var]. THIS IS CRUCIAL and self explanatory.
88
+ - **embs_fut** = [ts.dataset[c].nunique() for c in ts.cat_fut_var]. THIS IS CRUCIAL and self explanatory.
89
+ - **use_classical_positional_encoder** = classical positioal code are done with the combination of sin/cos/exponenstial function, otherwise the positional encoding is done with the `nn.Embedding` like the other categorical variables
90
+ - **reduction_mode** = the categorical metafeatures can be summed, averaged or stacked depending on what behavior you like more.
91
+ - **emb_dim** = int. Dimension of embedded categorical variables, the choice here is to use a constant value and let the user chose if concatenate or sum the variables
92
+ - **quantiles** =[0.1,0.5,0.9]. Quantiles for quantile loss
93
+ - **kind** =str. If there are some similar architectures with small differences maybe is better to use the same code specifying some properties (e.g. GRU vs LSTM)
94
+ - **activation** = str ('torch.nn.ReLU' default). activation function between layers (see [pytorch activation functions](https://pytorch.org/docs/stable/nn.html#non-linear-activations-weighted-sum-nonlinearity))
95
+ - **optim** = str ('torch.optim.Adam' default). optimization function see [pytorch optimization functions](https://pytorch.org/docs/stable/optim.html)
96
+ - **dropout_rate** =float. dropout rate
97
+ - **use_bn** =boolean . Use or not batch normalization
98
+ - **persistence_weight** = float . Penalization weight for persistent predictions
99
+ - **loss_type** = str . There are some other metrics implemented, see the [metric section](#metrics) for details
100
+
101
+
102
+ ---
103
+ some are more specific for RNN-CONV architectures:
104
+
105
+ ---
106
+ - **hidden_RNN** = int. If there are some RNN use this and the following
107
+ - **num_layers_RNN** = int.
108
+ - **kernel_size** = int. If there are some convolutional layers
109
+
110
+ ---
111
+
112
+ linear:
113
+
114
+ - **hidden_size** = int. Usually the hidden dimension, for some architecture maybe you can pass the list of the dimensions
115
+ - **kind** =str. Type of linear approach
116
+
117
+ ---
118
+
119
+ or attention based models:
120
+
121
+ - **d_model** = int .d_model of a typical attention layer
122
+ - **n_heads** = int .Heads
123
+ - **dropout_rate** = float. dropout
124
+ - **n_layer_encoder** = int. encoder layers
125
+ - **n_layer_decoder** = int. decoder layers
126
+ ---
127
+
128
+ ## Install
129
+ Clone the repo (gitlab or github)
130
+ The library is structured to work with [uv](https://github.com/astral-sh/uv). After installing `uv` just run
131
+ ```bash
132
+ uv pip install .
133
+ ```
134
+ You can install also the package from pip (be sure that the python version is less than 3.12, still sperimental):
135
+ ```bash
136
+ uv venv --python 3.11
137
+ uv pip install dsipts
138
+ ```
139
+
140
+
141
+ ## For developers
142
+ - Remember to update the `pyproject.toml`
143
+ - use `uv add` and `uv sync` for update the project
144
+ - `uv pip install -e .` for install dsipts
145
+ - `uv build` for building it
146
+ - `uv pip install dist/dsipts-X.Y.Z-py3-none-any.whl` for checking the installation
147
+ - generate documentation with `uv run sphinx-quickstart docs` (just the first time)
148
+ - `uv run sphinx-apidoc -o docs/source src/dsipts`
149
+ - `uv run sphinx-build -b html docs/source ../docs`
150
+ ## AIM
151
+ DSIPTS uses AIM for tracking losses, parameters and other useful information. The first time you use DSIPTS you may need to initialize aim executing:
152
+ ```bash
153
+ aim init
154
+ ```
155
+
156
+
157
+
158
+ ## Usage
159
+
160
+ Let make an example with the public weather data (you can find it [here](https://drive.google.com/drive/folders/13Cg1KYOlzM5C7K8gK8NfC-F3EYxkM3D2) or [here](https://github.com/thuml/Time-Series-Library?tab=readme-ov-file))
161
+
162
+
163
+
164
+
165
+ ```python
166
+ import pandas as pd
167
+ import numpy as np
168
+ from dsipts import TimeSeries, RNN,read_public_dataset
169
+ import matplotlib.pyplot as plt
170
+ from datetime import timedelta
171
+ import logging
172
+ import sys
173
+ data, columns = read_public_dataset(PATH_TO_DATA,'weather')
174
+ ```
175
+ define then how to use the information and define the time series. You can add automatically the `hour` categorical data using the key `enrich_cat` that will be automatically added to the categorical past and categorical future list of columns:
176
+ ```pyhon
177
+ use_covariates = False #use only y in the PAST
178
+ use_future_covariate = True #suppose to have some future covariates
179
+ ts = TimeSeries('weather')
180
+ ts.load_signal( data,enrich_cat=['hour'],target_variables=['y'],past_variables=columns if use_covariates else [], future_variables=columns if use_future_covariate else [] )
181
+ fig = ts.plot() # plot the target variable(s )
182
+ ```
183
+ The most important part is the method `ts.load_signal` where the user can specify the parameters of the timeseries such as:
184
+
185
+
186
+ - **data** (pd.DataFrame) – input dataset the column indicating the time must be called time
187
+
188
+ - **enrich_cat** (List[str], optional) – it is possible to let this function enrich the dataset for example adding the standard columns: hour, dow, month and minute. Defaults to [].
189
+
190
+ - **past_variables** (List[str], optional) – list of column names of past variables not available for future times . Defaults to [].
191
+
192
+ - **future_variables** (List[str], optional) – list of future variables available for future times. Defaults to [].
193
+
194
+ - **target_variables** (List[str], optional) – list of the target variables. They will added to past_variables by default unless check_past is false. Defaults to [].
195
+
196
+ - **cat_past_var** (List[str], optional) – list of the past categorical variables. Defaults to [].
197
+
198
+ - **cat_future_var** (List[str], optional) – list of the future categorical variables. Defaults to [].
199
+
200
+ - **check_past** (bool, optional) – see target_variables. Defaults to True.
201
+
202
+ - **group** (str or None, optional) – if not None the time series dataset is considered composed by homogeneous timeseries coming from different realization (for example point of sales, cities, locations) default None (and the relative series are not split during the sample generation. Defaults to)
203
+
204
+ - **check_holes_and_duplicates** (bool, optional) – if False duplicates or holes will not checked, the dataloader can not correctly work, disable at your own risk. Defaults True
205
+
206
+ - **silly_model (bool, optional)** – if True, target variables will be added to the pool of the future variables. This can be useful to see if information passes thought the decoder part of your model (if any)
207
+
208
+
209
+
210
+ Now we can define a forecasting problem (`past_steps` as context, `future_steps` as future horizon )
211
+
212
+ Let suppose to use a RNN encoder-decoder structure, then the model has the following parameters:
213
+ ```python
214
+ past_steps = 12*7
215
+ future_steps = 12
216
+ config = dict(model_configs =dict(
217
+
218
+ past_steps = past_steps, #TASK DEPENDENT
219
+ future_steps = future_steps,#TASK DEPENDENT
220
+
221
+ emb_dim = 16, # categorical stuff
222
+ use_classical_positional_encoder = True, # categorical stuff
223
+ reduction_mode = 'mean',# categorical stuff
224
+
225
+ kind = 'gru',# model dependent
226
+ hidden_RNN = 12,# model dependent
227
+ num_layers_RNN = 2,# model dependent
228
+ kernel_size = 15,# model dependent
229
+ dropout_rate= 0.5,# model dependent
230
+ remove_last= True,# model dependent
231
+ use_bn = False,# model dependent
232
+ activation= 'torch.nn.PReLU', # model dependent
233
+
234
+ quantiles=[0.1,0.5,0.9], #LOSS
235
+ persistence_weight= 0.010, #LOSS
236
+ loss_type= 'l1', #LOSS
237
+
238
+ optim= 'torch.optim.Adam', #OPTIMIZER
239
+
240
+ past_channels = len(ts.past_variables), #parameter that depends on the ts dataset
241
+ future_channels = len(ts.future_variables), #parameter that depends on the ts dataset
242
+ embs_past = [ts.dataset[c].nunique() for c in ts.cat_past_var], #parameter that depends on the ts dataset
243
+ embs_fut = [ts.dataset[c].nunique() for c in ts.cat_fut_var], #parameter that depends on the ts dataset
244
+ out_channels = len(ts.target_variables)), #parameter that depends on the ts dataset
245
+
246
+ scheduler_config = dict(gamma=0.1,step_size=100),
247
+ optim_config = dict(lr = 0.0005,weight_decay=0.01))
248
+ model_rnn = RNN(**config['model_configs'],optim_config = config['optim_config'],scheduler_config =config['scheduler_config'],verbose=False )
249
+
250
+ ts.set_model(model_rnn,config=config )
251
+
252
+ ```
253
+
254
+
255
+ Now we are ready to split and train our model. First define the splitting configuration:
256
+ ```python
257
+ split_params = {'perc_train':0.7,'perc_valid':0.1, ##if not None it will split 70% 10% 20%
258
+ 'range_train':None, 'range_validation':None, 'range_test':None, ## or we can split using ranges for example range_train=['2021-02-03','2022-04-08']
259
+ 'past_steps':past_steps,
260
+ 'future_steps':future_steps,
261
+ 'starting_point':None, ## do not skip samples
262
+ 'skip_step' : 10 ## distance between two consecutive samples, aka the stride (larger it is, less point we have in train)
263
+ }
264
+
265
+ ts.train_model(dirpath=PATH_TO_SAVING_STUFF,
266
+ split_params=split_params,
267
+ batch_size=128,
268
+ num_workers=4,
269
+ max_epochs=2,
270
+ gradient_clip_val= 0.0,
271
+ gradient_clip_algorithm='value',
272
+ precision='bf16',
273
+ auto_lr_find=True)
274
+
275
+ ts.losses.plot()
276
+ ts.save("weather") ##save all the metadata to use it in inference mode after
277
+
278
+ ```
279
+
280
+ It is possble to split the data indicating the percentage of data to use in train, validation, test or the ranges. The `shift` parameters indicates if there is a shift constucting the y array. It cab be used for some attention model where we need to know the first value of the timeseries to predict. It may disappear in future because it is misleading. The `skip_step` parameters indicates how many temporal steps there are between samples. If you need a future signal that is long `skip_step+future_steps` then you should put `keep_entire_seq_while_shifting` to True (see Informer model).
281
+
282
+ During the training phase a log stream will be generated. If a single process is spawned the log will be displayed, otherwise a file will be generated. Moreover, inside the `weight` path there wil be the `loss.csv` file containing the running losses.
283
+
284
+ At the end of the training process it is possible to load the model passing the model class (`RNN`) and the saving name used before (`weather`)
285
+ If the same model and the same name are used for defining the time series, the training procedure will continue from the last checkpoint. Due to lightening related usage, the counting of the epochs will start from the last stage (if you trained if for 10 epochs and you want to train 10 epochs more you need to change it to 20).
286
+
287
+
288
+
289
+ ```python
290
+
291
+ ts.load(RNN,"weather",load_last=True)
292
+ res = ts.inference_on_set(200,4,set='test',rescaling=True)
293
+ error = res.groupby('lag').apply(lambda x: np.nanmean((x.y-x.y_median)**2)).reset_index().rename(columns={0:'error'})
294
+
295
+ ```
296
+ If a quantile loss has been selected the model generates three signals `_low, _median, _high`, if not the output the model is indicated with `_pred`. Lag indicates which step the prediction is referred (eg. lag=1 is the first output of the model along the sequence output).
297
+
298
+ ```
299
+ import matplotlib.pyplot as plt
300
+ mask = res.prediction_time=='2020-10-19 19:50:00'
301
+ plt.plot(res.lag[mask],res.y[mask],label='real')
302
+ plt.plot(res.lag[mask],res.y_median[mask],label='median')
303
+ plt.legend()
304
+ ```
305
+ Another useful plot is the error plot per lag where it is possible to observe the increment of the error in correlation with the lag time:
306
+
307
+ ```
308
+ import numpy as np
309
+ res['error'] =np.abs( res['y']-res['y_median'])
310
+ res.groupby('lag').error.mean().plot()
311
+ ```
312
+
313
+
314
+
315
+ This example can be found [here](/notebooks/public_timeseries.ipynb).
316
+
317
+ # Categorical variables
318
+ Most of the models implemented can deal with categorical variables (`cat_past_var` and `cat_fut_var`). In particulare there are some variables that you don't need to computed. When declaring a `ts` obejct you can pass also the parameter `enrich_cat=['dow']` that will add to the dataframe (and to the dataloader) the day of the week. Since now you can automatically add `hour, dow, month and minute`. If there are other categorical variables pleas add it to the list while loading your data.
319
+
320
+
321
+
322
+ # Models
323
+ A description of each model can be found in the class documentation [here](https://dsip.pages.fbk.eu/dsip_dlresearch/timeseries/).
324
+ It is possible to use one of the following architectures:
325
+
326
+ - **RNN** (GRU, LSTM or xLSTM) models, (xLSTM)[https://arxiv.org/pdf/2405.04517] are taken from the [official repo](https://github.com/muditbhargava66/PyxLSTM)
327
+ - **Linear** models based on the [official repository](https://github.com/cure-lab/LTSF-Linear), [paper](https://arxiv.org/pdf/2205.13504.pdf). An alternative model (alinear) has been implemented that drop the autoregressive part and uses only covariates
328
+ - **Crossformer** [official repository](https://github.com/cheerss/CrossFormer), [paper](https://openreview.net/forum?id=vSVLM2j9eie)
329
+ - **Informer** [official repository](https://github.com/zhouhaoyi/Informer2020), [paper](https://arxiv.org/abs/2012.07436)
330
+ - **Autoformer** [non official repository](https://github.com/yuqinie98/PatchTST/tree/main), [paper](https://arxiv.org/abs/2106.13008)
331
+ - **PatchTST** [official repository](https://github.com/yuqinie98/PatchTST/tree/main), [paper](https://arxiv.org/abs/2211.14730)
332
+ - **Persistent** baseline model
333
+ - **TFT** [paper](https://arxiv.org/abs/1912.09363)
334
+ - **DilatedConv** dilated convolutional RNN: the transfer of knowledge between past and future is performed reusing the final hidden status of the RNN of the encoder as initial hidden status of the decoder.
335
+ - **DilatedConvED** dilated convolutional RNN with an encoder/decoder structure.
336
+
337
+ - **ITransformer** [paper](https://arxiv.org/abs/2310.06625), [official repo](https://github.com/thuml/iTransformer)
338
+ - **TIDE** [paper](https://arxiv.org/abs/2304.08424)
339
+ - **Samformer** [paper](https://arxiv.org/pdf/2402.10198) [official repo](https://github.com/romilbert/samformer/tree/main?tab=MIT-1-ov-)
340
+ - **Duet** [paper](https://arxiv.org/abs/2412.10859) [official repo](https://github.com/decisionintelligence/DUET)
341
+
342
+ These models are under review because broken or not aligned with the recent distinction between past and future categorical data:
343
+
344
+ - **Diffusion** custom [diffusion process](https://arxiv.org/abs/2102.09672) using the attention mechanism in the subnets.
345
+ - **D3VAE** adaptation of the [official repository](https://github.com/PaddlePaddle/PaddleSpatial), [paper](https://arxiv.org/abs/2301.03028)
346
+ - **VQVAE** adaptation of [vqvae for images](https://nbviewer.org/github/zalandoresearch/pytorch-vq-vae/blob/master/vq-vae.ipynb) decribed in this [paper](https://arxiv.org/abs/1711.00937) paired with [GPT](https://github.com/karpathy/minGPT) transformer.
347
+ - **VVA** like VQVAE but the tokenization step is performed using a clustering standard procedure.
348
+
349
+ ## Metrics
350
+ In some cases the persistence model is hard to beat and even the more complex model can fall in the persistence trap that propagates the last seen values.
351
+ For this reason a set of metrics can be used trying to avoid the model to get stuck in the trap. In particular we implemented: MSE, L1, sinkhorn divergence, dilated
352
+ loss, quantile loss, MDA and a couple of experimental losses for minimizing the variance or penalizing the persistency. See the base model definition in `dsipts/models/base.py` for more details.
353
+
354
+
355
+
356
+ # Bash experiment
357
+ Most of the time you want to train the models in a cluster with a GPU and command line training procedure can help speedup the process. DSIPTS leverages on OmegaConf-Hydra to to this and in the folder `bash_examples` you can find an examples. Please read the documentation [here](/bash_examples/README.md)
358
+
359
+
360
+
361
+ # Modifiers
362
+
363
+ The VVA model is composed by two steps: the first is a clusterting procedure that divides the input time series in smaller segments an performs a clustering procedure in order to associate a label for each segment. A this point the GPT models works on the sequence of labels trying to predict the next cluster id. Using the centroids of the clusters (and the variace) the final ouput is reconstructed. This pipeline is quite unusual and does not fit with the automation pipeline, but it is possible to use a `Modifier` an abstract class that has 3 methods:
364
+ - **fit_transform**: called before startin the training process and returns the train/validation pytorch datasets. In the aforementioned model the clustering model is trained.
365
+ - **transform**: used during the inference phase. It is similar to fit_transform but without the training process
366
+ - **inverse_transform**: the output of the model are reverted to the original shape. In the VVA model the centroids are used for reconstruct the predicted timeseries.
367
+
368
+
369
+ ## Documentation
370
+ You can find the documentation [here](https://dsip.pages.fbk.eu/dsip_dlresearch/timeseries/):
371
+ or in the folder `docs/_build/html/index.html`
372
+ If yon need to generate the documentation after some modification just run:
373
+ ```
374
+ ./make_doc.sh
375
+ ```
376
+
377
+ For user only: be sure that the the CI file has pages enabled, see [public pages](https://roneo.org/en/gitlab-public-pages-private-repo/)
378
+
379
+ # Adding new models
380
+ If you want to add a model:
381
+
382
+ - extend the `Base` class in `dsipts/models`
383
+ - add the export line in the `dsipts/__init__.py`
384
+ - add a full configuration file in `bash_examples/config_test/architecture`
385
+ - optional: add in `bash_script/utils.py` the section to initializate and load the new model
386
+ - add the modifier in `dsipts/data_structure/modifiers.py` if it is required
387
+
388
+ # Testing
389
+ See [here](/bash_examples/README.md) for the testing session.
390
+
391
+ # Logging
392
+ From version 1.1.0, Aim is used for logging all the experiments and metrics. It is quite easy to install and to use. Just go inside the main folder (`bash_exaples`) and run:
393
+ ```
394
+ aim init #only the first time
395
+ aim up
396
+ ```
397
+ and then open the url (http://127.0.0.1:43800)[http://127.0.0.1:43800]. It will show the model parameters, some metrics and the losses during the training procedure
398
+ ![plot](bash_examples/figures/aim1.png)
399
+ but also some prediction (the first sample of the first batch of the validation set, every 10% of the maximum number of epochs.)
400
+ ![plot](bash_examples/figures/aim2.png)
401
+
402
+
403
+ ## TODO
404
+ [ ] reduce test time
405
+
406
+ [ ] add pre-commit hook for code checking (`ruff check --ignore E501,E722 .`)
407
+
408
+ [ ] add pre-commit hook testing
409
+
410
+ [ ] clean code and standardize documentation
411
+
412
+ [ ] add more sintetic data
413
+
414
+ [ ] check all the code in the README
415
+
416
+ [ ] check architecture description (which model can be used under certain assumption)
417
+
418
+ [ ] complete the classification part (loss function + inference step)
419
+
420
+
421
+ [ ] check D3VAE, it seems broken in some configurations
422
+
423
+ [ ] add hybrid models https://www.sciencedirect.com/science/article/pii/S138912862400118X
424
+
425
+ [ ] add SOFTS https://github.com/Secilia-Cxy/SOFTS/blob/main/models/SOFTS.py
426
+
427
+ [ ] add https://github.com/Hank0626/PDF/blob/main/models/PDF.py
428
+
429
+ [ ] add https://github.com/decisionintelligence/pathformer
430
+
431
+ [x] add Duet
432
+
433
+ [x] add categorical support to Crossformer, Samformer
434
+
435
+ [ ] in 1.1.5 we split the future and past categorical variables. D3VAE, Diffusion, TTM need to be revised
436
+
437
+ [ ] all snippet of code and notebook must be review in 1.1.5 (categorical past and future, embedding layer parameters)
438
+
@@ -3,14 +3,14 @@ dsipts/data_management/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
3
3
  dsipts/data_management/monash.py,sha256=aZxq9FbIH6IsU8Lwou1hAokXjgOAK-wdl2VAeFg2k4M,13075
4
4
  dsipts/data_management/public_datasets.py,sha256=yXFzOZZ-X0ZG1DoqVU-zFmEGVMc2033YDQhRgYxY8ws,6793
5
5
  dsipts/data_structure/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
- dsipts/data_structure/data_structure.py,sha256=5yHi6N0zXYzzKooy-91-5C1PEdNuU6ZWD-mApJvDOe8,58888
6
+ dsipts/data_structure/data_structure.py,sha256=kCZHgAWKnubmm06Ao15kIxZ5pU3RkwzHriXeWpNfJxQ,58994
7
7
  dsipts/data_structure/modifiers.py,sha256=qlry9dfw8pEE0GrvgwROZJkJ6oPpUnjEHPIG5qIetss,7948
8
8
  dsipts/data_structure/utils.py,sha256=QwfKPZgSy6DIw5n6ztOdPJIAnzo4EnlMTgRbpiWnyko,6593
9
9
  dsipts/models/Autoformer.py,sha256=ddGT3L9T4gAXNJHx1TsuYZy7j63Anyr0rkqqXaOoSu4,8447
10
10
  dsipts/models/CrossFormer.py,sha256=iO64L3S01jxuWA9dmm8FsK1WRvBIXbZ0PQ2tZlEQg4w,6481
11
11
  dsipts/models/D3VAE.py,sha256=NstHIniNteBRrkfL7SJ3-bJEl3l3IIxoSxavRV3j16U,6857
12
12
  dsipts/models/Diffusion.py,sha256=pUujnrdeSSkj4jC1RORbcptt03KpuCsGVwg414o4LPg,40733
13
- dsipts/models/DilatedConv.py,sha256=2gK69p4Jn9nEI2T2PebNOr70wpyR2QWxzmNQIXRAmJE,14845
13
+ dsipts/models/DilatedConv.py,sha256=_c0NvFuT3vbYmo9A8cQchGo1XVb0qOpzBprNEkkAgiE,14292
14
14
  dsipts/models/DilatedConvED.py,sha256=fXk1-EWiRC5J_VIepTjYKya_D02SlEAkyiJcCjhW_XU,14004
15
15
  dsipts/models/Duet.py,sha256=EharWHT_r7tEYIk7BkozVLPZ0xptE5mmQmeFGm3uBsA,7628
16
16
  dsipts/models/ITransformer.py,sha256=jO8wxLaC06Wgu4GncrFFTISv3pVyfFLLhQvbEOYsz6Y,7368
@@ -27,8 +27,8 @@ dsipts/models/TimeXER.py,sha256=aCg0003LxYZzqZWyWugpbW_iOybcdHN4OH6_v77qp4o,7056
27
27
  dsipts/models/VQVAEA.py,sha256=sNJi8UZh-10qEIKcZK3SzhlOFUUjvqjoglzeZBFaeZM,13789
28
28
  dsipts/models/VVA.py,sha256=BnPkJ0Nzue0oShSHZVRNlf5RvT0Iwtf9bx19vLB9Nn0,11939
29
29
  dsipts/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
30
- dsipts/models/base.py,sha256=uqAjDdAjpnDWBlEeGuy-SZir0K8GjsoyMgxwlT1DQYg,17523
31
- dsipts/models/base_v2.py,sha256=YHrejmxTmICXvLaXiual8j4dztSnWoQevIZWwy9zmfQ,17695
30
+ dsipts/models/base.py,sha256=JWmZ_B56EAWfZOo0vdQrVUP6scLl9yXtHj0F_7hSNKk,18442
31
+ dsipts/models/base_v2.py,sha256=arVlw0STOK9CwU2t-VYost6ZpUf2zKDhTy_hg-HClJY,18741
32
32
  dsipts/models/utils.py,sha256=H1lr1lukDk7FNyXXTJh217tyTBsBW8hVDQ6jL9oev7I,21765
33
33
  dsipts/models/autoformer/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
34
34
  dsipts/models/autoformer/layers.py,sha256=xHt8V1lKdD1cIvgxXdDbI_EqOz4zgOQ6LP8l7M1pAxM,13276
@@ -75,7 +75,7 @@ dsipts/models/vva/minigpt.py,sha256=bg0JddqSD322uxSGexen3nPXL_hGTsk3vNLR62d7-w8,
75
75
  dsipts/models/vva/vqvae.py,sha256=RzCQ_M9xBprp7_x20dSV3EQqlO0FjPUGWV-qdyKrQsM,19680
76
76
  dsipts/models/xlstm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
77
77
  dsipts/models/xlstm/xLSTM.py,sha256=ZKZZmffmIq1Vb71CR4GSyM8viqVx-u0FChxhcNgHub8,10081
78
- dsipts-1.1.5.dist-info/METADATA,sha256=qR-kBKMsp_LN4nGOzRE6piEsaiDaD5WUB8-ASMRWbAQ,1082
79
- dsipts-1.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
80
- dsipts-1.1.5.dist-info/top_level.txt,sha256=i6o0rf5ScFwZK21E89dSKjVNjUBkrEQpn0-Vij43748,7
81
- dsipts-1.1.5.dist-info/RECORD,,
78
+ dsipts-1.1.7.dist-info/METADATA,sha256=dWg1A0BbSkwobE_WaE3Z-Qc6OFvxd8oK2injg0muPiI,24993
79
+ dsipts-1.1.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
80
+ dsipts-1.1.7.dist-info/top_level.txt,sha256=i6o0rf5ScFwZK21E89dSKjVNjUBkrEQpn0-Vij43748,7
81
+ dsipts-1.1.7.dist-info/RECORD,,
@@ -1,31 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: dsipts
3
- Version: 1.1.5
4
- Summary: Unified library for timeseries modelling
5
- Author-email: Andrea Gobbi <agobbi@fbk.eu>
6
- Project-URL: Homepage, https://github.com/DSIP-FBK/DSIPTS
7
- Project-URL: Docs, https://dsip-fbk.github.io/DSIPTS/
8
- Requires-Python: ==3.11.13
9
- Description-Content-Type: text/markdown
10
- Requires-Dist: aim==3.20.1
11
- Requires-Dist: beautifulsoup4==4.12.0
12
- Requires-Dist: einops>=0.8.1
13
- Requires-Dist: html-table-parser-python3==0.3.1
14
- Requires-Dist: html5lib>=1.1
15
- Requires-Dist: hydra-core>=1.3.2
16
- Requires-Dist: hydra-joblib-launcher>=1.2.0
17
- Requires-Dist: hydra-optuna-sweeper>=1.2.0
18
- Requires-Dist: hydra-submitit-launcher>=1.2.0
19
- Requires-Dist: ipykernel>=6.30.1
20
- Requires-Dist: lightning>=2.5.4
21
- Requires-Dist: matplotlib>=3.10.6
22
- Requires-Dist: nbformat>=5.10.4
23
- Requires-Dist: numba>=0.61.2
24
- Requires-Dist: numpy<2.0.0
25
- Requires-Dist: pandas>=2.3.2
26
- Requires-Dist: plotly>=6.3.0
27
- Requires-Dist: scikit-learn>=1.7.1
28
- Requires-Dist: sphinx>=8.2.3
29
- Requires-Dist: sphinx-mdinclude>=0.6.2
30
- Requires-Dist: sphinx-pdj-theme>=0.7.3
31
- Requires-Dist: transformers>=4.56.0
File without changes