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
相关产品推荐
相关产品推荐

