KiyuHub http://kiyukuta.github.io/ メシと寝所と呼吸と en-us Mon, 09 Dec 2013 00:00:00 +0900 http://kiyukuta.github.io/2013/12/09/mlac2013_day9_recurrent_neural_network_language_model.html http://kiyukuta.github.io/2013/12/09/mlac2013_day9_recurrent_neural_network_language_model.html <![CDATA[これもある意味Deep Learning,Recurrent Neural Network Language Modelの話 [MLAC2013_9日目]]]>

これもある意味Deep Learning,Recurrent Neural Network Language Modelの話 [MLAC2013_9日目]

この投稿は Machine Learning Advent Calendar 2013 の9日目の記事です.

本日は,Neural Network(NN)を利用したLanguage Model(LM),つまりNeural Network Language Model(NNLM)の一種であり, Recurrent Neural Network(RNN)を使ったRecurrent Neural Network Language Model(RNNLM)について説明します.

RNNLMに行く前置きとしてざっくりいくつか用意したので,知ってそうな人は先へ進んでください. 前置きを入れているうちに長くなりすぎた....

しかも,そもそもNNの説明し忘れたことに気づいて戦慄しました. とりあえず手前味噌関連リンクを貼っておきます.A yet another brief introduction to neural networks

はじめに

RNNLMを提案したのはThomas Mikolovと言うひとです.

最近話題になったword2vecの人でもあります.

ただしword2vecはRNNLMを実装したものでは無いので今日は本題ではありません. 今日の本題は,彼らがword2vecの前に公開している rnnlmというツール の中身の話になります.

“ある意味deep learning”と言うのは, 後にでてくるBPTTで \(\tau\) を大きな値をとると,時間的に深く層を見ている形になるためです, そのため多層ニューラルネットの問題にあったように, vanishing gradient problemが起きてしまうことがわかっています. が,今回はその辺の学習の難しさや対策は踏み込みません,あんまり調べてないので.

前置き1: Recurrent Neural Network

  • RNNはNNで時系列解析を行うためのもので,80年代に提案されました
  • ある時刻tにおける隠れ層の状態を,次の時刻t+1の入力に使う.そのため,時刻t+1では,その時刻における入力+前回の履歴を時間的文脈として利用する.
  • RNNを言語モデルとして応用したものがRNNLMです
../../../_images/rnn_intro.png

最初にRNNついて図を書いてみました,今後は右のシンプルなやつっぽい図のみを使います.

赤い部分が普通のNNと違うところで,前回の隠れ層の状態を保持して次回の入力に加える事で, 過去の履歴を利用します.

このRNNの特徴である赤と緑の部分を取り除くと, モデルの形はシンプルなNNと同じになり, 同じようにBackpropagationによってパラメータ( \(CONTEXT(t)\) の前後の矢印)を学習することができます.

しかし,やはりRNNに特化した学習アルゴリズムであるBackpropagation Through Time (BPTT)という ものもあり,後に説明します.

前置き2: Distributed Word RepresentationあるいはWord Embeddings

計算機で単語を扱う際に,単語をどう表現するかという話(表現方法はいくつかありますが,ニューラル言語モデル界隈だでの話です)

単語に連続値ベクトルを割り当てます.

で,ベクトルの中身がその単語の特徴をよしなに表現し,似た単語同士は似たベクトルになるよう学習します. どんなベクトル空間になっているかの分析は後の Analysis で紹介する論文とかでされてます.

../../../_images/word_embeddings.png

えんどう豆やカエルの卵やらに見えるものはベクトルです.

学習は,次のNeural Language Modelによって行われます.

その結果得られたDistributedなWordのRepresentationはWord Embeddingsと言われたりします.

前置き3: Neural Language Model

  • Y.Bengioが2003年に発表したNeural Languageベースのn-gram言語モデルです

  • 言語モデル,n-gram言語モデルの説明は長くなるので,以下の二つの目的があることだけ示して進めます
    • 過去の文脈(n-1個の単語)から,次に辞書中の各単語がどのくらいの確率で出てくるかを出力するモデル
    • 単語の特徴を表現した単語ベクトルの学習

上の論文の中に,以下の図が出てきます.

../../../_images/nnlm_bengio.png

