神经网络不学习时有1个以上的隐藏层



我正在实现我的第一个神经网络,作为我的高中期末论文。在使用MNIST数据集进行训练时,我得到了很好的结果。但这只是当我只使用一个隐藏层时,如果我在训练后尝试使用一个以上的隐藏层,总是给出相同的输出。我试着用多个层重新计算误差函数的导数,但我一定遗漏了什么。。。这是我的反向传播方法的代码:

public void BackPropagation(double[] error, bool batch)
{
double[][] temp = null;
temp = NNMath.ArrayToMatrix(NNMath.EntryWiseProduct(error, NNMath.SigmoidDerivativeFromSigmoid(this.A[this.A.Length - 1])));
this.DW[this.DW.Length - 1] = NNMath.TransposeMatrix(NNMath.DotProduct(NNMath.TransposeMatrix(temp), NNMath.ArrayToMatrix(this.A[this.DW.Length - 1])));
temp[0].CopyTo(this.DB[this.DB.Length - 1], 0);
for (int i = this.W.Length - 1; i > 0; i--)
{
temp = NNMath.DotProduct(temp, NNMath.TransposeMatrix(this.W[i]));
temp = NNMath.EntryWiseProduct(temp, NNMath.ArrayToMatrix(NNMath.SigmoidDerivativeFromSigmoid(this.A[i])));
if (batch)
{
this.DW[i - 1] = NNMath.EntryWiseSum(this.DW[i - 1], NNMath.DotProduct(NNMath.TransposeMatrix(this.A[i - 1]), temp));
this.DB[i - 1] = NNMath.EntryWiseSum(this.DB[i - 1], temp[0]);
}
else
{
this.DW[i - 1] = NNMath.DotProduct(NNMath.TransposeMatrix(this.A[i - 1]), temp);
temp[0].CopyTo(this.DB[i - 1], 0);
}
}
}

我创建了一个名为NNMath的静态类,用于执行矩阵运算。

  • this.A是一个二维阵列,每行代表一个激活层
  • CCD_ 2是一个三维阵列,其中每个元素都是2层之间的权重矩阵
  • this.DWthis.W相同,但包含计算的导数
  • this.DB是一个包含偏差导数的二维数组
  • 如果在批处理训练期间调用该方法,则batch为true

我使用MSE作为损失函数。

提前感谢!

编辑:以下是NNMath 的更多代码

public static double[] EntryWiseSum(double[] a, double[] b)
{
if (a.Length != b.Length)
return null;
double[] c = new double[a.Length];
for (int i = 0; i < a.Length; i++)
c[i] = a[i] + b[i];
return c;
}
public static double SigmoidDerivativeFromSigmoid(double sigmoidA)
{
return sigmoidA * (1.0 - sigmoidA);
}
public static double[] SigmoidDerivativeFromSigmoid(double[] a)
{
double[] res = new double[a.Length];
for (int i = 0; i < a.Length; i++)
res[i] = SigmoidDerivativeFromSigmoid(a[i]);
return res;
}

我发现了错误。如果有人想知道的话,下面是正确的方法。

public void BackPropagationNew(double[] error, bool batch)
{
double[][] temp = null;
temp = NNMath.ArrayToMatrix(NNMath.EntryWiseProduct(error, NNMath.SigmoidDerivativeFromSigmoid(this.A[this.A.Length - 1])));
if (batch)
{
this.DW[this.DW.Length - 1] = NNMath.EntryWiseSum(this.DW[this.DW.Length - 1],  NNMath.TransposeMatrix(NNMath.DotProduct(NNMath.TransposeMatrix(temp), NNMath.ArrayToMatrix(this.A[this.DW.Length - 1]))));
this.DB[this.DB.Length - 1] = NNMath.EntryWiseSum(this.DB[this.DB.Length - 1], temp[0]);
}
else
{
this.DW[this.DW.Length - 1] = NNMath.TransposeMatrix(NNMath.DotProduct(NNMath.TransposeMatrix(temp), NNMath.ArrayToMatrix(this.A[this.DW.Length - 1])));
temp[0].CopyTo(this.DB[this.DB.Length - 1], 0);
}
for (int i = this.W.Length - 1; i > 0; i--)
{
temp = NNMath.DotProduct(temp, NNMath.TransposeMatrix(this.W[i]));
temp = NNMath.EntryWiseProduct(temp, NNMath.ArrayToMatrix(NNMath.SigmoidDerivativeFromSigmoid(this.A[i])));
if (batch)
{
this.DW[i - 1] = NNMath.EntryWiseSum(this.DW[i - 1], NNMath.DotProduct(NNMath.TransposeMatrix(this.A[i - 1]), temp));
this.DB[i - 1] = NNMath.EntryWiseSum(this.DB[i - 1], temp[0]);
}
else
{
this.DW[i - 1] = NNMath.DotProduct(NNMath.TransposeMatrix(this.A[i - 1]), temp);
temp[0].CopyTo(this.DB[i - 1], 0);
}
}
}

因为我使用的是小批量训练,在第一次重量变化时,我忘记检查它是否在一个批次中,所以它实际上并没有改变重量。无论如何,感谢任何试图帮助我的人!下次我会尽量小心一点。

最新更新