type
status
date
slug
summary
tags
category
icon
password
一、核心思想概述二、算法结构(四步循环)三、核心优点四、应用典型场景五、与传统搜索算法的对比六、总结一句话一、你的理解(类似 Minimax)二、MCTS 的不同点三、用一个形象比喻四、可视化地总结整个循环五、总结一句话一、核心类比:都是“在不确定性下用采样逼近最优决策”二、数学思想上的共通根:UCB 与贝叶斯置信区间三、在概念层面上的“渊源”四、一句话总结一、总体理解:自我对弈闭环二、五个并发模块(必须同时运行)1. Selfplay Engine(自我对弈引擎)2. Shuffler(数据打乱器)什么是 TFRecord?3. Training(训练器)4. Exporter(模型导出器)5. Gatekeeper(守门人)三、总结:训练闭环的整体流程四、简化的类比五、关键术语小结一、问题的核心:如何启动一个闭环系统?二、获取“初始模型”的几种常见做法方法 1:随机初始化模型(最常见)效果方法 2:用一个已知的“弱模型”作为起点方法 3:人工生成少量样本作为起点(较少使用)三、典型项目中的实际做法四、为什么随机模型也能学起来?五、启动时的目录结构(简化示意)六、小结一、核心思想:模型既当“黑方”又当“白方”二、是谁在“控制”对弈?三、模型在自我对弈中的“输入”和“输出”四、为什么模型能靠“自己对弈”变强?五、控制流程总结六、你可以把它理解成:一、脚本整体行为概览二、关键部分:options 变量1. 基本初始化命令2. 引擎配置选项3. 核心命令:gensfen ...三、执行部分四、整体逻辑总结五、简要概括一句话一、哈希表在棋类引擎中的作用二、哈希值是什么三、哈希表中存的内容四、为什么要设置Hash value 10240五、总结
💡

Q: 什么是蒙特卡洛树搜索?

一、核心思想概述

蒙特卡洛树搜索(Monte Carlo Tree Search, MCTS) 是一种用于在决策空间极大(如棋类游戏)中寻找最优行动的算法。
它通过反复随机模拟(Monte Carlo) 的方式,估计各个可能行动的“好坏”,并以此逐步构建一棵搜索树,从而在有限计算时间内逼近最优策略。
MCTS 的核心思想是:
不遍历全部博弈树,而是用统计采样的方法逐步逼近最优节点的价值。

二、算法结构(四步循环)

MCTS 的一次迭代通常分为四个阶段:
  1. 选择(Selection)
    1. 从根节点出发,根据一定的选择策略(如 UCB1),在已展开的树中不断选择“最有前途”的子节点,直到到达一个尚未完全展开终局的节点。
      典型选择公式(UCB1):
      其中:
      • :动作 a 的平均奖励
      • :父节点被访问的总次数
      • :动作 a 被访问的次数
      • :探索系数,平衡“探索”与“利用”
  1. 扩展(Expansion)
    1. 如果当前节点不是终局,就从中选择一个未被访问过的动作,生成一个新子节点并加入搜索树。
  1. 模拟(Simulation / Rollout)
    1. 从新节点开始,使用随机策略(或轻量启发式)进行一局游戏的“快速对弈”,直到游戏结束。
      通过这种随机模拟得到一个最终结果(如胜负或分数)。
  1. 回传(Backpropagation)
    1. 将模拟得到的结果沿路径反向传播到根节点,更新经过的每个节点的访问次数与平均得分。

三、核心优点

  • 不需要完整模型:只需能模拟局面的演化与终局结果。
  • 可中断性好:随时可以停止,已有搜索结果仍可作为合理决策。
  • 自适应性:在计算时间充足时能逼近最优策略,时间有限时仍能做出较好决策。

四、应用典型场景

  • 棋类游戏(如围棋、国际象棋、将棋)
    • —— AlphaGo 的搜索部分即基于 MCTS。
  • 规划问题(机器人路径规划、游戏AI决策)
  • 强化学习结合
    • —— 在 AlphaZero 框架中,MCTS 与神经网络结合:
      网络提供先验策略概率局面价值评估,MCTS 用于搜索和改进策略

