java - 使用运行时生成的数据在 deeplearning4j 中训练递归神经网络

标签 java deep-learning lstm recurrent-neural-network deeplearning4j

我是 deeplearning4j 库的新手,但我对一般的神经网络有一些经验。
我正在尝试训练一个循环神经网络(特别是 LSTM),它应该实时检测音乐中的节拍。到目前为止,我发现所有将循环神经网络与 deeplearning4j 结合使用的示例都使用了一个从文件中读取训练数据的阅读器。因为我想通过麦克风实时录制音乐,所以我无法读取一些预生成的文件,所以输入神经网络的数据是由我的应用程序实时生成的。

这是我用来生成我的网络的代码:

    NeuralNetConfiguration.ListBuilder builder = new NeuralNetConfiguration.Builder()
            .optimizationAlgo(OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT).iterations(1)
            .learningRate(0.1)
            .rmsDecay(0.95)
            .regularization(true)
            .l2(0.001)
            .weightInit(WeightInit.XAVIER)
            .updater(Updater.RMSPROP)
            .list();

    int nextIn = hiddenLayers.length > 0 ? hiddenLayers[0] : numOutputs;
    builder = builder.layer(0, new GravesLSTM.Builder().nIn(numInputs).nOut(nextIn).activation("softsign").build());

    for(int i = 0; i < hiddenLayers.length - 1; i++){
        nextIn = hiddenLayers[i + 1];
        builder = builder.layer(i + 1, new GravesLSTM.Builder().nIn(hiddenLayers[i]).nOut(nextIn).activation("softsign").build());
    }

    builder = builder.layer(hiddenLayers.length, new RnnOutputLayer.Builder(LossFunctions.LossFunction.MCXENT).nIn(nextIn).nOut(numOutputs).activation("softsign").build());

    MultiLayerConfiguration conf = builder.backpropType(BackpropType.TruncatedBPTT).tBPTTForwardLength(DEFAULT_RECURRENCE_DEPTH).tBPTTBackwardLength(DEFAULT_RECURRENCE_DEPTH)
            .pretrain(false).backprop(true)
            .build();

    net = new MultiLayerNetwork(conf);
    net.init();  

在这种情况下,我使用了大约 700 个输入(主要是录制音频的 FFT 数据)、1 个输出(应该输出 0 [无节拍] 和 1 [节拍] 之间的数字)和我的hiddenLayers 数组由整数 {50, 25, 10} 组成。

为了获取网络的输出,我使用了这段代码:

    double[] output = new double[]{net.rnnTimeStep(Nd4j.create(netInputData)).getDouble(0)};

其中 netInputData 是我要作为一维 double 组输入到网络中的数据。
我相对确定这段代码工作正常,因为我得到了一些未经训练的网络的输出,看起来 something like this当我绘制它时。
然而,一旦我尝试训练一个网络(即使我只训练了很短的时间,这应该会稍微改变网络的权重,以便输出应该与未经训练的网络非常相似),我得到looks like a constant 的输出.

这是我用来训练网络的代码:

    for(int timestep = 0; timestep < trainingData.length - DEFAULT_RECURRENCE_DEPTH; timestep++){
        INDArray inputDataArray = Nd4j.create(new int[]{1, numInputs, DEFAULT_RECURRENCE_DEPTH},'f');
        for(int inputPos = 0; inputPos < trainingData[timestep].length; inputPos++)
            for(int inputTimeWindowPos = 0; inputTimeWindowPos < DEFAULT_RECURRENCE_DEPTH; inputTimeWindowPos++)
                inputDataArray.putScalar(new int[]{0, inputPos, inputTimeWindowPos}, trainingData[timestep + inputTimeWindowPos][inputPos]);

        INDArray desiredOutputDataArray = Nd4j.create(new int[]{1, numOutputs, DEFAULT_RECURRENCE_DEPTH},'f');
        for(int outputPos = 0; outputPos < desiredOutputData[timestep].length; outputPos++)
            for(int inputTimeWindowPos = 0; inputTimeWindowPos < DEFAULT_RECURRENCE_DEPTH; inputTimeWindowPos++)
                desiredOutputDataArray.putScalar(new int[]{0, outputPos, inputTimeWindowPos}, desiredOutputData[timestep + inputTimeWindowPos][outputPos]);

        net.fit(new DataSet(inputDataArray, desiredOutputDataArray));
    }  

再一次,我得到了我的输入数据和所需输出的 double 组。这次这两个数组是二维的。第一个索引表示时间(其中索引 0 是录制音频的第一个音频数据),第二个索引表示此时间步长的输入(或相应的所需输出)。
鉴于训练网络后显示的输出,我倾向于认为我用于从我的数据创建 INDArrays 的代码一定有问题。我是否遗漏了初始化这些数组的一些重要步骤,或者我是否弄乱了将数据放入这些数组所需的顺序?

提前感谢您的帮助。

最佳答案

我不确定,但也许 99.99% 的训练示例都是 0,只有偶尔 1 恰好出现在节拍的位置。这可能太不平衡而无法学习。祝你好运。

关于java - 使用运行时生成的数据在 deeplearning4j 中训练递归神经网络,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37855760/

相关文章:

keras - 批处理内的 LSTM 状态

machine-learning - 如何学习语言模型?

lstm - LSTM 中输入和标签的 PyTorch 张量

python - Keras `fit_generator` 验证准确度低,但 `fit` 验证准确度低

java - 如何使用 Math.random() 获取范围内的随机数

java - 对数组字符串进行排序 java 即输入 ="aab cde abc aaa"输出 ="aaa aab abc cde"

Java:如何从文本文件中读取特定行?

python - 使用 Keras 中的 Lambda 函数拆分 LSTM 输出

python - 应用程序中的 Keras 形状错误 Inception Resnet v2

即使在困惑的字符串中也能找到 YYYY-MM 的 Java 正则表达式