神经网络模型的效果以及优化目标是通过损失函数(loss function)来定义的。分类问题和回归问题有很多经典的损失函数。
分类问题和回归问题是监督学习的两大种类。
分类问题希望解决的是将不同的样本分到事先定义好的类别中。再这种问题下,需要将样本二分类(多分类)。手写字体识别就是一个十分类的问题。
再判断二分类问题的时候,可以定义一个有单个输出节点的神经网络,当这个节点输出越接近1(或者设定的其他条件)就越可能是合格这类(或定义的其他类),越接近0(或其他条件),就越可能是另一个类。为了给出具体的分类,通常需要给出一个阈值。然而这样的做法并不容易推广到多分类的问题,虽然设置多个阈值理论上是可能的,但是实际问题上并不容易操作。
通过神经网络解决多分类问题最常用的方法是设置n个输出节点,其中n为类别的个数,每一个样例,神经网络可以得到一个n维数组作为输出结果。数组终端每一个维度(也就是每一个输出节点)对应一个类别。
以识别数字为例:
再理想情况下,如果一个样本属于类别k,那么这个类别所对应输出结果越接近[0,0,0,0,1,0,0,0,0,0]越好。那么如何判断一个输出向量和期望的向量有多接近呢?
答案是交叉熵(cross entropy)。
交叉熵是常用的评判方法之一。交叉熵刻画了两个概率分布之间的距离,他是分类问题中使用比较广泛的损失函数。
交叉熵是信息论中的概念,它原本是用来估算平均编码长度的。
给定两个概率分布p和q,用q来表示p的交叉熵为:
注意交叉熵刻画的是两个概率分布之间的距离,然而神经网络的输出却不一定是一个概率分布。概率分布刻画了不同事件发生的概率。当事情总数是有限的情况下,概率分布函数p(X=x)满足:
也就是说,任意事件发生的概率都在[0,1]之间,且总有某一个事件发射那个(概率和为1)。如果将分类问题中“一个样例属于某一类别”看成一个概率事件,那么训练数据的正确答案就符合一个概率分布。因为事件“一个样例属于不正确的类别”的概率为0,而“一个样例属于正确的类别”概率为1.
如何将神经网络前向传播得到的结果也变成概率分布呢?Softmax回归就是一个很常用的方法。
Softmax回归本身可以作为一个学习算法来优化分类结果,但在tensorflow中,Softmax回归的参数被去掉了,它至少一层额外的处理层,将神经网络的输出变成一个概率分布。
原始神经网络的输出被用作置信度来生成新的输出,而新的输出满足概率分布的所有要求。这个新的输出可以理解为经过神经网络的推导,一个样例为不同类别的概率分别是多大。这样就把一个神经网络的输出变成一个概率分布,从而可以通过交叉熵(loss function)来计算预测的概率分布和真实答案的概率分布之间的距离了。
从交叉熵的公式中可以看出交叉熵函数不是对称的(H(p,q)≠H(q,p)),它刻画的是通过概率分布q来表达概率分布p的困难程度。因为正确答案是希望得到的结果,所以当交叉熵作为神经网络的损失函数时,p代表的是正确答案,q代表的是预测值。交叉熵刻画的是两个概率分布的距离,也就是说交叉熵可以判断预测答案和真实答案之间的距离。
假设有一个三分类问题,某个样例的正确答案是(1,0,0)。某模型经过softmax回归之后的预测答案是(0.5,0.4,0.1),那么这个预测和正确答案之间的交叉熵为:H((1,0,0),(0.5,0.4,0.1))=-(1*log0.5+0*log0.4+0*log0.1)≈0.3
如果另一个模型的预测是(0.8,0.1,0.1),那么这个预测值和真实值之间的交叉熵是:
H((1,0,0),(0.8,0.1,0.1))=-(1*log0.8)≈0.1
从直观上就可以容易地知道第二个预测答案是要优于第一个的。通过交叉熵计算得到的结果也是一致的(第二个交叉熵的值更小)
tf.clip_by_value(t, clip_value_min, clip_value_max, name=None)
基于定义的min与max对tesor数据进行截断操作,目的是为了应对梯度爆发或者梯度消失的情况.
Tensorflow中交叉熵代码形式是:
cross_entropy=-tf.reduce_mean(
y_*tf.log(tf.clip_by_value(y,1e-10,1.0)))
其中y_代表真确结果,y代表预测结果。通过tf.clip_by_value()函数将一个张量中是数值限制在一个范围之内,避免一些错误运算。下面是tf.clip_by_value()函数的一个例子:
从样例中我们可以看到小于2.5的都被替换成了2.5,大于4.5的都被替换成了4.5,这样通过tf.clip_by_value()函数就可以保证在进行log运算时,不会出现log0这样的错误或者大于1的概率。
tf.log函数,这个函数完成了对张量所有元素依次求对数的功能。
值得注意的是,在tensorflow中,*代表的是矩阵元素相乘,而想要实现矩阵乘法需要用到tf.matmul()函数。通过tf.clip_by_value、tf.log、*、三个运算后,得到了一个n×m的二维矩阵,其中n为一个batch中样例的数量,m为分类的类别数量。根据交叉熵公式,应该将每行中的m个结果相加得到的所有样例的交叉熵,然后在取平均值,得到一个batch的平均交叉熵。
因为分类问题的类别数量是不变的,所以可以直接对整个矩阵做平均而并不改变计算结果的意义。
tf.reduce_mean()函数使用方法为:
因为交叉熵一般会与softmax回归一起使用,所以Tensorflow对这两个功能进行了同一封装,并提供了tf.nn.softmax_cross_entropy_with_logits()函数。比如可以直接通过下面的代码实现使用softmax回归之后的交叉熵损失函数:
其中y代表了原始神经网络的输出结果,而y_给出了标准答案。这样通过一个命令就可以使用softmax回归之后的交叉熵了。在只有一个正确答案的分类问题中,Tensorflow提供了tf.nn.sparse_softmax_cross_entropy_with_logits函数来进一步加速计算过程。与分类问题不同,回归问题解决的是对具体数值的预测。这些问题需要预测的不是一个事先定义好的类别,而是一个任意实数。解决回归问题的神经网络一般只有一个输出节点,这个节点的输出值是预测值。对于回归问题,最常用的损失函数是均方误差(MSE,mean squared error):
其中y是正确数据,而y’是神经网络给的预测值。
mse=tf.reduce_mean(tf.square(y_-y)),其中y代表了神经网络的输出答案,y_代表了标准答案。