Julia言語のScikitLearn.jlでテキスト分類

Julia言語の最新版v0.5.0が公開されて、メジャーバージョンv1.0に向けて着実に進化しています。さっそくこちらのブログに変更点が日本語でまとめられています:
Julia言語の0.5の変更点 - りんごがでている

ダウンロードページのディスクイメージでインストールした場合、ターミナルから起動するときは次のようにします:

$ /Applications/Julia-0.5.app/Contents/Resources/julia/bin/julia
julia> 

Juliaは機械学習など数理モデルの計算に向いている高速な処理系ですが、後発の言語ということもあって、豊富な資産がすでにあるRやPythonの機能を直接呼び出すパッケージも充実しています。
JuliaからRを使う - りんごがでている
Python使いをJuliaに引き込むサンプル集 | mwSoft

Pythonのscikit-learnは統一された使いやすいインターフェースで人気がありますが、Juliaからも同じように使えるScikitLearn.jlが公開されているので、これをインストールしてみます:

julia> Pkg.add("ScikitLearn")

ところが、例えばテキスト分類のような自然言語処理のタスクで必要な疎な行列を扱うことが現時点ではまだできないようです:
ScikitLearn.jl/CONTRIBUTING.md at master · cstjean/ScikitLearn.jl · GitHub

幸い、こちらに疎行列をPythonオブジェクトに変換する方法が書かれていたので実際に試してみることにします:
Convert to sparse · Issue #204 · JuliaPy/PyCall.jl · GitHub

テキスト分類の古典的なデータセットである20NewsgroupsMatlab用に加工したデータセットが公開されているのでこれを利用します:

const urlbase  = "http://qwone.com/~jason/20Newsgroups/"
const filename = "20news-bydate-matlab.tgz"
const datadir  = "20news-bydate/matlab/"

function download_20news()
    isfile(filename) || download(joinpath(urlbase, filename), filename)
    isdir(datadir)   || run(`tar -zxf $filename`)
end

function load_20news_Xy(target=:train)
    file = joinpath(datadir, string(target, ".data"))
    I, J, V = Int[], Int[], Int[]
    for line in readlines(file)
        i, j, v = map(m->parse(Int, m), split(strip(line)))
        push!(I, i)
        push!(J, j)
        push!(V, v)
    end
    X = sparse(I, J, V)
    file = joinpath(datadir, string(target, ".label"))
    y = map(m->parse(Int, m), split(readstring(file)))
    return X, y
end

download_20news()
X_train, y_train = load_20news_Xy()

単語の重みには出現頻度をそのまま割り当てて、ロジスティック回帰モデルで分類します:

using ScikitLearn
@sk_import linear_model: LogisticRegression

これでX_trainをそのまま利用するとPythonの密な行列に変換されて極端に処理が遅くなってしまいますので、あらかじめ疎行列に変換しておいてから学習させます:

using PyCall
PyObject(S::SparseMatrixCSC) =
    pyimport("scipy.sparse")["csc_matrix"]((S.nzval, S.rowval .- 1, S.colptr .- 1),
                                           shape=size(S))
Xpy_train = PyObject(X_train)
clf = fit!(LogisticRegression(), Xpy_train, y_train)
@show score(clf, Xpy_train, y_train)

テストデータで分類精度を求めます:

X_test, y_test = load_20news_Xy(:test)
Xpy_test = PyObject(X_test[:, 1:size(X_train, 2)])
@show score(clf, Xpy_test, y_test)

以上の内容を20news.jlファイルにまとめて実行すると:

julia> include("20news.jl")
score(clf,Xpy_train,y_train) = 0.9988463927588961
score(clf,Xpy_test,y_test) = 0.7520319786808795
0.7520319786808795

julia> 

Julia言語で実装された深層学習フレームワークMerlin

Recurrent Neural Networksなどの深層学習に基づく手法が近年の自然言語研究を席巻していて、画像認識のような圧倒的な性能差ではないですが、伝統的な構文解析のタスクでもベンチマーク精度を叩き出していたりします:
Recurrent Neural Network Grammars

