英単語の “read” を例に取りましょう。書かれただけでは、どう発音するかはわかりません。“I read the book yesterday” と “I read the book every day” は、同じ五文字を二つの異なる音に使います — 一方は “red” と韻を踏み、もう一方は “reed” と韻を踏みます。綴りしか見ないスクリーンリーダー、音声アシスタント、検索ボックスは、これを正しく扱えません。テキストだけでなく発音について推論する必要があります。
その推論の問題 — 書かれた単語をそれが表す音に変えること — こそが、私たちの音韻論スタックが解決するものです。この記事は、生の表記法から言語固有の発音エンジン、そして音に基づく検索まで、その部品がどう組み合わさっているかの地図です。
いくつかの用語を明確に定義する
全体を通して出てくるいくつかの言葉です。
- 書記素(Grapheme): 文字一つ、あるいは “ch” のような文字の組み合わせといった、書かれた記号。
- 音素(Phoneme): ある言語における区別される音の単位。例えば “cat” の “k” の音。
- IPA(国際音声記号): ある言語の綴りとは独立して、音を正確に書き表すための標準的なアルファベット。“Cat” は IPA で
kætと書かれます。 - G2P(書記素から音素へ): 綴りを音に変換するという一般的な問題。
- 異音(Allophone): 文脈に応じて変わる同じ音素の実現形 — “top” の “t” と “stop” の “t” は英語では同じ音素ですが、わずかに異なって発音されます。
- 音節分割(Syllabification): 単語を音節に分けること。例えば “extraordinário” を
ex-tra-or-di-ná-ri-oに。 - 同綴語(Homograph): 綴りは同じだが意味が異なる二つの単語。異音同綴語(heterophone)は、どちらの意味かによって異なって発音される同綴語です。上記の “read”/“read” のように。
- 形態論(Morphology): 接頭辞、語根、接尾辞、活用といった単語の内部構造。
- 品詞(POS)タグ付け: 文中の各単語を名詞、動詞、形容詞などとラベル付けすること。
核心的な問題
綴りは音の損失のあるエンコーディングです。それを逆転させることを難しくしている三つの要因があります。
- 曖昧性。 同じ文字が、意味、文法、あるいは単なる不規則性に応じて異なる音にマッピングされ得ます(上記の “read”、英語はこれで満ちています)。
- 方言。 同じ言語の同じ単語でも、話者がどこの出身かによって異なって発音されます。ヨーロッパポルトガル語とブラジルポルトガル語は綴りを共有しますが、母音は共有しません。
- カバレッジ。 世界の言語のほとんどには、専門的にキュレーションされた発音辞書がまったく存在しません。単なる参照テーブルだけで動作する G2P システムは、ごく一部の言語でしか動作しないシステムです。
テキスト音声変換、音声認識の学習データ、あるいは音声を意識した検索への本気の取り組みは、この三つすべてに対処しなければなりません。
なぜこのスタックは層になっているのか
このスタックは、問題を互いに知る必要のない層に分割します。
- 表記法 — 音声アルファベットと文字体系の間の変換。これは特定の言語の音韻論とは何の関係もありません。記号の翻訳です。
- 音韻論 — ある言語の音体系の仕様を使って、綴りを IPA にマッピングすること。
- 言語固有の例外処理 — 一般的なエンジンが綴りの規則だけからは推測できない、不規則な単語、方言の癖、同綴語、形態論的構造。
これらを分離しておくことは偶然ではなく設計上の決定であり、直接的な見返りがあります。新しい言語を追加するということは、新しいプログラムではなく仕様(その言語の音体系を記述するデータ)を書くことを意味します。仕様を消費するエンジン、ラティス検索、トークナイザー、距離指標 — そのどれも書き直されません。その下にある表記法の層は、音韻論エンジンが一度も聞いたことのない言語も含め、すべての言語が共有します。
表記法の層: scriptconv
scriptconv は、音声表記法と文字体系処理のための依存関係のないコアです。ISO-15924 文字体系検出、ARPABET・X-SAMPA・Lexique・Kirshenbaum・Cotovía・RFE 表記法との IPA 間の変換、アラビア語のための Buckwalter 音訳、字母への ハングル分解、かなの処理。これらのどれも、単語がどの言語に属するかを知る必要がありません — IPA の音素文字列は、元の言語に関係なく同じ方法で ARPABET に変換されます。
>>> import scriptconv as s
>>> s.ipa_to_arpa("kæt")
'K AE T'
>>> s.ipa_to_xsampa("kæt")
'k{t'
この層より上のすべての層は、表記法の変換がすでに解決済みであると仮定できます。
エンジン: orthography2ipa
orthography2ipa は言語間エンジンです。言語仕様 — その言語の書記素から音素への規則の宣言的な記述 — とテキストの断片を受け取り、IPA を生成します。この記事を書いている時点で、820 の言語をカバーする仕様を提供しています(インストールされたパッケージの available_codes() はその長さのリストを返します。仕様は時間とともに追加されるため、正確な数値は変動するものと考えてください)。
>>> import orthography2ipa as o
>>> len(o.available_codes())
820
エンジン自体には言語固有のコードは組み込まれていません。新しい言語は、他のすべての仕様と同じスキーマに対して検証される新しい仕様ファイルにすぎません。
ラティス: 一つの推測ではなく、順位付けされた候補群
上記の曖昧性の問題を考えると、単語ごとに単一の出力に決め打ちすることはしばしば間違いです。orthography2ipa は代わりにラティス — 順位付けされた候補発音の集合 — を生成し、エンジン自体には存在しない文脈(意味、品詞、辞書エントリ)を使って上位の層がそれを絞り込めるようにします。
もう一度 “read” を見てみましょう。
>>> from orthography2ipa import G2P
>>> g = G2P("en")
>>> g.transcribe("read")
'ɹiːd'
>>> g.candidates("read")
[IPAPath('ɹiːd', score=0.0), IPAPath('ɹɛd', score=1.0)]
それ以上の文脈がなければ、エンジンは最良の推測(現在形、より低いコスト)を返しますが、代替案(過去形)もそのコストとともにラティスに保持します。文が過去形であることを知っている下流のコンポーネントは、一番目ではなく二番目の候補を選べます。これは、(後述の)bifonia がポルトガル語の異音同綴語に対してより大きな規模で使っているのと同じ発想です。汎用ラティスが候補を提供し、より狭く、より情報を持つ層がその中から選びます。
方言は一級市民です
同じ言語の二人の話者が同じ文を異なって発音することがあり、「ポルトガル語」を一つの固定された音体系として扱う音韻論スタックは、一つを除くすべての方言を間違えることになります。orthography2ipa は方言の扱いを直接公開しています — インストールされたパッケージの available_profiles() は lisbon、porto、estremenho、galician などの方言および lect プロファイルを一覧します — そして、その上に構築されたポルトガル語フロントエンドである tugaphone は、同じ文をルソフォニア諸変種にわたって音素化します。以下は、対応する五つの方言すべてを通した一つの文です。
| 方言 | 出力 |
|---|---|
| pt-PT(ポルトガル) | ˈbõ ˈdiɐ ˈkomu eˈʃta vɔˈse |
| pt-BR(ブラジル) | ˈbõ ˈdʒiɐ ˈkɔ̃mʊ eˈsta voˈse |
| pt-AO(アンゴラ) | ˈbõ ˈdiɐ ˈkomʊ eˈsta vɔˈse |
| pt-MZ(モザンビーク) | ˈbõ ˈdiɐ ˈkomu eˈsta vɔˈse |
| pt-TL(東ティモール) | ˈbõ ˈdiə ˈkoɔmʊ eˈsta vɔˈse |
(“Bom dia, como está você?” — 「おはようございます、お元気ですか?」)子音の骨格は五つの方言すべてで見分けがつくままですが、二つのよく知られた標識がすぐにこれらを区別します。“dia” では、ブラジルポルトガル語は i の前の d を英語の “jam” の最初の音である dʒ に変えますが、他の方言は単純な d を保ちます。“está” では、ヨーロッパポルトガル語は音節末の s を “shoe” の “sh” の音である ʃ として発音しますが、他のすべての変種は s を保ちます。一つの方言の規則から作られた発音辞書は、他のすべての方言の聴取者に対してこの両方を間違えます。
euskaphone は、別のエンジンではなく orthography2ipa のラティスの上に直接構築されており、バスク語の方言について同じことを行います。
>>> from euskaphone import EuskaPhonemizer
>>> EuskaPhonemizer().phonemize_sentence("Kaixo, zer moduz zaude?")
'kai̯ʃo s̻er modus̻ s̻au̯de'
言語固有のフロントエンド
共有エンジンの上には、一般的な仕様がカバーできないもの — 不規則な単語、キュレーションされた辞書、サンディ(語境界での音変化)、方言固有の上書き — を加えるフロントエンドがあります。
-
tugaphone — ポルトガル語、pt-PT・pt-BR・pt-AO・pt-MZ・pt-TL にわたり、キュレーションされた辞書とルールベースのフォールバックを組み合わせます(上記参照)。
-
euskaphone — バスク語、方言を考慮し、同じラティスの上に構築されています(上記参照)。
-
mwl_phonemizer — ポルトガルのミランダ地方のアストゥルレオン語であるミランダ語で、語をまたぐサンディ、異音、アクセントを含みます。
>>> from mwl_phonemizer import phonemize >>> phonemize("Falo la lhéngua mirandesa.") 'ˈfalu lɐ ˈʎɛŋɡwa miɾɐˈndez̺ɐ.' -
g2p_barranquenho — ポルトガル・スペイン国境のバランコス地域のイベロ・ロマンス系接触言語であるバランケーニョ語のための初のオープンな G2P です。その規則が自治体自身の正書法規約からどう導出されたかは、バランケーニョ語で初となる音素変換器のご紹介 をご覧ください。
-
arbtok — アラビア語、orthography2ipa のラティスの上に構築され、方言を考慮した分音記号の復元を加え、現代標準アラビア語、古典アラビア語、そしていくつかの地域変種をカバーします。アラビア文字は通常、音素化器が必要とする短母音記号を省略するため、arbtok の主な仕事は、共有エンジンに結果を渡す前にそれを復元することです。これはアラビア語のネイティブ話者ではない人が保守しているため、完成した、ネイティブによってレビューされた参照物としてではなく、活発に開発中のものとして扱ってください — 有用ですが、ユーザー向けの何かに出荷する前にネイティブ話者に対して出力を再確認すべき箇所です。
これらのフロントエンドのそれぞれは、その下にある同じ共有ラティスエンジンと同じ共有表記法層の上に乗る、言語固有ロジックの薄い層です。どれも IPA 変換やラティス検索を再実装していません。
ポルトガル語を支えるツール群
ポルトガル語は最も深いスタックを持っています。ポルトガル語の発音は綴りの規則以上のもの — 音節構造、品詞、時には単なる意味 — に依存するからです。
-
silabificador は手作りの規則を使って単語を音節に分けます。
>>> from silabificador import syllabify >>> syllabify("extraordinário") ['ex', 'tra', 'or', 'di', 'ná', 'ri', 'o'] -
tugalex は tugaphone の背後にある辞書です。実際の単語についての IPA 転写、音節データ、正書法規則で、一般的で不規則な語彙を毎回綴りから再導出しなくて済むようにします。
-
tugatagger は複数の品詞タグ付けバックエンド(spaCy、Stanza、Brill 式タガー、依存関係のないヒューリスティックなフォールバック)を一つのインターフェースの背後にラップし、他のツールが特定のバックエンドに縛られることなく「この単語の品詞は何か」を尋ねられるようにします。
-
tugamorph はルールベースの形態素解析器です。Python 標準ライブラリのみを使い、単語を接頭辞、語根、接尾辞、活用、接語に分割し、任意で silabificador と tugatagger によって精度を高めます。
-
bifonia はヨーロッパポルトガル語の異音同綴語 — “sede”(渇き、
ˈsedɨ、対 本部、ˈsɛdɨ)のように、正しい発音が文法ではなく意味に依存する単語 — を解消します。それがどう作られ評価されたかは、正しく発音する: TTS のためのポルトガル語異音同綴語の解消 をご覧ください。これは上記のラティスの発想の背後にある具体例です。orthography2ipa は “sede” の両方の候補読みを提供できますが、bifonia のような意味を知る層だけがその中から選べます。
silabificador と tugaphone が日々どう連携しているかについては、ポルトガル語のための古典的NLP: 音節分割と書記素から音素への変換 を、そしてこのすべての下にあるより広いエンジンについては 820の言語に対応するグラフェムからIPAへの変換 をご覧ください。
音に基づく検索: phonematcher
上記のすべてはテキストを音に変えます。phonematcher は音の表現そのものを扱います。IPA 記号間の音声的距離を計算し、綴りではなく単語がどう聞こえるかに基づいて単語リストに対するファジー検索を行います。
>>> from phonematcher.distance import phonetic_distance
>>> phonetic_distance('b', 'p') # voiced vs. voiceless bilabial stop — very similar
0.043478260869565216
>>> phonetic_distance('p', 'k') # bilabial vs. velar stop — less similar
0.34782608695652173
>>> phonetic_distance('a', 'k') # vowel vs. consonant — maximally different
1.0
その距離指標は二つの具体的な状況で役立ちます。正確な綴りではなく音で単語や名前のカタログを検索すること(誤字に寛容な音声インターフェースや、文字体系をまたぐ借用語のマッチングに有用です)、そして関連する二つの lect が音韻論的にどれだけ近いかを比較すること — 上記の方言表が目視で行っているのと同じ種類の比較を、目分量ではなく計算で行います。phonematcher は PyPI にはありません。ソースからインストールします(GitHub のチェックアウトに対して pip install -e .、加えて rapidfuzz)。
正直な限界
820の言語仕様にわたるカバレッジは、構造上、一様ではありません。確立された音韻論の文献と辞書を持つ言語は、主に一般的な正書法の慣習から推測された薄い仕様しか持たない言語よりも良い出力を出します。品質は、キュレーションされた辞書が存在する場所で一貫して最も良く、tugalex に支えられたポルトガル語がこのスタックの中で最も強い事例です。辞書なしで純粋に仕様の規則だけに依存する言語は、不規則な語彙や借用語を誤って処理します。
いくつかの構成要素は、明示的に未完成の、ネイティブによってレビューされていない参照物です。arbtok はアラビア語のネイティブ話者ではない人が保守しているため、ユーザー向けの何かに使う前にネイティブの判断に対して確認すべきです。薄い仕様の上に構築されたフロントエンドは、その薄さをそのまま受け継ぎます — フロントエンドは、その下にある仕様と辞書と同じだけしか良くありません。
あなたの言語に音声ツールが何もない場合、これが重要な理由
世界の言語のほとんどには、商用の TTS 音声も、商用の STT モデルも、専門的に保守された発音辞書もありません。上記の層化された設計は、そのギャップを埋めるために音韻論エンジンをゼロから作る必要はないことを意味します。対象言語の音体系の仕様と、可能であればその不規則な単語の辞書を書くだけでよいのです。ラティスエンジン、表記法の変換、検索ツールはすでにそこにあります。あなたの言語、方言、あるいは製品にまだ存在しない発音サポートが必要であれば、それが私たちが引き受ける種類の仕事です — 私たちのサービス をご覧いただくか、お問い合わせください。