环境#

在线强化学习 (RL) 中,算法通过使用 RL 环境或模拟器实时收集数据来训练策略神经网络。智能体在环境中导航,根据该策略选择动作,并收集环境的观测和奖励。算法的目标是在收集的数据上训练策略,以便策略的动作选择最终能够最大化智能体生命周期内的累积奖励。

../_images/single_agent_setup.svg

单智能体设置:一个智能体在环境中,并执行由单个策略计算出的动作。智能体到策略的映射是固定的 (“default_agent” 映射到 “default_policy”)。有关此设置在多智能体情况下的推广,请参阅 多智能体环境#

Farama Gymnasium#

RLlib 依赖 Farama 的 Gymnasium API 作为其主要的 RL 环境接口,用于单智能体训练(多智能体请参阅此处)。要使用 gymnasium 实现自定义逻辑并将其集成到 RLlib 配置中,请参阅此 SimpleCorridor 示例

提示

并非所有动作空间都与所有 RLlib 算法兼容。详情请参阅 算法概述。特别是,要注意哪些算法支持离散动作空间,哪些支持连续动作空间,或者两者都支持。

有关构建自定义 Farama Gymnasium 环境的更多详细信息,请参阅 gymnasium.Env 类定义

有关多智能体训练,请参阅 RLlib 的多智能体 API 和支持的第三方 API

配置环境#

要指定要训练的 RL 环境,您可以提供一个字符串名称或一个必须继承自 gymnasium.Env 的 Python 类。

按字符串指定#

默认情况下,RLlib 将字符串值解释为 已注册的 gymnasium 环境名称

例如

config = (
    PPOConfig()
    # Configure the RL environment to use as a string (by name), which
    # is registered with Farama's gymnasium.
    .environment("Acrobot-v1")
)
algo = config.build()
print(algo.train())

提示

对于与 Farama 注册的所有支持的环境名称,请参考以下资源(按环境类别划分)

按 gymnasium.Env 的子类指定#

如果您使用的是 gymnasium.Env 类的自定义子类,您可以传递类本身而不是已注册的字符串。您的子类必须在其构造函数中接受一个 config 参数(该参数可以默认为 None)。

例如

import gymnasium as gym
import numpy as np
from ray.rllib.algorithms.ppo import PPOConfig

class MyDummyEnv(gym.Env):
    # Write the constructor and provide a single `config` arg,
    # which may be set to None by default.
    def __init__(self, config=None):
        # As per gymnasium standard, provide observation and action spaces in your
        # constructor.
        self.observation_space = gym.spaces.Box(-1.0, 1.0, (1,), np.float32)
        self.action_space = gym.spaces.Discrete(2)

    def reset(self, seed=None, options=None):
        # Return (reset) observation and info dict.
        return np.array([1.0]), {}

    def step(self, action):
        # Return next observation, reward, terminated, truncated, and info dict.
        return np.array([1.0]), 1.0, False, False, {}

config = (
    PPOConfig()
    .environment(
        MyDummyEnv,
        env_config={},  # `config` to pass to your env class
    )
)
algo = config.build()
print(algo.train())

按 Tune 注册的 Lambda 指定#

向配置提供环境信息的第三种方法是向 Ray Tune 注册一个环境创建函数(或 lambda)。创建函数必须接受一个 config 参数,并返回一个非矢量化的 gymnasium.Env 实例。

例如

from ray.tune.registry import register_env

def env_creator(config):
    return MyDummyEnv(config)  # Return a gymnasium.Env instance.

register_env("my_env", env_creator)
config = (
    PPOConfig()
    .environment("my_env")  # <- Tune registered string pointing to your custom env creator.
)
algo = config.build()
print(algo.train())

有关使用自定义环境的完整示例,请参阅 custom_gym_env.py 示例脚本

警告

由于 Ray 的分布式特性,gymnasium 本身的注册表与 Ray 不兼容。请始终使用此处记录的注册方法,以确保远程 Ray actors 可以访问您的自定义环境。

在前面的示例中,env_creator 函数接受一个 config 参数。此配置主要是一个包含必需设置的字典。但是,您也可以在 config 变量中访问其他属性。例如,使用 config.worker_index 来获取远程 EnvRunner 的索引,或使用 config.num_workers 来获取 EnvRunner 的总数。此方法有助于自定义 ensemble 中的环境,并使某些 EnvRunner 上运行的环境与运行在其他 EnvRunner 上的环境表现不同。

例如

class EnvDependingOnWorkerAndVectorIndex(gym.Env):
    def __init__(self, config):
        # Pick actual env based on worker and env indexes.
        self.env = gym.make(
            choose_env_for(config.worker_index, config.vector_index)
        )
        self.action_space = self.env.action_space
        self.observation_space = self.env.observation_space

    def reset(self, seed, options):
        return self.env.reset(seed, options)

    def step(self, action):
        return self.env.step(action)

register_env("multi_env", lambda config: MultiEnv(config))

提示

在环境中使用日志记录时,必须在环境内部进行配置(在 Ray workers 中运行)。Ray 之前的日志配置将被忽略。使用以下代码连接到 Ray 的日志实例

import logging
logger = logging.getLogger("ray.rllib")

性能和扩展#

../_images/env_runners.svg

EnvRunner 和 gym.Env 设置:RLlib 中的环境位于 EnvRunner actors 中,其数量 (n) 可以通过 config.env_runners(num_env_runners=..) 设置进行扩展。每个 EnvRunner actor 可以包含多个 gymnasium 环境(矢量化)。您可以设置每个 EnvRunner 的单个环境副本数量,通过 config.env_runners(num_envs_per_env_runner=..) 进行设置。#

有两种方法可以扩展 RLlib 和 gymnasium 环境的样本收集。您可以将两者结合使用。

  1. 跨多个进程分发:RLlib 创建多个 EnvRunner 实例,每个实例都是一个 Ray actor,用于收集经验,这可以通过您的 AlgorithmConfig 进行控制:config.env_runners(num_env_runners=..)

  2. 单个进程内的矢量化:许多环境可以实现每核心高帧率,但受限于策略推理延迟。为了解决此限制,请在每个进程中创建多个环境,以将策略前向传递跨这些矢量化环境进行批处理。将 config.env_runners(num_envs_per_env_runner=..) 设置为每个 EnvRunner actor 创建多个环境副本。此外,您可以通过 gymnasium 使用的 Python 多进程功能,使矢量内的单个子环境成为独立进程。设置 config.env_runners(remote_worker_envs=True) 来创建单独的子环境作为单独的进程,并并行地对它们进行步进。

注意

多智能体设置尚不支持矢量化。Ray 团队正在通过使用 gymnasium >= 1.x 的自定义矢量化功能来解决此限制。

提示

有关 RLlib 大规模训练的更多信息,请参阅 扩展指南

昂贵的环境#

有些环境可能需要大量资源来进行初始化和运行。如果您的环境每个 EnvRunner 需要超过 1 个 CPU,您可以通过设置以下配置选项为每个 actor 提供更多资源:config.env_runners(num_cpus_per_env_runner=.., num_gpus_per_env_runner=..)