我正在使用5个卷积层,2个隐藏层和1个Softmax来尝试CNN。
架构如下:
cv0->relu->cv1->relu-cv2->relu->cv3->relu->cv4->relu->cv5->hid1->relu->hid2->relu->logistic softmax
通过对图像使用66个块的随机梯度来训练,目的是进行测试,只在单个图像上进行20个迭代的训练。
从网络中识别到错误在每次迭代中都会爆炸,因此梯度在第3或第4个迭代后就开始计算nan。
如下所示,在错误值爆炸成非常高的值之后,梯度产生了NaN,这被传播到整个网络中。
查看不同层次节点的权重值以了解发生了什么: layer8(softmax):
初始值[0.05436778 0.02379715]
epoch 1 [0.28402206 -0.20585714]
epoch 2 [-0.0527361184 0.0952038541]
epoch 3 [-7330.04199219 7330.12011719]
epoch 4 [nan nan] layer6(hid1):
初始值[-0.0254469 0.00760095 ..., -0.00587915 0.02619855 0.03809309]
epoch 1 [-0.0254469 0.00760095 ..., -0.00587915 0.02619855 0.03809309]
epoch 2 [-0.0254469 0.00760095 ..., -0.00587915 0.02619855 0.03809309
epoch 3 [-2.54468974e-02 1.79247314e+16 ..., -5.87915350e-03 2.61985492e-02 -2.06307964e+19]
epoch 4 [nan nan ..., nan nan nan] layer0(cv0):
初始化时为:
[[-0.01704694 -0.01683052 -0.0894756 ]
[ 0.12275343 -0.05518051 -0.09202443]
[-0.11599202 -0.04718829 -0.04359322]]
第三个时期是
[[-24165.15234375 -26490.89257812 -24820.1484375 ]
[-27381.8203125 -26653.3359375 -24762.28710938]
[-23120.56835938 -21189.44921875 -24513.65039062]]
很明显,权重值正在爆炸。
学习速率为0.01,为了解决这个问题,我将学习速率改为0.001,有时Nan会消失,网络会收敛,但有时会饱和并产生NaN。尝试更小的学习速率0.0001,并没有看到NaN出现。从结果来看,每次重新运行代码时,结果都非常不同,我认为这与权重初始化有关。
于是,我尝试了不同的权重初始化方法:
对于具有ReLU的卷积层:
W_bound_6 = numpy.sqrt(6. / (fan_in + fan_out))
W_bound_2 = numpy.sqrt(2. / (fan_in + fan_out))
W_values = numpy.asarray(
numpy.random.randn(filter_shape[0], filter_shape[1], filter_shape[2], filter_shape[3]) * W_bound_2,
dtype=theano.config.floatX)
对于隐藏层和softmax层
W_bound_2 = numpy.sqrt(2. / (filter_shape[0] + filter_shape[1]))
W_values = numpy.asarray(
numpy.random.randn(filter_shape[0], filter_shape[1]) * W_bound_2,
dtype=theano.config.floatX
)
并将 b 初始化为零。
差别不是很大,我仍然看不出结果上有何不同。
我在这里发布我的问题,目的是:
- 讨论我在权重初始化方面是否与编码正确;
- 看看我是否可以避免使学习率非常小,而保持至少前几次迭代的高水平,因为在我的情况下,第四次迭代中会传递NaN。
- 我想知道L1, L2正则化是否需要在成本函数中实现,因为我正在使用Theano,在哪里应该实现代码,还是我应该更改更新函数。
成本函数
-T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y])
更新功能
updates = [
(param_i, param_i - learning_rate * grad_i)
for param_i, grad_i in zip(classifier.params, grads)
]
- 在我的结构中,每层后都使用ReLU实现,但在Softmax后不使用,这样做正确吗?
grads = T.grad(cost, classifier.params)
。尝试添加一行新代码grads_clipped = [T.clip(g, -2, 2] for g in grads)
,并将更新中的zip中的grads
替换为grads_clipped
,即zip(classifier.params, grads_clipped)
。 - Andrej Žukov-Gregoričcost = -T.mean(T.log(self.p_y_given_x)[T.arange(y.shape[0]), y] + L1 + L2)
即可。 - Andrej Žukov-Gregorič