オリジナル辞書/コーパスからのパラメータ推定

$Id: learn.html,v 1.9 2006/04/30 14:30:25 taku-ku Exp $;

概要

学習用コーパスからパラメータ(コスト値)を推定することができます. MeCab 自身は品詞体系に非依存な設計になっているため, 独自の品詞体系, 辞書, コーパスに基づく解析器を作成することができます. パラメータ推定には Conditinoal Random Fields (CRF) を使っています.

処理の流れ

データフロー図は次のようになります.

パラメータ推定には以下のサブタスクがあります.

それぞれ順に説明していきます.

Seed辞書の準備

MeCabの辞書は CSV で記述されます. Seed 辞書と配布辞書のフォーマッ トは基本的に同一です.

以下が辞書のエントリの例です.

進学校,0,0,0,名詞,一般,*,*,*,*,進学校,シンガクコウ,シンガクコー
梅暦,0,0,0,名詞,一般,*,*,*,*,梅暦,ウメゴヨミ,ウメゴヨミ
気圧,0,0,0,名詞,一般,*,*,*,*,気圧,キアツ,キアツ
水中翼船,0,0,0,名詞,一般,*,*,*,*,水中翼船,スイチュウヨクセン,スイチューヨクセン

最初の4カラム目までは, 必須項目で,

となっています. 左連接状態番号, 右連接状態番号, コストは, Seed 辞書では 使われないので 0 としておきます.

5カラム目以降は「素性」と呼ばれる項目です. MeCab は, システムの汎用性 を高めるために, 「品詞」「活用」「読み」「発音」といった「単語に付与され る情報」をシステムは区別せず「素性」として扱っています. ユーザは CSV が 許す限り何個でも素性を付与することができます. ただし, 各カラムの素性の 定義はそろえておく必要があります. (5カラム目は品詞, 6カラム目は品詞再分 類等) 通常, 素性番号の若いものから順に一般的な素性を列挙していきます. (例: 品詞, 品詞細分類, 活用型, 活用形, 原形, 読み, 発音)

素性は内部的には配列として扱われます. 0番目の素性, 1番目の素性.. と いう呼び方で素性を参照することがあります. 素性の番号と内部表現(品詞, 読 み等)は, ユーザ自身が管理してください.

上記の例は, ipadic の例です. 素性列として

が定義されています.

MeCab は活用処理を行いません. 活用する語の場合は, ユーザが事前に活用 を展開する必要があります.

連れ出す,0,0,0,動詞,自立,*,*,五段・サ行,基本形,連れ出す,ツレダス,ツレダス
連れ出さ,0,0,0,動詞,自立,*,*,五段・サ行,未然形,連れ出す,ツレダサ,ツレダサ
連れ出そ,0,0,0,動詞,自立,*,*,五段・サ行,未然ウ接続,連れ出す,ツレダソ,ツレダソ
連れ出し,0,0,0,動詞,自立,*,*,五段・サ行,連用形,連れ出す,ツレダシ,ツレダシ
連れ出せ,0,0,0,動詞,自立,*,*,五段・サ行,仮定形,連れ出す,ツレダセ,ツレダセ
連れ出せ,0,0,0,動詞,自立,*,*,五段・サ行,命令e,連れ出す,ツレダセ,ツレダセ
連れ出しゃ,0,0,0,動詞,自立,*,*,五段・サ行,仮定縮約1,連れ出す,ツレダシャ,ツレダシャ

設定ファイルの準備

dicrc

辞書のさまざまな動作を指定するファイルです. 以下が最低限の設定です.

cost-factor = 800
bos-feature = BOS/EOS,*,*,*,*,*,*,*,*
eval-size = 6
unk-eval-size = 4

char.def

未知語処理の定義ファイルです. 通常日本語の形態素解析では字種に基づく未知 語処理が行われます. MeCab では, どの文字をどの字種として定義するかといった設 定を細かく指定することができます. さらに, 各字種に対し, どのような未知語 処理を行うか細かく指定することができます.

ファイルの最初には, カテゴリ名の定義と, 各カテゴリの未知語処理の動作 を定義します.

カテゴリ名      動作タイミング(0/1)  グルーピング(0/1)  長さ(0,1, 2... n)

KANJI          0 0 2
SYMBOL         1 1 0
NUMERIC        1 1 0
ALPHA          1 1 0
HIRAGANA       0 1 2 

次に, 各カテゴリがUCS2のコードポイントのどこに該当するか定義します.

codepoint デフォルトカテゴリ名 互換カテゴリ名1  互換カテゴリ名2 .. 

もしくは,

