Dockerを触ってみたい(1)

PHPの開発環境を作りたいけど、少し前に上司に教わりながらvagrantLAMP環境を作成したときは全く理解できなかったトラウマがあります。

そろそろちゃんと理解しなければということで、重い腰をあげてとりあえずDockerから始めてみます。

参考にさせていただいたところ

koni.hateblo.jp

↑これをそのまんまやってみます。

Dockerの準備

※homebrewはインストール済みとします。

まずはターミナルに下記を打ち込んでdockerをインストールします。

$ brew cask install docker

brewbrew caskの違いについてですが、brew caskGUIツールをインストールする用らしいです(違うかも...)。

dockerがインストールされたことを確認するためにバージョン情報を表示してみる。

$ docker version
-bash: docker: command not found

は?

なんで?インストールされたんじゃないの...?

ググる

Homebrewを使ってDockerをMacにインストール - Qiita

なるほど、起動しないといけないのかな?

openというコマンドを使用しているみたいなので、そこから調べてみる。

コマンド/open - MacWiki

どうやらopenはダブルクリックでアプリを立ち上げるのと同様の動きをするらしい。

やってみる。

$ open /Applications/Docker.app

...

f:id:kituman:20190108232811p:plain
えぇ...

え?なにこれログインとか必要なの?

...と最初は思いましたが、右上のバツボタンをクリックして先ほどのコマンドを入力。

$ docker version
Client: Docker Engine - Community
 Version:           18.09.0
 API version:       1.39
 Go version:        go1.10.4
 Git commit:        4d60db4
 Built:             Wed Nov  7 00:47:43 2018
 OS/Arch:           darwin/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          18.09.0
  API version:      1.39 (minimum version 1.12)
  Go version:       go1.10.4
  Git commit:       4d60db4
  Built:            Wed Nov  7 00:55:00 2018
  OS/Arch:          linux/amd64
  Experimental:     false

インストールできた!!

次はPHPが動作する環境を作りたい。

デザインパターンを学ぶ Strategy パターン偏その1

ゲームを作ろう

私はとあるゲームの開発を行っています。 このゲームは多種多様なキャラクターを操作することができます。 そこで全てのキャラクターが継承するChampionスーパークラスを作成しました。

//Champion.java
public class Champion {
  public void attack(){
    System.out.println("attack");
  }
  public void move(){
    System.out.println("move");
  }
  public void display();
}

全てのキャラクターは攻撃と移動が可能で、キャラクター毎に違う見た目を持っています。

//Ez.java
ublic class Ez {
  public void display(){
    System.out.println("Ezの表示");
  }
}

//Toris.java
ublic class Toris {
  public void display(){
    System.out.println("Torisの表示");
  }
}

うん、完璧な実装ですね。





しかし、仕様が変わってしまった

私の上司はこのゲームにブリンクが必要だと判断しました。 ブリンクのスタイリッシュな動きがこのゲームを素晴らしいものにするのです。

私は必要なのはChampionクラスにsay()メソッドを追加することだと判断しました。 そうすれば全てのキャラクターがブリンクをつかえるようになります。 さあ、実装しましょう。

//Champion.java
public class Champion {
  public void attack(){
    System.out.println("attack");
  }
  public void move(){
    System.out.println("move");
  }
  public void display();
  public void blink() {
    System.out.println("blink");
  }
}





だがしかし

私は気づいていませんでした。 全てのキャラクターがブリンクできるべきではないということに。

ブリンクを持ったコグマウがサマナーズリフトを駆け回っています。 Championスーパークラスに新しいふるまいを追加した際に、いくつかのChampionサブクラスには適切でないふるまいを追加してしまったのです。





display()メソッドと同様に、ブリンクできないキャラクターで常にblink()メソッドをオーバーライドすることもできます……

しかし、そうすると他のメソッドを追加した際はどうなるのでしょう?

例えば、MSアップを追加したときには? そのたびにそれが必要のないすべてのサブクラスでオーバーライドするのですか?





続く

続・RMPとIRPの差分ベクトルの積和平均による項目選択ルール

