本篇文章介绍一下tensorflow中必须要掌握的基础知识点,就是损失函数,因为最终训练迭代优化就是损失函数,那么总体来说它可以分为两大类:
1 以回归为主:MSE-均方根误差
2 以分类为主:SOFTMAX-交叉熵
3 根据特定场景:自定义损失函数
接下来我们具体来通过代码讲解每种具体的实例:
首先我们看一下均方根误差-MSE
import tensorflow as tf session = tf.InteractiveSession() y_ = tf.constant([1,2,3],dtype=tf.float32,shape=[3,1]) y1 = tf.constant([1,2,3],dtype=tf.float32,shape=[3,1]) y2 = tf.constant([3,5,5],dtype=tf.float32,shape=[3,1]) #先求差的平方,然后再求平均 mes = tf.reduce_mean(tf.square(y2-y_)) # reduce_sum 使用它的目的 如果当求差的平法之后是一个向量,需要先用这个函数求和 mes1 = tf.reduce_mean(tf.reduce_sum(tf.square(y2-y_))) print(session.run(mes)) print(session.run(mes1))
关于交叉熵有两种使用方法,一种是自定义交叉熵,一种是使用tensorflow自带的几种,接下来分别来讲解
& 自定义交叉熵
import tensorflow as tf session = tf.InteractiveSession() y_ = tf.constant([[1.0, 0, 0]]) # 正确标签 y1 = tf.constant([[0.9, 0.06, 0.04]]) # 预测结果1 y2 = tf.constant([[0.5, 0.3, 0.2]]) # 预测结果2 # 自定义交叉熵 cross_entropy = -tf.reduce_mean(y_ * tf.log(tf.clip_by_value(y1, 1e-10, 1.0))) print('cross_entropy',cross_entropy)
clib_by_value为了防止出现log0这种情况,还有不要忘记前面的'-',实际使用中建议使用tf自带的损失函数
& tensorflow自带实现的交叉熵
# -*- coding: utf-8 -*- import tensorflow as tf session = tf.InteractiveSession() y_ = tf.constant([[1.0, 0, 0]]) # 正确标签 y3 = tf.constant([[10.0, 3.0, 2.0]]) y4 = tf.constant([[5.0, 3.0, 1.0]]) # 该操作应该施加在未经过Softmax处理的logits上,否则会产生错误结果 # labels为期望输出,且必须采用labels=y_, logits=y的形式将参数传入 cross_entropy_v2_1 = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y3) cross_entropy_v2_2 = tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y4) print('v2_1', cross_entropy_v2_1.eval()) print('v2_2',cross_entropy_v2_2.eval())
我们举了其中的一个实现方法讲解,其实它提供了几大类,分别对应不同的场景实现:
# 基于单标签多分类 tf.nn.softmax_cross_entropy_with_logits() #基于单标签单分类 tf.nn.sparse_softmax_cross_entropy_with_logits() #基于多标签多分类 tf.nn.sigmoid_cross_entropy_with_logits() # 基于权重的损失函数 tf.nn.weighted_cross_entropy_with_logits() # 基于词向量的NCE tf.nn.nce_loss()
注意:前4个函数,返回的不是一个具体的数值,而是一个向量,所以如果要求交叉熵需要使用tf.reduce_sum()进行求和,如果还想求解最终的loss,需要再使用tf.reduce_mean()....
& 自定义损失函数:这个根据业务场景可以很简单也可以很复杂,接下来我们看一个比较简单的使用场景
# -*- coding: utf-8 -*- import tensorflow as tf from numpy.random import RandomState batch_size=8 # 定义两个输入节点 x=tf.placeholder(tf.float32,shape=(None,2),name='x-input') # 回归问题一般只有一个输出节点 y_=tf.placeholder(tf.float32,shape=(None,1),name='y-input') # 定义一个单层的神经网络 w1=tf.Variable(tf.random_normal([2,1],stddev=1,seed=1)) y=tf.matmul(x,w1) #自己定义损失函数 # 如果y>y_ 取(y-y_)* 1 # 如果y<=y_ 取(y_-y)*10 # 根据loss结果可以自动调节这个计算方式和系数的值 loss=tf.reduce_sum(tf.where(tf.greater(y,y_),(y-y_)*1,(y_-y)*10)) train_step=tf.train.AdamOptimizer(0.001).minimize(loss) # 随机生成一个模拟数据集 rdm=RandomState(1) dataset_size=128 X=rdm.rand(dataset_size,2) # 设置随机噪声,范围在-0.05~0.05 Y = [[x1+x2+rdm.rand()/10.0-0.05] for (x1,x2) in X] # 训练神经网路 with tf.Session() as sess: init_op = tf.global_variables_initializer() sess.run(init_op) STEPS=5000 for i in range(STEPS): start=(i*batch_size) % dataset_size end = min(start+batch_size,dataset_size) sess.run(train_step,feed_dict={x:X[start:end],y_:Y[start:end]}) print(sess.run(w1))通过上面自定义的损失函数可以发现,最后的输出结果的参数会略大于1,而我们在定义实际的输出结果是x1+x2+随机数,参数值应该都为1。因为,我们在使用损失函数的时候,指定了当预测少的损失更大,所以预测值会比实际值要大一些。如果,我们指定损失函数的时候,指定预测多的损失更大,那么所求得的参数值将会略小于1。通过自定义损失函数,来更好的满足我们实际的模型需要,从中可以发现,损失函数对一个模型的重要性。