You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UnityToGymWrapper无法获取正确射线观测,求助适配ML-Agents观测

解决UnityToGymWrapper无法正确获取射线观测的问题

1. 先确认Unity端观测配置是否正确

  • 检查RayPerceptionSensorComponent3D/2D参数:确保射线数量、检测角度、最大长度设置符合预期,且已勾选Send Raw Observations(需原始射线数据时)
  • 确认射线传感器已添加到Agent组件的观测列表中,在Unity的ML-Agents调试面板里实时查看Agent的观测输出,验证射线数据确实存在于原始观测中

2. 修正UnityToGymWrapper的初始化逻辑

标准包装代码修正

如果自动包装的观测解析有问题,调整初始化参数并手动验证观测结构:

from mlagents_envs.environment import UnityEnvironment
from stable_baselines3.common.env_util import make_unity_env

# 初始化Unity环境,替换为你的Sorter游戏路径
unity_env = UnityEnvironment(file_name="./Sorter", seed=42)

# allow_multiple_obs=True会保留ML-Agents的多观测列表,False会自动拼接
gym_env = make_unity_env(unity_env, n_envs=1, allow_multiple_obs=True)

# 重置环境并打印观测结构,确认射线观测是否存在
obs = gym_env.reset()
print(f"观测类型: {type(obs)}")
if isinstance(obs, list):
    print("各观测维度:")
    for idx, sub_obs in enumerate(obs):
        print(f"观测{idx}形状: {sub_obs.shape}")
else:
    print(f"观测形状: {obs.shape}")

自定义包装器处理多观测

如果标准包装器仍无法正确解析,手动实现包装逻辑来确保捕获所有观测:

from mlagents_envs.environment import UnityEnvironment
import gym
from gym import spaces
import numpy as np

class CustomUnityGymWrapper(gym.Env):
    def __init__(self, unity_env):
        self.unity_env = unity_env
        self.behavior_name = list(unity_env.behavior_specs.keys())[0]
        self.behavior_spec = unity_env.behavior_specs[self.behavior_name]

        # 构建观测空间,匹配ML-Agents的所有观测项
        obs_spaces = []
        for spec in self.behavior_spec.observation_specs:
            space_shape = spec.shape if spec.shape != () else (1,)
            obs_spaces.append(spaces.Box(low=-np.inf, high=np.inf, shape=space_shape, dtype=np.float32))
        self.observation_space = spaces.Tuple(obs_spaces) if len(obs_spaces) > 1 else obs_spaces[0]

        # 构建动作空间
        if self.behavior_spec.action_spec.is_discrete():
            self.action_space = spaces.Discrete(self.behavior_spec.action_spec.discrete_size)
        else:
            self.action_space = spaces.Box(low=-1, high=1, shape=self.behavior_spec.action_spec.continuous_size, dtype=np.float32)

    def reset(self):
        self.unity_env.reset()
        decision_steps, _ = self.unity_env.get_steps(self.behavior_name)
        obs_list = decision_steps.obs
        return obs_list if len(obs_list) > 1 else obs_list[0]

    def step(self, action):
        # 适配动作格式
        if self.behavior_spec.action_spec.is_discrete():
            action = np.array([action])
        self.unity_env.set_actions(self.behavior_name, action)
        self.unity_env.step()

        decision_steps, terminal_steps = self.unity_env.get_steps(self.behavior_name)
        if len(terminal_steps) > 0:
            obs = terminal_steps.obs
            reward = terminal_steps.reward[0]
            done = True
        else:
            obs = decision_steps.obs
            reward = decision_steps.reward[0]
            done = False

        return (obs if len(obs) > 1 else obs[0]), reward, done, {}

    def close(self):
        self.unity_env.close()

# 使用自定义包装器
unity_env = UnityEnvironment(file_name="./Sorter", seed=42)
gym_env = CustomUnityGymWrapper(unity_env)

# 测试观测获取
obs = gym_env.reset()
if isinstance(obs, list):
    # 假设射线观测是第二个元素,根据Unity端配置调整索引
    print(f"射线观测维度: {obs[1].shape}")

3. 版本兼容性排查

确保依赖版本匹配,避免兼容性问题:

  • 推荐组合:mlagents==0.29.0 + stable-baselines3==1.8.0 + gym==0.26.2
  • 不要盲目使用最新版本,优先选择经过验证的稳定版本组合

4. 确认观测顺序与索引

  • Unity端Agent的观测顺序由传感器添加顺序决定,在Unity编辑器的Agent组件中确认射线传感器的位置,对应到Python端的观测列表索引

内容的提问来源于stack exchange,提问作者Maisa-ASM

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 23:07:49