跳转到内容

准备数据 ​

训练数据和决策流图共同描述一个建模任务:数据记录系统的运行过程,决策流图定义变量之间的依赖关系。 本节介绍轨迹数据、变量类型、节点关系和动作物理边界。需要训练策略时,还应根据业务目标定义奖励函数。

下面以配套的倒立摆数据为例,说明数据格式,以及连续、类别和有序离散变量的配置方法。 请从源码仓库根目录执行其中的命令;真实业务的抽取与对齐方法见 业务接入。

查看数据与轨迹 ​

bash
revive info --data examples/pendulum/data/pendulum.npz
text
--- 变量详情 ---
  actions              (20000, 1)      float32    min=-2.000, max=2.000, mean=-0.146
  index                (100,)          int64      min=200.000, max=20000.000, mean=10100.000
  states               (20000, 3)      float32    min=-8.000, max=8.000, mean=0.542

倒立摆数据仅包含三项内容:

名称形状含义
states[20000, 3]摆杆姿态:角度的余弦、正弦、角速度
actions[20000, 1]施加的力矩
index[100]各段运行的结束行位置:100 段,每段 200 步

本例无需单独保存 next_states。REVIVE 在每条轨迹内部使用下一行作为下一时刻的状态, 并丢弃没有后续状态的最后一行。

index 将数据划分为 100 段独立运行记录。第 199 行与第 200 行属于不同轨迹, 两者之间不存在连续的状态转移,因此系统不会跨轨迹取样。

同一轨迹内按相邻行构造状态转移,index 标记轨迹结束位置,采样不跨越边界

图:index 使用不包含结束位置的累计下标;下一状态只从同一条轨迹内取得。

定义变量、列与边界 ​

这里的“连续/离散”指变量的取值类型,不是时间是否连续采样。三种数据都需要保持时间对齐和轨迹边界。 原始数组按 [样本数, 变量维度] 保存,列顺序与 columns 一致;归一化和独热编码(one-hot)由框架处理,保存数据时无需提前转换。

业务类型配置类型如何保存配置重点
连续量,如温度、流量、力矩continuous原始量纲数值,通常用 float32写明单位;动作需声明物理 min/max
离散类别,如模式、工况编号category一列固定数字编码,如 0、1、2,不保存字符串或 one-hot用 values 列出合法编码,并单独保留编码字典
离散有序量,如等间距档位、计数discrete保存真实档位值,如 0、25、50、75、100用 min、max、num 定义等间距取值,num 至少为 2

以下 columns: 配置片段均放在 graph: 下,不是完整训练配置。

连续数据 ​

保留原始单位和数值精度,排查 NaN、无穷、故障占位值与单位混用。 状态列的范围用于数据解释,不能用观测最大最小值替代执行器物理边界。

yaml
columns:
  temperature: [{name: water_temperature, type: continuous}]
  actions: [{name: flow_setpoint, type: continuous, min: 0.0, max: 100.0}]

离散类别数据 ​

例如停机/手动/自动分别编码为 0/1/2,数组形状是 [N, 1]。 这些编号用于区分类别,其数值差不表示类别之间的距离,因此应配置为 category。

yaml
columns:
  mode: [{name: operating_mode, type: category, values: [0, 1, 2]}]

框架在内部处理类别编码;values 的列表顺序决定内部编码位置,不代表业务顺序。 训练、验证、推理必须复用同一编码字典;新类别需更新配置并重新验证,不能临时更换编号。 缺失值及 -999 等占位值需要在训练前处理。类别列通过合法值表定义取值范围,无需填写连续边界。

离散有序数据 ​

discrete 适合数值间距也有意义的等间距档位。以下为 0、25、50、75、100 五档, 档距为 (max - min) / (num - 1):

yaml
columns:
  gear: [{name: power_level, type: discrete, min: 0, max: 100, num: 5}]

