FC2ブログ

*All archives* |  *Admin*

<<09  2018/10  1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31  11>>
はじめてのpython&Tensorflowその10・自分ツモ番の選択ほぼ完成
前回(はじめてのpython&Tensorflowその9・他家リーチ)から、
他家副露者なしの条件を外して、自分ツモ番での選択についてすべて判断可能にしました。

入力チャンネルの追加項目はだいたい前回書いた通りです。
他家一色手模様に関する指標として、(染め色がマンズの場合、)「最初にマンズが切られるまでに切られたピンズ・ソーズの枚数」という項目を加えました。
また、「ある牌が最後に通ってからの手出し回数」に加え、「ある牌と同一筋が最後に通ってからの手出し回数」も入力チャンネルに加えました。

入力チャンネル数は全部で56個になりました。
考慮すべき項目がだいぶ増えたので、フィルター枚数をさらに倍化の128枚にして、
バッチサイズ100×ステップ数1000×epoch数100と10倍の学習量にしました。

読み取るべきcsvの列数も増えて、重みパラメータの数も増えて、epoch数も10倍にしたので、
学習時間は丸1日~2日まで増えました。

まぁ、自分ツモ番に関しては今回ので完成形になるので、この程度の時間で済んでくれるなら安いもんだろうと。
ただ、後で入れ忘れた項目とかcsvからの変換のコードにバグがあったりすると悲惨です。
実際、他家リーチ一発状態を入れ忘れて1回やり直しになって1日強の間待ちぼうけでした。

学習結果はこんな感じ↓。
181030-01.png
損失関数も徐々に減っていって、最終的に正解率は66%overまで来ました。
他家リーチとか副露みたいな対応もまずまずの確度で当てられると。
学習が終わるまでじっと待った甲斐がありました。


実際の手牌との突合せがこちら↓。
181030-02.png
上位2牌の予測が成功してるのは86%まであるので、全体としてはだいぶ実際の牌譜と整合させることができてるかなーと思います。

次の課題は他家から鳴ける牌が出た時の反応についてです。
他家に対する警戒に関する項目はツモ番のときをそのまま流用できます。
自分手牌に関する項目についても、だいたい似たような感じで作れると思います。
シャンテン数や手役関連はスルー時と鳴き時で分ける必要があるとかはちょっとツモ番時とは異なってきそうですが。
難しそうなのは鳴き方が複数ある場合とか、喰い替え禁止あたりをどう表現するかですが、自分の中ではプランはある程度あるので、思い描いたどおりに入力チャンネルの設計ができるかどうかだけです。
まぁ、そこまではなんとかなるでしょう。最悪、場合分けしまくってチャンネル数特盛設計にすればいいです。

そうして、SLポリシーネットワークまでできたら、アルファ碁みたいにReinforceアルゴリズムで強化学習で強くするパートまで見えてきます。

今のところ抱えてる大きな課題は二つ。

・Pythonやkerasで強化学習ってどうすればいいんだ?なんかkeras-rlというもので強化学習ができるらしいという情報まではつかんだのですが、Q学習のサンプルコードは割と見つかったのですが、方策勾配法やReinforceアルゴリズムでは情報が少なくて調べるのが難航してます。actor-criticとかDDPGならkeras-rlの関数でできるらしいけど、普通の方策勾配法のやり方がわからない。
actorが既知(今やってるSLポリシーネットワーク)でcriticが未知みたいな状況なので。
がんばって英語のサイトを探し回るしかないのだろうか。
強化学習については全然素人なので、細かい理論的なところまで頭が回らないです。いちおう、前に薦めてもらった「これからの強化学習」は入手済みで読んだけど、ちょっと難しすぎて何言ってるかわからないです。

・強化学習をするにあたって、ゲームの流れやSLポリシーネットワークなりRLポリシーネットワークなりに突っ込む用のデータ作成のために、今までVB.NETで書いてきた各種関数をPythonで書き直さないといけないことがほぼ確定事項な感じ。最低でもシャンテン計算と、アガリ時メンツ切り分けと、アガリ役判定は必須です。とりあえずものすごくがんばってPythonへの移行を考えなきゃいけないことだけはわかった。

