策略表示方法:从表格到神经网络

大家好,我是你们这门课的老朋友。今天咱们聊聊策略搜索里最基础、也最绕不开的一个话题——策略到底该怎么表示?

说白了,策略就是一个映射:你给我一个状态,我告诉你该做什么动作。但怎么存这个映射,学问可就大了。我刚开始接触强化学习时,觉得这还不简单?拿个表格记下来不就完了?后来才发现,现实世界哪有那么温柔。

确定性策略 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) ]

别被公式吓到。说白了就是:

  1. 采样一条轨迹,得到状态 s、动作 a、奖励 r
  2. 计算 Q(s,a) —— 这个动作到底有多好
  3. 计算 ∇log π(a|s,θ) —— 参数往哪个方向调,能增加这个动作的概率
  4. 把两者乘起来,梯度更新

代码实现:

# 伪代码,实际项目中会用自动微分
for state, action, reward in trajectory:
    prob = policy_network(state)[action]  # 当前策略下该动作的概率
    gradient = log(prob) * reward         # 策略梯度
    optimizer.step(gradient)              # 更新参数

避坑指南:我曾经在计算梯度时忘了加 log,直接用了 prob * reward。结果梯度爆炸,策略直接崩了。记住,一定是 log 概率,不是概率本身。

知识体系总览

下面这张图帮你理清本章的核心逻辑:

策略表示方法知识体系 策略表示方法 确定性 vs 随机性 基于表格 基于函数 线性函数 神经网络 策略参数化与梯度 核心:用参数 θ 表示策略,通过梯度上升优化

嗯,这张图把今天的内容串起来了。从左到右,从上到下,你看到的是策略表示方法从简单到复杂、从离散到连续的演进路径。

我个人觉得,理解策略表示是入门策略搜索最关键的一步。表格法让你理解本质,函数法让你应对现实,参数化让你学会优化。这三块打通了,后面的策略梯度、Actor-Critic 都是水到渠成的事。

记住一句话:策略表示决定了你能解决什么问题,策略优化决定了你能解决得多好

本章小结

  • 确定性策略:一个状态对应一个动作
  • 随机性策略:一个状态对应动作的概率分布
  • 表格表示:简单直观,但状态空间有限
  • 函数表示:线性函数可解释,神经网络表达力强
  • 策略参数化:用 θ 表示策略,通过梯度上升优化

公众号:蓝海资料掘金营,微信deep3321