『Phase reconstruction based on recurrent phase unwrapping with deep neural networks』に基づく位相復元手法をPyTorchで実装した

はじめに

Masuyama氏らによる位相復元手法 "Phase reconstruction based on recurrent phase unwrapping with deep neural networks"が2020年に提案されている.

arxiv.org

本手法は,まずDNNで位相の微分(時間方向・周波数方向)を推定し,次に推定した微分に基づいて位相を再帰的に求める(積分する,アンラッピング)という2段階の処理からなる.位相が波形のずれに敏感という問題を回避しつつ,従来のDNNによる位相の直接推定(von Mises DNN)よりも高い精度で位相を推定することができる,というわけである.「位相を再帰的に求める」 recurrent phase unwrapping を指して,以降は本手法をRPUと呼ぶ.

ちなみに音声サンプルは以下で試聴できる.

sites.google.com

本記事はRPUに基づく位相復元をPyTorchで実装し,再現実験に成功したのでそれを報告するものである.

実装

以下のリポジトリに置いた.Enjoy!

github.com

前回記事のvon Mises DNNと同様に,基本的な構造は全結合層からなるDNNである.位相の時間微分である瞬時周波数,周波数微分である群遅延を推定するDNNを別々に用意する.いずれも活性化関数はGeGLUである.RPUの論文では活性化関数にWaveNetと同様のgated activationを使用したと書いてあるが,GeGLUはずっと収束が早いので,こちらを採用した.

ファイル名 機能
preprocess.py 各種の前処理を実施するスクリプト
dataset.py データローダの構築を実施するスクリプト
model.py ネットワークを定義
factory.py オプティマイザ,スケジューラ,loss関数を定義
training.py モデルの訓練を実施するスクリプト
evaluate_scores.py 音質の客観評価指標を計算するスクリプト

なおRPUのアルゴリズムはevaluate_scores.py内のcompute_rpu関数内で実装している.

実験

JSUTコーパスのBASIC5000を訓練データに,ONOMATOPE300をテストデータに用いた.客観評価指標にSTOI, (wideband) PESQ,LSC (log-spectral convergence)を採用した.

音声の分析条件

計算機環境を示す。

計算機環境 バージョンなど
OS Ubuntu 22.04
CPU Intel i9-9900K
GPU RTX2070
Python 3.10.12
PyTorch 2.2

訓練の基本的な設定は以下の通りである。

項目 設定
ミニバッチサイズ 256
エポック数 500
オプティマイザ RAdam
学習率 0.001から開始し,100エポックごとに0.8倍する
勾配クリッピングしきい値 10.0

音響特徴量の設定は以下の通りである。

項目 設定
標本化周波数 16000Hz
音響特徴量 対数振幅スペクトルおよび位相スペクトル
分析窓 ハン窓
FFTの窓長 512
フレーム長 512
フレームシフト 128

実験結果

図1,図2,図3に各評価指標の箱ひげ図を示す.図中,"Amp"は位相スペクトルを定数値0と置いたもの,"vM"はvon Mises分布による位相復元手法を示す.また図1はDNNの出力直後の位相スペクトルを復元に利用し,図2および図3はGriffin-LimアルゴリズムGLA)による事後処理的な位相補正を行ったときの結果である.それぞれGLAの繰り返し回数は10および100である.

図1:客観評価指標の箱ひげ図(GLA なし)
図2:客観評価指標の箱ひげ図(+GLA 10 iterations)
図3:客観評価指標の箱ひげ図(+GLA 100 iterations)

図1より,RPUによる位相復元はvMを大きく上回る音質を実現していることが確認できた.GLAによる位相復元を重ねても,RPUが客観評価指標で一番良いものとなっている.スコアの分布を含め,これらの結果はRPUの論文とほぼ一致している.

以下,それぞれの復元音声サンプルを載せておく.GLAなしの”RPU”の音質の良さが際立っている.

  • サンプル1

オリジナルの音声:

復元音声:

