KerasでDeep Learning

最近オススメのDeepLearningライブラリKeras。TheanoかTensorflowをバックエンドにして動きます。ProgressBarによる実行状況の確認や入出力レイヤーのバイアスの枠組みとか自動で行ったり、非常に使いやすいです。

Kerasで全結合層
ここに簡単なコードを上げました。
実質10行くらいで書けます。超便利。

ここのInputで入力、Denseで各層を定義しています。引数で前の層を入れておけばOK
これだけで前後の層を勝手につないで重みとかもスケールしてくれるので大変ありがたいです。

ちなみに同じようなやり方で以下のような書き方もできます。

Sequential()定義をすると、層をaddという形でどんどん追加できます。こちらも分かりやすいですね。
ただ、この形だと単純な構造なら良いのですが層の間に色々挟んだりAutoEncoderみたいに学習器を切り離す場合とかは不便です。

巷ではChainerが流行っているみたいですが、こっちの方が楽だと思うんですよね。海外でディープラーニングベンチャー立ち上げた人も時代はKerasって言ってましたし、サポートも充実(?)しており、自動翻訳突っ込んだような日本語ドキュメントもあります笑

今からDeep Learningを始める人はKerasにしてはいかがでしょう?

参考文献

ttp://aidiary.hatenablog.com/entry/20160328/1459174455
ttp://keras.io/
ttp://rnn.classcat.com/2016/03/15/keras-deep-learning-library-for-tensorflow/

Pandasでよく詰まるところメモ

Pandasはfor文使う必要なく条件指定ができたりまとめて操作できたりと大変便利なのですが、やっぱりちょっと癖があり、python的に普通の書き方をするとエラーが出ることがあります。なので今回はPandasで自分がよくやるミスをメモしておきます。

不要な行の削除

dfはDataframeです。content列のportforioという要素が入っている行を消去しようとしています。行を消去するという考えだとdropとか使いたくなるのですが、普通に排他制御でいいよね、という感じです。

条件の複数指定

複数条件を指定する場合です。つい”and”や”&&”を使いたくなるのですが、”&”一個が正しいです。

特定の行の編集

Dataframe自体を直接編集したいときによく間違えるミス。この例だと、contentがshoppingのものをcorporateに置き換えようとしています。
これも普通に条件指定するだけではダメで、locを使う必要があります。locだとindexの指定も必要なので、.indexでその情報も取得しています。もっとうまく書く方法あるかもしれませんが、とりあえずはこれで大丈夫です。

この辺はまた時間があるときにちょこちょこ追加していく予定です。

NMFを見直してみる

もう5月か…色々進めないとと思いつつ。
最近、NMFとか割と使っているんですが原理とか踏まえてもっかい確認しとこうと思いまして。車輪の再発明的な。

さて、NMF(Non-negative Matrix Factrization)といえば言わずと知れた次元削減手法で、非負値行列V(m×n)を非負値行列H(m×r)とW(r×n)に分解する手法です。

V \simeq HW

例えば、

要素1 要素2 ・・・・・ 要素200
ユーザ1 1.0 2.0 ・・・・・ 0.2
ユーザ2 3.0 0.4 ・・・・・ 1.0
・・・・・
ユーザ100 1.2 3.3 ・・・・・ 1.5

みたいなデータがあった場合、いちいち調べるのがとても面倒(というより要素数が多すぎて手に負えない)なので、次元を削減して

特徴量1 特徴量2 ・・・・・ 特徴量5
ユーザ1 1.0 3.0 ・・・・・ 0.0
ユーザ2 2.2 0.0 ・・・・・ 1.2
・・・・・
ユーザ100 0.2 3.4 ・・・・・ 1.5

みたいな感じに変換できると扱いやすいしいいよね、って話です(これがHに該当します)。これだとユーザがどんな傾向なのか分かります。またWの方を見てみると

要素1 要素2 ・・・・・ 要素200
特徴量1 0.1 0.0 ・・・・・ 1.0
特徴量2 1.2 1.0 ・・・・・ 0.0
・・・・・
特徴量5 0.2 3.4 ・・・・・ 3.0

となり、要素がどの特徴量にどれだけ効いてくるのかが分かります。
で、なぜ非負値行列という条件を設定しているのかというと、現実的には非負要素を扱うことが多いからです。具体的にはウェブページのユーザー数(0以上)とか画像のある画素数(8bitで0~255)とか商品の購入の有無(0 or 1)とかとか。特異値分解(Singular Value Decomposition, SVD)をしてしまうと、行列に負の値が出てきてしまうため、ユーザー数-10って何??亡霊???みたいになる場合があるので、NMFの方が自然な解釈が行いやすいというメリットがある場合があります。実際に特徴抽出できる厳密な話はよく分かってないのですが、こんな認識です。さて、ではさっそくやってみましょう。

とりあえず参考サイトに習ってユークリッド距離についてのNMFをやってみます。ただ全く同じことを書いても何なので自分がつまづいた部分も含めてもう少し詳しく書いてみます。

さて、それでは最初に戻ってみて
V \simeq HW
となるようなH,Wを見つけようという話でした。そこで、今回は以下の誤差関数Eが最小になる場合を考えます。
  E = || V - HW ||_F = \sum_{m,n}|V_{m,n}-\sum_{k}H_{m,k}W_{k,n}|^2
このように、行列のユークリッド距離は各要素の2乗和になります。これを展開して、
  E = \sum_{m,n}(|V_{m,n}|^2-2V_{m,n}\sum_{k}H_{m,k}W_{k,n}+|\sum_{k}H_{m,k}W_{k,n}|^2)

|\sum_{k}H_{m,k}W_{k,n}|^2の扱いが悩むところですが、ここでイェンゼンの不等式を適用します。イェンゼンの不等式とは\lambda_1+\lambda_2+\cdot\cdot\cdot+\lambda_n=1 (\lambda_i>0)の時
 \sum_i \lambda_i f(x_i) \geq f(\sum_i \lambda_i x_i)
となるという不等式です。等号成立条件はx_i = const

で、これが今回の場合はどのように使えるかというと、
  (\sum_{k}H_{m,k}W_{k,n})^2 = (\sum_{k} \lambda_{k,m,n} \frac{H_{m,k}W_{k,n}}{\lambda_{k,m,n}})^2  \leq \sum_{k} \lambda_{k,m,n} (\frac{H_{m,k}W_{k,n}}{\lambda_{k,m,n}})^2 = \sum_{k} \frac{H_{m,k}^2W_{k,n}^2}{\lambda_{k,m,n}}
不等号が入っている部分でイェンゼンの不等式を使いました。
つまり、x_i = \frac{H_{m,i}W_{i,n}}{\lambda_{i,m,n}}f(x) = x^2 としているわけです。ここがけっこうテクニカルなのにあんまり他のサイトには書いてない気がします。

この時、等号成立条件はx_i = constなので、
\frac{H_{m,i}W_{i,n}}{\lambda_{i,m,n}} = const
加えて、\sum_i \lambda_i=1 (\lambda_i>0)なので
  \sum_i \lambda_i=1  \Leftrightarrow \sum_i \frac{const}{H_{m,i}W_{i,n}} = 1  \Leftrightarrow const = \sum_i \frac{1}{H_{m,i}W_{i,n}}
よって、\lambda_i
  \lambda_i=\frac{H_{m,i}W_{i,n}}{const}=\frac{H_{m,i}W_{i,n}}{\sum_i' H_{m,i'}W_{i',n}}

これでめでたく\lambda_iが求まったので、元の式はこの\lambdaを用いて
  E = \sum_{m,n}(|V_{m,n}|^2-2V_{m,n}\sum_{k}H_{m,k}W_{k,n}+|\sum_{k}H_{m,k}W_{k,n}|^2)
  \leq \sum_{m,n}(|V_{m,n}|^2-2V_{m,n}\sum_{k}H_{m,k}W_{k,n} + \sum_{k} \frac{H_{m,k}^2W_{k,n}^2}{\lambda_{k,m,n}})
のように上界から囲むことができます。これで後は偏微分すればOK。

\frac{\partial E}{\partial H_{m,k}}=\sum_n(-2V_{m,n}W_{k,n}+2\frac{H_{m,k}W_{k,n}^2}{\lambda_{k,m,n}})=0
\frac{\partial E}{\partial W_{k,n}}=\sum_m(-2V_{m,n}H_{m,k}+2\frac{H_{m,k}^2W_{k,n}}{\lambda_{k,m,n}})=0

よって、これを解いて
H_{m,k}=\frac{\sum_n V_{m,n}W_{k,n}}{\sum_n \frac{W_{k,n}^2}{\lambda_{k,m,n}}}, \  W_{k,n}=\frac{\sum_m V_{m,n}H_{m,k}}{\sum_m \frac{H_{m,k}^2}{\lambda_{k,m,n}}}

\lambda_{k,m,n}の値を代入して、
H_{m,k}=H_{m,k}\frac{\sum_n V_{m,n}W_{k,n}}{\sum_n W_{k,n} \sum_k' H_{m,k'}W_{k',n}}, \  W_{k,n}=W_{k,n}\frac{\sum_m V_{m,n}H_{m,k}}{\sum_m H_{m,k} \sum_k' H_{m,k'}W_{k',n}}

行列式に書き直すと
H_{m,k}=H_{m,k}\frac{\left[ VW^T \right]_{m,k}}{\left[ HWW^T \right]_{m,k}}, \  W_{k,n}=W_{k,n}\frac{\left[ H^TV \right]_{k,n}}{\left[ H^THW \right]_{k,n}}
以上が乗法更新式となります。式がごちゃごちゃするので一回書いてみて追った方がいいような気もします。

これ、片方を固定してHとWを逐次的に更新していく式なのですが、どうやらこの最適化はEMアルゴリズムとは違って大域的最適解の保証がないみたいなので注意(詳しくは以下)

さて、それではこれをpythonで実装してみます。

ノルムが更新の度に小さくなるのが見て取れるかと思います。今回は要素も少ないのですぐ収束しましたが、特徴量の数を増やしすぎると収束しないで発散する場合があるので、収束性はちゃんと見た方が良いかと思います。

余談ですが、pythonなら自分で実装するまでもなくnimfaというNMF用のパッケージがあります。

こんな感じ。便利ですね。

参考文献

http://r9y9.github.io/blog/2013/07/27/nmf-euclid/
http://d.hatena.ne.jp/a_bicky/20100325/1269479839
http://d.hatena.ne.jp/yosshi71jp/20110520/1305918939