音声ファイル前処理(データロード)
例えばTensorFlowなどの深層学習ライブラリで音声を扱おうとした時、どのような変換をしているのか把握していないと応用が効かないし、詰まってしまう。
基本的なところからまとめ直してみる。
前回のTensorFlowチュートリアルに出てくる"yes"の音声データを使う。
Soxコマンドで音声ファイルの詳細を表示してみる。
% soxi speech_dataset/yes/0a7c2a8d_nohash_0.wav Input File : 'speech_dataset/yes/0a7c2a8d_nohash_0.wav' Channels : 1 Sample Rate : 16000 Precision : 16-bit Duration : 00:00:01.00 = 16000 samples ~ 75 CDDA sectors File Size : 32.0k Bit Rate : 256k Sample Encoding: 16-bit Signed Integer PCM
上の値が意味するのは以下のとおり。
- サンプリング周波数は「16000」(16k)
- モノラル(channels=1)
- 発話時間は「1秒」(Duration)
- 量子化ビット数は「16bit」(符号有り整数型、-32768〜32767で表現)
- ビットレートは「256k」(= サンプリング周波数 * 量子化ビット数 * チャンネル数 = 16k * 16bit * 1channel)
- PCM(圧縮無し)
ちょうど1秒間のデータなので、16000サンプルが得られる。
「サンプリング周波数」と「サンプル数」が同じになり、混同しやすくなるので注意。
Pythonでの音声ファイル読み込み方法をいくつか確認してみる。
- wave(標準モジュール)
- soundfile
- LibROSA
- SciPy
- TensorFlow(tf.audio.decode_wav)
Python 「wave」モジュール
ドキュメント
https://docs.python.org/ja/3/library/wave.html
import wave import numpy as np # Audio Data audio_path = 'speech_dataset/yes/0a7c2a8d_nohash_0.wav' # Read Binary waveFile = wave.open(audio_path , 'r') buf = waveFile.readframes(-1) waveFile.close() # Binary--> 16bit Signed Integer data = np.frombuffer(buf, dtype="int16") print('data shape: ', data.shape) print('data type: ', type(data)) print('data[:5]: ', data[:5])
読み込みの結果
data shape: (16000,) data type: <class 'numpy.ndarray'> data[:5]: [ 14 -7 -14 1 12]
プロット
# plot import matplotlib.pyplot as plt plt.plot(data) plt.title('yes/0a7c2a8d_nohash_0.wav') plt.xlabel('Sample Index') plt.ylabel('Sample Value') plt.ylim(-32768, 32767) plt.grid() plt.tight_layout() plt.show()
Python 「soundfile」ライブラリ
ドキュメント
https://pysoundfile.readthedocs.io/en/latest/
「-1」から「1」にスケーリングされる。
import soundfile as sf # Audio Data audio_path = 'speech_dataset/yes/0a7c2a8d_nohash_0.wav' data, sr = sf.read(audio_path) print('sample rate: ', sr) print('data shape: ', data.shape) print('data type: ', type(data)) print('data[:5]: ', data[:5])
読み込みの結果
sample rate: 16000 data shape: (16000,) data type: <class 'numpy.ndarray'> data[:5]: [ 4.27246094e-04 -2.13623047e-04 -4.27246094e-04 3.05175781e-05 3.66210938e-04]
プロット
# plot import matplotlib.pyplot as plt plt.plot(data) plt.title('yes/0a7c2a8d_nohash_0.wav') plt.xlabel('Sample Index') plt.ylabel('Sample Value') plt.ylim(-1, 1) plt.grid() plt.tight_layout() plt.show()
Python 「LibROSA」パッケージ
ドキュメント
https://librosa.github.io/librosa/generated/librosa.core.load.html
サンプリング周波数はデフォルトで「22050」なので注意。
今回は「16000」にしたいので、明示的に指定する。
「-1」から「1」にスケーリングされる。
import librosa # Audio Data audio_path = 'speech_dataset/yes/0a7c2a8d_nohash_0.wav' data, sr = librosa.load( audio_path, sr=16000) print('sample rate: ', sr) print('data shape: ', data.shape) print('data type: ', type(data)) print('data[:5]: ', data[:5])
読み込みの結果
sample rate: 16000 data shape: (16000,) data type: <class 'numpy.ndarray'> data[:5]: [ 4.2724609e-04 -2.1362305e-04 -4.2724609e-04 3.0517578e-05 3.6621094e-04]
プロット
# plot import librosa.display import matplotlib.pyplot as plt plt.figure() librosa.display.waveplot(data, sr=sr) plt.title('yes/0a7c2a8d_nohash_0.wav') plt.xlabel('Sample Index') plt.ylabel('Sample Value') plt.ylim(-1, 1) plt.grid() plt.tight_layout() plt.show()
Python 「SciPy」パッケージ
ドキュメント
https://docs.scipy.org/doc/scipy/reference/generated/scipy.io.wavfile.read.html
スケーリングされるかは、WAV formatによる。
16-bit PCMの場合、スケールされない。
import wave from scipy.io import wavfile # Audio Data audio_path = 'speech_dataset/yes/0a7c2a8d_nohash_0.wav' # Read fs, data = wavfile.read(audio_path) print('data shape: ', data.shape) print('data type: ', type(data)) print('data[:5]: ', data[:5])
読み込みの結果
data shape: (16000,) data type: <class 'numpy.ndarray'> data[:5]: [ 14 -7 -14 1 12]
プロット
# plot import matplotlib.pyplot as plt plt.plot(data) plt.title('yes/0a7c2a8d_nohash_0.wav') plt.xlabel('Sample Index') plt.ylabel('Sample Value') plt.ylim(-32768, 32767) plt.grid() plt.tight_layout() plt.show()
Python 「TensorFlow」ライブラリ
ドキュメント
https://www.tensorflow.org/versions/r1.15/api_docs/python/tf/audio/decode_wav
「-1」から「1」にスケーリングされる。
import tensorflow as tf from tensorflow.python.ops import io_ops tf.compat.v1.disable_eager_execution() # Audio Data audio_path = 'speech_dataset/yes/0a7c2a8d_nohash_0.wav' with tf.compat.v1.Session(graph=tf.Graph()) as sess: wav_filename_placeholder = tf.compat.v1.placeholder(tf.string, []) wav_loader = io_ops.read_file(wav_filename_placeholder) wav_decoder = tf.audio.decode_wav(wav_loader, desired_channels=1) data, sr = sess.run( wav_decoder, feed_dict={wav_filename_placeholder: audio_path} ) print('sample rate: ', sr) print('data shape: ', data.shape) print('data type: ', type(data)) print('data[:5]: ', data[:5])
読み込みの結果
sample rate: 16000 data shape: (16000, 1) data type: <class 'numpy.ndarray'> data[:5]: [[ 4.2724609e-04] [-2.1362305e-04] [-4.2724609e-04] [ 3.0517578e-05] [ 3.6621094e-04]]
プロット
# plot import matplotlib.pyplot as plt plt.plot(data) plt.title('yes/0a7c2a8d_nohash_0.wav') plt.xlabel('Sample Index') plt.ylabel('Sample Value') plt.ylim(-1, 1) plt.grid() plt.tight_layout() plt.show()
まとめ
以下に留意する。- サンプリング周波数(「LibROSA」は、ファイル情報をもとに自動で合わせてくれるわけではない)
- スケーリング有無(主要なものは「-1」から「1」のレンジにスケールしてくれる)