跳至主要内容

輸入特徵設計

神經網路只能處理數字。要讓它理解圍棋,我們需要一種方法把棋盤「翻譯」成數字。

這個翻譯過程,就是輸入特徵設計

AlphaGo 使用了 48 個特徵平面,AlphaGo Zero 簡化為 17 個,KataGo 則優化為 22 個。這篇文章將詳細解析這些設計選擇背後的考量。


什麼是特徵平面?

基本概念

一個特徵平面是一個 19×19 的矩陣,每個元素代表棋盤上對應位置的某種屬性。

例如,「黑子位置」這個特徵平面:

棋盤狀態:               特徵平面(黑子):
A B C D E A B C D E
1 . . . . . 1 0 0 0 0 0
2 . ● . . . 2 0 1 0 0 0
3 . . ○ . . → 3 0 0 0 0 0
4 . . . ● . 4 0 0 0 1 0
5 . . . . . 5 0 0 0 0 0
  • 有黑子的位置 = 1
  • 沒有黑子的位置 = 0

多個特徵平面

神經網路需要多種資訊,所以我們堆疊多個特徵平面:

這類似於彩色圖片有 R、G、B 三個通道。圍棋「圖片」有 N 個通道。


AlphaGo 的 48 個特徵平面

完整列表

AlphaGo 使用 48 個特徵平面,分為幾大類:

1. 棋子位置(3 個平面)

平面名稱說明
1黑子有黑子 = 1,否則 = 0
2白子有白子 = 1,否則 = 0
3空點空點 = 1,否則 = 0

2. 歷史記錄(16 個平面)

平面名稱說明
4-11黑子歷史黑子在 1-8 手前的位置
12-19白子歷史白子在 1-8 手前的位置

為什麼需要歷史?

  • 劫爭判斷:需要知道是否可以立即提回
  • 走棋意圖:最近幾手棋透露了雙方的計劃
  • 時序資訊:CNN 本身不處理時間,歷史平面補足這一點

3. 氣數特徵(8 個平面)

平面名稱說明
20-231-4 氣(我方)我方棋串有 1/2/3/4 氣 = 1
24-271-4 氣(對方)對方棋串有 1/2/3/4 氣 = 1

氣數是圍棋中最重要的戰術概念:

  • 1 氣:被叫吃,即將被提走
  • 2 氣:危險狀態
  • 3 氣:需要注意
  • 4+ 氣:暫時安全

4. 叫吃特徵(8 個平面)

平面名稱說明
28-31叫吃位置(我方)下這裡可以叫吃對方 1/2/3/4 顆棋
32-35叫吃位置(對方)下這裡可以叫吃我方 1/2/3/4 顆棋

叫吃是圍棋中最常見的戰術:

  • 叫吃多顆棋 = 更大的威脅
  • 不同大小的叫吃需要不同的應對

5. 征子特徵(8 個平面)

平面名稱說明
36-39征子相關(我方)與我方征子有關的位置
40-43征子相關(對方)與對方征子有關的位置

征子(Ladder)是圍棋中著名的戰術:

  • 沿對角線追逐對方棋子
  • 需要判斷「征子有利」還是「征子不利」
  • 這需要全局視野,是傳統電腦圍棋的難題

6. 合法性特徵(1 個平面)

平面名稱說明
44合法位置可以合法落子 = 1

這防止網路輸出非法著法:

  • 已有棋子的位置不能下
  • 禁入點(自殺且不提子)不能下
  • 劫立即提回不能下

7. 邊角特徵(4 個平面)

平面名稱說明
45距離邊線 1在第 1 線 = 1
46距離邊線 2在第 2 線 = 1
47距離邊線 3在第 3 線 = 1
48距離邊線 4+在第 4 線或更內側 = 1

邊角在圍棋中有特殊意義:

  • 第 1 線:死亡線,棋子容易被圍殺
  • 第 2 線:活棋線,但效率低
  • 第 3 線:實地線,穩健
  • 第 4 線:外勢線,追求影響力

