有了数据和核心的ProbAttention,接下来就可以复现完整的Informer(图1)了。
图1:Informer模型结构[1]
如果对图1还不太熟悉的同学,可以参考图2。由图2可知,informer与Transformer之间的差异并不大。
主要区别是ProbAttention和可能的encoder最后一层的conv(源代码中用来distil)。
图2:参考Transformer画的Informer模型结构
Informer三大基本要素: AttentionBlock, MLPBlock, ConvBlock
上次博文已复现了ProbAttention和AttentionBlock (attention + add&norm),而Conv又是基础模块,所以整个Informer不难复现。
MLPBlock
MLPBlock (mlp+add&norm):源代码中采用1x1卷积的形式,相对较为繁琐。为了匹配卷积对应(batch_size, channels, seq_len)的特点,需要将输入先进行维度调整,得到结果后再将维度调整回来。
# 源代码
y = x = self.norm1(x)
y = self.dropout(self.activation(self.conv1(y.transpose(-1,1))))
y = self.dropout(self.conv2(y).transpose(-1,1))
return self.norm2(x+y), attn
直接用mlp则不存在此问题。
class MLPBlock(nn.Module):
def __init__(self, d_model, d_ff=None, dropout=0.1, act="relu"):
super().__init__()
d_ff = d_ff or d_model * 4
act = nn.ReLU() if act=="relu" else nn.GELU()
self.net = nn.Sequential(
nn.Linear(d_model, d_ff),
act,
nn.Dropout(dropout),
nn.Linear(d_ff, d_model),
nn.Dropout(dropout)
)
self.norm = nn.LayerNorm(d_model)
def forward(self, x):
out = self.net(x)
return self.norm(out + x)
ConvBlock
有了AttentionBlock和MLPBlock,只差ConvBlock就可以完整实现Informer了。如上所述,需要对输入的维度进行调整。
class ConvBlock(nn.Module):
def __init__(self, cin):
super().__init__()
self.net= nn.Sequential(
nn.Conv1d(cin, cin, 3, 1, 1, bias=False),