PyTorchに繋げやすい音声前処理torchaudioを用いた音声処理を試してみる

PyTorchで音声を扱う際はtorchaudioを使用すると前処理が簡単にできるぞ

音声前処理が簡単にできるってことですね

メルケプストラムなど様々な処理が簡単に試せるようになっているぞ

参考情報

下記の記事を参考にしています。

https://pytorch.org/tutorials/beginner/audio_preprocessing_tutorial.html

Google Colabを使用して動作確認しました。下記に手順を載せています。

Google Colabでは予め必要なライブラリがインストールされていますがtorchaudioはインストールされていないのでインストールします。

!pip install torchaudio 
import torch
import torchaudio
import requests
import matplotlib.pyplot as plt

音声の読み込み

wavとmp3フォーマットのデータを取得して、torchaudioで読み込んで見ます。

url = "https://pytorch.org/tutorials/_static/img/steam-train-whistle-daniel_simon-converted-from-mp3.wav"
r = requests.get(url)

with open('steam-train-whistle-daniel_simon-converted-from-mp3.wav', 'wb') as f:
    f.write(r.content)

filename = "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())

スペクトログラム

音声の前処理をしていきます。まずはスペクトログラムです。1行のコードでスペクトログラムに変換できました。縦軸は周波数、横軸は時間、色で各周波数の強さを表しています。時間がもとの音声と異なるのはスペクトログラムで処理する窓幅がDefaultは400で移動幅のDefault値が200のため、その分、圧縮されています。

specgram = torchaudio.transforms.Spectrogram()(waveform)

print("Shape of spectrogram: {}".format(specgram.size()))

plt.figure()
plt.imshow(specgram.log2()[0,:,:].numpy())

試しに窓幅(win_length)と移動幅(hop_length)を変えてみます。時間が変わっていることが確認できます。

specgram = torchaudio.transforms.Spectrogram(win_length=200, hop_length=100)(waveform)

print("Shape of spectrogram: {}".format(specgram.size()))

plt.figure()
plt.imshow(specgram.log2()[0,:,:].numpy())

メルスペクトログラム

次にメルスペクトログラムを表示してみます。メルスペクトグラムに関しては下記の記事で解説しています。

specgram = torchaudio.transforms.MelSpectrogram()(waveform)

print("Shape of spectrogram: {}".format(specgram.size()))

plt.figure()
p = plt.imshow(specgram.log2()[0,:,:].detach().numpy())

リサンプリング

リサンプリングしてサンプリングレートを下げてみます。1/10に下げてみます。

  • Before: 276858
  • After: 27686
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())

圧縮

音声の圧縮処理であるμ-Lawを適用してみます。これは256ビットまでデータを量子化してくれる処理です。これによってデータ圧縮ができます。

transformed = torchaudio.transforms.MuLawEncoding()(waveform)

print("Shape of transformed waveform: {}".format(transformed.size()))

plt.figure()
plt.plot(transformed[0,:].numpy())

エンコードした音声をデコードします。

reconstructed = torchaudio.transforms.MuLawDecoding()(transformed)

print("Shape of recovered waveform: {}".format(reconstructed.size()))

plt.figure()
plt.plot(reconstructed[0,:].numpy())

もとの音声との差分を見てみます。

# Compute median relative difference
err = ((waveform-reconstructed).abs() / waveform.abs()).median()

print("Median relative difference between original and MuLaw reconstucted signals: {:.2%}".format(err))

1.28%程度の誤差で動作しました。

Median relative difference between original and MuLaw reconstucted signals: 1.28%

フィルター

低周波数帯域のみパスするフィルターをかけて動作を確認してみます。

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())

逆に高い周波数帯域のみ通してみます。

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())

可能なデータ・セット

torchaudioは下記の音声データ・セットもサポートしています。

  • VCTK: Speech data uttered by 109 native speakers of English with various accents (Read more here <https://homepages.inf.ed.ac.uk/jyamagis/page3/page58/page58.html>_).
  • Yesno: Sixty recordings of one individual saying yes or no in Hebrew; each recording is eight words long (Read more here <https://www.openslr.org/1/>_).
  • Common Voice: An open source, multi-language dataset of voices that anyone can use to train speech-enabled applications (Read more here <https://voice.mozilla.org/en/datasets>_).
  • LibriSpeech: Large-scale (1000 hours) corpus of read English speech (Read more here <http://www.openslr.org/12>_).

実際に読み込み処理をしてみます。

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())

音声でよく使用されるスペクトログラム、メルスペクトログラム、リサンプル、圧縮が簡単にできたぞ

1行のコードで簡単に使用できましたね。

前処理のコードを再利用して、自分の実装したい部分にフォーカスしていこう

Close Bitnami banner
Bitnami