為什麼需要這麼多特徵?

DeepMind 的設計理念是提供盡可能多的資訊,讓網路自己決定哪些有用:

原始棋盤 → 48 個特徵平面 → 神經網路 → 決策

特徵工程師的工作:把圍棋知識編碼成特徵
神經網路的工作:學會組合這些特徵

這是一種「把球傳給神經網路」的策略——人類負責特徵設計,網路負責學習組合。


AlphaGo Zero 的簡化:17 個特徵平面

革命性的改變

AlphaGo Zero 大幅簡化了輸入特徵:

版本特徵平面數使用人類知識
AlphaGo48大量(氣數、征子等)
AlphaGo Zero17幾乎沒有

17 個平面的組成

1. 棋子位置歷史(16 個平面)

平面名稱說明
1-8黑子 T-0 到 T-7黑子在當前和過去 7 步的位置
9-16白子 T-0 到 T-7白子在當前和過去 7 步的位置

2. 顏色(1 個平面)

平面名稱說明
17輪到誰輪到黑棋 = 全 1,輪到白棋 = 全 0

為什麼可以這麼簡化?

AlphaGo Zero 的核心洞見:

如果給足夠的計算資源和訓練時間,神經網路可以自己學會這些特徵

「氣數」、「叫吃」、「征子」這些概念,人類花了幾千年才發展出來。但 AlphaGo Zero 證明,神經網路可以在幾天內自己學會——甚至可能學到比人類更好的表示。

效果比較

令人驚訝的是,使用更少特徵的 AlphaGo Zero 反而更強:

版本特徵數訓練時間最終棋力
AlphaGo Master48數月約 5185 Elo
AlphaGo Zero1740 天約 5185 Elo
AlphaGo Zero (3 天)173 天超越人類

更少的人類知識,反而帶來更強的性能。

為什麼人類知識反而是負擔?

1. 人類知識可能有錯

人類總結的圍棋規則是經驗性的,可能不是最優的。例如:

  • 「金角銀邊草肚皮」——但某些局面下中央更重要
  • 「征子不利不要走」——但有時可以主動棄子

2. 特徵編碼限制了表示

當我們把「氣數」編碼為 1-4 氣四個平面時,我們隱含假設「氣數」是重要的分類方式。但也許有更好的分類方式,而這種編碼阻止了網路發現它。

3. 表示瓶頸

48 個平面佔用更多計算資源。如果其中一些特徵是冗餘的,這些資源就浪費了。


KataGo 的優化:22 個特徵平面

實用主義的平衡

KataGo 在 AlphaGo Zero 的基礎上,加入了少量精選的人類知識:

項目AlphaGo ZeroKataGo
歷史平面165
棋子位置
輪到誰
劫爭狀態
規則變體是(貼目、自殺規則等)
總計1722

KataGo 的特徵列表

基本特徵(5 個)

平面名稱說明
1黑子當前黑子位置
2白子當前白子位置
3空點當前空點位置
4輪到誰(1)始終為 1 的常數平面
5輪到誰(2)輪到黑 = 1,輪到白 = 0

歷史特徵(5 個)

平面名稱說明
6上一手位置對方上一步下的位置
7上二手位置我方上一步下的位置
8上三手位置對方上二步下的位置
9上四手位置我方上二步下的位置
10上五手位置對方上三步下的位置

劫爭特徵(3 個)

平面名稱說明
11劫禁點當前不能下的劫禁點
12潛在劫點(我方)我方下這裡會產生劫
13潛在劫點(對方)對方下這裡會產生劫

規則特徵(9 個)

平面名稱說明
14-22規則編碼貼目、自殺規則、超級劫等

為什麼加入這些特徵?

KataGo 的作者 lightvector 解釋:

1. 劫爭太重要

劫爭是圍棋中最複雜的概念之一。純粹從原始棋盤狀態學習劫的規則,需要大量樣本。明確標示劫禁點可以加速學習。

2. 規則多樣性

