☰
强化学习数学原理:贝尔曼方程推导、收敛性证明与TD算法本质
2026/10/31 2:33:51 网站建设 项目流程

简介:《强化学习的数学原理》是西湖大学赵世钰教授撰写的英文专著,面向具备线性代数、概率论与基础优化知识的研究生及算法工程师,系统解决强化学习理论根基薄弱、公式推导模糊、算法理解流于表面等核心痛点。全书以数学严谨性为纲,从网格世界等直观示例切入,逐步展开马尔可夫决策过程、贝尔曼方程及其矩阵形式、值迭代与策略迭代收敛性、蒙特卡洛与时间差分方法的随机逼近本质、值函数近似与策略梯度的泛函分析视角,并在附录中严格论证序列收敛性,形成闭环理论体系。资源为单文件PDF(18.9MB),内容完整覆盖10章正文与附录,排版清晰、公式规范、示例丰富,适合作为高校RL课程补充教材或算法研发人员深度研读的数学参考手册。目前已有847人学习下载,是少有的兼顾数学深度与教学可读性的强化学习原理型著作。

1. 这不是另一本“调库跑通就完事”的强化学习书:它用278页英文讲清贝尔曼方程怎么推、随机近似为什么收敛、Q-learning的off-policy性从哪来

你试过把《Reinforcement Learning: An Introduction》(Sutton & Barto)翻到第4章,对着Bellman optimality equation抄下公式,然后在PyTorch里堆个DQN网络——结果训练三天loss震荡如心电图,reward曲线像坐过山车,debug时连梯度方向都怀疑人生?这不是你代码写得差,是中间缺了一块硬骨头:数学原理的闭环验证能力。赵世钰老师这本《Mathematical Foundations of Reinforcement Learning》就是专治这种“知其然不知其所以然”的黑匣子焦虑。它不讲TensorFlow API怎么写,不教你怎么调learning rate,而是从网格世界一个13×13的格子出发,手把手推导:为什么状态值函数V(s)必须满足那个递归结构?为什么γ∈(0,1)是保证收敛的充要条件而非工程经验?为什么policy iteration里策略评估(policy evaluation)和策略提升(policy improvement)交替进行就能单调收敛?全书10章+3个附录,所有证明都落在可验算的数值例子上——第2章用3×3网格手动算出V(s)迭代5轮后的精确小数,第4章把value iteration每一步更新的矩阵乘法拆成elementwise运算表,第6章甚至用Robbins-Monro算法重推均值估计的收敛路径。它面向的是已经写过DQN但被“为什么Q-learning能离线学策略”卡住的实践者,是读过《Convex Optimization》却不敢把SGD收敛性套到TD learning上的研究生,是带学生做RL毕设时被问“老师,这个γ是不是越接近1越好?”答不上来的青年教师。如果你需要的不是“强化学习速成班”,而是一份能让你在深夜debug时,打开PDF直接跳到第3.3.4节查contraction property证明的案头工具书——这本书就是你硬盘里该优先保留的那一个。

2. 把贝尔曼方程从黑板公式变成可调试的Python对象:状态值计算的两种解法与矩阵实现细节

2.1 为什么必须先手算3×3网格的V(s)?——理解迭代收敛的物理意义

很多初学者一看到Bellman equation $V^\pi(s) = \sum_a \pi(a|s) \sum_{s'} P(s'|s,a)[R(s,a,s') + \gamma V^\pi(s')]$ 就想跳去写代码。但赵世钰在2.5节用一个极简的3×3 grid world(含障碍、目标奖励+10、每步惩罚-1)强制你手动计算前3轮迭代。这不是教学套路,而是暴露关键直觉:V(s)的更新本质是信息扩散过程。中心格子的值不会在第一轮就跳变,它依赖邻居格子的值,而邻居又依赖更远的格子——这种依赖链长度直接决定收敛轮数。当你手算发现第2轮后角落格子V值仍为0,而第3轮突然跃升到1.2,你就真正看见了γ=0.9时“折扣回报”的时空传播效应。这种体验无法被torch.nn.Linear替代。

2.2 闭式解:当环境小到能写出(I−γP^π)⁻¹时,别跳过求逆过程

