强化学习示例 - MACHINE-LEARNING教程

机器学习 - 强化学习示例

想象一下,你在教一只小狗学习坐下这个指令。你不会直接告诉它坐下这个单词是什么意思,而是通过奖励和惩罚来引导它。

  • 当小狗偶然做出坐下的动作时,你立刻给它一块零食( 奖励 )。
  • 当它做错时,你就不给零食( 惩罚 )。

经过多次尝试,小狗最终会明白坐下这个指令与获得零食之间的关联,从而学会这个技能。

强化学习 就是让计算机(或智能体)通过类似试错的方式,在与环境的互动中学习如何做出最优决策,以获得最大累积奖励的一种机器学习方法。

强化学习 与我们之前学过的监督学习(有标准答案)和无监督学习(寻找数据内在结构)有本质区别。强化学习的核心是 智能体 环境 的持续交互。


核心概念解析

在深入代码之前,我们先来理解几个关键概念,它们就像游戏规则,定义了强化学习世界如何运转。

  • 智能体: 智能体就是我们的学习者或决策者。在上面的比喻中,它就是那只小狗。在程序中,它是一个算法,负责观察环境、做出动作并从结果中学习。

  • 环境: 环境是智能体所处的外部世界。它接收智能体的动作,并给出两个反馈:新的环境状态和本次动作带来的即时奖励。

  • 状态: 状态是环境在某一时刻的具体情况描述。例如,在一个走迷宫的游戏里,状态就是智能体当前所在的位置坐标。

  • 动作: 动作是智能体在某个状态下可以做出的选择。比如,在迷宫中,动作可以是向上、向下、向左、向右。

  • 奖励: 奖励是环境对智能体动作的直接评价信号,通常是一个数值。 正奖励 表示鼓励, 负奖励 表示惩罚。智能体的终极目标就是最大化从开始到结束所获得的 总奖励(累积奖励)

  • 策略: 策略是智能体的行为准则,它定义了在每一个可能的状态下,应该选择哪个动作。学习的过程,本质上就是优化这个策略的过程。

为了更直观地理解这些概念如何协同工作,我们来看一下强化学习的基本交互流程:

这个循环会一直持续,直到达到终止状态(如游戏通关或失败)。


经典问题:悬崖寻路

为了将理论付诸实践,我们将使用一个经典的强化学习示例环境: CliffWalking-v0 (悬崖寻路)。它来自 gymnasium 库(原 OpenAI Gym 的维护分支)。

环境描述

  • 场景 :一个 4x12 的网格世界。
  • 起点 :左下角(坐标 [3, 0])。
  • 终点 :右下角(坐标 [3, 11])。
  • 悬崖 :最底部一排除了起点和终点的所有位置([3, 1] 到 [3, 10]),掉入悬崖会获得巨大惩罚并回到起点。
  • 目标 :智能体要从起点安全地走到终点,并避免掉下悬崖。
  • 动作 :上(0)、右(1)、下(2)、左(3)。
  • 奖励
    • 每走一步普通网格:-1(鼓励用更少步数到达)
    • 掉下悬崖:-100,并被送回起点
    • 到达终点:0,并结束本次尝试

算法简介:Q-Learning

我们将使用 Q-Learning 算法来解决这个问题。它是一种 无模型 的强化学习算法,意味着智能体不需要预先知道环境的运作规则(如状态转移概率),它通过不断尝试来学习。

它的核心是一个名为 Q表 的表格。

  • 代表所有可能的状态。
  • 代表所有可能的动作。
  • 单元格的值(Q值) 代表在某个状态下,采取某个动作的长期期望收益。

Q-Learning 的学习过程可以概括为以下几步,它展示了智能体如何通过一次经验来更新自己的知识(Q表):

核心公式:贝尔曼方程

Q表更新的数学基础是贝尔曼方程,其更新公式如下:

