前 5 课我们都在做同一件事:手里有一堆带标签的数据 \((x,y)\),写一个损失 \(L(\theta)\),再用梯度 \(\nabla_\theta L\) 把它压小。监督学习的世界里,"什么是对的"是给定的——标签就是真理。但很多任务根本没有标签。下棋时没人告诉你"这一步的正确走法是 e4";陪人聊天时没有"标准回复";让模型写代码,你能说的只有"这段跑通了、那段报错了"。你只有一个稀薄的信号:行为好不好。这一课我们换范式——从奖励中学习(reinforcement learning, RL)。
读完这一课,你将能够
- 用 MDP 五元组 \((\mathcal{S},\mathcal{A},P,r,\gamma)\) 把一个"序贯决策"问题形式化,并说清马尔可夫性意味着什么;
- 解释折扣回报 \(G_t\) 里的 \(\gamma\) 为什么同时管"数学收敛"和"近期更重要"两件事;
- 写出并口算一个小 MDP 的贝尔曼方程,求出状态价值 \(V^\pi\);
- 区分 \(V^\pi/Q^\pi\) 与最优 \(V^*/Q^*\),并说出贝尔曼最优方程里那个 \(\max\) 的来历;
- 用 numpy 在小 MDP 上跑价值迭代,看着 \(V\) 一轮轮收敛;并把 LLM 生成文本看成一个序贯决策问题。
一、为什么需要 RL:从"标签"到"奖励"
先把两种范式并排放:
| 监督学习 | 强化学习 | |
|---|---|---|
| 反馈 | 每个样本一个正确答案 \(y\) | 一个标量奖励 \(r\)(好不好,不告诉你"应该怎么做") |
| 样本独立性 | 样本通常 i.i.d. | 你的动作改变下一步看到的状态,样本互相牵连 |
| 目标 | 最小化损失 \(L(\theta)\) | 最大化长期累积奖励 |
| 反馈时机 | 立即、密集 | 常常延迟、稀疏(下完整盘棋才知道输赢) |
ML 和 ML 的联系(埋点:为什么前沿模型都在用 RL)
大语言模型的"对齐"和"推理"恰恰是没有标签的任务。"这个回答有没有帮助、安不安全"无法写成唯一正确字符串,只能由人类偏好或一个奖励模型打分——这就是 RLHF(基于人类反馈的强化学习)。推理模型则用"最终答案对不对"作奖励,去强化那些能导向正确结论的思维链。下一课我们会看到,这些都建立在本课的 MDP 语言之上。先把地基打牢。
二、Agent 与环境:交互回路
RL 的世界里只有两个角色:智能体(agent)和环境(environment)。它们来回传球:每一步,agent 观察到当前状态 \(s\),挑一个动作 \(a\);环境收到动作后,吐回一个奖励 \(r\) 和下一个状态 \(s'\)。如此循环。
这个回路就是 RL 的全部物理。agent 要解决的问题是:面对每个状态,该选什么动作,才能让未来累积的奖励最大?这个"选动作的规则"就叫策略(policy),记作 \(\pi(a\mid s)\)——给定状态 \(s\),在各动作上的概率分布(确定性策略就是把全部概率压在一个动作上)。
三、把问题写成数学:马尔可夫决策过程 MDP
要让"状态-动作-奖励"的循环可计算,我们需要一个干净的数学外壳。它叫 马尔可夫决策过程(Markov Decision Process, MDP),由五个东西组成:
- 状态集 \(\mathcal{S}\):环境可能处于的所有情况(棋盘局面、机器人位姿、已生成的文本前缀)。
- 动作集 \(\mathcal{A}\):每个状态下可选的动作(落子、关节力矩、下一个 token)。
- 转移 \(P(s'\mid s,a)\):在 \(s\) 做 \(a\) 后,跳到 \(s'\) 的概率。环境的"物理引擎"。
- 奖励 \(r(s,a)\)(或 \(r(s,a,s')\)):这一步拿到的即时标量反馈。
- 折扣 \(\gamma\in[0,1)\):未来奖励的打折系数(下面细讲)。
名字里的 "Markov" 是核心约束。马尔可夫性(Markov property)说的是:
\[ P(s_{t+1}\mid s_t,a_t,\,s_{t-1},a_{t-1},\dots,s_0)=P(s_{t+1}\mid s_t,a_t). \]翻译成人话:未来只依赖"现在",不依赖"怎么走到现在的"。只要状态 \(s_t\) 写得足够完整,过去的历史就被"压缩"进了当前状态,可以全部丢掉。
四、回报 \(G_t\) 与折扣 \(\gamma\):把"长期"装进一个数
agent 要最大化的不是某一步的 \(r\),而是从现在起未来全部奖励的总和。但"总和"有个麻烦:如果一直走下去,奖励无限多个相加可能发散(\(\infty\) 没法比较大小)。解决办法是给越远的奖励打越狠的折扣。定义折扣回报(discounted return):
\[ G_t \;=\; r_t + \gamma\, r_{t+1} + \gamma^2 r_{t+2} + \cdots \;=\; \sum_{k\ge 0}\gamma^k\, r_{t+k}, \qquad \gamma\in[0,1). \]这个 \(\gamma\) 同时干两件事:
- 数学上保证收敛。只要奖励有界 \(|r|\le R_{\max}\),几何级数 \(\sum_{k\ge0}\gamma^k R_{\max}=\tfrac{R_{\max}}{1-\gamma}\) 就是有限的——无穷的未来被压成一个有限的数,才能拿来比较和优化。这里用到的求和公式 \(\sum_{k\ge0}\gamma^k=\tfrac{1}{1-\gamma}\)(当 \(|\gamma|<1\))一行就能自证:记 \(S=1+\gamma+\gamma^2+\cdots\),两边乘 \(\gamma\) 得 \(\gamma S=\gamma+\gamma^2+\cdots\),相减 \(S-\gamma S=1\),故 \(S=\tfrac{1}{1-\gamma}\)。
- 表达"近期奖励更重要"。\(\gamma\) 越小,agent 越"短视",只在乎眼前;\(\gamma\to 1\),agent 越"有远见",愿意为长远回报牺牲眼前。一个常用直觉:把 \(\gamma\) 看成"每一步有 \(1-\gamma\) 的概率游戏突然结束"——所以未来的奖励要按存活概率打折。
五、价值函数:给状态/动作标个"值"
回报 \(G_t\) 依赖于具体走出来的那一条随机轨迹,每次都不一样。我们真正想知道的是期望意义下,在某个状态有多好。于是定义状态价值函数(state-value function):
\[ V^\pi(s)\;=\;\mathbb{E}_\pi\!\left[\,G_t \mid s_t=s\,\right] \;=\;\mathbb{E}_\pi\!\left[\sum_{k\ge0}\gamma^k r_{t+k}\,\Big|\,s_t=s\right]. \]读作:从状态 \(s\) 出发、之后一直按策略 \(\pi\) 行动,期望能拿到多少折扣回报。注意它带上标 \(\pi\)——价值是相对于某个策略而言的,换策略就换价值。
有时我们想更细一点:不仅问"这个状态多好",而是"在这个状态做某个特定动作有多好"。这就是动作价值函数(action-value function),也叫 Q 函数:
\[ Q^\pi(s,a)\;=\;\mathbb{E}_\pi\!\left[\,G_t \mid s_t=s,\,a_t=a\,\right]. \]它先强制在 \(s\) 做 \(a\)(哪怕 \(\pi\) 本来不爱选它),之后再按 \(\pi\) 走。两者关系直观:状态价值是动作价值按策略概率的加权平均,\(V^\pi(s)=\sum_a \pi(a\mid s)\,Q^\pi(s,a)\)。
六、贝尔曼方程:价值的递归骨架
价值函数定义里有个无穷求和,没法直接算。贝尔曼方程(Bellman equation)的魔法是把它拆成一步。把 \(G_t = r_t + \gamma G_{t+1}\) 这个恒等式代进期望,就得到:
\[ V^\pi(s)\;=\;\mathbb{E}_{a\sim\pi,\,s'\sim P}\big[\,r(s,a)+\gamma\,V^\pi(s')\,\big]. \]一句话读懂它:当前价值 = 即时奖励 + 未来价值的折扣。站在 \(s\),先拿这一步的 \(r\),然后跳到 \(s'\)——而 \(s'\) 那边的"好坏"早已被 \(V^\pi(s')\) 总结好了,打个 \(\gamma\) 折扣加回来即可。无穷的未来被一个递归引用替代了。
这是一组关于 \(\{V^\pi(s)\}\) 的线性方程(每个状态一条),原则上可以直接解。下面的例题就这么干。
例题:两状态 MDP,手解贝尔曼方程
两个状态 \(A,B\),策略固定(每个状态只有一个动作,所以不用写 \(\pi\))。规则:在 \(A\) 拿奖励 \(0\) 后必定去 \(B\);在 \(B\) 拿奖励 \(1\) 后必定回 \(A\)。折扣 \(\gamma=0.9\)。求 \(V(A),V(B)\)。
写出两条贝尔曼方程(转移确定,期望退化为代入):
\[ V(A)=0+0.9\,V(B),\qquad V(B)=1+0.9\,V(A). \]把第一式代入第二式:\(V(B)=1+0.9(0.9\,V(B))=1+0.81\,V(B)\),于是 \((1-0.81)V(B)=1\),
\[ V(B)=\frac{1}{0.19}\approx 5.2632,\qquad V(A)=0.9\,V(B)\approx 4.7368. \]验算:\(V(A)=0.9\times5.2632=4.7368\)✓;\(V(B)=1+0.9\times4.7368=5.2632\)✓。两个状态价值都是正的有限数。事实上这里有个精确的结构:从 \(B\) 出发每隔两步拿一次 \(+1\),所以 \(V(B)=1+\gamma^2+\gamma^4+\cdots=\tfrac{1}{1-\gamma^2}=\tfrac{1}{1-0.81}=\tfrac{1}{0.19}\),和上面解出来的分毫不差——"每隔一步 \(+1\)、按 \(\gamma^2\) 几何求和"不是巧合,而是这个交替 MDP 的本来面目。
最优价值与贝尔曼最优方程
上面是评估一个给定策略。但 RL 的终极目标是找最好的策略。定义最优状态价值 \(V^*(s)=\max_\pi V^\pi(s)\)、最优动作价值 \(Q^*(s,a)=\max_\pi Q^\pi(s,a)\)。它们满足贝尔曼最优方程(Bellman optimality equation):
\[ V^*(s)=\max_a \Big[\,r(s,a)+\gamma\,\mathbb{E}_{s'}\,V^*(s')\,\Big], \qquad Q^*(s,a)=r(s,a)+\gamma\,\mathbb{E}_{s'}\Big[\max_{a'}Q^*(s',a')\Big]. \]和普通贝尔曼方程唯一的差别是把"对策略求期望 \(\mathbb{E}_{a\sim\pi}\)"换成了"取最大 \(\max_a\)"。直觉:既然要最优,每一步当然挑当下看起来回报最高的动作,而不是按某个固定策略掷骰子。一旦有了 \(Q^*\),最优策略就是"每个状态选 \(\arg\max_a Q^*(s,a)\)"——决策变成查表。
七、怎么求解:价值迭代与 Q-learning(点到为止)
价值迭代(value iteration):把贝尔曼最优方程当成更新规则反复用。从随便一个 \(V_0\)(比如全 0)开始,每轮对所有状态做
\[ V_{k+1}(s)\;\leftarrow\;\max_a\Big[\,r(s,a)+\gamma\,\mathbb{E}_{s'}\,V_k(s')\,\Big]. \]可以证明这个更新是压缩映射(contraction)——每轮把 \(V_k\) 与真值 \(V^*\) 的距离至少缩小到原来的 \(\gamma\) 倍,所以必然收敛到唯一不动点 \(V^*\)。下面的代码会让你亲眼看到这个收敛。
Q-learning:当你不知道环境的转移 \(P\) 和奖励 \(r\)(只能与环境交互、采样),就没法算上式里的期望 \(\mathbb{E}_{s'}\)。Q-learning 用一次真实采样的 \((s,a,r,s')\) 来近似它,朝目标 \(r+\gamma\max_{a'}Q(s',a')\) 挪一小步:
\[ Q(s,a)\;\leftarrow\;Q(s,a)+\eta\Big[\underbrace{r+\gamma\max_{a'}Q(s',a')}_{\text{TD 目标}}-Q(s,a)\Big]. \]这里 \(\eta\) 就是熟悉的学习率,方括号叫 TD 误差——它就是"目标 \(-\) 当前估计"的残差。正因为括号里取的是"目标减预测",前面才用 \(+\) 号:朝目标方向挪一小步。(监督学习里梯度下降也是用"目标减预测"这个残差来推动更新,方向一致,异曲同工。)细节后面专门讲,这里只要记住:价值迭代是"已知模型、用期望算",Q-learning是"未知模型、用采样学"。
八、探索 vs 利用:ε-greedy
"未知模型、靠采样"带来一个新两难。假设你刚试了一家餐馆觉得不错(\(Q\) 较高)——你该每次都去它(利用 exploitation,吃稳的),还是偶尔去试没去过的(探索 exploration,万一更好)?只利用,你可能永远错过真正最好的;只探索,你浪费大量时间在烂选项上。这就是 探索–利用权衡(exploration–exploitation trade-off)。
最简单的解法是 ε-greedy:以概率 \(1-\varepsilon\) 选当前估计最好的动作(利用),以小概率 \(\varepsilon\) 随机乱选一个(探索)。
九、把 LLM 文本生成看成 MDP(RLHF 埋点)
现在把这套语言套到大模型上,你会发现严丝合缝:
| MDP 元素 | 在 LLM 文本生成里是什么 |
|---|---|
| 状态 \(s\) | 已经生成的前缀(prompt + 目前为止的 tokens) |
| 动作 \(a\) | 下一个 token(动作空间 = 整个词表) |
| 策略 \(\pi(a\mid s)\) | 语言模型本身——给定前缀,下一个 token 的概率分布 |
| 转移 \(P(s'\mid s,a)\) | 确定的:把选中的 token 拼到前缀后面,就是新状态 |
| 奖励 \(r\) | 通常在序列结束时由奖励模型 / 人类偏好打一个分(中间步 \(r=0\)) |
| 折扣 \(\gamma\) | 常取接近 1,因为我们在乎整段输出的最终质量 |
于是"训练 LLM 对齐人类偏好"就成了一个标准 RL 问题:调整策略 \(\pi_\theta\)(模型权重 \(\theta\)),让生成序列的期望奖励最大。奖励稀疏(只在末尾)、归因困难(哪个 token 该记功)正是 RLHF 的核心挑战——也正是下一课的策略梯度要解决的。
调一调,观察现象
下面三个小实验都用 numpy 现场搭一个最小 MDP,亲手验证上面的结论。每个都几秒内跑完。先读"改什么 → 预期看到什么 → 为什么",再跑代码核对。
实验 1:折扣 \(\gamma\) 怎么影响价值大小
改什么:在 1×4 走廊 GridWorld(状态 0,1,2,3;3 是终点,走进去得 \(+1\))上做价值迭代,把 \(\gamma\) 从 \(0.9\) 改成 \(0.5\)。
预期看到:\(\gamma=0.9\) 时收敛到 \([0.81,\,0.9,\,1.0,\,0]\);\(\gamma=0.5\) 时变成 \([0.25,\,0.5,\,1.0,\,0]\)。离终点越远,价值被折扣得越狠,\(\gamma\) 小则"远处"几乎没价值。
为什么:从状态 \(s\) 到终点要走 \(d\) 步,价值约为 \(\gamma^{d-1}\)(进终点那步才拿 \(+1\))。\(\gamma\) 越小,\(\gamma^{d}\) 衰减越快,远处的状态价值越接近 0——这就是"短视"的数值体现。
import numpy as np
def value_iter(gamma, iters=12):
nS, nA = 4, 2 # 状态 0..3, 动作 0=左 1=右
def step(s, a):
if s == 3: return s, 0.0, True # 3 是终点
ns = min(s+1,3) if a==1 else max(s-1,0)
return ns, (1.0 if ns==3 else 0.0), (ns==3)
V = np.zeros(nS)
for _ in range(iters):
Vn = V.copy()
for s in range(3): # 终点 V=0 不更新
qs = []
for a in range(nA):
ns, r, done = step(s, a)
qs.append(r + gamma*(0.0 if done else V[ns]))
Vn[s] = max(qs)
V = Vn
return np.round(V, 4)
print("gamma=0.9:", value_iter(0.9))
print("gamma=0.5:", value_iter(0.5))
实验 2:看 \(V\) 一轮轮"长"出来(收敛过程)
改什么:把每一轮的 \(V\) 都打印出来(而不是只看最后结果)。
预期看到(\(\gamma=0.9\)):价值像水波从终点倒灌回起点——
iter1 [0,0,1,0] → iter2 [0,0.9,1,0] → iter3 [0.81,0.9,1,0],第 3 轮起就不再变。
为什么:每一轮,信息只能从"已知价值的状态"往外传一格(贝尔曼更新一次只看一步邻居)。终点的 \(+1\) 第 1 轮先点亮 state2,第 2 轮才传到 state1,第 3 轮到 state0。走廊长 \(d\) 就需要约 \(d\) 轮——这正是"价值迭代是逐步压缩"的可视化。
import numpy as np
nS, nA, gamma = 4, 2, 0.9
def step(s, a):
if s == 3: return s, 0.0, True
ns = min(s+1,3) if a==1 else max(s-1,0)
return ns, (1.0 if ns==3 else 0.0), (ns==3)
V = np.zeros(nS)
for it in range(6):
Vn = V.copy()
for s in range(3):
Vn[s] = max(step(s,a)[1] + gamma*(0.0 if step(s,a)[2] else V[step(s,a)[0]])
for a in range(nA))
V = Vn
print("iter %d:"%(it+1), np.round(V,4))
实验 3:ε 调大/调小,探索的代价
改什么:在 3 臂伯努利老虎机(真实中奖率 0.2 / 0.5 / 0.8)上跑 ε-greedy,把 \(\varepsilon\) 从 \(0.1\) 改成 \(0.5\)。
预期看到:两种 \(\varepsilon\) 估出的 \(Q\) 都接近真值 \([0.2,0.5,0.8]\);但 \(\varepsilon=0.1\) 时绝大多数次数(约 1850/2000)拉在最优臂上,\(\varepsilon=0.5\) 时最优臂只占约三分之二(约 1330/2000),大量次数浪费在差臂。一般地,最优臂被拉的比例约为 \((1-\varepsilon)+\varepsilon/K\)(\(K\) = 臂数):利用阶段几乎全压最优臂,探索阶段则在 \(K\) 个臂里均摊。代入 \(\varepsilon=0.5,K=3\) 得 \(0.5+0.5/3\approx0.667\),正是约 \(2/3\)。
为什么:\(\varepsilon\) 越大,差臂被采样的次数越多、它们的 \(Q\) 估得越稳,但用于"利用"最优臂的次数越少——总收益更低。这就是探索–利用的天平:探索买的是信息,付的是即时回报。
import numpy as np
def run(eps, T=2000, seed=0):
rng = np.random.default_rng(seed)
true_p = np.array([0.2, 0.5, 0.8])
Q = np.zeros(3); N = np.zeros(3)
for _ in range(T):
a = rng.integers(3) if rng.random() < eps else int(np.argmax(Q))
r = 1.0 if rng.random() < true_p[a] else 0.0
N[a] += 1; Q[a] += (r - Q[a]) / N[a] # 增量平均
return np.round(Q,3), N.astype(int)
for eps in (0.1, 0.5):
Q, N = run(eps)
print(f"eps={eps} Q={Q} pulls={N}")
动手练习
- 手解贝尔曼。把例题的奖励改成"在 \(A\) 得 \(+2\)、在 \(B\) 得 \(-1\)",转移不变,\(\gamma=0.9\)。列出两条贝尔曼方程并解出 \(V(A),V(B)\)。(提示:\(V(A)=2+0.9V(B)\),\(V(B)=-1+0.9V(A)\);解线性方程组。)
- 价值迭代加长。把走廊从 4 个状态改成 6 个状态(终点在 state5),跑实验 2 的逐轮打印,数一数 \(V\) 需要几轮才稳定,验证"轮数 ≈ 走廊长度"。
- 从 \(V\) 读出策略。价值迭代收敛后,对每个状态 \(s\) 算 \(\arg\max_a[r+\gamma V(s')]\),打印出最优动作。预期:所有状态都选"向右"。写出这段提取代码。
- 随机转移版。把走廊改成"选右有 0.8 概率真往右、0.2 概率原地不动"。修改
step让它在期望意义下更新(\(\sum_{s'}P(s'|s,a)[r+\gamma V(s')]\)),重跑价值迭代,观察价值整体变小(因为达成目标更慢)。 - ε 衰减。把实验 3 改成 \(\varepsilon\) 随步数衰减 \(\varepsilon_t=1/\sqrt{t+1}\),比较固定 \(\varepsilon=0.1\) 与衰减版累计收益 \(\sum r\)。预期衰减版略胜(前期探索充分、后期充分利用)。
掌握自检
- 我能说清监督学习的"标签"和 RL 的"奖励"差在哪,并举一个只有奖励、没有标签的任务。
- 我能写出 MDP 五元组,并解释马尔可夫性"未来只依赖现在"在状态定义上的要求。
- 我能说出折扣 \(\gamma\) 同时承担的两个角色(收敛 + 近期优先)。
- 给一个两状态 MDP,我能列出贝尔曼方程并手解 \(V\)。
- 我能指出普通贝尔曼方程与贝尔曼最优方程的唯一差别(\(\mathbb{E}_{a\sim\pi}\) vs \(\max_a\)),以及为什么后者非线性。
- 我能解释价值迭代为什么会收敛(压缩映射 / 逐步把信息往外传),并能从 \(V\) 提取出贪心策略。
- 我能把 LLM 文本生成映射成 MDP 的五个元素,并说出为什么 RLHF 的奖励是稀疏的。
可以先放过的点
- 压缩映射的证明(Banach 不动点定理)。现在只需相信"价值迭代必收敛、收敛到唯一 \(V^*\)",等到专门讲收敛性分析时再回来啃 \(\gamma\)-压缩的 \(\varepsilon\)-\(\delta\)。
- Q-learning 的收敛条件与 TD 学习全貌。本课只给了更新式的直觉,离线/在线、on-policy/off-policy 的区别留到 RL 速成 II。
- 连续状态/动作与函数近似。这里的 \(V,Q\) 都是查表(有限状态)。当状态是图像或文本时要用神经网络近似,那是深度 RL 的内容,先不展开。
- 奖励塑形与折扣对偏好的细微影响。\(\gamma\) 选多少、奖励怎么设计才不"被钻空子",是 RLHF 的实战难题,下一课起逐步触及。
下一课预告:有了 MDP 与价值的地基,我们就能问"如何直接优化策略 \(\pi_\theta\)"——这就是策略梯度。我们会推出策略梯度定理、引入本课提过的优势函数 \(A=Q-V\) 降方差,一路走到 PPO,并把它接到 RLHF:用人类偏好训练奖励模型,再用 RL 微调大模型。本课埋下的每个点,下一课都会兑现。