読者です 読者をやめる 読者になる 読者になる

theanoでMNISTのnegative log-likelihood

Python Theano

theanoでMNISTを多層パーセプトロンするとき(日本語?)のnegative log-likelihoodをコストとして計算する式であるところの

NLL = -T.sum(T.log(p_y_given_x)[T.arange(y.shape[0]), y])]

という式について、ただし実用的には、

NLL = -T.mean(T.log(p_y_given_x)[T.arange(y.shape[0]), y])]

の式、の意味がよくわからず呆然としていた。Tはtheano.tensorのことです。
Getting Started — DeepLearning 0.1 documentationのNegative Log-Likelihood Lossの項やClassifying MNIST digits using Logistic Regression — DeepLearning 0.1 documentationのCreating a LogisticRegression classの項に出てくるやつ。

分解すると、
p_y_given_x: 出力層の値の分布。ラベルに対する確率分布ということになる。計算時にはこれは行列であり、rowがひとつのサンプルで、columnが0-9までのラベルに対する予測確率。
T.sum: 実際はT.meanを使う(値が大きくなりすぎてlearning rateに影響してしまうから)
T.log(p_y_given_x): logに入れるので値がすべて負になって0に近い値が高い確率になる
y.shape[0]: yがサンプル数の長さをもつ正解ラベルのリストで、shape[0]はサンプル数(=Nと書く)を与える
T.arange(y.shape[0]): [0,1,2,...,N] というリストを返す
[T.arange(y.shape[0]), y]: 行列から指定した座標の値をリストで取り出すためのnumpyの記法。M[取り出したい行番号からなるリスト(r_i), 取り出したい列番号からなるリスト(c_j)]に対して [M(r_1, c_1), M(r_2,c_2), ...] を返す。詳しくはIndexing — NumPy v1.10 Manualを参照
T.log(p_y_given_x)[T.arange(y.shape[0]), y]): 各サンプルが持つ長さ10の確率分布の配列から、正解ラベルの位置の値を取り出して長さNのリストで返す。つまり「各サンプルが正解ラベルに対して出力している確率」のリストを返す
\-T.mean(): マイナスが付くので正解に近づけば近づくほど正の値として0に近づく。したがって、NLLの値を0に近づけることが学習の目標になる。
という感じみたいです。

補記として、
learning rate などでfloat変数を突然出現させるとfloat64扱いされて(ほかをすべてfloat32で計算しているときには)弾かれるので、
lr = numpy.float32(0.01)
みたいに宣言したほうがいいのかもしれません(グローバルに宣言する(できる?)なら別なのだろうけど)。自分は課題提出のサーバーはそこでの型エラーを起こさなかったんだけど、手元で動かそうとしたらエラー吐かれた。どこをどう設定すれば解決するのかはきちんと調べてないですが、統一はしたい。