この図を,先に作ってしまった 前置き2 の図にあわせて書き換えて説明すると,以下のようになります. 対応がわかりづらかったので,双方の対応する箇所にa.-e.という記号を付けました.

上の画像を右に90度回転させて,緑の四角をそれぞれの単語として見ます. 上の図は文脈が3単語(n=4)で,下の図は2単語(n=3)です.

../../../_images/neural_language_model.png

showという単語のベクトルと,meという単語のベクトルを辞書から取り出して(b), ふつうのNNと同じように,隠れ層(c),出力層(d)と計算していきます. (d)は後述のsoftmax関数により辞書と同じサイズの確率分布になっていて,各次元が,そこに対応する単語が次に出てくる確率になります. 今回の場合,正解はyourなので,yourの所の確率を取り出してみます(e)

これが,この節の冒頭でいったふたつの目的の一つ目の処理です.

学習の際は,

  • NNのパラメータ(太い三つの矢印)
  • 単語辞書中のベクトルの値(カエルの卵みたいな行列,厳密にはその時出てきている赤と緑の部分)

を同時に修正し,正しい予測ができるよう訓練します. 単語ベクトル(の辞書)も修正対象なので,正しい予測ができるようになった暁には,単語ベクトルも文脈が予測できるようななんか表現が得られていることが期待されます.

後半の2層Neural Networkから見ると,Backpropagationにおいて, 入力データにまで誤差が伝播していき修正されるイメージです.

Recurrent Neural Network Language Model

さて,本題のRNNLMです. ちょっと前置きだけで長くなりすぎた感がありますが, そのおかげでここの説明が最小限で済んで(いると信じて)います.

上のモデルが,固定長(n-1)な文脈を考えていたのに対し, 使う文脈に明確な境目を付けない という特徴があります.

Model Architecture

../../../_images/rnnlm_org.png

これまでに出てきた要素や例に合わせて書くとこんなかんじです.

../../../_images/rnnlm.png

入力される単語は,一つずつですが. \(s(\cdot)\) に,過去の文脈が保存されているという理屈です.

式(1),(2)について説明しますが,疲れてきたので箇条書きで行きます.

\[\begin{split}s(t) =& f(Uw(t) + Ws(t-1)) \\ y(t) =& g(Vs(t))\end{split}\]

まず上の式(1)ですが,

  • \(Uw(t)\) が, 前置き2 の図の真ん中の処理(辞書からfalconの単語ベクトルを引く)です

  • \(Ws(t-1)\) が,t-1番目の単語のときの隠れ層sを行列Wで写像しています.
    • イメージ的に説明すると,過去の文脈(s)と,その文脈が予測に与える影響(W)といった感じでしょうかね.
  • \(f(\cdot)\) は,ベクトル” \(\cdot\) “の各要素に独立にsigmoid関数を書けます(上図の式(3)左)
    • sigmoid関数によって,ベクトルの各要素は,0~1に非線形に変換されます,NNが非線形モデルな所以です.
  • \(f(Uw(t) + Ws(t-1))\) は,今回の単語ベクトルと,過去の文脈を両方詰め込んだ隠れ層ベクトル \(s(t)\) の計算ということになります.

次に下の式(2)

  • \(Vs(t)\) は,式(1)な感じで現在の単語w(t)と過去の文脈の情報s(t-1)が詰め込まれたs(t)から,t+1番目の単語を予測するための写像
    • 行列Vの各行は,辞書中の各単語に対応づいていて,その行と \(s(t)\) の内積を取り,その単語のスコアが決まります.
  • \(g(\cdot)\) は,ベクトル” \(\cdot\) “にsoftmax関数を書けます(上図の式(3)右)
    • 式を見ると,入力の各次元mを指数関数で0以上の値に変換したあと,0~1の範囲に正則化しています.
    • つまり,softmax関数によってベクトルがその要素の確率分布に変換されています.
    • その次元は辞書と同じサイズなので,各次元が,次に各単語が来る確率となっています.
  • \(g(Vs(t))\) :つまり,この式で上記の情報が詰まった \(s(t)\) から,次にどの単語が来るか予想するわけです.

RNNLMの構造と各式の説明はこんなところです.

Back Propagation Through Time (BPTT)