low_codepoint..high_codepoint デフォルトカテゴリ名 互換カテゴリ名1  互換カテゴリ名2 .. 

0x0009 SPACE
0x30A1..0x30FF  KATAKANA
0x30FC          KATAKANA HIRAGANA  # ー

コードポイントは UCS2(Unicode)を 0x から始まる16進数で記述します.

最初のカテゴリは, そのコードポイントのデフォルトカテゴリです. さらに, 互換カテゴリを列挙することができます. 上記の例では, 長音記号「ー」 は, デフォルトではカタカナですが, 平仮名を互換カテゴリとして持ちます. グルーピング動作の時に互換カテゴリは同じグループとしてみなされます.

以下が char.def の具体例です.

DEFAULT        0 1 0  # DEFAULT is a mandatory category!
SPACE          0 1 0  
KANJI          0 0 2
SYMBOL         1 1 0
NUMERIC        1 1 0
ALPHA          1 1 0
HIRAGANA       0 1 2 
KATAKANA       1 1 0
KANJINUMERIC   1 1 0
GREEK          1 1 0
CYRILLIC       1 1 0

# SPACE
0x0020 SPACE  # DO NOT REMOVE THIS LINE,  0x0020 is reserved for SPACE
0x00D0 SPACE
0x0009 SPACE
0x000B SPACE
0x000A SPACE

# ASCII
0x0021..0x002F SYMBOL
0x0030..0x0039 NUMERIC

... 

# KATAKANA
0x30A1..0x30FF  KATAKANA
0x31F0..0x31FF  KATAKANA  # Small KU .. Small RO
0x30FC          KATAKANA HIRAGANA  # ー

unk.def

未知語用の辞書です.

DEFAULT,0,0,0,記号,一般,*,*,*,*,*
SPACE,0,0,0,記号,空白,*,*,*,*,*
KANJI,0,0,0,名詞,一般,*,*,*,*,*
KANJI,0,0,0,名詞,サ変接続,*,*,*,*,*
HIRAGANA,0,0,名詞,一般,*,*,*,*,*
HIRAGANA,0,0,0,名詞,サ変接続,*,*,*,*,*
HIRAGANA,0,0,0,名詞,固有名詞,地域,一般,*,*,*
... 

表層の部分を char.def で定義したカテゴリ名とした辞書ファイルです. 各カテゴリに対してどのような素生列を付与するかを定義します. 1つのカテゴリに複数の素性を定義してもかまいません. 学習後, 適切なコスト値が 自動的に与えられます.

rewrite.def

素性列から内部状態素生列に変換するマッピングを定義します.

CRFは, unigram, 左文脈 bigram, 右文脈 bigram の3情報を使って統計情報を計 算します. 例えば以下の「美しい川」という以下の例では, 辞書に定義されている素性から unigram素性, 左文脈素性(その形態素を左側から見た時の素性), 右文脈素性(その形態素を左側から見た時の素性)の3つが使われます. rewrite.def は, 辞書の素性からそれぞれの素性へのマッピングを定義します.

具体的に以下のようなことがマッピング関数を適切に定義することで実現できます.

rewrite.def は, perl のライブラリです. perl 言語のシンタックスで 以下の4つの関数を定義します.

(unigram|left|right)_rewrite は, 素性の配列のリファレンスを引数に与え, 書き換えられた素性の配列のリファレンスを返す関数です

sub init_rewrite {}

sub unigram_rewrite {

    # 読み, 発音をとりのぞいて,  品詞1, 2, 3, 4, 活用形, 活用型, 原形, よみ を使う
    my @F = @{shift @_}[0..7];

    # 原形の同一視ルール
    if ($F[6] =~ /^(言う|いう|云う)$/) {
        $F[6] = "言う";
    } elsif ($F[6] =~ /^(来る|くる)$/) {
        $F[6] = "来る";
    } elsif ($F[6] =~ /^(行く|行う|する)$/) {
        $F[6] = "行く";
    }

    return \@F;
}

