Skip to content

Level 8 _process 到 DLinear.forward

Abstract

入口:

python
out_loss = self._process(input, target, input_mark, target_mark)

当前例子里,它会进入:

python
TransformerAdapter._process(...)
-> self.model(input, input_mark, dec_input, target_mark)
-> DLinear.forward(...)

这一层解释:

训练循环里的统一前向入口,怎样先经过 adapter 做接口翻译,再进入 DLinear 的真实计算。

1. 上一层与当前层位置

上一层是:

当前层是:

  • Level 8:训练线里最底部的前向路径。

这一层是你当前 debug_tfb_framework.pyrun_benchmark.py 两条学习线重新汇合的地方。

1.5 这一层的关系类型说明

这一层是在继续下钻:

  • Level 7 训练循环里的 7B 模型前向

所以这里的 8A / 8B / 8C

  • 一次前向路径内部的角色分层
  • 不是新的同级业务流程

2. 当前层第一性

这一层要分清两个角色:

2.1 TransformerAdapter._process(...)

第一性:

把 TFB 训练循环提供的统一四元组接口,翻译成底层模型能接收的 forward 输入。

2.2 DLinear.forward(...)

第一性:

接收已经准备好的模型输入,并完成真正的数值计算,输出预测张量。

所以这层的核心不是一条线,而是两段不同职责的接力:

  1. adapter 负责接口翻译
  2. model 负责实际计算

3. 当前命令的最小例子

当前训练 batch 的真实 shape:

  • input.shape = (4, 96, 7)
  • target.shape = (4, 72, 7)
  • input_mark.shape = (4, 96, 4)
  • target_mark.shape = (4, 72, 4)

当前 config 的关键值:

  • seq_len = 96
  • label_len = 48
  • horizon = 24
  • pred_len = 24
  • enc_in = 7

这一层的关键任务就是把上面这些变量变成:

  • dec_input.shape = (4, 72, 7)
  • output.shape = (4, 24, 7)

4. 先看顺序图

5. 抽象索引树

6. 职责树

6.1 8A 统一接口层

职责:

  • 给训练循环一个统一前向入口:
    • self._process(...)

6.2 8B adapter 翻译层

职责:

  • target 中构造 decoder 输入 dec_input
  • 把训练循环的四元组翻译成底层模型的 forward 接口

6.3 8C DLinear 真实计算层

职责:

  • 基于 x_enc 做分解和线性预测
  • 输出未来 pred_len 段预测值

7. 输入输出接口

7.1 本层入口接口

训练循环调用的是:

python
self._process(input, target, input_mark, target_mark)

输入:

  • input
  • target
  • input_mark
  • target_mark

7.2 adapter 层关键中间变量

  • dec_input
  • output

7.3 DLinear.forward(...) 的接口

python
forward(x_enc, x_mark_enc, x_dec, x_mark_dec, mask=None)

当前例子里实际映射是:

  • x_enc = input
  • x_mark_enc = input_mark
  • x_dec = dec_input
  • x_mark_dec = target_mark

7.4 本层输出

python
{"output": output}

其中:

  • output.shape = (4, 24, 7)

8. 函数 / 文件关系图

9. 关键代码对应关系

9.1 统一前向入口

训练循环里:

python
out_loss = self._process(input, target, input_mark, target_mark)

这一层并不知道当前模型是不是 DLinear。
它只知道:

_process(...) 会给我一个 out_loss["output"]

9.2 adapter 翻译

TransformerAdapter._process(...) 里:

python
dec_input = torch.zeros_like(target[:, -self.config.horizon :, :]).float()
dec_input = torch.cat([target[:, : self.config.label_len, :], dec_input], dim=1)
output = self.model(input, input_mark, dec_input, target_mark)

这里最关键的是:

  • target[:, -horizon:, :] 先提供未来部分的零占位
  • target[:, :label_len, :] 提供 decoder 已知历史尾部

所以:

text
dec_input = 历史尾部(label_len) + 未来零填充(horizon)

在当前例子里:

  • label_len = 48
  • horizon = 24

所以:

  • dec_input.shape = (4, 72, 7)

9.3 DLinear.forward(...)

DLinear.forward(...) 里:

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

当前任务是 short_term_forecast,所以:

  • 它走 forecast(x_enc)
  • 并且只返回最后 pred_len=24

这也说明:

虽然接口上 DLinear 接收了 4 个输入,但真正用来计算 forecast 的核心输入是 x_enc

9.4 DLinear.encoder(...)

真正计算在这里:

python
seasonal_init, trend_init = self.decompsition(x)
seasonal_output = self.Linear_Seasonal(...)
trend_output = self.Linear_Trend(...)
x = seasonal_output + trend_output

也就是:

  1. 先把输入分成 trend / seasonal
  2. 分别做线性映射
  3. 再相加得到预测结果

10. 当前例子的具体落地

10.1 训练循环输入

  • input = (4, 96, 7)
  • target = (4, 72, 7)

10.2 adapter 构造的 dec_input

  • 前 48 步来自 target[:, :48, :]
  • 后 24 步是零

所以:

  • dec_input = (4, 72, 7)

10.3 DLinear.forward 输出

DLinear 实际只围绕:

  • x_enc = (4, 96, 7)

进行计算,最后返回:

  • output = (4, 24, 7)

10.4 回到训练循环

然后训练循环再做:

python
target = target[:, -24:, :]
loss = criterion(output, target)

所以这层和上一层正好闭环。

11. 当前层最重要的认知

这一层最重要的认知是:

self._process(...) 不是多余中间层,它是 TFB 统一训练循环和具体模型之间的接口翻译层。

以及:

在当前 DLinear 例子里,adapter 仍然按 transformer family 的统一接口传 4 个输入,但 DLinear 的核心计算几乎只依赖 x_enc

12. 下一层入口

如果后面还继续 DFS,下一个自然入口有两个方向:

  1. 继续拆 TransformerAdapter._process(...)
    • 专门看 dec_input 语义
  2. 继续拆 DLinear.encoder(...)
    • 专门看 series_decomp + Linear_Seasonal / Linear_Trend

如果按当前主线,我更建议先停在这里,因为:

对 benchmark 主链理解来说,Level 8 已经打通了“训练循环 -> adapter -> 模型 forward”。

13. 只留一句

Level 8 只看一件事:统一训练循环怎样先经过 adapter 翻译,再进入 DLinear 的真实前向计算。

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