BackpropagationはNNにおける,ネットワークパラメータの学習法です. 普通のBPでは,時間を考慮せずに,その時の入力,出力,教師信号だけでモデルを修正します.

BTTTでは,それに加え過去の時間も考慮した修正を行います. 時刻tの隠れ層は,時刻tの入力時刻t-1の隠れ層,だけでなく,時刻t-2以前の隠れ層の値も影響しているため, もっと時間を遡って修正しようということです.

../../../_images/bptt.png

この図では,過去の歴史としてt-1,t-2の状態を保持しておいて誤差や修正に加えます.

  • 緑で,計算した各ベクトル \(s(\cdot), y(t)\) がどの位間違っているかを計算
  • 次にオレンジで,その間違いをもたらした原因であるパラメータ \(U,W,V\) を修正

という流れです,BPTTだと,過去の状態まで見て修正を行います 実際には,計算量的に過去の履歴を見るのは \(\tau\) までと決める,truncated BPTT が使われたりします.図では \(\tau = 3\) ということになります.

\(e_o, e_h\)

  • \(e_o(t)\) : \(y(t)\) は次の単語 \(w(t+1)\) を予測するための確率分布でした,なので \(w(t+1)\) との差が誤差になります.

  • \(e_h(t)\) : 隠れ層の誤差です.自分の先の誤差( \(e_o(t)\) )が重み( \(V\) )付きで逆向きに流れてきています.

  • \(e_h(t - \tau - 1)\) : 過去の隠れ層の誤差です.自分の先の誤差( \(e_h(t-\tau)\) )が重み( \(W\) )付きで逆向きに流れてきています.
    • 関数dは,隠れ層を計算する際に使ったシグモイド関数の微分をかけることを意味しています

\(U, V, W\)

まず,共通の形がありますが,これは具体的な更新の処理です.

  • \(X(t+1) = X(t) + なんたら\alpha - X(t)\beta\)

この \(なんたら\) の部分が勾配です.\(\alpha\) が学習率, \(\beta\) がL2正則化の係数です.

また,行列の勾配は,よく見るとその行列の”出力側の誤差”と”行列への入力”の直積( \(XY^T\) )だということがわかると思います

  • V: \(s(t)e_o(t)^T\)
  • U: \(\sum_{z=0}^{T} w(t-z)e_h(t-z)^T\)
  • W: \(\sum_{z=0}^{T} s(t-z-1)e_h(t-z)^T\)

U,Wについては,過去の分も合わせて足し合わせています.

以上が,BPTTの説明の一回の修正についての説明です. これを訓練データで回してモデルを学習します.

最終的に,

  • モデル全体を言語モデルとして使う
  • \(U\) を取り出して,単語の特徴ベクトルとして他のタスクの素性として使う

などのことができます.

モデルの拡張版も幾つか提案されていますが,ここでは割愛

Analysis

このモデルで学習されたベクトルについて興味深い分析が行われています. 論文のタイトルと概要だけしょうかいします.

word2vecでも有名な分析だと思いますが,

“King” - “Man” + “Woman” と,三つのベクトルを足し引きしてできたベクトルと一番近い辞書中の単語を調べると,”Queen”が出てきましたよというもの.

男女,国と首都,複数形と単数形など,”関係”というものがoffsetという形で埋め込まれていることを示しました.

同じ意味合いの形容詞でも,その強さは異なります.

okay < good < excellent

こんな感じに,

学習された単語ベクトル空間上に,名詞と同じように,形容詞にもなんらかのなにかがないのか?ということに焦点を当てて分析を行なった論文です.

実験設定がユニークで面白いです. こちら の著者スライドが分かりやすいと思います.

RNNLMをとりあげた資料たち

まだ軽く調べただけですが,rnnlmについて他に日本語で資料を探すと,

  • rnnlm - slideshare

    まさにrnnlmをメインに取り上げたスライドです.被ってしまいましたが記事は書き始めてしまってたので強行しましたw

  • ⾃然⾔語処理分野におけるディープラーニングの現状

    IBIS2013のdeep learningに関する企画セッションのうちの一つ,rnnlmだけでなくnlpにおける網羅的なスライドで分かりやすいです. IBISは残念ながら行けなかったけど, 企画セッションのページ に他のスライドも上がっているので良かったです.

  • deep learningの技術と未来

    過去のpfiセミナーの資料でdropout,curriculum learningなど,deep learningに装備することで成功している技術などにも触れてくれています. 最後の付録として,rnnlmによる研究が紹介されています.

