Skip to content

Layer0 接入界面

本文档描述 TFB 框架如何把原始数据切片、配置超参数,最终构造出传入 iTransformer.forward() 的四元组。对应 [[00-总览]] BFS 树的第一层。


§1 在父层中的位置

RollingForecast 策略按滑动窗口切出 (x_enc, x_mark_enc, x_dec, x_mark_dec),交由 TransformerAdapter._process() 拼装 dec_input 并直接调用 model.forward()——本文档覆盖的就是这条从"数据切片"到"模型入口"的完整准备路径。


§2 I/O 接口定义

四元组 shape(toy 参数)

张量shape(toy)具体含义使用情况
x_enc(3, 12, 5)B=3 批次,seq_len=12 时间步,N=5 变量✅ 实际使用
x_mark_enc(3, 12, 4)encoder 时间特征,time_dims=4(hour/weekday/monthday/month)✅ 实际使用
x_dec(3, 12, 5)label_len=6 历史 + pred_len=6 零占位,共 12 步⚠️ 传入但完全未使用
x_mark_dec(3, 12, 4)decoder 时间特征,同 x_enc 的 time_dims⚠️ 传入但完全未使用

forward() 返回dec_out[:, -pred_len:, :](3, 6, 5),即 (B, pred_len, N)

x_dec / x_mark_dec 是"哑参数"

_process() 按通用框架逻辑构造了 dec_input,但 iTransformer.forecast() 函数体中一行都没有引用这两个参数。iTransformer 是 encoder-only 模型,Decoder 分支根本不存在。详见 [[#§5.1 encoder-only 与 哑参数]]。

label_len 推导(toy)

参数来源
seq_len12rolling_forecast 切片窗口
label_len6multi_forecasting_hyper_param_tune() 设置:seq_len // 2
pred_len6评测配置指定
dec_len(实际构造)12label_len + pred_len = 6 + 6(但模型不使用)

§3 顺序图(具体层)


§4 语义分组图(索引层)


§5 逐步精读

§5.1 encoder-only 与"哑参数"

iTransformer 是 encoder-only 模型,完全没有 Decoder 模块。但 TFB 框架的通用适配器 TransformerAdapter 并不区分模型架构——它对所有 Transformer 类模型统一构造四元组并调用相同签名的 forward()

结果是:forecast() 函数签名接收 x_decx_mark_dec,但函数体第一行到最后一行都没有引用它们。

与有 Decoder 的模型对比:

模型Decoderx_dec / x_mark_dec 实际用途
Informer✅ 有(ProbSparse Attention)传入 Decoder,做自回归预测
Autoformer✅ 有(Auto-Correlation Decoder)传入 Decoder,序列分解
iTransformer❌ 无⚠️ 收到但函数体完全不用(哑参数)

这是一个框架通用性 vs 模型实现之间的"接口冗余"——对 iTransformer 而言,_process() 中构造 dec_input 的代码是运行但无效的死代码路径。


§5.2 MODEL_HYPER_PARAMS 与 iTransformer 的关系

iTransformer 没有专属超参数。Autoformer 有 moving_avg,PatchTST 有 patch_lenstride,而 iTransformer 直接复用通用字段,无需额外注册。

与 iTransformer 直接相关的通用参数:

参数默认值iTransformer 用途
d_model512(toy: 8)DataEmbedding_inverted Linear 输出维度
n_heads8(toy: 4)FullAttention 多头数
e_layers2Encoder 堆叠层数
d_ff2048(toy: 16)EncoderLayer FFN 隐层维度
dropout0.1各层 Dropout
embed"timeF"时间特征编码方式(影响 time_dims=4)
freq"h"时间频率(hour → 4 维时间特征)
activation"gelu"FFN 激活函数
output_attention0不输出注意力权重矩阵
task_name"short_term_forecast"默认值;multi_forecasting_hyper_param_tune 会覆写为 "long_term_forecast"
factor1FullAttention 中 top_k = factor × ceil(ln(L))(稀疏注意力比例,Full 模式不使用)
enc_in / dec_in / c_out 不在 MODEL_HYPER_PARAMS 中

这三个参数由 multi_forecasting_hyper_param_tune() 在运行时根据数据集动态推断,不在静态默认值字典里。


§5.3 _process() 构造 dec_input

原始源码adapters_for_transformers.py):

python
def _process(self, input, target, input_mark, target_mark):
    dec_input = torch.zeros_like(target[:, -self.config.horizon:, :]).float()
    dec_input = torch.cat([target[:, :self.config.label_len, :], dec_input], dim=1).float().to(input.device)
    output = self.model(input, input_mark, dec_input, target_mark)
    return {"output": output}

逐行注解:

第 1 行:target[:, -self.config.horizon:, :]

  • target 是完整的标签窗口,shape = (B, label_len + pred_len, N) = (3, 12, 5)
  • [-horizon:] = [-pred_len:] = 取最后 6 步 → shape (3, 6, 5)
  • torch.zeros_like(...) 创建等形全零张量,作为"未来未知"的占位符

第 2 行:torch.cat([target[:, :label_len, :], dec_input], dim=1)

  • target[:, :label_len, :] = 取前 6 步历史(label 段),shape (3, 6, 5)
  • 与全零占位拼接,dim=1(时间维)→ dec_input 最终 shape (3, 12, 5)

第 3 行:直接调用 self.model(input, input_mark, dec_input, target_mark)

  • 参数名映射:input = x_encinput_mark = x_mark_encdec_input = x_dectarget_mark = x_mark_dec

toy 数值追踪:

target shape:              (3, 12, 5)   # label_len=6 历史 + pred_len=6 未来
target[:, -6:, :]  →       (3, 6, 5)   # pred_len=6 的未来段
zeros_like(...)    →       (3, 6, 5)   # 全零占位
target[:, :6, :]   →       (3, 6, 5)   # label_len=6 的历史段
cat([历史, 零占位], dim=1) → (3, 12, 5)  # dec_input 最终 shape(⚠️ iTransformer 不会使用)

⚠️ 重要:上述构造对 iTransformer 是无效的——代码会运行,dec_input 会被创建并传入 forward(),但 forecast() 函数体中没有任何代码访问 x_dec 参数。这是框架通用性导致的"合法但多余"的计算。


§5.4 forward() 分支路由

原始源码iTransformer.py):

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, x_mark_enc, x_dec, x_mark_dec)
        return dec_out[:, -self.pred_len:, :]  # [B, L, D]

