« 2005年06月 | メイン | 2005年08月 »

2005年07月27日

入門独立成分分析

タイトルの通り入門者向けにわかりやすい切り口で独立成分分析を解説してくれています。個人的には最後の章の「スパースコーディング」の観点から独立成分分析を説明しているる部分が興味深かったです。できるだけ少数の基底で、かつ基底は局所的なパターンを表現しているというのがスパースコーディングの概要ですが、人間のパターン認識に通じる「自然な」コーディングのようです。たとえば人間の目は、ぼんやりとした基底ではなく、局所的な基底(直線など)を組み合わせて物体を認識してるようです。

投稿者 taku : 22:41 | コメント (46) | トラックバック

2005年07月25日

SWIG の普及

「Ruby で XXX を使いたい(先に Ruby ありき)」ではなく、「XXX を Ruby で使えるようにする(先に XXX ありき)」という話。

先日の SWIG の話は先に XXX がある立場の文章です。
ひとつの立場にバイアスがかかった文章であったことは否めないです。

さて、「先に Ruby ありき」という意見が多いのであれば、無理して SWIG を使う必要はないかもしれません。スクリプト言語の場合、カバーする領域がかぶっているため多かれ少なかれ自分の使っている言語に閉じてしまうことが多いです。結果として SWIG を使わなくてもよい/知らなくてもよい状況が出来上がっているのでしょうか。
SWIG が普及していない理由のひとつはここにあるのかもしれません。
確認していませんが、SWIG だけで ruby のイテレーターはかけません。となると、やはり個別にバインディングを作らざるを得ません。

私は、「スクリプト言語はカバーする領域が同じだからどれも同じ」ぐらいの大雑把な考えなので Ruby/Python/Perl のバインディングを SWIG を使って提供することに何の抵抗もありません。ただ、それを「エレガント」にやるには、個々の言語の「最大公約数API」をデザインせざるを得ないです。

投稿者 taku : 20:31 | トラックバック

2005年07月12日

大阪高知特急フェリー

http://www006.upp.so-net.ne.jp/ok-ferry/

なななんと。廃業したみたい。いろいろ思い出がある船だけに寂しい。
なんやかんやで4回ぐらい乗った。

投稿者 taku : 16:42 | コメント (11) | トラックバック

2005年07月11日

もっと SWIG を!

はてなでは XS を使い始めて処理速度が改善されつつあるようです。

スクリプト言語へのバインディングは、もはやミドルウェアには必須の機能だと思います。 しかし、最近気になっているのは、少なくとも日本では XS 直書きのようなスクリプト言語固有の機能を直接使ってバインディングを作成している開発者が圧倒的に多いということです。

正直なところSWIG をもっと使ってほしいです。

私が気に入っている点は以下です。

1. SWIG はスクリプト言語固有のバインディング作成バッドノウハウを
  エレガントにラップしてくれます。たとえば、例外処理などがいい例ですが、
  SWIG のインタフェイス上で例外処理を書いておけば、
  各言語の例外処理のシンタックスに適切に変換してくれます。

2. バンディングレベルで OOP の機能が無く、プリミティブな関数呼び出ししかできない
  スクリプト言語(perl,python,java) などは適当な shadow class を
  作ってくれて、各言語の OO スタイルな呼び出しに変換してくれます。

正直なところ個々のスクリプト言語固有の機能を使ってほしくありません。
ユーザが混乱するだけです。たとえば、単にクールだという理由だけで
ruby binding のとある API を内部イテレータで表現するといった例は
私自身あまり好きではありません。 C/C++ の API をそのままの形で
wrap し、各言語間で全く同じ API を使えたほうがいいです。

東工大のNさんと以前話したのですが、日本語のドキュメントがあまりないのが
SWIG がはやっていない一つの要因のようです。

なにはともあれ、各言語個別のバインディングノウハウを覚えるより
SWIG のインタフェースファイルの書き方を覚えた方が生産性が高いように思うのですが、いかがでしょう?

さて、SWIG の例として kakasi のバインディングを作ってみました。

kakasi.i

%module kakasi
%{
#include "libkakasi.h"
%}
%newobject kakasi_do;
%ignore kakasi_free;
%ignore kakasi_getopt_argv;
%ignore kakasi_close_kanwadict;
%{
int kakasi_init(char* arg)
{
unsigned int size = 1;
char *p = 0;
char str [1024];
char* ptr [64];
ptr[0] = (char*)"kakasi";
strncpy (str, arg, 1024);
for (p = str; *p ; ) {
while (isspace (*p)) *p++ = '\0';
if (*p == '\0') break;
ptr[size++] = p;
if (size == 64) break;
while (*p && ! isspace (*p)) p++;
}
return kakasi_getopt_argv (size, ptr);
}
%}
char* kakasi_do(char *);
int kakasi_init(char* arg);


% swig -perl kakasi.i

Makefile.PL

use ExtUtils::MakeMaker;
WriteMakefile(
'NAME' => 'kakasi',
'INC' => '-I/usr/include',
'LIBS' => '-lkakasi',
'OBJECT' => 'kakasi_wrap.o'
);