強化学習ができれば、PCのスペックが許す限り、無尽蔵に牌譜を生み出せるので、「アルファ碁解体新書」に書いてる方法で、バリューネットワーク(評価値の算出)まで行ける公算が高いのですが、道はまだ険しいですなぁ。
スポンサーサイト



報告と宣伝
来年発売予定の「科学する麻雀2(仮)」の内容との兼ね合いで、最近書いた「シミュレーションとはなにか」の文章を非公開とさせていただきました。

「科学する麻雀2(仮)」にはこの前の記事よりも詳細な内容を書いているので、発売までもうちょっとお待ちいただけたらと思います。
はじめてのpython&Tensorflowその9・他家リーチ
前回(はじめてのpython&Tensorflowその8・自分副露)から、

他家リーチ者ありのケースを訓練データに追加、入力チャンネルに他家リーチかどうかと、各牌の現物筋変数状況を追加。

今回もチャンネル数が増えただけで、モデルの構造に大きな変化はないのでTensorBoradのグラフ図は省略。

損失関数と正解率のグラフ↓。
181026-01.png
途中で折れ曲がってるのは、最初の10epoch回して学習を打ち切ったのですが、グラフの曲線的に学習を進めればもうちょっと改善できそう?と思って、さらに10epoch追加で学習させたためです。

他家リーチへの対応とかいう普通の手作りと別要素が入ってくるにもかかわらず、正解率65%超えまで進んでくれていい感じ。
さらに学習を進めれば、まだまだ損失関数の改善が見込めそうですが、とりあえず試作段階なので、このへんで終えておきます。

手牌との突合せが↓。(最初の100件)
181026-02.png
全体のバランス的にはリーチ者なしのサンプル数の割合のほうが高いので、前回とそんなに変わらないように見える。

対面リーチがある場合でフィルターをかけたものの最初の数十件↓。
181026-03.png
対面リーチの件数は10000件中386件。予測1位的中率は58%、予測2位まで的中だと75%になってます。

対リーチだと手が広いことのほうが多い(現物や安全そうな牌が3種以上あるとか、危険牌を切って押し返しもあるとか)ので、全体よりは正解率は落ちますけど、それでも6割弱は正解を当てられてるというのは、自分としてはなかなかいいんじゃないか、と思いましたが、どうですかね?

次の課題は他家副露です。これで訓練データの制限は全部外れる(自分リーチの場合以外)ので、自分ツモ番についてのポリシーニューラルネットの決定版になりそうです。
ただ、他家副露まで含めると考えるべき要素が多くなるので、うまいこと入力データを作れるといいですが。
考えてる追加項目とすると、
・他家が副露しているかどうか、もしくは門前状態であるかどうか。
・他家副露数
・他家副露種類
・他家副露牌
・他家副露の見えてる役・ドラの枚数
・捨て牌が一色模様かどうか
・同巡フリテンと同巡筋牌
・ある牌が最後に通ってからの手出し回数
・同色5が切られてるかどうか、もしくは切られた巡目
・同色内側牌が切られてるかどうか、もしくは切られた巡目
・親番が誰か
・他家3人の役牌情報
・4人の点数
・残り局数
・積み棒、供託リーチ棒

うん、たくさんあるね。

一番難しそうなのは「捨て牌が一色模様かどうか」をどう定義してニューラルネットに組み込むかですね。

csvの容量的にもけっこう大変なことになってきてます。
現時点でエクセルで「AAR」列まで1件あたりのデータが増えてきてます。列番3桁は初めて見る。
はじめてのpython&Tensorflowその8・自分副露
前回(はじめてのpython&Tensorflowその7・リーチと暗槓)からの追加項目として、
自分が副露手の場合を訓練データに追加しました。(他家については従前どおり3人非リーチ門前)

