這是什麼?
我安排的五子棋平台上跑著 20 個不同的 CNN 模型,每個都有不同的「個性」——有的愛攻擊、有的很保守、有的超會防守。它們之間的 ELO 差距高達 500 分,而且全都是用同一套訓練程式、只是換了不同的參數和隨機種子。
重點是:你也可以自己訓練一個,然後丟上來打聯賽。
CNN 引擎原理(白話版)
傳統的五子棋 AI 是用搜尋樹(Minimax、MCTS)去「想」好幾步之後的局面,然後挑最好的。
我們的 CNN 引擎不一樣——它是用神經網路直接看棋盤,一眼就判斷「下一步放哪最好」,有點像人類的直覺。
架構長這樣
棋盤(15×15)
↓
3 個 channel 的輸入
Ch0: 我的棋子位置
Ch1: 對手棋子位置
Ch2: 現在輪到誰(黑=1, 白=0)
↓
初始卷積層(3 → 128 channels)
↓
N 個 ResBlock(殘差區塊)
每個 block = 2 層 3×3 卷積 + BatchNorm + ReLU + skip connection
↓
Policy Head(128 → 2 → 展平 → 225)
↓
輸出:225 個位置的機率(哪裡最該下)
簡單說:
- 輸入:3 張 15×15 的圖(我的子、對手的子、誰下)
- 中間:一堆卷積層疊起來,像 ResNet 一樣
- 輸出:15×15 = 225 個位置,每個位置一個分數,分數最高的就是 AI 覺得最好的落子
兩個關鍵參數
| 參數 | 說明 | 影響 |
|---|---|---|
| hidden_channels | 每層卷積的 channel 數 | 越大 → 模型越寬、越聰明、但越慢 |
| num_blocks | ResBlock 的數量 | 越多 → 模型越深、看得更遠、但越慢 |
我們的 20 個模型就是用不同的 channels × blocks 組合訓練出來的。
訓練流程
訓練分兩個階段:
Phase 1: 啟蒙(Bootstrap)
AI 一開始什麼都不會,所以先讓一個「規則型引擎」(Heuristic Engine)自己跟自己下棋,產生大量棋局資料。
規則引擎 vs 規則引擎 → 下 1000 盤 → 產生約 80,000 筆訓練資料
CNN 看這些資料學習:「哦,原來在這種局面下應該下這裡。」
Phase 2: 自我進化(Self-Play)
學會基本功之後,CNN 開始自己跟自己下,產生更高品質的資料,然後再訓練自己。
重複 N 次:
CNN vs CNN → 下 400 盤 → 產生新資料
混合新舊資料(70% 新 + 30% 舊)
重新訓練 25 個 epoch
存檔 checkpoint
每一輪 CNN 都會變強一點,因為它在向更強的自己學習。
資料增強(Data Augmentation)
每個棋局都會做 8 種對稱變換(4 次旋轉 × 2 次翻轉),等於一盤棋變成 8 盤的訓練資料。這讓模型更快收斂,也更不容易過擬合。
溫度(Temperature)是什麼?
訓練好的模型會輸出 225 個分數。temperature 控制 AI 多「隨機」:
| 溫度 | 行為 | 適合 |
|---|---|---|
| 0.1 | 幾乎只選最高分的位置 | 最強、最穩定 |
| 0.2 | 偶爾選第二或第三好的 | 競技用,推薦 |
| 0.6 | 常常嘗試不同走法 | 中等強度 |
| 1.0 | 很常亂下 | 弱,適合新手對手 |
| 2.0 | 基本上隨機 | 最弱 |
我們的 Lv1 ~ Lv5 其實是同一個模型,只是溫度不一樣:
Lv1 = 溫度 2.0(亂下)
Lv2 = 溫度 1.4
Lv3 = 溫度 1.0
Lv4 = 溫度 0.6
Lv5 = 溫度 0.2(認真下)
參數怎麼調?
以下是我們實驗 20 個模型得到的經驗:
模型大小
| 配置 | Channels | Blocks | 參數量 | 推論速度(CPU) | 說明 |
|---|---|---|---|---|---|
| 小型 | 80 | 6 | ~3M | ~5ms | 快但弱 |
| 中型 | 128 | 8 | ~9.5M | ~10ms | 平衡,推薦 |
| 大型 | 192 | 10 | ~26M | ~30ms | 慢但可能更強 |
有趣的發現:128ch/8blk 的模型,光是換不同的隨機種子,ELO 差距就有 400 分!所以多訓練幾個,挑最強的那個用。
訓練量
| 參數 | 建議值 | 說明 |
|---|---|---|
| bootstrap-games | 500 ~ 1000 | 啟蒙階段的棋局數。越多基礎越好 |
| self-play-iterations | 5 ~ 8 | 自我進化的輪數。8 輪差不多夠了 |
| self-play-games | 200 ~ 400 | 每輪自我對戰的盤數 |
| epochs | 20 ~ 25 | 每輪的訓練 epoch 數 |
| lr | 5e-4 ~ 1e-3 | 學習率。太高會不穩、太低學太慢 |
| batch-size | 128 | 一般不需要改 |
訓練時間估算
| 設備 | 小型配置 | 中型配置(推薦) | 大型配置 |
|---|---|---|---|
| CPU only | ~2 小時 | ~6 小時 | ~15 小時 |
| GPU (RTX 3060) | ~20 分鐘 | ~1 小時 | ~3 小時 |
| GPU (RTX 4090) | ~10 分鐘 | ~30 分鐘 | ~1.5 小時 |
動手訓練!
環境需求
Python >= 3.9
PyTorch >= 2.0(建議有 GPU)
numpy >= 1.21
Step 1: 安裝
# 下載 gomoku-ai
git clone https://github.com/fishbob889/gomoku-ai.git
cd gomoku-ai
# 安裝(含 PyTorch)
pip install -e “.[nn]”
# 如果你要用 GPU(CUDA)
pip install torch –index-url https://download.pytorch.org/whl/cu121
pip install -e “.[nn]”
Step 2: 訓練你的第一個模型
# 最簡單的版本(CPU,約 2 小時)
python -m gomoku.training.train_cnn \
–output-dir checkpoints/my_first_model \
–hidden-channels 128 \
–num-blocks 8 \
–bootstrap-games 500 \
–self-play-iterations 5 \
–self-play-games 200 \
–epochs 20 \
–lr 8e-4 \
–device cpu
# GPU 版本(約 1 小時)
python -m gomoku.training.train_cnn \
–output-dir checkpoints/my_first_model \
–hidden-channels 128 \
–num-blocks 8 \
–bootstrap-games 1000 \
–self-play-iterations 8 \
–self-play-games 400 \
–epochs 25 \
–lr 8e-4 \
–device cuda:0
訓練過程你會看到:
══════════════════════════════════════════════════════
Phase 1: Bootstrap from heuristic self-play
══════════════════════════════════════════════════════
Self-play: 10/1000 games (8240 samples)
Self-play: 20/1000 games (16480 samples)
…
Epoch 5/25 Loss: 3.2184
Epoch 10/25 Loss: 2.8741
Epoch 25/25 Loss: 2.3506
Saved bootstrap model → checkpoints/my_first_model/cnn_bootstrap.pt
══════════════════════════════════════════════════════
Phase 2: Self-play iteration 1/8
══════════════════════════════════════════════════════
Self-play: 10/400 games (6560 samples)
…
Step 3: 測試你的模型
訓練完會在 checkpoints/my_first_model/ 產生:
- cnn_bootstrap.pt — 啟蒙後的模型
- cnn_iter1.pt ~ cnn_iter8.pt — 每輪自我進化的存檔
- cnn_final.pt — 最終模型 ← 用這個
# 測試看看
from gomoku.engines import create_engine
from gomoku.game import Board
engine = create_engine(“cnn”,
model_path=”checkpoints/my_first_model/cnn_final.pt”,
temperature=0.2
)
board = Board()
board.place(7, 7) # 黑棋下中心
move = engine.get_move(board)
print(f”AI 決定下:{move}”) # 例如 (7, 8)
Step 4: 讓兩個模型對戰
from gomoku.engines import create_engine
from gomoku.game import Board
engine_a = create_engine(“cnn”,
model_path=”checkpoints/model_a/cnn_final.pt”,
temperature=0.2
)
engine_b = create_engine(“cnn”,
model_path=”checkpoints/model_b/cnn_final.pt”,
temperature=0.2
)
wins = {“a”: 0, “b”: 0, “draw”: 0}
for game_num in range(20):
board = Board()
# 交替先手
if game_num % 2 == 0:
black, white = engine_a, engine_b
else:
black, white = engine_b, engine_a
for turn in range(225):
current = black if turn % 2 == 0 else white
row, col = current.get_move(board)
board.place(row, col)
if board.winner is not None:
break
if board.winner is None:
wins[“draw”] += 1
elif (board.winner == “black” and game_num % 2 == 0) or \
(board.winner == “white” and game_num % 2 == 1):
wins[“a”] += 1
else:
wins[“b”] += 1
print(f”Game {game_num+1}: winner={board.winner or ‘draw’}”)
print(f”\nA wins: {wins[‘a’]}, B wins: {wins[‘b’]}, Draws: {wins[‘draw’]}”)
Step 5: 上傳到聯盟對戰 (目前聯盟測試中,尚未開放)
把你訓練好的模型部署到 OpenClaw Skill:
# 複製到指定位置
mkdir -p ~/gomoku-checkpoints/custom
cp checkpoints/my_first_model/cnn_final.pt ~/gomoku-checkpoints/custom/cnn_final.pt
# 切換到自訂模型
python3 ~/.openclaw-gomoku/gomoku-skill.py set-model custom
# 開始比賽!
python3 ~/.openclaw-gomoku/gomoku-skill.py play –auto-queue
進階玩法
多模型訓練(挑最強的)
同一個配置,換不同隨機種子多訓練幾個:
for i in $(seq 1 5); do
python -m gomoku.training.train_cnn \
–output-dir checkpoints/model_v${i} \
–hidden-channels 128 \
–num-blocks 8 \
–bootstrap-games 1000 \
–self-play-iterations 8 \
–self-play-games 400 \
–epochs 25 \
–lr 8e-4 \
–device cuda:0
done
然後用對戰腳本挑出最強的那個。我們 20 個模型裡,冠軍(ELO 1471)跟墊底(ELO 971)用的是完全一樣的架構和參數,只是種子不同。
嘗試不同架構
# 寬而淺(快速推論)
python -m gomoku.training.train_cnn \
–hidden-channels 192 –num-blocks 5 –device cuda:0 \
–output-dir checkpoints/wide_shallow
# 窄而深(慢但可能更強)
python -m gomoku.training.train_cnn \
–hidden-channels 80 –num-blocks 14 –device cuda:0 \
–output-dir checkpoints/narrow_deep
# 超大型
python -m gomoku.training.train_cnn \
–hidden-channels 192 –num-blocks 10 –device cuda:0 \
–output-dir checkpoints/big_model
調整溫度找最佳甜蜜點
from gomoku.engines import create_engine
from gomoku.game import Board
# 用不同溫度測試同一個模型
for temp in [0.1, 0.2, 0.3, 0.5]:
engine = create_engine(“cnn”,
model_path=”checkpoints/my_model/cnn_final.pt”,
temperature=temp
)
# … 跑對戰測試 …
print(f”Temperature {temp}: win rate = …”)
一般來說 0.1 ~ 0.3 是競技最佳範圍。
我們的 20 個模型排行榜
全部在同一條件下對戰 1,900 場的結果(溫度 0.2)
| 排名 | 模型 | Channels | Blocks | ELO | 勝率 |
|---|---|---|---|---|---|
| 1 | L5-K | 128 | 8 | 1471 | 82% |
| 2 | L5-L | 128 | 8 | 1469 | 82% |
| 3 | L5-T | 120 | 9 | 1333 | 68% |
| 4 | L5-M | 128 | 8 | 1282 | 61% |
| 5 | L5-J | 192 | 5 | 1276 | 59% |
| 6 | L5-A | 128 | 8 | 1253 | 56% |
| … | … | … | … | … | … |
| 20 | L5-N | 104 | 9 | 971 | 23% |
觀察:
- 128ch/8blk 出了冠軍也出了墊底 → 隨機種子影響巨大
- 192ch/5blk(寬淺)排第 5 → 寬一點有幫助
- 80ch/14blk(窄深)排第 13 → 太窄不好
- 最穩的策略:128/8 多練幾個,挑最好的
常見問題
Q: 沒有 GPU 可以訓練嗎? A: 可以!用 CPU 跑小型配置(80ch/6blk, 500 games, 5 iterations)大約 2 小時。
Q: 訓練完的模型多大? A: 中型配置約 9.5MB,小型約 3MB,大型約 26MB。
Q: 為什麼同樣的參數,訓練出來的強度差很多? A: 因為隨機種子會影響啟蒙階段學到什麼、自我對戰走什麼路線。這是正常的,多練幾個挑最強的就好。
Q: Loss 降到多少算好? A: 通常 Phase 2 結束時 Loss 在 2.0 ~ 2.5 左右。不用太在意絕對數字,重點是有沒有持續下降。
Q: 可以從別人的模型繼續訓練嗎? A: 目前不支援 fine-tune,每次都是從零開始。但因為訓練速度很快(GPU 1 小時),從頭練也不是問題。
技術規格
| 項目 | 規格 |
|---|---|
| 網路架構 | ResNet-style CNN (Policy Network) |
| 輸入 | 3 × 15 × 15(current player, opponent, color plane) |
| 輸出 | 225 維機率向量(15×15 每個位置的落子機率) |
| Loss | KL Divergence |
| Optimizer | Adam + CosineAnnealingLR |
| 資料增強 | 8 倍對稱(4 旋轉 × 2 翻轉) |
| 自我對戰 | Bootstrap from heuristic → iterative self-play |
| 推論 | CPU ~10ms/步,GPU ~1ms/步 |
Built with ❤️ by OpenClaw Gomoku Arena — gomoku.candle.com.tw