XOR 神经网络收敛到 0.5

XOR Neural Network Converges to 0.5

我实现了以下神经网络来解决 Python 中的 XOR 问题。我的神经网络由 2 个神经元的输入层、1 个 2 个神经元的隐藏层和 1 个神经元的输出层组成。我使用 Sigmoid 函数作为隐藏层的激活函数,使用线性(恒等)函数作为输出层的激活函数:

import numpy as np

def sigmoid(z):
    return 1/(1+np.exp(-z))

def s_prime(z):
    return np.multiply(sigmoid(z), sigmoid(1.0-z))

def init_weights(layers, epsilon):
    weights = []
    for i in range(len(layers)-1):
        w = np.random.rand(layers[i+1], layers[i]+1)
        w = w * 2*epsilon - epsilon
        weights.append(np.mat(w))
    return weights

def fit(X, Y, w, predict=False, x=None):
    w_grad = ([np.mat(np.zeros(np.shape(w[i]))) 
              for i in range(len(w))])
    for i in range(len(X)):
        x = x if predict else X[0]
        y = Y[0,i]
        # forward propagate
        a = x
        a_s = []
        for j in range(len(w)):
            a = np.mat(np.append(1, a)).T
            a_s.append(a)
            z = w[j] * a
            a = sigmoid(z)
        if predict: return a
        # backpropagate
        delta = a - y.T
        w_grad[-1] += delta * a_s[-1].T
        for j in reversed(range(1, len(w))):
            delta = np.multiply(w[j].T*delta, s_prime(a_s[j]))
            w_grad[j-1] += (delta[1:] * a_s[j-1].T)
    return [w_grad[i]/len(X) for i in range(len(w))]

def predict(x):
    return fit(X, Y, w, True, x)

####

X = np.mat([[0,0],
            [0,1],
            [1,0],
            [1,1]])
Y = np.mat([0,1,1,0])
layers = [2,2,1]
epochs = 10000
alpha = 0.5
w = init_weights(layers, 1)

for i in range(epochs):
    w_grad = fit(X, Y, w)
    print w_grad
    for j in range(len(w)):
        w[j] -= alpha * w_grad[j]

for i in range(len(X)):
    x = X[i]
    guess = predict(x)
    print x, ":", guess

反向传播似乎都是正确的;我想到的唯一问题是我实施偏置单元时遇到的一些问题。无论哪种方式,每次我 运行 代码时,每个输入的所有预测都会收敛到大约 0.5。我已经搜索了代码,但似乎找不到问题所在。谁能指出我的实施有什么问题?我感谢任何反馈。

如果出于任何原因它可能有所帮助,这是我得到的输出类型:

[[0 0]] : [[ 0.5]]
[[0 1]] : [[ 0.49483673]]
[[1 0]] : [[ 0.52006739]]
[[1 1]] : [[ 0.51610963]]

你的前向传播和反向传播的实现或多或少是正确的。但是,您出错的地方非常简单。第一个小错误是查看 fit 函数内部 - 特别是 for 循环中的第一条语句:

x = x if predict else X[0]

你是说如果你不预测(即执行训练),在随机梯度下降的每次迭代中选择的输入示例必须始终是第一个示例,这是 [0 0](即 X[0])。这就是为什么您的所有预测都得到 0.5 的原因,因为您只使用第一个输入进行训练。您需要更改它,以便它读取正确的示例,即示例 i:

x = x if predict else X[i]

您需要做的最后一个更改是 s_prime 函数。 sigmoid 函数的导数确实是你所拥有的:

def s_prime(z):
    return np.multiply(sigmoid(z), sigmoid(1.0-z))

当你计算前向传播时,你已经计算了a_s中每个神经元的输出激活,所以当你计算这些神经元的局部导数时,你直接将输出激活提供给[=21] =] 所以你不需要再次计算这些的 sigmoid。

因此:

def s_prime(z):
    return np.multiply(z, 1.0-z)

完成这两项更改后,我们现在得到以下输出:

[[0 0]] : [[ 0.00239857]]
[[0 1]] : [[ 0.99816778]]
[[1 0]] : [[ 0.99816596]]
[[1 1]] : [[ 0.0021052]]

可以看出,这与异或门的预期输出或多或少是一致的。我可以推荐的最后一件事是,考虑到您当前的代码结构,10000 次迭代在计算上太长了。我注意到通过上述更正,我们能够以更少的迭代次数达到预期的输出。我已将迭代次数减少到 1000 次,并将学习率 alpha 提高到 0.75。改变这两件事我们现在得到:

[[0 0]] : [[ 0.03029435]]
[[0 1]] : [[ 0.95397528]]
[[1 0]] : [[ 0.95371525]]
[[1 1]] : [[ 0.04796917]]