入力項目の追加は、
・チートイシャンテン数
・国士シャンテン数
・副露数
・副露種類(役牌・タンヤオ・その他)
・副露牌
・副露牌も入れた手牌枚数
です。

入力チャンネルが増えただけで、モデルの構造はほぼ変化がないので、TensorBoradのグラフは省略。

損失関数と正解率のグラフ↓。
181024-01.png
たぶんそんなに変わりはない。

手牌との突合せ↓。(最初の100件)
181024-02.png

副露している手牌についてフィルターをかけたもの↓。
181024-03.png
門前手と比較してもそこまで変な結果にはなってなさそう。

リーチされた手牌についてフィルターをかけたもの↓。
181024-04.png
前の時より予測リーチ率上がった?


ここまで、他家攻撃なしについて、65%弱程度の正解率で打牌決定ができたことになったと思います。
次はいよいよ他家攻撃ありの場合に移ろうかと思います。
やっと四人麻雀ができるぜー。
まずは対リーチでちゃんと判断ができるかどうかですね。

追加項目として考えてるのは、
・他家3人について、リーチをしているか。
・他家3人について、各牌の現物筋無筋状況。
とりあえずはこれだけで、ちゃんと対リーチ対応をやってくれることを祈ろう。
はじめてのpython&Tensorflowその7・リーチと暗槓
前回(はじめてのpython&Tensorflowその6・手役情報と複数回畳み込み計算)からの追加項目として、
自分のツモ番における選択肢として、牌を切る以外に、リーチ宣言と暗槓があるので、今回はその部分を入れました。

ニューラルネットの構造としては、出力値として、従前の牌番号だけから、リーチ宣言したかどうかと、暗槓したかどうかの出力値を2つ足した感じになります。
分岐は最後のDense計算層(従前だとdense_3層)からにしています。

損失関数は各出力ともクロスエントロピーで、3つの損失関数の単純加算した値を最小化させる最適化です。特に工夫もなくふつうです。

入力チャンネルの追加は、
・打牌可能か
・リーチ可能か
・暗槓可能か
の3つです。

構造はこんな感じ↓。
181022-01.png

損失関数と正解率はこんな感じ↓。
バッチサイズ100、1epochあたり1000ステップで、10epoch分回した。
181022-02.png

損失関数のカーブ的にまだ改善の見込みはありそうだけど、まぁ計算時間の都合で今回はこのへんにしておく。

リーチのほうはまだましですが、暗槓については全体のデータ数から見てだいぶレアケース(テスト用データ10000件中暗槓は6件のみ)な分、損失関数の値が小さすぎてほぼ機能してない疑惑。

手牌との突合せ↓(最初の100件)
181022-03.png
まぁこれは従前と似たようなものか。

実際にリーチ宣言されたデータについての予測値↓。
181022-04.png
さっきのよりは予測リーチ率は高めに出てくれてるけど、予測リーチ率5割以上を正解とみなす場合、けっこう5割に届いてないケースが多いです。

特に七対子聴牌のケースについては予測リーチ率が低くてちょっと適応できてない感があります。
後、赤5を切って聴牌のケースもうまく予測できずに弱点になってるっぽい。
このへんは学習量を増やせばなんとかなるものなのかなー。

実際に暗槓されたデータについての予測値↓。
181022-05.png

暗槓がまともに機能してない疑惑的中。
暗槓可能情報やリーチ可能情報を入力層のチャンネルの中に埋め込むんじゃなくて、別口でもうちょっと上のDense層とかに直接突っ込んだほうがいいのだろうか?


次の課題
・七対子国士情報追加
・リーチ暗槓可能情報の入れる場所
・自分副露手の打牌選択
理牌をするための必要並べ替え回数
今日はちょっとした小ネタを思いついたので、Pythonの練習がてらにやってみました。

リアル麻雀で、普通に山から4枚ずつ取ってくるのでも、自動配牌卓でもどちらでもいいですけど、
配牌を取ってくると普通は牌の順番がばらばらなんで理牌する必要がありますよね。

