mots quotidiens.
Daichi Mochihashi (持橋大地) daichi <at> ism.ac.jp by hns, version 2.10-pl1.

先月 2004年10月 来月
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31

2004年10月04日(月) [n年日記]

#1 Adaptive hash function?

先週, hash 構造のことでF澤さんと二人で話した内容が面白かったので, まとめ。

ハッシュの設計には

  1. キーが衝突した時のデータ構造(分離連鎖法(リンクドリスト)/開番地法(1つの配列 中で次を探す))
  2. ハッシュ関数の定義

の2つの自由度があるが, このうちデータ構造はどちらか選ぶだけなので 除くとすると, 残るのはハッシュ関数の設計。
で, 伝統的にこれは普通えいや, と適当に決めてしまう。別の言い方をすると, これが最適な解, というのは知られていない(多分)。

..というようなことを, ハッシュ関数のデバッグのついでに 話した。
もちろん, このへんの話は研究的にはある程度進んでいるかもしれない, とは思う のだけれども。


2004年10月13日(水) [n年日記]

#1 debug

デバッグ中だけど, 綺麗な図ができたので。

横軸は時間(=単語)。この Cranfield コーパスの記事は160 wordsくらいあった らしい。
縦軸はモンテカルロサンプル。


2004年10月15日(金) [n年日記]

#1 -

朝から晩まで(9:30ごろから)手計算してもわからなかったので, 公開デバッグ。(おいおい)

研究上 LDA をちゃんと実装する必要が生じたので(これまでは Gibbs sampler をCで 書いていて, MAP推定になっていてわりとナイーブだった), LDAのテクニカルレポートを見直していたのだが, あれほど前に難しいと思った付録の パラメータ推定の部分が普通にわかる。 人間の進歩ってすごいなぁ, と思うわけだけど, それは置いといて。

基本的な推定は上田さんがおっしゃっているほど *1 難しくはなくて, わかれば別に難しくないのだが *2 (そのうちエッセンスを紹介します), 拡張としてβ(=p(w|z)のマトリクス)を最尤推定する (Empirical Bayesという) のではなくて, (uniform) Dirichlet prior を与えて変分ベイズ推定する のが導出できない。

この場合, βに関しても p(β|λ) という確率分布があって, βに関して積分してλを求める。このとき, <log p(w|z)> = ∫Dir(β|λ)logβ_kdβ = Ψ(λ_k) - Ψ(Σ_k λ_k) がどこかに出てくるはず。..だが, 論文にはもっと簡単な式になっている。
きのう, 今日とうげーと言うような積分式を一日中計算した結果だと(今数えたら, A4 9枚だった(裏も使っている のがある。))

K(logΓ(Kη)-KlogΓ(η)) + ΣΣ(N(v,k)φ_vk+η-1)(Ψ(λ_kv)-Ψ(Σλ_kv))
                            v k                                 v
を λ_kv に関して最適化するという非線型な最適化になるはず (上のΨ関数が出てきているのに注意)。
何でだ。うー。


*1: 「テキストモデリングの新展開」 言語処理学会年次大会2003, or 最近のSIGNL.
*2: しかし, 1z1^T と言われてこれが要素が全部zの行列を表しているのが一瞬でわかる, という程度のテクはニュートン法を導くのに必要。

2004年10月17日() [n年日記]

#1 解決

土曜日に計算したら解決しました。
β = {p(w|z)} はグローバルなパラメーターなので, 最初にβに関して 変分近似して, その後残りを普通に変分近似するといい模様。 つまり, 変分近似を変分近似でくるむ感じ。 (PDF) どこが "easily derived" なんだどこが‥(笑)。

#2 psto{画像}

PSを画像にするには, 下のようなシェルスクリプト ps2ppm:
#!/bin/sh
gs -dBATCH -dNOPAUSE -sDEVICE=ppmraw -sOutputFile=- -q "$@"
を使って, % ps2ppm hoge.ps > hoge.ppm のようにするといいようだ。
ただし, こうするとアンチエイリアスがかからないので, こんな感じ(上のPDFの1ページ目) のようになってしまう。gv のようにアンチエイリアスがかかった, 綺麗な画像を psから作る方法はないのだろうか。ご存知の方がいたら教えて下さい.

