pydominoで日本語音声データの強制アライメントをやってみた

  • このエントリーをはてなブックマークに追加

 日本語のテキストと音声を音素レベルで対応をとる強制アライメントツールpydominoを使ってみました。pydominoのインストールから使い方、音素対応表の紹介を行っています。また、実際に母音や子音を含む音声データを波形やスペクトログラムで可視化しながら結果の検証を行いました。

はじめに

音素と強制アライメントについて

 音素Phoname)とは、言語の音声を構成する基本単位であり、単語の意味を区別する最小単位です。例えば「かな(魚)」と「かな(高菜)」は最初の文字の違いが意味の違いを生んでいます。この「さ」と「た」はそれぞれ異なる音素です。英語でも「Right」と「Light」は似ていますが、最初の音素「R」と「L」の違いで意味が異なります。つまり音素とは、単なる音の違いというよりも意味を区別できる音の違い、と捉えた方が良いでしょう。

 強制アライメントForced Alignment)とは、音声データの中で、音素とその書き起こしテキストを時間軸上で正確に対応付ける処理のことです。

Advertisements

 アライメントの例を簡単に説明しましょう。例えば次の図のように、「あいうえお」という言葉を音素毎に区切って発話した場合、無音区間と音素の有音区間が明確になっています。このような場合は信号処理のアルゴリズムだけを使って(無音区間を削除して有音区間だけを抽出)アライメントが可能です。

アライメントが簡単な例

 しかし、実際の発話で音素毎に区切って発話されるなんてことはなく、リアルワールドデータは次のような形になります。これだとどこで音素が区切られているかを信号処理のアルゴリズムだけで特定するのは困難(というか無理?)です。

アライメントが難しい時の例

 このような複雑なデータの場合、従来は人間が音を聞きながら手動でラベリングしていました。◯秒〜◯秒は◯の音素というように、明確に音素とデータの対応をとることをハードアライメントHard Alignment)と呼びます。精度の良いデータのためとはいえ、ハードアライメントを手動で行うのはなかなかに骨の折れる作業です…。

pydominoとは

 pydominoDwango Media Villageで開発された日本語音素アライメントツールです。Pythonやコマンドラインツールから使うことができ、MITライセンスのためいくつかの条件(著作権表示とライセンス条文の記載等)を遵守すれば商用利用等幅広く使うことができます。詳細は以下のリンクをご確認ください。
・GitHub:https://github.com/DwangoMediaVillage/pydomino
・DWANGO MEDIA VILLAGE公式:https://dmv.nico/ja/articles/domino_phoneme_transition/

 pydominoを使えば先ほどの区切り発話と連続発話のデータ両方で音素をハードアライメントすることができます(スゴイ!)。この記事ではGitHubのコードや公式の記事を参考にしながら、pydominoの使い方を学びます。

pydominoによる強制アライメント結果例

 これから紹介するpydominoは2025年3月4日に公開された公式記事の内容です。それ以前の音素の弁別的素性に基づいたアライメントツールの記事にも参考になる情報が沢山あるのでご確認ください。

強制アライメントができると何ができる?

音声認識モデルの訓練データ作成

 音声認識システムを構築するには機械学習を用いるのが既に一般的です。機械学習には学習データが必要ですが、どのタイミングで何の音が話されているかというアライメント情報はモデルの精度向上に大いに役立ちます。学習データを自動で収集できるシステムを作ることができればスケール則でどんどん賢くなる機械学習モデルの大きな武器になるでしょう。

リップシンク

 アニメーションや映像制作の分野ではキャラクターの口の動きとセリフを同期させるリップシンクと呼ばれる技術があります。従来は主に手動でこの作業を行うしかありませんでしたが、正確な強制アライメント技術の登場はリップシンクの自動化に貢献すると考えられます。