理牌をするための牌の入れ替え回数って平均で何回くらいなんだろう?というのが今回のテーマです。

並べ替えの法則は以下の通りとします。

①13枚の配牌をランダムに取る。
②左側にソート済みの手牌、右側に未ソートの手牌を置く。
③左からi(i=2~13まで繰り返し)番目の牌について、ソート済み手牌の右端の牌より牌番号(マンズ1~9、ピンズ10~18、ソーズ19~27、字牌28~34。赤牌は区別しないものとする。)が小さい場合、ソート済み手牌の中の適切な場所に左からi番目の牌を移し、入れ替え回数を+1する。ソート済み手牌の右端の牌と同じ牌か牌番号が大きい場合はそのままの順番で合ってるので、次のi+1番目の牌の比較へと移る。
④ ①~③を10万回繰り返し、各シナリオの牌の入れ替え回数を記録する。

だいぶ原始的なソート方法です。専門用語で〇〇ソートとかいう名称がついてるんでしょうけど、詳細は知らないです。

ソースコードはこんな感じ↓。
181020-05.txt

結果はこんな感じ↓。
181020-04.png

平均値は9~10回くらいの並べ替え回数になってます。めんどくさいですね。

熟練者だと色とか昇順降順を変えるとかで、もっと並べ替え回数の少ない方法があったりするんでしょうけど、私レベルではよくわからないです。

今日の結論:自動理牌のあるネット麻雀は神。
はじめてのpython&Tensorflowその6・手役情報と複数回畳み込み計算
前回(はじめてのpython&Tensorflowその5・ドラや役牌などの情報追加)から、

・畳み込み計算のフィルター枚数を32枚→64枚へと倍化。
・2次元畳み込み計算後全牌連結前に1次元畳み込み計算を2回はさむのを追加。
・手役関連情報(一色手限定シャンテン数、トイトイ限定シャンテン数、タンヤオ限定シャンテン数、チャンタ限定シャンテン数、三色一通に足りるパーツの数)の追加

モデルの構造↓
181020-01.png

損失関数・正解率↓
181020-02.png

手牌との突合せ↓
181020-03.png

入力内容やパラメータの数が増えてステップあたり学習時間は増えたが、それに見合った効果が得られているかどうかはだいぶあやしい。

次は自分副露時とリーチ宣言まわりをどうやるかを考えましょうかね。
はじめてのpython&Tensorflowその5・ドラや役牌などの情報追加
前回の最後で書いた通り、
手牌の枚数のみでなく、巡目・ドラ・赤5・役牌・シャンテン数・見えてる枚数の情報を足してニューラルネットを組みました。

情報を今後どんどん足していくことを考えると、csvを事前に読み込んでおくとメモリが足らなくなりそうなのは明らかなので、
ジェネレータというのを使ってcsvを都度読み込みする方式に変更しました。

ジェネレータ導入の副産物として、あらかじめ定義してあるジェネレータ関数の中で入力値を加工する(色ごとに配列を分けるとか、one_hotベクトルの生成など)のが簡単になりました。
Lambdaレイヤーとかで苦労してぐちゃぐちゃとデータをいじる必要がなくなったのはプログラミング難易度的に下がってうれしい。
Tensorflow関数を使わずに済んだので、model.saveも通るようになったのもいい感じ。

TensorBoradによるモデルグラフはこんな感じ↓。
181017-01.png
前回の畳み込み層以下のLambda層などの集団が一掃されました。

入力はあらかじめ牌譜解析で必要な情報をcsv化してあるのをジェネレータ関数内で下処理してマンズ、ピンズ、ソーズ、字牌ごとに分けたnumpy配列。

ドラや役牌等の情報を足した分、畳み込み計算の入力チャンネル数が1から7に増えました。
変数の値を1か所変えるだけでshapeが異なる畳み込み計算もすぐにできるのはkeras様様ですね。
というか、今までそういうめんどいのを自力で実装しようとしてたのは車輪の再発明みたいで頭の悪さ全開でした。


