在市中心有一家生意火爆的“未来餐厅”,老板最拿手的不是做菜,而是预测——预测接下来一周每天会来多少客人、点哪些菜。老板手里攥着三个信息源:一本记录老顾客口味的VIP台账、一张挂在墙上的节日与活动排期表,以及一本厚厚的历史点餐流水账。他把三类信息汇总,再结合“今天是周几”“是不是节假日”这类时间线索,就能做出相当靠谱的判断。如果天气预报说周末要下暴雨,他还会调低堂食备货、提高外卖食材的权重——这种对信息的灵活取舍,就是TFT中“门控”思想的生活版本。 TFT(Temporal Fusion Transformer,时序融合Transformer)正是这位老板的数字化大脑:它把静态变量、已知未来变量、历史观测变量三类输入统一融合,通过门控残差网络、多头注意力机制输出带置信区间的多步预测,还能像老板解释推荐理由一样,向工程师解释“为什么这么预测”。

岗位关联

学透TFT,你就能在电力、零售、金融等场景中做出“可解释、带不确定性估计”的多变量时序预测——这是工业级预测建模的核心竞争力。

目录
  1. 可视化演示
  2. 三类输入特征
  3. 时序特征编码
  4. 门控残差网络
  5. 多头注意力
  6. 编码解码结构
  7. 可解释与实战
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

动态演示TFT时序融合Transfo的核心机制,通过概览/流程/对比/趋势四种模式展示关键概念与交互流程。

本节配有交互动效(进入视口后自动加载,约 3KB)。

TFT时序融合Transfo:TFT整 TFT整体架构与三类变量融合设 变量选择网络与特征重要性自适应 核心机制可视化 TFT时序融合Transfo整体架构与关键组件

三类输入特征

“未来餐厅”的老板每天开门前会看三样东西:立在收银台旁的VIP顾客档案册、墙上贴着未来一周节气与商场活动的排期表、后厨那摞厚厚的历史点餐流水账。档案册告诉他熟客的口味与消费习惯,排期表告诉他哪天会迎来人流高峰,流水账则记录了去年同期的点餐趋势。三样信息合在一起,老板心里就有了底。

TFT也在做同样的事。它把输入统一划分为三类:静态变量(static variables,对象固定属性,如门店ID、地区)、已知未来变量(known future variables,如未来节假日、天气预报)、历史观测变量(past/observed variables,如过去30天的销量)。三者最终都被映射成向量,在同一套网络里融合。这就像老板把三本册子在脑子里汇成一张“今日备菜计划”。

把三类特征拼接起来,就得到每个时刻的输入表示:

有了这份“情报菜单”,TFT不像普通方法那样只盯着一列数字,而是像老板一样把熟客口味、节日活动和历史趋势同时装进脑子再开口报价。三种情报缺一不可。

xt=[ξ,χt,ψt]\mathbf{x}_t = [\boldsymbol{\xi}, \boldsymbol{\chi}_t, \boldsymbol{\psi}_t]
公式含义:t 时刻的输入 = 静态变量 ξ + 已知未来变量 χ_t + 历史观测变量 ψ_t。
  1. 静态变量描述对象固定属性的特征向量,在整个预测周期内不随时间变化。
    ξ\boldsymbol{\xi}
  2. 已知未来变量未来时间步上可以提前获得的特征,如节假日标记。
    χt\boldsymbol{\chi}_t
  3. 历史观测变量截至当前时刻 t 能观测到的序列值,如历史销量。
    ψt\boldsymbol{\psi}_t

时序特征编码

老板的直觉里藏着一套朴素的时间感知力:周五傍晚的客流量总比周一早晨高,月底总比月初忙,春节前后要提前三天备货。这些节奏并不直接写在流水账里,而是融在他对时间的敏感中。模型没有这种直觉,它得靠显式的时间特征来“补课”。

TFT把每个时间戳 t 转化成一组多尺度的周期性特征,让网络能感知小时、天、周、月等不同节奏。这类似于Transformer中的位置编码:先告诉模型“你现在站在时间轴的哪个位置”,再让它理解这个位置蕴含的规律。

具体做法是用一组正弦、余弦函数把时间戳投影到不同频率的空间:

