COSUMIのKataGo用サーバが止まっていました (2024年2月16日)

同じような話を繰り返して申し訳ないのですが、16日2:55~14:15ぐらいの間、COSUMIのKataGo用サーバが止まっていました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

今現在はもうすでに復旧しています。今回も前回同様、KataGoを使用しないサービスには影響ありませんでした。

原因は前回とは違って、ログを見てもよくわかりません。EC2のモニタリングの「CPU 使用率」とか、「ネットワーク受信量」とかのグラフが一瞬途切れているのがなんかおかしくて、lastコマンド叩くと、当該の時間帯は二重にシステムが起動していることになっている…(どゆこと?) なんか特殊なリブートしたのかな?

COSUMIのKataGo用サーバが止まっていました

16日1:26~17日2:06ぐらいの間、COSUMIのKataGo用サーバが止まっていました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

今現在はもうすでに復旧しています。気づくのが少し遅くなってごめんなさい。ちなみに、KataGoを使用しないサービスには影響ありませんでした。

ログを見たかぎり、GPUのハードウェアの問題に思えるのですが、AWS EC2の場合、インスタンスを再起動できちんとさようならできているのでしょうか?

COSUMI 15周年

[以前の関連記事] : COSUMI 5周年
[以前の関連記事] : COSUMI 10周年

今日2023年5月26日で、COSUMIは開始から15周年を迎えることになりました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

15年という数字に特別の切りのよさを感じているわけでもないのですが、10周年の時に「最低でもあと5年は続けたいなと思っています」と書いたので、それを今一度ここで更新させてください。今日からまた、最低でもあと5年は続けます。そして、それ以降については時代に決めてもらいたいと思っています。

ここ最近、私がCOSUMIとさよならするタイミングについて、本当によく考えるようになりました。開始当初はこれっぽっちも想像しなかったことなんですが、それは私がぽっくり逝った時になる可能性も高くなってきたように思います(笑)。で、もしそうなると、みなさんに結構な迷惑を掛けることになりそうなので、どうしたものかなとも思ったり… 本当にまだなにも調べていませんけど、ドメインを買ってくれて、その1/30の価格で1年間、最大30年使わせてくれるサービスとかないかな?

直近1年間(2022年5月26日~2023年5月25日)にCOSUMIが打った総手数(COSUMI側だけ。ユーザが打った手数は含まず)は、計2,286,711,427手でした(実際はもうほんの少しだけ多いのですが、正確にはちょっと分からず…)。平均して190,559,286手/月、6,264,963手/日、261,040手/時、4,351手/分、72.5手/秒ぐらいになります。一番最後の秒あたりの手数に10.0(以前から使っているこの数字、これは10.5ぐらいの方がより正確かもですが…)を掛けると、だいたいその時の対局数になりますので、平均725面打ちぐらいですね。もうきちんと調べはしませんが、この15年間での平均は400面打ちとかだと思うので、だとすると延べ対局時間は6000年ぐらいでしょうか? なんだか大ごとになっちゃいましたね(笑)。このまま続けさえすれば、来年中には夢の1億敗も達成できそうです。

COSUMIに関わってくださった全ての方に、改めて心からお礼申し上げます。15年間ずっと、私はとても楽しかったです。

* * * * * * *

以下は、先日少し話題になっていた本因坊戦の縮小のニュースなどに関連して、15年間COSUMIを続けてきた私が、日本の囲碁界(日本国内に話を限定しています。ご注意ください!)について思うことを、少し長くなりますが書いておきたいと思います。このブログに以前書いたこととの重複もかなりありますが、ご了承ください。

「囲碁の人気が無くなってきて…」みたいなことを、囲碁の人たちは本当に頻繁に口にします。では、一体どれぐらい人気が無くなってきているのでしょうか? この話題について考える時、どうしても避けられないのがヒカルの碁の影響ですが、2023年現在は、直接的な影響についてはほぼ無くなったと言っていいと思いますし、漫画の連載開始が1999年らしく、今から25年前の1998年なら全くその影響が無かったわけなので、ここではこの2つの時点での比較をしてみたいと思います。まずはじめに、プロ棋戦の人気について考えます。人気なんていうと不正確な話になりやすいので、ここではそれを、新聞や雑誌で読んだり、テレビやインターネットの動画配信で観たりなど、どのような手段を通じてでもよいので、誰かがプロ棋戦を消費している時間をすべての人で合計したものと定義して、その定義での私の推測は、2023年現在は1998年の1/3ぐらいになっている、というものなんですが、おそらくこれは多くの方が概ね同意してくれるような数字ではと予想します。次に今度は、誰かが囲碁の対局をしている時間をすべての人で合計したものを考えてみたいのですが、これは1998年と2023年現在とではあまり大きく変わらない、というのが私の推測です。そしておそらくですが、多くの方はこれには同意されないでしょう(まあそもそもの話、これが減っていなければ、「囲碁の人気が無くなってきた」とは普通言わないわけで…)。大幅に減っているはずだと考える人が大半なのでは? ですけど試しに、席料の要る碁会所のような集まりでの対局、要らない集まりでの対局、もっと個人的な2人だけでの対局、ネット碁会所での対局、コンピュータとの対局など、全ての囲碁の対局が行われるシーンの数字を、ひとつひとつの積み上げて比較してみてください。ぜひ一度、頭の体操だと思って少し時間を取って本当にやってみて欲しいのですが、「あれっ、意外と減ってないかも」という気がしてきませんか? 実際、上で書いたように、この15年間のCOSUMIだけでも、もともとゼロだったものが平均725面打ち、それを国内に限定して×0.72の平均522面打ちになっているんですよ? この分だけでも、代わりに減った部分を見つけるのは結構大変なことだと思いますが… 以前から、「コンピュータとの対局」量は乱暴に推測された時に、実際よりもかなり小さく見積もられる傾向があると感じていて、おそらくそれは、誰かが行う「人間との対局」は最低1人にそれが観測されるのに対して、「コンピュータとの対局」は全く誰からも観測されないことも多い、という事実に起因していると考えています。COSUMIのことを知っている人に、「直近24時間中、COSUMIで一番たくさんのユーザが打っていた時間帯では、何人の人が対局していたと思う?」と質問すると、多くの方が100人以下と答えるのではないでしょうか? ですが、実際は1200~1500人です(加えて言うと、この5年間ぐらいは、メンテナンスなどでサーバが止まった時とその前後以外、一瞬たりとも100人以下にはなっていないはずです)。そして、10000人以上だと答える人は一人もいないでしょう。

で、ここから先は、この「対局時間は減っていない」という私の推測を正しいものとして話を続けさせていただきたいのですが、まあ正直、ここまで来ても多くの方はその前提に同意されないでしょうし、その場合は、ここで読むのやめていただいて結構です。まだ先は少し長いので…(笑) これに関しては、誰もきちんとした数字を出しようがないと思うのでどうしようもないですね。

以前から強く感じていたことなのですが、多くの人(これは囲碁をやる人に限らず)が上の「プロ棋戦の観戦」と「自身の対局」の2つ(や他の囲碁の楽しみ方)を、典型的な補完財だと思いこんでるような気がしています。「自身の対局」のために「プロ棋戦の観戦」し、「プロ棋戦の観戦」すると「自身の対局」もやりたくなるでしょと。コーヒーと砂糖の関係ですね。確かにそのような側面があるのはもちろんのことなのですが、それと同時に、この2つにはかなり強い代替財の側面もあると私は思っています。例えばそれは、誰かの囲碁な欲求が片方だけで満たされてしまうことがあるからだったりでもありますが、それ以外にも、仮に両方を望んでもどちらか片方だけしか選択できないということが、実際は結構多いんですよ。多くの場合、それは自由時間の少なさが原因で。以前、このブログで書いたことですが、COSUMIでは平日の12:40あたりで、いつもちょっとした対局数のスパイクが発生します。データが少し古いですし、今はもう少しマイルドなようですが、その時載せた、時間帯別にCOSUMIが打った手数のグラフがこれです。

COSUMIに纏わる数字の話
http://www.perfectsky.net/blog/?p=273

生活リズムなんて本当に人それぞれだし、海外からのアクセスだって無いわけではないのに、これだけはっきりした形が出ていました。さっきカルピスを飲んだ。後で風呂上りにビールを飲むつもり。そんな時に誰もコーヒーと紅茶の両方を飲んだりはしません。お腹たぷたぷになっちゃう(笑)。そんなわけなので、「プロ棋戦の観戦」量と「自身の対局」量の推移に大きな乖離が生まれるのは、なにも不思議なことではないんです。そして、これがまた結構重要なことだと思うのですが、この自由時間の少なさに由来する代替財の側面は、1998年よりも2023年現在の方が強くて、今後も時代が進むにつれてさらに強くなっていくと思います。

最後に、ここまで長々と続けてきたこの話の最終的な結論なんですが、それは「プロ棋戦の人気をどうにかしたいなら、プロ棋戦自体をどうにかするしかない」ということです。いやいやここまで引っ張ってきてそんな当たり前のことをと言われるかもしれませんが、これ同じことを主張される方が本当に少ない。代わりに「囲碁人口をもっと増やさないと」とか、そんなのばっかりじゃないですか。先日の本因坊戦の時も、二日制やめるな、リーグ廃止するなと、棋戦の変更を嫌う声の方がよっぽど多いですからね。まあ、そういうことを言っている人が、必ずしも「プロ棋戦の人気をどうにかしたい」人ではないのかもしれませんが、さすがにもう少しちゃんと現実を見た方が良い。隙間時間に囲碁したい気持ちを、ある意味強く意図せず、しかし結果的にかき集めることになったが、今のCOSUMIです。雨の日にアクセスが大きく増えるのもそういうこと。2023年に必要なのは、10分で消費できるプロ棋戦コンテンツであって、二日制ではありません。

COSUMIでKataGoを使い始めます

前回の記事でも少し書きましたが、COSUMIでKataGoを使ってみようと思います。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

とりあえず19路盤の互先の対局でレベル8まで作ってみました。こちらがテストページ。今までの(と置き碁)はレベル1相当です。19路盤の互先以外は今までのと違いはありません。

https://www.cosumi.net/play-test20220703.html (正式にリリースしたので削除しました)

問題なく動くようであれば、正式にリリースします。重大な問題が発生したら、永久的に止める可能性も今はまだありますが、たぶん大丈夫かな? ぜひ一度遊んでみてください。注意点として、上のテストページからリプレイに行ってその後盤面クリックしても、元のテストページには戻りませんので、そこはご注意ください。また、予告なく削除されたりなんなりもします。

今回の19路盤のレベル設定は、レベルがひとつ違うもの同士での自己対戦の勝率が80%になるように調整しています。このあたりの話を書きだすとかなり長くなるので詳細は省きますが、おそらくですが、レベルのひとつ違いの差が9路盤などと比較して大きく感じられるのではと予想しています。でももう、この「自己対戦の勝率が80%」で今後もいきます。それなりにしっかりとした考えあってのことなので、変更することはまずありません。それにしても、この強さの設定はいつもながら本当に難しいですね… あちらを立てるとこちらが立たずで、どうにも収拾がつきません。今しばらくは微調整が続くと思います。あと、その方が打っていて楽しいのではと思うので、「どのように強さを変えているのか」もあえて今回はここに書かないでいようと思います。と言っても、もちろん特別なことは何もしていません。

今後の予定もここに書いておきます。まず、今回のテストが問題ないようであれば、19路盤よりも小さな15路盤、13路盤、11路盤、9路盤でも同じくレベル8ぐらいまでできるようにしたいと思います。それから、これも前回の記事に少し書きましたが、8路盤までの棋譜を日本語で添削するNNを今作っているので、それも使えるようにしたいと思います。で、それができたら、今ある9路盤までの悪手指摘の機能は、少なくとも日本語ページでは完全に削除するつもりです。その代りに、サーバ代との兼ね合いになりますが、9路盤以上ではKataGoに添削してもらえるかもしれません。ちなみに、この2つの添削機能は、COSUMIで打たれた棋譜に限らないようにするつもりです。以上の内、どれから実装するかは、現時点では未定です。これが全部できたら、私の中でCOSUMIはおしまい…

[追記 2022/7/9]
13路盤以下は、今でもそれなりに強いレベルで対局できるので、あまり急ぐ必要もないのですが、15路盤に関しては19路盤と同じ状況なので、最初のリリース時に、19路盤だけでなく15路盤でもレベル選択できるようにしたいと思います。現在、大急ぎで準備していますが、19路盤も今一度設定を詰め直したいので、正式なリリースまで早くても後2週間は掛かりそうです。

[追記 2022/7/21]
テストページで15路盤の互先でもレベル選択できるようにしました。15路盤は、「レベルがひとつ違うもの同士での自己対戦の勝率が78%」でいきます。19路盤も全て調整し直して、こちらはレベル9もいけそうですが、もういいですよね? 大きな問題が無ければ、このテストページの内容で3日後ぐらいに正式にリリースします。

レベル調整の作業は、どうしても待ち時間が大きくなるのですが、ここ最近はそれに合わせた生活リズムになっていましたし、時間が経ってしまうと勘所が頭から抜けてしまうので、次の作業としては、引き続き9路盤、11路盤、13路盤もレベル8ぐらいまでにしてしまおうと思います。そしてその次に、今ある悪手指摘の機能を、19路盤まですべて対応させる形でKataGoに置き換えたいと思います。ここまでいろいろやってきた感じでは、KataGoはかなり安定してますね。たまによく分からないおかしなことが起こっても、よくよく調べると、私かGNU Goが悪いことがほとんどでした。そして、やはりとても軽いです! なのでこれもできると思います。そして一番最後に、8路盤以下はそれを私の作った日本語で添削する機能に置き換えて、それで完成かなというのが今の予定です。あと書き忘れていたのですが、置き碁に関してはレベル選択も含め今後も一切変更加える予定はありません。

テストページで打ってくれる人が現時点までほとんどいませんでしたので、とりあえず今からCOSUMIで宣伝してきます。

[追記 2022/7/24]
正式にリリースしました。今回は、かなり大がかりなアップデートですし、エラーが出ない不具合が発生する可能性も高いので、まだかなり心配なんですが、とりあえず今のところは大丈夫でしょうか? ちなみに今現時点で、正式リリース後、19路盤レベル8の作り碁になった対局は、COSUMIの807勝13敗です。ユーザが投了しているケースも相当多いと思われます。

KataGo用の本番サーバは、当初、メインメモリが16GBのg5g.2xlargeで考えていたのですが、ちょっとお値段が気になってしまい、8GBのxlargeにしてしまいました。裏で何か作業する時に気をつかわされるのがいやですが、足りてるといえば足りてますので、何かあったらまたその時考えます。と思っていたら、CPUもボトルネックになりかねないことにちょうど今、気がついて、少し驚きました。でも、まあ大丈夫なはず。KataGo動かすというのに、メインメモリやCPUの心配ばかりして、GPUは安心っていうのもすごい話です…

で、g5gということでCPUがARMなんですが、ネットで調べてもKataGoを動かしている話はほとんど出てきませんが、特に何も問題なく使えています。Ubuntu 22.04nvidia driver 515CUDA 11.7KataGo 1.11.0という最新(?)の組み合わせで、NVIDIAやKataGoのドキュメントどおりの手順でいけます。書かれていないことでやったのは、KataGoをビルドする時に、cmakeに-DCMAKE_CUDA_COMPILER=/usr/local/cuda-11.7/bin/nvccとオプションを付けたことぐらい。引っ掛かりポイントは特にありませんでした。そして、それでとても安定しています。他のクラウドサービスのことは、私はぜんぜん詳しくありませんが、g5g.xlargeはオレゴンで0.42USD/時間とお安いので、同じようなことをするのには、まあ良いのではないでしょうか? 今回いろいろ作業していて強く思ったのは、KataGoの動作環境はできるだけ多くの人で共有したほうがいいってことですね。日本棋院とかそういうことやらないんですかね? てかやってるのかな?

[追記 2022/7/26]
現時点で、正式リリース後、19路盤レベル8の作り碁になった対局はCOSUMIの3191勝39敗、レベル7は165勝6敗、レベル6は169勝6敗。今後、ガチな方々が遊んでくれるようになったとしても、強さはもう十分ですね。

KataGo用のサーバを追加した代わりに1台サーバを止めたのですが、結果、KataGo用のサーバ以外のリソースがぎりぎりになってしまいました。事前にユーザの行動が正確に読めなかったので仕方ない部分もあるのですが、正直、全く問題ないだろうと予測していました。AWSのSavings Plansの関係もあり、向こう1か月はこのままの構成で行かせていただきたいのですが、ちょっと無理かもしれません…

[追記 2022/7/28]
どこまでいっても正確な言葉の定義や数字を示しようがないのですが、いろいろ調べてみた感じ、19路盤レベル8でユーザが投了している対局は、作り碁になった対局の7倍ほどあるとみてよさそうです。この数字は、私の予想よりもかなり大きいのですが、投了するようなユーザは、投了で対局を早く終わらせる分、1人あたりの対局数が多いのかもしれません。加えて、これは最初から分かっていたことですが、ユーザが勝った対局も、結構な割合でユーザが人間ではなくコンピュータです(今回はあるのかどうか調べていませんが、COSUMI vs COSUMIとかやる人は昔からちょくちょくいます。ちなみに、私もテスト中に何回もやりました。AutoGo便利!)。となると、人間ユーザの勝率はもう0.1%ぐらいしかないことに… 確かに、レベル8はそれなりに強いのでしょう。しかし、それ以上に思うのは、COSUMIには本当に強い人は全然いないんだなあということです。もともとCOSUMIが弱かったのだから、当然でしかたのないことではあるのですが、これからはそういった方々にも価値を提供できるようになりたいですね。ぜひ一度、名のある方にレベル8をバサバサと叩き切ってもらいたいところです。

後、対局リプレイページにSGFをクリップボードにコピーするボタン用意しておきましたので、便利にお使いください。

[追記 2022/8/27]
9路盤、11路盤、13路盤でもレベル8まで強さを選択できるようにしました。ただ、本当に申し訳ないのですが、いろいろな事情があり、強さの最終的な微調整は、15路盤と19路盤の時とは違って、ユーザとの対局結果を確認しながらでやらせていただきます。ものすごく雑なことをしますが、総合的にそれが一番良さそうに思いました。今一番心配しているのは9路盤ですね。約1日分のデータから判断する限り何とかなってそうでもありますが、レベル8はかなりぎりぎりのようです。できれば残したいのですが…

それから、すべてのレベル、すべての碁盤サイズで、サーバの負荷が高い時に対局が開始できなくなるのを止めました。「9路盤のレベル6とレベル4はできるけどレベル5はできない」みたいなのは、ユーザも混乱するばかりですし、私も気持ち悪いのでそういうことにしました。サーバの負荷を見積もるにあたっていろいろ考慮しなければいけないことがあるのですが、これも約1日分のデータを見る限り、現在のサーバ構成で酷い状態になることは無さそうです。もし危なそうだったら、もうお金で解決してしまう予定です。

次は、KataGoに棋譜を分析させる機能を実装していきたいと思います。

[追記 2022/8/30]
9路盤レベル6~8をレベル0.2相当分ぐらい、11路盤レベル5~8をレベル0.3相当分ぐらい、13路盤レベル5~8をレベル0.4相当分ぐらい、弱くしました。一回これで様子を見てみます。

[追記 2022/9/14]
棋力を調整するために、ここ最近さまざまなデータを調べていたのですが、なんだかちょっと問題が多すぎますね… 詳しくはもうここに書きませんが、棋力を調整すると言ったって、「棋力」という言葉を気持ちよく定義しようがなく、どうにもやりようがありません。これは以前このブログでも書いたことがあるかもしれませんが、私は「COSUMIでは、新しいものを追加するのは自由にしていいけれど、すでにあるものはできるかぎり変更してはいけない」とかなり強く考えています。というのは、長い期間の中で、ユーザがCOSUMIを自身の棋力向上のベンチマークにしていることがとても多いからです。そういう考えがあったので、実際もう何年も、着手の変わる変更は基本的に行ってませんでしたし、また、そういった期間が長くなればなるほど、またさらになにか変更することが憚られるようになっていきました。今回、KataGoを使い始めていろいろ作業している時も、9~13路盤のレベル2以上も全部これに差し替えられたらなと何度も何度も思いましたが(ぱっと思いつくだけでもメリットは腐るほどあります)、それだけは絶対だめだと思い、真剣に検討することは一度も無かったんです。が、ここにきて、それがもうちょっと避けられない気がしてきました。

今回の話に関係する私がCOSUMIで実現したいことを、重要性の高い順に書き出していくとこんな感じです。

  • 以前からあった9路盤のレベル1~レベル5、11路盤レベル1~レベル4、13路盤レベル1~レベル4、15路盤レベル1、19路盤レベル1の棋力を変えたくない
  • 棋力は同じでも、できるだけきれいな手を打たせたい
  • 同じ碁盤サイズの中で、レベルひとつ違いがすべて同じぐらいの棋力の違いに感じられるようにしたい
  • すべての碁盤サイズで、数字の同じレベルが同じぐらいの棋力に感じられるようにしたい
  • 以前からあった9路盤のレベル1~レベル5、11路盤レベル1~レベル4、13路盤レベル1~レベル4、15路盤レベル1、19路盤レベル1の棋風を変えたくない
  • できるだけ説明が容易な基準で、それぞれのレベルの棋力を決定したい
  • サーバの負荷を下げたい

いろいろ考慮した結果、これらをできるだけバランスよく実現するために、次のような変更を行うことにしました。

  • 9路盤レベル2~レベル5、11路盤レベル2~レベル4、13路盤レベル2~レベル4を、それより上のレベルと同じようにKataGoベースに変更する
  • それぞれの碁盤サイズのレベル2以上は自己対戦で同じ勝率になるように調整する
  • レベル1とレベル2の間はまた別の勝率になるように調整する

ここまではもう決定事項です。自己対戦での勝率はもう少し微調整が必要だと思いますが、とりあえず、レベル2以上は9路盤で66%、11路盤で70%、13路盤で73%、15路盤で75%、19路盤で77%、レベル1とレベル2の間は、9路盤で71%、11路盤で75%、13路盤で78%、15路盤で80%、19路盤で82%で調整することにして、すでに変更しました。

変更前との比較を簡単に書いておきます。まず、すべての碁盤サイズでレベル1は何も変わっていません。9路盤レベル2~レベル5、11路盤レベル2~レベル4、13路盤レベル2~レベル4は、棋風が激変していると思います。棋力の方はあまり変わってないはずですが、ここをもう一度チェックする必要があります。9路盤レベル6~レベル8は、下の方は少し強くなり、上の方はあまり変わらず、11路盤レベル5~レベル8は、下の方は少し強くなり、上の方は少し弱く、13路盤レベル5~レベル8は、下の方はあまり変わらず、上の方は少し弱くといった感じ。15路盤と19路盤のレベル2~レベル8は、下の方はあまり変わりませんが、上に行くにつれ弱くなっていってレベル8は変更前のレベル7.2ぐらいです(そういうわけなのでレベル9以上も考えたほうが良いのですが、それはまた今度)。

今回の変更は新規のユーザにとっては間違いなく良い変更ですが、以前からのユーザにとって良いか悪いかは場合によるとしか言えないですね。それでも、もし今後長い期間遊んでもらえるのならば、やはり最終的には良い変更になる可能性が高いとも思います。結局のところ、これはCOSUMIをいつまで続けるのかが大きく関係していて、長く続けたいのであれば必要なアップデートに違いないのですが、私自身COSUMIを長く続けられるイメージがなかなか持てないんですよね… だから、こんなに躊躇してしまうのだと思います。

買ったばかりのc7gのSavings Plans、48万円ぐらいしたのですが、少し腐ったっぽい…(泣) なかなか上手くはいきませんね。なにか使い道はないかな?

[追記 2022/10/1]
5路盤~9路盤(レベル0)のみにあった悪手指摘の機能を廃止し、代わりに19路盤までに対応した新しい棋譜解析の機能をKataGoを利用して作ってみました。以前の悪手指摘機能とは比較にならないくらい精度が上がっていますし、結果的に悪手の指摘がたくさんできるようになっています。そして、悪手が無い時もその局面の良い手を表示するようにもしました。あと、目数による形勢の推移のグラフも用意しました。

今回の棋譜解析機能と以前の悪手指摘機能とのひとつ大きな違いとしては、悪手を指摘するタイミングが1手分早くなっていることがあります。COSUMIは基本的にまず「対局」があって、その後、その対局の手をどうこう言うってところから、一般的なその手の囲碁ソフトの「この局面ではここに打つのが良い/悪い」ではなく、「ひとつ前の局面でここに打ったのが良い/悪い」という1手後のタイミングで指摘が行われていました。理屈としては特におかしなことではなかったように思いますし、私自身、それを見づらいと思ったことは正直今までぜんぜん無かったのですが、今回、表示する情報量が増えたからでしょうか、盤面見ていると不思議な感じに頭がバグって、表示されていることの意味がどうにもこうにも取れなくなってしまったので、一般的なタイミングである1手前に早めました。ただ、そうなると今度は「良い手悪い手は分かったけど、実際に打った手はなんだっけ」ってどうしてもなりますので、次に打たれた石を半透明で表示するようにしています。乱暴な言い方をすると、0.2手分ぐらい今度は遅らせたイメージですね。このあたり、さんざんいろいろ試したのですが、まあこれで良いのではと今は考えています。

それから、ユーザの手番だけではなくCOSUMIの手番も解析しているのも大きな違いのひとつです。今までは、1手とばしで片側だけを見ていましたが、今回、形勢のグラフにも必要なこともあって黒白両側見るようになったので、COSUMIの手番でも良い手悪い手表示するようにしました。ユーザ側だけに表示を限定したいという要望は必ずあると思いますが、特別なUIを用意したくはありませんので、申し訳ありませんがこのまま使ってください。

最後にもうひとつ違いを挙げると、以前の悪手指摘機能は対局リプレイページに飛ぶだけで利用できましたが、サーバリソースが無駄に使われても困るので、今回からは基本的にワンクリック必要にしています。ただし、今現在はまだそうはなっていないのですが、8路盤以下に関しては自動で有効になるようにしようと思っています。というのは、8路盤以下は今までも自動だったからいうことがまずひとつと、あと、今私が作っている8路盤までの棋譜を日本語で添削するNNは、クライアントサイドで動かす予定で、だとしたら必ず自動で有効になるようにしますので、その時ともつながりがいいかなと思うからです。それから、サーバ負荷がまだちょっと正確には読めないので、現在は初手から最大100手までしか解析しませんが、これはおそらく300手までいけると思います。現在、データを取っているところなので、しばらくお待ちください。最終的には、サーバ負荷に応じて、多少の制限はするかもしれません。

それから、これも忘れずに書いておきたいのですが、今回の棋譜解析機能は、COSUMIで打たれた棋譜に限らず使えます。これとかこれとかから、適当にご利用ください。

対局も棋譜解析も、大量のパラメータを手で調整しなければいけませんので、しばらくは微調整が続きますが、KataGoを利用したもろもろの実装は、一応これにてひとまずおしまいです。この死ぬほど強くて、死ぬほど速くて、死ぬほど便利で、死ぬほど安定した神プロダクトを作ってくれたlightvectorぱいせんとゆかいな仲間たちに、心から感謝申し上げます。GNU Goをブラウザで動かしたいと思って始め、Fuegoで大きくなったCOSUMIですが、KataGoですべての夢が叶いました。今現在、KataGoは1日あたり約270万手打ってくれています。

[追記 2022/10/3]
8路盤以下でかつ総手数が100手以下の対局は、棋譜解析機能が自動で有効になるようにしました。また、解析するのが初手から最大100手までだったのを、最大200手に伸ばしました。これでもまだ余裕があるようなら、できるだけ早い段階で300手にします。今の感じだと、たぶん全く問題ないでしょう。それにしても、これだけの処理がg5g.xlargeで足りてしまうのは本当にやばいですね。ついCOSUMIを始めた頃のことと比べてしまうのですが、ハードもソフトも本当に性能向上したんですねえ… 今、囲碁を始めようとしている人が、ちょっと羨ましかったりしてしまいます。

[追記 2022/10/6]
初手から最大300手まで解析するように変更しました。

[追記 2023/2/4]
まだリソースにぜんぜん余裕があったので、15路盤以下でかつ総手数が250手以下の対局まで、棋譜解析機能が自動で有効になるようにしました。また、初手から最大500手まで解析するようにもしました。

それから、今現在使用している「レベル2以上は9路盤で66%、11路盤で70%、13路盤で73%、15路盤で75%、19路盤で77%、レベル1とレベル2の間は、9路盤で71%、11路盤で75%、13路盤で78%、15路盤で80%、19路盤で82%」という自己対戦での勝率は、もうこの数字で固定することにします。いろいろ考えたのですが、まあいいかげんなのではと思います。少し調べてみたところ、KataGoの新しいb18c384nbt-uecっていうモデルはかなり良さそうなので、もうしばらく時間をおいて少し様子を見たうえで、その新しいモデルの使用とこまごまとした修正を入れたものを、COSUMIの最後のバージョンとしたいと思います。そして、その時に19路盤はレベル9も追加すると思います。

去年の春ごろは「もうすぐできるかな?」なんて思っていた日本語で添削する機能は、ちょっと手が止まってしまいました… でも、これもできるだけ早く一回形にしたいと思います。

COSUMIで多数の小さな改良を行いました(2022年4月)

COSUMIで以前から気になっていた部分を、まとめて大量に追加・修正行いました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

全て些細なことばかりで大した話は特にないのですが、一応その中で主だったのをここに書いておきます。

まず、対局リプレイページに、そのページのURLが入っている二次元コードを表示するようにしました。何かの時に使えると思います。それと、スライダーを動かしたりして進めたその局面を初期表示とするURLに変更するボタンも用意しました。先ほどの二次元コードやツイートボタンもこの新しいURLでのものになりますので、これも便利な時があると思います。

次に、ただの碁盤で、一番最後の局面で右矢印を連打してもらうと対局リプレイページに行けるようにしました。これ、以前できないかと聞かれたことがあって、その時にどういう仕様で作ればいいかなと考えている内に、もう作った気になっていました…(笑) 本当にすいません。馬鹿みたいにシンプルな作りですが、そこはご容赦ください

それから、オンライン棋譜ビューアのSGFのパーサを改良しました。もうあまりエラーを出さないと思います。

最後に、white shade囲碁ベンチマークのTensorFlow.jsのバージョンを、最新のに上げさせてもらいました。囲碁ベンチマークのベンチマーク結果については、当然、以前のバージョンとは比較不可ですので、こちらもVer. 3.0という新しいバージョンということにしておきました。

話は変わりますが、AWS EC2のC7gインスタンスはまだ使えないんでしょうか? Savings Plansがひとつ切れたので、どうすればいいのか迷ってます。

[追記 2022/6/5]
COSUMIのこれからの予定を、少しだけここに書いておきます。

C7gインスタンスがようやく来たので、ちょうどいい機会だと思い、これからのサーバ構成をどうしようかといろいろ調べていて気が付いたのですが、KataGoってめちゃくちゃ軽いんですね! b20c256playout 1CUDAmatchモードで、g5g.xlarge500~600手/秒g5.xlargeでは1300~1400手/秒出ることに気づいて本当にびっくりしました(さすがに桁を間違えてるだろと、何回も計算をし直してしまいました(笑))。一応補足しておくと、matchモードとかanalysisモードとかでは、複数の局面をまとめてNNに放り込んで高速化するという、とても素敵な実装になっている(これは前から知っていました。しかし凄い!)のが大きいのですが、今まで自分は一体何を勘違いしていたのか、もうよく分からなくなるぐらい思っていたより速いです。COSUMIはg5.xlargeの1.5倍以上のお金を掛けて120手/秒ぐらいなので、もはやKataGoの方が全然安いですね。

先月でCOSUMIは開始してから14年が経ちました。さすがに折り返し地点はすでに通り過ぎてしまっていると思っています。そして、何か新しいものを実装するのも、もう今が最後のチャンスだなという気持ちでもいます。以前からCOSUMI最後の仕事としてKataGoは出来れば使いたいと思っていましたが、直近は、やっぱり少し無理かなと感じてて半ば諦めモードでいたので、それをやらないのならその代わりにと、今ある悪手指摘の機能を置き換える、棋譜添削を日本語で行うNNを、ここ2か月間ほどずっと作っていました。これについてはほぼ見通しが立ったので、残りの作業は必ず最後まで進めますが、上に書いたようにKataGoがこんなに軽いのであれば使わない手はないので、そちらも少し頑張ってみます。安定して動きさえすれば、19路盤でlevel 10とかも余裕でしょう(それができたらなんかすごいですよね。COSUMIじゃないみたい!(笑))。とりあえず今は、analysisモードのレスポンスで、rootInfovisitsが1の時、moveInfosが空になってしまうのが理由が分からずストップしてます… これなんでなんだろう?

ちなみにC7gは、私がいつも使っているGNU Goを同時に100個走らせるベンチでC6gより26%ほど速く、料金は7%ほど高いって感じでした。

[追記 2022/6/9]
なんかいろいろ勘違いしていたのですが、moveInfosが空になってしまうのはそれでいいんですね。なんとか動きそうですが、いつものことながら棋力の調整が死ぬほど難しい…

COSUMIが非常に重くなっていたのでサーバを再起動しました

昨日7日14:45ぐらいからでしょうか、COSUMIが非常に重くなっていたので、先ほどの8:45ぐらいにサーバを一度再起動しました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

とりあえず、今現在は特に問題ないようですが、しばらくの間、不安定な状態が続く可能性があります。原因は現時点ではよくわかっていません。

サーバ再起動した時に、数百局の対局がぶちっといってしまったと思います。どうかお許しください。

[追記 2022/1/8 10:25]
たぶん分かりました。ハードウェアの障害だと思います。今後、どこかのタイミングで比較的長い期間サービスが停止する可能性があります。先ほどの再起動で改善したようにも見えるのですが、おそらく根本的な解決にはなっていません。うう、めんどくさい…(泣)

[追記 2022/1/8 18:10]
メモリ周りのハードの問題で間違いなさそうです。明日9日の早朝にストレージ以外すべて交換してもらえることになりました。メンテの時はいつもそうですし、確定的なことはとても言えませんので、向こうに予告等を載せておいたりはしませんが、一応、4:00ぐらいに新規の対局開始を止めて、5:00ぐらいにサーバを完全に止めて、7:00までにできれば復帰させる予定だと、ここに書いておきます。

[追記 2022/1/9 6:45]
交換作業が終わりました。今のところ、特に問題ないようです。それではベッドに戻ります。オヤスミナサイ…

7路盤スペシャルバージョンのコミを8目に変更しました

7路盤スペシャルバージョンのコミを、9目から8目に変更しました。

7路盤スペシャルバージョン
https://www.cosumi.net/seven.html

コミを変更した理由については、ぜひこちらをご覧ください。

http://www.perfectsky.net/blog/?p=494

また考えが変わったら、その時再度変更する可能性はありますが、とりあえずはこれで負けないように定石を追加し続けたいと思います。

あと、現時点での最新の定石もこちらで公開しています。

http://www.perfectsky.net/blog/?p=106

[追記 2021/07/11]
難しい変化に飛び込まなくてもよくなったからでしょうか、主だった手順ではもうあんまり負けてないですね。現時点では、日本ルールの7路盤は盤面8目だと、私はかなり強く思っています。12年以上前に始めた7路盤スペシャルバージョン、少し時間が掛かってしまいましたが、これでだいたい一仕事終わりかなとも感じています。

white shadeをアップデートしました(2021年5月)

white shadeをアップデートしました。

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

white shadeのVNの構造に、かなり小さな、けれどもたぶんだいぶ良いと思われる変更を加えました。実際、ロスは少し下がったのですが、以前のバージョンと対局させて強さを計測しても全く変わっていなくてちょっと意外… そういうわけなので、使うかどうか迷ったのですが、手がきれいにはなっているだろうと信じて、アップデートすることにしました。さらに、TensorFlow.jsも最新のバージョンに上げておきましたが、それ以外は基本的に以前と同じです。

今回のアップデートで、一応white shadeをいじるのは最後のつもりです。そんなに強くなくても、きれいにちゃんと打ってくれたら嬉しかったのですが、私にはちょっと難しかったですね。ただし、white shade諦める代わりとして、オンライン版の方でKataGoが使えないかを、時間のある時に少し調べてみます。サーバのリソースもできるだけ無駄なく使いたいので、なんとか実現させたいですね。COSUMI始めてからもう13年が経過したのですが、これがCOSUMIでの最後の大きな仕事でしょうか?

それにしても、今回の変更で少しも強くなっていないというのがまだちょっと信じられないので、CGOSでも少し動かしてみたいと思います。

