2007年コンピュータ将棋選手権準優勝記
by 棚瀬 寧


 

今回、拙作「棚瀬将棋(あくまで仮名称のつもり)」が活躍できたので簡単にその成長ぶり、及び選手権での戦いを振り返りたいと思います。

 

決断まで

2005年5月の選手権が終わってしばらくして登場したBonanzaに刺激を受け、メンテ性の悪くなった古いプログラムを捨てて自分も新たに一から書いてみる決心をする。
一から書いてみたいというのは何年も前から思っていてやっと決心がついたというところなのだが、すぐに新しいのを書く気も起きず、かと言って書き直すと決めたのに元のをいじる気も起きず、結局10月22日、23日の王者戦まで一行も将棋のプログラムを書かなかった。
作者のやる気のなさが出たような悪い内容でIS将棋の引退試合は公式戦初の負け越しで幕を閉じた。
しかし、ここで他プログラムの作者達と会うことにより久々に大きな情熱がみなぎり、あと半年に迫った次の選手権までにものすごいものを作ってやろう、という気になった。

2005.11月頃

OSLが速いそうなので勉強して真似してみることにする。
ちなみにOSLとはGPS将棋の元になっているライブラリでソースが公開されている。
が、そのあまりの難解さに読んだ人がいないと言われているもの。
最初はだいぶ苦労したがこつこつ読んでいるうちに少しずつ理解していった。
Modern C++ Designというこれまた難解なことで有名な本(かつて少し読んで挫折した経験あり)があるのだが、その本の中で展開されている理論がOSLで実際に使われている。
OSLを読んだ後に上記の本を読むとよくその意味するところが分かる。
例えば下が実際の棚瀬将棋におけるαβ法の再帰的呼び出しのコードで、doUndoMoveによりmakeMove, unmakeMoveが行われ、その間で再帰的な呼び出しを行う(searchNextにより)。
searchNextはfunctorと呼ばれるもので、operator()を定義することによりあたかも関数であるかのように振舞う。
Pは手番、altPはPと反対の手番で、このようにさまざまな関数にtemplate引数Pをつけて先手・後手を展開してしまう。

typedef TSearch< altP, SEARCHMODE_Normal > next_tsearch_t;
next_tsearch_t searchNext(
    tree,
    ..略.. );
ApplyMove< P >::doUndoMove< HashEvalEffectState, next_tsearch_t >( state, move, searchNext );

ちなみにHashEvalEffectStateというのは一番基本の局面クラスStateを継承してEffect(利き)情報を付加し、同様に評価関数の情報、ハッシュ情報も付加した拡張局面クラスのようなものである。

当初はtemplate多用に起因するコンパイルエラーも大量に出て非常に苦しんだ。
普通プログラミングにおいてバグに苦労することはあってもコンパイルエラーに苦しむことはそれほどないのではないだろうか?
だが今回ばかりはコンパイルエラーを解決すること自体に多大なエネルギーを費やした。
最近はtemplateにも慣れ、エラーに苦しむことはなくなったが、templateを使ってコードをコンパイル時に展開してしまうため、コンパイルにものすごく時間がかかり、それが開発効率を下げている面は否定出来ない。
このような手法がトータルで見てお勧めなのかどうか正直判断つきかねるところではあるが、OSLは開発者の田中哲朗先生の超絶なテクニックが随所に見られて目から鱗が落ちることは請け合いである。

結局αβ法が正しく動作して将棋が指せるようになったのが11月後半。
この時のnpsは250万くらい(Athlon64 fx-55で)。

2005.12月

killer手とか基本的なものの性能を測ったり、評価関数の構想を練ったりしているうちに終わった。
今から思えば探索の基本的な部分はCraftyかFruitを真似して深入りしないのが正解かもしれない。
たいしてオリジナリティが発揮出来る部分でもないし、もっと面白い部分にエネルギーを使った方がいい。
大体調べだすときりがない部分でもある。killer手を呼ぶ順番だとか何個保存するだとか。
評価関数については、この頃、全てを利きだけで表現する、というような構想を練っていた。
これは前に鶴岡さんが「駒の価値は大体利きの数と比例する」と言っていたことに影響されたもの。
普通のプログラムは駒自体の価値を足し合わせたり飛車や角などは利きの数を数えたり、ということをしていると思うが、全て利きとして評価すれば統一感が出る。
利きのバランスを見れば玉を左右から包むように寄せるようなこともきれいに表現出来るかも。
また△2二玉に対する▲3五桂が▲1五桂より価値が高いというようなことも1五の桂馬は一つの利きが盤の外に出てしまう、ということからも説明がつく。
しかし差分計算が難しいか、というような理由で結局採用しなかった。
今考えると、差分計算にこだわりすぎていたかなと思うし、改めて挑戦してみたい気になる。

2006.1月頃

