Tensorflow中的损失函数和梯度下降

损失函数

均值平方差

均值平方差(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
2
3
MSE=tf.reduce_mean(tf.pow(tf.sub(logits,outputs),2.0))
MSE=tf.reduce_mean(tf.square(tf.sub(logits,outputs)))
MSE=tf.reduce_mean(tf.square(logits-outputs))

logits代表标签值,outputs代表预测值。同样也可以组合其它类似loss,

1
2
rmse=tf.sqrt(tf.reduce_mean(tf.pow(tf.sub(logits,outputs),2.0)))
mad=tf.reduce_mean(tf.complex_abs(logits,outputs))

交叉熵

在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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import tensorflow as tf
labels=[[0,0,1],[0,1,0],]
logits=[[2,0.5,6],[0.1,0,3]]
#进行第一次softmax
logits_scaled=tf.nn.softmax(logits)
#进行第二次softmax
logits_scaled2=tf.nn.softmax(logits_scaled)
#用第一次的softmax进行交叉熵计算
result1=tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits)
#用第二次的softmax进行交叉熵计算
result2=tf.nn.softmax_cross_entropy_with_logits(labels=labels,logits=logits_scaled)
#用自建公式实验
result3=-tf.reduce_sum(labels*tf.log(logits_scaled),1)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
print("logits_scaled:",sess.run(logits_scaled))
print("logits_scaled2",sess.run(logits_scaled2))
print("result1:",sess.run(result1))
print("result2:",sess.run(result2))
print("result3:",sess.run(result3))

从结果看,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
2
3
4
5
6
labels2=[[0.4,0.1,0.5],[0.3,0.6,0.1]]
result4=tf.nn.softmax_cross_entropy_with_logits(labels=labels2,logits=logits)
with tf.Session() as sess:
print("result4:",result4)
#输出结果
result4 [2.1721554 2.7696736]

与前面的result1对比发现,标准的one-hot的结果比较明显。

sparse交叉熵

使用sparse_softmax_cross_entropy_with_logits函数的用法,他需要使用非one-hot的标签,所以要把前面的标签换成具体的数值[2,1]。PS:这个labels能不能换成[1,2]

1
2
3
4
5
6
labels3=[2,1]#表明labels共有3个类,0、1、2。[2,1]等价于one-hot编码的001与010
result5=tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels3,logits=logits)
with tf.Session() as sess:
print("result5:",result5)
#输出结果
result5 [0.02215516 3.0996735 ]

result5与result1完全一样。

计算loss值

对于softmax_cross_entropy_with_logits后的结果求loss直接取均值。

1
2
3
4
5
loss=tf.reduce_mean(result1)
with tf.Session() as sess:
print("loss",sess.run(loss))
#输出结果
#loss 1.5609143

对于softmax后的结果,先使用-tf.reduce_sum(labels*tf.log(logits_scaled)),接着求均值。

1
2
3
4
5
loss2=tf.reduce_mean(-tf.reduce_sum(labels*tf.log(logits_scaled),1))
with tf.Session() as sess:
print("loss2:",loss2)
#输出结果
#loss 1.5609144

梯度下降

梯度下降法是一个最优化算法, 通常也称为最速下降法, 常用于机器学习和人工智能中递归性地逼近最小偏差模型, 梯度下降的方向也就是用负梯度方向为搜索方向, 沿着梯度下降的方向求解极小值。

在训练过程中,每次的正向传播后都会得到输出值与真实值的损失值。这个损失值越小越好,代表模型越好。于是梯度下降的算法就用在这里,帮助寻找最小的那个损失值,从而可以反推出对应的学习参数b和w,达到优化模型的效果。

常用的梯度下降方法可以分为:批量梯度下降、随机梯度下降、小批量梯度下降。

批量梯度下降: 遍历全部数据集算一次损失函数, 然后算函数对各个参数的梯度和更新梯度。 这种方法每更新一次参数, 都要把数据集里的所有样本看一遍, 计算量大, 计算速度慢, 不支持在线学习,称为batch gradient descent。

随机梯度下降:每看一个数据就算一下损失函数,然后求梯度更新参数。 这称为stochastic gradient descent, 随机梯度下降。 这个方法速度比较快, 但是收敛性能不太好, 可能在最优点附近晃来晃去, 命中不到最优点。 两次参数的更新也有可能互相抵消, 造成目标函数震荡比较剧烈

小批量梯度下降:为了克服上面两种方法的缺点, 一般采用一种折中手段——小批的梯度下降。 这种方法把数据分为若干个批, 按批来更新参数, 这样一批中的一组数据共同决定了本次梯度的方向, 下降起来就不容易跑偏, 减少了随机性。 另一方面因为批量的样本数与整个数据集相比小了很多, 计算量也不是很大。

tensorflow中的梯度下降函数

在tensorflow中是通过一个叫做Optimizer的优化器进行训练优化的。对于不同的优化器,在tensorflow会有不同的类:

在训练过程中,先实例化一个优化函数,并基于一定的学习率进行梯度优化训练:

1
optimizer=tf.train.GradientDescentOptimizer(learning_rate)

接着使用minimize()操作,接着传入损失值loss到这个操作。优化器就会按照循环的次数一次次沿着loss最小值的方向优化参数。

----本文结束,感谢您的阅读。如有错,请指正。----
大哥大嫂过年好!支持我一下呗
0%