公開されている深層学習のフレームワークはまさに百花繚乱の状態で、多数のマシンに分散して計算が可能なGoogleTensorFlowや、TensorFlowやTheanoをベースにして直観的にプログラミングができるKeras、日本のPreferred NetworksのChainer、高性能なアンサンブル機械学習ライブラリXGBoostでも有名なdmlc (Distributed (Deep) Machine Learning Community)MXNetなど枚挙にいとまがありません。その中でもMerlinJulia言語で実装された異色のフレームワークです。

Julia言語のウェブページには、Pythonのような書きやすさでありながらCやFortranに迫る実行速度を示す衝撃的なベンチマーク結果が載っています。しかし例えばPythonの場合でも、NumpyやCythonなどを使ってさらに高速化していくことはできます。Juliaの良い点は、あまり速度面を気にしなくてもそこそこ高速なプログラムが書けて、さらに変数に型情報を与えたり配列のメモリ割当を減らすなど言語仕様の枠内のことをすることで比較的簡単に性能改善できる余地があることだと思います。このときマニュアルにあるような点に気をつけることが必要で、FAQにあるように、配列の演算処理で余計なメモリ割当が起きてしまうことがあるので、原始的なループ処理で記述した方が高速になることがあります。

Juliaは2012年に公開されてからまだ日が浅く、言語仕様もまだまだ未成熟で、RやPythonMATLABなどと比べてライブラリが十分ではないなどの欠点はありますが、魅力的な特徴が色々ある言語なので、広まっていってほしいと切に願います。

新語が追加されたmecab-ipadic-neologd辞書

日本語形態素解析エンジンMeCabで標準的に使われているIPA辞書に新語を追加したmecab-ipadic-neologdが公開されました:
[O] MeCab 用の新語辞書 mecab-ipadic-neologd を公開しました

これまでもWikipediaはてなキーワードからとりだした単語をMeCabの辞書に登録する取り組みはいろいろとありました:
livedoor Techブログ : wikipediaのデータや顔文字辞書からmecabのユーザ辞書を作成するフレームワーク
MeCabの辞書にはてなキーワードを追加しよう - 不可視点

最近のJUMANの辞書にもWikipediaやWebからとられた単語が登録されています:
JUMAN - KUROHASHI-KAWAHARA LAB

mecab-ipadic-neologdは新語データを定期的に更新して改善を続ける予定ということで、今後が楽しみです。

MacPortsにこのmecab-ipadic-neologdを追加しました。MeCabのシステム辞書として使う場合は次のコマンドを実行します:

$ sudo port selfupdate
$ sudo port install mecab-utf8 +neologd

解析対象の文字コードはUTF−8です。MeCabはもともとEUC文字コードベースだったため、ポート名には-utf8がついています。辞書データは、/opt/local/lib/mecab/dic/neologd-utf8にインストールされます。

ただし、すでにIPA辞書版などのmecab-utf8がインストールされている場合は上のコマンドがエラーを起こしてしまうので、いったんmecab-utf8を取り除いてから、オプションを指定して入れ直します:

$ sudo port -f uninstall mecab-utf8
$ sudo port install mecab-utf8 +neologd

なお、上のコマンドは単にシステム辞書のシンボリックリンク/opt/local/lib/mecab/dic/sysを張り替えるだけなので、これまでにインストールした辞書データやエンジン自体は消えずにそのまま残ります。

システム辞書を変えずに辞書データだけをインストールする場合は:

$ sudo port install mecab-ipadic-neologd

試しにサンプルの文を解析してみます:

$ echo '「人工知能」という名前は1956年にダートマス会議でジョン・マッカーシーにより命名された。' | mecab
「	記号,括弧開,*,*,*,*,「,「,「
人工知能	名詞,固有名詞,一般,*,*,*,人工知能,ジンコウチノウ,ジンコウチノウ
」	記号,括弧閉,*,*,*,*,」,」,」
という	助詞,格助詞,連語,*,*,*,という,トイウ,トユウ
名前	名詞,一般,*,*,*,*,名前,ナマエ,ナマエ
は	助詞,係助詞,*,*,*,*,は,ハ,ワ
1956年	名詞,固有名詞,一般,*,*,*,1956年,センキュウヒャクゴジュウロクネン,センキュウヒャクゴジュウロクネン
に	助詞,格助詞,一般,*,*,*,に,ニ,ニ
ダートマス会議	名詞,固有名詞,一般,*,*,*,ダートマス会議,ダートマスカイギ,ダートマスカイギ
で	助詞,格助詞,一般,*,*,*,で,デ,デ
ジョン・マッカーシー	名詞,固有名詞,人名,*,*,*,ジョン・マッカーシー,ジョンマッカーシー,ジョンマッカーシー
により	助詞,格助詞,連語,*,*,*,により,ニヨリ,ニヨリ
命名	名詞,サ変接続,*,*,*,*,命名,メイメイ,メイメイ
さ	動詞,自立,*,*,サ変・スル,未然レル接続,する,サ,サ
れ	動詞,接尾,*,*,一段,連用形,れる,レ,レ
た	助動詞,*,*,*,特殊・タ,基本形,た,タ,タ
。	記号,句点,*,*,*,*,。,。,。
EOS

人工知能」「1956年」「ダートマス会議」「ジョン・マッカーシー」が固有名詞としてかたまりでとれています。実際には解析の前に正規化処理をしておく必要があります。

ちなみにMacPortsではソースのスクリプトパッチをあてています。一つは、辞書をビルドするときに使われるxargsに制限によるもので、MacPortsでビルド作業をするディレクトリの絶対パス名が、xargsが扱える引数のバイト数を超えて長くなってしまうので、相対パス名を使うようにしています。もう一つは、/tmpに一時ファイルを作らないようにして、MacPortsが管理していない場所にファイルが作られるのを防ぎます。ビルドのときはmacportsユーザで作業するため、/tmpに残ったファイルは一般ユーザが上書きできなくなってしまいます。

ところで現在MeCabソースコードGoogle Codeで管理されていますが、来年閉鎖されることが発表されました:
Bidding farewell to Google Code | Google Open Source Blog

MeCabのページにも、Export to GitHubのボタンがありますね。いろいろなコードやページのリンク先を書き換える必要がありそうです。

MacPortsでCaffe

2012年の国際的な画像認識技術評価タスクで、多段の畳み込みニューラルネットワークを使った手法が圧倒的な性能を達成してから、画像認識研究は深層学習中心に一変しました:
[1409.0575] ImageNet Large Scale Visual Recognition Challenge

自然言語処理研究の分野でも、畳み込みニューラルネットワークを使う手法は、タスクごとの知識を利用しないで最高性能に迫る解析を行うSENNAが現れ、word2vecの分散表現やアルファベットや読みを入力としてテキスト分類タスクでベンチマークのbag-of-wordsモデルを超える性能を示したりと大変注目を集めています:
[1103.0398] Natural Language Processing (almost) from Scratch
[1408.5882] Convolutional Neural Networks for Sentence Classification
[1502.01710] Text Understanding from Scratch

深層学習を実装するフレームワークとして、Theano/Pylearn2TorchCaffeなど様々公開されていますが、Caffeは画像認識研究の最新成果が反映されていて、高速な上に使いやすく人気があります。

Caffeのインストール手順を見ると、Mavericks(10.9)以降のMacの場合、NVIDIAGPUを利用するために必要なCUDAのバージョン6までがgccベースのlibstdc++にリンクされているため、homebrewを使った少々面倒な手順が記述されていますが、CPUだけ、もしくは次期CUDAのバージョン7を利用する場合はもっと単純です。

Caffeは効率的なデータ処理を行うprotobufなどいくつかの依存パッケージが必要で、Pythonのインタフェースも用意されていますが、MacPortsCaffeポートを使うと、CPUでの処理限定になりますが、簡単にMacにインストールできます。Mac標準のベクトル数値演算ライブラリは、十分にチューニングされているためか結構高速ですが、複数のCPUコアでは同時に動作しません。Caffeポートはデフォルトの指定でOpenBLAS対応になって、CPUコアが最大限利用されるようになります。ただし、残念ながら全体の処理速度は思ったほどあがらないですが。。

