深层神经网络进行Gradient Check的时候注意delta的大小

神经网络的Backward Pass实现是比较容易出错的,一个不错的做法是实现一个神经网络之后,利用Numeric的方法计算一个粗略的梯度,和你实际上算出来的梯度进行比对,如果差的不多,就说明你实现对了。

前两天做CS231n作业的时候遇到了一个特别奇怪的事,我实现了一个N层卷积层,之后跟M层FC-Relu层的简单神经网络,指定N=1,M=2之后,死活过不了Gradient Check,并且永远是FC层的第二层的bias出错,其他参数都完全正确:

num_inputs = 2
input_dim = (3, 16, 16)
reg = 0.0
num_classes = 10
X = np.random.randn(num_inputs, *input_dim)
y = np.random.randint(num_classes, size=num_inputs)

model = ConvNet(num_filters=[3], filter_size=[3],
                          input_dim=input_dim, hidden_dim=[7, 7],
                          dtype=np.float64)
loss, grads = model.loss(X, y)
for param_name in sorted(grads):
    f = lambda _: model.loss(X, y)[0]
    param_grad_num = eval_numerical_gradient(f, model.params[param_name], verbose=False, h=1e-6) #h就是delta,计算公式是d = (f(x+h)-f(x-h))/2h

    e = rel_error(param_grad_num, grads[param_name])
    print '%s max relative error: %e' % (param_name, rel_error(param_grad_num, grads[param_name]))
W_conv0 max relative error: 2.488318e-02
W_fc0 max relative error: 3.070288e-02
W_fc1 max relative error: 1.011455e-02
W_soft max relative error: 5.722041e-03
b_conv0 max relative error: 3.798044e-03
b_fc0 max relative error: 6.489261e-05
b_fc1 max relative error: 1.000000e+00
b_soft max relative error: 9.867731e-10

查了好几天,百思不得其解,我以为是不是又出现了谁的cache被悄悄修改了的情况,但是打断点进去以后发现一切输入都非常正常。经过很长时间的debug无果以后,我开始怀疑是不是标答有问题。这个时候我突然注意到,在输入FC1,进行完XW+b之后,输出给Relu1的X是这样的:

 [[  7.29069965e-08  -2.22044158e-07  -1.74749819e-08  -2.84726995e-08]
 [  1.43855178e-07  -3.39216429e-07   1.75782951e-08  -2.42950271e-08]]

我们可以看到,这个X都是1e-8级别的,非常小,但是Gradient Check的时候,delta的值却是1e-6,其量级已经与X相当,所以当然得不出正确的结果。

究其原因,这个ConvNet在初始化的时候采用的是从一个均值为0,标准差为weight_scale的正态分布中采样参数的。当时的weight_scale设的是1e-3,因此X每过一层,大约都会减少1000倍。随着层数的深入,值也就会越来越小。当到了第3层以后,与一个1e-6的值相加,自然就会出错。

我尝试调小了delta的值到1e-8,但是结果变成所有的梯度都不对了。我猜是因为这么小的delta不太能准确计算出梯度了。

既然减小delta不行,那么就将weight_scale调大好了,调大到1之后就顺利Pass了Gradient Check。

你可能感兴趣的:(Python和深度学习)