策略与价值函数: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^{\pi}(s) = \mathbb{E}_{\pi}\left[G_t \mid S_t = s\right] = \mathbb{E}_{\pi}\left[\sum_{k=0}^{\infty} \gamma^k R_{t+k+1} \;\middle|\; S_t = s\right]\)

什么用(应用):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^{\pi}(s, a) = \mathbb{E}_{\pi}\left[G_t \mid S_t = s, A_t = a\right] = \mathbb{E}_{\pi}\left[\sum_{k=0}^{\infty} \gamma^k R_{t+k+1} \;\middle|\; S_t = s, A_t = a\right]\)

什么用(应用):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的贝尔曼关系\(V^{\pi}(s) = \sum_{a \in \mathcal{A}} \pi(a \mid s) \cdot Q^{\pi}(s, a)\)

什么用(应用):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("说明:策略迭代通过反复评估和改进策略,最终收敛到最优策略")
最优价值函数\(V^{*}(s) = \max_{\pi} V^{\pi}(s), \quad Q^{*}(s, a) = \max_{\pi} Q^{\pi}(s, a)\)

什么用(应用):最优价值函数是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应用场景
策略π决策函数状态到动作的映射π(as)
状态价值V^π价值函数状态的好坏程度V^π(s)=E_π[G_tS_t=s]
动作价值Q^π价值函数状态-动作对的好坏Q^π(s,a)=E_π[G_tS_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吗?

从数学上讲,贝尔曼期望方程是一组线性方程,理论上可以一次求解(矩阵求逆)。但在强化学习中,我们通常用迭代法(动态规划)来求解,原因包括:

  1. 状态空间太大时,矩阵求逆的计算复杂度是O(n³),n是状态数,不现实。
  2. 迭代法每次只更新V(s),计算复杂度O(n²),更高效。
  3. 迭代法可以随时停止,得到近似解,这在工程上很有用。
  4. 无模型方法(如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)衡量的是"这个动作比平均水平好多少"。它的核心优势在于:

  1. 降低方差:在策略梯度方法中,用A代替Q可以显著降低梯度估计的方差,让训练更稳定。
  2. 归一化:A(s,a)以V(s)为基准,正值表示"好于平均",负值表示"差于平均",更容易解释。
  3. 避免偏差: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*都满足贝尔曼最优方程。