跳转到主要内容

程序生成游戏型强化学习环境

项目描述

状态: 维护(预期修复错误和进行小更新)

Procgen 基准

[博客文章] [论文]

16个简单易用的程序生成gym环境,这些环境可以直接衡量强化学习代理学习泛化技能的速度。这些环境在单个核心上以高速(每秒数千步)运行。

我们在2020年举办了一场比赛,使用这些环境来衡量强化学习中的样本效率和泛化。您可以在这里了解更多信息。

这些环境与论文Leveraging Procedural Generation to Benchmark Reinforcement Learning相关(参考文献)。该论文中一些实验的代码在train-procgen仓库中。对于熟悉原始CoinRun环境的人来说,请务必阅读下面更新的CoinRun描述,因为环境已经发生了细微的变化。

Gym Retro相比,这些环境是

  • 更快:Gym Retro环境已经很快,但Procgen环境可以运行>4倍更快。
  • 随机化:Gym Retro环境始终相同,因此您可以记住一系列动作以获得最高奖励。Procgen环境是随机的,所以这不可能。
  • 可定制:如果您从源代码安装,您可以进行更改环境的实验,或构建自己的环境。每个环境的环境特定代码通常少于300行。这几乎不可能与Gym Retro相比。

支持的平台

  • Windows 10
  • macOS 10.14 (Mojave), 10.15 (Catalina)
  • Linux (manylinux2010)

支持的Python版本

  • 3.7 64位
  • 3.8 64位
  • 3.9 64位
  • 3.10 64位

支持的CPU

  • 必须至少支持AVX

安装

首先确保您有支持版本的Python

# run these commands to check for the correct python version
python -c "import sys; assert (3,7,0) <= sys.version_info <= (3,10,0), 'python is incorrect version'; print('ok')"
python -c "import platform; assert platform.architecture()[0] == '64bit', 'python is not 64-bit'; print('ok')"

安装wheel

pip install procgen

如果您遇到类似 "找不到满足要求的版本 procgen" 的错误,请升级pip: pip install --upgrade pip.

尝试交互式地测试环境

python -m procgen.interactive --env-name coinrun

按键为:左右/上/下 + q, w, e, a, s, d,执行不同的(环境相关)操作。您的得分显示在左下角。在一段游戏结束后,您可以看到最终的 "episode_return" 以及 "prev_level_complete",如果成功完成关卡,则 "prev_level_complete" 为 1

创建gym环境的实例

import gym
env = gym.make("procgen:procgen-coinrun-v0")

创建gym3(向量化)环境的实例

from procgen import ProcgenGym3Env
env = ProcgenGym3Env(num=1, env_name="coinrun")

Docker

包含了一个 Dockerfile,以演示一个基于Docker的、适用于运行随机代理的最小设置。

docker build docker --tag procgen
docker run --rm -it procgen python3 -m procgen.examples.random_agent_gym

还有一个额外的 Dockerfile,用于演示从源代码安装。

docker build . --tag procgen --file docker/Dockerfile.dev
docker run --rm -it procgen python -c "from procgen import ProcgenGym3Env; env = ProcgenGym3Env(num=1, env_name='coinrun'); print(env.observe())"

环境

观察空间是一个盒式空间,包含代理在numpy数组(形状为(64, 64, 3))中看到的RGB像素。人类玩家的期望步频为15Hz。

动作空间是Discrete(15),表示需要按下的按钮组合。按钮组合在env.py中定义。

如果您使用的是向量化环境,观察空间是一个字典空间,其中像素位于“rgb”键下。

以下是16个环境