あたりがあります.

まとめ

時系列を扱うNNであるRecurrent Neural Networkを利用したニューラル言語モデル, RNNLMについて記事を書きました.

nn,rnn,nnlm,rnnlmあたりのイメージがざっくりできてもらえればと思います.

]]>
Mon, 09 Dec 2013 00:00:00 +0900
http://kiyukuta.github.io/2013/09/28/casualdeeplearning4nlp.html http://kiyukuta.github.io/2013/09/28/casualdeeplearning4nlp.html <![CDATA[自然言語処理まわりのDeep Learningを自分なりにまとめてみた]]>

自然言語処理まわりのDeep Learningを自分なりにまとめてみた

“自然言語処理のためのDeep Learning”というスライドを公開しました.

自然言語処理のためのDeep Learning from Yuta Kikuchi

カジュアルな感じで自然言語処理まわりのDeep Learningの話題をまとめた感じになっています.

きっかけは,勉強会をしていることを知ったOBのbeatinaniwaさんにお願いされたことで, 株式会社Gunosyの勉強会の場で,発表の機会を頂きました. それが,9/11で,その後9/26に研究室内で同じ内容で発表しました.

どちらも思った以上に好評を頂け,公開してはと進めて頂いたので,公開することにしました. もちろん間違いが含まれている可能性も多分にあるので.気づいた方はご指摘頂けると幸いです.

内容ざっくり

前半は,ニューラルネットワークを図を使った軽い説明になっています. NNがあって,Deepは難しかったけど,2006年にブレークスルーが起きて...みたいな 1~77枚目はそんな感じで,そのうち15~58枚目は,以前ボクが公開した ” A yet another brief introduction to Neural Networks”そのままになっています.

Deep Learning関係の話を良く知っている方なら何度か聞いたことある話ばかりだと思うので, 自然言語処理の話題に行きたい人はいきなり78枚目以降を見ていただければと思います.

ほかに

関連記事としておすすめなものに,

Deep Learning : Bengio先生のおすすめレシピ

があります,一度勉強した身としては全体的な復習としてとてもよい資料になっています. こちらはNLPではないですが,ニューラルネットとしてはいちばんオーソドックスな2層NN以上のモデルたちを実装しようとしたときに必ず約に立ちます.

]]>
Sat, 28 Sep 2013 00:00:00 +0900
http://kiyukuta.github.io/2013/09/09/a_yet_another_brief_introduction_to_neural_networks.html http://kiyukuta.github.io/2013/09/09/a_yet_another_brief_introduction_to_neural_networks.html <![CDATA[A yet another brief introduction to neural networks]]>

A yet another brief introduction to neural networks

過去にニューラルネットワークについて発表したスライドを改訂したものをslideshareアップしました.

説明を簡略化するために,細かい式の導出やバイアス項などはスルーしています. なんとなくネットワークのイメージや計算の流れが分かってもらえたらという気持ちで作りました.

それにしてもこれは説明しないとだろ,って所は指摘して頂けるとありがたいです.

A yet another brief introduction to neural networks from Yuta Kikuchi

そして,はじめてslideshareを使ったのだけど,Tinkererへの埋め込みがうまくいかなかった...

が,こちらの記事の方法で解決しました.

[雑記][はてな]slideshareの仕様変更(?)ではてなダイアリーに表示出来なくなった件について

上記記事を参考に,「allowfullscreen」,「webkitallowfullscreen」と「mozallowfullscreen」を削除したら無事表示できました.

]]>
Mon, 09 Sep 2013 00:00:00 +0900
http://kiyukuta.github.io/2013/09/04/mecab_wakati_lemma.html http://kiyukuta.github.io/2013/09/04/mecab_wakati_lemma.html <![CDATA[MeCabの分かち書きの出力を基本形で行う]]>

MeCabの分かち書きの出力を基本形で行う

<訂正>

こちらの記事に,同じ話題をより良い方法で実現する方法があると教えていただきました.

MeCabの出力フォーマット - 唯物是真 @Scaled_Wurm

