2017-08-22(Tue)
なんかかなり迷走した感はありましたが、危険度を加味した評価関数がなんとかなりそうになりました。
(前回のデータベースうんぬんの話は結局うまいこと使いこなせなかった。)
今回の話はこちらのサイトを参考にしました。
http://www.anlp.jp/proceedings/annual_meeting/2015/pdf_dir/D3-3.pdf#search=%27%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92+%EF%BD%86%E5%80%A4%27
http://www.procrasist.com/entry/ml-metrics
前までの話は全体正解率(に近いもの)を最大化しようとしていましたが、
これをすると、母集団が多いスルーの方に大きく引っ張られてほぼどんな状況でもAIはスルーと回答するようになっていました。

この表で言うと、全体正解率は(TP+TN)/(TP+FP+FN+TN)ですが、このうち、TPとFP(鳴くべきなのにスルーと回答)がかなりの部分を占めている形になっていました。
重要と思われるのは、スルーと回答した場合に実際にスルーすべき手である割合(適合率、Precision、TP/(TP+FP))とか、鳴きと回答した場合に実際に鳴くべき手である割合(真陰性と仮に命名、TN/(FN+TN))であろうかと思います。
一般的な機械学習だとF値というもので2値分類器の良し悪しをチェックすることが多いらしいです。
なので、今回は損失関数的なのをやめて、上記サイトの理論を利用させてもらうことにしました。

入力する情報は、評価値(攻撃面の手牌価値のみ)・巡目・親かどうか・副露数・字牌枚数(この2つは主に守備力関係のつもりで入れた。)・切る牌の危険度指数で、これに対して学習データでは実際に選ばれた行動(スルーとか鳴きとか)が出力値としてあります。
前回は評価値と危険度指数だけで、判断する材料が少なかった、ということが考えられたので巡目とかいろんなものを判断材料として増やしました。
それで、これら入力値に対して危険度を加味した評価値を↑の関数fでモデル化します。
それで、適合率とかは離散的な値でパラメータpで微分できないので、そこを回避するために、
シグモイド関数で微分可能な形に置き換えます。
鳴きについてはその後の打牌候補が複数あるので、そのうちの最も評価値が高いものをスルーとの比較対象にする。

このとき、目的の関数F値(αはとりあえず0.5にしておいた。)は次のように表すことができます。

…理論上はpで微分可能かもしれないけど、実際問題これを微分したものを求めるとか極めて無理な雰囲気しかしないです。
幸い、今回は変数の数がそこまで多くない(各30個ずつ)ので偏微分を数式で計算せずに、近似的な偏差分(1個のパラメータを0.0001とか動かしてF値の差分を計算して0.0001で割る。)を計算機に無理やり計算させる方向にしようかと思います。
それで計算した結果がこちら。
(ただし、準ニュートン法のアルゴリズムの調子が悪くて最急降下法に変えたので、収束性はイマイチかもしれない。0副露のみ1000試合分で、それ以外は1万試合分のデータ。)

変数が多く、込み入っているので具体的にはわかりづらいですけど、
前回みたいにほぼ全部スルーと回答している状態は脱していそうな感じです。
ただ、実際に出力結果を見たり、この文章を書きながら思ったのはF値の構成要素のうちPrecisionの方はいいとして、Recall(TP/(TP+FN)、実際にスルーされた手を正しく選別できる割合)って別にどうでもよくない?みたいには思いました。(どうでもいいことはないけど。)
それよりは真陰性(TN/(FN+TN))が高い方がうれしいような気がします。これが高いということはAIが鳴いた場合は実際の鳳凰卓の打ち手も鳴いている、ということを表していると思うので。
理論的に意味ある数値かどうかはわからないけど、一回Recallを真陰性に置き換えたバージョンも作ってみようか。
後は準ニュートン法アルゴリズムが壊れた(偏微分の符号とパラメータの修正の方向が逆転して全く収束しない)のもなんとかしないとなぁ。私の理解を超えているアルゴリズムを利用するのはどこらへんがおかしいかが見当つかないから大変です。
(前回のデータベースうんぬんの話は結局うまいこと使いこなせなかった。)
今回の話はこちらのサイトを参考にしました。
http://www.anlp.jp/proceedings/annual_meeting/2015/pdf_dir/D3-3.pdf#search=%27%E6%A9%9F%E6%A2%B0%E5%AD%A6%E7%BF%92+%EF%BD%86%E5%80%A4%27
http://www.procrasist.com/entry/ml-metrics
前までの話は全体正解率(に近いもの)を最大化しようとしていましたが、
これをすると、母集団が多いスルーの方に大きく引っ張られてほぼどんな状況でもAIはスルーと回答するようになっていました。