圍棋有多種規則:

  • 貼目:中國規則 7.5 目,日本規則 6.5 目
  • 自殺規則:部分規則允許自殺
  • 超級劫:處理長循環的不同方式

在輸入中明確編碼規則,讓一個網路能夠處理所有變體。

3. 訓練效率

加入少量人類知識可以大幅加速訓練。KataGo 用 50 GPU 天達到的棋力,AlphaGo Zero 用 5000+ TPU 天才達到。


特徵設計的哲學

三種方法

方法代表特徵數人類知識計算需求
大量人類知識AlphaGo48很多中等
最少人類知識AlphaGo Zero17幾乎沒有很高
適度人類知識KataGo22少量精選較低

取捨考量

資源有限時

如果計算資源有限(大多數研究者的情況),加入一些人類知識是明智的:

  • 加速訓練收斂
  • 減少所需的訓練資料
  • 避免重新發明輪子

追求極限時

如果計算資源充足,減少人類知識可能達到更高棋力:

  • 避免人類偏見
  • 發現人類未知的策略
  • 真正的「從零開始」

啟示

AlphaGo 系列的演進告訴我們:

  1. 特徵工程仍然重要——但形式改變了
  2. 端到端學習是趨勢——讓網路自己學會特徵
  3. 沒有唯一正確答案——取決於資源和目標

實作範例

特徵提取(AlphaGo 風格)

import numpy as np

def extract_features_alphago(board, history, current_player):
"""
提取 AlphaGo 風格的 48 個特徵平面

board: 19×19 的棋盤,0=空,1=黑,2=白
history: 最近 8 手的歷史
current_player: 1=黑,2=白
"""
features = np.zeros((48, 19, 19))

# 1-3: 棋子位置
features[0] = (board == 1) # 黑子
features[1] = (board == 2) # 白子
features[2] = (board == 0) # 空點

# 4-19: 歷史位置
for i, hist_board in enumerate(history[:8]):
features[3 + i] = (hist_board == 1) # 黑子歷史
features[11 + i] = (hist_board == 2) # 白子歷史

# 20-27: 氣數特徵
liberties = compute_liberties(board)
for i, lib_count in enumerate([1, 2, 3, 4]):
my_color = current_player
opp_color = 3 - current_player
features[19 + i] = (liberties == lib_count) & (board == my_color)
features[23 + i] = (liberties == lib_count) & (board == opp_color)

# 28-35: 叫吃特徵
capture_counts = compute_captures(board)
for i, cap_count in enumerate([1, 2, 3, 4]):
features[27 + i] = (capture_counts[current_player] == cap_count)
features[31 + i] = (capture_counts[3-current_player] == cap_count)

# 36-43: 征子特徵(簡化)
ladder_status = compute_ladder(board)
# ... 省略詳細實現 ...

# 44: 合法位置
features[43] = compute_legal_moves(board, current_player)

# 45-48: 邊角距離
for i in range(19):
for j in range(19):
dist = min(i, j, 18-i, 18-j)
if dist == 0:
features[44, i, j] = 1
elif dist == 1:
features[45, i, j] = 1
elif dist == 2:
features[46, i, j] = 1
else:
features[47, i, j] = 1

return features

特徵提取(AlphaGo Zero 風格)

def extract_features_zero(board_history, current_player):
"""
提取 AlphaGo Zero 風格的 17 個特徵平面

board_history: 最近 8 步的棋盤狀態列表
current_player: 1=黑,2=白
"""
features = np.zeros((17, 19, 19))

# 1-8: 黑子在 T-0 到 T-7 的位置
for i, board in enumerate(board_history[:8]):
features[i] = (board == 1)

# 9-16: 白子在 T-0 到 T-7 的位置
for i, board in enumerate(board_history[:8]):
features[8 + i] = (board == 2)

# 17: 輪到誰
if current_player == 1: # 黑棋
features[16] = np.ones((19, 19))
else:
features[16] = np.zeros((19, 19))

return features

效能比較

import time