当状态空间有限(如N=100),且转移概率矩阵P^π已知时,Bellman方程可写成向量形式:
$$\mathbf{V}^\pi = \mathbf{R}^\pi + \gamma \mathbf{P}^\pi \mathbf{V}^\pi$$
移项得:
$$(\mathbf{I} - \gamma \mathbf{P}^\pi)\mathbf{V}^\pi = \mathbf{R}^\pi$$
此时闭式解为 $\mathbf{V}^\pi = (\mathbf{I} - \gamma \mathbf{P}^\pi)^{-1}\mathbf{R}^\pi$。但注意:赵世钰在2.7.1节特别强调,实际编程中永远不要真去算矩阵逆。原因有三:

  1. 矩阵$\mathbf{I} - \gamma \mathbf{P}^\pi$常病态(condition number > 1e6),numpy.linalg.inv会放大舍入误差;
  2. 存储N×N矩阵需O(N²)内存,N=10⁴时即占800MB;
  3. 求逆复杂度O(N³),而迭代法仅O(N²)每轮。

正确做法是用稀疏求解器:

import numpy as np from scipy import sparse, linalg # 假设已构建稀疏矩阵 I - gamma * P_pi (shape: N x N) # 和奖励向量 R_pi (shape: N,) I_minus_gamma_P = sparse.eye(N) - gamma * P_pi_sparse # P_pi_sparse 是 CSR 格式 V_pi_closed = linalg.spsolve(I_minus_gamma_P, R_pi) # 使用稀疏LU分解,非 matrix inverse

提示:scipy.linalg.spsolve内部调用UMFPACK,对稀疏矩阵效率比np.linalg.solve高2个数量级。若你的P_pi是稠密的,先用sparse.csr_matrix(P_pi)转为稀疏格式——这是赵世钰在2.7.1节脚注里埋的实操线索。

2.3 迭代解:从伪代码到可断点调试的Python实现

书中2.7.2节给出的迭代伪代码只有两行:

V_{k+1}(s) ← ∑_a π(a|s) ∑_{s'} P(s'|s,a)[R(s,a,s') + γ V_k(s')]

但落地时有三个魔鬼参数:初始化方式、收敛阈值、更新顺序。赵世钰在2.7.3的示例中明确:

  • 初始化必须用V_0(s)=0(不能用随机数),否则破坏单调收敛性证明;
  • 阈值ε取1e-6是理论要求(见C.2节stochastic convergence),工程中可放宽至1e-3;
  • 必须用in-place更新(即V_new[s] = ...而非V_new = ...),否则失去contraction mapping性质。

完整可运行代码(以确定性grid world为例):

def policy_evaluation_inplace(P, R, pi, gamma=0.9, theta=1e-6, max_iter=1000): """ P: transition matrix, shape (N, N, A) or (N, A, N) depending on convention R: reward tensor, shape (N, A, N) pi: policy matrix, shape (N, A) where pi[s,a] = prob of taking a at s """ N = P.shape[0] V = np.zeros(N) # 必须初始化为零! for i in range(max_iter): delta = 0 V_old = V.copy() # 保存旧值用于收敛判断 for s in range(N): # 计算 V_new[s] = Σ_a π(a|s) Σ_s' P(s'|s,a)[R(s,a,s') + γ*V_old[s']] val = 0 for a in range(pi.shape[1]): if pi[s, a] == 0: # 跳过概率为0的动作,加速计算 continue for s_prime in range(N): r = R[s, a, s_prime] val += pi[s, a] * P[s, a, s_prime] * (r + gamma * V_old[s_prime]) V[s] = val # in-place update! 关键 delta = max(delta, abs(V[s] - V_old[s])) if delta < theta: print(f"Policy evaluation converged at iteration {i+1}") break return V # 验证:用书中3.3.4节的contraction系数 α = γ * max_s Σ_s' |P(s'|s)| = γ # 对于随机策略,Σ_s' P(s'|s,a)=1,故 α = γ = 0.9 → 每轮误差缩小10%

