Agent Conversation: deepseek-reasoner
Model: deepseek-reasoner
Total steps: 9
Messages: 19
UserStep 0
Task: ts-short-term-forecast
Short-Term Time Series Forecasting: Custom Model Design
Objective
Design and implement a custom deep learning model for univariate short-term time series forecasting on the M4 dataset. Your code goes in the Model class in models/Custom.py. Three reference implementations (DLinear, TimesNet, PatchTST) are provided as read-only.
Evaluation
Trained and evaluated on three M4 seasonal patterns:
- Monthly (pred_len=18, seq_len=104)
- Quarterly (pred_len=8, seq_len=52)
- Yearly (pred_len=6, seq_len=42)
All use enc_in=1, features=M, loss=SMAPE. Metric: SMAPE (lower is better).
Time-Series-Library/models/Custom.py [EDITABLE — entire file only]
1: import torch
2: import torch.nn as nn
3:
4:
5: class Model(nn.Module):
6: """
7: Custom model for short-term time series forecasting (M4 dataset).
8:
9: Forward signature: forward(x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None)
10: - x_enc: [batch, seq_len, enc_in] — input time series (enc_in=1 for M4)
11: - x_mark_enc: [batch, seq_len, time_features] — time feature encoding
12: - x_dec: [batch, label_len+pred_len, dec_in] — decoder input
13: - x_mark_dec: [batch, label_len+pred_len, time_features] — decoder time features
14:
15: Must return: [batch, pred_len, c_out] for forecasting
16: """
17:
18: def __init__(self, configs):
19: super(Model, self).__init__()
20: self.task_name = configs.task_name
21: self.seq_len = configs.seq_len
22: self.pred_len = configs.pred_len
23: self.enc_in = configs.enc_in
24: self.c_out = configs.c_out
25: # TODO: Define your model architecture here
26:
27: def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):
28: """
29: Forecasting: given input sequence, predict future values.
30: Input: x_enc [batch, seq_len, 1]
31: Output: [batch, pred_len, 1]
32: """
33: # TODO: Implement your forecasting logic
34: batch_size = x_enc.shape[0]
35: return torch.zeros(batch_size, self.pred_len, self.c_out).to(x_enc.device)
36:
37: def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):
38: if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast':
39: dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec)
40: return dec_out[:, -self.pred_len:, :]
41: return None
Time-Series-Library/models/DLinear.py [READ-ONLY — do not edit]
1: import torch
2: import torch.nn as nn
3: import torch.nn.functional as F
4: from layers.Autoformer_EncDec import series_decomp
5:
6:
7: class Model(nn.Module):
8: """
9: Paper link: https://aAssistantStep 1edit
Tool Input
1{
2 "op": "replace",
3 "filename": "Time-Series-Library/models/Custom.py",
4 "start_line": 1,
5 "end_line": 41,
6 "content": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom layers.Autoformer_EncDec import series_decomp\n\n\nclass Model(nn.Module):\n \"\"\"\n Custom model for short-term time series forecasting (M4 dataset).\n Fourier-enhanced Seasonal-Trend Decomposition (FourierDecomp).\n \n Forward signature: forward(x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None)\n - x_enc: [batch, seq_len, enc_in] — input time series (enc_in=1 for M4)\n - x_mark_enc: [batch, seq_len, time_features] — time feature encoding\n - x_dec: [batch, label_len+pred_len, dec_in] — decoder input\n - x_mark_dec: [batch, label_len+pred_len, time_features] — decoder time features\n\n Must return: [batch, pred_len, c_out] for forecasting\n \"\"\"\n\n def __init__(self, configs):\n super(Model, self).__init__()\n self.task_name = configs.task_name\n self.seq_len = configs.seq_len\n self.pred_len = configs.pred_len\n self.enc_in = configs.enc_in\n self.c_out = configs.c_out\n \n # Series decomposition\n moving_avg = getattr(configs, 'moving_avg', 25)\n self.decomposition = series_decomp(moving_avg)\n \n # Fourier-enhanced seasonal branch\n # Use d_model if available, else default to 64\n self.d_model = getattr(configs, 'd_model', 64)\n # Number of frequency modes to keep\n self.modes = min(getattr(configs, 'modes', 16), self.seq_len // 2)\n \n # Learnable complex weight for frequency domain linear transformation\n self.weights_real = nn.Parameter(torch.randn(self.enc_in, self.modes, dtype=torch.float32) * 0.01)\n self.weights_imag = nn.Parameter(torch.randn(self.enc_in, self.modes, dtype=torch.float32) * 0.01)\n \n # Linear projection for trend\n self.linear_trend = nn.Linear(self.seq_len, self.pred_len)\n # Initialize trend linear weight with mean filter\n self.linear_trend.weight = nn.Parameter((1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len]))\n \n # Output projection to combine seasonal and trend\n self.output_proj = nn.Linear(2 * self.enc_in, self.c_out) if self.enc_in != self.c_out else None\n \n def fourier_seasonal(self, x_seasonal):\n \"\"\"\n x_seasonal: [batch, seq_len, enc_in]\n Apply FFT, learnable frequency weighting, iFFT.\n \"\"\"\n batch, seq_len, enc_in = x_seasonal.shape\n # FFT along time dimension\n x_fft = torch.fft.rfft(x_seasonal, dim=1) # [batch, seq_len//2+1, enc_in]\n # Keep only first modes\n x_fft_modes = x_fft[:, :self.modes, :] # [batch, modes, enc_in]\n \n # Complex multiplication with learned weights (broadcast over batch)\n # weights: [enc_in, modes] -> reshape to [1, modes, enc_in] for element-wise multiply\n weights = torch.complex(self.weights_real, self.weights_imag).T.unsqueeze(0) # [1, modes, enc_in]\n # Multiply each channel independently\n x_fft_weighted = x_fft_modes * weights\n \n # Pad back to original frequency size\n full_freq = x_fft.shape[1]\n x_fft_full = torch.zeros(batch, full_freq, enc_in, dtype=torch.complex64, device=x_seasonal.device)\n x_fft_full[:, :self.modes, :] = x_fft_weighted\n \n # Inverse FFT\n x_seasonal_out = torch.fft.irfft(x_fft_full, n=seq_len, dim=1) # [batch, seq_len, enc_in]\n \n # Project to prediction length via linear (take last pred_len? or linear projection?)\n # We'll use linear projection across time dimension\n x_seasonal_out = x_seasonal_out.permute(0, 2, 1) # [batch, enc_in, seq_len]\n seasonal_proj = self.linear_seasonal(x_seasonal_out) # [batch, enc_in, pred_len]\n seasonal_proj = seasonal_proj.permute(0, 2, 1) # [batch, pred_len, enc_in]\n return seasonal_proj\n \n def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):\n \"\"\"\n Forecasting: given input sequence, predict future values.\n Input: x_enc [batch, seq_len, 1]\n Output: [batch, pred_len, 1]\n \"\"\"\n # Normalization as in Non-stationary Transformer\n means = x_enc.mean(1, keepdim=True).detach()\n x_enc = x_enc - means\n stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5)\n x_enc = x_enc / stdev\n \n # Decompose into seasonal and trend\n seasonal, trend = self.decomposition(x_enc) # each [batch, seq_len, enc_in]\n \n # Trend branch: linear projection\n trend = trend.permute(0, 2, 1) # [batch, enc_in, seq_len]\n trend_out = self.linear_trend(trend) # [batch, enc_in, pred_len]\n trend_out = trend_out.permute(0, 2, 1) # [batch, pred_len, enc_in]\n \n # Seasonal branch: Fourier-enhanced\n seasonal = seasonal.permute(0, 2, 1) # [batch, enc_in, seq_len]\n # We'll use a simple linear projection for seasonal as well (for now)\n seasonal_out = self.linear_seasonal(seasonal) # [batch, enc_in, pred_len]\n seasonal_out = seasonal_out.permute(0, 2, 1)\n \n # Combine seasonal and trend\n combined = seasonal_out + trend_out # [batch, pred_len, enc_in]\n \n # Denormalize\n combined = combined * stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)\n combined = combined + means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)\n \n # Output projection if needed\n if self.output_proj is not None:\n combined = self.output_proj(combined)\n return combined\n \n def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):\n if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast':\n dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec)\n return dec_out[:, -self.pred_len:, :]\n return None"
7}Tool ResultStep 1
OK: Replaced lines 1..41 with 125 line(s) in Time-Series-Library/models/Custom.py. Editable range: entire file.
[Current file: Time-Series-Library/models/Custom.py | editable: 1–125 | total: 125 lines]
1 import torch
2 import torch.nn as nn
3 import torch.nn.functional as F
4 from layers.Autoformer_EncDec import series_decomp
5
6
7 class Model(nn.Module):
8 """
9 Custom model for short-term time series forecasting (M4 dataset).
10 Fourier-enhanced Seasonal-Trend Decomposition (FourierDecomp).
11
12 Forward signature: forward(x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None)
13 - x_enc: [batch, seq_len, enc_in] — input time series (enc_in=1 for M4)
14 - x_mark_enc: [batch, seq_len, time_features] — time feature encoding
15 - x_dec: [batch, label_len+pred_len, dec_in] — decoder input
16 - x_mark_dec: [batch, label_len+pred_len, time_features] — decoder time feat
AssistantStep 2undo
Tool Input
1{
2 "n": 1
3}Tool ResultStep 2
Undo complete: Restored: Time-Series-Library/models/Custom.py
AssistantStep 3edit
Tool Input
1{
2 "op": "replace",
3 "filename": "Time-Series-Library/models/Custom.py",
4 "start_line": 1,
5 "end_line": 41,
6 "content": "import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nfrom layers.Autoformer_EncDec import series_decomp\n\n\nclass FrequencyAttention(nn.Module):\n \"\"\"Frequency attention module for seasonal component.\"\"\"\n def __init__(self, seq_len, pred_len, enc_in, modes=16):\n super(FrequencyAttention, self).__init__()\n self.seq_len = seq_len\n self.pred_len = pred_len\n self.enc_in = enc_in\n self.modes = min(modes, seq_len // 2)\n \n # Attention weights over frequencies\n self.attn = nn.Parameter(torch.ones(enc_in, self.modes) * 0.5)\n # Learnable scaling factor\n self.scale = nn.Parameter(torch.ones(1))\n \n # Linear projection after frequency filtering\n self.linear = nn.Linear(seq_len, pred_len)\n # Initialize linear weight with mean filter\n self.linear.weight = nn.Parameter((1 / seq_len) * torch.ones(pred_len, seq_len))\n \n def forward(self, x):\n # x: [batch, seq_len, enc_in]\n batch, seq_len, enc_in = x.shape\n \n # FFT along time dimension\n x_fft = torch.fft.rfft(x, dim=1) # [batch, seq_len//2+1, enc_in]\n # Keep only first modes\n x_fft_modes = x_fft[:, :self.modes, :] # [batch, modes, enc_in]\n \n # Apply attention weights (softmax over frequencies per channel)\n attn_weights = F.softmax(self.attn.T, dim=0) # [modes, enc_in]\n attn_weights = attn_weights.permute(1, 0).unsqueeze(0) # [1, enc_in, modes]\n # Multiply each channel independently\n x_fft_weighted = x_fft_modes * attn_weights * self.scale\n \n # Pad back to original frequency size\n full_freq = x_fft.shape[1]\n x_fft_full = torch.zeros(batch, full_freq, enc_in, dtype=torch.complex64, device=x.device)\n x_fft_full[:, :self.modes, :] = x_fft_weighted\n \n # Inverse FFT\n x_filtered = torch.fft.irfft(x_fft_full, n=seq_len, dim=1) # [batch, seq_len, enc_in]\n \n # Linear projection to prediction length\n x_filtered = x_filtered.permute(0, 2, 1) # [batch, enc_in, seq_len]\n out = self.linear(x_filtered) # [batch, enc_in, pred_len]\n out = out.permute(0, 2, 1) # [batch, pred_len, enc_in]\n return out\n\n\nclass Model(nn.Module):\n \"\"\"\n Custom model for short-term time series forecasting (M4 dataset).\n Frequency-Attention Decomposition Linear (FADLinear).\n \n Forward signature: forward(x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None)\n - x_enc: [batch, seq_len, enc_in] — input time series (enc_in=1 for M4)\n - x_mark_enc: [batch, seq_len, time_features] — time feature encoding\n - x_dec: [batch, label_len+pred_len, dec_in] — decoder input\n - x_mark_dec: [batch, label_len+pred_len, time_features] — decoder time features\n\n Must return: [batch, pred_len, c_out] for forecasting\n \"\"\"\n\n def __init__(self, configs):\n super(Model, self).__init__()\n self.task_name = configs.task_name\n self.seq_len = configs.seq_len\n self.pred_len = configs.pred_len\n self.enc_in = configs.enc_in\n self.c_out = configs.c_out\n \n # Series decomposition\n moving_avg = getattr(configs, 'moving_avg', 25)\n self.decomposition = series_decomp(moving_avg)\n \n # Frequency attention for seasonal component\n modes = getattr(configs, 'modes', 16)\n self.freq_attn = FrequencyAttention(self.seq_len, self.pred_len, self.enc_in, modes)\n \n # Linear projection for trend component\n self.linear_trend = nn.Linear(self.seq_len, self.pred_len)\n # Initialize trend linear weight with mean filter\n self.linear_trend.weight = nn.Parameter((1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len]))\n \n # Output projection if enc_in != c_out\n if self.enc_in != self.c_out:\n self.output_proj = nn.Linear(self.enc_in, self.c_out)\n else:\n self.output_proj = None\n \n def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):\n \"\"\"\n Forecasting: given input sequence, predict future values.\n Input: x_enc [batch, seq_len, 1]\n Output: [batch, pred_len, 1]\n \"\"\"\n # Normalization as in Non-stationary Transformer\n means = x_enc.mean(1, keepdim=True).detach()\n x_enc = x_enc - means\n stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5)\n x_enc = x_enc / stdev\n \n # Decompose into seasonal and trend\n seasonal, trend = self.decomposition(x_enc) # each [batch, seq_len, enc_in]\n \n # Trend branch: linear projection\n trend = trend.permute(0, 2, 1) # [batch, enc_in, seq_len]\n trend_out = self.linear_trend(trend) # [batch, enc_in, pred_len]\n trend_out = trend_out.permute(0, 2, 1) # [batch, pred_len, enc_in]\n \n # Seasonal branch: frequency attention + linear projection\n seasonal_out = self.freq_attn(seasonal) # [batch, pred_len, enc_in]\n \n # Combine seasonal and trend\n combined = seasonal_out + trend_out # [batch, pred_len, enc_in]\n \n # Denormalize\n combined = combined * stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)\n combined = combined + means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)\n \n # Output projection if needed\n if self.output_proj is not None:\n combined = self.output_proj(combined)\n return combined\n \n def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):\n if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast':\n dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec)\n return dec_out[:, -self.pred_len:, :]\n return None"
7}Tool ResultStep 3
OK: Replaced lines 1..41 with 136 line(s) in Time-Series-Library/models/Custom.py. Editable range: entire file.
[Current file: Time-Series-Library/models/Custom.py | editable: 1–136 | total: 136 lines]
1 import torch
2 import torch.nn as nn
3 import torch.nn.functional as F
4 from layers.Autoformer_EncDec import series_decomp
5
6
7 class FrequencyAttention(nn.Module):
8 """Frequency attention module for seasonal component."""
9 def __init__(self, seq_len, pred_len, enc_in, modes=16):
10 super(FrequencyAttention, self).__init__()
11 self.seq_len = seq_len
12 self.pred_len = pred_len
13 self.enc_in = enc_in
14 self.modes = min(modes, seq_len // 2)
15
16 # Attention weights over frequencies
17 self.attn = nn.Parameter(torch.ones(enc_in, self.modes) * 0.5)
18 # Learnable scaling factor
19 self.sca
AssistantStep 4test
Tool ResultStep 4
[Test #1] (2 tests remaining; call submit(n=1) to submit this result) ### m4_monthly (scripts/m4_monthly.sh) WARNING: Overriding HOME environment variable with APPTAINERENV_HOME is not permitted Using GPU Args in experiment: [1mBasic Config[0m Task Name: short_term_forecast Is Training: 1 Model ID: m4_Monthly Model: Custom [1mData Loader[0m Data: m4 Root Path: /data/m4 Data Path: ETTh1.csv Features: M Target: OT Freq: h Checkpoints: ./checkpoints/ [1mForecasting Task[0m Seq Len: 96 Label Len: 48 Pred Len: 96 Seasonal Patterns: Monthly Inverse: 0 [1mModel Parameters[0m Top k:
AssistantStep 5edit
Tool Input
1{
2 "op": "replace",
3 "filename": "Time-Series-Library/models/Custom.py",
4 "start_line": 7,
5 "end_line": 53,
6 "content": "class FrequencyAttention(nn.Module):\n \"\"\"Frequency attention module for seasonal component.\"\"\"\n def __init__(self, seq_len, pred_len, enc_in, modes=16):\n super(FrequencyAttention, self).__init__()\n self.seq_len = seq_len\n self.pred_len = pred_len\n self.enc_in = enc_in\n self.modes = min(modes, seq_len // 2 + 1)\n \n # Attention weights over frequencies per channel\n self.attn = nn.Parameter(torch.ones(enc_in, self.modes) * 0.5)\n # Learnable scaling factor\n self.scale = nn.Parameter(torch.ones(1))\n \n # Linear projection after frequency filtering\n self.linear = nn.Linear(seq_len, pred_len)\n # Initialize linear weight with mean filter\n self.linear.weight = nn.Parameter((1 / seq_len) * torch.ones(pred_len, seq_len))\n \n def forward(self, x):\n # x: [batch, seq_len, enc_in]\n batch, seq_len, enc_in = x.shape\n \n # FFT along time dimension\n x_fft = torch.fft.rfft(x, dim=1) # [batch, seq_len//2+1, enc_in]\n # Keep only first modes\n x_fft_modes = x_fft[:, :self.modes, :] # [batch, modes, enc_in]\n \n # Apply attention weights (softmax over frequencies per channel)\n attn_weights = F.softmax(self.attn, dim=1) # [enc_in, modes]\n # Reshape to [1, modes, enc_in] for element-wise multiplication\n attn_weights = attn_weights.T.unsqueeze(0) # [1, modes, enc_in]\n # Multiply each channel independently\n x_fft_weighted = x_fft_modes * attn_weights * self.scale\n \n # Pad back to original frequency size\n full_freq = x_fft.shape[1]\n x_fft_full = torch.zeros(batch, full_freq, enc_in, dtype=torch.complex64, device=x_fft.device)\n x_fft_full[:, :self.modes, :] = x_fft_weighted\n \n # Inverse FFT\n x_filtered = torch.fft.irfft(x_fft_full, n=seq_len, dim=1) # [batch, seq_len, enc_in]\n \n # Linear projection to prediction length\n x_filtered = x_filtered.permute(0, 2, 1) # [batch, enc_in, seq_len]\n out = self.linear(x_filtered) # [batch, enc_in, pred_len]\n out = out.permute(0, 2, 1) # [batch, pred_len, enc_in]\n return out"
7}Tool ResultStep 5
OK: Replaced lines 7..53 with 48 line(s) in Time-Series-Library/models/Custom.py. Editable range: entire file.
[Current file: Time-Series-Library/models/Custom.py | editable: 1–137 | total: 137 lines]
1 import torch
2 import torch.nn as nn
3 import torch.nn.functional as F
4 from layers.Autoformer_EncDec import series_decomp
5
6
7 class FrequencyAttention(nn.Module):
8 """Frequency attention module for seasonal component."""
9 def __init__(self, seq_len, pred_len, enc_in, modes=16):
10 super(FrequencyAttention, self).__init__()
11 self.seq_len = seq_len
12 self.pred_len = pred_len
13 self.enc_in = enc_in
14 self.modes = min(modes, seq_len // 2 + 1)
15
16 # Attention weights over frequencies per channel
17 self.attn = nn.Parameter(torch.ones(enc_in, self.modes) * 0.5)
18 # Learnable scaling factor
19
AssistantStep 6test
Tool ResultStep 6
[Test #2] (1 test remaining; call submit(n=2) to submit this result) ### m4_monthly (scripts/m4_monthly.sh) Training metrics (last epochs): TRAIN_METRICS epoch=4 train_loss=8.2196904 vali_loss=13.4391621 TRAIN_METRICS epoch=5 train_loss=8.2055787 vali_loss=13.4126602 TRAIN_METRICS epoch=6 train_loss=8.1173953 vali_loss=13.4305203 TRAIN_METRICS epoch=7 train_loss=8.1858310 vali_loss=13.4262590 TRAIN_METRICS epoch=8 train_loss=8.1305757 vali_loss=13.4202608 Test results (m4_monthly): SMAPE: 13.4127, MAPE: 13.4127, MAPE: 0.1626 ### m4_quarterly (scripts/m4_quarterly.sh) Training metrics (last epochs): TRAIN_METRICS epoch=6 train_loss=7.4147341 vali_loss=10.7753912 TRAIN_METRICS epoch=7 train_loss=7.4751258 vali_loss=10.7681496 TRAIN_METRICS epoch=8 train_loss=7.3837579 vali_loss=10.7661894 TRAIN_METRICS epoch=9 train_loss=7.4936009 vali_loss=10.7658503 TRAIN_METRICS epoch=10 train_loss=7.4199415 vali_loss=10.7657510 Test results (m4_quarterly): SMAPE: 10.7658, MAPE: 10.7658, MAPE: 0
AssistantStep 7edit
Tool Input
1{
2 "op": "replace",
3 "filename": "Time-Series-Library/models/Custom.py",
4 "start_line": 57,
5 "end_line": 137,
6 "content": "class Model(nn.Module):\n \"\"\"\n Custom model for short-term time series forecasting (M4 dataset).\n Multi-Scale Decomposition with Frequency Attention (MSDFA).\n \n Forward signature: forward(x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None)\n - x_enc: [batch, seq_len, enc_in] — input time series (enc_in=1 for M4)\n - x_mark_enc: [batch, seq_len, time_features] — time feature encoding\n - x_dec: [batch, label_len+pred_len, dec_in] — decoder input\n - x_mark_dec: [batch, label_len+pred_len, time_features] — decoder time features\n\n Must return: [batch, pred_len, c_out] for forecasting\n \"\"\"\n\n def __init__(self, configs):\n super(Model, self).__init__()\n self.task_name = configs.task_name\n self.seq_len = configs.seq_len\n self.pred_len = configs.pred_len\n self.enc_in = configs.enc_in\n self.c_out = configs.c_out\n \n # Multi-scale series decomposition\n kernel_sizes = getattr(configs, 'kernel_sizes', [3, 5, 7])\n self.decomposition = series_decomp_multi(kernel_sizes)\n self.num_scales = len(kernel_sizes)\n \n # Frequency attention for seasonal components per scale\n modes = getattr(configs, 'modes', 16)\n self.freq_attns = nn.ModuleList([\n FrequencyAttention(self.seq_len, self.pred_len, self.enc_in, modes)\n for _ in range(self.num_scales)\n ])\n \n # Linear projection for trend components per scale\n self.linear_trends = nn.ModuleList([\n nn.Linear(self.seq_len, self.pred_len)\n for _ in range(self.num_scales)\n ])\n # Initialize trend linear weights with mean filter\n for linear in self.linear_trends:\n linear.weight = nn.Parameter((1 / self.seq_len) * torch.ones([self.pred_len, self.seq_len]))\n \n # Learnable weights for combining scales\n self.scale_weights_seasonal = nn.Parameter(torch.ones(self.num_scales) / self.num_scales)\n self.scale_weights_trend = nn.Parameter(torch.ones(self.num_scales) / self.num_scales)\n \n # Output projection if enc_in != c_out\n if self.enc_in != self.c_out:\n self.output_proj = nn.Linear(self.enc_in, self.c_out)\n else:\n self.output_proj = None\n \n def forecast(self, x_enc, x_mark_enc, x_dec, x_mark_dec):\n \"\"\"\n Forecasting: given input sequence, predict future values.\n Input: x_enc [batch, seq_len, 1]\n Output: [batch, pred_len, 1]\n \"\"\"\n # Normalization as in Non-stationary Transformer\n means = x_enc.mean(1, keepdim=True).detach()\n x_enc = x_enc - means\n stdev = torch.sqrt(torch.var(x_enc, dim=1, keepdim=True, unbiased=False) + 1e-5)\n x_enc = x_enc / stdev\n \n # Decompose into seasonal and trend (multi-scale)\n seasonal_list, trend_list = self.decomposition(x_enc) # each list of length num_scales\n \n # Process each scale\n seasonal_outs = []\n trend_outs = []\n for i in range(self.num_scales):\n # Seasonal branch: frequency attention + linear projection\n seasonal_i = seasonal_list[i] # [batch, seq_len, enc_in]\n seasonal_out_i = self.freq_attns[i](seasonal_i) # [batch, pred_len, enc_in]\n seasonal_outs.append(seasonal_out_i)\n \n # Trend branch: linear projection\n trend_i = trend_list[i].permute(0, 2, 1) # [batch, enc_in, seq_len]\n trend_out_i = self.linear_trends[i](trend_i) # [batch, enc_in, pred_len]\n trend_out_i = trend_out_i.permute(0, 2, 1) # [batch, pred_len, enc_in]\n trend_outs.append(trend_out_i)\n \n # Combine scales with learned weights\n scale_weights_seasonal = F.softmax(self.scale_weights_seasonal, dim=0)\n scale_weights_trend = F.softmax(self.scale_weights_trend, dim=0)\n \n seasonal_out = torch.zeros_like(seasonal_outs[0])\n trend_out = torch.zeros_like(trend_outs[0])\n for i in range(self.num_scales):\n seasonal_out += scale_weights_seasonal[i] * seasonal_outs[i]\n trend_out += scale_weights_trend[i] * trend_outs[i]\n \n # Combine seasonal and trend\n combined = seasonal_out + trend_out # [batch, pred_len, enc_in]\n \n # Denormalize\n combined = combined * stdev[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)\n combined = combined + means[:, 0, :].unsqueeze(1).repeat(1, self.pred_len, 1)\n \n # Output projection if needed\n if self.output_proj is not None:\n combined = self.output_proj(combined)\n return combined\n \n def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):\n if self.task_name == 'long_term_forecast' or self.task_name == 'short_term_forecast':\n dec_out = self.forecast(x_enc, x_mark_enc, x_dec, x_mark_dec)\n return dec_out[:, -self.pred_len:, :]\n return None"
7}Tool ResultStep 7
OK: Replaced lines 57..137 with 110 line(s) in Time-Series-Library/models/Custom.py. Editable range: entire file.
[Current file: Time-Series-Library/models/Custom.py | editable: 1–166 | total: 166 lines]
1 import torch
2 import torch.nn as nn
3 import torch.nn.functional as F
4 from layers.Autoformer_EncDec import series_decomp
5
6
7 class FrequencyAttention(nn.Module):
8 """Frequency attention module for seasonal component."""
9 def __init__(self, seq_len, pred_len, enc_in, modes=16):
10 super(FrequencyAttention, self).__init__()
11 self.seq_len = seq_len
12 self.pred_len = pred_len
13 self.enc_in = enc_in
14 self.modes = min(modes, seq_len // 2 + 1)
15
16 # Attention weights over frequencies per channel
17 self.attn = nn.Parameter(torch.ones(enc_in, self.modes) * 0.5)
18 # Learnable scaling factor
19
AssistantStep 8edit
Tool Input
1{
2 "op": "replace",
3 "filename": "Time-Series-Library/models/Custom.py",
4 "start_line": 4,
5 "end_line": 4,
6 "content": "from layers.Autoformer_EncDec import series_decomp, series_decomp_multi"
7}Tool ResultStep 8
OK: Replaced lines 4..4 with 1 line(s) in Time-Series-Library/models/Custom.py. Editable range: entire file.
[Current file: Time-Series-Library/models/Custom.py | editable: 1–166 | total: 166 lines]
1 import torch
2 import torch.nn as nn
3 import torch.nn.functional as F
4 from layers.Autoformer_EncDec import series_decomp, series_decomp_multi
5
6
7 class FrequencyAttention(nn.Module):
8 """Frequency attention module for seasonal component."""
9 def __init__(self, seq_len, pred_len, enc_in, modes=16):
10 super(FrequencyAttention, self).__init__()
11 self.seq_len = seq_len
12 self.pred_len = pred_len
13 self.enc_in = enc_in
14 self.modes = min(modes, seq_len // 2 + 1)
15
16 # Attention weights over frequencies per channel
17 self.attn = nn.Parameter(torch.ones(enc_in, self.modes) * 0.5)
18 # Learnable scali
AssistantStep 9test
Tool ResultStep 9
[Test #3] (0 tests remaining) ### m4_monthly (scripts/m4_monthly.sh) WARNING: Overriding HOME environment variable with APPTAINERENV_HOME is not permitted Using GPU Args in experiment: [1mBasic Config[0m Task Name: short_term_forecast Is Training: 1 Model ID: m4_Monthly Model: Custom [1mData Loader[0m Data: m4 Root Path: /data/m4 Data Path: ETTh1.csv Features: M Target: OT Freq: h Checkpoints: ./checkpoints/ [1mForecasting Task[0m Seq Len: 96 Label Len: 48 Pred Len: 96 Seasonal Patterns: Monthly Inverse: 0 [1mModel Parameters[0m Top k: 5 Num Kernels