Shortcuts

煮过头了

概述

Overcooked-AI 是一个用于完全合作的人机任务性能的基准环境,基于广受欢迎的视频游戏 Overcooked

游戏的目标是尽可能快地递送汤。每份汤需要将最多3种食材放入锅中,等待汤煮熟,然后让一个代理拿起汤并递送它。

此环境可用于测试协作代理的鲁棒性、RL代理与人类之间的交互等。

环境仍在开发中,但目前已有六篇研究论文正在使用Overcooked-AI,你可以在原始的Overcooked-AI仓库中找到这些论文。

原始的 overcooked-ai 仓库包含了 5 种可用的布局,如下所示:

../_images/overcooked_layouts.gif

新布局很容易硬编码或通过编程生成。

安装

安装方法

安装 overcooked-ai。你可以通过命令 pip 安装或从源代码构建。

# Method1: Install Directly
pip install overcooked-ai
# Method2: Build from source
git clone https://github.com/HumanCompatibleAI/overcooked_ai.git
pip install -e overcooked_ai/

安装检查

安装完成后,您可以通过以下命令检查是否成功:

cd DI-engine
pytest -sv dizoo/overcooked/envs/test_overcooked_env.py

RL 环境空间

观察空间

  • 目前我们使用cramped_room设置来描述overcooked环境的观察空间。cramped_room的布局形状为(5, 4)

  • 包含2个代理。

  • 每个代理的观测形状是 (layout_width, layout_height, 26) ,即对于cramped_room来说是 (5, 4, 26)

  • 如果在环境中使用 concat_obs,那么观测形状将是 (2*layout_width, layout_height, 26),否则观测形状将是 (2, (layout_width, layout_height, 26))

  • 如果启用了action_mask,观察结果还将返回一个action_mask,它将不可用的动作屏蔽为零(而一表示动作可用)。action_mask的形状为(2, 6)

动作空间

  • 动作空间也包含2个代理。

  • 游戏中使用的按钮。通常有6个离散动作(N在不同的子环境中有所不同)。

  • 动作的含义。 - 0:北(上)

    • 1:南(下)

    • 2:东(左)

    • 3:西(右)

    • 4:停留

    • 5:互动

奖励空间

  • 《煮糊了》的游戏分数。

  • 请注意,我们使用了奖励塑形来简化训练过程。您可以通过将use_shaped_reward设置为TrueFalse来开启或关闭奖励塑形。

其他

  • 游戏在固定的步数后结束(默认设置为400步)。

关键事实

  1. 环境中包含两个代理。

  2. 离散动作空间。

  3. 如果我们设置use_shaped_rewardFalse,奖励可能会很稀疏。

其他

不同的布局

你可以通过更改环境配置中的env_name来改变使用的布局。然而,overcooked环境仍在开发中,因此并非所有布局都受支持。

你也可以手动编写自己的布局,参考此链接获取布局文件

DI-zoo 代码示例

完整的训练配置在github链接。 你可以按照以下方式运行演示:

from ding.config import compile_config
from ding.worker import BaseLearner, Episode1v1Collector, OnevOneEvaluator, NaiveReplayBuffer
from ding.envs import BaseEnvManager, DingEnvWrapper
from ding.policy import PPOPolicy
from dizoo.overcooked.models.overcooked_vac import BaselineVAC
from ding.utils import set_pkg_seed
from dizoo.overcooked.envs import OvercookGameEnv
from dizoo.overcooked.config import overcooked_demo_ppo_config


def wrapped_overcookgame():
    return OvercookGameEnv({})


def main(cfg, seed=0, max_iterations=int(1e10)):
    cfg.exp_name = 'selfplay_demo_ppo'
    cfg = compile_config(
        cfg,
        BaseEnvManager,
        PPOPolicy,
        BaseLearner,
        Episode1v1Collector,
        OnevOneEvaluator,
        NaiveReplayBuffer,
        save_cfg=True
    )
    collector_env_num, evaluator_env_num = cfg.env.collector_env_num, cfg.env.evaluator_env_num
    collector_env = BaseEnvManager(env_fn=[wrapped_overcookgame for _ in range(collector_env_num)], cfg=cfg.env.manager)
    evaluator_env1 = BaseEnvManager(
        env_fn=[wrapped_overcookgame for _ in range(evaluator_env_num)], cfg=cfg.env.manager
    )
    evaluator_env2 = BaseEnvManager(
        env_fn=[wrapped_overcookgame for _ in range(evaluator_env_num)], cfg=cfg.env.manager
    )

    collector_env.seed(seed)
    evaluator_env1.seed(seed, dynamic_seed=False)
    evaluator_env2.seed(seed, dynamic_seed=False)
    set_pkg_seed(seed, use_cuda=cfg.policy.cuda)

    model1 = BaselineVAC(**cfg.policy.model)
    policy1 = PPOPolicy(cfg.policy, model=model1)
    model2 = BaselineVAC(**cfg.policy.model)
    policy2 = PPOPolicy(cfg.policy, model=model2)

    tb_logger = SummaryWriter(os.path.join('./{}/log/'.format(cfg.exp_name), 'serial'))
    learner1 = BaseLearner(
        cfg.policy.learn.learner, policy1.learn_mode, tb_logger, exp_name=cfg.exp_name, instance_name='learner1'
    )
    learner2 = BaseLearner(
        cfg.policy.learn.learner, policy2.learn_mode, tb_logger, exp_name=cfg.exp_name, instance_name='learner2'
    )
    collector = Episode1v1Collector(
        cfg.policy.collect.collector,
        collector_env, [policy1.collect_mode, policy2.collect_mode],
        tb_logger,
        exp_name=cfg.exp_name
    )
    # collect_mode ppo use multimonial sample for selecting action
    evaluator1_cfg = copy.deepcopy(cfg.policy.eval.evaluator)
    evaluator1_cfg.stop_value = cfg.env.stop_value
    evaluator1 = OnevOneEvaluator(
        evaluator1_cfg,
        evaluator_env1, [policy1.collect_mode, policy2.collect_mode],
        tb_logger,
        exp_name=cfg.exp_name,
        instance_name='selfplay_evaluator1'
    )
    evaluator2_cfg = copy.deepcopy(cfg.policy.eval.evaluator)
    evaluator2_cfg.stop_value = cfg.env.stop_value
    evaluator2 = OnevOneEvaluator(
        evaluator2_cfg,
        evaluator_env2, [policy2.collect_mode, policy1.collect_mode],
        tb_logger,
        exp_name=cfg.exp_name,
        instance_name='selfplay_evaluator2'
    )

    for _ in range(max_iterations):
        if evaluator1.should_eval(learner1.train_iter):
            stop_flag1, reward = evaluator1.eval(learner1.save_checkpoint, learner1.train_iter, collector.envstep)
            tb_logger.add_scalar('selfplay1_evaluator_step/reward_mean', reward, collector.envstep)
        if evaluator2.should_eval(learner1.train_iter):
            stop_flag2, reward = evaluator2.eval(learner1.save_checkpoint, learner1.train_iter, collector.envstep)
            tb_logger.add_scalar('selfplay2_evaluator_step/reward_mean', reward, collector.envstep)
        if stop_flag1 and stop_flag2:
            break
        train_data, _ = collector.collect(train_iter=learner1.train_iter)
        for i in range(cfg.policy.learn.update_per_collect):
            learner1.train(train_data[0], collector.envstep)
            learner2.train(train_data[1], collector.envstep)


if __name__ == "__main__":
    main(overcooked_demo_ppo_config)

算法基准测试

  • 待办事项