\[ Q(S, A) \leftarrow Q(S, A) + \alpha [R + \gamma \max_{a} Q(S', a) - Q(S, A)] \]

让我们拆解这个公式中的每个部分:

符号 含义 类比解释
\( Q(S, A) \) 状态S下动作A原有的Q值 你之前对在十字路口直行这个决策的旧评分
\(\alpha \) 学习率 (0 < α ≤ 1) 你有多相信这次的新经验。α=1表示完全用新经验覆盖旧认知;α=0.1表示新经验只轻微修正旧认知
\(R \) 执行动作A后获得的 即时奖励 你直行后,发现道路通畅,获得了一个小的正反馈(+1)
\(\gamma \) 折扣因子 (0 ≤ γ < 1) 你对未来奖励的重视程度。γ=0表示只在乎眼前奖励;γ=0.9表示非常重视长远收益
\(\max_{a} Q(S', a) \) 在新状态S'下,所有可能动作中最大的Q值 到达新路口后,你评估左转、右转、直行哪个未来收益最高
\(R + \gamma \max_{a} Q(S', a)\) 目标Q值 ,代表对当前决策的新的、更优的估计 结合即时奖励和未来最佳收益,得出对在旧路口直行这个决策的新评分
\(R + \gamma \max_{a} Q(S', a) - Q(S, A)\) 时序差分误差 ,新老认知的差距 新评分与旧评分的差距,这个差距驱动学习

简单来说,这个公式让智能体用 即时奖励 + 对未来最优估计的折扣 来不断修正自己对当前决策价值的判断。


实战:编写Q-Learning智能体

现在,让我们用代码实现一个解决悬崖寻路问题的Q-Learning智能体。

步骤1:安装与导入库

首先,确保你已安装必要的库。在终端或命令行中运行:

示例代码
pipinstallgymnasium numpy

然后,在Python文件中导入它们:

示例代码
importgymnasiumasgymimportnumpyasnpimportrandom

步骤2:初始化环境和Q表

示例代码
# 1. 创建环境env=gym.make("CliffWalking-v0",render_mode="human")# render_mode="human" 用于可视化# 2. 获取环境信息n_states=env.observation_space.n# 状态总数 (4*12=48)n_actions=env.action_space.n# 动作总数 (4个方向)# 3. 初始化Q表, 形状为 [状态数, 动作数], 初始值全为0Q_table=np.zeros((n_states,n_actions))print(f"环境状态数: {n_states}, 动作数: {n_actions}")print(f"Q表形状: {Q_table.shape}")

步骤3:设置超参数

超参数是控制算法行为的旋钮,需要根据问题调整。

示例代码
# 定义超参数alpha=0.1# 学习率:新信息的影响程度gamma=0.99# 折扣因子:未来奖励的重要性epsilon=0.1# 探索率:以多大概率进行随机探索(而非选择已知最优)num_episodes=500# 训练轮数(智能体玩游戏的次数)

步骤4:实现ε-greedy策略

这是智能体做决策的核心策略,它平衡了 探索 利用

  • 探索 :随机选择动作,以发现可能更好的策略。
  • 利用 :选择当前Q表认为最优的动作,以获取最大收益。
示例代码
defchoose_action(state,Q_table,epsilon):"""根据ε-greedy策略选择动作。参数:state: 当前状态Q_table: Q值表epsilon: 探索概率返回:action: 选择的动作 (0, 1, 2, 3)"""# 生成一个0-1之间的随机数ifrandom.uniform(0,1)<epsilon:# 探索:随机选择一个动作action=env.action_space.sample()else:# 利用:选择当前状态下Q值最大的动作# np.argmax 返回最大值的索引,即最优动作action=np.argmax(Q_table[state])returnaction

步骤5:核心训练循环

这是算法学习的主要过程。

示例代码
# 用于记录每轮的总奖励,以便观察学习进展reward_history=[]forepisodeinrange(num_episodes):# 重置环境,获取初始状态state,_=env.reset()total_reward=0# 本轮累积奖励terminated=False# 是否到达终止状态(终点/悬崖)truncated=False# 是否因步数超限而终止(本环境一般不会)# 本轮交互循环,直到游戏结束whilenot(terminatedortruncated):# 1. 选择动作action=choose_action(state,Q_table,epsilon)# 2. 执行动作,获取环境反馈next_state,reward,terminated,truncated,_=env.step(action)# 3. 更新Q表 (Q-Learning 核心更新公式)# 获取当前Q值current_q=Q_table[state,action]# 计算目标Q值:即时奖励 + 未来最大Q值的折扣# 注意:如果下一状态是终止状态,则没有未来Q值ifterminated:target_q=rewardelse:target_q=reward + gamma * np.max(Q_table[next_state])# 应用贝尔曼方程更新Q值Q_table[state,action]=current_q + alpha *(target_q - current_q)# 4. 转移到下一个状态,并累积奖励state=next_statetotal_reward +=reward# 记录本轮总奖励reward_history.append(total_reward)# 每100轮打印一次进度if(episode +1)%100==0:avg_reward=np.mean(reward_history[-100:])# 最近100轮的平均奖励print(f"轮次 {episode + 1}, 最近100轮平均奖励: {avg_reward:.2f}")# 训练结束,关闭环境env.close()

步骤6:测试训练好的智能体

训练完成后,我们关闭探索,让智能体纯粹利用学到的知识(Q表)来走一遍,看看它的表现。

示例代码
print("\n=== 开始测试 ===")# 创建新的测试环境(可以不加render_mode,或改为"human"观看)test_env=gym.make("CliffWalking-v0",render_mode="human")state,_=test_env.reset()test_terminated=Falsetest_truncated=Falsestep_count=0whilenot(test_terminatedortest_truncated):# 测试时,我们设置 epsilon=0, 即完全利用,不探索action=choose_action(state,Q_table,epsilon=0)state,reward,test_terminated,test_truncated,_=test_env.step(action)step_count +=1print(f"步骤 {step_count}: 状态 {state}, 动作 {action}, 奖励 {reward}")print(f"测试完成!总步数: {step_count}, 总奖励: {reward} (到达终点奖励为0)")test_env.close()

运行结果与分析

完整代码:

示例代码
importgymnasiumasgymimportnumpyasnpimportrandom# =========================# 1. 创建环境# =========================env=gym.make("CliffWalking-v0",render_mode="human")# =========================# 2. 获取环境信息# =========================n_states=env.observation_space.nn_actions=env.action_space.n# =========================# 3. 初始化 Q 表# =========================Q_table=np.zeros((n_states,n_actions))print(f"环境状态数: {n_states}")print(f"动作数: {n_actions}")print(f"Q表形状: {Q_table.shape}")# =========================# 4. 设置超参数# =========================alpha=0.1gamma=0.99epsilon=0.1num_episodes=500# =========================# 5. ε-greedy 策略# =========================defchoose_action(state,Q_table,epsilon):ifrandom.uniform(0,1)<epsilon:returnenv.action_space.sample()returnnp.argmax(Q_table[state])# =========================# 6. 训练循环# =========================reward_history=[]forepisodeinrange(num_episodes):state,_=env.reset()total_reward=0terminated=Falsetruncated=Falsewhilenot(terminatedortruncated):action=choose_action(state,Q_table,epsilon)next_state,reward,terminated,truncated,_=env.step(action)current_q=Q_table[state,action]ifterminated:target_q=rewardelse:target_q=reward + gamma * np.max(Q_table[next_state])Q_table[state,action]=current_q + alpha *(target_q - current_q)state=next_statetotal_reward +=rewardreward_history.append(total_reward)if(episode +1)%100==0:avg_reward=np.mean(reward_history[-100:])print(f"轮次 {episode + 1},最近100轮平均奖励: {avg_reward:.2f}")env.close()# =========================# 7. 测试训练结果# =========================print("\n=== 开始测试 ===")test_env=gym.make("CliffWalking-v0",render_mode="human")state,_=test_env.reset()terminated=Falsetruncated=Falsestep_count=0total_reward=0whilenot(terminatedortruncated):action=choose_action(state,Q_table,epsilon=0)state,reward,terminated,truncated,_=test_env.step(action)step_count +=1total_reward +=rewardprint(f"步骤 {step_count}: 状态 {state}, 动作 {action}, 奖励 {reward}")print(f"测试完成,总步数: {step_count},总奖励: {total_reward}")test_env.close()

运行上述完整代码后,你将看到两个非常直观的现象:训练阶段的奖励变化,以及测试阶段智能体的实际行动路径。

1. 训练阶段:奖励逐步提升

在训练过程中,控制台会每 100 轮输出一次最近 100 轮的平均奖励。例如:


轮次 100, 最近100轮平均奖励: -120.45

轮次 200, 最近100轮平均奖励: -65.32

轮次 300, 最近100轮平均奖励: -32.18

轮次 400, 最近100轮平均奖励: -18.06

轮次 500, 最近100轮平均奖励: -13.94

你会发现一个明显趋势: 平均奖励在不断上升(负值绝对值变小)

这说明什么?

  • 在训练初期,智能体频繁掉入悬崖,受到大量 -100 的惩罚。
  • 随着训练进行,Q 表逐渐学习到"哪些路径危险、哪些路径安全"。
  • 智能体开始主动绕开悬崖,选择一条虽然更长、但惩罚更小的安全路线。

奖励的提升,本质上反映了策略质量的提升。

2. 测试阶段:智能体的行为表现

在测试阶段,我们将 epsilon 设置为 0,意味着:

  • 不再进行任何随机探索
  • 完全按照 Q 表中学到的最优策略行动

如果你开启了 render_mode="human" ,会看到一个非常典型的行为:

  • 智能体从起点出发
  • 沿着悬崖上方一格的位置水平移动
  • 在接近终点时再向下移动,安全抵达终点

这正是 CliffWalking 环境中被认为的 最优策略

  • 不是最短路径(贴着悬崖)
  • 而是 期望惩罚最小 的路径

这体现了强化学习的一个核心特征: 它追求的是长期累计回报,而不是短期最优

3. 为什么学到的是绕路,而不是冒险直走?

这是一个非常重要、也非常经典的问题。

从人类直觉来看,贴着悬崖走是最短路径,但对智能体来说:

  • 一旦走错一步,立刻获得 -100 的巨大惩罚
  • 相比之下,多走几步只会多几个 -1

在贝尔曼方程的累计效应下:

稳定的小损失 < 偶发的大灾难

因此,Q-Learning 会自然收敛到一条更保守、但整体期望回报更高的策略。


常见问题与参数影响

1. 学习率 α 过大或过小会发生什么?

  • α 过大 :学习过程震荡,策略不稳定,容易反复推翻已有经验
  • α 过小 :学习非常慢,需要大量轮次才能收敛

在这个示例中, 0.1 是一个相对稳妥的选择。

2. 折扣因子 γ 的直观含义

  • γ → 0 :智能体只关心眼前奖励,容易变得短视
  • γ → 1 :智能体非常重视长期后果,更像有远见的规划者

在悬崖寻路问题中,较大的 γ 能帮助智能体意识到现在多走一步,是为了未来避免更大损失。

3. ε 的作用本质

ε 决定了智能体的性格:

  • ε 大 → 爱冒险,探索多
  • ε 小 → 保守,更多利用已有经验

在真实项目中,通常会使用 ε 衰减策略

  • 前期多探索
  • 后期逐渐收敛到稳定策略

本示例的局限与扩展方向

虽然 Q-Learning 非常经典,但它也有明显限制:

  • Q 表大小随状态空间线性增长
  • 无法直接处理连续状态(如真实物理世界)
  • 在复杂环境中收敛速度慢

这也是为什么在更复杂问题中,我们会引入:

  • Deep Q-Network(DQN)
  • Policy Gradient
  • Actor-Critic

它们用神经网络替代 Q 表,使强化学习能够应用到游戏、机器人控制、自动驾驶等真实场景。


总结

通过这个完整的强化学习示例,你已经:

  1. 理解了强化学习与监督 / 无监督学习的根本区别
  2. 掌握了智能体、环境、状态、动作、奖励、策略的完整闭环
  3. 亲手实现了一个可运行、可观察、可收敛的 Q-Learning 智能体
  4. 理解了最大化长期回报这一强化学习的核心思想