今振り返ると評価関数をどうするつもりだったのだろうか?と非常に疑問なのだが、独自のαβ法の拡張を考えることばかりに随分エネルギーを割いている。
これは王者戦の時に山下さん達にその場の思いつきでt's number search(tはtanaseのt)を発明するなどとほざいてしまったことに原因がある。
αβγδ法などというふざけた名前の手法を開発し実際利用したりもしたが、後に意味がないことが判明、この頃の成果は結局現在何も利用していない。

2006.2月頃から

学習への取り組み開始。
本や論文を読んだり。
強化学習で序盤の学習はまず無理だろうから、やはりプロの手を真似る方向で行くことにする。
ちなみにこの頃考えた評価項目としては、玉とその近傍(8八玉の場合9七、5九で作られる長方形内)の金銀の形をハッシュ化して点数をつけるというものがある。
まさに部分ハッシュ。
以下がそのテーブルの一部。
プロの棋譜にある程度の頻度で出現する2012の形に対して、相手玉が左右どちらの位置にいるかによって2通りに分類している。

    { 0x0012e2bd,   0,   2 }, { 0x0026afad,   0,   0 }, { 0x004e62c6,  11,  18 }, { 0x0051486e,   0,   0 }, 
    { 0x0099f13b,   4,  10 }, { 0x00f34607,  35,  27 }, { 0x00fa5377,   0,   0 }, { 0x0126264d,  22,   5 },
    { 0x01293400,   8,   8 }, { 0x0140c2c3,  45,  17 }, { 0x0150c3fe,   0,   0 }, { 0x015adccb,   7,   4 },
    { 0x015c0973,   0,  19 }, { 0x01b239c7,  34,   0 }, { 0x01c20b44,   0,   8 }, { 0x01c9d067,  10,  16 },
    { 0x020643e7,   8,  25 }, { 0x0214a033,  20,   0 }, { 0x021bb609,   0,   0 }, { 0x021e10db,  16,  29 },
    { 0x0224a31f,   8,  30 }, { 0x0240d2da,   2,   0 }, { 0x0285aca8,   4,   4 }, { 0x02ae28ce,   0,  53 },
    { 0x02d76a1f,   4,  43 }, { 0x02da71fe,   0,   6 }, { 0x02e26eee,   0,  12 }, { 0x02eed1bb,   0,  57 },
    { 0x032d108f,  19,   0 }, { 0x032f75d3,  17,   0 }, { 0x033b96ef,   0,  38 }, { 0x034162ee,   0,   7 },
    { 0x037c8792,  33,  39 }, { 0x03907aa1,  16,   8 }, { 0x03aaf68c,  11,  27 }, { 0x03af0346,   0,  56 },
    { 0x03c9aa76,   0,   0 }, { 0x03ff0587,   0,   0 }, { 0x0408180a,  31,   5 }, { 0x041037f8,   0,  25 },
    { 0x04155905,  23,   0 }, { 0x04342a9c,  54,   0 }, { 0x043c5236,   3,   0 }, { 0x043e616f,   0,   0 },
    { 0x04ef95ab,  27,  21 }, { 0x0512da21,   0,  12 }, { 0x0521f4e5,   0,   0 }, { 0x0531a9ec,   0,  22 },

・・・

例えば0x037c8792というのは下の玉&金銀の形。

 歩 歩 角 ・ 銀 歩 歩 歩 ・
 ・ ・ ・ 飛 金 ・ 玉 ・ ・
 香 桂 ・ ・ ・ 金 銀 桂 香

下の松尾流穴熊なんかも登録されていてハッシュ値は0xa1cc03b1などとなっている。

 歩 歩 角 金 ・ 歩 ・ ・ ・
 香 銀 金 ・ ・ ・ ・ 飛 ・
 玉 桂 銀 ・ ・ ・ ・ 桂 香

以降今に至るまで苦労したのは学習だけ。
学習はバグがあってもすぐには分からないし、徐々に値がおかしくなってきてから何か間違えたか?と考えることになる。
かと言ってバグとは限らず、そもそも理論が健全でないという可能性もあるわけで、私の場合どういう結果が出てくるかびくびくしながら見守っているというのが実情である。

