我是 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/