keras实战-实际经验
一些实际遇到的问题
验证集val_acc一直为0
在做keras训练的时候,设置了
model.fit(x,y,batch_size=2,epochs=1000,verbose=1,validation_split=0.2,
callbacks=[ModelCheckpoint("dnn5.h5", monitor='val_acc', verbose=1, save_best_only=True, mode='max')])
但是发现log中val_acc的值一直是0,没变,觉得很奇怪,后来只能看keras的源码,发现这段
其实就是把数据给分成前面80%后面20%,也就是说,如果我的数据是乱序的,那没问题,如果是顺序的,还特别是一堆堆的,比如有100个数据,每20个数据是1个标签,对应 1,2,3,4,5,如果这样来训练的话,刚好5这堆数据作为验证集,永远是0,因为前面只训练了1-4,不会有5。
后来我在获得训练集的时候就进行了混洗,就好了
np.random.shuffle(x) 可以用这个,同样要根据混洗后的x重新对应上y的标签,这个看具体情况了,只要能对上就行。
还有点要提下,就是shuffle
选项,如果设置了batch
,那就会给每个batch重新排列,否则是把数据全部重新排列,每轮都会进行一次重排,然后这个其实是在划分训练集后面的,所以设置了这个只是在划分好的数据内部重新排列,依然对有序数据无用,即1,2,3,4重新排成1,4,3,2,对5依然是无法验证的。
loss无下降或者准确率不提高
这个问题让我很苦恼,明明用了relu
了,怎么貌似梯度消失了,后来才知道,学习率太大了,因为这样参数w
更新后就可能是负的,wx+b
就可能<0
,进入relu
后,梯度当然就是0啦,所以一直没学习。解决方法可以减小学习率,或者更换leaky relu
,或者换换tanh试试,当然也可能有其他方法,我是调低了学习率。
分类为什么不用均方差用交叉熵
2019.6.29
今天突然看到这个问题,想搞清楚点。
主要是从两方面,一方面就是直觉的,一方面是公式推导的。
一方面是直觉的,我们知道均方差一般用于回归问题,为什么用于分类就不适合呢,因为均方差的目的是为了让真实和预测的差距越小越好,对于回归当然很好,我希望就是差距越小越好,但是概率不一样。我只希望输出的那个概率是最大的就可以了.
举个例子说明下,比如真实的标签一般已经one-hot
成[0 1 0 ]了softmax
输出[0 0.6 0.4],求均方差,应该是
(
(
0
−
0
)
2
+
(
0.6
−
1
)
2
+
(
0.4
−
0
)
2
)
/
3
=
0.106
((0-0)^2+(0.6-1)^2+(0.4-0)^2)/3=0.106
((0−0)2+(0.6−1)2+(0.4−0)2)/3=0.106,然后我们再训练,比如输出[0.2,0.6,0.2],我们求下均方差,应该是
(
(
0.2
−
0
)
2
+
(
0.6
−
1
)
2
+
(
0.2
−
0
)
2
)
/
3
=
0.08
((0.2-0)^2+(0.6-1)^2+(0.2-0)^2)/3=0.08
((0.2−0)2+(0.6−1)2+(0.2−0)2)/3=0.08,看起来我们loss更加小了,但是准确率还是没变,你可能就发现,你训练了半天,准确率好像没怎么变了,说明对于分类来说,均方差可能太严格了,分类只要求最大的概率值就行,而均方差还要求loss最小,目的很早就达到了,后面可能做无用功了。
另一方面就是梯度问题,假设二分类,用sigmoid
当激活函数,如果用均方差,你会发现梯度是跟激活函数的导数相关的,sigmoid
两边的导数几乎为0,所以就可能存在误差很大的情况下,取到了右边,自然可能就梯度消失了,所以也训练不起来或者学起来很慢,跟上面的结果一样。而交叉熵函数的梯度直接跟误差相关,误差越大,梯度越大,相对来说学习的越快。(具体的求导公式我就不推了,网上拿了张图)。
可以看到均方差的梯度跟sigmoid导数有关,交叉熵无关。
好了,今天就到这里了,希望对学习理解有帮助,其他遇到的问题后面慢慢增加上去,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵,部分图片来自网络,侵删。