指南
强化学习
Oloproof 通过按回合(episode)运行强化学习策略来评估它,或依据它将要取代的那个策略的日志来评估。能运行时就运行它;当结果只会在真实世界中发生时,就使用日志。本页是这两种方式的参考,教程会在一个可运行的示例上逐一演练。
Oloproof 不托管、不重置也不模拟环境,也不训练策略。你的系统运行它自己的环境,就像 Oloproof 评估的每个系统都运行它自己的代码一样。
回合
一个任务就是一个用例。一个回合是对它的一次度量:你的系统在它的环境中运行策略,并用 current_case().rl_episode(...) 把这个回合记录为一个 rl_episode/v1 产物。
| 字段 | 类型 | 含义 |
|---|---|---|
| steps | 步骤列表,index 从 1 开始 | 每一步的 reward(奖励)、它的约束 cost(成本,默认 0),以及可选的 action 和 observation |
| success | true、false 或缺省 | 环境自己对这个回合的判定 |
| truncated | 布尔值,默认 false | 步数上限在到达终止状态之前结束了这个回合 |
| horizon | 整数,可选 | 步数上限;回合不得比它更长 |
记录包含回合的每一步。被截断的回合是评估协议定义为在其上限处结束的回合,因此它的回报(return)和成本是完整的,而不是下界。
声明系统记录的类型,这样运行就能拒绝一个需要系统从不写入的记录的评估器:
system:
name: grid-agent
callable: env:run_baseline
records: [rl_episode/v1]回合评估器
| 类型 | 度量 | 字段 |
|---|---|---|
| episode_return | 回报,每一步的奖励按 discount 逐步加权,作为分数 | return_range(必需)、discount(默认 1) |
| episode_success | 回合记录了 success: true 时通过;没有记录时为缺失 | 无 |
| episode_cost_within | 各步成本之和不超过 budget 时通过 | budget(必需) |
return_range 是每个回报都落在其中的范围,例如最差是 30 步、每步 -1,最好是到达目标的奖励。平均回报上的区间只在这个范围内成立,因此超出范围的回报会以退出码 2 停止运行。在 SDK 中,对应的类是 oloproof.evaluators 中的 EpisodeReturn、EpisodeSuccess 和 EpisodeCostWithin。
每个任务多个回合
设置 replicates: 以便为每个任务运行多个回合。current_case().replicate 说明正在运行的是哪一个(第一个为 0),它是已存储执行的键的一部分,因此用它为回合设定种子的环境会为同一次重复测量重放同一个回合,第二次运行会复用已存储的内容。
任务仍然是单位。每个判据都成为各任务的平均值,而每个任务的值是它自己在各回合上的平均值;区间按任务计数:一个任务的五个回合不是五个独立的任务。
对重复测量的任务计算的通过率,读取的是每个任务通过的回合所占比例。若要改为询问一个任务是否每次都通过,请声明一个 every_replicate 指标:
metrics:
- {id: solved_every_time, type: every_replicate, criterion: episode_success}只有当一个任务的所有回合都通过时,它才计为通过,因此每个任务是一次通过或失败,适用精确二项区间。每个任务只有一个回合时,它等于通过率。有一个回合缺失的任务即为缺失,即使它的另一个回合失败了也是如此。
比较两个策略
oloproof compare 把每个任务与它自己配对,每一侧取它在各回合上的平均值。回报的差异以回报自身的单位显示,通过率的差异以百分点显示。两次运行可以为每个任务运行不同数量的回合,但 every_replicate 指标除外:五个回合全部成功与唯一一个回合成功是不同的问题,因此不计算这种比较。当任一次运行的每个任务有多个回合时,不计算分位数和排序比较。
离策略评估
当你关心的结果只会在真实世界中发生(一张工单被解决、一位用户再次回来),而你还不能在真实流量上试用新策略时,就使用它。证据是一个较旧的策略所做决策的日志。
每个用例是一条已记录的决策:
{"id":"t001","input":{"topic":"technical","length":"short"},"expected":{"action":"small","logging_probabilities":{"small":0.7,"large":0.3},"reward":1}}| 字段 | 含义 |
|---|---|
| input | 策略做决策时看到的内容 |
| expected.action | 日志策略(logging policy)采取的动作 |
| expected.logging_probabilities | 日志策略在那一刻给每个动作的概率,总和为 1 |
| expected.reward | 随后发生的结果,位于 reward_range 之内;如果它从未到来则缺省 |
系统就是你想评估的策略。它接收 input,并在 probabilities 下(或在你用 probabilities_field 指定的字段下)返回它自己给每个动作的概率。它从不运行模型,也不触及真实世界。input 只包含日志策略做决策时看到的内容:绝不包含已记录的动作或奖励,被测策略不得看到它们。通过采样做出选择的策略,返回它采样所依据的概率,而不是它抽到的动作;即使输入重复,每条决策也会重新评估。动作的名称必须与日志中的完全一致:拼写不同的动作被视为日志策略从未采取过的动作。
| 类型 | 估计 |
|---|---|
| off_policy_value | 该策略在与已记录决策相似的决策上的平均奖励 |
| off_policy_improvement | 这个平均值减去日志策略自身的平均值 |
两者都接受 reward_range 和 propensity_floor,即日志策略给新策略可能采取的任何动作的最小概率。请依据日志策略的设计方式(探索率、最小份额)来设定它,绝不要在日志上试值。每条已记录的决策都按新策略对其动作的概率与日志策略的概率之比重新加权,而这个下限约束了该权重:没有它,任何区间都不成立。在 SDK 中,对应的类是 OffPolicyValue 和 OffPolicyImprovement。
引擎如何处理一条它无法按原样读取的决策:
| 情况 | 结果 |
|---|---|
| 概率总和不为 1、某个已记录动作的概率为 0、奖励超出 reward_range | 运行以退出码 2 停止:错误的概率会让区间出错而不显露出来 |
| 新策略可能采取一个以低于下限的概率被记录的动作 | 该决策为缺失,并按最坏情况约束 |
| 奖励缺省 | 该决策为缺失,并按最坏情况约束 |
这个答案的假设:
- 概率是在日志策略做决策时记录的,并且正是它所使用的概率。Oloproof 从不估计它们。
- 每条决策的奖励取决于它自己的输入和动作,而不取决于其他决策。
- 日志策略在日志所覆盖的时间窗口内保持相同的概率。
- 答案描述的是与已记录决策相似的决策,范围是日志所覆盖的时期。
下限较小时区间较宽:能为一个很少被选中的动作提供信息的决策很少,而每一条都被计入许多次。更长的日志,以及探索更多的日志策略,会让区间变窄。
尚未构建的功能
- 对一系列决策的离策略评估,其中每个选择都会改变接下来发生的事情。
- 策略在时间窗口内一边学习一边改变概率的日志。
- 事后估计的概率。
- 托管或重置环境和模拟器。
下一步
- 教程:评估强化学习策略:两个部分,端到端运行。
- 编写测试套件:重复测量以及其他测试套件字段。
- 配置参考:这些评估器的每个字段。