【问题标题】:CTC model does not learnCTC模型不学习
【发布时间】:2018-12-06 02:36:30
【问题描述】:

我正在尝试使用连接主义时间分类来编写用于音频转录的 Keras 模型。使用一个主要工作的逐帧分类模型和OCR example,我想出了下面给出的模型,我想训练它来将德语句子的短时傅里叶变换映射到它们的音标。

我的训练数据确实有时间信息,所以我可以用它来训练没有 CTC 的逐帧模型。没有 CTC 损失的逐帧预测模型运行良好(训练准确率 80%,验证准确率 50%)。 然而,在没有时间信息的情况下,还有更多潜在的训练数据可用,所以我真的很想换一个 CTC。为了测试这一点,我从数据中删除了时间,将 NULL 类的输出大小增加了一倍,并添加了 CTC 损失函数。

这个 CTC 模型似乎没有学习。总体而言,损失并没有下降(从 2000 年下降到 180 次,每个 80 句,但随后又回到了 430 次),它产生的最大似然输出在 [nh 左右徘徊。句子,一般有六个单词左右,[foːɐmʔɛsndʰaɪnəhɛndəvaʃn] - [] 等转录是序列的一部分,代表音频开始和结束时的停顿。

我发现在 Keras 中找到 CTC 的良好解释有点困难,所以可能是我做了一些愚蠢的事情。我是否弄乱了模型,在某处混淆了参数的顺序?在给模型完整的句子之前,我是否需要更加小心地训练模型,从音频 sn-ps 开始,每个声音有一个、两个或三个声音?总之,

如何让这个 CTC 模型学习?

connector = inputs
for l in [100, 100, 150]:
    lstmf, lstmb = Bidirectional(
        LSTM(
            units=l,
            dropout=0.1,
            return_sequences=True,
        ), merge_mode=None)(connector)

    connector = keras.layers.Concatenate(axis=-1)([lstmf, lstmb])

output = Dense(
    units=len(dataset.SEGMENTS)+1,
    activation=softmax)(connector)

loss_out = Lambda(
    ctc_lambda_func, output_shape=(1,),
    name='ctc')([output, labels, input_length, label_length])

ctc_model = Model(
    inputs=[inputs, labels, input_length, label_length],
    outputs=[loss_out])
ctc_model.compile(loss={'ctc': lambda y_true, y_pred: y_pred},
                  optimizer=SGD(
                      lr=0.02,
                      decay=1e-6,
                      momentum=0.9,
                      nesterov=True,
                      clipnorm=5))

ctc_lambda_function 和从预测中生成序列的代码来自 OCR 示例。

【问题讨论】:

  • 没有 CTC 你是如何学习的?通常,当我无法使用其他任何东西(输出未对齐)时,我会使用 CTC。也许您正在使用的数据已经因为不使用 CTC 而被perprocessed?
  • 我更改的解释有效吗?
  • 好的,谢谢。我只是想确定输入是否适合问题。我在您的 ctc 代码中没有看到任何问题(我还根据相同的示例创建了我的模型)。我用完整的句子(类似图像的 ocr)进行训练,并且训练没有问题。

标签: python machine-learning keras ctc


【解决方案1】:

从此处给出的代码中完全看不到它,但在其他地方 OP 提供了指向其Github repository 的链接。错误其实出在数据准备上:

数据是对数频谱图。它们是非标准化的,并且大多是高度负面的。 CTC 函数比 LSTM 层适应其输入偏差和输入权重要快得多,因此输入中的所有变化都被拉平了。当标签的边缘化分布尚未在全球范围内假设时,损失的局部最小值可能来自时代。

解决方案是缩放输入频谱图,使其同时包含正值和负值:

for i, file in enumerate(files):
    sg = numpy.load(file.with_suffix(".npy").open("rb"))
    spectrograms[i][:len(sg)] = 2 * (sg-sg.min())/(sg.max()-sg.min()) - 1

【讨论】: