强化学习实践之旅:从零到构建高效马里奥AI

今天,我们踏上了一段激动人心的强化学习实践之旅。从理解最基础的环境交互,到应用高级算法和并行计算,我们一步步构建并完善了一个能够学习玩《超级马里奥兄弟》的AI。

一、 基础概念:智能体与环境的交互

万丈高楼平地起。我们首先要理解强化学习中最核心的交互循环。当一个智能体(Agent)在环境(Environment)中执行一个动作(Action)后,会发生什么?

答案是,环境会返回一个包含四个标准信息的值:obs, reward, done, info

# 这行代码是关键
state, reward, done, info = env.step(action)

这四个值的具体含义如下:

变量 含义 作用
obs 新状态 (Observation) 告诉智能体:“环境现在是什么样子了?”
reward 奖励信号 (Reward) 告诉智能体:“你刚才那步做得好不好?”
done 结束标志 (Done) 告诉智能体:“这一局结束了吗?”
info 调试信息 (Info) 告诉**我们(人类)**一些额外的、用于诊断的细节。

理解这个反馈循环是后续所有学习内容的基础。

二、 实践起步:探索环境与训练模型

理解了基本概念后,我们通过两个具体的代码实例,对比了“随机探索”和“算法训练”的区别。

阶段 1:随机探索马里奥环境

我们首先搭建了一个《超级马里奥兄弟》的游戏环境,但并未引入任何学习算法,而是让马里奥进行纯随机的动作。

from nes_py.wrappers import JoypadSpace
import gym_super_mario_bros
from gym_super_mario_bros.actions import SIMPLE_MOVEMENT

env = gym_super_mario_bros.make(SuperMarioBros-v2)
env = JoypadSpace(env, SIMPLE_MOVEMENT)

done = True
for step in range(5000):
    if done:
        state = env.reset()
    state, reward, done, info = env.step(env.action_space.sample())
    env.render()

env.close()

此时的马里奥只是在“瞎玩”,这帮助我们理解了如何加载和运行一个强化学习环境。

阶段 2:使用 A2C 算法训练 CartPole 模型

接着,我们引入了一个完整的强化学习流程:使用 stable-baselines3 库中的 A2C 算法来训练一个智能体玩经典的 “CartPole” 游戏。

import gym
from stable_baselines3 import A2C

env = gym.make("CartPole-v1")

model = A2C("MlpPolicy", env, verbose=1, tensorboard_log=logs)
model.learn(total_timesteps=10_0000)

obs = env.reset()
for i in range(1000):
    action, _state = model.predict(obs, deterministic=True)
    obs, reward, done, info = env.step(action)
    env.render()
    if done:
        obs = env.reset()

这个例子展示了一个完整的训练循环,包括定义环境、选择算法、训练模型、评估成果的全过程。

工具的地位与作用

  • Gym & Gym-like Environments: 强化学习领域的行业标准,提供了统一的环境接口,是算法开发和测试的基石。
  • Stable Baselines3 (SB3): 最流行、最受认可的 RL 算法库之一,提供了多种经典算法的可靠实现,极大降低了强化学习的实践门槛。
  • TensorBoard: 主流的可视化工具,能将抽象的训练数据变为直观的图表,是调试和优化模型的必备利器。

三、 深入训练:监控与理解训练过程

在开始真正的模型训练后,理解训练日志和监控工具变得至关重要。

1. 使用 TensorBoard 可视化训练

TensorBoard 是一个能让您**“看见”**模型训练过程的工具。在训练代码中,我们通过 tensorboard_log=logs 参数指定了日志的保存位置。

在 PyCharm 的 PowerShell 终端中,我们使用以下复合命令来启动 TensorBoard 和 Conda 环境:

$env:PYTHONIOENCODING="utf-8"; conda activate Rl_mario

这条命令不仅激活了正确的 Rl_mario 环境,还通过设置 PYTHONIOENCODING 解决了潜在的中文乱码问题。

启动 TensorBoard 后,我们重点关注 rollout 目录下的指标。rollout 指的是智能体与环境交互以收集经验数据的过程。其中最重要的指标是:

  • rollout/ep_rew_mean (Mean Episode Reward / 平均回合奖励): 这是判断训练是否成功的核心指标。它的持续上升意味着智能体正在变得越来越聪明。

2. 解读训练过程中的打印信息

训练时,控制台会打印出类似下表的摘要信息,这是 TensorBoard 的文本版快照。