・ answer

玉野さん から, 情報をいただきました。
新しい Ghostscript でサポートされている pngalpha を出力デバイスに指定する といいとのこと。
#!/bin/sh
gs -dBATCH -dNOPAUSE -sDEVICE=pngalpha -r100 -sOutputFile=- -q "$@"
-r* が解像度(resolution)のよう。
ただし, pngalpha はかなり新しい gs でないとダメのようで, 手元の Ghostscript 7.05 では入っていませんでした。 8.14 をコンパイルして入れてみたところ, 以下のような感じに。 gv で見るのに比べるといまいちの気がしますが, これはフォントの関係かも 知れません。 gs.png

松本研でも gs は 7.05, mint は 5.50 なので, そのままでは使えない模様。 gs を不用意にアップデートして gv が使えなくなったりすると大変なので, gs のバージョンが自然に上がったら使ってみることにしようかなと思います。


2004年10月25日(月) [n年日記]

#1 -

"A note on a Variational Bayes derivation of full Bayesian Latent Dirichlet Allocation" として 公開 しました.

#2 screen tips

最近気付いた GNU screen の tips を少し.

・ sessionname

screen では
% screen -S <session_name>
としてセッション名を付けてから起動すると, 以降 -r で復帰する時などに <session_name> で参照できるが, 普通付け忘れることが多い (^^;)。というか, 起動してから, その screen での主な 作業が決まることも多い。
で, そういう時でも, 実は <prefix> : sessionname foo とタイプすれば, 名前を foo に変更することができる。 ..しかし, その際に $STY を変更してはくれないし, やや手続きが面倒。
次のように ~/.zshrc に書いておくと, シェルから % session hoge とタイプする だけで今のセッションネームを hoge に変更できる。
session () {
        screen -X sessionname "$@"
        eval "STY=$STY:r.$@"
}
ただし, $STY の変更はこれを実行したシェルだけなので, 他に同時に走っている シェルでは /tmp/uscreens/S-username/* を見たりして$STYをアップデート する必要があるかも。

・ completion

複数の screen が上がっていてレジュームする時, 特に名前を付けていなければ,
% screen -r 21576
のようにプロセス番号を指定しなければならない。(または, 名前を付けていれば どの名前があるか思い出さないといけない。)
screen -ls を見てプロセス番号をコピーするのは何だかなぁ, とずっと思っていた のだが, .zshrc に次のように書いておくと,
% screen -r <TAB>
で補完できる。
_screen () {
reply=(`screen -ls | awk '/^[ \t]*[0-9][0-9]+/{ split($1,a,"."); print a[1] }'`)
}
compctl -K _screen screen
compinit が重いのと余計な補完をしてくれるため, わざと使っていないので, compctl になっているのに注意。
compinit だと, 上の補完は誰かが書いてすでに入って いる可能性があると思う。これでタブで補完しまくり。便利便利。

・ prefix

screen のデフォルトのプレフィクスは C-a のため, Emacs が使いにくい ので, screen を使っている人は普通何かのキーに変更していると思う。
僕は telnet のエスケープからの繋がりで
escape ^]]
としていたが (C-] で screen の機能を実行する), いずれにしても ホームポジションから指を離さないといけないので, 頻繁に使うウインドウの移動 (C-] C-]) などがやりにくい。
以前 screen スレを見ていたら, "C-;" は普通は意味を持っていないよ, という情報 があった。; はホームポジションなので, 全く手を離さずにタイプできる。

ただし, 普通に C-; を設定しても, そんなコードは存在しないのでバインドできない。 が, 普通X上で使うことが今は仮定できるので, その場合は, C-; が C-] のコードを 出すように ~/.Xresources で設定してあげれば実現できる。
具体的には, .screenrc が

escape ^]]
だった場合, .Xresources に次のように書いておく。
KTerm*VT100*Translations: #override \
        Ctrl  <Key> ;: string(0x1d) \n\
        Meta  Ctrl <Key> p: string(0x1d) string("[") string(0x15) \n\
        Meta Ctrl <Key> n: string(0x1d) string("[") string(0x04)
これで, X上では C-; を screen のプレフィクスとして使える。2行目〜3行目 は, screen の copy モードに入らなくても, M-C-{p,n} でバックスクロール するための設定。C-] でない人は, "0x1d" の部分を自分が使っているプレフィクス のコードに変更すればいけると思う。


2004年10月26日(火) [n年日記]

#1 -

class unigram のスムージング係数に対する Newton 法を導いたのはいいけど (というのが下のPDFの内容), 実際にコードしてみると動かない。
関数自体は独立に動かすと動くので, 合っているはずなのだけど。 何でだ。;_;
というわけでデバッグのためにさらしてみる。 ldabayes.m newton_eta.m

#2 "Numerical matrices in C"

Cでは一応多次元配列が使えるが, double matrix[10][20] のように コンパイル時に決まっていない場合は, 普通は matrix[i][j] のようにはアクセスでき ない。
列ごとに1行を malloc して割り付ければアクセスできるが, 10000x1000の行列なら 10000回 malloc することになるわけで, メモリ上で断片化が起きるし, malloc のオーバヘッドがありそうなので良くないかと思っていた。 (& 原理的に連続なものを断片的に malloc するのは良くないという気もした。)
そうでないと, matrix = (double *)malloc(rows * cols * sizeof(double)); のように確保する ことになるが, これは matrix[i][j] ではアクセスできない。
仕方がないので, これまで
#define  LZS(i,j)       (*(lzs + K * i + j))
のようにマクロを定義して使っていたが, 家に帰って, 前にPCに保存しておいた C FAQ (fj.lang.c に定期的に流れていたもの) を読んでいたら, 以下のようなコードを書くと, matrix[i][j] でアクセスできることを知った。
/*
    dmatrix.h
    a header file of double matrix.
    $Id: dmatrix.h,v 1.1 2004/10/26 05:04:21 dmochiha Exp $
*/
#ifndef __DMATRIX_H__
#define __DMATRIX_H__