たぶんRMPの計算方法がわかったので書く.
確認のしようがないのであんまりあてにしないでください.
前回の記事よりはマシ程度に受け止めて.

定義

RMPの計算に必要なのは

  • IRP
  • 受験者の回答

の2つ

IRP

q : 問題番号
r : ランク
IRP : \displaystyle{\vec{V}\ni\vec{V_q}\ni\vec{v_{qr}}}
また,このようにも見れる
IRP : \displaystyle{\vec{V}\ni\vec{V_r}\ni\vec{v_{qr}}}

表にすると
f:id:kituman:20170208183826p:plain

受験者の回答

同じく
q : 問題番号
回答 : \displaystyle{\vec{U}\ni u_q}

表にすると
f:id:kituman:20170208184235p:plain

RMP

同じく
r : ランク
RMP : \displaystyle {\vec{p} \ni p_r}

表にすると
f:id:kituman:20170208184459p:plain

RMPを算出する

例えば,RMP要素をとあるランクr1について求めるとき
ランクrの範囲を1~Rとすると
RMPの要素 : \displaystyle{p_{r1} = \frac{p(\vec{U} | \vec{V_{r1}})g(f_{r1})}{\sum_{r=1}^{R} p(\vec{U} | \vec{V_r})g(f_r)}}

\displaystyle{g(f_r)}は前回話したね.事前確立だったはず.


また,問題番号qの範囲を1~Qとすると
\displaystyle{ p(\vec{U} | \vec{V_{r1}}) = exp(\sum_{q=1}^{Q} u_q\log (v_{qr1}) + (1 - u_q)\log (1 - v_{qr1}))}

完成

後は?

どんどん問題を出しつつRMPを更新してください.
{g(f_r)}は前回のRMPを使えばいいと思います.
qの範囲Qは問題を解く毎に増えていくと思います.

しかしまあ,ここら辺のことはよくわかってないので
前回のリンクを参照してください.

RMPとIRPの差分ベクトルの積和平均による項目選択ルール

f:id:kituman:20170208044336j:plain

期間内に終わりそうもないのでかわいそうだからまとめる.
これに懲りたら今後は計画的に作業を進めること.

追記:書き終えたあたりでなんか式に矛盾を感じてきた.
とりあえず雰囲気だけ掴んで細かい式は先輩方の論文の方を参考にしてください.

やりたいこと

コンピュータ適応型テスト (略称CAT)
項目応答理論 (略称IRT)によって推定されたパラメータの付与された問題項目(アイテム)をアイテムプールに置き、受験者の回答パターンに応じて、困難度の異なるアイテムを選んで出題することにより、動的、短時間、高精度で受験者特性の測定を判定を行う方法.

これをIRTではなくLRTでやりたいですね.
LRTだと離散的なので例えば
A君はクラス1,B君はクラス3
みたいな感じで受験者をレベルに応じてクラス分けできるぞ.

やりかた概要

  1. 初期暫定RMPを算出
  2. 暫定 RMPとIRPの差分ベクトルの積和平均が最小となるものを選択し出題する(ここを何度も繰り返す)
  3. 条件を満たしたらテスト終了

以下に詳しいやり方を書く.

1番

まずは初期暫定RMPを出す
RMPを出すために受験者に何問か問題を解かせる.
今回はランク(困難度)が3つなので3つ解かせる.(各ランクからランダムに1つずつ)


3つ解かせ終わったら実際にRMPを算出する.
ランク・メンバーシップ・プロファイル(rank membership profile, RMP)は,各被験者のそれぞれの潜在ランクに対する所属確率を見るのに便利


とりあえず先に説明しておくと,RMPはベクトルだよ.
次元数はランクの数と同じだよ
今回は3つだから最終的にRMPを{\vec{p}}とすると
{ \displaystyle
\vec{p} = (p_1, p_2, p_3)
} になるね
つまり,{p_1}はその人がランク1に属する確率だよ


それでは,初期暫定RMPを求めていくよ
RMPを求めるために必要なのは以下の2つ

  • 受験者の回答

