# Lecture 11 · 博弈 II：TD 学习与同时博弈

> **CS221: Artificial Intelligence — Principles and Techniques** · Stanford · Autumn 2025
> 📅 Oct 27 · 💻 [`td_learning.py`](https://github.com/stanford-cs221/autumn2025-lectures/blob/main/td_learning.py) · [`simultaneous_games.py`](https://github.com/stanford-cs221/autumn2025-lectures/blob/main/simultaneous_games.py)

---

## 从手工启发式到自我对弈

**上一讲（[[Lecture 10 · 博弈 I：Minimax 与 α-β 剪枝]]）**：我们把两人零和博弈形式化为游戏树，用 minimax / expectimax / expectiminimax 三种递归给局面定价；为了对付指数级的树，引入了两个加速手段——**α-β 剪枝**（精确，只跳过不可能影响答案的子树）与**评估函数 + 深度受限搜索**（近似，用先验知识给中间局面打分）。遗留问题：评估函数是**人手工写的启发式**（子力分 + 位置分 + 机动性……），既费人力又难以超越设计者的棋理。

**本讲（博弈 II）**分成两大块：

- **第一部分（TD 学习）**：能不能把评估函数**学**出来？用强化学习估计状态价值 $V_\pi(s)$，并让程序**自我对弈（self-play）**自己生成训练数据、自己变强——这条路从 Samuel 跳棋通向 TD-Gammon 与 AlphaGo。
- **第二部分（同时博弈）**：放开"回合制"假设，研究双方**同时**出手的博弈（石头剪刀布、two-finger Morra）。游戏树失效，引出**混合策略**、**minimax 定理**与**纳什均衡**。

> [!note]
> 两部分共享「博弈」这个主题，但技术上几乎独立：第一部分是「学习 + 回合制博弈」（承接 [[Lecture 8 · 强化学习]] 与 [[Lecture 9 · 函数逼近与策略梯度]]），第二部分是「同时博弈的博弈论」。分开读即可。

---

# 第一部分 · TD 学习：学习评估函数

## 1. 动机：为什么要「学」评估函数？

### 1.1 回顾：minimax 与评估函数

上一讲的核心是 **minimax**：己方取 $\max$，对手取 $\min$，在游戏树上递归。游戏树太深无法走到底，于是在某个深度**截断**，用**评估函数** $\mathrm{Eval}(s)$ 估计当前局面的好坏。

```mermaid
graph TD
    A["s（轮到 agent）"] -->|"max_a"| B["s'（轮到对手）"]
    B -->|"min_b"| C["s''"]
    C -.->|"深度耗尽"| E["评估函数<br/>Eval(s)"]

    style A fill:#c8e6c9,stroke:#2e7d32
    style B fill:#ffcdd2,stroke:#c62828
    style E fill:#ffe0b2,stroke:#e65100
```

**问题**：$\mathrm{Eval}(s)$ 一直是**人手工设计的启发式**（如国际象棋的「子力价值 + 棋子位置」）。手工设计有两个硬伤：需要深厚的领域知识（换一个游戏就得重来），而且天花板就是设计者自己的理解。能不能让机器自己**学**出这个评估函数？

### 1.2 关键类比：TD 学习 : $V_\pi$ :: SARSA : $Q_\pi$

这是理解本讲第一部分的钥匙。先把 [[Lecture 8 · 强化学习]] 的两个价值函数摆出来：

| 记号 | 含义 |
| :--- | :--- |
| $V_\pi(s)$ | 从状态 $s$ 出发、此后遵循策略 $\pi$ 的期望效用（**状态**有多好） |
| $Q_\pi(s, a)$ | 在 $s$ 先执行动作 $a$、此后遵循 $\pi$ 的期望效用（**动作**有多好） |

L8 里的 **SARSA** 用自举（bootstrapping）估计 $Q_\pi(s, a)$。本讲的 **TD 学习（temporal difference learning，时序差分学习）** 用同样的思路估计 $V_\pi(s)$：

> [!note] 核心类比
> $$\text{TD learning} : V_\pi \;::\; \text{SARSA} : Q_\pi$$
> SARSA 告诉你「每个**动作**有多好」；TD 学习告诉你「每个**状态**有多好」。评估函数要回答的恰恰是后者——"这个局面值多少分"。

### 1.3 只知道 $V_\pi(s)$，如何读出策略？

有了 Q 值，读出更好的策略很自然（**策略改进 policy improvement**）：

$$\pi_{\text{new}}(s) = \arg\max_a Q_\pi(s, a)$$

那如果**只有** $V_\pi(s)$ 呢？回顾 MDP 里 $V$ 与 $Q$ 的关系：

$$V_\pi(s) = Q_\pi(s, \pi(s)),\qquad Q_\pi(s, a) = \sum_{s'} T(s, a, s')\,\big[R(s, a, s') + \gamma\, V_\pi(s')\big]$$

其中 $T(s,a,s')$ 是转移概率，$R(s,a,s')$ 是即时奖励，$\gamma$ 是折扣因子。代入即得从 $V$ 读出策略的公式：

$$\pi_{\text{new}}(s) = \arg\max_a \sum_{s'} T(s, a, s')\,\big[R(s, a, s') + \gamma\, V_\pi(s')\big]$$

> [!warning] 易错点
> 这一步**需要知道 MDP**（转移 $T$、奖励 $R$）！因为要「往前看一步」，把每个动作展开成后继分布才能比较。SARSA 用 Q 值读策略时不需要模型（Q 已经替你把"往前看一步"折进去了），而 TD 学习用 V 值时必须借助模型做这步 $\arg\max$。这是「估计 V」比「估计 Q」便宜（少一个动作维度）所付出的代价。

**但在博弈里，我们恰好知道 $T$ 和 $R$！**——游戏规则完全已知。而且博弈的「动作 → 下一状态」是**确定性**的（我落一子，棋盘状态就唯一确定），上式大幅简化：

$$\pi_{\text{new}}(s) = \arg\max_a V_\pi\big(\mathrm{Succ}(s, a)\big)$$

其中 $\mathrm{Succ}(s, a)$ 是在 $s$ 执行动作 $a$ 后**确定**到达的后继状态。**只要知道每个后继局面有多好，就能直接选出最好的一步。** 这正是「学评估函数」的意义：学到的 $V_\pi$ 就是一个可以直接用来下棋的 $\mathrm{Eval}$。

### 1.4 为什么用 RL，而不是价值迭代？

一个自然的反问：

> 「既然博弈里我们已经**知道** MDP（规则完全已知），为什么不直接用**价值迭代**求解，非要用强化学习？」

**答案**：因为状态数是**指数级**的，价值迭代根本存不下、算不动。

- 国际象棋约 $10^{45}$ 个局面，围棋约 $10^{170}$ 个；
- 价值迭代要为**每个状态**存一个 $V(s)$ 并反复全表扫描——在这种规模下不可能。

> [!tip] 直觉
> 这是一个重要的视角转变。[[Lecture 8 · 强化学习]] 用 RL 是因为 MDP **未知**（转移/奖励是黑盒，只能靠试）；本讲用 RL **不是**因为未知，而是因为**状态空间太大**——必须用**函数逼近** $V(s; \mathbf{w})$ 把天文数字个状态压缩进一组参数里，并且只从**采样到的经验**（实际下出来的对局）学习，而不是遍历所有状态。同一个算法，两种完全不同的使用理由。

```mermaid
flowchart LR
    A["博弈 MDP<br/>规则已知"] --> B{"状态数?"}
    B -->|"少"| C["价值迭代<br/>逐状态精确解"]
    B -->|"指数级<br/>(棋类)"| D["强化学习<br/>+ 函数逼近 V(s;w)"]

    style C fill:#e3f2fd,stroke:#1976d2
    style D fill:#c8e6c9,stroke:#2e7d32
```

---

## 2. TD 学习算法

### 2.1 函数逼近：价值网络

不再为每个状态存表，而是用**带参数的函数**逼近价值：

$$V_\pi(s) \approx V(s; \mathbf{w})$$

其中 $\mathbf{w}$ 是待学习的权重向量。这与 [[Lecture 9 · 函数逼近与策略梯度]] 里 Q-learning 的函数逼近是同一招，只是套在 $V$ 上。

> [!note]
> 在深度强化学习里，$V(s; \mathbf{w})$ 就叫**价值网络（value network）**。它可以是线性的 $\phi(s) \cdot \mathbf{w}$（$\phi(s)$ 为特征向量），也可以是一个 MLP / 深度网络。AlphaGo 论文里的 value network 就是这个对象。

### 2.2 核心思路：自举 + 平方损失 + 梯度步

TD 学习从一条条**经验** $(s, a, r, s')$（当前状态、动作、即时奖励、下一状态）中在线更新权重 $\mathbf{w}$，五步一循环：

1. 拿到一段经验 $(s, a, r, s')$；
2. 模型**预测**：$V(s; \mathbf{w})$；
3. 构造**自举目标（bootstrap target）**：$r + \gamma\, V(s'; \mathbf{w})$；
4. **平方损失**：$$\mathcal{L}(\mathbf{w}) = \Big(V(s; \mathbf{w}) - \big(r + \gamma\, V(s'; \mathbf{w})\big)\Big)^2$$
5. **梯度步**：$\mathbf{w} \leftarrow \mathbf{w} - \alpha\, \nabla_{\mathbf{w}} \mathcal{L}(\mathbf{w})$，其中 $\alpha$ 是学习率。

**直觉**：让「当前状态的预测」向「即时奖励 + 下一状态的（估计）价值」靠拢。目标里用到了 $V$ 自己（$V(s')$），这就是**自举**——用一个估计去改进另一个估计，与 L7 策略评估、L8 SARSA 一脉相承。两者的差 $$\delta = r + \gamma\, V(s'; \mathbf{w}) - V(s; \mathbf{w})$$ 称为 **TD 误差（TD error）**：$\delta > 0$ 说明实际比预期好（上调 $V(s)$），$\delta < 0$ 说明比预期差（下调）。

> [!warning] 易错点
> 求梯度时，目标 $r + \gamma V(s'; \mathbf{w})$ 中的 $\mathbf{w}$ **按惯例视为常数**（不对它求导），只对预测项 $V(s;\mathbf{w})$ 求导——这叫**半梯度（semi-gradient）**更新。线性情形下更新有干净的形式：$\mathbf{w} \leftarrow \mathbf{w} + \alpha\,\delta\,\phi(s)$。表格版是它的特例（$\phi$ 为 one-hot）：$V(s) \leftarrow V(s) + \alpha\,\delta$。

对比 L8 的无模型算法家族，TD 学习填上了「估计 V」这一格：

| 算法 | 估计对象 | 自举目标 | 读策略是否需模型 |
| :--- | :---: | :--- | :---: |
| **SARSA** | $Q_\pi$ | $r + \gamma\, Q(s', a')$ | 否 |
| Q-Learning | $Q^*$ | $r + \gamma \max_{a'} Q(s', a')$ | 否 |
| **TD 学习** | $V_\pi$ | $r + \gamma\, V(s')$ | **是** |

> [!tip] 直觉
> TD 学习和 SARSA 一样是 **on-policy** 的：它估计的是「当前这套策略走下去」的价值，目标里只用到实际走出的下一状态 $s'$，不去看其他动作。这正合博弈的用法——我们要评估的就是"照当前棋力下完这盘"的胜率，然后再用它改进棋力，循环往复。

### 2.3 源码：`TDLearning` 类

以下是 `td_learning.py` 中的真实实现（加了中文注释）。注意它复用了 L8 的 `RLAlgorithm` 接口（`get_action` + `incorporate_feedback`）。这里为了在小 MDP 上演示，`V` 用的是 `defaultdict`（表格版）；把它换成 $V(s;\mathbf{w})$ 就是函数逼近版。

```python
class TDLearning(RLAlgorithm):
    """实现 TD 学习算法。"""
    def __init__(self, mdp: MDP, exploration_policy: Policy,
                 epsilon: float, discount: float, learning_rate: float):
        self.mdp = mdp                              # 需要 MDP 来读出策略！
        self.exploration_policy = exploration_policy
        self.epsilon = epsilon                      # ε-贪婪探索
        self.discount = discount                    # 折扣 γ
        self.learning_rate = learning_rate          # 学习率 α
        self.V = defaultdict(float)                 # 状态价值 V_π(s)

    def get_action(self, state: Any) -> Any:
        """用 MDP 从 V_π(s) 计算 Q_π(s, a)，再 ε-贪婪选动作。"""
        if np.random.random() < self.epsilon:
            return self.exploration_policy(state)   # 探索
        else:
            return self.pi(state)                   # 利用

    def pi(self, state: Any) -> Any:
        """返回当前 V_π(s) 对应的策略：argmax_a V(Succ(s,a))。"""
        # 为每个动作计算 Q 值（唯一用到 MDP 知识的地方）
        q_values = {}  # action -> Q 值
        for action, successors in get_action_successors(self.mdp, state).items():
            q_values[action] = sum(
                succ.prob * (succ.reward + self.discount * self.V[succ.state])
                for succ in successors
            )
        # 选 Q 值最大的动作
        return max(q_values.keys(), key=lambda action: q_values[action])

    def incorporate_feedback(self, state: Any, action: Any, reward: Any,
                             next_state: Any, is_end: bool) -> None:
        """根据经验 (s, a, r, s') 更新 V_π(s)。"""
        predicted = self.V[state]                                # 预测
        target = reward + self.discount * self.V[next_state]     # 自举目标
        self.V[state] += self.learning_rate * (target - predicted)  # 梯度步
```

> [!note]
> 看 `incorporate_feedback` 的最后一行：$V(s) \leftarrow V(s) + \alpha\,(\text{target} - \text{predicted})$，括号里正是 TD 误差 $\delta$。这是平方损失对表格项 $V(s)$ 求导后的**随机梯度下降**——和 L8 里 SARSA 更新 Q 的形式一模一样，只是把 $Q(s,a)$ 换成了 $V(s)$。另外注意 `pi` 方法：`self.mdp` 只在**读策略**时用到，更新 `V` 本身不需要模型。

### 2.4 在 flaky tram 上跑一遍

沿用 [[Lecture 7 · 马尔可夫决策过程]] 的**不可靠电车 MDP**（`FlakyTramMDP`：走路确定 +1 站、坐电车翻倍但有概率故障）喂一条轨迹，观察 `V` 被逐条经验推着更新：

```python
mdp = FlakyTramMDP(num_locs=6, failure_prob=0.1)
policy = partial(walk_tram_policy, 6)
# 注意：TDLearning 需要 mdp 来计算策略（做 policy improvement）
rl = TDLearning(mdp=mdp, exploration_policy=policy,
                epsilon=0.2, discount=1, learning_rate=0.1)

rl.get_action(state=1)
rl.incorporate_feedback(state=1, action="walk", reward=-1, next_state=2, is_end=False)
rl.get_action(state=2)
rl.incorporate_feedback(state=2, action="walk", reward=-1, next_state=3, is_end=False)
rl.get_action(state=3)
rl.incorporate_feedback(state=3, action="tram", reward=-2, next_state=6, is_end=True)
```

每条 `incorporate_feedback` 都把 $V(s)$ 朝 $r + \gamma V(s')$ 挪一小步（步长 $\alpha=0.1$）。跑足够多轨迹后，$V$ 收敛到当前探索策略的 $V_\pi$。

**小结（TD 学习）**：从经验 $(s, a, r, s')$ 估计 $V_\pi(s)$；**on-policy**（只沿当前策略实际走出的转移学习）；用**自举**（目标含 $V(s')$）；读出策略时需要模型（博弈中天然满足）。

---

## 3. 把 TD 学习用到博弈上

### 3.1 从任意 MDP 到博弈

TD 学习对**任意 MDP** 都成立。适配到两人零和博弈只需注意三点：$\mathrm{Succ}(s, a)$ **确定性**地刻画状态转移（落子即定）；游戏中途**没有奖励**，只有终局才有效用（赢 $+1$ / 输 $-1$，且通常 $\gamma = 1$）——所以价值信号要靠 TD 更新从终局一步步"倒灌"回中盘与开局；有**两个玩家**（agent 与 opponent），需要说明对手从哪来——这就是自我对弈。

### 3.2 自我对弈（self-play）

关键技巧：**双方共用同一个价值函数** $V_\pi(s)$，但取向相反——agent 挑价值最大的后继，对手挑价值最小的后继：

$$\pi_{\text{agent}}(s) = \arg\max_a V_\pi\big(\mathrm{Succ}(s, a)\big),\qquad \pi_{\text{opp}}(s) = \arg\min_a V_\pi\big(\mathrm{Succ}(s, a)\big)$$

零和博弈里这不浪费——一个 $V$（站在 agent 视角）同时刻画了双方的利害，对手的"最好"就是它的"最小"。

```mermaid
flowchart LR
    V["共享价值函数<br/>V(s; w)"] --> AG["π_agent = argmax<br/>Succ(s,a)"]
    V --> OP["π_opp = argmin<br/>Succ(s,a)"]
    AG -->|"对弈产生经验"| EXP["(s, a, r, s')"]
    OP -->|"对弈产生经验"| EXP
    EXP -->|"TD 更新 w"| V

    style V fill:#ffe0b2,stroke:#e65100
    style AG fill:#c8e6c9,stroke:#2e7d32
    style OP fill:#ffcdd2,stroke:#c62828
    style EXP fill:#e1f5fe,stroke:#0277bd
```

> [!tip] 直觉
> **自我对弈**：程序左右手互搏，用同一个 $V$ 既当自己又当对手。对弈产生经验，经验用来 TD 更新 $V$，更强的 $V$ 又产生更强的对弈——正反馈循环让棋力螺旋上升。妙处有二：① **不需要人类对局数据**，训练数据无限自产；② 对手强度始终与自己**匹配**（永远棋逢对手），课程难度自动递增。这是 TD-Gammon 与 AlphaGo Zero 的共同灵魂，也与 CS336 里 LLM 的 RLVR 训练（[[Lecture 16 · 对齐 II：RLVR]]）遥相呼应——都是"自己生成数据、按结果信号改进自己"。

### 3.3 例子：西洋双陆棋（Backgammon）

双陆棋是带**随机性**（掷骰子）的双人博弈。rollout 时策略与骰子交替出场：

$$\pi_{\text{dice}} \to \pi_{\text{agent}} \to \pi_{\text{dice}} \to \pi_{\text{opp}} \to \pi_{\text{dice}} \to \pi_{\text{agent}} \to \cdots$$

我们要学的是 $\pi_{\text{agent}}$ 和 $\pi_{\text{opp}}$（同一个 $V$ 的两副面孔），而 $\pi_{\text{dice}}$（骰子）是**固定的随机环境**，不用学。这正是上一讲 expectiminimax 场景（[[Lecture 10 · 博弈 I：Minimax 与 α-β 剪枝]] §2.4）的学习版。

**参数化价值函数**：先为每个局面定义特征向量 $\phi(s)$（如各点位上双方棋子的数量），再定义

$$\text{线性：}\; V(s; \mathbf{w}) = \phi(s) \cdot \mathbf{w}\qquad\text{或 MLP：}\; V(s; \mathbf{w}) = \mathrm{MLP}_{\mathbf{w}}\big(\phi(s)\big)$$

然后**直接套用 §2 的 TD 学习**即可——算法一行不用改。

---

## 4. 历史里程碑

TD 学习 + 自我对弈是 AI 博弈史上最漂亮的一条线。从 Samuel 到 AlphaGo Zero 的趋势非常清晰：人手工注入的**领域知识越来越少**（特征越来越「笨」，从精心设计的棋理特征退化到几乎原始的棋盘编码），而**自我对弈 + 神经网络**承担的比重越来越大。

| 系统 | 特征 | 评估函数 | 中途奖励 | 训练 |
| :--- | :--- | :--- | :---: | :--- |
| **Samuel 跳棋** (1959) | 精心设计的特征 | 线性 | 有 | 自我对弈 + α-β 剪枝，达业余水平（IBM 701，约 9K 内存） |
| **TD-Gammon** (1992) | 「笨」特征（近乎原始棋盘编码） | 神经网络 | 无 | 自我对弈约 100 万局，达人类专家水平 |
| **AlphaGo Zero** (2017) | 「笨」特征（棋子位置） | 深度网络 | 无 | 自我对弈约 490 万局 + MCTS，击败 AlphaGo（后者 2016 年胜李世石） |

> [!note]
> 三个补充："机器学习（machine learning）"这个词正是 Samuel 在 1959 年那篇跳棋论文里创造的；TD-Gammon 甚至给人类玩家带来了全新的**开局理论**——机器反过来教会了人类；AlphaGo Zero 在价值网络之外还引入了策略网络与**蒙特卡洛树搜索（MCTS）**，用搜索增强学习信号，但"自我对弈 + 学出来的评估"这条主线与 TD-Gammon 一脉相承。

---

# 第二部分 · 同时博弈

## 5. 从回合制到同时出手

上一讲的博弈都是**回合制（turn-based）**：一方走完另一方再走，所以可以画出游戏树、逐层交替取 $\max$ / $\min$。

现在换成**同时博弈（simultaneous games）**：两名玩家**同一时刻**出手，谁也看不到对方这一步。**例子**：石头剪刀布、two-finger Morra（两指莫拉）。

> [!warning] 易错点
> 游戏树**失效**了！树结构隐含"后走的人看得见先走的人做了什么"——每个节点都以到达它的历史为条件。同时博弈里没有"先后"，无法再用「我走这步之后对手最优应对」的方式递归——双方的决策相互纠缠、互为条件。需要一套新的解概念。

**灵魂拷问（课上 Poll）**：如果你**公开自己的策略**，还能打得同样好吗？直觉说不行——石头剪刀布里固定出石头（纯策略）一旦被知道，对手立刻用布克制。但本部分的高潮（§8.4）会证明：只要允许**混合策略**，公开你的最优策略**一点也不吃亏**。

本部分结构：先零和（§6–§8），再非零和（§9）。

---

## 6. 单步同时博弈：定义

以 **two-finger Morra** 为例：两名玩家 A、B 同时伸出 1 根或 2 根手指。

> [!note] 定义：单步同时博弈（single-move simultaneous game）
> - 两名玩家 A 和 B；
> - **收益矩阵（payoff matrix）** $V(a, b)$：对每个动作对 $(a, b)$ 给出一个数；
> - **零和**：A 的效用是 $V(a, b)$，B 的效用是 $-V(a, b)$；
> - 注意：**没有状态、没有序列**，一人只出一个动作（单步）。这是最小可研究单元，却已足够呈现同时博弈的全部核心现象。

Morra 的收益矩阵（行是 A 的动作，列是 B 的动作，数值是 A 的收益）：

| A ＼ B | B 出 1 | B 出 2 |
| :---: | :---: | :---: |
| **A 出 1** | +2 | −3 |
| **A 出 2** | −3 | +4 |

```python
actions = [1, 2]
V = {
    1: {1: 2, 2: -3},
    2: {1: -3, 2: 4},
}
```

**直觉**：A 想和 B 出**一样多**的手指（对角线为正），且偏爱凑成总和 4（右下的 +4 最大）；B 则相反，想让手指数**错开**（反对角线上 A 拿 −3，即 B 拿 +3）。

---

## 7. 纯策略 vs 混合策略

> [!note] 定义：策略
> - **纯策略（pure strategy）**：确定性地出某个单一动作 $a$；
> - **混合策略（mixed strategy）**：动作上的**概率分布** $\pi(a)$，每次按分布随机抽一个动作。纯策略是混合策略把全部概率压在一个动作上的特例。

Morra 里的几个策略：

```python
always_one = {1: 1.0}          # π = [1, 0]      总出 1
always_two = {2: 1.0}          # π = [0, 1]      总出 2
uniform    = {1: 0.5, 2: 0.5}  # π = [0.5, 0.5]  五五开
```

**博弈评估（game evaluation）**：给定双方（混合）策略，A 的期望收益是

$$V(\pi_A, \pi_B) = \sum_a \sum_b \pi_A(a)\, \pi_B(b)\, V(a, b)$$

即对所有动作组合 $(a,b)$，按两人独立随机选中它的概率 $\pi_A(a)\pi_B(b)$ 加权求和。源码里就是一个双重循环：

```python
def evaluate_game(V, policy_a, policy_b):
    """计算博弈的期望效用。"""
    value = 0
    for a, prob_a in policy_a.items():
        for b, prob_b in policy_b.items():
            value += prob_a * prob_b * V[a][b]
    return value
```

> [!example]
> `evaluate_game(V, uniform, uniform)`：四个格子各占 $0.25$，$0.25 \times (2 - 3 - 3 + 4) = 0$——双方都五五开时博弈值为 0，看似"公平"。但下面会看到，这**不是**均衡：双方都还有更好的选择，而真正的均衡值并不是 0。

---

## 8. minimax 定理

### 8.1 同时最优的困境与「先走者劣势」

博弈值 $V(\pi_A, \pi_B)$：A 想**最大化**、B 想**最小化**，而且要**同时**决定——像十字路口两车对峙，互相等对方先动，谁也不敢先动（deadlock）。

**破局思路**：既然"同时"难分析，干脆**让一方先亮出策略**、另一方看到后再应对，把问题变回有先后的序贯决策；然后比较"A 先亮"与"B 先亮"两种次序的结果。

**先看纯策略**：若 A 被迫先亮出纯策略，B 看到后必能针对性克制——Morra 里 A 亮 `always_one`，B 出 2，A 拿 $-3$；A 亮 `always_two`，B 出 1，A 还是拿 $-3$。结论：

> [!warning] 纯策略下的先走者劣势
> **后走者不吃亏，甚至占便宜**（the second player is no worse off）。先亮出纯策略等于暴露全部信息，被对手精确克制——这似乎印证了"策略必须保密"的直觉。

### 8.2 引入混合策略：后走者的最优应对

现在让 A 先亮出一个**混合策略**，比如 $\pi_A = [0.5, 0.5]$，看 B 如何最优应对。把博弈值按 B 的两个纯动作展开：

$$V(\pi_A, \pi_B) = \pi_B(1)\underbrace{\big[0.5(2) + 0.5(-3)\big]}_{-0.5} + \pi_B(2)\underbrace{\big[0.5(-3) + 0.5(4)\big]}_{+0.5} = -0.5\,\pi_B(1) + 0.5\,\pi_B(2)$$

B 想最小化 → 把全部概率压到系数更小的动作上：$\pi_B(1) = 1$，A 拿 $-0.5$。注意这已经比亮纯策略的 $-3$ 好多了——**随机化本身就在保护你**。

> [!tip] 直觉
> 关键观察：**后走的玩家总可以用纯策略应对**。因为博弈值对 $\pi_B$ 是**线性**的（固定 $\pi_A$ 后，它是 $\pi_B$ 各分量的加权和），线性函数在单纯形上的最小值必在**顶点**（某个纯动作）取到——混合不会更优。这一步把"对手的最优应对"从无穷维搜索压缩成了有限枚举。

一般地，设 A 先亮 $\pi_A = [p,\, 1-p]$，B 分别用两个纯动作应对时 A 的收益是：

$$\text{B 出 1}:\; 2p - 3(1-p) = 5p - 3,\qquad \text{B 出 2}:\; -3p + 4(1-p) = 4 - 7p$$

B 取两者的**最小值**（下包络），A 再对 $p$ 取最大（下包络的最高点）——这就是「A 先走」的 $\max\min$ 值。反过来让 B 先亮 $\pi_B$，同理得「B 先走」的 $\min\max$ 值。

### 8.3 minimax 定理：先后手价值相等

神奇之处：让 A 先亮和让 B 先亮，算出来的博弈值**相等**！

> [!note] minimax 定理（von Neumann, 1928）
> 对任意二人零和博弈（有限动作集），只要允许**混合策略**：
> $$\max_{\pi_A} \min_{\pi_B} V(\pi_A, \pi_B) = \min_{\pi_B} \max_{\pi_A} V(\pi_A, \pi_B)$$
> 交换 $\max$ / $\min$ 的顺序**不改变**博弈值。先手劣势**消失了**——这个共同的值称为**博弈值（value of the game）**。
> - **证明**：线性规划**对偶性（LP duality）**——"A 先走"和"B 先走"恰好是一对互为对偶的 LP；
> - **算法**：最优混合策略可用**线性规划**求解（两动作情形可像下面一样手算）。

```mermaid
graph LR
    subgraph 纯策略
    P1["先走者暴露<br/>→ 劣势"]
    end
    subgraph 混合策略
    M1["max min = min max<br/>先后手等价"]
    end
    P1 -->|"允许随机化"| M1

    style P1 fill:#ffcdd2,stroke:#c62828
    style M1 fill:#c8e6c9,stroke:#2e7d32
```

> [!example] 手算 Morra 的最优混合策略与博弈值
> A 亮 $[p, 1-p]$ 后，B 的两个纯应对给 A 的收益分别是 $5p-3$ 与 $4-7p$。A 要最大化两者的最小值；最优点在两条直线**相交**处（否则总可以往低的一侧挪一点 $p$ 换取提升）：
> $$5p - 3 = 4 - 7p \;\Longrightarrow\; 12p = 7 \;\Longrightarrow\; p = \tfrac{7}{12}$$
> 代回得博弈值 $5 \cdot \tfrac{7}{12} - 3 = -\tfrac{1}{12}$。由对称的推导，B 的最优混合策略同样是 $[\tfrac{7}{12}, \tfrac{5}{12}]$。
> $$\pi_A^* = \pi_B^* = \Big[\tfrac{7}{12},\; \tfrac{5}{12}\Big],\qquad V(\pi_A^*, \pi_B^*) = -\tfrac{1}{12}$$
> 注意博弈值是**负**的：two-finger Morra 看似对称，其实**对 B（求错开的一方）有利**——A 每局平均要亏 $\tfrac{1}{12}$。"双方五五开时值为 0"只是假象，因为五五开不是均衡。

```python
V = { 1: {1: 2, 2: -3},
      2: {1: -3, 2: 4} }
pi_opt = {1: 7/12, 2: 5/12}                  # A、B 的最优混合策略相同
value  = evaluate_game(V, pi_opt, pi_opt)    # = -1/12 ≈ -0.083
```

### 8.4 Upshot：公开最优混合策略也不吃亏

> [!note] 结论
> **公开你的最优混合策略，不会让你变差**（revealing your optimal mixed strategy doesn't hurt you）。

这正好回答了 §5 的 Poll：因为 $\max\min = \min\max$，即使对手**事先知道**你的最优混合策略，他能做到的最好也只是把你压到博弈值——不能更多。需要保密的只是**每一局具体抽到的动作**（随机性本身），而不是生成动作的**分布**。

> [!tip] 直觉：从 minimax 原理看稳定性
> 站在最优策略对 $(\pi_A^*, \pi_B^*)$ 上：
> - 如果**对手单方面改变**策略，你的收益只会**变好或不变**（对手放弃了对你的最优压制）；
> - 如果**你单方面改变**策略（偏离最优），你的收益只会**变差或不变**。
> 谁都没有单方面偏离的动机——这正是「**均衡**」的味道，也为 §9 的纳什均衡做了铺垫。另外注意 $p = \tfrac{7}{12}$ 恰好让 B 的两个纯应对**收益相等**（indifference，无差异原则）：最优混合策略的本质就是"调配概率，让对手怎么应对都一样"，从而无懈可击。

---

## 9. 非零和博弈与纳什均衡

### 9.1 从零和到非零和

- **零和**：$U_A + U_B = 0$，一方所得即另一方所失，纯粹竞争；
- **非零和（non-zero-sum）**：双方效用**任意**，可能**双赢**也可能**双输**。

效用关系构成一个谱系：一端是**纯竞争**（零和，用 minimax / 线性规划求解），另一端是**纯合作**（双方效用完全相同，退化成普通的联合最大化/搜索），**现实生活大多介于两者之间**。

非零和时**每个玩家各有一张收益矩阵**：记 $V_p(\pi_A, \pi_B)$ 为策略对下玩家 $p \in \{A, B\}$ 的期望效用（零和时只需一张，因为 $V_B = -V_A$）。

### 9.2 囚徒困境

经典的**囚徒困境（prisoner's dilemma）**：两名嫌犯分开审讯，可选沉默或招供；效用 $=-$（服刑年数）。

| A ＼ B | B 沉默 | B 招供 |
| :---: | :---: | :---: |
| **A 沉默** | (−1, −1) | (−15, 0) |
| **A 招供** | (0, −15) | (−10, −10) |

（每格为 `(A 的效用, B 的效用)`；数值为示意，结构才是重点。）

**困境**：对每个人来说，无论对方怎么选，**招供都严格更优**——对方沉默时招供把 $-1$ 变 $0$，对方招供时招供把 $-15$ 变 $-10$。招供是**严格优势策略（strictly dominant strategy）** → 双方都招供，各判 10 年。但若两人都能沉默，本可只判 1 年——**个体理性导致集体次优**。问题出在两人无法缔结可信承诺：即使约好都沉默，各自仍有偏离的动机。

### 9.3 纳什均衡

零和世界的 von Neumann minimax 定理**不再适用**（它的证明本质依赖"你的所得就是我的所失"这一 LP 对偶结构）。退一步，我们得到一个更弱但更普适的解概念：

> [!note] 纳什均衡（Nash equilibrium）
> 一组策略 $(\pi_A^*, \pi_B^*)$，使得**任何一方单方面改变策略都不会让自己变好**：
> $$V_A(\pi_A, \pi_B^*) \le V_A(\pi_A^*, \pi_B^*)\;\; \forall \pi_A,\qquad V_B(\pi_A^*, \pi_B) \le V_B(\pi_A^*, \pi_B^*)\;\; \forall \pi_B$$
> 没有人有偏离的动机 → **稳定**。注意定义里只有"稳定"，**没有"最优"**。

> [!note] 纳什存在性定理（Nash, 1950）
> 任何**有限玩家、有限动作**的博弈，都**至少存在一个**纳什均衡（可能是混合策略）。囚徒困境说明均衡可以是纯策略；石头剪刀布说明有些博弈的均衡**只能**是混合策略。

**几个例子**：

| 博弈 | 纳什均衡 |
| :--- | :--- |
| 竞争 Morra（零和） | 双方 $[\tfrac{7}{12}, \tfrac{5}{12}]$（同时也是 minimax 策略） |
| 合作 Morra（双方效用相同） | 双方同出 1，或双方同出 2（**两个**均衡） |
| 囚徒困境 | 双方都招供（唯一均衡，但非社会最优） |

### 9.4 零和 vs 非零和：一张对照

```mermaid
graph TD
    A["同时博弈"] --> B["零和"]
    A --> C["非零和"]
    B --> B1["von Neumann<br/>minimax 定理"]
    B --> B2["多个 minimax 策略<br/>单一博弈值"]
    C --> C1["Nash<br/>存在性定理"]
    C --> C2["多个纳什均衡<br/>多个博弈值"]

    style B fill:#e1f5fe,stroke:#0277bd
    style C fill:#f3e5f5,stroke:#7b1fa2
    style B1 fill:#c8e6c9,stroke:#2e7d32
    style C1 fill:#ffe0b2,stroke:#e65100
```

| 维度 | 零和同时博弈 | 非零和同时博弈 |
| :--- | :--- | :--- |
| 核心定理 | von Neumann minimax (1928) | Nash 存在性 (1950) |
| 解的性质 | **最优性**（对最坏对手的保证） | **稳定性**（无单方偏离动机） |
| 博弈值 | **唯一** | 可能**多个**（不同均衡不同值） |

> [!tip] 直觉
> 从零和到非零和，「解」的含义悄悄变了：零和讲**最优**（minimax 值是能向对手强制执行的保证），非零和只讲**稳定**（没人想动，但没人保证结果好）。纳什均衡**存在但不唯一**，也**未必社会最优**——囚徒困境里唯一的均衡恰恰是全局较差的结局。这也是机制设计（mechanism design）存在的理由：改造收益结构，让稳定点恰好落在想要的地方。

---

## 10. 总结

```mermaid
mindmap
  root((博弈 II))
    TD 学习
      学评估函数而非手写
      类比 SARSA·估 V 而非 Q
      从 V 读策略需要模型
      用 RL 因状态数指数级
      自举·平方损失·梯度步
      自我对弈 self-play
      TD-Gammon 与 AlphaGo
    同时博弈
      游戏树失效
      收益矩阵
      纯策略 vs 混合策略
      minimax 定理
        max min 等于 min max
        公开最优混合策略不吃亏
        Morra 最优 7比5 分 值负十二分之一
      非零和
        纳什均衡存在但不唯一
        囚徒困境
```

**关键要点**：

- **学评估函数**：博弈的评估函数不必手工写，可以用 **TD 学习**从经验中学 $V_\pi(s)$——$\text{TD 学习} : V_\pi :: \text{SARSA} : Q_\pi$；更新为 $V(s) \leftarrow V(s) + \alpha\,\big[r + \gamma V(s') - V(s)\big]$。
- **从 V 读策略**：博弈里转移确定，$\pi_{\text{new}}(s) = \arg\max_a V_\pi(\mathrm{Succ}(s, a))$；这一步需要知道 MDP，而博弈规则恰好完全已知。
- **为何用 RL**：不是因为 MDP 未知（L8 的动机），而是因为**状态数指数级**，必须用**函数逼近**（价值网络）+ 采样经验。
- **自我对弈**：双方共用一个 $V$，一方 $\arg\max$ 一方 $\arg\min$；对弈产经验、经验更新 $V$、更强的 $V$ 产生更强的对弈——TD-Gammon、AlphaGo Zero 的共同引擎，历史趋势是手工知识越来越少。
- **同时博弈**：游戏树失效；纯策略下**先走者劣势**，但引入**混合策略**后 **minimax 定理**保证 $\max\min = \min\max$，先后手等价，**公开最优混合策略也不吃亏**——Morra 最优 $[\tfrac{7}{12}, \tfrac{5}{12}]$，博弈值 $-\tfrac{1}{12}$（偏向 B）。
- **纳什均衡**：非零和博弈的解概念从"最优"退为"**稳定**"；Nash (1950) 保证有限博弈**至少一个**均衡，但**不唯一、非社会最优**（囚徒困境）。

**下一讲预告**：至此走完了「状态型模型」（搜索 → [[Lecture 7 · 马尔可夫决策过程]] → 博弈）。接下来转向**变量型模型**——如何用图刻画随机变量之间的依赖并做概率推断？→ [[Lecture 12 · 贝叶斯网络 I：建模与推断]]。

---

## 复习自测

> [!question]- Q1：TD 学习与 SARSA 各估计什么？为什么 TD 学习读出策略时需要模型，而 SARSA 不需要？
> SARSA 估计 $Q_\pi(s,a)$（动作价值），TD 学习估计 $V_\pi(s)$（状态价值）。从 Q 读策略直接 $\arg\max_a Q(s,a)$ 即可——"执行 a 之后会怎样"已经折在 Q 里。从 V 读策略必须自己往前看一步：$\arg\max_a \sum_{s'} T(s,a,s')[R + \gamma V(s')]$，需要 $T, R$。博弈里规则已知且转移确定，这一步简化为 $\arg\max_a V(\mathrm{Succ}(s,a))$，所以"只学 V"在博弈里格外划算（少一个动作维度）。

> [!question]- Q2：推导 two-finger Morra 的最优混合策略与博弈值。
> A 亮 $[p, 1-p]$，B 纯应对：出 1 得 $2p - 3(1-p) = 5p-3$，出 2 得 $-3p + 4(1-p) = 4-7p$。B 取最小，A 最大化该下包络；最优在交点 $5p-3 = 4-7p \Rightarrow p = 7/12$，值 $= -1/12$。对 B 对称推导得同样的 $[7/12, 5/12]$。博弈值为负说明该游戏偏向 B——"看起来对称"的收益矩阵并不对称（$+2$ 对 $+4$ 不平衡）。

> [!question]- Q3：为什么"后走者总可以用纯策略最优应对"？这个事实在推导里起了什么作用？
> 固定先走者的混合策略后，博弈值是后走者概率分布的**线性函数**，线性函数在概率单纯形上的极值必在顶点（纯动作）取到，混合不可能严格更好。作用：它把"对手的最优应对"从无穷多个混合策略压缩成有限个纯动作的枚举，使先走者的问题变成"最大化若干条直线的下包络"——两动作时可直接手算交点，一般情形正好是一个线性规划。

> [!question]- Q4：「公开最优混合策略不吃亏」的确切含义是什么？它和「纯策略先走者劣势」矛盾吗？
> 不矛盾，二者刻画的对象不同。纯策略被公开后，对手能精确克制（Morra 里至多拿 $-3$）；而公开最优**混合**策略 $[7/12,5/12]$ 后，由 minimax 定理 $\max\min=\min\max$，对手的最优应对也只能把你压到博弈值 $-1/12$，与不公开时相同。需要保密的是每局**抽到的具体动作**，不是**分布**本身。本质是无差异原则：最优混合让对手所有应对的收益相等，无从"针对"。

> [!question]- Q5：minimax 解与纳什均衡分别提供什么保证？为什么囚徒困境说明纳什均衡"未必好"？
> 零和博弈的 minimax 解提供**最优性**保证：无论对手做什么，你至少拿到博弈值（可强制执行的下界），且博弈值唯一。纳什均衡只提供**稳定性**：没人有单方面偏离的动机——不承诺结果的好坏，也不唯一。囚徒困境里唯一的均衡（双双招供，各 $-10$）严格差于双双沉默（各 $-1$）：稳定点可以是集体次优的，个体理性不蕴含集体理性。

> [!question]- Q6：自我对弈中为什么双方可以共用同一个价值函数？这个循环为什么能让棋力上升？
> 因为零和：一个站在 agent 视角的 $V$ 已完整刻画双方利害，agent 取 $\arg\max V(\mathrm{Succ})$、对手取 $\arg\min V(\mathrm{Succ})$ 即可。循环之所以有效：当前 $V$ 决定双方策略 → 对弈生成带终局信号的经验 → TD 更新让 $V$ 更准 → 更准的 $V$ 给出更强的策略。同时对手强度始终与自己匹配（训练难度自动课程化），且不依赖任何人类棋谱——这是 TD-Gammon 与 AlphaGo Zero 的公共配方。

---

## 参考资料

- 💻 [td_learning.py](https://github.com/stanford-cs221/autumn2025-lectures/blob/main/td_learning.py) — TD 学习与自我对弈
- 💻 [simultaneous_games.py](https://github.com/stanford-cs221/autumn2025-lectures/blob/main/simultaneous_games.py) — 同时博弈、minimax 定理、纳什均衡
- 📖 [Sutton & Barto: Reinforcement Learning (2nd ed.)](http://incompleteideas.net/book/the-book-2nd.html) — 第 6 章：时序差分学习（TD Learning）
- 📄 [Temporal Difference Learning and TD-Gammon (Tesauro, 1995)](https://dl.acm.org/doi/10.1145/203330.203343) — 神经网络自我对弈的开山之作
- 📄 [Some Studies in Machine Learning Using the Game of Checkers (Samuel, 1959)](https://ieeexplore.ieee.org/document/5392560) — 「机器学习」一词与自我对弈的起点
- 📄 [Mastering the game of Go without human knowledge (AlphaGo Zero, Silver et al., 2017)](https://www.nature.com/articles/nature24270) — 纯自我对弈登顶
- 📄 [Zur Theorie der Gesellschaftsspiele (von Neumann, 1928)](https://link.springer.com/article/10.1007/BF01448847) — minimax 定理原始论文
- 📄 [Equilibrium Points in N-Person Games (Nash, 1950)](https://www.pnas.org/doi/10.1073/pnas.36.1.48) — 纳什均衡存在性定理
- 🌐 [CS221 课程主页](https://stanford-cs221.github.io/) — 课程讲义与作业
