よるデータ拡張を行うことで性能を落とさず学習速度を2倍にできた。S1において、同じ学習時間で比較したときにはこのようなデータ拡張が有効であると示されている。将棋では回転は利用できないので左右対称だけの2倍にしかならず、また飛車角の初期位置自体は左右非対称なので左右反転したデータが良いデータかはわからないが、ものは試しということで実装・実験を行った。実験いつも通りのAlphaZero式強化学習を、左右反転によるデータ拡張あり/なしで比較した。データ拡張を入れる場合、対局を行ってリプレイバッファにデータを格納する際、盤面及び指し手の教師ラベルを左右反転させたものを同時に格納する(Valueの教師ラベルは同じものを使う)。右:Value損失Policy損失については左右反転によるデータ拡張を行った方が小さい値となった。Value損失はほぼ変わらなかった。最後のステップでやや伸びているが、基本的に同程度の性能だった。データ拡張により生成速度はほぼ2倍になっており、現在Miacisでは生成速度に応じて自動的に学習時間を調整しているため学習時間が半分で済むようになった。上で示したグラフを、横軸に学習時間を取って描画し直すと次のようになる。1753(-26)D問題までの4完でレート減。レート下がってもそんなに悲しくならないくらい今は競技プログラミングへのモチベーションが落ちている。コンテストに出ることは継続しているけれど振り返りを一切しないようになっていて、流石にそれではまずそうなのでここらで再開。Poor長さ3のstd::vectorに受け取ってソートして上手くできるのかと思って書きかけたが、なんか結局面倒なことになりそうだったので方針転換して条件をベタ書きした。Please問題文が理解できず頭の悪さを感じた。"APPROVED"、"DENIED"をコピペせず手打ちするという勇者プレイ(普通に通った)。Pollstd::mapで出現回数を数えてから最大のものだけstd::setに詰め直す。auto&にするタイプの人間。」をと勘違いしていた。答えにしようとするのでWAになる。それは些細な話として、この問題は実装をどうするかが要点だったんだろう。自分は最初に「std::upper_boundを使おう!」と心に決めて実装を始めた。comp)が使えるはずだと確認したところまでは良かったが、ここから罠が多い。element)についての記述なので逆が正しい。ここに気づくのにかなり時間がかかった。valueはcompのどっち側の引数に入るかも、上の式を冷静に見れば左側だとわかるんだけど混乱していたので何回も間違えた。混乱していた理由としてはstd::lower_boundだと引数が入る順番が逆になる。思うと適切な方ってどっちだとみたいな感じになり脳が爆発する。時間はかかってパフォーマンスは崩壊したけど、なんとか最終的にはそこそこ綺麗には書けた気がするので満足感はある。最近はコンテスト中もわりと綺麗なコードを書きたいという気持ちが強くなってきた。int64_tすら外しているのもその一環で、タイピング速度はやや落ちている気はするので損はあるんだけど、気持ちの問題。PaymentD問題でさんざん混乱した頭ではこれを30分で処理することなんてできない。桁ごとに見ていって繰り下がりを考慮しながらどうにかこうにかするんだろうということはわかるが、それを適切に実装するのは一日明けて今日実装していても大変だった。桁DPだという気持ちを持っていた方が楽だったのかな。提出F問題は解説PDFを読んでもはぁという感じだったのでまた後日。論文を書いているのもあってある程度情報を隠しながらやっていかないといけないかなと思っていた部分もあったのだけど、やはり性に合わない感じがしてきたので書きたいように書こうという方針で。正直なところ論文も公開しながら書きたいくらい......。前回からの変更点を(オセロへの対応を追加した以外のものについて)振り返ってみる。今まで基本的に技巧2をレート測定の対戦相手に使っていたが、不具合が出てきたので替えることにした。不具合というのは技巧2が探索中にセグメンテーション違反で落ちることで、今までは上手くいっていたのだが新規に技巧2のリポジトリからクローンしてコンパイルすると失敗してしまう(Ubuntu18.04/g++7.4.0)。いくらかコミットを戻ってコンパイルしてみたりもしたが上手くいかなかった。今まで正常に動いていたバイナリは今も動くのだが、どうやってコンパイルしたものか覚えておらず、再現性が確保できない。仕方ないので対戦相手をやねうら王/Kristallweizenに変更した。今度はちゃんと手順を忘れないようにダウンロードスクリプトを書いた。submoduleで管理した方が良いのかもしれないが、ちょっと使い方がよくわからなかったので妥協中。あとはGPLソフトをsubmoduleとして取り込むとMiacis自体もライセンスをGPLにしなければならないかもしれないと思ったのもある。レート測定で用いるのはセーフな気がしているが、ちゃんと規約を確認しているわけではない。Ubuntuで利用可能な最強ソフトがなんなのかわかっていないが、論文で引用する可能性があることも考えるとWCSC優勝・準優勝などの箔が付いているソフトを使っている方が良いかなと思ったのでやねうら王/Kristallweizenにしている。そのあたりの事情に疎い将棋ソフト開発者である。ネットワークの巨大化とりあえず手っ取り早く強くする手法としてネットワークを巨大化した。以前fp16を検証したときは学習もfp16でやろうとしていたので上手くいかず諦めていたが、対局時のみfp16にすれば性能低下はなかった。これにより生成速度は1.7倍ほど(正確な数字は取っていないがだいたいこれくらい)になったのでこれも多少性能向上に繋がったと思われる。対局結果というわけで128chで学習したものをやねうら王/Kristallweizenと対局させた。うら王/Kristallweizenは強いので1Threadかつ一手0.1秒にして、それに対してMiacisは一手0.5秒でようやく互角くらいになる。2Mステップまで学習させていった結果が次のような感じ(縦軸はやねうら王/Kristallweizenに対する相対Eloレート)。今までの64chだとまさに丁度互角くらいだったので、128chにしてレートが+80くらいは伸びたと思われる。学習率の制御とかをちゃんとすればもう少し伸びそうな気はしているが、だいたいこれの学習に2080ti×2枚のマシンで2週間かかるのでそうそうたくさん試せるわけではない。みたいな話もあるdepth12くらいだと0.1秒オーダーかな。試すと分かりますがこのレンジだと技巧2が未だに最強ですよ。2020年1月22日ので、できれば技巧2も使えるようにしたいのだが、セグメンテーション違反になる原因を探ってみた感じだと合法手生成でコケている感じでよくわからなかった。Ubuntu18.04/g++7.4.0で上手くできる方法を知っている方がいれば教えていただければ......。03:00ここ2ヶ月の進捗Tweet広告を非表示にするもっと読むコメントを書く2020-02-15近況1行まとめ去年のWCSCで使った手法(AlphaZero+分布型強化学習)についての論文を出そうと奮闘していたのですがちょっと挫折しかかっているという感じです。長い現在はジャーナルに投稿してレビューが返ってきた段階です。レビューの指摘に従って改稿作業や追加実験を行っていたのですが、追加実験で論文の主張と合わない結果が出てき始めていて頭を抱えています。詳しく言うと、論文ではゲームドメインによらず性能が上げられる手法であるとアピールするために将棋だけでなくオセロでも実験を行っていまして、そっちでの提案手法の効果が今一つといった感じなんですね。1回目投稿版では超小規模ネットワークでの結果を使っていたのですが、比較対象が弱いと指摘されたのもあってMaicisにオセロ対応を追加する形で完全に実装し直して実験しました。提案手法フルではやや性能が上がっているんですが、切除実験をしてみると一番主張したいところがほぼ効果なく、一番どうでもいいところが一番効果があるという感じで......。将棋の方で切除実験をやればもっと顕著な差が出そうな感じはあるんですが、将棋では1回の学習・評価に2,3週間かかるので実験をたくさんやるのはしんどいんですよね。計算資源がそんなにあるわけじゃないのに本将棋で実験しているのが良くないなぁと改めて反省しています。再投稿の締め切りが迫ったプレッシャーもあってかここ数日心身の調子が悪くなっていて、ちょっと再投稿は無理そうかなという見通しになっています。再投稿締め切りに間に合わなかった場合でも新規投稿として扱われるだけなので、そんなにデメリットがあるわけでもないのかなとは思うわけですが。実験結果をちゃんと解釈すると論旨がやや変わりそうな気配もあるので新規投稿の方がむしろ相応しいのかもしれないとも思いつつ。あとはそもそもレビューの指摘でもあったんですが、「トップソフトと差が大きすぎる低レベルなところで手法の有効性を示してもどうなのか」みたいなところは自分としても感じるところであり、もう少しプログラム自体の性能を上げないとなーと思います。ここ数カ月は基本的にオセロの方ばかりいじっていたので将棋側の性能は上がっているわけではなく......。根本的に論文を書くことが全く好きではないことがわかり始めていてつらいですね。プログラムを書きたい。最近はあまり新しい工夫を実装する時間がなく、とりあえず今の時点での学習に再現性があるかどうかを確認していた。現状使えるマシンは、2080tiを2枚搭載しているものが1台、1080を2枚搭載しているものが2台となっている。実装上の都合によりマシン間でのデータのやりとりはできないので、これら3台をそれぞれ独立に学習させることしかできない。個人的にデスクトップマシン1台で学習できることを目標としているので、クラスタ化学習はあまり進んで実装する気になれないという事情もある。これら3台でそれぞれ別にランダム初期化したパラメータから学習を初めて同じような結果になるかを確認した。かかった時間は2080tiのマシンが344時間(≒2週間)、1080のマシンが487時間、526時間(≒3週間)となった。2080tiと1080では本来もっと差があってしかるべきだが、そうなっていないのは実装上の問題でGPU利用率が100%になっていないからである。Validation損失floodgate2015年の棋譜からレート2800以上のソフト同士のものだけを抽出し、各局面について指し手と最終結果に対して損失を計算した。右:Value損失どれでも損失としては大差なく、再現性がある結果だと言える。本題とはずれるが、1.5Mステップ経過時点で学習率を1/10にすることを試したところ、そこで損失が大きく落ちるよく知られた現象が起きた。1.75Mステップ経過時点でも学習率を1/10にしたのだが、そちらの効果はよくわからない。対局結果1手0.25秒で技巧2(深さ10)と500局対局を行った。技巧2(深さ10)はuuunuuun氏のサイトによるとレート2808であり、それに対する相対Eloレートを示す。どの学習でもほぼ技巧2(深さ10)と互角という結果になった。再現性はある結果だと言える。性能面でも1.5Mステップにおける学習率の調整は効果があるようだ。まとめとりあえず1手0.25秒でレート2800は安定的に出せることがわかった。1080マシンでも同じような結果が出ることが確認できたので、これらを使って上手く実験を進めていきたい。現状は諸事情により将棋だけでなくオセロでも検証できるように実装を進めている(multi_gameブランチ)。ゲームには対応できそうだと期待しているが、どこまで上手くできているかはわからない。いずれは囲碁なども実装してみたい。技術的な内容というよりはやや曖昧な、(この言い方は好きではないが)ポエムっぽい文章を書いてみるなど。今年の選手権でmerom氏には話した気がするのだけど、プログラム内部に盤面を保持してそれを遷移させて評価関数に入力するという方式は、継ぎ盤を用いて思考しているようなものなのではないかと感じることもある。盤面の遷移則自体も学習できるならそうして欲しいし、その学習が価値判断や指し手の学習に良い効果をもたらす可能性もあるとは思っていた。MuZeroの手法は表現ベクトルにおいて遷移を考えるという手法の一つとして見なすことができ、これは個人的な解釈で言えばまさに脳内盤を遷移させているようなものだと感じられる。一方で明示的には「遷移予測した表現ベクトル」と「遷移先の盤面をエンコードした表現ベクトル」が近くなるような損失はないので、価値や方策は似た値を出力するが表現ベクトルとしては違うものになっている可能性は高いと思われる。手元の実験(教師あり学習)では、「遷移予測した表現ベクトル」と「遷移先の盤面をエンコードした表現ベクトル」の二乗誤差を損失に含めるなどとしない限り、両者の各要素についての平均二乗誤差が5くらいは残り続けるような結果が得られている。二乗誤差を損失に含めれば二乗誤差は0.005ほどまで落ちるが、これは表現ベクトル全体が単純に小さくなるためでもあることがわかっている。個人的にはやはり「遷移予測した表現ベクトル」と「遷移先をエンコードした表現ベクトル」はできるだけ一致する方が良いのではないかと思われる。ルール的に同じ盤面であることが理屈としてわかっていることが担保できれば嬉しい。そのためには連続的な表現ベクトルではなくて、離散化などの処理が必要なのかもしれないとも考えたりはするが、試したみたことはない。自分は盤面の再構成誤差を損失に含めるブランチも作ってみていて、少なくとも盤面を直接エンコードした表現ベクトルから盤面を再構成することはかなりの精度(99%以上)で可能であることがわかっている。遷移予測した表現ベクトルからの再構成では確か70%程度まで落ちてしまい、特に持ち駒の数を誤解するケースが多かったと記憶している。盤面の認識は怪しいのに価値判断はそれなりに可能というはやや妙だなという印象を受けた。したデータがどこにあるかわからなくなっているので曖昧な話ではあるが......。遷移則を学習することが性能向上に結びつくかは微妙なところではあるけれど、学習の高速化に少しでも寄与する可能性はあるのではないかと期待している面もある。MuZeroではあまりそのような傾向は見られていないようだが、なにかうまいやり方があればなぁとは思うところ。1842(+7)全完早解きセットだったので3WAを出すようではそれほど良い順位にならない。出力のYes/Noが1/0だと判定をそのまま出せば良いので楽なんだな。実際に方針として選ぶかどうかは別の問題として、DPがさっぱり思い浮かばないの自分でも呆れるな。ついて、自分より左に出現している文字の集合と、自分より右に出現している文字の集合をあらかじめ構築しておいて、あとはループして実際に構築して答えの集合に突っ込んでいってサイズを出力。計算量重いかなと思ったけど、解説PDFを見るにもっと重い解法でも大丈夫っぽいのでそういうのに救われた。時だけ特別扱いをするという意味不明なことをして1WA。美しくない処理を平気で提出してしまうのひどいなぁ。して固定して考えたくなる。1回交わる可能性があって、それは距離の差がある値になるまで続く。1回交わる場合に対処できてなくて2WA。考えればこれは二分探索をする意味がない。普通に割り算で求められることを無駄にやって混乱してWA出して、ということになっている。言えば解説PDFを見ると出会う場所がint64_tを超える場合があるらしく、全然注意してなかった。なんとなく差分っぽい感じで計算したのでそれは回避できていたようだが、運が良かっただけ。1835(-4)E問題以外の5完。うーん、E問題解けないようではひどい。レート下がるのもしょうがない。前回ドハマりした反省として、今回は順位表を常に眺めながら参加した。ある問題について何人解けているかという情報は大きく、それである程度の難易度を察することができる。それが問題を解く力を付ける上で良いのかどうかは判断がつかないが、最近はちょっとまたレート最大化に拘りたいという気持ちになってきたのでこうすることに。今回はそれが結構大きく、F問題が簡単であることが読み取れたのでそっちに先に取り組んだおかげで大失敗を免れた。Holiday流石にこれは曜日名をコピペしたが、コピペしても結局何を求めるのかでやや混乱した。S)と書けることが思い浮かんだので満足。N最初は全部小文字かと思ってそう処理するプログラムを書いたら意味不明な文字列が表れて混乱した。無駄なキャストが挟まってしまった。桁数を求める部分とかがきれいに書けなくてやや不満。Tree解法自体は簡単にわかるけどどうやって実装するかに少し迷う。最終的に辺にインデックス持たせてそこに書き込んでいく感じの実装にして、まぁそんなに悪くなかったかな。なるこのを数え上げれば良いというところまで気づいたのにそこからどうやればいいのかがわからなくて解き切れなかった。std::mapを自然に使うだけで良いじゃん。なんでこれが思い浮かばないのか。類問がパッと思い浮かばないのも全然練習していないことの証左。Sugoroku妙に解いた人が多いので先にこっちに取り組んだ。いうのもあってどうせ単純な解法なんだろうと決めてかかる。適当にダイクストラ法書いて提出してTLE。