-----------------------------------------
| time/                   |             |
|    fps                  | 151         |
|    iterations           | 2           |
|    time_elapsed         | 27          |
|    total_timesteps      | 4096        |
| train/                  |             |
|    approx_kl            | 0.014048623 |
|    clip_fraction        | 0.237       |
|    clip_range           | 0.2         |
|    entropy_loss         | -1.93       |
|    explained_variance   | 0.00061     |
|    learning_rate        | 0.0003      |
|    loss                 | 3.43        |
|    n_updates            | 10          |
|    policy_gradient_loss | 0.0138      |
|    value_loss           | 27.9        |
-----------------------------------------

这些指标帮助我们深入了解模型的内部状态,例如:

  • time/ 部分:关注 fps(每秒帧数),衡量训练速度。
  • train/ 部分
    • value_lossexplained_variance 反映了价值网络(Critic)的准确度。
    • policy_gradient_lossentropy_loss 反映了策略网络(Actor)的优化和探索程度。
    • approx_klclip_fraction 是 PPO 算法特有的诊断指标,用于监控策略更新的稳定性。

四、 优化与进阶:构建高效的训练管线

为了让马里奥AI学得更快、更好,我们对训练流程进行了多次关键的优化。

优化 1:自定义 SkipFrameWrapper 提升效率

连续的游戏帧之间信息冗余度很高。我们编写了一个自定义的环境包装器 SkipFrameWrapper,它让智能体每执行一次动作,游戏实际运行多帧,从而提高训练效率。

import gym

class SkipFrameWrapper(gym.Wrapper):
    def __init__(self, env, skip):
        super().__init__(env)
        self._skip = skip

    def step(self, action):
        obs, reward_total, done, info = None, 0, False, None
        for _ in range(self._skip):
            obs, reward, done, info = self.env.step(action)
            reward_total += reward
            if done:
                break
        return obs, reward_total, done, info

优化 2:多进程并行加速 (SubprocVecEnv)

这是训练流程中的一次巨大飞跃。我们使用 SubprocVecEnv 创建了8个并行的马里奥游戏环境,让它们在不同的CPU核心上同时运行和收集数据。这极大地提高了数据采样效率,加快了训练速度。

# 第 2 条记录内容:
import gym
from stable_baselines3 import A2C, PPO
from nes_py.wrappers import JoypadSpace
import gym_super_mario_bros
from gym_super_mario_bros.actions import SIMPLE_MOVEMENT
from gym.wrappers import GrayScaleObservation, ResizeObservation
from my_wrapper import SkipFrameWrapper
from test_obs import make_env
from stable_baselines3.common.vec_env import SubprocVecEnv

def main():
    env = make_env()
    vec_env = SubprocVecEnv([make_env for _ in range(8)])
    model = PPO("CnnPolicy", vec_env, verbose=1, tensorboard_log=logs)
    model.learn(total_timesteps=10_0000000)
    model.save(ppo_mario)

if __name__ == "__main__":
    main()

同时,我们选择了 PPO 算法和适合处理图像输入的 CnnPolicy 策略网络,并整合了灰度化 (GrayScaleObservation) 和尺寸缩放 (ResizeObservation) 等标准预处理步骤。

优化 3:引入帧堆叠 (VecFrameStack) 感知动态

最后,我们为AI安装了一双能够感知**“时间”和“动态”**的眼睛。仅靠单张静态图片,AI无法判断马里奥的运动方向和速度。 VecFrameStack 通过将连续的4帧画面堆叠在一起,形成一个 (84, 84, 4) 的输入,让AI能够感知到动态信息。

# 第 1 条记录内容:
import gym
from stable_baselines3 import A2C, PPO
from nes_py.wrappers import JoypadSpace
import gym_super_mario_bros
from gym_super_mario_bros.actions import SIMPLE_MOVEMENT
from gym.wrappers import GrayScaleObservation, ResizeObservation
from my_wrapper import SkipFrameWrapper
from test_obs import make_env
from stable_baselines3.common.vec_env import SubprocVecEnv, VecFrameStack

def main():
    # 环境创建及环境预处理
    env = make_env()
    vec_env = SubprocVecEnv([make_env for _ in range(8)])
    vec_env= VecFrameStack(vec_env, 4, channels_order=last) # 帧堆叠
    
    # 模型训练
    model = PPO("CnnPolicy", vec_env, verbose=1, tensorboard_log=logs)
    model.learn(total_timesteps=10_0000000)
    model.save(ppo_mario)

if __name__ == __main__:
    main()

至此,我们已经构建了一个整合了并行加速、计算优化和动态信息感知的、非常完整和强大的强化学习训练管线。这是训练高水平游戏AI的标准配置,期待我们的马里奥AI在经过大规模训练后的精彩表现!

Logo

更多推荐