PyTorch 1.5 Tutorials : 音声 : torchaudio チュートリアル (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/10/2020 (1.5.0)
* 本ページは、PyTorch 1.5 Tutorials の以下のページを翻訳した上で適宜、補足説明したものです:
- Audio : torchaudio Tutorial
* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。
- お住まいの地域に関係なく Web ブラウザからご参加頂けます。事前登録 が必要ですのでご注意ください。
- Windows PC のブラウザからご参加が可能です。スマートデバイスもご利用可能です。
◆ お問合せ : 本件に関するお問い合わせ先は下記までお願いいたします。
株式会社クラスキャット セールス・マーケティング本部 セールス・インフォメーション |
E-Mail:sales-info@classcat.com ; WebSite: https://www.classcat.com/ |
Facebook: https://www.facebook.com/ClassCatJP/ |
音声 : torchaudio チュートリアル
PyTorch はオープンソースの深層学習プラットフォームで、GPU サポートとともに研究プロトタイピングからプロダクション配備までシームレスなパスを提供します。
機械学習問題を解く重要な努力はデータ準備に進んでいます。torchaudio は PyTorch の GPU サポートを活用し、そしてデータロードを容易にしてより可読にするために多くのツールを提供します。このチュートリアルでは、単純なデータセットからデータをどのようにロードして前処理するかを見ます。
このチュートリアルのために、容易な可視化のために matplotlib パッケージがインストールされていることを確実にしてください。
import torch import torchaudio import matplotlib.pyplot as plt
ファイルをオープンする
torchaudio は wav と mp3 形式の音声ファイルのロードをサポートします。結果としての生音声信号を waveform 呼び出しをします。
filename = "../_static/img/steam-train-whistle-daniel_simon-converted-from-mp3.wav" waveform, sample_rate = torchaudio.load(filename) print("Shape of waveform: {}".format(waveform.size())) print("Sample rate of waveform: {}".format(sample_rate)) plt.figure() plt.plot(waveform.t().numpy())
Shape of waveform: torch.Size([2, 276858]) Sample rate of waveform: 44100
torchaudio 内にファイルをロードするとき、オプションで SoX か SoundFile を利用するか torchaudio.set_audio_backend を通してバックエンドを指定できます。これらのバックエンドは必要なときに遅延してロードされます。
torchaudio はまた関数のために JIT コンパイルをオプションにして、可能なところでは nn.Module を利用します。
変換
torchaudio は次の変換の増大中のリストをサポートします。
- Resample: 異なるサンプルレートで waveform を再サンプリングする。
- Spectrogram: waveform からスペクトログラムを作成する。
- GriffinLim: Griffin-Lim 変換を使用して線形スケール magnitude スペクトログラムから waveform を計算する。
- ComputeDeltas: tensor のデルタ係数を計算する、通常はスペクトログラム。
- ComplexNorm: 複素 tensor のノルムを計算する。
- MelScale: これは変換行列を使用して、normal STFT をメル周波数 STFT に変える。
- AmplitudeToDB: これはパワー/振幅スケールからのスペクトログラムをデシベル・スケールに変える。
- MFCC: waveform からメル周波数ケプストラム係数を作成する。
- MelSpectrogram: PyTorch の STFT 関数を使用して waveform からメル・スペクトログラムを作成する。
- MuLawEncoding: μ-law 圧伸に基づいて waveform をエンコードする。
- MuLawDecoding: μ-law エンコードされた waveform をデコードする。
- TimeStretch: 与えられたレートのためのピッチを変更することなくスペクトログラムを in time でストレッチする。
- FrequencyMasking: 周波数領域でスペクトログラムにマスキングを適用する。
- TimeMasking: 時間領域でスペクトログラムにマスキングを適用する。
各変換はバッチ処理をサポートします : 単一の生音声信号かスペクトログラム、あるいは多くの同じ shape 上で変換を遂行できます。
総ての変換は nn.Modules か jit.ScriptModules ですので、それらは任意のポイントでニューラルネットワークの一部として使用できます。
始めるために、log スケールでスペクトログラムの log を見ることができます。
specgram = torchaudio.transforms.Spectrogram()(waveform) print("Shape of spectrogram: {}".format(specgram.size())) plt.figure() plt.imshow(specgram.log2()[0,:,:].numpy(), cmap='gray')
Shape of spectrogram: torch.Size([2, 201, 1385])
あるいは log スケールでメル・スペクトログラムを見ることができます。
specgram = torchaudio.transforms.MelSpectrogram()(waveform) print("Shape of spectrogram: {}".format(specgram.size())) plt.figure() p = plt.imshow(specgram.log2()[0,:,:].detach().numpy(), cmap='gray')
Shape of spectrogram: torch.Size([2, 128, 1385])
一度に 1 チャネルで、waveform を再サンプリングすることができます。
new_sample_rate = sample_rate/10 # Since Resample applies to a single channel, we resample first channel here channel = 0 transformed = torchaudio.transforms.Resample(sample_rate, new_sample_rate)(waveform[channel,:].view(1,-1)) print("Shape of transformed waveform: {}".format(transformed.size())) plt.figure() plt.plot(transformed[0,:].numpy())
ShaShape of transformed waveform: torch.Size([1, 27686])
変換のもう一つの例として、μ-Law エンコーディングに基づいて信号をエンコードできます。しかしそのためには、信号が -1 と 1 の間にあることを必要とします。tensor は単なる通常の PyTorch tensor ですので、その上で標準的な演算を適用できます。
# Let's check if the tensor is in the interval [-1,1] print("Min of waveform: {}\nMax of waveform: {}\nMean of waveform: {}".format(waveform.min(), waveform.max(), waveform.mean()))
Min of waveform: -0.572845458984375 Max of waveform: 0.575958251953125 Mean of waveform: 9.293758921558037e-05
waveform は既に -1 と 1 の間ですので、それを正規化する必要はありません。
def normalize(tensor): # Subtract the mean, and scale to the interval [-1,1] tensor_minusmean = tensor - tensor.mean() return tensor_minusmean/tensor_minusmean.abs().max() # Let's normalize to the full interval [-1,1] # waveform = normalize(waveform)
waveform のエンコードを適用しましょう。
transformed = torchaudio.transforms.MuLawEncoding()(waveform) print("Shape of transformed waveform: {}".format(transformed.size())) plt.figure() plt.plot(transformed[0,:].numpy())
Shape of transformed waveform: torch.Size([2, 276858])
そして今はデコードします。
reconstructed = torchaudio.transforms.MuLawDecoding()(transformed) print("Shape of recovered waveform: {}".format(reconstructed.size())) plt.figure() plt.plot(reconstructed[0,:].numpy())
Shape of recovered waveform: torch.Size([2, 276858])
最後に元の waveform を再構築されたバージョンと比較できます。
# Compute median relative difference err = ((waveform-reconstructed).abs() / waveform.abs()).median() print("Median relative difference between original and MuLaw reconstucted signals: {:.2%}".format(err))
Median relative difference between original and MuLaw reconstucted signals: 1.28%
Functional
上で見られる変換はそれらの計算のために低位ステートレス関数に依拠しています。これらの関数は torchaudio.functional の下で利用可能です。完全なリストは ここ で利用可能でそして以下を含みます :
- istft: 逆短時間フーリエ変換。
- gain: waveform 全体に増幅か減衰を適用する。
- dither: 特定のビット深度にストアされた音声の知覚されるダイナミックレンジを増加する。
- compute_deltas: tensor のデルタ係数を計算する。
- equalizer_biquad: 双二次ピーキングイコライザー・フィルターを設計してフィルタリングを遂行する。
- lowpass_biquad: 双二次ローパスフィルターを設計してフィルタリングを遂行する。
- highpass_biquad: 双二次ハイパスフィリたーを設計してフィルタリングを遂行する。
例えば、mu_law_encoding functional を試しましょう :
mu_law_encoding_waveform = torchaudio.functional.mu_law_encoding(waveform, quantization_channels=256) print("Shape of transformed waveform: {}".format(mu_law_encoding_waveform.size())) plt.figure() plt.plot(mu_law_encoding_waveform[0,:].numpy())
Shape of transformed waveform: torch.Size([2, 276858])
torchaudio.functional.mu_law_encoding からの出力が torchaudio.transforms.MuLawEncoding からの出力とどのように同じであるかを見れるでしょう。
今は他の functional の 2, 3 を実験してそれらの出力を可視化しましょう。スペクトログラムを取り、そのデルタを計算できます :
computed = torchaudio.functional.compute_deltas(specgram.contiguous(), win_length=3) print("Shape of computed deltas: {}".format(computed.shape)) plt.figure() plt.imshow(computed.log2()[0,:,:].detach().numpy(), cmap='gray')
Shape of computed deltas: torch.Size([2, 128, 1385])
元の waveform を取りそれに違うエフェクトを適用することができます。
gain_waveform = torchaudio.functional.gain(waveform, gain_db=5.0) print("Min of gain_waveform: {}\nMax of gain_waveform: {}\nMean of gain_waveform: {}".format(gain_waveform.min(), gain_waveform.max(), gain_waveform.mean())) dither_waveform = torchaudio.functional.dither(waveform) print("Min of dither_waveform: {}\nMax of dither_waveform: {}\nMean of dither_waveform: {}".format(dither_waveform.min(), dither_waveform.max(), dither_waveform.mean()))
Min of gain_waveform: -1.0186792612075806 Max of gain_waveform: 1.024214744567871 Mean of gain_waveform: 0.00016526904073543847 Min of dither_waveform: -0.572784423828125 Max of dither_waveform: 0.575927734375 Mean of dither_waveform: 0.00010744280007202178
torchaudio.functional の機能のもう一つのサンプルはフィルターを waveform に適用しています。waveform へのローパス双二次フィルターの適用は変更された周波数の信号を持つ新しい waveform を出力します。
lowpass_waveform = torchaudio.functional.lowpass_biquad(waveform, sample_rate, cutoff_freq=3000) print("Min of lowpass_waveform: {}\nMax of lowpass_waveform: {}\nMean of lowpass_waveform: {}".format(lowpass_waveform.min(), lowpass_waveform.max(), lowpass_waveform.mean())) plt.figure() plt.plot(lowpass_waveform.t().numpy())
Min of lowpass_waveform: -0.5595061182975769 Max of lowpass_waveform: 0.5595013499259949 Mean of lowpass_waveform: 9.293758921558037e-05
ハイパス双二次フィルターを伴う waveform を可視化することもできます。
highpass_waveform = torchaudio.functional.highpass_biquad(waveform, sample_rate, cutoff_freq=2000) print("Min of highpass_waveform: {}\nMax of highpass_waveform: {}\nMean of highpass_waveform: {}".format(highpass_waveform.min(), highpass_waveform.max(), highpass_waveform.mean())) plt.figure() plt.plot(highpass_waveform.t().numpy())
Min of highpass_waveform: -0.11269105970859528 Max of highpass_waveform: 0.10451901704072952 Mean of highpass_waveform: -4.971002776077427e-12
Kaldi から torchaudio にマイグレートする
ユーザは Kaldi、発話認識のためのツールキットに馴染みがあるかもしれません。torchaudio は torchaudio.kaldi_io でそれとの互換性を提供します。それは実際には kaldi scp、または ark ファイルあるいは次によるストリームから読むことができます :
- read_vec_int_ark
- read_vec_flt_scp
- read_vec_flt_arkfile/stream
- read_mat_scp
- read_mat_ark
torhaudio はスペクトログラム, fbank, mfcc そして resample_waveform のための Kaldi-互換な変換を GPU サポートの利点とともに提供します、より多くの情報については こちら (訳注: リンク切れ) を見てください。
n_fft = 400.0 frame_length = n_fft / sample_rate * 1000.0 frame_shift = frame_length / 2.0 params = { "channel": 0, "dither": 0.0, "window_type": "hanning", "frame_length": frame_length, "frame_shift": frame_shift, "remove_dc_offset": False, "round_to_power_of_two": False, "sample_frequency": sample_rate, } specgram = torchaudio.compliance.kaldi.spectrogram(waveform, **params) print("Shape of spectrogram: {}".format(specgram.size())) plt.figure() plt.imshow(specgram.t().numpy(), cmap='gray')
Shape of spectrogram: torch.Size([1383, 201])
Kaldi の実装に適合させて、waveform からの filterbank 特徴の計算もまたサポートしています。
fbank = torchaudio.compliance.kaldi.fbank(waveform, **params) print("Shape of fbank: {}".format(fbank.size())) plt.figure() plt.imshow(fbank.t().numpy(), cmap='gray')
Shape of fbank: torch.Size([1383, 23])
生音声信号からメル周波数ケプストラム係数を作成できます。これは Kaldi の compute-mfcc-feats の入出力に適合します。
mfcc = torchaudio.compliance.kaldi.mfcc(waveform, **params) print("Shape of mfcc: {}".format(mfcc.size())) plt.figure() plt.imshow(mfcc.t().numpy(), cmap='gray')
Shape of mfcc: torch.Size([1383, 13])
利用可能なデータセット
モデルを訓練するために貴方自身のデータセットを作成することを望まない場合、torchaudio は統一されたデータセット・インターフェイスを提供します。このインターフェイスはメモリへのファイルの遅延ローディング、download と extract 関数、そしてモデルを構築するためのデータセットをサポートします。
torchaudio が現在サポートするデータセットは :
- VCTK: 様々なアクセントを持つ 109 人の英語のネイティブ・スピーカーにより発声されたスピーチデータ ( ここを更に読んでください )。
- Yesno: ヘブライ語で yes か no を言う個々人の 60 の録音 ( ここを更に読んでください )。
- Common Voice: スピーチ-enabled アプリケーションを訓練するために誰でも利用できるオープンソースの、声のマルチ言語データセット ( ここを更に読んでください )。
- LibriSpeech: 読まれた英語スピーチの巨大スケール (1000 時間) コーパス ( ここを更に読んでください )
yesno_data = torchaudio.datasets.YESNO('./', download=True) # A data point in Yesno is a tuple (waveform, sample_rate, labels) where labels is a list of integers with 1 for yes and 0 for no. # Pick data point number 3 to see an example of the the yesno_data: n = 3 waveform, sample_rate, labels = yesno_data[n] print("Waveform: {}\nSample rate: {}\nLabels: {}".format(waveform, sample_rate, labels)) plt.figure() plt.plot(waveform.t().numpy())
Waveform: tensor([[3.0518e-05, 6.1035e-05, 3.0518e-05, ..., 5.8594e-03, 3.5400e-03, 3.3569e-04]]) Sample rate: 8000 Labels: [0, 1, 0, 0, 1, 0, 1, 0]
今では、データセットから音声ファイルを求めるときはいつでも、それを求めるときに限りメモリにロードされます。
つまり、データセットは貴方が望み使用する項目だけをメモリにロードして保持します、メモリを節約します。
終わりに
サンプル生音声信号、あるいは waveform を使用して、torchaudio を使用してどのように音声ファイルをオープンするか、そしてそのような waveform をどのように前処理して変換するかそして関数を適用するかを示しました。馴染みのある Kaldi 関数をどのように使用するか、そしてモデルを構築するために組込みデータセットをどのように利用するかを実演しました。torchaudio が PyTorch 上で構築されたとすると、これらのテクニックは、GPU を活用しながら、発話認識のようなより進んだ音声アプリケーションのためのビルディングブロックとして使用できます。
以上