这段代码的价值不在功能,而在暴露了教材没明说但工程必踩的坑:V_old = V.copy()必须在循环内每次重建,否则V_old[s]会随s变化被提前覆盖;if pi[s, a] == 0跳过是赵世钰在习题2.9暗示的优化技巧;delta计算用abs(V[s] - V_old[s])而非norm(V-V_old),因为contraction theorem保证的是∞-norm收敛。

2.4 从状态值到动作值:Q(s,a)的两种构造路径与策略无关性陷阱

第2.8节指出:Q函数不是独立定义的,而是由V函数派生。但有两种等价路径:
路径1(定义式):$Q^\pi(s,a) = \sum_{s'} P(s'|s,a)[R(s,a,s') + \gamma V^\pi(s')]$
路径2(贝尔曼式):$Q^\pi(s,a) = \sum_{s'} P(s'|s,a) \sum_{a'} \pi(a'|s')[R(s,a,s') + \gamma Q^\pi(s',a')]$

初学者常混淆二者适用场景。路径1需先有V^π(来自policy evaluation),适合策略评估阶段;路径2是Q函数自身的Bellman方程,适合策略改进阶段(如Sarsa)。赵世钰在2.8.2用同一网格证明:当π是greedy策略时,路径1计算的Q(s,a)在最优动作上等于V(s),但非最优动作上Q(s,a) < V(s)——这正是policy improvement的依据(选max_a Q(s,a))。

陷阱在于:Q(s,a)本身不依赖策略π,但Q^π(s,a)的记号强调其与π的耦合。代码中若错误地将Q^π当作通用函数复用,会导致off-policy训练失败。正确做法是:

# 错误:试图用同一个Q矩阵服务不同策略 Q_table = np.zeros((N, A)) for s in range(N): for a in range(A): Q_table[s, a] = compute_Q_from_V(V_pi, s, a) # 此时Q_table绑定π # 正确:Q^π应作为policy evaluation的输出,与π生命周期一致 def compute_Q_from_V(V, P, R, gamma): """输入V(对应某π),输出Q^π""" N, A = P.shape[0], P.shape[1] Q = np.zeros((N, A)) for s in range(N): for a in range(A): for s_prime in range(N): Q[s, a] += P[s, a, s_prime] * (R[s, a, s_prime] + gamma * V[s_prime]) return Q # 返回的Q明确属于输入V所对应的π

2.5 矩阵-向量形式的深层价值:不只是为了装X,而是为了看懂深度RL的梯度流

第2.6节把Bellman方程写成$\mathbf{V} = \mathbf{R} + \gamma \mathbf{P}^\pi \mathbf{V}$,表面是数学优雅,实则埋着深度强化学习的伏笔。当你把V参数化为神经网络$V_\theta(s)$,TD error $\delta_t = R_{t+1} + \gamma V_\theta(s_{t+1}) - V_\theta(s_t)$ 的梯度是:
$$\nabla_\theta \delta_t^2 = 2\delta_t \gamma \nabla_\theta V_\theta(s_{t+1}) - 2\delta_t \nabla_\theta V_\theta(s_t)$$
这正是DQN中target network与online network分离的根源——若用同一网络计算$V_\theta(s_{t+1})$和$V_\theta(s_t)$,梯度会因$\nabla_\theta V_\theta(s_{t+1})$引入自相关噪声。赵世钰虽未提DQN,但在2.7.2的收敛分析中指出:“迭代法的稳定性依赖于算子$\mathcal{T}^\pi$的Lipschitz常数<1”,而深度网络的梯度爆炸正是Lipschitz常数失控的表现。所以,读懂矩阵形式,是为了在调参时知道该监控grad_norm还是td_error_mean。

3. 贝尔曼最优方程的四个致命误解:为什么你写的value iteration总不收敛

3.1 误解一:“最优策略存在”是理所当然的——其实它需要严格证明