[追記 2021/07/11]
こちらにも追記しましたが、CGOSで動かしてみました。今回の改良は小さい碁盤サイズで有効だと思われるものだったのですが、9路盤ではやはり少し強くなっているように見えます。手元でもう一度確認してみて、いけそうであれば9路盤にレベル6を戻したいと思います。

[追記 2022/4/23]
ここに書くのをずっと忘れたままだったのですが、あの後、手元で調べたところ、やはりあまり強くなっていないようなので、Tensorflow.jsのバージョン以外はなにも変更せず、そのままの状態で今に至ります

COSUMIのサーバを変更しました(2021年3月)

ここに書くのが少し遅くなりましたが、3月末に、COSUMIで使用してた専用サーバ1台をAmazon EC2 c6g.4xlargeに変更しました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

全体としてほんの少しだけ処理能力が下がっていますが、大きな違いはありません。

解約した専用サーバは8年以上も借りていたらしくてびっくり! 元はメインだったのが、後輩の現メインサーバが来てからはサブとして使っていたものです。8c16tが2発でそれだけの期間ですから、冗談抜きに歴史上一番たくさん囲碁のことを考えたコンピュータなのでは? 50億手ぐらい(?)は打っているような気がしますが、それが対局としてなら、対コンピュータなのが普通であって、対人間でこれだけっていうのは価値があると思います。詳しいことは本当によくわかりませんが、優秀な君のことだから、きっと次の仕事もあるのでしょう。頑張ってね。今まで本当にありがとう。

white shadeをCGOSで動かしています

なんとかかんとか、white shadeをTromp-Taylorな終局とPositional Superkoに対応させて、以前から一度は挑戦してみたかったCGOSで、今現在、動かさせていただいています。

Computer Go Server
http://www.yss-aya.com/cgos/

9路盤と13路盤でそれぞれひとつずつ動かしていて、player nameは9路盤がws-201217_9lv5、13路盤がws-201217_13lv6です。

Crosstable for ws-201217_9lv5
http://www.yss-aya.com/cgos/9×9/cross/ws-201217_9lv5.html

Crosstable for ws-201217_13lv6
http://www.yss-aya.com/cgos/13×13/cross/ws-201217_13lv6.html

それぞれ、こちらのレベル設定と同じに、内部の設定を合わせていますが、Tromp-Taylorな終局とPositional Superkoに対応させた関係で、厳密には全く同じ強さとは言えません。また、いろいろと無駄に重くもなっているのですが、まあそれでも、ほとんどノータイムで打つと思います。少し話変わりますが、以前から、入門者の方には純碁よりTromp-Taylorの方がいいのでは、と思っています。個人的には、どんどん推していきたいです。普及において、ルールは本当に本当に重要だと思いますが… あと少し気になったのですが、例えばfloodgateにはhumanがいることもあると思いますが、CGOSは全くいないと思っていいんですよね? 申し訳ないですが、終局は決してきれいではありません…

最初、すんなり動かなくて少し頭を抱えたのですが、どうやら、genmoveに対するレスポンスの末尾が、改行2つではなく3つだった(今の今まで、全く気づかなかったよ…(笑))のが、関係していたようでした。それ以外にも、Stopに対して一局やらかしてしまいましたが、それに関しても修正済みです。できるだけご迷惑が掛からないように、またおかしかったらできるだけすぐに止めれるよう気をつけますので、どうかよろしくお願いいたします。

[追記 2020/12/18]
13路盤でAya786m_10kに一局、時間切れ負けしていますが、ログを見る限りエンジンの問題ではなさそうでしょうか? 続けて次の対局も打てていたみたいですが、一旦OSごと再起動しました。

[追記 2020/12/21]
一旦、止めました。また少し期間を空けてから動かします。9路盤と13路盤の両方とも、最終的には少なくとも1000局は打たせるつもりにしています。

[追記 2021/02/12]
ここ最近も少し動かしていたのですが、とりあえず両方とも1000局を超えました。現時点で、9路盤が1630局打ってレートが2091、13路盤が1535局打ってレートが2474です。多様なプレーヤーがいることが、正確なレートの測定に不可欠だと思いますので、これからも可能であれば、定期的にCGOSでwhite shadeを動かす予定です。

[追記 2021/07/11]
ここ最近も、white shadeをCGOSで動かしていました。できれば最新のバージョンと以前のバージョンの両方を同時期にと思い、コンフィグファイルでpriorityを設定してやったりもしました。あとで見返した時のために書いておくと、現時点で、ws-201217_9lv5が2730局打ってレートが2124、ws-210530_9lv5が2962局打ってレートが2196、ws-201217_13lv6が1940局打ってレートが2468、ws-210530_13lv6が1265局打ってレートが2445です。当たり前ですけど、CGOSって対局数がなかなか稼げなくて辛いですね…

white shadeをアップデートしました(2020年12月)

white shadeをアップデートしました。

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

今までのバージョンのwhite shadeが全体的に大きく/重くなりすぎてしまっていたので、今回、大幅に小さく/軽くしました(この変更はいろいろ考えてのことなのですが、COSUMI的には今回のバージョンより多くのリソースを食ってしまうものは基本的にNGだと考えています)。今まで動作が怪しかった環境でも、きちんと動くようになっている可能性が、結構あると思います。ただし、この結果、本当に申し訳ないのですが、9路盤のレベル6に関しては、維持することができなくなったので削除しました。あともう一回ぐらいは頑張ってみようかなと思っているので、その時はまた元に戻せるかもしれませんが、とりあえず今現在は無理です。もともと11路盤と13路盤には少し余裕があったのですが、9路盤にはほとんど無かったので、どうにもなりませんでした。

あと、変なタイミングでパスすることがちょくちょくあるのですが、これが減るように少し変更を加えました。実際にどれぐらい効果があるのかは、また時間があったら調べてみます。

さらに、TensorFlow.jsも最新のバージョンに上げておきました。

それから、かなり長い間ほったらかしだった、囲碁ベンチマークも併せてアップデートしました。詳細はこちらに追記しています。今の時期、スマホで5局ぐらい打たせるといい感じにカイロになりますので、ぜひお試しください(笑)。

ベッドに寝転がって、ぼけーっとベンチマーク動かして眺めていると、自分なんかがGTX 1060一発でよくこんなの作れたなと思います(最近はもやっていたし…)。5年前の自分にwhite shadeを見せてもまず信じてもらえないだろうとか、1060ではなく1070買っていたらもはや別の人生だったのではとか、妄想が捗る…(笑) ちょうど今、年季の入ったメインPCを新調しようかなと少し考えていて、もし新しくしたらそれは間違いなく別の人生ですが、まあとにかく面倒なんですよね。もう壊れるまで今のままでいいかな…

COSUMIのサーバメンテナンスをします(2020年11月26日-)

本日、26日23:00頃から、メンテナンスのためCOSUMIを一時止める予定にしています。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

27日の朝までには、なんとか終わらせるつもりですが、絶対の自信はありません。COSUMIにアクセスできなければそういうことだと思ってください。

[追記 2020/11/27 9:50]
えらく時間が掛かってしまいましたが、一応終わりました。遅くなってすみません。ではでは、オヤスミナサイ…

[追記 2020/11/27 23:00]
今まで使っていたFuegoのバージョンr1670が、今回ビルド出来なかったので、代わりに一番新しいr2038を使うことにしたのですが、それででしょうか、Fuegoがなんか遅いですね。かなり以前に調べた時には、r1670と最新のとで、ほとんど何にも違いが無いように感じていたのですが、そうでもなかったのかな? かなり不味そうなのでこれはすぐに調べます。あと、これはまた別件になりますが、今月の10日~21日あたり、サブのサーバのディスクが溢れていて動いていませんでした…(泣) 本当にごめんなさい。今後は気をつけます。

[追記 2020/11/28]
r1670と最新のとで、ほとんど何にも違いが無いっていうのは、どうやら私の記憶違いだったようで、なにがどう違うのかは、ちゃんと調べてみないとよくわかりませんが、同じplayout数では、r2038の方がはっきり遅そうです。とりあえずr1670のビルドが通ったので、そちらに戻しました。ご迷惑をおかけして申し訳ありませんでした。

RapidSSLからJPRSに乗り換えました

COSUMIで使用していたSSL/TLS証明書の期限が近づいて来ていたので、このタイミングでRapidSSLからJPRSに乗り換えました。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

併せて、TLS 1.0とTLS 1.1を切って、さらにcipher suiteも大幅に制限しました。

# Apache
SSLProtocol    all -SSLv2 -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384

この設定はこちらのIntermediateを参考にしたものです。

Mozilla SSL Configuration Generator
https://ssl-config.mozilla.org/

3年前も同じくIntermediateを参考にしたはずですが、状況がかなり変わったんでしょうね、その時と比較すると大幅に厳格になっているように思います。COSUMIはそんなサイトではありませんので、そこまでカリカリに設定する必要もないのですが、もし仮にこれでアクセスできない環境があっても、そんな環境はそもそも対局ゲームなどはまず動きませんので、これで良いと考えています。

JPRSの証明書はさくらで990円/年と十分に安くて良かったです。逆に、最近は有効期間が1年での証明書しか駄目になったようで、毎年この作業をしなければならないのは、結構面倒ですね。

日本ルールの7路盤では黒は盤面9目も勝てない?

このブログへのコメントで教えていただいたのですが、7路盤の次の局面で白からAに切る手があるようです。ちなみに今までは単にBに押さえるぐらいと考えられていたはずです。


Sorry, your browser doesn’t support WGo.js.

このキリがあっては、どうもこの局面から黒が盤面9目勝つのも難しいようで、もしも仮にそうだとすると、今まで悪手だと思われていた白6手目のカタツギが唯一の最善手となり、唯一の最善手だと思われていた黒3手目のハネは、ノビと同じ価値になります(併せて、これも最善手のひとつだと思われていた白4手目でのキリチガイは悪手となります)。そしてそれは、従来から言われてきた「日本ルールの7路盤は、最善尽くして黒の盤面9目勝ち」という結論が覆されることを意味しますので、これは結構大変な話ではないでしょうか? ぜひ強い方に調べて頂けたらと思います。

いつも書いていますが、7路盤についてはこちらが詳しいのでどうぞ。

七路盤の研究
http://orange.zero.jp/qin.olive/7ro/

7路盤に関しては、もう今となっては、7路盤専用に強化学習してしまえば、結構簡単にそれなりの答えが出そうな気もしますね。

[追記 2021/6/10]
この手を教えていただいてからも、オープニングブックの修正をちょくちょく行っていたのですが、現時点での私の感覚としては、盤面8目が答えのような気がしています。「勝てるものなら勝ってみな」の7路盤スペシャルバージョンも、コミ8目に変更することを少しだけ考えてみます。

[追記 2021/6/13]
7路盤スペシャルバージョンのコミを8目に変更しました。

COSUMIのサーバを3台から2台に減らします

かなり長い期間、COSUMIは専用サーバ3台で運用してきたのですが、これを7月末までに2台に減らします。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

3台目のサーバというのは、実質的にアクセスの多い時間帯の9路盤~13路盤のレベルの高い対局のためだけにあるようなものだったのですが、さすがにそのためだけに年40万+はちょっと辛いので、解約することにしました。本当はもう少し早い時期に行う予定だったのですが、コロナの影響でアクセスがかなり多くなっていたので、ここまで延期することになってしまいました。未だにアクセスは高止まりしたままなので、解約するのは正直かなり怖いのですが、もしもどうにもならないようなら、Amazon EC2辺りを特定の時間帯だけ使おうかなと考えています。今回解約するサーバは6年間以上借りてたみたいで、確かに初期費用も小さくはなかったですが、それでもそろそろ割高になってきそうなのも理由のひとつで、実はまだちゃんと調べてはいないのですが、以前ほどはEC2などに価格の優位性はないはずです。

ただ、一番理想的なのは、9路盤~13路盤はwhite shadeがごっそり受け持ってくれることで、これをなんとかしたいのですが、中途半端な誘導ではみなさんほとんど打ってくれないんですよね…(泣) 私の環境からだとほぼ問題ないのですが、動作しないことも多いのでしょうか? 月末までにいろいろよく考えてみます。

あと、これはかなり今更ですが、サーバのリソースがたっぷり余る時間帯は、逆にそれを贅沢に使ったなにかをやってみたい気もしています。

[追記 2020/7/27 7:50]
やはり常時サーバ2台で済ますのはさすがにちょっと無理があるように思うので、曜日問わず、15:00から18:00まで、EC2をサポートに使う予定です。とりあえずのテストとして、今日(と明日?)は、その時間帯以外、2台でいってみて、データ取れたらまた考えます。

[追記 2020/7/28 8:00]
いやあ、昨日はちょっときつかったですね… とりあえず、今日も少しだけ設定を変更した上で、15:00~18:00以外はサーバ2台でいきます。

[追記 2020/7/29]
15:00~18:00のみというのは、どうも虫がよすぎたようです。少し薄くても構わないので10:00~22:00は必要ですね。しかしそうなると、EC2にはリザーブドインスタンスとかがありますから、時間帯を限らず24時間動かしっぱで良いですね。って、それはただのサーバの乗り換えでは…

ここ最近、EC2のコストパフォーマンスをちょくちょく調べていたのですが、先月出たばかりのC6gというArmのCPUが載ったインスタンスが、COSUMI的に激安なんですよね。24時間動かし続けても、ぜんぜん今のサーバより安そうです。なので、その辺りが落としどころかな… しかしなんにせよ、「サーバ解約する前に良く調べておけよ」って思いました(笑)。

[追記 2020/8/1]
昨日の朝、専用サーバ3台から専用サーバ2台+c6g.4xlargeに変更しました(間に合って良かった…)。今のところは特に問題ないようです。ほんの少しだけ全体の処理能力が落ちましたが、たいしたほどではありません。

white shadeをアップデートしました(2020年4月)

white shadeに7路盤が新しく追加され、9路盤~13路盤では強さをレベル6まで選択できるようになりました。

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

ここ最近、COSUMIへのアクセスが本当にかなり多い状態が続いていて(昨日なんか36,010敗…)、なんとか早急に手を打たないと不味いので、実はまだいくつか問題点が残っているのですが、とりあえずwhite shadeをここで一度アップデートして、できるだけそちらへ誘導していきたいと思います。

その問題点としてはまず、7路盤で対局結果を1目間違えることがよくあります。できるだけ早く直したいと思いますが、きちんとやるには学習やり直さないといけないので、少なくとも2週間でしょうか? その次に、アップデート直前に自分の少し非力なiPadで動かすまで気づいていなかったのですが、今回の設定では動作がちょっと重すぎるみたいなので(そのせいで少し不安定かも?)、これも今後修正したいと思います。今は、white shadeもかなり強くなって、特に大きな碁盤サイズでは、今回のレベル6程度の強さなら、そんなにリソース使わなくてもいけるようになっているのですが、もろもろ事情があって、ここを直すのは、全部やり直さないと無理なので、だいぶ先のことになります。あと、レベルが低い時の手の汚さも気になります。white shadeが強くなるにしたがって、弱い設定にするのがかなり難しくなってきました。今回こんなにアップデートに時間が掛かったのも、かなりの部分、そのせいです。良い方法がどうしても見つからなければ、どうせ置き石もたくさん置けることですし、レベル1は今後無くすかもしれません。

white shadeは、一応COSUMI史上最強だと思いますし、もう少しブラッシュアップできたら、メインコンテンツのひとつに昇格かな? もうちょっとだけ頑張ってみます。

前回のwhite shadeのアップデートはちょうど一年前だったみたいですが、この一年間、私は一体何をしていたのでしょうか?(笑) ほんとに心配なるわ…

[追記 2020/5/10]
原因が思っていたのと違っていたのでだいぶ頭抱えましたが、7路盤でスコアをよく間違える理由がようやく判明しました。分かってしまうと、よくこれで7路盤を普通に打っていたなって感じだし、それ以外の碁盤サイズにもだいぶ悪影響があった気がします… このえげつないバグを見た後に、このまま7路盤を公開したままにするのは、ちょっと気が引けるので、一度、7路盤は削除しました。再度公開できるのは、一回学習を回さないといけないので早くて10日後ぐらいですね。ついでに、少し軽く動くようにもします。たぶん、全体的に手もきれいになるでしょう。レベル調整は狂ってきそうですが、それはまたおいおい修正していきます。あと、7路盤では互先はこのままずっと削除したままにするつもりです。やるならまた別の場所に用意します。

[追記 2020/5/21]
スコアをよく間違えるのが直ったので、互先以外は7路盤を元に戻しました。全碁盤サイズで少し軽くなって、おそらく手が自然になってもいるはずです。9路盤以上の碁盤サイズでは、同じレベルで比較した場合、少しだけ弱くなっているとも思いますが(ただ、元々がたぶん少し強すぎたと思う)、ここを調整するのが一番リソースを食うので、細かい修正を全部終わらせた後に行う予定です。もう少し全体的に軽くするために、できるだけ早くPNも学習し直したいのですが、一回先にやります。

[追記 2020/6/5]
今現在、2種類のPNを使用しているのですが、その内のひとつを大幅に小さくしました。少しだけ弱くなっていますが、だいぶリソースを食わなくなっているはずです。手は自然になっているかもしれません。あと、tensorflowjs_converterの--quantization_bytesというオプションを設定して、すべてのNNのウェイトを4byteから2byteに丸めました。半分になった今現在でファイルサイズが全部合わせて3MB弱ぐらいあって、今まではいくらなんでもちょっと大きすぎだったんですよね… 1byteとかだと、予めそういう学習の仕方をしておかないとだめだと思いますが、2byteだと、出力はたぶんあんまり変わらないんじゃないかと思います(以前調べた気がするのですが、詳しいことは忘れた)。それから、話がちょっと変わりますが、クリック/タップ周りも少し手を入れました。本当はこれもっと早くやらなければいけなかったのですが、こういうところを触るのは本当に怖くて、ずっと見て見ぬふりをしてました。なにかまずそうなら、出来るだけすぐに直します。問題無さそうなら、通常版などCOSUMI全体を書き換えたいと思います。

white shadeが動きにくいことはだいぶ減ったと思うので、ぜひ一度遊んでみてください。

[追記 2020/9/7]
white shadeが極端に早いタイミングでパスすることがあったのですが、ようやくひとつ理由がわかった! ちょっとおかしな話なのですが、左上10×10以外の箇所でコウが発生した時に、そこをコウだとしていませんでした(全く頓珍漢なコードだったので、本来なら盤面全体でそうなるはずが、かなり運悪く左上10×10では動いてしまってた…(泣))。なので、このバグは9路盤以下には影響がなく、11路盤でも限定的ですが、13路盤では大問題となっていました。うーん、条件がかなり限られるので、なかなか気づきませんでした… というわけで、急いで修正しておきましたが、結果的に13路盤(と11路盤)はおそらく大幅に強くなっています。もともと、今現在のこの強さに設定したかったのが、意図せず弱くなってしまっていたということです。いろいろと申し訳ありませんでした。

ただ、今回のバグは手元のPython版には関係なかったものですが、そちらでも早すぎるパスは見たことがありますので、単にVNの精度の問題と言えるケースは、これからも残っていくと思います。

COSUMIのプレイ実況動画

COSUMIを始めた頃だったでしょうか、「アメリカでは若者世代のYouTube視聴時間がテレビ視聴時間を抜いた」というニュースを見て、本当にひっくり返りそうなぐらいびっくりしたのを、今でもよく覚えているのですが、気がつけば、私の家にはテレビは無く、暇があったらYouTubeをずっと観ている毎日になってしまいました。そんなみんな大好きYouTubeに、COSUMIとの対局のプレイ実況動画を上げてくださる方が少しずつ増えてきて、すごくうれしく思っています。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

今回はその中からいくつか紹介していきたいと思います。

まず最初はVTuber。オドロキノシロサ(笑)。 それにしてもこの子、将棋する人だからでしょうか? 入門者にしては異常にセンスが良いですね…

もう一人VTuber。最後は熱いですねえ。ほんとCOSUMIはクソザコやろーです(笑)。

強い方も打ってくださいました。当然COSUMIは勝てないのですが、この2局はレベルの割に上手できれいに打てていると思うので、正直うれしいです。

政光さんも、純碁の紹介にCOSUMIを使ってくださいました。

上の5つの動画はすべて、今現在、視聴回数がものすごく少なくてなんだか悲しいので、試しに、COSUMIの対局ページにパソコンからアクセスした時、ランダムに選択して右下の空いているスペースに埋め込むことにしました。ささやかですが、COSUMIからの恩返しです。でも、意外と視聴回数伸びるかもしれませんよ。ちなみに、今現時点では上から順に、36回、44回、377回、403回、233回です。

私は、自分の目の前で誰かがCOSUMIと対局しているのを見たことが、今の今までただの一度も無く(もっと言うと、リアルな間柄で私のことを中の人だと知っている人も一人もいない…)、昔、こういうプレイ実況動画を初めて見た時に、「ああ、本当に対局しているユーザがいるんだ」と変に感動した覚えがあります。あと、COSUMIの話をしている人もリアルでは見たことがなく、「COSUMIって声に出して読むとそういうイントネーションなんだ」とかは、今でもよく思ったりします(笑)。

COVID-19とCOSUMI

ここ最近、COSUMIへのアクセスがかなり多い状態が続いています。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

説得力のあるデータは出せませんし、私も決して断言する訳ではありませんが、これは新型コロナウイルス感染症の流行のみでほぼ説明できると、自分の中では確信しています。

今年に入ってからのCOSUMIが一日に負けた数の推移です。寒さの厳しい時期の話でもありますので、比較対象として前々年と前年もグラフに加えました。

以前からここでも何度か書いていますが、COSUMIは雨や雪が降ると、アクセスが増える傾向があります(これは、他のオンラインゲームなどでも同じようです)。COSUMIへのアクセスの約1/4は海外からで、さらにその内訳に韓国や中国など東アジアが占める割合が多いというのが計算を難しくしますが、とりあえず直近見られる28,000+という数字は、仮に日本全国で大雨が降ったとしても、特別な他の要因が無ければなかなかいくことのない、非常に大きな値です。新型肺炎による健康被害が最終的にどれぐらいのものになるのかは、現時点では私にはよくわかりませんが、もしも実際に、それほどまでに人の外出が抑えられているのならば、経済的な影響についてはすでに甚大なものなのではないでしょうか?

中国でオンラインゲームや動画アプリの利用急増、新型肺炎で – ロイター
https://jp.reuters.com/article/china-health-online-idJPKBN1ZY109

しかし、こんな時ですので、外出を控えること自体はとても良いことだと思います。実はCOSUMIでは、この春、3台あるサーバを2台に減らす予定だったのですが、これについてはとりあえず当面の間、延期します。サーバの負荷が高い時間帯が続いて申し訳ありませんが、あと一か月ほどでwhite shadeをかなり強くできそうなので、そのあたりでそちらへの誘導を強めます。しばらくお待ちください。

[追記 2020/4/1]
3月末までのデータを追加したグラフです。細い線は、7日移動平均です。

なんだかえぐみが増してきましたね… 3月中旬からの自粛ムードの中だるみも、うっすら観測できているような気もします。white shadeは、ちょっといろいろ手間取っています。申し訳ありませんが、もう少しだけお待ちください。

white shade使ったベンチマークテストを作ってみました

white shadeを強くしようと、時間のある時に少し手を動かしてはいたのですが、なかなかなかなか強くなりません。もう、真面目に探索しないと、レベル6は難しいですかね? で、なかなかなかなか強くならないのがつまらないので、今回はwhite shadeを利用したベンチマークテストを作ってみました。

囲碁ベンチマーク – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/benchmark.html

ひたすらwhite shadeに手を打たせて、速度を測るというやつです。もちろん、こんなのはまともなベンチマークテストではなく、ただのネタにしかすぎませんので、真面目に使おうとはしないでくださいね。

今現在は、white shadeとの対局はレベル4までしかできませんが、今回のベンチマークはレベル5相当の強さになっています。手元のPython版での計測では、13路盤でGNU Go Level 10に、勝率95.2%、平均42.6目勝つぐらいなのですが、地たくさん勝つ割には、勝率が低くて、なんか安定性がないですね。めいいっぱいの設定にしても、勝率は98%に届かない感じ。でも、この強さでも対局できるように、ここらで一度、対局ページの方も後日アップデートしておきます。

このベンチマーク、私のiPhone 8だと速くて4手/秒ぐらい、GTX 1060(ブラウザが使ってくれているみたい)が載っているPC+google chromeで速くて10手/秒ぐらいになります。それだけ速いのならば、もう少したくさん考えさせてもいいのかもしれませんが、私のクソコードで、ユーザのバッテリーを無駄に消費することになるのは、どうも気が咎めるんですよね…(笑) もうしばらく、シンプルな形で強くならないか、探ってみます。

今回のこのプロダクトを、味気ないベンチマークに飽きた囲碁クラスタに贈ります。とんでもない手も多いですが、そこも含めてお楽しみください。後、これから寒さが厳しくなっていって、スマホをカイロ代わりにしたくなった時にも便利にお使いいただけると思いますので、ぜひお試しください(笑)。

[追記 2020/9/18]
少し書くのが遅くなりましたが、コウの扱いがおかしい時があったのを修正したVer. 1.1にアップデートしました。打つ手は以前のバージョンと同じではありませんが、ベンチマーク結果は基本的に比較可能です。

[追記 2020/12/13]
現在のwhite shadeの対局ゲームとほぼ同じ中身の、Ver. 2.0にアップデートしました。強さはレベル5.8ってぐらいで、全体的に自然な着手になっていると思います。ベンチマークテストの性格上、気軽に上げることができなかったTensorFlow.jsのバージョンも、かなり古いものから最新のにしてあります。ベンチマーク結果については、同じ環境でなら以前のバージョンとほぼ同じぐらいの数字が出るように調整しておきましたが、基本的に比較不可です。ご注意ください。

[追記 2022/4/23]
TensorFlow.jsを最新のバージョンに上げて、囲碁ベンチマークのバージョンをVer. 3.0とします。それ以外の変更はなにもありません。ベンチマーク結果については、当然、以前のバージョンとは比較不可です。全然ちゃんと調べていませんが、ほんのり速くなったような、なってないようなですね。

形勢を目数で返すNNを公開します

囲碁の局面の形勢を、目数で返すNNを公開します。ここ最近も改良しようといろいろと試していたのですが、ほとんど進歩が無かったので、今回公開するのは最新のバージョンですが、数か月前に作成した、今現在white shadeで使っているものと性能はほとんど同じです。

http://www.perfectsky.net/misc/whiteshade_vn-20190902.h5

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

13路盤より大きな碁盤サイズには対応していませんが、それより小さい碁盤サイズは、特になにも問題はないと思います(12路盤、10路盤、8路盤とかもOK)。公開するのは、KerasのHDF5形式のファイルですが、TensorFlow.jsのコンバータも私の環境では問題なく通ります。このNNを使っても、そんなに強い思考エンジンは作れないと思いますが、目数で形勢を返すNNは比較的珍しいと思うので、だれかが何か面白いものを作ってくれたら嬉しいです。

以下、使い方を簡単に説明していきます。わたしも本当によく分かっていないので、難しいこと聞かれても、どうせちゃんとお答えできませんので、この説明で分からなかったら、もう諦めちゃってください(笑)。

入力は「盤上」・「次の手番の石」・「相手の石」・「コウで打てない場所」の4面です。「次の手番の石」・「相手の石」は、「黒石」・「白石」ではないので注意してください。出力は「次の手番から見た目数単位での形勢(中国ルール・コミは無いとして)」です。「黒から見た目数単位での形勢」ではないので注意してください。入力は当てはまる所は1、そうでない所は0です。

例えば次の局面の形勢を知りたい場合は、

次のようなコードになります。

# score.py

from keras.models import Model, load_model
import numpy as np

MODEL = load_model('whiteshade_vn-20190902.h5')

TURN       = 'WHITE' # or 'BLACK'
BOARD_SIZE = 9

