矩阵维度在反向传播中不匹配

时间:2017-12-16 09:01:38

标签: python numpy machine-learning neural-network backpropagation

在这里,我尝试使用单个隐藏层实现神经网络,以对两个训练示例进行分类。该网络利用sigmoid激活功能。

图层尺寸和重量如下:

X : 2X4
w1 : 2X3
l1 : 4X3
w2 : 2X4
Y : 2X3

我遇到了矩阵尺寸不正确的反向传播问题。这段代码:

import numpy as np

M = 2
learning_rate = 0.0001

X_train = np.asarray([[1,1,1,1] , [0,0,0,0]])
Y_train = np.asarray([[1,1,1] , [0,0,0]])

X_trainT = X_train.T
Y_trainT = Y_train.T

A2_sig = 0;
A1_sig = 0;

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

def forwardProp() : 

    global A2_sig, A1_sig;

    w1=np.random.uniform(low=-1, high=1, size=(2, 2))
    b1=np.random.uniform(low=1, high=1, size=(2, 1))
    w1 = np.concatenate((w1 , b1) , axis=1)
    A1_dot = np.dot(X_trainT , w1)
    A1_sig = sigmoid(A1_dot).T

    w2=np.random.uniform(low=-1, high=1, size=(4, 1))
    b2=np.random.uniform(low=1, high=1, size=(4, 1))
    w2 = np.concatenate((w2 , b2) , axis=1)
    A2_dot = np.dot(A1_sig, w2)
    A2_sig = sigmoid(A2_dot)

def backProp() : 

    global A2_sig;
    global A1_sig;

    error1 = np.dot((A2_sig - Y_trainT).T, A1_sig / M)
    print(A1_sig)
    print(error1)
    error2 = A1_sig.T - error1

forwardProp()
backProp()

返回错误:

ValueError                                Traceback (most recent call last)
<ipython-input-605-5aa61e60051c> in <module>()
     45 
     46 forwardProp()
---> 47 backProp()
     48 
     49 # dw2 = np.dot((Y_trainT - A2_sig))

<ipython-input-605-5aa61e60051c> in backProp()
     42     print(A1_sig)
     43     print(error1)
---> 44     error2 = A1_sig.T - error1
     45 
     46 forwardProp()

ValueError: operands could not be broadcast together with shapes (4,3) (2,4) 

如何计算上一层的错误?

更新:

import numpy as np

M = 2
learning_rate = 0.0001

X_train = np.asarray([[1,1,1,1] , [0,0,0,0]])
Y_train = np.asarray([[1,1,1] , [0,0,0]])

X_trainT = X_train.T
Y_trainT = Y_train.T

A2_sig = 0;
A1_sig = 0;

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


A1_sig = 0;
A2_sig = 0;

def forwardProp() : 

    global A2_sig, A1_sig;

    w1=np.random.uniform(low=-1, high=1, size=(4, 2))
    b1=np.random.uniform(low=1, high=1, size=(2, 1))
    A1_dot = np.dot(X_train , w1) + b1
    A1_sig = sigmoid(A1_dot).T

    w2=np.random.uniform(low=-1, high=1, size=(2, 3))
    b2=np.random.uniform(low=1, high=1, size=(2, 1))
    A2_dot = np.dot(A1_dot , w2) + b2
    A2_sig = sigmoid(A2_dot)

    return(A2_sig)

def backProp() : 
    global A2_sig;
    global A1_sig;

    error1 = np.dot((A2_sig - Y_trainT.T).T , A1_sig / M)
    error2 = error1 - A1_sig

    return(error1)

print(forwardProp())
print(backProp())

返回错误:

ValueError                                Traceback (most recent call last)
<ipython-input-664-25e99255981f> in <module>()
     47 
     48 print(forwardProp())
---> 49 print(backProp())

<ipython-input-664-25e99255981f> in backProp()
     42 
     43     error1 = np.dot((A2_sig - Y_trainT.T).T , A1_sig / M)
---> 44     error2 = error1.T - A1_sig
     45 
     46     return(error1)

ValueError: operands could not be broadcast together with shapes (2,3) (2,2) 

错误设置了矩阵尺寸?

2 个答案:

答案 0 :(得分:2)

您的第一个权重矩阵w1应该是(n_features, layer_1_size)的形状,因此当您将X形状(m_examples, n_features)乘以w1时,你得到一个(m_examples, layer_1_size)矩阵。这将通过激活第1层然后进入第2层,第2层应具有形状(layer_1_size, output_size)的权重矩阵,其中output_size=3,因为您正在为3个类进行多标签分类。正如您所看到的,关键是将每个图层的输入转换为适合该图层中神经元数量的形状,换句话说,图层的每个输入都必须输入该图层中的每个神经元。 / p>

