softmax从名字上看就是软最大,其做法其实很简单:
前提:最后输出向量长度为N,与要区分的类别个数一致
1 第一步,取向量的最大值,将每个值减去最大值,这样就会将所有的数都变成非正数
2 求softmax:
3 经过第二步就会将向量变成全部小于1,大于0,累加为1的向量,这样就比较符合我们输出每个类别的概率的判断:在那个类别下的值最大,就判别为哪一类
4 有了类别输出概率,在训练的时候还需要求loss,根据loss去更新梯度,优化参数,类别向量长度也为N,求loss的公式:loss=−∑kyklog(pk)
5 在实际计算的时候,比第四步要简单的多,直接取对应类别下的概率输出,取负对数,就得到了loss,即只管对应类别下的概率,将其进行优化,因为概率和为1,对应类别下的概率值变大,其他值自然变小:
loss -= log(std::max(prob_data[i * dim + label_value * inner_num_ + j], Dtype(FLT_MIN)));
这样取prob_data的值是因为在loss的公式中,只需要关注k=y^(i)的那一类即可
dim:批大小个数
label_value:标签
inner_num_:标签个数
FLT_MIN的值:1.17549435E-38F
这个值的自然对数是:-87.3365,取负号变成87.3365
这个值是在训练的时候经常会出现的一个值,出现这个值是因为,求得的值比系统能够表示的float最小值还小,一般就是0了,即求得的概率值为0,
而前面已经说过了。经过softmax后,值都在0-1之间,观察以e为底的指数函数的曲线的话,你会发现,当取值趋向于无穷小时,其值才趋近于0:
因此问题就出现在前面的features值溢出,即超过float能够表示的范围成为inf,inf在和其他数的运算中会将其他数也变成inf,最后在取inf和FLT_MIN较大值后做log运算后就变成了传说中的87.3365
softmax输入的feature由两部分计算得到:一部分是上一层的输入数据,另部分是各层权重参数,针对性的可以尝试下面的方法进行解决:
1 学习率太大,尝试降低学习率
2 增大批处理试试
3 有时未加归一化时,也会导致loss为这个值,尝试着在最后面的fc层添加批处理层试试
4 数据标签未从0开始,将数据标签改成从0开始,并将SoftmaxWithLoss层的前一层的fc层的输出个数改成类别个数,如果类别个数不对,也有可能出现这个问题
5 偏置初始化值太大,最好初始化为0,或者是权重初始化值太大,尝试降低权重初始化方差
6 在solver 中加clip_gradients设置,也许能够解决这个问题
7 还有一个可能的原因就是:当你的批大小不大,而图像中混有一些灰度图,注意,虽然有些图是3通道,但是各个通过值相等,也是灰度图,在这种情况下,有些网络结构就会出现这个值,这个值的出现与批大小,网络结构,灰度图,这个三都有关系,如果是这种情况,将灰度图进行排除