BOARD = [
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', 'W', 'B', ' ', ' ', ' ', ' ', ' '], 
    [' ', 'W', 'B', 'K', 'B', ' ', 'B', ' ', ' '], 
    [' ', ' ', 'W', 'B', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
]

NUM_PREDICT     =  1
MAX_BOARD_SIZE  = 13
NUM_INPUT_LAYER =  4

ON_BOARD = 0
MY_STONE = 1
YR_STONE = 2
KO       = 3


################################################################################


predict_input = np.zeros((NUM_PREDICT, MAX_BOARD_SIZE, MAX_BOARD_SIZE, NUM_INPUT_LAYER))

for i in range(BOARD_SIZE):
    for j in range(BOARD_SIZE):

        predict_input[0][i][j][ON_BOARD] = 1

        if BOARD[i][j] == 'B':
            if TURN == 'BLACK':
                predict_input[0][i][j][MY_STONE] = 1
            else:
                predict_input[0][i][j][YR_STONE] = 1
        elif BOARD[i][j] == 'W':
            if TURN == 'BLACK':
                predict_input[0][i][j][YR_STONE] = 1
            else:
                predict_input[0][i][j][MY_STONE] = 1
        elif BOARD[i][j] == 'K':
            predict_input[0][i][j][KO] = 1

predict_output = MODEL.predict(predict_input)

if TURN == 'BLACK':
    score = predict_output[0][0]
else:
    score = -(predict_output[0][0])

if score > 0:
    print('B+' + str(score))
else:
    print('W+' + str(abs(score)))

$ python ./score.py 2>/dev/null
B+18.516293

13路盤より小さい碁盤は、13×13のどこに描いても大丈夫だと思っていたのですが、四隅のどれかにぴたっとくっつけたデータでしか学習してなかったせいか、例えば9路盤を13×13のど真ん中に描いてpredictさせると、ちょっと精度が悪くなるような気がします。まあ普通に、0の0から使ってください。

このNNは、まず座標ごとにどちらの地になりそうなのかを予測し、それを集計したような構造になっています。これは、そういうふうにした方が、評価関数として性能が良かったからそうしただけなのですが、結果的にその集計前の途中の出力を、副産物として利用することも一応は可能です。ただ、本当に一応ですね。例えば9路盤をpredictさせると、盤外の座標にもスコアがしっかり付いていて(!)、でもどちらかに偏らないようになっていたりと、13×13全体で上手にバランスをとっている感じなので、まあ参考程度に見てください。例えば、次のようなコードで使えます。activation_103っていう名前のレイヤーの出力を使ってください。

# territory.py

from keras.models import Model, load_model
import numpy as np

OUTPUT_LAYER_NAME = 'activation_103'

MODEL   = load_model('whiteshade_vn-20190902.h5')
MODEL_2 = Model(inputs  = MODEL.input,
                outputs = MODEL.get_layer(OUTPUT_LAYER_NAME).output)

TURN       = 'WHITE' # or 'BLACK'
BOARD_SIZE = 9

BOARD = [
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', 'W', 'B', ' ', ' ', ' ', ' ', ' '], 
    [' ', 'W', 'B', 'K', 'B', ' ', 'B', ' ', ' '], 
    [' ', ' ', 'W', 'B', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '], 
    [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']
]

NUM_PREDICT     =  1
MAX_BOARD_SIZE  = 13
NUM_INPUT_LAYER =  4

ON_BOARD = 0
MY_STONE = 1
YR_STONE = 2
KO       = 3


################################################################################


predict_input = np.zeros((NUM_PREDICT, MAX_BOARD_SIZE, MAX_BOARD_SIZE, NUM_INPUT_LAYER))

for i in range(BOARD_SIZE):
    for j in range(BOARD_SIZE):

        predict_input[0][i][j][ON_BOARD] = 1

        if BOARD[i][j] == 'B':
            if TURN == 'BLACK':
                predict_input[0][i][j][MY_STONE] = 1
            else:
                predict_input[0][i][j][YR_STONE] = 1
        elif BOARD[i][j] == 'W':
            if TURN == 'BLACK':
                predict_input[0][i][j][YR_STONE] = 1
            else:
                predict_input[0][i][j][MY_STONE] = 1
        elif BOARD[i][j] == 'K':
            predict_input[0][i][j][KO] = 1

predict_output = MODEL_2.predict(predict_input)

for i in range(MAX_BOARD_SIZE):
    for j in range(MAX_BOARD_SIZE):

        if TURN == 'BLACK':
            darkness = predict_output[0][i][j][0]
        else:
            darkness = -(predict_output[0][i][j][0])
        
        if darkness > 0.9:
            print ('B', end='')
        elif darkness > 0.5:
            print ('b', end='')
        elif darkness > -0.5:
            print ('.', end='')
        elif darkness > -0.9:
            print ('w', end='')
        else:
            print ('W', end='')
    
    print ('\n', end='')

$ python ./territory.py 2>/dev/null
bw.bBBBBBBWBB
.WWw...wBBWWB
WWwbBBBbBBWWB
WWwbBBBBBBWWB
WWwbBBBBBBWWB
WWwbBBBBBBWWB
WWw.BBBbBBWWB
WWWw...wBBWWB
b..bBBBBBBWWB
BBBBBBBBBBWWB
WBBBBBBBBBBBB
WWWWWWWWWWWWB
WWWWWWWWWWWWW

盤上は、左上の9×9なんですけどね。盤外がなんだか凄まじいことに…(笑)

white shadeの方は、NNの入力に「ダメの数」追加するか、少し深く探索した方が良さそうです。そういったことは無しでも、レベル5までは問題なくいけるのですが、できればレベル6が作りたい…

晴耕雨棋

つい先日も、台風10号がやって来るなど、今年もまさに台風シーズンを迎えた日本列島ですが、今日は雨と囲碁の関係についてです。

以前にも少し書いたことがありますが、雨や雪の日は、COSUMIへのアクセスが大幅に増えます。きちんとしたデータを出すのはあまり簡単ではないので、ここではそれは控えますが、ざっくりと言って、「日本全国でしっかりと雨が降ると、日本からのアクセスが約25%増える」という感覚を私は持っています。そしてこれはおそらく、「どこかでしっかりと雨が降ると、その場所からのアクセスが約25%増える」ということだと思っています。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

雨と囲碁っていうと、「笠碁」という落語の演目を思い出す方が多いかもしれません。調べてみると、元は江戸時代からある話のようですね。その時代においての雨は、仕事をできなくして対局を増やすことの方が多かったのか、それとも、碁敵の所に行くのを阻んで対局を減らすことの方が多かったのか、私にはちょっとわかりませんが、少なくとも現代では、雨が囲碁の対局を増やすものなのは、まず間違いが無さそうです。

white shadeで11路盤と13路盤の対局ができるようになりました

今まで9路盤しか無かったwhite shadeで、11路盤と13路盤の対局ができるようになりました。

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

少し前にできるようになっていたのですが、ブログ書くの忘れてました… 11路盤なら6子、13路盤なら8子まで石を置くことができます。前にも書きましたが、white shadeの9路盤のレベルごとの強さは、「レベル1はGNU GoのLevel 7に勝率60%、レベル4はFuego1.1の7000playoutに勝率50%、それ以外のレベルは、1レベル違いの自己対戦の勝率が同じ」に合わせていますが、11路盤と13路盤は、「9路盤の同じレベルに勝率50%の人間が勝率50%になるぐらいに」というふわっとした感じに定義しておきたいと思います。通常版の強さと少しずれていくかもしれませんが、とにかくこれでいきたいと思います。

使用した学習データにはほとんど含まれていない碁盤サイズですが、7路盤でもほぼ問題なく打つようなので、これは今度追加するかもしれません。

今回のアップデートでは、動作も大幅に高速になって、ほとんどの環境でサクサクだと思います(もし極端に遅い場合は何かおかしい可能性が高いです)。貴重なバッテリーを大切に使うようになりました。そして、打つ手自体も全体的にかなりきれいになったと思います。石をたくさん置いた時にも、こう打ってほしいなと私が考える理想に近い、個人的に好感もてる打ち方をするようになりました。今現在の一番の問題点は、シチョウがだめなのと、大石のアタリをうっかりする(というか、平たく言うと大石の攻め合いがかなりあやしい)ことですね。でもまあ、これから何とかできそうな気もします。そして、それが本当になんとかなれば19路盤も考えるのですが…

NNのモデルは、碁盤サイズにかかわらず同一のものを使っています。いろいろ考慮するとこれが一番良さそうかなと思いました。もうあと一回、VNとPN作り直して、次のアップデートでレベル6はいけるのではないかと… それで無理なら、少し深く探索してみます。そしてできれば、次のバージョンのVNは一度だけ、自由に使ってもらえるように公開したいなと考えています。13路盤以下だけですが碁盤サイズを選ばず、出力が目数単位のスコアなのは、結構使いやすいと思います。それを使って、だれかが何か素敵なのを作ってくれたりはしないかな?

最初は「とりあえず作ってみました」って感じだったwhite shadeですが、今現在はすでにかなり実用的だと思います。通常版と比較しても、特に大きく劣る点も無い気がしますし、実際、「こっちのほうが好き」って方も多いはず。ぜひ一度、試しに遊んでみてください。

完全にwhite shadeがオフラインでも動くようになりました

COSUMIのwhite shadeは、思考エンジン自体はクライアントサイドで動いているので、今までもオフラインでも対局することができたのですが、そもそもオフラインだとウェブページにアクセスして開くことができなかったので、あまり意味はありませんでした。それを、今まで一度でもオンラインの時にwhite shadeのページにアクセスしたことがあれば、次に開こうとした時に、それが仮にオフラインであっても、ちゃんとページが開けて対局もできるようにしました。

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

自分で書いててもどういうことだよって感じで、なんだかとても摩訶不思議なのですが、そういうことができるみたいです。時代の進歩って本当に凄いですね。スマホのホーム画面にwhite shadeのページのアイコンを出しておけば、もうほとんどネイティブアプリと同じように使えます。

私は、Service Workerとか言われても、もうよくわかりませんので、今回はUpUpというライブラリをありがたく使わせてもらいました。ひとつだけ注意点として、オフラインでは対局のリプレイは見れませんので、そこだけはご容赦ください(これは今となっては、まあまあ面倒なんです…)。

今後は、空の旅のお供に、もしくは秘境においてのエクストリーム囲碁の対局相手として(笑)、white shadeをぜひご活用ください。

現在、COSUMIのサーバが落ちています

1月23日の朝6時ぐらいから、COSUMIのサーバが落ちています。現在復旧中ですが、再開時期は未定です。どうかしばらくお待ちください…

[追記 2019/1/23 19:30]
本当に申し訳ないのですが、タイミングが悪いことに私の体調がちょっと良くありません。復旧はどんなに早くても明日24日の早朝、もしかするとかなり遅くなるかもしれません。ご容赦ください。

こんな時こそのwhite shadeですよね… あらかじめperfectsky.netにでも用意しておけばよかったです。今はそんな元気はとてもありません…

[追記 2019/1/24 8:00]
朝までの復旧は間に合いませんでした。申し訳ありません。自信ないですが、お昼にはたぶん… 昨日はインフルエンザに罹ったかもと心配したのですが、どうもそうではなかったようで、そうと分かるとなんか急に元気がでてきました(笑)。

[追記 2019/1/24 12:30]
ごめんなさい。もうお昼も無理です… 夕方!

[追記 2019/1/24 17:30]
とりあえず直りました。ハードウェアのトラブルだったのですが、いろんな事情が重なって時間がかかってしまいました。これはいつものことなのですが、動かし始めた途端、tail -fしたウェブサーバのアクセスログ(ほぼ1行1手)がものすごい勢いで流れ始めて、もう本当に怖いです…(笑) お待たせして本当に申し訳ありませんでした。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

[追記 2019/1/24 18:00]
今頃気づいたのですが、こんなに長い時間COSUMIが止まったのは、今までで初めてですね。しかも断トツで一番だと思います。うーん、その割には私に危機感が無かったかもしれません…(笑)

クライアントサイド版COSUMIを作ってみました

このブログ記事は、以前書いた記事の続きです。よろしければ、そちらもどうぞ。

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる
http://www.perfectsky.net/blog/?p=350

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる その2
http://www.perfectsky.net/blog/?p=380

囲碁の思考エンジンを作ってみる
http://www.perfectsky.net/blog/?p=389

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

以前から作っていた囲碁思考エンジン「white shade」を、JavaScriptに書き直してブラウザで打てるようにしてみました。COSUMIのクライアントサイド版です。

white shade – 囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/whiteshade.html

今現在は9路盤しかできませんが、強さはレベル1からレベル4まで選択できるようになっています。それぞれのレベルでの強さは、一応、通常版のとできるだけ合わせましたが、通常版を手元で再現するのがちょっとめんどくさくて、なかなか完璧にはいっていません。一応、クライアントサイド版では、レベル1はGNU GoのLevel 7に勝率60%、レベル4はFuego1.1の7000playoutに勝率50%、それ以外のレベルは、1レベル違いの自己対戦の勝率が同じになるようにしていきます(これでまあだいたい通常版と同じです)。最終的には、通常版にも無いレベル7ぐらいまで行きたいですね。まだやれることはたくさんあるので、それぐらいはなんとかなりそうな気はしています。現状は、目一杯の設定で、だいたいレベル4.5ぐらい。GNU Goに一局あたり平均16目ぐらい勝てるのですが、それでも勝率は90%を辛うじて超える程度で、100%っていうのはやはりかなり大変そうですね。

レベル1では、4子までの置き碁もできるようにしました。GNU Goにこれをさせると怪しいことになるのでちょっとあれなんですが、white shadeは、どれだけ形勢が悪くても結構自然に打つので、特に問題は無さそうです。今後はもっと大きな碁盤サイズでも対局できるようにしていきますが、8路盤以下は、もうこれで許してください…

JavaScriptのDNNライブラリ(って呼んでいいのかな?)は、TensorFlow.jsを使っています。私も使えたので(笑)、たぶんそんなに難しいものではないです。元々のPython版white shadeも、GTPとかデバッグ用のコードとかもろもろ除けば、実質200行ぐらい(?)のプログラムだったので、JavaScriptに書き直すのも大した手間ではありませんでした。一番たいへんだったのは、先ほどの強さの調整ですね。きれいに弱くするということがこんなに難しいことだとは、本当に思っていませんでした。後、少し心配しているのが、JavaScript版にした時に、NNのモデルのコンバートなんかで弱くなってたりしていないかなんですが、自分が打っている限りでは、大丈夫なように見えます。JavaScript版の強さの計測は、これも今後ちょっと厄介ですね。

簡単にwhite shadeの中身についても、書いておくと、基本的に、左上から右下まで本当に全幅で1手読んでるだけですが、人の手のみを学習したPolicy Networkの出力も少しだけ加味して手を決定していて、あとは、自然に打てるように微調整ですね。レベル4が少し重いかもですが、それ以外のレベルは、ちゃんと動きさえする環境ならば、おそらくサクサクだと思います。で、問題はそのちゃんと動く動作環境なんですが、今現在、iPhone/iPadのiOS系が安定して動かないと思います(後、IEもですがこれはもう本当にどうでもいい。Androidはちょっと分かっていません)。これは結構色々調べたのですが、まず、iPad+Chromeはだめで、Mac+Safariは大丈夫なので、iOSがだめっぽいのですが、NNのモデルを小さいものに変更するとかなり安定するようになるので(ちなみに今現在、Value Networkが92万、Policy Networkが45万パラメータぐらい。本当はもっと大きなNN使いたいぐらいなのに…)、端末が非力なことが単純に問題なのかもしれません。とはいえ、とりあえず動くだけは動いて欲しいのですが… iPhoneで動かない限り、トップページからのリンクもちょっと張れません。これはまた、なんとかします。

今現在、COSUMIは年間のサーバ代(最初に掛かった初期費用は入れず)が130万ぐらい掛かっているのですが、それがこのクライアントサイド版でいつか半分ぐらいにならないかなあと、つい皮算用してしまいます。私は今、車が欲しいんです(笑)。生まれてこのかた、一度も車なんて買ったことないのですが、今猛烈に欲しいんですね。軽でいいんですけど、新車が欲しい(笑)。そのためにも、このサーバ代はなんとかしなければいけません。話変わりますが、なんかネット見ていたら、さくらインターネットからお中元が来たって方がちょくちょくいるのですが、今までに新車のポルシェ一台分ぐらい貢いだ私はもらったことがない!(笑) うー、まだ足らないのかな… おいらもチョコが食べたい。

[追記 2018/9/2]
今回は、white shadeで囲碁の対局をできるようにしたわけですが、いつかは、9路盤以下の悪手指摘機能をこれで置き換えたいですし、もっと言うと、white shade Teach作りたいですね。この場合、teachするのは、囲碁というよりも、white shadeの囲碁に対する気持ちぐらいでしかありませんが(笑)、それでも、初心者の方には、十分有益なような気がします。忙しいので当面の間は無理ですが、またいつかがんばります。

[追記 2019/1/5]
ブラウザがロードするTensorFlow.jsのライブラリのバージョンを上げたら、iOSでもwhite shadeが動くようになったみたいです(やほい!)。ひさしぶりに私も対戦してみましたが、この子、そんなに弱くはないのですが、ときどきとんでもない転び方するので、ちょっと面白いです。ぜひiPhoneで一局打ってみてください。

今現在、9路盤以外でも対局できるように準備していますので、そちらはもうしばらくお待ちください。

COSUMI 10周年

[以前の関連記事] : COSUMI 5周年

今日2018年5月26日で、COSUMIは開始から10周年を迎えることになりました(実は、黒嘉嘉と誕生日がいっしょなんです(笑)。あっ、先生お誕生日おめでとうございます)。

囲碁ブラウザゲーム COSUMI
https://www.cosumi.net/

10年間の総ページビューは、221,499,920(におくにせんまん…)。もう本当に訳の分からない数字ですが、個人的には、セッション数59,413,618と平均セッション時間12分22秒という2つの数字が一番やばいと思っています。単純に掛け算すると約1398年。人生80年だとすると、17.47人分ですよ!(もう怖えーよ…) そして、COSUMIは10年間通算で、40,599,753敗しました。うーん、たくさん負かされましたね。究極の目標は1億敗なんですが、いつか達成できる日が来るのでしょうか?

10年間のページビューの推移(ともろもろ)です。

基本的にCOSUMIは、非常にゆるやかな右肩上がりをずっと続けてきました。このグラフを形作っているのは、そのほとんどがCOSUMI固有の要因だと言えると思いますが、その中で、唯一といっていいほど例外的に、外部的な要因で大きくアクセス数が変動したのが、2016年3月のAlphaGo-セドル戦で、結局のところ、この10年の間に起こった、囲碁をやらない人までを巻き込んだ大きな囲碁の話題って、この時一回きりだったのだと思います。AlphaGo-柯潔戦とか、井山七冠達成とかは、ニュースバリューがほとんどなかったと見るべきでしょう。

COSUMIの今後については、現時点ではあまりはっきりしたことは言えませんが、新しい機能の追加とかはもうあまりないと思ってください。ただし、使用している囲碁の思考エンジンは、最近、急に出てきた非常に強いオープンソースのソフトや、今現在、私が作っているソフトに、部分的には置き換えられていく可能性が高いと思います。たぶん、そのあたりが今COSUMIに一番足らない部分ではないでしょうか?

そして、ここ最近、私がよく考えていることとして、「いつまでCOSUMIを続けるのか」っていうのがあるのですが、一応、最低でもあと5年は続けたいなと思っています。ただ、それ以降については、私ではなく時代が決めることなのかなという気がしています。

似たような内容のことを、このブログでも何度か書いていると思いますが、COSUMIを最初に作っていた時は、10年後、まさかこんなことになるとは、夢にも思っていませんでした。驚くほどたくさんの方に遊んでいただきましたが、一番楽しんだのは自分自身なんだということについては、よく理解しているつもりです。これも以前からの繰り返しになりますが、すばらしいソフトウェアを自由に使わせてくださっているGNU GoとFuegoの開発者の方にも、再度お礼申し上げます。そして、今までCOSUMIで遊んでくださった方々へ。10年間、本当にありがとうございました。感謝しています。

10周年にかけて、10路盤の対局ができるようにしてみました(笑)。強さはLevel 1相当です。COSUMIは黒しか持たないようになっています。これは、今だけの期間限定です。一週間ぐらいしたらまた元に戻しておきます。

[以後の関連記事] : COSUMI 15周年

[追記 2018/5/27]
セッション数と平均セッション時間を掛けた1398年という数字は、ユーザがCOSUMIを見ていてくれた延べ時間ぐらいの意味で出したのですが、実情は、おそらくそんなものではありません。古いログは解凍するのも恐ろしいので(笑)、きちんとした数字を出すのはここではやりませんが、例えば、この2週間の間にCOSUMIが打った手数が70,843,582手(+α)、同期間のページビューが1,623,460pvで、割り算すると43.6手/pvぐらいです。それに、全期間のページビューを掛けると約96.7億手(本当によく知らないけど、AlphaGoといい勝負になってない?(笑) GNU Goは軽いですね)。COSUMIでは、これに10秒掛けたのがだいたい対局時間と考えてよいので、そうなると約3065年になります。これはかなり適当な計算ですが、とはいえ、対局リプレイを見ている時間なども含まれていません。

囲碁の思考エンジンを作ってみる

このブログ記事は、以前書いた記事の続きです。できれば、まずはそちらをお読みください。

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる
http://www.perfectsky.net/blog/?p=350

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる その2
http://www.perfectsky.net/blog/?p=380

時間ができたので、以前から作っていたDNNな囲碁の評価関数を使って、囲碁の思考エンジンを作ってみました。「パスも含めて全幅で深さ1だけ読む」という単純なプログラムです。9路盤しか打てません。一応、名前も必要かと思ったので、コードネームだったのをそのまま使って、white shadeと名づけました。由来は、Procol Harumの例の曲です。特にそれ以上の深い意味はありません。ちなみにこの映像は、ちょうど今から50年前のものみたいですが、ポピュラー音楽って本当に進歩がないですね。コンピュータ囲碁は、この5年だけでもめっちゃくちゃ強くなったのに…(笑)

ということで、早速、GNU Goとの対戦を行ってみました。使用した評価関数は、BottleneckアーキテクチャになっているRes-Blockのネックの部分が、32Filterなのと48Filterなのとの2種類。共に10 Res-Block(ちなみに、32Filterはパラメータ数が210,769で、48Filterは368,529。できれば、このあたりのサイズで何とかしたい…)。それぞれ、8対称形の平均をとったのと、とらないのとの、計4種類です。対局数は、先後を換えて150局ずつ計300局。同じような対局ばかりになりがちなので、twogtpに付属していたオープニングブックを使用しています。結果は、

32Filter 106勝194敗 (勝率 35.33%)
32Filter/8対称形の平均 144勝156敗 (勝率 48.00%)
48Filter 128勝172敗 (勝率 42.67%)
48Filter/8対称形の平均 176勝124敗 (勝率 58.67%)

うーん、よくわからんけどまあこんなものかな? とりあえず、ここがスタートですね。棋譜を見ていると、序盤はかなり上手なんですが、この子どうやらアタリがよく分かってないみたいで(笑)、後半すさまじいファンタを見せてくれます。一番強い48Filterの8対称形平均版から適当に3局選んでみたので、ご覧ください。


Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

こんなのに半分以上負けるGNU Goもどうなのよって感じですが(笑)、まあ強い時は強いからしかたないか… でもって、何でこんなにアタリがわからないのかっていうと、いろいろ理由はあるんでしょうが、おそらく一番大きいのは、学習データにこういう局面があまり含まれていないからだと思います。もちろん、大石がアタリになっている局面はそれなりの数あるのですが、そのほとんどが、アタリにされている方の手番になっていて、つぐなり逃げるなりすれば大事にならないので、それで深刻なことだと学習できていない気がします。NNの入力にダメの数を入れるとか、深さ2読むとかしたら、ここまでひどいことにはたぶんならないと思いますが、そんなことしなくても評価関数だけでこれぐらいは分かってほしいですし、こんなことも分からなくて、もっと高度なことが分かるはずもないような気がするので、なんとかしたいのですが、どうするのがいいかな? 「いっぱい対局させて、それをRayに添削してもらって、酷そうな手の前後を学習データに追加していく」みたいな感じでだめかな? また少し試してみます。

9路盤での最終的な目標は、GNU Goに対して1局平均10目勝ちです(今はだいたいイーブンぐらい)。勝率はあまり気にせず、そこを目指していきたいと思っています。そこまでいけたら、ブラウザで打てるようにしたいですね。

いろいろやっている間に、Rayが出してくれる形勢判断が常に1目ずれていること(黒番の時と白番の時で向きが逆、平均すれば0。簡易的な日本ルール対策?)に気づいて、その分を修正しようとしたのですが、今度は別のところで矛盾が生じてきて絶賛混乱中です。もう一目ぐらいどうでもいいか… あと、現在、Policy Networkも作っています。Value Networkもそうですが、よくこんなのでちゃんとしたアウトプットが出てきますね… なんだか、狐につままれた気分です。

あとあと、CapsNetで囲碁やった人とかいないんでしょうか?

[追記 2018/5/6]
最近、Policy Networkを作っているのですが、学習データを普通の棋譜からランダムに切り出して使ったりすると、結構ラベルに偏りが出てくるのが気になります。ということで、囲碁で一局を通して、座標ごとにどれぐらいの回数打たれるのかっていうのを調べてみました。例えば、COSUMIの9路盤のレベル1の作り碁ならこんな感じ。一番打たれる回数の多い場所を100として、それとの割合です。

 14  29  40  52  59  52  40  29  14
 30  44  56  68  71  67  55  44  30
 40  56  76  86  88  86  75  56  41
 53  68  87  96  95  96  86  68  54
 60  73  89  95 100  95  88  73  60
 54  68  87  97  94  95  86  68  53
 41  57  76  86  87  85  75  56  41
 30  45  56  68  71  67  56  44  30
 15  31  41  53  59  52  40  30  14

そして、レベル5ではこんな感じです。

 24  48  56  67  71  67  57  48  24
 48  64  74  82  85  82  74  64  48
 57  74  89  95  97  95  89  75  57
 67  83  96  99  98  99  95  83  67
 71  86  97  99  99  98  97  86  72
 67  83  95 100  98  99  95  83  68
 57  74  89  95  96  94  88  74  56
 48  65  74  83  86  83  74  64  47
 25  48  57  67  71  67  57  48  25

どうでしょう、ちょっと不安になってきませんか?

今現在、学習に使っているデータは、COSUMIの棋譜から取って、いくつかの条件でふるいをかけたものですが、それの検証用データのラベルの合計がこちら。これを[1]とします。

 1628 2786 3627 4372 4508 4372 3627 2786 1628
 2786 4038 4507 5506 6126 5506 4507 4038 2786
 3627 4507 5296 6662 6550 6662 5296 4507 3627
 4372 5506 6662 8024 6928 8024 6662 5506 4372
 4508 6126 6550 6928 7928 6928 6550 6126 4508
 4372 5506 6662 8024 6928 8024 6662 5506 4372
 3627 4507 5296 6662 6550 6662 5296 4507 3627
 2786 4038 4507 5506 6126 5506 4507 4038 2786
 1628 2786 3627 4372 4508 4372 3627 2786 1628

そして、そのデータと同じ作り方をしている学習用データで学習したNNで、先ほどの検証用データを予測させた時の最後のsoftmaxの出力をそのまま合計したのがこちら(この数字をここで使うことが正しいのかがちょっと確信持てませんが…)。これを[2]とします。

 1584 2745 3695 4300 4598 4301 3668 2754 1594
 2735 3890 4561 5532 6039 5525 4578 3922 2746
 3678 4605 5399 6763 6706 6754 5334 4583 3663
 4272 5503 6705 7787 7231 7720 6611 5479 4303
 4623 5987 6656 7232 7764 7128 6517 5946 4598
 4308 5513 6673 7657 7236 7645 6586 5511 4306
 3756 4626 5447 6669 6662 6638 5312 4612 3694
 2820 3924 4578 5491 5972 5544 4613 3944 2766
 1609 2763 3694 4276 4583 4272 3667 2726 1592

それぞれの座標で、[2]/[1]*100したのがこちら。

  97  99 102  98 102  98 101  99  98
  98  96 101 100  99 100 102  97  99
 101 102 102 102 102 101 101 102 101
  98 100 101  97 104  96  99 100  98
 103  98 102 104  98 103 100  97 102
  99 100 100  95 104  95  99 100  98
 104 103 103 100 102 100 100 102 102
 101  97 102 100  97 101 102  98  99
  99  99 102  98 102  98 101  98  98

ほんの少しだけ、それっぽい傾向が見受けられるような気もしますが、まあこれぐらいならぜんぜんOKでしょうかね? とりあえずは気にしないことにします。

[追記 2018/5/25]
「white shadeの棋譜をRayに添削してもらって、悪手っぽいところの前後を学習データに追加して、それをもう一度学習する」ってやり方で、いきなりGNU Goに1局平均10目ぐらい勝てるようになったのですが、それってそれなりの棋力がないとできないはずだと思って実際に棋譜を眺めてみても、そこまで強そうには見えません。どうも、最後にねちねちやられてGNU Goが自爆していることが、ちょくちょくあるからみたいです。手法自体はかなり有効そうなので、目標を「1局平均20目」に変更して、現在、二周目やってます。

[追記 2018/8/29]
ブラウザで対局できるようにしてみました。続きの記事をどうぞ。

クライアントサイド版COSUMIを作ってみました
http://www.perfectsky.net/blog/?p=402

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる その2

このブログ記事は、以前書いた記事の続きです。できれば、まずはそちらをお読みください。

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる
http://www.perfectsky.net/blog/?p=350

ずいぶん長い間ほったらかしにしていたのですが、そろそろ自分でも、囲碁の思考エンジンを作ってみたいと思い、ここ最近、久しぶりに以前作っていたディープラーニングな評価関数の作成の続きをやっています。

ただ、思いつくことはある程度、前回の時に試していたこともあって、ほとんどの試行はたいした改良に繋がらないのですが、その中で唯一、非常に大きく数字が改善したのが、Squeeze-and-Excitation Networks(SENet)というやつです。

[1709.01507] Squeeze-and-Excitation Networks
https://arxiv.org/abs/1709.01507

このモデルがどのようなものかを解説するのは、私にはちょっと難しいので、詳しくはリンク先を読んでいただくとして、以下簡単に、私が試してみたテスト内容とその結果を書いてみたいと思います。

現在、最終的にはクライアントサイドで思考エンジンが動くウェブアプリの制作を目標にしていて、その関係もあって、とりあえず今回は9路盤です。データの作成方法などは前回とほぼ一緒。対称形に8倍して切りの良い数字にまで少し減らして、230万局面分。95%を学習用に、5%を検証用に使います。

NNのモデルは、基本的に、前回の最後の方で使っていた普通のResNetみたいなのが性能良いのでは、と思っているのですが、今回は非力なスマホなどでも動かしたいので、できるだけ小さなモデルにしなければいけません。特に、パラメータ数は、モデルのファイルサイズになってネットワークの転送量とかにまで影響してくるので、少ないにこしたことはないように思います。ということで、Residual Block内は1×1 -> 3×3 -> 1×1のいわゆるBottleneckアーキテクチャにしました。そもそも、たかだか19×19の囲碁で、3×3のConvが30も50も重なるのって、なんかおかしいような気が以前からしていて、なんというか、そんな遠くの場所よりも、まずはもっと近いところとの関係をよく見ないといけないのではと、つい思ってしまうんですよね… 9路盤なんか、たった4つの3×3のConvで、天元のところにすべての座標の入力の情報が来るわけで、そういう意味でも、3×3を一定量1×1に置き換えるのは、理にかなっているような気がしています。「5×5は3×3が2つの方が良いように、3×3はdepthwiseとpointwiseに分けたほうが良い」みたいなことを言われてしまうと、確かに3×3のConvはちょっと大きすぎですよね… 囲碁だったら、四隅の欠けた3×3の、「十字型」なんかどうなんでしょうか?

ってすみません。話がそれてしまいました。元に戻って今回のNNのモデルですが、前回からの変更点としてもうひとつ、入力層の所でまず、周囲をゼロパディングして、9×9だったフィールドを13×13に広げています。これはパラメータ増やさず、ロスを下げます。やっぱり9×9って小さすぎるんですよね、ってまた似たような話に…(笑)

入力は、「手番のプレーヤーの石の配置」、「相手の石の配置」、「コウで打てない場所」、「全部1」の4面(9,9,4)です。最後の「全部1」と、先ほどの入力層でのゼロパディングで、盤上/盤外を表現したつもりです。

その他の条件は、だいたい前回と同じかな?

コードはこんな感じ。まずは「SENetなし」。

BOARD_SIZE = 9
FIELD_SIZE = 13


def rn_block(input):

    relu_1 = Activation("relu")(input)
    bn_1   = BatchNormalization()(relu_1)
    conv_1 = Conv2D(32, (1, 1))(bn_1)

    relu_2 = Activation("relu")(conv_1)
    bn_2   = BatchNormalization()(relu_2)
    conv_2 = Conv2D(32, (3, 3), padding='same')(bn_2)

    relu_3 = Activation("relu")(conv_2)
    bn_3   = BatchNormalization()(relu_3)
    conv_3 = Conv2D(128, (1, 1))(bn_3)

    return conv_3


input = Input(shape=x_train.shape[1:])

main    = ZeroPadding2D(padding=(int((FIELD_SIZE-BOARD_SIZE)/2), int((FIELD_SIZE-BOARD_SIZE)/2)))(input)
rn_fork = Conv2D(128, (3, 3), padding='same')(main)

main    = rn_block(rn_fork)

rn_fork = add([main, rn_fork])

main    = rn_block(rn_fork)

rn_fork = add([main, rn_fork])

main    = rn_block(rn_fork)

rn_fork = add([main, rn_fork])

main    = rn_block(rn_fork)

rn_fork = add([main, rn_fork])

main    = rn_block(rn_fork)

rn_fork = add([main, rn_fork])

main    = rn_block(rn_fork)

main    = add([main, rn_fork])

main    = Activation("relu")(main)
main    = BatchNormalization()(main)
main    = Conv2D(1, (3, 3), padding='valid')(main)
main    = AveragePooling2D(pool_size=(FIELD_SIZE-2, FIELD_SIZE-2))(main)

output  = Flatten()(main)

そして「SENetあり」。

BOARD_SIZE = 9
FIELD_SIZE = 13


def rn_block(input):

    relu_1 = Activation("relu")(input)
    bn_1   = BatchNormalization()(relu_1)
    conv_1 = Conv2D(32, (1, 1))(bn_1)

    relu_2 = Activation("relu")(conv_1)
    bn_2   = BatchNormalization()(relu_2)
    conv_2 = Conv2D(32, (3, 3), padding='same')(bn_2)

    relu_3 = Activation("relu")(conv_2)
    bn_3   = BatchNormalization()(relu_3)
    conv_3 = Conv2D(128, (1, 1))(bn_3)

    return conv_3


def se_block(input):

    ap      = AveragePooling2D(pool_size=(FIELD_SIZE, FIELD_SIZE))(input)
    conv_1  = Conv2D(8, (1, 1))(ap)
    relu    = Activation("relu")(conv_1)
    conv_2  = Conv2D(128, (1, 1))(relu)
    sigmoid = Activation("sigmoid")(conv_2)
    us      = UpSampling2D(size=(FIELD_SIZE, FIELD_SIZE))(sigmoid)

    return us


main    = ZeroPadding2D(padding=(int((FIELD_SIZE-BOARD_SIZE)/2), int((FIELD_SIZE-BOARD_SIZE)/2)))(input)
rn_fork = Conv2D(128, (3, 3), padding='same')(main)

#main    = rn_block(rn_fork)
se_fork = rn_block(rn_fork)
se_out  = se_block(se_fork)
main    = multiply([se_fork, se_out])

rn_fork = add([main, rn_fork])

#main    = rn_block(rn_fork)
se_fork = rn_block(rn_fork)
se_out  = se_block(se_fork)
main    = multiply([se_fork, se_out])

rn_fork = add([main, rn_fork])

#main    = rn_block(rn_fork)
se_fork = rn_block(rn_fork)
se_out  = se_block(se_fork)
main    = multiply([se_fork, se_out])

rn_fork = add([main, rn_fork])

#main    = rn_block(rn_fork)
se_fork = rn_block(rn_fork)
se_out  = se_block(se_fork)
main    = multiply([se_fork, se_out])

rn_fork = add([main, rn_fork])

#main    = rn_block(rn_fork)
se_fork = rn_block(rn_fork)
se_out  = se_block(se_fork)
main    = multiply([se_fork, se_out])

rn_fork = add([main, rn_fork])

#main    = rn_block(rn_fork)
se_fork = rn_block(rn_fork)
se_out  = se_block(se_fork)
main    = multiply([se_fork, se_out])

main    = add([main, rn_fork])

main    = Activation("relu")(main)
main    = BatchNormalization()(main)
main    = Conv2D(1, (3, 3), padding='valid')(main)
main    = AveragePooling2D(pool_size=(FIELD_SIZE-2, FIELD_SIZE-2))(main)

output  = Flatten()(main)

「SENetなし」はResidual Blockが6つと7つの2種類、「SENetあり」はResidual Blockが6つの、計3種類をテストしてグラフにしてみました。

「SENetなし/Residual Block 7つ」と「SENetあり」は、パラメータ数、予測に掛かる時間、1エポックあたりの学習時間などがそれほどは大きく変わらず、それでいてこのロスの差なので、すばらしいです。ILSVRC2017チャンプは伊達ではない(笑)。しばらく忙しいのですぐには無理そうですが、いずれこいつを使って一手全幅君を作ってみたいと思います。

[追記 2018/4/4]
現在使用している学習データのラベルは、Rayに付けてもらったものですが、それをそのデータを学習したDNNで付け替えて、もう一度最初から学習し直したらどうなるのか、試してみました。

学習する局面は上と同じ230万局面分。95%を学習用、5%を検証用に。ネットワーク構成も上のSENetありと基本的に同じで、10 res-blockです。今回の複数のテストでの唯一の違いは学習データのラベルで、まずは次の3種類、

  • [1] Train/ValidateともRayが付けたもの
  • [2] Trainを[1]の50エポック目のDNNが付け、ValidateはRayが付けたもの
  • [3] Train/Validateとも[1]の50エポック目のDNNが付けたもの

です。[3][2]とTrainのラベルが同じなので、Validateだけ調べれば良かったのですが、実際にやってみると、想像以上に低い数字が出て来て自分の書いたコードが信用できなくなり(笑)、念のために、いつもと同じように最初から学習回しながら、Validateを計測してみました(どうやら、自分の書いたコードは合ってたみたい…)。乱数の加減も今回はあまり関係無かったようで、赤の実線は緑の実線にきれいに隠れていますが、そこにあります(一応、少し太くしておいた(笑))。

正直、驚きの結果です。DNNに予測させるのは、Rayにラベルを付けてもらうより、遥かにコストが掛かからないので、「もし、DNNが付けたラベルでそれなりに学習できたら、データの水増しが可能になるかも」ぐらいに思っていたのですが、ばっさりと全部差し替えても全く問題なさそうですし、グラフ見ているだけでははっきりしませんが、囲碁の神様が付けたラベルに対して、[1]より[2]/[3]の方が性能が高い可能性までありそうに見えます。しかし、そんなうまい話本当にあるのかなあ? どうも信じられないのですが…

以前にも書きましたが、同じ局面の対称形をDNNで予測させると、結構ばらばらな数字を返してくるので、

  • [4] Trainを[1]の50エポック目のDNNが予測した8対称形すべての平均にして、ValidateはRayが付けたもの

もテストしてみました。

このブログには書いていませんが、以前Trainのラベルに平均0の乱数を混ぜて学習させてみたことがあったのですが、その時も意外とValidateの数字が大きく悪くはなったりせず(もちろんTrainはノイズの分がっつり悪くなります)、たくさんのデータで鍛えるとそんなものなんだなあと思ったことがあったのですが、今回の[2]は、[4]に平均0の乱数を混ぜたようなものなので、似たような結果と言えるでしょうか、ってじゃあやっぱり精度の高い予測が欲しい時は、平均とって使った方が良さそうですね。うーん、めんどくさ…

[追記 2018/4/30]
続きの記事があります。

囲碁の思考エンジンを作ってみる
http://www.perfectsky.net/blog/?p=389

COSUMIを常時SSL化しました

COSUMIにSSLを導入して、トップページからなにからすべて、暗号化するようにしました。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/
https://www.cosumi.net/

大変申し訳ないのですが、チャレンジモードの段級位とか、1/2 ClickやサウンドOn/Offの設定が引き継がれません(引き継ぐための細工をしていません)。チャレンジモードに関しては、代わりにといってはなんですが、最初の連勝中は一級まで2ランクずつ上がっていけるようにしましたので、それでご容赦願います。それから、今回SSL 3.0は切りましたので、極端に古い環境からは、ページの閲覧が一切できなくなっていると思います。

httpからhttpsへリダイレクトされるように設定してあるので、以前張っていただいたリンクなどは、もうそのままで全然問題ないのですが、もし可能であれば、今後はhttpsなURLを使っていただけるとうれしいです。

COSUMIのFlash版を廃止します

来年の5月で、COSUMIはなんと10周年を迎えることになるのですが、そのあたりのタイミングで、「Flash版がメインでHTML5版がサブ」っていう感じの現状を、「HTML5版がメインでFlash版がサブ」っていう感じに変更しようかなあと、少し前から考えていました。ところが先日、Flashが2020年に廃止されるというニュースを聞いた時に、その変更を行うのは、もう今すぐにでも良いのかもと思い始め、さらにその後いろいろ考えているうちに、あまり段階を踏まずに、すっぱりFlash版を無くす方がいいのかも、という気になってきています。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

Flash版はいずれ廃止しなければいけなくなりますし、結局のところ、問題はそのタイミングだけなんですが、まだ最終決定ではないですが、おそらく今年の10月末ぐらいまでには、Flash版は廃止することになると思います。正式に決定したら、また事前に通知します。

Flash版を廃止するのを今まで躊躇していた理由は、主に次の二つかなと思います。

一つ目は、「HTML5版が全く動かない環境があるから」です。そんな環境っていうのは、ずばり古いIEなんですが(と言っても、現時点で、実際にどのバージョンが動かないのかよく分かってないですが…(笑))、これは最近調べてびっくりしたのですが、現在すでに、IE10以下って基本的にベンダがサポートしていないんですね… ベンダがサポートしていない環境を、COSUMIでサポートしなきゃいけない義理はないので(笑)、これはもう大丈夫そうです。

そして二つ目は、「HTML5版では音がきちんと再生されない環境があるから」です。実は、最初にHTML5版を作った時に(これ、もう5年前なのか…)、audio要素を使用してサウンドも鳴るようにコード書いたのですが、環境によって鳴ったり鳴らなかったり、それもいろいろな形でおかしなことになったんですよね。iOSなどは、そもそも仕様が本当にふざけてますし…(これ今もなんでしょうか?) そんなこんなで、その時は匙を投げたのですが、これから試してみないとはっきりとは分かりませんが、今は状況も少しはましになっているんでしょうし、なんとか最低限の形にはなりそうな気がするので、これもたぶん大丈夫だと思います。MP3だってもう使って良いですかね? いろいろ、昔とは違ってきているのではないかなと期待しています。

実は、自分の中でCOSUMIを作り始めた瞬間となっているのは、ネットで買ったFlash Basic 8のパッケージを開けた時なんですよね… 「Flash版はもっと早く廃止したかった」とも思っていますが、実際に無くすとなると、寂しい気持ちが全くないわけではありません。

– – – – – – –

ブログのコメントが簡単にスパム判定されるのは、まだ直ってないですね… ごめんなさい。WP-SpamShieldっていうプラグイン使っているのですが、Akismetの方がいいのかなあ?

[追記 2017/8/13]
Flash版を廃止するのは、少し急なのですが、8月27日と決定しました。廃止するに当たって、手を動かさなければいけないことがいろいろあったですが、一旦やり始めてみると、なんかあっと言う間にほとんど出来てしまいました。そして、そんな作業の中で、Flash版を残して続けていた弊害に、今更ながら気づくことも多くて、もう善は急げで今月中に廃止してしまうことにしました。こまごまとした、いくつかの機能追加もあるので、ほとんどの方には良い変更になると思います。そして、ごく一部の方には、ぼろくそに文句言われそうです…(笑) 毎日、万の単位の人に遊んでもらっているので、結構勇気は要りますね。

「現在のFlash版ページ(例えばhttp://www.cosumi.net/play.html)がHTML5版となり、現在のHTML5版ページ(例えばhttp://www.cosumi.net/mobile/play.html)へのアクセスはそのページにリダイレクトする」って形で行きます。Flashじゃなくなったことに気づかない人も、たくさんいるかもしれません。

ちなみに、サウンド関係はhowler.jsっていうので一発でした。良い時代ですね。

[追記 2017/8/28]
Flash版を廃止しました。それ以外にも、外から見える所も、見えない所も、結構な量、手を入れましたので、なにかやらかしていないか、かなり不安ですが、とりあえず大丈夫かな? 音も出ます。前からやりたかった、チャレンジモードの秒読みも再生されます。

今回、「今後5年間、戦えるように」と考えながら作業していたのですが、その中で、今はまだできていないけれど、これだけはすぐにでもやらないといけないかなと思ったことがひとつだけあって、それはSSLの導入です。はっきり言って、COSUMIはそんな(どんな?)サイトじゃないので、今までSSL無しだったのは、まあ良いと思います。COSUMIエゴサーチが日課の私ですが(笑)、いまだかつてそのことについての指摘を見たことは一度もないですし、ユーザの肌感覚とも合っていたんだと思います。ただ、常時SSLなどということが、これだけ言われるようになっている2017年現在は、SSLってみるのにちょうど良いタイミングな気がするので、時間見つけて一度勉強してみます。たぶんですが、お金はたいしたことなさそうです。SSLサーバー証明書は、例えばさくらのラピッドSSLなら、3年で税込み3,456円だそうで、これならほとんどただみたいなものだし、サーバリソースも、年数千円レベルしか余分に食わないんじゃないかなあ? 桁が違ってたら、ちょっといやですが…

[追記 2017/9/2]
今回初めて、oggとかmp3とかのファイルを用意することになったのですが、stagefrightという文字列の入ったUser agentの行儀が非常に悪くて、繰り返し、繰り返し、同じ音声ファイルを取りに来ます。おそらく、この方とかこの方とかの言っていることと、問題の種類は同じではないかと思いますが、意外と情報少ないですね。Androidのバージョンとしては、4.4.2とか4.2.2とかあたりが多いです。他のサウンドよりも圧倒的に石音のサウンドへのアクセスが多いところから(2番目は、どこかのボタンをクリックしたときのサウンド)、音を鳴らすたびに取りに来ているのかなあと推測しますが、はっきりとは分かりません。結構うざいのですが、下手に弾くのも怖いので、もうこやつらが絶滅するのを待つほか無いのでしょうか…

後、エゴサしていたら、ちょっと嫌なのを発見。ぱっとは理由が分かりませんが、とにかくこちらの問題でないことを、祈るばかり… しかし報酬 1500円って、COSUMIのためだけにいいのであろうか…(笑)

レベル2以上のすべてのレベルでサーバの負荷が高い時に対局が開始できなくなりました

COSUMIのサーバの負荷が高い時に、今までのように9路盤レベル5と11路盤と13路盤のレベル4だけではなく、レベル2以上のすべてのレベルで、高いレベル・大きな碁盤サイズから順に、対局の開始ができなくなるようになりました。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

実質的に今までとそれほど変わりはないですが、一応今後はこういう仕様にさせていただきます。

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる

「囲碁をディープラーニングするのは面白い」という噂なので(笑)、私も試しに一度やってみることにしました。作るならやっぱり評価関数。それも、その時の形勢を「目数」で教えてくれるやつがなんかいいですよね? とりあえず今回は19路盤用です。

まずは学習に使うデータについてです。とりあえず評価する局面は、COSUMIで打たれた19路盤互先の作り碁の棋譜から作りました。GNU Go、強い人、弱い人、意図した序盤早々の連続パス、意図しないクリックミスの混ぜ合わさった様々なよく分からない局面が出現しそうで、まあ良いのではないかと…(笑) まず、最後のパスパスを取り除き、1手から最終手の間の一様乱数にまで棋譜の手数を短くして、さらに対称形を考慮しない完全な重複分を取り除き、残った棋譜の最終局面を使うことにしました。

そして次に、その局面に付けるラベル、今回の場合は「目数単位の形勢判断」ですが、うーん、これが本当にどうするのが良いのか… とりあえず、今回の作成方法は以下のとおりです。

  • まず先ほど作った局面を、コミ6目でRayの2k playoutに考えさせます
  • 返ってきたwin rateが0.5に近づく方向にコミを10目ずらして、もう一度Rayに考えさせます
  • それをwin rateが0.5の反対側に行くまで、繰り返します
  • 0.5をまたいだ2点を結んで、0.5と交わるところを「大体の形勢」とします
  • 再度、コミを「大体の形勢」として、今度はRayの20k playoutに考えさせます
  • 返ってきたwin rateが0.5に近づく方向に、今度はコミを4目ずらして、もう一度Rayに考えさせます
  • 先ほどと同じように、それをwin rateが0.5の反対側に行くまで、繰り返します
  • 先ほどと同じように、0.5をまたいだ2点を結んで、0.5と交わるところを「最終的な形勢」とします

あまりにも素朴すぎる気はしますが、こんな感じで作りました。前半は消費リソースを減らすためにやっているだけなので、後半だけを行っても当然似たようなラベルができるはずです。

最初のころは、これを10,000局面分作っていろいろ試していたのですが、ちょっと遊んでみたいだけとはいえ、それではあまりにも少なすぎたので、50,000局面分まで増やしました。そしてそれを対称形に8倍して、ここでもう一度重複分を除去し、きりの良い数字にまで少し減らして399,000局面分できました。今回は、その内80%の319,200局面分を学習用に、残りの20%の79,800局面分を検証用に使用します。

ここまで、学習データは用意できましたので、次に実際に学習を始めます。

今回の実行環境は、

  • Amazon EC2 p2.xlarge
  • Ubuntu 16.04 LTS
  • CUDA 8.0
  • cuDNN 5.1

です。最初、手元のGPUなしのWindowsマシン(CPU:Intel Core i5-3470S メモリ:16GB)でいろいろ試していたのですが、実際に学習が動き始めると、さすがにやはりちょっと遅すぎるので、EC2使いました。学習内容によって結構変わってくるみたいですが、だいたい12倍ほど速かったです。もう少し速いとうれしいのですが、しかたないでしょうか?

DNNのフレームワークには、バックエンドにTensorFlowを使ったKerasを使ってみました。

Keras
https://keras.io/

TensorFlow
https://www.tensorflow.org/

Kerasはとても分かりやすくて、私のような素人には本当にありがたい。かなりおすすめです。TensorFlowもですが、本家のドキュメントがしっかりしているのがいいですよね。例えば、今回のケースだと、こんな感じのコードになります。

import numpy as np
from keras.models import Sequential
from keras.layers import Activation, AveragePooling2D, Conv2D, Flatten
from keras.layers.advanced_activations import LeakyReLU
from keras.layers.normalization import BatchNormalization
from keras.optimizers import Adam

BATCH_SIZE   = 200
EPOCHS       = 20

x_train = np.load('x_train.npy');
y_train = np.load('y_train.npy');
x_test  = np.load('x_test.npy');
y_test  = np.load('y_test.npy');

model = Sequential()

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(AveragePooling2D(pool_size=(13, 13)))
model.add(Flatten())

model.summary()

model.compile(loss      = 'mean_absolute_error',
              optimizer = Adam())

model.fit(x_train, y_train,
          batch_size      = BATCH_SIZE,
          epochs          = EPOCHS,
          verbose         = 1,
          validation_data = (x_test, y_test))

驚くほどシンプルに書けます。

今回は、以下すべての場合において(ただし、追記に関してはこの限りではありません)、

バッチサイズ 200
エポック数 20
損失関数 平均絶対誤差(Mean Absolute Error)
最適化アルゴリズム Adam(パラメータはKerasのデフォルト)

です。バッチサイズは、実行速度などに影響がかなり大きいです。エポック数は、収束していなくても、過学習していても、なにがあっても、今回は一定でいきたいと思います。

ネットワークへの入力は、とりあえず最初、「次の手番のプレーヤーの石」と「相手のプレーヤーの石」の2面(19,19,2)、数値は0と1です。ちなみにですが、今回の学習データのラベルは、平均5.7、標準偏差32.9、平均偏差21.5ぐらいです。なので、とりあえず盤面見ないで「黒5.7目形勢が良い」って答えておけば、Lossは21.5にはなりますので(どちらが黒か教えませんので、実際はもう少し難しいはずですが)、最終的にその数字がどれくらい0に近づくのか、っていう感じで見てもらうと良いと思います。

それではいってみましょう。まず最初に考えたのはこんなネットワーク構成でした。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Activation('relu'))
model.add(AveragePooling2D(pool_size=(13, 13)))
model.add(Flatten())

model.summary()が吐いてくれるネットワークの要約がこちら。

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 32)        608       
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 32)        9248      
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 32)        9248      
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 32)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 13, 13, 1)         33        
_________________________________________________________________
activation_4 (Activation)    (None, 13, 13, 1)         0         
_________________________________________________________________
average_pooling2d_1 (Average (None, 1, 1, 1)           0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 19,137.0
Trainable params: 19,137.0
Non-trainable params: 0.0

パタパタパタと畳んで、ペタンを押しつぶして、フワーと見るイメージなんですが(笑)、ところがこれ、全く学習してくれません。

Epoch 1/20
319200/319200 [==============================] - 29s - loss: 22.3445 - val_loss: 21.9808
Epoch 2/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 3/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 4/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 5/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 6/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 7/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 8/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 9/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 10/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 11/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 12/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 13/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 14/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 15/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 16/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 17/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 18/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 19/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808
Epoch 20/20
319200/319200 [==============================] - 25s - loss: 22.3445 - val_loss: 21.9808

試しに、活性化関数をtanhに変更してみます。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('tanh'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('tanh'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('tanh'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Activation('tanh'))
model.add(AveragePooling2D(pool_size=(13, 13)))
model.add(Flatten())
Epoch 1/20
319200/319200 [==============================] - 29s - loss: 22.2877 - val_loss: 21.9071
Epoch 2/20
319200/319200 [==============================] - 26s - loss: 22.2663 - val_loss: 21.8958
Epoch 3/20
319200/319200 [==============================] - 26s - loss: 22.2548 - val_loss: 21.8842
Epoch 4/20
319200/319200 [==============================] - 26s - loss: 22.2462 - val_loss: 21.8796
Epoch 5/20
319200/319200 [==============================] - 26s - loss: 22.2417 - val_loss: 21.8763
Epoch 6/20
319200/319200 [==============================] - 26s - loss: 22.2386 - val_loss: 21.8739
Epoch 7/20
319200/319200 [==============================] - 26s - loss: 22.2370 - val_loss: 21.8727
Epoch 8/20
319200/319200 [==============================] - 26s - loss: 22.2341 - val_loss: 21.8692
Epoch 9/20
319200/319200 [==============================] - 26s - loss: 22.2325 - val_loss: 21.8677
Epoch 10/20
319200/319200 [==============================] - 26s - loss: 22.2305 - val_loss: 21.8665
Epoch 11/20
319200/319200 [==============================] - 26s - loss: 22.2290 - val_loss: 21.8653
Epoch 12/20
319200/319200 [==============================] - 26s - loss: 22.2273 - val_loss: 21.8669
Epoch 13/20
319200/319200 [==============================] - 26s - loss: 22.2259 - val_loss: 21.8618
Epoch 14/20
319200/319200 [==============================] - 26s - loss: 22.2245 - val_loss: 21.8624
Epoch 15/20
319200/319200 [==============================] - 26s - loss: 22.2234 - val_loss: 21.8621
Epoch 16/20
319200/319200 [==============================] - 26s - loss: 22.2221 - val_loss: 21.8590
Epoch 17/20
319200/319200 [==============================] - 26s - loss: 22.2208 - val_loss: 21.8604
Epoch 18/20
319200/319200 [==============================] - 26s - loss: 22.2197 - val_loss: 21.8587
Epoch 19/20
319200/319200 [==============================] - 26s - loss: 22.2191 - val_loss: 21.8621
Epoch 20/20
319200/319200 [==============================] - 26s - loss: 22.2178 - val_loss: 21.8557

ちょびっとだけ数字が動いた…(笑) 今度はLeakyReLUに。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(LeakyReLU(alpha=0.1))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(LeakyReLU(alpha=0.1))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(LeakyReLU(alpha=0.1))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(LeakyReLU(alpha=0.1))
model.add(AveragePooling2D(pool_size=(13, 13)))
model.add(Flatten())
Epoch 1/20
319200/319200 [==============================] - 34s - loss: 21.7510 - val_loss: 20.9956
Epoch 2/20
319200/319200 [==============================] - 30s - loss: 21.1638 - val_loss: 20.7552
Epoch 3/20
319200/319200 [==============================] - 30s - loss: 20.8117 - val_loss: 20.4443
Epoch 4/20
319200/319200 [==============================] - 30s - loss: 20.5938 - val_loss: 20.1891
Epoch 5/20
319200/319200 [==============================] - 30s - loss: 20.3966 - val_loss: 19.9154
Epoch 6/20
319200/319200 [==============================] - 30s - loss: 20.1918 - val_loss: 19.6722
Epoch 7/20
319200/319200 [==============================] - 30s - loss: 20.0177 - val_loss: 19.7719
Epoch 8/20
319200/319200 [==============================] - 30s - loss: 19.8868 - val_loss: 19.3948
Epoch 9/20
319200/319200 [==============================] - 30s - loss: 19.7355 - val_loss: 19.4068
Epoch 10/20
319200/319200 [==============================] - 30s - loss: 19.5322 - val_loss: 19.0625
Epoch 11/20
319200/319200 [==============================] - 30s - loss: 19.3279 - val_loss: 19.1659
Epoch 12/20
319200/319200 [==============================] - 30s - loss: 19.1512 - val_loss: 18.8860
Epoch 13/20
319200/319200 [==============================] - 30s - loss: 18.8963 - val_loss: 18.6369
Epoch 14/20
319200/319200 [==============================] - 30s - loss: 18.6399 - val_loss: 18.4589
Epoch 15/20
319200/319200 [==============================] - 30s - loss: 18.4826 - val_loss: 18.1423
Epoch 16/20
319200/319200 [==============================] - 30s - loss: 18.3363 - val_loss: 18.1451
Epoch 17/20
319200/319200 [==============================] - 30s - loss: 18.1859 - val_loss: 18.0372
Epoch 18/20
319200/319200 [==============================] - 30s - loss: 18.0898 - val_loss: 17.8348
Epoch 19/20
319200/319200 [==============================] - 30s - loss: 18.0122 - val_loss: 17.7273
Epoch 20/20
319200/319200 [==============================] - 30s - loss: 17.9057 - val_loss: 17.9030

おお、がっつり動き始めました! ここで、なんとなく分かりましたよ。現在のネットワーク構成では、一番最後の活性化関数の後ろに、もう畳み込み層や全結合層がありません。活性化関数がひとつ余分なんですね。ReLUは正の値しか出力しないので、それを平均してもまた正の値の出力しか出てきませんが、ラベルの方には負の値(次の手番側が形勢悪い)もあります。その時にパラメータの更新ができないとか、たぶんそういう話です(合ってるかな?)。ということで、活性化関数をReLUに戻して、一番最後のは削ります。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(AveragePooling2D(pool_size=(13, 13)))
model.add(Flatten())
Epoch 1/20
319200/319200 [==============================] - 29s - loss: 21.7389 - val_loss: 20.8649
Epoch 2/20
319200/319200 [==============================] - 25s - loss: 20.8634 - val_loss: 20.4426
Epoch 3/20
319200/319200 [==============================] - 25s - loss: 19.7709 - val_loss: 19.0222
Epoch 4/20
319200/319200 [==============================] - 25s - loss: 19.1506 - val_loss: 18.5475
Epoch 5/20
319200/319200 [==============================] - 25s - loss: 18.7009 - val_loss: 18.1697
Epoch 6/20
319200/319200 [==============================] - 25s - loss: 18.3530 - val_loss: 17.9657
Epoch 7/20
319200/319200 [==============================] - 25s - loss: 18.1615 - val_loss: 17.7496
Epoch 8/20
319200/319200 [==============================] - 25s - loss: 18.0063 - val_loss: 17.8551
Epoch 9/20
319200/319200 [==============================] - 25s - loss: 17.9094 - val_loss: 17.5887
Epoch 10/20
319200/319200 [==============================] - 25s - loss: 17.8051 - val_loss: 17.4792
Epoch 11/20
319200/319200 [==============================] - 25s - loss: 17.7149 - val_loss: 17.4250
Epoch 12/20
319200/319200 [==============================] - 25s - loss: 17.6149 - val_loss: 17.3268
Epoch 13/20
319200/319200 [==============================] - 25s - loss: 17.5354 - val_loss: 17.7732
Epoch 14/20
319200/319200 [==============================] - 25s - loss: 17.4814 - val_loss: 17.6514
Epoch 15/20
319200/319200 [==============================] - 25s - loss: 17.3799 - val_loss: 17.4220
Epoch 16/20
319200/319200 [==============================] - 25s - loss: 17.3349 - val_loss: 17.0786
Epoch 17/20
319200/319200 [==============================] - 25s - loss: 17.2229 - val_loss: 17.1846
Epoch 18/20
319200/319200 [==============================] - 25s - loss: 17.1549 - val_loss: 16.9264
Epoch 19/20
319200/319200 [==============================] - 25s - loss: 17.1092 - val_loss: 17.0422
Epoch 20/20
319200/319200 [==============================] - 25s - loss: 17.0327 - val_loss: 18.2891

OKのようです。

LeakyReLUってなんとなく好きなんですが、ReLUの方がやはり軽いみたいなので、ここから先はひとまずReLUを使います。

次に、ネットワークを深くしていきます。3×3の畳み込み層を全部で4層に。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(AveragePooling2D(pool_size=(11, 11)))
model.add(Flatten())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 32)        608       
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 32)        9248      
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 32)        9248      
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 32)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 11, 11, 32)        9248      
_________________________________________________________________
activation_4 (Activation)    (None, 11, 11, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 11, 11, 1)         33        
_________________________________________________________________
average_pooling2d_1 (Average (None, 1, 1, 1)           0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 28,385.0
Trainable params: 28,385.0
Non-trainable params: 0.0

そして5層、6層、7層、8層、と増やしていって、最後に全部で9層。今回はパディングを入れていないので、どんどん畳み込まれていって、3×3の畳み込みのみで1×1のサイズに。そうなると、最後の平均プーリングはもう意味がありませんので削除します。1×1の畳み込み層も、実質、ただの全結合になってしまいました。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Flatten())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 32)        608       
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 32)        9248      
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 32)        9248      
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 32)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 11, 11, 32)        9248      
_________________________________________________________________
activation_4 (Activation)    (None, 11, 11, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 9, 9, 32)          9248      
_________________________________________________________________
activation_5 (Activation)    (None, 9, 9, 32)          0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 7, 7, 32)          9248      
_________________________________________________________________
activation_6 (Activation)    (None, 7, 7, 32)          0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 5, 5, 32)          9248      
_________________________________________________________________
activation_7 (Activation)    (None, 5, 5, 32)          0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 3, 3, 32)          9248      
_________________________________________________________________
activation_8 (Activation)    (None, 3, 3, 32)          0         
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 1, 1, 32)          9248      
_________________________________________________________________
activation_9 (Activation)    (None, 1, 1, 32)          0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 1, 1, 1)           33        
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 74,625.0
Trainable params: 74,625.0
Non-trainable params: 0.0