GLA Amp vM RPU
0
10
100


  • サンプル2

オリジナルの音声:

復元音声:

GLA Amp vM RPU
0
10
100

おわりに

本記事ではRPUに基づく位相復元技術を実装した.評価実験により,RPUはvon Mises DNNから客観評価指標を大きく改善できることが確かめられた.RPUの後続となる位相復元手法は他にも多くあるので,色々と実装してみたい.

von Mises分布DNNに基づく位相復元手法をPyTorchで実装した

はじめに

音声の位相復元という研究トピックが存在している.分野に不慣れな人はまず,矢田部先生の解説記事を読むことをおすすめする.

www.jstage.jst.go.jp

音声の位相復元をDNNで行う流れがあり,日本の研究者も大いに貢献している.

speakerdeck.com

表題のvon Mises 分布DNNに基づく位相復元手法は,慶應義塾大学の高道先生が東京大学に在籍していたころの仕事である.

今回はこの手法をPyTorchで実装し,位相復元の実験をしてみたということである.

実装

以下のリポジトリに置いた.Enjoy!

github.com

基本的な構造は全結合層からなるDNNであり,活性化関数はGLUである.オリジナルのGLUは線形変換に対してgateの役割を果たすシグモイド関数を乗じているが,今回はシグモイド関数の代わりにGELU (Gaussian Error Linear Units) を用いることにした.手元の実験では収束がシグモイド関数よりも早くなる(=損失が早く減少する)ことを確認している.なおオリジナルの論文では言及されていなかったLayerNormも導入している.

ファイル名 機能
preprocess.py 各種の前処理を実施するスクリプト
dataset.py データローダの構築を実施するスクリプト
model.py ネットワークを定義
factory.py オプティマイザ,スケジューラ,loss関数を定義
training.py モデルの訓練を実施するスクリプト
evaluate_scores.py 音質の客観評価指標を計算するスクリプト

実験

JSUTコーパスのBASIC5000を訓練データに,ONOMATOPE300をテストデータに用いた.客観評価指標にSTOI, (wideband) PESQ,LSC (log-spectral convergence)を採用した.

特徴抽出およびミニバッチ構築について

少々込み入っているので説明しておく.

BASIC5000について,東京大学猿渡研究室の公式リポジトリにおいてフルコンテキストラベルが公開されている.

github.com

まず上記フルコンテキストラベルに基づいて,BASIC5000に含まれている各音声ファイルの無音区間(発話冒頭および発話末尾)を削除する. 得られた音声ファイルをサンプリング周波数16kHzにリサンプリングしたうえで,音響特徴量を抽出する.音声の分析条件は後述する. 今回は位相復元ということで,DNNの入力は対数振幅スペクトル,出力は位相スペクトルであり,これらが抽出対象である. 抽出済の特徴量は一旦ファイルに保存しておく(ファイルは発話単位).

無音区間除去後のBASIC5000の音声データは,最小時間(duration)が約0.9秒である.その特徴量のフレーム数(約110フレーム)をもって時間軸方向に固定長のミニバッチを構築する. 一方で0.9秒を超えて3秒や4秒近くになる音声(発話)データも数多く存在する.したがってそのような音声データについて,特徴量抽出前に一様に約0.9秒単位で分割してしまうのは一つの手なのだが,今回は事前の分割はしなかった.その代わり,ミニバッチ構築時には発話単位の特徴量をロードし,その開始フレーム位置をランダムに決定する.フレーム終端はそこから定数フレーム(約110フレーム)だけ後ろの位置で決まる.ミニバッチをこのように構築することで,訓練時のGPUメモリ使用量を抑えることができ,浮いた分のメモリをミニバッチサイズに当てることができる.またフレーム数が固定長となるため,lossを取る際にマスクが不要になりモデル訓練のコードが幾分すっきりする.ミニバッチ構築時にサンプル単位でランダムに音声の小区間を決定したのちに特徴抽出を行う方法も考えられたが,ミニバッチ構築の度に特徴量を抽出するのは訓練時間を多く消費するため,採用を見送った.そのほか,ミニバッチサイズを可変にすることも不可能ではないが,実装をシンプルにすることを優先した.