公式の 出力フォーマット一覧 も改めて見たらちゃんと乗ってました,流し読みしてしまっていた...

必要になったので,MeCabの分かち書き(-Owakati)での出力を, 表層形でなく基本形として出力するオプション(-Owakati_lemma)を追加で書いてみました.

% echo "諦めんなよ!" | mecab -Owakati
諦めん な よ !
% echo "諦めんなよ!" | mecab -Owakati_lemma
諦める な よ !

MeCab

自然言語処理界隈で知らない人はいないであろう,オープンソースの形態素解析エンジン.

Wikipedia記事: http://ja.wikipedia.org/wiki/MeCab

公式ページ: http://mecab.googlecode.com/svn/trunk/mecab/doc/index.html

自然言語処理関係者でなくても,テキストを使ったウェブアプリを 開発している人たちにも広く利用されていると思う,

例として”MeCabで形態素解析を行うとこうなる.”という文をMeCabにかけると

% echo "MeCabで形態素解析を行うとこうなる." | mecab
MeCab      名詞,一般,*,*,*,*,*
で      助詞,格助詞,一般,*,*,*,で,デ,デ
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
を      助詞,格助詞,一般,*,*,*,を,ヲ,ヲ
行う    動詞,自立,*,*,五段・ワ行促音便,基本形,行う,オコナウ,オコナウ
と      助詞,接続助詞,*,*,*,*,と,ト,ト
こう    副詞,助詞類接続,*,*,*,*,こう,コウ,コー
なる    動詞,自立,*,*,五段・ラ行,基本形,なる,ナル,ナル
.      記号,句点,*,*,*,*,.,.,.
EOS

という結果が得られる. echoで渡さずに,単に mecabとコマンドラインに打っても実行できる. この場合は入力待ち状態になるので,好きな文を入力するとすぐさま結果が出力される.

そして, 分かち書き とは,上の結果まで詳細に品詞などの情報は必要なく, 単に文が形態素で区切られた形だけ欲しいという時に使える.

具体的には,実行時に”-Owakati”という出力形式のオプションを渡せばOK. (出力形式は他にも”-Ochasen”,”-Oyomi” などもある他,ユーザで定義することもできる)

% echo "MeCabで形態素解析を行うとこうなる." | mecab -Owakati
MeCab で 形態素 解析 を 行う と こう なる .

このように,形態素が半角スペースで区切られた文が出力される.

なぜ分かち書き?

英語のテキストはデフォルトで半角スペース区切りされているので, 英語用に開発されたソフトウェアには,入力として生の英語テキストを入力としたもの存在する.

つまり 単語が半角スペースで区切られた文たち を入力として受け取るシステム.

そんな時に分かち書きを使うと,日本語テキストを,そのシステムに入れるための形に 変換するためのスクリプトをわざわざ書かずに,コマンドライン上で解決することができます.

% meacb -Owakati < ja.txt > ja_wakati.txt

このように,リダイレクションを用いて分かち書きされたコーパスに変換できます.

なぜ見出語?

文中に出てきた表現は格変化などが起きるが,もちろん辞書中にはそれに対応する基本形 が存在します.(辞書の”見出し語”と言うことも.)

MeCabの標準的な出力では,コンマ区切りの7番目の要素にこの情報が含まれます.

% echo "形態素解析すりゃいいだろ!!\n形態素解析しろや!!!" | mecab
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
すりゃ  動詞,自立,*,*,サ変・スル,仮定縮約1,する,スリャ,スリャ
いい    形容詞,非自立,*,*,形容詞・イイ,基本形,いい,イイ,イイ
だろ    助動詞,*,*,*,特殊・ダ,未然形,だ,ダロ,ダロ
!      記号,一般,*,*,*,*,!,!,!
!      記号,一般,*,*,*,*,!,!,!
EOS
形態素  名詞,一般,*,*,*,*,形態素,ケイタイソ,ケイタイソ
解析    名詞,サ変接続,*,*,*,*,解析,カイセキ,カイセキ
しろ    動詞,自立,*,*,サ変・スル,命令ro,する,シロ,シロ
や      助詞,接続助詞,*,*,*,*,や,ヤ,ヤ
!      記号,一般,*,*,*,*,!,!,!
!      記号,一般,*,*,*,*,!,!,!
!      記号,一般,*,*,*,*,!,!,!
EOS