3層~9層すべてのTrain Lossをグラフにしてみます。カッコ内の秒数は、2エポック目に掛かった時間です。だいたいこれが、1エポックあたりの平均の実行時間になります。

ネットワークが深くなるにつれ、どんどん賢くなっていくのがよく分かります。しかし、小さく畳み込まれたのをさらに畳み込んでいっているので、学習時間はあまり増えていきません。とはいえ、パラメータ数はどんどん増えていくので、過学習しやすくなったりはしてそうです。

パディングを入れれば、3×3の畳み込みをもっと重ねていくことは可能ですが、ここから先はひとまず9層で続けていきます。

次は、畳み込み層のフィルターの数を増やしていきたいと思います。まずは48に。

model.add(Conv2D(48, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(48, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Flatten())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 48)        912       
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 48)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 48)        20784     
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 48)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 48)        20784     
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 48)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 11, 11, 48)        20784     
_________________________________________________________________
activation_4 (Activation)    (None, 11, 11, 48)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 9, 9, 48)          20784     
_________________________________________________________________
activation_5 (Activation)    (None, 9, 9, 48)          0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 7, 7, 48)          20784     
_________________________________________________________________
activation_6 (Activation)    (None, 7, 7, 48)          0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 5, 5, 48)          20784     
_________________________________________________________________
activation_7 (Activation)    (None, 5, 5, 48)          0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 3, 3, 48)          20784     
_________________________________________________________________
activation_8 (Activation)    (None, 3, 3, 48)          0         
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 1, 1, 48)          20784     
_________________________________________________________________
activation_9 (Activation)    (None, 1, 1, 48)          0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 1, 1, 1)           49        
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 167,233.0
Trainable params: 167,233.0
Non-trainable params: 0.0

次は64に。

model.add(Conv2D(64, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(64, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Flatten())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 64)        1216      
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 64)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 64)        36928     
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 64)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 64)        36928     
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 64)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 11, 11, 64)        36928     
_________________________________________________________________
activation_4 (Activation)    (None, 11, 11, 64)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 9, 9, 64)          36928     
_________________________________________________________________
activation_5 (Activation)    (None, 9, 9, 64)          0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 7, 7, 64)          36928     
_________________________________________________________________
activation_6 (Activation)    (None, 7, 7, 64)          0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 5, 5, 64)          36928     
_________________________________________________________________
activation_7 (Activation)    (None, 5, 5, 64)          0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 3, 3, 64)          36928     
_________________________________________________________________
activation_8 (Activation)    (None, 3, 3, 64)          0         
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 1, 1, 64)          36928     
_________________________________________________________________
activation_9 (Activation)    (None, 1, 1, 64)          0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 1, 1, 1)           65        
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 296,705.0
Trainable params: 296,705.0
Non-trainable params: 0.0

フィルター数の違いを、グラフにしてみます。

これも増やせば増やすほど、賢くなっていきますが、学習時間の増え方もすごいですね。フィルター数64の時のTotal paramsは30万近くに… 身の丈に合っていないような気がするので(笑)、ここから先はひとまずフィルター数は32で続けていきます。

ここまでは、ネットワーク構成をいろいろ試してきましたが、ここで一度、ネットワークに対する入力を変更してみたいと思います。今現在は、石の配置の2面だけですが、これに「その場所の石のダメの数」を加えた3面にしてみました。数値はtanh(ダメの数*0.05)して0と1の間に収めました(0~1に正規化するのは、Kerasのサンプルがそうなっていたので)。ダメの数/256min(1, ダメの数/32)など、まあ何でもいいような気はします。ところで19路盤の最大ダメ数っていくらなんでしょう?

ダメなしとダメありとでの違いを、グラフにしてみます。

うーん、ちょっと効果が薄いですね。実は劇的に良くなるかと期待していたのですが… ダメの数は特に必要な情報でないからなのか、石の配置を見ればそんなことは分かるからなのかちょっとはっきりしませんが、ネットワークへの入力でがんばれることは、意外とあんまり無いのかもしれません。とはいえ、効果が全く無いわけではないので、ここから先はひとまず入力はダメありの3面で続けていきます。

次は、みんな大好き(笑)Batch Normalizationです。私は当初、Batch Normalizationって畳み込み層や全結合層の前に置くものだと、完全に思い込んでいたのですが、どうやら活性化関数の前に置くのが正しい? そのあたりも含めて調べてみます。

まずは、活性化関数の前にBatch Normalizationを置くバージョン。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(BatchNormalization())
model.add(Activation('relu'))
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Flatten())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 32)        896       
_________________________________________________________________
batch_normalization_1 (Batch (None, 17, 17, 32)        128       
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 32)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 32)        9248      
_________________________________________________________________
batch_normalization_2 (Batch (None, 15, 15, 32)        128       
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 32)        0         
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 32)        9248      
_________________________________________________________________
batch_normalization_3 (Batch (None, 13, 13, 32)        128       
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 32)        0         
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 11, 11, 32)        9248      
_________________________________________________________________
batch_normalization_4 (Batch (None, 11, 11, 32)        128       
_________________________________________________________________
activation_4 (Activation)    (None, 11, 11, 32)        0         
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 9, 9, 32)          9248      
_________________________________________________________________
batch_normalization_5 (Batch (None, 9, 9, 32)          128       
_________________________________________________________________
activation_5 (Activation)    (None, 9, 9, 32)          0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 7, 7, 32)          9248      
_________________________________________________________________
batch_normalization_6 (Batch (None, 7, 7, 32)          128       
_________________________________________________________________
activation_6 (Activation)    (None, 7, 7, 32)          0         
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 5, 5, 32)          9248      
_________________________________________________________________
batch_normalization_7 (Batch (None, 5, 5, 32)          128       
_________________________________________________________________
activation_7 (Activation)    (None, 5, 5, 32)          0         
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 3, 3, 32)          9248      
_________________________________________________________________
batch_normalization_8 (Batch (None, 3, 3, 32)          128       
_________________________________________________________________
activation_8 (Activation)    (None, 3, 3, 32)          0         
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 1, 1, 32)          9248      
_________________________________________________________________
batch_normalization_9 (Batch (None, 1, 1, 32)          128       
_________________________________________________________________
activation_9 (Activation)    (None, 1, 1, 32)          0         
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 1, 1, 1)           33        
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 76,065.0
Trainable params: 75,489.0
Non-trainable params: 576.0

長い…(笑) 次は、活性化関数の後にBatch Normalizationを置くバージョン。

