Langchain系列文章目录
01-玩转LangChain:从模型调用到Prompt模板与输出解析的完整指南
02-玩转 LangChain Memory 模块:四种记忆类型详解及应用场景全覆盖
03-全面掌握 LangChain:从核心链条构建到动态任务分配的实战指南
04-玩转 LangChain:从文档加载到高效问答系统构建的全程实战
05-玩转 LangChain:深度评估问答系统的三种高效方法(示例生成、手动评估与LLM辅助评估)
06-从 0 到 1 掌握 LangChain Agents:自定义工具 + LLM 打造智能工作流!
07-【深度解析】从GPT-1到GPT-4:ChatGPT背后的核心原理全揭秘
PyTorch系列文章目录
Python系列文章目录
机器学习系列文章目录
01-什么是机器学习?从零基础到自动驾驶案例全解析
02-从过拟合到强化学习:机器学习核心知识全解析
03-从零精通机器学习:线性回归入门
04-逻辑回归 vs. 线性回归:一文搞懂两者的区别与应用
05-决策树算法全解析:从零基础到Titanic实战,一文搞定机器学习经典模型
06-集成学习与随机森林:从理论到实践的全面解析
07-支持向量机(SVM):从入门到精通的机器学习利器
08-【机器学习】KNN算法入门:从零到电影推荐实战
09-【机器学习】朴素贝叶斯入门:从零到垃圾邮件过滤实战
10-【机器学习】聚类算法全解析:K-Means、层次聚类、DBSCAN在市场细分的应用
11-【机器学习】降维与特征选择全攻略:PCA、LDA与特征选择方法详解
12-【机器学习】手把手教你构建神经网络:从零到手写数字识别实战
13-【机器学习】从零开始学习卷积神经网络(CNN):原理、架构与应用
14-【机器学习】RNN与LSTM全攻略:解锁序列数据的秘密
15-【机器学习】GAN从入门到实战:手把手教你实现生成对抗网络
16-【机器学习】强化学习入门:从零掌握 Agent 到 DQN 核心概念与 Gym 实战
文章目录
前言
大家好!欢迎来到我们机器学习探索之旅的第 16 天!在前面的学习中,我们已经接触了监督学习和无监督学习。今天,我们将踏入一个同样令人兴奋且应用广泛的领域——强化学习 (Reinforcement Learning, RL)。想象一下,我们如何学习骑自行车?不是通过阅读说明书,而是通过不断的尝试、摔倒、调整,最终掌握平衡。强化学习正是模拟了这种“试错学习”的过程,让机器(智能体 Agent)在与环境 (Environment) 的交互中学习如何做出最优决策,以获得最大的累积奖励 (Reward)。从 AlphaGo 战胜围棋冠军,到机器人自主导航、推荐系统优化,再到游戏 AI 的惊人表现,强化学习正展现出其独特的魅力和强大的能力。
在本篇文章中,我们将系统地为你揭开强化学习的神秘面纱:
- 理解强化学习的基本框架和核心概念。
- 掌握强化学习的数学基石——马尔可夫决策过程 (MDP)。
- 深入理解价值函数与策略函数的意义。
- 详细解析经典的 Q-Learning 算法。
- 初步了解深度强化学习的代表——深度 Q 网络 (DQN)。
- 通过 OpenAI Gym 的 CartPole 实例,亲手实践一个简单的强化学习任务。
无论你是刚接触 RL 的新手,还是希望巩固基础知识的进阶者,相信本文都能为你提供清晰、实用且深入的指导。让我们一起开始吧!
一、强化学习:让机器在交互中学习
强化学习的核心思想是让智能体通过与环境的互动来学习。它不像监督学习那样有明确的“标签”告诉智能体每一步应该怎么做,而是通过环境反馈的“奖励”或“惩罚”来引导智能体学习。
1.1 什么是强化学习 (RL)?
强化学习是机器学习的一个分支,关注的是智能体 (Agent) 如何在一个环境 (Environment) 中采取一系列动作 (Action),以最大化其获得的累积奖励 (Cumulative Reward)。
可以把它想象成训练宠物:
- 智能体 (Agent):你的宠物。
- 环境 (Environment):你家以及周围的环境。
- 状态 (State):宠物当前所处的情况(例如,在客厅、饿了、听到了“坐下”的指令)。
- 动作 (Action):宠物可以做出的行为(例如,跑、叫、坐下、摇尾巴)。
- 奖励 (Reward):你对宠物行为的反馈(例如,执行“坐下”后给零食是正奖励,随地大小便是负奖励或惩罚)。
宠物通过不断尝试不同的动作,并观察得到的奖励,逐渐学会哪些行为能带来好的结果(零食),哪些行为会带来坏的结果。
1.2 核心要素:智能体与环境的互动
强化学习系统主要由以下几个核心要素构成:
- 智能体 (Agent):学习者和决策者。它可以是任何能够采取行动的事物,例如机器人、游戏角色、自动驾驶系统中的控制器等。
- 环境 (Environment):智能体所处的外部世界。智能体与之交互,并能对其产生影响。
- 状态 (State - S):描述环境在某一时刻的具体情况。例如,在棋类游戏中,棋盘的布局就是一种状态;在自动驾驶中,车辆的位置、速度、周围障碍物等信息构成了状态。
- 动作 (Action - A):智能体可以执行的操作。动作会改变环境的状态。例如,棋类游戏中下一步棋,自动驾驶中转动方向盘、加速或刹车。
- 奖励 (Reward - R):环境对智能体在某个状态下执行某个动作后给出的即时反馈信号。它是一个标量值,表示该动作的好坏。正奖励表示鼓励,负奖励表示惩罚。
1.3 强化学习的目标
强化学习的目标不是最大化眼前的即时奖励,而是最大化从当前状态开始的长期累积奖励(通常是带有折扣的未来奖励总和)。这涉及到延迟奖励 (Delayed Reward) 的概念:有时当前一步看似不好的动作(例如,为了吃掉对方一个重要的棋子而牺牲自己一个次要的棋子),从长远来看可能会带来更大的总收益(赢得整局游戏)。智能体需要学会权衡短期利益和长期目标。
二、马尔可夫决策过程 (MDP):RL 的数学基石
为了更形式化地描述强化学习问题,我们引入了马尔可夫决策过程 (Markov Decision Process, MDP)。MDP 是对序贯决策问题的经典数学建模框架。
2.1 什么是马尔可夫决策过程?
MDP 基于一个核心假设:马尔可夫性质 (Markov Property)。该性质指出,未来的状态只取决于当前的状态和动作,而与过去的历史状态无关。换句话说,当前状态 S t S_t St 已经包含了所有与未来决策相关的信息。
P ( S t + 1 ∣ S t , A t , S t − 1 , A t − 1 , . . . , S 0 , A 0 ) = P ( S t + 1 ∣ S t , A t ) P(S_{t+1} | S_t, A_t, S_{t-1}, A_{t-1}, ..., S_0, A_0) = P(S_{t+1} | S_t, A_t) P(St+1∣St,At,St−1,At−1,...,S0,A0)=P(St+1∣St,At)
虽然现实世界并不总是严格满足马尔可夫性质,但在许多场景下,这是一个非常有用且合理的简化。
2.2 MDP 的组成要素
一个标准的 MDP 通常由以下五个元素定义: ( S , A , P , R , γ ) (S, A, P, R, \gamma) (S,A,P,R,γ)
2.2.1 状态集合 (S)
智能体可能遇到的所有状态的集合。可以是离散的(如棋盘位置),也可以是连续的(如机器人手臂的角度)。
2.2.2 动作集合 (A)
智能体在每个状态下可以采取的所有动作的集合。同样可以是离散的(上、下、左、右)或连续的(方向盘转动角度)。
2.2.3 转移概率 §
状态转移概率函数, P ( s ′ ∣ s , a ) = P r ( S t + 1 = s ′ ∣ S t = s , A t = a ) P(s' | s, a) = Pr(S_{t+1}=s' | S_t=s, A_t=a) P(s′∣s,a)=Pr(St+1=s′∣St=s,At=a)。它表示在状态 s s s 下采取动作 a a a 后,转移到下一个状态 s ′ s' s′ 的概率。在确定性环境中,这个概率是 1;在随机性环境中(如掷骰子),则是一个概率分布。
2.2.4 奖励函数 ®
描述了智能体在状态 s s s 下采取动作 a a a 并转移到状态 s ′ s' s′ 后,能获得的即时奖励。通常表示为 R ( s , a , s ′ ) R(s, a, s') R(s,a,s′) 或简化为 R ( s , a ) R(s, a) R(s,a) (转移后立即获得的奖励) 或 R ( s ) R(s) R(s) (进入某个状态获得的奖励)。
2.2.5 折扣因子 (γ - Gamma)
折扣因子 γ \gamma γ 是一个介于 0 和 1 之间的值 ( 0 ≤ γ < 1 0 \le \gamma < 1 0≤γ<1)。它用于衡量未来奖励相对于当前奖励的重要性。
- 如果 γ \gamma γ 接近 0,智能体更关注即时奖励(短视)。
- 如果
γ
\gamma
γ 接近 1,智能体更关注长期累积奖励(远视)。
引入折扣因子可以确保无限过程的累积奖励是收敛的,并且符合经济学中“未来的回报不如当前的回报有价值”的直觉。
三、价值函数与策略函数:指导智能体的决策
在 MDP 框架下,智能体如何学习做出最优决策呢?这需要引入两个核心概念:策略函数和价值函数。
3.1 策略函数 (Policy Function - π)
策略 (Policy) 定义了智能体在特定状态下选择动作的方式。可以看作是智能体的“行为准则”。
- 确定性策略 (Deterministic Policy): a = π ( s ) a = \pi(s) a=π(s),在每个状态 s s s 下,策略直接指定一个唯一的动作 a a a。
- 随机性策略 (Stochastic Policy): π ( a ∣ s ) = P r ( A t = a ∣ S t = s ) \pi(a|s) = Pr(A_t=a | S_t=s) π(a∣s)=Pr(At=a∣St=s),在每个状态 s s s 下,策略给出一个采取各个动作 a a a 的概率分布。
强化学习的目标就是找到一个最优策略 π ∗ \pi^* π∗,使得智能体遵循该策略时能够获得最大的累积奖励。
3.2 价值函数 (Value Function)
价值函数 用来评估一个状态或状态-动作对的“好坏程度”,即遵循特定策略 π \pi π 时,从该状态或状态-动作对开始所能获得的期望累积奖励。
3.2.1 状态价值函数 (Vπ(s))
状态价值函数
V
π
(
s
)
V^{\pi}(s)
Vπ(s) 表示在状态
s
s
s 开始,遵循策略
π
\pi
π 所能获得的期望累积奖励。
V
π
(
s
)
=
E
π
[
∑
k
=
0
∞
γ
k
R
t
+
k
+
1
∣
S
t
=
s
]
V^{\pi}(s) = E_{\pi}[\sum_{k=0}^{\infty} \gamma^k R_{t+k+1} | S_t = s]
Vπ(s)=Eπ[k=0∑∞γkRt+k+1∣St=s]
它回答了“处于状态
s
s
s 有多好?”这个问题。
3.2.2 动作价值函数 (Qπ(s, a))
动作价值函数
Q
π
(
s
,
a
)
Q^{\pi}(s, a)
Qπ(s,a) 表示在状态
s
s
s 下,采取动作
a
a
a,然后继续遵循策略
π
\pi
π 所能获得的期望累积奖励。
Q
π
(
s
,
a
)
=
E
π
[
∑
k
=
0
∞
γ
k
R
t
+
k
+
1
∣
S
t
=
s
,
A
t
=
a
]
Q^{\pi}(s, a) = E_{\pi}[\sum_{k=0}^{\infty} \gamma^k R_{t+k+1} | S_t = s, A_t = a]
Qπ(s,a)=Eπ[k=0∑∞γkRt+k+1∣St=s,At=a]
它回答了“在状态
s
s
s 下采取动作
a
a
a 有多好?”这个问题。Q 函数(读作 Q-function)对于决策至关重要,因为如果我们知道了所有动作的 Q 值,就可以选择 Q 值最大的那个动作。
3.3 Bellman 方程:价值函数的递归关系
价值函数(包括 V 函数和 Q 函数)满足一种递归关系,称为贝尔曼方程 (Bellman Equation)。它将一个状态(或状态-动作对)的价值与其后继状态的价值联系起来。
对于动作价值函数 Q,贝尔曼最优方程 (Bellman Optimality Equation) 描述了最优 Q 函数
Q
∗
(
s
,
a
)
Q^*(s, a)
Q∗(s,a) 必须满足的关系:
Q
∗
(
s
,
a
)
=
E
[
R
t
+
1
+
γ
max
a
′
Q
∗
(
S
t
+
1
,
a
′
)
∣
S
t
=
s
,
A
t
=
a
]
Q^*(s, a) = E[R_{t+1} + \gamma \max_{a'} Q^*(S_{t+1}, a') | S_t=s, A_t=a]
Q∗(s,a)=E[Rt+1+γa′maxQ∗(St+1,a′)∣St=s,At=a]
Q
∗
(
s
,
a
)
=
∑
s
′
P
(
s
′
∣
s
,
a
)
[
R
(
s
,
a
,
s
′
)
+
γ
max
a
′
Q
∗
(
s
′
,
a
′
)
]
Q^*(s, a) = \sum_{s'} P(s' | s, a) [R(s, a, s') + \gamma \max_{a'} Q^*(s', a')]
Q∗(s,a)=s′∑P(s′∣s,a)[R(s,a,s′)+γa′maxQ∗(s′,a′)]
这个方程说明:最优策略下,在状态
s
s
s 采取动作
a
a
a 的价值,等于立即获得的奖励
R
R
R 加上所有可能的下一个状态
s
′
s'
s′ 的最优未来价值(即在
s
′
s'
s′ 状态下选择最优动作
a
′
a'
a′ 的 Q 值)的期望,并进行折扣。
贝尔曼方程是许多强化学习算法(包括 Q-Learning)的基础。
四、Q-Learning:经典的无模型学习算法
Q-Learning 是一种非常流行且重要的无模型 (Model-Free) 强化学习算法。所谓“无模型”,是指它不需要事先知道环境的完整模型(即不需要知道状态转移概率 P P P 和奖励函数 R R R),可以直接从与环境的交互经验中学习最优策略。
4.1 Q-Learning 的核心思想
Q-Learning 的目标是直接学习最优动作价值函数 Q ∗ ( s , a ) Q^*(s, a) Q∗(s,a)。它采用时序差分 (Temporal Difference, TD) 学习 的方法,利用当前对 Q ∗ Q^* Q∗ 的估计值来更新之前的估计值。它是一种离策略 (Off-Policy) 算法,意味着它学习的策略 ( π ∗ \pi^* π∗,对应于 Q ∗ Q^* Q∗) 与其在环境中探索时实际执行的策略(例如,ε-greedy 策略)可以不同。
4.2 Q 表格 (Q-Table)
在状态和动作空间都是离散且有限的情况下,Q-Learning 使用一个表格(称为 Q-Table)来存储每个状态-动作对的 Q 值。表格的行代表状态,列代表动作。
状态 (State) | 动作 A | 动作 B | 动作 C | … |
---|---|---|---|---|
状态 1 | Q(1,A) | Q(1,B) | Q(1,C) | … |
状态 2 | Q(2,A) | Q(2,B) | Q(2,C) | … |
状态 3 | Q(3,A) | Q(3,B) | Q(3,C) | … |
… | … | … | … | … |
算法的目标就是通过与环境交互,不断更新和完善这个 Q 表格。
4.3 Q-Learning 更新规则
Q-Learning 的核心在于其更新规则。当智能体在状态 S t S_t St 采取动作 A t A_t At,得到奖励 R t + 1 R_{t+1} Rt+1 并转移到新状态 S t + 1 S_{t+1} St+1 后,它会按照以下公式更新 Q 表中对应 ( S t , A t ) (S_t, A_t) (St,At) 的 Q 值:
Q ( S t , A t ) ← Q ( S t , A t ) + α [ R t + 1 + γ max a Q ( S t + 1 , a ) ⏟ TD 目标 (Target) − Q ( S t , A t ) ⏟ 当前估计 (Old Value) ] Q(S_t, A_t) \leftarrow Q(S_t, A_t) + \alpha [ \underbrace{R_{t+1} + \gamma \max_{a} Q(S_{t+1}, a)}_{\text{TD 目标 (Target)}} - \underbrace{Q(S_t, A_t)}_{\text{当前估计 (Old Value)}} ] Q(St,At)←Q(St,At)+α[TD 目标 (Target) Rt+1+γamaxQ(St+1,a)−当前估计 (Old Value) Q(St,At)]
让我们分解这个公式:
- Q ( S t , A t ) Q(S_t, A_t) Q(St,At):当前估计的在状态 S t S_t St 执行动作 A t A_t At 的 Q 值。
- α \alpha α (Alpha):学习率 (Learning Rate),介于 0 和 1 之间,控制每次更新的步长。较小的学习率使学习更稳定但可能较慢,较大的学习率则相反。
- R t + 1 R_{t+1} Rt+1:执行动作 A t A_t At 后获得的即时奖励。
- γ \gamma γ (Gamma):折扣因子,同 MDP 中的定义,平衡短期和长期奖励。
- max a Q ( S t + 1 , a ) \max_{a} Q(S_{t+1}, a) amaxQ(St+1,a):在下一个状态 S t + 1 S_{t+1} St+1 中,所有可能动作 a a a 对应的 Q 值的最大值。这代表了我们对从 S t + 1 S_{t+1} St+1 开始能获得的最优未来价值的估计。
- R t + 1 + γ max a Q ( S t + 1 , a ) R_{t+1} + \gamma \max_{a} Q(S_{t+1}, a) Rt+1+γamaxQ(St+1,a):这部分被称为 TD 目标 (Temporal Difference Target),是基于当前经验( R t + 1 R_{t+1} Rt+1)和下一个状态的最佳 Q 值估计( max a Q ( S t + 1 , a ) \max_{a} Q(S_{t+1}, a) amaxQ(St+1,a))计算出的、对 Q ( S t , A t ) Q(S_t, A_t) Q(St,At) 的更准确的估计。
- [ TD 目标 − 当前估计 ] [ \text{TD 目标} - \text{当前估计} ] [TD 目标−当前估计]:这部分是 TD 误差 (Temporal Difference Error),表示新的估计值(TD 目标)与旧的估计值之间的差异。Q-Learning 通过这个误差来调整 Q 值。
通过反复迭代这个更新过程,Q 表中的值会逐渐收敛到最优动作价值函数 Q ∗ Q^* Q∗。
4.4 探索与利用 (Exploration vs. Exploitation)
在学习过程中,智能体面临一个经典的困境:
- 利用 (Exploitation):选择当前看来 Q 值最高的动作,以获得已知的最大奖励。
- 探索 (Exploration):尝试一些当前看来不是最优的动作,以发现可能存在的、具有更高长期回报的未知路径。
如果只利用,智能体可能陷入局部最优,错过更好的策略。如果只探索,智能体无法稳定地获得高奖励。因此,需要在两者之间取得平衡。
ε-greedy 策略 是最常用的方法之一:
- 以 1 − ϵ 1-\epsilon 1−ϵ 的概率选择当前状态下 Q 值最大的动作(利用)。
- 以
ϵ
\epsilon
ϵ 的概率随机选择一个动作(探索)。
通常,在训练开始时设置较高的 ϵ \epsilon ϵ 值以鼓励探索,随着训练的进行逐渐减小 ϵ \epsilon ϵ 值,让智能体更多地利用已学到的知识。
五、深度 Q 网络 (DQN):当深度学习遇上强化学习
经典的 Q-Learning 使用 Q 表格来存储 Q 值,这在状态和动作空间都很小的情况下是可行的。但如果状态空间非常大(例如,处理像素级的游戏画面,状态数量是天文数字)甚至是连续的,Q 表格就会变得不可行(维度诅咒)。
5.1 Q-Learning 的局限性
- 内存需求:对于大状态空间,Q 表需要巨大的内存。
- 泛化能力:Q 表无法泛化到未见过的状态。每个状态的 Q 值都需要独立学习。
- 连续空间:无法直接处理连续状态或动作空间。
5.2 DQN 的核心思想
为了解决这些问题,研究者们将深度学习与 Q-Learning 结合起来,提出了深度 Q 网络 (Deep Q-Network, DQN)。DQN 的核心思想是用一个深度神经网络 (Deep Neural Network) 来近似最优动作价值函数 Q ∗ ( s , a ) Q^*(s, a) Q∗(s,a)。
这个网络通常接收状态 s s s 作为输入,输出该状态下所有可能动作 a a a 对应的 Q 值。即: Q ( s , a ; θ ) ≈ Q ∗ ( s , a ) Q(s, a; \theta) \approx Q^*(s, a) Q(s,a;θ)≈Q∗(s,a) 其中 θ \theta θ 代表神经网络的参数(权重和偏置)。
这样,我们不再需要存储巨大的 Q 表,而是学习一个能够泛化的函数近似器。对于相似的状态,网络可以输出相似的 Q 值,即使这些状态从未在训练中精确出现过。
5.3 关键技术:经验回放与目标网络
直接用神经网络替代 Q 表进行 Q-Learning 更新可能会导致训练不稳定甚至发散。DQN 引入了两个关键技术来解决这个问题:
(1) 经验回放 (Experience Replay)
智能体与环境交互产生的经验(一个包含状态、动作、奖励、下一状态的元组: ( s t , a t , r t + 1 , s t + 1 ) (s_t, a_t, r_{t+1}, s_{t+1}) (st,at,rt+1,st+1))被存储在一个固定大小的回放缓冲区 (Replay Buffer) 中。在训练神经网络时,不是使用刚刚产生的单个经验,而是从缓冲区中随机采样一个小批量 (mini-batch) 的经验来进行更新。
好处:
- 打破数据相关性:连续的经验之间通常高度相关,随机采样打破了这种相关性,使得样本更接近独立同分布,这有助于神经网络的稳定训练。
- 提高数据利用率:一个经验可以被多次用于训练,提高了数据的利用效率。
(2) 目标网络 (Target Network)
在计算 TD 目标时,如果使用同一个正在更新的网络来估计 max a ′ Q ( S t + 1 , a ′ ) \max_{a'} Q(S_{t+1}, a') a′maxQ(St+1,a′),会导致目标值随着网络参数 θ \theta θ 的更新而不断快速变化,使得训练目标不稳定。
DQN 使用一个独立的、结构相同但参数不同的网络,称为目标网络 (Target Network),其参数 θ − \theta^- θ−。目标网络用于计算 TD 目标中的 max a ′ Q ( S t + 1 , a ′ ; θ − ) \max_{a'} Q(S_{t+1}, a'; \theta^-) a′maxQ(St+1,a′;θ−)。主网络(参数为 θ \theta θ)则负责选择动作并被更新。目标网络的参数 θ − \theta^- θ− 不会像主网络那样在每一步都更新,而是定期从主网络复制参数(例如,每隔几千步或几百步才同步一次 θ − ← θ \theta^- \leftarrow \theta θ−←θ)。
好处:
- 稳定训练目标:目标 Q 值在一段时间内保持固定,降低了 TD 误差的方差,使得训练过程更加稳定。
DQN 的损失函数通常是 TD 误差的均方误差 (MSE):
L
(
θ
)
=
E
(
s
,
a
,
r
,
s
′
)
∼
U
(
D
)
[
(
r
+
γ
max
a
′
Q
(
s
′
,
a
′
;
θ
−
)
⏟
TD Target (using target network)
−
Q
(
s
,
a
;
θ
)
⏟
Current Q (using main network)
)
2
]
L(\theta) = E_{(s, a, r, s') \sim U(D)} [ ( \underbrace{r + \gamma \max_{a'} Q(s', a'; \theta^-)}_{\text{TD Target (using target network)}} - \underbrace{Q(s, a; \theta)}_{\text{Current Q (using main network)}} )^2 ]
L(θ)=E(s,a,r,s′)∼U(D)[(TD Target (using target network)
r+γa′maxQ(s′,a′;θ−)−Current Q (using main network)
Q(s,a;θ))2]
其中
U
(
D
)
U(D)
U(D) 表示从经验回放缓冲区 D 中均匀采样。然后通过梯度下降等优化算法来最小化这个损失函数,更新主网络的参数
θ
\theta
θ。
DQN 的提出是深度强化学习领域的一个里程碑,它成功地让智能体直接从高维输入(如像素)中学习控制策略,并在 Atari 游戏上达到了超越人类水平的表现。
六、实战演练:使用 OpenAI Gym 训练 CartPole 智能体
理论讲了这么多,让我们动手实践一下!我们将使用 OpenAI Gym 这个流行的强化学习环境库,来训练一个智能体玩 CartPole(车杆)游戏。
6.1 OpenAI Gym 简介
OpenAI Gym 是一个用于开发和比较强化学习算法的工具包。它提供了各种模拟环境(从简单的 CartPole 到复杂的机器人控制和 Atari 游戏),并提供了一套标准的 API,使得研究者可以方便地测试和复现算法。
安装 Gym(通常需要 Python 环境):
pip install gym
# 可能需要安装特定环境的依赖,例如经典控制环境:
pip install gym[classic_control]
6.2 CartPole 环境介绍
CartPole-v1 是一个经典的控制问题环境。任务是控制一个小车(Cart)左右移动,使得立在小车上的杆子(Pole)保持竖直不倒。
- 状态 (State):一个包含 4 个连续值的向量:
- 小车位置 (Cart Position)
- 小车速度 (Cart Velocity)
- 杆子角度 (Pole Angle)
- 杆子角速度 (Pole Angular Velocity)
- 动作 (Action):离散动作空间,包含 2 个动作:
0. 向左推动小车- 向右推动小车
- 奖励 (Reward):在每个时间步,只要杆子没有倒下(角度在一定范围内)且小车没有移出边界,就会获得 +1 的奖励。
- 结束条件 (Done):当杆子倾斜角度过大、小车移出屏幕边界,或者达到最大步数(通常是 500 步)时,一个回合 (Episode) 结束。
目标是让智能体学会一种策略,使得每个回合能够坚持尽可能长的时间(获得尽可能高的累积奖励)。
6.3 使用 Q-Learning 实现 CartPole (简化版)
由于 CartPole 的状态是连续的,直接使用 Q 表格是不可行的。为了演示 Q-Learning,我们这里采用一种简化方法:状态离散化 (State Discretization)。我们将连续的状态空间划分为有限个离散的“格子”或“箱子 (bins)”,每个格子代表一个离散状态。
注意:这种方法对于低维状态空间尚可,但对于高维问题效果会急剧下降。对于 CartPole,更标准的做法是使用 DQN 或其他基于函数近似的方法。这里仅为教学目的演示 Q-Learning。
import gym
import numpy as np
import math
import matplotlib.pyplot as plt
# 1. 环境设置与状态离散化
env = gym.make('CartPole-v1')
# 定义状态空间边界 (根据经验或环境文档设定)
# [小车位置, 小车速度, 杆子角度, 杆子角速度]
pos_space = np.linspace(-2.4, 2.4, 10)
vel_space = np.linspace(-4, 4, 10)
ang_space = np.linspace(-0.2095, 0.2095, 10) # 约 -12 到 12 度
ang_vel_space = np.linspace(-4, 4, 10)
# Q 表初始化 (状态数量 = 10*10*10*10, 动作数量 = 2)
q_table = np.zeros((len(pos_space)+1, len(vel_space)+1, len(ang_space)+1, len(ang_vel_space)+1, env.action_space.n))
# 学习参数
learning_rate = 0.1 # 学习率 alpha
discount_factor = 0.99 # 折扣因子 gamma
epsilon = 1.0 # 初始探索率
epsilon_decay_rate = 0.001 # 探索率衰减
rng = np.random.default_rng()
# 训练回合数
num_episodes = 20000
rewards_per_episode = np.zeros(num_episodes)
# 状态离散化函数
def discretize_state(state):
pos, vel, ang, ang_vel = state
pos_idx = np.digitize(pos, pos_space)
vel_idx = np.digitize(vel, vel_space)
ang_idx = np.digitize(ang, ang_space)
ang_vel_idx = np.digitize(ang_vel, ang_vel_space)
return (pos_idx, vel_idx, ang_idx, ang_vel_idx)
# 2. Q-Learning 算法实现
for episode in range(num_episodes):
state = env.reset()
if isinstance(state, tuple): # 处理新版 gym 返回值
state = state[0]
state_idx = discretize_state(state)
terminated = False
truncated = False
while not terminated and not truncated:
# ε-greedy 策略选择动作
if rng.random() < epsilon:
action = env.action_space.sample() # 探索:随机选择动作
else:
action = np.argmax(q_table[state_idx]) # 利用:选择 Q 值最大的动作
# 执行动作,观察新状态和奖励
new_state, reward, terminated, truncated, _ = env.step(action)
new_state_idx = discretize_state(new_state)
# Q-Learning 更新规则
q_table[state_idx + (action,)] = q_table[state_idx + (action,)] + learning_rate * (
reward + discount_factor * np.max(q_table[new_state_idx]) - q_table[state_idx + (action,)]
)
# 状态转移
state_idx = new_state_idx
rewards_per_episode[episode] += reward
# 探索率衰减 (线性衰减,可以有其他方式)
epsilon = max(epsilon - epsilon_decay_rate, 0.01) # 保证至少有 1% 的探索
# 打印训练进度
if (episode + 1) % 1000 == 0:
print(f"Episode {episode + 1}/{num_episodes}. Epsilon: {epsilon:.3f}. Avg Reward (last 100): {np.mean(rewards_per_episode[episode-99:episode+1]):.2f}")
env.close()
# 3. 训练与结果展示 (简单绘图)
# 计算滑动平均奖励
smoothed_rewards = [np.mean(rewards_per_episode[max(0, i-99):i+1]) for i in range(num_episodes)]
plt.figure(figsize=(12, 6))
plt.plot(rewards_per_episode, label='Reward per Episode', alpha=0.6)
plt.plot(smoothed_rewards, label='Smoothed Reward (100 episodes average)', color='red')
plt.xlabel('Episode')
plt.ylabel('Total Reward')
plt.title('CartPole Q-Learning Training Progress (Discretized State)')
plt.legend()
plt.grid(True)
plt.show()
print("Training finished.")
# 你可以保存 q_table,然后加载它来测试训练好的智能体的性能。
代码关键点注释:
- 状态离散化:
discretize_state
函数将连续的状态值映射到离散的索引。np.digitize
是实现这一功能的便捷函数。 - Q 表: 使用 NumPy 创建一个多维数组来存储 Q 值,维度对应离散化后的状态维度加上动作维度。
- ε-greedy: 在
while
循环开始时,根据epsilon
决定是随机探索还是利用当前 Q 表选择最优动作。 - Q 值更新: 核心的 Q-Learning 更新公式在
q_table[state_idx + (action,)] = ...
这行实现。 - 探索率衰减:
epsilon
在每个回合结束后逐渐减小,使得智能体从探索逐渐转向利用。 - 结果可视化: 绘制每个回合的总奖励和滑动平均奖励,可以直观地看到智能体学习的进步过程。
运行这段代码,你会看到智能体在 CartPole 环境中通过 Q-Learning 逐步学习,其每个回合能获得的奖励(坚持的时间)会逐渐增加。
6.4 (选讲) 使用 DQN 解决 CartPole
正如前面提到的,对于 CartPole 这种状态连续(即使维度不高)的问题,使用 DQN 或其变种通常是更有效、更标准的做法。DQN 使用神经网络来近似 Q 函数,无需进行状态离散化,能够更好地处理连续状态并具有泛化能力。
实现 DQN 相对复杂,通常会借助深度学习框架(如 TensorFlow/Keras 或 PyTorch)以及强化学习库(如 Stable Baselines3, TF-Agents, Ray RLlib)。这些库封装了 DQN 的实现细节(包括神经网络结构、经验回放、目标网络更新等),让使用者可以更专注于环境设计和超参数调整。如果你对 DQN 感兴趣,可以查阅这些库的文档和示例代码进行深入学习。
七、总结
恭喜你完成了强化学习入门的学习!让我们回顾一下今天的主要内容:
- 强化学习基础:理解了智能体 (Agent) 通过与环境 (Environment) 交互,根据状态 (State) 选择动作 (Action),并获得奖励 (Reward) 来学习最优策略的基本框架。目标是最大化长期累积奖励。
- 马尔可夫决策过程 (MDP):学习了 MDP 作为强化学习问题的数学模型,理解了其核心要素(状态 S, 动作 A, 转移概率 P, 奖励 R, 折扣因子 γ)和马尔可夫性质。
- 价值与策略:区分了策略函数(决定行为)和价值函数(评估状态或动作的好坏),理解了状态价值函数 V(s) 和动作价值函数 Q(s, a) 的含义,以及贝尔曼方程的核心思想。
- Q-Learning:深入解析了经典的无模型、离策略算法 Q-Learning。掌握了其核心思想(基于 TD 学习直接估计最优 Q 函数)、Q 表的使用、关键的更新规则以及探索与利用(ε-greedy)策略。
- 深度 Q 网络 (DQN):了解了 Q-Learning 在处理大状态空间或连续状态时的局限性,并学习了 DQN 如何使用深度神经网络来近似 Q 函数,以及经验回放和目标网络这两个关键技术来稳定训练。
- 实战演练:通过 OpenAI Gym 的 CartPole 环境,实践了使用 Q-Learning(配合状态离散化)训练智能体的过程,并了解了 DQN 是解决此类问题的更优方法。
强化学习是一个充满活力且快速发展的领域。今天我们学习的内容是入门的基础,后续还有许多更高级的算法(如 Policy Gradient, Actor-Critic, PPO 等)和更复杂的应用场景等待探索。希望本文能为你打开强化学习的大门,激发你进一步学习的兴趣!
在下一篇文章中,我们将回到机器学习流程中的一个关键环节:模型评估与选择。我们将学习如何科学地衡量模型的性能,并选择最适合我们任务的模型。敬请期待!