Ray RLlib SingleAgentEpisode 完全指南:新 API 栈中单智能体回合数据的存储、读取与切分

发布时间:2026/9/20 12:19:44
Ray RLlib SingleAgentEpisode 完全指南:新 API 栈中单智能体回合数据的存储、读取与切分
人工智能分布式训练强化学习任务调度模型推理服务【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址https://gitcode.com/gh_mirrors/ra/ray点击查看免费下载导读SingleAgentEpisode是 Ray RLlib 新 API 栈New API Stack中描述单个智能体一个回合Episode的核心数据结构负责按时间顺序记录 observations、infos、actions、rewards 以及各类模型附加输出如action_logp、RNN 内部状态并在此基础上提供灵活的切片、拼接、lookback 缓冲等能力。本篇文章以 single_agent_episode.rst 为骨架结合 single_agent_episode.py 的完整源码实现与 test_single_agent_episode.py 测试用例深入讲解该类的构造、数据写入、读取、回合分块cut/slice/concat以及序列化全流程帮助你理解并直接使用这一新 API 栈核心组件。一、SingleAgentEpisode 在 RLlib 新 API 栈中的定位根据 new_api_stack.rst 的说明Ray 2.40 及以后版本的 RLlib 默认启用新 API 栈算法、示例脚本和文档均已迁移到新代码库。在新 API 栈中环境交互的数据载体不再是旧式SampleBatch的单条记录流而是以回合为单位组织的Episode对象单个智能体的回合数据 →SingleAgentEpisode多智能体环境的一次完整交互 →MultiAgentEpisode内部由多个SingleAgentEpisode组合而成见 multi_agent_episode.py 中对SingleAgentEpisode的引用与封装。从源码可见SingleAgentEpisode被标记为PublicAPI(stabilityalpha)见 single_agent_episode.py是面向用户公开的 API。它在整个数据链路中的角色大致如下gym.Env.reset() ──► add_env_reset(obs, infos) gym.Env.step(a) ──► add_env_step(obs, action, reward, ...) 循环多步 │ ▼ get_observations / get_actions / get_rewards / ...读取 cut() / slice() / concat_episode() 切分与拼接 to_numpy() / get_sample_batch() / get_state() 批量化与序列化EnvRunner如 single_agent_env_runner.py会在采样过程中持续创建并填充SingleAgentEpisode随后将其交给 Learner 等下游模块使用。二、构造函数与底层数据结构SingleAgentEpisode的构造函数签名见 single_agent_episode.py如下SingleAgentEpisode( id_None, # 回合唯一 ID缺省时自动生成 uuid4().hex *, observationsNone, # 观测列表或 InfiniteLookbackBuffer observation_spaceNone, # gym.Space用于数据合法性校验 infosNone, # info 字典列表或 InfiniteLookbackBuffer actionsNone, # 动作列表或 InfiniteLookbackBuffer action_spaceNone, # gym.Space rewardsNone, # 奖励列表或 InfiniteLookbackBuffer terminatedFalse, # 回合是否已终止 truncatedFalse, # 回合是否已被截断 extra_model_outputsNone, # {action_logp: [...], ...} 等模型附加输出 t_startedNone, # 回合或分块起始的全局时间步 len_lookback_bufferauto, # lookback 缓冲长度默认 auto agent_idNone, # 归属的智能体 ID仅作引用 module_idNone, # 归属的 RLModule ID仅作引用 multi_agent_episode_idNone, # 所属 MultiAgentEpisode 的 ID )关键参数说明源码 docstring 归纳len_lookback_buffer指定保留在回合数据最左侧的历史缓冲大小。缓冲区的数据不属于当前回合分块本身仅用于向后回看以派生新数据例如做观测帧叠加时切分后的新分块需要回看上一分块的末尾数据。默认值auto会把构造时传入的全部数据都解释为 lookback 缓冲。t_started回合分块起始时间步。若传入了数据默认从最后一个观测开始计数显式传入则以给定值为准。terminated/truncated分别表示回合被环境终止或截断两者均为 False 时回合仍在进行中。内部存储InfiniteLookbackBuffer所有时序数据observations、infos、actions、rewards、extra_model_outputs都不是直接存为普通 list而是存放在InfiniteLookbackBuffer中见 infinite_lookback_buffer.py。该缓冲的核心语义维护一个lookback长度即数据左侧有多少个时间步属于历史区而不属于当前回合提供append、extend、pop、finalize列表转 numpy 批、get按索引/切片/回看语义读取、set按索引覆盖写入等方法支持嵌套结构如 dict 观测空间finalize()后叶子变为np.ndarray。值得注意的是奖励缓冲在构造时绑定了_REWARDS_BOX_SPACE gym.spaces.Box(-inf, inf, (), np.float32)见 single_agent_episode.py保证奖励数据以 float32 标量语义存储。时间步与长度的约定源码中回合的时序关系非常严格这也是 MDP 数据形态的直接体现observations / infos从 t0reset 观测一直记录到 Tactions / rewards / extra_model_outputs从 t1 记录到 T因此恒有len(observations) len(infos) len(actions) 1 len(rewards) 1见validate()single_agent_episode.pylen(episode)返回self.t - self.t_started不包含 lookback 缓冲且只有调用过add_env_step后才会从 0 变为 1。测试 test_single_agent_episode.py 的test_init印证了这些约定传入 100 条数据、len_lookback_buffer10时len(episode) 90而len(episode.rewards.data) 100说明 10 个时间步进入了 lookback 缓冲。三、写入数据add_env_reset 与 add_env_step文档把数据写入划分为两个方法正好对应gym.Env的两个核心接口。add_env_reset写入 reset 初始数据episode.add_env_reset(observationobs, infosinfo)对应env.reset()的返回初始观测 初始 info。源码single_agent_episode.py规定调用前必须满足尚未 reset 过len(observations) 0回合尚未 donet t_started 0只能用于全新空回合。调用后 observations 与 infos 各追加一项但t保持为 0智能体还没有真正走一步。is_reset属性此时返回 True。add_env_step写入一步环境交互episode.add_env_step( observationobs, # env.step 返回的下一个观测 actionaction, # 本次采取的动作 rewardreward, # 本次获得的奖励 terminatedterm, # 是否终止 truncatedtrunc, # 是否截断 infosinfo, # 环境返回的 info extra_model_outputs{ # 可选模型附加输出 action_logp: logp, state_out: state, }, )源码行为single_agent_episode.py向 observations / actions / rewards / infos 各追加一项self.t 1extra_model_outputs中每个 key 若不存在则新建InfiniteLookbackBuffer([v])存在则append(v)更新is_terminated/is_truncated标志已 done 的回合不允许再追加数据会触发断言若 episode 已被to_numpy()且设置了 space每隔 100 步校验一次观测/动作是否落在observation_space/action_space内。# 来自类 docstring 的最小可用示例CartPole-v1 import gymnasium as gym from ray.rllib.env.single_agent_episode import SingleAgentEpisode episode SingleAgentEpisode() env gym.make(CartPole-v1) obs, infos env.reset() episode.add_env_reset(obs, infos) for _ in range(5): action env.action_space.sample() obs, reward, term, trunc, infos env.step(action) episode.add_env_step( observationobs, actionaction, rewardreward, terminatedterm, truncatedtrunc, infosinfos, ) assert len(episode) 5 # reset 数据不计入长度四、读取环境数据五种 getter 与索引语义文档将get_observations、get_infos、get_actions、get_rewards、get_extra_model_outputs归为读取环境数据一组。五个方法共享同一套索引语义掌握其中一个即可触类旁通。indices 参数int / list / slice单个 int返回该索引处的单条数据无 0 轴批量维度例如episode.get_actions(-1)取最近一次动作int 列表按多个索引批量收集返回带 0 轴batch的结果例如episode.get_rewards([-1, 0])slice 对象返回一段区间例如episode.get_rewards(slice(-4, None))等价于episode.rewards[-4:]None返回全部数据ts0 到末尾。三个高级参数neg_index_as_lookback / fill / one_hot_discrete这三个参数是SingleAgentEpisode最独特、也最实用的能力源码实现见 single_agent_episode.py 的get_observationsdocstring 及 infinite_lookback_buffer.pyneg_index_as_lookbackTrue默认情况下负索引表示从末尾倒数开启后负索引被解释为ts0 左侧即回溯进入 lookback 缓冲。例如观测为[4, 5, 6, 7, 8, 9]其中[4, 5, 6]是 lookbackts0 对应 7则get_observations(-1, neg_index_as_lookbackTrue)返回 6get_observations(slice(-2, 1), neg_index_as_lookbackTrue)返回[5, 6, 7]。fill...当请求的索引区间超出 episode 边界含 lookback 左侧时用该值填充越界部分天然实现零填充。例如观测[10, 11, 12, 13, 14]lookback2时get_observations(slice(-7, -2), fill0.0)返回[0.0, 0.0, 10, 11, 12]。对于嵌套的 dict 观测空间fill会作用于所有叶子。one_hot_discreteTrue将观测/动作空间中Discrete/MultiDiscrete子分量自动转为 one-hot或 multi-one-hot向量便于直接作为神经网络输入。配合fill0使用时越界填充出来的 one-hot 向量是全零的zero-hot注意与[1, 0, 0, 0]的差异。# 类 docstring 中的典型用法在 connector 里为每个时间步构造前 4 步动作 prev_4_a [] for ts in range(len(episode)): prev_4_a.append( episode.get_actions( indicesslice(ts - 4, ts), neg_index_as_lookbackTrue, # 负索引视为进入 lookback fill0.0, # 更早的越界部分补零 one_hot_discreteTrue, # 离散子分量转 one-hot ) ) from ray.rllib.utils.spaces.space_utils import batch prev_4_actions_col batch(prev_4_a) # 汇总为叶子为 numpy 的批量结构get_infos 与 get_extra_model_outputs 的差异get_infos(indices...)返回 info 字典签名不含one_hot_discreteinfo 本身无空间结构。get_extra_model_outputs(key, indices...)第一个参数是key从extra_model_outputs字典中按 key 取对应缓冲例如episode.get_extra_model_outputs(action_logp, slice(None, -1))。五、基础信息查询get_return / get_duration_s / is_done / is_numpy / env_steps文档将以下方法归为获取基本信息的 APIget_return()返回回合累计回报实现为sum(self.get_rewards())single_agent_episode.py。注意两点① 忽略折扣因子、纯求和② 若当前实例是cut()产生的延续分块前一分块的奖励不计入lookback 缓冲中的奖励同样排除。get_duration_s()返回该回合分块的耗时秒数即_last_step_time - _start_time尚无 step 时返回 0.0。is_doneis_terminated or is_truncateddone 后不可再追加数据、不可被右侧拼接或生成后继分块。is_numpy底层奖励缓冲是否已finalize()列表转 numpy即是否已调用过to_numpy()。env_steps()返回环境步数即len(self)不含 lookback对单智能体而言agent_steps()与env_steps()数值相同多智能体场景下二者才会不同。六、回合分块与生命周期cut / slice / concat_episode / to_numpy这是文档归为创建与处理回合分块的一组方法也是新 API 栈支持非完整回合采样partial episode sampling的关键。cut从当前回合切出后继分块successor episode.cut(len_lookback_buffer2)cut()single_agent_episode.py返回一个同 ID、长度为 0的后继分块用于在不打断真实 gym 回合的前提下把当前分块交出去、稍后继续构建len_lookback_buffer0时后继只携带self最后一个观测类似一次 reset长度为 0len_lookback_buffer2时self.actions[-2:]会作为 lookback 放进后继注意t_started与t仍保持等于切分点而不是回退 2 步如果self数据量不足以满足请求的 lookback 长度该值会被自动调低前提是self尚未 done。测试 test_single_agent_episode.py 的test_cut覆盖了这一行为。slice按区间切出子回合slice(slice_)single_agent_episode.py返回一个新的SingleAgentEpisode包含指定区间的数据并自动把原 episode 的 lookback 前置到结果中。例如self含 o0~o4、a1~a4len4时self.slice(slice(1, 3))得到观测 o1,o2,o3 与动作 a2,a3——因为观测总是比动作多一个reset 观测。切片到末尾时is_terminated/is_truncated状态会保留未到末尾则重置为 False。同时支持 Python 切片语法糖slice_1 episode[:1] # 等价 episode.slice(slice(None, 1)) slice_2 episode[-2:] # 取最后两个时间步lookback 自动前置concat_episode拼接续接的分块concat_episode(other)single_agent_episode.py把other拼接到self右侧拼接合法性检查包括两者id_必须一致self.t other.t_started时间步必须无缝衔接other.observations[0]与self.observations[-1]逐叶子np.array_equal边界观测必须相同self未 done。拼接时会把self末尾的观测与 info 弹出因为它与other开头的观测重复再扩展各自的数据并合并custom_dataother优先因为作为后继分块它拥有更完整的版本。测试中的test_concat_episode与test_concat_episode_with_complex_obstest_single_agent_episode.py、test_single_agent_episode.py分别验证了普通与嵌套观测空间的拼接。to_numpy冻结数据并转 numpyto_numpy()single_agent_episode.py把所有列表形式的数据含嵌套结构转换为叶子为 numpy 数组的批量结构0 轴大小为请求批长度。调用后is_numpy变为 True不能再调用add_env_step追加数据infos永远不会被 numpy 化始终保留原始 dict 列表因为 env 返回的 info 高度异构。# 源码 docstring 示例 episode SingleAgentEpisode( observations[0, 1, 2, 3], actions[1, 2, 3], rewards[1, 2, 3], len_lookback_buffer0, ) episode.to_numpy() assert episode.is_numpy assert isinstance(episode.actions[0:2], np.ndarray)七、数据校验validatevalidate()single_agent_episode.py保证回合数据自洽len(observations) len(infos)空回合时actions / rewards / extra_model_outputs 长度也必须为 0非空回合必须满足观测比动作/奖励恰好多 1MDP 的 reset/末观测逻辑且每个extra_model_outputs缓冲长度等于观测数减 1。该校验在构造函数、add_env_reset、add_env_step、concat_episode、to_numpy、from_state等关键路径上都会被调用保证任何阶段的数据都是合法的 MDP 轨迹。八、更多实用 APIsetter、SampleBatch 转换与状态序列化虽然 single_agent_episode.rst 的 autosummary 只列出上述方法源码中还提供了与之配套的实用接口理解它们有助于掌握完整的数据流覆盖写 setter 族set_observations/set_actions/set_rewards/set_extra_model_outputssingle_agent_episode.py用于后处理阶段整体或按索引改写数据例如修改奖励、修正观测同样支持at_indices与neg_index_as_lookback。get_data_dict()/get_sample_batch()把回合转换为以ColumnsEPS_ID、T、OBS、ACTIONS、REWARDS、TERMINATEDS、TRUNCATEDS等为 key 的数据字典或SampleBatch是回合数据流向训练管线的主要出口single_agent_episode.py。get_state()/from_state()回合整体可序列化为可 pickle 的 dictgym space 会经gym_space_to_dict/gym_space_from_dict转换用于分布式传输与回放测试test_get_and_from_statetest_single_agent_episode.py验证了往返一致性。custom_data一个自由字典可从回调等位置写入自定义指标如渲染图片旧的add_temporary_timestep_data/get_temporary_timestep_data已标记Deprecated应改用custom_data。九、测试与验证仓库在 test_single_agent_episode.py 中提供了完整的单元测试覆盖初始化空/指定t_started/带 lookback 与预置数据、add_env_reset、add_env_step、各类 getter、cut、slice、concat_episode含复杂观测、get_state/from_state往返、setter 及其错误路径。阅读这些测试是快速掌握 API 语义的最佳方式例如test_init印证了 lookback 对len(episode)的影响test_getters则逐一验证了索引、切片、fill与neg_index_as_lookback的预期输出。总结SingleAgentEpisode是 RLlib 新 API 栈中以回合为单位组织单智能体轨迹的基础设施通过add_env_reset/add_env_step增量写入通过五组 getter 配合neg_index_as_lookback、fill、one_hot_discrete完成任意时刻/区间的灵活读取通过cut/slice/concat_episode支撑非完整回合采样与分块续接通过to_numpy与get_sample_batch衔接训练管线并以get_state/from_state实现序列化。无论是自定义 EnvRunner、编写 connector 做特征工程还是深度理解 RLlib 新 API 栈的数据流掌握本文所述的核心方法族都能直接受益进一步细节可深入阅读 single_agent_episode.py、infinite_lookback_buffer.py 以及对应的 测试文件。赞分享人工智能分布式训练强化学习任务调度模型推理服务【免费下载链接】rayRay is an AI compute engine. Ray consists of a core distributed runtime and a set of AI Libraries for accelerating ML workloads.项目地址https://gitcode.com/gh_mirrors/ra/ray点击查看免费下载相关推荐10分钟上手ShapesiOS开发者必备的几何视图动画库10分钟上手ShapesiOS开发者必备的几何视图动画库 Shapes是一款专为iOS开发者打造的几何视图动画框架能够帮助开发者快速实现各种复杂的图形绘制和人工智能分布式训练强化学习任务调度模型推理服务Ray RLlib 环境 API 完全指南gymnasium 单智能体、MultiAgentEnv 多智能体与 EnvRunner 数据采集体系Ray RLlib 环境 API 完全指南gymnasium 单智能体、MultiAgentEnv 多智能体与 EnvRunner 数据采集体系 导读 本文以人工智能分布式训练强化学习任务调度模型推理服务Ray RLlib MultiAgentEpisode API 完全指南多智能体强化学习的新一代 Episode 数据结构Ray RLlib MultiAgentEpisode API 完全指南多智能体强化学习的新一代 Episode 数据结构 导读 MultiAgentEpis人工智能分布式训练强化学习任务调度模型推理服务上一篇微信聊天记录永久保存真的可以免费实现吗下一篇【免费下载】 探索通信新边界双曲调频MATLAB代码推荐【matlab下载】创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考