如果你也接触过强化学习,大概率在第一个星期就会反复听到三个字母:MDP。我当年最困惑的是,它到底是纯数学概念,还是真的能拿来干活的东西。后来自己做了一些项目之后才慢慢想明白:MDP 与其说是一套公式,不如说它是强化学习世界的元素周期表。你之后见到的 Q-learning、策略梯度、演员-评论家,本质都是在从这张表里挑元素,再组合成不同的方法。无论你是刚入门还是已经在调各种算法了,我都会建议先把这张表背到条件反射的程度,因为后面所有的“高级话题”都建立在一个小小的五元组上。
这篇内容不想给你堆一排空泛定义,我尽量用一个实际项目的视角来讲清楚:MDP 里每个符号到底在描述什么,为什么要这样设计,以及你在自己搭环境、写算法时会踩到什么坑。
1. 为什么说 MDP 是强化学习世界的元素周期表
1.1 一张表收纳所有序贯决策问题
先想象一个生活场景:你想让一个机器人从客厅走到厨房,打开冰箱,拿出一瓶饮料。这个过程不是一个单独的动作,而是一连串的决策:先迈左脚还是右脚,走到门口要不要转弯,接近冰箱时伸手的位置在哪里。每一步行动都会改变机器人的状态,它会收到来自环境的一个反馈——可能是远离目标,也可能是拿到了饮料。
这种“不断根据当前情况做决定,再根据结果调整下一步”的问题,就是序贯决策问题。强化学习要解决的恰恰就是这类问题,而 MDP 是描述这类问题的通用数学框架。换句话说,只要一个问题可以拆成“状态、动作、回报”三个关键字,它基本上就能放进 MDP 的筐里。
这就是我为什么喜欢用“元素周期表”这个比喻。化学周期表只有一百多种元素,却能组成世界上所有的物质。MDP 也只有五个基本元素,却能组合出无数种强化学习算法和环境。你后面看到的每个复杂 Demo,拆到最后都跑不出这五样东西。
1.2 元素是固定的,组合方式千变万化
元素周期表的意义在于,你不需要记住每一种化合物的全部性质,只要理解元素的基本规律,就能推断新物质可能的行为。MDP 也是这个道理。你只要理解状态、动作、转移概率、奖励函数、折扣因子这五个概念,再遇到一个新的强化学习场景,你都能先把它“翻译”成标准格式,然后再决定用哪种算法。
举个例子。同样是控制一个四轴飞行器,如果你想让它悬停,状态可以是当前位置和速度,动作是四个电机的输出,奖励是偏离目标点的距离的负数。你想让它做巡航,把状态里加上目标航点,奖励改成“到达目标点给正分,偏离航线给负分”,问题结构立刻就从悬停变成了路径规划。底层元素没变,变的只是组合方式。
我自己的经验是:拿到任何任务,别急着上深度强化学习,先在纸上把五元组写清楚。如果连状态和奖励都定义不清楚,后面跑出来的结果基本没法解释。
2. MDP 的五个基本要素,缺一不可
2.1 五元组 (S, A, P, R, γ) 到底在说啥
标准 MDP 被写成一个五元组:状态集合 S、动作集合 A、状态转移概率 P、奖励函数 R,以及折扣因子 γ。这五个元素分别回答了一个决策问题最核心的问题:我们在哪、我们能做什么、环境如何回应、做好做坏怎么判断、未来值多少钱。
状态集合 S 描述了智能体所处环境的一切相关信息。动作集合 A 则是智能体可以采取的选择。转移概率 P 是环境的规律,它告诉我们从某个状态执行某个动作之后,下一个状态会怎么变。奖励函数 R 是评价信号,智能体做的事好还是坏,全靠它。折扣因子 γ 是一个 0 到 1 之间的数,表示未来回报的相对权重。
我自己在搭环境时最重视的其实是转移概率。很多初学者以为环境就是一张图片或一组传感器,其实“环境”真正的数学本质是转移概率分布。如果转移概率描述得不对,后面所有优化都会建立在错误的世界观上。举个例子,一个机器人的状态是位置,如果动作是“向左走 1 米”,但地面有摩擦,那么转移概率就不能写“100% 到左边 1 米处”,而应该写“以某种概率到左边 0.8 米,以某种概率到左边 1 米”。
2.2 马尔可夫性:为什么只看当前状态就够了
MDP 名字里的“马尔可夫”是关键设定。所谓马尔可夫性,用大白话说就是:当前状态已经包含了做决策所需的全部历史信息,过去的状态和动作不再提供额外信息。数学上可以表示为:
[ P(s_{t+1} \mid s_t, a_t, s_{t-1}, a_{t-1}, \dots) = P(s_{t+1} \mid s_t, a_t) ]
这句话看起来简单,但落地时非常容易翻车。我见过有人做一个无人机避障项目,状态里只有位置坐标,结果训练出来的策略忽左忽右,完全不像有经验的飞手。原因就是位置信息不充分:没有速度,模型就不知道下一步会怎么运动,马尔可夫性不成立。把速度加进状态之后,问题立刻自然了很多。
所以说,马尔可夫性不是一个可选的假设,而是一个你必须通过设计状态来满足的条件。它真正的好处是让决策只依赖一个固定大小的输入,而不是一段越来越长的历史。否则你每次做决策都要吞下一整条轨迹,算法很快就会撑不住。
2.3 折扣因子:眼前奖励和长远奖励的权衡
有了状态、动作、转移和奖励,还不能直接训练,因为时序上的回报需要累加。最简单的累加就是把所有未来奖励直接相加,但如果问题是无限的,这个和可能发散。所以标准 MDP 引入了折扣因子 γ。
智能体的目标通常是最大化期望回报:
[ G_t = R_{t+1} + \gamma R_{t+2} + \gamma^2 R_{t+3} + \dots ]
γ 越小,智能体越短视;γ 越接近 1,智能体越重视长期收益。一个经典例子是下棋:某个局面下立刻吃掉一个子奖励很大,但走完几步可能会丢掉更大的机会。如果 γ 设得太低,策略就会变得贪心,只看眼前的“吃子”而不顾后面“将军”。
在实际项目中,γ 常常是在 0.9 到 0.99 之间选。如果是有限步数的回合制任务,最后一步就结束,那么 γ 可以设成 1;如果是机器人连续控制这种无限时长的任务,通常需要设成一个小于 1 的数,一方面防止回报发散,另一方面也给算法一点“近视”的压力,让它在可控范围内快速做出反应。
3. 在 MDP 框架下,强化学习到底在解什么
3.1 策略、价值函数与最优策略
有了五元组,我们还需要一个“行为准则”,也就是策略。策略 π 告诉智能体在某个状态下应该怎么选动作。它可以是确定性的,也可以是一个概率分布。强化学习的目标就是找到那个能让累计回报期望最大化的策略,也就是最优策略 π*。
但直接搜索策略空间非常困难,所以大家会引入价值函数做中介。状态价值函数 V^π(s) 表示“从状态 s 出发,按照策略 π 继续走,得到的期望回报”。动作价值函数 Q^π(s, a) 则更进一步,表示“在状态 s 先执行动作 a,之后再按照策略 π 走,得到的期望回报”。
为什么价值函数有用?因为它把“组合爆炸”的未来变成了一张可以递归计算的表。你不需要把所有可能的轨迹全部列出来,只需要从当前状态出发,一层层往前看,价值函数会替你压缩掉大量重复信息。我自己在 debug 算法时,第一件事就是看价值函数是不是合理的。如果状态价值出现违反直观的数字,那大概率不是算法的问题,而是状态设计或奖励函数出了问题。
3.2 从 MDP 到最优性方程
价值函数之间有一种递归关系。最核心的想法是:当前状态的价值,等于当前奖励加上下一状态价值的折扣。对于最优策略,这个关系变成:
[ V^(s) = \max_{a \in A} \sum_{s'} P(s' \mid s, a) \left[ R(s, a, s') + \gamma V^(s') \right] ]
这个方程看起来复杂,实际上只干了一件事:把长远的期望回报拆成“眼前这一步 + 未来的最好情况”。它同时也是一个万能的求解引擎。你只要不断迭代这个方程,让每个状态的价值往右边更优的方向靠拢,最后就能收敛到最优价值函数,再从中恢复出最优策略。
我刚开始学时总觉得这是“数学课上的花架子”,直到自己动手写了一次值迭代,才真正明白为什么强化学习许多算法都是从这个方程演变来的。Q-learning 其实就是不知道转移概率 P 时的采样版最优性方程;策略迭代则是不断在当前价值估计下改进策略。这张“元素周期表”的核心,就是这一条递归关系。
3.3 已知环境与未知环境,解法完全不同
同一个 MDP,如果状态转移概率 P 和奖励函数 R 已知,你可以靠动态规划直接算,不需要和环境交互。比如迷宫如果地图完全已知,你离线就能算出每个格子的价值。但绝大多数真实问题没有这种待遇,机器人不知道地砖的摩擦系数,交易系统不知道行情涨跌的概率,这时候只能靠采样。
所以强化学习实际上是在处理“P 和 R 未知,或至少无法精确写出”的 MDP。常见的 Q-learning、策略梯度,都是这种未知环境下的经验求解方法。这也解释了为什么强化学习训练通常慢:它不是靠公式直接算答案,而是靠一遍遍试错去逼近同一个最优值函数。记住这一点,看到训练曲线抖成心电图的时候,你就不会太慌了。
4. 手把手拆一个例子:四宫格找宝藏
4.1 定义问题
理论讲多了容易晕,我带你做一个最小的例子。假设智能体处在一段走廊里,有三个格子,编号是 0、1、2。格子在右边,到达格子 2 代表成功。动作只有两个:向左走一格或向右走一格。走左边没有奖励,走进格子 2 得到 +1 奖励。为了简单,转移是确定性的:你说向右,就一定向右。
这样五元组就是:状态 S = {0, 1, 2},动作 A = {左, 右},转移概率非 0 即 1,奖励函数 R(1, 右, 2) = +1,其他情况都是 0,折扣因子 γ = 0.9。格子 2 是终点,不再产生任何价值。
这个例子小到可以手动算,但足以展示 MDP 的全部套路。
4.2 价值迭代的代码与执行过程
用一个最简单的值迭代就能求最优价值函数。初始时把所有状态价值都设成 0,然后反复套用最优性方程更新。
gamma = 0.9 V = [0, 0, 0] for _ in range(5): V_new = V[:] # 状态 0:向左留在 0,向右去 1 V_new[0] = max(gamma * V[0], gamma * V[1]) # 状态 1:向左去 0,向右到终点获得奖励 1 V_new[1] = max(gamma * V[0], 1 + gamma * V[2]) # 状态 2:终点,价值固定为 0 V_new[2] = 0 V = V_new print(V)跑出来的迭代过程大致是:
| 迭代次数 | 状态0价值 | 状态1价值 | 状态2价值 |
|---|---|---|---|
| 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 0 |
| 2 | 0.9 | 1 | 0 |
| 3 | 0.9 | 1 | 0 |
第一次迭代时,状态 1 发现向右走立刻拿到 +1,所以价值变成 1。第二次迭代,状态 0 发现可以先走到状态 1,再到终点,但中间隔一步,奖励被折扣一次,所以价值是 0.9。第三次开始价值不再变化,表示已经收敛。
4.3 结果解读
这个收敛结果说明,最优策略其实非常朴素:状态 0 向右走,状态 1 向右走。但价值函数告诉我们的信息更多。状态 1 的价值是 1,因为再走一步就能立即获得奖励;状态 0 的价值是 0.9,因为要多等一步,未来的 1 被 γ 折扣了一次。这就是折扣因子的直观含义:距离奖励越远,当前价值越低,但也不是完全忽略。
如果你把折扣因子改成 0.5,状态 0 的价值会变成 0.5。这就是为什么代理越“近视”,越不愿意为了远处的大奖励做铺垫。很多项目里调不好策略,不是算法不行,而是 γ 这个隐含假设跟任务目标不匹配。我的建议是:在动手跑深度强化学习之前,至少要把这种小例子亲手算几遍。它能帮你把符号和直觉对上。
5. 实际项目中用 MDP 会遇到的坑
5.1 状态设计不满足马尔可夫性
这是我在各种项目里见过最多的问题。很多人说“状态是当前画面”,于是直接把一帧图像扔给神经网络。如果任务本身是一局弹球游戏,光有当前帧确实不够,因为小球的速度信息没办法从单帧里看出来,至少需要前后两帧。这个问题在视觉决策里尤其明显。
解决思路有两个。第一,手动在状态里补上历史信息,比如把连续几帧叠在一起,或者加入速度、角速度这种衍生意。第二,用一个循环网络去把历史信息编码成内部状态。但无论选择哪一种,本质上都是在强行让状态重新满足马尔可夫性。记住这一点,能帮你省掉很多“加个 LSTM 试试”的无头苍蝇式调参。
5.2 转移概率建模的误区
有的任务可以精确建模,有的不能。比如一个库存管理模拟环境,你完全可以写出进货、销售、过期这些转移概率;但一个真人对话系统,你几乎不可能预测对方下一句说什么。面对后者,有些人还是硬着头皮搭一个不准确的模型,结果训练出来的策略只在错误模型里有效,一到真实场景就失效。
更稳妥的做法是:能建模的部分就建模,不能建模的部分用 model-free 方法去采样。把这两者分开,而不是混在一个 P 里。比如机器人控制里,刚体动力学好建模,但轮子打滑是一种无法完全确定的噪声,那就可以把确定模型作为模拟器,把打滑当作随机扰动采样。MDP 本身允许你用一个概率分布去描述不确定性,关键是要诚实地区分“已知规律”和“黑箱部分”。
5.3 奖励函数和折扣因子里的隐形偏好
很多人以为设奖励只是“加加减减”,实际它决定了智能体学习到的是不是你真正想要的行为。比如一个清理地面碎片的任务,如果只奖励“捡起一个碎片 +1”,智能体可能学会先抓取碎片但随后把它丢进墙角,因为奖励已经拿了。要缓解这种问题,你需要把奖励设置在真正想要的结果上,比如“碎片最终消失了才加 1”。
折扣因子同样藏着偏好。设得太小,智能体只顾眼前;设得太大,训练会很难收敛,因为远期的随机性太强。想要让智能体长时间规划,就别迷信 γ=0.99 一定好。我通常先观察任务的最佳步骤数:如果从开始到拿到奖励大概需要 10 步,那 0.9 就够用;如果需要几百步,再往 0.99、0.995 去调。这样至少有一个合理的起点。
6. 常见问题速查与经验总结
6.1 几个我经常被问到的问题
| 常见问题 | 我的回答 |
|---|---|
| MDP 和强化学习到底什么关系 | MDP 是数学框架,强化学习是解决未知 MDP 中策略优化问题的方法集合。 |
| 既然有值迭代,为什么还要用 RL | 值迭代和策略迭代要求已知转移概率 P 和奖励 R。现实中很多环境给不出精确 P,只能靠样本估计。 |
| 状态和观测有什么区别 | MDP 假设智能体能直接看到完整状态。如果只能看到部分甚至带噪声的观测,那就成了 POMDP,需要额外处理历史信息。 |
| 折扣因子是不是越大越好 | 不是。越大越重视长期,但训练方差越大、收敛越慢。根据任务有效步数来选更合理。 |
| 不知道转移概率时能做动态规划吗 | 不能直接做。可以先学习环境模型再做规划,或者直接用 model-free 算法采样逼近。 |
| 连续状态为什么也能叫 MDP | 状态集合 S 可以是连续空间,五元组依然成立,只是价值函数的表示和更新方式要换一种思路。 |
6.2 学 MDP 时最值得投入时间的地方
如果让我给一个学习优先级,我会把“手写一次值迭代”放在最前面。整个过程不超过五十行,但你会在里面看到价值是怎么从终点反推回起点,动作是怎么被比较的,收敛是怎么发生的。有了这些直觉,后面再看 DQN、PPO 这些复杂算法,你会发现它们的内核仍然是这个元素周期表。
第二部分值得投入时间的是状态设计。尽量找一个你熟悉的真实任务,把它写成一个五元组。哪怕只是“用手机导航去某个地点”,你也可以拆出当前位置、速度、动作、路况转移概率和到达奖励。这种练习比背公式有用得多,因为你会被迫思考“哪些信息必须进入状态”。
第三,是学会读训练曲线时回到 MDP 本身。曲线不涨,先别急着换网络结构,问问自己:奖励函数真的表达了目标吗?折扣因子和任务步数匹配吗?状态里有没有丢掉关键信息?大多数时候,问题都不是出在高级技巧上,而是出在这张元素周期表的某一个格子里。我自己踩过太多次这种坑,所以现在有个习惯:每次开始一个新的强化学习任务,第一件事就是打开一个空白文档,把 (S, A, P, R, γ) 一个一个写清楚。写完之后,算法怎么选反而成了相对简单的问题。巧合的是,这件事哪怕你只做过一次价值迭代,也会不由自主地一直做下去。