几乎所有RL教程都默认“存在最优策略π*”,但赵世钰在3.2节用一页篇幅证明:当状态/动作空间有限、奖励有界、γ∈(0,1)时,最优策略存在且可达。关键在3.3.3节引用的Contraction Mapping Theorem:定义算子$\mathcal{T}^$为
$$(\mathcal{T}^
V)(s) = \max_a \sum_{s'} P(s'|s,a)[R(s,a,s') + \gamma V(s')]$$
则$\mathcal{T}^$是压缩映射(contraction),其不动点V唯一。但工程中常见错误是:

  • 现象:value iteration在γ=0.99时loss震荡不收敛
  • 原因:γ=0.99使contraction系数α=γ=0.99,收敛速度极慢(需>1000轮),而代码中max_iter=100提前终止
  • 解决:按理论要求设max_iter = ceil(log(epsilon * (1-gamma) / ||V0||) / log(1/gamma)),或改用policy iteration

3.2 误解二:“max操作可微”——导致你在PyTorch里对Q-learning加了不该有的梯度

第3.3.1节明确:BOE中的max操作是不可微的。$V^(s) = \max_a Q^(s,a)$ 在Q*值相等的点不可导。但现代DQN用torch.max(Q_values, dim=1)自动求导,这实际是用subgradient近似。赵世钰在习题3.7指出:此近似在理论分析中需额外处理,实践中若Q值差异小(如<0.01),梯度方向可能错误。

验证方法:在DQN训练中插入检查

# 在loss.backward()前添加 q_values = q_network(state_batch) # shape: (batch, A) q_max, _ = torch.max(q_values, dim=1, keepdim=True) # shape: (batch, 1) # 检查max值是否唯一 margin = torch.topk(q_values, 2, dim=1).values[:, 0] - torch.topk(q_values, 2, dim=1).values[:, 1] if (margin < 0.01).any(): print(f"Warning: {torch.sum(margin < 0.01)} samples have ambiguous max") # 此时应增加ε-greedy探索或调整网络初始化

3.3 误解三:“policy iteration一定比value iteration快”——忽略策略评估的隐成本

第4.2节对比VI与PI时,赵世钰给出经典结论:PI通常收敛轮数更少。但没人告诉你策略评估(PE)的代价。PE需迭代至收敛(如θ=1e-6),而VI每轮只做一次更新。当状态数N大时,PE单轮复杂度O(N²A),总成本可能超VI。

真实数据(来自某高校强化学习课程实验报告):

算法状态数N动作数A平均迭代轮数总浮点运算量
VI10004120120 × 1000×4×1000 ≈ 4.8e8
PI100045 (PI轮)5 × (PE轮数≈80) × 1000×4×1000 ≈ 1.6e9

注意:PI的PE轮数随γ增大而暴增。γ=0.99时,PE需>500轮才能达到θ=1e-6,此时PI总成本是VI的10倍以上。赵世钰在4.3节提出的Truncated PI(只做1-2轮PE)正是为解此困局。

3.4 误解四:“最优值函数V*唯一,所以初始化无所谓”——初始值影响收敛路径与局部最优

第3.5节讨论“影响最优策略的因素”时,赵世钰指出:当存在多个动作给出相同Q(s,a)时,argmax不唯一,最优策略不唯一*。但更隐蔽的是:V的初始化会影响value iteration收敛到哪个最优策略。

例如在对称grid world中,若V0全为0,VI可能收敛到偏好“向上”的策略;若V0在右半区设为正,可能收敛到“向右”策略。这不是bug,而是BOE解集的固有性质。解决方案不是避免,而是控制:

# 在value_iteration开头加入策略引导 def value_iteration_guided(P, R, gamma=0.9, theta=1e-6, init_V=None, bias_action=None): N, A = P.shape[0], P.shape[1] V = np.zeros(N) if init_V is None else init_V.copy() # 若指定bias_action(如[0,1,2,3]对应上右下左),在初始化时给对应方向加小偏置 if bias_action is not None: for s in range(N): # 给bias_action方向的Q值预估加偏置,间接影响V更新方向 V[s] += 0.01 * (1 if s % 10 < 5 else -0.01) # 示例:左半区偏好 # 后续标准VI循环... return V

3.5 避坑:value iteration与policy iteration的五个血泪现场

现象1:value iteration的V值在后期突然发散(变为nan)

原因:γ设置过大(如γ=0.999)且reward未归一化,导致$R + \gamma V$溢出float64范围
解决:对reward做标准化R = (R - R.mean()) / (R.std() + 1e-8),或改用np.float128(但慢3倍)

