策略与价值函数:V函数、Q函数
一句话概述
策略(Policy)和价值函数(Value Function)是强化学习的双核心——策略回答"看到什么情况该做什么",价值函数回答"这个局面有多好"。V函数衡量一个状态的好坏,Q函数衡量在某个状态下做某个动作的好坏。理解了策略和价值函数,你就理解了强化学习算法在"优化什么"和"如何决策"。
💡 核心要点:①策略π(a|s)是智能体的"行为准则",从状态映射到动作概率;②状态价值函数V^π(s)评估从状态s开始按策略π行动的期望累积奖励;③动作价值函数Q^π(s,a)评估在状态s执行动作a后按策略π行动的期望累积奖励;④V和Q的关系:V^π(s)=Σ_a π(a|s)Q^π(s,a),Q^π(s,a)=R(s,a)+γΣ_{s'}P(s'|s,a)V^π(s')。
教学与演示
一、策略——智能体的"大脑"
是什么(定义):策略(Policy)π是一个从状态到动作的映射。确定性策略π(s)直接输出一个动作a;随机性策略π(a|s)输出在状态s下选择每个动作a的概率。策略是强化学习智能体的核心,学习的目标就是找到最优策略π*。
大白话 策略就是智能体的"条件反射"——看到红灯就停,看到绿灯就行。简单情况可以写成"如果...就..."的规则表,复杂情况(如自动驾驶)则需要一个神经网络来处理各种路况。
为什么(原理):策略是强化学习区别于监督学习的关键。在监督学习中,我们直接告诉模型"正确答案是什么";在强化学习中,我们只告诉智能体"做得好不好"(奖励),然后让智能体自己摸索出策略。策略可以是随机的——在博弈(石头剪刀布)、探索(需要尝试新动作)和对策(不让对手预测)中,随机策略至关重要。
怎么做(实现):
import numpy as np
# ==================== 策略的三种表示方式 ====================
# 方式1:表格策略(离散状态,离散动作)
# 适用于状态和动作都很少的情况
class TablePolicy:
"""用表格存储每个状态的动作概率分布"""
def __init__(self, n_states, n_actions):
# 初始化为均匀随机策略
self.probs = np.ones((n_states, n_actions)) / n_actions
def get_action(self, state):
"""根据策略选择动作"""
probs = self.probs[state] # 获取该状态的动作概率分布
return np.random.choice(len(probs), p=probs)
def update(self, state, action, value):
"""更新策略(如增加某个动作的概率)"""
self.probs[state][action] += value
self.probs[state] = np.abs(self.probs[state]) # 确保非负
self.probs[state] /= self.probs[state].sum() # 归一化
# 方式2:ε-greedy 策略(最常用的探索策略)
class EpsilonGreedyPolicy:
"""ε-greedy:以概率ε随机探索,以概率1-ε选择最优动作"""
def __init__(self, n_actions, epsilon=0.1):
self.n_actions = n_actions
self.epsilon = epsilon # 探索概率
self.q_values = {} # 存储状态-动作对的Q值
def get_action(self, state, q_values=None):
"""根据Q值和ε-greedy规则选择动作"""
if q_values is None:
q_values = self.q_values.get(state, np.zeros(self.n_actions))
if np.random.random() < self.epsilon:
# 探索:随机选择一个动作
return np.random.randint(self.n_actions)
else:
# 利用:选择Q值最大的动作
return np.argmax(q_values)
# 方式3:神经网络策略(连续状态空间)
# 实际中由深度学习框架(PyTorch/TensorFlow)实现
# 这里展示概念代码
class NeuralNetworkPolicy:
"""概念:用神经网络表示策略(实际实现需深度学习框架)"""
def __init__(self, input_dim, output_dim, hidden_dim=64):
"""神经网络参数(概念演示)"""
# 实际中:self.network = nn.Sequential(...)
self.input_dim = input_dim # 状态维度
self.output_dim = output_dim # 动作数量
self.hidden_dim = hidden_dim # 隐藏层大小
def get_action_probs(self, state):
"""概念:输入状态,输出动作概率分布"""
# 实际中:probs = self.network(state)
# 返回 shape=(n_actions,) 的概率分布
pass
# 演示表格策略
print("=== 表格策略演示 ===")
n_states, n_actions = 5, 3
policy = TablePolicy(n_states, n_actions)
print(f"初始均匀策略 - 状态0: {policy.probs[0]}")
# 演示ε-greedy策略
print("\n=== ε-greedy 策略演示 ===")
eg_policy = EpsilonGreedyPolicy(n_actions=3, epsilon=0.2)
# 假设Q值:动作0=1.0, 动作1=3.0, 动作2=2.0
q_vals = np.array([1.0, 3.0, 2.0])
# 模拟多次选择
np.random.seed(42)
actions_taken = [eg_policy.get_action(0, q_vals) for _ in range(100)]
unique, counts = np.unique(actions_taken, return_counts=True)
print(f"Q值: {q_vals}")
print(f"100次选择中:")
for a, c in zip(unique, counts):
print(f" 动作{a}: {c}次 ({c/100*100:.1f}%)")
print(f"最优动作(动作1)被选中的比例约80% (1-ε=0.8)")
print(f"其余动作各约10% (ε/2=0.1)")什么用(应用):策略是RL的最终产出。AlphaGo的策略网络输出361个落子概率;自动驾驶策略输出方向盘角度和油门大小;推荐系统策略输出每个物品的推荐概率。策略评估和改进是几乎所有RL算法的核心循环。
哪些坑(缺点):表格策略无法处理连续状态或大状态空间;随机策略增加了探索但可能降低短期表现;策略的泛化能力有限——一个环境中学到的策略难以迁移到其他环境。
二、状态价值函数V——衡量"局面好坏"
是什么(定义):状态价值函数V^π(s)表示在策略π下,从状态s开始,智能体按照策略π行动所能获得的期望累积折扣奖励。数学上:V^π(s) = E_π[G_t | S_t = s] = E_π[Σ_{k=0}^∞ γ^k R_{t+k+1} | S_t = s]。
大白话 V函数就像给每个局面"打分"——在围棋中,V(黑棋大优)很高,V(白棋大优)很低。它不考虑你下一步具体怎么走,只看"当前这个局面,按照你的水平继续下,最终能赢多少"。V函数回答的是"我现在处于什么位置"。
为什么(原理):V函数是策略评估的核心工具。有了V函数,我们可以比较不同状态的好坏,也可以比较不同策略——如果π'在所有状态上的V值都大于等于π,那么π'就是更好的策略。V函数也启发了"值迭代"的思想:不断更新V(s)使其逼近最优V*,从而提取最优策略。
怎么做(实现):
import numpy as np
# ==================== 策略评估:计算给定策略的价值函数 ====================
# 使用3x3网格世界,确定性转移
# 网格世界定义
n_states = 9
n_actions = 4
actions = [(-1, 0), (1, 0), (0, -1), (0, 1)] # 上、下、左、右
def step(state, action):
"""执行动作,返回 (next_state, reward)"""
row, col = state // 3, state % 3
dr, dc = actions[action]
nr = max(0, min(2, row + dr))
nc = max(0, min(2, col + dc))
next_state = nr * 3 + nc
if next_state == 8: r = 10.0
elif next_state == 7: r = -5.0
else: r = -0.1
return next_state, r
# 策略评估:迭代计算V^π(s)
def policy_evaluation(policy, gamma=0.9, theta=1e-6):
"""
给定策略π,迭代计算状态价值函数V^π(s)
使用贝尔曼期望方程:V(s) = Σ_a π(a|s) [R(s,a) + γ Σ_{s'} P(s'|s,a) V(s')]
"""
V = np.zeros(n_states)
while True:
delta = 0
V_old = V.copy()
for s in range(n_states):
if s == 8: # 终止状态
V[s] = 0
continue
# 计算期望值:Σ_a π(a|s) * Q(s,a)
expected_value = 0
for a in range(n_actions):
prob = policy[s][a] # 策略选择该动作的概率
next_s, r = step(s, a)
q_value = r + gamma * V_old[next_s]
expected_value += prob * q_value
V[s] = expected_value
delta = max(delta, abs(V[s] - V_old[s]))
if delta < theta:
break
return V
# 评估三种策略
# 策略1:随机策略(每个动作等概率)
random_policy = np.ones((n_states, n_actions)) / n_actions
# 策略2:优先向右,其次向下
greedy_policy = np.zeros((n_states, n_actions))
for s in range(n_states):
row, col = s // 3, s % 3
if col < 2:
greedy_policy[s][3] = 0.8 # 右:80%
greedy_policy[s][1] = 0.2 # 下:20%
elif row < 2:
greedy_policy[s][1] = 0.8 # 下:80%
greedy_policy[s][0] = 0.2 # 上:20%
else:
greedy_policy[s] = np.ones(4) / 4
V_random = policy_evaluation(random_policy)
V_greedy = policy_evaluation(greedy_policy)
print("策略评估结果对比(3x3网格):")
print("\n随机策略的V值:")
for i in range(3):
print(" " + " ".join(f"{V_random[i*3+j]:>7.2f}" for j in range(3)))
print("\n贪婪策略的V值:")
for i in range(3):
print(" " + " ".join(f"{V_greedy[i*3+j]:>7.2f}" for j in range(3)))
print(f"\n分析:贪婪策略在每个状态上的V值都高于随机策略,说明贪婪策略更好")
print(f"状态0(起点):V_random={V_random[0]:.2f}, V_greedy={V_greedy[0]:.2f}")
什么用(应用):V函数是策略评估的基础。在AlphaGo中,价值网络(Value Network)输出当前局面的胜率估计;在资产定价中,V函数可以表示投资组合的期望收益;在机器人控制中,V函数衡量从当前位置到达目标的可能性。
哪些坑(缺点):V函数依赖于策略——不同策略的V值不同,需要标明是V^π;V函数不直接告诉你该做什么动作(需要结合模型);在大状态空间中,必须用函数近似(神经网络)来估计V(s)。
三、动作价值函数Q——选择"最佳动作"
是什么(定义):动作价值函数Q^π(s,a)表示在策略π下,从状态s执行动作a后,后续按照策略π行动所能获得的期望累积折扣奖励。数学上:Q^π(s,a) = E_π[G_t | S_t = s, A_t = a] = E_π[Σ_{k=0}^∞ γ^k R_{t+k+1} | S_t = s, A_t = a]。
大白话 Q函数比V函数多了一个"第一动作"的信息——V(s)告诉你"到这个位置算好算坏",Q(s,a)告诉你"在这个位置做这个动作算好算坏"。Q函数直接告诉你该做什么:选Q值最大的动作就行!这也是为什么Q-learning如此流行——不需要知道环境模型,直接学Q函数就能做决策。
为什么(原理):Q函数的魅力在于——一旦你知道了最优Q函数Q*,你不需要知道环境转移概率,直接在每个状态选argmax_a Q*(s,a)就是最优策略。这被称为"无模型"(model-free)方法,因为它不需要环境模型。Q-learning、DQN等算法都是基于这个思想。
怎么做(实现):
import numpy as np
# ==================== Q函数计算与最优策略提取 ====================
# 使用3x3网格世界,确定性转移
n_states = 9
n_actions = 4
actions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
def step(state, action):
row, col = state // 3, state % 3
dr, dc = actions[action]
nr = max(0, min(2, row + dr))
nc = max(0, min(2, col + dc))
next_state = nr * 3 + nc
if next_state == 8: r = 10.0
elif next_state == 7: r = -5.0
else: r = -0.1
return next_state, r
# 计算最优Q函数(使用值迭代结果)
def compute_optimal_Q(gamma=0.9):
"""先计算最优V,再推导最优Q"""
# 值迭代计算最优V*
V = np.zeros(n_states)
theta = 1e-6
while True:
delta = 0
V_old = V.copy()
for s in range(n_states):
if s == 8: continue
action_values = []
for a in range(n_actions):
next_s, r = step(s, a)
action_values.append(r + gamma * V_old[next_s])
V[s] = max(action_values)
delta = max(delta, abs(V[s] - V_old[s]))
if delta < theta:
break
# 从V*计算Q*: Q*(s,a) = R(s,a) + γ * V*(s')
Q = np.zeros((n_states, n_actions))
for s in range(n_states):
if s == 8: continue
for a in range(n_actions):
next_s, r = step(s, a)
Q[s][a] = r + gamma * V[next_s]
return Q, V
Q_opt, V_opt = compute_optimal_Q()
action_names = ["上", "下", "左", "右"]
print("最优Q函数 Q*(s,a)(每个状态4个动作的Q值):")
for s in range(n_states):
if s == 8:
print(f" 状态{s} (目标): 终止状态")
continue
print(f" 状态{s} (位置 {s//3},{s%3}): ", end="")
for a in range(n_actions):
print(f"{action_names[a]}:{Q_opt[s][a]:>7.2f} ", end="")
best_action = np.argmax(Q_opt[s])
print(f"→ 最优: {action_names[best_action]}")
print(f"\n说明:对于每个状态,选择Q值最大的动作就是最优策略")
print(f"例如状态0:Q(上)={Q_opt[0][0]:.2f}, Q(下)={Q_opt[0][1]:.2f}, Q(左)={Q_opt[0][2]:.2f}, Q(右)={Q_opt[0][3]:.2f}")
print(f"最大Q值是右,所以最优动作是向右")
# 演示:从Q函数提取最优策略
print("\n从Q函数提取的最优策略(3x3网格):")
for i in range(3):
row = []
for j in range(3):
s = i * 3 + j
if s == 8:
row.append("目标")
elif s == 7:
row.append("陷阱")
else:
best_a = np.argmax(Q_opt[s])
row.append(action_names[best_a])
print(" " + " ".join(f"{a:>4}" for a in row))什么用(应用):Q函数是Q-learning、DQN、Double DQN等算法的核心。在Atari游戏中,DQN的Q网络输出每个动作的Q值,游戏AI直接选Q值最大的动作;在推荐系统中,Q(s,a)可以表示"在用户状态s下推荐物品a的长期价值";在机器人控制中,Q函数指导机器人在每个状态下选择最优动作。
哪些坑(缺点):Q函数比V函数多一个维度(动作空间),学习难度更大;当动作空间连续时,argmax操作变得困难(需要特殊的优化方法);Q函数的最大化操作可能引入"过估计偏差"(overestimation bias),这是Double DQN要解决的问题。
四、V与Q的关系——贝尔曼期望方程
是什么(定义):V函数和Q函数之间存在紧密的关系。V函数是Q函数按策略的加权平均:V^π(s) = Σ_a π(a|s) Q^π(s,a)。Q函数可以用V函数和奖励表示:Q^π(s,a) = R(s,a) + γ Σ_{s'} P(s'|s,a) V^π(s')。这两个关系合起来就是贝尔曼期望方程。
大白话 V和Q就像"班级平均分"和"某道题的得分"——V(s)是"在这个状态下,按你的水平做下去能得多少分"(平均),Q(s,a)是"在这个状态下做这个动作,后续按你的水平做下去能得多少分"(具体)。V是所有可能动作的Q的加权平均。
为什么(原理):V和Q的关系是强化学习算法设计的核心。Actor-Critic方法中,Actor(策略)用V函数来评估好坏,Critic(价值网络)输出V或Q值。优势函数A(s,a) = Q(s,a) - V(s)就是从Q中减去V得到"这个动作比平均好多少",广泛用于策略梯度方法。
怎么做(实现):
import numpy as np
# ==================== V与Q的相互转换 ====================
# 使用之前计算的Q_opt和V_opt
# 验证关系1:V(s) = Σ_a π(a|s) * Q(s,a)(确定性策略下 = max_a Q(s,a))
print("关系1验证:V(s) = max_a Q(s,a)(最优策略下)")
for s in range(n_states):
if s == 8: continue
max_q = np.max(Q_opt[s])
print(f" 状态{s}: V={V_opt[s]:.2f}, max_a Q={max_q:.2f}, 相等? {abs(V_opt[s]-max_q)<1e-6}")
# 验证关系2:Q(s,a) = R(s,a) + γ * V(s')
print("\n关系2验证:Q(s,a) = R(s,a) + γ * V(s')")
gamma = 0.9
for s in [0, 4]: # 验证几个状态
for a in range(n_actions):
next_s, r = step(s, a)
q_from_v = r + gamma * V_opt[next_s]
print(f" 状态{s},a={action_names[a]}: Q={Q_opt[s][a]:.2f}, R+γV={q_from_v:.2f}, 相等? {abs(Q_opt[s][a]-q_from_v)<1e-6}")
# ==================== 优势函数 A(s,a) = Q(s,a) - V(s) ====================
print("\n=== 优势函数 A(s,a) = Q(s,a) - V(s) ===")
print("优势函数衡量:'这个动作比平均好多少'")
print("A>0 表示该动作优于平均水平,A<0 表示劣于平均水平")
print("A=0 表示该动作正好是平均水平(即最优动作)")
for s in [0, 4]:
print(f"\n状态{s} (位置 {s//3},{s%3}):")
for a in range(n_actions):
advantage = Q_opt[s][a] - V_opt[s]
sign = "+" if advantage > 0 else ""
print(f" {action_names[a]}: A={sign}{advantage:.2f} ", end="")
if advantage > 0:
print("↑ 优于平均")
elif advantage < 0:
print("↓ 劣于平均")
else:
print(" 最优动作")
print(f"\n优势函数在策略梯度方法中被广泛使用,可以有效降低方差")什么用(应用):V-Q关系是设计Actor-Critic方法的基础。Critic用V或Q来评估,Actor利用优势函数A(s,a)来改进策略。在PPO算法中,优势函数的计算直接影响策略更新的方向和幅度;在A2C/A3C中,优势函数帮助降低梯度估计的方差,加速训练收敛。
哪些坑(缺点):V和Q的估计都有误差,两者相减会导致误差放大;需要同时维护V和Q的估计,增加了计算和存储开销;如果V或Q的估计不准确,优势函数也会不准确,误导策略更新。
五、最优价值函数——V和Q
是什么(定义):最优状态价值函数V*(s)是在所有可能策略中,状态s能获得的最大期望累积奖励:V*(s) = max_π V^π(s)。最优动作价值函数Q*(s,a)是在所有可能策略中,在状态s执行动作a能获得的最大期望累积奖励:Q*(s,a) = max_π Q^π(s,a)。
大白话 V和Q就是"上帝视角"下的最优评分——V*(s)告诉你"这个局面在最理想的操作下能得多少分",Q*(s,a)告诉你"这个局面下做这个动作,后续最理想操作能得多少分"。RL的目标就是让智能体学到的价值函数逼近V和Q。
为什么(原理):一旦知道Q*,最优策略就是π*(s) = argmax_a Q*(s,a)。这意味着——如果我们能精确学到Q*,就不需要显式维护策略,只需在每个状态选Q值最大的动作。这就是Q-learning和DQN的核心思想:通过与环境交互,逐步逼近Q*。
怎么做(实现):
import numpy as np
# ==================== 最优价值函数与策略改进 ====================
# 使用之前的网格世界,展示从任意策略改进到最优策略的过程
def get_optimal_V_Q(gamma=0.9):
"""计算最优V和Q"""
V = np.zeros(n_states)
theta = 1e-6
while True:
delta = 0
V_old = V.copy()
for s in range(n_states):
if s == 8: continue
action_values = []
for a in range(n_actions):
next_s, r = step(s, a)
action_values.append(r + gamma * V_old[next_s])
V[s] = max(action_values)
delta = max(delta, abs(V[s] - V_old[s]))
if delta < theta:
break
Q = np.zeros((n_states, n_actions))
for s in range(n_states):
if s == 8: continue
for a in range(n_actions):
next_s, r = step(s, a)
Q[s][a] = r + gamma * V[next_s]
return V, Q
V_opt, Q_opt = get_optimal_V_Q()
# 策略改进演示:从随机策略出发,每次贪心改进
print("=== 策略改进过程 ===")
# 初始策略:全随机
policy = np.ones((n_states, n_actions)) / n_actions
for iteration in range(5):
# 策略评估:计算当前策略的V值
V = policy_evaluation(policy, gamma=0.9)
# 策略改进:贪心选择Q值最大的动作
improved = False
for s in range(n_states):
if s == 8: continue
old_best = np.argmax(policy[s])
new_best = np.argmax(Q_opt[s])
if old_best != new_best:
improved = True
# 更新为确定性策略(指向最优动作)
policy[s] = np.zeros(n_actions)
policy[s][new_best] = 1.0
# 检查是否已收敛到最优
is_optimal = True
for s in range(n_states):
if s == 8: continue
if abs(V[s] - V_opt[s]) > 1e-6:
is_optimal = False
break
print(f"第{iteration+1}轮改进: V(0)={V[0]:.2f}, "
f"与V*(0)={V_opt[0]:.2f}的差距={abs(V[0]-V_opt[0]):.4f}, "
f"已收敛? {is_optimal}")
if is_optimal:
break
print(f"\n策略迭代收敛后,V(0)={V[0]:.2f} = V*(0)={V_opt[0]:.2f}")
print("说明:策略迭代通过反复评估和改进策略,最终收敛到最优策略")什么用(应用):最优价值函数是RL的理论目标。Q-learning直接学习Q的近似,DQN用神经网络逼近Q,AlphaGo的价值网络输出V*的近似。理解最优价值函数能帮助你判断算法是否收敛、学习是否有效。
哪些坑(缺点):V和Q是理论上的存在,实际中几乎不可能精确得到(除非状态空间很小);函数近似(神经网络)只能逼近最优价值函数,存在逼近误差;Q*的学习可能不稳定——因为Q-learning的更新目标本身也在变化(移动目标问题)。
六、实战:用策略评估比较不同策略的优劣
是什么(定义):本节将策略评估和策略改进结合起来,在一个完整的MDP环境中比较多种策略的优劣,并展示如何通过策略改进逐步逼近最优策略。这是理解"策略"和"价值函数"关系的最佳实践。
大白话 我们来当一回"策略裁判"——给几个不同的策略打分(计算V值),看看哪个策略更好,然后通过贪心改进把一个烂策略逐步变成好策略。这就像看着一个笨手笨脚的机器人通过不断"反思和调整"变成高手的过程。
怎么做(实现):
import numpy as np
# ==================== 完整策略比较与改进 ====================
# 使用5x5的更大网格世界
N = 5
n_states = N * N
n_actions = 4
actions = [(-1, 0), (1, 0), (0, -1), (0, 1)]
action_names = ["上", "下", "左", "右"]
def step_big(state, action):
"""5x5网格世界的转移函数"""
row, col = state // N, state % N
dr, dc = actions[action]
nr = max(0, min(N-1, row + dr))
nc = max(0, min(N-1, col + dc))
next_state = nr * N + nc
# 目标在右下角(24),陷阱在(23)
if next_state == N*N-1: r = 50.0
elif next_state == N*N-2: r = -20.0
else: r = -0.1
return next_state, r
# 定义三种不同的策略
# 策略A:随机策略
policy_random = np.ones((n_states, n_actions)) / n_actions
# 策略B:总是向右
policy_right = np.zeros((n_states, n_actions))
for s in range(n_states):
policy_right[s][3] = 1.0 # 总是右
# 策略C:总是向下
policy_down = np.zeros((n_states, n_actions))
for s in range(n_states):
policy_down[s][1] = 1.0 # 总是下
# 策略评估函数
def evaluate_policy(policy, gamma=0.95, max_iter=1000):
V = np.zeros(n_states)
for _ in range(max_iter):
delta = 0
V_old = V.copy()
for s in range(n_states):
if s == N*N-1: continue
expected = 0
for a in range(n_actions):
prob = policy[s][a]
next_s, r = step_big(s, a)
expected += prob * (r + gamma * V_old[next_s])
V[s] = expected
delta = max(delta, abs(V[s] - V_old[s]))
if delta < 1e-6:
break
return V
# 评估所有策略
print("=== 5x5网格世界策略比较 ===")
print("目标:右下角(24),陷阱:右下角左边(23)")
print()
V_random = evaluate_policy(policy_random)
V_right = evaluate_policy(policy_right)
V_down = evaluate_policy(policy_down)
# 打印起点(0)的价值
print(f"起点(0,0)的价值对比:")
print(f" 随机策略 V(0) = {V_random[0]:.2f}")
print(f" 总是向右 V(0) = {V_right[0]:.2f}")
print(f" 总是向下 V(0) = {V_down[0]:.2f}")
# 找出最佳策略
policies = {"随机": V_random, "总是向右": V_right, "总是向下": V_down}
best = max(policies, key=lambda k: policies[k][0])
print(f"\n最佳策略是: {best}")
# 策略改进:从随机策略开始,贪心改进
print("\n=== 策略改进:从随机到最优 ===")
current_policy = policy_random.copy()
for iteration in range(10):
V = evaluate_policy(current_policy, gamma=0.95)
# 贪心改进
improved = False
for s in range(n_states):
if s == N*N-1: continue
# 计算每个动作的Q值
q_values = []
for a in range(n_actions):
next_s, r = step_big(s, a)
q_values.append(r + 0.95 * V[next_s])
best_a = np.argmax(q_values)
if np.argmax(current_policy[s]) != best_a:
improved = True
current_policy[s] = np.zeros(n_actions)
current_policy[s][best_a] = 1.0
print(f" 第{iteration+1}轮: V(0)={V[0]:.2f}, 有改进? {improved}")
if not improved:
print(f" 策略已收敛到最优!")
break
print(f"\n结论:策略迭代通过反复评估和改进,最终找到最优策略")什么用(应用):策略评估和改进是RL的核心循环。在实际应用中,我们通常用神经网络来近似V和Q函数,用梯度下降来更新策略参数,但核心思想与本节展示的表格方法完全一致。理解了这个循环,就理解了所有RL算法的工作方式。
哪些坑(缺点):表格方法只能处理小状态空间;策略评估在大状态空间下计算量巨大;贪心改进可能陷入局部最优(在确定性环境中不会,但在函数近似中可能);需要足够多的迭代才能收敛。
概念关系图谱
| 概念 | 上位概念 | 核心思想 | 关键公式/方法 | RL应用场景 |
|---|---|---|---|---|
| 策略π | 决策函数 | 状态到动作的映射 | π(a | s) |
| 状态价值V^π | 价值函数 | 状态的好坏程度 | V^π(s)=E_π[G_t | S_t=s] |
| 动作价值Q^π | 价值函数 | 状态-动作对的好坏 | Q^π(s,a)=E_π[G_t | S_t=s,A_t=a] |
| 最优价值V* | 最优性 | 所有策略中状态的最大价值 | V*(s)=max_π V^π(s) | 理论目标 |
| 最优Q值Q* | 最优性 | 所有策略中动作的最大价值 | Q*(s,a)=max_π Q^π(s,a) | 最优策略提取 |
| 优势函数A | 相对价值 | 动作比平均好多少 | A(s,a)=Q(s,a)-V(s) | 策略梯度 |
| 策略评估 | 算法步骤 | 计算给定策略的价值函数 | 贝尔曼期望方程 | 评估策略好坏 |
| 策略改进 | 算法步骤 | 贪心更新策略 | π'(s)=argmax_a Q^π(s,a) | 改进策略 |
| ε-greedy | 探索策略 | 以ε概率随机探索 | 随机动作 vs 最优动作 | 探索-利用平衡 |
重点答疑
Q1: V函数和Q函数到底有什么区别?什么时候用哪个?
V函数告诉你"站在这个位置好不好",Q函数告诉你"在这个位置做这个动作好不好"。关键区别:V不需要知道具体动作,Q需要。
- 如果只需要评价局面(如围棋的形势判断),用V函数就够了。
- 如果需要选择动作(如控制机器人),Q函数更直接——选Q值最大的动作。
- 在实际算法中,Q-learning系(DQN)直接用Q函数,Actor-Critic系通常用V函数(或优势函数)配合策略。
解答:V衡量"位置",Q衡量"动作"。V像地图上的海拔,Q像每一步的得分。能直接选动作时用Q,只需评估时用V。
Q2: 为什么策略评估需要多次迭代?不能一次算出V吗?
从数学上讲,贝尔曼期望方程是一组线性方程,理论上可以一次求解(矩阵求逆)。但在强化学习中,我们通常用迭代法(动态规划)来求解,原因包括:
- 状态空间太大时,矩阵求逆的计算复杂度是O(n³),n是状态数,不现实。
- 迭代法每次只更新V(s),计算复杂度O(n²),更高效。
- 迭代法可以随时停止,得到近似解,这在工程上很有用。
- 无模型方法(如TD学习)天然就是迭代的,与动态规划的思想一致。
解答:理论上可以一次求解,但实践中迭代法更高效、更灵活,且与RL的核心思想一致。
Q3: 最优价值函数V和Q是唯一的吗?最优策略呢?
V和Q是唯一的——对于给定的MDP,最优价值函数只有一个。但最优策略可能不唯一。例如,在网格世界中,如果有两条长度相同的路径通往目标,那么两条路径上的动作都是最优的(Q值相同)。这种情况下,任意选择其中一个动作都是最优策略。
解答:V和Q是唯一的,但最优策略可能不唯一。当多个动作的Q*值相同时,选哪个都是最优的。
Q4: 优势函数A(s,a)为什么有用?它和Q(s,a)有什么区别?
优势函数A(s,a) = Q(s,a) - V(s)衡量的是"这个动作比平均水平好多少"。它的核心优势在于:
- 降低方差:在策略梯度方法中,用A代替Q可以显著降低梯度估计的方差,让训练更稳定。
- 归一化:A(s,a)以V(s)为基准,正值表示"好于平均",负值表示"差于平均",更容易解释。
- 避免偏差:Q(s,a)同时包含"状态本身的好坏"和"动作的好坏",A(s,a)剥离了状态的影响,只关注动作的贡献。
解答:A(s,a) = Q(s,a) - V(s),它剥离了状态本身好坏的影响,只衡量"这个动作比平均好多少"。在PPO等算法中,优势函数是策略更新的关键信号。
Q5: ε-greedy策略中,ε应该怎么设置?
ε的设置取决于任务阶段和需求:
- 训练初期:ε较大(如0.5~1.0),鼓励探索以收集多样化的经验。
- 训练中期:ε逐渐衰减(如从1.0线性衰减到0.1),逐步从探索转向利用。
- 训练后期:ε较小(如0.01~0.05),主要利用已学到的知识,保留少量探索。
- 评估时:ε=0,完全利用,评估策略的真实表现。
解答:ε从大到小逐渐衰减是最常见的做法。但要注意,ε衰减过快可能导致探索不足,衰减过慢则训练效率低。
Q6: 策略迭代和值迭代与V函数、Q函数有什么关系?
策略迭代隐式使用V函数和Q函数:
- 策略评估阶段:用贝尔曼期望方程计算V^π。
- 策略改进阶段:贪心选择Q值最大的动作(Q值从V值推导)。
- 核心是:V用于评估,Q用于改进。
值迭代直接使用V函数:
- 每次更新:V(s) ← max_a [R(s,a) + γ Σ_{s'} P(s'|s,a) V(s')]
- 这个更新中隐式包含了"对所有动作求Q值然后取max"。
- 核心是:用max操作同时完成评估和改进。
解答:策略迭代显式地交替使用V和Q,值迭代在V的更新中隐式地包含了Q的max操作。
章节单词汇总
| 英文 | 音标 | 中文 |
|---|---|---|
| policy | /ˈpɑːləsi/ | 策略 |
| value function | /ˈvæljuː ˈfʌŋkʃn/ | 价值函数 |
| state value function | /steɪt ˈvæljuː ˈfʌŋkʃn/ | 状态价值函数 |
| action value function | /ˈækʃn ˈvæljuː ˈfʌŋkʃn/ | 动作价值函数 |
| Q-function | /kjuː ˈfʌŋkʃn/ | Q函数 |
| optimal value | /ˈɑːptɪməl ˈvæljuː/ | 最优价值 |
| advantage function | /ədˈvæntɪdʒ ˈfʌŋkʃn/ | 优势函数 |
| policy evaluation | /ˈpɑːləsi ɪˌvæljuˈeɪʃn/ | 策略评估 |
| policy improvement | /ˈpɑːləsi ɪmˈpruːvmənt/ | 策略改进 |
| greedy policy | /ˈɡriːdi ˈpɑːləsi/ | 贪婪策略 |
| epsilon-greedy | /ˈepsɪlɒn ˈɡriːdi/ | ε-贪婪 |
| deterministic | /dɪˌtɜːrmɪˈnɪstɪk/ | 确定性的 |
| stochastic | /stəˈkæstɪk/ | 随机的 |
| expectation | /ˌekspekˈteɪʃn/ | 期望 |
| weighted average | /ˈweɪtɪd ˈævərɪdʒ/ | 加权平均 |
| convergence | /kənˈvɜːrdʒəns/ | 收敛 |
| baseline | /ˈbeɪslaɪn/ | 基线 |
| approximation | /əˌprɑːksɪˈmeɪʃn/ | 近似 |
面试练习
Q1 [单选] 以下关于V函数和Q函数的说法,正确的是?
- A. V(s) = Q(s,a) 对所有a成立
- B. Q(s,a) = max_a V(s)
- C. V(s) = Σ_a π(a|s) Q(s,a)
- D. V(s)和Q(s,a)没有关系
解答:V(s)是Q(s,a)按策略概率的加权平均,即V(s)=Σ_a π(a|s)Q(s,a)。A错误,V和Q通常不相等。B错误,Q(s,a)和V(s')的关系需要通过贝尔曼方程。D错误,V和Q有明确的数学关系。
Q2 [单选] 如果已知最优Q函数Q*,最优策略如何确定?
- A. 选Q*(s,a)最小的动作
- B. 选Q*(s,a)最大的动作
- C. 按Q*(s,a)概率采样
- D. 随机选择动作
解答:最优策略就是选Q值最大的动作:π*(s) = argmax_a Q*(s,a)。这正是无模型方法(Q-learning、DQN)的核心思想——不需要知道环境模型,只需要Q*就能做最优决策。
Q3 [多选] 以下关于策略的说法,哪些是正确的?
- A. 确定性策略输出一个确定的动作
- B. 随机策略输出动作的概率分布
- C. 随机策略总是比确定性策略好
- D. 在博弈中,随机策略可以防止被对手预测
解答:A正确,确定性策略π(s)=a。B正确,随机策略π(a|s)输出概率分布。C错误,随机策略不一定更好——在确定性环境中,最优策略往往是确定性的。D正确,石头剪刀布如果用确定性策略(总是出石头),对手会轻易击败你。
Q4 [单选] 优势函数A(s,a) = Q(s,a) - V(s)的含义是什么?
- A. 状态s本身的价值
- B. 动作a比状态s的平均水平好多少
- C. 动作a的绝对价值
- D. 状态s的折扣价值
解答:优势函数A(s,a)=Q(s,a)-V(s)衡量的是"动作a比平均水平好多少"。V(s)是状态s下所有动作的平均价值,Q(s,a)是特定动作a的价值,两者之差就是该动作的"优势"。
Q5 [多选] 策略评估的作用包括哪些?
- A. 衡量当前策略的好坏
- B. 为策略改进提供依据
- C. 直接生成最优策略
- D. 比较不同策略的优劣
解答:A正确,V^π(s)越高说明策略越好。B正确,策略改进需要知道每个动作的Q值(从V值推导),才知道该改进哪个动作。C错误,策略评估只评估策略,不改进策略。D正确,比较不同策略的V值可以判断哪个策略更好。
Q6 [单选] 在ε-greedy策略中,ε=0.1的含义是什么?
- A. 90%概率随机选择动作
- B. 10%概率随机探索,90%概率选择最优动作
- C. 所有动作概率相同
- D. 10%概率选择最优动作
解答:ε=0.1表示探索概率10%,利用概率90%。即:10%的时间随机选择一个动作(探索),90%的时间选择Q值最大的动作(利用)。
Q7 [单选] 以下哪个不是价值函数的性质?
- A. V^π(s)依赖于策略π
- B. V*(s) ≥ V^π(s) 对任意π和s成立
- C. V^π(s) = V*(s) 对任意π成立
- D. V函数满足贝尔曼方程
解答:C错误,V^π(s)通常不等于V*(s),除非π本身就是最优策略。A正确,不同策略对应不同的V^π。B正确,V*是所有策略中最大的。D正确,V函数满足贝尔曼期望方程。
Q8 [多选] 以下哪些是函数近似(神经网络)相比表格方法表示价值函数的优势?
- A. 可以处理连续状态空间
- B. 可以泛化到未见过的状态
- C. 总能精确表示最优价值函数
- D. 存储需求不随状态数量线性增长
解答:A正确,神经网络可以处理连续输入。B正确,函数近似有泛化能力——相似状态有相似的价值。C错误,神经网络只能近似,存在逼近误差。D正确,神经网络参数数量固定,不随状态数增长。
Q9 [单选] 在策略迭代中,策略改进步骤使用的是什么信息?
- A. 仅使用V函数
- B. 使用从V函数推导出的Q值
- C. 仅使用奖励函数
- D. 使用随机探索
解答:策略改进步骤贪心地选择Q值最大的动作。Q值通过贝尔曼关系从V函数推导:Q(s,a) = R(s,a) + γ Σ_{s'} P(s'|s,a) V(s')。然后π'(s) = argmax_a Q(s,a)。
Q10 [多选] 以下关于V和Q的说法,哪些是正确的?
- A. V和Q对于给定的MDP是唯一的
- B. 最优策略一定唯一
- C. Q已知后,最优策略就是argmax Q
- D. V和Q满足贝尔曼最优方程
解答:A正确,最优价值函数唯一。B错误,最优策略可能不唯一(多个动作Q值相同)。C正确,argmax Q就是最优策略。D正确,V和Q*都满足贝尔曼最优方程。