第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 知识体系总览

为了让你更直观地理解本章内容,我画了一张图:

Gymnasium核心知识体系 Env(环境) Space(空间) Wrapper(包装器) reset() / step() Discrete / Box / Tuple TimeLimit / RecordVideo 实践:CartPole环境交互循环 渲染与可视化(human / rgb_array)

这张图展示了本章的知识脉络。从三个核心模块出发,经过CartPole实践,最后落到渲染可视化。你跟着这个路径走,就能把Gymnasium用起来。

好了,这一章就到这里。记住:环境是舞台,空间是规则,包装器是工具。把这三样玩明白,后面的强化学习之路就顺畅多了。