跳至主要内容

强化学习:基于 Python 示例的入门指南

通过猫学用猫抓柱的类比,学习强化学习的基本概念。
· 14分钟 阅读

使用 AI 探索

基础与深度强化学习(RL)模型在很多时候更像科幻中的 AI,而非当下的任意一种大语言模型。先来看看 RL 如何让一个智能体通关超级马里奥中的高难度关卡:

python_RL_lowq_lowres.gif

一开始,智能体对这款游戏一无所知。它不知道按键、不了解如何推进进度、不清楚有哪些障碍,也不知道怎样才能通关。它必须在没有人为干预的情况下学会这一切——完全依靠强化学习算法的力量。

RL 智能体能够在没有预设解法、没有明确编程动作、且最重要的是不依赖海量数据的情况下解决问题。这也是 RL 正在影响众多领域的原因。例如,它被用于:

  • 自动驾驶汽车: RL 智能体可基于交通状况与道路规则学习最优驾驶策略。
  • 机器人: 通过 RL,机器人能够在动态环境中完成复杂任务。
  • 游戏博弈: 借助 RL 技术,AI 智能体可以在围棋或星际争霸 II 等游戏中学习复杂策略。

强化学习是一个快速演进且潜力巨大的领域。随着研究推进,我们有望在资源管理、医疗健康与个性化学习等方向看到更多突破性应用。

因此,现在正是学习这一迷人机器学习分支的好时机。在本教程中,我们将帮助您理解强化学习的基本概念,并一步步讲解智能体、环境、动作、状态、奖励等关键要素。

智能体与环境

假设您想教您的猫 Bob 在房间里使用多个猫抓柱,而不是抓坏您昂贵的家具。用强化学习的术语来说,Bob 是智能体,即学习者和决策者。它需要学会哪些东西可以抓(地毯和猫抓柱),哪些不可以(沙发和窗帘)。

房间就是我们的环境,智能体与之交互。它既提供挑战(诱人的家具),也包含目标(令人满意的猫抓柱)。

在 RL 中,环境主要分为两类:

  • 离散环境: 如果房间像经典街机游戏那样被划分为网格,Bob 只能沿四个方向移动。此类环境中,无论是 Bob 的动作还是房间变化,都只有有限种可能。
  • 连续环境: 现实中的房间几乎可以无限排列猫抓柱和家具。此外,Bob 也可以自由做猫平时会做的各种事。因此,我们的房间是连续环境,Bob 与房间都存在无穷多种可能。

我们的房间还是一个静态环境。家具不会移动,猫抓柱也固定不变。

但如果您每隔几小时随机移动家具和猫抓柱(就像超级马里奥的不同关卡),房间就会变成一个动态环境。对于智能体来说,这更难学习,因为一切都在变化。

动作与状态

所有强化学习问题都有两个重要方面:状态空间与动作空间。

状态空间表示任意时刻智能体与环境可能处于的所有状态(情境)。状态空间的大小取决于环境类型:

  • 有限状态空间: 当环境是离散的,可能的状态数量是有限或可数无穷。例子包括棋类游戏、网格化电子游戏或井字棋。
  • 无限状态空间: 当环境是连续的,其状态空间是无界的。例子包括具有复杂角色与环境的电子游戏、机器人学会行走,或在我们的案例中,猫学习使用猫抓柱。

动作空间则是 Bob 在环境中可以做的所有事情。在猫抓柱的例子里,Bob 的动作可能包括抓猫抓柱、在沙发上打盹,甚至追自己的尾巴。

与状态空间类似,Bob 可执行的动作数量也取决于环境:

  • 离散环境: 在一个网格世界游戏中,Bob 的动作可能仅限于上、下、左、右移动以及抓挠。
  • 连续环境: 在现实房间里,Bob 的动作范围更广,比如向任意方向移动、跳跃,甚至(但希望不会)咬电线。

当 Bob 开始它的猫抓柱探险时,环境处于默认状态,我们称为状态零。在我们的例子里,这可能是已摆好猫抓柱的房间。它每做一个动作,环境就会转移到新的后续状态。

奖励、时间步与回合

要让 Bob 实现总体目标,它需要激励,也就是奖励。

大多数 RL 问题都有预先设定的奖励。例如,在国际象棋中,吃子是正奖励,被将军是负奖励。

在我们的案例里,如果我们观察到积极行为,比如在一段时间内没有抓家具,或者它确实找到了某个猫抓柱,我们可以给 Bob 奖励零食。如果它抓坏了窗帘,我们也可能用喷水来惩罚它。

