鱼皮AI导航
鱼皮AI导航
  • 主页
  • 社区
  • AI工具
  • AI知识库
  • AI提示词
  • MCP
  • Skills
  • AI学习资源
  • AI资讯
  • GitHub开源
登录/注册
站长:程序员鱼皮 老鱼简历 商务合作 增值电信业务经营许可证
2026 鱼皮AI导航 | 沪ICP备19026706号-6
3
2
2

MCTS + CNN 自对弈强化学习实战总结

鱼儿
鱼儿
2026-10-18 21:24
阅读 578
鱼儿
2026-10-18 21:24
阅读 578

MCTS + CNN 自对弈强化学习实战总结

本文是对一个五子棋自对弈强化学习项目(GomokuCnn)的完整复盘。 项目在一台 RTX 3060 Laptop 上,用 AlphaZero 式"自对弈 → 训练 → 评估" 循环从零训出强 AI:最终模型对战传统 NNUE 引擎 rapfi,先手执黑基本保持 100% 胜率。 训练方案参考了 zhoukangyang233/Gomoku (nn_012 管线),在此之上做了大量机制研究与工程优化。

项目已开源:https://github.com/YorickFin/GomokuCnn

这个项目最有价值的部分不是"训出了一个能下棋的 AI",而是过程中沉淀的 几条反直觉结论——它们大多来自失败的 run,每一条都有实测数据背书:

  1. 标签质量不来自 sims 数,来自标签生成机制;棋力不来自单轮精度,来自总轮次;
  2. 双盲期不是要"解决"的问题,而是要"穿越"的阶段;
  3. 物化 D4 对称增强是强 AI 的信息论硬约束,Online D4 + 经验回放无法替代;
  4. 防杀能力不生活在搜索里,它生活在训练标签里;
  5. 跨轮持久的低学习率是棋力退化的隐形杀手。

下面按管线逐一展开。

一、管线总览

整体是标准 AlphaZero 架构的轻量版:

▼
text
复制代码
自对弈(MCTS + 当前模型生成对局数据) ↓ 标签生成(全节点收集 + prior/Q 分层重分配) ↓ 物化 D4 八倍对称增强 ↓ 训练(每轮重建 Adam + ReduceLROnPlateau 轮内调度) ↓ arena 竞技评估(对 champion 胜率 ≥52% 晋升) ↺ 回到自对弈

关键配置(低 sims 三支柱,缺一不可):

支柱配置作用
低算力搜索30 sims/步单轮快 → 总轮次多
标签机制全节点收集 + 分层重分配低 visits 数据可用
小网络32 通道 / 5 残差块容量匹配噪声标签

三支柱是绑定的。只搬其中两根会得到最差组合:首次启动时曾用 128ch/6blk 大网络配 30 sims,单轮 8 分钟(大网络吃不动 28 万全收样本), 且大容量在噪声标签上只会过拟合——128ch 的训练段计算量是 32ch 的 19 倍。 换 32ch 后全程平均约 22 秒/轮(自对弈 ~6s + 训练 ~15s)。

二、低 sims 的经济学:总轮次 > 单轮标签精度

选择 30 sims 是一场明示的赌注。自对弈训练的总学习信号可以分解为:

▼
text
复制代码
总学习信号量 ≈ 总轮次 × 每轮数据量 × 每样本信息密度

高 sims 管线的每样本信息密度高,但每轮慢;低 sims 管线的前期标签 基本是噪声(30 次模拟摊在 20 个子节点上,每个 1~3 次访问,毫无分辨力), 但换来的是 7 倍以上的轮次吞吐。

一组真实的对照实验:

  • run_8:800 sims,268 轮——arena 胜率停在 59% 天花板,且其 base 本身停滞后,新 run 只能摸到 base 的水平;
  • nn_012(参考管线):30 sims,约 20000 轮——训出强 AI,对弈仅需 200 sims 就能稳定防杀。

轮次差 7.5 倍,sims 差 27 倍,结果完全倒挂。单轮标签精度的短板 可以靠机制补(见下文重分配),总轮次的短板没有任何东西能补。