Caffeをインストールして、手書き数字認識テストセットMNISTを標準的な畳み込みニューラルネットワークのLeNetで学習するサンプルを試してみます:

$ sudo port selfupdate
$ sudo port install caffe
$ cp -r /opt/local/libexec/caffe .
$ cd caffe
$ ./data/mnist/get_mnist.sh
Downloading...
...
Unzipping...
Done.
$ ./examples/mnist/create_mnist.sh
Creating lmdb...
Done.
$ vi examples/mnist/lenet_solver.prototxt
(最終行のGPUをCPUに変更します)
$ ./examples/mnist/train_lenet.sh
I0215 22:35:43.757207 2073379584 caffe.cpp:103] Use CPU.
I0215 22:35:43.758378 2073379584 caffe.cpp:107] Starting Optimization
I0215 22:35:43.759407 2073379584 solver.cpp:32] Initializing solver from parameters:
...
I0215 22:43:08.604959 2073379584 solver.cpp:246] Iteration 10000, loss = 0.00372661
I0215 22:43:08.604992 2073379584 solver.cpp:264] Iteration 10000, Testing net (#0)
I0215 22:43:11.086513 2073379584 solver.cpp:315]     Test net output #0: accuracy = 0.9902
I0215 22:43:11.087237 2073379584 solver.cpp:315]     Test net output #1: loss = 0.0292476 (* 1 = 0.0292476 loss)
I0215 22:43:11.087249 2073379584 solver.cpp:251] Optimization Done.
I0215 22:43:11.087255 2073379584 caffe.cpp:121] Optimization Done.
$ 

2.7 GHz Intel Core i5のマシンで動かして、8分弱の学習時間でテスト精度が99%を超えました! CUDAを有効にしてGPUを使ったり、NVIDIAが公開している深層学習用のcuDNNライブラリを利用するとさらに高速になります。ちなみにTheanoで同様のことを行うとCPU処理で6時間程度かかるようです。。

ちなみに、CaffeのPythonインタフェースは/opt/local/bin/python2.7から利用できます。NumPyやmatplotlib、scikit-learn、pandas、ipythonなど、機械学習や統計処理などに適したAnacondaのように各種Pythonライブラリも同時にインストールされるので、デフォルトのPythonとして普段から利用するのも良いと思います:

$ sudo port select --set python python27
$ sudo port select --set ipython ipython27

[2015-02-22追記]
CaffeポートにGPUとcuDNNを利用するオプションを追加しました。CUDA7(+cuDNN)が/usr/local/cudaにインストールされていることが前提です。ポートを+gpuや+cudnnオプションつきでインストールしようとすると、ソースからコンパイルが始まります:

$ port variants caffe
caffe has the variants:
[+]cpu: Use CPU only
     * conflicts with gpu
   cudnn: Use cuDNN
   gpu: Use GPU and CUDA in /usr/local/cuda
     * conflicts with cpu
[+]openblas: Use OpenBLAS
[+]python27: Install Python 2.7 interface
   universal: Build for multiple architectures
$ sudo port install caffe +gpu
または
$ sudo port install caffe +cudnn
...

また、まもなくCaffeのバージョン1.0が公開されるようです:
https://github.com/BVLC/caffe/pull/1849

Emacs 24.4リリース

Emacsの最新版24.4がリリースされました。素のままのEmacsでは、日本語入力のときにキーに割り当てられた機能を使おうとすると、日本語がわたってしまってうまくいかないことなどがあって不便なので、インラインパッチが欠かせませんでした:
http://macemacsjp.sourceforge.jp/index.php?InlinePatchForCarbonEmacs

上のパッチは現時点で24.3版用ですが、24.4版に対応したパッチが公開されています:
http://blog.goo.ne.jp/toshi-mtk/e/172f1a01d235c05ff77a35ee370abcc9

MacPortsのApplication版Emacsを最新版に更新してインラインパッチを適用しました。MacPortsがインストールされていれば次のようにインストールできます:

$ sudo port selfupdate
$ sudo port install emacs-app

ちなみに、デフォルトで+inlineの指定が有効になってインラインパッチが適用されていて、これまで使えていた +patchesなどは無効です。最新版のOS X Yosemite (10.10)ではMacPortsのBuildbotが動いていませんが、Mavericks (10.9)、Mountain Lion (10.8)、Lion (10.7) ではバイナリができていて、インストールは短時間で終わります。Yosemite用のBuildbotの準備も進んでいるようなので楽しみです。
Index of /emacs-app

EmacsテキストエディタとしてVimとよく比較されますが、相互に類似のパッケージが実装されています。EmacsVimの操作性を実現したEvilや、ファイル名やモード名などを表示するモードラインを美しく描画するPowerlineなど、Vimに触発されたパッケージが様々あります:
Evil: EmacsをVimのごとく使う - 導入編 - 貳佰伍拾陸夜日記
emacsにpowerlineを導入 - $shibayu36->blog;

Powerlineですが、Emacs 24.4で表示されなくなる不具合が報告されています:
powerline is not saved properly under Emacs 24.4 · Issue #58 · milkypostman/powerline · GitHub

とりあえずの解決方法としては、設定ファイル ~/emacs.d/init.el に次の行を加えれば良いようです:

(powerline-reset)

機械学習に適した大規模分散計算環境Apache Spark

大規模分散計算環境のApache Sparkは、HadoopのMacReduceに比べてメモリ内で効率的に処理を行うことが特長で、機械学習ストリーム処理グラフ解析SQLデータ分析などの機能ライブラリがあります。Spark自体はScala言語で実装されていますが、Scalaの他にPython用のAPIや対話的なシェルも用意されていて、どちらの言語でもプログラミングや動作確認が可能です。

動作確認は簡単にできて、Java6以上がインストールされていれば、Downloadsページから適当なビルド済みパッケージをダウンロードして解凍すると、ScalaまたはPythonの対話的シェルが起動できます:

$ curl -O http://d3kbcqa49mib13.cloudfront.net/spark-1.0.2-bin-hadoop1.tgz
$ tar zxf spark-1.0.2-bin-hadoop1.tgz
$ cd spark-1.0.2-bin-hadoop1
$ bin/pyspark
..(中略)..
Welcome to
      ____              __
     / __/__  ___ _____/ /__
    _\ \/ _ \/ _ `/ __/  '_/
   /__ / .__/\_,_/_/ /_/\_\   version 1.0.2
      /_/

Using Python version 2.7.8 (default, Jul 13 2014 17:11:32)
SparkContext available as sc.
>>> 

ここではPythonの対話的シェルを起動しています。

Sparkは、処理対象のデータをResilient Distributed Dataset (RDD)とよばれる並列処理用のデータ形式に変換します。RDDの内容そのものではなく適用する処理手順を記録しておき、どこかの計算機ノードで処理が失敗しても、直前のRDDの内容を復元して別のノードで処理を継続します。対話的シェルで動作を確認すると、値が必要になるまで実際の処理を行っていないことが分かります。

たとえば、README.mdファイルを読み込んで各行の文字数を合計してみます:

>>> lines = sc.textFile("README.md")
14/08/11 18:54:09 INFO MemoryStore: ensureFreeSpace(32856) called with curMem=0, maxMem=309225062
14/08/11 18:54:09 INFO MemoryStore: Block broadcast_0 stored as values to memory (estimated size 32.1 KB, free 294.9 MB)
>>> lengths = lines.map(lambda s: len(s))
>>> lengths.reduce(lambda a, b: a + b)
14/08/11 18:55:03 WARN NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
14/08/11 18:55:03 WARN LoadSnappy: Snappy native library not loaded
14/08/11 18:55:03 INFO FileInputFormat: Total input paths to process : 1
14/08/11 18:55:03 INFO SparkContext: Starting job: reduce at <stdin>:1
14/08/11 18:55:03 INFO DAGScheduler: Got job 0 (reduce at <stdin>:1) with 2 output partitions (allowLocal=false)
14/08/11 18:55:03 INFO DAGScheduler: Final stage: Stage 0(reduce at <stdin>:1)
14/08/11 18:55:03 INFO DAGScheduler: Parents of final stage: List()
14/08/11 18:55:03 INFO DAGScheduler: Missing parents: List()
14/08/11 18:55:03 INFO DAGScheduler: Submitting Stage 0 (PythonRDD[2] at RDD at PythonRDD.scala:37), which has no missing parents
14/08/11 18:55:03 INFO DAGScheduler: Submitting 2 missing tasks from Stage 0 (PythonRDD[2] at RDD at PythonRDD.scala:37)
14/08/11 18:55:03 INFO TaskSchedulerImpl: Adding task set 0.0 with 2 tasks
14/08/11 18:55:03 INFO TaskSetManager: Starting task 0.0:0 as TID 0 on executor localhost: localhost (PROCESS_LOCAL)
14/08/11 18:55:03 INFO TaskSetManager: Serialized task 0.0:0 as 2999 bytes in 3 ms
14/08/11 18:55:03 INFO TaskSetManager: Starting task 0.0:1 as TID 1 on executor localhost: localhost (PROCESS_LOCAL)
14/08/11 18:55:03 INFO TaskSetManager: Serialized task 0.0:1 as 2999 bytes in 1 ms
14/08/11 18:55:03 INFO Executor: Running task ID 0
14/08/11 18:55:03 INFO Executor: Running task ID 1
14/08/11 18:55:03 INFO BlockManager: Found block broadcast_0 locally
14/08/11 18:55:03 INFO BlockManager: Found block broadcast_0 locally
14/08/11 18:55:04 INFO HadoopRDD: Input split: file:/.../spark-1.0.2-bin-hadoop1/README.md:2110+2111
14/08/11 18:55:04 INFO HadoopRDD: Input split: file:/.../spark-1.0.2-bin-hadoop1/README.md:0+2110
14/08/11 18:55:04 INFO PythonRDD: Times: total = 1345, boot = 1314, init = 30, finish = 1
14/08/11 18:55:04 INFO PythonRDD: Times: total = 1352, boot = 1310, init = 38, finish = 4
14/08/11 18:55:04 INFO Executor: Serialized size of result for 1 is 638
14/08/11 18:55:04 INFO Executor: Sending result for 1 directly to driver
14/08/11 18:55:04 INFO Executor: Finished task ID 1
14/08/11 18:55:04 INFO Executor: Serialized size of result for 0 is 638
14/08/11 18:55:04 INFO Executor: Sending result for 0 directly to driver
14/08/11 18:55:04 INFO Executor: Finished task ID 0
14/08/11 18:55:04 INFO TaskSetManager: Finished TID 1 in 1427 ms on localhost (progress: 1/2)
14/08/11 18:55:04 INFO DAGScheduler: Completed ResultTask(0, 1)
14/08/11 18:55:04 INFO TaskSetManager: Finished TID 0 in 1456 ms on localhost (progress: 2/2)
14/08/11 18:55:04 INFO TaskSchedulerImpl: Removed TaskSet 0.0, whose tasks have all completed, from pool 
14/08/11 18:55:04 INFO DAGScheduler: Completed ResultTask(0, 0)
14/08/11 18:55:04 INFO DAGScheduler: Stage 0 (reduce at <stdin>:1) finished in 1.475 s
14/08/11 18:55:04 INFO SparkContext: Job finished: reduce at <stdin>:1, took 1.656086 s
4094

Sparkに同梱されている機械学習ライブラリはMLlibとよばれていますが、現時点で、線形SVM、ロジスティック回帰、決定木、ナイーブベイズ協調フィルタリング、k-meansクラスタリングなどの機能が提供されています。SparkのGithubにはサンプルのスクリプトとデータが登録されているので、動作確認をする場合はこちらをチェックアウトするとよいでしょう。

なお、Hadoopとの連携など大規模並列処理向け機械学習ライブラリのMahoutは、今後MapReduceアルゴリズムを新規に実装することはやめて、Sparkに対応することになっています。

JavaScriptで実装された日中形態素解析エンジンRakuten MA

日本語と中国語(簡体字)に対応した形態素解析エンジンRakuten MAが公開されています。JavaScriptで実装されていてnode.jsでアプリケーションのように使うことも、ブラウザ上で実行することもできます。Apacheライセンスで公開されているので商用利用も可能です。

TinySegmenterJavaScriptの少ないコード量で日本語分かち書きを実現した先駆的なソフトだと思いますが、Rakuten MAは現代日本語書き言葉均衡コーパス(BCCWJ)Chinese TreeBank (CTB)などから学習したモデルを同梱していて、品詞情報も出力できます。オンライン学習モデルを採用していて、新たにコーパスを用意してモデルを作ったり、サンプルコーパスを追加して再学習した結果を即座に反映することも簡単にできます。

実行するにはGithubからコード一式をダウンロードしてnode.jsなどで実行します:

$ git clone https://github.com/rakuten-nlp/rakutenma.git
$ cd rakutenma
$ sudo port install nodejs
$ node demo.js
[ [ '彼', '' ],
  [ 'は', '' ],
  [ '新', '' ],
  [ 'し', '' ],
  [ 'い', '' ],
  [ '仕', '' ],
  [ '事', '' ],
  [ 'で', '' ],
  [ 'き', '' ],
  [ 'っ', '' ],
  [ 'と', '' ],
  [ '成', '' ],
  [ '功', '' ],
  [ 'す', '' ],
  [ 'る', '' ],
  [ 'だ', '' ],
  [ 'ろ', '' ],
  [ 'う', '' ],
  [ '。', '' ] ]
[ [ '彼', 'N-nc' ],
  [ 'は', 'P-k' ],
  [ '新し', 'V-c' ],
  [ 'い', 'P-k' ],
  [ '仕事', 'N-nc' ],
  [ 'で', 'P-k' ],
  [ 'きっ', 'N-nc' ],
  [ 'と', 'P-rj' ],
  [ '成功', 'N-nc' ],
  [ 'す', 'P-k' ],
  [ 'るだ', 'V-c' ],
  [ 'ろう', 'X' ],
  [ '。', 'M-p' ] ]
[ [ 'うらにわ', 'N-nc' ],
  [ 'に', 'P-k' ],
  [ 'は', 'P-rj' ],
  [ 'にわにわとり', 'N-nc' ],
  [ 'が', 'P-k' ],
  [ 'いる', 'V-dp' ] ]
{ ans: 
   [ [ 'うらにわ', 'N-nc' ],
     [ 'に', 'P-k' ],
     [ 'は', 'P-rj' ],
     [ 'にわ', 'N-n' ],
     [ 'にわとり', 'N-nc' ],
     [ 'が', 'P-k' ],
     [ 'いる', 'V-c' ] ],
  sys: 
   [ [ 'うらにわ', 'N-nc' ],
     [ 'に', 'P-k' ],
     [ 'は', 'P-rj' ],
     [ 'にわにわとり', 'N-nc' ],
     [ 'が', 'P-k' ],
     [ 'いる', 'V-dp' ] ],
  updated: true }
[ [ 'うらにわ', 'N-nc' ],
  [ 'に', 'P-k' ],
  [ 'は', 'P-rj' ],
  [ 'にわ', 'N-n' ],
  [ 'にわとり', 'N-nc' ],
  [ 'が', 'P-k' ],
  [ 'いる', 'V-c' ] ]

ここではMacPortsでnode.jsをインストールしています。demo.jsでは「彼は新しい仕事できっと成功するだろう。」と「うらにわにはにわにわとりがいる」の2つの例文を解析しています。まず、空のモデルを使って1番目の例文を解析して無意味が結果が出ていますが、正解コーパスで学習して再度解析して正しい結果が出ていることを確認しています。次に、同梱してあるモデルを使って2番目の例文を解析していますが、「にわにわとり」の部分に誤りがあり、正しい解析例を再学習して最終的に解析が成功している様子が分かります。