TextWorldExpress: 专注于指令跟随、常识推理和对象识别的三个文本游戏基准的高度优化重实现。
项目描述
TextWorldExpress
TextWorldExpress是三个文本游戏基准的高度优化重实现,专注于指令跟随、常识推理和对象识别。TextWorldExpress旨在用于自然语言处理研究,可以在Arxiv预印本TextWorldExpress: 每秒模拟一百万步文本游戏(PDF)中找到系统描述。
在YouTube上观看系统演示视频
快速入门
运行前: 您必须在系统上安装Java 1.8+
(大多数Linux发行版都附带)。
使用pip安装
conda create --name textworld-express python=3.8
conda activate textworld-express
pip install textworld-express
运行示例随机代理,在Coin Collector游戏中...
python examples/random_agent.py --game-name=coin
运行用户控制台,您可以与环境交互,在CookingWorld...
python examples/human.py --game-name=cookingworld
Web服务器演示
还提供了一个Web服务器演示,允许在Web浏览器中交互地运行TextWorldExpress用户控制台。
运行Web服务器演示
conda create --name textworld-express python=3.8
conda activate textworld-express
pip install textworld-express[webserver]
运行Web服务器
python examples/textworldexpress-web-server.py
将您的网络浏览器指向localhost:8080。
TextWorldExpress设计
TextWorldExpress用Scala(2.12.9)编写,并使用sbt
编译成JAR文件,然后用java
运行。为了方便起见,提供了一个python
API,该API使用py4j
包进行接口。
环境
TextWorldExpress包括三个流行的文本游戏研究基准环境的高速版本。此外,它还包括4个独家环境,用于研究算术、导航和神经符号推理。
CookingWorld ("cookingworld")
烹饪世界环境将任务分配给智能体,要求它们根据环境中提供的菜谱说明准备餐点。智能体必须首先收集环境中的必需食材(例如,牛奶、甜椒、面粉、盐),这些食材可以在规范位置(例如,厨房、储藏室、超市、花园)和容器(例如,冰箱、橱柜)中找到。随机生成的菜谱要求智能体首先使用刀将部分食材切片、切丁或切碎,然后使用合适的加热设备油炸、烤制或烧烤食材。如果所有食材都按照菜谱准备好,智能体可以使用动作准备餐点,最后享用餐点以成功完成任务。可以通过改变环境中位置的数量、菜谱所需食材的数量以及随机放置在环境中的不需要的干扰食材的数量来控制任务复杂度。菜谱和环境是参数化生成的,食材的子集和具体的准备方式在训练、开发和测试集中分离,以防止过拟合。烹饪世界最初是为第一文本世界问题竞赛创建的,后来被[Madotto etal., 2020]命名。
TextWorld 常识 ("twc")
文本游戏智能体通常通过与环境本身交互来学习环境的动态,例如,在通过门前需要先打开门,而不是使用预先存在的常识事实或对象属性知识库来加速任务学习。TextWorld 常识[Murugesan etal., 2021]旨在通过为智能体提供一个清洁任务,评估它们无法直接从环境中学习的常识知识。在这个任务中,智能体必须将常见的家庭物品(例如,脏盘子)放置在它们在知识库(例如,ConceptNet)中可以找到的规范位置(例如,洗碗机)。在训练、开发和测试集中使用不同的对象列表,这意味着智能体不能仅从训练集中学习对象位置,而必须依赖外部常识知识库来在开发和测试集中表现良好。TextWorld 常识基准有三个任务难度级别,其中最简单的包括一个位置和一个需要放置的物体,而困难设置包括多达11个位置和任意数量的任务相关和干扰物体。
硬币收集者 ("coin")
智能体经常发现对象搜索、环境导航或拣选放置等任务具有挑战性。Coin Collector[Coin Collector]将这些挑战汇总成一个基准,在这个基准中,智能体必须探索一系列房间来定位并捡起一枚硬币。在原始实现中,游戏地图通常采用连接的环路或链的形式,这样不断移动到新的位置意味着智能体最终会找到硬币——而中等和困难模式则添加了一个或多个“死胡同”路径。为了控制游戏中的环境难度,TextWorldExpress重实现使用相同的地图生成器跨环境,并生成任意的家庭环境而不是连接的环路。用户控制其他难度指标,包括房间总数和环境中放置的干扰物体数量。
地图阅读者 ("mapreader")
Map Reader环境要求智能体从特定位置取回一枚硬币,并将其放入起始位置找到的盒子里。与Coin Collector相比,该环境提供了一个智能体可以用来更有效地导航的环境地图。取回硬币得分为0.5分,将硬币放入起始位置的盒子得分为1.0分。可以通过改变环境中的位置数量、起始位置与硬币之间的距离以及环境中随机放置的干扰对象数量来控制任务复杂度,这些干扰对象不是完成任务所必需的。
算术("算术")
算术环境要求智能体首先解决一个数学问题,然后捡起与数学问题答案相同数量的物品,并将其放入盒子中。例如,智能体可能阅读数学问题(“拿出与3乘以6相等的物品束,放入盒子中”),然后必须执行算术,然后拿18个苹果放入答案盒子。干扰物品与执行算术错误相对应(例如,包括3个橙子,对应于从6中减去3,以及2个梨,对应于6除以3),结果必须是正整数。捡起正确物品得分为0.5分,成功完成任务得分为1.0分。目前,尚不能控制任务复杂度。
排序("排序")
排序环境要求智能体根据数量增加的顺序,逐个将物品放入答案盒子中。为了增加游戏复杂度,数量可以包括单位(例如,5kg的铜,8mg的钢,2g的铁),涵盖体积、质量或长度的度量。得分是正确排序的物品的归一化比例,完美排序得分为1.0分,错误会导致得分降为零,游戏结束。需要排序的物品数量在3到5之间。目前,尚不能控制任务复杂度。
用法
典型用法,以及有效动作生成
典型用法涉及首先初始化游戏生成器,然后反复生成和执行游戏。/examples/文件夹中提供了示例,其中包含一个在每个步骤中选择随机动作的示例智能体。
import random
from textworld_express import TextWorldExpressEnv
# Initialize game generator
env = TextWorldExpressEnv(envStepLimit=100)
# Set the game generator to generate a particular game (cookingworld, twc, or coin)
env.load(gameName="twc", gameParams="numLocations=3,includeDoors=1")
# Then, randomly generate and play 10 games within the defined parameters
for episode_id in range(10):
# First step
obs, infos = env.reset(seed=episode_id, gameFold="train", generateGoldPath=True)
# Display the observations from the environment.
print(obs)
for step_id in range(0, 50):
# Select a random valid action
validActions = sorted(infos['validActions'])
randomAction = random.choice(validActions)
# Take that action
obs, reward, done, infos = env.step(randomAction)
# Display action and the game's feedback.
print(">", randomAction)
print(obs)
设置游戏参数
环境使用默认参数初始化。要更改参数,在调用env.load()
时向gameParams
提供一个以逗号分隔的字符串。CookingWorld的有效参数配置字符串示例可能为numLocations=5, numIngredients=3, numDistractorItems=0, includeDoors=0, limitInventorySize=0
。每个环境的有效参数不同,包括
CookingWorld
参数 | 描述 | 有效范围 |
---|---|---|
numLocations | 环境中位置的数量 | 1-11 |
numIngredients | 用于生成随机菜谱的食材数量 | 1-5 |
numDistractorItems | 环境中干扰食材(即不用于菜谱的食材)的数量 | 0-10 |
includeDoors | 房间是否有需要打开的门 | 0或1 |
limitInventorySize | 是否限制库存大小 | 0或1 |
TextWorld常识
参数 | 描述 | 有效范围 |
---|---|---|
numLocations | 环境中位置的数量 | 1-3 |
numItemsToPutAway | 需要放入的物品数量 | 1-10 |
includeDoors | 房间是否有需要打开的门 | 0或1 |
limitInventorySize | 是否限制库存大小 | 0或1 |
Coin Collector
参数 | 描述 | 有效范围 |
---|---|---|
numLocations | 环境中位置的数量 | 1-11 |
numDistractorItems | 环境中干扰(即非硬币)物品的数量 | 0-10 |
includeDoors | 房间是否有需要打开的门 | 0或1 |
limitInventorySize | 是否限制库存大小 | 0或1 |
Map Reader
参数 | 描述 | 有效范围 |
---|---|---|
numLocations | 环境中位置的数量 | 1-50 |
maxDistanceApart | 找到硬币之前要经过的位置数量 | 1-8 |
maxDistractorItemsPerLocation | 每个位置的最大干扰(即非硬币)物品数量 | 0-3 |
includeDoors | 房间是否有需要打开的门 | 0或1 |
limitInventorySize | 是否限制库存大小 | 0或1 |
算术:该环境目前尚无可调整的参数。
排序:该环境目前尚无可调整的参数。
查询当前游戏参数:有时您可能想知道当前游戏使用哪些参数生成。这些参数可以通过使用 getGenerationProperties()
方法进行查询。
print("Generation properties: " + str(env.getGenerationProperties()))
金路径
可以通过在调用 reset()
时将 generateGoldPath
标志设置为 true
来生成金路径。路径本身可以通过使用 env.getGoldActionSequence()
方法获取。
print("Gold path: " + str(env.getGoldActionSequence()))
请注意,金路径是由在环境中一般进行随机漫步的代理生成的,因此虽然它们可以完成成功任务,但可能不是最短/最有效的路径。例如,Text World Common Sense 这个路径在环境中徘徊,直到它看到可以捡起的对象(例如,拿起白色外套),或者可以放置对象的合适容器(例如,将白色外套放入衣柜)。
金路径:['环顾四周', '向西移动', '拿起白色外套', '拿起刷子', '打开衣柜', '将白色外套放入衣柜', '向东移动', '向西移动', '向东移动', '向西移动', '向东移动', '向西移动', '向东移动', '向北移动', '拿起眼线笔', '拿起格子毯', '将眼线笔放入梳妆台', '打开浴室柜', '将刷子放入浴室柜', '向南移动', '向北移动', '向南移动', '向西移动', '打开抽屉柜', '将格子毯放入抽屉柜', '向东移动']
生成预爬路径
TextWorldExpress
的一个独特特性是它的性能非常快,因此可以预先爬取假设代理可能会为给定游戏采取的所有可能动作,直到一定步数。这有几个主要优点和缺点。
- 优点:游戏速度显著提高 - 通常,与使用指针遍历树的速度一样。在 Scala 中,遍历的单线程性能已基准测试为每秒 4-5 百万步。
- 缺点:预先爬取路径需要一些初始时间(一次性投资;通常几分钟到几小时)。
- 缺点:在每次运行的开始加载路径需要时间(通常几秒到几分钟)。
- 缺点:存储预爬路径可能需要大量空间(通常每场游戏/种子高达 1GB,对于大约 10-12 步的树,取决于游戏)。
- 缺点:存在有限的步长范围 - 一旦代理超过预先爬取的步数,就没有更多信息可以提供。因此,仅对足够小、可以在预先爬取的步数内解决的游戏进行预先爬取非常重要。
通常,如果您在训练期间使用不到几十个游戏变体,并且使用可以在 10-12 步内解决的游戏,那么路径预先爬取可能是提高性能的一种方式。
要预先爬取路径,请使用路径预先爬取工具 PathCrawler
。
java -Xmx8g -cp textworld_express/textworld-express-1.0.0.jar textworldexpress.pathcrawler.PathPrecrawler twc train 0 8 numLocations=1,includeDoors=0,numItemsToPutAway=2
(请注意,根据正在爬取的路径的大小,可能需要提供超过 8g
的内存。)
参数(按顺序)是 gameName
、gameFold
、seed
、爬取游戏状态树的深度上限
和 游戏生成属性字符串
。路径爬取器将导出一个大型的 JSON 文件作为输出。要在 Python 中加载这些预先爬取的路径,请检查 precrawledPathReader.py
示例。对于 Java/Scala,请参阅 textworldexpress.benchmark.BenchmarkPrecrawledPath
作为端到端示例,其中 textworldexpress.pathcrawler.PrecrawledPath
提供了一个用于加载/保存预先爬取路径(以及快速找到获胜路径)的存储类。路径节点作为字符串散列存储类(PrecrawledNode
和 StepResultHashed
)内部存储,以提高速度/存储效率,其中 StepResultHashed
可以使用 StepResultHashed.toStepResult()
方法快速转换为正常的、人类可读的、未散列版本。提供了一些示例预先爬取路径(用于基准测试脚本),位于 precrawledpaths.zip
中。
路径爬取可能会生成大文件。在进行路径爬取之前,您可能需要确保游戏大小适当,以便在给定的步数内解决。通常,这意味着限制位置数量、任务物品数量等。以下是在16核机器上使用以下参数生成的Text World Common Sense游戏的示例时间和爬取大小:numItemsToPutAway=2, numLocations=3, includeDoors=0, limitInventorySize=0
深度 | 爬取时间 | 节点数量 |
---|---|---|
7 | 2秒 | 198k |
8 | 23秒 | 1.6M |
9 | 209秒 | 13.5M |
基准测试
Python基准测试
在线生成模式
python examples/random_agent_speed_test.py --game-name=cookingworld --max-steps=50 --num-episodes=10000
预爬取路径模式(注意此演示使用存储库中提供的用于基准测试的预爬取路径)
unzip precrawledpaths.zip
python examples/precrawledPathReader.py
Scala基准测试
在线生成模式(参数应为cookingworld、twc或coin之一)
java -Xmx4g -cp textworld_express/textworld-express-1.0.0.jar textworldexpress.benchmark.BenchmarkOnline coin
预爬取路径模式(单线程,注意此演示使用存储库中提供的用于基准测试的预爬取路径)
java -Xmx4g -cp textworld_express/textworld-express-1.0.0.jar textworldexpress.benchmark.BenchmarkPrecrawledPath
为了提高速度,可以进行线程化的预爬取路径基准测试(在此,将32
更改为所需线程数)
java -Xmx4g -cp textworld_express/textworld-express-1.0.0.jar textworldexpress.benchmark.BenchmarkPrecrawledPathThreaded 32
常见问题
问:为什么Python版本比Java/Scala版本慢10倍?答:这部分原因是因为py4j
绑定器,它允许通过套接字将Python与Java/Scala代码接口。虽然我们将在未来寻找更快的解决方案,但Python与TextWorldExpress
的接口仍然比原始TextWorld快约100倍,所以仍然是一个很大的进步。
问:是否会有更多基准测试游戏添加/我想将我的基准测试游戏添加到TextWorldExpress中答:TextWorldExpress获得速度的主要方法是通过基本上硬编码游戏、机制以及(尤其是)有效的动作生成。要实现您自己的游戏,请使用现有游戏作为模板,并在遇到任何问题的情况下在GitHub上创建一个问题。如果您想推荐添加到TextWorldExpress中的新游戏,请在GitHub问题中提出功能请求。
问:TextWorldExpress最快能运行多快?答:我们使用随机代理基准测试测得的TextWorldExpress
最快速度为每线程每秒4-5百万步,使用预爬取游戏和Scala原生API,多线程性能约为每秒3400万步,使用AMD 3950X 16核CPU和32线程。这相当于每分钟约20亿步。20亿步对于原始TextWorld的单线程来说需要大约77天。
引用
如果您使用TextWorldExpress
,请提供以下引用
@article{jansen2022textworldexpress,
url = {https://arxiv.org/abs/2208.01174},
author = {Jansen, Peter A. and Côté, Marc-Alexandre},
title = {TextWorldExpress: Simulating Text Games at One Million Steps Per Second},
journal = {arXiv},
year = {2022},
}