Python Softmax神经网络在实现时存在错误,但在正确实现时不起作用

Python Softmax神经网络在实现时存在错误,但在正确实现时不起作用,python,machine-learning,neural-network,classification,softmax,Python,Machine Learning,Neural Network,Classification,Softmax,我已经尝试解决这个问题好几天了,但运气不好。我一直在实现一个简单的神经网络与一个单一的隐藏层从头开始,只是为了我自己的理解。我已经成功地用sigmoid、tanh和relu激活实现了二进制分类,现在我正在尝试在多类分类的输出中使用softmax 在我遇到的每个关于softmax实现的教程中,包括我的讲师的笔记,输出层的softmax交叉熵误差的导数被简化为仅预测-标签,因此本质上从真实标签位置的预测值中减去1 然而,我发现,如果使用这种方法,那么我的网络的误差将持续增加,直到它收敛到总是预测一个

我已经尝试解决这个问题好几天了,但运气不好。我一直在实现一个简单的神经网络与一个单一的隐藏层从头开始,只是为了我自己的理解。我已经成功地用sigmoid、tanh和relu激活实现了二进制分类,现在我正在尝试在多类分类的输出中使用softmax

在我遇到的每个关于softmax实现的教程中,包括我的讲师的笔记,输出层的softmax交叉熵误差的导数被简化为仅
预测-标签
,因此本质上从真实标签位置的预测值中减去1

然而,我发现,如果使用这种方法,那么我的网络的误差将持续增加,直到它收敛到总是预测一个随机类为100%,另一个为0%。有趣的是,如果我将其更改为
标签-预测
,它在我学习下面的二进制XOR函数的简单测试中非常有效。不幸的是,如果我尝试将相同的网络应用于更复杂的问题(手写字母-26类),当使用
labels-predictions
predictions-labels
时,它再次收敛到以100%的概率输出一个类

我不知道为什么这行不正确的代码适用于简单的二进制分类,但不适用于包含许多类的分类。我假设我的代码中有其他的东西,这个不正确的更改实际上是在逆转这个错误,但是我找不到它可能在哪里

import numpy as np


class MLP:

    def __init__(self, numInputs, numHidden, numOutputs):
        # MLP architecture sizes
        self.numInputs = numInputs
        self.numHidden = numHidden
        self.numOutputs = numOutputs

        # MLP weights
        self.IH_weights = np.random.rand(numInputs, numHidden)      # Input -> Hidden
        self.HO_weights = np.random.rand(numHidden, numOutputs)     # Hidden -> Output

        # Gradients corresponding to weight matrices computed during backprop
        self.IH_w_gradients = np.zeros_like(self.IH_weights)
        self.HO_w_gradients = np.zeros_like(self.HO_weights)

    def sigmoid(self, x):
        return 1 / (1 + np.exp(-x))

    def sigmoidDerivative(self, x):
        return x * (1 - x)

    def softmax(self, x):
        # exps = np.exp(x)
        exps = np.exp(x - np.max(x))                            # Allows for large values
        return exps / np.sum(exps)

    def forward(self, input):
        self.I = np.array(input).reshape(1, self.numInputs)     # (numInputs, ) -> (1, numInputs)
        self.H = self.I.dot(self.IH_weights)
        self.H = self.sigmoid(self.H)
        self.O = self.H.dot(self.HO_weights)
        self.O = self.softmax(self.O)
        self.O += 1e-10                                         # Allows for log(0)
        return self.O

    def backwards(self, label):
        self.L = np.array(label).reshape(1, self.numOutputs)    # (numOutputs, ) -> (1, numOutputs)
        self.O_error = - np.sum([t * np.log(y) for y, t in zip(self.O, self.L)])
        # self.O_delta = self.O - self.L                        # CORRECT (not working)
        self.O_delta = self.L - self.O                          # INCORRECT (working)
        self.H_error = self.O_delta.dot(self.HO_weights.T)
        self.H_delta = self.H_error * self.sigmoidDerivative(self.H)
        self.IH_w_gradients += self.I.T.dot(self.H_delta)
        self.HO_w_gradients += self.H.T.dot(self.O_delta)
        return self.O_error

    def updateWeights(self, learningRate):
        self.IH_weights += learningRate * self.IH_w_gradients
        self.HO_weights += learningRate * self.HO_w_gradients

        self.IH_w_gradients = np.zeros_like(self.IH_weights)
        self.HO_w_gradients = np.zeros_like(self.HO_weights)


data = [
    [[0, 0], [1, 0]],
    [[0, 1], [0, 1]],
    [[1, 0], [0, 1]],
    [[1, 1], [1, 0]]
]

mlp = MLP(2, 5, 2)

numEpochs = 10000
learningRate = 0.1

for epoch in range(numEpochs):
    epochLosses, epochAccuracies = [], []
    for i in range(len(data)):
        prediction = mlp.forward(data[i][0])
        # print(prediction, "\n")
        label = data[i][1]
        loss = mlp.backwards(label)
        epochLosses.append(loss)
        epochAccuracies.append(np.argmax(prediction) == np.argmax(label))
    mlp.updateWeights(learningRate)
    if epoch % 1000 == 0 or epoch == numEpochs - 1:
        print("EPOCH:", epoch)
        print("LOSS: ", np.mean(epochLosses))
        print("ACC:  ", np.mean(epochAccuracies) * 100, "%\n")

softmax函数是否为def softmax(x):返回np.exp(x)/np.sum(np.exp(x),axis=0)@karthikbharadwaj,该函数也不起作用-它会导致负损失值。我认为它应该是
轴=-1
,如果我的数据在更高的维度上,这只会产生影响。