【问题标题】:Neural network- derivative for second layer parameters wrong第二层参数的神经网络导数错误
【发布时间】:2019-01-19 20:27:29
【问题描述】:

我正在构建我的第一个神经网络。虽然看到我得到大约 95-98% 的准确率是令人鼓舞的。我从梯度检查中发现,第二层的 theta(参数)的导数与我使用数值梯度检查得到的结果相差甚远(最大差异为 0.9 ..)。我的输入是来自 sklearn load_digits 的 8X8 数字图像。

  • 输入维度 (1797,65),有偏差。
  • 输出维度 (1797,10)。
  • 神经网络架构:3 层。 layer1-65 节点,layer2-101 节点,layer3 10 节点。

下面是python代码sn-ps。

#forward propagation
a1 = x #(1797, 64)
a1 = np.column_stack((np.ones(m,),a1)) #(1797,65)
a2 = expit(a1.dot(theta1)) #(1797,100)
a2 = np.column_stack((np.ones(m,),a2)) #(1797,101)
a3 = expit(a2.dot(theta2)) #(1797,10)
a3[a3==1] = 0.999999 #to avoid log(1)
res1 = np.multiply(outputs,np.log(a3)) #(1797,10) .* (1797,10) 
res2 = np.multiply(1-outputs,np.log(1-a3))
lamda = 0.5
cost = (-1/m)*(res1+res2).sum(axis=1).sum() + lamda/(2*m)*(np.square(theta1[1:,:]).sum(axis=1).sum() + np.square(theta2[1:,:]).sum(axis=1).sum())

反向传播代码:

#Back propagation
delta3 = a3 - outputs
delta2 = np.multiply(delta3.dot(theta2.T),np.multiply(a2,1-a2)) #(1797,10) * (10,101) = (1797,101)
D1 = (a1.T.dot(delta2[:,1:])) #(65, 1797) * (1797,100) = (65,100)
D1[0,:] = 1/m * D1[0,:]
D1[1:,:] = 1/m * (D1[1:,:] + lamda*theta1[1:,:])
D2 = (a2.T.dot(delta3)) #(101,1797) * (1797, 10) = (101,10)
D2[0,:] = 1/m * D2[0,:]
D2[1:,:] = 1/m * (D2[1:,:] + lamda*theta2[1:,:]) #something wrong in D2 calculation steps...
#print(theta1.shape,theta2.shape,D1.shape,D2.shape)
#this is what is returned by cost function
return cost,np.concatenate((np.asarray(D1).flatten(),np.asarray(D2).flatten())) #last 1010 wrong values

如您所见,渐变已变平。当我使用数值梯度检查时,我发现前 6500 个数字非常接近“D1”,最大差异 = 1.0814544260334766e-07。但最后 1010 个项目,对应于 D2,最多关闭 0.9。下面是梯度检查代码:

print("Checking gradient:")
c,grad = cost(np.concatenate((np.asarray(theta1).flatten(),np.asarray(theta2).flatten())),x_tr,y_tr,theta1.shape,theta2.shape)
grad_approx = checkGrad(x_tr,y_tr,theta1,theta2)
print("Non zero in grad",np.count_nonzero(grad),np.count_nonzero(grad_approx))
tup_grad = np.nonzero(grad)
print("Original\n",grad[tup_grad[0][0:20]])
print("Numerical\n",grad_approx[tup_grad[0][0:20]])
wrong_grads = np.abs(grad-grad_approx)>0.1
print("Max diff:",np.abs(grad-grad_approx).max(),np.count_nonzero(wrong_grads),np.abs(grad-grad_approx)[0:6500].max())
print(np.squeeze(np.asarray(grad[wrong_grads]))[0:20])
print(np.squeeze(np.asarray(grad_approx[wrong_grads]))[0:20])
where_tup = np.where(wrong_grads)
print(where_tup[0][0:5],where_tup[0][-5:])

查看grad函数:

def checkGrad(x,y,theta1,theta2):
eps = 0.0000001 #0.00001    
theta = np.concatenate((np.asarray(theta1).flatten(),np.asarray(theta2).flatten()))
gradApprox = np.zeros((len(theta,)))
thetaPlus = np.copy(theta)
thetaMinus = np.copy(theta)
print("Total iterations to be made",len(theta))
for i in range(len(theta)):
    if(i % 100 == 0):
        print("iteration",i)
    if(i != 0):
        thetaPlus[i-1] = thetaPlus[i-1]-eps
        thetaMinus[i-1] = thetaMinus[i-1]+eps
    thetaPlus[i] = theta[i]+eps
    thetaMinus[i] = theta[i]-eps
    cost1,grad1 = cost(thetaPlus,x,y,theta1.shape,theta2.shape)
    cost2,grad2 = cost(thetaMinus,x,y,theta1.shape,theta2.shape)
    gradApprox[i] = (cost1 - cost2)/(2*eps)

return gradApprox

我相信我犯了一些新手错误。我意识到这可能需要很多代码。但是对于在该领域有经验的人可能会对我做错的地方提出一些建议。

  1. 哪里出错了?
  2. 为什么我使用相同的算法 (TNC) 得到非常不同的 scipy 最小化结果。 BFGS 的结果很糟糕。

编辑:进一步明确:我使用 checkGrad 函数来验证我使用反向传播为参数 theta1 和 theta2 计算的导数(D1 和 D2)是否正确。 “lamda”(错字)是正则化常数 0.5。 expit 是 numpy 的 sigmoid 函数。

完整代码:https://www.kaggle.com/darkknight91/neuralnet-digits

【问题讨论】:

  • 您能指定您的checkGrad 函数的作用吗? expit 也一样? (此外,字母“lambda”的写法不同;-)
  • :-D。很抱歉造成混乱。我已添加对您的查询的回复。
  • 我实际上想看看你在内部调用了什么。这是scipy.optimize.check_grad?此外,您最初在哪里设置 theta 值?
  • @dennlinger 因为在这里发布整个代码会很笨拙,所以我添加了一个指向我的完整代码的链接。 Theta 设置为 0 到 3 之间的随机值。

标签: python machine-learning neural-network minimization


【解决方案1】:

一般方法

如果这是您的第一个 NN,那么我建议您使用网络本身计算梯度:

from copy import deepcopy as dc


def gradient(net, weights, dx=0.01):
    der = []
    # compute partial derivatives
    for i in range(len(weights)):
        w = dc(weights)     # dc is needed
        w[i] += dx
        der.append((net(w) - net(weights)) / dx)    # dy/dx
    return der

这里有一个简单的例子

def net(weights):
    """ this is your net """
    # example with just a simple cost function for clarity purposes
    return sum([i**2 for i in weights])

print('cost', net([1, 1]))
print('gradient =', gradient(net, [1, 1]))

额外提示:请务必在需要时使用 deepcopy,这花了我很多时间才弄清楚!

【讨论】:

  • 我已经在计算数值导数(就像你写的那样)来验证我的模型。我不明白你到底建议什么作为解决方案。你的意思是,用这种方法训练我的整个数据集?这将需要很长时间。
  • 这种方法要简单得多,不需要任何第n层导数公式。对于你的第一个 NN,我推荐它,反正它不应该花太多时间;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-02
  • 2017-12-05
  • 2023-02-17
  • 2017-11-20
相关资源
最近更新 更多