五、与传统搜索算法的对比

特征
Minimax / Alpha-Beta
Monte Carlo Tree Search
搜索方式
全面剪枝搜索
随机采样估计
评估函数
需人工定义
可通过模拟直接估计
适用领域
局面小、规则明晰
局面大、状态复杂
结果性质
精确(理论最优)
近似(统计最优)

六、总结一句话

MCTS 是一种用“随机模拟”代替“穷举搜索”的决策算法。
它通过反复的“选择-扩展-模拟-回传”循环,用统计的方法逐渐学到哪些行动更优,从而在巨大状态空间中高效地逼近最优解。
💡

Q: 我来描述一下我的理解. 我的理解是, 蒙特卡洛树搜索, 就是先从一个基本局面出发, 然后不断递归生成新的局面, 直至到达终局(也就是叶节点)然后再从叶节点开始递归返回, 根据每个子节点的得分值计算出每个中间界点的得分值, 是这样吗?

你的理解已经非常接近正确,只是目前的描述更接近“Minimax 搜索”的思路,而 蒙特卡洛树搜索(MCTS) 在细节上有几个关键区别。下面我帮你对比并澄清:

一、你的理解(类似 Minimax)

你说的流程是:
从根节点开始递归展开 → 到达终局(叶节点) → 递归返回计算每个中间节点的得分。
这种方式确实是典型的 深度搜索 + 回溯,也是 Minimax 或 Alpha-Beta 剪枝 的基本思想。
但它需要遍历大量或全部可能局面,且每个节点的得分是确定计算出来的。

二、MCTS 的不同点

MCTS 也是“从根出发,不断扩展、回传”,但它的核心不是遍历所有局面,而是:
随机采样+统计估计
具体区别如下:
环节
你理解的版本(Minimax)
MCTS 的实际做法
搜索方式
递归遍历全部分支
随机选择部分分支
节点得分
精确计算(通过规则或评估函数)
通过随机模拟的平均结果估计
终局到中间节点的传播
一次完整递归(一次性完成)
多次模拟的统计累积(逐步逼近)
搜索目标
求理论最优策略
在有限计算下逼近最优决策

三、用一个形象比喻

假设你要判断“下这一步棋好不好”:
  • Minimax:穷举所有未来几步的可能变化,直到终局,用理论推导出结果。
  • MCTS:不穷举,而是随机下很多盘,从当前局面出发随机模拟到终局,看哪种走法在大量随机对局中平均胜率更高
于是:
  • 节点得分不是一次计算出来的,而是由反复多次“玩”出来的平均胜率
  • 每次模拟结束都会“回传”结果,不断更新中间节点的统计信息。

四、可视化地总结整个循环

随着循环次数增加:
  • 好的分支会被不断探索(利用)
  • 不确定的分支也会被偶尔尝试(探索)
  • 树结构逐渐向更优方向“生长”

五、总结一句话

你的理解中“自下而上计算得分”的部分是对的,但 MCTS 不会穷举所有路径,而是通过
大量随机模拟
换句话说:
MCTS 是“用反复随机实验”代替“穷举推理”的树搜索方法。

💡

Q: 我只要理解到这里就可以了, 这就是自对弈棋类引擎用来生成训练数据的方法, 即通过随机自对弈对弈给一大批不同的局面打分, 对吧?

完全正确。
你可以把整个流程理解成这样:
自对弈 + 蒙特卡洛树搜索
近似的“真实价值”标签
更具体地说:
  1. MCTS 在自对弈时的角色
      • 它不是直接训练的目标,而是一个“老师”。
      • 它通过在每个局面下进行多次随机模拟,统计各个可能走法的胜率,得到一个比较可靠的“策略分布”(每步棋的选择概率)和“局面价值”(从此局面赢的概率)。
  1. 神经网络训练的目标
      • 输入:局面(棋盘状态)
      • 输出:
        • 策略头(policy head):预测每一步棋的胜率分布
        • 价值头(value head):预测当前局面对执棋方的胜率
      • 训练时,就把 MCTS 统计出来的结果作为监督信号。
  1. 自我改进循环(例如 AlphaZero)
      • 用当前神经网络指导 MCTS 的搜索;
      • MCTS 搜索生成对局数据;
      • 用这些数据重新训练网络;
      • 新网络又更强,从而产生更高质量的数据;
      • 循环往复。