test.pl

use kakasi;
my $sentence = "太郎はこの本を二郎を見た女性に渡した。";
kakasi::kakasi_init("-w");
print kakasi::kakasi_do($sentence);

kakasi_do の戻り値の領域は,呼び出し側で free する必要があるので
%newobject を指定しています。また kakasi_getopt_argv は使わず
kakasi_init で一つの文字列として渡すように変更してみました。

上記は perl の例ですが、swig -ruby, siwg -python, swig -java など
すれば個々の言語のモジュールが作れます。

投稿者 taku : 15:37 | コメント (14) | トラックバック

2005年07月10日

形態素長

形態素の長さについて、研究レベルでもあまり考察されたことはないのですが、
未知語がからむといろいろやっかいなことが起きます。
とくにカタカナの未知後の扱いはなかなかくせ者です。

入力: ホテルホテルホテルホテルホテルホテルホテルホテルホテル......

の時に、

ホテルホテルホテルホテルホテルホテルホテルホテルホテル.....

が一つの形態素として取り出されてしまいます。
カタカナはデフォルトで未知後処理が動くのですが、カタカナの
連続は1語として扱われてしまい、複数の単語の組み合わせよりひとつに
まとめてしまったほうがコストが小さくなってしまうために、こういう問題が発生してしまいます。いわゆる length-bias (最長一致の原則が悪影響する問題)です。

これを根本的に解決するには、長さに対するペナルティー項を作るしか
ありません。簡単には、永田さんがやったように、形態素の長さを
ポアソン分布を使って表現して、長いものはコストが大きく
見積もられるようにすればいいと思います。

CRF だと、長さ素性を入れるという手もあります。

投稿者 taku : 03:58 | コメント (6) | トラックバック

2005年07月05日

new Classs or Class->new

http://d.hatena.ne.jp/naoya/20050705

完全に好みの問題だけど、C++ に慣れてしまっているので、その首尾一貫性から perl でも new Class を使います。
そもそも、C++は primitive を new できるので、クラスメソッド new があるという考え方は常に真ではありません。

int *i = new int(0);

クラスメソッドそのものが C++ ではあまり使われないので、実体のない物の
メンバ関数を呼んでいるようで違和感を感じます。C++ では、static メンバ関数
を作れば、クラスメソッドが作れますが用途は限られています。(ファクトリとか?)
コンストラクタを直接呼ぶこともできますが、アロケートの方法が変わってしまいます。複雑。

class Foo{};
int main () {
Foo a = Foo::Foo();
Foo *b = new Foo();
}

投稿者 taku : 17:52 | トラックバック

CRF++

ある環境でコンパイルできない問題を修正しました。
ちょーマニアックなツールにもかかわらず、ユーザが何人かいらっしゃるようです。
ありがとうございます。

http://chasen.org/~taku/software/CRF++/

投稿者 taku : 03:12 | トラックバック

2005年07月04日

DLL + C++

C++ の class を Win32 DLL で公開するのは無理だと思っていたのですが、
pImpl と同じやり方で公開できるみたいですね。
pure virtual クラスをヘッダファイルに書いて、実体への
ポインタをファクトリ関数で返す。

MeCab 0.90 の mecab.h はさらに pImpl 化が進んで、
インスタンスはファクトリ関数で作るよう変更しています。

http://www2s.biglobe.ne.jp/~ragnarok/program/win32/class_of_cpp_in_dll.htm

投稿者 taku : 14:52 | コメント (13) | トラックバック

英語係り受け

ACL 2005 で英語係り受けの話がチラホラ出ていました。
どれも Yamada & Matsumoto 2003 を引用しています。
この分野を開拓したのはこの二人に間違いないです。

以下の論文は、最近はやりの帯域的な Large Margine
Disicrimnation に基づく英語係り受けです。
http://acl.ldc.upenn.edu/P/P05/P05-1012.pdf

英語の係り受けは、日本語のそれにくらべると素性設計がシンプルなので
実装がとても楽だと思います。以前に作ったものをいじってパフォーマンスを
向上させてみたくなりました。

投稿者 taku : 14:22 | トラックバック

2005年07月01日

stream wrapper

ファイル名として "-" を指定したときに標準入出力として
扱うプログラムがあります。 (wget など)
それを C++ の fstream で実現したくて、以下のwrapper を書いてみますた。

 class istream_wrapper {
  private:
    std::istream* is;
  public:
    std::istream &operator*() const  { return *is; }
    std::istream *operator->() const { return is;  }
    istream_wrapper(const char* filename): is(0)
    {
      if (std::strcmp(filename, "-") == 0)
        is = &std::cin;
      else
        is = new std::ifstream(filename);
    }
    ~istream_wrapper()
    {
      if (is != &std::cin) delete is;
    }
  };

* と -> を overload しているので、あたかも stream のポインタのように動作します。また、デストラクタで delete するので、スコープを抜けると自動的に close します。

これをもっと極めれば、文字列ストリーム、socket, pipe といった stream を
透過的に扱えるようなファクトリが作れそうです。

投稿者 taku : 00:25 | コメント (10) | トラックバック