複数の固定されたAIモデル(例:囲碁エージェント)の性能を比較する際、各モデル間の対戦勝率をもとに全体的な順位を決定する必要がある。このような状況では、Eloレーティングのような逐次更新型スコアリングよりも、事前に得られた安定した勝率関係を一括で処理できるPageRankアルゴリズムが適している。
PageRankアルゴリズムの基本思想
PageRankは、ノード間の「投票」関係に基づいて重要度を再帰的に計算する手法である。この考え方は、モデルAがモデルBに勝つ確率が高いほど、BがAから「多くの支持」を得ていると解釈できるため、AIモデルの相対評価にも応用可能である。
具体的には、以下のように遷移確率行列を構築する:
- 各要素 $M_{ij}$ はモデル $j$ がモデル $i$ に勝つ確率を表す。
- 対角成分 $M_{ii}$ は0.5とし、「自分自身との対戦は五分五分」と仮定することで、正規化時の歪みを防ぐ。
- 各列を合計1になるように正規化し、マルコフ連鎖の遷移確率行列とする。
収束性の保証:吸収状態と不可約性の問題
純粋な勝率行列から作成した遷移行列は、一部のモデルが他のすべてに勝つ(吸収状態)などして、マルコフ連鎖が「不可約」でなくなる可能性がある。この場合、初期分布に依存した複数の定常分布が存在し、順位が不安定になる。
これを回避するために、Googleが実装した「ダンピングファクター」に類似した手法を用いる:
ここで、$T$ は正規化済み勝率遷移行列、$E$ は全要素が $1/n$ の均一行列、$\alpha$ は小さな定数(例:0.001)。これにより、任意の状態から任意の他の状態へ微小ながら遷移可能となり、連鎖が不可約かつ正常返となることが保証される。
実装例
import numpy as np
def model_ranking(win_matrix):
"""
勝率行列に基づきPageRank風スコアを計算
win_matrix[i, j]: モデルjがモデルiに勝つ確率
"""
M = np.matrix(win_matrix, dtype=float)
n = M.shape[0]
# 対角成分を0.5に設定(自己対戦は引き分け)
for i in range(n):
M[i, i] = 0.5
# 各列を正規化(モデルjの総勝率を1に)
for j in range(n):
col_sum = np.sum(M[:, j])
if col_sum > 0:
M[:, j] /= col_sum
else:
M[:, j] = 1.0 / n # 安全策
# ダンピング付き遷移行列
uniform = np.ones((n, n)) / n
alpha = 1e-3
S = (1 - alpha) * M + alpha * uniform
# 初期確率ベクトル
x = np.matrix([1.0 / n] * n).T
# 収束までべき乗(200回で十分)
scores = (S ** 200) @ x
return np.array(scores).flatten()
使用例
相互に勝敗が循環するケース:
win_rates = [
[0.5, 0.6, 0.3], # A vs A,B,C
[0.4, 0.5, 0.6], # B vs A,B,C
[0.7, 0.4, 0.5] # C vs A,B,C
]
scores = model_ranking(win_rates)
# 出力: [0.308, 0.341, 0.351] → 順位: C > B > A
この方法は、勝率データが完全かつ安定しているAIモデル評価に特に有効であり、Eloのような逐次更新のオーバーヘッドを回避しつつ、グローバルな相対強度を反映した順位を提供する。