一句话总结:
是的。MCTS 就是自对弈引擎中用来“为不同局面打分”的机制,它通过统计大量随机对弈结果,为神经网络提供训练监督信号。
💡

Q: 我感觉它的思想与贝叶斯优化有点相似, 它们之间是不是有什么渊源?

非常敏锐的观察——蒙特卡洛树搜索(MCTS)与贝叶斯优化(Bayesian Optimization, BO)确实有深层的思想共通点,虽然两者应用场景完全不同。
我们可以从“算法机制”和“数学哲学”两个角度来解释这种关系。

一、核心类比:都是“在不确定性下用采样逼近最优决策”

思想
蒙特卡洛树搜索 (MCTS)
贝叶斯优化 (BO)
问题目标
在一个巨大的决策树中寻找最优行动
在一个连续空间中寻找最优输入(最大化黑箱函数)
信息特征
可以模拟但代价高,结果随机
可以评估但代价高,函数未知
学习方式
通过反复模拟,更新节点统计值
通过高斯过程或其他模型,更新后验分布
决策策略
UCB 或 PUCT:利用平均奖励 + 探索项
Acquisition Function(如 UCB、EI、PI)平衡探索与利用
核心思想
用随机模拟估计期望收益
用概率模型估计期望收益
可以看到,两者的本质都在解决“探索–利用权衡(exploration vs. exploitation)”问题
  • MCTS 在搜索树上做局部探索;
  • 贝叶斯优化在连续输入空间中做全局探索。

二、数学思想上的共通根:UCB 与贝叶斯置信区间

MCTS 的选择策略常用 UCB1 (Upper Confidence Bound)
\text{score}(a) = \bar{X}_a + C \sqrt{\frac{\ln N}{n_a}}
而贝叶斯优化的常见采集函数之一正是 GP-UCB
\text{score}(x) = \mu(x) + \kappa \sigma(x)
它们结构几乎一样:
含义(MCTS)
含义(贝叶斯优化)
均值项
当前动作平均回报
预测函数均值
不确定性项
访问次数的置信区间
后验方差的置信区间
平衡系数
C
κ(控制探索强度)
可以说:
MCTS 的 UCB 是一种“经验频率”形式的置信上界,
而贝叶斯优化的 UCB 是一种“概率分布”形式的置信上界。
两者在哲学上是同一种思想的两种实现:
“在不确定性下,优先选择
期望值高
不确定性大

三、在概念层面上的“渊源”

  • 两者都属于“Sequential Decision under Uncertainty”(不确定性下的序贯决策)范畴;
  • 都起源于 统计学习 + 强化学习 + 概率推理 的交叉领域;
  • 都可追溯到 Bandit Problem(多臂老虎机问题) 的研究:
    • 这是 UCB 理论和贝叶斯采样(Thompson Sampling)的共同源头。
换句话说:
MCTS ≈ 树状空间的非参数化贝叶斯优化。
它没有显式的高斯过程模型,而是用“多次模拟的经验平均”代替概率分布建模。

四、一句话总结

贝叶斯优化是在“连续函数空间”中做采样决策,
蒙特卡洛树搜索是在“离散树状空间”中做采样决策;
两者都用不确定性引导探索,思想上是一脉相承的。

如果你以后深入强化学习或元学习,会发现:
  • AlphaZero 的 MCTS
    • ≈ 在离散动作空间中做“经验型贝叶斯优化”;
  • 贝叶斯优化
    • ≈ 在连续空间中做“模型驱动型 MCTS”。
它们的区别更像“同一思维的两种几何形态”,而非完全不同的算法体系。
💡

Q: 我在读一个关于自我对弈的文档, 其中给出了以下指导, 但我看不太懂(例如什么是TFRecord, 什么是Shuffle, 整个训练流程大致是怎样的), 请你帮我读懂它.

There are 5 things that need to all run concurrently to form a closed self-play training loop.
Selfplay engine (C++ - cpp/katago selfplay) - continuously plays games using the latest neural net in some directory of accepted models, writing the data to some directory. Shuffler (python - python/shuffle.py) - scans directories of data from selfplay and shuffles it to produce TFRecord files to write to some directory. Training (python - python/train.py) - continuously trains a neural net using TFRecord files from some directory, saving models periodically to some directory. Exporter (python - python/export_model.py) - scans a directory of saved models and converts from Tensorflow's format to the format that all the C++ uses, exporting to some directory. Gatekeeper (C++ - cpp/katago gatekeeper) - polls a directory of newly exported models, plays games against the latest model in an accepted models directory, and if the new model passes, moves it to the accepted models directory. OPTIONAL, it is also possible to train just accepting every new model.
好的,我们一步步拆解这段话,把整个自我对弈训练流程讲清楚,并解释其中提到的术语。

一、总体理解:自我对弈闭环

这段文字描述的是一个完整的强化学习训练闭环(self-play loop),类似 AlphaGo/AlphaZero 的架构。
简单来说,就是:
模型自己下棋 → 生成数据 → 打乱整理 → 训练新模型 → 导出新模型 → 验证好坏 → 再用好模型继续下棋
整个过程是持续循环的,自动化运行。

二、五个并发模块(必须同时运行)

1. Selfplay Engine(自我对弈引擎)

作用:用当前最好的模型进行对弈,生成训练数据。
  • 语言:C++ 实现,性能高。
  • 流程:
      1. 从“已接受的模型目录”加载最新的神经网络(例如最新版本的棋力模型)。
      1. 让这个模型反复自我对弈(自己对自己下棋)。
      1. 把每一步的棋局状态、落子、胜负结果等数据写入某个“数据目录”(data directory)。
这些数据会成为神经网络的训练样本。

2. Shuffler(数据打乱器)

作用:整理并打乱(shuffle)自我对弈产生的原始数据,输出为标准化的训练文件。
  • 语言:Python 脚本(python/shuffle.py)
  • 它会:
      1. 扫描自我对弈生成的数据目录。
      1. 打乱(shuffle)这些数据,以避免训练时样本顺序有偏差。
      1. 输出为 TFRecord 文件。

什么是 TFRecord?

TFRecord 是 TensorFlow 官方的二进制数据格式,可以高效地存储和读取大量样本。
比如每个样本都包含棋盘状态、落子概率、胜负结果等,用 TFRecord 存放会比 CSV 或 JSON 更快。
简单理解:
TFRecord = “TensorFlow 训练用的二进制打包数据文件”
输出的这些 TFRecord 文件会被下一个环节(训练器)使用。

3. Training(训练器)

作用:不断读取 TFRecord 文件,训练出新的神经网络模型。
  • 语言:Python(python/train.py)
  • 流程:
      1. 从打乱后的 TFRecord 数据目录中加载样本。
      1. 使用神经网络(例如卷积网络)进行训练,更新权重。
      1. 定期保存新模型到“保存模型目录”。
这些新模型会等待被导出(Exporter 处理)。

4. Exporter(模型导出器)

作用:把 TensorFlow 格式的模型转换成 C++ 引擎可用的格式。
  • 语言:Python(python/export_model.py)
  • 流程:
      1. 扫描训练目录中保存的模型。
      1. 把 TensorFlow 的格式(例如 .ckpt 或 .pb)转换成 C++ 引擎能直接加载的格式(例如 .bin 或自定义结构)。
      1. 把转换好的模型放入“导出模型目录”。
这样 C++ 的自我对弈引擎就可以使用新模型进行下一轮对弈。

5. Gatekeeper(守门人)

作用:判断新模型是否真的比旧模型更强。
  • 语言:C++(cpp/katago gatekeeper)
  • 流程:
      1. 它从“导出模型目录”中检测到新模型。
      1. 让“新模型”与“当前已接受的模型”进行对战。
      1. 如果新模型在测试对局中获胜率超过阈值(例如 55%),则将其“晋升”为新的 accepted 模型。
      1. 如果失败,则丢弃。
这样可以避免模型“退化”(新模型训练后反而变差)。
有时为了简化实验,也可以跳过 gatekeeper,让每个新模型都自动被接受。

三、总结:训练闭环的整体流程

阶段
模块
输入
输出
说明
① 自我对弈
Selfplay Engine
最新 accepted 模型
原始对弈数据
模型自己玩棋生成训练样本
② 数据打乱
Shuffler
原始对弈数据
TFRecord 文件
清洗并随机化样本
③ 模型训练
Training
TFRecord 文件
新模型(TensorFlow 格式)
用强化学习方式更新权重
④ 模型导出
Exporter
TensorFlow 模型
C++ 可用模型
转换格式供引擎使用
⑤ 模型评估
Gatekeeper
新旧模型
更新 accepted 模型目录
确保模型迭代有效

四、简化的类比

可以把整个过程想象成:
AI 自己打牌、整理对局记录、复盘学习、生成新牌技、验证是否变强、再继续打。
整个循环自动运行,不断自我改进。

五、关键术语小结

术语
含义
Selfplay
模型自己与自己对弈以生成数据
TFRecord
TensorFlow 使用的高效二进制数据格式
Shuffle
打乱样本顺序以避免训练偏差
Exporter
转换模型格式供推理引擎使用
Gatekeeper
比赛验证新模型是否更强
💡

Q: 文档中提到Selfplay Engine(自我对弈引擎) 作用:用当前最好的模型进行对弈,生成训练数据。 问题是我在训练的最开始似乎不存在一个"当前最好的模型", 如何获取该初始模型呢?

非常棒的问题——这其实是自我对弈强化学习体系(AlphaZero / KataGo / Leela Zero)中一个最基础但关键的环节。
你的直觉完全正确:
在训练一开始,系统里根本还没有一个“最好的模型”。
那自我对弈该从哪里开始呢?
我们一步步来理解。

一、问题的核心:如何启动一个闭环系统?

自我对弈系统是一个自举系统(bootstrapping system)
它自己生成数据、自己训练、自己迭代。
但任何自举过程都需要一个最初的起点(seed model)
这个初始模型通常叫做:
初始网络(initial model / bootstrap model / random model)

二、获取“初始模型”的几种常见做法

方法 1:随机初始化模型(最常见)

最简单的做法就是:
  • 使用网络结构定义;
  • 随机初始化所有权重(例如 Xavier 初始化或 He 初始化);
  • 保存成一个“第 0 号模型”;
  • 让它直接参与自我对弈。

效果

刚开始时,这个模型完全不会下棋,只会随机落子。
但这没关系,因为:
  1. 它仍然能生成合法的棋局;
  1. 每局都有明确的胜负结果;
  1. 训练器可以学习“哪些随机落子带来胜利”;
  1. 经过多轮自我迭代后,模型会逐步学会基本规律。
这就是 AlphaZero 式自学习 的精髓:
从完全不会下棋的状态出发,仅靠自我对弈就能学会强大的策略。

方法 2:用一个已知的“弱模型”作为起点

有些项目(例如 KataGo)为了加快早期收敛
会从一个“预训练的模型”开始,而不是完全随机。
这些预训练模型可能来源于:
  • 随机对弈+短时间训练得到的初始网络;
  • 用旧版本 KataGo 训练出的基础模型;
  • 从公开模型(例如 Leela Zero)微调得到的模型。
这样可以让最初几轮自对弈数据更高质量、更快收敛

方法 3:人工生成少量样本作为起点(较少使用)

极少数实验项目会用一些人类棋谱或规则走法
让模型“学会合法落子”,然后再进入自我对弈循环。
但这不属于纯强化学习(它引入了外部知识),
更多出现在教学或实验版本中。

三、典型项目中的实际做法

项目
初始模型来源
备注
AlphaZero
随机初始化
纯自学习,无人类数据
Leela Zero
随机初始化
第一个自对弈循环的网络完全随机
KataGo
从预训练基础网络开始
用几千盘“简单规则对弈”预训练加快收敛
MiniZero / ELF OpenGo
随机或弱模型
视实现而定
在 KataGo 的代码仓中,官方也提供了一些 初始权重文件(bootstrap models)
可以作为一开始的 accepted model 放入目录中。

