反向传播不起作用:神经网络 Java
Backpropagation not working: Neural Network Java
我根据这个 python 示例创建了一个简单的 3 层神经网络:Link(PS:您必须向下滚动才能到达第 2 部分)
这是我的Java实现代码:
private void trainNet()
{
// INPUT is a 4*3 matrix
// SYNAPSES is a 3*4 matrix
// SYNAPSES2 is a 4*1 matrix
// 4*3 matrix DOT 3*4 matrix => 4*4 matrix: unrefined test results
double[][] layer1 = sigmoid(dot(inputs, synapses), false);
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: 4 final test results
double[][] layer2 = sigmoid(dot(layer1, synapses2), false);
// 4*1 matrix - 4*1 matrix => 4*1 matrix: error of 4 test results
double[][] layer2Error = subtract(outputs, layer2);
// 4*1 matrix DOT 4*1 matrix => 4*1 matrix: percentage of change of 4 test results
double[][] layer2Delta = dot(layer2Error, sigmoid(layer2, true));
// 4*1 matrix DOT 3*1 matrix => 4*1 matrix
double[][] layer1Error = dot(layer2Delta, synapses2);
// 4*1 matrix DOT 4*4 matrix => 4*4 matrix: percentage of change of 4 test results
double[][] layer1Delta = dot(layer1Error, sigmoid(layer1, true));
double[][] transposedInputs = transpose(inputs);
double[][] transposedLayer1 = transpose(layer1);
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: the updated weights
// Update the weights
synapses2 = sum(synapses2, dot(transposedLayer1, layer2Delta));
// 3*4 matrix DOT 4*4 matrix => 3*4 matrix: the updated weights
// Update the weights
synapses = sum(synapses, dot(transposedInputs, layer1Delta));
// Test each value of two 4*1 matrices with each other
testValue(layer2, outputs);
}
我自己创建的点、求和、减和转置函数,我很确定它们能完美地完成它们的工作。
第一批输入给我大约 0.4 的误差,这没关系,因为权重是随机值。在第二个 运行 上,误差较小,但只有很小的数量 (0.001)
经过 500,000 个批次(因此总共进行了 2,000,000 次测试),网络仍然没有给出任何正确的值!所以我尝试使用更大数量的批次。使用 1,000,000 个批次(总共 4,000,000 次测试),网络生成了高达 16,900 个正确的结果。
谁能告诉我这是怎么回事?
这些是使用的权重:
第一层:
- 2.038829298171684 2.816232761170282 1.6740269469812146 1.634422766238497
- 1.5890997594993828 1.7909325329112222 2.101840236824494 1.063579126586681
- 3.761238407071311 3.757148454039234 3.7557450538398176 3.6715972104291605
第二层:
- -0.019603811941904248
- 218.38253323323553
- 53.70133275445734
-272.83589796861514
编辑:
感谢 lsnare 向我指出使用库会更容易!
对于那些感兴趣的人,这里是使用 math.nist.gov/javanumerics 库的工作代码:
private void trainNet()
{
// INPUT is a 4*3 matrix
// SYNAPSES is a 3*4 matrix
// SYNAPSES2 is a 4*1 matrix
// 4*3 matrix DOT 3*4 matrix => 4*4 matrix: unrefined test results
Matrix hiddenLayer = sigmoid(inputs.times(synapses), false);
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: 4 final test results
Matrix outputLayer = sigmoid(hiddenLayer.times(synapses2), false);
// 4*1 matrix - 4*1 matrix => 4*1 matrix: error of 4 test results
Matrix outputLayerError = outputs.minus(outputLayer);
// 4*1 matrix DOT 4*1 matrix => 4*1 matrix: percentage of change of 4 test results
Matrix outputLayerDelta = outputLayerError.arrayTimes(sigmoid(outputLayer, true));
// 4*1 matrix DOT 1*4 matrix => 4*4 matrix
Matrix hiddenLayerError = outputLayerDelta.times(synapses2.transpose());
// 4*4 matrix DOT 4*4 matrix => 4*4 matrix: percentage of change of 4 test results
Matrix hiddenLayerDelta = hiddenLayerError.arrayTimes(sigmoid(hiddenLayer, true));
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: the updated weights
// Update the weights
synapses2 = synapses2.plus(hiddenLayer.transpose().times(outputLayerDelta));
// 3*4 matrix DOT 4*4 matrix => 3*4 matrix: the updated weights
// Update the weights
synapses = synapses.plus(inputs.transpose().times(hiddenLayerDelta));
// Test each value of two 4*1 matrices with each other
testValue(outputLayer.getArrayCopy(), outputs.getArrayCopy());
}
一般来说,在编写涉及高级数学或数值计算(例如线性代数)的代码时,最好使用该领域专家编写的现有库,而不是编写您自己的函数。标准库将产生更准确的结果,并且很可能更高效。例如,在您引用的博客中,作者使用 numpy 库计算点积和矩阵转置。对于 Java,您可以使用由 NIST 开发的 Java 矩阵包 (JAMA):http://math.nist.gov/javanumerics/jama/
例如,要转置矩阵:
double[4][3] in = {{0,0,1},{0,1,1},{1,0,1},{1,1,1}};
Matrix input = new Matrix(in);
input = input.transpose();
我不确定这是否能完全解决您的问题,但希望这能帮助您在将来避免编写额外的代码。
我根据这个 python 示例创建了一个简单的 3 层神经网络:Link(PS:您必须向下滚动才能到达第 2 部分)
这是我的Java实现代码:
private void trainNet()
{
// INPUT is a 4*3 matrix
// SYNAPSES is a 3*4 matrix
// SYNAPSES2 is a 4*1 matrix
// 4*3 matrix DOT 3*4 matrix => 4*4 matrix: unrefined test results
double[][] layer1 = sigmoid(dot(inputs, synapses), false);
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: 4 final test results
double[][] layer2 = sigmoid(dot(layer1, synapses2), false);
// 4*1 matrix - 4*1 matrix => 4*1 matrix: error of 4 test results
double[][] layer2Error = subtract(outputs, layer2);
// 4*1 matrix DOT 4*1 matrix => 4*1 matrix: percentage of change of 4 test results
double[][] layer2Delta = dot(layer2Error, sigmoid(layer2, true));
// 4*1 matrix DOT 3*1 matrix => 4*1 matrix
double[][] layer1Error = dot(layer2Delta, synapses2);
// 4*1 matrix DOT 4*4 matrix => 4*4 matrix: percentage of change of 4 test results
double[][] layer1Delta = dot(layer1Error, sigmoid(layer1, true));
double[][] transposedInputs = transpose(inputs);
double[][] transposedLayer1 = transpose(layer1);
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: the updated weights
// Update the weights
synapses2 = sum(synapses2, dot(transposedLayer1, layer2Delta));
// 3*4 matrix DOT 4*4 matrix => 3*4 matrix: the updated weights
// Update the weights
synapses = sum(synapses, dot(transposedInputs, layer1Delta));
// Test each value of two 4*1 matrices with each other
testValue(layer2, outputs);
}
我自己创建的点、求和、减和转置函数,我很确定它们能完美地完成它们的工作。
第一批输入给我大约 0.4 的误差,这没关系,因为权重是随机值。在第二个 运行 上,误差较小,但只有很小的数量 (0.001)
经过 500,000 个批次(因此总共进行了 2,000,000 次测试),网络仍然没有给出任何正确的值!所以我尝试使用更大数量的批次。使用 1,000,000 个批次(总共 4,000,000 次测试),网络生成了高达 16,900 个正确的结果。
谁能告诉我这是怎么回事?
这些是使用的权重:
第一层:
- 2.038829298171684 2.816232761170282 1.6740269469812146 1.634422766238497
- 1.5890997594993828 1.7909325329112222 2.101840236824494 1.063579126586681
- 3.761238407071311 3.757148454039234 3.7557450538398176 3.6715972104291605
第二层:
- -0.019603811941904248
- 218.38253323323553
- 53.70133275445734
-272.83589796861514
编辑: 感谢 lsnare 向我指出使用库会更容易!
对于那些感兴趣的人,这里是使用 math.nist.gov/javanumerics 库的工作代码:
private void trainNet()
{
// INPUT is a 4*3 matrix
// SYNAPSES is a 3*4 matrix
// SYNAPSES2 is a 4*1 matrix
// 4*3 matrix DOT 3*4 matrix => 4*4 matrix: unrefined test results
Matrix hiddenLayer = sigmoid(inputs.times(synapses), false);
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: 4 final test results
Matrix outputLayer = sigmoid(hiddenLayer.times(synapses2), false);
// 4*1 matrix - 4*1 matrix => 4*1 matrix: error of 4 test results
Matrix outputLayerError = outputs.minus(outputLayer);
// 4*1 matrix DOT 4*1 matrix => 4*1 matrix: percentage of change of 4 test results
Matrix outputLayerDelta = outputLayerError.arrayTimes(sigmoid(outputLayer, true));
// 4*1 matrix DOT 1*4 matrix => 4*4 matrix
Matrix hiddenLayerError = outputLayerDelta.times(synapses2.transpose());
// 4*4 matrix DOT 4*4 matrix => 4*4 matrix: percentage of change of 4 test results
Matrix hiddenLayerDelta = hiddenLayerError.arrayTimes(sigmoid(hiddenLayer, true));
// 4*4 matrix DOT 4*1 matrix => 4*1 matrix: the updated weights
// Update the weights
synapses2 = synapses2.plus(hiddenLayer.transpose().times(outputLayerDelta));
// 3*4 matrix DOT 4*4 matrix => 3*4 matrix: the updated weights
// Update the weights
synapses = synapses.plus(inputs.transpose().times(hiddenLayerDelta));
// Test each value of two 4*1 matrices with each other
testValue(outputLayer.getArrayCopy(), outputs.getArrayCopy());
}
一般来说,在编写涉及高级数学或数值计算(例如线性代数)的代码时,最好使用该领域专家编写的现有库,而不是编写您自己的函数。标准库将产生更准确的结果,并且很可能更高效。例如,在您引用的博客中,作者使用 numpy 库计算点积和矩阵转置。对于 Java,您可以使用由 NIST 开发的 Java 矩阵包 (JAMA):http://math.nist.gov/javanumerics/jama/
例如,要转置矩阵:
double[4][3] in = {{0,0,1},{0,1,1},{1,0,1},{1,1,1}};
Matrix input = new Matrix(in);
input = input.transpose();
我不确定这是否能完全解决您的问题,但希望这能帮助您在将来避免编写额外的代码。