当前位置: 首页 > 知识库问答 >
问题:

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

刘弘济
2023-03-14

在这里,我试图实现一个具有单个隐藏层的神经网络来分类两个训练示例。该网络利用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个答案

璩涵衍
2023-03-14

我已经检查了您的最新版本,并注意到以下错误:

>

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

关键表达式是:A2_sig-Y_trainT. T(尽管也许我只是不明白你的想法)。

然而,您提到您正在进行多标签分类,很可能是二进制分类。在这种情况下,L2丢失是一个糟糕的选择(如果您对原因感兴趣,请参阅本文)。相反,使用logistic回归损失,即交叉熵。在你的情况下,它是二进制的。

(关键)在后退过程中,跳过了sigmoid层。下一行获取损耗误差并将其通过线性层:

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

。。。而向前传球是在线性层(这是正确的)之后通过乙状结肠激活。此时,“错误1”没有任何意义,它的尺寸也无关紧要。

我不喜欢你的变量命名,很容易混淆。所以我改变了它并稍微重组了代码。这是收敛的NN:

import numpy as np

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

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

hidden_size = 2
output_size = 3
learning_rate = 0.1

w1 = np.random.randn(hidden_size, 4) * 0.1
b1 = np.zeros((hidden_size, 1))
w2 = np.random.randn(output_size, hidden_size) * 0.1
b2 = np.zeros((output_size, 1))

for i in xrange(50):
  # forward pass

  Z1 = np.dot(w1, X_train) + b1
  A1 = sigmoid(Z1)

  Z2 = np.dot(w2, A1) + b2
  A2 = sigmoid(Z2)

  cost = -np.mean(Y_train * np.log(A2) + (1 - Y_train) * np.log(1 - A2))
  print(cost)

  # backward pass

  dA2 = (A2 - Y_train) / (A2 * (1 - A2))

  dZ2 = np.multiply(dA2, A2 * (1 - A2))
  dw2 = np.dot(dZ2, A1.T)
  db2 = np.sum(dZ2, axis=1, keepdims=True)

  dA1 = np.dot(w2.T, dZ2)
  dZ1 = np.multiply(dA1, A1 * (1 - A1))
  dw1 = np.dot(dZ1, X_train.T)
  db1 = np.sum(dZ1, axis=1, keepdims=True)

  w1 = w1 - learning_rate * dw1
  w2 = w2 - learning_rate * dw2
  b1 = b1 - learning_rate * db1
  b2 = b2 - learning_rate * db2
申查猛
2023-03-14

您的第一个权重矩阵w1应为形状(n\u特征,layer\u 1\u大小),因此当您将形状(m\u示例,n\u特征)的输入X乘以w1时,您将得到一个矩阵(m\u示例,layer\u 1\u大小)。这将通过激活第1层运行,然后输入第2层,该层应具有形状的权重矩阵(layer\u 1\u size,output\u size),其中output\u size=3,因为您正在对3个类进行多标签分类。正如你所看到的,关键是将每一层的输入转换成一个与该层中神经元数量相匹配的形状,或者换句话说,每一层的输入都必须反馈给该层中的每一个神经元。

我不会像你所拥有的那样对你的层输入进行转置,我会按照描述塑造权重矩阵,这样你就可以计算np。dot(X,w1)等。

看起来你没有正确处理你的偏见。当我们计算Z=np时。点(w1,X)b1,b1,应进行广播,以便将其添加到w1X产品的每一列中。如果在权重矩阵中添加b1,则不会发生这种情况。相反,您应该在输入矩阵中添加一列“1”,在权重矩阵中添加一行,这样偏差项就位于权重矩阵的那一行,而输入中的“1”确保它们被添加到所有位置。在此设置中,您不需要单独的术语。

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