sub left_rewrite {

    # 読み, 発音をとりのぞいて,  品詞1, 2, 3, 4, 活用形, 活用型, 原形のみを使う
    my @F = @{shift @_}[0..6]; 

    if ($F[0] =~ /^(助詞|助動詞)/) {

        # 語彙化なのでそのまま    

    } elsif ($F[0] =~ /^動詞/) {

        if ($F[6] =~ /^(言う|いう|云う)$/) {
            $F[6] = "言う";
        } elsif ($F[6] =~ /^(来る|くる)$/) {
            $F[6] = "来る";
        } elsif ($F[6] =~ /^(行く|行う|する)$/) {
            $F[6] = $1;
        } else {
            $F[6] = "*";
        }

    } elsif ($F[0] =~ /^形容詞/) {

        if ($F[6] =~ /(ない|づらい|にくい|ぽい|っぽい|たらしい|ったらしい|くさい)$/) {
            $F[6] = $1; # 語尾でまとめる
        } elsif ($F[6] =~ /(欲しい|ほしい)$/) {
            $F[6] = "欲しい";
        } elsif ($F[6] =~ /(がたい|難い)$/) {
            $F[6] = "難い";
        } else {
            $F[6] = "*";
        }

    } else {
        $F[6] = "*"; # 語彙部分を * に変更
    }

    return \@F;
}

sub right_rewrite {
  return left_rewrite(shift @_);
}

1;

feature.def

内部状態の素生列から CRFの素生列を抽出するためのテンプレートを定義したファイルです

各行が一テンプレートに対応します. UNIGRAM ではじまるものは UNIGRAM 用 のテンプレート, BIGRAM ではじまるものは連接用のテンプレートです.

各テンプレートでは, 以下のマクロを使うことができます

UNIGRAM W0:%F[6]
UNIGRAM W1:%F[0]/%F[6]
UNIGRAM W2:%F[0],%F?[1]/%F[6]
UNIGRAM W3:%F[0],%F[1],%F?[2]/%F[6]
UNIGRAM W4:%F[0],%F[1],%F[2],%F?[3]/%F[6]

UNIGRAM T0:%t
UNIGRAM T1:%F[0]/%t
UNIGRAM T2:%F[0],%F?[1]/%t
UNIGRAM T3:%F[0],%F[1],%F?[2]/%t
UNIGRAM T4:%F[0],%F[1],%F[2],%F?[3]/%t

BIGRAM B00:%L[0]/%R[0]
BIGRAM B01:%L[0],%L?[1]/%R[0]
BIGRAM B02:%L[0]/%R[0],%R?[1]
BIGRAM B03:%L[0]/%R[0],%R[1],%R?[2]
BIGRAM B04:%L[0],%L?[1]/%R[0],%R[1],%R?[2]
BIGRAM B05:%L[0]/%R[0],%R[1],%R[2],%R?[3]
BIGRAM B06:%L[0],%L?[1]/%R[0],%R[1],%R[2],%R?[3]
... 

学習用コーパスの準備

学習データは, MeCab のデフォルト出力と同一フォーマットで記述します.

太郎    名詞,固有名詞,人名,名,*,*,太郎,タロウ,タロー
は      助詞,係助詞,*,*,*,*,は,ハ,ワ
花子    名詞,固有名詞,人名,名,*,*,花子,ハナコ,ハナコ
が      助詞,格助詞,一般,*,*,*, が,ガ,ガ
好き    名詞,形容動詞語幹,*,*,*,*, 好き,スキ,スキ
だ      助動詞,*,*,*, 特殊・ダ,基本形,だ,ダ,ダ
.       記号,句点,*,*,*,*, . , . , . 
EOS
焼酎    名詞,一般,*,*,*,*,焼酎,ショウチュウ,ショーチュー
好き    名詞,形容動詞語幹,*,*,*,*,好き,スキ,スキ
の      助詞,連体化,*,*,*,*, の,ノ,ノ
親父    名詞,一般,*,*,*,*,親父,オヤジ,オヤジ
.       記号,句点,*,*,*,*, . , . , . 
EOS
... 

タブで区切られた最初の部分が表層文字です. 次に素性配列を CSVで表現した文 字列が続きます. 文の区切りには EOS のみの行を置きます.

学習用バイナリ辞書の作成

現在の作業ディレクトリを WORK とします. WORK 以下に seed と final と いう二つのディレクトリを作ってください.

cd $WORK
mkdir seed final

seed ディレクトリにさきほど説明した以下のファイルをコピーします.

% cd $WORK/seed
% ls 
Adj.csv          Interjection.csv   Noun.name.csv    Noun.verbal.csv  Symbol.csv        rewrite.def
Adnominal.csv    Noun.adjv.csv      Noun.number.csv  Others.csv       Verb.csv          unk.def
Adverb.csv       Noun.adverbal.csv  Noun.org.csv     Postp-col.csv    char.def
Auxil.csv        Noun.csv           Noun.others.csv  Postp.csv        corpus
Conjunction.csv  Noun.demonst.csv   Noun.place.csv   Prefix.csv       dicrc
Filler.csv       Noun.nai.csv       Noun.proper.csv  Suffix.csv       feature.def

