十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Gymnasium Action Wrappers 完全指南:从 TransformAction 到 StickyAction 的源码级解析与实战

Gymnasium Action Wrappers 完全指南:从 TransformAction 到 StickyAction 的源码级解析与实战 Gymnasium Action Wrappers 完全指南从 TransformAction 到 StickyAction 的源码级解析与实战【免费下载链接】GymnasiumA standard API for single-agent reinforcement learning environments, with popular reference environments and related utilities (formerly Gym)项目地址: https://gitcode.com/GitHub_Trending/gy/GymnasiumGymnasium 的 Action Wrappers 是一组专门用于在动作传入底层环境step之前对其进行变换的包装器涵盖动作裁剪、线性重缩放、离散化、粘滞与重复执行等经典强化学习场景。本文以 docs/api/wrappers/action_wrappers.md 为骨架结合仓库源码与测试系统讲解ActionWrapper基类的接口约定、五个内置动作包装器的原理与用法以及如何编写自定义动作包装器。读完本文你将掌握在不改动底层环境代码的前提下灵活操控动作空间与动作流的标准姿势。一、ActionWrapper 基类动作变换的接口约定所有动作包装器都继承自 gymnasium/core.py 中的gymnasium.ActionWrapper。它的核心思想是在调用底层env.step(action)之前先通过self.action(action)对动作做一次变换。class ActionWrapper(Wrapper[ObsType, WrapperActType, ObsType, ActType]): def step(self, action: WrapperActType) - tuple[ObsType, SupportsFloat, bool, bool, dict[str, Any]]: Runs the :attr:env :meth:env.step using the modified action from :meth:self.action. return self.env.step(self.action(action)) def action(self, action: WrapperActType) - ActType: Returns a modified action before :meth:step is called. raise NotImplementedError从源码可以看到两个关键点子类只需实现action()方法返回变换后的动作step的返回结构(observation, reward, terminated, truncated, info)与底层环境完全一致动作包装器不修改观测、奖励与终止/截断信号只改变动作。ActionWrapper的文档字符串还特别强调了两条接口约定变换结果必须落在底层环境的动作空间内The transformation defined in that method must take values in the base environments action space变换函数的定义域domain可以不同于原始动作空间——此时必须在__init__中通过设置self.action_space来声明新的动作空间。第二条正是ClipAction、RescaleAction、DiscretizeAction等包装器能够改变动作空间的机制来源Wrapper基类见 gymnasium/core.py的action_space属性在self._action_space未设置时回退到self.env.action_space一旦子类赋了新值包装器对外暴露的就是新空间。二、TransformAction用任意函数变换动作gymnasium/wrappers/transform_action.py 中的TransformAction是最通用的动作包装器它接收一个 Python 可调用对象func在每次step前对动作应用该函数。def __init__( self, env: gym.Env[ObsType, ActType], func: Callable[[WrapperActType], ActType], action_space: Space[WrapperActType] | None, ): ... if action_space is not None: self.action_space action_space self.func func def action(self, action: WrapperActType) - ActType: Apply function to action. return self.func(action)参数说明参数类型说明envgym.Env待包装的底层环境funcCallable施加在step动作上的变换函数action_spaceSpace \| None变换后新的动作空间传入None则保持原动作空间不变需要注意func的返回值必须属于底层环境的动作空间否则底层环境会收到非法动作。官方文档给出的示例是对MountainCarContinuous-v0的动作做线性变换import numpy as np import gymnasium as gym from gymnasium.wrappers import TransformAction env gym.make(MountainCarContinuous-v0) env TransformAction(env, lambda a: 0.5 * a 0.1, env.action_space) _ env.reset(seed123) obs, *_ env.step(np.array([0.0, 1.0]))该包装器在 v1.0.0 中引入并且存在对应的向量化版本gymnasium.wrappers.vector.TransformAction实现于 gymnasium/wrappers/vector/vectorize_action.py可批量作用于由gym.make_vec创建的多环境对象。三、ClipAction将越界动作裁剪回合法范围ClipAction继承自TransformAction见 gymnasium/wrappers/transform_action.py专门解决连续动作越界问题当策略网络输出的动作超出环境Box动作空间的上下界时将其裁剪到合法区间内。class ClipAction(TransformAction[ObsType, WrapperActType, ActType], gym.utils.RecordConstructorArgs): def __init__(self, env: gym.Env[ObsType, ActType]): if not isinstance(env.action_space, Box): raise TypeError( fClipAction requires a Box action space, got {type(env.action_space)} ) ... TransformAction.__init__( self, envenv, funclambda action: np.clip( action, env.action_space.low, env.action_space.high ), action_spaceBox( -np.inf, np.inf, shapeenv.action_space.shape, dtypeenv.action_space.dtype, ), )3.1 底层原理变换函数是np.clip(action, low, high)即把每个分量逐一裁剪到[low, high]只支持Box动作空间其他空间类型直接抛出TypeError包装器对外暴露的动作空间被更新为无界 Box-inf到inf。这是 v1.0.0 的刻意改动——从技术上正确的角度看ClipAction对任意实数输入都合法因此包装器自身的动作空间应为无界见该类的 Change logAction space is updated to infinite bounds as is technically correct。官方示例Hopper-v4 的动作空间为Box(-inf, inf, (3,), float32)底层环境内部实际限制为[-1, 1]import gymnasium as gym from gymnasium.wrappers import ClipAction import numpy as np env gym.make(Hopper-v4, disable_env_checkerTrue) env ClipAction(env) env.action_space # Box(-inf, inf, (3,), float32) _ env.reset(seed42) _ env.step(np.array([5.0, -2.0, 0.0], dtypenp.float32)) # 底层环境实际执行 np.array([1.0, -1.0, 0.0])3.2 使用场景当使用 MuJoCo 这类动作空间声明为无界、但物理引擎内部实际有隐式边界的环境时直接让策略输出原始动作可能导致数值不稳定套上ClipAction后可以保证传入引擎的动作始终处于其物理合法范围。该包装器最早在 v0.12.6 加入向量化版本为gymnasium.wrappers.vector.ClipAction见 gymnasium/wrappers/vector/vectorize_action.py。四、RescaleAction动作空间的仿射重缩放RescaleActiongymnasium/wrappers/transform_action.py把底层环境的Box动作空间仿射线性映射到自定义的[min_action, max_action]区间是统一动作尺度的常用工具——例如把不同环境各自的动作范围统一映射到[-1, 1]或[0, 1]方便复用同一套策略。4.1 构造参数与约束参数类型说明envgym.Env底层环境其动作空间必须是Boxmin_actionfloat \| int \| np.ndarray新动作空间各维最小值传标量会对所有维度广播max_actionfloat \| int \| np.ndarray新动作空间各维最大值传数组时形状必须与动作空间一致源码层面的三条校验规则必须是Box空间否则抛TypeError若min_action/max_action为数组其形状必须等于动作空间形状min_action的任何分量都不能等于max_action的对应分量否则抛InvalidBound——原因是包装器需要执行重缩放的逆映射而某一维被压成单点后逆映射不存在输出会变成nan。4.2 底层实现rescale_box重缩放的数学核心在 gymnasium/wrappers/utils.py 的rescale_box函数。它计算一个仿射映射gradient * x intercept把原始区间[low, high]逐分量线性映射到[new_min, new_max]并同时返回新的Box空间前向变换函数原空间 → 新空间反向变换函数新空间 → 原空间即RescaleAction.action实际使用的映射。对无界分量源码要求目标边界也必须保持无穷For unbounded components, the target bounds must match the original infinity bounds否则抛ValueError。计算梯度时优先使用float128提高数值精度不可用时回退float64。4.3 官方示例与测试验证官方示例展示了重缩放后的最大动作与原环境指定动作产生相同观测的等价性import gymnasium as gym from gymnasium.wrappers import RescaleAction import numpy as np env gym.make(Hopper-v4, disable_env_checkerTrue) _ env.reset(seed42) obs, _, _, _, _ env.step(np.array([1, 1, 1], dtypenp.float32)) _ env.reset(seed42) min_action -0.5 max_action np.array([0.0, 0.5, 0.75], dtypenp.float32) wrapped_env RescaleAction(env, min_actionmin_action, max_actionmax_action) wrapped_env_obs, _, _, _, _ wrapped_env.step(max_action) np.all(obs wrapped_env_obs) # np.True_其正确性由 tests/wrappers/test_rescale_action.py 覆盖测试构造了一个包含无穷分量的五维Box空间[0,1,-inf,5,-inf]→[1,3,inf,inf,7]断言重缩放后包装器的动作空间等于目标空间并逐样本验证wrapped_env.step(sample)实际传入底层环境的动作等于期望值test_rescale_action_equal_bounds则验证了min_action max_action包括仅单维退化会正确抛出InvalidBound。该包装器 v0.15.4 引入向量化版本gymnasium.wrappers.vector.RescaleAction见 gymnasium/wrappers/vector/vectorize_action.py。五、StickyAction带概率的粘滞动作StickyActiongymnasium/wrappers/stateful_action.py实现了经典强化学习论文 Machado et al., 2018Atari 基准测评建议中 Section 5.2 提出的粘滞动作机制以一定概率用上一步的动作替代智能体当前步的输出从而模拟真实环境中控制信号延迟/丢失带来的随机性常被用于更严谨的基准测试。5.1 构造参数参数类型说明envgym.Env底层环境repeat_action_probabilityfloat动作被上一动作替换的概率必须满足0 p 1否则抛InvalidProbabilityrepeat_action_durationint \| tuple[int, int]动作重复持续步数传整数为确定性重复传二元组则在区间内随机采样默认1v1.1.0 新增对repeat_action_duration的校验规则见 gymnasium/wrappers/stateful_action.py必须是整数或长度为 2 的元组、下界不能大于上界、且每步重复次数必须 1。5.2 工作机理StickyAction覆盖action()与reset()两个方法并用last_action、is_sticky_actions、num_repeats、repeats_taken四个内部状态记录粘滞进度若当前正处于粘滞序列中或随机数np_random.uniform() repeat_action_probability触发了新序列则用last_action替换当前动作新序列开始时从[duration_low, duration_high]中随机采样重复步数重复步数用完后重置状态并把本次实际执行的动作记为last_actionreset()会清空全部粘滞状态避免跨 episode 残留。官方示例CartPole-v1重复概率 0.9import gymnasium as gym from gymnasium.wrappers import StickyAction env gym.make(CartPole-v1) env StickyAction(env, repeat_action_probability0.9) env.reset(seed123)该包装器 v1.0.0 加入v1.1.0 增加了repeat_action_duration且没有向量化版本。六、RepeatAction确定性重复执行当前动作RepeatActiongymnasium/wrappers/stateful_action.py与StickyAction互补它确定性地把当前动作连续执行num_repeats次并累加各内部步的奖励返回最终观测与累计奖励。def __init__(self, env: gym.Env[ObsType, ActType], num_repeats: int): if not np.issubdtype(type(num_repeats), np.integer): raise TypeError(...) if num_repeats 1: raise ValueError(...) ... def step(self, action): total_reward 0.0 terminated truncated False info {} for _ in range(self.num_repeats): obs, reward, terminated, truncated, info self.env.step(action) total_reward float(reward) if terminated or truncated: break return obs, total_reward, terminated, truncated, info6.1 与 StickyAction 的差异对照维度StickyActionRepeatAction替换/执行对象用上一动作替换当前动作重复执行当前动作随机性概率性触发重复步数可随机完全确定性奖励单步奖励每次step只执行一次底层step累加内部多步奖励终止处理不涉及提前终止时循环立即停止6.2 使用价值降低决策频率当环境不需要每个时间步都决策时如部分机器人控制任务RepeatAction等效于frame_skip可加速训练并提升探索效率奖励累加语义源码明确返回所有内部步奖励之和total_reward并把最后一步的terminated、truncated、info透传构造时要求num_repeats为不小于 1 的整数且该包装器没有向量化版本。官方示例CartPole-v1重复 4 次import gymnasium as gym from gymnasium.wrappers import RepeatAction env gym.make(CartPole-v1) env RepeatAction(env, num_repeats4) obs, info env.reset(seed123) obs, reward, terminated, truncated, info env.step(1) reward # 4.0即 4 个内部步奖励之和该包装器在 v1.3.0 中引入。七、DiscretizeAction 与自定义包装器把动作空间改造为己所用虽然 docs/api/wrappers/action_wrappers.md 正文只罗列了五个类但仓库 gymnasium/wrappers/transform_action.py 中还提供了同为动作包装器家族的重要成员DiscretizeAction以及两个面向扩展的机制一并说明如下。7.1 DiscretizeAction连续动作均匀离散化DiscretizeAction把连续Box动作空间均匀切分为多个 bin并将动作映射到每个 bin 的中心值。构造参数为参数类型说明envgym.Env底层环境动作空间必须是有限的Boxbinsint \| tuple[int, ...]每个维度的 bin 数量传整数对所有维度广播传元组时长度必须等于动作维度数multidiscretebool为True时动作空间变为MultiDiscrete(bins)否则展平为单个Discrete(prod(bins))默认False源码中的三条硬约束仅支持Box动作空间动作空间边界必须有限——存在±inf分量时抛ValueError因为无法对无穷区间均匀切分bins元组长度必须与动作维度一致。以Reacher-v5Box(-1, 1, (2,), float32)为例import gymnasium as gym from gymnasium.wrappers import DiscretizeAction env gym.make(Reacher-v5) env DiscretizeAction(env, bins10) env.action_space # Discrete(100) env DiscretizeAction(env, bins10, multidiscreteTrue) env.action_space # MultiDiscrete([10 10])其action()把离散索引Discrete模式下经_unflatten_index反展平为各维索引映射到对应 bin 中心revert_action()则提供逆操作把连续动作还原为最近的 bin 索引方便做动作空间的双向转换。7.2 编写自定义动作包装器当内置包装器不满足需求时参照ActionWrapper的约定即可快速实现。核心步骤继承gym.ActionWrapper在__init__中调用super().__init__(env)若动作空间被变换则给self.action_space赋新值实现action(self, action)返回变换后的动作。import gymnasium as gym class SquashAction(gym.ActionWrapper): 将动作压缩到 [0, 1] 并保持动作空间不变的自定义包装器示例。 def __init__(self, env): super().__init__(env) def action(self, action): return (action - self.env.action_space.low) / ( self.env.action_space.high - self.env.action_space.low )写完后可通过gymnasium.make(..., wrapper...)或手动Wrapper(env, **kwargs)方式挂载仓库自带的包装器大多同时混入gym.utils.RecordConstructorArgs见 gymnasium/utils/record_constructor.py用于在环境 spec 中记录构造参数以便复现自定义包装器如需要同样能力可混入该类。八、组合使用与工程建议8.1 包装器链式组合包装器可以任意嵌套最内层是底层环境越靠外越接近用户代码。gym.make默认返回的CartPole-v1本身就是TimeLimitOrderEnforcingPassiveEnvCheckerCartPoleEnv的嵌套结构动作包装器只需套在最外层import gymnasium as gym from gymnasium.wrappers import RescaleAction, ClipAction, StickyAction base gym.make(Hopper-v4, disable_env_checkerTrue) env RescaleAction(base, min_action-1.0, max_action1.0) env ClipAction(env) env StickyAction(env, repeat_action_probability0.1)此时env.step(a)的调用链为StickyAction.action概率性替换→ClipAction.action裁剪到原始无界区间实际边界由引擎隐式约束→RescaleAction.action仿射逆映射回 Hopper 物理动作→ 底层环境。每个包装器只负责一个关注点组合起来可以拼出复杂的动作策略管线。8.2 工程建议动作空间一致性凡是在action()中改变了动作语义如DiscretizeAction把连续变离散务必同步更新self.action_space否则依赖动作空间的外部代码如env.action_space.sample()、env_checker会拿到错误信息面向Box的包装器有类型门槛ClipAction、RescaleAction、DiscretizeAction均要求Box空间离散动作环境请直接使用TransformAction或自定义包装器向量化场景需要配合gym.make_vec使用多环境训练时优先选择对应的向量版本gymnasium.wrappers.vector.TransformAction / ClipAction / RescaleAction而非手动对单环境逐个包装状态注意StickyAction是有状态包装器reset()会清空粘滞状态跨 episode 复用同一实例时无需额外处理RepeatAction会累加奖励阅读info时需注意其语义已从单步奖励变为多步累加奖励。参考资料官方 API 文档docs/api/wrappers/action_wrappers.md基类与实现gymnasium/core.py、gymnasium/wrappers/transform_action.py、gymnasium/wrappers/stateful_action.py核心工具函数gymnasium/wrappers/utils.py向量化版本gymnasium/wrappers/vector/vectorize_action.py测试用例tests/wrappers/test_rescale_action.py、tests/wrappers/test_sticky_action.py自定义包装器教程docs/tutorials/gymnasium_basics/implementing_custom_wrappers.py【免费下载链接】GymnasiumA standard API for single-agent reinforcement learning environments, with popular reference environments and related utilities (formerly Gym)项目地址: https://gitcode.com/GitHub_Trending/gy/Gymnasium创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表