上の文で すりゃしろ も,基本形は する であり, コンマで区切られた7番目の要素を見ると,基本形の する が記されていることが分かります.

一般に,これらは全部 する なわけですから,全部 する にしてしまってから 処理してしまったほうが良いです. する , しろ , すりゃ ,という別々の単語が 一回ずつでた,と考えるよりも, する が3回出たと扱うわけです.

ですが,デフォルトの分かち書きオプションでは,表層形を分かち書きしたものが出力されるので, 分かち書きした上で見出語に変換してあると助かります.

イメージしやすいように,仮想のオプション-Owakati_lemmaを導入すると.

% echo "諦めんなよ!" | mecab -Owakati
諦めん な よ !
% echo "諦めんなよ!" | mecab -Owakati_lemma
諦める な よ !

といった機能があると,助かったりします.

wakati_lemmaを導入するパッチを書いた

こちらのGist にあげているので,当て方や使い方はそこのREADMEを参照して下さい.

処理としては,まず未知語(辞書に未登録野語,読みや基本形が”*”)かチェックし, 未知語なら表層形をそのまま出力し, そうでない場合は,文字列の後ろから”,”を手がかりにして,基本形に該当する部分文字列を取得しています.

おまけ1 パッチの作り方

パッチの作り方については以下の記事が参考になりました.

[機械学習]LibSVMのcross validationオプションでprecision/recallを出力する

基本的には,この記事と同じです.簡単! ただし,今回はヘッダーファイルにも変更を加えているため,二つパッチを用意するのかー? と思ったが,試したら以下のように追加で書き込むだけで大丈夫だった.

% diff -u writer.cpp writer-new.cpp > writer.patch
% diff -u writer.h writer-new.h >> writer.patch

おまけ2,awkで基本形辞書

コーパスから,そこに含まれている単語に通し番号をつけるという処理もよく必要になります.

% mecab < corpus.txt | cut -f1 | sort | uniq -c | sort -nr | awk '{print NR"\t"$2}' > dic.txt

たとえば,こうやってパイプでつないでいくと,出現頻度順に並んだ, 番号付きの単語一覧ファイルdic.txtが出来上がります.

ただしこれは,表層形で辞書を作っているので, この時に,wakati_lemmaと同じように,未知語以外は基本形に直すという処理に変更すると,

% mecab < test.txt | awk -F"\t|," '{print $8 == "*" ? $1 : $8}' | sort | uniq -c | sort -nr | awk '{print NR"\t"$2}' > dic3.txt

たとえばこう書けます.たまに使うけどawk便利.

これで,基本形での分かち書きされたテキストコーパスと, そのコーパスに出現した通しid付きの辞書ができたので, コーパスをid列に変換するみたいな,後の処理に使えます.

]]>
Wed, 04 Sep 2013 00:00:00 +0900
http://kiyukuta.github.io/2013/08/20/hello_autoencoder.html http://kiyukuta.github.io/2013/08/20/hello_autoencoder.html <![CDATA[Hello Autoencoder]]>

Hello Autoencoder

最近,身内でDeep Learningを題材に含んだ勉強会を行なっている.

メインは専門である自然言語処理まわりだが, とりあえず実装(というよりnumpy)の導入になる上,結果を視覚化できることから, 画像データを利用したAutoencoderの実装について取り扱った.

軽い説明と共にコードと,色々な結果を

Autoencoder

Autoencoderとは,Neural Networkの特殊系で,基本的には

  • 入力層と出力層のユニット数が同じである.
  • 教師信号として入力そのものを与える.

という特徴を持つ.

../../../_images/autoencoder.png

入力と出力が共に4次元で,隠れ層が2次元なAutoencoderの図

Autoencoderは,入力の情報をを一度隠れ層の空間に写像(encode) したあと, 元の信号を復元(decode)するようなパラメータを学習する.

図のように,もしも隠れ層のユニットが入力層のものよりも少ない場合は, decodeの際,より少ない情報から元の信号を復元する必要がある. そのため,そのようなことが可能なパラメータが学習できれば, Autoencoderは非線形な次元圧縮器とみなすことができる.