以下のコマンドを実行して, 学習用バイナリ辞書を作成します.

% cd $WORK/seed
% /usr/local/libexec/mecab/mecab-dict-index -l 

以下のように -d,  -o を使うこともできます. 
% /usr/local/libexec/mecab/mecab-dict-index -l -d $WORK/seed -o $WORK/seed

CRF パラメータの学習

% cd $WORK/seed
% /usr/local/libexec/mecab/mecab-cost-train -c 1.0 corpus model

以下のように -d を使って辞書を指定することもできます<
% /usr/local/libexec/mecab/mecab-cost-train -d $WORK/seed -c 1.0 $WORK/seed/corpus $WORK/seed/model

mecab-cost-train はバイナリモデルの作成の時に大量のメモリを消費します. 以下のようにバイナリモデルの作成を別プロセスで行うことでメモリ消費を 抑えることができます.

% /usr/local/libexec/mecab/mecab-cost-train -y -c 1.0 corpus model
% /usr/local/libexec/mecab/mecab-tool -b -i model.txt -o model

ハイパーパラメータCは, 学習の「強さ」を決めます. C を大きくすると, 学習データにできるだけフィットしようとしますが, 過学習する可能性があります. 小さくすると, 過学習を避けようとしますが, 十分な学習ができない可能性があります. 適切な C は, 交差検定等のモデル選択手法で発見的に見つけるしかありません. デフォルトの値は 1. 0 となっています.

-f オプションによって素性頻度の閾値を指定することができます. 例えば, -f 3 とすると, 学習データ中に3回以上出現した素性のみを使います. 適切な 素性閾値は, 交差検定等のモデル選択手法で発見的に見つけるしかありません.

学習中, 以下のような情報が出力されます.

reading corpus ... adding virtual node: 名詞,固有名詞,地域,一般,*,*,東日,トウニチ,トウニチ
adding virtual node: 副詞,助詞類接続,*,*,*,*,かなり,カナリ,カナリ

Number of sentences: 32
Number of features:  47547
eta:                 0.00010
freq:                1
C(sigma^2):          1.00000

iter=0 err=1.00000 F=0. 41186 target=1691.68869 diff=1.00000
iter=1 err=1.00000 F=0. 68727 target=1077.14848 diff=0.36327
iter=2 err=0.87500 F=0. 81904 target=621.20311 diff=0.42329
iter=3 err=0.81250 F=0. 86354 target=384.72432 diff=0.38068
iter=4 err=0.68750 F=0. 93685 target=233.72722 diff=0.39248
..

配布用辞書の作成

% cd $WORK/seed
% /usr/local/libexec/mecab/mecab-dict-gen -o ../final -m model

以下のように -d,  -o を使って辞書を指定することもできます
% /usr/local/libexec/mecab/mecab-dict-gen -o $WORK/final -d $WORK/seed -m $WORK/seed/model

配布用辞書は, seed 辞書と別のディレクトリに出力しなければなりません. 通常, 配布辞書ディレクトリ final をアーカイブしてユーザに配布します.

解析用バイナリ辞書の作成

% cd $WORK/final
% /usr/local/libexec/mecab/mecab-dict-index 

以下のように -d,  -o を使うこともできます. 
% /usr/local/libexec/mecab/mecab-dict-index -d $WORK/final -o $WORK/final

今作った辞書を使って実際に解析してみます.

% mecab -d $WORK/final
焼酎好きの親父. 
焼酎    名詞,一般,*,*,*,*,焼酎,ショウチュウ,ショーチュー
好き    名詞,形容動詞語幹,*,*,*,*,好き, スキ, スキ
の      助詞,連体化,*,*,*,*,の,ノ,ノ
親父    名詞,一般,*,*,*,*,親父, オヤジ, オヤジ
.       記号,句点,*,*,*,*,.,.,. 
EOS

評価

テストデータを用意します. テストデータは MeCab の デフォルト出力と同一フォーマットで記述します.

まず, mecab-test-gen を使ってテストコーパス(test)から, 文のみ(test.sen)を抽出します.

% /usr/local/libexec/mecab/mecab-test-gen test > test.sen

test.sen をさきほど作った辞書で解析します.

% mecab -d $WORK/final test.sen > test.result

評価スクリプト mecab-system-eval を実行します. 第一引数がシステムの結果, 第二引数が正解のファイルです.

% /usr/local/libexec/mecab/mecab-system-eval test.result test

-l オプションによって, どの素性のレベルを使って評価するか指定できます.


$Id: learn.html,v 1.9 2006/04/30 14:30:25 taku-ku Exp $;