目前,我遇到了Backpropagation算法的问题。 我正在尝试实现它并使用它来识别面部的方向(左,右,下,直)。 基本上,我有N个图像,读取像素并将其值(0到255)更改为0.0到1.0之间的值。所有图像均为32 * 30。 我有一个960个神经元的输入层,一个隐藏的3个神经元层和一个4个神经元的输出层。例如,输出<0.1,0.9,0.1,0.1&gt;意味着该人向右看。 我遵循了pseudy-code。但是,它无法正常工作 - 它不会计算正确的权重,因此无法处理培训和测试示例。 以下是代码的一部分:
// main function - it runs the algorithm
private void runBackpropagationAlgorithm() {
for (int i = 0; i < 900; ++i) {
for (ImageUnit iu : images) {
double [] error = calcOutputError(iu.getRatioMatrix(), iu.getClassification());
changeHiddenUnitsOutWeights(error);
error = calcHiddenError(error);
changeHiddenUnitsInWeights(error,iu.getRatioMatrix());
}
}
}
// it creates the neural network
private void createNeuroneNetwork() {
Random generator = new Random();
for (int i = 0; i < inHiddenUnitsWeights.length; ++i) {
for (int j = 0; j < hiddenUnits; ++j) {
inHiddenUnitsWeights[i][j] = generator.nextDouble();
}
}
for (int i = 0; i < hiddenUnits; ++i) {
for (int j = 0; j < 4; ++j) {
outHddenUnitsWeights[i][j] = generator.nextDouble();
}
}
}
// Calculates the error in the network. It runs through the whole network.
private double [] calcOutputError(double[][] input, double [] expectedOutput) {
int currentEdge = 0;
Arrays.fill(hiddenUnitNodeValue, 0.0);
for (int i = 0; i < input.length; ++i) {
for (int j = 0; j < input[0].length; ++j) {
for (int k = 0; k < hiddenUnits; ++k) {
hiddenUnitNodeValue[k] += input[i][j] * inHiddenUnitsWeights[currentEdge][k];
}
++currentEdge;
}
}
double[] out = new double[4];
for (int j = 0; j < 4; ++j) {
for (int i = 0; i < hiddenUnits; ++i) {
out[j] += outHddenUnitsWeights[i][j] * hiddenUnitNodeValue[i];
}
}
double [] error = new double [4];
Arrays.fill(error, 4);
for (int i = 0; i < 4; ++i) {
error[i] = ((expectedOutput[i] - out[i])*(1.0-out[i])*out[i]);
//System.out.println((expectedOutput[i] - out[i]) + " " + expectedOutput[i] + " " + out[i]);
}
return error;
}
// Changes the weights of the outgoing edges of the hidden neurons
private void changeHiddenUnitsOutWeights(double [] error) {
for (int i = 0; i < hiddenUnits; ++i) {
for (int j = 0; j < 4; ++j) {
outHddenUnitsWeights[i][j] += learningRate*error[j]*hiddenUnitNodeValue[i];
}
}
}
// goes back to the hidden units to calculate their error.
private double [] calcHiddenError(double [] outputError) {
double [] error = new double[hiddenUnits];
for (int i = 0; i < hiddenUnits; ++i) {
double currentHiddenUnitErrorSum = 0.0;
for (int j = 0; j < 4; ++j) {
currentHiddenUnitErrorSum += outputError[j]*outHddenUnitsWeights[i][j];
}
error[i] = hiddenUnitNodeValue[i] * (1.0 - hiddenUnitNodeValue[i]) * currentHiddenUnitErrorSum;
}
return error;
}
// changes the weights of the incomming edges to the hidden neurons. input is the matrix of ratios
private void changeHiddenUnitsInWeights(double [] error, double[][] input) {
int currentEdge = 0;
for (int i = 0; i < input.length; ++i) {
for (int j = 0; j < input[0].length; ++j) {
for (int k = 0; k < hiddenUnits; ++k) {
inHiddenUnitsWeights[currentEdge][k] += learningRate*error[k]*input[i][j];
}
++currentEdge;
}
}
}
随着算法的工作,它会计算越来越大的权重,最终接近无穷大(NaN值)。我查了一下代码。唉,我没办法解决我的问题。 我会非常感谢那些试图帮助我的人。
答案 0 :(得分:3)
我没有检查你的所有代码。我只是想给你一些一般的建议。我不知道你的目标是(1)学习面部方向还是(2)实现你自己的神经网络。
如果是(1),您应该考虑those个库中的一个。它们只是工作并为您提供更灵活的配置选项。例如,标准反向传播是神经网络最差的优化算法之一。收敛取决于学习率。我看不出您在实施中选择了哪个值,但它可能太高了。还有其他优化算法不需要学习速率或在培训期间对其进行调整。另外,隐藏层中的3个神经元很可能是不够的。大多数用于图像的神经网络都有数百甚至数千个隐藏单元。我建议你先用完全开发的库来解决你的问题。如果它确实有效,请尝试实施您自己的ANN或开心。 :)
在情况(2)中,您应该首先尝试解决一个更简单的问题。获取一个非常简单的人工数据集,然后选择standard benchmark,然后使用您的数据进行尝试。验证反向传播实现是否有效的一种好方法是与numerical differentation method进行比较。
答案 1 :(得分:2)
您的代码缺少传输功能。听起来你想要具有softmax输出的逻辑功能。您需要在calcOutputError
中包含以下内容// Logistic transfer function for hidden layer.
for (int k = 0; k < hiddenUnits; ++k) {
hiddenUnitNodeValue[k] = logistic(hiddenUnitNodeValue[k]);
}
和
// Softmax transfer function for output layer.
sum = 0;
for (int j = 0; j < 4; ++j) {
out[j] = logistic(out[j]);
sum += out[j];
}
for (int j = 0; j < 4; ++j) {
out[j] = out[j] / sum;
}
物流功能
public double logistic(double x){
return (1/(1+(Math.exp(-x)));
}
请注意,softmax传递函数为您提供总和为1的输出,因此可以将它们解释为概率。
此外,您对输出图层的误差梯度的计算不正确。它应该只是
for (int i = 0; i < 4; ++i) {
error[i] = (expectedOutput[i] - out[i]);
}
答案 2 :(得分:0)
我还没有测试过你的代码,但我几乎可以肯定你是从大量开始的。 关于这些主题的大多数介绍都将其置于“使用随机值初始化权重”,并且忽略了算法实际上偏离(转到Inf)以获得一些起始值。
尝试使用较小的起始值,例如介于-1 / 5和1/5之间并将其缩小。
另外做一个矩阵乘法的方法,你(只)使用了4次,更容易看出那里是否有问题。
答案 3 :(得分:0)
我的神经网络处理灰度图像有类似的问题。您有960个输入值,范围在0到255之间。即使初始权重很小,您最终也会以非常大的幅度输入神经元,并且反向传播算法会被卡住。
尝试将每个像素值除以255,然后再将其传递到神经网络中。这对我有用。刚开始使用极小的初始权重是不够的,我相信由于评论中提出的浮点精度问题。
正如另一个答案中所建议的,测试算法的一个好方法是查看您的网络是否可以学习像XOR这样的简单函数。
为了它的价值,隐藏层中的3个神经元对我来说是充足的(识别面部图像的性别)
答案 4 :(得分:0)
我写了一个全新的神经网络库并且它有效。可以肯定的是,在我之前的尝试中,我错过了使用传递函数及其衍生物的想法。谢谢大家!