正解率、損失関数はこんな感じ↓。
181017-02.png
val_acc(テストデータの正解率)の方で63%へと前回からさらに向上しました。

実際の手牌と予測値との突合せがこんな感じ↓。
181017-03.png
そこまで予測値がおかしくなってるのは多くはなさそうでいい感じ。


次の課題として考えられるのは、
・畳み込み計算を複数回噛ませることができないか?もしそうするとすると、色ごとに分けたものを使うのか、1回畳み込み後に結合したものを使うのか。
・手役狙い(主に一色手・トイトイ・三色・チャンタあたり)をどう考えるか。
・自分副露時の情報をどのように追加するか。

どれも一筋縄ではいかないというか、モデルの構想力が試される感じです。
とりあえず畳み込み計算についてもうちょっと勉強して理解を深めておきたいところです。
はじめてのpython&Tensorflowその4・手牌枚数で畳み込みニューラルネット
前回で、Denseを直列つなぎしただけのちゃちなニューラルネットを組みましたが、
今回はそこから卒業してアルファ碁みたいに畳み込み計算をやってみようと思います。

大量のエラーメッセージの波をかき分けながら、なんとかモデルのコンパイルが通りました。
型変換するだけとか、ベクトルのサイズ変更するだけでもえらく大変でした。kerasたん、ツンデレすぎる…。
ググって調べる能力だけでなんとかやってきてます。

今回組んだニューラルネットの構造はこんな感じ↓。(TensorBoradのグラフ図)
181014-02.png

入力は前回と同じで、37種牌の枚数を要素にもつ37次ベクトル。
まずは入力のベクトルをマンズ、ピンズ、ソーズ、字牌の4つに分割しています。

その4区分に対して、下のほうのlambda_〇みたいな層がいっぱいあるのは畳み込み計算ができる形に整形をするなどの下ごしらえ工程です。

マンズ、ピンズ、ソーズについては数牌フィルター(サイズ5×6、重みパラメータは共有)32枚を通す2次元畳み込み計算をしています。(conv2d_1層)

字牌については数牌とは別個のフィルター(サイズ1×6)32枚を通す2次元畳み込み計算をしています。(conv_2d_2)

で、出力がshape9×32が3つと7×32が1個出てきたのを統合してるのが、その上のconcatenateの層。
そこからは前回と同じ感じで全結合3回を直列させてるのを計算してます。

なんかすんごいぐっちゃぐっちゃにかき回してるだけの汚いニューラルネットですね。

それで上記のようなニューラルネットで学習させたのがこんな感じ↓。(1万試合分の手牌で、10epoch)
181014-03.png
前回の正解率44%から、今回は57%くらいへと評価値がだいぶ向上してます。
汚くても結果が出ればええねん、みたいな。

テストデータ(手牌+正解ラベル)による検証がこちら↓。(サイズがでかすぎるとエクセルでの取り回しが効きにくいので、10000試合だけ抜き取った。)
181014-01.png
2位的中率まで含めれば82%まで予測的中率が上がってます。だいぶいい感じです。
畳み込み計算によって当該牌の周囲の形を見ることができるようになったのが表れてるのかなーと思います。


〇現在困ってること
model.saveをしようとするとエラーが出る。
model.save_weghitsは通る。
model.to_jsonは通らないので、重みのセーブはできるけど、ニューラルネットの構造がセーブできない状況。(現在は訓練用と同じコードを予測用プログラムでもコピペすることで応急的に対応してる。)
おそらく、原因は、
kakou_manzu = Lambda(tf.cast,arguments={'dtype':tf.int32})(kakou_manzu)
の行(テンソルのdtypeをfloatからintに変えたい)で、kerasの関数でなくTensorflowの関数を使ってるため。
kerasの関数で型変換ができればたぶんmodel.saveも通るので、構造のセーブができると思うのだけど、何かいい方法はないだろうか?