仅有“低/中/高”的顺序、但无法定义间距,或合法值为 0、10、50 等不等间距集合时, 应使用 category 并列出合法值;num: 3 仅适用于三个等间距取值。 确认数据均落在合法档位;保存为浮点数也不改变其离散语义。 归一化不执行档位合法性检查,部署时仍需确认输出符合设备实际档位。

以上都是列配置片段,不是完整训练配置。不同类型可属于不同节点,也可在同一节点中按列声明; 输入输出维度和分布由列布局决定。完整规则见列与物理边界。 类别状态不能套用“类别编号相减”的增量语义;有序离散状态也不要直接套用连续 delta 配置。

声明列与物理边界 ​

graph.columns 定义每个变量各维度的含义与取值范围。下面的片段放在 graph: 下,与 nodes: 同级:

yaml
  columns:
    states: [cos_theta, sin_theta, theta_dot]
    actions: [{name: torque, min: -2.0, max: 2.0}]

列的顺序必须与数组最后一维的顺序一致。 列名用于解释各维度,并显示在日志与图表中。 例如 states 是一个输入变量,cos_theta、sin_theta、theta_dot 是它的三个维度。 ONNX 的张量名称以导出说明文件为准,不会把每个列名自动变成独立输入。

连续与有序离散动作需要显式物理 min/max;类别动作通过 values 声明合法值。 该错误表示直接策略 ONNX 导出缺少动作的原始量及处理后边界。以下保留程序报错原文便于检索:

text
preflight (kind=run, phase=onnx_action_bounds): direct policy ONNX requires explicit
physical raw and processed bounds for every action;
missing=['actions:raw', 'actions:processed']

策略的动作范围由这些边界确定。边界需要符合执行器的实际能力,避免输出设备无法执行的指令。

数据中的最大最小值不是物理边界

倒立摆力矩的 ±2.0 来自任务本身的执行器上限,而非「数据中出现过的最大力矩」。 历史运行可能只覆盖设备允许范围的一部分,因此物理边界应以设备规格或工艺规程为依据。

若难以确定,可使用工具基于数据生成候选值:

bash
revive suggest-bounds \
  --config config.yaml \
  --data train.npz \
  --ratio 1.5

工具输出的为 中心 ± 1.5 × 观测半幅,仅为候选值。已声明 min/max 的项不会被覆盖。 写入配置前需要逐项核对。revive init 使用相同规则,对倒立摆力矩给出的建议为 ±3.0,比真实上限宽了 50%。逐节点调整比例、直接写回新配置等用法见 物理边界建议。

构建决策流图 ​

倒立摆角度从竖直向上起算,状态为角度的余弦、正弦和角速度,动作为转轴力矩

图:先将物理对象对应到状态与控制量,再根据变量关系定义决策流图。

倒立摆的决策流图包含动作、状态增量和下一状态三个计算节点,其依赖关系如下:

flowchart LR
    S["<b>states</b><br/>cos θ、sin θ、θ̇"] --> A["<b>actions</b><br/>力矩(决策)"]
    S --> D["<b>delta_states</b><br/>状态变化量"]
    A --> D
    S --> N["<b>next_states</b><br/>下一时刻状态"]
    D --> N

    style S fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
    style A fill:#fff3e0,stroke:#ef6c00,color:#e65100
    style D fill:#e8f5e9,stroke:#2e7d32,stroke-width:1.5px,color:#1b5e20
    style N fill:#e3f2fd,stroke:#1565c0,color:#0d47a1

在 graph.nodes 中对应以下配置片段:

yaml
graph:
  nodes:
    actions: {inputs: [states]}
    delta_states: {inputs: [states, actions]}
    next_states: {inputs: [states, delta_states], function: builtin.delta_add}

各节点的作用如下:

  • actions — 策略节点。根据当前姿态确定施加的力矩。
  • delta_states — 世界模型节点。预测施加力矩后的状态变化。
  • next_states — 函数节点。当前值与变化量相加,属于确定的算术运算,无需学习。 builtin.delta_add 是内置函数,不必自行编写。