代价也要有预期:低 sims 的双盲期更长(30 sims 树深约 3 层,搜不出 战术序列,战术能力只能等网络从数据里"背会"棋形)。这是设计内风险, 不是 bug。

三、双盲期:定义、诊断与穿越

什么是双盲期

自对弈冷启动阶段,对局双方(同一模型的自我复制)都弱到数据分布中 不含任何有意义的对抗行为——双方都不堵、不攻,谁先随手连五谁赢。 模型从这样的数据里学不到进步方向,形成自我强化的低水平均衡:

▼
text
复制代码
模型弱 → 搜索树里没有战术信号 → 训练数据里没有"防守收益"的正例 → 模型学不会防守 → 模型依然弱

诊断指标(不要靠肉眼感觉)

run_1 实测的双盲期指纹:

特征实测值说明
对局极短~3.5 s/100 局折合每局仅 ~10 手搜索
胜率暴涨假象arena 对随机 base 99:1赢随机对手不需要会下棋
value/policy 分离val value 0.088→0.029,policy 反而恶化终局信号先教会 value 头;policy 无信号可学

三个关键判据:

  1. 对局长度(最灵敏):防守涌现 = 互堵 = 对局拉锯变长。自对弈 耗时台阶式上升且不回落才是涌现(平台期单次冲高不算数);
  2. arena 对 champion 的持续区分度:5060% 震荡且晋升不断 = 代际 进步;长期 4550% 停滞 = 警惕;
  3. val value loss 在降:说明逃逸引擎在转。注意 val policy loss 不能当判据——重分配标签是移动靶(value 变准 → 标签本身变锐), run_1 全程 policy loss 没有掉头向下,模型照样逃逸了。

穿越手段

按"重要性 × 容易被忽视"排序:

  • 随机开局(opening_max_moves=20,保留空盘开局概率):纯空盘自 对弈的开局标签退化成"先验 top-k 摊平",且所有对局开局段高度相似。 随机预落子把对局起点推进中盘,并用网络估值筛选最均势局面。踩坑 提醒:每个候选必须独立采样——参考实现曾把 shuffle 放在循环外, 1000 个候选实际只有 ~11 种不同局面;
  • 温度:每局随机 0.1~0.8,让整个数据集覆盖从贪心到乱下的行为谱 (固定两阶段温度会导致中后期轨迹趋同,中盘残局偏弱);
  • 根节点 Dirichlet 噪声(α=0.1,混合比 0.25):只加在根节点, 防止搜索被先验锁死;
  • 层次重分配标签:这是低 sims 可行的支点——30 sims 的原始访问 分布是噪声,但每个子节点下方的树内 Q 是连续信号,把访问概率 按"Q 对比 + prior 层级"重新分配给树认为更好的分支,配合全节点 收集(visits 门槛设 0,可信度进样本权重 √(visits/sims)), 低 visits 数据不用丢弃。双盲期里它救不了命(Q 也是噪声),但 value 头一旦变准,policy 标签立刻变准,不用等数据分布先改变 ——这把逃逸正反馈链的长度砍了一半;
  • value 头是逃逸的正反馈引擎:终局胜负 z 是唯一永远真实的监督 信号。逃逸链条:终局 z → value 变准 → 树内 Q 变准 → 重分配标签 变准 → policy 学会堵活三 → 对局拉锯 → 数据出现真战术 → 正循环。

run_1 完整逃逸时间线(1200 轮,约 12 万局,8.4 小时)

阶段轮次自对弈耗时/轮arena 表现状态
双盲期r0~99~3.6 s频繁晋升(假进步)随手连五
长平台r100~7993.6→9.6→5.5 s 冲高回落晋升频繁但幅度小行为在变
深平台r800~1049~3.4 s胜率 50% 无区分全程最像"失败"
逃逸启动r1050~11493.5→5.0 s场均 82.5%,连续大胜突破
巩固r1150~1379稳定 7~8 s54~63% 震荡晋升中等 AI 强度

