深夜的棋馆里空无一人,老棋手却没有收摊。他摆好棋盘,左手执白、右手执黑,自己和自己对弈。开始时,他全凭习惯随手落子;几局之后,他开始发现自己的棋路里有明显的“漏洞”——每次总是用同样的方式开局,总是在同一个位置被“自己”偷袭成功。于是他记下这一点,下一局就提前防范。就这样,他的对手永远是自己当前最强的版本,他的棋力也在这种“我与我”的交锋中不断突破。 这套方法,在人工智能领域叫“自我博弈”(Self-Play)。AlphaGo 用它从打遍人类棋手变成“无人能敌”;最近大热的 o1 类推理模型,也把同样的套路应用到了数学和代码推理中——让模型的“出题手”与“解题手”相互对抗,在大量自我博弈中练出逐步推理、自我检查的能力。本文将用一个“自己与自己下棋”的故事,带你拆解自博弈背后的胜负判定、策略迭代、奖励设计和推理涌现全过程。

岗位关联

对 AI 从业者来说,理解自我博弈等于拿到一把“没有人类数据也能变强”的钥匙。无论你是在做游戏 AI、推理大模型还是智能体系统,自博弈都是让模型突破数据瓶颈、逼近超人类表现的核心心法。

目录
  1. 可视化演示
  2. 自博弈思想
  3. 胜负判定机制
  4. 策略迭代流程
  5. 蒙特卡洛搜索
  6. 奖励信号设计
  7. 推理能力涌现
  8. 实践应用场景
  9. 局限与未来
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示自我博弈迭代循环、胜负奖励信号设计与累计收益曲线、模型能力超越人类数据天花板的过程。切换模式查看Self-Play训练核心机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

自博弈循环:模型与自身对弈持续进化 当前版本与历史版本对弈生成训练数据 通过PPO强化学习更新策略网络参数 Loop: Play → Reward → Update → Validate 新版本与旧版本对弈验证提升形成闭环

自博弈思想

想象一位棋手每天夜里只做一件事:与昨天的自己下一盘棋。第一天,他执白棋时发现自己的黑棋总是躲在角落;第二天,他执黑棋时就主动防住那个角落。同一副大脑,换一个“立场”看问题,立刻看出破绽。这种“左右互搏”式的训练,就是自我博弈最朴素的形式。

在强化学习里,自我博弈指的不是模型和固定数据集训练,而是“当前策略模型”同时担任对局的双方,或让新旧两代策略互相比赛。它的特别之处在于:对手不是照棋谱模仿来的,而是从自己身体里“长出来”的。既然是同一个模型,它最了解自己怕什么,也就最能逼出自己最薄弱的环节。

AlphaGo 用这种思路,在初步学习人类棋谱后,进入自我博弈阶段:两个相近版本的策略网络互相比赛,不断刷新对局库。后来的 AlphaZero 干脆连人类棋谱都不用,完全从随机落子开始自我博弈。如今,o1 类推理模型把这套逻辑搬进了语言空间:让一个“生成器”不断抛出解题思路,让另一个“验证器”不断从反面挑刺,两者在对抗中共同提升。

这一节我们用式子来刻划“自博弈的训练数据是怎么来的”:

棋手夜里下了十局,第二天一早把十局的复盘记在脑子里,于是“今天的我”悄悄比“昨天的我”高了一点点。自博弈能训练出超强推理的第一个秘密,就是永远选自己最好的版本当对手。

Dt={(si,ai,ri)}i=1K∼Play⁡(πt,πt)\mathcal{D}_t = \{ (s_i, a_i, r_i) \}_{i=1}^K \sim \operatorname{Play}(\pi_t, \pi_t)
这个公式的意思是:第 t 轮训练的数据,来自“策略 πt 与它本身对弈”产生的 K 个(状态–动作–奖励)样本。
  1. \(\pi_t\)当前策略:\(\pi_t\) 是第 t 轮训练时模型的能力。在围棋里,它决定“看到什么局面就下哪一手”;在语言模型里,它决定“看到什么题目就生成什么推理步骤”。
    πt(a∣s)\pi_t(a \mid s)
  2. \(\operatorname{Play}(\pi_t,\pi_t)\)左右互搏的对局:让两个相同的策略副本在同一个环境里互相下完整盘棋。\(\operatorname{Play}\) 表示一整局或多局比赛全过程。
    Play⁡:π×π→{(s,a,r)}\operatorname{Play}: \pi \times \pi \to \{(s,a,r)\}
  3. \(\mathcal{D}_t\)训练数据集合:对局中每走一步,记录当前局面 \(s\)、走法 \(a\) 和最终胜负带来的奖励 \(r\),共收集 \(K\) 条记录,作为下一轮学习的基础。
    Dt={(s1,a1,r1),…,(sK,aK,rK)}\mathcal{D}_t = \{ (s_1,a_1,r_1), \ldots, (s_K,a_K,r_K) \}