注解:

  • task_namemulti_forecasting_hyper_param_tune() 覆写为 "long_term_forecast",因此命中第一个条件
  • forecast() 接收四元组签名,但函数体只使用 x_encx_mark_encx_decx_mark_dec 进入函数后立即被忽略
  • 返回 dec_out[:, -self.pred_len:, :],对 forecast() 的输出做末端裁剪(详见 §5.5)

§5.5 返回值裁剪:dec_out[:, -pred_len:, :]

裁剪机制:

forecast() 内部 Projection 层的输出 shape 为 (B, pred_len, N),即已经是目标维度。forward() 再用 [:, -pred_len:, :] 裁剪是防御性写法——确保无论 forecast() 返回多长的序列,都只取最后 pred_len 步。

toy 数值追踪:

forecast() 输出 dec_out:      (3, 6, 5)   # B=3, pred_len=6, N=5
[:, -pred_len:, :]
  = [:, -6:, :]               (3, 6, 5)   # ← 索引 [0..5],无裁剪(dec_len = pred_len)

在本 toy 参数下,forecast() 输出恰好是 (3, 6, 5),裁剪前后 shape 不变。

⚠️ 为什么在这里 pred_len = dec_len?

  • forecast() 的 Projection 层是 nn.Linear(d_model, pred_len),permute 后直接输出 (B, pred_len, N)
  • 不像 Informer/Autoformer 会输出 label_len + pred_len 长度的序列再裁剪
  • 因此 [:, -pred_len:, :] 对 iTransformer 而言是幂等操作,但保留它是为了与其他 Transformer 模型保持接口一致性

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