最深刻的教训:深平台段(胜率 50% 无区分 + 耗时回落到双盲水平)是 全程最像"该止损"的阶段,但它恰恰是逃逸前夜。防守是模式识别问题, 网络需要"见过足够多活三/冲四被惩罚"的对局——run_1 逃逸时累计约 12 万局,与参考实现的 20 万局同一数量级。数据量门槛真实存在,管线 优化只是压低它,没有取消它。

四、物化 D4:强 AI 的信息论硬约束

逃出双盲期之后,下一个瓶颈是自对弈闭环的对称性破缺:

▼
text
复制代码
模型有微小方位偏置(如左上角着法略多) → 自对弈生成的局面里,左上方战术出现频次更高 → 训练后偏置被巩固甚至放大 → 下次自对弈继续生成偏置数据 → 闭环正反馈:偏置永久固化,盲点永远存在

关键在于这个偏置发生在数据生成端。训练端的 Online D4(取样时 随机翻一个方位)只翻已有的偏置数据,改变不了模型下次下棋的偏置。

硬约束 vs 软约束

  • 物化 D4:每个原始局面物化 8 份方位副本,8 个方位在同一次 forward/backward 里一起反传——梯度直接竞争,模型没有任何机会 选择性忽略某个方位;
  • Online D4 + replay_rounds=7:数字上等效(每样本训练 24 次, 方位覆盖 ~96%,Coupon Collector 问题),但 8 个方位分散在不同 epoch、不同轮次,每次训练步模型权重都不同——梯度永远不直接 竞争,偏置有充分的生存空间。且 replay 旧数据的重分配标签是 历史 value 头生成的,已经过时。

分阶段收益

阶段核心瓶颈物化 D4 收益性价比
冷启动期标签全是噪声8 份噪声平均,信噪比 +√8差(每轮样本 ×8)
逃出冷启动后闭环对称性破缺打破偏置正反馈,消除盲点极高

所以正确的姿势是:没学会防守之前 Online D4(省钱熬双盲期), 学会防守之后必须物化 D4(强 AI 的关键)。这个约束与 sims 数 无关——高 sims 管线标签干净后,同样会被闭环偏置卡在强 AI 门槛前。

五、value 标签前缀重分配:防杀能力住在标签里

这是全项目最硬的一条结论,证据来自一次搜索预算完全倒挂的对抗测试:

  • 参考管线:约 2 万轮训练,对弈 200 sims——稳定防杀;
  • 新管线:6000 轮训练,对弈 3600 sims——反复失守。

18 倍搜索预算差距。修复前的新管线对强算杀对手呈现出两个不对称:

▼
text
复制代码
对手的杀点落子之前:树里完全搜不到 10~20 步杀(3600 sims 如同不存在) 对手的杀点落子之后:立刻判断对面胜率 99%(一次前向就完成)

"下之后"只是模式识别(威胁已成型,CNN 一眼可见);"下之前"需要的 是前瞻推理,MCTS 能算深杀的唯一前提是 value 头在杀路早期节点上 给出强烈负值信号,引导搜索分配模拟。而嗅杀能力是训练标签教出来的。

问题出在 value 标签的"半套重分配"

原管线只重分配了 policy 标签,value 标签仍用访问量加权树 Q:

▼
text
复制代码
子节点 A:prior=0.7(正常回应),Q=+0.2,访问 7 次 子节点 B:prior=0.2(潜伏杀点),Q=+0.99,访问 3 次 访问量加权 Q:(7×0.2 + 3×0.99)/10 = 0.437 → 杀点信号被访问占比稀释,再被平庸回应平均掉 前缀 max 重分配:value ≈ 0.551,杀点权重 0.44,远超其 0.3 访问占比 → max 结构保证极端值不被平均掉

更尖锐的情况:杀点只被访问 1 次时(30 sims 常态),旧标签里它的 权重是 1/30 ≈ 3%,信号基本消失;前缀 max 里只要它 prior 靠前, 包含它的层级价值就全额等于它的极端价值。

修复方法:value 标签与 policy 标签从同一个分层循环产出——按 prior 降序逐层差分切分概率预算,每层的前缀 max 价值以同源权重累入 value 标签。数学上有 telescoping 恒等式保证权重和恰为已访问 prior 之和,标签是子节点取反 Q 的凸组合,恒在 [-1,1],与 tanh 输出域对齐。

