Java中的神经网络无法反向传播

Java中的神经网络无法反向传播,java,neural-network,artificial-intelligence,gradient-descent,backpropagation,Java,Neural Network,Artificial Intelligence,Gradient Descent,Backpropagation,我已经为神经网络编写了代码,但当我训练我的网络时,它不会产生期望的输出(网络不学习,有时训练时会出现NaN值)。我的反向传播算法有什么问题?下面是我如何分别推导权重和偏差梯度公式的附件。可以找到完整的代码 public double[][]预测(double[][]输入){ if(input.length!=this.activations.get(0).length | | input[0].length!=this.activations.get(0)[0].length){ 抛出新的Ill

我已经为神经网络编写了代码,但当我训练我的网络时,它不会产生期望的输出(网络不学习,有时训练时会出现NaN值)。我的反向传播算法有什么问题?下面是我如何分别推导权重和偏差梯度公式的附件。可以找到完整的代码

public double[][]预测(double[][]输入){
if(input.length!=this.activations.get(0).length | | input[0].length!=this.activations.get(0)[0].length){
抛出新的IllegalArgumentException(“预测错误!”);
}
this.activations.set(0,输入);
对于(int i=1;i

您看到的NaN是由于下溢,您需要使用BigDecimal类而不是double类以获得更高的精度。为了更好地理解,请参考这些内容。

这个问题涉及的数学量,加上缺乏数据/代码的复制,几乎不可能回答“我的NaN在哪里”这一原始问题

相反,我建议您将这个问题重新考虑为一个更简单的问题,“如何判断像NaN这样的值在我的代码中来自何处?”

如果您可以在IDE中运行代码,那么大多数代码都支持条件断点。i、 当变量达到某个值时,断点将暂停代码。在您的情况下,我建议您在首选IDE中运行代码,并使用条件断点检测值是否为NaN

你可以在这篇文章中阅读更多关于如何设置它的内容,文章中很好地提到了NaN双重检查的主题:

另一个后续考虑是考虑需要将这些断点放在哪里。简单的答案是把它们放在计算双精度的任何地方,因为这些计算中的任何一个都可能引入NaN

为此,我提出以下两项建议:

首先,在当前计算double的位置放置一个断点,以查看NaN是否来自这些计算。这就是这两个变量:

double z = ...

double sum = ...
其次,重构对gradientOfWeight的调用,以返回到一个临时变量中,然后在这些interrim计算上设置一个类似的断点

所以不是

this.weightGradients.get(l)[i][j] = this.gradientOfWeight(l, i, j, target);
你应该:

double interrimComputationToListenForNaNon = this.gradientOfWeight(l, i, j, target);
this.weightGradients.get(l)[i][j] = interrimComputationToListenForNaNon;

有了这些interrim变量,您就可以更方便地监视计算,而无需以任何重要方式更改调用。也许有一种更聪明的方法可以做到这一点,而不需要使用interrim变量,但这种方法似乎最容易监控和解释。

你能找出哪一行数学计算产生了NaN吗?可能使用断点条件调试?
double interrimComputationToListenForNaNon = this.gradientOfWeight(l, i, j, target);
this.weightGradients.get(l)[i][j] = interrimComputationToListenForNaNon;