2006年5月の選手権時は全く話にならない状況で出場をキャンセル。
その後も岸本や飯田さん経由で論文を仕入れたり、直接関係なさそうな本なども以前よりも読むようになった。
そうこうするうちに11月のGPW。
GPWでは保木さんの発表があった。
この手の話では定石ということだが、特徴ベクトルの要素の大きさに対するペナルティという考え方などなど非常にためになった。
そこでまた学習を作り替え。
12月頃には3手の機械的な組み合わせに対して延長深さを割り当てる、ということを考えて実装してみた。
分類→深さの対応は結局確率を用いるしか思いつかなかった。
ただし2倍じゃなくて8倍が深さ1に対応するのと(これは実験して決めるべき)、合法手が少ない局面で指された手の補正(逆に多い局面で指された手も補正)、1手で消費する最大深さは3、疎なカテゴリを別カテゴリと同一視、などの特徴がある。
下に一部を抜粋。

 10832: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307
 10833: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307
 10834: 2.2 / 110.1 ( 1.90) (depth=1.9 INCPLY=-14) simple= 9307
 10835: 3.6 / 259.9 ( 1.37) (depth=2.1 INCPLY=-17) simple= 9307
 10836: 4.8 / 129.9 ( 3.35) (depth=1.6 INCPLY=-10) simple= 9307
 10839: 7.8 / 1017.9 ( 0.78) (depth=2.3 INCPLY=-21) simple= 9307
 10840: 36.9 / 482.0 ( 7.40) (depth=1.3 INCPLY=-4) simple= 9307
 10841: 1.0 / 852.3 ( 0.15) (depth=3.1 INCPLY=-34) simple= 9307
 10842: 13.9 / 150.6 ( 8.27) (depth=1.2 INCPLY=-3) simple= 9307
 10843: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307
 10844: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307
 10845: 23.5 / 104.9 (19.00) (depth=0.8 INCPLY=3) simple= 9307
 10846: 0.0 / 175.3 ( 0.13) (depth=3.2 INCPLY=-35) simple= 9307
 10847: 18.4 / 247.9 ( 6.96) (depth=1.3 INCPLY=-4) simple= 9307
 10848: 8.0 / 214.7 ( 3.53) (depth=1.6 INCPLY=-9) simple= 9307
 10849: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307
 10850: 1.2 / 140.3 ( 0.90) (depth=2.3 INCPLY=-20) simple= 9307
 10851: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307
 10854: 14.4 / 725.1 ( 1.96) (depth=1.9 INCPLY=-14) simple= 9307
 10855: 11.4 / 1159.4 ( 0.99) (depth=2.2 INCPLY=-19) simple= 9307
 10856: 29.3 / 417.7 ( 6.75) (depth=1.3 INCPLY=-4) simple= 9307
 10857: 0.0 / 151.8 ( 0.15) (depth=3.1 INCPLY=-34) simple= 9307
 10858: 1853.9 / 63687.7 ( 2.91) (depth=1.7 INCPLY=-11) simple= 9307

simple=9307というのは、疎な場合に9307番と同一視する、という意味である。
実際10832, 10833番などは同一視されている。
また1手で消費する最大深さの設定であるが、これの元になった実験は次のリンク先をどうぞ。
http://spreadsheets.google.com/pub?key=psQO-k1azTe_1Vmje6rQZNw
最低extension(最大reductionと言った方がいい)を-2から-∞にしてもほとんど速度向上が見られないことが分かる。
指し手の質の面からは出来るだけreductionを小さく抑えつつノード数を抑えたいので、この実験結果から-2が一番いいであろうという結論に達した。
この実験結果は前向き枝狩りによる速度上の効果がほとんどないことの証明にもなっていると考えられる。
前向き枝狩りには半quiescence search的とも言うべき局面安定化効果もあるので、意味がないとは言えないが、残り深さが多い場合(ルート局面に近いノードなど)でははっきり意味がないと言っていいというのが今の私の結論である。
さて、この3手の分類というアイディアは面白いのだが、効果のほどは全く調べていないのでよく分からない。
ただ一つ言えるのはtacticalな問題集に対しては確実に性能が落ちた。
ただ捨てっぽい手などが深さが減らされるのでどうしても作られた問題は苦手になるようだ。

年も変わって2007年2月頃から進行度導入に本格的に取り組み始めた。
私のプログラムでは上で書いた特徴ベクトルに対するペナルティを強めに設定していたため、序盤でBonanzaのように角を切ってしまうようなことはないかわりに終盤がかなりぬるいプログラムになっていた。
そこを補うのが進行度の予定だったのだが、進行度計算も学習、というのがちょっと欲張りすぎたかもしれない。
これがなかなかうまくいかず、急遽進行度の計算部分にはGPWで発表されたGPS将棋の竹内さんの考え方も取り入れてみたりした。
こちらは統計ソフトに式を入れて最小2乗法などで解かせればよく、お手軽である。
しかしこれでもいい値が得られず進行度断念。
かなり色々悪戦苦闘したのだが。
この頃にはもう4月。
これでかなりの予定変更を余儀なくされた。
仕方なく一番下がって欲しい部分の値のペナルティを弱めることで、強引に学習を誘導することにした。
具体的には相手玉から遠い位置の金銀などの値。
これの値があまり低い値に設定されていなかったせいで、終盤で無限と金作りにいそしんだりする問題が出ていた。
ところが4月中旬ごろに学習がぼろぼろの状態に。
この時は2年連続のキャンセルが頭をよぎった。正直かなり惨めな気持ちに陥った。
しかし気を取り直して調べた結果、これはしばらく前に実装した学習の並列化(ただ単に4つプロセスを走らせてそれぞれ結果をファイルを介して読みあうだけのシンプルな実装)で、中間ファイルを削除し忘れていたせいであることが判明。