节点配置说明 ​

节点名即其输出变量名。 定义了名为 delta_states 的节点后,下游节点即以 delta_states 引用其输出。此约定贯穿全部配置与报错信息。

inputs 的顺序具有语义。 它决定网络输入的拼接方式。[states, actions] 与 [actions, states] 对应两个结构不同的模型,其权重不可互换。确定之后不应随意调整。

连续状态推荐预测增量,也支持直接预测下一状态。 当前示例使用默认 raw_delta: 学习 delta_X,再通过 builtin.delta_add 合成 next_X。相邻状态变化较小时, 这样可以集中学习变化部分;是否改善效果仍需对照验证。

直接预测时设置 graph.transition_contract: direct_next,将目标写成网络节点:

yaml
graph:
  transition_contract: direct_next
  nodes:
    next_states: {inputs: [states, actions]}
  columns:
    states: [cos_theta, sin_theta, theta_dot]
    actions: [{name: torque, min: -2.0, max: 2.0}]

上例是仅世界模型的图,actions 由数据或调用者提供,不要求 delta_states。 需要策略时再声明策略节点与阶段。当前版本支持 direct_next; 配套倒立摆的默认配置仍使用增量写法,可在源码的 examples/pendulum/config.min.yaml 中查看。 ADM2 依赖显式增量节点,不适用 direct_next。更改状态转移方式后,应创建新的训练任务, 旧检查点不支持按新的转移方式恢复训练。

默认情况下,next_states 节点的输出作为下一时间步 states 的输入 (transitions: auto 是默认值)。静态任务应显式声明 transitions: none。

定义奖励 ​

奖励函数用于定义策略的优化目标。它接收当前时间步的变量,返回该时间步的奖励。 倒立摆任务要求摆杆保持倒立,同时控制角速度和力矩开销,对应实现见 examples/pendulum/reward.py:

python
import torch


def get_reward(data):
    states = data["states"]                                # [B, 3] = cos θ, sin θ, θ̇
    u = torch.clamp(data["actions"][..., 0:1], -2, 2)      # [B, 1] 力矩

    theta = torch.atan2(states[:, 1:2], states[:, 0:1])    # 有符号角度,正上方为 0
    thdot = states[:, 2:3]

    costs = theta ** 2 + 0.1 * thdot ** 2 + 0.001 * u ** 2
    return -costs                                          # [B, 1],越大越好

三项代价的权重(1 : 0.1 : 0.001)分别控制姿态误差、角速度和力矩开销的相对影响。 例如,提高力矩项权重会增加大动作的惩罚,可能影响摆杆达到目标姿态的能力,需结合任务效果验证。

奖励函数的接口要求如下:函数须使用张量运算、保留批次维度、返回有限值;不得读取文件、 不得转换为 NumPy、不得在函数内生成随机数。预检会检查函数调用与导出兼容性,奖励的业务含义和数值尺度仍需自行核对。

若仅训练世界模型而不训练策略,本步骤可跳过。

准备检查与业务迁移 ​

完成倒立摆示例后,进入配置步骤前应备好以下内容:

准备内容检查结果
轨迹数据各变量时间对齐,维度和数据类型明确,index 正确标记边界
变量与边界列顺序、单位和动作物理范围与实际任务一致
决策流图节点名与变量对应,输入依赖与状态转移关系明确
奖励函数策略任务已定义奖励;仅训练世界模型时可跳过

接入自己的业务时,按“目标与变量 → 图与数据对齐 → 奖励与检查”的顺序整理。 下方实操以加氯和温控为例,说明历史数据抽取、时间可用性、轨迹划分和奖励设计;仅运行倒立摆时可直接进入下一步。

业务实操:从目标、变量字典到决策流图与奖励

