4、价值函数与策略:状态价值函数V(s)、动作价值函数Q(s,a)、策略梯度
好,咱们今天聊点硬核的。价值函数和策略,这俩东西是强化学习的核心骨架。说白了,你训练一个智能体,最终目的就是找到一套好的策略——也就是在什么状态下该做什么动作。而价值函数,就是用来评估这套策略好不好的工具。
我个人习惯把价值函数比作「导航仪」,策略比作「方向盘」。导航仪告诉你这条路走下去能赚多少钱,方向盘决定你具体怎么打。两者缺一不可。
4.1 状态价值函数 V(s)
先看状态价值函数 V(s)。它的定义很简单:从状态 s 出发,按照某个策略 π 走下去,能获得的期望累积回报。
数学上写出来就是:
Vπ(s) = Eπ[ Gt | St = s ]
其中 Gt 是从 t 时刻开始的折扣累积奖励。嗯,这里要注意,V(s) 是依赖于策略 π 的。策略不同,同一个状态的价值可能天差地别。
我在项目中遇到过一个问题:刚开始做资产配置时,我直接用 V(s) 来选状态,结果发现市场震荡期和趋势期的状态价值完全没法直接比较。后来我才意识到,V(s) 必须结合策略来看,不能孤立地评估状态好坏。
核心理解: V(s) 回答的是「我现在这个位置,按当前策略走下去,到底能赚多少?」
举个例子。假设你手里有100万现金,市场处于低估值状态。如果你的策略是「低估时加仓」,那这个状态的价值就很高;如果你的策略是「永远不动」,那这个状态的价值就是0。你看,同一个状态,价值完全取决于策略。
4.2 动作价值函数 Q(s,a)
接下来是动作价值函数 Q(s,a)。它比 V(s) 多了一个维度——不仅考虑状态,还考虑具体动作。
定义也很直观:在状态 s 下执行动作 a,之后按照策略 π 走下去,能获得的期望累积回报。
Qπ(s,a) = Eπ[ Gt | St = s, At = a ]
你想想看,V(s) 和 Q(s,a) 之间有什么关系?其实很简单:
Vπ(s) = Σa π(a|s) * Qπ(s,a)
也就是说,状态价值等于所有动作价值的加权平均,权重就是策略给出的概率。
我的经验: 在实际做资产配置时,Q(s,a) 比 V(s) 更实用。因为你要做决策,必须知道每个具体动作(比如加仓、减仓、调仓)的预期收益。V(s) 更多是用来做评估和对比的。
我曾经踩过一个坑:直接用 Q 值最大的动作来执行,结果发现 Q 值估计有偏差,导致连续亏损。后来我加了双 Q 网络(Double DQN),才把这个问题解决掉。嗯,这个后面会细讲。
4.3 策略梯度
好,前面两个是评估工具,现在聊聊怎么优化策略本身。策略梯度(Policy Gradient)就是干这个的。
传统方法(比如 Q-learning)是先学 Q 函数,再从 Q 函数推导出策略。但策略梯度直接对策略参数 θ 求梯度,沿着梯度上升方向更新策略。
目标函数很简单:
J(θ) = Eπθ[ Gt ]
梯度公式是:
∇θ J(θ) = Eπθ[ ∇θ log πθ(a|s) * Gt ]
这个公式看着有点抽象,我解释一下。它的意思是:如果某个动作带来的回报 Gt 是正的,那就增加这个动作的概率;如果是负的,就减少。说白了就是「好的多干,坏的少干」。
注意: 策略梯度有一个大问题——方差高。因为 Gt 本身波动很大,导致梯度更新不稳定。我在做回测时,经常看到策略收益曲线像过山车一样。后来用了「优势函数」来替代 Gt,才把方差降下来。
4.4 三者关系与实战选择
这三者的关系,我用一张图来展示:
在实际的资产配置项目中,我一般这样选:
- 离散动作空间(比如加仓、减仓、不动):用 Q(s,a) 为主,V(s) 辅助评估
- 连续动作空间(比如仓位比例0到1):用策略梯度,配合优势函数降低方差
- 混合场景:Actor-Critic 架构,Actor 用策略梯度,Critic 用 Q 函数
避坑指南: 我曾经在回测中直接用策略梯度做资产配置,结果因为方差太大,策略每轮都在剧烈波动。后来我加了「基线函数」(baseline),用 V(s) 作为基线,把梯度公式改成 ∇θ log π * (Q - V),效果立马稳定了。这个技巧叫「优势函数」,后面会详细讲。
4.5 代码示例:简单策略梯度
最后给个简单的策略梯度实现,帮你理解核心逻辑:
import numpy as np
class PolicyGradient:
def __init__(self, state_dim, action_dim, lr=0.01):
self.theta = np.random.randn(state_dim, action_dim) * 0.01
self.lr = lr
def get_action(self, state):
# 计算动作概率
logits = state @ self.theta
probs = np.exp(logits) / np.sum(np.exp(logits))
# 采样动作
return np.random.choice(len(probs), p=probs)
def update(self, states, actions, rewards):
# 计算梯度
grad = np.zeros_like(self.theta)
for s, a, r in zip(states, actions, rewards):
logits = s @ self.theta
probs = np.exp(logits) / np.sum(np.exp(logits))
# ∇log π = one_hot(a) - probs
grad += np.outer(s, (np.eye(len(probs))[a] - probs)) * r
# 梯度上升
self.theta += self.lr * grad / len(states)
这段代码虽然简单,但核心思想都在里面了。你想想看,每次更新都是「回报高的动作概率增加,回报低的概率减少」。这就是策略梯度的本质。
嗯,今天就聊到这儿。价值函数和策略是强化学习的基石,理解透了后面学 Actor-Critic、PPO 都会轻松很多。