具体的な計算式は以下で,パラメータとは \(W_1, W_2, b_1, b_2\).

\[\begin{split}hidden &= encode(input) &= f( W_1 input + b_1) \\ output &= decode(hidden) &= f( W_2 hidden + b_2)\end{split}\]

圧縮された表現(この場合4次元の入力が2次元に圧縮されている)は,元の情報から, 大切な情報だけをうまく抜き出したなんか良い感じのもの

Denoising Autoencoder

Autoencoderの派生系の一つにDenoising Autoencoderがある. 入力にノイズを付与し,そのノイズを取り除くようなencoderを学習しようというもの. 出力層で再構築する対象は,ノイズ付与前の入力なので,Denoising Auroencoderは,

  • 入力の情報を保持する良いencoderの学習

に加えて

  • 入力に加えられたノイズを除去する

ことも学習しなければならない.

以下の画像のように,N%の画素が欠落ことがノイズに相当する.(教師は常に左のオリジナル)

../../../_images/noising.png

Autoencoderを複数積み上げるStacked Autoencoderの構成要素にこれを採用することで, かなり性能が上がる .

実装

コードは こちらのGist に. 実行にはnumpy, PILが必要.

最初に,autoencoder.py冒頭のコメントにあるように,MNISTのデータセットをDLする.

これは,28*28の手書き数字画像(0~9)が大量に入ったデータベース. そのためautoencoderの入力,出力次元は784.

可視化

隠れ層の各ユニットにつながる重み(入力画像と同じ次元になる)を可視化 (参考は こちら ).

なので,隠れ層が100だったら,28*28の画像が100枚並んだものが出てくる. 白いと重みの値が大きく,黒いと小さい.

結果

いくつか条件を変えて学習されるパラメータ画像を見る.

感想は,画像を見て個人的に感じたことであって,ちゃんとした考察ではない. (可視化についてちゃんと調べていずれちゃんと書きたい)

Autoencoder

../../../_images/b20.bmp

隠れ層が100ユニットで,ノイズ付与なしのAutoencoder

python autoencoder.py 100

Denoising

ノイズの付与率によるパラメータの違い.

結果は以下

  • noise 20%
python autoencoder.py 100 -n 0.2
../../../_images/b20_n20.bmp
  • noise 50%
python autoencoder.py 100 -n 0.5
../../../_images/b20_n50.bmp
  • noise 80%
python autoencoder.py 100 -n 0.8
../../../_images/b20_n80.bmp

ノイズを載せたほうが,載せない( Autoencoder のとこの画像)よりもそれっぽい学習ができている隠れユニットが多い.

80%もノイズをのせると,情報がなさすぎるためか, 答えを丸暗記しているためそのまま数字が浮かび上がってしまっている?過学習? つまり,データに潜む本質的な情報を捉えることを放棄している? (要出展)

number of hidden units

隠れ層のサイズを784にしてみた時の様子. 入力層,出力層,隠れ層が同じなので,あまりうまく学習できないという噂. ※わりと時間かかります(一時間半から二時間くらい?)

visualize_weights()の最後二行のコメントアウトを外し,直前の二行をコメントアウトする必要あり. デフォルトだと,784枚中最初の100枚分しか出ません

python autoencoder.py 784
../../../_images/h784.bmp

たしかに,さぼっている(という表現で良いのか?)隠れユニットが多い.

ノイズを付与していくと...

  • noise 20%
python autoencoder.py 784 -n 0.2
../../../_images/h784_n20.bmp
  • noise 50%
python autoencoder.py 784 -n 0.5
../../../_images/h784_n50.bmp

全体的に学習しているっぽくなってる. Denoisingの80%と似たような感じになっている隠れユニットも存在する (そもそも悪いことなのかは分からないが)

てっとり早いのは,encodeされたcodeを入力とするsoftmax層を載せて, 実際に0~9の分類を行わせてスコアを見るのがよさそう(なのでそのうちやってみよう)

Tied vs. Untied weight

decoderとencoderが転置の関係にあるのがTied weight ( \(W_2 = W_1^T\) ).

逆にencoderとdecoderを別々に学習するのがUntied.

どっちが良いかはよくわからない.