model.add(Conv2D(32, (3, 3), padding='valid', input_shape=x_train.shape[1:]))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(32, (3, 3), padding='valid'))
model.add(Activation('relu'))
model.add(BatchNormalization())
model.add(Conv2D(1, (1, 1), padding='valid'))
model.add(Flatten())
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_1 (Conv2D)            (None, 17, 17, 32)        896       
_________________________________________________________________
activation_1 (Activation)    (None, 17, 17, 32)        0         
_________________________________________________________________
batch_normalization_1 (Batch (None, 17, 17, 32)        128       
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 15, 15, 32)        9248      
_________________________________________________________________
activation_2 (Activation)    (None, 15, 15, 32)        0         
_________________________________________________________________
batch_normalization_2 (Batch (None, 15, 15, 32)        128       
_________________________________________________________________
conv2d_3 (Conv2D)            (None, 13, 13, 32)        9248      
_________________________________________________________________
activation_3 (Activation)    (None, 13, 13, 32)        0         
_________________________________________________________________
batch_normalization_3 (Batch (None, 13, 13, 32)        128       
_________________________________________________________________
conv2d_4 (Conv2D)            (None, 11, 11, 32)        9248      
_________________________________________________________________
activation_4 (Activation)    (None, 11, 11, 32)        0         
_________________________________________________________________
batch_normalization_4 (Batch (None, 11, 11, 32)        128       
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 9, 9, 32)          9248      
_________________________________________________________________
activation_5 (Activation)    (None, 9, 9, 32)          0         
_________________________________________________________________
batch_normalization_5 (Batch (None, 9, 9, 32)          128       
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 7, 7, 32)          9248      
_________________________________________________________________
activation_6 (Activation)    (None, 7, 7, 32)          0         
_________________________________________________________________
batch_normalization_6 (Batch (None, 7, 7, 32)          128       
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 5, 5, 32)          9248      
_________________________________________________________________
activation_7 (Activation)    (None, 5, 5, 32)          0         
_________________________________________________________________
batch_normalization_7 (Batch (None, 5, 5, 32)          128       
_________________________________________________________________
conv2d_8 (Conv2D)            (None, 3, 3, 32)          9248      
_________________________________________________________________
activation_8 (Activation)    (None, 3, 3, 32)          0         
_________________________________________________________________
batch_normalization_8 (Batch (None, 3, 3, 32)          128       
_________________________________________________________________
conv2d_9 (Conv2D)            (None, 1, 1, 32)          9248      
_________________________________________________________________
activation_9 (Activation)    (None, 1, 1, 32)          0         
_________________________________________________________________
batch_normalization_9 (Batch (None, 1, 1, 32)          128       
_________________________________________________________________
conv2d_10 (Conv2D)           (None, 1, 1, 1)           33        
_________________________________________________________________
flatten_1 (Flatten)          (None, 1)                 0         
=================================================================
Total params: 76,065.0
Trainable params: 75,489.0
Non-trainable params: 576.0

これも、グラフにします。今回はValidate Loss付きです。

もう少したくさん学習させてみないと、最終的に収束した時のLossが低くなるのか、学習が速いだけなのか、よく分かりませんが、なんにせよ、とりあえずBatch Normalizationはすばらしい! Validate Lossも10をはっきりと切ってきました。みんな大好きBatch Normalization、僕も大好きです(笑)。1エポックあたりの学習時間は大幅に増えて、たしかに重いのは重いんですが、学習が速くなるのであれば、それも少なくともある程度はペイしそうです。

そして、先ほどの「Batch Normalizationは活性化関数の前なのか後なのか問題」ですが、今回のケースでは、「活性化関数の後」が良さそうです。平均した数字だけ見てもそうなのですが、「活性化関数の前」のValidate Lossの上下にバタバタする感じがちょっと気持ち悪い… ただ、今回は検証用データの量が絶対的に少ないので、もう少しちゃんと調べないと、はっきりしたことは言えません。

今後は、ひとまず「活性化関数の後」にBatch Normalizationを置く形で続けていきます。

いやあ、それにしても長い記事になりました。しかも、まだぜんぜん終わってない… たぶん、大量に追記することになります。

ここまで、やってきて一番思うのは、「学習データって大事」ってことです。これは量も質もですね。最初始めた時、「学習データなんてなんでもいいよ。俺はディープなラーニングがしたいだけなんだよ」って思ってた自分を引っ叩いてやりたい(笑)。ただ、当初はここまで良い数字が出るとは、正直思ってなかったから、ということもあります。例えば、今現在のようなネットワーク構成でも、もう少しネットワークを深くして、もう少しフィルターを増やして、学習データ増やして、ワンコインぐらい課金すれば、Validate Lossが7ぐらいまでいけそうですが、そこまでいければ、今回の評価関数は(も?)同じような盤面は同じように形勢判断を間違えるのだろうと思うので、深さ1の全幅と組み合わせて、GNU Goぐらいならなんとか勝てないでしょうか? もし仮にそれができたら、Keras.js使って、もうこれは何て言うか一丁上がりなんですが、なかなか事前にそこまで夢みることはできませんでした。

そういう訳で、とにかく学習データです。今現在、COSUMIのサーバを使って学習データを大量に作成中です(負荷が低くなったら、自動的に作り始めるようにした)。それができあがったら、また引き続きいろいろ試してみたいと思います。

[追記 2017/5/2]
あの後、学習データをたくさん作りました。まずは、前回使用したデータと今回分との、形勢の分布のグラフを。比較しやすいように、スケールは調整してあります。

前回分のデータの分布を最初に見た時、いくらなんでもこれは分散が足らないんじゃないかと思ったので、今回は平均近辺を適当に間引きながらデータを作成したのですが、あんまりきれいな間引き方になっていないような気がして、少しもったいなかったのですが、思いきって新規作成分の平均近辺をスクエアにぱすっと捨てて、それに前回作成分を足しました。えっと、なに言っている分からないと思いますが(笑)、とにかくグラフのような感じに、真ん中減らしました。前回、21.5だった平均偏差は27.8に。そこだけでいうと、今回の方が厳しいデータセットになっていると思います。

今回使用分は15万局面分+α。これを対称形に8倍して、切り良く120万局面分に減らしました。そして、前回と同じく、その内80%を学習用に、残りの20%を検証用に使用します。

この新しい学習データで、前回最後のネットワーク構成から試してみたいと思います。現在地をおさらいすると、

  • 入力は「手番のプレーヤーの石の配置」「相手の石の配置」「その場所にある石のダメの数」の3面(19,19,3)
  • 3×3の畳み込み層が9層、1×1の畳み込み層が1層、フィルター数は最後以外32
  • 活性化関数は全部ReLU
  • ReLUの後にBatch Normalization

です。さらに今回はここから、入力層の所にパディング付の3×3の畳み込み層を追加していく形で、どんどん深くしてみました。最後は3×3の畳み込み層が18層です。今回はエポック数は固定にしないで、Validate Lossが下げ止まったら、学習を止めるようにしました。話が少しそれますが、Kerasには、そういう時に使うkeras.callbacks.EarlyStoppingというコールバック関数が用意されているのですが、それのpatienceという引数についてのまともな説明が、ウェブ上にほとんど無い! これは本家のドキュメントも一緒で、例えば、日本語版ではこうなってます。

patience: トレーニングが停止し,値が改善しなくなった時のエポック数.

なにを言っているのか、まじでぜんぜん分からん…(笑) 次に本家英語版。

patience: number of epochs with no improvement after which training will be stopped.

私の英語力が確かなら、これも間違っています。例えば、patience=1の時は、最高なり最低なりを1回でも更新できなかったらそこですぐに止まるわけではなく、2回連続して更新できなかったら止まるんです。patience=2の時は、3回です。1回でも更新できなかったらすぐ止まるpatience=0を基準に、さらに何回待つかっていうのがこのpatienceですよ。みなさん気をつけてください。で、今回は最初の「3×3の畳み込み層が9層」の時のみpatience=2(ちょっと少なかった。加減が結構難しい…)、10層からはpatience=3に設定してみました。

うーん、もうネットワークを深くすれば良いだけなのかな? 簡単に数字が良くなっていきます。もっと早くサチるかと思っていたのに、なかなか止まらないので、気持ちよくお金が溶けていきました…(泣) 「こんな風に深くするだけでいいんであれば、小細工なしにResNetってやつをやれば終了じゃない?」ということで、前半部分にショートカットを入れたバージョンの14層と18層も追加で試してみました。先ほどのpatienceは4にしました。14層ならコードはこんな感じ。本当にこれで良いのか、かなり不安ですが…

input = Input(shape=x_train.shape[1:])

fork = Conv2D(32, (3, 3), padding='same')(input)

main = Activation('relu')(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation('relu')(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

main = add([main, fork])

main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='valid')(main)
main = Activation('relu')(main)
main = BatchNormalization()(main)
main = Conv2D(1, (1, 1), padding='valid')(main)

output = Flatten()(main)

model = Model(inputs=input, outputs=output)

ショートカットあるなしで比較してみます。

「18層の時は、もしかしたらショートカットが効いてるのかな?」ってぐらいですね。そもそも、この程度ではまだぜんぜんネットワークが深すぎるっていうほどのものじゃないのかもしれません。深くしたからサチったのではなくて、そろそろ学習データの精度の問題かも…

ここで一度、現在作っている評価関数が実際にどんな形勢判断を返してくるのか確認することにしてみました。使った評価関数のバージョンは、先ほどの「3×3の畳み込み層が18層/ショートカットあり」。これに、検証用データの先頭200局面分を予測させた時の数値のグラフがこちらです。

当たり前の話なんですが、本当に形勢判断できるんですね(笑)。感動します。ただ、ちょっと気になることもあって、この検証用データのラベルが8つずつ全く同じのが続くのは、同じ局面の対称形が連続して並んでいるからなんですが、評価関数の出力の方はなかなかきれいに揃わないですね。これを「まだ伸び代がある」とか、「対称形8つ全部を順番に評価関数に入れて平均とったら精度上がるんじゃない?」とか、ポジティブに捉えることもできなくはないかもしれませんが、個人的にはこういうのはただただ気持ち悪いです… こうなる理由として考えられるのは、「3×3の畳み込み層のフィルタの初期値が対称形でないから」とか、「学習用データに対称形がすべて含まれているけど、学習するタイミングが前後するので、先に学習した、後に学習したでモデルに与える影響が変わってくるから」とかあたりでしょうか? これはまた調べてみたいですね。

今回の200局面分の予測の中で検証用データのラベルと一番食い違っているのが、グラフ中央右寄りにある100を超えているやつなので、この局面を探して実際に盤面を見てみることにしました。それがこちら。


Sorry, your browser doesn’t support WGo.js.

検証用データのラベルは約138.61。これは、「コミがないとすれば次の手番である白が138.61目勝っている」の意味です。最初に盤面で確認しておかないといけないのは、下辺の黒の大石の死活ですが、これはセキにはなりますが生きてますね(見損じしてないよね?)。だとすると、形勢は白100目弱勝ちぐらいでしょうか? 自作評価関数の出力は対称形8つの平均で87.31。おお、自作評価関数の方がだいぶ近い… 先生より正確とはやるじゃん!(笑) まあ、「石いっぱいあるから強ーい」ぐらいに思っているだけで(笑)、Ray先生のような高度な判断をしている訳ではないような気がしますが、とはいえ、こういった不正確なラベルのせいで、40目も余分に間違えていることにされるようなことがちょくちょくあったら、下がるはずのLossも下がりません。「機械学習では質の良い学習データを大量に用意することが肝心」、という結論にまた落ち着いてしまいますね。ということで、現在、学習データの精度を上げるべく、COSUMIのサーバをまたぶん回しております。いつか、学習データの作成自体を、この評価関数にやらせたいですね。それができれば、量の問題は一発で解決なんですが…

[追記 2017/6/11]
あの後、ASUSのSTRIX-GTX1060-DC2O6GっていうGTX1060・メモリ6GBなビデオカード買いました。EC2への課金が100ドルを超えてきたので、EC2使い続けるのか、別の方法を取るのか、今決めてしまわないといけないと思い、かなりいろいろ考えて、結局GPU買っちゃいました。最初は、GPU買うなら中途半端はだめで、1080ti一択だなと思い込んでいたのですが、そうなってくると電源ユニットの買い直しが確定するので、それがちょっとなあと思っていました。けれども、よく調べてみると、その下のグレードでも十分実用性がありそうですし、なによりはるかに安いので、こういう選択肢になりました。1070でも良かったけど、電源が100%自信が持てなかったので1060に。使っているマザーはASUSのP8H77-Vで、H77と最近のビデオカードとでは動かない時がある、という話を見て少し心配していたのですが、全く問題ありませんでした。このビデオカードは、温度が低い時にファンが完全に止まる静音設計で、それも購入にあたって重視していた点なのですが、そもそもファンが回っていても、めちゃくちゃ静かです。良い買い物でした。こんな高価なビデオカードを買うのは、もちろん初めてですし、ビデオカード自体、一番最後に買ったのはいつのことだろう… Rage Fury MAXX(笑)が最後かな?(一番最後まで使っていたのは、たぶんG400) ちなみに、今現在のメインメモリは16GBなんですが、GPU買ってしまうと、今度はこれを32GBに増やしたくて仕方がない…(笑) ただ、4年半前に買った時は5,880円だった物が、今現在、値段が倍以上する感じで萎えまくりです。うーん、どうしたものか…

そして、学習データもこの前使っていたものを、さらに50k playoutで2目ずつずらしていく形でラベル付け直して精度を上げてみました(この前までは、20k playoutで4目ずつ)。量も少し増やして、計159万局面分。今までと同じく、その内80%を学習用に、残りの20%を検証用に使用します。

ということで、新しいGPUと新しいデータでいろいろ試してみましたが、結局一番数字が良くなるのは、次のようなパディングとショートカットを入れながら、ひたすら3×3の畳み込み層を重ねるだけというシンプルなやつでした。

input = Input(shape=x_train.shape[1:])

fork = Conv2D(32, (3, 3), padding='same')(input)

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

fork = add([main, fork])

main = Activation("relu")(fork)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)
main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(32, (3, 3), padding='same')(main)

main = add([main, fork])

main = Activation("relu")(main)
main = BatchNormalization()(main)
main = Conv2D(1, (3, 3), padding='valid')(main)
main = AveragePooling2D(pool_size=(17, 17))(main)

output = Flatten()(main)

model = Model(inputs=input, outputs=output)

ショートカットなし版との比較がこちら。

ショートカットは、はっきり効果があるようです。そして問題は、深くするのが良いのか広くするのが良いのかなんですが、まずはフィルタ数を32で固定して、3×3の畳み込み層が24層、32層、40層の比較がこちら。

そして次に、3×3の畳み込み層を24層に固定して、フィルタ数が32、48、64の比較がこちら。

それ以外にもいろいろ試した結果としては、

  • ReLUとBatch Normalizationの順番は、BN -> ReLU -> ConvよりReLU -> BN -> Convの方が、やはり良さそう
  • 入力は、「だめの数なし」より「だめの数あり」の方が、やはり少し数字が良い
  • オプティマイザにNesterov MomentumなSGDを少し試してみたけど、特に良さそうには見えない

といった感じでしょうか。

数字はだいぶ良くなってきたので、本当に何か使い道も考えてみたいですね。

[追記 2017/6/14]
今のデータ量で行けるところまでやってみようと、3×3の畳み込み層が30層、フィルタ数が48で50エポック回してみました。さらに、その30エポック目からAdamの学習率をKerasのデフォルト(そしてそれは論文の推奨値だそうです)の1e-3から1e-4に小さくしたのと、またさらに、その40エポック目から学習率を1e-5に小さくしたのとのグラフがこちら。

この学習率を下げるのは手動でやっているのですが、本当はこのあたり、コンピュータにスマートによろしくやってもらわないといけないのでしょうね。keras.callbacks.LearningRateScheduler()使ったり、keras.optimizers.Adam()decayを設定すれば良いのかなと、少し試してみたりもしましたが、結局どのくらいずつ下げていけば良いのか事前にはっきり分からないので、もう手動でもいいかな…

それと、学習率下げてはっきりしましたが、最後はほんの少し過学習ぎみですね。対称形に8倍して1,272,000局面分のデータ量では、Trainable params586,513の今回の大きさのネットワークあたりが限界かな、という気がしてます。

しかしそれにしても、数字がかなりよくなってきて、Validate Loss3.6(!)を切ってきました。そんなのもう、ほとんどRay由来のノイズじゃないのかと思ってしまいます。というより、データ作成で何かやらかしていないか、心配になるレベルなのですが…(笑)

[追記 2017/8/2]
KerasのConv2Dkernel_initializerのデフォルトは、Glorot uniformってやつなんですが、He uniformも試して比較してみました(本当に申し訳ないのですが、今回の追記分のテストは1ヶ月以上前にやっていたことで、他の細かい条件がはっきりとは分からなくなってしまいました。さっさとブログに書けば良かった…(笑))。

なんだか、あまり小さくない差があるように見えます。

glorot_uniformVarianceScaling(scale=1., mode=’fan_avg’, distribution=’uniform’)と等価なんですが、次に、このscaleをいろいろな数値に変えた時の、1エポック目のTrain Lossをグラフにしてみました。

0.1ぐらいが一番良さそうで、Glorot uniformの1とそれなりに差があるように見えます。まあこれは、まだ1エポック目ですし、そしてValidate LossではなくTrain Lossですので、あまり真に受けてもいけないと思うのですが、「畳み込み層の初期値はなんでも良いわけではない」のは、間違いなさそうです。意外とこんな所に宝物が隠れていることが少なくないのかも…

[追記 2018/2/11]
続きの記事があります。

Keras/TensorFlowでDNNな囲碁の評価関数を作ってみる その2
http://www.perfectsky.net/blog/?p=380

Rnやばい

Masterやらなんやらで大騒ぎだったここ一ヶ月間ほどのコンピュータ囲碁界でしたが、そんな中、ひっそりと、しかし何気に本格的にやばいなと思うのが、CGOSでのRayのニューラルネットワーク強化版、Rn(と呼べばいいのか?)の強さです。現在最新のRn.3.6-4cは、アンカーとして(?)以前からずっと居続けているZen-12.0n-1c追いついた(この表現は誤解を生む…)たどり着いた感じです。

(CGOS) 19×19 Computer Go Server
http://www.yss-aya.com/cgos/19×19/standings.html

逆にちょっとだめそうなのがZenで、ここ最近あまりレート上がってないですよね? CGOSだけで判断していいのかは分かりませんが、今度のワールド碁チャンピオンシップは3連敗の可能性が一番高いのでは…

一番直近のRnとZenの最新版の対局を一局どうぞ。


Sorry, your browser doesn’t support WGo.js.

そろそろCOSUMIの19路盤も強くできそうな気がしてきました。AlphaGoがオープンソースにならないかな?(笑)

「Ray 囲碁」をGoogleで検索すると、うちのブログ記事が一番上に来るのが気に食わないので、最後にRay関係のリンクをいろいろ置いておきます。

Rayの本家サイト
http://computer-go-ray.com/

RayのGitHub
https://github.com/koban6/Ray/

RnのGitHub
https://github.com/zakki/Ray/

Rayの中の人のTwitter
https://twitter.com/goraychan

Rnの中の人のTwitter
https://twitter.com/k_matsuzaki

[追記 2017/2/7]
Rnの中の人、松崎さんがこの記事を見てくださったみたいです。

一応念のために書いておくと、CGOSで動いているRnとZen(1c0g)はハードがだいぶ違うというのは理解しています。でもまあ、あれだけガチで開発しているZenが強いのはある意味当然ですし、毎日毎日、計52コアでGNU GoとFuegoを動かし続けている私からすると、自分はものすごく間違ったことをしているのではという不安に襲われ(笑)、「Rnやばい」って感想になります。

コメントがスパム判定されるっていうのは、他の方にも言われました。コメントしようとして下さったみなさん、申し訳ありません。また時間のある時に調べます。

[追記 2017/2/19]
Rn.3.9-4cが14戦全敗だったZen-13.3-1c1gに、Rn.3.10-4cがいきなり土をつけてちょっとびっくり。しかし、すべては偶然の産物か…


Sorry, your browser doesn’t support WGo.js.

それにしても、碁のレベルが高すぎ…

13路盤レベル4の棋譜を公開します

COSUMIの13路盤レベル4の棋譜がある程度溜まってきたので、公開します。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

作り碁になった対局のみの、全部で72,498局分です。COSUMIが黒番のも、白番のも、勝ったのも、負けたのも、まぜこぜになったひとつのテキストファイルが圧縮してあります。解凍してから、適当に切り分けてお使いください。

http://www.perfectsky.net/misc/cosumi_13x13level4.zip

以前公開した9路盤レベル5の棋譜も、よければどうぞ。

http://www.perfectsky.net/misc/cosumi_9x9level5.zip

なんかの役に立ちますかね?

趙治勲 vs Zen

第2回囲碁電王戦が開催されることになりました。

第2回囲碁電王戦
http://denou.jp/go/

記者発表会が行われると発表された時に、ある程度予想できた内容と言えるでしょうか。前回の囲碁電王戦の時も、発表から開催までの間隔が非常に短かったのですが、こうした方が注目を集めやすいという判断なんでしょうね。それにしても、世間一般的に囲碁は全く話題になりませんね。ただ、AlphaGoの時も一回始まってからがすごかったので、まだ今のところはっきりとは言えませんが…

ZenはKGSで10dですから、もちろん勝機は十分にあるでしょう。記者発表会で出てくる12.4というバージョンから、どれだけ上積みがあるのかはちょっと分かりませんが、CGOSとか見てる限り、むちゃくちゃな進歩は無さそうでしょうか?

おそらく、来年の柯潔-AlphaGo戦はすでに決まっているのだと思いますが、ここまでくるとGoogleは一番手直りでやりたいぐらいでしょうから、柯潔先生にそれを受けてもらえなければ、とりあえず今回Zenにがんばってもらって、その後Zenと一番手直り十番勝負ぐらいやればいいんじゃないかと思います。

[追記 2016/11/20]
ということで、第一局は趙治勲名誉名人の中押し勝ちでした。実力が拮抗してそうなので、残り2局もかなり楽しめるんじゃないかと… ただの勘で本当に適当なことを書きますが、右下を黒にコスミできっちり取りきっててもらえれば、Zenが勝てたような気がしないでもないです。できれば、Zenにも一つ勝ってもらいたいですね。

しかし、COSUMIには本当に人が来ないですねえ。第1回囲碁電王戦の時は、(たしかものすごい突貫工事で作った)囲碁のルール説明の動画を流してたのに、なんで今回はそういうの流さないんだろうと思います。考えがあってそうしているのならまあなんですが、ただうっかりしているだけっぽいのがなんとも…

[追記 2016/11/20]
第二局はDeepZenGoの中押し勝ちでした。対局内容が、なんだかものすごくZenな感じでした。これで両者とも一つは勝てて、良かったのではないでしょうか。第三局も楽しみです。

[追記 2016/11/24]
第三局は趙治勲名誉名人の中押し勝ちとなり、第2回囲碁電王戦は趙治勲名誉名人の勝利となりました。おめでとうございます。

ここからは、少し話題になっているZen開発者の加藤さんの判断による投了について、私の考えを書いてみたいと思います。

まず第一に、あんな局面で投了するなんてありえません。趙先生も井山先生も全然しっかりとした見通しが立っている感じではないですし、なによりもZen自身の白番のwinrateが50.1%のタイミングで投げるなんて、正気の沙汰ではない(ちなみに、手元の天頂の囲碁6だと62%ぐらい、山下さん曰くAyaは72%!)。しかし、以前、将棋電王戦で話題になった時にも感じたことですが、そもそも大会レギュレーションで開発者判断の投了が許可されているのがおかしな話で、「本当にドワンゴは学習能力ないわ。五目ナカデで死ね」って最初思ったのですが(笑)、一応念のために、今回の第2回囲碁電王戦の対局ルールを確認してみると、これって開発者判断による投了を認めていない気が…

囲碁電王戦 趙治勲名誉名人 vs DeepZenGo 対局ルール
http://denou.jp/go/pdf/denou_go_rule201611.pdf

ゆっくりと順番に読んでいきますと、まず今回の大会では対局ルールを

対局は日本囲碁規約に準ずるものとする。

としています。日本囲碁規約とはこれのことです。

日本囲碁規約(全文) | 棋戦 | 囲碁の日本棋院
http://www.nihonkiin.or.jp/match/kiyaku/zenbun.html

この日本囲碁規約の第十一条でこのように定められています。

第十一条(投了)
対局の途中でも、自らの負けを申し出て対局を終えることができる。これを「投了」という。その相手方を「中押勝」という。

素直に読めば、負けを申し出ることができるのは対局者のみ、今回の場合はDeepZenGo(と趙治勲名誉名人)のみです。そして、先ほどの「囲碁電王戦 趙治勲名誉名人 vs DeepZenGo 対局ルール」にはこれを上書き、または補完するような規定が見つかりません。このようなレギュレーションで行われていた対局にもかかわらず、開発者の判断で勝手に投了するのは無理があると思われます。

開発者の判断で投了することの是非が、過去に大きく話題になったのは、なんといっても将棋電王戦FINALでの、AWAKE開発者、巨瀬亮一さんによる21手投了でしょう。あの投了に対して様々な議論があるのは致し方ないことですが、ただ間違いなく言えるのは、レギュレーション的には問題なかったということです。

将棋電王戦FINAL 対局ルール
http://ex.nicovideo.jp/img/denou/final/pc/Rules_denousen_final.pdf

着手確定について」の項目には、こう書かれています。

ソフト開発者には「投了する」の権利を認める。

ドワンゴはしっかりとした意図を持って、このような権利を開発者に付与することを今回は止めたのではないかと推測するのですが、もし仮にそうだとしたら、運営としてレギュレーション違反だとちゃんと指摘しようよ…

長くなりましたが、まとめます。

  • 開発者の判断による投了は、レギュレーション違反。運営も含めて、なぜみんなそれを指摘しない…
  • 仮にレギュレーション的に問題なくても、あんな所で投げるな!(怒)

以上です。

13路盤にレベル4を追加しました

COSUMIの13路盤に、レベル4の強さ設定を追加しました。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

ただし、今回もサーバの負荷が高い時に対局が開始できず、9路盤レベル5や11路盤レベル4よりもさらに早い段階で、対局開始不可能になりますのでご了承ください。今現在は、一日の内、1/5ぐらいは動かない感じなんですが、今後は正直ちょっとよくわかりません。「打てればラッキー」ぐらいでお願いします。棋力は、囲碁クエだと1700にはちょっと足りないくらいでしょうか? 自分でも何局か打ちましたが、まだ少し調整が必要な気はしています。

今回の13路盤レベル4ははっきり言って重いです… あまりに重いので、一局あたりサーバ代がいくらになるのかを試しに計算してみると、サーバのリソースをきっちり使い切ったとして、0.15円ぐらいでした。最初、「意外と安いな」と思ってしまった自分がいて怖かったのですが、いやいやぜんぜん安くないから!(笑) でも、サーバの負荷が高い時間帯に止めれば、実質タダであります。

今回はRay先生のお世話になろうかと、当初考えていたのですが、とりあえず実績のあるFuegoでいってみます。あと、今回の13路盤レベル4の棋譜がある程度たまったら、後日まとめて公開したいと思います。

[追記 2017/1/8]
棋譜を公開しました。

http://www.perfectsky.net/blog/?p=339

Amazon EC2でDarkForestを動かしてみた

Amazon EC2のg2.2xlargeでDarkForestを動かしてみました。G2はGPUなインスタンスファミリーです。基本的にドキュメントどおりで、あまり中身のある内容ではありませんが、以下、簡単に手順を書いていきたいと思います。

まずはともあれ、DarkForestのドキュメントに目を通しておきます(g2.2xlargeはそんなに安くありませんので(笑)、インスタンス立ち上げる前に準備をしっかりしとかないとね!)。

darkforestGo/README.md at master ・ facebookresearch/darkforestGo ・ GitHub
https://github.com/facebookresearch/darkforestGo/blob/master/README.md

EC2は初めて使ったのですが、インスタンスの使用数に制限があって、私の場合は、なんとg2.2xlarge0(!)でした。制限緩和のリクエストは可能ですが、承認されるのに私の場合で半日ほど掛かりましたので、使用の予定がある時は、早めに確認しておくことをお勧めします。

OSは、Ubuntu 16.04で今回はいきたいと思います。Ubuntu初めて触りました。初めてだらけです。こちらのページで、Version16.04 LTSを選び、Instanch Typehvm:ebs-ssdを選びして(他との違いがよく分かりませんが…)、最後にZoneus-west-2(オレゴン)なami-191fd379に決定しました。

インスタンスを起動したら、まず最初にこちらに書かれていることを全部やります。ただし、cuDNNはcudnn-7.5-linux-x64-v5.1-rc.tgzを使用してみました。cuDNNのダウンロードには、NVIDIAのAccelerated Computing Developer Programへの登録が必要です。

Ubuntu 16.04へのCUDAインストール方法 – Qiita
http://qiita.com/yukoba/items/3692f1cb677b2383c983

次にTorchです。こちらを参考にします。

Torch | Getting started with Torch
http://torch.ch/docs/getting-started.html

言われるようにやっていきます。

$ git clone https://github.com/torch/distro.git ~/torch --recursive
$ cd ~/torch
$ bash install-deps
$ ./install.sh
$ source ~/.bashrc
$ luarocks install class
$ luarocks install image
$ luarocks install tds
$ luarocks install cudnn

そして、本題のDarkForest。まずはコンパイル。

$ git clone https://github.com/facebookresearch/darkforestGo.git ~/darkforest --recursive
$ cd ~/darkforest
$ sh ./compile.sh

次に、モデルファイルを用意します。

$ mkdir ~/darkforest/models

作ったmodelsディレクトリにこちらのファイルを(よく分からんから全部)入れておきます。

Dropbox – df_models
https://www.dropbox.com/sh/6nm8g8z163omb9f/AABQxJyV7EIdbHKd9rnPQGnha?dl=0

次に、pipeファイル用のディレクトリをどこか適当な場所に作ります。

$ mkdir ~/df_pipe

ここまでで、準備は完了です。そして、実際にDarkForestを動かすためには、まずGPUサーバを動かします。ここで、先ほどのpipeファイル用のディレクトリを指定してください。

$ cd ~/darkforest/local_evaluator
$ sh cnn_evaluator.sh 1 ~/df_pipe

そして、本体を動かします。再度、先ほどのpipeファイル用のディレクトリを指定してください。

$ cd ~/darkforest/cnnPlayerV2
$ th cnnPlayerMCTSV2.lua --pipe_path ~/df_pipe

これでGTPコマンドを受け付けてくれるようになります。cnnPlayerMCTSV2.luaにはオプションがいろいろあるので確認してみてください。ただ、MCTSではないPure-DCNN playerCNNPlayerV3.luaっていうのもあるのですが、こいつが動いてくれません(本当は、こっちに興味があったのですが…)。df.binは、代わりにdf2.binとかを使えばいいのかもしれませんが、value_model.binっていうのがどこにも見当たりません。残念です。

最後に、gogui-twogtpで取った棋譜を3局載せておきます。3局とも、黒が--time_limit 10で、白が--time_limit 20です(実際の消費時間は、白が黒の約1.37倍)。


Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

はっきりとは棋力が分かりませんが、とりあえず私よりは間違いなく強そう…(笑) とはいえ、私はこの3局以外にも何局か棋譜を確認しましたが、あきらかにおかしな手が結構あります。一種の攻め合いのような時が多いように思えますが、例えば、3局目の291手目(同じく292手目、293手目、ついでに295手目!)とかやばすぎる… 「MCTSは攻め合いが…」とかそんなレベルではないと思うし、というか、これはもうただのアタリアタリですしね。なんか致命的なのが、コードに残っているような気がします。

あと、部分部分でDarkForestがものすごく好む形っていうのがいろいろありますね。いくつかの棋譜を続けて見ていたら、「あれっ、これ今さっき見たやつじゃない?」ってなるぐらい、部分的に同じような形のオンパレードになります。ひとつだけ例をあげると、星に小ゲイマに掛かられた時、ほぼ例外なくケイマか一間に受けて、周りの状況がどうであれ、ハサミ返すことはしません(私がざっと見たかぎり、約20回中0回でした)。モデル、ひいてはそれを作成するのに使った棋譜によるところが大きいのだろうし、これをDarkForestの特徴とは言っていいのかよく分かりませんが、Fuegoなどでは、あまり感じない傾向だと思います。

先ほどの3局は、並列ではなく一局ずつ打たせてて、全部で3時間以上掛かっています。そして、あまりよく分からないですが、GPUはだいたい使い切っているように見えます。もちろん、消費リソースをもっと絞って打たせることはできますが、やっぱりお金が掛かりますね。「DarkForestを、なんらかの形でCOSUMIで使えたら…」と思ったのですが、簡単ではないなあ… また、しばらく考えておきます。

強豪囲碁ソフト「Ray」のソースコードが公開されました

先日の第9回UEC杯コンピュータ囲碁大会でも7位になった、とても強い囲碁ソフト、「Ray」のソースコードが公開されています。

Ray – Computer Go Program
http://computer-go-ray.com/

すばらしすぎる話です。現時点で、オープンソース最強は間違いないところでしょうか?

ということで、とりあえずFuegoとたくさん対局させてみました。まずは19路盤、Ray 5,000playoutとFuego 5,000playoutで先後を換えて50局ずつ計100局やってみました。Windows用のバイナリも公開されていて、ただなぜか動作がすごく遅いらしいのですが、今回はLinuxで動かしてます。

Rayは--playout 5000というオプションと付けただけ。Fuegoはこれだけ。

uct_param_search number_threads 1
uct_param_player ignore_clock 1
uct_param_player max_games 5000

結果は、

Ray 5,000po(443.5sec) 89勝 – 11勝 Fuego 5,000po(211.5sec)

カッコ内は一局あたりの平均消費時間です。この設定だとRayがFuegoの2倍ほど時間を使うので、次にRayのみ2,500playoutにしてさらに試してみます。結果は、

Ray 2,500po(210.9sec) 81勝 – 19勝 Fuego 5,000po(198.9sec)

Ray強い…

次に13路盤で、Fuego 10,000playoutに対してRay 5,000playout、3,000playout、2,000playoutでも試してみました。結果は、

Ray 5,000po(69.0sec) 76勝 – 24勝 Fuego 10,000po(59.5sec)
Ray 3,000po(42.1sec) 56勝 – 44勝 Fuego 10,000po(58.7sec)
Ray 2,000po(27.8sec) 50勝 – 50勝 Fuego 10,000po(57.7sec)

13路盤では、Fuegoの倍ほど速そうです。COSUMIでは、Fuegoを動かすためだけに、だいたい年50万円ぐらい掛かっていると思うので、それが半分になる計算に…(ニヤリ) などという皮算用をついしてしまいますが、実際はまたいろいろ大変かな? さらに強くなったバージョンを、いつか公開していただけたら、かなり真剣に考えると思います。

それにしても、このRayに勝てる方って囲碁ファン全体の何パーセントぐらいなんでしょうか? たぶん、大半の人はもう勝てないと思うのですが、そんなソフトが自由に使える訳で、なんかすごいですね…

井山棋聖の七冠挑戦とCOSUMI

昨日の第54期十段戦第3局は、黒番伊田十段の中押し勝ちとなり、井山棋聖の七冠達成は次局以降へと持ち越しとなりました。私は、「井山七冠」を何とか一度見てみたいと思っている人間なんですが、昨日の結果はまあこれで良かったのかなと思っています。伊田先生の意地を強く感じましたし、なんだか盛り上がりに欠けるなあと思っていた今回の七冠挑戦ですが、一回世間の注目を大きく集めることができたような気がしてます。

ここでは、井山棋聖の七冠挑戦関連の話題にCOSUMIがどんな影響を受けたのか、書いていきたいと思います。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

とりあえず、昨日は言うほどたいしたことはなかったような気がしますが(AlphaGo騒動で感覚が麻痺しているだけかも(笑))、それでも一瞬凄いことに…

PM5:26、たぶんテレビ? 4桁は初めて見ました…

続きの情報は、おいおいここに追記していきます。

[追記 2016/4/24]
ということで、井山七冠が誕生したわけですが、COSUMIへの新たな人の流入はほとんど無いと言っていい状況です。いろんな意味でこれは結構まずいと思いますが、無駄に毒吐いてもしかたないので、もう別に何も言いません。一週間後ぐらいに、年始からのアクセスの推移を追記して、AlphaGoの時との比較なんかが分かるようにしたいと考えてますので、興味のある方はぜひご覧ください。

[追記 2016/5/2]
年始から4月末までのCOSUMIへの1日単位のアクセスの推移です。

次に、COSUMI開始時から4月末まで。

最後は、「AlphaGo vs セドル」の時と「井山七冠誕生」の時とでの、COSUMIへのアクセスの質的な違いが一番よく分かる気がしているグラフを載せておきたいと思います。3月1日から4月末までの、1時間単位の新規セッション率の推移です。

このグラフについて少しだけ補足しておくと、右側「井山七冠誕生」の方の一番大きな3つのスパイクは、左から順に、「新・情報7daysニュースキャスター」(ダイヤモンド囲碁サロンとかが出てた?)、「アッコにおまかせ」(碁的の話などをしてた?)、「プロフェッショナル 仕事の流儀」(約2年前の再放送。今日もまた放送してました)で間違いないと思います。一番最初の「新・情報7daysニュースキャスター」ですら、井山七冠誕生の瞬間から丸3日以上経っての話というのも、なんだか凄いです。これ以上のことは、もうノーコメントで…(笑)

[追記 2016/5/6]
PM10:42、報道ステーションです(報道ステーション多いなあ)。

これもまた、二度とはお目にかかれなさそうな数字です。この「現在★人のアクティブユーザーがサイトを訪問しています」ってやつは、その時たまたまGoogle Analyticsの管理画面を見ていないかぎり確認できないんですが、実は、自分の知らない時にもっとすごい数字になっていることがあるんでしょうか? ちなみにこういう数字になる時は、大半が囲碁のルール解説のページ(http://www.cosumi.net/learn.html)へのアクセスで、さらにいつもはけっして多くはない、スマホからのアクセスだらけになります。

サーバの負荷が高い時に9路盤レベル5と11路盤レベル4の対局が開始できなくなりました

COSUMIのサーバの負荷が高い時に、9路盤レベル5と11路盤レベル4の対局が開始できなくなりました。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

現時点では、これは予防的処置なので、実際に対局が開始できない時間帯はほとんどないはずです(井山七冠が誕生したら知りませんが…)。ただ、もし今後、対局ができない状態がある程度常態化しても、それがもうよっぽどではないかぎり、サーバの増強は控えさせていただきます。実は、この一年間にお支払いしたサーバ代が160万を超えていて、いくらなんでもさすがにやりすぎだったので、ちょっと自重します。私はここ何年もの間、「朝起きたら、GNU GoとFuegoが二子ずつ強くなっていないかな」と思いながら床に就く日々を送らせていただいております(笑)。

というマイナス方向の改変のお知らせでしたが、今回のような対策をすれば、今度は逆に今後13路盤レベル4が追加できるかもしれません。せっかく高いお金を出して買ったリソースなので、できるだけ全部使い切りたいですしね。状況見ながら考えておきます。

という訳で、井山七冠対策はこれにて終了。何とか間に合いました(結構早い段階からいろいろがんばっていたおかげで、AlphaGo騒動も乗り切ることができました。何もしていない時にあんなの始まったら、どうにもなんない(笑))。「ここまでやってだめならもう知らない」って感じなんですが、しかし、今のところなんだか盛り上がりに欠けますねえ。AlphaGoのインパクトが強すぎたせいもあるんでしょうか?

セドル vs AlphaGo

本当に楽しみです。関連する内容はここに書いていきたいと思います。

対戦条件を確認しておくと、

  • 全部で5番勝負
  • 日程は3月9日、10日、12日、13日、15日。開始は午後1時
  • 対局ルールは中国ルール、コミは7目半
  • 持ち時間は2時間+1分*3回

マイケル・レドモンド九段の解説(お相手は、Chris Garlockという方)が、YouTubeで生放送されます。あと38時間

Match 1 – Google DeepMind Challenge Match: Lee Sedol vs AlphaGo – YouTube
https://www.youtube.com/watch?v=vFr3K2DORc8

ただし、英語の解説なので、今回初めて囲碁に興味を持った方も対象にした感じになるのかな、という気がします。日本語の解説は囲碁プレミアムで無料で見れるようです。

[追記 2016/3/9]
ということで、第1戦は白番AlphaGoの中押し勝ちとなり、歴史的な日となりました。以前、「羽生よりセドルが先にコンピュータに負けるよ」と言っていた人がいて、深い読みだなあと妙に感心したことがあったのですが、単に深いだけはなく、正確でもありましたね。私の「Xデーは2018年」という予想は、残念ながら外れてしまいましたが、まあでも結構いい線いっていたほうでしょうか?


Sorry, your browser doesn’t support WGo.js.

私は今日、天頂の囲碁3に手を入力しながら観戦していたのですが、かなり最初の方から形勢はAlphaGoがいいと言い続けていて、コンピュータ同士気が合うのか面白いなと思いました。最後の方の石田先生が首をひねっていた手などは、例のモンテカルロ特有の緩みだと思われますので、そういう意味ではまだもっとやれるのでしょう。とはいえ、今日の一局でセドル先生もAlphaGoに対して変な恐怖心は無くなったのではないかと思うので、AlphaGoの5-0は相当難しいように感じます。あまりあの人をなめないほうがいいです(笑)。

あと一点だけ気になったのは、対局者の手前に置かれたパネルに国旗が表示されていたり、YouTubeの放送の対局前の映像がこんなだったりと、イギリスvs韓国というのを強調していたことです。

これは、Googleが極度にコンピュータvs人間という構図になるのを避けたかったからなのか、(別の参加者の?)別の思惑があったのか、ちょっと興味深いところです。とりあえず、あきらかな意図は感じました。

COSUMIへのアクセスも一日中物凄いですが、とりあえず今のところは耐えています。さっき、COSUMIが「新参者を返り討ちにしてやる」と生意気なことを言っていたので、みんなでぼこぼこにしてあげてください(笑)。

[追記 2016/3/9 23:45]
22:45。また報道ステーションみたいです。

ただ、この時間帯が今日一日の中で特別多かったってことはなくて、対局開始からこの時間まで、平均して500はありました。Google Analytics使ってない人には伝わりにくいかもしれませんが、これかなりすごいです。

[追記 2016/3/10]
第2戦も黒番AlphaGoの中押し勝ち。個人的には昨日より今日の方が衝撃的でした。AlphaGoは間違いなく本物ですね…

私は今日も、天頂の囲碁3に手を入力しながら観戦していたのですが、やはり結構最初の方からAlphaGo持ちだと言い続けていました。強いのか、AlphaGoと気が合うだけなのか、いまいち判断ができません。

今回、セドル先生の前に座ってAlphaGoの手を打っているのが、Aja Huangさんですね。対Fan Hui戦の時も、映像をよく見るとAjaさんが担当されているようです。この方、碁がめちゃくちゃ強いんですよね。手つきが怪しいのは、こういう場合セドル先生的にちょっといやだと思うので、適任者なんでしょう。Ajaさんが昔作っておられたEricaというソフトがコンピュータオリンピックで優勝し、エキシビションマッチで藤沢里菜三段と対局することになった時、「尊敬する秀行先生のお孫さんと対局できてとてもうれしい」いう旨のコメントをされていた記憶があるのですが、セドル先生と碁盤を挟んで座り、こんな大きな対局を行うっていうのは、一体どんな気持ちなんでしょうか?

[追記 2016/3/12]
今日もAlphaGoの勝ち。もう怖いです… この感じだと、Zenはレートで500どころか1000でも足らないんじゃないでしょうか?

[追記 2016/3/13]
今日はイ・セドル九段の勝ち。セドル先生が0-5はちょっとなあと思っていたので良かったです。ただ、AlphaGoが暴発するのがなんか早過ぎないですかね? それだけちゃんと先が見通せているだけなのかもしれませんが、ボロ勝ちさせようと、「今日はコミが20目だからね」と言われていたりはないですよね?(笑)

[追記 2016/3/18]
第5局はAlphaGoの勝ち。通算成績はAlphaGoの4勝1敗でした。もうすでに今後のAlphaGoの動向が気になってしかたありません。

今回のAlphaGo騒動で、COSUMIへのアクセスもすごいことになりました。とりあえず、今年に入ってからのアクセスの推移です。中央やや左が最初にAlphaGoの話が出てきた時で、右端が対セドル戦です。

次に英語ページ限定で。

どんなグラフが今回のすごさを一番理解してもらいやすいのかよく分からないんですが、例えばこんなのはどうでしょう? COSUMIスタート時からの約8年間のアクセスの推移です。一番右端がおかしなことに…

3月14日月曜日(ちなみにこの日は、第4局と第5局の間の日で対局は行われていません)の238,901pvという数字は、今後、記録更新することができないと思われます(とか言っていたら、井山七冠がぶち抜いたりして…(笑))。この後の推移もまだ気になりますし、このあたりの数字はCOSUMIがどうとか抜きに、もうほとんど歴史的資料なので、またこのブログで後日談が書けたらと思います。

COSUMIのサーバは、今日も元気よくロードアベレージが200を超えたりしてますが(笑)、基本的にずっと問題なく動いてました。良かったです。ただ今後は、9路盤のレベル5などをサーバに負荷が掛かっている時間帯に対局が開始できないようにするなど、なにかしらの対策が必要ですね。最初からやっとけよって感じで、今までちょっとずぼら過ぎたような気がします。

COSUMIに最大何目差で勝つことができるか? その2

[以前の関連記事] : COSUMIに最大何目差で勝つことができるか?

以前、「COSUMIに最大何目差で勝つことができるか?」という記事を書いたのですが、その時は15路盤までだったので、再度、19路盤でも調べてみました。

囲碁ブラウザゲーム COSUMI
http://www.cosumi.net/

調べたのは、直近約3ヶ月の対局のみ。まずは互先から調べてみましたが、COSUMIの石を全滅させた対局が何局かありました。その中で一番大差で勝っている対局は、夢の400目(?!)オーバーを達成されています。


Sorry, your browser doesn’t support WGo.js.

GNU Goが謎です…(地の計算も1目ずれてる(笑))

続いて、COSUMIに9子置かせた対局です。これは全滅させた対局は無いようです。それではベスト3を順に紹介していきます。まずは第3位、284目勝ち。


Sorry, your browser doesn’t support WGo.js.

最初に7回パスしているので、実質16子局(!)になっています。凄過ぎです。

次に第2位、290目勝ち。


Sorry, your browser doesn’t support WGo.js.

そして第1位、315目勝ち。


Sorry, your browser doesn’t support WGo.js.

うーん、GNU Goはもうちょっとがんばったほうがいいね(笑)。

衝撃のAlphaGo

「今年のUEC杯はすごいよ。保木さん、山本さん、西海枝さんのコンピュータ将棋開発者組に加えて、あのFacebookもいるよ!」って感じのブログ記事書こうかと思っていたら、とんでもないニュースが飛び込んできました。

Google Japan Blog: AlphaGo: マシンラーニングで囲碁を
http://googlejapan.blogspot.jp/2016/01/alphago.html

AlphaGo | Google DeepMind
http://www.deepmind.com/alpha-go.html

いろんな情報が一気に出てきて、把握できていないことも多いのですが、すごく簡単に書くと、

  • Googleが開発した囲碁ソフト「AlphaGo」が、ヨーロッパチャンプに互先で5戦5勝
  • 他の強豪ソフトに対しても、495戦494勝!
  • 今年3月に、イ・セドル九段と対決。賞金100万ドル。たぶんYouTubeで生で見れそう

今回、AlphaGoと対戦したFan Hui二段は、Remiさんのレーティングによると、阿部良希初段髙嶋湧吾初段後藤俊午九段万波奈穂三段あたりと同格で、イ・セドル九段とのレートの差は599。現時点では、まだAlphaGoはトッププロの域に達していないのではないかと私は思っているのですが、大橋先生曰く、「3月はあぶないそうです。なんだか、たった一日で世界が変わってしまいましたね…

COSUMIも今日は本当に大盛況で、アクセス数の最高記録を大幅に更新することは間違いありません。特に海外からのアクセスがすさまじく、中でもアメリカ、イギリス、カナダ、オーストラリアなどの英語圏が相対的に多いですね。一次ソースが英語だと、こんな感じになるんですかね? 英語圏の人に刺さりやすい話題だってことは、特にないですよね?

あと、ここ最近COSUMIのレスポンスが悪い時間帯が多くて申し訳ありません(たぶん今日はひどかったですね…)。理由は分かっていて、サーバのリソースが足りていない訳ではなく、ウェブサーバの設定が悪いだけなのですが、このとおり24時間ものすごいアクセスなので、直すタイミングが無くなってしまいました… 適当な時を見計らって直しますので、もうしばらく我慢していただけたらと思います。

最後にAlphaGo vs Fan Huiの全5局の棋譜を置いておきます。


Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

Sorry, your browser doesn’t support WGo.js.

[追記 2016/1/28]
なにこれ…(絶句) 22:55ぐらいです。報道ステーションらしい。ルール解説のページだけで457。しばらくこんなのが続くのか…

[追記 2016/1/30]
書き忘れたこととか、後で知ったことなど書いていきます。

このペーパーがとても面白いので、がんばって読んでみるんですが、対Fan Hui戦は、公式には5勝0敗ですが、それ以外に非公式な対局が5局行われていて、結果はAlphaGoの3勝2敗だそうです。この非公式な対局は、3 periods of 30 seconds byoyomi のみの時間の短かい碁だったみたいですね。このあたりをどう見るのか… そして、Ericaの作者、Aja Huangさんのお名前を発見! DeepMindでお仕事されているんですね。あんなに強いソフトを作っておられたのに、もうやめちゃったのかと勝手に思っていました。私が知らなかっただけのことですが、なんだかちょっとうれしかったです。

対イ・セドル戦は3月8日~15日に行われ、先に3局勝った方が勝ちの5番勝負と言うことですが、途中の結果にかかわらず5局全部打つらしいです。セドル先生の対コンピュータ戦が5局も見れるなんて本当に夢のようですね。結果の予想については、当初、私はセドル乗りだったのですが、いろいろ考えているうちになんだかイーブンな気がしてきました。とりあえず5局も打ったら相当な確率で1発入りそうな気がします。そしてもし本当にそうなれば、まさに歴史に残る大偉業と言えるでしょう。しかし、3月8日~15日ってUEC杯の前に差し込んでくるんですね(笑)。なんか「UEC杯が霞んだ」みたいなこと言う人が多いですが、実際は、UEC杯と電聖戦はそれはそれでかなり面白いと思います。

ここからしばらく、囲碁関係の大きな話題が続きそうなので、私はCOSUMIが安定して動きつつけるようにだけはがんばってみます。ひとまずウェブサーバは新しい設定で再起動したので、今はサクサクかな?

[追記 2016/2/7]
対セドル戦の日程は、3月9日、10日、12日、13日、15日と決まりました。もう、ほんの一ヶ月後のことですね。もしタイムマシンがあったら、一ヶ月前に戻って「二ヵ月後、100万ドルを賭けた、コンピュータとセドルの5番勝負があって、戦前の予想はけっこう拮抗してるよ」って言って回りたいですね(笑)。まあ、誰も信じてはくれないでしょう。私が思うに、このタイミングでのAlphaGoの出現って、いわゆるブラックスワンじゃないかと。2016年(違った。2015年だった)にAlphaGoが存在していることを、「予測可能だった自然なもの」として受け止め始めている世間(もしかしたら私も)の現状に、なんというか軽い狂気を感じます。

もう一方のZenはというと、4子で伊田先生に勝ったようです。

[追記 2016/2/7]
今年に入ってからの、COSUMIのアクセスの推移です。まずは全体。

そして、英語ページ限定。

どーんと来た後、元の水準まで完全に戻りきらなかったことは、今までちょっと記憶にありません。AlphaGoは囲碁普及に大いに役立ったのではないでしょうか?

COSUMIに纏わる数字の話

COSUMIを始めて7年ちょっと経ちました。今では、当初は想像もしなかったようなたくさんのアクセスがあって、本当に驚くばかりです。Googleで「囲碁」という単語で検索しても、当然環境には左右されるのですが、一番上に表示されることが多くなり、そうなってくると、もはやCOSUMIの様々な統計情報も、自分で眺めてニヤニヤするだけではなく(笑)、囲碁普及に努めておられる方々と、ある程度共有していかないといけないような気がしますので、今日はCOSUMIに纏わるもろもろの数字を、まとめて公開していきたいと思います。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

今回の記事はかなり長めになりますが、いきなりハイライトです(笑)。Google Analyticsでの平均セッション時間、直帰率、新規セッション率がとにかくすごいです。

平均セッション時間 12分9秒
直帰率 37.17%
新規セッション率 14.77%

(データは直近一ヶ月)

これから分かることは、「COSUMIはアブノーマル。でもたぶん嫌われてはいない」(笑)。アクセスがそれなりにあって、こんな数字になるサイト、実際のところ他にどれだけあるのでしょうか?

次は、COSUMIが打っている手数(ユーザが打っている手数は含まず)です。これも現在なかなかどえらいことになっていて、例えば、6/28~7/4の7日間では計26,386,121手でした(実際はもうほんの少しだけ(1%以下)多いですが、正確にカウントできるのだけに限定しました。以下、COSUMIが打った手数についてはすべて同じ)。平均して3,769,446手/日、157,060手/時間、2,618手/分、43.6手/秒になります。同じ期間中の、1分単位で見た一番のピークは7/4(土)の17:46台で、4,854手/分、80.9手/秒。COSUMIが手を打った後、同じ対局の次の手を打つまでの間隔(要するに黒白1手ずつ計2手対局が進む時間)は平均10秒ぐらいなので、このピーク時は800面打ち(!)ぐらいになっている計算に…(いや、何て言うか、囲碁が不人気だとかオワコンだとか、絶対嘘でしょ?(笑)) あと、COSUMIの2台のサーバもちょっとすごい。1台で400人相手できるとか、なんかもうかっこいい。現在メインで使用しているサーバはレンタル開始から2年半ぐらいになりますが、歴史上、囲碁の手を一番たくさん考えたコンピュータじゃないかと、本気で思っています(笑)。

続けてCOSUMIが打っている手数を時間帯別に見ていきます。次のグラフは7/1(水)の0時~24時の24時間を1分単位で見たものです。

典型的な平日の推移となっていて、昼・夕方・夜の3つの山が確認できると思います。その中でも、特に注目していただきたいのは、昼の山(ピークは12:41台)で、このいかにも「隙間時間に何とか碁を打ちたい」って感じは、これからの囲碁普及の結構重要なポイントではないでしょうか? 時間さえ許せば、みんなきっと碁を打ちたいんだと思います。

さらに今度は碁盤サイズ・レベル・置石の数などの対局条件別にCOSUMIが打っている手数を見ていきます。次のグラフは、6/28~7/4の7日間のデータです。Lはレベル、Hは置石の数、Hの後の-(マイナス)はCOSUMIが石を置いていることを意味します。ちょっと見にくいかもしれませんが、グラフをクリックしていただくと、たぶん大きく表示されます。

ひとつだけ、なんだかおかしな数字になっている項目があるので、スケールを変更したグラフも用意しました。

実は今回いろいろ調べていて、一番驚いたのがこの数字です。見ていただいて分かるとおり、19路盤の互先がなんかもうよく分からないぐらい多いです。19路盤が多いと言うのは、ある程度分かっていましたが(それも正直想像以上ですが…)、それはともかくとして、互先と置き碁にこんな差があるというのは、今の今まで全く知りませんでした… 15路盤にも全く同じ傾向が見られるのですが、これはCOSUMI固有の現象なのでしょうか? それとも、みんな置き碁が好きではないのでしょうか? 9路盤~13路盤では、レベルが一番低いのと一番高いのが人気なのが見てとれると思いますが(個人的には、これは理解できます)、それと比較すると、ちょっと異様な感じがします。あと、9路盤・13路盤・19路盤という昔からよく打たれていた碁盤サイズの手堅い人気も見てとれます。11路盤・15路盤は、打てる環境が無いから打たないのではなく、打つことができても打たないのですね。とは言え、その大本の原因は、「元々打てる環境が無かったから」でしょうから、これから時代が進むにつれ、このあたりも少しずつ変わっていくのでしょうか? ちなみに、大きな碁盤サイズの方が、一手に掛かる時間が短い傾向がありますが、程度としてはあまり大きなものではないので、「COSUMIが打った手数」を「ユーザが対局している時間」に置き換えて上のグラフを見ていただいても、特に問題はありません。

今回調べていて、もうひとつ初めて気がついたことがあります。それは、囲碁のルール解説のページ(http://www.cosumi.net/learn.html)へのアクセスが、日曜日だけ少し多いということです。ある程度落ち着ける休日に、新しい趣味を始めたいのかもしれませんし、それならそれで感覚的にも分からなくはないですが、しかし、土曜日は特にアクセスが多かったりはしませんね。日曜日ですか… これは怪しいですね(笑)。ということで、6/28(日)~7/4(土)の7日間を1時間単位で見たグラフを用意しました。比較対象としてFlash版の囲碁対局ページ(http://www.cosumi.net/play.html)へのアクセス数に[learn.htmlへの7日間の総アクセス数/play.htmlへの7日間の総アクセス数]を掛けたものも表示しています。

日曜日のお昼がおかしいですね。ピークは13時台、その次は多いのが12時台。もうお分かりだと思いますが、NHKの囲碁の時間ですね。先ほど、初めて気がついたと書きましたが、今まで、NHKの囲碁の時間の影響を気にしたことが無かった訳ではありません。むしろとても興味のあるところなので、今まで何度か調べてみたことはありましたし、その上で特に大きな影響は無いんだなと判断していました。実際、囲碁対局ページへの影響は特にあるように見えませんし、これは囲碁のルール解説のページだけに顕著なようです。あの放送を見て、囲碁に興味を持つような人が毎週毎週これだけいるのならば、この人たちを丁寧に掬い上げてあげられたら、それだけで囲碁人口は結構増えていきそうなものですが… 個人的に面白いなと思うのは、テレビを見て囲碁に興味を持った人って、ほとんどリアルタイムでウェブ検索するんですよね。今の人って、「後で、誰かに聞こう」とか、「今度、本を買ってこよう」とかではなく、「今、ぐぐってみよう」になるわけで、ウェブ上に、しっかりとした入門者向けのコンテンツがあるというのは、当たり前のこととはいえ、ものすごく大切なことだと思うのですが、しかし実際は、今ある囲碁関連のウェブコンテンツって、ものすごくしょぼく感じます。いや、本当に「お前が言うな」ですけど(笑)、もうちょっと何とかならないでしょうか?

次は、モバイル関連の話です。Google Analyticsでの全セッションに対する「デバイス カテゴリ」ごとの割合はこんな感じ。

desktop 78.26%
mobile 15.66%
tablet 6.08%

(データは直近一ヶ月)

そうなんです、モバイル端末からのアクセスがちょっと少ないです… たぶん、「囲碁のゲームがやりたい」ってなったら、ウェブなんか調べず、アプリを探すんでしょうね。囲碁のゲームぐらいネイティブアプリじゃなくてもと、私なんかはつい思ってしまうのですが、うーん、これはどうしたものか…

次は、国別の利用状況です。Google Analyticsでの全セッションに対するアクセス元の国ごとの割合はこんな感じ。

日本 81.90%
中国 7.37%
アメリカ 4.20%
韓国 2.06%
カナダ 0.66%
台湾 0.37%
オーストラリア 0.30%
イギリス 0.28%
香港 0.19%
ドイツ 0.18%

(データは直近一ヶ月)

意外に思われるかもしれませんが、海外からのアクセスも決して少なくありません。中国からは結構以前からアクセスが多かったのですが、ここ最近は他の海外の国からのアクセスが増えました。とは言え、海外からのアクセスは伸び悩んでる感じもあって、ちょっと寂しいです。伸び代はまだまだあるはずですが…

ということで、たくさん調べて、たくさん文章書きました。うーん、疲れた…

[追記 2015/7/12]
iPadだけとiPhoneだけに限定した、対局条件別のCOSUMIが打っている手数のグラフも作ってみました。期間は6/28~7/4の7日間。まずはiPad。

そしてiPhone。

タブレットなら碁盤サイズを好きに選べるけれども、スマホではさすがに19路盤は厳しいということでしょうか? スマホを触っているときはあまり時間が無いってこともあると思います。

悪手の指摘が少し正確になりました

COSUMIの5路盤~9路盤(レベル0)の対局リプレイでは、ユーザの打った悪手を指摘する時がありますが、これが少しだけ正確になりました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

今までは、Fuegoに初手から調べさせて、ユーザから見たwin rateが下がったところを悪手としていました。ただ、これだと勝っている局面で、不必要な手入れをした方がいいと言うことがたびたび起こり、ちょっとみっともないことになっていました。そこで、今度からはさらにGNU Goの意見も聴くようにし、GNU Goが「確かにFuegoの指摘する手の方が得だ」と判断しないかぎり、COSUMIとしてはその手を悪手とは指摘しないようにしました(実際は、今までも今現在も、そこまで単純ではありませんが…)。

例えば、次の棋譜は実際にCOSUMIで打たれたものですが、最後に2回、自陣に手を入れろと指摘が入っています。Fuego的にはそうした方がだいぶwin rateが高くなるようですが、正しくはこれらの手は不必要な手入れであり、かなり問題のある指摘になっています。逆に、GNU Goはこういうところであまり不正確にならないので、Fuegoの主張をいい感じに却下してくれます。という訳で、今現在は、同じ棋譜の対局が行われても、悪手の指摘はしなくなっています。

[9路盤 レベル0] 黒(You)12目勝ち – オンライン囲碁ゲーム COSUMI

今回は同時に、Fuegoが悪手と判断する基準も緩くしたので、COSUMIが悪手とする回数自体はあまり変わっていないと思います。

ということで、今回の変更でなかなか良くなったのではと思っているのですが、サーバの負荷がしゃれになっていないので、これから何とかチューニングしてみます。なんだったら最後はお金の力で…(笑)

チャレンジモード

COSUMIに、勝敗に応じて段級位が昇降格する「チャレンジモード」というのを作ってみました。

チャレンジモード
http://www.cosumi.net/mobile/challenge.html

COSUMIでは初めて、持ち時間のある対局ゲームとなっていて、方式は個人的に大好きなフィッシャーです。囲碁ではこれに限ると思っています。対局条件やコンピュータの強さは、もしかしたら比較的早い時期に微調整するかもしれません。もうあまりFlashはやりたくないので、今回はHTML5版のみです。

間接的にでも、他の人と競えたら面白いかなという発想で作ってみました。ぜひ、家族や友達といっしょに挑戦してみてください。

[追記 2014/11/2]
現時点では、六段になった人がまだいないみたいです。実際、そこまで難しくはないと思うのですが、必要があれば対局条件などを微調整したいと思います。

[追記 2014/11/9]
とりあえず六段になられた方はいるみたいなので、上の方はもういいかなと思うのですが、十五級の人の作り碁になった対局の勝率が62%程度しかなく、こっちはちょっとまずそうです… ということで、十五級はコミ15目ではなく20目でスタートとし、そこから十級まで、級位がひとつ上がるごとに2目ずつ減っていくということにします(そこから上は今までどおり)。対局条件などを変更することは、おそらくもうありません。

変更前までの、それぞれの段級位の人が打った、作り碁になった対局の数のグラフを載せておきます(作り碁だけに限定しているのは、それがすぐに調べやすかったからです。それ以外の理由はありません)。

どんなに強い人でも最初は十五級ですから、左側のボリュームが大きくなるのは当然です。またさらに、強い人ほど負けている碁を作らないで投げる割合が多そうですので、だとすればこれも右側のボリュームが減る原因になります。というようなことを考慮しつつ見ていただくとして、やはり気になるのは、二級をピークとした小さな山ですね。まあ、ここが平均的な囲碁プレーヤーなのでしょう。ざっくり言って、COSUMIのチャレンジモード二級は、KGSで同じく2kぐらいでしょうか?

[追記 2015/3/26]
ちょっと気になったので、もう一度、最初から現在まで全期間のデータでグラフを作ってみました。

やはり、ピークは二級ぐらいのようです。

置かせ碁

COSUMIの15路盤と19路盤で、相手に石を置かせた対局ができるようになりました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

COSUMIがもっと強くなるのが本当は一番いいのですが、15路盤と19路盤ではもうそれはちょっと無理だと思うので、こういう形でお茶を濁しておきます。

祝1000万敗!!

COSUMIが1000万敗を達成しました!

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

もう何を見ても驚かなくなりました。とりあえず続けてさえいれば、1億敗だってありうるんじゃないかという気にすらなっています…(笑)

今日のGoogleトップページのロゴは本因坊秀策です

今日のGoogle(google.co.jp)のトップページのロゴは本因坊秀策です。

https://www.google.co.jp/

最初見た時、碁石の意味するところがすぐに分からなかったのですが、普通に「Google」でした(笑)。どうしても、「Go」の部分が瞬時に「碁」に変換されてしまって… しかし、そうなると秀策と碁盤を、「Google」の4文字目のgに見立てていることになりますが、いつも感じますがちょっと無理筋ですねえ… 碁盤の上で、初手の小目から最後は「秀策のコスミ」までがアニメーションで打たれるのですが、「秀策のコスミ」は7手目で、それがアルファベットで7番目の文字、gを表しているということかもしれません。

さらに、本当に毎度のことですが(笑)、すばやくCOSUMIのアクセス解析もチェックしてみると、英語ページへのアクセスが見たことない数字になっています(それ以外も多め)。てっきり日本だけでの表示だと思い込んでいたので少しびっくりしたのですが、こちらのページに今回のDoodleの詳細が載っていて、表示地域は日本、台湾、インドネシア、ラトビア、ウクライナ、ギリシャ、ドイツ、アイルランド、ポルトガル、コロンビアとなっています(たしかにこれらの国々からのアクセスが多い)。もう少し多くの地域で表示してもらえたら、囲碁の普及に大変役立ったのではないかと思うと同時に、どのような理由で、これらの国々だけに限定されているのかという疑問も少し湧いてきます。

[追記 2014/6/10]
6月1日から6月9日までの、COSUMI全体のアクセスの推移です。

そしてこちらが、英語ページのアクセスの推移です。

11路盤にレベル4を追加しました

COSUMIの11路盤に、レベル4の強さ設定を追加しました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

9路盤はレベル5、11路盤はレベル4、13路盤はレベル3までという現状は、かなり限界に近いです。少なくとも当面の間は、これ以上はありません。

FAQページを用意しました

このブログのコメントや、その他ネット上でよく見られるCOSUMIに関する質問に対する回答ページを用意してみました。

よくある質問 – オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/faq.html

このブログにご質問いただける場合は、事前に一度、こちらに目を通していただけるとありがたいです。

COSUMIで打たれた9路盤の棋譜を公開します

COSUMIの9路盤レベル5の対局の内、ユーザが勝った棋譜を、黒番白番それぞれ5000局ずつ、計10000局分公開します。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

人間が打った9路盤の棋譜を大量に入手するのは、意外と難しいように感じたので、なにかの役に立つかと思い公開することにしました。大量の棋譜をひとつのSGFファイルにまとめたら面白いかなとか、Fuego使って名局を探してみようかなとか、以前ちょっとだけ考えたことがあるんですが、なかなか腰が重くて未だできてませんので、もし誰かがやってくださるとうれしいです。もちろん、マンパワーで「COSUMI名局100選」を選出していただいても(笑)良いと思います。

今回公開する棋譜は直近の対局分なのですが、具体的にはだいたいここ20日間ぐらいの間に打たれたものになります。

http://www.perfectsky.net/misc/cosumi_9x9level5.zip

少し話は変わりますが、以前にも書いたとおり、白番よりは黒番持った方がほんの少し勝ちやすい傾向が今もあるようです。

[追記 2014/1/13]
公開した棋譜を少し眺めていたんですが、かなり頻繁にGNU Go先生が終盤でファンタしてますね(笑)。まあこれは、以前から分かってたことではあるんですが、でもこんなに多かったかなあ? ということで、少し調べてみることにしました。

COSUMIの9路盤レベル5では、まず独自のオープニングブックを使い、それが切れると38手目までFuegoが打って、その後GNU Goが終局まで打ちます(とは言っても、実際はいろいろ例外があります)。それを踏まえて次のグラフを見てください。

今回公開した棋譜の内、ユーザが黒番だった対局の、総手数が50手以上の対局(4202局)の30、34、38、42、46手目終了時点の形勢を、Fuegoを使って調べてみました。win rateが100%に近いほど黒番の人間ユーザが優勢ということになります。

まず驚くのは、34手目終了時まではやや左に偏っていることです。9路盤で34手目といえばだいぶ後の方ですが、ここから最終的には右端に張り付くんだと考えると、これはかなり特異な印象を受けます。そして、その前と比較して、38手目終了時以降は急に差が大きくなっているような気がしますので、これはやはり、GNU Go先生はファンタジスタと言わざるを得ませんね(笑)。個人的には46手目終了時のグラフを見ただけでも、ちょっと悲しくなります。30%以下からなんて、普通はそこからひっくり返らないんですが…

Fuegoにヨセを打たすとかなり不自然になるのでGNU Goを使っている訳ですが、GNU Goの手を一度FuegoでチェックしてだめそうならFuegoが打つとかは、した方がいいかもしれません。一番いいのは、GNU Goが後ほんの少しでいいので、強くなってくれることなんですが…

[追記 2014/1/14]
昨日のグラフに、10手目と20手目終了時点の形勢も調べて追加してみました。

さらに9路盤のレベル1も調べてみました。レベル5と同じくユーザが黒番で勝った直近の対局5000局の中から調べたのですが、総手数がレベル5の時より大幅に短いものが多いので(碁盤を真っ二つに分けたような分かりやすい対局が多いんです)、総手数は50手以上ではなく40手以上の対局(それでもたったの2217局しかありません)としました。ちなみに、レベル1ではまず独自のオープニングブックを使い、それが切れるとそこから終局までGNU Goが打ちます。要するに、レベル5のFuegoが打っているところをGNU Goが打つのと同じことになります。

うーん、これが普通だと思います。レベル5の方はちょっと問題がありますね…

ただの碁盤

単純に石を順番に碁盤の上に並べていくことができるだけの、「ただの碁盤」を作ってみました。

ただの碁盤 – オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/mobile/goban.html

COSUMIに再利用できそうなコードがたくさんあったから作ってみました。というか、COSUMIで使っていたコードを削り倒しただけです。友達が「囲碁のルールを教えて」って言ってきたけど、手元には囲碁アプリなんか入っていないタブレット端末しかないって時にでも使ってみてください。

Flash版は無し。HTML5版のみです。使える時がかなり限定される、機能の少なさですが、これ以上作り込む気はありません。

9路盤に対局条件が定先のレベル0を追加しました

COSUMIの9路盤に、対局条件が定先のレベル0を追加しました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

「9路盤はレベル1でもそこそこ強いです。ルールを覚えたばかりの方は、5路盤から順にやってください」っていうのが、COSUMIのスタンスなんですが、「初心者は9路盤から」(多くの場合、その意味は「初心者は小路盤から」のような気もしますが…)と他の人に言われているからか、ルールがあやふやな状態でも9路盤から始める人が多いように感じたので、それに対する簡易な対策です。

この9路盤のレベル0では、8路盤以下と同様に悪手の指摘をするようにしましたが、はっきり言って精度が悪いです(この辺りのこともあるので、初心者の方には8路盤以下をしていただきたかった/していただきたい)。そしてサーバ的にもめちゃくちゃ重いです。精度に関しては、今後の課題とさせてください。今はwin rateの推移を見てるだけって感じなんですが、何目ぐらい損したかって観点も絡めないと、どうも不自然になってしまいますね。

COSUMI 5周年

COSUMIをスタートさせてから、今日で5年になります。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

この5年間の、1日あたりのCOSUMIが負けた数の推移はこんな感じ。

中央付近で0になっているのは震災の時に一時止めてたからで、最後のほうでぐっと伸びているのは19路盤をメインの対局ゲームに統合したからです(メインの対局ゲームの負けた数しか数えていません)。この数が増えていくのが、私にとって一番うれしいことです。なので、これからもみなさんどんどん負かしてください(笑)。トータルでは今現在4,620,131敗です。ものすごい数ですね…

当然のことながら、COSUMIが打っている手の数もものすごいことになっていて、1日あたり約1,900,000手ぐらい。平均して、79,167手/時間、1,319手/分、22手/秒(!)ぐらいになりますね。以前から漠然と思っていたのですが、今までGNU Goが生成した手(これを正確に定義するのはちょっと難しいんですが…)のほとんどは、「COSUMI上で」ではないかなと思っています。もしそうだとすれば、COSUMIは「GNU Goというすばらしいソフトを世に広めるのだ」と作り始めたサイトですので、こんなにうれしいことはありません。

COSUMIを最初に作っていたのが、本当に昨日のことのようです。もちろん、あの時は5年後にまさかこんなにたくさんの人に遊んでもらえるようになるとは思っていませんでした。どちらかというと、あの時はウェブサイトが完成しない可能性を心配していたのですが…(笑) 今まで、COSUMIで遊んでくださった方々、本当にありがとうございました。すばらしいソフトウェアをこんなに自由なライセンスで公開してくださっている、GNU GoとFuegoの開発者の方々にも改めてお礼申し上げます。あと5年はCOSUMIを続けていると思うので、その時どうなっているのか今から楽しみです。

[以後の関連記事] : COSUMI 10周年
[以後の関連記事] : COSUMI 15周年

jQuery 2.0を使い始めます

COSUMIのHTML5版ではjQueryを使用しているのですが、先日正式にリリースされたバージョン2.0に切り替えました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

jQueryは現在、1.9系と2.0系という2つの系列があって、1.9系が通常版で2.0系がIE6~8に非対応なスペシャル版的な位置付けになっているんですが、COSUMIのHTML5版はもともとIE6~8では動かなかったので、割り切って2.0系を使い始めることにしました。たぶん、なんの問題も発生しないと思いますが、なにかあってもすぐに直せると思います。

オンライン囲碁ゲーム GUZUMI

COSUんでばかりではつまらないので、昨日はGUZUんでみました。

黒番、黒番、黒番、黒番、また黒番…

COSUMIの囲碁対局ゲームで、1局目の自分の石の色が、ページをリロードなどしない限り、2局目以降もずっと続いたり、1局目で白番が当たった後、8路盤以下や置き碁など自分が必ず黒番になる対局を行おうとするとエラーが発生してしまうバグを修正しました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

このバグは、Flash版では先日19路盤をメインの囲碁ゲームに統合した時から、そしてHTML5版では最初からずっと(←おいっ!)あったようです… ほんとひどいですね。ごめんなさいです。

COSUMIのサーバを交換しました(4回目)

一昨日、COSUMIのメインのサーバを新しいのに交換しました(変えたとたん、ハードウェアの障害でさんざんでしたが、たぶんもう大丈夫です)。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

新しいサーバは、「さくらの専用サーバ」のエクスプレスG2シリーズの一番高いやつ。Xeon E5-2670が2発のモンスターマシンで、/proc/cpuinfoがすごいことに…(笑)

$ cat /proc/cpuinfo | grep processor | wc -l
32

COSUMI的な性能は、以前のと比べて2.5倍ぐらい。今回のサーバは5代目なんですが、初代との比較なら100倍(!)ぐらい速いんじゃないでしょうか?

なぜここまでのスペックが必要になったかというと、それはもうすべて9路盤Level5のせいです(笑)。さすがにちょっと調子に乗りすぎました…

今までは専用サーバ1台、VPS4台だったんですが、これからは専用サーバ2台でやっていく予定です。

現在COSUMIが止まっています

ごめんなさい。今のところ、いつ復旧できるかわかりません…

[追記 2013/2/6 9:30]
復旧しました。5日22時ぐらいから6日9時15分ぐらいの間止まってました。サーバのハードウェアの障害です。また今夜メンテナンスで少し止めます。

一昨日の「情熱大陸」は井山裕太五冠でした

[以前の関連記事] : タモリ倶楽部がCOSUMIにたくさんの人を連れてきてくれたかもしれない

この手の話大好きなので、またさせて頂きます(笑)。

一昨日の13日、TBS系列で放送されているテレビ番組「情熱大陸」で、井山裕太五冠が特集されていました。事前に井山先生が出演されるのを知っていたので、とても楽しみにしていたのですが、放送終了後すぐに、こちらもちょっと楽しみにしていた(笑)COSUMIのアクセス状況を確認したんです。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

いやー、びっくりしましたよ。Google Analyticsのリアルタイムのアクティブユーザーが300オーバー!(200オーバーはちょくちょく見るのですが…) ただ、通常はこの数字が200を超えるとサーバ負荷が危険な状態になるので大急ぎで確認しましたが、そっちはぜんぜん大したことはなかったです(これは対局している人が多くないことを意味します)。そして、10分そこらでまた200を切ってました。普段は決して多くないトップページ囲碁のルール解説のページへのアクセスが、とても多かったですね。

13日~14日のアクセスの推移です。もう一目瞭然です。

あと、1日単位で見たアクセス数で14日(13日ではなく)が過去最高でした。これについては、今回の放送との関連がいまいちはっきりしません。

COSUMIは数ある囲碁関連サイトの中のひとつにしか過ぎないわけで、そう考えるとなんかすごいですね。NHK杯だとかヒカルの碁だとかではなく、いつもは囲碁の話が出てこないテレビ番組で囲碁の話が出てくると大変なことになりやすいようです。

[追記 2013/1/15]
14日のアクセスが多い理由、今気づきました。大雪の影響です。まず間違いありません。COSUMIは以前から台風の日にアクセスが多い傾向がありましたが、それと同じことだと思います。ちなみに、今までで一番アクセスの多かった日は去年の9月30日だったのですが、この日も台風だったようです。

[追記 2013/1/16]
昨日書き忘れましたが、14日のアクセスの多さが大雪だったからだと気づいたのは、パズドラが(おそらく大雪の影響で)ダウンしたというニュースを見たからです。暇つぶし系は、基本的にどこもこういう傾向があるんだと思います。

[追記 2013/1/22]
井山先生は、先週金曜日のNHKのニュースウオッチ9でも特集されていたようです。

史上初 囲碁六冠に挑む | NHKニュースウオッチ9 ピックアップ
http://cgi2.nhk.or.jp/nw9/pickup/index.cgi?date=130118_1

ということで、18日~19日のアクセスの推移です。

情熱大陸ほどではないですが、これも結構すごく思えます。

WebKit系ブラウザでcanvasタグがborder-radiusを無視する時がある

非常にささいな話なのですが、COSUMIの囲碁対局ゲームの碁盤は、ほんの少しだけ角を丸めています。ところが特定の環境では、HTML5版の方の碁盤の角が全く丸くならないことに気づきました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

少し調べたところ、このバグが原因のようです。

css – How to hide canvas content from parent rounded corners in any webkit for Mac? – Stack Overflow
http://stackoverflow.com/questions/10616668/how-to-hide-canvas-content-from-parent-rounded-corners-in-any-webkit-for-mac

要約すると、「WebKit系ブラウザにおいて、指定されたwidth属性とheight属性の積が66000以上のcanvasタグが、border-radiusを無視する時がある」ということのようです。リンク先では「canvasタグの親要素に指定されたborder-radius」という話になってますが、COSUMIではcanvasタグ自体にborder-radiusが指定されています。ちなみに私の環境では、Win7+ChromeとNexus7+Chromeはだめ、iPad3+SafariとiPad3+Chromeは大丈夫でした。

COSUMI側でも簡単に修正することができますが、これは明らかにブラウザ側のバグだと思われますので、とりあえずこのまま放置します。たぶんそのうち直るでしょう。

COSUMIのFlashがきれいに拡大・縮小するようになりました

COSUMIの囲碁対局ゲームでページ全体を拡大・縮小した時などに、Flashががたがたせずに滑らかに拡大・縮小するようになりました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

「なんでこんなにがたがたしちゃうんだろう」と、以前からかなり気にはなっていたのですが、「できることは全部やってるはずだし、こんなものなのかな」と、もうほとんどあきらめてました。ところがここにきて、その理由がわかった!

ActionScript 2.0のMovieClip.attachBitmapメソッドは、4番目の引数smoothingで、画像を滑らかに拡大・縮小するかを指定することができます。この項目は省略可能なんですが、省略した時のデフォルトはtrueだと自分の手元にあった日本語の公式のリファレンスに書いてあるんですよ。で、これが嘘でした…(泣) デフォルトはfalseです。公式のリファレンスにもいろいろなバージョンがあるのかもしれませんが、ちゃっと調べた感じ、英語の方には正しく載ってるみたいなんですけどね。ほんと、なんでこうなるの…

Fuegoの最新開発版が強い

以前からCGOS見ていて思っていたのですが、Fuegoの最新開発版は結構強そうな感じです。ということで、現在COSUMIで試しに使っています。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

使用しているのは、Rev 1604。正式版のバージョン1.1とそれぞれ20k playoutの設定で9路盤の対戦をさせると、勝率約78%。Rev 1604の方のplayoutを6kに絞ると、これでだいたいイーブンです。いい感じですね! COSUMIはできるだけ安全運転・保守的にと、いつも気をつけているのですが、さすがにこれだけ違うと我慢できませんでした(笑)。COSUMIではplayoutを調整したので、基本的に強さはこれまでと変わりませんが、もし安定して動作し続けるようなら、まず9路盤にレベル5を追加して、そのあと11路盤と13路盤もレベルを選択できるようにしたいと思っています。

最新開発版を使ってひとつ気になったのは、Fuego起動時、オープニングブック以外にpatterns9.datpatterns19.datという2つのファイルを読み込むようになっていることです。これはRev 1588で追加された機能のようで、Greenpeepというのはそういう名前の囲碁ソフトのことみたいです。ちなみにpatterns9.datpatterns19.datのファイル名の919というのは、当然のことながら9路盤と19路盤の意味だと思いますが、といっても9路盤専用と19路盤専用ということではなく、15路盤未満はpatterns9.dat、15路盤以上はpatterns19.datを使用しているみたいです。でもって、この2つのファイルの読み込みがけっこう重い… 通常Fuegoは1プロセスで1局とか100局とか打つのが普通だと思うので、そういった場合はほとんど問題にならないんだと思いますが、1プロセスで1手なCOSUMIではちょっと無視できない感じです。無くても大して弱くならないかなと9路盤で「patterns9.datあり」と「patterns9.datなし」を対戦させてみると「patterns9.datあり」の勝率が7割近くなるので(すごい!)、外すわけにもいきません。とりあえず、COSUMIでは使わないpatterns19.datの方は空にしておきましたが、ちょっと頭が痛いです。

[追記 2012/11/19]
9路盤にレベル5を追加しました。

[追記 2012/11/30]
11路盤と13路盤でも、コンピュータの強さが選べるようになりました。

iOS6ではページをスクロール中に発生したタッチイベントからJavaScriptのタイマーがセットされない?

このブログ記事で問題にしているiOSのバグは、iOS6.1ですでに修正されています

– – – – – – –

先日公開したCOSUMIのHTML5版には、「iPad3でページをスクロール中に碁盤や碁盤の周りのクリッカブルな所をタップするとその後の動作がおかしくなる」という不具合がありました。私もいまだによく分かっていないところがたくさんあるのですが、原因とそれに対してとった対策を簡単に書いておきたいと思います(このブログ記事には私の勘違いが含まれている可能性が高いです。すべてを鵜呑みにはしないでください)。

この不具合に気づいた時、まず最初に思ったのは、これはフェードイン・フェードアウトが絡んでいるのでは、ということでした。スクロール中のフェードイン・フェードアウトは、描画がたいへんなのではないかなと。しかし、必ずしもそうだと言い切れないような感じだったので、少しネットで検索してみると、こんな情報が見つかりました。

javascript – setInterval pauses in iphone/ipad (mobile Safari) during scrolling – Stack Overflow
http://stackoverflow.com/questions/11177774/setinterval-pauses-in-iphone-ipad-mobile-safari-during-scrolling

おおこれだと思いました。jQueryの.fadeIn()/.fadeOut()はJavaScriptのsetIntervalを使っているようです。しかしちょっと腑に落ちないのは、なぜタイマーが止まっただけで、その後の動作がおかしくなるのかです。再開さえしてくれれば問題無いはずですが… そこで、もう少し調べてみると、こちらのブログのコメント欄に、ちょっと気になることが書いてありました。

There is one more bug I haven't seen anybody writing about. If a touch event causes a setTimeout, but that same touch event causes scrolling, that timer will never fire.

More information and a workaround here: https://gist.github.com/3755461

あれっ? なんかおかしい… 「止まる」のではなく「発火しない」と書いてあります。そしてリンク先のios6-timers.jsをCOSUMIのに試させてもらうと、不具合が完全に起こらなくなりました。

簡単なサンプルページを用意してみました。モバイル端末から試してみてください。Startボタンをタップすると、赤と青の四角が右に動きます。赤い方はJavaScriptのsetIntervalを使っていて、青い方はCSSのtransitionを使ってのアニメーションです。

http://www.perfectsky.net/misc/20121002.html

<!DOCTYPE HTML>
<html>
<head>
<meta name="viewport" content="width=640px">
<title>iOS6 Timer Test</title>

<style>
div{
  position : absolute;
  left     : 20px;
  width    : 100px;
  height   : 100px;
}
#div1{
  background-color : #ee4444;
  top              : 20px;
}
#div2{
  background-color : #6666bb;
  top              : 140px;
}
button{
  display   : block;
  margin    : 300px auto 0;
  font-size : 200%;
}
</style>

<script src="http://code.jquery.com/jquery-1.8.2.min.js"></script>
<script>
$(function(){

  var pos = 20;

  $("#div2").css("transition", "left 10s linear");

  $("button").on((window.ontouchstart === null) ? "touchstart" : "mousedown",
                 function () {

                   $(this).remove();

                   var timerId = setInterval(
                     function(){
                       $("#div1").css("left", ++pos);
                       if(pos >= 520){
                         clearInterval(timerId);
                       }
                     }, 20);

                   $("#div2").css("left", "520px");

                 });
});
</script>

</head>
<body>
<div id="div1"></div>
<div id="div2"></div>
<button type="button">Start</button>
</body>
</html>

まず最初は、Startボタンをタップして赤と青の四角が右に動き始めたらそこでページをスクロール(ピンチイン/ピンチアウトでもいいです)してみてください。たぶん、両方の四角が停止すると思います。そしてスクロールしていた指を離すとまた動き始めます。これは、iOSやAndoidではよく知られた挙動のようです。

そして次は、まずページをスクロールし、その指を離さないままStartボタンを押して、最後にスクロールしていた指を離してみてください。私の持っているiOS6のiPad3では(SafariでもChromeでも)、下の青い四角は動きだしますが、上の赤い四角は動き始めません。これはどうやらiOS6のバグのようです。そして先ほどのios6-timers.jsを使うとこの不具合は起きません。

肝心のCOSUMIへの対策ですが、最初はjquery.animate-enhanced pluginを使えばそれだけで直るかなと思ったのですが、よくは調べてませんがそれではうまくいかなかったので、最終的にはjQueryの.fadeIn()/.fadeOut()をすべて.show()/.hide()に書き換えることによって解決しました。他にも書き換えないといけないところがありそうでしたが、とりあえずCOSUMIの場合は、すべてjQueryの.fadeIn()/.fadeOut()に絡んでいたようです。ios6-timers.jsの使用は副作用があってもいやなのでちょっと控えました。将来的にはできればもうちょっとましな対策をしたいと思いますが、とりあえず今はこれでいきます。

今回のバグは、ページのスクロール中という限られた状態でしか発生しないためか、当初は全くといっていいほど情報がありませんでしたが、すこしずつ気づいた人がでてきたようです。

javascript – iOS 6 safari, setInterval doesn't get fired – Stack Overflow
http://stackoverflow.com/questions/12683510/ios-6-safari-setinterval-doesnt-get-fired

setTimeout while scrolling in iOS 6 doesn’t work, works in iOS 5 – Google グループ
https://groups.google.com/forum/?fromgroups=#!topic/phonegap/3Xe_M79qHEM

[追記 2013/1/29]
今回のiOSのバグは、iOS6.1で修正されたようです。COSUMIの方もまた今度元に戻しておきます。

[追記 2013/2/7]
.fadeIn()/.fadeOut()に戻しておきました。たったこれだけのことで、リッチな感じになるんですよね。

COSUMIにモバイル端末向けHTML5版ができました

COSUMIに、Flashを使用しないモバイル端末向けHTML5版の囲碁対局ゲームを作ってみました。

囲碁対局ゲーム(モバイル端末向けHTML5版)
http://www.cosumi.net/mobile/play.html

かなり以前から作り始めていたのですが、ちょっと完成までに時間が掛かってしまいました。とりあえずiPadでは動きます。WindowsではChromeとFirefoxは大丈夫です。IEですか? もうよく知りません…(笑) IEが入っている環境なら、きっとFlashも入っているのでそれでもういいかな? 音は出ません。これは宿題とさせてください。とりあえずテスト公開です。しばらくしてから、トップページなどからリンクを張ります。

もし遊んでみて動作がおかしかったら、お使いの環境も含めてぜひ教えてください。明らかバグは大抵直せるはずです(逆に、微妙な不具合は少し難しいかもしれません…)。反対にちゃんと動いたよという報告も、たいへんありがたいです。どうかよろしくお願いします。

最後に、制作中に感じたことなど、ぐだぐだと書いていきたいと思います。

「携帯でCOSUMIが動けばなあ」というのは、思い返せば、一番最初にCOSUMIを制作し始めたころから思っていたことでした。しかし、当時は自分自身のスキルや状況がそれを許さず、どうにもなりませんでした。その内、AndroidでFlashが動くようになり「へへ、やっと時代がCOSUMIに追いついたぜ」と余裕をかましていたら(笑)、そのまま時代に追い抜かれてしまいました(泣)。仕方なく、重い腰を上げHTML5版の制作に取り掛かったという次第です。

当初は携帯電話を常に念頭に置いていたのですが、作っていく内にCOSUMIの主戦場はスマフォではなく、タブレット端末じゃないかと思うようになりました。これについては、今後のアクセス解析がちょっと楽しみです。

技術的なことも少し書いておくと、碁石はCanvasで描いています。画像を貼っているとかじゃなくてグラデーションをつけて丸を描いています。いろいろ試したのですが、これが速くて綺麗でした。絵を手直ししたい時も、少し数字をいじればいいだけなのでものすごく楽です。

それから、動作確認のためにiPad3買ったのですが、Retinaディスプレイが本当に綺麗です。そしてこういったモバイル端末使っていると、画像がドットバイドットで表示されることを期待する時代は完全に終ったんだということを実感します。例えば、どこのサイトを見ていても、画像汚い・テキスト綺麗です。こういうのはものすごく驚きでした。

iPadと言えば、新しいiOS6です。個人的には地図は許せますが(笑)、この仕様(バグ?)は許さん! 少しはまってしまいました。なんでPOSTのレスポンスをキャッシュするんだ… これ、もう少し世間的に大ごとになりそうなものですけどね。

[追記 2012/9/29]
トップページからのリンクも張って、正式公開としました。ウェブサーバのアクセスログを見る限り、Androidでも動いているのかな?

ただ、ちょっとした不具合がひとつだけ見つかりました(正確には制作中になんどか経験していた不具合の再現方法がようやく分かりました)。それは、「iPad3でページをスクロール中に碁盤や碁盤の周りのクリッカブルな所をタップするとその後の動作がおかしくなる」というものです。時間はかなり掛かったのですが、少しずつ原因も分かってきました。この話はこの話だけで一度ブログ記事にしたいと思います。ちなみにこの不具合は、まだちゃんと確かめてはいませんが、たぶん直せると思います。

[追記 2012/10/2]
この不具合を修正しました。技術的な詳細はこちらをみてください。

iOS6ではページをスクロール中に発生したタッチイベントからJavaScriptのタイマーがセットされない?
http://www.perfectsky.net/blog/?p=152

9路盤でコンピュータの強さが選べるようになりました

COSUMIの9路盤で、レベル1からレベル4までコンピュータの強さを選べるようにしてみました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

今回の変更直前の9路盤の強さは、(常に一定ではありませんでしたが)だいたいレベル3.5相当ぐらいでした。ですので、今回のレベル4は今までよりも少し強く、レベル4以下は今までよりも弱いです。将来的にはレベル5はいつか必ずできそうです。それより上はFuegoの進化しだいですね。それぞれのレベルの強さがころころ変わっては意味が無いと思うので、今後のアップデート時には、できるだけ同じ強さを維持できるように気をつけたいと思います。

一応、どのようにレベルの調整をしているかも、以下簡単に書いておきたいと思います。COSUMIの9路盤は、まず初手からCOSUMI独自のオープニングブックを使い、それが切れるとFuegoに考えさせ、そしてある一定の手数まで来るとGNU Goに考えさせていました(厳密にはもう少しややこしいことをやっていますが…)。今回はこの元々Fuegoに考えさせていた中盤を、GNU Go、Fuego 2000playout、Fuego 6000playout、Fuego 20000playoutにすることで、それぞれレベル1からレベル4の強さに調整しています。ちなみに、GNU GoとFuego 2000playout、Fuego 2000playoutとFuego 6000playout、Fuego 6000playoutとFuego 20000playoutの組み合わせで初手から終局まで丸々一局戦わせると、だいたい後者が勝率8割ぐらいになります。

19路盤で置き碁ができるようになりました

COSUMIの19路盤で置き碁ができるようになりました。

19路盤
http://www.cosumi.net/nineteen.html

例によって石を置くことしかできませんが、まあこれで良いと思います。

とりあえずで作ったこの19路盤ですが、プレイしてくれる人の割合がすごく多くてびっくりしています。このあたりは本当にちょっと認識を改めないと…

COSUMIのサーバを交換しました(3回目)

昨日、COSUMIのメインのサーバを新しいのに交換しました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

新しいサーバは、「さくらの専用サーバ」のエクスプレスシリーズの一番高いのです。お値段は、35,800円/月から13,800円/月に!(幸せです。いやほんとに) しかも、COSUMI的な性能はそれほど変わらないかなと思っていたのですが、新しいのは倍近く処理能力があるみたいで… 特に意外だったのは、GNU Goを同時にたくさん動かしている時に、Hyper-Threadingで4割ほど多く仕事してくれること。テストする前はゼロみたいなものだろうと思ってました。

サーバのスペックも良くなったので、少し贅沢にリソースを使うようにもしました。Fuegoのバージョンも0.4.1から1.1に変更(ずっとほったらかしだった…)。定石も少しアップデートしました。という訳で、もろもろ結構良くなっているはずです。

あと、今現在COSUMIのHTML5版を作成中です。最初は大変かなと思っていたのですが、作り始めたらそうでもなかった… とりあえず、iPhoneやiPadなどのiOS系で動くようにだけはしたいと思います。

Pachiにたくさんたくさん戦わせてみた

COSUMIの新しいサーバを借りたので、本番に投入する前に、自分のPCでは普段できない、負荷の掛かる重いPachiのテストをいろいろやってみました。とりあえずplayout数を20kにそれぞれ設定してFuegoと100局(以下すべて19路盤、コミ6目半。Pachiのバージョンは9.01、Fuegoは1.1。カッコ内は、一局あたりの平均消費時間です)。

Pachi。

$ pachi -t =20000

Fuego。

$ fuego --config foo.conf

foo.conf。

uct_param_search number_threads 1
uct_param_player ignore_clock 1
uct_param_player max_games 20000

そして結果は、

Pachi(832.2sec) 67勝 – 33勝 Fuego(550.5sec)

消費時間が結構違うので、今度はplayout数を15kと25kにして更に100局。

Pachi(619.4sec) 41勝 – 59勝 Fuego(635.6sec)

うーん、そうなんですよね。私が調べた範囲では、以前から19路盤でもPachiがいまいち冴えないんですよね… 一応、ここにあるextra pattern filesを使うと強くなるらしいですが、言っても50~150Elo程度のようですし、なにか他にしておいた方が良い設定とかあるのかな?

気を取り直して次行きます。今度はplayout数に因る強さの変化を調べてみます。playout数が1kから128kの8つのバージョンのPachiに、Gomillというソフトを使って、1ペアあたり10局の総当たり戦を行わせてみました(このGomillというソフトはすごい便利!)。

                     A    B    C    D    E    F    G    H
A pachi-playout1k        1-9  0-10 0-10 0-10 0-10 0-10 0-10
B pachi-playout2k   9-1       0-10 0-10 0-10 0-10 0-10 0-10
C pachi-playout4k   10-0 10-0      0-10 0-10 0-10 0-10 0-10
D pachi-playout8k   10-0 10-0 10-0      1-9  0-10 0-10 0-10
E pachi-playout16k  10-0 10-0 10-0 9-1       1-9  0-10 0-10
F pachi-playout32k  10-0 10-0 10-0 10-0 9-1       2-8  1-9
G pachi-playout64k  10-0 10-0 10-0 10-0 10-0 8-2       2-8
H pachi-playout128k 10-0 10-0 10-0 10-0 10-0 9-1  8-2

playout数が増えるにしたがってきっちりと強くなっていくのですが、上の方ではその効果が少しずつ失われていくのがわかります。そして問題はこれが最終的にはどのように収束していくのかなので、さらに追加で128kと256kを20局。

                     A    B
A pachi-playout128k      7-13
B pachi-playout256k 13-7

そして、Fuegoでも同じようなことをさせてみました。

                     A   B   C   D
A fuego-playout16k      2-8 2-8 1-9
B fuego-playout32k  8-2     3-7 1-9
C fuego-playout64k  8-2 7-3     2-8
D fuego-playout128k 9-1 9-1 8-2

はっきりしたことを言うには対局数が少なすぎますが、Pachiの時とはちょっと様相が違って見えます。

全体的な結論としては、「playout数が多ければPachiは強いけど、少なければそうでもない」といった感じでしょうか?

最後に、無作為に選んだPachiの128kと256kとの対局を先後を換えて1局ずつ貼っておきます。

19路盤

COSUMIで19路盤の対局もできるようにしました。

19路盤
http://www.cosumi.net/nineteen.html

COSUMIが黒番の時の初手以外は、もう完全に全部GNU Goです。正直、ローカルでお好きなGUI使ってGNU Goと対局してもらった方が何かと良いと思うので、存在意義がちょっと薄い気もしますが、まあとりあえず作ってみました。一応、この19路盤だけはサーバの負荷が高い時は対局できない仕様にさせてもらいますが、実際はたぶん基本的にいつでも動くと思います。というか、いつでも動くようにサーバを増強し続けたいと思います。

今回の19路盤の対局ゲームでは、さくらのVPSを初めて使ってみました。最近になって気づいたのですが、このサービスちょっと安過ぎではないでしょうか? 鯖をたくさん食べたければ(笑)丸ごと一匹買ってくるのが良いに決まってると思ってたのに、この小さい切り身はとってもお買い得に見えます。もし今回これでうまくいくようなら、今後はこのさくらのVPSをたくさん借りて負荷を分散させていく予定です。本当にありがたいことなんですが、現在のCOSUMIのアクセス量は4コアXeon2発ではとても捌ききれません… サーバが複数台の構成になるのは技術的にいろいろ大変ですが、もうこれは避けようがなさそうです。

Yahoo!と囲碁ガール

かなりいまさらな話ですが、先々月の10月24日(か23日)、Yahoo! JAPANのトップページのニュースがいろいろ載っている欄に、「囲碁ガール」がうんたらかんたらというのが出てました。その時のリンク先のページは今はもう消えているみたいなんですが、そのリンク先のページに載っていた記事自体はこちらです。

“囲碁ガール”が増殖中! 知られざる囲碁の魅力とは? | web R25
http://r25.yahoo.co.jp/fushigi/girlscolumn_detail/?id=20111020-00021797-r25

そして、先々月のCOSUMIの(Google Analyticsで言うところの)ユーザー数の推移がこれです。

「囲碁ガール」と「COSUMI」にそこまでどんぴしゃな関連性があるとは思いませんので、Yahooすごいとしか言えません…

Pachiのこと書くのを忘れてた

先日、このサイト内でまだ一度も「Pachi」という単語が使われてないことに気づき、めちゃくちゃ驚いてしまいました。ということで今回はこのすごく強いオープンソースの囲碁ソフトの紹介です。ちょうど9.00という新しいバージョンがリリースされたばかりです。

Pachi: Software for the Board Game of Go / Weiqi / Baduk
http://pachi.or.cz/

Pachiは、かなり以前からKGSでよく見かけたりしたのでそこそこ有名なソフトだと思います。そして、オープンソースのプログラムの中ではたぶん最強でしょう(少なくとも19路盤では間違いないかと)。この周俊勲九段との7子局とかけっこうすごいです。

いつかCOSUMIでもお世話になることがあるかもしれませんが、碁盤サイズが小さいとFuegoもかなり強いんですよね。

15路盤で置き碁もできるようにしてみました

COSUMIの15路盤で置き碁もできるようにしてみました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

置き碁といっても黒番しか持てませんので、石を置かせたい時は適当な回数最初にパスしてください。1ヶ月ぐらいしたら、この置き碁の対局用の定石をちゃんと作ってみたいと思います。今はとりあえずの分しか用意できてません。

それから、純碁のルール解説のページも作ってみました。まあこっちのページを削り倒しただけなんですが…

http://www.cosumi.net/jungolearn.html

[追記 2011/11/12]
置き碁用の定石をとりあえず一回アップデートしました。1ヶ月後ぐらいにもう一度やると思います。

[追記 2011/12/23]
もう一回アップデートしました。できるだけ早い内にもう一度やります。

定石アップデート 9路盤-30693局面 11路盤-18776局面 13路盤-19523局面 15路盤-20285局面

COSUMIの定石をアップデートしました。今現在、9路盤が30693局面分、11路盤が18776局面分、13路盤が19523局面分、15路盤が20285局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

当初、かなりあやしかった5路盤も、COSUMIで打たれた棋譜を見ている限り、今はもうかなりまともになっているようです。

サウンドオフと2回クリックの機能を付けました

COSUMIに、サウンドをオフにする機能と、手を打つ時に1回ではなく2回クリックして初めて確定されるようにする機能を付けてみました。碁盤の右上に小さなボタン(というか文字)ができています。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

サウンドオフは、どうせならもっと早くやっておけばよかったかもしれません(あまりごちゃごちゃさせるのは好きではないんですが…)。2回クリックは、最近ものすごくアクセスが増えているスマートフォンでの操作性を考えて付けてみました。これで多少は遊びやすくなったのではないでしょうか? よくアンドゥができる囲碁ソフトがありますが、そんなの囲碁じゃないって思うのと、サーバサイドが絡むと一気に話がややこしくなるので、この形にしました。個人的にはこれで十分だと思います。

あとそれから、Fuegoの考える手に対して簡易的なダイナミックコミも導入してみました。具体的には、前の手を考えた時に返ってきたwin rateに応じて調整したコミで、その次の手を考えさせるようにしました。別に、Fuegoのソースコードをいじったとかそんな高級な話ではありません。この改良で強くなったり弱くなったりはほとんど無いと思いますが、9路盤~13路盤の手が少し自然になっているかもしれません。

それ以外にも、今回はいろいろと細かいところを修正したはずなのですが、もうよく覚えていません(笑)。

祝100万敗!

COSUMIが100万敗を達成しました!

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

現在、3000敗/日、COSUMIが打つ手が40万手/日ぐらい。始めたころを思うと、考えられないような数字です。もしいつか、1000万敗までいくようなことがあったら、もう涙が出ちゃいますね。1億敗までいったら、たぶん心臓が止まると思います!(笑)

あらためて、GNU GoとFuegoの開発者の方には、心より感謝です。

7路盤スペシャルバージョンの定石を公開します

[以前の関連記事] : 7路盤スペシャルバージョン

COSUMIの7路盤スペシャルバージョンの定石を公開したいと思います。本当はもう少しちゃんとしたのができてからにしたかったのですが、なかなか終らないので… これからはアップデートするたびに随時公開していきます

7路盤スペシャルバージョン
http://www.cosumi.net/seven.html

まずはSGFファイル。

http://www.perfectsky.net/misc/kifu/seven-20110608.sgf
http://www.perfectsky.net/misc/kifu/seven-20210610.sgf

ここにも貼り付けておきます。


Sorry, your browser doesn’t support WGo.js.

以下、注意点を箇条書きにしていきます。

  • Bad Moveというコメントがついている手は地を損する手(以下、悪手と呼びます)で、それ以外の手は地を損することのない手(以下、最善手と呼びます)です。悪手・最善手の区別に、コウ材の数や、人間が見て自然な手かどうかなどといったことは一切考慮されていません。COSUMIは最善手だけを打ちます。
  • 悪手となっている手が実際は最善手ということはほとんどないと思いますが、その反対に最善手となっている手が実際は悪手ということはけっこうよくあります。特に、一度悪手を打った後の手順中には多いです。
  • COSUMIでは手順ではなく盤面の形で定石を持っているかどうか調べています。例えば、黒A・白B・黒C・白Dという手順が入っていたら、黒C・白B・黒Aの手順でも白Dと打ちます。ただし、コウは考慮されます。
  • COSUMIでは対称形は考慮されます。
  • GNU Goの尻拭い的な手順がけっこうたくさん入っています。あまり気にしないでください。
  • 棋譜管理ソフトの操作ミスで明らかにおかしな手順が入っている時もあると思います。それもあまり気にしないでください。

一応、現在の7路盤解析の進捗状況はというと、まず、COSUMIが負けたけどまだ定石を修正できていない対局の棋譜が5000局分ぐらいあります。その内の半分ぐらいは、GNU Goが最後に勝手に転んでるだけの対局なのでどうでもいいのですが、残りの半分はちゃんと調べないといけないやつで、これがパターン数で本当にだいたいですが20パターンぐらい。ただ、主だった変化はもう出尽くした感もあるので、この20パターンさえ調べられたら一応終わりかなと思います。

ということで、今回はその中から、比較的やっかいなのを2つ紹介します。興味があったら調べてみてください(何人かでつつくと楽しいかもしれません)。そして、結果を教えてください!

とりあえず、7路盤を調べるならまずはこのサイト。

七路盤の研究
http://olive.zero.ad.jp/qin/7ro/

その1。


Sorry, your browser doesn’t support WGo.js.

先のサイトにはこの局面で、6-4にあてて、6-3に継ぐ手順が載っていますが、素人目には、3-5が良い所に見えてしかたありません(Fuegoもここを曲がりたがります)。単に曲がるのが良いのか、6-4に一本あててから曲がるのが良いのかはよく分かりませんが、最低でもどちらか一方は盤面9目ぐらいありそうに思えるのですがどうでしょうか? ちなみに、この形は7路盤調べ始めた時から、自分の中でラスボス的な扱いになっています(笑)。

その2。


Sorry, your browser doesn’t support WGo.js.

私にはまず気がつかない手なんですが、この局面で3-5にこすむ手があるようです。一見、ぬるく見えますが、この手がすごいのは、(相手から対称形で手を渡されたのに対し、さらに)相手に対称形で手を渡しているところで、白は右下半分だけで(左上半分だけで)、なにか手を捜さなければいけませんが、しかし狭い… この勝負どころで、選択肢がほとんどないのは白も怖いです。うーん、これは油断ならない手。一応、さすがにこの手は成立しないというのが私の予想なのですが、Fuegoに打ち次がせると黒の勝率もそれほど悪くないんですよね。ひょっとすると…

7路盤調べていていつも思うのは、「本当にちゃんと調べた人はいないんじゃないかな」ということです。盤面9目という話もまだ怪しい… でも自分が死ぬまでにはきっとはっきりするだろうと思うので、ちょっと楽しみです。

話が少しそれますが、こちらのサイトによると7×4では白は生きないけど、6×5なら生きがあるようです。面白いですね。ここまで来れば、6×6がコンピュータで解析されるのも、もう時間の問題でしょうか? できればそれまでに、ある程度しっかりした7×7の答えを出したいですね。人間様のすごさを見せてやる!(笑)

[追記 2021/06/13]
これからはアップデートするたびに随時公開していきますとか書いておきながら、ちょうど10年(!)ほったらかしにしてしまいました…(笑) 本当にすみません。上は現時点の最新版に、更新しておきました。今後は「できるだけこまめに公開する」とさせてください。

定石アップデート 9路盤-28937局面 11路盤-16976局面 13路盤-18127局面 15路盤-14549局面

COSUMIの定石をアップデートしました。今現在、9路盤が28937局面分、11路盤が16976局面分、13路盤が18127局面分、15路盤が14549局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

今回はとにかく徹底的に5路盤を修正しました。それ以外は微調整です。

あと、ごくまれに特に小さい碁盤サイズでコウの時にエラーが起こることがあった不具合も修正しました。

COSUMI APIを停止します

サーバの負荷がかなり増えてきたので、今月末の5月31日をもってCOSUMI APIを無期限停止します。

囲碁Web API 「COSUMI API」
http://www.cosumi.net/api.html

そもそも、COSUMI APIは負荷が高い時には正常にレスポンスを返さない仕様なので、今だって停止しまくりだったりするわけですが、「売り物が無いのに店を開け続けている」のはちょっとなんなので、こういうことになりました。

続けられなくてごめんなさい。もしも再開することがあったら(まずないとは思いますが)、その時は24時間いつでも使えるようにします。そうじゃないと、結局使いようがないと思います。

[追記 2011/6/1]
止めました。

GNU Goに純碁を打たせる

正直、COSUMIを始めるまではあまりそういう認識ではなかったんですが、「囲碁のルールは難しい」と感じる人は少なくないようです。囲碁を始めてみたいと思っても、一番最初のルール覚えるところでつまづいてしまうらしい… 囲碁のルールが「シンプル」なのは間違いないと思うのですが、必ずしもすべての人に「わかりやすい」とは言えないのかもしれません。ただ、難しく感じる原因が、囲碁のルール自体ではなく、人や書籍やウェブサイトなど、ルールを教えるものにあることも多い気がします。じゃあなぜそうなってしまうのかというと、それは囲碁のルールがムズカシイからで…

ということで「純碁」です。もうみんなで純碁をやりましょう!

王銘エン九段著「純碁」
http://park6.wakwak.com/~igo/golax/jungo/ohmei.html

みんなで純碁をやると決まったので(笑)、GNU Goにも純碁を打ってもらうことにします。ここからが今回の本題です。

まず、使えそうな起動オプションを探してみます。とりあえずこのあたりかな?

$ gnugo --chinese-rules --play-out-aftermath --capture-all-dead

これで打たせたのがこの対局。

ちょっぴり感じが出てますが、最後はもっと自分の地に石を埋めていってもらわないといけません。そこで、読めないソースコードを読んだふりして、少し分かった気になってみます。aftermath.cの952行目あたりに以下の赤字部分を追加します(以下、すべてバージョン3.8の話です)。

  /* Case 7.
   * In very rare cases it turns out we need yet another pass. An
   * example is this position:
   *
   * |.....
   * |OOOO.
   * |XXXO.
   * |.OXO.
   * |O.XO.
   * +-----
   *
   * Here the X stones are found tactically dead and therefore the
   * corner O stones have been amalgamated with the surrounding
   * stones. Since the previous case only allows sacrificing
   * INESSENTIAL stones, it fails to take X off the board.
   *
   * The solution is to look for tactically attackable opponent stones
   * that still remain on the board but should be removed.
   */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (board[pos] == other
	&& (worm[pos].unconditional_status == UNKNOWN
	    || do_capture_dead_stones)
	&& (DRAGON2(pos).safety == DEAD
	    || DRAGON2(pos).safety == TACTICALLY_DEAD)
	&& worm[pos].attack_codes[0] != 0
	&& !is_illegal_ko_capture(worm[pos].attack_points[0], color)) {
      DEBUG(DEBUG_AFTERMATH, "Tactically attack %1m at %1m\n",
	    pos, worm[pos].attack_points[0]);
      return worm[pos].attack_points[0];
    }
  }
  
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (ON_BOARD(pos)
    && board[pos] == EMPTY
    && is_allowed_move(pos, color)
    && safe_move(pos, color)) {
      return pos;
    }
  }
  
  /* No move found. */
  return PASS_MOVE;
}

ちなみに、is_allowed_moveを付けておかないと、ごくまれに非合法な手を打とうとしてエラーになる時があるようです。で、これで打たせたのがこの対局。

おー、これは純碁っぽいですね。地を埋めていくのがなんだか面白い。ただ、何局も打たせて調べていると、次のような局面で左上の1目の地を埋めてしまうことが判明しました…(それはsafe_moveなのか?(笑))

しかたないので、かなり無理やりですが、先ほど追加したコードの前にさらに以下の赤字部分を追加します。

  /* Case 7.
   * In very rare cases it turns out we need yet another pass. An
   * example is this position:
   *
   * |.....
   * |OOOO.
   * |XXXO.
   * |.OXO.
   * |O.XO.
   * +-----
   *
   * Here the X stones are found tactically dead and therefore the
   * corner O stones have been amalgamated with the surrounding
   * stones. Since the previous case only allows sacrificing
   * INESSENTIAL stones, it fails to take X off the board.
   *
   * The solution is to look for tactically attackable opponent stones
   * that still remain on the board but should be removed.
   */
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (board[pos] == other
	&& (worm[pos].unconditional_status == UNKNOWN
	    || do_capture_dead_stones)
	&& (DRAGON2(pos).safety == DEAD
	    || DRAGON2(pos).safety == TACTICALLY_DEAD)
	&& worm[pos].attack_codes[0] != 0
	&& !is_illegal_ko_capture(worm[pos].attack_points[0], color)) {
      DEBUG(DEBUG_AFTERMATH, "Tactically attack %1m at %1m\n",
	    pos, worm[pos].attack_points[0]);
      return worm[pos].attack_points[0];
    }
  }
  
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (ON_BOARD(pos)
    && board[pos] == EMPTY
    && (board[SOUTH(pos)] == EMPTY
        || board[WEST(pos)]  == EMPTY
        || board[NORTH(pos)] == EMPTY
        || board[EAST(pos)]  == EMPTY)
    && is_allowed_move(pos, color)
    && safe_move(pos, color)) {
      return pos;
    }
  }
  
  for (pos = BOARDMIN; pos < BOARDMAX; pos++) {
    if (ON_BOARD(pos)
    && board[pos] == EMPTY
    && is_allowed_move(pos, color)
    && safe_move(pos, color)) {
      return pos;
    }
  }
  
  /* No move found. */
  return PASS_MOVE;
}

