- 强化学习
- 深度学习
- 人工智能
【免费下载链接】PufferLib
Puffing up reinforcement learning
Guerrilla Checkers 是 PufferLib 内置的一款棋盘类强化学习环境,它把 Checkers(国际跳棋)与 Go(围棋)的规则不对称地混合在一起,一方扮演"游击队"、另一方扮演"金币",形成了与常规对称棋类截然不同的博弈结构。本指南以仓库中的 ocean/guerrillacheckers/README.md 为核心,结合 ocean/guerrillacheckers/guerrillacheckers.h、ocean/guerrillacheckers/mcts.h 与 config/guerrillacheckers.ini 的源码与配置实现,完整讲解:如何理解这个不对称环境的状态与动作空间、如何启动标准 5c 自对弈训练、如何保持新旧检查点格式兼容、以及如何构建独立客户端并对候选模型做与 Puffer 40 基线的交叉对局评估。
读完本文,你将掌握一套可直接复用的训练、评估与基线对照工作流,并理解其中每一项关键配置在源码层面的真实作用。
游戏规则:Checkers 与 Go 的不对称混合
Guerrilla Checkers 在源码头部被明确注释为 "an asymmetric hybrid of Checkers and Go"(参见 ocean/guerrillacheckers/guerrillacheckers.h)。棋盘由8×8的 COIN 格网与7×7的游击队格点叠加而成:
| 常量 | 值 | 含义 |
|---|---|---|
GC_BOARD_W / GC_BOARD_H | 8 / 8 | COIN 棋子所在格网 |
GC_G_W / GC_G_H | 7 / 7 | 游击队落子点网格 |
GC_COIN_CELLS | 64 | COIN 格点数 |
GC_G_CELLS | 49 | 游击队格点数 |
GC_MAX_GUERRILLAS | 66 | 游击队最多可投放的石子数 |
GC_ACTIONS | 256 | 动作头宽度 |
GC_PASS_ACTION | 255 | 非活跃槽位的确定性 pass 动作 |
GC_OBS_SIZE | 120 | 观测长度(49 + 64 + 7) |
GC_INVALID_ACTION_REWARD | -1.0 | 非法动作的负反馈 |
GC_MAX_BANKS | 8 | 历史银行(对手池)最大数量 |
规则要点(均可从 ocean/guerrillacheckers/guerrillacheckers.h 的gc_*系列函数中确认):
- 初始局面:
puf_reset在 6 个固定坐标{3,2},{2,3},{4,3},{3,4},{5,4},{4,5}放置金币(见 guerrillacheckers.h)。 - 游击队(Guerrilla)先手:每个回合可以在格点上连放两枚相邻的石子(第一枚与已有石子邻接,第二枚必须与第一枚邻接),
GC_MAX_GUERRILLAS = 66是全局投放上限。 - 金币(COIN)移动:金币沿对角方向移动,若跳越相邻的游击队格点则"吃掉"该石子;吃到后若仍可继续连跳,则强制继续(
coin_must_capture标志)。 - 包围吃子:一枚金币若被其四角全部占据游击石子,即被提走(
gc_check_guerrilla_capture)。 - 胜负判定(
gc_check_victory):金币被全部清除 → Guerrilla 胜;游击队用尽 66 枚或场上无合法落点 → COIN 胜。 - 超时判定(
gc_check_timeout):到达max_episode_length步仍胜负未分时,直接判 Guerrilla 负(COIN 胜),因为 Guerrilla 的唯一胜利条件就是清空棋盘。
这种"一方通过围困蚕食、另一方通过跳吃反制"的非对称设计,是研究非对称博弈、不同行动节奏(回合内连放两子 vs 单步移动)与稀疏奖励的理想测试床。
检查点格式:Puffer 40 基线与新 5c 模型的兼容契约
仓库为 Guerrilla Checkers 保留了"原版 Puffer 40"作为新标准 5c 自对弈模型的评估基线。README 记录的唯一基线检查点如下:
| Checkpoint | Purpose | SHA-256 |
|---|---|---|
guerrillacheckers_weights.bin | Original Puffer 40 | f58615069b9a0e50105dd54b4729d366d602fe14b957a0042e4dc88089120398 |
两种布局的差异需要特别留意:
- Puffer 40使用旧的587,264 字节 biased 布局;
- 新训练的标准 5c 检查点使用586,240 字节 bias-free 布局,且带 value-head 行;
- 独立评估器(standalone evaluator)会直接自动检测这两种格式,因此新旧检查点可以用同一套评估流程、在完全相同的输入上对局。
这得益于 guerrillacheckers.h 中的"原生 5c 构建契约":
#define OBS_SIZE GC_OBS_SIZE // 120 #define NUM_ATNS 1 #define ACT_SIZES {GC_ACTIONS} // 单头 256 动作 #define PUF_STEPS_PER_SEC 3代码注释明确写道:保持与原始 Puffer 策略契约一致,是为了"让新旧检查点能够在相同输入上被评估"。这也解释了为什么 README 强调标准 5c 检查点带 value-head 行——旧模型只有 policy 头,新模型额外携带 value 头,评估器需要能分辨两者。
训练:真正交替的自对弈(genuine alternating self-play)
启动命令
./puffer train guerrillacheckers该命令的 env 名guerrillacheckers由 config/guerrillacheckers.ini 的[base] env_name决定,训练器编译环境的方式见 build.sh(默认编译ocean/guerrillacheckers/guerrillacheckers.h,产出./puffer)。
自对弈机制:双逻辑策略槽位
README 明确描述了这套"真正交替自对弈 + 随机化 sides"的机制,其源码实现在Env结构体与gc_actor_slot/gc_rebuild_action_mask中:
- slot 0 是可训练策略,slot 1 是当前或历史对手;
- 每局开始时随机决定哪一方由哪个槽位扮演(
side_cfg = 0表示每局随机),保证两边都被两个槽位充分训练到; - 非活跃槽位每步收到一个确定性 pass 动作(动作 255)。在 guerrillacheckers.h 中注释了设计意图:pass 动作在正常对局中不可能出现(它是右下角金币格网向外的越界移动),因此既能让等待槽位保持"每步一个动作"以维持 PPO 与循环状态的更新有效性,又不会被误用;
- 两个槽位的循环状态(recurrent states)在每个游戏步都观察到完整局面,遵循已有的 Ocean Chess 自对弈约定(见 ocean/chess/chess.h);
- 20% 的环境使用历史银行(historical bank),即对手来自冻结的历史快照池;
- 对手交换只在所有 tagged 游戏都到达 episode boundary 之后进行,避免在局中打断,保证策略切换的干净边界。
关键配置逐项解读
config/guerrillacheckers.ini 是标准训练的规范配置,以下为各节参数及其源码层面的作用:
[base] env_name = guerrillacheckers # 一个 epoch = 4096 agents * 64 horizon = 262,144 agent steps。 # 每 20 个 epoch 存一次快照,历史池大约每 5.24M 步收到一个新策略。 checkpoint_interval = 20 [selfplay] enabled = 1 max_size = 100 seed = 42 # 冻结银行大约按快照产出频率刷新;加载推迟到所有 tagged 游戏到达 episode boundary。 opp_timeout_steps = 5_000_000 [vec] total_agents = 4096 num_buffers = 8 num_threads = 8 num_policies = 2 # 80% 当前对当前,20% 对历史池。 hist_policy_percent = 0.2 hist_policy_hidden_size = 128 hist_policy_num_layers = 2 [env] # 硬性步数上限;超时判 Guerrilla 失败(COIN 胜)。 max_episode_length = 256 # selfplay = 1:两个策略槽位交替 sides;历史池环境中 slot 0 是主策略,slot 1 是冻结对手。 # selfplay = 0:策略以 `side` 与内置 `opponent` bot 对局。 selfplay = 1 # slot 0(主策略)在自对弈中扮演的 side,或 bot 模式下 agent 的 side: # 0 = 每局随机,1 = Guerrilla,2 = COIN。 side = 0 # selfplay = 0 时的对手 bot:0 = random,1 = greedy(最大化吃子),2 = mcts。 opponent = 1 # MCTS 对手参数(opponent = 2 时使用)。迭代越多越强、越慢。 mcts_iterations = 256 mcts_exploration = 0.7 # rollout 策略:0 = random(忠实 UCT),1 = greedy(更强,尤其是 Guerrilla 侧)。 mcts_rollout = 1 [policy] hidden_size = 128 num_layers = 2 [train] total_timesteps = 100_000_000 gamma = 0.98 # 本环境是稀疏的 256 路动作头;action mask 负责合法性, # 低熵系数让探索不至于与 mask 过度对抗。 ent_coef = 0.0001要点说明:
num_policies = 2对应自对弈中的两个逻辑槽位;hist_policy_percent = 0.2使 20% 环境接入历史银行,这与 README 中"Twenty percent of environments use the historical bank"一致;side = 0的随机化语义在 guerrillacheckers.h 中实现:side_cfg为 1/2 时固定槽位归属,否则按随机位分配;max_episode_length = 256直接驱动gc_check_timeout的超时判负逻辑;ent_coef = 0.0001的低熵压力,是为了让探索不干扰 action mask 的合法性约束(非法动作会被 mask 屏蔽,且puf_step对非法动作按GC_INVALID_ACTION_REWARD = -1.0的"负向 no-op"处理,不即时判负,由超时兜底——详见 guerrillacheckers.h)。
观测、动作与奖励的编码细节
观测(OBS_SIZE = 120)
每个槽位看到完全相同的绝对棋盘编码(源码注释强调这是为了保持原始检查点契约),顺序为 guerrillacheckers.h:
GC_G_CELLS = 49:游击队占位(0/1);GC_COIN_CELLS = 64:金币占位(0/1);- 7 个标量:当前行动方 side id(Guerrilla=1 / COIN=2)、
coin_must_capture标志、金币上一格(+1,-1 记 0)、游击队上一格(+1)、本回合已放子数、游击队总投放数、场上现存游击队石子数。
动作编码(256 路单头)
- Guerrilla 动作:
action = first * 4 + dir,其中first是 49 个格点之一,dir映射为四个方向({2,3,0,1},即下/右优先,保证 reset 后动作 0 合法),落子点在first与其该方向邻居——一个动作即"连放两枚相邻石子"; - COIN 动作:
action = src * 4 + dir,src为 64 个金币格之一,dir为四个对角方向; - 合法动作由
gc_rebuild_action_mask实时枚举生成(gc_enumerate_legal),写入行动槽位的action_mask。
奖励设计
- 每局终止时胜方 +1.0、负方 -1.0(自对弈中按
slot_for_side[winner]结算到具体槽位); - 吃子即时奖励:Guerrilla 每次吃子 +0.05 × 枚数,COIN 每次 +0.03 × 枚数(guerrillacheckers.h);
- 非法动作:
GC_INVALID_ACTION_REWARD = -1.0作为负向 no-op; invalid_rate统计每局决策中非法动作占比,是评估/训练日志中重要的健康度指标。
Log结构(guerrillacheckers.h)记录了 perf、score、episode_return/length、invalid_rate、按阵营统计的胜负场次、slot 0/1 得分,以及hist_score_bank[0..7]的历史银行分槽统计——这些字段在puf_log中全部导出为训练日志,用于监控自对弈进程。
评估:构建独立客户端并与 Puffer 40 基线对比
构建与对比命令
README 给出的完整评估流程:
./build.sh guerrillacheckers --fast ./guerrillacheckers --compare-candidate 1000 \ .runtime/checkpoints/guerrillacheckers/<run>/<checkpoint>.bin- 第一步构建独立客户端(standalone client)并产出可执行文件
./guerrillacheckers; - 第二步让原生候选模型与原始 Puffer 40从两侧各下 1000 局(
--compare-candidate 1000为局数参数),候选检查点路径位于.runtime/checkpoints/guerrillacheckers/<run>/<checkpoint>.bin; - 独立客户端同时内建了人类对战能力:在 raylib 窗口中按住 Left Shift 点击即可"先选点、再选目标"地手动走棋(
gc_human_controls,见 guerrillacheckers.h)。
关于构建的一般性说明:仓库根目录的 build.sh 同时支持./build.sh guerrillacheckers(原生训练/评估,产出./puffer)、./build.sh guerrillacheckers mybin(自定义输出名)、以及--cpu模式构建独立 CPU 评估二进制(产出./build/cpu_guerrillacheckers,要求环境头必须typedef obs_t)。README 中记录的--fast是针对独立客户端的快速构建选项,以其为准即可。
基线交叉对局表(每格 100 局,Guerrilla wins - COIN wins)
README 记录的基线字段为每格 100 局、以"Guerrilla 胜 - COIN 胜"形式展示:
| Guerrilla / COIN | Random | Greedy | Puffer 40 | MCTS 2K | MCTS 10K |
|---|---|---|---|---|---|
| Random | 8-92 | 0-100 | 0-100 | 0-100 | 0-100 |
| Greedy | 98-2 | 33-67 | 1-99 | 0-100 | 0-100 |
| Puffer 40 | 96-4 | 99-1 | 15-85 | 12-88 | 9-91 |
| MCTS 2K | 99-1 | 100-0 | 50-50 | 30-70 | 11-89 |
| MCTS 10K | 100-0 | 100-0 | 84-16 | 81-19 | 65-35 |
分侧 Bradley-Terry Elo(锚定 Elo 1500)
README 同时给出了**分侧(side-specific)**的 Bradley-Terry 拟合 Elo,锚定基准为 1500,覆盖全部 10 个分侧条目:
| Bot | Guerrilla Elo | COIN Elo |
|---|---|---|
| Random | 338 | 727 |
| Greedy | 1120 | 1189 |
| Puffer 40 | 1636 | 1879 |
| MCTS 2K | 1834 | 1969 |
| MCTS 10K | 2200 | 2108 |
两点值得注意:同一策略扮演不同阵营时强度差异明显——Puffer 40 的 COIN Elo(1879)显著高于其 Guerrilla Elo(1636),MCTS 10K 则反过来(Guerrilla 2200 vs COIN 2108),这与环境的不对称规则直接相关;基线表中 MCTS 10K 作为 Guerrilla 对阵任何对手都保持压倒性胜率,而作为 COIN 对阵同级别 MCTS 对手时胜率下降(65-35 vs 同 Bot 行),这些数据是评估新模型时必须对照的分侧基线。
内置对手与 MCTS 实现
当selfplay = 0(bot 模式)时,agent 在puf_step内与内置 bot 对局。对手由opponent参数选择(枚举见 guerrillacheckers.h):
- Random(
GC_BOT_RANDOM = 0):均匀随机挑选合法动作; - Greedy(
GC_BOT_GREEDY = 1):使用gc_action_capture_score对每个合法动作做不改动棋盘的即时吃子评估,选取吃子数最多的动作(并列时随机),见gc_greedy_pick; - MCTS(
GC_BOT_MCTS = 2):完整 UCT 搜索,实现在 ocean/guerrillacheckers/mcts.h 中。
MCTS 对手的实现要点(从源码结构看):
- 移植自参考实现
nico/guerrillacheckers/src/mcts.nim,采用完美信息单树 UCT:每步决策构建一棵树,wins 从"移入该节点的玩家"视角存储,因此最大化子节点胜率即选择当前行动方的最优着法; - 节点池化:每次迭代最多展开一个节点,因此池大小取
itermax + 1(mcts.h),迭代循环只克隆棋盘状态(GuerrillaCheckers s = *env后清空 agent 缓冲); - UCB1 选择:探索常数默认
0.7(≈ sqrt(2)/2,与参考引擎一致),由mcts_exploration覆盖; - rollout 策略二选一(
mcts_rollout):0为均匀随机 playout(忠实 UCT),1为 greedy 吃子最大化 playout——源码注释指出 greedy rollout 在宽阔的 Guerrilla 侧明显更强,但单次迭代成本更高; - 选择最终着法时采用最高访问次数子节点(most-visited child)而非最高胜率,这是 UCT 的标准稳健做法。
MCTS 的mcts_iterations(默认 256)、mcts_exploration(默认 0.7)、mcts_rollout(默认 1)三项旋钮全部来自 config/guerrillacheckers.ini 的[env]节,在puf_init中读取并存入Env结构体。
实操建议与注意事项
- 用基线先行验证评估链路:在评估任何新候选模型前,先用
guerrillacheckers_weights.bin(SHA-256f58615069b9a0e50105dd54b4729d366d602fe14b957a0042e4dc88089120398)跑一遍--compare-candidate,确认评估器能同时识别 587,264 字节的 biased 布局与 586,240 字节的 bias-free + value-head 布局。 - 关注分侧表现而非总胜率:由于规则不对称,同一模型的 Guerrilla Elo 与 COIN Elo 往往相差数百点。评估新模型时应分别对照 README 的十个分侧条目,而不是只看整体胜率。
- 自对弈健康度监控:训练日志中的
invalid_rate、slot_0_score_as_guerrilla/slot_0_score_as_coin与hist_score_bank_*分别反映合法性、分侧强度与历史对手池的对抗进程;对手池交换被刻意推迟到所有 tagged 游戏到达 episode boundary,这是保证策略切换干净的关键设计。 - 超时兜底语义:
max_episode_length超时判 Guerrilla 负而非当前行动方负(guerrillacheckers.h 注释),这在 bot 模式下避免超时总是落在学习者头上——理解这一点对解释边界样本的奖励归属很重要。 - 构建环境:所有构建入口统一在仓库根目录的 build.sh,无需修改任何源码即可完成
./puffer train guerrillacheckers、独立客户端构建与--compare-candidate评估全流程。
小结
Guerrilla Checkers 是一个罕见的非对称混合规则棋盘博弈,PufferLib 为其提供了完整的训练、评估与基线闭环:genuine alternating self-play的双槽位机制与历史银行保证了稳定的对手进化;586,240 / 587,264两种检查点布局的自动识别让新旧模型可以在同一契约下对局;分侧 Elo 与交叉胜负表则给出了透明、可复现的评估锚点。对研究非对称博弈、回合节奏差异与稀疏奖励的读者来说,这是一套可以立即上手的实验台。
- 强化学习
- 深度学习
- 人工智能
【免费下载链接】PufferLib
Puffing up reinforcement learning
相关推荐
KaTrain 完全指南:基于 KataGo 的围棋复盘、AI 对弈与分布式训练实战手册
KaTrain 完全指南:基于 KataGo 的围棋复盘、AI 对弈与分布式训练实战手册 KaTrain 是一款以 KataGo 分析引擎为核心的围棋(Badu
AI 应用桌面应用教育KaTrain围棋AI训练平台:5步完成智能对弈环境搭建终极指南
KaTrain围棋AI训练平台:5步完成智能对弈环境搭建终极指南 想要通过AI技术快速提升围棋水平吗?KaTrain正是你需要的智能对弈伙伴!这个基于KataG
AI 应用桌面应用教育PaddleNLP 向量检索模型对比学习训练与评估实战指南
PaddleNLP 向量检索模型对比学习训练与评估实战指南 导读 本文基于 PaddleNLP 仓库中 slm/pipelines/examples/contr
人工智能大模型预训练微调LoRARLHF强化学习分布式训练模型推理服务推理引擎模型量化模型压缩本地部署NLP
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考