当前位置: 首页 > 工具软件 > PySC2 > 使用案例 >

使用pysc2的环境并与其进行交互

西门安宁
2023-12-01

使用pysc2的环境并与其进行交互

作为应用于强化学习的SCII环境是被定义在 pysc2.env.sc2_env 中的,(action 和 observation 空间是定义在 pysc2.lib.features 中的),环境的类即 SC2Env,继承自 pysc2.env.environment.Base 类。可以作为使用一般的gym库的强化学习的环境一样使用它

要实例化并使用一个 SC2Env,需要传入几个重要的参数,完整的参数列表如下:

_only_use_kwargs=None,
map_name=None,
battle_net_map=False,
players=None,
agent_interface_format=None,
discount=1.,
discount_zero_after_timeout=False,
visualize=False,
step_mul=None,
realtime=False,
save_replay_episodes=0,
replay_dir=None,
replay_prefix=None,
game_steps_per_episode=None,
score_index=None,
score_multiplier=None,
random_seed=None,
disable_fog=False,
ensure_available_actions=True,
version=None

重要的参数说明

一些重要的参数说明如下:

  • map_name:地图的名称,一个字符串
    • 地图名均列在了 pysc2.bin.map_list 中,可以使用如下的命令来列出所有的地图名称:
      python -m pysc2.bin.map_list
      
    • 或者可以在 pysc2/maps/ 下的文件夹中查找,比如 pysc2/maps/melee.py 中定义了所有 Melee 的地图名称:
      melee_maps = ["Flat32", "Flat48", "Flat64", "Flat96", "Flat128", "Simple64", "Simple96", "Simple128",]
      
  • players:传入一个list,list中是一个或两个 pysc2.env.sc2_env.Agentpysc2.env.sc2_env.Bot 的实例,目前只支持一个或者两个,一个就是单 Agent 与环境交互,两个就是互相对战,有些地图只能传入一个。注意,就是使用一个 AgentBot 的实例时,也要使用 list 包裹。
    • 注意,此处的 pysc2.env.sc2_env.Agentpysc2.env.sc2_env.Bot 是不同于我们前文中所提到的自定义的继承自 pysc2.agetns.base_agent 的,这是两个不同的类,这里使用的 Agent 和 Bot 用于定义与环境交互的player的类型、名称、种族、困难度等信息,这两个类的定义很简单:
      class Agent(collections.namedtuple("Agent", ["race", "name"])):
          """Define an Agent. It can have a single race or a list of races."""
      
          def __new__(cls, race, name=None):
              return super(Agent, cls).__new__(cls, to_list(race), name or "<unknown>")
      
      
      class Bot(collections.namedtuple("Bot", ["race", "difficulty", "build"])):
          """Define a Bot. It can have a single or list of races or builds."""
      
          def __new__(cls, race, difficulty, build=None):
              return super(Bot, cls).__new__(cls, to_list(race), difficulty, to_list(build or BotBuild.random))
      
  • agent_interface_format:用于规定 observation 和 action 的形式,比如地图或者feature layers的分辨率等,接受 pysc2.lib.features.AgentInterfaceFormat 实例,或者 pysc2.env.sc2_env.AgentInterfaceFormat 实例。(实际上两者相同,sc2_env.py 中使用了 = 将其两者赋值)
    • 如果你在players参数中传入了两个对象,那么可以传入一个 AgentInterfaceFormat 的实例同时应用于两个player,或者传入一个包含两个 AgentInterfaceFormat的list,和players的顺序一致地分别应用于两个player
    • AgentInterfaceFormat 的参数等设置方法直接参考其定义
  • step_mul 参数接收一个整数,可以理解为:每次采集observation和应用action之间跳过多少个帧(但是不是实际上的帧数)。1 秒相当于 16 steps,如果这里设置为 16,就代表每秒采集一次。
  • game_steps_per_episode:一代多少个 steps,比如这里设置为 200*16,就表示一代经历 200 秒结束
  • save_replay_episodes:多少代保存一次replay
  • replay_dir:replay保存在哪个位置

使用自己实例化的环境