为了衡量 Bob 学习进度,我们可以按时间步来看它的动作。比如在时间步 t1,Bob 采取动作 a1,带来新状态 s1(s0 是默认状态),它也可能获得一个奖励 r1。

一系列时间步的集合称为一个回合。回合总是从默认状态开始(家具与猫抓柱已摆好),并在目标达成(找到猫抓柱)或智能体失败(抓家具)时终止。有时,回合也可能根据经过的时间而结束(如在国际象棋中)。

探索与利用

像一名熟练的棋手一样,Bob 不应只满足于找到任意一个猫抓柱,而应追求能带来最多零食奖励的那一个。这突显了强化学习中的经典两难:探索与利用。

虽然一个诱人的猫抓柱可能带来即时满足,但更具策略性的探索可能在后面赢得大量奖励。正如棋手可能放弃一次吃子以获取更优位置,Bob 也可能先抓一个次优猫抓柱(探索),以发现终极抓挠天堂(利用)。这种长期策略对智能体在复杂环境中最大化回报至关重要。

换句话说,Bob 必须在利用(坚持当前最有效的做法)与探索(偶尔外出寻找新的猫抓柱)之间取得平衡。探索过多可能浪费时间,特别是在连续环境中;而过度利用又可能让 Bob 错过更好的选择。

幸运的是,Bob 可以采用一些巧妙策略:

  • Epsilon-贪心学习:想象一下,Bob 有一个会生成随机数的“抓挠仪”。如果生成的数字小于某个称为 epsilon 的预设阈值,Bob 就随机尝试一个抓挠表面(探索);如果数字大于 epsilon,Bob 就去抓之前感觉最好的猫抓柱(利用)。
  • Boltzmann 探索:如果 Bob 总在抓起来感觉不对(获得负奖励)的东西,它更可能去探索新选项(增加探索);但一旦找到完美的猫抓柱(正奖励),它就会守着那块“快乐之地”(利用)。

通过使用这些策略(或其他超出本文范围的策略),Bob 能在探索未知与坚守有效之间找到平衡。

强化学习算法

Bob 不可能凭空想出如何最大化零食数量。它需要方法与工具来指导其在环境各状态下的决策。这正是强化学习算法大显身手之处。

从更广的角度看,强化学习算法可按智能体如何与环境交互并从经验中学习来分类。两大类是基于模型与无模型方法。

基于模型的强化学习

在基于模型的算法中,智能体(如 Bob)会构建环境的内部模型。该模型刻画环境的动力学,包括状态转移与奖励概率。随后,智能体可以用这个模型在真实环境行动之前进行规划与评估不同动作。

这种方法的优势在于更高的样本效率,尤其在复杂环境中。也就是说,与纯粹的试错方法相比,Bob 可能需要更少的抓挠尝试就能找出最优猫抓柱,因为它可以先规划、后行动。

劣势是构建精确模型很难,特别是在复杂环境中。模型可能无法准确反映真实环境,从而导致次优行为。

常见的基于模型 RL 算法之一是Dyna-Q,它实际上结合了基于模型与无模型学习。它既构建环境模型并用于动作规划,同时也通过无模型的 Q-learning(我们稍后会解释)直接从经验中学习。

无模型的强化学习

这种方法专注于直接通过与环境交互来学习,而不显式构建内部模型。智能体(Bob)通过试错学习状态与动作的价值,或学习最优策略。

在难以构建精确模型的环境中,无模型 RL 提供了更简单的路径。对 Bob 而言,这意味着它无需绘制复杂的房间心智地图——可以通过抓挠并感受后果来学习。

无模型 RL 在规则可能变化的动态环境中表现出色。如果房间的家具布局改变,Bob 可以调整探索并学习新的最优抓挠点。

不过,仅靠试错学习的样本效率可能较低。Bob 或许得抓很多家具,才能稳定找到回报最高的猫抓柱。

常见的无模型 RL 算法包括:

  • Q-Learning: 该算法为每个状态-动作对学习一个 Q 值。Q 值表示在特定状态下采取某个动作的预期未来回报。随后,智能体选择 Q 值最高的动作以最大化长期回报(我们将在下一节更详细解释)。
  • SARSA(State-Action-Reward-State-Action): 与 Q-learning 类似,但它为每个状态-动作对学习一个价值函数。它根据采取动作后获得的奖励以及观察到的下一个状态来更新。
  • 策略梯度方法: 这类算法直接学习策略函数,即将状态映射到动作。它们使用梯度来沿着期望带来更高回报的方向更新策略。代表方法包括 REINFORCE 与 Proximal Policy Optimization(PPO)。
  • 深度 Q 网络(DQN): 该算法将 Q-learning 与深度神经网络结合,以应对高维状态空间,常见于电子游戏等复杂环境。

