Skip to content

Level3 forward 主链

Abstract

这一篇对应 00-DLinear总览与Level树Level 3

它只讲一件事:

进入 DLinear.forward(...) 以后,forecasting 任务到底走哪条分支,以及 encoder(...) 在这里到底扮演什么角色。

1. 当前层第一性

这一层存在的第一性是:

先确定 forecasting 任务里,forward(...) 真实走的是哪条分支,并钉死 DLinear 里的 encoder(...) 不是 Transformer encoder,而是“分解 + 两路线性预测”的主体函数。

用户最容易误解的地方就在这里:

  • 名字叫 encoder
  • 但它并不是注意力 encoder
  • 它实际上就是 DLinear 的主运算体

2. 上下文

父节点:

下一层:

当前入口接口:

python
DLinear.forward(x_enc, x_mark_enc, x_dec, x_mark_dec)

当前出口接口:

python
forecast(x_enc)
-> encoder(x_enc)
-> output.shape = (B, pred_len, C)

3. 顺序图

4. 抽象树

5. forward(...) 完整代码

位置:

python
def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):
    if (
        self.task_name == "long_term_forecast"
        or self.task_name == "short_term_forecast"
    ):
        dec_out = self.forecast(x_enc)
        return dec_out[:, -self.pred_len :, :]
    if self.task_name == "imputation":
        dec_out = self.imputation(x_enc)
        return dec_out
    if self.task_name == "anomaly_detection":
        dec_out = self.anomaly_detection(x_enc)
        return dec_out
    if self.task_name == "classification":
        dec_out = self.classification(x_enc)
        return dec_out
    return None

6. 中文注释版完整代码

python
def forward(self, x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None):
    # forecasting 任务:真正走 forecast(x_enc)
    if (
        self.task_name == "long_term_forecast"
        or self.task_name == "short_term_forecast"
    ):
        dec_out = self.forecast(x_enc)
        # 只保留最后 pred_len 段作为预测输出
        return dec_out[:, -self.pred_len :, :]

    if self.task_name == "imputation":
        dec_out = self.imputation(x_enc)
        return dec_out

    if self.task_name == "anomaly_detection":
        dec_out = self.anomaly_detection(x_enc)
        return dec_out

    if self.task_name == "classification":
        dec_out = self.classification(x_enc)
        return dec_out

    return None

7. 代码块 1:任务分支判断

7.1 输入/输出语义

输入:

  • task_name
    • 当前任务类型。

输出:

  • 决定走哪一条模型内部路径。

当前真实例子里:

  • task_name = short_term_forecast

所以一定走:

python
dec_out = self.forecast(x_enc)
return dec_out[:, -self.pred_len :, :]

这一段在总体里的作用:

先把 forecasting 任务和其他任务分开。DLinear 不同任务会共享部分代码壳,但当前例子只关心 forecasting。

8. 代码块 2:forecast(x_enc)

代码:

python
def forecast(self, x_enc):
    return self.encoder(x_enc)

8.1 输入/输出语义

输入:

  • x_enc
    • 历史数值窗口,形状 (B, seq_len, C)

输出:

  • dec_out
    • 未来预测窗口,形状 (B, pred_len, C)

8.2 这里最该固定的认识

这里没有 decoder、没有 attention、没有复杂桥接。

forecast(...) 的语义非常直接:

把历史窗口 x_enc 直接送进 DLinear 的主体函数 encoder(...),得到未来预测。

9. 代码块 3:为什么名字叫 encoder

这是用户最容易困惑的点。

在 DLinear 里:

python
def encoder(self, x):
    ...

这个名字容易让人误以为:

  • 它像 Informer 一样是一个注意力 encoder
  • 只是整个模型的一部分

但在当前 forecasting 主链里,它其实承担的是:

DLinear 的核心运算主体。

也就是:

  • 输入原始历史序列 x_enc
  • 先分解 seasonal / trend
  • 再各自线性预测到未来 pred_len
  • 最后相加返回

所以这里更准确的脑内翻译应该是:

text
encoder(x)

DLinear 的主运算体

10. toy 例子贴代码讲解

固定 toy 参数(与所有文档对齐):

  • B = 2
  • seq_len = 6
  • pred_len = 2
  • enc_in = 3
text
x_enc.shape = (2, 6, 3)

10.1 代码块 1:进入 forecasting 分支

python
dec_out = self.forecast(x_enc)
  • 入口:(2, 6, 3) — 2 个 batch,每个 6 步历史,3 个变量
  • 出口:(2, 2, 3) — 每个 batch 预测 2 步

10.2 代码块 2:最终返回

python
return dec_out[:, -self.pred_len :, :]

forecast(x_enc)encoder(...) 已经直接输出 (B, pred_len, C),所以这里的 [:, -pred_len:, :] 是保险切片:

text
dec_out.shape = (2, 2, 3)
dec_out[:, -2:, :].shape = (2, 2, 3)   ← 等于整体,没有截断

保险切片的目的:某些 encoder 实现可能输出比 pred_len 长的序列,统一从末尾取 pred_len 步保证输出形状正确。在 DLinear 这里恰好等于全部。

11. 这一层最该固定什么

  1. 当前 forecasting 任务里,forward(...) 只走 forecast(x_enc)
  2. x_mark_enc / x_dec / x_mark_dec 不是真正核心。
  3. encoder(...) 在 DLinear 里不是 Transformer encoder,而是模型主体。
  4. 这层的真正出口是:
python
encoder(x_enc)

12. 下一步

继续看:

*记录并在线阅读我的笔记*