これで打たせたのがこの対局。

地の埋め方がなんだかいい感じに臆病になっています(笑)。

ところが、これでもうOKかなと思っていたら、さらに別の問題が判明しました。次のような局面で白石を打ち上げてくれません…

これは先ほどのコードを追加したからとかではなく、そもそもGNU Goはこの巨大墓場を打ち上げてくれないようです(そういえば、COSUMIでも打ち上げてないのを見たことがある(笑))。最初は「これは純碁として致命的!」と思ったんですが、よく考えたら致命的なのは中国ルールでも日本ルールでも同じようなもの。ただ、囲碁を知っている人が打てば、普通こんな局面にはなったりしないので別にあれですが、純碁を打つような初心者の人なら、こんな局面にだってしてしまうかもしれないし、このまま終局したらなにかと誤解しかねないのでちょっとやな感じです。で、なんとかならないかなといろいろ試したところ、この局面の後、黒パス白パスとなると、今度は打ち上げてくれることに気づきました(GNU Goの中で、一体何が起こったのかは全くわかりません(笑))。正確には、--capture-all-deadオプションと、黒パスか白パスのどちらかひとつでも最後に付いていれば(2手打ちになるけど)、GNU Goは打ち上げてくれるようです。

ということで、時間のある時にこのあたりを何とかまとめて、COSUMIでも純碁が打てるようにしたいと思います。ちなみに、今回のようなことをしても、切り賃を意識したような純碁的に良い手を打つようになったり、純碁でスコア計算をしてくれるようになったりはしませんので注意してください。あくまでも、最後に上手に地を埋めていってくれるようになるだけです。

