关于XOR数据集的反向传播实现未能收敛

我已经四处寻找,熬了几个晚上,查看了许多不同的反向传播实现(包括在Stack Overflow上),试图解决这个问题,但我似乎无法理解它们是如何工作的。

我目前正在参加Andrew Ng的Coursera机器学习课程,课程很棒,但课程中展示的反向传播实现与我在互联网上看到的有很大不同。

我在理解各权重的维度和计算每个权重的增量方面遇到了问题。如果有人能详细解释反向传播的具体过程,我将不胜感激。我在前向传播方面没有问题。

这是我的代码(跳到第一个for循环)。

import numpy as npimport sysx_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.03reg_param = 0.5num_h_units = 5max_iter = 60000 # for gradient descentm = 4 # trainingnp.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 = 0w_grad2 = 0for 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_traina2_full = np.insert(sigmoid(a1_full.dot(weights1)), 0, 1, axis=1)a3_full = sigmoid(a2_full.dot(weights2))print(a3_full)

这是我得到的输出:我的输出

我还有一些不明白的地方:

  1. 在Coursera课程中,delta3是通过简单的a3 – target计算得出的,但在其他地方我看到delta3的计算是(a3 – target) * sigmoid(a3, derv=True)。我很困惑,哪个是正确的?为什么?
  2. 在许多实现中,人们没有使用learning_rate和(1 / m)来降低梯度。learning_rate和(1 / m)是可选的吗?
  3. 我们应该如何处理偏置?更新它们?还是不更新它们?在许多其他实现中,我看到人们也在更新偏置。
  4. 偏置应该放在固定的位置吗?比如作为第一列还是最后一列等。
  5. 我是否需要使用np.insert()来添加偏置列以进行计算?

我对此非常迷茫,提前感谢你们。我以为我理解了反向传播,但实现它却是一场噩梦。


回答:

这个是我所知道的最直观的反向传播解释。强烈推荐。

1.你使用的是什么损失函数?如果你使用的是交叉熵损失(带有log的那个),那么delta3就应该是简单的(a3 – target)。对于最小二乘损失,另一个是正确的。在你的代码中只使用(a3 – y_train[j])。

2.不,learning_rate和1/m不是可选的。

3.偏置总是应该被更新的。

4.尝试分别初始化偏置和权重。我发现这样理解起来更容易。

示例前向传递:

Z1 = Weights*X + biases

A1 = sigmoid(Z1)

参考这个笔记本。我使用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)。你的前向传播函数也需要返回这个值,以便在这里使用它。

另外,由于你使用的是随机梯度下降(而不是小批量梯度下降),这里你的m实际上是1。所以你应该去掉1/m项。

使用np.random.normal而不是np.random.random来初始化权重。

不要去掉偏置项。

阅读上面的链接以及这里关于反向传播的内容

Related Posts

L1-L2正则化的不同系数

我想对网络的权重同时应用L1和L2正则化。然而,我找不…

使用scikit-learn的无监督方法将列表分类成不同组别,有没有办法?

我有一系列实例,每个实例都有一份列表,代表它所遵循的不…

f1_score metric in lightgbm

我想使用自定义指标f1_score来训练一个lgb模型…

通过相关系数矩阵进行特征选择

我在测试不同的算法时,如逻辑回归、高斯朴素贝叶斯、随机…

可以将机器学习库用于流式输入和输出吗?

已关闭。此问题需要更加聚焦。目前不接受回答。 想要改进…

在TensorFlow中,queue.dequeue_up_to()方法的用途是什么?

我对这个方法感到非常困惑,特别是当我发现这个令人费解的…

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注