这些编码就像老板脑中那本“日历直觉手册”——不用翻开日历,他也知道今天星期几、离上次促销过了几天。模型因为有了时间编码,才能在预测时区分“日常的平淡”和“节日的喧闹”。

ϕ(t)=[sin⁡(2πf1t),cos⁡(2πf1t),…,sin⁡(2πfkt),cos⁡(2πfkt)]\phi(t) = \left[\sin(2\pi f_1 t), \cos(2\pi f_1 t), \dots, \sin(2\pi f_k t), \cos(2\pi f_k t)\right]
公式含义:用 k 组不同频率的正余弦函数,把时间 t 编码成 2k 维向量,不同频率捕获不同时间尺度的节奏。
  1. 周期频率集合选择 k 个有代表性的频率,对应小时、天、周等周期。
    fk={f1,f2,…,fk}f_k = \{f_1, f_2, \dots, f_k\}
  2. 正弦分量计算时间 t 在某个周期内的相位位置。
    sin⁡(2πfkt)\sin(2\pi f_k t)
  3. 余弦分量与正弦分量互补,保留完整相位信息。
    cos⁡(2πfkt)\cos(2\pi f_k t)

门控残差网络

如果某天暴雨突至,老板不会机械地按“周末人多”的旧经验备菜,而会立刻调低堂食食材量、增加外卖包装盒的采购。他之所以如此灵活,是因为大脑里有个“应变开关”——根据当下情况决定每条经验该听多少。TFT里的门控残差网络就是这枚开关。

门控残差网络(Gated Residual Network,GRN)接收两类输入:主输入特征 a 和外部上下文向量 c(通常由静态变量编码而来)。它在内部用门控线性单元(GLU)决定信息流动的强度,再用残差连接和 LayerNorm 保持深层训练稳定:

变量选择网络是 GRN 的关键应用:每个输入特征先经过各自的 GRN 产生特征向量和得分,再通过 softmax 得到归一化权重,最后按权重加权求和。模型因此能针对不同样本自动调整“该信哪个变量”。当暴雨预警和节日排期同时到达,那枚“应变开关”会压低历史经验的权重、抬高天气信息的权重——老板不必重新学怎么开餐厅,只需在关键时刻调整关注点。

GRNω(a,c)=LayerNorm(a+GLUω(η1))\text{GRN}_{\omega}(a, c) = \text{LayerNorm}\left(a + \text{GLU}_{\omega}(\eta_1)\right)
公式含义:GRN 先把输入 a 与上下文 c 融合,经过门控挑选后,再把原始输入加回来(残差),最后归一化输出。
  1. 上下文向量由静态变量编码得到的全局条件向量,作为门控决策的“大背景”。
    cc
  2. 主输入融合与非线性输入 a 与上下文 c 融合后经过 ELU 激活,增强表达能力。
    η2=ELU(W2,ωa+W3,ωc+b2,ω)\eta_2 = \text{ELU}(W_{2,\omega} a + W_{3,\omega} c + b_{2,\omega})
  3. GLU 门控用 sigmoid 生成 0 到 1 的门值,逐元素决定信息通过的比例。
    GLUω(η1)=σ(W4,ωη1+b4,ω)⊙(W5,ωη1+b5,ω)\text{GLU}_{\omega}(\eta_1) = \sigma(W_{4,\omega}\eta_1 + b_{4,\omega}) \odot (W_{5,\omega}\eta_1 + b_{5,\omega})
  4. 残差与归一化加上原始输入保持梯度畅通,LayerNorm 稳定训练。
    LayerNorm(a+GLUω(η1))\text{LayerNorm}(a + \text{GLU}_{\omega}(\eta_1))

多头注意力

门店生意好时,老板会同时让几位经验丰富的老店长各盯一件事:一位盯节气与客流的关系,一位盯最近异常订单的苗头,还有一位盯老顾客的消费习惯变化。几位店长各看各的,最后在例会上把观察拼在一起,形成完整判断。

TFT用多头注意力机制实现同样的分工。每个注意力头独立执行“缩放点积注意力”,并行地捕捉序列中不同模式的长程依赖——有的头抓到周期性规律,有的头关注近期突变。基础计算方式如下:

特别的是,TFT在最后的解码层使用单头注意力,以便直接输出可解释的注意力权重——这是它区别于普通Transformer的设计亮点。多头注意力就像一群各有所长的老店长:一个看节日、一个看趋势、一个看异常。他们各执己见虽不能单独拍板,但汇合后的观察足以支撑老板做出决策。