图像 名称 描述
bigfish 玩家以一条小鱼开始,通过吃掉其他鱼变得更大。玩家只能吃掉比自己小的鱼,这仅由宽度决定。如果玩家与更大的鱼接触,玩家将被吃掉,游戏结束。玩家吃掉较小的鱼会获得少量奖励,而当玩家变得比所有其他鱼都大时,游戏结束,玩家会获得大量奖励。
bossfight 玩家控制一艘小型飞船,必须摧毁一艘更大的boss飞船。boss在与玩家交战时会从一系列可能的攻击中选择。玩家必须躲避 incoming projectiles 或被摧毁。玩家还可以使用随机散布的陨石作为掩护。经过一定时间后,boss变得脆弱,其护盾下降。此时,玩家的projectile attacks会伤害boss。一旦boss受到一定程度的伤害,玩家会获得奖励,boss会重新升起护盾。如果玩家多次以这种方式伤害boss,boss会被摧毁,玩家会获得大量奖励,游戏结束。
caveflyer 玩家必须导航一个洞穴网络以到达出口。玩家移动模仿Atari游戏“Asteroids”:飞船可以旋转并沿当前轴向前或向后移动。大多数奖励来自成功到达关卡末端,虽然玩家还可以通过使用飞船的激光摧毁沿途的目标对象来收集额外奖励。关卡中布满了固定和移动的致命障碍物。
chaser 灵感来自Atari游戏“MsPacman”。迷宫布局使用Kruskal算法生成,然后移除墙壁,直到迷宫中没有死胡同为止。玩家必须收集所有绿色球。会生成3个大型星星,收集后会暂时使敌人脆弱。与未脆弱的敌人碰撞会导致玩家死亡。当吃掉脆弱的敌人时,地图上某个位置会孵化出一个蛋,经过一段时间后会孵化成新的敌人,以保持敌人总数不变。玩家收集每个球会获得少量奖励,完成关卡会获得大量奖励。
climber 一个简单的平台游戏。玩家必须攀登一系列的平台,沿途收集星星。收集星星会获得小奖励,在一个关卡中收集所有星星会获得更大的奖励。如果收集了所有星星,该章节结束。关卡中散布着致命的飞行怪物。
coinrun 一个简单的平台游戏。目标是收集关卡最右边的硬币,玩家从最左边开始。代理必须躲避固定的锯齿障碍物、来回走动的敌人和通向死亡的峡谷。请注意,虽然之前发布的CoinRun版本直接将速度信息绘制到观察结果中,但当前版本并没有这样做。这使得环境变得更加困难。
dodgeball 灵感来源于Atari游戏“Berzerk”。玩家在具有随机配置的墙壁和敌人的房间里开始。触摸墙壁会输掉游戏并结束章节。玩家移动速度相对较慢,可以穿越整个房间。还有移动速度相对较慢的敌人,偶尔会向玩家投掷球。玩家也可以投掷球,但只能投掷他们面向的方向。如果所有敌人都被击中,玩家可以移动到解锁的平台并赢得显著的水平完成奖励。
fruitbot 一款滚动游戏,玩家控制一个机器人,必须穿越墙壁间的缝隙并收集沿途的水果。收集水果会获得正奖励,错误地收集非水果对象会获得更大的负奖励。生成对象中有一半是水果(正奖励)和一半是非水果(负奖励)。如果玩家到达关卡末尾,将获得大量奖励。偶尔玩家必须使用钥匙来解锁阻挡道路的门户。
heist 玩家必须偷走隐藏在一串锁背后的宝石。每个锁有三种颜色之一,打开这些锁的必要钥匙散布在关卡中。关卡布局采用迷宫形式,同样由克鲁斯卡尔算法生成。一旦玩家收集到某种颜色的钥匙,就可以打开该颜色的锁。玩家拥有的所有钥匙都显示在屏幕右上角。
jumper 一款具有开放世界布局的平台游戏。玩家,一只兔子,必须穿越世界寻找胡萝卜。可能需要上升或下降关卡才能做到这一点。玩家可以进行“双跳”,允许它穿越复杂的布局并到达高平台。有刺障碍物会在接触时摧毁玩家。屏幕包括一个指南针,显示胡萝卜的方向和距离。游戏中唯一的奖励来自收集胡萝卜,此时章节结束。由于允许玩家在关键对象(障碍物或目标)上出生的bug,大约7%的关卡在单一动作后就会结束,其中绝大多数将没有奖励。
leaper 灵感来源于经典游戏“Frogger”。玩家必须穿越几条车道以到达终点线并获得奖励。第一条车道包含汽车,必须避开。第二条车道包含河流上的木桩。玩家必须从木桩跳到木桩上以穿越河流。如果玩家掉入河流,章节结束。
maze 玩家,一只老鼠,必须穿越迷宫以找到唯一的奶酪并赢得奖励。迷宫由克鲁斯卡尔算法生成,大小从3x3到25x25不等。迷宫尺寸在这个范围内均匀采样。玩家可以向上、向下、向左或向右移动来穿越迷宫。
miner 受到经典游戏“BoulderDash”的启发。玩家,一个机器人,可以通过挖掘泥土来在世界中移动。世界有重力,泥土支撑着巨石和钻石。巨石和钻石会穿过自由空间并从对方滚落。如果巨石或钻石落在玩家身上,游戏就结束了。目标是收集关卡中的所有钻石,然后通过出口。收集钻石可以获得小奖励,完成关卡可以获得更大奖励。
忍者 一个简单的平台游戏。玩家,一个忍者,必须跳过狭窄的台地,同时避开炸弹障碍。如果需要,玩家可以从几个角度投掷飞镖以清除炸弹。玩家的跳跃可以在几个时间步长内蓄力以增强效果。收集关卡末尾的蘑菇可以获得奖励,此时游戏结束。
掠夺 玩家必须通过从屏幕底部的自己的船发射炮弹来摧毁敌对海盗船。屏幕上的计时器会慢慢倒计时。如果计时器耗尽,关卡结束。每次玩家开火时,计时器都会跳过几步,鼓励玩家节约弹药。玩家必须小心不要击中友军船只。击中敌舰可以获得正奖励,而击中友舰会受到大计时处罚。屏幕左下角的目标指示了应针对的敌舰颜色。
星际飞行员 一个简单的侧滚动射击游戏。对于人类玩家来说相对具有挑战性,因为所有敌人都会发射直接针对玩家的炮弹。无法快速躲避会导致玩家死亡。有快速和慢速敌人、高血量的固定炮塔、遮挡玩家视线的云彩以及不可通过的陨石。