四、为什么随机模型也能学起来?

这是很多初学者觉得“违反直觉”的地方。
即使模型是随机的:
  • 它依然能玩出完整的棋局
  • 每盘棋都有结果(赢/输)
  • 训练器能从中学习“哪些局面倾向于赢”;
  • 下几轮后模型开始形成“稳定偏好”;
  • MCTS 搜索进一步放大这种偏好;
  • 模型逐渐稳定并变强。
换句话说:
即使一开始数据很“蠢”,但随着循环次数增加,信号会越来越有意义。

五、启动时的目录结构(简化示意)

第一次运行时,Selfplay Engine 会:
  1. 从 models/accepted/ 加载 bootstrap_model;
  1. 用它生成数据;
  1. 开始训练循环。

六、小结

阶段
是否已有模型
模型来源
作用
初始阶段
没有
手动放入一个随机或弱模型
启动自对弈
第一轮自对弈
刚放入的初始模型
生成首批训练数据
之后
有多个
来自不断训练、验证
实现强化学习闭环

如果你想自己实现这样一个系统(例如做个小实验),
我可以帮你写出一个“如何随机生成第一个自对弈模型”的流程——
包括如何定义结构、初始化、保存为引擎可加载格式。
要我帮你写那个“初始化阶段”的操作步骤吗?
💡

Q: 如何让模型自己与自己对弈? 这个过程是由引擎控制的吗?

是的,“让模型自己与自己对弈”这个过程完全是由自我对弈引擎(Selfplay Engine)控制的。
它是整个强化学习闭环的“数据生成器”,负责模拟棋局并产生训练样本。
下面我详细解释它是怎么做到“自己和自己下棋”的

一、核心思想:模型既当“黑方”又当“白方”

在自我对弈中,没有人类参与。
同一个神经网络模型被用来评估所有局面、选择每一步棋。
流程示意如下:
  1. 初始化一个空棋盘。
  1. 让模型计算当前局面的落子概率分布(policy)和胜率估计(value)。
  1. 根据概率分布(可能加上随机性或蒙特卡洛树搜索 MCTS)选择一步棋。
  1. 执行该落子,更新棋盘。
  1. 交换执方(模型再次思考,但这次是“对手”角色)。
  1. 重复直到棋局结束(胜负明确)。
  1. 把整局的每一步局面、模型输出、最后结果都记录下来。
这整个过程是自动进行的,不需要人干预。

二、是谁在“控制”对弈?

是由自我对弈引擎(Selfplay Engine)控制的。
以文档中的项目为例(KataGo),这个引擎是一个 C++ 程序,功能包括:
  • 加载模型文件(通常是一个神经网络,例如 TensorFlow 导出的 .bin 模型)。
  • 初始化游戏环境(围棋、国际象棋或其他棋类)。
  • 在每个局面调用模型进行推理,得到落子概率与胜负预测。
  • 执行搜索算法(一般是 MCTS)来平衡探索与利用。
  • 根据策略选择一步棋执行
  • 持续记录整个对局的状态与结果
  • 把这些数据写入文件系统(供后续 Shuffle 和 Train 模块使用)。
简化图示:

三、模型在自我对弈中的“输入”和“输出”

以棋类游戏为例:
项目
内容
输入
当前棋盘状态(通常编码成张量,例如19×19×N特征图)
输出
两个分支: 1. Policy head:每个合法落子的概率分布 2. Value head:当前局面对己方的胜率预测
引擎利用这些输出决定下一步该下哪。
训练时,模型学习:
  • policy head 拟合实际的落子(来自MCTS统计结果);
  • value head 拟合最后的胜负结果。

四、为什么模型能靠“自己对弈”变强?

这是强化学习(Reinforcement Learning)的核心逻辑:
  1. 模型初始很弱,只能随机对弈;
  1. 自我对弈产生大量数据;
  1. 神经网络通过学习这些对局,逐渐掌握哪些局面会带来胜利;
  1. 新模型用于下一轮自我对弈,产生更高质量的数据;
  1. 不断循环,棋力逐步提升。
这就是 AlphaGo Zero、KataGo、Leela Zero 等系统的关键机制。

五、控制流程总结

阶段
执行者
内容
模型加载
Selfplay Engine
从目录中读取当前“最优模型”
对弈执行
Selfplay Engine
运行数千场自我博弈
决策过程
模型 + MCTS
由神经网络提供概率与评估,MCTS辅助搜索
数据记录
Selfplay Engine
记录每步状态、策略、结果到文件
训练输入
Shuffler + Trainer
后续模块使用这些数据进行训练

六、你可以把它理解成:

“引擎是裁判 + 规则 + 控制系统
“模型是棋手(同时扮演黑方和白方)”
引擎不断调用模型的推理接口来选择落子。
整个对弈过程由引擎的逻辑驱动,模型只是“决策函数”。

是否希望我接下来帮你画一张图,说明“自我对弈引擎如何利用神经网络完成一局游戏”的数据流?
那张图能直观看出模型、搜索、数据记录的交互结构。
💡

Q: 解释一下以下脚本的行为

这段脚本是一个用于批量生成国际象棋局面(Self-play / Sfen生成)的自动化脚本,核心思想是:
通过向 stockfish 引擎批量发送命令,让它以指定参数运行自对弈生成局面数据。

一、脚本整体行为概览

声明使用 Bash 解释器。
设置参数:
  • DEPTH=5:每局搜索深度为 5 层;
  • GAMES=128000000:要生成的局面数量(这里是 1.28 亿);
  • SEED=$RANDOM:生成一个随机种子,确保每次运行结果不同。

二、关键部分:options 变量

这是一个要传入 Stockfish 的一串 UCI 命令序列
下面分行解释这些命令的意义。

1. 基本初始化命令

命令
作用
uci
切换到 UCI 协议模式(标准棋类引擎通信协议)
isready
等待引擎初始化完成

2. 引擎配置选项

命令
说明
setoption name PruneAtShallowDepth value false
关闭浅层剪枝,让引擎在低深度时保留更多搜索分支,利于多样化局面
setoption name Use NNUE value pure
强制使用 NNUE(神经网络评估)模式,而非传统评估函数
setoption name Threads value 250
使用 250 个线程(显然是为高并发环境或集群机器设计)
setoption name Hash value 10240
分配 10GB 哈希表内存(10240 MB)
setoption name SyzygyPath value ...
设置残局表库路径,用于精确残局评估

3. 核心命令:gensfen ...

gensfen 是 Stockfish 的一个扩展命令(不属于标准 UCI),
用于批量生成随机或自对弈的 SFEN(Shogi FEN,或类似格式) 局面。
在强化学习中,这些局面可作为训练样本。
参数含义如下:
参数
含义
set_recommended_uci_options
使用推荐的 UCI 参数
ensure_quiet
确保输出时不包含调试或噪声信息
random_multi_pv 4
随机生成 4 个不同的主变(PV)线路
random_multi_pv_diff 50
允许多PV之间评估差异最大为50分(增加多样性)
random_move_count 8
每局最多随机8步
random_move_maxply 20
随机探索最多20个半回合(ply)
write_minply 5
只写出至少经过5个半回合的局面
eval_limit 1000
限制评估节点上限,控制计算开销
seed $SEED
随机种子
depth $DEPTH
搜索深度
loop $GAMES
迭代次数(生成局面数量)
output_file_name d${DEPTH}_${GAMES}_${SEED}
输出文件名,例如:d5_128000000_12345

三、执行部分

这行命令的意思是:
把 $options 中的全部命令逐行“打印”,
并通过管道符 | 把它们输入给 ./stockfish 可执行文件。
效果上就像你在命令行手动打开 Stockfish,然后一行一行输入这些命令。

四、整体逻辑总结

整个脚本的流程:
  1. 初始化环境参数(深度、局面数、随机种子)。
  1. 设置 Stockfish 的搜索和运行参数。
  1. 调用 gensfen 命令让引擎批量生成带随机性的局面(用于训练数据)。
  1. 输出结果写入文件 d<depth>_<games>_<seed>。
最终输出的文件将包含成千上万条(或亿级)随机对弈生成的棋局样本,用于后续:
  • 神经网络训练(例如AlphaZero式自我博弈数据);
  • 局面评估学习;
  • NNUE 数据生成。

五、简要概括一句话

这段脚本是一个自动化调用 Stockfish 的数据生成器,
它用大量随机化的自对弈在指定深度下生成训练局面,
并将结果保存到文件中,供后续机器学习或NNUE训练使用。
💡

Q: 你提到setoption name Hash value 10240这条命令是为了分配 10GB 哈希表内存(10240 MB), 此处哈希表和哈希值是干嘛用的?

非常好的问题,这一点其实是理解棋类引擎工作机制的关键。
下面我分几层解释:什么是哈希表、Stockfish 为什么需要它、它存的“哈希值”是什么、以及为什么要设成这么大。

一、哈希表在棋类引擎中的作用

在国际象棋引擎(如 Stockfish)中,哈希表(Hash Table) 通常指的是一种叫做 Transposition Table(置换表) 的结构。
它的核心目的是:
在搜索树中缓存已经计算过的局面(position)及其评估结果,避免重复计算。
因为在国际象棋中,不同的走子序列可能到达同一个棋局。
例如:
虽然走法顺序不同,但最终局面是一样的。
如果引擎每次都重新搜索这个局面,会浪费大量计算资源。
因此 Stockfish 在搜索过程中,会将每个局面的 哈希值(唯一标识) 作为键(key),
将其 搜索结果(分数、深度、最佳着法等) 存入哈希表。

二、哈希值是什么

Stockfish 为每一个局面计算一个唯一标识码,叫作 Zobrist Hash
这是一种通过随机数异或(XOR)计算出的、几乎唯一的 64 位整数。
计算方式大致是这样:
  • 为每个棋子+位置的组合预先分配一个随机数;
  • 例如:
    • 白方国王在 e1 的随机数;
    • 黑方兵在 c7 的随机数;
    • 等等。
  • 当前局面的哈希值 = 对所有棋子随机数做 XOR;
  • 再加上回合信息、王车易位权利、吃过路兵权等。
这样生成的哈希码能唯一代表一个局面。
Stockfish 搜索时:
  1. 对当前局面计算 Zobrist Hash;
  1. 查询哈希表中是否已有此哈希;
  1. 如果有,就直接用缓存结果,跳过重复搜索;
  1. 如果没有,就进行搜索,并把结果写入表中。

三、哈希表中存的内容

哈希表的每一项一般包含:
字段
含义
Key
Zobrist 哈希值(64位)
Depth
搜索到的深度
Score
评估分数(例如 +0.23 表示略优)
Move
在该局面下的最佳着法
Bound
表示该分数是下界、上界还是精确值
Age
用于淘汰旧条目(当表满时)
这些内容在 Stockfish 搜索函数(AlphaBeta 或 Negamax)中会频繁读写。

四、为什么要设置Hash value 10240

setoption name Hash value 10240
表示为哈希表分配 10240 MB = 10 GB 内存
这个数值决定了缓存容量。
缓存越大,命中率越高,重复搜索越少,速度越快。
但也占用更多内存。
通常:
  • 家用设备:512MB ~ 2GB 已足够;
  • 大规模训练或多线程并行(如脚本里 Threads=250):需要更大哈希表以减少线程间冲突。

五、总结

概念
含义
哈希表 (Transposition Table)
缓存已搜索局面的结果
哈希值 (Zobrist Hash)
唯一标识一个棋局状态
作用
避免重复搜索、加速搜索过程
Hash value 参数
设置哈希表所占内存大小(以MB为单位)
一句话总结:
在 Stockfish 中,哈希表相当于一个巨大的“搜索记忆库”, 哈希值是每个局面的“指纹”。 它们共同让引擎不再“健忘”,从而能以指数级加速搜索速度。
胶片里的苏州写真之道
Loading...
目录
0%
JAY
JAY
Textbooks shouldn’t require a cryptologist to decode -- welcome to readable software engineering.
目录
0%