💭

C++ 日本語係り受け解析 J.DepP(ジョニーデップ)のメモ

2023/12/25に公開

背景

LLM 向けデータセット構築で, web 文章が自然な日本語かどうか, 精度はいくらか犠牲になってもよいので高速に判定したい(TB 単位のテキストを処理なので, GiNZA とかだとおそすぎる)

https://www.tkl.iis.u-tokyo.ac.jp/~ynaga/jdepp/

高速を謳う J.DepP(ジョニーデップ)を試します!

J.DepP を動かすには POS tagger(mecab とか juman とか)が必要になります.

ビルド

Ubuntu 20.04 を想定します.

形態素解析モジュール

J.DepP 用辞書ビルドのためにも, MeCab or Juman が必要です.

J.DepP の configure が mecab-config で dict の場所を取得するのですが, Ubuntu package ではこれはいろいろ壊れていて変な場所を dictdir として返してくるので使い物になりません. configure.ac 書き直ししてもいいのですが, めんどいのでとりあえず juman 使います.

$ sudo apt install juman # default? 辞書もインストールされる

京都大学テキストコーパス?

最高精度を求めるなら京都大学テキストコーパス利用がよいとあります.

https://nlp.ist.i.kyoto-u.ac.jp/index.php?京都大学テキストコーパス

ただ, これを利用するには毎日新聞CD-ROMが必要です.

https://www.nichigai.co.jp/sales/corpus.html
(2023/12/24 時点でアクセスしたらサイト落ちてる...)

今回はそんなに精度はいらないので, default で進めます.

configure

デフォだと /usr/local/ に install し, model file も /usr/local/.. がデフォになる(jdepp 実行時に -m で指定できるが), --prefix で適当にユーザフォルダを指定しておくとよいでしょう.

$ ./configure --prefix=`pwd`/dist --with-postagger=juman
$ make # jdepp のビルド
$ make model # モデルのビルド
$ make install # optional

使う

jdepp への入力は, POS Tagger(品詞付与), つまり mecab, juman などにより処理したテキストになります.

適当に入力文を用意します.

# test.sent
吾輩は猫である。名前はまだない。

まず juman で変換します(ここは mecab でもいいかも)

$ juman < test.sent
吾輩 わがはい 吾輩 名詞 6 普通名詞 1 * 0 * 0 "代表表記:我が輩/わがはい カテゴリ:人"
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
猫 ねこ 猫 名詞 6 普通名詞 1 * 0 * 0 "代表表記:猫/ねこ 漢字読み:訓 カテゴリ:動物"
である である だ 判定詞 4 * 0 判定詞 25 デアル列基本形 15 NIL
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
名前 なまえ 名前 名詞 6 普通名詞 1 * 0 * 0 "代表表記:名前/なまえ カテゴリ:抽象物"
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
まだ まだ まだ 副詞 8 * 0 * 0 * 0 "代表表記:まだ/まだ"
ない ない ない 形容詞 3 * 0 イ形容詞アウオ段 18 基本形 2 "代表表記:無い/ない 反義:動詞:有る/ある"
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
EOS EOS EOS 未定義語 15 その他 1 * 0 * 0 NIL
EOS

処理結果を jdepp に渡します.

$ ./src/jdepp -m model/knbc < pos.sent
(input: STDIN [-I 0])
# S-ID: 1; J.DepP
* 0 1D
吾輩 わがはい 吾輩 名詞 6 普通名詞 1 * 0 * 0 "代表表記:我が輩/わがはい カテゴリ:人"
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
* 1 4D
猫 ねこ 猫 名詞 6 普通名詞 1 * 0 * 0 "代表表記:猫/ねこ 漢字読み:訓 カテゴリ:動物"
である である だ 判定詞 4 * 0 判定詞 25 デアル列基本形 15 NIL
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
* 2 4D
名前 なまえ 名前 名詞 6 普通名詞 1 * 0 * 0 "代表表記:名前/なまえ カテゴリ:抽象物"
は は は 助詞 9 副助詞 2 * 0 * 0 NIL
* 3 4D
まだ まだ まだ 副詞 8 * 0 * 0 * 0 "代表表記:まだ/まだ"
* 4 -1D
ない ない ない 形容詞 3 * 0 イ形容詞アウオ段 18 基本形 2 "代表表記:無い/ない 反義:動詞:有る/ある"
。 。 。 特殊 1 句点 1 * 0 * 0 NIL
EOS

J.DepP profiler:
io        : 0.0081 ms./trial (0.03242676/4)
dict      : 0.2302 ms.
preproc   : 0.0147 ms.
chunk     : 0.0203 ms.
depnd     : 0.0175 ms.

Voila!

ただこれだけだと人間にはわかずらいので, ↑の出力を tools/to_tree.py で tree 可視化します!

$ python tools/to_tree.py < test.jdep

# S-ID: 1; J.DepP
  0:  吾輩は━━┓   
  1:   猫である。━━┓
  2:     名前は━━┫
  3:      まだ━━┫
  4:        ない。EOS

Super cool!

日本語の品質判定

品詞やかかり受け具合とかみて, SVO 形式かどうかなど判断すればなんかいけそう?

とりあえずフォーマットは KNP と同じっぽいようなので, KNP をいじいじしたらいろいろとわかるかも.

https://qiita.com/Ultra-grand-child/items/ca6967f0ce07a978f358

文境界判定

web 文章でよくある途中で改行になっているもの.

吾輩は猫である♪
明日の天気
は晴れでしょう

https://zenn.dev/syoyo/scraps/a92ba417204672

bunkai などで文境界判定できますが, 遅すぎるので J.DepP(+ jagger 形態素解析) で高速化できるといいが...

そのままではこんな感じに判定されます.

# S-ID: 1; J.DepP
  0:  吾輩は━━┓
  1:   猫である♪EOS
# S-ID: 2; J.DepP
  0:  明日の━━┓
  1:      天気EOS
# S-ID: 3; J.DepP
  0:  は@@@@━━┓
  1:  晴れでしょうEOS

一行にして処理させてもこんな感じ

# S-ID: 1; J.DepP
  0:       吾輩は━━┓
  1:  猫である♪━━┓  ┃
  2:    明日の━━┫  ┃
  3:       天気は━━┫
  4:       晴れでしょうEOS

文節情報はあるので(tools/to_chunk.py で chunk(文節)区切り可視化できる)

$ python tools/to_chunk.py < test.jdepp 
# S-ID: 1; J.DepP
吾輩 は │ 猫 である ♪  │ 明日 の │ 天気  は │ 晴れ でしょう EOS

文節や品詞情報からいろいろ判断すればいけそうでしょうか...

TODO

  • Universal Dependencies あたりの構文ルールを元に, 日本語の自然らしさを判定する
  • 文境界判定ができないか調べる

Discussion