从目标开始 ​

业务建模需要同时考虑变量之间的关系和数据的可用性。用户可以先根据工艺建立变量表与决策流图, 再核对数据源,补充缺失信息或调整任务范围,使图结构与数据对应。

以下按变量选择、图结构定义和数据准备的顺序说明。

从业务目标倒推候选变量 ​

历史数据通常保存在业务数据库、时序数据库或 CSV 文件中。选择变量时,需要结合业务目标、 采集情况与工艺关系。建议先确定动作和目标量,再选择相关状态与外部条件:

顺序类别选择依据加氯任务中的例子
1动作业务系统可下发的执行器设定值次氯酸钠投加泵的设定流量
2目标量评价业务效果所需的观测量或可验证计算量出水余氯浓度
3状态影响目标量动态变化的可观测变量进水余氯、加药点水温、清水池液位
4外部条件影响系统、不能由策略控制且决策时可获得的变量进水流量、原水浊度

动作应对应实际可下发的控制量,目标量应具有可观测或可验证的计算方式。两者决定模型需要学习的响应关系和奖励函数的计算依据。

状态变量应与目标量的动态变化相关。对于信息重复或关联较弱的变量,可以通过工艺分析与对照试验判断是否保留。

应当排除的三类变量 ​

以下三类需要检查是否适合进入在线模型:

  • 上线时拿不到的量。 化验室隔天出的结果、人工填报的台账、事后才计算的指标。训练时 可用而推理时不可用的变量,会导致训练与使用时的输入条件不一致,并可能使离线评估高估模型效果。
  • 由动作单向决定、不含额外信息的量。 例如泵的电流完全由泵频率决定。它不提供新信息, 可考虑用确定性函数表示,或在不参与任务时省略。
  • 同一物理量的重复测点。 三个并联测温点读数一致时,取其一或取均值,不必三个都抽。

反过来应优先评估一类变量:长滞后过程中间环节的测点。加药点至出水口之间的中途余氯、 多级换热的中间温度——它们把一段长滞后拆成几段短滞后,可能改善动态过程的可观测性,需要用对照验证。

对照数据源核对 ​

对照数据源,逐项核对候选变量:

核对项不满足时的后果
测点是否存在、有无历史必需变量缺失时,需要补充采集或调整任务定义
各变量的采样频率同时记录采样时间与可用时间;控制周期、聚合与延迟处理需共同确认
覆盖时长与工况范围数据未覆盖到的工况,模型的输出不可作为依据
历史动作是否有变化动作近乎常数时学不出「改变操作后系统如何响应」,且与数据量多少无关

历史动作的变化范围决定数据能够提供多少操作响应信息。若投加量长期固定,仅增加同类记录可能无法改善这一问题。 准备数据前,可绘制动作时间序列,检查动作变化幅度、频率及对应工况。

关键变量缺失的处理方式 ​

关键变量缺失时,可结合采集成本和业务目标选择以下处理方式:

  • 换用代理量。 目标量不可测时,找一个与之强相关且在线可测的量替代(出水余氯不可测 → 取管网首端在线余氯仪的读数)。
  • 缩小任务范围。 只在数据覆盖良好的那段工况上做决策,其余工况仍走原有控制方案。
  • 补充采集。 历史数据缺少动作变化时,可在业务允许的范围内安排试验,补充不同操作下的响应记录。

定义决策流图 ​

确定变量表后,按变量之间的计算依赖定义决策流图。配置方式与倒立摆示例一致。 以水厂加氯为例:进水流量为外部条件,投加量为动作,出水余氯为状态。

flowchart LR
    S["余氯浓度<br/>(状态)"] --> A["投加量<br/>(动作)"]
    S --> D["余氯变化量"]
    A --> D
    D --> N["下一时刻余氯"]
    S --> N

    style S fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
    style A fill:#fff3e0,stroke:#ef6c00,color:#e65100
    style D fill:#e8f5e9,stroke:#2e7d32,stroke-width:1.5px,color:#1b5e20
    style N fill:#e3f2fd,stroke:#1565c0,color:#0d47a1