とりあえず画像だけ.プログラムではuオプションをつけるとuntiedになる.

  • Untied な場合のencoder
../../../_images/W1_n50.bmp
  • Untied な場合のdecoder
../../../_images/W2_n50.bmp
  • Tied weightな場合のencoder (転置するとdecoder)
../../../_images/b20_n50.bmp

はじめの方はなんとなくuntiedなのの方が良いのかな?と思ってたけど, よく考えたらAutoencoderをStacked autoencoderに組み込む際は,decoderは使用しない. なので,decoderとencoderを別に学習するUntied weightなモデルは無駄が出てしまうかもしれない? (decoderの方が特徴っぽいのが大きく出ているし)

validation.pyについて

最後に,gistについてるvalidation.pyについて. back propagationにおける勾配計算の**コードが正しいか否か**を判別するための方法.j

back propagationはデバッグがしにくいが,これを使うと割と楽.

\[\frac{d}{d \theta} J(\theta) = \lim_{\varepsilon \to 0} \frac{J(\theta + \varepsilon) - J(\theta - \varepsilon)}{2 \varepsilon}\]

を勾配の近似とし,計算した勾配の値と比べる. 二つの差分が十分小さくなれば,勾配の計算部分にバグはないという確認ができる.

参考は Gradient checking and advanced optimization など

この項目は最後の最後に書いてないの見つけて急いで書いたので,いずれ詳しくメモを書きたい.

]]>
Tue, 20 Aug 2013 00:00:00 +0900
http://kiyukuta.github.io/2013/08/16/hello_math.html http://kiyukuta.github.io/2013/08/16/hello_math.html <![CDATA[Hello math. Tinkererで数式を扱う]]>

Hello math. Tinkererで数式を扱う

\[\frac{1}{1^0} + \log{\exp{1}} = \sum_{i=0}^{9} 0.1\]

Tinkererにおける数式の表示について,すぐには見つからなかったのでメモ. 基本的には,Sphinxがベースなので,

  • sphinx.ext.pngmath
  • sphinx.ext.mathjax
  • sphinx.ext.jsmath

のいずれかを使うことになる.(詳しくは こちら )

いずれも,\(\TeX\) の形式で数式が書けるので便利. ちなみに,上の数式はMathjaxで書いたもの.

sphinx.ext.pngmath

数式の画像が conf.pyに以下を追加するとできる. latex環境が整っていなければいけない.

sphinxの場合は,システムによる環境の違いを懸念して, 以下のようにbuild時のオプションとして渡せと書いてある.

sphinx-build -b html -D pngmath_latex=C:\tex\latex.exe . _build/html

しかし,Tinkererの場合のその方法がよくわからなかったので, とりあえずconf.pyに直書きした.

extensions += ['sphinx.ext.pngmath']
pngmath_latex='platex'

このような画像になる.

../../../_images/sample_pngmath.png

sphinx.ext.mathjax

jsMathの後継的な?

これは,Sphinexと同じようにconf.pyに書けばOK

extensions += ['sphinx.ext.mathjax']
mathjax_path = 'http://mathjax.connectmv.com/MathJax.js?config=default'

上の数式の再掲になるが,こんな感じ

\[\frac{1}{1^0} + \log{\exp{1}} = \sum_{i=0}^{9} 0.1\]

sphinx.ext.jsmath

うまくいかなかった. Firefoxだと表示されるけど,Chromeだとされないとか. まぁMathjaxがあるのでぶっちゃけもう良い感じではある.

まとめ

Mathjaxを使います.

]]>
Fri, 16 Aug 2013 00:00:00 +0900
http://kiyukuta.github.io/2013/08/15/hello_world.html http://kiyukuta.github.io/2013/08/15/hello_world.html <![CDATA[Hello world]]>

Hello world

Tinkererでブログ始めてみました. 以前Sphinxを先輩に教えてもらったので,同じような感覚でできるTinkererにした. 自分はにわかSphinxerだけど, Sphinx拡張も使えるらしいのでよくSphinxを使っている人にとっては良さそう

過去二年間ほど,この時期にブログをはじめてすこし記事を書いて放置している. 毎年この時期にブログ意識を持つのはなぜなのか...続かないのがたちが悪い.

]]>
Thu, 15 Aug 2013 00:00:00 +0900