PyTorch 1.5 Tutorials : 音声 : torchaudio チュートリアル

PyTorch 1.5 Tutorials : 音声 : torchaudio チュートリアル (翻訳/解説)
翻訳 : (株)クラスキャット セールスインフォメーション
作成日時 : 06/10/2020 (1.5.0)

* 本ページは、PyTorch 1.5 Tutorials の以下のページを翻訳した上で適宜、補足説明したものです:

* サンプルコードの動作確認はしておりますが、必要な場合には適宜、追加改変しています。
* ご自由にリンクを張って頂いてかまいませんが、sales-info@classcat.com までご一報いただけると嬉しいです。

 

無料セミナー開催中 クラスキャット主催 人工知能 & ビジネス Web セミナー

人工知能とビジネスをテーマにウェビナー (WEB セミナー) を定期的に開催しています。スケジュールは弊社 公式 Web サイト でご確認頂けます。
  • お住まいの地域に関係なく 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 が現在サポートするデータセットは :

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 を活用しながら、発話認識のようなより進んだ音声アプリケーションのためのビルディングブロックとして使用できます。

 
以上