Attention(Q,K,V)=Softmax(QKTdk)V\text{Attention}(Q, K, V) = \text{Softmax}\left(\frac{QK^T}{\sqrt{d_k}}\right)V
公式含义:用查询 Q 和键 K 的相似度做 softmax 归一化,得到对值 V 的加权汇总;除以根号 d_k 是为了防止点积过大导致梯度消失。
  1. 查询向量当前时间步“想找什么”的表示,由输入变换而来。
    Q=XWQQ = XW^Q
  2. 键与值向量序列中其他位置提供的“索引标签”和“具体内容”。
    K=XWK,V=XWVK = XW^K, \quad V = XW^V
  3. 缩放点积注意力计算查询与所有键的相似度并缩放,再经 softmax 转成权重。
    QKTdk\frac{QK^T}{\sqrt{d_k}}
  4. 多头拼接输出多个头捕获不同模式后拼接,再投影到输出空间。
    MultiHead(Q,K,V)=Concat(h1,…,hh)WO\text{MultiHead}(Q,K,V) = \text{Concat}(h_1, \dots, h_h)W^O

编码解码结构

预测的过程有点像“备菜—出餐”的流水线:先翻看过去几天的流水账(编码器盘点历史),再结合未来的排期表(解码器预估未来),最后把预估结果做成几档规格——保守备菜、常规备菜、充足备菜,分别对应低、中、高三种置信水平。

在结构上,编码器处理长度为历史窗口的观测序列,输出携带历史信息的隐状态;解码器以已知未来变量为输入,结合编码器隐状态“翻译”出未来时间步的表征。这一思路与NLP中的“源序列→目标序列”编解码一脉相承,但TFT把注意力灵活地连接在历史与未来之间,既看过去也看未来可知信息。

为了量化不确定性,TFT在输出层同时预测多个分位数(如 0.1、0.5、0.9),用分位数损失训练:

三档备菜量各有用途:保守档保证不浪费食材,常规档服务日常客流,充足档应对意外高峰。老板不必赌一个确定数字,而是手握一套“风险预案”——这正是分位数输出在业务中的价值。

Q(q,y,y^)=q⋅max⁡(y−y^,0)+(1−q)⋅max⁡(y^−y,0)Q(q, y, \hat{y}) = q \cdot \max(y - \hat{y}, 0) + (1-q) \cdot \max(\hat{y} - y, 0)
公式含义:当真实值 y 高于预测 ŷ 时按权重 q 惩罚(低估代价);当预测高于真实时按 (1-q) 惩罚(高估代价)。q 越大,模型越倾向给出偏高的预测。
  1. 分位数参数表示目标置信水平,常用 0.1 / 0.5 / 0.9。
    q∈[0,1]q \in [0, 1]
  2. 低估惩罚项真实值高于预测时,按 q 的比例计入损失。
    q⋅max⁡(y−y^,0)q \cdot \max(y - \hat{y}, 0)
  3. 高估惩罚项预测高于真实时,按 (1-q) 的比例计入损失。
    (1−q)⋅max⁡(y^−y,0)(1-q) \cdot \max(\hat{y} - y, 0)

可解释与实战

这家餐厅之所以被街坊信任,是因为老板每次都解释推荐理由:“明天是七夕且天气晴,预估客流比平日多三成,建议提前腌制牛肉。”这种“可解释性”让决策有据可循,也让顾客愿意配合。

TFT同样重视可解释性,提供了两把“透明钥匙”:其一是注意力权重可视化,观察模型在预测未来时重点“回看”了哪些历史时刻;其二是变量选择权重,直接量化每个输入变量对当前预测的贡献。变量选择权重由 softmax 计算:

实战方面,数据预处理要注意按序列做归一化、充分编码时间戳特征、按 group 划分样本;训练时推荐早停和较小学习率;评估时除了 MAE 和 RMSE,常用 P50 中位数误差与分位数损失之和(QRM)衡量区间预测质量。老板把依据讲给顾客听,赢得了长期信任;TFT把注意力与变量权重“摊开”给工程师看,让模型从“黑盒”变成了“会解释自己的厨房”,这正是它落地工业场景的底气。

