我已经实现了以下神经网络来解决Python中的XOR问题。我的神经网络由2个神经元的输入层,2个神经元的1个隐藏层和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的原因,因为您仅使用第一个输入进行训练。您需要对其进行更改,以使其读取正确的示例,例如example 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
中计算了每个神经元的输出激活,因此,当您在这些神经元处计算局部导数时,可以将输出激活直接提供给s_prime
,因此无需计算S形这些再次。所以:
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]]
您可以看到,这或多或少与XOR门的预期输出相符。我可以建议的最后一件事是,鉴于您当前的代码结构,10000次迭代的计算时间太长。我注意到通过上述更正,我们能够以较少的迭代次数达到预期的输出。我将迭代次数减少到1000,并将学习速率
alpha
提升到0.75。改变这两个事情,我们现在得到:[[0 0]] : [[ 0.03029435]]
[[0 1]] : [[ 0.95397528]]
[[1 0]] : [[ 0.95371525]]
[[1 1]] : [[ 0.04796917]]
关于python - XOR神经网络收敛到0.5,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/36369335/