Java 用SGD微调数字识别的神经网络有问题。我能';从测试数据来看,t似乎优于87%

Java 用SGD微调数字识别的神经网络有问题。我能';从测试数据来看,t似乎优于87%,java,machine-learning,neural-network,gradient-descent,mnist,Java,Machine Learning,Neural Network,Gradient Descent,Mnist,我可以可靠地获得10000幅MNIST图像的测试数据约87%的准确率,以及训练数据约98%的准确率。我从零开始开发了神经网络,同时开发了一个矩阵类。目前,我正在使用学习率为0.6的小批量随机梯度下降(64号小批量)。我使用的是固定的学习率,我听说这很糟糕,但我有点不确定如何最好地结合不断变化的学习率。这是一个输入->隐藏->输出分层MLP NN 目前,5000次迭代足够让我获得70%左右的准确度(也需要6秒钟),但如果我想要更好的,我必须迭代400k左右。我一直在跟踪输出的平均误差,并在exce

我可以可靠地获得10000幅MNIST图像的测试数据约87%的准确率,以及训练数据约98%的准确率。我从零开始开发了神经网络,同时开发了一个矩阵类。目前,我正在使用学习率为0.6的小批量随机梯度下降(64号小批量)。我使用的是固定的学习率,我听说这很糟糕,但我有点不确定如何最好地结合不断变化的学习率。这是一个输入->隐藏->输出分层MLP NN

目前,5000次迭代足够让我获得70%左右的准确度(也需要6秒钟),但如果我想要更好的,我必须迭代400k左右。我一直在跟踪输出的平均误差,并在excel上为每个参数更改绘制图表,它总是遵循这样一种模式:先以难以置信的速度下降,然后趋于平稳,并且以更大的间隔发生更改

我想实现动量和不断变化的学习速率,但不幸的是,我对反向传播的数学符号有点生疏。我已经看了20多个关于实现动量的答案,但它们都使用符号来描述动量,如果我100%理解它,那就好了。我得到了使用过去的权重矩阵来更新当前权重矩阵的想法,但是当我考虑在我的特定代码中在哪里实现它时,我的困惑开始显现出来

这是我的正向传播和反向传播的代码,我希望有任何关于实现动量或改变学习率的建议(或者根据我提供的信息,有任何关于如何更好地改进我的NN的建议)。forward prop中的所有变量都是矩阵(很明显,但我只想澄清)

/**
*通过网络向前传播
*/
私有传播(矩阵输入批处理、矩阵输出批处理、布尔训练){
hiddenActivation=inputBatch.mult(InputOHiddenWeights);
hiddenActivation=hiddenActivation.sigmoidify();
outputActivation=hiddenActivation.mult(this.hiddenToOutputWeights);
outputActivation=outputActivation.sigmodify();
国际单项体育联合会(训练){
反向传播(inputBatch,outputBatch);
}
}
/**
*执行反向传播算法以更新权重
*训练神经网络。
*/
私有无效反向传播(矩阵输入批处理、矩阵输出批处理){
//计算输出层的梯度
outputErrorMatrix=outputBatch.sub(输出激活);
//跟踪每次迭代的平均误差(我绘制的数据)
this.avgerrorpinization[iterationToEpsilon]=outputErrorMatrix.averageValue();
//如果当前错误小于某个给定错误,请退出并保存权重
if(this.avgerorperiperation[iterationToEpsilon]
我认为动量或改变学习率不会帮助您获得更好的测试精度,因为这两种技术只会帮助优化算法,而您的优化算法已经做得很好了(因为它只是试图减少训练集上的错误,而且这个错误非常低)

显然,你的神经网络对训练集拟合过度,所以你可以尝试一件事。你可以尝试的一件简单的事情是。关键是,由于过度拟合,需要对网络进行正则化,这两种是正则化技术,而其他两种通常不是

    /**
     * forward propagate through the network
     */
    private void forwardPropagation(Matrix inputBatch, Matrix outputBatch, boolean training) {

        hiddenActivation = inputBatch.mult(inputToHiddenWeights);

        hiddenActivation = hiddenActivation.sigmoidify();

        outputActivation = hiddenActivation.mult(this.hiddenToOutputWeights);

        outputActivation = outputActivation.sigmoidify();

        if(training) {
            backPropagation(inputBatch, outputBatch);

        }
    }

    /**
     * Perform backpropagation algorithm to update the weights
     * and train the NN.
     */
    private void backPropagation(Matrix inputBatch, Matrix outputBatch) {

        // Compute gradient at output layer
        outputErrorMatrix = outputBatch.sub(outputActivation);

        // to keep track of the average error on every iteration (the data I plot)
        this.avgErrorPerIteration[iterationToEpsilon] = outputErrorMatrix.averageValue();

        // if the current error is less than a certain given error, exit and save weights
        if(this.avgErrorPerIteration[iterationToEpsilon] < this.epsilon) {
            this.lessThanEpsilon = true;
            return;
        }

        // to print out the initial error value (I compare it to the end value)
        if(iterationToEpsilon==0) {         
            System.out.println("Average error after first propagation: " + outputErrorMatrix.averageValue());
        }

        // compute slope at output and hidden layers
        Matrix slopeOutput = outputActivation.sigmoidifyPrime();
        Matrix slopeHiddenLayer = hiddenActivation.sigmoidifyPrime();

        // compute delta at output layer
        Matrix deltaOutput = (outputErrorMatrix.multAcross(slopeOutput)).mult(LEARNING_RATE);

        // calculate error at hidden layer
        Matrix hiddenError = deltaOutput.mult(hiddenToOutputWeights.transpose());

        // compute delta at hidden layer
        Matrix deltaHidden = hiddenError.multAcross(slopeHiddenLayer);

        // update weight at both output and hidden layers
        hiddenToOutputWeights = hiddenToOutputWeights.add(((hiddenActivation.transpose()).mult(deltaOutput)).mult(LEARNING_RATE));      
        inputToHiddenWeights = inputToHiddenWeights.add(((inputBatch.transpose()).mult(deltaHidden)).mult(LEARNING_RATE));

        iterationToEpsilon++;
    }