構造化パーセプトロン実装の評価レポート
背景
learn-corpus 改善実験で、カウントベース更新(加算/減算)は evaluate スコアに影響を与えないと報告された。しかし、この実験には評価方法の問題があった(後述)。
コスト関数 cost = -log10((count + α) / (total + α + V)) の非線形性により、カウント操作では高頻度語のコスト変化が微小で変換結果を変えにくい。この問題を解決するため、構造化パーセプトロンの方針に基づき、カウントではなくコストに直接加算するスコアベースの構造化パーセプトロンを実装した。
前回実験の評価方法の問題
前回の実験では「ベースライン」として data/(learn-corpus 適用済みモデル)を使用し、これを learn-corpus 再実行後のモデルと比較していた。つまり学習済み vs 再学習済みの比較であり、未学習 vs 学習済みの比較ではなかった。旧 learn-corpus のカウント操作がわずかしか効果がない場合、再学習してもほぼ同じモデルが生成されるため、差が出ないのは当然だった。
実装概要
変更点
- OnMemory LM に
adjustment: HashMap<K, f32>を追加:find()/get_edge_cost()が返す値に adjustment を加算 - 学習ロジックの書き換え: 不正解時に以下の更新を実行
- 教師パスの全特徴(unigram/bigram/skip-bigram): コスト -= step_size(安くする)
- 予測パスの全特徴: コスト += step_size(高くする)
- CLI 引数:
--delta(u32) →--step-size(f32, default 0.5)
パラメータ
step_size = 0.5
may_epochs = 10, should_epochs = 100, must_epochs = 10000
実験結果
3条件の比較
今回は「未学習モデル」(learn-corpus を epochs=1 で実行し、学習ループを実行しないモデル)を加えて、正しくベースラインを取った。
| 手法 | Good | Top-5 | Bad | 再現率 |
|---|---|---|---|---|
| 未学習(生の統計のみ) | 6708 | 426 | 3931 | 93.239% |
| 旧 learn-corpus(delta=2000) | 6719 | 416 | 3930 | 93.267% |
| 構造化パーセプトロン (step=0.5) | 6614 | 492 | 3959 | 92.768% |
旧 learn-corpus の効果(再評価)
| 比較 | Good差 | 再現率差 |
|---|---|---|
| 旧 learn-corpus vs 未学習 | +11 | +0.028% |
前回の実験では「旧 learn-corpus は効果なし」と結論づけたが、正しくはわずかに効果がある(+11 文, +0.028%)。前回は「学習済み vs 再学習済み」を比較していたため差が出なかった。
構造化パーセプトロンの効果
| 比較 | Good差 | 再現率差 |
|---|---|---|
| パーセプトロン vs 未学習 | -94 | -0.471% |
| パーセプトロン vs 旧 learn-corpus | -105 | -0.499% |
構造化パーセプトロンは未学習モデルよりも悪い。学習が悪影響を与えている。
差分分析(パーセプトロン vs 旧 learn-corpus)
概要
| カテゴリ | 件数 |
|---|---|
| 新版でBADになった(以前は正解) | 431 |
| 新版で修正された(以前はBAD) | 405 |
| 両方BADだが変換が変わった | ~820 |
| 純損失 | 26 |
新規リグレッション上位パターン
| パターン | 件数 | 説明 |
|---|---|---|
| 「き」→「季」 | 51件 | 文節区切り失敗で語末「き」が独立文節「季」に |
| 「を」→「ヲ」 | 33件 | 助詞がカタカナ化 |
| 「きのう」→「機能」 | 19件 | 「昨日」が「機能」に誤変換 |
| 「きゅう」: 急→旧 | 11件 | 同音異義語の優先度逆転 |
| 「ご」→「御」 | 9件 | ひらがなであるべき接頭辞の漢字化 |
| 「にほん」→「に本」 | 7件 | 文節区切りの破壊 |
| 「かく」: 書く→各 | 7件 | 同音異義語の優先度逆転 |
修正されたパターン(改善点)
| パターン | 件数 | 説明 |
|---|---|---|
| 「き」: 木→気 | 35件 | 旧版の「気→木」誤変換が修正 |
| 「さい」: 賽→再 | 14件 | 旧版の「再→賽」誤変換が修正 |
| 「あき」: 空き→秋 | 7件 | 旧版の「秋→空き」誤変換が修正 |
| 「えん」: 縁→円 | 6件 | 旧版の「円→縁」誤変換が修正 |
考察
1. コストへの直接加算は変換結果を変える力がある
前回のカウントベース実験(正しく評価すると +11 文の微小な効果)と異なり、構造化パーセプトロンは大量の変換結果を変化させた(1000件超)。コストに直接加算するアプローチは確実にモデルに影響を与える。
2. しかし方向が間違っている
学習の力はあるが、全体としては悪化。改善(405文)より劣化(431文)が上回っている。
3. 劣化の原因分析
a) 学習コーパスの規模と評価コーパスのドメイン差
学習コーパス(training-corpus/)は手作業で作成した少量のデータ。この限られたデータで学んだ重みが、11,065 件の評価コーパスに対して汎化できていない。「季」「ヲ」「機能」などのリグレッションは、学習コーパスの偏りを反映している。
b) step_size = 0.5 が大きすぎる
step_size 0.5 は、典型的なコスト値(2〜8 程度)に対してかなり大きい。数十〜数百エポック繰り返すと adjustment が数十に達し、元のコスト構造を大きく歪める。
c) 正則化の欠如
現在の実装には正則化がない。過学習により、学習コーパスにフィットする代わりに汎化性能が低下している。
d) 教師パスのみの更新
教師パスと予測パスで共通する特徴が相殺されるため、差分のみを更新すべき。また、正解時にも重み更新しないため、正の事例からの学習が不足している可能性がある。
4. 今後の改善方向
- step_size の縮小: 0.05〜0.1 など、より保守的な値を試す
- averaged perceptron: 全エポックの重みの平均を取ることで過学習を抑制
- 学習コーパスの拡充: 評価コーパスとドメインが重なるデータの追加
- early stopping: 検証セットで精度が低下し始めたらエポックを打ち切る
- 特徴の重複除外: 教師パスと予測パスで共通する特徴をスキップ
- 学習率スケジューリング: エポックが進むにつれて step_size を減衰させる
結論
構造化パーセプトロンによるスコアベース学習は、カウントベース学習と異なりモデルの変換結果を大量に変える力があることが確認された。しかし、現在のパラメータ設定(step_size=0.5)と限られた学習コーパスでは未学習モデルより悪化する結果となった。
旧 learn-corpus(カウントベース)も正しく評価すると +11 文(+0.028%)のわずかな改善効果があることが判明した。
構造化パーセプトロンの実装基盤は整ったが、正則化(averaged perceptron)、学習率の調整、学習コーパスの拡充が精度改善のために必要である。現時点ではこの変更をデフォルトモデルのビルドに適用すべきではない。