我是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时必定存在问题。我是否错过了初始化这些数组的一些重要步骤,还是我搞砸了将数据放入这些数组所需的顺序?
感谢您提前提供任何帮助。
答案 0 :(得分:1)
我不确定,但也许99.99%的训练样例都是0,偶尔只有1个正好在节拍的位置。这可能太不平衡而无法学习。祝你好运。