重新初始化数据集后,损失会回升到起始值

Ana*_*ory 10 python tensorflow tensorflow-datasets

我正在使用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
Run Code Online (Sandbox Code Playgroud)

完整的代码,包括使用的足够免费的数据(带有IPA转录的维基百科声音文件),在github上.

非自由数据(EMU语料库声音文件)确实有显着差异,但我不确定如何向您展示:

  • 当在整个数据集上运行脚本时,输出在迭代0中开始,丢失大约5000,然后在数据集上减少到大约1000.然后是1指示第二个循环的行,并且突然损失再次大约为5000 .
  • 当将订单交换到DATA_PATH.glob("**/*.wav"), DATA_PATH.glob("**/*.ogg")损失时,从低于5000开始并下降到大约1000,然后再次跳到4000以获取*.ogg样本.

重新排序样本给我一个不同的结果,所以看起来WAV文件比OGG文件更相似.我有一个概念,理想情况下,洗牌应该发生在数据集的层面,而不是依赖于随机读取它.但是,这意味着要将大量的wav文件读入内存,这听起来不是一个好的解决方案.

我的代码应该是什么样的?

Eka*_*ong 5

请试试这个:

  • 添加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()
Run Code Online (Sandbox Code Playgroud)

更新到会话

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)
Run Code Online (Sandbox Code Playgroud)

如果我可以访问一些数据样本,我可以更精确地帮助.现在,我在这里工作,无论如何,请告诉我这是否有效.


Phi*_*rro 3

这看起来像是架构中的一个问题。首先,您在旅途中生成数据,尽管这是一种常用的技术,但并不总是最合理的选择。这是因为:

其缺点之一Dataset.from_generator()是使用大小为 n 的洗牌缓冲区对结果数据集进行洗牌需要加载 n 个示例。这要么会在管道中造成周期性暂停(大 n),要么导致可能较差的洗牌(小 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()
Run Code Online (Sandbox Code Playgroud)

这将解决该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)
Run Code Online (Sandbox Code Playgroud)

这应该确保您的数据被彻底洗牌并给出更好的结果。

此外,我相信您会从一些数据预处理中受益。对于初学者,尝试将数据集中的所有文件转换为标准化的 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")
Run Code Online (Sandbox Code Playgroud)

最后,您可能会发现以浮点形式读取声音文件并不符合您的最佳利益。你应该考虑尝试类似的事情:

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
Run Code Online (Sandbox Code Playgroud)

然后像这样应用函数:

#convert file if you need to
convert(filepath)

#get spectrogram
spec = getSpectrogram(filepath)
Run Code Online (Sandbox Code Playgroud)

这会将 WAVE 文件中的数据解析为图像,然后您可以像处理任何图像分类问题一样处理这些图像。