胜负判定机制

棋手和自己下棋,如果分不出输赢,就不知道哪步该改。任何博弈首先要有一个明确的“终局哨声”:谁赢了,谁输了,或者平局。裁判的哨声,就是自博弈的第一个基础设施。

在围棋中,终局状态很清晰:占地多者胜。AI 把“赢”编码为奖励 \(r=+1\),“输”为 \(r=-1\),“平局”为 0。但自博弈走向语言推理后,“胜负”不再天然存在:数学题有唯一答案,可以用程序验证器判定对错;开放式问题则靠“验证器”——可以是另一套模型,也可以是一组规则——来充当裁判。

更精细的做法是让模型不仅知道“赢没赢”,还知道“有多大把握赢”。价值网络就是这个作用的:输入一个局面(或一段推理链),输出一个 0 到 1 之间的胜率估计(或正确与否的概率)。这个概率信号将用于引导蒙特卡洛搜索和策略更新。公式如下:

就像棋手复盘时先看记分牌:只有分清了哪一步是“臭棋”,下一次才能避坑。自博弈中的胜负判定,正是给每一次落子贴上一张“对错标签”的记分牌。

p^w=11+e−vθ(s)\hat{p}_w = \frac{1}{1 + e^{-v_\theta(s)}}
价值网络把局面的“优势”压缩成一个获胜概率,接近 1 表示稳赢,接近 0.5 表示均势。
  1. \(v_\theta(s)\)局面打分:神经网络的输出,\(\theta\) 是网络权重,\(s\) 是当前局面。它把“这个局面到底对我多有利”映射成一个实数,数值越大表示优势越大。
    vθ(s)=NeuralNet(局面)v_\theta(s) = \text{NeuralNet}(\text{局面})
  2. sigmoid 函数 \(\frac{1}{1+e^{-x}}\)把任意实数压缩到 0 和 1 之间,形成一个可解释的“获胜概率”。
    σ(x)=11+e−x∈(0,1)\sigma(x) = \frac{1}{1+e^{-x}} \in (0,1)
  3. \(\hat{p}_w\)估计胜率:当 \(v_\theta(s)\) 是很大的正数时,\(e^{-v}\) 接近 0,\(\hat{p}_w\) 接近 1;反之接近 0。价值网络训练的目标,就是让这个概率尽量接近真实对局的胜负结果。
    p^w→1 (胜局),p^w→0 (败局)\hat{p}_w \to 1 \ (\text{胜局}), \qquad \hat{p}_w \to 0 \ (\text{败局})

策略迭代流程

棋手每天复盘,发现“我总在第三回合丢子”,于是第二天把第三回合的走法改掉。自博弈中的“改掉”不是靠直觉,而是靠一种数学化的迭代循环:先打比赛,再分析录像,最后更新“下棋风格”。

流程上,自博弈迭代是这样的:当前策略 \(\pi_t\) 与它自己的副本(或上一轮快照)打出一批对局;然后从对局中提取“局面–动作–胜负”样本;再用策略梯度等方法更新网络参数,得到 \(\pi_{t+1}\)。\(\pi_{t+1}\) 成为新对手后,重新开始打下一批对局。如此循环往复,每一轮的比赛数据都来自“当时最强的自己”。

策略梯度是最常用的更新方式之一。直观地说,它能记住哪些动作“带来了胜利”,并提高这些动作的概率;哪些动作“导致了失败”,就降低概率。公式:

棋手每天都在“更新自己的棋谱”:赢了的招法留下,输了的招法淘汰。自博弈的迭代循环,就是把这个过程自动化、大规模化:每天都对着“昨天的自己”做体检,然后进化出“今天的自己”。