今回は最初に3問出題することにしたので{u_1,u_2,u_3}とする.
{u_1}はランク1の問題に対する回答
{u_2}はランク2の問題に対する回答
なお,回答は当たったかどうか(1 or 0)の2値とする
1 : 正答
0 : 誤答

  • 出題した問題のIRP

IRPもベクトルだね.簡単に言うとある問題に対してのそれぞれのランク毎の正答率だね.
ランク i の問題のIRPを{\vec{V_i}}とすると今回はランクが3つなので
{\vec{V_i} = (v_1,v_2,v_3)} ってかんじになるね.
{v_1}{\vec{V_i}}に対するランク1の人の正答率.
また,{\vec{V_i}}も今回は最初に3問出題することにしたので
{\vec{V_1},\vec{V_2},\vec{V_3}}の3つができるね.

↓下図はランク数10のIRP
f:id:kituman:20170208015504g:plain


RMPの要素{p_1}を求める式は
{ \displaystyle
p_1 = \frac{p(u_1|V_1)g(f_1)}{\sum_{i=1}^3 p(u_i|V_i)g(f_i)}
} だよ
{p_2,p_3}も分子を変えるだけで求められるね.
一応だけど分子の p は確率(probability)の p だぞ.

で,これが何を意味しているかというと
正直資料が全然みつからなくてわからないんだぜ.
だから,俺の予想を書くぜ

まず,{g(f_1)} っていうのは事前確率を表しているぞ.
{g(f_1)} = 事前にわかっている回答者がクラス1に分類される確率ってことだね.

さて,今事前にわかっている事前確率{g(f_1)})はいくつかな?

そうだね,まだわからないね.

というわけでまだ分からない

どのクラスに分類される確率も等しい
とうことでクラス数が3つなので
{g(f_1) = \frac{1}{3}} にしましょう.
同じように{g(f_2),g(f_3)}{\frac{1}{3}}だね.

それじゃあ{ \displaystyle
p_1 = \frac{p(u_1|V_1)g(f_1)}{\sum_{i=1}^3 p(u_i|V_i)g(f_i)}
}
分子 { \displaystyle
p(u_1|V_1)g(f_1)} について考えてみよう.

{ \displaystyle
p(u_1|V_1)} っていうのは
{V_1} のとき {u_1} が起こる確率だね.
これは文字に起こすと
IRPが {V_1} のとき回答が {u_1} の確率といえる.
つまり,
とあるクラス1の問題は各ランクの人の正答率が {V_1} なんですけども,その時に正答(or 誤答)する確率は?
って意味だと思う.

で,それに事前確率 {g(f_1)} が掛けられているので,
確率で掛け算は○○かつ××って意味なので
クラス1に属する確率 {g(f_1)} の人が,とあるクラス1の問題(各ランクの人の正答率が {V_1})に,その時に正答(or 誤答)する確率
ってことです.
(余計わかりづらくなった気がする…)


話が逸れたから実際の計算に戻るよ


RMPベクトル : { \displaystyle
\vec{p} = (p_1, p_2, p_3)
}
{ \displaystyle
p_1 = \frac{p(u_1|V_1)g(f_1)}{\sum_{i=1}^3 p(u_i|V_i)g(f_i)}
} ←これを求めるんだったね.


{ \displaystyle p(u_1|V_1) = \mathrm{e}^{(u_1)log v_1 + (1 - u_1)log (1 - v_1)}}

追記:多分ここが間違ってる↑なんか多分総和とかとらないといけないハズ

で求めるよ
実は,ここがマジで資料見つからなかったから曖昧だよ.
なんかややこしいけど,これは結局
正答だったら {u_1 = 1}
誤答だったら {u_1 = 0}
になるから,指数の左側か右側の片方は消えるよ

で,結局
正答だったら {v_1} → IRPから得られる正答確率
誤答だったら {1 - v_1} → IRPから得られる誤答確率
っぽいのが出てくるっぽい.


そんでもって, {p_1} の分母 {\sum_{i=1}^3 p(u_i|V_i)g(f_i)}
これはたぶん{ \displaystyle
\vec{p} = (p_1, p_2, p_3)
} の要素の総和が1になるように正規化するためのものだと思うよ.
総和が1だったらそのまま確率(百分率)で表せるからね.便利.


