首先给出 TimeMixer 的调用类图 ,接着我们继续看 forcast 的执行, 接第一篇
TimeMixer 调用图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
|
输入: x_enc [B,T,N] → x_mark_enc [B,T,feat]
|
▼
┌──────────────────────────────────────────────────┐
│ __multi_scale_process_inputs │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ 原始尺度 │ → │ 尺度/2 │ → │ 尺度/4 │ → ... │
│ └─────────┘ └─────────┘ └─────────┘ │
└──────────────────────────────────────────────────┘
|
▼
┌──────────────────────────────────────────────────┐
│ normalize_layers 归一化 │
└──────────────────────────────────────────────────┘
|
▼
┌──────────────────────────────────────────────────┐
│ pre_enc 预处理 │
│ ┌───────────────────┐ ┌───────────────────┐ │
│ │ channel_independence=True │ │ channel_independence=False │ │
│ └─────────┬─────────┘ └──────────┬────────┘ │
│ │ │ │
│ │ ┌───────────────┐ │
│ │ │ 序列分解 │ │
│ │ │ 季节性 + 趋势 │ │
│ │ └───────────────┘ │
└────────────┼──────────────────────────┼──────────┘
│ │
▼ ▼
┌────────────────────────────────────────────────┐
│ enc_embedding 特征嵌入 │
│ [value_embedding + temporal_embedding] │
└────────────────────────────────────────────────┘
|
▼
┌────────────────────────────────────────────────┐
│ pdm_blocks 多尺度混合编码器 │
│ ┌───────────────┐ │
│ │ 序列分解 │ │
│ └───────┬───────┘ │
│ │ │
│ ┌───────▼───────┐ ┌───────────────┐ │
│ │ 季节性分量 │ │ 趋势性分量 │ │
│ └───────┬───────┘ └───────┬───────┘ │
│ │ │ │
│ ┌───────▼───────┐ ┌───────▼───────┐ │
│ │ 自下而上混合 │ │ 自上而下混合 │ │
│ └───────┬───────┘ └───────┬───────┘ │
│ │ │ │
│ └─────────┬───────────┘ │
│ │ │
└────────────────────┼───────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ future_multi_mixing 解码器 │
│ [多个预测器并行预测未来] │
└────────────────────┬───────────────────────────┘
│
▼
┌────────────────────────────────────────────────┐
│ 结果合并与反归一化 │
└────────────────────┬───────────────────────────┘
│
▼
输出: dec_out [B,pred_len,N]
|
forcast $- >$ self.pdm_blocks
1
2
|
for i in range(self.layer):
enc_out_list = self.pdm_blocks[i](enc_out_list)
|
输入
- self.layer = 2
- enc_out_list
- enc_out_list[0] [224,96,16]
- enc_out_list[1] [224,48,16]
- enc_out_list[2] [224,24,16]
- enc_out_list[3] [224,12,16]
处理: self.pdm_blocks
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
|
ModuleList(
(0-1): 2 x PastDecomposableMixing(
(layer_norm): LayerNorm((16,), eps=1e-05, elementwise_affine=True)
(dropout): Dropout(p=0.1, inplace=False)
(decompsition): series_decomp(
(moving_avg): moving_avg(
(avg): AvgPool1d(kernel_size=(25,), stride=(1,), padding=(0,))
)
)
(mixing_multi_scale_season): MultiScaleSeasonMixing(
(down_sampling_layers): ModuleList(
(0): Sequential(
(0): Linear(in_features=96, out_features=48, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=48, out_features=48, bias=True)
)
(1): Sequential(
(0): Linear(in_features=48, out_features=24, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=24, out_features=24, bias=True)
)
(2): Sequential(
(0): Linear(in_features=24, out_features=12, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=12, out_features=12, bias=True)
)
)
)
(mixing_multi_scale_trend): MultiScaleTrendMixing(
(up_sampling_layers): ModuleList(
(0): Sequential(
(0): Linear(in_features=12, out_features=24, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=24, out_features=24, bias=True)
)
(1): Sequential(
(0): Linear(in_features=24, out_features=48, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=48, out_features=48, bias=True)
)
(2): Sequential(
(0): Linear(in_features=48, out_features=96, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=96, out_features=96, bias=True)
)
)
)
(out_cross_layer): Sequential(
(0): Linear(in_features=16, out_features=32, bias=True)
(1): GELU(approximate='none')
(2): Linear(in_features=32, out_features=16, bias=True)
)
)
)
|
-
首先 self.pdm_blocks 堆叠了两个 ,因为 self.layer = 2
-
一个 self.pdm_blocks 就是 self.pdm_blocks[0]
-
它的结构是 self.pdm_blocks[0] = 一个趋势分解 + 多尺度季节性混合 + 趋势性混合 + 前馈(这里有一个遗留问题 就是为什么是 1 映射到 16 维呢? )
- (layer_norm)
- (dropout)
- (decompsition) 名称: 类名 series_decomp
- (moving_avg) 名称: 类名 moving_avg = (avg): AvgPool1d(kernel_size=(25,), stride=(1,), padding=(0,))
- (mixing_multi_scale_season): MultiScaleSeasonMixing
- 96 $->$ 48 (48 → 48)$->$ 24(24→24) $->$ 12(12→12)
- (mixing_multi_scale_trend): MultiScaleTrendMixing
- 12 $->$ 24 (24 → 24)$->$ 48 (48→48) $->$ 96 (96→96)
- (out_cross_layer): Sequential
- 16 -> 32 -> 16 (d_model $->$ d_ff $->$ d_model)
- 类似 Transformer 的 FFN
self.pdm_blocks[0] = 一个趋势分解 + 多尺度季节性混合 + 趋势性混合 + 前馈(这里有一个遗留问题 就是为什么是 1 映射到 16 维呢? )
1
2
|
for i in range(self.layer):
enc_out_list = self.pdm_blocks[i](enc_out_list)
|
好了 这里看完了 , 输出
enc_out_list
- enc_out_list[0] [224,96,16]
- enc_out_list[1] [224,48,16]
- enc_out_list[2] [224,24,16]
- enc_out_list[3] [224,12,16]
1
2
|
# Future Multipredictor Mixing as decoder for future
dec_out_list = self.future_multi_mixing(B, enc_out_list, x_list)
|
输入:
-
B = 32(batch size)
-
enc_out_list
- enc_out_list[0] [224,96,16]
- enc_out_list[1] [224,48,16]
- enc_out_list[2] [224,24,16]
- enc_out_list[3] [224,12,16]
-
x_list
- x_list[0] [224,96,1]
- x_list[1] [224,48,1]
- x_list[0] [224,96,1]
- x_list[3] [224,12,1]
处理:
- “Future Multipredictor Mixing”(未来多预测器混合)
- 多尺度并行预测:对每个时间尺度的特征分别进行未来预测, 每个尺度使用独立的预测器(self.predict_layers[i]), 不同尺度的预测结果互相独立,捕获不同频率的模式
- 特征投影变换:将高维特征映射到目标维度, 用projection_layer将特征维度转换为目标变量维度 , 处理形状从[B,T,d_model]到[B,pred_len,c_out]的转变
- 步进
self.future_multi_mixing
完整代码
1
2
3
4
5
6
7
8
9
10
|
def future_multi_mixing(self, B, enc_out_list, x_list):
dec_out_list = []
if self.channel_independence:
x_list = x_list[0]
for i, enc_out in zip(range(len(x_list)), enc_out_list):
dec_out = self.predict_layers[i](enc_out.permute(0, 2, 1)).permute(
0, 2, 1) # align temporal dimension
dec_out = self.projection_layer(dec_out)
dec_out = dec_out.reshape(B, self.configs.c_out, self.pred_len).permute(0, 2, 1).contiguous()
dec_out_list.append(dec_out)
|
-
结构不难
-
输入 B, enc_out_list, x_list
点击查看输入的形状
===================================
• B = 32(batch size)
• enc_out_list
◦ enc_out_list[0] [224,96,16]
◦ enc_out_list[1] [224,48,16]
◦ enc_out_list[2] [224,24,16]
◦ enc_out_list[3] [224,12,16]
• x_list
◦ x_list[0] [224,96,1]
◦ x_list[1] [224,48,1]
◦ x_list[0] [224,96,1]
◦ x_list[3] [224,12,1]
-
中间执行 if 条件句
-
关键层是 self.predict_layers ① args.down_sampling_layers=3 这个叫 下采样层下采样了三层 ②args.down_sampling_window=2 这个东西叫下采样倍率,$96->48->24->12$ ③然后 self.prediction 就是 $96 -> 720, 48->720, 24->720,12->720$
self.predict_layers的 init 和具体的实例化
===================================
self.predict_layers = torch.nn.ModuleList(
[
torch.nn.Linear(
configs.seq_len // (configs.down_sampling_window ** i),
configs.pred_len,
)
for i in range(configs.down_sampling_layers + 1)
]
)
===================================
ModuleList(
(0): Linear(in_features=96, out_features=720, bias=True)
(1): Linear(in_features=48, out_features=720, bias=True)
(2): Linear(in_features=24, out_features=720, bias=True)
(3): Linear(in_features=12, out_features=720, bias=True)
)
-
self.projection_layer
- (具体地实例化) self.projection_layer = Linear(in_features=16, out_features=1, bias=True)
- (初始化) self.projection_layer = nn.Linear(configs.d_model, 1, bias=True)
-
输出 dec_out_list
-
开始吧 逐步执行,看功能,要画类似 UNET 的计算流程图, TimesNet 的也是,要补
1
|
def future_multi_mixing(self, B, enc_out_list, x_list):
|
步进,是一个函数, 接收参数,
B = 32, enc_out_list, x_list分别是有四个元素的列表,去前面翻吧,不想写了
enc_out_list, [Tensor[224,96,16], [224,48,16], [224,24,16], [224,12,16]]
x_list, [Tensor[224,96,1], [224,48,1], [224,24,1], [224,12,1]]
存储 输出列表
1
|
if self.channel_independence:
|
如果通道独立 , 执行,是的 这里 self.channel_independence=1
取出 第一个元素 x_list,
输出 : x_list[0] .shape= [224,96,1]
1
|
for i, enc_out in zip(range(len(x_list)), enc_out_list):
|
for 循环遍历列表
输入 :
- range(len(x_list)) = range(0,4) (遍历 4 次,i 的取值 0,1,2,3,现在第一次,i=0)
- enc_out_list=List[Tensor(224,96,16),(224,48,16),(224,24,16),(224,12,16)]
输出 :
- i=0
- enc_out = Tensor(224,96,16)
1
|
dec_out = self.predict_layers[i](enc_out.permute(0, 2, 1)).permute(0, 2, 1)
|
- 输入 enc_out Tensor(224,96,16)
- .permute(0, 2, 1) $->$ Tensor(224,16,96)
- self.predict_layers[i] = Linear(in_features=96, out_features=720, bias=True) $->$ Tensor(224,16,720)
- .permute(0, 2, 1) $->$ Tensor(224,720,16)
- 输出 dec_out Tensor(224,720,16)
1
|
dec_out = self.projection_layer(dec_out)
|
- 输入 dec_out Tensor(224,720,16)
- self.projection_layer = Linear(in_features=16, out_features=1, bias=True) -> Tensor(224,720,1)
- 输出 dec_out Tensor(224,720,1)
1
|
dec_out = dec_out.reshape(B, self.configs.c_out, self.pred_len).permute(0, 2, 1).contiguous()
|
- 输入 dec_out Tensor(224,720,1)
- .reshape(B, self.configs.c_out, self.pred_len) $->$ Tensor(32,7,720)
- .permute(0, 2, 1).contiguous() $->$ [32,720,7]
- 输出 dec_out [32,720,7]
1
|
dec_out_list.append(dec_out)
|
输入 dec_out Tensor (32,720,7)
添加进列表
输出 dec_out_list[0] tensor (32,720,7)
1
2
3
4
5
6
|
for i, enc_out in zip(range(len(x_list)), enc_out_list):
dec_out = self.predict_layers[i](enc_out.permute(0, 2, 1)).permute(
0, 2, 1) # align temporal dimension
dec_out = self.projection_layer(dec_out)
dec_out = dec_out.reshape(B, self.configs.c_out, self.pred_len).permute(0, 2, 1).contiguous()
dec_out_list.append(dec_out)
|
重复整个 for 循环,最终得到这个部分的返回值 dec_out_list,长度为 4 的列表,列表中每个元素的形状
- dec_out_list[0] Tensor(32,720,7)
- dec_out_list[1] Tensor(32,720,7)
- dec_out_list[0] Tensor(32,720,7)
- dec_out_list[3] Tensor(32,720,7)
继续 def forcast
1
|
dec_out = torch.stack(dec_out_list, dim=-1).sum(-1)
|
- 输入 dec_out_list , 是一个长度为 4 的列表, 形状List [Tensor(32,720,7), Tensor(32,720,7), Tensor(32,720,7), Tensor(32,720,7)]
- stack(dim=-1) Tensor(32,720,7,4) (增加维度堆叠)
- .sum(-1) Tensor(32,720,7)
- 输出 dec_out Tensor(32,720,7)
1
|
dec_out = self.normalize_layers[0](dec_out, 'denorm')
|
- 输入 dec_out Tensor(32,720,7)
- self.normalize_layers[0] = Normalize(),逆标准化,没啥意思,不会改变形状, self.normalize_layers是一个 4 层的标准化层,这里只需要进行一个标准化,所以只取 0
- 输出 dec_out Tensor(32,720,7)
输出: dec_out 形状 [32,720,7] batchsize,sequence_length,feature_dim
返回 Model forward
dec_out dec_out 形状 [32,720,7]
整个模型 前向传播结束