选择何种算法取决于多种因素:环境的复杂度、可用资源以及期望的可解释性水平。

在能较好构建精确模型的简单环境中,基于模型的方法可能更优;而在复杂的现实场景中,无模型方法通常更为实用。

此外,随着深度学习的发展,DQN 及其他深度 RL 算法在处理高维状态空间的复杂任务时日益受欢迎。

Q-learning

现在我们聚焦于一个具体算法,深入了解 Q-learning。

高层概览

Q-learning 是一种无模型算法,它通过与环境的聪明交互来教会智能体最优制胜策略。

让我们回到猫的例子,设想我们在一个离散环境、有限动作集合的街机版本中求解该问题。

假设我们给 Bob 一张表。列表示可用动作,每一行将该动作映射到状态空间中的一个特定状态。

A q-table that is used to guide the actions of an agent. Q-table is integral to Q-learning algorithm of reinforcement learning.

起初,我们用零填充该表,表示初始的Q 值——因此这叫做Q 表。

然后,我们从默认状态(回合开始)启动交互循环。在循环中,Bob 会在给定状态下选择 Q 值最高的动作。然而,在第一次循环时,并没有“最高 Q 值”可供参考,因为所有 Q 值最初都是零。

这时,探索策略(如随机探索或 epsilon-贪心)就派上用场了。它们帮助 Bob 在 Q 表为空时收集信息。

一旦 Q 表被更新,Bob 会再次开始交互循环。它采取的动作会产生奖励与新状态。接着,我们会为 Bob 在新状态下可以采取的每个动作计算新的 Q 值(稍后我们会展示如何计算)。

回合会持续到终止(Bob 在每个回合中可执行任意步数),然后我们重新开始。后续每个回合都会拥有更丰富的 Q 表,使 Bob 更加聪明。

以下是相关步骤的高层概览:

  1. 初始化 Q 表并填入初始值。
  2. 开始一个回合。
  3. 智能体采取动作。
  4. 衡量所获得的奖励。
  5. 到达新状态。
  6. 为新状态计算新的 Q 值。
  7. 回合因失败、胜利或超时而终止。
  8. 重置环境。
  9. 为所需回合数重复步骤 2-8。

像第 1 与第 2 步可能很直观,但其余步骤需要更多解释。

智能体如何选择动作?

在第 1 个时间步,Bob 的首次动作将是随机的,因为所有 Q 值为零。在后续时间步中,Bob 需要在探索与利用之间权衡。

为此,我们给 Bob 一个名为epsilon的超参数,取一个较小的值——通常为 0.1。然后,我们让 Bob 生成一个 0 到 1 的随机数,如果该数小于 epsilon,它将不考虑 Q 值而随机选择一个动作。

如果随机数大于 epsilon,Bob 将选择 Q 值最高的动作。这样,Bob 将以 epsilon(0.1 或 10%)的比例进行探索,以(1 - epsilon,即 0.9 或 90%)的比例进行利用。

我们刚描述的就是epsilon-贪心策略。策略定义了智能体如何采取动作以及如何计算 Q 值。

奖励如何衡量?

计算奖励的规则通常由环境的创建者设定。比如,您可以决定 Bob 使用地毯抓挠奖励一块零食,跳得足够高去抓墙上的猫抓柱奖励五块零食。对于抓挠贵重物品,您也可能惩罚它。

但多数时候并没有奖励,因为 Bob 可能只是在睡觉、走动或玩耍。

如何更新 Q 表?

计算 Q 值的公式看起来可能有些吓人,我们先给出完整形式,然后再逐步解释:

The official formula of Q-learning.

先看公式的开头:

The first component of Q-learning's formula

这部分的意思是:“给定先前的状态与动作,新的 Q 值计算为(……)”。

下面这部分是当前(即将成为旧的)Q 值,智能体据此采取了动作。

再看最后一部分:

St+1 是采取动作 At 后得到的新状态。因此,这部分是在该新状态下,从所有动作(a)中找最大的 Q 值。我们将该值乘以参数 γ(gamma,折扣因子),再与所获奖励相加。

