Hatena::ブログ(Diary)

Mi manca qualche giovedi`? このページをアンテナに追加 RSSフィード

2017-10-02 他にも大きいのを見つけたら追記するかも

「Chainer による実践深層学習」の気づいたこといくつか



Chainer について書かれた数少ない本。

この9月に v2 対応版が出た。が、v3 リリース秒読みの時期に……というツラミはある*1

深層学習ライブラリは現状「泳ぎ続けなければ死ぬ」(アップデート止まったら、終わったのかな? とか思っちゃう)ので、宿命的にしょうがないのかな。


社内でこの本の読書会とかしており、ちょいちょい間違いを見つけてしまう。

細かいのはもういいかなとは思うんだが(全部書いてたら正直キリがない)、せっかくの Chainer 本、読者が誤解すると事故が起きそうなちょっと大きめの間違いを放置するのはもったいないので、ここにメモしておく。

自分で読んだのは RNN 以降なので、主にその範囲。


以下、章・ページやリスト名などの表記は v1 版だが、v2 版でも残っていれば特定は難しくないと思う。

手元にあるのは v1 版で、v2 版では直ってるかもしれない。が、ちら見した感じでは残ってそうだった……。

ちなみに著者の新納先生のサイトに Erratta も出ているので参考に。見つけた間違いはほとんど載っていないが……。


7.7 Chainer による LSTM の実装(p98-99)


LSTM をあえて基本的な部品だけで実装する、本書の白眉


lstm0.py のパラメータ宣言部で、式 Wx+Rh+b を実装するのに W 用の L.Linear と R 用の L.Linear を宣言しているが、両方がバイアス項を持つため、ダブってしまっている。Wx+Rh+a+b という状態。

致命的な悪さはおそらくしないだろうが、メリットは何もない*2ので、片方に nobias=True をつけて、バイアス項を一本化するべきだろう。

学習時間も 5% ほど短くなる。


class MyLSTM(chainer.Chain):
    def __init__(self, v, k):
        super(MyLSTM, self).__init__(
            embed = L.EmbedID(v, k),
            Wz = L.Linear(k, k, nobias=True),
            Wi = L.Linear(k, k, nobias=True),
            Wf = L.Linear(k, k, nobias=True),
            Wo = L.Linear(k, k, nobias=True),
            Rz = L.Linear(k, k),
            Ri = L.Linear(k, k),
            Rf = L.Linear(k, k),
            Ro = L.Linear(k, k),
            W = L.Linear(k, v),
        )

7.7 Chainer による LSTM の実装(p100)


また学習の部分は素の RNN のものと同じでよいのですが、計算時間がかなりかかります。RNN の学習には unchain_backward() という関数を使うことで改善されます。これは長い系列を学習する際に、古い情報を捨てて、計算時間を改善するのに使います。ここでは文の長さが 30 を超える場合に、この関数を起動することにします。


と記述されているが、残念ながらここでの使い方では unchain_backward は全く効果がない。

本書の lstm0.py で unchain_backward を入れたり削ったりしたときに性能が変わったように見えたとしても、それはおそらく初期値の乱数の影響である。


unchain_backward は、L.LSTM のような「前時刻の隠れユニットや記憶の状態をメンバーとして保持しておき、各時刻ごとに __call__ を呼ぶ」タイプの実装を前提として設計されている。RNN のグラフの横方向の辺を切って、計算グラフを小さくするために、例えば 30 時刻ごとに unchain_backward を発行する。加えて、公式のサンプルを含め、多くの LSTM 実装では「1系列=全データをつなげたもの」なので、切らないと大変なことになる。


しかし、本書の lstm0.py は「__call__ には系列全体を渡す。隠れユニットや記憶の状態は __call__ の先頭でローカル変数として宣言&初期化する」タイプの実装となっている。したがって、前の __call__ のあとに unchain_backward を発行しようがしまいが、次の __call__ が呼ばれたときは計算グラフは切れている。


ちなみに本書では「1系列=1文」であり、truncate しなくても死なない。が、隠れユニットが 100 次元しか無いので、適切に切ったほうがおそらく性能は高くなるだろう。

しかし lstm0.py で truncate したいと思っても、学習ループ(特に backward 発行)と時刻のループが別れてしまっているので、簡単な改造では難しそう。同等ではないが、 __call__ の中で、30時刻ごとに h.unchain() と c.unchain() を発行すれば、近いものになるのかな?


8.5 Attention の導入(p123)


Encoder の各時刻の隠れベクトルを Decoder に渡すためのリスト gh を作る部分の説明。


リスト gh に Encoder 側の ¥tilde{h}_i を順番に追加しています。

(中略)

gh に ¥tilde{h}_i を追加する際に、明示的に np.copy を使っていますが、おそらく必要ありません。そのまま ht.data[0] を渡しても問題ないとは思いますが、念のためコピーしました。


コピーしちゃダメーーー!!!


.data やそのコピーではなく Variable のまま渡さないと、せっかくの計算グラフが切れてしまう。

Decoder に渡す変数(もともとの Attention では隠れユニットを渡すが、最近のモデルでは Encoder の出力を渡すのが流行っている?)の計算グラフを切ってしまうと、「Attention にも有効なように Encoder が符号化してくれる」という Attention の嬉しさの一つが消えてしまう。


というわけで、コピーしないで、Variable のまま渡しましょう。

*1:ちなみに v1 版も、Chainer v2 が出た後の出版、しかも v1.10 準拠だった……

*2:aとbが最適解を持たないというデメリットはある

2017-09-27 最近トピックモデルのコードあんまり書いてないなー

無限関係モデル(Infinite Relational Model)の紹介資料+実装


サイボウズ・ラボでは社内向けの機械学習勉強会を 2012年から週1ペースで継続している(前身の PRML 読書会も合わせれば 2011年から)。割り振られた担当者が、書籍や論文など読んだり、実装してみた話などを紹介している。


例えば今年の4月以降の勉強会のネタをピックアップするとこんな感じ。明らかに「いわゆる機械学習」周辺にすら含みようがないネタもポロポロあるが、「機械について学習」くらいまで拡大解釈している、ことにしてほしい(苦笑)。


  • プライバシー保護データマイニング
  • 並行実行制御
  • 強化学習
  • 状態空間モデル
  • 秘密計算(暗号化したまま各種演算)
  • 確率論
  • seq2seqで計算
  • Attention
  • End-to-End Memory Networks
  • WebAssembly
  • 複雑ネットワーク
  • "Why does deep and cheap learning work so well?"
  • "Sliding right into disaster"

この勉強会の資料は一部公開されている。西尾さんの強化学習や、光成さんの暗号系などなど。



中谷も当勉強会で機械学習自然言語処理のネタを紹介してきたのだが、資料はほとんど公開してなかった。口頭の説明やその場での書き込み前提とか、著作権的な配慮が足りてないとか、内部データを使っちゃってるとか、セキララな毒舌が炸裂してるとか、要は内部勉強会なことに甘えて作りがユルかった。

まあでもやっぱりもったいないので、先週から資料を人に見せられるレベルまで改訂して公開週間を始めた。第1弾が Memory Networks で、第2弾がこの無限関係モデル(Infinite Relational Model)。



無限関係モデルは2年くらい前(↓このあたりのブログ記事を書いていた頃)にやったので、上の最近の勉強会ネタリストにはない。



古いネタを掘り起こしてきたのは、実装があるものを優先したため。



この実装では、スライドでも説明しているとおり、ベルヌーイ分布をポアソン分布に替えた「0/1 じゃない関係解析」版を実装してみている。

が、ポアソン分布が外れ値に弱いので、ちょっと多い項目があると1要素のクラスタを作ってしまい、残念ながら使い物にならなかった。負の二項分布あたりを使いたいところだが、全情報付き事後分布を閉じた形で書き下せないだろう……。

CRP を Stick Breaking で書き直して、トピック数の上限入れて、Stan あたりで解かせてみるというのも考えたけど、ちょっと大きくなるだけで死ぬよな。まずはモデルとして意味があるか検証する、ってならアリかもしれない。


「古いネタ」なんて言っちゃったが、引き続き「続・わかりやすいパターン認識」はノンパラベイズについてきちんと詳解してくれている希少な和書だろう。続パタ以外となると、今なら佐藤一誠さんの「ノンパラメトリックベイズ」(MLP青シリーズ)があるので、もう1つ選択肢がある? でも続パタとは難易度がかなり違うので、読者層は重ならないかもしれない(と、えらそうに評してみたが、買っただけでまだ読んでない。ごめん)。


ノンパラベイズ、というかトピックモデルは昨今の深層学習ブームに押されまくっているが、内部の構造を想像しながらモデリングする楽しさは(一般的な)深層学習には無いものなので、またそのうち揺り戻しが来るかも?


というわけで次の資料公開週間は、実装があるので GAN あたりかな(トピックモデル推しの舌の根も乾かぬうちに……)。

GAN の記事や資料はすでに溺れるほどあるのであまり意味ないかもしれないが、Conditional GAN をやってる人は少ないっぽいので、そのあたりはちょっとおもしろいかもしれない。

2016-02-03 今年のお年玉駄文、ネタはあったがヒマがなかったorz

「続・わかりやすいパターン認識」13章「共クラスタリング」の無限関係モデル(IRM)の数式について #ぞくパタ

ということを1年近く前につぶやいたりしてたのだが、オーム社のサイトで「続・わかりやすいパターン認識」(以降「ぞくパタ」)の正誤表がちゃんと公開されていることに最近ようやく気づいた。

上のツイートで言っている式 (6.9) ももちろん修正されているし、以下の記事で書いていた8章の問題点もことごとく手当されている。すばらしす。

まあこのツイートやらブログやらを参考にしてもらえたかどうかは定かではないわけだが、どこかで間違いを指摘しておくと反映される可能性がある、というのは勇気づけられる話。


話は変わって、2014/12 から開催されていた「続・わかりやすいパターン認識読書会が先月めでたく最終回を迎えた、っぽい。

「ぽい」というのは、最後の2回に参加できなかったから。

まあもともと興味のある回にとびとびにしか参加してなかったわけだが、12章後半はある意味ディリクレ過程混合モデルの実装編で、この本のクライマックスだったから是非参加したかった。13章の無限関係モデル(IRM)も一応参加してみたかったところ。


というわけで参加できなかったフォローというか腹いせというか、で無限関係モデルを実装でもしてやろうと思って本を読み始めたのだが……。


まだ読んでいる人が少ないせいだろうか、少なくない数式が結構大胆に間違っている。

まあ、だいたいどの間違いも一目見て間違っていることはわかる(左辺に j がないのに、右辺に消えない j が残っている、とか)ので、抜き打ちの演習みたいなものか。

「これくらい計算できるよね?」という読者への親心を無下にするのも心苦しいが、見つけてしまった間違いはじゃんじゃん指摘してしまおう。


というわけで、この記事はぞくパタ13章の数式の誤りを淡々と指摘するだけの記事であり、IRM(Infinite Relational Model) がなにかわかるような記事ではないので、あらかじめ。


まずは p284 の式 (13.8)。右辺の分母に n が現れているが、実は n なんてどこにも定義されていない。

n_i^1 とか n_{(k,+)(i,j)} とか、そういうややこしいのはいろいろ定義されている*1からだまされるかもしれないが、ワナである。

この n の位置に入るのは、s_k^1 の個数なので正しくは K である。


P(s_k^1=¥omega_i^1|{¥bf s}_{-k}^1)=¥begin{cases}¥frac{n_i^1}{K-1+¥alpha}¥hspace{12}&(¥text{existing cluster})¥¥¥frac{¥alpha}{K-1+¥alpha} & (¥text{new cluster})¥end{cases}


次は同じ p284 (13.9) 式の新規クラスタのときの式。G_0({¥bf¥theta}_{i,+}) という記号が出てくる。

11章12章でさんざん見てきたので、ついうっかり知ってる記号だと思ってしまったかもしれないが、これも未定義である。

G_0 は11章12章ではディリクレ過程の基底分布として使われていた記号だが、13章では2次元の構造を持つクラスタを素のディリクレ過程ではモデリングできず、CRP(中華料理店過程)でモデリングされているため、そもそもディリクレ過程自体が出てこない。


「ディリクレ過程だったら基底分布にあたるもの」なら p281-282 にて導入されているベータ分布が相当する。

では G_0 はベータ分布なのだろうと解釈すると (13.9) 式で困ったことになる。


G_0(¥theta)={¥rm Be}(¥theta;a,b)


G_0 はパラメータθ(スカラー)の分布であり、それを束ねた {¥bf¥theta}_{i,+} (ベクトル)の分布ではないので、G_0({¥bf¥theta}_{i,+}) という書き方は厳密には間違いとなる。

と、なんかややこしげに書いてしまったが、解決方法は簡単。G_0 じゃなくて単に P({¥bf¥theta}_{i,+}) と書いて同時分布にしてしまえばいい。厳密に考えても何の問題もなく、当たり障りもない。いや、この本の表記だと小文字 p か。


次、p287 (13.26) 式。左辺に j がないのに、右辺に消えない j が残る。

これは \prod 忘れなので、単純に正解を記そう。(13.9) 式と同じく未定義 n も手当すると、場合分けの式それぞれ次のようになる。


¥displaystyle¥frac{n_i^1}{K-1+¥alpha}¥prod_j¥frac{B¥left(n_{(+,+)(i,j)}+a,¥;¥tilde{n}_{(+,+)(i,j)}+b¥right)}{B¥left(n_{(-k,+)(i,j)}+a,¥;¥tilde{n}_{(-k,+)(i,j)}+b¥right)}


¥displaystyle¥frac{¥alpha}{K-1+¥alpha}¥prod_j¥frac{B¥left(n_{(k,+)(i,j)}+a,¥;¥tilde{n}_{(k,+)(i,j)}+b¥right)}{B(a,¥;b)}


(13.27) 式も同様なので、略。ただし、n は L になる。

もっとも、K-1+α も L-1+α も k や l に依存せず、どうせ全部足して1にするときに消えてしまうから、どちらにせよ実装では省略してしまってよかったりする(笑)。


最後、p288 (13.28)式。 k,l が消えずに残る。これも \prod 忘れ。

例によって未定義 G_0 があるので、これも p(¥theta_{ij}) と直してあげつつ、2行目の式だけ正しく書きなおすとこうなる。


¥displaystyle =P({¥bf s}^1)P({¥bf s}^2)¥prod_{i=1}^{c^1}¥prod_{j=1}^{c^2}¥int¥prod_{k:s_k^1=¥omega_i^1¥¥l:s_l^2=¥omega_j^2}P(R_{kl}|¥theta_{ij})p(¥theta_{ij})d¥theta_{ij}


見つけた間違いはこれで打ち止めだが、2点蛇足。


その1。

この本の積分はちゃんと閉じた形式に計算しつくされており、実装者は自分で計算する必要がほとんどなくてすばらしいのだが、本文最後の積分であるこの ¥int¥prod_{k:s_k^1=¥omega_i^1¥¥l:s_l^2=¥omega_j^2}P(R_{kl}|¥theta_{ij})p(¥theta_{ij})d¥theta_{ij} だけは計算されていない。

ここまでの計算が全部できていたらこれくらい朝飯前(誇張抜き)なので、例によって抜き打ち演習として残しておいてもいいんだけど、せっかく全部の積分がやっつけられているのに雑魚一匹だけ残しておくのもなんだよなあ。というわけで、計算してしまおう。


¥int¥prod_{k:s_k^1=¥omega_i^1¥¥l:s_l^2=¥omega_j^2}P(R_{kl}|¥theta_{ij})p(¥theta_{ij})d¥theta_{ij}=¥frac{B¥left(n_{(+,+)(i,j)}+a,¥;¥tilde{n}_{(+,+)(i,j)}+b¥right)}{B(a,¥;b)}


その2。

p288 に「P(s^1), P(s^2) は式 (11.11) のイーウェンスの抽出公式で求める」とある。そういえば 12章でもほぼ同じ文言を見た(p265)。

というわけで式 (11.11)「だけ」で P(s) 類が計算できる……と思ったらこれがワナだったりする。


式(11.11)をよく見てみよう。


P_E(n_1,¥cdots,n_c)=¥cdots


左辺は P(s) ではなく P(n_1,¥cdots,n_c) なのである。実は、P(s) は並べ替えの自由度の分、確率はこれより下がる。

心配しなくても大丈夫、P(s) と P(n_1,¥cdots,n_c) の変換式は式 (11.17) としてちゃんと載っている。

というわけで「P(s^1), P(s^2) は式 (11.11) のイーウェンスの抽出公式と式 (11.17) で求める」だと親切である。


と、あれこれ書いたが、当然、ここに書いてあることにも誤りが含まれている可能性はある。もし間違いなどあればご指摘歓迎。

IRM 実装編はまた今度。


【追記】

社内勉強会の資料公開した。


無限関係モデル (続・わかりやすいパターン認識 13章)
https://www.slideshare.net/shuyo/infinite-relational-model

【/追記】

*1n_i^1n_{(k,+)(i,j)} では数えている対象が異なるので、個人的にはどちらかは m とか記号を変えて欲しかった。

2015-09-14 日本橋はおひるごはんの開拓が楽しい

「調査観察データの統計科学」読書会資料を公開しました(数式周りをフォロー)

因果推論、特に傾向スコアについて日本語で学ぼうとしたら、第一に名前が挙がるのは「調査観察データの統計科学」だろう。

ところがこの本、数式を中心に難が多く、読み始めたはいいけど困っているという人がかなり多そうだ。実は社内の機械学習勉強会でこの本を紹介したのだが、数式のフォローがかなり大変で、そこそこ端折ったにもかかわらず、3章が終わるまでに7回ほどかかってしまった。

特に3章頭の「難所」については、社内勉強会の時の資料をもとにメモを書いてブログに公開したりもしている。

ひと段落したら勉強会の資料も公開しようかと思っていたのだが、3章をとりあえず終わらせたところで力尽きて、ほったらかしにしてしまっていた(忘れていたともいう……)。が、上の記事のコメントで公開要請をいただいたので、ようやく重い腰を上げて資料を整え公開した。




1・2章についてはおそらく大きな問題はない。せいぜい、層別解析の紹介がおざなりすぎることくらいだろう(それは他の本で得るべき知識というスタンスなのだと思う)。

3章は、つじつまの合わない数式や記述が正直かなり多い。スライドではできる範囲でフォローしたつもりだがもちろん完全ではない。因果推論が専門なわけでもなんでもないので、「こうならつじつまがあう」という想像に基づくフォロー自体が適切ではない部分だってきっとあるだろう。資料の間違いや勇み足については指摘大歓迎なので、ぜひ。


書籍と対照させながら読んでもらうためのものなので、原則として記号は書籍のものを踏襲している。が、ひとつだけ記号の付け替えを行っている(θの真値をθ_0 から θ^* に)。

理由はスライドの中でも説明しているし、実際に数式を追ってもらったら納得いくと思うが、念のため。


企業で取り扱うデータの多くは、この本で言う「調査観察データ」、つまり実験室的セッティングが許されない状況で集められたデータであり、そんな「調査観察データ」でもバイアスを抑えた分析ができる(かもしれない)傾向スコアは多くの人が興味を持つ可能性があるだろう。

それなのに、数式が追えないという理由だけで詰まったり読まれなかったりするのはもったいない。この資料が「調査観察データの統計科学」を読む人の助けになれば幸いである。


え? 4章以降はって? まだ読んでないっす……。た、たぶん4章以降は3章ほど大変じゃないと思うよ。きっと……。

2015-07-15 次回はかなりのガチ?

「続・わかりやすいパターン認識」11章「ノンパラメトリックベイズ」の「クラスタリングの事前確率」について

昨日の「続・わかりやすいパターン認識」読書会にて、「ホップの壺や中華料理店過程のシミュレーションをみると、これを使うと均等にクラスタリングされるのではなく、クラスタサイズが大きいものから順に小さくなっていくようなクラスタリングがされるように見えるのだが、その認識で正しいのか」といった感じの質疑があった。

いい質問。


実は「続・わかりやすいパターン認識」(以降「ぞくパタ」)では、 p225 の「クラスタリングの事前確率の考え方」のところに、ダイレクトにではないがその質問の答えにつながることが書いてあったりする。coffee break というコラムの形になっているので、つい読み飛ばしちゃった人も多いかもしれないが、結構大事なことが書いてあるので一度じっくり読んでみるといい。


そのあたりも含めて読書会でフォローした内容をここにメモしておく。


まずそもそもの話として。

ベイズにおいて、事前確率(事前分布)の選び方に論理的な裏付けがありうるのか、というと、実のところ全く何もない。ぶっちゃけ事前分布はなんでもいい。

手前味噌だが、そのあたりのことは gihyo.jp での機械学習連載で書いたので、興味があれば一度。


理論的にはなんでもいいが、そこに人間様の都合が絡むと、こういう事前分布は困る、とか、こういうのは嬉しい、とか出てくる。

望ましい事前分布の条件として、どんな問題でも共通して求められるとすればこの 2つだろう。

  • ありうる事象(今回の場合は分割方法)の確率が非ゼロ
  • なんらかの方法で事後分布が計算できる

共役事前分布は後者の「計算できる」を最優先にした選び方になる。共役でなくても、今回のディリクレ過程のように「ギブスサンプリングできる」でもいい。そこらへんの詳細は 12章でやる話なので、ここではとりあげない。


ベイズ公式を見ればわかるが、事前確率がゼロである事象は、たとえどんなデータをもってきても、事後確率もゼロである。よって「ありうる事象」、つまり「答えとして考えられるすべての可能性」には非ゼロの確率を与えておかないといけない。

今やりたいことは「クラスタ数をあらかじめ決めない」なので、クラスタ数が3個でも4個でも5個でも、何個であってもちゃんと非ゼロの確率を持つ事前分布が必要なわけである。


さて、これで冒頭の質問に答える準備ができた。

ここで大事なことは、事前確率は非ゼロでさえあればどんなに小さくても(理論的には)いいということ。

ホップの壺(中華料理店過程)は、色(テーブル)ごとの玉(客)数の偏りが大きい分布だが、均等な分割、たとえば 500個の玉について 100, 100, 100, 100, 100 という割り方にもちゃんと非ゼロの確率が割り振られる。現実には到底観測されることなんかあり得ないほど低い確率だろうけど、ゼロでさえなければ、データが何とかしてくれる期待が持てるわけだ。


ただし、いくら何でもいいといっても、事前分布が「変」であるほど、「正しい答え」にたどり着くには膨大なデータ数が必要になる。逆に言えば、データ数が少ないと事前分布に引きずられる。

例えば 3 クラス× 50 データの iris データセットを 12章のディリクレ過程混合モデルに食わせると、100, 50 の2個のクラスタにまでは分かれるのだが、そこから分割が進まなかったりする*1。k-means (もちろん3クラス決め打ち)などなら、50, 50, 50 に近いところまで行くのだが。

これはおそらく事前分布であるディリクレ過程に引きずられているのだろう。


というわけで冒頭の疑問の答えは、均等な分割もちゃんと行われうるから大丈夫! という点では No だが、事前分布に負けて、希望よりも偏ったクラスタになることもあるという点では Yes でもある。

それなら、中華料理店過程のような偏った分割モデルではなく、もっと一様な分割を考えたらいいのでは? という発想が当然出てくるだろうが、実は可算無限な台を持つ一様分布は作れない(ちょっと考えれば雰囲気はわかる、はず)のと同じ理由で、どうしたって傾斜を持たせるしかなかったりする。


つまり、ディリクレ過程(やホップの壺や中華料理店過程)は、上の「任意クラスタ数で非ゼロ&計算できる」という条件を満たす中で一番易しいものなのだ。

とはいえ、他にもノンパラメトリックベイズのための無限分割モデルは解きたい問題にあわせて考えられており、ぞくパタ 11.4 でちらっと紹介されているピットマン・ヨー過程*2はその代表的な一つである。


読書会では、ピットマン・ヨー過程がなぜかついでに紹介されているっぽい刺身のツマのような扱いを受けていて、あわてて言語処理ではめっちゃ重要ですから! と突っ込んだり(笑)。

ある分野でどんなに有名であっても、その隣接分野ですら知られているとは限らないというよくある現象なんだけどね。

*1:ぞくパタに書かれている「全パターンが 1 つのクラスタに所属」という初期化だと、実はそれすらもままならず、150個が 1 クラスタのままから動かなかったりする

*2:ぞくパタで「ピットマン・ヨー過程」だといって紹介されているのは、正確には「中華料理店過程をピットマン・ヨー過程に対応するように拡張したもの」ではあるが