extern double **dmatrix(int rows, int cols);

#endif
/*
    dmatrix.c
    an implementation of double matrix.
    $Id: dmatrix.c,v 1.1 2004/10/26 05:04:20 dmochiha Exp $
*/
#include <stdlib.h>
#include "dmatrix.h"

double **
dmatrix (int rows, int cols)
{
        double **matrix;
        int i;

        matrix = (double **)malloc(rows * sizeof(double *));
        if (matrix == NULL)
                return NULL;
        *matrix = (double *)malloc(rows * cols * sizeof(double));  // 中身を連続して malloc	
        if (*matrix == NULL)
                return NULL;
        for (i = 1; i < rows; i++)
                matrix[i] = *matrix + i * cols;

        return matrix;
}
以下のように使う。
#include "dmatrix.h"

double **matrix;

if ((matrix = dmatrix(nrows, ncols)) == NULL) {
	fprintf(stderr, "cannot allocate matrix\n");
	exit(1);
}
st = myclock();
for (i = 0; i < nrows; i++)
	for (j = 0; j < ncols; j++)
		matrix[i][j] = i + j;
ed = myclock();
ふむふむ, と思っていたが, コードを書いて調べてみると, 下のように 列ごとに malloc する方が速いようだ。えーーーー。;;
コードは上の dmatrix を使った方が綺麗なんだけど..。;
pxn:~/tmp/test% ./mdary 100 100        % 上の dmatrix を使った場合
elapsed =   0.000128
pxn:~/tmp/test% ./mdary2 100 100       % 列ごとに malloc する場合
elapsed =   0.000038
pxn:~/tmp/test% ./mdary 10000 1000
elapsed =   0.158179
pxn:~/tmp/test% ./mdary2 10000 1000
elapsed =   0.128347

6 days displayed.
タイトル一覧
カテゴリ分類
 なかのひと
Powered by hns-2.10-pl1, HyperNikkiSystem Project