为什么堆数据补不上这块?自对弈闭环会系统性饥饿这类样本:双方都 看不见长杀 → 树内 Q 没信号 → 对局在杀路成型前就结束了 →"被正确 标注的潜伏威胁"样本极其稀疏 → 模型更看不见。与 D4 闭环偏置同构: 数据生成端缺失的东西,训练端技巧补不齐。前缀 max 有效恰恰是 因为它不需要额外数据——它把树里已经存在但被埋没的信息以正确权重 暴露出来。

教训:3600 sims 防不住的,36000 也防不住——搜索预算由 policy 先验驱动分配,杀点先验低的前提下,堆预算是无效堆砌。

六、学习率:一次退化的教训

run_2 曾采用"余弦下降 + 谷底停留 + arena 驱动跳回"的跨轮 LR 状态机, 结果是:前 324 轮 9 次晋升后,LR 长期压在谷底 lr_min=1e-5 长达 460 轮,期间 arena 对 champion 胜率 45/49/39/50/51%(含明显连败), 棋力巅峰停在前 300 轮。

根因:跨轮持久优化器 + 谷底低 LR = Adam 动量长期累积 + LR 过低, 双重退化。

最终方案(nn_012)极其朴素:

▼
python
复制代码
# 每一轮训练(每次调用)都重建优化器与调度器 optimizer = optim.Adam(model.parameters(), lr=1e-4) # 每轮回 1e-4 scheduler = ReduceLROnPlateau(optimizer, mode='min', patience=2, factor=0.5) # 每个 epoch 用当轮验证损失 val_total = 2*val_value + val_policy step 一次

优化器每轮重建带来三个性质:LR 每轮回到 1e-4、Adam 动量不跨轮累积、 scheduler 每轮重置。与旧方案的本质区别:旧方案在固定评估集上做 跨轮调度(锚定 base,结构上跟踪不了进步);新方案在当轮新鲜自对弈 验证集上做轮内调度(3 个 epoch 内动态下调)。

另外一个相关教训:固定评估集 loss 与模型进步是结构性脱钩的——模型 变强后会偏离 base 的着法偏好,考卷 loss 反而上升。它可以留着看趋势, 但永远不能驱动 LR 调度和早停。

七、工程优化速览

消费级显卡上跑通这套管线,工程优化占了一半功劳:

  • C++ MCTS 核心(pybind11):树操作加速 33.9 倍,端到端 2.18 倍;
  • 批量叶子推理(infer_batch_size=16):30 sims 树浅,批 64 会 覆盖整棵树导致 Q 反馈进不了访问分布;
  • bf16 autocast 训练 + channels_last:batch 2048 下 3.64 倍;
  • fp16 + channels_last 推理:forward 2.49 倍;
  • 4 worker 并行自对弈:~20 分钟/100 局训练轮(优化前配置下)。

八、最终成果与已知短板

最终模型(models/run_6/950.pth)对战 NNUE 引擎 rapfi 的实测:

  • 先手执黑:基本 100% 胜率;
  • 后手执白与平衡开局:表现不佳。

短板的原因很清晰:自对弈管线的数据分布由模型自己决定,后手防守 局面与人为构造的平衡开局不在自然分布内。补强需要另做这两项的 专项训练——这本质上是又一处"数据生成端缺失"问题。

另一个值得记录的观察:修复 value 标签后,自对弈能稳定下到残局, run_5 的 6300 局里出现了 2 局和棋——终局覆盖和防守能力的改善 会直接反映在对局长尾上。

九、可迁移的结论