音声合成(TTS)

 音声合成(TTS:Text-to-Speech)はテキスト情報をコンピューターが読み取り、それを人間が話すような自然な音声に変換する技術のことです。この技術は色々な手法がありますが、音声波形を生成する段階で波形接続型Concatenative)と呼ばれる人間の声を細かく分割したデータを活用する手法があります。音素毎に細かく分割されたデータの作成に強制アライメントされたデータが有効に活用されるでしょう。

様々な活用方法がある強制アライメントを早速Pythonで使ってみよう!

動作環境

 この記事では以下の環境でコードの動作を確認しました。pydominoはGitHubリポジトリから pip installするので、余計なライブラリ依存関係のエラーを避けるために新規仮想環境を立ち上げた方が良いと思います。venvによる仮想環境の構築は「M3 Macでvenv/VSCodeによるPython環境を構築するときの備忘録」をご覧ください。

Mac OS macOS Sonoma 14.5
チップ Apple M3
CPU 1.4[GHz]
メモリ 16[GB]
Python Python 3.12.3
pydomino 1.1.0
numpy 2.1.3
librosa 0.11.0
matplotlib 3.10.1
scipy 1.15.2

pydominoのインストール

 pydominoはGitHubのリポジトリから cloneしてインストールします。

母音検証】pydominoで強制アライメントを行うコード

 まずは一番簡単な母音だけの音声データでpydominoの使い方を確かめてみましょう。

サンプルのwavファイル

 コードの検証には音声品質の良い音読さんによる音声ファイルを使用しました。こちらの「あいうえお」の音声ファイルを使います。

サンプルコード1:強制アライメントの結果をタブ区切りで出力する

 次のPythonコードはwavファイルに対して強制アライメントを実施し、結果の情報を .tsv形式(タブ区切り)テキストファイルに出力します。

 実行すると alignment-result.tsvというファイルが作成されます。ここで、各行の第一要素と第二要素は秒数を表し、音素の範囲を示しています。第三要素はその範囲の音素です。

サンプルコード2:強制アライメント結果をグラフで示す

 先ほどのコードは強制アライメントの結果をテキスト情報のみに出力していたので、今度は実際の波形を使って見えるようにしてみましょう。

ここがポイント!

