変換精度改善の方針
現状の仕組み
モデルのパイプライン
- ベースモデル: akaza-corpus-stats の大規模コーパス統計から unigram/bigram の出現頻度を取得
- コーパス学習:
learn-corpusが training-corpus の正解データを使ってスコアを補正 - 辞書: SKK-JISYO.L + SKK-JISYO.akaza で語彙をカバー
学習アルゴリズム(learn-corpus)
パーセプトロン的な手法を採用している:
- 正解と変換結果が異なる場合、正解側の unigram/bigram 出現頻度を delta(=2000)ずつ加算
- 正解と一致するまで、または最大エポック数に達するまで繰り返す
- 不正解側のスコアを下げる処理はない(正解を引き上げるのみ)
コーパスの3階層
| ファイル | エポック数 | 用途 |
|---|---|---|
| must.txt | 10,000 | 絶対に正しく変換すべきもの |
| should.txt | 100 | 正しく変換してほしいもの |
| may.txt | 10 | できれば正しく変換したいもの |
過学習のリスク
コーパスにエントリを追加していくと以下のリスクがある:
- スコアの偏り: delta=2000 × 最大10,000エポックで、個別エントリのスコアがベース統計を圧倒しうる
- 副作用: 特定の文脈でスコアを歪めると、同じ読みを含む別の文脈で誤変換が発生する
- 片方向学習: 正解のスコアを上げるだけで不正解を下げないため、多数のエントリが積み重なるとスコア分布が不自然になる
改善アプローチ
1. エラー分類を先に行う
make evaluate の k-best スコアリング(--k-best 5)で誤変換を2種類に分類する:
- BAD(top-k にも正解なし): 語彙やセグメンテーションの問題。コーパス学習では直らない可能性が高い
- TOP-k(top-1 は外れだが候補にはある): スコアリングの問題。コーパス学習で改善の見込みがある
対処の優先度は BAD > TOP-k。BAD はユーザーが候補を探しても見つからないため体験が最悪。
2. 辞書で直せるものは辞書で直す
dict/SKK-JISYO.akaza への追加は語彙を増やすだけで、unigram/bigram のスコアバランスを崩さない。
BAD のうち「そもそも候補に出ない」ものはまず辞書で対処するのが安全。
3. コーパスは「パターン」で入れる
1つの誤変換を直すために1行追加するのではなく、同じ種類の誤変換パターンをまとめて入れる。
例: 「暑い/熱い/厚い」の使い分け → 典型的な共起パターンを複数入れて bigram で自然に学習させる
夏/なつ は/は 暑い/あつい
お湯/おゆ が/が 熱い/あつい
板/いた が/が 厚い/あつい
個別の文をピンポイントで追加するより、パターンとして入れた方が汎化しやすく過学習しにくい。
4. 定量的にモニタリングする
コーパスを追加するたびに make evaluate の結果を確認し、退行がないか検証する。
Good=XXXX, Top-5=XXXX, Bad=XXXX, 再現率=XX.XX
Good が増えずに Top-k から BAD に移動するような退行が起きていないか注意する。
現状の評価結果(2026-02-08)
Good=5870 (53.1%), Top-5=493 (4.5%), Bad=4702 (42.5%), 再現率=91.47%
全11,065文中、半数強が top-1 で正解。再現率(文字レベルの LCS ベース)は91.5%。
エラーパターン分析
BAD(4,702件)の内訳
| カテゴリ | 件数 | 割合 | 説明 |
|---|---|---|---|
| 1箇所だけ誤り | 3,600 | 76.6% | 文中の1箇所だけが間違っている |
| 2箇所誤り | 937 | 19.9% | 文中の2箇所が間違っている |
| 3箇所以上 | 165 | 3.5% | 広範な誤り |
文字数の差(セグメンテーション品質の指標):
| 差 | 件数 | 割合 |
|---|---|---|
| 同一長 | 2,920 | 62.1% |
| 差2以下 | 4,660 | 99.1% |
| 差3以上 | 42 | 0.9% |
BAD のうち99%はセグメンテーション自体はほぼ正しく、漢字の選択ミス(同音異義語の取り違え) が主因。
主な誤パターン:
- 同音異義語の誤選択(~1,585件, 33.7%): 「使用/仕様」「行/言」「日本/二本」「買/書」等。セグメンテーションは正しいが漢字選択が間違い
- 漢字にすべきところがひらがな(~913件, 19.4%): 「明後日→あさって」「物→もの」「事→こと」等
- ひらがなにすべきところが漢字(~538件, 11.4%): 「ください→下さい」(63件)、「ない→無い」(136件)等
- 表記スタイルの不一致(588件, 12.5%): 「すでに」vs「既に」、「たくさん」vs「沢山」等
- カタカナ/ひらがな不一致(~175件, 3.8%): 「ダメ→だめ」「ごみ→ゴミ」等
- 全角/半角の違い(41件, 0.9%): 「?→?」「0→0」等。評価時の正規化で対処可能
- 文末表現の誤解析(~80件): 「かね→鐘」「よね→米」「ますね→マスネ」「ないん→ナイン」
TOP-5(493件)の内訳
TOP-5 の 94.7% は1箇所だけの誤りで、スコア調整で修正可能。
主な改善可能パターン:
| パターン | 件数 | 例 |
|---|---|---|
| 文末「かね」→「鐘」 | 17 | 「ありますかね」→「あります鐘」 |
| 文末「よね」→「米」 | 10 | 「ないですよね」→「ないです米」 |
| 「ないん」→「ナイン」 | 7 | 「ないんですよ」→「ナインですよ」 |
| 「ますね」→「マスネ」 | 4 | 「使えますね」→「仕えマスネ」 |
| 「きき」→「気気」 | 4 | 「危機に瀕する」→「気気に瀕する」 |
| 1文字漢字違い | 148 | 様々な同音異義語 |
| その他1箇所 | 278 | - |
スコアリングロジックの改善ポイント
重大度: 高
1. bigram バックオフが定数フォールバック
bigram が見つからない場合、default_edge_cost(= calc_cost(0, total_bigrams, unique_bigrams) ≈ 10-12)という単一の定数にフォールバックする。unigram 確率との補間(Jelinek-Mercer 補間や Stupid Backoff)がない。
影響: 「私は」のようなありふれた語の組み合わせでも、bigram モデルに含まれていなければ「鑢蛸」のような稀な組み合わせと同じペナルティを受ける。
改善案: lambda * P_bigram + (1-lambda) * P_unigram のような線形補間を導入する。
2. パスに長さ正規化がない
Viterbi のコストは sum(node_costs) + sum(edge_costs) の単純加算。セグメント数が増えるほど edge_cost が加算されるため、少ない分節数(長い単語)が体系的に有利。
影響: 「きょういくのはなし」→「教育の話」(3分節)より「今日行くの話」(4分節のように見えるが実際は「教育」vs「今日行く」のセグメンテーション競合)が不利になる構造的バイアス。
3. コスト関数の smoothing が非標準
#![allow(unused)]
fn main() {
cost = -log10((count + 0.00001) / (total_words + 0.00001 + unique_words))
}
ALPHA=0.00001 が極端に小さく、count=0(未知語)と count=1 の間に約5.0のコスト断崖がある。標準的な加算スムージングでは分母は total + alpha * V だが、現在は total + alpha + V で、未知語への確率配分がほぼゼロ。
重大度: 中
4. OOV の二重ペナルティ
未知語はノードコスト(高い unigram ペナルティ)とエッジコスト(全ての接続が default_edge_cost)の両方で罰せられる。固有名詞などの正当な未知語が候補に上がりにくい。
5. OOV 判定のバイト長ヒューリスティック
surface.len() < yomi.len() で漢字変換かどうかを判定しているが、1文字漢字(「気/き」等、バイト長が同一)はフル OOV ペナルティを受ける。
6. 文末表現の体系的な誤変換
「かね」「よね」「ますね」「ないん」が漢字/カタカナに変換される問題は、文末の助詞・終助詞が直前の動詞と分離されてセグメント化され、独立した語として漢字変換される ことが原因。bigram で「ます→ね」の接続コストが「ます→マスネ」より高くなっている。
頻出誤変換パターンと対処の優先度
優先度: 高(アルゴリズム改善で多数のケースに効く)
| パターン | 影響件数 | 対処方法 |
|---|---|---|
| 文末助詞「かね/よね/ますね/ないん」→ 漢字・カタカナ | ~80件 (BAD+TOP-5) | bigram「ます+かね」「です+よね」等の強化 |
| 「使用/仕様」(しよう) | ~35件 | bigram「使用+する/した/して」の強化 |
| 「行/言」(いって等) | ~33件 | bigram で移動先「に+行って」等を強化 |
| 「金/鐘」(かね) | ~40件 | unigram で「金」の重み引き上げ |
| 「日本/二本」(にほん) | ~18件 | bigram「日本+語/人/で/の」等の強化 |
| 「ここ/個々」 | ~25件 | unigram「ここ」の重み引き上げ |
| 「買/書/勝/飼」(かう等) | ~60件 | 目的語名詞との bigram 強化 |
| 「危機」→「気気」 | ~5件 | 辞書エントリの確認・追加 |
優先度: 中(表記規約の問題、方針を決めて対処)
| パターン | 影響件数 | 備考 |
|---|---|---|
| 「ください/下さい」 | ~63件 | 補助動詞としてはひらがなが現代標準 |
| 「ない/無い」 | ~136件 | anthy コーパスは「無い」を好む |
| 「もの/物」「こと/事」「ところ/所」 | ~129件 | 形式名詞としてはひらがなが標準 |
| 「ダメ/だめ/駄目」等カタカナ・ひらがな揺れ | ~175件 | 文脈依存、統一困難 |
優先度: 低(評価方法の改善で対処可能)
| パターン | 影響件数 | 備考 |
|---|---|---|
| 全角半角「?/?」「0/0」 | ~41件 | 評価時に正規化すれば解消 |
スコアリングロジック改善の優先順位
上記のエラー分析とコードの構造分析を総合すると、以下の順で取り組むのが効果的:
- bigram バックオフの改善 — 最多のエラー原因。定数フォールバックから unigram 補間への変更で、同音異義語の文脈判定が大幅に改善する見込み
- 文末助詞の bigram 強化 — コーパス追加で対処可能で即効性がある。「ます+かね」「です+よね」等のパターンを training-corpus に入れる
- コスト関数の smoothing 改善 — ALPHA の調整と標準的な加算スムージング式への変更で、OOV 周辺の挙動が安定する
- パス長の正規化 — 長い単語への構造的バイアスを緩和