yaml
nodes:
  dosage:
    inputs: [residual_cl]

  delta_residual_cl:
    inputs: [residual_cl, dosage]

  next_residual_cl:
    inputs: [residual_cl, delta_residual_cl]
    function: builtin.delta_add

与倒立摆逐一对应:dosage 是策略节点,delta_residual_cl 是世界模型节点, next_residual_cl 是函数节点。列与物理边界的写法也相同——dosage 的 min/max 取投加泵的实际流量范围,而不是历史上出现过的最大投加量。

已知且适用的确定性关系优先用公式表达。 单位换算、配比等可写成函数 节点(function:),减少需要学习的部分;但公式自身的适用条件、单位、数值误差和可微性仍需验证。 函数节点的写法(内置函数与自定义 Python 函数)见图结构。

系统存在滞后时 ​

若当前状态不足以决定下一时刻(如加药后需数十分钟才能在出水端见效、室温受数小时前的 供热功率影响),可令节点读取若干步的历史信息:

yaml
nodes:
  delta_residual_cl:
    inputs: ["residual_cl@[-6:]", "dosage@[-6:]"]

@[-6:] 表示「最近 6 步」。引号不可省略——方括号在 YAML 流式序列中具有特殊含义, 缺少引号将被解析为嵌套列表而失败。语法与适用场景见历史窗口。

已知存在滞后时,应在建模之初检查是否需要历史输入或中间状态;可将无历史模型作为对照。 多步发散还可能来自数据覆盖、时间对齐或模型误差,不能据此单独认定需要历史窗口。

按图结构准备数据 ​

确定图结构后,按节点名称组织 .npz 数据: 图中每个输入变量在数据中必须有同名数组,数据中抽出来的每个变量在图中应有下游去向。

抽取与时间对齐。 先定义决策时刻 t 对应的实际可用信息,再统一步长。 以下为预处理片段,需要 pandas 和含所示列的 raw.csv;不是适用于所有业务的固定规则。 此处显式使用右闭、右标记区间 (t-1min, t],避免把 t 之后的数据放进 t 的输入; 即使时间戳对齐,晚到的测量也不能提前使用。

python
import pandas as pd

df = pd.read_csv("raw.csv", parse_dates=["ts"]).set_index("ts")

resampled = pd.concat(
    [
        df[["dosage_sp"]].resample("1min", closed="right", label="right").last(),   # 控制量:取区间内最后一次下发值
        df[["cl_out", "q_in", "temp"]].resample("1min", closed="right", label="right").mean(),  # 测量量:取均值
    ],
    axis=1,
)

采样步长应能反映系统响应过程。步长过长可能遗漏动态变化,过短则可能使相邻步的变化接近测量噪声。 候选值需结合采集延迟、设备响应与控制周期验证。

缺失与异常的处理:

  • 短缺口仅在允许信号保持、确认无未来信息泄漏时考虑前向填充,记录最大允许间隔;
  • 长缺口不要填充,直接在缺口处切断为两段运行;
  • 传感器故障值(-9999、常数卡死、超量程)按缺口处理,不可留在数据中当作真实观测。

REVIVE 按轨迹处理时序数据,每条轨迹对应一段连续运行记录。以下事件可能使状态转移不再连续,需要据此划分运行段:

  • 停机、检修、大修
  • 控制模式切换(手动 ↔ 自动)
  • 数据缺口超过所定义的有效间隔,或无法可信填补
  • 工艺参数大改(配置方案、牌号、目标值变更)

若未标记运行段边界,停机前与重启后的相邻记录可能被当作一个状态转移样本。数据格式检查不能识别所有业务上的不连续情况。