如果把整个项目压缩成几句话:

  1. 标签机制 > sims 数,总轮次 > 单轮精度。 低 sims 的标签噪声 靠重分配机制补,高轮次的学习信号没有任何替代品;
  2. 双盲期靠穿越,不靠解决。 盯住对局长度、arena 区分度、 val value 三个指标;最像失败的深平台往往是逃逸前夜;
  3. 自对弈闭环里,数据生成端缺的东西训练端补不齐。 方位偏置 要靠物化 D4 硬约束,潜伏威胁要靠 value 标签前缀 max,后手与 平衡开局要靠专项数据——三条同构;
  4. 防杀能力住在标签里,不住在搜索里。 搜索预算由先验驱动, 先验看不见的,预算堆多少都是无效堆砌;
  5. 跨轮持久的低 LR 是退化的隐形杀手。 每轮重建优化器 + 轮内调度,朴素但有效。

参考与深入阅读

  • 项目仓库:https://github.com/YorickFin/GomokuCnn
  • 参考管线:zhoukangyang233/Gomoku(nn_012)
  • 对抗测试对手:dhbloo/rapfi(NNUE)

本文每个主题在项目仓库 docs 目录下都有一篇完整的机制分析, 含全部实测数据、推导过程与代码落位:

  • 低 sims 下棋类游戏强化学习如何逃出双盲期
  • 自对弈强化学习成为强 AI 的硬约束——物化 D4 对称增强的不可替代性
  • 自对弈强化学习的潜伏威胁盲区——value 标签前缀重分配
深度学习
人工智能
AI
3
2
分享
操作
评论
相关内容
0个评论
全部评论
点击登录,快来和大家讨论吧~
表情
图片

目录

