历史窗口
历史窗口让模型读取过去若干步的观测或动作,适合描述惯性、输送延迟和未被直接测量的过程状态。本页以温度预测为例,说明窗口选择、数据对齐、训练与连续推理的方法。
使用场景
相同的当前读数可能对应不同的后续变化。例如,两台设备当前都是 22°C,一台刚结束强加热,另一台刚从高温冷却下来;由于内部储热不同,接下来一段时间的温度变化也不同。过去几步的温度和动作能帮助模型区分这两种情况。
| 任务 | 当前读数缺少的信息 | 可考虑的历史输入 |
|---|---|---|
| 温控与暖通 | 升降温趋势、墙体或设备储热 | 温度、供热动作 |
| 水处理 | 药剂输送、混合及仪表延迟 | 投加命令、流量、余氯观测 |
| 三容水箱 | 上游动作经过容积传递的影响 | 液位、泵流量 |
先核对时间对齐和当前状态是否充分,再决定是否加入历史。若三容水箱的全部液位都已测得,当前状态可能已经包含足够的储水信息;若只测到末端液位,历史输入通常更有意义。
示例:观察温度变化趋势
源码 examples/thermal_workflows/history.yaml 使用一分钟采样,在当前温度之外加入过去三步温度。以下是该文件中的节点片段:
graph:
nodes:
delta_temperature:
inputs: [temperature, heat, fan, ambient, load, "temperature@[-3:]"]
network:
backbone: thermal_tutorial_mlp
custom_params: {width: 16}
output_dist: normal在 t=3 预测时,模型同时看到当前 T[3] 和过去 T[0]、T[1]、T[2],预测下一步 T[4]。当前值与历史窗口分别声明,便于区分当前状态和过去的变化趋势。
图:历史窗口不包含当前值;当前输入直接使用变量名,未来标签不作为历史输入。
训练数据需要保留连续采样顺序与轨迹边界。不能将两次独立运行的末尾和开头拼成一个窗口。缺测、变采样周期和传感器延迟应在数据准备时处理。
配置窗口与补齐方式
历史输入语法
| 写法 | 覆盖的时刻 |
|---|---|
var@-k | 第 t−k 步 |
var@[-k:] | t−k 到 t−1 |
var@[-k:-j] | t−k 到 t−j−1 |
var@[-a,-b,-c] | 指定的若干历史时刻 |
历史索引使用负数;当前值直接写 var。含方括号的引用在 YAML 中加引号,例如 "temperature@[-3:]"。历史定义在状态变量上,使用 obs@-1,不使用转移目标 next_obs@-1。
根据业务时间尺度选择长度
可以用“需覆盖的过程时长 ÷ 采样周期”估计窗口初值。例如输送延迟约 30 分钟、每 5 分钟采样一次,可先试 @[-6:]。本例三步窗口覆盖三分钟,适合演示温度趋势输入。
窗口越长,输入维数越大。一个三维变量读取 12 步历史时,拼接宽度为 36。保持验证条件一致,比较不同窗口下的多步误差与推理耗时,再决定长度。
起始历史不足时的设置
graph:
history:
default_pad_mode: repeat_first
default_output_format: concat
init_fill_mode: repeat
detach_history: true| 字段 | 用途 |
|---|---|
default_pad_mode | 数据轨迹开头历史不足时采用 repeat_first、zeros 或 none |
default_output_format | concat 拼成长向量;stack 保留时间轴,需与网络输入接口匹配 |
init_fill_mode | 推理初始化时以 repeat、zeros 或 none 处理缺失历史 |
detach_history | 是否截断跨步历史梯度 |
窗口长度写在 inputs 的 @ 表达式中。补齐方式应符合启动过程:重复初值相当于假设此前读数接近当前值,补零则引入另一种初始条件。有真实历史时,优先用真实前缀初始化。
训练并检查效果
在仓库根目录执行。已有数据时跳过生成步骤,重新生成会覆盖示例数据。
python examples/thermal_workflows/prepare_data.py
revive validate --config examples/thermal_workflows/history.yaml
revive train --config examples/thermal_workflows/history.yaml --run-id thermal_history该配置使用连续序列训练,训练 horizon 为 4,验证 horizon 为 8。历史窗口提供的是预测起点以前的信息,horizon 表示从起点向后预测的长度,两者应分别设置。
查看 示例目录下的 logs/thermal_history/report.md。比较有、无历史的模型时,使用相同轨迹和预测窗口,关注温度趋势、外扰发生后的恢复过程及误差随预测步数的变化。
连续推理与部署
真实前缀、当前状态与未来输入
下面的命令使用训练好的模型,读取示例轨迹的真实前缀并推演八步:
python examples/thermal_workflows/consume.py \
--model examples/thermal_workflows/logs/thermal_history/models/env.pt --source replay真实前缀 当前状态与动作 预测结果
T[0:3] → T[3], u[3], e[3] → T̂[4] ... T̂[11]
未来外部条件: e[3], e[4], ... e[10]后续温度来自模型递推。动作和外部条件 e(环境温度、负载)按时间逐步提供,未来温度标签只用于评估误差。示例的 --source 标记输入来源,实际读取同一数据文件;业务预测应换成在决策时已经发布的计划、天气预报或负载预测。
为每条轨迹保存状态
带历史窗口的模型需要在调用间保存运行时状态。每条设备运行或每条独立轨迹各自维护状态,新轨迹重新初始化,同一轨迹逐步更新。
高层 EnvModel.infer_k_steps(..., prefix_data=...) 可接收真实前缀;外部序列通过 env.graph.set_static_vars(...) 声明,再按步注入。低层图预热使用 [T,B,D] 前缀,策略部署按 runtime manifest 规定的轴排列。完整代码见有状态模型调用。
导出 ONNX 后,按 manifest 的 init、warmup、step 接口完成初始化、预热和状态回传。将环境或批量切换为另一组轨迹时,应重新初始化。
常见问题
| 现象 | 处理方法 |
|---|---|
| YAML 无法解析 | 将含 @ 窗口和方括号的输入用引号括起来 |
| 提示只能使用过去索引 | 使用负索引,当前值直接写变量名 |
next_obs 无法声明历史 | 使用转移前的基础变量 obs |
| 轨迹开头误差偏大 | 检查历史补齐假设,尝试提供真实前缀 |
| 换设备或新轨迹后输出异常 | 检查是否重用了上一条轨迹的历史状态 |
| 加长窗口没有改善 | 检查数据对齐、可观测性和分工况误差,再调整窗口或网络 |
普通网络的输入拼接顺序与 inputs 声明一致;GRU 等有状态网络的训练和部署路径按输入键字母序规范化。自定义网络按 FeatureMapping 读取编译后的实际布局。改变输入布局后重新训练,避免复用不同结构的权重。