策略表示方法:从表格到神经网络
大家好,我是你们这门课的老朋友。今天咱们聊聊策略搜索里最基础、也最绕不开的一个话题——策略到底该怎么表示?
说白了,策略就是一个映射:你给我一个状态,我告诉你该做什么动作。但怎么存这个映射,学问可就大了。我刚开始接触强化学习时,觉得这还不简单?拿个表格记下来不就完了?后来才发现,现实世界哪有那么温柔。
确定性策略 vs 随机性策略
先看两种最基本的策略类型。
确定性策略:给定状态 s,输出唯一的动作 a。公式写出来就是:
a = π(s)
比如你玩俄罗斯方块,当前方块是长条,底部有空隙——确定性策略会说:「直接旋转,插进去。」没有第二种选择。
随机性策略:给定状态 s,输出一个动作的概率分布:
π(a|s) = P(A=a | S=s)
还是俄罗斯方块的例子。随机性策略可能会说:「有 80% 的概率旋转插入,20% 的概率先移到最右边再说。」
为什么需要随机性?
我踩过这个坑。早期做机器人抓取时用了确定性策略,结果每次遇到同一个零件,机械臂都走一模一样的轨迹。一旦轨迹上有障碍物没建模,就撞上了。随机性策略能探索更多可能性,这在训练阶段尤其重要。
我的经验:训练初期用随机性策略,收敛后逐渐退火成确定性策略。这个技巧在很多项目中都管用。
基于表格的策略表示
这是最直观的方法。状态空间有限且不大时,直接拿一张表存:
| 状态 | 动作 | 概率/值 |
|---|---|---|
| s₁ | a₁ | 0.7 |
| s₁ | a₂ | 0.3 |
| s₂ | a₁ | 1.0 |
代码实现也很简单:
# 确定性策略表
policy_table = {
'state_1': 'action_left',
'state_2': 'action_right',
'state_3': 'action_up'
}
# 随机性策略表
stochastic_policy = {
'state_1': {'action_left': 0.7, 'action_right': 0.3},
'state_2': {'action_up': 0.5, 'action_down': 0.5}
}
注意:表格法有个致命问题——状态一多就炸了。围棋的状态数比宇宙原子还多,你拿什么表去存?我曾经天真地想用表格法做自动驾驶,结果状态维度一上来,内存直接爆了。
基于函数的策略表示
既然表格不行,那就用函数来近似。函数的好处是:你不需要记住每个状态,只需要记住函数的参数。
线性函数
最简单的函数形式:
π(s) = θᵀ · φ(s)
其中 φ(s) 是状态的特征向量,θ 是参数。比如在 CartPole 游戏中,状态是位置、速度、角度、角速度,你可以把这些特征加权求和,得到动作的概率。
线性函数的好处是简单、可解释。我做过一个工业控制项目,客户要求每个决策都能解释为什么。线性策略就很好办——把权重拿出来一看,哦,原来「角度偏差」的权重最大,说明系统最在意平衡。
但线性函数的表达能力有限。遇到非线性关系,它就抓瞎了。
神经网络
这时候就该神经网络上场了。一个简单的策略网络:
import torch
import torch.nn as nn
class PolicyNetwork(nn.Module):
def __init__(self, state_dim, action_dim, hidden_dim=128):
super().__init__()
self.net = nn.Sequential(
nn.Linear(state_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, hidden_dim),
nn.ReLU(),
nn.Linear(hidden_dim, action_dim),
nn.Softmax(dim=-1) # 输出概率分布
)
def forward(self, state):
return self.net(state)
你看,输入状态,经过两层隐藏层,最后用 Softmax 输出每个动作的概率。这就是一个典型的随机性策略网络。
为什么用 Softmax?
因为我们要输出概率分布。Softmax 能把任意实数映射成 [0,1] 之间的值,并且所有动作的概率加起来等于 1。如果你想要确定性策略,最后一层去掉 Softmax,直接取 argmax 就行。
策略参数化与梯度
好了,现在策略有了参数 θ(不管是线性函数的权重,还是神经网络的权重),怎么优化它?
核心思想很简单:让好动作的概率变大,坏动作的概率变小。
数学上,我们定义目标函数 J(θ) 为期望累积奖励。策略梯度定理告诉我们:
∇J(θ) = E[ ∇log π(a|s, θ) · Q(s, a) ]
别被公式吓到。说白了就是:
- 采样一条轨迹,得到状态 s、动作 a、奖励 r
- 计算 Q(s,a) —— 这个动作到底有多好
- 计算 ∇log π(a|s,θ) —— 参数往哪个方向调,能增加这个动作的概率
- 把两者乘起来,梯度更新
代码实现:
# 伪代码,实际项目中会用自动微分
for state, action, reward in trajectory:
prob = policy_network(state)[action] # 当前策略下该动作的概率
gradient = log(prob) * reward # 策略梯度
optimizer.step(gradient) # 更新参数
避坑指南:我曾经在计算梯度时忘了加 log,直接用了 prob * reward。结果梯度爆炸,策略直接崩了。记住,一定是 log 概率,不是概率本身。
知识体系总览
下面这张图帮你理清本章的核心逻辑:
嗯,这张图把今天的内容串起来了。从左到右,从上到下,你看到的是策略表示方法从简单到复杂、从离散到连续的演进路径。
我个人觉得,理解策略表示是入门策略搜索最关键的一步。表格法让你理解本质,函数法让你应对现实,参数化让你学会优化。这三块打通了,后面的策略梯度、Actor-Critic 都是水到渠成的事。
记住一句话:策略表示决定了你能解决什么问题,策略优化决定了你能解决得多好。
本章小结:
- 确定性策略:一个状态对应一个动作
- 随机性策略:一个状态对应动作的概率分布
- 表格表示:简单直观,但状态空间有限
- 函数表示:线性函数可解释,神经网络表达力强
- 策略参数化:用 θ 表示策略,通过梯度上升优化
公众号:蓝海资料掘金营,微信deep3321