patchfm 2.2.2__tar.gz → 2.2.5__tar.gz
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.
- {patchfm-2.2.2/src/patchfm.egg-info → patchfm-2.2.5}/PKG-INFO +1 -1
- {patchfm-2.2.2 → patchfm-2.2.5}/pyproject.toml +1 -1
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm/configs/model_config.py +1 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm/inference/forecaster.py +32 -20
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm/inference/modules.py +18 -8
- {patchfm-2.2.2 → patchfm-2.2.5/src/patchfm.egg-info}/PKG-INFO +1 -1
- {patchfm-2.2.2 → patchfm-2.2.5}/LICENSE +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/README.md +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/setup.cfg +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm/__init__.py +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm.egg-info/SOURCES.txt +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm.egg-info/dependency_links.txt +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm.egg-info/requires.txt +0 -0
- {patchfm-2.2.2 → patchfm-2.2.5}/src/patchfm.egg-info/top_level.txt +0 -0
|
@@ -18,12 +18,18 @@ class Forecaster(nn.Module):
|
|
|
18
18
|
self.d_model = config["d_model"]
|
|
19
19
|
self.n_heads = config["n_heads"]
|
|
20
20
|
self.n_layers_encoder = config["n_layers_encoder"]
|
|
21
|
+
self.use_xsa = config["use_xsa"]
|
|
21
22
|
self.quantiles = config["quantiles"]
|
|
22
23
|
self.n_quantiles = len(self.quantiles)
|
|
23
24
|
self.max_patches = self.max_seq_len // self.patch_len
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
26
|
+
if not self.use_xsa:
|
|
27
|
+
print("Loading base model from HuggingFace Hub...")
|
|
28
|
+
base_model = PatchFM.from_pretrained("vilhess/PatchFM")
|
|
29
|
+
else:
|
|
30
|
+
print("Loading XSA model from HuggingFace Hub...")
|
|
31
|
+
base_model = PatchFM.from_pretrained("vilhess/PatchFM-XSA")
|
|
32
|
+
|
|
27
33
|
self._init_from_base(base_model)
|
|
28
34
|
|
|
29
35
|
self.eval()
|
|
@@ -46,7 +52,8 @@ class Forecaster(nn.Module):
|
|
|
46
52
|
self.transformer_encoder = TransformerEncoder(
|
|
47
53
|
d_model=self.d_model,
|
|
48
54
|
n_heads=self.n_heads,
|
|
49
|
-
n_layers=self.n_layers_encoder
|
|
55
|
+
n_layers=self.n_layers_encoder,
|
|
56
|
+
use_xsa=self.use_xsa
|
|
50
57
|
)
|
|
51
58
|
self.proj_output = ResidualBlock(
|
|
52
59
|
in_dim=self.d_model,
|
|
@@ -69,15 +76,7 @@ class Forecaster(nn.Module):
|
|
|
69
76
|
# Default horizon = patch_len
|
|
70
77
|
forecast_horizon = forecast_horizon or self.patch_len
|
|
71
78
|
|
|
72
|
-
x = self.converter.convert(x)
|
|
73
|
-
assert x.ndim in (1, 2), f"Input dimension must be 1D (time) or 2D (batch, time), got {x.ndim}D."
|
|
74
|
-
|
|
75
|
-
batch_dim=True
|
|
76
|
-
if x.ndim != 2:
|
|
77
|
-
x = x.unsqueeze(0)
|
|
78
|
-
batch_dim=False
|
|
79
79
|
bs, ws = x.size()
|
|
80
|
-
|
|
81
80
|
x = x.to(self.device)
|
|
82
81
|
|
|
83
82
|
if ws > self.max_seq_len:
|
|
@@ -153,26 +152,39 @@ class Forecaster(nn.Module):
|
|
|
153
152
|
pred_median = torch.zeros_like(pred_median)
|
|
154
153
|
pred_quantiles = torch.zeros_like(pred_quantiles)
|
|
155
154
|
|
|
156
|
-
if not batch_dim:
|
|
157
|
-
pred_median = pred_median.squeeze(0)
|
|
158
|
-
pred_quantiles = pred_quantiles.squeeze(0)
|
|
159
|
-
|
|
160
|
-
pred_median, pred_quantiles = self.converter.deconvert(pred_median, pred_quantiles)
|
|
161
155
|
return pred_median, pred_quantiles
|
|
162
156
|
|
|
163
157
|
def __call__(self, context: torch.Tensor, forecast_horizon: int | None = None, quantiles: list[float] | None = None, flip_equivariance: bool = False) -> torch.Tensor:
|
|
158
|
+
|
|
159
|
+
x = self.converter.convert(context)
|
|
160
|
+
assert x.ndim in (1, 2), f"Input dimension must be 1D (time) or 2D (batch, time), got {x.ndim}D."
|
|
161
|
+
|
|
162
|
+
batch_dim=True
|
|
163
|
+
if x.ndim != 2:
|
|
164
|
+
x = x.unsqueeze(0)
|
|
165
|
+
batch_dim=False
|
|
166
|
+
|
|
167
|
+
bs, ws = x.size()
|
|
168
|
+
|
|
164
169
|
if flip_equivariance:
|
|
165
170
|
print("Flip equivariance enabled: forecast = (f(x) - f(-x)) / 2. This requires multiplying by 2 the batch size (Reverso: Efficient Time Series Foundation Models for Zero-shot Forecasting).")
|
|
166
171
|
bs = context.size(0)
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
pred_median_full, pred_quantiles_full = self.auto_regressive_quantile_decoding(
|
|
172
|
+
x_flipped = -x
|
|
173
|
+
concat_x = torch.cat([x, x_flipped], dim=0)
|
|
174
|
+
pred_median_full, pred_quantiles_full = self.auto_regressive_quantile_decoding(concat_x, forecast_horizon, quantiles)
|
|
170
175
|
pred_median, pred_quantiles = pred_median_full[:bs], pred_quantiles_full[:bs]
|
|
171
176
|
pred_median2, pred_quantiles2 = pred_median_full[bs:], pred_quantiles_full[bs:]
|
|
172
177
|
pred_median = (pred_median - pred_median2) / 2
|
|
173
178
|
pred_quantiles = (pred_quantiles - flip_last_dim(pred_quantiles2)) / 2
|
|
174
179
|
else:
|
|
175
|
-
pred_median, pred_quantiles = self.auto_regressive_quantile_decoding(
|
|
180
|
+
pred_median, pred_quantiles = self.auto_regressive_quantile_decoding(x, forecast_horizon, quantiles)
|
|
181
|
+
|
|
182
|
+
if not batch_dim:
|
|
183
|
+
pred_median = pred_median.squeeze(0)
|
|
184
|
+
pred_quantiles = pred_quantiles.squeeze(0)
|
|
185
|
+
|
|
186
|
+
pred_median, pred_quantiles = self.converter.deconvert(pred_median, pred_quantiles)
|
|
187
|
+
|
|
176
188
|
return pred_median, pred_quantiles
|
|
177
189
|
|
|
178
190
|
def clear_cache(self):
|
|
@@ -185,7 +185,7 @@ class ResidualBlock(nn.Module):
|
|
|
185
185
|
return out
|
|
186
186
|
|
|
187
187
|
class MultiHeadAttention(nn.Module):
|
|
188
|
-
def __init__(self, d_model, n_heads, last=False):
|
|
188
|
+
def __init__(self, d_model, n_heads, last=False, use_xsa=False):
|
|
189
189
|
super().__init__()
|
|
190
190
|
assert d_model%n_heads==0, f"d_model ({d_model}) must be divisible by n_heads ({n_heads})"
|
|
191
191
|
|
|
@@ -204,7 +204,8 @@ class MultiHeadAttention(nn.Module):
|
|
|
204
204
|
self.v_cache = None
|
|
205
205
|
|
|
206
206
|
self.last = last
|
|
207
|
-
|
|
207
|
+
self.use_xsa = use_xsa
|
|
208
|
+
|
|
208
209
|
def forward(self, q):
|
|
209
210
|
bs, context, dim = q.size()
|
|
210
211
|
offset = 0
|
|
@@ -239,6 +240,13 @@ class MultiHeadAttention(nn.Module):
|
|
|
239
240
|
|
|
240
241
|
values = nn.functional.scaled_dot_product_attention(q, k, v, is_causal=is_causal)
|
|
241
242
|
|
|
243
|
+
if self.use_xsa:
|
|
244
|
+
if v.size(2) != values.size(2):
|
|
245
|
+
v = v[:, :, -values.size(2) :, :]
|
|
246
|
+
|
|
247
|
+
vn = torch.nn.functional.normalize(v, dim=-1)
|
|
248
|
+
values = values - (values * vn).sum(dim=-1, keepdim=True) * vn
|
|
249
|
+
|
|
242
250
|
values = values.transpose(1, 2).reshape(bs, -1, dim)
|
|
243
251
|
values = self.out_proj(values)
|
|
244
252
|
return values
|
|
@@ -267,10 +275,10 @@ class FeedForward(nn.Module):
|
|
|
267
275
|
|
|
268
276
|
|
|
269
277
|
class TransformerEncoderLayer(nn.Module):
|
|
270
|
-
def __init__(self, d_model, n_heads, last=False):
|
|
278
|
+
def __init__(self, d_model, n_heads, last=False, use_xsa=False):
|
|
271
279
|
super().__init__()
|
|
272
280
|
self.ln1 = nn.LayerNorm(d_model)
|
|
273
|
-
self.attn = MultiHeadAttention(d_model=d_model, n_heads=n_heads, last=last)
|
|
281
|
+
self.attn = MultiHeadAttention(d_model=d_model, n_heads=n_heads, last=last, use_xsa=use_xsa)
|
|
274
282
|
self.ln2 = nn.LayerNorm(d_model)
|
|
275
283
|
self.ff = FeedForward(d_model=d_model)
|
|
276
284
|
|
|
@@ -281,15 +289,15 @@ class TransformerEncoderLayer(nn.Module):
|
|
|
281
289
|
return out
|
|
282
290
|
|
|
283
291
|
class TransformerEncoder(nn.Module):
|
|
284
|
-
def __init__(self, d_model, n_heads, n_layers):
|
|
292
|
+
def __init__(self, d_model, n_heads, n_layers, use_xsa=False):
|
|
285
293
|
super().__init__()
|
|
286
294
|
self.layers = nn.ModuleList(
|
|
287
295
|
[
|
|
288
|
-
TransformerEncoderLayer(d_model=d_model, n_heads=n_heads)
|
|
296
|
+
TransformerEncoderLayer(d_model=d_model, n_heads=n_heads, use_xsa=use_xsa)
|
|
289
297
|
for _ in range(n_layers-1)
|
|
290
298
|
]
|
|
291
299
|
)
|
|
292
|
-
self.layers.append(TransformerEncoderLayer(d_model=d_model, n_heads=n_heads, last=True))
|
|
300
|
+
self.layers.append(TransformerEncoderLayer(d_model=d_model, n_heads=n_heads, last=True, use_xsa=use_xsa))
|
|
293
301
|
self.norm = nn.LayerNorm(d_model)
|
|
294
302
|
|
|
295
303
|
def forward(self, x):
|
|
@@ -306,6 +314,7 @@ class PatchFM(nn.Module, PyTorchModelHubMixin):
|
|
|
306
314
|
self.d_model = config["d_model"]
|
|
307
315
|
self.n_heads = config["n_heads"]
|
|
308
316
|
self.n_layers_encoder = config["n_layers_encoder"]
|
|
317
|
+
self.use_xsa = config["use_xsa"]
|
|
309
318
|
self.quantiles = config["quantiles"]
|
|
310
319
|
self.n_quantiles = len(self.quantiles)
|
|
311
320
|
|
|
@@ -319,7 +328,8 @@ class PatchFM(nn.Module, PyTorchModelHubMixin):
|
|
|
319
328
|
self.transformer_encoder = TransformerEncoder(
|
|
320
329
|
d_model=self.d_model,
|
|
321
330
|
n_heads=self.n_heads,
|
|
322
|
-
n_layers=self.n_layers_encoder
|
|
331
|
+
n_layers=self.n_layers_encoder,
|
|
332
|
+
use_xsa=self.use_xsa
|
|
323
333
|
)
|
|
324
334
|
self.proj_output = ResidualBlock(
|
|
325
335
|
in_dim=self.d_model,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|