You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Darts中实现含静态协变量的Lorenz系统ODE自定义损失函数

Darts TFT模型结合Lorenz ODE残差损失的混沌序列预测解决方案

问题背景

你当前用Darts的TFT模型预测3D Lorenz混沌时间序列,训练数据是分组合成的200组模拟数据,每组包含固定的静态协变量sigma、rho、beta,数据加载代码如下:

train_series = TimeSeries.from_group_dataframe(training_df, 
                                group_cols = 'simNum',
                                time_col = 'time_idx',
                                value_cols = ['x','y','z'],
                                static_cols = ['sigma','rho','beta'])

所有数值列已做Scaler缩放,time_idx为每组独立重置的时间整数。目标是将Lorenz系统的3个ODE作为残差损失,与MSE数据损失结合训练模型,但遇到核心问题:

  • 不知道如何在配点(训练时间步)生成模型预测值用于ODE残差计算
  • 不清楚如何将每组的静态协变量融入ODE损失的计算逻辑
  • 纠结是否需要随机生成sigma/rho/beta来整合预测与ODE计算

核心解决方案

1. 配点预测的获取:直接利用模型forward输出

不需要额外调用model.predict,在训练循环中,TFT的LightningModule会接收batch输入,直接拿到模型对当前输入序列的预测值(配点输出)。重写TFT的training_step方法即可实现:

from darts.models import TFTModel
import torch

class ODEIntegratedTFT(TFTModel):
    def __init__(self, *args, ode_loss_weight=0.1, **kwargs):
        super().__init__(*args, **kwargs)
        self.ode_loss_weight = ode_loss_weight
        self.mse_loss = torch.nn.MSELoss()

    def lorenz_ode(self, x, y, z, sigma, rho, beta):
        # 适配缩放后数据的Lorenz ODE实现
        dx_dt = sigma * (y - x)
        dy_dt = x * (rho - z) - y
        dz_dt = x * y - beta * z
        return dx_dt, dy_dt, dz_dt

    def training_step(self, batch, batch_idx):
        # 提取batch中的输入与目标序列
        x, y = batch
        # 获取模型对输入序列的配点预测
        pred = self(x)
        # 计算数据损失:预测值与目标的MSE
        data_loss = self.mse_loss(pred, y)

        # 提取当前batch的静态协变量:每组的sigma/rho/beta
        static_covs = x['static_covariates']
        sigma = static_covs[:, 0]
        rho = static_covs[:, 1]
        beta = static_covs[:, 2]

        # 从预测值中拆分x/y/z分量,用差分近似连续导数(适配离散时间序列)
        pred_x = pred[:, :, 0].squeeze()
        pred_y = pred[:, :, 1].squeeze()
        pred_z = pred[:, :, 2].squeeze()
        # 用后向差分近似导数(步长对应time_idx的间隔)
        dx_dt_pred = torch.diff(pred_x, dim=1)
        dy_dt_pred = torch.diff(pred_y, dim=1)
        dz_dt_pred = torch.diff(pred_z, dim=1)

        # 用ODE计算理论导数(对应差分后的时间步)
        dx_dt_ode, dy_dt_ode, dz_dt_ode = self.lorenz_ode(
            pred_x[:, :-1], pred_y[:, :-1], pred_z[:, :-1], sigma, rho, beta
        )

        # 计算ODE残差损失
        ode_loss = self.mse_loss(
            torch.stack([dx_dt_pred, dy_dt_pred, dz_dt_pred], dim=-1),
            torch.stack([dx_dt_ode, dy_dt_ode, dz_dt_ode], dim=-1)
        )

        # 加权合并总损失
        total_loss = data_loss + self.ode_loss_weight * ode_loss

        # 记录训练日志
        self.log("train_data_loss", data_loss)
        self.log("train_ode_loss", ode_loss)
        self.log("train_total_loss", total_loss)
        return total_loss

2. 静态协变量的融入:直接从batch提取,无需随机生成

训练数据中每组的sigma/rho/beta是已知的静态协变量,Darts加载分组数据时已将这些信息绑定到样本中。在训练循环的batch里,静态协变量会作为输入的一部分传递给模型,直接从x['static_covariates']提取即可用于ODE计算,完全不需要随机生成参数——随机生成仅适用于无监督参数估计场景,你这里训练数据的参数是已知的,应该用真实值约束模型。

3. 损失函数的整合:在training_step中加权结合

不要直接定义loss_fn = MSELoss() + odeLoss(),这种方式无法传递静态协变量和配点预测的上下文。正确方式是在training_step中分别计算两种损失,再根据需求加权求和,可灵活调整权重避免某一种损失主导训练。

注意事项

  • 确保Lorenz ODE实现与数据缩放后的数值范围匹配,必要时对ODE输出做反向缩放
  • 导数近似方式可根据时间步长调整,比如用中心差分或数值积分提升精度
  • 若需在验证阶段加入ODE损失,只需重写validation_step方法,逻辑与training_step一致

内容的提问来源于stack exchange,提问作者Farooq Zahid

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:07:19