🙌

将棋AIの新たな手法を考える

に公開

背景

将棋AIがプロを超えたと言われ始め、ずっとAIの中でも将棋AIを作ってみたいと思っていました。
しかし、家庭のPCの性能では到底、高性能AIに太刀打ちできません。
そのため、軽量なモデル、学習でも強い将棋AIを作る方法について考えました。
今回は設計・試作の段階です。

従来のよく使われる手法

有名な将棋の多くは、AlphaZeroをベースにしていると考えられます。
AlphaZeroは以下のように、囲碁のAIから始まった主にボードゲーム系AIの手法の1つです。

Google傘下の英国DeepMind社が開発した「AlphaGo」は、2015年に「囲碁」の一流棋士に圧勝したことで、世界中の大きな注目を集めました。それを発展させ、「囲碁」だけでなく「チェス」「将棋」でも最強のコンピュータソフトを目指して作られたのが、2017年末に発表された「AlphaZero」です。

引用:株式会社ボーンデジタル、AlphaZero 深層学習・強化学習・探索 人工知能プログラミング実践入門
https://www.borndigital.co.jp/book/14383/

昔はAIの中でも機械学習を用いずに、Alpha-Beta探索法という探索アルゴリズムで最善手を探していました。
しかし上記方法だと、ゲームの規模が大きくなるほど計算量が大きくなります。
例えば将棋であれば、1つの局面あたり150の手が存在する場合、
3手先全てを読むだけで単純計算で

150^3 = 3,375,000通りになり、非常に処理が重くなります。

AlphaZeroの手法

AlphaZeroは以下のように手法が解説されています。

引用:【強化学習】AlphaZeroを解説・実装
https://qiita.com/pocokhc/items/a1b5f66361f23b2aefe8

モンテカルロ木探索法というものを使用していますが、それは全てのパターンを終局ランダムに試し、次の1手が勝ちに繋がったものと負けに繋がったもので確率を出します。
次の1手のうち最も勝ちに繋がった確率の高いものを最善手として選びます。

しかし、それではランダム性に精度が左右されたり、終局までランダムで対戦を何通りもシミュレートするとなると大変効率が悪いです。

そこでAlphaZeroでは、そのモンテカルロ木の探索による勝率をニューラルネットワークの予測に置き換えます。こうすると、終局までランダムでシミュレートしなくても、ニューラルネットワークの予測結果を見るだけで大体の好手、悪手を判別できるようになります。

新たな手法を考える

有名AIと同じ手法で将棋AIを作成しても、PCのスペックとモデルの規模の差で絶対に勝つことができません。色々と考えたのですが、自己教師ありクラスタリングというものに目をつけました。

自己教師ありクラスタリングとは、データを学習し、自動で分別するためのクラスタIDをつけることです。将棋では局面ごとの共通点を自動で見つけさせます。
例えば「先手が攻めている」「先手が守っている」「詰まされそう」など、どのような基準で分けるか自体はブラックボックス的ですが、局面を種類分けすることが可能です。

そこで、自動クラスタの出力を、本体モデルの特徴量に追加する ことを考えました。

class CombinedNet(nn.Module):

## --- 中略 ---

    def __init__(
        self,
        in_channels: int = 31,
        action_size: int = ACTION_SIZE,
        channels: int = 128,
        blocks: int = 10,
        meta_clusters: int = 16,
        meta_temperature: float = 0.5,
    ):

        ## --- 中略 ---

        # ---- Trunk ----
        self.trunk_in = nn.Conv2d(in_channels, channels, kernel_size=3, padding=1, bias=False)
        self.trunk_bn = nn.BatchNorm2d(channels)
        self.blocks = nn.ModuleList([ResidualBlock(channels) for _ in range(blocks)])

        # ---- Meta head(自己教師ありクラスタリングの割当を出す)----
        self.m_gap = nn.AdaptiveAvgPool2d((1, 1))
        self.m_fc1 = nn.Linear(channels, 128)
        self.m_fc2 = nn.Linear(128, meta_clusters)  # => meta_logits [B, K]

        # ---- Heads ----
        head_in_ch = channels + meta_clusters

        # Policy
        self.p_conv = nn.Conv2d(head_in_ch, 2, kernel_size=1, bias=False)
        self.p_bn = nn.BatchNorm2d(2)
        self.p_fc = nn.Linear(2 * BOARD_SIZE * BOARD_SIZE, action_size)

        # Value
        self.v_conv = nn.Conv2d(head_in_ch, 1, kernel_size=1, bias=False)
        self.v_bn = nn.BatchNorm2d(1)
        self.v_fc1 = nn.Linear(BOARD_SIZE * BOARD_SIZE, 256)
        self.v_fc2 = nn.Linear(256, 1)

上記のように、従来の AlphaZero の構造に「自己教師ありクラスタリング」による Meta ヘッド を追加しました。
この Meta が自動クラスタを指し、局面を自動でクラスタリングした結果を本体の特徴量に組み込みます。
これにより、小さなモデルでも局面をより人間的に捉えることができ、より強いAIを作れる可能性を秘めています。(まだ作成、学習中のため実際のところは不明です。)

実際のAI

実装や学習も途中のプロトタイプなので、現状は意味がわからない手ばかりです。
AI同士で戦わせると、なぜか右側だけの総力戦になり千日手となりました。
おそらく学習初期なので、学習段階で勝敗がつくことがほとんどなかったのが原因かと思われます。

完成したAI

随時更新予定ですので、完成までお待ちください。

株式会社ソニックムーブ

Discussion