ichou1のブログ

主に音声認識、時々、データ分析のことを書く

音声ファイル前処理(データロード)

例えば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()

f:id:ichou1:20200216101122p:plain


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

f:id:ichou1:20200216100851p:plain

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

f:id:ichou1:20200216104951p:plain

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

f:id:ichou1:20200216101122p:plain

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

f:id:ichou1:20200216111412p:plain

まとめ

以下に留意する。

  • サンプリング周波数(「LibROSA」は、ファイル情報をもとに自動で合わせてくれるわけではない)
  • スケーリング有無(主要なものは「-1」から「1」のレンジにスケールしてくれる)