次は、入力情報を増やす(畳み込み計算の入力チャンネル数を増やす)ことをやろうかと思っています。

入れようとしている情報として、
・巡目
・ドラ
・赤5牌
・役牌
・当該牌を切った時の面子手シャンテン数
・当該牌を切った時の対子数(七対子がらみ)
・当該牌を切った時のヤオ九牌種類数(国士がらみ)

また牌譜解析からcsvを取って、それをPythonで読み取ってうまいことNNの設計をして、…みたいなイメージ。
はじめてのpython&Tensorflowその3・他家攻撃なし、手牌枚数のみニューラルネット
前回で、Pythonの機械学習で自力での応用ができるようになった(多分)ので、
いよいよ麻雀におけるデータで試してみたいと思います。

まず最初は前回でも書いた通り、
他家攻撃なしかつ手牌の枚数情報のみを入力値にして、
てきとうなニューラルネットにぶちこんでみます。
本当に手牌の枚数情報のみなので、巡目もドラも役牌種類も全然考慮してません。

入力データは最初の1000試合分、約13万種類の手牌を訓練用に最初の6分の5の11万種類を充て、残りの6分の1の2万種類をテスト用(評価用)としました。
出力値は37種類の牌の切られる確率の予測値です。

ニューラルネットの構造
・入力層…37種類の牌の手持ち枚数
・隠れ層1…全結合でノード数64、活性化関数Relu
・隠れ層2…全結合でノード数64、活性化関数Relu
・出力層…全結合でノード数37、活性化関数ソフトマックス
・損失関数…クロスエントロピー

TensorBoardとやらでニューラルネットの構造を可視化というものをやってみたらこんな感じ↓。
181011-02.png
とりあえず今の私には理解が難しいことだけわかった。

正解率(おそらく予測切られ率で最も大きい牌番号が実際の正解ラベルと同じである確率と思われる。)と損失関数の推移もTensorBoradによるとこういう感じらしい↓。
181011-03.png
多分左側のvalがないほうが訓練用データの正解率(acc)と損失関数(loss)で、右側のvalがついてるほうがテスト用データの正解率と損失関数だと思われます。

学習が進むにつれ正解率は上昇し、損失関数は減少しているようなことがわかります。
10epoch回した結果、テストデータの正解率で44%くらいということです。
37種類の牌もしくは手牌にある牌のどれかを切れる中で、5回に2回は実際に切られた牌と同一の予測をできるのは、初回で適当に組んだだけで、役牌とかドラとかも考慮してないにしてはまずまずの結果じゃないかなーと思います。

結果をエクセルでまとめるとこんな感じ↓
181011-01.png
テスト用データについて、予測率が1番高い牌番号と2番目に高い牌番号を取ってきて、1位的中率と1位or2位の的中率を出してみました。
(牌番号1~10がマンズ、11~20がピンズ、21~30がソーズ、31~37が字牌)

特徴として、
予測1位や2位の牌はことごとく字牌や端寄りになってる感じです。
全員リーチも副露もしてないので、データが序巡に偏ってるためかなーと。
真ん中牌が切られるケースは外れデータみたいな扱いをされてるのかもしれないです。
まぁ、手持ちにない牌が予測1位や2位になるケースはほぼなさそうで安心。


次はニューラルネットの構造をもうちょっとましにして実用的にしようかと思います。
具体的には枚数と重みパラメータのテンソル積の全結合にするんじゃなくて、アルファ碁みたいに畳み込み計算を導入してパラメータの個数を減らして計算時間にかかる負荷を減らそうかと。

まだKerasについて十分理解していないので、全結合と単純な畳み込み計算以外の方法を知りませんが、調べたらどこかに載ってるかなぁ。
プロフィール

nisi5028

Author:nisi5028
FC2ブログへようこそ!

最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
FC2カウンター
フリーエリア
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム

この人とブロともになる

QRコード
QRコード