离线数据分布偏移与外推误差
理解数据占用分布、分布外动作、bootstrap 误差累积以及为什么固定 replay 会让朴素 DQN/SAC 失效。
学习目标
- 从状态与动作覆盖分析离线策略为何会利用训练误差看不到的高估。
- 独立复核“未见动作的高 Q 怎样诱导错误贪心”的输入、计算和解释。
- 支持限制能防止本例显式选择未见动作。
为什么重要
从状态与动作覆盖分析离线策略为何会利用训练误差看不到的高估。
学习前需要掌握
背景与问题
离线数据可能记录了数百万次平稳驾驶,却几乎没有急转弯。一个 Q 网络在这些记录上误差很小,仍可能给未执行的急转弯极高分;策略优化正会主动寻找这些高分,而不是按历史频率随机遇到它们。
概念定义
离线分布偏移是目标策略与数据行为策略的状态动作访问分布不同。动作层面可能在已见状态选未见动作;状态层面则可能因前几步改变而进入全新区域。固定数据无法通过新试验直接验证这些选择。
直观理解
历史地图上的空白处不能因为模型写了“距离很短”就变成可靠捷径。选择最高预测值的过程会偏向地图上最乐观、却可能最缺证据的地方。
核心原理
Bellman 训练只直接约束数据中的动作。下一状态的 max 或 actor 却可能查询数据外动作,并把误差作为目标传回数据动作,使小训练残差与严重策略错误同时存在。
覆盖不是简单总样本数:需看条件动作频率、状态区域、轨迹连续性和终止标记。某动作在别的状态出现过,不能证明它在当前状态有足够证据;低概率覆盖也可能不足以估计罕见风险。
重要性比率要求目标访问分布被数据支持,并可能因长时序变得高方差。行为约束、CQL 与 IQL 各以不同方式减少无支持改进,但没有数据或额外结构假设,就不能比较任意未见动作的反事实收益。
数学表达
占用分布密度比
当行为占用 d^β(s,a) 接近 0 而目标策略仍访问该区域时,密度比不可稳定估计,离线数据无法支持该决策。
变量含义
d^β(s,a)行为策略及环境动力学在数据中诱导的折扣占用分布。d^π(s,a)待部署策略诱导的目标占用分布。w(s,a)目标与行为占用密度比;极大值提示覆盖风险。OOD相对数据支持而言的分布外状态或动作。
计算步骤
- 1无约束贪心选择动作 2,因为 4.8 最大。
- 2仅在观察支持内比较,会选择动作 1。
- 3支持筛选只避免本例缺失动作,不说明动作 1 的长期收益已可靠。
代码对应位置
示例 1固定数据中的覆盖缺口与 OOD 动作:用动作计数展示静态数据未覆盖动作如何被函数近似器高估。
变量解释
| 变量 | 含义 |
|---|---|
d^β(s,a) | 行为策略及环境动力学在数据中诱导的折扣占用分布。 |
d^π(s,a) | 待部署策略诱导的目标占用分布。 |
w(s,a) | 目标与行为占用密度比;极大值提示覆盖风险。 |
OOD | 相对数据支持而言的分布外状态或动作。 |
完整数值示例
未见动作的高 Q 怎样诱导错误贪心
已知条件
- 数据动作计数为 [4,2,0]。
- critic 估计为 [1.0,1.3,4.8];动作 2 没有直接数据。
计算步骤
- 无约束贪心选择动作 2,因为 4.8 最大。
- 仅在观察支持内比较,会选择动作 1。
- 支持筛选只避免本例缺失动作,不说明动作 1 的长期收益已可靠。
计算结果
普通贪心选动作 2,支持内贪心选动作 1;二者差异来自缺失证据。
处理前后对比
- 支持限制能防止本例显式选择未见动作。
- 神经网络部署还会遇到相近状态泛化与长期分布变化。
计算与实现步骤
- 确认数据收集策略与时间范围
- 按终止、任务、状态簇和动作统计覆盖
- 比较行为动作与候选策略动作
- 检查 Q 在数据动作和候选动作上的间隙
- 用 BC/DQN/SAC 基线定位外推故障
- 采用约束、CQL 或 IQL 并做压力测试
代码实现
示例 1
固定数据中的覆盖缺口与 OOD 动作
example_01.py用途:用动作计数展示静态数据未覆盖动作如何被函数近似器高估。
import numpy as np
actions = np.array([0, 0, 0, 1, 0, 1]) # 数据里没有动作 2
counts = np.bincount(actions, minlength=3)
support = counts > 0
q_estimate = np.array([1.0, 1.3, 4.8])
naive_action = int(q_estimate.argmax())
masked_q = np.where(support, q_estimate, -np.inf)
supported_action = int(masked_q.argmax())
print('counts:', counts)
print('naive greedy:', naive_action)
print('support-aware:', supported_action)代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
用动作计数展示静态数据未覆盖动作如何被函数近似器高估。
Step 1 · 1–1 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import numpy as npStep 2 · 3–12 行
输出中间参数、形状或最终指标,用于核对代码是否符合预期。
actions = np.array([0, 0, 0, 1, 0, 1]) # 数据里没有动作 2
counts = np.bincount(actions, minlength=3)
support = counts > 0
q_estimate = np.array([1.0, 1.3, 4.8])
naive_action = int(q_estimate.argmax())
masked_q = np.where(support, q_estimate, -np.inf)
supported_action = int(masked_q.argmax())
print('counts:', counts)
print('naive greedy:', naive_action)
print('support-aware:', supported_action)预期输出或运行结果
counts: [4 2 0] naive greedy: 2 support-aware: 1
常见错误 · 3 条
- 只看全数据平均 TD loss,忽略策略查询动作。
- 把动作在任意位置出现过当作每个状态都覆盖。
- 把支持掩码当成真实价值或安全的证明。
实际应用
- 序贯决策
- 控制与资源分配
常见错误
- 只看全数据平均 TD loss,忽略策略查询动作。
- 把动作在任意位置出现过当作每个状态都覆盖。
- 把支持掩码当成真实价值或安全的证明。
扩展内容说明
本页数值均为解释机制的构造案例,不能解读为真实训练或基准性能。定义和适用条件参见 Levine 等:Offline Reinforcement Learning: Tutorial, Review, and Perspectives。
算法属性与数据边界
目标函数
识别并限制 d^π 相对 d^β 的不受支持偏移
数据边界
- 行为策略 β 可能未知、非平稳或由多策略混合。
- 覆盖统计只能证明看见过,不能证明奖励正确、长时序后果充分或部署安全。
- 离线调参若反复依据在线回报,会把评测环境变成隐式训练数据。
与 DQN、SAC 及相邻方法对照
- DQN 的离散 max backup 明确枚举并偏好最高估动作。
- SAC 的 actor 在连续空间优化 Q−αlogπ,可能找到数据外的 critic 漏洞。
- CQL 压低广泛动作的 Q;IQL 避免对策略生成的新动作求 Q。
失败模式、风险与性能
失败模式
- 把 replay buffer 大误当作覆盖充分
- 只看边际动作频率,忽略状态条件覆盖
- 终止/超时标记错误导致虚假 bootstrap
- 用训练集 Q 值代替策略价值评测
风险
- 历史日志可能含隐私、异常操作或已废止权限。
- 策略会利用日志中的奖励漏洞,数据清洗不能替代环境侧硬约束。
性能考虑
- 报告数据规模、轨迹数、行为策略混合和 return 分布。
- 按数据子集与随机种子报告不确定性;OOD 分数本身也需校准。
常见问题
训练损失很低为什么策略仍会失败?
损失主要在数据分布上评价;优化策略查询的数据外动作和新状态可能完全没有被该损失有效约束,误差还会经 bootstrap 传播。
网页是否会训练模型?
不会。所有图表使用固定种子或解析公式在浏览器本地计算,不执行页面中的示例代码。
推荐学习资料
Conservative Q-Learning for Offline Reinforcement Learning
在 Bellman 误差之外加入保守价值正则,降低固定数据外动作的乐观估计。
Kumar et al. · arXiv / NeurIPS
资料笔记
Farama-Foundation/Minari
为离线强化学习提供标准化数据集 API、数据集目录和数据收集工具。
Farama Foundation · GitHub
仓库信息
加载、创建和管理离线 RL 数据集
主要语言:Python包含数据集或实验需要额外环境