已知问题

  • bigfish - 玩家偶尔可能被困在环境边界的周围。
  • caveflyer - 在 ~0.5% 的关卡中,玩家会在靠近敌人的地方出生,无论采取何种行动,都会在一步之内死亡。
  • jumper - 在 ~7% 的关卡中,玩家会在敌人或目标上方出生,无论采取何种行动,关卡都会在一步之后结束。
  • miner - 存在低概率的不可解关卡配置,钻石或出口无法到达。

我们计划保持环境在其最初发布的形式,而不是修补这些问题,以便于重现已经发表的结果。

环境选项

  • env_name - 环境名称,或以逗号分隔的环境名称列表,用于实例化 VecEnv 中的每个环境。
  • num_levels=0 - 可以生成的独特关卡数量。设置为 0 以使用无限关卡。
  • start_level=0 - 将用于生成关卡的最小种子。'start_level' 和 'num_levels' 完全指定了可能的关卡集合。
  • paint_vel_info=False - 在左上角绘制玩家速度信息。仅由某些游戏支持。
  • use_generated_assets=False - 使用随机生成的资产代替人类设计的资产。
  • debug=False - 如果从源代码构建,设置为 True 以使用调试构建。
  • debug_mode=0 - 一个有用的标志,会传递给 procgen 环境。在调试期间按需使用。
  • center_agent=True - 确定是否将观察集中在代理上或显示完整关卡。自行承担风险。
  • use_sequential_levels=False - 当达到关卡末尾时,剧集结束并选择新关卡。如果将 use_sequential_levels 设置为 True,达到关卡末尾不会结束剧集,新关卡种子将从当前关卡种子派生。如果您将此与 start_level=<some seed>num_levels=1 结合使用,则可以拥有类似 gym-retro 或 ALE 游戏的单一线性关卡序列。
  • distribution_mode="hard" - 使用何种关卡变体,选项有 "easy", "hard", "extreme", "memory", "exploration"。所有游戏都支持 "easy""hard",其他选项是游戏特定的。默认为 "hard"。切换到 "easy" 将减少解决每个游戏所需的步数,这在测试或使用有限计算资源时很有用。
  • use_backgrounds=True - 通常游戏使用人类设计背景,如果此标志设置为 False,游戏将使用纯黑色背景。
  • restrict_themes=False - 一些游戏从多个主题中选择资源,如果此标志设置为 True,这些游戏将只使用一个主题。
  • use_monochrome_assets=False - 如果设置为 True,游戏将使用单色矩形代替人类设计的资源。最好与 restrict_themes=True 结合使用。

以下是设置选项的方法

import gym
env = gym.make("procgen:procgen-coinrun-v0", start_level=0, num_levels=1)

由于 gym 环境是从 gym3 环境改编而来,因此禁止早期调用 reset(),且 render() 方法不执行任何操作。要渲染环境,请将 render_mode="human" 传递给构造函数,这将向环境构造函数发送 render_mode="rgb_array" 并将其包装在 gym3.ViewerWrapper 中。如果您只想获取帧而不是窗口,请传递 render_mode="rgb_array"

对于 gym3 向量化环境

from procgen import ProcgenGym3Env
env = ProcgenGym3Env(num=1, env_name="coinrun", start_level=0, num_levels=1)

要使用 gym3 环境进行渲染,请传递 render_mode="rgb_array"。如果您想查看输出,请使用 gym3.ViewerWrapper

保存和加载环境状态

