Skip to content

[BUG] MultiLoss crashes for multi-target datasets in M-mode due to incorrect target unpacking #2291

@andersendsa

Description

@andersendsa

Description

While testing M-mode (multivariate multiple series) for the TimeXer_pkg_v2 model using the high-level pkg.fit() API, I found that the model crashes during loss evaluation when using multi-target datasets.
Ref Pr : #2284
CC: @phoeenniixx
For multi-target forecasting, the dataloader yields the target as a list of tensors, for example:

[target1, target2]

However, inside LightningMetric.update() (which MultiLoss inherits from), any list or tuple target is assumed to be formatted as:

(target, weight)

This causes the multi-target list to be incorrectly unpacked:

  • target = target1
  • weight = target2

The multi-target list is incorrectly interpreted as (target, weight).

This later triggers:

lengths = torch.full(
    (target.size(0),),
    fill_value=target.size(1),
    dtype=torch.long,
    device=target.device,
)

which crashes with:

IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)

Expected Behavior

The metric logic should correctly distinguish between:

  • a weighted target tuple:
(target, weight)
  • and a multi-target forecasting structure:
[target1, target2, ...]

MultiLoss should properly support multi-target datasets without crashing, allowing high-level APIs such as:

  • pkg.fit()
  • pkg.predict()

to work seamlessly for M-mode forecasting.


Minimal Reproduction

import pandas as pd
import numpy as np

from pytorch_forecasting.data import TimeSeries
from pytorch_forecasting.metrics import MAE, MultiLoss
from pytorch_forecasting.models.timexer._timexer_pkg_v2 import TimeXer_pkg_v2

# 1. Generate a mock multi-target dataset
series_len = 30
time_idx = np.arange(series_len, dtype=np.int64)

df = pd.DataFrame({
    "time_idx": time_idx,
    "group_id": "series_0",
    "target1": np.random.normal(0, 1, series_len).astype(np.float32),
    "target2": np.random.normal(0, 1, series_len).astype(np.float32),
    "temperature": np.random.normal(0, 1, series_len).astype(np.float32),
})

df["group_id"] = df["group_id"].astype("category")

# 2. Build the TimeSeries dataset with multiple targets
dataset = TimeSeries(
    data=df,
    time="time_idx",
    target=["target1", "target2"],  # Multiple targets (M mode)
    group=["group_id"],
    num=["temperature"],
    known=["temperature", "time_idx"],
)

# 3. Setup the package config with MultiLoss
pkg = TimeXer_pkg_v2(
    model_cfg=dict(
        loss=MultiLoss([MAE(), MAE()]),
        hidden_size=64,
        n_heads=2,
        e_layers=1,
        patch_length=4,
    ),
    datamodule_cfg=dict(
        batch_size=2,
        context_length=12,
        prediction_length=8,
    ),
    trainer_cfg=dict(
        fast_dev_run=True,
    )
)

# 4. Trigger the fit (this produces the crash)
pkg.fit(dataset, save_ckpt=False)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions