基本的反向传播实现不起作用

时间:2017-08-08 19:40:14

标签: python numpy backpropagation

我在理解backpropagation的早期阶段,我试图自己实现它。

我尝试使用的数据集是大小的虹膜数据集(150,4)。

我只担心backpropagation而不是梯度下降,所以我只是在一个例子中尝试我的算法,看看我是否能得到看似合适的输出。

然而,我的问题是试图获得我的初始权重矩阵的渐变,我收到了形状错误。

我喜欢我的网络是这样的 - 4个输入,8个隐藏神经元和1个输出神经元 Neural network

我的代码如下。 错误在最后一行,因为x的大小为(4,1)而delta2的大小为(8,8)所以我无法获得点积我只是在&#39 ;如果我按照其他来源正确地遵循算法,我应该理解如何获得正确的delta2大小。

from sklearn.datasets import load_iris
from keras.utils import to_categorical
import numpy as np

# LOAD DATA
data = load_iris()
X = data.data[:-20]
y = to_categorical(data.target[:-20])
# only 20 samples because we have a small dataset
X_test = data.data[-20:]
y_test = to_categorical(data.target[-20:])

# INIT WEIGHTS  - will try to add bias later on
w1 = np.random.rand(np.shape(X)[1], h_neurons)
w2 = np.random.rand(h_neurons, 3)

def sigmoid(x, deriv=False):
    if deriv:
        return sigmoid(x)*(1-sigmoid(x))
    else:
        return 1/(1+np.exp(-x))

# Feed forward
x = X[1].reshape(4,1)
z1 = w1.T.dot(x) # need to transpose weight matrix
a1 = sigmoid(z1)
z2 = w2.T.dot(a1)
y_hat = sigmoid(z2,deriv=True) # output


# BACKPROP
y_ = y[1].reshape(3,1)
delta3 = np.multiply((y_hat - y_), sigmoid(z2, deriv=True))
dJdW2 = a1.dot(delta3) ## ERROR !!!

delta2 = np.dot(delta3, w2.T) * sigmoid(z1, deriv=True)
dJdW1 = np.dot(x.T, delta2) ## ERROR !!!

我以为我正确实施了backpropagation,但显然不是,有人可以指出我哪里出错了吗?

我被困住了,我已经查看了各种来源,计算dJdW的代码(相对于权重的成本衍生)大致相同。

1 个答案:

答案 0 :(得分:1)

我认为您的代码中存在一些问题。让我们一步一步解决它们。首先,这是完整的代码:

from sklearn.preprocessing import StandardScaler

def sigmoid(x, deriv=False):
    if deriv:
        return sigmoid(x)*(1-sigmoid(x))
    else:
        return 1/(1+np.exp(-x))


data = load_iris()
X = data.data[:-20]
X = StandardScaler().fit_transform(X)
y = data.target[:-20]
y = y.reshape(-1,1)

w1 = np.random.rand(np.shape(X)[1], 8)
w2 = np.random.rand(8, 1)

z1 = np.dot(X, w1) #shape (130, 8)
a1 = sigmoid(z1)
z2 = np.dot(a1, w2) #shape (130,1)
y_hat = sigmoid(z2) # l2 should also use sigmoid activation
delta3 = ((y - y_hat) * sigmoid(z2, deriv=True)) #shape (130,1)
dJdW2 = a1.T.dot(delta3) #shape (8,1)
delta2 = np.dot(delta3, w2.T) * sigmoid(z1, deriv=True) #shape (130,8)
dJdW1 = np.dot(X.T, delta2) #shape (4,8)
  1. 它与您的问题并不完全相关,但我建议缩放输入数据
  2. 在开头y形状是(130,),值得重塑为(130,1),否则可能会出现一些问题。 重要:我没有使用一个热编码,并留下形状为130的y,因为一个热编码需要softmax,sigmoid会更糟。
  3. 我认为最好使用矢量化版本而不是为一个样本编写代码,这样它应该更容易理解。并且你需要在前进时使用较少的转座。
  4. 所以你输入了形状为130,4的形状X和形状为4的重量w1。结果应该是形状130,8。你这样做:

    z1 = np.dot(X, w1)
    a1 = sigmoid(z1)
    

    然后从隐藏层移动到输出层,从形状130,8移动到形状130,1。并且不要忘记将激活功能应用于y_hat:

    z2 = np.dot(a1, w2)
    y_hat = sigmoid(z2)
    

    现在我们可以反向传播。您已正确计算delta:

    delta3 = np.multiply((y_hat - y_), sigmoid(z2, deriv=True)) #shape (130,1)
    

    所以你有delta3的形状(130,1),a1的形状为130,8,需要得到一个值来更新w2,所以结果应该有形状(8,1):

    dJdW2 = a1.T.dot(delta3) #shape (8,1)
    

    以类似的方式获得更新w1的值:

    delta2 = np.dot(delta3, w2.T) * sigmoid(z1, deriv=True) #shape (130,8)
    dJdW1 = np.dot(X.T, delta2) #shape (4,8)
    

    所以就是这样。但是我想指出,使用这样的模型你无法对这个数据集进行良好的预测:sigmoid的输出范围从0到1,你在虹膜数据集中有3个类。您可以采用以下几种方法:仅采用属于2个类的数据;为每个类使用单独的sigmoid或对输出层使用softmax激活。