Online VB inference for HDP (Wang+ 2011) を実装してみたけど

HDP-LDA を Online な VB で解くという論文。
Teh さんらの VB 推論の論文も読んだんだけど、実にアクロバティックな分解が出てきて、いやこれはどうなんだろう……という気分になってしまい、実装してみる気にはならなかった。
一方、Wang さんらのこれはとても素直な式展開で、そんな簡単でいいんだーという感じ。自力で全部の式導出してみたけど、引っかかるところも特になし。


とはいえやっぱり VB なので、きつい独立の仮定がどれくらい精度に影響があるのか気になるところ。
アルゴリズムはとても簡単なので、これは試してみるっきゃあないでしょう、と実装してみた。
論文の pseudo code では u, v, λ を保持しておくように書かれていたが、それだけでは likelihood が計算出来ないので ζと\varphi も持ちまわっている*1


HDP-LDA の CGS 推論はこの前2回目の実装してみた*2んだけど、中核部分だけで300行くらいあって、とにかく間違いやすくて、めんどくさくて、遅くて。
一方 Online HDP の方は中核部分は100行未満、 dish や table が増えたり減ったりしないので、なんと楽なことか。推論も速い。
と、ここまではいいことだらけだけど、一番肝心の結果が定量的にも定性的にも全然ダメ。


そうすると、どこか間違えちゃったんだろうな、と当然思うところ。
幸い、Wang さんら自身が公開されている Python 実装があるので、これを読んでみたのだが、論文とは似ても似つかない実装になっていて、どういうこと状態。
そんなわけで実装がまるで似ていないのだが、一応動かしてみたところ、結果の「定量的にも定性的にも全然ダメ」というところは同じだった。


パラメータを最適なものを選べば良くなったりするんだろうかとか、もうちょっと粘るつもりだけど、なにか有益なアドバイスがもらえたり、みたいなことをちょっぴり期待してとりあえず実装を晒しておく。


ああ、そうそう。[Wang+ 11] では likelihood を求めるための具体的な式が書かれていないので、自分で導出した。
ここで間違えているという可能性もあるわけなので、晒しておこう。


トピック-単語分布 : \bar{\phi}_{kw}\propto\lambda_{kw}


文書-トピック分布 : \bar{\pi}_{jk}=\frac{1}{N_j}\sum_t \varphi_{jtk}\sum_n \zeta_{jnt}


あと、Wang さんらの実装が出力する *.topics ファイルから、単語-トピック分布を出力するスクリプトも貼り付けておく。
*.topics ファイルは論文の中で λ にあたるパラメータ(実装の中の m_lambda は、論文の中のλ-ηに対応しているのでややこしい)をべたっと出力しているので、上の式が正しければかんたんにトピック単語分布が得られる。

import sys, codecs, numpy

# topic-word distribution
with open(sys.argv[1], 'rb') as f:
    b = numpy.array([[float(x) for x in s.strip().split()] for s in f])
phi = b / b.sum(axis=1)[:,None]
K, W = phi.shape

with codecs.open('ap/vocab.txt', 'rb', 'utf-8') as f:
    voca = [s.strip() for s in f]
assert W == len(voca)

for k in xrange(K):
    print "\n-- topic: %d" % k
    for w in numpy.argsort(-phi[k])[:20]:
        print "%s: %f" % (voca[w], phi[k,w])

*1:後に出てくる Wang さんらの実装では、イテレーションの中でその時のパラメータで書く文書の likelihood を計算してそれらの変数の値は捨てていた

*2:この実装は Tokyo.ML 用のネタなので今のところはスルー