v^t(j)=exp⁡(wt(j))∑k=1mexp⁡(wt(k))\hat{v}_t^{(j)} = \frac{\exp(w_t^{(j)})}{\sum_{k=1}^{m} \exp(w_t^{(k)})}
公式含义:第 j 个变量的原始得分 w 经过 softmax,转成和为 1 的权重;权重越大,该变量对本次预测的贡献越高。
  1. 变量得分每个变量经过门控残差网络产生一个标量得分。
    wt(j)w_t^{(j)}
  2. softmax 归一化将得分转成概率分布,所有变量权重相加为 1。
    exp⁡(wt(j))∑k=1mexp⁡(wt(k))\frac{\exp(w_t^{(j)})}{\sum_{k=1}^{m} \exp(w_t^{(k)})}
  3. 加权融合特征用权重对各变量的特征向量做加权求和,得到融合表示。
    x~t=∑j=1mv^t(j)x~t(j)\tilde{x}_t = \sum_{j=1}^{m} \hat{v}_t^{(j)} \tilde{x}_t^{(j)}

AI 应用场景

电力负荷预测

阶段:特征工程与预测建模

解决的问题:电力需求受温度、节假日、时段等多因素影响,传统时间序列模型难以同时融合异质特征,也无法给出波动区间。TFT将历史负荷(历史观测)、天气预报与节假日标记(已知未来)、区域属性(静态变量)三类输入统一融合,输出多步负荷预测及其分位数区间,帮助调度员评估供电压力。

具体案例:某省级电网利用TFT预测未来24小时每15分钟的负荷曲线。模型输入包括过去7天的实测负荷、未来24小时的温度预报、节假日标记和用电区域ID。预测输出的0.1分位数用于低谷期机组检修安排,0.9分位数用于高峰期备用容量预留,调度决策效率显著提升。

零售库存与销量预测

阶段:模型训练与业务应用

解决的问题:零售SKU数量庞大,促销、季节与门店属性互相交织,靠Excel和经验难以做到精细预测。TFT的门控残差网络能自动学习“何时该信促销特征、何时该信历史趋势”,变量选择权重还能告诉采购部门“上周销量上涨主要是哪家门店的哪个品类带动的”。

具体案例:某连锁超市用TFT预测120家门店未来7天各品类销量。输入含门店ID(静态变量)、未来促销计划与天气(已知未来变量)、过去60天销量(历史观测变量)。模型不仅给出点预测,还输出0.1/0.5/0.9三个分位数,用于指导不同门店的配货量与安全库存设置,平均库存周转率提升了约15%。

Python 演示