记住在你的体重上再加一行,这样w1就应该有形状(n\u features 1,layer\u 1\u 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

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

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

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

由于激活尚未应用,我正在为您的A2\U dot使用Z,并且我正在为您的A2\U sig使用A2。

关于sigmoid激活的交叉熵损失的详细推导,请参见反向传播[pdf]上的注释。然而,这提供了一个逐点的推导,而我们正在寻找一个矢量化的实现,因此您需要做一些工作来找出矩阵的正确布局。不幸的是,也没有明确的偏差向量。

您对error1的表达式看起来是正确的,但我将其称为dw2,我只使用Y\U train,而不是两次换位:

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

您还需要db2,它应该是:

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

您必须进一步应用链式规则才能获得dw1和db1,我将把这留给您,但在第3周的神经网络和深度学习课程中有一个很好的推导。

我不能对你得到的错误行说太多,除此之外,我认为你不应该在你的backprop代码中有这样的计算,所以维度不匹配是有道理的。你可能会想到输出的梯度,但我想不出在这个网络中有任何类似的表达式涉及backprop的A1。

本文在numpy中实现了一个非常好的单隐藏层神经网络。它确实在输出处使用softmax,但它在隐藏层中具有sigmoid激活,否则计算差异很小。它应该可以帮助您计算隐藏层的dw1db1。具体来说,请查看标题为“实践中的神经网络”的部分中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)
 类似资料:
  • 我在吴恩达教授的讲座或这方面的帮助下,使用图31算法实现神经网络。 我想我很好地理解了正向传播和反向传播,但混淆了每次迭代后更新权重(theta)。 何时以及如何更新权重(θ)矩阵-θ1,θ2? 大三角洲是干什么的?[已解决,谢谢@xhudik] 我们是否必须添加1(输入层和隐藏层中的偏差单位?)

  • 卷积神经网络其实是神经网络特征学习的一个典型例子。传统的机器学习算法其实需要人工的提取特征,比如很厉害的SVM。而卷积神经网络利用模板算子的参数也用以学习这个特点,把特征也学习出来了。其实不同的模板算子本质上就是抽象了图像的不同方面的特征。比如提取边缘,提取梯度的算子。用很多卷积核去提取,那就是 提取了很多的特征。一旦把参数w,b训练出来,意味着特征和目标之间的函数就被确定。今天分享下CNN的关键

  • 训练发散 理想的分类器应当是除了真实标签的概率为1,其余标签概率均为 0,这样计算得到其损失函数为 -ln(1) = 0 损失函数越大,说明该分类器在真实标签上分类概率越小,性能也就越差。一个非常差的分类器,可能在真实标签上的匪类概率接近于0,那么损失函数就接近于正无穷,我们成为训练发散,需要调小学习速率。 6.9 高原反应 在 ImageNet-1000 分类问题中,初始状态为均匀分布,每个类别

  • 1 正向传播(Forward propagation) 回忆一下,给出一个输入特征$x$的时候,我们定义了$a^{[0]}=x$。然后对于层(layer)$l=1,2,3,\dots,N$,其中的$N$是网络中的层数,则有: $z^{[l]}=W^{[l]}a^{[l-1]}+b^{[l]}$ $a^{[l]}=g^{[l]}(z^{[l]})$ 在讲义中都是假设了非线性特征$g^{[l]}$对除

  • 在使用relu激活功能时,我在实现backprop时遇到问题。我的模型有两个隐藏层,两个隐藏层中都有10个节点,输出层中有一个节点(因此有3个权重,3个偏差)。我的模型不适用于这个断开的backward\u prop函数。但是,该函数使用sigmoid激活函数(作为注释包含在函数中)与backprop一起工作。因此,我认为我把relu推导搞砸了。 谁能把我推向正确的方向?

  • 表示为一个 4x4 matrix. 在3D计算机图形学中,4x4矩阵最常用的用法是作为一个变换矩阵Transformation Matrix。 有关WebGL中使用的变换矩阵的介绍,请参阅本教程this tutorial。 这使得表示三维空间中的一个点的向量Vector3通过乘以矩阵来进行转换,如平移、旋转、剪切、缩放、反射、正交或透视投影等。这就是把矩阵应用到向量上。 任何3D物体Object3