MPE中environment.py复盘
1.__init__
-
初始化函数参数:
world
: 一个包含环境信息和所有智能体的世界对象。reset_callback
,reward_callback
,observation_callback
,info_callback
,done_callback
: 这些都是回调函数,用于在环境的特定事件发生时执行相应的操作。shared_viewer
: 一个布尔值,用于决定是否共享渲染视图。
-
存储世界对象和智能体列表:
self.world
: 存储传入的世界对象。self.agents
: 从世界对象中获取所有策略智能体(policy_agents
)的列表。
-
设置智能体数量:
self.n
: 设置智能体的数量,等于世界中策略智能体的数量。
-
设置回调函数:
- 将传入的回调函数赋值给类属性。
-
设置环境参数:
self.discrete_action_space
: 布尔值,表示动作空间是否为离散的,默认为Trueself.discrete_action_input
: 布尔值,表示动作输入是否为离散的(即使动作空间是连续的),默认为Falseself.force_discrete_action
: 布尔值,表示是否强制将连续动作离散化。self.shared_reward
: 布尔值,表示是否所有智能体共享相同的奖励。
-
初始化时间和动作/观测空间列表:
self.time
: 初始化时间计数器。self.action_space
和self.observation_space
: 初始化动作空间和观测空间的列表。
-
配置动作和观测空间:
- 遍历每个智能体,根据智能体的特性和环境参数配置其动作空间和观测空间。离散的情况下就使用spaces.Discrete函数,连续情况下就使用spaces.Box函数。
-
总动作空间:
- 如果智能体有多个动作空间,将它们组合成一个总动作空间。如果所有动作空间都是离散的,可以使用
MultiDiscrete
动作空间简化表示。
- 如果智能体有多个动作空间,将它们组合成一个总动作空间。如果所有动作空间都是离散的,可以使用
-
观测空间:
- 调用
observation_callback
函数来确定每个智能体的观测空间维度,并创建一个无限边界的盒子空间作为观测空间。
- 调用
-
初始化通信动作向量:
- 将每个智能体的通信动作向量初始化为零。
-
渲染设置:
- 根据
self.shared_viewer
的值,初始化渲染视图列表self.viewers
。
- 根据
-
重置渲染:
- 调用
_reset_render
方法来重置渲染设置。
- 调用
2.step
-
输入动作:接受一个动作列表
action_n
,其中每个元素action_n[i]
是针对相应智能体i
的动作。 -
初始化列表:初始化用于存储每个智能体观测、奖励、完成状态和信息的列表。
-
设置智能体动作:遍历每个智能体,使用
_set_action
函数为每个智能体设置动作。这个函数根据传入的动作和智能体的动作空间来更新智能体的内部状态。 -
推进世界状态:调用
self.world.step()
来根据所有智能体的动作推进环境的状态。 -
记录观测:再次遍历智能体,为每个智能体获取观测、奖励、完成状态和信息。
obs_n
:存储每个智能体的观测。reward_n
:存储每个智能体获得的奖励。done_n
:存储每个智能体的任务完成状态(例如,是否达到终止状态)。info_n
:存储每个智能体的额外信息。
-
计算总奖励:如果环境是合作性的(
self.shared_reward
为True
),则将所有智能体获得的奖励相加,然后让每个智能体都获得相同的总奖励。 -
返回结果:返回一个元组,包含每个智能体的观测列表、奖励列表、完成状态列表和信息字典。
以下是对函数中一些关键部分的详细解释:
-
_set_action
:这个函数负责根据智能体的动作空间和传入的动作来设置智能体的动作。例如,如果动作空间是离散的,它可能会将动作转换为特定的动作向量。 -
_get_obs
:这个函数负责获取智能体的观测。观测通常包括智能体对环境的感知,例如周围实体的位置、速度等。 -
_get_reward
:这个函数负责计算并返回智能体获得的奖励。奖励可以基于智能体的表现或达到的目标。 -
_get_done
:这个函数负责判断智能体的任务是否完成,或者环境是否已经达到一个终止状态。 -
_get_info
:这个函数负责提供关于智能体状态的额外信息,这可以包括任何对调试或分析有用的数据。
3._set_action
以离散动作输入和非离散动作输入两种情况进行分析。
离散动作输入情况
当self.discrete_action_input
为True
时,表示动作输入是离散的:
-
初始化动作向量:
agent.action.u = np.zeros(self.world.dim_p) agent.action.c = np.zeros(self.world.dim_c)
-
处理动作: 如果动作空间是
MultiDiscrete
类型,代码将动作分解为多个离散动作,并存储在列表act
中。否则,动作已经是列表形式。 -
物理动作:
- 根据动作的值(1, 2, 3, 4),设置智能体在x轴和y轴上的移动方向:
if action[0] == 1: agent.action.u[0] = -1.0 if action[0] == 2: agent.action.u[0] = +1.0 if action[0] == 3: agent.action.u[1] = -1.0 if action[0] == 4: agent.action.u[1] = +1.0
- 根据动作的值(1, 2, 3, 4),设置智能体在x轴和y轴上的移动方向:
-
通信动作:
- 将通信动作向量
agent.action.c
的对应位置设置为1:agent.action.c[action[0]] = 1.0
- 将通信动作向量
非离散动作输入情况
当self.discrete_action_input
为False
时,表示动作输入是连续的:
-
初始化动作向量:
agent.action.u = np.zeros(self.world.dim_p) agent.action.c = np.zeros(self.world.dim_c)
-
物理动作:
- 如果
self.force_discrete_action
为True
,则将动作向量中最大的元素设置为1,其余设置为0,以强制离散化动作。 - 如果
self.discrete_action_space
为True
,则根据连续动作的值更新智能体在x轴和y轴上的移动:agent.action.u[0] += action[0][1] - action[0][2] agent.action.u[1] += action[0][3] - action[0][4]
- 否则,直接将连续动作赋值给智能体的物理动作:
agent.action.u = action[0]
- 如果
-
通信动作:
- 直接将连续动作赋值给智能体的通信动作:
agent.action.c = action[0]
- 直接将连续动作赋值给智能体的通信动作:
通用步骤
无论动作输入是离散的还是连续的,以下步骤是通用的:
-
灵敏度调整: 物理动作向量
agent.action.u
乘以一个灵敏度因子sensitivity
,以调整智能体的移动速度。 -
断言检查: 最后,使用
assert
语句确保所有动作元素都已被处理,即动作列表action
的长度为0。
4.观测环境,在simple_tag.py里的
-
获取所有实体的位置:
entity_pos
用于存储环境中除了智能体自身以外的其他实体(如路标或目标)相对于智能体的位置。- 通过遍历
world.landmarks
(环境中的所有地标),如果地标entity
不是边界(not entity.boundary
),则计算其相对于智能体agent
的位置entity.state.p_pos - agent.state.p_pos
,并将其添加到entity_pos
列表中。
-
获取其他智能体的通信、位置和速度:
comm
用于存储其他智能体的通信状态。other_pos
用于存储其他智能体相对于当前智能体的位置。other_vel
用于存储其他智能体的速度,但只包括那些不是对手(adversary
)的智能体。- 通过遍历
world.agents
(环境中的所有智能体),如果other
不是当前智能体agent
,则将其通信状态other.state.c
添加到comm
列表中,将其相对于智能体的位置添加到other_pos
列表中,如果other
不是对手,则将其速度添加到other_vel
列表中。
-
返回观测向量:
- 使用
np.concatenate
函数将智能体自身的速度agent.state.p_vel
、智能体自身的位置agent.state.p_pos
、所有地标的相对位置entity_pos
、其他智能体的相对位置other_pos
以及其他智能体的速度(如果适用)other_vel
合并成一个观测向量。 - 这个合并的观测向量提供了智能体对环境的全面感知,它可以用来决定智能体的下一步动作。
- 使用
总结来说,这个 observation
函数收集了智能体对环境的感知信息,包括:
- 自身的速度 (
agent.state.p_vel
) - 自身的位置 (
agent.state.p_pos
) - 地标的相对位置 (
entity_pos
) - 其他智能体的通信状态 (
comm
) - 其他智能体的相对位置 (
other_pos
) - 其他智能体的速度 (
other_vel
)