4月20日頃から思考エンジンの並列化を始めた。
普通に考えると残り日数では無理そうなので1日で終わらせるつもりで挑んだ。
実際は5日ほどかかったが、とにかく忠実にCraftyを真似たため、信じられないほどバグが出なかった。
上の方にαβ法の再帰呼び出しのコードを載せたように、かなり実装が隠蔽された書き方になっているのも並列化のような大変更にプラスに働いたかもしれない。

並列化は成功したものの学習は思ったほどは反応して来ず、全く自信がないまま選手権に向かうことになった。

5月2日、1次予選前日

LANのテストで柿木さんと2局対局。
1局目に必勝の将棋を金銀をべたべたと打ちつけて飛車を取りに行く手を指して負け。
これが何度も見た典型的な終盤のぬるさ。
2局目は勝ったが、この練習対局2局の中でも既知の欠点が出たことで2次予選までにはやはり伝家の宝刀ドーピングを抜くしかないか、と覚悟した。
ちなみにその夜、柿木さんとの対局をホテルの部屋で分析していたら並列化の重大なバグを発見した。
ルート局面でも並列化しているのだが、splitしたスレッドで最善手順を更新しても全く最終的な結果に反映されていなかった。
スレッド0以外で最善手順が浮上しても全く意味がなかったわけでかなりひどいバグだが、何しろ並列化のテストも少し問題を解かせて「大体動いてそうだな」程度にしかしていなかったため無理もない。
いずれにしてもLANのテストの名目で行った柿木将棋との対局が本大会での快進撃の原動力になったと言えるかもしれない。

5月3日、1次予選

1回戦:GA将!!戦
相手のバグでいきなり終わってしまった。

2回戦:Shallow Thoughts戦
作者の方としゃべってたんで内容はあまり記憶にないが、美濃囲いから穴熊にしたことがちょっと目を引いたようだ。

3回戦:遠見戦
作者は私の大学院の研究室の先輩である高橋さんという方の研究室の学生さんとのこと。
遠見はかなり強かった。この一戦を見ると決勝に行ってしまうんじゃないかと思った。

4回戦:マイムーブ戦
最後玉が上に逃げ出して来られた場合の相手の妙手を棚瀬将棋が読んでいて、そう来られたらどうなったことやら。
具体的には、56手目に△8四玉と逃げ出された場合、棚瀬将棋は当初は▲6四角で良しと読んでいたのだが、それに対して△8六香という好手がある。以下は実戦の読み筋。
55:▲6五桂△8四玉▲6四角△8六香▲同 角△9九馬▲6四角△7七馬▲4八玉△6三香▲9一角成△5九銀▲3八玉△1一馬▲同 と△2六桂▲2八玉△6五香 < 先手優勢(669) >

5回戦:SPEAR戦
序盤いきなりあっさりと飛車先を突破させたが意外と大したことなかったのか。

6回戦:みさき戦
お互いあまりよろしくない序盤からなんとなく仕掛けが生じて勝利。

7回戦:まったりゆうちゃん戦
見ていなかったが、快勝だったようだ。

まあさすがに1次は楽勝だったようだ。
正直始まる前は少し心配だったのだが。
終わってからはそそくさとホテルの部屋に戻って学習を走らせてから山下さんと夕食。
本来学習は最後は学習率を小さくして収束に持っていかなくてはいけないのだが、私の場合直前まで評価項目を追加したりしていたため、まだ少し粗く学習させていた。
そのため、1ステップごとにプロの手との一致率も結構上下していたし、一致率が悪い方の場合はShallow Thoughts戦のような美濃から穴熊に囲ったりといったことが起きていた。
というわけで、2次予選前に1ステップ学習を行うことは絶対肝要だと思っていた。
本当は1次予選前にも1ステップやる予定だったのだがホテルの部屋のマスター電源みたいなものを切ってしまってパーになってしまった。
部屋に入ってすぐのところにいかにも押してくれと言わんばかりにあるので、オークラに泊まる方は気をつけられたい。
現在プロ棋譜約8000局とちょっと少なめで学習をさせていて1ステップ大体7時間程で終わるのだが、途中で止めると全部無駄になる。
余談だが美濃やちゃんとした穴熊はいいけど美濃から穴熊にもぐってはいけない、というのは私のプログラムの場合、非常に微妙なパラメータ調節を要求する難しい問題になっているようである。
何か評価項目を加えてやってもっと簡単な問題にしてやる必要があるのだろう。

で夕食の後は禁断のドーピング(手で学習されたデータをいじること)をどのように行うかを大体決めて一旦少し睡眠。
少し寝たら汗だくで目を覚ました。
これは選手権に参加するたびに経験をする。
どういう生理現象なのか知らないが、暑くもないのに汗だくになるのである。
2年振りの参加でも変わってなかった。

