跳转到主要内容

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

项目描述

状态: 维护(预计将修复错误并发布小更新)

Procgen基准

[博客文章] [论文]

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

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

这些环境与论文利用程序生成来基准测试强化学习 (引用)相关。论文中某些实验的代码在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像素的箱空间。人类玩家的预期步速为15 Hz。

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

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

以下有16个环境

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

已知问题

  • 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 环境,你可以 fork 此存储库并执行以下操作

  • 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 wheel。为了通过缓存Qt编译使构建更快,您需要在common.py设置服务账户凭证中配置GCS bucket。

向info字典添加信息

要从C++游戏代码将游戏信息导出到Python,您可以定义一个新的info_type。这些info_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}
}

项目详情


下载文件

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

源代码分发

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

构建分发

procgen_mirror-0.10.7-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (47.6 MB 查看哈希)

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

procgen_mirror-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

支持者