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

时间:2016-06-16 09:53:18

标签: 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是我想作为一维双数组输入网络的数据 我相对确定这段代码工作正常,因为我为未经训练的网络获取了一些输出,当我绘制它时看起来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));
    }  

我再一次得到了输入数据和双数组所需的输出数据。这次两个阵列是二维的。第一个索引表示时间(索引0是录制音频的第一个音频数据),第二个索引表示此时间步的输入(或相应的所需输出)。
鉴于在训练网络后显示的输出,我倾向于认为我的代码用于从我的数据创建INDArrays时必定存在问题。我是否错过了初始化这些数组的一些重要步骤,还是我搞砸了将数据放入这些数组所需的顺序?

感谢您提前提供任何帮助。

1 个答案:

答案 0 :(得分:1)

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