我不会像你一样对你的图层输入进行转置,我会按照描述对权重矩阵进行整形,以便你可以计算np.dot(X, w1)等。

看起来你还没有正确处理你的偏见。当我们计算Z = np.dot(w1,X) + b1时,应广播b1,以便将其添加到w1X的产品的每一列。如果您将b1追加到权重矩阵中,则不会发生这种情况。相反,您应该在输入矩阵中添加一列ones,在权重矩阵中添加一行,因此偏差项位于权重矩阵的那一行,输入中的ones确保它们得到到处都有。在此设置中,您不需要单独的b1b2条款。

X_train = np.c_(X_train, np.ones(m_examples))

并且请记住在权重中再添加一行,因此w1的形状应为(n_features+1, layer_1_size)

反向传播更新:

反向传播的目标是根据权重和偏差计算误差函数的梯度,并使用每个结果更新每个权重矩阵和每个偏差向量。

因此,您需要dE/dw2dE/db2dE/dw1dE/db1,以便您可以应用更新:

w2 <- w2 - learning_rate * dE/dw2
b2 <- b2 - learning_rate * dE/db2
w1 <- w1 - learning_rate * dE/dw1
b1 <- b1 - learning_rate * dE/db1

由于您正在进行多标记分类,因此您应该使用二进制交叉熵丢失:

binary crossentropy loss

您可以使用链规则计算dE/dw2

dE/dw2 = (dE/dA2) * (dA/dZ2) * (dZ2/dw2)

我正在为Z使用A2_dot,因为尚未应用激活,我正在使用A2为您的A2_sig

参见Notes on Backpropagation [pdf],了解有关乙状结肠激活的交叉熵丢失的详细推导。然而,这给出了逐点推导,而我们正在寻找矢量化实现,因此您需要做一些工作来找出矩阵的正确布局。不幸的是,也没有明确的偏向量。

您对error1的表达看起来是正确的,但我会称之为dw2,而我只会使用Y_train而不是两次转置:

dw2 = (1/m) * np.dot((A2 - Y_train).T , A1)

你还需要db2,应该是:

db2 = (1/m) * np.sum(A2 - Y_train, axis=1, keepdims=True)

您必须进一步应用链规则才能获得dw1db1,我会留给您,但在{{第3周有一个很好的推导3}} Coursera课程。

除了我不认为你应该在你的backprop代码中进行计算之外,我不能多说你所犯的错误这一行,所以这些维度并不合适。匹配。您可能会考虑输出处的渐变,但我无法想到在此网络中涉及A1的任何类似表达式的backprop。

Neural Networks and Deep Learning在numpy中有一个非常好的一个隐藏层神经网络的实现。它确实在输出端使用softmax,但在隐藏层中有sigmoid激活,否则计算的差异很小。它可以帮助您计算隐藏图层的dw1db1。具体来说,请在标题为&#34;实践中的神经网络&#34;。

的部分中查看delta1的表达式。

将他们的计算转换为我们正在使用的符号,并在输出处使用sigmoid而不是softmax,它应该如下所示:

dZ2 = A2 - Y_train
dZ1 = np.dot(dZ2, w2.T) * A1 * (1 - A1) # element-wise product

dw2 = (1/m) * np.dot(dZ2, A1.T)
db2 = (1/m) * np.sum(dZ2, axis=1, keepdims=True)

dw1 = (1/m) * np.dot(dZ1, X_train.T)
db1 = (1/m) * np.sum(dZ1, axis=1, keepdims=True)

答案 1 :(得分:1)

代码审查

我检查了你的最新版本并注意到以下错误:

  • 次要 )在正向传递中,永远不会使用String,也许它只是一个错字。
  • major )在向后传递中,我不确定您打算将其用作丢失函数。从代码中看起来像L2损失:

    country

    关键表达是这样的:A1_sig(虽然也许我不理解你的想法)。

    但是,您提到您正在进行多标签分类,很可能是二进制分类。在这种情况下,L2损失是一个糟糕的选择(如果您对此感兴趣,请参阅this post)。相反,使用逻辑回归损失,a.k.a。交叉熵。就你而言,它是二进制文件。

  • critical )在向后传递中,您跳过了sigmoid图层。以下行获取损失错误并将其传递给线性层:

    error1 = np.dot((A2_sig - Y_trainT.T).T , A1_sig / M)
    

    ...正向传递在线性层之后经过sigmoid激活(这是正确的)。此时,A2_sig - Y_trainT.T没有任何意义,其尺寸也不重要。

解决方案

我不喜欢你的变量命名,很容易混淆。所以我改变了它并重新组织了一些代码。这是融合的NN:

error1 = np.dot((A2_sig - Y_trainT.T).T , A1_sig / M)