外部环境和应用#
注意
Ray 2.40 默认使用 RLlib 的新 API 栈。Ray 团队已基本完成将算法、示例脚本和文档迁移到新代码库的工作。
如果你仍在使用旧的 API 栈,请参阅新 API 栈迁移指南了解如何迁移的详细信息。
在许多情况下,由 RLlib 来“步进”RL 环境是没有意义的。例如,如果你在具有自己执行循环的复杂模拟器(如游戏引擎或机器人模拟)中训练策略。一种自然且用户友好的方法是反转此设置——不是由 RLlib“步进”环境,而是允许模拟中的智能体完全控制自己的步进。一个外部的、由 RLlib 驱动的服务将可用于查询个体动作或接受批量样本数据。该服务负责训练策略的任务,但不限制模拟器每秒应该步进的时间和频率。
具有客户端推理的外部应用:外部模拟器(例如游戏引擎)连接到 RLlib,RLlib 通过一个支持 TCP 的自定义 EnvRunner 作为服务器运行。模拟器会不时向服务器发送批量数据,并反过来接收权重更新。为了更好的性能,动作在客户端本地计算。#
为此,RLlib 提供了一个名为 RLlink 的外部消息协议,并提供了自定义 EnvRunner
类以通过 RLlink 与一个或多个客户端通信的选项。一个基于 TCP 的、使用 RLlink 的 EnvRunner 实现示例可在此处获取:https://github.com/ray-project/ray/blob/master/rllib/examples/envs/env_connecting_to_rllib_w_tcp_client.py。它还包含一个用于测试的虚拟(CartPole)客户端,可作为你的外部应用或模拟器如何使用 RLlink 协议的模板。
注意
在 RLlib 的新 API 栈上,外部应用支持仍在开发中。Ray 团队正在努力提供更多自定义 EnvRunner 实现示例(除了已有的基于 TCP 的实现)以及各种客户端非 Python 的 RLlib 适配器,例如用于流行的游戏引擎和其他模拟软件的适配器。
RLlink 协议#
RLlink 是一个简单、有状态的协议,用于强化学习 (RL) 服务器(例如 RLlib)与充当环境模拟器的外部客户端之间的通信。该协议可以无缝交换 RL 特定的数据,如 episode、配置和模型权重,同时还促进了 on-policy 训练工作流程。
主要特性#
有状态设计:协议通过一系列消息交换(例如,
GET_CONFIG
->SET_CONFIG
这样的请求-响应对)维护一些状态。严格的请求-响应设计:该协议严格基于(客户端)请求 -> (服务器)响应。由于客户端模拟需要在自己的执行循环中运行,服务器端避免向客户端发送任何未经请求的消息。
RL 特定功能:专为 RL 工作流程设计,包括 episode 处理、模型权重更新和配置管理。
灵活采样:支持 on-policy 和 off-policy 数据收集模式。
JSON:为了更好的调试和更快的迭代,RLlink 的首个版本完全基于 JSON,未加密且不安全。
消息结构#
RLlink 消息由头部和正文组成
头部:一个 8 字节的长度字段,指示正文的大小,例如
00000016
表示一个长度为 16 的正文(因此,总消息大小为 8 + 16)。正文:JSON 编码的内容,包含一个指示消息类型的
type
字段。
示例消息:PING 和 EPISODES_AND_GET_STATE#
这里是 PING
消息的一个完整简单示例。请注意 8 字节的头部编码了后续正文的大小为 16
,紧随其后的是包含必需的“type”字段的消息正文。
00000016{"type": "PING"}
客户端在建立新连接后应发送 PING
消息。服务器随后响应
00000016{"type": "PONG"}
这里是一个由客户端发送到服务器,并携带批量采样数据的 EPISODES_AND_GET_STATE
消息示例。通过同一条消息,客户端请求服务器发回更新后的模型权重。
{
"type": "EPISODES_AND_GET_STATE",
"episodes": [
{
"obs": [[...]], // List of observations
"actions": [...], // List of actions
"rewards": [...], // List of rewards
"is_terminated": false,
"is_truncated": false
}
],
"env_steps": 128
}
所有消息类型概览#
请求:客户端 → 服务器#
``PING``
示例:
{"type": "PING"}
目的:初始握手以建立通信。
预期响应:
{"type": "PONG"}
。
``GET_CONFIG``
示例:
{"type": "GET_CONFIG"}
目的:请求相关配置(例如,单条
EPISODES_AND_GET_STATE
消息需要收集多少时间步;详见下文)。预期响应:
{"type": "SET_CONFIG", "env_steps_per_sample": 500, "force_on_policy": true}
。
``EPISODES_AND_GET_STATE``
示例:点此查看消息示例
目的:将
EPISODES
和GET_STATE
合并为一个请求。这对于在数据收集后需要进行 on-policy(同步)模型权重更新的工作流程非常有用。正文
episodes
:JSON 对象(字典)列表,每个对象都包含必需的键:“obs”(episode 中的观测列表)、“actions”(episode 中的动作列表)、“rewards”(episode 中的奖励列表)、“is_terminated”(布尔值)和“is_truncated”(布尔值)。请注意,“obs”列表由于初始的“reset”观测,比“actions”和“rewards”列表多一个项。weights_seq_no
:模型权重版本的序列号,用于确保同步。
预期响应:
{"type": "SET_STATE", "weights_seq_no": 123, "mlir_file": ".. [包含模型的二进制 .mlir 文件的 b64 编码字符串] .."}
。
响应:服务器 → 客户端#
``PONG``
示例:
{"type": "PONG"}
目的:确认收到
PING
请求以验证连接性。
``SET_STATE``
示例:
{"type": "PONG"}
目的:向客户端提供当前状态(例如,模型权重)。
正文
onnx_file
:Base64 编码的压缩 ONNX 模型文件。weights_seq_no
:模型权重的序列号,确保同步。
``SET_CONFIG``
目的:向客户端发送相关配置详情。
正文
env_steps_per_sample
:为一条EPISODES_AND_GET_STATE
消息收集的总环境步数。force_on_policy
:是否强制执行 on-policy 采样。如果为 true,客户端在发送EPISODES_AND_GET_STATE
消息后应等待SET_STATE
响应,然后再继续收集下一轮样本。
工作流程示例#
初始握手
客户端发送
PING
。服务器响应
PONG
。
配置请求
客户端发送
GET_CONFIG
。服务器响应
SET_CONFIG
。
训练 (on-policy)
客户端收集 on-policy 数据并发送
EPISODES_AND_GET_STATE
。服务器处理 episode 并响应
SET_STATE
。
注意
该协议是尝试开发一个用于外部客户端与远程 RL 服务之间通信的广泛适配协议的初步草案。随着其逐渐成熟,预计会有许多更改、增强和升级,包括增加安全层和压缩。然而,目前它提供了一个轻量、简单而强大的接口,用于将外部环境与 RL 框架集成。
示例:外部客户端连接到基于 TCP 的 EnvRunner#
这里提供了一个使用 RLlink 的基于 TCP 的 EnvRunner 实现示例:https://github.com/ray-project/ray/blob/master/rllib/env/tcp_client_inference_env_runner.py。完整的端到端示例请参阅此处:https://github.com/ray-project/ray/blob/master/rllib/examples/envs/env_connecting_to_rllib_w_tcp_client.py。
你可以随意修改自定义 EnvRunner 的底层逻辑,例如,可以实现一个基于共享内存的通信层(而不是基于 TCP 的通信层)。