というわけで,これで初期暫定RMPは求められるはず.

2番&3番

正直疲れたからここ読んでほしい

http://www.rd.dnc.ac.jp/~shojima/ntt/KimuraJART11.pdf

簡単だからすぐわかると思う.

RMPの求め方(初期暫定RMP以外のRMP)

ここら辺あいまい

初期暫定以外の普通のRMPはどうやって求めるかというと,
初期暫定RMPとほとんど同じですよ.

ただし,一つだけ違うのが事前確率 {g(f_i)}
こいつは最初はわからなかったから 1/3 にしたけど,
2回目からはこの値にRMPを使えばいいんじゃない?
だって,RMPって被験者の各クラスに対する所属確率だったもんね.


そんでもって,ここが一番わからないんだけど
RMPの更新についてのお話

例えば,「初期暫定RMPが求まり,その値からクラス2の問題が選ばれた」としよう
↑つまり4問目
その時その問題の回答結果からRMPを更新することとなるが,
俺の中でどっちの更新式が2パターンある.
どっちが正しいかは知らんし,どっちも正しくないのかもしれない.


①どんどん値が増えてくパターン
{ \displaystyle
p_2 = \frac{(p(u_2|V_2)g(f_2) + p(u_4|V_4)g(f_2)) / 2}{\sum_{i=1}^4 p(u_i|V_i)g(f_i)}
}

追記:絶対間違ってる↑

②出題した問題のクラスに対してのみ更新するパターン
{ \displaystyle
p_2 = \frac{p(u_4|V_4)g(f_2)}{\sum_{i=1 (i != 2)}^4 p(u_i|V_i)g(f_i)}
}

追記:絶対間違ってる↑

ニューラルネットワークに対する理解

ニューラルネットワークが何をしているのか?
今の自分の考えを記す.

とりあえずニューラルネットワークの図

f:id:kituman:20170125162756p:plain

図の丸はそれぞれパーセプトロン. 左が入力層,中央が隠れ層,右が出力層となっている.

何がしたい?

何かの式を解きたい

とある真のモデルからサンプルを取ってくる

それをNNに食わせる

モデルを予測する

例えば

f:id:kituman:20170125164034p:plain

こんな感じのサンプルがあります.

なんとなくではありますが,

f:id:kituman:20170125165321p:plain

こんな感じに線を引けそうですね. この線を予測するのがニューラルネットワークの働きです. これにより真のモデルf:id:kituman:20170125165207j:plainを予測します. ちなみに,今回はサンプルの次元が身長とバストの2次元だけだったので線を予測しましたが,3次元のデータなら面を,4次元以上なら超平面のようになります.

モデルが予測出来たら何がうれしいか?

サンプルにないデータも予測できる

例えば,今回のデータを使ってサンプルにないアイドルの身長さえ分かればバストが予測できる という寸法です.

じゃあ,予測するにはどうすればいいの?

誤差逆伝播

これについては後日.

パーセプトロンってなに?

ニューラルネットワークを作ろうと思ったので、とりあえず基本となるパーセプトロンから。

 

 

図にするとこんな感じ。

f:id:kituman:20170116031429p:plain

xが入力、zが出力となっていて

  • u = w * x
  • z = f(u)

 

 

関数f活性化関数と呼ばれるもの。

単調増加する非線形関数が用いられる。

よく使われるのがロジスティック関数とかシグモイド関数とか呼ばれるもの

  • f(u) = 1 / (1 + exp(-u))

f:id:kituman:20170116033404p:plain

他には双曲線正接関数ランプ関数などが用いられる

結局のところ、「ある値付近で急に立ち上がるインパルスみたいな関数であればなんでもいい」と理解している。(たぶん)

 

 

パーセプトロンの話に戻る。

入力は何個でも構わない

f:id:kituman:20170116032103p:plain

入力が増えたらその分だけ計算が増える

  • u = w1 * x1 + w2 * x2 + w3 * x3
  • z = f(u)

 

これをたくさん並べたものがニューラルネットワークとなる。

続きはまた今度。