python90 行
import torchimport torch.nn as nn  class GLU(nn.Module):    """门控线性单元: 用sigmoid门控决定信息通过比例"""     def __init__(self, hidden_size):        super().__init__()        self.fc = nn.Linear(hidden_size, hidden_size)        self.gate = nn.Linear(hidden_size, hidden_size)     def forward(self, x):        return self.fc(x) * torch.sigmoid(self.gate(x))  class GRN(nn.Module):    """门控残差网络: 融合主输入与静态上下文"""     def __init__(self, hidden_size):        super().__init__()        self.fc1 = nn.Linear(hidden_size, hidden_size)        self.fc2 = nn.Linear(hidden_size, hidden_size)        self.glu = GLU(hidden_size)        self.norm = nn.LayerNorm(hidden_size)     def forward(self, a, c=None):        eta1 = self.fc1(a)        if c is not None:            eta1 = eta1 + self.fc2(c)        eta2 = torch.nn.functional.elu(eta1)        out = self.glu(eta2)        return self.norm(a + out)  class SimpleTFT(nn.Module):    """简化版TFT: 特征投影 + GRN + 多头注意力 + 分位数输出"""     def __init__(self, num_features, hidden_size=32,                 num_heads=2, quantiles=[0.1, 0.5, 0.9]):        super().__init__()        self.embed = nn.Linear(num_features, hidden_size)        self.grn = GRN(hidden_size)        self.attn = nn.MultiheadAttention(hidden_size, num_heads,                                          batch_first=True)        self.output = nn.Linear(hidden_size, len(quantiles))        self.quantiles = quantiles     def forward(self, x):        h = torch.relu(self.embed(x))        h = self.grn(h)        h, _ = self.attn(h, h, h)        return self.output(h[:, -1, :])  class QuantileLoss(nn.Module):    """分位数损失: 对低估和高估施加不对称惩罚"""     def __init__(self, quantiles=[0.1, 0.5, 0.9]):        super().__init__()        self.quantiles = quantiles     def forward(self, preds, target):        loss = 0.0        for i, q in enumerate(self.quantiles):            diff = target - preds[:, i]            loss += torch.max(q * diff, (q - 1) * diff).mean()        return loss  def main():    torch.manual_seed(42)    batch = 16    seq_len = 8    num_features = 5    x = torch.randn(batch, seq_len, num_features)    y = torch.randn(batch, 3)    model = SimpleTFT(num_features)    optimizer = torch.optim.Adam(model.parameters(), lr=0.01)    criterion = QuantileLoss()    for epoch in range(5):        optimizer.zero_grad()        loss = criterion(model(x), y)        loss.backward()        optimizer.step()        print(f"epoch {epoch + 1}: loss = {loss.item():.4f}")  if __name__ == "__main__":    main()
目的:用PyTorch实现一个简化版TFT,包含GLU门控、门控残差网络、多头注意力和分位数损失,演示核心组件如何协同工作。
  1. self.embed = nn.Linear(num_features, hidden_size)把原始多特征映射到统一隐空间,后续模块才能共享表示。
  2. eta1 = self.fc1(a)对主输入做第一层线性变换,为融合上下文做准备。
  3. eta2 = torch.nn.functional.elu(eta1)用ELU激活引入非线性,负区间不饱和不易梯度消失。
  4. out = self.glu(eta2)经过GLU门控,模型只放行高价值信息,抑制噪声信号。
  5. return self.norm(a + out)残差连接再加LayerNorm,稳定深层训练。
  6. h, _ = self.attn(h, h, h)对隐状态做自注意力,捕捉序列内部的长程依赖。
  7. return self.output(h[:, -1, :])取最后一个时间步的隐状态映射到多个分位数。
  8. loss += torch.max(q * diff, (q - 1) * diff).mean()分位数损失核心公式,对高估和低估施加不对称惩罚。

常见误区

误区以为TFT只是把Transformer搬到时间序列上,网络结构一点不用改,直接喂原始数据就能用。

正解TFT专门设计了门控残差网络、变量选择网络和多尺度时间特征编码,让模型能融合异构输入并保持可解释性。直接套用NLP Transformer会丢失这些关键设计,难以处理静态变量与已知未来变量的融合。

为何常见:Transformer在NLP中太成功,容易产生“拿来主义”,忽略了时序数据本身的异质性和多源特性。

误区看到“已知未来”四个字,就以为它是指模型要预测的Y值,训练时把未来真实值也塞进特征里。

正解已知未来变量是未来时间段内提前可知的外部特征,比如天气预报、节假日标记、促销计划。预测目标Y的未来真值是未知的,一旦混入特征会造成严重的数据泄漏。

为何常见:概念名字里带“未来”二字,容易被误解为未来真实值,很多初学者在这里翻车。

误区10%、50%、90%三个分位数得分别训练三个模型,工作量大且模型间还容易不一致。

正解TFT通过一个模型同时输出多个分位数,分位数损失把三者放进同一个优化目标。这样不仅训练高效,还能保证不同分位数预测之间的内在一致性。

为何常见:传统回归任务通常只输出一个均值,惯性思维让人以为多个分位就要多个模型。

误区把TFT输出的注意力热力图直接当作因果结论——“模型注意力越大的地方,就是销量上涨的原因”。

正解注意力权重表示模型对信息的“关注程度”,不等于因果推断。需要结合变量选择权重、业务逻辑做交叉验证,才能得出可靠结论。

为何常见:注意力可视化最直观,热力图一画出来就很有说服力,容易让人过度解读。

误区门控残差网络能自动适应一切数据分布变化,模型部署后一劳永逸,不用再管。

正解门控只能在不改变训练分布的前提下做特征取舍。当外部环境发生剧烈变化(如疫情冲击、新政策出台),仍需用新数据做微调甚至重新训练。

为何常见:门控听起来像“自适应系统”,给人很强的错觉,其实它的自适应范围有限。

面试题

Q1. TFT的输入特征不包括以下哪一项?

