MCMCの理論


マルコフ連鎖モンテカルロ法(MCMC)の理論を簡単にまとめた。

MCMCするモチベーション

  • モデルの重みとかの事後分布を求めたい
  • けど積分計算が解析的に解けない。。。
  • 対象をサンプリングしてサンプルのヒストグラムから分布を作ってしまおう!

というのがモチベーション。

どうやってサンプリングするか?

確率変数$\boldsymbol{w}$のデータ$\boldsymbol{X}$観測後の事後分布$P(\boldsymbol{w}|\boldsymbol{X})$を求めたいとする。

MCMCでは、$P(\boldsymbol{w}|\boldsymbol{X})$が定常分布となるようなマルコフモデルを作り、このマルコフモデルからサンプリングを行う。

なぜそうするかというと、定常分布は時間が経過してもずっと同じ分布となる分布で、この分布となるようなマルコフモデルはずっと分布が変わることがないため、このサンプルが$P(\boldsymbol{w}|\boldsymbol{X})$からのサンプルであることを保証してくれるから。

どうやって上のようなマルコフモデルを作るか?

  1. 詳細釣り合い条件
  2. エルゴード性

を満たす遷移確率を持つようなマルコフモデルを作ればOK。

詳細釣り合い条件

マルコフモデルの$\boldsymbol{w} \rightarrow \boldsymbol{w'}$の遷移確率を$T(\boldsymbol{w}'|\boldsymbol{w})$としたとき、

$$ T(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t})P^*(\boldsymbol{w}^{t})=T(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1})P^*(\boldsymbol{w}^{t+1}) $$

が成立するならば、$P^*(\boldsymbol{w})$は定常分布。

証明

両辺で$\boldsymbol{w}^{t}$について和を取ると


\begin{align}
\sum_{\boldsymbol{w}^{t}} T(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t})P^*(\boldsymbol{w}^{t}) &= \sum_{\boldsymbol{w}^{t}} T(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1})P^*(\boldsymbol{w}^{t+1}) \\
&= P^*(\boldsymbol{w}^{t+1})
\end{align}

となる。

これは左辺で$\boldsymbol{w}^{t}$が$\boldsymbol{w}^{t+1}$に遷移したとしても$\boldsymbol{w}$の分布$P^*(\boldsymbol{w})$が変化しないことを意味する。

つまり、詳細釣り合い条件が満たされるとき、$P^*(\boldsymbol{w})$は定常分布。

エルゴード性

これは$\boldsymbol{w}$の初期値に関わらず、$t\rightarrow\infty$で$P(\boldsymbol{w})$が定常分布$P^*(\boldsymbol{w})$に収束する性質のこと。

ちゃんとした証明は調べてないけど、基本的に$\boldsymbol{w}$の初期値に関わらず、$\boldsymbol{w}$が取りうる値全てにいずれは遷移できるようなマルコフモデルならOK。

MCMCアルゴリズム例:MH法

うまく目的の分布からサンプルを得るためには、詳細釣り合い条件とエルゴード性を持ったマルコフモデルを用意しなければならない。 Metropolis-Hastings(MH)法では以下の遷移確率で定義されたマルコフモデルを使用する。

$P(\boldsymbol{w}|\boldsymbol{X})=\frac{P(\boldsymbol{X}|\boldsymbol{w})P(\boldsymbol{w})}{\int P(\boldsymbol{X}, \boldsymbol{w})d\boldsymbol{w}}=\frac{f(\boldsymbol{w})}{Z}$としたとき、 $$ \begin{align} T(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) &= q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) \times \min(1, \frac{ f(\boldsymbol{w^{t+1}}) q(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) }{ f(\boldsymbol{w^{t}}) q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) }) \\ T(\boldsymbol{w}^{t}|\boldsymbol{w}^{t}) &= 1 - T(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) \end{align} $$ ここで、$q(\boldsymbol{w}'|\boldsymbol{w})$は提案分布と呼ばれ、$\boldsymbol{w}$が遷移する候補の値を取ってくるための分布。

手順は、

  1. $q(\boldsymbol{w}'|\boldsymbol{w})$から遷移先の候補点$\boldsymbol{w}'$を取ってくる
  2. $a = \frac{ f(\boldsymbol{w^{t+1}}) q(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) }{ f(\boldsymbol{w^{t}}) q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) }$を計算する
  3. $a$が1以上だったら候補点$\boldsymbol{w}'$をサンプルとして受理し、1より小さかったら$a$の確率で$\boldsymbol{w}'$をサンプルとして受理する
  4. 受理された場合は$\boldsymbol{w}\rightarrow\boldsymbol{w}'$と遷移させ、されなかった場合は遷移させず$\boldsymbol{w}\rightarrow\boldsymbol{w}$とする
  5. 上記を繰り返す

のようにしてサンプリングを行う。

証明

詳細釣り合い条件が成立するか確かめる。 $$ \begin{align} T(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) P(\boldsymbol{w^{t}}|\boldsymbol{X}) &= q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) \times \min(1, \frac{ f(\boldsymbol{w^{t+1}}) q(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) }{ f(\boldsymbol{w^{t}}) q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) }) \frac{f(\boldsymbol{w}^{t})}{Z} \\ &= \min( f(\boldsymbol{w}^{t}) q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}), f(\boldsymbol{w}^{t+1}) q(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) ) \frac{1}{Z} \\ &= q(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) \times \min(\frac{ f(\boldsymbol{w^{t}}) q(\boldsymbol{w}^{t+1}|\boldsymbol{w}^{t}) }{ f(\boldsymbol{w^{t+1}}) q(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) }, 1) \frac{f(\boldsymbol{w}^{t+1})}{Z} \\ &= T(\boldsymbol{w}^{t}|\boldsymbol{w}^{t+1}) P(\boldsymbol{w^{t+1}}|\boldsymbol{X}) \end{align} $$ で詳細釣り合い条件が成立するので、$P(\boldsymbol{w}|\boldsymbol{X})$が定常分布となることがわかる。