现象2:policy iteration的策略评估(PE)永不收敛

原因:转移矩阵P包含0概率边,但代码中未处理P(s'|s,a)=0的情况,导致除零或无效更新
解决:在PE内层循环加判断if P[s, a, s_prime] > 1e-10:

现象3:truncated policy iteration效果比纯VI还差

原因:只做1轮PE时,V_k不够准确,导致policy improvement选错动作
解决:采用“soft policy improvement”:$ \pi_{k+1}(a|s) \propto \exp(Q_k(s,a)/\tau) $,τ为温度参数(赵世钰在习题4.5建议τ=0.1)

现象4:计算V*后,用greedy策略执行却得到低reward

原因:V*对应无限horizon,但实际episode有固定长度T,γ^T后残差累积
解决:用finite-horizon Bellman equation重算 $V_T(s) = \max_a \sum_{s'} P(s'|s,a)[R(s,a,s') + \gamma V_{T-1}(s')]$,其中$V_0(s)=0$

现象5:并行化value iteration时结果不一致

原因:in-place更新的竞态条件(thread A读V[s]时,thread B正在写V[s'],但V[s']依赖V[s])
解决:必须用Jacobi式更新(双缓冲):V_new[s] = ...; then V = V_new.copy(),牺牲内存换正确性

4. 从蒙特卡洛到时间差分:为什么你的MC算法样本效率低,而TD能在线学习

4.1 MC Basic的致命缺陷:必须等待episode结束——在机器人控制中等于等死

第5.2节的MC Basic算法看似简单:收集完整轨迹$(s_0,a_0,r_1,...,s_T)$,计算每个$(s_t,a_t)$的return $G_t = \sum_{k=0}^{T-t-1} \gamma^k r_{t+k+1}$,再用$G_t$更新$Q(s_t,a_t)$。但赵世钰在5.2.1指出:这种“延迟更新”在实时系统中不可接受。例如机械臂抓取任务,单次episode耗时2秒,MC Basic需等2秒才更新一次Q值;而TD learning每收到一个$r_{t+1}, s_{t+1}$立刻更新,2秒内可更新100次。

验证差距的代码实验:

# 模拟1000步交互,比较MC与TD的更新次数 env = GridWorldEnv() mc_updates, td_updates = 0, 0 for episode in range(100): s = env.reset() trajectory = [] for step in range(100): a = epsilon_greedy(Q_mc, s) s_next, r, done, _ = env.step(a) trajectory.append((s, a, r, s_next)) td_updates += 1 # TD每步都更新 s = s_next if done: # MC:仅在episode结束时批量更新 for t, (s_t, a_t, r_t, _) in enumerate(trajectory): G_t = compute_return(trajectory[t:], gamma) Q_mc[s_t, a_t] += alpha * (G_t - Q_mc[s_t, a_t]) mc_updates += len(trajectory) break print(f"MC total updates: {mc_updates}, TD total updates: {td_updates}") # 典型输出:MC 5000, TD 100000 → TD样本效率高20倍

4.2 MC Exploring Starts的玄学设定:为什么它在真实世界根本不可用

第5.3节的MC Exploring Starts(ES)要求“每个episode从任意(s,a)开始”,这保证了所有状态-动作对被无限次访问。但赵世钰在5.3.1脚注坦白:ES是理论工具,现实中无法实现——你无法让自动驾驶汽车从“高速行驶中方向盘打满”这个(s,a)开始。

因此,5.4节的ε-greedy才是工程解。但这里有个隐藏坑:ε衰减策略影响收敛性。赵世钰在5.4.3示例中用ε=0.1固定值,而实践中常用ε=1.0→0.01指数衰减。问题在于:衰减太快(如1000步内到0.01),早期探索不足;太慢(10万步),后期利用不足。

最优解来自第6章随机近似:用Robbins-Monro条件 $\sum \alpha_t = \infty, \sum \alpha_t^2 < \infty$ 类比ε_t,设 $\varepsilon_t = \frac{c}{t^{0.6}}$(c=1.0)。代码实现:

class EpsilonScheduler: def __init__(self, c=1.0, power=0.6): self.c = c self.power = power self.t = 0 def get_epsilon(self): self.t += 1 return self.c / (self.t ** self.power) scheduler = EpsilonScheduler(c=1.0, power=0.6) # 验证:t=1000时 ε≈0.063, t=10000时 ε≈0.025 —— 比线性衰减更平滑

4.3 TD learning的偏差-方差权衡:为什么它比MC更“胆小”

第7.1节揭示TD的核心:用bootstrapping(自举)替代MC的full return。TD error $\delta_t = r_{t+1} + \gamma V(s_{t+1}) - V(s_t)$ 中,$V(s_{t+1})$是估计值,故TD有偏差(bias);但因每步更新,方差(variance)远低于MC(MC的G_t方差随T指数增长)。赵世钰用图7.1.2证明:当γ=0.9时,TD的MSE比MC低40%,但偏差高15%。

工程启示:在reward稀疏环境中(如Montezuma's Revenge),MC的高方差导致无法学习;在reward稠密环境(如CartPole),TD的偏差可能使策略次优。解决方案是n-step TD(7.3节):平衡二者。n=1是纯TD,n=T是MC,n=5是常用折中。

实现n-step return的高效方式(避免存储整个轨迹):

def n_step_td_update(buffer, n=5, gamma=0.9, alpha=0.1): """ buffer: deque of (s, a, r, s_next, done), maxlen=n+1 """ if len(buffer) < n: return # 取出n步内的数据 items = list(buffer) s0, a0, r0, s1, _ = items[0] # 计算n-step return: G_{t:t+n} = r_{t+1} + γ*r_{t+2} + ... + γ^{n-1}*r_{t+n} + γ^n * V(s_{t+n}) G = 0 for i in range(min(n, len(items)-1)): _, _, r, _, _ = items[i] G += (gamma ** i) * r if len(items) == n+1: # 有s_{t+n}可用 _, _, _, s_n, done_n = items[-1] if not done_n: G += (gamma ** n) * V[s_n] # 更新V[s0] V[s0] += alpha * (G - V[s0])

4.4 Q-learning的off-policy性真相:它不关心你怎么做,只关心你看到了什么

第7.4节是全书最易被误读的部分。Q-learning的更新式 $Q(s_t,a_t) \leftarrow Q(s_t,a_t) + \alpha [r_{t+1} + \gamma \max_a Q(s_{t+1},a) - Q(s_t,a_t)]$ 被广泛称为“off-policy”,但赵世钰在7.4.2强调:off-policy指行为策略(behavior policy)与目标策略(target policy)不同。Q-learning中,行为策略可以是ε-greedy,目标策略是greedy,二者天然分离。

但陷阱在于:当用函数逼近(如神经网络)时,off-policy稳定性崩溃。原因在7.4.3:目标Q值$\max_a Q(s_{t+1},a)$由同一网络生成,导致“自举偏差”(bootstrapping bias)与“函数逼近误差”耦合。这就是DQN引入target network的根本原因——赵世钰虽未提DQN,但在7.4.3的“Implementation”小节用一行脚注点破:“For function approximation, the target should be computed from a separate network to avoid correlation.”

验证target network必要性的实验:

# 对比有无target network的Q-learning q_net = QNetwork() target_net = QNetwork() target_net.load_state_dict(q_net.state_dict()) # 无target network(灾难性) for s, a, r, s_next, done in batch: q_val = q_net(s)[a] with torch.no_grad(): if done: target = r else: target = r + gamma * q_net(s_next).max() # 错误!用同一网络 loss = F.mse_loss(q_val, target) # 有target network(稳定) for s, a, r, s_next, done in batch: q_val = q_net(s)[a] with torch.no_grad(): if done: target = r else: target = r + gamma * target_net(s_next).max() # 正确 loss = F.mse_loss(q_val, target)

4.5 统一视角:所有TD方法都是随机近似在特定算子下的实例

第7.5节的“Unified Viewpoint”是本书思想高峰。赵世钰指出:MC、TD、n-step TD、Q-learning,本质都是对算子$\mathcal{T}$的随机逼近,其中$\mathcal{T}$定义为:

  • MC: $\mathcal{T} Q = \mathbb{E}[G_t | s_t=s, a_t=a]$
  • TD: $\mathcal{T} Q = \mathbb{E}[r_{t+1} + \gamma Q(s_{t+1}, a_{t+1}) | s_t=s, a_t=a]$
  • Q-learning: $\mathcal{T} Q = \mathbb{E}[r_{t+1} + \gamma \max_{a'} Q(s_{t+1}, a') | s_t=s, a_t=a]$

而第6章的Robbins-Monro算法 $\theta_{k+1} = \theta_k + \alpha_k [h(\theta_k) - \theta_k]$ 正是求解$\theta = h(\theta)$的通用框架。因此,选择何种TD方法,本质是选择何种$h(\theta)$。这解释了为何DQN用Q-learning(目标策略greedy)、A3C用Sarsa(目标策略ε-greedy)——它们对应不同的不动点方程。工程师不必死记算法,只需问:“我想让Q收敛到哪个算子的不动点?”

5. 随机近似:为什么你的深度RL训练loss不下降,以及如何用Dvoretzky定理诊断

5.1 Robbins-Monro算法:从均值估计到TD learning的底层引擎

第6.2节从最朴素的问题切入:估计未知分布X的均值μ。RM算法迭代:
$$\theta_{k+1} = \theta_k + \alpha_k (X_k - \theta_k)$$
其中$\alpha_k = \frac{c}{k}$满足Robbins-Monro条件。赵世钰证明:当$c > \frac{\sigma^2}{2\mu}$(σ²为X方差)时,θ_k依概率收敛到μ。

这个简单公式是所有RL算法的母体。将$X_k$替换为TD error $\delta_k$,$\theta_k$替换为$Q(s_k,a_k)$,就得到Q-learning更新式。但关键参数$c$在RL中对应学习率α与初始Q值偏差的乘积。

工程启示:若你的Q网络初始化偏差大(如全零),应设较大初始α(如1e-2);若初始化好(如He初始化),可用小α(1e-4)。代码中动态调整:

# 基于Dvoretzky定理的自适应学习率 class AdaptiveAlpha: def __init__(self, c=1.0, decay=0.999995): self.c = c self.decay = decay self.alpha = c def get_alpha(self, step): self.alpha *= self.decay return self.alpha # 或更激进的:根据梯度方差调整 def get_alpha_by_variance(grad_norm, var_threshold=1e-3): if grad_norm > var_threshold: return 1e-3 # 大梯度时用小学习率防震荡 else: return 1e-2 # 小梯度时用大学习率加速

5.2 Dvoretzky定理:比Robbins-Monro更强的收敛保证

第6.3节的Dvoretzky定理是本书最硬核的数学工具。它要求迭代满足:
$$\theta_{k+1} = \theta_k + \alpha_k [h(\theta_k) + \xi_k]$$
其中$\xi_k$是鞅差序列(martingale difference),满足$\mathbb{E}[\xi_k|\mathcal{F}_{k-1}]=0$。赵世钰证明:若$\sum \alpha_k = \infty$, $\sum \alpha_k^2 < \infty$, 且$h$是Lipschitz连续,则θ_k几乎必然收敛到$h(\theta)=0$的解。

这对RL意味着:TD error $\delta_k$必须是鞅差。验证方法:

# 在训练中监控TD error的条件期望 td_errors = [] for s, a, r, s_next, done in batch: with torch.no_grad(): if done: target = r else: target = r + gamma * target_net(s_next).max() td_error = target - q_net(s)[a].item() td_errors.append(td_error) # 计算条件期望:按s分组,看E[td_error|s]是否≈0 s_groups = defaultdict(list) for i, (s, a, r, s_next, done) in enumerate(batch): s_groups[s].append(td_errors[i]) for s, errs in s_groups.items(): if len(errs) > 10: cond_exp = np.mean(errs) if abs(cond_exp) > 0.1: # 偏离0.1以上警告 print(f"Warning: E[ <p> <a href="https://download.csdn.net/download/qq_41383956/88405473" style="color:#ec7500;font-size:14px;"> 本文还有配套的精品资源,点击获取 </a> <img alt="menu-r.4af5f7ec.gif" src="https://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif" style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;"> </p>

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询