🔥 热门文章
1
离谱,DeepSeek 崩了 5 小时,大家却喊:梁圣恩情还不完??
450
2
B 站上 DeepSeek 闹鱼灾了,我发起《大肥鱼清除计划》!
410
3
DeepSeek 全新模型发布,性价比最高的一集!
410
4
自己学习ai,直接买cursor 的套餐,还是买gpt 或者claude 的套餐?
370
5
又一个国产版 Codex 神器,也来卷办公了!
340
6
Vibe Coding 实战:从零构建现代专业级 AI 搜索引擎
330
7
day3-如何写出一个高质量的 Skill(组内分享) 高质量 Skill 不是“一个调得很顺的巨型 Prompt”,而是一个可验证、可回归、可维护的能力包。 先定义“什么算好”,再实现“怎么做好”。评估体系先于 Skill 本身成型。 下面用“故障诊断 Markdown 转 YAML”作为例子,但方法是通用的。 --- 一、先想清楚:Skill 到底是什么 一个 Skill 至少包含四部分: 部分 作用 接口 输入什么、输出什么、边界在哪 流程 分几步做,每步的产物是什么 规则 硬约束、经验规则、失败模式 降级策略 不确定时怎么办,而不是硬编一个看似合理的结果 高质量 Skill 的共同点:职责单一、接口清晰、规则可定位、输出可验证。 反例:把几十条经验全塞进一个主 Prompt,改一条规则要重调整个 Prompt,评估时也不知道是哪条规则退化。 --- 二、核心方法:先建评估,再写 Skill 不要先写转换器再补测试。正确顺序是: 1. 定义输出契约:什么算合法、什么算合格; 2. 建金标准集:一小批人工认可“可放行”的样本; 3. 先写评估 Skill:让它在金标准集上跑出基线; 4. 再迭代生成 Skill:每次修改跑同一套评估,无退化且目标维度提升才算正向。 这就是评估驱动开发:评估是 Skill 的单元测试,金标准集是回归锚点。 --- 三、评估 Skill:三层门禁,逐层递进 前一层不过,后一层不跑。每层留可追溯证据。 第 1 层:确定性硬门禁 用解析器、Schema、校验器完成,不消耗模型成本。 · 输出可解析; · 必填字段齐全,类型/枚举合法; · 引用目标存在,无悬空引用、无不可达节点; · 关键路径至少有一条能到达预期出口。 不通过直接打回。 第 2 层:语义断言 用脚本 + 结构遍历检查“逻辑对不对”,仍然保持确定性。 通用检查项: · 覆盖率:源材料里的关键步骤、分支、条件,输出里是否都有对应? · 完整性:每个判断节点是否都有明确出口?有没有死胡同? · 可达性:每条路径是否都能到达预期终点?有没有无出口循环? · 顺序与依赖:有先后依赖的操作,是否保留了顺序?有没有被拍平成无序列表? 例子:故障诊断转换中,检查“每个判断项是否有是/否/异常出口”“每条路径是否能到根因”。 第 3 层:LLM-as-Judge 只处理解析器表达不了的维度:忠实度、完整性、可执行性。 但 Judge 会漂移,不能单独放行,必须建立在第 1、2 层之上。Judge 的 Prompt、rubric、模型版本都要版本化,换模型必须用金标准集重新校准。 通用 Judge 维度: 维度 问什么 忠实度 输出是否忠实源材料意图?有没有自行发明内容? 完整性 关键步骤、条件、证据是否保留?隐式知识有没有被压成空话? 收敛性 输出是否仍指向原目标,而不是发散? 可执行性 下游不依赖源材料能否直接使用? --- 四、金标准集:回归测试的锚点 不需要一开始就标注几百份。用已认可的样本当种子,扩到 15~30 份,覆盖失败模式而非随机抽样: · 完整正例:典型流程; · 边界/异常分支:异常路径、循环、前置失败回退; · 已知易错模式:实际踩过的坑; · 留出集:不参与调优,只用于最终验收,防过拟合。 金标准不需要完美,只需要当前标准下认可可放行。 回归指标:关键路径用 pass^k(k 次全过),稳定性用 pass@k。 --- 五、工程约束:让批量产出可重放 · 幂等:同输入 + 同 Skill 版本 + 同规则 → 输出一致,否则无法判断变好是 Skill 改了还是随机波动; · 隔离不阻断:单份失败进隔离队列,记录失败层和原因,不阻塞其余; · 版本绑定:规则、rubric、金标准集进 Git;每份报告绑定“源版本 + 生成 Skill 版本 + 评估 Skill 版本 + Judge 模型版本”; · 抽样人工复核:Judge 临界样本 + 易错模式,人工抽检结果反过来校准 rubric。 --- 六、Skill 本身怎么写 · SKILL.md 控制篇幅,写清:输入约定、输出契约、分步流程、硬规则、降级策略; · 经验规则放 references/ 或 rules/,按失败模式分类,不要全塞进主 Prompt; · 不确定时标 needs_review: true,不要硬编看似合理的结果; · 迭代由评估报告驱动:报告告诉你哪层挂了、哪类失败模式,你改对应规则文件,而不是漫无目的调 Prompt。 --- 七、落地顺序(不要反过来) 1. 固化输出契约:Schema + 结构约束; 2. 建金标准集:从已认可的 + 最易出错的样本开始; 3. 先写评估 Skill:跑出基线报告; 4. 再迭代生成 Skill:每次修改对比逐项通过率,无退化且目标提升才算正向; 5. 批量运行 + 隔离回放:失败进队列,结束后人工抽检; 6. 评估 Skill 自身版本化:换 Judge 模型必须重新校准。 --- 八、给组员的三条硬要求 1. 不许凭感觉说“变好了”:每次修改必须附评估报告对比,逐项通过率说话。 2. 不许跳过确定性门禁直接看 Judge 分数:前两层挂了,Judge 分数没有意义。 3. 不许把规则堆进主 Prompt:规则按失败模式分文件,评估报告要能定位到具体文件。 --- 一句话收尾 生成 Skill 决定“能不能做”,评估 Skill 决定“敢不敢用”。 先让评估体系站稳,再让生成器迭代。这样交付的不是一堆“看起来还行”的产出,而是一套可证明、可回归、可交接的 Skill 质量体系。
320
8
我的第一个出海产品!7 天 2 万
310
9
WorkBuddy 本地 API 桥 + dsh 插件:把你的 WorkBuddy 额度,变成手边随手可用的模型
310
10
什么是LLM
300
🔥热门工具
朱雀AI检测朱雀AI检测
朱雀AI检测助手朱雀AI检测助手
LovartLovart
老鱼简历老鱼简历
WritePass官网WritePass官网
面多多面多多
CursorCursor
星月写作星月写作
零感AI零感AI
墨得问题墨得问题