はじめに
kanasim は、カタカナ列同士の「音韻的な近さ」を計算するPythonライブラリです。Julius(dictation-kit)の音響モデルから導出した音素間距離表をコストとする重み付き編集距離で、カナダ と カラダ は近く、カナダ と バハマ は遠い、といった距離を返します。
from kanasim import create_kana_distance_calculator
calculator = create_kana_distance_calculator()
print(calculator.calculate("カナダ", "カラダ")) # 近い
print(calculator.calculate("カナダ", "バハマ")) # 遠い
空耳・替え歌・押韻などへの応用を想定して「音の似た言葉」を扱う用途で作ったものですが、以前から、母音重み(vowel_ratio)を上げても思ったほど効かないという課題を感じていました。母音の一致/不一致を特別扱いする vowel_binary のような対処も入れていたものの、根本的には子音と母音の距離を独立したスケールで扱えるようにすべきでは、と考えたのが今回のきっかけです。そこで v0.0.11 にかけて距離計算のオプションを4つ追加し、性質の異なる2つのベンチマークで実測比較しました。
追加した4つのオプション
1. phoneme_unit="mono": モノフォン距離表
デフォルトの距離表はバイフォン単位(k+a vs k+i のように後続母音つき)です。このため子音距離に母音文脈が混入し、直感に反するケースがあります。実測では、同じ子音の k+a vs k+i(69.5)が、別の子音の k+a vs t+a(67.3)より遠くなっていました。
phoneme_unit="mono" で、バイフォン距離を同一モノフォン組で平均したモノフォン距離表に切り替えられるようにしました。また、Julius dictation-kit のモノフォンGMM-HMM(jnas-mono-16mix-gid.hmmdefs)から再計算した距離表も同梱しています。導出はバイフォン表と同じモンテカルロ流で、音素Aの各状態のGMMから1000サンプル(シード固定)を生成し、音素BのGMMでの平均負対数尤度(=交差エントロピー)を推定します。後述のベンチマークではバイフォン平均とほぼ同等でした。
2. consonant_distance="features": 弁別素性ベースの子音距離
音響モデル由来の距離の代わりに、音韻論の弁別素性(有声性・調音位置・調音様式・鼻音性・口蓋化など)の一致度から子音距離を求めるオプションです。ラップの押韻分析(川原 2007 "Half rhymes in Japanese rap lyrics and knowledge of similarity" など)で使われる「共有素性が多いほど良い韻」という考え方に準拠し、距離は不一致素性の割合(対称・[0,1])です。
日本語子音28個×素性7項目の行列をCSVで同梱しているので、素性の追加・削除・重み付けを編集して再生成できます。音韻的な直感とはよく合います(有声化ペア k↔g = 0.14 < 調音位置違い k↔s = 0.29 < ほぼ全部違う m↔s = 0.71)。
3. normalize: 子音・母音距離の正規化
kanasimの距離は 子音距離 × (1 - vowel_ratio) + 母音距離 × vowel_ratio の線形結合です。ところが子音・母音の距離表は音響モデル由来の生スケール(数十)なので、スケールの異なる距離(0/1のバイナリ距離や、前述の [0,1] の素性距離)と混ぜると、スケールの大きい側が結果を支配してしまい、vowel_ratio による重み付けが意味をなしません。normalize=True で、子音・母音の距離表をそれぞれ最大値で [0, 1] に正規化してから結合できるようにしました。
なお、順位づけだけを考えるなら normalize に固有の表現力はありません。kanasimでは挿入・削除コストも同じ距離表から作られるため、全コストが (1 - vowel_ratio) × 子音距離 + vowel_ratio × 母音距離 の共通スケール倍になっており、normalizeによる子音・母音バランスの変化は vowel_ratio の振り直しで厳密に再現できます(例: 生スケールの vr=0.8 は normalize での vr≈0.89 と同じ順位を与えます)。normalizeの価値は、子音と母音を同じ [0, 1] スケールに揃えることで、vowel_ratio を「母音をどれだけ重視するか」の直感的なつまみとして使えるようにする点にあります。
4. symmetric: 距離の対称化
kanasimの距離は実は非対称で、calculate("カナダ", "バハマ") と calculate("バハマ", "カナダ") は違う値を返します。これはバグではなく、距離表が「音素AのHMMのサンプルが音素BのHMMからどれだけ出力されにくいか」という尤度ベースで導出されているためです(交差エントロピーなので向きがある)。
とはいえ用途によっては向き非依存の距離が欲しいので、symmetric=True で双方向平均を取れるようにしました。精度向上を狙うものではなく、対称性が必要な場面のためのオプションです。
# 歌唱ASRマッチング向け(検証1の最良設定)
calculator = create_kana_distance_calculator(normalize=True, vowel_ratio=0.3)
# 押韻・替え歌の語検索向け(検証2の最良設定)
calculator = create_kana_distance_calculator(vowel_ratio=0.8)
なお、これらと並行して編集距離の実装を再帰+メモ化から反復DPに書き換え、計算値そのままで約10倍高速化しました(30モーラ×400ペアで0.87s→0.085s)。
オプションの使い分け
-
音響モデル由来の子音・母音バランスをそのまま使いたい: biphone または mono を normalize なし・
vowel_ratio=0.5で使う。距離表の子音:母音のスケール比が、そのまま音響モデル上の間違いやすさの比として効きます -
母音の重要度を明示的に調整したい、またはバイナリ・素性など別種の距離を使う: mono系の距離表 +
normalize=Trueを前提にvowel_ratioで良いところを探る。biphoneの距離表は子音・母音の各チャンネルに相手側の文脈が滲んでいるため、vowel_ratioを0.5からずらしても「母音の重みだけ」を動かすことにならず、解釈が難しくなります(ただし後述の検証2ではbiphone vr=0.8が最良であり、解釈のしにくさが性能低下に直結するとは限りません) -
距離として対称性が欲しい(クラスタリング、相互距離行列など):
symmetric=Trueを付ける
検証1: 歌唱ASRの誤りマッチング
1つ目のベンチマークは「英語歌唱→空耳カナ」ASRの出力と正解カナのマッチングです。人手の空耳カナ(歌える表記)が付いた実歌唱653クリップに対し、ASR出力カナをクエリ、653件の正解カナ全体を候補として、kanasimの距離そのままでランキングし、自クリップの正解カナを何位に置けるかを測ります(チャンス水準はmedian rank ≈ 327。ASR出力が空のクリップは全挿入コストとして採点し、未対応トークンを含む数件のみ除外、n=644)。
vowel_ratio の調整を伴う比較では、クエリを偶奇で調整用327件と検証用326件に分割し、調整用データで最良の vowel_ratio を選び、検証用データでの数値だけを報告します。
軸1: 距離表の種類
まず母音重みを調整しない素の状態(修飾なし・vr=0.5=音響モデルの特徴をそのまま使う場合、全653クエリ)の比較です。
| biphone | mono_avg | mono_hmm | features |
|---|---|---|---|
| 24.5% | 19.1% | 20.7% | 9.2% |
biphoneがモノフォン系を4〜5pt上回り、素性距離は大差で悪化します。mono_avg(バイフォン平均)と mono_hmm(GMM-HMMから再計算)はほぼ同水準でした。
次に、normalize=True で各距離表ごとに最適な vowel_ratio を調整した場合(調整用データで選び、検証用データで報告)です。素の能力はタスクによらない参考値、こちらは「このタスクに合わせ込んだときのベスト」の比較です。
| 距離表 | 調整で選ばれたvr | top-1 | MRR | median rank |
|---|---|---|---|---|
| biphone | 0.3 | 32.2% | 0.296 | 60.5 |
| mono_avg | 0.2 | 25.7% | 0.246 | 92 |
| mono_hmm | 0.2 | 25.4% | 0.241 | 92 |
| features | 0.6 | 18.6% | 0.190 | 131.5 |
それぞれのベスト状態で比べても biphone > mono_avg ≈ mono_hmm > features で、素の比較と序列は同じでした。最適vrは距離表ごとに違う(0.2〜0.6)ので、固定vrでの比較は不公平になります。normalizeは前述の通り順位づけ上はvrの再パラメータ化と等価なので、この軸は実質「各距離表のベスト同士の比較」です。母音重みは生スケール換算で0.1〜0.2相当の低めが合うタスクでした(biphoneの調整曲線はvr=0.1〜0.3でほぼ平坦です)。
軸2: symmetric — biphone + normalize で vr=0.2〜0.8 を比較すると、対称化はどの点でも一貫してtop-1を1.6〜3.4pt下げました。距離表(対角引き後)の非対称成分は、対称成分の平均に対して子音で約14%・母音で約7%、挿入・削除コストの元になる無音 sp との距離では約41%あります。対称化でこうした非対称性が失われたことが悪化につながったのかもしれません。精度向上を狙うオプションではない、という位置づけ通りの結果です。
軸3: vowel_binary(normalize+vr調整つき)— biphone + vowel_binary は vr=0.1 で top-1 29.1%・median 68 まで来ますが、連続母音距離のbiphone(32.2%)には3pt及びません。vr=0.5固定では12.1%まで落ちるので、「重みを合わせてようやく数pt差、合わせないと大きく損」なオプションです(最適vrがスイープ下端の0.1なので、真の最適はさらに低い可能性があります)。mono_avg + vowel_binary(調整で選ばれたvrは同じく0.1)は24.1%でした。
まとめると、このタスクの最良は biphone + normalize(vr=0.3、生スケール換算で母音重み≈0.18)で、距離表の選択が支配的でした。文脈情報を含むbiphoneが、含まないその他の条件に比べ、順当に高性能だったということになります。
検証2: 替え歌ベースの押韻語検索
2つ目は公開ベンチマーク soramimi-phonetic-search-dataset です。替え歌(「〇〇で歌ってみた」)から抽出した単語ペアで、クエリの音韻を模倣できる単語を検索するタスクです。韻とリズム(音節数)の一致を重視する、押韻寄りの評価です。指標はRecall@10(150クエリ、候補プール約1.3万語)で、既存のleaderboardではkanasim(vowel_ratio=0.8)が非LLM手法の最良値 0.831 を持っています。
検証1と同じ軸構成で見ます。vowel_ratio の調整を伴う比較では、150クエリを難易度サブセットごとに層化して調整用76件と検証用74件に分割し、調整用で最良のvrを選び、検証用の Recall@10 を報告します(基準線の既存設定も同じ検証用データで評価します)。
軸1: 距離表の種類
まず母音重みを調整しない素の状態(修飾なし・vr=0.5=音響モデルの特徴をそのまま使う場合、全150クエリ)の比較です。
| biphone | mono_avg | mono_hmm | features |
|---|---|---|---|
| 0.789 | 0.825 | 0.712 | 0.759 |
検証1と違い、vr=0.5では mono_avg が最良で biphone を上回ります。ただし後述の通り、このタスクの最適な母音重みはどの距離表でも0.5より高い側にあり、最適vr同士の比較では順位が入れ替わります。
次に、normalize=True で各距離表ごとに最適な vowel_ratio を調整した場合(調整用データで選び、検証用データで報告)です。
| 設定 | 調整で選ばれたvr | 検証Recall@10 |
|---|---|---|
| 基準線: biphone・normalizeなし・vr=0.8(leaderboard設定) | — | 0.832 |
| biphone + normalize | 0.9 | 0.832 |
| features + normalize | 0.8 | 0.823 |
| mono_avg + normalize | 0.6 | 0.801 |
| mono_hmm + normalize | 0.6 | 0.771 |
既存の基準線を上回る設定はありませんでした。biphone + normalize(vr=0.9)が同値で並びますが、これは前述の等価性から予想される通りです。生スケール換算すると vr≈0.82、つまり基準線とほぼ同一の距離関数で、normalizeは精度を上乗せするのではなく最適vrの位置を動かしているだけです。また mono_avg で選ばれた vr=0.6 は、mono_avg の距離表(子音・母音のスケール差が小さい)では生スケール換算で vr≈0.56 に相当し、素の vr=0.5 とほぼ同じバランスです。素の比較で mono_avg が最良だったことと整合します。
なお、この規模のデータ(調整76件・検証74件)でのvr調整・検証には0.01〜0.06程度のノイズが乗ります。features の 0.823 と上位2者との差はその範囲内なので、この表の細かい順位から距離表の優劣を論じるのは避けます。
軸2: symmetric — biphone + normalize ± symmetric を vr=0.5 / 0.8 / 0.9 で比較すると、差は −0.005〜−0.025 と小さく一貫して負でした。押韻検索でも対称化に利点はありません。
軸3: vowel_binary — biphone + vowel_binary + normalize は、調整側では 0.855 と全条件中最高に見えますが、検証側では 0.796 に落ちます(ギャップ約0.06の過学習)。「押韻には母音を0/1にして影響を強めた方が良い」という当初の直感は、公平に測ると支持されませんでした。vowel_ratio=0.8 の連続母音距離が既に「母音重視」であり、母音の段階的な近さ(ア-オはア-イより近い)が識別に効いていて、0/1化はその情報を捨ててしまう、と解釈しています。mono_avg + vowel_binary も 0.757 で、biphoneに及ばずでした。
まとめ
| 用途 | 推奨設定 |
|---|---|
| 押韻・替え歌の語検索 | デフォルト(biphone・非対称)+ vowel_ratio=0.8
|
| 歌唱ASRの採点・マッチング |
normalize=True, vowel_ratio=0.3(生スケール換算で母音重み≈0.18) |
| 素性ベースで解釈可能な距離が欲しい | phoneme_unit="mono", consonant_distance="features" |
新オプションはすべてopt-inで、デフォルト挙動は従来と完全互換です。pip install "kanasim>=0.0.11" で使えます。
本記事の4オプションは v0.0.11 として公開済みですが、デフォルトの切り替えはまだ行っていません。今後のバージョンで、デフォルトを normalize=True に切り替えることを検討しています。子音・母音距離が最初から共通の [0, 1] スケールに揃い、vowel_ratio を「母音重視度」の直感的なつまみとして使えるようにするためです。その際の vowel_ratio の初期値は、押韻検索で実績のある生スケール vr=0.8 と同じ子音・母音バランスになる 0.89 を想定しています。現行デフォルト(正規化なし・vr=0.5、正規化換算で vr≈0.67 相当)からは挙動が変わり、距離の絶対値のスケールも小さくなるため、変更する場合はバージョンを上げて変更点を明記する予定です。
どちらのタスクでも音響モデル由来のbiphone連続距離が最上位で、mono化・素性距離・母音0/1化はいずれも上回れませんでした。文脈情報を加味するbiphoneが順当に強かったと解釈しています。一方で、替え歌作詞支援等の応用でユーザがパラメータを調整しながら多様な結果を眺めたい場合の操作性の観点では、monoなど子音と母音が独立した指標にも意味はあるはずなので、用途に応じて使い分けていきたく思います。
参考
- kanasim
- soramimi-phonetic-search-dataset
- 音響モデルから音素間の距離を求める(yaamaa-memoブログ) — 距離表の元手法
- Kawahara, S. (2007). Half rhymes in Japanese rap lyrics and knowledge of similarity.