エルゴード性は提案分布$q(\boldsymbol{w}'|\boldsymbol{w})$が$\boldsymbol{w}$の取りうる値へ遷移できるような分布であればOK。

ubuntuをスリープしてもマウス触っただけで復帰してしまう

ubuntu18.04をスリープしたのにマウスをちょっと触っただけで復帰してしまってうざい。。。

調べると以下のサイトで解決法を見つけた。

Wake up from suspend using wireless USB keyboard or mouse (for any Linux Distro) - Ask Ubuntu

解決法

まず以下のコマンドでスリープから復帰するデバイスを見つける。

grep . /sys/bus/usb/devices/*/power/wakeup

自分の環境だと以下のとおり、1-41-7がenabledになってた。

/sys/bus/usb/devices/1-4/power/wakeup:enabled
/sys/bus/usb/devices/1-7/power/wakeup:enabled
/sys/bus/usb/devices/1-8/power/wakeup:disabled
/sys/bus/usb/devices/usb1/power/wakeup:disabled
/sys/bus/usb/devices/usb2/power/wakeup:disabled
/sys/bus/usb/devices/usb3/power/wakeup:disabled
/sys/bus/usb/devices/usb4/power/wakeup:disabled

1-4とか1-7とかってなんやねんということで、以下のコマンドで調べる。

grep . /sys/bus/usb/devices/*/product

以下のとおり、キーボートとマウスだった。

/sys/bus/usb/devices/1-4/product:2.4G Keyboard Mouse
/sys/bus/usb/devices/1-7/product:USB Keyboard
...

/sys/bus/usb/devices/*/power/wakeupは普通にエディタを使ってやれば編集できるので、vimとかを使って enabledからdisabledに変更してやれば良い(sudoで編集する必要あり)。

実際1-41-7disabledに変更してスリープしたらキーボートやマウスを触っても復帰しなくなった。 この状態で復帰する際は電源ボタンを押してやればOK。

恒久的にマウスで復旧しないようにするには

上でdisabledにしても再起動するとenabledに戻ってしまう。。。 ならば起動時に自動でdisabledにするようにしてしまおう。

以下のようにして起動時に自動で実行するコマンドの設定ファイル/etc/rc.localを作成(既にある場合は編集)。

sudo vim /etc/rc.local

echo disabled > /sys/bus/usb/devices/[disabledにしたいデバイス]/power/wakeupを追加。

自分の環境では以下のように書いた。

#!/bin/bash

echo disabled > /sys/bus/usb/devices/1-4/power/wakeup
echo disabled > /sys/bus/usb/devices/1-7/power/wakeup

以下のコマンドで実行権限を付与。

sudo chmod +x /etc/rc.local

※既に/etc/rc.localがあった場合は#!/bin/bashを書く必要もchmod +xを実行する必要もない。

これで再起動してもキーボートやマウスで復帰しなくなったb

ubuntuでconda installしようとするとNotWritableErrorが出る

UbuntuにAnacondaをインストール後、conda install updateとかをしても以下のようなエラーが出た。

Collecting package metadata (current_repodata.json): failed

NotWritableError: The current user does not have write permissions to a required path.
  path: /home/user_name/.conda/pkgs/urls.txt
  uid: 1000
  gid: 1000

If you feel that permissions on this path are set incorrectly, you can manually
change them by executing

  $ sudo chown 1000:1000 /home/user_name/.conda/pkgs/urls.txt

In general, it's not advisable to use 'sudo conda'.

/home/user_name/.conda/pkgs/urls.txtのアクセス権を与えてやればいいと思ったがそもそもこのパスが存在しなかった。

解決法

/home/user_name/anaconda3のアクセス権を付与すればよかった。

sudo chown -R user_name /home/user_name/anaconda3

この後conda install updateとかが正常にできるようになった。

docker上でjupyter-notebookを使用する方法

dockerコンテナ上でjupyter-notebookを起動させてローカルPCのブラウザで動かすための方法。

1. ポートの接続

コンテナ上のポートとローカルのポートを接続する。

docker run -p [ローカルのポート]:[コンテナのポート]

とすれば接続できる。

2. notebook起動時にオプションをつける

コンテナ上でjupyter notebookとコマンドしても

OSError: [Errno 99] Cannot assign requested address

と出る。 以下のようにipとallow-rootオプションをつければ解決。

jupyter notebook --ip=0.0.0.0 --allow-root

※もし、1.のポートの接続時のコンテナのポートがnotebookのデフォルト値の8888以外にした場合は以下のようにしてポートも設定する必要がある。

jupyter notebook --port [コンテナ側の接続ポート] --ip=0.0.0.0 --allow-root

3. ブラウザでnotebookにアクセス

ローカルPCのブラウザでコンテナで起動したnotebookにアクセスする。 ブラウザに下記URLを打ち込む。

localhost:[ローカル側の接続ポート]

するとJupyter Notebookの画面に遷移してPassword or token:と入力が求められる。

入力するためのtokenはコンテナ上でnotebookを起動したときに以下のようなURLが出るのでそこから取得する。

    Copy/paste this URL into your browser when you connect for the first time,
    to login with a token:
        http://5217807fea51:8888/?token=601c330c097e59cd7b69dcaa6ea336218583a492e4684bde&token=601c330c097e59cd7b69dcaa6ea336218583a492e4684bde

上の場合、601c330c097e59cd7b69dcaa6ea336218583a492e4684bdePassword or token:に入力すればいつものnotebookの画面に遷移する。

4. notebookの設定を変更する(オプション)

notebook起動時に--portとか--ip=0.0.0.0とか--allow-rootとかをいちいち打ち込むのが面倒くさい人用。 これらの設定をconfigに書き込んでおく。 まず下記コマンドでconfigファイルを作成。

jupyter notebook --generate-config

/root/.jupyter/jupyter_notebook_config.pyにconfigファイルが作成されるので以下を書き加える。

c.NotebookApp.ip = '0.0.0.0'
c.NotebookApp.port = [コンテナ側の接続ポート]
c.NotebookApp.token = ''
c.NotebookApp.allow_root = True
c.NotebookApp.open_browser = False

以後はjupyter notebookとコマンドするだけで良い。

grub画面にwindows10が認識されない問題

windows10のマシンにubuntu 18.04 LTSをインストールしたが、grubにwindows10がなかった。 ※そもそもgrub画面が出なかったので、この問題はこちらで解決。

まずこちらで解決を試みたけれどもうまく行かなかった。 grub画面で作成したwindowsを選択しても以下のエラーができ起動できなかった。

エラー: unspecified search type
エラー: file '/efi/Microsoft/Boot/bootmgfw.efi' not found

その理由はwindows10をインストールしているHDDのパーティションMBR形式になっていたからであった。 windows上でMBR2GPT.exeを使用することでGTP形式に変更ができた。変更方法はこちら

変更後、ubuntu上でsudo update-grubgrub更新。 再起動したら「Windows Boot Manager (on /dev/...)」という欄が追加され、ここからwindowsの起動ができた。

windows10がインストールされたHDDをMBR形式からGPT形式にする方法

GPTかどうか調べる

cmdでdiskpartと入力。 diskpart.exeというcmdに似た画面が開くのでここにlist diskとコマンド。 GPTの列に*マークがあればGPT、なければMBR

GPTに変換できるかチェック

変換したいディスクをdisk:0とする(ディスクは上記で調べる)。 cmdで以下をコマンド。

mbr2gpt /validate /disk:0

「Validation completed successfully」と出ればOK。 「ERROR: MBR2GPT can only be used from the Windows Preinstallation Environment. Use /allowFullOS to override.」 と出た場合は以下のように/allowFullOSオプションを追加すればうまくいく。

mbr2gpt /validate /disk:0 /allowFullOS

GPTに変換

cmdで以下をコマンドする。

mbr2gpt /convert /disk:0

上記のチェックで/allowFullOSが必要だった場合は以下のようにオプションを追加。

mbr2gpt /convert /disk:0 /allowFullOS

メモ:MBRとGPTの違い

  • MBR形式:昔のパーティション形式。レガシBIOSで使用。
  • GPT形式:これからの主流。UEFIモードで使用。昔のマザボでは使えない。2TB以上の容量が扱える。

Ubuntu18.04起動時にgrub画面が表示されない問題

 

Ubuntu 18.04 LTSのインストール後起動したらgrub画面が出ずにUbuntuが起動したので復旧方法をメモ。

まず、下記コマンドでgrub画面を作成。

sudo grub-mkconfig

次に、「/etc/default/grub」の設定ファイルを以下のように編集。

GRUB_TIMEOUT_STYLE=menu
#GRUB_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT_QUIET=false

編集後、下記コマンドで変更内容を反映。

sudo update-grub

再起動後、grub画面が出て来るようになった。