如果将 gamma 设为接近 1,就更重视未来奖励;若调低至接近 0,则更强调当前奖励 Rt+1。这意味着 gamma 也是我们用于平衡探索与利用的一个参数。

最后是 alpha(α),它控制训练速度,范围为 0 到 1。接近 1 的取值会使 Q 值更新幅度更大,智能体学得更快,也让加号右侧更“重”。相反,接近 0 会让左侧(当前 Q 值)更“重”。

用学习率来控制训练速度,可避免智能体进展过快而遗忘旧信息,也能避免学习过慢而错过重要信息。

这是理解 Q-learning 最具挑战的部分,希望您已对其机理有一个大致感觉。

Python Gymnasium 中的强化学习

和很多事情一样,Python 也有解决强化学习问题的框架。最流行的是 Gymnasium,自带 2000 多个环境(且文档详尽)。

$ pip install "gymnasium[atari]"
$ pip install autorom[accept-rom-license]
$ AutoROM --accept-license

import gymnasium as gym
env = gym.make("ALE/Breakout-v5")

我们刚加载的环境叫做 Breakout。长这样:

目标是通过试错,让球拍(智能体)学会消除所有砖块。游戏规则决定了惩罚与奖励。

本文最后我们将展示如何运行您自己的交互回合,并用如上所示的 GIF 可视化智能体的进展。

以下是交互循环的代码:

epochs = 0

frames = []  # for animation
done = False

env = gym.make("ALE/Breakout-v5", render_mode="rgb_array")
observation, info = env.reset()

while not done:
    action = env.action_space.sample()
    observation, reward, terminated, truncated, info = env.step(action)

    # Put each rendered frame into dict for animation
    frames.append(
        {
            "frame": env.render(),
            "state": observation,
            "action": action,
            "reward": reward,
        }
    )

    epochs += 1
    if epochs == 1000:
        break

我们刚刚运行了一千个时间步,换言之,智能体执行了 1000 次动作。然而,所有这些动作都是完全随机的——它并没有从过去的错误中学习。为验证这一点,我们可以用 frames 变量来创建一个 GIF:

from moviepy.editor import ImageSequenceClip
# !pip install moviepy - if you don’t have moviepy

def create_gif(frames: dict, filename, fps=100):
    """
    Creates a GIF animation from a list of RGBA NumPy arrays.

    Args:
        frames: A list of RGBA NumPy arrays representing the animation frames.
        filename: The output filename for the GIF animation.
        fps: The frames per second of the animation (default: 10).
    """
    rgba_frames = [frame["frame"] for frame in frames]

    clip = ImageSequenceClip(rgba_frames, fps=fps)
    clip.write_gif(filename, fps=fps)

# Example usage
create_gif(frames, "animation.gif") #saves the GIF locally

注意:如果您遇到 “RuntimeError: No ffmpeg exe could be found” 错误,请在导入 moviepy 之前尝试添加以下两行代码:

from moviepy.config import change_settings
change_settings({"FFMPEG_BINARY": "/usr/bin/ffmpeg"})

我们的第一段代码在每个时间步返回了环境状态的 RGBA 数组,并存储在 frames 中。通过使用 moviepy 库把所有帧拼接在一起,我们就能创建前面看到的 GIF:

另外,若您运行了很多时间步,可以调整 fps 参数让 GIF 播放更快。

既然我们看到智能体只是在随机行动,是时候尝试一些算法了。您可以在 Reinforcement Learning with Gymnasium in Python 这门课程中一步步实践,其中涵盖 Q-learning、SARSA 等多种算法。

别忘了使用我们刚创建的函数来为智能体的进展制作动画,祝您玩得开心!

结语

强化学习是计算机科学与机器学习中最引人入胜的方向之一。在本教程中,我们学习了 RL 的基础概念——从智能体与环境到 Q-learning 等无模型算法。

不过,想要打造能解决国际象棋或电子游戏等复杂问题的世界级智能体,需要时间与练习。以下资源可助您一臂之力:

感谢阅读!

Bexruz (Bex) Tuychiev

作者

Bexruz (Bex) Tuychiev

我是一名数据科学内容创作者,拥有超过 2 年的经验,并在 Medium 上拥有较大的读者群。我喜欢用略带讽刺的笔调撰写有关 AI 和机器学习的深度文章——毕竟总得想点办法让这些内容不那么枯燥。我已发表 130 多篇文章,并制作了一门 DataCamp 课程,另有一门正在筹备中。我的内容已被超过 500 万人次阅读,其中有 2 万人在 Medium 和 LinkedIn 上成为关注者。 

主题