2017-08-08 58 views
1

我处于理解backpropagation的初期阶段,我试图自己实现它。基本后向传播实施不起作用

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

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

但是,我的问题是试图让我的渐变为我的初始权重矩阵,我得到的形状错误。

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

我的代码如下。 错误是与最后一行,因为x的大小(4,1)和delta2的大小(8,8),所以我不能得到点产品我只是不明白我应该得到如果我按照其他来源正确地跟踪算法,那么正确的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(与权重有关的费用的导数)的代码大致相同。

+0

也许这是相关的:您的预测是多类的,但您使用的是单个单元,并且假设预测是线性形式0-2。考虑使用三个S形输出单元(每个类一个),它应该工作得更好。 –

+0

谢谢,我想到了这一点,尽管我仍然得到与我的delta矩阵大小相同的错误。 –

回答

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,1的y,因为一个热门编码需要softmax,sigmoid会更糟。
  3. 我认为使用矢量化版本更好,而不是为一个样本编写代码,这样应该更容易理解。你需要在正向传球时使用更少的转置。

所以,你必须形状130,4,重量输入X W1与形状4,8的结果应该具有形状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) 

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

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

所以,你必须与形状(130,1)delta3,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激活。

+0

非常感谢你!你不知道这是多么有帮助! –