[追記 2011/5/13]
COSUMIでも純碁が打てるようにしました。

http://www.cosumi.net/jungo.html

棋譜の最後にパスを付けると、取れないコウが取れるようになってしまうので(気づくのが遅い!(笑))、(盤面全体の)巨大墓場は、GNU Goを使わずに自前のコードで打ち上げるようにしました。なので、純碁以外の対局ゲームでも、今度からは巨大墓場を打ち上げます。少し賢くなりました。

節電にご協力ください

当面の間、COSUMIの囲碁対局ゲームを停止します。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

現在、政府や電力会社が節電を呼びかけていますが、その様な状況で、PCでゲームっていうのはないんじゃないかということです。ご理解ください。

また、他にも身の回りに不必要な電気の使用がないか、今一度ご確認ください。どうかよろしくお願いいたします。

私自身、今回のような判断が正しいものなのか確信は持てませんが、COSUMIと似たようなサイトの運営者の方が、熟慮のうえで追従してくださるのなら、とてもうれしく思います。

[追記 2011/3/22]
昨日21日、再開しました。本当にいろいろなことを考えた結果、このタイミングになりました。ご理解ください。

石が出てこない

COSUMIの対局リプレイ時に、ごくまれに石の表示がおかしくなることがあったので修正しました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

ちょっとややこしいのですが、「石が取られた後、その石が取られた場所の内、上下左右に石が無い所に打つと、その打った石が表示されず無いものとされる」って感じでおかしくなってました(こんなのの最後に打たれた黒石なんかが出てこなかった)。ちなみにこの不具合は、対局リプレイの時だけ話で、対局中は問題ありませんでした。

このバグはかなり以前から存在していたと思うのですが、何で今まで気づかなかったんでしょうねえ…

一色碁

作ってってコメントをこのブログにいただいたので、COSUMIに「一色碁」の対局ゲームを作ってみました。ていうか、目隠し碁を作った時にいっしょに作っておけば良かったんですが…

一色碁
http://www.cosumi.net/onecolor.html

一色碁って目隠し碁より簡単とはいえ思ったより難しいですね。正直、9路盤なら余裕かと思ってましたが、途中から白の巨大な団子石としか見えなくなってきて…(笑)

話のねたによかったら遊んでみてください。

* * * * * * *

Android 2.2+ではFlash Playerが動くようになったので(端末によっては動かないこともあるらしいけど)、これでこれからは携帯なんかでもCOSUMIで遊んでもらえるなあと喜んでいたんですが、実際に動くかどうかは今まで全く確認していなかったので、少し調べてみました。とりあえずアクセスログを見た感じでは、GALAXY Tab SC-01C、GALAXY S SC-02B、SIRIUS α IS06、GALAPAGOS SoftBank 003SHなどで終局まで打たれている形跡がありました。操作のしやすさなどに関しては全くわかりませんが、一応動くのは動くようです(良かった!)。私もAndroidのスマートフォンが少し気になってるんですが、もう買っちゃおうかな?

/proc/loadavgの謎

CentOS 5.5なCOSUMIのサーバでcat /proc/loadavgとすると、ごくまれに最後の改行が1つではなく2つになっていることがあります。どうでもいいような細かい話ではありますが(笑)、しかしたぶんこれは意図されていない出力形式だと思います。

$ cat /proc/loadavg
5.02 4.74 4.32 4/245 6023
$ cat /proc/loadavg
5.02 4.74 4.32 9/257 6072

$ cat /proc/loadavg
5.02 4.74 4.32 12/267 6146

そもそもなぜこれに気づいたかというと、この出力内容をログに取り続けているからなんですが、最近、そのログを見ていた時に、偶然、改行が2つの時だけに見られる奇妙な規則性に気がつきました。その規則性とは、「4カラム目のスラッシュの左側(実行中のプロセス数)が9」ということです(ほんとよく気がついたと思う(笑))。

5.02 4.74 4.32 9/257 6072

簡単なスクリプトを書いてさらにもう少し詳しく調べたところ、分かったのは、

  • 89の時しか改行が2つにならない
  • 8の時に改行が2つになる確率は、だいたい1%ぐらい。ごくまれ
  • 9の時に改行が2つになる確率は、だいたい50%ぐらい。こっちは多い

ということです。さらにさらに、以前使ってたサーバのログなども調べてみると、同じような条件で同じく改行2つになっている時があるのはあるのですが、発生頻度が今より少なかったです。初代、二代目、三代目(現在)となるにつれて、改行2つになる確率が増えていきます。ついでにいうと、簡単にしか調べてませんが、手元のPCでは改行2つが再現しませんでした。

一体なぜこういうことになるんでしょうか? 皆さんの環境でも同じことが起こりますか? とにかく不思議で不思議でしかたありません…

COSUMIには黒番白番どちらが勝ちやすい?

以前から調べよう調べようと思っていた、コミ6目半なCOSUMIの9~15路盤での手番による有利不利を調べてみました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

COSUMIでは、ユーザが勝った碁しか正確に把握できないんですが、それらの対局の内、ユーザが黒番だった割合は以下のような感じでした(調査対象期間はここ1ヶ月間ぐらい)。

9路盤 52.2%
11路盤 51.1%
13路盤 53.2%
15路盤 52.6%

一応だいたい私の事前の予想ぐらいでした。最適なコミの大きさの話はけっこう複雑で、あまり簡単にこれという答えが出せませんが、COSUMIは今後も引き続き6目半でいいかなと思っています。いつかCOSUMIがもっと強くなったら、もう一度調べてみたいですね。

COSUMI特有の要因もいろいろあると思いますので、この数字が囲碁というゲームそのものだけから来ているとは考えないで、参考程度に眺めるぐらいにしておいてください。