私のプログラムでは玉と例えば金の関係を全ての玉位置について持っているのではなくて、単なるベクトル+x座標を固定したベクトル+y座標を固定したベクトルという形で持っている。
これにより頻度の極端に低い位置についてもそれなりに対応出来る、というメリットがあるが、ドーピングがしやすいというメリットもあった。
単純なベクトルは9*17という小さなテーブルなので、手でいじるのも簡単なのだ。
ちょうど1ステップ終了。プロ棋譜との一致率も高い値になっている。出来上がった学習データにさくっとドーピングを施し、大体良さそうな感じであることを目で確認して30分ほどで完成。
柿木戦でのぬるい手を指さないことなどを確認して後はなるようになれ、で迎えた2日目の朝。

5月4日、2次予選

1回戦:奈良将棋戦
怖い相手。四間飛車になるがいきなり飛車先が押さえ込まれる形。やはりこのクラスには勝てないのか、と思ったがなんとか手をつなげて勝利。
かなり安心したのだが。

2回戦:神乎棋技(神の一手)戦
神乎棋技はアメリカ在住の台湾人であるLarryさんによるプログラム。
奈良将棋に勝てたところで1次で3敗しているプログラム、これは楽勝と思ったのだが。
変な序盤から不用意に玉頭の歩を突いて相手の銀を追い返したのがよくなかった。
その歩を狙われて飛車で苦しく守らされる展開に。
そのうちミスをしてくれるはず、と祈りながら見ていたのだが、相手の読みはかなりしっかりしていた。
結局最後の最後こっちの王様に詰みが生じてそれを自分で読みきってしまうところまで行ってしまった。
評価値が-∞になったものの時間制限が来て141手目▲3一桂成を着手。
それに対して神乎棋技は当然正解の△6六角を指して来る。
仕方のない▲7七桂の受け。
ここでは完全にあきらめていたのだが、なんとそこまで正確な手を指し続けた神乎棋技がそこからの詰みに気づかず受けに回るという奇跡が起きて冷や汗の勝利。
結果的に141手目が自玉の難しい詰みに目をつぶった人間的な勝負手になった。
ここでパニックモードがあって時間延長なんかをしようものなら、恐らく水平線気味の暴発手が指されてあっさり負けてしまったのではないだろうか。
それにしても神乎棋技はなんとも不思議なプログラムである。

3回戦:Shotest戦
久々の対戦。快勝だと思う。

4回戦:竜の卵戦
竜の卵はここ最近2年連続(今年で3年連続)決勝に残っている。
この辺りから猛者との連戦になる。竜の卵は今年は定跡を入れ、定跡が切れた後も去年までとは比べ物にならないほど筋がよくなっていた。
本局は私好みのなかなかこくのある戦いの末勝利。

5回戦:激指戦
これは大一番だったのだが、序盤で切れ筋に陥ってしまって後はだれた展開で敗北。ただ桂馬をぽんぽんと跳ねて行った手は悪くなかったようで悪いのは銀を打ち込んで角桂を捨てて飛車を取った手順。
後で調べてみると飛車を取って△2八飛と打ち込むことが高く評価されていた。実際安全に打ち込めるのなら桂を損してもそれなりに元が取れるのかもしれないが、現実は▲3八銀と打たれて飛車が閉じ込められて殺される形。
残り深さがたくさんある段階で飛車を打つと殺されることが読めてしまうのだが、何かやって残り深さを少なくしてから打ち込むという読みになっていた。
その後もずっと我慢する指し方をすればそんなにすぐに終わることはなかったようだが、隙を見て△2八飛を打ってやろうという読みのせいで読みの質が悪くなり死を早めることになってしまったようだ。

6回戦:大槻将棋戦
大槻将棋も学習を採用しているようで、金銀を連係させてくるところなど本局にもその雰囲気が出ている気がする。
この1局も私好み。終盤の金銀をわざと取らせる寄せがえらくほめられたが、最終盤の寄せよりもその前の攻防がなかなかいい感じだった。

7回戦:柿木将棋戦
柿木将棋十八番の振り飛車穴熊に対して面白い仕掛けをして優勢になったかと思ったが、やはり穴熊は怖い。
どうも逆転されてしまったようなのだが、なんと柿木将棋が暴走してillegalな手を返すというハプニングがあり一応勝利ということになった。
結果的に最終手となった86手目△3六桂に対して▲1五角を打ってから取り返せば先手が勝ちという勝又さんの話。
確かめるとその通りでプロの終盤力は改めてすごいと思った。
そうゆう結論が一瞬で見えているわけだから。
この勝利で決勝進出はほぼ決定。
柿木さんはこの1局がたたって最初5連勝しながらまさかの予選落ち。
8回戦の大槻将棋戦も柿木将棋勝勢で一旦大盤解説が打ち切られてからの逆転負けだったようでとにかくついてなかったようだ。