写成 .npz 文件。 到这一步,数据已经是「按时间排序的若干段运行记录」。保存为一个 .npz 文件:

  • 每个业务变量保存为一个数组,第一维为时间轴,各数组长度一致;
  • 一个 index 数组标注各段运行的结束位置(不含该行)。

以下是保存结构示意,obs_rows / action_rows 需由自己的预处理生成,示例段长也需替换。

python
import numpy as np

obs = np.asarray(obs_rows, dtype=np.float32)        # [N, obs_dim]
action = np.asarray(action_rows, dtype=np.float32)  # [N, action_dim]
index = np.asarray([100, 250, 420], dtype=np.int64) # 三段运行

assert obs.shape[0] == action.shape[0] == index[-1]
assert np.all(np.diff(index) > 0)
assert np.isfinite(obs).all() and np.isfinite(action).all()

np.savez("train.npz", obs=obs, action=action, index=index)

index=[100, 250, 420] 表示共三段运行,分别对应第 0~99、100~249、250~419 行。

轨迹边界不可跨越

一段运行的最后一行之后并非另一段运行的第一行——这两行之间的「变化」并不真实存在。 index 的作用即在于向系统标明边界位置。标注错误不会触发报错,但会导致模型学到 不存在的转移关系。

变量的分组方式。 按节点角色组织 .npz 键。属于同一节点的物理向量分量 放在数组最后一维,例如三个温度测点可组成 [N, 3] 的 temperatures。 若需要不同的输入依赖或网络,也可拆为独立节点,并分别声明列映射。分组的依据是「哪些变量在图中扮演同一角色」——正如倒立摆把三个姿态量合并成 一个 [N, 3] 的 states。

使用 done 标志。 若数据本身带有 done 标志(每段运行的最后一行为 True),可用其 替代 index。两种方式任选其一。

独立的验证集。 如需严格的泛化评估,应按完整运行段划分为两个文件并分别传入:

bash
revive validate \
  --config config.yaml \
  --train-data train.npz \
  --val-data val.npz

未传入 --val-data 时系统将自动划分,默认以完整运行段为单位(见 data.split_mode)。划分依据不得涉及模型误差或未来标签—— 否则验证集将失去独立性。

时间可用性与轨迹边界 ​

信息决策时刻 t 能否使用处理
已到达系统的当前测量可以记录测量时间、到达时间与单位
已下发且仍有效的动作可以按实际执行与保持语义对齐
t 时已经发布的天气或排产预测可以,需版本留痕使用当时的预测值,不替换成事后真实值
下一时刻真实输出或次日化验结果不可提前作为策略输入可作训练目标或离线评估,不能伪装成当前输入
flowchart LR
    A["段 A:行 0…99"] --> X["结束位置 index = 100"]
    X -. "不构造跨段转移" .-> B["段 B:行 100…249"]
    B --> Y["结束位置 index = 250"]

图中的虚线表示存储上相邻,但动力学上不连续。末行不能连接到下一段首行; 训练目标可以使用同段下一时刻观测,策略输入只能使用决策时刻已获得的信息。 最终还应保留不参与调参的测试数据,见业务验收。

图与数据互查 ​

图结构与数据准备完成后,检查缺失输入和未使用变量,并据此调整变量表:

  • 节点缺少输入:已有测点时补充抽取;缺少测点时,选择代理量、调整任务范围或补充采集;
  • 某个变量没有任何下游 → 核对是否用于奖励、评估或外生输入;确认不参与任务后再移出模型输入。

数据保存后再用命令核对一轮:

bash
revive info --data train.npz

该命令列出数据中包含的变量、各变量的维度与取值范围,对照图的 inputs 逐项检查—— 维度不匹配是最常见的首个问题,应在编写配置之前发现。

