代码之家  ›  专栏  ›  技术社区  ›  Anaphory

重新初始化数据集后,丢失将返回到起始值

  •  10
  • Anaphory  · 技术社区  · 6 年前

    我正在用Python Tensorflow对LSTM网络进行音频数据培训。我的数据集是一堆wave文件 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
    

    完整的代码,包括使用的足够免费的数据(Wikipedia声音文件和IPA转录),是 on github

    非自由数据(EMU corpus声音文件)确实有很大的不同,尽管我不确定如何向您展示它:

    • 在整个数据集上运行脚本时,输出从迭代0开始,损失约5000,然后在数据集上减少到约1000。接下来是 1
    • 当交换订单到 DATA_PATH.glob("**/*.wav"), DATA_PATH.glob("**/*.ogg") 损失开始在5000以下,下降到1000左右,然后又上升到4000 *.ogg

    重新排序示例会得到不同的结果,因此WAV文件看起来比OGG文件更相似。我有一个想法,洗牌应该理想地发生在数据集级别,而不是依赖于它被随机顺序读取。然而,这意味着要将大量wav文件读入内存,这听起来不是一个好的解决方案。

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

    2 回复  |  直到 6 年前
        1
  •  3
  •   Philip DiSarro    6 年前

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

    它的缺点之一 Dataset.from_generator() 正在重新整理结果数据集 对于大小为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()
    

    这将需要 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文件中的数据解析成图像,然后您就可以用处理任何图像分类问题的方法来处理这些图像。

        2
  •  5
  •   Ekaba Bisong    6 年前

    请试试这个:

    • 添加 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)
    

    如果我可以访问一些数据样本,我可能能够提供更精确的帮助。现在,我在这里瞎工作,无论如何,一定要让我知道这是否有效。