8回戦:K-Shogi戦
K-Shogiはフリーで公開されていて、これまでの安定した2次予選上位という実績から、特に選手権の決勝を目指す人達にとってはいい練習相手のようだ。
かくいう私も一時期よく利用させていただいた。
1回戦と似た感じでまたも四間飛車が押さえ込まれジリ貧寸前。
ただ、棚瀬将棋はIS将棋と違ってこうゆう展開で飛車角の機動力を高く保ってチャンスを狙うのがうまい感じがする。
ずっと完全に押さえ込みをはかっていたK-Shogiの95手目5三歩と叩いた手が方針の一貫しない悪手ということで、さらに次の1六香と打った手が決定的な悪手で、以下はばたばたと形勢が入れ替わってしまった。

9回戦:備後将棋戦
お互い決勝進出を決めた消化試合。余裕でトイレに行っている間に備後将棋が少し無理な仕掛けを断行して不利になったようである。

と終わってみれば心配した2次予選も8-1の通過。
将棋の内容を見てもドーピングは確実に利いたと思った。

その夜は激指戦で評価値が落ちたのに時間がなくなって悪手を指してしまったのでパニックモードを実装しようかと思っていたのだが、危険なのでやめ。
妙に四間飛車を指すことが多いので急戦を仕掛けて来そうなTACOSとYSS相手には▲7六歩に△8四歩と指すようにだけして寝た(と言ってもまた汗だくで目が覚めるのだが)。
選手権に参加して直前の夜にコンパイルしなかったのは初である。

5月5日、決勝

やっとこの場所に戻って来られた、という感慨に浸る間もなくマシンを設定してばたばたと試合は始まる。
せっかく前日にコンパイルしなかったにも関わらず、1局目直前にせっかく2GBのメモリがあるのに256MBしかハッシュを取ってないことに気づいてとりあえず512MBにしてコンパイル。

1回戦:Bonanza戦
勝又さんには相振りがお奨めと言われていたが、私の作ったばかりの定跡ルーチンはそういう高度な機能がないのでなるようになるしかない。
相手の四間美濃にこちらの居飛車穴熊へと進んだ。
これは少しラッキーだった。
60手目のBonanzaの△5三銀の局面を見て「きれいだねえ。完璧だよ。‥だけど勝ちやすくなったわけじゃないぞ。」と勝又さん。
実際そこからこちらとしては普通の手を指しているだけで普通に優勢に。
穴熊恐るべし。
93手目の▲9五香△同香と取らせてから▲6八飛と引いたのがなかなかの手だったと思う。
普通に先に▲6八飛△4七成桂としてからだと相手が歩を持っているので▲9五香は無効である。
(全て私の隣りに座って観戦されていた勝又さんの受け売り)
これで寄せやすくなった。
以下かなり優勢になったかと思った後も「これ相当危ないぞ」などと勝又さんに言われて(こういうプロの直感の正しさは選手権で嫌というほど感じてきた)かなりびびらされたがなんとか勝ちきることが出来た。

2回戦:TACOS戦
なんか銀が危ないなあと思っていたらやはり銀ばさみを食らった。
こうゆうところが私がコンピュータは(と一般化していいかどうかは分からないが)読みが浅いと言っている所以である。
以下押さえ込みを狙われると困っていたのだろうが、ソフトは一般的に押さえ込みが下手なので、本局も銀を取られても多分なんとかなるんだろうなあ、と案外安心して観戦していた。
以下やはりTACOSが攻め合ってきたため、急に楽になった。

3回戦:激指戦
前半から強豪との戦いが続く。
これまた四間飛車で桂香損になる、という今大会何度も出てきた展開。
58手目△5四歩から角を展開したのが色々な人から褒められた好手順。
以降は圧倒的な差になった。
やっぱ将棋って駒の効率が大事なんだな、という一局。
この時点で急に優勝の大本命に。

4回戦:竜の卵戦
またも四間飛車で桂香損に。
しかし妙にうまいさばきを見せて快勝。
本局は個人的に一番の会心譜。

5回戦:YSS戦
これを勝てば早くも優勝が濃厚になる大一番。
正直負ける気はしなかった。
YSSらしい低い感じの陣形に対して中央を制圧する展開で勝ちパターンに。
やはり勝つんだなと思った。
その後、YSSが玉に向かって攻めてくる。が受けきり完全に勝ちになった。
全勝優勝が見えた刹那、なんと簡単な9手詰のとん死を食らって敗北。
しかもその局面ではYSS玉に詰みもあり、詰めろを防いでも勝ち、相手を詰ませても勝ち、というかなり負けにくい局面を負けてしまったわけである。
ジャンケン勝負の選手権の一試合一試合に昔ほど一喜一憂しなくなった自分をも落ち込ませてくれるに十分の劇的な負け方だった。
棚瀬将棋には簡単な反復深化の詰将棋ルーチンは入っていて、本来このような簡単なとん死は食らわないはずなのだが並列のスレッドがルートの最善手を更新した場合にはこのチェックがされないというバグがあったことが試合後判明。
そもそも詰将棋ルーチンなしでも簡単に読めそうな詰みなので不思議なのだが王手延長とかあまりやってないせいかな。
とにもかくにもぎりぎりの網をかいくぐって起きてしまったハプニングという感じだった。
それにしてもやはり証明数探索は絶対入れたい。
IS将棋に入ってたくらいの詰めルーチンが入っていれば何事もなく詰ませて終了してただろうし。