数据量是否充足不存在通用阈值,但可通过以下三点自查:

  • 操作量是否存在变化。 若历史动作接近常数,模型将无法学到「改变操作后系统如何响应」—— 需要结合动作分布评估,不能仅根据样本数判断。
  • 工况覆盖范围。 期望模型在何种范围内决策,数据就应覆盖至该范围。
  • 单段运行时长。 至少应长于计划让模型推演的步数(第 3 步训练时的 rollout_horizon)。

写出自己的奖励函数 ​

结构与倒立摆的那份相同:取出需要的变量,算一个「越大越好」的分数。加氯任务的写法是 「余氯偏离目标值的代价 + 投药量的代价」:

python
def get_reward(data):
    # 余氯与目标值 0.5 mg/L 的偏差越小越好,投药量越少越好
    deviation = (data["next_residual_cl"] - 0.5).abs().sum(dim=-1, keepdim=True)
    cost = 0.1 * data["dosage"].abs().sum(dim=-1, keepdim=True)
    return -(deviation + cost)

两项之间的权重(此处为 0.1)用于平衡余氯达标与节约药剂的目标。 奖励函数需使用张量运算,保留批次维度,并返回有限值。

温控奖励与输入可用性示例 ​

联合动作与奖励配置见多控制节点。所有 reward 输入为 raw 物理空间,每个量 [B,1];采样周期固定为一分钟。定义三个无量纲代价:

text
tracking = ((T_next - 22 °C) / 2 °C)²
energy   = (4 kW * heater + 0.2 kW * fan²) / 4.2 kW
change   = [(heater - previous_heater)² + (fan - previous_fan)²] / 2
reward   = -(tracking + 0.1 * energy + 0.05 * change)

change 是本例以每分钟满量程变化为尺度的动作变化率代价;若采样周期不为一分钟,应使用 (u-u_prev)/Δt 并同步修改尺度。能耗项目前是归一化平均功率;固定时长比较能量时乘共同 Δt 不改变排序,不同采样周期/时域下则需要明确能量积分和奖励聚合规则。

业务检查手算结果 / 要求
T_next=22、两动作及上一动作全为 0三项为 0,reward=0
T_next=24、两动作为 1、上一动作均为 0三项均为 1,reward=-1.15
温度改用 K、功率改用 W设定值和尺度一起换算,代价不变
动作连续保持change 为 0;必须使用实际执行值,而非另一条策略的历史动作
缺上一动作完整 reward 拒绝;调用方显式提供初始上一动作
NaN、缺外生序列、动作超界模型调用端在推理前报错;不凭空补未来信息

reward.py:get_reward 提供完整三项,模型调用端逐步保存实际执行动作。当前无状态 PPO/SAC 短训配置使用 get_training_reward,只包含 tracking 和 energy;其 rollout 没有上述上一 动作状态,因此不把三项评估奖励写成训练目标。将日志里的 previous_heater 当成新策略的 上一动作会得到错误的平滑代价。三项策略训练只在业务需要动作平滑时考虑,相应 history/状态 路径需另行验证;它不是多控制节点联合优化的前置条件。

只依赖本步状态转移和动作的业务约束,可直接加入同一个 reward,例如总功率超限的归一化 平方代价。可选函数、尺度与手算示例见多控制节点。 这种奖励写法无需上一动作状态;奖励惩罚属于软约束,已有动作取值边界继续生效。 策略收益比较按具体业务问题安排,不要求先完成固定规则、两项与三项奖励的三方比较。

在一步训练中,网络损失衡量模型预测误差;reward 表达控制偏好。改变 reward 权重不会 直接使世界模型更准。先检查各分项的尺度和数据分布,再用独立业务指标判断偏好是否合理。 0.1 和 0.05 只用于教学,不是业务默认权重。

未来计划、预测、情景、真实回放的可用时刻不同,详见历史与外生输入。 不能把未来真实温度当作计划输入;也不能用事后环境实测替换上线时只有的预测。

下一步:编写配置——将图、列与奖励转化为可运行的配置。字段说明见任务定义与条件必填。