この表で言うと、全体正解率は(TP+TN)/(TP+FP+FN+TN)ですが、このうち、TPとFP(鳴くべきなのにスルーと回答)がかなりの部分を占めている形になっていました。
重要と思われるのは、スルーと回答した場合に実際にスルーすべき手である割合(適合率、Precision、TP/(TP+FP))とか、鳴きと回答した場合に実際に鳴くべき手である割合(真陰性と仮に命名、TN/(FN+TN))であろうかと思います。
一般的な機械学習だとF値というもので2値分類器の良し悪しをチェックすることが多いらしいです。
なので、今回は損失関数的なのをやめて、上記サイトの理論を利用させてもらうことにしました。

入力する情報は、評価値(攻撃面の手牌価値のみ)・巡目・親かどうか・副露数・字牌枚数(この2つは主に守備力関係のつもりで入れた。)・切る牌の危険度指数で、これに対して学習データでは実際に選ばれた行動(スルーとか鳴きとか)が出力値としてあります。
前回は評価値と危険度指数だけで、判断する材料が少なかった、ということが考えられたので巡目とかいろんなものを判断材料として増やしました。
それで、これら入力値に対して危険度を加味した評価値を↑の関数fでモデル化します。
それで、適合率とかは離散的な値でパラメータpで微分できないので、そこを回避するために、
シグモイド関数で微分可能な形に置き換えます。
鳴きについてはその後の打牌候補が複数あるので、そのうちの最も評価値が高いものをスルーとの比較対象にする。

このとき、目的の関数F値(αはとりあえず0.5にしておいた。)は次のように表すことができます。

…理論上はpで微分可能かもしれないけど、実際問題これを微分したものを求めるとか極めて無理な雰囲気しかしないです。
幸い、今回は変数の数がそこまで多くない(各30個ずつ)ので偏微分を数式で計算せずに、近似的な偏差分(1個のパラメータを0.0001とか動かしてF値の差分を計算して0.0001で割る。)を計算機に無理やり計算させる方向にしようかと思います。
それで計算した結果がこちら。
(ただし、準ニュートン法のアルゴリズムの調子が悪くて最急降下法に変えたので、収束性はイマイチかもしれない。0副露のみ1000試合分で、それ以外は1万試合分のデータ。)

変数が多く、込み入っているので具体的にはわかりづらいですけど、
前回みたいにほぼ全部スルーと回答している状態は脱していそうな感じです。
ただ、実際に出力結果を見たり、この文章を書きながら思ったのはF値の構成要素のうちPrecisionの方はいいとして、Recall(TP/(TP+FN)、実際にスルーされた手を正しく選別できる割合)って別にどうでもよくない?みたいには思いました。(どうでもいいことはないけど。)
それよりは真陰性(TN/(FN+TN))が高い方がうれしいような気がします。これが高いということはAIが鳴いた場合は実際の鳳凰卓の打ち手も鳴いている、ということを表していると思うので。
理論的に意味ある数値かどうかはわからないけど、一回Recallを真陰性に置き換えたバージョンも作ってみようか。
後は準ニュートン法アルゴリズムが壊れた(偏微分の符号とパラメータの修正の方向が逆転して全く収束しない)のもなんとかしないとなぁ。私の理解を超えているアルゴリズムを利用するのはどこらへんがおかしいかが見当つかないから大変です。
スポンサーサイト