6回戦:K-Shogi戦
K-Shogiの端攻めが一見筋っぽいが実は無理で楽勝ペースに。

7回戦:備後将棋戦
備後将棋が1手とんでもなくぬるい手を指したことにより勝勢に。

最終戦でBonanzaがYSSに勝てば優勝という他力の目があり、実際Bonanzaが完勝しそうな雰囲気だったがYSSが命からがら逃げ切り、ほんとにあと一歩というところまで迫った復活優勝ならず。
この一戦は今までの私のキャラだと山下さんと一緒に観戦して「来た来たー」などと叫ぶことが期待されていたようだが、隅で心静かに観戦した。
結局過去2度YSSに対してやった同率頭はねをついに自分がやられてしまった。
やはり勝った時にプレーオフをすべきと強く主張しておくべきだったか。
まあ時間的にも現状でいっぱいいっぱいなので無理だろうが。

その後はパーティー。
あまり関係ないがMYCOM小川さんの4者団体戦構想(プロ、女流プロ、アマチュア、コンピュータ)で盛り上がった。
今回再び人間の力を見せつけた加藤幸男さんの「血が出ない戦いは面白くない」という意見、私も同意見である。
そんな戦い私は是非見てみたい。

あと、Larryさんが言っていたのだが、Chinese Chessではコンピュータの大会の後、上位5プログラム対人間のグランドマスター5人の団体戦が行われるらしい。
将棋もこのような方向を考えた方がいいのではないだろうか?
今はアマトップやプロとコンピュータの差が大きくてそう簡単に人間側が負けることはないだろうが、今でも人間がミスをすればコンピュータが勝っても全く不思議ではない。
仮にそういうことがたまたま起こった場合にマスコミが大騒ぎをしたり、コンピュータがアマチュアトップを抜いたなどと思われるかと考えるだけで、コンピュータはまだまだ弱いと思っている自分としては今からうんざりしてしまう。

その後、山下さんの部屋でYSSと非公式プレーオフ。
そう言えば2003年に6-1で並んでIS将棋が優勝した時も私の部屋で対戦させたんで、立場が入れ替わってまさにあの時の再現となった。
通信の関係で2局ともまた後手番だったが、なんと2連敗。
まあYSSも「結構」強いみたいです。
決勝の1局も含めて、3局とも序中盤でリード、終盤で薄くされて絡まれる、という展開。
確かに今の私のプログラムには薄くされると嫌、という評価はほとんどなかったんだな、と改めて気づかされた。
それにしても正直2連敗という結果にはほっとした。
2連勝だと当然「なんて運がなかったんだー」とまた苦しんでしまうことになるので。


まとめ

本プログラムで利用しているような学習法はAと指すかBと指すかという指し手ベースの学習であるため、もう少し難しい概念の学習があまりきれいに行かないのではないかという気がする。
例えば先手8八玉に対する9九香と1九香の大小関係とか。
縦方向の大小関係はプロがめったに1七香などと上がったりしないことからきれいに学習されるのだが、横方向の比較は直接的には行われないためあまりきれいにいかないようである。
かたや金など動きがなめらかな駒については非常にきれいに学習される。

また本質的な問題として、プロの棋譜にはひどい局面があまり出てこない、という問題がある。
例えば少し前の棚瀬将棋は相手陣に3枚も4枚もと金を作る手を好んで指した。では、と金が3枚以上いる場合に減点するというような評価要素を加えてみることを考えたとしよう。
だが、これはプロの棋譜を見て学習してもうまく学習されないと思う。それはプロの棋譜にそういう局面が出てこないからである。
あるいは出てきたとしても、当然プロが意味もなくと金作りにいそしむわけはなくて、その場ではなんらかの理由で好手になっている(入玉を見据えているとか)場合しかなくて、狙い通りの値に学習されることはあまり期待できない。
保木さんの方法では、プロが指さなかった、ということからも学習されるので実際に3枚も4枚もと金が出来ている局面が出現する必要はないのだが、それでもすぐに3枚目、4枚目が作れる局面が出現する必要はあり、やはり難しいだろう。
こう考えると一部ドーピングも仕方ないのかもしれない。