# 模擬 1000 次特徵提取
board = np.random.randint(0, 3, (19, 19))
history = [np.random.randint(0, 3, (19, 19)) for _ in range(8)]

# AlphaGo 風格(有複雜計算)
start = time.time()
for _ in range(1000):
features = extract_features_alphago(board, history, 1)
alphago_time = time.time() - start

# AlphaGo Zero 風格(簡單)
start = time.time()
for _ in range(1000):
features = extract_features_zero(history, 1)
zero_time = time.time() - start

print(f"AlphaGo 風格: {alphago_time:.2f}s")
print(f"AlphaGo Zero 風格: {zero_time:.2f}s")
# 典型結果:AlphaGo 風格慢 5-10 倍

視覺化特徵平面

實際局面範例

實際棋盤:
A B C D E F G H J K L M N O P Q R S T
19 . . . . . . . . . . . . . . . . . . .
18 . . . . . . . . . . . . . . . . . . .
17 . . . ● . . . . . . . . . . . ○ . . .
16 . . . . . . . . . . . . . . . . . . .
15 . . . . . . . . . . . . . . . . . . .
...

特徵平面 1(黑子):
A B C D E F G H J K L M N O P Q R S T
19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
17 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...

特徵平面 2(白子):
A B C D E F G H J K L M N O P Q R S T
19 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
17 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
16 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
...

特徵平面的啟發

觀察不同特徵平面可以理解模型「看到」什麼:

特徵直觀含義模型可能學到的
黑子/白子位置誰在哪裡棋形、連接性
歷史最近發生什麼走棋意圖、戰鬥方向
氣數誰危險攻擊/防守目標
叫吃戰術機會局部戰術
邊角距離位置重要性開局選點、邊角定式

動畫對應

本文涉及的核心概念與動畫編號:

編號概念物理/數學對應
🎬 A8特徵編碼張量表示
🎬 A10輸入正規化特徵工程
🎬 D1卷積輸入多通道圖像
🎬 E3Zero 的簡化最小表示

延伸閱讀


關鍵要點

  1. 特徵平面是棋盤的數字化表示:每個平面是 19×19 的矩陣
  2. AlphaGo 使用 48 個平面:包含大量人類圍棋知識
  3. AlphaGo Zero 簡化為 17 個:證明網路可以自己學會特徵
  4. KataGo 優化為 22 個:平衡效率與性能
  5. 特徵設計是權衡:人類知識 vs 計算資源

輸入特徵設計是連接「人類理解的圍棋」與「機器可處理的數字」的橋樑。


參考資料

  1. Silver, D., et al. (2016). "Mastering the game of Go with deep neural networks and tree search." Nature, 529, 484-489.
  2. Silver, D., et al. (2017). "Mastering the game of Go without human knowledge." Nature, 551, 354-359.
  3. Wu, D. (2019). "Accelerating Self-Play Learning in Go." arXiv:1902.10565.
  4. KataGo Documentation: https://github.com/lightvector/KataGo

📌 重點摘要

本文重點:

  • 特徵平面是將棋盤狀態轉換為神經網路可處理的 19x19 矩陣
  • AlphaGo 使用 48 個特徵平面編碼人類圍棋知識,AlphaGo Zero 簡化為 17 個
  • KataGo 採用 22 個精選特徵平面,在效率與性能間取得平衡

常見問題

為什麼 AlphaGo Zero 用更少特徵反而更強?

因為過多的人類知識可能包含偏見或錯誤。AlphaGo Zero 證明神經網路可以自己學會氣數、征子等概念,甚至可能發現比人類更好的特徵表示方式。

特徵平面中的歷史記錄有什麼作用?

歷史記錄幫助處理劫爭判斷、理解走棋意圖,並補充 CNN 本身不具備的時序資訊。這對於理解對局脈絡非常重要。

KataGo 為什麼要加入規則特徵?

圍棋有多種規則變體(不同貼目、自殺規則等),在輸入中編碼規則讓單一網路能處理所有規則變體,大幅提升訓練效率和實用性。