上記,preprocess.pyが特徴量抽出であり,dataset.pyがミニバッチ構築の処理をしているので参考にしてほしい.

ちなみに当該フレームに前後2フレームを加えた5フレーム分をまとめて入力特徴量を構築する.その特徴量構築にはPyTorchのunfold関数が便利に使える.

音声の分析条件

計算機環境を示す。

計算機環境 バージョンなど
OS Ubuntu 22.04
CPU Intel i9-9900K
GPU RTX2070
Python 3.10.12
PyTorch 2.2

訓練の基本的な設定は以下の通りである。

項目 設定
ミニバッチサイズ 256
エポック数 500
オプティマイザ RAdam
学習率 0.001から開始し,100エポックごとに0.8倍する
勾配クリッピングしきい値 10.0
群遅延ロスの重み 0.1

音響特徴量の設定は以下の通りである。

項目 設定
標本化周波数 16000Hz
音響特徴量 対数振幅スペクトルおよび位相スペクトル
分析窓 ハン窓
FFTの窓長 512
フレーム長 512
フレームシフト 128

なお特徴抽出に用いたライブラリはscipyのShortTimeFFTである.以前書いた記事は本記事の布石であった.

tam5917.hatenablog.com

実験結果

図1,図2,図3に各評価指標の箱ひげ図を示す.図中,"Amp"は位相スペクトルを定数値0と置いたもの,"Rnd"は位相スペクトルを$-\pi$から$\pi$の乱数としたもの,"vM"はvon Mises分布による位相復元手法を示す.また図1はDNNの出力直後の位相スペクトルを復元に利用し,図2および図3はGriffin-LimアルゴリズムGLA)による事後処理的な位相補正を行ったときの結果である.それぞれGLAの繰り返し回数は10および100である.

図1:客観評価指標の箱ひげ図(GLA なし)
図2:客観評価指標の箱ひげ図(+GLA 10 iterations)
図3:客観評価指標の箱ひげ図(+GLA 100 iterations)

図1より,von Mises分布DNNによる位相復元のスコアはいずれも優れたものになっており,先行研究で示された有効性がここでも確認できた.GLAによる位相復元を重ねると,客観評価指標のうえでは位相の初期化手法の違いが少なくなっているようである.GLA 100回後の"Amp"(zero-phase)のLSCが一番良い値になっているのは興味深い.

以下,それぞれの復元音声サンプルを載せておく."vM"の生成音声(GLAなし)に”ビリビリ”としたノイズがかすかに乗っているが,これはShortTimeFFTのistftによる影響もあるだろうか.

  • サンプル1

オリジナルの音声:

復元音声:

GLA Amp Rnd vM
0
10
100


  • サンプル2

オリジナルの音声:

復元音声:

GLA Amp Rnd vM
0
10
100

おわりに

本記事ではvon Mises分布DNNに基づく位相復元技術を実装した.簡単な評価実験により,件の手法は客観評価指標を改善できることが確かめられた(少なくともGLAなしのとき).位相復元手法は他にも多くあるので,色々と実装してみたい.

追記

Recurrent phase unwrappingに基づく位相復元手法を実装したのは以下の記事にて.

tam5917.hatenablog.com

PyTorch 版 Gated Linear Unit (GLU) のラッパー

はじめに

PyTorchにもGated Linear Unit (GLU)は用意されているが,アフィン変換などの部分はGLUモジュールの外で書かないといけない."Linear" は一体どこへやら.

pytorch.org

なのでラッパーを書いたということ.

ソースコード

ここに置いた.畳み込みはConv1dのみ.もはや"Linear"ではない.おまけで"GatedConv1d"クラスも作っておいた.

gist.github.com

scipyの新しいShortTimeFFTを使って振幅スペクトルと位相スペクトルを描画した