phoneme_sequence = "pau a i u e o pau"で事前に音素を指定します。pydominoでは以下表(引用:https://github.com/DwangoMediaVillage/pydominoに示す音素を選択します。発話内容は「あいうえお」ですが、前後に「pau」という無音区間を示す音素を入れるのが決まりです。
音素表

 子音の指定方法は記事の後半に示しますが、pydominoでは指定された音素と音素の間の遷移を検出します。そのため音素の遷移が見つからない時は RuntimeError: Transition from a to i is not defined.というエラーが出るので注意が必要です。

 下図はコードの実行結果です。「あいうえお」という発話にpydominoで得られたアライメント情報(時間範囲)を青点線で示したものです。

波形に強制アライメント結果を表示した結果の画像

カーソルがあると間違っていないかどうかの確認がしやすいですね!

サンプルコード3:音素毎のwavファイルを保存する

 波形にカーソルを表示させただけではなく、実際に音素を耳で聴いてみましょう。次のコードは先ほどまでの強制アライメント結果を使って音声データ全体を個別のwavファイルに保存するものです。

 このコードを実行すると、プログラム実行フォルダの中に各音素セグメント毎のwavファイルが作成されます。pauの範囲は意味を持たないので、pau以外の音素を保存しています。

保存されたwavファイル

これで自分の耳で音素の音声を聴くことができます!

サンプルコード4:スペクトログラムに音素ラベルを表示する

 音声データは生波形よりもスペクトログラムで見た方が情報が整理されます。「Pythonで音のSTFT計算を自作!スペクトログラム表示する方法」で作成した自家製スペクトログラムコードを使ってpydominoの音素ラベルをプロットできるようにしてみましょう。

 以下の図が実行結果です。スペクトログラム上に音素のラベルが表示されました。こちらの方が声帯振動やフォルマントの様子を確認しやすいですね。

子音検証】pydominoで強制アライメントを行う時の音素列

 母音は簡単でしたが、正直素人には音素列に何を指定して良いかわかりません。pydominoの音素ラベルは上記表に示す39種類ですが、概ねヘボン式ローマ字のように音と対応づけられているようです[1]。この節では実際に音声に対して音素列を定義して、効果を確かめてみることをやってみましょう。

「こんにちは」の音素列

 以下の音読さん音声をサンプルに使います。

 「こんにちは」は次の音素列で表現されます。

 matplotlibで確認したりwav音声を聴いて確認したりすると、以下の結果は妥当のようです。kやchといった子音は母音の前で微かに音が鳴っているレベルのように見えますね。「ん」は撥音(はつおん)と呼ばれる種類の音素で[2]、pydominoでは大文字のNで表現するとのことです[1]

 スペクトログラムで見ると次の通り。音屋からするとこちらの方が見やすいですね。kやchは声帯振動が目立っていませんが、その他の音素は基本周波数とその高調波からなる声帯振動がよくわかります。

「こんにちは」のスペクトログラム

「かきくけこ」の音素列

 先ほどと同様に、音読さんで作成した「かきくけこ」もローマ字の要領で以下の音素列を指定します。

 スペクトログラムを見るとk iのkやk oのkはややフライング気味なような気がしますが、分割されたwavファイルを聴くと確かに正確に判定できているようです。発話のタイミングによっては間にpauを入れるべき部分があるのかも知れませんが、pauを入れなくても遷移を計算できるレベルであったからこうなるのでしょうか?この辺は使いながら確認していく必要がありそうですね。

50音の音素表

 50音と音素の対応表を作成してみました。間違いがあるかも知れませんが、まずはこの表を目安に音素ラベルを作ればよさそうです。

あ段 い段 う段 え段 お段
あ行 a i u e o
か行 k a k i k u k e k o
さ行 s a sh i s u s e s o
た行 t a ch i ts u t e t o
な行 n a n i n u n e n o
は行 h a h i f u h e h o
ま行 m a m i m u m e m o
や行 y a (-) y u (-) y o
ら行 r a r i r u r e r o
わ行 w a (-) (-) (-) w o
が行 g a g i g u g e g o
ざ行 z a j i z u z e z o
だ行 d a j i d u d e d o
ば行 b a b i b u b e b o
ぱ行 p a p i p u p e p o
拗音 ky a, gy a,
sh a, j a,
ch a, ny a,
hy a, by a, py a,
my a, ry a
(-) ky u, gy u,
sh u, j u,
ch u, ny u,
hy u, by u, py u,
my u, ry u
(-) ky o, gy o,
sh o, j o,
ch o, ny o,
hy o, by o, py o,
my o, ry o
特殊音 ん:N っ:cl 無音:pau 無声い:I 無声う:U ヴ:v

 明確に区切って発話する場合、長音の場合…は今回試していませんが、試したらここに追記しようと思います。

まとめ

 ここでは基礎知識として強制アライメントやハードアライメント、音素といった用語を説明し、強制アライメントの活用先とpydominoを使うメリットをいくつか紹介しました。
 また、pydominoのインストール方法とサンプルコードを紹介し、母音と子音を含む実際の音声に対して処理を適用してみました。結果、意図した通りの音素分割ができることを確認しました。これらの音素分割を活用したソリューションは色々思いつくので今後試して有用なものができたら差し支えない範囲で公開してみたいと思います。

参考文献

[1]:Shun Ueda, 音素の弁別的素性に基づいたアラインメントツール pydomino
[2]:竹内京子, 稲田朋野晃, 言語聴覚療法学テキスト 音響・音声学, (2023), 第1版第1刷, pp28-29

自動的に強制アライメントを行うpydominoを使ってみました!
Xでも関連情報をつぶやいているので、wat(@watlablog)のフォローお待ちしています!

SNSでもご購読できます。

コメントを残す

*