定义了自己的env以及agent,就可以像使用其他gym环境一样进行交互了,一个很好的官方提供的例子就是这个 pysc2/env/run_loop.py 文件下的 run_loop 函数,它接收一个/两个 agent(s) 实例和一个 env 实例,运行若干帧/代:

def run_loop(agents, env, max_frames=0, max_episodes=0):
    """A run loop to have agents and an environment interact."""
    total_frames = 0
    total_episodes = 0
    start_time = time.time()

    observation_spec = env.observation_spec()
    action_spec = env.action_spec()
    for agent, obs_spec, act_spec in zip(agents, observation_spec, action_spec):
        agent.setup(obs_spec, act_spec)

    try:
        while not max_episodes or total_episodes < max_episodes:
            total_episodes += 1
            timesteps = env.reset()
            for a in agents:
                a.reset()
            while True:
                total_frames += 1
                actions = [agent.step(timestep) for agent, timestep in zip(agents, timesteps)]
                if max_frames and total_frames >= max_frames:
                    return
                if timesteps[0].last():
                    break
                timesteps = env.step(actions)
    except KeyboardInterrupt:
        pass
    finally:
        elapsed_time = time.time() - start_time
        print("Took %.3f seconds for %s steps: %.3f fps" % (elapsed_time, total_frames, total_frames / elapsed_time))

最后再来看一下官方提供的,实例化一个 SC2Env 实例,一个 Agent 实例,然后使用上述的 run_loop 函数进行测试的例子,若干个例子可以在 pysc2/tests/easy_scripted_test.py 中找到:

def test_move_to_beacon(self):
    with sc2_env.SC2Env(
            map_name="MoveToBeacon",
            players=[sc2_env.Agent(sc2_env.Race.terran)],
            agent_interface_format=sc2_env.AgentInterfaceFormat(
                feature_dimensions=sc2_env.Dimensions(
                    screen=84,
                    minimap=64)),
            step_mul=self.step_mul,
            game_steps_per_episode=self.steps * self.step_mul) as env:
        agent = scripted_agent.MoveToBeacon()
        run_loop.run_loop([agent], env, self.steps)

这里使用了 with as 的形式,我们需要创建长久的交互式直接使用 evn = SC2Env(…) 即可。

启动SCII程序

启动真正的SCII程序需要使用 absl.app 下的 run 函数,然后传入一个运行我们上述代码的主要函数作为参数,比如我们设置了一个主函数来设置env、agent等,以及完成了基本的循环条件,把这些都封装在了一个名为 main 的函数中,最后,需要使用 absl.app.run(main) 来启动真正的 SCII 程序。一个完整的例子如下:

from pysc2.env import run_loop, sc2_env
from pysc2.agents import random_agent
from absl import app


def main(args):
    agent = random_agent.RandomAgent()

    with sc2_env.SC2Env(map_name="MoveToBeacon", players=[sc2_env.Agent(sc2_env.Race.terran)],
                        agent_interface_format=sc2_env.AgentInterfaceFormat(
                            feature_dimensions=sc2_env.Dimensions(screen=84, minimap=64)), step_mul=16,
                        game_steps_per_episode=200 * 16, visualize=True) as env:
        run_loop.run_loop([agent], env, 200)


if __name__ == "__main__":
    app.run(main)

几个非常需要注意的点:

  • app.run 内传入的参数,第一个参数是必须传入的,是主函数的名字,不带括号和参数,第二个参数可选,当主函数需要参数的时候,在第二个参数这里提供,需要将所用到的参数打包成list作为参数传入
  • 定义main函数时,必须为其设置至少一个参数,比如这里的 args,这个参数可以不在函数中使用,但是如果只定义 def main() 就会报错
  • 这里我们使用了官方提供的 run_loop 函数,传入时,第一个参数为我们的 agent 们,即使只有一个,也要打包成list传入

重要参考官方文档:https://github.com/deepmind/pysc2/blob/master/docs/environment.md#rl-environment
参考一篇blog:https://itnext.io/build-a-zerg-bot-with-pysc2-2-0-295375d2f58e

 类似资料: