在中文互联网中没有找到合适的文章,翻译此文以供参考。
提问
在训练模型陷入困境(比如出现nans、loss不收敛)时,查看冗长的日志有时候会有意外收获,为了得到日志,需要在solver.prototxt文件中设置debug_info为True。
训练日志有时候看起来长这样:
I1109 ...] [Forward] Layer data, top blob data data: 0.343971
I1109 ...] [Forward] Layer conv1, top blob conv1 data: 0.0645037
I1109 ...] [Forward] Layer conv1, param blob 0 data: 0.00899114
I1109 ...] [Forward] Layer conv1, param blob 1 data: 0
I1109 ...] [Forward] Layer relu1, top blob conv1 data: 0.0337982
I1109 ...] [Forward] Layer conv2, top blob conv2 data: 0.0249297
I1109 ...] [Forward] Layer conv2, param blob 0 data: 0.00875855
I1109 ...] [Forward] Layer conv2, param blob 1 data: 0
I1109 ...] [Forward] Layer relu2, top blob conv2 data: 0.0128249
.
.
.
I1109 ...] [Forward] Layer fc1, top blob fc1 data: 0.00728743
I1109 ...] [Forward] Layer fc1, param blob 0 data: 0.00876866
I1109 ...] [Forward] Layer fc1, param blob 1 data: 0
I1109 ...] [Forward] Layer loss, top blob loss data: 2031.85
I1109 ...] [Backward] Layer loss, bottom blob fc1 diff: 0.124506
I1109 ...] [Backward] Layer fc1, bottom blob conv6 diff: 0.00107067
I1109 ...] [Backward] Layer fc1, param blob 0 diff: 0.483772
I1109 ...] [Backward] Layer fc1, param blob 1 diff: 4079.72
.
.
.
I1109 ...] [Backward] Layer conv2, bottom blob conv1 diff: 5.99449e-06
I1109 ...] [Backward] Layer conv2, param blob 0 diff: 0.00661093
I1109 ...] [Backward] Layer conv2, param blob 1 diff: 0.10995
I1109 ...] [Backward] Layer relu1, bottom blob conv1 diff: 2.87345e-06
I1109 ...] [Backward] Layer conv1, param blob 0 diff: 0.0220984
I1109 ...] [Backward] Layer conv1, param blob 1 diff: 0.0429201
E1109 ...] [Backward] All net params (data, diff): L1 norm = (2711.42, 7086.66); L2 norm = (6.11659, 4085.07)
这是什么意思?
回答
前向传播
大看一眼,首先日志分为[Forward]和[Backward]两部分,考虑到网络的学习由前向推断和后向传播组成:
训练样本(或者batch)输入样本,前向传播得到预测值,由预测值计算loss并求导,估计梯度并按照链式法则后向传播。
我们知道caffe利用Blob来处理data/weights/parameters等数据,这里我们需要明确,一个Blob由data和diff两部分组成,data储存数据,diff储存梯度。(类似于PyTorch中的Tensor)
前向传播:
你可以看到日志中展示了所有层从bottom到top的传播过程。每一层如下:
I1109 ...] [Forward] Layer conv1, top blob conv1 data: 0.0645037
I1109 ...] [Forward] Layer conv1, param blob 0 data: 0.00899114
I1109 ...] [Forward] Layer conv1, param blob 1 data: 0
conv1层有两个Blob参数:卷积核filter和偏置bias,加上数据一共有3行。
I1109 ...] [Forward] Layer conv1, param blob 0 data: 0.00899114
当前conv1卷积核权重的L2范数是0.00899,bias值(para blob 1)为0:
I1109 ...] [Forward] Layer conv1, param blob 1 data: 0
啰嗦一句,conv1层有个输出,叫“conv1”(…),这个输出的L2范数是0.0645
I1109 ...] [Forward] Layer conv1, top blob conv1 data: 0.0645037
需要注意的是所有[Forward]中报告的L2范数对象都是blob的data部分。
loss和梯度
[Forward]的最后一层是loss
I1109 ...] [Forward] Layer loss, top blob loss data: 2031.85
I1109 ...] [Backward] Layer loss, bottom blob fc1 diff: 0.124506
传入的该batch的loss是2031.85,loss对应于fc1的梯度保存在fc1的Blob中(我们知道fc1的data和diff应该是shape相同的),且L2范数幅度是0.1245。
后向传播
[backward]中的计算的是对应层Blob的diff的L2范数
最后
[Backward] All net params (data, diff): L1 norm = (2711.42, 7086.66); L2 norm = (6.11659, 4085.07)
最后报告了网络所有参数(data和diff)的L1范数和L2范数
我应该怎么找?
- 如果loss中含有nan,找找哪一层、哪一次迭代中开始产生nan。
- 观察梯度的幅度,这些数据应该很好看,如果出现了e+8,那说明产生了梯度爆炸,不妨减小学习率。
- diff不可能为0,否则0梯度->无更新->无学习,所以随机初始化权重时应当设置为高方差。
- 比起报0的梯度层,尤其要注意报0的激活层。对于ReLU来说,报0意味着你来到了一个没有激活的"死神经元"区域,不妨试试normalizrtion、batch normalization或leaky ReLU。