θk+1=θk+η∑(s,a,r)∈D∇θlog⁡πθ(a∣s)⋅r\theta_{k+1} = \theta_k + \eta \sum_{(s,a,r)\in\mathcal{D}} \nabla_\theta \log \pi_\theta(a \mid s) \cdot r
简单说:这局赢了,就把那些为胜利出力的动作概率调高;这局输了,就把那些动作概率调低。
  1. \(\theta_k\) 与 \(\theta_{k+1}\)更新前后:\(\theta\) 是策略网络中所有参数,下标 \(k\) 表示第 \(k\) 轮训练,更新后参数变为 \(k+1\) 轮。
    θk+1=θk+Δθ\theta_{k+1} = \theta_k + \Delta\theta
  2. \(\eta\)学习率:控制每步调整的幅度,\(\eta\) 太大容易震荡,太小则进步缓慢。
    η∈(0,1)\eta \in (0,1)
  3. \(\nabla_\theta \log \pi_\theta(a\mid s)\)梯度方向:告诉我们“朝哪个方向调整参数,会提高选择动作 \(a\) 的概率”。让获胜的动作概率变大。
    ∇θlog⁡πθ(a∣s)≈∂log⁡πθ(a∣s)∂θ\nabla_\theta \log \pi_\theta(a\mid s) \approx \frac{\partial \log \pi_\theta(a\mid s)}{\partial \theta}
  4. 乘以奖励 \(r\)若本局 \(r=+1\),则动作概率上升;若 \(r=-1\),则同样操作但方向相反,概率下降。
    r=+1⇒↑π(a∣s),r=−1⇒↓π(a∣s)r=+1 \Rightarrow \uparrow \pi(a|s), \qquad r=-1 \Rightarrow \downarrow \pi(a|s)

蒙特卡洛搜索

棋手落子前,脑子里会快速“过电影”:如果我走马,对方会走炮,那我再走车,对方又可能怎样……这种对未来几步的推演,在 AI 里叫树搜索。自博弈中棋手每一步都在做这件事,只不过靠的是“数据+直觉”代替了凭空想象。

蒙特卡洛树搜索(MCTS)是 AlphaGo 的核心组件。它在当前局面 \(s\) 上展开一棵“未来之树”:从根节点开始,反复选择最有价值的子节点,一路走到叶子,然后让策略网络快速模拟几步并评估胜负,再把结果反向传回沿途节点。选择节点时不是单纯选胜率最高的,而是用 UCT 公式在“胜率”和“新鲜度”之间做权衡:

深夜的棋手也会在落子前把棋盘上下左右都脑补一遍:走这边对方怎么防,走那边对方怎么杀。MCTS 就是把这种“脑内推演”变成一套可以无限放大、无限快的算法——它让自博弈中的每一步都经过深思熟虑。

a∗=arg⁡max⁡a[Q(s,a)+cln⁡N(s)N(s,a)]a^* = \arg\max_a \left[ Q(s,a) + c \sqrt{\frac{\ln N(s)}{N(s,a)}} \right]
UCT 公式是搜索的“探路原则”:既要多走胜率高的路,也要岔开去走那些还没探过的路。
  1. \(Q(s,a)\)平均胜率:在节点 \((s,a)\) 处历史模拟中获胜的比例,代表这条路线的“实绩”。
    Q(s,a)=该动作累计胜场该动作被访问次数Q(s,a) = \frac{\text{该动作累计胜场}}{\text{该动作被访问次数}}
  2. \(\sqrt{\frac{\ln N(s)}{N(s,a)}}\)不确定性红利:\(N(s)\) 是父节点访问总次数,\(N(s,a)\) 是当前动作被访问次数。一个动作被访问得越少,这项值越大,越容易被“照顾式地尝试一遍”。
    N(s,a)→0⇒ln⁡N(s)N(s,a)→∞N(s,a) \to 0 \Rightarrow \sqrt{\frac{\ln N(s)}{N(s,a)}} \to \infty
  3. \(c\)探索系数:调节“探索”和“利用”的权重。\(c=0\) 时只选胜率最高;\(c\) 大时更爱试冷门棋路。
    c≥0c \ge 0
  4. \(\arg\max\)取最大者:最终选出“胜率优 + 值得尝鲜”的最佳子节点,作为下一步。
    a∗=使方括号内数值最大的动作a^* = \text{使方括号内数值最大的动作}

奖励信号设计

棋手最头疼的问题是:一盘棋下了两个小时,只有最后那一秒知道输赢。难道中间每一手棋都没有奖励吗?如果只看结局,棋手很难判断“是哪一步开始崩的”。这就是稀疏奖励问题。

在自博弈中,一局围棋只有终局才出现 +1 或 -1,中间上千步奖励都为 0。强化学习算法若直接在这种奖励上做策略梯度,会非常慢,因为无法定位是哪个动作导致了失败。为了解决这个问题,研究者引入折扣回报和价值网络:让模型学一个“未来可期程度”的打分器,每一步都能获得一个“预测分数”来引导方向。折扣回报定义如下:

棋手下完棋复盘,会给每一步标上“好棋、缓手、败招”的记号。折扣回报和价值网络,就是 AI 在训练时自动生成的“复盘评语”。

Gt=rt+γrt+1+γ2rt+2+⋯=∑k=0∞γkrt+kG_t = r_t + \gamma r_{t+1} + \gamma^2 r_{t+2} + \cdots = \sum_{k=0}^{\infty} \gamma^k r_{t+k}
折扣回报把“从某一步一路到终局”的所有奖励按时间衰减相加,让中间的每一步都拥有一个“带方向感的反馈”。
  1. \(r_t\)即时奖励:第 \(t\) 步获得的奖励,在围棋自博弈中通常只有终局非零。
    rt={+1终局胜−1终局负0其他r_t = \begin{cases} +1 & \text{终局胜} \\ -1 & \text{终局负} \\ 0 & \text{其他} \end{cases}
  2. \(\gamma\)折扣因子:\(0 \le \gamma \le 1\)。它表示“未来的奖励不如眼前的奖励值钱”,让模型更关注近期的因果。
    γkrt+k:越远的奖励给的权重越小\gamma^{k} r_{t+k}: \text{越远的奖励给的权重越小}
  3. 累加得到目标从当前步开始,把未来每一步奖励按衰减系数加总,得到 \(G_t\)。这个 \(G_t\) 就是价值网络的回归目标。
    Gt=rt+γGt+1G_t = r_t + \gamma G_{t+1}
  4. 价值网络用 \(G_t\) 作为监督信号,让 \(v_\theta(s)\) 学会“这个局面值多少分”,从而在没到终局时就能预测胜负。
    vθ(s)≈E[Gt∣s]v_\theta(s) \approx \mathbb{E}[G_t \mid s]

推理能力涌现

老棋手和自己下久了,不仅棋力变强,还练出了一种新本事:下完棋能立刻当“解说员”,指出自己刚才是怎么走岔的。这种“事后诸葛”的能力,放在 AI 身上,就是在自博弈中涌现出来的推理能力——它开始给自己挑刺。

语言推理模型无法像围棋那样一步一步地明确“胜负”,但可以这样设计自我博弈:模型生成多条解题链,然后用验证器给每条链打分。生成器和验证器不断对抗,最终迫使生成器产出更严密、更经得起推敲的步骤。这种“多尝试 + 自我批判”的模式,术语叫自洽性(self-consistency)或推理时搜索。它有一个清晰的数学助力:

深夜棋手最奇妙的一刻,是他能一边下棋一边“吐槽自己”:这一手太冒进了,换一种思路才不会输。自我博弈把这种“自我批评”也练成了模型的能力——推理能力强,本质上是“能不断地把自己当对手来检查”。

Pcorrect(K)=1−(1−p)KP_{\text{correct}}(K) = 1 - (1-p)^K
假设模型单次生成答案的正确率是 \(p\),独立采样 \(K\) 条答案并用验证器选优,那么至少一条正确的概率随 \(K\) 增大而快速上升。
  1. \(p\)单次正确率:模型一次生成得到正确答案的概率。训练较差时 \(p\) 可能只有 0.5。
    p=P(单次答案正确)p = P(\text{单次答案正确})
  2. \((1-p)^K\)全部答错的概率:如果每条答案独立,\(K\) 条全错的概率就是 \((1-p)\) 的 \(K\) 次幂。
    P(K条全错)=(1−p)KP(\text{K条全错}) = (1-p)^K
  3. \(1-(1-p)^K\)至少一条正确:用 1 减去全错的概率。\(p=0.5,K=5\) 时正确率上升到 \(1-(0.5)^5=96.9\%\)。
    K=5, p=0.5 ⇒ P=1−132=0.969K=5,\ p=0.5 \ \Rightarrow\ P = 1-\frac{1}{32} = 0.969
  4. 推理涌现的机制与其让模型“一口说出答案”,不如让它扮演“多个自己”,提出多种解释再互相投票,最终选出一致且合理的结论。
    答案=arg⁡max⁡a∑chain1[chain 的结论=a]\text{答案} = \arg\max_{a} \sum_{\text{chain}} \mathbb{1}[\text{chain 的结论} = a]

实践应用场景

回到棋馆:当年只和自己下棋的老棋手,如今走上大赛赛场,发现遇到的每位高手都像“某个版本的自己”。原来那种与自己过招练出的敏锐,在和外人交锋时同样管用。自博弈从棋类走向数学与代码,也是同样的路径。

实践里,自博弈的应用分为两条线。一条是棋类:AlphaGo/AlphaZero 在围棋、国际象棋、日本将棋上,完全靠自博弈从零起步成为世界冠军,显著超越依赖人类棋谱的旧系统。另一条是推理:o1 类模型把“左右互搏”嵌进“生成–验证”循环,让模型在数学证明、代码调试等任务中反复试错、自我修正。共同点是它们都最大化同一个目标——期望累积奖励:

老棋手大赛夺冠后回到棋馆,依然摆开棋盘和自己对阵,因为他知道:真正的对手永远是自己。o1 模型在数学难题上超越人类平均分后,训练仍在继续——自博弈的终点不是打败别人,而是不断打败上一秒的自己。

max⁡θJ(θ)=Eτ∼πθ[∑t=1Tγt−1rt]\max_\theta J(\theta) = \mathbb{E}_{\tau \sim \pi_\theta} \left[ \sum_{t=1}^{T} \gamma^{t-1} r_t \right]
这个公式是自博弈训练的“总指挥”:所有策略更新、搜索、奖励设计,最终都服务于让期望总收益最大。
  1. \(\tau \sim \pi_\theta\)一整条轨迹:\(\tau\) 是从开局到终局的一条完整轨迹(状态、动作、奖励的序列),由策略 \(\pi_\theta\) 做决策而生成。
    τ=(s1,a1,r1,…,sT,aT,rT)\tau = (s_1,a_1,r_1,\ldots,s_T,a_T,r_T)
  2. \(\sum_{t=1}^{T} \gamma^{t-1} r_t\)整局折扣总回报:把一盘棋或一次解题过程中所有奖励累加,形成一个唯一的分数。
    R(τ)=∑t=1Tγt−1rtR(\tau) = \sum_{t=1}^{T} \gamma^{t-1} r_t
  3. 期望与最大值\(\mathbb{E}\) 表示“平均而言”。训练目标就是调整 \(\theta\),让这条轨迹的平均总回报尽可能高。
    θ∗=arg⁡max⁡θEτ∼πθ[R(τ)]\theta^* = \arg\max_\theta \mathbb{E}_{\tau\sim\pi_\theta}[R(\tau)]
  4. 实践意义棋类场景中 \(r_t\) 是胜负;数学解题场景中 \(r_t\) 是“验证器判定步骤是否正确”。目标函数不变,变的只是奖励的载体。
    通用目标=自博弈中所有方法的北极星\text{通用目标} = \text{自博弈中所有方法的北极星}

局限与未来

棋手和自己下了十年后,发现自己只会下某种“自家风格”的棋,遇到高手时反而被奇招克制。单打独斗的训练,练久了也会进入死角。自博弈不是万能的,它也有自己的“天花板”。

自博弈面临的最大问题是“循环与退化”。如果模型只和当前版本的自己对局,可能收敛到一种“狭窄风格”:它擅长骗过自己,却不擅长应对外部多样化的对手。有时策略还会出现震荡式反弹,这让人联想到石头剪刀布的循环压制。另一个风险是博弈崩溃:生成器发现验证器的漏洞后学会“骗过裁判”,而不再提升真正的推理能力。对抗这些问题的思路,是引入“对手池”和群体博弈,让模型面对一群历史对手,而不是单个自己。在理想状态下,自博弈收敛到博弈论中的纳什均衡:

老棋手后来走出棋馆,开始和不同棋风的棋友切磋,把他们的招数“揉”进自己的自搏训练里。自博弈的下一个时代,或许不是“一人对镜”,而是一群“镜子”互相映照——在彼此的学习中,练出更广阔、更稳健的推理能力。

π∗=arg⁡max⁡πV(π,π∗)\pi^* = \arg\max_{\pi} V(\pi, \pi^*)
纳什均衡是自博弈的“理想终点”:在这个状态下,任何单方面改变策略都无法获得更大收益,双方都不想换了。
  1. \(V(\pi, \pi^)\)两策略对战的期望收益:若策略 \(\pi\) 去挑战最优自博弈策略 \(\pi^\),能得到的期望收益。
    V(π,π∗)=E[胜+1, 负−1]V(\pi,\pi^*) = \mathbb{E}[\text{胜}+1,\ \text{负}-1]
  2. \(\arg\max_\pi\)寻找最优应对:在所有可能的策略里,找一个收益最大的。若结果仍是 \(\pi^*\) 本身,说明它已经“无懈可击”。
    π∗ 是 V(π,π∗) 的最大点\pi^* \text{ 是 } V(\pi, \pi^*) \text{ 的最大点}
  3. 自博弈的目标不是简单地赢下当前对局,而是逼近那个“即使自己思考也想不出更优解”的策略固定点。
    V(π∗,π∗)≥V(π,π∗),∀πV(\pi^*, \pi^*) \ge V(\pi, \pi^*), \quad \forall \pi
  4. 未来方向用多智能体群体博弈替代单智能体自博弈、与真实世界数据混合、引入可验证奖励(如数学定理证明器),都是突破瓶颈的钥匙。
    对手池={π1,π2,…,πn}\text{对手池} = \{\pi_1, \pi_2, \ldots, \pi_n\}

AI 应用场景

弈棋游戏 AI 训练

阶段:数据生成与策略训练

解决的问题:棋类游戏往往缺少高质量对手数据,人类棋谱有限且水平分布不均。自博弈让游戏 AI 摆脱对棋谱的依赖,通过“两个自己下棋”不断产生风格鲜活的训练数据,使模型在探索–利用循环中持续进步。

具体案例:AlphaZero 在不知道任何人类棋谱的情况下,仅用 24 小时自博弈便在围棋上击败了此前最强的 AlphaGo Master。现在许多棋类对战平台用类似方法训练“陪练机器人”,让玩家随时可以挑战不同段位的 AI。

数学与代码推理模型

阶段:推理时搜索与验证器训练

解决的问题:大模型在复杂数学题上“一遍算对”很难,传统监督微调又需要大量人工解题过程。自博弈让模型生成多条解题路径,再用验证器挑选最优,把“推理能力”转变成“自我博弈后的最优路径搜索”。

具体案例:o1 类模型在竞赛数学题上采用类自博弈流程:生成候选解题链 → 用规则验证器或奖励模型打分 → 选取得分最高的链;如果验证失败,模型会重新生成并自我修正,最终在 AIME 等竞赛数据集上达到远超传统模型的准确率。

大模型红队与对抗测试

阶段:安全评估与鲁棒性训练

解决的问题:单靠人类红队难以覆盖全部攻击面。自博弈让一个模型扮演“攻击者”,另一个扮演“防守者”,不断对抗,自动发现漏洞并补齐短板,从而提升系统的鲁棒性与安全性。

具体案例:语言模型安全团队用两个模型互相对话:攻击模型尝试诱导越狱,防守模型尝试拒绝并提供安全解释。多轮对抗后,防守策略越来越稳,攻击版本也越来越刁钻,最后把两类策略蒸馏进正式版本中。

Python 演示

python95 行
"""用自我博弈训练一个极简井字棋智能体。 核心思想:同一个智能体既执先手也执后手,通过与自己对弈产生数据,再用胜负结果更新 Q 表。这是 AlphaGo 自博弈思想的最小演示版本。""" import randomfrom collections import defaultdict  class Game:    """井字棋棋盘,始终从'当前行动方'视角看盘面。"""     def __init__(self):        self.board = [0] * 9  # 0 空位 / 1 我方 / -1 对方     def legal(self):        return [i for i, v in enumerate(self.board) if v == 0]     def move(self, pos):        self.board[pos] = 1        self.board = [-v for v in self.board]  # 换边视角     def result(self):        lines = [(0,1,2),(3,4,5),(6,7,8),(0,3,6),(1,4,7),(2,5,8),(0,4,8),(2,4,6)]        for a, b, c in lines:            if self.board[a] == self.board[b] == self.board[c] == 1:                return 1   # 当前行动方获胜        if not self.legal():            return 0       # 平局        return None        # 尚未结束  class QAgent:    """用 Q 表表示策略:状态 + 动作 -> 期望价值。"""     def __init__(self, alpha=0.3, gamma=0.9):        self.q_table = defaultdict(float)        self.alpha = alpha        self.gamma = gamma     def choose(self, game, eps):        moves = game.legal()        state = tuple(game.board)        if random.random() < eps:            return random.choice(moves)        return max(moves, key=lambda m: self.q_table[(state, m)])     def learn(self, episode, reward):        """对所有历史落子做一次简易策略更新。"""        for state, action in episode:            old = self.q_table[(state, action)]            self.q_table[(state, action)] = old + self.alpha * (reward - old)  def self_play_train(episodes=2000):    agent = QAgent()    for ep in range(episodes):        game = Game()        episode = []        eps = 0.5 * (1 - ep / episodes) + 0.05   # epsilon 逐渐降低        while True:            state = tuple(game.board)            act = agent.choose(game, eps)            game.move(act)            episode.append((state, act))            result = game.result()            if result is not None:                break        agent.learn(episode, result)    return agent  def verify(agent, rounds=500):    """用随机策略当陪练,粗略评测自博弈训练效果。"""    wins = 0    for _ in range(rounds):        game = Game()        while True:            moves = game.legal()            if len(moves) == 0:                break            game.move(agent.choose(game, 0.0))  # 完全利用            r = game.result()            if r is not None:                if r == 1:                    wins += 1                break    return wins / rounds  if __name__ == "__main__":    agent = self_play_train(2000)    print("自博弈后胜率(对随机策略): %.2f" % verify(agent))
目的:用井字棋这个小棋盘演示自我博弈训练闭环——同一个 agent 轮流执先手和后手,自己与自己下棋,再根据胜负更新 Q 表。
  1. self.board = [-v for v in self.board]每走一步就翻转盘面视角,这样同一个 agent 可以轮流扮演双方,无需两支队伍。
  2. agent = QAgent()只有一个策略表却担任“白方”和“黑方”,这就是“左右互搏”的代码化身。
  3. agent.learn(episode, result)用整局胜负作为奖励信号,把所有落子的 Q 值都向最终结果靠拢。
  4. eps = 0.5 * (1 - ep / episodes) + 0.05训练初期多乱走探索,后期趋于稳定利用,模拟“从菜鸟逐步变强”。
  5. verify(agent, 500)训练后让模型和随机策略对战,用胜率量化自博弈的效果。

常见误区

误区我听过 AlphaZero 完全从零开始,所以自博弈肯定是在空房间里自己练,任何真实人类数据都可以不要。

正解AlphaZero 在棋类里确实不依赖人类棋谱,因为规则和胜负天然可判定。但语言推理场景中,自博弈通常仍需要少量种子任务、验证器,甚至少量人类标注的推理链做初始引导,否则模型连“该往哪个方向推理”都不知道。自博弈减少的是对海量外部标注的依赖,而不是完全摒弃一切先验。

为何常见:AlphaZero“零人类知识”的宣传太深入人心,大家误以为“零数据”是普适的。

误区模型每次都在和更强的自己打,肯定一直变强,不会出现退步。

正解自博弈没有天生的“单调递增”保证。策略可能陷入循环(石头剪刀布式的摇摆),或过度适应一个狭窄风格而在新任务上退化;当验证器有漏洞时,模型还可能学会欺骗。所以工程上要加对手池、熵正则、混合历史数据,甚至回滚到更好的旧策略。

为何常见:因为日常训练中我们看到训练损失在下降,就把“损失降低”等同于“博弈水平提升”,忽略了对抗场景的动态性。

误区稀疏奖励让模型不知道哪步对,所以我要每一步都设计密集奖励,这样模型学得更快。

正解不当的密集奖励会引入主观偏见,模型可能学会迎合奖励函数而不是真正下好棋或做好推理,出现奖励欺骗。自博弈的标准做法是尽量保持稀疏的胜负信号,再用价值网络去拟合期望回报,只在必要时引入过程奖励(如数学证明中的步骤检验)。

为何常见:初学强化学习时,人们习惯用“即时反馈”类比教学,觉得奖励越密集反馈越及时。

误区只要自博弈模型在训练中把旧版本全部打败,就说明它是终极正确答案。

正解胜率只是在特定策略分布下的表现,不能代表绝对强度。自博弈的目标是逼近纳什均衡:没有一个策略能单方面占便宜。此外,在开放任务(语言推理)里,“胜负判定”本身可能是近似信号,所以胜率高并不等于真实推理可靠。

为何常见:对抗训练中胜率最容易量化,人们下意识用竞技排名代替真实能力评估。

面试题

Q1. 自我博弈中,模型下一轮训练的主要对手是?

单选题 · easy

  • A.随机噪声策略
  • B.当前模型的最佳版本← 正确答案
  • C.固定的人类棋谱库
  • D.预训练语料库

答案:B。自我博弈的核心是“自己和自己下棋”,因此对手通常是当前模型自己(或其副本/旧版本)。随机噪声无法提供有意义的对抗压力,棋谱库和语料库则是外部数据而非博弈对手。

Q2. AlphaZero 相比 AlphaGo 最关键的改变是?

单选题 · easy

  • A.使用更多人类棋谱
  • B.完全抛弃人类棋谱,仅靠自博弈← 正确答案
  • C.引入更深的神经网络
  • D.使用更大的 CPU 集群

答案:B。AlphaZero 的最大突破是“零人类知识初始化”:它从随机策略出发,只通过自我博弈就能超越此前学习过人类棋谱的 AlphaGo。网络深度和计算资源是辅助因素,不是本质区别。

Q3. UCT 公式中的“探索项”主要作用是?

单选题 · mid

  • A.提高旧策略的权重
  • B.鼓励尝试访问次数少的节点← 正确答案
  • C.直接决定最终胜负
  • D.减少搜索树的深度

答案:B。UCT 中的 \(c\sqrt{\ln N(s)/N(s,a)}\) 会随访问次数变少而变大,引导搜索去尝试尚未被充分探索的节点。它负责“探索”,而不是直接给出胜负或管理旧策略权重。

Q4. 自博弈训练需要具备哪些要素?

多选题 · mid

  • A.明确的胜负判定机制← 正确答案
  • B.预训练好的超大规模模型
  • C.策略迭代与奖励信号← 正确答案
  • D.固定的对手棋谱库

答案:AC。自博弈依赖“可判定胜负”的环境(围棋、数学题验证器等),以及不断迭代策略和传递奖励信号的循环。超大规模模型和固定棋谱库并非必要条件,AlphaZero 用中等规模的网络也能从零开始训练。

Q5. 价值网络 \(v_\theta(s)\) 的学习目标是逼近什么?

单选题 · mid

  • A.下一步的最佳动作
  • B.当前局面的折扣回报期望← 正确答案
  • C.棋盘上棋子的数量
  • D.对手策略的参数

答案:B。价值网络把“当前局面到底有多好”映射成一个分数,目标是逼近从该局面出发的期望折扣回报 \(\mathbb{E}[G_t\mid s]\)。它不直接输出动作,也不预测棋子数量或对手参数。

Q6. 稀疏奖励训练中,折扣因子 \(\gamma\) 越接近 1,代表什么?

单选题 · mid

  • A.模型只在乎眼前一步
  • B.远期奖励越受到重视← 正确答案
  • C.奖励信号全部为 0
  • D.不再需要价值网络

答案:B。\(\gamma\) 控制未来奖励的衰减速度。\(\gamma\) 接近 1 时,远处的奖励几乎不打折,模型会考虑更长期的收益;\(\gamma\) 接近 0 时,模型变得短视。

Q7. 自洽性(多数投票)提升推理正确率依赖的核心假设是?

单选题 · hard

  • A.各采样答案独立且单次正确率高于随机← 正确答案
  • B.验证器完全无误差
  • C.采样次数无限大
  • D.模型一定收敛到纳什均衡

答案:A。多数投票只有在“每次采样有一定正确概率且彼此较独立”时才有效。如果单次正确率低于随机,投票反而放大错误;验证器无误差和无限采样都不是必要假设。

Q8. 自博弈训练中的“博弈崩溃”可能表现为?

多选题 · hard

  • A.策略循环震荡,旧版本反而更优← 正确答案
  • B.生成器利用验证器漏洞骗分← 正确答案
  • C.对局数据完全无法采集
  • D.训练奖励信号全部为零

答案:AB。博弈崩溃指训练脱离“真实进步”的轨道:策略可能反复震荡、互相克制,或生成器学会欺骗不完善的验证器,导致表面奖励上升但真实能力下降。对局数据仍能采集、奖励也非零,所以 C 和 D 不是崩溃的典型表现。

Q9. 下列哪项最适合缓解自博弈的“狭窄风格”问题?

单选题 · hard

  • A.增大学习率
  • B.引入对手池与群体博弈← 正确答案
  • C.去掉全部奖励信号
  • D.降低网络容量

答案:B。只在单一自博弈中训练会让模型只擅长应对“自己的风格”。引入包含多个历史版本与异质策略的对手池,可以增加策略多样性,从而缓解狭窄化。增大学习率或降低网络容量反而可能加剧不稳定。

Q10. 纳什均衡作为自博弈理想终点的核心含义是?

单选题 · extreme

  • A.所有策略的胜率完全相等
  • B.任何单方策略偏移都无法获得更大收益← 正确答案
  • C.模型不再需要任何训练
  • D.策略达到人类世界冠军水平

答案:B。纳什均衡描述一种对抗平衡:给定对手策略不变,任何一个玩家单独改变策略都不可能提高收益。它不要求所有策略胜率相等,也不等于“训练停止”或“超越人类”,而是自博弈收敛性的理论标尺。