单选题 · easy

  • A.静态变量特征
  • B.已知未来变量
  • C.历史观测变量
  • D.随机噪声变量← 正确答案

答案:D。TFT三类输入是静态变量、已知未来变量、历史观测变量,随机噪声不是合法输入。就像未来餐厅的三本册子里不会放一本“乱数表”。

Q2. 门控残差网络(GRN)的核心作用是什么?

单选题 · mid

  • A.对输入做随机采样
  • B.自适应筛选有效信号← 正确答案
  • C.为模型增加随机噪声
  • D.降低输入数据的维度

答案:B。GRN通过GLU门控决定信息通过比例,再配合残差连接,实现“自适应筛选有效信号”。它不负责降维,更不是加噪声或采样。

Q3. TFT用哪个损失函数处理预测不确定性?

单选题 · mid

  • A.交叉熵损失
  • B.分位数损失← 正确答案
  • C.均方误差损失
  • D.对比损失函数

答案:B。TFT输出多个分位数并用分位数损失训练,能对高估和低估施加不对称惩罚。交叉熵用于分类,对比损失用于表征学习,均方误差只给点估计。

Q4. 以下哪些是TFT的可解释性设计?

多选题 · mid

  • A.注意力权重可视化← 正确答案
  • B.变量选择权重输出← 正确答案
  • C.随机数据增强策略
  • D.学习率自动调整

答案:AB。TFT的可解释性来自可解释注意力(权重可视化)和变量选择网络(各变量贡献权重)。随机数据增强和学习率调整是训练技巧,不直接提供解释能力。

Q5. TFT中“已知未来变量”的正确理解是什么?

单选题 · easy

  • A.预测目标真实值
  • B.未来时刻已知特征← 正确答案
  • C.历史观测的特征
  • D.随机生成的特征

答案:B。已知未来变量是未来时间段内可以提前获取的特征,如节假日、天气预报。预测目标真实值永远不能作为输入,否则造成数据泄漏。

Q6. 关于TFT门控机制的描述正确的是?

多选题 · hard

  • A.GLU输出为逐元素乘积← 正确答案
  • B.门控控制信息流动强度← 正确答案
  • C.门控机制完全移除注意力
  • D.门控用于扩大隐藏维度

答案:AB。GLU用sigmoid门值与线性变换结果逐元素相乘,门值在0到1之间控制信息流动强度。门控不替代注意力,也不负责扩大维度。

Q7. TFT区别于普通Transformer的最大特点是什么?

单选题 · easy

  • A.更强的语言生成能力
  • B.面向时序预测的多源融合← 正确答案
  • C.更深的网络层数
  • D.无监督预训练机制

答案:B。TFT专门为时序预测设计,能融合静态变量、已知未来变量和历史观测变量,并输出分位数区间。语言生成、深层网络、无监督预训练都不是它的核心定位。

Q8. 分位数 q=0.9 的预测含义是什么?

单选题 · mid

  • A.真实值始终大于预测值
  • B.真实值有90%概率低于预测值← 正确答案
  • C.预测值有90%概率低于真实值
  • D.预测值与真实值完全相等

答案:B。0.9分位数意味着 P(y ≤ ŷ) ≈ 0.9,即真实值有90%的概率不超过这个预测值。这是偏保守的高估档位,常用于设置安全库存上限。

Q9. 训练TFT时,数据预处理需要注意哪些?

多选题 · hard

  • A.按序列统一采样长度← 正确答案
  • B.充分编码时间戳特征← 正确答案
  • C.归一化每个序列目标← 正确答案
  • D.放弃缺失值不管它

答案:ABC。TFT要求固定长度序列窗口;时间戳特征(周几、小时、节假日)要显式编码;目标归一化帮助稳定训练。缺失值必须处理,不能直接丢弃。

Q10. 当分位数参数 q=0.5 时,分位数损失等价于哪个常见损失?

单选题 · extreme

  • A.平均绝对误差损失← 正确答案
  • B.均方误差损失
  • C.交叉熵损失函数
  • D.对抗生成损失函数

答案:A。q=0.5时,分位数损失变成 0.5·max(y-ŷ,0) + 0.5·max(ŷ-y,0) = 0.5·|y-ŷ|,等价于MAE。它对待高估和低估对称,所以就是绝对误差的平均。