数値+助数詞変換の再設計
背景
現在の Akaza は、<NUM> 正規化と数字+かな複合セグメントにより、数字付き語のカバレッジを拡張している。
一方で、助数詞変換については以下の課題が残る。
- コーパスに存在しない数字パターン(例:
516しゅうかん)の安定性をさらに上げたい - 入力数字の表記ゆれ(半角/全角/かな数詞)を同一に扱いたい
- 出力候補として半角数字・全角数字・漢数字を常に提示したい
本メモは、数値+助数詞を「コーパス依存の語彙問題」ではなく「規則ベースの構造問題」として扱う再設計案を示す。
目的
0ひき,ぜろひき,ひゃっぴき,3しゅうかん,516しゅうかんのような入力を安定して変換できる- Wikipedia / 青空文庫 / CC-100 に未出の数字でも候補生成できる
- 数字表記の候補として以下を自動追加する
- 半角数字(
516週間) - 全角数字(
516週間) - 漢数字(
五百十六週間)
- 半角数字(
非目的
- すべての日本語数詞(分数、序数、慣用表現)への一括対応
- 助数詞の音便規則を 100% 網羅すること
- 既存の Viterbi / reranking の全面置換
要件
機能要件
- 入力先頭の数値表現を抽出できること
- 半角数字:
0,516 - 全角数字:
0,516 - かな数詞:
ぜろ,れい,ひゃく,ひゃっ,せんなど(段階導入)
- 数値の直後に助数詞読みが続く場合、助数詞辞書により surface を生成できること
- 例:
ひき/びき/ぴき→匹 - 例:
しゅうかん→週間
- 同一の内部値(例: 516)に対して、複数数字表記を候補生成できること
516週間516週間五百十六週間
- LM lookup では
<NUM>助数詞キーでスコア共有できること
- 表記差 (
3週間,3週間,三週間) を同一スコア空間で扱う
品質要件
- 裸数字正規化は継続して禁止(
に→2型退行の防止) - 助数詞を伴わない入力への影響を最小化
- 既存変換の top-1 品質を大きく悪化させない
設計方針
数値+助数詞の処理を以下 3 レイヤに分離する。
NumericParser(入力正規化)
- 入力先頭から数値表現を抽出し、
NumericValueに正規化する
CounterLexicon(助数詞正規化)
- 助数詞読みと漢字表記の対応を管理
- 連濁・促音を同義として収束(例:
ひき/びき/ぴき)
CounterCandidateGenerator(候補生成)
NumericValue + Counterから多表記候補を動的生成- LM は
<NUM>正規化キーで評価
この分離により、コーパスカバレッジ不足を候補生成規則で補い、LM は主に順位付けに使う。
データ構造(案)
#![allow(unused)]
fn main() {
pub struct NumericValue {
pub value: i64,
pub consumed_len: usize, // 入力で消費した byte 長
pub source: NumericSource, // ASCII / Fullwidth / Kana
}
pub enum NumericSource {
AsciiDigits,
FullwidthDigits,
KanaNumeral,
}
pub struct CounterEntry {
pub canonical_yomi: &'static str, // 例: "ひき"
pub yomi_aliases: &'static [&'static str], // 例: ["ひき", "びき", "ぴき"]
pub surfaces: &'static [&'static str], // 例: ["匹"]
}
}
候補生成規則
入力 N + counter_yomi が成立した場合:
Nをi64に正規化counter_yomiをCounterLexiconでCounterEntryに解決- 各
surface_counterに対し、以下 3 系統の数字表記を生成
- 半角:
N_ascii + surface_counter - 全角:
N_fullwidth + surface_counter - 漢数字:
int2kanji(N) + surface_counter
例:
0ひき/ぜろひき→0匹,0匹,零匹ひゃっぴき(=100+ぴき)→100匹,100匹,百匹516しゅうかん→516週間,516週間,五百十六週間
スコアリング方針
候補キーは既存ルールに沿って <NUM>助数詞/<NUM>助数詞読み に正規化して LM lookup する。
516週間/516しゅうかん516週間/516しゅうかん五百十六週間/516しゅうかん
上記は同一キー "<NUM>週間/<NUM>しゅうかん" で評価できるようにする。
これにより、コーパスに 2週間 しかなくても 516週間 のスコアを共有できる。
ユーザー学習の汎化
ユーザーが変換結果を確定した際の学習データも、同じ <NUM> 正規化を適用する。
これにより、ある数字パターンでの学習が他の数字パターンにも汎化される。
- ユーザーが
3週間を確定 →<NUM>週間/<NUM>しゅうかんとして記録 - 以降、
516週間,2週間,百週間なども同じキーで lookup → スコアが上がる - unigram / bigram / skip-bigram の全ユーザー統計で同じ正規化を適用
連濁・促音の alias も正規化される:
3びきを確定 →<NUM>匹/<NUM>ひきとして記録(びき→ canonicalひき)- 以降、
5ひき,100ぴきなども同じキーでスコア共有
実装ポイント
Segmenter
- 数値検出を ASCII 専用正規表現から拡張し、全角数字とかな数詞を抽出可能にする
- 数値+助数詞の複合セグメントを優先的に候補化する
GraphBuilder
- 既存の数字+かな複合候補ロジックを
CounterCandidateGeneratorに置換 - 数字表記 3 系統を同時に追加
<NUM>フォールバックは継続し、裸数字除外も継続
辞書/設定
- 初期はコード内静的テーブルで開始し、将来的に
default-model側の辞書ファイルへ外出し可能な形にする
段階導入計画
- Phase 1: インフラ追加
NumericParser(ASCII/全角)CounterLexicon(最小セット: 匹, 人, 週間 など)CounterCandidateGenerator(3表記生成)
- Phase 2: かな数詞対応
ぜろ,れい,ひゃく,ひゃっ,せんなどを実装ひゃっぴきのような促音ケースを通す
- Phase 3: 評価と拡張
- 助数詞テーブルの拡充
- 退行監視を通して alias を追加
テスト計画
Unit Tests
- NumericParser:
0,0,516,516,ぜろ,ひゃっ
- CounterLexicon:
ひき/びき/ぴき -> 匹しゅうかん -> 週間
- CandidateGenerator:
3しゅうかん→3週間,3週間,三週間516しゅうかん→516週間,516週間,五百十六週間
Integration Tests
0ひき,ぜろひき,ひゃっぴき,3しゅうかん,516しゅうかんの変換結果確認- 既存退行ケース(助詞「に」「さん」「ご」)が悪化しないこと
Evaluate
default-modelの評価結果で Good/Bad 差分を確認- 数字表記差分は必要に応じて
accept.tsvで管理
リスクと対策
- かな数詞解析の誤爆
- 対策: 数値として解釈する条件を「助数詞が後続する場合」に限定する
- 追加対策(実装済み):
- 1文字かな数詞(
に,し,ご,く)は曖昧性が高いため除外(にほん→2本防止) - 1文字助数詞(
じ,ど,こ,わ)はかな数詞との組み合わせでは除外(いちじ→1時防止) - かな数詞パスでは助数詞の完全一致のみマッチ(
じょうがじにマッチする誤爆を防止) - かな数詞検出時も trie 探索を並行実行し、Viterbi に両方の解釈を提供
- 1文字かな数詞(
- 助数詞同音語(週間/週刊 など)の誤選択
- 対策: CounterLexicon で優先候補を制御し、LM は補助に使う
- 候補数増加による速度低下
- 対策: 数字表記は原則 3 種固定、助数詞未解決時は既存経路にフォールバック
受け入れ条件
- 指定例(
0ひき,ぜろひき,ひゃっぴき,3しゅうかん,516しゅうかん)で期待候補が出る - 裸数字正規化禁止ルールを破らない
- 既存評価で重大退行(助詞の数字化)が発生しない