我在理解backpropagation
的早期阶段,我试图自己实现它。
我尝试使用的数据集是大小的虹膜数据集(150,4)。
我只担心backpropagation
而不是梯度下降,所以我只是在一个例子中尝试我的算法,看看我是否能得到看似合适的输出。
然而,我的问题是试图获得我的初始权重矩阵的渐变,我收到了形状错误。
我喜欢我的网络是这样的 - 4个输入,8个隐藏神经元和1个输出神经元
我的代码如下。 错误在最后一行,因为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的代码(相对于权重的成本衍生)大致相同。
答案 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)
所以你输入了形状为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激活。