1 均方差损失函数:MSE
均方误差(Mean Square Error),应该是最常用的误差计算方法了,数学公式为:
import tensorflow as tfy = tf.random.uniform((5,),maxval=5,dtype=tf.int32) # 假设这是真实值print(y) y = tf.one_hot(y,depth=5) # 转为热独编码print(y)
tf.Tensor([2 4 4 0 2], shape=(5,), dtype=int32) tf.Tensor( [[0. 0. 1. 0. 0.] [0. 0. 0. 0. 1.] [0. 0. 0. 0. 1.] [1. 0. 0. 0. 0.] [0. 0. 1. 0. 0.]], shape=(5, 5), dtype=float32)
y
<tf.Tensor: id=7, shape=(5, 5), dtype=float32, numpy= array([[0., 0., 1., 0., 0.], [0., 0., 0., 0., 1.], [0., 0., 0., 0., 1.], [1., 0., 0., 0., 0.], [0., 0., 1., 0., 0.]], dtype=float32)>
pred = tf.random.uniform((5,),maxval=5,dtype=tf.int32) # 假设这是预测值 pred = tf.one_hot(pred,depth=5) # 转为热独编码 print(pred)
tf.Tensor( [[0. 1. 0. 0. 0.] [0. 0. 0. 1. 0.] [1. 0. 0. 0. 0.] [0. 0. 0. 1. 0.] [0. 0. 0. 0. 1.]], shape=(5, 5), dtype=float32)
loss1 = tf.reduce_mean(tf.square(y-pred))loss1
<tf.Tensor: id=19, shape=(), dtype=float32, numpy=0.4>
在tensorflow的losses模块中,提供能MSE方法用于求均方误差,注意简写MSE指的是一个方法,全写MeanSquaredError指的是一个类,通常通过方法的形式调用MSE使用这一功能。MSE方法返回的是每一对真实值和预测值之间的误差,若要求所有样本的误差需要进一步求平均值:
loss_mse_1 = tf.losses.MSE(y,pred)loss_mse_1
<tf.Tensor: id=22, shape=(5,), dtype=float32, numpy=array([0.4, 0.4, 0.4, 0.4, 0.4], dtype=float32)>
loss_mse_2 = tf.reduce_mean(loss_mse_1)loss_mse_2
<tf.Tensor: id=24, shape=(), dtype=float32, numpy=0.4>
一般而言,均方误差损失函数比较适用于回归问题中,对于分类问题,特别是目标输出为One-hot向量的分类任务中,下面要说的交叉熵损失函数就要合适的多。
2 交叉熵损失函数
交叉熵(Cross Entropy)是信息论中一个重要概念,主要用于度量两个概率分布间的差异性信息,交叉熵越小,两者之间差异越小,当交叉熵等于0时达到最佳状态,也即是预测值与真实值完全吻合。先给出交叉熵计算公式:
可见,,所以第一个模型的结果更加可靠。
在TensorFlow中,计算交叉熵通过tf.losses模块中的categorical_crossentropy()方法。
tf.losses.categorical_crossentropy([0,1,0,0,0],[0.1, 0.7, 0.05, 0.05, 0.1])
<tf.Tensor: id=41, shape=(), dtype=float32, numpy=0.35667497>
tf.losses.categorical_crossentropy([0,1,0,0,0],[0, 0.6, 0.2, 0.1, 0.1])
<tf.Tensor: id=58, shape=(), dtype=float32, numpy=0.5108256>
模型在最后一层隐含层的输出可能并不是概率的形式,不过可以通过softmax函数转换为概率形式输出,然后计算交叉熵,但有时候可能会出现不稳定的情况,即输出结果是NAN或者inf,这种情况下可以通过直接计算隐藏层输出结果的交叉熵,不过要给categorical_crossentropy()方法传递一个from_logits=True参数。
x = tf.random.normal([1,784]) w = tf.random.normal([784,2]) b = tf.zeros([2])
logits = x@w + b # 最后一层没有激活函数的层称为logits层 logits
<tf.Tensor: id=75, shape=(1, 2), dtype=float32, numpy=array([[ 5.236802, 18.843138]], dtype=float32)>
prob = tf.math.softmax(logits, axis=1) # 转换为概率的形式prob
<tf.Tensor: id=77, shape=(1, 2), dtype=float32, numpy=array([[1.2326591e-06, 9.9999881e-01]], dtype=float32)>
tf.losses.categorical_crossentropy([0,1],logits,from_logits=True) # 通过logits层直接计算交叉熵
<tf.Tensor: id=112, shape=(1,), dtype=float32, numpy=array([1.1920922e-06], dtype=float32)>
tf.losses.categorical_crossentropy([0,1],prob) # 通过转换后的概率计算交叉熵
<tf.Tensor: id=128, shape=(1,), dtype=float32, numpy=array([1.1920936e-06], dtype=float32)>