はじめに

Python短時間フーリエ変換(STFT)を計算するためのツール(ライブラリ)の一つにscipyがある. scipyでSTFTを計算するための関数がstftであったが,最新版(v1.12.0)ではlegacyに位置づけられている.

scipy.signal.stft — SciPy v1.12.0 Manual

その代わりに ”ShortTimeFFT” クラスが新設され,stftはこのクラスのいちメソッドになった.

docs.scipy.org

本記事はこの新しいstftを使ってみて実行結果を眺めてみよう,という主旨のもと,特に位相スペクトルに注目する.

新しいクラスと注目のパラメータ phase_shift

ここでShortTimeFFT クラスのパラメータを見てみよう.

パラメータ 説明
win 分析窓(numpy 配列)
hop ホップ長(フレームシフト長)
fft_mode 両側FFTや片側FFTなどを指定
mfft FFT
dual_win 双対窓
scale_to STFT結果のスケーリングを指定
phase_shift 線形位相シフトの量

本記事では最後のphase_shiftが重要である. このパラメータを指定することで,STFT時の位相スペクトルに線形位相成分が付加される.デフォルト値は0,つまり線形位相成分を付加しない.Noneを指定すると,-mfft//2に比例した線形位相成分が付加される.

docs.scipy.org

このphase_shift,初見では「一体何だこれは?」だろう.

細かい理論はすっ飛ばして,このパラメータの指定いかんで位相スペクトルがどのように変化するかを見ていこう.

スペクトルの描画

JSUTコーパスに含まれる onomatopee300 から 001.wavを選び,そのSTFTを計算して振幅スペクトルと位相スペクトルを描画する. 比較のため,旧stftでSTFTを計算した結果も示す. 以下,図1から図3まで振幅スペクトル(各図上段)と位相スペクトル(各図下段)を描画した結果を示している.

図1:旧stftを使ったときの振幅スペクトルと位相スペクトル

図2:ShortTimeFFTを使ったときの振幅スペクトルと位相スペクトル(phase_shift=0)

図3:ShortTimeFFTを使ったときの振幅スペクトルと位相スペクトル(phase_shift=None)

振幅スペクトルはどれも同じに見えるが,図2の位相スペクトルだけ見かけが大きく異なっていることが分かるだろう. 図1(旧stft)の位相スペクトルと図3(新stft)の位相スペクトルは,「何だかとても見づらい(構造が把握しづらい)」が,見かけは似ている.

描画に使ったコードは以下に置いた.

plot_amp_phase_spec.py · GitHub

仕掛け

STFTに伴って線形位相成分が付与される事情は矢田部先生の解説記事を読むのがよい(5.2節).

www.jstage.jst.go.jp

線形位相成分の議論は同じく矢田部先生よる以下の記事にも詳しい.

www.jstage.jst.go.jp

要するに,STFTでは分析窓の影響で音声本来の位相スペクトルに加えて窓由来の線形位相成分が乗ってしまう.ゆえに図1や図3のような位相スペクトルの見かけになっている. 新stftでphase_shift=0とすると,その線形位相成分が除去された状態の位相スペクトルが手に入る.phase_shift=Noneとすると,旧stftと同じような線形位相成分を乗せる.

線形位相成分が除去された状態の位相スペクトルを使うと分析しやすい事情は上記の記事にも書かれている.

細かい実装はソースコードを見れば分かるのだが,FFT計算の直前にサンプルのシフト(roll)を行っており,これにより線形位相成分をキャンセルしている. scipy/scipy/signal/_short_time_fft.py at v1.12.0 · scipy/scipy · GitHub

まとめ

新stftで位相スペクトルの線形位相成分の除去がやりやすくなったのは嬉しい.

「誤り訂正技術Ⅰ ~基礎編~」および「誤り訂正技術Ⅱ ~応用編~」の各記事へのリンク

ブックマーク程度に。

基礎編

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

応用編

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp

www.jstage.jst.go.jp