ちなみにプロ棋譜から指し手のカテゴリの実現確率を求める実現確率探索についても同じような問題点がある。
例えば直前の飛車を取り返す手など当然非常に高い確率になり深く読まれることになる。
だが、ほんとに飛車を取り返す手は深く読みたい手なのか?
これが微妙なところで、実際の探索の内部で発生する飛車の取り返しのほとんどは直前にランダムに生成された全く無意味な飛車打ちを取り返す手である。
プロが指す飛車を捨てる手とは全く質が異なるわけである。
こういうところにプロが飛車を取り返す手の確率を適用しても意味はないだろう。
実際例えばCraftyで同じ駒の連続した取り合いだけを延長しているのは、質の悪い手の取り返しを延長したくないという意味である。
一部のカテゴリに対しては自己対戦の勝率で最適な値を決めるといった柔軟さが必要だと考えている。

評価関数の学習の話に戻ると、一部の評価要素に関しては局面の値の学習を目指すアルゴリズム(例えば強化学習のような)が必要になるのではないかと思っていて、GPS将棋の竹内さんが発表された方法が実用的なんじゃないかと思っている。
ただ、本学習も想像以上に強力な面もあり、指し手間の比較では学習が難しいかな?と思ったら意外といい感じに学習されている例を挙げておく。

下は玉の周りの利きの評価。ULはUpLeft、DはDownなどの略。
3番目が攻め側の利きが勝っている状態で一番攻め側有利。
D3とU3と比べると104対192と倍近い差。

static const Val neighbor8_empty_UL0 = 0;
static const Val neighbor8_empty_UL10 = 16;
static const Val neighbor8_empty_UL11 = 25;
static const Val neighbor8_empty_UL2 = 76;
static const Val neighbor8_empty_UL3 = 160;
static const Val neighbor8_empty_U0 = 0;
static const Val neighbor8_empty_U10 = 23;
static const Val neighbor8_empty_U11 = 45;
static const Val neighbor8_empty_U2 = 113;
static const Val neighbor8_empty_U3 = 192;
static const Val neighbor8_empty_L0 = 0;
static const Val neighbor8_empty_L10 = 12;
static const Val neighbor8_empty_L11 = 7;
static const Val neighbor8_empty_L2 = 64;
static const Val neighbor8_empty_L3 = 126;
static const Val neighbor8_empty_DL0 = 2;
static const Val neighbor8_empty_DL10 = 22;
static const Val neighbor8_empty_DL11 = 7;
static const Val neighbor8_empty_DL2 = 49;
static const Val neighbor8_empty_DL3 = 98;
static const Val neighbor8_empty_D0 = 14;
static const Val neighbor8_empty_D10 = 9;
static const Val neighbor8_empty_D11 = 19;
static const Val neighbor8_empty_D2 = 48;
static const Val neighbor8_empty_D3 = 104;

玉が1九の場合。一般の場合よりも対応する位置がはっきりと高い値になっていることが分かる。

static const Val king19_neighbor8_empty_UL0 = 16;
static const Val king19_neighbor8_empty_UL10 = 37;
static const Val king19_neighbor8_empty_UL11 = 45;
static const Val king19_neighbor8_empty_UL2 = 149;
static const Val king19_neighbor8_empty_UL3 = 393;
static const Val king19_neighbor8_empty_U0 = 35;
static const Val king19_neighbor8_empty_U10 = 50;
static const Val king19_neighbor8_empty_U11 = 137;
static const Val king19_neighbor8_empty_U2 = 184;
static const Val king19_neighbor8_empty_U3 = 304;
static const Val king19_neighbor8_empty_L0 = 0;
static const Val king19_neighbor8_empty_L10 = 39;
static const Val king19_neighbor8_empty_L11 = 113;
static const Val king19_neighbor8_empty_L2 = 105;
static const Val king19_neighbor8_empty_L3 = 274;

さらに上記の値を持ち駒の数によって増幅する値。256で割って利用。
飛車の場合、やはり利きがある位置(U,L,D)の値が高くなっている。

static const int mul_rook_UL = 29;
static const int mul_rook_U = 53;
static const int mul_rook_L = 61;
static const int mul_rook_DL = 25;
static const int mul_rook_D = 53;

他の駒についてもはっきりとその傾向がうかがえた。

ところで、選手権が終わってからの帰路に気づいたのだが、どうも今回相掛りと四間飛車ばっかりだと思ったら定跡ルーチンでsrandomをするのを忘れていた。
つまりランダム性がなかったわけである。
2次予選と決勝の激指戦、両方とも後手番だったので相手が手を変えてくれなかったらやばいところだった。

今後の予定

・進行度導入
・学習の安定化(ドーピングしなくていいように)
・IS将棋の研究。使えること色々あるはず。現状は何も利用していない状況。
・プログラムに名前をつける

 

第17回世界コンピュータ将棋選手権
加藤徹さんによるまとめページ

2007.5.10(5.26加筆)