核心问题:机器如何“学习”最优决策?
机器如何在一个复杂的、不确定的世界中,通过与环境的互动和试错,自动学出一套最优的决策序列,以实现其长期目标?
这不仅是技术问题,更触及了经济学中理性决策、动态优化和博弈论的核心。
经济学中的“智能体”
经济学对象: 消费者、公司和政府等智能体(agents)通过选择最大化效用或利润。
强化学习框架: 用可计算方式模拟和优化智能体在动态环境中的决策过程。
关键场景: 当信息不完全且环境持续变化时,行动会同时影响当前回报和未来状态。
一个商业案例:动态定价
想象一下,你是一个电商平台的定价算法(智能体)。
- 状态 (State): 当前库存、竞争对手价格、用户流量、时间…
- 动作 (Action): 提高价格、降低价格、保持不变。
- 奖励 (Reward): 当天的总销售额。
- 目标: 找到一个定价策略 (Policy),最大化未来30天的总销售额。
你没有一个“正确答案”的数据集,你只能通过不断尝试和观察结果来学习。这就是强化学习的主场。
本章学习目标:理解强化学习的经济学直觉
完成本讲后,你能够:
- 把序贯经济决策写成状态、动作、奖励、转移与折扣因子。
- 手算一次 Bellman 期望、Q-learning 与终止状态更新。
- 区分 on-policy Sarsa 与 off-policy Q-learning 的更新目标。
- 逐项计算标准 DQN 与 Double DQN target,并解释目标网络的作用。
- 说明教学环境的假设,以及把 RL 迁移到中国金融数据时的离线评估风险。
开始前回顾
- 若两期奖励为 2 和 4、γ=0.5,回报是多少?
- 终止转移后是否还应 bootstrap 下一状态价值?
- 行为策略与目标策略不同,是 on-policy 还是 off-policy?
先独立写下三个答案,再揭示。
揭示与补救
\(2+0.5\times4=4\);不应,terminal mask 为 0;off-policy。若答错,分别回到折扣回报、终止状态更新或 on/off-policy 定义。
90 分钟学习安排与拓展学习顺序
- 0–15 分钟:MDP 五元组、回报与折扣;完成先修检查。
- 15–38 分钟:状态价值、动作价值与 Bellman 期望手算。
- 38–62 分钟:从期望到 max,比较 Sarsa 与 Q-learning,并手算一次更新。
- 62–80 分钟:DQN、目标网络、经验回放的作用与限制。
- 80–90 分钟:本地离线 RL 支持度检查和本讲回顾。
学习顺序
MDP → Bellman 手算 → Q-learning → DQN/DDQN target → 练习 → 离线 RL 案例回顾。
课后选学:悬崖行走大图、Dueling DQN 与应用展望。
机器学习的三大家族
机器学习根据学习方式和数据形式,通常分为三大范式。
监督学习 (Supervised Learning)
学习一个从输入到输出的映射函数,就像一个老师给出标准答案。
- 核心任务: 预测或分类。
- 数据形式: 有标签数据
(X, y),其中y是正确答案。
- 经济学类比:
- 回归:根据历史数据(GDP、利率、通胀)预测明年的GDP。
- 分类:根据客户信息判断其是否会违约。
- 局限: 依赖大量高质量的标注数据,无法做出序贯决策。
无监督学习 (Unsupervised Learning)
在没有标准答案的情况下,自行发现数据中隐藏的结构或模式。
- 核心任务: 发现数据结构。
- 数据形式: 无标签数据
X。
- 经济学类比:
- 聚类:将客户群体细分为不同的市场区隔 (market segments)。
- 降维:从数百个宏观经济指标中提取少数几个关键因子。
- 局限: 只能描述数据,不能指导决策。
强化学习 (Reinforcement Learning)
智能体通过与环境的互动,在“试错”中学习如何做出一系列决策以最大化累积奖励。
- 核心任务: 学习最优的决策序列 (sequence)。
- 数据形式: 与环境的交互数据 (状态, 动作, 奖励)。
- 经济学类比:
- 一家企业在多个季度中,持续调整广告、研发和定价策略,以最大化长期市场份额和利润。
强化学习的本质(一):没有“正确答案”
强化学习与监督学习最根本的区别在于:
强化学习的本质(二):反馈有延迟
强化学习的本质(三):探索 vs. 利用
核心框架:马尔可夫决策过程 (MDP)
强化学习的问题通常被数学化地建模为 马尔可夫决策过程 (Markov Decision Process, MDP)。
这是一个描述决策者(智能体)与环境进行序贯交互的数学框架。理解了MDP,就理解了整个强化学习的基石。
它由五个核心要素构成:(S, A, P, R, γ)。
MDP的主角:智能体 (Agent) 与环境 (Environment)
MDP要素 1: 状态 (State, S)
状态 (State, \(s \in S\)) 描述环境在某一时刻的情况。
- 定义:描述世界当前状况的一组信息,这组信息足以做出未来的决策。
- 关键特性 (马尔可夫性):未来只与当前状态有关,与过去如何到达当前状态无关。
\[
\large{ P(S_{t+1}|S_t, A_t) = P(S_{t+1}|S_1, A_1, ..., S_t, A_t) }
\]
- 经济学案例:
- 一个公司的状态可以是:
(现金流, 库存水平, 市场份额)。
- 一个经济体的状态可以是:
(GDP增速, 通胀率, 失业率)。
MDP要素 2: 动作 (Action, A)
动作 (Action, \(a \in A\)) 是智能体可以执行的操作。
- 定义:智能体在每个状态下可以选择的行为集合。
- 类型:可以是离散的(如:买入、卖出、持有),也可以是连续的(如:设定价格为$10.53)。
- 经济学案例:
- 一家公司的动作可以是:
(设定产品价格, 决定广告预算)。
- 中央银行的动作可以是:
(加息25个基点, 降息, 维持不变)。
MDP要素 3: 奖励 (Reward, R)
奖励 (Reward, \(R_t\)) 是环境对智能体在状态 \(S_t\) 下采取动作 \(A_t\) 后给出的即时反馈信号。
- 定义:一个标量数值,衡量了智能体所做动作的“好坏”。奖励假设 (Reward Hypothesis) 指出,所有目标都可以被描述为最大化期望累积奖励。
- RL的目标:最大化的是累积奖励,而非瞬时奖励。
- 经济学案例:
- 对于交易算法,奖励是每日的投资组合回报率。
- 对于公司,奖励是当季的利润。
MDP要素 4: 状态转移概率 (Transition Probability, P)
状态转移概率 (State Transition Probability) 描述了环境的动态性 (dynamics)。
定义:在状态 \(s\) 采取动作 \(a\) 后,转移到下一个状态 \(s'\) 的概率。
数学表示:
\[
\begin{aligned}
p(s' \mid s,a)
&= P\!\left(S_{t+1}=s' \mid S_t=s,\,A_t=a\right)
\end{aligned}
\]
经济学案例:
MDP要素 5: 折扣因子 (\(\gamma\))
汇总:MDP五元组
一个完整的马尔可夫决策过程可以由一个五元组定义: \((\mathcal{S}, \mathcal{A}, P, R, \gamma)\)
交互循环:智能体与环境的“舞蹈”
强化学习的核心过程就是一个不断循环的交互。
交互循环:一步详解
- 观察: 在
t 时刻,智能体观察到环境的状态 \(S_t\)。
- (例:交易算法观察到当前股价为$100,交易量为50万手)
- 决策: 智能体根据其策略 \(\pi\) 选择一个动作 \(A_t\)。
- 执行: 环境接收动作 \(A_t\)。
- 演变: 环境根据其内部动态演变到新状态 \(S_{t+1}\),并给出一个奖励 \(R_{t+1}\)。
- (例:市场成交,股价变为$101,当日浮盈为+$100)
- 这个循环不断重复。
智能体的大脑:策略函数 (Policy Function, \(\pi\))
策略 (Policy, \(\pi\)) 是智能体的行为准则,是其“大脑”,定义了从状态到动作的映射。
- 定义:一个从状态到动作的映射。它告诉智能体在每个状态下应该采取什么动作。
- 类型:
- 确定性策略:\(a = \pi(s)\),每个状态对应一个唯一动作。
- 随机性策略:\(\pi(a|s) = P(A_t = a | S_t = s)\),在状态 \(s\) 下采取动作 \(a\) 的概率。
- RL的目标:找到一个最优策略 \(\pi^*\),以最大化长期回报。
随机性策略的经济学直觉
为什么需要随机性策略?
应对不确定性与对手
在某些情况下,最优的行为本身就是随机的。这在博弈论中很常见,例如“剪刀石头布”的最优策略就是随机出拳,让对手无法预测。
目标函数:最大化累积回报
智能体的目标不是最大化眼前的瞬时奖励 \(R_{t+1}\),而是最大化从当前时刻开始的未来累积回报 (Return)。
回报 \(G_t\) 的定义为:
\[
\large{ G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots = \sum_{k=0}^{\infty} \gamma^k R_{t+k+1} }
\]
核心概念:折扣因子 (Discount Factor, \(\gamma\))
公式中的 \(\gamma\) (gamma) 是折扣因子,\(0 \le \gamma \le 1\)。
- 经济学类比:
- 为什么需要折扣?
- 时间价值:今天的1美元比明天的1美元更有价值。
- 任务时间偏好:\(\gamma\) 规定近期与远期奖励的相对权重;模型不确定性应由状态、转移或稳健性分析另行表达。
- 数学条件:当奖励有界且 \(0\le\gamma<1\) 时,无限折扣回报绝对收敛;\(\gamma=1\) 需要终止性等额外条件。
折扣因子的作用:一个例子
假设奖励序列是 [+10, +2, +5, +8, ...]
\(\gamma = 0\) (极度短视)
\(G_t = 10 + 0 \cdot 2 + 0 \cdot 5 + \dots = 10\) 只关心立即奖励。
\(\gamma = 0.9\) (有远见)
\(G_t = 10 + 0.9 \cdot 2 + 0.9^2 \cdot 5 + \dots\) \(G_t = 10 + 1.8 + 4.05 + \dots\) 会权衡短期和长期利益。
\(\gamma\) 的选择是一个关键的建模决策,它定义了智能体的“远见”程度。
衡量策略好坏的标尺:价值函数 (Value Function)
我们如何判断一个状态是“好”还是“坏”?或者一个动作是“好”还是“坏”?
这就是价值函数的作用。它是对未来回报的期望 (Expectation)。
有两种核心的价值函数:
- 状态价值函数 (State-Value Function, \(V_\pi(s)\))
- 动作价值函数 (Action-Value Function, \(Q_\pi(s, a)\))
状态价值函数 V(s): 当前处境有多好?
状态价值函数 \(V_\pi(s)\) 回答了这个问题:“如果我从状态 \(s\) 开始,并始终遵循策略 \(\pi\),我能期望获得多少未来的总回报?”
动作价值函数 Q(s, a): 这个选择有多好?
起点: 当前位于状态 \(s\),并先选择动作 \(a\)。
后续规则: 之后继续遵循策略 \(\pi\)。
回答的问题: 动作价值 \(Q_\pi(s,a)\) 是此时能够期望获得的未来总回报。
定义:
\[
\large{ Q_\pi(s, a) = E_\pi[G_t | S_t = s, A_t = a] }
\]
直观理解:\(Q_\pi(s, a)\) 是对在特定状态下采取特定动作的质量 (Quality) 的评估。
经济学案例:在当前库存水平(状态 \(s\))下,如果公司选择降价10%(动作 \(a\)),那么对公司未来总利润(回报)的期望值是多少。
V函数与Q函数的关系:一个重要的恒等式
状态的价值,等于在该状态下,遵循策略 \(\pi\) 所可能采取的所有动作的价值的期望。
\[
\large{ V_\pi(s) = \sum_{a \in A} \pi(a|s) Q_\pi(s, a) }
\]
- \(\pi(a|s)\) 是在状态 \(s\) 选择动作 \(a\) 的概率。
- \(Q_\pi(s, a)\) 是选择了动作 \(a\) 之后的价值。
这个关系非常直观,并且在后续的算法中至关重要。
动态规划的核心:贝尔曼期望方程
贝尔曼方程(Bellman Equation)是强化学习中最核心的方程,它将一个状态的价值与其后继状态的价值联系起来,构建了一个递归关系。
对于状态价值函数 \(V_\pi(s)\):
\[
\large{ V_\pi(s) = \sum_{a \in A} \pi(a|s) \left( E[R_{t+1}|s,a] + \gamma \sum_{s' \in S} p(s'|s,a) V_\pi(s') \right) }
\]
这个方程说的是:当前状态的价值 = 所有可能动作的(即时奖励 + 折扣后的下一状态期望价值)的期望。
贝尔曼期望方程的直观分解 (V函数)
让我们把这个方程拆开来看:
\[ \large{V_\pi(s) = \sum_{a \in A} \pi(a|s) \Big( \underbrace{R(s,a)}_{\text{立即能得到什么}} + \gamma \underbrace{\sum_{s' \in S} p(s'|s,a) V_\pi(s')}_{\text{未来能期望得到什么}} \Big)} \]
- 外层期望 \(\sum_{a \in A} \pi(a|s) \dots\):因为我们的策略可能是随机的,所以要对所有可能的动作求期望。
- 即时奖励 \(R(s,a)\):采取动作 \(a\) 后立即获得的奖励。
- 内层期望 \(\sum_{s' \in S} p(s'|s,a) \dots\):因为环境的反应(状态转移)可能是随机的,所以要对所有可能的下一状态求期望。
- \(V_\pi(s')\):这就是递归的魔力所在。下一状态的价值,又可以用同样的方式展开。
贝尔曼期望方程 (Q函数)
对于动作价值函数 \(Q_\pi(s, a)\),贝尔曼方程形式略有不同:
\[
\large{ Q_\pi(s, a) = R(s,a) + \gamma \sum_{s' \in S} p(s'|s,a) \sum_{a' \in A} \pi(a'|s') Q_\pi(s', a') }
\]
由于 \(\sum_{a' \in A} \pi(a'|s') Q_\pi(s', a') = V_\pi(s')\), 我们可以简化为:
\[
\large{ Q_\pi(s, a) = R(s,a) + \gamma \sum_{s' \in S} p(s'|s,a) V_\pi(s') }
\]
这个方程说的是:在状态s采取动作a的价值 = 即时奖励 + 折扣后的期望下一状态价值。
Bellman 手算:先算期望
先作答
计算两个 \(Q_\pi(s_0,a)\) 与 \(V_\pi(s_0)\)。若改求最优价值,应把哪一步换成 max?
Bellman 手算:揭示期望与 max 的区别
\[
Q_\pi(s_0,\text{持有})=1+0.9\times4=4.6,
\qquad Q_\pi(s_0,\text{卖出})=3+0.9\times0=3.0.
\]
\[
V_\pi(s_0)=0.5\times4.6+0.5\times3.0=3.8,
\qquad \max_a Q_\pi(s_0,a)=4.6.
\]
\[
Q^*(s_0,\text{持有})=4.6,\quad Q^*(s_0,\text{卖出})=3.0,\quad V^*(s_0)=4.6.
\]
求解RL问题:找到最优策略 \(\pi^*\)
强化学习的最终目标是找到一个最优策略 \(\pi^*\),使得在任何初始状态下,它所能获得的期望回报都大于或等于其他任何策略。
\[
\large{ \pi^* = \arg\max_{\pi} V_\pi(s) \quad \text{for all } s \in S }
\]
对应的最优价值函数记为 \(V^*(s)\) 和 \(Q^*(s, a)\)。
贝尔曼最优方程
对于最优策略,贝尔曼方程有一个特殊的形式,即贝尔曼最优方程。它不再是求期望,而是取最大值 (max)。
对于 \(V^*(s)\):
\[
\large{ V^*(s) = \max_{a \in A} \left( R(s,a) + \gamma \sum_{s' \in S} p(s'|s,a) V^*(s') \right) }
\]
对于 \(Q^*(s, a)\):
\[
\large{ Q^*(s, a) = R(s,a) + \gamma \sum_{s' \in S} p(s'|s,a) \max_{a' \in A} Q^*(s', a') }
\]
这里的 \(\max\) 体现了“最优性”:智能体总是会选择那个能导向最优未来的动作。
如何求解?广义策略迭代 (GPI)
知道了目标(贝尔曼最优方程),但如何找到解?大多数RL算法都遵循一个通用的模式,叫做广义策略迭代 (Generalized Policy Iteration, GPI)。
这是一个“左右手互搏”的过程,包含两个相互交织的步骤:
策略评估:我的当前策略到底有多好?
假设我们有一个固定的策略 \(\pi\)(比如,一个交易算法的现有规则),我们想知道它的价值。
任务:计算 \(V_\pi(s)\)。
方法:利用贝尔曼期望方程,通过迭代来求解。
\[
\large{ V_{k+1}(s) = \sum_{a \in A} \pi(a|s) \left( R(s,a) + \gamma \sum_{s' \in S} p(s'|s,a) V_k(s') \right) }
\]
我们从一个随机的 \(V_0\) 开始,不断用旧的价值函数计算新的价值函数,直到 \(V_k\) 收敛。这个过程也叫 iterative policy evaluation。
策略改进:我能做得更好吗?
一旦我们知道了当前策略 \(\pi\) 的价值函数 \(V_\pi\),我们就可以尝试改进它。
方法:对于每个状态 \(s\),我们不再遵循 \(\pi\),而是采取“贪心”策略,选择那个能带来最大Q值的动作:
\[
\large{ \pi'(s) = \arg\max_{a \in A} Q_\pi(s,a) }
\]
\[
\large{ = \arg\max_{a \in A} \left( R(s,a) + \gamma \sum_{s' \in S} p(s'|s,a) V_\pi(s') \right) }
\]
在有限 MDP、精确策略评估且动作价值可比较的条件下,可以证明新策略 \(\pi'\) 不劣于旧策略 \(\pi\)。
这就是策略改进定理;离线金融数据若缺少动作支持,则不能直接套用这一保证。
算法分类:是否需要环境模型?
解决GPI这个循环的算法,可以分为两大类:
基于模型 (Model-Based)
算法学习和/或使用显式的状态转移与奖励模型进行规划。模型可由环境给定,也可从数据学得,并且可以是近似的。
- 特殊情形: 已知精确模型的动态规划。
- 优点: 数据效率高。
- 限制: 学得模型可有错误,规划会放大模型偏差;现实中通常得不到精确转移模型。
无模型 (Model-Free)
算法不需要知道环境模型,它直接通过与环境交互产生的样本(经验)来学习。
- 典型算法: Q-Learning, Sarsa
- 优点: 更适用于现实世界的复杂问题。
无模型方法:探索世界的方式
算法分类:学习方式有何不同?
无模型算法内部,又可以根据学习方式分为两类:
同轨策略 (On-policy)
学习和决策使用同一个策略。它评估和改进的是当前正在执行的那个策略。
- 类比: 一个新手司机在开车时,边开边总结经验,以改进自己的驾驶技术。
- 典型算法: Sarsa。
离轨策略 (Off-policy)
学习和决策可以使用不同的策略。它可以在执行一个探索性策略的同时,评估和改进一个目标(贪心)策略。
- 类比: 一个专家在观看新手司机的录像,从中学习如何成为一个完美的司机。
- 典型算法: Q-Learning。
无模型方法一:蒙特卡洛 (Monte Carlo, MC)
MC方法是最直观的无模型学习方法。
- 核心思想:通过大量的完整回合 (episode) 模拟来估计价值函数。一个回合指从开始状态到终止状态的完整轨迹。
- 如何估计 \(Q_\pi(s,a)\)?
遵循策略 \(\pi\) 玩很多次回合。
对于所有访问过 \((s,a)\) 对的回合,记录其后续的实际回报 \(G_t\)。
将这些回报取平均值,作为 \(Q_\pi(s,a)\) 的估计。
\[
\large{ Q(s,a) \leftarrow \text{Average}(G_t \text{ for all visits to } (s,a)) }
\]
- 限制:
无模型方法二:时序差分 (Temporal-Difference, TD)
TD学习是强化学习中最核心、最创新的思想之一。它结合了MC和动态规划的优点。
- 核心思想:不需要等待回合结束,每走一步就进行学习和更新。它使用当前对下一状态价值的估计来更新当前状态的价值。
- 与MC对比:
- MC 更新目标是实际的最终回报 \(G_t\)。
- TD 更新目标是估计的未来回报 \(R_{t+1} + \gamma V(S_{t+1})\)。
- 这个过程叫做自举 (Bootstrapping),即用一个估计值来更新另一个估计值。
TD(0) 算法的更新规则
最简单的TD算法,称为TD(0),其更新规则为:
\[
\large{ V(S_t) \leftarrow V(S_t) + \alpha \underbrace{\left[ \overbrace{R_{t+1} + \gamma V(S_{t+1})}^{\text{TD Target}} - V(S_t) \right]}_{\text{TD Error}} }
\]
- \(\alpha\):学习率,决定了我们多大程度上接受新的估计。
- TD目标 (\(R_{t+1} + \gamma V(S_{t+1})\)):由一步真实奖励和当前下一状态估计组成的自举目标;它不保证比 \(V(S_t)\) 更准确。
- TD误差 (\(\delta_t\)):当前估计与这个自举目标之差,用于构造增量更新;有限样本中仍可能有偏差与噪声。
一个生动的例子:从宿舍到教室
假设你每天从宿舍走到教室,想预测总共需要多长时间。你最初的预测是18分钟。
- MC方法:等待回合最终回报,再更新起点状态价值。
- TD方法:每次观察后,用当前奖励和下一状态估计立即更新。
On-Policy TD 控制算法:Sarsa
Sarsa是一种On-policy的TD控制算法,它的目标是学习Q函数。
名字来源:其更新规则需要一个五元组 \((S_t, A_t, R_{t+1}, S_{t+1}, A_{t+1})\),即 S, A, R, S’, A’。
更新规则:
\[
\begin{aligned}
Q(S_t,A_t) &\leftarrow Q(S_t,A_t) \\
&\quad + \alpha\!\left[R_{t+1}+\gamma(1-d_t)Q(S_{t+1},\mathbf{A_{t+1}})-Q(S_t,A_t)\right]
\end{aligned}
\]
关键点:更新 \(Q(S_t, A_t)\) 时,使用的是在 \(S_{t+1}\) 实际将要采取的动作 \(A_{t+1}\) 对应的 Q 值;\(d_t=1\) 表示该转移终止,此时 \((1-d_t)\) 令自举项为 0。
探索与利用:\(\epsilon\)-greedy 策略
为在利用当前最优动作的同时保留探索机会,我们通常不直接使用纯贪心策略,而是使用 \(\epsilon\)-greedy 策略。
以 \(1-\epsilon\) 的概率,选择当前估计的最好动作:\(a^* = \arg\max_a Q(s,a)\)。 (利用)
以 \(\epsilon\) 的概率,从所有动作中随机选择一个。 (探索)
\(\epsilon\) 的值常随学习逐渐减小。
只有在相关状态可达、行为持续访问且衰减日程仍提供足够探索等条件下,才可谈“所有状态—动作对被充分探索”;
\(\epsilon\)-greedy 本身不提供无条件保证。
Off-Policy TD 控制算法:Q-Learning
Q-Learning是强化学习中最著名、应用最广泛的算法之一。它是一种Off-policy算法。
核心思想:它遵循一个行为策略(例如\(\epsilon\)-greedy)来探索,但同时学习的是另一个目标策略(纯贪心策略)的Q值。
更新规则:
\[
\begin{aligned}
Q(S_t,A_t) &\leftarrow Q(S_t,A_t) \\
&\quad + \alpha\!\left[R_{t+1}+\gamma(1-d_t)\max_{a'}Q(S_{t+1},a')-Q(S_t,A_t)\right]
\end{aligned}
\]
关键区别:非终止转移用 \(\max_{a'} Q(S_{t+1}, a')\),不依赖实际下一动作;终止转移有 \(d_t=1\),因此不从终止状态自举。
Sarsa vs. Q-Learning: 一个悬崖行走的比喻
想象一个智能体在悬崖边行走,目标是到达终点(G),起点是(S)。掉下悬崖(Cliff)会得到巨大负奖励。
Sarsa vs. Q-Learning: 解读
- Sarsa (On-policy):
- Q-Learning (Off-policy):
| 学习目标 |
学习当前行为策略的价值 |
学习最优策略的价值 |
| 更新方式 |
使用下一个实际采取的动作A’ |
使用下一个可能的最优动作 |
| 行为特点 |
更保守,会避开有危险的捷径 |
更激进,倾向于走最优但有风险的路径 |
Python实践:使用Q-Learning解决“冰湖”问题
为了让概念更具体,我们来看一个经典的RL问题:FrozenLake。
- 环境:一个 4x4 的网格,部分是冰面(F),部分是洞(H)。
- 目标:从起点(S)走到终点(G),不能掉进洞里。
- 状态:16个格子位置。
- 动作:上、下、左、右。
- 奖励:到达终点得1分,其他情况得0分。
- 挑战:冰面是滑的,执行“向右”的动作,可能有一定概率滑到别处。
这是一个典型的MDP。
Q-Learning代码框架:初始化
我们需要一个Q表来存储每个 (状态, 动作) 对的价值。初始时,我们对所有价值一无所知,所以全部设为0。
Code
# 导入依赖以支持本页的数据处理、建模或可视化。
import numpy as np
# 导入依赖以支持本页的数据处理、建模或可视化。
import pandas as pd
# 环境参数
n_states = 16 # 教学说明:4x4 grid。
n_actions = 4 # 教学说明:left, down, up, right。
# 初始化Q表,所有值都为0
q_table = np.zeros((n_states, n_actions))
# 执行 `print`,生成当前步骤需要的结果或可视化。
print('Initialized Q-Table (Shape: {}):'.format(q_table.shape)) # 展示当前步骤的结果。
# 使用pandas美化输出
q_df = pd.DataFrame(q_table, columns=['Left', 'Down', 'Up', 'Right'])
q_df.index.name = 'State'
# 执行 `print`,生成当前步骤需要的结果或可视化。
print(q_df.head()) # 展示当前步骤的结果。
Initialized Q-Table (Shape: (16, 4)):
Left Down Up Right
State
0 0.0 0.0 0.0 0.0
1 0.0 0.0 0.0 0.0
2 0.0 0.0 0.0 0.0
3 0.0 0.0 0.0 0.0
4 0.0 0.0 0.0 0.0
Q-Learning代码框架:主循环
算法的核心是一个循环,在其中智能体与环境交互并更新Q表。为了让代码可独立运行,我们模拟一个简单的、无滑动的冰湖环境。
Code
# 导入依赖以支持本页的数据处理、建模或可视化。
import numpy as np
# 导入依赖以支持本页的数据处理、建模或可视化。
import pandas as pd
# 教学说明:--- Mock Environment ---。
MAP = ["SFFF", "FHFH", "FFFH", "HFFG"]
# 动作效果: 0:左, 1:下, 2:上, 3:右
ACTION_EFFECTS = [-1, 4, -4, 1]
GOAL_STATE = 15
HOLES =[5,7,11,12]
# 定义函数 `mock_step`,复用当前教学案例的计算逻辑。
def mock_step(state, action): # 定义当前教学案例所需的函数。
new_state = state + ACTION_EFFECTS[action]
# 边界检查
if (action == 0 and state % 4 == 0) or \
(action == 3 and state % 4 == 3) or \
(action == 2 and state < 4) or \
(action == 1 and state > 11):
new_state = state # 撞墙则停在原地
if new_state in HOLES: # 落入冰洞时终止回合且不给奖励
return new_state, 0, True # 掉进洞,无奖励,回合结束
elif new_state == GOAL_STATE: # 到达目标时终止回合并给成功奖励
return new_state, 1, True # 到达终点,奖励为1,回合结束
else: # 按当前教学条件控制计算分支。
return new_state, 0, False # 普通移动
环境与学习器分开,便于检查转移逻辑,也使每个代码块聚焦于单一任务。
Code
# 固定局部随机数生成器,使探索轨迹与课堂输出可复现。
random_generator = np.random.default_rng(20250830)
q_table = np.zeros((16, 4)) # 从零初始化所有状态—动作价值
learning_rate = 0.2 # 用适中的步长传播稀疏终点奖励
gamma = 0.95 # 对更短的成功路径赋予更高价值
n_episodes = 12000 # 给稀疏奖励足够的可重复探索机会
successful_episodes = 0 # 记录训练期间实际到达终点的回合
# 前半程逐步退火探索率,后半程保留少量探索。
for episode_index in range(n_episodes): # 遍历当前教学对象以完成重复计算。
state = 0 # 每回合都从起点 S 开始
epsilon = max(0.05, 1 - episode_index / 6000) # 从充分探索平滑过渡到利用
for step_index in range(64): # 设置上限,避免撞墙策略形成无限回合
if random_generator.random() < epsilon: # 按退火后的概率探索
action = int(random_generator.integers(4)) # 在四个动作中均匀探索
else: # 按当前教学条件控制计算分支。
state_values = q_table[state] # 读取当前状态的动作价值
best_actions = np.flatnonzero(np.isclose(state_values, state_values.max())) # 找出并列最优动作
action = int(random_generator.choice(best_actions)) # 随机打破零值并列,避免固定偏向左移
new_state, reward, done = mock_step(state, action) # 执行一步环境转移
bootstrap_value = 0 if done else q_table[new_state].max() # 终止状态不再自举
temporal_difference = reward + gamma * bootstrap_value - q_table[state, action] # 计算 TD 误差
q_table[state, action] += learning_rate * temporal_difference # 把奖励向可达前序状态传播
state = new_state # 推进到下一状态
if done: # 按当前教学条件控制计算分支。
successful_episodes += reward # 只把到达目标计为成功
break # 洞或目标都会结束当前回合
Q-Learning 结果:贪心路径动作价值
只展示贪心路径上的可达状态;完整 16 状态 Q 表仍保存在 q_df_final 中。
Code
# 教学说明:--- Print Results ---。
print("Q-values on the greedy path:") # 明确展示的是完整 Q 表的可达路径子集
q_df_final = pd.DataFrame(q_table, columns=['Left', 'Down', 'Up', 'Right'])
q_df_final.index.name = 'State'
# 执行 `print`,生成当前步骤需要的结果或可视化。
print(q_df_final.loc[[0, 4, 8, 9, 13, 14, 15]].round(3)) # 展示与后续策略确认直接相关的状态
Q-values on the greedy path:
Left Down Up Right
State
0 0.735 0.774 0.735 0.774
4 0.774 0.815 0.735 0.000
8 0.815 0.000 0.774 0.857
9 0.815 0.902 0.000 0.902
13 0.000 0.902 0.857 0.950
14 0.902 0.950 0.902 1.000
15 0.000 0.000 0.000 0.000
Code
# 从起点执行确定性的贪心策略,验证学得策略确实到达目标。
greedy_state = 0 # 从 FrozenLake 起点开始验证
greedy_path = [greedy_state] # 保存可解释的状态路径
for rollout_step in range(16): # 最短成功路径远少于 16 步
greedy_action = int(np.flatnonzero(np.isclose(q_table[greedy_state], q_table[greedy_state].max()))[0]) # 固定选择首个最优动作
greedy_state, rollout_reward, rollout_done = mock_step(greedy_state, greedy_action) # 执行贪心动作
greedy_path.append(greedy_state) # 记录到达的下一状态
if rollout_done: # 按当前教学条件控制计算分支。
break # 到达洞或目标后停止验证
assert greedy_state == GOAL_STATE and rollout_reward == 1 # 若策略未到目标则使渲染失败
assert np.count_nonzero(q_table[[0, 4, 8, 9, 13, 14]]) > 0 # 确认奖励已传播到可达前序状态
print(f'成功训练回合: {successful_episodes}/{n_episodes}') # 报告探索确实多次到达目标
print(f'贪心路径: {greedy_path}; 到达目标: {greedy_state == GOAL_STATE}') # 展示可重复策略
成功训练回合: 8311/12000
贪心路径: [0, 4, 8, 9, 13, 14, 15]; 到达目标: True
结果解读
奖励传播到起点,确认路径为 0 → 4 → 8 → 9 → 13 → 14 → 15。终止掩码阻断跨回合自举;这个确定性执行检查不能外推到滑动、连续或市场环境。
从表格到现实:状态空间爆炸
我们刚才讨论的表格方法(Q表)非常适合状态和动作空间很小的问题。
但是,现实世界的经济问题呢?
- 国际象棋的状态空间大约是 \(10^{47}\)。
- 围棋的状态空间大约是 \(10^{170}\)。
- 一个自动驾驶汽车的状态是连续的(位置、速度、方向),状态空间是无限的。
我们不可能为这些问题创建一个Q表。这就是深度强化学习 (Deep Reinforcement Learning, DRL) 的用武之地。
深度强化学习:神经网络赋能RL
DRL的核心思想是用一个深度神经网络来近似价值函数或策略函数,而不是用一个表格。
价值网络 (Value Network):输入是状态 \(s\),输出是这个状态的价值 \(V(s)\),或者每个动作的Q值 \(Q(s,a)\)。
\[
\large{ Q(s, a; \mathbf{w}) \approx Q^*(s, a) }
\]
这里的 \(\mathbf{w}\) 是神经网络的权重。
策略网络 (Policy Network):输入是状态 \(s\),输出是在这个状态下采取每个动作的概率 \(\pi(a|s)\)。
重要进展:Deep Q-Network (DQN)
来源:Mnih et al. (2013);Mnih et al. (2015)。
DQN的核心就是用一个深度卷积神经网络(CNN)来近似最优动作价值函数 \(Q^*(s,a)\)。
DQN的损失函数:如何训练网络?
我们如何训练这个Q网络呢?我们希望网络的预测 \(Q(s, a; \mathbf{w})\) 尽可能接近贝尔曼最优方程给出的“目标值”。
令在线网络参数为 \(\theta\)、冻结的目标网络参数为 \(\theta^-\),终止指示为 \(d_t\in\{0,1\}\)。标准 target-network DQN 的目标与损失为:
\[
\large{Y_t^{\mathrm{DQN}}=R_{t+1}+\gamma(1-d_t)\max_{a'}Q(S_{t+1},a';\theta^-)}
\]
\[
\large{L(\theta)=\mathbb{E}\left[\left(Y_t^{\mathrm{DQN}}-Q(S_t,A_t;\theta)\right)^2\right]}
\]
然后我们可以用梯度下降法来优化网络权重 \(\mathbf{w}\)。
经验回放降低相邻更新的相关性
DQN 通过存储转移并在稍后抽样来稳定训练。
- 效果:回放降低相邻转移相关性并提高复用率;变化策略仍会留下陈旧分布与不完整的状态—动作覆盖。
冻结目标网络稳定 bootstrap 目标
训练不稳定的第二个原因是目标若随在线参数同时变化,就像追逐移动靶。DQN 用 θ 计算当前预测,用冻结一段时间的 θ⁻ 计算 bootstrap 目标。
- 效果:目标网络
w- 被“冻结”一段时间,使得学习目标更加稳定。
DQN的过高估计问题
标准 DQN 的 max 同时完成动作选择与价值评估;当估计含噪声时,最大值会产生向上选择偏差。
\[
\large{Y_t^{\mathrm{DQN}}=R_{t+1}+\gamma(1-d_t)\max_{a'}Q(S_{t+1},a';\theta^-)}
\]
如果Q值的估计本身有噪声,那么取最大值会放大正向噪声,导致乐观的偏差。这种偏差会通过自举过程不断传播和累积。
解决方案:Double DQN (DDQN)
DDQN通过一个巧妙的修改来解耦“动作选择”和“价值评估”,从而缓解过高估计问题。
标准DQN的目标:
\[
\large{Y_t^{\mathrm{DQN}}=R_{t+1}+\gamma(1-d_t)\max_{a'}Q(S_{t+1},a';\theta^-)}
\]
DDQN的目标:它使用主网络来选择最佳动作,但使用目标网络来评估这个动作的价值。
\[
\large{Y_t^{\mathrm{DDQN}}=R_{t+1}+\gamma(1-d_t)Q\!\left(S_{t+1},\arg\max_{a'}Q(S_{t+1},a';\theta);\theta^-\right)}
\]
这种解耦的目标是减少 DQN 由取最大值引起的过高估计偏差;
它不保证每个状态都更保守或更准确,低估与准确性须在具体任务中实证检验。
数值确认:先独立计算 DQN 与 DDQN target
设 \(R_{t+1}=1, \gamma=0.9, d_t=0\)。
下一状态在线网络给动作 A/B 的估计为 \((5,4)\),目标网络估计为 \((3,6)\)。
先分别写出两个 target,并判断 \(d_t=1\) 时是否仍 bootstrap。
- DQN:目标网络直接取最大值 6,故 \(Y^{DQN}=1+0.9\times6=6.4\)。
- DDQN:在线网络选择 A,目标网络对 A 估值为 3,故 \(Y^{DDQN}=1+0.9\times3=3.7\)。
- 若 \(d_t=1\),两者都等于即时奖励 1;terminal mask 禁止 bootstrap。
补救
若 DQN 选了在线网络最大值,回到 target-network 公式;若 DDQN 用目标网络选动作,回到“在线选择、目标评估”。继续核心检查,或进入 Dueling DQN 拓展。
价值函数的进一步分解:Dueling DQN
课后选学
学习核心内容时可先进入练习;时间允许时再学习Dueling DQN。
Dueling DQN提出了一种新的网络架构,它将Q值的估计分解为两部分:
- 状态价值 (State Value, \(V(s)\)):这个状态本身有多好,与采取什么动作无关。
- 优势函数 (Advantage Function, \(A(s,a)\)):在这个状态下,采取动作 \(a\) 比采取平均动作要好多少。
\[
\large{ Q(s,a) = V(s) + \left( A(s,a) - \frac{1}{|\mathcal{A}|} \sum_{a' \in \mathcal{A}} A(s,a') \right) }
\]
这种架构让网络能够更有效地学习状态的内在价值,尤其是在很多动作的价值都差不多时。
形成性检查:终止状态与策略语义
- 揭示与补救: 第 1 题为 −2,因为终止 mask 屏蔽 bootstrap;第 2 题 Sarsa 是 on-policy、Q-learning 是 off-policy。若写 97,回到终止状态;若颠倒策略语义,回到两种 target。
分步练习:手算一次 DDQN
- 任务: (R=0.5,γ=0.8,d=0);在线网络 A/B/C 为 (2,5,4),目标网络为 (6,1,3)。计算两种 target。
- 完整答案: DQN 取目标网络最大值 6,得到 \(0.5+0.8\times6=5.3\);DDQN 由在线网络选择 B,再用目标网络评价 B=1,得到 \(0.5+0.8\times1=1.3\)。
综合练习:本地中国指数的离线 RL 设计
- 任务:
使用本地 hs300_index_only.h5 / hs300 设计月度仓位教学环境:状态仅含月末可得特征,动作 {空仓, 持有},奖励为下一月组合收益减交易成本。
提交状态、动作、转移、奖励、行为策略覆盖与按时间离线评估方案。
- 完整答案提醒:
- 学习顺序: 核心内容在此完成本讲回顾;时间允许时可 返回 Dueling DQN 拓展。
综合练习:可执行参考实现
Code
from pathlib import Path # 定位本地沪深300最小文件
import numpy as np # 计算收益率与波动状态
import pandas as pd # 读取并构造离线转移表
# 公网下载:https://assets.qiufei.site/data/index/hs300_index_only.h5
# 下载后把下一行改为本机文件位置;按课程结构存放时可用 Path("data/index/hs300_index_only.h5")。
# Windows:Path(r"C:\qiufei\data\index\hs300_index_only.h5")
# macOS:Path("/Users/你的用户名/data/index/hs300_index_only.h5")
# Linux:Path("/home/你的用户名/data/index/hs300_index_only.h5")
index_path = Path("/home/ubuntu/r2_data_mount/data/index/hs300_index_only.h5")
daily_index = pd.read_hdf(index_path, key='hs300') # 读取真实中国指数行情
daily_index['date'] = pd.to_datetime(daily_index['datetime'].astype(str), format='%Y%m%d%H%M%S') # 解析交易时间
monthly_close = daily_index.query("'2005-01-01' <= date <= '2024-12-31'").set_index('date')['close'].resample('ME').last().to_frame() # 固定样本期并按月聚合
monthly_close['return_1m'] = monthly_close['close'].pct_change() # 构造月度收益
monthly_close['momentum_3m'] = monthly_close['close'].pct_change(3) # 构造月末可见动量
monthly_close['volatility_3m'] = monthly_close['return_1m'].rolling(3).std() # 构造过去三月波动
monthly_close['high_vol'] = monthly_close['volatility_3m'].gt(monthly_close['volatility_3m'].expanding().median()).astype(int) # 只用历史扩展中位数离散化
monthly_close['positive_momentum'] = monthly_close['momentum_3m'].gt(0).astype(int) # 形成无前视动量状态
monthly_close['state'] = 2 * monthly_close['high_vol'] + monthly_close['positive_momentum'] # 编码四个离散状态
monthly_close['behavior_action'] = monthly_close['positive_momentum'] # 明确示范行为策略而非虚构真实交易
monthly_close['next_return'] = monthly_close['return_1m'].shift(-1) # 对齐下一月环境反馈
monthly_close['reward'] = monthly_close['behavior_action'] * monthly_close['next_return'] - .001 * monthly_close['behavior_action'].diff().abs().fillna(0) # 扣除10bp换仓成本
monthly_close['next_state'] = monthly_close['state'].shift(-1) # 对齐下一状态
offline_batch = monthly_close.dropna().copy() # 形成完整离线转移样本
support_table = pd.crosstab(offline_batch['state'], offline_batch['behavior_action']) # 检查每个状态动作覆盖
display(support_table) # 展示能否识别反事实动作价值
| state |
|
|
| 0 |
73 |
0 |
| 1 |
0 |
73 |
| 2 |
39 |
0 |
| 3 |
0 |
51 |
综合练习:结果与支持判断规则
- 完整参考输出:
236 个转移覆盖 2005-04 至 2024-11。
四个状态的动作计数分别为 (73,0)、(0,73)、(39,0)、(0,51);每个状态都缺少一个动作,说明该确定性行为策略没有反事实支持。
正确结论是不能从这批数据可靠比较替代动作价值,更不能报告策略改进收益;需要更有覆盖的行为数据、保守离线 RL 与滚动基线。
- 按时间评估方案:
使用 rolling-origin 切分:每一折只用过去月份拟合策略,在紧接其后的验证窗确定超参数与支持阈值,再在更后的测试窗评估一次;
随后整体向前滚动。
每个测试窗都同时报告“始终空仓”“始终持有”和上述行为策略三条基线,并计入同一交易成本。
当前支持表在每个状态都缺少一个动作,因此支持判断规则直接阻止替代策略价值比较;
此处结论是“不可识别”,而不是补报一个回测收益。
来源与延伸阅读
- Sutton, R. S. and Barto, A. G. (2018), Reinforcement Learning: An Introduction, 2nd ed.;邻近支持 Bellman 方程、TD 与收敛条件。
- Mnih, V. et al. (2015), “Human-level control through deep reinforcement learning,” Nature。
- van Hasselt, H., Guez, A., and Silver, D. (2016), “Deep Reinforcement Learning with Double Q-learning,” AAAI。
- FrozenLake 是明确标注的教学模拟;迁移任务使用本地沪深300真实行情,但不在本页虚构回测结果。
结论:强化学习为经济学决策提供了新范式
- 核心框架:MDP为序贯决策问题提供了统一的数学语言。
- 核心思想:
- 核心算法:从Q-Learning到DQN及其变体,算法的进步使得解决日益复杂的问题成为可能。
- 经济学意义:
未来的方向:RL在经济学中的应用
- 市场建模:将多个RL智能体放在一个模拟市场中,研究市场均衡和复杂动态的涌现 (emergence)。
- 算法博弈论:设计在竞争或合作环境中表现最优的智能体,例如在拍卖或供应链谈判中。
- 个性化策略:为每个用户(如电商推荐)或每个资产(如投资组合)制定动态的、个性化的策略。
强化学习正在从一个计算机科学的子领域,演变为理解和优化复杂系统中智能决策的通用框架。