第3章 Gymnasium入门:核心API详解与环境交互
好,咱们今天来聊聊Gymnasium。说实话,这个库是强化学习仿真里最基础的工具之一。我刚开始做机器人控制时,第一个接触的就是它。你想想看,没有环境,你的算法往哪儿跑?
Gymnasium是OpenAI Gym的继承者,说白了就是强化学习界的“Hello World”。它帮你把环境、动作、状态这些东西都封装好了。你只需要关心算法,不用操心底层通信。
3.1 核心API:Env、Space、Wrapper
Gymnasium有三个核心概念:Env(环境)、Space(空间)、Wrapper(包装器)。我习惯把它们比作:环境是舞台,空间是演员的活动范围,包装器是导演加的滤镜。
3.1.1 Env(环境)
Env是所有环境的基类。它定义了强化学习交互的基本接口。我个人觉得,理解Env的关键就两个方法:reset()和step()。
- reset():重置环境到初始状态。返回初始观测值。
- step(action):执行动作。返回(observation, reward, terminated, truncated, info)。
嗯,这里要注意:terminated表示任务是否完成(比如小车倒了),truncated表示是否因为步数限制而截断。这两个概念容易混淆,我在项目中就踩过坑。
3.1.2 Space(空间)
Space定义了动作和观测的取值范围。常见的有:
| 空间类型 | 说明 | 示例 |
|---|---|---|
| Discrete | 离散空间 | Discrete(2) → 0或1 |
| Box | 连续空间 | Box(low=-1, high=1, shape=(3,)) |
| MultiDiscrete | 多维离散 | MultiDiscrete([2, 3]) |
| Tuple | 组合空间 | Tuple((Discrete(2), Box(0,1))) |
我曾经在做一个机械臂项目时,动作空间定义错了维度,结果算法怎么都学不会。后来发现是Box的shape写成了(6,)而不是(7,)。这种低级错误,排查起来真让人头大。
3.1.3 Wrapper(包装器)
Wrapper允许你在不修改环境代码的前提下,给环境加功能。比如:
- TimeLimit:限制最大步数
- RecordVideo:录制视频
- NormalizeObservation:归一化观测值
我建议你养成用Wrapper的习惯。它让代码更干净,也方便调试。
核心要点:Env是骨架,Space是规则,Wrapper是扩展。三者配合,能应对绝大多数场景。
3.2 创建第一个CartPole环境
CartPole是强化学习的“Hello World”。一根杆子立在车上,你要控制小车左右移动,让杆子不倒。听起来简单,但做起来挺有意思。
创建环境只需要一行代码:
import gymnasium as gym
env = gym.make("CartPole-v1")
就这么简单。但别急着跑,先看看环境长什么样:
print("观测空间:", env.observation_space)
print("动作空间:", env.action_space)
print("观测示例:", env.reset())
输出大概是:
观测空间: Box([-4.8 -inf -inf -inf], [4.8 inf inf inf], (4,), float32)
动作空间: Discrete(2)
观测示例: (array([ 0.0123, 0.0456, -0.0234, 0.0789], dtype=float32), {})
观测有4个维度:小车位置、速度、杆子角度、角速度。动作只有两个:左移或右移。
小技巧:我习惯在创建环境后先打印空间信息,确认维度对不对。这一步能省掉很多调试时间。
3.3 环境交互循环
强化学习的核心就是交互循环。说白了就是:看状态→想动作→执行→看结果→再想动作。这个循环跑起来,算法才能学习。
标准交互循环长这样:
import gymnasium as gym
env = gym.make("CartPole-v1")
observation, info = env.reset()
for _ in range(1000):
action = env.action_space.sample() # 随机动作
observation, reward, terminated, truncated, info = env.step(action)
if terminated or truncated:
observation, info = env.reset()
env.close()
这里有几个关键点:
- reset()返回两个值:observation和info。info里可能包含调试信息。
- step()返回5个值:obs, reward, terminated, truncated, info。
- 任务结束后要调用
reset(),否则环境会卡住。
我曾经犯过一个错误:忘记检查terminated,结果环境一直返回无效状态,算法训练了三天都没收敛。嗯,这种教训一次就够了。
注意:Gymnasium的step()返回5个值,而旧版Gym返回4个。如果你看到代码里只有4个返回值,那可能是旧版API。升级时要注意兼容性。
3.4 渲染与可视化
光看数字没意思,咱们得让环境“动”起来。Gymnasium支持多种渲染模式:
| 渲染模式 | 说明 | 适用场景 |
|---|---|---|
| human | 弹出窗口显示 | 调试、演示 |
| rgb_array | 返回RGB数组 | 录制视频、训练CNN |
| ansi | 文本渲染 | 终端环境 |
使用human模式很简单:
env = gym.make("CartPole-v1", render_mode="human")
然后正常跑交互循环,就会弹出窗口显示画面。我建议你在调试时用human模式,能直观看到算法表现。
如果想录制视频,可以用RecordVideo包装器:
from gymnasium.wrappers import RecordVideo
env = gym.make("CartPole-v1", render_mode="rgb_array")
env = RecordVideo(env, video_folder="./videos")
这样每次reset()时,都会自动录制一段视频。我习惯用这个功能来保存训练过程,方便对比不同算法的效果。
个人经验:录制视频时,建议设置episode_trigger=lambda e: e % 10 == 0,每10个episode录一次。不然文件太多,硬盘受不了。
3.5 知识体系总览
为了让你更直观地理解本章内容,我画了一张图:
这张图展示了本章的知识脉络。从三个核心模块出发,经过CartPole实践,最后落到渲染可视化。你跟着这个路径走,就能把Gymnasium用起来。
好了,这一章就到这里。记住:环境是舞台,空间是规则,包装器是工具。把这三样玩明白,后面的强化学习之路就顺畅多了。