重新初始化数据集后损失回到起始值
Loss goes up back to starting value after re-initializing dataset
我正在 Python Tensorflow 中针对音频数据训练 LSTM 网络。我的数据集是一堆波形文件,read_wavfiles
变成了 numpy
数组的生成器。我决定尝试使用相同的数据集训练我的网络 20 次,并编写了一些代码如下。
from with_hyperparams import stft
from model import lstm_network
import tensorflow as tf
def read_wavfile():
for file in itertools.chain(DATA_PATH.glob("**/*.ogg"),
DATA_PATH.glob("**/*.wav")):
waveform, samplerate = librosa.load(file, sr=hparams.sample_rate)
if len(waveform.shape) > 1:
waveform = waveform[:, 1]
yield waveform
audio_dataset = Dataset.from_generator(
read_wavfile,
tf.float32,
tf.TensorShape([None]))
dataset = audio_dataset.padded_batch(5, padded_shapes=[None])
iterator = tf.data.Iterator.from_structure(dataset.output_types,
dataset.output_shapes)
dataset_init_op = iterator.make_initializer(dataset)
signals = iterator.get_next()
magnitude_spectrograms = tf.abs(stft(signals))
output, loss = lstm_network(magnitude_spectrograms)
train_op = tf.train.AdamOptimizer(1e-3).minimize(loss)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
for i in range(20):
print(i)
sess.run(dataset_init_op)
while True:
try:
l, _ = sess.run((loss, train_op))
print(l)
except tf.errors.OutOfRangeError:
break
完整代码,包括使用的足够免费的数据(带有 IPA 转录的维基百科声音文件),是 on github。
非免费数据(EMU 语料库声音文件)确实有很大的不同,尽管我不确定如何向您展示:
- 当 运行 整个数据集上的脚本时,输出从迭代 0 开始,损失约为 5000,然后在数据集上减少到大约 1000。然后是带有 [=13= 的行] 表示第二次循环,突然又损失了5000左右
- 当将订单换成
DATA_PATH.glob("**/*.wav"), DATA_PATH.glob("**/*.ogg")
时,损失从 5000 以下开始下降到 1000 左右,然后在 *.ogg
样本再次跳升至 4000。
重新排序样本得到了不同的结果,所以看起来 WAV 文件比 OGG 文件更相似。我有一个想法,洗牌应该理想地发生在数据集级别,而不是依赖于它以随机顺序读取。然而,这意味着将大量 wav 文件读入内存,这听起来不是一个好的解决方案。
我的代码应该是什么样的?
请试试这个:
- 将
dataset.shuffle(buffer_size=1000)
添加到输入管道。
- 隔离对
loss
的调用以在每个训练时期后进行评估。
如下图:
更新输入管道
dataset = audio_dataset.padded_batch(5, padded_shapes=[None])
dataset = dataset.shuffle(buffer_size=1000)
iterator = tf.data.Iterator.from_structure(dataset.output_types,
dataset.output_shapes)
dataset_init_op = iterator.make_initializer(dataset)
signals = iterator.get_next()
会话更新
with tf.Session() as sess:
sess.run(init_op)
for i in range(20):
print(i)
sess.run(dataset_init_op)
while True:
try:
sess.run(train_op)
except tf.errors.OutOfRangeError:
break
# print loss for each epoch
l = sess.run(loss)
print(l)
如果我能访问一些数据样本,我可能会提供更准确的帮助。现在,我在这里盲目工作,无论如何,请告诉我这是否有效。
这看起来像是架构中的问题。首先,您是在移动中生成数据,尽管这是一种常用的技术,但并不总是最合理的选择。这是因为:
One of the downsides of Dataset.from_generator()
is shuffling the resulting dataset
with a shuffle buffer of size n requires n examples to be loaded. This
will either create periodic pauses in your pipeline (large n) or
result in potentially poor shuffling (small n).
将您的数据转换为 numpy 数组,然后将 numpy 数组存储在磁盘上以用作您的数据集可能是个好主意,如下所示:
def array_to_tfrecords(X, y, output_file):
feature = {
'X': tf.train.Feature(float_list=tf.train.FloatList(value=X.flatten())),
'y': tf.train.Feature(float_list=tf.train.FloatList(value=y.flatten()))
}
example = tf.train.Example(features=tf.train.Features(feature=feature))
serialized = example.SerializeToString()
writer = tf.python_io.TFRecordWriter(output_file)
writer.write(serialized)
writer.close()
这将使 Dataset.from_generator
部分脱离问题。然后可以使用以下方式读取数据:
def read_tfrecords(file_names=("file1.tfrecord", "file2.tfrecord", "file3.tfrecord"),
buffer_size=10000,
batch_size=100):
dataset = tf.contrib.data.TFRecordDataset(file_names)
dataset = dataset.map(parse_proto)
dataset = dataset.shuffle(buffer_size)
dataset = dataset.repeat()
dataset = dataset.batch(batch_size)
return tf.contrib.data.Iterator.from_structure(dataset.output_types, dataset.output_shapes)
这应该确保您的数据被彻底洗牌并提供更好的结果。
此外,我相信您会从一些数据预处理中受益。对于初学者,尝试将数据集中的所有文件转换为标准化的 WAVE 形式,然后将该数据保存到 TFRecord。目前您正在将它们转换为 WAVE 并使用 librosa 标准化采样率,但这并没有标准化通道。而是尝试使用如下函数:
from pydub import AudioSegment
def convert(path):
#open file (supports all ffmpeg supported filetypes)
audio = AudioSegment.from_file(path, path.split('.')[-1].lower())
#set to mono
audio = audio.set_channels(1)
#set to 44.1 KHz
audio = audio.set_frame_rate(44100)
#save as wav
audio.export(path, format="wav")
最后,您可能会发现将声音文件读取为浮点数并不符合您的最佳利益。您应该考虑尝试类似的方法:
import scipy.io.wavfile as wave
import python_speech_features as psf
def getSpectrogram(path, winlen=0.025, winstep=0.01, NFFT=512):
#open wav file
(rate,sig) = wave.read(path)
#get frames
winfunc=lambda x:np.ones((x,))
frames = psf.sigproc.framesig(sig, winlen*rate, winstep*rate, winfunc)
#Magnitude Spectrogram
magspec = np.rot90(psf.sigproc.magspec(frames, NFFT))
#noise reduction (mean substract)
magspec -= magspec.mean(axis=0)
#normalize values between 0 and 1
magspec -= magspec.min(axis=0)
magspec /= magspec.max(axis=0)
#show spec dimensions
print magspec.shape
return magspec
然后像这样应用函数:
#convert file if you need to
convert(filepath)
#get spectrogram
spec = getSpectrogram(filepath)
这会将 WAVE 文件中的数据解析为图像,然后您可以像处理任何图像分类问题一样处理这些图像。
我正在 Python Tensorflow 中针对音频数据训练 LSTM 网络。我的数据集是一堆波形文件,read_wavfiles
变成了 numpy
数组的生成器。我决定尝试使用相同的数据集训练我的网络 20 次,并编写了一些代码如下。
from with_hyperparams import stft
from model import lstm_network
import tensorflow as tf
def read_wavfile():
for file in itertools.chain(DATA_PATH.glob("**/*.ogg"),
DATA_PATH.glob("**/*.wav")):
waveform, samplerate = librosa.load(file, sr=hparams.sample_rate)
if len(waveform.shape) > 1:
waveform = waveform[:, 1]
yield waveform
audio_dataset = Dataset.from_generator(
read_wavfile,
tf.float32,
tf.TensorShape([None]))
dataset = audio_dataset.padded_batch(5, padded_shapes=[None])
iterator = tf.data.Iterator.from_structure(dataset.output_types,
dataset.output_shapes)
dataset_init_op = iterator.make_initializer(dataset)
signals = iterator.get_next()
magnitude_spectrograms = tf.abs(stft(signals))
output, loss = lstm_network(magnitude_spectrograms)
train_op = tf.train.AdamOptimizer(1e-3).minimize(loss)
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
sess.run(init_op)
for i in range(20):
print(i)
sess.run(dataset_init_op)
while True:
try:
l, _ = sess.run((loss, train_op))
print(l)
except tf.errors.OutOfRangeError:
break
完整代码,包括使用的足够免费的数据(带有 IPA 转录的维基百科声音文件),是 on github。
非免费数据(EMU 语料库声音文件)确实有很大的不同,尽管我不确定如何向您展示:
- 当 运行 整个数据集上的脚本时,输出从迭代 0 开始,损失约为 5000,然后在数据集上减少到大约 1000。然后是带有 [=13= 的行] 表示第二次循环,突然又损失了5000左右
- 当将订单换成
DATA_PATH.glob("**/*.wav"), DATA_PATH.glob("**/*.ogg")
时,损失从 5000 以下开始下降到 1000 左右,然后在*.ogg
样本再次跳升至 4000。
重新排序样本得到了不同的结果,所以看起来 WAV 文件比 OGG 文件更相似。我有一个想法,洗牌应该理想地发生在数据集级别,而不是依赖于它以随机顺序读取。然而,这意味着将大量 wav 文件读入内存,这听起来不是一个好的解决方案。
我的代码应该是什么样的?
请试试这个:
- 将
dataset.shuffle(buffer_size=1000)
添加到输入管道。 - 隔离对
loss
的调用以在每个训练时期后进行评估。
如下图:
更新输入管道
dataset = audio_dataset.padded_batch(5, padded_shapes=[None])
dataset = dataset.shuffle(buffer_size=1000)
iterator = tf.data.Iterator.from_structure(dataset.output_types,
dataset.output_shapes)
dataset_init_op = iterator.make_initializer(dataset)
signals = iterator.get_next()
会话更新
with tf.Session() as sess:
sess.run(init_op)
for i in range(20):
print(i)
sess.run(dataset_init_op)
while True:
try:
sess.run(train_op)
except tf.errors.OutOfRangeError:
break
# print loss for each epoch
l = sess.run(loss)
print(l)
如果我能访问一些数据样本,我可能会提供更准确的帮助。现在,我在这里盲目工作,无论如何,请告诉我这是否有效。
这看起来像是架构中的问题。首先,您是在移动中生成数据,尽管这是一种常用的技术,但并不总是最合理的选择。这是因为:
One of the downsides of
Dataset.from_generator()
is shuffling the resulting dataset with a shuffle buffer of size n requires n examples to be loaded. This will either create periodic pauses in your pipeline (large n) or result in potentially poor shuffling (small n).
将您的数据转换为 numpy 数组,然后将 numpy 数组存储在磁盘上以用作您的数据集可能是个好主意,如下所示:
def array_to_tfrecords(X, y, output_file):
feature = {
'X': tf.train.Feature(float_list=tf.train.FloatList(value=X.flatten())),
'y': tf.train.Feature(float_list=tf.train.FloatList(value=y.flatten()))
}
example = tf.train.Example(features=tf.train.Features(feature=feature))
serialized = example.SerializeToString()
writer = tf.python_io.TFRecordWriter(output_file)
writer.write(serialized)
writer.close()
这将使 Dataset.from_generator
部分脱离问题。然后可以使用以下方式读取数据:
def read_tfrecords(file_names=("file1.tfrecord", "file2.tfrecord", "file3.tfrecord"),
buffer_size=10000,
batch_size=100):
dataset = tf.contrib.data.TFRecordDataset(file_names)
dataset = dataset.map(parse_proto)
dataset = dataset.shuffle(buffer_size)
dataset = dataset.repeat()
dataset = dataset.batch(batch_size)
return tf.contrib.data.Iterator.from_structure(dataset.output_types, dataset.output_shapes)
这应该确保您的数据被彻底洗牌并提供更好的结果。
此外,我相信您会从一些数据预处理中受益。对于初学者,尝试将数据集中的所有文件转换为标准化的 WAVE 形式,然后将该数据保存到 TFRecord。目前您正在将它们转换为 WAVE 并使用 librosa 标准化采样率,但这并没有标准化通道。而是尝试使用如下函数:
from pydub import AudioSegment
def convert(path):
#open file (supports all ffmpeg supported filetypes)
audio = AudioSegment.from_file(path, path.split('.')[-1].lower())
#set to mono
audio = audio.set_channels(1)
#set to 44.1 KHz
audio = audio.set_frame_rate(44100)
#save as wav
audio.export(path, format="wav")
最后,您可能会发现将声音文件读取为浮点数并不符合您的最佳利益。您应该考虑尝试类似的方法:
import scipy.io.wavfile as wave
import python_speech_features as psf
def getSpectrogram(path, winlen=0.025, winstep=0.01, NFFT=512):
#open wav file
(rate,sig) = wave.read(path)
#get frames
winfunc=lambda x:np.ones((x,))
frames = psf.sigproc.framesig(sig, winlen*rate, winstep*rate, winfunc)
#Magnitude Spectrogram
magspec = np.rot90(psf.sigproc.magspec(frames, NFFT))
#noise reduction (mean substract)
magspec -= magspec.mean(axis=0)
#normalize values between 0 and 1
magspec -= magspec.min(axis=0)
magspec /= magspec.max(axis=0)
#show spec dimensions
print magspec.shape
return magspec
然后像这样应用函数:
#convert file if you need to
convert(filepath)
#get spectrogram
spec = getSpectrogram(filepath)
这会将 WAVE 文件中的数据解析为图像,然后您可以像处理任何图像分类问题一样处理这些图像。