程序生成游戏式强化学习环境
项目描述
状态: 维护(预期修复bug和进行小更新)
Procgen基准
[博客文章] [论文]
16个简单易用的程序生成gym环境,这些环境提供了直接衡量强化学习代理学习通用技能速度的方法。这些环境在单个核心上以高速(每秒数千步)运行。
我们在2020年举办了一场比赛,使用了这些环境来衡量RL中的样本效率和泛化。您可以在这里了解更多信息。
这些环境与论文利用程序生成来评估强化学习相关(引用)。该论文中一些实验的代码在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" 显示。一局游戏结束时,您可以看到最终的 "episode_return" 以及 "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 的弹丸,否则会被摧毁。玩家还可以使用随机散布的流星作为掩护。经过一段设定的时间后,BOSS变得脆弱,其护盾下降。此时,玩家的弹丸攻击会伤害BOSS。一旦BOSS受到一定量的伤害,玩家就会获得奖励,BOSS会重新升起护盾。如果玩家以这种方式多次伤害BOSS,BOSS就会被摧毁,玩家获得大量奖励,游戏结束。 | |
caveflyer |
玩家必须导航一系列洞穴以到达出口。玩家的移动模仿了Atari游戏“小行星”:飞船可以旋转并沿着当前轴向前或向后移动。大部分奖励来自成功到达关卡终点,虽然还可以通过用飞船的激光摧毁沿途的目标对象来收集额外的奖励。在整个关卡中,都有静止和移动的致命障碍物。 | |
chaser |
灵感来自Atari游戏“MsPacman”。迷宫布局是通过Kruskal算法生成的,然后移除墙壁,直到迷宫中没有死胡同为止。玩家必须收集所有的绿色球体。生成3个大型星星,收集后会使敌人短暂地变得脆弱。与一个非脆弱的敌人碰撞会导致玩家死亡。当一个脆弱的敌人被吃掉后,地图上的某个地方会孵化出一个鸡蛋,经过一段时间后会孵化成新的敌人,保持敌人总数不变。玩家收集每个球体可以获得少量奖励,完成关卡可以获得大量奖励。 | |
climber |
一个简单的平台游戏。玩家必须攀爬一系列的平台,在途中收集星星。收集星星会有小奖励,在一个关卡中收集所有星星会得到更大奖励。如果收集了所有星星,这一集就结束了。整个关卡中散布着致命的飞行怪物。 | |
coinrun |
一个简单的平台游戏。目标是收集关卡最右侧的硬币,玩家从最左侧出生。智能体必须躲避静止的锯齿障碍物、来回走动的敌人以及通往死亡的深渊。注意,虽然之前发布的CoinRun版本直接将速度信息绘制到观察中,但当前版本没有这样做。这使得环境难度大大增加。 | |
dodgeball |
灵感来源于雅达利游戏“Berzerk”。玩家在一个随机配置墙壁和敌人的房间里出生。触碰墙壁会输掉游戏并结束这一集。玩家移动速度较慢,可以在这个房间中导航。还有移动速度较慢的敌人,它们偶尔会向玩家扔球。玩家也可以扔球,但只能朝它们面向的方向扔。如果所有敌人都被击中,玩家可以移动到解锁的平台并获得显著的关卡完成奖励。 | |
fruitbot |
一款滚动游戏,玩家控制一个机器人,必须在其间穿梭,收集水果。收集一块水果会有正奖励,错误收集非水果对象会有较大的负奖励。一半的生成对象是水果(正奖励),另一半是非水果(负奖励)。如果玩家到达关卡终点,会获得大奖励。偶尔玩家必须使用钥匙解锁阻挡道路的门。 | |
heist |
玩家必须偷走隐藏在一串锁背后的宝石。每个锁有三种颜色之一,打开这些锁所需的钥匙散布在整个关卡中。关卡布局呈迷宫状,再次由克鲁斯卡尔算法生成。一旦玩家收集到某种颜色的钥匙,就可以打开该颜色的锁。玩家拥有的所有钥匙都显示在屏幕右上角。 | |
jumper |
一款开放式世界布局的平台游戏。玩家是一只兔子,必须在这个世界中导航找到胡萝卜。可能需要上升或下降关卡才能做到这一点。玩家可以进行“双重跳跃”,允许它导航复杂的布局并到达高平台。有尖刺障碍物,一旦接触就会摧毁玩家。屏幕中包括一个指南针,显示胡萝卜的方向和距离。游戏的唯一奖励是收集胡萝卜,此时这一集结束。由于一个允许玩家在关键对象(障碍物或目标)上出生的bug,大约7%的关卡在单一操作后就会结束,其中绝大多数将没有奖励。 | |
leaper |
灵感来源于经典游戏“蛙人”。玩家必须穿越几条车道到达终点线并赢得奖励。第一组车道有汽车,必须避开。第二组车道有河流上的木头。玩家必须从一块木头跳到另一块木头以穿越河流。如果玩家掉进河里,这一集就会结束。 | |
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 获取它,或者手动从 environment.yml
安装依赖项。在 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 <名称>
来进行测试
该仓库包含一个 Travis 配置,可以编译您的环境并构建 Python 轮子以便于安装。为了通过缓存 Qt 编译来加快构建速度,您需要在 common.py 和 设置服务账户凭证 中配置一个 GCS 存储桶。
向 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}
}
项目详情
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源代码分发
构建分发
哈希值 for procgen-0.10.7-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 4b594d14e42f0f2166e59a9e294477b906eb99c90c3343b570b7124cbc865f53 |
|
MD5 | 8c5a6413f93fa85cd7ff1072dc9d764c |
|
BLAKE2b-256 | eb9e4dea48895a9350ff045ae724cbebf1fb8f2d2eafff16b6a39fc8842e1084 |
哈希值 用于 procgen-0.10.7-cp310-cp310-macosx_10_9_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 277c0e781dc80ec568f0da428185d0b767ff1b6610304af85c7b7522d0ecfec6 |
|
MD5 | bbff10ffa8bc765d4c143bbe819c5ada |
|
BLAKE2b-256 | 99a65a05b24fab236a9bd09a592cb21def870a732f68a21c48b52dac0089d7ec |
哈希值 用于 procgen-0.10.7-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 2987d6e37cd532fa96f8c9d76104f51f3a3df9310c668a62cd4f9859245a3797 |
|
MD5 | 4773e8befd85e3353d17bb20587702ea |
|
BLAKE2b-256 | ddae6fdda3b2cb05e428db798c19ad582f2ef74fa9722b16b86d8b64cccb0577 |
哈希值 用于 procgen-0.10.7-cp39-cp39-macosx_10_9_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 852d917f4ba9ba6e1c59a5c69747874660177e496e5c02b19ab2dd146101bd16 |
|
MD5 | 37f6ab4bcb8d13b556b266af8e425da1 |
|
BLAKE2b-256 | 5ce81883259907e9cd61121ca9738db10caea8b2f5ab10ca14a21e06bc2eca72 |
哈希值 用于 procgen-0.10.7-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 9add41424c574cfb5c98b87121dfd5d660737d354020aea5bca459fb072cb831 |
|
MD5 | 9fc1cf0fc7a782a201f48a69aadaa09b |
|
BLAKE2b-256 | 46f42bd12e01d7c3528f8dffe6719b775e2daec840f32157043bffaa0acbf404 |
哈希值 用于 procgen-0.10.7-cp38-cp38-macosx_10_9_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 4a42a83922580d26ca1dcc3f814a3e9311d99d0fcc222898accff4a6632023c4 |
|
MD5 | ad0e8aca908336ffd91865937bcf9f8e |
|
BLAKE2b-256 | 1b3236aa672766d2dcbf82c8724aa4159c35ab5a07b3a5a541fa3a7840129d3a |
哈希值 用于 procgen-0.10.7-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 6a61be92dcdd3cc4ba1d4f5d2535d13faf0a86433a99f8757c1891f5ac46b8fd |
|
MD5 | 2a3e1ca81c4b9257b38d53a0fde57d66 |
|
BLAKE2b-256 | 36523e4c2ce539c0ffc18a6dca9a9c997299dc90ec9d8f067c61e60d8024b746 |
哈希值 用于 procgen-0.10.7-cp37-cp37m-macosx_10_9_x86_64.whl
算法 | 哈希摘要 | |
---|---|---|
SHA256 | a5ae5421b83b6e0757c6b0ecd5156a04c739878ce42d5bb5eca1318c190aeed4 |
|
MD5 | 3b0cf74ffb46943bba3b261ac5ec06fc |
|
BLAKE2b-256 | d63ce3e75aaaf4583712380daf20c69d33dfbd29908d738d1d7d1cb04b698c37 |