环境#

注意

Ray 2.40 默认使用 RLlib 的新 API 栈。Ray 团队已基本完成算法、示例脚本和文档向新代码库的迁移。

如果你仍在使用旧 API 栈,请参阅新 API 栈迁移指南了解如何迁移的详细信息。

在在线强化学习(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 actor 可以访问你的自定义环境。

在前面的示例中,env_creator 函数接受一个 config 参数。此配置主要是一个包含所需设置的字典。然而,你也可以在 config 变量中访问其他属性。例如,使用 config.worker_index 获取远程 EnvRunner 索引,或使用 config.num_workers 获取使用的 EnvRunner 总数。这种方法有助于自定义集成中的环境,并使在某些 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 worker 中运行)完成配置。Ray 之前的日志记录配置将被忽略。使用以下代码连接到 Ray 的日志记录实例

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

性能和扩缩容#

../_images/env_runners.svg

EnvRunner 与 gym.Env 设置:RLlib 中的环境位于 EnvRunner actor 内,您可以通过 config.env_runners(num_env_runners=..) 设置来扩展其数量 (n)。每个 EnvRunner actor 可以容纳多个 gymnasium 环境(向量化)。您可以通过 config.env_runners(num_envs_per_env_runner=..) 设置每个 EnvRunner 中的单个环境副本数量。此外,您可以通过 gymnasium 使用的 Python 多进程将向量中的单个子环境设为独立进程。设置 config.env_runners(remote_worker_envs=True) 可以将单个子环境创建为单独的进程并并行进行步进。#

使用 RLlib 和 gymnasium 环境扩展样本收集有两种方法。你可以结合使用这两种方法。

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

  1. 单进程内的向量化:许多环境可以达到较高的每核帧率,但受限于策略推理延迟。为了解决这一限制,可以在每个进程中创建多个环境,以在这向量化环境上批量进行策略前向传播。设置 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=..)