详解 pysc2 中的 Observation 和 Action
Posted 超级超级小天才
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了详解 pysc2 中的 Observation 和 Action相关的知识,希望对你有一定的参考价值。
详解 pysc2 中的 Observation 和 Action
SCII 环境具有非常丰富的动作空间和状态空间。Pysc2
接口从游戏中读取并提供给我们使用的信息有两类:空间/视觉类的(spatial/visual);结构性的元素(structured elements),其中结构性的元素主要是提供一些重要的数据,而且这些数据对于机器来说往往很难通过游戏画面直接读取,比如燃料的数量,所以接口直接提供这些数据。
Important!
从observation中获取得到的坐标信息是 (y,x)
形式的,即纵坐标写在前,而有些action需要跟上一个屏幕/小地图的坐标位参数,比如移动某单位到哪个点去,这里需要传入的坐标是 (x,y)
形式的,即横坐标写在前。坐标原点 (0,0)
都是左上角,y轴正方向向下,x轴正方向向右。
例如,一个将 observation 中获取得到的坐标传递给某个 action 的例子:
# Spatial observations have the y-coordinate first:
y, x = (obs.observation["feature_screen"][_PLAYER_RELATIVE] == _PLAYER_NEUTRAL).nonzero()
# Actions expect x-coordinate first:
target = [int(x.mean()), int(y.mean())]
action = actions.FunctionCall.Move_screen("now", target)
Observation
Spitial/Visual
RGB Pixels
这一类Observation就是屏幕和小地图真实显示的画面,即在规定的分辨率下所看到的游戏界面,和正常游戏看到的一致(除了分辨率较低),但是,不包括下边的UI等信息。
Feature Layers
Feature layers 是对于一些游戏中重要信息的表示,并对这些信息进行了结构化处理,根据所显示的范围分为两类:feature_screen
和 feature_minimap
,即屏幕的feature和小地图的feature,如下图中所示的都是feature layers:
完整的列表在 pysc2.lib.features
中。
collections.namedtuple("ScreenFeatures", ["height_map", "visibility_map", "creep", "power", "player_id", "player_relative", "unit_type", "selected", "unit_hit_points", "unit_hit_points_ratio", "unit_energy", "unit_energy_ratio", "unit_shields", "unit_shields_ratio", "unit_density", "unit_density_aa", "effects", "hallucinations", "cloaked", "blip", "buffs", "buff_duration", "active", "build_progress", "pathable", "buildable", "placeholder"])
collections.namedtuple("MinimapFeatures", ["height_map", "visibility_map", "creep", "camera", "player_id", "player_relative", "selected", "unit_type", "alerts", "pathable", "buildable"])
Minimap(小地图)
小地图即对全局的低分辨率图像,可以设置minimap的分辨率,一些主要的 features_minimap
:
height_map
:显示地形特征visibility
:显示地图的哪一部分是隐藏的、已经被看到的或当前可见的creep
:哪些部分是虫族势力camera
:地图的哪一部分在屏幕中可见player_id
:显示所拥有的单位,以及其IDplayer_relative
:显示所有的单位是己方的还是地方的。 取[0,4]
的值,分别表示[background, self, ally, neutral, enemy]
([背景,自身,盟友,中立,敌人]单位selected
:选择了哪些单位
Screen(屏幕)
屏幕显示的即当前玩家所看到的区域,拥有比小地图更高的分辨率(of course),一些主要的 feature_screen
:
height_map
:显示地形特征visibility
:显示地图的哪一部分是隐藏的、已经被看到的或当前可见的creep
:哪些部分是虫族势力power
:哪些部分是神族势力,只会显示你的势力player_id
:显示所拥有的单位,以及其IDplayer_relative
:显示所有的单位是己方的还是地方的。 取[0,4]
的值,分别表示[background, self, ally, neutral, enemy]
([背景,自身,盟友,中立,敌人]单位unit_type
:单位类型的ID,可以在pysc2/lib/units.py
中查看完整列表selected
:选择了哪些单位hit_points
:单位所具有的生命值energy
:设备所具有的能量值shields
:装置所具有的防御值/盾值(仅适用于神族单位)unit_density
:该像素中有多少个单位unit_density_aa
:unit_density
的抗锯齿版本,每个像素每单位最多16个
Structured(结构化的数据)
Structured(结构化的)数据是那些无法从像素中直接读取的信息,通过 tensor 表示。详细的说明请参考:
https://github.com/deepmind/pysc2/blob/master/docs/environment.md#structured
这里列一下主要的结构化信息有:
- 基本的玩家信息(General player information)
- 控制组信息(Control groups)
- 单独选中的单位信息(Single Select)
- 多选中的单位信息(Multi Select)
- 多个选中的正在移动中的单位信息(Cargo)
- 多个选中的正在修建的单位信息(Build Queue)
- 可用动作(的id)(Available Actions)
- 上一轮中成功运行的动作(的id)(Last Actions)
- 给出动作的结果(Action Result)
- 提醒被攻击的信号(一般为空)(Alerts)
可以通过Debug清楚地看到这些变量(如何在PyCharm中对pysc2的Agent类进行Debug):
Actions
函数化动作(Function Actions)
SCII 环境中的动作空间非常非常复杂且庞大,因此,pysc2 使用了函数化动作(function actions),所有可用的动作/函数类型定义在了 pysc2.lib.action
中的 ValidActions
类中,每一个动作就是一个 FunctionCall
,同样也定义在了 pysc2.lib.action
中。
There are hundreds of possible actions, many of which take a point in either screen or minimap space, and many of which take an additional modifier.
We created function actions that are rich enough to give composability, without the complexity of an arbitrary hierarchy.
collections.namedtuple("ValidActions", ["types", "functions"])
collections.namedtuple("FunctionCall", ["function", "arguments"])
简单说就是,在pysc2
中,每一个动作(action)其实是一个 FunctionCall
类的实例,需要两个参数来确定,一个是 function_id
,表示某个函数的id,另一个就是与该函数对应的参数。比如已经确定一个函数id,表示为 fun_id
,以及对应的满足要求的参数,表示为 args
,此时一个真正的action就可以这样写:
(from pysc2.lib import actions)
action = actions.FunctionCall(fun_id, args)
值得一提的是,所有的函数及其类型均被定义在了 pysc2.lib.actions
中,如果你有自定义的环境需要用到自定义的动作、函数类型,需要把它加到这个列表中才能起作用。
显示动作列表
可以使用如下命令显示所有动作:
Python -m pysc2.bin.valid_actions
可选的参数有:
--hide_specific
:不显示具体的动作(specific actions)(下边会提到什么是specific actions)--screen_resolution
:只显示应用于游戏屏幕的动作--minimap_resolution
:只显示应用于小地图的动作
比如列出了如下的动作们(实际上多得多):
0/no_op ()
1/move_camera (1/minimap [64, 64])
11/build_queue (11/build_queue_id [10])
12/Attack_screen (3/queued [2]; 0/screen [84, 84])
23/Behavior_CloakOff_quick (3/queued [2])
42/Build_Barracks_screen (3/queued [2]; 0/screen [84, 84])
220/Effect_Repair_screen (3/queued [2]; 0/screen [84, 84])
264/Harvest_Gather_screen (3/queued [2]; 0/screen [84, 84])
303/Morph_Lair_quick (3/queued [2])
331/Move_screen (3/queued [2]; 0/screen [84, 84])
每一行的格式为:
<function id>/<function name>(<type id>/<type name> [<value size>, *]; *)
表示为:
【函数ID】/【函数名称】 (【函数参数类型的ID】/【函数参数的类型名称】 【函数参数的取值类型与范围】)
两个例子:
1/move_camera (1/minimap [64, 64])
:表示名字为move_camera
的函数,它对应函数id为1
,他的参数类型为minimap
,对应函数参数类型中的第1
类,参数取两个数值,都是 [0,64) 范围内的数值,表示小地图上的一个坐标331/Move_screen (3/queued [2]; 0/screen [84, 84])
:表示名字为Move_screen
的函数,它对应函数id为331
,它接收两个参数,第一个参数是一个queued
类型的参数,对应的参数类型id为3
,是一个布尔值,表示该操作是应该立即发生还是在之前的操作之后发生;第二个参数是一个screen
类型的参数,对应类型id为0
,后边的 [84, 84] 同上边的 [64, 64]
pysc2 中所定义的函数以及参数名称都代表一定的意义,通常可以通过名称来大致理解其作用。
完整的列表同样也是定义在 pysc2.lib.actions
中。
官方给出的 random agent 就是一个非常好的理解 function actions 的例子:
import numpy as np
from pysc2.lib import actions
def step(self, obs):
super(MyAgent, self).step(obs)
function_id = np.random.choice(obs.observation.available_actions)
args = [[np.random.randint(0, size) for size in arg.sizes]
for arg in self.action_spec.functions[function_id].args]
return actions.FunctionCall(function_id, args)
根据前后缀对动作的分类
所有动作函数的名称都具有一定的意义,而且可以通过其前缀、后缀来进行分类,(但是前后缀的使用并不是完全严格的),比如以 Morph
开头的动作即“转换”动作,比如虫族中的一些孵化动作;以 Effect
开头的一般是一个单独的效果,通常不可以被取消;以 Behavior
开头的通常是一个可以调为 on 或 off 的值;以 screen
结尾的通常是作用于游戏屏幕;而以 minimap
结尾的通常是作用与小地图中的动作。
一般动作 vs 具体动作(General vs. Specific Actions)
SCII中,动作可以被分为两类,一般动作(general actions)和具体动作(specific actions),一般动作是一个大类,而具体动作则更加具体。举个例子,Burrow(打洞)这个动作,有很多单位可以完成,比如虫族中的 Zergling 和 Drone(两种不同的作战单位),但是他们自己的打洞动作有自己对应的具体动作,BurrowDown_Zergling
和 BurrowDown_Drone
,其中 BurrowDown_Zergling
只能被应用于 Zergling 单位, Drone同理,那么如果在某一帧下,我们选中的单位既有 Zergling 也有 Drone 呢,那此时如果使用 BurrowDown_Zergling
动作,那其中的 Drone 单位就没有办法行动了,所以需要 BurrowDown
这个一般动作来执行,选中这个动作,所有能够执行这个动作的单位都可以执行。
在pysc2的定义中,可以理解为具体动作是相应的一般动作的继承,只是多了一个额外的参数来确定其“具体的部分”。
以上是关于详解 pysc2 中的 Observation 和 Action的主要内容,如果未能解决你的问题,请参考以下文章
Pysc2Deepmind Pysc2 环境配置及其踩坑记录
将 AppKit/UIKit 中的 Key-Value Observation 转换为 Combine 和 SwiftUI