反向传播实现不与 XOR 数据集收敛
Backpropagation implementation not converging with XOR Dataset
我到处都看了,站了几个晚上,并针对这个确切的问题研究了许多不同的反向传播实现(也在堆栈溢出上),但我似乎无法理解它们是如何工作的。
我目前正在注册 Andrew Ng 的 coursera 机器学习课程,课程很棒,但该课程中显示的反向传播实现与我在互联网上看到的非常不同。
我在理解尺寸和计算每个重量的增量时遇到问题。如果有人能给我 运行 反向传播中到底发生了什么,我将不胜感激。我的前向道具没有问题。
这是我的代码(跳到第一个 for 循环)。
import numpy as np
import sys
x_train = np.array([
[1, 0, 1],
[1, 1, 0],
[1, 1, 1],
[1, 0, 0]
])
y_train = np.array([
[1],
[1],
[0],
[0]
])
learning_rate = 0.03
reg_param = 0.5
num_h_units = 5
max_iter = 60000 # for gradient descent
m = 4 # training
np.random.seed(1)
weights1 = np.random.random((x_train.shape[1], num_h_units)) # 3x5 (Including bias)
weights2 = np.random.random((num_h_units + 1, 1)) # 6x1 (Including bias)
def sigmoid(z, derv=False):
if derv: return z * (1 - z)
return (1 / (1 + np.exp(-z)))
def forward(x, predict=False):
a1 = x # 1x3
a1.shape = (1, a1.shape[0]) # Reshaping now, to avoid reshaping the other activations.
a2 = np.insert(sigmoid(a1.dot(weights1)), 0, 1, axis=1) # 1x3 * 3x5 = 1x5 + bias = 1x6
a3 = sigmoid(a2.dot(weights2)) # 1x6 * 6x1 = 1x1
if predict: return a3
return (a1, a2, a3)
w_grad1 = 0
w_grad2 = 0
for i in range(max_iter):
for j in range(m):
sys.stdout.write("\rIteration: {} and {}".format(i + 1, j + 1))
a1, a2, a3 = forward(x_train[j])
delta3 = np.multiply((a3 - y_train[j]), sigmoid(a3, derv=True)) # 1x1
# (1x6 * 1x1) .* 1x6 = 1x6 (Here, ".*" stands for element wise mult)
delta2 = np.multiply((weights2.T * delta3), sigmoid(a2, derv=True))
delta2 = delta2[:, 1:] # Getting rid of the bias value since that shouldn't be updated.
# 3x1 * 1x5 = 3x5 (Gradient of all the weight values for weights connecting input to hidden)
w_grad1 += (1 / m) * a1.T.dot(delta2)
# 6x1 * 1x1 = 6x1 (Updating the bias as well. If bias is removed, dimensions don't match)
a2[:, 0] = 0
w_grad2 += (1 / m) * a2.T.dot(delta3)
sys.stdout.flush() # Updating the text.
weights1 -= learning_rate * w_grad1
weights2 -= learning_rate * w_grad2
# Outputting all the outputs at once.
a1_full = x_train
a2_full = np.insert(sigmoid(a1_full.dot(weights1)), 0, 1, axis=1)
a3_full = sigmoid(a2_full.dot(weights2))
print(a3_full)
这是我得到的输出:
以下我也不太明白:
- 在 coursera 课程中,delta3 是通过执行以下操作来计算的:a3 - target 但我在其他地方看到过计算 delta3 (a3 - target) * sigmoid(a3, derv=True)。我很困惑,哪个是正确的?为什么?
- 在许多实现中,该人没有使用 learning_rate 和 (1 / m) 来降级。 learning_rate 和 (1 / m) 是可选的吗?
- 我们应该如何处理这些偏见?更新它们?不更新他们?在许多其他实现中,我看到人们也只是更新了偏差。
- 有没有固定的偏差位置?就像第一列或最后一列一样。等等
- 我是否需要执行 np.insert() 以将偏差列添加到计算中?
我对此非常迷茫,所以提前谢谢你。我以为我了解反向传播,但实现它绝对是一场噩梦。
This 是我知道 of.Highly 推荐的最直观的反向传播解释。
1.What 你在用损失函数吗?如果您使用 cross-entropy 损失(其中包含 log 的那个),则 delta3 必须只是 (a3 - target)。对于最小二乘损失,另一个只有 correct.Use (a3 - y_train[j]) 在你的代码中。
2.No学习率和1/m不可选
3.The 偏差应该始终更新。
4.Try 初始化偏差和权重 seperatedly.I 发现它更容易理解。
前传示例:
Z1 = 权重*X + 偏差
A1 = sigmoid(Z1)
参考 this notebook 。我已经使用 numpy 实现了完全相同的东西并且它有效。
更正:
delta3 = a3 - y_train[j]
delta2 = np.multiply((weights2.T * delta3), sigmoid_prime(z1))
在哪里
sigmoid_prime 是:
def sigmoid_prime(z):
return sigmoid(z)*(1-sigmoid(z))
z1 是 a1.dot(weights1)
。你的前馈函数也需要 return 这个值,这样你才能在这里使用它。
此外,由于您使用的是随机梯度下降(而不是 mini-batch 梯度下降),您的 m 实际上是 1 here.So 您应该删除 1/m 项。
使用 np.random.normal 而非 np.random.random
初始化权重
不要去掉偏差项。
阅读上面 link 的 back-prop 以及 here
我到处都看了,站了几个晚上,并针对这个确切的问题研究了许多不同的反向传播实现(也在堆栈溢出上),但我似乎无法理解它们是如何工作的。
我目前正在注册 Andrew Ng 的 coursera 机器学习课程,课程很棒,但该课程中显示的反向传播实现与我在互联网上看到的非常不同。
我在理解尺寸和计算每个重量的增量时遇到问题。如果有人能给我 运行 反向传播中到底发生了什么,我将不胜感激。我的前向道具没有问题。
这是我的代码(跳到第一个 for 循环)。
import numpy as np
import sys
x_train = np.array([
[1, 0, 1],
[1, 1, 0],
[1, 1, 1],
[1, 0, 0]
])
y_train = np.array([
[1],
[1],
[0],
[0]
])
learning_rate = 0.03
reg_param = 0.5
num_h_units = 5
max_iter = 60000 # for gradient descent
m = 4 # training
np.random.seed(1)
weights1 = np.random.random((x_train.shape[1], num_h_units)) # 3x5 (Including bias)
weights2 = np.random.random((num_h_units + 1, 1)) # 6x1 (Including bias)
def sigmoid(z, derv=False):
if derv: return z * (1 - z)
return (1 / (1 + np.exp(-z)))
def forward(x, predict=False):
a1 = x # 1x3
a1.shape = (1, a1.shape[0]) # Reshaping now, to avoid reshaping the other activations.
a2 = np.insert(sigmoid(a1.dot(weights1)), 0, 1, axis=1) # 1x3 * 3x5 = 1x5 + bias = 1x6
a3 = sigmoid(a2.dot(weights2)) # 1x6 * 6x1 = 1x1
if predict: return a3
return (a1, a2, a3)
w_grad1 = 0
w_grad2 = 0
for i in range(max_iter):
for j in range(m):
sys.stdout.write("\rIteration: {} and {}".format(i + 1, j + 1))
a1, a2, a3 = forward(x_train[j])
delta3 = np.multiply((a3 - y_train[j]), sigmoid(a3, derv=True)) # 1x1
# (1x6 * 1x1) .* 1x6 = 1x6 (Here, ".*" stands for element wise mult)
delta2 = np.multiply((weights2.T * delta3), sigmoid(a2, derv=True))
delta2 = delta2[:, 1:] # Getting rid of the bias value since that shouldn't be updated.
# 3x1 * 1x5 = 3x5 (Gradient of all the weight values for weights connecting input to hidden)
w_grad1 += (1 / m) * a1.T.dot(delta2)
# 6x1 * 1x1 = 6x1 (Updating the bias as well. If bias is removed, dimensions don't match)
a2[:, 0] = 0
w_grad2 += (1 / m) * a2.T.dot(delta3)
sys.stdout.flush() # Updating the text.
weights1 -= learning_rate * w_grad1
weights2 -= learning_rate * w_grad2
# Outputting all the outputs at once.
a1_full = x_train
a2_full = np.insert(sigmoid(a1_full.dot(weights1)), 0, 1, axis=1)
a3_full = sigmoid(a2_full.dot(weights2))
print(a3_full)
这是我得到的输出:
以下我也不太明白:
- 在 coursera 课程中,delta3 是通过执行以下操作来计算的:a3 - target 但我在其他地方看到过计算 delta3 (a3 - target) * sigmoid(a3, derv=True)。我很困惑,哪个是正确的?为什么?
- 在许多实现中,该人没有使用 learning_rate 和 (1 / m) 来降级。 learning_rate 和 (1 / m) 是可选的吗?
- 我们应该如何处理这些偏见?更新它们?不更新他们?在许多其他实现中,我看到人们也只是更新了偏差。
- 有没有固定的偏差位置?就像第一列或最后一列一样。等等
- 我是否需要执行 np.insert() 以将偏差列添加到计算中?
我对此非常迷茫,所以提前谢谢你。我以为我了解反向传播,但实现它绝对是一场噩梦。
This 是我知道 of.Highly 推荐的最直观的反向传播解释。
1.What 你在用损失函数吗?如果您使用 cross-entropy 损失(其中包含 log 的那个),则 delta3 必须只是 (a3 - target)。对于最小二乘损失,另一个只有 correct.Use (a3 - y_train[j]) 在你的代码中。
2.No学习率和1/m不可选
3.The 偏差应该始终更新。
4.Try 初始化偏差和权重 seperatedly.I 发现它更容易理解。
前传示例:
Z1 = 权重*X + 偏差
A1 = sigmoid(Z1)
参考 this notebook 。我已经使用 numpy 实现了完全相同的东西并且它有效。
更正:
delta3 = a3 - y_train[j]
delta2 = np.multiply((weights2.T * delta3), sigmoid_prime(z1))
在哪里 sigmoid_prime 是:
def sigmoid_prime(z):
return sigmoid(z)*(1-sigmoid(z))
z1 是 a1.dot(weights1)
。你的前馈函数也需要 return 这个值,这样你才能在这里使用它。
此外,由于您使用的是随机梯度下降(而不是 mini-batch 梯度下降),您的 m 实际上是 1 here.So 您应该删除 1/m 项。
使用 np.random.normal 而非 np.random.random
初始化权重不要去掉偏差项。
阅读上面 link 的 back-prop 以及 here