COSUMIに最大何目差で勝つことができるか?

COSUMIにツイートボタンを付けてから、COSUMIでの対局をつぶやいてくれる人が少しずつ増えてきてとても喜んでるのですが、それらのツイートを見ていると、ものすごい大差でCOSUMIをやっつけている人がちょくちょくいるので、では一体最大何目差で勝った人がいるんだろうと思い、ここ一ヶ月間ぐらいの棋譜をちょっと調べてみました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

調べ始めてすぐに気がついたのは、COSUMIを全滅させている棋譜がかなりあるということです…(笑) 当然のことながら基本的にそれ以上大差で勝つことはできませんが、9路盤なんかではそんな棋譜が山ほどあり、11路盤、13路盤と、碁盤が大きくなるに連れて数は減っていきますが、ゼロにはなりません。そして、なんと15路盤でもCOSUMIを全滅させている棋譜が3つもありましたので、ここに貼っておきたいと思います。その内ひとつは、なんと白番を持ってCOSUMIを全滅させてます!

まずは、黒番216目半勝ち。

次は、黒番217目半勝ち。

そして最後に、白番223目半勝ち。

ここまで来ると、ハム将棋に裸玉で勝つみたいな趣がありますね…(笑)

[以後の関連記事] : COSUMIに最大何目差で勝つことができるか? その2

タモリ倶楽部がCOSUMIにたくさんの人を連れてきてくれたかもしれない

COSUMIで使っているさくらの専用サーバには、データ転送量をグラフにして見せてくれるサービスがあります。今日、たまたまそれを見ていたら、昨日(日付変わっていたので正確には今日だけど)の深夜に突発的に転送量が増えていた時間帯がありました。

このグラフはサーバ全体のデータ転送量のグラフなので、必ずしもウェブサーバへのアクセスによるものではありません。例えば、自分が大きなファイルをアップロードしたりダウンロードしたりすると、当然こんなものではないぐらい跳ね上がります。ですが、昨日のその時間は暖かい布団の中で夢の中… 自分では何もしていません。また、誰かがどこかでCOSUMIのことを紹介してくれたので、一気にアクセスが増えたってこともありえますが、真夜中のことなのでちょっと考えにくい。うーん、普段から全くないことでもないので、こういうのを気にしすぎてもあれなんですが、気持ち悪いので一応サーバのログなどを調べておいた方がいいかなあなんて考えている時に、ふとあることを思い出しました。

「タモリ倶楽部で囲碁の話題をやるって言ってたけど…」

そうなんです! 昨日のタモリ倶楽部は「アンガールズ田中の恋人、友達募集!!ただし囲碁のできる方」という回で、もろに囲碁の話だったんです! 中島美絵子先生が出演されて、例の「碁的」の話なんかもあったらしい… 放送時間は0:20~0:50。上のグラフと比べてみてください。どんぴしゃですね。

ということで、普段は全くないような種類のアクセスがあったようなのでもう少し調べてみます。先ほどのグラフにロードアベレージの推移を重ねてみました。

全体に見られる転送量とロードアベレージとの相関が、例の時間帯では大幅に弱くなっていて、明らかに通常とは異質のアクセスがあったことがうかがえます。COSUMIでは、「ロードアベレージが高い」イコール「囲碁対局ゲームがたくさん行われている」なので(本当にほとんど完全にイコールです)、例の時間帯はウェブサイトには来たけど、囲碁対局ゲームはやらなかった人が多かったと言えそうです(テレビを見てた? 囲碁のやり方がわからない?)。それから、他の時間帯と比べると、Outbound/Inbound比がやや大きいのは、ブラウザのキャッシュにCOSUMIのファイルが無かったからという可能性があります(初めて来てくれた人が多かった?)。ちなみに、昼の12:40ぐらいにあるピークの時は、100面打ちから150面打ちぐらいになっていると推定しますが(昨日はちょっと多かった)、そことの比較で、いかに深夜のこのアクセスがすごいか分かっていただけるでしょうか?(ていうか、ウェブサーバのログ解析してもっとましなデータ持って来いって怒られそうですね。でも、めんどくさいのでやりません(笑))

私は、テレビの将来はかなり暗いと常々思ってますが、直接関係がある訳でもないウェブサイトに、深夜にも関わらずこんなにもたくさんの人を連れてくるこの底力は本当にすごいなと驚きました。タモリ倶楽部は、放送日が地域によってかなりばらばららしいので、うまくいけば、第2波、第3波も観測できるかもしれません。

[追記 2011/1/9]
ウェブな数字を出さないで、話をこのまま終わらすのはあまりにいいかげんなので、1時間単位のデータしか見れないのがなんですが、Google Analyticsのページビューのグラフも貼っておきます。1つ目のが1月5日~1月7日の合計、2つ目のが1月8日分です。放送時間だったのは、2つ目の一番頭の部分です。


明らかにボリュームがありますし、「新規ユーザー」と「リピーター」の逆転も見られます。放送時間終了後も、この逆転がしばらく続いているのも分かりますね。

ということで、この時間ウェブサイトへ多くのアクセスがあったのは間違いありません。後はこれがタモリ倶楽部の影響だったかどうかですが、”tamoriclub”なんてリファラが付いてくるわけでもないので(笑)、正確に調べるのはなかなか難しいですね。上で、放送日が地域によってかなりばらばらだと書きましたが、こちらのサイトを見た感じでは、主だったものは1月22日(正確には23日。放送時間は地域で微妙に違う)の岐阜・愛知・三重・長崎・沖縄と、1月29日(同じく正確には30日)の滋賀・京都・奈良・大阪・兵庫・和歌山・徳島の2日だと思われるので(注意! 放送日が正しいかどうかは私は全く保証できません)、この2日についてはちゃんと調べて事後報告したいと思います。

[追記 2011/1/9]
先ほどページビューのグラフを貼ってた時に、1月8日分の23時台に違和感を感じていたんですが、理由が分かったような気がします。またも似たような話ですが、その時間帯のNHKのトップランナーって番組に、井山裕太名人が出演されていたんだそうです! たまたまかそれともこのブログ記事を書いたからかな、なんて思っていたのですが違いました。っていうかテレビってやっぱりすごいですね。ただ、日本棋院のウェブサイトとかならともかく、COSUMIなんかがこんなに影響を受けるってのが不思議な感じもあるんですが…

とりあえず細かい動きが分かるので、また転送量のグラフを貼っておきます。ページビューのグラフは明日にでもまた貼ります。

書かなくても大体分かりそうな感じですが(笑)、放送時間は23:30~23:59でした。その前の時間帯に軽く谷を感じますが、これは「今から井山君がテレビに出るのに、COSUMIなんかで遊んでいる場合じゃない!」ってことでしょうか? ちょっと面白いですね。

一応、過去の金曜日、土曜日の夜に似たような傾向が無いか調べましたが、はっきり言って皆無でした。明らかにこの2日間は特別だったと思います。

[追記 2011/1/10]
1月9日分のページビューのグラフです。上の1月8日分からの続きにあたります。

トップランナーの放送終了直後の0時台からがなかなかすごいです。「新規ユーザー」と「リピーター」の逆転もまた見られますが、今のCOSUMIではこれは相当珍しい現象です。

[追記 2011/1/22]
タモリ倶楽部の関西圏の放送は、17日の夜だったようです。放送時間は1:42~2:12かな? ということで1月18日分のページビューのグラフです。

かすかに2時台に波を感じますが、首都圏での放送時とは全く様子が違いますね。

[追記 2011/2/7]
タモリ倶楽部の名古屋での放送は、2月5日の夜だったようです(遅すぎ!)。放送時間は0:55~1:24。ということで2月6日分のページビューのグラフです。

関西圏での放送時に同じく、かすかに1時台と2時台に波を感じますが…

GNU Go 3.9.1

GNU Goの最新開発版、バージョン3.9.1がリリースされています。

GNU Go – GNU Project – Free Software Foundation (FSF)
http://www.gnu.org/software/gnugo/

ということで、バージョン3.8と対戦させてみました。

GNU Goは、両方のバージョンとも自分でコンパイルしました。使用したPCのOSはWindows XP、CPUはAthlon X2 BE-2400。それぞれの碁盤サイズごとに、先後を換えて100局ずつ計200局対戦させました。コミは6目半。同じような手順の対局ばかりになってもあれなんで、対局開始局面はGoGuiに入っているテスト用のを使っています。カッコ内は、一局あたりの平均消費時間です。ちょっとうっかりして、付けなくてもいいのに--never-resignオプションを付けてテストしてしまいましたが、結果にはほとんど関係ないと思います。

9路盤 GNU Go 3.9.1(8.2sec) 105勝 – 95勝 GNU Go 3.8(8.4sec)
19路盤 GNU Go 3.9.1(140.6sec) 90勝 – 110勝 GNU Go 3.8(141.9sec)

特に強くはなっていないようです。それより、再現条件がよく分からないんですが、レベルを下げるとたまにエラーを出して死ぬのが… このバージョンは、COSUMIでは使いません。

[追記 2011/2/7]
レベルを下げるとおかしくなるのは、たぶんこれですね。パッチ当てたら直りました。

定石アップデート 9路盤-28405局面 11路盤-15460局面 13路盤-17431局面 15路盤-13397局面

COSUMIの定石をアップデートしました。今現在、9路盤が28405局面分、11路盤が15460局面分、13路盤が17431局面分、15路盤が13397局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

いつも思うのですが、大変なのでもうやりたくない…(笑) それより、こっちをできるだけ早く何とかしたいと思います。ただ、GNU Goがありえない負け方をしてくれるので、負けた碁を全部修正するのはもうできそうもありません。とりあえず、変化の本線をきっちり調べていきます。

COSUMIにツイートボタンを付けてみました

COSUMIの対局リプレイページに、先日公開された公式のツイートボタンを付けてみました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

「初心者が負けた対局をつぶやくと、優しい有段者が教えてくれる」って感じの流れが生まれたらいいなと思ってます。Twitterのアカウントをお持ちの方は、ぜひ活用してみてください。

5路盤

COSUMIで5路盤の対局もできるようにしました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

黒白が共に最善を尽くして生き生きにならない5路盤というのは、囲碁は相手を全滅させるゲームだと勘違いしかねないので、入門者にとってあまり良いものではないと、今までずっと思っていました。ところが、COSUMIの6路盤の対局の棋譜を見ていると、COSUMIが相手を全滅させている棋譜が山ほどあるんですね。あまりしっかりと調べたわけではないですが、1回2回ではどころではなく、10回20回と連続で全滅させられている人だってかなりの数居そうです(完全な初心者には、そんなのぜんぜん仕方のないことですが…)。なので、相手を全滅させるゲームだと勘違いしかねないのは6路盤から始めても同じことのような気がするし、どうせならちょっとでも早く人生最初の勝利を挙げてもらいたいので、今回COSUMIに5路盤の対局ゲームを追加することにしました。本当にこれで良かったのか、自信があるわけではないですが…

明らかにおかしな手を打ったり、諦めが異常に早かったりする時がありますが、ある程度は近いうちに修正しますのでちょっと待っててください。

COSUMIのサーバを交換しました(2回目)

[以前の関連記事] : COSUMIのサーバを交換します

アクセス量が限界に近づいてきたので、COSUMIのサーバを新しいのに交換しました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

交換したサーバは、さくらのアドバンスドの一番高いのです。前に使っていたさくらのアドバンスドの一番安いのと比較して、4倍弱ほどCOSUMI的に速そうです。ここ最近、止まっている時間の長かったCOSUMI APIも、とりあえず今なら24時間いつでも動くと思います(まあ、言ってる間にまたアクセスが増えそうなんですが…(笑))。

また、このタイミングでかなりの量のコードを書き直しました。新たなバグを仕込んだ可能性も高いですが、ごく一部の環境では、今までより動作が大幅に安定したんじゃないかなと思います。それから、定石も少しアップデートしました。

COSUMIはちょうど2年前の今頃始めたサイトなんですが、当時と今とでは比較にならないほど全体的に良くなりました。棋力も今が一番だと思います。ぜひ一度遊んでみてください。

祝10万敗

COSUMIが10万敗を達成しました! たくさん負けたなあと喜んでおります(笑)。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

次の目標は、志を大きく100万敗です。ちなみに、ハム将棋は今現在、平手だけで(!)2,849,752敗だそうです。うーん、「ハム囲碁」への道のりは遠い…

定石アップデート 9路盤-26383局面 11路盤-12327局面 13路盤-15919局面 15路盤-8017局面

COSUMIの定石をアップデートしました。今現在、9路盤が26383局面分、11路盤が12327局面分、13路盤が15919局面分、15路盤が8017局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

こっちの方の定石もずっと直し続けていますので、よかったら遊んでみてください。ばかな負け方は、かなり少なくなってきています。ただ、COSUMIが負けたけどどの手が悪かったのか私の棋力ではわからない棋譜が手元に残り始めてますので、そろそろ他人様にすがりたい感じ… また今度、このブログの記事にまとめるので、碁の強い方に教えていただけるとありがたいです。

今回は、定石以外もいろいろ微調整してみました。全体的に良くなったんじゃないでしょうか?

それから、最近アクセスがめちゃくちゃ増えてきました。またサーバを替えないといけないんですが、来月出るらしいWestmere-EPことXeon 5600番台が2発載ったサーバ、良いタイミングでさくらから出てきたりしないですかね? とにかく、安くてCPUが速いサーバが欲しいです。

Fuego 0.4.1リリース

かなりいまさらな話ですが、去年の年末にFuegoの新しいバージョン、0.4.1がリリースされています。

Fuego
http://fuego.sourceforge.net/

Windows用のバイナリが手に入ったら、またテストしてみたいと思いますが、以前のバージョンよりもいくらか強くなっているようです。

COSUMIでも、この新しいバージョンに変更済みです。

[追記 2010/4/4]
バージョン0.4.1と0.4を、13路盤で

uct_param_player max_games 10000

として、先後を換えて50局ずつ計100局対戦させてみました。

結果は、

Fuego 0.4.1 55勝 – 45勝 Fuego 0.4

となりました。実際に強くなっているのは間違いないらしいのですが、この結果はかなり微妙… 消費時間はほとんど変わりませんでした。

目隠し碁

COSUMIに「目隠し碁」の対局ゲームを作ってみました。

目隠し碁
http://www.cosumi.net/blindfold.html

目隠し碁というのは、その言葉どおり目隠しして行う囲碁の対局のこと。NHKの番組でやっている脳内将棋の囲碁版と言えば、分かる人には分かってもらえると思います。チェスでもblindfold chessと呼ばれ、古くからあったみたい。みんな考えることがいっしょですね。

今回のゲームは着手を目で確認するので、本当に目隠しして打つ碁よりは少し楽かなと思いますが、それでも相当難しいです。私も何度かやってみましたが、9路盤ならなんとかなるだろうと思っていたのに、それすらままならない…(泣) 同じ9×9でも、同じ手数なら将棋の方がだいぶ簡単だと思いました。

自信のある方は、ぜひ一度遊んでみてください。挑戦、お待ちしています!

15路盤

COSUMIで15路盤の対局もできるようにしました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

いろいろ考えてこうしました。本当にいろいろ考えて… 強さは期待しないでください。前も同じことを書いたのですが(笑)、これより大きな碁盤サイズに対応することはたぶんないです。

悪手を指摘してくれる機能を付けてみました

COSUMIの6路盤~8路盤の対局リプレイ時に、どの手が悪手だったか、代わりにどこに打てば良かったかを表示するようにしてみました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

要するに、こんな感じ。初心者の方に喜んでもらえそうな、かなり良い機能だとは思うのですが、要チューニングではあります。下手すると、左右対称の局面で「右に打つな、左に打て」とか言い出しかねない…(笑) 初手から最後の手まで、きっちりと調べているわけでもありません。あまり信用し過ぎないようにしてください。

COSUMIのサーバを交換します

たいへんありがたいことなんですが、ここ最近COSUMIへのアクセスが急激に増え、サーバの負荷が高い状態が続いています。ということで、来月中をめどにサーバをもっと速いのに交換したいと思います。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

ひどい時には、GNU GoとFuegoのプロセスが10個以上同時に走っているのですが、これは、10面打ちをしている状態ということではなく、15面打ちだか20面打ちだかしていて、COSUMIの手番になっている対局が10局あるということでして、うーん、なんともオソロシイ…

しばらくの間、時間帯によっては遅かったり弱かったりすると思いますが、まったりとお楽しみください(笑)。

[以後の関連記事] : COSUMIのサーバを交換しました(2回目)

[追記 2009/10/16]
交換しました。今度のサーバは、さくらのアドバンスドの一番安いやつです。以前のサーバと比べて8倍くらいは処理能力があるんじゃないかと思うのですが、ここ最近のアクセス数の伸びは、本当に本当に凄まじく、これもいつまで持つやら… 先月1ヶ月の間に、COSUMIが考えた総手数(COSUMIの手だけ。遊んでくれているユーザの手は含まず)は、なんと1,000,000手を超えてたんですよ! 平均すると、33,333手/日、1,389手/時間、23.1手/分、0.386手/秒。ピーク時はこんなものではないですから、GNU Goはどんだけ軽いんだって話ですよね。

でも、今月はもっと凄そうです…(泣)

でも、調子に乗ってFuegoの一手あたりのPlayout数を少し増やしました!(笑) ちょっと怪しそうだったので… それから定石もちょっぴり追加しました。

[追記 2009/11/11]
なにかいろいろと勘違いしていたようで、処理能力は8倍も上がっていません。4倍ちょっとぐらいかな? 困りましたね…

COSUMIでFuegoをテスト中…

現在、COSUMIでFuegoの使用をテストしています。正直、何も問題が起こらないとは思えないのですが、もし、うまく行きそうならこのまま継続してFuegoを使い続ける予定です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

Fuegoを使うと言っても、基本は今までどおりGNU Goで、特定の場合のみFuegoに考えさせるだけです。どのような条件の時にFuegoを使うかは、今現在、詰めているところです。

しかし、9路盤なんかは相当強くなってるんじゃないでしょうか? Fuegoを使うのならば、サーバを新しいのにしたくなりますねえ…

[追記]
特に何も問題は発生しないようなので、このままFuegoを使い続けようと思います。どういう場合にGNU GoではなくFuegoを使うかの大まかな条件は、

  • サーバの負荷がそれほど高くない時で
  • 9路盤~13路盤で
  • 最序盤ではなくて
  • 終盤でもなくて
  • 形勢がどちらかに大きく傾いていない時

って感じです。ただ、大変ありがたいことに、ここ最近アクセスがだいぶ増えてきたので、サーバ負荷は常にけっこう高めなんですよね…(笑) そろそろサーバを替えなきゃだめかな?

定石アップデート 9路盤-23385局面 11路盤-10051局面 13路盤-10881局面

COSUMIの定石をアップデートしました。今現在、9路盤が23385局面分、11路盤が10051局面分、13路盤が10881局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

合わせて、対局結果の判定が不正確になりやすかった不具合を修正しました(これは気づいてほんと良かった…)。GNU Goも間違う時はあるので、どうがんばっても100%正確ってわけにはいかないのですが、少なくとも以前よりはましになっているはずです。

定石アップデート 9路盤-20996局面 11路盤-8628局面 13路盤-7672局面

COSUMIの定石をアップデートしました。今現在、9路盤が20996局面分、11路盤が8628局面分、13路盤が7672局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

9路(以下)はだいぶましになってきたと思うんですが、11路と13路はもうこれ以上がんばっても無駄かも…

6路盤・8路盤

COSUMIで6路盤と8路盤の対局もできるようにしました。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

うーん、これはもっと早くやっておけば良かった… ついでに、GNU Goを新しく出たばかりのバージョン3.8に変更して、定石も少し追加しました。

定石アップデート 9路盤-19788局面 11路盤-7828局面 13路盤-4144局面

COSUMIの定石をアップデートしました。今現在、9路盤が19788局面分、11路盤が7828局面分、13路盤が4144局面分です。

オンライン囲碁ゲーム COSUMI
http://www.cosumi.net/

ふー、けっこう大変…(笑)

定石アップデート 9路盤-17984局面 11路盤-7514局面 13路盤-3656局面

COSUMIの定石をアップデートしました。今現在、9路盤が17984局面分、11路盤が7514局面分、13路盤が3656局面分です。

オンライン囲碁 COSUMI
http://www.cosumi.net/

COSUMIが負けた棋譜を数百局並べましたが、うーんGNU Goってこんなに弱かったっけ?(笑) まあ、負けてる対局ばかり見ているからかもしれませんが、9路以下はともかく、それより大きな碁盤サイズでは、いくら定石を用意しても後ろのソフトががんばってくれないとどうしようもありません。もうちょびっと強くなってくれるとうれしいんですが…

7路盤スペシャルバージョン

囲碁は5路盤までコンピュータで完全に解析されていますが、それより大きなサイズでは、7路盤までがある程度しっかりと人力で調べられていて、お互いが最善を尽くすと先番9目勝ちだと言われています。ということで、それが本当に正しいのか確かめるためにこんなものを作ってみました。

7路盤スペシャルバージョン
http://www.cosumi.net/seven.html

ただのコミ9目の7路盤ですが、このページでCOSUMIが負けた棋譜は全て保存しています。そして、その棋譜に後から目を通して、同じ間違いをしないように正しい手を定石に追加していきたいと思います。時間は掛かると思いますが、いつか(持碁になる時はあっても)負けなくなるでしょう。可能性はかなり低いですが、もしかしたら新しい妙手が見つかるかもしれません。最終的に、ある程度ちゃんとした定石が出来上がれば、SGFファイルにして公開したいと思います。7路といっても想像以上に難解で、自分の棋力が足りるのかがちょっと心配ですが…

7路盤については、こちらのページがとても詳しいです。

七路盤の研究
http://tokyo.cool.ne.jp/keioigo/7ro/
http://orange.zero.jp/qin.olive/7ro/

だいたいこれで、COSUMIでやってみたかったことは全て終わりました。後は、時間のある時に少しずつ定石を増やして、強く・面白くしていきたいと思います。

[以後の関連記事] : 7路盤スペシャルバージョンの定石を公開します

さくら専用サーバエントリープランの使用感

COSUMIは、さくらの専用サーバエントリープランで現在運営しています。このサーバを借り始めてから半年近く経ったので、このあたりで使ってみた感想を記事にしておきたいと思います。と言っても、ごく単純なウェブサーバとして使っているだけなので、高度な内容の話はなにもありません。

専用サーバ|エントリー:月額7800円ではじめられるさくらの専用レンタルサーバ
http://server.sakura.ad.jp/dedicated/entry/

ハードウェアはCeleron 215、メモリ 1GB、HDD 80GBとかなりミニマムなスペックです(なんて言ったら贅沢か(笑))。Celeron 215ってのが調べてもあまりよく分かりませんが、一応こんな感じのCPUです。

$ cat /proc/cpuinfo
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 14
model name	: Intel(R) Celeron(R) CPU          215  @ 1.33GHz
stepping	: 8
cpu MHz		: 1333.439
cache size	: 512 KB
fdiv_bug	: no
hlt_bug		: no
f00f_bug	: no
coma_bug	: no
fpu		: yes
fpu_exception	: yes
cpuid level	: 10
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat clflush
 dts acpi mmx fxsr sse sse2 ss tm pbe nx constant_tsc up pni monitor tm2 xtpr
bogomips	: 2667.65

なにを見てそう勘違いしたのか、借りる前はデュアルコアのCPUだと思ってたのですが、ではないです(泣)。ただしこちらからダウンロードしてきたSuperπでベンチとってみると、そこそこ速そう。

Start of PI calculation up to 1048576 decimal digits
 End of initialization. Time=       0.651 Sec.
 I= 1 L=       0        Time=       2.072 Sec.
 I= 2 L=       0        Time=       2.379 Sec.
 I= 3 L=       1        Time=       2.381 Sec.
 I= 4 L=       2        Time=       2.378 Sec.
 I= 5 L=       5        Time=       2.383 Sec.
 I= 6 L=      10        Time=       2.377 Sec.
 I= 7 L=      21        Time=       2.381 Sec.
 I= 8 L=      43        Time=       2.377 Sec.
 I= 9 L=      87        Time=       2.380 Sec.
 I=10 L=     174        Time=       2.377 Sec.
 I=11 L=     349        Time=       2.380 Sec.
 I=12 L=     698        Time=       2.376 Sec.
 I=13 L=    1396        Time=       2.379 Sec.
 I=14 L=    2794        Time=       2.374 Sec.
 I=15 L=    5588        Time=       2.371 Sec.
 I=16 L=   11176        Time=       2.358 Sec.
 I=17 L=   22353        Time=       2.324 Sec.
 I=18 L=   44707        Time=       2.266 Sec.
 I=19 L=   89415        Time=       2.104 Sec.
 End of main loop
 End of calculation.    Time=      46.937 Sec.
 End of data output.    Time=       0.195 Sec.
 Total calculation(I/O) time=      47.132(       1.321) Sec.

COSUMIはCPUがボトルネックなので、このあたりの数字が結構気になるのですが、とりあえずOKかな? ただ、今現在さくらのサイトでは、CPUはIntel CeleronまたはIntel Atomってなっていますので注意してください。Atomにもいろいろ種類があると思うのですが、どうなんでしょうか?

OSはCentOS 5のみです。上位のプランだともっとたくさんの種類の中から選べるのですが、個人的には他の選択肢があったとしてもCentOS 5を選ぶと思うので、別に構いません。

OSは選択できませんが、パッケージ構成は、「標準構成」と「最小構成」の二つから選べます。うちは最小構成なんですが、今さくらのサイト見てみると、最初はウェブサーバも入ってなかったんですね。自分で入れた記憶がちょっと無いんですが…(笑) 参考までに今現在こんな感じ。

$ rpm -qa | wc -l
478

自分で入れたパッケージはそんなにたくさんはないはずです。

それから、標準サービスとしてトラフィックレポートを見ることができるのがGood! サーバでの設定等は一切必要ありません。

専用サーバ|トラフィックレポート – さくらインターネット
http://server.sakura.ad.jp/dedicated/service/traffic.html

全体的な感想としてはかなり満足です。とりあえず今までのところ安定して動いてますし、サーバのレスポンスも悪くないと思うので。価格もまあ妥当ではないでしょうか? 初期費用が0っていうのは、気軽に始められるのですごくいいです! だめならだめでどこかに乗り換えればいいだけですしね。月額10,000円以下の専用サーバを探している時は、候補に入れてみてはいかがでしょうか?

[追記]
他の方が書かれたこちらの記事も参考にしてみてください。

さくらの専用サーバーエントリープランが良かった6つの理由(+嫌な点3つ)
http://p0t.jp/archives/2008/10/post-35.html

クオリティの高い背景画像がダウンロードできる ava7 patterns

さまざまなテイストのハイクオリティな背景画像がダウンロードできるサイトです。現時点で500種類以上公開されてます。

ava7 patterns | free seamless background patterns
http://patterns.ava7.com/

使用条件は、「ウェブサイトで使う時はリンクしてくれるとうれしいけど、絶対必要ってわけではないよ。でも、売ったり配布したりするのはダメ!」みたいな感じ。さっそく、COSUMIで使わせてもらうことにしましたが、すごくいいです!(色合いは少し変えちゃってますが… 改変はOKだよね?) ずいぶん品が良くなりました。

対局リプレイ

COSUMIで、対局後に対局のリプレイを見ることができるようになりました。

オンライン囲碁 COSUMI
http://www.cosumi.net/

対局リプレイのURLはその対局固有のものになっていて、とりあえずブックマークに入れておいて後からゆっくり見たりすることができます。さらに、他の人に見てもらうこともできるので、友達にメールで送ったり、ブログに載せたりして見てもらうのもいいかもしれません。「そうは言うけど、URLがちょっと長すぎるよ!」って人は、TinyURLのようなURL短縮サービスでも使ってください。余談ですが、この手のサービスが最近ほんとたくさんあるんですね。セキュリティなんかが少し気になるところです。

主なURL短縮サービス14個の長所と短所(その1) | Web担当者Forum
http://web-tan.forum.impressrd.jp/e/2008/10/06/4134
主なURL短縮サービス14個の長所と短所(その2) | Web担当者Forum
http://web-tan.forum.impressrd.jp/e/2008/10/07/4135
主なURL短縮サービス14個の長所と短所(その3) | Web担当者Forum
http://web-tan.forum.impressrd.jp/e/2008/10/08/4136

話し戻って対局リプレイですが、URLのパラメータを変更することで、COSUMIで打った対局以外の棋譜のリプレイも見ることができるようになります。URLを見ればだいたいの意味は分かると思いますが、よければこちらも参考にしてみてください。13路盤までしか対応していないのがなんですが、自由に使っていただいてかまいません。

[追記]
対局リプレイを19路盤にも対応させました。さらに、手持ちのSGF形式の棋譜をこの機能を使って再生できるように、簡単なウェブフォームも用意しました。棋譜を貼り付けて送信すると、その棋譜に応じたURLへリダイレクトします。何かの時に少しは便利かもしれません。

http://www.cosumi.net/sgf2replay.html

自前のSGFのパーサはあまり賢くないので、そこは大目に見てください(笑)。

13路盤

COSUMIで13路盤の対局もできるようにしました。

オンライン囲碁 COSUMI
http://www.cosumi.net/

定石はとりあえず3228局面分用意しました。時間がある時にまた追加します。併せて、COSUMI APIも13路盤まで対応しました。

これより大きな碁盤に対応することは、たぶんもうありません(笑)。

定石アップデート 9路盤-15676局面 11路盤-6862局面

COSUMIの定石をアップデートしました。今現在、9路盤が15676局面分、11路盤が6862局面分です。

オンライン囲碁 COSUMI
http://www.cosumi.net/

全部ではないですが、COSUMIが負けた棋譜をひとつひとつ並べて調べて、定石を追加・修正しました。これで少しはましになったかな? これからも、この方法で少しずつ改善させていくつもりです。

とっても囲碁なWeb APIを作ってみました

囲碁の棋譜を送るとその次の一手を考えて返すという、とっても囲碁なWeb APIを作ってみました。今現在のところ、9路盤と11路盤のみにしか対応してませんので使い道はかなり限られると思いますが、このWeb APIを利用した楽しい「なにか」を、だれかが作ってくれたらうれしいです。

囲碁Web API 「COSUMI API」
http://www.cosumi.net/api.html

このWeb APIは、あくまでサーバのリソースが余っていたら仕事するって感じなので、サーバが過負荷な状態の時は手を考えないでエラーレスポンスを返すようになっていますが、今現在ならほぼ24時間いつでも正常にレスポンスを返せると思います。こういうWeb APIは継続してサービスを提供し続けることがすごく大切だと思うので、約束は一切できませんが、できるだけ長い期間使えるようにがんばります!

「仕様がおかしい!」とか、「仕様どおりに動いてない!」とかがあればぜひ教えてください。それもできるだけがんばって直してみたいと思います。

[追記]
13路盤にも対応しました。

定石アップデート 9路盤-14148局面 11路盤-5246局面

COSUMIの定石をアップデートしました。今現在、9路盤が14148局面分、11路盤が5246局面分です。

オンライン囲碁 COSUMI
http://www.cosumi.net/

気力はあるんですが、棋力がそろそろ限界です…(笑) もう少し詰碁の勉強とかやらないとだめですね。

Flashは動き始めるまでにダウンロードが完了しているとは限らない

以前からたまに、COSUMIのオンライン対局のFlashが動かない時があってちょっと気持ち悪く思っていたのですが、ようやくその原因が分かりました! どうやら、自身のswfファイルのダウンロード完了を待たずして動き始めたFlashが、まだダウンロードできてない部分のデータを必要として問題が起こっていたようです(なので、ブラウザがそのswfファイルをキャッシュに持っている時は問題が出なかった)。うーん、Flashというのは、ファイルがすべてダウンロードされてから動き始めるわけではないんですね! 一度分かってしまえばごくごく単純なことなんですが、Flashは最近初めたばかりなので、このあたりの基本がなってませんでした…

ということで、今回はMovieClip.getBytesLoadedMovieClip.getBytesTotalを使って、自身のswfファイルのダウンロードが完了するまでは、メインの動作を始めないように直しました。たぶんこれで大丈夫だと思います。

回線の速度やブラウザの種類、それからPCのスペックなども関係してくると思うので、はっきりしたことはよく分かりませんが、今までどれくらいの確率で動かなかったのかを考えるとめちゃくちゃ恐ろしい…(笑)

11路盤

COSUMIで11路盤の対局もできるようにしました。

オンライン囲碁 COSUMI
http://www.cosumi.net/

このところ7路盤や9路盤ばかり見ていたので余計にそう感じるのですが、11路盤ってけっこう広いですねー 2路しか違わないのに、明らかに9路盤とは違う感覚が要求されるような気がします。なんだかもう、初手からしてどこに打っていいのかよく分からないような状態なんですが(笑)、とりあえず2590局面分の定石をなんとか用意しました。ついでに9路盤も定石を追加・整理して、こちらは今現在11352局面分です。GNU Goの11路盤はなんだかちょっとあやしい感じがあるので、できるだけ定石でごまかしてしまいたい(笑)。

シックでポップなフリーフォント Fontin

今日3つ目の記事は、Fontinというフォントです。COSUMI全体で多用させてもらっています。

Fontin :: a Free Quality Font from exljbris
http://www.josbuivenga.demon.nl/fontin.html

上品さとカジュアルさが同居した感じの、すてきなフォントですよね! 個人的にかなりお気に入りです。さらに、「Flashにも埋め込み可」という緩いライセンスがほんとありがたいです。

先のサイトでは、これ以外にもいくつかの非常にクオリティの高いフォントを公開されていますので、興味のある人はぜひチェックしてみてください。

xyzzy用のactionscript-mode

今日2つ目の記事は、xyzzy用のactionscript-modeです。これは特に説明は要りませんね!

ActionScript mode for xyzzy
http://shield.jp/~dseg/xyzzy/actionscript-mode/

機能の詳細はリンク先で調べてください。コードヒントが文字化けする場合は、こちらページの一番下を参照のこと。一応ActionScript 2.0までに対応って感じみたいですが、3.0でも重宝するんじゃないでしょうか?

余談ですが、Flash制作のためにFlash Basic 8を購入したのですが、今これを少し後悔しています。と言うのも、本当に買うべきだったのは、Flex Builder 3だったような気がしてならないんですよね… 気分が悪くなるので、Flex Builderでなにができるのかあまり調べていません(笑)。

効果音を作成するのに便利なソフトシンセ Beam2002

今日は、COSUMI制作時にお世話になったソフトなどを3つ記事にします。1つ目は、Flashで使う効果音を作るのに使用した、Beam2002というソフトウェアシンセサイザーです。かなり簡単にいろんな音が作り出せるので、これはけっこうおすすめです。

Beam2002 / Cycle of 5th
http://www.cycleof5th.com/products/beam2002/

次の3つの効果音を、このソフトで作ってみました。

石音
ボタンにマウスカーソルを乗せた時の音
ボタンをクリックした時の音

どうですか? なかなかいい感じでしょ! バリバリとか、ガラガラとか、ドスドスとか、もっと過激な音も、もちろん作成可能です。うーん、こういうソフトは、いじりだすと止まりません…(笑)

「オンライン囲碁 COSUMI」始めました

コンピュータと対局できるオンライン囲碁サイトを、GNU Goを使って作ってみました。かなり以前からやってみたかったのですが、これがなかなかたいへんで、ひとまず公開できて今は少しほっとしています。

オンライン囲碁 COSUMI
http://www.cosumi.net/

とりあえず今は、7路盤と9路盤が遊べます。初心者向けですね。基本はGNU Goなんですが、それとは別に独自に用意した定石からも手を探すので、対局ごとにいろいろな形になる分、普通にGNU Goと対局するよりは面白いかもしれません(たぶん、ちょっぴり攻撃的です)。ちなみに今現在、9路盤の定石が10908局面分入ってます(対称形を重複して数えてますので、実質的にはもっと少ないですが…)。

今後、「定石を充実させてもう少し強くすること」と「11路盤の対局ができるようにすること」の2つは、必ず実現したいと思います。他にもいくつかやってみたいことがあるんですが、自分のスキルの問題もあって(笑)、何ができて何ができないのかまだよく分かりません。とにかく、少しでも多くの人にこのサイトで囲碁を覚えてもらえればと思っています。気軽に遊んでみてください!

それから、英語のページも用意したんですが、英語がおかしかったら教えていただけると助かります。

それからそれから、7路盤や9路盤用のスペシャルGNU Goの作り方を知っていたら教えていただけるとすごーく助かります。board.hMIN_BOARDMAX_BOARDMAX_HANDICAPだけは変更したんですが(ちなみにこれは有意な差がありました)、他に何か無いでしょうか? ここはけっこう切実なんですが…