损失函数
均值平方差
均值平方差(Mean Squared Error,MSE),也称”均方误差”,在神经网络中主要是表达预测值与真实值之间的差异,在数理统计中,均方误差是指参数估计值与参数真值之差平方的期望值。
均方误差的值越小,表明模型越好。类似的损失算法还有均方误差RMSE(将MSE开平方),平均绝对值误差MAD(对一个真实值与预测值相减的绝对值取平均值)。
注意:在神经网络计算时,预测值要与真实值控制在同样的数据分布内,假设将预测值经过Sigmoid激活函数得到取值范围在0~1之间,那么真实值也归一化成0~1之间。
交叉熵
交叉熵(crossentropy)也是loss算法的一种,一般用于分类问题,表达的意思为预测输入样本属于某一类的概率。其中y代表真实值分类(0或1),a代表预测值。
交叉熵也只值越小,代表预测结果越准。
注意:这里用于计算的a也是通过分布同一化处理的(或者是经过Sigmoid函数激活的),取值范围0~1。
损失算法的选取
损失函数的选取取决于输入标签数据的类型: 如果输入的是实数、 无界的值, 损失函数使用平方差; 如果输入标签是位矢量(分类标志) , 使用交叉熵会更适合。
Tensorflow的loss函数
均值平方差
在Tensorflow没有单独的MSE函数,不过由于公式比较简单,往往都是自己写函数。也有多种写法:
1 | MSE=tf.reduce_mean(tf.pow(tf.sub(logits,outputs),2.0)) |
logits代表标签值,outputs代表预测值。同样也可以组合其它类似loss,
1 | rmse=tf.sqrt(tf.reduce_mean(tf.pow(tf.sub(logits,outputs),2.0))) |
交叉熵
在tensorflow中常见的交叉熵函数有:Sigmoid交叉熵、softmax交叉熵、Sparse交叉熵、加权Sigmoid交叉熵
当然,我们也可以像MSE那样使用自己组合的公式计算交叉熵。对于softmax后的结果logits我们可以对其使用公式-tf.reduce_sum(labels*tf.log(logis),1),就等同于softmax_cross_entropy_with_logits得到结果。(注意有个负号)
softmax_cross_entropy_with_logits和sigmoid_cross_entropy_with_logits区别:softmax_cross_entropy_with_logits有一个且只有一个标签,不能同时有两个标签。sigmoid_cross_entropy_with_logits可以执行多标签分类。
实验
softmax交叉熵
标签是one-hot编码。
1 | import tensorflow as tf |
从结果看,logits里面的值原本加和都是大于1的,但是经过softmax之后,总和变成了1。logits中的第一个是跟标签分类相符的,第二个与标签分类不符,所以第一个的交叉熵比较小,是0.02215518。第二个交叉熵比较大,是3.09967351。
总结:
比较scaled和scaled2可以看到: 经过第二次的softmax后, 分布概率会有变化, 而scaled才是我们真实转化的softmax值。 比较rel1和rel2可以看到: 传入softmax_cross_entropy_with_logits的logits是不需要进行softmax的。 如果将softmax后的值scaled传入softmax_cross_entropy_with_ logits就相当于进行了两次的softmax转换。
对于已经用softmax转换过的scaled,在计算loss的时候不能再使用softmax_cross_entropy_with_logits了。应该自己写一个函数,如上面代码的result3。
下面用一组总和为1但是数组中每个值都不等于0或1的数组来代替标签。
1 | labels2=[[0.4,0.1,0.5],[0.3,0.6,0.1]] |
与前面的result1对比发现,标准的one-hot的结果比较明显。
sparse交叉熵
使用sparse_softmax_cross_entropy_with_logits函数的用法,他需要使用非one-hot的标签,所以要把前面的标签换成具体的数值[2,1]。PS:这个labels能不能换成[1,2]
1 | labels3=[2,1]#表明labels共有3个类,0、1、2。[2,1]等价于one-hot编码的001与010 |
result5与result1完全一样。
计算loss值
对于softmax_cross_entropy_with_logits后的结果求loss直接取均值。
1 | loss=tf.reduce_mean(result1) |
对于softmax后的结果,先使用-tf.reduce_sum(labels*tf.log(logits_scaled)),接着求均值。
1 | loss2=tf.reduce_mean(-tf.reduce_sum(labels*tf.log(logits_scaled),1)) |
梯度下降
梯度下降法是一个最优化算法, 通常也称为最速下降法, 常用于机器学习和人工智能中递归性地逼近最小偏差模型, 梯度下降的方向也就是用负梯度方向为搜索方向, 沿着梯度下降的方向求解极小值。
在训练过程中,每次的正向传播后都会得到输出值与真实值的损失值。这个损失值越小越好,代表模型越好。于是梯度下降的算法就用在这里,帮助寻找最小的那个损失值,从而可以反推出对应的学习参数b和w,达到优化模型的效果。
常用的梯度下降方法可以分为:批量梯度下降、随机梯度下降、小批量梯度下降。
批量梯度下降: 遍历全部数据集算一次损失函数, 然后算函数对各个参数的梯度和更新梯度。 这种方法每更新一次参数, 都要把数据集里的所有样本看一遍, 计算量大, 计算速度慢, 不支持在线学习,称为batch gradient descent。
随机梯度下降:每看一个数据就算一下损失函数,然后求梯度更新参数。 这称为stochastic gradient descent, 随机梯度下降。 这个方法速度比较快, 但是收敛性能不太好, 可能在最优点附近晃来晃去, 命中不到最优点。 两次参数的更新也有可能互相抵消, 造成目标函数震荡比较剧烈
小批量梯度下降:为了克服上面两种方法的缺点, 一般采用一种折中手段——小批的梯度下降。 这种方法把数据分为若干个批, 按批来更新参数, 这样一批中的一组数据共同决定了本次梯度的方向, 下降起来就不容易跑偏, 减少了随机性。 另一方面因为批量的样本数与整个数据集相比小了很多, 计算量也不是很大。
tensorflow中的梯度下降函数
在tensorflow中是通过一个叫做Optimizer的优化器进行训练优化的。对于不同的优化器,在tensorflow会有不同的类:
在训练过程中,先实例化一个优化函数,并基于一定的学习率进行梯度优化训练:
1 | optimizer=tf.train.GradientDescentOptimizer(learning_rate) |
接着使用minimize()操作,接着传入损失值loss到这个操作。优化器就会按照循环的次数一次次沿着loss最小值的方向优化参数。