如果您使用 gym3 接口,可以保存和加载环境状态

from procgen import ProcgenGym3Env
env = ProcgenGym3Env(num=1, env_name="coinrun", start_level=0, num_levels=1)
states = env.callmethod("get_state")
env.callmethod("set_state", states)

这将返回一个表示向量化环境中每个游戏状态的字节字符串列表。

注意

  • 您应该依赖于此库的特定版本(使用 ==)来进行实验,以确保它们具有可重复性。您可以使用 pip show procgen 获取当前已安装的版本。
  • 此库不需要或使用 GPU。
  • 虽然该库应该是线程安全的,但每个环境实例只能从单个线程中使用。除非您将 num_threads=0 设置,否则该库不是可分叉安全的。即使您这样做,Qt 也不保证是可分叉安全的,因此您可能需要在分叉后创建环境或根本不使用分叉。

从源代码安装

如果您想更改环境或创建新的环境,您应该从源代码构建。如果您没有 miniconda,可以从 https://docs.conda.org.cn/en/latest/miniconda.html 获取它,或者手动安装依赖项。在 Windows 上,您还需要安装 "Visual Studio 16 2019"。

git clone git@github.com:openai/procgen.git
cd procgen
conda env update --name procgen --file environment.yml
conda activate procgen
pip install -e .
# this should say "building procgen...done"
python -c "from procgen import ProcgenGym3Env; ProcgenGym3Env(num=1, env_name='coinrun')"
# this should create a window where you can play the coinrun environment
python -m procgen.interactive

环境代码是用 C++ 编写的,并将其编译成共享库,暴露了 gym3.libenv C 接口,然后由 Python 加载。C++ 代码使用 Qt 进行绘图。

创建新环境

一旦您从源代码安装,您就可以自定义现有的环境或创建自己的新环境。如果您想创建一个快速的 C++ 2D 环境,您可以从该存储库分叉并执行以下操作

  • src/games/bigfish.cpp 复制到 src/games/<name>.cpp
  • 将cpp文件中的BigFish替换为<name>,将"bigfish"替换为"<name>"
  • src/games/<name>.cpp添加到CMakeLists.txt
  • 运行python -m procgen.interactive --env-name <name>来测试

此存储库包含一个travis配置,可以编译您的环境和构建Python轮子以方便安装。为了通过缓存Qt编译来加速构建,您需要在common.py中配置一个GCS存储桶,并设置服务账户凭据

向info字典添加信息

要从C++游戏代码导出游戏信息到Python,您可以定义一个新的info_typeinfo_type出现在由gym环境返回的info字典中,或在gym3环境的get_info()中。

要定义一个新的,请在此处将以下代码添加到VecGame构造函数中:vecgame.cpp

{
    struct libenv_tensortype s;
    strcpy(s.name, "heist_key_count");
    s.scalar_type = LIBENV_SCALAR_TYPE_DISCRETE;
    s.dtype = LIBENV_DTYPE_INT32;
    s.ndim = 0,
    s.low.int32 = 0;
    s.high.int32 = INT32_MAX;
    info_types.push_back(s);
}

这使Python代码知道要期望一个整数并在info字典中暴露它。

添加后,您可以在此处添加以下代码到heist.cpp

void observe() override {
    Game::observe();
    int32_t key_count = 0;
    for (const auto& has_key : has_keys) {
        if (has_key) {
            key_count++;
        }
    }
    *(int32_t *)(info_bufs[info_name_to_offset.at("heist_key_count")]) = key_count;
}

每次观察到环境时,都会填充heist_key_count信息值。

如果您运行交互式脚本(确保您已从源代码安装),新的密钥应出现在左下角

python -m procgen.interactive --env-name heist

变更日志

查看CHANGES以了解每个版本中的更改。

贡献

查看CONTRIBUTING以获取有关贡献的信息。

资产

查看ASSET_LICENSES以获取资产许可信息。

引用

请使用以下bibtex条目进行引用

@article{cobbe2019procgen,
  title={Leveraging Procedural Generation to Benchmark Reinforcement Learning},
  author={Cobbe, Karl and Hesse, Christopher and Hilton, Jacob and Schulman, John},
  journal={arXiv preprint arXiv:1912.01588},
  year={2019}
}

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。

源代码分发

此版本没有可用的源代码分发文件。请参阅生成分发存档的教程。

构建分发

procgen2-0.10.7-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (47.6 MB 查看哈希值)

上传时间 CPython 3.11 manylinux: glibc 2.17+ x86_64

由以下赞助商支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误记录 StatusPage StatusPage 状态页面