我正在从头开始开发一个神经网络。问题似乎可能出在我的ReLU反向传播上。当我训练模型时,它有时会输出-0,有时会输出较好的预测(相对来说)。有人能告诉我我的反向传播是否有误,或者为什么我的ReLU会预测出-0吗?
–[edit]
已经修复了预测-0的问题,但现在它对XOR的所有输入都只预测0。有人能帮我检查一下我的反向传播吗?
# Create a neural network with 2 inputs, 2 hidden neurons in each layer, and 2 layers net = NeuralNetwork(2,16,4, 'relu')epochs = 5000# Input data (A,B) for XORX = np.array([[0,0],[1,1], [1,0],[0,1]])# Expected output data Y = np.array([[0],[0],[1],[1]])for i in range(epochs): preds = [] for idx, x in enumerate(X): predictions = net.forward(x) preds.append(predictions) loss = net.meanSquaredError(predictions, Y[idx]) loss_grad = net.meanSquaredErrorGrad() net.backward(loss_grad) net.step()print("Model predicted: {}\nactual values: {} ".format(preds, Y.T))
输出:
Model predicted: [array([[-0.]]), array([[-0.]]), array([[1.]]), array([[-0.]])]
实际值:[[0 0 1 1]]
有时候预测结果是完美的,但大多数时候至少有一个预测会是-0
回答:
偏置梯度计算不正确。你使用的是self.grad_bias = grad.sum()
。这会计算整个矩阵的总和。它需要是self.grad_bias = grad.sum(axis=0, keepdims=True)
来计算一个1 x output_neurons
的数组,以便正确更新偏置向量。否则,grad.sum()
提供一个单一的数字,你用它来更新所有的偏置,这是不正确的。
此外,请确保你更新ReLU的前向传递为np.maximum(neurons, 0)
,如评论中所述。
def relu(self, neurons): self.act = (neurons > 0) return np.maximum(neurons, 0)
激活函数的梯度将根据输入的哪些部分是正值而为0或1。
最后,对于XOR问题,你通常不会使用ReLU作为输出层的激活函数,因为它不像XOR问题那样在[0-1]之间有界。你使用sigmoid激活函数得到好的结果是因为该激活函数的动态范围非常适合XOR问题。作为一个实验,你可以将输出层修改为sigmoid,隐藏层修改为ReLU。如果你这样做,你应该能得到与全程使用sigmoid一样好的性能。